Merge branch 'for-usb-linus' of git+ssh://master.kernel.org/pub/scm/linux/kernel...
authorGreg Kroah-Hartman <gregkh@suse.de>
Mon, 1 Aug 2011 23:38:38 +0000 (16:38 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 1 Aug 2011 23:39:14 +0000 (16:39 -0700)
* 'for-usb-linus' of git+ssh://master.kernel.org/pub/scm/linux/kernel/git/sarah/xhci:
  usb/config: use proper endian access for wMaxPacketSize
  USB: xhci: fix OS want to own HC
  xhci: Don't submit commands or URBs to halted hosts.

1753 files changed:
CREDITS
Documentation/DocBook/.gitignore
Documentation/DocBook/Makefile
Documentation/DocBook/dvb/.gitignore [deleted file]
Documentation/DocBook/dvb/audio.xml [deleted file]
Documentation/DocBook/dvb/ca.xml [deleted file]
Documentation/DocBook/dvb/demux.xml [deleted file]
Documentation/DocBook/dvb/dvbapi.xml [deleted file]
Documentation/DocBook/dvb/dvbproperty.xml [deleted file]
Documentation/DocBook/dvb/dvbstb.pdf [deleted file]
Documentation/DocBook/dvb/dvbstb.png [deleted file]
Documentation/DocBook/dvb/examples.xml [deleted file]
Documentation/DocBook/dvb/frontend.h.xml [deleted file]
Documentation/DocBook/dvb/frontend.xml [deleted file]
Documentation/DocBook/dvb/intro.xml [deleted file]
Documentation/DocBook/dvb/kdapi.xml [deleted file]
Documentation/DocBook/dvb/net.xml [deleted file]
Documentation/DocBook/dvb/video.xml [deleted file]
Documentation/DocBook/media-entities.tmpl [deleted file]
Documentation/DocBook/media-indices.tmpl [deleted file]
Documentation/DocBook/media.tmpl [deleted file]
Documentation/DocBook/media/Makefile [new file with mode: 0644]
Documentation/DocBook/media/bayer.png.b64 [new file with mode: 0644]
Documentation/DocBook/media/crop.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/dvb/.gitignore [new file with mode: 0644]
Documentation/DocBook/media/dvb/audio.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/ca.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/demux.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/dvbapi.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/dvbproperty.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/dvbstb.pdf [new file with mode: 0644]
Documentation/DocBook/media/dvb/examples.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/frontend.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/intro.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/kdapi.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/net.xml [new file with mode: 0644]
Documentation/DocBook/media/dvb/video.xml [new file with mode: 0644]
Documentation/DocBook/media/dvbstb.png.b64 [new file with mode: 0644]
Documentation/DocBook/media/fieldseq_bt.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/fieldseq_tb.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/nv12mt.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/nv12mt_example.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/pipeline.png.b64 [new file with mode: 0644]
Documentation/DocBook/media/v4l/.gitignore [new file with mode: 0644]
Documentation/DocBook/media/v4l/biblio.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/capture.c.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/common.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/compat.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/controls.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/crop.pdf [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-capture.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-codec.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-effect.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-event.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-osd.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-output.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-overlay.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-radio.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-raw-vbi.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-rds.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-sliced-vbi.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-subdev.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/dev-teletext.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/driver.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/fdl-appendix.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/fieldseq_bt.pdf [new file with mode: 0644]
Documentation/DocBook/media/v4l/fieldseq_tb.pdf [new file with mode: 0644]
Documentation/DocBook/media/v4l/func-close.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/func-ioctl.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/func-mmap.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/func-munmap.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/func-open.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/func-poll.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/func-read.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/func-select.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/func-write.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/gen-errors.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/io.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/keytable.c.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/libv4l.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/lirc_device_interface.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/media-controller.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/media-func-close.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/media-func-ioctl.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/media-func-open.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/media-ioc-device-info.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/media-ioc-enum-links.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/media-ioc-setup-link.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pipeline.pdf [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-grey.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-m420.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-nv12.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-nv12m.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-nv16.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-srggb10.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-srggb12.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-srggb8.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-uyvy.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-vyuy.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-y10.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-y10b.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-y12.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-y16.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-y41p.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-yuv410.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-yuv420.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-yuyv.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt-yvyu.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/pixfmt.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/planar-apis.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/remote_controllers.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/subdev-formats.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/v4l2.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/v4l2grab.c.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vbi_525.pdf [new file with mode: 0644]
Documentation/DocBook/media/v4l/vbi_625.pdf [new file with mode: 0644]
Documentation/DocBook/media/v4l/vbi_hsync.pdf [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-cropcap.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-dqevent.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-enumaudio.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-enumaudioout.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-enuminput.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-enumoutput.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-enumstd.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-audio.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-audioout.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-crop.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-enc-index.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-fmt.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-frequency.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-input.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-modulator.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-output.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-parm.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-priority.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-std.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-g-tuner.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-log-status.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-overlay.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-qbuf.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-querybuf.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-querycap.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-queryctrl.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-querystd.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-reqbufs.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-streamon.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml [new file with mode: 0644]
Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml [new file with mode: 0644]
Documentation/DocBook/media/vbi_525.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/vbi_625.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media/vbi_hsync.gif.b64 [new file with mode: 0644]
Documentation/DocBook/media_api.tmpl [new file with mode: 0644]
Documentation/DocBook/v4l/.gitignore [deleted file]
Documentation/DocBook/v4l/bayer.pdf [deleted file]
Documentation/DocBook/v4l/bayer.png [deleted file]
Documentation/DocBook/v4l/biblio.xml [deleted file]
Documentation/DocBook/v4l/capture.c.xml [deleted file]
Documentation/DocBook/v4l/common.xml [deleted file]
Documentation/DocBook/v4l/compat.xml [deleted file]
Documentation/DocBook/v4l/controls.xml [deleted file]
Documentation/DocBook/v4l/crop.gif [deleted file]
Documentation/DocBook/v4l/crop.pdf [deleted file]
Documentation/DocBook/v4l/dev-capture.xml [deleted file]
Documentation/DocBook/v4l/dev-codec.xml [deleted file]
Documentation/DocBook/v4l/dev-effect.xml [deleted file]
Documentation/DocBook/v4l/dev-event.xml [deleted file]
Documentation/DocBook/v4l/dev-osd.xml [deleted file]
Documentation/DocBook/v4l/dev-output.xml [deleted file]
Documentation/DocBook/v4l/dev-overlay.xml [deleted file]
Documentation/DocBook/v4l/dev-radio.xml [deleted file]
Documentation/DocBook/v4l/dev-raw-vbi.xml [deleted file]
Documentation/DocBook/v4l/dev-rds.xml [deleted file]
Documentation/DocBook/v4l/dev-sliced-vbi.xml [deleted file]
Documentation/DocBook/v4l/dev-subdev.xml [deleted file]
Documentation/DocBook/v4l/dev-teletext.xml [deleted file]
Documentation/DocBook/v4l/driver.xml [deleted file]
Documentation/DocBook/v4l/fdl-appendix.xml [deleted file]
Documentation/DocBook/v4l/fieldseq_bt.gif [deleted file]
Documentation/DocBook/v4l/fieldseq_bt.pdf [deleted file]
Documentation/DocBook/v4l/fieldseq_tb.gif [deleted file]
Documentation/DocBook/v4l/fieldseq_tb.pdf [deleted file]
Documentation/DocBook/v4l/func-close.xml [deleted file]
Documentation/DocBook/v4l/func-ioctl.xml [deleted file]
Documentation/DocBook/v4l/func-mmap.xml [deleted file]
Documentation/DocBook/v4l/func-munmap.xml [deleted file]
Documentation/DocBook/v4l/func-open.xml [deleted file]
Documentation/DocBook/v4l/func-poll.xml [deleted file]
Documentation/DocBook/v4l/func-read.xml [deleted file]
Documentation/DocBook/v4l/func-select.xml [deleted file]
Documentation/DocBook/v4l/func-write.xml [deleted file]
Documentation/DocBook/v4l/io.xml [deleted file]
Documentation/DocBook/v4l/keytable.c.xml [deleted file]
Documentation/DocBook/v4l/libv4l.xml [deleted file]
Documentation/DocBook/v4l/lirc_device_interface.xml [deleted file]
Documentation/DocBook/v4l/media-controller.xml [deleted file]
Documentation/DocBook/v4l/media-func-close.xml [deleted file]
Documentation/DocBook/v4l/media-func-ioctl.xml [deleted file]
Documentation/DocBook/v4l/media-func-open.xml [deleted file]
Documentation/DocBook/v4l/media-ioc-device-info.xml [deleted file]
Documentation/DocBook/v4l/media-ioc-enum-entities.xml [deleted file]
Documentation/DocBook/v4l/media-ioc-enum-links.xml [deleted file]
Documentation/DocBook/v4l/media-ioc-setup-link.xml [deleted file]
Documentation/DocBook/v4l/nv12mt.gif [deleted file]
Documentation/DocBook/v4l/nv12mt_example.gif [deleted file]
Documentation/DocBook/v4l/pipeline.pdf [deleted file]
Documentation/DocBook/v4l/pipeline.png [deleted file]
Documentation/DocBook/v4l/pixfmt-grey.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-m420.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-nv12.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-nv12m.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-nv12mt.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-nv16.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-packed-rgb.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-packed-yuv.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-sbggr16.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-sbggr8.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-sgbrg8.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-sgrbg8.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-srggb10.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-srggb12.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-srggb8.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-uyvy.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-vyuy.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-y10.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-y10b.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-y12.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-y16.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-y41p.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-yuv410.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-yuv411p.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-yuv420.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-yuv420m.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-yuv422p.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-yuyv.xml [deleted file]
Documentation/DocBook/v4l/pixfmt-yvyu.xml [deleted file]
Documentation/DocBook/v4l/pixfmt.xml [deleted file]
Documentation/DocBook/v4l/planar-apis.xml [deleted file]
Documentation/DocBook/v4l/remote_controllers.xml [deleted file]
Documentation/DocBook/v4l/subdev-formats.xml [deleted file]
Documentation/DocBook/v4l/v4l2.xml [deleted file]
Documentation/DocBook/v4l/v4l2grab.c.xml [deleted file]
Documentation/DocBook/v4l/vbi_525.gif [deleted file]
Documentation/DocBook/v4l/vbi_525.pdf [deleted file]
Documentation/DocBook/v4l/vbi_625.gif [deleted file]
Documentation/DocBook/v4l/vbi_625.pdf [deleted file]
Documentation/DocBook/v4l/vbi_hsync.gif [deleted file]
Documentation/DocBook/v4l/vbi_hsync.pdf [deleted file]
Documentation/DocBook/v4l/videodev2.h.xml [deleted file]
Documentation/DocBook/v4l/vidioc-cropcap.xml [deleted file]
Documentation/DocBook/v4l/vidioc-dbg-g-chip-ident.xml [deleted file]
Documentation/DocBook/v4l/vidioc-dbg-g-register.xml [deleted file]
Documentation/DocBook/v4l/vidioc-dqevent.xml [deleted file]
Documentation/DocBook/v4l/vidioc-encoder-cmd.xml [deleted file]
Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml [deleted file]
Documentation/DocBook/v4l/vidioc-enum-fmt.xml [deleted file]
Documentation/DocBook/v4l/vidioc-enum-frameintervals.xml [deleted file]
Documentation/DocBook/v4l/vidioc-enum-framesizes.xml [deleted file]
Documentation/DocBook/v4l/vidioc-enumaudio.xml [deleted file]
Documentation/DocBook/v4l/vidioc-enumaudioout.xml [deleted file]
Documentation/DocBook/v4l/vidioc-enuminput.xml [deleted file]
Documentation/DocBook/v4l/vidioc-enumoutput.xml [deleted file]
Documentation/DocBook/v4l/vidioc-enumstd.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-audio.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-audioout.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-crop.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-ctrl.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-dv-preset.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-dv-timings.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-enc-index.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-ext-ctrls.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-fbuf.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-fmt.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-frequency.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-input.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-jpegcomp.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-modulator.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-output.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-parm.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-priority.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-sliced-vbi-cap.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-std.xml [deleted file]
Documentation/DocBook/v4l/vidioc-g-tuner.xml [deleted file]
Documentation/DocBook/v4l/vidioc-log-status.xml [deleted file]
Documentation/DocBook/v4l/vidioc-overlay.xml [deleted file]
Documentation/DocBook/v4l/vidioc-qbuf.xml [deleted file]
Documentation/DocBook/v4l/vidioc-query-dv-preset.xml [deleted file]
Documentation/DocBook/v4l/vidioc-querybuf.xml [deleted file]
Documentation/DocBook/v4l/vidioc-querycap.xml [deleted file]
Documentation/DocBook/v4l/vidioc-queryctrl.xml [deleted file]
Documentation/DocBook/v4l/vidioc-querystd.xml [deleted file]
Documentation/DocBook/v4l/vidioc-reqbufs.xml [deleted file]
Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml [deleted file]
Documentation/DocBook/v4l/vidioc-streamon.xml [deleted file]
Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml [deleted file]
Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml [deleted file]
Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml [deleted file]
Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml [deleted file]
Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml [deleted file]
Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml [deleted file]
Documentation/DocBook/v4l/vidioc-subscribe-event.xml [deleted file]
Documentation/devicetree/bindings/arm/arm-boards [new file with mode: 0644]
Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio_keys.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/arm-versatile.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/arm-versatile.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/fsl-fec.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/smsc-lan91c111.txt [new file with mode: 0644]
Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/samsung-wdt.txt [new file with mode: 0644]
Documentation/dvb/get_dvb_firmware [changed mode: 0644->0755]
Documentation/feature-removal-schedule.txt
Documentation/hwmon/adm1275
Documentation/hwmon/coretemp
Documentation/hwmon/lm25066 [new file with mode: 0644]
Documentation/hwmon/lm90
Documentation/hwmon/lm95245 [new file with mode: 0644]
Documentation/hwmon/max16064
Documentation/hwmon/max1668 [new file with mode: 0644]
Documentation/hwmon/max34440
Documentation/hwmon/max8688
Documentation/hwmon/ntc_thermistor [new file with mode: 0644]
Documentation/hwmon/pmbus
Documentation/hwmon/sysfs-interface
Documentation/md.txt
Documentation/media-framework.txt
Documentation/scsi/ChangeLog.megaraid_sas
Documentation/security/keys-ecryptfs.txt [new file with mode: 0644]
Documentation/security/keys-trusted-encrypted.txt
Documentation/video4linux/API.html
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/CARDLIST.usbvision
Documentation/video4linux/README.davinci-vpbe [new file with mode: 0644]
Documentation/video4linux/v4l2-controls.txt
Documentation/video4linux/v4l2-framework.txt
Documentation/watchdog/00-INDEX
Documentation/watchdog/watchdog-kernel-api.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/alpha/kernel/sys_alcor.c
arch/alpha/kernel/sys_cabriolet.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_eb64p.c
arch/alpha/kernel/sys_eiger.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/sys_miata.c
arch/alpha/kernel/sys_mikasa.c
arch/alpha/kernel/sys_nautilus.c
arch/alpha/kernel/sys_noritake.c
arch/alpha/kernel/sys_rawhide.c
arch/alpha/kernel/sys_ruffian.c
arch/alpha/kernel/sys_rx164.c
arch/alpha/kernel/sys_sable.c
arch/alpha/kernel/sys_sio.c
arch/alpha/kernel/sys_sx164.c
arch/alpha/kernel/sys_takara.c
arch/alpha/kernel/sys_titan.c
arch/alpha/kernel/sys_wildfire.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/Makefile
arch/arm/boot/dts/skeleton.dtsi [new file with mode: 0644]
arch/arm/boot/dts/tegra-harmony.dts [new file with mode: 0644]
arch/arm/boot/dts/tegra-seaboard.dts [new file with mode: 0644]
arch/arm/boot/dts/tegra20.dtsi [new file with mode: 0644]
arch/arm/boot/dts/versatile-ab.dts [new file with mode: 0644]
arch/arm/boot/dts/versatile-pb.dts [new file with mode: 0644]
arch/arm/common/it8152.c
arch/arm/include/asm/hardware/it8152.h
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/mach/pci.h
arch/arm/include/asm/prom.h
arch/arm/kernel/bios32.c
arch/arm/kernel/devtree.c
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at91cap9.c
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/board-1arm.c
arch/arm/mach-at91/board-afeb-9260v1.c
arch/arm/mach-at91/board-cam60.c
arch/arm/mach-at91/board-cap9adk.c
arch/arm/mach-at91/board-carmeva.c
arch/arm/mach-at91/board-cpu9krea.c
arch/arm/mach-at91/board-cpuat91.c
arch/arm/mach-at91/board-csb337.c
arch/arm/mach-at91/board-csb637.c
arch/arm/mach-at91/board-eb9200.c
arch/arm/mach-at91/board-ecbat91.c
arch/arm/mach-at91/board-eco920.c
arch/arm/mach-at91/board-flexibity.c
arch/arm/mach-at91/board-foxg20.c
arch/arm/mach-at91/board-gsia18s.c
arch/arm/mach-at91/board-kafa.c
arch/arm/mach-at91/board-kb9202.c
arch/arm/mach-at91/board-neocore926.c
arch/arm/mach-at91/board-pcontrol-g20.c
arch/arm/mach-at91/board-picotux200.c
arch/arm/mach-at91/board-qil-a9260.c
arch/arm/mach-at91/board-rm9200dk.c
arch/arm/mach-at91/board-rm9200ek.c
arch/arm/mach-at91/board-sam9-l9260.c
arch/arm/mach-at91/board-sam9260ek.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board-snapper9260.c
arch/arm/mach-at91/board-stamp9g20.c
arch/arm/mach-at91/board-usb-a9260.c
arch/arm/mach-at91/board-usb-a9263.c
arch/arm/mach-at91/board-yl-9200.c
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/include/mach/at91_dbgu.h
arch/arm/mach-at91/include/mach/at91_wdt.h [deleted file]
arch/arm/mach-at91/include/mach/at91cap9.h
arch/arm/mach-at91/include/mach/at91rm9200.h
arch/arm/mach-at91/include/mach/at91sam9260.h
arch/arm/mach-at91/include/mach/at91sam9261.h
arch/arm/mach-at91/include/mach/at91sam9263.h
arch/arm/mach-at91/include/mach/at91sam9g45.h
arch/arm/mach-at91/include/mach/at91sam9rl.h
arch/arm/mach-at91/include/mach/cpu.h
arch/arm/mach-at91/include/mach/debug-macro.S
arch/arm/mach-at91/include/mach/hardware.h
arch/arm/mach-at91/include/mach/io.h
arch/arm/mach-at91/setup.c [new file with mode: 0644]
arch/arm/mach-at91/soc.h [new file with mode: 0644]
arch/arm/mach-cns3xxx/pcie.c
arch/arm/mach-dove/pcie.c
arch/arm/mach-footbridge/cats-pci.c
arch/arm/mach-footbridge/ebsa285-pci.c
arch/arm/mach-footbridge/netwinder-pci.c
arch/arm/mach-footbridge/personal-pci.c
arch/arm/mach-imx/clock-imx1.c
arch/arm/mach-imx/clock-imx21.c
arch/arm/mach-imx/clock-imx25.c
arch/arm/mach-imx/clock-imx27.c
arch/arm/mach-imx/clock-imx31.c
arch/arm/mach-imx/clock-imx35.c
arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
arch/arm/mach-imx/mach-mx25_3ds.c
arch/arm/mach-imx/mach-pcm043.c
arch/arm/mach-imx/mm-imx25.c
arch/arm/mach-imx/mm-imx31.c
arch/arm/mach-imx/mm-imx35.c
arch/arm/mach-integrator/pci.c
arch/arm/mach-iop13xx/iq81340mc.c
arch/arm/mach-iop13xx/pci.c
arch/arm/mach-iop32x/em7210.c
arch/arm/mach-iop32x/glantank.c
arch/arm/mach-iop32x/iq31244.c
arch/arm/mach-iop32x/iq80321.c
arch/arm/mach-iop32x/n2100.c
arch/arm/mach-iop33x/iq80331.c
arch/arm/mach-iop33x/iq80332.c
arch/arm/mach-ixp2000/enp2611.c
arch/arm/mach-ixp2000/ixdp2400.c
arch/arm/mach-ixp2000/ixdp2800.c
arch/arm/mach-ixp2000/ixdp2x01.c
arch/arm/mach-ixp23xx/ixdp2351.c
arch/arm/mach-ixp23xx/roadrunner.c
arch/arm/mach-ixp4xx/avila-pci.c
arch/arm/mach-ixp4xx/coyote-pci.c
arch/arm/mach-ixp4xx/dsmg600-pci.c
arch/arm/mach-ixp4xx/fsg-pci.c
arch/arm/mach-ixp4xx/gateway7001-pci.c
arch/arm/mach-ixp4xx/goramo_mlr.c
arch/arm/mach-ixp4xx/gtwx5715-pci.c
arch/arm/mach-ixp4xx/ixdp425-pci.c
arch/arm/mach-ixp4xx/ixdpg425-pci.c
arch/arm/mach-ixp4xx/nas100d-pci.c
arch/arm/mach-ixp4xx/nslu2-pci.c
arch/arm/mach-ixp4xx/vulcan-pci.c
arch/arm/mach-ixp4xx/wg302v2-pci.c
arch/arm/mach-kirkwood/pcie.c
arch/arm/mach-ks8695/board-dsm320.c
arch/arm/mach-ks8695/board-micrel.c
arch/arm/mach-ks8695/include/mach/devices.h
arch/arm/mach-msm/Kconfig
arch/arm/mach-msm/Makefile
arch/arm/mach-msm/gpio-v2.c [deleted file]
arch/arm/mach-msm/gpio.c [deleted file]
arch/arm/mach-msm/gpio_hw.h [deleted file]
arch/arm/mach-msm/gpiomux.h
arch/arm/mach-msm/include/mach/msm_gpiomux.h [new file with mode: 0644]
arch/arm/mach-msm/include/mach/msm_iomap-7x00.h
arch/arm/mach-msm/include/mach/msm_iomap-7x30.h
arch/arm/mach-msm/include/mach/msm_iomap-8x50.h
arch/arm/mach-msm/include/mach/msm_iomap.h
arch/arm/mach-msm/io.c
arch/arm/mach-mv78xx0/pcie.c
arch/arm/mach-mx5/board-mx51_babbage.c
arch/arm/mach-mx5/board-mx53_loco.c
arch/arm/mach-mx5/clock-mx51-mx53.c
arch/arm/mach-mx5/mm.c
arch/arm/mach-mx5/mx51_efika.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/display.c
arch/arm/mach-orion5x/common.h
arch/arm/mach-orion5x/db88f5281-setup.c
arch/arm/mach-orion5x/dns323-setup.c
arch/arm/mach-orion5x/kurobox_pro-setup.c
arch/arm/mach-orion5x/mss2-setup.c
arch/arm/mach-orion5x/pci.c
arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
arch/arm/mach-orion5x/rd88f5182-setup.c
arch/arm/mach-orion5x/terastation_pro2-setup.c
arch/arm/mach-orion5x/ts209-setup.c
arch/arm/mach-orion5x/ts409-setup.c
arch/arm/mach-orion5x/wnr854t-setup.c
arch/arm/mach-orion5x/wrt350n-v2-setup.c
arch/arm/mach-pxa/cm-x2xx-pci.c
arch/arm/mach-sa1100/pci-nanoengine.c
arch/arm/mach-shark/pci.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/clock-sh7367.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/clock-sh7377.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/Makefile.boot
arch/arm/mach-tegra/board-dt.c [new file with mode: 0644]
arch/arm/mach-tegra/pcie.c
arch/arm/mach-versatile/Kconfig
arch/arm/mach-versatile/Makefile
arch/arm/mach-versatile/core.c
arch/arm/mach-versatile/core.h
arch/arm/mach-versatile/pci.c
arch/arm/mach-versatile/versatile_dt.c [new file with mode: 0644]
arch/arm/mach-zynq/Makefile
arch/arm/mach-zynq/board_dt.c [deleted file]
arch/arm/plat-mxc/devices/platform-fec.c
arch/arm/plat-mxc/devices/platform-imx-dma.c
arch/arm/plat-mxc/devices/platform-imx-uart.c
arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c
arch/arm/plat-mxc/include/mach/devices-common.h
arch/arm/plat-mxc/include/mach/dma.h
arch/arm/plat-mxc/include/mach/esdhc.h
arch/arm/plat-mxc/include/mach/sdma.h
arch/frv/mm/pgalloc.c
arch/m68k/Kconfig.mmu
arch/m68k/amiga/chipram.c
arch/m68k/atari/stram.c
arch/m68k/include/asm/atari_stram.h
arch/m68k/include/asm/atarihw.h
arch/m68k/kernel/setup_mm.c
arch/m68k/math-emu/fp_log.c
arch/m68k/math-emu/multi_arith.h
arch/m68k/mm/init_mm.c
arch/microblaze/include/asm/cpuinfo.h
arch/microblaze/include/asm/irqflags.h
arch/microblaze/include/asm/processor.h
arch/microblaze/include/asm/prom.h
arch/microblaze/include/asm/pvr.h
arch/microblaze/include/asm/setup.h
arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
arch/microblaze/kernel/cpu/cpuinfo-static.c
arch/microblaze/kernel/cpu/cpuinfo.c
arch/microblaze/kernel/cpu/mb.c
arch/microblaze/kernel/early_printk.c
arch/microblaze/kernel/hw_exception_handler.S
arch/microblaze/kernel/intc.c
arch/microblaze/kernel/process.c
arch/microblaze/kernel/prom.c
arch/microblaze/kernel/setup.c
arch/sh/Makefile
arch/sh/boards/board-apsh4a3a.c
arch/sh/boards/board-apsh4ad0a.c
arch/sh/boards/board-sh7785lcr.c
arch/sh/boards/board-urquell.c
arch/sh/boards/mach-ap325rxa/setup.c
arch/sh/boards/mach-highlander/setup.c
arch/sh/boards/mach-sdk7786/setup.c
arch/sh/drivers/pci/fixups-cayman.c
arch/sh/drivers/pci/fixups-dreamcast.c
arch/sh/drivers/pci/fixups-landisk.c
arch/sh/drivers/pci/fixups-r7780rp.c
arch/sh/drivers/pci/fixups-rts7751r2d.c
arch/sh/drivers/pci/fixups-sdk7780.c
arch/sh/drivers/pci/fixups-se7751.c
arch/sh/drivers/pci/fixups-sh03.c
arch/sh/drivers/pci/fixups-snapgear.c
arch/sh/drivers/pci/fixups-titan.c
arch/sh/drivers/pci/pcie-sh7786.c
arch/sh/include/asm/pci.h
arch/sh/include/cpu-sh3/cpu/serial.h [new file with mode: 0644]
arch/sh/include/cpu-sh4a/cpu/serial.h [new file with mode: 0644]
arch/sh/kernel/cpu/clock-cpg.c
arch/sh/kernel/cpu/sh3/Makefile
arch/sh/kernel/cpu/sh3/serial-sh770x.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh3/serial-sh7710.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh3/serial-sh7720.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh770x.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c
arch/sh/kernel/cpu/sh4/clock-sh4-202.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4a/Makefile
arch/sh/kernel/cpu/sh4a/clock-sh7343.c
arch/sh/kernel/cpu/sh4a/clock-sh7366.c
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
arch/sh/kernel/cpu/sh4a/clock-sh7723.c
arch/sh/kernel/cpu/sh4a/clock-sh7724.c
arch/sh/kernel/cpu/sh4a/clock-sh7757.c
arch/sh/kernel/cpu/sh4a/clock-sh7763.c
arch/sh/kernel/cpu/sh4a/clock-sh7780.c
arch/sh/kernel/cpu/sh4a/clock-sh7785.c
arch/sh/kernel/cpu/sh4a/clock-sh7786.c
arch/sh/kernel/cpu/sh4a/clock-shx3.c
arch/sh/kernel/cpu/sh4a/serial-sh7722.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7763.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sparc/include/asm/elf_64.h
arch/sparc/include/asm/hypervisor.h
arch/sparc/include/asm/leon_pci.h
arch/sparc/include/asm/spitfire.h
arch/sparc/include/asm/xor_64.h
arch/sparc/kernel/cpu.c
arch/sparc/kernel/cpumap.c
arch/sparc/kernel/head_64.S
arch/sparc/kernel/hvapi.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/leon_pci_grpci2.c
arch/sparc/kernel/pcr.c
arch/sparc/kernel/perf_event.c
arch/sparc/lib/atomic32.c
arch/tile/kernel/pci.c
arch/unicore32/kernel/pci.c
arch/x86/Kconfig
arch/x86/pci/acpi.c
arch/x86/pci/ce4100.c
arch/x86/pci/common.c
arch/x86/pci/direct.c
arch/x86/pci/numaq_32.c
arch/x86/pci/olpc.c
arch/x86/pci/pcbios.c
arch/x86/pci/visws.c
arch/x86/xen/Makefile
drivers/char/hw_random/n2-drv.c
drivers/char/hw_random/n2rng.h
drivers/char/ramoops.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_nsc.c
drivers/char/tpm/tpm_tis.c
drivers/crypto/n2_core.c
drivers/dma/imx-sdma.c
drivers/dma/shdma.c
drivers/dma/shdma.h
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-ab8500.c
drivers/gpio/gpio-msm-v1.c [new file with mode: 0644]
drivers/gpio/gpio-msm-v2.c [new file with mode: 0644]
drivers/gpio/gpio-tps65912.c [new file with mode: 0644]
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/adm1275.c [deleted file]
drivers/hwmon/coretemp.c
drivers/hwmon/lm90.c
drivers/hwmon/lm95241.c
drivers/hwmon/lm95245.c [new file with mode: 0644]
drivers/hwmon/max16064.c [deleted file]
drivers/hwmon/max1668.c [new file with mode: 0644]
drivers/hwmon/max34440.c [deleted file]
drivers/hwmon/max8688.c [deleted file]
drivers/hwmon/ntc_thermistor.c [new file with mode: 0644]
drivers/hwmon/pmbus.c [deleted file]
drivers/hwmon/pmbus.h [deleted file]
drivers/hwmon/pmbus/Kconfig [new file with mode: 0644]
drivers/hwmon/pmbus/Makefile [new file with mode: 0644]
drivers/hwmon/pmbus/adm1275.c [new file with mode: 0644]
drivers/hwmon/pmbus/lm25066.c [new file with mode: 0644]
drivers/hwmon/pmbus/max16064.c [new file with mode: 0644]
drivers/hwmon/pmbus/max34440.c [new file with mode: 0644]
drivers/hwmon/pmbus/max8688.c [new file with mode: 0644]
drivers/hwmon/pmbus/pmbus.c [new file with mode: 0644]
drivers/hwmon/pmbus/pmbus.h [new file with mode: 0644]
drivers/hwmon/pmbus/pmbus_core.c [new file with mode: 0644]
drivers/hwmon/pmbus/ucd9000.c [new file with mode: 0644]
drivers/hwmon/pmbus/ucd9200.c [new file with mode: 0644]
drivers/hwmon/pmbus_core.c [deleted file]
drivers/hwmon/ucd9000.c [deleted file]
drivers/hwmon/ucd9200.c [deleted file]
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/adp5589-keys.c
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/lm8323.c
drivers/input/keyboard/mpr121_touchkey.c
drivers/input/keyboard/pmic8xxx-keypad.c
drivers/input/keyboard/qt1070.c
drivers/input/keyboard/sh_keysc.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/keyboard/tnetv107x-keypad.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/bfin_rotary.c
drivers/input/misc/kxtj9.c [new file with mode: 0644]
drivers/input/misc/mma8450.c [new file with mode: 0644]
drivers/input/misc/mpu3050.c [new file with mode: 0644]
drivers/input/misc/xen-kbdfront.c
drivers/input/mouse/gpio_mouse.c
drivers/input/mouse/lifebook.c
drivers/input/mouse/pxa930_trkball.c
drivers/input/mouse/sentelic.c
drivers/input/mouse/synaptics.c
drivers/input/mouse/synaptics.h
drivers/input/serio/at32psif.c
drivers/input/serio/hp_sdc.c
drivers/input/tablet/aiptek.c
drivers/input/tablet/wacom_wac.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/atmel-wm97xx.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/cy8ctmg110_ts.c
drivers/input/touchscreen/intel-mid-touch.c
drivers/input/touchscreen/mainstone-wm97xx.c
drivers/input/touchscreen/tnetv107x-ts.c
drivers/input/touchscreen/wm9705.c
drivers/input/touchscreen/wm9712.c
drivers/input/touchscreen/wm9713.c
drivers/input/touchscreen/zylonite-wm97xx.c
drivers/isdn/i4l/isdn_net.c
drivers/md/bitmap.c
drivers/md/bitmap.h
drivers/md/md.c
drivers/md/md.h
drivers/md/raid1.c
drivers/md/raid1.h
drivers/md/raid10.c
drivers/md/raid10.h
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/Kconfig
drivers/media/common/tuners/Kconfig
drivers/media/common/tuners/Makefile
drivers/media/common/tuners/tuner-types.c
drivers/media/common/tuners/xc4000.c [new file with mode: 0644]
drivers/media/common/tuners/xc4000.h [new file with mode: 0644]
drivers/media/dvb/Kconfig
drivers/media/dvb/Makefile
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/dvb/ddbridge/Kconfig [new file with mode: 0644]
drivers/media/dvb/ddbridge/Makefile [new file with mode: 0644]
drivers/media/dvb/ddbridge/ddbridge-core.c [new file with mode: 0644]
drivers/media/dvb/ddbridge/ddbridge-regs.h [new file with mode: 0644]
drivers/media/dvb/ddbridge/ddbridge.h [new file with mode: 0644]
drivers/media/dvb/dvb-core/Makefile
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_net.h
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/anysee.h
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/gp8psk.h
drivers/media/dvb/dvb-usb/technisat-usb2.c
drivers/media/dvb/dvb-usb/vp7045.h
drivers/media/dvb/firewire/firedtv-avc.c
drivers/media/dvb/firewire/firedtv-ci.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/au8522_decoder.c
drivers/media/dvb/frontends/cx24113.c
drivers/media/dvb/frontends/cx24116.c
drivers/media/dvb/frontends/cxd2820r.h
drivers/media/dvb/frontends/cxd2820r_core.c
drivers/media/dvb/frontends/cxd2820r_priv.h
drivers/media/dvb/frontends/dib7000p.c
drivers/media/dvb/frontends/drxd_hard.c
drivers/media/dvb/frontends/drxk.h [new file with mode: 0644]
drivers/media/dvb/frontends/drxk_hard.c [new file with mode: 0644]
drivers/media/dvb/frontends/drxk_hard.h [new file with mode: 0644]
drivers/media/dvb/frontends/drxk_map.h [new file with mode: 0644]
drivers/media/dvb/frontends/itd1000.c
drivers/media/dvb/frontends/nxt6000.c
drivers/media/dvb/frontends/s5h1420.c
drivers/media/dvb/frontends/tda18271c2dd.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda18271c2dd.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda18271c2dd_maps.h [new file with mode: 0644]
drivers/media/dvb/ngene/Kconfig
drivers/media/dvb/ngene/ngene-cards.c
drivers/media/dvb/ngene/ngene-core.c
drivers/media/dvb/ngene/ngene-dvb.c
drivers/media/dvb/ngene/ngene.h
drivers/media/dvb/siano/smscoreapi.c
drivers/media/dvb/siano/smscoreapi.h
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-aztech.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-tea5764.c
drivers/media/radio/radio-terratec.c
drivers/media/radio/radio-timb.c
drivers/media/radio/radio-trust.c
drivers/media/radio/radio-typhoon.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/radio-zoltrix.c
drivers/media/radio/si470x/radio-si470x-i2c.c
drivers/media/radio/si470x/radio-si470x-usb.c
drivers/media/radio/si470x/radio-si470x.h
drivers/media/radio/wl128x/fmdrv.h
drivers/media/radio/wl128x/fmdrv_v4l2.c
drivers/media/rc/Kconfig
drivers/media/rc/Makefile
drivers/media/rc/ene_ir.c
drivers/media/rc/ene_ir.h
drivers/media/rc/ir-lirc-codec.c
drivers/media/rc/ir-mce_kbd-decoder.c [new file with mode: 0644]
drivers/media/rc/ir-raw.c
drivers/media/rc/ite-cir.c
drivers/media/rc/keymaps/rc-rc6-mce.c
drivers/media/rc/mceusb.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/rc-core-priv.h
drivers/media/rc/rc-loopback.c
drivers/media/rc/rc-main.c
drivers/media/rc/redrat3.c
drivers/media/rc/winbond-cir.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adp1653.c [new file with mode: 0644]
drivers/media/video/arv.c
drivers/media/video/atmel-isi.c [new file with mode: 0644]
drivers/media/video/au0828/au0828-core.c
drivers/media/video/au0828/au0828-video.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/bw-qcam.c
drivers/media/video/c-qcam.c
drivers/media/video/cafe_ccic-regs.h [deleted file]
drivers/media/video/cafe_ccic.c [deleted file]
drivers/media/video/cpia2/cpia2.h
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx18/cx18-alsa-main.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-version.h
drivers/media/video/cx231xx/cx231xx-avcore.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx231xx/cx231xx-core.c
drivers/media/video/cx231xx/cx231xx-video.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx23885/altera-ci.c
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-input.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/davinci/Kconfig
drivers/media/video/davinci/Makefile
drivers/media/video/davinci/vpbe.c [new file with mode: 0644]
drivers/media/video/davinci/vpbe_display.c [new file with mode: 0644]
drivers/media/video/davinci/vpbe_osd.c [new file with mode: 0644]
drivers/media/video/davinci/vpbe_osd_regs.h [new file with mode: 0644]
drivers/media/video/davinci/vpbe_venc.c [new file with mode: 0644]
drivers/media/video/davinci/vpbe_venc_regs.h [new file with mode: 0644]
drivers/media/video/davinci/vpif_capture.c
drivers/media/video/davinci/vpif_capture.h
drivers/media/video/davinci/vpif_display.c
drivers/media/video/davinci/vpif_display.h
drivers/media/video/em28xx/Kconfig
drivers/media/video/em28xx/Makefile
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-reg.h
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/et61x251/et61x251.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/fsl-viu.c
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/gl860/gl860.h
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/se401.c [new file with mode: 0644]
drivers/media/video/gspca/se401.h [new file with mode: 0644]
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/hdpvr/hdpvr-core.c
drivers/media/video/hdpvr/hdpvr-video.c
drivers/media/video/hdpvr/hdpvr.h
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-version.h
drivers/media/video/m5mols/m5mols_capture.c
drivers/media/video/m5mols/m5mols_core.c
drivers/media/video/marvell-ccic/Kconfig [new file with mode: 0644]
drivers/media/video/marvell-ccic/Makefile [new file with mode: 0644]
drivers/media/video/marvell-ccic/cafe-driver.c [new file with mode: 0644]
drivers/media/video/marvell-ccic/mcam-core.c [new file with mode: 0644]
drivers/media/video/marvell-ccic/mcam-core.h [new file with mode: 0644]
drivers/media/video/marvell-ccic/mmp-driver.c [new file with mode: 0644]
drivers/media/video/mem2mem_testdev.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9t031.c
drivers/media/video/mt9t112.c
drivers/media/video/mt9v011.c
drivers/media/video/mt9v022.c
drivers/media/video/mt9v032.c
drivers/media/video/mx1_camera.c
drivers/media/video/mx2_camera.c
drivers/media/video/mx3_camera.c
drivers/media/video/omap/Kconfig
drivers/media/video/omap/Makefile
drivers/media/video/omap/omap_vout.c
drivers/media/video/omap/omap_vout_vrfb.c [new file with mode: 0644]
drivers/media/video/omap/omap_vout_vrfb.h [new file with mode: 0644]
drivers/media/video/omap/omap_voutdef.h
drivers/media/video/omap/omap_voutlib.c
drivers/media/video/omap/omap_voutlib.h
drivers/media/video/omap1_camera.c
drivers/media/video/omap24xxcam.c
drivers/media/video/omap3isp/isp.c
drivers/media/video/omap3isp/isp.h
drivers/media/video/omap3isp/ispccdc.c
drivers/media/video/omap3isp/ispccp2.c
drivers/media/video/omap3isp/ispccp2.h
drivers/media/video/omap3isp/ispstat.c
drivers/media/video/omap3isp/ispvideo.c
drivers/media/video/omap3isp/ispvideo.h
drivers/media/video/ov2640.c
drivers/media/video/ov5642.c [new file with mode: 0644]
drivers/media/video/ov7670.c
drivers/media/video/ov7670.h [deleted file]
drivers/media/video/ov772x.c
drivers/media/video/ov9640.c
drivers/media/video/ov9740.c
drivers/media/video/pms.c
drivers/media/video/pvrusb2/pvrusb2-main.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/Kconfig
drivers/media/video/pwc/pwc-ctrl.c
drivers/media/video/pwc/pwc-dec1.c
drivers/media/video/pwc/pwc-dec1.h
drivers/media/video/pwc/pwc-dec23.c
drivers/media/video/pwc/pwc-dec23.h
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-ioctl.h [deleted file]
drivers/media/video/pwc/pwc-kiara.c
drivers/media/video/pwc/pwc-misc.c
drivers/media/video/pwc/pwc-uncompress.c
drivers/media/video/pwc/pwc-uncompress.h [deleted file]
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pwc/pwc.h
drivers/media/video/pxa_camera.c
drivers/media/video/rj54n1cb0c.c
drivers/media/video/s2255drv.c
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/s5p-mfc/Makefile [new file with mode: 0644]
drivers/media/video/s5p-mfc/regs-mfc.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_cmd.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_cmd.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_common.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_debug.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_dec.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_dec.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_enc.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_enc.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_intr.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_intr.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_opr.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_opr.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_pm.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_pm.h [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_shm.c [new file with mode: 0644]
drivers/media/video/s5p-mfc/s5p_mfc_shm.h [new file with mode: 0644]
drivers/media/video/s5p-tv/Kconfig [new file with mode: 0644]
drivers/media/video/s5p-tv/Makefile [new file with mode: 0644]
drivers/media/video/s5p-tv/hdmi_drv.c [new file with mode: 0644]
drivers/media/video/s5p-tv/hdmiphy_drv.c [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer.h [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer_drv.c [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer_grp_layer.c [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer_reg.c [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer_video.c [new file with mode: 0644]
drivers/media/video/s5p-tv/mixer_vp_layer.c [new file with mode: 0644]
drivers/media/video/s5p-tv/regs-hdmi.h [new file with mode: 0644]
drivers/media/video/s5p-tv/regs-mixer.h [new file with mode: 0644]
drivers/media/video/s5p-tv/regs-sdo.h [new file with mode: 0644]
drivers/media/video/s5p-tv/regs-vp.h [new file with mode: 0644]
drivers/media/video/s5p-tv/sdo_drv.c [new file with mode: 0644]
drivers/media/video/saa7115.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa7164/saa7164-encoder.c
drivers/media/video/saa7164/saa7164-vbi.c
drivers/media/video/saa7164/saa7164.h
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sh_mobile_csi2.c
drivers/media/video/sh_vou.c
drivers/media/video/sn9c102/sn9c102.h
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/soc_camera.c
drivers/media/video/soc_camera_platform.c
drivers/media/video/sr030pc30.c
drivers/media/video/tda7432.c
drivers/media/video/timblogiw.c
drivers/media/video/tlg2300/pd-common.h
drivers/media/video/tlg2300/pd-main.c
drivers/media/video/tlg2300/pd-radio.c
drivers/media/video/tuner-core.c
drivers/media/video/tw9910.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-ctrls.c
drivers/media/video/v4l2-device.c
drivers/media/video/v4l2-event.c
drivers/media/video/v4l2-fh.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-subdev.c
drivers/media/video/videobuf-dma-sg.c
drivers/media/video/videobuf2-dma-sg.c
drivers/media/video/videobuf2-memops.c
drivers/media/video/vino.c
drivers/media/video/vivi.c
drivers/media/video/w9966.c
drivers/media/video/zoran/zoran.h
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zoran/zoran_driver.c
drivers/media/video/zr364xx.c
drivers/message/fusion/mptscsih.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/aat2870-core.c [new file with mode: 0644]
drivers/mfd/ab3550-core.c
drivers/mfd/ab8500-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/jz4740-adc.c
drivers/mfd/lpc_sch.c
drivers/mfd/max8997-irq.c
drivers/mfd/max8998.c
drivers/mfd/omap-usb-host.c
drivers/mfd/stmpe.c
drivers/mfd/stmpe.h
drivers/mfd/timberdale.c
drivers/mfd/tps65910.c
drivers/mfd/tps65911-comparator.c
drivers/mfd/tps65912-core.c [new file with mode: 0644]
drivers/mfd/tps65912-i2c.c [new file with mode: 0644]
drivers/mfd/tps65912-irq.c [new file with mode: 0644]
drivers/mfd/tps65912-spi.c [new file with mode: 0644]
drivers/mfd/twl-core.c
drivers/mfd/twl4030-madc.c
drivers/mfd/twl6030-pwm.c
drivers/mfd/wm831x-auxadc.c [new file with mode: 0644]
drivers/mfd/wm831x-core.c
drivers/mfd/wm831x-irq.c
drivers/mfd/wm8350-irq.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-irq.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-pltfm.c
drivers/net/Makefile
drivers/net/acenic.c
drivers/net/acenic.h
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/fec.c
drivers/net/forcedeth.c
drivers/net/gianfar.c
drivers/net/ibm_newemac/core.c
drivers/net/ibm_newemac/emac.h
drivers/net/ibm_newemac/phy.c
drivers/net/ifb.c
drivers/net/macvlan.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/sungem.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/tun.c
drivers/net/usb/asix.c
drivers/net/veth.c
drivers/net/wan/hdlc_fr.c
drivers/net/wireless/airo.c
drivers/net/wireless/b43/Kconfig
drivers/net/wireless/b43/bus.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/hostap/hostap_main.c
drivers/net/wireless/orinoco/orinoco_cs.c
drivers/nfc/pn533.c
drivers/of/gpio.c
drivers/of/of_net.c
drivers/pci/hotplug/acpi_pcihp.c
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/pci.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/aer/aerdrv_errprint.c
drivers/pci/probe.c
drivers/pci/setup-bus.c
drivers/pci/setup-irq.c
drivers/pci/setup-res.c
drivers/pcmcia/pxa2xx_balloon3.c
drivers/pcmcia/pxa2xx_cm_x255.c
drivers/pcmcia/pxa2xx_cm_x270.c
drivers/pcmcia/pxa2xx_colibri.c
drivers/pcmcia/pxa2xx_mainstone.c
drivers/pcmcia/pxa2xx_palmld.c
drivers/pcmcia/pxa2xx_palmtc.c
drivers/pcmcia/pxa2xx_palmtx.c
drivers/pcmcia/pxa2xx_stargate2.c
drivers/pcmcia/pxa2xx_viper.c
drivers/pcmcia/soc_common.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/apm_power.c
drivers/power/bq20z75.c
drivers/power/gpio-charger.c
drivers/power/max17042_battery.c
drivers/power/max8903_charger.c
drivers/power/max8997_charger.c [new file with mode: 0644]
drivers/power/max8998_charger.c [new file with mode: 0644]
drivers/power/s3c_adc_battery.c
drivers/power/twl4030_charger.c
drivers/power/wm831x_backup.c
drivers/power/wm831x_power.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/aat2870-regulator.c [new file with mode: 0644]
drivers/regulator/tps65912-regulator.c [new file with mode: 0644]
drivers/scsi/be2iscsi/be_main.h
drivers/scsi/bfa/bfa.h
drivers/scsi/bfa/bfa_core.c
drivers/scsi/bfa/bfa_defs.h
drivers/scsi/bfa/bfa_defs_svc.h
drivers/scsi/bfa/bfa_fc.h
drivers/scsi/bfa/bfa_fcpim.c
drivers/scsi/bfa/bfa_fcpim.h
drivers/scsi/bfa/bfa_fcs.c
drivers/scsi/bfa/bfa_fcs.h
drivers/scsi/bfa/bfa_fcs_fcpim.c
drivers/scsi/bfa/bfa_fcs_lport.c
drivers/scsi/bfa/bfa_fcs_rport.c
drivers/scsi/bfa/bfa_hw_cb.c
drivers/scsi/bfa/bfa_hw_ct.c
drivers/scsi/bfa/bfa_ioc.c
drivers/scsi/bfa/bfa_ioc.h
drivers/scsi/bfa/bfa_modules.h
drivers/scsi/bfa/bfa_svc.c
drivers/scsi/bfa/bfa_svc.h
drivers/scsi/bfa/bfad.c
drivers/scsi/bfa/bfad_bsg.c
drivers/scsi/bfa/bfad_bsg.h
drivers/scsi/bfa/bfad_drv.h
drivers/scsi/bfa/bfad_im.c
drivers/scsi/bfa/bfad_im.h
drivers/scsi/bfa/bfi.h
drivers/scsi/bnx2fc/bnx2fc.h
drivers/scsi/bnx2fc/bnx2fc_debug.h
drivers/scsi/bnx2fc/bnx2fc_els.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2fc/bnx2fc_hwi.c
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/bnx2fc/bnx2fc_tgt.c
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/device_handler/scsi_dh_rdac.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/hpsa.c
drivers/scsi/hpsa.h
drivers/scsi/ipr.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libiscsi.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/scsi/lpfc/lpfc_debugfs.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_hw4.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fp.c
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/mvsas/Kconfig
drivers/scsi/mvsas/mv_64xx.c
drivers/scsi/mvsas/mv_94xx.c
drivers/scsi/mvsas/mv_94xx.h
drivers/scsi/mvsas/mv_chips.h
drivers/scsi/mvsas/mv_defs.h
drivers/scsi/mvsas/mv_init.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h
drivers/scsi/pmcraid.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_dbg.h
drivers/scsi/qla2xxx/qla_dfs.c
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_nx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_transport_spi.c
drivers/sh/clk/core.c
drivers/staging/ath6kl/os/linux/ar6000_drv.c
drivers/staging/brcm80211/brcmsmac/mac80211_if.h
drivers/staging/cxd2099/Kconfig
drivers/staging/cxd2099/cxd2099.c
drivers/staging/cxd2099/cxd2099.h
drivers/staging/tm6000/tm6000-alsa.c
drivers/target/Kconfig
drivers/target/Makefile
drivers/target/iscsi/Kconfig [new file with mode: 0644]
drivers/target/iscsi/Makefile [new file with mode: 0644]
drivers/target/iscsi/iscsi_target.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_auth.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_auth.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_configfs.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_configfs.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_core.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_datain_values.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_datain_values.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_device.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_device.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_erl0.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_erl0.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_erl1.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_erl1.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_erl2.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_erl2.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_login.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_login.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_nego.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_nego.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_nodeattrib.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_nodeattrib.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_parameters.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_parameters.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_seq_pdu_list.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_seq_pdu_list.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_stat.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_stat.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_tmr.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_tmr.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_tpg.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_tpg.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_tq.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_tq.h [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_util.c [new file with mode: 0644]
drivers/target/iscsi/iscsi_target_util.h [new file with mode: 0644]
drivers/target/target_core_transport.c
drivers/tty/serial/Kconfig
drivers/tty/serial/imx.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sh-sci.h
drivers/usb/gadget/uvc_v4l2.c
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/aat2870_bl.c [new file with mode: 0644]
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/dss/Kconfig
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/display.c
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.h
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/venc.c
drivers/video/omap2/omapfb/omapfb-ioctl.c
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/omap2/omapfb/omapfb-sysfs.c
drivers/video/omap2/omapfb/omapfb.h
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/at91sam9_wdt.c
drivers/watchdog/at91sam9_wdt.h [new file with mode: 0644]
drivers/watchdog/dw_wdt.c [new file with mode: 0644]
drivers/watchdog/hpwdt.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/imx2_wdt.c
drivers/watchdog/it8712f_wdt.c
drivers/watchdog/it87_wdt.c
drivers/watchdog/mpcore_wdt.c
drivers/watchdog/mtx-1_wdt.c
drivers/watchdog/of_xilinx_wdt.c [new file with mode: 0644]
drivers/watchdog/pc87413_wdt.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sch311x_wdt.c
drivers/watchdog/sp805_wdt.c
drivers/watchdog/watchdog_core.c [new file with mode: 0644]
drivers/watchdog/watchdog_dev.c [new file with mode: 0644]
drivers/watchdog/watchdog_dev.h [new file with mode: 0644]
drivers/xen/grant-table.c
drivers/xen/xen-pciback/xenbus.c
drivers/xen/xen-selfballoon.c
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/dir-item.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/locking.c
fs/btrfs/locking.h
fs/btrfs/relocation.c
fs/btrfs/struct-funcs.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/xattr.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/misc.c
fs/cifs/sess.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/inode.c
fs/ecryptfs/keystore.c
fs/ext2/acl.h
fs/fs-writeback.c
fs/gfs2/ops_fstype.c
fs/jfs/jfs_dmap.c
fs/jfs/jfs_txnmgr.c
fs/jfs/namei.c
fs/lockd/clntproc.c
fs/nfs/Kconfig
fs/nfs/Makefile
fs/nfs/blocklayout/Makefile [new file with mode: 0644]
fs/nfs/blocklayout/blocklayout.c [new file with mode: 0644]
fs/nfs/blocklayout/blocklayout.h [new file with mode: 0644]
fs/nfs/blocklayout/blocklayoutdev.c [new file with mode: 0644]
fs/nfs/blocklayout/blocklayoutdm.c [new file with mode: 0644]
fs/nfs/blocklayout/extents.c [new file with mode: 0644]
fs/nfs/callback_proc.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/internal.h
fs/nfs/namespace.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayout.h
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/objlayout/objio_osd.c
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/pnfs_dev.c
fs/nfs/read.c
fs/nfs/unlink.c
fs/nfs/write.c
fs/proc/generic.c
fs/proc/proc_net.c
fs/proc/root.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/xfs_acl.h
fs/xfs/xfs_da_btree.c
include/keys/encrypted-type.h
include/linux/aer.h
include/linux/dvb/audio.h
include/linux/ecryptfs.h [new file with mode: 0644]
include/linux/if.h
include/linux/input.h
include/linux/input/kxtj9.h [new file with mode: 0644]
include/linux/ioport.h
include/linux/irq.h
include/linux/irqdomain.h [new file with mode: 0644]
include/linux/kconfig.h [new file with mode: 0644]
include/linux/kernel.h
include/linux/mfd/aat2870.h [new file with mode: 0644]
include/linux/mfd/ab8500.h
include/linux/mfd/max8997.h
include/linux/mfd/max8998.h
include/linux/mfd/stmpe.h
include/linux/mfd/tps65910.h
include/linux/mfd/tps65912.h [new file with mode: 0644]
include/linux/mfd/wm831x/core.h
include/linux/mfd/wm831x/pdata.h
include/linux/mm_types.h
include/linux/netdevice.h
include/linux/nfs.h
include/linux/nfs4.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/of_gpio.h
include/linux/of_irq.h
include/linux/of_net.h
include/linux/page-flags.h
include/linux/pci.h
include/linux/phy.h
include/linux/platform_data/ntc_thermistor.h [new file with mode: 0644]
include/linux/pnfs_osd_xdr.h
include/linux/power/bq20z75.h
include/linux/power/max17042_battery.h
include/linux/proc_fs.h
include/linux/raid/md_p.h
include/linux/serial_sci.h
include/linux/sh_clk.h
include/linux/sh_dma.h
include/linux/shm.h
include/linux/slub_def.h
include/linux/sunrpc/bc_xprt.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/xprt.h
include/linux/videodev2.h
include/linux/watchdog.h
include/linux/wm97xx.h
include/media/adp1653.h [new file with mode: 0644]
include/media/atmel-isi.h [new file with mode: 0644]
include/media/davinci/vpbe.h [new file with mode: 0644]
include/media/davinci/vpbe_display.h [new file with mode: 0644]
include/media/davinci/vpbe_osd.h [new file with mode: 0644]
include/media/davinci/vpbe_types.h [new file with mode: 0644]
include/media/davinci/vpbe_venc.h [new file with mode: 0644]
include/media/mmp-camera.h [new file with mode: 0644]
include/media/ov7670.h [new file with mode: 0644]
include/media/rc-core.h
include/media/rc-map.h
include/media/sh_mobile_ceu.h
include/media/sh_mobile_csi2.h
include/media/soc_camera.h
include/media/soc_camera_platform.h
include/media/timb_radio.h
include/media/tuner.h
include/media/v4l2-chip-ident.h
include/media/v4l2-ctrls.h
include/media/v4l2-event.h
include/media/v4l2-fh.h
include/media/v4l2-mediabus.h
include/media/v4l2-subdev.h
include/pcmcia/device_id.h
include/scsi/fc_frame.h
include/scsi/iscsi_proto.h
include/sound/pcm.h
include/sound/pcm_params.h
include/sound/soc-dapm.h
include/sound/tea575x-tuner.h
include/trace/events/xen.h
include/video/omapdss.h
ipc/shm.c
kernel/cgroup.c
kernel/compat.c
kernel/irq/Kconfig
kernel/irq/Makefile
kernel/irq/irqdomain.c [new file with mode: 0644]
kernel/resource.c
kernel/signal.c
mm/slab.c
mm/slub.c
net/8021q/vlan_dev.c
net/bluetooth/bnep/netdev.c
net/core/dev.c
net/core/pktgen.c
net/ethernet/eth.c
net/ipv4/devinet.c
net/ipv6/addrconf.c
net/l2tp/l2tp_eth.c
net/mac80211/iface.c
net/socket.c
net/sunrpc/Kconfig
net/sunrpc/Makefile
net/sunrpc/backchannel_rqst.c
net/sunrpc/bc_svc.c
net/sunrpc/clnt.c
net/sunrpc/sched.c
net/sunrpc/svc.c
net/sunrpc/svcsock.c
net/sunrpc/xdr.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtrdma/xprt_rdma.h
net/sunrpc/xprtsock.c
net/wireless/reg.c
scripts/kconfig/Makefile
scripts/kconfig/conf.c
scripts/kconfig/confdata.c
scripts/kconfig/expr.c
scripts/kconfig/expr.h
scripts/kconfig/gconf.c
scripts/kconfig/kconfig_load.c [deleted file]
scripts/kconfig/kxgettext.c
scripts/kconfig/lkc.h
scripts/kconfig/lkc_proto.h
scripts/kconfig/mconf.c
scripts/kconfig/menu.c
scripts/kconfig/nconf.c
scripts/kconfig/qconf.cc
scripts/kconfig/qconf.h
scripts/kconfig/symbol.c
scripts/kconfig/util.c
scripts/kconfig/zconf.l
scripts/kconfig/zconf.lex.c_shipped
scripts/kconfig/zconf.tab.c_shipped
scripts/kconfig/zconf.y
security/apparmor/domain.c
security/apparmor/lsm.c
security/keys/Makefile
security/keys/ecryptfs_format.c [new file with mode: 0644]
security/keys/ecryptfs_format.h [new file with mode: 0644]
security/keys/encrypted.c
security/keys/request_key_auth.c
security/tomoyo/Kconfig
security/tomoyo/Makefile
security/tomoyo/audit.c [new file with mode: 0644]
security/tomoyo/common.c
security/tomoyo/common.h
security/tomoyo/condition.c [new file with mode: 0644]
security/tomoyo/domain.c
security/tomoyo/file.c
security/tomoyo/gc.c
security/tomoyo/group.c
security/tomoyo/load_policy.c
security/tomoyo/memory.c
security/tomoyo/mount.c
security/tomoyo/realpath.c
security/tomoyo/securityfs_if.c
security/tomoyo/tomoyo.c
security/tomoyo/util.c
sound/core/pcm_lib.c
sound/i2c/other/tea575x-tuner.c
sound/oss/ad1848.c
sound/oss/sb_mixer.c
sound/pci/Kconfig
sound/pci/asihpi/asihpi.c
sound/pci/asihpi/hpioctl.c
sound/pci/hda/Kconfig
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_local.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/wm8962.c
sound/soc/davinci/davinci-vcif.c
sound/soc/samsung/i2s.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
tools/power/cpupower/.gitignore [new file with mode: 0644]
tools/power/cpupower/Makefile [new file with mode: 0644]
tools/power/cpupower/README [new file with mode: 0644]
tools/power/cpupower/ToDo [new file with mode: 0644]
tools/power/cpupower/bench/Makefile [new file with mode: 0644]
tools/power/cpupower/bench/README-BENCH [new file with mode: 0644]
tools/power/cpupower/bench/benchmark.c [new file with mode: 0644]
tools/power/cpupower/bench/benchmark.h [new file with mode: 0644]
tools/power/cpupower/bench/config.h [new file with mode: 0644]
tools/power/cpupower/bench/cpufreq-bench_plot.sh [new file with mode: 0644]
tools/power/cpupower/bench/cpufreq-bench_script.sh [new file with mode: 0644]
tools/power/cpupower/bench/example.cfg [new file with mode: 0644]
tools/power/cpupower/bench/main.c [new file with mode: 0644]
tools/power/cpupower/bench/parse.c [new file with mode: 0644]
tools/power/cpupower/bench/parse.h [new file with mode: 0644]
tools/power/cpupower/bench/system.c [new file with mode: 0644]
tools/power/cpupower/bench/system.h [new file with mode: 0644]
tools/power/cpupower/debug/i386/Makefile [new file with mode: 0644]
tools/power/cpupower/debug/i386/centrino-decode.c [new file with mode: 0644]
tools/power/cpupower/debug/i386/dump_psb.c [new file with mode: 0644]
tools/power/cpupower/debug/i386/intel_gsic.c [new file with mode: 0644]
tools/power/cpupower/debug/i386/powernow-k8-decode.c [new file with mode: 0644]
tools/power/cpupower/debug/kernel/Makefile [new file with mode: 0644]
tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c [new file with mode: 0644]
tools/power/cpupower/debug/x86_64/Makefile [new file with mode: 0644]
tools/power/cpupower/debug/x86_64/centrino-decode.c [new symlink]
tools/power/cpupower/debug/x86_64/powernow-k8-decode.c [new symlink]
tools/power/cpupower/lib/cpufreq.c [new file with mode: 0644]
tools/power/cpupower/lib/cpufreq.h [new file with mode: 0644]
tools/power/cpupower/lib/sysfs.c [new file with mode: 0644]
tools/power/cpupower/lib/sysfs.h [new file with mode: 0644]
tools/power/cpupower/man/cpupower-frequency-info.1 [new file with mode: 0644]
tools/power/cpupower/man/cpupower-frequency-set.1 [new file with mode: 0644]
tools/power/cpupower/man/cpupower-info.1 [new file with mode: 0644]
tools/power/cpupower/man/cpupower-monitor.1 [new file with mode: 0644]
tools/power/cpupower/man/cpupower-set.1 [new file with mode: 0644]
tools/power/cpupower/man/cpupower.1 [new file with mode: 0644]
tools/power/cpupower/po/cs.po [new file with mode: 0644]
tools/power/cpupower/po/de.po [new file with mode: 0644]
tools/power/cpupower/po/fr.po [new file with mode: 0644]
tools/power/cpupower/po/it.po [new file with mode: 0644]
tools/power/cpupower/po/pt.po [new file with mode: 0644]
tools/power/cpupower/utils/builtin.h [new file with mode: 0644]
tools/power/cpupower/utils/cpufreq-info.c [new file with mode: 0644]
tools/power/cpupower/utils/cpufreq-set.c [new file with mode: 0644]
tools/power/cpupower/utils/cpuidle-info.c [new file with mode: 0644]
tools/power/cpupower/utils/cpupower-info.c [new file with mode: 0644]
tools/power/cpupower/utils/cpupower-set.c [new file with mode: 0644]
tools/power/cpupower/utils/cpupower.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/amd.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/bitmask.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/bitmask.h [new file with mode: 0644]
tools/power/cpupower/utils/helpers/cpuid.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/helpers.h [new file with mode: 0644]
tools/power/cpupower/utils/helpers/misc.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/msr.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/pci.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/sysfs.c [new file with mode: 0644]
tools/power/cpupower/utils/helpers/sysfs.h [new file with mode: 0644]
tools/power/cpupower/utils/helpers/topology.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/idle_monitors.def [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/idle_monitors.h [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/mperf_monitor.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/nhm_idle.c [new file with mode: 0644]
tools/power/cpupower/utils/idle_monitor/snb_idle.c [new file with mode: 0644]
tools/power/cpupower/utils/version-gen.sh [new file with mode: 0755]
tools/slub/slabinfo.c

diff --git a/CREDITS b/CREDITS
index 1deb331d96edbe60f3026ce4175dc0efe3bffaa4..07e32a87d956808fbb8b979fb38d434d93c879fc 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -504,7 +504,7 @@ N: Dominik Brodowski
 E: linux@brodo.de
 W: http://www.brodo.de/
 P: 1024D/725B37C6  190F 3E77 9C89 3B6D BECD  46EE 67C3 0308 725B 37C6
-D: parts of CPUFreq code, ACPI bugfixes
+D: parts of CPUFreq code, ACPI bugfixes, PCMCIA rewrite, cpufrequtils
 S: Tuebingen, Germany
 
 N: Andries Brouwer
@@ -857,6 +857,10 @@ S: One Dell Way
 S: Round Rock, TX  78682
 S: USA
 
+N: Mattia Dongili
+E: malattia@gmail.com
+D: cpufrequtils (precursor to cpupowerutils)
+
 N: Ben Dooks
 E: ben-linux@fluff.org
 E: ben@simtec.co.uk
@@ -1883,6 +1887,11 @@ S: Kruislaan 419
 S: 1098 VA Amsterdam 
 S: The Netherlands
 
+N: Goran Koruga
+E: korugag@siol.net
+D: cpufrequtils (precursor to cpupowerutils)
+S: Slovenia
+
 N: Jiri Kosina
 E: jikos@jikos.cz
 E: jkosina@suse.cz
@@ -2916,6 +2925,12 @@ S: Schlossbergring 9
 S: 79098 Freiburg
 S: Germany
 
+N: Thomas Renninger
+E: trenn@suse.de
+D: cpupowerutils
+S: SUSE Linux GmbH
+S: Germany
+
 N: Joerg Reuter
 E: jreuter@yaina.de
 W: http://yaina.de/jreuter/
index 679034cbd686ceb4e38b8d1879592a132ca4baeb..720f245ceb1f34dcf2f01c9607291db14a118d40 100644 (file)
@@ -8,4 +8,7 @@
 *.dvi
 *.log
 *.out
-media/
+*.png
+*.gif
+media-indices.tmpl
+media-entities.tmpl
index 3cebfa0d161182bb562f349359b5676bb660dbd2..66725a3d30dcf5255c31a5428ef177506cec5a0b 100644 (file)
@@ -14,7 +14,9 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
            genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
            80211.xml debugobjects.xml sh.xml regulator.xml \
            alsa-driver-api.xml writing-an-alsa-driver.xml \
-           tracepoint.xml media.xml drm.xml
+           tracepoint.xml drm.xml media_api.xml
+
+include $(srctree)/Documentation/DocBook/media/Makefile
 
 ###
 # The build process is as follows (targets):
@@ -32,7 +34,7 @@ PS_METHOD     = $(prefer-db2x)
 
 ###
 # The targets that may be used.
-PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs xmldoclinks
+PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs
 
 BOOKS := $(addprefix $(obj)/,$(DOCBOOKS))
 xmldocs: $(BOOKS)
@@ -45,27 +47,14 @@ PDF := $(patsubst %.xml, %.pdf, $(BOOKS))
 pdfdocs: $(PDF)
 
 HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS)))
-htmldocs: $(HTML) xmldoclinks
+htmldocs: $(HTML)
        $(call build_main_index)
        $(call build_images)
+       $(call install_media_images)
 
 MAN := $(patsubst %.xml, %.9, $(BOOKS))
 mandocs: $(MAN)
 
-build_images = mkdir -p $(objtree)/Documentation/DocBook/media/ && \
-              cp $(srctree)/Documentation/DocBook/dvb/*.png \
-                 $(srctree)/Documentation/DocBook/v4l/*.gif \
-                 $(objtree)/Documentation/DocBook/media/
-
-xmldoclinks:
-ifneq ($(objtree),$(srctree))
-       for dep in dvb media-entities.tmpl media-indices.tmpl v4l; do \
-               rm -f $(objtree)/Documentation/DocBook/$$dep \
-               && ln -s $(srctree)/Documentation/DocBook/$$dep $(objtree)/Documentation/DocBook/ \
-               || exit; \
-       done
-endif
-
 installmandocs: mandocs
        mkdir -p /usr/local/man/man9/
        install Documentation/DocBook/man/*.9.gz /usr/local/man/man9/
@@ -97,11 +86,11 @@ define rule_docproc
         ) > $(dir $@).$(notdir $@).cmd
 endef
 
-%.xml: %.tmpl xmldoclinks FORCE
+%.xml: %.tmpl FORCE
        $(call if_changed_rule,docproc)
 
 ###
-#Read in all saved dependency files 
+#Read in all saved dependency files
 cmd_files := $(wildcard $(foreach f,$(BOOKS),$(dir $(f)).$(notdir $(f)).cmd))
 
 ifneq ($(cmd_files),)
@@ -150,7 +139,7 @@ quiet_cmd_db2pdf = PDF     $@
 
 index = index.html
 main_idx = Documentation/DocBook/$(index)
-build_main_index = rm -rf $(main_idx) && \
+build_main_index = rm -rf $(main_idx); \
                   echo '<h1>Linux Kernel HTML Documentation</h1>' >> $(main_idx) && \
                   echo '<h2>Kernel Version: $(KERNELVERSION)</h2>' >> $(main_idx) && \
                   cat $(HTML) >> $(main_idx)
@@ -242,7 +231,7 @@ clean-files := $(DOCBOOKS) \
 
 clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man
 
-cleandocs:
+cleandocs: cleanmediadocs
        $(Q)rm -f $(call objectify, $(clean-files))
        $(Q)rm -rf $(call objectify, $(clean-dirs))
 
diff --git a/Documentation/DocBook/dvb/.gitignore b/Documentation/DocBook/dvb/.gitignore
deleted file mode 100644 (file)
index d7ec32e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-!*.xml
diff --git a/Documentation/DocBook/dvb/audio.xml b/Documentation/DocBook/dvb/audio.xml
deleted file mode 100644 (file)
index eeb96b8..0000000
+++ /dev/null
@@ -1,1473 +0,0 @@
-<title>DVB Audio Device</title>
-<para>The DVB audio device controls the MPEG2 audio decoder of the DVB hardware. It
-can be accessed through <emphasis role="tt">/dev/dvb/adapter0/audio0</emphasis>. Data types and and
-ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/video.h</emphasis> in your
-application.
-</para>
-<para>Please note that some DVB cards don&#8217;t have their own MPEG decoder, which results in
-the omission of the audio and video device.
-</para>
-
-<section id="audio_data_types">
-<title>Audio Data Types</title>
-<para>This section describes the structures, data types and defines used when talking to the
-audio device.
-</para>
-
-<section id="audio_stream_source_t">
-<title>audio_stream_source_t</title>
-<para>The audio stream source is set through the AUDIO_SELECT_SOURCE call and can take
-the following values, depending on whether we are replaying from an internal (demux) or
-external (user write) source.
-</para>
-<programlisting>
- typedef enum {
-        AUDIO_SOURCE_DEMUX,
-        AUDIO_SOURCE_MEMORY
- } audio_stream_source_t;
-</programlisting>
-<para>AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the
-DVR device) as the source of the video stream. If AUDIO_SOURCE_MEMORY
-is selected the stream comes from the application through the <emphasis role="tt">write()</emphasis> system
-call.
-</para>
-
-</section>
-<section id="audio_play_state_t">
-<title>audio_play_state_t</title>
-<para>The following values can be returned by the AUDIO_GET_STATUS call representing the
-state of audio playback.
-</para>
-<programlisting>
- typedef enum {
-        AUDIO_STOPPED,
-        AUDIO_PLAYING,
-        AUDIO_PAUSED
- } audio_play_state_t;
-</programlisting>
-
-</section>
-<section id="audio_channel_select_t">
-<title>audio_channel_select_t</title>
-<para>The audio channel selected via AUDIO_CHANNEL_SELECT is determined by the
-following values.
-</para>
-<programlisting>
- typedef enum {
-        AUDIO_STEREO,
-        AUDIO_MONO_LEFT,
-        AUDIO_MONO_RIGHT,
- } audio_channel_select_t;
-</programlisting>
-
-</section>
-<section id="struct_audio_status">
-<title>struct audio_status</title>
-<para>The AUDIO_GET_STATUS call returns the following structure informing about various
-states of the playback operation.
-</para>
-<programlisting>
- typedef struct audio_status {
-        boolean AV_sync_state;
-        boolean mute_state;
-        audio_play_state_t play_state;
-        audio_stream_source_t stream_source;
-        audio_channel_select_t channel_select;
-        boolean bypass_mode;
- } audio_status_t;
-</programlisting>
-
-</section>
-<section id="struct_audio_mixer">
-<title>struct audio_mixer</title>
-<para>The following structure is used by the AUDIO_SET_MIXER call to set the audio
-volume.
-</para>
-<programlisting>
- typedef struct audio_mixer {
-        unsigned int volume_left;
-        unsigned int volume_right;
- } audio_mixer_t;
-</programlisting>
-
-</section>
-<section id="audio_encodings">
-<title>audio encodings</title>
-<para>A call to AUDIO_GET_CAPABILITIES returns an unsigned integer with the following
-bits set according to the hardwares capabilities.
-</para>
-<programlisting>
- #define AUDIO_CAP_DTS    1
- #define AUDIO_CAP_LPCM   2
- #define AUDIO_CAP_MP1    4
- #define AUDIO_CAP_MP2    8
- #define AUDIO_CAP_MP3   16
- #define AUDIO_CAP_AAC   32
- #define AUDIO_CAP_OGG   64
- #define AUDIO_CAP_SDDS 128
- #define AUDIO_CAP_AC3  256
-</programlisting>
-
-</section>
-<section id="struct_audio_karaoke">
-<title>struct audio_karaoke</title>
-<para>The ioctl AUDIO_SET_KARAOKE uses the following format:
-</para>
-<programlisting>
- typedef
- struct audio_karaoke{
-        int vocal1;
-        int vocal2;
-        int melody;
- } audio_karaoke_t;
-</programlisting>
-<para>If Vocal1 or Vocal2 are non-zero, they get mixed into left and right t at 70% each. If both,
-Vocal1 and Vocal2 are non-zero, Vocal1 gets mixed into the left channel and Vocal2 into the
-right channel at 100% each. Ff Melody is non-zero, the melody channel gets mixed into left
-and right.
-</para>
-
-</section>
-<section id="audio_attributes">
-<title>audio attributes</title>
-<para>The following attributes can be set by a call to AUDIO_SET_ATTRIBUTES:
-</para>
-<programlisting>
- typedef uint16_t audio_attributes_t;
- /&#x22C6;   bits: descr. &#x22C6;/
- /&#x22C6;   15-13 audio coding mode (0=ac3, 2=mpeg1, 3=mpeg2ext, 4=LPCM, 6=DTS, &#x22C6;/
- /&#x22C6;   12    multichannel extension &#x22C6;/
- /&#x22C6;   11-10 audio type (0=not spec, 1=language included) &#x22C6;/
- /&#x22C6;    9- 8 audio application mode (0=not spec, 1=karaoke, 2=surround) &#x22C6;/
- /&#x22C6;    7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit,  &#x22C6;/
- /&#x22C6;    5- 4 Sample frequency fs (0=48kHz, 1=96kHz) &#x22C6;/
- /&#x22C6;    2- 0 number of audio channels (n+1 channels) &#x22C6;/
-</programlisting>
- </section></section>
-<section id="audio_function_calls">
-<title>Audio Function Calls</title>
-
-
-<section id="audio_fopen">
-<title>open()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call opens a named audio device (e.g. /dev/dvb/adapter0/audio0)
- for subsequent use. When an open() call has succeeded, the device will be ready
- for use. The significance of blocking or non-blocking mode is described in the
- documentation for functions where there is a difference. It does not affect the
- semantics of the open() call itself. A device opened in blocking mode can later
- be put into non-blocking mode (and vice versa) using the F_SETFL command
- of the fcntl system call. This is a standard system call, documented in the Linux
- manual page for fcntl. Only one user can open the Audio Device in O_RDWR
- mode. All other attempts to open the device in this mode will fail, and an error
- code will be returned. If the Audio Device is opened in O_RDONLY mode, the
- only ioctl call that can be used is AUDIO_GET_STATUS. All other call will
- return with an error code.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open(const char &#x22C6;deviceName, int flags);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>const char
- *deviceName</para>
-</entry><entry
- align="char">
-<para>Name of specific audio device.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int flags</para>
-</entry><entry
- align="char">
-<para>A bit-wise OR of the following flags:</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDONLY read-only access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDWR read/write access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_NONBLOCK open in non-blocking mode</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>(blocking mode is the default)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="audio_fclose">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call closes a previously opened audio device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(int fd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="audio_fwrite">
-<title>write()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call can only be used if AUDIO_SOURCE_MEMORY is selected
- in the ioctl call AUDIO_SELECT_SOURCE. The data provided shall be in
- PES format. If O_NONBLOCK is not specified the function will block until
- buffer space is available. The amount of data to be transferred is implied by
- count.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>size_t write(int fd, const void &#x22C6;buf, size_t count);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>void *buf</para>
-</entry><entry
- align="char">
-<para>Pointer to the buffer containing the PES data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t count</para>
-</entry><entry
- align="char">
-<para>Size of buf.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Mode AUDIO_SOURCE_MEMORY not selected.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOMEM</para>
-</entry><entry
- align="char">
-<para>Attempted to write more data than the internal buffer can
- hold.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_STOP</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to stop playing the current stream.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_STOP);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_STOP for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_PLAY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to start playing an audio stream from the
- selected source.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_PLAY);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_PLAY for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_PAUSE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call suspends the audio stream being played. Decoding and playing
- are paused. It is then possible to restart again decoding and playing process of
- the audio stream using AUDIO_CONTINUE command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>If AUDIO_SOURCE_MEMORY is selected in the ioctl call
- AUDIO_SELECT_SOURCE, the DVB-subsystem will not decode (consume)
- any more data until the ioctl call AUDIO_CONTINUE or AUDIO_PLAY is
- performed.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_PAUSE);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_PAUSE for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_SELECT_SOURCE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call informs the audio device which source shall be used
- for the input data. The possible sources are demux or memory. If
- AUDIO_SOURCE_MEMORY is selected, the data is fed to the Audio Device
- through the write command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_SELECT_SOURCE,
- audio_stream_source_t source);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SELECT_SOURCE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_stream_source_t
- source</para>
-</entry><entry
- align="char">
-<para>Indicates the source that shall be used for the Audio
- stream.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_SET_MUTE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the audio device to mute the stream that is currently being
- played.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_SET_MUTE,
- boolean state);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_MUTE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>boolean state</para>
-</entry><entry
- align="char">
-<para>Indicates if audio device shall mute or not.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>TRUE Audio Mute</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>FALSE Audio Un-mute</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_SET_AV_SYNC</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to turn ON or OFF A/V synchronization.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_SET_AV_SYNC,
- boolean state);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_AV_SYNC for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>boolean state</para>
-</entry><entry
- align="char">
-<para>Tells the DVB subsystem if A/V synchronization shall be
- ON or OFF.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>TRUE AV-sync ON</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>FALSE AV-sync OFF</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_SET_BYPASS_MODE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to bypass the Audio decoder and forward
- the stream without decoding. This mode shall be used if streams that can&#8217;t be
- handled by the DVB system shall be decoded. Dolby DigitalTM streams are
- automatically forwarded by the DVB subsystem if the hardware can handle it.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- AUDIO_SET_BYPASS_MODE, boolean mode);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_BYPASS_MODE for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>boolean mode</para>
-</entry><entry
- align="char">
-<para>Enables or disables the decoding of the current Audio
- stream in the DVB subsystem.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>TRUE Bypass is disabled</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>FALSE Bypass is enabled</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to select the requested channel if possible.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- AUDIO_CHANNEL_SELECT, audio_channel_select_t);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_CHANNEL_SELECT for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_channel_select_t
- ch</para>
-</entry><entry
- align="char">
-<para>Select the output format of the audio (mono left/right,
- stereo).</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter ch.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_GET_STATUS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to return the current state of the Audio
- Device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_GET_STATUS,
- struct audio_status &#x22C6;status);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_GET_STATUS for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct audio_status
- *status</para>
-</entry><entry
- align="char">
-<para>Returns the current state of Audio Device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>status points to invalid address.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_GET_CAPABILITIES</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to tell us about the decoding capabilities
- of the audio hardware.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- AUDIO_GET_CAPABILITIES, unsigned int &#x22C6;cap);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_GET_CAPABILITIES for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>unsigned int *cap</para>
-</entry><entry
- align="char">
-<para>Returns a bit array of supported sound formats.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>cap points to an invalid address.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_CLEAR_BUFFER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Audio Device to clear all software and hardware buffers
- of the audio decoder device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_CLEAR_BUFFER);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_CLEAR_BUFFER for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_SET_ID</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl selects which sub-stream is to be decoded if a program or system
- stream is sent to the video device. If no audio stream type is set the id has to be
- in [0xC0,0xDF] for MPEG sound, in [0x80,0x87] for AC3 and in [0xA0,0xA7]
- for LPCM. More specifications may follow for other stream types. If the stream
- type is set the id just specifies the substream id of the audio stream and only
- the first 5 bits are recognized.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_SET_ID, int
- id);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_ID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int id</para>
-</entry><entry
- align="char">
-<para>audio sub-stream id</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid sub-stream id.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_SET_MIXER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl lets you adjust the mixer settings of the audio decoder.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = AUDIO_SET_MIXER,
- audio_mixer_t &#x22C6;mix);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_ID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_mixer_t *mix</para>
-</entry><entry
- align="char">
-<para>mixer settings.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>mix points to an invalid address.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_SET_STREAMTYPE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl tells the driver which kind of audio stream to expect. This is useful
- if the stream offers several audio sub-streams like LPCM and AC3.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = AUDIO_SET_STREAMTYPE,
- int type);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_STREAMTYPE for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int type</para>
-</entry><entry
- align="char">
-<para>stream type</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>type is not a valid or supported stream type.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_SET_EXT_ID</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl can be used to set the extension id for MPEG streams in DVD
- playback. Only the first 3 bits are recognized.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = AUDIO_SET_EXT_ID, int
- id);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_EXT_ID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int id</para>
-</entry><entry
- align="char">
-<para>audio sub_stream_id</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>id is not a valid id.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_SET_ATTRIBUTES</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is intended for DVD playback and allows you to set certain
- information about the audio stream.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = AUDIO_SET_ATTRIBUTES,
- audio_attributes_t attr );</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_ATTRIBUTES for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_attributes_t
- attr</para>
-</entry><entry
- align="char">
-<para>audio attributes according to section ??</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>attr is not a valid or supported attribute setting.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>AUDIO_SET_KARAOKE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl allows one to set the mixer settings for a karaoke DVD.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = AUDIO_SET_STREAMTYPE,
- audio_karaoke_t &#x22C6;karaoke);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals AUDIO_SET_STREAMTYPE for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>audio_karaoke_t
- *karaoke</para>
-</entry><entry
- align="char">
-<para>karaoke settings according to section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>karaoke is not a valid or supported karaoke setting.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section>
-</section>
diff --git a/Documentation/DocBook/dvb/ca.xml b/Documentation/DocBook/dvb/ca.xml
deleted file mode 100644 (file)
index b1f1d2f..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-<title>DVB CA Device</title>
-<para>The DVB CA device controls the conditional access hardware. It can be accessed through
-<emphasis role="tt">/dev/dvb/adapter0/ca0</emphasis>. Data types and and ioctl definitions can be accessed by
-including <emphasis role="tt">linux/dvb/ca.h</emphasis> in your application.
-</para>
-
-<section id="ca_data_types">
-<title>CA Data Types</title>
-
-
-<section id="ca_slot_info_t">
-<title>ca_slot_info_t</title>
- <programlisting>
- /&#x22C6; slot interface types and info &#x22C6;/
-
- typedef struct ca_slot_info_s {
-        int num;               /&#x22C6; slot number &#x22C6;/
-
-        int type;           /&#x22C6; CA interface this slot supports &#x22C6;/
- #define CA_CI            1  /&#x22C6; CI high level interface &#x22C6;/
- #define CA_CI_LINK       2  /&#x22C6; CI link layer level interface &#x22C6;/
- #define CA_CI_PHYS       4  /&#x22C6; CI physical layer level interface &#x22C6;/
- #define CA_SC          128  /&#x22C6; simple smart card interface &#x22C6;/
-
-        unsigned int flags;
- #define CA_CI_MODULE_PRESENT 1 /&#x22C6; module (or card) inserted &#x22C6;/
- #define CA_CI_MODULE_READY   2
- } ca_slot_info_t;
-</programlisting>
-
-</section>
-<section id="ca_descr_info_t">
-<title>ca_descr_info_t</title>
- <programlisting>
- typedef struct ca_descr_info_s {
-        unsigned int num;  /&#x22C6; number of available descramblers (keys) &#x22C6;/
-        unsigned int type; /&#x22C6; type of supported scrambling system &#x22C6;/
- #define CA_ECD           1
- #define CA_NDS           2
- #define CA_DSS           4
- } ca_descr_info_t;
-</programlisting>
-
-</section>
-<section id="ca_cap_t">
-<title>ca_cap_t</title>
- <programlisting>
- typedef struct ca_cap_s {
-        unsigned int slot_num;  /&#x22C6; total number of CA card and module slots &#x22C6;/
-        unsigned int slot_type; /&#x22C6; OR of all supported types &#x22C6;/
-        unsigned int descr_num; /&#x22C6; total number of descrambler slots (keys) &#x22C6;/
-        unsigned int descr_type;/&#x22C6; OR of all supported types &#x22C6;/
- } ca_cap_t;
-</programlisting>
-
-</section>
-<section id="ca_msg_t">
-<title>ca_msg_t</title>
- <programlisting>
- /&#x22C6; a message to/from a CI-CAM &#x22C6;/
- typedef struct ca_msg_s {
-        unsigned int index;
-        unsigned int type;
-        unsigned int length;
-        unsigned char msg[256];
- } ca_msg_t;
-</programlisting>
-
-</section>
-<section id="ca_descr_t">
-<title>ca_descr_t</title>
- <programlisting>
- typedef struct ca_descr_s {
-        unsigned int index;
-        unsigned int parity;
-        unsigned char cw[8];
- } ca_descr_t;
-</programlisting>
- </section></section>
-<section id="ca_function_calls">
-<title>CA Function Calls</title>
-
-
-<section id="ca_fopen">
-<title>open()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call opens a named ca device (e.g. /dev/ost/ca) for subsequent use.</para>
-<para>When an open() call has succeeded, the device will be ready for use.
- The significance of blocking or non-blocking mode is described in the
- documentation for functions where there is a difference. It does not affect the
- semantics of the open() call itself. A device opened in blocking mode can later
- be put into non-blocking mode (and vice versa) using the F_SETFL command
- of the fcntl system call. This is a standard system call, documented in the Linux
- manual page for fcntl. Only one user can open the CA Device in O_RDWR
- mode. All other attempts to open the device in this mode will fail, and an error
- code will be returned.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open(const char &#x22C6;deviceName, int flags);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>const char
- *deviceName</para>
-</entry><entry
- align="char">
-<para>Name of specific video device.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int flags</para>
-</entry><entry
- align="char">
-<para>A bit-wise OR of the following flags:</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDONLY read-only access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDWR read/write access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_NONBLOCK open in non-blocking mode</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>(blocking mode is the default)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="ca_fclose">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call closes a previously opened audio device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(int fd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section>
-</section>
diff --git a/Documentation/DocBook/dvb/demux.xml b/Documentation/DocBook/dvb/demux.xml
deleted file mode 100644 (file)
index 1b8c4e9..0000000
+++ /dev/null
@@ -1,973 +0,0 @@
-<title>DVB Demux Device</title>
-
-<para>The DVB demux device controls the filters of the DVB hardware/software. It can be
-accessed through <emphasis role="tt">/dev/adapter0/demux0</emphasis>. Data types and and ioctl definitions can be
-accessed by including <emphasis role="tt">linux/dvb/dmx.h</emphasis> in your application.
-</para>
-<section id="dmx_types">
-<title>Demux Data Types</title>
-
-<section id="dmx_output_t">
-<title>dmx_output_t</title>
- <programlisting>
- typedef enum
- {
-        DMX_OUT_DECODER,
-        DMX_OUT_TAP,
-        DMX_OUT_TS_TAP
- } dmx_output_t;
-</programlisting>
-<para><emphasis role="tt">DMX_OUT_TAP</emphasis> delivers the stream output to the demux device on which the ioctl is
-called.
-</para>
-<para><emphasis role="tt">DMX_OUT_TS_TAP</emphasis> routes output to the logical DVR device <emphasis role="tt">/dev/dvb/adapter0/dvr0</emphasis>,
-which delivers a TS multiplexed from all filters for which <emphasis role="tt">DMX_OUT_TS_TAP</emphasis> was
-specified.
-</para>
-</section>
-
-<section id="dmx_input_t">
-<title>dmx_input_t</title>
- <programlisting>
- typedef enum
- {
-        DMX_IN_FRONTEND,
-        DMX_IN_DVR
- } dmx_input_t;
-</programlisting>
-</section>
-
-<section id="dmx_pes_type_t">
-<title>dmx_pes_type_t</title>
- <programlisting>
- typedef enum
- {
-        DMX_PES_AUDIO,
-        DMX_PES_VIDEO,
-        DMX_PES_TELETEXT,
-        DMX_PES_SUBTITLE,
-        DMX_PES_PCR,
-        DMX_PES_OTHER
- } dmx_pes_type_t;
-</programlisting>
-</section>
-
-<section id="dmx_event_t">
-<title>dmx_event_t</title>
- <programlisting>
- typedef enum
- {
-        DMX_SCRAMBLING_EV,
-        DMX_FRONTEND_EV
- } dmx_event_t;
-</programlisting>
-</section>
-
-<section id="dmx_scrambling_status_t">
-<title>dmx_scrambling_status_t</title>
- <programlisting>
- typedef enum
- {
-        DMX_SCRAMBLING_OFF,
-        DMX_SCRAMBLING_ON
- } dmx_scrambling_status_t;
-</programlisting>
-</section>
-
-<section id="dmx_filter">
-<title>struct dmx_filter</title>
- <programlisting>
- typedef struct dmx_filter
- {
-        uint8_t         filter[DMX_FILTER_SIZE];
-        uint8_t         mask[DMX_FILTER_SIZE];
- } dmx_filter_t;
-</programlisting>
-</section>
-
-<section id="dmx_sct_filter_params">
-<title>struct dmx_sct_filter_params</title>
- <programlisting>
- struct dmx_sct_filter_params
- {
-        uint16_t            pid;
-        dmx_filter_t        filter;
-        uint32_t            timeout;
-        uint32_t            flags;
- #define DMX_CHECK_CRC       1
- #define DMX_ONESHOT         2
- #define DMX_IMMEDIATE_START 4
- };
-</programlisting>
-</section>
-
-<section id="dmx_pes_filter_params">
-<title>struct dmx_pes_filter_params</title>
- <programlisting>
- struct dmx_pes_filter_params
- {
-        uint16_t            pid;
-        dmx_input_t         input;
-        dmx_output_t        output;
-        dmx_pes_type_t      pes_type;
-        uint32_t            flags;
- };
-</programlisting>
-</section>
-
-<section id="dmx_event">
-<title>struct dmx_event</title>
- <programlisting>
- struct dmx_event
- {
-        dmx_event_t          event;
-        time_t               timeStamp;
-        union
-        {
-                dmx_scrambling_status_t scrambling;
-        } u;
- };
-</programlisting>
-</section>
-
-<section id="dmx_stc">
-<title>struct dmx_stc</title>
- <programlisting>
- struct dmx_stc {
-        unsigned int num;       /&#x22C6; input : which STC? 0..N &#x22C6;/
-        unsigned int base;      /&#x22C6; output: divisor for stc to get 90 kHz clock &#x22C6;/
-        uint64_t stc;           /&#x22C6; output: stc in 'base'&#x22C6;90 kHz units &#x22C6;/
- };
-</programlisting>
- </section>
-
-</section>
-
-<section id="dmx_fcalls">
-<title>Demux Function Calls</title>
-
-<section id="dmx_fopen">
-<title>open()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call, used with a device name of /dev/dvb/adapter0/demux0,
- allocates a new filter and returns a handle which can be used for subsequent
- control of that filter. This call has to be made for each filter to be used, i.e. every
- returned file descriptor is a reference to a single filter. /dev/dvb/adapter0/dvr0
- is a logical device to be used for retrieving Transport Streams for digital
- video recording. When reading from this device a transport stream containing
- the packets from all PES filters set in the corresponding demux device
- (/dev/dvb/adapter0/demux0) having the output set to DMX_OUT_TS_TAP. A
- recorded Transport Stream is replayed by writing to this device. </para>
-<para>The significance of blocking or non-blocking mode is described in the
- documentation for functions where there is a difference. It does not affect the
- semantics of the open() call itself. A device opened in blocking mode can later
- be put into non-blocking mode (and vice versa) using the F_SETFL command
- of the fcntl system call.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open(const char &#x22C6;deviceName, int flags);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>const char
- *deviceName</para>
-</entry><entry
- align="char">
-<para>Name of demux device.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int flags</para>
-</entry><entry
- align="char">
-<para>A bit-wise OR of the following flags:</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDWR read/write access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_NONBLOCK open in non-blocking mode</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>(blocking mode is the default)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EMFILE</para>
-</entry><entry
- align="char">
-<para>&#8220;Too many open files&#8221;, i.e. no more filters available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOMEM</para>
-</entry><entry
- align="char">
-<para>The driver failed to allocate enough memory.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_fclose">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call deactivates and deallocates a filter that was previously
- allocated via the open() call.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(int fd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_fread">
-<title>read()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call returns filtered data, which might be section or PES data. The
- filtered data is transferred from the driver&#8217;s internal circular buffer to buf. The
- maximum amount of data to be transferred is implied by count.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>When returning section data the driver always tries to return a complete single
- section (even though buf would provide buffer space for more data). If the size
- of the buffer is smaller than the section as much as possible will be returned,
- and the remaining data will be provided in subsequent calls.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The size of the internal buffer is 2 * 4096 bytes (the size of two maximum
- sized sections) by default. The size of this buffer may be changed by using the
- DMX_SET_BUFFER_SIZE function. If the buffer is not large enough, or if
- the read operations are not performed fast enough, this may result in a buffer
- overflow error. In this case EOVERFLOW will be returned, and the circular
- buffer will be emptied. This call is blocking if there is no data to return, i.e. the
- process will be put to sleep waiting for data, unless the O_NONBLOCK flag
- is specified.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>Note that in order to be able to read, the filtering process has to be started
- by defining either a section or a PES filter by means of the ioctl functions,
- and then starting the filtering process via the DMX_START ioctl function
- or by setting the DMX_IMMEDIATE_START flag. If the reading is done
- from a logical DVR demux device, the data will constitute a Transport Stream
- including the packets from all PES filters in the corresponding demux device
- /dev/dvb/adapter0/demux0 having the output set to DMX_OUT_TS_TAP.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>size_t read(int fd, void &#x22C6;buf, size_t count);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>void *buf</para>
-</entry><entry
- align="char">
-<para>Pointer to the buffer to be used for returned filtered data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t count</para>
-</entry><entry
- align="char">
-<para>Size of buf.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>No data to return and O_NONBLOCK was specified.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ECRC</para>
-</entry><entry
- align="char">
-<para>Last section had a CRC error - no data returned. The
- buffer is flushed.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EOVERFLOW</para>
-</entry><entry
- align="char">
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>The filtered data was not read from the buffer in due
- time, resulting in non-read data being lost. The buffer is
- flushed.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ETIMEDOUT</para>
-</entry><entry
- align="char">
-<para>The section was not loaded within the stated timeout
- period. See ioctl DMX_SET_FILTER for how to set a
- timeout.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>The driver failed to write to the callers buffer due to an
- invalid *buf pointer.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_fwrite">
-<title>write()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call is only provided by the logical device /dev/dvb/adapter0/dvr0,
- associated with the physical demux device that provides the actual DVR
- functionality. It is used for replay of a digitally recorded Transport Stream.
- Matching filters have to be defined in the corresponding physical demux
- device, /dev/dvb/adapter0/demux0. The amount of data to be transferred is
- implied by count.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>ssize_t write(int fd, const void &#x22C6;buf, size_t
- count);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>void *buf</para>
-</entry><entry
- align="char">
-<para>Pointer to the buffer containing the Transport Stream.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t count</para>
-</entry><entry
- align="char">
-<para>Size of buf.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>No data was written. This
- might happen if O_NONBLOCK was specified and there
- is no more buffer space available (if O_NONBLOCK is
- not specified the function will block until buffer space is
- available).</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>This error code indicates that there are conflicting
- requests. The corresponding demux device is setup to
- receive data from the front- end. Make sure that these
- filters are stopped and that the filters with input set to
- DMX_IN_DVR are started.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_start">
-<title>DMX_START</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to start the actual filtering operation defined via the ioctl
- calls DMX_SET_FILTER or DMX_SET_PES_FILTER.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_START);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_START for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument, i.e. no filtering parameters provided via
- the DMX_SET_FILTER or DMX_SET_PES_FILTER
- functions.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>This error code indicates that there are conflicting
- requests. There are active filters filtering data from
- another input source. Make sure that these filters are
- stopped before starting this filter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_stop">
-<title>DMX_STOP</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to stop the actual filtering operation defined via the
- ioctl calls DMX_SET_FILTER or DMX_SET_PES_FILTER and started via
- the DMX_START command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_STOP);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_STOP for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_set_filter">
-<title>DMX_SET_FILTER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call sets up a filter according to the filter and mask parameters
- provided. A timeout may be defined stating number of seconds to wait for a
- section to be loaded. A value of 0 means that no timeout should be applied.
- Finally there is a flag field where it is possible to state whether a section should
- be CRC-checked, whether the filter should be a &#8221;one-shot&#8221; filter, i.e. if the
- filtering operation should be stopped after the first section is received, and
- whether the filtering operation should be started immediately (without waiting
- for a DMX_START ioctl call). If a filter was previously set-up, this filter will
- be canceled, and the receive buffer will be flushed.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_SET_FILTER,
- struct dmx_sct_filter_params &#x22C6;params);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_SET_FILTER for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dmx_sct_filter_params
- *params</para>
-</entry><entry
- align="char">
-<para>Pointer to structure containing filter parameters.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_set_pes_filter">
-<title>DMX_SET_PES_FILTER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call sets up a PES filter according to the parameters provided. By a
- PES filter is meant a filter that is based just on the packet identifier (PID), i.e.
- no PES header or payload filtering capability is supported.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The transport stream destination for the filtered output may be set. Also the
- PES type may be stated in order to be able to e.g. direct a video stream directly
- to the video decoder. Finally there is a flag field where it is possible to state
- whether the filtering operation should be started immediately (without waiting
- for a DMX_START ioctl call). If a filter was previously set-up, this filter will
- be cancelled, and the receive buffer will be flushed.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_SET_PES_FILTER,
- struct dmx_pes_filter_params &#x22C6;params);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_SET_PES_FILTER for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dmx_pes_filter_params
- *params</para>
-</entry><entry
- align="char">
-<para>Pointer to structure containing filter parameters.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>This error code indicates that there are conflicting
- requests. There are active filters filtering data from
- another input source. Make sure that these filters are
- stopped before starting this filter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dms_set_buffer_size">
-<title>DMX_SET_BUFFER_SIZE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to set the size of the circular buffer used for filtered data.
- The default size is two maximum sized sections, i.e. if this function is not called
- a buffer size of 2 * 4096 bytes will be used.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request =
- DMX_SET_BUFFER_SIZE, unsigned long size);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_SET_BUFFER_SIZE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>unsigned long size</para>
-</entry><entry
- align="char">
-<para>Size of circular buffer.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOMEM</para>
-</entry><entry
- align="char">
-<para>The driver was not able to allocate a buffer of the
- requested size.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_get_event">
-<title>DMX_GET_EVENT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns an event if available. If an event is not available,
- the behavior depends on whether the device is in blocking or non-blocking
- mode. In the latter case, the call fails immediately with errno set to
- EWOULDBLOCK. In the former case, the call blocks until an event becomes
- available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The standard Linux poll() and/or select() system calls can be used with the
- device file descriptor to watch for new events. For select(), the file descriptor
- should be included in the exceptfds argument, and for poll(), POLLPRI should
- be specified as the wake-up condition. Only the latest event for each filter is
- saved.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_GET_EVENT,
- struct dmx_event &#x22C6;ev);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_GET_EVENT for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dmx_event *ev</para>
-</entry><entry
- align="char">
-<para>Pointer to the location where the event is to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>ev points to an invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>There is no event pending, and the device is in
- non-blocking mode.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="dmx_get_stc">
-<title>DMX_GET_STC</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the current value of the system time counter (which is driven
- by a PES filter of type DMX_PES_PCR). Some hardware supports more than one
- STC, so you must specify which one by setting the num field of stc before the ioctl
- (range 0...n). The result is returned in form of a ratio with a 64 bit numerator
- and a 32 bit denominator, so the real 90kHz STC value is stc-&#x003E;stc /
- stc-&#x003E;base
- .</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request = DMX_GET_STC, struct
- dmx_stc &#x22C6;stc);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals DMX_GET_STC for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dmx_stc *stc</para>
-</entry><entry
- align="char">
-<para>Pointer to the location where the stc is to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>stc points to an invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid stc number.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section></section>
diff --git a/Documentation/DocBook/dvb/dvbapi.xml b/Documentation/DocBook/dvb/dvbapi.xml
deleted file mode 100644 (file)
index 9fad86c..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-<partinfo>
-<authorgroup>
-<author>
-<firstname>Ralph</firstname>
-<surname>Metzler</surname>
-<othername role="mi">J. K.</othername>
-<affiliation><address><email>rjkm@metzlerbros.de</email></address></affiliation>
-</author>
-<author>
-<firstname>Marcus</firstname>
-<surname>Metzler</surname>
-<othername role="mi">O. C.</othername>
-<affiliation><address><email>rjkm@metzlerbros.de</email></address></affiliation>
-</author>
-</authorgroup>
-<authorgroup>
-<author>
-<firstname>Mauro</firstname>
-<othername role="mi">Carvalho</othername>
-<surname>Chehab</surname>
-<affiliation><address><email>mchehab@redhat.com</email></address></affiliation>
-<contrib>Ported document to Docbook XML.</contrib>
-</author>
-</authorgroup>
-<copyright>
-       <year>2002</year>
-       <year>2003</year>
-       <holder>Convergence GmbH</holder>
-</copyright>
-<copyright>
-       <year>2009-2011</year>
-       <holder>Mauro Carvalho Chehab</holder>
-</copyright>
-
-<revhistory>
-<!-- Put document revisions here, newest first. -->
-<revision>
-       <revnumber>2.0.4</revnumber>
-       <date>2011-05-06</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>
-               Add more information about DVB APIv5, better describing the frontend GET/SET props ioctl's.
-       </revremark>
-</revision>
-<revision>
-       <revnumber>2.0.3</revnumber>
-       <date>2010-07-03</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>
-               Add some frontend capabilities flags, present on kernel, but missing at the specs.
-       </revremark>
-</revision>
-<revision>
-       <revnumber>2.0.2</revnumber>
-       <date>2009-10-25</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>
-               documents FE_SET_FRONTEND_TUNE_MODE and FE_DISHETWORK_SEND_LEGACY_CMD ioctls.
-       </revremark>
-</revision>
-<revision>
-<revnumber>2.0.1</revnumber>
-<date>2009-09-16</date>
-<authorinitials>mcc</authorinitials>
-<revremark>
-Added ISDB-T test originally written by Patrick Boettcher
-</revremark>
-</revision>
-<revision>
-<revnumber>2.0.0</revnumber>
-<date>2009-09-06</date>
-<authorinitials>mcc</authorinitials>
-<revremark>Conversion from LaTex to DocBook XML. The
-       contents is the same as the original LaTex version.</revremark>
-</revision>
-<revision>
-<revnumber>1.0.0</revnumber>
-<date>2003-07-24</date>
-<authorinitials>rjkm</authorinitials>
-<revremark>Initial revision on LaTEX.</revremark>
-</revision>
-</revhistory>
-</partinfo>
-
-
-<title>LINUX DVB API</title>
-<subtitle>Version 5.2</subtitle>
-<!-- ADD THE CHAPTERS HERE -->
-  <chapter id="dvb_introdution">
-    &sub-intro;
-  </chapter>
-  <chapter id="dvb_frontend">
-    &sub-frontend;
-  </chapter>
-  <chapter id="dvb_demux">
-    &sub-demux;
-  </chapter>
-  <chapter id="dvb_video">
-    &sub-video;
-  </chapter>
-  <chapter id="dvb_audio">
-    &sub-audio;
-  </chapter>
-  <chapter id="dvb_ca">
-    &sub-ca;
-  </chapter>
-  <chapter id="dvb_net">
-    &sub-net;
-  </chapter>
-  <chapter id="dvb_kdapi">
-    &sub-kdapi;
-  </chapter>
-  <chapter id="dvb_examples">
-    &sub-examples;
-  </chapter>
-<!-- END OF CHAPTERS -->
-  <appendix id="frontend_h">
-    <title>DVB Frontend Header File</title>
-    &sub-frontend-h;
-  </appendix>
-
diff --git a/Documentation/DocBook/dvb/dvbproperty.xml b/Documentation/DocBook/dvb/dvbproperty.xml
deleted file mode 100644 (file)
index b5365f6..0000000
+++ /dev/null
@@ -1,590 +0,0 @@
-<section id="FE_GET_SET_PROPERTY">
-<title>FE_GET_PROPERTY/FE_SET_PROPERTY</title>
-
-<programlisting>
-/* Reserved fields should be set to 0 */
-struct dtv_property {
-       __u32 cmd;
-       union {
-               __u32 data;
-               struct {
-                       __u8 data[32];
-                       __u32 len;
-                       __u32 reserved1[3];
-                       void *reserved2;
-               } buffer;
-       } u;
-       int result;
-} __attribute__ ((packed));
-
-/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
-#define DTV_IOCTL_MAX_MSGS 64
-
-struct dtv_properties {
-       __u32 num;
-       struct dtv_property *props;
-};
-</programlisting>
-
-<section id="FE_GET_PROPERTY">
-<title>FE_GET_PROPERTY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns one or more frontend properties. This call only
- requires read-only access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>,
- dtv_properties &#x22C6;props);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int num</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dtv_property *props</para>
-</entry><entry
- align="char">
-<para>Points to the location where the front-end property commands are stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS</para>
-<informaltable><tgroup cols="2"><tbody><row>
-  <entry align="char"><para>EINVAL</para></entry>
-  <entry align="char"><para>Invalid parameter(s) received or number of parameters out of the range.</para></entry>
- </row><row>
-  <entry align="char"><para>ENOMEM</para></entry>
-  <entry align="char"><para>Out of memory.</para></entry>
- </row><row>
-  <entry align="char"><para>EFAULT</para></entry>
-  <entry align="char"><para>Failure while copying data from/to userspace.</para></entry>
- </row><row>
-  <entry align="char"><para>EOPNOTSUPP</para></entry>
-  <entry align="char"><para>Property type not supported.</para></entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_SET_PROPERTY">
-<title>FE_SET_PROPERTY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call sets one or more frontend properties. This call only
- requires read-only access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
- dtv_properties &#x22C6;props);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int num</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct dtv_property *props</para>
-</entry><entry
- align="char">
-<para>Points to the location where the front-end property commands are stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row>
-  <entry align="char"><para>EINVAL</para></entry>
-  <entry align="char"><para>Invalid parameter(s) received or number of parameters out of the range.</para></entry>
- </row><row>
-  <entry align="char"><para>ENOMEM</para></entry>
-  <entry align="char"><para>Out of memory.</para></entry>
- </row><row>
-  <entry align="char"><para>EFAULT</para></entry>
-  <entry align="char"><para>Failure while copying data from/to userspace.</para></entry>
- </row><row>
-  <entry align="char"><para>EOPNOTSUPP</para></entry>
-  <entry align="char"><para>Property type not supported.</para></entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section>
-       <title>Property types</title>
-<para>
-On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
-the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
-get/set up to 64 properties. The actual meaning of each property is described on the next sections.
-</para>
-
-<para>The available frontend property types are:</para>
-<programlisting>
-#define DTV_UNDEFINED          0
-#define DTV_TUNE               1
-#define DTV_CLEAR              2
-#define DTV_FREQUENCY          3
-#define DTV_MODULATION         4
-#define DTV_BANDWIDTH_HZ       5
-#define DTV_INVERSION          6
-#define DTV_DISEQC_MASTER      7
-#define DTV_SYMBOL_RATE                8
-#define DTV_INNER_FEC          9
-#define DTV_VOLTAGE            10
-#define DTV_TONE               11
-#define DTV_PILOT              12
-#define DTV_ROLLOFF            13
-#define DTV_DISEQC_SLAVE_REPLY 14
-#define DTV_FE_CAPABILITY_COUNT        15
-#define DTV_FE_CAPABILITY      16
-#define DTV_DELIVERY_SYSTEM    17
-#define DTV_ISDBT_PARTIAL_RECEPTION    18
-#define DTV_ISDBT_SOUND_BROADCASTING   19
-#define DTV_ISDBT_SB_SUBCHANNEL_ID     20
-#define DTV_ISDBT_SB_SEGMENT_IDX       21
-#define DTV_ISDBT_SB_SEGMENT_COUNT     22
-#define DTV_ISDBT_LAYERA_FEC                   23
-#define DTV_ISDBT_LAYERA_MODULATION            24
-#define DTV_ISDBT_LAYERA_SEGMENT_COUNT         25
-#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING     26
-#define DTV_ISDBT_LAYERB_FEC                   27
-#define DTV_ISDBT_LAYERB_MODULATION            28
-#define DTV_ISDBT_LAYERB_SEGMENT_COUNT         29
-#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING     30
-#define DTV_ISDBT_LAYERC_FEC                   31
-#define DTV_ISDBT_LAYERC_MODULATION            32
-#define DTV_ISDBT_LAYERC_SEGMENT_COUNT         33
-#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING     34
-#define DTV_API_VERSION                35
-#define DTV_CODE_RATE_HP       36
-#define DTV_CODE_RATE_LP       37
-#define DTV_GUARD_INTERVAL     38
-#define DTV_TRANSMISSION_MODE  39
-#define DTV_HIERARCHY          40
-#define DTV_ISDBT_LAYER_ENABLED        41
-#define DTV_ISDBS_TS_ID                42
-</programlisting>
-</section>
-
-<section id="fe_property_common">
-       <title>Parameters that are common to all Digital TV standards</title>
-       <section id="DTV_FREQUENCY">
-               <title><constant>DTV_FREQUENCY</constant></title>
-
-               <para>Central frequency of the channel, in HZ.</para>
-
-               <para>Notes:</para>
-               <para>1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
-                       E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
-                       the channel which is 6MHz.</para>
-
-               <para>2)As in ISDB-Tsb the channel consists of only one or three segments the
-                       frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
-                       central frequency of the channel is expected.</para>
-       </section>
-
-       <section id="DTV_BANDWIDTH_HZ">
-               <title><constant>DTV_BANDWIDTH_HZ</constant></title>
-
-               <para>Bandwidth for the channel, in HZ.</para>
-
-               <para>Possible values:
-                       <constant>1712000</constant>,
-                       <constant>5000000</constant>,
-                       <constant>6000000</constant>,
-                       <constant>7000000</constant>,
-                       <constant>8000000</constant>,
-                       <constant>10000000</constant>.
-               </para>
-
-               <para>Notes:</para>
-
-               <para>1) For ISDB-T it should be always 6000000Hz (6MHz)</para>
-               <para>2) For ISDB-Tsb it can vary depending on the number of connected segments</para>
-               <para>3) Bandwidth doesn't apply for DVB-C transmissions, as the bandwidth
-                        for DVB-C depends on the symbol rate</para>
-               <para>4) Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
-                       other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
-                       DTV_ISDBT_SB_SEGMENT_COUNT).</para>
-               <para>5) DVB-T supports 6, 7 and 8MHz.</para>
-               <para>6) In addition, DVB-T2 supports 1.172, 5 and 10MHz.</para>
-       </section>
-
-       <section id="DTV_DELIVERY_SYSTEM">
-               <title><constant>DTV_DELIVERY_SYSTEM</constant></title>
-
-               <para>Specifies the type of Delivery system</para>
-
-               <para>Possible values: </para>
-<programlisting>
-typedef enum fe_delivery_system {
-       SYS_UNDEFINED,
-       SYS_DVBC_ANNEX_AC,
-       SYS_DVBC_ANNEX_B,
-       SYS_DVBT,
-       SYS_DSS,
-       SYS_DVBS,
-       SYS_DVBS2,
-       SYS_DVBH,
-       SYS_ISDBT,
-       SYS_ISDBS,
-       SYS_ISDBC,
-       SYS_ATSC,
-       SYS_ATSCMH,
-       SYS_DMBTH,
-       SYS_CMMB,
-       SYS_DAB,
-       SYS_DVBT2,
-} fe_delivery_system_t;
-</programlisting>
-
-       </section>
-
-       <section id="DTV_TRANSMISSION_MODE">
-               <title><constant>DTV_TRANSMISSION_MODE</constant></title>
-
-               <para>Specifies the number of carriers used by the standard</para>
-
-               <para>Possible values are:</para>
-<programlisting>
-typedef enum fe_transmit_mode {
-       TRANSMISSION_MODE_2K,
-       TRANSMISSION_MODE_8K,
-       TRANSMISSION_MODE_AUTO,
-       TRANSMISSION_MODE_4K,
-       TRANSMISSION_MODE_1K,
-       TRANSMISSION_MODE_16K,
-       TRANSMISSION_MODE_32K,
-} fe_transmit_mode_t;
-</programlisting>
-
-               <para>Notes:</para>
-               <para>1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
-                       'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
-
-               <para>2) If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
-                       hardware will try to find the correct FFT-size (if capable) and will
-                       use TMCC to fill in the missing parameters.</para>
-               <para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
-               <para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
-       </section>
-
-       <section id="DTV_GUARD_INTERVAL">
-               <title><constant>DTV_GUARD_INTERVAL</constant></title>
-
-               <para>Possible values are:</para>
-<programlisting>
-typedef enum fe_guard_interval {
-       GUARD_INTERVAL_1_32,
-       GUARD_INTERVAL_1_16,
-       GUARD_INTERVAL_1_8,
-       GUARD_INTERVAL_1_4,
-       GUARD_INTERVAL_AUTO,
-       GUARD_INTERVAL_1_128,
-       GUARD_INTERVAL_19_128,
-       GUARD_INTERVAL_19_256,
-} fe_guard_interval_t;
-</programlisting>
-
-               <para>Notes:</para>
-               <para>1) If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
-                       try to find the correct guard interval (if capable) and will use TMCC to fill
-                       in the missing parameters.</para>
-               <para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
-       </section>
-</section>
-
-<section id="isdbt">
-       <title>ISDB-T frontend</title>
-       <para>This section describes shortly what are the possible parameters in the Linux
-               DVB-API called "S2API" and now DVB API 5 in order to tune an ISDB-T/ISDB-Tsb
-               demodulator:</para>
-
-       <para>This ISDB-T/ISDB-Tsb API extension should reflect all information
-               needed to tune any ISDB-T/ISDB-Tsb hardware. Of course it is possible
-               that some very sophisticated devices won't need certain parameters to
-               tune.</para>
-
-       <para>The information given here should help application writers to know how
-               to handle ISDB-T and ISDB-Tsb hardware using the Linux DVB-API.</para>
-
-       <para>The details given here about ISDB-T and ISDB-Tsb are just enough to
-               basically show the dependencies between the needed parameter values,
-               but surely some information is left out. For more detailed information
-               see the following documents:</para>
-
-       <para>ARIB STD-B31 - "Transmission System for Digital Terrestrial
-               Television Broadcasting" and</para>
-       <para>ARIB TR-B14 - "Operational Guidelines for Digital Terrestrial
-               Television Broadcasting".</para>
-
-       <para>In order to read this document one has to have some knowledge the
-               channel structure in ISDB-T and ISDB-Tsb. I.e. it has to be known to
-               the reader that an ISDB-T channel consists of 13 segments, that it can
-               have up to 3 layer sharing those segments, and things like that.</para>
-
-       <para>Parameters used by ISDB-T and ISDB-Tsb.</para>
-
-       <section id="isdbt-new-parms">
-               <title>ISDB-T only parameters</title>
-
-               <section id="isdbt-part-rec">
-                       <title><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></title>
-
-                       <para><constant>If DTV_ISDBT_SOUND_BROADCASTING</constant> is '0' this bit-field represents whether
-                               the channel is in partial reception mode or not.</para>
-
-                       <para>If '1' <constant>DTV_ISDBT_LAYERA_*</constant> values are assigned to the center segment and
-                               <constant>DTV_ISDBT_LAYERA_SEGMENT_COUNT</constant> has to be '1'.</para>
-
-                       <para>If in addition <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'
-                               <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> represents whether this ISDB-Tsb channel
-                               is consisting of one segment and layer or three segments and two layers.</para>
-
-                       <para>Possible values: 0, 1, -1 (AUTO)</para>
-               </section>
-
-               <section id="isdbt-sound-bcast">
-                       <title><constant>DTV_ISDBT_SOUND_BROADCASTING</constant></title>
-
-                       <para>This field represents whether the other DTV_ISDBT_*-parameters are
-                               referring to an ISDB-T and an ISDB-Tsb channel. (See also
-                               <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>).</para>
-
-                       <para>Possible values: 0, 1, -1 (AUTO)</para>
-               </section>
-
-               <section id="isdbt-sb-ch-id">
-                       <title><constant>DTV_ISDBT_SB_SUBCHANNEL_ID</constant></title>
-
-                       <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
-
-                       <para>(Note of the author: This might not be the correct description of the
-                               <constant>SUBCHANNEL-ID</constant> in all details, but it is my understanding of the technical
-                               background needed to program a device)</para>
-
-                       <para>An ISDB-Tsb channel (1 or 3 segments) can be broadcasted alone or in a
-                               set of connected ISDB-Tsb channels. In this set of channels every
-                               channel can be received independently. The number of connected
-                               ISDB-Tsb segment can vary, e.g. depending on the frequency spectrum
-                               bandwidth available.</para>
-
-                       <para>Example: Assume 8 ISDB-Tsb connected segments are broadcasted. The
-                               broadcaster has several possibilities to put those channels in the
-                               air: Assuming a normal 13-segment ISDB-T spectrum he can align the 8
-                               segments from position 1-8 to 5-13 or anything in between.</para>
-
-                       <para>The underlying layer of segments are subchannels: each segment is
-                               consisting of several subchannels with a predefined IDs. A sub-channel
-                               is used to help the demodulator to synchronize on the channel.</para>
-
-                       <para>An ISDB-T channel is always centered over all sub-channels. As for
-                               the example above, in ISDB-Tsb it is no longer as simple as that.</para>
-
-                       <para><constant>The DTV_ISDBT_SB_SUBCHANNEL_ID</constant> parameter is used to give the
-                               sub-channel ID of the segment to be demodulated.</para>
-
-                       <para>Possible values: 0 .. 41, -1 (AUTO)</para>
-               </section>
-
-               <section id="isdbt-sb-seg-idx">
-
-                       <title><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant></title>
-
-                       <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
-
-                       <para><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant> gives the index of the segment to be
-                               demodulated for an ISDB-Tsb channel where several of them are
-                               transmitted in the connected manner.</para>
-
-                       <para>Possible values: 0 .. <constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> - 1</para>
-
-                       <para>Note: This value cannot be determined by an automatic channel search.</para>
-               </section>
-
-               <section id="isdbt-sb-seg-cnt">
-                       <title><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant></title>
-
-                       <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
-
-                       <para><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> gives the total count of connected ISDB-Tsb
-                               channels.</para>
-
-                       <para>Possible values: 1 .. 13</para>
-
-                       <para>Note: This value cannot be determined by an automatic channel search.</para>
-               </section>
-
-               <section id="isdb-hierq-layers">
-                       <title>Hierarchical layers</title>
-
-                       <para>ISDB-T channels can be coded hierarchically. As opposed to DVB-T in
-                               ISDB-T hierarchical layers can be decoded simultaneously. For that
-                               reason a ISDB-T demodulator has 3 viterbi and 3 reed-solomon-decoders.</para>
-
-                       <para>ISDB-T has 3 hierarchical layers which each can use a part of the
-                               available segments. The total number of segments over all layers has
-                               to 13 in ISDB-T.</para>
-
-                       <section id="isdbt-layer-ena">
-                               <title><constant>DTV_ISDBT_LAYER_ENABLED</constant></title>
-
-                               <para>Hierarchical reception in ISDB-T is achieved by enabling or disabling
-                                       layers in the decoding process. Setting all bits of
-                                       <constant>DTV_ISDBT_LAYER_ENABLED</constant> to '1' forces all layers (if applicable) to be
-                                       demodulated. This is the default.</para>
-
-                               <para>If the channel is in the partial reception mode
-                                       (<constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> = 1) the central segment can be decoded
-                                       independently of the other 12 segments. In that mode layer A has to
-                                       have a <constant>SEGMENT_COUNT</constant> of 1.</para>
-
-                               <para>In ISDB-Tsb only layer A is used, it can be 1 or 3 in ISDB-Tsb
-                                       according to <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>. <constant>SEGMENT_COUNT</constant> must be filled
-                                       accordingly.</para>
-
-                               <para>Possible values: 0x1, 0x2, 0x4 (|-able)</para>
-
-                               <para><constant>DTV_ISDBT_LAYER_ENABLED[0:0]</constant> - layer A</para>
-                               <para><constant>DTV_ISDBT_LAYER_ENABLED[1:1]</constant> - layer B</para>
-                               <para><constant>DTV_ISDBT_LAYER_ENABLED[2:2]</constant> - layer C</para>
-                               <para><constant>DTV_ISDBT_LAYER_ENABLED[31:3]</constant> unused</para>
-                       </section>
-
-                       <section id="isdbt-layer-fec">
-                               <title><constant>DTV_ISDBT_LAYER*_FEC</constant></title>
-
-                               <para>Possible values: <constant>FEC_AUTO</constant>, <constant>FEC_1_2</constant>, <constant>FEC_2_3</constant>, <constant>FEC_3_4</constant>, <constant>FEC_5_6</constant>, <constant>FEC_7_8</constant></para>
-                       </section>
-
-                       <section id="isdbt-layer-mod">
-                               <title><constant>DTV_ISDBT_LAYER*_MODULATION</constant></title>
-
-                               <para>Possible values: <constant>QAM_AUTO</constant>, QP<constant>SK, QAM_16</constant>, <constant>QAM_64</constant>, <constant>DQPSK</constant></para>
-
-                               <para>Note: If layer C is <constant>DQPSK</constant> layer B has to be <constant>DQPSK</constant>. If layer B is <constant>DQPSK</constant>
-                                       and <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>=0 layer has to be <constant>DQPSK</constant>.</para>
-                       </section>
-
-                       <section id="isdbt-layer-seg-cnt">
-                               <title><constant>DTV_ISDBT_LAYER*_SEGMENT_COUNT</constant></title>
-
-                               <para>Possible values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1 (AUTO)</para>
-
-                               <para>Note: Truth table for <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> and
-                                       <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> and <constant>LAYER</constant>*_SEGMENT_COUNT</para>
-
-                               <informaltable id="isdbt-layer_seg-cnt-table">
-                                       <tgroup cols="6">
-
-                                               <tbody>
-                                                       <row>
-                                                               <entry>PR</entry>
-                                                               <entry>SB</entry>
-                                                               <entry>Layer A width</entry>
-                                                               <entry>Layer B width</entry>
-                                                               <entry>Layer C width</entry>
-                                                               <entry>total width</entry>
-                                                       </row>
-
-                                                       <row>
-                                                               <entry>0</entry>
-                                                               <entry>0</entry>
-                                                               <entry>1 .. 13</entry>
-                                                               <entry>1 .. 13</entry>
-                                                               <entry>1 .. 13</entry>
-                                                               <entry>13</entry>
-                                                       </row>
-
-                                                       <row>
-                                                               <entry>1</entry>
-                                                               <entry>0</entry>
-                                                               <entry>1</entry>
-                                                               <entry>1 .. 13</entry>
-                                                               <entry>1 .. 13</entry>
-                                                               <entry>13</entry>
-                                                       </row>
-
-                                                       <row>
-                                                               <entry>0</entry>
-                                                               <entry>1</entry>
-                                                               <entry>1</entry>
-                                                               <entry>0</entry>
-                                                               <entry>0</entry>
-                                                               <entry>1</entry>
-                                                       </row>
-
-                                                       <row>
-                                                               <entry>1</entry>
-                                                               <entry>1</entry>
-                                                               <entry>1</entry>
-                                                               <entry>2</entry>
-                                                               <entry>0</entry>
-                                                               <entry>13</entry>
-                                                       </row>
-                                               </tbody>
-
-                                       </tgroup>
-                               </informaltable>
-
-                       </section>
-
-                       <section id="isdbt_layer_t_interl">
-                               <title><constant>DTV_ISDBT_LAYER*_TIME_INTERLEAVING</constant></title>
-
-                               <para>Possible values: 0, 1, 2, 3, -1 (AUTO)</para>
-
-                               <para>Note: The real inter-leaver depth-names depend on the mode (fft-size); the values
-                                       here are referring to what can be found in the TMCC-structure -
-                                       independent of the mode.</para>
-                       </section>
-               </section>
-       </section>
-       <section id="dvbt2-params">
-               <title>DVB-T2 parameters</title>
-               
-               <para>This section covers parameters that apply only to the DVB-T2 delivery method. DVB-T2
-                       support is currently in the early stages development so expect this section to grow
-                       and become more detailed with time.</para>
-
-               <section id="dvbt2-plp-id">
-                       <title><constant>DTV_DVBT2_PLP_ID</constant></title>
-
-                       <para>DVB-T2 supports Physical Layer Pipes (PLP) to allow transmission of
-                               many data types via a single multiplex. The API will soon support this
-                               at which point this section will be expanded.</para>
-               </section>
-       </section>
-</section>
-</section>
diff --git a/Documentation/DocBook/dvb/dvbstb.pdf b/Documentation/DocBook/dvb/dvbstb.pdf
deleted file mode 100644 (file)
index 0fa75d9..0000000
Binary files a/Documentation/DocBook/dvb/dvbstb.pdf and /dev/null differ
diff --git a/Documentation/DocBook/dvb/dvbstb.png b/Documentation/DocBook/dvb/dvbstb.png
deleted file mode 100644 (file)
index 9b8f372..0000000
Binary files a/Documentation/DocBook/dvb/dvbstb.png and /dev/null differ
diff --git a/Documentation/DocBook/dvb/examples.xml b/Documentation/DocBook/dvb/examples.xml
deleted file mode 100644 (file)
index f037e56..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-<title>Examples</title>
-<para>In this section we would like to present some examples for using the DVB API.
-</para>
-<para>Maintainer note: This section is out of date. Please refer to the sample programs packaged
-with the driver distribution from <ulink url="http://linuxtv.org/hg/dvb-apps" />.
-</para>
-
-<section id="tuning">
-<title>Tuning</title>
-<para>We will start with a generic tuning subroutine that uses the frontend and SEC, as well as
-the demux devices. The example is given for QPSK tuners, but can easily be adjusted for
-QAM.
-</para>
-<programlisting>
- #include &#x003C;sys/ioctl.h&#x003E;
- #include &#x003C;stdio.h&#x003E;
- #include &#x003C;stdint.h&#x003E;
- #include &#x003C;sys/types.h&#x003E;
- #include &#x003C;sys/stat.h&#x003E;
- #include &#x003C;fcntl.h&#x003E;
- #include &#x003C;time.h&#x003E;
- #include &#x003C;unistd.h&#x003E;
-
- #include &#x003C;linux/dvb/dmx.h&#x003E;
- #include &#x003C;linux/dvb/frontend.h&#x003E;
- #include &#x003C;linux/dvb/sec.h&#x003E;
- #include &#x003C;sys/poll.h&#x003E;
-
- #define DMX "/dev/dvb/adapter0/demux1"
- #define FRONT "/dev/dvb/adapter0/frontend1"
- #define SEC "/dev/dvb/adapter0/sec1"
-
- /&#x22C6; routine for checking if we have a signal and other status information&#x22C6;/
- int FEReadStatus(int fd, fe_status_t &#x22C6;stat)
- {
-        int ans;
-
-        if ( (ans = ioctl(fd,FE_READ_STATUS,stat) &#x003C; 0)){
-                perror("FE READ STATUS: ");
-                return -1;
-        }
-
-        if (&#x22C6;stat &amp; FE_HAS_POWER)
-                printf("FE HAS POWER\n");
-
-        if (&#x22C6;stat &amp; FE_HAS_SIGNAL)
-                printf("FE HAS SIGNAL\n");
-
-        if (&#x22C6;stat &amp; FE_SPECTRUM_INV)
-                printf("SPEKTRUM INV\n");
-
-        return 0;
- }
-
-
- /&#x22C6; tune qpsk &#x22C6;/
- /&#x22C6; freq:             frequency of transponder                      &#x22C6;/
- /&#x22C6; vpid, apid, tpid: PIDs of video, audio and teletext TS packets  &#x22C6;/
- /&#x22C6; diseqc:           DiSEqC address of the used LNB                &#x22C6;/
- /&#x22C6; pol:              Polarisation                                  &#x22C6;/
- /&#x22C6; srate:            Symbol Rate                                   &#x22C6;/
- /&#x22C6; fec.              FEC                                           &#x22C6;/
- /&#x22C6; lnb_lof1:         local frequency of lower LNB band             &#x22C6;/
- /&#x22C6; lnb_lof2:         local frequency of upper LNB band             &#x22C6;/
- /&#x22C6; lnb_slof:         switch frequency of LNB                       &#x22C6;/
-
- int set_qpsk_channel(int freq, int vpid, int apid, int tpid,
-                int diseqc, int pol, int srate, int fec, int lnb_lof1,
-                int lnb_lof2, int lnb_slof)
- {
-        struct secCommand scmd;
-        struct secCmdSequence scmds;
-        struct dmx_pes_filter_params pesFilterParams;
-        FrontendParameters frp;
-        struct pollfd pfd[1];
-        FrontendEvent event;
-        int demux1, demux2, demux3, front;
-
-        frequency = (uint32_t) freq;
-        symbolrate = (uint32_t) srate;
-
-        if((front = open(FRONT,O_RDWR)) &#x003C; 0){
-                perror("FRONTEND DEVICE: ");
-                return -1;
-        }
-
-        if((sec = open(SEC,O_RDWR)) &#x003C; 0){
-                perror("SEC DEVICE: ");
-                return -1;
-        }
-
-        if (demux1 &#x003C; 0){
-                if ((demux1=open(DMX, O_RDWR|O_NONBLOCK))
-                    &#x003C; 0){
-                        perror("DEMUX DEVICE: ");
-                        return -1;
-                }
-        }
-
-        if (demux2 &#x003C; 0){
-                if ((demux2=open(DMX, O_RDWR|O_NONBLOCK))
-                    &#x003C; 0){
-                        perror("DEMUX DEVICE: ");
-                        return -1;
-                }
-        }
-
-        if (demux3 &#x003C; 0){
-                if ((demux3=open(DMX, O_RDWR|O_NONBLOCK))
-                    &#x003C; 0){
-                        perror("DEMUX DEVICE: ");
-                        return -1;
-                }
-        }
-
-        if (freq &#x003C; lnb_slof) {
-                frp.Frequency = (freq - lnb_lof1);
-                scmds.continuousTone = SEC_TONE_OFF;
-        } else {
-                frp.Frequency = (freq - lnb_lof2);
-                scmds.continuousTone = SEC_TONE_ON;
-        }
-        frp.Inversion = INVERSION_AUTO;
-        if (pol) scmds.voltage = SEC_VOLTAGE_18;
-        else scmds.voltage = SEC_VOLTAGE_13;
-
-        scmd.type=0;
-        scmd.u.diseqc.addr=0x10;
-        scmd.u.diseqc.cmd=0x38;
-        scmd.u.diseqc.numParams=1;
-        scmd.u.diseqc.params[0] = 0xF0 | ((diseqc &#x22C6; 4) &amp; 0x0F) |
-                (scmds.continuousTone == SEC_TONE_ON ? 1 : 0) |
-                (scmds.voltage==SEC_VOLTAGE_18 ? 2 : 0);
-
-        scmds.miniCommand=SEC_MINI_NONE;
-        scmds.numCommands=1;
-        scmds.commands=&amp;scmd;
-        if (ioctl(sec, SEC_SEND_SEQUENCE, &amp;scmds) &#x003C; 0){
-                perror("SEC SEND: ");
-                return -1;
-        }
-
-        if (ioctl(sec, SEC_SEND_SEQUENCE, &amp;scmds) &#x003C; 0){
-                perror("SEC SEND: ");
-                return -1;
-        }
-
-        frp.u.qpsk.SymbolRate = srate;
-        frp.u.qpsk.FEC_inner = fec;
-
-        if (ioctl(front, FE_SET_FRONTEND, &amp;frp) &#x003C; 0){
-                perror("QPSK TUNE: ");
-                return -1;
-        }
-
-        pfd[0].fd = front;
-        pfd[0].events = POLLIN;
-
-        if (poll(pfd,1,3000)){
-                if (pfd[0].revents &amp; POLLIN){
-                        printf("Getting QPSK event\n");
-                        if ( ioctl(front, FE_GET_EVENT, &amp;event)
-
-                             == -EOVERFLOW){
-                                perror("qpsk get event");
-                                return -1;
-                        }
-                        printf("Received ");
-                        switch(event.type){
-                        case FE_UNEXPECTED_EV:
-                                printf("unexpected event\n");
-                                return -1;
-                        case FE_FAILURE_EV:
-                                printf("failure event\n");
-                                return -1;
-
-                        case FE_COMPLETION_EV:
-                                printf("completion event\n");
-                        }
-                }
-        }
-
-
-        pesFilterParams.pid     = vpid;
-        pesFilterParams.input   = DMX_IN_FRONTEND;
-        pesFilterParams.output  = DMX_OUT_DECODER;
-        pesFilterParams.pes_type = DMX_PES_VIDEO;
-        pesFilterParams.flags   = DMX_IMMEDIATE_START;
-        if (ioctl(demux1, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
-                perror("set_vpid");
-                return -1;
-        }
-
-        pesFilterParams.pid     = apid;
-        pesFilterParams.input   = DMX_IN_FRONTEND;
-        pesFilterParams.output  = DMX_OUT_DECODER;
-        pesFilterParams.pes_type = DMX_PES_AUDIO;
-        pesFilterParams.flags   = DMX_IMMEDIATE_START;
-        if (ioctl(demux2, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
-                perror("set_apid");
-                return -1;
-        }
-
-        pesFilterParams.pid     = tpid;
-        pesFilterParams.input   = DMX_IN_FRONTEND;
-        pesFilterParams.output  = DMX_OUT_DECODER;
-        pesFilterParams.pes_type = DMX_PES_TELETEXT;
-        pesFilterParams.flags   = DMX_IMMEDIATE_START;
-        if (ioctl(demux3, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
-                perror("set_tpid");
-                return -1;
-        }
-
-        return has_signal(fds);
- }
-
-</programlisting>
-<para>The program assumes that you are using a universal LNB and a standard DiSEqC
-switch with up to 4 addresses. Of course, you could build in some more checking if
-tuning was successful and maybe try to repeat the tuning process. Depending on the
-external hardware, i.e. LNB and DiSEqC switch, and weather conditions this may be
-necessary.
-</para>
-</section>
-
-<section id="the_dvr_device">
-<title>The DVR device</title>
-<para>The following program code shows how to use the DVR device for recording.
-</para>
-<programlisting>
- #include &#x003C;sys/ioctl.h&#x003E;
- #include &#x003C;stdio.h&#x003E;
- #include &#x003C;stdint.h&#x003E;
- #include &#x003C;sys/types.h&#x003E;
- #include &#x003C;sys/stat.h&#x003E;
- #include &#x003C;fcntl.h&#x003E;
- #include &#x003C;time.h&#x003E;
- #include &#x003C;unistd.h&#x003E;
-
- #include &#x003C;linux/dvb/dmx.h&#x003E;
- #include &#x003C;linux/dvb/video.h&#x003E;
- #include &#x003C;sys/poll.h&#x003E;
- #define DVR "/dev/dvb/adapter0/dvr1"
- #define AUDIO "/dev/dvb/adapter0/audio1"
- #define VIDEO "/dev/dvb/adapter0/video1"
-
- #define BUFFY (188&#x22C6;20)
- #define MAX_LENGTH (1024&#x22C6;1024&#x22C6;5) /&#x22C6; record 5MB &#x22C6;/
-
-
- /&#x22C6; switch the demuxes to recording, assuming the transponder is tuned &#x22C6;/
-
- /&#x22C6; demux1, demux2: file descriptor of video and audio filters &#x22C6;/
- /&#x22C6; vpid, apid:     PIDs of video and audio channels           &#x22C6;/
-
- int switch_to_record(int demux1, int demux2, uint16_t vpid, uint16_t apid)
- {
-        struct dmx_pes_filter_params pesFilterParams;
-
-        if (demux1 &#x003C; 0){
-                if ((demux1=open(DMX, O_RDWR|O_NONBLOCK))
-                    &#x003C; 0){
-                        perror("DEMUX DEVICE: ");
-                        return -1;
-                }
-        }
-
-        if (demux2 &#x003C; 0){
-                if ((demux2=open(DMX, O_RDWR|O_NONBLOCK))
-                    &#x003C; 0){
-                        perror("DEMUX DEVICE: ");
-                        return -1;
-                }
-        }
-
-        pesFilterParams.pid = vpid;
-        pesFilterParams.input = DMX_IN_FRONTEND;
-        pesFilterParams.output = DMX_OUT_TS_TAP;
-        pesFilterParams.pes_type = DMX_PES_VIDEO;
-        pesFilterParams.flags = DMX_IMMEDIATE_START;
-        if (ioctl(demux1, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
-                perror("DEMUX DEVICE");
-                return -1;
-        }
-        pesFilterParams.pid = apid;
-        pesFilterParams.input = DMX_IN_FRONTEND;
-        pesFilterParams.output = DMX_OUT_TS_TAP;
-        pesFilterParams.pes_type = DMX_PES_AUDIO;
-        pesFilterParams.flags = DMX_IMMEDIATE_START;
-        if (ioctl(demux2, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
-                perror("DEMUX DEVICE");
-                return -1;
-        }
-        return 0;
- }
-
- /&#x22C6; start recording MAX_LENGTH , assuming the transponder is tuned &#x22C6;/
-
- /&#x22C6; demux1, demux2: file descriptor of video and audio filters &#x22C6;/
- /&#x22C6; vpid, apid:     PIDs of video and audio channels           &#x22C6;/
- int record_dvr(int demux1, int demux2, uint16_t vpid, uint16_t apid)
- {
-        int i;
-        int len;
-        int written;
-        uint8_t buf[BUFFY];
-        uint64_t length;
-        struct pollfd pfd[1];
-        int dvr, dvr_out;
-
-        /&#x22C6; open dvr device &#x22C6;/
-        if ((dvr = open(DVR, O_RDONLY|O_NONBLOCK)) &#x003C; 0){
-                        perror("DVR DEVICE");
-                        return -1;
-        }
-
-        /&#x22C6; switch video and audio demuxes to dvr &#x22C6;/
-        printf ("Switching dvr on\n");
-        i = switch_to_record(demux1, demux2, vpid, apid);
-        printf("finished: ");
-
-        printf("Recording %2.0f MB of test file in TS format\n",
-               MAX_LENGTH/(1024.0&#x22C6;1024.0));
-        length = 0;
-
-        /&#x22C6; open output file &#x22C6;/
-        if ((dvr_out = open(DVR_FILE,O_WRONLY|O_CREAT
-                                 |O_TRUNC, S_IRUSR|S_IWUSR
-                                 |S_IRGRP|S_IWGRP|S_IROTH|
-                                 S_IWOTH)) &#x003C; 0){
-                perror("Can't open file for dvr test");
-                return -1;
-        }
-
-        pfd[0].fd = dvr;
-        pfd[0].events = POLLIN;
-
-        /&#x22C6; poll for dvr data and write to file &#x22C6;/
-        while (length &#x003C; MAX_LENGTH ) {
-                if (poll(pfd,1,1)){
-                        if (pfd[0].revents &amp; POLLIN){
-                                len = read(dvr, buf, BUFFY);
-                                if (len &#x003C; 0){
-                                        perror("recording");
-                                        return -1;
-                                }
-                                if (len &#x003E; 0){
-                                        written = 0;
-                                        while (written &#x003C; len)
-                                                written +=
-                                                        write (dvr_out,
-                                                               buf, len);
-                                        length += len;
-                                        printf("written %2.0f MB\r",
-                                               length/1024./1024.);
-                                }
-                        }
-                }
-        }
-        return 0;
- }
-
-</programlisting>
-
-</section>
diff --git a/Documentation/DocBook/dvb/frontend.h.xml b/Documentation/DocBook/dvb/frontend.h.xml
deleted file mode 100644 (file)
index d792f78..0000000
+++ /dev/null
@@ -1,428 +0,0 @@
-<programlisting>
-/*
- * frontend.h
- *
- * Copyright (C) 2000 Marcus Metzler &lt;marcus@convergence.de&gt;
- *                  Ralph  Metzler &lt;ralph@convergence.de&gt;
- *                  Holger Waechtler &lt;holger@convergence.de&gt;
- *                  Andre Draszik &lt;ad@convergence.de&gt;
- *                  for convergence integrated media GmbH
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser 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 _DVBFRONTEND_H_
-#define _DVBFRONTEND_H_
-
-#include &lt;linux/types.h&gt;
-
-typedef enum fe_type {
-        FE_QPSK,
-        FE_QAM,
-        FE_OFDM,
-        FE_ATSC
-} fe_type_t;
-
-
-typedef enum fe_caps {
-        FE_IS_STUPID                    = 0,
-        FE_CAN_INVERSION_AUTO           = 0x1,
-        FE_CAN_FEC_1_2                  = 0x2,
-        FE_CAN_FEC_2_3                  = 0x4,
-        FE_CAN_FEC_3_4                  = 0x8,
-        FE_CAN_FEC_4_5                  = 0x10,
-        FE_CAN_FEC_5_6                  = 0x20,
-        FE_CAN_FEC_6_7                  = 0x40,
-        FE_CAN_FEC_7_8                  = 0x80,
-        FE_CAN_FEC_8_9                  = 0x100,
-        FE_CAN_FEC_AUTO                 = 0x200,
-        FE_CAN_QPSK                     = 0x400,
-        FE_CAN_QAM_16                   = 0x800,
-        FE_CAN_QAM_32                   = 0x1000,
-        FE_CAN_QAM_64                   = 0x2000,
-        FE_CAN_QAM_128                  = 0x4000,
-        FE_CAN_QAM_256                  = 0x8000,
-        FE_CAN_QAM_AUTO                 = 0x10000,
-        FE_CAN_TRANSMISSION_MODE_AUTO   = 0x20000,
-        FE_CAN_BANDWIDTH_AUTO           = 0x40000,
-        FE_CAN_GUARD_INTERVAL_AUTO      = 0x80000,
-        FE_CAN_HIERARCHY_AUTO           = 0x100000,
-        FE_CAN_8VSB                     = 0x200000,
-        FE_CAN_16VSB                    = 0x400000,
-        FE_HAS_EXTENDED_CAPS            = 0x800000,   /* We need more bitspace for newer APIs, indicate this. */
-        FE_CAN_TURBO_FEC                = 0x8000000,  /* frontend supports "turbo fec modulation" */
-        FE_CAN_2G_MODULATION            = 0x10000000, /* frontend supports "2nd generation modulation" (DVB-S2) */
-        FE_NEEDS_BENDING                = 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */
-        FE_CAN_RECOVER                  = 0x40000000, /* frontend can recover from a cable unplug automatically */
-        FE_CAN_MUTE_TS                  = 0x80000000  /* frontend can stop spurious TS data output */
-} fe_caps_t;
-
-
-struct dvb_frontend_info {
-        char       name[128];
-        fe_type_t  type;
-        __u32      frequency_min;
-        __u32      frequency_max;
-        __u32      frequency_stepsize;
-        __u32      frequency_tolerance;
-        __u32      symbol_rate_min;
-        __u32      symbol_rate_max;
-        __u32      symbol_rate_tolerance;       /* ppm */
-        __u32      notifier_delay;              /* DEPRECATED */
-        fe_caps_t  caps;
-};
-
-
-/**
- *  Check out the DiSEqC bus spec available on http://www.eutelsat.org/ for
- *  the meaning of this struct...
- */
-struct dvb_diseqc_master_cmd {
-        __u8 msg [6];   /*  { framing, address, command, data [3] } */
-        __u8 msg_len;   /*  valid values are 3...6  */
-};
-
-
-struct dvb_diseqc_slave_reply {
-        __u8 msg [4];   /*  { framing, data [3] } */
-        __u8 msg_len;   /*  valid values are 0...4, 0 means no msg  */
-        int  timeout;   /*  return from ioctl after timeout ms with */
-};                      /*  errorcode when no message was received  */
-
-
-typedef enum fe_sec_voltage {
-        SEC_VOLTAGE_13,
-        SEC_VOLTAGE_18,
-        SEC_VOLTAGE_OFF
-} fe_sec_voltage_t;
-
-
-typedef enum fe_sec_tone_mode {
-        SEC_TONE_ON,
-        SEC_TONE_OFF
-} fe_sec_tone_mode_t;
-
-
-typedef enum fe_sec_mini_cmd {
-        SEC_MINI_A,
-        SEC_MINI_B
-} fe_sec_mini_cmd_t;
-
-
-typedef enum fe_status {
-        FE_HAS_SIGNAL   = 0x01,   /* found something above the noise level */
-        FE_HAS_CARRIER  = 0x02,   /* found a DVB signal  */
-        FE_HAS_VITERBI  = 0x04,   /* FEC is stable  */
-        FE_HAS_SYNC     = 0x08,   /* found sync bytes  */
-        FE_HAS_LOCK     = 0x10,   /* everything's working... */
-        FE_TIMEDOUT     = 0x20,   /* no lock within the last ~2 seconds */
-        FE_REINIT       = 0x40    /* frontend was reinitialized,  */
-} fe_status_t;                    /* application is recommended to reset */
-                                  /* DiSEqC, tone and parameters */
-
-typedef enum fe_spectral_inversion {
-        INVERSION_OFF,
-        INVERSION_ON,
-        INVERSION_AUTO
-} fe_spectral_inversion_t;
-
-
-typedef enum fe_code_rate {
-        FEC_NONE = 0,
-        FEC_1_2,
-        FEC_2_3,
-        FEC_3_4,
-        FEC_4_5,
-        FEC_5_6,
-        FEC_6_7,
-        FEC_7_8,
-        FEC_8_9,
-        FEC_AUTO,
-        FEC_3_5,
-        FEC_9_10,
-} fe_code_rate_t;
-
-
-typedef enum fe_modulation {
-        QPSK,
-        QAM_16,
-        QAM_32,
-        QAM_64,
-        QAM_128,
-        QAM_256,
-        QAM_AUTO,
-        VSB_8,
-        VSB_16,
-        PSK_8,
-        APSK_16,
-        APSK_32,
-        DQPSK,
-} fe_modulation_t;
-
-typedef enum fe_transmit_mode {
-        TRANSMISSION_MODE_2K,
-        TRANSMISSION_MODE_8K,
-        TRANSMISSION_MODE_AUTO,
-        TRANSMISSION_MODE_4K,
-        TRANSMISSION_MODE_1K,
-        TRANSMISSION_MODE_16K,
-        TRANSMISSION_MODE_32K,
-} fe_transmit_mode_t;
-
-typedef enum fe_bandwidth {
-        BANDWIDTH_8_MHZ,
-        BANDWIDTH_7_MHZ,
-        BANDWIDTH_6_MHZ,
-        BANDWIDTH_AUTO,
-        BANDWIDTH_5_MHZ,
-        BANDWIDTH_10_MHZ,
-        BANDWIDTH_1_712_MHZ,
-} fe_bandwidth_t;
-
-
-typedef enum fe_guard_interval {
-        GUARD_INTERVAL_1_32,
-        GUARD_INTERVAL_1_16,
-        GUARD_INTERVAL_1_8,
-        GUARD_INTERVAL_1_4,
-        GUARD_INTERVAL_AUTO,
-        GUARD_INTERVAL_1_128,
-        GUARD_INTERVAL_19_128,
-        GUARD_INTERVAL_19_256,
-} fe_guard_interval_t;
-
-
-typedef enum fe_hierarchy {
-        HIERARCHY_NONE,
-        HIERARCHY_1,
-        HIERARCHY_2,
-        HIERARCHY_4,
-        HIERARCHY_AUTO
-} fe_hierarchy_t;
-
-
-struct dvb_qpsk_parameters {
-        __u32           symbol_rate;  /* symbol rate in Symbols per second */
-        fe_code_rate_t  fec_inner;    /* forward error correction (see above) */
-};
-
-struct dvb_qam_parameters {
-        __u32           symbol_rate; /* symbol rate in Symbols per second */
-        fe_code_rate_t  fec_inner;   /* forward error correction (see above) */
-        fe_modulation_t modulation;  /* modulation type (see above) */
-};
-
-struct dvb_vsb_parameters {
-        fe_modulation_t modulation;  /* modulation type (see above) */
-};
-
-struct dvb_ofdm_parameters {
-        fe_bandwidth_t      bandwidth;
-        fe_code_rate_t      code_rate_HP;  /* high priority stream code rate */
-        fe_code_rate_t      code_rate_LP;  /* low priority stream code rate */
-        fe_modulation_t     constellation; /* modulation type (see above) */
-        fe_transmit_mode_t  transmission_mode;
-        fe_guard_interval_t guard_interval;
-        fe_hierarchy_t      hierarchy_information;
-};
-
-
-struct dvb_frontend_parameters {
-        __u32 frequency;     /* (absolute) frequency in Hz for QAM/OFDM/ATSC */
-                             /* intermediate frequency in kHz for QPSK */
-        fe_spectral_inversion_t inversion;
-        union {
-                struct dvb_qpsk_parameters qpsk;
-                struct dvb_qam_parameters  qam;
-                struct dvb_ofdm_parameters ofdm;
-                struct dvb_vsb_parameters vsb;
-        } u;
-};
-
-
-struct dvb_frontend_event {
-        fe_status_t status;
-        struct dvb_frontend_parameters parameters;
-};
-
-/* S2API Commands */
-#define DTV_UNDEFINED           0
-#define DTV_TUNE                1
-#define DTV_CLEAR               2
-#define DTV_FREQUENCY           3
-#define DTV_MODULATION          4
-#define DTV_BANDWIDTH_HZ        5
-#define DTV_INVERSION           6
-#define DTV_DISEQC_MASTER       7
-#define DTV_SYMBOL_RATE         8
-#define DTV_INNER_FEC           9
-#define DTV_VOLTAGE             10
-#define DTV_TONE                11
-#define DTV_PILOT               12
-#define DTV_ROLLOFF             13
-#define DTV_DISEQC_SLAVE_REPLY  14
-
-/* Basic enumeration set for querying unlimited capabilities */
-#define DTV_FE_CAPABILITY_COUNT 15
-#define DTV_FE_CAPABILITY       16
-#define DTV_DELIVERY_SYSTEM     17
-
-/* ISDB-T and ISDB-Tsb */
-#define DTV_ISDBT_PARTIAL_RECEPTION     18
-#define DTV_ISDBT_SOUND_BROADCASTING    19
-
-#define DTV_ISDBT_SB_SUBCHANNEL_ID      20
-#define DTV_ISDBT_SB_SEGMENT_IDX        21
-#define DTV_ISDBT_SB_SEGMENT_COUNT      22
-
-#define DTV_ISDBT_LAYERA_FEC                    23
-#define DTV_ISDBT_LAYERA_MODULATION             24
-#define DTV_ISDBT_LAYERA_SEGMENT_COUNT          25
-#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING      26
-
-#define DTV_ISDBT_LAYERB_FEC                    27
-#define DTV_ISDBT_LAYERB_MODULATION             28
-#define DTV_ISDBT_LAYERB_SEGMENT_COUNT          29
-#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING      30
-
-#define DTV_ISDBT_LAYERC_FEC                    31
-#define DTV_ISDBT_LAYERC_MODULATION             32
-#define DTV_ISDBT_LAYERC_SEGMENT_COUNT          33
-#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING      34
-
-#define DTV_API_VERSION         35
-
-#define DTV_CODE_RATE_HP        36
-#define DTV_CODE_RATE_LP        37
-#define DTV_GUARD_INTERVAL      38
-#define DTV_TRANSMISSION_MODE   39
-#define DTV_HIERARCHY           40
-
-#define DTV_ISDBT_LAYER_ENABLED 41
-
-#define DTV_ISDBS_TS_ID         42
-
-#define DTV_DVBT2_PLP_ID       43
-
-#define DTV_MAX_COMMAND                         DTV_DVBT2_PLP_ID
-
-typedef enum fe_pilot {
-        PILOT_ON,
-        PILOT_OFF,
-        PILOT_AUTO,
-} fe_pilot_t;
-
-typedef enum fe_rolloff {
-        ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */
-        ROLLOFF_20,
-        ROLLOFF_25,
-        ROLLOFF_AUTO,
-} fe_rolloff_t;
-
-typedef enum fe_delivery_system {
-        SYS_UNDEFINED,
-        SYS_DVBC_ANNEX_AC,
-        SYS_DVBC_ANNEX_B,
-        SYS_DVBT,
-        SYS_DSS,
-        SYS_DVBS,
-        SYS_DVBS2,
-        SYS_DVBH,
-        SYS_ISDBT,
-        SYS_ISDBS,
-        SYS_ISDBC,
-        SYS_ATSC,
-        SYS_ATSCMH,
-        SYS_DMBTH,
-        SYS_CMMB,
-        SYS_DAB,
-        SYS_DVBT2,
-} fe_delivery_system_t;
-
-struct dtv_cmds_h {
-        char    *name;          /* A display name for debugging purposes */
-
-        __u32   cmd;            /* A unique ID */
-
-        /* Flags */
-        __u32   set:1;          /* Either a set or get property */
-        __u32   buffer:1;       /* Does this property use the buffer? */
-        __u32   reserved:30;    /* Align */
-};
-
-struct dtv_property {
-        __u32 cmd;
-        __u32 reserved[3];
-        union {
-                __u32 data;
-                struct {
-                        __u8 data[32];
-                        __u32 len;
-                        __u32 reserved1[3];
-                        void *reserved2;
-                } buffer;
-        } u;
-        int result;
-} __attribute__ ((packed));
-
-/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
-#define DTV_IOCTL_MAX_MSGS 64
-
-struct dtv_properties {
-        __u32 num;
-        struct dtv_property *props;
-};
-
-#define <link linkend="FE_GET_PROPERTY">FE_SET_PROPERTY</link>            _IOW('o', 82, struct dtv_properties)
-#define <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>            _IOR('o', 83, struct dtv_properties)
-
-
-/**
- * When set, this flag will disable any zigzagging or other "normal" tuning
- * behaviour. Additionally, there will be no automatic monitoring of the lock
- * status, and hence no frontend events will be generated. If a frontend device
- * is closed, this flag will be automatically turned off when the device is
- * reopened read-write.
- */
-#define FE_TUNE_MODE_ONESHOT 0x01
-
-
-#define <link linkend="FE_GET_INFO">FE_GET_INFO</link>                _IOR('o', 61, struct dvb_frontend_info)
-
-#define <link linkend="FE_DISEQC_RESET_OVERLOAD">FE_DISEQC_RESET_OVERLOAD</link>   _IO('o', 62)
-#define <link linkend="FE_DISEQC_SEND_MASTER_CMD">FE_DISEQC_SEND_MASTER_CMD</link>  _IOW('o', 63, struct dvb_diseqc_master_cmd)
-#define <link linkend="FE_DISEQC_RECV_SLAVE_REPLY">FE_DISEQC_RECV_SLAVE_REPLY</link> _IOR('o', 64, struct dvb_diseqc_slave_reply)
-#define <link linkend="FE_DISEQC_SEND_BURST">FE_DISEQC_SEND_BURST</link>       _IO('o', 65)  /* fe_sec_mini_cmd_t */
-
-#define <link linkend="FE_SET_TONE">FE_SET_TONE</link>                _IO('o', 66)  /* fe_sec_tone_mode_t */
-#define <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link>             _IO('o', 67)  /* fe_sec_voltage_t */
-#define <link linkend="FE_ENABLE_HIGH_LNB_VOLTAGE">FE_ENABLE_HIGH_LNB_VOLTAGE</link> _IO('o', 68)  /* int */
-
-#define <link linkend="FE_READ_STATUS">FE_READ_STATUS</link>             _IOR('o', 69, fe_status_t)
-#define <link linkend="FE_READ_BER">FE_READ_BER</link>                _IOR('o', 70, __u32)
-#define <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link>    _IOR('o', 71, __u16)
-#define <link linkend="FE_READ_SNR">FE_READ_SNR</link>                _IOR('o', 72, __u16)
-#define <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link> _IOR('o', 73, __u32)
-
-#define <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link>            _IOW('o', 76, struct dvb_frontend_parameters)
-#define <link linkend="FE_GET_FRONTEND">FE_GET_FRONTEND</link>            _IOR('o', 77, struct dvb_frontend_parameters)
-#define <link linkend="FE_SET_FRONTEND_TUNE_MODE">FE_SET_FRONTEND_TUNE_MODE</link>  _IO('o', 81) /* unsigned int */
-#define <link linkend="FE_GET_EVENT">FE_GET_EVENT</link>               _IOR('o', 78, struct dvb_frontend_event)
-
-#define <link linkend="FE_DISHNETWORK_SEND_LEGACY_CMD">FE_DISHNETWORK_SEND_LEGACY_CMD</link> _IO('o', 80) /* unsigned int */
-
-#endif /*_DVBFRONTEND_H_*/
-</programlisting>
diff --git a/Documentation/DocBook/dvb/frontend.xml b/Documentation/DocBook/dvb/frontend.xml
deleted file mode 100644 (file)
index 60c6976..0000000
+++ /dev/null
@@ -1,1851 +0,0 @@
-<title>DVB Frontend API</title>
-
-<para>The DVB frontend device controls the tuner and DVB demodulator
-hardware. It can be accessed through <emphasis
-role="tt">/dev/dvb/adapter0/frontend0</emphasis>. Data types and and
-ioctl definitions can be accessed by including <emphasis
-role="tt">linux/dvb/frontend.h</emphasis> in your application.</para>
-
-<para>DVB frontends come in three varieties: DVB-S (satellite), DVB-C
-(cable) and DVB-T (terrestrial). Transmission via the internet (DVB-IP)
-is not yet handled by this API but a future extension is possible. For
-DVB-S the frontend device also supports satellite equipment control
-(SEC) via DiSEqC and V-SEC protocols. The DiSEqC (digital SEC)
-specification is available from
-<ulink url="http://www.eutelsat.com/satellites/4_5_5.html">Eutelsat</ulink>.</para>
-
-<para>Note that the DVB API may also be used for MPEG decoder-only PCI
-cards, in which case there exists no frontend device.</para>
-
-<section id="frontend_types">
-<title>Frontend Data Types</title>
-
-<section id="frontend_type">
-<title>frontend type</title>
-
-<para>For historical reasons frontend types are named after the type of modulation used in
-transmission.</para>
-<programlisting>
-       typedef enum fe_type {
-       FE_QPSK,   /&#x22C6; DVB-S &#x22C6;/
-       FE_QAM,    /&#x22C6; DVB-C &#x22C6;/
-       FE_OFDM    /&#x22C6; DVB-T &#x22C6;/
-       } fe_type_t;
-</programlisting>
-
-</section>
-
-<section id="frontend_caps">
-<title>frontend capabilities</title>
-
-<para>Capabilities describe what a frontend can do. Some capabilities can only be supported for
-a specific frontend type.</para>
-<programlisting>
-       typedef enum fe_caps {
-       FE_IS_STUPID                  = 0,
-       FE_CAN_INVERSION_AUTO         = 0x1,
-       FE_CAN_FEC_1_2                = 0x2,
-       FE_CAN_FEC_2_3                = 0x4,
-       FE_CAN_FEC_3_4                = 0x8,
-       FE_CAN_FEC_4_5                = 0x10,
-       FE_CAN_FEC_5_6                = 0x20,
-       FE_CAN_FEC_6_7                = 0x40,
-       FE_CAN_FEC_7_8                = 0x80,
-       FE_CAN_FEC_8_9                = 0x100,
-       FE_CAN_FEC_AUTO               = 0x200,
-       FE_CAN_QPSK                   = 0x400,
-       FE_CAN_QAM_16                 = 0x800,
-       FE_CAN_QAM_32                 = 0x1000,
-       FE_CAN_QAM_64                 = 0x2000,
-       FE_CAN_QAM_128                = 0x4000,
-       FE_CAN_QAM_256                = 0x8000,
-       FE_CAN_QAM_AUTO               = 0x10000,
-       FE_CAN_TRANSMISSION_MODE_AUTO = 0x20000,
-       FE_CAN_BANDWIDTH_AUTO         = 0x40000,
-       FE_CAN_GUARD_INTERVAL_AUTO    = 0x80000,
-       FE_CAN_HIERARCHY_AUTO         = 0x100000,
-       FE_CAN_8VSB                   = 0x200000,
-       FE_CAN_16VSB                  = 0x400000,
-       FE_HAS_EXTENDED_CAPS          = 0x800000,
-       FE_CAN_TURBO_FEC              = 0x8000000,
-       FE_CAN_2G_MODULATION          = 0x10000000,
-       FE_NEEDS_BENDING              = 0x20000000,
-       FE_CAN_RECOVER                = 0x40000000,
-       FE_CAN_MUTE_TS                = 0x80000000
-       } fe_caps_t;
-</programlisting>
-</section>
-
-<section id="frontend_info">
-<title>frontend information</title>
-
-<para>Information about the frontend ca be queried with
-       <link linkend="FE_GET_INFO">FE_GET_INFO</link>.</para>
-
-<programlisting>
-       struct dvb_frontend_info {
-       char       name[128];
-       fe_type_t  type;
-       uint32_t   frequency_min;
-       uint32_t   frequency_max;
-       uint32_t   frequency_stepsize;
-       uint32_t   frequency_tolerance;
-       uint32_t   symbol_rate_min;
-       uint32_t   symbol_rate_max;
-       uint32_t   symbol_rate_tolerance;     /&#x22C6; ppm &#x22C6;/
-       uint32_t   notifier_delay;            /&#x22C6; ms &#x22C6;/
-       fe_caps_t  caps;
-       };
-</programlisting>
-</section>
-
-<section id="frontend_diseqc">
-<title>diseqc master command</title>
-
-<para>A message sent from the frontend to DiSEqC capable equipment.</para>
-<programlisting>
-       struct dvb_diseqc_master_cmd {
-       uint8_t msg [6]; /&#x22C6;  { framing, address, command, data[3] } &#x22C6;/
-       uint8_t msg_len; /&#x22C6;  valid values are 3...6  &#x22C6;/
-       };
-</programlisting>
-</section>
-<section role="subsection">
-<title>diseqc slave reply</title>
-
-<para>A reply to the frontend from DiSEqC 2.0 capable equipment.</para>
-<programlisting>
-       struct dvb_diseqc_slave_reply {
-       uint8_t msg [4]; /&#x22C6;  { framing, data [3] } &#x22C6;/
-       uint8_t msg_len; /&#x22C6;  valid values are 0...4, 0 means no msg  &#x22C6;/
-       int     timeout; /&#x22C6;  return from ioctl after timeout ms with &#x22C6;/
-       };                       /&#x22C6;  errorcode when no message was received  &#x22C6;/
-</programlisting>
-</section>
-
-<section id="frontend_diseqc_slave_reply">
-<title>diseqc slave reply</title>
-<para>The voltage is usually used with non-DiSEqC capable LNBs to switch the polarzation
-(horizontal/vertical). When using DiSEqC epuipment this voltage has to be switched
-consistently to the DiSEqC commands as described in the DiSEqC spec.</para>
-<programlisting>
-       typedef enum fe_sec_voltage {
-       SEC_VOLTAGE_13,
-       SEC_VOLTAGE_18
-       } fe_sec_voltage_t;
-</programlisting>
-</section>
-
-<section id="frontend_sec_tone">
-<title>SEC continuous tone</title>
-
-<para>The continuous 22KHz tone is usually used with non-DiSEqC capable LNBs to switch the
-high/low band of a dual-band LNB. When using DiSEqC epuipment this voltage has to
-be switched consistently to the DiSEqC commands as described in the DiSEqC
-spec.</para>
-<programlisting>
-       typedef enum fe_sec_tone_mode {
-       SEC_TONE_ON,
-       SEC_TONE_OFF
-       } fe_sec_tone_mode_t;
-</programlisting>
-</section>
-
-<section id="frontend_sec_burst">
-<title>SEC tone burst</title>
-
-<para>The 22KHz tone burst is usually used with non-DiSEqC capable switches to select
-between two connected LNBs/satellites. When using DiSEqC epuipment this voltage has to
-be switched consistently to the DiSEqC commands as described in the DiSEqC
-spec.</para>
-<programlisting>
-       typedef enum fe_sec_mini_cmd {
-       SEC_MINI_A,
-       SEC_MINI_B
-       } fe_sec_mini_cmd_t;
-</programlisting>
-
-<para></para>
-</section>
-
-<section id="frontend_status">
-<title>frontend status</title>
-<para>Several functions of the frontend device use the fe_status data type defined
-by</para>
-<programlisting>
- typedef enum fe_status {
-        FE_HAS_SIGNAL     = 0x01,   /&#x22C6;  found something above the noise level &#x22C6;/
-        FE_HAS_CARRIER    = 0x02,   /&#x22C6;  found a DVB signal  &#x22C6;/
-        FE_HAS_VITERBI    = 0x04,   /&#x22C6;  FEC is stable  &#x22C6;/
-        FE_HAS_SYNC       = 0x08,   /&#x22C6;  found sync bytes  &#x22C6;/
-        FE_HAS_LOCK       = 0x10,   /&#x22C6;  everything's working... &#x22C6;/
-        FE_TIMEDOUT       = 0x20,   /&#x22C6;  no lock within the last ~2 seconds &#x22C6;/
-        FE_REINIT         = 0x40    /&#x22C6;  frontend was reinitialized,  &#x22C6;/
- } fe_status_t;                      /&#x22C6;  application is recommned to reset &#x22C6;/
-</programlisting>
-<para>to indicate the current state and/or state changes of the frontend hardware.
-</para>
-
-</section>
-
-<section id="frontend_params">
-<title>frontend parameters</title>
-<para>The kind of parameters passed to the frontend device for tuning depend on
-the kind of hardware you are using. All kinds of parameters are combined as an
-union in the FrontendParameters structure:</para>
-<programlisting>
- struct dvb_frontend_parameters {
-        uint32_t frequency;       /&#x22C6; (absolute) frequency in Hz for QAM/OFDM &#x22C6;/
-                                  /&#x22C6; intermediate frequency in kHz for QPSK &#x22C6;/
-        fe_spectral_inversion_t inversion;
-        union {
-                struct dvb_qpsk_parameters qpsk;
-                struct dvb_qam_parameters  qam;
-                struct dvb_ofdm_parameters ofdm;
-        } u;
- };
-</programlisting>
-<para>For satellite QPSK frontends you have to use the <constant>QPSKParameters</constant> member defined by</para>
-<programlisting>
- struct dvb_qpsk_parameters {
-        uint32_t        symbol_rate;  /&#x22C6; symbol rate in Symbols per second &#x22C6;/
-        fe_code_rate_t  fec_inner;    /&#x22C6; forward error correction (see above) &#x22C6;/
- };
-</programlisting>
-<para>for cable QAM frontend you use the <constant>QAMParameters</constant> structure</para>
-<programlisting>
- struct dvb_qam_parameters {
-        uint32_t         symbol_rate; /&#x22C6; symbol rate in Symbols per second &#x22C6;/
-        fe_code_rate_t   fec_inner;   /&#x22C6; forward error correction (see above) &#x22C6;/
-        fe_modulation_t  modulation;  /&#x22C6; modulation type (see above) &#x22C6;/
- };
-</programlisting>
-<para>DVB-T frontends are supported by the <constant>OFDMParamters</constant> structure
-</para>
-<programlisting>
- struct dvb_ofdm_parameters {
-        fe_bandwidth_t      bandwidth;
-        fe_code_rate_t      code_rate_HP;  /&#x22C6; high priority stream code rate &#x22C6;/
-        fe_code_rate_t      code_rate_LP;  /&#x22C6; low priority stream code rate &#x22C6;/
-        fe_modulation_t     constellation; /&#x22C6; modulation type (see above) &#x22C6;/
-        fe_transmit_mode_t  transmission_mode;
-        fe_guard_interval_t guard_interval;
-        fe_hierarchy_t      hierarchy_information;
- };
-</programlisting>
-<para>In the case of QPSK frontends the <constant>Frequency</constant> field specifies the intermediate
-frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of
-the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and
-OFDM frontends the Frequency specifies the absolute frequency and is given in
-Hz.
-</para>
-<para>The Inversion field can take one of these values:
-</para>
-<programlisting>
- typedef enum fe_spectral_inversion {
-        INVERSION_OFF,
-        INVERSION_ON,
-        INVERSION_AUTO
- } fe_spectral_inversion_t;
-</programlisting>
-<para>It indicates if spectral inversion should be presumed or not. In the automatic setting
-(<constant>INVERSION_AUTO</constant>) the hardware will try to figure out the correct setting by
-itself.
-</para>
-<para>The possible values for the <constant>FEC_inner</constant> field are
-</para>
-<programlisting>
- typedef enum fe_code_rate {
-        FEC_NONE = 0,
-        FEC_1_2,
-        FEC_2_3,
-        FEC_3_4,
-        FEC_4_5,
-        FEC_5_6,
-        FEC_6_7,
-        FEC_7_8,
-        FEC_8_9,
-        FEC_AUTO
- } fe_code_rate_t;
-</programlisting>
-<para>which correspond to error correction rates of 1/2, 2/3, etc., no error correction or auto
-detection.
-</para>
-<para>For cable and terrestrial frontends (QAM and OFDM) one also has to specify the quadrature
-modulation mode which can be one of the following:
-</para>
-<programlisting>
- typedef enum fe_modulation {
- QPSK,
-        QAM_16,
-        QAM_32,
-        QAM_64,
-        QAM_128,
-        QAM_256,
-        QAM_AUTO
- } fe_modulation_t;
-</programlisting>
-<para>Finally, there are several more parameters for OFDM:
-</para>
-<programlisting>
- typedef enum fe_transmit_mode {
-        TRANSMISSION_MODE_2K,
-        TRANSMISSION_MODE_8K,
-        TRANSMISSION_MODE_AUTO
- } fe_transmit_mode_t;
-</programlisting>
- <programlisting>
- typedef enum fe_bandwidth {
-        BANDWIDTH_8_MHZ,
-        BANDWIDTH_7_MHZ,
-        BANDWIDTH_6_MHZ,
-        BANDWIDTH_AUTO
- } fe_bandwidth_t;
-</programlisting>
- <programlisting>
- typedef enum fe_guard_interval {
-        GUARD_INTERVAL_1_32,
-        GUARD_INTERVAL_1_16,
-        GUARD_INTERVAL_1_8,
-        GUARD_INTERVAL_1_4,
-        GUARD_INTERVAL_AUTO
- } fe_guard_interval_t;
-</programlisting>
- <programlisting>
- typedef enum fe_hierarchy {
-        HIERARCHY_NONE,
-        HIERARCHY_1,
-        HIERARCHY_2,
-        HIERARCHY_4,
-        HIERARCHY_AUTO
- } fe_hierarchy_t;
-</programlisting>
-
-</section>
-
-<section id="frontend_events">
-<title>frontend events</title>
- <programlisting>
- struct dvb_frontend_event {
-        fe_status_t status;
-        struct dvb_frontend_parameters parameters;
- };
-</programlisting>
- </section>
-</section>
-
-
-<section id="frontend_fcalls">
-<title>Frontend Function Calls</title>
-
-<section id="frontend_f_open">
-<title>open()</title>
-<para>DESCRIPTION</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>This system call opens a named frontend device (/dev/dvb/adapter0/frontend0)
- for subsequent use. Usually the first thing to do after a successful open is to
- find out the frontend type with <link linkend="FE_GET_INFO">FE_GET_INFO</link>.</para>
-<para>The device can be opened in read-only mode, which only allows monitoring of
- device status and statistics, or read/write mode, which allows any kind of use
- (e.g. performing tuning operations.)
-</para>
-<para>In a system with multiple front-ends, it is usually the case that multiple devices
- cannot be open in read/write mode simultaneously. As long as a front-end
- device is opened in read/write mode, other open() calls in read/write mode will
- either fail or block, depending on whether non-blocking or blocking mode was
- specified. A front-end device opened in blocking mode can later be put into
- non-blocking mode (and vice versa) using the F_SETFL command of the fcntl
- system call. This is a standard system call, documented in the Linux manual
- page for fcntl. When an open() call has succeeded, the device will be ready
- for use in the specified mode. This implies that the corresponding hardware is
- powered up, and that other front-ends may have been powered down to make
- that possible.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open(const char &#x22C6;deviceName, int flags);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>const char
- *deviceName</para>
-</entry><entry
- align="char">
-<para>Name of specific video device.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int flags</para>
-</entry><entry
- align="char">
-<para>A bit-wise OR of the following flags:</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDONLY read-only access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDWR read/write access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_NONBLOCK open in non-blocking mode</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>(blocking mode is the default)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="frontend_f_close">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call closes a previously opened front-end device. After closing
- a front-end device, its corresponding hardware might be powered down
- automatically.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(int fd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_READ_STATUS">
-<title>FE_READ_STATUS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns status information about the front-end. This call only
- requires read-only access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_READ_STATUS">FE_READ_STATUS</link>,
- fe_status_t &#x22C6;status);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_STATUS">FE_READ_STATUS</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct fe_status_t
- *status</para>
-</entry><entry
- align="char">
-<para>Points to the location where the front-end status word is
- to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>status points to invalid address.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_READ_BER">
-<title>FE_READ_BER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the bit error rate for the signal currently
- received/demodulated by the front-end. For this command, read-only access to
- the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_READ_BER">FE_READ_BER</link>,
- uint32_t &#x22C6;ber);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_BER">FE_READ_BER</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>uint32_t *ber</para>
-</entry><entry
- align="char">
-<para>The bit error rate is stored into *ber.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>ber points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSIGNAL</para>
-</entry><entry
- align="char">
-<para>There is no signal, thus no meaningful bit error rate. Also
- returned if the front-end is not turned on.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSYS</para>
-</entry><entry
- align="char">
-<para>Function not available for this device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_READ_SNR">
-<title>FE_READ_SNR</title>
-
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the signal-to-noise ratio for the signal currently received
- by the front-end. For this command, read-only access to the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_READ_SNR">FE_READ_SNR</link>, int16_t
- &#x22C6;snr);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_SNR">FE_READ_SNR</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int16_t *snr</para>
-</entry><entry
- align="char">
-<para>The signal-to-noise ratio is stored into *snr.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>snr points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSIGNAL</para>
-</entry><entry
- align="char">
-<para>There is no signal, thus no meaningful signal strength
- value. Also returned if front-end is not turned on.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSYS</para>
-</entry><entry
- align="char">
-<para>Function not available for this device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_READ_SIGNAL_STRENGTH">
-<title>FE_READ_SIGNAL_STRENGTH</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the signal strength value for the signal currently received
- by the front-end. For this command, read-only access to the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request =
- <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link>, int16_t &#x22C6;strength);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link> for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int16_t *strength</para>
-</entry><entry
- align="char">
-<para>The signal strength value is stored into *strength.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>status points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSIGNAL</para>
-</entry><entry
- align="char">
-<para>There is no signal, thus no meaningful signal strength
- value. Also returned if front-end is not turned on.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSYS</para>
-</entry><entry
- align="char">
-<para>Function not available for this device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_READ_UNCORRECTED_BLOCKS">
-<title>FE_READ_UNCORRECTED_BLOCKS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns the number of uncorrected blocks detected by the device
- driver during its lifetime. For meaningful measurements, the increment in block
- count during a specific time interval should be calculated. For this command,
- read-only access to the device is sufficient.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>Note that the counter will wrap to zero after its maximum count has been
- reached.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl( int fd, int request =
- <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link>, uint32_t &#x22C6;ublocks);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link> for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>uint32_t *ublocks</para>
-</entry><entry
- align="char">
-<para>The total number of uncorrected blocks seen by the driver
- so far.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>ublocks points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOSYS</para>
-</entry><entry
- align="char">
-<para>Function not available for this device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_SET_FRONTEND">
-<title>FE_SET_FRONTEND</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call starts a tuning operation using specified parameters. The result
- of this call will be successful if the parameters were valid and the tuning could
- be initiated. The result of the tuning operation in itself, however, will arrive
- asynchronously as an event (see documentation for <link linkend="FE_GET_EVENT">FE_GET_EVENT</link> and
- FrontendEvent.) If a new <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> operation is initiated before
- the previous one was completed, the previous operation will be aborted in favor
- of the new one. This command requires read/write access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link>,
- struct dvb_frontend_parameters &#x22C6;p);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_parameters
- *p</para>
-</entry><entry
- align="char">
-<para>Points to parameters for tuning operation.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>p points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Maximum supported symbol rate reached.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_GET_FRONTEND">
-<title>FE_GET_FRONTEND</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call queries the currently effective frontend parameters. For this
- command, read-only access to the device is sufficient.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_GET_FRONTEND">FE_GET_FRONTEND</link>,
- struct dvb_frontend_parameters &#x22C6;p);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_parameters
- *p</para>
-</entry><entry
- align="char">
-<para>Points to parameters for tuning operation.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>ERRORS
-</para>
-
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>p points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Maximum supported symbol rate reached.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-
-<section id="FE_GET_EVENT">
-<title>FE_GET_EVENT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns a frontend event if available. If an event is not
- available, the behavior depends on whether the device is in blocking or
- non-blocking mode. In the latter case, the call fails immediately with errno
- set to EWOULDBLOCK. In the former case, the call blocks until an event
- becomes available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The standard Linux poll() and/or select() system calls can be used with the
- device file descriptor to watch for new events. For select(), the file descriptor
- should be included in the exceptfds argument, and for poll(), POLLPRI should
- be specified as the wake-up condition. Since the event queue allocated is
- rather small (room for 8 events), the queue must be serviced regularly to avoid
- overflow. If an overflow happens, the oldest event is discarded from the queue,
- and an error (EOVERFLOW) occurs the next time the queue is read. After
- reporting the error condition in this fashion, subsequent
- <link linkend="FE_GET_EVENT">FE_GET_EVENT</link>
- calls will return events from the queue as usual.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>For the sake of implementation simplicity, this command requires read/write
- access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = QPSK_GET_EVENT,
- struct dvb_frontend_event &#x22C6;ev);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_GET_EVENT">FE_GET_EVENT</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_event
- *ev</para>
-</entry><entry
- align="char">
-<para>Points to the location where the event,</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>if any, is to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>ev points to invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>There is no event pending, and the device is in
- non-blocking mode.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EOVERFLOW</para>
-</entry><entry
- align="char">
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>Overflow in event queue - one or more events were lost.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_GET_INFO">
-<title>FE_GET_INFO</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns information about the front-end. This call only requires
- read-only access to the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(int fd, int request = <link linkend="FE_GET_INFO">FE_GET_INFO</link>, struct
- dvb_frontend_info &#x22C6;info);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_GET_INFO">FE_GET_INFO</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_frontend_info
- *info</para>
-</entry><entry
- align="char">
-<para>Points to the location where the front-end information is
- to be stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>info points to invalid address.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_DISEQC_RESET_OVERLOAD">
-<title>FE_DISEQC_RESET_OVERLOAD</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>If the bus has been automatically powered off due to power overload, this ioctl
- call restores the power to the bus. The call requires read/write access to the
- device. This call has no effect if the device is manually powered off. Not all
- DVB adapters support this ioctl.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_DISEQC_RESET_OVERLOAD">FE_DISEQC_RESET_OVERLOAD</link>);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_DISEQC_RESET_OVERLOAD">FE_DISEQC_RESET_OVERLOAD</link> for this
- command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Permission denied (needs read/write access).</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_DISEQC_SEND_MASTER_CMD">
-<title>FE_DISEQC_SEND_MASTER_CMD</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to send a a DiSEqC command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_DISEQC_SEND_MASTER_CMD">FE_DISEQC_SEND_MASTER_CMD</link>, struct
- dvb_diseqc_master_cmd &#x22C6;cmd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_DISEQC_SEND_MASTER_CMD">FE_DISEQC_SEND_MASTER_CMD</link> for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_diseqc_master_cmd
- *cmd</para>
-</entry><entry
- align="char">
-<para>Pointer to the command to be transmitted.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>Seq points to an invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>The data structure referred to by seq is invalid in some
- way.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Permission denied (needs read/write access).</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_DISEQC_RECV_SLAVE_REPLY">
-<title>FE_DISEQC_RECV_SLAVE_REPLY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to receive reply to a DiSEqC 2.0 command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_DISEQC_RECV_SLAVE_REPLY">FE_DISEQC_RECV_SLAVE_REPLY</link>, struct
- dvb_diseqc_slave_reply &#x22C6;reply);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_DISEQC_RECV_SLAVE_REPLY">FE_DISEQC_RECV_SLAVE_REPLY</link> for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- dvb_diseqc_slave_reply
- *reply</para>
-</entry><entry
- align="char">
-<para>Pointer to the command to be received.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>Seq points to an invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>The data structure referred to by seq is invalid in some
- way.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Permission denied (needs read/write access).</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_DISEQC_SEND_BURST">
-<title>FE_DISEQC_SEND_BURST</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call is used to send a 22KHz tone burst.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_DISEQC_SEND_BURST">FE_DISEQC_SEND_BURST</link>, fe_sec_mini_cmd_t burst);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_DISEQC_SEND_BURST">FE_DISEQC_SEND_BURST</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>fe_sec_mini_cmd_t
- burst</para>
-</entry><entry
- align="char">
-<para>burst A or B.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>Seq points to an invalid address.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>The data structure referred to by seq is invalid in some
- way.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Permission denied (needs read/write access).</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_SET_TONE">
-<title>FE_SET_TONE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This call is used to set the generation of the continuous 22kHz tone. This call
- requires read/write permissions.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_SET_TONE">FE_SET_TONE</link>,
- fe_sec_tone_mode_t tone);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_TONE">FE_SET_TONE</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>fe_sec_tone_mode_t
- tone</para>
-</entry><entry
- align="char">
-<para>The requested tone generation mode (on/off).</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>File not opened with read permissions.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_SET_VOLTAGE">
-<title>FE_SET_VOLTAGE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This call is used to set the bus voltage. This call requires read/write
- permissions.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link>,
- fe_sec_voltage_t voltage);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>fe_sec_voltage_t
- voltage</para>
-</entry><entry
- align="char">
-<para>The requested bus voltage.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>File not opened with read permissions.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_ENABLE_HIGH_LNB_VOLTAGE">
-<title>FE_ENABLE_HIGH_LNB_VOLTAGE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>If high != 0 enables slightly higher voltages instead of 13/18V (to compensate
- for long cables). This call requires read/write permissions. Not all DVB
- adapters support this ioctl.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request =
- <link linkend="FE_ENABLE_HIGH_LNB_VOLTAGE">FE_ENABLE_HIGH_LNB_VOLTAGE</link>, int high);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link> for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int high</para>
-</entry><entry
- align="char">
-<para>The requested bus voltage.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>File not opened with read permissions.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error in the device driver.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_SET_FRONTEND_TUNE_MODE">
-<title>FE_SET_FRONTEND_TUNE_MODE</title>
-<para>DESCRIPTION</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>Allow setting tuner mode flags to the frontend.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>int ioctl(int fd, int request =
-<link linkend="FE_SET_FRONTEND_TUNE_MODE">FE_SET_FRONTEND_TUNE_MODE</link>, unsigned int flags);</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS</para>
-<informaltable><tgroup cols="2"><tbody><row>
-<entry align="char">
-       <para>unsigned int flags</para>
-</entry>
-<entry align="char">
-<para>
-FE_TUNE_MODE_ONESHOT When set, this flag will disable any zigzagging or other "normal" tuning behaviour. Additionally, there will be no automatic monitoring of the lock status, and hence no frontend events will be generated. If a frontend device is closed, this flag will be automatically turned off when the device is reopened read-write.
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>ERRORS</para>
-<informaltable><tgroup cols="2"><tbody><row>
-<entry align="char"><para>EINVAL</para></entry>
-<entry align="char"><para>Invalid argument.</para></entry>
- </row></tbody></tgroup></informaltable>
-</section>
-
-<section id="FE_DISHNETWORK_SEND_LEGACY_CMD">
-       <title>FE_DISHNETWORK_SEND_LEGACY_CMD</title>
-<para>DESCRIPTION</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>WARNING: This is a very obscure legacy command, used only at stv0299 driver. Should not be used on newer drivers.</para>
-<para>It provides a non-standard method for selecting Diseqc voltage on the frontend, for Dish Network legacy switches.</para>
-<para>As support for this ioctl were added in 2004, this means that such dishes were already legacy in 2004.</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-<para>int ioctl(int fd, int request =
-       <link linkend="FE_DISHNETWORK_SEND_LEGACY_CMD">FE_DISHNETWORK_SEND_LEGACY_CMD</link>, unsigned long cmd);</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-
-<para>PARAMETERS</para>
-<informaltable><tgroup cols="2"><tbody><row>
-<entry align="char">
-       <para>unsigned long cmd</para>
-</entry>
-<entry align="char">
-<para>
-sends the specified raw cmd to the dish via DISEqC.
-</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>ERRORS</para>
-<informaltable><tgroup cols="1"><tbody><row>
-<entry align="char">
-       <para>There are no errors in use for this call</para>
-</entry>
-</row></tbody></tgroup></informaltable>
-</section>
-
-</section>
-
-&sub-dvbproperty;
diff --git a/Documentation/DocBook/dvb/intro.xml b/Documentation/DocBook/dvb/intro.xml
deleted file mode 100644 (file)
index 0dc83f6..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-<title>Introduction</title>
-
-<section id="requisites">
-<title>What you need to know</title>
-
-<para>The reader of this document is required to have some knowledge in
-the area of digital video broadcasting (DVB) and should be familiar with
-part I of the MPEG2 specification ISO/IEC 13818 (aka ITU-T H.222), i.e
-you should know what a program/transport stream (PS/TS) is and what is
-meant by a packetized elementary stream (PES) or an I-frame.</para>
-
-<para>Various DVB standards documents are available from
-<ulink url="http://www.dvb.org" /> and/or
-<ulink url="http://www.etsi.org" />.</para>
-
-<para>It is also necessary to know how to access unix/linux devices and
-how to use ioctl calls. This also includes the knowledge of C or C++.
-</para>
-</section>
-
-<section id="history">
-<title>History</title>
-
-<para>The first API for DVB cards we used at Convergence in late 1999
-was an extension of the Video4Linux API which was primarily developed
-for frame grabber cards. As such it was not really well suited to be
-used for DVB cards and their new features like recording MPEG streams
-and filtering several section and PES data streams at the same time.
-</para>
-
-<para>In early 2000, we were approached by Nokia with a proposal for a
-new standard Linux DVB API. As a commitment to the development of
-terminals based on open standards, Nokia and Convergence made it
-available to all Linux developers and published it on
-<ulink url="http://www.linuxtv.org/" /> in September 2000.
-Convergence is the maintainer of the Linux DVB API. Together with the
-LinuxTV community (i.e. you, the reader of this document), the Linux DVB
-API will be constantly reviewed and improved. With the Linux driver for
-the Siemens/Hauppauge DVB PCI card Convergence provides a first
-implementation of the Linux DVB API.</para>
-</section>
-
-<section id="overview">
-<title>Overview</title>
-
-<figure id="stb_components">
-<title>Components of a DVB card/STB</title>
-<mediaobject>
-<imageobject>
-<imagedata fileref="dvbstb.pdf" format="PS" />
-</imageobject>
-<imageobject>
-<imagedata fileref="dvbstb.png" format="PNG" />
-</imageobject>
-</mediaobject>
-</figure>
-
-<para>A DVB PCI card or DVB set-top-box (STB) usually consists of the
-following main hardware components: </para>
-
-<itemizedlist>
- <listitem>
-
-<para>Frontend consisting of tuner and DVB demodulator</para>
-
-<para>Here the raw signal reaches the DVB hardware from a satellite dish
-or antenna or directly from cable. The frontend down-converts and
-demodulates this signal into an MPEG transport stream (TS). In case of a
-satellite frontend, this includes a facility for satellite equipment
-control (SEC), which allows control of LNB polarization, multi feed
-switches or dish rotors.</para>
-
-</listitem>
- <listitem>
-
-<para>Conditional Access (CA) hardware like CI adapters and smartcard slots
-</para>
-
-<para>The complete TS is passed through the CA hardware. Programs to
-which the user has access (controlled by the smart card) are decoded in
-real time and re-inserted into the TS.</para>
-
-</listitem>
- <listitem>
- <para>Demultiplexer which filters the incoming DVB stream</para>
-
-<para>The demultiplexer splits the TS into its components like audio and
-video streams. Besides usually several of such audio and video streams
-it also contains data streams with information about the programs
-offered in this or other streams of the same provider.</para>
-
-</listitem>
-<listitem>
-
-<para>MPEG2 audio and video decoder</para>
-
-<para>The main targets of the demultiplexer are the MPEG2 audio and
-video decoders. After decoding they pass on the uncompressed audio and
-video to the computer screen or (through a PAL/NTSC encoder) to a TV
-set.</para>
-
-
-</listitem>
-</itemizedlist>
-
-<para><xref linkend="stb_components" /> shows a crude schematic of the control and data flow
-between those components.</para>
-
-<para>On a DVB PCI card not all of these have to be present since some
-functionality can be provided by the main CPU of the PC (e.g. MPEG
-picture and sound decoding) or is not needed (e.g. for data-only uses
-like &#8220;internet over satellite&#8221;). Also not every card or STB
-provides conditional access hardware.</para>
-
-</section>
-
-<section id="dvb_devices">
-<title>Linux DVB Devices</title>
-
-<para>The Linux DVB API lets you control these hardware components
-through currently six Unix-style character devices for video, audio,
-frontend, demux, CA and IP-over-DVB networking. The video and audio
-devices control the MPEG2 decoder hardware, the frontend device the
-tuner and the DVB demodulator. The demux device gives you control over
-the PES and section filters of the hardware. If the hardware does not
-support filtering these filters can be implemented in software. Finally,
-the CA device controls all the conditional access capabilities of the
-hardware. It can depend on the individual security requirements of the
-platform, if and how many of the CA functions are made available to the
-application through this device.</para>
-
-<para>All devices can be found in the <emphasis role="tt">/dev</emphasis>
-tree under <emphasis role="tt">/dev/dvb</emphasis>. The individual devices
-are called:</para>
-
-<itemizedlist>
-<listitem>
-
-<para><emphasis role="tt">/dev/dvb/adapterN/audioM</emphasis>,</para>
-</listitem>
-<listitem>
-<para><emphasis role="tt">/dev/dvb/adapterN/videoM</emphasis>,</para>
-</listitem>
-<listitem>
-<para><emphasis role="tt">/dev/dvb/adapterN/frontendM</emphasis>,</para>
-</listitem>
- <listitem>
-
-<para><emphasis role="tt">/dev/dvb/adapterN/netM</emphasis>,</para>
-</listitem>
- <listitem>
-
-<para><emphasis role="tt">/dev/dvb/adapterN/demuxM</emphasis>,</para>
-</listitem>
- <listitem>
-
-<para><emphasis role="tt">/dev/dvb/adapterN/caM</emphasis>,</para></listitem></itemizedlist>
-
-<para>where N enumerates the DVB PCI cards in a system starting
-from&#x00A0;0, and M enumerates the devices of each type within each
-adapter, starting from&#x00A0;0, too. We will omit the &#8220;<emphasis
-role="tt">/dev/dvb/adapterN/</emphasis>&#8221; in the further dicussion
-of these devices. The naming scheme for the devices is the same wheter
-devfs is used or not.</para>
-
-<para>More details about the data structures and function calls of all
-the devices are described in the following chapters.</para>
-
-</section>
-
-<section id="include_files">
-<title>API include files</title>
-
-<para>For each of the DVB devices a corresponding include file exists.
-The DVB API include files should be included in application sources with
-a partial path like:</para>
-
-
-<programlisting>
-       #include &#x003C;linux/dvb/frontend.h&#x003E;
-</programlisting>
-
-<para>To enable applications to support different API version, an
-additional include file <emphasis
-role="tt">linux/dvb/version.h</emphasis> exists, which defines the
-constant <emphasis role="tt">DVB_API_VERSION</emphasis>. This document
-describes <emphasis role="tt">DVB_API_VERSION&#x00A0;3</emphasis>.
-</para>
-
-</section>
-
diff --git a/Documentation/DocBook/dvb/kdapi.xml b/Documentation/DocBook/dvb/kdapi.xml
deleted file mode 100644 (file)
index 6c67481..0000000
+++ /dev/null
@@ -1,2309 +0,0 @@
-<title>Kernel Demux API</title>
-<para>The kernel demux API defines a driver-internal interface for registering low-level,
-hardware specific driver to a hardware independent demux layer. It is only of interest for
-DVB device driver writers. The header file for this API is named <emphasis role="tt">demux.h</emphasis> and located in
-<emphasis role="tt">drivers/media/dvb/dvb-core</emphasis>.
-</para>
-<para>Maintainer note: This section must be reviewed. It is probably out of date.
-</para>
-
-<section id="kernel_demux_data_types">
-<title>Kernel Demux Data Types</title>
-
-
-<section id="dmx_success_t">
-<title>dmx_success_t</title>
- <programlisting>
- typedef enum {
-   DMX_OK = 0, /&#x22C6; Received Ok &#x22C6;/
-   DMX_LENGTH_ERROR, /&#x22C6; Incorrect length &#x22C6;/
-   DMX_OVERRUN_ERROR, /&#x22C6; Receiver ring buffer overrun &#x22C6;/
-   DMX_CRC_ERROR, /&#x22C6; Incorrect CRC &#x22C6;/
-   DMX_FRAME_ERROR, /&#x22C6; Frame alignment error &#x22C6;/
-   DMX_FIFO_ERROR, /&#x22C6; Receiver FIFO overrun &#x22C6;/
-   DMX_MISSED_ERROR /&#x22C6; Receiver missed packet &#x22C6;/
- } dmx_success_t;
-</programlisting>
-
-</section>
-<section id="ts_filter_types">
-<title>TS filter types</title>
- <programlisting>
- /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
- /&#x22C6; TS packet reception &#x22C6;/
- /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
-
- /&#x22C6; TS filter type for set_type() &#x22C6;/
-
- #define TS_PACKET       1   /&#x22C6; send TS packets (188 bytes) to callback (default) &#x22C6;/
- #define TS_PAYLOAD_ONLY 2   /&#x22C6; in case TS_PACKET is set, only send the TS
-                               payload (&#x003C;=184 bytes per packet) to callback &#x22C6;/
- #define TS_DECODER      4   /&#x22C6; send stream to built-in decoder (if present) &#x22C6;/
-</programlisting>
-
-</section>
-<section id="dmx_ts_pes_t">
-<title>dmx_ts_pes_t</title>
-<para>The structure
-</para>
-<programlisting>
- typedef enum
- {
-        DMX_TS_PES_AUDIO,   /&#x22C6; also send packets to audio decoder (if it exists) &#x22C6;/
-        DMX_TS_PES_VIDEO,   /&#x22C6; ... &#x22C6;/
-        DMX_TS_PES_TELETEXT,
-        DMX_TS_PES_SUBTITLE,
-        DMX_TS_PES_PCR,
-        DMX_TS_PES_OTHER,
- } dmx_ts_pes_t;
-</programlisting>
-<para>describes the PES type for filters which write to a built-in decoder. The correspond (and
-should be kept identical) to the types in the demux device.
-</para>
-<programlisting>
- struct dmx_ts_feed_s {
-        int is_filtering; /&#x22C6; Set to non-zero when filtering in progress &#x22C6;/
-        struct dmx_demux_s&#x22C6; parent; /&#x22C6; Back-pointer &#x22C6;/
-        void&#x22C6; priv; /&#x22C6; Pointer to private data of the API client &#x22C6;/
-        int (&#x22C6;set) (struct dmx_ts_feed_s&#x22C6; feed,
-                    __u16 pid,
-                    size_t callback_length,
-                    size_t circular_buffer_size,
-                    int descramble,
-                    struct timespec timeout);
-        int (&#x22C6;start_filtering) (struct dmx_ts_feed_s&#x22C6; feed);
-        int (&#x22C6;stop_filtering) (struct dmx_ts_feed_s&#x22C6; feed);
-        int (&#x22C6;set_type) (struct dmx_ts_feed_s&#x22C6; feed,
-                         int type,
-                         dmx_ts_pes_t pes_type);
- };
-
- typedef struct dmx_ts_feed_s dmx_ts_feed_t;
-</programlisting>
- <programlisting>
- /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
- /&#x22C6; PES packet reception (not supported yet) &#x22C6;/
- /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
-
- typedef struct dmx_pes_filter_s {
-        struct dmx_pes_s&#x22C6; parent; /&#x22C6; Back-pointer &#x22C6;/
-        void&#x22C6; priv; /&#x22C6; Pointer to private data of the API client &#x22C6;/
- } dmx_pes_filter_t;
-</programlisting>
- <programlisting>
- typedef struct dmx_pes_feed_s {
-        int is_filtering; /&#x22C6; Set to non-zero when filtering in progress &#x22C6;/
-        struct dmx_demux_s&#x22C6; parent; /&#x22C6; Back-pointer &#x22C6;/
-        void&#x22C6; priv; /&#x22C6; Pointer to private data of the API client &#x22C6;/
-        int (&#x22C6;set) (struct dmx_pes_feed_s&#x22C6; feed,
-                    __u16 pid,
-                    size_t circular_buffer_size,
-                    int descramble,
-                    struct timespec timeout);
-        int (&#x22C6;start_filtering) (struct dmx_pes_feed_s&#x22C6; feed);
-        int (&#x22C6;stop_filtering) (struct dmx_pes_feed_s&#x22C6; feed);
-        int (&#x22C6;allocate_filter) (struct dmx_pes_feed_s&#x22C6; feed,
-                                dmx_pes_filter_t&#x22C6;&#x22C6; filter);
-        int (&#x22C6;release_filter) (struct dmx_pes_feed_s&#x22C6; feed,
-                               dmx_pes_filter_t&#x22C6; filter);
- } dmx_pes_feed_t;
-</programlisting>
- <programlisting>
- typedef struct {
-        __u8 filter_value [DMX_MAX_FILTER_SIZE];
-        __u8 filter_mask [DMX_MAX_FILTER_SIZE];
-        struct dmx_section_feed_s&#x22C6; parent; /&#x22C6; Back-pointer &#x22C6;/
-        void&#x22C6; priv; /&#x22C6; Pointer to private data of the API client &#x22C6;/
- } dmx_section_filter_t;
-</programlisting>
- <programlisting>
- struct dmx_section_feed_s {
-        int is_filtering; /&#x22C6; Set to non-zero when filtering in progress &#x22C6;/
-        struct dmx_demux_s&#x22C6; parent; /&#x22C6; Back-pointer &#x22C6;/
-        void&#x22C6; priv; /&#x22C6; Pointer to private data of the API client &#x22C6;/
-        int (&#x22C6;set) (struct dmx_section_feed_s&#x22C6; feed,
-                    __u16 pid,
-                    size_t circular_buffer_size,
-                    int descramble,
-                    int check_crc);
-        int (&#x22C6;allocate_filter) (struct dmx_section_feed_s&#x22C6; feed,
-                                dmx_section_filter_t&#x22C6;&#x22C6; filter);
-        int (&#x22C6;release_filter) (struct dmx_section_feed_s&#x22C6; feed,
-                               dmx_section_filter_t&#x22C6; filter);
-        int (&#x22C6;start_filtering) (struct dmx_section_feed_s&#x22C6; feed);
-        int (&#x22C6;stop_filtering) (struct dmx_section_feed_s&#x22C6; feed);
- };
- typedef struct dmx_section_feed_s dmx_section_feed_t;
-
- /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
- /&#x22C6; Callback functions &#x22C6;/
- /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
-
- typedef int (&#x22C6;dmx_ts_cb) ( __u8 &#x22C6; buffer1,
-                           size_t buffer1_length,
-                           __u8 &#x22C6; buffer2,
-                           size_t buffer2_length,
-                           dmx_ts_feed_t&#x22C6; source,
-                           dmx_success_t success);
-
- typedef int (&#x22C6;dmx_section_cb) ( __u8 &#x22C6; buffer1,
-                                size_t buffer1_len,
-                                __u8 &#x22C6; buffer2,
-                                size_t buffer2_len,
-                                dmx_section_filter_t &#x22C6; source,
-                                dmx_success_t success);
-
- typedef int (&#x22C6;dmx_pes_cb) ( __u8 &#x22C6; buffer1,
-                            size_t buffer1_len,
-                            __u8 &#x22C6; buffer2,
-                            size_t buffer2_len,
-                            dmx_pes_filter_t&#x22C6; source,
-                            dmx_success_t success);
-
- /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
- /&#x22C6; DVB Front-End &#x22C6;/
- /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
-
- typedef enum {
-        DMX_OTHER_FE = 0,
-        DMX_SATELLITE_FE,
-        DMX_CABLE_FE,
-        DMX_TERRESTRIAL_FE,
-        DMX_LVDS_FE,
-        DMX_ASI_FE, /&#x22C6; DVB-ASI interface &#x22C6;/
-        DMX_MEMORY_FE
- } dmx_frontend_source_t;
-
- typedef struct {
-        /&#x22C6; The following char&#x22C6; fields point to NULL terminated strings &#x22C6;/
-        char&#x22C6; id;                    /&#x22C6; Unique front-end identifier &#x22C6;/
-        char&#x22C6; vendor;                /&#x22C6; Name of the front-end vendor &#x22C6;/
-        char&#x22C6; model;                 /&#x22C6; Name of the front-end model &#x22C6;/
-        struct list_head connectivity_list; /&#x22C6; List of front-ends that can
-                                               be connected to a particular
-                                               demux &#x22C6;/
-        void&#x22C6; priv;     /&#x22C6; Pointer to private data of the API client &#x22C6;/
-        dmx_frontend_source_t source;
- } dmx_frontend_t;
-
- /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
- /&#x22C6; MPEG-2 TS Demux &#x22C6;/
- /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
-
- /&#x22C6;
-  &#x22C6; Flags OR'ed in the capabilites field of struct dmx_demux_s.
-  &#x22C6;/
-
- #define DMX_TS_FILTERING                        1
- #define DMX_PES_FILTERING                       2
- #define DMX_SECTION_FILTERING                   4
- #define DMX_MEMORY_BASED_FILTERING              8    /&#x22C6; write() available &#x22C6;/
- #define DMX_CRC_CHECKING                        16
- #define DMX_TS_DESCRAMBLING                     32
- #define DMX_SECTION_PAYLOAD_DESCRAMBLING        64
- #define DMX_MAC_ADDRESS_DESCRAMBLING            128
-</programlisting>
-
-</section>
-<section id="demux_demux_t">
-<title>demux_demux_t</title>
- <programlisting>
- /&#x22C6;
-  &#x22C6; DMX_FE_ENTRY(): Casts elements in the list of registered
-  &#x22C6; front-ends from the generic type struct list_head
-  &#x22C6; to the type &#x22C6; dmx_frontend_t
-  &#x22C6;.
- &#x22C6;/
-
- #define DMX_FE_ENTRY(list) list_entry(list, dmx_frontend_t, connectivity_list)
-
- struct dmx_demux_s {
-        /&#x22C6; The following char&#x22C6; fields point to NULL terminated strings &#x22C6;/
-        char&#x22C6; id;                    /&#x22C6; Unique demux identifier &#x22C6;/
-        char&#x22C6; vendor;                /&#x22C6; Name of the demux vendor &#x22C6;/
-        char&#x22C6; model;                 /&#x22C6; Name of the demux model &#x22C6;/
-        __u32 capabilities;          /&#x22C6; Bitfield of capability flags &#x22C6;/
-        dmx_frontend_t&#x22C6; frontend;    /&#x22C6; Front-end connected to the demux &#x22C6;/
-        struct list_head reg_list;   /&#x22C6; List of registered demuxes &#x22C6;/
-        void&#x22C6; priv;                  /&#x22C6; Pointer to private data of the API client &#x22C6;/
-        int users;                   /&#x22C6; Number of users &#x22C6;/
-        int (&#x22C6;open) (struct dmx_demux_s&#x22C6; demux);
-        int (&#x22C6;close) (struct dmx_demux_s&#x22C6; demux);
-        int (&#x22C6;write) (struct dmx_demux_s&#x22C6; demux, const char&#x22C6; buf, size_t count);
-        int (&#x22C6;allocate_ts_feed) (struct dmx_demux_s&#x22C6; demux,
-                                 dmx_ts_feed_t&#x22C6;&#x22C6; feed,
-                                 dmx_ts_cb callback);
-        int (&#x22C6;release_ts_feed) (struct dmx_demux_s&#x22C6; demux,
-                                dmx_ts_feed_t&#x22C6; feed);
-        int (&#x22C6;allocate_pes_feed) (struct dmx_demux_s&#x22C6; demux,
-                                  dmx_pes_feed_t&#x22C6;&#x22C6; feed,
-                                  dmx_pes_cb callback);
-        int (&#x22C6;release_pes_feed) (struct dmx_demux_s&#x22C6; demux,
-                                 dmx_pes_feed_t&#x22C6; feed);
-        int (&#x22C6;allocate_section_feed) (struct dmx_demux_s&#x22C6; demux,
-                                      dmx_section_feed_t&#x22C6;&#x22C6; feed,
-                                      dmx_section_cb callback);
-        int (&#x22C6;release_section_feed) (struct dmx_demux_s&#x22C6; demux,
-                                     dmx_section_feed_t&#x22C6; feed);
-        int (&#x22C6;descramble_mac_address) (struct dmx_demux_s&#x22C6; demux,
-                                       __u8&#x22C6; buffer1,
-                                       size_t buffer1_length,
-                                       __u8&#x22C6; buffer2,
-                                       size_t buffer2_length,
-                                       __u16 pid);
-        int (&#x22C6;descramble_section_payload) (struct dmx_demux_s&#x22C6; demux,
-                                           __u8&#x22C6; buffer1,
-                                           size_t buffer1_length,
-                                           __u8&#x22C6; buffer2, size_t buffer2_length,
-                                           __u16 pid);
-        int (&#x22C6;add_frontend) (struct dmx_demux_s&#x22C6; demux,
-                             dmx_frontend_t&#x22C6; frontend);
-        int (&#x22C6;remove_frontend) (struct dmx_demux_s&#x22C6; demux,
-                                dmx_frontend_t&#x22C6; frontend);
-        struct list_head&#x22C6; (&#x22C6;get_frontends) (struct dmx_demux_s&#x22C6; demux);
-        int (&#x22C6;connect_frontend) (struct dmx_demux_s&#x22C6; demux,
-                                 dmx_frontend_t&#x22C6; frontend);
-        int (&#x22C6;disconnect_frontend) (struct dmx_demux_s&#x22C6; demux);
-
-
-        /&#x22C6; added because js cannot keep track of these himself &#x22C6;/
-        int (&#x22C6;get_pes_pids) (struct dmx_demux_s&#x22C6; demux, __u16 &#x22C6;pids);
- };
- typedef struct dmx_demux_s dmx_demux_t;
-</programlisting>
-
-</section>
-<section id="demux_directory">
-<title>Demux directory</title>
- <programlisting>
- /&#x22C6;
-  &#x22C6; DMX_DIR_ENTRY(): Casts elements in the list of registered
-  &#x22C6; demuxes from the generic type struct list_head&#x22C6; to the type dmx_demux_t
-  &#x22C6;.
-  &#x22C6;/
-
- #define DMX_DIR_ENTRY(list) list_entry(list, dmx_demux_t, reg_list)
-
- int dmx_register_demux (dmx_demux_t&#x22C6; demux);
- int dmx_unregister_demux (dmx_demux_t&#x22C6; demux);
- struct list_head&#x22C6; dmx_get_demuxes (void);
-</programlisting>
- </section></section>
-<section id="demux_directory_api">
-<title>Demux Directory API</title>
-<para>The demux directory is a Linux kernel-wide facility for registering and accessing the
-MPEG-2 TS demuxes in the system. Run-time registering and unregistering of demux drivers
-is possible using this API.
-</para>
-<para>All demux drivers in the directory implement the abstract interface dmx_demux_t.
-</para>
-
-<section
-role="subsection"><title>dmx_register_demux()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function makes a demux driver interface available to the Linux kernel. It is
- usually called by the init_module() function of the kernel module that contains
- the demux driver. The caller of this function is responsible for allocating
- dynamic or static memory for the demux structure and for initializing its fields
- before calling this function. The memory allocated for the demux structure
- must not be freed before calling dmx_unregister_demux(),</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int dmx_register_demux ( dmx_demux_t &#x22C6;demux )</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_demux_t*
- demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux structure.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EEXIST</para>
-</entry><entry
- align="char">
-<para>A demux with the same value of the id field already stored
- in the directory.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOSPC</para>
-</entry><entry
- align="char">
-<para>No space left in the directory.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>dmx_unregister_demux()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function is called to indicate that the given demux interface is no
- longer available. The caller of this function is responsible for freeing the
- memory of the demux structure, if it was dynamically allocated before calling
- dmx_register_demux(). The cleanup_module() function of the kernel module
- that contains the demux driver should call this function. Note that this function
- fails if the demux is currently in use, i.e., release_demux() has not been called
- for the interface.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int dmx_unregister_demux ( dmx_demux_t &#x22C6;demux )</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_demux_t*
- demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux structure which is to be
- unregistered.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>The specified demux is not registered in the demux
- directory.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>The specified demux is currently in use.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>dmx_get_demuxes()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Provides the caller with the list of registered demux interfaces, using the
- standard list structure defined in the include file linux/list.h. The include file
- demux.h defines the macro DMX_DIR_ENTRY() for converting an element of
- the generic type struct list_head* to the type dmx_demux_t*. The caller must
- not free the memory of any of the elements obtained via this function call.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>struct list_head &#x22C6;dmx_get_demuxes ()</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>none</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>struct list_head *</para>
-</entry><entry
- align="char">
-<para>A list of demux interfaces, or NULL in the case of an
- empty list.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section></section>
-<section id="demux_api">
-<title>Demux API</title>
-<para>The demux API should be implemented for each demux in the system. It is used to select
-the TS source of a demux and to manage the demux resources. When the demux
-client allocates a resource via the demux API, it receives a pointer to the API of that
-resource.
-</para>
-<para>Each demux receives its TS input from a DVB front-end or from memory, as set via the
-demux API. In a system with more than one front-end, the API can be used to select one of
-the DVB front-ends as a TS source for a demux, unless this is fixed in the HW platform. The
-demux API only controls front-ends regarding their connections with demuxes; the APIs
-used to set the other front-end parameters, such as tuning, are not defined in this
-document.
-</para>
-<para>The functions that implement the abstract interface demux should be defined static or
-module private and registered to the Demux Directory for external access. It is not necessary
-to implement every function in the demux_t struct, however (for example, a demux interface
-might support Section filtering, but not TS or PES filtering). The API client is expected to
-check the value of any function pointer before calling the function: the value of NULL means
-&#8220;function not available&#8221;.
-</para>
-<para>Whenever the functions of the demux API modify shared data, the possibilities of lost
-update and race condition problems should be addressed, e.g. by protecting parts of code with
-mutexes. This is especially important on multi-processor hosts.
-</para>
-<para>Note that functions called from a bottom half context must not sleep, at least in the 2.2.x
-kernels. Even a simple memory allocation can result in a kernel thread being put to sleep if
-swapping is needed. For example, the Linux kernel calls the functions of a network device
-interface from a bottom half context. Thus, if a demux API function is called from network
-device code, the function must not sleep.
-</para>
-
-
-<section id="kdapi_fopen">
-<title>open()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function reserves the demux for use by the caller and, if necessary,
- initializes the demux. When the demux is no longer needed, the function close()
- should be called. It should be possible for multiple clients to access the demux
- at the same time. Thus, the function implementation should increment the
- demux usage count when open() is called and decrement it when close() is
- called.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open ( demux_t&#x22C6; demux );</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>demux_t* demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EUSERS</para>
-</entry><entry
- align="char">
-<para>Maximum usage count reached.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="kdapi_fclose">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function reserves the demux for use by the caller and, if necessary,
- initializes the demux. When the demux is no longer needed, the function close()
- should be called. It should be possible for multiple clients to access the demux
- at the same time. Thus, the function implementation should increment the
- demux usage count when open() is called and decrement it when close() is
- called.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(demux_t&#x22C6; demux);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>demux_t* demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENODEV</para>
-</entry><entry
- align="char">
-<para>The demux was not in use.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="kdapi_fwrite">
-<title>write()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function provides the demux driver with a memory buffer containing TS
- packets. Instead of receiving TS packets from the DVB front-end, the demux
- driver software will read packets from memory. Any clients of this demux
- with active TS, PES or Section filters will receive filtered data via the Demux
- callback API (see 0). The function returns when all the data in the buffer has
- been consumed by the demux. Demux hardware typically cannot read TS from
- memory. If this is the case, memory-based filtering has to be implemented
- entirely in software.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int write(demux_t&#x22C6; demux, const char&#x22C6; buf, size_t
- count);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>demux_t* demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>const char* buf</para>
-</entry><entry
- align="char">
-<para>Pointer to the TS data in kernel-space memory.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t length</para>
-</entry><entry
- align="char">
-<para>Length of the TS data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOSYS</para>
-</entry><entry
- align="char">
-<para>The command is not implemented.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>allocate_ts_feed()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Allocates a new TS feed, which is used to filter the TS packets carrying a
- certain PID. The TS feed normally corresponds to a hardware PID filter on the
- demux chip.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int allocate_ts_feed(dmx_demux_t&#x22C6; demux,
- dmx_ts_feed_t&#x22C6;&#x22C6; feed, dmx_ts_cb callback);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>demux_t* demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_ts_feed_t**
- feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the TS feed API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_ts_cb callback</para>
-</entry><entry
- align="char">
-<para>Pointer to the callback function for passing received TS
- packet</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EBUSY</para>
-</entry><entry
- align="char">
-<para>No more TS feeds available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOSYS</para>
-</entry><entry
- align="char">
-<para>The command is not implemented.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>release_ts_feed()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Releases the resources allocated with allocate_ts_feed(). Any filtering in
- progress on the TS feed should be stopped before calling this function.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int release_ts_feed(dmx_demux_t&#x22C6; demux,
- dmx_ts_feed_t&#x22C6; feed);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>demux_t* demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_ts_feed_t* feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the TS feed API and instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>allocate_section_feed()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Allocates a new section feed, i.e. a demux resource for filtering and receiving
- sections. On platforms with hardware support for section filtering, a section
- feed is directly mapped to the demux HW. On other platforms, TS packets are
- first PID filtered in hardware and a hardware section filter then emulated in
- software. The caller obtains an API pointer of type dmx_section_feed_t as an
- out parameter. Using this API the caller can set filtering parameters and start
- receiving sections.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int allocate_section_feed(dmx_demux_t&#x22C6; demux,
- dmx_section_feed_t &#x22C6;&#x22C6;feed, dmx_section_cb callback);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>demux_t *demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_section_feed_t
- **feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the section feed API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_section_cb
- callback</para>
-</entry><entry
- align="char">
-<para>Pointer to the callback function for passing received
- sections.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EBUSY</para>
-</entry><entry
- align="char">
-<para>No more section feeds available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOSYS</para>
-</entry><entry
- align="char">
-<para>The command is not implemented.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>release_section_feed()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Releases the resources allocated with allocate_section_feed(), including
- allocated filters. Any filtering in progress on the section feed should be stopped
- before calling this function.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int release_section_feed(dmx_demux_t&#x22C6; demux,
- dmx_section_feed_t &#x22C6;feed);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>demux_t *demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_section_feed_t
- *feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the section feed API and instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>descramble_mac_address()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function runs a descrambling algorithm on the destination MAC
- address field of a DVB Datagram Section, replacing the original address
- with its un-encrypted version. Otherwise, the description on the function
- descramble_section_payload() applies also to this function.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int descramble_mac_address(dmx_demux_t&#x22C6; demux, __u8
- &#x22C6;buffer1, size_t buffer1_length, __u8 &#x22C6;buffer2,
- size_t buffer2_length, __u16 pid);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_demux_t
- *demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u8 *buffer1</para>
-</entry><entry
- align="char">
-<para>Pointer to the first byte of the section.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t buffer1_length</para>
-</entry><entry
- align="char">
-<para>Length of the section data, including headers and CRC,
- in buffer1.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u8* buffer2</para>
-</entry><entry
- align="char">
-<para>Pointer to the tail of the section data, or NULL. The
- pointer has a non-NULL value if the section wraps past
- the end of a circular buffer.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t buffer2_length</para>
-</entry><entry
- align="char">
-<para>Length of the section data, including headers and CRC,
- in buffer2.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u16 pid</para>
-</entry><entry
- align="char">
-<para>The PID on which the section was received. Useful
- for obtaining the descrambling key, e.g. from a DVB
- Common Access facility.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOSYS</para>
-</entry><entry
- align="char">
-<para>No descrambling facility available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>descramble_section_payload()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function runs a descrambling algorithm on the payload of a DVB
- Datagram Section, replacing the original payload with its un-encrypted
- version. The function will be called from the demux API implementation;
- the API client need not call this function directly. Section-level scrambling
- algorithms are currently standardized only for DVB-RCC (return channel
- over 2-directional cable TV network) systems. For all other DVB networks,
- encryption schemes are likely to be proprietary to each data broadcaster. Thus,
- it is expected that this function pointer will have the value of NULL (i.e.,
- function not available) in most demux API implementations. Nevertheless, it
- should be possible to use the function pointer as a hook for dynamically adding
- a &#8220;plug-in&#8221; descrambling facility to a demux driver.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>While this function is not needed with hardware-based section descrambling,
- the descramble_section_payload function pointer can be used to override the
- default hardware-based descrambling algorithm: if the function pointer has a
- non-NULL value, the corresponding function should be used instead of any
- descrambling hardware.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int descramble_section_payload(dmx_demux_t&#x22C6; demux,
- __u8 &#x22C6;buffer1, size_t buffer1_length, __u8 &#x22C6;buffer2,
- size_t buffer2_length, __u16 pid);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_demux_t
- *demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u8 *buffer1</para>
-</entry><entry
- align="char">
-<para>Pointer to the first byte of the section.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t buffer1_length</para>
-</entry><entry
- align="char">
-<para>Length of the section data, including headers and CRC,
- in buffer1.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u8 *buffer2</para>
-</entry><entry
- align="char">
-<para>Pointer to the tail of the section data, or NULL. The
- pointer has a non-NULL value if the section wraps past
- the end of a circular buffer.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t buffer2_length</para>
-</entry><entry
- align="char">
-<para>Length of the section data, including headers and CRC,
- in buffer2.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u16 pid</para>
-</entry><entry
- align="char">
-<para>The PID on which the section was received. Useful
- for obtaining the descrambling key, e.g. from a DVB
- Common Access facility.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOSYS</para>
-</entry><entry
- align="char">
-<para>No descrambling facility available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>add_frontend()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Registers a connectivity between a demux and a front-end, i.e., indicates that
- the demux can be connected via a call to connect_frontend() to use the given
- front-end as a TS source. The client of this function has to allocate dynamic or
- static memory for the frontend structure and initialize its fields before calling
- this function. This function is normally called during the driver initialization.
- The caller must not free the memory of the frontend struct before successfully
- calling remove_frontend().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int add_frontend(dmx_demux_t &#x22C6;demux, dmx_frontend_t
- &#x22C6;frontend);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_demux_t*
- demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_frontend_t*
- frontend</para>
-</entry><entry
- align="char">
-<para>Pointer to the front-end instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EEXIST</para>
-</entry><entry
- align="char">
-<para>A front-end with the same value of the id field already
- registered.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINUSE</para>
-</entry><entry
- align="char">
-<para>The demux is in use.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOMEM</para>
-</entry><entry
- align="char">
-<para>No more front-ends can be added.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>remove_frontend()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Indicates that the given front-end, registered by a call to add_frontend(), can
- no longer be connected as a TS source by this demux. The function should be
- called when a front-end driver or a demux driver is removed from the system.
- If the front-end is in use, the function fails with the return value of -EBUSY.
- After successfully calling this function, the caller can free the memory of
- the frontend struct if it was dynamically allocated before the add_frontend()
- operation.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int remove_frontend(dmx_demux_t&#x22C6; demux,
- dmx_frontend_t&#x22C6; frontend);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_demux_t*
- demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_frontend_t*
- frontend</para>
-</entry><entry
- align="char">
-<para>Pointer to the front-end instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EBUSY</para>
-</entry><entry
- align="char">
-<para>The front-end is in use, i.e. a call to connect_frontend()
- has not been followed by a call to disconnect_frontend().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>get_frontends()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Provides the APIs of the front-ends that have been registered for this demux.
- Any of the front-ends obtained with this call can be used as a parameter for
- connect_frontend().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The include file demux.h contains the macro DMX_FE_ENTRY() for
- converting an element of the generic type struct list_head* to the type
- dmx_frontend_t*. The caller must not free the memory of any of the elements
- obtained via this function call.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>struct list_head&#x22C6; get_frontends(dmx_demux_t&#x22C6; demux);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_demux_t*
- demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_demux_t*</para>
-</entry><entry
- align="char">
-<para>A list of front-end interfaces, or NULL in the case of an
- empty list.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>connect_frontend()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Connects the TS output of the front-end to the input of the demux. A demux
- can only be connected to a front-end registered to the demux with the function
- add_frontend().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>It may or may not be possible to connect multiple demuxes to the same
- front-end, depending on the capabilities of the HW platform. When not used,
- the front-end should be released by calling disconnect_frontend().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int connect_frontend(dmx_demux_t&#x22C6; demux,
- dmx_frontend_t&#x22C6; frontend);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_demux_t*
- demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_frontend_t*
- frontend</para>
-</entry><entry
- align="char">
-<para>Pointer to the front-end instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EBUSY</para>
-</entry><entry
- align="char">
-<para>The front-end is in use.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>disconnect_frontend()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Disconnects the demux and a front-end previously connected by a
- connect_frontend() call.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int disconnect_frontend(dmx_demux_t&#x22C6; demux);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_demux_t*
- demux</para>
-</entry><entry
- align="char">
-<para>Pointer to the demux API and instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section></section>
-<section id="demux_callback_api">
-<title>Demux Callback API</title>
-<para>This kernel-space API comprises the callback functions that deliver filtered data to the
-demux client. Unlike the other APIs, these API functions are provided by the client and called
-from the demux code.
-</para>
-<para>The function pointers of this abstract interface are not packed into a structure as in the
-other demux APIs, because the callback functions are registered and used independent
-of each other. As an example, it is possible for the API client to provide several
-callback functions for receiving TS packets and no callbacks for PES packets or
-sections.
-</para>
-<para>The functions that implement the callback API need not be re-entrant: when a demux
-driver calls one of these functions, the driver is not allowed to call the function again before
-the original call returns. If a callback is triggered by a hardware interrupt, it is recommended
-to use the Linux &#8220;bottom half&#8221; mechanism or start a tasklet instead of making the callback
-function call directly from a hardware interrupt.
-</para>
-
-<section
-role="subsection"><title>dmx_ts_cb()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function, provided by the client of the demux API, is called from the
- demux code. The function is only called when filtering on this TS feed has
- been enabled using the start_filtering() function.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>Any TS packets that match the filter settings are copied to a circular buffer. The
- filtered TS packets are delivered to the client using this callback function. The
- size of the circular buffer is controlled by the circular_buffer_size parameter
- of the set() function in the TS Feed API. It is expected that the buffer1 and
- buffer2 callback parameters point to addresses within the circular buffer, but
- other implementations are also possible. Note that the called party should not
- try to free the memory the buffer1 and buffer2 parameters point to.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>When this function is called, the buffer1 parameter typically points to the
- start of the first undelivered TS packet within a circular buffer. The buffer2
- buffer parameter is normally NULL, except when the received TS packets have
- crossed the last address of the circular buffer and &#8221;wrapped&#8221; to the beginning
- of the buffer. In the latter case the buffer1 parameter would contain an address
- within the circular buffer, while the buffer2 parameter would contain the first
- address of the circular buffer.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The number of bytes delivered with this function (i.e. buffer1_length +
- buffer2_length) is usually equal to the value of callback_length parameter
- given in the set() function, with one exception: if a timeout occurs before
- receiving callback_length bytes of TS data, any undelivered packets are
- immediately delivered to the client by calling this function. The timeout
- duration is controlled by the set() function in the TS Feed API.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>If a TS packet is received with errors that could not be fixed by the TS-level
- forward error correction (FEC), the Transport_error_indicator flag of the TS
- packet header should be set. The TS packet should not be discarded, as
- the error can possibly be corrected by a higher layer protocol. If the called
- party is slow in processing the callback, it is possible that the circular buffer
- eventually fills up. If this happens, the demux driver should discard any TS
- packets received while the buffer is full. The error should be indicated to the
- client on the next callback by setting the success parameter to the value of
- DMX_OVERRUN_ERROR.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The type of data returned to the callback can be selected by the new
- function int (*set_type) (struct dmx_ts_feed_s* feed, int type, dmx_ts_pes_t
- pes_type) which is part of the dmx_ts_feed_s struct (also cf. to the
- include file ost/demux.h) The type parameter decides if the raw TS packet
- (TS_PACKET) or just the payload (TS_PACKET&#8212;TS_PAYLOAD_ONLY)
- should be returned. If additionally the TS_DECODER bit is set the stream
- will also be sent to the hardware MPEG decoder. In this case, the second
- flag decides as what kind of data the stream should be interpreted. The
- possible choices are one of DMX_TS_PES_AUDIO, DMX_TS_PES_VIDEO,
- DMX_TS_PES_TELETEXT, DMX_TS_PES_SUBTITLE,
- DMX_TS_PES_PCR, or DMX_TS_PES_OTHER.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int dmx_ts_cb(__u8&#x22C6; buffer1, size_t buffer1_length,
- __u8&#x22C6; buffer2, size_t buffer2_length, dmx_ts_feed_t&#x22C6;
- source, dmx_success_t success);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>__u8* buffer1</para>
-</entry><entry
- align="char">
-<para>Pointer to the start of the filtered TS packets.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t buffer1_length</para>
-</entry><entry
- align="char">
-<para>Length of the TS data in buffer1.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u8* buffer2</para>
-</entry><entry
- align="char">
-<para>Pointer to the tail of the filtered TS packets, or NULL.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t buffer2_length</para>
-</entry><entry
- align="char">
-<para>Length of the TS data in buffer2.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_ts_feed_t*
- source</para>
-</entry><entry
- align="char">
-<para>Indicates which TS feed is the source of the callback.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_success_t
- success</para>
-</entry><entry
- align="char">
-<para>Indicates if there was an error in TS reception.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>Continue filtering.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-1</para>
-</entry><entry
- align="char">
-<para>Stop filtering - has the same effect as a call to
- stop_filtering() on the TS Feed API.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>dmx_section_cb()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function, provided by the client of the demux API, is called from the
- demux code. The function is only called when filtering of sections has been
- enabled using the function start_filtering() of the section feed API. When the
- demux driver has received a complete section that matches at least one section
- filter, the client is notified via this callback function. Normally this function is
- called for each received section; however, it is also possible to deliver multiple
- sections with one callback, for example when the system load is high. If an
- error occurs while receiving a section, this function should be called with
- the corresponding error type set in the success field, whether or not there is
- data to deliver. The Section Feed implementation should maintain a circular
- buffer for received sections. However, this is not necessary if the Section Feed
- API is implemented as a client of the TS Feed API, because the TS Feed
- implementation then buffers the received data. The size of the circular buffer
- can be configured using the set() function in the Section Feed API. If there
- is no room in the circular buffer when a new section is received, the section
- must be discarded. If this happens, the value of the success parameter should
- be DMX_OVERRUN_ERROR on the next callback.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int dmx_section_cb(__u8&#x22C6; buffer1, size_t
- buffer1_length, __u8&#x22C6; buffer2, size_t
- buffer2_length, dmx_section_filter_t&#x22C6; source,
- dmx_success_t success);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>__u8* buffer1</para>
-</entry><entry
- align="char">
-<para>Pointer to the start of the filtered section, e.g. within the
- circular buffer of the demux driver.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t buffer1_length</para>
-</entry><entry
- align="char">
-<para>Length of the filtered section data in buffer1, including
- headers and CRC.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u8* buffer2</para>
-</entry><entry
- align="char">
-<para>Pointer to the tail of the filtered section data, or NULL.
- Useful to handle the wrapping of a circular buffer.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t buffer2_length</para>
-</entry><entry
- align="char">
-<para>Length of the filtered section data in buffer2, including
- headers and CRC.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_section_filter_t*
- filter</para>
-</entry><entry
- align="char">
-<para>Indicates the filter that triggered the callback.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_success_t
- success</para>
-</entry><entry
- align="char">
-<para>Indicates if there was an error in section reception.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>Continue filtering.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-1</para>
-</entry><entry
- align="char">
-<para>Stop filtering - has the same effect as a call to
- stop_filtering() on the Section Feed API.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section></section>
-<section id="ts_feed_api">
-<title>TS Feed API</title>
-<para>A TS feed is typically mapped to a hardware PID filter on the demux chip.
-Using this API, the client can set the filtering properties to start/stop filtering TS
-packets on a particular TS feed. The API is defined as an abstract interface of the type
-dmx_ts_feed_t.
-</para>
-<para>The functions that implement the interface should be defined static or module private. The
-client can get the handle of a TS feed API by calling the function allocate_ts_feed() in the
-demux API.
-</para>
-
-<section
-role="subsection"><title>set()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function sets the parameters of a TS feed. Any filtering in progress on the
- TS feed must be stopped before calling this function.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int set ( dmx_ts_feed_t&#x22C6; feed, __u16 pid, size_t
- callback_length, size_t circular_buffer_size, int
- descramble, struct timespec timeout);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_ts_feed_t* feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the TS feed API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u16 pid</para>
-</entry><entry
- align="char">
-<para>PID value to filter. Only the TS packets carrying the
- specified PID will be passed to the API client.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t
- callback_length</para>
-</entry><entry
- align="char">
-<para>Number of bytes to deliver with each call to the
- dmx_ts_cb() callback function. The value of this
- parameter should be a multiple of 188.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t
- circular_buffer_size</para>
-</entry><entry
- align="char">
-<para>Size of the circular buffer for the filtered TS packets.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int descramble</para>
-</entry><entry
- align="char">
-<para>If non-zero, descramble the filtered TS packets.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct timespec
- timeout</para>
-</entry><entry
- align="char">
-<para>Maximum time to wait before delivering received TS
- packets to the client.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOMEM</para>
-</entry><entry
- align="char">
-<para>Not enough memory for the requested buffer size.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOSYS</para>
-</entry><entry
- align="char">
-<para>No descrambling facility available for TS.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>start_filtering()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Starts filtering TS packets on this TS feed, according to its settings. The PID
- value to filter can be set by the API client. All matching TS packets are
- delivered asynchronously to the client, using the callback function registered
- with allocate_ts_feed().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int start_filtering(dmx_ts_feed_t&#x22C6; feed);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_ts_feed_t* feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the TS feed API and instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>stop_filtering()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Stops filtering TS packets on this TS feed.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int stop_filtering(dmx_ts_feed_t&#x22C6; feed);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_ts_feed_t* feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the TS feed API and instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section></section>
-<section id="section_feed_api">
-<title>Section Feed API</title>
-<para>A section feed is a resource consisting of a PID filter and a set of section filters. Using this
-API, the client can set the properties of a section feed and to start/stop filtering. The API is
-defined as an abstract interface of the type dmx_section_feed_t. The functions that implement
-the interface should be defined static or module private. The client can get the handle of
-a section feed API by calling the function allocate_section_feed() in the demux
-API.
-</para>
-<para>On demux platforms that provide section filtering in hardware, the Section Feed API
-implementation provides a software wrapper for the demux hardware. Other platforms may
-support only PID filtering in hardware, requiring that TS packets are converted to sections in
-software. In the latter case the Section Feed API implementation can be a client of the TS
-Feed API.
-</para>
-
-</section>
-<section id="kdapi_set">
-<title>set()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function sets the parameters of a section feed. Any filtering in progress on
- the section feed must be stopped before calling this function. If descrambling
- is enabled, the payload_scrambling_control and address_scrambling_control
- fields of received DVB datagram sections should be observed. If either one is
- non-zero, the section should be descrambled either in hardware or using the
- functions descramble_mac_address() and descramble_section_payload() of the
- demux API. Note that according to the MPEG-2 Systems specification, only
- the payloads of private sections can be scrambled while the rest of the section
- data must be sent in the clear.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int set(dmx_section_feed_t&#x22C6; feed, __u16 pid, size_t
- circular_buffer_size, int descramble, int
- check_crc);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_section_feed_t*
- feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the section feed API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>__u16 pid</para>
-</entry><entry
- align="char">
-<para>PID value to filter; only the TS packets carrying the
- specified PID will be accepted.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t
- circular_buffer_size</para>
-</entry><entry
- align="char">
-<para>Size of the circular buffer for filtered sections.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int descramble</para>
-</entry><entry
- align="char">
-<para>If non-zero, descramble any sections that are scrambled.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int check_crc</para>
-</entry><entry
- align="char">
-<para>If non-zero, check the CRC values of filtered sections.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOMEM</para>
-</entry><entry
- align="char">
-<para>Not enough memory for the requested buffer size.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOSYS</para>
-</entry><entry
- align="char">
-<para>No descrambling facility available for sections.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameters.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>allocate_filter()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function is used to allocate a section filter on the demux. It should only be
- called when no filtering is in progress on this section feed. If a filter cannot be
- allocated, the function fails with -ENOSPC. See in section ?? for the format of
- the section filter.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>The bitfields filter_mask and filter_value should only be modified when no
- filtering is in progress on this section feed. filter_mask controls which bits of
- filter_value are compared with the section headers/payload. On a binary value
- of 1 in filter_mask, the corresponding bits are compared. The filter only accepts
- sections that are equal to filter_value in all the tested bit positions. Any changes
- to the values of filter_mask and filter_value are guaranteed to take effect only
- when the start_filtering() function is called next time. The parent pointer in
- the struct is initialized by the API implementation to the value of the feed
- parameter. The priv pointer is not used by the API implementation, and can
- thus be freely utilized by the caller of this function. Any data pointed to by the
- priv pointer is available to the recipient of the dmx_section_cb() function call.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>While the maximum section filter length (DMX_MAX_FILTER_SIZE) is
- currently set at 16 bytes, hardware filters of that size are not available on all
- platforms. Therefore, section filtering will often take place first in hardware,
- followed by filtering in software for the header bytes that were not covered
- by a hardware filter. The filter_mask field can be checked to determine how
- many bytes of the section filter are actually used, and if the hardware filter will
- suffice. Additionally, software-only section filters can optionally be allocated
- to clients when all hardware section filters are in use. Note that on most demux
- hardware it is not possible to filter on the section_length field of the section
- header &#8211; thus this field is ignored, even though it is included in filter_value and
- filter_mask fields.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int allocate_filter(dmx_section_feed_t&#x22C6; feed,
- dmx_section_filter_t&#x22C6;&#x22C6; filter);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_section_feed_t*
- feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the section feed API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_section_filter_t**
- filter</para>
-</entry><entry
- align="char">
-<para>Pointer to the allocated filter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENOSPC</para>
-</entry><entry
- align="char">
-<para>No filters of given type and length available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameters.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>release_filter()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This function releases all the resources of a previously allocated section filter.
- The function should not be called while filtering is in progress on this section
- feed. After calling this function, the caller should not try to dereference the
- filter pointer.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int release_filter ( dmx_section_feed_t&#x22C6; feed,
- dmx_section_filter_t&#x22C6; filter);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_section_feed_t*
- feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the section feed API and instance data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>dmx_section_filter_t*
- filter</para>
-</entry><entry
- align="char">
-<para>I/O Pointer to the instance data of a section filter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-ENODEV</para>
-</entry><entry
- align="char">
-<para>No such filter allocated.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>start_filtering()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Starts filtering sections on this section feed, according to its settings. Sections
- are first filtered based on their PID and then matched with the section
- filters allocated for this feed. If the section matches the PID filter and
- at least one section filter, it is delivered to the API client. The section
- is delivered asynchronously using the callback function registered with
- allocate_section_feed().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int start_filtering ( dmx_section_feed_t&#x22C6; feed );</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_section_feed_t*
- feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the section feed API and instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>stop_filtering()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>Stops filtering sections on this section feed. Note that any changes to the
- filtering parameters (filter_value, filter_mask, etc.) should only be made when
- filtering is stopped.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int stop_filtering ( dmx_section_feed_t&#x22C6; feed );</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>dmx_section_feed_t*
- feed</para>
-</entry><entry
- align="char">
-<para>Pointer to the section feed API and instance data.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>RETURNS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>0</para>
-</entry><entry
- align="char">
-<para>The function was completed without errors.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>-EINVAL</para>
-</entry><entry
- align="char">
-<para>Bad parameter.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
diff --git a/Documentation/DocBook/dvb/net.xml b/Documentation/DocBook/dvb/net.xml
deleted file mode 100644 (file)
index 94e388d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<title>DVB Network API</title>
-<para>The DVB net device enables feeding of MPE (multi protocol encapsulation) packets
-received via DVB into the Linux network protocol stack, e.g. for internet via satellite
-applications. It can be accessed through <emphasis role="tt">/dev/dvb/adapter0/net0</emphasis>. Data types and
-and ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/net.h</emphasis> in your
-application.
-</para>
-<section id="dvb_net_types">
-<title>DVB Net Data Types</title>
-<para>To be written&#x2026;
-</para>
-</section>
diff --git a/Documentation/DocBook/dvb/video.xml b/Documentation/DocBook/dvb/video.xml
deleted file mode 100644 (file)
index 7bb287e..0000000
+++ /dev/null
@@ -1,1971 +0,0 @@
-<title>DVB Video Device</title>
-<para>The DVB video device controls the MPEG2 video decoder of the DVB hardware. It
-can be accessed through <emphasis role="tt">/dev/dvb/adapter0/video0</emphasis>. Data types and and
-ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/video.h</emphasis> in your
-application.
-</para>
-<para>Note that the DVB video device only controls decoding of the MPEG video stream, not
-its presentation on the TV or computer screen. On PCs this is typically handled by an
-associated video4linux device, e.g. <emphasis role="tt">/dev/video</emphasis>, which allows scaling and defining output
-windows.
-</para>
-<para>Some DVB cards don&#8217;t have their own MPEG decoder, which results in the omission of
-the audio and video device as well as the video4linux device.
-</para>
-<para>The ioctls that deal with SPUs (sub picture units) and navigation packets are only
-supported on some MPEG decoders made for DVD playback.
-</para>
-<section id="video_types">
-<title>Video Data Types</title>
-
-<section id="video_format_t">
-<title>video_format_t</title>
-<para>The <emphasis role="tt">video_format_t</emphasis> data type defined by
-</para>
-<programlisting>
- typedef enum {
-        VIDEO_FORMAT_4_3,
-        VIDEO_FORMAT_16_9
- } video_format_t;
-</programlisting>
-<para>is used in the VIDEO_SET_FORMAT function (??) to tell the driver which aspect ratio
-the output hardware (e.g. TV) has. It is also used in the data structures video_status
-(??) returned by VIDEO_GET_STATUS (??) and video_event (??) returned by
-VIDEO_GET_EVENT (??) which report about the display format of the current video
-stream.
-</para>
-</section>
-
-<section id="video_display_format_t">
-<title>video_display_format_t</title>
-<para>In case the display format of the video stream and of the display hardware differ the
-application has to specify how to handle the cropping of the picture. This can be done using
-the VIDEO_SET_DISPLAY_FORMAT call (??) which accepts
-</para>
-<programlisting>
- typedef enum {
-        VIDEO_PAN_SCAN,
-        VIDEO_LETTER_BOX,
-        VIDEO_CENTER_CUT_OUT
- } video_display_format_t;
-</programlisting>
-<para>as argument.
-</para>
-</section>
-
-<section id="video_stream_source">
-<title>video stream source</title>
-<para>The video stream source is set through the VIDEO_SELECT_SOURCE call and can take
-the following values, depending on whether we are replaying from an internal (demuxer) or
-external (user write) source.
-</para>
-<programlisting>
- typedef enum {
-        VIDEO_SOURCE_DEMUX,
-        VIDEO_SOURCE_MEMORY
- } video_stream_source_t;
-</programlisting>
-<para>VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the
-DVR device) as the source of the video stream. If VIDEO_SOURCE_MEMORY
-is selected the stream comes from the application through the <emphasis role="tt">write()</emphasis> system
-call.
-</para>
-</section>
-
-<section id="video_play_state">
-<title>video play state</title>
-<para>The following values can be returned by the VIDEO_GET_STATUS call representing the
-state of video playback.
-</para>
-<programlisting>
- typedef enum {
-        VIDEO_STOPPED,
-        VIDEO_PLAYING,
-        VIDEO_FREEZED
- } video_play_state_t;
-</programlisting>
-</section>
-
-<section id="video_event">
-<title>struct video_event</title>
-<para>The following is the structure of a video event as it is returned by the VIDEO_GET_EVENT
-call.
-</para>
-<programlisting>
- struct video_event {
-        int32_t type;
-        time_t timestamp;
-        union {
-                video_format_t video_format;
-        } u;
- };
-</programlisting>
-</section>
-
-<section id="video_status">
-<title>struct video_status</title>
-<para>The VIDEO_GET_STATUS call returns the following structure informing about various
-states of the playback operation.
-</para>
-<programlisting>
- struct video_status {
-        boolean video_blank;
-        video_play_state_t play_state;
-        video_stream_source_t stream_source;
-        video_format_t video_format;
-        video_displayformat_t display_format;
- };
-</programlisting>
-<para>If video_blank is set video will be blanked out if the channel is changed or if playback is
-stopped. Otherwise, the last picture will be displayed. play_state indicates if the video is
-currently frozen, stopped, or being played back. The stream_source corresponds to the seleted
-source for the video stream. It can come either from the demultiplexer or from memory.
-The video_format indicates the aspect ratio (one of 4:3 or 16:9) of the currently
-played video stream. Finally, display_format corresponds to the selected cropping
-mode in case the source video format is not the same as the format of the output
-device.
-</para>
-</section>
-
-<section id="video_still_picture">
-<title>struct video_still_picture</title>
-<para>An I-frame displayed via the VIDEO_STILLPICTURE call is passed on within the
-following structure.
-</para>
-<programlisting>
- /&#x22C6; pointer to and size of a single iframe in memory &#x22C6;/
- struct video_still_picture {
-        char &#x22C6;iFrame;
-        int32_t size;
- };
-</programlisting>
-</section>
-
-<section id="video_caps">
-<title>video capabilities</title>
-<para>A call to VIDEO_GET_CAPABILITIES returns an unsigned integer with the following
-bits set according to the hardwares capabilities.
-</para>
-<programlisting>
- /&#x22C6; bit definitions for capabilities: &#x22C6;/
- /&#x22C6; can the hardware decode MPEG1 and/or MPEG2? &#x22C6;/
- #define VIDEO_CAP_MPEG1   1
- #define VIDEO_CAP_MPEG2   2
- /&#x22C6; can you send a system and/or program stream to video device?
-    (you still have to open the video and the audio device but only
-     send the stream to the video device) &#x22C6;/
- #define VIDEO_CAP_SYS     4
- #define VIDEO_CAP_PROG    8
- /&#x22C6; can the driver also handle SPU, NAVI and CSS encoded data?
-    (CSS API is not present yet) &#x22C6;/
- #define VIDEO_CAP_SPU    16
- #define VIDEO_CAP_NAVI   32
- #define VIDEO_CAP_CSS    64
-</programlisting>
-</section>
-
-<section id="video_system">
-<title>video system</title>
-<para>A call to VIDEO_SET_SYSTEM sets the desired video system for TV output. The
-following system types can be set:
-</para>
-<programlisting>
- typedef enum {
-         VIDEO_SYSTEM_PAL,
-         VIDEO_SYSTEM_NTSC,
-         VIDEO_SYSTEM_PALN,
-         VIDEO_SYSTEM_PALNc,
-         VIDEO_SYSTEM_PALM,
-         VIDEO_SYSTEM_NTSC60,
-         VIDEO_SYSTEM_PAL60,
-         VIDEO_SYSTEM_PALM60
- } video_system_t;
-</programlisting>
-</section>
-
-<section id="video_highlight">
-<title>struct video_highlight</title>
-<para>Calling the ioctl VIDEO_SET_HIGHLIGHTS posts the SPU highlight information. The
-call expects the following format for that information:
-</para>
-<programlisting>
- typedef
- struct video_highlight {
-        boolean active;      /&#x22C6;    1=show highlight, 0=hide highlight &#x22C6;/
-        uint8_t contrast1;   /&#x22C6;    7- 4  Pattern pixel contrast &#x22C6;/
-                             /&#x22C6;    3- 0  Background pixel contrast &#x22C6;/
-        uint8_t contrast2;   /&#x22C6;    7- 4  Emphasis pixel-2 contrast &#x22C6;/
-                             /&#x22C6;    3- 0  Emphasis pixel-1 contrast &#x22C6;/
-        uint8_t color1;      /&#x22C6;    7- 4  Pattern pixel color &#x22C6;/
-                             /&#x22C6;    3- 0  Background pixel color &#x22C6;/
-        uint8_t color2;      /&#x22C6;    7- 4  Emphasis pixel-2 color &#x22C6;/
-                             /&#x22C6;    3- 0  Emphasis pixel-1 color &#x22C6;/
-        uint32_t ypos;       /&#x22C6;   23-22  auto action mode &#x22C6;/
-                             /&#x22C6;   21-12  start y &#x22C6;/
-                             /&#x22C6;    9- 0  end y &#x22C6;/
-        uint32_t xpos;       /&#x22C6;   23-22  button color number &#x22C6;/
-                             /&#x22C6;   21-12  start x &#x22C6;/
-                             /&#x22C6;    9- 0  end x &#x22C6;/
- } video_highlight_t;
-</programlisting>
-
-</section>
-<section id="video_spu">
-<title>video SPU</title>
-<para>Calling VIDEO_SET_SPU deactivates or activates SPU decoding, according to the
-following format:
-</para>
-<programlisting>
- typedef
- struct video_spu {
-        boolean active;
-        int stream_id;
- } video_spu_t;
-</programlisting>
-
-</section>
-<section id="video_spu_palette">
-<title>video SPU palette</title>
-<para>The following structure is used to set the SPU palette by calling VIDEO_SPU_PALETTE:
-</para>
-<programlisting>
- typedef
- struct video_spu_palette{
-        int length;
-        uint8_t &#x22C6;palette;
- } video_spu_palette_t;
-</programlisting>
-
-</section>
-<section id="video_navi_pack">
-<title>video NAVI pack</title>
-<para>In order to get the navigational data the following structure has to be passed to the ioctl
-VIDEO_GET_NAVI:
-</para>
-<programlisting>
- typedef
- struct video_navi_pack{
-        int length;         /&#x22C6; 0 ... 1024 &#x22C6;/
-        uint8_t data[1024];
- } video_navi_pack_t;
-</programlisting>
-</section>
-
-
-<section id="video_attributes">
-<title>video attributes</title>
-<para>The following attributes can be set by a call to VIDEO_SET_ATTRIBUTES:
-</para>
-<programlisting>
- typedef uint16_t video_attributes_t;
- /&#x22C6;   bits: descr. &#x22C6;/
- /&#x22C6;   15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) &#x22C6;/
- /&#x22C6;   13-12 TV system (0=525/60, 1=625/50) &#x22C6;/
- /&#x22C6;   11-10 Aspect ratio (0=4:3, 3=16:9) &#x22C6;/
- /&#x22C6;    9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-sca &#x22C6;/
- /&#x22C6;    7    line 21-1 data present in GOP (1=yes, 0=no) &#x22C6;/
- /&#x22C6;    6    line 21-2 data present in GOP (1=yes, 0=no) &#x22C6;/
- /&#x22C6;    5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 &#x22C6;/
- /&#x22C6;    2    source letterboxed (1=yes, 0=no) &#x22C6;/
- /&#x22C6;    0    film/camera mode (0=camera, 1=film (625/50 only)) &#x22C6;/
-</programlisting>
-</section></section>
-
-
-<section id="video_function_calls">
-<title>Video Function Calls</title>
-
-
-<section id="video_fopen">
-<title>open()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call opens a named video device (e.g. /dev/dvb/adapter0/video0)
- for subsequent use.</para>
-<para>When an open() call has succeeded, the device will be ready for use.
- The significance of blocking or non-blocking mode is described in the
- documentation for functions where there is a difference. It does not affect the
- semantics of the open() call itself. A device opened in blocking mode can later
- be put into non-blocking mode (and vice versa) using the F_SETFL command
- of the fcntl system call. This is a standard system call, documented in the Linux
- manual page for fcntl. Only one user can open the Video Device in O_RDWR
- mode. All other attempts to open the device in this mode will fail, and an
- error-code will be returned. If the Video Device is opened in O_RDONLY
- mode, the only ioctl call that can be used is VIDEO_GET_STATUS. All other
- call will return an error code.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int open(const char &#x22C6;deviceName, int flags);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>const char
- *deviceName</para>
-</entry><entry
- align="char">
-<para>Name of specific video device.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int flags</para>
-</entry><entry
- align="char">
-<para>A bit-wise OR of the following flags:</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDONLY read-only access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_RDWR read/write access</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>O_NONBLOCK open in non-blocking mode</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>(blocking mode is the default)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>ENODEV</para>
-</entry><entry
- align="char">
-<para>Device driver not loaded/available.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBUSY</para>
-</entry><entry
- align="char">
-<para>Device or resource busy.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid argument.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="video_fclose">
-<title>close()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call closes a previously opened video device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int close(int fd);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section>
-<section id="video_fwrite">
-<title>write()</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This system call can only be used if VIDEO_SOURCE_MEMORY is selected
- in the ioctl call VIDEO_SELECT_SOURCE. The data provided shall be in
- PES format, unless the capability allows other formats. If O_NONBLOCK is
- not specified the function will block until buffer space is available. The amount
- of data to be transferred is implied by count.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>size_t write(int fd, const void &#x22C6;buf, size_t count);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>void *buf</para>
-</entry><entry
- align="char">
-<para>Pointer to the buffer containing the PES data.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>size_t count</para>
-</entry><entry
- align="char">
-<para>Size of buf.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>ENOMEM</para>
-</entry><entry
- align="char">
-<para>Attempted to write more data than the internal buffer can
- hold.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_STOP</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to stop playing the current stream.
- Depending on the input parameter, the screen can be blanked out or displaying
- the last decoded frame.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_STOP, boolean
- mode);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_STOP for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>Boolean mode</para>
-</entry><entry
- align="char">
-<para>Indicates how the screen shall be handled.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>TRUE: Blank screen when stop.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>FALSE: Show last decoded frame.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_PLAY</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to start playing a video stream from the
- selected source.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_PLAY);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_PLAY for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_FREEZE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call suspends the live video stream being played. Decoding
- and playing are frozen. It is then possible to restart the decoding
- and playing process of the video stream using the VIDEO_CONTINUE
- command. If VIDEO_SOURCE_MEMORY is selected in the ioctl call
- VIDEO_SELECT_SOURCE, the DVB subsystem will not decode any more
- data until the ioctl call VIDEO_CONTINUE or VIDEO_PLAY is performed.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_FREEZE);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_FREEZE for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_CONTINUE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call restarts decoding and playing processes of the video stream
- which was played before a call to VIDEO_FREEZE was made.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_CONTINUE);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_CONTINUE for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SELECT_SOURCE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call informs the video device which source shall be used for the input
- data. The possible sources are demux or memory. If memory is selected, the
- data is fed to the video device through the write command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_SELECT_SOURCE,
- video_stream_source_t source);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SELECT_SOURCE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_stream_source_t
- source</para>
-</entry><entry
- align="char">
-<para>Indicates which source shall be used for the Video stream.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SET_BLANK</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to blank out the picture.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_SET_BLANK, boolean
- mode);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_BLANK for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>boolean mode</para>
-</entry><entry
- align="char">
-<para>TRUE: Blank screen when stop.</para>
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>FALSE: Show last decoded frame.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal input parameter</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_GET_STATUS</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to return the current status of the device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_GET_STATUS, struct
- video_status &#x22C6;status);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_STATUS for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct video_status
- *status</para>
-</entry><entry
- align="char">
-<para>Returns the current status of the Video Device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error, possibly in the communication with the
- DVB subsystem.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>status points to invalid address</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_GET_EVENT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call returns an event of type video_event if available. If an event is
- not available, the behavior depends on whether the device is in blocking or
- non-blocking mode. In the latter case, the call fails immediately with errno
- set to EWOULDBLOCK. In the former case, the call blocks until an event
- becomes available. The standard Linux poll() and/or select() system calls can
- be used with the device file descriptor to watch for new events. For select(),
- the file descriptor should be included in the exceptfds argument, and for
- poll(), POLLPRI should be specified as the wake-up condition. Read-only
- permissions are sufficient for this ioctl call.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_GET_EVENT, struct
- video_event &#x22C6;ev);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_EVENT for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct video_event
- *ev</para>
-</entry><entry
- align="char">
-<para>Points to the location where the event, if any, is to be
- stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>ev points to invalid address</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EWOULDBLOCK</para>
-</entry><entry
- align="char">
-<para>There is no event pending, and the device is in
- non-blocking mode.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EOVERFLOW</para>
-</entry><entry
- align="char">
-</entry>
- </row><row><entry
- align="char">
-</entry><entry
- align="char">
-<para>Overflow in event queue - one or more events were lost.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SET_DISPLAY_FORMAT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to select the video format to be applied
- by the MPEG chip on the video.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request =
- VIDEO_SET_DISPLAY_FORMAT, video_display_format_t
- format);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_DISPLAY_FORMAT for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_display_format_t
- format</para>
-</entry><entry
- align="char">
-<para>Selects the video format to be used.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal parameter format.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_STILLPICTURE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to display a still picture (I-frame). The
- input data shall contain an I-frame. If the pointer is NULL, then the current
- displayed still picture is blanked.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_STILLPICTURE,
- struct video_still_picture &#x22C6;sp);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_STILLPICTURE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>struct
- video_still_picture
- *sp</para>
-</entry><entry
- align="char">
-<para>Pointer to a location where an I-frame and size is stored.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>sp points to an invalid iframe.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_FAST_FORWARD</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the Video Device to skip decoding of N number of I-frames.
- This call can only be used if VIDEO_SOURCE_MEMORY is selected.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_FAST_FORWARD, int
- nFrames);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_FAST_FORWARD for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int nFrames</para>
-</entry><entry
- align="char">
-<para>The number of frames to skip.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal parameter format.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SLOWMOTION</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the video device to repeat decoding frames N number of
- times. This call can only be used if VIDEO_SOURCE_MEMORY is selected.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_SLOWMOTION, int
- nFrames);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SLOWMOTION for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int nFrames</para>
-</entry><entry
- align="char">
-<para>The number of times to repeat each frame.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EPERM</para>
-</entry><entry
- align="char">
-<para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Illegal parameter format.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_GET_CAPABILITIES</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call asks the video device about its decoding capabilities. On success
- it returns and integer which has bits set according to the defines in section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_GET_CAPABILITIES,
- unsigned int &#x22C6;cap);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_CAPABILITIES for this
- command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>unsigned int *cap</para>
-</entry><entry
- align="char">
-<para>Pointer to a location where to store the capability
- information.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>cap points to an invalid iframe.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SET_ID</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl selects which sub-stream is to be decoded if a program or system
- stream is sent to the video device.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(int fd, int request = VIDEO_SET_ID, int
- id);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_ID for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int id</para>
-</entry><entry
- align="char">
-<para>video sub-stream id</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINTERNAL</para>
-</entry><entry
- align="char">
-<para>Internal error.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>Invalid sub-stream id.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_CLEAR_BUFFER</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl call clears all video buffers in the driver and in the decoder hardware.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_CLEAR_BUFFER);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_CLEAR_BUFFER for this command.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SET_STREAMTYPE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl tells the driver which kind of stream to expect being written to it. If
- this call is not used the default of video PES is used. Some drivers might not
- support this call and always expect PES.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>int ioctl(fd, int request = VIDEO_SET_STREAMTYPE,
- int type);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_STREAMTYPE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int type</para>
-</entry><entry
- align="char">
-<para>stream type</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>type is not a valid or supported stream type.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SET_FORMAT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl sets the screen format (aspect ratio) of the connected output device
- (TV) so that the output of the decoder can be adjusted accordingly.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_FORMAT,
- video_format_t format);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_FORMAT for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_format_t
- format</para>
-</entry><entry
- align="char">
-<para>video format of TV as defined in section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>format is not a valid video format.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SET_SYSTEM</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl sets the television output format. The format (see section ??) may
- vary from the color format of the displayed MPEG stream. If the hardware is
- not able to display the requested format the call will return an error.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_SYSTEM ,
- video_system_t system);</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_FORMAT for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_system_t
- system</para>
-</entry><entry
- align="char">
-<para>video system of TV output.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>system is not a valid or supported video system.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SET_HIGHLIGHT</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl sets the SPU highlight information for the menu access of a DVD.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_HIGHLIGHT
- ,video_highlight_t &#x22C6;vhilite)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_HIGHLIGHT for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_highlight_t
- *vhilite</para>
-</entry><entry
- align="char">
-<para>SPU Highlight information according to section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>input is not a valid highlight setting.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SET_SPU</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl activates or deactivates SPU decoding in a DVD input stream. It can
- only be used, if the driver is able to handle a DVD stream.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_SPU ,
- video_spu_t &#x22C6;spu)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_SPU for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_spu_t *spu</para>
-</entry><entry
- align="char">
-<para>SPU decoding (de)activation and subid setting according
- to section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>input is not a valid spu setting or driver cannot handle
- SPU.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SET_SPU_PALETTE</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl sets the SPU color palette.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_SPU_PALETTE
- ,video_spu_palette_t &#x22C6;palette )</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_SPU_PALETTE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_spu_palette_t
- *palette</para>
-</entry><entry
- align="char">
-<para>SPU palette according to section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>input is not a valid palette or driver doesn&#8217;t handle SPU.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_GET_NAVI</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl returns navigational information from the DVD stream. This is
- especially needed if an encoded stream has to be decoded by the hardware.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_GET_NAVI ,
- video_navi_pack_t &#x22C6;navipack)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_GET_NAVI for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_navi_pack_t
- *navipack</para>
-</entry><entry
- align="char">
-<para>PCI or DSI pack (private stream 2) according to section
- ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EFAULT</para>
-</entry><entry
- align="char">
-<para>driver is not able to return navigational information</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-
-</section><section
-role="subsection"><title>VIDEO_SET_ATTRIBUTES</title>
-<para>DESCRIPTION
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para>This ioctl is intended for DVD playback and allows you to set certain
- information about the stream. Some hardware may not need this information,
- but the call also tells the hardware to prepare for DVD playback.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>SYNOPSIS
-</para>
-<informaltable><tgroup cols="1"><tbody><row><entry
- align="char">
-<para> int ioctl(fd, int request = VIDEO_SET_ATTRIBUTE
- ,video_attributes_t vattr)</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>PARAMETERS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>int fd</para>
-</entry><entry
- align="char">
-<para>File descriptor returned by a previous call to open().</para>
-</entry>
- </row><row><entry
- align="char">
-<para>int request</para>
-</entry><entry
- align="char">
-<para>Equals VIDEO_SET_ATTRIBUTE for this command.</para>
-</entry>
- </row><row><entry
- align="char">
-<para>video_attributes_t
- vattr</para>
-</entry><entry
- align="char">
-<para>video attributes according to section ??.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
-<para>ERRORS
-</para>
-<informaltable><tgroup cols="2"><tbody><row><entry
- align="char">
-<para>EBADF</para>
-</entry><entry
- align="char">
-<para>fd is not a valid open file descriptor</para>
-</entry>
- </row><row><entry
- align="char">
-<para>EINVAL</para>
-</entry><entry
- align="char">
-<para>input is not a valid attribute setting.</para>
-</entry>
- </row></tbody></tgroup></informaltable>
- </section></section>
diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
deleted file mode 100644 (file)
index e5fe094..0000000
+++ /dev/null
@@ -1,464 +0,0 @@
-<!-- Generated file! Do not edit. -->
-
-<!-- Functions -->
-<!ENTITY func-close "<link linkend='func-close'><function>close()</function></link>">
-<!ENTITY func-ioctl "<link linkend='func-ioctl'><function>ioctl()</function></link>">
-<!ENTITY func-mmap "<link linkend='func-mmap'><function>mmap()</function></link>">
-<!ENTITY func-munmap "<link linkend='func-munmap'><function>munmap()</function></link>">
-<!ENTITY func-open "<link linkend='func-open'><function>open()</function></link>">
-<!ENTITY func-poll "<link linkend='func-poll'><function>poll()</function></link>">
-<!ENTITY func-read "<link linkend='func-read'><function>read()</function></link>">
-<!ENTITY func-select "<link linkend='func-select'><function>select()</function></link>">
-<!ENTITY func-write "<link linkend='func-write'><function>write()</function></link>">
-
-<!ENTITY media-func-close "<link linkend='media-func-close'><function>close()</function></link>">
-<!ENTITY media-func-ioctl "<link linkend='media-func-ioctl'><function>ioctl()</function></link>">
-<!ENTITY media-func-open "<link linkend='media-func-open'><function>open()</function></link>">
-
-<!-- Ioctls -->
-<!ENTITY VIDIOC-CROPCAP "<link linkend='vidioc-cropcap'><constant>VIDIOC_CROPCAP</constant></link>">
-<!ENTITY VIDIOC-DBG-G-CHIP-IDENT "<link linkend='vidioc-dbg-g-chip-ident'><constant>VIDIOC_DBG_G_CHIP_IDENT</constant></link>">
-<!ENTITY VIDIOC-DBG-G-REGISTER "<link linkend='vidioc-dbg-g-register'><constant>VIDIOC_DBG_G_REGISTER</constant></link>">
-<!ENTITY VIDIOC-DBG-S-REGISTER "<link linkend='vidioc-dbg-g-register'><constant>VIDIOC_DBG_S_REGISTER</constant></link>">
-<!ENTITY VIDIOC-DQBUF "<link linkend='vidioc-qbuf'><constant>VIDIOC_DQBUF</constant></link>">
-<!ENTITY VIDIOC-DQEVENT "<link linkend='vidioc-dqevent'><constant>VIDIOC_DQEVENT</constant></link>">
-<!ENTITY VIDIOC-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_ENCODER_CMD</constant></link>">
-<!ENTITY VIDIOC-ENUMAUDIO "<link linkend='vidioc-enumaudio'><constant>VIDIOC_ENUMAUDIO</constant></link>">
-<!ENTITY VIDIOC-ENUMAUDOUT "<link linkend='vidioc-enumaudioout'><constant>VIDIOC_ENUMAUDOUT</constant></link>">
-<!ENTITY VIDIOC-ENUMINPUT "<link linkend='vidioc-enuminput'><constant>VIDIOC_ENUMINPUT</constant></link>">
-<!ENTITY VIDIOC-ENUMOUTPUT "<link linkend='vidioc-enumoutput'><constant>VIDIOC_ENUMOUTPUT</constant></link>">
-<!ENTITY VIDIOC-ENUMSTD "<link linkend='vidioc-enumstd'><constant>VIDIOC_ENUMSTD</constant></link>">
-<!ENTITY VIDIOC-ENUM-DV-PRESETS "<link linkend='vidioc-enum-dv-presets'><constant>VIDIOC_ENUM_DV_PRESETS</constant></link>">
-<!ENTITY VIDIOC-ENUM-FMT "<link linkend='vidioc-enum-fmt'><constant>VIDIOC_ENUM_FMT</constant></link>">
-<!ENTITY VIDIOC-ENUM-FRAMEINTERVALS "<link linkend='vidioc-enum-frameintervals'><constant>VIDIOC_ENUM_FRAMEINTERVALS</constant></link>">
-<!ENTITY VIDIOC-ENUM-FRAMESIZES "<link linkend='vidioc-enum-framesizes'><constant>VIDIOC_ENUM_FRAMESIZES</constant></link>">
-<!ENTITY VIDIOC-G-AUDIO "<link linkend='vidioc-g-audio'><constant>VIDIOC_G_AUDIO</constant></link>">
-<!ENTITY VIDIOC-G-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_G_AUDOUT</constant></link>">
-<!ENTITY VIDIOC-G-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_G_CROP</constant></link>">
-<!ENTITY VIDIOC-G-CTRL "<link linkend='vidioc-g-ctrl'><constant>VIDIOC_G_CTRL</constant></link>">
-<!ENTITY VIDIOC-G-DV-PRESET "<link linkend='vidioc-g-dv-preset'><constant>VIDIOC_G_DV_PRESET</constant></link>">
-<!ENTITY VIDIOC-G-DV-TIMINGS "<link linkend='vidioc-g-dv-timings'><constant>VIDIOC_G_DV_TIMINGS</constant></link>">
-<!ENTITY VIDIOC-G-ENC-INDEX "<link linkend='vidioc-g-enc-index'><constant>VIDIOC_G_ENC_INDEX</constant></link>">
-<!ENTITY VIDIOC-G-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_G_EXT_CTRLS</constant></link>">
-<!ENTITY VIDIOC-G-FBUF "<link linkend='vidioc-g-fbuf'><constant>VIDIOC_G_FBUF</constant></link>">
-<!ENTITY VIDIOC-G-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_G_FMT</constant></link>">
-<!ENTITY VIDIOC-G-FREQUENCY "<link linkend='vidioc-g-frequency'><constant>VIDIOC_G_FREQUENCY</constant></link>">
-<!ENTITY VIDIOC-G-INPUT "<link linkend='vidioc-g-input'><constant>VIDIOC_G_INPUT</constant></link>">
-<!ENTITY VIDIOC-G-JPEGCOMP "<link linkend='vidioc-g-jpegcomp'><constant>VIDIOC_G_JPEGCOMP</constant></link>">
-<!ENTITY VIDIOC-G-MPEGCOMP "<link linkend=''><constant>VIDIOC_G_MPEGCOMP</constant></link>">
-<!ENTITY VIDIOC-G-MODULATOR "<link linkend='vidioc-g-modulator'><constant>VIDIOC_G_MODULATOR</constant></link>">
-<!ENTITY VIDIOC-G-OUTPUT "<link linkend='vidioc-g-output'><constant>VIDIOC_G_OUTPUT</constant></link>">
-<!ENTITY VIDIOC-G-PARM "<link linkend='vidioc-g-parm'><constant>VIDIOC_G_PARM</constant></link>">
-<!ENTITY VIDIOC-G-PRIORITY "<link linkend='vidioc-g-priority'><constant>VIDIOC_G_PRIORITY</constant></link>">
-<!ENTITY VIDIOC-G-SLICED-VBI-CAP "<link linkend='vidioc-g-sliced-vbi-cap'><constant>VIDIOC_G_SLICED_VBI_CAP</constant></link>">
-<!ENTITY VIDIOC-G-STD "<link linkend='vidioc-g-std'><constant>VIDIOC_G_STD</constant></link>">
-<!ENTITY VIDIOC-G-TUNER "<link linkend='vidioc-g-tuner'><constant>VIDIOC_G_TUNER</constant></link>">
-<!ENTITY VIDIOC-LOG-STATUS "<link linkend='vidioc-log-status'><constant>VIDIOC_LOG_STATUS</constant></link>">
-<!ENTITY VIDIOC-OVERLAY "<link linkend='vidioc-overlay'><constant>VIDIOC_OVERLAY</constant></link>">
-<!ENTITY VIDIOC-QBUF "<link linkend='vidioc-qbuf'><constant>VIDIOC_QBUF</constant></link>">
-<!ENTITY VIDIOC-QUERYBUF "<link linkend='vidioc-querybuf'><constant>VIDIOC_QUERYBUF</constant></link>">
-<!ENTITY VIDIOC-QUERYCAP "<link linkend='vidioc-querycap'><constant>VIDIOC_QUERYCAP</constant></link>">
-<!ENTITY VIDIOC-QUERYCTRL "<link linkend='vidioc-queryctrl'><constant>VIDIOC_QUERYCTRL</constant></link>">
-<!ENTITY VIDIOC-QUERYMENU "<link linkend='vidioc-queryctrl'><constant>VIDIOC_QUERYMENU</constant></link>">
-<!ENTITY VIDIOC-QUERYSTD "<link linkend='vidioc-querystd'><constant>VIDIOC_QUERYSTD</constant></link>">
-<!ENTITY VIDIOC-QUERY-DV-PRESET "<link linkend='vidioc-query-dv-preset'><constant>VIDIOC_QUERY_DV_PRESET</constant></link>">
-<!ENTITY VIDIOC-REQBUFS "<link linkend='vidioc-reqbufs'><constant>VIDIOC_REQBUFS</constant></link>">
-<!ENTITY VIDIOC-STREAMOFF "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMOFF</constant></link>">
-<!ENTITY VIDIOC-STREAMON "<link linkend='vidioc-streamon'><constant>VIDIOC_STREAMON</constant></link>">
-<!ENTITY VIDIOC-SUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_SUBSCRIBE_EVENT</constant></link>">
-<!ENTITY VIDIOC-S-AUDIO "<link linkend='vidioc-g-audio'><constant>VIDIOC_S_AUDIO</constant></link>">
-<!ENTITY VIDIOC-S-AUDOUT "<link linkend='vidioc-g-audioout'><constant>VIDIOC_S_AUDOUT</constant></link>">
-<!ENTITY VIDIOC-S-CROP "<link linkend='vidioc-g-crop'><constant>VIDIOC_S_CROP</constant></link>">
-<!ENTITY VIDIOC-S-CTRL "<link linkend='vidioc-g-ctrl'><constant>VIDIOC_S_CTRL</constant></link>">
-<!ENTITY VIDIOC-S-DV-PRESET "<link linkend='vidioc-g-dv-preset'><constant>VIDIOC_S_DV_PRESET</constant></link>">
-<!ENTITY VIDIOC-S-DV-TIMINGS "<link linkend='vidioc-g-dv-timings'><constant>VIDIOC_S_DV_TIMINGS</constant></link>">
-<!ENTITY VIDIOC-S-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_S_EXT_CTRLS</constant></link>">
-<!ENTITY VIDIOC-S-FBUF "<link linkend='vidioc-g-fbuf'><constant>VIDIOC_S_FBUF</constant></link>">
-<!ENTITY VIDIOC-S-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_S_FMT</constant></link>">
-<!ENTITY VIDIOC-S-FREQUENCY "<link linkend='vidioc-g-frequency'><constant>VIDIOC_S_FREQUENCY</constant></link>">
-<!ENTITY VIDIOC-S-HW-FREQ-SEEK "<link linkend='vidioc-s-hw-freq-seek'><constant>VIDIOC_S_HW_FREQ_SEEK</constant></link>">
-<!ENTITY VIDIOC-S-INPUT "<link linkend='vidioc-g-input'><constant>VIDIOC_S_INPUT</constant></link>">
-<!ENTITY VIDIOC-S-JPEGCOMP "<link linkend='vidioc-g-jpegcomp'><constant>VIDIOC_S_JPEGCOMP</constant></link>">
-<!ENTITY VIDIOC-S-MPEGCOMP "<link linkend=''><constant>VIDIOC_S_MPEGCOMP</constant></link>">
-<!ENTITY VIDIOC-S-MODULATOR "<link linkend='vidioc-g-modulator'><constant>VIDIOC_S_MODULATOR</constant></link>">
-<!ENTITY VIDIOC-S-OUTPUT "<link linkend='vidioc-g-output'><constant>VIDIOC_S_OUTPUT</constant></link>">
-<!ENTITY VIDIOC-S-PARM "<link linkend='vidioc-g-parm'><constant>VIDIOC_S_PARM</constant></link>">
-<!ENTITY VIDIOC-S-PRIORITY "<link linkend='vidioc-g-priority'><constant>VIDIOC_S_PRIORITY</constant></link>">
-<!ENTITY VIDIOC-S-STD "<link linkend='vidioc-g-std'><constant>VIDIOC_S_STD</constant></link>">
-<!ENTITY VIDIOC-S-TUNER "<link linkend='vidioc-g-tuner'><constant>VIDIOC_S_TUNER</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-ENUM-FRAME-SIZE "<link linkend='vidioc-subdev-enum-frame-size'><constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-ENUM-MBUS-CODE "<link linkend='vidioc-subdev-enum-mbus-code'><constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-G-CROP "<link linkend='vidioc-subdev-g-crop'><constant>VIDIOC_SUBDEV_G_CROP</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-G-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_G_FMT</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-G-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-S-CROP "<link linkend='vidioc-subdev-g-crop'><constant>VIDIOC_SUBDEV_S_CROP</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-S-FMT "<link linkend='vidioc-subdev-g-fmt'><constant>VIDIOC_SUBDEV_S_FMT</constant></link>">
-<!ENTITY VIDIOC-SUBDEV-S-FRAME-INTERVAL "<link linkend='vidioc-subdev-g-frame-interval'><constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></link>">
-<!ENTITY VIDIOC-TRY-ENCODER-CMD "<link linkend='vidioc-encoder-cmd'><constant>VIDIOC_TRY_ENCODER_CMD</constant></link>">
-<!ENTITY VIDIOC-TRY-EXT-CTRLS "<link linkend='vidioc-g-ext-ctrls'><constant>VIDIOC_TRY_EXT_CTRLS</constant></link>">
-<!ENTITY VIDIOC-TRY-FMT "<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>">
-<!ENTITY VIDIOC-UNSUBSCRIBE-EVENT "<link linkend='vidioc-subscribe-event'><constant>VIDIOC_UNSUBSCRIBE_EVENT</constant></link>">
-
-<!ENTITY MEDIA-IOC-DEVICE-INFO "<link linkend='media-ioc-device-info'><constant>MEDIA_IOC_DEVICE_INFO</constant></link>">
-<!ENTITY MEDIA-IOC-ENUM-ENTITIES "<link linkend='media-ioc-enum-entities'><constant>MEDIA_IOC_ENUM_ENTITIES</constant></link>">
-<!ENTITY MEDIA-IOC-ENUM-LINKS "<link linkend='media-ioc-enum-links'><constant>MEDIA_IOC_ENUM_LINKS</constant></link>">
-<!ENTITY MEDIA-IOC-SETUP-LINK "<link linkend='media-ioc-setup-link'><constant>MEDIA_IOC_SETUP_LINK</constant></link>">
-
-<!-- Types -->
-<!ENTITY v4l2-std-id "<link linkend='v4l2-std-id'>v4l2_std_id</link>">
-
-<!-- Enums -->
-<!ENTITY v4l2-buf-type "enum&nbsp;<link linkend='v4l2-buf-type'>v4l2_buf_type</link>">
-<!ENTITY v4l2-colorspace "enum&nbsp;<link linkend='v4l2-colorspace'>v4l2_colorspace</link>">
-<!ENTITY v4l2-ctrl-type "enum&nbsp;<link linkend='v4l2-ctrl-type'>v4l2_ctrl_type</link>">
-<!ENTITY v4l2-exposure-auto-type "enum&nbsp;<link linkend='v4l2-exposure-auto-type'>v4l2_exposure_auto_type</link>">
-<!ENTITY v4l2-field "enum&nbsp;<link linkend='v4l2-field'>v4l2_field</link>">
-<!ENTITY v4l2-frmivaltypes "enum&nbsp;<link linkend='v4l2-frmivaltypes'>v4l2_frmivaltypes</link>">
-<!ENTITY v4l2-frmsizetypes "enum&nbsp;<link linkend='v4l2-frmsizetypes'>v4l2_frmsizetypes</link>">
-<!ENTITY v4l2-mbus-pixelcode "enum&nbsp;<link linkend='v4l2-mbus-pixelcode'>v4l2_mbus_pixelcode</link>">
-<!ENTITY v4l2-memory "enum&nbsp;<link linkend='v4l2-memory'>v4l2_memory</link>">
-<!ENTITY v4l2-mpeg-audio-ac3-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-ac3-bitrate'>v4l2_mpeg_audio_ac3_bitrate</link>">
-<!ENTITY v4l2-mpeg-audio-crc "enum&nbsp;<link linkend='v4l2-mpeg-audio-crc'>v4l2_mpeg_audio_crc</link>">
-<!ENTITY v4l2-mpeg-audio-emphasis "enum&nbsp;<link linkend='v4l2-mpeg-audio-emphasis'>v4l2_mpeg_audio_emphasis</link>">
-<!ENTITY v4l2-mpeg-audio-encoding "enum&nbsp;<link linkend='v4l2-mpeg-audio-encoding'>v4l2_mpeg_audio_encoding</link>">
-<!ENTITY v4l2-mpeg-audio-l1-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-l1-bitrate'>v4l2_mpeg_audio_l1_bitrate</link>">
-<!ENTITY v4l2-mpeg-audio-l2-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-l2-bitrate'>v4l2_mpeg_audio_l2_bitrate</link>">
-<!ENTITY v4l2-mpeg-audio-l3-bitrate "enum&nbsp;<link linkend='v4l2-mpeg-audio-l3-bitrate'>v4l2_mpeg_audio_l3_bitrate</link>">
-<!ENTITY v4l2-mpeg-audio-mode "enum&nbsp;<link linkend='v4l2-mpeg-audio-mode'>v4l2_mpeg_audio_mode</link>">
-<!ENTITY v4l2-mpeg-audio-mode-extension "enum&nbsp;<link linkend='v4l2-mpeg-audio-mode-extension'>v4l2_mpeg_audio_mode_extension</link>">
-<!ENTITY v4l2-mpeg-audio-sampling-freq "enum&nbsp;<link linkend='v4l2-mpeg-audio-sampling-freq'>v4l2_mpeg_audio_sampling_freq</link>">
-<!ENTITY chroma-spatial-filter-type "enum&nbsp;<link linkend='chroma-spatial-filter-type'>v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</link>">
-<!ENTITY luma-spatial-filter-type "enum&nbsp;<link linkend='luma-spatial-filter-type'>v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</link>">
-<!ENTITY v4l2-mpeg-cx2341x-video-median-filter-type "enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-median-filter-type'>v4l2_mpeg_cx2341x_video_median_filter_type</link>">
-<!ENTITY v4l2-mpeg-cx2341x-video-spatial-filter-mode "enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-spatial-filter-mode'>v4l2_mpeg_cx2341x_video_spatial_filter_mode</link>">
-<!ENTITY v4l2-mpeg-cx2341x-video-temporal-filter-mode "enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-temporal-filter-mode'>v4l2_mpeg_cx2341x_video_temporal_filter_mode</link>">
-<!ENTITY v4l2-mpeg-stream-type "enum&nbsp;<link linkend='v4l2-mpeg-stream-type'>v4l2_mpeg_stream_type</link>">
-<!ENTITY v4l2-mpeg-stream-vbi-fmt "enum&nbsp;<link linkend='v4l2-mpeg-stream-vbi-fmt'>v4l2_mpeg_stream_vbi_fmt</link>">
-<!ENTITY v4l2-mpeg-video-aspect "enum&nbsp;<link linkend='v4l2-mpeg-video-aspect'>v4l2_mpeg_video_aspect</link>">
-<!ENTITY v4l2-mpeg-video-bitrate-mode "enum&nbsp;<link linkend='v4l2-mpeg-video-bitrate-mode'>v4l2_mpeg_video_bitrate_mode</link>">
-<!ENTITY v4l2-mpeg-video-encoding "enum&nbsp;<link linkend='v4l2-mpeg-video-encoding'>v4l2_mpeg_video_encoding</link>">
-<!ENTITY v4l2-power-line-frequency "enum&nbsp;<link linkend='v4l2-power-line-frequency'>v4l2_power_line_frequency</link>">
-<!ENTITY v4l2-priority "enum&nbsp;<link linkend='v4l2-priority'>v4l2_priority</link>">
-<!ENTITY v4l2-subdev-format-whence "enum&nbsp;<link linkend='v4l2-subdev-format-whence'>v4l2_subdev_format_whence</link>">
-<!ENTITY v4l2-tuner-type "enum&nbsp;<link linkend='v4l2-tuner-type'>v4l2_tuner_type</link>">
-<!ENTITY v4l2-preemphasis "enum&nbsp;<link linkend='v4l2-preemphasis'>v4l2_preemphasis</link>">
-
-<!-- Structures -->
-<!ENTITY v4l2-audio "struct&nbsp;<link linkend='v4l2-audio'>v4l2_audio</link>">
-<!ENTITY v4l2-audioout "struct&nbsp;<link linkend='v4l2-audioout'>v4l2_audioout</link>">
-<!ENTITY v4l2-bt-timings "struct&nbsp;<link linkend='v4l2-bt-timings'>v4l2_bt_timings</link>">
-<!ENTITY v4l2-buffer "struct&nbsp;<link linkend='v4l2-buffer'>v4l2_buffer</link>">
-<!ENTITY v4l2-plane "struct&nbsp;<link linkend='v4l2-plane'>v4l2_plane</link>">
-<!ENTITY v4l2-capability "struct&nbsp;<link linkend='v4l2-capability'>v4l2_capability</link>">
-<!ENTITY v4l2-captureparm "struct&nbsp;<link linkend='v4l2-captureparm'>v4l2_captureparm</link>">
-<!ENTITY v4l2-clip "struct&nbsp;<link linkend='v4l2-clip'>v4l2_clip</link>">
-<!ENTITY v4l2-control "struct&nbsp;<link linkend='v4l2-control'>v4l2_control</link>">
-<!ENTITY v4l2-crop "struct&nbsp;<link linkend='v4l2-crop'>v4l2_crop</link>">
-<!ENTITY v4l2-cropcap "struct&nbsp;<link linkend='v4l2-cropcap'>v4l2_cropcap</link>">
-<!ENTITY v4l2-dbg-chip-ident "struct&nbsp;<link linkend='v4l2-dbg-chip-ident'>v4l2_dbg_chip_ident</link>">
-<!ENTITY v4l2-dbg-match "struct&nbsp;<link linkend='v4l2-dbg-match'>v4l2_dbg_match</link>">
-<!ENTITY v4l2-dbg-register "struct&nbsp;<link linkend='v4l2-dbg-register'>v4l2_dbg_register</link>">
-<!ENTITY v4l2-dv-enum-preset "struct&nbsp;<link linkend='v4l2-dv-enum-preset'>v4l2_dv_enum_preset</link>">
-<!ENTITY v4l2-dv-preset "struct&nbsp;<link linkend='v4l2-dv-preset'>v4l2_dv_preset</link>">
-<!ENTITY v4l2-dv-timings "struct&nbsp;<link linkend='v4l2-dv-timings'>v4l2_dv_timings</link>">
-<!ENTITY v4l2-enc-idx "struct&nbsp;<link linkend='v4l2-enc-idx'>v4l2_enc_idx</link>">
-<!ENTITY v4l2-enc-idx-entry "struct&nbsp;<link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link>">
-<!ENTITY v4l2-encoder-cmd "struct&nbsp;<link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link>">
-<!ENTITY v4l2-event "struct&nbsp;<link linkend='v4l2-event'>v4l2_event</link>">
-<!ENTITY v4l2-event-subscription "struct&nbsp;<link linkend='v4l2-event-subscription'>v4l2_event_subscription</link>">
-<!ENTITY v4l2-event-vsync "struct&nbsp;<link linkend='v4l2-event-vsync'>v4l2_event_vsync</link>">
-<!ENTITY v4l2-ext-control "struct&nbsp;<link linkend='v4l2-ext-control'>v4l2_ext_control</link>">
-<!ENTITY v4l2-ext-controls "struct&nbsp;<link linkend='v4l2-ext-controls'>v4l2_ext_controls</link>">
-<!ENTITY v4l2-fmtdesc "struct&nbsp;<link linkend='v4l2-fmtdesc'>v4l2_fmtdesc</link>">
-<!ENTITY v4l2-format "struct&nbsp;<link linkend='v4l2-format'>v4l2_format</link>">
-<!ENTITY v4l2-fract "struct&nbsp;<link linkend='v4l2-fract'>v4l2_fract</link>">
-<!ENTITY v4l2-framebuffer "struct&nbsp;<link linkend='v4l2-framebuffer'>v4l2_framebuffer</link>">
-<!ENTITY v4l2-frequency "struct&nbsp;<link linkend='v4l2-frequency'>v4l2_frequency</link>">
-<!ENTITY v4l2-frmival-stepwise "struct&nbsp;<link linkend='v4l2-frmival-stepwise'>v4l2_frmival_stepwise</link>">
-<!ENTITY v4l2-frmivalenum "struct&nbsp;<link linkend='v4l2-frmivalenum'>v4l2_frmivalenum</link>">
-<!ENTITY v4l2-frmsize-discrete "struct&nbsp;<link linkend='v4l2-frmsize-discrete'>v4l2_frmsize_discrete</link>">
-<!ENTITY v4l2-frmsize-stepwise "struct&nbsp;<link linkend='v4l2-frmsize-stepwise'>v4l2_frmsize_stepwise</link>">
-<!ENTITY v4l2-frmsizeenum "struct&nbsp;<link linkend='v4l2-frmsizeenum'>v4l2_frmsizeenum</link>">
-<!ENTITY v4l2-hw-freq-seek "struct&nbsp;<link linkend='v4l2-hw-freq-seek'>v4l2_hw_freq_seek</link>">
-<!ENTITY v4l2-input "struct&nbsp;<link linkend='v4l2-input'>v4l2_input</link>">
-<!ENTITY v4l2-jpegcompression "struct&nbsp;<link linkend='v4l2-jpegcompression'>v4l2_jpegcompression</link>">
-<!ENTITY v4l2-mbus-framefmt "struct&nbsp;<link linkend='v4l2-mbus-framefmt'>v4l2_mbus_framefmt</link>">
-<!ENTITY v4l2-modulator "struct&nbsp;<link linkend='v4l2-modulator'>v4l2_modulator</link>">
-<!ENTITY v4l2-mpeg-vbi-fmt-ivtv "struct&nbsp;<link linkend='v4l2-mpeg-vbi-fmt-ivtv'>v4l2_mpeg_vbi_fmt_ivtv</link>">
-<!ENTITY v4l2-output "struct&nbsp;<link linkend='v4l2-output'>v4l2_output</link>">
-<!ENTITY v4l2-outputparm "struct&nbsp;<link linkend='v4l2-outputparm'>v4l2_outputparm</link>">
-<!ENTITY v4l2-pix-format "struct&nbsp;<link linkend='v4l2-pix-format'>v4l2_pix_format</link>">
-<!ENTITY v4l2-pix-format-mplane "struct&nbsp;<link linkend='v4l2-pix-format-mplane'>v4l2_pix_format_mplane</link>">
-<!ENTITY v4l2-plane-pix-format "struct&nbsp;<link linkend='v4l2-plane-pix-format'>v4l2_plane_pix_format</link>">
-<!ENTITY v4l2-queryctrl "struct&nbsp;<link linkend='v4l2-queryctrl'>v4l2_queryctrl</link>">
-<!ENTITY v4l2-querymenu "struct&nbsp;<link linkend='v4l2-querymenu'>v4l2_querymenu</link>">
-<!ENTITY v4l2-rect "struct&nbsp;<link linkend='v4l2-rect'>v4l2_rect</link>">
-<!ENTITY v4l2-requestbuffers "struct&nbsp;<link linkend='v4l2-requestbuffers'>v4l2_requestbuffers</link>">
-<!ENTITY v4l2-sliced-vbi-cap "struct&nbsp;<link linkend='v4l2-sliced-vbi-cap'>v4l2_sliced_vbi_cap</link>">
-<!ENTITY v4l2-sliced-vbi-data "struct&nbsp;<link linkend='v4l2-sliced-vbi-data'>v4l2_sliced_vbi_data</link>">
-<!ENTITY v4l2-sliced-vbi-format "struct&nbsp;<link linkend='v4l2-sliced-vbi-format'>v4l2_sliced_vbi_format</link>">
-<!ENTITY v4l2-subdev-frame-interval "struct&nbsp;<link linkend='v4l2-subdev-frame-interval'>v4l2_subdev_frame_interval</link>">
-<!ENTITY v4l2-subdev-frame-interval-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-interval-enum'>v4l2_subdev_frame_interval_enum</link>">
-<!ENTITY v4l2-subdev-frame-size-enum "struct&nbsp;<link linkend='v4l2-subdev-frame-size-enum'>v4l2_subdev_frame_size_enum</link>">
-<!ENTITY v4l2-subdev-crop "struct&nbsp;<link linkend='v4l2-subdev-crop'>v4l2_subdev_crop</link>">
-<!ENTITY v4l2-subdev-format "struct&nbsp;<link linkend='v4l2-subdev-format'>v4l2_subdev_format</link>">
-<!ENTITY v4l2-subdev-mbus-code-enum "struct&nbsp;<link linkend='v4l2-subdev-mbus-code-enum'>v4l2_subdev_mbus_code_enum</link>">
-<!ENTITY v4l2-standard "struct&nbsp;<link linkend='v4l2-standard'>v4l2_standard</link>">
-<!ENTITY v4l2-streamparm "struct&nbsp;<link linkend='v4l2-streamparm'>v4l2_streamparm</link>">
-<!ENTITY v4l2-timecode "struct&nbsp;<link linkend='v4l2-timecode'>v4l2_timecode</link>">
-<!ENTITY v4l2-tuner "struct&nbsp;<link linkend='v4l2-tuner'>v4l2_tuner</link>">
-<!ENTITY v4l2-vbi-format "struct&nbsp;<link linkend='v4l2-vbi-format'>v4l2_vbi_format</link>">
-<!ENTITY v4l2-window "struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link>">
-
-<!ENTITY media-device-info "struct&nbsp;<link linkend='media-device-info'>media_device_info</link>">
-<!ENTITY media-entity-desc "struct&nbsp;<link linkend='media-entity-desc'>media_entity_desc</link>">
-<!ENTITY media-links-enum "struct&nbsp;<link linkend='media-links-enum'>media_links_enum</link>">
-<!ENTITY media-pad-desc "struct&nbsp;<link linkend='media-pad-desc'>media_pad_desc</link>">
-<!ENTITY media-link-desc "struct&nbsp;<link linkend='media-link-desc'>media_link_desc</link>">
-
-<!-- Error Codes -->
-<!ENTITY EACCES "<errorcode>EACCES</errorcode> error code">
-<!ENTITY EAGAIN "<errorcode>EAGAIN</errorcode> error code">
-<!ENTITY EBADF "<errorcode>EBADF</errorcode> error code">
-<!ENTITY EBUSY "<errorcode>EBUSY</errorcode> error code">
-<!ENTITY EFAULT "<errorcode>EFAULT</errorcode> error code">
-<!ENTITY EIO "<errorcode>EIO</errorcode> error code">
-<!ENTITY EINTR "<errorcode>EINTR</errorcode> error code">
-<!ENTITY EINVAL "<errorcode>EINVAL</errorcode> error code">
-<!ENTITY ENFILE "<errorcode>ENFILE</errorcode> error code">
-<!ENTITY ENOMEM "<errorcode>ENOMEM</errorcode> error code">
-<!ENTITY ENOSPC "<errorcode>ENOSPC</errorcode> error code">
-<!ENTITY ENOTTY "<errorcode>ENOTTY</errorcode> error code">
-<!ENTITY ENXIO "<errorcode>ENXIO</errorcode> error code">
-<!ENTITY EMFILE "<errorcode>EMFILE</errorcode> error code">
-<!ENTITY EPERM "<errorcode>EPERM</errorcode> error code">
-<!ENTITY EPIPE "<errorcode>EPIPE</errorcode> error code">
-<!ENTITY ERANGE "<errorcode>ERANGE</errorcode> error code">
-
-<!-- Subsections -->
-<!ENTITY sub-biblio SYSTEM "v4l/biblio.xml">
-<!ENTITY sub-common SYSTEM "v4l/common.xml">
-<!ENTITY sub-planar-apis SYSTEM "v4l/planar-apis.xml">
-<!ENTITY sub-compat SYSTEM "v4l/compat.xml">
-<!ENTITY sub-controls SYSTEM "v4l/controls.xml">
-<!ENTITY sub-dev-capture SYSTEM "v4l/dev-capture.xml">
-<!ENTITY sub-dev-codec SYSTEM "v4l/dev-codec.xml">
-<!ENTITY sub-dev-event SYSTEM "v4l/dev-event.xml">
-<!ENTITY sub-dev-effect SYSTEM "v4l/dev-effect.xml">
-<!ENTITY sub-dev-osd SYSTEM "v4l/dev-osd.xml">
-<!ENTITY sub-dev-output SYSTEM "v4l/dev-output.xml">
-<!ENTITY sub-dev-overlay SYSTEM "v4l/dev-overlay.xml">
-<!ENTITY sub-dev-radio SYSTEM "v4l/dev-radio.xml">
-<!ENTITY sub-dev-raw-vbi SYSTEM "v4l/dev-raw-vbi.xml">
-<!ENTITY sub-dev-rds SYSTEM "v4l/dev-rds.xml">
-<!ENTITY sub-dev-sliced-vbi SYSTEM "v4l/dev-sliced-vbi.xml">
-<!ENTITY sub-dev-subdev SYSTEM "v4l/dev-subdev.xml">
-<!ENTITY sub-dev-teletext SYSTEM "v4l/dev-teletext.xml">
-<!ENTITY sub-driver SYSTEM "v4l/driver.xml">
-<!ENTITY sub-libv4l SYSTEM "v4l/libv4l.xml">
-<!ENTITY sub-lirc_device_interface SYSTEM "v4l/lirc_device_interface.xml">
-<!ENTITY sub-remote_controllers SYSTEM "v4l/remote_controllers.xml">
-<!ENTITY sub-fdl-appendix SYSTEM "v4l/fdl-appendix.xml">
-<!ENTITY sub-close SYSTEM "v4l/func-close.xml">
-<!ENTITY sub-ioctl SYSTEM "v4l/func-ioctl.xml">
-<!ENTITY sub-mmap SYSTEM "v4l/func-mmap.xml">
-<!ENTITY sub-munmap SYSTEM "v4l/func-munmap.xml">
-<!ENTITY sub-open SYSTEM "v4l/func-open.xml">
-<!ENTITY sub-poll SYSTEM "v4l/func-poll.xml">
-<!ENTITY sub-read SYSTEM "v4l/func-read.xml">
-<!ENTITY sub-select SYSTEM "v4l/func-select.xml">
-<!ENTITY sub-write SYSTEM "v4l/func-write.xml">
-<!ENTITY sub-io SYSTEM "v4l/io.xml">
-<!ENTITY sub-grey SYSTEM "v4l/pixfmt-grey.xml">
-<!ENTITY sub-m420 SYSTEM "v4l/pixfmt-m420.xml">
-<!ENTITY sub-nv12 SYSTEM "v4l/pixfmt-nv12.xml">
-<!ENTITY sub-nv12m SYSTEM "v4l/pixfmt-nv12m.xml">
-<!ENTITY sub-nv12mt SYSTEM "v4l/pixfmt-nv12mt.xml">
-<!ENTITY sub-nv16 SYSTEM "v4l/pixfmt-nv16.xml">
-<!ENTITY sub-packed-rgb SYSTEM "v4l/pixfmt-packed-rgb.xml">
-<!ENTITY sub-packed-yuv SYSTEM "v4l/pixfmt-packed-yuv.xml">
-<!ENTITY sub-sbggr16 SYSTEM "v4l/pixfmt-sbggr16.xml">
-<!ENTITY sub-sbggr8 SYSTEM "v4l/pixfmt-sbggr8.xml">
-<!ENTITY sub-sgbrg8 SYSTEM "v4l/pixfmt-sgbrg8.xml">
-<!ENTITY sub-sgrbg8 SYSTEM "v4l/pixfmt-sgrbg8.xml">
-<!ENTITY sub-uyvy SYSTEM "v4l/pixfmt-uyvy.xml">
-<!ENTITY sub-vyuy SYSTEM "v4l/pixfmt-vyuy.xml">
-<!ENTITY sub-y16 SYSTEM "v4l/pixfmt-y16.xml">
-<!ENTITY sub-y41p SYSTEM "v4l/pixfmt-y41p.xml">
-<!ENTITY sub-yuv410 SYSTEM "v4l/pixfmt-yuv410.xml">
-<!ENTITY sub-yuv411p SYSTEM "v4l/pixfmt-yuv411p.xml">
-<!ENTITY sub-yuv420 SYSTEM "v4l/pixfmt-yuv420.xml">
-<!ENTITY sub-yuv420m SYSTEM "v4l/pixfmt-yuv420m.xml">
-<!ENTITY sub-yuv422p SYSTEM "v4l/pixfmt-yuv422p.xml">
-<!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
-<!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
-<!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
-<!ENTITY sub-srggb12 SYSTEM "v4l/pixfmt-srggb12.xml">
-<!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
-<!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
-<!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml">
-<!ENTITY sub-y10b SYSTEM "v4l/pixfmt-y10b.xml">
-<!ENTITY sub-pixfmt SYSTEM "v4l/pixfmt.xml">
-<!ENTITY sub-cropcap SYSTEM "v4l/vidioc-cropcap.xml">
-<!ENTITY sub-dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
-<!ENTITY sub-encoder-cmd SYSTEM "v4l/vidioc-encoder-cmd.xml">
-<!ENTITY sub-enum-fmt SYSTEM "v4l/vidioc-enum-fmt.xml">
-<!ENTITY sub-enum-frameintervals SYSTEM "v4l/vidioc-enum-frameintervals.xml">
-<!ENTITY sub-enum-framesizes SYSTEM "v4l/vidioc-enum-framesizes.xml">
-<!ENTITY sub-enumaudio SYSTEM "v4l/vidioc-enumaudio.xml">
-<!ENTITY sub-enumaudioout SYSTEM "v4l/vidioc-enumaudioout.xml">
-<!ENTITY sub-enuminput SYSTEM "v4l/vidioc-enuminput.xml">
-<!ENTITY sub-enumoutput SYSTEM "v4l/vidioc-enumoutput.xml">
-<!ENTITY sub-enum-dv-presets SYSTEM "v4l/vidioc-enum-dv-presets.xml">
-<!ENTITY sub-g-dv-preset SYSTEM "v4l/vidioc-g-dv-preset.xml">
-<!ENTITY sub-query-dv-preset SYSTEM "v4l/vidioc-query-dv-preset.xml">
-<!ENTITY sub-g-dv-timings SYSTEM "v4l/vidioc-g-dv-timings.xml">
-<!ENTITY sub-enumstd SYSTEM "v4l/vidioc-enumstd.xml">
-<!ENTITY sub-g-audio SYSTEM "v4l/vidioc-g-audio.xml">
-<!ENTITY sub-g-audioout SYSTEM "v4l/vidioc-g-audioout.xml">
-<!ENTITY sub-dbg-g-chip-ident SYSTEM "v4l/vidioc-dbg-g-chip-ident.xml">
-<!ENTITY sub-g-crop SYSTEM "v4l/vidioc-g-crop.xml">
-<!ENTITY sub-g-ctrl SYSTEM "v4l/vidioc-g-ctrl.xml">
-<!ENTITY sub-g-enc-index SYSTEM "v4l/vidioc-g-enc-index.xml">
-<!ENTITY sub-g-ext-ctrls SYSTEM "v4l/vidioc-g-ext-ctrls.xml">
-<!ENTITY sub-g-fbuf SYSTEM "v4l/vidioc-g-fbuf.xml">
-<!ENTITY sub-g-fmt SYSTEM "v4l/vidioc-g-fmt.xml">
-<!ENTITY sub-g-frequency SYSTEM "v4l/vidioc-g-frequency.xml">
-<!ENTITY sub-g-input SYSTEM "v4l/vidioc-g-input.xml">
-<!ENTITY sub-g-jpegcomp SYSTEM "v4l/vidioc-g-jpegcomp.xml">
-<!ENTITY sub-g-modulator SYSTEM "v4l/vidioc-g-modulator.xml">
-<!ENTITY sub-g-output SYSTEM "v4l/vidioc-g-output.xml">
-<!ENTITY sub-g-parm SYSTEM "v4l/vidioc-g-parm.xml">
-<!ENTITY sub-g-priority SYSTEM "v4l/vidioc-g-priority.xml">
-<!ENTITY sub-g-sliced-vbi-cap SYSTEM "v4l/vidioc-g-sliced-vbi-cap.xml">
-<!ENTITY sub-g-std SYSTEM "v4l/vidioc-g-std.xml">
-<!ENTITY sub-g-tuner SYSTEM "v4l/vidioc-g-tuner.xml">
-<!ENTITY sub-log-status SYSTEM "v4l/vidioc-log-status.xml">
-<!ENTITY sub-overlay SYSTEM "v4l/vidioc-overlay.xml">
-<!ENTITY sub-qbuf SYSTEM "v4l/vidioc-qbuf.xml">
-<!ENTITY sub-querybuf SYSTEM "v4l/vidioc-querybuf.xml">
-<!ENTITY sub-querycap SYSTEM "v4l/vidioc-querycap.xml">
-<!ENTITY sub-queryctrl SYSTEM "v4l/vidioc-queryctrl.xml">
-<!ENTITY sub-querystd SYSTEM "v4l/vidioc-querystd.xml">
-<!ENTITY sub-reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
-<!ENTITY sub-s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
-<!ENTITY sub-streamon SYSTEM "v4l/vidioc-streamon.xml">
-<!ENTITY sub-subdev-enum-frame-interval SYSTEM "v4l/vidioc-subdev-enum-frame-interval.xml">
-<!ENTITY sub-subdev-enum-frame-size SYSTEM "v4l/vidioc-subdev-enum-frame-size.xml">
-<!ENTITY sub-subdev-enum-mbus-code SYSTEM "v4l/vidioc-subdev-enum-mbus-code.xml">
-<!ENTITY sub-subdev-formats SYSTEM "v4l/subdev-formats.xml">
-<!ENTITY sub-subdev-g-crop SYSTEM "v4l/vidioc-subdev-g-crop.xml">
-<!ENTITY sub-subdev-g-fmt SYSTEM "v4l/vidioc-subdev-g-fmt.xml">
-<!ENTITY sub-subdev-g-frame-interval SYSTEM "v4l/vidioc-subdev-g-frame-interval.xml">
-<!ENTITY sub-capture-c SYSTEM "v4l/capture.c.xml">
-<!ENTITY sub-keytable-c SYSTEM "v4l/keytable.c.xml">
-<!ENTITY sub-v4l2grab-c SYSTEM "v4l/v4l2grab.c.xml">
-<!ENTITY sub-videodev2-h SYSTEM "v4l/videodev2.h.xml">
-<!ENTITY sub-v4l2 SYSTEM "v4l/v4l2.xml">
-<!ENTITY sub-dqevent SYSTEM "v4l/vidioc-dqevent.xml">
-<!ENTITY sub-subscribe-event SYSTEM "v4l/vidioc-subscribe-event.xml">
-<!ENTITY sub-intro SYSTEM "dvb/intro.xml">
-<!ENTITY sub-frontend SYSTEM "dvb/frontend.xml">
-<!ENTITY sub-dvbproperty SYSTEM "dvb/dvbproperty.xml">
-<!ENTITY sub-demux SYSTEM "dvb/demux.xml">
-<!ENTITY sub-video SYSTEM "dvb/video.xml">
-<!ENTITY sub-audio SYSTEM "dvb/audio.xml">
-<!ENTITY sub-ca SYSTEM "dvb/ca.xml">
-<!ENTITY sub-net SYSTEM "dvb/net.xml">
-<!ENTITY sub-kdapi SYSTEM "dvb/kdapi.xml">
-<!ENTITY sub-examples SYSTEM "dvb/examples.xml">
-<!ENTITY sub-frontend-h SYSTEM "dvb/frontend.h.xml">
-<!ENTITY sub-dvbapi SYSTEM "dvb/dvbapi.xml">
-<!ENTITY sub-media SYSTEM "media.xml">
-<!ENTITY sub-media-entities SYSTEM "media-entities.tmpl">
-<!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
-
-<!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
-<!ENTITY sub-media-func-open SYSTEM "v4l/media-func-open.xml">
-<!ENTITY sub-media-func-close SYSTEM "v4l/media-func-close.xml">
-<!ENTITY sub-media-func-ioctl SYSTEM "v4l/media-func-ioctl.xml">
-<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
-<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
-<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
-<!ENTITY sub-media-ioc-setup-link SYSTEM "v4l/media-ioc-setup-link.xml">
-
-<!-- Function Reference -->
-<!ENTITY close SYSTEM "v4l/func-close.xml">
-<!ENTITY ioctl SYSTEM "v4l/func-ioctl.xml">
-<!ENTITY mmap SYSTEM "v4l/func-mmap.xml">
-<!ENTITY munmap SYSTEM "v4l/func-munmap.xml">
-<!ENTITY open SYSTEM "v4l/func-open.xml">
-<!ENTITY poll SYSTEM "v4l/func-poll.xml">
-<!ENTITY read SYSTEM "v4l/func-read.xml">
-<!ENTITY select SYSTEM "v4l/func-select.xml">
-<!ENTITY write SYSTEM "v4l/func-write.xml">
-<!ENTITY grey SYSTEM "v4l/pixfmt-grey.xml">
-<!ENTITY nv12 SYSTEM "v4l/pixfmt-nv12.xml">
-<!ENTITY nv12m SYSTEM "v4l/pixfmt-nv12m.xml">
-<!ENTITY nv16 SYSTEM "v4l/pixfmt-nv16.xml">
-<!ENTITY packed-rgb SYSTEM "v4l/pixfmt-packed-rgb.xml">
-<!ENTITY packed-yuv SYSTEM "v4l/pixfmt-packed-yuv.xml">
-<!ENTITY sbggr16 SYSTEM "v4l/pixfmt-sbggr16.xml">
-<!ENTITY sbggr8 SYSTEM "v4l/pixfmt-sbggr8.xml">
-<!ENTITY sgbrg8 SYSTEM "v4l/pixfmt-sgbrg8.xml">
-<!ENTITY sgrbg8 SYSTEM "v4l/pixfmt-sgrbg8.xml">
-<!ENTITY uyvy SYSTEM "v4l/pixfmt-uyvy.xml">
-<!ENTITY vyuy SYSTEM "v4l/pixfmt-vyuy.xml">
-<!ENTITY y16 SYSTEM "v4l/pixfmt-y16.xml">
-<!ENTITY y41p SYSTEM "v4l/pixfmt-y41p.xml">
-<!ENTITY yuv410 SYSTEM "v4l/pixfmt-yuv410.xml">
-<!ENTITY yuv411p SYSTEM "v4l/pixfmt-yuv411p.xml">
-<!ENTITY yuv420 SYSTEM "v4l/pixfmt-yuv420.xml">
-<!ENTITY yuv420m SYSTEM "v4l/pixfmt-yuv420m.xml">
-<!ENTITY yuv422p SYSTEM "v4l/pixfmt-yuv422p.xml">
-<!ENTITY yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
-<!ENTITY yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
-<!ENTITY srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
-<!ENTITY srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
-<!ENTITY y10 SYSTEM "v4l/pixfmt-y10.xml">
-<!ENTITY cropcap SYSTEM "v4l/vidioc-cropcap.xml">
-<!ENTITY dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
-<!ENTITY encoder-cmd SYSTEM "v4l/vidioc-encoder-cmd.xml">
-<!ENTITY enum-fmt SYSTEM "v4l/vidioc-enum-fmt.xml">
-<!ENTITY enum-frameintervals SYSTEM "v4l/vidioc-enum-frameintervals.xml">
-<!ENTITY enum-framesizes SYSTEM "v4l/vidioc-enum-framesizes.xml">
-<!ENTITY enumaudio SYSTEM "v4l/vidioc-enumaudio.xml">
-<!ENTITY enumaudioout SYSTEM "v4l/vidioc-enumaudioout.xml">
-<!ENTITY enuminput SYSTEM "v4l/vidioc-enuminput.xml">
-<!ENTITY enumoutput SYSTEM "v4l/vidioc-enumoutput.xml">
-<!ENTITY enum-dv-presets SYSTEM "v4l/vidioc-enum-dv-presets.xml">
-<!ENTITY g-dv-preset SYSTEM "v4l/vidioc-g-dv-preset.xml">
-<!ENTITY query-dv-preset SYSTEM "v4l/vidioc-query-dv-preset.xml">
-<!ENTITY g-dv-timings SYSTEM "v4l/vidioc-g-dv-timings.xml">
-<!ENTITY enumstd SYSTEM "v4l/vidioc-enumstd.xml">
-<!ENTITY g-audio SYSTEM "v4l/vidioc-g-audio.xml">
-<!ENTITY g-audioout SYSTEM "v4l/vidioc-g-audioout.xml">
-<!ENTITY dbg-g-chip-ident SYSTEM "v4l/vidioc-dbg-g-chip-ident.xml">
-<!ENTITY g-crop SYSTEM "v4l/vidioc-g-crop.xml">
-<!ENTITY g-ctrl SYSTEM "v4l/vidioc-g-ctrl.xml">
-<!ENTITY g-enc-index SYSTEM "v4l/vidioc-g-enc-index.xml">
-<!ENTITY g-ext-ctrls SYSTEM "v4l/vidioc-g-ext-ctrls.xml">
-<!ENTITY g-fbuf SYSTEM "v4l/vidioc-g-fbuf.xml">
-<!ENTITY g-fmt SYSTEM "v4l/vidioc-g-fmt.xml">
-<!ENTITY g-frequency SYSTEM "v4l/vidioc-g-frequency.xml">
-<!ENTITY g-input SYSTEM "v4l/vidioc-g-input.xml">
-<!ENTITY g-jpegcomp SYSTEM "v4l/vidioc-g-jpegcomp.xml">
-<!ENTITY g-modulator SYSTEM "v4l/vidioc-g-modulator.xml">
-<!ENTITY g-output SYSTEM "v4l/vidioc-g-output.xml">
-<!ENTITY g-parm SYSTEM "v4l/vidioc-g-parm.xml">
-<!ENTITY g-priority SYSTEM "v4l/vidioc-g-priority.xml">
-<!ENTITY g-sliced-vbi-cap SYSTEM "v4l/vidioc-g-sliced-vbi-cap.xml">
-<!ENTITY g-std SYSTEM "v4l/vidioc-g-std.xml">
-<!ENTITY g-tuner SYSTEM "v4l/vidioc-g-tuner.xml">
-<!ENTITY log-status SYSTEM "v4l/vidioc-log-status.xml">
-<!ENTITY overlay SYSTEM "v4l/vidioc-overlay.xml">
-<!ENTITY qbuf SYSTEM "v4l/vidioc-qbuf.xml">
-<!ENTITY querybuf SYSTEM "v4l/vidioc-querybuf.xml">
-<!ENTITY querycap SYSTEM "v4l/vidioc-querycap.xml">
-<!ENTITY queryctrl SYSTEM "v4l/vidioc-queryctrl.xml">
-<!ENTITY querystd SYSTEM "v4l/vidioc-querystd.xml">
-<!ENTITY reqbufs SYSTEM "v4l/vidioc-reqbufs.xml">
-<!ENTITY s-hw-freq-seek SYSTEM "v4l/vidioc-s-hw-freq-seek.xml">
-<!ENTITY streamon SYSTEM "v4l/vidioc-streamon.xml">
-<!ENTITY dqevent SYSTEM "v4l/vidioc-dqevent.xml">
-<!ENTITY subscribe_event SYSTEM "v4l/vidioc-subscribe-event.xml">
diff --git a/Documentation/DocBook/media-indices.tmpl b/Documentation/DocBook/media-indices.tmpl
deleted file mode 100644 (file)
index 78d6031..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<!-- Generated file! Do not edit. -->
-
-<index><title>List of Types</title>
-<indexentry><primaryie><link linkend='v4l2-std-id'>v4l2_std_id</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-buf-type'>v4l2_buf_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-colorspace'>v4l2_colorspace</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-ctrl-type'>v4l2_ctrl_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-exposure-auto-type'>v4l2_exposure_auto_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-field'>v4l2_field</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-frmivaltypes'>v4l2_frmivaltypes</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-frmsizetypes'>v4l2_frmsizetypes</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-memory'>v4l2_memory</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-ac3-bitrate'>v4l2_mpeg_audio_ac3_bitrate</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-crc'>v4l2_mpeg_audio_crc</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-emphasis'>v4l2_mpeg_audio_emphasis</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-encoding'>v4l2_mpeg_audio_encoding</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-l1-bitrate'>v4l2_mpeg_audio_l1_bitrate</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-l2-bitrate'>v4l2_mpeg_audio_l2_bitrate</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-l3-bitrate'>v4l2_mpeg_audio_l3_bitrate</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-mode'>v4l2_mpeg_audio_mode</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-mode-extension'>v4l2_mpeg_audio_mode_extension</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-audio-sampling-freq'>v4l2_mpeg_audio_sampling_freq</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='chroma-spatial-filter-type'>v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='luma-spatial-filter-type'>v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-median-filter-type'>v4l2_mpeg_cx2341x_video_median_filter_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-spatial-filter-mode'>v4l2_mpeg_cx2341x_video_spatial_filter_mode</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-cx2341x-video-temporal-filter-mode'>v4l2_mpeg_cx2341x_video_temporal_filter_mode</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-stream-type'>v4l2_mpeg_stream_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-stream-vbi-fmt'>v4l2_mpeg_stream_vbi_fmt</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-video-aspect'>v4l2_mpeg_video_aspect</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-video-bitrate-mode'>v4l2_mpeg_video_bitrate_mode</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-mpeg-video-encoding'>v4l2_mpeg_video_encoding</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-power-line-frequency'>v4l2_power_line_frequency</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-priority'>v4l2_priority</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-tuner-type'>v4l2_tuner_type</link></primaryie></indexentry>
-<indexentry><primaryie>enum&nbsp;<link linkend='v4l2-preemphasis'>v4l2_preemphasis</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-audio'>v4l2_audio</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-audioout'>v4l2_audioout</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-bt-timings'>v4l2_bt_timings</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-buffer'>v4l2_buffer</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-capability'>v4l2_capability</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-captureparm'>v4l2_captureparm</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-clip'>v4l2_clip</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-control'>v4l2_control</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-crop'>v4l2_crop</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-cropcap'>v4l2_cropcap</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dbg-chip-ident'>v4l2_dbg_chip_ident</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dbg-match'>v4l2_dbg_match</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dbg-register'>v4l2_dbg_register</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dv-enum-preset'>v4l2_dv_enum_preset</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dv-preset'>v4l2_dv_preset</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-dv-timings'>v4l2_dv_timings</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-enc-idx'>v4l2_enc_idx</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-enc-idx-entry'>v4l2_enc_idx_entry</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-encoder-cmd'>v4l2_encoder_cmd</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-ext-control'>v4l2_ext_control</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-ext-controls'>v4l2_ext_controls</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-fmtdesc'>v4l2_fmtdesc</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-format'>v4l2_format</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-fract'>v4l2_fract</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-framebuffer'>v4l2_framebuffer</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frequency'>v4l2_frequency</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frmival-stepwise'>v4l2_frmival_stepwise</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frmivalenum'>v4l2_frmivalenum</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frmsize-discrete'>v4l2_frmsize_discrete</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frmsize-stepwise'>v4l2_frmsize_stepwise</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-frmsizeenum'>v4l2_frmsizeenum</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-hw-freq-seek'>v4l2_hw_freq_seek</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-input'>v4l2_input</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-jpegcompression'>v4l2_jpegcompression</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-modulator'>v4l2_modulator</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-mpeg-vbi-fmt-ivtv'>v4l2_mpeg_vbi_fmt_ivtv</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-output'>v4l2_output</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-outputparm'>v4l2_outputparm</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-pix-format'>v4l2_pix_format</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-queryctrl'>v4l2_queryctrl</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-querymenu'>v4l2_querymenu</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-rect'>v4l2_rect</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-requestbuffers'>v4l2_requestbuffers</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-sliced-vbi-cap'>v4l2_sliced_vbi_cap</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-sliced-vbi-data'>v4l2_sliced_vbi_data</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-sliced-vbi-format'>v4l2_sliced_vbi_format</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-standard'>v4l2_standard</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-streamparm'>v4l2_streamparm</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-timecode'>v4l2_timecode</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-tuner'>v4l2_tuner</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-vbi-format'>v4l2_vbi_format</link></primaryie></indexentry>
-<indexentry><primaryie>struct&nbsp;<link linkend='v4l2-window'>v4l2_window</link></primaryie></indexentry>
-</index>
diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media.tmpl
deleted file mode 100644 (file)
index 88f2cc6..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
-<!ENTITY % media-entities SYSTEM "./media-entities.tmpl"> %media-entities;
-<!ENTITY media-indices SYSTEM "./media-indices.tmpl">
-
-<!ENTITY eg                     "e.&nbsp;g.">
-<!ENTITY ie                     "i.&nbsp;e.">
-<!ENTITY fd                     "File descriptor returned by <link linkend='func-open'><function>open()</function></link>.">
-<!ENTITY i2c                    "I<superscript>2</superscript>C">
-<!ENTITY return-value          "<title>Return Value</title><para>On success <returnvalue>0</returnvalue> is returned, on error <returnvalue>-1</returnvalue> and the <varname>errno</varname> variable is set appropriately:</para>">
-<!ENTITY manvol                 "<manvolnum>2</manvolnum>">
-
-<!-- Table templates: structs, structs w/union, defines. -->
-<!ENTITY cs-str                 "<colspec colname='c1' colwidth='1*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='2*' /><spanspec spanname='hspan' namest='c1' nameend='c3' />">
-<!ENTITY cs-ustr                "<colspec colname='c1' colwidth='1*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='1*' /><colspec colname='c4' colwidth='2*' /><spanspec spanname='hspan' namest='c1' nameend='c4' />">
-<!ENTITY cs-def                 "<colspec colname='c1' colwidth='3*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='4*' /><spanspec spanname='hspan' namest='c1' nameend='c3' />">
-
-<!-- Video for Linux mailing list address. -->
-<!ENTITY v4l-ml                 "<ulink url='http://www.linuxtv.org/lists.php'>http://www.linuxtv.org/lists.php</ulink>">
-
-<!-- LinuxTV v4l-dvb repository. -->
-<!ENTITY v4l-dvb               "<ulink url='http://linuxtv.org/repo/'>http://linuxtv.org/repo/</ulink>">
-]>
-
-<book id="media_api">
-<bookinfo>
-<title>LINUX MEDIA INFRASTRUCTURE API</title>
-
-<copyright>
-       <year>2009-2011</year>
-       <holder>LinuxTV Developers</holder>
-</copyright>
-
-<legalnotice>
-
-<para>Permission is granted to copy, distribute and/or modify
-this document under the terms of the GNU Free Documentation License,
-Version 1.1 or any later version published by the Free Software
-Foundation. A copy of the license is included in the chapter entitled
-"GNU Free Documentation License"</para>
-</legalnotice>
-
-</bookinfo>
-
-<toc></toc> <!-- autogenerated -->
-
-<preface>
-       <title>Introduction</title>
-
-       <para>This document covers the Linux Kernel to Userspace API's used by
-               video and radio straming devices, including video cameras,
-               analog and digital TV receiver cards, AM/FM receiver cards,
-               streaming capture devices.</para>
-       <para>It is divided into three parts.</para>
-       <para>The first part covers radio, capture,
-               cameras and analog TV devices.</para>
-       <para>The second part covers the
-               API used for digital TV and Internet reception via one of the
-               several digital tv standards. While it is called as DVB API,
-               in fact it covers several different video standards including
-               DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated
-               to documment support also for DVB-S2, ISDB-T and ISDB-S.</para>
-       <para>The third part covers Remote Controller API</para>
-       <para>For additional information and for the latest development code,
-               see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
-       <para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
-
-</preface>
-
-<part id="v4l2spec">
-&sub-v4l2;
-</part>
-<part id="dvbapi">
-&sub-dvbapi;
-</part>
-<part id="v4ldvb_common">
-<partinfo>
-<authorgroup>
-<author>
-<firstname>Mauro</firstname>
-<surname>Chehab</surname>
-<othername role="mi">Carvalho</othername>
-<affiliation><address><email>mchehab@redhat.com</email></address></affiliation>
-<contrib>Initial version.</contrib>
-</author>
-</authorgroup>
-<copyright>
-       <year>2009-2011</year>
-       <holder>Mauro Carvalho Chehab</holder>
-</copyright>
-
-<revhistory>
-<!-- Put document revisions here, newest first. -->
-<revision>
-<revnumber>1.0.0</revnumber>
-<date>2009-09-06</date>
-<authorinitials>mcc</authorinitials>
-<revremark>Initial revision</revremark>
-</revision>
-</revhistory>
-</partinfo>
-
-<title>Remote Controller API</title>
-<chapter id="remote_controllers">
-&sub-remote_controllers;
-</chapter>
-</part>
-<part id="media_common">
-&sub-media-controller;
-</part>
-
-&sub-fdl-appendix;
-
-</book>
diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
new file mode 100644 (file)
index 0000000..6628b4b
--- /dev/null
@@ -0,0 +1,386 @@
+###
+# Media build rules - Auto-generates media contents/indexes and *.h xml's
+#
+
+SHELL=/bin/bash
+
+MEDIA_OBJ_DIR=$(objtree)/Documentation/DocBook/
+MEDIA_SRC_DIR=$(srctree)/Documentation/DocBook/media
+
+MEDIA_TEMP =  media-entities.tmpl \
+             media-indices.tmpl \
+             videodev2.h.xml \
+             v4l2.xml \
+             audio.h.xml \
+             ca.h.xml \
+             dmx.h.xml \
+             frontend.h.xml \
+             net.h.xml \
+             video.h.xml \
+
+IMGFILES := $(patsubst %.b64,%, $(notdir $(shell ls $(MEDIA_SRC_DIR)/*.b64)))
+OBJIMGFILES := $(addprefix $(MEDIA_OBJ_DIR)/, $(IMGFILES))
+GENFILES := $(addprefix $(MEDIA_OBJ_DIR)/, $(MEDIA_TEMP))
+
+PHONY += cleanmediadocs
+
+cleanmediadocs:
+       -@rm `find $(MEDIA_OBJ_DIR) -type l` $(GENFILES) $(OBJIMGFILES) 2>/dev/null
+
+$(obj)/media_api.xml: $(GENFILES) FORCE
+
+#$(MEDIA_OBJ_DIR)/media_api.html: $(MEDIA_OBJ_DIR)/media_api.xml
+#$(MEDIA_OBJ_DIR)/media_api.pdf: $(MEDIA_OBJ_DIR)/media_api.xml
+#$(MEDIA_OBJ_DIR)/media_api.ps: $(MEDIA_OBJ_DIR)/media_api.xml
+
+V4L_SGMLS = \
+       $(shell ls $(MEDIA_SRC_DIR)/v4l/*.xml|perl -ne 'print "$$1 " if (m,.*/(.*)\n,)') \
+       capture.c.xml \
+       keytable.c.xml \
+       v4l2grab.c.xml
+
+DVB_SGMLS = \
+       $(shell ls $(MEDIA_SRC_DIR)/dvb/*.xml|perl -ne 'print "$$1 " if (m,.*/(.*)\n,)')
+
+MEDIA_SGMLS =  $(addprefix ./,$(V4L_SGMLS)) $(addprefix ./,$(DVB_SGMLS)) $(addprefix ./,$(MEDIA_TEMP))
+
+FUNCS = \
+       close \
+       ioctl \
+       mmap \
+       munmap \
+       open \
+       poll \
+       read \
+       select \
+       write \
+
+IOCTLS = \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/videodev2.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/audio.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/ca.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/dmx.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/frontend.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([A-Z][^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/net.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/dvb/video.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/media.h) \
+       $(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/v4l2-subdev.h) \
+       VIDIOC_SUBDEV_G_FRAME_INTERVAL \
+       VIDIOC_SUBDEV_S_FRAME_INTERVAL \
+       VIDIOC_SUBDEV_ENUM_MBUS_CODE \
+       VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
+       VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
+
+TYPES = \
+       $(shell perl -ne 'print "$$1 " if /^typedef\s+[^\s]+\s+([^\s]+)\;/' $(srctree)/include/linux/videodev2.h) \
+       $(shell perl -ne 'print "$$1 " if /^}\s+([a-z0-9_]+_t)/' $(srctree)/include/linux/dvb/frontend.h)
+
+ENUMS = \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/videodev2.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/audio.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/ca.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/dmx.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/frontend.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/net.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/dvb/video.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/media.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-mediabus.h) \
+       $(shell perl -ne 'print "$$1 " if /^enum\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-subdev.h)
+
+STRUCTS = \
+       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/videodev2.h) \
+       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s\{]+)\s*/)' $(srctree)/include/linux/dvb/audio.h) \
+       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/ca.h) \
+       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/dmx.h) \
+       $(shell perl -ne 'print "$$1 " if (!/dtv\_cmds\_h/ && /^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/frontend.h) \
+       $(shell perl -ne 'print "$$1 " if (/^struct\s+([A-Z][^\s]+)\s+/)' $(srctree)/include/linux/dvb/net.h) \
+       $(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/linux/dvb/video.h) \
+       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/media.h) \
+       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-subdev.h) \
+       $(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/v4l2-mediabus.h)
+
+ERRORS = \
+       E2BIG \
+       EACCES \
+       EAGAIN \
+       EBADF \
+       EBADFD \
+       EBADR \
+       EBADRQC \
+       EBUSY \
+       ECHILD \
+       ECONNRESET \
+       EDEADLK \
+       EDOM \
+       EEXIST \
+       EFAULT \
+       EFBIG \
+       EILSEQ \
+       EINIT \
+       EINPROGRESS \
+       EINTR \
+       EINVAL \
+       EIO \
+       EMFILE \
+       ENFILE \
+       ENOBUFS \
+       ENODATA \
+       ENODEV \
+       ENOENT \
+       ENOIOCTLCMD \
+       ENOMEM \
+       ENOSPC \
+       ENOSR \
+       ENOSYS \
+       ENOTSUP \
+       ENOTSUPP \
+       ENOTTY \
+       ENXIO \
+       EOPNOTSUPP \
+       EOVERFLOW \
+       EPERM \
+       EPIPE \
+       EPROTO \
+       ERANGE \
+       EREMOTE \
+       EREMOTEIO \
+       ERESTART \
+       ERESTARTSYS \
+       ESHUTDOWN \
+       ESPIPE \
+       ETIME \
+       ETIMEDOUT \
+       EUSERS \
+       EWOULDBLOCK \
+       EXDEV \
+
+ESCAPE = \
+       -e "s/&/\\&amp;/g" \
+       -e "s/</\\&lt;/g" \
+       -e "s/>/\\&gt;/g"
+
+FILENAME = \
+       -e s,"^[^\/]*/",, \
+       -e s/"\\.xml"// \
+       -e s/"\\.tmpl"// \
+       -e s/\\\./-/g \
+       -e s/"^func-"// \
+       -e s/"^pixfmt-"// \
+       -e s/"^vidioc-"//
+
+# Generate references to these structs in videodev2.h.xml.
+DOCUMENTED = \
+       -e "s/\(enum *\)v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1<link linkend=\"\2\">v4l2_mpeg_cx2341x_video_\2<\/link>/g" \
+       -e "s/\(\(enum\|struct\) *\)\(v4l2_[a-zA-Z0-9_]*\)/\1<link linkend=\"\3\">\3<\/link>/g" \
+       -e "s/\(V4L2_PIX_FMT_[A-Z0-9_]\+\) /<link linkend=\"\1\">\1<\/link> /g" \
+       -e ":a;s/\(linkend=\".*\)_\(.*\">\)/\1-\2/;ta" \
+       -e "s/v4l2\-mpeg\-vbi\-ITV0/v4l2-mpeg-vbi-itv0-1/g"
+
+DVB_DOCUMENTED = \
+       -e "s/\(linkend\=\"\)FE_SET_PROPERTY/\1FE_GET_PROPERTY/g" \
+       -e "s,\(struct\s\+\)\([a-z0-9_]\+\)\(\s\+{\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
+       -e "s,\(}\s\+\)\([a-z0-9_]\+_t\+\),\1\<link linkend=\"\2\">\2\<\/link\>,g" \
+       -e "s,\(define\s\+\)\(DTV_[A-Z0-9_]\+\)\(\s\+[0-9]\+\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
+       -e "s,<link\s\+linkend=\".*\">\(DTV_IOCTL_MAX_MSGS\|dtv_cmds_h\|__.*_old\)<\/link>,\1,g" \
+       -e ":a;s/\(linkend=\".*\)_\(.*\">\)/\1-\2/;ta" \
+       -e "s,\(audio-mixer\|audio-karaoke\|audio-status\|ca-slot-info\|ca-descr-info\|ca-caps\|ca-msg\|ca-descr\|ca-pid\|dmx-filter\|dmx-caps\|video-system\|video-highlight\|video-spu\|video-spu-palette\|video-navi-pack\)-t,\1,g" \
+       -e "s,DTV-ISDBT-LAYER[A-C],DTV-ISDBT-LAYER,g" \
+       -e "s,\(define\s\+\)\([A-Z0-9_]\+\)\(\s\+_IO\),\1\<link linkend=\"\2\">\2\<\/link\>\3,g" \
+       -e "s,<link\s\+linkend=\".*\">\(__.*_OLD\)<\/link>,\1,g" \
+
+#
+# Media targets and dependencies
+#
+
+install_media_images = \
+       $(Q)cp $(OBJIMGFILES) $(MEDIA_OBJ_DIR)/media_api
+
+$(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64
+       $(Q)base64 -d $< >$@
+
+$(MEDIA_OBJ_DIR)/v4l2.xml: $(OBJIMGFILES)
+       @$($(quiet)gen_xml)
+       @(ln -sf $(MEDIA_SRC_DIR)/v4l/*xml $(MEDIA_OBJ_DIR)/)
+       @(ln -sf $(MEDIA_SRC_DIR)/dvb/*xml $(MEDIA_OBJ_DIR)/)
+
+$(MEDIA_OBJ_DIR)/videodev2.h.xml: $(srctree)/include/linux/videodev2.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DOCUMENTED) |         \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/audio.h.xml: $(srctree)/include/linux/dvb/audio.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/ca.h.xml: $(srctree)/include/linux/dvb/ca.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/dmx.h.xml: $(srctree)/include/linux/dvb/dmx.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/frontend.h.xml: $(srctree)/include/linux/dvb/frontend.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/net.h.xml: $(srctree)/include/linux/dvb/net.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/video.h.xml: $(srctree)/include/linux/dvb/video.h $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                      \
+       echo "<programlisting>") > $@
+       @(                                      \
+       expand --tabs=8 < $< |                  \
+         sed $(ESCAPE) $(DVB_DOCUMENTED) |     \
+         sed 's/i\.e\./&ie;/') >> $@
+       @(                                      \
+       echo "</programlisting>") >> $@
+
+$(MEDIA_OBJ_DIR)/media-entities.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                                              \
+       echo "<!-- Generated file! Do not edit. -->") >$@
+       @(                                                              \
+       echo -e "\n<!-- Functions -->") >>$@
+       @(                                                              \
+       for ident in $(FUNCS) ; do                                      \
+         entity=`echo $$ident | tr _ -` ;                              \
+         echo "<!ENTITY func-$$entity \"<link"                         \
+           "linkend='func-$$entity'><function>$$ident()</function></link>\">" \
+         >>$@ ;                                                        \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Ioctls -->") >>$@
+       @(                                                              \
+       for ident in $(IOCTLS) ; do                                     \
+         entity=`echo $$ident | tr _ -` ;                              \
+         id=`grep "<refname>$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \
+         echo "<!ENTITY $$entity \"<link"                              \
+           "linkend='$$id'><constant>$$ident</constant></link>\">"     \
+         >>$@ ;                                                        \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Types -->") >>$@
+       @(                                                              \
+       for ident in $(TYPES) ; do                                      \
+         entity=`echo $$ident | tr _ -` ;                              \
+         echo "<!ENTITY $$entity \"<link"                              \
+           "linkend='$$entity'>$$ident</link>\">" >>$@ ;               \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Enums -->") >>$@
+       @(                                                              \
+       for ident in $(ENUMS) ; do                                      \
+         entity=`echo $$ident | sed -e "s/v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1/" | tr _ -` ; \
+         echo "<!ENTITY $$entity \"enum&nbsp;<link"                    \
+           "linkend='$$entity'>$$ident</link>\">" >>$@ ;               \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Structures -->") >>$@
+       @(                                                              \
+       for ident in $(STRUCTS) ; do                                    \
+         entity=`echo $$ident | tr _ - | sed s/v4l2-mpeg-vbi-ITV0/v4l2-mpeg-vbi-itv0-1/g` ; \
+         echo "<!ENTITY $$entity \"struct&nbsp;<link"                  \
+           "linkend='$$entity'>$$ident</link>\">" >>$@ ;               \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Error Codes -->") >>$@
+       @(                                                              \
+       for ident in $(ERRORS) ; do                                     \
+         echo "<!ENTITY $$ident \"<errorcode>$$ident</errorcode>"      \
+           "error code\">" >>$@ ;                                      \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Subsections -->") >>$@
+       @(                                                              \
+       for file in $(MEDIA_SGMLS) ; do                                 \
+         entity=`echo "$$file" | sed $(FILENAME) -e s/"^([^-]*)"/sub\1/` ; \
+         if ! echo "$$file" |                                          \
+           grep -q -E -e '^(func|vidioc|pixfmt)-' ; then               \
+           echo "<!ENTITY sub-$$entity SYSTEM \"$$file\">" >>$@ ;      \
+         fi ;                                                          \
+       done)
+       @(                                                              \
+       echo -e "\n<!-- Function Reference -->") >>$@
+       @(                                                              \
+       for file in $(MEDIA_SGMLS) ; do                                 \
+         if echo "$$file" |                                            \
+           grep -q -E -e '(func|vidioc|pixfmt)-' ; then                \
+           entity=`echo "$$file" |sed $(FILENAME)` ;                   \
+           echo "<!ENTITY $$entity SYSTEM \"$$file\">" >>$@ ;  \
+         fi ;                                                          \
+       done)
+
+# Jade can auto-generate a list-of-tables, which includes all structs,
+# but we only want data types, all types, and sorted please.
+$(MEDIA_OBJ_DIR)/media-indices.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
+       @$($(quiet)gen_xml)
+       @(                                                              \
+       echo "<!-- Generated file! Do not edit. -->") >$@
+       @(                                                              \
+       echo -e "\n<index><title>List of Types</title>") >>$@
+       @(                                                              \
+       for ident in $(TYPES) ; do                                      \
+         id=`echo $$ident | tr _ -` ;                                  \
+         echo "<indexentry><primaryie><link"                           \
+           "linkend='$$id'>$$ident</link></primaryie></indexentry>" >>$@ ; \
+       done)
+       @(                                                              \
+       for ident in $(ENUMS) ; do                                      \
+         id=`echo $$ident | sed -e "s/v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1/" | tr _ -`; \
+         echo "<indexentry><primaryie>enum&nbsp;<link"                 \
+           "linkend='$$id'>$$ident</link></primaryie></indexentry>" >>$@ ; \
+       done)
+       @(                                                              \
+       for ident in $(STRUCTS) ; do                                    \
+         id=`echo $$ident | tr _ - | sed s/v4l2-mpeg-vbi-ITV0/v4l2-mpeg-vbi-itv0-1/g` ; \
+         echo "<indexentry><primaryie>struct&nbsp;<link"               \
+           "linkend='$$id'>$$ident</link></primaryie></indexentry>" >>$@ ; \
+       done)
+       @(                                                              \
+       echo "</index>") >>$@
+
diff --git a/Documentation/DocBook/media/bayer.png.b64 b/Documentation/DocBook/media/bayer.png.b64
new file mode 100644 (file)
index 0000000..ccdf2bc
--- /dev/null
@@ -0,0 +1,171 @@
+iVBORw0KGgoAAAANSUhEUgAAAlgAAACqCAMAAABGfcHVAAAAAXNSR0IArs4c6QAAAwBQTFRFAAIA
+CAICAAQVEQEBAgsAJgECAAogAwsTAQopHQYBNAEAAAxNARQAERIQAhoDABwAABZEHRQKGRYKQw0F
+ACMBACUAERwpHR4cVRAFBR5rZhADACR2JiIhBDAGAiWGgQ4AcxQABDYACSeQMSYlJykmESxYlQ4A
+PSYZIS05OSsJHS5JOC8kAEMDUC8SADXLNDUzADbEAEsAADX/2RABCFIAAD/qxB0AAD//BFgAK0Vp
+WT4r3hwA3RsTRERAAEf/5CIA2iYCCUv+WUgz7iIAOk5g3CgVSU5SiD8uB2sABm8AE1X/U1RQOFyL
+4jkfIlz/RV98M1j+G2H/fVk23jtD4T0pXl9ieFtGcV894UIiYWJfAIwA50gOV2p+4kssO2j+dGZx
+bG1qVmj/OHH/aHJzfnBX5lQ7B50AZnahdXd0AKUG5V1ARnz/6mErCqgAAKsAent46GBIW4GhAK0A
+AK8B42FtALIOin9/ALUAiIOBALkAVIf/6WxWg4eBi4SKJrEAmoVtdY2geoP/rYVXhoyOqYVuJbUh
+IrgWX5D/jo6J7nszP7gAsI9S63xnN70zZqO/fZzCOb4+cZr+64dy8otYnJ6b7ImDRcM56IqcWMEo
+oJb/N8ZoTMRL7Y9/QchcsaOTo6eohaj/7ZqKXspXj6v9xal+oK+7d7vTUM+Afco5r7CumLTVStKV
+bs9ukbb/9qx/9q9l8queoLv/e9R66beG7rDImNRhi9aDwsPAs8bWzcK2cd67jtqP5MWUodyB8b+1
+tMr/z8L/j9+kbOXWnN2ZstD7yc7Rzs7Ly9xb183UwdD/+si/qeOmvuKIx9fj4tPCtuWiqOrL+tS2
+y9v++NPK2dvZt+m0ueq80+Wo3OeSwuy/yezG+d7f/eS/z/DS3uf/6Ono4PC71O39xPb02vPZ/+nR
++Ori6e399+vt+PGz+ur65fL55/Xb4vbh7ffX/PPY8vP9+vLy6Pf36fjr/PfM8vjr//f+/vn48P36
+9vv+/vzf+fv4/fvu//z7+v7//P/7/v/8//QpxAAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAFY8AABWW
+AQ2TT8cAAAAHdElNRQfaCRQXGSltwbPRAAAgAElEQVR42u2dDXwU1bXAZwEJtEaNH1nbh68fpoWK
+iE1ao2Bgo9RqIrEg+BIFmqLYLOlMcHHlU6DiQmrJM2jKo0QIBHgUjD5ETcQIlKq0gKDmA+UjiRAT
+BCOBkGzC5re/++6987Ezszszdzc7s9jfPa2wO+zMPefc/5575t67Z5hB/0Ek/W668xckcmVmQZ5S
+CvLmgshl4QCiZu+8ntCOgWlzVfrl5ZZFrl6T/VYSv9x5K3Pj9wnkh9fFFxQE6VcVqXY+8PjgH5K0
++/0bBxDaYcsN0i+vLlTbzH9kjEknkEF3zptjLPPmXL2VwGC/nxysm+YRyc+/S2bHNYUgmtJkf5RI
+vScH3HEvifz05mhqB8G68d6xJO3ecSWhHXYfYdvM99LHGEv6mEF3zmFJ5Gr49e9qVUh7O/wP/w/9
+gf4EXnKwbpjNGQs779bvktlxzULg7TCQzvDAItBvzqMD7hjrMJaxPx0Cv3OdBvqFBRZJs46xCCwi
+O+xNwNfSclom6F2L4j1A/UsG1hgI1jyWUzLEKf/gX0CwevIzsvSlJoyh8IY5LmPhEFhEhsCI9b7L
+oy/uI2GBRaDfPATWaGO596dDADhioJ+7PKyI5SBoF4NFZAcEa6ZjvL7MOg9MAWtPxv4aHdlfM315
+TMHy7Gg4pifN5cUxBMsPisub9dRrqHc1xBCsC7vHH6jVlQOO3eGBhccc9B+rGIWkP/ALBNYEA3uX
+xxasooMGbVaWxhSs0kr9Njs8zbEE60C2UbOTTAOrR6/ZHjB/ZWzBet+gzR0xBmuHfpttsQbLIEP2
+ZpsGVrsBWMspWBQsGrEoWFEAK1UUDbBkQEkJu+Ko+WDxDRmApWmH+WCF0u/bCFYIMyIHK30CL1kZ
+Y1J17wo51snhW1/4d9BdoZlgcZx7mcezzM1yemBp22E2WBzL66fsExVYjmxBxsNed1gHVra8XX2w
+WBc2A/4dDbCSp4v/2PrGb1L1hkKnZ8sRNFH39cel6K1lQyFbvLcZXf3YrmWsNlg6dpgMFltc3dAN
+j3+zazWrCVbKBun8ltcfS3FYBpb0D721L+uCxXoqxO5VfEMiBmsa6BL/+UxWqhZYMFytPSVd5yMU
+qKxJ3jlub7f4D5f+xmqDpW2HuWCxr0r69b7N6oAV6JsTj6VYBpaciP9L0QaLVXQv13ewUqeBdjyS
+ZM0/Cf6uBRbkak03uLSraBHnWfsJAJ/LEi2TIxZs7bPyZS6XZwu0XEaWCiwdO0wFi3sXgC/K4QDi
+qfhEoV8QWNtT8FLK+L90gddHWwjWjNGw1dG/mgW7/jFNsFjYvd/sKnK73Kh7P4oSWHw3JOcDkJGq
+BVbxBfD5IidKqpzOV/3gb05rwGJfRXEAfYM41nMKfMXpgaVhh5lgsVsAeJvj9YOMXVrE6YAlvHwa
+XJSFLJPBOg8m8W2lpLwFQ5YjNFgc6t45OFCx0OVgNRu1iIVEByznu+ArIUixnPMfKGRZARaCSRpf
+ENx/4wwiVgg7TASLc52CA4f4BiobCFmaYDlSusBUC8GaGgC6VgssFnavS3QtC7uXiyJYMP09o5m8
+O2GfOsW8il1TudoisF4FX8hGvy3lc1yGYAXZYSZYa+RBitvy9hyXIVij744RWP+jDRb8ygaCFLdm
+x7KoJO/tyWj2Jz3/JPhjssY8lnNL91cvsNL8KOtk1fNY5iTv3D/AP2UJMaubvGvZYSJY8Jv+T04+
+8eAyBCsFdvBXVg6F2UK7k85oDoUs7N5FsiwjSsk7v5cKkqHsD3nEcm4BnznxHINTENaaCVJpcBGn
+zXQilpYdZoL1iThSB+kXBNbu8VOhzFhwAICXrUzeF2RPnTpp6qy/nAG9YzWSd5gpfqZhRl/AkpjY
+P0HrrtBZDQ468ZuKHVgqXdYk793Ag4zkllXyDZfq5FhadpgJVjMoxZ3g3sHrV84ZzmMB8LpjdCym
+G3r/oDXdwFaD97EZHG9FxQ53VHKsadOh5K8/q51jYbDwC/FSiywFixX7/Sirk2Np2GEmWA2gHOvn
+Efe3aCfvXiTA27J9lpVLOl7cLvyH2g2PaU6QSmCx4mXcXDTASkaSmpxxEvw1VXsofBLPt79/9AgU
+2DJr5VDIFh2rh9IM6vXA0rDDgqGQW4b1awAN+neFvzoDvpTPjlqVvD8Nw+ToFG2wxKGQO3gUmnEk
+GmAlS/M/Y5KXg5pkLbD45F3IsdhgsExO3vHS5JMV2mDp2GFJ8o71KzYCK+VhSJYjxXKw4A0DeF0P
+LDF5xxOVXLQiltg384PAktaanxSmG+D9AkrtEFhWLEKzr4Jv+FsUNOizO/QjloYd5k439C6SVIID
+doPRPNbTXeA96yPW6JS3AFCkWMrpBg/qXmmYcEcbLO2IxTrfBRdfcAqYOZ1WDYVozvGf0s2vkxAs
+6yIWGqs/l9ZsnWtBsxFYKHa8bOEitDiPBQfhc49prhWyqHuliWhX1HIsvI1JL8eCMJ0CF1ezeBxk
+iz+xLMdCSyYfzRZugbd0gCO6OVZoO0xd0lnTDT57QdiktqYDtBnOvMPYcc7CRWhpghSmWW9qgoVW
+EC6u5uMGh7s3KmBNQzJ9+UnQpTnzzjmLTwHwRUVxcemWBnjnusuqRWi0ctX5cXlR8dq9HQB8s1pv
+SUfDDlMjFkxPQO/H5auKy/e2of0XhmuFKQ93gTctHwpHO1ColA+GqkVovntXFQndG5WZd0m6fqe9
+bYZzej6RPvjZ6qAJUtP2vLNrpP0c53bNYXVm3rXsMHnbzFrJL727XtCbIA0srYA/pVg33SAu6dx9
+BpyQ3Teot80oujc6E6TtWBpr1mfobPRDUrzlSEfH10d3FcEbBws3+rnX7m3o6Pjm43K9jX46dpi8
+0Y9zFe891tHZ/HHFMo5zEawV/uo4+HKsVWCdli1C+2F2p7nRj+OK+O7dUeRio7vnPdVoazIr3/Ru
+4dZkce2bI9vznmr51mRh2wd72e95T9HdmhzKDEt+paP4MQX9+Rf9lU60wKI//6JgUbAoWJczWMRF
+QehQSMEyJWJNM7B3eYwj1re8KEhnjMGaZNSsaUVB0tcrZaPqbVaMyxiVVlcqRP22KLZljEqLlApV
+q97uiG0ZowOOVzboyitmlTECK6fly2V6fr7qfXtMwTpaVKyUUtX74uYYggVAs1o9lX5F1SCGYDWB
+l2bMVMos5dsZL4HwwTIQFwYrmmICWNEUM8CKnpgDFpmEAVZQM263+shsl1ZxWz/6H/oD/ukPC6x5
+s42L6s4mrEFqClgkRX8hWPeONRYzwBpN0i4Ci8iOkGB5Q7xjbP2CZGDwoX62K29Qy/U33RB8bEDS
+SLUkpfUlYjE3EMmVIewIJTZ7sH4FfQHrqhuuV8tNQUduuJrpTyQ228hg/UoiByuXsN3+A64OtiPE
+kauYEP0bslw4c9MD9xPIA9d/5wc/JJH+uWUlaunL6Di3P1GzPxhMaMfV920N0q8qcvVO27/34/80
+lh9/b8D9D5DIz+3B7ivZFzlYv73+AaKG7x9AaEd8YbB+IUdH5hdkddR/9H2iOuX3XrE1ujnW3O+Q
+tXsdqR3PRnko/GUGQXX5jNsYjki9B5JIWvWSg3UrmVtY5jYSO9J/SV7n/efzOJKsDYI1mkSugOGp
+7ai+HAsLrLEE2afj3uvI7JhzEwTrgJGEA9ZtRPXlbx/wJMlNCA/WfgNpB/4wwCJyy5PM7UQ56u0w
+x2o7YtC/bSaB1eZx6xcqd9XHFKyXpLpnGuLYQBwTog+WF7wmlo3TkIzp7SB2YJ027F63p80csOoX
+dXR3aksHKC2PKVjZG8BpPQEvzYgpWPkrhd1koaWnJqMmhmCdqXd3dOpJd4e73hywjngM7C2viClY
+M7YbtPnKrFiDpSutWY0xBcuoe4HHNLC6KVgmgtUYa7AM8ncfBYuCRcGiYH3rwRJ+UKYLVookVoLl
+0Gw3FFgh7TAZrNRkQVKNwVKXCLIIrNBuUYKlZUZfwOJYd3FpeemqZawOWI4VCwSZ6bAyYk0V2501
+VVnzIBgsDTvMBSt1+vL5WPKVtZNCgMW6iqB6pcs41lKwtNyiACt1gmjGNHWZ/IjBYj17+T0jX+9a
+xGqCNT5wlZbXrQMrJUBEb+0f5D9NDwJLyw5zwUreLx4/80Z6qg5YrGvLMeykznplPXiTwZLc8o3K
+LQqwkqX9cl5VdbGIwWLXXIDGNjc0dwBwSfFLRWXEAoB/NN3xLgBetw6sDeC00C5UT/5LXjVYmnaY
+DNYe0IoeydgIe75GBywO/SC0t62hARXpV5S7NhcsdouWW9RgdfFm+EGXskx+hGCxW/yoTjnHch6o
+wsUXdMDi053Rk94CQFFewmSwtgsp1oIz4M2xmmBp22E6WCtxapK+shv8MVUTLM8p0LurCFVRXauq
+B28qWKj2hcwti3TAqklORRlWvrpMfoRgeU6Cz4VfvqLyDB+x2mA5UCV62OV3v6V8xoHpYOHC+6ic
+9CUZ0CqwtO0wHaz1yWPSUfb7GngjWQss9l0UL4QSVKgevEVgofrtvFtw9Y1drA5YqenIjuT5UqGx
+voCFCnzPFltzvgo+l1XADwZL6Oy/SHUIrAFLfH0azNACS8cOK8DCr1aCPVpgscXdgSjFek71yoqH
+mAkWrt+u4ZbgiKWuYNcXsIrlNe9dntJlLpcxWG8pC+JYBdbDivroSrB07LAALFw9acwH2kMh7ODP
+ZflN6arZ1kQsPbeEAAvbsTIaQyG79pQ8HXEpCnyHzrFSUHGJP8Ugx4Ij8InHNHIsPTtMB2vjmIyM
+jKzpe5QdohwK/6GsB29R8q7rliCwxmRBM6at7z7zm2iABb7RLPCtBmsFlld2A/CplXeFtQtwuxvO
+AHmxFDVY2naYDpbU+2O0wTolPPmBcwbVgzcVLB23aEw3gK7fJfd9uoEtB8f4Osw7ULnc+vpjHlYL
+rIDjP1UW/jUZrIC8PFoTLB07LAML7E/XBMsnlBUv4tU7uoO1BKwK0S2VQrsezhAs0Pi71KiB5XaK
+v6srZnXnsbygd/tMVWFnk8FqOYAnsb58KVt75l3PDvNzrFS0E3nCym7FWKgEqxsUadSrNxUsyS1t
+wW4JcVcIBT2VrysKEWut/yIfossr0SMJOsEqVjfHelo9O2pRjvUW+FJZ9Fc9FGrbYdFdYWry/G4g
+G0XUQyFOojkPUq/iiKxIr7lDodotRazBXWFqctZJ8NfkKCTvwnQsXw65Qw8sNI/FFwxPsRYs9BzH
+46D3MZ2IpWOHVdMNY1JrwHwNsHTq1ZsJFgfd8oLCLYZgwZfrFfNxkc5jfSKfS2QNwBIKhv/J4oiF
+XkxCFTS1F6F17LAMrGRtsFhUDz6g7A6LwFK5hbMQLG4NWl/gxJKMHXo5Ft+vdx9XFQy3BCx+ENZe
+hNaxwyqwUtNPakcszyk0A87x6jmrZWXFzQULAh1wC8z0VhmClZr6RjTAQlN34O1l+HET7jUNQIa0
+BlgpDwNFOWmrJkhhqOzVWYTWtsOatcLk5DGvgTOy/Q2qJZ21F8AXq92ouoq7aK8ffMxatFao7ZZg
+sPj9WMv9QHFbGCFYnAs23ftxZcWOgx3oOezGM+9BT8+waOYdDoafai9Ca9thOlh7lq+Esr4GKJJe
+1SI03nzxBVSvGpW9/uwFa5Z0VG659LbOPFYjNmPlHgD+nhyV/VicVEi996NlrM5+LLG3YQ9flG+6
+Mxms3YFnGsufIBm0H0vLDqv2YwGwUXc/VvFe8XNflLo4y/ZjabpFcx5rf3qUdpCyruLqg0cOVpe7
+We2Nfo7aA9Ja4YLa2plWgbXi+EvSIvT22t1jdXaQathhMljra/BPlfe8sVK5jSloBynLeir2HqlH
+5eBZ6/ZjSW6pVLtFCVa+YMaejdNTo73nnTXY8x76tfl73h2ybfcke97Z2Ox5Tybd887FZs87S7bn
+PWjTu9m/0nE4ZC8dlu15d2i1e9n8SkeonfFt/5VOuoYd9Odf9OdffQKL/q6QgkXBomBRsPoKlo+C
+9e8MllGzZoFV7+4EPm3pBqWxBSt7A/DqyWVQxqirpwv+H/6BRfybF9AY4zJGHt3u9YFOs8BqVlfi
+KlIXXjsYU7BWOCYpC61NUr6f5NhArJ4ZYK1Pn6astKZ6mzWtNYZgnf7aYyjNPFizSeowQ7DGkgiq
+QdpWf0QhR5Vv64+CcMAiaheBRWZHqFKRu1UCog7WbQOcROWucanID5RSs3+PUlrDKhVJ5BYnQ2iH
+vQl8repetdTj/ZXMreyTBML+6EbHHSRyRYmv6fQZlYDI5ZnvELU7+joyO5w3PXO+6YJKuiNXr8l+
++5hfGkv67cyjThI3329vamrqVYu61TCK2/6IzC2PwohFYAeMWB8Gd29IdZgBVwbJVVcFHxtgG0wk
+tiH2IBnZB7BKCNu9NpQdwYeuZOKD1IvP7QNYSf0GBsmg4EP9mBC6XB3iWLB69viIn3ngA8+GajeU
+MKR2BOtnD13nPbNuH4HUjcwl+ty+pMLgz9X1BayRZPpl9sGOPujXNKSs7kNjqSuzV5HoV1eYFOJo
+U+Rg5RK6pcreBztCTgIwhF/XtKVkn0siqfPeRe6bQsLHWuROJrRjIYimNNnJqKyznyf63NakaGrn
+Azk5ZJ/sIraDpM67VwCrcf1GXVnfDjtkLgANldX6gsAqA2C//vXWv0acJPBgvW/QbmUbADkQrI0b
+CewoAJ1GZlSHAxYcB+r1L1gJ7773oWfQbDd4HNsBASwD7SobwgLLf3yDgWzn7TDqXtGOAxsM7fBi
+sHqmTcifriP5WfkYrA6P+nlsKnFVYLBqMqZN15X0jWFFrGqXfrPFniIfAmtlhq4Zgh3PglJ3qbEd
+YYBVb6Sfqx53yAbHzBm64qiFYPlAhUtfvyJPWzhgeWdkz9JtdqZjA7TjX4bdy9txoXb8jBmGdmCw
+2rMMJtzemIDBanYbGFRZjMHak2VgbziP7oVgVRg98PSYuwOBZTRjzdvxLPAYPmG1OCywqosMPlRU
+jcFascDgc9m7MVhGj+7tcDeEA9bp8bUGH1uwAoH1tbuDxI4LB7KBsR08WBP2AP6Rb/5QAjtkGg+W
+0SNj0bOUk/hnQoe8EN9GTwRg6Q/sxzydAlh+YzuejfIzoavA+0ZgreLBemmBfgrgJQQrnGdCQ7DO
+Zx8wSIh4sNoMA+EqASyyZ0IjsPYbfNPDBSuKT7EnilgSWAR2ULAoWBQsChYFi4JFwaJgfVvBajcA
+azkFi4JFIxYFi4JFwaJgUbAoWBQsChZN3ilYNGJRsChYFCwKVphg5RCCVUAG1pCS6A6Fc0eSgNUB
+cu4jBKsgumDFE4IVTwZWmT3KYGWC00RgxROCFU8MViEZWLklZGDlVEU3YpXlkkWswgIysKAdUQUr
+s44IrLpMMrCqMkFUwVo4lzBiZf7raxKw6jK7ScECRGChaxGBBSWqYEEhAgsKCVjQDm80wUJCAhYS
+ErCQRA8sLERg4e5tI7Jjd1TBQjuiiMDygegOhfCCZGD1kEUsnzeqEQvZSwSWjxAsX5TB8hGC5SME
+yxdtsC77iOUnAwsKjViXU8QKC6xoRiwKFgWLRiwKFgWLgkXBomBRsChYFCwKFgWL3hVSsChYNGJR
+sChYFCwKFgWLgkXBomBhsGoIwTIoR1IpgmWg4PIwk/dygw80IMUgWOsJwTKsNhNlsIolsPRlkgBW
+pf7HOsIFy6jazIoVRN0r2LHbsNrMJBGsjNcaa3SkcT1fl6jBVd/coCNtFXz5nz0ZNcrrqa7emB8m
+WMVtDbrtHnR1oC9e/nxdMyQ7PJUG16soDku/ao+uWxqaPTwpK2Ycr9WV8TxYxeW6+jUfcTWEo97p
+8dv12z0+cwXfvUeI7Ng9vraWwA4IFliZkaWQaRMUbydk8KHAV+7WL+8t1G9vn66+nvJtFnEBfGGk
+W2RQVhwXSvNDoLN0RbSj0uUhsoNUDOvaCxGmdrxKpirfOma04M/VG+jnLveFpd8Kh7Kd7Gy1IgeI
+ulewo2WG6nrjs0PZwaCa4Y2tja2tjY3wL/g3fo3+j9/gF9LorpQO1Xt+jPaDdnxuo3AJ8bKyNkjr
+lIuxv81AhM81tirsaNWyo43wepHqp37fKeQyLcdb9OT4eSEHazO4XpjqAf1moVZ8uz4jt3TyZpw3
+uh62gyFSzQ8uf/H/m9jxbyIMdQEVChYVChYVChYVKhQsKhQsKhQsKlQoWFQoWFQoWCD0g0V8fvUL
+2SdDbKDwmqqu1xtQQd1SqCNBp/WYrKDkpR5/kEt9BKf5zFscUDTfE/zSq+llXwTdq4hYWwvmIlla
+8o786M6SwmeXbj6ruOjhrYVzl5YdEo41FSycK5z5odnfhJadJagZ6XG7hULLSBm0ZFNXoDgiSi86
+benmdtO/qYGGsGuqeJfOXbi0rJVfUtonOHnp5h6VlxeqvRxlrsokXTa3KjpzHWq6Sd408vKzopel
+M5eWHIpsKExjBIkfd1LEc93wBHxo2JRuiebD9wyxoWOJ4w7hz9QxktinmNp3LYtvxi3HD1si+EFs
+2JY4hf9yyHXhu9ILehcPF0/zmxey4IV7BXfFDVvSjRvKlanzIj5SKB0Y9g7Q8rIpYKUxoZremZYg
+eOuk6JqAlzerzhTACBesTGZkDpTJsKlbeANbHoH43Dc5J3M4w9wiXvP5BCYOHUuzMQO3ocel1jHx
+OVgyYf89ZOJ37vBQ6JP7YDsJjO0hXsN4JlNs+SkcIhi7qAsDj3Sh074cJZ3G3GVaz6H9C7Ahu+Cu
+u86iYwVMkqBOAtNvG3JNCX9kMjww6JD8tEzey2dN857QvTk5sH8HviN00xM2Ji5tMvZfIj7mlbyc
+hrzs589ME8Eg9Z8KrBL+xbqh/V7EcX0iE7fkEPrWt6yTrvmcjZnyYQ+Ol6OYQTU4YsVLEaV/3Aem
+9dyXI5jEzdjxdYttzO9xOLIzTfwQ9Hx/rEsVIz7bvOURW2KNeNqSJv60BHiaecPgKNjQId4PCcyD
+PFjis5EPj7Jh1kqYTOHACPgRv+RlIHj5Qb95YJWIugy1Pci/eo6JEzpz3XAhdEB3DdvcJHr5KcWZ
+6wbzYIQNlvjA9CeY3yKbN6GQJMh7gxkcGE8k2J4Sj50bxUzhwRLzu97/Mq/n4LWlqAnxjsOv7cw+
+4V+HM1sxWElisnnpZ7YXkRXPMbdIucEm4bToC24oUcpON/W3HVKABb66FkeoEiYNKojo2cQMA7yX
+A6dBL79jHliFUjPMNThlec8WJ4FyYiizJNjLiScVSCIwIgfLDxZiPHqHMjI+JyIdusAjzDi/6Enw
+pu2hs3Kw/HJPRrvjDg+OCzj93IjEDySwvH6o2HDbZgVYXYI9h69gtgXgHJG4zaxtWS3XMbJrTxy4
+TeUO/jvAg4XzdeYWrNJ1zIuB9GFi3IsWgNXL2M6jUW8UzFykf3+OeQpqj73slcYI6OUAWH6QRxo3
+QkescyP6ob54b8A1rYF/PXcIJiz+iz/jUwW+oUsfnvdaFrH+zPwk0AG9hw95gWwohN91/EWTR6x7
+bEuE0wLSiawwR95kftKtcpccrBPX9jskHwrBRD4rhNHjrPo08yPWoPNYpUEBiADsTOyuu4CkQm8n
+9LIsYn05ot8HEYGVu68KyrpRcLSDt3+/tj0l3HBCEW6Ot18x7JR0DM+6+GU5Vi/MsfaY1XG/Zv4X
+KNThc6wSrPPihMRtQJFj9T5iG/gBPu2/g08zI3VXNCT0TagcKw0rvPUe20N4UgJ62a/2sgU5Fmpz
+Q/9xFwKdqeVldGYeD8bQuCWE92YqsEQZ181rsjTohHXMfUGXhmAVYMk19a5wKBNiGiU+XtSZn26o
+YobMRark5eK7Qi867R1ggfjguLI56GgBM5JXJwfeSgt3haLGiYcwj6G8bBJYabwu8IZ0IJ4oeoZ5
+POj7EexlnwqMSMCyJyEZYkP5G5q+4BH3jeQlTYjkXlxCPAkfS6rDYEkTHQ+1muYaO1OHo03VEL7l
+PB6sJEFnfGsMwZJ0ieMjwRCmisdfUDgH+MzpuJH47gGAJqGhTHisIDB3lMinEBAsXuEEG8zZ/TIv
+JwW8bBJY4pyfeLeQJ8bTNEFlH/DFq7xcgM+UgxF5jtWybiiDponE75JPpAb75T4erCTh4D4MVi6U
+oTbhZtskuVn4LolzoJkibcJEBx6Jqhg7VCUnIT5xyVnxtHeEWMZLmllgpQkRS5wvTsJgjczLzc0c
+HD9MnPUXcyzv4XuYRMXXV+ZlsyIWdE1mf2bcZiHuSBFLRA7mqwlBXg4Moi3rbmYe8kcOFkzuEq75
+AA23S7AGvq1QqgqZIfD17sHj+ByrCh3cahfAQkc+HYxaNW+x60Zh9G/C6uSIYO0Tb/ZtP+mRcqxN
+trglqtSMPy3XLLACORbvLogUBiuXny5KFO9MA3eFJ0b0ezHotELIo6k5Vu9E5hYxY39ezLFwZ5bF
+I7DUXs5RpP0QjJo+gNUDhjNl6DZHfldYh8E68bNB2xTD077AXeGmBHT3ahpZf2YelC2eFirAQvdT
+TL/zgbvC51CGhXVR3hVuNQss3JDM9io5WLA3+21TgyVMCilvJveZCVYh8si5UWjePYBJICXGEes5
+6OUumZdz5Gm/X5gtjBSsLhif4fmXZPNYfvAhAgvNYz0kW65UgAWet9leNAsrPzjcP64m8G6pGqxe
+xtYjm26YaBO6Ep4mZu9ePygzD6xzV0jzWLChrXKwwLkRaNxTgCVOcp2TzbMhL5sLFpozGMrccoEP
+sqOYpwJN92CwdvZPVHhZAVaXlEhGOBQKcUk+lQzvB6/FlPfv91RgkeVaOVj+XvhlOGkWWTiIB67+
+hHoofNP23XYZWOew+/zq0xabB5Ziih+6Sw4WzhOE5F1U4NJE2+9BsJeHmD6Ptckm8iRfWgGH8awp
+dNddSi+LYHl5MPZHApYAZssjDB58YSOJwlrhzidsaAUCyNYKfXWLb7bZ6gJgecGJwba7zNs+EFjF
+atl5j42ZrJggPTwUeyswQWjMGXEAAAJqSURBVPpef366gV8rPCuddp9pYPGLkry7HrEx4+RgoTUo
+YbohU5zzs/FBLMjLfpPBgtFcXISeKK4Vnt+3OMEWh159qvTy44oJ0ntIJxxUYKUVoNu7nOEMjs5e
+YXcDOmJjmHHC1/F5G9rdkItWv6EKfsXM+3MMs80srsR1d3hnAxWMm9LKg5WTh3TOTGDUM++PMGgM
+9PrA4VH8adiKKa3m6Ye2UUjuwhMvAbBganNLK45YSdjJuXg/hh97+Z4QXjYTLDgY3iXQ/QQT6Mxx
+7wS8PFn08ln+fhI7OedmJo5wUjD0fixmmLRss244nhey2ccJW3jwfqwEfr/OyCU9wv21CNalEcwg
+8wZDaacQY59yiE/NmcBWITznt5Wxi2DBACJsQhH3Y/GnmSi968SGkLu8aD9WjrSM0h9veAjsx7Lz
+82z8Nq74wGlmgZXGzBW/AZsYKbkS92PF4xiBs4qWxUPkXvaFBCMcsEpy87Aod1ruLJlbwG/HlO0w
+hMcKln4oZDdNuXmBT+dONm8XKcqYdhbCljdLq2sFvMoFS/mOBHU5c6UAsi53ssiR+jTzBDaUt7Ss
+SbwJzSmTdH8+93GYX1TlCE4uUygDvZyn9nKUwSrJqZLePZO7tNsrtHUYdTDuTG9IL/tkYBAvORnu
+eff6Zb0qSo/OcADM3Pfu1VHWq3fAr2djlNlXudQXdCTYjV4L6uCodfEG97RwSL7nXa2zPwKwqFCJ
+mlCwqFCwqFCwqFCwqFChYFGhYFGhYFGhQsGiQsGiQsGiQoWCRYWCRYWCRYUKBYsKBYsKBYsKFQoW
+FQoWFQoWFSoULCqXq/w/gbudjI6bMwYAAAAASUVORK5CYII=
diff --git a/Documentation/DocBook/media/crop.gif.b64 b/Documentation/DocBook/media/crop.gif.b64
new file mode 100644 (file)
index 0000000..11d936a
--- /dev/null
@@ -0,0 +1,105 @@
+R0lGODlhuQJGAeMAAAAAAH9/fwCvAP8AANEA0dEAAK8Ar////wCOAAAA0QAA////////////////
+/////ywAAAAAuQJGAQAE/vDISau9OOvNu/9gKI5kaZ5oqq5s675wLM90bd94ru987//AoHBILBqP
+yKRyyWw6n9CodEqtWq/YrHbL7Xq/4LB4TC6bz+i0es1uu9/wuHxOr9vv+Lx+z+/7/4CBgoOEhYaH
+iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6gQC9vr/A
+wcLDxMXGx8jJysvMzc7P0NHS09TV1tfYxbth2d3e3+DRAePk5ebn6Onl4ezt7u3q8fLqANtg7/j5
++s/z/f4B+wIKHAjsn8F09ex5IciwobuDEM1Bi0ixosWLGDNqrJhQIZdk/htDihxJsiTJiSZTqlzJ
+MmNHj1q+tRznsKbNmzhzDoz3EiYWmTN7+vQJgOfQmN5mAjzKtCg9pj+TBoU61ClCqlaAthSKVZdV
+dFy7NtHKMqxYW1/PmT2bhOzKtWxlpZUYF4pblXDrvpq7Tq+Tu+UGCB5MuLDhw4gTK17MuLHjx5Aj
+S55MubLly5gza95MmVxev0EAkxsg8jNoVXNJ0zy9RPQ41RtNsz6V2vPstlLTwdYo+zap2qt9G3Ed
+YLdL4bGAL0VOhLhxjL2Zf1IeXboM56Wtt6KuPXRudM8vVu+eiTt5H9hDjj9vyfyIXrTW80gfO4OC
++/jz69/Pv7///wAG/ijggAQWaOCBCCao4IIMNujggRe4J4IwBxBg4YUYZqjhhhx26OGHIIYo4ogk
+loihMBbi1k084VlklgLsWQKjBRJqgIwEBJRyY4UqZsNidhjMGOMkQlLgnjERwkdBjuVpk2QFTB5B
+H2/2DUlJkRNYhWQKUTKyJQpdFjHlcUFaSaQxo9nGQph/fCkDm0OMCV2VZh7iZpbnwCYfBnDKcecO
+fXq3ojotckRnnXr8SQGWEtQIphuKEhEoEHKKdygHCUiQ6QEJdDrEphWA2oGo3UXaAaMHOHrCpFmY
+2gSr6H2XJ5AXoHqBp5xyuimpPfCa6we+6uWqCaiqagKsTAxrBbLz/slqTqEUvWgBqLviSqqvnXpq
+rbbZTpDtt9ziSsG3unKraabkltutWMq+UOyswa3A7A/tfjGvDpW6eKm3v+a667i38vvvuQLzW7Cm
+AJ878L/W9ouuR/Xi8O6zasorRMRo3JtDvoaWOe2v4IIc7LUIE4zwtd1Sm7C6KZ8MLsmzYBzExIFV
+rILGJsgcB843cBztvgqHWnKwup5s8rroVivwwEc3DHLR/jKcis5K0JxmvDezQLUePNvgc0TSBix0
+1OuG6nS56nob7ssqp132wuIi7cnWU1j9ms1chkD3IF3X8DVEYe9AtNi37M2F3cXh/WgFhjPSNw1/
+HxS4CS97MPjH/ts5uQfieqbQuCWPzxC5QZPncPnYoXz+BueKY+Bm6J3AHsPo/5TOmup5sB5vxLJv
+0vsLtPtjO1W4D0Kz6r9nknwLwfczvFeam6IAmndjnfcsy2vtbM3qAT2KkhkULwj4SRITIbzLWYx9
+j9j82L3HvyljivzeG1tC9qCzf4379cEPigACCAYAB0jAAhrwgAhMoAIXyMAGOvCBEIygAVMVDBLo
+Ln1ZWx8SmjeP521CAEYiXypAGML1XHBPF8BfJVToue1drX+1GgUJZTHDFJywBSycRA5PwEF5eFAT
+NYRFEE9wwzXRYoc5c2H1YGgBW32QFkMk1vkoZr3FyQKJJeih/lH894kotsKLFpwi9zB4vSvqzxr8
+oxIXPQHGVbRRBEVUnxk3qMTEvS+GonjjBBCwxwMg4I+d0CMI4pjBOUqpjtACm/c4IUhASuCPfPQj
+I1lAyDLGAosk0OJT1hhIC0RSkpDsoyg9GUpAhtKPp6QAJD9pB0F+oJJWvOQZq5FGMuExFFHkYyR1
+OUpWqrKPvHykJIXZyzy40gOwXNURZ0mNWs6Jk5P0JChXKUxHXsCXwQTlKIe5h2OeSowvRKEFMOkI
+ck4IkbRqogyvaU1uZpOd1URlNXepSnriwZscSOaxlknHQekmnRVwIhAxgM09rtKXBrXnKalJzFTe
+AZ8b0Of9/vh5SH+CB6CLWicPEAoIiGpAoiQwp+OYOQ1nWgqaT0TBQTl6TUN4tH7oEyeUKDocdN5R
+nXnsAUv98FJO2i+kNBWTTZkYUI3SkJLgXKJMlxTU5gxVjbf8HxSRSqOY4rCpcXqqLXGKy6muAKQj
+EOkixPoBTV4FpQOdRU+jiicqkjGWsCCrB8wKlkWm9KhfTaod36pMDVbUR4TC6AQEmom1spGqjLOq
+Ef1aU4uiD6pclapaEWskxcpRlv0E7D9vWtScTjavVXXrUicgV0SUlgN0VYtd04pXFYBVBKc1RGxt
+pNVnsvWwn3WtXju3WEM2VrMX5WxGPdtaG+62dftkrFAd/utWyHa2q7k1bmjHOFocYfVitT3pbTsZ
+XRS8NgSzJUR4XZddfaG1sF7V7XTDeVXlOpW5Y3TucKFbXO8et4p99e1ygfvYrT5XsvUl4n35mlz9
+vpe/zfXvfAEcC8P+t63Uba+BswrfF8p3sEZtMGUhzN7eYvav7QuscDFMXA2DNrGilfCHfxvizRJ1
+wV1Mr3RRHGEPx5Wk0jCpebcbzQBLcb1KVfGNM9vi4L6YxPQ1sXpp3OHLDhnE+xPxkSVAWEw4uMcz
+rmyKbfyK8ZYPwfFVMJIZLMQNN8qyhVzxfovcX9tGNsbdFTCQ91pdHrmXwmC2sJipnOEyn1jLNXZy
+l3Es/g4pX5jPJfbzkgHd5DQ/mcVRdvGhD1DlS1z5rlnmcJC57Aov06i8HeMxphWd6TNvWdCdJjRK
+JL1nSvf5FZdGNJM3jepWeJpxoP7Zea0sY/vOmbe1ZsWtS5jnJU660paINXr/rGk6C3nQRI60kY/9
+alco+7sgGLYftN2oXCty15butZxn7WxO21rV/DB0q5FdCWXzmtmmDrSjoQ1lNKrbzQ/GrY9LgO0P
+cJsP/04tXcCdbHH/mNzAnneqo21vVuMbxvpWcqlThWZLPnrN0m6zdt8ccVL7GuHIneidsVthY6+7
+2l80M8VPrfBzM5yW9954vrm77zD+OuRAHbmgir1X/monGtYq/2lYr7tzNif44WOGc81H0G8P/HsP
+Afc24Fa77KXDccB1fjrX0O0MHYea4zSX+McZTeuWC5vrzfC6rkXNWrGPm+zlDvYqol7ynp/859YO
+esXhSm9IN3zad0+yx9/e7IRbvO8Y/7vGdwx2LA/+4HA3PN8XXm+YO1zmEA/74/mN9WdT3u+WBzzS
+ZU1moMN75fI+/OcTH/rFf33mjjf9oguP86HrnFJSlxzV3231EDS9A1rPA915nsipE7zdBuf8zfFb
+YDUf2OhhHr2r8Z7y0wsdtkTHfd2Lr/vjU8Ld4bb+3vPrfDxDX8/SZ/f3k29zkDNf5BMmOfEFS3ql
+/rsd8rR/f87jX/SMHx3zSddxsjdx1wde2UcvuUc6uxd+vTdInWduZ/dyzRRzjAd7ozaAY5d/BAZ/
+5Sd/52dy6YdyrHBtDyh3qjB8H2h3IUh9I6h3LKd6Lld5E3h5FZh5sZd34veCkxeDoDeDogeA9SeA
+ODh78dZoMBiBMlhSFPh6NniBQ0iA49d8F/d8/hd9QDh9goeBhFeEZXeEc4d2zKB238Z2VXd/yud+
+G7h/Hdh/ivd/NRiAmqeF+MeFcWd2XyiBSkiDTAiHN1h9RIh6RriDSNiDefiDbxiEcfiEGUiHkkd+
+U2h+VYh+V6h+kyBBlniJmJiJmriJluiCqSeI/neYhDm2hGvXeJzgCzEjQkxXgnZ4gmC4DGJofGS4
+CcAAC7XYfpFXe9h3ewi4ffSHhfGjiqvwC2eYi/pne/ynffM3YoiYOqhoi894dcuXhsi4hsqYgtyn
+gN5XHt1mi93oe6zoha6Ih6Ooh6VogTpSZ+3RG7/HAcGHBygYiSA4idCYisgUjqA4jqJYaOY4hqY4
+NepYCcI4cwWYbQcYK77IjMBYj3KxFu24Ae94B/HYhlZ4iAuZHAFJCQP5kBoQkXYwka3nhnvYjAyJ
+kWBXkP52kD0gcH2xjQBpj3CIkk6nks2SkFN2kWiRkZOgJByZAR5ZByDpg653jk1YCwM5jADQ/pN8
+QpM7wJIhR4l7oZOSoIoyCXxMiS8JWDsLaJRS+QgwQj5V6Y5XuTFZKTxbmZOvICRKEpYQOZY44JTv
+B5Xx0ZWKgCW+EIUc+IgeKI8qSI9YcZSiUCxp0YhSiHhUSJGSaJFyWTh0WQjv0guB6IiGCYmIOY+K
+GReA2QnHUxSEmZeTuZeV2ZeXWReZqQl2A5nHuIvJ2IvLeJOLuQ2leQmcA5lZ55Y9U5bOc5ZHEZtX
+cl+8mZK8iJCt6XO305h6cEK/KZbBuZK42UG6STzGeQdFlJw+aZte05w+9Jx/GZ10QEjUOU7W6TfY
+uUWzKCzcGQew9J2kFZ6QM56bVJ5+oZ6E/qBP6vmTdBCUhTiU/oiOtyGfgQBS1Gmfc4Cf5WiII4mT
+0uGffvBavymgckCg/GigRMmH1qGgm4OP5GWVy1mTwxl4Q2KheNB0memgO/OKyhCL3QefzAGiddCO
+R0micAChqyah+1mU58GicsCRwgijbyCj6daPsviPMYKjq4OhZdUTPOoGPtp1pFijFGomRMoGSvmN
+draawomNv/iaCXqeh2Ok51Sl1siaWKqQWlqhXJoFU4pr7Ck67nlWKgqlZ2oFaQolUZo/5Bih+hmk
+/IkoIfQHc8pUFKSXbBiSFXmgZcoedQoGf7qeWRKngrCkadekemqjfPokx+mlakilqQCp/mEoqSkq
+pJWaoSGKqdXYp5tqoiDhqdr4pqFqqi1KqqppqabAqbCoqlrpkq3aqK86jbW5AYlqWqiKDCi6qqCa
+q7Q1B4tqXR3wq4VAqydqq2aJq8bqqm6QrGCKWo4KlMF6DMN6q6w6rbIqpbBqgHqTrQ+6rdQDpJ+6
+p+C6rObqA9baNcy6behaDN0ard/arqKaBvGaRJzgrKmqrsTKrvo6V++aA/3KQwebBgArrNCam9Ja
+sPtKBgmLAvMqkfVKDPcKsfkqscdKseNqkCtwsfeZscOwsc4ZsR4bPgsbAxU7si0bBg3LrQ+bsh27
+sr4asy3wstojCTObrjQ6qU+Ks/7q/gU8yzw6uwU/a681m50qS7Q52wVH6wIkuwZLq7FNS57FCrVZ
+lLTFqIG92p4jdaczmqfrSqlcq7BoGrLAeZ2KcLUnm7XvubVpW7RVMLVsCqxk+6NBe7ZDW7cqULUu
+y7Yz2ZRe+wRwKwwo67Q3C7jlWjeEq6HNIl4mq7hy66Z067gWe7gwpYOSiZWPWrnBsLhaS7CaG7ic
+e5J4manMCQiJO7qXW1dPe7pfygR4O7l98LoFEbuqNbu0W7tJcLutC3Wiu7sC662Z+7swG7yRq5w1
+tXV7y6THi6/Jq7zLawTCi3vwWLy/QLpza7rWS7U6m73e8ZHce5e8O3CNG76bOwTk/otdJRu9kTq9
+HFu97Iu0M9O8bfkEgvsq54ua9Guz9nu/+Auv+tuRUtC/SqC73Zu+Lbm+BIy6PfC+h6Sk/8sXiWmo
+EQy/OkDBdMQGDIy+Acy4A7zBwHOeHowbahDCANy3A4u2JnybN5DCSqDAQcDCGGyZGhzDTlUDNNwa
+qQuB18iX2Yi84MvDbisDP5wsQSyOV0rEWYrEFQwDSzwWTVyYlEmoGTyhJCnFCOguB1yd3HDFpXqY
+WqzDXIygXly+nhiZWNwFNmwDOOy9mHvEa0yWOfiJn/sFcTwDc+zAT3nHQAyFnvvG90DGzkuIBWq2
+L/y3gqy9cwiIXZiPfIzIYryP/mUrkml8qI8snl/LiLpIrmrQx0IsplBMpp38F+NRxUhBBX88wqUL
+w6nMxq8Uxkv5BqS8x4MqlJrspF08y897j7zqeWuQy6ybxbxcqJsMzFEQm6xcyU7wyi5sxLLMzFkV
+UbacQnZgzG2ryHjay0L7y9b8wT61umXsJ6krzYxMzY48zlNMkOYcq9t8uOoMzn4rzu6swpnHlgi8
+B9x8y5jMt+tMvXaczz2MiPx8yf4cs/WszL6sxgatyjiZ0ADdB//MqAEtvdNM0NUc0eSMhmHbJu/a
+0Fv80Jzs0T8wPT1B0do8CNxM0mhs0ih9BTMCPiwNnoWQyzAtmjs801RQJPBx/tMzZSdcutNFzNHt
+7NNHwCgtPMm6zAvcadRRrNSQ+2lf0ZnHnNPGKdWoTNVSMDGoidXnTNQ0wNWu6dVfDU69INbyvAgX
+a9bEidZOgDioGdKOwKxw7aFybbvHFY2tmAiJmtcruNdNgJyl7NbVJdh+Sdh8Pcw4yiwGMAGRbQCU
+jQGRnQKXvQWPfcF0LLsQzNg+XIIgiiyVLQGUfdmZTQGpbQKr3cpPbcqhedT1W9CgjbDhqKBsktmT
+XdoHkNqtXdqnLdm7fdqVTdy7PcaGPMSxPdW1zbzD/GnHPNmm3duSXd0XIN3TTd3ajdoVwN1iIJ+K
+PZrNjQQS9Z1wIt3GPd28/m0B2L3d2e3dxJ3dY2DenA3IcTnezg3SUdvNwu3b1d3aqt3b8P3e6m3d
+AH7IIpvR87vRs93R+D3D48qbfbLaup3e7G3avD3g1G3c7W0GEl7fsPy9Dv7gof3c7prIolCa4d3T
+JO6+kQuYssPhgL0WK77MLU4ED7mWQ40KOg6oCt6pIV7HI37jg2vi50Q+SVoGxIjR3pzJDh3OEE3k
+tm3kR94RSa7k0VjjMi3l+Uvl5fqMV04GFaTlUH7SXL6FklyH/hrmZ+ALZH7PUX7mJa7fa2Iidn7n
+eJ7ner7nJgLiDC7AtC3neezG9wuXG2jmgr6KXh7Bhv5DiT4D1qqvja6d/o/+h0K9spPuu5UujXTO
+w5n+2ZsOjotOwJ9ewqGOi2ArxaUe6Keu6J0ew6s+5K3u6sZIjdYb60k962h+6R6L6/is64uY5myt
+vL4e58Ae7LwuscWO6Me+XclesMve7EqczUQb7dJOxdSOs9Z+7S4Q6e267dzexk5N6m3q2aYe7uVc
+yIVe7r0L6ugek/FM7OyuvudurAUgAfd+AAWw7z+Q7yfg79806utuk3F9uvyu7/qe7wCvAwtPAg3/
+UdmO6fP+wPVuJf5+7/uu8BXw8BmP8QrP7x0/AR0/8gl/8CKf8fhu8hpf8h4P8iHfuXpM7gAw8wBQ
+8zZ/8zif8zrf2e1e/vEWj/AIv/L4fgEXD/QXX/RFL/JAv/RLr/JDb/Qpr/QmD/ECz746f/VYj/U8
+T++sjigYz/Jfn/AYsPBC7/Rkj/JJ//Ri//Qr//FKz/JU/+omnPV0X/dbT/FdXyco//ZCbwEHH/Z/
+//drb/Z9H/htz/Ypr/Fp7+zx/rt1//hXf/eB7LhkP/Qk7/eCn/hwr/kjf/lBv/d7v/mKj/ahn+4x
+P/CQn/o5zNM2jtIPnwGvvwPeDq6qX/uSf99I3PkeEPtE7+JVH761r/q3f+g+zft+7/tyv8HBn/rD
+7+jvLurJz+jL//jNT+nPb/qEbvXTb/f2fegP8v3gH/7iP/7kX/7m/n/+6D/707r93K8bnPH+8B//
+8j//9F//9n//+E//oez47J/1SmHJEHDkpNVenPXm3X8wFEeyNM8RCFa2BVA4lme6tm8g13e+9/lW
+UDgkFgOvW1K5ZDadT6hSVURGrVdsdvnjdntGcHhY1ZbNZ3Ra3ZkSyWt4XF7z1rtivNi+5/f9f8BA
+wUHCQsNDxETFHaO3uUfISDa7vErLS8xMzU3OTr1Az1DRUdJS0yBHSdXVyL3TV9hY2dmjRdtb3NxB
+2iNW3985XeFh4mLjY+Rk5WUeYOdn6Gjpaepq62vsbO1t7m7vb/Bw8XHycvNz9HT1dfZ293f4ePl5
++nr7e/x8/X3+G37/f4ABBQ4kWNDgQYQJFS5k2NDhQ4gRJdKLAAA7
diff --git a/Documentation/DocBook/media/dvb/.gitignore b/Documentation/DocBook/media/dvb/.gitignore
new file mode 100644 (file)
index 0000000..d7ec32e
--- /dev/null
@@ -0,0 +1 @@
+!*.xml
diff --git a/Documentation/DocBook/media/dvb/audio.xml b/Documentation/DocBook/media/dvb/audio.xml
new file mode 100644 (file)
index 0000000..d643862
--- /dev/null
@@ -0,0 +1,1203 @@
+<title>DVB Audio Device</title>
+<para>The DVB audio device controls the MPEG2 audio decoder of the DVB hardware. It
+can be accessed through <emphasis role="tt">/dev/dvb/adapter0/audio0</emphasis>. Data types and and
+ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/video.h</emphasis> in your
+application.
+</para>
+<para>Please note that some DVB cards don&#8217;t have their own MPEG decoder, which results in
+the omission of the audio and video device.
+</para>
+
+<section id="audio_data_types">
+<title>Audio Data Types</title>
+<para>This section describes the structures, data types and defines used when talking to the
+audio device.
+</para>
+
+<section id="audio-stream-source-t">
+<title>audio_stream_source_t</title>
+<para>The audio stream source is set through the AUDIO_SELECT_SOURCE call and can take
+the following values, depending on whether we are replaying from an internal (demux) or
+external (user write) source.
+</para>
+<programlisting>
+typedef enum {
+       AUDIO_SOURCE_DEMUX,
+       AUDIO_SOURCE_MEMORY
+} audio_stream_source_t;
+</programlisting>
+<para>AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the
+DVR device) as the source of the video stream. If AUDIO_SOURCE_MEMORY
+is selected the stream comes from the application through the <emphasis role="tt">write()</emphasis> system
+call.
+</para>
+
+</section>
+<section id="audio-play-state-t">
+<title>audio_play_state_t</title>
+<para>The following values can be returned by the AUDIO_GET_STATUS call representing the
+state of audio playback.
+</para>
+<programlisting>
+typedef enum {
+       AUDIO_STOPPED,
+       AUDIO_PLAYING,
+       AUDIO_PAUSED
+} audio_play_state_t;
+</programlisting>
+
+</section>
+<section id="audio-channel-select-t">
+<title>audio_channel_select_t</title>
+<para>The audio channel selected via AUDIO_CHANNEL_SELECT is determined by the
+following values.
+</para>
+<programlisting>
+typedef enum {
+       AUDIO_STEREO,
+       AUDIO_MONO_LEFT,
+       AUDIO_MONO_RIGHT,
+       AUDIO_MONO,
+       AUDIO_STEREO_SWAPPED
+} audio_channel_select_t;
+</programlisting>
+
+</section>
+<section id="audio-status">
+<title>struct audio_status</title>
+<para>The AUDIO_GET_STATUS call returns the following structure informing about various
+states of the playback operation.
+</para>
+<programlisting>
+typedef struct audio_status {
+       boolean AV_sync_state;
+       boolean mute_state;
+       audio_play_state_t play_state;
+       audio_stream_source_t stream_source;
+       audio_channel_select_t channel_select;
+       boolean bypass_mode;
+       audio_mixer_t mixer_state;
+} audio_status_t;
+</programlisting>
+
+</section>
+<section id="audio-mixer">
+<title>struct audio_mixer</title>
+<para>The following structure is used by the AUDIO_SET_MIXER call to set the audio
+volume.
+</para>
+<programlisting>
+typedef struct audio_mixer {
+       unsigned int volume_left;
+       unsigned int volume_right;
+} audio_mixer_t;
+</programlisting>
+
+</section>
+<section id="audio_encodings">
+<title>audio encodings</title>
+<para>A call to AUDIO_GET_CAPABILITIES returns an unsigned integer with the following
+bits set according to the hardwares capabilities.
+</para>
+<programlisting>
+ #define AUDIO_CAP_DTS    1
+ #define AUDIO_CAP_LPCM   2
+ #define AUDIO_CAP_MP1    4
+ #define AUDIO_CAP_MP2    8
+ #define AUDIO_CAP_MP3   16
+ #define AUDIO_CAP_AAC   32
+ #define AUDIO_CAP_OGG   64
+ #define AUDIO_CAP_SDDS 128
+ #define AUDIO_CAP_AC3  256
+</programlisting>
+
+</section>
+<section id="audio-karaoke">
+<title>struct audio_karaoke</title>
+<para>The ioctl AUDIO_SET_KARAOKE uses the following format:
+</para>
+<programlisting>
+typedef
+struct audio_karaoke {
+       int vocal1;
+       int vocal2;
+       int melody;
+} audio_karaoke_t;
+</programlisting>
+<para>If Vocal1 or Vocal2 are non-zero, they get mixed into left and right t at 70% each. If both,
+Vocal1 and Vocal2 are non-zero, Vocal1 gets mixed into the left channel and Vocal2 into the
+right channel at 100% each. Ff Melody is non-zero, the melody channel gets mixed into left
+and right.
+</para>
+
+</section>
+<section id="audio-attributes-t">
+<title>audio attributes</title>
+<para>The following attributes can be set by a call to AUDIO_SET_ATTRIBUTES:
+</para>
+<programlisting>
+ typedef uint16_t audio_attributes_t;
+ /&#x22C6;   bits: descr. &#x22C6;/
+ /&#x22C6;   15-13 audio coding mode (0=ac3, 2=mpeg1, 3=mpeg2ext, 4=LPCM, 6=DTS, &#x22C6;/
+ /&#x22C6;   12    multichannel extension &#x22C6;/
+ /&#x22C6;   11-10 audio type (0=not spec, 1=language included) &#x22C6;/
+ /&#x22C6;    9- 8 audio application mode (0=not spec, 1=karaoke, 2=surround) &#x22C6;/
+ /&#x22C6;    7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit,  &#x22C6;/
+ /&#x22C6;    5- 4 Sample frequency fs (0=48kHz, 1=96kHz) &#x22C6;/
+ /&#x22C6;    2- 0 number of audio channels (n+1 channels) &#x22C6;/
+</programlisting>
+ </section></section>
+<section id="audio_function_calls">
+<title>Audio Function Calls</title>
+
+
+<section id="audio_fopen">
+<title>open()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call opens a named audio device (e.g. /dev/dvb/adapter0/audio0)
+ for subsequent use. When an open() call has succeeded, the device will be ready
+ for use. The significance of blocking or non-blocking mode is described in the
+ documentation for functions where there is a difference. It does not affect the
+ semantics of the open() call itself. A device opened in blocking mode can later
+ be put into non-blocking mode (and vice versa) using the F_SETFL command
+ of the fcntl system call. This is a standard system call, documented in the Linux
+ manual page for fcntl. Only one user can open the Audio Device in O_RDWR
+ mode. All other attempts to open the device in this mode will fail, and an error
+ code will be returned. If the Audio Device is opened in O_RDONLY mode, the
+ only ioctl call that can be used is AUDIO_GET_STATUS. All other call will
+ return with an error code.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int open(const char &#x22C6;deviceName, int flags);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>const char
+ *deviceName</para>
+</entry><entry
+ align="char">
+<para>Name of specific audio device.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int flags</para>
+</entry><entry
+ align="char">
+<para>A bit-wise OR of the following flags:</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_RDONLY read-only access</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_RDWR read/write access</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_NONBLOCK open in non-blocking mode</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>(blocking mode is the default)</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>ENODEV</para>
+</entry><entry
+ align="char">
+<para>Device driver not loaded/available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBUSY</para>
+</entry><entry
+ align="char">
+<para>Device or resource busy.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Invalid argument.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section>
+<section id="audio_fclose">
+<title>close()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call closes a previously opened audio device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int close(int fd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EBADF</para>
+</entry><entry
+ align="char">
+<para>fd is not a valid open file descriptor.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section>
+<section id="audio_fwrite">
+<title>write()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call can only be used if AUDIO_SOURCE_MEMORY is selected
+ in the ioctl call AUDIO_SELECT_SOURCE. The data provided shall be in
+ PES format. If O_NONBLOCK is not specified the function will block until
+ buffer space is available. The amount of data to be transferred is implied by
+ count.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>size_t write(int fd, const void &#x22C6;buf, size_t count);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>void *buf</para>
+</entry><entry
+ align="char">
+<para>Pointer to the buffer containing the PES data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t count</para>
+</entry><entry
+ align="char">
+<para>Size of buf.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EPERM</para>
+</entry><entry
+ align="char">
+<para>Mode AUDIO_SOURCE_MEMORY not selected.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ENOMEM</para>
+</entry><entry
+ align="char">
+<para>Attempted to write more data than the internal buffer can
+ hold.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBADF</para>
+</entry><entry
+ align="char">
+<para>fd is not a valid open file descriptor.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="AUDIO_STOP"
+role="subsection"><title>AUDIO_STOP</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to stop playing the current stream.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_STOP);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_STOP for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_PLAY"
+role="subsection"><title>AUDIO_PLAY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to start playing an audio stream from the
+ selected source.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_PLAY);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_PLAY for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_PAUSE"
+role="subsection"><title>AUDIO_PAUSE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call suspends the audio stream being played. Decoding and playing
+ are paused. It is then possible to restart again decoding and playing process of
+ the audio stream using AUDIO_CONTINUE command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>If AUDIO_SOURCE_MEMORY is selected in the ioctl call
+ AUDIO_SELECT_SOURCE, the DVB-subsystem will not decode (consume)
+ any more data until the ioctl call AUDIO_CONTINUE or AUDIO_PLAY is
+ performed.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_PAUSE);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_PAUSE for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_CONTINUE"
+role="subsection"><title>AUDIO_CONTINUE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl restarts the decoding and playing process previously paused
+with AUDIO_PAUSE command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>It only works if the stream were previously stopped with AUDIO_PAUSE</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_CONTINUE);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_CONTINUE for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_SELECT_SOURCE"
+role="subsection"><title>AUDIO_SELECT_SOURCE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call informs the audio device which source shall be used
+ for the input data. The possible sources are demux or memory. If
+ AUDIO_SOURCE_MEMORY is selected, the data is fed to the Audio Device
+ through the write command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_SELECT_SOURCE,
+ audio_stream_source_t source);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_SELECT_SOURCE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>audio_stream_source_t
+ source</para>
+</entry><entry
+ align="char">
+<para>Indicates the source that shall be used for the Audio
+ stream.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_SET_MUTE"
+role="subsection"><title>AUDIO_SET_MUTE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the audio device to mute the stream that is currently being
+ played.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_SET_MUTE,
+ boolean state);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_SET_MUTE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>boolean state</para>
+</entry><entry
+ align="char">
+<para>Indicates if audio device shall mute or not.</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>TRUE Audio Mute</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>FALSE Audio Un-mute</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_SET_AV_SYNC"
+role="subsection"><title>AUDIO_SET_AV_SYNC</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to turn ON or OFF A/V synchronization.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_SET_AV_SYNC,
+ boolean state);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_AV_SYNC for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>boolean state</para>
+</entry><entry
+ align="char">
+<para>Tells the DVB subsystem if A/V synchronization shall be
+ ON or OFF.</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>TRUE AV-sync ON</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>FALSE AV-sync OFF</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_SET_BYPASS_MODE"
+role="subsection"><title>AUDIO_SET_BYPASS_MODE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to bypass the Audio decoder and forward
+ the stream without decoding. This mode shall be used if streams that can&#8217;t be
+ handled by the DVB system shall be decoded. Dolby DigitalTM streams are
+ automatically forwarded by the DVB subsystem if the hardware can handle it.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ AUDIO_SET_BYPASS_MODE, boolean mode);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_SET_BYPASS_MODE for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>boolean mode</para>
+</entry><entry
+ align="char">
+<para>Enables or disables the decoding of the current Audio
+ stream in the DVB subsystem.</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>TRUE Bypass is disabled</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>FALSE Bypass is enabled</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_CHANNEL_SELECT"
+role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to select the requested channel if possible.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ AUDIO_CHANNEL_SELECT, audio_channel_select_t);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_CHANNEL_SELECT for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>audio_channel_select_t
+ ch</para>
+</entry><entry
+ align="char">
+<para>Select the output format of the audio (mono left/right,
+ stereo).</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_GET_STATUS"
+role="subsection"><title>AUDIO_GET_STATUS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to return the current state of the Audio
+ Device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_GET_STATUS,
+ struct audio_status &#x22C6;status);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_GET_STATUS for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct audio_status
+ *status</para>
+</entry><entry
+ align="char">
+<para>Returns the current state of Audio Device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_GET_CAPABILITIES"
+role="subsection"><title>AUDIO_GET_CAPABILITIES</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to tell us about the decoding capabilities
+ of the audio hardware.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ AUDIO_GET_CAPABILITIES, unsigned int &#x22C6;cap);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_GET_CAPABILITIES for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>unsigned int *cap</para>
+</entry><entry
+ align="char">
+<para>Returns a bit array of supported sound formats.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_CLEAR_BUFFER"
+role="subsection"><title>AUDIO_CLEAR_BUFFER</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to clear all software and hardware buffers
+ of the audio decoder device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_CLEAR_BUFFER);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_CLEAR_BUFFER for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_SET_ID"
+role="subsection"><title>AUDIO_SET_ID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl selects which sub-stream is to be decoded if a program or system
+ stream is sent to the video device. If no audio stream type is set the id has to be
+ in [0xC0,0xDF] for MPEG sound, in [0x80,0x87] for AC3 and in [0xA0,0xA7]
+ for LPCM. More specifications may follow for other stream types. If the stream
+ type is set the id just specifies the substream id of the audio stream and only
+ the first 5 bits are recognized.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_SET_ID, int
+ id);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_SET_ID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int id</para>
+</entry><entry
+ align="char">
+<para>audio sub-stream id</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_SET_MIXER"
+role="subsection"><title>AUDIO_SET_MIXER</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl lets you adjust the mixer settings of the audio decoder.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = AUDIO_SET_MIXER,
+ audio_mixer_t &#x22C6;mix);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_SET_ID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>audio_mixer_t *mix</para>
+</entry><entry
+ align="char">
+<para>mixer settings.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_SET_STREAMTYPE"
+role="subsection"><title>AUDIO_SET_STREAMTYPE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl tells the driver which kind of audio stream to expect. This is useful
+ if the stream offers several audio sub-streams like LPCM and AC3.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = AUDIO_SET_STREAMTYPE,
+ int type);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_SET_STREAMTYPE for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int type</para>
+</entry><entry
+ align="char">
+<para>stream type</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>type is not a valid or supported stream type.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="AUDIO_SET_EXT_ID"
+role="subsection"><title>AUDIO_SET_EXT_ID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl can be used to set the extension id for MPEG streams in DVD
+ playback. Only the first 3 bits are recognized.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = AUDIO_SET_EXT_ID, int
+ id);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_SET_EXT_ID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int id</para>
+</entry><entry
+ align="char">
+<para>audio sub_stream_id</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>id is not a valid id.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="AUDIO_SET_ATTRIBUTES"
+role="subsection"><title>AUDIO_SET_ATTRIBUTES</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is intended for DVD playback and allows you to set certain
+ information about the audio stream.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = AUDIO_SET_ATTRIBUTES,
+ audio_attributes_t attr );</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_SET_ATTRIBUTES for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>audio_attributes_t
+ attr</para>
+</entry><entry
+ align="char">
+<para>audio attributes according to section ??</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>attr is not a valid or supported attribute setting.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="AUDIO_SET_KARAOKE"
+role="subsection"><title>AUDIO_SET_KARAOKE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl allows one to set the mixer settings for a karaoke DVD.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = AUDIO_SET_KARAOKE,
+ audio_karaoke_t &#x22C6;karaoke);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_SET_KARAOKE for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>audio_karaoke_t
+ *karaoke</para>
+</entry><entry
+ align="char">
+<para>karaoke settings according to section ??.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>karaoke is not a valid or supported karaoke setting.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+ </section>
+</section>
diff --git a/Documentation/DocBook/media/dvb/ca.xml b/Documentation/DocBook/media/dvb/ca.xml
new file mode 100644 (file)
index 0000000..5c4adb4
--- /dev/null
@@ -0,0 +1,229 @@
+<title>DVB CA Device</title>
+<para>The DVB CA device controls the conditional access hardware. It can be accessed through
+<emphasis role="tt">/dev/dvb/adapter0/ca0</emphasis>. Data types and and ioctl definitions can be accessed by
+including <emphasis role="tt">linux/dvb/ca.h</emphasis> in your application.
+</para>
+
+<section id="ca_data_types">
+<title>CA Data Types</title>
+
+
+<section id="ca-slot-info">
+<title>ca_slot_info_t</title>
+ <programlisting>
+typedef struct ca_slot_info {
+       int num;               /&#x22C6; slot number &#x22C6;/
+
+       int type;              /&#x22C6; CA interface this slot supports &#x22C6;/
+#define CA_CI            1     /&#x22C6; CI high level interface &#x22C6;/
+#define CA_CI_LINK       2     /&#x22C6; CI link layer level interface &#x22C6;/
+#define CA_CI_PHYS       4     /&#x22C6; CI physical layer level interface &#x22C6;/
+#define CA_DESCR         8     /&#x22C6; built-in descrambler &#x22C6;/
+#define CA_SC          128     /&#x22C6; simple smart card interface &#x22C6;/
+
+       unsigned int flags;
+#define CA_CI_MODULE_PRESENT 1 /&#x22C6; module (or card) inserted &#x22C6;/
+#define CA_CI_MODULE_READY   2
+} ca_slot_info_t;
+</programlisting>
+
+</section>
+<section id="ca-descr-info">
+<title>ca_descr_info_t</title>
+<programlisting>
+typedef struct ca_descr_info {
+       unsigned int num;  /&#x22C6; number of available descramblers (keys) &#x22C6;/
+       unsigned int type; /&#x22C6; type of supported scrambling system &#x22C6;/
+#define CA_ECD           1
+#define CA_NDS           2
+#define CA_DSS           4
+} ca_descr_info_t;
+</programlisting>
+
+</section>
+<section id="ca-caps">
+<title>ca_caps_t</title>
+<programlisting>
+typedef struct ca_caps {
+       unsigned int slot_num;  /&#x22C6; total number of CA card and module slots &#x22C6;/
+       unsigned int slot_type; /&#x22C6; OR of all supported types &#x22C6;/
+       unsigned int descr_num; /&#x22C6; total number of descrambler slots (keys) &#x22C6;/
+       unsigned int descr_type;/&#x22C6; OR of all supported types &#x22C6;/
+ } ca_cap_t;
+</programlisting>
+
+</section>
+<section id="ca-msg">
+<title>ca_msg_t</title>
+<programlisting>
+/&#x22C6; a message to/from a CI-CAM &#x22C6;/
+typedef struct ca_msg {
+       unsigned int index;
+       unsigned int type;
+       unsigned int length;
+       unsigned char msg[256];
+} ca_msg_t;
+</programlisting>
+
+</section>
+<section id="ca-descr">
+<title>ca_descr_t</title>
+<programlisting>
+typedef struct ca_descr {
+       unsigned int index;
+       unsigned int parity;
+       unsigned char cw[8];
+} ca_descr_t;
+</programlisting>
+</section>
+
+<section id="ca-pid">
+<title>ca-pid</title>
+<programlisting>
+typedef struct ca_pid {
+       unsigned int pid;
+       int index;              /&#x22C6; -1 == disable&#x22C6;/
+} ca_pid_t;
+</programlisting>
+</section></section>
+
+<section id="ca_function_calls">
+<title>CA Function Calls</title>
+
+
+<section id="ca_fopen">
+<title>open()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call opens a named ca device (e.g. /dev/ost/ca) for subsequent use.</para>
+<para>When an open() call has succeeded, the device will be ready for use.
+ The significance of blocking or non-blocking mode is described in the
+ documentation for functions where there is a difference. It does not affect the
+ semantics of the open() call itself. A device opened in blocking mode can later
+ be put into non-blocking mode (and vice versa) using the F_SETFL command
+ of the fcntl system call. This is a standard system call, documented in the Linux
+ manual page for fcntl. Only one user can open the CA Device in O_RDWR
+ mode. All other attempts to open the device in this mode will fail, and an error
+ code will be returned.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int open(const char &#x22C6;deviceName, int flags);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>const char
+ *deviceName</para>
+</entry><entry
+ align="char">
+<para>Name of specific video device.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int flags</para>
+</entry><entry
+ align="char">
+<para>A bit-wise OR of the following flags:</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_RDONLY read-only access</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_RDWR read/write access</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_NONBLOCK open in non-blocking mode</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>(blocking mode is the default)</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>ENODEV</para>
+</entry><entry
+ align="char">
+<para>Device driver not loaded/available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EINTERNAL</para>
+</entry><entry
+ align="char">
+<para>Internal error.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBUSY</para>
+</entry><entry
+ align="char">
+<para>Device or resource busy.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Invalid argument.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section>
+<section id="ca_fclose">
+<title>close()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call closes a previously opened audio device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int close(int fd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EBADF</para>
+</entry><entry
+ align="char">
+<para>fd is not a valid open file descriptor.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+ </section>
+</section>
diff --git a/Documentation/DocBook/media/dvb/demux.xml b/Documentation/DocBook/media/dvb/demux.xml
new file mode 100644 (file)
index 0000000..37c1790
--- /dev/null
@@ -0,0 +1,902 @@
+<title>DVB Demux Device</title>
+
+<para>The DVB demux device controls the filters of the DVB hardware/software. It can be
+accessed through <emphasis role="tt">/dev/adapter0/demux0</emphasis>. Data types and and ioctl definitions can be
+accessed by including <emphasis role="tt">linux/dvb/dmx.h</emphasis> in your application.
+</para>
+<section id="dmx_types">
+<title>Demux Data Types</title>
+
+<section id="dmx-output-t">
+<title>dmx_output_t</title>
+<programlisting>
+typedef enum
+{
+       DMX_OUT_DECODER, /&#x22C6; Streaming directly to decoder. &#x22C6;/
+       DMX_OUT_TAP,     /&#x22C6; Output going to a memory buffer &#x22C6;/
+                        /&#x22C6; (to be retrieved via the read command).&#x22C6;/
+       DMX_OUT_TS_TAP,  /&#x22C6; Output multiplexed into a new TS  &#x22C6;/
+                        /&#x22C6; (to be retrieved by reading from the &#x22C6;/
+                        /&#x22C6; logical DVR device).                 &#x22C6;/
+       DMX_OUT_TSDEMUX_TAP /&#x22C6; Like TS_TAP but retrieved from the DMX device &#x22C6;/
+} dmx_output_t;
+</programlisting>
+<para><emphasis role="tt">DMX_OUT_TAP</emphasis> delivers the stream output to the demux device on which the ioctl is
+called.
+</para>
+<para><emphasis role="tt">DMX_OUT_TS_TAP</emphasis> routes output to the logical DVR device <emphasis role="tt">/dev/dvb/adapter0/dvr0</emphasis>,
+which delivers a TS multiplexed from all filters for which <emphasis role="tt">DMX_OUT_TS_TAP</emphasis> was
+specified.
+</para>
+</section>
+
+<section id="dmx-input-t">
+<title>dmx_input_t</title>
+<programlisting>
+typedef enum
+{
+       DMX_IN_FRONTEND, /&#x22C6; Input from a front-end device.  &#x22C6;/
+       DMX_IN_DVR       /&#x22C6; Input from the logical DVR device.  &#x22C6;/
+} dmx_input_t;
+</programlisting>
+</section>
+
+<section id="dmx-pes-type-t">
+<title>dmx_pes_type_t</title>
+<programlisting>
+typedef enum
+{
+       DMX_PES_AUDIO0,
+       DMX_PES_VIDEO0,
+       DMX_PES_TELETEXT0,
+       DMX_PES_SUBTITLE0,
+       DMX_PES_PCR0,
+
+       DMX_PES_AUDIO1,
+       DMX_PES_VIDEO1,
+       DMX_PES_TELETEXT1,
+       DMX_PES_SUBTITLE1,
+       DMX_PES_PCR1,
+
+       DMX_PES_AUDIO2,
+       DMX_PES_VIDEO2,
+       DMX_PES_TELETEXT2,
+       DMX_PES_SUBTITLE2,
+       DMX_PES_PCR2,
+
+       DMX_PES_AUDIO3,
+       DMX_PES_VIDEO3,
+       DMX_PES_TELETEXT3,
+       DMX_PES_SUBTITLE3,
+       DMX_PES_PCR3,
+
+       DMX_PES_OTHER
+} dmx_pes_type_t;
+</programlisting>
+</section>
+
+<section id="dmx-filter">
+<title>struct dmx_filter</title>
+ <programlisting>
+ typedef struct dmx_filter
+{
+       __u8  filter[DMX_FILTER_SIZE];
+       __u8  mask[DMX_FILTER_SIZE];
+       __u8  mode[DMX_FILTER_SIZE];
+} dmx_filter_t;
+</programlisting>
+</section>
+
+<section id="dmx-sct-filter-params">
+<title>struct dmx_sct_filter_params</title>
+<programlisting>
+struct dmx_sct_filter_params
+{
+       __u16          pid;
+       dmx_filter_t   filter;
+       __u32          timeout;
+       __u32          flags;
+#define DMX_CHECK_CRC       1
+#define DMX_ONESHOT         2
+#define DMX_IMMEDIATE_START 4
+#define DMX_KERNEL_CLIENT   0x8000
+};
+</programlisting>
+</section>
+
+<section id="dmx-pes-filter-params">
+<title>struct dmx_pes_filter_params</title>
+<programlisting>
+struct dmx_pes_filter_params
+{
+       __u16          pid;
+       dmx_input_t    input;
+       dmx_output_t   output;
+       dmx_pes_type_t pes_type;
+       __u32          flags;
+};
+</programlisting>
+</section>
+
+<section id="dmx-event">
+<title>struct dmx_event</title>
+ <programlisting>
+ struct dmx_event
+ {
+        dmx_event_t          event;
+        time_t               timeStamp;
+        union
+        {
+                dmx_scrambling_status_t scrambling;
+        } u;
+ };
+</programlisting>
+</section>
+
+<section id="dmx-stc">
+<title>struct dmx_stc</title>
+<programlisting>
+struct dmx_stc {
+       unsigned int num;       /&#x22C6; input : which STC? 0..N &#x22C6;/
+       unsigned int base;      /&#x22C6; output: divisor for stc to get 90 kHz clock &#x22C6;/
+       __u64 stc;              /&#x22C6; output: stc in 'base'&#x22C6;90 kHz units &#x22C6;/
+};
+</programlisting>
+</section>
+
+<section id="dmx-caps">
+<title>struct dmx_caps</title>
+<programlisting>
+ typedef struct dmx_caps {
+       __u32 caps;
+       int num_decoders;
+} dmx_caps_t;
+</programlisting>
+</section>
+
+<section id="dmx-source-t">
+<title>enum dmx_source_t</title>
+<programlisting>
+typedef enum {
+       DMX_SOURCE_FRONT0 = 0,
+       DMX_SOURCE_FRONT1,
+       DMX_SOURCE_FRONT2,
+       DMX_SOURCE_FRONT3,
+       DMX_SOURCE_DVR0   = 16,
+       DMX_SOURCE_DVR1,
+       DMX_SOURCE_DVR2,
+       DMX_SOURCE_DVR3
+} dmx_source_t;
+</programlisting>
+</section>
+
+</section>
+<section id="dmx_fcalls">
+<title>Demux Function Calls</title>
+
+<section id="dmx_fopen">
+<title>open()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call, used with a device name of /dev/dvb/adapter0/demux0,
+ allocates a new filter and returns a handle which can be used for subsequent
+ control of that filter. This call has to be made for each filter to be used, i.e. every
+ returned file descriptor is a reference to a single filter. /dev/dvb/adapter0/dvr0
+ is a logical device to be used for retrieving Transport Streams for digital
+ video recording. When reading from this device a transport stream containing
+ the packets from all PES filters set in the corresponding demux device
+ (/dev/dvb/adapter0/demux0) having the output set to DMX_OUT_TS_TAP. A
+ recorded Transport Stream is replayed by writing to this device. </para>
+<para>The significance of blocking or non-blocking mode is described in the
+ documentation for functions where there is a difference. It does not affect the
+ semantics of the open() call itself. A device opened in blocking mode can later
+ be put into non-blocking mode (and vice versa) using the F_SETFL command
+ of the fcntl system call.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int open(const char &#x22C6;deviceName, int flags);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>const char
+ *deviceName</para>
+</entry><entry
+ align="char">
+<para>Name of demux device.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int flags</para>
+</entry><entry
+ align="char">
+<para>A bit-wise OR of the following flags:</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_RDWR read/write access</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_NONBLOCK open in non-blocking mode</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>(blocking mode is the default)</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>ENODEV</para>
+</entry><entry
+ align="char">
+<para>Device driver not loaded/available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Invalid argument.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EMFILE</para>
+</entry><entry
+ align="char">
+<para>&#8220;Too many open files&#8221;, i.e. no more filters available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ENOMEM</para>
+</entry><entry
+ align="char">
+<para>The driver failed to allocate enough memory.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="dmx_fclose">
+<title>close()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call deactivates and deallocates a filter that was previously
+ allocated via the open() call.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int close(int fd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EBADF</para>
+</entry><entry
+ align="char">
+<para>fd is not a valid open file descriptor.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="dmx_fread">
+<title>read()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call returns filtered data, which might be section or PES data. The
+ filtered data is transferred from the driver&#8217;s internal circular buffer to buf. The
+ maximum amount of data to be transferred is implied by count.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>When returning section data the driver always tries to return a complete single
+ section (even though buf would provide buffer space for more data). If the size
+ of the buffer is smaller than the section as much as possible will be returned,
+ and the remaining data will be provided in subsequent calls.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>The size of the internal buffer is 2 * 4096 bytes (the size of two maximum
+ sized sections) by default. The size of this buffer may be changed by using the
+ DMX_SET_BUFFER_SIZE function. If the buffer is not large enough, or if
+ the read operations are not performed fast enough, this may result in a buffer
+ overflow error. In this case EOVERFLOW will be returned, and the circular
+ buffer will be emptied. This call is blocking if there is no data to return, i.e. the
+ process will be put to sleep waiting for data, unless the O_NONBLOCK flag
+ is specified.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>Note that in order to be able to read, the filtering process has to be started
+ by defining either a section or a PES filter by means of the ioctl functions,
+ and then starting the filtering process via the DMX_START ioctl function
+ or by setting the DMX_IMMEDIATE_START flag. If the reading is done
+ from a logical DVR demux device, the data will constitute a Transport Stream
+ including the packets from all PES filters in the corresponding demux device
+ /dev/dvb/adapter0/demux0 having the output set to DMX_OUT_TS_TAP.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>size_t read(int fd, void &#x22C6;buf, size_t count);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>void *buf</para>
+</entry><entry
+ align="char">
+<para>Pointer to the buffer to be used for returned filtered data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t count</para>
+</entry><entry
+ align="char">
+<para>Size of buf.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EWOULDBLOCK</para>
+</entry><entry
+ align="char">
+<para>No data to return and O_NONBLOCK was specified.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBADF</para>
+</entry><entry
+ align="char">
+<para>fd is not a valid open file descriptor.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ECRC</para>
+</entry><entry
+ align="char">
+<para>Last section had a CRC error - no data returned. The
+ buffer is flushed.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EOVERFLOW</para>
+</entry><entry
+ align="char">
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>The filtered data was not read from the buffer in due
+ time, resulting in non-read data being lost. The buffer is
+ flushed.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ETIMEDOUT</para>
+</entry><entry
+ align="char">
+<para>The section was not loaded within the stated timeout
+ period. See ioctl DMX_SET_FILTER for how to set a
+ timeout.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EFAULT</para>
+</entry><entry
+ align="char">
+<para>The driver failed to write to the callers buffer due to an
+ invalid *buf pointer.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="dmx_fwrite">
+<title>write()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call is only provided by the logical device /dev/dvb/adapter0/dvr0,
+ associated with the physical demux device that provides the actual DVR
+ functionality. It is used for replay of a digitally recorded Transport Stream.
+ Matching filters have to be defined in the corresponding physical demux
+ device, /dev/dvb/adapter0/demux0. The amount of data to be transferred is
+ implied by count.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>ssize_t write(int fd, const void &#x22C6;buf, size_t
+ count);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>void *buf</para>
+</entry><entry
+ align="char">
+<para>Pointer to the buffer containing the Transport Stream.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t count</para>
+</entry><entry
+ align="char">
+<para>Size of buf.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EWOULDBLOCK</para>
+</entry><entry
+ align="char">
+<para>No data was written. This
+ might happen if O_NONBLOCK was specified and there
+ is no more buffer space available (if O_NONBLOCK is
+ not specified the function will block until buffer space is
+ available).</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBUSY</para>
+</entry><entry
+ align="char">
+<para>This error code indicates that there are conflicting
+ requests. The corresponding demux device is setup to
+ receive data from the front- end. Make sure that these
+ filters are stopped and that the filters with input set to
+ DMX_IN_DVR are started.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBADF</para>
+</entry><entry
+ align="char">
+<para>fd is not a valid open file descriptor.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="DMX_START">
+<title>DMX_START</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call is used to start the actual filtering operation defined via the ioctl
+ calls DMX_SET_FILTER or DMX_SET_PES_FILTER.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request = DMX_START);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_START for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Invalid argument, i.e. no filtering parameters provided via
+ the DMX_SET_FILTER or DMX_SET_PES_FILTER
+ functions.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBUSY</para>
+</entry><entry
+ align="char">
+<para>This error code indicates that there are conflicting
+ requests. There are active filters filtering data from
+ another input source. Make sure that these filters are
+ stopped before starting this filter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="DMX_STOP">
+<title>DMX_STOP</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call is used to stop the actual filtering operation defined via the
+ ioctl calls DMX_SET_FILTER or DMX_SET_PES_FILTER and started via
+ the DMX_START command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request = DMX_STOP);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_STOP for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_SET_FILTER">
+<title>DMX_SET_FILTER</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call sets up a filter according to the filter and mask parameters
+ provided. A timeout may be defined stating number of seconds to wait for a
+ section to be loaded. A value of 0 means that no timeout should be applied.
+ Finally there is a flag field where it is possible to state whether a section should
+ be CRC-checked, whether the filter should be a &#8221;one-shot&#8221; filter, i.e. if the
+ filtering operation should be stopped after the first section is received, and
+ whether the filtering operation should be started immediately (without waiting
+ for a DMX_START ioctl call). If a filter was previously set-up, this filter will
+ be canceled, and the receive buffer will be flushed.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request = DMX_SET_FILTER,
+ struct dmx_sct_filter_params &#x22C6;params);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_SET_FILTER for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dmx_sct_filter_params
+ *params</para>
+</entry><entry
+ align="char">
+<para>Pointer to structure containing filter parameters.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_SET_PES_FILTER">
+<title>DMX_SET_PES_FILTER</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call sets up a PES filter according to the parameters provided. By a
+ PES filter is meant a filter that is based just on the packet identifier (PID), i.e.
+ no PES header or payload filtering capability is supported.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>The transport stream destination for the filtered output may be set. Also the
+ PES type may be stated in order to be able to e.g. direct a video stream directly
+ to the video decoder. Finally there is a flag field where it is possible to state
+ whether the filtering operation should be started immediately (without waiting
+ for a DMX_START ioctl call). If a filter was previously set-up, this filter will
+ be cancelled, and the receive buffer will be flushed.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request = DMX_SET_PES_FILTER,
+ struct dmx_pes_filter_params &#x22C6;params);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_SET_PES_FILTER for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dmx_pes_filter_params
+ *params</para>
+</entry><entry
+ align="char">
+<para>Pointer to structure containing filter parameters.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EBUSY</para>
+</entry><entry
+ align="char">
+<para>This error code indicates that there are conflicting
+ requests. There are active filters filtering data from
+ another input source. Make sure that these filters are
+ stopped before starting this filter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="DMX_SET_BUFFER_SIZE">
+<title>DMX_SET_BUFFER_SIZE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call is used to set the size of the circular buffer used for filtered data.
+ The default size is two maximum sized sections, i.e. if this function is not called
+ a buffer size of 2 * 4096 bytes will be used.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request =
+ DMX_SET_BUFFER_SIZE, unsigned long size);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_SET_BUFFER_SIZE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>unsigned long size</para>
+</entry><entry
+ align="char">
+<para>Size of circular buffer.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_GET_EVENT">
+<title>DMX_GET_EVENT</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns an event if available. If an event is not available,
+ the behavior depends on whether the device is in blocking or non-blocking
+ mode. In the latter case, the call fails immediately with errno set to
+ EWOULDBLOCK. In the former case, the call blocks until an event becomes
+ available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>The standard Linux poll() and/or select() system calls can be used with the
+ device file descriptor to watch for new events. For select(), the file descriptor
+ should be included in the exceptfds argument, and for poll(), POLLPRI should
+ be specified as the wake-up condition. Only the latest event for each filter is
+ saved.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request = DMX_GET_EVENT,
+ struct dmx_event &#x22C6;ev);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_GET_EVENT for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dmx_event *ev</para>
+</entry><entry
+ align="char">
+<para>Pointer to the location where the event is to be stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EWOULDBLOCK</para>
+</entry><entry
+ align="char">
+<para>There is no event pending, and the device is in
+ non-blocking mode.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="DMX_GET_STC">
+<title>DMX_GET_STC</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns the current value of the system time counter (which is driven
+ by a PES filter of type DMX_PES_PCR). Some hardware supports more than one
+ STC, so you must specify which one by setting the num field of stc before the ioctl
+ (range 0...n). The result is returned in form of a ratio with a 64 bit numerator
+ and a 32 bit denominator, so the real 90kHz STC value is stc-&#x003E;stc /
+ stc-&#x003E;base
+ .</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request = DMX_GET_STC, struct
+ dmx_stc &#x22C6;stc);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_GET_STC for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dmx_stc *stc</para>
+</entry><entry
+ align="char">
+<para>Pointer to the location where the stc is to be stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Invalid stc number.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+ </section></section>
diff --git a/Documentation/DocBook/media/dvb/dvbapi.xml b/Documentation/DocBook/media/dvb/dvbapi.xml
new file mode 100644 (file)
index 0000000..2ab6ddc
--- /dev/null
@@ -0,0 +1,141 @@
+<partinfo>
+<authorgroup>
+<author>
+<firstname>Ralph</firstname>
+<surname>Metzler</surname>
+<othername role="mi">J. K.</othername>
+<affiliation><address><email>rjkm@metzlerbros.de</email></address></affiliation>
+</author>
+<author>
+<firstname>Marcus</firstname>
+<surname>Metzler</surname>
+<othername role="mi">O. C.</othername>
+<affiliation><address><email>rjkm@metzlerbros.de</email></address></affiliation>
+</author>
+</authorgroup>
+<authorgroup>
+<author>
+<firstname>Mauro</firstname>
+<othername role="mi">Carvalho</othername>
+<surname>Chehab</surname>
+<affiliation><address><email>mchehab@redhat.com</email></address></affiliation>
+<contrib>Ported document to Docbook XML.</contrib>
+</author>
+</authorgroup>
+<copyright>
+       <year>2002</year>
+       <year>2003</year>
+       <holder>Convergence GmbH</holder>
+</copyright>
+<copyright>
+       <year>2009-2011</year>
+       <holder>Mauro Carvalho Chehab</holder>
+</copyright>
+
+<revhistory>
+<!-- Put document revisions here, newest first. -->
+<revision>
+       <revnumber>2.0.4</revnumber>
+       <date>2011-05-06</date>
+       <authorinitials>mcc</authorinitials>
+       <revremark>
+               Add more information about DVB APIv5, better describing the frontend GET/SET props ioctl's.
+       </revremark>
+</revision>
+<revision>
+       <revnumber>2.0.3</revnumber>
+       <date>2010-07-03</date>
+       <authorinitials>mcc</authorinitials>
+       <revremark>
+               Add some frontend capabilities flags, present on kernel, but missing at the specs.
+       </revremark>
+</revision>
+<revision>
+       <revnumber>2.0.2</revnumber>
+       <date>2009-10-25</date>
+       <authorinitials>mcc</authorinitials>
+       <revremark>
+               documents FE_SET_FRONTEND_TUNE_MODE and FE_DISHETWORK_SEND_LEGACY_CMD ioctls.
+       </revremark>
+</revision>
+<revision>
+<revnumber>2.0.1</revnumber>
+<date>2009-09-16</date>
+<authorinitials>mcc</authorinitials>
+<revremark>
+Added ISDB-T test originally written by Patrick Boettcher
+</revremark>
+</revision>
+<revision>
+<revnumber>2.0.0</revnumber>
+<date>2009-09-06</date>
+<authorinitials>mcc</authorinitials>
+<revremark>Conversion from LaTex to DocBook XML. The
+       contents is the same as the original LaTex version.</revremark>
+</revision>
+<revision>
+<revnumber>1.0.0</revnumber>
+<date>2003-07-24</date>
+<authorinitials>rjkm</authorinitials>
+<revremark>Initial revision on LaTEX.</revremark>
+</revision>
+</revhistory>
+</partinfo>
+
+
+<title>LINUX DVB API</title>
+<subtitle>Version 5.2</subtitle>
+<!-- ADD THE CHAPTERS HERE -->
+  <chapter id="dvb_introdution">
+    &sub-intro;
+  </chapter>
+  <chapter id="dvb_frontend">
+    &sub-frontend;
+  </chapter>
+  <chapter id="dvb_demux">
+    &sub-demux;
+  </chapter>
+  <chapter id="dvb_video">
+    &sub-video;
+  </chapter>
+  <chapter id="dvb_audio">
+    &sub-audio;
+  </chapter>
+  <chapter id="dvb_ca">
+    &sub-ca;
+  </chapter>
+  <chapter id="dvb_net">
+    &sub-net;
+  </chapter>
+  <chapter id="dvb_kdapi">
+    &sub-kdapi;
+  </chapter>
+  <chapter id="dvb_examples">
+    &sub-examples;
+  </chapter>
+<!-- END OF CHAPTERS -->
+  <appendix id="audio_h">
+    <title>DVB Audio Header File</title>
+    &sub-audio-h;
+  </appendix>
+  <appendix id="ca_h">
+    <title>DVB Conditional Access Header File</title>
+    &sub-ca-h;
+  </appendix>
+  <appendix id="dmx_h">
+    <title>DVB Demux Header File</title>
+    &sub-dmx-h;
+  </appendix>
+  <appendix id="frontend_h">
+    <title>DVB Frontend Header File</title>
+    &sub-frontend-h;
+  </appendix>
+  <appendix id="net_h">
+    <title>DVB Network Header File</title>
+    &sub-net-h;
+  </appendix>
+  <appendix id="video_h">
+    <title>DVB Video Header File</title>
+    &sub-video-h;
+  </appendix>
+
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
new file mode 100644 (file)
index 0000000..207e1a5
--- /dev/null
@@ -0,0 +1,859 @@
+<section id="FE_GET_SET_PROPERTY">
+<title><constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></title>
+<para>This section describes the DVB version 5 extention of the DVB-API, also
+called "S2API", as this API were added to provide support for DVB-S2. It was
+designed to be able to replace the old frontend API. Yet, the DISEQC and
+the capability ioctls weren't implemented yet via the new way.</para>
+<para>The typical usage for the <constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant>
+API is to replace the ioctl's were the <link linkend="dvb-frontend-parameters">
+struct <constant>dvb_frontend_parameters</constant></link> were used.</para>
+<section id="dtv-property">
+<title>DTV property type</title>
+<programlisting>
+/* Reserved fields should be set to 0 */
+struct dtv_property {
+       __u32 cmd;
+       union {
+               __u32 data;
+               struct {
+                       __u8 data[32];
+                       __u32 len;
+                       __u32 reserved1[3];
+                       void *reserved2;
+               } buffer;
+       } u;
+       int result;
+} __attribute__ ((packed));
+
+/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
+#define DTV_IOCTL_MAX_MSGS 64
+</programlisting>
+</section>
+<section id="dtv-properties">
+<title>DTV properties type</title>
+<programlisting>
+struct dtv_properties {
+       __u32 num;
+       struct dtv_property *props;
+};
+</programlisting>
+</section>
+
+<section id="FE_GET_PROPERTY">
+<title>FE_GET_PROPERTY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns one or more frontend properties. This call only
+ requires read-only access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>,
+ dtv_properties &#x22C6;props);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int num</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dtv_property *props</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the front-end property commands are stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row>
+  <entry align="char"><para>EOPNOTSUPP</para></entry>
+  <entry align="char"><para>Property type not supported.</para></entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="FE_SET_PROPERTY">
+<title>FE_SET_PROPERTY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call sets one or more frontend properties. This call only
+ requires read-only access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
+ dtv_properties &#x22C6;props);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int num</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dtv_property *props</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the front-end property commands are stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row>
+  <entry align="char"><para>EOPNOTSUPP</para></entry>
+  <entry align="char"><para>Property type not supported.</para></entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section>
+       <title>Property types</title>
+<para>
+On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
+the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
+get/set up to 64 properties. The actual meaning of each property is described on the next sections.
+</para>
+
+<para>The available frontend property types are shown on the next section.</para>
+</section>
+
+<section id="fe_property_parameters">
+       <title>Digital TV property parameters</title>
+       <section id="DTV-UNDEFINED">
+       <title><constant>DTV_UNDEFINED</constant></title>
+       <para>Used internally. A GET/SET operation for it won't change or return anything.</para>
+       </section>
+       <section id="DTV-TUNE">
+       <title><constant>DTV_TUNE</constant></title>
+       <para>Interpret the cache of data, build either a traditional frontend tunerequest so we can pass validation in the <constant>FE_SET_FRONTEND</constant> ioctl.</para>
+       </section>
+       <section id="DTV-CLEAR">
+       <title><constant>DTV_CLEAR</constant></title>
+       <para>Reset a cache of data specific to the frontend here. This does not effect hardware.</para>
+       </section>
+       <section id="DTV-FREQUENCY">
+               <title><constant>DTV_FREQUENCY</constant></title>
+
+               <para>Central frequency of the channel, in HZ.</para>
+
+               <para>Notes:</para>
+               <para>1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
+                       E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
+                       the channel which is 6MHz.</para>
+
+               <para>2)As in ISDB-Tsb the channel consists of only one or three segments the
+                       frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
+                       central frequency of the channel is expected.</para>
+       </section>
+       <section id="DTV-MODULATION">
+       <title><constant>DTV_MODULATION</constant></title>
+<para>Specifies the frontend modulation type for cable and satellite types. The modulation can be one of the types bellow:</para>
+<programlisting>
+ typedef enum fe_modulation {
+       QPSK,
+       QAM_16,
+       QAM_32,
+       QAM_64,
+       QAM_128,
+       QAM_256,
+       QAM_AUTO,
+       VSB_8,
+       VSB_16,
+       PSK_8,
+       APSK_16,
+       APSK_32,
+       DQPSK,
+ } fe_modulation_t;
+</programlisting>
+       </section>
+       <section id="DTV-BANDWIDTH-HZ">
+               <title><constant>DTV_BANDWIDTH_HZ</constant></title>
+
+               <para>Bandwidth for the channel, in HZ.</para>
+
+               <para>Possible values:
+                       <constant>1712000</constant>,
+                       <constant>5000000</constant>,
+                       <constant>6000000</constant>,
+                       <constant>7000000</constant>,
+                       <constant>8000000</constant>,
+                       <constant>10000000</constant>.
+               </para>
+
+               <para>Notes:</para>
+
+               <para>1) For ISDB-T it should be always 6000000Hz (6MHz)</para>
+               <para>2) For ISDB-Tsb it can vary depending on the number of connected segments</para>
+               <para>3) Bandwidth doesn't apply for DVB-C transmissions, as the bandwidth
+                        for DVB-C depends on the symbol rate</para>
+               <para>4) Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
+                       other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
+                       DTV_ISDBT_SB_SEGMENT_COUNT).</para>
+               <para>5) DVB-T supports 6, 7 and 8MHz.</para>
+               <para>6) In addition, DVB-T2 supports 1.172, 5 and 10MHz.</para>
+       </section>
+       <section id="DTV-INVERSION">
+       <title><constant>DTV_INVERSION</constant></title>
+       <para>The Inversion field can take one of these values:
+       </para>
+       <programlisting>
+       typedef enum fe_spectral_inversion {
+               INVERSION_OFF,
+               INVERSION_ON,
+               INVERSION_AUTO
+       } fe_spectral_inversion_t;
+       </programlisting>
+       <para>It indicates if spectral inversion should be presumed or not. In the automatic setting
+       (<constant>INVERSION_AUTO</constant>) the hardware will try to figure out the correct setting by
+       itself.
+       </para>
+       </section>
+       <section id="DTV-DISEQC-MASTER">
+       <title><constant>DTV_DISEQC_MASTER</constant></title>
+       <para>Currently not implemented.</para>
+       </section>
+       <section id="DTV-SYMBOL-RATE">
+       <title><constant>DTV_SYMBOL_RATE</constant></title>
+       <para>Digital TV symbol rate, in bauds (symbols/second). Used on cable standards.</para>
+       </section>
+       <section id="DTV-INNER-FEC">
+       <title><constant>DTV_INNER_FEC</constant></title>
+       <para>Used cable/satellite transmissions. The acceptable values are:
+       </para>
+       <programlisting>
+typedef enum fe_code_rate {
+       FEC_NONE = 0,
+       FEC_1_2,
+       FEC_2_3,
+       FEC_3_4,
+       FEC_4_5,
+       FEC_5_6,
+       FEC_6_7,
+       FEC_7_8,
+       FEC_8_9,
+       FEC_AUTO,
+       FEC_3_5,
+       FEC_9_10,
+} fe_code_rate_t;
+       </programlisting>
+       <para>which correspond to error correction rates of 1/2, 2/3, etc.,
+       no error correction or auto detection.</para>
+       </section>
+       <section id="DTV-VOLTAGE">
+       <title><constant>DTV_VOLTAGE</constant></title>
+       <para>The voltage is usually used with non-DiSEqC capable LNBs to switch
+       the polarzation (horizontal/vertical). When using DiSEqC epuipment this
+       voltage has to be switched consistently to the DiSEqC commands as
+       described in the DiSEqC spec.</para>
+       <programlisting>
+               typedef enum fe_sec_voltage {
+               SEC_VOLTAGE_13,
+               SEC_VOLTAGE_18
+               } fe_sec_voltage_t;
+       </programlisting>
+       </section>
+       <section id="DTV-TONE">
+       <title><constant>DTV_TONE</constant></title>
+       <para>Currently not used.</para>
+       </section>
+       <section id="DTV-PILOT">
+       <title><constant>DTV_PILOT</constant></title>
+       <para>Sets DVB-S2 pilot</para>
+       <section id="fe-pilot-t">
+               <title>fe_pilot type</title>
+               <programlisting>
+typedef enum fe_pilot {
+       PILOT_ON,
+       PILOT_OFF,
+       PILOT_AUTO,
+} fe_pilot_t;
+               </programlisting>
+               </section>
+       </section>
+       <section id="DTV-ROLLOFF">
+       <title><constant>DTV_ROLLOFF</constant></title>
+               <para>Sets DVB-S2 rolloff</para>
+
+       <section id="fe-rolloff-t">
+               <title>fe_rolloff type</title>
+               <programlisting>
+typedef enum fe_rolloff {
+       ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */
+       ROLLOFF_20,
+       ROLLOFF_25,
+       ROLLOFF_AUTO,
+} fe_rolloff_t;
+               </programlisting>
+               </section>
+       </section>
+       <section id="DTV-DISEQC-SLAVE-REPLY">
+       <title><constant>DTV_DISEQC_SLAVE_REPLY</constant></title>
+       <para>Currently not implemented.</para>
+       </section>
+       <section id="DTV-FE-CAPABILITY-COUNT">
+       <title><constant>DTV_FE_CAPABILITY_COUNT</constant></title>
+       <para>Currently not implemented.</para>
+       </section>
+       <section id="DTV-FE-CAPABILITY">
+       <title><constant>DTV_FE_CAPABILITY</constant></title>
+       <para>Currently not implemented.</para>
+       </section>
+       <section id="DTV-DELIVERY-SYSTEM">
+               <title><constant>DTV_DELIVERY_SYSTEM</constant></title>
+               <para>Specifies the type of Delivery system</para>
+               <section id="fe-delivery-system-t">
+               <title>fe_delivery_system type</title>
+               <para>Possible values: </para>
+<programlisting>
+typedef enum fe_delivery_system {
+       SYS_UNDEFINED,
+       SYS_DVBC_ANNEX_AC,
+       SYS_DVBC_ANNEX_B,
+       SYS_DVBT,
+       SYS_DSS,
+       SYS_DVBS,
+       SYS_DVBS2,
+       SYS_DVBH,
+       SYS_ISDBT,
+       SYS_ISDBS,
+       SYS_ISDBC,
+       SYS_ATSC,
+       SYS_ATSCMH,
+       SYS_DMBTH,
+       SYS_CMMB,
+       SYS_DAB,
+       SYS_DVBT2,
+} fe_delivery_system_t;
+</programlisting>
+               </section>
+       </section>
+       <section id="DTV-ISDBT-PARTIAL-RECEPTION">
+               <title><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></title>
+
+               <para>If <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '0' this bit-field represents whether
+                       the channel is in partial reception mode or not.</para>
+
+               <para>If '1' <constant>DTV_ISDBT_LAYERA_*</constant> values are assigned to the center segment and
+                       <constant>DTV_ISDBT_LAYERA_SEGMENT_COUNT</constant> has to be '1'.</para>
+
+               <para>If in addition <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'
+                       <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> represents whether this ISDB-Tsb channel
+                       is consisting of one segment and layer or three segments and two layers.</para>
+
+               <para>Possible values: 0, 1, -1 (AUTO)</para>
+       </section>
+       <section id="DTV-ISDBT-SOUND-BROADCASTING">
+               <title><constant>DTV_ISDBT_SOUND_BROADCASTING</constant></title>
+
+               <para>This field represents whether the other DTV_ISDBT_*-parameters are
+                       referring to an ISDB-T and an ISDB-Tsb channel. (See also
+                       <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>).</para>
+
+               <para>Possible values: 0, 1, -1 (AUTO)</para>
+       </section>
+       <section id="DTV-ISDBT-SB-SUBCHANNEL-ID">
+               <title><constant>DTV_ISDBT_SB_SUBCHANNEL_ID</constant></title>
+
+               <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
+
+               <para>(Note of the author: This might not be the correct description of the
+                       <constant>SUBCHANNEL-ID</constant> in all details, but it is my understanding of the technical
+                       background needed to program a device)</para>
+
+               <para>An ISDB-Tsb channel (1 or 3 segments) can be broadcasted alone or in a
+                       set of connected ISDB-Tsb channels. In this set of channels every
+                       channel can be received independently. The number of connected
+                       ISDB-Tsb segment can vary, e.g. depending on the frequency spectrum
+                       bandwidth available.</para>
+
+               <para>Example: Assume 8 ISDB-Tsb connected segments are broadcasted. The
+                       broadcaster has several possibilities to put those channels in the
+                       air: Assuming a normal 13-segment ISDB-T spectrum he can align the 8
+                       segments from position 1-8 to 5-13 or anything in between.</para>
+
+               <para>The underlying layer of segments are subchannels: each segment is
+                       consisting of several subchannels with a predefined IDs. A sub-channel
+                       is used to help the demodulator to synchronize on the channel.</para>
+
+               <para>An ISDB-T channel is always centered over all sub-channels. As for
+                       the example above, in ISDB-Tsb it is no longer as simple as that.</para>
+
+               <para><constant>The DTV_ISDBT_SB_SUBCHANNEL_ID</constant> parameter is used to give the
+                       sub-channel ID of the segment to be demodulated.</para>
+
+               <para>Possible values: 0 .. 41, -1 (AUTO)</para>
+       </section>
+       <section id="DTV-ISDBT-SB-SEGMENT-IDX">
+               <title><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant></title>
+               <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
+               <para><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant> gives the index of the segment to be
+                       demodulated for an ISDB-Tsb channel where several of them are
+                       transmitted in the connected manner.</para>
+               <para>Possible values: 0 .. <constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> - 1</para>
+               <para>Note: This value cannot be determined by an automatic channel search.</para>
+       </section>
+       <section id="DTV-ISDBT-SB-SEGMENT-COUNT">
+               <title><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant></title>
+               <para>This field only applies if <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> is '1'.</para>
+               <para><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant> gives the total count of connected ISDB-Tsb
+                       channels.</para>
+               <para>Possible values: 1 .. 13</para>
+               <para>Note: This value cannot be determined by an automatic channel search.</para>
+       </section>
+       <section id="isdb-hierq-layers">
+               <title><constant>DTV-ISDBT-LAYER*</constant> parameters</title>
+               <para>ISDB-T channels can be coded hierarchically. As opposed to DVB-T in
+                       ISDB-T hierarchical layers can be decoded simultaneously. For that
+                       reason a ISDB-T demodulator has 3 viterbi and 3 reed-solomon-decoders.</para>
+               <para>ISDB-T has 3 hierarchical layers which each can use a part of the
+                       available segments. The total number of segments over all layers has
+                       to 13 in ISDB-T.</para>
+               <para>There are 3 parameter sets, for Layers A, B and C.</para>
+               <section id="DTV-ISDBT-LAYER-ENABLED">
+                       <title><constant>DTV_ISDBT_LAYER_ENABLED</constant></title>
+                       <para>Hierarchical reception in ISDB-T is achieved by enabling or disabling
+                               layers in the decoding process. Setting all bits of
+                               <constant>DTV_ISDBT_LAYER_ENABLED</constant> to '1' forces all layers (if applicable) to be
+                               demodulated. This is the default.</para>
+                       <para>If the channel is in the partial reception mode
+                               (<constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> = 1) the central segment can be decoded
+                               independently of the other 12 segments. In that mode layer A has to
+                               have a <constant>SEGMENT_COUNT</constant> of 1.</para>
+                       <para>In ISDB-Tsb only layer A is used, it can be 1 or 3 in ISDB-Tsb
+                               according to <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>. <constant>SEGMENT_COUNT</constant> must be filled
+                               accordingly.</para>
+                       <para>Possible values: 0x1, 0x2, 0x4 (|-able)</para>
+                       <para><constant>DTV_ISDBT_LAYER_ENABLED[0:0]</constant> - layer A</para>
+                       <para><constant>DTV_ISDBT_LAYER_ENABLED[1:1]</constant> - layer B</para>
+                       <para><constant>DTV_ISDBT_LAYER_ENABLED[2:2]</constant> - layer C</para>
+                       <para><constant>DTV_ISDBT_LAYER_ENABLED[31:3]</constant> unused</para>
+               </section>
+               <section id="DTV-ISDBT-LAYER-FEC">
+                       <title><constant>DTV_ISDBT_LAYER*_FEC</constant></title>
+                       <para>Possible values: <constant>FEC_AUTO</constant>, <constant>FEC_1_2</constant>, <constant>FEC_2_3</constant>, <constant>FEC_3_4</constant>, <constant>FEC_5_6</constant>, <constant>FEC_7_8</constant></para>
+               </section>
+               <section id="DTV-ISDBT-LAYER-MODULATION">
+                       <title><constant>DTV_ISDBT_LAYER*_MODULATION</constant></title>
+                       <para>Possible values: <constant>QAM_AUTO</constant>, QP<constant>SK, QAM_16</constant>, <constant>QAM_64</constant>, <constant>DQPSK</constant></para>
+                       <para>Note: If layer C is <constant>DQPSK</constant> layer B has to be <constant>DQPSK</constant>. If layer B is <constant>DQPSK</constant>
+                               and <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant>=0 layer has to be <constant>DQPSK</constant>.</para>
+               </section>
+               <section id="DTV-ISDBT-LAYER-SEGMENT-COUNT">
+                       <title><constant>DTV_ISDBT_LAYER*_SEGMENT_COUNT</constant></title>
+                       <para>Possible values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1 (AUTO)</para>
+                       <para>Note: Truth table for <constant>DTV_ISDBT_SOUND_BROADCASTING</constant> and
+                               <constant>DTV_ISDBT_PARTIAL_RECEPTION</constant> and <constant>LAYER</constant>*_SEGMENT_COUNT</para>
+                       <informaltable id="isdbt-layer_seg-cnt-table">
+                               <tgroup cols="6">
+                                       <tbody>
+                                               <row>
+                                                       <entry>PR</entry>
+                                                       <entry>SB</entry>
+                                                       <entry>Layer A width</entry>
+                                                       <entry>Layer B width</entry>
+                                                       <entry>Layer C width</entry>
+                                                       <entry>total width</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>0</entry>
+                                                       <entry>0</entry>
+                                                       <entry>1 .. 13</entry>
+                                                       <entry>1 .. 13</entry>
+                                                       <entry>1 .. 13</entry>
+                                                       <entry>13</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>1</entry>
+                                                       <entry>0</entry>
+                                                       <entry>1</entry>
+                                                       <entry>1 .. 13</entry>
+                                                       <entry>1 .. 13</entry>
+                                                       <entry>13</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>0</entry>
+                                                       <entry>1</entry>
+                                                       <entry>1</entry>
+                                                       <entry>0</entry>
+                                                       <entry>0</entry>
+                                                       <entry>1</entry>
+                                               </row>
+                                               <row>
+                                                       <entry>1</entry>
+                                                       <entry>1</entry>
+                                                       <entry>1</entry>
+                                                       <entry>2</entry>
+                                                       <entry>0</entry>
+                                                       <entry>13</entry>
+                                               </row>
+                                       </tbody>
+                               </tgroup>
+                       </informaltable>
+               </section>
+               <section id="DTV-ISDBT-LAYER-TIME-INTERLEAVING">
+                       <title><constant>DTV_ISDBT_LAYER*_TIME_INTERLEAVING</constant></title>
+                       <para>Possible values: 0, 1, 2, 3, -1 (AUTO)</para>
+                       <para>Note: The real inter-leaver depth-names depend on the mode (fft-size); the values
+                               here are referring to what can be found in the TMCC-structure -
+                               independent of the mode.</para>
+               </section>
+       </section>
+       <section id="DTV-API-VERSION">
+       <title><constant>DTV_API_VERSION</constant></title>
+       <para>Returns the major/minor version of the DVB API</para>
+       </section>
+       <section id="DTV-CODE-RATE-HP">
+       <title><constant>DTV_CODE_RATE_HP</constant></title>
+       <para>Used on terrestrial transmissions. The acceptable values are:
+       </para>
+       <programlisting>
+typedef enum fe_code_rate {
+       FEC_NONE = 0,
+       FEC_1_2,
+       FEC_2_3,
+       FEC_3_4,
+       FEC_4_5,
+       FEC_5_6,
+       FEC_6_7,
+       FEC_7_8,
+       FEC_8_9,
+       FEC_AUTO,
+       FEC_3_5,
+       FEC_9_10,
+} fe_code_rate_t;
+       </programlisting>
+       </section>
+       <section id="DTV-CODE-RATE-LP">
+       <title><constant>DTV_CODE_RATE_LP</constant></title>
+       <para>Used on terrestrial transmissions. The acceptable values are:
+       </para>
+       <programlisting>
+typedef enum fe_code_rate {
+       FEC_NONE = 0,
+       FEC_1_2,
+       FEC_2_3,
+       FEC_3_4,
+       FEC_4_5,
+       FEC_5_6,
+       FEC_6_7,
+       FEC_7_8,
+       FEC_8_9,
+       FEC_AUTO,
+       FEC_3_5,
+       FEC_9_10,
+} fe_code_rate_t;
+       </programlisting>
+       </section>
+       <section id="DTV-GUARD-INTERVAL">
+               <title><constant>DTV_GUARD_INTERVAL</constant></title>
+
+               <para>Possible values are:</para>
+<programlisting>
+typedef enum fe_guard_interval {
+       GUARD_INTERVAL_1_32,
+       GUARD_INTERVAL_1_16,
+       GUARD_INTERVAL_1_8,
+       GUARD_INTERVAL_1_4,
+       GUARD_INTERVAL_AUTO,
+       GUARD_INTERVAL_1_128,
+       GUARD_INTERVAL_19_128,
+       GUARD_INTERVAL_19_256,
+} fe_guard_interval_t;
+</programlisting>
+
+               <para>Notes:</para>
+               <para>1) If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
+                       try to find the correct guard interval (if capable) and will use TMCC to fill
+                       in the missing parameters.</para>
+               <para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
+       </section>
+       <section id="DTV-TRANSMISSION-MODE">
+               <title><constant>DTV_TRANSMISSION_MODE</constant></title>
+
+               <para>Specifies the number of carriers used by the standard</para>
+
+               <para>Possible values are:</para>
+<programlisting>
+typedef enum fe_transmit_mode {
+       TRANSMISSION_MODE_2K,
+       TRANSMISSION_MODE_8K,
+       TRANSMISSION_MODE_AUTO,
+       TRANSMISSION_MODE_4K,
+       TRANSMISSION_MODE_1K,
+       TRANSMISSION_MODE_16K,
+       TRANSMISSION_MODE_32K,
+} fe_transmit_mode_t;
+</programlisting>
+               <para>Notes:</para>
+               <para>1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
+                       'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
+
+               <para>2) If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
+                       hardware will try to find the correct FFT-size (if capable) and will
+                       use TMCC to fill in the missing parameters.</para>
+               <para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
+               <para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
+       </section>
+       <section id="DTV-HIERARCHY">
+       <title><constant>DTV_HIERARCHY</constant></title>
+       <para>Frontend hierarchy</para>
+       <programlisting>
+typedef enum fe_hierarchy {
+        HIERARCHY_NONE,
+        HIERARCHY_1,
+        HIERARCHY_2,
+        HIERARCHY_4,
+        HIERARCHY_AUTO
+ } fe_hierarchy_t;
+       </programlisting>
+       </section>
+       <section id="DTV-ISDBS-TS-ID">
+       <title><constant>DTV_ISDBS_TS_ID</constant></title>
+       <para>Currently unused.</para>
+       </section>
+       <section id="DTV-DVBT2-PLP-ID">
+               <title><constant>DTV_DVBT2_PLP_ID</constant></title>
+               <para>DVB-T2 supports Physical Layer Pipes (PLP) to allow transmission of
+                       many data types via a single multiplex. The API will soon support this
+                       at which point this section will be expanded.</para>
+       </section>
+</section>
+       <section id="frontend-property-terrestrial-systems">
+       <title>Properties used on terrestrial delivery systems</title>
+               <section id="dvbt-params">
+                       <title>DVB-T delivery system</title>
+                       <para>The following parameters are valid for DVB-T:</para>
+                       <itemizedlist mark='opencircle'>
+                               <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-CODE-RATE-HP"><constant>DTV_CODE_RATE_HP</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-CODE-RATE-LP"><constant>DTV_CODE_RATE_LP</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem>
+                       </itemizedlist>
+               </section>
+               <section id="dvbt2-params">
+                       <title>DVB-T2 delivery system</title>
+                       <para>DVB-T2 support is currently in the early stages
+                       of development, so expect that this section maygrow and become
+                       more detailed with time.</para>
+               <para>The following parameters are valid for DVB-T2:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CODE-RATE-HP"><constant>DTV_CODE_RATE_HP</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CODE-RATE-LP"><constant>DTV_CODE_RATE_LP</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DVBT2-PLP-ID"><constant>DTV_DVBT2_PLP_ID</constant></link></para></listitem>
+               </itemizedlist>
+               </section>
+               <section id="isdbt">
+               <title>ISDB-T delivery system</title>
+               <para>This ISDB-T/ISDB-Tsb API extension should reflect all information
+                       needed to tune any ISDB-T/ISDB-Tsb hardware. Of course it is possible
+                       that some very sophisticated devices won't need certain parameters to
+                       tune.</para>
+               <para>The information given here should help application writers to know how
+                       to handle ISDB-T and ISDB-Tsb hardware using the Linux DVB-API.</para>
+               <para>The details given here about ISDB-T and ISDB-Tsb are just enough to
+                       basically show the dependencies between the needed parameter values,
+                       but surely some information is left out. For more detailed information
+                       see the following documents:</para>
+               <para>ARIB STD-B31 - "Transmission System for Digital Terrestrial
+                       Television Broadcasting" and</para>
+               <para>ARIB TR-B14 - "Operational Guidelines for Digital Terrestrial
+                       Television Broadcasting".</para>
+               <para>In order to understand the ISDB specific parameters,
+                       one has to have some knowledge the channel structure in
+                       ISDB-T and ISDB-Tsb. I.e. it has to be known to
+                       the reader that an ISDB-T channel consists of 13 segments,
+                       that it can have up to 3 layer sharing those segments,
+                       and things like that.</para>
+               <para>The following parameters are valid for ISDB-T:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CODE-RATE-HP"><constant>DTV_CODE_RATE_HP</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CODE-RATE-LP"><constant>DTV_CODE_RATE_LP</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-GUARD-INTERVAL"><constant>DTV_GUARD_INTERVAL</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TRANSMISSION-MODE"><constant>DTV_TRANSMISSION_MODE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-HIERARCHY"><constant>DTV_HIERARCHY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-ENABLED"><constant>DTV_ISDBT_LAYER_ENABLED</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-PARTIAL-RECEPTION"><constant>DTV_ISDBT_PARTIAL_RECEPTION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-SOUND-BROADCASTING"><constant>DTV_ISDBT_SOUND_BROADCASTING</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-SB-SUBCHANNEL-ID"><constant>DTV_ISDBT_SB_SUBCHANNEL_ID</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-SB-SEGMENT-IDX"><constant>DTV_ISDBT_SB_SEGMENT_IDX</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-SB-SEGMENT-COUNT"><constant>DTV_ISDBT_SB_SEGMENT_COUNT</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-FEC"><constant>DTV_ISDBT_LAYERA_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-MODULATION"><constant>DTV_ISDBT_LAYERA_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-SEGMENT-COUNT"><constant>DTV_ISDBT_LAYERA_SEGMENT_COUNT</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-TIME-INTERLEAVING"><constant>DTV_ISDBT_LAYERA_TIME_INTERLEAVING</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-FEC"><constant>DTV_ISDBT_LAYERB_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-MODULATION"><constant>DTV_ISDBT_LAYERB_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-SEGMENT-COUNT"><constant>DTV_ISDBT_LAYERB_SEGMENT_COUNT</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-TIME-INTERLEAVING"><constant>DTV_ISDBT_LAYERB_TIME_INTERLEAVING</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-FEC"><constant>DTV_ISDBT_LAYERC_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-MODULATION"><constant>DTV_ISDBT_LAYERC_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-SEGMENT-COUNT"><constant>DTV_ISDBT_LAYERC_SEGMENT_COUNT</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBT-LAYER-TIME-INTERLEAVING"><constant>DTV_ISDBT_LAYERC_TIME_INTERLEAVING</constant></link></para></listitem>
+               </itemizedlist>
+               </section>
+               <section id="atsc-params">
+                       <title>ATSC delivery system</title>
+                       <para>The following parameters are valid for ATSC:</para>
+                       <itemizedlist mark='opencircle'>
+                               <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+                       </itemizedlist>
+               </section>
+       </section>
+       <section id="frontend-property-cable-systems">
+       <title>Properties used on cable delivery systems</title>
+       <section id="dvbc-params">
+               <title>DVB-C delivery system</title>
+               <para>The DVB-C Annex-A/C is the widely used cable standard. Transmission uses QAM modulation.</para>
+               <para>The following parameters are valid for DVB-C Annex A/C:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+               </itemizedlist>
+       </section>
+       <section id="dvbc-annex-b-params">
+               <title>DVB-C Annex B delivery system</title>
+               <para>The DVB-C Annex-B is only used on a few Countries like the United States.</para>
+               <para>The following parameters are valid for DVB-C Annex B:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-MODULATION"><constant>DTV_MODULATION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+               </itemizedlist>
+       </section>
+       </section>
+       <section id="frontend-property-satellital-systems">
+       <title>Properties used on satellital delivery systems</title>
+       <section id="dvbs-params">
+               <title>DVB-S delivery system</title>
+               <para>The following parameters are valid for DVB-S:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+               </itemizedlist>
+               <para>Future implementations might add those two missing parameters:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-DISEQC-MASTER"><constant>DTV_DISEQC_MASTER</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DISEQC-SLAVE-REPLY"><constant>DTV_DISEQC_SLAVE_REPLY</constant></link></para></listitem>
+               </itemizedlist>
+       </section>
+       <section id="dvbs2-params">
+               <title>DVB-S2 delivery system</title>
+               <para>The following parameters are valid for DVB-S2:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TONE"><constant>DTV_TONE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-PILOT"><constant>DTV_PILOT</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ROLLOFF"><constant>DTV_ROLLOFF</constant></link></para></listitem>
+               </itemizedlist>
+               <para>Future implementations might add those two missing parameters:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-DISEQC-MASTER"><constant>DTV_DISEQC_MASTER</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DISEQC-SLAVE-REPLY"><constant>DTV_DISEQC_SLAVE_REPLY</constant></link></para></listitem>
+               </itemizedlist>
+       </section>
+       <section id="isdbs-params">
+               <title>ISDB-S delivery system</title>
+               <para>The following parameters are valid for ISDB-S:</para>
+               <itemizedlist mark='opencircle'>
+                       <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INVERSION"><constant>DTV_INVERSION</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-SYMBOL-RATE"><constant>DTV_SYMBOL_RATE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-INNER-FEC"><constant>DTV_INNER_FEC</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-VOLTAGE"><constant>DTV_VOLTAGE</constant></link></para></listitem>
+                       <listitem><para><link linkend="DTV-ISDBS-TS-ID"><constant>DTV_ISDBS_TS_ID</constant></link></para></listitem>
+               </itemizedlist>
+       </section>
+       </section>
+</section>
diff --git a/Documentation/DocBook/media/dvb/dvbstb.pdf b/Documentation/DocBook/media/dvb/dvbstb.pdf
new file mode 100644 (file)
index 0000000..0fa75d9
Binary files /dev/null and b/Documentation/DocBook/media/dvb/dvbstb.pdf differ
diff --git a/Documentation/DocBook/media/dvb/examples.xml b/Documentation/DocBook/media/dvb/examples.xml
new file mode 100644 (file)
index 0000000..f037e56
--- /dev/null
@@ -0,0 +1,365 @@
+<title>Examples</title>
+<para>In this section we would like to present some examples for using the DVB API.
+</para>
+<para>Maintainer note: This section is out of date. Please refer to the sample programs packaged
+with the driver distribution from <ulink url="http://linuxtv.org/hg/dvb-apps" />.
+</para>
+
+<section id="tuning">
+<title>Tuning</title>
+<para>We will start with a generic tuning subroutine that uses the frontend and SEC, as well as
+the demux devices. The example is given for QPSK tuners, but can easily be adjusted for
+QAM.
+</para>
+<programlisting>
+ #include &#x003C;sys/ioctl.h&#x003E;
+ #include &#x003C;stdio.h&#x003E;
+ #include &#x003C;stdint.h&#x003E;
+ #include &#x003C;sys/types.h&#x003E;
+ #include &#x003C;sys/stat.h&#x003E;
+ #include &#x003C;fcntl.h&#x003E;
+ #include &#x003C;time.h&#x003E;
+ #include &#x003C;unistd.h&#x003E;
+
+ #include &#x003C;linux/dvb/dmx.h&#x003E;
+ #include &#x003C;linux/dvb/frontend.h&#x003E;
+ #include &#x003C;linux/dvb/sec.h&#x003E;
+ #include &#x003C;sys/poll.h&#x003E;
+
+ #define DMX "/dev/dvb/adapter0/demux1"
+ #define FRONT "/dev/dvb/adapter0/frontend1"
+ #define SEC "/dev/dvb/adapter0/sec1"
+
+ /&#x22C6; routine for checking if we have a signal and other status information&#x22C6;/
+ int FEReadStatus(int fd, fe_status_t &#x22C6;stat)
+ {
+        int ans;
+
+        if ( (ans = ioctl(fd,FE_READ_STATUS,stat) &#x003C; 0)){
+                perror("FE READ STATUS: ");
+                return -1;
+        }
+
+        if (&#x22C6;stat &amp; FE_HAS_POWER)
+                printf("FE HAS POWER\n");
+
+        if (&#x22C6;stat &amp; FE_HAS_SIGNAL)
+                printf("FE HAS SIGNAL\n");
+
+        if (&#x22C6;stat &amp; FE_SPECTRUM_INV)
+                printf("SPEKTRUM INV\n");
+
+        return 0;
+ }
+
+
+ /&#x22C6; tune qpsk &#x22C6;/
+ /&#x22C6; freq:             frequency of transponder                      &#x22C6;/
+ /&#x22C6; vpid, apid, tpid: PIDs of video, audio and teletext TS packets  &#x22C6;/
+ /&#x22C6; diseqc:           DiSEqC address of the used LNB                &#x22C6;/
+ /&#x22C6; pol:              Polarisation                                  &#x22C6;/
+ /&#x22C6; srate:            Symbol Rate                                   &#x22C6;/
+ /&#x22C6; fec.              FEC                                           &#x22C6;/
+ /&#x22C6; lnb_lof1:         local frequency of lower LNB band             &#x22C6;/
+ /&#x22C6; lnb_lof2:         local frequency of upper LNB band             &#x22C6;/
+ /&#x22C6; lnb_slof:         switch frequency of LNB                       &#x22C6;/
+
+ int set_qpsk_channel(int freq, int vpid, int apid, int tpid,
+                int diseqc, int pol, int srate, int fec, int lnb_lof1,
+                int lnb_lof2, int lnb_slof)
+ {
+        struct secCommand scmd;
+        struct secCmdSequence scmds;
+        struct dmx_pes_filter_params pesFilterParams;
+        FrontendParameters frp;
+        struct pollfd pfd[1];
+        FrontendEvent event;
+        int demux1, demux2, demux3, front;
+
+        frequency = (uint32_t) freq;
+        symbolrate = (uint32_t) srate;
+
+        if((front = open(FRONT,O_RDWR)) &#x003C; 0){
+                perror("FRONTEND DEVICE: ");
+                return -1;
+        }
+
+        if((sec = open(SEC,O_RDWR)) &#x003C; 0){
+                perror("SEC DEVICE: ");
+                return -1;
+        }
+
+        if (demux1 &#x003C; 0){
+                if ((demux1=open(DMX, O_RDWR|O_NONBLOCK))
+                    &#x003C; 0){
+                        perror("DEMUX DEVICE: ");
+                        return -1;
+                }
+        }
+
+        if (demux2 &#x003C; 0){
+                if ((demux2=open(DMX, O_RDWR|O_NONBLOCK))
+                    &#x003C; 0){
+                        perror("DEMUX DEVICE: ");
+                        return -1;
+                }
+        }
+
+        if (demux3 &#x003C; 0){
+                if ((demux3=open(DMX, O_RDWR|O_NONBLOCK))
+                    &#x003C; 0){
+                        perror("DEMUX DEVICE: ");
+                        return -1;
+                }
+        }
+
+        if (freq &#x003C; lnb_slof) {
+                frp.Frequency = (freq - lnb_lof1);
+                scmds.continuousTone = SEC_TONE_OFF;
+        } else {
+                frp.Frequency = (freq - lnb_lof2);
+                scmds.continuousTone = SEC_TONE_ON;
+        }
+        frp.Inversion = INVERSION_AUTO;
+        if (pol) scmds.voltage = SEC_VOLTAGE_18;
+        else scmds.voltage = SEC_VOLTAGE_13;
+
+        scmd.type=0;
+        scmd.u.diseqc.addr=0x10;
+        scmd.u.diseqc.cmd=0x38;
+        scmd.u.diseqc.numParams=1;
+        scmd.u.diseqc.params[0] = 0xF0 | ((diseqc &#x22C6; 4) &amp; 0x0F) |
+                (scmds.continuousTone == SEC_TONE_ON ? 1 : 0) |
+                (scmds.voltage==SEC_VOLTAGE_18 ? 2 : 0);
+
+        scmds.miniCommand=SEC_MINI_NONE;
+        scmds.numCommands=1;
+        scmds.commands=&amp;scmd;
+        if (ioctl(sec, SEC_SEND_SEQUENCE, &amp;scmds) &#x003C; 0){
+                perror("SEC SEND: ");
+                return -1;
+        }
+
+        if (ioctl(sec, SEC_SEND_SEQUENCE, &amp;scmds) &#x003C; 0){
+                perror("SEC SEND: ");
+                return -1;
+        }
+
+        frp.u.qpsk.SymbolRate = srate;
+        frp.u.qpsk.FEC_inner = fec;
+
+        if (ioctl(front, FE_SET_FRONTEND, &amp;frp) &#x003C; 0){
+                perror("QPSK TUNE: ");
+                return -1;
+        }
+
+        pfd[0].fd = front;
+        pfd[0].events = POLLIN;
+
+        if (poll(pfd,1,3000)){
+                if (pfd[0].revents &amp; POLLIN){
+                        printf("Getting QPSK event\n");
+                        if ( ioctl(front, FE_GET_EVENT, &amp;event)
+
+                             == -EOVERFLOW){
+                                perror("qpsk get event");
+                                return -1;
+                        }
+                        printf("Received ");
+                        switch(event.type){
+                        case FE_UNEXPECTED_EV:
+                                printf("unexpected event\n");
+                                return -1;
+                        case FE_FAILURE_EV:
+                                printf("failure event\n");
+                                return -1;
+
+                        case FE_COMPLETION_EV:
+                                printf("completion event\n");
+                        }
+                }
+        }
+
+
+        pesFilterParams.pid     = vpid;
+        pesFilterParams.input   = DMX_IN_FRONTEND;
+        pesFilterParams.output  = DMX_OUT_DECODER;
+        pesFilterParams.pes_type = DMX_PES_VIDEO;
+        pesFilterParams.flags   = DMX_IMMEDIATE_START;
+        if (ioctl(demux1, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
+                perror("set_vpid");
+                return -1;
+        }
+
+        pesFilterParams.pid     = apid;
+        pesFilterParams.input   = DMX_IN_FRONTEND;
+        pesFilterParams.output  = DMX_OUT_DECODER;
+        pesFilterParams.pes_type = DMX_PES_AUDIO;
+        pesFilterParams.flags   = DMX_IMMEDIATE_START;
+        if (ioctl(demux2, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
+                perror("set_apid");
+                return -1;
+        }
+
+        pesFilterParams.pid     = tpid;
+        pesFilterParams.input   = DMX_IN_FRONTEND;
+        pesFilterParams.output  = DMX_OUT_DECODER;
+        pesFilterParams.pes_type = DMX_PES_TELETEXT;
+        pesFilterParams.flags   = DMX_IMMEDIATE_START;
+        if (ioctl(demux3, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
+                perror("set_tpid");
+                return -1;
+        }
+
+        return has_signal(fds);
+ }
+
+</programlisting>
+<para>The program assumes that you are using a universal LNB and a standard DiSEqC
+switch with up to 4 addresses. Of course, you could build in some more checking if
+tuning was successful and maybe try to repeat the tuning process. Depending on the
+external hardware, i.e. LNB and DiSEqC switch, and weather conditions this may be
+necessary.
+</para>
+</section>
+
+<section id="the_dvr_device">
+<title>The DVR device</title>
+<para>The following program code shows how to use the DVR device for recording.
+</para>
+<programlisting>
+ #include &#x003C;sys/ioctl.h&#x003E;
+ #include &#x003C;stdio.h&#x003E;
+ #include &#x003C;stdint.h&#x003E;
+ #include &#x003C;sys/types.h&#x003E;
+ #include &#x003C;sys/stat.h&#x003E;
+ #include &#x003C;fcntl.h&#x003E;
+ #include &#x003C;time.h&#x003E;
+ #include &#x003C;unistd.h&#x003E;
+
+ #include &#x003C;linux/dvb/dmx.h&#x003E;
+ #include &#x003C;linux/dvb/video.h&#x003E;
+ #include &#x003C;sys/poll.h&#x003E;
+ #define DVR "/dev/dvb/adapter0/dvr1"
+ #define AUDIO "/dev/dvb/adapter0/audio1"
+ #define VIDEO "/dev/dvb/adapter0/video1"
+
+ #define BUFFY (188&#x22C6;20)
+ #define MAX_LENGTH (1024&#x22C6;1024&#x22C6;5) /&#x22C6; record 5MB &#x22C6;/
+
+
+ /&#x22C6; switch the demuxes to recording, assuming the transponder is tuned &#x22C6;/
+
+ /&#x22C6; demux1, demux2: file descriptor of video and audio filters &#x22C6;/
+ /&#x22C6; vpid, apid:     PIDs of video and audio channels           &#x22C6;/
+
+ int switch_to_record(int demux1, int demux2, uint16_t vpid, uint16_t apid)
+ {
+        struct dmx_pes_filter_params pesFilterParams;
+
+        if (demux1 &#x003C; 0){
+                if ((demux1=open(DMX, O_RDWR|O_NONBLOCK))
+                    &#x003C; 0){
+                        perror("DEMUX DEVICE: ");
+                        return -1;
+                }
+        }
+
+        if (demux2 &#x003C; 0){
+                if ((demux2=open(DMX, O_RDWR|O_NONBLOCK))
+                    &#x003C; 0){
+                        perror("DEMUX DEVICE: ");
+                        return -1;
+                }
+        }
+
+        pesFilterParams.pid = vpid;
+        pesFilterParams.input = DMX_IN_FRONTEND;
+        pesFilterParams.output = DMX_OUT_TS_TAP;
+        pesFilterParams.pes_type = DMX_PES_VIDEO;
+        pesFilterParams.flags = DMX_IMMEDIATE_START;
+        if (ioctl(demux1, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
+                perror("DEMUX DEVICE");
+                return -1;
+        }
+        pesFilterParams.pid = apid;
+        pesFilterParams.input = DMX_IN_FRONTEND;
+        pesFilterParams.output = DMX_OUT_TS_TAP;
+        pesFilterParams.pes_type = DMX_PES_AUDIO;
+        pesFilterParams.flags = DMX_IMMEDIATE_START;
+        if (ioctl(demux2, DMX_SET_PES_FILTER, &amp;pesFilterParams) &#x003C; 0){
+                perror("DEMUX DEVICE");
+                return -1;
+        }
+        return 0;
+ }
+
+ /&#x22C6; start recording MAX_LENGTH , assuming the transponder is tuned &#x22C6;/
+
+ /&#x22C6; demux1, demux2: file descriptor of video and audio filters &#x22C6;/
+ /&#x22C6; vpid, apid:     PIDs of video and audio channels           &#x22C6;/
+ int record_dvr(int demux1, int demux2, uint16_t vpid, uint16_t apid)
+ {
+        int i;
+        int len;
+        int written;
+        uint8_t buf[BUFFY];
+        uint64_t length;
+        struct pollfd pfd[1];
+        int dvr, dvr_out;
+
+        /&#x22C6; open dvr device &#x22C6;/
+        if ((dvr = open(DVR, O_RDONLY|O_NONBLOCK)) &#x003C; 0){
+                        perror("DVR DEVICE");
+                        return -1;
+        }
+
+        /&#x22C6; switch video and audio demuxes to dvr &#x22C6;/
+        printf ("Switching dvr on\n");
+        i = switch_to_record(demux1, demux2, vpid, apid);
+        printf("finished: ");
+
+        printf("Recording %2.0f MB of test file in TS format\n",
+               MAX_LENGTH/(1024.0&#x22C6;1024.0));
+        length = 0;
+
+        /&#x22C6; open output file &#x22C6;/
+        if ((dvr_out = open(DVR_FILE,O_WRONLY|O_CREAT
+                                 |O_TRUNC, S_IRUSR|S_IWUSR
+                                 |S_IRGRP|S_IWGRP|S_IROTH|
+                                 S_IWOTH)) &#x003C; 0){
+                perror("Can't open file for dvr test");
+                return -1;
+        }
+
+        pfd[0].fd = dvr;
+        pfd[0].events = POLLIN;
+
+        /&#x22C6; poll for dvr data and write to file &#x22C6;/
+        while (length &#x003C; MAX_LENGTH ) {
+                if (poll(pfd,1,1)){
+                        if (pfd[0].revents &amp; POLLIN){
+                                len = read(dvr, buf, BUFFY);
+                                if (len &#x003C; 0){
+                                        perror("recording");
+                                        return -1;
+                                }
+                                if (len &#x003E; 0){
+                                        written = 0;
+                                        while (written &#x003C; len)
+                                                written +=
+                                                        write (dvr_out,
+                                                               buf, len);
+                                        length += len;
+                                        printf("written %2.0f MB\r",
+                                               length/1024./1024.);
+                                }
+                        }
+                }
+        }
+        return 0;
+ }
+
+</programlisting>
+
+</section>
diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml
new file mode 100644 (file)
index 0000000..61407ea
--- /dev/null
@@ -0,0 +1,1515 @@
+<title>DVB Frontend API</title>
+
+<para>The DVB frontend device controls the tuner and DVB demodulator
+hardware. It can be accessed through <emphasis
+role="tt">/dev/dvb/adapter0/frontend0</emphasis>. Data types and and
+ioctl definitions can be accessed by including <emphasis
+role="tt">linux/dvb/frontend.h</emphasis> in your application.</para>
+
+<para>DVB frontends come in three varieties: DVB-S (satellite), DVB-C
+(cable) and DVB-T (terrestrial). Transmission via the internet (DVB-IP)
+is not yet handled by this API but a future extension is possible. For
+DVB-S the frontend device also supports satellite equipment control
+(SEC) via DiSEqC and V-SEC protocols. The DiSEqC (digital SEC)
+specification is available from
+<ulink url="http://www.eutelsat.com/satellites/4_5_5.html">Eutelsat</ulink>.</para>
+
+<para>Note that the DVB API may also be used for MPEG decoder-only PCI
+cards, in which case there exists no frontend device.</para>
+
+<section id="frontend_types">
+<title>Frontend Data Types</title>
+
+<section id="fe-type-t">
+<title>Frontend type</title>
+
+<para>For historical reasons, frontend types are named by the type of modulation used in
+transmission. The fontend types are given by fe_type_t type, defined as:</para>
+
+<table pgwide="1" frame="none" id="fe-type">
+<title>Frontend types</title>
+<tgroup cols="3">
+   &cs-def;
+   <thead>
+     <row>
+       <entry>fe_type</entry>
+       <entry>Description</entry>
+       <entry><link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> equivalent type</entry>
+     </row>
+  </thead>
+  <tbody valign="top">
+  <row>
+     <entry id="FE_QPSK"><constant>FE_QPSK</constant></entry>
+     <entry>For DVB-S standard</entry>
+     <entry><constant>SYS_DVBS</constant></entry>
+  </row>
+  <row>
+     <entry id="FE_QAM"><constant>FE_QAM</constant></entry>
+     <entry>For DVB-C annex A/C standard</entry>
+     <entry><constant>SYS_DVBC_ANNEX_AC</constant></entry>
+  </row>
+  <row>
+     <entry id="FE_OFDM"><constant>FE_OFDM</constant></entry>
+     <entry>For DVB-T standard</entry>
+     <entry><constant>SYS_DVBT</constant></entry>
+  </row>
+  <row>
+     <entry id="FE_ATSC"><constant>FE_ATSC</constant></entry>
+     <entry>For ATSC standard (terrestrial) or for DVB-C Annex B (cable) used in US.</entry>
+     <entry><constant>SYS_ATSC</constant> (terrestrial) or <constant>SYS_DVBC_ANNEX_B</constant> (cable)</entry>
+  </row>
+</tbody></tgroup></table>
+
+<para>Newer formats like DVB-S2, ISDB-T, ISDB-S and DVB-T2 are not described at the above, as they're
+supported via the new <link linkend="FE_GET_SET_PROPERTY">FE_GET_PROPERTY/FE_GET_SET_PROPERTY</link> ioctl's, using the <link linkend="DTV-DELIVERY-SYSTEM">DTV_DELIVERY_SYSTEM</link> parameter.
+</para>
+</section>
+
+<section id="fe-caps-t">
+<title>frontend capabilities</title>
+
+<para>Capabilities describe what a frontend can do. Some capabilities can only be supported for
+a specific frontend type.</para>
+<programlisting>
+       typedef enum fe_caps {
+       FE_IS_STUPID                  = 0,
+       FE_CAN_INVERSION_AUTO         = 0x1,
+       FE_CAN_FEC_1_2                = 0x2,
+       FE_CAN_FEC_2_3                = 0x4,
+       FE_CAN_FEC_3_4                = 0x8,
+       FE_CAN_FEC_4_5                = 0x10,
+       FE_CAN_FEC_5_6                = 0x20,
+       FE_CAN_FEC_6_7                = 0x40,
+       FE_CAN_FEC_7_8                = 0x80,
+       FE_CAN_FEC_8_9                = 0x100,
+       FE_CAN_FEC_AUTO               = 0x200,
+       FE_CAN_QPSK                   = 0x400,
+       FE_CAN_QAM_16                 = 0x800,
+       FE_CAN_QAM_32                 = 0x1000,
+       FE_CAN_QAM_64                 = 0x2000,
+       FE_CAN_QAM_128                = 0x4000,
+       FE_CAN_QAM_256                = 0x8000,
+       FE_CAN_QAM_AUTO               = 0x10000,
+       FE_CAN_TRANSMISSION_MODE_AUTO = 0x20000,
+       FE_CAN_BANDWIDTH_AUTO         = 0x40000,
+       FE_CAN_GUARD_INTERVAL_AUTO    = 0x80000,
+       FE_CAN_HIERARCHY_AUTO         = 0x100000,
+       FE_CAN_8VSB                   = 0x200000,
+       FE_CAN_16VSB                  = 0x400000,
+       FE_HAS_EXTENDED_CAPS          = 0x800000,
+       FE_CAN_TURBO_FEC              = 0x8000000,
+       FE_CAN_2G_MODULATION          = 0x10000000,
+       FE_NEEDS_BENDING              = 0x20000000,
+       FE_CAN_RECOVER                = 0x40000000,
+       FE_CAN_MUTE_TS                = 0x80000000
+       } fe_caps_t;
+</programlisting>
+</section>
+
+<section id="dvb-frontend-info">
+<title>frontend information</title>
+
+<para>Information about the frontend ca be queried with
+       <link linkend="FE_GET_INFO">FE_GET_INFO</link>.</para>
+
+<programlisting>
+       struct dvb_frontend_info {
+       char       name[128];
+       fe_type_t  type;
+       uint32_t   frequency_min;
+       uint32_t   frequency_max;
+       uint32_t   frequency_stepsize;
+       uint32_t   frequency_tolerance;
+       uint32_t   symbol_rate_min;
+       uint32_t   symbol_rate_max;
+       uint32_t   symbol_rate_tolerance;     /&#x22C6; ppm &#x22C6;/
+       uint32_t   notifier_delay;            /&#x22C6; ms &#x22C6;/
+       fe_caps_t  caps;
+       };
+</programlisting>
+</section>
+
+<section id="dvb-diseqc-master-cmd">
+<title>diseqc master command</title>
+
+<para>A message sent from the frontend to DiSEqC capable equipment.</para>
+<programlisting>
+       struct dvb_diseqc_master_cmd {
+       uint8_t msg [6]; /&#x22C6;  { framing, address, command, data[3] } &#x22C6;/
+       uint8_t msg_len; /&#x22C6;  valid values are 3...6  &#x22C6;/
+       };
+</programlisting>
+</section>
+<section role="subsection" id="dvb-diseqc-slave-reply">
+<title>diseqc slave reply</title>
+
+<para>A reply to the frontend from DiSEqC 2.0 capable equipment.</para>
+<programlisting>
+       struct dvb_diseqc_slave_reply {
+       uint8_t msg [4]; /&#x22C6;  { framing, data [3] } &#x22C6;/
+       uint8_t msg_len; /&#x22C6;  valid values are 0...4, 0 means no msg  &#x22C6;/
+       int     timeout; /&#x22C6;  return from ioctl after timeout ms with &#x22C6;/
+       };                       /&#x22C6;  errorcode when no message was received  &#x22C6;/
+</programlisting>
+</section>
+
+<section id="fe-sec-voltage-t">
+<title>diseqc slave reply</title>
+<para>The voltage is usually used with non-DiSEqC capable LNBs to switch the polarzation
+(horizontal/vertical). When using DiSEqC epuipment this voltage has to be switched
+consistently to the DiSEqC commands as described in the DiSEqC spec.</para>
+<programlisting>
+       typedef enum fe_sec_voltage {
+       SEC_VOLTAGE_13,
+       SEC_VOLTAGE_18
+       } fe_sec_voltage_t;
+</programlisting>
+</section>
+
+<section id="fe-sec-tone-mode-t">
+<title>SEC continuous tone</title>
+
+<para>The continuous 22KHz tone is usually used with non-DiSEqC capable LNBs to switch the
+high/low band of a dual-band LNB. When using DiSEqC epuipment this voltage has to
+be switched consistently to the DiSEqC commands as described in the DiSEqC
+spec.</para>
+<programlisting>
+       typedef enum fe_sec_tone_mode {
+       SEC_TONE_ON,
+       SEC_TONE_OFF
+       } fe_sec_tone_mode_t;
+</programlisting>
+</section>
+
+<section id="fe-sec-mini-cmd-t">
+<title>SEC tone burst</title>
+
+<para>The 22KHz tone burst is usually used with non-DiSEqC capable switches to select
+between two connected LNBs/satellites. When using DiSEqC epuipment this voltage has to
+be switched consistently to the DiSEqC commands as described in the DiSEqC
+spec.</para>
+<programlisting>
+       typedef enum fe_sec_mini_cmd {
+       SEC_MINI_A,
+       SEC_MINI_B
+       } fe_sec_mini_cmd_t;
+</programlisting>
+
+<para></para>
+</section>
+
+<section id="fe-status-t">
+<title>frontend status</title>
+<para>Several functions of the frontend device use the fe_status data type defined
+by</para>
+<programlisting>
+ typedef enum fe_status {
+        FE_HAS_SIGNAL     = 0x01,   /&#x22C6;  found something above the noise level &#x22C6;/
+        FE_HAS_CARRIER    = 0x02,   /&#x22C6;  found a DVB signal  &#x22C6;/
+        FE_HAS_VITERBI    = 0x04,   /&#x22C6;  FEC is stable  &#x22C6;/
+        FE_HAS_SYNC       = 0x08,   /&#x22C6;  found sync bytes  &#x22C6;/
+        FE_HAS_LOCK       = 0x10,   /&#x22C6;  everything's working... &#x22C6;/
+        FE_TIMEDOUT       = 0x20,   /&#x22C6;  no lock within the last ~2 seconds &#x22C6;/
+        FE_REINIT         = 0x40    /&#x22C6;  frontend was reinitialized,  &#x22C6;/
+ } fe_status_t;                      /&#x22C6;  application is recommned to reset &#x22C6;/
+</programlisting>
+<para>to indicate the current state and/or state changes of the frontend hardware.
+</para>
+
+</section>
+
+<section id="dvb-frontend-parameters">
+<title>frontend parameters</title>
+<para>The kind of parameters passed to the frontend device for tuning depend on
+the kind of hardware you are using.</para>
+<para>The struct <constant>dvb_frontend_parameters</constant> uses an
+union with specific per-system parameters. However, as newer delivery systems
+required more data, the structure size weren't enough to fit, and just
+extending its size would break the existing applications. So, those parameters
+were replaced by the usage of <link linkend="FE_GET_SET_PROPERTY">
+<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> ioctl's. The
+new API is flexible enough to add new parameters to existing delivery systems,
+and to add newer delivery systems.</para>
+<para>So, newer applications should use <link linkend="FE_GET_SET_PROPERTY">
+<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></link> instead, in
+order to be able to support the newer System Delivery like  DVB-S2, DVB-T2,
+DVB-C2, ISDB, etc.</para>
+<para>All kinds of parameters are combined as an union in the FrontendParameters structure:</para>
+<programlisting>
+struct dvb_frontend_parameters {
+       uint32_t frequency;     /&#x22C6; (absolute) frequency in Hz for QAM/OFDM &#x22C6;/
+                               /&#x22C6; intermediate frequency in kHz for QPSK &#x22C6;/
+       fe_spectral_inversion_t inversion;
+       union {
+               struct dvb_qpsk_parameters qpsk;
+               struct dvb_qam_parameters  qam;
+               struct dvb_ofdm_parameters ofdm;
+               struct dvb_vsb_parameters  vsb;
+       } u;
+};
+</programlisting>
+<para>In the case of QPSK frontends the <constant>frequency</constant> field specifies the intermediate
+frequency, i.e. the offset which is effectively added to the local oscillator frequency (LOF) of
+the LNB. The intermediate frequency has to be specified in units of kHz. For QAM and
+OFDM frontends the <constant>frequency</constant> specifies the absolute frequency and is given in Hz.
+</para>
+<section id="dvb-qpsk-parameters">
+<title>QPSK parameters</title>
+<para>For satellite QPSK frontends you have to use the <constant>dvb_qpsk_parameters</constant> structure:</para>
+<programlisting>
+ struct dvb_qpsk_parameters {
+        uint32_t        symbol_rate;  /&#x22C6; symbol rate in Symbols per second &#x22C6;/
+        fe_code_rate_t  fec_inner;    /&#x22C6; forward error correction (see above) &#x22C6;/
+ };
+</programlisting>
+</section>
+<section id="dvb-qam-parameters">
+<title>QAM parameters</title>
+<para>for cable QAM frontend you use the <constant>dvb_qam_parameters</constant> structure:</para>
+<programlisting>
+ struct dvb_qam_parameters {
+        uint32_t         symbol_rate; /&#x22C6; symbol rate in Symbols per second &#x22C6;/
+        fe_code_rate_t   fec_inner;   /&#x22C6; forward error correction (see above) &#x22C6;/
+        fe_modulation_t  modulation;  /&#x22C6; modulation type (see above) &#x22C6;/
+ };
+</programlisting>
+</section>
+<section id="dvb-vsb-parameters">
+<title>VSB parameters</title>
+<para>ATSC frontends are supported by the <constant>dvb_vsb_parameters</constant> structure:</para>
+<programlisting>
+struct dvb_vsb_parameters {
+       fe_modulation_t modulation;     /&#x22C6; modulation type (see above) &#x22C6;/
+};
+</programlisting>
+</section>
+<section id="dvb-ofdm-parameters">
+<title>OFDM parameters</title>
+<para>DVB-T frontends are supported by the <constant>dvb_ofdm_parameters</constant> structure:</para>
+<programlisting>
+ struct dvb_ofdm_parameters {
+        fe_bandwidth_t      bandwidth;
+        fe_code_rate_t      code_rate_HP;  /&#x22C6; high priority stream code rate &#x22C6;/
+        fe_code_rate_t      code_rate_LP;  /&#x22C6; low priority stream code rate &#x22C6;/
+        fe_modulation_t     constellation; /&#x22C6; modulation type (see above) &#x22C6;/
+        fe_transmit_mode_t  transmission_mode;
+        fe_guard_interval_t guard_interval;
+        fe_hierarchy_t      hierarchy_information;
+ };
+</programlisting>
+</section>
+<section id="fe-spectral-inversion-t">
+<title>frontend spectral inversion</title>
+<para>The Inversion field can take one of these values:
+</para>
+<programlisting>
+typedef enum fe_spectral_inversion {
+       INVERSION_OFF,
+       INVERSION_ON,
+       INVERSION_AUTO
+} fe_spectral_inversion_t;
+</programlisting>
+<para>It indicates if spectral inversion should be presumed or not. In the automatic setting
+(<constant>INVERSION_AUTO</constant>) the hardware will try to figure out the correct setting by
+itself.
+</para>
+</section>
+<section id="fe-code-rate-t">
+<title>frontend code rate</title>
+<para>The possible values for the <constant>fec_inner</constant> field used on
+<link refend="dvb-qpsk-parameters"><constant>struct dvb_qpsk_parameters</constant></link> and
+<link refend="dvb-qam-parameters"><constant>struct dvb_qam_parameters</constant></link> are:
+</para>
+<programlisting>
+typedef enum fe_code_rate {
+       FEC_NONE = 0,
+       FEC_1_2,
+       FEC_2_3,
+       FEC_3_4,
+       FEC_4_5,
+       FEC_5_6,
+       FEC_6_7,
+       FEC_7_8,
+       FEC_8_9,
+       FEC_AUTO,
+       FEC_3_5,
+       FEC_9_10,
+} fe_code_rate_t;
+</programlisting>
+<para>which correspond to error correction rates of 1/2, 2/3, etc., no error correction or auto
+detection.
+</para>
+</section>
+<section id="fe-modulation-t">
+<title>frontend modulation type for QAM, OFDM and VSB</title>
+<para>For cable and terrestrial frontends, e. g. for
+<link refend="dvb-qam-parameters"><constant>struct dvb_qpsk_parameters</constant></link>,
+<link refend="dvb-ofdm-parameters"><constant>struct dvb_qam_parameters</constant></link> and
+<link refend="dvb-vsb-parameters"><constant>struct dvb_qam_parameters</constant></link>,
+it needs to specify the quadrature modulation mode which can be one of the following:
+</para>
+<programlisting>
+ typedef enum fe_modulation {
+       QPSK,
+       QAM_16,
+       QAM_32,
+       QAM_64,
+       QAM_128,
+       QAM_256,
+       QAM_AUTO,
+       VSB_8,
+       VSB_16,
+       PSK_8,
+       APSK_16,
+       APSK_32,
+       DQPSK,
+ } fe_modulation_t;
+</programlisting>
+</section>
+<para>Finally, there are several more parameters for OFDM:
+</para>
+<section id="fe-transmit-mode-t">
+<title>Number of carriers per channel</title>
+<programlisting>
+typedef enum fe_transmit_mode {
+       TRANSMISSION_MODE_2K,
+       TRANSMISSION_MODE_8K,
+       TRANSMISSION_MODE_AUTO,
+       TRANSMISSION_MODE_4K,
+       TRANSMISSION_MODE_1K,
+       TRANSMISSION_MODE_16K,
+       TRANSMISSION_MODE_32K,
+ } fe_transmit_mode_t;
+</programlisting>
+</section>
+<section id="fe-bandwidth-t">
+<title>frontend bandwidth</title>
+<programlisting>
+typedef enum fe_bandwidth {
+       BANDWIDTH_8_MHZ,
+       BANDWIDTH_7_MHZ,
+       BANDWIDTH_6_MHZ,
+       BANDWIDTH_AUTO,
+       BANDWIDTH_5_MHZ,
+       BANDWIDTH_10_MHZ,
+       BANDWIDTH_1_712_MHZ,
+} fe_bandwidth_t;
+</programlisting>
+</section>
+<section id="fe-guard-interval-t">
+<title>frontend guard inverval</title>
+<programlisting>
+typedef enum fe_guard_interval {
+       GUARD_INTERVAL_1_32,
+       GUARD_INTERVAL_1_16,
+       GUARD_INTERVAL_1_8,
+       GUARD_INTERVAL_1_4,
+       GUARD_INTERVAL_AUTO,
+       GUARD_INTERVAL_1_128,
+       GUARD_INTERVAL_19_128,
+       GUARD_INTERVAL_19_256,
+} fe_guard_interval_t;
+</programlisting>
+</section>
+<section id="fe-hierarchy-t">
+<title>frontend hierarchy</title>
+<programlisting>
+typedef enum fe_hierarchy {
+        HIERARCHY_NONE,
+        HIERARCHY_1,
+        HIERARCHY_2,
+        HIERARCHY_4,
+        HIERARCHY_AUTO
+ } fe_hierarchy_t;
+</programlisting>
+</section>
+
+</section>
+
+<section id="dvb-frontend-event">
+<title>frontend events</title>
+ <programlisting>
+ struct dvb_frontend_event {
+        fe_status_t status;
+        struct dvb_frontend_parameters parameters;
+ };
+</programlisting>
+ </section>
+</section>
+
+
+<section id="frontend_fcalls">
+<title>Frontend Function Calls</title>
+
+<section id="frontend_f_open">
+<title>open()</title>
+<para>DESCRIPTION</para>
+<informaltable><tgroup cols="1"><tbody><row>
+<entry align="char">
+<para>This system call opens a named frontend device (/dev/dvb/adapter0/frontend0)
+ for subsequent use. Usually the first thing to do after a successful open is to
+ find out the frontend type with <link linkend="FE_GET_INFO">FE_GET_INFO</link>.</para>
+<para>The device can be opened in read-only mode, which only allows monitoring of
+ device status and statistics, or read/write mode, which allows any kind of use
+ (e.g. performing tuning operations.)
+</para>
+<para>In a system with multiple front-ends, it is usually the case that multiple devices
+ cannot be open in read/write mode simultaneously. As long as a front-end
+ device is opened in read/write mode, other open() calls in read/write mode will
+ either fail or block, depending on whether non-blocking or blocking mode was
+ specified. A front-end device opened in blocking mode can later be put into
+ non-blocking mode (and vice versa) using the F_SETFL command of the fcntl
+ system call. This is a standard system call, documented in the Linux manual
+ page for fcntl. When an open() call has succeeded, the device will be ready
+ for use in the specified mode. This implies that the corresponding hardware is
+ powered up, and that other front-ends may have been powered down to make
+ that possible.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int open(const char &#x22C6;deviceName, int flags);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>const char
+ *deviceName</para>
+</entry><entry
+ align="char">
+<para>Name of specific video device.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int flags</para>
+</entry><entry
+ align="char">
+<para>A bit-wise OR of the following flags:</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_RDONLY read-only access</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_RDWR read/write access</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_NONBLOCK open in non-blocking mode</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>(blocking mode is the default)</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>ENODEV</para>
+</entry><entry
+ align="char">
+<para>Device driver not loaded/available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EINTERNAL</para>
+</entry><entry
+ align="char">
+<para>Internal error.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBUSY</para>
+</entry><entry
+ align="char">
+<para>Device or resource busy.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Invalid argument.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="frontend_f_close">
+<title>close()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call closes a previously opened front-end device. After closing
+ a front-end device, its corresponding hardware might be powered down
+ automatically.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int close(int fd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EBADF</para>
+</entry><entry
+ align="char">
+<para>fd is not a valid open file descriptor.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="FE_READ_STATUS">
+<title>FE_READ_STATUS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns status information about the front-end. This call only
+ requires read-only access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_READ_STATUS">FE_READ_STATUS</link>,
+ fe_status_t &#x22C6;status);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_READ_STATUS">FE_READ_STATUS</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct fe_status_t
+ *status</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the front-end status word is
+ to be stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EBADF</para>
+</entry><entry
+ align="char">
+<para>fd is not a valid open file descriptor.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EFAULT</para>
+</entry><entry
+ align="char">
+<para>status points to invalid address.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="FE_READ_BER">
+<title>FE_READ_BER</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns the bit error rate for the signal currently
+ received/demodulated by the front-end. For this command, read-only access to
+ the device is sufficient.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_READ_BER">FE_READ_BER</link>,
+ uint32_t &#x22C6;ber);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_READ_BER">FE_READ_BER</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>uint32_t *ber</para>
+</entry><entry
+ align="char">
+<para>The bit error rate is stored into *ber.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_READ_SNR">
+<title>FE_READ_SNR</title>
+
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns the signal-to-noise ratio for the signal currently received
+ by the front-end. For this command, read-only access to the device is sufficient.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_READ_SNR">FE_READ_SNR</link>, int16_t
+ &#x22C6;snr);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_READ_SNR">FE_READ_SNR</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int16_t *snr</para>
+</entry><entry
+ align="char">
+<para>The signal-to-noise ratio is stored into *snr.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_READ_SIGNAL_STRENGTH">
+<title>FE_READ_SIGNAL_STRENGTH</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns the signal strength value for the signal currently received
+ by the front-end. For this command, read-only access to the device is sufficient.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request =
+ <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link>, int16_t &#x22C6;strength);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_READ_SIGNAL_STRENGTH">FE_READ_SIGNAL_STRENGTH</link> for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int16_t *strength</para>
+</entry><entry
+ align="char">
+<para>The signal strength value is stored into *strength.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_READ_UNCORRECTED_BLOCKS">
+<title>FE_READ_UNCORRECTED_BLOCKS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns the number of uncorrected blocks detected by the device
+ driver during its lifetime. For meaningful measurements, the increment in block
+ count during a specific time interval should be calculated. For this command,
+ read-only access to the device is sufficient.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>Note that the counter will wrap to zero after its maximum count has been
+ reached.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl( int fd, int request =
+ <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link>, uint32_t &#x22C6;ublocks);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_READ_UNCORRECTED_BLOCKS">FE_READ_UNCORRECTED_BLOCKS</link> for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>uint32_t *ublocks</para>
+</entry><entry
+ align="char">
+<para>The total number of uncorrected blocks seen by the driver
+ so far.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_SET_FRONTEND">
+<title>FE_SET_FRONTEND</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call starts a tuning operation using specified parameters. The result
+ of this call will be successful if the parameters were valid and the tuning could
+ be initiated. The result of the tuning operation in itself, however, will arrive
+ asynchronously as an event (see documentation for <link linkend="FE_GET_EVENT">FE_GET_EVENT</link> and
+ FrontendEvent.) If a new <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> operation is initiated before
+ the previous one was completed, the previous operation will be aborted in favor
+ of the new one. This command requires read/write access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link>,
+ struct dvb_frontend_parameters &#x22C6;p);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dvb_frontend_parameters
+ *p</para>
+</entry><entry
+ align="char">
+<para>Points to parameters for tuning operation.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Maximum supported symbol rate reached.</para>
+</entry>
+</row></tbody></tgroup></informaltable>
+</section>
+
+<section id="FE_GET_FRONTEND">
+<title>FE_GET_FRONTEND</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call queries the currently effective frontend parameters. For this
+ command, read-only access to the device is sufficient.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_GET_FRONTEND">FE_GET_FRONTEND</link>,
+ struct dvb_frontend_parameters &#x22C6;p);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_FRONTEND">FE_SET_FRONTEND</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dvb_frontend_parameters
+ *p</para>
+</entry><entry
+ align="char">
+<para>Points to parameters for tuning operation.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Maximum supported symbol rate reached.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section>
+
+<section id="FE_GET_EVENT">
+<title>FE_GET_EVENT</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns a frontend event if available. If an event is not
+ available, the behavior depends on whether the device is in blocking or
+ non-blocking mode. In the latter case, the call fails immediately with errno
+ set to EWOULDBLOCK. In the former case, the call blocks until an event
+ becomes available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>The standard Linux poll() and/or select() system calls can be used with the
+ device file descriptor to watch for new events. For select(), the file descriptor
+ should be included in the exceptfds argument, and for poll(), POLLPRI should
+ be specified as the wake-up condition. Since the event queue allocated is
+ rather small (room for 8 events), the queue must be serviced regularly to avoid
+ overflow. If an overflow happens, the oldest event is discarded from the queue,
+ and an error (EOVERFLOW) occurs the next time the queue is read. After
+ reporting the error condition in this fashion, subsequent
+ <link linkend="FE_GET_EVENT">FE_GET_EVENT</link>
+ calls will return events from the queue as usual.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>For the sake of implementation simplicity, this command requires read/write
+ access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = QPSK_GET_EVENT,
+ struct dvb_frontend_event &#x22C6;ev);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_GET_EVENT">FE_GET_EVENT</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dvb_frontend_event
+ *ev</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the event,</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>if any, is to be stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EWOULDBLOCK</para>
+</entry><entry
+ align="char">
+<para>There is no event pending, and the device is in
+ non-blocking mode.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EOVERFLOW</para>
+</entry><entry
+ align="char">
+<para>Overflow in event queue - one or more events were lost.</para>
+</entry>
+</row></tbody></tgroup></informaltable>
+</section>
+
+<section id="FE_GET_INFO">
+<title>FE_GET_INFO</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns information about the front-end. This call only requires
+ read-only access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(int fd, int request = <link linkend="FE_GET_INFO">FE_GET_INFO</link>, struct
+ dvb_frontend_info &#x22C6;info);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_GET_INFO">FE_GET_INFO</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dvb_frontend_info
+ *info</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the front-end information is
+ to be stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="FE_DISEQC_RESET_OVERLOAD">
+<title>FE_DISEQC_RESET_OVERLOAD</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>If the bus has been automatically powered off due to power overload, this ioctl
+ call restores the power to the bus. The call requires read/write access to the
+ device. This call has no effect if the device is manually powered off. Not all
+ DVB adapters support this ioctl.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ <link linkend="FE_DISEQC_RESET_OVERLOAD">FE_DISEQC_RESET_OVERLOAD</link>);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_DISEQC_RESET_OVERLOAD">FE_DISEQC_RESET_OVERLOAD</link> for this
+ command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_DISEQC_SEND_MASTER_CMD">
+<title>FE_DISEQC_SEND_MASTER_CMD</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call is used to send a a DiSEqC command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ <link linkend="FE_DISEQC_SEND_MASTER_CMD">FE_DISEQC_SEND_MASTER_CMD</link>, struct
+ dvb_diseqc_master_cmd &#x22C6;cmd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_DISEQC_SEND_MASTER_CMD">FE_DISEQC_SEND_MASTER_CMD</link> for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dvb_diseqc_master_cmd
+ *cmd</para>
+</entry><entry
+ align="char">
+<para>Pointer to the command to be transmitted.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_DISEQC_RECV_SLAVE_REPLY">
+<title>FE_DISEQC_RECV_SLAVE_REPLY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call is used to receive reply to a DiSEqC 2.0 command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ <link linkend="FE_DISEQC_RECV_SLAVE_REPLY">FE_DISEQC_RECV_SLAVE_REPLY</link>, struct
+ dvb_diseqc_slave_reply &#x22C6;reply);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_DISEQC_RECV_SLAVE_REPLY">FE_DISEQC_RECV_SLAVE_REPLY</link> for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ dvb_diseqc_slave_reply
+ *reply</para>
+</entry><entry
+ align="char">
+<para>Pointer to the command to be received.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="FE_DISEQC_SEND_BURST">
+<title>FE_DISEQC_SEND_BURST</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call is used to send a 22KHz tone burst.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ <link linkend="FE_DISEQC_SEND_BURST">FE_DISEQC_SEND_BURST</link>, fe_sec_mini_cmd_t burst);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_DISEQC_SEND_BURST">FE_DISEQC_SEND_BURST</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>fe_sec_mini_cmd_t
+ burst</para>
+</entry><entry
+ align="char">
+<para>burst A or B.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_SET_TONE">
+<title>FE_SET_TONE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This call is used to set the generation of the continuous 22kHz tone. This call
+ requires read/write permissions.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_SET_TONE">FE_SET_TONE</link>,
+ fe_sec_tone_mode_t tone);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_TONE">FE_SET_TONE</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>fe_sec_tone_mode_t
+ tone</para>
+</entry><entry
+ align="char">
+<para>The requested tone generation mode (on/off).</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="FE_SET_VOLTAGE">
+<title>FE_SET_VOLTAGE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This call is used to set the bus voltage. This call requires read/write
+ permissions.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link>,
+ fe_sec_voltage_t voltage);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>fe_sec_voltage_t
+ voltage</para>
+</entry><entry
+ align="char">
+<para>The requested bus voltage.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_ENABLE_HIGH_LNB_VOLTAGE">
+<title>FE_ENABLE_HIGH_LNB_VOLTAGE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>If high != 0 enables slightly higher voltages instead of 13/18V (to compensate
+ for long cables). This call requires read/write permissions. Not all DVB
+ adapters support this ioctl.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ <link linkend="FE_ENABLE_HIGH_LNB_VOLTAGE">FE_ENABLE_HIGH_LNB_VOLTAGE</link>, int high);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_VOLTAGE">FE_SET_VOLTAGE</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int high</para>
+</entry><entry
+ align="char">
+<para>The requested bus voltage.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_SET_FRONTEND_TUNE_MODE">
+<title>FE_SET_FRONTEND_TUNE_MODE</title>
+<para>DESCRIPTION</para>
+<informaltable><tgroup cols="1"><tbody><row>
+<entry align="char">
+<para>Allow setting tuner mode flags to the frontend.</para>
+</entry>
+</row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS</para>
+<informaltable><tgroup cols="1"><tbody><row>
+<entry align="char">
+<para>int ioctl(int fd, int request =
+<link linkend="FE_SET_FRONTEND_TUNE_MODE">FE_SET_FRONTEND_TUNE_MODE</link>, unsigned int flags);</para>
+</entry>
+</row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS</para>
+<informaltable><tgroup cols="2"><tbody><row>
+<entry align="char">
+       <para>unsigned int flags</para>
+</entry>
+<entry align="char">
+<para>
+FE_TUNE_MODE_ONESHOT When set, this flag will disable any zigzagging or other "normal" tuning behaviour. Additionally, there will be no automatic monitoring of the lock status, and hence no frontend events will be generated. If a frontend device is closed, this flag will be automatically turned off when the device is reopened read-write.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+<section id="FE_DISHNETWORK_SEND_LEGACY_CMD">
+       <title>FE_DISHNETWORK_SEND_LEGACY_CMD</title>
+<para>DESCRIPTION</para>
+<informaltable><tgroup cols="1"><tbody><row>
+<entry align="char">
+<para>WARNING: This is a very obscure legacy command, used only at stv0299 driver. Should not be used on newer drivers.</para>
+<para>It provides a non-standard method for selecting Diseqc voltage on the frontend, for Dish Network legacy switches.</para>
+<para>As support for this ioctl were added in 2004, this means that such dishes were already legacy in 2004.</para>
+</entry>
+</row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS</para>
+<informaltable><tgroup cols="1"><tbody><row>
+<entry align="char">
+<para>int ioctl(int fd, int request =
+       <link linkend="FE_DISHNETWORK_SEND_LEGACY_CMD">FE_DISHNETWORK_SEND_LEGACY_CMD</link>, unsigned long cmd);</para>
+</entry>
+</row></tbody></tgroup></informaltable>
+
+<para>PARAMETERS</para>
+<informaltable><tgroup cols="2"><tbody><row>
+<entry align="char">
+       <para>unsigned long cmd</para>
+</entry>
+<entry align="char">
+<para>
+sends the specified raw cmd to the dish via DISEqC.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+&return-value-dvb;
+</section>
+
+</section>
+
+&sub-dvbproperty;
diff --git a/Documentation/DocBook/media/dvb/intro.xml b/Documentation/DocBook/media/dvb/intro.xml
new file mode 100644 (file)
index 0000000..c75dc7c
--- /dev/null
@@ -0,0 +1,212 @@
+<title>Introduction</title>
+
+<section id="requisites">
+<title>What you need to know</title>
+
+<para>The reader of this document is required to have some knowledge in
+the area of digital video broadcasting (DVB) and should be familiar with
+part I of the MPEG2 specification ISO/IEC 13818 (aka ITU-T H.222), i.e
+you should know what a program/transport stream (PS/TS) is and what is
+meant by a packetized elementary stream (PES) or an I-frame.</para>
+
+<para>Various DVB standards documents are available from
+<ulink url="http://www.dvb.org" /> and/or
+<ulink url="http://www.etsi.org" />.</para>
+
+<para>It is also necessary to know how to access unix/linux devices and
+how to use ioctl calls. This also includes the knowledge of C or C++.
+</para>
+</section>
+
+<section id="history">
+<title>History</title>
+
+<para>The first API for DVB cards we used at Convergence in late 1999
+was an extension of the Video4Linux API which was primarily developed
+for frame grabber cards. As such it was not really well suited to be
+used for DVB cards and their new features like recording MPEG streams
+and filtering several section and PES data streams at the same time.
+</para>
+
+<para>In early 2000, we were approached by Nokia with a proposal for a
+new standard Linux DVB API. As a commitment to the development of
+terminals based on open standards, Nokia and Convergence made it
+available to all Linux developers and published it on
+<ulink url="http://www.linuxtv.org/" /> in September 2000.
+Convergence is the maintainer of the Linux DVB API. Together with the
+LinuxTV community (i.e. you, the reader of this document), the Linux DVB
+API will be constantly reviewed and improved. With the Linux driver for
+the Siemens/Hauppauge DVB PCI card Convergence provides a first
+implementation of the Linux DVB API.</para>
+</section>
+
+<section id="overview">
+<title>Overview</title>
+
+<figure id="stb_components">
+<title>Components of a DVB card/STB</title>
+<mediaobject>
+<imageobject>
+<imagedata fileref="dvbstb.pdf" format="PS" />
+</imageobject>
+<imageobject>
+<imagedata fileref="dvbstb.png" format="PNG" />
+</imageobject>
+</mediaobject>
+</figure>
+
+<para>A DVB PCI card or DVB set-top-box (STB) usually consists of the
+following main hardware components: </para>
+
+<itemizedlist>
+ <listitem>
+
+<para>Frontend consisting of tuner and DVB demodulator</para>
+
+<para>Here the raw signal reaches the DVB hardware from a satellite dish
+or antenna or directly from cable. The frontend down-converts and
+demodulates this signal into an MPEG transport stream (TS). In case of a
+satellite frontend, this includes a facility for satellite equipment
+control (SEC), which allows control of LNB polarization, multi feed
+switches or dish rotors.</para>
+
+</listitem>
+ <listitem>
+
+<para>Conditional Access (CA) hardware like CI adapters and smartcard slots
+</para>
+
+<para>The complete TS is passed through the CA hardware. Programs to
+which the user has access (controlled by the smart card) are decoded in
+real time and re-inserted into the TS.</para>
+
+</listitem>
+ <listitem>
+ <para>Demultiplexer which filters the incoming DVB stream</para>
+
+<para>The demultiplexer splits the TS into its components like audio and
+video streams. Besides usually several of such audio and video streams
+it also contains data streams with information about the programs
+offered in this or other streams of the same provider.</para>
+
+</listitem>
+<listitem>
+
+<para>MPEG2 audio and video decoder</para>
+
+<para>The main targets of the demultiplexer are the MPEG2 audio and
+video decoders. After decoding they pass on the uncompressed audio and
+video to the computer screen or (through a PAL/NTSC encoder) to a TV
+set.</para>
+
+
+</listitem>
+</itemizedlist>
+
+<para><xref linkend="stb_components" /> shows a crude schematic of the control and data flow
+between those components.</para>
+
+<para>On a DVB PCI card not all of these have to be present since some
+functionality can be provided by the main CPU of the PC (e.g. MPEG
+picture and sound decoding) or is not needed (e.g. for data-only uses
+like &#8220;internet over satellite&#8221;). Also not every card or STB
+provides conditional access hardware.</para>
+
+</section>
+
+<section id="dvb_devices">
+<title>Linux DVB Devices</title>
+
+<para>The Linux DVB API lets you control these hardware components
+through currently six Unix-style character devices for video, audio,
+frontend, demux, CA and IP-over-DVB networking. The video and audio
+devices control the MPEG2 decoder hardware, the frontend device the
+tuner and the DVB demodulator. The demux device gives you control over
+the PES and section filters of the hardware. If the hardware does not
+support filtering these filters can be implemented in software. Finally,
+the CA device controls all the conditional access capabilities of the
+hardware. It can depend on the individual security requirements of the
+platform, if and how many of the CA functions are made available to the
+application through this device.</para>
+
+<para>All devices can be found in the <emphasis role="tt">/dev</emphasis>
+tree under <emphasis role="tt">/dev/dvb</emphasis>. The individual devices
+are called:</para>
+
+<itemizedlist>
+<listitem>
+
+<para><emphasis role="tt">/dev/dvb/adapterN/audioM</emphasis>,</para>
+</listitem>
+<listitem>
+<para><emphasis role="tt">/dev/dvb/adapterN/videoM</emphasis>,</para>
+</listitem>
+<listitem>
+<para><emphasis role="tt">/dev/dvb/adapterN/frontendM</emphasis>,</para>
+</listitem>
+ <listitem>
+
+<para><emphasis role="tt">/dev/dvb/adapterN/netM</emphasis>,</para>
+</listitem>
+ <listitem>
+
+<para><emphasis role="tt">/dev/dvb/adapterN/demuxM</emphasis>,</para>
+</listitem>
+ <listitem>
+
+<para><emphasis role="tt">/dev/dvb/adapterN/dvrM</emphasis>,</para>
+</listitem>
+ <listitem>
+
+<para><emphasis role="tt">/dev/dvb/adapterN/caM</emphasis>,</para></listitem></itemizedlist>
+
+<para>where N enumerates the DVB PCI cards in a system starting
+from&#x00A0;0, and M enumerates the devices of each type within each
+adapter, starting from&#x00A0;0, too. We will omit the &#8220;<emphasis
+role="tt">/dev/dvb/adapterN/</emphasis>&#8221; in the further dicussion
+of these devices. The naming scheme for the devices is the same wheter
+devfs is used or not.</para>
+
+<para>More details about the data structures and function calls of all
+the devices are described in the following chapters.</para>
+
+</section>
+
+<section id="include_files">
+<title>API include files</title>
+
+<para>For each of the DVB devices a corresponding include file exists.
+The DVB API include files should be included in application sources with
+a partial path like:</para>
+
+<programlisting>
+       #include &#x003C;linux/dvb/audio.h&#x003E;
+</programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/ca.h&#x003E;
+</programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/dmx.h&#x003E;
+</programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/frontend.h&#x003E;
+</programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/net.h&#x003E;
+</programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/osd.h&#x003E;
+</programlisting>
+<programlisting>
+       #include &#x003C;linux/dvb/video.h&#x003E;
+</programlisting>
+
+<para>To enable applications to support different API version, an
+additional include file <emphasis
+role="tt">linux/dvb/version.h</emphasis> exists, which defines the
+constant <emphasis role="tt">DVB_API_VERSION</emphasis>. This document
+describes <emphasis role="tt">DVB_API_VERSION&#x00A0;3</emphasis>.
+</para>
+
+</section>
+
diff --git a/Documentation/DocBook/media/dvb/kdapi.xml b/Documentation/DocBook/media/dvb/kdapi.xml
new file mode 100644 (file)
index 0000000..6c67481
--- /dev/null
@@ -0,0 +1,2309 @@
+<title>Kernel Demux API</title>
+<para>The kernel demux API defines a driver-internal interface for registering low-level,
+hardware specific driver to a hardware independent demux layer. It is only of interest for
+DVB device driver writers. The header file for this API is named <emphasis role="tt">demux.h</emphasis> and located in
+<emphasis role="tt">drivers/media/dvb/dvb-core</emphasis>.
+</para>
+<para>Maintainer note: This section must be reviewed. It is probably out of date.
+</para>
+
+<section id="kernel_demux_data_types">
+<title>Kernel Demux Data Types</title>
+
+
+<section id="dmx_success_t">
+<title>dmx_success_t</title>
+ <programlisting>
+ typedef enum {
+   DMX_OK = 0, /&#x22C6; Received Ok &#x22C6;/
+   DMX_LENGTH_ERROR, /&#x22C6; Incorrect length &#x22C6;/
+   DMX_OVERRUN_ERROR, /&#x22C6; Receiver ring buffer overrun &#x22C6;/
+   DMX_CRC_ERROR, /&#x22C6; Incorrect CRC &#x22C6;/
+   DMX_FRAME_ERROR, /&#x22C6; Frame alignment error &#x22C6;/
+   DMX_FIFO_ERROR, /&#x22C6; Receiver FIFO overrun &#x22C6;/
+   DMX_MISSED_ERROR /&#x22C6; Receiver missed packet &#x22C6;/
+ } dmx_success_t;
+</programlisting>
+
+</section>
+<section id="ts_filter_types">
+<title>TS filter types</title>
+ <programlisting>
+ /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
+ /&#x22C6; TS packet reception &#x22C6;/
+ /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
+
+ /&#x22C6; TS filter type for set_type() &#x22C6;/
+
+ #define TS_PACKET       1   /&#x22C6; send TS packets (188 bytes) to callback (default) &#x22C6;/
+ #define TS_PAYLOAD_ONLY 2   /&#x22C6; in case TS_PACKET is set, only send the TS
+                               payload (&#x003C;=184 bytes per packet) to callback &#x22C6;/
+ #define TS_DECODER      4   /&#x22C6; send stream to built-in decoder (if present) &#x22C6;/
+</programlisting>
+
+</section>
+<section id="dmx_ts_pes_t">
+<title>dmx_ts_pes_t</title>
+<para>The structure
+</para>
+<programlisting>
+ typedef enum
+ {
+        DMX_TS_PES_AUDIO,   /&#x22C6; also send packets to audio decoder (if it exists) &#x22C6;/
+        DMX_TS_PES_VIDEO,   /&#x22C6; ... &#x22C6;/
+        DMX_TS_PES_TELETEXT,
+        DMX_TS_PES_SUBTITLE,
+        DMX_TS_PES_PCR,
+        DMX_TS_PES_OTHER,
+ } dmx_ts_pes_t;
+</programlisting>
+<para>describes the PES type for filters which write to a built-in decoder. The correspond (and
+should be kept identical) to the types in the demux device.
+</para>
+<programlisting>
+ struct dmx_ts_feed_s {
+        int is_filtering; /&#x22C6; Set to non-zero when filtering in progress &#x22C6;/
+        struct dmx_demux_s&#x22C6; parent; /&#x22C6; Back-pointer &#x22C6;/
+        void&#x22C6; priv; /&#x22C6; Pointer to private data of the API client &#x22C6;/
+        int (&#x22C6;set) (struct dmx_ts_feed_s&#x22C6; feed,
+                    __u16 pid,
+                    size_t callback_length,
+                    size_t circular_buffer_size,
+                    int descramble,
+                    struct timespec timeout);
+        int (&#x22C6;start_filtering) (struct dmx_ts_feed_s&#x22C6; feed);
+        int (&#x22C6;stop_filtering) (struct dmx_ts_feed_s&#x22C6; feed);
+        int (&#x22C6;set_type) (struct dmx_ts_feed_s&#x22C6; feed,
+                         int type,
+                         dmx_ts_pes_t pes_type);
+ };
+
+ typedef struct dmx_ts_feed_s dmx_ts_feed_t;
+</programlisting>
+ <programlisting>
+ /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
+ /&#x22C6; PES packet reception (not supported yet) &#x22C6;/
+ /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
+
+ typedef struct dmx_pes_filter_s {
+        struct dmx_pes_s&#x22C6; parent; /&#x22C6; Back-pointer &#x22C6;/
+        void&#x22C6; priv; /&#x22C6; Pointer to private data of the API client &#x22C6;/
+ } dmx_pes_filter_t;
+</programlisting>
+ <programlisting>
+ typedef struct dmx_pes_feed_s {
+        int is_filtering; /&#x22C6; Set to non-zero when filtering in progress &#x22C6;/
+        struct dmx_demux_s&#x22C6; parent; /&#x22C6; Back-pointer &#x22C6;/
+        void&#x22C6; priv; /&#x22C6; Pointer to private data of the API client &#x22C6;/
+        int (&#x22C6;set) (struct dmx_pes_feed_s&#x22C6; feed,
+                    __u16 pid,
+                    size_t circular_buffer_size,
+                    int descramble,
+                    struct timespec timeout);
+        int (&#x22C6;start_filtering) (struct dmx_pes_feed_s&#x22C6; feed);
+        int (&#x22C6;stop_filtering) (struct dmx_pes_feed_s&#x22C6; feed);
+        int (&#x22C6;allocate_filter) (struct dmx_pes_feed_s&#x22C6; feed,
+                                dmx_pes_filter_t&#x22C6;&#x22C6; filter);
+        int (&#x22C6;release_filter) (struct dmx_pes_feed_s&#x22C6; feed,
+                               dmx_pes_filter_t&#x22C6; filter);
+ } dmx_pes_feed_t;
+</programlisting>
+ <programlisting>
+ typedef struct {
+        __u8 filter_value [DMX_MAX_FILTER_SIZE];
+        __u8 filter_mask [DMX_MAX_FILTER_SIZE];
+        struct dmx_section_feed_s&#x22C6; parent; /&#x22C6; Back-pointer &#x22C6;/
+        void&#x22C6; priv; /&#x22C6; Pointer to private data of the API client &#x22C6;/
+ } dmx_section_filter_t;
+</programlisting>
+ <programlisting>
+ struct dmx_section_feed_s {
+        int is_filtering; /&#x22C6; Set to non-zero when filtering in progress &#x22C6;/
+        struct dmx_demux_s&#x22C6; parent; /&#x22C6; Back-pointer &#x22C6;/
+        void&#x22C6; priv; /&#x22C6; Pointer to private data of the API client &#x22C6;/
+        int (&#x22C6;set) (struct dmx_section_feed_s&#x22C6; feed,
+                    __u16 pid,
+                    size_t circular_buffer_size,
+                    int descramble,
+                    int check_crc);
+        int (&#x22C6;allocate_filter) (struct dmx_section_feed_s&#x22C6; feed,
+                                dmx_section_filter_t&#x22C6;&#x22C6; filter);
+        int (&#x22C6;release_filter) (struct dmx_section_feed_s&#x22C6; feed,
+                               dmx_section_filter_t&#x22C6; filter);
+        int (&#x22C6;start_filtering) (struct dmx_section_feed_s&#x22C6; feed);
+        int (&#x22C6;stop_filtering) (struct dmx_section_feed_s&#x22C6; feed);
+ };
+ typedef struct dmx_section_feed_s dmx_section_feed_t;
+
+ /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
+ /&#x22C6; Callback functions &#x22C6;/
+ /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
+
+ typedef int (&#x22C6;dmx_ts_cb) ( __u8 &#x22C6; buffer1,
+                           size_t buffer1_length,
+                           __u8 &#x22C6; buffer2,
+                           size_t buffer2_length,
+                           dmx_ts_feed_t&#x22C6; source,
+                           dmx_success_t success);
+
+ typedef int (&#x22C6;dmx_section_cb) ( __u8 &#x22C6; buffer1,
+                                size_t buffer1_len,
+                                __u8 &#x22C6; buffer2,
+                                size_t buffer2_len,
+                                dmx_section_filter_t &#x22C6; source,
+                                dmx_success_t success);
+
+ typedef int (&#x22C6;dmx_pes_cb) ( __u8 &#x22C6; buffer1,
+                            size_t buffer1_len,
+                            __u8 &#x22C6; buffer2,
+                            size_t buffer2_len,
+                            dmx_pes_filter_t&#x22C6; source,
+                            dmx_success_t success);
+
+ /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
+ /&#x22C6; DVB Front-End &#x22C6;/
+ /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
+
+ typedef enum {
+        DMX_OTHER_FE = 0,
+        DMX_SATELLITE_FE,
+        DMX_CABLE_FE,
+        DMX_TERRESTRIAL_FE,
+        DMX_LVDS_FE,
+        DMX_ASI_FE, /&#x22C6; DVB-ASI interface &#x22C6;/
+        DMX_MEMORY_FE
+ } dmx_frontend_source_t;
+
+ typedef struct {
+        /&#x22C6; The following char&#x22C6; fields point to NULL terminated strings &#x22C6;/
+        char&#x22C6; id;                    /&#x22C6; Unique front-end identifier &#x22C6;/
+        char&#x22C6; vendor;                /&#x22C6; Name of the front-end vendor &#x22C6;/
+        char&#x22C6; model;                 /&#x22C6; Name of the front-end model &#x22C6;/
+        struct list_head connectivity_list; /&#x22C6; List of front-ends that can
+                                               be connected to a particular
+                                               demux &#x22C6;/
+        void&#x22C6; priv;     /&#x22C6; Pointer to private data of the API client &#x22C6;/
+        dmx_frontend_source_t source;
+ } dmx_frontend_t;
+
+ /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
+ /&#x22C6; MPEG-2 TS Demux &#x22C6;/
+ /&#x22C6;--------------------------------------------------------------------------&#x22C6;/
+
+ /&#x22C6;
+  &#x22C6; Flags OR'ed in the capabilites field of struct dmx_demux_s.
+  &#x22C6;/
+
+ #define DMX_TS_FILTERING                        1
+ #define DMX_PES_FILTERING                       2
+ #define DMX_SECTION_FILTERING                   4
+ #define DMX_MEMORY_BASED_FILTERING              8    /&#x22C6; write() available &#x22C6;/
+ #define DMX_CRC_CHECKING                        16
+ #define DMX_TS_DESCRAMBLING                     32
+ #define DMX_SECTION_PAYLOAD_DESCRAMBLING        64
+ #define DMX_MAC_ADDRESS_DESCRAMBLING            128
+</programlisting>
+
+</section>
+<section id="demux_demux_t">
+<title>demux_demux_t</title>
+ <programlisting>
+ /&#x22C6;
+  &#x22C6; DMX_FE_ENTRY(): Casts elements in the list of registered
+  &#x22C6; front-ends from the generic type struct list_head
+  &#x22C6; to the type &#x22C6; dmx_frontend_t
+  &#x22C6;.
+ &#x22C6;/
+
+ #define DMX_FE_ENTRY(list) list_entry(list, dmx_frontend_t, connectivity_list)
+
+ struct dmx_demux_s {
+        /&#x22C6; The following char&#x22C6; fields point to NULL terminated strings &#x22C6;/
+        char&#x22C6; id;                    /&#x22C6; Unique demux identifier &#x22C6;/
+        char&#x22C6; vendor;                /&#x22C6; Name of the demux vendor &#x22C6;/
+        char&#x22C6; model;                 /&#x22C6; Name of the demux model &#x22C6;/
+        __u32 capabilities;          /&#x22C6; Bitfield of capability flags &#x22C6;/
+        dmx_frontend_t&#x22C6; frontend;    /&#x22C6; Front-end connected to the demux &#x22C6;/
+        struct list_head reg_list;   /&#x22C6; List of registered demuxes &#x22C6;/
+        void&#x22C6; priv;                  /&#x22C6; Pointer to private data of the API client &#x22C6;/
+        int users;                   /&#x22C6; Number of users &#x22C6;/
+        int (&#x22C6;open) (struct dmx_demux_s&#x22C6; demux);
+        int (&#x22C6;close) (struct dmx_demux_s&#x22C6; demux);
+        int (&#x22C6;write) (struct dmx_demux_s&#x22C6; demux, const char&#x22C6; buf, size_t count);
+        int (&#x22C6;allocate_ts_feed) (struct dmx_demux_s&#x22C6; demux,
+                                 dmx_ts_feed_t&#x22C6;&#x22C6; feed,
+                                 dmx_ts_cb callback);
+        int (&#x22C6;release_ts_feed) (struct dmx_demux_s&#x22C6; demux,
+                                dmx_ts_feed_t&#x22C6; feed);
+        int (&#x22C6;allocate_pes_feed) (struct dmx_demux_s&#x22C6; demux,
+                                  dmx_pes_feed_t&#x22C6;&#x22C6; feed,
+                                  dmx_pes_cb callback);
+        int (&#x22C6;release_pes_feed) (struct dmx_demux_s&#x22C6; demux,
+                                 dmx_pes_feed_t&#x22C6; feed);
+        int (&#x22C6;allocate_section_feed) (struct dmx_demux_s&#x22C6; demux,
+                                      dmx_section_feed_t&#x22C6;&#x22C6; feed,
+                                      dmx_section_cb callback);
+        int (&#x22C6;release_section_feed) (struct dmx_demux_s&#x22C6; demux,
+                                     dmx_section_feed_t&#x22C6; feed);
+        int (&#x22C6;descramble_mac_address) (struct dmx_demux_s&#x22C6; demux,
+                                       __u8&#x22C6; buffer1,
+                                       size_t buffer1_length,
+                                       __u8&#x22C6; buffer2,
+                                       size_t buffer2_length,
+                                       __u16 pid);
+        int (&#x22C6;descramble_section_payload) (struct dmx_demux_s&#x22C6; demux,
+                                           __u8&#x22C6; buffer1,
+                                           size_t buffer1_length,
+                                           __u8&#x22C6; buffer2, size_t buffer2_length,
+                                           __u16 pid);
+        int (&#x22C6;add_frontend) (struct dmx_demux_s&#x22C6; demux,
+                             dmx_frontend_t&#x22C6; frontend);
+        int (&#x22C6;remove_frontend) (struct dmx_demux_s&#x22C6; demux,
+                                dmx_frontend_t&#x22C6; frontend);
+        struct list_head&#x22C6; (&#x22C6;get_frontends) (struct dmx_demux_s&#x22C6; demux);
+        int (&#x22C6;connect_frontend) (struct dmx_demux_s&#x22C6; demux,
+                                 dmx_frontend_t&#x22C6; frontend);
+        int (&#x22C6;disconnect_frontend) (struct dmx_demux_s&#x22C6; demux);
+
+
+        /&#x22C6; added because js cannot keep track of these himself &#x22C6;/
+        int (&#x22C6;get_pes_pids) (struct dmx_demux_s&#x22C6; demux, __u16 &#x22C6;pids);
+ };
+ typedef struct dmx_demux_s dmx_demux_t;
+</programlisting>
+
+</section>
+<section id="demux_directory">
+<title>Demux directory</title>
+ <programlisting>
+ /&#x22C6;
+  &#x22C6; DMX_DIR_ENTRY(): Casts elements in the list of registered
+  &#x22C6; demuxes from the generic type struct list_head&#x22C6; to the type dmx_demux_t
+  &#x22C6;.
+  &#x22C6;/
+
+ #define DMX_DIR_ENTRY(list) list_entry(list, dmx_demux_t, reg_list)
+
+ int dmx_register_demux (dmx_demux_t&#x22C6; demux);
+ int dmx_unregister_demux (dmx_demux_t&#x22C6; demux);
+ struct list_head&#x22C6; dmx_get_demuxes (void);
+</programlisting>
+ </section></section>
+<section id="demux_directory_api">
+<title>Demux Directory API</title>
+<para>The demux directory is a Linux kernel-wide facility for registering and accessing the
+MPEG-2 TS demuxes in the system. Run-time registering and unregistering of demux drivers
+is possible using this API.
+</para>
+<para>All demux drivers in the directory implement the abstract interface dmx_demux_t.
+</para>
+
+<section
+role="subsection"><title>dmx_register_demux()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function makes a demux driver interface available to the Linux kernel. It is
+ usually called by the init_module() function of the kernel module that contains
+ the demux driver. The caller of this function is responsible for allocating
+ dynamic or static memory for the demux structure and for initializing its fields
+ before calling this function. The memory allocated for the demux structure
+ must not be freed before calling dmx_unregister_demux(),</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int dmx_register_demux ( dmx_demux_t &#x22C6;demux )</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_demux_t*
+ demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux structure.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EEXIST</para>
+</entry><entry
+ align="char">
+<para>A demux with the same value of the id field already stored
+ in the directory.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOSPC</para>
+</entry><entry
+ align="char">
+<para>No space left in the directory.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>dmx_unregister_demux()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function is called to indicate that the given demux interface is no
+ longer available. The caller of this function is responsible for freeing the
+ memory of the demux structure, if it was dynamically allocated before calling
+ dmx_register_demux(). The cleanup_module() function of the kernel module
+ that contains the demux driver should call this function. Note that this function
+ fails if the demux is currently in use, i.e., release_demux() has not been called
+ for the interface.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int dmx_unregister_demux ( dmx_demux_t &#x22C6;demux )</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_demux_t*
+ demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux structure which is to be
+ unregistered.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ENODEV</para>
+</entry><entry
+ align="char">
+<para>The specified demux is not registered in the demux
+ directory.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBUSY</para>
+</entry><entry
+ align="char">
+<para>The specified demux is currently in use.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>dmx_get_demuxes()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Provides the caller with the list of registered demux interfaces, using the
+ standard list structure defined in the include file linux/list.h. The include file
+ demux.h defines the macro DMX_DIR_ENTRY() for converting an element of
+ the generic type struct list_head* to the type dmx_demux_t*. The caller must
+ not free the memory of any of the elements obtained via this function call.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>struct list_head &#x22C6;dmx_get_demuxes ()</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>none</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>struct list_head *</para>
+</entry><entry
+ align="char">
+<para>A list of demux interfaces, or NULL in the case of an
+ empty list.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+ </section></section>
+<section id="demux_api">
+<title>Demux API</title>
+<para>The demux API should be implemented for each demux in the system. It is used to select
+the TS source of a demux and to manage the demux resources. When the demux
+client allocates a resource via the demux API, it receives a pointer to the API of that
+resource.
+</para>
+<para>Each demux receives its TS input from a DVB front-end or from memory, as set via the
+demux API. In a system with more than one front-end, the API can be used to select one of
+the DVB front-ends as a TS source for a demux, unless this is fixed in the HW platform. The
+demux API only controls front-ends regarding their connections with demuxes; the APIs
+used to set the other front-end parameters, such as tuning, are not defined in this
+document.
+</para>
+<para>The functions that implement the abstract interface demux should be defined static or
+module private and registered to the Demux Directory for external access. It is not necessary
+to implement every function in the demux_t struct, however (for example, a demux interface
+might support Section filtering, but not TS or PES filtering). The API client is expected to
+check the value of any function pointer before calling the function: the value of NULL means
+&#8220;function not available&#8221;.
+</para>
+<para>Whenever the functions of the demux API modify shared data, the possibilities of lost
+update and race condition problems should be addressed, e.g. by protecting parts of code with
+mutexes. This is especially important on multi-processor hosts.
+</para>
+<para>Note that functions called from a bottom half context must not sleep, at least in the 2.2.x
+kernels. Even a simple memory allocation can result in a kernel thread being put to sleep if
+swapping is needed. For example, the Linux kernel calls the functions of a network device
+interface from a bottom half context. Thus, if a demux API function is called from network
+device code, the function must not sleep.
+</para>
+
+
+<section id="kdapi_fopen">
+<title>open()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function reserves the demux for use by the caller and, if necessary,
+ initializes the demux. When the demux is no longer needed, the function close()
+ should be called. It should be possible for multiple clients to access the demux
+ at the same time. Thus, the function implementation should increment the
+ demux usage count when open() is called and decrement it when close() is
+ called.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int open ( demux_t&#x22C6; demux );</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>demux_t* demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EUSERS</para>
+</entry><entry
+ align="char">
+<para>Maximum usage count reached.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section>
+<section id="kdapi_fclose">
+<title>close()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function reserves the demux for use by the caller and, if necessary,
+ initializes the demux. When the demux is no longer needed, the function close()
+ should be called. It should be possible for multiple clients to access the demux
+ at the same time. Thus, the function implementation should increment the
+ demux usage count when open() is called and decrement it when close() is
+ called.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int close(demux_t&#x22C6; demux);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>demux_t* demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENODEV</para>
+</entry><entry
+ align="char">
+<para>The demux was not in use.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section>
+<section id="kdapi_fwrite">
+<title>write()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function provides the demux driver with a memory buffer containing TS
+ packets. Instead of receiving TS packets from the DVB front-end, the demux
+ driver software will read packets from memory. Any clients of this demux
+ with active TS, PES or Section filters will receive filtered data via the Demux
+ callback API (see 0). The function returns when all the data in the buffer has
+ been consumed by the demux. Demux hardware typically cannot read TS from
+ memory. If this is the case, memory-based filtering has to be implemented
+ entirely in software.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int write(demux_t&#x22C6; demux, const char&#x22C6; buf, size_t
+ count);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>demux_t* demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>const char* buf</para>
+</entry><entry
+ align="char">
+<para>Pointer to the TS data in kernel-space memory.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t length</para>
+</entry><entry
+ align="char">
+<para>Length of the TS data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOSYS</para>
+</entry><entry
+ align="char">
+<para>The command is not implemented.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>allocate_ts_feed()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Allocates a new TS feed, which is used to filter the TS packets carrying a
+ certain PID. The TS feed normally corresponds to a hardware PID filter on the
+ demux chip.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int allocate_ts_feed(dmx_demux_t&#x22C6; demux,
+ dmx_ts_feed_t&#x22C6;&#x22C6; feed, dmx_ts_cb callback);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>demux_t* demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_ts_feed_t**
+ feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the TS feed API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_ts_cb callback</para>
+</entry><entry
+ align="char">
+<para>Pointer to the callback function for passing received TS
+ packet</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EBUSY</para>
+</entry><entry
+ align="char">
+<para>No more TS feeds available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOSYS</para>
+</entry><entry
+ align="char">
+<para>The command is not implemented.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>release_ts_feed()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Releases the resources allocated with allocate_ts_feed(). Any filtering in
+ progress on the TS feed should be stopped before calling this function.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int release_ts_feed(dmx_demux_t&#x22C6; demux,
+ dmx_ts_feed_t&#x22C6; feed);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>demux_t* demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_ts_feed_t* feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the TS feed API and instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>allocate_section_feed()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Allocates a new section feed, i.e. a demux resource for filtering and receiving
+ sections. On platforms with hardware support for section filtering, a section
+ feed is directly mapped to the demux HW. On other platforms, TS packets are
+ first PID filtered in hardware and a hardware section filter then emulated in
+ software. The caller obtains an API pointer of type dmx_section_feed_t as an
+ out parameter. Using this API the caller can set filtering parameters and start
+ receiving sections.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int allocate_section_feed(dmx_demux_t&#x22C6; demux,
+ dmx_section_feed_t &#x22C6;&#x22C6;feed, dmx_section_cb callback);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>demux_t *demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_section_feed_t
+ **feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the section feed API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_section_cb
+ callback</para>
+</entry><entry
+ align="char">
+<para>Pointer to the callback function for passing received
+ sections.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EBUSY</para>
+</entry><entry
+ align="char">
+<para>No more section feeds available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOSYS</para>
+</entry><entry
+ align="char">
+<para>The command is not implemented.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>release_section_feed()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Releases the resources allocated with allocate_section_feed(), including
+ allocated filters. Any filtering in progress on the section feed should be stopped
+ before calling this function.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int release_section_feed(dmx_demux_t&#x22C6; demux,
+ dmx_section_feed_t &#x22C6;feed);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>demux_t *demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_section_feed_t
+ *feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the section feed API and instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>descramble_mac_address()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function runs a descrambling algorithm on the destination MAC
+ address field of a DVB Datagram Section, replacing the original address
+ with its un-encrypted version. Otherwise, the description on the function
+ descramble_section_payload() applies also to this function.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int descramble_mac_address(dmx_demux_t&#x22C6; demux, __u8
+ &#x22C6;buffer1, size_t buffer1_length, __u8 &#x22C6;buffer2,
+ size_t buffer2_length, __u16 pid);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_demux_t
+ *demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u8 *buffer1</para>
+</entry><entry
+ align="char">
+<para>Pointer to the first byte of the section.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t buffer1_length</para>
+</entry><entry
+ align="char">
+<para>Length of the section data, including headers and CRC,
+ in buffer1.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u8* buffer2</para>
+</entry><entry
+ align="char">
+<para>Pointer to the tail of the section data, or NULL. The
+ pointer has a non-NULL value if the section wraps past
+ the end of a circular buffer.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t buffer2_length</para>
+</entry><entry
+ align="char">
+<para>Length of the section data, including headers and CRC,
+ in buffer2.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16 pid</para>
+</entry><entry
+ align="char">
+<para>The PID on which the section was received. Useful
+ for obtaining the descrambling key, e.g. from a DVB
+ Common Access facility.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOSYS</para>
+</entry><entry
+ align="char">
+<para>No descrambling facility available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>descramble_section_payload()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function runs a descrambling algorithm on the payload of a DVB
+ Datagram Section, replacing the original payload with its un-encrypted
+ version. The function will be called from the demux API implementation;
+ the API client need not call this function directly. Section-level scrambling
+ algorithms are currently standardized only for DVB-RCC (return channel
+ over 2-directional cable TV network) systems. For all other DVB networks,
+ encryption schemes are likely to be proprietary to each data broadcaster. Thus,
+ it is expected that this function pointer will have the value of NULL (i.e.,
+ function not available) in most demux API implementations. Nevertheless, it
+ should be possible to use the function pointer as a hook for dynamically adding
+ a &#8220;plug-in&#8221; descrambling facility to a demux driver.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>While this function is not needed with hardware-based section descrambling,
+ the descramble_section_payload function pointer can be used to override the
+ default hardware-based descrambling algorithm: if the function pointer has a
+ non-NULL value, the corresponding function should be used instead of any
+ descrambling hardware.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int descramble_section_payload(dmx_demux_t&#x22C6; demux,
+ __u8 &#x22C6;buffer1, size_t buffer1_length, __u8 &#x22C6;buffer2,
+ size_t buffer2_length, __u16 pid);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_demux_t
+ *demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u8 *buffer1</para>
+</entry><entry
+ align="char">
+<para>Pointer to the first byte of the section.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t buffer1_length</para>
+</entry><entry
+ align="char">
+<para>Length of the section data, including headers and CRC,
+ in buffer1.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u8 *buffer2</para>
+</entry><entry
+ align="char">
+<para>Pointer to the tail of the section data, or NULL. The
+ pointer has a non-NULL value if the section wraps past
+ the end of a circular buffer.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t buffer2_length</para>
+</entry><entry
+ align="char">
+<para>Length of the section data, including headers and CRC,
+ in buffer2.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16 pid</para>
+</entry><entry
+ align="char">
+<para>The PID on which the section was received. Useful
+ for obtaining the descrambling key, e.g. from a DVB
+ Common Access facility.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOSYS</para>
+</entry><entry
+ align="char">
+<para>No descrambling facility available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>add_frontend()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Registers a connectivity between a demux and a front-end, i.e., indicates that
+ the demux can be connected via a call to connect_frontend() to use the given
+ front-end as a TS source. The client of this function has to allocate dynamic or
+ static memory for the frontend structure and initialize its fields before calling
+ this function. This function is normally called during the driver initialization.
+ The caller must not free the memory of the frontend struct before successfully
+ calling remove_frontend().</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int add_frontend(dmx_demux_t &#x22C6;demux, dmx_frontend_t
+ &#x22C6;frontend);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_demux_t*
+ demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_frontend_t*
+ frontend</para>
+</entry><entry
+ align="char">
+<para>Pointer to the front-end instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EEXIST</para>
+</entry><entry
+ align="char">
+<para>A front-end with the same value of the id field already
+ registered.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINUSE</para>
+</entry><entry
+ align="char">
+<para>The demux is in use.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOMEM</para>
+</entry><entry
+ align="char">
+<para>No more front-ends can be added.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>remove_frontend()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Indicates that the given front-end, registered by a call to add_frontend(), can
+ no longer be connected as a TS source by this demux. The function should be
+ called when a front-end driver or a demux driver is removed from the system.
+ If the front-end is in use, the function fails with the return value of -EBUSY.
+ After successfully calling this function, the caller can free the memory of
+ the frontend struct if it was dynamically allocated before the add_frontend()
+ operation.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int remove_frontend(dmx_demux_t&#x22C6; demux,
+ dmx_frontend_t&#x22C6; frontend);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_demux_t*
+ demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_frontend_t*
+ frontend</para>
+</entry><entry
+ align="char">
+<para>Pointer to the front-end instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EBUSY</para>
+</entry><entry
+ align="char">
+<para>The front-end is in use, i.e. a call to connect_frontend()
+ has not been followed by a call to disconnect_frontend().</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>get_frontends()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Provides the APIs of the front-ends that have been registered for this demux.
+ Any of the front-ends obtained with this call can be used as a parameter for
+ connect_frontend().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>The include file demux.h contains the macro DMX_FE_ENTRY() for
+ converting an element of the generic type struct list_head* to the type
+ dmx_frontend_t*. The caller must not free the memory of any of the elements
+ obtained via this function call.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>struct list_head&#x22C6; get_frontends(dmx_demux_t&#x22C6; demux);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_demux_t*
+ demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_demux_t*</para>
+</entry><entry
+ align="char">
+<para>A list of front-end interfaces, or NULL in the case of an
+ empty list.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>connect_frontend()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Connects the TS output of the front-end to the input of the demux. A demux
+ can only be connected to a front-end registered to the demux with the function
+ add_frontend().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>It may or may not be possible to connect multiple demuxes to the same
+ front-end, depending on the capabilities of the HW platform. When not used,
+ the front-end should be released by calling disconnect_frontend().</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int connect_frontend(dmx_demux_t&#x22C6; demux,
+ dmx_frontend_t&#x22C6; frontend);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_demux_t*
+ demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_frontend_t*
+ frontend</para>
+</entry><entry
+ align="char">
+<para>Pointer to the front-end instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EBUSY</para>
+</entry><entry
+ align="char">
+<para>The front-end is in use.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>disconnect_frontend()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Disconnects the demux and a front-end previously connected by a
+ connect_frontend() call.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int disconnect_frontend(dmx_demux_t&#x22C6; demux);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_demux_t*
+ demux</para>
+</entry><entry
+ align="char">
+<para>Pointer to the demux API and instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+ </section></section>
+<section id="demux_callback_api">
+<title>Demux Callback API</title>
+<para>This kernel-space API comprises the callback functions that deliver filtered data to the
+demux client. Unlike the other APIs, these API functions are provided by the client and called
+from the demux code.
+</para>
+<para>The function pointers of this abstract interface are not packed into a structure as in the
+other demux APIs, because the callback functions are registered and used independent
+of each other. As an example, it is possible for the API client to provide several
+callback functions for receiving TS packets and no callbacks for PES packets or
+sections.
+</para>
+<para>The functions that implement the callback API need not be re-entrant: when a demux
+driver calls one of these functions, the driver is not allowed to call the function again before
+the original call returns. If a callback is triggered by a hardware interrupt, it is recommended
+to use the Linux &#8220;bottom half&#8221; mechanism or start a tasklet instead of making the callback
+function call directly from a hardware interrupt.
+</para>
+
+<section
+role="subsection"><title>dmx_ts_cb()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function, provided by the client of the demux API, is called from the
+ demux code. The function is only called when filtering on this TS feed has
+ been enabled using the start_filtering() function.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>Any TS packets that match the filter settings are copied to a circular buffer. The
+ filtered TS packets are delivered to the client using this callback function. The
+ size of the circular buffer is controlled by the circular_buffer_size parameter
+ of the set() function in the TS Feed API. It is expected that the buffer1 and
+ buffer2 callback parameters point to addresses within the circular buffer, but
+ other implementations are also possible. Note that the called party should not
+ try to free the memory the buffer1 and buffer2 parameters point to.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>When this function is called, the buffer1 parameter typically points to the
+ start of the first undelivered TS packet within a circular buffer. The buffer2
+ buffer parameter is normally NULL, except when the received TS packets have
+ crossed the last address of the circular buffer and &#8221;wrapped&#8221; to the beginning
+ of the buffer. In the latter case the buffer1 parameter would contain an address
+ within the circular buffer, while the buffer2 parameter would contain the first
+ address of the circular buffer.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>The number of bytes delivered with this function (i.e. buffer1_length +
+ buffer2_length) is usually equal to the value of callback_length parameter
+ given in the set() function, with one exception: if a timeout occurs before
+ receiving callback_length bytes of TS data, any undelivered packets are
+ immediately delivered to the client by calling this function. The timeout
+ duration is controlled by the set() function in the TS Feed API.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>If a TS packet is received with errors that could not be fixed by the TS-level
+ forward error correction (FEC), the Transport_error_indicator flag of the TS
+ packet header should be set. The TS packet should not be discarded, as
+ the error can possibly be corrected by a higher layer protocol. If the called
+ party is slow in processing the callback, it is possible that the circular buffer
+ eventually fills up. If this happens, the demux driver should discard any TS
+ packets received while the buffer is full. The error should be indicated to the
+ client on the next callback by setting the success parameter to the value of
+ DMX_OVERRUN_ERROR.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>The type of data returned to the callback can be selected by the new
+ function int (*set_type) (struct dmx_ts_feed_s* feed, int type, dmx_ts_pes_t
+ pes_type) which is part of the dmx_ts_feed_s struct (also cf. to the
+ include file ost/demux.h) The type parameter decides if the raw TS packet
+ (TS_PACKET) or just the payload (TS_PACKET&#8212;TS_PAYLOAD_ONLY)
+ should be returned. If additionally the TS_DECODER bit is set the stream
+ will also be sent to the hardware MPEG decoder. In this case, the second
+ flag decides as what kind of data the stream should be interpreted. The
+ possible choices are one of DMX_TS_PES_AUDIO, DMX_TS_PES_VIDEO,
+ DMX_TS_PES_TELETEXT, DMX_TS_PES_SUBTITLE,
+ DMX_TS_PES_PCR, or DMX_TS_PES_OTHER.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int dmx_ts_cb(__u8&#x22C6; buffer1, size_t buffer1_length,
+ __u8&#x22C6; buffer2, size_t buffer2_length, dmx_ts_feed_t&#x22C6;
+ source, dmx_success_t success);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>__u8* buffer1</para>
+</entry><entry
+ align="char">
+<para>Pointer to the start of the filtered TS packets.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t buffer1_length</para>
+</entry><entry
+ align="char">
+<para>Length of the TS data in buffer1.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u8* buffer2</para>
+</entry><entry
+ align="char">
+<para>Pointer to the tail of the filtered TS packets, or NULL.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t buffer2_length</para>
+</entry><entry
+ align="char">
+<para>Length of the TS data in buffer2.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_ts_feed_t*
+ source</para>
+</entry><entry
+ align="char">
+<para>Indicates which TS feed is the source of the callback.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_success_t
+ success</para>
+</entry><entry
+ align="char">
+<para>Indicates if there was an error in TS reception.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>Continue filtering.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-1</para>
+</entry><entry
+ align="char">
+<para>Stop filtering - has the same effect as a call to
+ stop_filtering() on the TS Feed API.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>dmx_section_cb()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function, provided by the client of the demux API, is called from the
+ demux code. The function is only called when filtering of sections has been
+ enabled using the function start_filtering() of the section feed API. When the
+ demux driver has received a complete section that matches at least one section
+ filter, the client is notified via this callback function. Normally this function is
+ called for each received section; however, it is also possible to deliver multiple
+ sections with one callback, for example when the system load is high. If an
+ error occurs while receiving a section, this function should be called with
+ the corresponding error type set in the success field, whether or not there is
+ data to deliver. The Section Feed implementation should maintain a circular
+ buffer for received sections. However, this is not necessary if the Section Feed
+ API is implemented as a client of the TS Feed API, because the TS Feed
+ implementation then buffers the received data. The size of the circular buffer
+ can be configured using the set() function in the Section Feed API. If there
+ is no room in the circular buffer when a new section is received, the section
+ must be discarded. If this happens, the value of the success parameter should
+ be DMX_OVERRUN_ERROR on the next callback.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int dmx_section_cb(__u8&#x22C6; buffer1, size_t
+ buffer1_length, __u8&#x22C6; buffer2, size_t
+ buffer2_length, dmx_section_filter_t&#x22C6; source,
+ dmx_success_t success);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>__u8* buffer1</para>
+</entry><entry
+ align="char">
+<para>Pointer to the start of the filtered section, e.g. within the
+ circular buffer of the demux driver.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t buffer1_length</para>
+</entry><entry
+ align="char">
+<para>Length of the filtered section data in buffer1, including
+ headers and CRC.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u8* buffer2</para>
+</entry><entry
+ align="char">
+<para>Pointer to the tail of the filtered section data, or NULL.
+ Useful to handle the wrapping of a circular buffer.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t buffer2_length</para>
+</entry><entry
+ align="char">
+<para>Length of the filtered section data in buffer2, including
+ headers and CRC.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_section_filter_t*
+ filter</para>
+</entry><entry
+ align="char">
+<para>Indicates the filter that triggered the callback.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_success_t
+ success</para>
+</entry><entry
+ align="char">
+<para>Indicates if there was an error in section reception.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>Continue filtering.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-1</para>
+</entry><entry
+ align="char">
+<para>Stop filtering - has the same effect as a call to
+ stop_filtering() on the Section Feed API.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+ </section></section>
+<section id="ts_feed_api">
+<title>TS Feed API</title>
+<para>A TS feed is typically mapped to a hardware PID filter on the demux chip.
+Using this API, the client can set the filtering properties to start/stop filtering TS
+packets on a particular TS feed. The API is defined as an abstract interface of the type
+dmx_ts_feed_t.
+</para>
+<para>The functions that implement the interface should be defined static or module private. The
+client can get the handle of a TS feed API by calling the function allocate_ts_feed() in the
+demux API.
+</para>
+
+<section
+role="subsection"><title>set()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function sets the parameters of a TS feed. Any filtering in progress on the
+ TS feed must be stopped before calling this function.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int set ( dmx_ts_feed_t&#x22C6; feed, __u16 pid, size_t
+ callback_length, size_t circular_buffer_size, int
+ descramble, struct timespec timeout);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_ts_feed_t* feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the TS feed API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16 pid</para>
+</entry><entry
+ align="char">
+<para>PID value to filter. Only the TS packets carrying the
+ specified PID will be passed to the API client.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t
+ callback_length</para>
+</entry><entry
+ align="char">
+<para>Number of bytes to deliver with each call to the
+ dmx_ts_cb() callback function. The value of this
+ parameter should be a multiple of 188.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t
+ circular_buffer_size</para>
+</entry><entry
+ align="char">
+<para>Size of the circular buffer for the filtered TS packets.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int descramble</para>
+</entry><entry
+ align="char">
+<para>If non-zero, descramble the filtered TS packets.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct timespec
+ timeout</para>
+</entry><entry
+ align="char">
+<para>Maximum time to wait before delivering received TS
+ packets to the client.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOMEM</para>
+</entry><entry
+ align="char">
+<para>Not enough memory for the requested buffer size.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOSYS</para>
+</entry><entry
+ align="char">
+<para>No descrambling facility available for TS.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>start_filtering()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Starts filtering TS packets on this TS feed, according to its settings. The PID
+ value to filter can be set by the API client. All matching TS packets are
+ delivered asynchronously to the client, using the callback function registered
+ with allocate_ts_feed().</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int start_filtering(dmx_ts_feed_t&#x22C6; feed);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_ts_feed_t* feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the TS feed API and instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>stop_filtering()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Stops filtering TS packets on this TS feed.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int stop_filtering(dmx_ts_feed_t&#x22C6; feed);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_ts_feed_t* feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the TS feed API and instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+ </section></section>
+<section id="section_feed_api">
+<title>Section Feed API</title>
+<para>A section feed is a resource consisting of a PID filter and a set of section filters. Using this
+API, the client can set the properties of a section feed and to start/stop filtering. The API is
+defined as an abstract interface of the type dmx_section_feed_t. The functions that implement
+the interface should be defined static or module private. The client can get the handle of
+a section feed API by calling the function allocate_section_feed() in the demux
+API.
+</para>
+<para>On demux platforms that provide section filtering in hardware, the Section Feed API
+implementation provides a software wrapper for the demux hardware. Other platforms may
+support only PID filtering in hardware, requiring that TS packets are converted to sections in
+software. In the latter case the Section Feed API implementation can be a client of the TS
+Feed API.
+</para>
+
+</section>
+<section id="kdapi_set">
+<title>set()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function sets the parameters of a section feed. Any filtering in progress on
+ the section feed must be stopped before calling this function. If descrambling
+ is enabled, the payload_scrambling_control and address_scrambling_control
+ fields of received DVB datagram sections should be observed. If either one is
+ non-zero, the section should be descrambled either in hardware or using the
+ functions descramble_mac_address() and descramble_section_payload() of the
+ demux API. Note that according to the MPEG-2 Systems specification, only
+ the payloads of private sections can be scrambled while the rest of the section
+ data must be sent in the clear.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int set(dmx_section_feed_t&#x22C6; feed, __u16 pid, size_t
+ circular_buffer_size, int descramble, int
+ check_crc);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_section_feed_t*
+ feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the section feed API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16 pid</para>
+</entry><entry
+ align="char">
+<para>PID value to filter; only the TS packets carrying the
+ specified PID will be accepted.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t
+ circular_buffer_size</para>
+</entry><entry
+ align="char">
+<para>Size of the circular buffer for filtered sections.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int descramble</para>
+</entry><entry
+ align="char">
+<para>If non-zero, descramble any sections that are scrambled.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int check_crc</para>
+</entry><entry
+ align="char">
+<para>If non-zero, check the CRC values of filtered sections.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOMEM</para>
+</entry><entry
+ align="char">
+<para>Not enough memory for the requested buffer size.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOSYS</para>
+</entry><entry
+ align="char">
+<para>No descrambling facility available for sections.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameters.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>allocate_filter()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function is used to allocate a section filter on the demux. It should only be
+ called when no filtering is in progress on this section feed. If a filter cannot be
+ allocated, the function fails with -ENOSPC. See in section ?? for the format of
+ the section filter.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>The bitfields filter_mask and filter_value should only be modified when no
+ filtering is in progress on this section feed. filter_mask controls which bits of
+ filter_value are compared with the section headers/payload. On a binary value
+ of 1 in filter_mask, the corresponding bits are compared. The filter only accepts
+ sections that are equal to filter_value in all the tested bit positions. Any changes
+ to the values of filter_mask and filter_value are guaranteed to take effect only
+ when the start_filtering() function is called next time. The parent pointer in
+ the struct is initialized by the API implementation to the value of the feed
+ parameter. The priv pointer is not used by the API implementation, and can
+ thus be freely utilized by the caller of this function. Any data pointed to by the
+ priv pointer is available to the recipient of the dmx_section_cb() function call.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>While the maximum section filter length (DMX_MAX_FILTER_SIZE) is
+ currently set at 16 bytes, hardware filters of that size are not available on all
+ platforms. Therefore, section filtering will often take place first in hardware,
+ followed by filtering in software for the header bytes that were not covered
+ by a hardware filter. The filter_mask field can be checked to determine how
+ many bytes of the section filter are actually used, and if the hardware filter will
+ suffice. Additionally, software-only section filters can optionally be allocated
+ to clients when all hardware section filters are in use. Note that on most demux
+ hardware it is not possible to filter on the section_length field of the section
+ header &#8211; thus this field is ignored, even though it is included in filter_value and
+ filter_mask fields.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int allocate_filter(dmx_section_feed_t&#x22C6; feed,
+ dmx_section_filter_t&#x22C6;&#x22C6; filter);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_section_feed_t*
+ feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the section feed API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_section_filter_t**
+ filter</para>
+</entry><entry
+ align="char">
+<para>Pointer to the allocated filter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENOSPC</para>
+</entry><entry
+ align="char">
+<para>No filters of given type and length available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameters.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>release_filter()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This function releases all the resources of a previously allocated section filter.
+ The function should not be called while filtering is in progress on this section
+ feed. After calling this function, the caller should not try to dereference the
+ filter pointer.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int release_filter ( dmx_section_feed_t&#x22C6; feed,
+ dmx_section_filter_t&#x22C6; filter);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_section_feed_t*
+ feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the section feed API and instance data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_section_filter_t*
+ filter</para>
+</entry><entry
+ align="char">
+<para>I/O Pointer to the instance data of a section filter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-ENODEV</para>
+</entry><entry
+ align="char">
+<para>No such filter allocated.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>start_filtering()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Starts filtering sections on this section feed, according to its settings. Sections
+ are first filtered based on their PID and then matched with the section
+ filters allocated for this feed. If the section matches the PID filter and
+ at least one section filter, it is delivered to the API client. The section
+ is delivered asynchronously using the callback function registered with
+ allocate_section_feed().</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int start_filtering ( dmx_section_feed_t&#x22C6; feed );</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_section_feed_t*
+ feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the section feed API and instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section
+role="subsection"><title>stop_filtering()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>Stops filtering sections on this section feed. Note that any changes to the
+ filtering parameters (filter_value, filter_mask, etc.) should only be made when
+ filtering is stopped.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int stop_filtering ( dmx_section_feed_t&#x22C6; feed );</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>dmx_section_feed_t*
+ feed</para>
+</entry><entry
+ align="char">
+<para>Pointer to the section feed API and instance data.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURNS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>0</para>
+</entry><entry
+ align="char">
+<para>The function was completed without errors.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>-EINVAL</para>
+</entry><entry
+ align="char">
+<para>Bad parameter.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section>
diff --git a/Documentation/DocBook/media/dvb/net.xml b/Documentation/DocBook/media/dvb/net.xml
new file mode 100644 (file)
index 0000000..67d37e5
--- /dev/null
@@ -0,0 +1,29 @@
+<title>DVB Network API</title>
+<para>The DVB net device enables feeding of MPE (multi protocol encapsulation) packets
+received via DVB into the Linux network protocol stack, e.g. for internet via satellite
+applications. It can be accessed through <emphasis role="tt">/dev/dvb/adapter0/net0</emphasis>. Data types and
+and ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/net.h</emphasis> in your
+application.
+</para>
+<section id="dvb_net_types">
+<title>DVB Net Data Types</title>
+
+<section id="dvb-net-if">
+<title>struct dvb_net_if</title>
+<programlisting>
+struct dvb_net_if {
+       __u16 pid;
+       __u16 if_num;
+       __u8  feedtype;
+#define DVB_NET_FEEDTYPE_MPE 0 /&#x22C6; multi protocol encapsulation &#x22C6;/
+#define DVB_NET_FEEDTYPE_ULE 1 /&#x22C6; ultra lightweight encapsulation &#x22C6;/
+};
+</programlisting>
+</section>
+
+</section>
+<section id="net_fcalls">
+<title>DVB net Function Calls</title>
+<para>To be written&#x2026;
+</para>
+</section>
diff --git a/Documentation/DocBook/media/dvb/video.xml b/Documentation/DocBook/media/dvb/video.xml
new file mode 100644 (file)
index 0000000..25fb823
--- /dev/null
@@ -0,0 +1,1657 @@
+<title>DVB Video Device</title>
+<para>The DVB video device controls the MPEG2 video decoder of the DVB hardware. It
+can be accessed through <emphasis role="tt">/dev/dvb/adapter0/video0</emphasis>. Data types and and
+ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/video.h</emphasis> in your
+application.
+</para>
+<para>Note that the DVB video device only controls decoding of the MPEG video stream, not
+its presentation on the TV or computer screen. On PCs this is typically handled by an
+associated video4linux device, e.g. <emphasis role="tt">/dev/video</emphasis>, which allows scaling and defining output
+windows.
+</para>
+<para>Some DVB cards don&#8217;t have their own MPEG decoder, which results in the omission of
+the audio and video device as well as the video4linux device.
+</para>
+<para>The ioctls that deal with SPUs (sub picture units) and navigation packets are only
+supported on some MPEG decoders made for DVD playback.
+</para>
+<section id="video_types">
+<title>Video Data Types</title>
+
+<section id="video-format-t">
+<title>video_format_t</title>
+<para>The <emphasis role="tt">video_format_t</emphasis> data type defined by
+</para>
+<programlisting>
+typedef enum {
+       VIDEO_FORMAT_4_3,     /&#x22C6; Select 4:3 format &#x22C6;/
+       VIDEO_FORMAT_16_9,    /&#x22C6; Select 16:9 format. &#x22C6;/
+       VIDEO_FORMAT_221_1    /&#x22C6; 2.21:1 &#x22C6;/
+} video_format_t;
+</programlisting>
+<para>is used in the VIDEO_SET_FORMAT function (??) to tell the driver which aspect ratio
+the output hardware (e.g. TV) has. It is also used in the data structures video_status
+(??) returned by VIDEO_GET_STATUS (??) and video_event (??) returned by
+VIDEO_GET_EVENT (??) which report about the display format of the current video
+stream.
+</para>
+</section>
+
+<section id="video-displayformat-t">
+<title>video_displayformat_t</title>
+<para>In case the display format of the video stream and of the display hardware differ the
+application has to specify how to handle the cropping of the picture. This can be done using
+the VIDEO_SET_DISPLAY_FORMAT call (??) which accepts
+</para>
+<programlisting>
+typedef enum {
+       VIDEO_PAN_SCAN,       /&#x22C6; use pan and scan format &#x22C6;/
+       VIDEO_LETTER_BOX,     /&#x22C6; use letterbox format &#x22C6;/
+       VIDEO_CENTER_CUT_OUT  /&#x22C6; use center cut out format &#x22C6;/
+} video_displayformat_t;
+</programlisting>
+<para>as argument.
+</para>
+</section>
+
+<section id="video-stream-source-t">
+<title>video stream source</title>
+<para>The video stream source is set through the VIDEO_SELECT_SOURCE call and can take
+the following values, depending on whether we are replaying from an internal (demuxer) or
+external (user write) source.
+</para>
+<programlisting>
+typedef enum {
+       VIDEO_SOURCE_DEMUX, /&#x22C6; Select the demux as the main source &#x22C6;/
+       VIDEO_SOURCE_MEMORY /&#x22C6; If this source is selected, the stream
+                              comes from the user through the write
+                              system call &#x22C6;/
+} video_stream_source_t;
+</programlisting>
+<para>VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the frontend or the
+DVR device) as the source of the video stream. If VIDEO_SOURCE_MEMORY
+is selected the stream comes from the application through the <emphasis role="tt">write()</emphasis> system
+call.
+</para>
+</section>
+
+<section id="video-play-state-t">
+<title>video play state</title>
+<para>The following values can be returned by the VIDEO_GET_STATUS call representing the
+state of video playback.
+</para>
+<programlisting>
+typedef enum {
+       VIDEO_STOPPED, /&#x22C6; Video is stopped &#x22C6;/
+       VIDEO_PLAYING, /&#x22C6; Video is currently playing &#x22C6;/
+       VIDEO_FREEZED  /&#x22C6; Video is freezed &#x22C6;/
+} video_play_state_t;
+</programlisting>
+</section>
+
+<section id="video-command">
+<para>The structure must be zeroed before use by the application
+This ensures it can be extended safely in the future.</para>
+<title>struct video-command</title>
+<programlisting>
+struct video_command {
+       __u32 cmd;
+       __u32 flags;
+       union {
+               struct {
+                       __u64 pts;
+               } stop;
+
+               struct {
+                       /&#x22C6; 0 or 1000 specifies normal speed,
+                          1 specifies forward single stepping,
+                          -1 specifies backward single stepping,
+                          &gt;>1: playback at speed/1000 of the normal speed,
+                          &lt;-1: reverse playback at (-speed/1000) of the normal speed. &#x22C6;/
+                       __s32 speed;
+                       __u32 format;
+               } play;
+
+               struct {
+                       __u32 data[16];
+               } raw;
+       };
+};
+</programlisting>
+</section>
+
+<section id="video-size-t">
+<title>struct video_size-t</title>
+<programlisting>
+typedef struct {
+       int w;
+       int h;
+       video_format_t aspect_ratio;
+} video_size_t;
+</programlisting>
+</section>
+
+
+<section id="video-event">
+<title>struct video_event</title>
+<para>The following is the structure of a video event as it is returned by the VIDEO_GET_EVENT
+call.
+</para>
+<programlisting>
+struct video_event {
+       __s32 type;
+#define VIDEO_EVENT_SIZE_CHANGED       1
+#define VIDEO_EVENT_FRAME_RATE_CHANGED 2
+#define VIDEO_EVENT_DECODER_STOPPED    3
+#define VIDEO_EVENT_VSYNC              4
+       __kernel_time_t timestamp;
+       union {
+               video_size_t size;
+               unsigned int frame_rate;        /&#x22C6; in frames per 1000sec &#x22C6;/
+               unsigned char vsync_field;      /&#x22C6; unknown/odd/even/progressive &#x22C6;/
+       } u;
+};
+</programlisting>
+</section>
+
+<section id="video-status">
+<title>struct video_status</title>
+<para>The VIDEO_GET_STATUS call returns the following structure informing about various
+states of the playback operation.
+</para>
+<programlisting>
+struct video_status {
+       int                   video_blank;   /&#x22C6; blank video on freeze? &#x22C6;/
+       video_play_state_t    play_state;    /&#x22C6; current state of playback &#x22C6;/
+       video_stream_source_t stream_source; /&#x22C6; current source (demux/memory) &#x22C6;/
+       video_format_t        video_format;  /&#x22C6; current aspect ratio of stream &#x22C6;/
+       video_displayformat_t display_format;/&#x22C6; selected cropping mode &#x22C6;/
+};
+</programlisting>
+<para>If video_blank is set video will be blanked out if the channel is changed or if playback is
+stopped. Otherwise, the last picture will be displayed. play_state indicates if the video is
+currently frozen, stopped, or being played back. The stream_source corresponds to the seleted
+source for the video stream. It can come either from the demultiplexer or from memory.
+The video_format indicates the aspect ratio (one of 4:3 or 16:9) of the currently
+played video stream. Finally, display_format corresponds to the selected cropping
+mode in case the source video format is not the same as the format of the output
+device.
+</para>
+</section>
+
+<section id="video-still-picture">
+<title>struct video_still_picture</title>
+<para>An I-frame displayed via the VIDEO_STILLPICTURE call is passed on within the
+following structure.
+</para>
+<programlisting>
+/&#x22C6; pointer to and size of a single iframe in memory &#x22C6;/
+struct video_still_picture {
+       char &#x22C6;iFrame;        /&#x22C6; pointer to a single iframe in memory &#x22C6;/
+       int32_t size;
+};
+</programlisting>
+</section>
+
+<section id="video_caps">
+<title>video capabilities</title>
+<para>A call to VIDEO_GET_CAPABILITIES returns an unsigned integer with the following
+bits set according to the hardwares capabilities.
+</para>
+<programlisting>
+ /&#x22C6; bit definitions for capabilities: &#x22C6;/
+ /&#x22C6; can the hardware decode MPEG1 and/or MPEG2? &#x22C6;/
+ #define VIDEO_CAP_MPEG1   1
+ #define VIDEO_CAP_MPEG2   2
+ /&#x22C6; can you send a system and/or program stream to video device?
+    (you still have to open the video and the audio device but only
+     send the stream to the video device) &#x22C6;/
+ #define VIDEO_CAP_SYS     4
+ #define VIDEO_CAP_PROG    8
+ /&#x22C6; can the driver also handle SPU, NAVI and CSS encoded data?
+    (CSS API is not present yet) &#x22C6;/
+ #define VIDEO_CAP_SPU    16
+ #define VIDEO_CAP_NAVI   32
+ #define VIDEO_CAP_CSS    64
+</programlisting>
+</section>
+
+<section id="video-system">
+<title>video system</title>
+<para>A call to VIDEO_SET_SYSTEM sets the desired video system for TV output. The
+following system types can be set:
+</para>
+<programlisting>
+typedef enum {
+        VIDEO_SYSTEM_PAL,
+        VIDEO_SYSTEM_NTSC,
+        VIDEO_SYSTEM_PALN,
+        VIDEO_SYSTEM_PALNc,
+        VIDEO_SYSTEM_PALM,
+        VIDEO_SYSTEM_NTSC60,
+        VIDEO_SYSTEM_PAL60,
+        VIDEO_SYSTEM_PALM60
+} video_system_t;
+</programlisting>
+</section>
+
+<section id="video-highlight">
+<title>struct video_highlight</title>
+<para>Calling the ioctl VIDEO_SET_HIGHLIGHTS posts the SPU highlight information. The
+call expects the following format for that information:
+</para>
+<programlisting>
+ typedef
+ struct video_highlight {
+        boolean active;      /&#x22C6;    1=show highlight, 0=hide highlight &#x22C6;/
+        uint8_t contrast1;   /&#x22C6;    7- 4  Pattern pixel contrast &#x22C6;/
+                             /&#x22C6;    3- 0  Background pixel contrast &#x22C6;/
+        uint8_t contrast2;   /&#x22C6;    7- 4  Emphasis pixel-2 contrast &#x22C6;/
+                             /&#x22C6;    3- 0  Emphasis pixel-1 contrast &#x22C6;/
+        uint8_t color1;      /&#x22C6;    7- 4  Pattern pixel color &#x22C6;/
+                             /&#x22C6;    3- 0  Background pixel color &#x22C6;/
+        uint8_t color2;      /&#x22C6;    7- 4  Emphasis pixel-2 color &#x22C6;/
+                             /&#x22C6;    3- 0  Emphasis pixel-1 color &#x22C6;/
+        uint32_t ypos;       /&#x22C6;   23-22  auto action mode &#x22C6;/
+                             /&#x22C6;   21-12  start y &#x22C6;/
+                             /&#x22C6;    9- 0  end y &#x22C6;/
+        uint32_t xpos;       /&#x22C6;   23-22  button color number &#x22C6;/
+                             /&#x22C6;   21-12  start x &#x22C6;/
+                             /&#x22C6;    9- 0  end x &#x22C6;/
+ } video_highlight_t;
+</programlisting>
+
+</section>
+<section id="video-spu">
+<title>video SPU</title>
+<para>Calling VIDEO_SET_SPU deactivates or activates SPU decoding, according to the
+following format:
+</para>
+<programlisting>
+ typedef
+ struct video_spu {
+        boolean active;
+        int stream_id;
+ } video_spu_t;
+</programlisting>
+
+</section>
+<section id="video-spu-palette">
+<title>video SPU palette</title>
+<para>The following structure is used to set the SPU palette by calling VIDEO_SPU_PALETTE:
+</para>
+<programlisting>
+ typedef
+ struct video_spu_palette{
+        int length;
+        uint8_t &#x22C6;palette;
+ } video_spu_palette_t;
+</programlisting>
+
+</section>
+<section id="video-navi-pack">
+<title>video NAVI pack</title>
+<para>In order to get the navigational data the following structure has to be passed to the ioctl
+VIDEO_GET_NAVI:
+</para>
+<programlisting>
+ typedef
+ struct video_navi_pack{
+        int length;         /&#x22C6; 0 ... 1024 &#x22C6;/
+        uint8_t data[1024];
+ } video_navi_pack_t;
+</programlisting>
+</section>
+
+
+<section id="video-attributes-t">
+<title>video attributes</title>
+<para>The following attributes can be set by a call to VIDEO_SET_ATTRIBUTES:
+</para>
+<programlisting>
+ typedef uint16_t video_attributes_t;
+ /&#x22C6;   bits: descr. &#x22C6;/
+ /&#x22C6;   15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) &#x22C6;/
+ /&#x22C6;   13-12 TV system (0=525/60, 1=625/50) &#x22C6;/
+ /&#x22C6;   11-10 Aspect ratio (0=4:3, 3=16:9) &#x22C6;/
+ /&#x22C6;    9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-sca &#x22C6;/
+ /&#x22C6;    7    line 21-1 data present in GOP (1=yes, 0=no) &#x22C6;/
+ /&#x22C6;    6    line 21-2 data present in GOP (1=yes, 0=no) &#x22C6;/
+ /&#x22C6;    5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 &#x22C6;/
+ /&#x22C6;    2    source letterboxed (1=yes, 0=no) &#x22C6;/
+ /&#x22C6;    0    film/camera mode (0=camera, 1=film (625/50 only)) &#x22C6;/
+</programlisting>
+</section></section>
+
+
+<section id="video_function_calls">
+<title>Video Function Calls</title>
+
+
+<section id="video_fopen">
+<title>open()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call opens a named video device (e.g. /dev/dvb/adapter0/video0)
+ for subsequent use.</para>
+<para>When an open() call has succeeded, the device will be ready for use.
+ The significance of blocking or non-blocking mode is described in the
+ documentation for functions where there is a difference. It does not affect the
+ semantics of the open() call itself. A device opened in blocking mode can later
+ be put into non-blocking mode (and vice versa) using the F_SETFL command
+ of the fcntl system call. This is a standard system call, documented in the Linux
+ manual page for fcntl. Only one user can open the Video Device in O_RDWR
+ mode. All other attempts to open the device in this mode will fail, and an
+ error-code will be returned. If the Video Device is opened in O_RDONLY
+ mode, the only ioctl call that can be used is VIDEO_GET_STATUS. All other
+ call will return an error code.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int open(const char &#x22C6;deviceName, int flags);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>const char
+ *deviceName</para>
+</entry><entry
+ align="char">
+<para>Name of specific video device.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int flags</para>
+</entry><entry
+ align="char">
+<para>A bit-wise OR of the following flags:</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_RDONLY read-only access</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_RDWR read/write access</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>O_NONBLOCK open in non-blocking mode</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>(blocking mode is the default)</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>ENODEV</para>
+</entry><entry
+ align="char">
+<para>Device driver not loaded/available.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EINTERNAL</para>
+</entry><entry
+ align="char">
+<para>Internal error.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBUSY</para>
+</entry><entry
+ align="char">
+<para>Device or resource busy.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Invalid argument.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section>
+<section id="video_fclose">
+<title>close()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call closes a previously opened video device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int close(int fd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EBADF</para>
+</entry><entry
+ align="char">
+<para>fd is not a valid open file descriptor.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section>
+<section id="video_fwrite">
+<title>write()</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This system call can only be used if VIDEO_SOURCE_MEMORY is selected
+ in the ioctl call VIDEO_SELECT_SOURCE. The data provided shall be in
+ PES format, unless the capability allows other formats. If O_NONBLOCK is
+ not specified the function will block until buffer space is available. The amount
+ of data to be transferred is implied by count.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>size_t write(int fd, const void &#x22C6;buf, size_t count);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>void *buf</para>
+</entry><entry
+ align="char">
+<para>Pointer to the buffer containing the PES data.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>size_t count</para>
+</entry><entry
+ align="char">
+<para>Size of buf.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>RETURN VALUE</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EPERM</para>
+</entry><entry
+ align="char">
+<para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ENOMEM</para>
+</entry><entry
+ align="char">
+<para>Attempted to write more data than the internal buffer can
+ hold.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EBADF</para>
+</entry><entry
+ align="char">
+<para>fd is not a valid open file descriptor.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="VIDEO_STOP"
+role="subsection"><title>VIDEO_STOP</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to stop playing the current stream.
+ Depending on the input parameter, the screen can be blanked out or displaying
+ the last decoded frame.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_STOP, boolean
+ mode);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_STOP for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>Boolean mode</para>
+</entry><entry
+ align="char">
+<para>Indicates how the screen shall be handled.</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>TRUE: Blank screen when stop.</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>FALSE: Show last decoded frame.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_PLAY"
+role="subsection"><title>VIDEO_PLAY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to start playing a video stream from the
+ selected source.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_PLAY);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_PLAY for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_FREEZE"
+role="subsection"><title>VIDEO_FREEZE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call suspends the live video stream being played. Decoding
+ and playing are frozen. It is then possible to restart the decoding
+ and playing process of the video stream using the VIDEO_CONTINUE
+ command. If VIDEO_SOURCE_MEMORY is selected in the ioctl call
+ VIDEO_SELECT_SOURCE, the DVB subsystem will not decode any more
+ data until the ioctl call VIDEO_CONTINUE or VIDEO_PLAY is performed.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_FREEZE);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_FREEZE for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_CONTINUE"
+role="subsection"><title>VIDEO_CONTINUE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call restarts decoding and playing processes of the video stream
+ which was played before a call to VIDEO_FREEZE was made.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_CONTINUE);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_CONTINUE for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_SELECT_SOURCE"
+role="subsection"><title>VIDEO_SELECT_SOURCE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call informs the video device which source shall be used for the input
+ data. The possible sources are demux or memory. If memory is selected, the
+ data is fed to the video device through the write command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_SELECT_SOURCE,
+ video_stream_source_t source);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SELECT_SOURCE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_stream_source_t
+ source</para>
+</entry><entry
+ align="char">
+<para>Indicates which source shall be used for the Video stream.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_SET_BLANK"
+role="subsection"><title>VIDEO_SET_BLANK</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to blank out the picture.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_SET_BLANK, boolean
+ mode);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SET_BLANK for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>boolean mode</para>
+</entry><entry
+ align="char">
+<para>TRUE: Blank screen when stop.</para>
+</entry>
+ </row><row><entry
+ align="char">
+</entry><entry
+ align="char">
+<para>FALSE: Show last decoded frame.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_STATUS"
+role="subsection"><title>VIDEO_GET_STATUS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to return the current status of the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(fd, int request = VIDEO_GET_STATUS, struct
+ video_status &#x22C6;status);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_STATUS for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct video_status
+ *status</para>
+</entry><entry
+ align="char">
+<para>Returns the current status of the Video Device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_EVENT"
+role="subsection"><title>VIDEO_GET_EVENT</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns an event of type video_event if available. If an event is
+ not available, the behavior depends on whether the device is in blocking or
+ non-blocking mode. In the latter case, the call fails immediately with errno
+ set to EWOULDBLOCK. In the former case, the call blocks until an event
+ becomes available. The standard Linux poll() and/or select() system calls can
+ be used with the device file descriptor to watch for new events. For select(),
+ the file descriptor should be included in the exceptfds argument, and for
+ poll(), POLLPRI should be specified as the wake-up condition. Read-only
+ permissions are sufficient for this ioctl call.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(fd, int request = VIDEO_GET_EVENT, struct
+ video_event &#x22C6;ev);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_EVENT for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct video_event
+ *ev</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the event, if any, is to be
+ stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EWOULDBLOCK</para>
+</entry><entry
+ align="char">
+<para>There is no event pending, and the device is in
+ non-blocking mode.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>EOVERFLOW</para>
+</entry><entry
+ align="char">
+<para>Overflow in event queue - one or more events were lost.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="VIDEO_SET_DISPLAY_FORMAT"
+role="subsection"><title>VIDEO_SET_DISPLAY_FORMAT</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to select the video format to be applied
+ by the MPEG chip on the video.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(fd, int request =
+ VIDEO_SET_DISPLAY_FORMAT, video_display_format_t
+ format);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SET_DISPLAY_FORMAT for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_display_format_t
+ format</para>
+</entry><entry
+ align="char">
+<para>Selects the video format to be used.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_STILLPICTURE"
+role="subsection"><title>VIDEO_STILLPICTURE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to display a still picture (I-frame). The
+ input data shall contain an I-frame. If the pointer is NULL, then the current
+ displayed still picture is blanked.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_STILLPICTURE,
+ struct video_still_picture &#x22C6;sp);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_STILLPICTURE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct
+ video_still_picture
+ *sp</para>
+</entry><entry
+ align="char">
+<para>Pointer to a location where an I-frame and size is stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_FAST_FORWARD"
+role="subsection"><title>VIDEO_FAST_FORWARD</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to skip decoding of N number of I-frames.
+ This call can only be used if VIDEO_SOURCE_MEMORY is selected.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_FAST_FORWARD, int
+ nFrames);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_FAST_FORWARD for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int nFrames</para>
+</entry><entry
+ align="char">
+<para>The number of frames to skip.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EPERM</para>
+</entry><entry
+ align="char">
+<para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="VIDEO_SLOWMOTION"
+role="subsection"><title>VIDEO_SLOWMOTION</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the video device to repeat decoding frames N number of
+ times. This call can only be used if VIDEO_SOURCE_MEMORY is selected.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_SLOWMOTION, int
+ nFrames);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SLOWMOTION for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int nFrames</para>
+</entry><entry
+ align="char">
+<para>The number of times to repeat each frame.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EPERM</para>
+</entry><entry
+ align="char">
+<para>Mode VIDEO_SOURCE_MEMORY not selected.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="VIDEO_GET_CAPABILITIES"
+role="subsection"><title>VIDEO_GET_CAPABILITIES</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the video device about its decoding capabilities. On success
+ it returns and integer which has bits set according to the defines in section ??.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_GET_CAPABILITIES,
+ unsigned int &#x22C6;cap);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_CAPABILITIES for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>unsigned int *cap</para>
+</entry><entry
+ align="char">
+<para>Pointer to a location where to store the capability
+ information.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_SET_ID"
+role="subsection"><title>VIDEO_SET_ID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl selects which sub-stream is to be decoded if a program or system
+ stream is sent to the video device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = VIDEO_SET_ID, int
+ id);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SET_ID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int id</para>
+</entry><entry
+ align="char">
+<para>video sub-stream id</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>Invalid sub-stream id.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="VIDEO_CLEAR_BUFFER"
+role="subsection"><title>VIDEO_CLEAR_BUFFER</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call clears all video buffers in the driver and in the decoder hardware.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_CLEAR_BUFFER);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_CLEAR_BUFFER for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_SET_STREAMTYPE"
+role="subsection"><title>VIDEO_SET_STREAMTYPE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl tells the driver which kind of stream to expect being written to it. If
+ this call is not used the default of video PES is used. Some drivers might not
+ support this call and always expect PES.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = VIDEO_SET_STREAMTYPE,
+ int type);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SET_STREAMTYPE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int type</para>
+</entry><entry
+ align="char">
+<para>stream type</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_SET_FORMAT"
+role="subsection"><title>VIDEO_SET_FORMAT</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl sets the screen format (aspect ratio) of the connected output device
+ (TV) so that the output of the decoder can be adjusted accordingly.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(fd, int request = VIDEO_SET_FORMAT,
+ video_format_t format);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SET_FORMAT for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_format_t
+ format</para>
+</entry><entry
+ align="char">
+<para>video format of TV as defined in section ??.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>format is not a valid video format.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="VIDEO_SET_SYSTEM"
+role="subsection"><title>VIDEO_SET_SYSTEM</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl sets the television output format. The format (see section ??) may
+ vary from the color format of the displayed MPEG stream. If the hardware is
+ not able to display the requested format the call will return an error.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(fd, int request = VIDEO_SET_SYSTEM ,
+ video_system_t system);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SET_FORMAT for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_system_t
+ system</para>
+</entry><entry
+ align="char">
+<para>video system of TV output.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>system is not a valid or supported video system.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="VIDEO_SET_HIGHLIGHT"
+role="subsection"><title>VIDEO_SET_HIGHLIGHT</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl sets the SPU highlight information for the menu access of a DVD.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(fd, int request = VIDEO_SET_HIGHLIGHT
+ ,video_highlight_t &#x22C6;vhilite)</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SET_HIGHLIGHT for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_highlight_t
+ *vhilite</para>
+</entry><entry
+ align="char">
+<para>SPU Highlight information according to section ??.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_SET_SPU"
+role="subsection"><title>VIDEO_SET_SPU</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl activates or deactivates SPU decoding in a DVD input stream. It can
+ only be used, if the driver is able to handle a DVD stream.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(fd, int request = VIDEO_SET_SPU ,
+ video_spu_t &#x22C6;spu)</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SET_SPU for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_spu_t *spu</para>
+</entry><entry
+ align="char">
+<para>SPU decoding (de)activation and subid setting according
+ to section ??.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>input is not a valid spu setting or driver cannot handle
+ SPU.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="VIDEO_SET_SPU_PALETTE"
+role="subsection"><title>VIDEO_SET_SPU_PALETTE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl sets the SPU color palette.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(fd, int request = VIDEO_SET_SPU_PALETTE
+ ,video_spu_palette_t &#x22C6;palette )</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SET_SPU_PALETTE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_spu_palette_t
+ *palette</para>
+</entry><entry
+ align="char">
+<para>SPU palette according to section ??.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>input is not a valid palette or driver doesn&#8217;t handle SPU.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="VIDEO_GET_NAVI"
+role="subsection"><title>VIDEO_GET_NAVI</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl returns navigational information from the DVD stream. This is
+ especially needed if an encoded stream has to be decoded by the hardware.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(fd, int request = VIDEO_GET_NAVI ,
+ video_navi_pack_t &#x22C6;navipack)</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_NAVI for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_navi_pack_t
+ *navipack</para>
+</entry><entry
+ align="char">
+<para>PCI or DSI pack (private stream 2) according to section
+ ??.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EFAULT</para>
+</entry><entry
+ align="char">
+<para>driver is not able to return navigational information</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+
+</section><section id="VIDEO_SET_ATTRIBUTES"
+role="subsection"><title>VIDEO_SET_ATTRIBUTES</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is intended for DVD playback and allows you to set certain
+ information about the stream. Some hardware may not need this information,
+ but the call also tells the hardware to prepare for DVD playback.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para> int ioctl(fd, int request = VIDEO_SET_ATTRIBUTE
+ ,video_attributes_t vattr)</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_SET_ATTRIBUTE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_attributes_t
+ vattr</para>
+</entry><entry
+ align="char">
+<para>video attributes according to section ??.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>EINVAL</para>
+</entry><entry
+ align="char">
+<para>input is not a valid attribute setting.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+ </section></section>
diff --git a/Documentation/DocBook/media/dvbstb.png.b64 b/Documentation/DocBook/media/dvbstb.png.b64
new file mode 100644 (file)
index 0000000..e8b52fd
--- /dev/null
@@ -0,0 +1,398 @@
+iVBORw0KGgoAAAANSUhEUgAAAzMAAAGaCAYAAAA7Jx25AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBI
+WXMAAA3XAAANiQFmEOuiAAAgAElEQVR42uzdd1RU18I28GdgKFZUBE0saFA0KoqFFkEhKhbAQmxJ
+bIkNNEpMEUwsMZarJMZrw4KxRExQczUqil0jRBA1GAjGQqLYC4TemdnfH76cj3HodYDntxaLmTll
+zuw57Zmz9z4yIYQAkYZzcnJCSkoKGjZsyMIgIiIiquPS09PRoEEDyBhmqCaQyWRo06YN3nvvPRYG
+ERERUR137Ngx/Pnnn5CzKKgmMDAwwKpVqxhmiIiIiAj29vZ4//33ocWiICIiIiKimohhhoiIiIiI
+GGaIiIiIiIgYZoiIiIiIiBhmiIiIiIiIYYaIiIiIiIhhhoiIiIiIiGGGiIiIiIgYZoiIiIiIiBhm
+iIiIiIiIGGaIiIiIiIgYZoiIiIiIiGGGiIiIiIiIYYaIiIiIiIhhhoiIiIiIGGaIiIiIiIgYZoiI
+iIiIiBhmiIiIiIiIYYaIiIiIiIhhhoiIiIiIqFLIWQRElSMsLAy2trZo1KgR5HJualTxEhIS8P33
+3+PDDz+sM5+5bdu2ePDgAZo2bcoVgCplm3J0dMS5c+fqzGf++uuvsWTJEm5TVClSU1ORk5ODBw8e
+oHXr1gwzRDVJbm4uAGDRokUwMDBggVCFmzlzJrKysurUZ3727BksLCzg4eHBFYAq3IIFC5CQkFCn
+PnNGRgYAYNWqVVwBqMJFRUVh48aNUCqVlfYeDDNElWzGjBkMM1QpNm7cWOc+c8uWLTFjxgzMmDGD
+KwBVuLt37yIkJKTOfW5nZ2duU1SpYaYysc0MERERERHVSAwzRERERETEMENERERERMQwQ0RERERE
+xDBDREREREQMM0RERERERAwzREREREREDDNERERERMQwQ0RERERExDBDRERERETEMENERERERMQw
+Q0REREREDDNEREREREQMM0RERERERAwzRERERETEMENERERERMQwQ0RERERExDBDREREREQMM0RE
+RERERAwzREREREREDDNEREREREQMM0RERERExDBDRERERETEMENERERERMQwQ0REREREDDNERERE
+REQMM0RERERERAwzRERERETEMENERERERMQwQ0REREREVGnkLAKimunBgwdISkoq8/SGhoZ47bXX
+WJCV6NmzZwgMDMS5c+ewd+9eFgiVSVZWFkJCQnD16lU8evQICoUChoaG6NChA2xsbNCxY0fIZDI8
+efIEp06dwuTJk0s876CgIJiYmKBLly4saKq2Y5Wuri6aNm0KQ0NDaGnxd3ZimCGqE/78808EBgbi
+p59+QkJCgsowLS0tyGQy6blSqYQQQmWcjz/+GGvXrmVBVoKtW7di+/btuHbtGoQQMDQ0ZKFQqf37
+77/w8fHBtm3bkJCQgCZNmsDS0hLGxsZ48OABtm/fjidPnsDU1BR2dnYICwtDz549SxxmlEol5s6d
+CxsbG+zZs4cFTpV2rDpx4gQOHDiAJ0+eqAzT09ODUqlETk4OAEBfXx/dunWDvb093Nzc0LdvX5Vj
+GVFBGH+JaqihQ4di06ZNOHr0qMrrly5dgkKhQG5urvSnVCqRlZWF27dvY8mSJQCA7OxsFmIlmTFj
+Bs6ePctfu6nMTp48iTfffBOrV6+Gnp4e9uzZg+fPn+PUqVPw9/fHkSNH8PDhQxw9ehRCCOzevRu3
+bt1CWlpaqd4jJiYG+/btw+PHj1noVGnHqnXr1uHcuXMqr+/fvx8ZGRnIzs5GSkoKIiIi8M0330BH
+Rwdr166Fvb09evXqhdOnT7MQiWGGqDazsrJSeV5Y1TFdXV107NgRX331FSZPniz9ElbTnDp1SuOX
+USaToXHjxujevTtXUCq1H3/8EcOGDcPz58/RtWtXREREYMKECdDR0VE9gGtpwcXFBdeuXYONjQ0A
+ID09vcTvs2HDBgBATk4OfH19WfBUqTp16gS5/P9XCDI3N5euujRs2BAWFhb46KOP8Ntvv+HIkSNo
+3rw5rl+/DicnJ3z66adQKpUsRGKYIaqNdHR0Sl3HeNy4cTXyysyBAwdq1EkX635TaV29ehVTpkyB
+UqlEw4YNcfToUbRs2bLIaZo0aYIjR47AyMioxFdm7ty5g6CgIGhrawMAtmzZgoyMDH4BVGlkMhl0
+dXVLNJ6rqyvCwsLQqlUrAMB3332Hjz/+mIVIDDNEtfkgURqOjo5YunRpjfqMd+7cwfTp0/llU62l
+VCoxY8YM6arp/Pnz0b59+xJNa2RkBC8vrxJfmfH19YWVlRUmTJgAAIiPj2cnFaRRxypTU1McOnRI
+CtwbNmzA4cOHWYjEMENUl+Xm5iIhIQH6+vowMTEpcJz8HQUIIdQ6DijoBKy0CppnUfN59uwZnJ2d
+S9V7mxCiVMtW2mWqiPckyu/EiROIiIgAAGhra8Pd3b1U00+aNAlZWVnFjpeamoqdO3di9uzZmD17
+tvT6f//732K3d6KqZGlpiRkzZkjPvby8it3HlmY/XNh+v6jtoCTHRU1RlmNSac8BGGaIqEpduXIF
+CxYsUHs9MTERfn5+sLa2xrVr15CSkoJJkyZBX18fbdq0QWRkpMrOLTAwEMOHD4epqSnat2+Pxo0b
+o3///vDz8yu0LU5ubi7Onz8PDw8PmJubS+87d+5cGBoaQi6Xw8LCQq2x5+XLl2Fra4s7d+4AAEJD
+Q+Hi4gIXFxfMnz9fZdzs7Gz4+vrC2toa+vr60NHRQdeuXeHj41PgSV5Zl+lVx44dw8CBA/Haa6+h
+Q4cO6NmzJw4cOFBn17OgoCC1XouoeD/++KP02NbWFkZGRqWa3sjICDt37ix2PH9/f8jlcowdOxaW
+lpawtrYGAERHR+Ps2bP8IjRQaGgooqKi6mTYnDNnjvT41q1buHTpkto4pdn3CyFw7do1eHt7o127
+dkhMTIQQAv7+/rCwsIBcLkfTpk3x8ccfS9Wxc3NzsXnzZvTu3Ru6urqoX78+3n33XbWeRPfv34/x
+48dLx6jFixdLw5KSkjB37lwMHz5cGp6/hkRsbCzmz58vDcv7++KLL5Cbm4vDhw9j7Nix0utz587F
+s2fPylUWZTkH0NTURqTxDAwMxN69e2vUMgcHBwsAIjExsdLfS1tbWwAQAMTdu3cLHW/hwoVi5syZ
+0vMrV66IESNGCF1dXWn63377TfTv31/o6+tLry1YsEAIIUR6eroYPXq00NPTE7t37xY5OTlCCCFu
+374t+vbtKwCIHj16iNjYWJX3PXXqlHBycpLm16JFCxEdHS06duwoHB0dhYuLi6hfv74AIHR0dMQf
+f/whTfvXX3+J06dPC2NjYwFA2NraitOnT4vTp0+L8PBwabynT5+KPn36iOnTp4vIyEjx6NEjcejQ
+IdGiRQsBQPTt21ekpaVVyDLlUSgUYvbs2UIul4stW7aI7OxsIYQQ0dHRwsLCQjRq1EgAEIaGhpXy
+vZubmwtfX1+NW/fzyrRdu3Zi5syZIiAgQDx58qRC5t22bVuN/MwVoVWrVlLZeXp6Vsp7KJVK0bVr
+V+Hl5SW95u/vL72vs7NznT7WeHt7Czs7O41brmnTpgkAwsDAQIwYMUKsX79eREZGCqVSWSGfuaq+
+9wYNGkjr2l9//VXi6dq3by9Nt3jxYpVhpdn3X7p0SYwePVrI5XKV5Rg8eLCwsrIS7u7u4u2335aG
+ff755+LJkyfirbfeEo6OjmLWrFli1KhRQktLSwAQrq6uast67949af6DBw9WGx4dHS0ds18td6VS
+KZYtWya9f+/evVWGr1y5Uujq6oqAgIACv/vSHgdLew5QFpGRkQKA2nlBRQgMDBQGBgaCYYYYZmpZ
+mDl48KAIDQ2V/i5duiTOnj0rvv76a6Grq6sSZtLS0kR2drZ0oAQgnJycxKFDh0RqaqqYOHGiaNKk
+iTh9+rRQKpVi7NixAkCBJ5MpKSmic+fOAoDo1KmTSElJURtn6NChAoDQ19cXlpaWIiIiQhr2xx9/
+SJ9jypQpatOamJgIAGLEiBFqw7Kzs0WfPn3EqFGj1Hbw+/fvlz6bt7d3hS7TokWLBACxZs0atWGP
+Hz+WDtx1Lcw0a9ZMKnMdHR3pwF4R4aa2hpnk5GSpzApbpyrC2bNnhUwmU/nRIzMzU/qxAIC4efMm
+w4yG8fDwkE6gtbS0hJ6eXoWFm5oQZkaOHClNN3r06HLv+xcsWCANs7GxUflhTKlUSu/XoEEDYWlp
+KS5cuKAy/erVq6XpY2Ji1JbX1NS00DCT/3hWULkrlUoxZMgQ6bvOK6f09HTRsWNH8d133xU4z7KU
+RWnOARhmiBhmqizMFPeXP8zk+eGHH6ThX331VYHvcezYMQFANG3aVGRlZRU4zpEjR6T5fPHFF2rD
+P/roI2n4s2fP1Ib369dPCkOlCTNbt24VAMS5c+fUhmVmZkq/MDVt2lS6mlTeZbpx44bQ1tYWhoaG
+hZbH8OHD62SYMTIyKnT9K2+4qa1h5p9//lEpp61bt1bK+4waNarAX5PzgjkAMWvWLIYZDQwz+a8m
+5P8rb7ipCWFmxowZ0nSOjo7l3vdv375dml9YWJjatPv27ZOGb9q0SW34zZs3peG7du1SG96pU6ci
+w0xe2Cms3O/fvy9d2XdychJKpVJMmzZNODg4CIVCUeA05TkOluQcQJPDjJw1UYlql5s3b6o07hdC
+IC0tDZcuXcKHH35Y4DT5718xZMiQAsfJ6xLZysqq0O41hw0bBmNjYzx//hxbt27F0qVLVe4rkNcr
+DQAYGxurTZ/XDWd8fHypPrOfnx8AIDw8HNHR0WrDmzVrhsePHyMhIQE3btxQuf9LWZdp3bp1UCgU
+GDhwYKHl0ahRI66Qr8jfpurevXvYsWMHvv/+e+Tm5qJdu3YYPHgwHB0d0b9//2K7JK7NFApFhc8z
+NjYWhw8fxvHjx9WGzZw5EytXroRCocCuXbuwfPlyNG3alCtsDZB3U+S8dhlHjx7FiRMnkJWVBQMD
+Azg4OGDAgAFwcHBAt27dSt37pSbIv8z5j1dl3ffn3+83aNCg0P1+3jxe1aJFC+nxw4cPK/zztmnT
+Bt988w3c3d1x6tQpTJo0CYcPH0ZUVFShXf6X5zhYknMATcYwQ1TL6OnpQV9fX+W1evXqYfjw4Viw
+YIHUkL4w+Xfy+Q+WFy5cAAA0b968yGn79++PAwcOID4+HtHR0ejRo0eJlz1vJy1K0cg1OTkZ165d
+g7a2dqGNzseMGaP2HuVZJiGE1EVo586dq/Uk5v79+7h27ZpGrYO5ubllDjfff/89tm/fDoVCIYWb
+3r17w9XVtVaHm1eDQ1xcXIW/x5YtW/DGG29g0KBBBZ68ubm54cCBA0hPT8f27dvx+eef18l9aFpa
+msZtUy9evChzuDly5AiCgoKQnZ2Nxo0bw9HREf369YO9vT369OlTI76Tf//9V3r8+uuvV/q+v6Dj
+oMrJc74f6Srr/kzTp0/Hvn37cP78efj7+2Pjxo2F9kJakWVR3GdnmCGqQ4QG9jrz9ttv4+7du6We
+Lj4+XroZX3Enqp06dZIeP3z4sFRhpizu3r0rdT+5Zs2aKtkRv3jxAk+fPgVQvVdfsrOzsWrVKqxa
+tarWbDf516979+5h69atUkifOnVqpVyx0ARNmjSRrmoCQExMTIXOPyMjA35+flAoFCq/yL66nefZ
+sGED5s2bp3LSVlfcuHGjxpzkl/RYlNcrV3JyMg4fPiz9GOPo6CiFA01269Yt6XHv3r2rbd9flbS0
+tODn5wdzc3NkZGTg1KlTmDVrVoFX1mp7WTDMEFWDFy9eYPny5Rq3XD179sTGjRtLPV3+E8i8k/jC
+GBoaSo+rYoeaF7KEELh//36JbzJYHvl/Nc/MzKy271NPTw/ffvttodUHq4uZmVmZryzo6ekhKysL
+enp6sLS0hJOTE/r37w8bGxvo6uoiMDCw1u437OzscPDgQQAvu+KtSAEBAUhNTYWPj0+Rv8quWLEC
+T58+xYMHD3Do0CGVX3Prip49exZYFa86ffbZZ/jhhx9KddUzj46ODpRKJZRKJTp06IChQ4fCwcEB
+ffv2hbGxMRYsWIDExESNPp5GRUVJz11cXKpt31/V0tLSpOPvkSNHsG/fPowfP14jjoMMM0S12Llz
+5zBgwABMnTq11nym5s2bQ0dHBzk5OYiOjoYQotB61/lv0PXGG29U+rLVr19fehwSElIlO3E9PT3p
+8d9//11t34tMJkP9+vU1rm1Daerk6+vrIzMzUyW8ODo6Ftk2q7YaO3asFGbu3LmDqKgo6f5H5SGE
+wIYNGzBmzBjMnTu3yHHj4+Px1VdfAXh5E826GGby7jOiSfLvc4qjq6sLhUIBpVKJjh07YsiQIXBw
+cIC9vX2R1YQ11c6dO6WaDi4uLmjXrl217furUlZWFiZMmIClS5di48aNePToEebMmYMBAwao3YOq
+tpdFcXjTTKIKolQqsXz5cgwYMAAAMHz48Fp1cM+7sV5cXBxu3LhR6Lh59XVbtWqFjh07VvqymZqa
+SifPfn5+RVbvS01NxcyZM8v9nq1bt5YaTF64cIF3TS+FvPZcenp6sLOzwxdffIHg4GAkJycjODgY
+ixYtgp2dXZ0LMgDg5uamchLy3XffVch8L168iIiICEyfPr3YcWfOnCmt25cuXUJ4eDhXWg2nq6sL
+bW1tyGQymJmZwd3dHQcOHMCLFy9w69YtrFu3DqNGjaqRQebx48dSNVpdXV2sXr26Wvf9FaUkx4yF
+CxeicePGmD9/PjZv3iwdfz09PTXiOMgwQ1TLvHjxAoMGDcKSJUsAvLxjcUE9oFTWTjH/1ZDKOrH+
+4IMPpMcBAQGFjpd38uPu7l7qXnOKWva8eeXV/c7TqFEjKWgFBwdjz549BU6fm5uLKVOmwMnJqdzL
+pKenh/79+wN4WVc5KCioyGnrWtjJq/Lwanixt7dneCmCjo4ONm3aJD3ftWsXTp8+XeLpExMT4erq
+qnZX8NWrV8PMzAz29vbFzqNly5YYPXq09Hzt2rXcwWsApVIpVTcqaXjJX+W3Jp3E50lISMDIkSOR
+kJAAANi0aRO6dOlSZfv+8sirYp2enl5gGaSkpBQ5/a+//oqNGzfCz88PWlpacHV1xbvvvgsA+Omn
+n3D06NEqPQ4yzBDVcufPn0fXrl1x8eJFKJVKaGlp4bPPPquy909PT1c5QJSlZ5X8YaiwOtmTJk2C
+paUlAGDz5s0F1rG+ffs2goODYWZmhnnz5qkNL67xdl7PVgUd8PKqfdy+fVsanp2djcePH6v8UjVt
+2jSsX79e6s0HeFllx8XFBdnZ2XBzc6uQZcr/+Tw8PNS650xMTERISAiAl41uU1NT68w2kXcAfzW8
+XLx4keGlGEOHDsWaNWuk525ubiVqJxQaGgpLS0v069dPpdvYK1euICgoCGPGjCnxjwvvvfee9PjA
+gQPVWpWS/v8JsBCixoWXV/e1+dsYFhZshBA4deoU+vTpgytXrkBXVxfbtm3DtGnT1MYt674//zGv
+LMfE4n5AzLvCevnyZdy+fVulDFasWCHtIwu6DUFycjImT56MBQsW4M0335ReX7dunfQdu7u7qx2D
+y3McLMk5AMMMUS2kVCrx9ddfY+DAgYiPj0dubi7kcjnGjx+Ptm3bVtlynDx5UuV5YVcJipK/u+bf
+f/+9wHHkcjkOHTqETp06IT4+HhMmTFD5BT4hIQETJ05EmzZtEBgYWGDf/flPivJ6bcp/QPjzzz8B
+vOxONDk5WWW4ra2tNI/58+fj4MGDeOedd/Dvv/9i3LhxGDdunBQ+PD090bx5c/To0QOmpqYwMzND
+UlIS/P391U7oyrpMw4YNg4eHBwDg/v376NWrF1asWIHAwEBs27YNjo6OMDAwkA4O3bt3r3WX9gtz
+7do1ZGVlMbyU0SeffIJ9+/ahWbNmSE1NhaurK9zc3HDy5EmVX3pTU1MRFBSEd955By4uLli2bJlK
+d8qZmZmYNWuWtP2WVF6bhLyTr3nz5hV78keVa968eYiLi6tR4eVV58+fV1mP9u3bh5iYGPz999/4
+/fffcfjwYSxatAg9evTA4MGDce/ePbi5ueH69euFVpEs674/f2+BBQWK2NhY6XFB1aofPHggPX78
++LHa8LyaDNnZ2bCzs4OXlxe8vb1hbm4OIQQcHBwAAGFhYXj//fdx7Ngx6bxi2rRpUCqV8PLyUpmn
+kZGRVPvj8ePHmDJlikrwKM9xsCTnAJqe9ok0noGBgdi7d6/GLM+TJ0+Eg4OD2h2ZZTKZiIyMFEII
+ERwcLACIxMTESlkGPz8/MWjQoALvCm1nZyc+/fTTYudx5swZ4erqKrS0tKRp9fT0xKRJk8T27dsL
+nCYpKUnMmzdPNGrUSLz++utixowZ4sMPPxQmJibC3d1dxMXFqU0TGhoqxo8fr7KMXbp0EV9++aUQ
+QoiTJ08KJycnleE9e/YU27Ztk+YRGxsrWrduLQ1//fXXxfnz56XhOTk5YsmSJdJdk/P+DAwMxMKF
+C0VGRkaFL5NCoRDffPONaNq0qcp4JiYm4ty5c+L9998XhoaGwsPDQwQHBxd65+ayMjc3F76+vnVq
+X9C2bds685nj4uLEkiVLRNu2bVX2MYaGhqJZs2YCgGjTpo1YtGiR2na3f/9+0blzZ2k6uVwuRo0a
+JY4fP17o+/31119i8uTJol27dmr7lN69e4tffvml1pe5t7e3sLOzq1PblLe3d6F3oq+oY5WTk5PQ
+1dVVW6/y/zVu3Fh06dJFjB07VmzatEk8fPiwRPMvzb7/119/FbNmzRJ6enoq+2tvb28RGxsr/v77
+bzFv3jzRvHlzabiurq7w8PAQFy5cEBkZGeLzzz8X7du3V9m23N3dRWBgoPQ+SqVSLF26VOX43KxZ
+M+n44ezsLNq3by+8vb1FaGioyM3NFcHBweLtt98WAISRkZHw8fFR+Zznzp0TDg4OKp/R1tZWZZsu
+7XGwLOcApRUZGSkAiNjY2ApftwIDA4WBgYGQCbZcpRqgSZMm8PX1Van+UJ2/Lo0ZMwYpKSkq7Tfk
+cjkcHR1x6tQpAC97FLG3t0diYqL0C31tkpWVhT/++ANxcXFo2rQpevToodKjSmVIS0tDWFiY1PNV
+QT38ZGRk4Pr160hISICRkRG6d+9eqp6AyloW169fR1xcHIyNjdGzZ0/I5XLExMTAxMRE5e7KFal7
+9+7w8PCQrhDVBSYmJvD29q5Tn1kIgdu3b+PPP/9EXFwclEoljI2N0bVrV3Tq1KlG3tFdUy1YsAAh
+ISEIDg6uU585Kiqqxnd7Xh37/uK8ePEC169fR7169dCnTx+pDeE///yDdu3alfomzjWxLKKiotC9
+e3fExsZWeK2VY8eO4f3332fXzEQlpVAosGzZMixbtky6HPzq8C+++KLOlIeenh6srKyq9D0bNGgg
+9RZXmHr16klV0qqyLPIaX+bXoUMHbjhUbjKZDJ06dVK5IS0RVf++vzhGRkYYNGiQ2uuVfdsCTSyL
+ysQwQ1QCT58+xZgxYxAWFlZg3XEtLS1YWFhI9WCJiIiIqPKxAwCiYpw5cwbdunVDeHh4kb18LFy4
+kIVFRERExDBDVP0UCgUWL14MJycnJCQkqN3fJI9MJoOJiQlGjBjBQiMiIiKqQqxmRlSAR48eYfz4
+8QgLC5P69y+MtrY2vvjii0pryEdEREREDDNEJXLq1CkMHjwYurq6Jbp5lIGBASZNmsSCIyIiIqpi
+/CmZKB8hBPbv3w8AhVYry09XVxdeXl68ISARERERwwxR9ZLJZNi+fTvWr18PLS2tYquO6ejoYMaM
+GSw4IiIiIoYZIs0wZ84cnDlzBo0aNSr0hoe6urr46KOPauUNMYmIiIgYZohqMEdHR4SGhkJbW7vA
+O2wrlUp4enqyoIiIiIgYZog0z6pVq9CsWTO4uLhAW1tbel1XVxeTJ0/Ga6+9xkIiIiIiYpgh0izr
+1q1DQEAA/ve//+Hw4cNYvnw5tLS0IJPJkJ2dDS8vLxYSEREREcMMkWa5cOECPvvsM/j6+sLGxgYy
+mQze3t4IDAyEEAI2Njbo2LEjC4qIiIioGvE+M0SvuH//PsaOHYtp06Zh6tSpKsOGDh2KW7duISsr
+iwVFRERExDBDpDnS09Ph5uYGMzMzrFu3rsBxzMzMWFBEREREDDNEmsXDwwNPnz7F1atXeSNMIiIi
+IoYZopohr8H/r7/+ipYtW7JAiIiIiBhmiDRfXoP/LVu2wMbGhgVCREREVAOwNzOq84pq8E9ERERE
+DDNEGqkkDf6JiIiISDOxmhnVaWzwT0RERFQLwsz333+P77//Hg0aNGCpUIVTKBTIycnB//73Pxgb
+G2vEMrHBPxEREVEtCTMxMTEIDQ2Fl5cXS4UqXFRUFM6fP4/MzEyNWB42+CciIiKqRWEGAJydnbFq
+1SqWClVKmDl+/LhGLAsb/BMRERHVDuwAgOoUNvgnIiIiqj3YAQDVKWzwT0RERMQwQ1TjsME/ERER
+EcMMUY3DBv9EREREtQ/bzFCtxwb/RERERAwzRDUOG/wTERER1V6sZka1Ghv8ExERETHMENU4bPBP
+RERExDBDVOOwwT8RERFR7cc2M1TrsME/EREREcMMUY3DBv9EREREdQermVGtwgb/RERERAwzRDWO
+pjb4X716NQwMDPgFUYWLioqqc5/54cOHWL16NZKTk7kCUKXsr83Nzevc5z527BhWr17NFaAYycnJ
+uH//Ptq1a4eGDRuyQDTkOMUwQ7WCJjb4b9iwIUxMTHDixAloabFGJ1W8Nm3awMjIqE59ZkdHR9y/
+fx8HDhzgCkAVrl27dujZs2ed+sytWrVCmzZtuE29QqlUIi0tTeUvJycHMpkM+vr66NKlCwupBLKz
+s2FqalqptWUYZqjG09QG/xYWFrh37x6/IKIKdObMGRYCUQX66KOP8NFHH9XpMlAoFIiOjkZ4eDgu
+X76My5cv48aNGxBCoHPnznBycoKVlRVsbGwQFRWFhQsX4urVq1x5NATDDNVobPBPREREpfHo0SMp
+tFy+fBnXrhOJlUQAACAASURBVF1DamoqWrZsCWtra4wfPx42Njbo06cPGjdurDLtjRs3WIAMM0QV
+hw3+iYiIqDCpqam4evUqwsPDERYWhvDwcDx69Aj169dH7969YWVlhdmzZ8Pa2hpt27ZlgTHMEFUd
+TW3wT0RERFWvuOpi1tbWWLhwIWxsbNCtWzfI5TwNZpghqiaa2OCfiIiIqk55qosRwwxRtdHUBv9E
+RERUOVhdjBhmqFZgg38iIqLajdXFiGGGai02+CciIqpdWF2MGGaoTjhx4gT27dvHBv9EREQ1FKuL
+EcMM1Um5ubn48ccfsXXrVjb4JyIiqgFYXYwYZojwssF/eno63n77bTb4JyIi0lCsLkYMM0SvyGvw
+r6WlhUmTJrFAiIiINACrixHDDFEJeHh44NmzZ2jQoAEvPxMREVUDVhcjhhmiMli3bh0CAgLw66+/
+YsiQISwQIiKiKlCS6mLW1tawtLRkdTFimCEqyIULF/DZZ59hy5YtbPBPRERUSVhdjBhmiCrY/fv3
+MXbsWEybNo0N/omIiCoIq4sRw0wVCAoKgomJCbp06cJvpw7Ka/BvZmaGdevWsUCIiIjKiNXFiGGm
+iimVSsydOxc2NjbYs2cPv506KK/B/5UrV6Crq8sCISIiKgFWFyOGGQ1w8uRJxMTEIDY2FqtXr8br
+r7/Ob6gOyd/gv2XLliwQIiKiAigUCty4cUPlqgurixHDjAbYsGEDACAnJwe+vr5Yvnx5lb7/qVOn
+4OTkxLWiGrDBPxERUcFYXYyoBoSZO3fuICgoCNra2lAoFNiyZQu+/PJL1KtXr0re/8CBA9i7dy/D
+TDVgg38iIqKXWF2MqIaGGV9fX1hZWeHNN9/E7t27ER8fj71792LatGlVEqSmT58OBwcHrhFVjA3+
+iYiormJ1Mc329OlThISEYPTo0UWOFxMTg3/++Yc/iNflMJOamoqdO3di/fr1UpgBgP/+97+YOnUq
+ZDJZieclhFAbX6lUQktLq8Dxnz17BmdnZyQlJZVqmYUQEEIUOt/yLFNFTfvqfACUqiyrAhv8ExFR
+XcHqYjXLzZs3MW7cOMTFxaFp06aFjrdnzx4cPXqUYaaaaGnCQvj7+0Mul2Ps2LGwtLSEtbU1ACA6
+Ohpnz54tdvrc3FycP38eHh4eMDc3BwAkJiZi7ty5MDQ0hFwuh4WFBU6fPq0y3eXLl2Fra4s7d+4A
+AEJDQ+Hi4gIXFxfMnz9f7X2ys7Ph6+sLa2tr6OvrQ0dHB127doWPjw+ysrIqZJnKO21+V69excSJ
+E2Fvb4/Bgwejbdu26N27N3bs2CGFm+qU1+D/wIEDbPBPRES1SmpqKi5cuAAfHx+4ubmhdevWaN26
+NSZOnIjQ0FD06dMHO3bsQGxsLJ48eYJffvkFX3zxBQYMGMAgoyFsbGygq6uLkJCQIse7cOECHB0d
+WWDVRfwfb29v4ezsLKqaUqkUXbt2FV5eXtJr/v7+AoAAUOwynTp1Sjg5OUnjt2jRQkRHR4uOHTsK
+R0dH4eLiIurXry8ACB0dHfHHH39I0/7111/i9OnTwtjYWAAQtra24vTp0+L06dMiPDxc5X2ePn0q
++vTpI6ZPny4iIyPFo0ePxKFDh0SLFi0EANG3b1+RlpZW7mUqz7T5bdq0SchkMuHp6SkUCoUQQoi0
+tDRhZ2cnAIgVK1ZU6fccGRkpAIjY2FghhBDnz58XcrlcbN++vUTTGxgYiL179woiIiJNk5ubKyIj
+I4Wfn5+YNm2aMDc3F9ra2kJLS0t06dJFfPDBB2Lz5s0iIiJC5OTksMBqkH79+olPPvlEer53717R
+tm1b6Xl6errQ09MTR44cYWFVscDAQGFgYCCqPcycPXtWyGQycffuXem1zMxMKWAAEDdv3ix2PkOH
+DhUAhL6+vrC0tBQRERHSsD/++ENoa2sLAGLKlClq05qYmAgAYsSIEQXOOzs7W/Tp00eMGjVKKJVK
+lWH79++XltPb27vClqk80z548EAafurUKZVhAQEBAoBo1KiRyMrKqpYwExsbK4yMjIS7u3uJp2eY
+ISIiTfHw4UPxv//9T8yfP1/0799fNGzYUAAQLVu2FCNGjBArVqwQZ86cEUlJSSysGm7x4sWiZ8+e
+hYaZ8+fPC21tbZGQkMDCqqYwU+3VzDZu3AgXFxe0a9dOek1PTw8zZ86Unq9fv77Y+ZiamgIAMjMz
+ERgYCAsLC2lY9+7d0bdvX6kqWWnt3LkTV69exZw5c9TanAwfPhz6+voAgK1btyI3N7dClqk8096+
+fRsKhQIAEBcXpzLM2NgYAJCSkoK7d+9W+fedkZHBBv9ERMTqYlQjODo64o8//kBCQkKBw8+fP4/u
+3bujSZMmLKxqUq0dAMTGxuLw4cM4fvy42rCZM2di5cqVUCgU2LVrF5YvX15k4yttbW21E/b8WrVq
+BQCIj48v9XL6+fkBAMLDwxEdHa02vFmzZnj8+DESEhJw48YNdO/evdzLVJ5p+/Xrh08//RRZWVkY
+OXKkyrD8Yay0nR5UhC+//JIN/omISCOxdzF6lY2NDXR0dBASEgJXV1e14WwvU8fDzJYtW/DGG29g
+0KBBBZ6su7m54cCBA0hPT8f27dvx+eefl/m98nr/EqVs+J6cnIxr165BW1sbT548KXCcMWPGqL1P
+ZS5TcdPK5XJ8++23Kq+lp6cjICAAO3bskF5TKpVV/p0fOXIEFy9eZIN/IiKqduxdjIqjr68Pa2tr
+XLhwQS3MZGRk4PLly/jss89YUHUxzGRkZMDPzw8KhUK6kvGq/FcdNmzYgHnz5lX5ryB3796FEAJK
+pRJr1qxRuWJSE9y7dw/r16/HrVu3MHXqVCxZsqRauw5csWIFbGxsuOUREVGV4s0oqawcHBxw9OhR
+tdcvX76M3Nxc2Nvbs5DqYpgJCAhAamoqfHx8iryasWLFCjx9+hQPHjzAoUOHVK6CVIW0tDQAL6+A
+3L9/H+3bt68RX2xaWhoWLFgAf39/+Pr6Ys2aNZDJZLhw4UK1Ltft27dx//59HiiIiKjSsLoYVSRH
+R0csX74ciYmJKq+zvUwdDjNCCGzYsAFjxozB3Llzixw3Pj4eX331FYCXN9Gs6jBTv3596XFISEiN
+CDNJSUlwdHREREQEgoKCMGTIEI1Ztl69esHExASTJk2Cn58f280QEVG5sboYVaa8djPBwcEqr7O9
+jGaolt7MLl68iIiICEyfPr3YcWfOnAkdHR0AwKVLlxAeHl6ly2pqaio1mvfz8yuyfUtqaqpKL2zV
+ZeXKlYiIiICJiYlGBRkAcHZ2BgD88MMPePPNN3HixAluhUREVGLsXYyqWv52M3ny2ss4ODiwgOpi
+mFm9ejXMzMxKVMewZcuWGD16tPR87dq1ZXrPokJIXljJzs5WG9aoUSNYW1sDAIKDg7Fnz54C55Gb
+m4spU6aUqj1KWRr+l2TavN7h9PT01Ibl5ORU+0oXFRUF4GV7JGdnZ4wcORL//PMPt0YiIlKhUCgQ
+FRWF7du3Y/r06VKVngEDBmD37t1o0qQJFi5ciIiICCQlJeHixYv49ttvMWbMGFZnpgrl4OCA8+fP
+S8/DwsLYXqauhpkrV64gKCgIY8aMUbtnS2Hee+896fGBAwfw999/F7jDK0reSXxBISCvy+fbt29L
+w7Ozs/H48WMAgKenpzTutGnTsH79emRlZUmv3blzBy4uLsjOzoabm1uFLFN5ps3rpezOnTv4888/
+pdczMzOxe/dulV8VyhuqyqJbt2745JNPYGBgAF1dXcTExKBbt2746quvpGUiIiLNdP36ddy5c6dS
+5v3o0SMcPHgQXl5ecHBwQJMmTdC9e3csWrQIL168wPjx43Hy5EkkJCQgOjoaO3bsgLu7OywsLNju
+hSpV3v1m0tPTAbysYtajRw+2l6lrYSYzMxOzZs0CgFLtdPLfUFOhUGDevHlq3QrnDzjPnz9XGSaE
+kE7qk5KSkJycrDLc1tZWmsf8+fNx8OBBvPPOO/j3338BAOPGjcO4ceOkEOHp6YnmzZujR48eMDU1
+hZmZGZKSkuDv768S0MqzTOWZNu/qkBACgwYNwsKFCzF79mz06NEDXbt2lcZbtWoVlixZgh9++KHK
+V7wlS5ZAX18fPXr0wN27dzFr1ixs3rwZXbp0waFDh7hlEhFpmN9//x0jR45Er169EBAQUO75sboY
+1SR57WZu3rwphRlWMdMQ4v94e3sLZ2dnUVn2798vOnfuLAAIAEIul4tRo0aJ48ePFzrNX3/9JSZP
+nizatWsnTZf317t3b/HLL7+I0NBQMX78eJVhXbp0EV9++aUQQoiTJ08KJycnleE9e/YU27Ztk94n
+NjZWtG7dWhr++uuvi/Pnz6ssS05OjliyZIlo1KiRyrwMDAzEwoULRUZGhjRueZapIj5PUlKScHBw
+UBnH2dlZxMTECIVCIczNzaXXR40aJdLT00Vli4yMFABEbGys9NquXbuEvr6+mDx5sqhfv744dOiQ
+mDt3rpDL5WLIkCHi1q1b0rgGBgZi7969goiIqtaVK1eEq6urkMlkwsnJSYSEhJR6Hrm5uSIyMlL4
++fmJadOmCXNzc6GtrS20tLREly5dxAcffCA2b94sIiIiRE5ODgudNFK/fv3EsGHDRJs2bYSenp44
+cuQIC6UaBQYGCgMDAyET/1fHaMGCBYiKikJgYGCdDHVpaWkICwuDnp4eLC0tC2xvArysmnX9+nUk
+JCTAyMgI3bt3L3Tcag6piIyMxJMnT/Dmm2/CxMREGpaSkoLQ0FA0b94cPXv2LHF1v/KIiopC9+7d
+ERsbK9VjFkLA3t4eTZo0QYcOHeDn54fDhw+jRYsWmDNnDkJDQ/HJJ5/gyy+/ROvWreHr66tS5ZCI
+iCpPeHg4vv76axw7dgxDhgzB4sWLpZoMxSmudzErKyv2LkY1zpIlS+Dv74/U1FTEx8cjLi6O1cyq
+0bFjx/D++++DFUz/T4MGDTBgwIBix6tXr16Jd+bVSSaToUePHujRo4fasEaNGlXrjTPzL+PGjRvR
+p08f/PLLLwCAESNG4PDhwzh//jwCAgLw6aefwt/fXyM6LiAiqgvCwsLw9ddfIygoCMOGDUNYWJjU
+EU5BeDNKqivy7jfToEEDtpfRIAwzVK0sLCwwY8YMzJs3D5GRkSqB5t1334Wrqyu+/vprfPPNN1i+
+fLlaux8iIqoYv/32G77++mucPn0azs7OCA8Ph6Wlpco4vBkl1WXW1taQy+VISUlhexmGGaL/b9my
+Zfj555/x7bffSl1v5wWagQMHwsfHB1u2bIFcLoeFhQXmzJmDxYsX8xcRIqIKEBwcjKVLl+LcuXNw
+dXXFlStX0Lt3bwBFVxezsrLizSipTqlXrx7Mzc1x7do1hhmGGaL/z9DQECtXroSnpycmT55cYKDR
+0tKCt7c39PX1MW/ePAQEBGD9+vUq9yAiIqKS+/XXX7F06VJcuHABI0eOREhICLKzs3H27FmsWLGC
+1cWICtC8eXMA4P1lGGaIVH344YfYunUrPv30Uxw4cEAt0ORxc3PD0KFDsXLlSrXuuYmIqHjnz5/H
+0qVLERwcjF69emHUqFG4c+cO+vXrx+piRMXw9vbGixcvWDuEYYZIlZaWFjZs2IC+ffvi1KlTcHJy
+Ugk0+Xtcq1evHpYtW8ZCIyIqhb1792LChAkAAG1tbSiVSsTGxsLIyAgjR47E2rVrWV2MqBjW1tYY
+PHgwC4JhhkidjY0NPvzwQ3h6eiIyMhI6OjpSoFm/fr10o9Ca4s8//8TEiRPRrFkzaGlp8QumCvf8
++XMsX74crq6udeYzv/POO3j48CFPuEshOTkZMTEx0o2ggZcN+QHgxYsXCAoKQlBQEJYtWwaZTCZd
+hcn7r6Ojo/JcLpdDJpNBW1sbLVq0gKGhYa0pq3///RdvvfUWNmzYUGfWj++//x7r16+HsbExN5YS
+ysrKwqBBg1gQJZCdnY309HQcO3as0tYxhhnSKCtXroSZmRnWrVuHzz77DDKZDGvXrsWWLVuwZs0a
+vP322xg4cGCN+CyJiYm4fv063N3dYWBgwC+XKtzq1avx8OHDOvWZDx48iMaNG8PDw4MrQCk4OjpK
+ISYnJ0f6r1QqkZ2drfZfCIGsrCzpf94JHABkZmZK/9u3b4+OHTvWqm0qOzu7Tq0bMTExiIyMhJeX
+FzcUqnBRUVG4ePGitN9gmKFaz8jICEuXLsWXX36Jd999F61atYJMJoO+vj5sbW1VOgWoKVatWsUw
+Q5Xi+PHjde4zt23bFt7e3gwzVClkMhlCQkLq3Od2dnbGqlWruAJQpYSZyj5Wse4LaZzZs2ejQ4cO
+mD9/vsrrEyZMwPTp0zFixAicOXOGBUVERERUxzHMkMbR1tbG+vXrERAQgODgYOn1vCpnDDRERERE
+BLCaGWkoe3t7zJw5E8+ePVN5PS/QAKiRVc6IiIiIiGGG6gBfX98CX2egISIiIiKGGaqxGGiIiIiI
+iGGGGGiIiIiIiGGGiIGGiIiIiBhmiBhoiIiIiIhhhhhoiIiIiIhhhoiBhoiIiIgYZogYaIiIiIiI
+YYaIgYaIiIiIYYaIgYaIiIiIGGaIGGiIiIiIiGGGiIGGiIiIiBhmiIGGiIiIiBhmiBhoiIiIiIhh
+hoiBhoiIiIgYZogYaIiIiIgYZogYaIiIiIiIYYaIgYaIiIiIGGaIGGiIiIiIGGaIGGiIiIiIiGGG
+iIGGiIiIiBhmiBhoiIiIiIhhhoiBhoiIiIhhhoiBhoiIiIiqNcxcuHABZ86cYalQhYuKimKgISIi
+IqLKCzNpaWkYNGgQS4XqPAYaIiIiohoUZv7zn//gP//5D0uEiIGGiIiIqGaFGSJioCmMEALh4eE4
+ceIEnj17BmNjY1haWuLtt99GvXr1kJiYiJ9//hnTpk2Tpnnw4AGSkpLK/J6GhoZ47bXXih0vKysL
+ISEhuHr1Kh49egSFQgFDQ0N06NABNjY26NixI2QyGZ48eYJTp05h8uTJXLGpWgUFBcHExARdunTR
+mGV69uwZAgMDce7cOezdu1dl2L179+Dh4QEDAwNs3boVBgYG/BKpytbLFy9eFDq8adOmaNWqVYHH
+rOjo6AKnad++PRo0aFBh63ZR2w4xzBAx0GiAFy9eYNKkSThx4gSaN28OW1tb3L9/H76+vsjKyoKL
+iwsePnwIuVyuEmb+/PNPBAYG4qeffkJCQoLKPLW0tCCTyaTnSqUSQgiVcT7++GOp3Avy77//wsfH
+B9u2bUNCQgKaNGkCS0tLGBsb48GDB9i+fTuePHkCU1NT2NnZISwsDD179mSYoWqlVCoxd+5c2NjY
+YM+ePdW+PFu3bsX27dtx7do1CCFgaGioNs6aNWtw4sQJAICtrS08PT35RVKV+Oeff+Dn54ddu3ap
+HCM6deqE8ePHo1+/foWGmaCgIPz22284fPgwAMDAwACzZs3CRx99JIWZ8qzbJdl2qIoIohrAwMBA
+7N27t1qXQalUCk9PT1G/fn1x+vTpYscPDg4WAERiYmKNLfeMjAxhYWEhAIjJkyeLjIwMaVh2drbY
+vHmzqFevngAgOnfuXOA8QkJCBADpLyQkpMDxsrKyxO3bt8WSJUsEADFr1qxCl+vEiRPC2NhYABAt
+W7YUe/bsEdnZ2SrjKBQKcfToUfHGG29I7+3q6lqrtgtzc3Ph6+tbp/YFbdu2rdGf+fjx4wKA0NHR
+EY8ePar25VEqlSIpKUl07dpVABCGhoZq42zbtk0AEDKZTJw9e7ZWr1/e3t7Czs6uTm1T3t7ewtnZ
+WaOX0cfHR+U48tNPP5V42i5duggA4sSJExW6bpdk2yEhIiMjBQARGxtb4fMODAwUBgYGQotxjqh0
+V2imT5+OESNG1Ime/7Zt24br16+jSZMm2Lx5M/T19aVhOjo6cHd3x5kzZ1CvXj08evSowHlYWVmp
+PC/oVzQA0NXVRceOHfHVV19h8uTJyMnJKXC8H3/8EcOGDcPz58/RtWtXREREYMKECdDR0VG7+uPi
+4oJr167BxsYGAJCens4VmarVhg0bAAA5OTnw9fXViP1a48aN0b1790LHmT59Oi5fvoyoqCi8/fbb
+/BKpys2bNw9vvvmm9DwkJKSkP9gjLi4OdnZ2GDx4cIWu2yXZdqhqMMwQMdAU6siRIwAAU1NT1KtX
+r8Bx3nrrLXzzzTdISUlBSkqK2nAdHR1oaZVuVzNu3DhkZ2ervX716lVMmTIFSqUSDRs2xNGjR9Gy
+Zcsi59WkSRMcOXIERkZGSEtL40pM1ebOnTsICgqCtrY2AGDLli3IyMjQjJOBYrZRKysrdO3alV8i
+VQu5XI7FixdLz/39/Uu0Pw8PD8fz58/x0UcfVdq6XdrjGzHMEDHQVKHHjx9LJ2FFXdWYPn06WrRo
+IY1fUJmVhqOjI5YuXarymlKpxIwZM6QrNvPnz0f79u1LND8jIyN4eXnxygxVK19fX1hZWWHChAkA
+gPj4eDYYJiqh0aNHw8TEBACQlJSEHTt2FDvN999/j+bNm2PkyJEsQIYZIqqLgaZJkyYAgOTkZCxY
+sKDQ8XR1dTFp0iT8+++/5X7PFy9eQF9fXzpo5Tlx4gQiIiIAANra2nB3dy/VfCdNmoSsrCyuvFQt
+UlNTsXPnTsyePRuzZ8+WXv/vf/+r1vlFVRBCQKlUlmm6kirL/IkKI5fL8fHHH0vP165dC4VCUej4
+KSkp+PHHHzF58mTo6elV2Lpd1m2nPNNyW2KYIWKgKaP8N9Fdv349Pv744wKrfwGAj48PbG1ty/V+
+SqWy0J7ifvzxR+mxra0tjIyMSjVvIyMj7Ny5kysuVQt/f3/I5XKMHTsWlpaWsLa2BgBER0fj7Nmz
+RU67f/9+jB8/Hi4uLnBxcVGpbpOUlIS5c+di+PDh0vBXr2rmd+zYMQwcOBCvvfYaOnTogJ49e+LA
+gQNFvn9KSgp++OEHDB48GOvWrSvyRC0wMBDDhw+Hqakp2rdvj8aNG6N///7w8/MrtB0cUUlNnTpV
+6j757t27Uk9lhR0z0tLSMH369HKv22XddgAgOzsbvr6+sLa2hr6+PnR0dNC1a1f4+PgU+gMbt6XS
+p0Qi9mZWCb2c1YbezOLi4sRrr72m0ouMhYWFCA8PL9V8tLW1penv3r1b6HghISHCxMSkwGGtWrWS
+5uHp6cmNgr2Z1RhKpVJ07dpVeHl5Sa/5+/tL63NJepK6d++ekMvlAoAYPHiw2vDo6GhpOytofgqF
+QsyePVvI5XKxZcsWqfe/6OhoYWFhIRo1aqTWI1N0dLQYO3as0NfXl5b1m2++KXD50tPTxejRo4We
+np7YvXu3yMnJEUIIcfv2bdG3b18BQPTo0aNSejRib2a1vzez/D7//HNpfezbt2+h21zPnj1Fv379
+ChxemnW7LNtOnqdPn4o+ffqI6dOni8jISPHo0SNx6NAh0aJFC2n509LSauW2VJW9mTHMEMNMJQWa
+2hBmhBDi999/F82bN1cJNADExIkTxcOHD0sdZg4ePChCQ0NV/n799VexZcsW0a5duwLDTHJyssp7
+r1mzhhsFw0yNcfbsWSGTyVSCfGZmptS9OABx8+bNYudjampaaJgRQggTE5NCw8yiRYsK3XYeP34s
+GjRooHZClpqaKjIzM8Xu3buLPOFTKpVi7NixAkCB301KSoro3LmzACA6deokUlJSGGYYZsrswYMH
+UrAHIMLCwtTGuXLligAg/P39C5xHSdftsm47Qry8fUGfPn3EqFGjhFKpVBm2f/9+6X29vb1r5bZU
+lWGG1cyIWOWsSD179sS1a9fUuq3cs2cPOnfujG3btpWqHr2bmxtsbW1V/vr37w93d3fcu3evwGni
+4uJUnjds2JArHdUYGzduhIuLC9q1aye9pqenh5kzZ6pU4yyOXC4v0/C//voLK1euhKGhYYG9Or32
+2msYMGCA2usNGjSAnp4e7O3ti3zfoKAg7N+/H02bNsXUqVPVhjds2BA+Pj4AgFu3buE///kPVwoq
+s9atW2PcuHHS8++++05tnK1bt6Jp06Z45513CpxHSdftsm47ALBz505cvXoVc+bMUesEZ/jw4dKt
+DrZu3Yrc3FxuS+XAMENUSYHm6tWrteaztW3bFmfOnMG+ffvwxhtvSK+npqZi5syZRd4X5lU3b95E
+RkaG9Jeeno6kpCRcvXoVffv2LdE8imr0SaRJYmNjcfjwYZVG/3lmzpwpddO8a9cuJCQkVMoyrFu3
+DgqFAgMHDoSurm6B4zRq1KjQ6V+9h9Or8u6XY2VlVej8hw0bBmNjY7WTN6Ky+OSTT6THP//8M2Jj
+Y6XnycnJ+OmnnzBx4kSVe6OVZd0uz7bj5+cH4GX30Bs3blT58/PzQ7NmzQAACQkJuHHjBrclhhki
+zQs0RfX+VVM/29ixY3Hjxg0sXbpU5VfgPXv2YPLkySW6QqOnpwd9fX3pr169emjcuDF69+6NzZs3
+FzhN06ZNVZ6/eqWGSFNt2bIFb7zxhkpnGnlatWoFNzc3AC9v6Lp9+/YKf38hhNRIunPnzhU+f6VS
+iQsXLgAAmjdvXuh42tra6N+/P4CXXVJHR0dz5aAy69WrFxwcHKR1MP+VzZI0/K/sbSc5ORnXrl2D
+trY2njx5gpiYGLW/MWPGwNPTE56entDS0uK2VA5ybhJElRNoHj9+XKKeTmoaPT09LF68GEOGDMGI
+ESPw9OlTAMBPP/2EUaNGYcyYMWWed7du3dCqVSu115s0aQJjY2M8f/4cABATE8MVjTReRkYG/Pz8
+oFAoCr1LeHx8vPR4w4YNmDdvXrHVyUrjxYsX0jZa1NWXsoqPj5duXljcL8SdOnWSHj98+BA9evTg
+SkJl9umnn0on/35+fliyZAkaNWqErVu3wtbWFt26dau2befu3btSN8xr1qyRrsAW937clhhmiDQq
+0MyZM6dGh5nU1FQ0aNCg0BteWllZITg4GLa2ttKVEl9f33KFGZlMht9++63AYXZ2djh48CAAIDQ0
+lCsZDE9QJwAAGAdJREFUabyAgACkpqbCx8enyLuEr1ixAk+fPsWDBw9w6NChcm1Dr8p/FTMzM7PC
+P2P+Kp95J36FMTQ0lB6X5OSOqCjDhg1Dp06dcOvWLaSkpGD79u2wt7fH9evXK6Qb/vJsO3mhRAiB
++/fvl+gGz9yWGGaINDLQ1GTu7u6YNWsW3nrrrULH6dChA3x8fPDhhx8CAP74448KXYaHDx/CyMgI
+enp6GDt2rBRm7ty5g6ioKJibm3NFI40khMCGDRswZswYzJ07t8hx4+Pj8dVXXwF4eRPNigwz+W8W
++Pfff1f452zevDl0dHSQk5OD6OhoCCEK3fflv/Ff/rZ3RGWhpaWFTz75ROpIY926dYiMjETjxo0r
+ZBsqz7ZTv3596XFISEiJwgy3pXKsC9wciKiwoLJ8+fJix8t/o8yS3GW5pJKSkmBpaSldbndzc1M5
+IBTUgw2Rprh48SIiIiJKVG9/5syZUkPkS5cuITw8vMwB6lWtW7eW5n3hwoVS9TxYEnK5XLoBaFxc
+nNSQuSBPnjwB8LKtUMeOHbmSULlNnDhRal9y//597N69GxMmTECDBg3KPe/ybDumpqZSEPHz8yty
+2ryOdLgtMcwQUSWEmaCgoCLvsAy8bBeQx8bGpsQnWcVZtGgROnfuLB2UdHR0sGnTJmn4rl27cPr0
+6RLPLzExEa6urnj27Bm/XKp0q1evhpmZWbFdvwJAy5YtMXr0aOn52rVrCxwvrzpJenp6gdtYSkqK
+2ut6enpSY+G7d+8iKCioyG20oG21uO33gw8+kB4HBAQUOl5eSHN3d6/xV65JM9SrVw+zZs1Sea00
+Df+LWrfLs+00atRICibBwcHYs2dPgdPm5uZiypQpcHJy4rbEMENElRFm8nauRf1ClL9dUP7uMvNk
+ZmaqXBIv7sQor3rOhg0b1HqAGjp0KNasWSM9d3NzQ2BgYLGfJTQ0FJaWlujXrx9atGjBL5cq1ZUr
+VxAUFIQxY8aU+ETjvffeU9mmCqrWkndl8vLly7h9+7b0ukKhwIoVK6SQk79TAQCYN2+e9NjDwwMP
+Hz5UC/ohISEAXvbClJqaqjI8f7frBTVMnjRpEiwtLQEAmzdvRmJioto4t2/fRnBwMMzMzFSWh6i8
+Zs2aJdUK6NOnDywsLEo8bXHrdnm2HU9PT+nxtGnTsH79emRlZUmv3blzBy4uLsjOzpZ6NeS2xDBD
+RJUQZhISEmBnZ4effvpJpYGiUqnEjh07pBt4LV++vMBfoV8NGzt27EBYWBhiYmJw79493L17Fzdv
+3sTFixexadMm2NvbS20MBg4cqDa/Tz75BPv27UOzZs2QmpoKV1dXuLm54eTJkyq/WKempiIoKAjv
+vPMOXFxcsGzZMnz++ef8YqlSZWZmSr8Ul6ZXsvw31FQoFJg3b57KjwB5PywAQHZ2Nuzs7ODl5QVv
+b2+Ym5tDCCF1VRsWFob3338fx44dA/CyobSHhweAl1VxevXqhRUrViAwMBDbtm2Do6MjDAwMpBO6
+7t27q9zQM/+PGbdu3VJbdrlcjkOHDqFTp06Ij4/HhAkTpAbQefuQiRMnok2bNggMDKyQKkBEeVq0
+aIGJEycCAGbMmFGqaYtbt8uz7YwbN066uWdOTg48PT3RvHlz9OjRA6ampjAzM0NSUhL8/f2lHz24
+LZWRIKoBDAwMxN69e2vUMgcHBwsAIjExsUaWuVKpFAYGBmLJkiXCy8tLmJmZiRYtWoghQ4YIV1dX
+0bZtWwFAmJqaip9//lltej8/PzFgwAChra0tAJT6z8DAQOTm5ha6fHFxcWLJkiXScgAQMplMGBoa
+imbNmgkAok2bNmLRokUiLi6uVm4X5ubmwtfXt07tC9q2bauxn3n//v2ic+fO0vool8vFqFGjxPHj
+xwud5q+//hKTJ08W7dq1U9sGevfuLX755ReVbXLp0qVCLpdL4zRr1kxs27ZNCCGEs7OzaN++vfD2
+9hahoaEq249CoRDffPONaNq0qcp7mJiYiHPnzon33/9/7d1/dNV1/cDxF9vdxgZzTn4VET/q2DIC
+A9EgEaxOBxI9kOmRUA6dOqEQET+UMDrQOXKC6mQHS4qAlHM8mgdPHTMMzBN4GHFU1CUJyVkonFJ+
+jDMYsrGN7dMfftnXxa8pG9y7PR5/7W73fnbv+3Mv7LnPfX12e9KtW7dk2rRpyebNm5OGhoZk06ZN
+yYwZM5Lu3bs3e41NnDgxeeyxx055LEeOHElmz56dFBYWJr17906mTp2afOMb30j69euX3HXXXRnx
+Opw/f34ycuTIDvWamj9/fjJu3LiMfgw7duxICgsLk6qqqhZd//08tz/Ia+ek+vr6ZNGiRUlhYeEp
+/7/94Ac/SGpqak57/9rDa+mkV199NYmIZM+ePa2+7T/96U9JUVFR0ilp7WlAaAOXXnppLF++vNlb
+MdJdaWlpXHfddXH48OGm39xkmqeffjpuuOGGk7/4iF27dkVZWVkcOnQo8vPzY9CgQTF06NCznnb2
+AvxCJnbt2hX/+Mc/oqKiIhobG6Nnz54xcODAKCkpadfvJx48eHBMmzat6TeHHUG/fv1i/vz5Heox
+/6+DBw9GWVlZ5Ofnx7Bhw5r+yvnu3bujf//+Z3091tbWRllZWVRUVETPnj1jyJAhkUqlory8PPr1
+63fOv4jeErW1tfH3v/89Kioqori4OK688spmZ3dKZ/fee2+UlpbG5s2bO8zz6d57743t27e36C27
+6ezll1+OoUOHttn2z+e1U1NTE2VlZVFZWRk9evSIwYMHt+iEOZn8Wjpp+/btMXjw4NizZ0/07du3
+Vbe9bt26uP32252aGTizkyET8e6ppktKSpr9sa50kK73C9pKjx49Tpkni2jZKVrz8vKaBpPf6+Tb
+SltDXl5eXHPNNXYUF1Rbhsz5vnby8/ObnfnTa6l1mZkBAADEDAAAgJgBAAAQMwAAgJgBAAAQMwAA
+AGIGAAAQMwAAAGIGAABAzAAAAIgZAABAzAAAAIgZAAAAMQMAAIgZAAAAMQMAACBmAAAAMQMAACBm
+AAAAxAwAAICYAQAAxAwAAICYAQAAEDMAAICYAQAAEDMAAABiBgAAEDMAAABiBgAAQMwAAACIGQAA
+QMwAAACIGQAAADEDAACIGQAAgDSTsgTQttauXRtFRUUWgla3ffv2DveYKyoqYu3atdG9e/cO85gb
+Ghri+PHj0aVLF096/163iXXr1sXatWs9AVqguro68vPzo1OnThYjTf6fEjPQVi+u1Lsvr9mzZ0dO
+To4FoU3k5eV1qMdbVFQUGzdujLKysg7zmOvq6qK6ujry8vKic+fOfohqQ5WVlTF69OgO9Zjz8/Mj
+IuLOO+/0BDiH2traqKmpiYKCgsjNzbUgLXDkyJGIiMjKars3g4kZaCPDhw+PJEksBLSit956q8M9
+5rq6uli1alUsXbo0qqqqYubMmTFr1qwoLi72hOC8LVy4MBYuXGghzmL9+vUxd+7c2Lt3b9x3330x
+Z86cpgjk4jMzAwBpLDc3N6ZPnx7l5eXxox/9KB566KEYMGBALFq0KCorKy0QtJHy8vIYP358jBs3
+LoYPHx67du2KBQsWCBkxAwCIGkhPhw8fjrvvvjsGDhwYVVVVsW3btli9enV8+MMftjhiBgAQNZB+
+Tpw4EcuXL4/LL7881q5dG2vWrImNGzfGkCFDLI6YAQBEDaSn9evXx5VXXhnf+973YtasWfHPf/4z
+Jk6caGHEDAAgaiA9mYsRMwCAqIGMYi5GzAAAogYyirkYMQMAiBrIOOZixAwAIGogo5iLETMAQDuN
+moULF4oa2iVzMWIGAGjnUfPwww+LGtoVczFiBgAQNZBxzMWIGQBA1IgaMkp5eXlMmDDBXIyYAQBE
+jaghM7x3LubIkSPmYsQMACBqRA3pzVwMYgYAEDVkHHMxiBkAQNSQUczFIGYAAFFDRjEXg5gBAFo9
+apYsWSJqaDPmYhAzAECbRc20adNEDW3CXAwt1SlJksQykPZP1E6dYvDgwTFp0iSLAZCGGhoa4sUX
+X4yNGzdGbW1tXHvttTFy5EjzDLwvhw4dinXr1sXOnTvjqquuijFjxkRhYaGF4RTr1q2LzZs3ixky
+wzXXXBNVVVXRtWtXiwGQxpIkiYqKiti3b180NDREz549o1evXpGdnW1xOGsMv/3223HgwIHo2rVr
+9OnTJwoKCiwMZ1RdXR1du3YVMwBA66urq4vVq1fHkiVLoqqqKmbOnBmzZ8+O4uJii0OTEydOxG9+
+85tYtGhRFBQUxI9//GNvJ+N9ETMAgKjhglu/fn3MnTs39u7dG/Pnz485c+Z4WyJiBgAQNaSv8vLy
+uPvuu+Opp56Kr3/967F48WKnWeYDczYzAKDNOfsZ/l4MbcGRGQDggnOkpuMwF4OYAQBEDRnHXAxi
+BgAQNWQUczFcKGZmAICLzkxN+2AuhgvNkRkAIO04UpNZzMUgZgAARE3GMReDmAEAEDUZxVwM6cDM
+DACQ9szUpA9zMaQTR2YAgIzjSM2FZy4GMQMAIGoyjrkYxAwAgKjJKOZiSHdmZgCAjGempnWZiyFT
+ODIDALQ7jtR8MP87F7N06dL42te+ZmEQMwAAoiZ9mYtBzAAAiJqMYi6GTGZmBgBo98zUnMpcDO2B
+IzMAQIfTHo/UvPnmm/Hmm2/G9ddff9brmYtBzAAAdPCoOXbsWDz77LMxfvz4i/44du3aFSUlJU2P
+KScn57TXMxdDe+NtZgBAh3U+bz/75S9/GRMmTIilS5de1Mewc+fOuPbaayM7OzuysrLigQceOOU6
+5eXlMWHChBg3blwMHz48du3aFQsWLBAyZDxHZgAA/k9Lj9QcO3YsPvrRj0ZlZWVkZ2fHlClTYsWK
+FZFKpS7o/S0rK4svfOELcfTo0Thx4kRERHTp0iXeeOON6NGjRxw+fDgWL14cv/jFL+Jzn/tc3H//
+/TFkyBA7GjEDANBRo+anP/1pLFiwIOrr6yMiIicnJ0aOHBl/+MMfoqio6ILcx5deeik+//nPR3V1
+dTQ0NDR9Pjc3NyZNmhRXX321uRjEDACAqPn/qLnzzjtj0KBBp7wNLTc3NwYMGBDPPPNM9O3bt03v
+15YtW2LMmDFx/PjxZiHzXgUFBfH973/fXAxiBgBA1LwbNQcPHoz6+vrTRkROTk5ccsklsWHDhrjq
+qqva5L5s2rQpvvzlL0ddXV00Njae9jpZWVkxZMiQ2LZtm52HmAEAIKKysjL69OkT1dXVZ7xOdnZ2
+pFKpePzxx1v9TGcbNmyI8ePHR319/RlD5r1B87vf/S5uvfVWO452y9nMAABaaNWqVU1zMmfS0NAQ
+dXV1cfPNN8eyZcta7Xs/9dRTceONN571iMx7JUkS3/3ud+P48eN2HGIGAKAjO3bsWCxZsuScMXMy
+JBobG2POnDnx7W9/+4xzLS31xBNPxM033xwnTpyIlr6pJkmSePvtty/6qaNBzAAAXGTLli2Lo0eP
+vq/bNDY2xsqVK+Omm26Kd9555wN930ceeSRuu+229xVEeXl50alTp4iIeO2118JUAe2VmRkAgHOo
+qamJgoKCiHj3rGV1dXXv6/a5ubnxiU98IjZs2BC9e/du8e1Wr14dU6dObdF8TCqVirq6uhgwYEBM
+mDAhxo4dG6NGjYrOnTvbgYgZAICObN++fbF169bYunVrPPfcc1FWVhZ1dXWRl5fXooH8nJycKC4u
+jmeffTYGDRp0zu/34IMPxne+850zHlXJy8uLurq6yM3NjS9+8Ytx0003xdixY6N///52FmIGAIAz
+q6+vj5dffjmef/75+Nvf/habNm2K/fv3RyqViuzs7KitrT3lNllZWZGXlxe///3vY+zYsWfc9s9+
+9rOYN29es0By9AXEDABAm/nPf/4TL7zwQmzZsiU2bdoUr776atTX10fnzp2jtra22VGWX/3qV3HX
+XXedso377rsvFi5cGBHvnua5sbHR0RcQMwAAF1ZdXV288sorsXXr1ti8eXOUlpbGgQMHmr7+pS99
+KdavXx9ZWe+ek2natGnx61//OiIi+vfvH1/5ylccfQExAwBcKPv27Ys//vGPFuIMDh8+HP/617/i
+6aefjoaGhujbt2/ccccdsX79+vj3v/8dH/rQh2L06NHRrVs3i3UWI0eOjE996lMWQsyIGQCg9ZSW
+lsZ1110XvXr1ii5duliQczj5N2mysrKaTqfM2e3evTuWL18e06ZNsxgdXMoSAABt4fXXX4+ioiIL
+QasbPHiwRSAi/NFMAABAzAAAAIgZAAAAMQMAAIgZAAAAMQMAACBmAAAAMQMAACBmAAAAxAwAAICY
+AQAAxAwAAICYAQAAEDMAAICYAQAAEDMAAABiBgAAEDMAAABiBgAAQMwAAACIGQAAQMwAAACIGQAA
+ADEDAACIGQAAADEDAAAgZgAAADEDAAAgZgAAAMQMAACAmAEAANqBlCUAADh/VVVVsXfv3vP7wSyV
+ik9+8pOxf//+OHjw4BmvV1xcHB/5yEdO+XySJPHaa6+d9jYDBgyILl262FGIGQAAmvvLX/4St9xy
+y3lto2fPnrF///7YvXt3rFy5Mh5++OFIkqTp6yUlJTFx4sQYNWrUGWPmz3/+c2zZsiWefPLJiIgo
+KiqK6dOnx4wZM8QMYgYAgFPV1NRERETv3r1jwYIF8dnPfjYuu+yySKVSUVpaGpMmTYqIiI997GPx
+3HPPRZIkcfz48XjrrbfiySefjGXLljVtY8SIETFixIi44oorYt68eU3f44c//GFMnDjxjPchKysr
+7rnnnrjnnnti4MCBsWPHjnj88cdjzJgxdhBiBgCA06uuro6cnJz461//GiUlJc2+1qNHj6aPc3Jy
+ok+fPk2XL7/88hg9enRceumlsXjx4ma3mz17djz00EOxc+fOiIgoLS09a8yclCRJVFRUxMiRI4UM
+7ZoTAAAAtIKampoYP378KSHTUjNmzIjGxsZoaGho+lwqlYqFCxc2XX7kkUfi2LFj59zWCy+8EAcO
+HIgZM2bYMYgZAADOHTPjxo37wLe/7LLLYtiwYXH8+PFmn7/llluiX79+ERFx5MiR+O1vf3vOba1e
+vTq6d+8eEyZMsGMQMwAAnN28efNiypQp57WNLVu2REFBQbPPpVKpmDVrVtPln//8582O3vyvo0eP
+xqOPPhpTpkyJvLw8OwYxAwDAOX6oysqKTp06ndc2srOzT7uNb37zm1FUVBQREW+88UbTmcpO59FH
+H41jx47Ft771LTsFMQMAwMVVWFgYU6dObbp8//33n/Z6SZLEihUrYtSoUR94dgfEDAAArWrmzJmR
+Sr17ItotW7bE888/f8p1XnrppXjllVeahQ+IGQAALqo+ffrEbbfd1nT5dEdnVqxYEcXFxfHVr37V
+giFmAABIH3PmzGn6+Iknnog9e/Y0Xa6qqorHHnssJk+eHJ07d7ZYiBkAANLH0KFD4/rrr4+IiMbG
+xnjggQeavmbwHzEDAEBamzt3btPHK1eujKqqqqbB/xEjRsSnP/1pi4SYAQAg/dxwww1NZyo7evRo
+rFq1KrZt2xZlZWUG/xEzAACk8Q9vWVnNZmeWLVsWDz74YFxyySVx6623WiDEDAAA6Wvy5MnRvXv3
+iIjYu3dvrFmzJu64447o0qWLxUHMAADQehobG1t1e/n5+TF9+vRmnzP4j5gBAKDVvfPOO00f19TU
+tMo2p0+fHnl5eRERMWzYsPjMZz5joREzAAC0rmeeeabp471798aOHTvOe5u9evWKyZMnR0QY/EfM
+AADQeg4dOhRTpkyJIUOGxIoVK5p97eqrr44bb7wxfvKTn5zX95gzZ04UFhbGxIkTLTgdUsoSAAC0
+vm7dusWaNWva9HtcccUVsWnTpigsLLTgdEiOzAAAZLChQ4daBMQMAACAmAEAABAzAAAAYgYAABAz
+AAAAYgYAAEDMAAAAYgYAAEDMAAAAiBkAAEDMAAAAiBkAAAAxAwAAIGYAAAAxAwAAIGYAAADEDAAA
+IGYAAADEDAAAgJgBAADEjCUAAADEDAAAgJgBAAAQMwAAgJgBAAAQMwAAAGIGAAAQMwAAAGIGAABA
+zAAAAIgZAABAzAAAAIgZAAAAMQMAAIgZAACA9JCyBABAW+jVq1cUFBRYCFpdZWWlRSAiIjolSZJY
+BgCgtVRUVMTGjRstBG1q6NCh8fGPf9xCiBkxAwAAZB4zMwAAQEZKvb79xaYLJYOutiIAAEBGcGQG
+AADISP8FpxZnWS0U37cAAAAASUVORK5CYII=
diff --git a/Documentation/DocBook/media/fieldseq_bt.gif.b64 b/Documentation/DocBook/media/fieldseq_bt.gif.b64
new file mode 100644 (file)
index 0000000..b5b557b
--- /dev/null
@@ -0,0 +1,447 @@
+R0lGODlhcwKfAucAAAAAAElJDK+vr0gSElYMDC8kDV5bEBcHOwYGSEQODmEaGgoKOBkTVC0tVyAg
+aDcJC6Ojoys8DAAYGqSkxV9fFFtdEJmZmUA4EF0wMAAAcAoTHTZHJ0gYGAcMTwcSO29ISFUHB2AV
+FXd3YAcHMRUVQiIAGg4HT3t7eywOJ3d3dwcHSEEgABMuDnd3OGpkSQAAYlZGBzEEBGJlDCstCxwc
+WQcHSzkRGWBtYC0AACA3ABAKNhAQTTMwDA0VQD4AAEYVFVVVVSQMJQULOB8fQScnYBgYRD5VPmZm
+DEZRB2ZiDAoKSgAAVAwQOH5+lBwcS+7u7hoaST4+X3d3WACPADMzMyBRIDgAAGBgc0JCEHEAAEwN
+DRkwDAoKOR8kPZR7eyA1IABpABgNQBA9EABVAAsLRww/DAwMPgBNAENDCgc9B8zMzAUFQQBDAD4M
+DAwOKgAAcQA5AEtLFYqKAA0NTC8HBxEREQgfCAArAAApACIqMkkGBhoqKnwAAAsGQ6qqqkoKCg4O
+MlkcHAoZJCcrW6SkpFQAAAAAOBAOSwAVGh0ROgMPHWZmB00QEGUAAFQaGjEyC2w4OLe3n4qKioiI
+iBAVMC4uXhkZUGIAAHJYWHd3AAAAPhAQUQUGL0BAIGggIBgAGkIVFV9fEAwcJR8KJA8MU9EAAAcH
+VRoaYWhoaDcAALu7AGZmZnAAAGRkZGQVFVhqWD4KCgwOUzMzDAAAmgklBzEHBzExClhYWBMTPAYJ
+Qy8fCFpaB///////ACISRExUDUQrDAwMVhISSEYYGHd3IDhcOERERElJAAkPNTsHF1hYckgGBj05
+CFYAADg4OCAVO0hCDDAwMLu7ilpaDR8qCDg+EBxGHN3d3REGNjo9CDQ8DBwYRGZmHFMAABQ+FBE+
+ESIiIhs+BxU0FWVeBw04DYqKsxAsEB8hQAwuDAc2BwwqDAoqCgcIL1dMDQAA0Q0iDQwiDAckBxAQ
+EDwAAAAAU0JCDAkJPru7u5oAADg4bAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAALwALAAAAABzAp8C
+AAj+AHkJHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXMmypcuX
+MGPKnEmzps2bOHPq3Mkz5z0AQIMCSNHyZ0WjE5GqNAZAqcGmT+8VZMoL6k6rEp0KfEJl489VBcEB
+GGjBwk8LBJsyFQqU15MUdQDUWfVk4JNVccER5ZXCT8+/gAN/xFp0LEWtDxEfRKo44s8n1/YeJCyQ
+8GO+1xhSbvwxRWaklBEiXoVW4886BNW0FQjkyem6laUKdLqKSuZrQIxtpbLqc51JbsHBFkw8pYUT
+w4uHDK2SM0PnCqHPNiz9uWGFoS1fb7h5u0nQshf+ar2G2isAKn4FpqByHQivn8YkY3WK9RoANXx1
+kwUncBVw5QCSdAsA8jiDXIAeEQYXAMbgp0YKKQAFYVxEPbjgXm/FBURmD1pQxz1qsDfUdAVlCMCG
+vFg4lhpMgbOKYX6IBY5fHX642FBx0cULbnKlUFdQkgS1IxA91mWMBWJRYQF7dZQ2HVBIsdhjbG4R
+WUeE4f3UFlQN6hUiUK1puV1Q93Sp24LglNYlAGmmKGJrvBxJ4YWxiUkmLzGymZ6ULnqXAlgC5Tmj
+QRE2qd+NkwDKCziTwAjcT6rhV1WW28013D11UfHfVrItieCnHw0YVIEHgnoRVutllgJ/X+F54hP+
+fjT1FWR68WXbXV3dU4cxmBoDnGpSaZUqru/NJRUVrV3DXrHBAnCNrrwmN9Cs17jIC2+QUUEUY4Zh
+qyxR52X2IlFwFWSUUU/8tmObXBrzxBNEhveeYVCd5wd5RD1Ra3eVzajGPeCoSq8x4qJ2ZXDghvlq
+rFJBBR6z82aGbLbe+TqbjT9lNtCq4npHUMblqQEOUr3Nmx+VJJIVl7aSToqQan/ZydbMNNds8804
+56zzzjzXbGpFWA0q0IdKWSWrswIhyUuTAtn3L9IE2ddsQUzveF/GKUJtwVirSAZECliLpnUdqmns
+ockml500agCkx625YxnlqUCT6NaU2lbL+zD+AKXNpTHK09Lr5MaCk+h3WrIZ3fDULnc90Nd4b12Q
+VY6zJtmiTnoc+LV+QYiUfuiyS6lB96wHAKDMAa5TZBC27vrrsMcu++y012777bjDHg3N4Dgj7c8P
+YTXzPUUnTvx1Rgl/PFlUgBMv2gMp/zaJawUFtuabT6fUudTFjfxYVk2/uVERCmX38tHrTe/iTa8C
+Th1A4MevyykCsStV9Bt1jfvwy288lQ5bX5zYcr3spU8g1ZMQ4gbCH7HxIlGLetp7/sOYOjxhPthz
+FX40VRDPqA54IISIqAhkoN+F0CFBkxf0FBe2s1XNaVG6D5W08sKrGcY+ZuPa5aB3I7OBI3L+qHkb
+EPPXPbiZzAKHSh8Om6YdAKowQ/TLnlUOhrbwbQeKinNiFaVSuYEskReSI4iNeNFFg1StKgnRH9lY
+NZYUSEopX8NgWpIDlVURJFawSd0J92iQW5DKhHzkTnhS9UALFq9Op6MVuW5VG7RF6oFt46GtrkEs
+pRgjWcvSVbCIhrwdUqtW3tLWvOqClFCCSzbiIxG61PUtlxnDXfBqosusAgQ42TGSHwPAj2TDSqbs
+kkS1rMst/zdLxjkMYza6JMWmshdNQqx0fAkYGanjyW6J0iiHUkq65DiQV2aGWMFB0T1EmbVAmjMh
+lDwnRRS0MvwcclI/WZCOTAQnpSwoPgD+mIRW6EnK6zyBKYZKmozQYk/vqIiKPEKoWNRAHtQkdC9W
+TNn4DPMlKkIllldyYy61mKK1UAE/AI3aQq2CJDbBhW2oXJFH/YeyekmlodeSYUnb5BaAIrEgk3CP
+QNlUmgi55UVNMoxPNwpJd95HMk5p1Ojsghe5lGwrTa1V0nSqzqpadSXVmckOr7rHdAEyNbDRVU+A
+MDiumvWsHclqTO6xKbSeMAVlPcgqWgMvReWkWm7Nq14tota9+vUjb2FILF/FE7P89bCITaxiF8vY
+xjr2sZCNrGQnS9nKWvaymM2sZjfL2c569rOgDa1oR1uSfxHvtKhNrWpXy9rWuva1sI3+7WkBaVrZ
+2va2uM0tbNOo29769re7FQ1wh0vc3/K2uMhNbnAN4hrlOve5p21ZQvIxi+pa97rYza52t8vd7nr3
+u+CtbgZUOBBP4OO86E2vetfL3va6973wja98z1uIhHBDFfjNr373y9/++ve/AA6wgAeMX24kxBpg
+SLCCF8zgBjv4wRCOsIQnTOEEWyMhSwivhjfM4Q6DlwaiYcV8R0ziEptYvp5gSD7cweIWu/jFMI6x
+jGdM4xrb+MYsngV5BeKJUvj4x0AOspCHTOQiG/nISE6yjy+REGL04slQjrKUp0zlKlv5yljOspaf
+TIyEVGEKYA6zmMdM5jKb+cxoTrP+mtcM5iok5AU4jrOc50znGztANPhQsp73zOc+JznFC1lxnQdN
+6ELTWMcI6bGfF83oRhuZyQhx8pYnTelKWzrLXUbIl9nM6U57+tNqdjNC4GzoUpt60HdeTJ4dzepW
+LxrQChH0qWdN60PvmBeKdrWud/3oJl/618AONpYzfZBNg/rYyE72mUV9EFLX+tnQdkeqSbdqXlv7
+2qWAdULOYYZue/vb4A63uMdN7nKb+9zo7jYXIIAQDhDg3fCOt7znTe962/ve+M63vt9di4TI4ggA
+D7jAB07wghv84AhPuMIXDnBZJOQd6Ii4xCdO8Ypb/OIYz7jGN87xiL8jIexIt8j+R07ykqPbDQiB
+wB/2zfKWu/zl+uaAiqNNc1oj+iC5xrbOWw3pg0ha2EAP+qWJbRBjK/voSP80sw3i7Jo7ndDTNle1
+d051RmsbIbJ+utbnfHOD5LzqYN9zzw3yc6Gb/exWJnpBjJ70trvdzEsvSNO3TncbR/1jUw+73pF8
+9YNkve6Al3HXC/L1vRt+yGMvSNnRznjGq50gbH+75N8ed4LMPfCYb/Hdp5X3w3v+x303yN8zn/nB
+E6Twn/d84gmy+Ma7PuiPH0jkJ0/7o1d+IJcnfeA3P5vOp/7woS/IEOZA/OIb//jIT77yl8/85jv/
++cUnBEJ+oIXqW//62M++9rf+z/3ue//74K8+LBKChWmY//zoT7/618/+9rv//fCPv/mxkBBzkOP+
++M+//vfP//77//8AGIACeH/mkBD2AH0ImIAKuIDPxwQIQQjhF4ESOIEUGH4/MHO6p3umV16/14Gr
+NxCt93oi+GuxJxCzV3soCGq3JxC5l4F0x3vv4XsdqHfBRxCj54J0t4E8NoOp94ECEYIjGISTVoK8
+cIIpeIRstoK80II4+HQweA8yyINVV4MDcYNN+HQ6iGtSqHq+JoReWGlEaIRIOIbL9mZXuHt4toXA
+h4FnmIO3hnpquHM+yAtA+IV2OGVhSIZ6mIRm2IYvmIZxSIMMAQUvUIiGeIj+iJiIiriIjNiIjviI
+kFiIS8BuB5EA83CJmJiJmriJnNiJnviJoBiKoniJOJAQ2ZAJqJiKqriKrNiKrviKsBiLsjiLqJgN
+CREPbJCLuriLvNiLvviLwBiMwjiMxJiL8ZAQhhCJyriMzNiMkDgCKZcKoziN1FiN1iiKCcCGfoiF
+bxiIejeHdXiH4tgLebiH5liGo7aNW/eEUeiNvEaFAmGF6lhrWQiH7shr4DiO+oiHXnaO/khmSsiE
+8zhr7HiPU6iNAwlt9WiQVJeP+/iQ5NiP/ziRUxCQCVlzBcmQOgePvEAEHvaRIBmS3pUBAoAQrsAH
+KJmSKrmSLNmSLvmSMBn+kzI5kyjZDAkRCgSWkzq5kzw5YKGQEGJQYUI5lERZlBQmBhgmkkq5lCC5
+CQghAI1Ak1I5lVRZlTPpCgzRAG+wlVzZlV75lWAZlmI5lmRZlma5lfRQkgehACfWlm75lvBVXwgR
+B3JQl3Z5l3iZl3q5l3zZl375l4BZl3GQEOJwBoZ5mIiZmIq5mIzZmI75mJAZmYYpDgmhCWd5mZiZ
+mZppliTwlCIGl6AZmm2pAAh5kTbXjRqJbQ4JkfpYjhTpjxZpmtCWkalpbRwpj7JZaAtZm9a2mqwp
+jq75muYYm7lJa7TJm7p2m8VJj6iJnLrmm79ph8EpnHpInMtpasfpnKz+xpFOUAPe+Z3gGZ7iOZ7k
+WZ7meZ7omZ7eqQKUaBADAALwGZ/yOZ/0WZ/2eZ/4mZ/6uZ/wGQMJgQa7EKACOqAEWqAGeqAImqAK
+uqAMGqBokBDrkA4SOqEUWqEWeqEYmqEauqEc2qESug4JsQbqOaIkWqImmp4LkHJ6wJ8s2qIu+qL7
+OQCleZ2EtpvayXNdGJ13OJ3UOYbWSaOFlp03anUzCqR0ZqND2mjQqaNCyKM9eoQ/aqR1JqRJ2mfK
+KaW62ZxVumhLyqQj6KRPioJRiqVyRqVbqmdXSqZ1hqRnymdd6qWvB6ZhSntjqqZ2BohtaqUM0Z0n
+2qd++qfmyZ4I8Z7+MFqohnqo+OmfCAGgDdqojvqokLqgD4oQEeqhlnqpmJqpHAqiCCGigPqpoNqn
+KXoQELCiiHqqqFqoMhpodrqmWpqnevamcNp4cjqnklenrUpjZgqrRpamuYpjbMqrSCars4p2tWqr
+boervxpjuyqsQ+ary1pjweqsRUasxWp2x4qsSaes0epizUqtQMaRWrmZ5Fqu5jqWaYkQbCma7Nqu
+cZkQdBmY8jqv9FqvfzmYCFGYkrmv/Nqv/gqZlIkQlnmuBFuw5NqZByEAn+muDNuw+ECaC+GRTDmx
+FDuSamkQJ2mVGruxHAuTNokQONmTIjuyJAtgP4kQQWmUKruyLBv+YUiJEBlWsTI7s9XllAkblR2b
+szqrsVjJqt1qY9MKrkJmrdcKexKprWLahz+rq3gqtEUGrUsLY0HrtD9GtEUrbNmKtMrGrUv7rU4L
+tVHrYlNLtaVgtVcLbFmrtcjGtT/rtULLkVHgAHI7t3Rbt3Z7t3ibt3q7t3zbt3JLA7eGAZ4wuIRb
+uIZ7uIibuIq7uIzbuI47uKCQEJ1ADJRbuZZ7uZibuZq7uZzbuZ77uZTbCQnxBVVQuqZ7uqibuqq7
+uqzbuq77urBbul+QELjgt7Z7u7ibu317DqIRCI/7u8AbvMLruBhAWsZ7vMibvMq7vMzbvM77vNAb
+vdI7vdRbvdb+e73Ym73au73c273e+73gG77iO77kW77me77om77qy1VnBEblsRXNlEGawRa6ARr0
+K0nzEhRCcxDlwxZScRdxYSnRIxRwsr4GfMAPkQJUxQtAYFdDhRhqQCSEhRCh8TBGdMHumx5ptB3k
+gSK4UQcaYxXKssAIXMImPBCqARsXpMF+EBcSxUB0wRVJNDnkZcFEdcPRJB7bcUkFUUuAEysnHMRB
+TFMt7EVpUkRTEVYZVMEChMEGZDV/cyN2IUOpoUtRBMRCnMUHrMD9IRm+kkqE0kCTUcNNjMMvHEVS
+fMYcNcJa3Mbqm8JLIylcDMZ2ARe3VhVskTIzsy0eoxV6BD3+ilEv5vNVblzI3qskMXIx/aTGhUQw
+2EHGH4S/TvFFDrQVVIzCVvzHhrzJ3ptTldO/ZIIYq3LHB3TBTEw622FH0bHDJOzDaMzJsAy+9vFD
+qHzGFyRdCXHKryzJ1+EhGlzJTQM/t2E/IUzKsXzM19s8aSwzvDIzuQzJeJzHzJy/QLG/G1wiTXU4
+kYzM3NzN3vzN4BzO4jzOZpUCr3TOr4TLH4FE6PxKcUXO8BzP8jzP9FzP9nzP+JzP+rzP/NzP/vzP
+AP1YuTPQBF3QBn3QUexXrHPQDN3QDk3QCb1XpfPQFF3RFg0hjtUzGr3RHN3RPGPMZiUzHj3SJF3S
+NwPSXAX+yia90ixN0hm9VXr1Eyh9VTKdWDWNWEOF0/K7VyOCWDd9WD/9V0HtVzl9WEWtWD0N1Joc
+0kvNVUO9V0dN1DutV0ntBZhw1Vid1Vq91Vzd1V791WAd1mKN1YEz01b10zfwCmq91mzd1m791nAd
+13I913Rd12p9A2WdWDl9DWPd137914A91l5AOC/NgWRLZD331DGNFWKotlub1zrNeYdNZLAW1YiV
+1PZItond1DTN2I5Np5Bt1MjTjlRb2VOdV5g92YgX2kLt2Z99q6wt1ZKt2kFm2oW9g7QNZJtt1lX1
+04392ioY21A92rkdroTdWEnNCKm63Mytn8sg3IsdHur+oKnUXd3WvaHqAN15ldOE0Nze/d3yyQjH
+zVipXdxLpt1u5dvATXnojVY5DYXm7WO2jdySkdlUu9s27drrva3tfVbvTdpfO96LVd7mjd8+rd/7
+bXv9Xc7EHd/zTd71Hd9lu+BOjeAJnmzMptjb3eDm/eADLhmECt4inqqKOi+8rU4/XanXveIsrqmc
+auJ6fR2lOuI0fqqryhen7VYEXtwGrtTh8dsXvmYZztlW9d8S7uFIHeHx3eOt/eNBruDaE+Oz3eEC
+nuSGXeAU3tlO/uQYnuVFzuHFjeSJldTr6rBmLppyCeMHHh76+q9u/uZw3pgBq+aiPRAKe+Z4DpoQ
+i+P+t80LjpAFgB7ogj7ohF7ohn7oiJ7oir7ogO4DXt7bWOENLTvplL6y3vDo6pTTAtANjN7pnv7p
+oL7ojlDlY67kWB7lay57XN7lqF7nvXfkpH7Zps7jmH5O6r3qxzbkJ35ORu7gsX5YO57bTO5Xt47r
+Slfr5tTrVK4eOY5WST0MbRDt0j7t1F7t1n7t2J7t2r7t3B7tdIDsgfTT8FAG5F7u5n7u6J7u6r7u
+7N7u7v7u5A4P4M5HOQ0BD9Dt+J7v+r7v3D4Mv/5XwU7bwy7RFm7sfNjqf6XsYf7vfhXwqj3w0a3q
+Bu9pui7lr+7rzN7n9u20EJ9XxT7xB0/nCQ/muS3+5rJ+5bSO8MRe8CCPZhUf2Re/7HxO3wNBfRV4
+8zif8903fipP8OFhfwMY9EI/9EQfgAXY83rF3Tq/9Eyf8xeY8TSP26cu8iu/5S0v5PO+Rwpf8gzP
+07Mu7Fl/Qh9/9S4f9iG09bRt8sD+9QJv9iA09mQPd24PPGiv2moP8Gz/8HP/M3Af9wC596ZS95N9
+9w0vGe4Gc4if+Ip/b/2G9B6PFRDXcZI/+ZRf+Rv3cY7vVvW+covf+Z6P+DIH9RCO8mCf+WjV934v
+Zi/v6jEI66L/4aTf9qZ/Vqif+m0G+KAi+IdN+F4f+3o/+0xt9bb/98Cf0iSf9l1P1ZIRAnne/G3+
+meYant5Y8Q1jUP3Wf/3Yn/3av/3c3/3e//3gX/3fgPufoukL6/zoL18hkPyoLRl/HurwH//yj+iO
+XvxaPhCSXun6v/8Sdun2/+UAwUuggG5ZDB5EmFDhQoYNHT6EGNGgI4G8UgComFHjRo4dPX4EGVLk
+yIwAUlT0VErlSpYtXb6EGVPmTJo1VV6qeA/APZI9ff4E2lMnT4FVphxFmlTpUqZNnT6FGlXq0So5
+dwbFmlUryYs58dkEG1bs2JqeKnbdmlbt2oomUZKFG1fuTJwCh7LFm3fk3aJT/f4FHFhqVbtX9R5G
+nBEtr3tf5z6GDNeswMWJLSd2KzBlZM6d6Vr+JXpZtFq+vIwKRp1a9VPCjA2Php11cWPPtW2vnGwR
+Y2zeWzPzwuBJ+HDixY0fR55c+XLmzYWDAt1butDXX6pcx55d+3bu3b1/Bx9e/PUv0aefBzk7kHP2
+7d2/b47h7G709UH+tp/fdWj99kv3r+8/AM+rbEAC6TMwP/wS7E1ABmNz8MHRIpTwsgIrHO1CDGNb
+cEPLKPRQLxBDxGtEEtfS8MS8UlTxMABWuSdGGWeksUYbb8QxRx135DHHSV5rUUQAJumxSCOPRDLJ
+GH/kL0i8LlIySimnNHIVBJ1EDAAtt+SySy+/BDNMMccks0wzm8SSNDPXZLNNN9/0Es00t7r+CE47
+78TTzTkTo7JPP/+U8Yk92XoCUEMPRVLQQdW6BlFHH8VxUUknpbRSSy/FNFNNN+W0U08/BTVUUUcl
+tVRTT0U1VVVXZbVVV1+FNVZZZ6W1VltvxTVXXXfltdfD6rAgIwvqyOiJk1zDyktjkOVFWWYz0mlL
+cPz4qEsqQrtmlToAACcFQaPt8pYvj7WACi2pCFYgbjWyUk5f34V31xSAyAiIVRTbTaeN1ABCSyAU
+5QjIwtRFU1+NDOZlWGo7MuwJbQW9po5VruFFDSqo0EjgZvlbhYqF/aDi3mYBUCOjbd2NN2WVY1UD
+AEWfAGBhXvzYdmCNwFnliSeoWJbhgnf+0xhhqxQDx6PXYObJGHoreqLbktB8zQJwAOblCWCbpeLY
+mc1FeWWvv0YVnHRprugasfO9khdjFBU6458J3qjtZ3m5BgCKAw7Nap1J1mgSjNuCOjQqJtkoBYyH
+LFqgVZgEu3HHUZ1Xca2NIRLtj1JIHO+4gX774Cs1hrvqVaiVW2iNXwsao53AKZmXOuru+nHZZ6+0
+ZUHraD1yg+UWyNg6UPbSZi9PKv1zd50t/umNUH97pxROAnlj2qen/lJ0/Uj8njq+tXyjSeow5m6f
+Nw8d2rSFrlt8tyv6UQ2YW2f/7/IBr2hw7w+/R42iF5e+ev//T9Mk7HWsOnEpRmnDXOz++me++dmM
+gWfJ3PL4cxWlFctp9FufQIZFNasF6yqse90CAThCEmKobqwj39yqxreQpK6BKnyWwowWmu8JJGIT
+q9jFMqi8inTsYyGDm+H+BroSFtGI9qFCBIfmGi4ZA1xbmmEKv8TELS3ridOqFpeoAL9sbatbVBNh
+A8t1LsLBrWVlJOIR1bhGNrbRjW+EYxzlOMdQpcAYd8SjMeCHGAvkEY/pomMgBTlIQhbSkIdEZCIV
+uUhGNtKRj4RkJCU5SUpW0pKXxGR98rRJTnZyS1pD1RM9OUpSnmlVoixlKlXJJVgBwBjPg2UsZTlL
+WtbSlrfEZS51mcsOlUonq9hlMIX+OUxiFvN57Trli4y5TGY2M5jGSJuqelmqaY7KRKC65qey6SkW
+naqao/pmqLbZqXFyqpyb6qapwhmqdWozjaI6p6bimal0UlNryshHPvW5T37205//BGhABTpQguoT
+fu30VGlc0AKGNtShD4VoRCU6UYpW1KIXZagLzJOq0lSioB8FaUhFStAozKeVWsuHO1S6Upa21KUv
+hWlMZTpTmtZUpbMIDULJ+Rpi9MKnPwVqUIU6VKIW1ahHRWpSfUqMjYbyNS+waVSlOlWq1tQBJn3V
+b1JaVa521asyxWlbQHmq0vRUqWdFa1rVilSmFkaB7gwNVL86V7py9aqUiWaqtFr+V772laZhVddY
+TVXWtRbWsIc9alv3k8y4+tWxj13pXXVz0opsFbKXrStgmyVYX/IUsZ8FrWEVO09MlUaumEWtVyVb
+T1L9BgovgG1sZTtb2tbWtrfFbW51u1vYLgECYmVsRWxxDOIW17jHRW5ylbtc5jbXuc8lri2aStbX
+GIK318VudrW72xFg1VV7TW14q6pZnZrTs6FFb3oTO93BPlW875XqavOKKvDC175gzSlnSUVY9fbX
+v0tlb2cbe18Cv1S+lBWIZQu8YHeQV7/WPO9/JRza0b5TnO5lMIMPnFWtEWEWHwZxiEU8YhKX2MQn
+RnGKVfzhDAgAuKoqTShUMWP+GtfYxjfGcY51vGMe99jHMw5FgPf7miWs2MhHRnKSVbwJ77bqNw14
+Q5SlPGUqV9nKV8ZylrW8ZS5HmR4uDmxwBRIHOZTZzGdGc5rVvGY2t9nNb4ZzmeMgZAiHRhNdxnOe
+9bxnLpOgyayqb4YJ7GAx88KsE0b0YSv81oRiWNAE3vB3UfroAhMaxhFOdKbTuuhCn5bS8I20kyf9
+aftamqOY1nSq2UpneDqa1OINNaC15oQa1NrWt8Z1rnW9a1732te/BnatVfDbMF86NGjYRbKVvWxm
+N9vZz4Z2tKU9bWonGw2svnBo1hBsbnfb298G9gL+vKpAvzq1pnZqaA6tanb+F5XTxq6Ip82N2liT
+e9TzPnd+C73udvcbqO8+9YDxTe9xS/PeA78suqmrbn83/N/YxqarEf7Yehu8shPHrMLby3CHOxzg
+6Y43xi9bcb3OGtwnR3nKfT3sFwe8IsiudsxlPnOaT/vabi30tlW+c56fXNx4RTAvFCzyvmpcwBXh
+d8fZ/fGFh5zojiU5fQ/+9MzqG94CSbrSU830jTud6nyNujen/vWvGn3IHNd6u7l+dIHIm+yqLXjJ
+KwJlPtfd7nfP8pdbDvIxx9nvfwd84OE8Z5xfnRd3xnviFV93PwOdwxXxsJIlP3nKn7jFe2+6QGT8
+Y8533vOf73GQC+9ygRT+ufKnR73kmex4SV/87XQ1e52RnvZ+r/3sXn893Fkvatfn3quxbzXaab91
+iMMV976vatjVOXbkSxX42Z798FVte9m3vfldVb49KzKEYHTf+98Hf/jFP37yl9/850d/95VA7M0W
+WhZHgH/85T9/+tff/vfHf/71v3/4y6L4jQ6NEUi/ASTAAjRA9HODuJO63ru+qXq+iBM+6Us06gu+
+42tAm8q+1mK+C5ypBzQ+rJNA4hs9vuMFt+PAmcpAcNrAE4QpDwTA6AvBCfy/nRI4FqSpFBSVcrPB
+mHJBGoTBGJwwCoQ+69vBG1RAsdu+OVDCJWTCJnTCJ4TCKJTCKaTCKlz+QkLAvK4TCCyYhi70wi8E
+wzAUwzEkwzI0wzNEwy7Eghk0r9CwByuEwziUwzmsQiY4wuVjwCJsQasjPUMDQhkcwcwrQT1EwTvU
+vgQjRPzKQrbzwz8MQjbcFNNKxJjCQXZawUTswTb8QUfsLyGEQAucRJWqRFDRwVBsMD4kwazjRAqD
+RHmSOFN0h1H8lN9oAmWwxVvExVzUxV3kxV70xV8ExmC8RfEpr0h8DRGQgmRUxmVkxmZ0xmeExmiU
+xmmkxmQUgVbMlNIQxm3kxm70RmG8AkPUQFkrNBI0x1NhLRUkR8M7Ry1MlXTMwQdTR3YUxHYsFXhk
+J3Dwo33kx370x3/+BMiAFMiB5MdidEWeIciEVMiFZEiC5JpkQsiGlMiJpEiBBIf5OpWK1MiN5Mg/
+WhU16MiQFMmF3KNTAcmRRMmU7MdMYsmWdMmXhMmYlMmZpMmatMmbxMmc1Mmd5Mme9MmfBMqgFMqh
+JMrzuJqKGJZiORbeGQnkAZousaLz4RIsAomWWZr5QSWTQCXisZaFcaUHEoh+OShncZaiNEv0iJyK
+sBd8caCK4Bd/ASMeeiAX8hykrAOZ6Yg6ARgieg3eEZoU2J6RKaNngZkOARILO8vEFA3b6Z2YqQia
+6Z6MwBmd4ZkoqsswgqG/VKKNAJajxMzy8UvjaRZjCMxnmQRwOE3+CZJLxWTN3hAbgSAbGzqbthSI
+taHN1RSezgFLurEbj/ADl1mFq+TL0AjNjKGYnaCCpUGYrKmbkjxMRmvN6ESRpQGmiqCc3cFIzLHM
+udTNJcIgjgjOmXGZFwLNaPpLNMofxzSY5uSFrNmhz5TO+MwLxsQdyqAX7OwI3wGeLhGeLuHKFPpO
+zlyYOkDP8SmMLuEJUTrKqwDMQtkNvxGIGlrN4ZHPCsWL68mewMRP7wEf9VHNy6TL3UyfjvhNLSLP
+BSrOHkocwwgZgzEXLsHL57TQGc0LAapO3UBQuUmgFuqcEPVOi9jMHhIZ8TzO4yFO80QQgzGMlumK
+ERUIIApQxKT+0SkdiRMqSWZpm/cRCbr0UQeSIY6wGrwkUPjsSyTlzvnACMPJCAmdHyml0jf9iCTi
+COxsIlTaziWaIlGKSmnBS41IyozomJFhpe9EpajMiLqhFiAxF15AzUN1zDYNHjiV1Eml1Eq11Ev1
+HzvaxyvNiz7aR0DC1FAV1VEl1VI11VNF1VRV1VVl1VZ1VQNxpliV1Vl9Hme4BVrF1VzdJVRwBlTQ
+1V8FVlniVV8N1mLV1WE11mSl1VtwBmV11llVl1WS1mml1mq11mvF1mzV1m3l1m711m8Nk2KTJmdY
+FUkAAEko13NNV3RVFWfASFFBC4PUFAAgV1UxV3ZNlXtd11X+cVdWiVd5zMF6zVd1tVeCHVh8RZV+
+XZV/dUtIcdg+2UuBVYOHpdgoqQh9tYuK1dgjuViD3diP7ZGOxVeQJdkcqQiFrZqSVVkagR+GTbDU
+g9mYTbEMyCmB9QR8wNmc1dmd5dme9dmfBdqgFdqhxdlCENmK4AbQU9qlZVoe44ajFQhrAIOppdqq
+tdqrxdqs1dqt5dqu9dqptQao5QXTk9myNdtZoIGTpY97YAWiddu3hdu4HdrccFmhg8WWIi+bvY29
+7Yy64AWMbcRV7ESxPY3VMNzDFYzWAFwTDEXJQlna4NvInQu6BZpLJMS8fQvJ1Vyy8FvAVUXBRSzF
+AtzCRdz+0jVdp1Bcg2XcSXTctXWMzYVdm6BccR06WMRczYjd3KWJzjXYzwVd0SLc0xXe4UWK1MXX
+1U3E1vUK3WVemJjd9hOIczCD6aXe6rXe68Xe7NXe7eXe7vXe6eUC9qPXiuAAAjDf80Xf9FXf9WXf
+9nXf94Xf+DXfWhDb9+O/+8Xf/NVf/fM/gQDcd0CHABbgASbgAjbgA0bgBFbgBWbgAH4HsWWH75Xg
+CabgCvbeBBQIlIWAP5DfDvbgDwbh+OUArCrFULxdXtiM5lXhmxBb3/3dtRJdgyVd4qVhwzVeUGxc
+tV3eFV7h5y3hSTzhFOZh5uVdfHXhF9604K3hJV6NGyb+wrsVRR22i9cdYt31YcvVwyCu4uYt4k1E
+YkVTYiYW48Bw4kGE4ijOYNfdYua94jy03ZrN3DWO3S4GwS8GrRjG1xke4z2GijJGXkJU3imW49xt
+Y4EYAjpE5ERWZCrEQnUR2B/QgkiW5Emm5Eq25EvG5EzW5E3m5EiGBbHlwjQU5VEm5VI+wzX0X4M1
+B3Jg5VZ25VeG5ViW5Vmm5Vq25VtmZXMQ2zdc5F72ZUS2wzSuCELo5GI25mNG5k7+ARLG4iLU4kGG
+XToOXDsG41TOYz7G5qjw4zNGY154XCqG5sgtZLvl5mcOZ8mV5iOm5lWz5orQ42yGZ6oQ2z/Ww0Bm
+DHD+PufbGOfaNUVzzue9Ted1Dt0wjueCnoJt5mZ7htx/3tt95uZTbAu9ZWiAbmGBrua/lWGD1miE
+PmOFxueJ5oxx5r4DJOmSNunyW7+IrohhaIOWdumXhumYlumZpumatumbxumWpoP63d+e9umfzr/+
+xWh8hYcyMOqjRuqkVuqlZuqmduqnhuqoNmp4EFsBPOmrxmqSxmBvpg8IeICcBuuwFuuxxulhYGY3
+7mc4xl2Qto2AtujCwmN31miD5mgo9mi2tg2HLme1RmG8rg23fmu1iuu+mOt4ruu7vWu/7gy9PmN/
+VuzHAOzARqvBNo3CNux5fujEfmzIGOfIO9vPTr3+y3PkinAFPjDt00bt1Fbt1Wbt1nbt14bt2Dbt
+ZhDbzWva28Zt0BO9oa4IMfja3wbu4BZurxUDsSVb0EbuyVs9rq4IAWgE2Ybu6Jbu6Y5tVzhrgaC7
+xdPu7c47MGsWgVUAuRXv8SbvoDXadu47wVPv9WbvNiM83hYIcTiD+abv+rbv+8bv/Nbv/ebv/vbv
++RYHsUU87ibwAn+DxmPugWjb8mbwBhdvBbhucm5svhbizZaLyJZspaLsd7ZsJj5sWNRsC5cLxoZi
+xxZxzq3oDJ9sgu7wMf5wUwzxEycLEr9bE5fxsMBwFV8v9K7sFufjF89hYRbkG5eMCKe1nkPyJF/+
+OfEV2AEAgSeH8iiX8imn8iq38ivH8izX8iePAbGFuZoD8zAXc2i7OfjmhXVIhzRX8zVn8zZ38zeH
+8ziX8zmn8zRfB7HVOSXX8z2vgZ9LcF6AAD3Y8kEn9EI3dC0fgAjnZxOmcCKHixzXcXdjcR9fYiBn
+XSm+Z0efcUV/aBvX9M/gcXWO9F7YcErfY0tPXkxf6E+XXU7fa5Vea1a3CUgfdaEqdVMXY1QHZFX/
+aFl3XlefcFjva1+vCVqv9YfjcQ7H9dPV9XrmdWIviwgvAj6ndiVv5O+uCEY49G3n9m7H8mUQ23oY
+83En9zCvB7FVhzpX93Vn93anc3XA82qX953+83OUJQRvx/d873ZGAPYSb3RoB3UzF/VIv/Vlr+Fm
+L8IYB3iXoPE3FvYKX/iWMPZjB7BkN/hKx+yEfvaI/3XH+2FM/HeOd4mJp/iCv/jhRfgdVHiRL4Vx
+zm4Dh3nF07vRFojwdvCbx3nzFlsya++e93n1fm/Ale//JvqiN/qj7+8A5/EBj/mmtzsER1kBWPCc
+p/qqxwcI9/gOS+6tlzzRxnaBKG3qFvuxJ3vXpm0et+3cVvu117HdBlzfHu64l/u539ri5vHj5vq8
+T7HljvrnLvu/B3yxt+6sR2tGf3iWH/kUp3iiMvmTZ/aM7+iNR3zc6PcaD/nJLwWSP/bGd/z+0k15
+G1x5kW/4tD58zGfhUF98Sbf4zhfez2fB0Of4ca6E7aL92rf93FoCvg6ES+D93vf93wf+4Bf+4Sf+
+4jf+4+d9KwDlTGD+5nf+54f+6Jf+6af+6rf+62d+VDZzFmCD7vf+7wf/8Bf/8Sf/8jf/80f/7mcB
+sbWu23f/96d9XFD1QkD++rf/+8f/4w+ECNcrgUUVwAUIXgIHEixo8CDChAoXMmx4UBIASQ4nUqxo
+8aJAiBIxcuzo0aEzAB9HkiyZQiQvAClKsmxpEYAzlzJnItRI8+ZNmzh3ttTJ8+fHkECHejwpUCXR
+pBdhKm3q0KfTqA8jSq1qEKrVqkKzcjX+mnLVvbBix5Ita/Ys2rRq17JVCyBa27hy59KtG7YVgFZ2
+9/LtGxevXr+CBwsGTPgw4rnRACRu7BjtKpQAJlOubPky5syaN3Pu7Pkz6NCiR5Mubfo06tSqV7Nu
+7fo17NiyZ78W+Pg27rCSIOTufViAJAG+h/sFLpw48rrGkzOXC0FS8+hxuVKvbv069uzat3Pv7v07
++PDix5Mvb/48+vTq17Nv7/49/Pjy59Ovb/8+/vz69/Pv7/8/gAEKOCCBBRp4IIIJKrgggw06+CCE
+EUo4IYUVWnghhhlq2N0TFvBizEIgJmSMMSlQoUaIaohI0IofbvgijDGilwKIIF5DhTH+JxbUokE1
+NsTjQC0CKSORRRqp1CQe+rHSkj5a4Acv1/BYIonXuPjhNeCkoOU1JuqYQgoe8rJll7xYQAUVHoLo
+B47gCDTkkXHKOadH1wDByyrXPOFji0vueA8v96xyJZ+8qHHnjR+iGKSLVDzBCzh78uLoE3XQeSmm
+mVrkIxBW+mgoECvtyKiIhVpQolFTYqnllvd8Cqemscp66SSrqEliHacGusqjPQIq6KSGFqrGSh1e
+SeqVkzT6RKWzOvssndcA0OubLq6CY4kFgUnio9eC6aKIXkJZarUgnknFSmvieOex0Lr7Lrzxyjsv
+vQx1CSaYVta7L7/9+vsvwAELPDD+wQUbfDDCCSu8MMMNO/wwxBFLPHF1VOhrgbK8GNuuQiSSqOaH
+HqfLIonoHlRHyYt6uZKKxqBM5ctK4kjFuIMKtAqsCIUpkJ0DiZkzySSOzMvLxqhYUNHUBukyiSiu
+/GbJYlL0hJs3L2os0AQVjWKNIrfrsckGvazjmGiudCrT28ZcdtjG2Ixn1tqK2bNAPzvkcbZde/x1
+yaIS1PLLvLCZI5Qh57jo1FXjuWjhcQu0tYhFgzxQ0ifnKOrgNJuJK5VMG822qG4PhHNFFtedsZnV
+/ugxyHh/CvXlBqGNMpMzFz424hdNknGnAtGoepQz5w58uaMyerPUx0u6s5l+Czn+0D1APPoEEK4q
+Do7jAx0qUJK2odSil8kTTyiLxgN70IrMWzB0sBYBsSgVA/3e4o2H9ziqqsfjKf6Vy4u5vv6Opb50
+XS97AtkeL7o3JnINBAho4p+q8gc8WyFERNGbXvWuRLeKvE8g8TPU9whyD+Hd73gSvNL5jBe/C2os
+g8RL3/8IOBDsVWR3AundAoFXP7KVr3wnXBEF0Wcb6bUQUCLa4EUSRTWBNAl4T4oSkCJoPB2yq4dP
+YN+xnnczfUUJZ6uAkh9IV5FITcpK1GPgzTxYQhP2UH9wWtHzVvTBigAwjEycH0GeKKU1Fq+Nx0Ki
+6q74tQDC0YdfFJwYKUJG0xH+C43EEojiAgiuKf6xisbL00CuMagjWnIidbSZGMGHIkAOkmNa5Jjq
+QIRJnr3tlHE8ZBgNGDyNVa2RToTSHik5ST+uiJSqW2UXNdhJi1jMT5JC40D8tKO9gYt1pRwf0XBl
+xDa6cplqGBRYZDkmCzzhgyk4GioltcymXaloppSkG30YtYssMQVQOiYqBec3ygmtXM48JSpfVodp
+prOf5bomnlxlkTB184biBBIp8cY1w+WNlxUcn97AMTyHtBNKk/ADMpM5z8fVM3IeW6g/tZYjcOQy
+pIUkFUCzScxrKFN6GZVnj5ipt4YS8qHnxJ1HdrcKFPUOmYfaKETPqb+ECqT+oNXUHzA1CaL4xU+b
+h8JYoIbWoiumQGlBfSbw3lhTbRrkfR/sKcd+KkQfUrKXwxSRUampVmQxNZ4LeaqyUsDPqa6CV3zc
+ZU15NsxfclGTbqWIV1tIPhGuAqil/CE6r3SopLZyrcVrqzZ16rS5/i1UY0WWQ/VqU8b+1SJ2+qDH
+cnUsQVlVkq974eggyKgB5jVQRKSeQFNQ2M4mhAq9m91pO3jZVPoRhW+bImu5WhAL1BV2uWoRaW2K
+2dYGUa2sRa3vYugi2WJxIra1Eo1cxr49cVGXp31mc8332gwKN4/FBZzRWgRA5Q42rym0YvXGCyjo
+brNuI6MubQ/yWd/hin3+yd0tXukb3h6yELb5BexGPUqia9XTuwxNF+vAZljJ+c5smWWi7VwkLU/p
+bo6qK5oAzOngaDYNbyup3G6fdmCG1KFwpBIZg7PlYBOTOL19s9zHKhw2+oKuWhtecUEm4eFyeuwE
+2CPRXWc60+zGTrmZa9xIWtxDEx9Zxpml8NZQjLSPCi7Dre2xhgHAYfclmKMLxhZQI4g3hqKtyZd9
+MjQpJuc5y+he+OouR/AFpvmqZ3344t9F/AwmQGfFzvn6iKFTgOfz6FmuIxE0865zj0aPJNGLNk+j
++dyRTNO5057+NKhDLepRk7rUpj41qlOt6lWzutWufjWsY91q0frMUgP+EWSgULIUy4DoHpLhda4N
+4mvKgMPFB/F1rpPHmGFbZiWX6bVlNJcSTWvN1rdeRR0AUIeqHuUy3aYMDvkIhN9KK3d+YwxGmE2Z
+YKfE29MuiLqLrRBkpwS5IsEMiDDz7cnIm91dBcDwXDUZ3ap7Mr+qTL8REm1AneQy1JZ1VFJgyXET
+xCv0ruzASzsQdMNbMg+/OPR0bQEpIwTZvq4DtTh+FE2rPOQVR/m7DeKHybi4m71Tg21XfhCOPwHb
+pX1kMq2dwEh6JebXzjYPha1rlxudIC3398iN3fFuow7kLX+6zn0Hc5DfejLzVAMAlHXFrS+d6WYi
++c7n23OYew/i1gH+e6+eAAAX+yHbbS8IOHjVTVhhnd59L7u/xxTJqfvayldn+cfLjm6s82LcFPdd
+JMFuJca33MoDmQS10b7je9g966Mznc9LDni/P7zpgd9SQvzusl5ZHfFpd/rBDzIJcMyeRfNMU+DN
+LviEqFzufOa6260CDjHVPZPDRwnwjcF6wG888Z7X/d15JmbR5xrsizo87JVekOljXe5+GPlAqIA6
+2zyK8pq2wOBRWVyNAbyotNf10x39fBGO3uOvpz9Bfnxsj+c88Ng3yNWhCPBNiqK1H/vljhpYyQCC
+nP4BIJ9VCrUMYPBFHLvM1ptgHvIxn/ykX/Npn+nlXu4xXrAh2+/+NN3/4Z/8ZAzWgZ/3zV8HOiAK
+ZtJvMZGtnYn8yBX8lZ73XBoIkt79QZ8Ikh7YQUnrZR8M+o7NAF+5EWD0TZ0HvuAR9pyxSeAENgXc
+EY3K3Am9SeDY6WC7VcbdXcZKAB/XBaFIIBvVeMgJfiFljKFl0BrWWVbjsYsIPtvzcd1FnQyUAEHG
+jJC/ieDIjV/HVUbsseFkiMjTlaEO+mAKoFwRbhywGSJSgKCQcY+tSWDBZeD26aAdQl8VSkWa+EHV
+cN6jbCHzTQLK8KAL+qATxmCUTN/+sRspruHfEcQqVM3TyZ1lPIr4DRegmF8eDd5ejQmvTF+lFOIH
+3gM4gIMX9qD+/R2h7jWgE3IcFYDF0q0hFFrA9AEfFVgGLhmgbXjIAi6dNBphAoEjFX5iUkzCuIlK
+wxEi8LUKQ9RiMtZfxXFg211cqNCi8zHd06Ff13kI6nUdlABjkMwT9SCEGuTKB2Wis1Eb5wliLE5j
+6SXi0g3kRHIc2BWdCVak63FdA1bjm8yTZY3jPfKe6zWhOkaFtEiUB3Kd3E3UD/pjP8Zg1KXeGepa
+pfDjE7Lb01keENyJzVnJjXyQQa6d0lgAoUEK7T3h0/UiQ5DhM25iK94k9Rldw5njB3Zk7pkIQaCi
+90zCo6CiAjLfxVnlD4KlJ65kU1ABB5piZRhDJqKkB+pbwUH+G7FJHeEt3STQorcx4NxJIgSAo5lM
+i8Zgm7bZlSQuXmWEm0ElxEks2sV5m8NdJQpixi9aRq7l5bxN5aRcI8tVZstpyWa2YVNmUmAGSjcC
+AMGJYWkCQMLtXGUkXTqypW3eJm7mpm7uZp65DjnhRJvhzVJSSHA6E060jOsYFnsUZ47xpnM+J3RG
+p3ROJ3VWp3VeJ3Zmp3Zu54D4pnd+J3iGp3iOJ3mWp3nKpH8gp3muJ3u2p3uyJ3r2B3O+J33Wp32S
+p4LA5n3uJ3/yZzc24374Grb0J4EWqHn+Z4GchIEuKIOCJzhooIBM4oD4GoDqB4UWyIUSCEcKyIYW
+iIQKSIb+TqgI9keIciiE9keHEsiHBkiJsuiI8keLAkiK/seMRqjfeAEm5KiO7iiP9qiP/iiQBqmQ
+DimR6mjIVWh+hOgNvAKTNqmTPimURqmUTimVVqmVXimT3sCRJqiuXUORfimYhqmYFqkXyM+JAoiE
+ekIprCmbtqmbvimcxqmczimd1qmdruklbCmBhGgVTIGf/imgBqqgDiqhFqqhHiqiJqqfVoGeDkjR
+3QM+3KmkTiqlVqqdeoKZ5qffqKmldqqnfuqc5qn3ICl+8KminiqqpqqqJiqjjiqXQk+kgqqszmqn
+YqrvnOl/pCmt7iqv1qmo5hqp3oepriqxFquxGmqrAuv+q9pGrPaqsz5rKdjqmOCqf+gqtF7rrv5q
+jP7HsB6rt37rqibrtvrHozYrtp6rp0prjQaIhNpAMrwrvMarvM4rvdarvd4rvuarvr7rAzQqiKrc
+FoSDwA4swRaswR4swiaswi4swzaswG6BvwZI0RHCvlasxV4sxu6rDWRqgkioA7gDyIasyI4syZas
+yZ4syqasyq4syL5AxAJIiBJDL8wszdaszd4szuaszu4sz/asz84sMbwsjeraPcwCyx4t0iat0q6s
+A3Asgnjs0kat1E5tyrqsq+6pysnsz24t13at1/Zs0F6toxKt0VKt2Z5t1DbtrWrqQHws2r4t3Fat
+0Pr+R8x+rd3eLd7ybNgqq4aSbdz+LeCGrNpOK9sKhNsGLuKirdXyrYjymdbmLeRG7tfu7biiqN8m
+LuZS7eCuK5r6DQqUAOiGruiOLumWrumeLuqmruquLuh+wtySqMrRAhvMLu3Wru3eLu7mru7uLu/2
+ru/OLi28Ln8UHQSwrvEeL/ImL+uigNMeiLWiK/RWqra+aICqXJ+CK/Zm76GKK/XqR7lGL/hOqrpS
+a388b/ier5xOb7DaR7dqr/u+L/eub318L/rWL5yOb+HyAqfaL//iqfBWL59d7/sOcPbG77IGirn2
+b/3ib8d6rvI+MARHcOq6rtj+K59RQw5ksAZvMAf+d7AHfzAIh7AIjzAJZzA1/K/36lrxSjALtzAE
+M+/aNnDbZi4NR+3iVi6MZq3k7jAPgy0K58ejlm0NDzHLbi758gfUErESy20Fu6jj9jAURzHNUm73
+AvHlLjEWk6wR5+/hZrEXu8MNV3Gp6rAUl/EOU7H80kcQfzEbb7EMGy4bf3EYp/F81K0Z33HeovEB
+F20ce7EbP63fhIEJDDIhF7IhHzIiJ7IiLzIjN7IjD3If/PAY81nAOqwlXzImZzLDQmwTy6iuEcIj
+h7IojzIpP3IYNK+BmK8Co6/6Yqj1EjAsg6sB9y2srjL/MjAgD8T+2vL5tjLWBnAsB7OxzvLY1jL+
+L6MvLjvvph4zK0uysL6yMEdzqhKziRozM4NvMqfyMl8z+Ppy4w6EAEuzOG+vM9sH/XIz9Gazh/rN
+NpCCO78zPMezPM8zPdezPd8zPuezO7NDOddHiD6CDAS0QA80QRe0QR80Qie0Qi80Qwf0I/SzGqsw
+GegzRVe0RV90Pm8DKq/zDPcxFs+xKz8xHo/05EL0fKyxRy/xHytzR6c0EYP0Lw/E45I0TfusHtOy
+bQixS9fwSmtzS+80DcP0NwvETNe0UefsTRdzTgP1EPc0RwvEKcyCVE81VVe1VV81Vme1Vm81V3e1
+VC+BSctHiFKAKpS1WZ81Wqe1Wq81W7e1W7/+NVyXNQWEdXwUnQBkgFfntV7vNV939SlstIr6jSNk
+AWEXtmEfNmIntmIvNmM3tmM/NmH7AF3DR4iKwxlcNmZntmZvNmd3tmd/NmiHtmhftjhM9nvYdTdA
+tmqvNmu39mM7AmAPiCqj87V6swWD8zjnNrKatnucM21jqzoHti7/NrrathPjtm4nd6BSs8QSbQIT
+t7MGt2xvM3RDq3HDLDQrt3Yztydbc3VHd2zb6ECgQBCUt3mfN3qnt3qvN3u3t3u/N3yXNwUz7m0L
+xAxEAH7nt37vN3/3t3//N4AHuIAPOH7PAG+3B/GOQnwvOIM3uIPDNwwT7hvzQhczdeIKdX3+80JR
+HzWHT/GBswdKWzjmOrVww7GIYy6GHzdRdziL12xSV/NSn3jikvh0/7SM/22KY7dItziLv3hzQ49O
+33jc0rh4m7iQ4/iHr4cd83iH+3h3x/iRD3l4s6vfPEMYXDmWZ7mWbzmXd7mXfzmYh7mYX7kOJLl6
+hGg1/IKarzmbt7mbvzmcx7mczzmd17maV4OZp8fEjjmf97mf//mYP8OUd+5wf/ezXje3Zrd2Jzd3
+D613G/quSneR6y+kOyui062iL3puNzq5Onel96qkU3mhfzqtXjrsArOmM3qez4inkzqthjqhC8Qu
+u/qnmnoOo3qqb/qqM1qr0zqownqusjP+Rg87sRf7PfNzJyc6nwF0Qze7sz87tC/0Qyd7pw8EBEy0
+sWe7tg+7RsdwLht5lL9tjiu7TDN5j+86pl1xuKMtkYs6uK+72Y47pu+4uRu1kzs6lMO72bZ7rFO4
+visuupfHktd7Td97tef7v0stvwf7QER1Xz88xEe8VoM1tZ/6QFRAXGe8xm88x8N1BQQ8edg1Xks8
+yZf8w/+1t7O0QAy2a7e8y788Y0t2xd/6QFj2aN88zue8zod2ac/8fqA2zAe90Ls8bKe8T8u6r8uq
+rQMwcuf6OHO65T560lcqsFcrdU+9pS69hWa60wsz1A9vr2M91Q86wyO92Gc9yI9H+3b+vdenvXj4
+9tlLatWXr9/4wgHcPd7nvd7vPd/3vd//PeAHvuDfPTa4fXiEaDYggeIvPuM3vuM/PuRHvuRPPuVX
+vuJng+GDB/EOPud3vud//uD7AtlbvY0n/NLKu8WvOMHbe+Z/R4ibftqOPt2XPuwjLerTvOqvPk0b
+fNQjfO0j7cKT/rv//tHePtPnvu6PNO+DPZAT/9IG/+wPv/OrrPFvPb0n/x0v/8+r+/Qzrewjsd8k
+AuiPP/mXP+AXvs9b/0Bog+W3v/u/P/xXvja0vndMrPnfP/6XfyJ8/37Mdtz7KkDwEngPwD2BBxEm
+VLiQYUOHDyFGfEjQoMAqUzBm1Lj+kWNHjx9BhhQ5EmOVgxQlplS5kmVLgSkAnMRXimZNmzdx5tS5
+k2dPnz9pejoI02VRo0ddAkhx0BNQp0+hRv156WRBpFexYkVpkWRXr1/BjjQ50GpWs2dVEh04U2pb
+t295Cn0ZE21duxCVMoW7l69bqmQr3hVsdyuvi2ERJ1YMciyvwoMhZ1XrmG1fy5fjDqUbmfPZvAId
+ZRE9mnRp06dRp1a9mnVr0T6qBu48u2VhcWdw59a9m3dv37+BBxc+HLe42LSRs5wsoJtr58+hR2/t
+SHNy6y0/8zo1i3t379/Bhxc/nnx58+e5Lzl+nX3DwhVUxZc/n359+/fx59e/n3/+/Arr2wsQoeUy
+QM/AAxFM8LxTqhPQQYWyc8CdCSms0MILMcxQww057NDDCV8A8MH2CiOmlxNRTFHFFVls0cUXYYxR
+xhOJEXHE6ya7Z5YPeezRxx89dKDBGx+MEMgjkUySwxABI5LEsngxccYpqazSyhhrbNJJHDfTUckv
+wURSyLm2dNDIMNFMc0kby+ysxCvhjFNOGLN0DMo2Z8txRzX57HPCMXmZDE/rsjvkhUMRTVTRRRlt
+1NFHIY1U0kMNYXPQwQrLJpNNOe3U009BDVXUUUkt1dRNs7H00rsmg2CJSWGNVdZZJT1kyFVpy64p
+zHjtlaa/7JQNV8EKO2yxY5H+Dauxx4ZltcvKfI2WL7kC3axZznSVVtu9gGX2WrSKTVbccUVa9s5v
+0coR2m3ZfYpaQdEVLNt26XWq23PjzSpccvnttyRV8z1K3XoJ9uldawOua96CGcbpXmETRmpffylO
+1lyIIzZq4IY5rungjO3K7pkwSC7Z5JNRTlnllVlu2eWXSdYBYJBXKqyaX3DOWeedee7Z55+BDlro
+oXGuZmaaU5qMEJiZbtrpp2F+5lakrzrTz6vDZDJYqo96c86vwYazTm+5TqvLPbFOO0lA4S27KKvV
+jttHrcl2OyKvw85b7xfHxtfuiPSUW/Ae2Ub4b5bgHlzxDOn2+3CH8N5b8sn++8b48YYCX1xzDAu/
+PKmlBJJw89EpbNxyzxWKfPLVw64cdcDPJl32zl9XKbsmlMld9915793334EPXvjhidf96NoLE0GK
+5Zlv3vnnoY9e+umpr9765UU4/vXJrine++/BD7/4Jqau/aHszF+o7vS3Zl99x9lv230y53cI/frb
+x19L/fPXX/75/6e/+9VvfekroPkOWLsAxs9w/OMFAMBhDAlOkIIVtOAFMZhBDW6Qgx3UIBXgZ0AA
+UMGDJTThCVGYQgmC8HTpg4kKYRhDGZoQHA3k3wxxmEMdTlANDuSFGnYYRCGisIcOtMAQkZjEDPqQ
+iU104hOhGEUpTpGKVbT+4hWxmEUtbpGLXfTiF8EYRjGOkYxlNOMZ0ZhGNa6RjW104xvhGEc5zpGO
+dbTjHfGYRz3ukY999OMfARlIQQ6SkIU05CERyQsgrAIh1wBAEV9ykBBCDgCVtKSdBGJJTWZSWASx
+JDj8QMlMGgMhBHmgJitJSlRWMpOaBCVZGAKERybkHsaoJBCK6ElNGkSXEAwlQ2Cyynv08pUKUQMj
+z9fChFhlkispyBOM8YRETvMufqgDQiYBjgFt5lxPWEUdRgjJ1BnOlA/E2LnKyQsL1OGX72vlJKqC
+kDv5DUopqIM004mQJ1QSdAJRAwDg+QR74rOB6VxnOxmSz3TCRJoJMYb+OIF5jZRYJQUSzYpVLIBM
+am7ULOw8CBX6eQ9wSlJYq6CCRL/Z0HGu1JwLQae1UqDNhNIFAMa4JyxJKs9zysYq+TxINrOJEGP0
+kxdUsAAmWfoSmbrHWvk8lxqWelFlJsUgT6iDRTma1aOsApn7LOITwDEJbgorBYFxnE+RSs9OWsuR
+WKUlTe9BBSDglJM6dSlPe4jWolZ0lrzwKkLUIFG95rOtooynJN0aKNAZwwI1NCoI63BUq6gBsqCj
+LD/rapUnyDKypFRDCuz5GW9WchXSHG0dYFKRVcBTq611iTUFYgEqDKWsY2VqYg9bSrje9a3LtFw5
+C/LPUDqVpzsdCjL+0erIHoKUrr1Nal2ZqlvaKsQYrB0hSvNiz5ailhfXqINBqvtDZhrEKsYAwhOe
+AELH1IGRfpilMUq7WUbG9BqjrcgkSOla/a7Eo0BgbVyR2tKFrJO179tlWlGZ35f6dqZ1HShx5Zng
+VmoSdGidxGx5MYlrBvitqGyugBtcFVQe1a4P/GU5TWkV9uK2u+M1Z2ExSZCGFsSRDf0nLyIrEEdW
+RK/79fFCUlBaAEjUqry0LS3BAY4WohW4xpXuQWDM0rJQYRUQzimEAmOBIXNYICDUZCiVW8qjDpat
+W45ubr254SuXBcUxsco1VgGOOuBSnVQAhyzJm+d0OjLABeklK6H+xGYb/pjQ/owshv+cF3TWocBn
+frJanavUM5fln4Kap5Pr6tMoU1kgQ0UIEJZC5gFF1Z255XJZBA3LOwm0Dv8soouDa2ZTppPGhgMH
+iXc8EDUXmtcISXKj6XouKgA7xI/GNF0POunABLPE0GVwTn2aAgwLRMNkmYQ0NSzYgm4m2Yalqzfn
+KlTr8pguKTYIdwMFDldnGAChdLF50ateWoM3vqsgJX3t+5L89prf1cItrT0szGIfdpXM9DAxESpl
+2aj3yhM+8J3AEWpUxrTRjjyxl+lsp4lrvJLF9DbHb6nSlyAz1Zi0ih8w3sPQDhWgLoYmBFcRk3n7
+VZYAOO9clJL+giL6t98997lDrkHqutyjoSJFilVF/nOl/7zKg4k4zTVaFNAuneorOaIFSSwYIFqQ
+qFy7egWz3pJrdB0tQCRt0lsS9aqvne1td/vb4R53uc+d7nW3+93xnne9F1KJffd72PG3db8PXogQ
+rZ/gCZ94HEIRgop3PAwHOD+CkPDxlS8hC304ectvnoM1ZDzZ6xd59yXwdaRHnek9t8DQg35+omcf
+6i8H+8fJ/nCqbz3r3ed6EU619M3sPe9RZ/vc91MSrzD+8ZGffOUvn/nNd/7zoR/942NV9wiEEiaw
+n33tb5/73ff+98EffvGPX/vaOz2UpJ9+9a+f/dK/QfkcmJ3+YlSM/scCg1lxv3u9dKxj1KL93wqD
+DepvABGjMYSPfeSPABXQK+5PkvLP+gJjV/ivYfzP984vMARwATUwJAxw0PAnATcwBDuiATPpAZEH
+SiRwAgumAoHPcwJQBGFQIzrw8w5i/mIwBknwgUzw9/ZPBVfQ/FwQSjLwBkVwBp8oO7qgB5RwCZmw
+CZ3wCaEwCqVwCqmwCpeQEBww86DkAtqhC73wC8EwDMVwDMmwDM3wDNGwCy8ACGMPSpDBCuEwDuVw
+DquQEuCPf7IjH2SHdGYB/7QwMKSEdQTxa1zHgQrjBfZwdGjHifIwETenD7PQEKEkEAexEq+kEPnn
+EB1Rcxb+sYkacRMVBxJL8A8PghIt8RRnBBP1RxNBcXA6kYk+sRXlRhR1kBQFwhRRMRddRBXxhxVl
+MW5e0YeyIw9EoRiN8RiRMRmVcRmZsRmd8RmhsRgFAQIiMROhpACAIRu1cRu5sRu98RvBMRzFcRzJ
+MRsLgA1nD0o0IBrZsR3d8R2hUQPuUID6yQaJMARzsPpOMAJ9kGFY0BZ5YQjvUQONkBHrcSDx0Q8l
+kR/7kWD+cSEPQiARkgAL0hMPciIXMB938AJ7sCHb5SGtEQMxcgErEhb7aQOIIyVVciVZcjjgQACq
+cRWhBBSkoyZt8iZXAxTQ8XAK4w5a8ieBMiiDwzjoxyD+D6ISFCQplXIpyyMDYHIUIVIgKKA/qLIq
+rfIq+YMCdhIAoWQJmPIrwVIpGWAeP7Cf9PAX44YW9ZEHb1EX3ZJvttJufBEtsSYY488s6VJt1HIj
+gxAQ3/IvV4QXCQhKEDEv65IsV+8gztIw/WQvARIXAdMtBVPyCJMxr8Yu8bCfuqADOLMzPfMzQTM0
+RXM0SbM0TfM0OTMXqBEqQ/IgeGAcYDM2ZXM2abM2bfM2cTM3dXM3YZMH4tJtCoMTUHM4ibM4jfM0
+3QAxb68GR1IBNRIgU9AjtwUkZVIkm3MAS1IYL/I66e85o5IXolM6pYU6e1EIubP+svMumfM8K8Y7
+W1P+IMJTPH2FPAfTOtnTX9IzM9fzPvvFPauzI+UzWuiTMu2TP8klP+nxIIbgOBm0QR3UNLGQNf9T
+IKCBNy30QjE0Q3cTGn6zbAojFx40REW0QZlAOYdPMS2zMRXyPaMkMl10MkevMlOUTzAzQQViMWcU
+TRzzOyHTRVERRl9PRnMUTWq0LFF0SHV0RSe0RX30L4FU/wSiMJEUTIo0MW90SsNkR1m0R5u0Ep8U
+Ag9CSrF0bUwUAftpDyQgTdV0Tdm0Td30TeE0TuV0Tuk0TRFhNWvxO3VhBfi0T/30TwE1UAV1UAm1
+UA31UPlUFzqUawpDEer0USE1UiWVTuWxKC1yPw3+dFz8szwZMkDHc1Gp5gUz9UDLNH1AcFTFZVPr
+E0A9lVcGNEYLFFWPBUGNVCDsUVbtT0k5lVVb9TJeNUhjFVcTg1atlBfQdFKRNVmVNU7vNCZ3VSD2
+FFGldVqptVoNVVH3Z0kddVm5tVuRtVKrhQavdEyVREuXlEu7VBC/dB/DlFyVpEqXc1zd9UjM9VmZ
+NF1zcV3ZkhfEdF59BF5PVF791UfqdVXbEl/zFVSRZi4HlkcA1kyPtGF7pGAJtBQRNmGz1V77VWI7
+5GFNtZ8WdERFdmQh1FkNlhcqVENVdmVZFjc5NGNPFkRJdmZpljNL1FJNElOFNTFUtWLhs1cFVGH+
+aUZUd1YxiDVeeeFWizYsehZWeRVop0VoQYZol1ZZStV8TrVqwaJpgfVpoRYufhVKA1JrC/Bqaydr
+ybYruFZs4/NrwVZqM4Zq05YkjjZgeeEcYiFv9XZv+bZv/fZvATdwBXdwCTdvyQBP15IjBYIHkqBx
+HfdxITdyJXdyKbdyLfdyMbdxfRNmfZYX2KFwQTd0RXd0CTc5cVY7I5ZjPYRinfZgL9YS9VVx+VV1
+HdZsXycWaZdDWLdrXfd1BzF2+7Jdc7djbRd1cHd4M2R3xRZdfTdvgLcNA2NjkddCPBZr+wkpwzJ7
+tbcpnzJPWXQqsTJ8xXd880MrObd1ecErt3f+fdmXO8bydNVTIFBSKOm3fn/yJU22c2kSJ/m3f2tS
+J8+Xd3nBJ+23gA14KIvXc9B2bkVibcH0Z93WV+E2YuSWgTkwgS9ngS34IxyYXSE4gvsibB94bDdY
+LDD4cTS4hDmig/e1bUFYKkTYg0lYhRnjhA9nGOExh3V4h51xGvMXfbGxHIV4iIm4iMfxHANYbNeR
+h5m4iXMYXA/wY1N3ei9EeUeYeZsXbJ43HaOXijWkes8WL70YQ6xYhrE4i+dki3lSSMe4QsD4dsW4
+jSukjPf1jNE4TtSYK7tYjt3Yhv/meOWYjmXXju/4Eic4YRhWjt/YeDWTDh35kSGZCiPUe5f+lAvT
+8JIxOZM1+QzXMIlH+A0jOZRF2ZHtEH7101ZpOCRYWHZd+IWhIob3VSJTeSPqFmJReZY9YpWD94Nd
++S1gWXZlGZf/xZRtNGmFeQR19WRbuZeB4pd3eYaPOSNqWYpvOZozQpeh12uZuZkPOWAq+Jin2XoP
+Am9Jt5zN+ZwD93B/WIAZN3Pd+Z3hOZ4vd3P7x14/F53xOZ/L2XTD9QjjmI/dQZCfmZALuUryWC7Z
+mI8XWYH/mY8FOpt7t6Cdt5vzJZHbeKEzuKEDOZk7l6AlOhUpOl4seowxGoX7aRDaN6W11ynXWWwN
+gHxhOqbF1wBCGl0KQ31VOqeXcgf82G7+smN+DziohfoM8FdC7XV//TeplVo1ALieT5aAhzqq7Zco
++9koq9mapwCbuVibt9lgavpbvlmYwzmMdTaatXqNO7Wro8KZIRqarXms4bisj/ms9Zir1Xon2Hqr
+BSKYxbqn3QYJPSCwBXuwCbuwDfuwETuxFXuxGVuwEZcv25oZYGCyKbuyLfuyMTuzNXuzObuzPXuy
+meGrr6UwhKCxTfu0UTu1GRsQ/LpsALmNH1qv7/WjW0e0m2Wkvbikb1ijYZuj0dejaZtObHtYcJuK
+dfuPeXuMYxutLTa4a9uTZVh6Sbq1uea1ldu3BRi4nbtFDho4E1qRqZtqskMZ8qG8zfv+vNE7vdV7
+vdm7vd37veHbvCEpcZ/ZBVrgvvE7v/V7v/m7v/37vwE8wAX8vl1guHGlMCohvhV8wRm8weE7CsIb
+aeiboQFySS0cf6JYnFH3Oy/8ZP3HA4v1lFm0wzv3wxkvgjgvxTFowtOR8lT8xVfIAoPQxWFcxT3v
+iWo8xyUI8A5Px3Pc8OYH8Xw8xfeuyI38yJE8yZV8yZm8yZ38yaE8yqV8yqm8yq38yrE8y7V8y7m8
+y738y8E8zMV8zMm8zM38zNEcInLsINZJnyoMxO1HwoBLzsnJlRIuIVgNANhrxlYJyr4JglIA7UTM
+koDgGhKNxdP8y1Mg3ARikbbpw37+qOZujiHwpcmeC9k8iiFMSqKuAQgUDGO8axUkirKmLamugYSa
+LdFVHbAAoKH2qZ2sqdxsLb5QndIhxtIjzdRiqiGgJMz8xrz0KawGzr1SfdWN/dYEArZ07NZknbqK
+btAqfbdyvbmiLCH2/CSkCV/+CptK/cmSfd9AzNiNfdEFYhX6qbrazCF23dYV7tJPzXLWaYR0ruFM
+DdLpauxETsbFHcz/SZpa7SXmKt0XgtVOp88RjMK47N0hR9oAgOTo3N3JYsSKfd8T3aj8QKZEiqDs
+XcOMgcXoHaei/bmqvSHcq4e0va9+Sui+7ZsmnuLRfBIWCXSCaZfQKqamKuTDHdL+82ndXSrf82wh
+gL3T7uHpSq259N3lu9yR1I2lfGrbk6ndpz3Aug3oO96vTMrZGmnF2O2mih7cWh7pzdzOSu3PjCHR
+eP3WaarPyR7kPG7g/1zrTwmVKgLOwKmmkN3ACN3nwX7v9UcNiI3vAT/wBf+OUuCCgPwsvo6CeLwo
+MGjwHf/xIT/yJX/yKb/yLf/yMT/zNZ8zQKvzPf/zQT/0RX/0Sb/0Tf/0Ub+ifGjsUr/1Xf/1YR/2
+Pf71Yr/2bf/2YZ/xCm73eb/3ff/3gT/4hV/utXD4jf/4kT/5g78FL2fmlf/5oT/6f19cR9xeSdx9
+Mrz54dxur1+Au9+Ftn97wp/+mqvfw60fw8c/9dKfrAViAsrh/eE//uV//um//u3//vE///Uf/g18
+VQojEgBCmsCBBAsaPIgwocKFDBsKjMQr4j0A9yJavIgxo8aNHDt6/AjSYwoAFp+UO4kypcqVLFu6
+fAkzpkyUEyyODIkzp86dPDUCSGHRwayhRIsaPYo0qdKlTJs6HbrE4sSKPatavRpyqkVuqrp6/Qo2
+rNixZMuaPYu2KzepFLG6ffv2psQMT+vavYvXqQObJOH6/Vv1Z1B3hAsbPow4seLFjBs7fkz4BVuq
+gCtbzqg1IrFenDt7/gw6tOjRpEubPs2Z2OTLrFnL5XVvFuTZtGvbfrw34uv+1rwtC47o4Lbw4cQb
+S5bYtrdyt5l5bUYNPbr06aZVI6e8PDvP17GLe/8+PDev3drL8/zNKzj49eyNrzYPH2Tz59Tr278/
+2jrs5PH7b+QuW3sCDkiYeOT5h2BG6O1gSoMOPghhhBJOSGGFFl6IYYMIvJdgh83Vs0uIIo5IYokm
+nohiiiquyGKI9XDYIYKvEZJhjTbeiGOGO/AVY48WoacegUKCd9x+2PkI33z4Lcmkffo1hyR8AA5J
+pXcG9hVlgkBWyaVwRUKZpXZKNklmmaU9yV+Y2k3ZZZuzXakmglu6Sad718VZ3phm7slnL2geiSdv
+bNZJKGJwBgrfnIUuGhn+jIi2pmefkjL556PKDcpooYdamh16wuQIaqiiWsiJo5xW1pwsi6zKaquu
+vgprrLLOSmuttq4qi6mn/vUaBAiMCmywoQrD467KKZopoV+maexfkU4KbX2VNlsZpsnSuSm1lyF7
+rZvLAqotVs9GSy5004YLl7Xddpktun9xuy6X37oL17jl3kvaufRepW68VLa7r1vonZJXwQYfzFRU
+dwZ8VXNxyAFxxBJPTHHFFl+MccYabwxxHLoynNNrAtCFcMkmF3xKsSALDFRElrwBc8wyz0xzzTbf
+jHPOOu8MsyYfrywffxSkRXTRRh+NFgU/Ay0SlgLQw3PUUk9N9c6WqMz+dGAtp+evt0tnvZG9+I79
+mb5gg9Rv1wQCfDZO8KpN4LxtZ8UffWTfXfbXc6vcHdxVsr23R2/73Z7cgXckNt5jm314RmkTvh7g
+jfu0dRFmXI555ppvznnnnn8OeuiiX86O3oE390gAqq/Oeuuuvw577LLPTnvtqj9i+t69cjF6777/
+DrzoRWA9eUeDQ05k7nMnrvi9jBevG5Z9Iz+g5ND/uHWQ1BeufNvMN0/u89A/vj1x1l/Py/HlD2c4
++gs7B37z4hdP/vq3nX+9+vbb1r7738c/qflNrn77ow3+oIceEsxhgQxsoAMfCMEISnCCFKygBRdo
+j+6drTlYmIYHPwj+whCKcIQkLKEJT4jCFHoQCxoE24wuCMMYynCGFyQB8dx3Ef0VcDb9Q9//ANgn
+ATaOgDvEzQ1xGBEdFtExPbzeD4G4JyEejohLZMwBi6fEKi6midB7IhTLJMXAUVGLibni5LJIRsRw
+sXhe/GKTwqg76QUojbUxY+PQA4Vg6HGPfOyjH/8IyEAKcpCELKQeR9DCrKXqCIxspCMfCclISnKS
+lKykJS/JyFy9D4e9UoIhPwnKUIqykFA4IhLRSMfCrHFybXTjkuA4tzGmskCmxCEqZ7nKxrXSlfeB
+ZdtkOUs7Hu6Wqczl4XbJS2klkmnATKUwAzewk0lzmk1RmJGQ+L7+h3Fsm9zspjc15rFNuk9kJKOm
+Oc85i5RFD5sK2trLqgbPeMoTZz4Tpw+FhrR86nOfZlGaPa8nMqjNc6AEhefV1snOHGZvlrQx5unq
+lszwLRNozaTjM/dGTDo6dG/IjKh0fHm2iqbxonPLaBo3ujyIejSAE12ZSMlI0rahJxEmqKlNb4rT
+nOp0pzztqU9/CtSaluqfXeQPC8KB1KQqdalMbapTnwrVqEp1qkhlQUtB1qs+BHWrXO2qV4GaiFq6
+Dz2eKIVZz4rWtKp1rWxtq1vfCte4mvUSV2VYc6owhbzqda987atf/wrYwAp2sITNaxXqGjDu4EOu
+jG2sYx8bV0/+iBV9ZIWsZS+L2bfSlahs5A9eCwva0Ip2tIM9LGcHKL3FZna1rLWsZBGa0CRurayt
+ra1tNYvYfd2VtLztrW8Fa9prYlOxty2ucc/62vFgKbaVPa5za7tZ4SJxt7+trnV5G1wwoY+4z+1u
+ZpN7IGyihxEgKK95z4ve9Kp3vextr3vfC9/yLiO39GqOOtKB3/zqd7/87a9//wvgAAt4wPhVB33d
+NaP4KnjBDG5wfBkx2fzN1rsUtmx0tetEz153wxwu7YHRxd0Ki1iu4F1uQps74hS79cLMuidlPtvh
+GMt4CtltMUBTq+Ics7XEscWeRWir4yDP9cPhou6Mj3zdGoP+a3w4FrKQedzj9E3YyUFm8ZI7+2Ik
+a7m6SmZniKmsYij3GD0JmIeZz4zmNKt5zWxus5vfDOc4mxkHRNZWc+yAhzzrec987rOf/wzoQAt6
+0ITOsx3qTK1epULOjG60ox8d5wREGIFTBrOKrcxOI29506Lt8nCbbOkUi5m5lQ61iDGNTU1zetUe
+Pu0QQW3qCo/6xKWOtXdRPV0Ns3rXwEV0s75s6+7Omp1khrSxj43sN9PZ1cfkTzzYAO1oS3va1K62
+ta+N7Wxre9vQjoevjaXoZIt73MeWNGxJ/eNgVxjXOFQ1r9+tV08jEdjqPu6wxVvrehuX3f7TNbz/
+bdhv74r+3vq+7b1Pme+C25bfLrYIjAEOb3lzEtYKN/iksZjwirOW4RnOMsT/LfFxUlzjrT24LbdG
+XgerfOUsb+98mf1QyqAjDTSvuc1vjvOc63znPO+5z39Oc3QI/FQJbrnRj75yCJ+b1ukm+W05XlSP
+f/zdId/uyJ3+3YufMeNYt/DQOeXuqXO66jeWimq7zlqTj5XraHcs1LHscLFT/euWInjbH6t2yrL9
+7nJ9Oyv9LfdVk53JZud71pdO7K1xgACMb7zjHw/5yEt+8pSvvOUvz/ha0P1RzXkHOj4P+tCLfvSk
+L73pT4/61Kv+8+/YPKJ69QfMy372tK/95Tmg9Tvu3fD+uIU5RwEf+E0Pnn5X5z2Jcz/M3RufrX7X
+JfCDr+Xho7bwy8c78qGp/OqntfnNljr0tyz9V1Nf+4zNu4QtogB8qH/97G+/+98P//jLf/70r7/6
+C+H6QDXHG2Dov///D4ABKIADSIAFaIAHiID95w35hyciwwr2B4ERKIETWH8KcH0YtTWOkAUbyIEd
+6IEfCIIhKIIjSIIlaIIb6AMMGCfNIQ5n4IIvCIMxKIMzSIM1aIM3iIM56ILioIJqIjLdcIJBKIRD
+SIQm6AgXWFLZR35D5nsp5X3fh2ThN0XFt4RrZX6U1nRVCFfcF3NxB4Xg14NhYndamFZXiHFZSIZt
+xYX+v/eEXyhjUihGVJiGZmWGW2cRw9AGeaiHe8iHfeiHfwiIgSiIg0iIeUgHYZglzQEPZcCIjeiI
+jwiJkSiJk0iJlWiJl8iI8ICIUdIrD1CInwiKoSiKhDgMSChTSriEa+iEXuiGRwaHcTR+c2iFpng2
+KCaLaqWK3vN8rchhrxhLcjiHdah7aHiLaJWLG7SLvJhkm4gkYyiLwph8xFiMTChd7ZaMyshlzOgj
+zhiMtAg26PEBkCCO40iO5WiO54iO6aiO68iO7SiOGKCNPdIcRlAM9WiP94iP+aiP+8iP/eiP/wiQ
+9WgE8Rgjr6EG7oiQCamQC+mOH+CNWYMe1nhlfzeTkc5XkVOYUOGFcJlmY1HHkRcZhxlpYon3kSWZ
+ah1JfCIZZeljDCngki8JkzEpkzNJkzVpkzeJkzlpk6uAkn+3CjoJlEEplENJlC7JkyAZR0WplEvJ
+lEFpDCMpXgAglVNJlVVplVeJlVmplVvJlV3ZlUiZUl4plmNJlmVpllUJlr90lmvJlm1plisJl3Ep
+l3O5NwEBADs=
diff --git a/Documentation/DocBook/media/fieldseq_tb.gif.b64 b/Documentation/DocBook/media/fieldseq_tb.gif.b64
new file mode 100644 (file)
index 0000000..7b4c176
--- /dev/null
@@ -0,0 +1,445 @@
+R0lGODlhdQKaAucAAAAAAElJDK+vr1YMDBUVZC8kDQAAVkYQEBcHOwYGSCEJHSAgaKOjoys8DDMz
+CgAYGp+fn19fFJmZmQoKO10wMA0VIAAAcDsICCsMDAcMT1MMD2ZmAAcSO29ISFUHByIAGoiIAA4H
+T0pKDJaFhXd3d0EgABoaVGYyAC4AKXd3ODs7BwAAN1MAKQAAYlZGB2JlDBwcWWBtYCA3ABAQTQAA
+ZQ0VQD4AAFVVVUhjSCQMJQAAfBMHMkQgIEtLSzAyDD5VPmZmDEZRB2FhEWZiDFo2ETkdCwAAVEUt
+Gu7u7js7Ozc3N3d3WACPADU1NTMzMyBRIDgAAEJCEHEAAEwNDZeXAABpAEQFBSMjIxgNQDooCBA9
+EEhIbwBVAAw/DAwMPgBNAENDCgc9B8zMzABDAD4MDAwOKjwKCkQWKUscHAAAcUtLFRMTEwohCoqK
+AA0NTBEREQgfCBUqIgApADIAAA4ULzg+DEEfH3wAAAcHSaqqqlkcHDgMDKSkpFQAABUVRjEwCGZm
+B00QEDAwXSUMJGUAAJaWlhQUUnx8jVQaGgcGLggSGy8GBmw4OGNAL4qKioiIiGIAAEsHB3JYWHd3
+AAAAPlctLYQyAGggIBgAGkIVFQwcJRgYSA8MU9EAAAcHVQAALRoaYbu7AEY1H2ZmZlxdEHAAAD82
+DlhqWExGHgwOUzMzDAAAmgA5KTEHB2ZmPlpaB///////ACISRExUDTJPJUQrDAwMVhISSEhISHd3
+IC4xCjhcOA4ORERERBkVXElJAG5gYFhYcnt1ZkgGBlYAAAUFMTg4ODo3BTJrAFESEmZmMF5jBwoG
+Q1paDUkKChxGHN3d3RwYRGZmHCgoKFMAACYmJi4YLhQ+FCIiIhU0FT0AKR4eHmVeBw04DRAsEAwu
+DAc2BwoqCgAAPFdMDQAA0WAqKgwiDEgZGRkQRAckBxsTPDEwDBAQEDwAAEJGDAAAU0FBQEJCDLu7
+u2IYGJoAABgYRjg4bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAALAALAAAAAB1ApoC
+AAj+AGEJHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXMmypcuX
+MGOelAegpk0AJFrSrLhTpYQ3AHoeDFpQqMCfQQHIXEh0olGBYkZtpGkTW56B0EYBfTMKCUEJEqja
+7DpQDIAbBJsOJHF1qdu3cOOqVKtTKcWnEOnmlQALWk6Eep8C4Ou3YWC7JUlAg9VUL0K8vcRMRUwC
+gFdoXBdD6+WE4A0kQqE5kSqwsuWBepFg8yq3tevXsPPKg4n3YW2HjnHPZrp7oODehoHDui2ysfDH
+iKFi42iU6A20A5G84SsQrdE8iKdPR3181KPY4MP+NySBC4L4lHRJAI0MSwwJ0++B5nSvHqdAJPVv
+LHb/U54YJzX99RR+QOnX3ntKidELANiMYlce2DB4FX9vHMdYTfIQeNZ+8dlHkFg9QSihQEQpyKCD
+H9q0E4X+AfhGTir6ZhMskWGTU33Y8EWffFC5OB+CONX3V1BixVgfe7DgWFlB7621nmRMAjBdLwk1
+Bw0SAEBZ1mKw5PHddQ9aNgp0jB0nQWfnpanmDTVNU56aI6lFghOLkbAcTVJh9xl28uCJBDQ2Jkkn
+EqN0Js8bvWTYy3dmzfbUnFcWOhxXsznxmWhKHeooANAcmihrBhEFKaGGAtAVoH9xN1ymFa66GFH+
+lv4JYEFE7eRphi/21ephJDqRR6fY1MlqnlnCkitmfZra5VlI8Fnms89CmuRy6jkKVEGLlkbntEwG
+CwuKyK2VE3HfLhaapQKNuSxrjpkF50Sg9SnvvPTWa++9+Oar77789lsvPDcBsE0Tqb67kVpWDVSh
+UMbRxKUEy23XV5YOFwRNrckZS93FYlRs1sNKjZLqDSRUnBBREnNsMsS0bvrtyDD6x+lRGWPsqkCZ
+pSVcT4MZtCRN7M6Ws0AM70bU0UbPljDO8uQ4kAQ177a0scA5TWKVAQ8mVJECUbnqTZ/h3NYb30Hb
+ssEQFZn12my37fbbcMct99xxo62RWlknq2r+mVsrhbfeRzmBDZsu68xdT33TGHDJGYc629+JG77T
+gjfFHLmqtiKWFTZv3CAZr9CKcQOiC66q6uadd4yYcc+ynrdav5EYMHAIYx2dVljunGnZtWF3E5q5
+5Wb3QfH6a/zxyCev/LwAB3xFEoUMnxHCuu9N5Myw/KSxQCrbZRaUNhOUMsV2XQzyy0U1fvb4qj/8
+xtk7iey4+TTDn2njBJpNtF1N5Wp60QQhEABb97ikwQIbwrFa9qImEAQmRGKMsZ2MaESmdCmFBFCq
+zShIs6xXWUh40gthStgEAHZYSksitIictvWIN4BmdUnzE6oEFalSQaVYjwDAVR41KEkJpRf+l5qV
+piYFuOEUjESzGZUPTfWnQEmOVdYqIAVlxcDMKewvdtKf6aBFtr4s6IWq8p+dBog0xrRFVCx0YbWG
+EyFslU1aLfRKyaa1GHDNMUW3QwtmDOSXa3ltiwF8Q1tw9p12qS+FiCxJoTyXyOkBpz5OkAwZk1Uf
+smgobEI5UmUeMaD8eEUoSFjQlI4SIadlsnEAEsMlP4kToJDliaRkEHWIEkopSeCPSPwfYvIAoLNI
+JpUEwcz7mgIxBqmnQjDsUi89N8lniRIWwIQklKSJyyRxUJokygmhbMm/I6otbH3RijFp5J4JFkR7
+BJFU3rJXwUa6UySgemddxHPEhZBLnij+AVRDVEm097XmBtTBp0AHOrx7ukUeZXOIQQk6klFYqCBj
+QgISbsBBuOiToRjNaHgWCieOarQjhVnIRGsCzriE5aMoTalKV8rSlrr0pTCNqUxnStOa2vSmOM2p
+TnfK05769KdADapQh0rUohr1qEhNqlKXipARSOKpUI2qVKdK1apa9apYzapWocolgxwiGGANq1jH
+StaymvWsaE2rWtca1oTE4BRwjatc50rXutr1rnjNq173CtcYJEQYSwisYAdL2MIa9rCITaxiF8vY
+wAojIVuNrGQnS9mtAgMh0GCrZjfL2c6y9RAOYUQnRkva0pr2tKhNrWpXy9rWuna09Hj+6ALIQdva
+2va2uM2tbnfL29769re0bUFCnsCE4hr3uMhNrnKXy9zmOve50C3uExKSi1hY97rYza52t8vd7nr3
+u+ANr3VzkRBIvPa86E2vel17icesArjwja985/vbBYR2vfjNr35ZG1uEzJa+AA6wgHkrXIQQN7oI
+TrCCF/zc6SKkuuKNsIQnTGHwkhch5t2vhjeM3/YeRB7vHbCIRwxg+zZEtBxOsYr5K1sSu/jFvi3w
+QQ7M4Brb+MbMdfBBIFzhHvv4x9298EEyvOIiG7kTHjYIiGHM5CbX1sQMQfGRp8zh/h7kv07OMoll
+bBAa4/jLYF6wjg3CYyCb+cwUFrL+QYhM5TbnN8lFCbGW5yxgKC/EDlPIs573zOc++/nPgA60oAdN
+aD3zASF+cIOiF83oRjv60ZCOtKQnTelKK9oLCfFGNzbN6U57+tOgDrWoR03qUpt6095ISBSawepW
+u/rVsI61rGdN61rb+tasjkJCzFDoXvv618Am9B4QwgdLG/vYyE62pf1wXzc7e71WNgiW6Uxt+XK5
+IF4Os7a3vdwxF6TMaA63uLmr5oKw+dnobi2cPyTnaru7vs1Ot7xXG+2CTPvd+NbttQmSbW77m9ve
+Jgi4x03wcZebIOeet8JJu27ftDvfELetnRUi5YVbvBP1Jsi9Ix7xfQ+k3/8O+Zf+Az6QgRf85GY+
++EASfnF5N5xoD+c4xCeekIq3fN4ZH8jGZY5vjwsE5CIPOoNJLhCTo/zoFVa5QFh+82e/fDgx5/m7
+aY4QHgzg6ljPuta3zvWue/3rYA+72K/uDAYgpB5eSLva1872trv97XCPu9znTve0JyIh5uiC3vfO
+9777/e+AD7zgB0/4wuvdHAlRBRAWz/jGO/7xkI+85CdP+cpbfvGqSEgrxs75znv+82LHAEIYMIG6
+m/70qE893esR76bLO+cC2bnUq+1zWABd6LiPLtFhYXSk+168SocF013f5qcvefYzbz3xnw17WMge
++XOu/e1zT/0cU/f32E9zeZf+73L3Qj/fVD+Izbnf5uY///tOln7116/762f//eEN/vDJX2TjRx39
+WQ6/QcpBj/77//8AGIACOIAEWIAGeIAI2H+lIAAIYQJp8IAQGIESOIEUWIEWeIEYmIEa+ICUkBDZ
+8AUgGIIiOIIkWIImeIIomIIquIIgmA0JoQZtEIMyOIM0WIM2eIM4mIM6uIM8GINqkBB9kIBCOIRE
+WIQImAwIIQDvsIFM2IRO+IQaaAIOUQlSUIVWeIVYmIVauIVc2IVe+IVgWIXUwIAHAQqrcIZomIZq
+uIZs2IZu+IZwGIdyeIZGkBDXUAV4mId6uId82Id++IeAGIiCOIh4eA0JEQH+oZCIiriIjNiIjviI
+kBiJkjiJlJiIEZAQNhCGmriJnNiJYJgJSWgBcziKpFiKpiiHoKB89Ddl5od/7qZ+7BeL1vdg8FeL
+3iV/q+hs9ueK1aZ/BTF+uVhkrciLdAaLsniMx7V7vWeL8IeLwUhlu0iMc+aLBAGMz5hiwyiNWWaM
+yIiMysiM4IhdzniNRhaN2uhk1DgQaBAJ7NiO7viO8BiP8jiP9FiP9niP7DgMZncQt+AJ/viPABmQ
+AjmQBFmQBnmQCJmQ/lgMCREO4PCQEBmREjmRFFmRFnmRGJmRGvmQ4ZAQYPAKIBmSIjmSJFmSJnmS
+KJmSKrmSIAkGCWEF+Bj+kzI5kzR5j8N2EAyQAAq5kzzZkz6ZkLegiuRYZS12juk3XN2YlN8YjuE4
+jkOpYuZolDCWjgJhjU+pX9kolS/GjUkZi0vJlMzolFe5YVGplSRGlbBglWMJbUVpli7GlV25fl8J
+lrUolmupX2XplgOGlmp5l+iVlXo5YHAZl9Q3l3T5fnbpl+uVl4FZYg6RCTUZmZI5mfZ4aAcxAz+Z
+mZq5mQeZAAnxDWEQmqI5mqRZmqZ5mqiZmqq5mqwZmt+QECIACLI5m7RZm7Z5m7iZm7q5m7zZm7Ip
+AglxAZQ5nMQpmTdpEHzAmcq5nJs5A0KpmOkFmI0JYINJmLhnmIeJfYn+CZ3oxZjTKV98yZ1Y2Zbf
+SZ1IaZ3sh53Z6XvbKZ7s5X3lGWDh6Z5s6V/xGWDViZ4ip57reXTtSZ+r5Z336VvzCaB/SZ4DCl/5
+qZ//xp/9eXL/aaCoJaAJultoeQ6QkKEauqEc2qEe+qEgGqIiOqIkmqF9sI8GwQvisKIs2qIu+qIw
+GqMyOqM0WqM2uqKfkBDpMAY82qM++qNAGqRCOqREWqRGeqQ8mg4JoQKT0KRO+qRQGqVSOqVUWqVW
+eqVY2qQqkBBQUKJe+qVgGqYk2gqjtwI3eqZomqZqaqO88JwSmlrSWaG9taAMCnDu96C/F6FvWloU
+Kqe4VaB7ymL26af+wEWndaptDoqnBrd9gapu8EmoBOqmjUpacQqpuGWohwpmiaqo4aanjdqnlkoO
+FyqmpFqqpiqiJ4oQKrqmrNqqrjqjOYoQcCAHtFqrtnqruJqrurqrvNqrvvqrtAoHCfEHv1Csxnqs
+yJqsyrqszNqszvqs0Fqsf8Clp1qt1lqqZIqTZvqq3NqtrNqmJzapgnploTqn55mpQbepnHpmnhqo
+oGqpgCqup1Wp5Rpc54quIaeu6wpk7bqn7wqp8SqvpUWv9Yqp+Gpj+rqvPtavb/qvhBqwAgtbCFqv
+tmWwBzt0d6qwBMewEuqwfoqWHXAJIjuyJFuyJnuyKJuyKruyLNv+siOLQgRhDwswszRbszZ7szib
+szq7szzbsz47szCQELTwBERbtEZ7tEibtEq7tEzbtE77tERLCwmhDLlQtVZ7tVibtVq7tVzbtV77
+tWBbtcqQEHrgsmZ7tmibti1LAQghBj/7tnAbt3L7s/bAVHZ7t3ibt3q7t3zbt377t4AbuII7uIRb
+uIZ7uIibuIq7uIzbuI77uJAbuZI7uZRbuZb7UhCUPf50HwJySIYRMFTCM6ALSDJSFYPkM2szG4Sy
+Fa90ITZRUpcbu7KLESRQQRRFEEtCulBBQrB7NumTS78bvJp7uh+WHHukGaPDJU0hGu00u877vPt0
+GrCAJYOUB9f+orsH1BVI4ATVZDjB6xh4YRRZpBBGAUQF8RzAuyzQu77sqxBWY71YkSN2ARmsQRzg
+yz/HEb7Giz3hch/FQhBm4RVqgR3tW8AGnCTQIT9dw0nz67ncAhj5i79K1jixI0HYS0Dcgy4HvMHP
+G8DGMk3W0cAIIUAnEzD7IzuVg70V3L8XfDQ30QvxxMEybLlOIAEQ0k+sdMIG0UK90FVDEcHpa054
+hBX8W7zR8b9lcRogNMNMLLmPQFFYlDd4MUYMcb9BrMNDXBrLQb7JYb6eAR1L3MRi3LgXgw0wu0UD
+gsQKYcVapMKI8RPEO8HB1DnI+wbK+1BjnMeMKzhG/DU2kSj+WXMyQOy6N+HHNRG6NzE1Fnwf4jQ0
+bazHkBzJkjzJlFzJlnzJNEUCvbDJnIwkInFLnbzJAYXJpFzKpnzKqJzKqrzKrNzKrvzKsBzLsjzL
+tFzLtnzLGhHKurzLvNzLvvzLwBzMwuzLo8xSCjLMyJzMyrzMy3zGKnXMzBzN0jzNyXxTDELN2JzN
+2uwhLkUT3KvN4BzOyAwgePxR3izO6JzOvNxGNsXNLuXOLEUT5axR8gxT9fxSuVtT8MxS+6xS99zN
+YZxR/9xS+UxT/axSB41SAx3PAY1RC71SBT1T3CwMjFDRFn3RGJ3RGr3RHN3RHv3RIG3RXZXQ5qwW
+OLALKJ3+0iq90izd0i790jAd0zI90yiNAzIyzwKtFiG90zzd0z4d0h2wFg7cUtzcl5MabSRNz2ox
+fRd7Yzr20P6sFvMnrkkW0TJV1BGLWkhdT1HdG0zd1DX21A3NUP881ZNa1UPNz6li1I261fa81GDt
+b2KN0w4t1Vl9WmhtzWt916bl1i/1z18d1wo212/dG2b9qUKt1+pYnIzd2Paoj6jB1Sn1z2zQmpZ9
+2Zid2azJBjdd2AMBk44d2qLNjsdp1TGF1XxNqb2R1Dnt1YK9bYT913ad2qOV1+2817SNcast2QoN
+168dZrEN0Iad20iW2Lc9EGwdqH4t3B/328Dd2bI93Ln+bdv6nCpU6InYnd3a3YVjGNmeLRAfyILi
+Pd7kXd4q6IL7Q9dkrRaZuN3u/d7YDYqlkdYrxc38Z4T4nd/6XYAL6N3RPRBaQIgCPuAEXuCDqAXQ
+zdwCEYT73eAOjt9ION+KXZXEvdwtBdjOrakJfuGzTdvUbdC4TdsWztCuneE4FtwcLt0ebtzVjdwV
+vtvfbXsmfuIbTuIrR9wfLtGpgqHX2uM+jqooytp13RuzCqxGfuRInuS+KqzpHeNd+uNQHuUZmq1J
+Qt8IHeKpPeIrheEzjrA1vuUdnto5ftVYztda3tXN3eVh/eVovnQ4zuIg7uK5feaT7dtqLmZsXucq
+Lub+cK7jci7iMP7fP3fnGNvkgi58by7hxy0QeBZsjv7okC5olskYvF3SvaFpp5bpmr7pnF5qqWbo
+Cg4LvBbppF7qjl7aVp5SqA3o/h3qgU3oyIXiNu7m093nZP7nWR7org7rg53nvb3nfD3mp13md03n
+v57mvN5+oJ7iN17rit7iFD7nus7sg57syr4q6k1QZZ3oVT7hsMADZBDu4j7u5F7u5n7u6J7u6r7u
+7B7uZhDkla7UvZF3hlfv9n7v+E54iLfssw4Li9DuAB/wAj/w7C56zx7n0c7q2RTjr27tsg7mwH7X
+wg5Tq57rrU7tMm7t0PXwbY7ozt7ti56WL37x/d7+8MnO8Xre7Ct+8H4uENcN3zAf89xNhpQe4+Ft
+3jif8zp/guiN7THe3jIf9EIvBfIN8tAOC/f94Eq/9PxN80K+3r1xhwY+9VRf9YBoiPwO8QPB4Ezf
+9V5PDxFu9Agv8tJO8lpf7RrvXCh/7LS+8mLf8mSv8DV/6CbP62tv6SrP5yx/6wlv8QtP92nfYL6O
+922v92/P998Oeoq/+IwPdmVn9h1vDt8w+ZRf+ZZ/+Zif+Zq/+Zzf+Z4/+fvu84e+eY1f+qav+AZ/
++MOO62Y+7SUf+Go/+PKe98Fu66vf960P+SmP9rCvXHc/+4Vf+3t/+3Hv93O/673fbbLf2rQv8bb+
+T/HEntXGTvgZn/zJ9fvMH/zOP/zQPxCS8NPgH/7i/9Fa8vTarhY/QNPqv/7s3/4z/QPLP+QDQQHj
+X//2L/7P/1LmT1D7L1BQvfsAAUvgQIIFDR5EmFDhQoYNEcoDIM/hRIoVLV4USAIARo4dPXYEQOLj
+SJIlQ5ZEmbIiRIkqXb48yBLmzJkyad5MqRHnTpgnef4EKRLo0JURiR51aBPp0odGmT4tqBPqVIQA
+epHAmlXrVq5dvX4FG1bs2LA+qT6FOIrsWrZt3b7FOsrpWaZp4d7Fm3dtr410/QIAHFjwYMKFDR9G
+nFjxYsZC/SKFyFjyZMqVLQ9u+fho5MudPX/+pqxZ9GjSpU2fRp1a9WrWrV2/hh1b9mzatW3fxp1b
+927evX3/Bh5c+HDixY0fR55c+XLmzZ0/hx5d+nTq1a1fx55d+3buFN9IICjhDUEkQiFyJNwL1nlY
+6df3JcgZALY8Cgc7yQxt1Jv5JJC8J+yGwoSSwAnAnABPoPkKkiuz7h6EMEKKSLiBoBtGIUgq9ggS
+Q0AAbvivKgcFYm+ugTY8ET7x6hNRICT2+w+aN0aBBhYxnHCiIBMVdHAUJ1jMwwkM2wNADIL4G1FC
+JZdUUgwAQkQCABZhyYM/EuEbCJtRkEDCCfVaLKjEJFG8MkNsEporSol6qXAgJLBxrL0k55L+AJsQ
+XfyuPSccC3JHJv8EVDtsEqxyIGgG7YtMWHoJUdGB/BTTIEVRhAaAGg9K8w0uiyzokRwfnTMzJx4x
+iIQcAXjkTIFGecTPQF+FFToKV3Wsl0fYc3QgElTFdMy+IMWyTIJcldPFUeqbFEs/5wJWTmyMhOWN
+SpOMtVprj3PyvzegnRXXYN0k4Q1qFRxMWMJESlbHcd1LF1SDmPVVTqyoPHXca+/FtzcE81BVHk3f
+E7bTN3q5FMz4fo03TCwrLVjdgVoVI0poH/6Ux3dFJbXTesU4k9Vi8wU55N0euVAojTBTdFd73VXY
+4pZfzojXi4dds00X4aR5ZoHEuxMWJPL+NOpZaT8WuWijY6v0WUkTDVbihpolOsWlB1oRzcweGQ8W
+GWm0EUeHv171R4GCHNIoUz8l9mi11x7NCZmlBjCwXuQDzOqpiSyXbvXko88+wZyYWD/+4Ow5apep
+NhCAUd11MuO02YY8csknp7xyyy/HPPNYSeilc897mRgmCT73PEHNT0c9ddVXZ71111+HPXbZZ6e9
+dttvxz133XeHXB7ffwc+eOGHJ754449HPnnlC08OCeWfhz566acXnnnkoKE+e+23n7460L4HP/zA
+ViaObvHPR38x8oc7OX333y/M+1G4p7/++ltdXziIbrW/f/+hx59zNPI/AhaweHLxXpz+lKOU5TBw
+gY8jjlSaI0HpmKWBEByOA5OjQeRQcDkehI4FH5i/4HDwOCY0DgiTo0LnmEUQC4BhDGU4QxrW0IY3
+xGEOdbhDGNYgRSQEjlJQkQsiFtGIR0RiEpW4RCY20YlPJCIqfihA+MgDBjzEYha1uMUdCkJX33qO
+WRZADjKW0YxnRGMa1bhGNrbRjW8kYwum2Byl5CIWd8RjHvW4Rz720Y9/BGQgBXnHXMyRORKUxyrg
+uEhGNtKRb1zAFxM4kDE+0pKXxCQb5XglIP6mjoMEZShFOUpBFpKTVDyRIjO5SlZaMpIZAWMLHVPJ
+VtbSlpo05AUzY0dS9tKXv/yjKd/+00nfIFKVt0RmMsnxSliwsDlmMUEapDlNalbTmtfEZja1uU1u
+dlOalMjlCAeihjaU05znRGc61blOdrbTne+EZznVEM4VwkcA7/BmPvW5T3520wSSpI5ZQLEKghbU
+oAdFaEIVulCGNtShDyWoEeiJHKVEIBQXxWhGNbpRjnbUox8FaUhFetEITPQ4EhSABSC6Upa21KUP
+BQVApyNGZdbUlpscpnM+CUye9rSXwkRhcYxpU6KukpnOZA5Ni7rUR+I0qOWbCy99OlWqBtOkKazi
+MZm6VUjKtIKz5GpY3ehUDOovqlVFa1rxCNSyBmeoYoVrGo8ay2c65haewGte9br+V7721a9/BWxg
+BTtYvBbjqsVRChhesVjGNtaxj4VsZCU7WcpW1rKLBcNhIwgfBiSAsJ8FbWhFO9hbeDU6So1rauOo
+2QyeVa2vnSpbidmbt6o2tXOdpEBoaVu4knW2vNkpbIX7S9mikkRa5W1YcRtQsCa3t6w16y6HO92f
+QtetWXUuXJc70+Zml6u+1alrqTveQRZ3gtj1Lle3+9WBzGC074VvfAObAOsGcS4iAER+9btf/vbX
+v/8FcIAFPGAC51cE9f2NBPkgXwY3OL4zMG0Iu5vepYKXjuIlb4b9aN5DopfCS13vaSf8YZtamDnB
+1XCK9cjhD3qYxDYNsYQp+eL+oppYlwORqop1HAsWK6e2NFZmjMM4YiDf0sbiFEiOd5ziHtczlUWu
+qZBlORBeiMPKV8ZylrW8ZS532ctfBnOYrfwJBPtGKSqYRJrVvGY2t9nNb4ZznOU8ZzqnWQVlpi1n
+VyBmPvfZz38OMy8iPOQZQzmZR94ghpes4SZ30MWGrqWU61poSN8Uz8BV9KLJ2+iTPrrSRh30lHX7
+aUuf8sLS1TSTL72bH5M6k5JOqmOqDGha19rWXiazqU88lz/8wte/BnawhT1sYhfb2MdGdrJ9/YdV
+60aCDNjzraU9bVoLGpa5hcVuXY1JRFM006meLqex+uRtg/razKV0uS/Z7RP+fhvcwhW3UD2t7kbC
+ejmopXdTm50bFL873PvGTavzzUh7KwffA2cku43Tb3/DG+C3ETjCu3pu7rbXwRfHuGDpq+sbCyQe
+lwV5yEU+csvG4+G2UXDGVb5yvUKY4uwdtcQbqXDEurvhaY33Zskt80UWPDkH53kbaQ5VVN98uDln
+37yDrkafIwfoS1fj0FtbdKPDFunCiTjU0dj04zxd62eUenRxXPWjn7w2Wf96GbluHLNswhZvh3vc
+5T53utfd7nfHe971/nbDchzJsFAFEAQ/eMIX3vCHR3ziFb94xjde8KowO22ejYe9V97yl8e83jcR
+6knHPO1Rj/xsGE72ql7+/bo7//zWOR/rdKfejGEvoc1J31PTAwftn197cbyeetjbl+qzL33oZXP7
+tOeeOGJ8afKVv/yGStTvic6MNEY6fepX3/oilYbwY4NIlTLf+99PvvGHYxYxGND89tM+bJRyfvZz
+L/2vkaDz2j9/6U0MqfdWIPTD+9vdPDXpz7k/g8s/b+M/3fA/sTsvAKQr1ju1/XPABDSumYKfCZzA
+AuQ3CsRA97HAgMvADhSf6tCLEBTBEcyKhlEOaCDBFFRBtzDBDVrBF4TBr+CdGaTBGrTBG8TBHNTB
+HeTBHvTBHwTCIBTCISTCIjTCI0TCJFTCJeSOPKGarHER81jAhWCXXxn+jL35Fr6ZkoRwEpuJGvMJ
+CfNBl/tgEas4GAvhFHK5QryRGyZ0Q9OYlYG4kAxhGoPoEMAAEbt5Gag5w515gy08iJO5E2KZC0dB
+kXD5D8DIGIBxEcDIPxNpqzeUxKfIlkackiqpw4LQEi7xEj3sQz6Em5hZiO9wQsNhGUaEGYuxin9B
+xVRJFZ05nEmURc0YlLGBwkORgEwkCEYJGFiEG1DsRYZJiDx4klGwGULMDEMMFkuREydokw3Zk0oJ
+naiJxFm0xp+IQ7UYCFvxFoXYFU/8xYTpw1M0CGOkkieJxZzpxVBsJseRBydBlr6QRljYE7AxxWvE
+R6SoxG3JiArpxoP+KA9xQZNyYcRzQUV2vEeB+EOFdEeDMR+JoBsnNBtNYQ9PEQissUeDzMeNHIp9
+6Zd/+UeBIRj7SBhgPEhhPAhi/Jt0PEVlJIhRUBWnEBL2SJzA2EJI3ECO1EmOIBltbCbC8J1vURmG
+gBqTPMS3eckhOccaQUaE7MVIsZGQ2AiUpEelpMac3MmspIikmUZGJBOnIcqSFMdQrBqAXMiBeANS
+acp1fEqE+aKNMBWCwEhyrEattEuOcJuYYBrBmBvCAEdz8Uu9iZv5AMTwgMKwYcO6ackqJIhKqQ8T
+MRBYwIZF1BopoUu/vMvM1MzN5MzO9Ewe5BzSAZ2bGB3RNJ3PRM3+1FTN1WTN1nTN14TN2JTN2aTN
+2jwd0cTN3NTN3eTN3vTN3/zNNZgG4CTO4jTO4yROJVgDJUDO5nTO5wRO5WRO6KTO6qRO6bTO7NTO
+4pyGNdjO7wRP3hwWbAjP8jRPAGAH81TP7awGAKiG9YTP6mzP94zP+mzO+bTP/DROdrAK/fTP38QG
+ZRlApzMG53AEAHAEA0VQBU3Q5jCGKdS5RxnQrivQ5jjQBmWOC2VQ53hQBRyWCWW7Cs3QBbVQEh1R
+DF2ODo3A9nCMEZCEF4XRGJXRGaXRGrXRG8XRHNVRGC0YABDRQwiGIBXSISXSIjXSI0XSJFXSJWVS
+IR0IDRWIGDj+hSml0iq10ivF0izV0i3l0i710imNgSc1UWFYgjI10zNF0zRV0zVl0zZ10zeF0zIV
+BjHF0B210zvF0zzdUWAYCBXVmiYF1EAV1EFt0kPwKrNghE5Q1EVl1EZ11EeF1EiV1Eml1EpVVHrI
+DB9tPddbLYGAUlh4AiYQ1VEl1VI11VNF1VRV1VVl1VYV1Seg07EDPpyLVYGABEvF1VzV1V2t1Evo
+U6VLvfVCVF4l1mI11knF1EcRUW3jVHLAqU8NVVeV1mml1mplVVj1VBNVsln1KWH61Fs91nAVV2L1
+VYHw00Rq1jMSVsdI1HF113dF1kxd1nR9vVoFVWvF13zV11X+xVZY+NRt5Vae8lYTBVd4NdiD7YRy
+hYVzRa5mXdeBaFeEldhxTVYFmVd67VR/NdFo3deO9Vhr7dd/Ddjgy1YMLdiJRdliVViGxVgyeliB
+sIMpkNmZpdmatdmbxdmc1dmd5dmenVk+UNaB8AM3INqiNdqjRdqkVdqlZdqmddqnJVovsFdv6Iaq
+tdqrxdqs1dqt5dqu9dqvBduq9QZ7jYJmMNuzRdu0Vdu1Zdu2ddu3hdu4NdsosFcz8Nm7xdu81due
+3YNfHQg+gNrAFdzBJVyo9YNDZdeUVVxirdj2uFiMfdaN/djJpdxrtVeAHVlfGliTXdzOzdWVBVbc
+Q1yI9dz+0qXUxtVUz6PXyMVQjq3c14XdkNXWzI0tez1Z08VdRgVd1EvXl4WFiM3d4O0E1H3c1bVX
+14Xd5P1Y2cVQzKXdUdrcgbhd4TXd3T2ull2m0RUI4KVe0yXeTeVU1h0I5FXe8s1X5pXV5wWm6LXV
+7g1e612PhuVU3+WBAbDf+8Xf/NXf/eXf/vXf/wXgALZfZ2CAoBWIevCCBFbgBWbgBnbgB4bgCJbg
+CabgBE4EezWHLtDgDebgDvbgDwbhEBbhESbhEtZgc7DXwHO8FWbhFnZhxoO8kh2IVhDgGrbhG8bh
+AMYAvxUIBpiACgbiIBbiIabgetDe33Xf3P1e1U1X8RX+CPI13yieVvRNMvUVWNtNYtyFX3RtWd/l
+3ixW3CXONux14nuV4jOmViqGBee14vLCYjD23C2WX9fzYjj2XDFm1vA9XjTmY1dVYzZu40BiX1iY
+XjuWWDnGXt8tB3pg5EZ25EeG5EiW5Emm5Eq25Etm5FIQAAOGhWjqp08G5VDWJnCSYYHIhi9A5VRW
+5VVm5VZ25VeG5ViW5VlG5WywV3KKp1zW5V3m5Xeap1KGhT7A5GEm5mI25ktOBh6GhXsS5WZ2ZlD+
+p5czi0qQgmq25mvG5mzW5m3m5m725m8G52qmhk222IEYKPBD53RuPnu9hipw53eG53iW53mm53q2
+53v+xud8dudrsFeLur5/BuiA/qiSAmYbCOeDRuiEVmhwzgRlTil1huiILqiYkubENeQwllfwdb0y
+huI+9uhR/eNA1tw3vmiUReQuPuIvLmmDxWMy3uOPhulSDWmRJqVBLuSVfteTxtg6xmmJbemW5eiY
+FupXvVyarmmS7mmD1Wl6pV8ycOqnhuqoluqppuqqtuqrxuqsdmozKOByFgi3y7ywFuuxvru+01gM
+NYdvUOu1Zuu2duu3huu4luu5puu6VmsUBuZ1CIC95uu+9uu/BuzAFuzBJuzCNuy9Xgd7XQStZuzG
+duzHzuodNlfOojyytuzLDuvNq2jSTeqD/WnIfen+oYbpmTbqULLpzj7Ype7dlEZtls5oJm7WoBbt
+0S7q0jZtpG5tcVVth2Xt3HbXzzZeYO7o2Y5i0rbtUsJt3zbW3Z7f3lbucAXuJg5t4uZj4z5uQDrt
+5w5X5qbjI86ESADv8Bbv8Sbv8jbv80bv9Fbv9Q5voPVqWHAvlpPvi9u4sx6IbwiD/Nbv/ebv/vbv
+/wbwABfwASfw/P4Ge8WvAlPwBWfwBh+wAwPmC2DvCafwCrfw9e7byf7b+ebwBnO5n/xQztZuY43u
+2J5u6j5j677uDUvuEddV7g5W53ZxXi1xPRZuFO9jFV9xPsruGedVGBfdzd5eH2fc1x5joD5xHDf+
+Xx3f8RVrcSKnVCAvPhmHckut8Y1OciVXXiZv8rV68iqPVCn/Ot89B0gw8zNH8zRX8zVn8zZ38zeH
+8zg38z7oaselMmrD8zwHs1yzb4FIhzEA9EAX9EEn9EI39ENH9ERX9EUH9HSwVzSrs0iX9Emn9Dm7
+M2CGAjnX9E3n9E6P81ZQZmjT81En9SuzNhCXUBEH80q9ct7Lci2P3dru8j7q8VWPcmXm4p2mcluP
+1Fb/PNmG9SWX9Vnfo1rn9TDH9TmOcSFH4mOPV07OYyy/8WAXdmAG5CY3dmd3VDHXOkU+5m8H93Cv
+ZE3mZALQgXNH93RX93Vn93Z393eH93iX93P+NwB71QIuwPd81/d95/d+9/d/B/iAF/iBx3ctsFch
+oIKEV/iFZ/iGd/iHh/iIl/iJp/iEFwJ7FWZx1/iN//Zk1nCBEAAamPeRJ/mSN3l5J4AjpuaFZvmW
+d/luHmdOPmeJpnnwc74+h4V21ued5/me93l85mdg9meBJvqivz6CxnmDfvmlZ3qWb+iPX+buq/mp
+Xz6KRnUFsWhth1RfTztgp/bk5fJZz3atX1RuhzqeJntH5fqv8/qvf92w7/KxT3uzXzq0T3tGXXut
+a3u3p1y4x/Yv13q6Dzrf7YBLMPzDR/zEV/zFZ/zGd/zHh/zIP/yJSV1YsAcuwvzM1/wcggH+e6WF
+JwD90Bf90Sf90jf900f91Ff91Qd9WrBXZYCi2Jf92af9J1IGe9UDydf93ef93o98ClBmMdj84Sd+
+zbeHI04qEV2OT11+E21+FFUOP+2wEG8h5VcO5r9+589+6E8O6W8x6n8m608O7B9/7S9/7kcO7/cx
+ZbmKGHT/F+yP95f/EewBAOiB+cd/vaj/+8///n+L/QcIEgIHEixo8CDChAoXMmyoEBsAhxInUqxo
+cWAvALA2wgLg8SPIkCJHkixp8iTKlCpXsmzp8iXMmDJn0qxp8ybOnDp38uzpUyfHoEKHEi1q9CjS
+pEqXMm3q9CnUqFKnUq1q9SrWrFq3cu3+6vUr2LBix5Ita/Ys2rRq17Jt6/Yt3Lhy59Kta/cu3rx6
+9/Lt6/cv4MCCBxMubPgw4sSKFzNu7Pgx5MiSJ1OubPky5syaN3Pu7Pkz6NCiR5Mubfo06tSqV7Nu
+7fo17NiyyyKRAKsXUtxGe/Ui4URMbjG6gw6/Pfs48uSbSeDGDc1Jr99Ciw9trpQ6x+LYlXPv7t3v
+I9t5SMAab11CHljQqPfmDc34bWjYSMyH5lu6QNuw6NuHJcGJE7bhlgd02Gy03XcJKrigWtDcAMso
+0CBhXXHjTScPLPKMAh+FsIjx4HO3AZedcU4gAQs2E8JiIhJvMPgijDGWZd0N71nn4Q3+5E1Hom4d
+StAbCRqxF9989MlzI4IyKrkkk009MoqAvL3xY4ajnFgdhhqu6GGHYpBXG3w8wvdIiUi02CSaaapZ
+FDQAXHmgcaNA15tQAvF2opwCGafbfen1CCdu/zlB3oDQPRjmmokquiijjTr6aFn2EfQepJVaeimm
+mWq6KaedevopqKGKOiqppZp6KqqpqspWHhtu5ARH+iU51Bu83Vgrb8AVh2svb2bXC67A3aejrQFC
+5QSlEpAJC5izTmergLfZSihxvA1KFK7S7QcgecIByxtzuIoHnRN+ugqhs0ORoJ+DscJ53bTw8Spc
+tdHpGJS3uG407IHWjtgUEgZuNMr+iOkhitS8Pca7q62+clTrtfty65+UQH7bi2383nbuKOnWye6h
+/r2blK0Y71kyosXey1G+vJVHrsHF/stUqxzBulHMTPEqL7SI8urwRhDrSGB06f34LXMXCzvxxhx1
+TJXAYrgqj0aI3qffjiQerN1GWhI13LobSUDtq1A9smyN+9640XPRzTwyoFmPDGV1G6kYtn/3ct31
+DSciccORAqPoMb6Hhtd11cXdACDWWmu999yNE8cR3mPD1+5TN4x4sxiJByUPuW+nDPfoVX5d9n76
+WQ432KoTKjg2hLNsuH7Mwb24sXLHPbnjdJ+eYd/MAn55yE1F7WrncIPudt2P667+m9dZwypP8H9j
+yDrlrt8Gu+xFjZJe2H//6TTqz5MOOYLDcT3czU6FGDDOtheHnnrYDTmk45jzjgTZI0MeIUeg0bHv
+ledpTknRit4jvpF5aSOCc9y7IBcm/cltfWwrHlMsVzN0wY0EwKEg9rbGu4NFMISlG10vCNiq7jnw
+RMjykO3C1EAUNU9MI5wgBrUGQLZtSDcgXAoB8WbA4nhQPTncG/789zvc7FA950Lf5FKYnhVSpWYm
+2g+9SKgiWvEmWrDY2QnTB8HmWEtyTEGWhVS0tqBY6FkuO1kXT0hCXL0BQ1B0HHt6ITUIHekp60LC
+zTw4vqD8sGS6Cpqt5ChG7Nn+ChuiUwr8SJCeR+RhkGxcGSLppLA43lEoEMOGjUbYyT3tcRR9dMof
+b9Y3S16wOomEoyZvuMj78caRULHiiSjJyvhx0WS6mVcYsRUdUCZxlM0p5SmnAsoHyYNsxeEfCYBW
+uiSGaZEorMrZCAaLtK0RR5g8nwjzd0S7wcqYTqOUE3EDq3I+5UPKypAzg4KEUViphiUcYwBzqEQb
+TkVzsPobh4SioW9O03yke9eHgonHKG6JnU5xJ5lIYEe4zbOeutuTQY1YFN00UYAkfMoyhRfQz42C
+oEjM6HZ086GOPlGUDF3nR51CT9scrVaI0txueEdN6J1LbpXrn1QcdDNbTan+OBqSpgh36jQzqi91
+YtPbCKnnN8DhhgQljSlSnJC2mq5tQui8qCX/Z8aR/RSrGaQnl76Vxafm1Hmy7FpPtQbQspqwrFW9
+KgtflbakvaF/Xt3ojpQ6sLHCR6rCmyhVZprWWq01b229Jz5N1zzrVW94ddXeXYEalc75apO9eAQY
+DQrMnf0MsJRjWl6JkqPATktO4LInLAkFLZUJM47bipgJX1Y047QplE95RPvexSv6vPKGPMtVyZJm
+r8fellhWeYPBIjit2L3WoMn9oq3EUNpe6lFiuJWjxpwDAN86BbhZ45UEqGs/1iYyubQ1rW7LddB2
+ukmn0FLvN/eGXuy6bLv+nsxufKMLXtSqZ7xmXRWCE5ymsQ2EsE5pJkHsIqmBfDUqExZIhQnD4PxY
+ZcN4o8uFSZDhp4R4xIIpyPWogmK7QHggVmmxnhQs4xnTuMY2vjGOc6zjHfO4xz7+MZCDLOQhE7nI
+Rj4yp6YUFAm4iCP8Q5xURIIbqm1Eyhmq2udAgg0BD4XKVGscAORBNZGQx8pj/oh8O5JiTzbZyaN4
+AwD6eqWRVBkkafvdRm7Q0zbN7F5hjsqZP3LlOoekymu+8ke2fBQqd8SoGhkJbujcES0bjNFDuQEA
+3nYkj+AU0SDJEqWNEiSRiDnUSMYLCYqn56AECcpC+RCnkarmLlftzwL+xTJHLM1kLmf5ym94k60N
+HZRg5xrXJPj1rIeSB49EF5BpE4NWhT0UW88T2a9eWR7aDItHPLDV0nYznLVFFEsX+9vDPrSuoWsU
+RntkWYPmCLGJDe8UH/tE5HayR1bWOTLxD9n3drV/1L1oXFs6SLI+tVs4azcARDfbVfs3NqwEyCTJ
++90V/ze56bNujVCNTuaO96HfPe9kC0XPq97XAzv3noqT/DbffMShBb6ie8kDziMPipze82akYrzW
+IW+5yPfzwFtXGVhXIjfIiZL0f28bG9wmzsqMxfSMD53Wvb45wuuCDf1kO4BbfziuD3T0sJ/b6kAP
+OsALbGIvZzrTH1/+88XDbuCKI4HhTLaZu7t2IpYTO72whZCr6j6igD0Cy/KWKNaJrni+oxvXvS0K
+u0F3KKTD/efxBg7TB8Xnhc9MDO+ZuuMNvPGrV9nEWXdLqgemN5iD/SgaL0rczZ322bN80FSOYdIT
+n3YSLKvid6+7wWrPeNLzUNlN/g/lJGr4nyNu7WSPvNIbL5TaR75z6aF82adN76mRffMRYzraac/8
+tBecoKd/i8LfMKLUMxr8/R6/SFxN5vDfm/oc10jAbJN7Qn+EPIGOs35U3Gpt06EIX0joBrHdGyVh
+S3rcwLKAjsjVHpPl3a19msUdoOzVH/NBX71hH7xh4KSBhI78m3n+bVuTgd//tV72QR7BiYSDnR9b
+BEgeCEzN2ZsKCgVo9YLpnR30KR7xPd643V/X/Nr+8SCujYLAyFvdhYQLUaAEYMjwxcrQ6dN+WImB
+tQio6V6GYAM2jB/9+Vz0+aDasaC0OYEp4VoRYp0EGNi/OUFIpMfm5ZptgB4hiR4ZlpvdvBkM0sUj
+6JmOjNqn/ZuRJEXsGaHZodzoWVqOFGEhyt+h+d3CZcwDAd/ZtZzH2Q0VahfyeVr/AV3NUWAQml0U
+4iEi3qGtdY63vV0Yjty9AeGKuMolbpP/kV3Qvd7okWL47WFbtIktKd69CZ5SFGIjkuKuJSKWtQgj
+hhy59WB2rMz+DTyIs73Hc9xMFFabr0iAg3EhKFqavDkBKIbi4lme9ImNzIkivXnEClbi0oWdbwQF
+aCHOI+TSG3weLaYbr4mhpc0TFeriWjhB1b3b//VCChqFMMZfQHKiohmjOzKiQYZeeogEA7hdrNRX
+tcWZRY0EFNpZhQVPUQRJhnFjoZHaHV4dRoagoAVaQprimrlhOpYksc0HJ0aE09VhpbkhAHRaCs5i
+ot0jPoYER/IjUAalUA4lURYlYCiXIYXF0ZSMyXTHUpbMC16FtzCl+SHGU/aMUWalVm4lV3alV34l
+WIalWI4lWZalWZ4lWqalcvwEW/qEF2JGCralXNLEW14GIM7+JV7ORGoAAJBchF/+JWA2xCjUnmZQ
+TUkFJmImJmIOZl1aRpAoJmRGZkVkxF5WZWZQTWNWBmaKxmaGRiqCxmeWRkRwJmFeZmnC5WnaJS1y
+RmiSxmiGRmeCRmx+xmx6Rmt2xm2KxmvCQgcwgm/+JnAGp3AOJ3EWp3EeJ3Imp29SQLFlJmXE5g/s
+gnROJ3VWp3VeJ3Zmp3ZuJ3d2p3T+QHOKRiqKgXKWp3meJ3oqZwdQzmqGxm5eQifEp3zOJ33Wp33e
+J37mp37uJ3/GJySEJ2wG2xMwAYEWqIEeKIImqIIuKIM2qIM+KIE+AYCCJpbJAz30J4ZmqIZuKH9e
+AntWJkf+wCeHjiiJlmh+/ifiOOdkxOaAQqiLviiMxqiDSmiKimeFXqiJ5qiOjqiH7kt7gsZ77qiQ
+Dul+ouiVqahksKiMLimTNmmD0uiR2miu4SiRVqmVdkKP7sePfkaQXqmXCqmR1mZnKKmTlqmZLimU
+iilr3uiXtmmOZmluuue9WMMg1Kmd3ime5qme7imf9qmf/img1qkCTChtBpsPvACiJqqiLiqjNqqj
+PiqkRqqkTiqi+gCh2iaWMYACBCqndqqnfiqgWsOHosZuLgA5nCqqpqqqriqrtqqrviqsxqqsnmoL
+XOqYBlsuxIKu7iqv9qqv/iqwBquwDiuxFquu5oKtrmn+rq3CrDarsz4rtMrqAozqaZRqtF4rtmYr
+rNZqjQZoiuWqsYaruI4ruRIrsnYrhS6rtq4ru2LrtPooiG6EqbYrvdbrtibrZsQmuJYrv/arvwbr
+uUapZ1Yos9qrwR7sqb6rlsYrLPjCKjwsxEasxE4sxVasxV4sxmasxj6sEeBrYQYbKYSCyI4syZas
+yZ4syqasyq4sy7asyJKCx2ZGKgqABWyszd4szuasxvoCtZrGbiKCFASt0A4t0Rat0R4t0iat0i4t
+0watDcQsaqZYNnwB1Vat1V4t1mat1m4t13at134t1WYD1KomRwgANTQt2qat2q4t0yJCz4rmvYio
+m87+7YaGaWpaBpmeqd7uLYOm6d1WRipaKN0ObobC6ZZ6RpcSruKe6NjirYDyLeRGboH6LZJGRuBS
+6eJmLn0aLsPKreZ+bifYbeVCRt5KrumaKeVKaddgLuhmLueS6r3IAgLMLu3Wru3eLu7mru7uLu/2
+ru/O7gQ0rmYGWx0EgfEeL/Imr/IuL/M2r/M+L/RGr/HWgfBSRioywO9mr/ZuL/f+riy8rWvey7wi
+LPm2K7cKrGzi6r+uL/v2a8Cq6XIQbPnO77oqbJwCqfjSr/5e6/nC78d+a/sGsACba/VORuAW7P4m
+8Kza7+F2hrUqMATfK7oWKgAPsAVf8LEWsGQccAT+d3CrMjDDjq8HjzA59O/fPqf6YrAKB/D7nrAB
+yy8JkzAIwy5HyG733jAO5/DuBu8Ee0ZsFq/0BrEQDzERQy/19jBuZqoOLzET5/D3wisNb4Tntu7i
+ii5ppliLnq4WN2nqDuyUUvHnvm61xi0Ya64VeytHZPEWrzGMdnG6rm4Zuy74jkbixvHgnnH6YjEb
+7/GLuvFnXK4dK64Y++y9AC3bHjIiJ3LSPi0Sc0ZsTi3YRrIkTzIle63YNnL8lu3ZKjInd/Ihuy0U
+jzFHOKzOlrIpn/LFdiwm/y9HhKzLvjIsx7IssyzMrrLMYhnNorIu77Ip82woEzJHiHAMR7AJj+7+
+Y+jrCifz+rawMTsGBw+zB8+wKMsrNHtwMV8xR+yrMm/zuDKz6mYIAlezAkszMFOzOEPwNaPxRmgz
+N7czAdsyZjzzOScwOcMtR0QDJ+SzPu8zP/ezP/8zQAe0QA80QedzImhwZMTmoVIqQze0Qz+0pFoq
+PJPtRjAALxQ0Rme0Rm80QUfDHOsmGQfyHSM06T4uH5/0k5L0YwCySNPtINuzFLc03eIxBacxSt+0
+gvoxpn6xTLvpS4dviPa0m9K0D5s0Th91hKq0M7OpUH/pT9NxSDf1lRL1reoxUiO1TicxT0u1lT41
+SHOEOmCBWI81WZe1WZ81Wqe1Wq81W7e1WO/+gFI3xg/PAl3XtV3fNV7ntV7vNV/3tV//NV0fMfr+
+MZbxgVsfNmIntmK7tTp8tJwG8zwrcDrncTa7s2W/82DvdNeEc2TPbz0DtTl3Nv1Odk2v82WfNrB6
+sxdvtmjr72dDNWS39vySdlFXMGrfdgZPtGPCsGyT72t/dWj39sHSdlVXNm7jtmq/MTgLt287Nv5y
+hDXkgHRPN3VXt3VfN3Znt3ZvN3d3t3RjQlwzRmzqQgOUt3mfN3qnt3qvN3u3t3u/N3yXty6E92Jc
+r3ffN37nt357t6j+MkzDwhRzNZjSt2KU7lWjdFYrKxwLeJV69WPHNIMTKVU7slEfOIITeGL+sHSE
+C6mDPzeEb/iOTni+VriF83GCZ/KCg7iOdjiXFrInvziMLy0jZ3ZxbwQkVzKO57iOb+0l07iCw4LZ
+xriQD7nQgvLCRjEsgAIvLzmTZ6wq+/iIp1gEzDKVV7mVr2wEYDhizGzNNrmXf/nDgoJzt3hsM7fB
+EjeF2/Zxn3ZyE7a6mrnB/vaDw4Iwwzm7onmUG/eas7mWH4Y823m7yrmH0zmg1yues7Jp7zmf6zbg
+8nah1++YI+694DNHV7qlX3pAHzSjo3CKLTREfzqoh/qjSjSUa8b1XjSmp7qqV7pH+zdoA7iKh3if
+G4aBlzgbn7ipM3WsmyiLS3pQ77qJijj+osOCGtv6rc96YWg4sPNopDtwVC87hwq7aVq1se8xrt/y
+VkP7hva6s/+6ttctshNGrVf76V57POv6txdus3PGbqJDCLw7vMe7vM87vde7vd87vue7vr87M4T7
+YMSmOyyDwA88wRe8wR88wie8wi88wze8wLuDv59YYe87xVe8xV/8vqPDum/GAz/6uh76tOu5ortz
+m2v2cns8pLs6bAc3yvNvxAcGMo+8ZZe8VrN2y2eroJM5y9/8s4J81Iq8zG8zzf+4PHA2zztrzvv6
+zh/9rPr8ZcR80HPz0KP4yTP9syZ9t2/EIHwA13e913892Ie92I892Ze92Z8914P3pq/+aLDJgNu/
+PdzHvdzPPd3Xvd3fPd7nPdy//FFmKtr/PeAHvuCj/SBsvGbUcbr3p7T//EYUO7mXO9//hbInfoca
+fmYgPuXr5+I/PYk/vumaO0VnCOtmfn5yO7s/O+kz7tonaed7fuSC/m5ne+rjp+lz/L2cAQvkvu7v
+Pu/3vu//PvAHv/APP/HnPgpEvl8APDIsP/M3v/M/P/RHv/RPP/VXv/UvP8SvvuXisjYUv/d/P/iH
+P/GfgeVjxm4qOZin/5I/uf+G/EZM+ZXHv/xTeZZrP2Rwufrnvy6LucoDN6FbPUCQEziQYEGBLWAl
+lAdAXkKHDyFGlDiRYkWLFzFaXNj+MGGuWB9BhhQ5kmRJkydRplT5MZfDjRlhxpQ5k2ZCEgBcrjK4
+k2dPnz+BBhU6cIHDmzWRJlWaFAAJhwuGRpU6lSpPhAoZLtW6devLjivBhhU7VmVLrBy5plUL86hC
+nVXhxpVrsKhNnGvx5s3Y9Olcv3+nXoXlVW/hvIQ9klW8mPFJs4OzGpastu3gt4AxZ95ZF1blyZ/X
+8k2ILkRp06dRp1a9mnVr169hl2bmMjJo2zUJu1u2m3dv37+BBxc+nHhx47vd0UZ7mznbu7D4xJY+
+nXr12OiMPm++faZoWJc6hRc/nnx58+fRp1e/nn14SMq5x69I+AkT+/fx59e/n3/+f///AQzQvifg
+k89AiCqTh572GGzQwQfZuyS7AymkyDvwIMxQww3Te++sCimkT8ARSSzRxAAJ/BBEAxNckMMXYcxQ
+QrtWrBGWC2PMUcf1PIRsORuZE/HEIYks0r8UfQSSuxZ3bNJJ8WbsTDsl5cPxyStz7JEwKm0T0sgv
+wTwRyS25/IxJLNHkMErPytzOO3Wsi1POOV1LpMA2PyNMl+P47NPPP43T5U48JauMAWboTFRROdWZ
+kFA3nUoIKs0opVQwMh89rLbEGuvUU7IewzTTtRK8rNJT/eKMzVEn825SVGGN69LaWMULsU9xzTWl
+UGmtlbLn5DE11mGjUnVKXwv+c5XYZaOa9Udku9pU12mpBYnXZ6FdqlRmuQXK2Gwlc3WVcckt19xz
+0U1X3XXZbdfdcY0YFNylCJMmlHvxzVffffnt199/AQ5Y4HulkXfepBK04N2FGW7YYXe/PTgv78SQ
+x+KLMc5Y44057tjjj0EO+WKDJaaJMJFRTlnllVEmuWSZKkOC5ZlprhlkMRx9OS3vdDa5155jEhVo
+jIQe2qJVjcYI6aRl4pnpi4p+OqKopX6I6qppxPqipbWuyOmuIboaa7GrJltqrsGWMm2YAGjb7bfh
+jlvuuemu2+678c4b27UXytvvvwEPXHC49077psERT1zxwNfOiITHIY9c8sn+Ka/c8ssxz1zzzaFp
+PCJoNg9d9NFJL33yzj232vTVWW+99NRhj1322Wmv3fbbcc9d9915793334EPXvjhiS/e+OORT175
+5Zlv3vnnoY9e+umpr97667HvXQwAUE9olBseygP1hZCK26ms+n7bKfIhgvuG7iVCHwAJHmLocMLT
+d7uh/AHoBecbsbU98D0ECaN4AwCwEakbwa0XCXEf/ML2QP61TYFGgeDUjkUR8rEvWrB4X/ZAmDQn
+POIhb6BfQrbHEQ46JA9OaNsokGChZ8lPIit0IEcK+IYYTkR+OnRIbVZoQ6w4BAk3aCAAJXK4HcIC
+CU4YRefk8QYSIjEikcn+4RIj6BBoOOGIN5zIFi8COpiQT4xc2WAXQ5jGkj3CCSwEwBJ7ERkbQkOK
+sNgiGts3w/1lUIi06kUF8wiZP/4QLUHko3bY9zNYmNCERkGjBLDhxSouZ5A11E4etKPIzgCSXhns
+ZEKw8T81jhJc0OCeTQbYmUfIcUpi6KIQCTlJyFhSlg6BpAwhs73/ARGRh7RaJKkYvjd+zyEjJCBH
+FEmrW9KShWjUJDYaIobHUZAEB1zfXaqJwP9lExv02+BdHoENBOahgf4TZzcTkodz5gGFccTGKO4y
+Ck6Skp6jMiYssMFOWIghkqysCAmAGT89zhKDtRwiD/fYmSPy0mq+TEj+AZH5LGJicoeaTOZyYElQ
+O5IAi4pEwikXMgpYYPIGSMCkxXCSQlg8ooHywEbnjvLNlb50pW27US86Z8DBvGGPnXNCSbcITjzW
+k6iEYuM+31DMhvhTIjkUZRXfttA9Ek6jsaQNLsmHBHQylDZww8rbQinJEuqzjsFsH9wiRauMTvCE
+Ym3oQanIEPJt7xFYnJBM0ZkQF97ohOSTp0NuQILtoU4Cd8loURELpI+CTqSdGSBTEfSGJ3ptoLDs
+43KWKVCCRvGjhewlM5l4g8b2CpNvayMs7mlBs1o1IZnN4kN1ytq3ajQycr0LOQHgBHaK4QZv6EUc
+Z0m+2sCTiuSLo/r+OMi+wyaWuSC6QTj1edy3VTUhN3DCUxEqS8sey4/z9CIHA8tVuM7WJlKFyCga
+O9JTAlSYMbzoQypZ0KvKdr4crC1KIYJJMbwhUjIlX15hAVx//vUhpiSsYT3ZXAUfCJJJraUN8+DD
+i/yMhvKtHw4NaNcLaxQJB/QseUFMAvMS8Q36TEgdtfpBeTghrdiyYoYnwsECpnK1P8SZfSNKvnBC
+kXt1hEYcZYYT8gG0c6vEiT+juD+eBhioe13pUBccZfl8NL0bhoz67uc2XAZygi1F6wLd9kGsameV
+H+6q+qoaxc7FTQIOdsgoTptDBCpQbg58m5gteeeO7k23tM0xTgr+2DZ0QnLOb+CpkLEpThYfWYV3
+IXRekRBHEx5xFFOU8qUxbbRHeJcrYuhem5fyhgtmmtSlRlYTDUNkO7JYKRKosqlhjaffznrWkxEx
+rX+L3ZfhutZJecSouYKEbPJXwzArdqyRnWxlL5vZzXb2s6EdbWlPm9rVtva1sZ1tbfOa29329rfB
+HW5xj5vcbYWdK8mdbnWvm93s1nXj0N1uec+b3urWHQLrnW997/trjVsIF/cdcIGn24WFA9u/B55w
+hXdbnPfmdNr6zTdNps1sT6s409AGu4ivbeMHn7jHDd61iyct46nrONhOrrWRG23lQ2s50EruOe+M
+QBI1t/nNcZ7+c53vnOc99/nPgW7z7qV8bLWJwSmQnnSlL53pTXf606EedalPHekxcBnFaxN0rW+d
+610POjBydjvvMCJNZc8QPdBC9LLVpj5hcvvb/zOmj4u8NpAw+90btKYEx27sePf7etD+w4fTHS1t
+h/vhEc8EuYdc5XX/++PPo3eHO4TskLe8eALvwME3vvCJ9/zbFz87wtj98peXfO76XnrLZ/5Gmy96
+5z8feyOFXnajV73lT48774jCBb33/e+BH3zhD5/4xTf+8ZHvez4IXvS1oQMHoB996U+f+tW3/vWx
+n33tbx/6dLg6yB0ChuSPn/zlNz/yTRF223knBdVyf65CkXb+168dLa/q1v0LwpmX94wwk3j//zvl
+MWKucdgPAA1QMeKP+WqvNuwP/xxQ/+aO8xzC/w6wAsFCAPdO4xSo/SywA1EiATWv+erPAUlQICCQ
+8V5vAj1wBUsCAycvITiQBWXwI0Cw9USwL0rwAb+P8FRwBmfQBVFPgUShFoiwCI3wCJEwCZVwCZmw
+CZ3wCYuQARQwdgijAjThCrEwC7VwC7mwC73wC8EwDMXwCitgByUwIbIACtVwDdmwDZ+wANSvdlLv
+9v6O9dROarxE9vSwRGiPCh2PDv8u98ROgSoPEPHODucPD9luDxmRRPoQdmzPEPFOENePECXxEOXv
+BhPC8Br+sRP74xFTJxIvsewoUQ4VqBKkIBVVcRVZsRVd8RVhMRZlcRZpMRWpQQCmEBJrIxu+oBd9
+8ReBMRiFcRiJsRiN8RiRsRezwQxTMCFsoBahMRqlcRppMRPikHa8QxkGZhu5sRu9UWBAABdDcAHR
+whAe5hzRMR3ZxRCYkf4cYgO+MR7lcR4BJgKucXYK0AdlsAbv0OIYMAd1UEX8EC0oUB9XEAh1bwMN
+kgX5MRH9cQQB8v5OUBNhoSAX0gIRchAdIgYvsgIbkiIbMCKJZSLJsQc7sgIzshIdAhWGoCVd8iVh
+MiZlciZpsiZt8iZxsiVfQQrHcSAdogxSISiFciiJsij+jfIokTIplXIpmTIoy6AdFREtjiEnqbIq
+rfIqcXId7lF25nAU0QQRKZITPXEs8QMUPUcUvRJLShEbLTEtvzITS3ITyXIuyxIqH9IhSM8tr2Qt
+8bEt9fJJwDIuYUEs6dITzdLf/vAvnYQvudIvFXNHAtMn5bIw5/IwJQ4t8vIxdYQx+U4Ix+EzQTM0
+RXM0SbM0TfM0UTM1VRM0l68ndREt6KAGZHM2abM2bfM2cTM3dXM3ebM3ZdP7BPI1w281ibM4jfM4
+VTP9siYhN/IkLfAjBTMkRTJWSFIyK9I5UXIrO7M5sdMAodM6pXM6UaU6hTMhLLI73S8lTZE70fP9
+vrP+PGEhPMWzUsgzFGvjPNtzWtSTLdkzP6nlPe0TIudzWOrzLO/TP9NTOzXQIY6gBBz0QSE0QiV0
+Qim0Qi30QjE0Qx+UJ21QMBXhAUA0REV0REm0RE30RFE0RVV0RUFUEeySaQijCDR0Rmm0Rm00Q+Fw
+OTUyIQpRM3MkMuGTMCmTES0T6zDTR3eEMxeUR5FUR4A0QB1CSIdUD4sU/BIiM5tUTRTU5BwzSzfk
+SQ0U9qa0E6uUB6/US2FESbnUIRrBEtz0TeE0TuV0Tum0Tu30TvE0T930BMSxQ60zDlghUAV1UAm1
+UA31UBE1URV1URk1UOPgRZOGME5ATym1Ui31UvP+lAi2VOYUSBvp8VNBNR7DMRehNCHMUR1RNVXP
+kR2Ds1RhAR5DNVZltR43lQAVEkH/Ey7Bc0BHElJZ7kBxVT9rleNuNVjhT1fhUz55FTMKFDEJ0lh1
+ZT/7sj+htVMANExxcFnH01ddDlir1VOktTFXkhvItVzN9VzRNV3VdV3ZtV3d9V3JdRw4tB9htDbK
+IAPwNV/1dV/5tV/99V8BNmAFdmDx9SlbFVsT4hjgdWEZtmEd9l3/YFghrkvRFELA1FmjdEwNk1uB
+Bi0rFkLUlFMp72O/FFldVUo11vPK9AxhAUtJNu8kFuUo9mXb42IvM2NTlkg5lv8Sk2ZhVkdVkkn+
+fdZBbNZIcTZnqXRndcZjh3Y9QtZWx/VhpXZqqZZd5ZVUERYW7pVgubZrvfZrBdZgk0QwFbZqzfZs
+pTZigXY9YfBbP+VaMVZStBVWmvVmzdNtwTVmuyYf8ZYx4NZu43Nut/Vg4/Y6+5YxwnU72/ZwF+Nv
+jVZuBZc+lfZl+o9xFyNxlxQWPHVWObdzQ2FUXdNVT1VVSbd014VVx9Y6YdVzWTdU7XFt+TMh2hRT
+abd2bddO+RRrCxdQG7V3ffd3gXdRH5VwAXdSb/d4kZd2NRV2p1Vom7ZmTTZrURZp4W5lm7Fln5dB
+npZYRzZ72aNorXQwqTdpifdxsdd7nVZvtab+K9H3PMDXTMV3fGPPet3xTNs3PbZ3Yh1iCN2wf/33
+f5twXh2yXtHCCsfwgBE4gRU4DMuwfMM3DQE4giW4f3NUbYKQWi0XLBw3fJU1cuOibs0XPzO4LNQX
+a/h2hDU4egu3gz24KkA4fEUYhR2jhKvmhGU4JTYYflm4hafiheE3hm+YJDB3TRc3iHFYhQF3h3m4
+WCa3ZCrXiHeFhqVm95Cziq34ilOzNf0UPmPTN734i8E4jHkTOFMXPsEAi9E4ja1YOS2YOZ33fs3j
+fVl2euUXTOg3KvESjtEjf2W2e/W4POT4eum4jmeviSWGaf+4E/h4b2f2jwO5fuOXkBHvju/+0n4T
+eTwWeX0bWY8fGY8nU5IPj5IJOI8vGZOl+Gm8gyWxcpVZuZVrcid1F3CBsilpuZZt+ZaXUmz3b2lr
+Yypd+ZeBeZW1knnFtYih2CRymGWVeImFwodZFoiPmSVOmWlsOJpFIpmvd5mZ2VsM+WCe2JqFeJqT
+pprBmQaR2Hy1eZt9wpmvF5qjeYhFNiE2t3XpWR5Bd4tF13T1eZ/JBXV3mXJrY3XreaC78XXbeEdh
+ARWpcaEZuqFj8RZj2Xx5MRkpuqIt+qKPcRkdGH6f0aE9+qMX2hqJWXFhoUdLuZMrOZJBGfS6eV4Q
++Y8z2YQ3GY5RepQ/eaXdTpQjtWdLOab+a3im77emd1pMcTpMdPpXj7SUoUScjWb3JvipofoJBZgi
+DXiBrfqqsdoLG7iMXRWCo/qrwboWKngAudeYyxkksBmS01mdeYKdIdmdjxmeodaszzoW0tqTA5et
+5cKt8RquoViuyxoWOLKu7fqcOViv97qlweWbCTsWAFt/6fqs7zql1xqxCYKvU9qvjfix+zghliAF
+QDu0RXu0Sbu0Tfu0UTu1VXu1Q1uU6HWoHcIeZHu2abu2bfu2cTu3dXu3ebu3aVuxs4UwlIG1ibu4
+jfu4V9sVmHpoXnucBxi2BRM+YYesIbuYrVO6XXW6M5CIrRu7s9a7G4e6Ue6PXKe8zdv+vJu7W+Xp
+vNm7vUUHnlBw7dbbvem7vicHuFBvcfR7v/mbgpqvvwE8wAEnvhVRwA38wOdG2xR8wRm8wR38wSE8
+wiV8wim8wi38wjE8wzV8wzm8wz38w0E8xEV8xEm8xE38xFE8xVV8xVm8xV38xWE8sRrJltyMifpr
+uy2EgQgqbrwMg9wmnypC2A5IsioqbrTIgObs2MAsqvgHz2L8yZmDBGhMtB6iLYSIt9qmpLZstn5G
+iDiozUwsIuCsc6DBiNxKiySrc8TACU6LsuZr1aAMyuW8MLZnhz7KxCIMwSLinZCgieK8xhLpWbxc
+O9gruxLClHBGkXqBxrTK0gy9qjD+ac4l/TPyKsK0qJv0HCJ6YYcOq8vvwtMtzI5OSSKI3CXc61k+
+CruOys3Hi5wm/dULQ8q9R4F64RGUa+8KXbNeC9Rfi75oPLcEy9cH3SLEC3SUHNaRHSnqfJG2CXxu
+fSKEvHCMfMe/bNitLMZIwIVGS8etfcvZKtnBnSucQALUSSF86Nkj4hF8C9jOfMcF/VhWyMAwQr9q
+LNUhIpyI3cyYKLbCvd+R4hFEK1KyrG3wC0GgacLevd27vTMCqor2rMaYzCF6waUGT7yoy98xPiNM
+Kaxey4bsHeHli9fJC8wp4rc6p4BOS5HoaLJWScK8/TlmLONlPiacoOHri4EmaMv+56vO+MfLfjzM
+I0LO0tzOqMqOkLx/AOzRm/zYZ77pdUcMHN3ppX7qqR7Cbw3X3k0tJIDbzE0puq3qwT7sxX7syb7s
+zf7s0T7t1X7t2f7B7fvt4R5y2B1sQCfu7Z6+517k7n7v2fveEPzv/57A/RHwCV/ABR/jCj/x+/sF
+rzu7Hd9zxBvxGR+8AZfyDQfHsSbyNZkiLT98tZt2NF+mHaJibKb0TZ9mgBtaTub0Wb/1Qyb1kSVm
+XH/2aR9jRCn0f9ohLoEeeL/3ff/3gT/4hX/4ib/4jf/4eb8PYN9XCOMZquD5oT/6pX/6qb/6rf/6
+sT/7tf/5n2H5ayVBSgH5xX/+/Mm//I/fp6dYgTBEqTtBSyJQkIuapTdaa86E/dEfldWf/d3D+1kl
+D+O/kAECFix5AOQJPIgwocKFDBs6fAgx4kMSAA7Ko9cpo8aNHDt6/AgypMiRJDNeOkhRosqVLFu6
+bAiAxMFLJWvavImTJCSLBV/6/AlUJUGDAp8wOYo0qdKlTJs6fQo1qtSjT3gSDYo1a9CUAi/m/Ao2
+rMiTArlqPYv2Z8yDBzy4fQs3rty5dOvavYs3r9tFVtP6/ctw6MFw4AobPow4seLFjBs7fgy5cLi+
+gCsDNstgmN7NnDt7znsAZUXLpEmvFUhTrOrVX3d27Vk6NlbBRafavo07t9T+qq+vyv7t0qxX1sSL
+jxUNPDnW07BSG38OvZPrgbCVW4dIG5ZR3dy7e3/Km7rv6+QVCscYPT1xsrDMln/vkLlz9fTBTs8O
+H3727d/7+9cdHn75lXdefQZ+xZ57Ay4Ii3wHPmjTfdUxeN1+/12IYVQBTkihcgVCCOJxZY3W4YDM
+BfJZiiqueNcwlJWoXHbfhEFjjTbeiGOOOu7IY48+/kjjNy/CCJxZfLCIZJIrBoIckfA5GGKUHkk4
+npOlWZhhllpSNaSVpX0oZZgmNenldVCKGSaVZcqG5ZZu/rdhlWv+BSaaUSZI4pzAnWlniGrqaVmb
+bw7aXZyAWlZnnxDieej+njIJNA89kk5KaaWWXopppppuymmnkvbRZaNnZZfNF6aeimqqqq7Kaquu
+vgprrKZmE6qoWZklQCme7sprr752Og+ZtlrG3Dx3HItsssouy2yzzj4LbbTSHktMrcMClZ0WVWzL
+bbfefgtuuOKOS2655m6rhbXX+oQrIdO+C2+88kob7IjrEvtoc4pG+ee9s1XHH6EC42aov1gluq+B
+jBrsF58JG9gvwz4JOnDFGqorsUQIP6zewhlr5TDH6kX8MUsUW4wyUwWX3NLGIkPnMctAMXdAOzbf
+jHPOOu/Mc88+/wx00DbPgbHMgVUHhxxKL810004/DXXUUk9NddVKw1H+tNHmkcgAFEJ/DXbYYgcd
+mr1aq5XvfC+nR/LZDp2cctxc9ua2xiQOt3bHwta9Ush5G9c23wrBLXfKKwvOkMt/sxYz4hH5vThr
+gTtOd22FX87E4ZQjpHjkYjW+OUxpew7d5JQTjvnAmofe3t3okV4c6KwrdKKStt+Ol4uVz747YZH9
+Dnzwwj822e68G4l78srDxaTZvDMEOez2Zc036qkTunronUuPk+zPCxQ99ziZ7rj117+Z/ebbi1+T
+99+Hz35N5CNu/vlbpk/5+vGP5P7z8O8/kvkJrn72yxL+HKc/AIKkf7xjzjkGAMEISnCCFKygBS+I
+wQxqcIMQbAX16pb+HXN0YYQkLKEJT4jCFKpwhSxsoQtHaI4Pug0zzuCgDW+Iwxxu8Bx7+95B/qdA
+kAiwegArIMoOiLgEBrEjDJwdEJfYkSGCsIhGrBgSBadEKGqkiax7ohY1IkW3EbCKcJLh2bL4RS6G
+rli/aqMb37gpUBlvdqSSlR3viMc8xopWc2QdrnQFx0AKso31ap0PF8IcREhhkYxspCMfCclISnKS
+lKykJRdpAzNqLTvXOJcnPwnKUJrrGpo0Gq6occlUqnKVrLQkInp4SC9+UTqllNkYydifK/INjVpU
+4+Zk+cUwnu2WuPSOLuvGSyj6knLA1KIwN0nFYqKvlixL5hKX6Tj+B2pgm9zspje/Cc5winOc5Cyn
+ObfpwT6GLju6aIA73wnPeMpznvSspz3vic98ulMX1CwZDc8J0IAKdKDm5KHzDvnDfC2AHAxtqEMf
+CtGISnSiFK2oRS/K0Bb082PZyUUsPgrSkIp0pCQtqUlPitKUqvSjudhoxoSzCozKdKY0relFFwBL
+HzJnoTbtqU9/SlGNqnNzHV2pUY+K1KSqtKVDzd/dYgrUqEq1pzg9KEIbpNCpanWrFhWqeHxYVKWK
+daxkPSlTv/o9mHJ1rWxtaFUNedWEHoSnba3rVL0qINaFtax87atSz5pX7T3VroSN6lsVhFDm+MEN
+jG2sYx8L2cj+SnaylK2sZS/LWC+4VGLZiUIzPgva0Ip2tKQtrWlPi9rUqvazUdgsw4yE2djKdra0
+xawfcvq+rBZ2tzbFK4f0Wh2P+nW4xEUpYH8rWItAlbfMxehh83TVnTZ3ul11rcH2Wtzsave4clLf
+YKkL3og+N65yFQhdw4tecvi2u6cLrnbfm13u+lCt6U3veMmL1bnWN73rBat74Qvgvso3rd/dL3jv
+S17m8EIcDG6wgx8M4QhLeMIUrrCFL8zgT1jXX9lRwSQ+DOIQi3jEJC6xiU+M4hSr+MMq2PC9MLMC
+DMt4xjSu8YV5gVv/6dbA1O3v97Ab4CAndcDPoy+Pp4vguEr+98jT9fHzgCzkKC/VxesyMpN5m+To
+7vjKu3Uy76As5TCXlMjHKzCXC5vlxOaLADpos5vfDOc4y3nOdK6zne+M5zYbgMrXyo4QqADoQAt6
+0IQutKEPjehEK3rRgBYCn4eFKxrkedKUrrSl8UyAHDcwX6BYhac/DepQi3rUpC61qU+N6lR72giP
+tlV2IhCKWMt61rSuta1vjetc63rXvI51BFotKlxZQNXELraxj51qUGjaiVs+s129TMf/innaYwZ2
+o6zs7LqmOZbNzjZboQ3cqwiX2uQOKZlnh21vr3XbOu22urcK7nVKu9zlPrcfzfxurrI7twe5hSf+
+DfCAC3z+4AQvuMEPjvCEK/zfxbD2obIDhldIfOIUr7jFL47xjGt84xzvuMTB4HBAYSYBCy+5yU+O
+coXfYtlddHe+pRpvos6b3tS2d3K7styXb3XfOtavzrka8/aKm+b0trl3lftzfbN8jS5Pek+DXr6Z
+Ez3MRncq0p0+VZ5v2udYjyrU6Sf1qUe56gjEd9epuvRf5svfKW+7299+8IY3NepXcQAg7o73vOt9
+73zvu9//DvjAC/7uDgi5nkYO98Qr3u0rt6qauX52n359gGEXe5DJnkSzR56mWmc25Ddf08kTceiW
+FzPmsah50Ds37cxsuuorKvopkr70Uj79LlP/+op2vuX+B+k0sn8P/OCbmtVzB/tV1NCG5Ct/+cxv
+vvOfD/3oS3/61E++Ggw/J2ELf/vcB76yHc/tg7D50uQvv/nrvOfiU/4qQui1+98P//jz2tHqv/1B
+BCDp8+t//+TPNPjb/Xm5d1GxJ0aVR3vvZXvIhHsCKFG7x3QByIBBhX1rAmYHiIATWCbpFoET5YBq
+B4EbGFEEOEwGaIHFlYAztIAg6Fasl035Ug9eAIMxKIMzSIM1aIM3iIM5qIM7CIOJgIFekh3rEABD
+SIRFaIRHiIRJqIRLyIRN6IRDuA4/aCWYMQE8aIVXiIVZuIP1wIKIs2QqKIH1J3sHMW4lCGAneEYp
+CIb+Hdh6HwiGDSWC0DR7ZghfaKg1GviGK/h//GZeeThRcWg0FUiHw2WHpqSGKsiGLeiGeQiItkSC
+g8hXhSgzeOiHieiF+bIF9qCJm8iJneiJnwiKoSiKo0iKpaiJgiCFTpIdrpACreiKrwiLsSiLs0iL
+tWiLt4iLregKqUgkZiEGpgiMwSiMw2iKW9CFgsMcX4ZcMsdedDdf0IVu0Bh+P7aMQudfzZh5h4RY
+0/hk1eiM1IiNqKeN0qhTvUAC54iO6aiO68iO7eiO7wiP8SiP7zgK3gh2ozCP+aiP+8iP/XiO9RiO
+t+ePA0mQBamPvUCO7wMAC8mQDemQDwmRESmRE0kokRVpkRYZkFN0kRvJkR3pkR/pkBmJgiBJkiVp
+kh6JXympkivJkm4TEAA7
diff --git a/Documentation/DocBook/media/nv12mt.gif.b64 b/Documentation/DocBook/media/nv12mt.gif.b64
new file mode 100644 (file)
index 0000000..083a7c8
--- /dev/null
@@ -0,0 +1,37 @@
+R0lGODlhFgFnAMZnAAAAAAYCAgAASAwFBQAAdEgAACQODkgASCoQEEgAdHQAADATEjUVFHQASDsX
+F3QAdE0eHVMhIABISABInEhIAIM0Mok2NI84Nk9PT5o9O5xIAHRInFlZWaxEQbhJRgB0v75LSLhQ
+TbRTUcBRTrBXVatcWsJWVKdfXW9vb6VhX0h0v8RcWZhpaJJubpBwb8ZiX8ZiYI5zc4t1dYd4eMhn
+Zb90AIN8fH9/f8pracpta8ttasxzcM51dM52dM53dc94dkic39F+fNOEgpmZmdWJh9ePjdiTkt+c
+SNuamd2gnt6lo3S//5y/nOCqqeKwr+S1tOa7uv+/dOjBwOrGxuzKye3KyuzMy5zf/7/fnO/S0fHX
+1//fnPPd3fTe3vXj4vfo6Pnu7r////v09N////35+f//v///3///////////////////////////
+/////////////////////////////////////////////////////////////////////////yH+
+FE5WMTJNVCBtZW1vcnkgbGF5b3V0ACwAAAAAFgFnAAAH/oBngoOEhYaHiImKi4yNjo+QkZKTlJWW
+l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGmkM3ysvMzc7P
+0NHS0CjT1tfY19XZ3N3Y297h4sxDlQDj6OLn6ezZ6+3w0u/x9M0A5r/3vvq9/Lz+kQDqEpiLIC6D
+txAyUliLIS2HsyDKkniIIiyLrzC60tiKoyCPq0CqEpmKJCqQJk+lNLWyVEtSKPPJ3Ddz0stRN0Xl
+DLUTVEyaQPvVlNTzU1FPRzsl5fRTaNB/QwNGHTi1IL6nu5Zu0qqpKVSsVME+4pqJLCazl9Ba8oqp
+jAIA/gTCIOXkVsAVo52OAABgV6kmMxr2Cgbil9LLGh/OIJ6r6QgBLAfuMm48YYzPT1siF7a5qUyD
+u1HibtaUWfLoS55NT+a0+DSklqXPxK5EJkuhm7NdV8pMYW9i3YJsT8q99Wqm2MQn/cihZRBuzasv
+RenrdgnwM8uFQzpSOfrrTcihW5KyogiYM89VF9cUWq7i3+sRTVlB5Lyj6ngNd/58pn0mMUmY4ER6
++R2nGWCEMbUIGQE2QUYj3Fnm3VibIPgeJ178kEFz4Imn4F8aEJbcWY18EcQLViziVoITOvLSFgXA
+5R4iVvxg44045oijByAU0QMIQAYppJAwPHhIFILx/qUeieDFCIB1igjBg45U4nhBlVSaAEIQYiTi
+2IzXLbTKF1mUaeaZaJr5RAc5aKeIFStw0RErVehARZp4mrlAnmlCscILU8yp3y5iILECBI7AKaeg
+q3DxQ5cuMgLgCg5uZBwuTpiAhBgQKZqRK45CKqYiftZ30aW1WEFDEF58xIinn4L6aCMIabHDDhye
+OqgtYgSRonOLwBqrrKImglAQUjyEalg0xjlRLKEuotayFIoliLC6whKtsVVFai222Wo7KyLT7kpU
+VeCGK26xhJTLmblZGZKuuutW1C2tUc1Lb7233TuqU9c6m9At2wJrLb68JEEGP/rG4u4iBaPnr7S8
+/ohhgsRnNOxwLgU/LJVh9YR8Qwsl3HCOCyHIIDI986yMjgwkzKBMyy63g1LN8JzAgskoq4wzOzT/
+3E0MIIiQggM2CG0ztbW88MUZDAgc7y5aFlHBCDsk4ebA8NryxQsZd7DoV7oIQcQKBpyhRRM/jOCE
+VV3X8kQRcKYtCBnsNsQLFHSLPQjecL+bi9lxApCFEjuM0ASzuXwNtdSMf5yLlkQEAcIOSmzN9S5O
+A6Dxs3HPogUIOSBhRQATy1LEE/d8vq+3t5BhhH0YA6zLFELo47qlocNChhC/unowLRYzDLnevbvy
+e/DC265LEqgPsntITCsPvCEef4fV9CVVz8ry/vYOjzwh3KvkvSrgh+985AGPDbrgvl9PbuoRNev+
+6wjHzzz29L8v7/G8g18r0sct8SkrEeXTyfkigaS9sIgRBCwge/bSlzBNAjAV/BACAXgIGAmmOxo8
+lybK8AC5TGdJh4igBAuhOUaUYQOWqQEIMVGb2jVGAh6iRA0N9iYOFmJE8RFhJ/CzIPn9qxDZoYR/
+NLEcBNClAUzIISWWw6FO+XAQQOzKAocjxUKoUBEImY+pIAEY+GhCCh0wT2OAkEVJkMc8EtGYB/cC
+pRBKjjVmTKER85fCBhlpEQ2c4SYGEKC3XWILCQhDGyUBIBNE4BG7O0IGtZg8SkRIEV+k2CJM/oSi
+R0gShWs5Q4aYY4kaiKiLlvDCBUjZCNcRMYh3zMSXFuEDHGAJS1e65Y20xKVGvPJNurTSjUbQox8N
+6ZhAosEf3ZIkADxQXsHU0QWI6SNkIrNIKlJAHSkpwEvIUEKK6AKfxrmncZbJT4BSxBZUIIgTlsic
+ZyrnE1bQJkws8gxkgieaIEDPFkaiBlCapR21dxwn7UWQTErEpCqlCMBQEJRrKdQKnkAaVFKiUB2g
+aEEPCk5YEpRshygV7VwRAU3lbRaZQsIA+qc+kBLCVriKhaos0CpcqIpVNpxaNwNXCGTJoldWyJ5C
+fcVDl35Up0blKVJjyT6lNvUgW/TfUp+6jzkhJhWqBqxfJQ+4Pqd6FXZXrepUv8rHsWK1q2e1qlnF
+SlVbsKWt4wurW6O6saxKFa5gZCn+5mrXiijNZn8FWmDTEbTBuqMSHDDsODCgWHEwtrHeeCxkucGB
+Y1j2spjNrGY3y9nOevazoA2taEdL2tKa9rSoTa1qV8va1rr2tbCNrWxnS9va2va2uM3tLQIBADs=
diff --git a/Documentation/DocBook/media/nv12mt_example.gif.b64 b/Documentation/DocBook/media/nv12mt_example.gif.b64
new file mode 100644 (file)
index 0000000..a512078
--- /dev/null
@@ -0,0 +1,121 @@
+R0lGODlhoAHkAOe1AAAAAAAASAAAdEgAAEgASEgAdBgYGHQAABoaGnQASHQAdC0eHigoKEIlJEYm
+JS4uLlssKzY2NgBISFIyMQBInEBAQEhBQUhIAFBBQVhCQkhISF5DQ2NDQmdDQ3NEQ05OToNGRHhJ
+SJxIAItHRY9HRXRInJdIRlpaWppLSaJJRqpJR7BIRa5KR2NfX7JKR2BgYGxdXWleXmZfX31ZWXJc
+XHpaWQB0v29dXLZKSHhbWolXVpVUU5JVU55SUJhUUqdQTrpLSK9OTKRRT6FSULRNS7hMSrVNSr5L
+SL9MSr1OS7xQTsBRTrtTUL5WU7lYVsJWVEh0v7deW4pqab5dW8RcWbdgXrZjYcZgXnd3d8ZiX8Zi
+YL9lY7RoZshnZb90ALJubLFwb8prabBzccpta79wbsttaqx6ecxzcKt8e4aGhr93dc10cs51dM52
+dImJib97ec53dc94dqiEhKeHhkic39F+fKeKiaWPj9OEgqSSkb6PjtWJh5qamqGamqCcnNePjZ+f
+n9iTkr6amtiUktmVk9+cSL6enduamb+jo92gnr+pqd6lo7Ozs7+wsHS//7W1tZy/nOCqqbm5ub+4
+uOKwr+S1tL+/v9+/dOa7uv+/dOjBwOrGxuzKye3KyuzMy5zf/7/fnO/S0d/fnPHX1+Dg4P/fnPPd
+3fTe3vXj4vfo6L//v+/v7/nu7r///9//v/v09N//39////35+f//v///3///////////////////
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////yH+EUNyZWF0ZWQgd2l0aCBH
+SU1QACwAAAAAoAHkAAAI/gBrCRxIsKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPHjyBDihxJ
+sqTJkyhTqlzJsqXLlzBjypxJs6bNmzhz6tzJs6fPn0CDCh1KtKjRo0iTKl3KtKnTp1CjSp1KtapV
+h6QkWdrKtavXr2DDih0rlpFWsmjTqkVrdq3bt27bwp1L16vcunjn3s3LNy2jVRU/MKhAuLDhw4gT
+K17MeDGCwY0jS54c+THly5gvW87MufPhzZ5DcwYturRkBGkqvgAEdPVP169Z+4Q9W3ZP2hJx89St
+k3dv27uBB4+tWvhO3ziRJzeeU/lN5zWhK5ROk7pM69eZL2+t/Xl3hthj/oZ/OZ789+jn0ROnWN5l
+e5bv4aefGX9l/ZTx7+Ofn537+tr/5cZffwAGeNyA4iFoXnH+FejgcAb+xmCEzSm44IMQ3mbhQPqh
+1KFJH4K4oXwNajghhhJSuJ2K3p1oIoopvgjjihOFWJKNI+GY44j28dgji+D5qJKOIRFZpJAeIpkk
+kAvZOMsBAAjQykdOHhDAJ1QqSVAhAABwpUcf0iJCl2TS0ZGNmZDpSJYcpekllmfyaKMXNtRCZ0av
+jEJQiIUIAAoBcMbJUSEUxHJkQa+wglEpgGKUJ4da1vLkmn1OiZEsoUC6USkDrJmJlIKyF+ksCWD5
+qaUWydJFHagIhCOj/oFyFCKpsYIp3CZPRCKLRXdeumqrs5Zay6kaxTGGniESS2uoNUYKay3PZhQJ
+FYnI8mqjtm5KwAVd1pltQangkYUnFEUrLbUtRGqnAKocsOZGmlDxRwyRZvLlpMwKqC2W5mLEyh5U
+zKAutNjme5G9WOJr8ECerJqKRIQautG/RsjRkRcAFNrRK4kUYQZHGHt5wbsb5edso/1mFEoQVrS6
+L5saEWunt7J+N221DyncUQ5OsJrRk2Z6AWpHN1RxbEc6a2TyRsvKjJAncUQt9dRUT/3DEUgcofXW
+XHc9CEMpK30ylmKaaRAebFSt9to/VLG21F0cQYUmDkXMENRvs13F/hFLXNH131wvgpCy7t6dt9pt
+L3HEH20ADrgWuyrktNguXlT2zAulEsrmnHfueec6KNEFuQt5QoUpYBdc80aXh11LJ2Vw8vnss+dg
+B+2cH3IEHg8zBHRDmuNOew5mPDE6RggTXOtBwQvveQ5oUDFGpnefvtCTNJcsp7qcRomqRq8Q4nFD
+pqMuOZlvLmxR9wCQbJApcbzSbEKoGEt9Q5V+9IoPSlCyEZddch/4dsCESjikfAl5UrdgNj+eUOIJ
+h5BBehB4oZTAT34R8c0rDvEEA8bkgTvog09AKELyWa8lS9NJw3wGHQpW0ILxy6BxHngIDL5khagw
+EkdwSB0XkkhU/jpBxRhIVwvn+NA9A4PIBSGiG0z4LCZCJJ0OwVcHKU7whEis3IEScsQstmSJDpmi
++ipUOix6sYEz6uIZWQLGIDFJPVw04xplWCKCqHGOK2njdJJ4KBbd8UdAjNAfUchHiegRIWJcnYoG
+OaTt1bEWjPwhTA5pkERq75ECieR+tBgjSMqRPoWcCCX3FMpvoUiTmwykg1AJSJmM0lWlHCONMvnJ
+BHHyJtWCDStb6coYHsSSlPsJD/xgx1raUpU6ecUTisiaXfKylzYk5Rtn8ooi2MaZS0JmTjaBB2Zi
+s5E3McUaeifNGd1kE0OQzTdPEp8TYKEv8ByLGvRgCQ1IoQmK/oinPr+igXfuE56IOMIU3iCISWyl
+n/9M6EH9qdB9qiEE7zQEPhsKTw3woSIagIxpNqoYFmCgAg5YQQY4StLEGECjJTUNDo5AAhMAIQUg
+aABKU1rSk9L0pixYAAM44IKR3pSjBkiNNm+SiixA0gh3mCZL8AAw1I0iEj9Igv9ktJOivmAOxoQj
+GnNSiT+YjgaykUU0W4QTTHj1hC/ww1jJ2JOu1oAJ5quFWNm6VZww9XQvsMMizrCESGwRJ0X1JOqA
+mRHCXoSpSK1FKPbaV7rqaydPOMIe6nCEKCzifp20SRYeVj7DXsSzFYlsD6xwhDNc9q91tckojjCG
+Q3giXUpl/skfPPjVWCpyJ6sdww7mELkMPRYnsgiEomAZ25Vwk2GJNedMgqso0N6yIc51iCzwQERm
+FlclyiTIW+OKWuBSl7jKbZJtKTLd6lo3vDDBmauwyl3H2qS8mkJvQqK7EPgWhL6/1dA6s3kT+4KX
+qnSsiX/LCeAt7ldE3jUvfgOc2pcMmMC+hdCBSbJghDz4vAV+SIUJcuH4ZpiuExbJhgvS4RFD15Ey
+6bCHI9zdEIPExAJRMYzF+9yUqHjF3Y2wi00ZkxvPeI81PsmNcZzZHAvWJiYe8o/ni+KYlekhQyay
+QBIlETd9CXzIGpiYrkyRR1WSOc5kX8YkdkmMPInLChxa/n2/C2SEYPZ6VgrUmZcX5Db/TAFTSh5D
+oizlWuBKVzkrgaG8oLGMqKoONxhYISSgOokc2mV93qXrgmmRPv0pUHfqlUL4rBz7McTS2AI1nYeq
+YT4mzcJsPnFCwjWuKqtZWkYQQ2/NnABINHoiN+utclg56cJqKVpNe7VB+Izhg2yCCnsYrkL61ev8
+MpgjzZZrqlWtkBWSkyFiyp5GYsAFKmxCI4WgQ7Qd8i9v//cgqBSzAH2tkWg9q9fELvZBZJGIXM3a
+IMy+dZ2Z/BFNo9q8bmRIrhfipkLXLBS/ukgpCtCKcT8E4axqYVYRUgguU1rh2Hq3vqUNcH4zJBV1
+aDVC/vI96gaHMYl2UwgcwnA4xLmt5XGI29zwZ/GnwVxqbYsa1hwHOMEZxAtmmjTebj41vhGB53/z
+uUNOjZEPuRtlG1850eOQ85tHtg5rVR5BHH7yfUMkfws5hfOGd7uxh0J3vGsI0w3SPLPbLhQPPB5F
+FIg+s4HL7J+Lew1MXbjbYhxOwf4eQcSO98293eyYoEIWvn0QkpfZ5BQhNJl5jJD6TW8hpYCCQPRc
+sj4Q4glTzQjXGRI+0MubV+8C++P/LpDL+fuz6eEYFQA9ctWNPuCQl4iYxyzLWmywgw0RU5dqnpHQ
+1RDaG48IDTEYIvYZfPUUcdPw+TUA70HfIIlPdkKk/v8m7hM/9zRm0fJh0jAh5AEnOISwkYs8kFGc
+4Qx6Oib4tVoQJ0LaJVFcchS/fN0XFqQOdANKXkcgHzZL6+de7Nd1/UdImISACUhW81cd43VxLOaA
+FgiBznaAGFiBBqiBSNZkBfiBDdiBDyiCpHaBJihfBBiC9PdsHLiBHtiCMSiBAyh/LwiDKJiCNxh+
+KmiDO0iDCyhJGViCMkiEQNiDMJFCSOh/MyiAQfhMTDSBFGiER/iDVdiECOFOFPVPCLWF8dSFXlhR
+DBWGeQGGZFiGY3iGdGFRGDVTP7VRNvWGJBWHcghUbliHnkGHeFgaeriHeShUEeiELFiEJJiDVxiF
+/iOIg4YoiIPIiC6IhT4IiUkohey2hOoniUxIhStohZuIiE8ITp+YSpbIgCdYiIpoijrIiZFYaomY
+ipiIR5q4igo4ikKoipPYioRIbbQIhbF4i6HIX0O4iJ3Yi5kojLKoi404jMboi7sIioGojKcYjbko
+jYfIir/ITpTYdNloEUvmccn4S9vIjeFYitToiK9Iis94jK5IjLC4jMWIjLb4juUIjfOojjxoEXM2
+ENJnd9r4M3Gmj9M3hRORj5unJtc3kP9YkOlTiQfzZJICJcImjhmxjwJBkAwZjF/nJ9gyC3g2LN+X
+jhSnkYAnaHbyfDUYkpdWkYWjerCHEaImEJzi/ikRCZIHwZF59iWZpm0SeRE26ZGf8JICOYusVxBr
+R5O1tzyTc5IJAWzCkpRKeZSbByrL0o9M4y6BF5Rz13e3d4+PWC63tpXeOJQDkW1YGRHmIjTtsm5P
+2XjYkjxF2ZUVASsaV3Jw6ZVwApZhWZdmeWuvBxFedm7rUzAFN3k7uSiqgzEmWZhTpmwQcZbDNzJd
+Fn+nxyt1MpcVgSl9Fnk0g5eIBIKBWSspNxGPBphxeWsVR5fWaJiAdwBBM5N19Wf3ljrL85b1lXB8
+ojGWWRHGkmX/Y3CcCY5riW+qw5IUkWtOd2u0mZpDSThqmVqs1nFLeWtOCRE3A1sZAXZXaRHx/jIv
+WsKSv8l/5NiYBSN5GlFuAtNuGad5PnmRn7l5X/Kdl5hJDuMQKYM9/rIHFZMR5Nl6IhA0OjkRHDM+
+GLGfAwGf8SmU0Yc+V7J7iSkRK9MyDUkmVyJ8C0mVFuF9WAJA7XOQAzFw26egn0B3/0kRPPNE5VJ9
+ZFIo3eOaE1E0RxOXKNolFHAJIMqenqgSQzd1V5M1SMc1X4OOJoE2U0c1Vfc2MheAG5GjN9c2fOM3
+Pbo1SocRStpyibM4jfOkRwA5vIigJ9F2hRc6cldtE0dh2Qg7slN4nXN4uIN215YRXup2xROmKPGm
+zgM90vNmTzOmfWSUKxE+AlpG7eWMJ/FK/lxJEJaHp33KP6G3E69AQB5UPYGKjcGJEjQkQZDKjChB
+qHk5ZRz0qC9BQiP0BCF0QHoqYp5pE+kncZEqqJnqS8opEONHfr/SjXY0q/OxY8FJq7Wwf6RZTKvK
+qq2adXlpfzLBq7rqe1XUqwWBq7k6jqXIrC35Ra6Ke/Eoj0eGqXq5jtdKjyWhqQdaj+oIrc3agOIa
+rS7hrcoKrtjqq+b4qkZWruZ6rtPamdcoqehWqvbKp7UIr/Eqr8KamdpKgvwannZGVQOrmC+hqcf6
+rTB4sPq6sATmsJPqEYQKsem6gRKLkdSqE7mkTvhai5M0rwA7jTYxTOyqrgxLTcvkGhk7/rEfMUoW
+O5k4UU3X9LHA+hBaqIZ0IQhkUE9YIFH5pLNwYYZCKxaKsAWNwE9pWLRrQbRMqxaCgAL+BLRPmxZs
+SBEZ5YehQQIeUAEGMAE9pbV5eIdiqxgbcAQqMAIdYAGE0Ydlexlu+7aTQQIQMBg85VNyKxlB5bIl
+sVm1sF3NOBKR9Qd4sARnkAg54KwaWxNZAAOA0LLjWlVG5QnJ9Y0qcVdOBVVSFbhdmgVXZbNAmq0x
+0VW1FWP/yq0uYVYUlFanW4034VZwNRBzhYqFahOYm1eM5Vfs2LlHFrMWi1hJtVh8pbsoO7IxEVmT
+VVmnVa0o4bedpbiiKxOiRVqmhaiu/guPqsVarmWdlqsSs0VLYFWvI5FbuxWbtFuw7yVcxtuuM3Fc
+mVS5zGtj6uu7p7pc00a/ybRMAwG43asS9oW/BMsSDwbAOaFeRcRe/YsS/kXAiyvA03axJIsekBvA
+DlxdDBy9NvbAEHy9LTLBDVzB9wW9N/rBCqzBG8y+K+LBI2y/AHfBK+xgJnzCqHuEKsylMFFiIuyu
+OgzCm+qOL1TDG3vDMezCO+y/Mby+M+yIQIy+MAydMlu8MjwSnJbDNoyAS0yvKXbETxywQYyQFrdl
+qElsyEFlS5eQYtagD/EoHWKRtQBAH5kQfxmfrJSPFOqQ/ZqgXWI2FLlnWvzE1nsQ/ntsZahZxF0c
+EUApEIuWfBxXxbD5aSIJk4oMEYeWaC75yIiMxnuWcAeqSYdcoJFcxRDRkwgjym8cY338xJ52PR05
+yiRJoAj7wnY5EKRiayUXb0/8nA3xdINMnbFmvrq3kcJiER76xOnGlyNKwmXsPrQpxt9xbNqndn0X
+lYJHwcApegUTbpNmy1sMSfO5bBkXo80pEdxmbkPJKNwCAMfMEOXGeEZUqiljoFGcy7aXfPEGHfRm
+b7I5liKQzrAMynt5lwznOtq8zQIxzMK5PKfpaxB3f78MJ24ZzROx0Kqaz1uCyRjsEK/Xl7J7yusL
+ciKXEL0ymGVZuxMRLUCndQYh/nVDWqSHc6RQSZQQbUc6+nI7h6VHEKWQ7NBDo2lTenNGZ9M3jXmq
+k5z9PBGh2caYrNJL+nIwd3XCetRtXMqETNIN/ZDoAwD8KBCEh6ahoKbOw6YvTRBFSae483Zx58QU
+/SyXIxBk7Tx692vDadEXvRAsSZwFsdV459XCk3iLF5LTTNTYO9UP8c6fLNiH6s1w4gWpx6JM5Hmm
+15610DqFjRCl5z/HKWes6XcV4cqubKMGIXu093O+qZ6c98qCzRAY6sm77M+/56kGgaHOR5gVYXyt
+S3A1yj7hzBCxqh+pbdembZYxmjGiENxy7c+1kH2MWRAMCgtjUqF3fNooHKsu/lF+53cT6YfE9piL
+7gd/SVzNM0KsMJF/VFwQvJqyHBywAHjeTLy7IMveW3q+KFzI8N3d2R3fXBzBPezDoXuO7a3f/R3Y
+/v3eUCzg963e+T3f9W3fBq7gDI7FnJuvCfzfA36zxo3f9L2uAU7gC+7dEa7hG47hGS6KyJzgJF7i
+1mrhJm7eH37iK96OCA7iAP7iLN7gKe7iBX7gEy7i8evhNA7j8p3jwLjjFC7jNr4QOVu1buG0SD4W
+Sr7kYtHkTq60Ua4WUD7lXHG1E5G1eZsZcbvljNHlXr4YYB7miDHmZH4YZn7mbQuII+7jKF7jEn7j
+F67iPT7jc77f7j3kPy7n/nAe5y1e5H8ez24e6H5e53Y+6DjO54hu6Hge4kFe1EAO4UKu4/zN4xw+
+6Y+e55Su6Zle4YSu54p+6Ive5zFL0Ize6JEu6e5d6kTs6KrO6a/u6adu6X0O6m8u6nR+54U+67b+
+6Zsu67pO66M+7MQO6Il+68bO679O5Ki+58je7KGe7MHe6w5+E3F8rF62ZHGM3dglmab+Etk+3s5+
+7A2xx5EtAlK9aZrcIRR5xrINZbY6kXbsxqstu5rM7R+ax3Wcx6K57koSyAaZKvGOPA4pyCO93hFB
+ynCSyPWOEMaJJAoPzwVNBSbLk6v8JVAdEcOsHwq/dZN9EA9vZhcfoivJ/tgOMS0Vj48jH5PDYvLA
+Dp4agS+z/PEJYZ7qMikSLxCs0ANMwHj+6AhTaRHrLOhw5j4aDRE2zxGTkp0XsfM9X5WOoCzB/Nwv
+n8/YTPMK8aAM/ZnqpjR2cO9cvy0LZBESzT0FA89a/zJoGdPc+PUm+pkPndvQfekXcScL13D61tNU
+WtNYitM/p20JbRB6/zY516RA7fcCcSdxzzBDKjU/bdOI//cVLduDnzdX0zeHrxCahpjvnkkr7TaG
+D/kI0SshEwCQaaFtrhB2c9Ku09bCA6Zo/RBQvXauXzt2cNYXYTcyo2m1Tztv3ZtkRvtcvTmwf50a
+8ztCM81szdW2g/uV/maSgD3u1V5pUgkldeco4vMx1xmR0b8QMvAFj039lqLW/VkRlf3tjvw9GQ+g
+2Q9uQ8OcGvH94V8Rdj2dqY/vo5+YBlqpSkKgio3IACGgVS2CBQ0eRFiQUhEwrxI+hOiFQqyCtETQ
+qVWKwCeIHWtRenLIYa0XgDyeJCiRYsFZBzCi9AjykAyTMDuqLJgpAEeNHG1CXNjw50OcB1vaGAqx
+ZNKCS5kaLDUAwFQAEwn2fErQU5c6qEjWzJpRKlUKosZaDbu1zg2wWaNSrRrrLQBHTNV6bdr26dyp
+EwsJDFvr7tfAYuH6pVo3sFq2hflWdXVgKtLCBJ0yvVxZs0FUYzzl/t0cmrNnwqIrd/58MLPpwKhB
+sw7tejVszbNt2qZdGHfurLt5P/X9e2hw4T+JF0d5/KFy5B6ZN1+uF3rS59NVS7d+G3v2k9UNeude
+Orz28cO3l08Inrt66+zZtz+P/rp8mO+h278fn75l/R3xN/+vuAAF7I++AYU7kDf3CjSQQfQSVNDB
+8iDMjULYFtyvOwnHs/DCDcPrkLUQRcMwQ/8+XA/FFE1USsXsRgytRBbTc3E6GGOsMb8Zo9sRIRl7
+fA1I/oT8LkcAjTySyCGBQxK5G2trkkAlxSPyycp+FNJK3aJEkMsIp6QSSCzF9LLCMs2cUsst03RR
+zcDc7O1M2uBksRJMOjFz8QQsLOGzTz//BDRQQQcldFAN9iw0UUUXTfRQRh+F9FFHI6W00j8ntTRT
+SjHVtFNFNeAjKzciqKBUU09FNVVVV2W1VVYfINVVWWelVVZYa8U1V1xv1bVXX1Hl9Vdhew12WGNn
+feARMJdltllnn4U2WmmnpbZaa6/FNlttt+W2W2+/BTdcccclt1xzz0U3XXXXZbddd9+FN15556W3
+XnvvxTdfffflt19//+03IAA7
diff --git a/Documentation/DocBook/media/pipeline.png.b64 b/Documentation/DocBook/media/pipeline.png.b64
new file mode 100644 (file)
index 0000000..97d9ac0
--- /dev/null
@@ -0,0 +1,213 @@
+iVBORw0KGgoAAAANSUhEUgAAAlgAAAEcCAMAAAAsmToJAAAAAXNSR0IArs4c6QAAAwBQTFRFAAEA
+EAEBAwUBCgMBCAUKAgkMHQIDCwYXFQYDBgkVDwgFCAsHChASJwkDFA4NEg4TDhANHgwHDg8aExAG
+DBEjBBUZERMQCBNRDxU0ExcZFRgVFRcgCRkzHBcUDRdCNRELIxYTAx4mLBUMEBwcEhsiDxwhExsu
+Dh8XJRkQByAtDCMUHx4bACk0DSsiGScsFCRcJSUiGSZCDiwqGCg1LyQbIycpVhsPDy0wNyQVECxA
+PSIfCS84ADJCEStWRiIULSwpADdHCDkgEy1/BjorEjhADDhXCzZvITNPUysQDzs8MjIvCj04BT1O
+PDEoQjEhMDU3LzY9KTdFTTMYNzk2GD6PAEpfEUVjBExFCEpPB1ArK0FjKEVZYTscdDYXG0d5SkA5
+FEiJQUNAOURPAFhCA1RpP0ZJVEMvYUAyBFtRWkYnDlR+QEleAF1jkTojHlV1AGB4PlN5YU87cUws
+SVRXAGaBWVJKUlRRRVZlAG1PWFNSBGt5AmqVAG+NAHNpK17BWl9ifFs9KWmnSGZ0YGFfp1IuCnWj
+AHuKbWBXoVNAdGBPDniWAHujTWmLk14rAH+ch19XX2aRX2t8AIeLiWgvAIeeAIaqa21rOnehdW1m
+AImspWJYj2tLW3C0AIyvWXaNAo6xb3Z5dXZzent4WIKiQojAen+CkX1pcoSWcYDOoH9fp4E+Y4ur
+hoWCXIvGb4mut3xpqYNYnYdUO5rDyXxdjY6LYJqk0IRGb5azXZnMjJGUgJWqpJB8l5aUyJN4kKK1
+rZ6IYqzge6Xho6GdnaWpgqy6yZ9zvaR0hqzMk6rN5Jxxw6mF26lbq7C2pLTGwrCbs7Owvb+8zcGc
+8rp42L2xsMbY3L+jtMfsz8W2nM/yx8jH0MfA7MWU78h/3crIyNTo4NLD6dK1z9bc1dbT3NXOv9vr
+/OKSwur8++Gw4uTh0ef78uPU+OPL3Ojz++bGyfH36evo/+3b6vT88vPw/feu1/v+//bb//nK/PnW
+5f/+//ro+fv49/7///37//71//3//v/8sZeTnQAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAFY4AABWO
+AUTUBDsAAAAHdElNRQfaCRQPAiJBEFMLAAAgAElEQVR42u2dD3wU5bX300nWws50shA4lyTGikRE
+Qy0aUChKvJZqTQGBFNurVo0FWq2VqhAq0hc0t1rAxtLLpu61cUl6gWtNe3vb7Z9IKm+Xqn2tkFih
+GmwFA9Xwpw1s/UOyCc97zvPM7L/sbjabXTLZPL/PhzA7O7M7s893zjnPmec5k8WkpNKgLPkTSEmw
+pCRYVlSjp5n/3+3xGGsONHt2vx1t04PNTbtP8aUujxAuHvN6XjHe721pbmqLsp/H021+crP5wce8
+Ta8Evi+wKMHKHKkwjf/vA+D/77SrAKDeeTRiO3/vcnzDoTzXgy/+CEKMbVdw5dh9tMGubAfuuMjf
+E7HnfgAf/X9yJn6Aupqv206fNfYdXHr/Aloc944EK7PBWg9QurVxlQ3s70Vs+FmAdQ0LAP6By1cA
+KCT2AsBqXKme7mEfajBr25MaTIjkSjPA0mHsVnz/G8jgzyBna4MGH/UzdgHYt9ZrMNovwcpksN4E
+eJpeHbLB5PDtelT4L/wP4Fr+95NirQa34d85cB1jX3eAsGVhiPRuR644WPjOafxgHXw9uD8axL/k
+3+gj3P4vLgJ0SrAyGaxzoFCsfpObJh8aJVMtzUSMA3JZTw/Ab8RKYcD+Rvu2ehsJJIBu9llFwdW3
+0l8N1B0CrDlgpz1K4OfIkRqgT4cOjNkkWBkLFiM4ejT4nXjVrcH/wb9G4BUUwOcZ+xCgtkh74Ci9
+9Iu1Jig/BjhDhmzCGUTzccaKNx9lAqwSUAVY17Kvw7U7S2wLn6fXRXCzn90P2dIVZhxYIlxSiCE0
+W+8F1l+GYDU0hG99P9/gVxiEKxiGvYPMoCMjT2a8fxyRQkQw9HpJg3EBGAmsr4PDz8Eaxz4F+UBf
++DjtMZ0WJ/9ZBu8ZDlZwfX7fjTG0x9ibPTF93D52UEdELgD9LXYw19zteA7onMwLAHuI74SB9QGG
+b372DKAvLQF4xN/7FPlR/17gjD3H/BKszHWFYRbr6siEA7sL4Jbga4zG2Yd2sCuqaoC1H63YS3wJ
+nSW3RyFgsQ0coQLsNn4KdD/3gtcauG0HOCItVgYH78EYq4fHWOFaDLA6tMNHe3St0m0L3+Ixln+/
+BqP3ib0xGue2LRQstmu+vXjz13mMZYRbubhoFw7yXyRYmdwrHMN7hR/fgVGSdrovVzvEUpuXYPhn
+wG9+wJcOaTDZ3GcOpU/fiACLmb3CP5o0ncemCcamQY4EK+PzWD3zYayNYvcwYUj0UiCldTf+9yXQ
+2RNlKl+6Aw2YLRCtU/D+uBZgxQDr9iIkrauIeo067OOu8Cfs38Fxgi9+XoKVyWCx+wBKG5t1tDfU
+9ME81hlybtki3U59w9XNuOVL/r+IJbu/58yXwOgGdPd0aXAuwXU384eAdT7YtzXqPPO+HuybPRdA
+9hnW5YDR2zz41ntnJFiZDBbbbnfQvUI7OBaF5bF+ZdwehALCj+4n2n9qLDkK/8zxMdSNjlA/3UP4
+vRFqsf4+xhG4V8h3G0sB+/4ptJjzB5luyDDV1otUVXd9vbGmpXFr09td96mXha5kT9Yb4psfbKxv
+EgMdDjZuE2MTzPfru/9eX/8HsabWeMcY3eBtaHrL+LiDjVt3B75v224/k2CNFL3+D/kbSLCkJFhS
+EiwpKQmWlARLSoIlJSXBkpJgSUmwpKQkWFISLCkJlpSUBEtKgiUlwZKSkmBJSbCkJFhSUhIsKQmW
+leRP28f50/H5EizLSlHEDC9jCuGxJ6crtoU7TkVjxJxkuGu+XVvNp9t0bS9SFu4Ra1+/PTt/c+R+
+uFLbfMJYtNvMbRk7nq34JFiZrPB5hYdsoKqqA9Sjfbm61ZhkOAdwG1D3IVd2WhJFGp4CB+6Xw8Iq
+kD6j0QbZR3D3F/he8CPjHT1s3r0EK8PB6rHBLARmby7kRm538i4QYP2Jag4dmwkOKkU69gjbqcEb
+rOddgD1sL8DDofu8D/C4/9gCyPHTrNVZp3oXixpZjCCVYI0gsHy8Tihjf1Rt+Le7pSWw2U4bjBZg
+faUEkRJ1QETZte8ShefDT3CxtukV1tXSQm6yBXf+d7Nc0T9o2/d4SUjCyf8iTJZgjTCwng2+FVKG
+janqMn9o3UgDLOKmy1g83NrKQ6zzwc493+/YFFFKpoAqIuk03/5dmoCP1g/00xKsjAerpIWLYzMK
+oDTw9ACfqgY2w7A8rCDpHEETzZb+kPgCeIpqAz7HOD0PI2yXMfYpUcS2gGosLwf7bq8G1zNuwn7D
+JFgZD1ZAFBWdTxVBcjZHezJFKFhPAfyQwLqDu0LOGCysmi8qHS0G+Dg6wR4qJHKCVy4ajWtn0lec
+SzvfDzczCVbmg1VQxWVgs2E6oaY/HgcsP3FVKvB6pGUDCLCu53aMB+eE0E9E3y9ntxet4Gh6a/QD
+q3Qi62UYyyRYIyzdwPt/O2/Xg+X4+oJF1bNhEV/k1YgWCVdIXvGfIupCS6Xz9/8+xQGQOwddoXh8
+ABqv/8JNf9/a2goQ0jWQYGU2WH7W0cbJ6dL6lLYNsVi3AnzNWHfwyXV7WDCOZyI4p7ptRvW/XdVb
+T8/B4P1TZtnRccFCWqoEa6RYrCvUfHPt5JhgfTeQ5uxobz1DVd7HElH0rIq/cb5wAx3yCLTDbf4z
+It1gxPElMAE7mCQqFS/BGilgIRiXdeDyTkoWsO7W1ihgvYkheCuJPz7nBDumUTbrV5D3NvOdT2VI
+j2O8hRudxz/8YT97EXL9fnSFz/nZq4FnpbA+z7yQYGVyjLXcAXb+MIFFEXmsIFi5gU6kv0tFs6OK
+eGsBf1iF9g9yhLnMz0vh+u/npd3VN/j7/EEBpWcCYMngPaOlqCWhSatd84tUteDGHZF5LAKLv+xR
+TeGLQ/N1dcZm8faGEjV/4VF0hCoHaaaqnOIrtYXivuP2MlBnBOvEq6oESyq+QobC9ER7vydyq5Eq
+CZaUBEtKgiUlwZJKnyqmlXRLsKRSrhJlBI5KlmClX+USLKl0qFKCJZUO1UqwpNKhZkVtl2BJpVzt
+qtIswZJKvRSlUoIllQ6wFAmWVOqlKkq3BEsq5apWyzokWFIpV4eiVEiwpNISZHVLsKRSrlpFaZBg
+SaVeoCidEiyplKthZGYcJFhpV4FSPgIHZUmw0q8KtFkdEiypVKsbwVIafBIsqVSrhNCq7ZBgSaU8
+gie2ytq6JVhSqVWVSlZLbeiUYEmlVp4ChexWebsESyq16qzgZmtahwRLKg1mSylvlGBJpVotQLGW
+T4IllXKrpYyAjKkEaygEmU+WBGtINE3J9AmHEqwhIwskWFKpV4mi1EuwpFIvJbMHAEqwhkrNme0M
++4Dl6+w4++rs7EnT+Q3R6SRysxm7hu3D5HQGC1Z3x7Kc8RNnX2XIds1VadXU8ebS7Ik2W+pHlfja
+Z+RMnBg4CVt6z+YqW+CHmzrRNr6x39PpUJQBPQjF10anY37HNek+nYkXm42Dp6N5O5MHy9eQs8Lt
+CqpufOirNGjtNaGv3POyWlOJVWeVbW3YCUysS+/pTHWGnc5VOYf7OcKCgSSzOm8cXxN6Au7x6T0b
+15IVoSy4LtYOJwlWs80Z/slnGSxaYUuZ1equ7XP0Zxcs1NJ+TqdNUaoSPZ2qyKM/u2DxCz/flwRY
+3fkrIz/57IPlqrumKjVcdUReJUMBlqtuam3co0y4sENn39M562DRV3oHDFZ7Tl+IhgAsl6smPxWD
+LFuiQXT2wXK5NtrinU5VGbQlcjreiX0/eQjAQhtcNUCwWi+OwtCQgOVy2gbPlWdetK8bCrBc7nh3
+broVpTyB09m6xGURsFxrywcE1oGov/nQgOVyOgadIVrisgxYSFb3IH1h41KXZcBybawcAFi+0VEJ
+GiKwXM6iwXHVNs9lIbCQrNiHWpFA9r09+q80RGC5VtYmDlZBdICGCizX2nWDSjPE+sWHCCyXszrm
+sbYqiqe/89FclgLLNa8lUbDqV7qsBZZr9mACeJvbYmC55nbEuWFY0s/pFNVYDCy3LUGwfBe7rAaW
+syR5rg6sdFkNLFdsZ+io6KesQ3uM5h06sFw1tYmB9aDTcmC5ViQ9Rao7x2U9sNYeiHW40/ob76e7
+LAeW62JfQmDFMlhDCZZzWrJgHV5pQbBim6zGfu7qdC+1IFg1iUwyyvKstCBYrquSBSvfZUWwlsS6
+xtv7id5vrLEgWHUTEwGr3G1FsNY2JTmgYbwlwaqrjToEprMdu4UFFQWxx89oLguC5Zp3IAGwprqs
+CFZNeXJgdaywJFiurOiDkwOKZdGWWBKstZ4EwFpiSbBcSSZJm93WBCvaLcP2ELBi5bnWWhIs94PD
+F6z85MCqqrMmWBdGM0mOAFexplU0bLQmWAn4k6yl1gRrYnJgLbMoWHN90buEhmL1DGstCtalIw6s
+iuEEFus3xFpnUbAulGBZGqwyg6uY4zkkWBKsZMDqNMDySLAkWKkEixcHiTdxVYIlwUoKrGYBVrcE
+S4KVUrBE+B77xqgES4KVHFj00ArFK8GSYKUYLF/cEEuCJcFKEiwevndLsCRYqQbLqyhx5r1IsCRY
+SYKF4XurBEuClXqwKuONTZZgSbCSBYvFe/yqBEuClTRYtRIsCVY6wGISLAmWBEuCJcGSYEmwMhGs
+JRIslFM3phzrOsQ54keHCViz9VFiI11fGe901kiLlW6wwOBJh/zYW10EwwUs0A2wIA5Yn4AVEixL
+gAUZBRa+KcE662A5UeZ7xrITN3I6hydYEafD/yewnBKsswqW8xOA0jfRms/RItxM9oo0HMF6lB95
+qVO4c+PM5vKVKyRYaQeLWyYOVo0uIIK7Xa5vGosPDTew6GwEWF8Vp6MjTuKK4WRJsM4SWKYQrEkA
+ZKwuIYwESxcu2TS8YqyAVrrcAJNx3RaACUZc9f1S8oEyxjrbYNUA3GEE658nyAqXOodd8B4C1hf0
+vG/Tyq/i/25yiStl8D40MVbIi0K60Emzhm+vcK7xoo5e3CA84b0SrKEBy2m8GId/vxgIroY3WFt4
+wPXo5fxs7pVgnX2wTFdYQ66Qa+MlwxgsdIWbTFco3l5TALl11gJr49xJ+Zfem+nphgIRvF9EXUWA
+q3HxWwZYzmEIVmjwjl1BKrl1OYyzFliXGB3Xh1IOVs0NULppoGD54oK1ZlL+TcmBZYby+sO8a8g1
+ziUyWYmCNQlqBgpWd1ywHr08/xpnUnksI91AOQZ3gVii1RTI5z2UIFg3wNI0gvUFgM9sqrkHD6wu
+xWBR5kindhwQWNOUKl9MsP7VyB0klXkX6Z6QBOksc22CYH0ZBg4WKNXdMcH6ajBlO/AEKcdpFh3f
+lot0I8Ry8UB+ZWJg3aOnE6y6POCPqXlUh9tSDNZFUOz8NBS6BwoWKoytIFiI6t14oNclBlYqFAoW
+IZgEWKgwtoJgoXn5TE0BfDIxsFKhULC+gDSmEyxdXLimq9ENr1in67xTXhxYC6V1Bueom/iuOl5y
+t8UC69FR8DDyqn87CbDC2AqC9W90OP8Gk4YELPScyYIVxlYQrG9SBP5lXXcOAVho9wrTChZ6F714
+ZRhXSNbdBJzQVdyaBVzHp43VpS6xSaQDDYK1ln6xLaH2ZUBgBdkKgnURXEgxd27dkIB1t2sQYAXZ
+CoJ1Azm37+uwaUjA+ow7ra6Qmp74mOcMmq8vQK4bF9H5110CY92uFaDjXl+dh32PFWi9hdm6jbbW
+H6qJ6QrX8r1CDeLEhgQU0hIGW0GwdAKrJhTmszuCNBys2fUJnI4adjrEVhCsKwks/BU3DokrdKUZ
+LIxkddMerRFm+fuj4A4836uIIKIDadJu4ZcVgja5Tti5c4m90jgxlgnW7CAFSjKq6gMWWAOsS5M6
+neogWJcSWO7MBQvbiiei5xFBhm5Caua6XIaxKuC92eJNLmMtIiiM2uwEwJo1OLCmtVvVYiUFVmXn
+yLFYwiNehE5vBeUHuOaGgeW6h/dt9W8PEKw+MVZ3vwqNsYgq68RYfcCa60vgdCCcKtbHFQ5RjJV2
+sJaCkWnCBfeaYA8lHCye7dRhXogrnFwXoCxGr1AfVK/QoCpar7DYZRGwBhS8V3b27RXqQ9Yr7B+s
+jsGB9X262y9uDlxWh/ZlFrbUo6VLnSFg1WFHG/faMgrj9jV83GUgeI8Hlisv+TxWkKrwPBbEymPp
+ISOv+tOWgn43ASMZmTKwKjti5rH08/rJY9WJzO7Fse8uzU00uz0QsMpaB515N8YifttMUgHkhoIV
+SEKQC7oE9JB0Q1ywRJbiNtfAwZrW3h098/7pWJl33XTi/YPljH/bmSs/pWBVdsTIvFOO0ribHBus
+uov4uYWl6Psm5VMPVr3SOLgYy8CmeFPwRbEz3BWKtYWbAglS/SZX/2Ald69wWjhVCd4r1EOzpmkD
+S9cHDJajsiPuvUK4qr97hV8QRIVb6tSApccDq7Vv+biBBu/OkPkewQkf5n9ha8OWnVHmtwx6dEN3
+UqMbQsCqyZ90zyTRFf3ipPzZnGy0clvmTip9iC+izSO79uiVBcaYjnxw3TPpwltMdC9cEgusCAd0
+dkY3mPcIL9dzuSOnkxK3mddcWZA/9aEgWFvmFly4xEDm0UmznP3dhA7/7gv7lo9THN0jfTxWKFim
+uzScfDF/W7y42ozGzFvSfMyMGZ/R3gVmZGAZsG7g8z8CSUdxeDRmRozug3NNsIzzXcvBmgR5mwYJ
+VjkFh+0SrFCw9E/y4VaFaylDV8xpKtxIMR+a2Ro+k/DLGDg715iDSOGmGgzfruW4Xc9XWwesOqLl
+QmO83Fd1KN1Y8zli7Vu6fq9z4yQaJcPBwrdmbdp4ER9IQxHZeXWDBKuWdzuaRzpYgU4hgkPjBWqM
+7u73aaSMDvS83G9yjJwGTNfxZbrhLpb58CyA8wSb1gHLmEEIGh6p8xJ+fM4r521y1XzxXpcxNpnA
+cn6Cj17EUP9eAuu8/mOs/sBqNe58jHSwzE5hjRhz5TSGXrnoRxYjsraEgeUU/bxP0p9NZorB2MlS
+YGEwdZHRwXZHDrZaczkYYLmN+YRz4bw6BOvewYNlPiGvRLpC0xWGdf4IKmMudBhYhgpNyAywnBYE
+ixz4F3XI+3ZY3Qa6HUJpCAOsQCpvVF3MAcoDA8t8Ql7gaQgSrOgWKxwspyFzPoVVLdaauWvNVPZa
+d8g0588BxlhiXrRpscwzShFYtYG7Bi0SrABYGGNNDomx+oJ1XUjeMwSsqy0GlrsAxvKFbyFYGGNN
+EIHUBMMrfisQY10iDt1IfaYCrNbgXc5aCZYJFvX7Jm+iXmGhKxKsux+l0fPXO7d8EfKvDgPrX83O
+oqXSDYUr+QCUUS7R9auhwArByuWnhwwFe4Wue4KT7gcNFgu5f14uwTLBMge7FrrCweKBvlGhxZyo
+E7RSYvVtVoqxPgGBCTmBPNb15tLkAozTRR7LeCt3U8rAKguC1T5SwQreJKwxK0TiVT5J55lpfJvW
+GbUjt1yuz+aZd9BmG+8Gt3GtmaSXbnLpVgret+B55M9+SBzKlhsgV9xOoCNd6/qEPoGqSNaJt/RL
+HxKZ95SAVRvuCeVM6NRpZBe3NYMsn5xiL8FKJVgs1A9KsCRYKQMLg6xpXkWpl2BJsFIKVi09H09R
+CiRYEqyUgtVBw2YqFaVj2IJVKcFyWfXJFM2K4hmuYHWoEizLguUz0qPDEawyRYJlWbBoGkL38ASr
+Q1HaJFiWBavBvAs97MAqD/ZoJVjWA6tNUaqHJVgdNONLgmXdx8opijoswaJR+yDBsi5YZsJhmIHV
+wW8bSLCsC5bHmFMxzMCqCBv+KsGyHljtxpSK4QWWMFhh04wkWNYCywyyhhdYFUbZDAmWdcEygqxh
+BVZnn0lGEizLgYVBlne4gWUYLEWVYFkXrHaRyRpOYHUGRlVLsKwLFgZZZRYGa3x0722oNdZJLbMo
+WLMzC6wZ/VQtI7CWWBOs/HgGyxyw31cPuq0J1vjkwGq0KFjl8Q66mo9PzppnTbCmxzNYsW/qtFnU
+YuUkN26xc601waqPd9Beng/Kml1nRbBqlvWtsuapClTYj3lTp3OpNcGakRxY7BpLgrXCy/qN3rNi
+O4+hBGtljKExtXjQVY7Y0Xu3zZpgtSQJlm5JsK7qZPGj9woEy7vUimCNj8GN6BF2x45YKtxWBGui
+L0mwqjZaECx3fvyDBsoHZbHxddYDa2NF9ENuDYx8jTkOcK4FwaorYMlqqgXBWtEc/5gr6erPYo0r
+rAfW1JhGVunv2tfc1gNrbmfSYE2rsRxYbls/x1xL3cIsxmLxM3RgbVwW02CV9NuRutJyYLnLWfKa
+aDmwlnr7OeRmuqmDYLXMsxpYWuwIq/9rv95pNbBs3YMAq3ajxcByl/V3yHj9NxBYrHqltcC6qj2G
+7y5XKhJoCsVtLbDmtrPBSK+xFFju/i8Tnm/I4jOqaqwE1opt0Y+3Je6g5JC5bTluK4G1opENTjZL
+gTW1td8D7qZ8AweL5TutA9bKZTGvg3gTv0J7hqPd1gFrRfUguWL+8RYC65rdifgMDIUFWKxko1XA
+WrouNleJtlFnVG84JGDNa2CDls9mFbDcF7+SyAFTIivLzMQtsQRYdeO9MQNCpXIATbHWEmC5x7ey
+FMinbbQEWHVKYuFiuaIEwGItORYAa60tRpqqakBcoZr6HvzZB2tFTgdLjWonuoccLPe8GxPs3lYq
+SndW8LJYN945pGDVrc2KYa7aoCDOUJkY7vDGqe4hBcu9IquNpUydkyJGC5xtsNxLshLu3aIZ6MwK
+Pfgm29SN7qDG/9ydVm28JuTFivHj26JfEB0l2B1UBu5TOmpzZteEfMPE9J6Ne6or5MXS8eMPs5Sq
+Y5ntGudZPJ0lK4LLdUtslw4gaVKtKB1ZEUd/eOvCS01pl6ZZ+ebC3GVN7TFSn94CGidTltxd3I7D
+62688mydTsjnL/O2d7LUq+PAA5eetdaZdKG5dOMDLe0DyvHSPZ0sZmV5y8IrpkoNC9VbGqz2anSB
+NLSvoE021fBSg6K0WROs1uoCY6xoWUOHbCgJVirUVlUgLBWG7M2SquEoC8ZYLWXGuPYSpT4t8a/U
+WVCUXuHQqkpV+FOrobHdJ5tnWIPVaSGwqvjseaVaQjXchS3pswxYbdwH1sugKgNUEXqvcIjlAap7
+JW1VRqjEOmB5MFwvl1hliGiqujXAokExHtkgmQNWpTXA6lQKlGbZHpmijsCYdwsEe9WyPTJGLYrS
+aAmwOhKcJSE1PNRIjz2xAlhV5YpXNkfmqIrK21oALF/ch5hIDTuBqN1ghS6hjLAySD5RxmjoD6Q2
+8LhXqUyQl2J3K4BVEO/hOFLDTtV8YvHQg9WtqOWyNTJIojje0IPV2W8xNanhpLYy/pSmoQfLfFyU
+VMZ4whargFUrmyPTPKEFwGqjMl1SGdQnrLYGWL7WVpltyByVG7NAs+RPIZVa/yNuo0iwpFKpShG6
+JwCWP4FPC27TM9AD6Ym+m182UUp0tn9HNFhGTftIsDyqkQZXVPEknu3zdVWbsbnvIR+7vUjVFu4j
+Jj7MUkm054YiNX/ZUbFnma6WrO6740Gb+IpD+MkzdoiVG0rU/DtPibWAn3B6xCNRFmwIUbniNfy9
+HTOWnYqGz1Pmxo9NdzhmPE1LO8t0rWQ1geXfH/JDB/puqiGyLxum68Ze2BB2beGJnqSP2jRYfcEC
+83yA+mpd04FmOQAUHo3Y8KAOqmID/Q90zhqQVNY7Exy4tUYb36/hnhpcH/ndvVOAPyH1VTtk4/tf
+o1XT+WcVcupwUaPFkR4Emw3hAA7WBgf+MPjL5L7Ul6tDYGy8gFoL4BvM/4wDf13gv/5+vuj4Qdg+
+KhhCDhabezF2K7afTbRfMmpWppkDVfoBaw7kPO9jPXtzYHLEht+FcSeYbw5chsu7wNbWimIvQu4R
+5ltM53PcBt/zs72a43fh++2fAhysro/Aom6210bv/xhmdLL9NvWHjH0JinFRgx9KsMLAegbgEew8
+Hz4f7H3syU4wwPp/GjzP2FOQd5RdADf72c+0vLcYmwn3+tkL2qi3Qvdp5VoOE/zsTQ2ew720vD/j
+Vnl7mG8B3JZkBz+kMFB8sF7TdHGBYFP/lEKzqsDQ9NunP0BZC8jhkF0mVl4BtPLvNvt77ECFfhoN
+cRasY69WVf2ZsWMPVG1lbL4KYzlYf9X0dxgxtYx15ehv0Lm+3clYNizjX75MghUG1vlGY6O9vxr/
+q68KFs6cDo5csfH2+dl+P+tVoY3RP8b//tNGdCFev2QfPFBFrbihqlLEXm/qo470sGa+F277CrsL
+rsPVv9Wy30s21RAYABUfrP+A85iJzE18ZUSS/H9hHP49Bx7Y+WATIyyqxb7/bYTk7+fA91jvR8je
+fRZGY3ygaM+3cbBahUNshQlo3EazXdVbT9DrL0EpWjObtFjhYP0JHCeE2/sOjMKlSgiOCFFK9wVf
+4m/+Tw3eRouFru9Nsli/EJgsh2sZ+wrkveV/hlsoxmF7OriXDfagg/olo0U0XkmoUVEcLDZYjuoq
+VLWDwPo4PBIgaAKdQ8SQvJOj4BbGPrBxb134FvsYt1hdWfC4scHPwP4Gt3dPvyhsXpvfQOqvoNP5
+vgpj0XgVLnAAOOgsj+fAwqrpUCxjLHBU8YYAAus7kG108Dg2vC6xqbfDOUN6sk+xF2z6sgd53PSE
+2HUVNWDXGDj3Q53bPGGZToXu9Q4bA1TGvZeM18DVGlYhry9YATWQBdpqrBc+L0IY2tuPoMO0QfHu
+XWSW/gPGYn/uZQ0M/l6wwSLGY8J8HS41D4CDhTHYN/hFo7EDALk7WpaDg8h7ir46SoQ68sAKCFur
+IkiOg8CKzB6FgLUe4EcijgcYi+A8KN6rogb0v4DRP2QbUdocvqHQUxpZL7sgKimwOsLnhvYFS21t
+QbUqkWCN7vNRJ6eA/izFbIep8uwhjNNP5kBh1e06YGBF9vUZJI5fEyfRpuW+EwYWGjO0TWXAwdJ/
+YnrB+0Hb0XKfpv9UgmU0BJbt7hUAAAvPSURBVAfr9gTB6mH3YVfQTxfs2N0tMyHnRBhYgrdfi23f
+tI06Yu613gGz/ATW7mTBosA9dJRK/BjrioAr/HEg2gro2BSw/zokjZAFm9mhMQ5wzLoCAys8WrwK
+ik+ZfUhhukLAIuwge7M2Dl2h6udeMZcds+m/YRTbTZZghcZYQVf4N97TiwFWD4ZScIuf+of2oxyj
+O4KukDfgnzQ0WGKn++BfTK7uEnsZrrCLwq2BclUWMayuv+D9XAqH9jGMnh6J5KoIcvaF5dyA0qgH
+WtrYKP13wrpeb/wax5AhnvEKBYsda209cQBmoVfkYB1AsA6I9w6AJsEKBetvGFmh/3qeneERVEyL
+tRx0Ho+vMs2UzQze74LPi3hdJKy4J/ylsTty9XjIqn/mDDh471SVaeGPkowP1n4bueHP2m/ZzoPw
+sPhqCow10J9TcgsPmvTfdXqf9NNSDv7FaP0b5hUxEwp1yPf7Q8HyNnq4Kfsa682B33CjeC6F9PQ9
+f8SQXoIVmm6YQhmdX6jFe3X4AYsJ1nrIEx2+JwR+y9FMYdeKTNwF8HsRwY4FnduDDwJ9P1z5U9OI
+kVn7Hy17gLeC2qgGY/cAwMIj1Vef6L0PIz5+U6eq2hsSIy6sRlVRj1HfwY4tQPd1yIbo49LX0Bzl
+QC69X+2hcEr/DfYMbw6zWN+F/CNsly33HT++n7+H4U/2DdaVQ51LXFwowQoD600NFu5hL4MOY6nR
+G6qrooCFG43lv3n7u7nwtVNsu07x1AIoPYHNRR7wXR1uRotAeR/yliLqfTPX2KsNwy7HDnZwSqBT
+n3DCXVGmRVSC7wcsdp8GqupA+5m/2R+ax3rfZnRZcPNetK+qCqOPUOxNS6V+sj+GqsgRLqLrwnCG
+Aiw/kqerDpVHaYtpEQr93EbS92knJFjht3RetuMPw2/E3HkkIr8QeLnA/M3bKIClrSkWOa7TIv+h
+MZo/RVc/XeL/CdmnTUcYuLuznpobxp0a0KFWRnvQUVbfJJcBliJuQr/+WJGiPdAyBfLeCM1jeRVT
+9GpXmZK/mTqxPTunKzOa6Jo6x3y/qmuMMprWzFFs7xn5DhFi3We33WkEorumK8U7uP099mQRLp4a
+6VyxacGGEMmhY9vLsm0Ln7/LQb6wPHzKXIV4+RHzN8de+sFVevaM53lO9dgG3XYnub/1ikJ5nKcU
+Bd3ig+ZHBPYib7R3fnb+5u6B3IRudSjRxgAnPGxm552Jf5c/ua3kWJlE9PpMS111vHJslEc8yIF+
+UoNQgwLoBqOVYpRgSSWtRipIDC1R35NgSSWn7lpR5zpG5VgJllQyaq0UPbOYTw+RYEkNWG314sE0
+1XHm7UmwpAYkX3MlUkUpBk/c8ukSLKmE1d5YaT7ur7q/h0hKsKT6V2erp7qiIJATr27t/0m+Eiyp
+aGrxNjd7GmurqyrLSxziOX9Clc2JPUdZgiUVTaBECFeU17Yk/nBuCZZUNBWEMFVQUe1paRvgY0kl
+WFJRXSEfFt3W3pHsY24lWFJpkQRLSoIlJcGSkmBJSUmwpCRYUhIsKak0g9Vab0zwqq3nQ057vQ1b
+m96OuuvL9XySoZ+1NG7b7RcTO7z1TebErdcbt/WtAHAwuPJg49am4LQA39Z62RgRqq8X2UmP0SYH
+Guu3RS+q8O5WsQW2RQNuwtuCWiV2U9TWG2o3WlDs5e/11jeeSAdYEfMKt9tpTqFaGuW7juXwSYb+
+Y9NVAIe2B49rfx5ubeNzvHuX22i/8FqiYmXhW+Yi2AKVMReb8+6lAnKAGEgnSs3sn0KzCtXRf4iy
+5QLRav69OpWDKj7Rw96fSa0yms95vs/GV4btEVIq0r+3iO91BFvwNWpB5fG0g/WyBouamh+zw8V9
+djw5EzhYvRdA/jbPdBj9Hk1MLW3aYHM820OgFDY9aaPqWSFaD7lbPTMh30+Tox2rmxeICfWMV0KU
+YMUF630dxm1tbiwC+9tnIjdcr4lWw20ubmoEGOdH1OybPUU0PxV/dftWXDw3bHaduAuoQd4+KpqF
+exXBuNO0iC2oOX6fbrCuAF71+GUtL6KSKNuZBwKs12xU1eGkDb7HvstrxPyWivy9puHJsf+dsSh0
+n+M2eBZJ/Bh87wz7GE2O7rIZ5R0O2SRY/YD1HbATGb1TqDJfmF6badYg/Y5qP2HU8RtFk+vf1ahg
+5Bh4iTO3L5qlQ+P0Pzaaa/+uLW8PewJoavEGXmQvrWBlGzVmmprbOOWBQpFesD+icrA6W71i82qE
+ZR1dNlRR9Me8tB93f3OU0afRrimj/X8FlVzji8TUOXyDLF40mfk+kvusBCs+WBVGISNvM9XkDJ0J
+rUDpjaLV2luahZtrYzq0MlGN9C/aqKN+ciE/YF15Ctqt9/lf0lNU25YdNveiGqQPMdbzF9uod9IM
+1q2Qu/lEyBkEAuzdq98KK0iKJucniOE6sdkP0dT98LEi28I96PePU6mAn4H+UmjZUVxRfITt0kQN
+m8Xw+AEJVhSwOoNg/QrgzmAEHlq7YeHz4aUcXgC0WAvgslOiEsh/CiKpGhYV9HuWikKKNv1wlB60
+Yi9Q1eSP8zJGH+bk/SENYBlDvHipyIPZ6KJmrDNOyNPcGuamg2D1ziS/fgUPqdArbkbzS1Xewf4c
+vy7053gditc0HlL9GHLxstgAdkXTnhMBVilrk2BFActsCsJmOjaFtszoSHubPaFbhoJ1vIjs0MkF
+oCowDsF5DLJp9SpeknEBZG/XzKJF60OK6Z2cQnvpyVf0GxhY7OAC6rw5tOei7BoEqxej8F9TKObY
+wU4uB/SK2aA/z3z3UUjPus7BjyhGJ9h7Dsw4wfbmIEPYl8TvUeFOvx+tXf5pCVa/YPVu4D05ZXWU
+EhchYCFXo45QTw93duAl7g+UiqSm/ruOH2E4wt4xwcJ9yNWofURUiwBrd7rTDeiBPbdnO0B9Lg5Y
+vpmgPm3UKcSzKcLTGWUaLyqrvV8Dx0uUJTmETClU8IhgW3SKvf4R3OzkmFw8pXYJVnxXSL+z97E8
+ozRRTLAO6ZCNsfoHOmz2U52xl9BiKUGLRUXW7EdEzvG3WraZDTpWJKp+ptVihYPFj2Hv+dH6CSZY
+vinC5VFfcboyY88V8N/oFY2C7xR1vaoB/Jp/0LFVDu2BV7QJ9PiAf/A4fhzaKsgm4wVKhWQpTh5L
+6PBiyDsRGyzkitfvNAKr5RhYhcRYIq+jG2DdBXeYNOZBDjdeIsb6IMk674mDdWDVFNE92AW2mGCh
+FdVCe7JdOXazV9ibRVVuu8ag+R0d7Ge8CnMpjqezfR00AstQpWQpNliPlf1cOLB4VZOP6/QgGhao
+wb0Kctifgr1CwxUaddXGmHYJvee4I0aamnqFf7LZ09wrxL7encYXxrZYiyHXeKbPX8vz3qFIazLF
+6WOPUoVu9Q1ebnKHqPf+lRL6Owc7kGixqMb4rTCZdXhI9eBo9kqWYoM1nUprM+pOx7FYRfBR4Sd/
+oelHeMD/eQLo14E8lgjeeWb9bwG7NF2Un2QskMc6L915rPsBCmsbn5wOKsVIEU8F52Cd2asZ4X41
+FRDN3/aY3f4Sz7xrW58cBbPQQFEW9Ble1f5F0Fc3zOePnVhMi7drjh8ZaWQZvPcD1ssOyFm3rWG5
+g9d5jKjoJ8A6Qw9fEBX9eqfg1g0XYBx/hjLv6xpE5v1n1CP8iqhua1RTZmeeMffyknOZsW2VI/2Z
+994N2fxeofZ8RB4raLG+ZDoyDKr2Z9P9Px5v9S7HqEmddYr6HsXcNo0+KlbaZ5GB66EbWJD9tPlh
+Eqz+YqxdOvUKHaJXGL0G6cxgDdJj/F5hDm+39XRfgyruoyO8mSfvP3oq8CgU8iDB24YH6bah8jRL
+PVhtnkax0OjhSavelmZPc1vYKlONnhb+1xC96PV6dpsjFl5vbqL9Xvd46Kazr8lDHY4DYiXpIG4b
+NOroECVJkRe5R/QKvUabHPB6ml45FbbKkPHSbApPB/+pPa8YHu5gcxMfvOD1eGj31zweDNNagi1t
+iM9GbfE0p2V0g5QUk2BJSbCkJFhSUoPW/wfr5tj8wgE+HwAAAABJRU5ErkJggg==
diff --git a/Documentation/DocBook/media/v4l/.gitignore b/Documentation/DocBook/media/v4l/.gitignore
new file mode 100644 (file)
index 0000000..d7ec32e
--- /dev/null
@@ -0,0 +1 @@
+!*.xml
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml
new file mode 100644 (file)
index 0000000..afc8a0d
--- /dev/null
@@ -0,0 +1,188 @@
+  <bibliography>
+    <title>References</title>
+
+    <biblioentry id="eia608">
+      <abbrev>EIA&nbsp;608-B</abbrev>
+      <authorgroup>
+       <corpauthor>Electronic Industries Alliance (<ulink
+url="http://www.eia.org">http://www.eia.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>EIA 608-B "Recommended Practice for Line 21 Data
+Service"</title>
+    </biblioentry>
+
+    <biblioentry id="en300294">
+      <abbrev>EN&nbsp;300&nbsp;294</abbrev>
+      <authorgroup>
+       <corpauthor>European Telecommunication Standards Institute
+(<ulink url="http://www.etsi.org">http://www.etsi.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>EN 300 294 "625-line television Wide Screen Signalling
+(WSS)"</title>
+    </biblioentry>
+
+    <biblioentry id="ets300231">
+      <abbrev>ETS&nbsp;300&nbsp;231</abbrev>
+      <authorgroup>
+       <corpauthor>European Telecommunication Standards Institute
+(<ulink
+url="http://www.etsi.org">http://www.etsi.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ETS 300 231 "Specification of the domestic video
+Programme Delivery Control system (PDC)"</title>
+    </biblioentry>
+
+    <biblioentry id="ets300706">
+      <abbrev>ETS&nbsp;300&nbsp;706</abbrev>
+      <authorgroup>
+       <corpauthor>European Telecommunication Standards Institute
+(<ulink url="http://www.etsi.org">http://www.etsi.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ETS 300 706 "Enhanced Teletext specification"</title>
+    </biblioentry>
+
+    <biblioentry id="mpeg2part1">
+      <abbrev>ISO&nbsp;13818-1</abbrev>
+      <authorgroup>
+       <corpauthor>International Telecommunication Union (<ulink
+url="http://www.itu.ch">http://www.itu.ch</ulink>), International
+Organisation for Standardisation (<ulink
+url="http://www.iso.ch">http://www.iso.ch</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ITU-T Rec. H.222.0 | ISO/IEC 13818-1 "Information
+technology &mdash; Generic coding of moving pictures and associated
+audio information: Systems"</title>
+    </biblioentry>
+
+    <biblioentry id="mpeg2part2">
+      <abbrev>ISO&nbsp;13818-2</abbrev>
+      <authorgroup>
+       <corpauthor>International Telecommunication Union (<ulink
+url="http://www.itu.ch">http://www.itu.ch</ulink>), International
+Organisation for Standardisation (<ulink
+url="http://www.iso.ch">http://www.iso.ch</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ITU-T Rec. H.262 | ISO/IEC 13818-2 "Information
+technology &mdash; Generic coding of moving pictures and associated
+audio information: Video"</title>
+    </biblioentry>
+
+    <biblioentry id="itu470">
+      <abbrev>ITU&nbsp;BT.470</abbrev>
+      <authorgroup>
+       <corpauthor>International Telecommunication Union (<ulink
+url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ITU-R Recommendation BT.470-6 "Conventional Television
+Systems"</title>
+    </biblioentry>
+
+    <biblioentry id="itu601">
+      <abbrev>ITU&nbsp;BT.601</abbrev>
+      <authorgroup>
+       <corpauthor>International Telecommunication Union (<ulink
+url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ITU-R Recommendation BT.601-5 "Studio Encoding Parameters
+of Digital Television for Standard 4:3 and Wide-Screen 16:9 Aspect
+Ratios"</title>
+    </biblioentry>
+
+    <biblioentry id="itu653">
+      <abbrev>ITU&nbsp;BT.653</abbrev>
+      <authorgroup>
+       <corpauthor>International Telecommunication Union (<ulink
+url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ITU-R Recommendation BT.653-3 "Teletext systems"</title>
+    </biblioentry>
+
+    <biblioentry id="itu709">
+      <abbrev>ITU&nbsp;BT.709</abbrev>
+      <authorgroup>
+       <corpauthor>International Telecommunication Union (<ulink
+url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ITU-R Recommendation BT.709-5 "Parameter values for the
+HDTV standards for production and international programme
+exchange"</title>
+    </biblioentry>
+
+    <biblioentry id="itu1119">
+      <abbrev>ITU&nbsp;BT.1119</abbrev>
+      <authorgroup>
+       <corpauthor>International Telecommunication Union (<ulink
+url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
+      </authorgroup>
+      <title>ITU-R Recommendation BT.1119 "625-line
+television Wide Screen Signalling (WSS)"</title>
+    </biblioentry>
+
+    <biblioentry id="jfif">
+      <abbrev>JFIF</abbrev>
+      <authorgroup>
+       <corpauthor>Independent JPEG Group (<ulink
+url="http://www.ijg.org">http://www.ijg.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>JPEG File Interchange Format</title>
+      <subtitle>Version 1.02</subtitle>
+    </biblioentry>
+
+    <biblioentry id="smpte12m">
+      <abbrev>SMPTE&nbsp;12M</abbrev>
+      <authorgroup>
+       <corpauthor>Society of Motion Picture and Television Engineers
+(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>SMPTE 12M-1999 "Television, Audio and Film - Time and
+Control Code"</title>
+    </biblioentry>
+
+    <biblioentry id="smpte170m">
+      <abbrev>SMPTE&nbsp;170M</abbrev>
+      <authorgroup>
+       <corpauthor>Society of Motion Picture and Television Engineers
+(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>SMPTE 170M-1999 "Television - Composite Analog Video
+Signal - NTSC for Studio Applications"</title>
+    </biblioentry>
+
+    <biblioentry id="smpte240m">
+      <abbrev>SMPTE&nbsp;240M</abbrev>
+      <authorgroup>
+       <corpauthor>Society of Motion Picture and Television Engineers
+(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>SMPTE 240M-1999 "Television - Signal Parameters -
+1125-Line High-Definition Production"</title>
+    </biblioentry>
+
+    <biblioentry id="en50067">
+      <abbrev>EN&nbsp;50067</abbrev>
+      <authorgroup>
+       <corpauthor>European Committee for Electrotechnical Standardization
+(<ulink url="http://www.cenelec.eu">http://www.cenelec.eu</ulink>)</corpauthor>
+      </authorgroup>
+      <title>Specification of the radio data system (RDS) for VHF/FM sound broadcasting
+in the frequency range from 87,5 to 108,0 MHz</title>
+    </biblioentry>
+
+    <biblioentry id="nrsc4">
+      <abbrev>NRSC-4</abbrev>
+      <authorgroup>
+       <corpauthor>National Radio Systems Committee
+(<ulink url="http://www.nrscstandards.org">http://www.nrscstandards.org</ulink>)</corpauthor>
+      </authorgroup>
+      <title>NTSC-4: United States RBDS Standard</title>
+    </biblioentry>
+
+  </bibliography>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/capture.c.xml b/Documentation/DocBook/media/v4l/capture.c.xml
new file mode 100644 (file)
index 0000000..1c5c49a
--- /dev/null
@@ -0,0 +1,659 @@
+<programlisting>
+/*
+ *  V4L2 video capture example
+ *
+ *  This program can be used and distributed without restrictions.
+ *
+ *      This program is provided with the V4L2 API
+ * see http://linuxtv.org/docs.php for more information
+ */
+
+#include &lt;stdio.h&gt;
+#include &lt;stdlib.h&gt;
+#include &lt;string.h&gt;
+#include &lt;assert.h&gt;
+
+#include &lt;getopt.h&gt;             /* getopt_long() */
+
+#include &lt;fcntl.h&gt;              /* low-level i/o */
+#include &lt;unistd.h&gt;
+#include &lt;errno.h&gt;
+#include &lt;sys/stat.h&gt;
+#include &lt;sys/types.h&gt;
+#include &lt;sys/time.h&gt;
+#include &lt;sys/mman.h&gt;
+#include &lt;sys/ioctl.h&gt;
+
+#include &lt;linux/videodev2.h&gt;
+
+#define CLEAR(x) memset(&amp;(x), 0, sizeof(x))
+
+enum io_method {
+        IO_METHOD_READ,
+        IO_METHOD_MMAP,
+        IO_METHOD_USERPTR,
+};
+
+struct buffer {
+        void   *start;
+        size_t  length;
+};
+
+static char            *dev_name;
+static enum io_method   io = IO_METHOD_MMAP;
+static int              fd = -1;
+struct buffer          *buffers;
+static unsigned int     n_buffers;
+static int              out_buf;
+static int              force_format;
+static int              frame_count = 70;
+
+static void errno_exit(const char *s)
+{
+        fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
+        exit(EXIT_FAILURE);
+}
+
+static int xioctl(int fh, int request, void *arg)
+{
+        int r;
+
+        do {
+                r = ioctl(fh, request, arg);
+        } while (-1 == r &amp;&amp; EINTR == errno);
+
+        return r;
+}
+
+static void process_image(const void *p, int size)
+{
+        if (out_buf)
+                fwrite(p, size, 1, stdout);
+
+        fflush(stderr);
+        fprintf(stderr, ".");
+        fflush(stdout);
+}
+
+static int read_frame(void)
+{
+        struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
+        unsigned int i;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                if (-1 == read(fd, buffers[0].start, buffers[0].length)) {
+                        switch (errno) {
+                        case EAGAIN:
+                                return 0;
+
+                        case EIO:
+                                /* Could ignore EIO, see spec. */
+
+                                /* fall through */
+
+                        default:
+                                errno_exit("read");
+                        }
+                }
+
+                process_image(buffers[0].start, buffers[0].length);
+                break;
+
+        case IO_METHOD_MMAP:
+                CLEAR(buf);
+
+                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory = V4L2_MEMORY_MMAP;
+
+                if (-1 == xioctl(fd, VIDIOC_DQBUF, &amp;buf)) {
+                        switch (errno) {
+                        case EAGAIN:
+                                return 0;
+
+                        case EIO:
+                                /* Could ignore EIO, see spec. */
+
+                                /* fall through */
+
+                        default:
+                                errno_exit("VIDIOC_DQBUF");
+                        }
+                }
+
+                assert(buf.index &lt; n_buffers);
+
+                process_image(buffers[buf.index].start, buf.bytesused);
+
+                if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
+                        errno_exit("VIDIOC_QBUF");
+                break;
+
+        case IO_METHOD_USERPTR:
+                CLEAR(buf);
+
+                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory = V4L2_MEMORY_USERPTR;
+
+                if (-1 == xioctl(fd, VIDIOC_DQBUF, &amp;buf)) {
+                        switch (errno) {
+                        case EAGAIN:
+                                return 0;
+
+                        case EIO:
+                                /* Could ignore EIO, see spec. */
+
+                                /* fall through */
+
+                        default:
+                                errno_exit("VIDIOC_DQBUF");
+                        }
+                }
+
+                for (i = 0; i &lt; n_buffers; ++i)
+                        if (buf.m.userptr == (unsigned long)buffers[i].start
+                            &amp;&amp; buf.length == buffers[i].length)
+                                break;
+
+                assert(i &lt; n_buffers);
+
+                process_image((void *)buf.m.userptr, buf.bytesused);
+
+                if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
+                        errno_exit("VIDIOC_QBUF");
+                break;
+        }
+
+        return 1;
+}
+
+static void mainloop(void)
+{
+        unsigned int count;
+
+        count = frame_count;
+
+        while (count-- &gt; 0) {
+                for (;;) {
+                        fd_set fds;
+                        struct timeval tv;
+                        int r;
+
+                        FD_ZERO(&amp;fds);
+                        FD_SET(fd, &amp;fds);
+
+                        /* Timeout. */
+                        tv.tv_sec = 2;
+                        tv.tv_usec = 0;
+
+                        r = select(fd + 1, &amp;fds, NULL, NULL, &amp;tv);
+
+                        if (-1 == r) {
+                                if (EINTR == errno)
+                                        continue;
+                                errno_exit("select");
+                        }
+
+                        if (0 == r) {
+                                fprintf(stderr, "select timeout\n");
+                                exit(EXIT_FAILURE);
+                        }
+
+                        if (read_frame())
+                                break;
+                        /* EAGAIN - continue select loop. */
+                }
+        }
+}
+
+static void stop_capturing(void)
+{
+        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                /* Nothing to do. */
+                break;
+
+        case IO_METHOD_MMAP:
+        case IO_METHOD_USERPTR:
+                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &amp;type))
+                        errno_exit("VIDIOC_STREAMOFF");
+                break;
+        }
+}
+
+static void start_capturing(void)
+{
+        unsigned int i;
+        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                /* Nothing to do. */
+                break;
+
+        case IO_METHOD_MMAP:
+                for (i = 0; i &lt; n_buffers; ++i) {
+                        struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
+
+                        CLEAR(buf);
+                        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                        buf.memory = V4L2_MEMORY_MMAP;
+                        buf.index = i;
+
+                        if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
+                                errno_exit("VIDIOC_QBUF");
+                }
+                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                if (-1 == xioctl(fd, VIDIOC_STREAMON, &amp;type))
+                        errno_exit("VIDIOC_STREAMON");
+                break;
+
+        case IO_METHOD_USERPTR:
+                for (i = 0; i &lt; n_buffers; ++i) {
+                        struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
+
+                        CLEAR(buf);
+                        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                        buf.memory = V4L2_MEMORY_USERPTR;
+                        buf.index = i;
+                        buf.m.userptr = (unsigned long)buffers[i].start;
+                        buf.length = buffers[i].length;
+
+                        if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
+                                errno_exit("VIDIOC_QBUF");
+                }
+                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                if (-1 == xioctl(fd, VIDIOC_STREAMON, &amp;type))
+                        errno_exit("VIDIOC_STREAMON");
+                break;
+        }
+}
+
+static void uninit_device(void)
+{
+        unsigned int i;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                free(buffers[0].start);
+                break;
+
+        case IO_METHOD_MMAP:
+                for (i = 0; i &lt; n_buffers; ++i)
+                        if (-1 == munmap(buffers[i].start, buffers[i].length))
+                                errno_exit("munmap");
+                break;
+
+        case IO_METHOD_USERPTR:
+                for (i = 0; i &lt; n_buffers; ++i)
+                        free(buffers[i].start);
+                break;
+        }
+
+        free(buffers);
+}
+
+static void init_read(unsigned int buffer_size)
+{
+        buffers = calloc(1, sizeof(*buffers));
+
+        if (!buffers) {
+                fprintf(stderr, "Out of memory\n");
+                exit(EXIT_FAILURE);
+        }
+
+        buffers[0].length = buffer_size;
+        buffers[0].start = malloc(buffer_size);
+
+        if (!buffers[0].start) {
+                fprintf(stderr, "Out of memory\n");
+                exit(EXIT_FAILURE);
+        }
+}
+
+static void init_mmap(void)
+{
+        struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> req;
+
+        CLEAR(req);
+
+        req.count = 4;
+        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        req.memory = V4L2_MEMORY_MMAP;
+
+        if (-1 == xioctl(fd, VIDIOC_REQBUFS, &amp;req)) {
+                if (EINVAL == errno) {
+                        fprintf(stderr, "%s does not support "
+                                 "memory mapping\n", dev_name);
+                        exit(EXIT_FAILURE);
+                } else {
+                        errno_exit("VIDIOC_REQBUFS");
+                }
+        }
+
+        if (req.count &lt; 2) {
+                fprintf(stderr, "Insufficient buffer memory on %s\n",
+                         dev_name);
+                exit(EXIT_FAILURE);
+        }
+
+        buffers = calloc(req.count, sizeof(*buffers));
+
+        if (!buffers) {
+                fprintf(stderr, "Out of memory\n");
+                exit(EXIT_FAILURE);
+        }
+
+        for (n_buffers = 0; n_buffers &lt; req.count; ++n_buffers) {
+                struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
+
+                CLEAR(buf);
+
+                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory      = V4L2_MEMORY_MMAP;
+                buf.index       = n_buffers;
+
+                if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &amp;buf))
+                        errno_exit("VIDIOC_QUERYBUF");
+
+                buffers[n_buffers].length = buf.length;
+                buffers[n_buffers].start =
+                        mmap(NULL /* start anywhere */,
+                              buf.length,
+                              PROT_READ | PROT_WRITE /* required */,
+                              MAP_SHARED /* recommended */,
+                              fd, buf.m.offset);
+
+                if (MAP_FAILED == buffers[n_buffers].start)
+                        errno_exit("mmap");
+        }
+}
+
+static void init_userp(unsigned int buffer_size)
+{
+        struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> req;
+
+        CLEAR(req);
+
+        req.count  = 4;
+        req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        req.memory = V4L2_MEMORY_USERPTR;
+
+        if (-1 == xioctl(fd, VIDIOC_REQBUFS, &amp;req)) {
+                if (EINVAL == errno) {
+                        fprintf(stderr, "%s does not support "
+                                 "user pointer i/o\n", dev_name);
+                        exit(EXIT_FAILURE);
+                } else {
+                        errno_exit("VIDIOC_REQBUFS");
+                }
+        }
+
+        buffers = calloc(4, sizeof(*buffers));
+
+        if (!buffers) {
+                fprintf(stderr, "Out of memory\n");
+                exit(EXIT_FAILURE);
+        }
+
+        for (n_buffers = 0; n_buffers &lt; 4; ++n_buffers) {
+                buffers[n_buffers].length = buffer_size;
+                buffers[n_buffers].start = malloc(buffer_size);
+
+                if (!buffers[n_buffers].start) {
+                        fprintf(stderr, "Out of memory\n");
+                        exit(EXIT_FAILURE);
+                }
+        }
+}
+
+static void init_device(void)
+{
+        struct <link linkend="v4l2-capability">v4l2_capability</link> cap;
+        struct <link linkend="v4l2-cropcap">v4l2_cropcap</link> cropcap;
+        struct <link linkend="v4l2-crop">v4l2_crop</link> crop;
+        struct <link linkend="v4l2-format">v4l2_format</link> fmt;
+        unsigned int min;
+
+        if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &amp;cap)) {
+                if (EINVAL == errno) {
+                        fprintf(stderr, "%s is no V4L2 device\n",
+                                 dev_name);
+                        exit(EXIT_FAILURE);
+                } else {
+                        errno_exit("VIDIOC_QUERYCAP");
+                }
+        }
+
+        if (!(cap.capabilities &amp; V4L2_CAP_VIDEO_CAPTURE)) {
+                fprintf(stderr, "%s is no video capture device\n",
+                         dev_name);
+                exit(EXIT_FAILURE);
+        }
+
+        switch (io) {
+        case IO_METHOD_READ:
+                if (!(cap.capabilities &amp; V4L2_CAP_READWRITE)) {
+                        fprintf(stderr, "%s does not support read i/o\n",
+                                 dev_name);
+                        exit(EXIT_FAILURE);
+                }
+                break;
+
+        case IO_METHOD_MMAP:
+        case IO_METHOD_USERPTR:
+                if (!(cap.capabilities &amp; V4L2_CAP_STREAMING)) {
+                        fprintf(stderr, "%s does not support streaming i/o\n",
+                                 dev_name);
+                        exit(EXIT_FAILURE);
+                }
+                break;
+        }
+
+
+        /* Select video input, video standard and tune here. */
+
+
+        CLEAR(cropcap);
+
+        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+        if (0 == xioctl(fd, VIDIOC_CROPCAP, &amp;cropcap)) {
+                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                crop.c = cropcap.defrect; /* reset to default */
+
+                if (-1 == xioctl(fd, VIDIOC_S_CROP, &amp;crop)) {
+                        switch (errno) {
+                        case EINVAL:
+                                /* Cropping not supported. */
+                                break;
+                        default:
+                                /* Errors ignored. */
+                                break;
+                        }
+                }
+        } else {
+                /* Errors ignored. */
+        }
+
+
+        CLEAR(fmt);
+
+        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        if (force_format) {
+                fmt.fmt.pix.width       = 640;
+                fmt.fmt.pix.height      = 480;
+                fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+                fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
+
+                if (-1 == xioctl(fd, VIDIOC_S_FMT, &amp;fmt))
+                        errno_exit("VIDIOC_S_FMT");
+
+                /* Note VIDIOC_S_FMT may change width and height. */
+        } else {
+                /* Preserve original settings as set by v4l2-ctl for example */
+                if (-1 == xioctl(fd, VIDIOC_G_FMT, &amp;fmt))
+                        errno_exit("VIDIOC_G_FMT");
+        }
+
+        /* Buggy driver paranoia. */
+        min = fmt.fmt.pix.width * 2;
+        if (fmt.fmt.pix.bytesperline &lt; min)
+                fmt.fmt.pix.bytesperline = min;
+        min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
+        if (fmt.fmt.pix.sizeimage &lt; min)
+                fmt.fmt.pix.sizeimage = min;
+
+        switch (io) {
+        case IO_METHOD_READ:
+                init_read(fmt.fmt.pix.sizeimage);
+                break;
+
+        case IO_METHOD_MMAP:
+                init_mmap();
+                break;
+
+        case IO_METHOD_USERPTR:
+                init_userp(fmt.fmt.pix.sizeimage);
+                break;
+        }
+}
+
+static void close_device(void)
+{
+        if (-1 == close(fd))
+                errno_exit("close");
+
+        fd = -1;
+}
+
+static void open_device(void)
+{
+        struct stat st;
+
+        if (-1 == stat(dev_name, &amp;st)) {
+                fprintf(stderr, "Cannot identify '%s': %d, %s\n",
+                         dev_name, errno, strerror(errno));
+                exit(EXIT_FAILURE);
+        }
+
+        if (!S_ISCHR(st.st_mode)) {
+                fprintf(stderr, "%s is no device\n", dev_name);
+                exit(EXIT_FAILURE);
+        }
+
+        fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
+
+        if (-1 == fd) {
+                fprintf(stderr, "Cannot open '%s': %d, %s\n",
+                         dev_name, errno, strerror(errno));
+                exit(EXIT_FAILURE);
+        }
+}
+
+static void usage(FILE *fp, int argc, char **argv)
+{
+        fprintf(fp,
+                 "Usage: %s [options]\n\n"
+                 "Version 1.3\n"
+                 "Options:\n"
+                 "-d | --device name   Video device name [%s]\n"
+                 "-h | --help          Print this message\n"
+                 "-m | --mmap          Use memory mapped buffers [default]\n"
+                 "-r | --read          Use read() calls\n"
+                 "-u | --userp         Use application allocated buffers\n"
+                 "-o | --output        Outputs stream to stdout\n"
+                 "-f | --format        Force format to 640x480 YUYV\n"
+                 "-c | --count         Number of frames to grab [%i]\n"
+                 "",
+                 argv[0], dev_name, frame_count);
+}
+
+static const char short_options[] = "d:hmruofc:";
+
+static const struct option
+long_options[] = {
+        { "device", required_argument, NULL, 'd' },
+        { "help",   no_argument,       NULL, 'h' },
+        { "mmap",   no_argument,       NULL, 'm' },
+        { "read",   no_argument,       NULL, 'r' },
+        { "userp",  no_argument,       NULL, 'u' },
+        { "output", no_argument,       NULL, 'o' },
+        { "format", no_argument,       NULL, 'f' },
+        { "count",  required_argument, NULL, 'c' },
+        { 0, 0, 0, 0 }
+};
+
+int main(int argc, char **argv)
+{
+        dev_name = "/dev/video0";
+
+        for (;;) {
+                int idx;
+                int c;
+
+                c = getopt_long(argc, argv,
+                                short_options, long_options, &amp;idx);
+
+                if (-1 == c)
+                        break;
+
+                switch (c) {
+                case 0: /* getopt_long() flag */
+                        break;
+
+                case 'd':
+                        dev_name = optarg;
+                        break;
+
+                case 'h':
+                        usage(stdout, argc, argv);
+                        exit(EXIT_SUCCESS);
+
+                case 'm':
+                        io = IO_METHOD_MMAP;
+                        break;
+
+                case 'r':
+                        io = IO_METHOD_READ;
+                        break;
+
+                case 'u':
+                        io = IO_METHOD_USERPTR;
+                        break;
+
+                case 'o':
+                        out_buf++;
+                        break;
+
+                case 'f':
+                        force_format++;
+                        break;
+
+                case 'c':
+                        errno = 0;
+                        frame_count = strtol(optarg, NULL, 0);
+                        if (errno)
+                                errno_exit(optarg);
+                        break;
+
+                default:
+                        usage(stderr, argc, argv);
+                        exit(EXIT_FAILURE);
+                }
+        }
+
+        open_device();
+        init_device();
+        start_capturing();
+        mainloop();
+        stop_capturing();
+        uninit_device();
+        close_device();
+        fprintf(stderr, "\n");
+        return 0;
+}
+</programlisting>
diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
new file mode 100644 (file)
index 0000000..a86f7a0
--- /dev/null
@@ -0,0 +1,1205 @@
+  <title>Common API Elements</title>
+
+  <para>Programming a V4L2 device consists of these
+steps:</para>
+
+  <itemizedlist>
+    <listitem>
+      <para>Opening the device</para>
+    </listitem>
+    <listitem>
+      <para>Changing device properties, selecting a video and audio
+input, video standard, picture brightness a.&nbsp;o.</para>
+    </listitem>
+    <listitem>
+      <para>Negotiating a data format</para>
+    </listitem>
+    <listitem>
+      <para>Negotiating an input/output method</para>
+    </listitem>
+    <listitem>
+      <para>The actual input/output loop</para>
+    </listitem>
+    <listitem>
+      <para>Closing the device</para>
+    </listitem>
+  </itemizedlist>
+
+  <para>In practice most steps are optional and can be executed out of
+order. It depends on the V4L2 device type, you can read about the
+details in <xref linkend="devices" />. In this chapter we will discuss
+the basic concepts applicable to all devices.</para>
+
+  <section id="open">
+    <title>Opening and Closing Devices</title>
+
+    <section>
+      <title>Device Naming</title>
+
+      <para>V4L2 drivers are implemented as kernel modules, loaded
+manually by the system administrator or automatically when a device is
+first opened. The driver modules plug into the "videodev" kernel
+module. It provides helper functions and a common application
+interface specified in this document.</para>
+
+      <para>Each driver thus loaded registers one or more device nodes
+with major number 81 and a minor number between 0 and 255. Assigning
+minor numbers to V4L2 devices is entirely up to the system administrator,
+this is primarily intended to solve conflicts between devices.<footnote>
+         <para>Access permissions are associated with character
+device special files, hence we must ensure device numbers cannot
+change with the module load order. To this end minor numbers are no
+longer automatically assigned by the "videodev" module as in V4L but
+requested by the driver. The defaults will suffice for most people
+unless two drivers compete for the same minor numbers.</para>
+       </footnote> The module options to select minor numbers are named
+after the device special file with a "_nr" suffix. For example "video_nr"
+for <filename>/dev/video</filename> video capture devices. The number is
+an offset to the base minor number associated with the device type.
+<footnote>
+         <para>In earlier versions of the V4L2 API the module options
+where named after the device special file with a "unit_" prefix, expressing
+the minor number itself, not an offset. Rationale for this change is unknown.
+Lastly the naming and semantics are just a convention among driver writers,
+the point to note is that minor numbers are not supposed to be hardcoded
+into drivers.</para>
+       </footnote> When the driver supports multiple devices of the same
+type more than one minor number can be assigned, separated by commas:
+<informalexample>
+         <screen>
+&gt; insmod mydriver.o video_nr=0,1 radio_nr=0,1</screen>
+       </informalexample></para>
+
+      <para>In <filename>/etc/modules.conf</filename> this may be
+written as: <informalexample>
+         <screen>
+alias char-major-81-0 mydriver
+alias char-major-81-1 mydriver
+alias char-major-81-64 mydriver              <co id="alias" />
+options mydriver video_nr=0,1 radio_nr=0,1   <co id="options" />
+         </screen>
+         <calloutlist>
+           <callout arearefs="alias">
+             <para>When an application attempts to open a device
+special file with major number 81 and minor number 0, 1, or 64, load
+"mydriver" (and the "videodev" module it depends upon).</para>
+           </callout>
+           <callout arearefs="options">
+             <para>Register the first two video capture devices with
+minor number 0 and 1 (base number is 0), the first two radio device
+with minor number 64 and 65 (base 64).</para>
+           </callout>
+         </calloutlist>
+       </informalexample> When no minor number is given as module
+option the driver supplies a default. <xref linkend="devices" />
+recommends the base minor numbers to be used for the various device
+types. Obviously minor numbers must be unique. When the number is
+already in use the <emphasis>offending device</emphasis> will not be
+registered. <!-- Blessed by Linus Torvalds on
+linux-kernel@vger.kernel.org, 2002-11-20. --></para>
+
+      <para>By convention system administrators create various
+character device special files with these major and minor numbers in
+the <filename>/dev</filename> directory. The names recommended for the
+different V4L2 device types are listed in <xref linkend="devices" />.
+</para>
+
+      <para>The creation of character special files (with
+<application>mknod</application>) is a privileged operation and
+devices cannot be opened by major and minor number. That means
+applications cannot <emphasis>reliable</emphasis> scan for loaded or
+installed drivers. The user must enter a device name, or the
+application can try the conventional device names.</para>
+
+      <para>Under the device filesystem (devfs) the minor number
+options are ignored. V4L2 drivers (or by proxy the "videodev" module)
+automatically create the required device files in the
+<filename>/dev/v4l</filename> directory using the conventional device
+names above.</para>
+    </section>
+
+    <section id="related">
+      <title>Related Devices</title>
+
+      <para>Devices can support several related functions. For example
+video capturing, video overlay and VBI capturing are related because
+these functions share, amongst other, the same video input and tuner
+frequency. V4L and earlier versions of V4L2 used the same device name
+and minor number for video capturing and overlay, but different ones
+for VBI. Experience showed this approach has several problems<footnote>
+         <para>Given a device file name one cannot reliable find
+related devices. For once names are arbitrary and in a system with
+multiple devices, where only some support VBI capturing, a
+<filename>/dev/video2</filename> is not necessarily related to
+<filename>/dev/vbi2</filename>. The V4L
+<constant>VIDIOCGUNIT</constant> ioctl would require a search for a
+device file with a particular major and minor number.</para>
+       </footnote>, and to make things worse the V4L videodev module
+used to prohibit multiple opens of a device.</para>
+
+      <para>As a remedy the present version of the V4L2 API relaxed the
+concept of device types with specific names and minor numbers. For
+compatibility with old applications drivers must still register different
+minor numbers to assign a default function to the device. But if related
+functions are supported by the driver they must be available under all
+registered minor numbers. The desired function can be selected after
+opening the device as described in <xref linkend="devices" />.</para>
+
+      <para>Imagine a driver supporting video capturing, video
+overlay, raw VBI capturing, and FM radio reception. It registers three
+devices with minor number 0, 64 and 224 (this numbering scheme is
+inherited from the V4L API). Regardless if
+<filename>/dev/video</filename> (81, 0) or
+<filename>/dev/vbi</filename> (81, 224) is opened the application can
+select any one of the video capturing, overlay or VBI capturing
+functions. Without programming (e.&nbsp;g. reading from the device
+with <application>dd</application> or <application>cat</application>)
+<filename>/dev/video</filename> captures video images, while
+<filename>/dev/vbi</filename> captures raw VBI data.
+<filename>/dev/radio</filename> (81, 64) is invariable a radio device,
+unrelated to the video functions. Being unrelated does not imply the
+devices can be used at the same time, however. The &func-open;
+function may very well return an &EBUSY;.</para>
+
+      <para>Besides video input or output the hardware may also
+support audio sampling or playback. If so, these functions are
+implemented as OSS or ALSA PCM devices and eventually OSS or ALSA
+audio mixer. The V4L2 API makes no provisions yet to find these
+related devices. If you have an idea please write to the linux-media
+mailing list: &v4l-ml;.</para>
+    </section>
+
+    <section>
+      <title>Multiple Opens</title>
+
+      <para>In general, V4L2 devices can be opened more than once.
+When this is supported by the driver, users can for example start a
+"panel" application to change controls like brightness or audio
+volume, while another application captures video and audio. In other words, panel
+applications are comparable to an OSS or ALSA audio mixer application.
+When a device supports multiple functions like capturing and overlay
+<emphasis>simultaneously</emphasis>, multiple opens allow concurrent
+use of the device by forked processes or specialized applications.</para>
+
+      <para>Multiple opens are optional, although drivers should
+permit at least concurrent accesses without data exchange, &ie; panel
+applications. This implies &func-open; can return an &EBUSY; when the
+device is already in use, as well as &func-ioctl; functions initiating
+data exchange (namely the &VIDIOC-S-FMT; ioctl), and the &func-read;
+and &func-write; functions.</para>
+
+      <para>Mere opening a V4L2 device does not grant exclusive
+access.<footnote>
+         <para>Drivers could recognize the
+<constant>O_EXCL</constant> open flag. Presently this is not required,
+so applications cannot know if it really works.</para>
+       </footnote> Initiating data exchange however assigns the right
+to read or write the requested type of data, and to change related
+properties, to this file descriptor. Applications can request
+additional access privileges using the priority mechanism described in
+<xref linkend="app-pri" />.</para>
+    </section>
+
+    <section>
+      <title>Shared Data Streams</title>
+
+      <para>V4L2 drivers should not support multiple applications
+reading or writing the same data stream on a device by copying
+buffers, time multiplexing or similar means. This is better handled by
+a proxy application in user space. When the driver supports stream
+sharing anyway it must be implemented transparently. The V4L2 API does
+not specify how conflicts are solved. <!-- For example O_EXCL when the
+application does not want to be preempted, PROT_READ mmapped buffers
+which can be mapped twice, what happens when image formats do not
+match etc.--></para>
+    </section>
+
+    <section>
+      <title>Functions</title>
+
+    <para>To open and close V4L2 devices applications use the
+&func-open; and &func-close; function, respectively. Devices are
+programmed using the &func-ioctl; function as explained in the
+following sections.</para>
+    </section>
+  </section>
+
+  <section id="querycap">
+    <title>Querying Capabilities</title>
+
+    <para>Because V4L2 covers a wide variety of devices not all
+aspects of the API are equally applicable to all types of devices.
+Furthermore devices of the same type have different capabilities and
+this specification permits the omission of a few complicated and less
+important parts of the API.</para>
+
+    <para>The &VIDIOC-QUERYCAP; ioctl is available to check if the kernel
+device is compatible with this specification, and to query the <link
+linkend="devices">functions</link> and <link linkend="io">I/O
+methods</link> supported by the device.</para>
+
+    <para>Starting with kernel version 3.1, VIDIOC-QUERYCAP will return the
+V4L2 API version used by the driver, with generally matches the Kernel version.
+There's no need of using &VIDIOC-QUERYCAP; to check if an specific ioctl is
+supported, the V4L2 core now returns ENOIOCTLCMD if a driver doesn't provide
+support for an ioctl.</para>
+
+    <para>Other features can be queried
+by calling the respective ioctl, for example &VIDIOC-ENUMINPUT;
+to learn about the number, types and names of video connectors on the
+device. Although abstraction is a major objective of this API, the
+ioctl also allows driver specific applications to reliable identify
+the driver.</para>
+
+    <para>All V4L2 drivers must support
+<constant>VIDIOC_QUERYCAP</constant>. Applications should always call
+this ioctl after opening the device.</para>
+  </section>
+
+  <section id="app-pri">
+    <title>Application Priority</title>
+
+    <para>When multiple applications share a device it may be
+desirable to assign them different priorities. Contrary to the
+traditional "rm -rf /" school of thought a video recording application
+could for example block other applications from changing video
+controls or switching the current TV channel. Another objective is to
+permit low priority applications working in background, which can be
+preempted by user controlled applications and automatically regain
+control of the device at a later time.</para>
+
+    <para>Since these features cannot be implemented entirely in user
+space V4L2 defines the &VIDIOC-G-PRIORITY; and &VIDIOC-S-PRIORITY;
+ioctls to request and query the access priority associate with a file
+descriptor. Opening a device assigns a medium priority, compatible
+with earlier versions of V4L2 and drivers not supporting these ioctls.
+Applications requiring a different priority will usually call
+<constant>VIDIOC_S_PRIORITY</constant> after verifying the device with
+the &VIDIOC-QUERYCAP; ioctl.</para>
+
+    <para>Ioctls changing driver properties, such as &VIDIOC-S-INPUT;,
+return an &EBUSY; after another application obtained higher priority.
+An event mechanism to notify applications about asynchronous property
+changes has been proposed but not added yet.</para>
+  </section>
+
+  <section id="video">
+    <title>Video Inputs and Outputs</title>
+
+    <para>Video inputs and outputs are physical connectors of a
+device. These can be for example RF connectors (antenna/cable), CVBS
+a.k.a. Composite Video, S-Video or RGB connectors. Only video and VBI
+capture devices have inputs, output devices have outputs, at least one
+each. Radio devices have no video inputs or outputs.</para>
+
+    <para>To learn about the number and attributes of the
+available inputs and outputs applications can enumerate them with the
+&VIDIOC-ENUMINPUT; and &VIDIOC-ENUMOUTPUT; ioctl, respectively. The
+&v4l2-input; returned by the <constant>VIDIOC_ENUMINPUT</constant>
+ioctl also contains signal status information applicable when the
+current video input is queried.</para>
+
+    <para>The &VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; ioctl return the
+index of the current video input or output. To select a different
+input or output applications call the &VIDIOC-S-INPUT; and
+&VIDIOC-S-OUTPUT; ioctl. Drivers must implement all the input ioctls
+when the device has one or more inputs, all the output ioctls when the
+device has one or more outputs.</para>
+
+    <!--
+    <figure id=io-tree>
+      <title>Input and output enumeration is the root of most device properties.</title>
+      <mediaobject>
+       <imageobject>
+         <imagedata fileref="links.pdf" format="ps" />
+       </imageobject>
+       <imageobject>
+         <imagedata fileref="links.gif" format="gif" />
+       </imageobject>
+       <textobject>
+         <phrase>Links between various device property structures.</phrase>
+       </textobject>
+      </mediaobject>
+    </figure>
+    -->
+
+    <example>
+      <title>Information about the current video input</title>
+
+      <programlisting>
+&v4l2-input; input;
+int index;
+
+if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &amp;index)) {
+       perror ("VIDIOC_G_INPUT");
+       exit (EXIT_FAILURE);
+}
+
+memset (&amp;input, 0, sizeof (input));
+input.index = index;
+
+if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
+       perror ("VIDIOC_ENUMINPUT");
+       exit (EXIT_FAILURE);
+}
+
+printf ("Current input: %s\n", input.name);
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Switching to the first video input</title>
+
+      <programlisting>
+int index;
+
+index = 0;
+
+if (-1 == ioctl (fd, &VIDIOC-S-INPUT;, &amp;index)) {
+       perror ("VIDIOC_S_INPUT");
+       exit (EXIT_FAILURE);
+}
+      </programlisting>
+    </example>
+  </section>
+
+  <section id="audio">
+    <title>Audio Inputs and Outputs</title>
+
+    <para>Audio inputs and outputs are physical connectors of a
+device. Video capture devices have inputs, output devices have
+outputs, zero or more each. Radio devices have no audio inputs or
+outputs. They have exactly one tuner which in fact
+<emphasis>is</emphasis> an audio source, but this API associates
+tuners with video inputs or outputs only, and radio devices have
+none of these.<footnote>
+       <para>Actually &v4l2-audio; ought to have a
+<structfield>tuner</structfield> field like &v4l2-input;, not only
+making the API more consistent but also permitting radio devices with
+multiple tuners.</para>
+      </footnote> A connector on a TV card to loop back the received
+audio signal to a sound card is not considered an audio output.</para>
+
+    <para>Audio and video inputs and outputs are associated. Selecting
+a video source also selects an audio source. This is most evident when
+the video and audio source is a tuner. Further audio connectors can
+combine with more than one video input or output. Assumed two
+composite video inputs and two audio inputs exist, there may be up to
+four valid combinations. The relation of video and audio connectors
+is defined in the <structfield>audioset</structfield> field of the
+respective &v4l2-input; or &v4l2-output;, where each bit represents
+the index number, starting at zero, of one audio input or output.</para>
+
+    <para>To learn about the number and attributes of the
+available inputs and outputs applications can enumerate them with the
+&VIDIOC-ENUMAUDIO; and &VIDIOC-ENUMAUDOUT; ioctl, respectively. The
+&v4l2-audio; returned by the <constant>VIDIOC_ENUMAUDIO</constant> ioctl
+also contains signal status information applicable when the current
+audio input is queried.</para>
+
+    <para>The &VIDIOC-G-AUDIO; and &VIDIOC-G-AUDOUT; ioctl report
+the current audio input and output, respectively. Note that, unlike
+&VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; these ioctls return a structure
+as <constant>VIDIOC_ENUMAUDIO</constant> and
+<constant>VIDIOC_ENUMAUDOUT</constant> do, not just an index.</para>
+
+    <para>To select an audio input and change its properties
+applications call the &VIDIOC-S-AUDIO; ioctl. To select an audio
+output (which presently has no changeable properties) applications
+call the &VIDIOC-S-AUDOUT; ioctl.</para>
+
+    <para>Drivers must implement all input ioctls when the device
+has one or more inputs, all output ioctls when the device has one
+or more outputs. When the device has any audio inputs or outputs the
+driver must set the <constant>V4L2_CAP_AUDIO</constant> flag in the
+&v4l2-capability; returned by the &VIDIOC-QUERYCAP; ioctl.</para>
+
+    <example>
+      <title>Information about the current audio input</title>
+
+      <programlisting>
+&v4l2-audio; audio;
+
+memset (&amp;audio, 0, sizeof (audio));
+
+if (-1 == ioctl (fd, &VIDIOC-G-AUDIO;, &amp;audio)) {
+       perror ("VIDIOC_G_AUDIO");
+       exit (EXIT_FAILURE);
+}
+
+printf ("Current input: %s\n", audio.name);
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Switching to the first audio input</title>
+
+      <programlisting>
+&v4l2-audio; audio;
+
+memset (&amp;audio, 0, sizeof (audio)); /* clear audio.mode, audio.reserved */
+
+audio.index = 0;
+
+if (-1 == ioctl (fd, &VIDIOC-S-AUDIO;, &amp;audio)) {
+       perror ("VIDIOC_S_AUDIO");
+       exit (EXIT_FAILURE);
+}
+      </programlisting>
+    </example>
+  </section>
+
+  <section id="tuner">
+    <title>Tuners and Modulators</title>
+
+    <section>
+      <title>Tuners</title>
+
+      <para>Video input devices can have one or more tuners
+demodulating a RF signal. Each tuner is associated with one or more
+video inputs, depending on the number of RF connectors on the tuner.
+The <structfield>type</structfield> field of the respective
+&v4l2-input; returned by the &VIDIOC-ENUMINPUT; ioctl is set to
+<constant>V4L2_INPUT_TYPE_TUNER</constant> and its
+<structfield>tuner</structfield> field contains the index number of
+the tuner.</para>
+
+      <para>Radio devices have exactly one tuner with index zero, no
+video inputs.</para>
+
+      <para>To query and change tuner properties applications use the
+&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; ioctl, respectively. The
+&v4l2-tuner; returned by <constant>VIDIOC_G_TUNER</constant> also
+contains signal status information applicable when the tuner of the
+current video input, or a radio tuner is queried. Note that
+<constant>VIDIOC_S_TUNER</constant> does not switch the current tuner,
+when there is more than one at all. The tuner is solely determined by
+the current video input. Drivers must support both ioctls and set the
+<constant>V4L2_CAP_TUNER</constant> flag in the &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl when the device has one or
+more tuners.</para>
+    </section>
+
+    <section>
+      <title>Modulators</title>
+
+      <para>Video output devices can have one or more modulators, uh,
+modulating a video signal for radiation or connection to the antenna
+input of a TV set or video recorder. Each modulator is associated with
+one or more video outputs, depending on the number of RF connectors on
+the modulator. The <structfield>type</structfield> field of the
+respective &v4l2-output; returned by the &VIDIOC-ENUMOUTPUT; ioctl is
+set to <constant>V4L2_OUTPUT_TYPE_MODULATOR</constant> and its
+<structfield>modulator</structfield> field contains the index number
+of the modulator. This specification does not define radio output
+devices.</para>
+
+      <para>To query and change modulator properties applications use
+the &VIDIOC-G-MODULATOR; and &VIDIOC-S-MODULATOR; ioctl. Note that
+<constant>VIDIOC_S_MODULATOR</constant> does not switch the current
+modulator, when there is more than one at all. The modulator is solely
+determined by the current video output. Drivers must support both
+ioctls and set the <constant>V4L2_CAP_MODULATOR</constant> flag in
+the &v4l2-capability; returned by the &VIDIOC-QUERYCAP; ioctl when the
+device has one or more modulators.</para>
+    </section>
+
+    <section>
+      <title>Radio Frequency</title>
+
+      <para>To get and set the tuner or modulator radio frequency
+applications use the &VIDIOC-G-FREQUENCY; and &VIDIOC-S-FREQUENCY;
+ioctl which both take a pointer to a &v4l2-frequency;. These ioctls
+are used for TV and radio devices alike. Drivers must support both
+ioctls when the tuner or modulator ioctls are supported, or
+when the device is a radio device.</para>
+    </section>
+  </section>
+
+  <section id="standard">
+    <title>Video Standards</title>
+
+    <para>Video devices typically support one or more different video
+standards or variations of standards. Each video input and output may
+support another set of standards. This set is reported by the
+<structfield>std</structfield> field of &v4l2-input; and
+&v4l2-output; returned by the &VIDIOC-ENUMINPUT; and
+&VIDIOC-ENUMOUTPUT; ioctl, respectively.</para>
+
+    <para>V4L2 defines one bit for each analog video standard
+currently in use worldwide, and sets aside bits for driver defined
+standards, &eg; hybrid standards to watch NTSC video tapes on PAL TVs
+and vice versa. Applications can use the predefined bits to select a
+particular standard, although presenting the user a menu of supported
+standards is preferred. To enumerate and query the attributes of the
+supported standards applications use the &VIDIOC-ENUMSTD; ioctl.</para>
+
+    <para>Many of the defined standards are actually just variations
+of a few major standards. The hardware may in fact not distinguish
+between them, or do so internal and switch automatically. Therefore
+enumerated standards also contain sets of one or more standard
+bits.</para>
+
+    <para>Assume a hypothetic tuner capable of demodulating B/PAL,
+G/PAL and I/PAL signals. The first enumerated standard is a set of B
+and G/PAL, switched automatically depending on the selected radio
+frequency in UHF or VHF band. Enumeration gives a "PAL-B/G" or "PAL-I"
+choice. Similar a Composite input may collapse standards, enumerating
+"PAL-B/G/H/I", "NTSC-M" and "SECAM-D/K".<footnote>
+       <para>Some users are already confused by technical terms PAL,
+NTSC and SECAM. There is no point asking them to distinguish between
+B, G, D, or K when the software or hardware can do that
+automatically.</para>
+    </footnote></para>
+
+    <para>To query and select the standard used by the current video
+input or output applications call the &VIDIOC-G-STD; and
+&VIDIOC-S-STD; ioctl, respectively. The <emphasis>received</emphasis>
+standard can be sensed with the &VIDIOC-QUERYSTD; ioctl. Note parameter of all these ioctls is a pointer to a &v4l2-std-id; type (a standard set), <emphasis>not</emphasis> an index into the standard enumeration.<footnote>
+       <para>An alternative to the current scheme is to use pointers
+to indices as arguments of <constant>VIDIOC_G_STD</constant> and
+<constant>VIDIOC_S_STD</constant>, the &v4l2-input; and
+&v4l2-output; <structfield>std</structfield> field would be a set of
+indices like <structfield>audioset</structfield>.</para>
+       <para>Indices are consistent with the rest of the API
+and identify the standard unambiguously. In the present scheme of
+things an enumerated standard is looked up by &v4l2-std-id;. Now the
+standards supported by the inputs of a device can overlap. Just
+assume the tuner and composite input in the example above both
+exist on a device. An enumeration of "PAL-B/G", "PAL-H/I" suggests
+a choice which does not exist. We cannot merge or omit sets, because
+applications would be unable to find the standards reported by
+<constant>VIDIOC_G_STD</constant>. That leaves separate enumerations
+for each input. Also selecting a standard by &v4l2-std-id; can be
+ambiguous. Advantage of this method is that applications need not
+identify the standard indirectly, after enumerating.</para><para>So in
+summary, the lookup itself is unavoidable. The difference is only
+whether the lookup is necessary to find an enumerated standard or to
+switch to a standard by &v4l2-std-id;.</para>
+      </footnote> Drivers must implement all video standard ioctls
+when the device has one or more video inputs or outputs.</para>
+
+    <para>Special rules apply to USB cameras where the notion of video
+standards makes little sense. More generally any capture device,
+output devices accordingly, which is <itemizedlist>
+       <listitem>
+         <para>incapable of capturing fields or frames at the nominal
+rate of the video standard, or</para>
+       </listitem>
+       <listitem>
+         <para>where <link linkend="buffer">timestamps</link> refer
+to the instant the field or frame was received by the driver, not the
+capture time, or</para>
+       </listitem>
+       <listitem>
+         <para>where <link linkend="buffer">sequence numbers</link>
+refer to the frames received by the driver, not the captured
+frames.</para>
+       </listitem>
+      </itemizedlist> Here the driver shall set the
+<structfield>std</structfield> field of &v4l2-input; and &v4l2-output;
+to zero, the <constant>VIDIOC_G_STD</constant>,
+<constant>VIDIOC_S_STD</constant>,
+<constant>VIDIOC_QUERYSTD</constant> and
+<constant>VIDIOC_ENUMSTD</constant> ioctls shall return the
+&EINVAL;.<footnote>
+       <para>See <xref linkend="buffer" /> for a rationale. Probably
+even USB cameras follow some well known video standard. It might have
+been better to explicitly indicate elsewhere if a device cannot live
+up to normal expectations, instead of this exception.</para>
+           </footnote></para>
+
+    <example>
+      <title>Information about the current video standard</title>
+
+      <programlisting>
+&v4l2-std-id; std_id;
+&v4l2-standard; standard;
+
+if (-1 == ioctl (fd, &VIDIOC-G-STD;, &amp;std_id)) {
+       /* Note when VIDIOC_ENUMSTD always returns EINVAL this
+          is no video device or it falls under the USB exception,
+          and VIDIOC_G_STD returning EINVAL is no error. */
+
+       perror ("VIDIOC_G_STD");
+       exit (EXIT_FAILURE);
+}
+
+memset (&amp;standard, 0, sizeof (standard));
+standard.index = 0;
+
+while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
+       if (standard.id &amp; std_id) {
+              printf ("Current video standard: %s\n", standard.name);
+              exit (EXIT_SUCCESS);
+       }
+
+       standard.index++;
+}
+
+/* EINVAL indicates the end of the enumeration, which cannot be
+   empty unless this device falls under the USB exception. */
+
+if (errno == EINVAL || standard.index == 0) {
+       perror ("VIDIOC_ENUMSTD");
+       exit (EXIT_FAILURE);
+}
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Listing the video standards supported by the current
+input</title>
+
+      <programlisting>
+&v4l2-input; input;
+&v4l2-standard; standard;
+
+memset (&amp;input, 0, sizeof (input));
+
+if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &amp;input.index)) {
+       perror ("VIDIOC_G_INPUT");
+       exit (EXIT_FAILURE);
+}
+
+if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
+       perror ("VIDIOC_ENUM_INPUT");
+       exit (EXIT_FAILURE);
+}
+
+printf ("Current input %s supports:\n", input.name);
+
+memset (&amp;standard, 0, sizeof (standard));
+standard.index = 0;
+
+while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
+       if (standard.id &amp; input.std)
+               printf ("%s\n", standard.name);
+
+       standard.index++;
+}
+
+/* EINVAL indicates the end of the enumeration, which cannot be
+   empty unless this device falls under the USB exception. */
+
+if (errno != EINVAL || standard.index == 0) {
+       perror ("VIDIOC_ENUMSTD");
+       exit (EXIT_FAILURE);
+}
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Selecting a new video standard</title>
+
+      <programlisting>
+&v4l2-input; input;
+&v4l2-std-id; std_id;
+
+memset (&amp;input, 0, sizeof (input));
+
+if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &amp;input.index)) {
+       perror ("VIDIOC_G_INPUT");
+       exit (EXIT_FAILURE);
+}
+
+if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
+       perror ("VIDIOC_ENUM_INPUT");
+       exit (EXIT_FAILURE);
+}
+
+if (0 == (input.std &amp; V4L2_STD_PAL_BG)) {
+       fprintf (stderr, "Oops. B/G PAL is not supported.\n");
+       exit (EXIT_FAILURE);
+}
+
+/* Note this is also supposed to work when only B
+   <emphasis>or</emphasis> G/PAL is supported. */
+
+std_id = V4L2_STD_PAL_BG;
+
+if (-1 == ioctl (fd, &VIDIOC-S-STD;, &amp;std_id)) {
+       perror ("VIDIOC_S_STD");
+       exit (EXIT_FAILURE);
+}
+      </programlisting>
+    </example>
+  <section id="dv-timings">
+       <title>Digital Video (DV) Timings</title>
+       <para>
+       The video standards discussed so far has been dealing with Analog TV and the
+corresponding video timings. Today there are many more different hardware interfaces
+such as High Definition TV interfaces (HDMI), VGA, DVI connectors etc., that carry
+video signals and there is a need to extend the API to select the video timings
+for these interfaces. Since it is not possible to extend the &v4l2-std-id; due to
+the limited bits available, a new set of IOCTLs is added to set/get video timings at
+the input and output: </para><itemizedlist>
+       <listitem>
+       <para>DV Presets: Digital Video (DV) presets. These are IDs representing a
+video timing at the input/output. Presets are pre-defined timings implemented
+by the hardware according to video standards. A __u32 data type is used to represent
+a preset unlike the bit mask that is used in &v4l2-std-id; allowing future extensions
+to support as many different presets as needed.</para>
+       </listitem>
+       <listitem>
+       <para>Custom DV Timings: This will allow applications to define more detailed
+custom video timings for the interface. This includes parameters such as width, height,
+polarities, frontporch, backporch etc.
+       </para>
+       </listitem>
+       </itemizedlist>
+       <para>To enumerate and query the attributes of DV presets supported by a device,
+applications use the &VIDIOC-ENUM-DV-PRESETS; ioctl. To get the current DV preset,
+applications use the &VIDIOC-G-DV-PRESET; ioctl and to set a preset they use the
+&VIDIOC-S-DV-PRESET; ioctl.</para>
+       <para>To set custom DV timings for the device, applications use the
+&VIDIOC-S-DV-TIMINGS; ioctl and to get current custom DV timings they use the
+&VIDIOC-G-DV-TIMINGS; ioctl.</para>
+       <para>Applications can make use of the <xref linkend="input-capabilities" /> and
+<xref linkend="output-capabilities"/> flags to decide what ioctls are available to set the
+video timings for the device.</para>
+       </section>
+  </section>
+
+  &sub-controls;
+
+  <section id="format">
+    <title>Data Formats</title>
+
+    <section>
+      <title>Data Format Negotiation</title>
+
+      <para>Different devices exchange different kinds of data with
+applications, for example video images, raw or sliced VBI data, RDS
+datagrams. Even within one kind many different formats are possible,
+in particular an abundance of image formats. Although drivers must
+provide a default and the selection persists across closing and
+reopening a device, applications should always negotiate a data format
+before engaging in data exchange. Negotiation means the application
+asks for a particular format and the driver selects and reports the
+best the hardware can do to satisfy the request. Of course
+applications can also just query the current selection.</para>
+
+      <para>A single mechanism exists to negotiate all data formats
+using the aggregate &v4l2-format; and the &VIDIOC-G-FMT; and
+&VIDIOC-S-FMT; ioctls. Additionally the &VIDIOC-TRY-FMT; ioctl can be
+used to examine what the hardware <emphasis>could</emphasis> do,
+without actually selecting a new data format. The data formats
+supported by the V4L2 API are covered in the respective device section
+in <xref linkend="devices" />. For a closer look at image formats see
+<xref linkend="pixfmt" />.</para>
+
+      <para>The <constant>VIDIOC_S_FMT</constant> ioctl is a major
+turning-point in the initialization sequence. Prior to this point
+multiple panel applications can access the same device concurrently to
+select the current input, change controls or modify other properties.
+The first <constant>VIDIOC_S_FMT</constant> assigns a logical stream
+(video data, VBI data etc.) exclusively to one file descriptor.</para>
+
+      <para>Exclusive means no other application, more precisely no
+other file descriptor, can grab this stream or change device
+properties inconsistent with the negotiated parameters. A video
+standard change for example, when the new standard uses a different
+number of scan lines, can invalidate the selected image format.
+Therefore only the file descriptor owning the stream can make
+invalidating changes. Accordingly multiple file descriptors which
+grabbed different logical streams prevent each other from interfering
+with their settings. When for example video overlay is about to start
+or already in progress, simultaneous video capturing may be restricted
+to the same cropping and image size.</para>
+
+      <para>When applications omit the
+<constant>VIDIOC_S_FMT</constant> ioctl its locking side effects are
+implied by the next step, the selection of an I/O method with the
+&VIDIOC-REQBUFS; ioctl or implicit with the first &func-read; or
+&func-write; call.</para>
+
+      <para>Generally only one logical stream can be assigned to a
+file descriptor, the exception being drivers permitting simultaneous
+video capturing and overlay using the same file descriptor for
+compatibility with V4L and earlier versions of V4L2. Switching the
+logical stream or returning into "panel mode" is possible by closing
+and reopening the device. Drivers <emphasis>may</emphasis> support a
+switch using <constant>VIDIOC_S_FMT</constant>.</para>
+
+      <para>All drivers exchanging data with
+applications must support the <constant>VIDIOC_G_FMT</constant> and
+<constant>VIDIOC_S_FMT</constant> ioctl. Implementation of the
+<constant>VIDIOC_TRY_FMT</constant> is highly recommended but
+optional.</para>
+    </section>
+
+    <section>
+      <title>Image Format Enumeration</title>
+
+      <para>Apart of the generic format negotiation functions
+a special ioctl to enumerate all image formats supported by video
+capture, overlay or output devices is available.<footnote>
+         <para>Enumerating formats an application has no a-priori
+knowledge of (otherwise it could explicitly ask for them and need not
+enumerate) seems useless, but there are applications serving as proxy
+between drivers and the actual video applications for which this is
+useful.</para>
+       </footnote></para>
+
+      <para>The &VIDIOC-ENUM-FMT; ioctl must be supported
+by all drivers exchanging image data with applications.</para>
+
+      <important>
+       <para>Drivers are not supposed to convert image formats in
+kernel space. They must enumerate only formats directly supported by
+the hardware. If necessary driver writers should publish an example
+conversion routine or library for integration into applications.</para>
+      </important>
+    </section>
+  </section>
+
+  &sub-planar-apis;
+
+  <section id="crop">
+    <title>Image Cropping, Insertion and Scaling</title>
+
+    <para>Some video capture devices can sample a subsection of the
+picture and shrink or enlarge it to an image of arbitrary size. We
+call these abilities cropping and scaling. Some video output devices
+can scale an image up or down and insert it at an arbitrary scan line
+and horizontal offset into a video signal.</para>
+
+    <para>Applications can use the following API to select an area in
+the video signal, query the default area and the hardware limits.
+<emphasis>Despite their name, the &VIDIOC-CROPCAP;, &VIDIOC-G-CROP;
+and &VIDIOC-S-CROP; ioctls apply to input as well as output
+devices.</emphasis></para>
+
+    <para>Scaling requires a source and a target. On a video capture
+or overlay device the source is the video signal, and the cropping
+ioctls determine the area actually sampled. The target are images
+read by the application or overlaid onto the graphics screen. Their
+size (and position for an overlay) is negotiated with the
+&VIDIOC-G-FMT; and &VIDIOC-S-FMT; ioctls.</para>
+
+    <para>On a video output device the source are the images passed in
+by the application, and their size is again negotiated with the
+<constant>VIDIOC_G/S_FMT</constant> ioctls, or may be encoded in a
+compressed video stream. The target is the video signal, and the
+cropping ioctls determine the area where the images are
+inserted.</para>
+
+    <para>Source and target rectangles are defined even if the device
+does not support scaling or the <constant>VIDIOC_G/S_CROP</constant>
+ioctls. Their size (and position where applicable) will be fixed in
+this case. <emphasis>All capture and output device must support the
+<constant>VIDIOC_CROPCAP</constant> ioctl such that applications can
+determine if scaling takes place.</emphasis></para>
+
+    <section>
+      <title>Cropping Structures</title>
+
+      <figure id="crop-scale">
+       <title>Image Cropping, Insertion and Scaling</title>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="crop.pdf" format="PS" />
+         </imageobject>
+         <imageobject>
+           <imagedata fileref="crop.gif" format="GIF" />
+         </imageobject>
+         <textobject>
+           <phrase>The cropping, insertion and scaling process</phrase>
+         </textobject>
+       </mediaobject>
+      </figure>
+
+      <para>For capture devices the coordinates of the top left
+corner, width and height of the area which can be sampled is given by
+the <structfield>bounds</structfield> substructure of the
+&v4l2-cropcap; returned by the <constant>VIDIOC_CROPCAP</constant>
+ioctl. To support a wide range of hardware this specification does not
+define an origin or units. However by convention drivers should
+horizontally count unscaled samples relative to 0H (the leading edge
+of the horizontal sync pulse, see <xref linkend="vbi-hsync" />).
+Vertically ITU-R line
+numbers of the first field (<xref linkend="vbi-525" />, <xref
+linkend="vbi-625" />), multiplied by two if the driver can capture both
+fields.</para>
+
+      <para>The top left corner, width and height of the source
+rectangle, that is the area actually sampled, is given by &v4l2-crop;
+using the same coordinate system as &v4l2-cropcap;. Applications can
+use the <constant>VIDIOC_G_CROP</constant> and
+<constant>VIDIOC_S_CROP</constant> ioctls to get and set this
+rectangle. It must lie completely within the capture boundaries and
+the driver may further adjust the requested size and/or position
+according to hardware limitations.</para>
+
+      <para>Each capture device has a default source rectangle, given
+by the <structfield>defrect</structfield> substructure of
+&v4l2-cropcap;. The center of this rectangle shall align with the
+center of the active picture area of the video signal, and cover what
+the driver writer considers the complete picture. Drivers shall reset
+the source rectangle to the default when the driver is first loaded,
+but not later.</para>
+
+      <para>For output devices these structures and ioctls are used
+accordingly, defining the <emphasis>target</emphasis> rectangle where
+the images will be inserted into the video signal.</para>
+
+    </section>
+
+    <section>
+      <title>Scaling Adjustments</title>
+
+      <para>Video hardware can have various cropping, insertion and
+scaling limitations. It may only scale up or down, support only
+discrete scaling factors, or have different scaling abilities in
+horizontal and vertical direction. Also it may not support scaling at
+all. At the same time the &v4l2-crop; rectangle may have to be
+aligned, and both the source and target rectangles may have arbitrary
+upper and lower size limits. In particular the maximum
+<structfield>width</structfield> and <structfield>height</structfield>
+in &v4l2-crop; may be smaller than the
+&v4l2-cropcap;.<structfield>bounds</structfield> area. Therefore, as
+usual, drivers are expected to adjust the requested parameters and
+return the actual values selected.</para>
+
+      <para>Applications can change the source or the target rectangle
+first, as they may prefer a particular image size or a certain area in
+the video signal. If the driver has to adjust both to satisfy hardware
+limitations, the last requested rectangle shall take priority, and the
+driver should preferably adjust the opposite one. The &VIDIOC-TRY-FMT;
+ioctl however shall not change the driver state and therefore only
+adjust the requested rectangle.</para>
+
+      <para>Suppose scaling on a video capture device is restricted to
+a factor 1:1 or 2:1 in either direction and the target image size must
+be a multiple of 16&nbsp;&times;&nbsp;16 pixels. The source cropping
+rectangle is set to defaults, which are also the upper limit in this
+example, of 640&nbsp;&times;&nbsp;400 pixels at offset 0,&nbsp;0. An
+application requests an image size of 300&nbsp;&times;&nbsp;225
+pixels, assuming video will be scaled down from the "full picture"
+accordingly. The driver sets the image size to the closest possible
+values 304&nbsp;&times;&nbsp;224, then chooses the cropping rectangle
+closest to the requested size, that is 608&nbsp;&times;&nbsp;224
+(224&nbsp;&times;&nbsp;2:1 would exceed the limit 400). The offset
+0,&nbsp;0 is still valid, thus unmodified. Given the default cropping
+rectangle reported by <constant>VIDIOC_CROPCAP</constant> the
+application can easily propose another offset to center the cropping
+rectangle.</para>
+
+      <para>Now the application may insist on covering an area using a
+picture aspect ratio closer to the original request, so it asks for a
+cropping rectangle of 608&nbsp;&times;&nbsp;456 pixels. The present
+scaling factors limit cropping to 640&nbsp;&times;&nbsp;384, so the
+driver returns the cropping size 608&nbsp;&times;&nbsp;384 and adjusts
+the image size to closest possible 304&nbsp;&times;&nbsp;192.</para>
+
+    </section>
+
+    <section>
+      <title>Examples</title>
+
+      <para>Source and target rectangles shall remain unchanged across
+closing and reopening a device, such that piping data into or out of a
+device will work without special preparations. More advanced
+applications should ensure the parameters are suitable before starting
+I/O.</para>
+
+      <example>
+       <title>Resetting the cropping parameters</title>
+
+       <para>(A video capture device is assumed; change
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> for other
+devices.)</para>
+
+       <programlisting>
+&v4l2-cropcap; cropcap;
+&v4l2-crop; crop;
+
+memset (&amp;cropcap, 0, sizeof (cropcap));
+cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+if (-1 == ioctl (fd, &VIDIOC-CROPCAP;, &amp;cropcap)) {
+       perror ("VIDIOC_CROPCAP");
+       exit (EXIT_FAILURE);
+}
+
+memset (&amp;crop, 0, sizeof (crop));
+crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+crop.c = cropcap.defrect;
+
+/* Ignore if cropping is not supported (EINVAL). */
+
+if (-1 == ioctl (fd, &VIDIOC-S-CROP;, &amp;crop)
+    &amp;&amp; errno != EINVAL) {
+       perror ("VIDIOC_S_CROP");
+       exit (EXIT_FAILURE);
+}
+      </programlisting>
+      </example>
+
+      <example>
+       <title>Simple downscaling</title>
+
+       <para>(A video capture device is assumed.)</para>
+
+       <programlisting>
+&v4l2-cropcap; cropcap;
+&v4l2-format; format;
+
+reset_cropping_parameters ();
+
+/* Scale down to 1/4 size of full picture. */
+
+memset (&amp;format, 0, sizeof (format)); /* defaults */
+
+format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+format.fmt.pix.width = cropcap.defrect.width &gt;&gt; 1;
+format.fmt.pix.height = cropcap.defrect.height &gt;&gt; 1;
+format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+
+if (-1 == ioctl (fd, &VIDIOC-S-FMT;, &amp;format)) {
+       perror ("VIDIOC_S_FORMAT");
+       exit (EXIT_FAILURE);
+}
+
+/* We could check the actual image size now, the actual scaling factor
+   or if the driver can scale at all. */
+       </programlisting>
+      </example>
+
+      <example>
+       <title>Selecting an output area</title>
+
+       <programlisting>
+&v4l2-cropcap; cropcap;
+&v4l2-crop; crop;
+
+memset (&amp;cropcap, 0, sizeof (cropcap));
+cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+if (-1 == ioctl (fd, VIDIOC_CROPCAP;, &amp;cropcap)) {
+       perror ("VIDIOC_CROPCAP");
+       exit (EXIT_FAILURE);
+}
+
+memset (&amp;crop, 0, sizeof (crop));
+
+crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+crop.c = cropcap.defrect;
+
+/* Scale the width and height to 50 % of their original size
+   and center the output. */
+
+crop.c.width /= 2;
+crop.c.height /= 2;
+crop.c.left += crop.c.width / 2;
+crop.c.top += crop.c.height / 2;
+
+/* Ignore if cropping is not supported (EINVAL). */
+
+if (-1 == ioctl (fd, VIDIOC_S_CROP, &amp;crop)
+    &amp;&amp; errno != EINVAL) {
+       perror ("VIDIOC_S_CROP");
+       exit (EXIT_FAILURE);
+}
+</programlisting>
+      </example>
+
+      <example>
+       <title>Current scaling factor and pixel aspect</title>
+
+       <para>(A video capture device is assumed.)</para>
+
+       <programlisting>
+&v4l2-cropcap; cropcap;
+&v4l2-crop; crop;
+&v4l2-format; format;
+double hscale, vscale;
+double aspect;
+int dwidth, dheight;
+
+memset (&amp;cropcap, 0, sizeof (cropcap));
+cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+if (-1 == ioctl (fd, &VIDIOC-CROPCAP;, &amp;cropcap)) {
+       perror ("VIDIOC_CROPCAP");
+       exit (EXIT_FAILURE);
+}
+
+memset (&amp;crop, 0, sizeof (crop));
+crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+if (-1 == ioctl (fd, &VIDIOC-G-CROP;, &amp;crop)) {
+       if (errno != EINVAL) {
+               perror ("VIDIOC_G_CROP");
+               exit (EXIT_FAILURE);
+       }
+
+       /* Cropping not supported. */
+       crop.c = cropcap.defrect;
+}
+
+memset (&amp;format, 0, sizeof (format));
+format.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+if (-1 == ioctl (fd, &VIDIOC-G-FMT;, &amp;format)) {
+       perror ("VIDIOC_G_FMT");
+       exit (EXIT_FAILURE);
+}
+
+/* The scaling applied by the driver. */
+
+hscale = format.fmt.pix.width / (double) crop.c.width;
+vscale = format.fmt.pix.height / (double) crop.c.height;
+
+aspect = cropcap.pixelaspect.numerator /
+        (double) cropcap.pixelaspect.denominator;
+aspect = aspect * hscale / vscale;
+
+/* Devices following ITU-R BT.601 do not capture
+   square pixels. For playback on a computer monitor
+   we should scale the images to this size. */
+
+dwidth = format.fmt.pix.width / aspect;
+dheight = format.fmt.pix.height;
+       </programlisting>
+      </example>
+    </section>
+  </section>
+
+  <section id="streaming-par">
+    <title>Streaming Parameters</title>
+
+    <para>Streaming parameters are intended to optimize the video
+capture process as well as I/O. Presently applications can request a
+high quality capture mode with the &VIDIOC-S-PARM; ioctl.</para>
+
+    <para>The current video standard determines a nominal number of
+frames per second. If less than this number of frames is to be
+captured or output, applications can request frame skipping or
+duplicating on the driver side. This is especially useful when using
+the &func-read; or &func-write;, which are not augmented by timestamps
+or sequence counters, and to avoid unnecessary data copying.</para>
+
+    <para>Finally these ioctls can be used to determine the number of
+buffers used internally by a driver in read/write mode. For
+implications see the section discussing the &func-read;
+function.</para>
+
+    <para>To get and set the streaming parameters applications call
+the &VIDIOC-G-PARM; and &VIDIOC-S-PARM; ioctl, respectively. They take
+a pointer to a &v4l2-streamparm;, which contains a union holding
+separate parameters for input and output devices.</para>
+
+    <para>These ioctls are optional, drivers need not implement
+them. If so, they return the &EINVAL;.</para>
+  </section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
new file mode 100644 (file)
index 0000000..ce1004a
--- /dev/null
@@ -0,0 +1,2506 @@
+  <title>Changes</title>
+
+  <para>The following chapters document the evolution of the V4L2 API,
+errata or extensions. They are also intended to help application and
+driver writers to port or update their code.</para>
+
+  <section id="diff-v4l">
+    <title>Differences between V4L and V4L2</title>
+
+    <para>The Video For Linux API was first introduced in Linux 2.1 to
+unify and replace various TV and radio device related interfaces,
+developed independently by driver writers in prior years. Starting
+with Linux 2.5 the much improved V4L2 API replaces the V4L API.
+The support for the old V4L calls were removed from Kernel, but the
+library <xref linkend="libv4l" /> supports the conversion of a V4L
+API system call into a V4L2 one.</para>
+
+    <section>
+      <title>Opening and Closing Devices</title>
+
+      <para>For compatibility reasons the character device file names
+recommended for V4L2 video capture, overlay, radio and raw
+vbi capture devices did not change from those used by V4L. They are
+listed in <xref linkend="devices" /> and below in <xref
+         linkend="v4l-dev" />.</para>
+
+      <para>The teletext devices (minor range 192-223) have been removed in
+V4L2 and no longer exist. There is no hardware available anymore for handling
+pure teletext. Instead raw or sliced VBI is used.</para>
+
+      <para>The V4L <filename>videodev</filename> module automatically
+assigns minor numbers to drivers in load order, depending on the
+registered device type. We recommend that V4L2 drivers by default
+register devices with the same numbers, but the system administrator
+can assign arbitrary minor numbers using driver module options. The
+major device number remains 81.</para>
+
+      <table id="v4l-dev">
+       <title>V4L Device Types, Names and Numbers</title>
+       <tgroup cols="3">
+         <thead>
+           <row>
+             <entry>Device Type</entry>
+             <entry>File Name</entry>
+             <entry>Minor Numbers</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row>
+             <entry>Video capture and overlay</entry>
+             <entry><para><filename>/dev/video</filename> and
+<filename>/dev/bttv0</filename><footnote> <para>According to
+Documentation/devices.txt these should be symbolic links to
+<filename>/dev/video0</filename>. Note the original bttv interface is
+not compatible with V4L or V4L2.</para> </footnote>,
+<filename>/dev/video0</filename> to
+<filename>/dev/video63</filename></para></entry>
+             <entry>0-63</entry>
+           </row>
+           <row>
+             <entry>Radio receiver</entry>
+             <entry><para><filename>/dev/radio</filename><footnote>
+                   <para>According to
+<filename>Documentation/devices.txt</filename> a symbolic link to
+<filename>/dev/radio0</filename>.</para>
+                 </footnote>, <filename>/dev/radio0</filename> to
+<filename>/dev/radio63</filename></para></entry>
+             <entry>64-127</entry>
+           </row>
+           <row>
+             <entry>Raw VBI capture</entry>
+             <entry><para><filename>/dev/vbi</filename>,
+<filename>/dev/vbi0</filename> to
+<filename>/dev/vbi31</filename></para></entry>
+             <entry>224-255</entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+
+      <para>V4L prohibits (or used to prohibit) multiple opens of a
+device file. V4L2 drivers <emphasis>may</emphasis> support multiple
+opens, see <xref linkend="open" /> for details and consequences.</para>
+
+      <para>V4L drivers respond to V4L2 ioctls with an &EINVAL;.</para>
+    </section>
+
+    <section>
+      <title>Querying Capabilities</title>
+
+      <para>The V4L <constant>VIDIOCGCAP</constant> ioctl is
+equivalent to V4L2's &VIDIOC-QUERYCAP;.</para>
+
+      <para>The <structfield>name</structfield> field in struct
+<structname>video_capability</structname> became
+<structfield>card</structfield> in &v4l2-capability;,
+<structfield>type</structfield> was replaced by
+<structfield>capabilities</structfield>. Note V4L2 does not
+distinguish between device types like this, better think of basic
+video input, video output and radio devices supporting a set of
+related functions like video capturing, video overlay and VBI
+capturing. See <xref linkend="open" /> for an
+introduction.<informaltable>
+         <tgroup cols="3">
+           <thead>
+             <row>
+               <entry>struct
+<structname>video_capability</structname>
+<structfield>type</structfield></entry>
+               <entry>&v4l2-capability;
+<structfield>capabilities</structfield> flags</entry>
+               <entry>Purpose</entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row>
+               <entry><constant>VID_TYPE_CAPTURE</constant></entry>
+               <entry><constant>V4L2_CAP_VIDEO_CAPTURE</constant></entry>
+               <entry>The <link linkend="capture">video
+capture</link> interface is supported.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_TUNER</constant></entry>
+               <entry><constant>V4L2_CAP_TUNER</constant></entry>
+               <entry>The device has a <link linkend="tuner">tuner or
+modulator</link>.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_TELETEXT</constant></entry>
+               <entry><constant>V4L2_CAP_VBI_CAPTURE</constant></entry>
+               <entry>The <link linkend="raw-vbi">raw VBI
+capture</link> interface is supported.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_OVERLAY</constant></entry>
+               <entry><constant>V4L2_CAP_VIDEO_OVERLAY</constant></entry>
+               <entry>The <link linkend="overlay">video
+overlay</link> interface is supported.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_CHROMAKEY</constant></entry>
+               <entry><constant>V4L2_FBUF_CAP_CHROMAKEY</constant> in
+field <structfield>capability</structfield> of
+&v4l2-framebuffer;</entry>
+               <entry>Whether chromakey overlay is supported. For
+more information on overlay see
+<xref linkend="overlay" />.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_CLIPPING</constant></entry>
+               <entry><constant>V4L2_FBUF_CAP_LIST_CLIPPING</constant>
+and <constant>V4L2_FBUF_CAP_BITMAP_CLIPPING</constant> in field
+<structfield>capability</structfield> of &v4l2-framebuffer;</entry>
+               <entry>Whether clipping the overlaid image is
+supported, see <xref linkend="overlay" />.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_FRAMERAM</constant></entry>
+               <entry><constant>V4L2_FBUF_CAP_EXTERNOVERLAY</constant>
+<emphasis>not set</emphasis> in field
+<structfield>capability</structfield> of &v4l2-framebuffer;</entry>
+               <entry>Whether overlay overwrites frame buffer memory,
+see <xref linkend="overlay" />.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_SCALES</constant></entry>
+               <entry><constant>-</constant></entry>
+               <entry>This flag indicates if the hardware can scale
+images. The V4L2 API implies the scale factor by setting the cropping
+dimensions and image size with the &VIDIOC-S-CROP; and &VIDIOC-S-FMT;
+ioctl, respectively. The driver returns the closest sizes possible.
+For more information on cropping and scaling see <xref
+                   linkend="crop" />.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_MONOCHROME</constant></entry>
+               <entry><constant>-</constant></entry>
+               <entry>Applications can enumerate the supported image
+formats with the &VIDIOC-ENUM-FMT; ioctl to determine if the device
+supports grey scale capturing only. For more information on image
+formats see <xref linkend="pixfmt" />.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_SUBCAPTURE</constant></entry>
+               <entry><constant>-</constant></entry>
+               <entry>Applications can call the &VIDIOC-G-CROP; ioctl
+to determine if the device supports capturing a subsection of the full
+picture ("cropping" in V4L2). If not, the ioctl returns the &EINVAL;.
+For more information on cropping and scaling see <xref
+                   linkend="crop" />.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_MPEG_DECODER</constant></entry>
+               <entry><constant>-</constant></entry>
+               <entry>Applications can enumerate the supported image
+formats with the &VIDIOC-ENUM-FMT; ioctl to determine if the device
+supports MPEG streams.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_MPEG_ENCODER</constant></entry>
+               <entry><constant>-</constant></entry>
+               <entry>See above.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_MJPEG_DECODER</constant></entry>
+               <entry><constant>-</constant></entry>
+               <entry>See above.</entry>
+             </row>
+             <row>
+               <entry><constant>VID_TYPE_MJPEG_ENCODER</constant></entry>
+               <entry><constant>-</constant></entry>
+               <entry>See above.</entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </informaltable></para>
+
+      <para>The <structfield>audios</structfield> field was replaced
+by <structfield>capabilities</structfield> flag
+<constant>V4L2_CAP_AUDIO</constant>, indicating
+<emphasis>if</emphasis> the device has any audio inputs or outputs. To
+determine their number applications can enumerate audio inputs with
+the &VIDIOC-G-AUDIO; ioctl. The audio ioctls are described in <xref
+         linkend="audio" />.</para>
+
+      <para>The <structfield>maxwidth</structfield>,
+<structfield>maxheight</structfield>,
+<structfield>minwidth</structfield> and
+<structfield>minheight</structfield> fields were removed. Calling the
+&VIDIOC-S-FMT; or &VIDIOC-TRY-FMT; ioctl with the desired dimensions
+returns the closest size possible, taking into account the current
+video standard, cropping and scaling limitations.</para>
+    </section>
+
+    <section>
+      <title>Video Sources</title>
+
+      <para>V4L provides the <constant>VIDIOCGCHAN</constant> and
+<constant>VIDIOCSCHAN</constant> ioctl using struct
+<structname>video_channel</structname> to enumerate
+the video inputs of a V4L device. The equivalent V4L2 ioctls
+are &VIDIOC-ENUMINPUT;, &VIDIOC-G-INPUT; and &VIDIOC-S-INPUT;
+using &v4l2-input; as discussed in <xref linkend="video" />.</para>
+
+      <para>The <structfield>channel</structfield> field counting
+inputs was renamed to <structfield>index</structfield>, the video
+input types were renamed as follows: <informaltable>
+         <tgroup cols="2">
+           <thead>
+             <row>
+               <entry>struct <structname>video_channel</structname>
+<structfield>type</structfield></entry>
+               <entry>&v4l2-input;
+<structfield>type</structfield></entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row>
+               <entry><constant>VIDEO_TYPE_TV</constant></entry>
+               <entry><constant>V4L2_INPUT_TYPE_TUNER</constant></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_TYPE_CAMERA</constant></entry>
+               <entry><constant>V4L2_INPUT_TYPE_CAMERA</constant></entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </informaltable></para>
+
+      <para>Unlike the <structfield>tuners</structfield> field
+expressing the number of tuners of this input, V4L2 assumes each video
+input is connected to at most one tuner. However a tuner can have more
+than one input, &ie; RF connectors, and a device can have multiple
+tuners. The index number of the tuner associated with the input, if
+any, is stored in field <structfield>tuner</structfield> of
+&v4l2-input;. Enumeration of tuners is discussed in <xref
+         linkend="tuner" />.</para>
+
+      <para>The redundant <constant>VIDEO_VC_TUNER</constant> flag was
+dropped. Video inputs associated with a tuner are of type
+<constant>V4L2_INPUT_TYPE_TUNER</constant>. The
+<constant>VIDEO_VC_AUDIO</constant> flag was replaced by the
+<structfield>audioset</structfield> field. V4L2 considers devices with
+up to 32 audio inputs. Each set bit in the
+<structfield>audioset</structfield> field represents one audio input
+this video input combines with. For information about audio inputs and
+how to switch between them see <xref linkend="audio" />.</para>
+
+      <para>The <structfield>norm</structfield> field describing the
+supported video standards was replaced by
+<structfield>std</structfield>. The V4L specification mentions a flag
+<constant>VIDEO_VC_NORM</constant> indicating whether the standard can
+be changed. This flag was a later addition together with the
+<structfield>norm</structfield> field and has been removed in the
+meantime. V4L2 has a similar, albeit more comprehensive approach
+to video standards, see <xref linkend="standard" /> for more
+information.</para>
+    </section>
+
+    <section>
+      <title>Tuning</title>
+
+      <para>The V4L <constant>VIDIOCGTUNER</constant> and
+<constant>VIDIOCSTUNER</constant> ioctl and struct
+<structname>video_tuner</structname> can be used to enumerate the
+tuners of a V4L TV or radio device. The equivalent V4L2 ioctls are
+&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; using &v4l2-tuner;. Tuners are
+covered in <xref linkend="tuner" />.</para>
+
+      <para>The <structfield>tuner</structfield> field counting tuners
+was renamed to <structfield>index</structfield>. The fields
+<structfield>name</structfield>, <structfield>rangelow</structfield>
+and <structfield>rangehigh</structfield> remained unchanged.</para>
+
+      <para>The <constant>VIDEO_TUNER_PAL</constant>,
+<constant>VIDEO_TUNER_NTSC</constant> and
+<constant>VIDEO_TUNER_SECAM</constant> flags indicating the supported
+video standards were dropped. This information is now contained in the
+associated &v4l2-input;. No replacement exists for the
+<constant>VIDEO_TUNER_NORM</constant> flag indicating whether the
+video standard can be switched. The <structfield>mode</structfield>
+field to select a different video standard was replaced by a whole new
+set of ioctls and structures described in <xref linkend="standard" />.
+Due to its ubiquity it should be mentioned the BTTV driver supports
+several standards in addition to the regular
+<constant>VIDEO_MODE_PAL</constant> (0),
+<constant>VIDEO_MODE_NTSC</constant>,
+<constant>VIDEO_MODE_SECAM</constant> and
+<constant>VIDEO_MODE_AUTO</constant> (3). Namely N/PAL Argentina,
+M/PAL, N/PAL, and NTSC Japan with numbers 3-6 (sic).</para>
+
+      <para>The <constant>VIDEO_TUNER_STEREO_ON</constant> flag
+indicating stereo reception became
+<constant>V4L2_TUNER_SUB_STEREO</constant> in field
+<structfield>rxsubchans</structfield>. This field also permits the
+detection of monaural and bilingual audio, see the definition of
+&v4l2-tuner; for details. Presently no replacement exists for the
+<constant>VIDEO_TUNER_RDS_ON</constant> and
+<constant>VIDEO_TUNER_MBS_ON</constant> flags.</para>
+
+      <para> The <constant>VIDEO_TUNER_LOW</constant> flag was renamed
+to <constant>V4L2_TUNER_CAP_LOW</constant> in the &v4l2-tuner;
+<structfield>capability</structfield> field.</para>
+
+      <para>The <constant>VIDIOCGFREQ</constant> and
+<constant>VIDIOCSFREQ</constant> ioctl to change the tuner frequency
+where renamed to &VIDIOC-G-FREQUENCY; and  &VIDIOC-S-FREQUENCY;. They
+take a pointer to a &v4l2-frequency; instead of an unsigned long
+integer.</para>
+    </section>
+
+    <section id="v4l-image-properties">
+      <title>Image Properties</title>
+
+      <para>V4L2 has no equivalent of the
+<constant>VIDIOCGPICT</constant> and <constant>VIDIOCSPICT</constant>
+ioctl and struct <structname>video_picture</structname>. The following
+fields where replaced by V4L2 controls accessible with the
+&VIDIOC-QUERYCTRL;, &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls:<informaltable>
+         <tgroup cols="2">
+           <thead>
+             <row>
+               <entry>struct <structname>video_picture</structname></entry>
+               <entry>V4L2 Control ID</entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row>
+               <entry><structfield>brightness</structfield></entry>
+               <entry><constant>V4L2_CID_BRIGHTNESS</constant></entry>
+             </row>
+             <row>
+               <entry><structfield>hue</structfield></entry>
+               <entry><constant>V4L2_CID_HUE</constant></entry>
+             </row>
+             <row>
+               <entry><structfield>colour</structfield></entry>
+               <entry><constant>V4L2_CID_SATURATION</constant></entry>
+             </row>
+             <row>
+               <entry><structfield>contrast</structfield></entry>
+               <entry><constant>V4L2_CID_CONTRAST</constant></entry>
+             </row>
+             <row>
+               <entry><structfield>whiteness</structfield></entry>
+               <entry><constant>V4L2_CID_WHITENESS</constant></entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </informaltable></para>
+
+      <para>The V4L picture controls are assumed to range from 0 to
+65535 with no particular reset value. The V4L2 API permits arbitrary
+limits and defaults which can be queried with the &VIDIOC-QUERYCTRL;
+ioctl. For general information about controls see <xref
+linkend="control" />.</para>
+
+      <para>The <structfield>depth</structfield> (average number of
+bits per pixel) of a video image is implied by the selected image
+format. V4L2 does not explicitely provide such information assuming
+applications recognizing the format are aware of the image depth and
+others need not know. The <structfield>palette</structfield> field
+moved into the &v4l2-pix-format;:<informaltable>
+         <tgroup cols="2">
+           <thead>
+             <row>
+               <entry>struct <structname>video_picture</structname>
+<structfield>palette</structfield></entry>
+               <entry>&v4l2-pix-format;
+<structfield>pixfmt</structfield></entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row>
+               <entry><constant>VIDEO_PALETTE_GREY</constant></entry>
+               <entry><para><link
+linkend="V4L2-PIX-FMT-GREY"><constant>V4L2_PIX_FMT_GREY</constant></link></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_HI240</constant></entry>
+               <entry><para><link
+linkend="pixfmt-reserved"><constant>V4L2_PIX_FMT_HI240</constant></link><footnote>
+                     <para>This is a custom format used by the BTTV
+driver, not one of the V4L2 standard formats.</para>
+                   </footnote></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_RGB565</constant></entry>
+               <entry><para><link
+linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_RGB565</constant></link></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_RGB555</constant></entry>
+               <entry><para><link
+linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_RGB555</constant></link></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_RGB24</constant></entry>
+               <entry><para><link
+linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_BGR24</constant></link></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_RGB32</constant></entry>
+               <entry><para><link
+linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_BGR32</constant></link><footnote>
+                     <para>Presumably all V4L RGB formats are
+little-endian, although some drivers might interpret them according to machine endianess. V4L2 defines little-endian, big-endian and red/blue
+swapped variants. For details see <xref linkend="pixfmt-rgb" />.</para>
+                   </footnote></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_YUV422</constant></entry>
+               <entry><para><link
+linkend="V4L2-PIX-FMT-YUYV"><constant>V4L2_PIX_FMT_YUYV</constant></link></para></entry>
+             </row>
+             <row>
+               <entry><para><constant>VIDEO_PALETTE_YUYV</constant><footnote>
+                     <para><constant>VIDEO_PALETTE_YUV422</constant>
+and <constant>VIDEO_PALETTE_YUYV</constant> are the same formats. Some
+V4L drivers respond to one, some to the other.</para>
+                   </footnote></para></entry>
+               <entry><para><link
+linkend="V4L2-PIX-FMT-YUYV"><constant>V4L2_PIX_FMT_YUYV</constant></link></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_UYVY</constant></entry>
+               <entry><para><link
+linkend="V4L2-PIX-FMT-UYVY"><constant>V4L2_PIX_FMT_UYVY</constant></link></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_YUV420</constant></entry>
+               <entry>None</entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_YUV411</constant></entry>
+               <entry><para><link
+linkend="V4L2-PIX-FMT-Y41P"><constant>V4L2_PIX_FMT_Y41P</constant></link><footnote>
+                     <para>Not to be confused with
+<constant>V4L2_PIX_FMT_YUV411P</constant>, which is a planar
+format.</para> </footnote></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_RAW</constant></entry>
+               <entry><para>None<footnote> <para>V4L explains this
+as: "RAW capture (BT848)"</para> </footnote></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_YUV422P</constant></entry>
+               <entry><para><link
+linkend="V4L2-PIX-FMT-YUV422P"><constant>V4L2_PIX_FMT_YUV422P</constant></link></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_YUV411P</constant></entry>
+               <entry><para><link
+linkend="V4L2-PIX-FMT-YUV411P"><constant>V4L2_PIX_FMT_YUV411P</constant></link><footnote>
+                     <para>Not to be confused with
+<constant>V4L2_PIX_FMT_Y41P</constant>, which is a packed
+format.</para> </footnote></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_YUV420P</constant></entry>
+               <entry><para><link
+linkend="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></link></para></entry>
+             </row>
+             <row>
+               <entry><constant>VIDEO_PALETTE_YUV410P</constant></entry>
+               <entry><para><link
+linkend="V4L2-PIX-FMT-YVU410"><constant>V4L2_PIX_FMT_YVU410</constant></link></para></entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </informaltable></para>
+
+      <para>V4L2 image formats are defined in <xref
+linkend="pixfmt" />. The image format can be selected with the
+&VIDIOC-S-FMT; ioctl.</para>
+    </section>
+
+    <section>
+      <title>Audio</title>
+
+      <para>The <constant>VIDIOCGAUDIO</constant> and
+<constant>VIDIOCSAUDIO</constant> ioctl and struct
+<structname>video_audio</structname> are used to enumerate the
+audio inputs of a V4L device. The equivalent V4L2 ioctls are
+&VIDIOC-G-AUDIO; and &VIDIOC-S-AUDIO; using &v4l2-audio; as
+discussed in <xref linkend="audio" />.</para>
+
+      <para>The <structfield>audio</structfield> "channel number"
+field counting audio inputs was renamed to
+<structfield>index</structfield>.</para>
+
+      <para>On <constant>VIDIOCSAUDIO</constant> the
+<structfield>mode</structfield> field selects <emphasis>one</emphasis>
+of the <constant>VIDEO_SOUND_MONO</constant>,
+<constant>VIDEO_SOUND_STEREO</constant>,
+<constant>VIDEO_SOUND_LANG1</constant> or
+<constant>VIDEO_SOUND_LANG2</constant> audio demodulation modes. When
+the current audio standard is BTSC
+<constant>VIDEO_SOUND_LANG2</constant> refers to SAP and
+<constant>VIDEO_SOUND_LANG1</constant> is meaningless. Also
+undocumented in the V4L specification, there is no way to query the
+selected mode. On <constant>VIDIOCGAUDIO</constant> the driver returns
+the <emphasis>actually received</emphasis> audio programmes in this
+field. In the V4L2 API this information is stored in the &v4l2-tuner;
+<structfield>rxsubchans</structfield> and
+<structfield>audmode</structfield> fields, respectively. See <xref
+linkend="tuner" /> for more information on tuners. Related to audio
+modes &v4l2-audio; also reports if this is a mono or stereo
+input, regardless if the source is a tuner.</para>
+
+      <para>The following fields where replaced by V4L2 controls
+accessible with the &VIDIOC-QUERYCTRL;, &VIDIOC-G-CTRL; and
+&VIDIOC-S-CTRL; ioctls:<informaltable>
+         <tgroup cols="2">
+           <thead>
+             <row>
+               <entry>struct
+<structname>video_audio</structname></entry>
+               <entry>V4L2 Control ID</entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row>
+               <entry><structfield>volume</structfield></entry>
+               <entry><constant>V4L2_CID_AUDIO_VOLUME</constant></entry>
+             </row>
+             <row>
+               <entry><structfield>bass</structfield></entry>
+               <entry><constant>V4L2_CID_AUDIO_BASS</constant></entry>
+             </row>
+             <row>
+               <entry><structfield>treble</structfield></entry>
+               <entry><constant>V4L2_CID_AUDIO_TREBLE</constant></entry>
+             </row>
+             <row>
+               <entry><structfield>balance</structfield></entry>
+               <entry><constant>V4L2_CID_AUDIO_BALANCE</constant></entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </informaltable></para>
+
+      <para>To determine which of these controls are supported by a
+driver V4L provides the <structfield>flags</structfield>
+<constant>VIDEO_AUDIO_VOLUME</constant>,
+<constant>VIDEO_AUDIO_BASS</constant>,
+<constant>VIDEO_AUDIO_TREBLE</constant> and
+<constant>VIDEO_AUDIO_BALANCE</constant>. In the V4L2 API the
+&VIDIOC-QUERYCTRL; ioctl reports if the respective control is
+supported. Accordingly the <constant>VIDEO_AUDIO_MUTABLE</constant>
+and <constant>VIDEO_AUDIO_MUTE</constant> flags where replaced by the
+boolean <constant>V4L2_CID_AUDIO_MUTE</constant> control.</para>
+
+      <para>All V4L2 controls have a <structfield>step</structfield>
+attribute replacing the struct <structname>video_audio</structname>
+<structfield>step</structfield> field. The V4L audio controls are
+assumed to range from 0 to 65535 with no particular reset value. The
+V4L2 API permits arbitrary limits and defaults which can be queried
+with the &VIDIOC-QUERYCTRL; ioctl. For general information about
+controls see <xref linkend="control" />.</para>
+    </section>
+
+    <section>
+      <title>Frame Buffer Overlay</title>
+
+      <para>The V4L2 ioctls equivalent to
+<constant>VIDIOCGFBUF</constant> and <constant>VIDIOCSFBUF</constant>
+are &VIDIOC-G-FBUF; and &VIDIOC-S-FBUF;. The
+<structfield>base</structfield> field of struct
+<structname>video_buffer</structname> remained unchanged, except V4L2
+defines a flag to indicate non-destructive overlays instead of a
+<constant>NULL</constant> pointer. All other fields moved into the
+&v4l2-pix-format; <structfield>fmt</structfield> substructure of
+&v4l2-framebuffer;. The <structfield>depth</structfield> field was
+replaced by <structfield>pixelformat</structfield>. See <xref
+         linkend="pixfmt-rgb" /> for a list of RGB formats and their
+respective color depths.</para>
+
+      <para>Instead of the special ioctls
+<constant>VIDIOCGWIN</constant> and <constant>VIDIOCSWIN</constant>
+V4L2 uses the general-purpose data format negotiation ioctls
+&VIDIOC-G-FMT; and &VIDIOC-S-FMT;. They take a pointer to a
+&v4l2-format; as argument. Here the <structfield>win</structfield>
+member of the <structfield>fmt</structfield> union is used, a
+&v4l2-window;.</para>
+
+      <para>The <structfield>x</structfield>,
+<structfield>y</structfield>, <structfield>width</structfield> and
+<structfield>height</structfield> fields of struct
+<structname>video_window</structname> moved into &v4l2-rect;
+substructure <structfield>w</structfield> of struct
+<structname>v4l2_window</structname>. The
+<structfield>chromakey</structfield>,
+<structfield>clips</structfield>, and
+<structfield>clipcount</structfield> fields remained unchanged. Struct
+<structname>video_clip</structname> was renamed to &v4l2-clip;, also
+containing a struct <structname>v4l2_rect</structname>, but the
+semantics are still the same.</para>
+
+      <para>The <constant>VIDEO_WINDOW_INTERLACE</constant> flag was
+dropped. Instead applications must set the
+<structfield>field</structfield> field to
+<constant>V4L2_FIELD_ANY</constant> or
+<constant>V4L2_FIELD_INTERLACED</constant>. The
+<constant>VIDEO_WINDOW_CHROMAKEY</constant> flag moved into
+&v4l2-framebuffer;, under the new name
+<constant>V4L2_FBUF_FLAG_CHROMAKEY</constant>.</para>
+
+      <para>In V4L, storing a bitmap pointer in
+<structfield>clips</structfield> and setting
+<structfield>clipcount</structfield> to
+<constant>VIDEO_CLIP_BITMAP</constant> (-1) requests bitmap
+clipping, using a fixed size bitmap of 1024 &times; 625 bits. Struct
+<structname>v4l2_window</structname> has a separate
+<structfield>bitmap</structfield> pointer field for this purpose and
+the bitmap size is determined by <structfield>w.width</structfield> and
+<structfield>w.height</structfield>.</para>
+
+      <para>The <constant>VIDIOCCAPTURE</constant> ioctl to enable or
+disable overlay was renamed to &VIDIOC-OVERLAY;.</para>
+    </section>
+
+    <section>
+      <title>Cropping</title>
+
+      <para>To capture only a subsection of the full picture V4L
+defines the <constant>VIDIOCGCAPTURE</constant> and
+<constant>VIDIOCSCAPTURE</constant> ioctls using struct
+<structname>video_capture</structname>. The equivalent V4L2 ioctls are
+&VIDIOC-G-CROP; and &VIDIOC-S-CROP; using &v4l2-crop;, and the related
+&VIDIOC-CROPCAP; ioctl. This is a rather complex matter, see
+<xref linkend="crop" /> for details.</para>
+
+      <para>The <structfield>x</structfield>,
+<structfield>y</structfield>, <structfield>width</structfield> and
+<structfield>height</structfield> fields moved into &v4l2-rect;
+substructure <structfield>c</structfield> of struct
+<structname>v4l2_crop</structname>. The
+<structfield>decimation</structfield> field was dropped. In the V4L2
+API the scaling factor is implied by the size of the cropping
+rectangle and the size of the captured or overlaid image.</para>
+
+      <para>The <constant>VIDEO_CAPTURE_ODD</constant>
+and <constant>VIDEO_CAPTURE_EVEN</constant> flags to capture only the
+odd or even field, respectively, were replaced by
+<constant>V4L2_FIELD_TOP</constant> and
+<constant>V4L2_FIELD_BOTTOM</constant> in the field named
+<structfield>field</structfield> of &v4l2-pix-format; and
+&v4l2-window;. These structures are used to select a capture or
+overlay format with the &VIDIOC-S-FMT; ioctl.</para>
+    </section>
+
+    <section>
+      <title>Reading Images, Memory Mapping</title>
+
+      <section>
+       <title>Capturing using the read method</title>
+
+       <para>There is no essential difference between reading images
+from a V4L or V4L2 device using the &func-read; function, however V4L2
+drivers are not required to support this I/O method. Applications can
+determine if the function is available with the &VIDIOC-QUERYCAP;
+ioctl. All V4L2 devices exchanging data with applications must support
+the &func-select; and &func-poll; functions.</para>
+
+       <para>To select an image format and size, V4L provides the
+<constant>VIDIOCSPICT</constant> and <constant>VIDIOCSWIN</constant>
+ioctls. V4L2 uses the general-purpose data format negotiation ioctls
+&VIDIOC-G-FMT; and &VIDIOC-S-FMT;. They take a pointer to a
+&v4l2-format; as argument, here the &v4l2-pix-format; named
+<structfield>pix</structfield> of its <structfield>fmt</structfield>
+union is used.</para>
+
+       <para>For more information about the V4L2 read interface see
+<xref linkend="rw" />.</para>
+      </section>
+      <section>
+       <title>Capturing using memory mapping</title>
+
+       <para>Applications can read from V4L devices by mapping
+buffers in device memory, or more often just buffers allocated in
+DMA-able system memory, into their address space. This avoids the data
+copying overhead of the read method. V4L2 supports memory mapping as
+well, with a few differences.</para>
+
+       <informaltable>
+         <tgroup cols="2">
+           <thead>
+             <row>
+               <entry>V4L</entry>
+               <entry>V4L2</entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row>
+               <entry></entry>
+               <entry>The image format must be selected before
+buffers are allocated, with the &VIDIOC-S-FMT; ioctl. When no format
+is selected the driver may use the last, possibly by another
+application requested format.</entry>
+             </row>
+             <row>
+               <entry><para>Applications cannot change the number of
+buffers. The it is built into the driver, unless it has a module
+option to change the number when the driver module is
+loaded.</para></entry>
+               <entry><para>The &VIDIOC-REQBUFS; ioctl allocates the
+desired number of buffers, this is a required step in the initialization
+sequence.</para></entry>
+             </row>
+             <row>
+               <entry><para>Drivers map all buffers as one contiguous
+range of memory. The <constant>VIDIOCGMBUF</constant> ioctl is
+available to query the number of buffers, the offset of each buffer
+from the start of the virtual file, and the overall amount of memory
+used, which can be used as arguments for the &func-mmap;
+function.</para></entry>
+               <entry><para>Buffers are individually mapped. The
+offset and size of each buffer can be determined with the
+&VIDIOC-QUERYBUF; ioctl.</para></entry>
+             </row>
+             <row>
+               <entry><para>The <constant>VIDIOCMCAPTURE</constant>
+ioctl prepares a buffer for capturing. It also determines the image
+format for this buffer. The ioctl returns immediately, eventually with
+an &EAGAIN; if no video signal had been detected. When the driver
+supports more than one buffer applications can call the ioctl multiple
+times and thus have multiple outstanding capture
+requests.</para><para>The <constant>VIDIOCSYNC</constant> ioctl
+suspends execution until a particular buffer has been
+filled.</para></entry>
+               <entry><para>Drivers maintain an incoming and outgoing
+queue. &VIDIOC-QBUF; enqueues any empty buffer into the incoming
+queue. Filled buffers are dequeued from the outgoing queue with the
+&VIDIOC-DQBUF; ioctl. To wait until filled buffers become available this
+function, &func-select; or &func-poll; can be used. The
+&VIDIOC-STREAMON; ioctl must be called once after enqueuing one or
+more buffers to start capturing. Its counterpart
+&VIDIOC-STREAMOFF; stops capturing and dequeues all buffers from both
+queues. Applications can query the signal status, if known, with the
+&VIDIOC-ENUMINPUT; ioctl.</para></entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </informaltable>
+
+       <para>For a more in-depth discussion of memory mapping and
+examples, see <xref linkend="mmap" />.</para>
+      </section>
+    </section>
+
+    <section>
+      <title>Reading Raw VBI Data</title>
+
+      <para>Originally the V4L API did not specify a raw VBI capture
+interface, only the device file <filename>/dev/vbi</filename> was
+reserved for this purpose. The only driver supporting this interface
+was the BTTV driver, de-facto defining the V4L VBI interface. Reading
+from the device yields a raw VBI image with the following
+parameters:<informaltable>
+           <tgroup cols="2">
+             <thead>
+               <row>
+                 <entry>&v4l2-vbi-format;</entry>
+                 <entry>V4L, BTTV driver</entry>
+               </row>
+             </thead>
+             <tbody valign="top">
+               <row>
+                 <entry>sampling_rate</entry>
+                 <entry>28636363&nbsp;Hz NTSC (or any other 525-line
+standard); 35468950&nbsp;Hz PAL and SECAM (625-line standards)</entry>
+               </row>
+               <row>
+                 <entry>offset</entry>
+                 <entry>?</entry>
+               </row>
+               <row>
+                 <entry>samples_per_line</entry>
+                 <entry>2048</entry>
+               </row>
+               <row>
+                 <entry>sample_format</entry>
+                 <entry>V4L2_PIX_FMT_GREY. The last four bytes (a
+machine endianess integer) contain a frame counter.</entry>
+               </row>
+               <row>
+                 <entry>start[]</entry>
+                 <entry>10, 273 NTSC; 22, 335 PAL and SECAM</entry>
+               </row>
+               <row>
+                 <entry>count[]</entry>
+                 <entry><para>16, 16<footnote><para>Old driver
+versions used different values, eventually the custom
+<constant>BTTV_VBISIZE</constant> ioctl was added to query the
+correct values.</para></footnote></para></entry>
+               </row>
+               <row>
+                 <entry>flags</entry>
+                 <entry>0</entry>
+               </row>
+             </tbody>
+           </tgroup>
+       </informaltable></para>
+
+      <para>Undocumented in the V4L specification, in Linux 2.3 the
+<constant>VIDIOCGVBIFMT</constant> and
+<constant>VIDIOCSVBIFMT</constant> ioctls using struct
+<structname>vbi_format</structname> were added to determine the VBI
+image parameters. These ioctls are only partially compatible with the
+V4L2 VBI interface specified in <xref linkend="raw-vbi" />.</para>
+
+      <para>An <structfield>offset</structfield> field does not
+exist, <structfield>sample_format</structfield> is supposed to be
+<constant>VIDEO_PALETTE_RAW</constant>, equivalent to
+<constant>V4L2_PIX_FMT_GREY</constant>. The remaining fields are
+probably equivalent to &v4l2-vbi-format;.</para>
+
+      <para>Apparently only the Zoran (ZR 36120) driver implements
+these ioctls. The semantics differ from those specified for V4L2 in two
+ways. The parameters are reset on &func-open; and
+<constant>VIDIOCSVBIFMT</constant> always returns an &EINVAL; if the
+parameters are invalid.</para>
+    </section>
+
+    <section>
+      <title>Miscellaneous</title>
+
+      <para>V4L2 has no equivalent of the
+<constant>VIDIOCGUNIT</constant> ioctl. Applications can find the VBI
+device associated with a video capture device (or vice versa) by
+reopening the device and requesting VBI data. For details see
+<xref linkend="open" />.</para>
+
+      <para>No replacement exists for <constant>VIDIOCKEY</constant>,
+and the V4L functions for microcode programming. A new interface for
+MPEG compression and playback devices is documented in <xref
+         linkend="extended-controls" />.</para>
+    </section>
+
+  </section>
+
+  <section id="hist-v4l2">
+    <title>Changes of the V4L2 API</title>
+
+    <para>Soon after the V4L API was added to the kernel it was
+criticised as too inflexible. In August 1998 Bill Dirks proposed a
+number of improvements and began to work on documentation, example
+drivers and applications. With the help of other volunteers this
+eventually became the V4L2 API, not just an extension but a
+replacement for the V4L API. However it took another four years and
+two stable kernel releases until the new API was finally accepted for
+inclusion into the kernel in its present form.</para>
+
+    <section>
+      <title>Early Versions</title>
+      <para>1998-08-20: First version.</para>
+
+      <para>1998-08-27: The &func-select; function was introduced.</para>
+
+      <para>1998-09-10: New video standard interface.</para>
+
+      <para>1998-09-18: The <constant>VIDIOC_NONCAP</constant> ioctl
+was replaced by the otherwise meaningless <constant>O_TRUNC</constant>
+&func-open; flag, and the aliases <constant>O_NONCAP</constant> and
+<constant>O_NOIO</constant> were defined. Applications can set this
+flag if they intend to access controls only, as opposed to capture
+applications which need exclusive access. The
+<constant>VIDEO_STD_XXX</constant> identifiers are now ordinals
+instead of flags, and the <function>video_std_construct()</function>
+helper function takes id and transmission arguments.</para>
+
+      <para>1998-09-28: Revamped video standard. Made video controls
+individually enumerable.</para>
+
+      <para>1998-10-02: The <structfield>id</structfield> field was
+removed from struct <structname>video_standard</structname> and the
+color subcarrier fields were renamed. The &VIDIOC-QUERYSTD; ioctl was
+renamed to &VIDIOC-ENUMSTD;, &VIDIOC-G-INPUT; to &VIDIOC-ENUMINPUT;. A
+first draft of the Codec API was released.</para>
+
+      <para>1998-11-08: Many minor changes. Most symbols have been
+renamed. Some material changes to &v4l2-capability;.</para>
+
+      <para>1998-11-12: The read/write directon of some ioctls was misdefined.</para>
+
+      <para>1998-11-14: <constant>V4L2_PIX_FMT_RGB24</constant>
+changed to <constant>V4L2_PIX_FMT_BGR24</constant>, and
+<constant>V4L2_PIX_FMT_RGB32</constant> changed to
+<constant>V4L2_PIX_FMT_BGR32</constant>. Audio controls are now
+accessible with the &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls under
+names starting with <constant>V4L2_CID_AUDIO</constant>. The
+<constant>V4L2_MAJOR</constant> define was removed from
+<filename>videodev.h</filename> since it was only used once in the
+<filename>videodev</filename> kernel module. The
+<constant>YUV422</constant> and <constant>YUV411</constant> planar
+image formats were added.</para>
+
+      <para>1998-11-28: A few ioctl symbols changed. Interfaces for codecs and
+video output devices were added.</para>
+
+      <para>1999-01-14: A raw VBI capture interface was added.</para>
+
+      <para>1999-01-19: The <constant>VIDIOC_NEXTBUF</constant> ioctl
+      was removed.</para>
+    </section>
+
+    <section>
+      <title>V4L2 Version 0.16 1999-01-31</title>
+      <para>1999-01-27: There is now one QBUF ioctl, VIDIOC_QWBUF and VIDIOC_QRBUF
+are gone. VIDIOC_QBUF takes a v4l2_buffer as a parameter. Added
+digital zoom (cropping) controls.</para>
+    </section>
+
+    <!-- Where's 0.17? mhs couldn't find that videodev.h, perhaps Bill
+        forgot to bump the version number or never released it. -->
+
+    <section>
+      <title>V4L2 Version 0.18 1999-03-16</title>
+      <para>Added a v4l to V4L2 ioctl compatibility layer to
+videodev.c. Driver writers, this changes how you implement your ioctl
+handler. See the Driver Writer's Guide. Added some more control id
+codes.</para>
+    </section>
+
+    <section>
+      <title>V4L2 Version 0.19 1999-06-05</title>
+      <para>1999-03-18: Fill in the category and catname fields of
+v4l2_queryctrl objects before passing them to the driver. Required a
+minor change to the VIDIOC_QUERYCTRL handlers in the sample
+drivers.</para>
+      <para>1999-03-31: Better compatibility for v4l memory capture
+ioctls. Requires changes to drivers to fully support new compatibility
+features, see Driver Writer's Guide and v4l2cap.c. Added new control
+IDs: V4L2_CID_HFLIP, _VFLIP. Changed V4L2_PIX_FMT_YUV422P to _YUV422P,
+and _YUV411P to _YUV411P.</para>
+      <para>1999-04-04: Added a few more control IDs.</para>
+      <para>1999-04-07: Added the button control type.</para>
+      <para>1999-05-02: Fixed a typo in videodev.h, and added the
+V4L2_CTRL_FLAG_GRAYED (later V4L2_CTRL_FLAG_GRABBED) flag.</para>
+      <para>1999-05-20: Definition of VIDIOC_G_CTRL was wrong causing
+a malfunction of this ioctl.</para>
+      <para>1999-06-05: Changed the value of
+V4L2_CID_WHITENESS.</para>
+    </section>
+
+    <section>
+      <title>V4L2 Version 0.20 (1999-09-10)</title>
+
+      <para>Version 0.20 introduced a number of changes which were
+<emphasis>not backward compatible</emphasis> with 0.19 and earlier
+versions. Purpose of these changes was to simplify the API, while
+making it more extensible and following common Linux driver API
+conventions.</para>
+
+      <orderedlist>
+       <listitem>
+         <para>Some typos in <constant>V4L2_FMT_FLAG</constant>
+symbols were fixed. &v4l2-clip; was changed for compatibility with
+v4l. (1999-08-30)</para>
+       </listitem>
+
+       <listitem>
+         <para><constant>V4L2_TUNER_SUB_LANG1</constant> was added.
+(1999-09-05)</para>
+       </listitem>
+
+       <listitem>
+         <para>All ioctl() commands that used an integer argument now
+take a pointer to an integer. Where it makes sense, ioctls will return
+the actual new value in the integer pointed to by the argument, a
+common convention in the V4L2 API. The affected ioctls are:
+VIDIOC_PREVIEW, VIDIOC_STREAMON, VIDIOC_STREAMOFF, VIDIOC_S_FREQ,
+VIDIOC_S_INPUT, VIDIOC_S_OUTPUT, VIDIOC_S_EFFECT. For example
+<programlisting>
+err = ioctl (fd, VIDIOC_XXX, V4L2_XXX);
+</programlisting> becomes <programlisting>
+int a = V4L2_XXX; err = ioctl(fd, VIDIOC_XXX, &amp;a);
+</programlisting>
+         </para>
+       </listitem>
+
+       <listitem>
+         <para>All the different get- and set-format commands were
+swept into one &VIDIOC-G-FMT; and &VIDIOC-S-FMT; ioctl taking a union
+and a type field selecting the union member as parameter. Purpose is to
+simplify the API by eliminating several ioctls and to allow new and
+driver private data streams without adding new ioctls.</para>
+
+         <para>This change obsoletes the following ioctls:
+<constant>VIDIOC_S_INFMT</constant>,
+<constant>VIDIOC_G_INFMT</constant>,
+<constant>VIDIOC_S_OUTFMT</constant>,
+<constant>VIDIOC_G_OUTFMT</constant>,
+<constant>VIDIOC_S_VBIFMT</constant> and
+<constant>VIDIOC_G_VBIFMT</constant>. The image format structure
+<structname>v4l2_format</structname> was renamed to &v4l2-pix-format;,
+while &v4l2-format; is now the envelopping structure for all format
+negotiations.</para>
+       </listitem>
+
+       <listitem>
+         <para>Similar to the changes above, the
+<constant>VIDIOC_G_PARM</constant> and
+<constant>VIDIOC_S_PARM</constant> ioctls were merged with
+<constant>VIDIOC_G_OUTPARM</constant> and
+<constant>VIDIOC_S_OUTPARM</constant>. A
+<structfield>type</structfield> field in the new &v4l2-streamparm;
+selects the respective union member.</para>
+
+         <para>This change obsoletes the
+<constant>VIDIOC_G_OUTPARM</constant> and
+<constant>VIDIOC_S_OUTPARM</constant> ioctls.</para>
+       </listitem>
+
+       <listitem>
+         <para>Control enumeration was simplified, and two new
+control flags were introduced and one dropped. The
+<structfield>catname</structfield> field was replaced by a
+<structfield>group</structfield> field.</para>
+
+         <para>Drivers can now flag unsupported and temporarily
+unavailable controls with <constant>V4L2_CTRL_FLAG_DISABLED</constant>
+and <constant>V4L2_CTRL_FLAG_GRABBED</constant> respectively. The
+<structfield>group</structfield> name indicates a possibly narrower
+classification than the <structfield>category</structfield>. In other
+words, there may be multiple groups within a category. Controls within
+a group would typically be drawn within a group box. Controls in
+different categories might have a greater separation, or may even
+appear in separate windows.</para>
+       </listitem>
+
+       <listitem>
+         <para>The &v4l2-buffer; <structfield>timestamp</structfield>
+was changed to a 64 bit integer, containing the sampling or output
+time of the frame in nanoseconds. Additionally timestamps will be in
+absolute system time, not starting from zero at the beginning of a
+stream. The data type name for timestamps is stamp_t, defined as a
+signed 64-bit integer. Output devices should not send a buffer out
+until the time in the timestamp field has arrived. I would like to
+follow SGI's lead, and adopt a multimedia timestamping system like
+their UST (Unadjusted System Time). See
+http://web.archive.org/web/*/http://reality.sgi.com
+/cpirazzi_engr/lg/time/intro.html. 
+UST uses timestamps that are 64-bit signed integers
+(not struct timeval's) and given in nanosecond units. The UST clock
+starts at zero when the system is booted and runs continuously and
+uniformly. It takes a little over 292 years for UST to overflow. There
+is no way to set the UST clock. The regular Linux time-of-day clock
+can be changed periodically, which would cause errors if it were being
+used for timestamping a multimedia stream. A real UST style clock will
+require some support in the kernel that is not there yet. But in
+anticipation, I will change the timestamp field to a 64-bit integer,
+and I will change the v4l2_masterclock_gettime() function (used only
+by drivers) to return a 64-bit integer.</para>
+       </listitem>
+
+       <listitem>
+         <para>A <structfield>sequence</structfield> field was added
+to &v4l2-buffer;. The <structfield>sequence</structfield> field counts
+captured frames, it is ignored by output devices. When a capture
+driver drops a frame, the sequence number of that frame is
+skipped.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 Version 0.20 incremental changes</title>
+      <!-- Version number didn't change anymore, reason unknown. -->
+
+      <para>1999-12-23: In &v4l2-vbi-format; the
+<structfield>reserved1</structfield> field became
+<structfield>offset</structfield>. Previously drivers were required to
+clear the <structfield>reserved1</structfield> field.</para>
+
+      <para>2000-01-13: The
+      <constant>V4L2_FMT_FLAG_NOT_INTERLACED</constant> flag was added.</para>
+
+      <para>2000-07-31: The <filename>linux/poll.h</filename> header
+is now included by <filename>videodev.h</filename> for compatibility
+with the original <filename>videodev.h</filename> file.</para>
+
+      <para>2000-11-20: <constant>V4L2_TYPE_VBI_OUTPUT</constant> and
+<constant>V4L2_PIX_FMT_Y41P</constant> were added.</para>
+
+      <para>2000-11-25: <constant>V4L2_TYPE_VBI_INPUT</constant> was
+added.</para>
+
+      <para>2000-12-04: A couple typos in symbol names were fixed.</para>
+
+      <para>2001-01-18: To avoid namespace conflicts the
+<constant>fourcc</constant> macro defined in the
+<filename>videodev.h</filename> header file was renamed to
+<constant>v4l2_fourcc</constant>.</para>
+
+      <para>2001-01-25: A possible driver-level compatibility problem
+between the <filename>videodev.h</filename> file in Linux 2.4.0 and
+the <filename>videodev.h</filename> file included in the
+<filename>videodevX</filename> patch was fixed. Users of an earlier
+version of <filename>videodevX</filename> on Linux 2.4.0 should
+recompile their V4L and V4L2 drivers.</para>
+
+      <para>2001-01-26: A possible kernel-level incompatibility
+between the <filename>videodev.h</filename> file in the
+<filename>videodevX</filename> patch and the
+<filename>videodev.h</filename> file in Linux 2.2.x with devfs patches
+applied was fixed.</para>
+
+      <para>2001-03-02: Certain V4L ioctls which pass data in both
+direction although they are defined with read-only parameter, did not
+work correctly through the backward compatibility layer.
+[Solution?]</para>
+
+      <para>2001-04-13: Big endian 16-bit RGB formats were added.</para>
+
+      <para>2001-09-17: New YUV formats and the &VIDIOC-G-FREQUENCY; and
+&VIDIOC-S-FREQUENCY; ioctls were added. (The old
+<constant>VIDIOC_G_FREQ</constant> and
+<constant>VIDIOC_S_FREQ</constant> ioctls did not take multiple tuners
+into account.)</para>
+
+      <para>2000-09-18: <constant>V4L2_BUF_TYPE_VBI</constant> was
+added. This may <emphasis>break compatibility</emphasis> as the
+&VIDIOC-G-FMT; and &VIDIOC-S-FMT; ioctls may fail now if the struct
+<structname>v4l2_fmt</structname> <structfield>type</structfield>
+field does not contain <constant>V4L2_BUF_TYPE_VBI</constant>. In the
+documentation of the &v4l2-vbi-format;
+<structfield>offset</structfield> field the ambiguous phrase "rising
+edge" was changed to "leading edge".</para>
+    </section>
+
+    <section>
+      <title>V4L2 Version 0.20 2000-11-23</title>
+
+      <para>A number of changes were made to the raw VBI
+interface.</para>
+
+      <orderedlist>
+       <listitem>
+         <para>Figures clarifying the line numbering scheme were
+added to the V4L2 API specification. The
+<structfield>start</structfield>[0] and
+<structfield>start</structfield>[1] fields no longer count line
+numbers beginning at zero. Rationale: a) The previous definition was
+unclear. b) The <structfield>start</structfield>[] values are ordinal
+numbers. c) There is no point in inventing a new line numbering
+scheme. We now use line number as defined by ITU-R, period.
+Compatibility: Add one to the start values. Applications depending on
+the previous semantics may not function correctly.</para>
+       </listitem>
+
+       <listitem>
+         <para>The restriction "count[0] &gt; 0 and count[1] &gt; 0"
+has been relaxed  to "(count[0] + count[1]) &gt; 0". Rationale:
+Drivers may allocate resources at scan line granularity and some data
+services are transmitted only on the first field. The comment that
+both <structfield>count</structfield> values will usually be equal is
+misleading and pointless and has been removed. This change
+<emphasis>breaks compatibility</emphasis> with earlier versions:
+Drivers may return EINVAL, applications may not function
+correctly.</para>
+       </listitem>
+
+       <listitem>
+         <para>Drivers are again permitted to return negative
+(unknown) start values as proposed earlier. Why this feature was
+dropped is unclear. This change may <emphasis>break
+compatibility</emphasis> with applications depending on the start
+values being positive. The use of <constant>EBUSY</constant> and
+<constant>EINVAL</constant> error codes with the &VIDIOC-S-FMT; ioctl
+was clarified. The &EBUSY; was finally documented, and the
+<structfield>reserved2</structfield> field which was previously
+mentioned only in the <filename>videodev.h</filename> header
+file.</para>
+       </listitem>
+
+       <listitem>
+         <para>New buffer types
+<constant>V4L2_TYPE_VBI_INPUT</constant> and
+<constant>V4L2_TYPE_VBI_OUTPUT</constant> were added. The former is an
+alias for the old <constant>V4L2_TYPE_VBI</constant>, the latter was
+missing in the <filename>videodev.h</filename> file.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 Version 0.20 2002-07-25</title>
+      <para>Added sliced VBI interface proposal.</para>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.5.46, 2002-10</title>
+
+      <para>Around October-November 2002, prior to an announced
+feature freeze of Linux 2.5, the API was revised, drawing from
+experience with V4L2 0.20. This unnamed version was finally merged
+into Linux 2.5.46.</para>
+
+      <orderedlist>
+       <listitem>
+         <para>As specified in <xref linkend="related" />, drivers
+must make related device functions available under all minor device
+numbers.</para>
+       </listitem>
+
+       <listitem>
+         <para>The &func-open; function requires access mode
+<constant>O_RDWR</constant> regardless of the device type. All V4L2
+drivers exchanging data with applications must support the
+<constant>O_NONBLOCK</constant> flag. The <constant>O_NOIO</constant>
+flag, a V4L2 symbol which aliased the meaningless
+<constant>O_TRUNC</constant> to indicate accesses without data
+exchange (panel applications) was dropped. Drivers must stay in "panel
+mode" until the application attempts to initiate a data exchange, see
+<xref linkend="open" />.</para>
+       </listitem>
+
+       <listitem>
+         <para>The &v4l2-capability; changed dramatically. Note that
+also the size of the structure changed, which is encoded in the ioctl
+request code, thus older V4L2 devices will respond with an &EINVAL; to
+the new &VIDIOC-QUERYCAP; ioctl.</para>
+
+         <para>There are new fields to identify the driver, a new RDS
+device function <constant>V4L2_CAP_RDS_CAPTURE</constant>, the
+<constant>V4L2_CAP_AUDIO</constant> flag indicates if the device has
+any audio connectors, another I/O capability
+<constant>V4L2_CAP_ASYNCIO</constant> can be flagged. In response to
+these changes the <structfield>type</structfield> field became a bit
+set and was merged into the <structfield>flags</structfield> field.
+<constant>V4L2_FLAG_TUNER</constant> was renamed to
+<constant>V4L2_CAP_TUNER</constant>,
+<constant>V4L2_CAP_VIDEO_OVERLAY</constant> replaced
+<constant>V4L2_FLAG_PREVIEW</constant> and
+<constant>V4L2_CAP_VBI_CAPTURE</constant> and
+<constant>V4L2_CAP_VBI_OUTPUT</constant> replaced
+<constant>V4L2_FLAG_DATA_SERVICE</constant>.
+<constant>V4L2_FLAG_READ</constant> and
+<constant>V4L2_FLAG_WRITE</constant> were merged into
+<constant>V4L2_CAP_READWRITE</constant>.</para>
+
+         <para>The redundant fields
+<structfield>inputs</structfield>, <structfield>outputs</structfield>
+and <structfield>audios</structfield> were removed. These properties
+can be determined as described in <xref linkend="video" /> and <xref
+linkend="audio" />.</para>
+
+         <para>The somewhat volatile and therefore barely useful
+fields <structfield>maxwidth</structfield>,
+<structfield>maxheight</structfield>,
+<structfield>minwidth</structfield>,
+<structfield>minheight</structfield>,
+<structfield>maxframerate</structfield> were removed. This information
+is available as described in <xref linkend="format" /> and
+<xref linkend="standard" />.</para>
+
+         <para><constant>V4L2_FLAG_SELECT</constant> was removed. We
+believe the select() function is important enough to require support
+of it in all V4L2 drivers exchanging data with applications. The
+redundant <constant>V4L2_FLAG_MONOCHROME</constant> flag was removed,
+this information is available as described in <xref
+             linkend="format" />.</para>
+       </listitem>
+
+       <listitem>
+         <para>In &v4l2-input; the
+<structfield>assoc_audio</structfield> field and the
+<structfield>capability</structfield> field and its only flag
+<constant>V4L2_INPUT_CAP_AUDIO</constant> was replaced by the new
+<structfield>audioset</structfield> field. Instead of linking one
+video input to one audio input this field reports all audio inputs
+this video input combines with.</para>
+
+         <para>New fields are <structfield>tuner</structfield>
+(reversing the former link from tuners to video inputs),
+<structfield>std</structfield> and
+<structfield>status</structfield>.</para>
+
+         <para>Accordingly &v4l2-output; lost its
+<structfield>capability</structfield> and
+<structfield>assoc_audio</structfield> fields.
+<structfield>audioset</structfield>,
+<structfield>modulator</structfield> and
+<structfield>std</structfield> where added instead.</para>
+       </listitem>
+
+       <listitem>
+         <para>The &v4l2-audio; field
+<structfield>audio</structfield> was renamed to
+<structfield>index</structfield>, for consistency with other
+structures. A new capability flag
+<constant>V4L2_AUDCAP_STEREO</constant> was added to indicated if the
+audio input in question supports stereo sound.
+<constant>V4L2_AUDCAP_EFFECTS</constant> and the corresponding
+<constant>V4L2_AUDMODE</constant> flags where removed. This can be
+easily implemented using controls. (However the same applies to AVL
+which is still there.)</para>
+
+         <para>Again for consistency the &v4l2-audioout; field
+<structfield>audio</structfield> was renamed to
+<structfield>index</structfield>.</para>
+       </listitem>
+
+       <listitem>
+         <para>The &v4l2-tuner;
+<structfield>input</structfield> field was replaced by an
+<structfield>index</structfield> field, permitting devices with
+multiple tuners. The link between video inputs and tuners is now
+reversed, inputs point to their tuner. The
+<structfield>std</structfield> substructure became a
+simple set (more about this below) and moved into &v4l2-input;. A
+<structfield>type</structfield> field was added.</para>
+
+         <para>Accordingly in &v4l2-modulator; the
+<structfield>output</structfield> was replaced by an
+<structfield>index</structfield> field.</para>
+
+         <para>In &v4l2-frequency; the
+<structfield>port</structfield> field was replaced by a
+<structfield>tuner</structfield> field containing the respective tuner
+or modulator index number. A tuner <structfield>type</structfield>
+field was added and the <structfield>reserved</structfield> field
+became larger for future extensions (satellite tuners in
+particular).</para>
+       </listitem>
+
+       <listitem>
+         <para>The idea of completely transparent video standards was
+dropped. Experience showed that applications must be able to work with
+video standards beyond presenting the user a menu. Instead of
+enumerating supported standards with an ioctl applications can now
+refer to standards by &v4l2-std-id; and symbols defined in the
+<filename>videodev2.h</filename> header file. For details see <xref
+             linkend="standard" />. The &VIDIOC-G-STD; and
+&VIDIOC-S-STD; now take a pointer to this type as argument.
+&VIDIOC-QUERYSTD; was added to autodetect the received standard, if
+the hardware has this capability. In &v4l2-standard; an
+<structfield>index</structfield> field was added for &VIDIOC-ENUMSTD;.
+A &v4l2-std-id; field named <structfield>id</structfield> was added as
+machine readable identifier, also replacing the
+<structfield>transmission</structfield> field. The misleading
+<structfield>framerate</structfield> field was renamed
+to <structfield>frameperiod</structfield>. The now obsolete
+<structfield>colorstandard</structfield> information, originally
+needed to distguish between variations of standards, were
+removed.</para>
+
+         <para>Struct <structname>v4l2_enumstd</structname> ceased to
+be. &VIDIOC-ENUMSTD; now takes a pointer to a &v4l2-standard;
+directly. The information which standards are supported by a
+particular video input or output moved into &v4l2-input; and
+&v4l2-output; fields named <structfield>std</structfield>,
+respectively.</para>
+       </listitem>
+
+       <listitem>
+         <para>The &v4l2-queryctrl; fields
+<structfield>category</structfield> and
+<structfield>group</structfield> did not catch on and/or were not
+implemented as expected and therefore removed.</para>
+       </listitem>
+
+       <listitem>
+         <para>The &VIDIOC-TRY-FMT; ioctl was added to negotiate data
+formats as with &VIDIOC-S-FMT;, but without the overhead of
+programming the hardware and regardless of I/O in progress.</para>
+
+         <para>In &v4l2-format; the <structfield>fmt</structfield>
+union was extended to contain &v4l2-window;. All image format
+negotiations are now possible with <constant>VIDIOC_G_FMT</constant>,
+<constant>VIDIOC_S_FMT</constant> and
+<constant>VIDIOC_TRY_FMT</constant>; ioctl. The
+<constant>VIDIOC_G_WIN</constant> and
+<constant>VIDIOC_S_WIN</constant> ioctls to prepare for a video
+overlay were removed. The <structfield>type</structfield> field
+changed to type &v4l2-buf-type; and the buffer type names changed as
+follows.<informaltable>
+             <tgroup cols="2">
+               <thead>
+                 <row>
+                   <entry>Old defines</entry>
+                   <entry>&v4l2-buf-type;</entry>
+                 </row>
+               </thead>
+               <tbody valign="top">
+                 <row>
+                   <entry><constant>V4L2_BUF_TYPE_CAPTURE</constant></entry>
+                   <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_BUF_TYPE_CODECIN</constant></entry>
+                   <entry>Omitted for now</entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_BUF_TYPE_CODECOUT</constant></entry>
+                   <entry>Omitted for now</entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_BUF_TYPE_EFFECTSIN</constant></entry>
+                   <entry>Omitted for now</entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_BUF_TYPE_EFFECTSIN2</constant></entry>
+                   <entry>Omitted for now</entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_BUF_TYPE_EFFECTSOUT</constant></entry>
+                   <entry>Omitted for now</entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_BUF_TYPE_VIDEOOUT</constant></entry>
+                   <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>-</constant></entry>
+                   <entry><constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>-</constant></entry>
+                   <entry><constant>V4L2_BUF_TYPE_VBI_CAPTURE</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>-</constant></entry>
+                   <entry><constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>-</constant></entry>
+                   <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>-</constant></entry>
+                   <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_BUF_TYPE_PRIVATE_BASE</constant></entry>
+                   <entry><constant>V4L2_BUF_TYPE_PRIVATE</constant></entry>
+                 </row>
+               </tbody>
+             </tgroup>
+           </informaltable></para>
+       </listitem>
+
+       <listitem>
+         <para>In &v4l2-fmtdesc; a &v4l2-buf-type; field named
+<structfield>type</structfield> was added as in &v4l2-format;. The
+<constant>VIDIOC_ENUM_FBUFFMT</constant> ioctl is no longer needed and
+was removed. These calls can be replaced by &VIDIOC-ENUM-FMT; with
+type <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>.</para>
+       </listitem>
+
+       <listitem>
+         <para>In &v4l2-pix-format; the
+<structfield>depth</structfield> field was removed, assuming
+applications which recognize the format by its four-character-code
+already know the color depth, and others do not care about it. The
+same rationale lead to the removal of the
+<constant>V4L2_FMT_FLAG_COMPRESSED</constant> flag. The
+<constant>V4L2_FMT_FLAG_SWCONVECOMPRESSED</constant> flag was removed
+because drivers are not supposed to convert images in kernel space. A
+user library of conversion functions should be provided instead. The
+<constant>V4L2_FMT_FLAG_BYTESPERLINE</constant> flag was redundant.
+Applications can set the <structfield>bytesperline</structfield> field
+to zero to get a reasonable default. Since the remaining flags were
+replaced as well, the <structfield>flags</structfield> field itself
+was removed.</para>
+         <para>The interlace flags were replaced by a &v4l2-field;
+value in a newly added <structfield>field</structfield>
+field.<informaltable>
+             <tgroup cols="2">
+               <thead>
+                 <row>
+                   <entry>Old flag</entry>
+                   <entry>&v4l2-field;</entry>
+                 </row>
+               </thead>
+               <tbody valign="top">
+                 <row>
+                   <entry><constant>V4L2_FMT_FLAG_NOT_INTERLACED</constant></entry>
+                   <entry>?</entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_FMT_FLAG_INTERLACED</constant>
+= <constant>V4L2_FMT_FLAG_COMBINED</constant></entry>
+                   <entry><constant>V4L2_FIELD_INTERLACED</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_FMT_FLAG_TOPFIELD</constant>
+= <constant>V4L2_FMT_FLAG_ODDFIELD</constant></entry>
+                   <entry><constant>V4L2_FIELD_TOP</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_FMT_FLAG_BOTFIELD</constant>
+= <constant>V4L2_FMT_FLAG_EVENFIELD</constant></entry>
+                   <entry><constant>V4L2_FIELD_BOTTOM</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>-</constant></entry>
+                   <entry><constant>V4L2_FIELD_SEQ_TB</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>-</constant></entry>
+                   <entry><constant>V4L2_FIELD_SEQ_BT</constant></entry>
+                 </row>
+                 <row>
+                   <entry><constant>-</constant></entry>
+                   <entry><constant>V4L2_FIELD_ALTERNATE</constant></entry>
+                 </row>
+               </tbody>
+             </tgroup>
+           </informaltable></para>
+
+         <para>The color space flags were replaced by a
+&v4l2-colorspace; value in a newly added
+<structfield>colorspace</structfield> field, where one of
+<constant>V4L2_COLORSPACE_SMPTE170M</constant>,
+<constant>V4L2_COLORSPACE_BT878</constant>,
+<constant>V4L2_COLORSPACE_470_SYSTEM_M</constant> or
+<constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant> replaces
+<constant>V4L2_FMT_CS_601YUV</constant>.</para>
+       </listitem>
+
+       <listitem>
+         <para>In &v4l2-requestbuffers; the
+<structfield>type</structfield> field was properly defined as
+&v4l2-buf-type;. Buffer types changed as mentioned above. A new
+<structfield>memory</structfield> field of type &v4l2-memory; was
+added to distinguish between I/O methods using buffers allocated
+by the driver or the application. See <xref linkend="io" /> for
+details.</para>
+       </listitem>
+
+       <listitem>
+         <para>In &v4l2-buffer; the <structfield>type</structfield>
+field was properly defined as &v4l2-buf-type;. Buffer types changed as
+mentioned above. A <structfield>field</structfield> field of type
+&v4l2-field; was added to indicate if a buffer contains a top or
+bottom field. The old field flags were removed. Since no unadjusted
+system time clock was added to the kernel as planned, the
+<structfield>timestamp</structfield> field changed back from type
+stamp_t, an unsigned 64 bit integer expressing the sample time in
+nanoseconds, to struct <structname>timeval</structname>. With the
+addition of a second memory mapping method the
+<structfield>offset</structfield> field moved into union
+<structfield>m</structfield>, and a new
+<structfield>memory</structfield> field of type &v4l2-memory; was
+added to distinguish between I/O methods. See <xref linkend="io" />
+for details.</para>
+
+         <para>The <constant>V4L2_BUF_REQ_CONTIG</constant>
+flag was used by the V4L compatibility layer, after changes to this
+code it was no longer needed. The
+<constant>V4L2_BUF_ATTR_DEVICEMEM</constant> flag would indicate if
+the buffer was indeed allocated in device memory rather than DMA-able
+system memory. It was barely useful and so was removed.</para>
+       </listitem>
+
+       <listitem>
+         <para>In &v4l2-framebuffer; the
+<structfield>base[3]</structfield> array anticipating double- and
+triple-buffering in off-screen video memory, however without defining
+a synchronization mechanism, was replaced by a single pointer. The
+<constant>V4L2_FBUF_CAP_SCALEUP</constant> and
+<constant>V4L2_FBUF_CAP_SCALEDOWN</constant> flags were removed.
+Applications can determine this capability more accurately using the
+new cropping and scaling interface. The
+<constant>V4L2_FBUF_CAP_CLIPPING</constant> flag was replaced by
+<constant>V4L2_FBUF_CAP_LIST_CLIPPING</constant> and
+<constant>V4L2_FBUF_CAP_BITMAP_CLIPPING</constant>.</para>
+       </listitem>
+
+       <listitem>
+         <para>In &v4l2-clip; the <structfield>x</structfield>,
+<structfield>y</structfield>, <structfield>width</structfield> and
+<structfield>height</structfield> field moved into a
+<structfield>c</structfield> substructure of type &v4l2-rect;. The
+<structfield>x</structfield> and <structfield>y</structfield> fields
+were renamed to <structfield>left</structfield> and
+<structfield>top</structfield>, &ie; offsets to a context dependent
+origin.</para>
+       </listitem>
+
+       <listitem>
+         <para>In &v4l2-window; the <structfield>x</structfield>,
+<structfield>y</structfield>, <structfield>width</structfield> and
+<structfield>height</structfield> field moved into a
+<structfield>w</structfield> substructure as above. A
+<structfield>field</structfield> field of type %v4l2-field; was added
+to distinguish between field and frame (interlaced) overlay.</para>
+       </listitem>
+
+       <listitem>
+         <para>The digital zoom interface, including struct
+<structname>v4l2_zoomcap</structname>, struct
+<structname>v4l2_zoom</structname>,
+<constant>V4L2_ZOOM_NONCAP</constant> and
+<constant>V4L2_ZOOM_WHILESTREAMING</constant> was replaced by a new
+cropping and scaling interface. The previously unused struct
+<structname>v4l2_cropcap</structname> and
+<structname>v4l2_crop</structname> where redefined for this purpose.
+See <xref linkend="crop" /> for details.</para>
+       </listitem>
+
+       <listitem>
+         <para>In &v4l2-vbi-format; the
+<structfield>SAMPLE_FORMAT</structfield> field now contains a
+four-character-code as used to identify video image formats and
+<constant>V4L2_PIX_FMT_GREY</constant> replaces the
+<constant>V4L2_VBI_SF_UBYTE</constant> define. The
+<structfield>reserved</structfield> field was extended.</para>
+       </listitem>
+
+       <listitem>
+         <para>In &v4l2-captureparm; the type of the
+<structfield>timeperframe</structfield> field changed from unsigned
+long to &v4l2-fract;. This allows the accurate expression of multiples
+of the NTSC-M frame rate 30000 / 1001. A new field
+<structfield>readbuffers</structfield> was added to control the driver
+behaviour in read I/O mode.</para>
+
+         <para>Similar changes were made to &v4l2-outputparm;.</para>
+       </listitem>
+
+       <listitem>
+         <para>The struct <structname>v4l2_performance</structname>
+and <constant>VIDIOC_G_PERF</constant> ioctl were dropped. Except when
+using the <link linkend="rw">read/write I/O method</link>, which is
+limited anyway, this information is already available to
+applications.</para>
+       </listitem>
+
+       <listitem>
+         <para>The example transformation from RGB to YCbCr color
+space in the old V4L2 documentation was inaccurate, this has been
+corrected in <xref linkend="pixfmt" />.<!-- 0.5670G should be
+0.587, and 127/112 != 255/224 --></para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 2003-06-19</title>
+
+      <orderedlist>
+       <listitem>
+         <para>A new capability flag
+<constant>V4L2_CAP_RADIO</constant> was added for radio devices. Prior
+to this change radio devices would identify solely by having exactly one
+tuner whose type field reads <constant>V4L2_TUNER_RADIO</constant>.</para>
+       </listitem>
+
+       <listitem>
+         <para>An optional driver access priority mechanism was
+added, see <xref linkend="app-pri" /> for details.</para>
+       </listitem>
+
+       <listitem>
+         <para>The audio input and output interface was found to be
+incomplete.</para>
+         <para>Previously the &VIDIOC-G-AUDIO;
+ioctl would enumerate the available audio inputs. An ioctl to
+determine the current audio input, if more than one combines with the
+current video input, did not exist. So
+<constant>VIDIOC_G_AUDIO</constant> was renamed to
+<constant>VIDIOC_G_AUDIO_OLD</constant>, this ioctl was removed on
+Kernel 2.6.39. The &VIDIOC-ENUMAUDIO; ioctl was added to enumerate
+audio inputs, while &VIDIOC-G-AUDIO; now reports the current audio
+input.</para>
+         <para>The same changes were made to &VIDIOC-G-AUDOUT; and
+&VIDIOC-ENUMAUDOUT;.</para>
+         <para>Until further the "videodev" module will automatically
+translate between the old and new ioctls, but drivers and applications
+must be updated to successfully compile again.</para>
+       </listitem>
+
+       <listitem>
+         <para>The &VIDIOC-OVERLAY; ioctl was incorrectly defined with
+write-read parameter. It was changed to write-only, while the write-read
+version was renamed to <constant>VIDIOC_OVERLAY_OLD</constant>. The old
+ioctl was removed on Kernel 2.6.39. Until further the "videodev"
+kernel module will automatically translate to the new version, so drivers
+must be recompiled, but not applications.</para>
+       </listitem>
+
+       <listitem>
+         <para><xref linkend="overlay" /> incorrectly stated that
+clipping rectangles define regions where the video can be seen.
+Correct is that clipping rectangles define regions where
+<emphasis>no</emphasis> video shall be displayed and so the graphics
+surface can be seen.</para>
+       </listitem>
+
+       <listitem>
+         <para>The &VIDIOC-S-PARM; and &VIDIOC-S-CTRL; ioctls were
+defined with write-only parameter, inconsistent with other ioctls
+modifying their argument. They were changed to write-read, while a
+<constant>_OLD</constant> suffix was added to the write-only versions.
+The old ioctls were removed on Kernel 2.6.39. Drivers and
+applications assuming a constant parameter need an update.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 2003-11-05</title>
+      <orderedlist>
+       <listitem>
+         <para>In <xref linkend="pixfmt-rgb" /> the following pixel
+formats were incorrectly transferred from Bill Dirks' V4L2
+specification. Descriptions below refer to bytes in memory, in
+ascending address order.<informaltable>
+             <tgroup cols="3">
+               <thead>
+                 <row>
+                   <entry>Symbol</entry>
+                   <entry>In this document prior to revision
+0.5</entry>
+                   <entry>Corrected</entry>
+                 </row>
+               </thead>
+               <tbody valign="top">
+                 <row>
+                   <entry><constant>V4L2_PIX_FMT_RGB24</constant></entry>
+                   <entry>B, G, R</entry>
+                   <entry>R, G, B</entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
+                   <entry>R, G, B</entry>
+                   <entry>B, G, R</entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
+                   <entry>B, G, R, X</entry>
+                   <entry>R, G, B, X</entry>
+                 </row>
+                 <row>
+                   <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
+                   <entry>R, G, B, X</entry>
+                   <entry>B, G, R, X</entry>
+                 </row>
+               </tbody>
+             </tgroup>
+           </informaltable> The
+<constant>V4L2_PIX_FMT_BGR24</constant> example was always
+correct.</para>
+         <para>In <xref linkend="v4l-image-properties" /> the mapping
+of the V4L <constant>VIDEO_PALETTE_RGB24</constant> and
+<constant>VIDEO_PALETTE_RGB32</constant> formats to V4L2 pixel formats
+was accordingly corrected.</para>
+       </listitem>
+
+       <listitem>
+         <para>Unrelated to the fixes above, drivers may still
+interpret some V4L2 RGB pixel formats differently. These issues have
+yet to be addressed, for details see <xref
+             linkend="pixfmt-rgb" />.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.6, 2004-05-09</title>
+      <orderedlist>
+       <listitem>
+         <para>The &VIDIOC-CROPCAP; ioctl was incorrectly defined
+with read-only parameter. It is now defined as write-read ioctl, while
+the read-only version was renamed to
+<constant>VIDIOC_CROPCAP_OLD</constant>. The old ioctl was removed
+on Kernel 2.6.39.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.8</title>
+      <orderedlist>
+       <listitem>
+         <para>A new field <structfield>input</structfield> (former
+<structfield>reserved[0]</structfield>) was added to the &v4l2-buffer;
+structure. Purpose of this field is to alternate between video inputs
+(&eg; cameras) in step with the video capturing process. This function
+must be enabled with the new <constant>V4L2_BUF_FLAG_INPUT</constant>
+flag. The <structfield>flags</structfield> field is no longer
+read-only.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 spec erratum 2004-08-01</title>
+
+      <orderedlist>
+       <listitem>
+         <para>The return value of the
+<xref linkend="func-open" /> function was incorrectly documented.</para>
+       </listitem>
+
+       <listitem>
+         <para>Audio output ioctls end in -AUDOUT, not -AUDIOOUT.</para>
+       </listitem>
+
+       <listitem>
+         <para>In the Current Audio Input example the
+<constant>VIDIOC_G_AUDIO</constant> ioctl took the wrong
+argument.</para>
+       </listitem>
+
+       <listitem>
+         <para>The documentation of the &VIDIOC-QBUF; and
+&VIDIOC-DQBUF; ioctls did not mention the &v4l2-buffer;
+<structfield>memory</structfield> field. It was also missing from
+examples. Also on the <constant>VIDIOC_DQBUF</constant> page the &EIO;
+was not documented.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.14</title>
+      <orderedlist>
+       <listitem>
+         <para>A new sliced VBI interface was added. It is documented
+in <xref linkend="sliced" /> and replaces the interface first
+proposed in V4L2 specification 0.8.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.15</title>
+      <orderedlist>
+       <listitem>
+         <para>The &VIDIOC-LOG-STATUS; ioctl was added.</para>
+       </listitem>
+
+       <listitem>
+         <para>New video standards
+<constant>V4L2_STD_NTSC_443</constant>,
+<constant>V4L2_STD_SECAM_LC</constant>,
+<constant>V4L2_STD_SECAM_DK</constant> (a set of SECAM D, K and K1),
+and <constant>V4L2_STD_ATSC</constant> (a set of
+<constant>V4L2_STD_ATSC_8_VSB</constant> and
+<constant>V4L2_STD_ATSC_16_VSB</constant>) were defined. Note the
+<constant>V4L2_STD_525_60</constant> set now includes
+<constant>V4L2_STD_NTSC_443</constant>. See also <xref
+             linkend="v4l2-std-id" />.</para>
+       </listitem>
+
+       <listitem>
+         <para>The <constant>VIDIOC_G_COMP</constant> and
+<constant>VIDIOC_S_COMP</constant> ioctl were renamed to
+<constant>VIDIOC_G_MPEGCOMP</constant> and
+<constant>VIDIOC_S_MPEGCOMP</constant> respectively. Their argument
+was replaced by a struct
+<structname>v4l2_mpeg_compression</structname> pointer. (The
+<constant>VIDIOC_G_MPEGCOMP</constant> and
+<constant>VIDIOC_S_MPEGCOMP</constant> ioctls where removed in Linux
+2.6.25.)</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 spec erratum 2005-11-27</title>
+      <para>The capture example in <xref linkend="capture-example" />
+called the &VIDIOC-S-CROP; ioctl without checking if cropping is
+supported. In the video standard selection example in
+<xref linkend="standard" /> the &VIDIOC-S-STD; call used the wrong
+argument type.</para>
+    </section>
+
+    <section>
+      <title>V4L2 spec erratum 2006-01-10</title>
+      <orderedlist>
+       <listitem>
+         <para>The <constant>V4L2_IN_ST_COLOR_KILL</constant> flag in
+&v4l2-input; not only indicates if the color killer is enabled, but
+also if it is active. (The color killer disables color decoding when
+it detects no color in the video signal to improve the image
+quality.)</para>
+       </listitem>
+
+       <listitem>
+         <para>&VIDIOC-S-PARM; is a write-read ioctl, not write-only as
+stated on its reference page. The ioctl changed in 2003 as noted above.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 spec erratum 2006-02-03</title>
+      <orderedlist>
+       <listitem>
+         <para>In &v4l2-captureparm; and &v4l2-outputparm; the
+<structfield>timeperframe</structfield> field gives the time in
+seconds, not microseconds.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 spec erratum 2006-02-04</title>
+      <orderedlist>
+       <listitem>
+         <para>The <structfield>clips</structfield> field in
+&v4l2-window; must point to an array of &v4l2-clip;, not a linked
+list, because drivers ignore the struct
+<structname>v4l2_clip</structname>.<structfield>next</structfield>
+pointer.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.17</title>
+      <orderedlist>
+       <listitem>
+         <para>New video standard macros were added:
+<constant>V4L2_STD_NTSC_M_KR</constant> (NTSC M South Korea), and the
+sets <constant>V4L2_STD_MN</constant>,
+<constant>V4L2_STD_B</constant>, <constant>V4L2_STD_GH</constant> and
+<constant>V4L2_STD_DK</constant>. The
+<constant>V4L2_STD_NTSC</constant> and
+<constant>V4L2_STD_SECAM</constant> sets now include
+<constant>V4L2_STD_NTSC_M_KR</constant> and
+<constant>V4L2_STD_SECAM_LC</constant> respectively.</para>
+       </listitem>
+
+       <listitem>
+         <para>A new <constant>V4L2_TUNER_MODE_LANG1_LANG2</constant>
+was defined to record both languages of a bilingual program. The
+use of <constant>V4L2_TUNER_MODE_STEREO</constant> for this purpose
+is deprecated now. See the &VIDIOC-G-TUNER; section for
+details.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 spec erratum 2006-09-23 (Draft 0.15)</title>
+      <orderedlist>
+       <listitem>
+         <para>In various places
+<constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant> and
+<constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant> of the sliced VBI
+interface were not mentioned along with other buffer types.</para>
+       </listitem>
+
+       <listitem>
+         <para>In <xref linkend="vidioc-g-audio" /> it was clarified
+that the &v4l2-audio; <structfield>mode</structfield> field is a flags
+field.</para>
+       </listitem>
+
+       <listitem>
+         <para><xref linkend="vidioc-querycap" /> did not mention the
+sliced VBI and radio capability flags.</para>
+       </listitem>
+
+       <listitem>
+         <para>In <xref linkend="vidioc-g-frequency" /> it was
+clarified that applications must initialize the tuner
+<structfield>type</structfield> field of &v4l2-frequency; before
+calling &VIDIOC-S-FREQUENCY;.</para>
+       </listitem>
+
+       <listitem>
+         <para>The <structfield>reserved</structfield> array
+in &v4l2-requestbuffers; has 2 elements, not 32.</para>
+       </listitem>
+
+       <listitem>
+         <para>In <xref linkend="output" /> and <xref
+             linkend="raw-vbi" /> the device file names
+<filename>/dev/vout</filename> which never caught on were replaced
+by <filename>/dev/video</filename>.</para>
+       </listitem>
+
+       <listitem>
+         <para>With Linux 2.6.15 the possible range for VBI device minor
+numbers was extended from 224-239 to 224-255. Accordingly device file names
+<filename>/dev/vbi0</filename> to <filename>/dev/vbi31</filename> are
+possible now.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.18</title>
+      <orderedlist>
+       <listitem>
+         <para>New ioctls &VIDIOC-G-EXT-CTRLS;, &VIDIOC-S-EXT-CTRLS;
+and &VIDIOC-TRY-EXT-CTRLS; were added, a flag to skip unsupported
+controls with &VIDIOC-QUERYCTRL;, new control types
+<constant>V4L2_CTRL_TYPE_INTEGER64</constant> and
+<constant>V4L2_CTRL_TYPE_CTRL_CLASS</constant> (<xref
+             linkend="v4l2-ctrl-type" />), and new control flags
+<constant>V4L2_CTRL_FLAG_READ_ONLY</constant>,
+<constant>V4L2_CTRL_FLAG_UPDATE</constant>,
+<constant>V4L2_CTRL_FLAG_INACTIVE</constant> and
+<constant>V4L2_CTRL_FLAG_SLIDER</constant> (<xref
+             linkend="control-flags" />). See <xref
+             linkend="extended-controls" /> for details.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.19</title>
+      <orderedlist>
+       <listitem>
+         <para>In &v4l2-sliced-vbi-cap; a buffer type field was added
+replacing a reserved field. Note on architectures where the size of
+enum types differs from int types the size of the structure changed.
+The &VIDIOC-G-SLICED-VBI-CAP; ioctl was redefined from being read-only
+to write-read. Applications must initialize the type field and clear
+the reserved fields now. These changes may <emphasis>break the
+compatibility</emphasis> with older drivers and applications.</para>
+       </listitem>
+
+       <listitem>
+         <para>The ioctls &VIDIOC-ENUM-FRAMESIZES; and
+&VIDIOC-ENUM-FRAMEINTERVALS; were added.</para>
+       </listitem>
+
+       <listitem>
+         <para>A new pixel format <constant>V4L2_PIX_FMT_RGB444</constant> (<xref
+linkend="rgb-formats" />) was added.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 spec erratum 2006-10-12 (Draft 0.17)</title>
+      <orderedlist>
+       <listitem>
+         <para><constant>V4L2_PIX_FMT_HM12</constant> (<xref
+linkend="reserved-formats" />) is a YUV 4:2:0, not 4:2:2 format.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.21</title>
+      <orderedlist>
+       <listitem>
+         <para>The <filename>videodev2.h</filename> header file is
+now dual licensed under GNU General Public License version two or
+later, and under a 3-clause BSD-style license.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.22</title>
+      <orderedlist>
+       <listitem>
+         <para>Two new field orders
+         <constant>V4L2_FIELD_INTERLACED_TB</constant> and
+         <constant>V4L2_FIELD_INTERLACED_BT</constant> were
+         added. See <xref linkend="v4l2-field" /> for details.</para>
+       </listitem>
+
+       <listitem>
+         <para>Three new clipping/blending methods with a global or
+straight or inverted local alpha value were added to the video overlay
+interface. See the description of the &VIDIOC-G-FBUF; and
+&VIDIOC-S-FBUF; ioctls for details.</para>
+         <para>A new <structfield>global_alpha</structfield> field
+was added to <link
+linkend="v4l2-window"><structname>v4l2_window</structname></link>,
+extending the structure. This may <emphasis>break
+compatibility</emphasis> with applications using a struct
+<structname>v4l2_window</structname> directly. However the <link
+linkend="vidioc-g-fmt">VIDIOC_G/S/TRY_FMT</link> ioctls, which take a
+pointer to a <link linkend="v4l2-format">v4l2_format</link> parent
+structure with padding bytes at the end, are not affected.</para>
+       </listitem>
+
+       <listitem>
+         <para>The format of the <structfield>chromakey</structfield>
+field in &v4l2-window; changed from "host order RGB32" to a pixel
+value in the same format as the framebuffer. This may <emphasis>break
+compatibility</emphasis> with existing applications. Drivers
+supporting the "host order RGB32" format are not known.</para>
+       </listitem>
+
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.24</title>
+      <orderedlist>
+       <listitem>
+         <para>The pixel formats
+<constant>V4L2_PIX_FMT_PAL8</constant>,
+<constant>V4L2_PIX_FMT_YUV444</constant>,
+<constant>V4L2_PIX_FMT_YUV555</constant>,
+<constant>V4L2_PIX_FMT_YUV565</constant> and
+<constant>V4L2_PIX_FMT_YUV32</constant> were added.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.25</title>
+      <orderedlist>
+       <listitem>
+         <para>The pixel formats <link linkend="V4L2-PIX-FMT-Y16">
+<constant>V4L2_PIX_FMT_Y16</constant></link> and <link
+linkend="V4L2-PIX-FMT-SBGGR16">
+<constant>V4L2_PIX_FMT_SBGGR16</constant></link> were added.</para>
+       </listitem>
+       <listitem>
+         <para>New <link linkend="control">controls</link>
+<constant>V4L2_CID_POWER_LINE_FREQUENCY</constant>,
+<constant>V4L2_CID_HUE_AUTO</constant>,
+<constant>V4L2_CID_WHITE_BALANCE_TEMPERATURE</constant>,
+<constant>V4L2_CID_SHARPNESS</constant> and
+<constant>V4L2_CID_BACKLIGHT_COMPENSATION</constant> were added. The
+controls <constant>V4L2_CID_BLACK_LEVEL</constant>,
+<constant>V4L2_CID_WHITENESS</constant>,
+<constant>V4L2_CID_HCENTER</constant> and
+<constant>V4L2_CID_VCENTER</constant> were deprecated.
+</para>
+       </listitem>
+       <listitem>
+         <para>A <link linkend="camera-controls">Camera controls
+class</link> was added, with the new controls
+<constant>V4L2_CID_EXPOSURE_AUTO</constant>,
+<constant>V4L2_CID_EXPOSURE_ABSOLUTE</constant>,
+<constant>V4L2_CID_EXPOSURE_AUTO_PRIORITY</constant>,
+<constant>V4L2_CID_PAN_RELATIVE</constant>,
+<constant>V4L2_CID_TILT_RELATIVE</constant>,
+<constant>V4L2_CID_PAN_RESET</constant>,
+<constant>V4L2_CID_TILT_RESET</constant>,
+<constant>V4L2_CID_PAN_ABSOLUTE</constant>,
+<constant>V4L2_CID_TILT_ABSOLUTE</constant>,
+<constant>V4L2_CID_FOCUS_ABSOLUTE</constant>,
+<constant>V4L2_CID_FOCUS_RELATIVE</constant> and
+<constant>V4L2_CID_FOCUS_AUTO</constant>.</para>
+       </listitem>
+       <listitem>
+         <para>The <constant>VIDIOC_G_MPEGCOMP</constant> and
+<constant>VIDIOC_S_MPEGCOMP</constant> ioctls, which were superseded
+by the <link linkend="extended-controls">extended controls</link>
+interface in Linux 2.6.18, where finally removed from the
+<filename>videodev2.h</filename> header file.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.26</title>
+      <orderedlist>
+       <listitem>
+         <para>The pixel formats
+<constant>V4L2_PIX_FMT_Y16</constant> and
+<constant>V4L2_PIX_FMT_SBGGR16</constant> were added.</para>
+       </listitem>
+       <listitem>
+         <para>Added user controls
+<constant>V4L2_CID_CHROMA_AGC</constant> and
+<constant>V4L2_CID_COLOR_KILLER</constant>.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.27</title>
+      <orderedlist>
+       <listitem>
+         <para>The &VIDIOC-S-HW-FREQ-SEEK; ioctl and the
+<constant>V4L2_CAP_HW_FREQ_SEEK</constant> capability were added.</para>
+       </listitem>
+       <listitem>
+         <para>The pixel formats
+<constant>V4L2_PIX_FMT_YVYU</constant>,
+<constant>V4L2_PIX_FMT_PCA501</constant>,
+<constant>V4L2_PIX_FMT_PCA505</constant>,
+<constant>V4L2_PIX_FMT_PCA508</constant>,
+<constant>V4L2_PIX_FMT_PCA561</constant>,
+<constant>V4L2_PIX_FMT_SGBRG8</constant>,
+<constant>V4L2_PIX_FMT_PAC207</constant> and
+<constant>V4L2_PIX_FMT_PJPG</constant> were added.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.28</title>
+      <orderedlist>
+       <listitem>
+         <para>Added <constant>V4L2_MPEG_AUDIO_ENCODING_AAC</constant> and
+<constant>V4L2_MPEG_AUDIO_ENCODING_AC3</constant> MPEG audio encodings.</para>
+       </listitem>
+       <listitem>
+         <para>Added <constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC</constant> MPEG
+video encoding.</para>
+       </listitem>
+       <listitem>
+         <para>The pixel formats
+<constant>V4L2_PIX_FMT_SGRBG10</constant> and
+<constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant> were added.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+
+    <section>
+      <title>V4L2 in Linux 2.6.29</title>
+      <orderedlist>
+       <listitem>
+         <para>The <constant>VIDIOC_G_CHIP_IDENT</constant> ioctl was renamed
+to <constant>VIDIOC_G_CHIP_IDENT_OLD</constant> and &VIDIOC-DBG-G-CHIP-IDENT;
+was introduced in its place. The old struct <structname>v4l2_chip_ident</structname>
+was renamed to <structname id="v4l2-chip-ident-old">v4l2_chip_ident_old</structname>.</para>
+       </listitem>
+       <listitem>
+         <para>The pixel formats
+<constant>V4L2_PIX_FMT_VYUY</constant>,
+<constant>V4L2_PIX_FMT_NV16</constant> and
+<constant>V4L2_PIX_FMT_NV61</constant> were added.</para>
+       </listitem>
+       <listitem>
+         <para>Added camera controls
+<constant>V4L2_CID_ZOOM_ABSOLUTE</constant>,
+<constant>V4L2_CID_ZOOM_RELATIVE</constant>,
+<constant>V4L2_CID_ZOOM_CONTINUOUS</constant> and
+<constant>V4L2_CID_PRIVACY</constant>.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+    <section>
+      <title>V4L2 in Linux 2.6.30</title>
+      <orderedlist>
+       <listitem>
+         <para>New control flag <constant>V4L2_CTRL_FLAG_WRITE_ONLY</constant> was added.</para>
+       </listitem>
+       <listitem>
+         <para>New control <constant>V4L2_CID_COLORFX</constant> was added.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+    <section>
+      <title>V4L2 in Linux 2.6.32</title>
+      <orderedlist>
+       <listitem>
+         <para>In order to be easier to compare a V4L2 API and a kernel
+version, now V4L2 API is numbered using the Linux Kernel version numeration.</para>
+       </listitem>
+       <listitem>
+         <para>Finalized the RDS capture API. See <xref linkend="rds" /> for
+more information.</para>
+       </listitem>
+       <listitem>
+         <para>Added new capabilities for modulators and RDS encoders.</para>
+       </listitem>
+       <listitem>
+         <para>Add description for libv4l API.</para>
+       </listitem>
+       <listitem>
+         <para>Added support for string controls via new type <constant>V4L2_CTRL_TYPE_STRING</constant>.</para>
+       </listitem>
+       <listitem>
+         <para>Added <constant>V4L2_CID_BAND_STOP_FILTER</constant> documentation.</para>
+       </listitem>
+       <listitem>
+         <para>Added FM Modulator (FM TX) Extended Control Class: <constant>V4L2_CTRL_CLASS_FM_TX</constant> and their Control IDs.</para>
+       </listitem>
+       <listitem>
+         <para>Added Remote Controller chapter, describing the default Remote Controller mapping for media devices.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+    <section>
+      <title>V4L2 in Linux 2.6.33</title>
+      <orderedlist>
+       <listitem>
+         <para>Added support for Digital Video timings in order to support HDTV receivers and transmitters.</para>
+       </listitem>
+      </orderedlist>
+    </section>
+    <section>
+      <title>V4L2 in Linux 2.6.34</title>
+      <orderedlist>
+       <listitem>
+         <para>Added
+<constant>V4L2_CID_IRIS_ABSOLUTE</constant> and
+<constant>V4L2_CID_IRIS_RELATIVE</constant> controls to the
+           <link linkend="camera-controls">Camera controls class</link>.
+         </para>
+       </listitem>
+      </orderedlist>
+    </section>
+    <section>
+      <title>V4L2 in Linux 2.6.37</title>
+      <orderedlist>
+       <listitem>
+         <para>Remove the vtx (videotext/teletext) API. This API was no longer
+used and no hardware exists to verify the API. Nor were any userspace applications found
+that used it. It was originally scheduled for removal in 2.6.35.
+         </para>
+       </listitem>
+      </orderedlist>
+    </section>
+    <section>
+      <title>V4L2 in Linux 2.6.39</title>
+      <orderedlist>
+        <listitem>
+          <para>The old VIDIOC_*_OLD symbols and V4L1 support were removed.</para>
+        </listitem>
+        <listitem>
+          <para>Multi-planar API added. Does not affect the compatibility of
+          current drivers and applications. See
+          <link linkend="planar-apis">multi-planar API</link>
+          for details.</para>
+        </listitem>
+      </orderedlist>
+    </section>
+    <section>
+      <title>V4L2 in Linux 3.1</title>
+      <orderedlist>
+        <listitem>
+         <para>VIDIOC_QUERYCAP now returns a per-subsystem version instead of a per-driver one.</para>
+         <para>Standardize an error code for invalid ioctl.</para>
+          <para>Added V4L2_CTRL_TYPE_BITMASK.</para>
+        </listitem>
+      </orderedlist>
+    </section>
+
+    <section id="other">
+      <title>Relation of V4L2 to other Linux multimedia APIs</title>
+
+      <section id="xvideo">
+        <title>X Video Extension</title>
+
+        <para>The X Video Extension (abbreviated XVideo or just Xv) is
+an extension of the X Window system, implemented for example by the
+XFree86 project. Its scope is similar to V4L2, an API to video capture
+and output devices for X clients. Xv allows applications to display
+live video in a window, send window contents to a TV output, and
+capture or output still images in XPixmaps<footnote>
+         <para>This is not implemented in XFree86.</para>
+       </footnote>. With their implementation XFree86 makes the
+extension available across many operating systems and
+architectures.</para>
+
+        <para>Because the driver is embedded into the X server Xv has a
+number of advantages over the V4L2 <link linkend="overlay">video
+overlay interface</link>. The driver can easily determine the overlay
+target, &ie; visible graphics memory or off-screen buffers for a
+destructive overlay. It can program the RAMDAC for a non-destructive
+overlay, scaling or color-keying, or the clipping functions of the
+video capture hardware, always in sync with drawing operations or
+windows moving or changing their stacking order.</para>
+
+        <para>To combine the advantages of Xv and V4L a special Xv
+driver exists in XFree86 and XOrg, just programming any overlay capable
+Video4Linux device it finds. To enable it
+<filename>/etc/X11/XF86Config</filename> must contain these lines:</para>
+        <para><screen>
+Section "Module"
+    Load "v4l"
+EndSection</screen></para>
+
+        <para>As of XFree86 4.2 this driver still supports only V4L
+ioctls, however it should work just fine with all V4L2 devices through
+the V4L2 backward-compatibility layer. Since V4L2 permits multiple
+opens it is possible (if supported by the V4L2 driver) to capture
+video while an X client requested video overlay. Restrictions of
+simultaneous capturing and overlay are discussed in <xref
+         linkend="overlay" /> apply.</para>
+
+        <para>Only marginally related to V4L2, XFree86 extended Xv to
+support hardware YUV to RGB conversion and scaling for faster video
+playback, and added an interface to MPEG-2 decoding hardware. This API
+is useful to display images captured with V4L2 devices.</para>
+      </section>
+
+      <section>
+        <title>Digital Video</title>
+
+        <para>V4L2 does not support digital terrestrial, cable or
+satellite broadcast. A separate project aiming at digital receivers
+exists. You can find its homepage at <ulink
+url="http://linuxtv.org">http://linuxtv.org</ulink>. The Linux DVB API
+has no connection to the V4L2 API except that drivers for hybrid
+hardware may support both.</para>
+      </section>
+
+      <section>
+        <title>Audio Interfaces</title>
+
+        <para>[to do - OSS/ALSA]</para>
+      </section>
+    </section>
+
+    <section id="experimental">
+      <title>Experimental API Elements</title>
+
+      <para>The following V4L2 API elements are currently experimental
+and may change in the future.</para>
+
+      <itemizedlist>
+        <listitem>
+         <para>Video Output Overlay (OSD) Interface, <xref
+           linkend="osd" />.</para>
+        </listitem>
+       <listitem>
+         <para><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant>,
+       &v4l2-buf-type;, <xref linkend="v4l2-buf-type" />.</para>
+        </listitem>
+        <listitem>
+         <para><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant>,
+&VIDIOC-QUERYCAP; ioctl, <xref linkend="device-capabilities" />.</para>
+        </listitem>
+        <listitem>
+         <para>&VIDIOC-ENUM-FRAMESIZES; and
+&VIDIOC-ENUM-FRAMEINTERVALS; ioctls.</para>
+        </listitem>
+        <listitem>
+         <para>&VIDIOC-G-ENC-INDEX; ioctl.</para>
+        </listitem>
+        <listitem>
+         <para>&VIDIOC-ENCODER-CMD; and &VIDIOC-TRY-ENCODER-CMD;
+ioctls.</para>
+        </listitem>
+        <listitem>
+         <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
+ioctls.</para>
+        </listitem>
+        <listitem>
+         <para>&VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
+        </listitem>
+        <listitem>
+         <para>Flash API. <xref linkend="flash-controls" /></para>
+        </listitem>
+      </itemizedlist>
+    </section>
+
+    <section id="obsolete">
+      <title>Obsolete API Elements</title>
+
+      <para>The following V4L2 API elements were superseded by new
+interfaces and should not be implemented in new drivers.</para>
+
+      <itemizedlist>
+        <listitem>
+         <para><constant>VIDIOC_G_MPEGCOMP</constant> and
+<constant>VIDIOC_S_MPEGCOMP</constant> ioctls. Use Extended Controls,
+<xref linkend="extended-controls" />.</para>
+        </listitem>
+      </itemizedlist>
+    </section>
+  </section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
new file mode 100644 (file)
index 0000000..8516401
--- /dev/null
@@ -0,0 +1,3366 @@
+  <section id="control">
+    <title>User Controls</title>
+
+    <para>Devices typically have a number of user-settable controls
+such as brightness, saturation and so on, which would be presented to
+the user on a graphical user interface. But, different devices
+will have different controls available, and furthermore, the range of
+possible values, and the default value will vary from device to
+device. The control ioctls provide the information and a mechanism to
+create a nice user interface for these controls that will work
+correctly with any device.</para>
+
+    <para>All controls are accessed using an ID value. V4L2 defines
+several IDs for specific purposes. Drivers can also implement their
+own custom controls using <constant>V4L2_CID_PRIVATE_BASE</constant>
+and higher values. The pre-defined control IDs have the prefix
+<constant>V4L2_CID_</constant>, and are listed in <xref
+linkend="control-id" />. The ID is used when querying the attributes of
+a control, and when getting or setting the current value.</para>
+
+    <para>Generally applications should present controls to the user
+without assumptions about their purpose. Each control comes with a
+name string the user is supposed to understand. When the purpose is
+non-intuitive the driver writer should provide a user manual, a user
+interface plug-in or a driver specific panel application. Predefined
+IDs were introduced to change a few controls programmatically, for
+example to mute a device during a channel switch.</para>
+
+    <para>Drivers may enumerate different controls after switching
+the current video input or output, tuner or modulator, or audio input
+or output. Different in the sense of other bounds, another default and
+current value, step size or other menu items. A control with a certain
+<emphasis>custom</emphasis> ID can also change name and
+type.<footnote>
+       <para>It will be more convenient for applications if drivers
+make use of the <constant>V4L2_CTRL_FLAG_DISABLED</constant> flag, but
+that was never required.</para>
+      </footnote> Control values are stored globally, they do not
+change when switching except to stay within the reported bounds. They
+also do not change &eg; when the device is opened or closed, when the
+tuner radio frequency is changed or generally never without
+application request. Since V4L2 specifies no event mechanism, panel
+applications intended to cooperate with other panel applications (be
+they built into a larger application, as a TV viewer) may need to
+regularly poll control values to update their user
+interface.<footnote>
+       <para>Applications could call an ioctl to request events.
+After another process called &VIDIOC-S-CTRL; or another ioctl changing
+shared properties the &func-select; function would indicate
+readability until any ioctl (querying the properties) is
+called.</para>
+      </footnote></para>
+
+    <para>
+      All controls use machine endianness.
+    </para>
+
+    <table pgwide="1" frame="none" id="control-id">
+      <title>Control IDs</title>
+      <tgroup cols="3">
+       &cs-def;
+       <thead>
+         <row>
+           <entry>ID</entry>
+           <entry>Type</entry>
+           <entry>Description</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_CID_BASE</constant></entry>
+           <entry></entry>
+           <entry>First predefined ID, equal to
+<constant>V4L2_CID_BRIGHTNESS</constant>.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_USER_BASE</constant></entry>
+           <entry></entry>
+           <entry>Synonym of <constant>V4L2_CID_BASE</constant>.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_BRIGHTNESS</constant></entry>
+           <entry>integer</entry>
+           <entry>Picture brightness, or more precisely, the black
+level.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_CONTRAST</constant></entry>
+           <entry>integer</entry>
+           <entry>Picture contrast or luma gain.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_SATURATION</constant></entry>
+           <entry>integer</entry>
+           <entry>Picture color saturation or chroma gain.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_HUE</constant></entry>
+           <entry>integer</entry>
+           <entry>Hue or color balance.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_AUDIO_VOLUME</constant></entry>
+           <entry>integer</entry>
+           <entry>Overall audio volume. Note some drivers also
+provide an OSS or ALSA mixer interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_AUDIO_BALANCE</constant></entry>
+           <entry>integer</entry>
+           <entry>Audio stereo balance. Minimum corresponds to all
+the way left, maximum to right.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_AUDIO_BASS</constant></entry>
+           <entry>integer</entry>
+           <entry>Audio bass adjustment.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_AUDIO_TREBLE</constant></entry>
+           <entry>integer</entry>
+           <entry>Audio treble adjustment.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_AUDIO_MUTE</constant></entry>
+           <entry>boolean</entry>
+           <entry>Mute audio, &ie; set the volume to zero, however
+without affecting <constant>V4L2_CID_AUDIO_VOLUME</constant>. Like
+ALSA drivers, V4L2 drivers must mute at load time to avoid excessive
+noise. Actually the entire device should be reset to a low power
+consumption state.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_AUDIO_LOUDNESS</constant></entry>
+           <entry>boolean</entry>
+           <entry>Loudness mode (bass boost).</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_BLACK_LEVEL</constant></entry>
+           <entry>integer</entry>
+           <entry>Another name for brightness (not a synonym of
+<constant>V4L2_CID_BRIGHTNESS</constant>). This control is deprecated
+and should not be used in new drivers and applications.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_AUTO_WHITE_BALANCE</constant></entry>
+           <entry>boolean</entry>
+           <entry>Automatic white balance (cameras).</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_DO_WHITE_BALANCE</constant></entry>
+           <entry>button</entry>
+           <entry>This is an action control. When set (the value is
+ignored), the device will do a white balance and then hold the current
+setting. Contrast this with the boolean
+<constant>V4L2_CID_AUTO_WHITE_BALANCE</constant>, which, when
+activated, keeps adjusting the white balance.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_RED_BALANCE</constant></entry>
+           <entry>integer</entry>
+           <entry>Red chroma balance.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_BLUE_BALANCE</constant></entry>
+           <entry>integer</entry>
+           <entry>Blue chroma balance.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_GAMMA</constant></entry>
+           <entry>integer</entry>
+           <entry>Gamma adjust.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_WHITENESS</constant></entry>
+           <entry>integer</entry>
+           <entry>Whiteness for grey-scale devices. This is a synonym
+for <constant>V4L2_CID_GAMMA</constant>. This control is deprecated
+and should not be used in new drivers and applications.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_EXPOSURE</constant></entry>
+           <entry>integer</entry>
+           <entry>Exposure (cameras). [Unit?]</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_AUTOGAIN</constant></entry>
+           <entry>boolean</entry>
+           <entry>Automatic gain/exposure control.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_GAIN</constant></entry>
+           <entry>integer</entry>
+           <entry>Gain control.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_HFLIP</constant></entry>
+           <entry>boolean</entry>
+           <entry>Mirror the picture horizontally.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_VFLIP</constant></entry>
+           <entry>boolean</entry>
+           <entry>Mirror the picture vertically.</entry>
+         </row>
+       <row>
+         <entry><constant>V4L2_CID_HCENTER_DEPRECATED</constant> (formerly <constant>V4L2_CID_HCENTER</constant>)</entry>
+           <entry>integer</entry>
+           <entry>Horizontal image centering. This control is
+deprecated. New drivers and applications should use the <link
+linkend="camera-controls">Camera class controls</link>
+<constant>V4L2_CID_PAN_ABSOLUTE</constant>,
+<constant>V4L2_CID_PAN_RELATIVE</constant> and
+<constant>V4L2_CID_PAN_RESET</constant> instead.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_VCENTER_DEPRECATED</constant>
+           (formerly <constant>V4L2_CID_VCENTER</constant>)</entry>
+           <entry>integer</entry>
+           <entry>Vertical image centering. Centering is intended to
+<emphasis>physically</emphasis> adjust cameras. For image cropping see
+<xref linkend="crop" />, for clipping <xref linkend="overlay" />. This
+control is deprecated. New drivers and applications should use the
+<link linkend="camera-controls">Camera class controls</link>
+<constant>V4L2_CID_TILT_ABSOLUTE</constant>,
+<constant>V4L2_CID_TILT_RELATIVE</constant> and
+<constant>V4L2_CID_TILT_RESET</constant> instead.</entry>
+         </row>
+         <row id="v4l2-power-line-frequency">
+           <entry><constant>V4L2_CID_POWER_LINE_FREQUENCY</constant></entry>
+           <entry>enum</entry>
+           <entry>Enables a power line frequency filter to avoid
+flicker. Possible values for <constant>enum v4l2_power_line_frequency</constant> are:
+<constant>V4L2_CID_POWER_LINE_FREQUENCY_DISABLED</constant> (0),
+<constant>V4L2_CID_POWER_LINE_FREQUENCY_50HZ</constant> (1) and
+<constant>V4L2_CID_POWER_LINE_FREQUENCY_60HZ</constant> (2).</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_HUE_AUTO</constant></entry>
+           <entry>boolean</entry>
+           <entry>Enables automatic hue control by the device. The
+effect of setting <constant>V4L2_CID_HUE</constant> while automatic
+hue control is enabled is undefined, drivers should ignore such
+request.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_WHITE_BALANCE_TEMPERATURE</constant></entry>
+           <entry>integer</entry>
+           <entry>This control specifies the white balance settings
+as a color temperature in Kelvin. A driver should have a minimum of
+2800 (incandescent) to 6500 (daylight). For more information about
+color temperature see <ulink
+url="http://en.wikipedia.org/wiki/Color_temperature">Wikipedia</ulink>.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_SHARPNESS</constant></entry>
+           <entry>integer</entry>
+           <entry>Adjusts the sharpness filters in a camera. The
+minimum value disables the filters, higher values give a sharper
+picture.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_BACKLIGHT_COMPENSATION</constant></entry>
+           <entry>integer</entry>
+           <entry>Adjusts the backlight compensation in a camera. The
+minimum value disables backlight compensation.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_CHROMA_AGC</constant></entry>
+           <entry>boolean</entry>
+           <entry>Chroma automatic gain control.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_CHROMA_GAIN</constant></entry>
+           <entry>integer</entry>
+           <entry>Adjusts the Chroma gain control (for use when chroma AGC
+           is disabled).</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_COLOR_KILLER</constant></entry>
+           <entry>boolean</entry>
+           <entry>Enable the color killer (&ie; force a black &amp; white image in case of a weak video signal).</entry>
+         </row>
+         <row id="v4l2-colorfx">
+           <entry><constant>V4L2_CID_COLORFX</constant></entry>
+           <entry>enum</entry>
+           <entry>Selects a color effect. Possible values for
+<constant>enum v4l2_colorfx</constant> are:
+<constant>V4L2_COLORFX_NONE</constant> (0),
+<constant>V4L2_COLORFX_BW</constant> (1),
+<constant>V4L2_COLORFX_SEPIA</constant> (2),
+<constant>V4L2_COLORFX_NEGATIVE</constant> (3),
+<constant>V4L2_COLORFX_EMBOSS</constant> (4),
+<constant>V4L2_COLORFX_SKETCH</constant> (5),
+<constant>V4L2_COLORFX_SKY_BLUE</constant> (6),
+<constant>V4L2_COLORFX_GRASS_GREEN</constant> (7),
+<constant>V4L2_COLORFX_SKIN_WHITEN</constant> (8) and
+<constant>V4L2_COLORFX_VIVID</constant> (9).</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_ROTATE</constant></entry>
+           <entry>integer</entry>
+           <entry>Rotates the image by specified angle. Common angles are 90,
+           270 and 180. Rotating the image to 90 and 270 will reverse the height
+           and width of the display window. It is necessary to set the new height and
+           width of the picture using the &VIDIOC-S-FMT; ioctl according to
+           the rotation angle selected.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_BG_COLOR</constant></entry>
+           <entry>integer</entry>
+           <entry>Sets the background color on the current output device.
+           Background color needs to be specified in the RGB24 format. The
+           supplied 32 bit value is interpreted as bits 0-7 Red color information,
+           bits 8-15 Green color information, bits 16-23 Blue color
+           information and bits 24-31 must be zero.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_ILLUMINATORS_1</constant>
+               <constant>V4L2_CID_ILLUMINATORS_2</constant></entry>
+           <entry>boolean</entry>
+           <entry>Switch on or off the illuminator 1 or 2 of the device
+               (usually a microscope).</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_LASTP1</constant></entry>
+           <entry></entry>
+           <entry>End of the predefined control IDs (currently
+<constant>V4L2_CID_ILLUMINATORS_2</constant> + 1).</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_MIN_BUFFERS_FOR_CAPTURE</constant></entry>
+           <entry>integer</entry>
+           <entry>This is a read-only control that can be read by the application
+and used as a hint to determine the number of CAPTURE buffers to pass to REQBUFS.
+The value is the minimum number of CAPTURE buffers that is necessary for hardware
+to work.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_MIN_BUFFERS_FOR_OUTPUT</constant></entry>
+           <entry>integer</entry>
+           <entry>This is a read-only control that can be read by the application
+and used as a hint to determine the number of OUTPUT buffers to pass to REQBUFS.
+The value is the minimum number of OUTPUT buffers that is necessary for hardware
+to work.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CID_PRIVATE_BASE</constant></entry>
+           <entry></entry>
+           <entry>ID of the first custom (driver specific) control.
+Applications depending on particular custom controls should check the
+driver name and version, see <xref linkend="querycap" />.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <para>Applications can enumerate the available controls with the
+&VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls, get and set a
+control value with the &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls.
+Drivers must implement <constant>VIDIOC_QUERYCTRL</constant>,
+<constant>VIDIOC_G_CTRL</constant> and
+<constant>VIDIOC_S_CTRL</constant> when the device has one or more
+controls, <constant>VIDIOC_QUERYMENU</constant> when it has one or
+more menu type controls.</para>
+
+    <example>
+      <title>Enumerating all controls</title>
+
+      <programlisting>
+&v4l2-queryctrl; queryctrl;
+&v4l2-querymenu; querymenu;
+
+static void
+enumerate_menu (void)
+{
+       printf ("  Menu items:\n");
+
+       memset (&amp;querymenu, 0, sizeof (querymenu));
+       querymenu.id = queryctrl.id;
+
+       for (querymenu.index = queryctrl.minimum;
+            querymenu.index &lt;= queryctrl.maximum;
+             querymenu.index++) {
+               if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &amp;querymenu)) {
+                       printf ("  %s\n", querymenu.name);
+               }
+       }
+}
+
+memset (&amp;queryctrl, 0, sizeof (queryctrl));
+
+for (queryctrl.id = V4L2_CID_BASE;
+     queryctrl.id &lt; V4L2_CID_LASTP1;
+     queryctrl.id++) {
+       if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+               if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
+                       continue;
+
+               printf ("Control %s\n", queryctrl.name);
+
+               if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+                       enumerate_menu ();
+       } else {
+               if (errno == EINVAL)
+                       continue;
+
+               perror ("VIDIOC_QUERYCTRL");
+               exit (EXIT_FAILURE);
+       }
+}
+
+for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
+     queryctrl.id++) {
+       if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+               if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
+                       continue;
+
+               printf ("Control %s\n", queryctrl.name);
+
+               if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+                       enumerate_menu ();
+       } else {
+               if (errno == EINVAL)
+                       break;
+
+               perror ("VIDIOC_QUERYCTRL");
+               exit (EXIT_FAILURE);
+       }
+}
+</programlisting>
+    </example>
+
+    <example>
+      <title>Changing controls</title>
+
+      <programlisting>
+&v4l2-queryctrl; queryctrl;
+&v4l2-control; control;
+
+memset (&amp;queryctrl, 0, sizeof (queryctrl));
+queryctrl.id = V4L2_CID_BRIGHTNESS;
+
+if (-1 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+       if (errno != EINVAL) {
+               perror ("VIDIOC_QUERYCTRL");
+               exit (EXIT_FAILURE);
+       } else {
+               printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+       }
+} else if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED) {
+       printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+} else {
+       memset (&amp;control, 0, sizeof (control));
+       control.id = V4L2_CID_BRIGHTNESS;
+       control.value = queryctrl.default_value;
+
+       if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &amp;control)) {
+               perror ("VIDIOC_S_CTRL");
+               exit (EXIT_FAILURE);
+       }
+}
+
+memset (&amp;control, 0, sizeof (control));
+control.id = V4L2_CID_CONTRAST;
+
+if (0 == ioctl (fd, &VIDIOC-G-CTRL;, &amp;control)) {
+       control.value += 1;
+
+       /* The driver may clamp the value or return ERANGE, ignored here */
+
+       if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &amp;control)
+           &amp;&amp; errno != ERANGE) {
+               perror ("VIDIOC_S_CTRL");
+               exit (EXIT_FAILURE);
+       }
+/* Ignore if V4L2_CID_CONTRAST is unsupported */
+} else if (errno != EINVAL) {
+       perror ("VIDIOC_G_CTRL");
+       exit (EXIT_FAILURE);
+}
+
+control.id = V4L2_CID_AUDIO_MUTE;
+control.value = TRUE; /* silence */
+
+/* Errors ignored */
+ioctl (fd, VIDIOC_S_CTRL, &amp;control);
+</programlisting>
+    </example>
+  </section>
+
+  <section id="extended-controls">
+    <title>Extended Controls</title>
+
+    <section>
+      <title>Introduction</title>
+
+      <para>The control mechanism as originally designed was meant
+to be used for user settings (brightness, saturation, etc). However,
+it turned out to be a very useful model for implementing more
+complicated driver APIs where each driver implements only a subset of
+a larger API.</para>
+
+      <para>The MPEG encoding API was the driving force behind
+designing and implementing this extended control mechanism: the MPEG
+standard is quite large and the currently supported hardware MPEG
+encoders each only implement a subset of this standard. Further more,
+many parameters relating to how the video is encoded into an MPEG
+stream are specific to the MPEG encoding chip since the MPEG standard
+only defines the format of the resulting MPEG stream, not how the
+video is actually encoded into that format.</para>
+
+      <para>Unfortunately, the original control API lacked some
+features needed for these new uses and so it was extended into the
+(not terribly originally named) extended control API.</para>
+
+      <para>Even though the MPEG encoding API was the first effort
+to use the Extended Control API, nowadays there are also other classes
+of Extended Controls, such as Camera Controls and FM Transmitter Controls.
+The Extended Controls API as well as all Extended Controls classes are
+described in the following text.</para>
+    </section>
+
+    <section>
+      <title>The Extended Control API</title>
+
+      <para>Three new ioctls are available: &VIDIOC-G-EXT-CTRLS;,
+&VIDIOC-S-EXT-CTRLS; and &VIDIOC-TRY-EXT-CTRLS;. These ioctls act on
+arrays of controls (as opposed to the &VIDIOC-G-CTRL; and
+&VIDIOC-S-CTRL; ioctls that act on a single control). This is needed
+since it is often required to atomically change several controls at
+once.</para>
+
+      <para>Each of the new ioctls expects a pointer to a
+&v4l2-ext-controls;. This structure contains a pointer to the control
+array, a count of the number of controls in that array and a control
+class. Control classes are used to group similar controls into a
+single class. For example, control class
+<constant>V4L2_CTRL_CLASS_USER</constant> contains all user controls
+(&ie; all controls that can also be set using the old
+<constant>VIDIOC_S_CTRL</constant> ioctl). Control class
+<constant>V4L2_CTRL_CLASS_MPEG</constant> contains all controls
+relating to MPEG encoding, etc.</para>
+
+      <para>All controls in the control array must belong to the
+specified control class. An error is returned if this is not the
+case.</para>
+
+      <para>It is also possible to use an empty control array (count
+== 0) to check whether the specified control class is
+supported.</para>
+
+      <para>The control array is a &v4l2-ext-control; array. The
+<structname>v4l2_ext_control</structname> structure is very similar to
+&v4l2-control;, except for the fact that it also allows for 64-bit
+values and pointers to be passed.</para>
+
+      <para>It is important to realize that due to the flexibility of
+controls it is necessary to check whether the control you want to set
+actually is supported in the driver and what the valid range of values
+is. So use the &VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls to
+check this. Also note that it is possible that some of the menu
+indices in a control of type <constant>V4L2_CTRL_TYPE_MENU</constant>
+may not be supported (<constant>VIDIOC_QUERYMENU</constant> will
+return an error). A good example is the list of supported MPEG audio
+bitrates. Some drivers only support one or two bitrates, others
+support a wider range.</para>
+
+      <para>
+       All controls use machine endianness.
+      </para>
+    </section>
+
+    <section>
+      <title>Enumerating Extended Controls</title>
+
+      <para>The recommended way to enumerate over the extended
+controls is by using &VIDIOC-QUERYCTRL; in combination with the
+<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> flag:</para>
+
+      <informalexample>
+       <programlisting>
+&v4l2-queryctrl; qctrl;
+
+qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
+       /* ... */
+       qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+}
+</programlisting>
+      </informalexample>
+
+      <para>The initial control ID is set to 0 ORed with the
+<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> flag. The
+<constant>VIDIOC_QUERYCTRL</constant> ioctl will return the first
+control with a higher ID than the specified one. When no such controls
+are found an error is returned.</para>
+
+      <para>If you want to get all controls within a specific control
+class, then you can set the initial
+<structfield>qctrl.id</structfield> value to the control class and add
+an extra check to break out of the loop when a control of another
+control class is found:</para>
+
+      <informalexample>
+       <programlisting>
+qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
+       if (V4L2_CTRL_ID2CLASS (qctrl.id) != V4L2_CTRL_CLASS_MPEG)
+               break;
+               /* ... */
+               qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+       }
+</programlisting>
+      </informalexample>
+
+      <para>The 32-bit <structfield>qctrl.id</structfield> value is
+subdivided into three bit ranges: the top 4 bits are reserved for
+flags (&eg; <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>) and are not
+actually part of the ID. The remaining 28 bits form the control ID, of
+which the most significant 12 bits define the control class and the
+least significant 16 bits identify the control within the control
+class. It is guaranteed that these last 16 bits are always non-zero
+for controls. The range of 0x1000 and up are reserved for
+driver-specific controls. The macro
+<constant>V4L2_CTRL_ID2CLASS(id)</constant> returns the control class
+ID based on a control ID.</para>
+
+      <para>If the driver does not support extended controls, then
+<constant>VIDIOC_QUERYCTRL</constant> will fail when used in
+combination with <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>. In
+that case the old method of enumerating control should be used (see
+1.8). But if it is supported, then it is guaranteed to enumerate over
+all controls, including driver-private controls.</para>
+    </section>
+
+    <section>
+      <title>Creating Control Panels</title>
+
+      <para>It is possible to create control panels for a graphical
+user interface where the user can select the various controls.
+Basically you will have to iterate over all controls using the method
+described above. Each control class starts with a control of type
+<constant>V4L2_CTRL_TYPE_CTRL_CLASS</constant>.
+<constant>VIDIOC_QUERYCTRL</constant> will return the name of this
+control class which can be used as the title of a tab page within a
+control panel.</para>
+
+      <para>The flags field of &v4l2-queryctrl; also contains hints on
+the behavior of the control. See the &VIDIOC-QUERYCTRL; documentation
+for more details.</para>
+    </section>
+
+    <section id="mpeg-controls">
+      <title>MPEG Control Reference</title>
+
+      <para>Below all controls within the MPEG control class are
+described. First the generic controls, then controls specific for
+certain hardware.</para>
+
+      <section>
+       <title>Generic MPEG Controls</title>
+
+       <table pgwide="1" frame="none" id="mpeg-control-id">
+         <title>MPEG Control IDs</title>
+         <tgroup cols="4">
+           <colspec colname="c1" colwidth="1*" />
+           <colspec colname="c2" colwidth="6*" />
+           <colspec colname="c3" colwidth="2*" />
+           <colspec colname="c4" colwidth="6*" />
+           <spanspec namest="c1" nameend="c2" spanname="id" />
+           <spanspec namest="c2" nameend="c4" spanname="descr" />
+           <thead>
+             <row>
+               <entry spanname="id" align="left">ID</entry>
+               <entry align="left">Type</entry>
+             </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CLASS</constant>&nbsp;</entry>
+               <entry>class</entry>
+             </row><row><entry spanname="descr">The MPEG class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class. This description can be used as the
+caption of a Tab page in a GUI, for example.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-stream-type">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_TYPE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_stream_type</entry>
+             </row><row><entry spanname="descr">The MPEG-1, -2 or -4
+output stream type. One cannot assume anything here. Each hardware
+MPEG encoder tends to support different subsets of the available MPEG
+stream types. This control is specific to multiplexed MPEG streams.
+The currently defined stream types are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_PS</constant>&nbsp;</entry>
+                     <entry>MPEG-2 program stream</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_TS</constant>&nbsp;</entry>
+                     <entry>MPEG-2 transport stream</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG1_SS</constant>&nbsp;</entry>
+                     <entry>MPEG-1 system stream</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_DVD</constant>&nbsp;</entry>
+                     <entry>MPEG-2 DVD-compatible stream</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG1_VCD</constant>&nbsp;</entry>
+                     <entry>MPEG-1 VCD-compatible stream</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD</constant>&nbsp;</entry>
+                     <entry>MPEG-2 SVCD-compatible stream</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_PMT</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Program Map Table
+Packet ID for the MPEG transport stream (default 16)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_AUDIO</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Audio Packet ID for
+the MPEG transport stream (default 256)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_VIDEO</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Video Packet ID for
+the MPEG transport stream (default 260)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_PCR</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Packet ID for the
+MPEG transport stream carrying PCR fields (default 259)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PES_ID_AUDIO</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Audio ID for MPEG
+PES</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PES_ID_VIDEO</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Video ID for MPEG
+PES</entry>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-stream-vbi-fmt">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_VBI_FMT</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_stream_vbi_fmt</entry>
+             </row><row><entry spanname="descr">Some cards can embed
+VBI data (&eg; Closed Caption, Teletext) into the MPEG stream. This
+control selects whether VBI data should be embedded, and if so, what
+embedding method should be used. The list of possible VBI formats
+depends on the driver. The currently defined VBI format types
+are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_STREAM_VBI_FMT_NONE</constant>&nbsp;</entry>
+                     <entry>No VBI in the MPEG stream</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant>&nbsp;</entry>
+                     <entry>VBI in private packets, IVTV format (documented
+in the kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.vbi</filename>)</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-sampling-freq">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_sampling_freq</entry>
+             </row><row><entry spanname="descr">MPEG Audio sampling
+frequency. Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100</constant>&nbsp;</entry>
+                     <entry>44.1 kHz</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000</constant>&nbsp;</entry>
+                     <entry>48 kHz</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000</constant>&nbsp;</entry>
+                     <entry>32 kHz</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-encoding">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_ENCODING</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_encoding</entry>
+             </row><row><entry spanname="descr">MPEG Audio encoding.
+This control is specific to multiplexed MPEG streams.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_1</constant>&nbsp;</entry>
+                     <entry>MPEG-1/2 Layer I encoding</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_2</constant>&nbsp;</entry>
+                     <entry>MPEG-1/2 Layer II encoding</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_3</constant>&nbsp;</entry>
+                     <entry>MPEG-1/2 Layer III encoding</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_AAC</constant>&nbsp;</entry>
+                     <entry>MPEG-2/4 AAC (Advanced Audio Coding)</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_AC3</constant>&nbsp;</entry>
+                     <entry>AC-3 aka ATSC A/52 encoding</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-l1-bitrate">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L1_BITRATE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_l1_bitrate</entry>
+             </row><row><entry spanname="descr">MPEG-1/2 Layer I bitrate.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_32K</constant>&nbsp;</entry>
+                     <entry>32 kbit/s</entry></row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_64K</constant>&nbsp;</entry>
+                     <entry>64 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_96K</constant>&nbsp;</entry>
+                     <entry>96 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_128K</constant>&nbsp;</entry>
+                     <entry>128 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_160K</constant>&nbsp;</entry>
+                     <entry>160 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_192K</constant>&nbsp;</entry>
+                     <entry>192 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_224K</constant>&nbsp;</entry>
+                     <entry>224 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_256K</constant>&nbsp;</entry>
+                     <entry>256 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_288K</constant>&nbsp;</entry>
+                     <entry>288 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_320K</constant>&nbsp;</entry>
+                     <entry>320 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_352K</constant>&nbsp;</entry>
+                     <entry>352 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_384K</constant>&nbsp;</entry>
+                     <entry>384 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_416K</constant>&nbsp;</entry>
+                     <entry>416 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_448K</constant>&nbsp;</entry>
+                     <entry>448 kbit/s</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-l2-bitrate">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L2_BITRATE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_l2_bitrate</entry>
+             </row><row><entry spanname="descr">MPEG-1/2 Layer II bitrate.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_32K</constant>&nbsp;</entry>
+                     <entry>32 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_48K</constant>&nbsp;</entry>
+                     <entry>48 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_56K</constant>&nbsp;</entry>
+                     <entry>56 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_64K</constant>&nbsp;</entry>
+                     <entry>64 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_80K</constant>&nbsp;</entry>
+                     <entry>80 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_96K</constant>&nbsp;</entry>
+                     <entry>96 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_112K</constant>&nbsp;</entry>
+                     <entry>112 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_128K</constant>&nbsp;</entry>
+                     <entry>128 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_160K</constant>&nbsp;</entry>
+                     <entry>160 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_192K</constant>&nbsp;</entry>
+                     <entry>192 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_224K</constant>&nbsp;</entry>
+                     <entry>224 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_256K</constant>&nbsp;</entry>
+                     <entry>256 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_320K</constant>&nbsp;</entry>
+                     <entry>320 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_384K</constant>&nbsp;</entry>
+                     <entry>384 kbit/s</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-l3-bitrate">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L3_BITRATE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_l3_bitrate</entry>
+             </row><row><entry spanname="descr">MPEG-1/2 Layer III bitrate.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_32K</constant>&nbsp;</entry>
+                     <entry>32 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_40K</constant>&nbsp;</entry>
+                     <entry>40 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_48K</constant>&nbsp;</entry>
+                     <entry>48 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_56K</constant>&nbsp;</entry>
+                     <entry>56 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_64K</constant>&nbsp;</entry>
+                     <entry>64 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_80K</constant>&nbsp;</entry>
+                     <entry>80 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_96K</constant>&nbsp;</entry>
+                     <entry>96 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_112K</constant>&nbsp;</entry>
+                     <entry>112 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_128K</constant>&nbsp;</entry>
+                     <entry>128 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_160K</constant>&nbsp;</entry>
+                     <entry>160 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_192K</constant>&nbsp;</entry>
+                     <entry>192 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_224K</constant>&nbsp;</entry>
+                     <entry>224 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_256K</constant>&nbsp;</entry>
+                     <entry>256 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_320K</constant>&nbsp;</entry>
+                     <entry>320 kbit/s</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_AAC_BITRATE</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">AAC bitrate in bits per second.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-ac3-bitrate">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_AC3_BITRATE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_ac3_bitrate</entry>
+             </row><row><entry spanname="descr">AC-3 bitrate.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_32K</constant>&nbsp;</entry>
+                     <entry>32 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_40K</constant>&nbsp;</entry>
+                     <entry>40 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_48K</constant>&nbsp;</entry>
+                     <entry>48 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_56K</constant>&nbsp;</entry>
+                     <entry>56 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_64K</constant>&nbsp;</entry>
+                     <entry>64 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_80K</constant>&nbsp;</entry>
+                     <entry>80 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_96K</constant>&nbsp;</entry>
+                     <entry>96 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_112K</constant>&nbsp;</entry>
+                     <entry>112 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_128K</constant>&nbsp;</entry>
+                     <entry>128 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_160K</constant>&nbsp;</entry>
+                     <entry>160 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_192K</constant>&nbsp;</entry>
+                     <entry>192 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_224K</constant>&nbsp;</entry>
+                     <entry>224 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_256K</constant>&nbsp;</entry>
+                     <entry>256 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_320K</constant>&nbsp;</entry>
+                     <entry>320 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_384K</constant>&nbsp;</entry>
+                     <entry>384 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_448K</constant>&nbsp;</entry>
+                     <entry>448 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_512K</constant>&nbsp;</entry>
+                     <entry>512 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_576K</constant>&nbsp;</entry>
+                     <entry>576 kbit/s</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_640K</constant>&nbsp;</entry>
+                     <entry>640 kbit/s</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-mode">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_mode</entry>
+             </row><row><entry spanname="descr">MPEG Audio mode.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_MODE_STEREO</constant>&nbsp;</entry>
+                     <entry>Stereo</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_MODE_JOINT_STEREO</constant>&nbsp;</entry>
+                     <entry>Joint Stereo</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_MODE_DUAL</constant>&nbsp;</entry>
+                     <entry>Bilingual</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_MODE_MONO</constant>&nbsp;</entry>
+                     <entry>Mono</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-mode-extension">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MODE_EXTENSION</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_mode_extension</entry>
+             </row><row><entry spanname="descr">Joint Stereo
+audio mode extension. In Layer I and II they indicate which subbands
+are in intensity stereo. All other subbands are coded in stereo. Layer
+III is not (yet) supported. Possible values
+are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4</constant>&nbsp;</entry>
+                     <entry>Subbands 4-31 in intensity stereo</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8</constant>&nbsp;</entry>
+                     <entry>Subbands 8-31 in intensity stereo</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12</constant>&nbsp;</entry>
+                     <entry>Subbands 12-31 in intensity stereo</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16</constant>&nbsp;</entry>
+                     <entry>Subbands 16-31 in intensity stereo</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-emphasis">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_EMPHASIS</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_emphasis</entry>
+             </row><row><entry spanname="descr">Audio Emphasis.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_NONE</constant>&nbsp;</entry>
+                     <entry>None</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS</constant>&nbsp;</entry>
+                     <entry>50/15 microsecond emphasis</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17</constant>&nbsp;</entry>
+                     <entry>CCITT J.17</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-audio-crc">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_CRC</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_audio_crc</entry>
+             </row><row><entry spanname="descr">CRC method. Possible
+values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_CRC_NONE</constant>&nbsp;</entry>
+                     <entry>None</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_AUDIO_CRC_CRC16</constant>&nbsp;</entry>
+                     <entry>16 bit parity check</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MUTE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Mutes the audio when
+capturing. This is not done by muting audio hardware, which can still
+produce a slight hiss, but in the encoder itself, guaranteeing a fixed
+and reproducible audio bitstream. 0 = unmuted, 1 = muted.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-video-encoding">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ENCODING</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_video_encoding</entry>
+             </row><row><entry spanname="descr">MPEG Video encoding
+method. This control is specific to multiplexed MPEG streams.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_1</constant>&nbsp;</entry>
+                     <entry>MPEG-1 Video encoding</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_2</constant>&nbsp;</entry>
+                     <entry>MPEG-2 Video encoding</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC</constant>&nbsp;</entry>
+                     <entry>MPEG-4 AVC (H.264) Video encoding</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-video-aspect">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ASPECT</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_video_aspect</entry>
+             </row><row><entry spanname="descr">Video aspect.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_1x1</constant>&nbsp;</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_4x3</constant>&nbsp;</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_16x9</constant>&nbsp;</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_221x100</constant>&nbsp;</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_B_FRAMES</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Number of B-Frames
+(default 2)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_GOP_SIZE</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">GOP size (default
+12)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_GOP_CLOSURE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">GOP closure (default
+1)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_PULLDOWN</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Enable 3:2 pulldown
+(default 0)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-video-bitrate-mode">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_video_bitrate_mode</entry>
+             </row><row><entry spanname="descr">Video bitrate mode.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_BITRATE_MODE_VBR</constant>&nbsp;</entry>
+                     <entry>Variable bitrate</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_BITRATE_MODE_CBR</constant>&nbsp;</entry>
+                     <entry>Constant bitrate</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Video bitrate in bits
+per second.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE_PEAK</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Peak video bitrate in
+bits per second. Must be larger or equal to the average video bitrate.
+It is ignored if the video bitrate mode is set to constant
+bitrate.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">For every captured
+frame, skip this many subsequent frames (default 0).</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MUTE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">"Mutes" the video to a
+fixed color when capturing. This is useful for testing, to produce a
+fixed video bitstream. 0 = unmuted, 1 = muted.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MUTE_YUV</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Sets the "mute" color
+of the video. The supplied 32-bit integer is interpreted as follows (bit
+0 = least significant bit):</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry>Bit 0:7</entry>
+                     <entry>V chrominance information</entry>
+                   </row>
+                   <row>
+                     <entry>Bit 8:15</entry>
+                     <entry>U chrominance information</entry>
+                   </row>
+                   <row>
+                     <entry>Bit 16:23</entry>
+                     <entry>Y luminance information</entry>
+                   </row>
+                   <row>
+                     <entry>Bit 24:31</entry>
+                     <entry>Must be zero.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">If enabled the decoder expects to receive a single slice per buffer, otherwise
+the decoder expects a single frame in per buffer. Applicable to the decoder, all codecs.
+</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">Enable writing sample aspect ratio in the Video Usability Information.
+Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_video_h264_vui_sar_idc</entry>
+             </row>
+             <row><entry spanname="descr">VUI sample aspect ratio indicator for H.264 encoding. The value
+is defined in the table E-1 in the standard. Applicable to the H264 encoder.</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED</constant>&nbsp;</entry>
+                         <entry>Unspecified</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1</constant>&nbsp;</entry>
+                         <entry>1x1</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11</constant>&nbsp;</entry>
+                         <entry>12x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11</constant>&nbsp;</entry>
+                         <entry>10x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11</constant>&nbsp;</entry>
+                         <entry>16x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33</constant>&nbsp;</entry>
+                         <entry>40x33</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11</constant>&nbsp;</entry>
+                         <entry>24x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11</constant>&nbsp;</entry>
+                         <entry>20x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11</constant>&nbsp;</entry>
+                         <entry>32x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33</constant>&nbsp;</entry>
+                         <entry>80x33</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11</constant>&nbsp;</entry>
+                         <entry>18x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11</constant>&nbsp;</entry>
+                         <entry>15x11</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33</constant>&nbsp;</entry>
+                         <entry>64x33</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99</constant>&nbsp;</entry>
+                         <entry>160x99</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3</constant>&nbsp;</entry>
+                         <entry>4x3</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2</constant>&nbsp;</entry>
+                         <entry>3x2</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1</constant>&nbsp;</entry>
+                         <entry>2x1</entry>
+                       </row>
+                       <row>
+                         <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED</constant>&nbsp;</entry>
+                         <entry>Extended SAR</entry>
+                       </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Extended sample aspect ratio width for H.264 VUI encoding.
+Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Extended sample aspect ratio height for H.264 VUI encoding.
+Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LEVEL</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_video_h264_level</entry>
+             </row>
+             <row><entry spanname="descr">The level information for the H264 video elementary stream.
+Applicable to the H264 encoder.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_0</constant>&nbsp;</entry>
+                     <entry>Level 1.0</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1B</constant>&nbsp;</entry>
+                     <entry>Level 1B</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_1</constant>&nbsp;</entry>
+                     <entry>Level 1.1</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_2</constant>&nbsp;</entry>
+                     <entry>Level 1.2</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_3</constant>&nbsp;</entry>
+                     <entry>Level 1.3</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_0</constant>&nbsp;</entry>
+                     <entry>Level 2.0</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_1</constant>&nbsp;</entry>
+                     <entry>Level 2.1</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_2</constant>&nbsp;</entry>
+                     <entry>Level 2.2</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_0</constant>&nbsp;</entry>
+                     <entry>Level 3.0</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_1</constant>&nbsp;</entry>
+                     <entry>Level 3.1</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_2</constant>&nbsp;</entry>
+                     <entry>Level 3.2</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_0</constant>&nbsp;</entry>
+                     <entry>Level 4.0</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_1</constant>&nbsp;</entry>
+                     <entry>Level 4.1</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_2</constant>&nbsp;</entry>
+                     <entry>Level 4.2</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_5_0</constant>&nbsp;</entry>
+                     <entry>Level 5.0</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_5_1</constant>&nbsp;</entry>
+                     <entry>Level 5.1</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_video_mpeg4_level</entry>
+             </row>
+             <row><entry spanname="descr">The level information for the MPEG4 elementary stream.
+Applicable to the MPEG4 encoder.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_0</constant>&nbsp;</entry>
+                     <entry>Level 0</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_0B</constant>&nbsp;</entry>
+                     <entry>Level 0b</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_1</constant>&nbsp;</entry>
+                     <entry>Level 1</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_2</constant>&nbsp;</entry>
+                     <entry>Level 2</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_3</constant>&nbsp;</entry>
+                     <entry>Level 3</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_3B</constant>&nbsp;</entry>
+                     <entry>Level 3b</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_4</constant>&nbsp;</entry>
+                     <entry>Level 4</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_LEVEL_5</constant>&nbsp;</entry>
+                     <entry>Level 5</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_PROFILE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_h264_profile</entry>
+             </row>
+             <row><entry spanname="descr">The profile information for H264.
+Applicable to the H264 encoder.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE</constant>&nbsp;</entry>
+                     <entry>Baseline profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE</constant>&nbsp;</entry>
+                     <entry>Constrained Baseline profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_MAIN</constant>&nbsp;</entry>
+                     <entry>Main profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED</constant>&nbsp;</entry>
+                     <entry>Extended profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH</constant>&nbsp;</entry>
+                     <entry>High profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10</constant>&nbsp;</entry>
+                     <entry>High 10 profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422</constant>&nbsp;</entry>
+                     <entry>High 422 profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE</constant>&nbsp;</entry>
+                     <entry>High 444 Predictive profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA</constant>&nbsp;</entry>
+                     <entry>High 10 Intra profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA</constant>&nbsp;</entry>
+                     <entry>High 422 Intra profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA</constant>&nbsp;</entry>
+                     <entry>High 444 Intra profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA</constant>&nbsp;</entry>
+                     <entry>CAVLC 444 Intra profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE</constant>&nbsp;</entry>
+                     <entry>Scalable Baseline profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH</constant>&nbsp;</entry>
+                     <entry>Scalable High profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA</constant>&nbsp;</entry>
+                     <entry>Scalable High Intra profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH</constant>&nbsp;</entry>
+                     <entry>Stereo High profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH</constant>&nbsp;</entry>
+                     <entry>Multiview High profile</entry>
+                   </row>
+
+                 </tbody>
+               </entrytbl>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_mpeg4_profile</entry>
+             </row>
+             <row><entry spanname="descr">The profile information for MPEG4.
+Applicable to the MPEG4 encoder.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_SIMPLE</constant>&nbsp;</entry>
+                     <entry>Simple profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_ADVANCED_SIMPLE</constant>&nbsp;</entry>
+                     <entry>Advanced Simple profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_CORE</constant>&nbsp;</entry>
+                     <entry>Core profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_SIMPLE_SCALABLE</constant>&nbsp;</entry>
+                     <entry>Simple Scalable profile</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_PROFILE_ADVANCED_CODING_EFFICIENCY</constant>&nbsp;</entry>
+                     <entry></entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MAX_REF_PIC</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">The maximum number of reference pictures used for encoding.
+Applicable to the encoder.
+</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_multi_slice_mode</entry>
+             </row>
+             <row><entry spanname="descr">Determines how the encoder should handle division of frame into slices.
+Applicable to the encoder.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE</constant>&nbsp;</entry>
+                     <entry>Single slice per frame.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB</constant>&nbsp;</entry>
+                     <entry>Multiple slices with set maximum number of macroblocks per slice.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES</constant>&nbsp;</entry>
+                     <entry>Multiple slice with set maximum size in bytes per slice.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">The maximum number of macroblocks in a slice. Used when
+<constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant> is set to <constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB</constant>.
+Applicable to the encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">The maximum size of a slice in bytes. Used when
+<constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant> is set to <constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES</constant>.
+Applicable to the encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_h264_loop_filter_mode</entry>
+             </row>
+             <row><entry spanname="descr">Loop filter mode for H264 encoder.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED</constant>&nbsp;</entry>
+                     <entry>Loop filter is enabled.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED</constant>&nbsp;</entry>
+                     <entry>Loop filter is disabled.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY</constant>&nbsp;</entry>
+                     <entry>Loop filter is disabled at the slice boundary.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Loop filter alpha coefficient, defined in the H264 standard.
+Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Loop filter beta coefficient, defined in the H264 standard.
+Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_h264_symbol_mode</entry>
+             </row>
+             <row><entry spanname="descr">Entropy coding mode for H264 - CABAC/CAVALC.
+Applicable to the H264 encoder.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC</constant>&nbsp;</entry>
+                     <entry>Use CAVLC entropy coding.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC</constant>&nbsp;</entry>
+                     <entry>Use CABAC entropy coding.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">Enable 8X8 transform for H264. Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Cyclic intra macroblock refresh. This is the number of continuous macroblocks
+refreshed every frame. Each frame a succesive set of macroblocks is refreshed until the cycle completes and starts from the
+top of the frame. Applicable to H264, H263 and MPEG4 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">Frame level rate control enable.
+If this control is disabled then the quantization parameter for each frame type is constant and set with appropriate controls
+(e.g. <constant>V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP</constant>).
+If frame rate control is enabled then quantization parameter is adjusted to meet the chosen bitrate. Minimum and maximum value
+for the quantization parameter can be set with appropriate controls (e.g. <constant>V4L2_CID_MPEG_VIDEO_H263_MIN_QP</constant>).
+Applicable to encoders.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">Macroblock level rate control enable.
+Applicable to the MPEG4 and H264 encoders.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_QPEL</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">Quarter pixel motion estimation for MPEG4. Applicable to the MPEG4 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an I frame for H263. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_MIN_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Minimum quantization parameter for H263. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_MAX_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Maximum quantization parameter for H263. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an P frame for H263. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an B frame for H263. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an I frame for H264. Valid range: from 0 to 51.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_MIN_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Minimum quantization parameter for H264. Valid range: from 0 to 51.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_MAX_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Maximum quantization parameter for H264. Valid range: from 0 to 51.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an P frame for H264. Valid range: from 0 to 51.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an B frame for H264. Valid range: from 0 to 51.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an I frame for MPEG4. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Minimum quantization parameter for MPEG4. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Maximum quantization parameter for MPEG4. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an P frame for MPEG4. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an B frame for MPEG4. Valid range: from 1 to 31.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VBV_SIZE</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">The Video Buffer Verifier size in kilobytes, it is used as a limitation of frame skip.
+The VBV is defined in the standard as a mean to verify that the produced stream will be succesfully decoded.
+The standard describes it as "Part of a hypothetical decoder that is conceptually connected to the
+output of the encoder. Its purpose is to provide a constraint on the variability of the data rate that an
+encoder or editing process may produce.".
+Applicable to the MPEG1, MPEG2, MPEG4 encoders.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">The Coded Picture Buffer size in kilobytes, it is used as a limitation of frame skip.
+The CPB is defined in the H264 standard as a mean to verify that the produced stream will be succesfully decoded.
+Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_I_PERIOD</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Period between I-frames in the open GOP for H264. In case of an open GOP
+this is the period between two I-frames. The period between IDR (Instantaneous Decoding Refresh) frames is taken from the GOP_SIZE control.
+An IDR frame, which stands for Instantaneous Decoding Refresh is an I-frame after which no prior frames are
+referenced. This means that a stream can be restarted from an IDR frame without the need to store or decode any
+previous frames. Applicable to the H264 encoder.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_HEADER_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_header_mode</entry>
+             </row>
+             <row><entry spanname="descr">Determines whether the header is returned as the first buffer or is
+it returned together with the first frame. Applicable to encoders.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE</constant>&nbsp;</entry>
+                     <entry>The stream header is returned separately in the first buffer.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME</constant>&nbsp;</entry>
+                     <entry>The stream header is returned together with the first encoded frame.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Enabled the deblocking post processing filter for MPEG4 decoder.
+Applicable to the MPEG4 decoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_RES</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">vop_time_increment_resolution value for MPEG4. Applicable to the MPEG4 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_INC</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">vop_time_increment value for MPEG4. Applicable to the MPEG4 encoder.</entry>
+             </row>
+
+           </tbody>
+         </tgroup>
+       </table>
+      </section>
+
+      <section>
+       <title>MFC 5.1 MPEG Controls</title>
+
+       <para>The following MPEG class controls deal with MPEG
+decoding and encoding settings that are specific to the Multi Format Codec 5.1 device present
+in the S5P family of SoCs by Samsung.
+</para>
+
+       <table pgwide="1" frame="none" id="mfc51-control-id">
+         <title>MFC 5.1 Control IDs</title>
+         <tgroup cols="4">
+           <colspec colname="c1" colwidth="1*" />
+           <colspec colname="c2" colwidth="6*" />
+           <colspec colname="c3" colwidth="2*" />
+           <colspec colname="c4" colwidth="6*" />
+           <spanspec namest="c1" nameend="c2" spanname="id" />
+           <spanspec namest="c2" nameend="c4" spanname="descr" />
+           <thead>
+             <row>
+               <entry spanname="id" align="left">ID</entry>
+               <entry align="left">Type</entry>
+             </row><row><entry spanname="descr" align="left">Description</entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">If the display delay is enabled then the decoder has to return a
+CAPTURE buffer after processing a certain number of OUTPUT buffers. If this number is low, then it may result in
+buffers not being dequeued in display order. In addition hardware may still use those buffers as reference, thus
+application should not write to those buffers. This feature can be used for example for generating thumbnails of videos.
+Applicable to the H264 decoder.
+             </entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Display delay value for H264 decoder.
+The decoder is forced to return a decoded frame after the set 'display delay' number of frames. If this number is
+low it may result in frames returned out of dispaly order, in addition the hardware may still be using the returned buffer
+as a reference picture for subsequent frames.
+</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">The number of reference pictures used for encoding a P picture.
+Applicable to the H264 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_PADDING</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Padding enable in the encoder - use a color instead of repeating border pixels.
+Applicable to encoders.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Padding color in the encoder. Applicable to encoders. The supplied 32-bit integer is interpreted as follows (bit
+0 = least significant bit):</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry>Bit 0:7</entry>
+                     <entry>V chrominance information</entry>
+                   </row>
+                   <row>
+                     <entry>Bit 8:15</entry>
+                     <entry>U chrominance information</entry>
+                   </row>
+                   <row>
+                     <entry>Bit 16:23</entry>
+                     <entry>Y luminance information</entry>
+                   </row>
+                   <row>
+                     <entry>Bit 24:31</entry>
+                     <entry>Must be zero.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Reaction coefficient for MFC rate control. Applicable to encoders.
+<para>Note 1: Valid only when the frame level RC is enabled.</para>
+<para>Note 2: For tight CBR, this field must be small (ex. 2 ~ 10).
+For VBR, this field must be large (ex. 100 ~ 1000).</para>
+<para>Note 3: It is not recommended to use the greater number than FRAME_RATE * (10^9 / BIT_RATE).</para>
+</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Adaptive rate control for dark region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Adaptive rate control for smooth region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Adaptive rate control for static region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row><row><entry spanname="descr">Adaptive rate control for activity region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_mfc51_frame_skip_mode</entry>
+             </row>
+             <row><entry spanname="descr">
+Indicates in what conditions the encoder should skip frames. If encoding a frame would cause the encoded stream to be larger then
+a chosen data limit then the frame will be skipped.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_DISABLED</constant>&nbsp;</entry>
+                     <entry>Frame skip mode is disabled.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_LEVEL_LIMIT</constant>&nbsp;</entry>
+                     <entry>Frame skip mode enabled and buffer limit is set by the chosen level and is defined by the standard.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_BUF_LIMIT</constant>&nbsp;</entry>
+                     <entry>Frame skip mode enabled and buffer limit is set by the VBV (MPEG1/2/4) or CPB (H264) buffer size control.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row><row><entry spanname="descr">Enable rate-control with fixed target bit.
+If this setting is enabled, then the rate control logic of the encoder will calculate the average bitrate
+for a GOP and keep it below or equal the set bitrate target. Otherwise the rate control logic calculates the
+overall average bitrate for the stream and keeps it below or equal to the set bitrate. In the first case
+the average bitrate for the whole stream will be smaller then the set bitrate. This is caused because the
+average is calculated for smaller number of frames, on the other hand enabling this setting will ensure that
+the stream will meet tight bandwidth contraints. Applicable to encoders.
+</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_mfc51_force_frame_type</entry>
+             </row>
+             <row><entry spanname="descr">Force a frame type for the next queued buffer. Applicable to encoders.
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_DISABLED</constant>&nbsp;</entry>
+                     <entry>Forcing a specific frame type disabled.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_I_FRAME</constant>&nbsp;</entry>
+                     <entry>Force an I-frame.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_NOT_CODED</constant>&nbsp;</entry>
+                     <entry>Force a non-coded frame.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+           </tbody>
+         </tgroup>
+       </table>
+      </section>
+
+      <section>
+       <title>CX2341x MPEG Controls</title>
+
+       <para>The following MPEG class controls deal with MPEG
+encoding settings that are specific to the Conexant CX23415 and
+CX23416 MPEG encoding chips.</para>
+
+       <table pgwide="1" frame="none" id="cx2341x-control-id">
+         <title>CX2341x Control IDs</title>
+         <tgroup cols="4">
+           <colspec colname="c1" colwidth="1*" />
+           <colspec colname="c2" colwidth="6*" />
+           <colspec colname="c3" colwidth="2*" />
+           <colspec colname="c4" colwidth="6*" />
+           <spanspec namest="c1" nameend="c2" spanname="id" />
+           <spanspec namest="c2" nameend="c4" spanname="descr" />
+           <thead>
+             <row>
+               <entry spanname="id" align="left">ID</entry>
+               <entry align="left">Type</entry>
+             </row><row><entry spanname="descr" align="left">Description</entry>
+             </row>
+           </thead>
+           <tbody valign="top">
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-cx2341x-video-spatial-filter-mode">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_spatial_filter_mode</entry>
+             </row><row><entry spanname="descr">Sets the Spatial
+Filter mode (default <constant>MANUAL</constant>). Possible values
+are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
+                     <entry>Choose the filter manually</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
+                     <entry>Choose the filter automatically</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-15)</entry>
+             </row><row><entry spanname="descr">The setting for the
+Spatial Filter. 0 = off, 15 = maximum. (Default is 0.)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row id="luma-spatial-filter-type">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</entry>
+             </row><row><entry spanname="descr">Select the algorithm
+to use for the Luma Spatial Filter (default
+<constant>1D_HOR</constant>). Possible values:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
+                     <entry>No filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
+                     <entry>One-dimensional horizontal</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT</constant>&nbsp;</entry>
+                     <entry>One-dimensional vertical</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE</constant>&nbsp;</entry>
+                     <entry>Two-dimensional separable</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE</constant>&nbsp;</entry>
+                     <entry>Two-dimensional symmetrical
+non-separable</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="chroma-spatial-filter-type">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</entry>
+             </row><row><entry spanname="descr">Select the algorithm
+for the Chroma Spatial Filter (default <constant>1D_HOR</constant>).
+Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
+                     <entry>No filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
+                     <entry>One-dimensional horizontal</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-cx2341x-video-temporal-filter-mode">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_temporal_filter_mode</entry>
+             </row><row><entry spanname="descr">Sets the Temporal
+Filter mode (default <constant>MANUAL</constant>). Possible values
+are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
+                     <entry>Choose the filter manually</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
+                     <entry>Choose the filter automatically</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-31)</entry>
+             </row><row><entry spanname="descr">The setting for the
+Temporal Filter. 0 = off, 31 = maximum. (Default is 8 for full-scale
+capturing and 0 for scaled capturing.)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row id="v4l2-mpeg-cx2341x-video-median-filter-type">
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE</constant>&nbsp;</entry>
+               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_median_filter_type</entry>
+             </row><row><entry spanname="descr">Median Filter Type
+(default <constant>OFF</constant>). Possible values are:</entry>
+             </row>
+             <row>
+               <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF</constant>&nbsp;</entry>
+                     <entry>No filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR</constant>&nbsp;</entry>
+                     <entry>Horizontal filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT</constant>&nbsp;</entry>
+                     <entry>Vertical filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT</constant>&nbsp;</entry>
+                     <entry>Horizontal and vertical filter</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG</constant>&nbsp;</entry>
+                     <entry>Diagonal filter</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-255)</entry>
+             </row><row><entry spanname="descr">Threshold above which
+the luminance median filter is enabled (default 0)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-255)</entry>
+             </row><row><entry spanname="descr">Threshold below which
+the luminance median filter is enabled (default 255)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-255)</entry>
+             </row><row><entry spanname="descr">Threshold above which
+the chroma median filter is enabled (default 0)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
+               <entry>integer&nbsp;(0-255)</entry>
+             </row><row><entry spanname="descr">Threshold below which
+the chroma median filter is enabled (default 255)</entry>
+             </row>
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS</constant>&nbsp;</entry>
+               <entry>boolean</entry>
+             </row>
+             <row><entry spanname="descr">The CX2341X MPEG encoder
+can insert one empty MPEG-2 PES packet into the stream between every
+four video frames. The packet size is 2048 bytes, including the
+packet_start_code_prefix and stream_id fields. The stream_id is 0xBF
+(private stream 2). The payload consists of 0x00 bytes, to be filled
+in by the application. 0 = do not insert, 1 = insert packets.</entry>
+             </row>
+           </tbody>
+         </tgroup>
+       </table>
+      </section>
+    </section>
+
+    <section id="camera-controls">
+      <title>Camera Control Reference</title>
+
+      <para>The Camera class includes controls for mechanical (or
+equivalent digital) features of a device such as controllable lenses
+or sensors.</para>
+
+    <table pgwide="1" frame="none" id="camera-control-id">
+      <title>Camera Control IDs</title>
+      <tgroup cols="4">
+       <colspec colname="c1" colwidth="1*" />
+       <colspec colname="c2" colwidth="6*" />
+       <colspec colname="c3" colwidth="2*" />
+       <colspec colname="c4" colwidth="6*" />
+       <spanspec namest="c1" nameend="c2" spanname="id" />
+       <spanspec namest="c2" nameend="c4" spanname="descr" />
+       <thead>
+         <row>
+           <entry spanname="id" align="left">ID</entry>
+           <entry align="left">Type</entry>
+         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row><entry></entry></row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_CAMERA_CLASS</constant>&nbsp;</entry>
+           <entry>class</entry>
+         </row><row><entry spanname="descr">The Camera class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row id="v4l2-exposure-auto-type">
+           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_AUTO</constant>&nbsp;</entry>
+           <entry>enum&nbsp;v4l2_exposure_auto_type</entry>
+         </row><row><entry spanname="descr">Enables automatic
+adjustments of the exposure time and/or iris aperture. The effect of
+manual changes of the exposure time or iris aperture while these
+features are enabled is undefined, drivers should ignore such
+requests. Possible values are:</entry>
+         </row>
+         <row>
+           <entrytbl spanname="descr" cols="2">
+             <tbody valign="top">
+               <row>
+                 <entry><constant>V4L2_EXPOSURE_AUTO</constant>&nbsp;</entry>
+                     <entry>Automatic exposure time, automatic iris
+aperture.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_EXPOSURE_MANUAL</constant>&nbsp;</entry>
+                 <entry>Manual exposure time, manual iris.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_EXPOSURE_SHUTTER_PRIORITY</constant>&nbsp;</entry>
+                 <entry>Manual exposure time, auto iris.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_EXPOSURE_APERTURE_PRIORITY</constant>&nbsp;</entry>
+                 <entry>Auto exposure time, manual iris.</entry>
+               </row>
+             </tbody>
+           </entrytbl>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_ABSOLUTE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">Determines the exposure
+time of the camera sensor. The exposure time is limited by the frame
+interval. Drivers should interpret the values as 100 &micro;s units,
+where the value 1 stands for 1/10000th of a second, 10000 for 1 second
+and 100000 for 10 seconds.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_AUTO_PRIORITY</constant>&nbsp;</entry>
+           <entry>boolean</entry>
+         </row><row><entry spanname="descr">When
+<constant>V4L2_CID_EXPOSURE_AUTO</constant> is set to
+<constant>AUTO</constant> or <constant>APERTURE_PRIORITY</constant>,
+this control determines if the device may dynamically vary the frame
+rate. By default this feature is disabled (0) and the frame rate must
+remain constant.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_PAN_RELATIVE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control turns the
+camera horizontally by the specified amount. The unit is undefined. A
+positive value moves the camera to the right (clockwise when viewed
+from above), a negative value to the left. A value of zero does not
+cause motion. This is a write-only control.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TILT_RELATIVE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control turns the
+camera vertically by the specified amount. The unit is undefined. A
+positive value moves the camera up, a negative value down. A value of
+zero does not cause motion. This is a write-only control.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_PAN_RESET</constant>&nbsp;</entry>
+           <entry>button</entry>
+         </row><row><entry spanname="descr">When this control is set,
+the camera moves horizontally to the default position.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TILT_RESET</constant>&nbsp;</entry>
+           <entry>button</entry>
+         </row><row><entry spanname="descr">When this control is set,
+the camera moves vertically to the default position.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_PAN_ABSOLUTE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control
+turns the camera horizontally to the specified position. Positive
+values move the camera to the right (clockwise when viewed from above),
+negative values to the left. Drivers should interpret the values as arc
+seconds, with valid values between -180 * 3600 and +180 * 3600
+inclusive.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TILT_ABSOLUTE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control
+turns the camera vertically to the specified position. Positive values
+move the camera up, negative values down. Drivers should interpret the
+values as arc seconds, with valid values between -180 * 3600 and +180
+* 3600 inclusive.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FOCUS_ABSOLUTE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control sets the
+focal point of the camera to the specified position. The unit is
+undefined. Positive values set the focus closer to the camera,
+negative values towards infinity.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FOCUS_RELATIVE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control moves the
+focal point of the camera by the specified amount. The unit is
+undefined. Positive values move the focus closer to the camera,
+negative values towards infinity. This is a write-only control.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FOCUS_AUTO</constant>&nbsp;</entry>
+           <entry>boolean</entry>
+         </row><row><entry spanname="descr">Enables automatic focus
+adjustments. The effect of manual focus adjustments while this feature
+is enabled is undefined, drivers should ignore such requests.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_ZOOM_ABSOLUTE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">Specify the objective lens
+focal length as an absolute value. The zoom unit is driver-specific and its
+value should be a positive integer.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_ZOOM_RELATIVE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">Specify the objective lens
+focal length relatively to the current value. Positive values move the zoom
+lens group towards the telephoto direction, negative values towards the
+wide-angle direction. The zoom unit is driver-specific. This is a write-only control.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_ZOOM_CONTINUOUS</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">Move the objective lens group
+at the specified speed until it reaches physical device limits or until an
+explicit request to stop the movement. A positive value moves the zoom lens
+group towards the telephoto direction. A value of zero stops the zoom lens
+group movement. A negative value moves the zoom lens group towards the
+wide-angle direction. The zoom speed unit is driver-specific.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_IRIS_ABSOLUTE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control sets the
+camera's aperture to the specified value. The unit is undefined.
+Larger values open the iris wider, smaller values close it.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_IRIS_RELATIVE</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">This control modifies the
+camera's aperture by the specified amount. The unit is undefined.
+Positive values open the iris one step further, negative values close
+it one step further. This is a write-only control.</entry>
+         </row>
+         <row><entry></entry></row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_PRIVACY</constant>&nbsp;</entry>
+           <entry>boolean</entry>
+         </row><row><entry spanname="descr">Prevent video from being acquired
+by the camera. When this control is set to <constant>TRUE</constant> (1), no
+image can be captured by the camera. Common means to enforce privacy are
+mechanical obturation of the sensor and firmware image processing, but the
+device is not restricted to these methods. Devices that implement the privacy
+control must support read access and may support write access.</entry>
+         </row>
+
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_BAND_STOP_FILTER</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row><row><entry spanname="descr">Switch the band-stop filter of a
+camera sensor on or off, or specify its strength. Such band-stop filters can
+be used, for example, to filter out the fluorescent light component.</entry>
+         </row>
+         <row><entry></entry></row>
+       </tbody>
+      </tgroup>
+    </table>
+  </section>
+
+    <section id="fm-tx-controls">
+      <title>FM Transmitter Control Reference</title>
+
+      <para>The FM Transmitter (FM_TX) class includes controls for common features of
+FM transmissions capable devices. Currently this class includes parameters for audio
+compression, pilot tone generation, audio deviation limiter, RDS transmission and
+tuning power features.</para>
+
+      <table pgwide="1" frame="none" id="fm-tx-control-id">
+      <title>FM_TX Control IDs</title>
+
+      <tgroup cols="4">
+       <colspec colname="c1" colwidth="1*" />
+       <colspec colname="c2" colwidth="6*" />
+       <colspec colname="c3" colwidth="2*" />
+       <colspec colname="c4" colwidth="6*" />
+       <spanspec namest="c1" nameend="c2" spanname="id" />
+       <spanspec namest="c2" nameend="c4" spanname="descr" />
+       <thead>
+         <row>
+           <entry spanname="id" align="left">ID</entry>
+           <entry align="left">Type</entry>
+         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row><entry></entry></row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FM_TX_CLASS</constant>&nbsp;</entry>
+           <entry>class</entry>
+         </row><row><entry spanname="descr">The FM_TX class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_RDS_TX_DEVIATION</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Configures RDS signal frequency deviation level in Hz.
+The range and step are driver-specific.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_RDS_TX_PI</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Sets the RDS Programme Identification field
+for transmission.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_RDS_TX_PTY</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Sets the RDS Programme Type field for transmission.
+This encodes up to 31 pre-defined programme types.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_RDS_TX_PS_NAME</constant>&nbsp;</entry>
+           <entry>string</entry>
+         </row>
+         <row><entry spanname="descr">Sets the Programme Service name (PS_NAME) for transmission.
+It is intended for static display on a receiver. It is the primary aid to listeners in programme service
+identification and selection.  In Annex E of <xref linkend="en50067" />, the RDS specification,
+there is a full description of the correct character encoding for Programme Service name strings.
+Also from RDS specification, PS is usually a single eight character text. However, it is also possible
+to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
+with steps of 8 characters. The result is it must always contain a string with size multiple of 8.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_RDS_TX_RADIO_TEXT</constant>&nbsp;</entry>
+           <entry>string</entry>
+         </row>
+         <row><entry spanname="descr">Sets the Radio Text info for transmission. It is a textual description of
+what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
+programme-related information or any other text. In these cases, RadioText should be used in addition to
+<constant>V4L2_CID_RDS_TX_PS_NAME</constant>. The encoding for Radio Text strings is also fully described
+in Annex E of <xref linkend="en50067" />. The length of Radio Text strings depends on which RDS Block is being
+used to transmit it, either 32 (2A block) or 64 (2B block).  However, it is also possible
+to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
+with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_ENABLED</constant>&nbsp;</entry>
+           <entry>boolean</entry>
+         </row>
+         <row><entry spanname="descr">Enables or disables the audio deviation limiter feature.
+The limiter is useful when trying to maximize the audio volume, minimize receiver-generated
+distortion and prevent overmodulation.
+</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_RELEASE_TIME</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Sets the audio deviation limiter feature release time.
+Unit is in useconds. Step and range are driver-specific.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_DEVIATION</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Configures audio frequency deviation level in Hz.
+The range and step are driver-specific.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_ENABLED</constant>&nbsp;</entry>
+           <entry>boolean</entry>
+         </row>
+         <row><entry spanname="descr">Enables or disables the audio compression feature.
+This feature amplifies signals below the threshold by a fixed gain and compresses audio
+signals above the threshold by the ratio of Threshold/(Gain + Threshold).</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_GAIN</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Sets the gain for audio compression feature. It is
+a dB value. The range and step are driver-specific.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_THRESHOLD</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Sets the threshold level for audio compression freature.
+It is a dB value. The range and step are driver-specific.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Sets the attack time for audio compression feature.
+It is a useconds value. The range and step are driver-specific.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Sets the release time for audio compression feature.
+It is a useconds value. The range and step are driver-specific.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_ENABLED</constant>&nbsp;</entry>
+           <entry>boolean</entry>
+         </row>
+         <row><entry spanname="descr">Enables or disables the pilot tone generation feature.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_DEVIATION</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Configures pilot tone frequency deviation level. Unit is
+in Hz. The range and step are driver-specific.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_FREQUENCY</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Configures pilot tone frequency value. Unit is
+in Hz. The range and step are driver-specific.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TUNE_PREEMPHASIS</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row id="v4l2-preemphasis"><entry spanname="descr">Configures the pre-emphasis value for broadcasting.
+A pre-emphasis filter is applied to the broadcast to accentuate the high audio frequencies.
+Depending on the region, a time constant of either 50 or 75 useconds is used. The enum&nbsp;v4l2_preemphasis
+defines possible values for pre-emphasis. Here they are:</entry>
+       </row><row>
+       <entrytbl spanname="descr" cols="2">
+                 <tbody valign="top">
+                   <row>
+                     <entry><constant>V4L2_PREEMPHASIS_DISABLED</constant>&nbsp;</entry>
+                     <entry>No pre-emphasis is applied.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_PREEMPHASIS_50_uS</constant>&nbsp;</entry>
+                     <entry>A pre-emphasis of 50 uS is used.</entry>
+                   </row>
+                   <row>
+                     <entry><constant>V4L2_PREEMPHASIS_75_uS</constant>&nbsp;</entry>
+                     <entry>A pre-emphasis of 75 uS is used.</entry>
+                   </row>
+                 </tbody>
+               </entrytbl>
+
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TUNE_POWER_LEVEL</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">Sets the output power level for signal transmission.
+Unit is in dBuV. Range and step are driver-specific.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_TUNE_ANTENNA_CAPACITOR</constant>&nbsp;</entry>
+           <entry>integer</entry>
+         </row>
+         <row><entry spanname="descr">This selects the value of antenna tuning capacitor
+manually or automatically if set to zero. Unit, range and step are driver-specific.</entry>
+         </row>
+         <row><entry></entry></row>
+       </tbody>
+      </tgroup>
+      </table>
+
+<para>For more details about RDS specification, refer to
+<xref linkend="en50067" /> document, from CENELEC.</para>
+    </section>
+
+    <section id="flash-controls">
+      <title>Flash Control Reference</title>
+
+      <note>
+       <title>Experimental</title>
+
+       <para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+      </note>
+
+      <para>
+       The V4L2 flash controls are intended to provide generic access
+       to flash controller devices. Flash controller devices are
+       typically used in digital cameras.
+      </para>
+
+      <para>
+       The interface can support both LED and xenon flash devices. As
+       of writing this, there is no xenon flash driver using this
+       interface.
+      </para>
+
+      <section id="flash-controls-use-cases">
+       <title>Supported use cases</title>
+
+       <section>
+         <title>Unsynchronised LED flash (software strobe)</title>
+
+         <para>
+           Unsynchronised LED flash is controlled directly by the
+           host as the sensor. The flash must be enabled by the host
+           before the exposure of the image starts and disabled once
+           it ends. The host is fully responsible for the timing of
+           the flash.
+         </para>
+
+         <para>Example of such device: Nokia N900.</para>
+       </section>
+
+       <section>
+         <title>Synchronised LED flash (hardware strobe)</title>
+
+         <para>
+           The synchronised LED flash is pre-programmed by the host
+           (power and timeout) but controlled by the sensor through a
+           strobe signal from the sensor to the flash.
+         </para>
+
+         <para>
+           The sensor controls the flash duration and timing. This
+           information typically must be made available to the
+           sensor.
+         </para>
+
+       </section>
+
+       <section>
+         <title>LED flash as torch</title>
+
+         <para>
+           LED flash may be used as torch in conjunction with another
+           use case involving camera or individually.
+         </para>
+
+       </section>
+
+      </section>
+
+      <table pgwide="1" frame="none" id="flash-control-id">
+      <title>Flash Control IDs</title>
+
+      <tgroup cols="4">
+       <colspec colname="c1" colwidth="1*" />
+       <colspec colname="c2" colwidth="6*" />
+       <colspec colname="c3" colwidth="2*" />
+       <colspec colname="c4" colwidth="6*" />
+       <spanspec namest="c1" nameend="c2" spanname="id" />
+       <spanspec namest="c2" nameend="c4" spanname="descr" />
+       <thead>
+         <row>
+           <entry spanname="id" align="left">ID</entry>
+           <entry align="left">Type</entry>
+         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row><entry></entry></row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_CLASS</constant></entry>
+           <entry>class</entry>
+         </row>
+         <row>
+           <entry spanname="descr">The FLASH class descriptor.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_LED_MODE</constant></entry>
+           <entry>menu</entry>
+         </row>
+         <row id="v4l2-flash-led-mode">
+           <entry spanname="descr">Defines the mode of the flash LED,
+           the high-power white LED attached to the flash controller.
+           Setting this control may not be possible in presence of
+           some faults. See V4L2_CID_FLASH_FAULT.</entry>
+         </row>
+         <row>
+           <entrytbl spanname="descr" cols="2">
+             <tbody valign="top">
+               <row>
+                 <entry><constant>V4L2_FLASH_LED_MODE_NONE</constant></entry>
+                 <entry>Off.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_LED_MODE_FLASH</constant></entry>
+                 <entry>Flash mode.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_LED_MODE_TORCH</constant></entry>
+                 <entry>Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY.</entry>
+               </row>
+             </tbody>
+           </entrytbl>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_SOURCE</constant></entry>
+           <entry>menu</entry>
+         </row>
+         <row id="v4l2-flash-strobe-source"><entry
+         spanname="descr">Defines the source of the flash LED
+         strobe.</entry>
+         </row>
+         <row>
+           <entrytbl spanname="descr" cols="2">
+             <tbody valign="top">
+               <row>
+                 <entry><constant>V4L2_FLASH_STROBE_SOURCE_SOFTWARE</constant></entry>
+                 <entry>The flash strobe is triggered by using
+                 the V4L2_CID_FLASH_STROBE control.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_STROBE_SOURCE_EXTERNAL</constant></entry>
+                 <entry>The flash strobe is triggered by an
+                 external source. Typically this is a sensor,
+                 which makes it possible to synchronises the
+                 flash strobe start to exposure start.</entry>
+               </row>
+             </tbody>
+           </entrytbl>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE</constant></entry>
+           <entry>button</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Strobe flash. Valid when
+           V4L2_CID_FLASH_LED_MODE is set to
+           V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE
+           is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this
+           control may not be possible in presence of some faults.
+           See V4L2_CID_FLASH_FAULT.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STOP</constant></entry>
+           <entry>button</entry>
+         </row>
+         <row><entry spanname="descr">Stop flash strobe immediately.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STATUS</constant></entry>
+           <entry>boolean</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Strobe status: whether the flash
+           is strobing at the moment or not. This is a read-only
+           control.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_TIMEOUT</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Hardware timeout for flash. The
+           flash strobe is stopped after this period of time has
+           passed from the start of the strobe.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_INTENSITY</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Intensity of the flash strobe when
+           the flash LED is in flash mode
+           (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps
+           (mA) if possible.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_TORCH_INTENSITY</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Intensity of the flash LED in
+           torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be
+           milliamps (mA) if possible. Setting this control may not
+           be possible in presence of some faults. See
+           V4L2_CID_FLASH_FAULT.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_INDICATOR_INTENSITY</constant></entry>
+           <entry>integer</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Intensity of the indicator LED.
+           The indicator LED may be fully independent of the flash
+           LED. The unit should be microamps (uA) if possible.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_FAULT</constant></entry>
+           <entry>bitmask</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Faults related to the flash. The
+           faults tell about specific problems in the flash chip
+           itself or the LEDs attached to it. Faults may prevent
+           further use of some of the flash controls. In particular,
+           V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE
+           if the fault affects the flash LED. Exactly which faults
+           have such an effect is chip dependent. Reading the faults
+           resets the control and returns the chip to a usable state
+           if possible.</entry>
+         </row>
+         <row>
+           <entrytbl spanname="descr" cols="2">
+             <tbody valign="top">
+               <row>
+                 <entry><constant>V4L2_FLASH_FAULT_OVER_VOLTAGE</constant></entry>
+                 <entry>Flash controller voltage to the flash LED
+                 has exceeded the limit specific to the flash
+                 controller.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_FAULT_TIMEOUT</constant></entry>
+                 <entry>The flash strobe was still on when
+                 the timeout set by the user ---
+                 V4L2_CID_FLASH_TIMEOUT control --- has expired.
+                 Not all flash controllers may set this in all
+                 such conditions.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_FAULT_OVER_TEMPERATURE</constant></entry>
+                 <entry>The flash controller has overheated.</entry>
+               </row>
+               <row>
+                 <entry><constant>V4L2_FLASH_FAULT_SHORT_CIRCUIT</constant></entry>
+                 <entry>The short circuit protection of the flash
+                 controller has been triggered.</entry>
+               </row>
+             </tbody>
+           </entrytbl>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_CHARGE</constant></entry>
+           <entry>boolean</entry>
+         </row>
+         <row><entry spanname="descr">Enable or disable charging of the xenon
+         flash capacitor.</entry>
+         </row>
+         <row>
+           <entry spanname="id"><constant>V4L2_CID_FLASH_READY</constant></entry>
+           <entry>boolean</entry>
+         </row>
+         <row>
+           <entry spanname="descr">Is the flash ready to strobe?
+           Xenon flashes require their capacitors charged before
+           strobing. LED flashes often require a cooldown period
+           after strobe during which another strobe will not be
+           possible. This is a read-only control.</entry>
+         </row>
+         <row><entry></entry></row>
+       </tbody>
+      </tgroup>
+      </table>
+
+    </section>
+</section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "common.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/crop.pdf b/Documentation/DocBook/media/v4l/crop.pdf
new file mode 100644 (file)
index 0000000..c9fb81c
Binary files /dev/null and b/Documentation/DocBook/media/v4l/crop.pdf differ
diff --git a/Documentation/DocBook/media/v4l/dev-capture.xml b/Documentation/DocBook/media/v4l/dev-capture.xml
new file mode 100644 (file)
index 0000000..2237c66
--- /dev/null
@@ -0,0 +1,118 @@
+  <title>Video Capture Interface</title>
+
+  <para>Video capture devices sample an analog video signal and store
+the digitized images in memory. Today nearly all devices can capture
+at full 25 or 30 frames/second. With this interface applications can
+control the capture process and move images from the driver into user
+space.</para>
+
+  <para>Conventionally V4L2 video capture devices are accessed through
+character device special files named <filename>/dev/video</filename>
+and <filename>/dev/video0</filename> to
+<filename>/dev/video63</filename> with major number 81 and minor
+numbers 0 to 63. <filename>/dev/video</filename> is typically a
+symbolic link to the preferred video device. Note the same device
+files are used for video output devices.</para>
+
+  <section>
+    <title>Querying Capabilities</title>
+
+    <para>Devices supporting the video capture interface set the
+<constant>V4L2_CAP_VIDEO_CAPTURE</constant> or
+<constant>V4L2_CAP_VIDEO_CAPTURE_MPLANE</constant> flag in the
+<structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl. As secondary device functions
+they may also support the <link linkend="overlay">video overlay</link>
+(<constant>V4L2_CAP_VIDEO_OVERLAY</constant>) and the <link
+linkend="raw-vbi">raw VBI capture</link>
+(<constant>V4L2_CAP_VBI_CAPTURE</constant>) interface. At least one of
+the read/write or streaming I/O methods must be supported. Tuners and
+audio inputs are optional.</para>
+  </section>
+
+  <section>
+    <title>Supplemental Functions</title>
+
+    <para>Video capture devices shall support <link
+linkend="audio">audio input</link>, <link
+linkend="tuner">tuner</link>, <link linkend="control">controls</link>,
+<link linkend="crop">cropping and scaling</link> and <link
+linkend="streaming-par">streaming parameter</link> ioctls as needed.
+The <link linkend="video">video input</link> and <link
+linkend="standard">video standard</link> ioctls must be supported by
+all video capture devices.</para>
+  </section>
+
+  <section>
+    <title>Image Format Negotiation</title>
+
+    <para>The result of a capture operation is determined by
+cropping and image format parameters. The former select an area of the
+video picture to capture, the latter how images are stored in memory,
+&ie; in RGB or YUV format, the number of bits per pixel or width and
+height. Together they also define how images are scaled in the
+process.</para>
+
+    <para>As usual these parameters are <emphasis>not</emphasis> reset
+at &func-open; time to permit Unix tool chains, programming a device
+and then reading from it as if it was a plain file. Well written V4L2
+applications ensure they really get what they want, including cropping
+and scaling.</para>
+
+    <para>Cropping initialization at minimum requires to reset the
+parameters to defaults. An example is given in <xref
+linkend="crop" />.</para>
+
+    <para>To query the current image format applications set the
+<structfield>type</structfield> field of a &v4l2-format; to
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> or
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant> and call the
+&VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
+the &v4l2-pix-format; <structfield>pix</structfield> or the
+&v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member of the
+<structfield>fmt</structfield> union.</para>
+
+    <para>To request different parameters applications set the
+<structfield>type</structfield> field of a &v4l2-format; as above and
+initialize all fields of the &v4l2-pix-format;
+<structfield>vbi</structfield> member of the
+<structfield>fmt</structfield> union, or better just modify the
+results of <constant>VIDIOC_G_FMT</constant>, and call the
+&VIDIOC-S-FMT; ioctl with a pointer to this structure. Drivers may
+adjust the parameters and finally return the actual parameters as
+<constant>VIDIOC_G_FMT</constant> does.</para>
+
+    <para>Like <constant>VIDIOC_S_FMT</constant> the
+&VIDIOC-TRY-FMT; ioctl can be used to learn about hardware limitations
+without disabling I/O or possibly time consuming hardware
+preparations.</para>
+
+    <para>The contents of &v4l2-pix-format; and &v4l2-pix-format-mplane;
+are discussed in <xref linkend="pixfmt" />. See also the specification of the
+<constant>VIDIOC_G_FMT</constant>, <constant>VIDIOC_S_FMT</constant>
+and <constant>VIDIOC_TRY_FMT</constant> ioctls for details. Video
+capture devices must implement both the
+<constant>VIDIOC_G_FMT</constant> and
+<constant>VIDIOC_S_FMT</constant> ioctl, even if
+<constant>VIDIOC_S_FMT</constant> ignores all requests and always
+returns default parameters as <constant>VIDIOC_G_FMT</constant> does.
+<constant>VIDIOC_TRY_FMT</constant> is optional.</para>
+  </section>
+
+  <section>
+    <title>Reading Images</title>
+
+    <para>A video capture device may support the <link
+linkend="rw">read() function</link> and/or streaming (<link
+linkend="mmap">memory mapping</link> or <link
+linkend="userp">user pointer</link>) I/O. See <xref
+linkend="io" /> for details.</para>
+  </section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/dev-codec.xml b/Documentation/DocBook/media/v4l/dev-codec.xml
new file mode 100644 (file)
index 0000000..6e156dc
--- /dev/null
@@ -0,0 +1,26 @@
+  <title>Codec Interface</title>
+
+  <note>
+    <title>Suspended</title>
+
+    <para>This interface has been be suspended from the V4L2 API
+implemented in Linux 2.6 until we have more experience with codec
+device interfaces.</para>
+  </note>
+
+  <para>A V4L2 codec can compress, decompress, transform, or otherwise
+convert video data from one format into another format, in memory.
+Applications send data to be converted to the driver through a
+&func-write; call, and receive the converted data through a
+&func-read; call. For efficiency a driver may also support streaming
+I/O.</para>
+
+  <para>[to do]</para>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/dev-effect.xml b/Documentation/DocBook/media/v4l/dev-effect.xml
new file mode 100644 (file)
index 0000000..9c243be
--- /dev/null
@@ -0,0 +1,25 @@
+  <title>Effect Devices Interface</title>
+
+  <note>
+    <title>Suspended</title>
+
+    <para>This interface has been be suspended from the V4L2 API
+implemented in Linux 2.6 until we have more experience with effect
+device interfaces.</para>
+  </note>
+
+  <para>A V4L2 video effect device can do image effects, filtering, or
+combine two or more images or image streams. For example video
+transitions or wipes. Applications send data to be processed and
+receive the result data either with &func-read; and &func-write;
+functions, or through the streaming I/O mechanism.</para>
+
+  <para>[to do]</para>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/dev-event.xml b/Documentation/DocBook/media/v4l/dev-event.xml
new file mode 100644 (file)
index 0000000..f14ae3f
--- /dev/null
@@ -0,0 +1,51 @@
+  <title>Event Interface</title>
+
+  <para>The V4L2 event interface provides a means for a user to get
+  immediately notified on certain conditions taking place on a device.
+  This might include start of frame or loss of signal events, for
+  example. Changes in the value or state of a V4L2 control can also be
+  reported through events.
+  </para>
+
+  <para>To receive events, the events the user is interested in first must
+  be subscribed using the &VIDIOC-SUBSCRIBE-EVENT; ioctl. Once an event is
+  subscribed, the events of subscribed types are dequeueable using the
+  &VIDIOC-DQEVENT; ioctl. Events may be unsubscribed using
+  VIDIOC_UNSUBSCRIBE_EVENT ioctl. The special event type V4L2_EVENT_ALL may
+  be used to unsubscribe all the events the driver supports.</para>
+
+  <para>The event subscriptions and event queues are specific to file
+  handles. Subscribing an event on one file handle does not affect
+  other file handles.</para>
+
+  <para>The information on dequeueable events is obtained by using select or
+  poll system calls on video devices. The V4L2 events use POLLPRI events on
+  poll system call and exceptions on select system call.</para>
+
+  <para>Starting with kernel 3.1 certain guarantees can be given with
+  regards to events:<orderedlist>
+       <listitem>
+         <para>Each subscribed event has its own internal dedicated event queue.
+This means that flooding of one event type will not interfere with other
+event types.</para>
+       </listitem>
+       <listitem>
+         <para>If the internal event queue for a particular subscribed event
+becomes full, then the oldest event in that queue will be dropped.</para>
+       </listitem>
+       <listitem>
+         <para>Where applicable, certain event types can ensure that the payload
+of the oldest event that is about to be dropped will be merged with the payload
+of the next oldest event. Thus ensuring that no information is lost, but only an
+intermediate step leading up to that information. See the documentation for the
+event you want to subscribe to whether this is applicable for that event or not.</para>
+       </listitem>
+      </orderedlist></para>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/dev-osd.xml b/Documentation/DocBook/media/v4l/dev-osd.xml
new file mode 100644 (file)
index 0000000..c9a68a2
--- /dev/null
@@ -0,0 +1,164 @@
+  <title>Video Output Overlay Interface</title>
+  <subtitle>Also known as On-Screen Display (OSD)</subtitle>
+
+  <note>
+    <title>Experimental</title>
+
+    <para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+  </note>
+
+  <para>Some video output devices can overlay a framebuffer image onto
+the outgoing video signal. Applications can set up such an overlay
+using this interface, which borrows structures and ioctls of the <link
+linkend="overlay">Video Overlay</link> interface.</para>
+
+  <para>The OSD function is accessible through the same character
+special file as the <link linkend="capture">Video Output</link> function.
+Note the default function of such a <filename>/dev/video</filename> device
+is video capturing or output. The OSD function is only available after
+calling the &VIDIOC-S-FMT; ioctl.</para>
+
+  <section>
+    <title>Querying Capabilities</title>
+
+    <para>Devices supporting the <wordasword>Video Output
+Overlay</wordasword> interface set the
+<constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant> flag in the
+<structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl.</para>
+  </section>
+
+  <section>
+    <title>Framebuffer</title>
+
+    <para>Contrary to the <wordasword>Video Overlay</wordasword>
+interface the framebuffer is normally implemented on the TV card and
+not the graphics card. On Linux it is accessible as a framebuffer
+device (<filename>/dev/fbN</filename>). Given a V4L2 device,
+applications can find the corresponding framebuffer device by calling
+the &VIDIOC-G-FBUF; ioctl. It returns, amongst other information, the
+physical address of the framebuffer in the
+<structfield>base</structfield> field of &v4l2-framebuffer;. The
+framebuffer device ioctl <constant>FBIOGET_FSCREENINFO</constant>
+returns the same address in the <structfield>smem_start</structfield>
+field of struct <structname>fb_fix_screeninfo</structname>. The
+<constant>FBIOGET_FSCREENINFO</constant> ioctl and struct
+<structname>fb_fix_screeninfo</structname> are defined in the
+<filename>linux/fb.h</filename> header file.</para>
+
+    <para>The width and height of the framebuffer depends on the
+current video standard. A V4L2 driver may reject attempts to change
+the video standard (or any other ioctl which would imply a framebuffer
+size change) with an &EBUSY; until all applications closed the
+framebuffer device.</para>
+
+    <example>
+      <title>Finding a framebuffer device for OSD</title>
+
+      <programlisting>
+#include &lt;linux/fb.h&gt;
+
+&v4l2-framebuffer; fbuf;
+unsigned int i;
+int fb_fd;
+
+if (-1 == ioctl (fd, VIDIOC_G_FBUF, &amp;fbuf)) {
+       perror ("VIDIOC_G_FBUF");
+       exit (EXIT_FAILURE);
+}
+
+for (i = 0; i &gt; 30; ++i) {
+       char dev_name[16];
+       struct fb_fix_screeninfo si;
+
+       snprintf (dev_name, sizeof (dev_name), "/dev/fb%u", i);
+
+       fb_fd = open (dev_name, O_RDWR);
+       if (-1 == fb_fd) {
+               switch (errno) {
+               case ENOENT: /* no such file */
+               case ENXIO:  /* no driver */
+                       continue;
+
+               default:
+                       perror ("open");
+                       exit (EXIT_FAILURE);
+               }
+       }
+
+       if (0 == ioctl (fb_fd, FBIOGET_FSCREENINFO, &amp;si)) {
+               if (si.smem_start == (unsigned long) fbuf.base)
+                       break;
+       } else {
+               /* Apparently not a framebuffer device. */
+       }
+
+       close (fb_fd);
+       fb_fd = -1;
+}
+
+/* fb_fd is the file descriptor of the framebuffer device
+   for the video output overlay, or -1 if no device was found. */
+</programlisting>
+    </example>
+  </section>
+
+  <section>
+    <title>Overlay Window and Scaling</title>
+
+    <para>The overlay is controlled by source and target rectangles.
+The source rectangle selects a subsection of the framebuffer image to
+be overlaid, the target rectangle an area in the outgoing video signal
+where the image will appear. Drivers may or may not support scaling,
+and arbitrary sizes and positions of these rectangles. Further drivers
+may support any (or none) of the clipping/blending methods defined for
+the <link linkend="overlay">Video Overlay</link> interface.</para>
+
+    <para>A &v4l2-window; defines the size of the source rectangle,
+its position in the framebuffer and the clipping/blending method to be
+used for the overlay. To get the current parameters applications set
+the <structfield>type</structfield> field of a &v4l2-format; to
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant> and call the
+&VIDIOC-G-FMT; ioctl. The driver fills the
+<structname>v4l2_window</structname> substructure named
+<structfield>win</structfield>. It is not possible to retrieve a
+previously programmed clipping list or bitmap.</para>
+
+    <para>To program the source rectangle applications set the
+<structfield>type</structfield> field of a &v4l2-format; to
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant>, initialize
+the <structfield>win</structfield> substructure and call the
+&VIDIOC-S-FMT; ioctl. The driver adjusts the parameters against
+hardware limits and returns the actual parameters as
+<constant>VIDIOC_G_FMT</constant> does. Like
+<constant>VIDIOC_S_FMT</constant>, the &VIDIOC-TRY-FMT; ioctl can be
+used to learn about driver capabilities without actually changing
+driver state. Unlike <constant>VIDIOC_S_FMT</constant> this also works
+after the overlay has been enabled.</para>
+
+    <para>A &v4l2-crop; defines the size and position of the target
+rectangle. The scaling factor of the overlay is implied by the width
+and height given in &v4l2-window; and &v4l2-crop;. The cropping API
+applies to <wordasword>Video Output</wordasword> and <wordasword>Video
+Output Overlay</wordasword> devices in the same way as to
+<wordasword>Video Capture</wordasword> and <wordasword>Video
+Overlay</wordasword> devices, merely reversing the direction of the
+data flow. For more information see <xref linkend="crop" />.</para>
+  </section>
+
+  <section>
+    <title>Enabling Overlay</title>
+
+    <para>There is no V4L2 ioctl to enable or disable the overlay,
+however the framebuffer interface of the driver may support the
+<constant>FBIOBLANK</constant> ioctl.</para>
+  </section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/dev-output.xml b/Documentation/DocBook/media/v4l/dev-output.xml
new file mode 100644 (file)
index 0000000..919e22c
--- /dev/null
@@ -0,0 +1,114 @@
+  <title>Video Output Interface</title>
+
+  <para>Video output devices encode stills or image sequences as
+analog video signal. With this interface applications can
+control the encoding process and move images from user space to
+the driver.</para>
+
+  <para>Conventionally V4L2 video output devices are accessed through
+character device special files named <filename>/dev/video</filename>
+and <filename>/dev/video0</filename> to
+<filename>/dev/video63</filename> with major number 81 and minor
+numbers 0 to 63. <filename>/dev/video</filename> is typically a
+symbolic link to the preferred video device. Note the same device
+files are used for video capture devices.</para>
+
+  <section>
+    <title>Querying Capabilities</title>
+
+    <para>Devices supporting the video output interface set the
+<constant>V4L2_CAP_VIDEO_OUTPUT</constant> or
+<constant>V4L2_CAP_VIDEO_OUTPUT_MPLANE</constant> flag in the
+<structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl. As secondary device functions
+they may also support the <link linkend="raw-vbi">raw VBI
+output</link> (<constant>V4L2_CAP_VBI_OUTPUT</constant>) interface. At
+least one of the read/write or streaming I/O methods must be
+supported. Modulators and audio outputs are optional.</para>
+  </section>
+
+  <section>
+    <title>Supplemental Functions</title>
+
+    <para>Video output devices shall support <link
+linkend="audio">audio output</link>, <link
+linkend="tuner">modulator</link>, <link linkend="control">controls</link>,
+<link linkend="crop">cropping and scaling</link> and <link
+linkend="streaming-par">streaming parameter</link> ioctls as needed.
+The <link linkend="video">video output</link> and <link
+linkend="standard">video standard</link> ioctls must be supported by
+all video output devices.</para>
+  </section>
+
+  <section>
+    <title>Image Format Negotiation</title>
+
+    <para>The output is determined by cropping and image format
+parameters. The former select an area of the video picture where the
+image will appear, the latter how images are stored in memory, &ie; in
+RGB or YUV format, the number of bits per pixel or width and height.
+Together they also define how images are scaled in the process.</para>
+
+    <para>As usual these parameters are <emphasis>not</emphasis> reset
+at &func-open; time to permit Unix tool chains, programming a device
+and then writing to it as if it was a plain file. Well written V4L2
+applications ensure they really get what they want, including cropping
+and scaling.</para>
+
+    <para>Cropping initialization at minimum requires to reset the
+parameters to defaults. An example is given in <xref
+linkend="crop" />.</para>
+
+    <para>To query the current image format applications set the
+<structfield>type</structfield> field of a &v4l2-format; to
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> or
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant> and call the
+&VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
+the &v4l2-pix-format; <structfield>pix</structfield> or the
+&v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member of the
+<structfield>fmt</structfield> union.</para>
+
+    <para>To request different parameters applications set the
+<structfield>type</structfield> field of a &v4l2-format; as above and
+initialize all fields of the &v4l2-pix-format;
+<structfield>vbi</structfield> member of the
+<structfield>fmt</structfield> union, or better just modify the
+results of <constant>VIDIOC_G_FMT</constant>, and call the
+&VIDIOC-S-FMT; ioctl with a pointer to this structure. Drivers may
+adjust the parameters and finally return the actual parameters as
+<constant>VIDIOC_G_FMT</constant> does.</para>
+
+    <para>Like <constant>VIDIOC_S_FMT</constant> the
+&VIDIOC-TRY-FMT; ioctl can be used to learn about hardware limitations
+without disabling I/O or possibly time consuming hardware
+preparations.</para>
+
+    <para>The contents of &v4l2-pix-format; and &v4l2-pix-format-mplane;
+are discussed in <xref linkend="pixfmt" />. See also the specification of the
+<constant>VIDIOC_G_FMT</constant>, <constant>VIDIOC_S_FMT</constant>
+and <constant>VIDIOC_TRY_FMT</constant> ioctls for details. Video
+output devices must implement both the
+<constant>VIDIOC_G_FMT</constant> and
+<constant>VIDIOC_S_FMT</constant> ioctl, even if
+<constant>VIDIOC_S_FMT</constant> ignores all requests and always
+returns default parameters as <constant>VIDIOC_G_FMT</constant> does.
+<constant>VIDIOC_TRY_FMT</constant> is optional.</para>
+  </section>
+
+  <section>
+    <title>Writing Images</title>
+
+    <para>A video output device may support the <link
+linkend="rw">write() function</link> and/or streaming (<link
+linkend="mmap">memory mapping</link> or <link
+linkend="userp">user pointer</link>) I/O. See <xref
+linkend="io" /> for details.</para>
+  </section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/dev-overlay.xml b/Documentation/DocBook/media/v4l/dev-overlay.xml
new file mode 100644 (file)
index 0000000..92513cf
--- /dev/null
@@ -0,0 +1,379 @@
+  <title>Video Overlay Interface</title>
+  <subtitle>Also known as Framebuffer Overlay or Previewing</subtitle>
+
+  <para>Video overlay devices have the ability to genlock (TV-)video
+into the (VGA-)video signal of a graphics card, or to store captured
+images directly in video memory of a graphics card, typically with
+clipping. This can be considerable more efficient than capturing
+images and displaying them by other means. In the old days when only
+nuclear power plants needed cooling towers this used to be the only
+way to put live video into a window.</para>
+
+  <para>Video overlay devices are accessed through the same character
+special files as <link linkend="capture">video capture</link> devices.
+Note the default function of a <filename>/dev/video</filename> device
+is video capturing. The overlay function is only available after
+calling the &VIDIOC-S-FMT; ioctl.</para>
+
+    <para>The driver may support simultaneous overlay and capturing
+using the read/write and streaming I/O methods. If so, operation at
+the nominal frame rate of the video standard is not guaranteed. Frames
+may be directed away from overlay to capture, or one field may be used
+for overlay and the other for capture if the capture parameters permit
+this.</para>
+
+  <para>Applications should use different file descriptors for
+capturing and overlay. This must be supported by all drivers capable
+of simultaneous capturing and overlay. Optionally these drivers may
+also permit capturing and overlay with a single file descriptor for
+compatibility with V4L and earlier versions of V4L2.<footnote>
+       <para>A common application of two file descriptors is the
+XFree86 <link linkend="xvideo">Xv/V4L</link> interface driver and
+a V4L2 application. While the X server controls video overlay, the
+application can take advantage of memory mapping and DMA.</para>
+       <para>In the opinion of the designers of this API, no driver
+writer taking the efforts to support simultaneous capturing and
+overlay will restrict this ability by requiring a single file
+descriptor, as in V4L and earlier versions of V4L2. Making this
+optional means applications depending on two file descriptors need
+backup routines to be compatible with all drivers, which is
+considerable more work than using two fds in applications which do
+not. Also two fd's fit the general concept of one file descriptor for
+each logical stream. Hence as a complexity trade-off drivers
+<emphasis>must</emphasis> support two file descriptors and
+<emphasis>may</emphasis> support single fd operation.</para>
+      </footnote></para>
+
+  <section>
+    <title>Querying Capabilities</title>
+
+    <para>Devices supporting the video overlay interface set the
+<constant>V4L2_CAP_VIDEO_OVERLAY</constant> flag in the
+<structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl. The overlay I/O method specified
+below must be supported. Tuners and audio inputs are optional.</para>
+  </section>
+
+  <section>
+    <title>Supplemental Functions</title>
+
+    <para>Video overlay devices shall support <link
+linkend="audio">audio input</link>, <link
+linkend="tuner">tuner</link>, <link linkend="control">controls</link>,
+<link linkend="crop">cropping and scaling</link> and <link
+linkend="streaming-par">streaming parameter</link> ioctls as needed.
+The <link linkend="video">video input</link> and <link
+linkend="standard">video standard</link> ioctls must be supported by
+all video overlay devices.</para>
+  </section>
+
+  <section>
+    <title>Setup</title>
+
+    <para>Before overlay can commence applications must program the
+driver with frame buffer parameters, namely the address and size of
+the frame buffer and the image format, for example RGB 5:6:5. The
+&VIDIOC-G-FBUF; and &VIDIOC-S-FBUF; ioctls are available to get
+and set these parameters, respectively. The
+<constant>VIDIOC_S_FBUF</constant> ioctl is privileged because it
+allows to set up DMA into physical memory, bypassing the memory
+protection mechanisms of the kernel. Only the superuser can change the
+frame buffer address and size. Users are not supposed to run TV
+applications as root or with SUID bit set. A small helper application
+with suitable privileges should query the graphics system and program
+the V4L2 driver at the appropriate time.</para>
+
+    <para>Some devices add the video overlay to the output signal
+of the graphics card. In this case the frame buffer is not modified by
+the video device, and the frame buffer address and pixel format are
+not needed by the driver. The <constant>VIDIOC_S_FBUF</constant> ioctl
+is not privileged. An application can check for this type of device by
+calling the <constant>VIDIOC_G_FBUF</constant> ioctl.</para>
+
+    <para>A driver may support any (or none) of five clipping/blending
+methods:<orderedlist>
+       <listitem>
+         <para>Chroma-keying displays the overlaid image only where
+pixels in the primary graphics surface assume a certain color.</para>
+       </listitem>
+       <listitem>
+         <para>A bitmap can be specified where each bit corresponds
+to a pixel in the overlaid image. When the bit is set, the
+corresponding video pixel is displayed, otherwise a pixel of the
+graphics surface.</para>
+       </listitem>
+       <listitem>
+         <para>A list of clipping rectangles can be specified. In
+these regions <emphasis>no</emphasis> video is displayed, so the
+graphics surface can be seen here.</para>
+       </listitem>
+       <listitem>
+         <para>The framebuffer has an alpha channel that can be used
+to clip or blend the framebuffer with the video.</para>
+       </listitem>
+       <listitem>
+         <para>A global alpha value can be specified to blend the
+framebuffer contents with video images.</para>
+       </listitem>
+      </orderedlist></para>
+
+    <para>When simultaneous capturing and overlay is supported and
+the hardware prohibits different image and frame buffer formats, the
+format requested first takes precedence. The attempt to capture
+(&VIDIOC-S-FMT;) or overlay (&VIDIOC-S-FBUF;) may fail with an
+&EBUSY; or return accordingly modified parameters..</para>
+  </section>
+
+  <section>
+    <title>Overlay Window</title>
+
+    <para>The overlaid image is determined by cropping and overlay
+window parameters. The former select an area of the video picture to
+capture, the latter how images are overlaid and clipped. Cropping
+initialization at minimum requires to reset the parameters to
+defaults. An example is given in <xref linkend="crop" />.</para>
+
+    <para>The overlay window is described by a &v4l2-window;. It
+defines the size of the image, its position over the graphics surface
+and the clipping to be applied. To get the current parameters
+applications set the <structfield>type</structfield> field of a
+&v4l2-format; to <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant> and
+call the &VIDIOC-G-FMT; ioctl. The driver fills the
+<structname>v4l2_window</structname> substructure named
+<structfield>win</structfield>. It is not possible to retrieve a
+previously programmed clipping list or bitmap.</para>
+
+    <para>To program the overlay window applications set the
+<structfield>type</structfield> field of a &v4l2-format; to
+<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, initialize the
+<structfield>win</structfield> substructure and call the
+&VIDIOC-S-FMT; ioctl. The driver adjusts the parameters against
+hardware limits and returns the actual parameters as
+<constant>VIDIOC_G_FMT</constant> does. Like
+<constant>VIDIOC_S_FMT</constant>, the &VIDIOC-TRY-FMT; ioctl can be
+used to learn about driver capabilities without actually changing
+driver state. Unlike <constant>VIDIOC_S_FMT</constant> this also works
+after the overlay has been enabled.</para>
+
+    <para>The scaling factor of the overlaid image is implied by the
+width and height given in &v4l2-window; and the size of the cropping
+rectangle. For more information see <xref linkend="crop" />.</para>
+
+    <para>When simultaneous capturing and overlay is supported and
+the hardware prohibits different image and window sizes, the size
+requested first takes precedence. The attempt to capture or overlay as
+well (&VIDIOC-S-FMT;) may fail with an &EBUSY; or return accordingly
+modified parameters.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-window">
+      <title>struct <structname>v4l2_window</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>&v4l2-rect;</entry>
+           <entry><structfield>w</structfield></entry>
+           <entry>Size and position of the window relative to the
+top, left corner of the frame buffer defined with &VIDIOC-S-FBUF;. The
+window can extend the frame buffer width and height, the
+<structfield>x</structfield> and <structfield>y</structfield>
+coordinates can be negative, and it can lie completely outside the
+frame buffer. The driver clips the window accordingly, or if that is
+not possible, modifies its size and/or position.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-field;</entry>
+           <entry><structfield>field</structfield></entry>
+           <entry>Applications set this field to determine which
+video field shall be overlaid, typically one of
+<constant>V4L2_FIELD_ANY</constant> (0),
+<constant>V4L2_FIELD_TOP</constant>,
+<constant>V4L2_FIELD_BOTTOM</constant> or
+<constant>V4L2_FIELD_INTERLACED</constant>. Drivers may have to choose
+a different field order and return the actual setting here.</entry>
+           </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>chromakey</structfield></entry>
+           <entry>When chroma-keying has been negotiated with
+&VIDIOC-S-FBUF; applications set this field to the desired pixel value
+for the chroma key. The format is the same as the pixel format of the
+framebuffer (&v4l2-framebuffer;
+<structfield>fmt.pixelformat</structfield> field), with bytes in host
+order. E.&nbsp;g. for <link
+linkend="V4L2-PIX-FMT-BGR32"><constant>V4L2_PIX_FMT_BGR24</constant></link>
+the value should be 0xRRGGBB on a little endian, 0xBBGGRR on a big
+endian host.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-clip; *</entry>
+           <entry><structfield>clips</structfield></entry>
+           <entry>When chroma-keying has <emphasis>not</emphasis>
+been negotiated and &VIDIOC-G-FBUF; indicated this capability,
+applications can set this field to point to an array of
+clipping rectangles.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>Like the window coordinates
+<structfield>w</structfield>, clipping rectangles are defined relative
+to the top, left corner of the frame buffer. However clipping
+rectangles must not extend the frame buffer width and height, and they
+must not overlap. If possible applications should merge adjacent
+rectangles. Whether this must create x-y or y-x bands, or the order of
+rectangles, is not defined. When clip lists are not supported the
+driver ignores this field. Its contents after calling &VIDIOC-S-FMT;
+are undefined.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>clipcount</structfield></entry>
+           <entry>When the application set the
+<structfield>clips</structfield> field, this field must contain the
+number of clipping rectangles in the list. When clip lists are not
+supported the driver ignores this field, its contents after calling
+<constant>VIDIOC_S_FMT</constant> are undefined. When clip lists are
+supported but no clipping is desired this field must be set to
+zero.</entry>
+         </row>
+         <row>
+           <entry>void *</entry>
+           <entry><structfield>bitmap</structfield></entry>
+           <entry>When chroma-keying has
+<emphasis>not</emphasis> been negotiated and &VIDIOC-G-FBUF; indicated
+this capability, applications can set this field to point to a
+clipping bit mask.</entry>
+         </row>
+         <row>
+           <entry spanname="hspan"><para>It must be of the same size
+as the window, <structfield>w.width</structfield> and
+<structfield>w.height</structfield>. Each bit corresponds to a pixel
+in the overlaid image, which is displayed only when the bit is
+<emphasis>set</emphasis>. Pixel coordinates translate to bits like:
+<programlisting>
+((__u8 *) <structfield>bitmap</structfield>)[<structfield>w.width</structfield> * y + x / 8] &amp; (1 &lt;&lt; (x &amp; 7))</programlisting></para><para>where <structfield>0</structfield> &le; x &lt;
+<structfield>w.width</structfield> and <structfield>0</structfield> &le;
+y &lt;<structfield>w.height</structfield>.<footnote>
+                 <para>Should we require
+             <structfield>w.width</structfield> to be a multiple of
+             eight?</para>
+               </footnote></para><para>When a clipping
+bit mask is not supported the driver ignores this field, its contents
+after calling &VIDIOC-S-FMT; are undefined. When a bit mask is supported
+but no clipping is desired this field must be set to
+<constant>NULL</constant>.</para><para>Applications need not create a
+clip list or bit mask. When they pass both, or despite negotiating
+chroma-keying, the results are undefined. Regardless of the chosen
+method, the clipping abilities of the hardware may be limited in
+quantity or quality. The results when these limits are exceeded are
+undefined.<footnote>
+                 <para>When the image is written into frame buffer
+memory it will be undesirable if the driver clips out less pixels
+than expected, because the application and graphics system are not
+aware these regions need to be refreshed. The driver should clip out
+more pixels or not write the image at all.</para>
+               </footnote></para></entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>global_alpha</structfield></entry>
+           <entry>The global alpha value used to blend the
+framebuffer with video images, if global alpha blending has been
+negotiated (<constant>V4L2_FBUF_FLAG_GLOBAL_ALPHA</constant>, see
+&VIDIOC-S-FBUF;, <xref linkend="framebuffer-flags" />).</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>Note this field was added in Linux 2.6.23, extending the structure. However
+the <link linkend="vidioc-g-fmt">VIDIOC_G/S/TRY_FMT</link> ioctls,
+which take a pointer to a <link
+linkend="v4l2-format">v4l2_format</link> parent structure with padding
+bytes at the end, are not affected.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-clip">
+      <title>struct <structname>v4l2_clip</structname><footnote>
+         <para>The X Window system defines "regions" which are
+vectors of struct BoxRec { short x1, y1, x2, y2; } with width = x2 -
+x1 and height = y2 - y1, so one cannot pass X11 clip lists
+directly.</para>
+       </footnote></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>&v4l2-rect;</entry>
+           <entry><structfield>c</structfield></entry>
+           <entry>Coordinates of the clipping rectangle, relative to
+the top, left corner of the frame buffer. Only window pixels
+<emphasis>outside</emphasis> all clipping rectangles are
+displayed.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-clip; *</entry>
+           <entry><structfield>next</structfield></entry>
+           <entry>Pointer to the next clipping rectangle, NULL when
+this is the last rectangle. Drivers ignore this field, it cannot be
+used to pass a linked list of clipping rectangles.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <!-- NB for easier reading this table is duplicated
+    in the vidioc-cropcap chapter.-->
+
+    <table pgwide="1" frame="none" id="v4l2-rect">
+      <title>struct <structname>v4l2_rect</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>left</structfield></entry>
+           <entry>Horizontal offset of the top, left corner of the
+rectangle, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>top</structfield></entry>
+           <entry>Vertical offset of the top, left corner of the
+rectangle, in pixels. Offsets increase to the right and down.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>width</structfield></entry>
+           <entry>Width of the rectangle, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>height</structfield></entry>
+           <entry>Height of the rectangle, in pixels. Width and
+height cannot be negative, the fields are signed for hysterical
+reasons. <!-- video4linux-list@redhat.com on 22 Oct 2002 subject
+"Re:[V4L][patches!] Re:v4l2/kernel-2.5" --></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </section>
+
+  <section>
+    <title>Enabling Overlay</title>
+
+    <para>To start or stop the frame buffer overlay applications call
+the &VIDIOC-OVERLAY; ioctl.</para>
+  </section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/dev-radio.xml b/Documentation/DocBook/media/v4l/dev-radio.xml
new file mode 100644 (file)
index 0000000..73aa90b
--- /dev/null
@@ -0,0 +1,57 @@
+  <title>Radio Interface</title>
+
+  <para>This interface is intended for AM and FM (analog) radio
+receivers and transmitters.</para>
+
+  <para>Conventionally V4L2 radio devices are accessed through
+character device special files named <filename>/dev/radio</filename>
+and <filename>/dev/radio0</filename> to
+<filename>/dev/radio63</filename> with major number 81 and minor
+numbers 64 to 127.</para>
+
+  <section>
+    <title>Querying Capabilities</title>
+
+    <para>Devices supporting the radio interface set the
+<constant>V4L2_CAP_RADIO</constant> and
+<constant>V4L2_CAP_TUNER</constant> or
+<constant>V4L2_CAP_MODULATOR</constant> flag in the
+<structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl. Other combinations of
+capability flags are reserved for future extensions.</para>
+  </section>
+
+  <section>
+    <title>Supplemental Functions</title>
+
+    <para>Radio devices can support <link
+linkend="control">controls</link>, and must support the <link
+linkend="tuner">tuner or modulator</link> ioctls.</para>
+
+    <para>They do not support the video input or output, audio input
+or output, video standard, cropping and scaling, compression and
+streaming parameter, or overlay ioctls. All other ioctls and I/O
+methods are reserved for future extensions.</para>
+  </section>
+
+  <section>
+    <title>Programming</title>
+
+    <para>Radio devices may have a couple audio controls (as discussed
+in <xref linkend="control" />) such as a volume control, possibly custom
+controls. Further all radio devices have one tuner or modulator (these are
+discussed in <xref linkend="tuner" />) with index number zero to select
+the radio frequency and to determine if a monaural or FM stereo
+program is received/emitted. Drivers switch automatically between AM and FM
+depending on the selected frequency. The &VIDIOC-G-TUNER; or
+&VIDIOC-G-MODULATOR; ioctl
+reports the supported frequency range.</para>
+  </section>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+ -->
diff --git a/Documentation/DocBook/media/v4l/dev-raw-vbi.xml b/Documentation/DocBook/media/v4l/dev-raw-vbi.xml
new file mode 100644 (file)
index 0000000..c5a70bd
--- /dev/null
@@ -0,0 +1,347 @@
+  <title>Raw VBI Data Interface</title>
+
+  <para>VBI is an abbreviation of Vertical Blanking Interval, a gap
+in the sequence of lines of an analog video signal. During VBI
+no picture information is transmitted, allowing some time while the
+electron beam of a cathode ray tube TV returns to the top of the
+screen. Using an oscilloscope you will find here the vertical
+synchronization pulses and short data packages ASK
+modulated<footnote><para>ASK: Amplitude-Shift Keying. A high signal
+level represents a '1' bit, a low level a '0' bit.</para></footnote>
+onto the video signal. These are transmissions of services such as
+Teletext or Closed Caption.</para>
+
+  <para>Subject of this interface type is raw VBI data, as sampled off
+a video signal, or to be added to a signal for output.
+The data format is similar to uncompressed video images, a number of
+lines times a number of samples per line, we call this a VBI image.</para>
+
+  <para>Conventionally V4L2 VBI devices are accessed through character
+device special files named <filename>/dev/vbi</filename> and
+<filename>/dev/vbi0</filename> to <filename>/dev/vbi31</filename> with
+major number 81 and minor numbers 224 to 255.
+<filename>/dev/vbi</filename> is typically a symbolic link to the
+preferred VBI device. This convention applies to both input and output
+devices.</para>
+
+  <para>To address the problems of finding related video and VBI
+devices VBI capturing and output is also available as device function
+under <filename>/dev/video</filename>. To capture or output raw VBI
+data with these devices applications must call the &VIDIOC-S-FMT;
+ioctl. Accessed as <filename>/dev/vbi</filename>, raw VBI capturing
+or output is the default device function.</para>
+
+    <section>
+      <title>Querying Capabilities</title>
+
+      <para>Devices supporting the raw VBI capturing or output API set
+the <constant>V4L2_CAP_VBI_CAPTURE</constant> or
+<constant>V4L2_CAP_VBI_OUTPUT</constant> flags, respectively, in the
+<structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl. At least one of the
+read/write, streaming or asynchronous I/O methods must be
+supported. VBI devices may or may not have a tuner or modulator.</para>
+    </section>
+
+    <section>
+      <title>Supplemental Functions</title>
+
+      <para>VBI devices shall support <link linkend="video">video
+input or output</link>, <link linkend="tuner">tuner or
+modulator</link>, and <link linkend="control">controls</link> ioctls
+as needed. The <link linkend="standard">video standard</link> ioctls provide
+information vital to program a VBI device, therefore must be
+supported.</para>
+    </section>
+
+    <section>
+      <title>Raw VBI Format Negotiation</title>
+
+      <para>Raw VBI sampling abilities can vary, in particular the
+sampling frequency. To properly interpret the data V4L2 specifies an
+ioctl to query the sampling parameters. Moreover, to allow for some
+flexibility applications can also suggest different parameters.</para>
+
+      <para>As usual these parameters are <emphasis>not</emphasis>
+reset at &func-open; time to permit Unix tool chains, programming a
+device and then reading from it as if it was a plain file. Well
+written V4L2 applications should always ensure they really get what
+they want, requesting reasonable parameters and then checking if the
+actual parameters are suitable.</para>
+
+      <para>To query the current raw VBI capture parameters
+applications set the <structfield>type</structfield> field of a
+&v4l2-format; to <constant>V4L2_BUF_TYPE_VBI_CAPTURE</constant> or
+<constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant>, and call the
+&VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
+the &v4l2-vbi-format; <structfield>vbi</structfield> member of the
+<structfield>fmt</structfield> union.</para>
+
+      <para>To request different parameters applications set the
+<structfield>type</structfield> field of a &v4l2-format; as above and
+initialize all fields of the &v4l2-vbi-format;
+<structfield>vbi</structfield> member of the
+<structfield>fmt</structfield> union, or better just modify the
+results of <constant>VIDIOC_G_FMT</constant>, and call the
+&VIDIOC-S-FMT; ioctl with a pointer to this structure. Drivers return
+an &EINVAL; only when the given parameters are ambiguous, otherwise
+they modify the parameters according to the hardware capabilites and
+return the actual parameters. When the driver allocates resources at
+this point, it may return an &EBUSY; to indicate the returned
+parameters are valid but the required resources are currently not
+available. That may happen for instance when the video and VBI areas
+to capture would overlap, or when the driver supports multiple opens
+and another process already requested VBI capturing or output. Anyway,
+applications must expect other resource allocation points which may
+return <errorcode>EBUSY</errorcode>, at the &VIDIOC-STREAMON; ioctl
+and the first read(), write() and select() call.</para>
+
+      <para>VBI devices must implement both the
+<constant>VIDIOC_G_FMT</constant> and
+<constant>VIDIOC_S_FMT</constant> ioctl, even if
+<constant>VIDIOC_S_FMT</constant> ignores all requests and always
+returns default parameters as <constant>VIDIOC_G_FMT</constant> does.
+<constant>VIDIOC_TRY_FMT</constant> is optional.</para>
+
+      <table pgwide="1" frame="none" id="v4l2-vbi-format">
+       <title>struct <structname>v4l2_vbi_format</structname></title>
+       <tgroup cols="3">
+         &cs-str;
+         <tbody valign="top">
+           <row>
+             <entry>__u32</entry>
+             <entry><structfield>sampling_rate</structfield></entry>
+             <entry>Samples per second, i.&nbsp;e. unit 1 Hz.</entry>
+           </row>
+           <row>
+             <entry>__u32</entry>
+             <entry><structfield>offset</structfield></entry>
+             <entry><para>Horizontal offset of the VBI image,
+relative to the leading edge of the line synchronization pulse and
+counted in samples: The first sample in the VBI image will be located
+<structfield>offset</structfield> /
+<structfield>sampling_rate</structfield> seconds following the leading
+edge. See also <xref linkend="vbi-hsync" />.</para></entry>
+           </row>
+           <row>
+             <entry>__u32</entry>
+             <entry><structfield>samples_per_line</structfield></entry>
+             <entry></entry>
+           </row>
+           <row>
+             <entry>__u32</entry>
+             <entry><structfield>sample_format</structfield></entry>
+             <entry><para>Defines the sample format as in <xref
+linkend="pixfmt" />, a four-character-code.<footnote>
+                   <para>A few devices may be unable to
+sample VBI data at all but can extend the video capture window to the
+VBI region.</para>
+                 </footnote> Usually this is
+<constant>V4L2_PIX_FMT_GREY</constant>, i.&nbsp;e. each sample
+consists of 8 bits with lower values oriented towards the black level.
+Do not assume any other correlation of values with the signal level.
+For example, the MSB does not necessarily indicate if the signal is
+'high' or 'low' because 128 may not be the mean value of the
+signal. Drivers shall not convert the sample format by software.</para></entry>
+           </row>
+           <row>
+             <entry>__u32</entry>
+             <entry><structfield>start</structfield>[2]</entry>
+             <entry>This is the scanning system line number
+associated with the first line of the VBI image, of the first and the
+second field respectively. See <xref linkend="vbi-525" /> and
+<xref linkend="vbi-625" /> for valid values. VBI input drivers can
+return start values 0 if the hardware cannot reliable identify
+scanning lines, VBI acquisition may not require this
+information.</entry>
+           </row>
+           <row>
+             <entry>__u32</entry>
+             <entry><structfield>count</structfield>[2]</entry>
+             <entry>The number of lines in the first and second
+field image, respectively.</entry>
+         </row>
+         <row>
+           <entry spanname="hspan"><para>Drivers should be as
+flexibility as possible. For example, it may be possible to extend or
+move the VBI capture window down to the picture area, implementing a
+'full field mode' to capture data service transmissions embedded in
+the picture.</para><para>An application can set the first or second
+<structfield>count</structfield> value to zero if no data is required
+from the respective field; <structfield>count</structfield>[1] if the
+scanning system is progressive, &ie; not interlaced. The
+corresponding start value shall be ignored by the application and
+driver. Anyway, drivers may not support single field capturing and
+return both count values non-zero.</para><para>Both
+<structfield>count</structfield> values set to zero, or line numbers
+outside the bounds depicted in <xref linkend="vbi-525" /> and <xref
+                   linkend="vbi-625" />, or a field image covering
+lines of two fields, are invalid and shall not be returned by the
+driver.</para><para>To initialize the <structfield>start</structfield>
+and <structfield>count</structfield> fields, applications must first
+determine the current video standard selection. The &v4l2-std-id; or
+the <structfield>framelines</structfield> field of &v4l2-standard; can
+be evaluated for this purpose.</para></entry>
+           </row>
+           <row>
+             <entry>__u32</entry>
+             <entry><structfield>flags</structfield></entry>
+             <entry>See <xref linkend="vbifmt-flags" /> below. Currently
+only drivers set flags, applications must set this field to
+zero.</entry>
+           </row>
+           <row>
+             <entry>__u32</entry>
+             <entry><structfield>reserved</structfield>[2]</entry>
+             <entry>This array is reserved for future extensions.
+Drivers and applications must set it to zero.</entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+
+      <table pgwide="1" frame="none" id="vbifmt-flags">
+       <title>Raw VBI Format Flags</title>
+       <tgroup cols="3">
+         &cs-def;
+         <tbody valign="top">
+           <row>
+             <entry><constant>V4L2_VBI_UNSYNC</constant></entry>
+             <entry>0x0001</entry>
+             <entry><para>This flag indicates hardware which does not
+properly distinguish between fields. Normally the VBI image stores the
+first field (lower scanning line numbers) first in memory. This may be
+a top or bottom field depending on the video standard. When this flag
+is set the first or second field may be stored first, however the
+fields are still in correct temporal order with the older field first
+in memory.<footnote>
+                 <para>Most VBI services transmit on both fields, but
+some have different semantics depending on the field number. These
+cannot be reliable decoded or encoded when
+<constant>V4L2_VBI_UNSYNC</constant> is set.</para>
+               </footnote></para></entry>
+           </row>
+           <row>
+             <entry><constant>V4L2_VBI_INTERLACED</constant></entry>
+             <entry>0x0002</entry>
+             <entry>By default the two field images will be passed
+sequentially; all lines of the first field followed by all lines of
+the second field (compare <xref linkend="field-order" />
+<constant>V4L2_FIELD_SEQ_TB</constant> and
+<constant>V4L2_FIELD_SEQ_BT</constant>, whether the top or bottom
+field is first in memory depends on the video standard). When this
+flag is set, the two fields are interlaced (cf.
+<constant>V4L2_FIELD_INTERLACED</constant>). The first line of the
+first field followed by the first line of the second field, then the
+two second lines, and so on. Such a layout may be necessary when the
+hardware has been programmed to capture or output interlaced video
+images and is unable to separate the fields for VBI capturing at
+the same time. For simplicity setting this flag implies that both
+<structfield>count</structfield> values are equal and non-zero.</entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+
+      <figure id="vbi-hsync">
+       <title>Line synchronization</title>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="vbi_hsync.pdf" format="PS" />
+         </imageobject>
+         <imageobject>
+           <imagedata fileref="vbi_hsync.gif" format="GIF" />
+         </imageobject>
+         <textobject>
+           <phrase>Line synchronization diagram</phrase>
+         </textobject>
+       </mediaobject>
+      </figure>
+
+      <figure id="vbi-525">
+       <title>ITU-R 525 line numbering (M/NTSC and M/PAL)</title>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="vbi_525.pdf" format="PS" />
+         </imageobject>
+         <imageobject>
+           <imagedata fileref="vbi_525.gif" format="GIF" />
+         </imageobject>
+         <textobject>
+           <phrase>NTSC field synchronization diagram</phrase>
+         </textobject>
+         <caption>
+           <para>(1) For the purpose of this specification field 2
+starts in line 264 and not 263.5 because half line capturing is not
+supported.</para>
+         </caption>
+       </mediaobject>
+      </figure>
+
+      <figure id="vbi-625">
+       <title>ITU-R 625 line numbering</title>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="vbi_625.pdf" format="PS" />
+         </imageobject>
+         <imageobject>
+           <imagedata fileref="vbi_625.gif" format="GIF" />
+         </imageobject>
+         <textobject>
+           <phrase>PAL/SECAM field synchronization diagram</phrase>
+         </textobject>
+         <caption>
+           <para>(1) For the purpose of this specification field 2
+starts in line 314 and not 313.5 because half line capturing is not
+supported.</para>
+         </caption>
+       </mediaobject>
+      </figure>
+
+      <para>Remember the VBI image format depends on the selected
+video standard, therefore the application must choose a new standard or
+query the current standard first. Attempts to read or write data ahead
+of format negotiation, or after switching the video standard which may
+invalidate the negotiated VBI parameters, should be refused by the
+driver. A format change during active I/O is not permitted.</para>
+    </section>
+
+    <section>
+      <title>Reading and writing VBI images</title>
+
+      <para>To assure synchronization with the field number and easier
+implementation, the smallest unit of data passed at a time is one
+frame, consisting of two fields of VBI images immediately following in
+memory.</para>
+
+      <para>The total size of a frame computes as follows:</para>
+
+      <programlisting>
+(<structfield>count</structfield>[0] + <structfield>count</structfield>[1]) *
+<structfield>samples_per_line</structfield> * sample size in bytes</programlisting>
+
+      <para>The sample size is most likely always one byte,
+applications must check the <structfield>sample_format</structfield>
+field though, to function properly with other drivers.</para>
+
+      <para>A VBI device may support <link
+      linkend="rw">read/write</link> and/or streaming (<link
+      linkend="mmap">memory mapping</link> or <link
+      linkend="userp">user pointer</link>) I/O. The latter bears the
+possibility of synchronizing video and
+VBI data by using buffer timestamps.</para>
+
+      <para>Remember the &VIDIOC-STREAMON; ioctl and the first read(),
+write() and select() call can be resource allocation points returning
+an &EBUSY; if the required hardware resources are temporarily
+unavailable, for example the device is already in use by another
+process.</para>
+  </section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/dev-rds.xml b/Documentation/DocBook/media/v4l/dev-rds.xml
new file mode 100644 (file)
index 0000000..2427f54
--- /dev/null
@@ -0,0 +1,204 @@
+     <title>RDS Interface</title>
+
+      <para>The Radio Data System transmits supplementary
+information in binary format, for example the station name or travel
+information, on an inaudible audio subcarrier of a radio program. This
+interface is aimed at devices capable of receiving and/or transmitting RDS
+information.</para>
+
+      <para>For more information see the core RDS standard <xref linkend="en50067" />
+and the RBDS standard <xref linkend="nrsc4" />.</para>
+
+      <para>Note that the RBDS standard as is used in the USA is almost identical
+to the RDS standard. Any RDS decoder/encoder can also handle RBDS. Only some of the
+fields have slightly different meanings. See the RBDS standard for more
+information.</para>
+
+      <para>The RBDS standard also specifies support for MMBS (Modified Mobile Search).
+This is a proprietary format which seems to be discontinued. The RDS interface does not
+support this format. Should support for MMBS (or the so-called 'E blocks' in general)
+be needed, then please contact the linux-media mailing list: &v4l-ml;.</para>
+
+  <section>
+    <title>Querying Capabilities</title>
+
+    <para>Devices supporting the RDS capturing API set
+the <constant>V4L2_CAP_RDS_CAPTURE</constant> flag in
+the <structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl.  Any tuner that supports RDS
+will set the <constant>V4L2_TUNER_CAP_RDS</constant> flag in
+the <structfield>capability</structfield> field of &v4l2-tuner;.  If
+the driver only passes RDS blocks without interpreting the data
+the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be
+set, see <link linkend="reading-rds-data">Reading RDS data</link>.
+For future use the
+flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> has also been
+defined. However, a driver for a radio tuner with this capability does
+not yet exist, so if you are planning to write such a driver you
+should discuss this on the linux-media mailing list: &v4l-ml;.</para>
+
+    <para> Whether an RDS signal is present can be detected by looking
+at the <structfield>rxsubchans</structfield> field of &v4l2-tuner;:
+the <constant>V4L2_TUNER_SUB_RDS</constant> will be set if RDS data
+was detected.</para>
+
+    <para>Devices supporting the RDS output API
+set the <constant>V4L2_CAP_RDS_OUTPUT</constant> flag in
+the <structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl.
+Any modulator that supports RDS will set the
+<constant>V4L2_TUNER_CAP_RDS</constant> flag in the <structfield>capability</structfield>
+field of &v4l2-modulator;.
+In order to enable the RDS transmission one must set the <constant>V4L2_TUNER_SUB_RDS</constant>
+bit in the <structfield>txsubchans</structfield> field of &v4l2-modulator;.
+If the driver only passes RDS blocks without interpreting the data
+the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be set. If the
+tuner is capable of handling RDS entities like program identification codes and radio
+text, the flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> should be set,
+see <link linkend="writing-rds-data">Writing RDS data</link> and
+<link linkend="fm-tx-controls">FM Transmitter Control Reference</link>.</para>
+  </section>
+
+  <section  id="reading-rds-data">
+    <title>Reading RDS data</title>
+
+      <para>RDS data can be read from the radio device
+with the &func-read; function. The data is packed in groups of three bytes.</para>
+  </section>
+
+  <section  id="writing-rds-data">
+    <title>Writing RDS data</title>
+
+      <para>RDS data can be written to the radio device
+with the &func-write; function. The data is packed in groups of three bytes,
+as follows:</para>
+  </section>
+
+  <section>
+    <title>RDS datastructures</title>
+    <table frame="none" pgwide="1" id="v4l2-rds-data">
+      <title>struct
+<structname>v4l2_rds_data</structname></title>
+      <tgroup cols="3">
+       <colspec colname="c1" colwidth="1*" />
+       <colspec colname="c2" colwidth="1*" />
+       <colspec colname="c3" colwidth="5*" />
+       <tbody valign="top">
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>lsb</structfield></entry>
+           <entry>Least Significant Byte of RDS Block</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>msb</structfield></entry>
+           <entry>Most Significant Byte of RDS Block</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>block</structfield></entry>
+           <entry>Block description</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+    <table frame="none" pgwide="1" id="v4l2-rds-block">
+      <title>Block description</title>
+      <tgroup cols="2">
+       <colspec colname="c1" colwidth="1*" />
+       <colspec colname="c2" colwidth="5*" />
+       <tbody valign="top">
+         <row>
+           <entry>Bits 0-2</entry>
+           <entry>Block (aka offset) of the received data.</entry>
+         </row>
+         <row>
+           <entry>Bits 3-5</entry>
+           <entry>Deprecated. Currently identical to bits 0-2. Do not use these bits.</entry>
+         </row>
+         <row>
+           <entry>Bit 6</entry>
+           <entry>Corrected bit. Indicates that an error was corrected for this data block.</entry>
+         </row>
+         <row>
+           <entry>Bit 7</entry>
+           <entry>Error bit. Indicates that an uncorrectable error occurred during reception of this block.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-rds-block-codes">
+      <title>Block defines</title>
+      <tgroup cols="4">
+       <colspec colname="c1" colwidth="1*" />
+       <colspec colname="c2" colwidth="1*" />
+       <colspec colname="c3" colwidth="1*" />
+       <colspec colname="c4" colwidth="5*" />
+       <tbody valign="top">
+         <row>
+           <entry>V4L2_RDS_BLOCK_MSK</entry>
+           <entry> </entry>
+           <entry>7</entry>
+           <entry>Mask for bits 0-2 to get the block ID.</entry>
+         </row>
+         <row>
+           <entry>V4L2_RDS_BLOCK_A</entry>
+           <entry> </entry>
+           <entry>0</entry>
+           <entry>Block A.</entry>
+         </row>
+         <row>
+           <entry>V4L2_RDS_BLOCK_B</entry>
+           <entry> </entry>
+           <entry>1</entry>
+           <entry>Block B.</entry>
+         </row>
+         <row>
+           <entry>V4L2_RDS_BLOCK_C</entry>
+           <entry> </entry>
+           <entry>2</entry>
+           <entry>Block C.</entry>
+         </row>
+         <row>
+           <entry>V4L2_RDS_BLOCK_D</entry>
+           <entry> </entry>
+           <entry>3</entry>
+           <entry>Block D.</entry>
+         </row>
+         <row>
+           <entry>V4L2_RDS_BLOCK_C_ALT</entry>
+           <entry> </entry>
+           <entry>4</entry>
+           <entry>Block C'.</entry>
+         </row>
+         <row>
+           <entry>V4L2_RDS_BLOCK_INVALID</entry>
+           <entry>read-only</entry>
+           <entry>7</entry>
+           <entry>An invalid block.</entry>
+         </row>
+         <row>
+           <entry>V4L2_RDS_BLOCK_CORRECTED</entry>
+           <entry>read-only</entry>
+           <entry>0x40</entry>
+           <entry>A bit error was detected but corrected.</entry>
+         </row>
+         <row>
+           <entry>V4L2_RDS_BLOCK_ERROR</entry>
+           <entry>read-only</entry>
+           <entry>0x80</entry>
+           <entry>An uncorrectable error occurred.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </section>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+ -->
diff --git a/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml
new file mode 100644 (file)
index 0000000..69e789f
--- /dev/null
@@ -0,0 +1,708 @@
+  <title>Sliced VBI Data Interface</title>
+
+  <para>VBI stands for Vertical Blanking Interval, a gap in the
+sequence of lines of an analog video signal. During VBI no picture
+information is transmitted, allowing some time while the electron beam
+of a cathode ray tube TV returns to the top of the screen.</para>
+
+  <para>Sliced VBI devices use hardware to demodulate data transmitted
+in the VBI. V4L2 drivers shall <emphasis>not</emphasis> do this by
+software, see also the <link linkend="raw-vbi">raw VBI
+interface</link>. The data is passed as short packets of fixed size,
+covering one scan line each. The number of packets per video frame is
+variable.</para>
+
+  <para>Sliced VBI capture and output devices are accessed through the
+same character special files as raw VBI devices. When a driver
+supports both interfaces, the default function of a
+<filename>/dev/vbi</filename> device is <emphasis>raw</emphasis> VBI
+capturing or output, and the sliced VBI function is only available
+after calling the &VIDIOC-S-FMT; ioctl as defined below. Likewise a
+<filename>/dev/video</filename> device may support the sliced VBI API,
+however the default function here is video capturing or output.
+Different file descriptors must be used to pass raw and sliced VBI
+data simultaneously, if this is supported by the driver.</para>
+
+  <section>
+    <title>Querying Capabilities</title>
+
+    <para>Devices supporting the sliced VBI capturing or output API
+set the <constant>V4L2_CAP_SLICED_VBI_CAPTURE</constant> or
+<constant>V4L2_CAP_SLICED_VBI_OUTPUT</constant> flag respectively, in
+the <structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl. At least one of the
+read/write, streaming or asynchronous <link linkend="io">I/O
+methods</link> must be supported. Sliced VBI devices may have a tuner
+or modulator.</para>
+  </section>
+
+  <section>
+    <title>Supplemental Functions</title>
+
+    <para>Sliced VBI devices shall support <link linkend="video">video
+input or output</link> and <link linkend="tuner">tuner or
+modulator</link> ioctls if they have these capabilities, and they may
+support <link linkend="control">control</link> ioctls. The <link
+linkend="standard">video standard</link> ioctls provide information
+vital to program a sliced VBI device, therefore must be
+supported.</para>
+  </section>
+
+  <section id="sliced-vbi-format-negotitation">
+    <title>Sliced VBI Format Negotiation</title>
+
+    <para>To find out which data services are supported by the
+hardware applications can call the &VIDIOC-G-SLICED-VBI-CAP; ioctl.
+All drivers implementing the sliced VBI interface must support this
+ioctl. The results may differ from those of the &VIDIOC-S-FMT; ioctl
+when the number of VBI lines the hardware can capture or output per
+frame, or the number of services it can identify on a given line are
+limited. For example on PAL line 16 the hardware may be able to look
+for a VPS or Teletext signal, but not both at the same time.</para>
+
+    <para>To determine the currently selected services applications
+set the <structfield>type </structfield> field of &v4l2-format; to
+<constant> V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant> or <constant>
+V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant>, and the &VIDIOC-G-FMT;
+ioctl fills the <structfield>fmt.sliced</structfield> member, a
+&v4l2-sliced-vbi-format;.</para>
+
+    <para>Applications can request different parameters by
+initializing or modifying the <structfield>fmt.sliced</structfield>
+member and calling the &VIDIOC-S-FMT; ioctl with a pointer to the
+<structname>v4l2_format</structname> structure.</para>
+
+    <para>The sliced VBI API is more complicated than the raw VBI API
+because the hardware must be told which VBI service to expect on each
+scan line. Not all services may be supported by the hardware on all
+lines (this is especially true for VBI output where Teletext is often
+unsupported and other services can only be inserted in one specific
+line). In many cases, however, it is sufficient to just set the
+<structfield>service_set</structfield> field to the required services
+and let the driver fill the <structfield>service_lines</structfield>
+array according to hardware capabilities. Only if more precise control
+is needed should the programmer set the
+<structfield>service_lines</structfield> array explicitly.</para>
+
+    <para>The &VIDIOC-S-FMT; ioctl modifies the parameters
+according to hardware capabilities. When the driver allocates
+resources at this point, it may return an &EBUSY; if the required
+resources are temporarily unavailable. Other resource allocation
+points which may return <errorcode>EBUSY</errorcode> can be the
+&VIDIOC-STREAMON; ioctl and the first &func-read;, &func-write; and
+&func-select; call.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-sliced-vbi-format">
+      <title>struct
+<structname>v4l2_sliced_vbi_format</structname></title>
+      <tgroup cols="5">
+       <colspec colname="c1" colwidth="3*" />
+       <colspec colname="c2" colwidth="3*" />
+       <colspec colname="c3" colwidth="2*" />
+       <colspec colname="c4" colwidth="2*" />
+       <colspec colname="c5" colwidth="2*" />
+       <spanspec namest="c3" nameend="c5" spanname="hspan" />
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>service_set</structfield></entry>
+           <entry spanname="hspan"><para>If
+<structfield>service_set</structfield> is non-zero when passed with
+&VIDIOC-S-FMT; or &VIDIOC-TRY-FMT;, the
+<structfield>service_lines</structfield> array will be filled by the
+driver according to the services specified in this field. For example,
+if <structfield>service_set</structfield> is initialized with
+<constant>V4L2_SLICED_TELETEXT_B | V4L2_SLICED_WSS_625</constant>, a
+driver for the cx25840 video decoder sets lines 7-22 of both
+fields<footnote><para>According to <link
+linkend="ets300706">ETS&nbsp;300&nbsp;706</link> lines 6-22 of the
+first field and lines 5-22 of the second field may carry Teletext
+data.</para></footnote> to <constant>V4L2_SLICED_TELETEXT_B</constant>
+and line 23 of the first field to
+<constant>V4L2_SLICED_WSS_625</constant>. If
+<structfield>service_set</structfield> is set to zero, then the values
+of <structfield>service_lines</structfield> will be used instead.
+</para><para>On return the driver sets this field to the union of all
+elements of the returned <structfield>service_lines</structfield>
+array. It may contain less services than requested, perhaps just one,
+if the hardware cannot handle more services simultaneously. It may be
+empty (zero) if none of the requested services are supported by the
+hardware.</para></entry>
+         </row>
+         <row>
+           <entry>__u16</entry>
+           <entry><structfield>service_lines</structfield>[2][24]</entry>
+           <entry spanname="hspan"><para>Applications initialize this
+array with sets of data services the driver shall look for or insert
+on the respective scan line. Subject to hardware capabilities drivers
+return the requested set, a subset, which may be just a single
+service, or an empty set. When the hardware cannot handle multiple
+services on the same line the driver shall choose one. No assumptions
+can be made on which service the driver chooses.</para><para>Data
+services are defined in <xref linkend="vbi-services2" />. Array indices
+map to ITU-R line numbers (see also <xref linkend="vbi-525" /> and <xref
+                 linkend="vbi-625" />) as follows: <!-- No nested
+tables, sigh. --></para></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>Element</entry>
+           <entry>525 line systems</entry>
+           <entry>625 line systems</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><structfield>service_lines</structfield>[0][1]</entry>
+           <entry align="center">1</entry>
+           <entry align="center">1</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><structfield>service_lines</structfield>[0][23]</entry>
+           <entry align="center">23</entry>
+           <entry align="center">23</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><structfield>service_lines</structfield>[1][1]</entry>
+           <entry align="center">264</entry>
+           <entry align="center">314</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><structfield>service_lines</structfield>[1][23]</entry>
+           <entry align="center">286</entry>
+           <entry align="center">336</entry>
+         </row>
+         <!-- End of line numbers table. -->
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry spanname="hspan">Drivers must set
+<structfield>service_lines</structfield>[0][0] and
+<structfield>service_lines</structfield>[1][0] to zero.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>io_size</structfield></entry>
+           <entry spanname="hspan">Maximum number of bytes passed by
+one &func-read; or &func-write; call, and the buffer size in bytes for
+the &VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl. Drivers set this field to
+the size of &v4l2-sliced-vbi-data; times the number of non-zero
+elements in the returned <structfield>service_lines</structfield>
+array (that is the number of lines potentially carrying data).</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[2]</entry>
+           <entry spanname="hspan">This array is reserved for future
+extensions. Applications and drivers must set it to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <!-- See also vidioc-g-sliced-vbi-cap.sgml -->
+    <table frame="none" pgwide="1" id="vbi-services2">
+      <title>Sliced VBI services</title>
+      <tgroup cols="5">
+       <colspec colname="c1" colwidth="2*" />
+       <colspec colname="c2" colwidth="1*" />
+       <colspec colname="c3" colwidth="1*" />
+       <colspec colname="c4" colwidth="2*" />
+       <colspec colname="c5" colwidth="2*" />
+       <spanspec namest="c3" nameend="c5" spanname="rlp" />
+       <thead>
+         <row>
+           <entry>Symbol</entry>
+           <entry>Value</entry>
+           <entry>Reference</entry>
+           <entry>Lines, usually</entry>
+           <entry>Payload</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_SLICED_TELETEXT_B</constant>
+(Teletext System B)</entry>
+           <entry>0x0001</entry>
+           <entry><xref linkend="ets300706" />, <xref linkend="itu653" /></entry>
+           <entry>PAL/SECAM line 7-22, 320-335 (second field 7-22)</entry>
+           <entry>Last 42 of the 45 byte Teletext packet, that is
+without clock run-in and framing code, lsb first transmitted.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SLICED_VPS</constant></entry>
+           <entry>0x0400</entry>
+           <entry><xref linkend="ets300231" /></entry>
+           <entry>PAL line 16</entry>
+           <entry>Byte number 3 to 15 according to Figure 9 of
+ETS&nbsp;300&nbsp;231, lsb first transmitted.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SLICED_CAPTION_525</constant></entry>
+           <entry>0x1000</entry>
+           <entry><xref linkend="eia608" /></entry>
+           <entry>NTSC line 21, 284 (second field 21)</entry>
+           <entry>Two bytes in transmission order, including parity
+bit, lsb first transmitted.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SLICED_WSS_625</constant></entry>
+           <entry>0x4000</entry>
+           <entry><xref linkend="itu1119" />, <xref linkend="en300294" /></entry>
+           <entry>PAL/SECAM line 23</entry>
+           <entry><screen>
+Byte         0                 1
+      msb         lsb  msb           lsb
+ Bit  7 6 5 4 3 2 1 0  x x 13 12 11 10 9
+</screen></entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SLICED_VBI_525</constant></entry>
+           <entry>0x1000</entry>
+           <entry spanname="rlp">Set of services applicable to 525
+line systems.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SLICED_VBI_625</constant></entry>
+           <entry>0x4401</entry>
+           <entry spanname="rlp">Set of services applicable to 625
+line systems.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <para>Drivers may return an &EINVAL; when applications attempt to
+read or write data without prior format negotiation, after switching
+the video standard (which may invalidate the negotiated VBI
+parameters) and after switching the video input (which may change the
+video standard as a side effect). The &VIDIOC-S-FMT; ioctl may return
+an &EBUSY; when applications attempt to change the format while i/o is
+in progress (between a &VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; call,
+and after the first &func-read; or &func-write; call).</para>
+  </section>
+
+  <section>
+    <title>Reading and writing sliced VBI data</title>
+
+    <para>A single &func-read; or &func-write; call must pass all data
+belonging to one video frame. That is an array of
+<structname>v4l2_sliced_vbi_data</structname> structures with one or
+more elements and a total size not exceeding
+<structfield>io_size</structfield> bytes. Likewise in streaming I/O
+mode one buffer of <structfield>io_size</structfield> bytes must
+contain data of one video frame. The <structfield>id</structfield> of
+unused <structname>v4l2_sliced_vbi_data</structname> elements must be
+zero.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-sliced-vbi-data">
+      <title>struct
+<structname>v4l2_sliced_vbi_data</structname></title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry>A flag from <xref linkend="vbi-services" />
+identifying the type of data in this packet. Only a single bit must be
+set. When the <structfield>id</structfield> of a captured packet is
+zero, the packet is empty and the contents of other fields are
+undefined. Applications shall ignore empty packets. When the
+<structfield>id</structfield> of a packet for output is zero the
+contents of the <structfield>data</structfield> field are undefined
+and the driver must no longer insert data on the requested
+<structfield>field</structfield> and
+<structfield>line</structfield>.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>field</structfield></entry>
+           <entry>The video field number this data has been captured
+from, or shall be inserted at. <constant>0</constant> for the first
+field, <constant>1</constant> for the second field.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>line</structfield></entry>
+           <entry>The field (as opposed to frame) line number this
+data has been captured from, or shall be inserted at. See <xref
+           linkend="vbi-525" /> and <xref linkend="vbi-625" /> for valid
+values. Sliced VBI capture devices can set the line number of all
+packets to <constant>0</constant> if the hardware cannot reliably
+identify scan lines. The field number must always be valid.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield></entry>
+           <entry>This field is reserved for future extensions.
+Applications and drivers must set it to zero.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>data</structfield>[48]</entry>
+           <entry>The packet payload. See <xref
+           linkend="vbi-services" /> for the contents and number of
+bytes passed for each data type. The contents of padding bytes at the
+end of this array are undefined, drivers and applications shall ignore
+them.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <para>Packets are always passed in ascending line number order,
+without duplicate line numbers. The &func-write; function and the
+&VIDIOC-QBUF; ioctl must return an &EINVAL; when applications violate
+this rule. They must also return an &EINVAL; when applications pass an
+incorrect field or line number, or a combination of
+<structfield>field</structfield>, <structfield>line</structfield> and
+<structfield>id</structfield> which has not been negotiated with the
+&VIDIOC-G-FMT; or &VIDIOC-S-FMT; ioctl. When the line numbers are
+unknown the driver must pass the packets in transmitted order. The
+driver can insert empty packets with <structfield>id</structfield> set
+to zero anywhere in the packet array.</para>
+
+    <para>To assure synchronization and to distinguish from frame
+dropping, when a captured frame does not carry any of the requested
+data services drivers must pass one or more empty packets. When an
+application fails to pass VBI data in time for output, the driver
+must output the last VPS and WSS packet again, and disable the output
+of Closed Caption and Teletext data, or output data which is ignored
+by Closed Caption and Teletext decoders.</para>
+
+    <para>A sliced VBI device may support <link
+linkend="rw">read/write</link> and/or streaming (<link
+linkend="mmap">memory mapping</link> and/or <link linkend="userp">user
+pointer</link>) I/O. The latter bears the possibility of synchronizing
+video and VBI data by using buffer timestamps.</para>
+
+  </section>
+
+  <section>
+    <title>Sliced VBI Data in MPEG Streams</title>
+
+    <para>If a device can produce an MPEG output stream, it may be
+capable of providing <link
+linkend="sliced-vbi-format-negotitation">negotiated sliced VBI
+services</link> as data embedded in the MPEG stream.  Users or
+applications control this sliced VBI data insertion with the <link
+linkend="v4l2-mpeg-stream-vbi-fmt">V4L2_CID_MPEG_STREAM_VBI_FMT</link>
+control.</para>
+
+    <para>If the driver does not provide the <link
+linkend="v4l2-mpeg-stream-vbi-fmt">V4L2_CID_MPEG_STREAM_VBI_FMT</link>
+control, or only allows that control to be set to <link
+linkend="v4l2-mpeg-stream-vbi-fmt"><constant>
+V4L2_MPEG_STREAM_VBI_FMT_NONE</constant></link>, then the device
+cannot embed sliced VBI data in the MPEG stream.</para>
+
+    <para>The <link linkend="v4l2-mpeg-stream-vbi-fmt">
+V4L2_CID_MPEG_STREAM_VBI_FMT</link> control does not implicitly set
+the device driver to capture nor cease capturing sliced VBI data.  The
+control only indicates to embed sliced VBI data in the MPEG stream, if
+an application has negotiated sliced VBI service be captured.</para>
+
+    <para>It may also be the case that a device can embed sliced VBI
+data in only certain types of MPEG streams: for example in an MPEG-2
+PS but not an MPEG-2 TS.  In this situation, if sliced VBI data
+insertion is requested, the sliced VBI data will be embedded in MPEG
+stream types when supported, and silently omitted from MPEG stream
+types where sliced VBI data insertion is not supported by the device.
+</para>
+
+    <para>The following subsections specify the format of the
+embedded sliced VBI data.</para>
+
+  <section>
+    <title>MPEG Stream Embedded, Sliced VBI Data Format: NONE</title>
+    <para>The <link linkend="v4l2-mpeg-stream-vbi-fmt"><constant>
+V4L2_MPEG_STREAM_VBI_FMT_NONE</constant></link> embedded sliced VBI
+format shall be interpreted by drivers as a control to cease
+embedding sliced VBI data in MPEG streams.  Neither the device nor
+driver shall insert "empty" embedded sliced VBI data packets in the
+MPEG stream when this format is set.  No MPEG stream data structures
+are specified for this format.</para>
+  </section>
+
+  <section>
+    <title>MPEG Stream Embedded, Sliced VBI Data Format: IVTV</title>
+    <para>The <link linkend="v4l2-mpeg-stream-vbi-fmt"><constant>
+V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant></link> embedded sliced VBI
+format, when supported, indicates to the driver to embed up to 36
+lines of sliced VBI data per frame in an MPEG-2 <emphasis>Private
+Stream 1 PES</emphasis> packet encapsulated in an MPEG-2 <emphasis>
+Program Pack</emphasis> in the MPEG stream.</para>
+
+    <para><emphasis>Historical context</emphasis>: This format
+specification originates from a custom, embedded, sliced VBI data
+format used by the <filename>ivtv</filename> driver.  This format
+has already been informally specified in the kernel sources in the
+file <filename>Documentation/video4linux/cx2341x/README.vbi</filename>
+.  The maximum size of the payload and other aspects of this format
+are driven by the CX23415 MPEG decoder's capabilities and limitations
+with respect to extracting, decoding, and displaying sliced VBI data
+embedded within an MPEG stream.</para>
+
+    <para>This format's use is <emphasis>not</emphasis> exclusive to
+the <filename>ivtv</filename> driver <emphasis>nor</emphasis>
+exclusive to CX2341x devices, as the sliced VBI data packet insertion
+into the MPEG stream is implemented in driver software.  At least the
+<filename>cx18</filename> driver provides sliced VBI data insertion
+into an MPEG-2 PS in this format as well.</para>
+
+    <para>The following definitions specify the payload of the
+MPEG-2 <emphasis>Private Stream 1 PES</emphasis> packets that contain
+sliced VBI data when <link linkend="v4l2-mpeg-stream-vbi-fmt">
+<constant>V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant></link> is set.
+(The MPEG-2 <emphasis>Private Stream 1 PES</emphasis> packet header
+and encapsulating MPEG-2 <emphasis>Program Pack</emphasis> header are
+not detailed here.  Please refer to the MPEG-2 specifications for
+details on those packet headers.)</para>
+
+    <para>The payload of the MPEG-2 <emphasis>Private Stream 1 PES
+</emphasis> packets that contain sliced VBI data is specified by
+&v4l2-mpeg-vbi-fmt-ivtv;.  The payload is variable
+length, depending on the actual number of lines of sliced VBI data
+present in a video frame.  The payload may be padded at the end with
+unspecified fill bytes to align the end of the payload to a 4-byte
+boundary.  The payload shall never exceed 1552 bytes (2 fields with
+18 lines/field with 43 bytes of data/line and a 4 byte magic number).
+</para>
+
+    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-fmt-ivtv">
+      <title>struct <structname>v4l2_mpeg_vbi_fmt_ivtv</structname>
+      </title>
+      <tgroup cols="4">
+       &cs-ustr;
+       <tbody valign="top">
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>magic</structfield>[4]</entry>
+           <entry></entry>
+           <entry>A "magic" constant from <xref
+           linkend="v4l2-mpeg-vbi-fmt-ivtv-magic" /> that indicates
+this is a valid sliced VBI data payload and also indicates which
+member of the anonymous union, <structfield>itv0</structfield> or
+<structfield>ITV0</structfield>, to use for the payload data.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry>(anonymous)</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0">
+             <structname>v4l2_mpeg_vbi_itv0</structname></link>
+           </entry>
+           <entry><structfield>itv0</structfield></entry>
+           <entry>The primary form of the sliced VBI data payload
+that contains anywhere from 1 to 35 lines of sliced VBI data.
+Line masks are provided in this form of the payload indicating
+which VBI lines are provided.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0-1">
+             <structname>v4l2_mpeg_vbi_ITV0</structname></link>
+           </entry>
+           <entry><structfield>ITV0</structfield></entry>
+           <entry>An alternate form of the sliced VBI data payload
+used when 36 lines of sliced VBI data are present.  No line masks are
+provided in this form of the payload; all valid line mask bits are
+implcitly set.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-fmt-ivtv-magic">
+      <title>Magic Constants for &v4l2-mpeg-vbi-fmt-ivtv;
+       <structfield>magic</structfield> field</title>
+      <tgroup cols="3">
+       &cs-def;
+       <thead>
+         <row>
+           <entry align="left">Defined Symbol</entry>
+           <entry align="left">Value</entry>
+           <entry align="left">Description</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_MPEG_VBI_IVTV_MAGIC0</constant>
+           </entry>
+           <entry>"itv0"</entry>
+           <entry>Indicates the <structfield>itv0</structfield>
+member of the union in &v4l2-mpeg-vbi-fmt-ivtv; is valid.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_MPEG_VBI_IVTV_MAGIC1</constant>
+           </entry>
+           <entry>"ITV0"</entry>
+           <entry>Indicates the <structfield>ITV0</structfield>
+member of the union in &v4l2-mpeg-vbi-fmt-ivtv; is valid and
+that 36 lines of sliced VBI data are present.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-itv0">
+      <title>struct <structname>v4l2_mpeg_vbi_itv0</structname>
+      </title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__le32</entry>
+           <entry><structfield>linemask</structfield>[2]</entry>
+           <entry><para>Bitmasks indicating the VBI service lines
+present.  These <structfield>linemask</structfield> values are stored
+in little endian byte order in the MPEG stream.  Some reference
+<structfield>linemask</structfield> bit positions with their
+corresponding VBI line number and video field are given below.
+b<subscript>0</subscript> indicates the least significant bit of a
+<structfield>linemask</structfield> value:<screen>
+<structfield>linemask</structfield>[0] b<subscript>0</subscript>:              line  6         first field
+<structfield>linemask</structfield>[0] b<subscript>17</subscript>:             line 23         first field
+<structfield>linemask</structfield>[0] b<subscript>18</subscript>:             line  6         second field
+<structfield>linemask</structfield>[0] b<subscript>31</subscript>:             line 19         second field
+<structfield>linemask</structfield>[1] b<subscript>0</subscript>:              line 20         second field
+<structfield>linemask</structfield>[1] b<subscript>3</subscript>:              line 23         second field
+<structfield>linemask</structfield>[1] b<subscript>4</subscript>-b<subscript>31</subscript>:   unused and set to 0</screen></para></entry>
+         </row>
+         <row>
+           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0-line">
+             <structname>v4l2_mpeg_vbi_itv0_line</structname></link>
+           </entry>
+           <entry><structfield>line</structfield>[35]</entry>
+           <entry>This is a variable length array that holds from 1
+to 35 lines of sliced VBI data.  The sliced VBI data lines present
+correspond to the bits set in the <structfield>linemask</structfield>
+array, starting from b<subscript>0</subscript> of <structfield>
+linemask</structfield>[0] up through b<subscript>31</subscript> of
+<structfield>linemask</structfield>[0], and from b<subscript>0
+</subscript> of <structfield>linemask</structfield>[1] up through b
+<subscript>3</subscript> of <structfield>linemask</structfield>[1].
+<structfield>line</structfield>[0] corresponds to the first bit
+found set in the <structfield>linemask</structfield> array,
+<structfield>line</structfield>[1] corresponds to the second bit
+found set in the <structfield>linemask</structfield> array, etc.
+If no <structfield>linemask</structfield> array bits are set, then
+<structfield>line</structfield>[0] may contain one line of
+unspecified data that should be ignored by applications.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-itv0-1">
+      <title>struct <structname>v4l2_mpeg_vbi_ITV0</structname>
+      </title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0-line">
+             <structname>v4l2_mpeg_vbi_itv0_line</structname></link>
+           </entry>
+           <entry><structfield>line</structfield>[36]</entry>
+           <entry>A fixed length array of 36 lines of sliced VBI
+data.  <structfield>line</structfield>[0] through <structfield>line
+</structfield>[17] correspond to lines 6 through 23 of the
+first field.  <structfield>line</structfield>[18] through
+<structfield>line</structfield>[35] corresponds to lines 6
+through 23 of the second field.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-itv0-line">
+      <title>struct <structname>v4l2_mpeg_vbi_itv0_line</structname>
+      </title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry>A line identifier value from
+<xref linkend="ITV0-Line-Identifier-Constants" /> that indicates
+the type of sliced VBI data stored on this line.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>data</structfield>[42]</entry>
+           <entry>The sliced VBI data for the line.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="ITV0-Line-Identifier-Constants">
+      <title>Line Identifiers for struct <link
+      linkend="v4l2-mpeg-vbi-itv0-line"><structname>
+v4l2_mpeg_vbi_itv0_line</structname></link> <structfield>id
+</structfield> field</title>
+      <tgroup cols="3">
+       &cs-def;
+       <thead>
+         <row>
+           <entry align="left">Defined Symbol</entry>
+           <entry align="left">Value</entry>
+           <entry align="left">Description</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_MPEG_VBI_IVTV_TELETEXT_B</constant>
+           </entry>
+           <entry>1</entry>
+           <entry>Refer to <link linkend="vbi-services2">
+Sliced VBI services</link> for a description of the line payload.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_MPEG_VBI_IVTV_CAPTION_525</constant>
+           </entry>
+           <entry>4</entry>
+           <entry>Refer to <link linkend="vbi-services2">
+Sliced VBI services</link> for a description of the line payload.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_MPEG_VBI_IVTV_WSS_625</constant>
+           </entry>
+           <entry>5</entry>
+           <entry>Refer to <link linkend="vbi-services2">
+Sliced VBI services</link> for a description of the line payload.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_MPEG_VBI_IVTV_VPS</constant>
+           </entry>
+           <entry>7</entry>
+           <entry>Refer to <link linkend="vbi-services2">
+Sliced VBI services</link> for a description of the line payload.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </section>
+  </section>
+
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+ -->
diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml
new file mode 100644 (file)
index 0000000..05c8fef
--- /dev/null
@@ -0,0 +1,313 @@
+  <title>Sub-device Interface</title>
+
+  <note>
+    <title>Experimental</title>
+    <para>This is an <link linkend="experimental">experimental</link>
+    interface and may change in the future.</para>
+  </note>
+
+  <para>The complex nature of V4L2 devices, where hardware is often made of
+  several integrated circuits that need to interact with each other in a
+  controlled way, leads to complex V4L2 drivers. The drivers usually reflect
+  the hardware model in software, and model the different hardware components
+  as software blocks called sub-devices.</para>
+
+  <para>V4L2 sub-devices are usually kernel-only objects. If the V4L2 driver
+  implements the media device API, they will automatically inherit from media
+  entities. Applications will be able to enumerate the sub-devices and discover
+  the hardware topology using the media entities, pads and links enumeration
+  API.</para>
+
+  <para>In addition to make sub-devices discoverable, drivers can also choose
+  to make them directly configurable by applications. When both the sub-device
+  driver and the V4L2 device driver support this, sub-devices will feature a
+  character device node on which ioctls can be called to
+  <itemizedlist>
+    <listitem><para>query, read and write sub-devices controls</para></listitem>
+    <listitem><para>subscribe and unsubscribe to events and retrieve them</para></listitem>
+    <listitem><para>negotiate image formats on individual pads</para></listitem>
+  </itemizedlist>
+  </para>
+
+  <para>Sub-device character device nodes, conventionally named
+  <filename>/dev/v4l-subdev*</filename>, use major number 81.</para>
+
+  <section>
+    <title>Controls</title>
+    <para>Most V4L2 controls are implemented by sub-device hardware. Drivers
+    usually merge all controls and expose them through video device nodes.
+    Applications can control all sub-devices through a single interface.</para>
+
+    <para>Complex devices sometimes implement the same control in different
+    pieces of hardware. This situation is common in embedded platforms, where
+    both sensors and image processing hardware implement identical functions,
+    such as contrast adjustment, white balance or faulty pixels correction. As
+    the V4L2 controls API doesn't support several identical controls in a single
+    device, all but one of the identical controls are hidden.</para>
+
+    <para>Applications can access those hidden controls through the sub-device
+    node with the V4L2 control API described in <xref linkend="control" />. The
+    ioctls behave identically as when issued on V4L2 device nodes, with the
+    exception that they deal only with controls implemented in the sub-device.
+    </para>
+
+    <para>Depending on the driver, those controls might also be exposed through
+    one (or several) V4L2 device nodes.</para>
+  </section>
+
+  <section>
+    <title>Events</title>
+    <para>V4L2 sub-devices can notify applications of events as described in
+    <xref linkend="event" />. The API behaves identically as when used on V4L2
+    device nodes, with the exception that it only deals with events generated by
+    the sub-device. Depending on the driver, those events might also be reported
+    on one (or several) V4L2 device nodes.</para>
+  </section>
+
+  <section id="pad-level-formats">
+    <title>Pad-level Formats</title>
+
+    <warning><para>Pad-level formats are only applicable to very complex device that
+    need to expose low-level format configuration to user space. Generic V4L2
+    applications do <emphasis>not</emphasis> need to use the API described in
+    this section.</para></warning>
+
+    <note><para>For the purpose of this section, the term
+    <wordasword>format</wordasword> means the combination of media bus data
+    format, frame width and frame height.</para></note>
+
+    <para>Image formats are typically negotiated on video capture and output
+    devices using the <link linkend="crop">cropping and scaling</link> ioctls.
+    The driver is responsible for configuring every block in the video pipeline
+    according to the requested format at the pipeline input and/or
+    output.</para>
+
+    <para>For complex devices, such as often found in embedded systems,
+    identical image sizes at the output of a pipeline can be achieved using
+    different hardware configurations. One such example is shown on
+    <xref linkend="pipeline-scaling" />, where
+    image scaling can be performed on both the video sensor and the host image
+    processing hardware.</para>
+
+    <figure id="pipeline-scaling">
+      <title>Image Format Negotiation on Pipelines</title>
+      <mediaobject>
+       <imageobject>
+         <imagedata fileref="pipeline.pdf" format="PS" />
+       </imageobject>
+       <imageobject>
+         <imagedata fileref="pipeline.png" format="PNG" />
+       </imageobject>
+       <textobject>
+         <phrase>High quality and high speed pipeline configuration</phrase>
+       </textobject>
+      </mediaobject>
+    </figure>
+
+    <para>The sensor scaler is usually of less quality than the host scaler, but
+    scaling on the sensor is required to achieve higher frame rates. Depending
+    on the use case (quality vs. speed), the pipeline must be configured
+    differently. Applications need to configure the formats at every point in
+    the pipeline explicitly.</para>
+
+    <para>Drivers that implement the <link linkend="media-controller-intro">media
+    API</link> can expose pad-level image format configuration to applications.
+    When they do, applications can use the &VIDIOC-SUBDEV-G-FMT; and
+    &VIDIOC-SUBDEV-S-FMT; ioctls. to negotiate formats on a per-pad basis.</para>
+
+    <para>Applications are responsible for configuring coherent parameters on
+    the whole pipeline and making sure that connected pads have compatible
+    formats. The pipeline is checked for formats mismatch at &VIDIOC-STREAMON;
+    time, and an &EPIPE; is then returned if the configuration is
+    invalid.</para>
+
+    <para>Pad-level image format configuration support can be tested by calling
+    the &VIDIOC-SUBDEV-G-FMT; ioctl on pad 0. If the driver returns an &EINVAL;
+    pad-level format configuration is not supported by the sub-device.</para>
+
+    <section>
+      <title>Format Negotiation</title>
+
+      <para>Acceptable formats on pads can (and usually do) depend on a number
+      of external parameters, such as formats on other pads, active links, or
+      even controls. Finding a combination of formats on all pads in a video
+      pipeline, acceptable to both application and driver, can't rely on formats
+      enumeration only. A format negotiation mechanism is required.</para>
+
+      <para>Central to the format negotiation mechanism are the get/set format
+      operations. When called with the <structfield>which</structfield> argument
+      set to <constant>V4L2_SUBDEV_FORMAT_TRY</constant>, the
+      &VIDIOC-SUBDEV-G-FMT; and &VIDIOC-SUBDEV-S-FMT; ioctls operate on a set of
+      formats parameters that are not connected to the hardware configuration.
+      Modifying those 'try' formats leaves the device state untouched (this
+      applies to both the software state stored in the driver and the hardware
+      state stored in the device itself).</para>
+
+      <para>While not kept as part of the device state, try formats are stored
+      in the sub-device file handles. A &VIDIOC-SUBDEV-G-FMT; call will return
+      the last try format set <emphasis>on the same sub-device file
+      handle</emphasis>. Several applications querying the same sub-device at
+      the same time will thus not interact with each other.</para>
+
+      <para>To find out whether a particular format is supported by the device,
+      applications use the &VIDIOC-SUBDEV-S-FMT; ioctl. Drivers verify and, if
+      needed, change the requested <structfield>format</structfield> based on
+      device requirements and return the possibly modified value. Applications
+      can then choose to try a different format or accept the returned value and
+      continue.</para>
+
+      <para>Formats returned by the driver during a negotiation iteration are
+      guaranteed to be supported by the device. In particular, drivers guarantee
+      that a returned format will not be further changed if passed to an
+      &VIDIOC-SUBDEV-S-FMT; call as-is (as long as external parameters, such as
+      formats on other pads or links' configuration are not changed).</para>
+
+      <para>Drivers automatically propagate formats inside sub-devices. When a
+      try or active format is set on a pad, corresponding formats on other pads
+      of the same sub-device can be modified by the driver. Drivers are free to
+      modify formats as required by the device. However, they should comply with
+      the following rules when possible:
+      <itemizedlist>
+        <listitem><para>Formats should be propagated from sink pads to source pads.
+       Modifying a format on a source pad should not modify the format on any
+       sink pad.</para></listitem>
+        <listitem><para>Sub-devices that scale frames using variable scaling factors
+       should reset the scale factors to default values when sink pads formats
+       are modified. If the 1:1 scaling ratio is supported, this means that
+       source pads formats should be reset to the sink pads formats.</para></listitem>
+      </itemizedlist>
+      </para>
+
+      <para>Formats are not propagated across links, as that would involve
+      propagating them from one sub-device file handle to another. Applications
+      must then take care to configure both ends of every link explicitly with
+      compatible formats. Identical formats on the two ends of a link are
+      guaranteed to be compatible. Drivers are free to accept different formats
+      matching device requirements as being compatible.</para>
+
+      <para><xref linkend="sample-pipeline-config" />
+      shows a sample configuration sequence for the pipeline described in
+      <xref linkend="pipeline-scaling" /> (table
+      columns list entity names and pad numbers).</para>
+
+      <table pgwide="0" frame="none" id="sample-pipeline-config">
+       <title>Sample Pipeline Configuration</title>
+       <tgroup cols="3">
+         <colspec colname="what"/>
+         <colspec colname="sensor-0" />
+         <colspec colname="frontend-0" />
+         <colspec colname="frontend-1" />
+         <colspec colname="scaler-0" />
+         <colspec colname="scaler-1" />
+         <thead>
+           <row>
+             <entry></entry>
+             <entry>Sensor/0</entry>
+             <entry>Frontend/0</entry>
+             <entry>Frontend/1</entry>
+             <entry>Scaler/0</entry>
+             <entry>Scaler/1</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row>
+             <entry>Initial state</entry>
+             <entry>2048x1536</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+           </row>
+           <row>
+             <entry>Configure frontend input</entry>
+             <entry>2048x1536</entry>
+             <entry><emphasis>2048x1536</emphasis></entry>
+             <entry><emphasis>2046x1534</emphasis></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+           </row>
+           <row>
+             <entry>Configure scaler input</entry>
+             <entry>2048x1536</entry>
+             <entry>2048x1536</entry>
+             <entry>2046x1534</entry>
+             <entry><emphasis>2046x1534</emphasis></entry>
+             <entry><emphasis>2046x1534</emphasis></entry>
+           </row>
+           <row>
+             <entry>Configure scaler output</entry>
+             <entry>2048x1536</entry>
+             <entry>2048x1536</entry>
+             <entry>2046x1534</entry>
+             <entry>2046x1534</entry>
+             <entry><emphasis>1280x960</emphasis></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+
+      <para>
+      <orderedlist>
+       <listitem><para>Initial state. The sensor output is set to its native 3MP
+       resolution. Resolutions on the host frontend and scaler input and output
+       pads are undefined.</para></listitem>
+       <listitem><para>The application configures the frontend input pad resolution to
+       2048x1536. The driver propagates the format to the frontend output pad.
+       Note that the propagated output format can be different, as in this case,
+       than the input format, as the hardware might need to crop pixels (for
+       instance when converting a Bayer filter pattern to RGB or YUV).</para></listitem>
+       <listitem><para>The application configures the scaler input pad resolution to
+       2046x1534 to match the frontend output resolution. The driver propagates
+       the format to the scaler output pad.</para></listitem>
+       <listitem><para>The application configures the scaler output pad resolution to
+       1280x960.</para></listitem>
+      </orderedlist>
+      </para>
+
+      <para>When satisfied with the try results, applications can set the active
+      formats by setting the <structfield>which</structfield> argument to
+      <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. Active formats are changed
+      exactly as try formats by drivers. To avoid modifying the hardware state
+      during format negotiation, applications should negotiate try formats first
+      and then modify the active settings using the try formats returned during
+      the last negotiation iteration. This guarantees that the active format
+      will be applied as-is by the driver without being modified.
+      </para>
+    </section>
+
+    <section>
+      <title>Cropping and scaling</title>
+
+      <para>Many sub-devices support cropping frames on their input or output
+      pads (or possible even on both). Cropping is used to select the area of
+      interest in an image, typically on a video sensor or video decoder. It can
+      also be used as part of digital zoom implementations to select the area of
+      the image that will be scaled up.</para>
+
+      <para>Crop settings are defined by a crop rectangle and represented in a
+      &v4l2-rect; by the coordinates of the top left corner and the rectangle
+      size. Both the coordinates and sizes are expressed in pixels.</para>
+
+      <para>The crop rectangle is retrieved and set using the
+      &VIDIOC-SUBDEV-G-CROP; and &VIDIOC-SUBDEV-S-CROP; ioctls. Like for pad
+      formats, drivers store try and active crop rectangles. The format
+      negotiation mechanism applies to crop settings as well.</para>
+
+      <para>On input pads, cropping is applied relatively to the current pad
+      format. The pad format represents the image size as received by the
+      sub-device from the previous block in the pipeline, and the crop rectangle
+      represents the sub-image that will be transmitted further inside the
+      sub-device for processing. The crop rectangle be entirely containted
+      inside the input image size.</para>
+
+      <para>Input crop rectangle are reset to their default value when the input
+      image format is modified. Drivers should use the input image size as the
+      crop rectangle default value, but hardware requirements may prevent this.
+      </para>
+
+      <para>Cropping behaviour on output pads is not defined.</para>
+
+    </section>
+  </section>
+
+  &sub-subdev-formats;
diff --git a/Documentation/DocBook/media/v4l/dev-teletext.xml b/Documentation/DocBook/media/v4l/dev-teletext.xml
new file mode 100644 (file)
index 0000000..414b1cf
--- /dev/null
@@ -0,0 +1,37 @@
+  <title>Teletext Interface</title>
+
+  <para>This interface was aimed at devices receiving and demodulating
+Teletext data [<xref linkend="ets300706" />, <xref linkend="itu653" />], evaluating the
+Teletext packages and storing formatted pages in cache memory. Such
+devices are usually implemented as microcontrollers with serial
+interface (I<superscript>2</superscript>C) and could be found on old
+TV cards, dedicated Teletext decoding cards and home-brew devices
+connected to the PC parallel port.</para>
+
+  <para>The Teletext API was designed by Martin Buck. It was defined in
+the kernel header file <filename>linux/videotext.h</filename>, the
+specification is available from <ulink url="ftp://ftp.gwdg.de/pub/linux/misc/videotext/">
+ftp://ftp.gwdg.de/pub/linux/misc/videotext/</ulink>. (Videotext is the name of
+the German public television Teletext service.)</para>
+
+  <para>Eventually the Teletext API was integrated into the V4L API
+with character device file names <filename>/dev/vtx0</filename> to
+<filename>/dev/vtx31</filename>, device major number 81, minor numbers
+192 to 223.</para>
+
+  <para>However, teletext decoders were quickly replaced by more
+generic VBI demodulators and those dedicated teletext decoders no longer exist.
+For many years the vtx devices were still around, even though nobody used
+them. So the decision was made to finally remove support for the Teletext API in
+kernel 2.6.37.</para>
+
+  <para>Modern devices all use the <link linkend="raw-vbi">raw</link> or
+<link linkend="sliced">sliced</link> VBI API.</para>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/driver.xml b/Documentation/DocBook/media/v4l/driver.xml
new file mode 100644 (file)
index 0000000..1f7eea5
--- /dev/null
@@ -0,0 +1,208 @@
+  <title>V4L2 Driver Programming</title>
+
+  <!-- This part defines the interface between the "videodev"
+    module and individual drivers. -->
+
+  <para>to do</para>
+<!--
+  <para>V4L2 is a two-layer driver system. The top layer is the "videodev"
+kernel module. When videodev initializes it registers as character device
+with major number 81, and it registers a set of file operations. All V4L2
+drivers are really clients of videodev, which calls V4L2 drivers through
+driver method functions. V4L2 drivers are also written as kernel modules.
+After probing the hardware they register one or more devices with
+videodev.</para>
+
+  <section id="driver-modules">
+    <title>Driver Modules</title>
+
+    <para>V4L2 driver modules must have an initialization function which is
+called after the module was loaded into kernel, an exit function whis is
+called before the module is removed.  When the driver is compiled into the
+kernel these functions called at system boot and shutdown time.</para>
+
+    <informalexample>
+      <programlisting>
+#include &lt;linux/module.h&gt;
+
+/* Export information about this module. For details and other useful
+   macros see <filename>linux/module.h</filename>. */
+MODULE_DESCRIPTION("my - driver for my hardware");
+MODULE_AUTHOR("Your name here");
+MODULE_LICENSE("GPL");
+
+static void
+my_module_exit (void)
+{
+       /* Free all resources allocated by my_module_init(). */
+}
+
+static int
+my_module_init (void)
+{
+       /* Bind the driver to the supported hardware, see
+          <link linkend="driver-pci"> and
+          <link linkend="driver-usb"> for examples. */
+
+       return 0; /* a negative value on error, 0 on success. */
+}
+
+/* Export module functions. */
+module_init (my_module_init);
+module_exit (my_module_exit);
+</programlisting>
+    </informalexample>
+
+    <para>Users can add parameters when kernel modules are inserted:</para>
+
+    <informalexample>
+      <programlisting>
+include &lt;linux/moduleparam.h&gt;
+
+static int my_option = 123;
+static int my_option_array[47];
+
+/* Export the symbol, an int, with access permissions 0664.
+   See <filename>linux/moduleparam.h</filename> for other types. */
+module_param (my_option, int, 0644);
+module_param_array (my_option_array, int, NULL, 0644);
+
+MODULE_PARM_DESC (my_option, "Does magic things, default 123");
+</programlisting>
+    </informalexample>
+
+    <para>One parameter should be supported by all V4L2 drivers, the minor
+number of the device it will register. Purpose is to predictably link V4L2
+drivers to device nodes if more than one video device is installed. Use the
+name of the device node followed by a "_nr" suffix, for example "video_nr"
+for <filename>/dev/video</filename>.</para>
+
+    <informalexample>
+      <programlisting>
+/* Minor number of the device, -1 to allocate the first unused. */
+static int video_nr = -1;
+
+module_param (video_nr, int, 0444);
+</programlisting>
+    </informalexample>
+  </section>
+
+  <section id="driver-pci">
+    <title>PCI Devices</title>
+
+    <para>PCI devices are initialized like this:</para>
+
+    <informalexample>
+      <programlisting>
+typedef struct {
+       /* State of one physical device. */
+} my_device;
+
+static int
+my_resume               (struct pci_dev *               pci_dev)
+{
+       /* Restore the suspended device to working state. */
+}
+
+static int
+my_suspend              (struct pci_dev *               pci_dev,
+                        pm_message_t                   state)
+{
+       /* This function is called before the system goes to sleep.
+          Stop all DMAs and disable interrupts, then put the device
+          into a low power state. For details see the kernel
+          sources under <filename>Documentation/power</filename>. */
+
+       return 0; /* a negative value on error, 0 on success. */
+}
+
+static void __devexit
+my_remove               (struct pci_dev *               pci_dev)
+{
+       my_device *my = pci_get_drvdata (pci_dev);
+
+       /* Describe me. */
+}
+
+static int __devinit
+my_probe                (struct pci_dev *               pci_dev,
+                        const struct pci_device_id *   pci_id)
+{
+       my_device *my;
+
+       /* Describe me. */
+
+       /* You can allocate per-device data here and store a pointer
+          to it in the pci_dev structure. */
+       my = ...;
+       pci_set_drvdata (pci_dev, my);
+
+       return 0; /* a negative value on error, 0 on success. */
+}
+
+/* A list of supported PCI devices. */
+static struct pci_device_id
+my_pci_device_ids [] = {
+       { PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { 0 } /* end of list */
+};
+
+/* Load our module if supported PCI devices are installed. */
+MODULE_DEVICE_TABLE (pci, my_pci_device_ids);
+
+static struct pci_driver
+my_pci_driver = {
+       .name     = "my",
+       .id_table = my_pci_device_ids,
+
+       .probe    = my_probe,
+       .remove   = __devexit_p (my_remove),
+
+       /* Power management functions. */
+       .suspend  = my_suspend,
+       .resume   = my_resume,
+};
+
+static void
+my_module_exit          (void)
+{
+       pci_unregister_driver (&my_pci_driver);
+}
+
+static int
+my_module_init          (void)
+{
+       return pci_register_driver (&my_pci_driver);
+}
+</programlisting>
+    </informalexample>
+  </section>
+
+  <section id="driver-usb">
+    <title>USB Devices</title>
+    <para>to do</para>
+  </section>
+  <section id="driver-registering">
+    <title>Registering V4L2 Drivers</title>
+
+    <para>After a V4L2 driver probed the hardware it registers one or more
+devices with the videodev module.</para>
+  </section>
+  <section id="driver-file-ops">
+    <title>File Operations</title>
+    <para>to do</para>
+  </section>
+  <section id="driver-internal-api">
+    <title>Internal API</title>
+    <para>to do</para>
+  </section>
+-->
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/fdl-appendix.xml b/Documentation/DocBook/media/v4l/fdl-appendix.xml
new file mode 100644 (file)
index 0000000..ae22394
--- /dev/null
@@ -0,0 +1,671 @@
+<!--
+     The GNU Free Documentation License 1.1 in DocBook
+     Markup by Eric Baudais <baudais@okstate.edu>
+     Maintained by the GNOME Documentation Project
+     http://live.gnome.org/DocumentationProject
+     Version: 1.0.1
+     Last Modified: Nov 16, 2000
+-->
+
+<appendix id="fdl">
+  <appendixinfo>
+    <releaseinfo>
+      Version 1.1, March 2000
+    </releaseinfo>
+    <copyright>
+      <year>2000</year><holder>Free Software Foundation, Inc.</holder>
+    </copyright>
+    <legalnotice id="fdl-legalnotice">
+      <para>
+       <address>Free Software Foundation, Inc. <street>59 Temple Place,
+       Suite 330</street>, <city>Boston</city>, <state>MA</state>
+       <postcode>02111-1307</postcode>  <country>USA</country></address>
+       Everyone is permitted to copy and distribute verbatim copies of this
+       license document, but changing it is not allowed.
+      </para>
+    </legalnotice>
+  </appendixinfo>
+  <title>GNU Free Documentation License</title>
+
+  <sect1 id="fdl-preamble">
+    <title>0. PREAMBLE</title>
+    <para>
+      The purpose of this License is to make a manual, textbook, or
+      other written document <quote>free</quote> in the sense of
+      freedom: to assure everyone the effective freedom to copy and
+      redistribute it, with or without modifying it, either
+      commercially or noncommercially. Secondarily, this License
+      preserves for the author and publisher a way to get credit for
+      their work, while not being considered responsible for
+      modifications made by others.
+    </para>
+
+    <para>
+      This License is a kind of <quote>copyleft</quote>, which means
+      that derivative works of the document must themselves be free in
+      the same sense. It complements the GNU General Public License,
+      which is a copyleft license designed for free software.
+    </para>
+
+    <para>
+      We have designed this License in order to use it for manuals for
+      free software, because free software needs free documentation: a
+      free program should come with manuals providing the same
+      freedoms that the software does. But this License is not limited
+      to software manuals; it can be used for any textual work,
+      regardless of subject matter or whether it is published as a
+      printed book. We recommend this License principally for works
+      whose purpose is instruction or reference.
+    </para>
+  </sect1>
+  <sect1 id="fdl-section1">
+    <title>1. APPLICABILITY AND DEFINITIONS</title>
+    <para id="fdl-document">
+      This License applies to any manual or other work that contains a
+      notice placed by the copyright holder saying it can be
+      distributed under the terms of this License. The
+      <quote>Document</quote>, below, refers to any such manual or
+      work. Any member of the public is a licensee, and is addressed
+      as <quote>you</quote>.
+    </para>
+
+    <para id="fdl-modified">
+      A <quote>Modified Version</quote> of the Document means any work
+      containing the Document or a portion of it, either copied
+      verbatim, or with modifications and/or translated into another
+      language.
+    </para>
+
+    <para id="fdl-secondary">
+      A <quote>Secondary Section</quote> is a named appendix or a
+      front-matter section of the <link
+      linkend="fdl-document">Document</link> that deals exclusively
+      with the relationship of the publishers or authors of the
+      Document to the Document's overall subject (or to related
+      matters) and contains nothing that could fall directly within
+      that overall subject. (For example, if the Document is in part a
+      textbook of mathematics, a Secondary Section may not explain any
+      mathematics.)  The relationship could be a matter of historical
+      connection with the subject or with related matters, or of
+      legal, commercial, philosophical, ethical or political position
+      regarding them.
+    </para>
+
+    <para id="fdl-invariant">
+      The <quote>Invariant Sections</quote> are certain <link
+      linkend="fdl-secondary"> Secondary Sections</link> whose titles
+      are designated, as being those of Invariant Sections, in the
+      notice that says that the <link
+      linkend="fdl-document">Document</link> is released under this
+      License.
+    </para>
+
+    <para id="fdl-cover-texts">
+      The <quote>Cover Texts</quote> are certain short passages of
+      text that are listed, as Front-Cover Texts or Back-Cover Texts,
+      in the notice that says that the <link
+      linkend="fdl-document">Document</link> is released under this
+      License.
+    </para>
+
+    <para id="fdl-transparent">
+      A <quote>Transparent</quote> copy of the <link
+      linkend="fdl-document"> Document</link> means a machine-readable
+      copy, represented in a format whose specification is available
+      to the general public, whose contents can be viewed and edited
+      directly and straightforwardly with generic text editors or (for
+      images composed of pixels) generic paint programs or (for
+      drawings) some widely available drawing editor, and that is
+      suitable for input to text formatters or for automatic
+      translation to a variety of formats suitable for input to text
+      formatters. A copy made in an otherwise Transparent file format
+      whose markup has been designed to thwart or discourage
+      subsequent modification by readers is not Transparent.  A copy
+      that is not <quote>Transparent</quote> is called
+      <quote>Opaque</quote>.
+    </para>
+
+    <para>
+      Examples of suitable formats for Transparent copies include
+      plain ASCII without markup, Texinfo input format, LaTeX input
+      format, SGML or XML using a publicly available DTD, and
+      standard-conforming simple HTML designed for human
+      modification. Opaque formats include PostScript, PDF,
+      proprietary formats that can be read and edited only by
+      proprietary word processors, SGML or XML for which the DTD
+      and/or processing tools are not generally available, and the
+      machine-generated HTML produced by some word processors for
+      output purposes only.
+    </para>
+
+    <para id="fdl-title-page">
+      The <quote>Title Page</quote> means, for a printed book, the
+      title page itself, plus such following pages as are needed to
+      hold, legibly, the material this License requires to appear in
+      the title page. For works in formats which do not have any title
+      page as such, <quote>Title Page</quote> means the text near the
+      most prominent appearance of the work's title, preceding the
+      beginning of the body of the text.
+    </para>
+  </sect1>
+
+  <sect1 id="fdl-section2">
+    <title>2. VERBATIM COPYING</title>
+    <para>
+      You may copy and distribute the <link
+      linkend="fdl-document">Document</link> in any medium, either
+      commercially or noncommercially, provided that this License, the
+      copyright notices, and the license notice saying this License
+      applies to the Document are reproduced in all copies, and that
+      you add no other conditions whatsoever to those of this
+      License. You may not use technical measures to obstruct or
+      control the reading or further copying of the copies you make or
+      distribute. However, you may accept compensation in exchange for
+      copies. If you distribute a large enough number of copies you
+      must also follow the conditions in <link
+      linkend="fdl-section3">section 3</link>.
+    </para>
+
+    <para>
+      You may also lend copies, under the same conditions stated
+      above, and you may publicly display copies.
+    </para>
+    </sect1>
+
+  <sect1 id="fdl-section3">
+    <title>3. COPYING IN QUANTITY</title>
+    <para>
+      If you publish printed copies of the <link
+      linkend="fdl-document">Document</link> numbering more than 100,
+      and the Document's license notice requires <link
+      linkend="fdl-cover-texts">Cover Texts</link>, you must enclose
+      the copies in covers that carry, clearly and legibly, all these
+      Cover Texts: Front-Cover Texts on the front cover, and
+      Back-Cover Texts on the back cover. Both covers must also
+      clearly and legibly identify you as the publisher of these
+      copies. The front cover must present the full title with all
+      words of the title equally prominent and visible. You may add
+      other material on the covers in addition. Copying with changes
+      limited to the covers, as long as they preserve the title of the
+      <link linkend="fdl-document">Document</link> and satisfy these
+      conditions, can be treated as verbatim copying in other
+      respects.
+    </para>
+
+    <para>
+      If the required texts for either cover are too voluminous to fit
+      legibly, you should put the first ones listed (as many as fit
+      reasonably) on the actual cover, and continue the rest onto
+      adjacent pages.
+    </para>
+
+    <para>
+      If you publish or distribute <link
+      linkend="fdl-transparent">Opaque</link> copies of the <link
+      linkend="fdl-document">Document</link> numbering more than 100,
+      you must either include a machine-readable <link
+      linkend="fdl-transparent">Transparent</link> copy along with
+      each Opaque copy, or state in or with each Opaque copy a
+      publicly-accessible computer-network location containing a
+      complete Transparent copy of the Document, free of added
+      material, which the general network-using public has access to
+      download anonymously at no charge using public-standard network
+      protocols. If you use the latter option, you must take
+      reasonably prudent steps, when you begin distribution of Opaque
+      copies in quantity, to ensure that this Transparent copy will
+      remain thus accessible at the stated location until at least one
+      year after the last time you distribute an Opaque copy (directly
+      or through your agents or retailers) of that edition to the
+      public.
+    </para>
+
+    <para>
+      It is requested, but not required, that you contact the authors
+      of the <link linkend="fdl-document">Document</link> well before
+      redistributing any large number of copies, to give them a chance
+      to provide you with an updated version of the Document.
+    </para>
+    </sect1>
+
+  <sect1 id="fdl-section4">
+    <title>4. MODIFICATIONS</title>
+    <para>
+      You may copy and distribute a <link
+      linkend="fdl-modified">Modified Version</link> of the <link
+      linkend="fdl-document">Document</link> under the conditions of
+      sections <link linkend="fdl-section2">2</link> and <link
+      linkend="fdl-section3">3</link> above, provided that you release
+      the Modified Version under precisely this License, with the
+      Modified Version filling the role of the Document, thus
+      licensing distribution and modification of the Modified Version
+      to whoever possesses a copy of it. In addition, you must do
+      these things in the Modified Version:
+    </para>
+
+    <itemizedlist mark="opencircle">
+      <listitem>
+       <formalpara>
+         <title>A</title>
+         <para>
+           Use in the <link linkend="fdl-title-page">Title
+           Page</link> (and on the covers, if any) a title distinct
+           from that of the <link
+           linkend="fdl-document">Document</link>, and from those of
+           previous versions (which should, if there were any, be
+           listed in the History section of the Document). You may
+           use the same title as a previous version if the original
+           publisher of that version gives permission.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>B</title>
+         <para>
+           List on the <link linkend="fdl-title-page">Title
+           Page</link>, as authors, one or more persons or entities
+           responsible for authorship of the modifications in the
+           <link linkend="fdl-modified">Modified Version</link>,
+           together with at least five of the principal authors of
+           the <link linkend="fdl-document">Document</link> (all of
+           its principal authors, if it has less than five).
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>C</title>
+         <para>
+           State on the <link linkend="fdl-title-page">Title
+           Page</link> the name of the publisher of the <link
+           linkend="fdl-modified">Modified Version</link>, as the
+           publisher.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>D</title>
+         <para>
+           Preserve all the copyright notices of the <link
+           linkend="fdl-document">Document</link>.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>E</title>
+         <para>
+           Add an appropriate copyright notice for your modifications
+           adjacent to the other copyright notices.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>F</title>
+         <para>
+           Include, immediately after the copyright notices, a
+           license notice giving the public permission to use the
+           <link linkend="fdl-modified">Modified Version</link> under
+           the terms of this License, in the form shown in the
+           Addendum below.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>G</title>
+         <para>
+           Preserve in that license notice the full lists of <link
+           linkend="fdl-invariant"> Invariant Sections</link> and
+           required <link linkend="fdl-cover-texts">Cover
+           Texts</link> given in the <link
+           linkend="fdl-document">Document's</link> license notice.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>H</title>
+         <para>
+           Include an unaltered copy of this License.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>I</title>
+         <para>
+           Preserve the section entitled <quote>History</quote>, and
+           its title, and add to it an item stating at least the
+           title, year, new authors, and publisher of the <link
+           linkend="fdl-modified">Modified Version </link>as given on
+           the <link linkend="fdl-title-page">Title Page</link>.  If
+           there is no section entitled <quote>History</quote> in the
+           <link linkend="fdl-document">Document</link>, create one
+           stating the title, year, authors, and publisher of the
+           Document as given on its Title Page, then add an item
+           describing the Modified Version as stated in the previous
+           sentence.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>J</title>
+         <para>
+           Preserve the network location, if any, given in the <link
+           linkend="fdl-document">Document</link> for public access
+           to a <link linkend="fdl-transparent">Transparent</link>
+           copy of the Document, and likewise the network locations
+           given in the Document for previous versions it was based
+           on. These may be placed in the <quote>History</quote>
+           section.  You may omit a network location for a work that
+           was published at least four years before the Document
+           itself, or if the original publisher of the version it
+           refers to gives permission.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>K</title>
+         <para>
+           In any section entitled <quote>Acknowledgements</quote> or
+           <quote>Dedications</quote>, preserve the section's title,
+           and preserve in the section all the substance and tone of
+           each of the contributor acknowledgements and/or
+           dedications given therein.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>L</title>
+         <para>
+           Preserve all the <link linkend="fdl-invariant">Invariant
+           Sections</link> of the <link
+           linkend="fdl-document">Document</link>, unaltered in their
+           text and in their titles.  Section numbers or the
+           equivalent are not considered part of the section titles.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>M</title>
+         <para>
+           Delete any section entitled
+           <quote>Endorsements</quote>. Such a section may not be
+           included in the <link linkend="fdl-modified">Modified
+           Version</link>.
+         </para>
+       </formalpara>
+      </listitem>
+
+      <listitem>
+       <formalpara>
+         <title>N</title>
+         <para>
+           Do not retitle any existing section as
+           <quote>Endorsements</quote> or to conflict in title with
+           any <link linkend="fdl-invariant">Invariant
+           Section</link>.
+         </para>
+       </formalpara>
+      </listitem>
+    </itemizedlist>
+
+    <para>
+      If the <link linkend="fdl-modified">Modified Version</link>
+      includes new front-matter sections or appendices that qualify as
+      <link linkend="fdl-secondary">Secondary Sections</link> and
+      contain no material copied from the Document, you may at your
+      option designate some or all of these sections as invariant. To
+      do this, add their titles to the list of <link
+      linkend="fdl-invariant">Invariant Sections</link> in the
+      Modified Version's license notice.  These titles must be
+      distinct from any other section titles.
+    </para>
+
+    <para>
+      You may add a section entitled <quote>Endorsements</quote>,
+      provided it contains nothing but endorsements of your <link
+      linkend="fdl-modified">Modified Version</link> by various
+      parties--for example, statements of peer review or that the text
+      has been approved by an organization as the authoritative
+      definition of a standard.
+    </para>
+
+    <para>
+      You may add a passage of up to five words as a <link
+      linkend="fdl-cover-texts">Front-Cover Text</link>, and a passage
+      of up to 25 words as a <link
+      linkend="fdl-cover-texts">Back-Cover Text</link>, to the end of
+      the list of <link linkend="fdl-cover-texts">Cover Texts</link>
+      in the <link linkend="fdl-modified">Modified Version</link>.
+      Only one passage of Front-Cover Text and one of Back-Cover Text
+      may be added by (or through arrangements made by) any one
+      entity. If the <link linkend="fdl-document">Document</link>
+      already includes a cover text for the same cover, previously
+      added by you or by arrangement made by the same entity you are
+      acting on behalf of, you may not add another; but you may
+      replace the old one, on explicit permission from the previous
+      publisher that added the old one.
+    </para>
+
+    <para>
+      The author(s) and publisher(s) of the <link
+      linkend="fdl-document">Document</link> do not by this License
+      give permission to use their names for publicity for or to
+      assert or imply endorsement of any <link
+      linkend="fdl-modified">Modified Version </link>.
+    </para>
+  </sect1>
+
+  <sect1 id="fdl-section5">
+    <title>5. COMBINING DOCUMENTS</title>
+    <para>
+      You may combine the <link linkend="fdl-document">Document</link>
+      with other documents released under this License, under the
+      terms defined in <link linkend="fdl-section4">section 4</link>
+      above for modified versions, provided that you include in the
+      combination all of the <link linkend="fdl-invariant">Invariant
+      Sections</link> of all of the original documents, unmodified,
+      and list them all as Invariant Sections of your combined work in
+      its license notice.
+    </para>
+
+    <para>
+      The combined work need only contain one copy of this License,
+      and multiple identical <link linkend="fdl-invariant">Invariant
+      Sections</link> may be replaced with a single copy. If there are
+      multiple Invariant Sections with the same name but different
+      contents, make the title of each such section unique by adding
+      at the end of it, in parentheses, the name of the original
+      author or publisher of that section if known, or else a unique
+      number. Make the same adjustment to the section titles in the
+      list of Invariant Sections in the license notice of the combined
+      work.
+    </para>
+
+    <para>
+      In the combination, you must combine any sections entitled
+      <quote>History</quote> in the various original documents,
+      forming one section entitled <quote>History</quote>; likewise
+      combine any sections entitled <quote>Acknowledgements</quote>,
+      and any sections entitled <quote>Dedications</quote>.  You must
+      delete all sections entitled <quote>Endorsements.</quote>
+    </para>
+    </sect1>
+
+  <sect1 id="fdl-section6">
+    <title>6. COLLECTIONS OF DOCUMENTS</title>
+    <para>
+      You may make a collection consisting of the <link
+      linkend="fdl-document">Document</link> and other documents
+      released under this License, and replace the individual copies
+      of this License in the various documents with a single copy that
+      is included in the collection, provided that you follow the
+      rules of this License for verbatim copying of each of the
+      documents in all other respects.
+    </para>
+
+    <para>
+      You may extract a single document from such a collection, and
+      dispbibute it individually under this License, provided you
+      insert a copy of this License into the extracted document, and
+      follow this License in all other respects regarding verbatim
+      copying of that document.
+    </para>
+    </sect1>
+
+  <sect1 id="fdl-section7">
+    <title>7. AGGREGATION WITH INDEPENDENT WORKS</title>
+    <para>
+      A compilation of the <link
+      linkend="fdl-document">Document</link> or its derivatives with
+      other separate and independent documents or works, in or on a
+      volume of a storage or distribution medium, does not as a whole
+      count as a <link linkend="fdl-modified">Modified Version</link>
+      of the Document, provided no compilation copyright is claimed
+      for the compilation.  Such a compilation is called an
+      <quote>aggregate</quote>, and this License does not apply to the
+      other self-contained works thus compiled with the Document , on
+      account of their being thus compiled, if they are not themselves
+      derivative works of the Document.  If the <link
+      linkend="fdl-cover-texts">Cover Text</link> requirement of <link
+      linkend="fdl-section3">section 3</link> is applicable to these
+      copies of the Document, then if the Document is less than one
+      quarter of the entire aggregate, the Document's Cover Texts may
+      be placed on covers that surround only the Document within the
+      aggregate. Otherwise they must appear on covers around the whole
+      aggregate.
+    </para>
+    </sect1>
+
+  <sect1 id="fdl-section8">
+    <title>8. TRANSLATION</title>
+    <para>
+      Translation is considered a kind of modification, so you may
+      distribute translations of the <link
+      linkend="fdl-document">Document</link> under the terms of <link
+      linkend="fdl-section4">section 4</link>. Replacing <link
+      linkend="fdl-invariant"> Invariant Sections</link> with
+      translations requires special permission from their copyright
+      holders, but you may include translations of some or all
+      Invariant Sections in addition to the original versions of these
+      Invariant Sections. You may include a translation of this
+      License provided that you also include the original English
+      version of this License. In case of a disagreement between the
+      translation and the original English version of this License,
+      the original English version will prevail.
+    </para>
+    </sect1>
+
+  <sect1 id="fdl-section9">
+    <title>9. TERMINATION</title>
+    <para>
+      You may not copy, modify, sublicense, or distribute the <link
+      linkend="fdl-document">Document</link> except as expressly
+      provided for under this License. Any other attempt to copy,
+      modify, sublicense or distribute the Document is void, and will
+      automatically terminate your rights under this License. However,
+      parties who have received copies, or rights, from you under this
+      License will not have their licenses terminated so long as such
+      parties remain in full compliance.
+    </para>
+    </sect1>
+
+  <sect1 id="fdl-section10">
+    <title>10. FUTURE REVISIONS OF THIS LICENSE</title>
+    <para>
+      The <ulink type="http"
+      url="http://www.gnu.org/fsf/fsf.html">Free Software
+      Foundation</ulink> may publish new, revised versions of the GNU
+      Free Documentation License from time to time. Such new versions
+      will be similar in spirit to the present version, but may differ
+      in detail to address new problems or concerns. See <ulink
+      type="http"
+      url="http://www.gnu.org/copyleft">http://www.gnu.org/copyleft/</ulink>.
+    </para>
+
+    <para>
+      Each version of the License is given a distinguishing version
+      number. If the <link linkend="fdl-document">Document</link>
+      specifies that a particular numbered version of this License
+      <quote>or any later version</quote> applies to it, you have the
+      option of following the terms and conditions either of that
+      specified version or of any later version that has been
+      published (not as a draft) by the Free Software Foundation. If
+      the Document does not specify a version number of this License,
+      you may choose any version ever published (not as a draft) by
+      the Free Software Foundation.
+    </para>
+  </sect1>
+
+  <sect1 id="fdl-using">
+    <title>Addendum</title>
+    <para>
+      To use this License in a document you have written, include a copy of
+      the License in the document and put the following copyright and
+      license notices just after the title page:
+    </para>
+
+    <blockquote>
+      <para>
+       Copyright &copy; YEAR YOUR NAME.
+      </para>
+      <para>
+       Permission is granted to copy, distribute and/or modify this
+       document under the terms of the GNU Free Documentation
+       License, Version 1.1 or any later version published by the
+       Free Software Foundation; with the <link
+       linkend="fdl-invariant">Invariant Sections</link> being LIST
+       THEIR TITLES, with the <link
+       linkend="fdl-cover-texts">Front-Cover Texts</link> being LIST,
+       and with the <link linkend="fdl-cover-texts">Back-Cover
+       Texts</link> being LIST.  A copy of the license is included in
+       the section entitled <quote>GNU Free Documentation
+       License</quote>.
+      </para>
+    </blockquote>
+
+    <para>
+      If you have no <link linkend="fdl-invariant">Invariant
+      Sections</link>, write <quote>with no Invariant Sections</quote>
+      instead of saying which ones are invariant.  If you have no
+      <link linkend="fdl-cover-texts">Front-Cover Texts</link>, write
+      <quote>no Front-Cover Texts</quote> instead of
+      <quote>Front-Cover Texts being LIST</quote>; likewise for <link
+      linkend="fdl-cover-texts">Back-Cover Texts</link>.
+    </para>
+
+    <para>
+      If your document contains nontrivial examples of program code,
+      we recommend releasing these examples in parallel under your
+      choice of free software license, such as the <ulink type="http"
+      url="http://www.gnu.org/copyleft/gpl.html"> GNU General Public
+      License</ulink>, to permit their use in free software.
+    </para>
+  </sect1>
+</appendix>
+
+
+
+
+
+
diff --git a/Documentation/DocBook/media/v4l/fieldseq_bt.pdf b/Documentation/DocBook/media/v4l/fieldseq_bt.pdf
new file mode 100644 (file)
index 0000000..26598b2
Binary files /dev/null and b/Documentation/DocBook/media/v4l/fieldseq_bt.pdf differ
diff --git a/Documentation/DocBook/media/v4l/fieldseq_tb.pdf b/Documentation/DocBook/media/v4l/fieldseq_tb.pdf
new file mode 100644 (file)
index 0000000..4965b22
Binary files /dev/null and b/Documentation/DocBook/media/v4l/fieldseq_tb.pdf differ
diff --git a/Documentation/DocBook/media/v4l/func-close.xml b/Documentation/DocBook/media/v4l/func-close.xml
new file mode 100644 (file)
index 0000000..dfb41cb
--- /dev/null
@@ -0,0 +1,70 @@
+<refentry id="func-close">
+  <refmeta>
+    <refentrytitle>V4L2 close()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>v4l2-close</refname>
+    <refpurpose>Close a V4L2 device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>close</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Closes the device. Any I/O in progress is terminated and
+resources associated with the file descriptor are freed. However data
+format parameters, current input or output, control values or other
+properties remain unchanged.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>The function returns <returnvalue>0</returnvalue> on
+success, <returnvalue>-1</returnvalue> on failure and the
+<varname>errno</varname> is set appropriately. Possible error
+codes:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBADF</errorcode></term>
+       <listitem>
+         <para><parameter>fd</parameter> is not a valid open file
+descriptor.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/func-ioctl.xml b/Documentation/DocBook/media/v4l/func-ioctl.xml
new file mode 100644 (file)
index 0000000..2de64be
--- /dev/null
@@ -0,0 +1,79 @@
+<refentry id="func-ioctl">
+  <refmeta>
+    <refentrytitle>V4L2 ioctl()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>v4l2-ioctl</refname>
+    <refpurpose>Program a V4L2 device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>void *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>V4L2 ioctl request code as defined in the <filename>videodev2.h</filename> header file, for example
+VIDIOC_QUERYCAP.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para>Pointer to a function parameter, usually a structure.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The <function>ioctl()</function> function is used to program
+V4L2 devices. The argument <parameter>fd</parameter> must be an open
+file descriptor. An ioctl <parameter>request</parameter> has encoded
+in it whether the argument is an input, output or read/write
+parameter, and the size of the argument <parameter>argp</parameter> in
+bytes. Macros and defines specifying V4L2 ioctl requests are located
+in the <filename>videodev2.h</filename> header file.
+Applications should use their own copy, not include the version in the
+kernel sources on the system they compile on. All V4L2 ioctl requests,
+their respective function and parameters are specified in <xref
+       linkend="user-func" />.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+    <para>When an ioctl that takes an output or read/write parameter fails,
+    the parameter remains unmodified.</para>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/func-mmap.xml b/Documentation/DocBook/media/v4l/func-mmap.xml
new file mode 100644 (file)
index 0000000..786732b
--- /dev/null
@@ -0,0 +1,191 @@
+<refentry id="func-mmap">
+  <refmeta>
+    <refentrytitle>V4L2 mmap()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>v4l2-mmap</refname>
+    <refpurpose>Map device memory into application address space</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>
+#include &lt;unistd.h&gt;
+#include &lt;sys/mman.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>void *<function>mmap</function></funcdef>
+       <paramdef>void *<parameter>start</parameter></paramdef>
+       <paramdef>size_t <parameter>length</parameter></paramdef>
+       <paramdef>int <parameter>prot</parameter></paramdef>
+       <paramdef>int <parameter>flags</parameter></paramdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>off_t <parameter>offset</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+    <variablelist>
+      <varlistentry>
+       <term><parameter>start</parameter></term>
+       <listitem>
+         <para>Map the buffer to this address in the
+application's address space. When the <constant>MAP_FIXED</constant>
+flag is specified, <parameter>start</parameter> must be a multiple of the
+pagesize and mmap will fail when the specified address
+cannot be used. Use of this option is discouraged; applications should
+just specify a <constant>NULL</constant> pointer here.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>length</parameter></term>
+       <listitem>
+         <para>Length of the memory area to map. This must be the
+same value as returned by the driver in the &v4l2-buffer;
+<structfield>length</structfield> field for the
+single-planar API, and the same value as returned by the driver
+in the &v4l2-plane; <structfield>length</structfield> field for the
+multi-planar API.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>prot</parameter></term>
+       <listitem>
+         <para>The <parameter>prot</parameter> argument describes the
+desired memory protection. Regardless of the device type and the
+direction of data exchange it should be set to
+<constant>PROT_READ</constant> | <constant>PROT_WRITE</constant>,
+permitting read and write access to image buffers. Drivers should
+support at least this combination of flags. Note the Linux
+<filename>video-buf</filename> kernel module, which is used by the
+bttv, saa7134, saa7146, cx88 and vivi driver supports only
+<constant>PROT_READ</constant> | <constant>PROT_WRITE</constant>. When
+the driver does not support the desired protection the
+<function>mmap()</function> function fails.</para>
+         <para>Note device memory accesses (&eg; the memory on a
+graphics card with video capturing hardware) may incur a performance
+penalty compared to main memory accesses, or reads may be
+significantly slower than writes or vice versa. Other I/O methods may
+be more efficient in this case.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>flags</parameter></term>
+       <listitem>
+         <para>The <parameter>flags</parameter> parameter
+specifies the type of the mapped object, mapping options and whether
+modifications made to the mapped copy of the page are private to the
+process or are to be shared with other references.</para>
+         <para><constant>MAP_FIXED</constant> requests that the
+driver selects no other address than the one specified. If the
+specified address cannot be used, <function>mmap()</function> will fail. If
+<constant>MAP_FIXED</constant> is specified,
+<parameter>start</parameter> must be a multiple of the pagesize. Use
+of this option is discouraged.</para>
+         <para>One of the <constant>MAP_SHARED</constant> or
+<constant>MAP_PRIVATE</constant> flags must be set.
+<constant>MAP_SHARED</constant> allows applications to share the
+mapped memory with other (&eg; child-) processes. Note the Linux
+<filename>video-buf</filename> module which is used by the bttv,
+saa7134, saa7146, cx88 and vivi driver supports only
+<constant>MAP_SHARED</constant>. <constant>MAP_PRIVATE</constant>
+requests copy-on-write semantics. V4L2 applications should not set the
+<constant>MAP_PRIVATE</constant>, <constant>MAP_DENYWRITE</constant>,
+<constant>MAP_EXECUTABLE</constant> or <constant>MAP_ANON</constant>
+flag.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>offset</parameter></term>
+       <listitem>
+         <para>Offset of the buffer in device memory. This must be the
+same value as returned by the driver in the &v4l2-buffer;
+<structfield>m</structfield> union <structfield>offset</structfield> field for
+the single-planar API, and the same value as returned by the driver
+in the &v4l2-plane; <structfield>m</structfield> union
+<structfield>mem_offset</structfield> field for the multi-planar API.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The <function>mmap()</function> function asks to map
+<parameter>length</parameter> bytes starting at
+<parameter>offset</parameter> in the memory of the device specified by
+<parameter>fd</parameter> into the application address space,
+preferably at address <parameter>start</parameter>. This latter
+address is a hint only, and is usually specified as 0.</para>
+
+    <para>Suitable length and offset parameters are queried with the
+&VIDIOC-QUERYBUF; ioctl. Buffers must be allocated with the
+&VIDIOC-REQBUFS; ioctl before they can be queried.</para>
+
+    <para>To unmap buffers the &func-munmap; function is used.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success <function>mmap()</function> returns a pointer to
+the mapped buffer. On error <constant>MAP_FAILED</constant> (-1) is
+returned, and the <varname>errno</varname> variable is set
+appropriately. Possible error codes are:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBADF</errorcode></term>
+       <listitem>
+         <para><parameter>fd</parameter> is not a valid file
+descriptor.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EACCES</errorcode></term>
+       <listitem>
+         <para><parameter>fd</parameter> is
+not open for reading and writing.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <parameter>start</parameter> or
+<parameter>length</parameter> or <parameter>offset</parameter> are not
+suitable. (E.&nbsp;g. they are too large, or not aligned on a
+<constant>PAGESIZE</constant> boundary.)</para>
+         <para>The <parameter>flags</parameter> or
+<parameter>prot</parameter> value is not supported.</para>
+         <para>No buffers have been allocated with the
+&VIDIOC-REQBUFS; ioctl.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENOMEM</errorcode></term>
+       <listitem>
+         <para>Not enough physical or virtual memory was available to
+complete the request.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/func-munmap.xml b/Documentation/DocBook/media/v4l/func-munmap.xml
new file mode 100644 (file)
index 0000000..e2c4190
--- /dev/null
@@ -0,0 +1,84 @@
+<refentry id="func-munmap">
+  <refmeta>
+    <refentrytitle>V4L2 munmap()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>v4l2-munmap</refname>
+    <refpurpose>Unmap device memory</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>
+#include &lt;unistd.h&gt;
+#include &lt;sys/mman.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>munmap</function></funcdef>
+       <paramdef>void *<parameter>start</parameter></paramdef>
+       <paramdef>size_t <parameter>length</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+  <refsect1>
+    <title>Arguments</title>
+    <variablelist>
+      <varlistentry>
+       <term><parameter>start</parameter></term>
+       <listitem>
+         <para>Address of the mapped buffer as returned by the
+&func-mmap; function.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>length</parameter></term>
+       <listitem>
+         <para>Length of the mapped buffer. This must be the same
+value as given to <function>mmap()</function> and returned by the
+driver in the &v4l2-buffer; <structfield>length</structfield>
+field for the single-planar API and in the &v4l2-plane;
+<structfield>length</structfield> field for the multi-planar API.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Unmaps a previously with the &func-mmap; function mapped
+buffer and frees it, if possible. <!-- ? This function (not freeing)
+has no impact on I/O in progress, specifically it does not imply
+&VIDIOC-STREAMOFF; to terminate I/O. Unmapped buffers can still be
+enqueued, dequeued or queried, they are just not accessible by the
+application.--></para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success <function>munmap()</function> returns 0, on
+failure -1 and the <varname>errno</varname> variable is set
+appropriately:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <parameter>start</parameter> or
+<parameter>length</parameter> is incorrect, or no buffers have been
+mapped yet.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/func-open.xml b/Documentation/DocBook/media/v4l/func-open.xml
new file mode 100644 (file)
index 0000000..7595d07
--- /dev/null
@@ -0,0 +1,121 @@
+<refentry id="func-open">
+  <refmeta>
+    <refentrytitle>V4L2 open()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>v4l2-open</refname>
+    <refpurpose>Open a V4L2 device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>open</function></funcdef>
+       <paramdef>const char *<parameter>device_name</parameter></paramdef>
+       <paramdef>int <parameter>flags</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>device_name</parameter></term>
+       <listitem>
+         <para>Device to be opened.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>flags</parameter></term>
+       <listitem>
+         <para>Open flags. Access mode must be
+<constant>O_RDWR</constant>. This is just a technicality, input devices
+still support only reading and output devices only writing.</para>
+         <para>When the <constant>O_NONBLOCK</constant> flag is
+given, the read() function and the &VIDIOC-DQBUF; ioctl will return
+the &EAGAIN; when no data is available or no buffer is in the driver
+outgoing queue, otherwise these functions block until data becomes
+available. All V4L2 drivers exchanging data with applications must
+support the <constant>O_NONBLOCK</constant> flag.</para>
+         <para>Other flags have no effect.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>Description</title>
+
+    <para>To open a V4L2 device applications call
+<function>open()</function> with the desired device name. This
+function has no side effects; all data format parameters, current
+input or output, control values or other properties remain unchanged.
+At the first <function>open()</function> call after loading the driver
+they will be reset to default values, drivers are never in an
+undefined state.</para>
+  </refsect1>
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success <function>open</function> returns the new file
+descriptor. On error -1 is returned, and the <varname>errno</varname>
+variable is set appropriately. Possible error codes are:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EACCES</errorcode></term>
+       <listitem>
+         <para>The caller has no permission to access the
+device.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The driver does not support multiple opens and the
+device is already in use.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENXIO</errorcode></term>
+       <listitem>
+         <para>No device corresponding to this device special file
+exists.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENOMEM</errorcode></term>
+       <listitem>
+         <para>Not enough kernel memory was available to complete the
+request.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EMFILE</errorcode></term>
+       <listitem>
+         <para>The  process  already  has  the  maximum number of
+files open.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENFILE</errorcode></term>
+       <listitem>
+         <para>The limit on the total number of files open on the
+system has been reached.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/func-poll.xml b/Documentation/DocBook/media/v4l/func-poll.xml
new file mode 100644 (file)
index 0000000..ec3c718
--- /dev/null
@@ -0,0 +1,127 @@
+<refentry id="func-poll">
+  <refmeta>
+    <refentrytitle>V4L2 poll()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>v4l2-poll</refname>
+    <refpurpose>Wait for some event on a file descriptor</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;sys/poll.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>poll</function></funcdef>
+       <paramdef>struct pollfd *<parameter>ufds</parameter></paramdef>
+       <paramdef>unsigned int <parameter>nfds</parameter></paramdef>
+       <paramdef>int <parameter>timeout</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>With the <function>poll()</function> function applications
+can suspend execution until the driver has captured data or is ready
+to accept data for output.</para>
+
+    <para>When streaming I/O has been negotiated this function waits
+until a buffer has been filled or displayed and can be dequeued with
+the &VIDIOC-DQBUF; ioctl. When buffers are already in the outgoing
+queue of the driver the function returns immediately.</para>
+
+    <para>On success <function>poll()</function> returns the number of
+file descriptors that have been selected (that is, file descriptors
+for which the <structfield>revents</structfield> field of the
+respective <structname>pollfd</structname> structure is non-zero).
+Capture devices set the <constant>POLLIN</constant> and
+<constant>POLLRDNORM</constant> flags in the
+<structfield>revents</structfield> field, output devices the
+<constant>POLLOUT</constant> and <constant>POLLWRNORM</constant>
+flags. When the function timed out it returns a value of zero, on
+failure it returns <returnvalue>-1</returnvalue> and the
+<varname>errno</varname> variable is set appropriately. When the
+application did not call &VIDIOC-QBUF; or &VIDIOC-STREAMON; yet the
+<function>poll()</function> function succeeds, but sets the
+<constant>POLLERR</constant> flag in the
+<structfield>revents</structfield> field.</para>
+
+    <para>When use of the <function>read()</function> function has
+been negotiated and the driver does not capture yet, the
+<function>poll</function> function starts capturing. When that fails
+it returns a <constant>POLLERR</constant> as above. Otherwise it waits
+until data has been captured and can be read. When the driver captures
+continuously (as opposed to, for example, still images) the function
+may return immediately.</para>
+
+    <para>When use of the <function>write()</function> function has
+been negotiated the <function>poll</function> function just waits
+until the driver is ready for a non-blocking
+<function>write()</function> call.</para>
+
+    <para>All drivers implementing the <function>read()</function> or
+<function>write()</function> function or streaming I/O must also
+support the <function>poll()</function> function.</para>
+
+    <para>For more details see the
+<function>poll()</function> manual page.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, <function>poll()</function> returns the number
+structures which have non-zero <structfield>revents</structfield>
+fields, or zero if the call timed out. On error
+<returnvalue>-1</returnvalue> is returned, and the
+<varname>errno</varname> variable is set appropriately:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBADF</errorcode></term>
+       <listitem>
+         <para>One or more of the <parameter>ufds</parameter> members
+specify an invalid file descriptor.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The driver does not support multiple read or write
+streams and the device is already in use.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EFAULT</errorcode></term>
+       <listitem>
+         <para><parameter>ufds</parameter> references an inaccessible
+memory area.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINTR</errorcode></term>
+       <listitem>
+         <para>The call was interrupted by a signal.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <parameter>nfds</parameter> argument is greater
+than <constant>OPEN_MAX</constant>.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/func-read.xml b/Documentation/DocBook/media/v4l/func-read.xml
new file mode 100644 (file)
index 0000000..a5089bf
--- /dev/null
@@ -0,0 +1,189 @@
+<refentry id="func-read">
+  <refmeta>
+    <refentrytitle>V4L2 read()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>v4l2-read</refname>
+    <refpurpose>Read from a V4L2 device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>ssize_t <function>read</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>void *<parameter>buf</parameter></paramdef>
+       <paramdef>size_t <parameter>count</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>buf</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>count</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><function>read()</function> attempts to read up to
+<parameter>count</parameter> bytes from file descriptor
+<parameter>fd</parameter> into the buffer starting at
+<parameter>buf</parameter>. The layout of the data in the buffer is
+discussed in the respective device interface section, see ##. If <parameter>count</parameter> is zero,
+<function>read()</function> returns zero and has no other results. If
+<parameter>count</parameter> is greater than
+<constant>SSIZE_MAX</constant>, the result is unspecified. Regardless
+of the <parameter>count</parameter> value each
+<function>read()</function> call will provide at most one frame (two
+fields) worth of data.</para>
+
+    <para>By default <function>read()</function> blocks until data
+becomes available. When the <constant>O_NONBLOCK</constant> flag was
+given to the &func-open; function it
+returns immediately with an &EAGAIN; when no data is available. The
+&func-select; or &func-poll; functions
+can always be used to suspend execution until data becomes available. All
+drivers supporting the <function>read()</function> function must also
+support <function>select()</function> and
+<function>poll()</function>.</para>
+
+    <para>Drivers can implement read functionality in different
+ways, using a single or multiple buffers and discarding the oldest or
+newest frames once the internal buffers are filled.</para>
+
+    <para><function>read()</function> never returns a "snapshot" of a
+buffer being filled. Using a single buffer the driver will stop
+capturing when the application starts reading the buffer until the
+read is finished. Thus only the period of the vertical blanking
+interval is available for reading, or the capture rate must fall below
+the nominal frame rate of the video standard.</para>
+
+<para>The behavior of
+<function>read()</function> when called during the active picture
+period or the vertical blanking separating the top and bottom field
+depends on the discarding policy. A driver discarding the oldest
+frames keeps capturing into an internal buffer, continuously
+overwriting the previously, not read frame, and returns the frame
+being received at the time of the <function>read()</function> call as
+soon as it is complete.</para>
+
+    <para>A driver discarding the newest frames stops capturing until
+the next <function>read()</function> call. The frame being received at
+<function>read()</function> time is discarded, returning the following
+frame instead. Again this implies a reduction of the capture rate to
+one half or less of the nominal frame rate. An example of this model
+is the video read mode of the bttv driver, initiating a DMA to user
+memory when <function>read()</function> is called and returning when
+the DMA finished.</para>
+
+    <para>In the multiple buffer model drivers maintain a ring of
+internal buffers, automatically advancing to the next free buffer.
+This allows continuous capturing when the application can empty the
+buffers fast enough. Again, the behavior when the driver runs out of
+free buffers depends on the discarding policy.</para>
+
+    <para>Applications can get and set the number of buffers used
+internally by the driver with the &VIDIOC-G-PARM; and &VIDIOC-S-PARM;
+ioctls. They are optional, however. The discarding policy is not
+reported and cannot be changed. For minimum requirements see <xref
+       linkend="devices" />.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, the number of bytes read is returned. It is not
+an error if this number is smaller than the number of bytes requested,
+or the amount of data required for one frame. This may happen for
+example because <function>read()</function> was interrupted by a
+signal. On error, -1 is returned, and the <varname>errno</varname>
+variable is set appropriately. In this case the next read will start
+at the beginning of a new frame. Possible error codes are:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EAGAIN</errorcode></term>
+       <listitem>
+         <para>Non-blocking I/O has been selected using
+O_NONBLOCK and no data was immediately available for reading.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBADF</errorcode></term>
+       <listitem>
+         <para><parameter>fd</parameter> is not a valid file
+descriptor or is not open for reading, or the process already has the
+maximum number of files open.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The driver does not support multiple read streams and the
+device is already in use.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EFAULT</errorcode></term>
+       <listitem>
+         <para><parameter>buf</parameter> references an inaccessible
+memory area.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINTR</errorcode></term>
+       <listitem>
+         <para>The call was interrupted by a signal before any
+data was read.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EIO</errorcode></term>
+       <listitem>
+         <para>I/O error. This indicates some hardware problem or a
+failure to communicate with a remote device (USB camera etc.).</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <function>read()</function> function is not
+supported by this driver, not on this device, or generally not on this
+type of device.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/func-select.xml b/Documentation/DocBook/media/v4l/func-select.xml
new file mode 100644 (file)
index 0000000..b671362
--- /dev/null
@@ -0,0 +1,138 @@
+<refentry id="func-select">
+  <refmeta>
+    <refentrytitle>V4L2 select()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>v4l2-select</refname>
+    <refpurpose>Synchronous I/O multiplexing</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>
+#include &lt;sys/time.h&gt;
+#include &lt;sys/types.h&gt;
+#include &lt;unistd.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>select</function></funcdef>
+       <paramdef>int <parameter>nfds</parameter></paramdef>
+       <paramdef>fd_set *<parameter>readfds</parameter></paramdef>
+       <paramdef>fd_set *<parameter>writefds</parameter></paramdef>
+       <paramdef>fd_set *<parameter>exceptfds</parameter></paramdef>
+       <paramdef>struct timeval *<parameter>timeout</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>With the <function>select()</function> function applications
+can suspend execution until the driver has captured data or is ready
+to accept data for output.</para>
+
+    <para>When streaming I/O has been negotiated this function waits
+until a buffer has been filled or displayed and can be dequeued with
+the &VIDIOC-DQBUF; ioctl. When buffers are already in the outgoing
+queue of the driver the function returns immediately.</para>
+
+    <para>On success <function>select()</function> returns the total
+number of bits set in the <structname>fd_set</structname>s. When the
+function timed out it returns a value of zero. On failure it returns
+<returnvalue>-1</returnvalue> and the <varname>errno</varname>
+variable is set appropriately. When the application did not call
+&VIDIOC-QBUF; or &VIDIOC-STREAMON; yet the
+<function>select()</function> function succeeds, setting the bit of
+the file descriptor in <parameter>readfds</parameter> or
+<parameter>writefds</parameter>, but subsequent &VIDIOC-DQBUF; calls
+will fail.<footnote><para>The Linux kernel implements
+<function>select()</function> like the &func-poll; function, but
+<function>select()</function> cannot return a
+<constant>POLLERR</constant>.</para>
+      </footnote></para>
+
+    <para>When use of the <function>read()</function> function has
+been negotiated and the driver does not capture yet, the
+<function>select()</function> function starts capturing. When that
+fails, <function>select()</function> returns successful and a
+subsequent <function>read()</function> call, which also attempts to
+start capturing, will return an appropriate error code. When the
+driver captures continuously (as opposed to, for example, still
+images) and data is already available the
+<function>select()</function> function returns immediately.</para>
+
+    <para>When use of the <function>write()</function> function has
+been negotiated the <function>select()</function> function just waits
+until the driver is ready for a non-blocking
+<function>write()</function> call.</para>
+
+    <para>All drivers implementing the <function>read()</function> or
+<function>write()</function> function or streaming I/O must also
+support the <function>select()</function> function.</para>
+
+    <para>For more details see the <function>select()</function>
+manual page.</para>
+
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, <function>select()</function> returns the number
+of descriptors contained in the three returned descriptor sets, which
+will be zero if the timeout expired. On error
+<returnvalue>-1</returnvalue> is returned, and the
+<varname>errno</varname> variable is set appropriately; the sets and
+<parameter>timeout</parameter> are undefined. Possible error codes
+are:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBADF</errorcode></term>
+       <listitem>
+         <para>One or more of the file descriptor sets specified a
+file descriptor that is not open.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The driver does not support multiple read or write
+streams and the device is already in use.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EFAULT</errorcode></term>
+       <listitem>
+         <para>The <parameter>readfds</parameter>,
+<parameter>writefds</parameter>, <parameter>exceptfds</parameter> or
+<parameter>timeout</parameter> pointer references an inaccessible memory
+area.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINTR</errorcode></term>
+       <listitem>
+         <para>The call was interrupted by a signal.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <parameter>nfds</parameter> argument is less than
+zero or greater than <constant>FD_SETSIZE</constant>.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/func-write.xml b/Documentation/DocBook/media/v4l/func-write.xml
new file mode 100644 (file)
index 0000000..2c09c09
--- /dev/null
@@ -0,0 +1,136 @@
+<refentry id="func-write">
+  <refmeta>
+    <refentrytitle>V4L2 write()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>v4l2-write</refname>
+    <refpurpose>Write to a V4L2 device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>ssize_t <function>write</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>void *<parameter>buf</parameter></paramdef>
+       <paramdef>size_t <parameter>count</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>buf</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>count</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><function>write()</function> writes up to
+<parameter>count</parameter> bytes to the device referenced by the
+file descriptor <parameter>fd</parameter> from the buffer starting at
+<parameter>buf</parameter>. When the hardware outputs are not active
+yet, this function enables them. When <parameter>count</parameter> is
+zero, <function>write()</function> returns
+<returnvalue>0</returnvalue> without any other effect.</para>
+
+    <para>When the application does not provide more data in time, the
+previous video frame, raw VBI image, sliced VPS or WSS data is
+displayed again. Sliced Teletext or Closed Caption data is not
+repeated, the driver inserts a blank line instead.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para>On success, the number of bytes written are returned. Zero
+indicates nothing was written. On error, <returnvalue>-1</returnvalue>
+is returned, and the <varname>errno</varname> variable is set
+appropriately. In this case the next write will start at the beginning
+of a new frame. Possible error codes are:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EAGAIN</errorcode></term>
+       <listitem>
+         <para>Non-blocking I/O has been selected using the <link
+linkend="func-open"><constant>O_NONBLOCK</constant></link> flag and no
+buffer space was available to write the data immediately.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBADF</errorcode></term>
+       <listitem>
+         <para><parameter>fd</parameter> is not a valid file
+descriptor or is not open for writing.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The driver does not support multiple write streams and the
+device is already in use.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EFAULT</errorcode></term>
+       <listitem>
+         <para><parameter>buf</parameter> references an inaccessible
+memory area.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINTR</errorcode></term>
+       <listitem>
+         <para>The call was interrupted by a signal before any
+data was written.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EIO</errorcode></term>
+       <listitem>
+         <para>I/O error. This indicates some hardware problem.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <function>write()</function> function is not
+supported by this driver, not on this device, or generally not on this
+type of device.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/gen-errors.xml b/Documentation/DocBook/media/v4l/gen-errors.xml
new file mode 100644 (file)
index 0000000..5bbf3ce
--- /dev/null
@@ -0,0 +1,78 @@
+<title>Generic Error Codes</title>
+
+<table frame="none" pgwide="1" id="gen-errors">
+  <title>Generic error codes</title>
+  <tgroup cols="2">
+    &cs-str;
+    <tbody valign="top">
+       <!-- Keep it ordered alphabetically -->
+      <row>
+       <entry>EBADF</entry>
+       <entry>The file descriptor is not a valid.</entry>
+      </row>
+      <row>
+       <entry>EBUSY</entry>
+       <entry>The ioctl can't be handled because the device is busy. This is
+              typically return while device is streaming, and an ioctl tried to
+              change something that would affect the stream, or would require the
+              usage of a hardware resource that was already allocated. The ioctl
+              must not be retried without performing another action to fix the
+              problem first (typically: stop the stream before retrying).</entry>
+      </row>
+      <row>
+       <entry>EFAULT</entry>
+       <entry>There was a failure while copying data from/to userspace,
+              probably caused by an invalid pointer reference.</entry>
+      </row>
+      <row>
+       <entry>EINVAL</entry>
+       <entry>One or more of the ioctl parameters are invalid or out of the
+              allowed range. This is a widely used error code. See the individual
+              ioctl requests for specific causes.</entry>
+      </row>
+      <row>
+        <entry>ENODEV</entry>
+       <entry>Device not found or was removed.</entry>
+      </row>
+      <row>
+       <entry>ENOMEM</entry>
+       <entry>There's not enough memory to handle the desired operation.</entry>
+      </row>
+      <row>
+       <entry>ENOTTY</entry>
+       <entry>The ioctl is not supported by the driver, actually meaning that
+              the required functionality is not available, or the file
+              descriptor is not for a media device.</entry>
+      </row>
+      <row>
+       <entry>ENOSPC</entry>
+       <entry>On USB devices, the stream ioctl's can return this error, meaning
+              that this request would overcommit the usb bandwidth reserved
+              for periodic transfers (up to 80% of the USB bandwidth).</entry>
+      </row>
+      <row>
+       <entry>ENOSYS or EOPNOTSUPP</entry>
+       <entry>Function not available for this device (dvb API only. Will likely
+              be replaced anytime soon by ENOTTY).</entry>
+      </row>
+      <row>
+       <entry>EPERM</entry>
+       <entry>Permission denied. Can be returned if the device needs write
+               permission, or some special capabilities is needed
+               (e. g. root)</entry>
+      </row>
+      <row>
+       <entry>EWOULDBLOCK</entry>
+       <entry>Operation would block. Used when the ioctl would need to wait
+              for an event, but the device was opened in non-blocking mode.</entry>
+      </row>
+    </tbody>
+  </tgroup>
+</table>
+
+<para>Note 1: ioctls may return other error codes. Since errors may have side
+effects such as a driver reset, applications should abort on unexpected errors.
+</para>
+
+<para>Note 2: Request-specific error codes are listed in the individual
+requests descriptions.</para>
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
new file mode 100644 (file)
index 0000000..c57d1ec
--- /dev/null
@@ -0,0 +1,1265 @@
+  <title>Input/Output</title>
+
+  <para>The V4L2 API defines several different methods to read from or
+write to a device. All drivers exchanging data with applications must
+support at least one of them.</para>
+
+  <para>The classic I/O method using the <function>read()</function>
+and <function>write()</function> function is automatically selected
+after opening a V4L2 device. When the driver does not support this
+method attempts to read or write will fail at any time.</para>
+
+  <para>Other methods must be negotiated. To select the streaming I/O
+method with memory mapped or user buffers applications call the
+&VIDIOC-REQBUFS; ioctl. The asynchronous I/O method is not defined
+yet.</para>
+
+  <para>Video overlay can be considered another I/O method, although
+the application does not directly receive the image data. It is
+selected by initiating video overlay with the &VIDIOC-S-FMT; ioctl.
+For more information see <xref linkend="overlay" />.</para>
+
+  <para>Generally exactly one I/O method, including overlay, is
+associated with each file descriptor. The only exceptions are
+applications not exchanging data with a driver ("panel applications",
+see <xref linkend="open" />) and drivers permitting simultaneous video capturing
+and overlay using the same file descriptor, for compatibility with V4L
+and earlier versions of V4L2.</para>
+
+  <para><constant>VIDIOC_S_FMT</constant> and
+<constant>VIDIOC_REQBUFS</constant> would permit this to some degree,
+but for simplicity drivers need not support switching the I/O method
+(after first switching away from read/write) other than by closing
+and reopening the device.</para>
+
+  <para>The following sections describe the various I/O methods in
+more detail.</para>
+
+  <section id="rw">
+    <title>Read/Write</title>
+
+    <para>Input and output devices support the
+<function>read()</function> and <function>write()</function> function,
+respectively, when the <constant>V4L2_CAP_READWRITE</constant> flag in
+the <structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl is set.</para>
+
+    <para>Drivers may need the CPU to copy the data, but they may also
+support DMA to or from user memory, so this I/O method is not
+necessarily less efficient than other methods merely exchanging buffer
+pointers. It is considered inferior though because no meta-information
+like frame counters or timestamps are passed. This information is
+necessary to recognize frame dropping and to synchronize with other
+data streams. However this is also the simplest I/O method, requiring
+little or no setup to exchange data. It permits command line stunts
+like this (the <application>vidctrl</application> tool is
+fictitious):</para>
+
+    <informalexample>
+      <screen>
+&gt; vidctrl /dev/video --input=0 --format=YUYV --size=352x288
+&gt; dd if=/dev/video of=myimage.422 bs=202752 count=1
+</screen>
+    </informalexample>
+
+    <para>To read from the device applications use the
+&func-read; function, to write the &func-write; function.
+Drivers must implement one I/O method if they
+exchange data with applications, but it need not be this.<footnote>
+       <para>It would be desirable if applications could depend on
+drivers supporting all I/O interfaces, but as much as the complex
+memory mapping I/O can be inadequate for some devices we have no
+reason to require this interface, which is most useful for simple
+applications capturing still images.</para>
+      </footnote> When reading or writing is supported, the driver
+must also support the &func-select; and &func-poll;
+function.<footnote>
+       <para>At the driver level <function>select()</function> and
+<function>poll()</function> are the same, and
+<function>select()</function> is too important to be optional.</para>
+      </footnote></para>
+  </section>
+
+  <section id="mmap">
+    <title>Streaming I/O (Memory Mapping)</title>
+
+    <para>Input and output devices support this I/O method when the
+<constant>V4L2_CAP_STREAMING</constant> flag in the
+<structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl is set. There are two
+streaming methods, to determine if the memory mapping flavor is
+supported applications must call the &VIDIOC-REQBUFS; ioctl.</para>
+
+    <para>Streaming is an I/O method where only pointers to buffers
+are exchanged between application and driver, the data itself is not
+copied. Memory mapping is primarily intended to map buffers in device
+memory into the application's address space. Device memory can be for
+example the video memory on a graphics card with a video capture
+add-on. However, being the most efficient I/O method available for a
+long time, many other drivers support streaming as well, allocating
+buffers in DMA-able main memory.</para>
+
+    <para>A driver can support many sets of buffers. Each set is
+identified by a unique buffer type value. The sets are independent and
+each set can hold a different type of data. To access different sets
+at the same time different file descriptors must be used.<footnote>
+       <para>One could use one file descriptor and set the buffer
+type field accordingly when calling &VIDIOC-QBUF; etc., but it makes
+the <function>select()</function> function ambiguous. We also like the
+clean approach of one file descriptor per logical stream. Video
+overlay for example is also a logical stream, although the CPU is not
+needed for continuous operation.</para>
+      </footnote></para>
+
+    <para>To allocate device buffers applications call the
+&VIDIOC-REQBUFS; ioctl with the desired number of buffers and buffer
+type, for example <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>.
+This ioctl can also be used to change the number of buffers or to free
+the allocated memory, provided none of the buffers are still
+mapped.</para>
+
+    <para>Before applications can access the buffers they must map
+them into their address space with the &func-mmap; function. The
+location of the buffers in device memory can be determined with the
+&VIDIOC-QUERYBUF; ioctl. In the single-planar API case, the
+<structfield>m.offset</structfield> and <structfield>length</structfield>
+returned in a &v4l2-buffer; are passed as sixth and second parameter to the
+<function>mmap()</function> function. When using the multi-planar API,
+struct &v4l2-buffer; contains an array of &v4l2-plane; structures, each
+containing its own <structfield>m.offset</structfield> and
+<structfield>length</structfield>. When using the multi-planar API, every
+plane of every buffer has to be mapped separately, so the number of
+calls to &func-mmap; should be equal to number of buffers times number of
+planes in each buffer. The offset and length values must not be modified.
+Remember, the buffers are allocated in physical memory, as opposed to virtual
+memory, which can be swapped out to disk. Applications should free the buffers
+as soon as possible with the &func-munmap; function.</para>
+
+    <example>
+      <title>Mapping buffers in the single-planar API</title>
+      <programlisting>
+&v4l2-requestbuffers; reqbuf;
+struct {
+       void *start;
+       size_t length;
+} *buffers;
+unsigned int i;
+
+memset(&amp;reqbuf, 0, sizeof(reqbuf));
+reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+reqbuf.memory = V4L2_MEMORY_MMAP;
+reqbuf.count = 20;
+
+if (-1 == ioctl (fd, &VIDIOC-REQBUFS;, &amp;reqbuf)) {
+       if (errno == EINVAL)
+               printf("Video capturing or mmap-streaming is not supported\n");
+       else
+               perror("VIDIOC_REQBUFS");
+
+       exit(EXIT_FAILURE);
+}
+
+/* We want at least five buffers. */
+
+if (reqbuf.count &lt; 5) {
+       /* You may need to free the buffers here. */
+       printf("Not enough buffer memory\n");
+       exit(EXIT_FAILURE);
+}
+
+buffers = calloc(reqbuf.count, sizeof(*buffers));
+assert(buffers != NULL);
+
+for (i = 0; i &lt; reqbuf.count; i++) {
+       &v4l2-buffer; buffer;
+
+       memset(&amp;buffer, 0, sizeof(buffer));
+       buffer.type = reqbuf.type;
+       buffer.memory = V4L2_MEMORY_MMAP;
+       buffer.index = i;
+
+       if (-1 == ioctl (fd, &VIDIOC-QUERYBUF;, &amp;buffer)) {
+               perror("VIDIOC_QUERYBUF");
+               exit(EXIT_FAILURE);
+       }
+
+       buffers[i].length = buffer.length; /* remember for munmap() */
+
+       buffers[i].start = mmap(NULL, buffer.length,
+                               PROT_READ | PROT_WRITE, /* recommended */
+                               MAP_SHARED,             /* recommended */
+                               fd, buffer.m.offset);
+
+       if (MAP_FAILED == buffers[i].start) {
+               /* If you do not exit here you should unmap() and free()
+                  the buffers mapped so far. */
+               perror("mmap");
+               exit(EXIT_FAILURE);
+       }
+}
+
+/* Cleanup. */
+
+for (i = 0; i &lt; reqbuf.count; i++)
+       munmap(buffers[i].start, buffers[i].length);
+      </programlisting>
+    </example>
+
+    <example>
+      <title>Mapping buffers in the multi-planar API</title>
+      <programlisting>
+&v4l2-requestbuffers; reqbuf;
+/* Our current format uses 3 planes per buffer */
+#define FMT_NUM_PLANES = 3
+
+struct {
+       void *start[FMT_NUM_PLANES];
+       size_t length[FMT_NUM_PLANES];
+} *buffers;
+unsigned int i, j;
+
+memset(&amp;reqbuf, 0, sizeof(reqbuf));
+reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+reqbuf.memory = V4L2_MEMORY_MMAP;
+reqbuf.count = 20;
+
+if (ioctl(fd, &VIDIOC-REQBUFS;, &amp;reqbuf) &lt; 0) {
+       if (errno == EINVAL)
+               printf("Video capturing or mmap-streaming is not supported\n");
+       else
+               perror("VIDIOC_REQBUFS");
+
+       exit(EXIT_FAILURE);
+}
+
+/* We want at least five buffers. */
+
+if (reqbuf.count &lt; 5) {
+       /* You may need to free the buffers here. */
+       printf("Not enough buffer memory\n");
+       exit(EXIT_FAILURE);
+}
+
+buffers = calloc(reqbuf.count, sizeof(*buffers));
+assert(buffers != NULL);
+
+for (i = 0; i &lt; reqbuf.count; i++) {
+       &v4l2-buffer; buffer;
+       &v4l2-plane; planes[FMT_NUM_PLANES];
+
+       memset(&amp;buffer, 0, sizeof(buffer));
+       buffer.type = reqbuf.type;
+       buffer.memory = V4L2_MEMORY_MMAP;
+       buffer.index = i;
+       /* length in struct v4l2_buffer in multi-planar API stores the size
+        * of planes array. */
+       buffer.length = FMT_NUM_PLANES;
+       buffer.m.planes = planes;
+
+       if (ioctl(fd, &VIDIOC-QUERYBUF;, &amp;buffer) &lt; 0) {
+               perror("VIDIOC_QUERYBUF");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Every plane has to be mapped separately */
+       for (j = 0; j &lt; FMT_NUM_PLANES; j++) {
+               buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */
+
+               buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
+                                PROT_READ | PROT_WRITE, /* recommended */
+                                MAP_SHARED,             /* recommended */
+                                fd, buffer.m.planes[j].m.offset);
+
+               if (MAP_FAILED == buffers[i].start[j]) {
+                       /* If you do not exit here you should unmap() and free()
+                          the buffers and planes mapped so far. */
+                       perror("mmap");
+                       exit(EXIT_FAILURE);
+               }
+       }
+}
+
+/* Cleanup. */
+
+for (i = 0; i &lt; reqbuf.count; i++)
+       for (j = 0; j &lt; FMT_NUM_PLANES; j++)
+               munmap(buffers[i].start[j], buffers[i].length[j]);
+      </programlisting>
+    </example>
+
+    <para>Conceptually streaming drivers maintain two buffer queues, an incoming
+and an outgoing queue. They separate the synchronous capture or output
+operation locked to a video clock from the application which is
+subject to random disk or network delays and preemption by
+other processes, thereby reducing the probability of data loss.
+The queues are organized as FIFOs, buffers will be
+output in the order enqueued in the incoming FIFO, and were
+captured in the order dequeued from the outgoing FIFO.</para>
+
+    <para>The driver may require a minimum number of buffers enqueued
+at all times to function, apart of this no limit exists on the number
+of buffers applications can enqueue in advance, or dequeue and
+process. They can also enqueue in a different order than buffers have
+been dequeued, and the driver can <emphasis>fill</emphasis> enqueued
+<emphasis>empty</emphasis> buffers in any order. <footnote>
+       <para>Random enqueue order permits applications processing
+images out of order (such as video codecs) to return buffers earlier,
+reducing the probability of data loss. Random fill order allows
+drivers to reuse buffers on a LIFO-basis, taking advantage of caches
+holding scatter-gather lists and the like.</para>
+      </footnote> The index number of a buffer (&v4l2-buffer;
+<structfield>index</structfield>) plays no role here, it only
+identifies the buffer.</para>
+
+    <para>Initially all mapped buffers are in dequeued state,
+inaccessible by the driver. For capturing applications it is customary
+to first enqueue all mapped buffers, then to start capturing and enter
+the read loop. Here the application waits until a filled buffer can be
+dequeued, and re-enqueues the buffer when the data is no longer
+needed. Output applications fill and enqueue buffers, when enough
+buffers are stacked up the output is started with
+<constant>VIDIOC_STREAMON</constant>. In the write loop, when
+the application runs out of free buffers, it must wait until an empty
+buffer can be dequeued and reused.</para>
+
+    <para>To enqueue and dequeue a buffer applications use the
+&VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl. The status of a buffer being
+mapped, enqueued, full or empty can be determined at any time using the
+&VIDIOC-QUERYBUF; ioctl. Two methods exist to suspend execution of the
+application until one or more buffers can be dequeued. By default
+<constant>VIDIOC_DQBUF</constant> blocks when no buffer is in the
+outgoing queue. When the <constant>O_NONBLOCK</constant> flag was
+given to the &func-open; function, <constant>VIDIOC_DQBUF</constant>
+returns immediately with an &EAGAIN; when no buffer is available. The
+&func-select; or &func-poll; function are always available.</para>
+
+    <para>To start and stop capturing or output applications call the
+&VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; ioctl. Note
+<constant>VIDIOC_STREAMOFF</constant> removes all buffers from both
+queues as a side effect. Since there is no notion of doing anything
+"now" on a multitasking system, if an application needs to synchronize
+with another event it should examine the &v4l2-buffer;
+<structfield>timestamp</structfield> of captured buffers, or set the
+field before enqueuing buffers for output.</para>
+
+    <para>Drivers implementing memory mapping I/O must
+support the <constant>VIDIOC_REQBUFS</constant>,
+<constant>VIDIOC_QUERYBUF</constant>,
+<constant>VIDIOC_QBUF</constant>, <constant>VIDIOC_DQBUF</constant>,
+<constant>VIDIOC_STREAMON</constant> and
+<constant>VIDIOC_STREAMOFF</constant> ioctl, the
+<function>mmap()</function>, <function>munmap()</function>,
+<function>select()</function> and <function>poll()</function>
+function.<footnote>
+       <para>At the driver level <function>select()</function> and
+<function>poll()</function> are the same, and
+<function>select()</function> is too important to be optional. The
+rest should be evident.</para>
+      </footnote></para>
+
+    <para>[capture example]</para>
+
+  </section>
+
+  <section id="userp">
+    <title>Streaming I/O (User Pointers)</title>
+
+    <para>Input and output devices support this I/O method when the
+<constant>V4L2_CAP_STREAMING</constant> flag in the
+<structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl is set. If the particular user
+pointer method (not only memory mapping) is supported must be
+determined by calling the &VIDIOC-REQBUFS; ioctl.</para>
+
+    <para>This I/O method combines advantages of the read/write and
+memory mapping methods. Buffers (planes) are allocated by the application
+itself, and can reside for example in virtual or shared memory. Only
+pointers to data are exchanged, these pointers and meta-information
+are passed in &v4l2-buffer; (or in &v4l2-plane; in the multi-planar API case).
+The driver must be switched into user pointer I/O mode by calling the
+&VIDIOC-REQBUFS; with the desired buffer type. No buffers (planes) are allocated
+beforehand, consequently they are not indexed and cannot be queried like mapped
+buffers with the <constant>VIDIOC_QUERYBUF</constant> ioctl.</para>
+
+    <example>
+      <title>Initiating streaming I/O with user pointers</title>
+
+      <programlisting>
+&v4l2-requestbuffers; reqbuf;
+
+memset (&amp;reqbuf, 0, sizeof (reqbuf));
+reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+reqbuf.memory = V4L2_MEMORY_USERPTR;
+
+if (ioctl (fd, &VIDIOC-REQBUFS;, &amp;reqbuf) == -1) {
+       if (errno == EINVAL)
+               printf ("Video capturing or user pointer streaming is not supported\n");
+       else
+               perror ("VIDIOC_REQBUFS");
+
+       exit (EXIT_FAILURE);
+}
+      </programlisting>
+    </example>
+
+    <para>Buffer (plane) addresses and sizes are passed on the fly with the
+&VIDIOC-QBUF; ioctl. Although buffers are commonly cycled,
+applications can pass different addresses and sizes at each
+<constant>VIDIOC_QBUF</constant> call. If required by the hardware the
+driver swaps memory pages within physical memory to create a
+continuous area of memory. This happens transparently to the
+application in the virtual memory subsystem of the kernel. When buffer
+pages have been swapped out to disk they are brought back and finally
+locked in physical memory for DMA.<footnote>
+       <para>We expect that frequently used buffers are typically not
+swapped out. Anyway, the process of swapping, locking or generating
+scatter-gather lists may be time consuming. The delay can be masked by
+the depth of the incoming buffer queue, and perhaps by maintaining
+caches assuming a buffer will be soon enqueued again. On the other
+hand, to optimize memory usage drivers can limit the number of buffers
+locked in advance and recycle the most recently used buffers first. Of
+course, the pages of empty buffers in the incoming queue need not be
+saved to disk. Output buffers must be saved on the incoming and
+outgoing queue because an application may share them with other
+processes.</para>
+      </footnote></para>
+
+    <para>Filled or displayed buffers are dequeued with the
+&VIDIOC-DQBUF; ioctl. The driver can unlock the memory pages at any
+time between the completion of the DMA and this ioctl. The memory is
+also unlocked when &VIDIOC-STREAMOFF; is called, &VIDIOC-REQBUFS;, or
+when the device is closed. Applications must take care not to free
+buffers without dequeuing. For once, the buffers remain locked until
+further, wasting physical memory. Second the driver will not be
+notified when the memory is returned to the application's free list
+and subsequently reused for other purposes, possibly completing the
+requested DMA and overwriting valuable data.</para>
+
+    <para>For capturing applications it is customary to enqueue a
+number of empty buffers, to start capturing and enter the read loop.
+Here the application waits until a filled buffer can be dequeued, and
+re-enqueues the buffer when the data is no longer needed. Output
+applications fill and enqueue buffers, when enough buffers are stacked
+up output is started. In the write loop, when the application
+runs out of free buffers it must wait until an empty buffer can be
+dequeued and reused. Two methods exist to suspend execution of the
+application until one or more buffers can be dequeued. By default
+<constant>VIDIOC_DQBUF</constant> blocks when no buffer is in the
+outgoing queue. When the <constant>O_NONBLOCK</constant> flag was
+given to the &func-open; function, <constant>VIDIOC_DQBUF</constant>
+returns immediately with an &EAGAIN; when no buffer is available. The
+&func-select; or &func-poll; function are always available.</para>
+
+    <para>To start and stop capturing or output applications call the
+&VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; ioctl. Note
+<constant>VIDIOC_STREAMOFF</constant> removes all buffers from both
+queues and unlocks all buffers as a side effect. Since there is no
+notion of doing anything "now" on a multitasking system, if an
+application needs to synchronize with another event it should examine
+the &v4l2-buffer; <structfield>timestamp</structfield> of captured
+buffers, or set the field before enqueuing buffers for output.</para>
+
+    <para>Drivers implementing user pointer I/O must
+support the <constant>VIDIOC_REQBUFS</constant>,
+<constant>VIDIOC_QBUF</constant>, <constant>VIDIOC_DQBUF</constant>,
+<constant>VIDIOC_STREAMON</constant> and
+<constant>VIDIOC_STREAMOFF</constant> ioctl, the
+<function>select()</function> and <function>poll()</function> function.<footnote>
+       <para>At the driver level <function>select()</function> and
+<function>poll()</function> are the same, and
+<function>select()</function> is too important to be optional. The
+rest should be evident.</para>
+      </footnote></para>
+  </section>
+
+  <section id="async">
+    <title>Asynchronous I/O</title>
+
+    <para>This method is not defined yet.</para>
+  </section>
+
+  <section id="buffer">
+    <title>Buffers</title>
+
+    <para>A buffer contains data exchanged by application and
+driver using one of the Streaming I/O methods. In the multi-planar API, the
+data is held in planes, while the buffer structure acts as a container
+for the planes. Only pointers to buffers (planes) are exchanged, the data
+itself is not copied. These pointers, together with meta-information like
+timestamps or field parity, are stored in a struct
+<structname>v4l2_buffer</structname>, argument to
+the &VIDIOC-QUERYBUF;, &VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl.
+In the multi-planar API, some plane-specific members of struct
+<structname>v4l2_buffer</structname>, such as pointers and sizes for each
+plane, are stored in struct <structname>v4l2_plane</structname> instead.
+In that case, struct <structname>v4l2_buffer</structname> contains an array of
+plane structures.</para>
+
+      <para>Nominally timestamps refer to the first data byte transmitted.
+In practice however the wide range of hardware covered by the V4L2 API
+limits timestamp accuracy. Often an interrupt routine will
+sample the system clock shortly after the field or frame was stored
+completely in memory. So applications must expect a constant
+difference up to one field or frame period plus a small (few scan
+lines) random error. The delay and error can be much
+larger due to compression or transmission over an external bus when
+the frames are not properly stamped by the sender. This is frequently
+the case with USB cameras. Here timestamps refer to the instant the
+field or frame was received by the driver, not the capture time. These
+devices identify by not enumerating any video standards, see <xref
+linkend="standard" />.</para>
+
+      <para>Similar limitations apply to output timestamps. Typically
+the video hardware locks to a clock controlling the video timing, the
+horizontal and vertical synchronization pulses. At some point in the
+line sequence, possibly the vertical blanking, an interrupt routine
+samples the system clock, compares against the timestamp and programs
+the hardware to repeat the previous field or frame, or to display the
+buffer contents.</para>
+
+      <para>Apart of limitations of the video device and natural
+inaccuracies of all clocks, it should be noted system time itself is
+not perfectly stable. It can be affected by power saving cycles,
+warped to insert leap seconds, or even turned back or forth by the
+system administrator affecting long term measurements. <footnote>
+         <para>Since no other Linux multimedia
+API supports unadjusted time it would be foolish to introduce here. We
+must use a universally supported clock to synchronize different media,
+hence time of day.</para>
+       </footnote></para>
+
+    <table frame="none" pgwide="1" id="v4l2-buffer">
+      <title>struct <structname>v4l2_buffer</structname></title>
+      <tgroup cols="4">
+       &cs-ustr;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry></entry>
+           <entry>Number of the buffer, set by the application. This
+field is only used for <link linkend="mmap">memory mapping</link> I/O
+and can range from zero to the number of buffers allocated
+with the &VIDIOC-REQBUFS; ioctl (&v4l2-requestbuffers; <structfield>count</structfield>) minus one.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-buf-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry>Type of the buffer, same as &v4l2-format;
+<structfield>type</structfield> or &v4l2-requestbuffers;
+<structfield>type</structfield>, set by the application.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>bytesused</structfield></entry>
+           <entry></entry>
+           <entry>The number of bytes occupied by the data in the
+buffer. It depends on the negotiated data format and may change with
+each buffer for compressed variable size data like JPEG images.
+Drivers must set this field when <structfield>type</structfield>
+refers to an input stream, applications when an output stream.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry></entry>
+           <entry>Flags set by the application or driver, see <xref
+linkend="buffer-flags" />.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-field;</entry>
+           <entry><structfield>field</structfield></entry>
+           <entry></entry>
+           <entry>Indicates the field order of the image in the
+buffer, see <xref linkend="v4l2-field" />. This field is not used when
+the buffer contains VBI data. Drivers must set it when
+<structfield>type</structfield> refers to an input stream,
+applications when an output stream.</entry>
+         </row>
+         <row>
+           <entry>struct timeval</entry>
+           <entry><structfield>timestamp</structfield></entry>
+           <entry></entry>
+           <entry><para>For input streams this is the
+system time (as returned by the <function>gettimeofday()</function>
+function) when the first data byte was captured. For output streams
+the data will not be displayed before this time, secondary to the
+nominal frame rate determined by the current video standard in
+enqueued order. Applications can for example zero this field to
+display frames as soon as possible. The driver stores the time at
+which the first data byte was actually sent out in the
+<structfield>timestamp</structfield> field. This permits
+applications to monitor the drift between the video and system
+clock.</para></entry>
+         </row>
+         <row>
+           <entry>&v4l2-timecode;</entry>
+           <entry><structfield>timecode</structfield></entry>
+           <entry></entry>
+           <entry>When <structfield>type</structfield> is
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> and the
+<constant>V4L2_BUF_FLAG_TIMECODE</constant> flag is set in
+<structfield>flags</structfield>, this structure contains a frame
+timecode. In <link linkend="v4l2-field">V4L2_FIELD_ALTERNATE</link>
+mode the top and bottom field contain the same timecode.
+Timecodes are intended to help video editing and are typically recorded on
+video tapes, but also embedded in compressed formats like MPEG. This
+field is independent of the <structfield>timestamp</structfield> and
+<structfield>sequence</structfield> fields.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>sequence</structfield></entry>
+           <entry></entry>
+           <entry>Set by the driver, counting the frames in the
+sequence.</entry>
+         </row>
+         <row>
+           <entry spanname="hspan"><para>In <link
+linkend="v4l2-field">V4L2_FIELD_ALTERNATE</link> mode the top and
+bottom field have the same sequence number. The count starts at zero
+and includes dropped or repeated frames. A dropped frame was received
+by an input device but could not be stored due to lack of free buffer
+space. A repeated frame was displayed again by an output device
+because the application did not pass new data in
+time.</para><para>Note this may count the frames received
+e.g. over USB, without taking into account the frames dropped by the
+remote hardware due to limited compression throughput or bus
+bandwidth. These devices identify by not enumerating any video
+standards, see <xref linkend="standard" />.</para></entry>
+         </row>
+         <row>
+           <entry>&v4l2-memory;</entry>
+           <entry><structfield>memory</structfield></entry>
+           <entry></entry>
+           <entry>This field must be set by applications and/or drivers
+in accordance with the selected I/O method.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry><structfield>m</structfield></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>offset</structfield></entry>
+           <entry>For the single-planar API and when
+<structfield>memory</structfield> is <constant>V4L2_MEMORY_MMAP</constant> this
+is the offset of the buffer from the start of the device memory. The value is
+returned by the driver and apart of serving as parameter to the &func-mmap;
+function not useful for applications. See <xref linkend="mmap" /> for details
+         </entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>unsigned long</entry>
+           <entry><structfield>userptr</structfield></entry>
+           <entry>For the single-planar API and when
+<structfield>memory</structfield> is <constant>V4L2_MEMORY_USERPTR</constant>
+this is a pointer to the buffer (casted to unsigned long type) in virtual
+memory, set by the application. See <xref linkend="userp" /> for details.
+           </entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct v4l2_plane</entry>
+           <entry><structfield>*planes</structfield></entry>
+           <entry>When using the multi-planar API, contains a userspace pointer
+           to an array of &v4l2-plane;. The size of the array should be put
+           in the <structfield>length</structfield> field of this
+           <structname>v4l2_buffer</structname> structure.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>length</structfield></entry>
+           <entry></entry>
+           <entry>Size of the buffer (not the payload) in bytes for the
+           single-planar API. For the multi-planar API should contain the
+           number of elements in the <structfield>planes</structfield> array.
+           </entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>input</structfield></entry>
+           <entry></entry>
+           <entry>Some video capture drivers support rapid and
+synchronous video input changes, a function useful for example in
+video surveillance applications. For this purpose applications set the
+<constant>V4L2_BUF_FLAG_INPUT</constant> flag, and this field to the
+number of a video input as in &v4l2-input; field
+<structfield>index</structfield>.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield></entry>
+           <entry></entry>
+           <entry>A place holder for future extensions and custom
+(driver defined) buffer types
+<constant>V4L2_BUF_TYPE_PRIVATE</constant> and higher. Applications
+should set this to 0.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-plane">
+      <title>struct <structname>v4l2_plane</structname></title>
+      <tgroup cols="4">
+        &cs-ustr;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>bytesused</structfield></entry>
+           <entry></entry>
+           <entry>The number of bytes occupied by data in the plane
+           (its payload).</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>length</structfield></entry>
+           <entry></entry>
+           <entry>Size in bytes of the plane (not its payload).</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry><structfield>m</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>mem_offset</structfield></entry>
+           <entry>When the memory type in the containing &v4l2-buffer; is
+             <constant>V4L2_MEMORY_MMAP</constant>, this is the value that
+             should be passed to &func-mmap;, similar to the
+             <structfield>offset</structfield> field in &v4l2-buffer;.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__unsigned long</entry>
+           <entry><structfield>userptr</structfield></entry>
+           <entry>When the memory type in the containing &v4l2-buffer; is
+             <constant>V4L2_MEMORY_USERPTR</constant>, this is a userspace
+             pointer to the memory allocated for this plane by an application.
+             </entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>data_offset</structfield></entry>
+           <entry></entry>
+           <entry>Offset in bytes to video data in the plane, if applicable.
+           </entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved[11]</structfield></entry>
+           <entry></entry>
+           <entry>Reserved for future use. Should be zeroed by an
+           application.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-buf-type">
+      <title>enum v4l2_buf_type</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant></entry>
+           <entry>1</entry>
+           <entry>Buffer of a single-planar video capture stream, see <xref
+               linkend="capture" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>
+           </entry>
+           <entry>9</entry>
+           <entry>Buffer of a multi-planar video capture stream, see <xref
+               linkend="capture" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant></entry>
+           <entry>2</entry>
+           <entry>Buffer of a single-planar video output stream, see <xref
+               linkend="output" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>
+           </entry>
+           <entry>10</entry>
+           <entry>Buffer of a multi-planar video output stream, see <xref
+               linkend="output" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant></entry>
+           <entry>3</entry>
+           <entry>Buffer for video overlay, see <xref linkend="overlay" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_VBI_CAPTURE</constant></entry>
+           <entry>4</entry>
+           <entry>Buffer of a raw VBI capture stream, see <xref
+               linkend="raw-vbi" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant></entry>
+           <entry>5</entry>
+           <entry>Buffer of a raw VBI output stream, see <xref
+               linkend="raw-vbi" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant></entry>
+           <entry>6</entry>
+           <entry>Buffer of a sliced VBI capture stream, see <xref
+               linkend="sliced" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant></entry>
+           <entry>7</entry>
+           <entry>Buffer of a sliced VBI output stream, see <xref
+               linkend="sliced" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant></entry>
+           <entry>8</entry>
+           <entry>Buffer for video output overlay (OSD), see <xref
+               linkend="osd" />. Status: <link
+linkend="experimental">Experimental</link>.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_TYPE_PRIVATE</constant></entry>
+           <entry>0x80</entry>
+         <entry>This and higher values are reserved for custom
+(driver defined) buffer types.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="buffer-flags">
+      <title>Buffer Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_BUF_FLAG_MAPPED</constant></entry>
+           <entry>0x0001</entry>
+           <entry>The buffer resides in device memory and has been mapped
+into the application's address space, see <xref linkend="mmap" /> for details.
+Drivers set or clear this flag when the
+<link linkend="vidioc-querybuf">VIDIOC_QUERYBUF</link>, <link
+         linkend="vidioc-qbuf">VIDIOC_QBUF</link> or <link
+         linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl is called. Set by the driver.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_FLAG_QUEUED</constant></entry>
+           <entry>0x0002</entry>
+         <entry>Internally drivers maintain two buffer queues, an
+incoming and outgoing queue. When this flag is set, the buffer is
+currently on the incoming queue. It automatically moves to the
+outgoing queue after the buffer has been filled (capture devices) or
+displayed (output devices). Drivers set or clear this flag when the
+<constant>VIDIOC_QUERYBUF</constant> ioctl is called. After
+(successful) calling the <constant>VIDIOC_QBUF </constant>ioctl it is
+always set and after <constant>VIDIOC_DQBUF</constant> always
+cleared.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_FLAG_DONE</constant></entry>
+           <entry>0x0004</entry>
+           <entry>When this flag is set, the buffer is currently on
+the outgoing queue, ready to be dequeued from the driver. Drivers set
+or clear this flag when the <constant>VIDIOC_QUERYBUF</constant> ioctl
+is called. After calling the <constant>VIDIOC_QBUF</constant> or
+<constant>VIDIOC_DQBUF</constant> it is always cleared. Of course a
+buffer cannot be on both queues at the same time, the
+<constant>V4L2_BUF_FLAG_QUEUED</constant> and
+<constant>V4L2_BUF_FLAG_DONE</constant> flag are mutually exclusive.
+They can be both cleared however, then the buffer is in "dequeued"
+state, in the application domain to say so.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_FLAG_ERROR</constant></entry>
+           <entry>0x0040</entry>
+           <entry>When this flag is set, the buffer has been dequeued
+           successfully, although the data might have been corrupted.
+           This is recoverable, streaming may continue as normal and
+           the buffer may be reused normally.
+           Drivers set this flag when the <constant>VIDIOC_DQBUF</constant>
+           ioctl is called.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_FLAG_KEYFRAME</constant></entry>
+           <entry>0x0008</entry>
+         <entry>Drivers set or clear this flag when calling the
+<constant>VIDIOC_DQBUF</constant> ioctl. It may be set by video
+capture devices when the buffer contains a compressed image which is a
+key frame (or field), &ie; can be decompressed on its own.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_FLAG_PFRAME</constant></entry>
+           <entry>0x0010</entry>
+           <entry>Similar to <constant>V4L2_BUF_FLAG_KEYFRAME</constant>
+this flags predicted frames or fields which contain only differences to a
+previous key frame.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_FLAG_BFRAME</constant></entry>
+           <entry>0x0020</entry>
+           <entry>Similar to <constant>V4L2_BUF_FLAG_PFRAME</constant>
+       this is a bidirectional predicted frame or field. [ooc tbd]</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_FLAG_TIMECODE</constant></entry>
+           <entry>0x0100</entry>
+           <entry>The <structfield>timecode</structfield> field is valid.
+Drivers set or clear this flag when the <constant>VIDIOC_DQBUF</constant>
+ioctl is called.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_BUF_FLAG_INPUT</constant></entry>
+           <entry>0x0200</entry>
+           <entry>The <structfield>input</structfield> field is valid.
+Applications set or clear this flag before calling the
+<constant>VIDIOC_QBUF</constant> ioctl.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-memory">
+      <title>enum v4l2_memory</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_MEMORY_MMAP</constant></entry>
+           <entry>1</entry>
+           <entry>The buffer is used for <link linkend="mmap">memory
+mapping</link> I/O.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_MEMORY_USERPTR</constant></entry>
+           <entry>2</entry>
+           <entry>The buffer is used for <link linkend="userp">user
+pointer</link> I/O.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_MEMORY_OVERLAY</constant></entry>
+           <entry>3</entry>
+           <entry>[to do]</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <section>
+      <title>Timecodes</title>
+
+      <para>The <structname>v4l2_timecode</structname> structure is
+designed to hold a <xref linkend="smpte12m" /> or similar timecode.
+(struct <structname>timeval</structname> timestamps are stored in
+&v4l2-buffer; field <structfield>timestamp</structfield>.)</para>
+
+      <table frame="none" pgwide="1" id="v4l2-timecode">
+       <title>struct <structname>v4l2_timecode</structname></title>
+       <tgroup cols="3">
+         &cs-str;
+         <tbody valign="top">
+           <row>
+             <entry>__u32</entry>
+             <entry><structfield>type</structfield></entry>
+             <entry>Frame rate the timecodes are based on, see <xref
+                 linkend="timecode-type" />.</entry>
+           </row>
+           <row>
+             <entry>__u32</entry>
+             <entry><structfield>flags</structfield></entry>
+             <entry>Timecode flags, see <xref linkend="timecode-flags" />.</entry>
+           </row>
+           <row>
+             <entry>__u8</entry>
+             <entry><structfield>frames</structfield></entry>
+             <entry>Frame count, 0 ... 23/24/29/49/59, depending on the
+           type of timecode.</entry>
+           </row>
+           <row>
+             <entry>__u8</entry>
+             <entry><structfield>seconds</structfield></entry>
+             <entry>Seconds count, 0 ... 59. This is a binary, not BCD number.</entry>
+           </row>
+           <row>
+             <entry>__u8</entry>
+             <entry><structfield>minutes</structfield></entry>
+             <entry>Minutes count, 0 ... 59. This is a binary, not BCD number.</entry>
+           </row>
+           <row>
+             <entry>__u8</entry>
+             <entry><structfield>hours</structfield></entry>
+             <entry>Hours count, 0 ... 29. This is a binary, not BCD number.</entry>
+           </row>
+           <row>
+             <entry>__u8</entry>
+             <entry><structfield>userbits</structfield>[4]</entry>
+             <entry>The "user group" bits from the timecode.</entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+
+      <table frame="none" pgwide="1" id="timecode-type">
+       <title>Timecode Types</title>
+       <tgroup cols="3">
+       &cs-def;
+         <tbody valign="top">
+           <row>
+             <entry><constant>V4L2_TC_TYPE_24FPS</constant></entry>
+             <entry>1</entry>
+             <entry>24 frames per second, i.&nbsp;e. film.</entry>
+           </row>
+           <row>
+             <entry><constant>V4L2_TC_TYPE_25FPS</constant></entry>
+             <entry>2</entry>
+             <entry>25 frames per second, &ie; PAL or SECAM video.</entry>
+           </row>
+           <row>
+             <entry><constant>V4L2_TC_TYPE_30FPS</constant></entry>
+             <entry>3</entry>
+             <entry>30 frames per second, &ie; NTSC video.</entry>
+           </row>
+           <row>
+             <entry><constant>V4L2_TC_TYPE_50FPS</constant></entry>
+             <entry>4</entry>
+             <entry></entry>
+           </row>
+           <row>
+             <entry><constant>V4L2_TC_TYPE_60FPS</constant></entry>
+             <entry>5</entry>
+             <entry></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+
+      <table frame="none" pgwide="1" id="timecode-flags">
+       <title>Timecode Flags</title>
+       <tgroup cols="3">
+       &cs-def;
+         <tbody valign="top">
+           <row>
+             <entry><constant>V4L2_TC_FLAG_DROPFRAME</constant></entry>
+             <entry>0x0001</entry>
+             <entry>Indicates "drop frame" semantics for counting frames
+in 29.97 fps material. When set, frame numbers 0 and 1 at the start of
+each minute, except minutes 0, 10, 20, 30, 40, 50 are omitted from the
+count.</entry>
+           </row>
+           <row>
+             <entry><constant>V4L2_TC_FLAG_COLORFRAME</constant></entry>
+             <entry>0x0002</entry>
+             <entry>The "color frame" flag.</entry>
+           </row>
+           <row>
+             <entry><constant>V4L2_TC_USERBITS_field</constant></entry>
+             <entry>0x000C</entry>
+             <entry>Field mask for the "binary group flags".</entry>
+           </row>
+           <row>
+             <entry><constant>V4L2_TC_USERBITS_USERDEFINED</constant></entry>
+             <entry>0x0000</entry>
+             <entry>Unspecified format.</entry>
+           </row>
+           <row>
+             <entry><constant>V4L2_TC_USERBITS_8BITCHARS</constant></entry>
+             <entry>0x0008</entry>
+             <entry>8-bit ISO characters.</entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
+  </section>
+
+  <section id="field-order">
+    <title>Field Order</title>
+
+    <para>We have to distinguish between progressive and interlaced
+video. Progressive video transmits all lines of a video image
+sequentially. Interlaced video divides an image into two fields,
+containing only the odd and even lines of the image, respectively.
+Alternating the so called odd and even field are transmitted, and due
+to a small delay between fields a cathode ray TV displays the lines
+interleaved, yielding the original frame. This curious technique was
+invented because at refresh rates similar to film the image would
+fade out too quickly. Transmitting fields reduces the flicker without
+the necessity of doubling the frame rate and with it the bandwidth
+required for each channel.</para>
+
+    <para>It is important to understand a video camera does not expose
+one frame at a time, merely transmitting the frames separated into
+fields. The fields are in fact captured at two different instances in
+time. An object on screen may well move between one field and the
+next. For applications analysing motion it is of paramount importance
+to recognize which field of a frame is older, the <emphasis>temporal
+order</emphasis>.</para>
+
+    <para>When the driver provides or accepts images field by field
+rather than interleaved, it is also important applications understand
+how the fields combine to frames. We distinguish between top (aka odd) and
+bottom (aka even) fields, the <emphasis>spatial order</emphasis>: The first line
+of the top field is the first line of an interlaced frame, the first
+line of the bottom field is the second line of that frame.</para>
+
+    <para>However because fields were captured one after the other,
+arguing whether a frame commences with the top or bottom field is
+pointless. Any two successive top and bottom, or bottom and top fields
+yield a valid frame. Only when the source was progressive to begin
+with, &eg; when transferring film to video, two fields may come from
+the same frame, creating a natural order.</para>
+
+    <para>Counter to intuition the top field is not necessarily the
+older field. Whether the older field contains the top or bottom lines
+is a convention determined by the video standard. Hence the
+distinction between temporal and spatial order of fields. The diagrams
+below should make this clearer.</para>
+
+    <para>All video capture and output devices must report the current
+field order. Some drivers may permit the selection of a different
+order, to this end applications initialize the
+<structfield>field</structfield> field of &v4l2-pix-format; before
+calling the &VIDIOC-S-FMT; ioctl. If this is not desired it should
+have the value <constant>V4L2_FIELD_ANY</constant> (0).</para>
+
+    <table frame="none" pgwide="1" id="v4l2-field">
+      <title>enum v4l2_field</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_FIELD_ANY</constant></entry>
+           <entry>0</entry>
+           <entry>Applications request this field order when any
+one of the <constant>V4L2_FIELD_NONE</constant>,
+<constant>V4L2_FIELD_TOP</constant>,
+<constant>V4L2_FIELD_BOTTOM</constant>, or
+<constant>V4L2_FIELD_INTERLACED</constant> formats is acceptable.
+Drivers choose depending on hardware capabilities or e.&nbsp;g. the
+requested image size, and return the actual field order. &v4l2-buffer;
+<structfield>field</structfield> can never be
+<constant>V4L2_FIELD_ANY</constant>.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FIELD_NONE</constant></entry>
+           <entry>1</entry>
+           <entry>Images are in progressive format, not interlaced.
+The driver may also indicate this order when it cannot distinguish
+between <constant>V4L2_FIELD_TOP</constant> and
+<constant>V4L2_FIELD_BOTTOM</constant>.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FIELD_TOP</constant></entry>
+           <entry>2</entry>
+           <entry>Images consist of the top (aka odd) field only.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FIELD_BOTTOM</constant></entry>
+           <entry>3</entry>
+           <entry>Images consist of the bottom (aka even) field only.
+Applications may wish to prevent a device from capturing interlaced
+images because they will have "comb" or "feathering" artefacts around
+moving objects.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FIELD_INTERLACED</constant></entry>
+           <entry>4</entry>
+           <entry>Images contain both fields, interleaved line by
+line. The temporal order of the fields (whether the top or bottom
+field is first transmitted) depends on the current video standard.
+M/NTSC transmits the bottom field first, all other standards the top
+field first.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FIELD_SEQ_TB</constant></entry>
+           <entry>5</entry>
+           <entry>Images contain both fields, the top field lines
+are stored first in memory, immediately followed by the bottom field
+lines. Fields are always stored in temporal order, the older one first
+in memory. Image sizes refer to the frame, not fields.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FIELD_SEQ_BT</constant></entry>
+           <entry>6</entry>
+           <entry>Images contain both fields, the bottom field
+lines are stored first in memory, immediately followed by the top
+field lines. Fields are always stored in temporal order, the older one
+first in memory. Image sizes refer to the frame, not fields.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FIELD_ALTERNATE</constant></entry>
+           <entry>7</entry>
+           <entry>The two fields of a frame are passed in separate
+buffers, in temporal order, &ie; the older one first. To indicate the field
+parity (whether the current field is a top or bottom field) the driver
+or application, depending on data direction, must set &v4l2-buffer;
+<structfield>field</structfield> to
+<constant>V4L2_FIELD_TOP</constant> or
+<constant>V4L2_FIELD_BOTTOM</constant>. Any two successive fields pair
+to build a frame. If fields are successive, without any dropped fields
+between them (fields can drop individually), can be determined from
+the &v4l2-buffer; <structfield>sequence</structfield> field. Image
+sizes refer to the frame, not fields. This format cannot be selected
+when using the read/write I/O method.<!-- Where it's indistinguishable
+from V4L2_FIELD_SEQ_*. --></entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FIELD_INTERLACED_TB</constant></entry>
+           <entry>8</entry>
+           <entry>Images contain both fields, interleaved line by
+line, top field first. The top field is transmitted first.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FIELD_INTERLACED_BT</constant></entry>
+           <entry>9</entry>
+           <entry>Images contain both fields, interleaved line by
+line, top field first. The bottom field is transmitted first.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <figure id="fieldseq-tb">
+       <title>Field Order, Top Field First Transmitted</title>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="fieldseq_tb.pdf" format="PS" />
+         </imageobject>
+         <imageobject>
+           <imagedata fileref="fieldseq_tb.gif" format="GIF" />
+         </imageobject>
+       </mediaobject>
+    </figure>
+
+    <figure id="fieldseq-bt">
+       <title>Field Order, Bottom Field First Transmitted</title>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="fieldseq_bt.pdf" format="PS" />
+         </imageobject>
+         <imageobject>
+           <imagedata fileref="fieldseq_bt.gif" format="GIF" />
+         </imageobject>
+       </mediaobject>
+    </figure>
+  </section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/keytable.c.xml b/Documentation/DocBook/media/v4l/keytable.c.xml
new file mode 100644 (file)
index 0000000..d53254a
--- /dev/null
@@ -0,0 +1,172 @@
+<programlisting>
+/* keytable.c - This program allows checking/replacing keys at IR
+
+   Copyright (C) 2006-2009 Mauro Carvalho Chehab &lt;mchehab@infradead.org&gt;
+
+   This 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.
+ */
+
+#include &lt;ctype.h&gt;
+#include &lt;errno.h&gt;
+#include &lt;fcntl.h&gt;
+#include &lt;stdio.h&gt;
+#include &lt;stdlib.h&gt;
+#include &lt;string.h&gt;
+#include &lt;linux/input.h&gt;
+#include &lt;sys/ioctl.h&gt;
+
+#include "parse.h"
+
+void prtcode (int *codes)
+{
+        struct parse_key *p;
+
+        for (p=keynames;p-&gt;name!=NULL;p++) {
+                if (p-&gt;value == (unsigned)codes[1]) {
+                        printf("scancode 0x%04x = %s (0x%02x)\n", codes[0], p-&gt;name, codes[1]);
+                        return;
+                }
+        }
+
+        if (isprint (codes[1]))
+                printf("scancode %d = '%c' (0x%02x)\n", codes[0], codes[1], codes[1]);
+        else
+                printf("scancode %d = 0x%02x\n", codes[0], codes[1]);
+}
+
+int parse_code(char *string)
+{
+        struct parse_key *p;
+
+        for (p=keynames;p-&gt;name!=NULL;p++) {
+                if (!strcasecmp(p-&gt;name, string)) {
+                        return p-&gt;value;
+                }
+        }
+        return -1;
+}
+
+int main (int argc, char *argv[])
+{
+        int fd;
+        unsigned int i, j;
+        int codes[2];
+
+        if (argc&lt;2 || argc&gt;4) {
+                printf ("usage: %s &lt;device&gt; to get table; or\n"
+                        "       %s &lt;device&gt; &lt;scancode&gt; &lt;keycode&gt;\n"
+                        "       %s &lt;device&gt; &lt;keycode_file&gt;\n",*argv,*argv,*argv);
+                return -1;
+        }
+
+        if ((fd = open(argv[1], O_RDONLY)) &lt; 0) {
+                perror("Couldn't open input device");
+                return(-1);
+        }
+
+        if (argc==4) {
+                int value;
+
+                value=parse_code(argv[3]);
+
+                if (value==-1) {
+                        value = strtol(argv[3], NULL, 0);
+                        if (errno)
+                                perror("value");
+                }
+
+                codes [0] = (unsigned) strtol(argv[2], NULL, 0);
+                codes [1] = (unsigned) value;
+
+                if(ioctl(fd, EVIOCSKEYCODE, codes))
+                        perror ("EVIOCSKEYCODE");
+
+                if(ioctl(fd, EVIOCGKEYCODE, codes)==0)
+                        prtcode(codes);
+                return 0;
+        }
+
+        if (argc==3) {
+                FILE *fin;
+                int value;
+                char *scancode, *keycode, s[2048];
+
+                fin=fopen(argv[2],"r");
+                if (fin==NULL) {
+                        perror ("opening keycode file");
+                        return -1;
+                }
+
+                /* Clears old table */
+                for (j = 0; j &lt; 256; j++) {
+                        for (i = 0; i &lt; 256; i++) {
+                                codes[0] = (j &lt;&lt; 8) | i;
+                                codes[1] = KEY_RESERVED;
+                                ioctl(fd, EVIOCSKEYCODE, codes);
+                        }
+                }
+
+                while (fgets(s,sizeof(s),fin)) {
+                        scancode=strtok(s,"\n\t =:");
+                        if (!scancode) {
+                                perror ("parsing input file scancode");
+                                return -1;
+                        }
+                        if (!strcasecmp(scancode, "scancode")) {
+                                scancode = strtok(NULL,"\n\t =:");
+                                if (!scancode) {
+                                        perror ("parsing input file scancode");
+                                        return -1;
+                                }
+                        }
+
+                        keycode=strtok(NULL,"\n\t =:(");
+                        if (!keycode) {
+                                perror ("parsing input file keycode");
+                                return -1;
+                        }
+
+                        // printf ("parsing %s=%s:", scancode, keycode);
+                        value=parse_code(keycode);
+                        // printf ("\tvalue=%d\n",value);
+
+                        if (value==-1) {
+                                value = strtol(keycode, NULL, 0);
+                                if (errno)
+                                        perror("value");
+                        }
+
+                        codes [0] = (unsigned) strtol(scancode, NULL, 0);
+                        codes [1] = (unsigned) value;
+
+                        // printf("\t%04x=%04x\n",codes[0], codes[1]);
+                        if(ioctl(fd, EVIOCSKEYCODE, codes)) {
+                                fprintf(stderr, "Setting scancode 0x%04x with 0x%04x via ",codes[0], codes[1]);
+                                perror ("EVIOCSKEYCODE");
+                        }
+
+                        if(ioctl(fd, EVIOCGKEYCODE, codes)==0)
+                                prtcode(codes);
+                }
+                return 0;
+        }
+
+        /* Get scancode table */
+        for (j = 0; j &lt; 256; j++) {
+                for (i = 0; i &lt; 256; i++) {
+                        codes[0] = (j &lt;&lt; 8) | i;
+                        if (!ioctl(fd, EVIOCGKEYCODE, codes) &amp;&amp; codes[1] != KEY_RESERVED)
+                                prtcode(codes);
+                }
+        }
+        return 0;
+}
+
+</programlisting>
diff --git a/Documentation/DocBook/media/v4l/libv4l.xml b/Documentation/DocBook/media/v4l/libv4l.xml
new file mode 100644 (file)
index 0000000..3cb10ec
--- /dev/null
@@ -0,0 +1,167 @@
+<title>Libv4l Userspace Library</title>
+<section id="libv4l-introduction">
+       <title>Introduction</title>
+
+       <para>libv4l is a collection of libraries which adds a thin abstraction
+layer on top of video4linux2 devices. The purpose of this (thin) layer
+is to make it easy for application writers to support a wide variety of
+devices without having to write separate code for different devices in the
+same class.</para>
+<para>An example of using libv4l is provided by
+<link linkend='v4l2grab-example'>v4l2grab</link>.
+</para>
+
+       <para>libv4l consists of 3 different libraries:</para>
+       <section>
+               <title>libv4lconvert</title>
+
+               <para>libv4lconvert is a library that converts several
+different pixelformats found in V4L2 drivers into a few common RGB and
+YUY formats.</para>
+               <para>It currently accepts the following V4L2 driver formats:
+<link linkend="V4L2-PIX-FMT-BGR24"><constant>V4L2_PIX_FMT_BGR24</constant></link>,
+<link linkend="V4L2-PIX-FMT-HM12"><constant>V4L2_PIX_FMT_HM12</constant></link>,
+<link linkend="V4L2-PIX-FMT-JPEG"><constant>V4L2_PIX_FMT_JPEG</constant></link>,
+<link linkend="V4L2-PIX-FMT-MJPEG"><constant>V4L2_PIX_FMT_MJPEG</constant></link>,
+<link linkend="V4L2-PIX-FMT-MR97310A"><constant>V4L2_PIX_FMT_MR97310A</constant></link>,
+<link linkend="V4L2-PIX-FMT-OV511"><constant>V4L2_PIX_FMT_OV511</constant></link>,
+<link linkend="V4L2-PIX-FMT-OV518"><constant>V4L2_PIX_FMT_OV518</constant></link>,
+<link linkend="V4L2-PIX-FMT-PAC207"><constant>V4L2_PIX_FMT_PAC207</constant></link>,
+<link linkend="V4L2-PIX-FMT-PJPG"><constant>V4L2_PIX_FMT_PJPG</constant></link>,
+<link linkend="V4L2-PIX-FMT-RGB24"><constant>V4L2_PIX_FMT_RGB24</constant></link>,
+<link linkend="V4L2-PIX-FMT-SBGGR8"><constant>V4L2_PIX_FMT_SBGGR8</constant></link>,
+<link linkend="V4L2-PIX-FMT-SGBRG8"><constant>V4L2_PIX_FMT_SGBRG8</constant></link>,
+<link linkend="V4L2-PIX-FMT-SGRBG8"><constant>V4L2_PIX_FMT_SGRBG8</constant></link>,
+<link linkend="V4L2-PIX-FMT-SN9C10X"><constant>V4L2_PIX_FMT_SN9C10X</constant></link>,
+<link linkend="V4L2-PIX-FMT-SN9C20X-I420"><constant>V4L2_PIX_FMT_SN9C20X_I420</constant></link>,
+<link linkend="V4L2-PIX-FMT-SPCA501"><constant>V4L2_PIX_FMT_SPCA501</constant></link>,
+<link linkend="V4L2-PIX-FMT-SPCA505"><constant>V4L2_PIX_FMT_SPCA505</constant></link>,
+<link linkend="V4L2-PIX-FMT-SPCA508"><constant>V4L2_PIX_FMT_SPCA508</constant></link>,
+<link linkend="V4L2-PIX-FMT-SPCA561"><constant>V4L2_PIX_FMT_SPCA561</constant></link>,
+<link linkend="V4L2-PIX-FMT-SQ905C"><constant>V4L2_PIX_FMT_SQ905C</constant></link>,
+<constant>V4L2_PIX_FMT_SRGGB8</constant>,
+<link linkend="V4L2-PIX-FMT-UYVY"><constant>V4L2_PIX_FMT_UYVY</constant></link>,
+<link linkend="V4L2-PIX-FMT-YUV420"><constant>V4L2_PIX_FMT_YUV420</constant></link>,
+<link linkend="V4L2-PIX-FMT-YUYV"><constant>V4L2_PIX_FMT_YUYV</constant></link>,
+<link linkend="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></link>,
+and <link linkend="V4L2-PIX-FMT-YVYU"><constant>V4L2_PIX_FMT_YVYU</constant></link>.
+</para>
+               <para>Later on libv4lconvert was expanded to also be able to do
+various        video processing functions to improve webcam video quality.
+The video processing is split in to 2 parts: libv4lconvert/control and
+libv4lconvert/processing.</para>
+
+               <para>The control part is used to offer video controls which can
+be used        to control the video processing functions made available by
+       libv4lconvert/processing. These controls are stored application wide
+(until reboot) by using a persistent shared memory object.</para>
+
+               <para>libv4lconvert/processing offers the actual video
+processing functionality.</para>
+       </section>
+       <section>
+               <title>libv4l1</title>
+               <para>This library offers functions that can be used to quickly
+make v4l1 applications work with v4l2 devices. These functions work exactly
+like the normal open/close/etc, except that libv4l1 does full emulation of
+the v4l1 api on top of v4l2 drivers, in case of v4l1 drivers it
+will just pass calls through.</para>
+               <para>Since those functions are emulations of the old V4L1 API,
+it shouldn't be used for new applications.</para>
+       </section>
+       <section>
+               <title>libv4l2</title>
+               <para>This library should be used for all modern V4L2
+applications.</para>
+               <para>It provides handles to call V4L2 open/ioctl/close/poll
+methods. Instead of just providing the raw output of the device, it enhances
+the calls in the sense that it will use libv4lconvert to provide more video
+formats and to enhance the image quality.</para>
+               <para>In most cases, libv4l2 just passes the calls directly
+through to the v4l2 driver, intercepting the calls to
+<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>,
+<link linkend='vidioc-g-fmt'><constant>VIDIOC_G_FMT</constant></link>
+<link linkend='vidioc-g-fmt'><constant>VIDIOC_S_FMT</constant></link>
+<link linkend='vidioc-enum-framesizes'><constant>VIDIOC_ENUM_FRAMESIZES</constant></link>
+and <link linkend='vidioc-enum-frameintervals'><constant>VIDIOC_ENUM_FRAMEINTERVALS</constant></link>
+in order to emulate the formats
+<link linkend="V4L2-PIX-FMT-BGR24"><constant>V4L2_PIX_FMT_BGR24</constant></link>,
+<link linkend="V4L2-PIX-FMT-RGB24"><constant>V4L2_PIX_FMT_RGB24</constant></link>,
+<link linkend="V4L2-PIX-FMT-YUV420"><constant>V4L2_PIX_FMT_YUV420</constant></link>,
+and <link linkend="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></link>,
+if they aren't available in the driver.
+<link linkend='vidioc-enum-fmt'><constant>VIDIOC_ENUM_FMT</constant></link>
+keeps enumerating the hardware supported formats, plus the emulated formats
+offered by libv4l at the end.
+</para>
+               <section id="libv4l-ops">
+                       <title>Libv4l device control functions</title>
+                       <para>The common file operation methods are provided by
+libv4l.</para>
+                       <para>Those functions operate just like glibc
+open/close/dup/ioctl/read/mmap/munmap:</para>
+<itemizedlist><listitem>
+                       <para>int v4l2_open(const char *file, int oflag,
+...) -
+operates like the standard <link linkend='func-open'>open()</link> function.
+</para></listitem><listitem>
+                       <para>int v4l2_close(int fd) -
+operates like the standard <link linkend='func-close'>close()</link> function.
+</para></listitem><listitem>
+                       <para>int v4l2_dup(int fd) -
+operates like the standard dup() function, duplicating a file handler.
+</para></listitem><listitem>
+                       <para>int v4l2_ioctl (int fd, unsigned long int request, ...) -
+operates like the standard <link linkend='func-ioctl'>ioctl()</link> function.
+</para></listitem><listitem>
+                       <para>int v4l2_read (int fd, void* buffer, size_t n) -
+operates like the standard <link linkend='func-read'>read()</link> function.
+</para></listitem><listitem>
+                       <para>void v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, int64_t offset); -
+operates like the standard <link linkend='func-mmap'>mmap()</link> function.
+</para></listitem><listitem>
+                       <para>int v4l2_munmap(void *_start, size_t length); -
+operates like the standard <link linkend='func-munmap'>munmap()</link> function.
+</para></listitem>
+</itemizedlist>
+                       <para>Those functions provide additional control:</para>
+<itemizedlist><listitem>
+                       <para>int v4l2_fd_open(int fd, int v4l2_flags) -
+opens an already opened fd for further use through v4l2lib and possibly
+modify libv4l2's default behavior through the v4l2_flags argument.
+Currently, v4l2_flags can be <constant>V4L2_DISABLE_CONVERSION</constant>,
+to disable format conversion.
+</para></listitem><listitem>
+                       <para>int v4l2_set_control(int fd, int cid, int value) -
+This function takes a value of 0 - 65535, and then scales that range to
+the actual range of the given v4l control id, and then if the cid exists
+and is not locked sets the cid to the scaled value.
+</para></listitem><listitem>
+                       <para>int v4l2_get_control(int fd, int cid) -
+This function returns a value of 0 - 65535, scaled to from the actual range
+of the given v4l control id. when the cid does not exist, could not be
+accessed for some reason, or some error occurred 0 is returned.
+</para></listitem>
+</itemizedlist>
+               </section>
+       </section>
+       <section>
+
+               <title>v4l1compat.so wrapper library</title>
+
+               <para>This library intercepts calls to
+open/close/ioctl/mmap/mmunmap operations and redirects them to the libv4l
+counterparts, by using LD_PRELOAD=/usr/lib/v4l1compat.so. It also
+emulates V4L1 calls via V4L2 API.</para>
+               <para>It allows usage of binary legacy applications that
+still don't use libv4l.</para>
+       </section>
+
+</section>
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/lirc_device_interface.xml b/Documentation/DocBook/media/v4l/lirc_device_interface.xml
new file mode 100644 (file)
index 0000000..8d7eb6b
--- /dev/null
@@ -0,0 +1,253 @@
+<section id="lirc_dev">
+<title>LIRC Device Interface</title>
+
+
+<section id="lirc_dev_intro">
+<title>Introduction</title>
+
+<para>The LIRC device interface is a bi-directional interface for
+transporting raw IR data between userspace and kernelspace. Fundamentally,
+it is just a chardev (/dev/lircX, for X = 0, 1, 2, ...), with a number
+of standard struct file_operations defined on it. With respect to
+transporting raw IR data to and fro, the essential fops are read, write
+and ioctl.</para>
+
+<para>Example dmesg output upon a driver registering w/LIRC:</para>
+  <blockquote>
+    <para>$ dmesg |grep lirc_dev</para>
+    <para>lirc_dev: IR Remote Control driver registered, major 248</para>
+    <para>rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0</para>
+  </blockquote>
+
+<para>What you should see for a chardev:</para>
+  <blockquote>
+    <para>$ ls -l /dev/lirc*</para>
+    <para>crw-rw---- 1 root root 248, 0 Jul  2 22:20 /dev/lirc0</para>
+  </blockquote>
+</section>
+
+<section id="lirc_read">
+<title>LIRC read fop</title>
+
+<para>The lircd userspace daemon reads raw IR data from the LIRC chardev. The
+exact format of the data depends on what modes a driver supports, and what
+mode has been selected. lircd obtains supported modes and sets the active mode
+via the ioctl interface, detailed at <xref linkend="lirc_ioctl"/>. The generally
+preferred mode is LIRC_MODE_MODE2, in which packets containing an int value
+describing an IR signal are read from the chardev.</para>
+
+<para>See also <ulink url="http://www.lirc.org/html/technical.html">http://www.lirc.org/html/technical.html</ulink> for more info.</para>
+</section>
+
+<section id="lirc_write">
+<title>LIRC write fop</title>
+
+<para>The data written to the chardev is a pulse/space sequence of integer
+values. Pulses and spaces are only marked implicitly by their position. The
+data must start and end with a pulse, therefore, the data must always include
+an uneven number of samples. The write function must block until the data has
+been transmitted by the hardware.</para>
+</section>
+
+<section id="lirc_ioctl">
+<title>LIRC ioctl fop</title>
+
+<para>The LIRC device's ioctl definition is bound by the ioctl function
+definition of struct file_operations, leaving us with an unsigned int
+for the ioctl command and an unsigned long for the arg. For the purposes
+of ioctl portability across 32-bit and 64-bit, these values are capped
+to their 32-bit sizes.</para>
+
+<para>The following ioctls can be used to change specific hardware settings.
+In general each driver should have a default set of settings. The driver
+implementation is expected to re-apply the default settings when the device
+is closed by user-space, so that every application opening the device can rely
+on working with the default settings initially.</para>
+
+<variablelist>
+  <varlistentry>
+    <term>LIRC_GET_FEATURES</term>
+    <listitem>
+      <para>Obviously, get the underlying hardware device's features. If a driver
+      does not announce support of certain features, calling of the corresponding
+      ioctls is undefined.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_SEND_MODE</term>
+    <listitem>
+      <para>Get supported transmit mode. Only LIRC_MODE_PULSE is supported by lircd.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_REC_MODE</term>
+    <listitem>
+      <para>Get supported receive modes. Only LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE
+      are supported by lircd.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_SEND_CARRIER</term>
+    <listitem>
+      <para>Get carrier frequency (in Hz) currently used for transmit.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_REC_CARRIER</term>
+    <listitem>
+      <para>Get carrier frequency (in Hz) currently used for IR reception.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_{G,S}ET_{SEND,REC}_DUTY_CYCLE</term>
+    <listitem>
+      <para>Get/set the duty cycle (from 0 to 100) of the carrier signal. Currently,
+      no special meaning is defined for 0 or 100, but this could be used to switch
+      off carrier generation in the future, so these values should be reserved.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_REC_RESOLUTION</term>
+    <listitem>
+      <para>Some receiver have maximum resolution which is defined by internal
+      sample rate or data format limitations. E.g. it's common that signals can
+      only be reported in 50 microsecond steps. This integer value is used by
+      lircd to automatically adjust the aeps tolerance value in the lircd
+      config file.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_M{IN,AX}_TIMEOUT</term>
+    <listitem>
+      <para>Some devices have internal timers that can be used to detect when
+      there's no IR activity for a long time. This can help lircd in detecting
+      that a IR signal is finished and can speed up the decoding process.
+      Returns an integer value with the minimum/maximum timeout that can be
+      set. Some devices have a fixed timeout, in that case both ioctls will
+      return the same value even though the timeout cannot be changed.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_M{IN,AX}_FILTER_{PULSE,SPACE}</term>
+    <listitem>
+      <para>Some devices are able to filter out spikes in the incoming signal
+      using given filter rules. These ioctls return the hardware capabilities
+      that describe the bounds of the possible filters. Filter settings depend
+      on the IR protocols that are expected. lircd derives the settings from
+      all protocols definitions found in its config file.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_GET_LENGTH</term>
+    <listitem>
+      <para>Retrieves the code length in bits (only for LIRC_MODE_LIRCCODE).
+      Reads on the device must be done in blocks matching the bit count.
+      The bit could should be rounded up so that it matches full bytes.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_{SEND,REC}_MODE</term>
+    <listitem>
+      <para>Set send/receive mode. Largely obsolete for send, as only
+      LIRC_MODE_PULSE is supported.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_{SEND,REC}_CARRIER</term>
+    <listitem>
+      <para>Set send/receive carrier (in Hz).</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_TRANSMITTER_MASK</term>
+    <listitem>
+      <para>This enables the given set of transmitters. The first transmitter
+      is encoded by the least significant bit, etc. When an invalid bit mask
+      is given, i.e. a bit is set, even though the device does not have so many
+      transitters, then this ioctl returns the number of available transitters
+      and does nothing otherwise.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_TIMEOUT</term>
+    <listitem>
+      <para>Sets the integer value for IR inactivity timeout (cf.
+      LIRC_GET_MIN_TIMEOUT and LIRC_GET_MAX_TIMEOUT). A value of 0 (if
+      supported by the hardware) disables all hardware timeouts and data should
+      be reported as soon as possible. If the exact value cannot be set, then
+      the next possible value _greater_ than the given value should be set.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_TIMEOUT_REPORTS</term>
+    <listitem>
+      <para>Enable (1) or disable (0) timeout reports in LIRC_MODE_MODE2. By
+      default, timeout reports should be turned off.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_FILTER_{,PULSE,SPACE}</term>
+    <listitem>
+      <para>Pulses/spaces shorter than this are filtered out by hardware. If
+      filters cannot be set independently for pulse/space, the corresponding
+      ioctls must return an error and LIRC_SET_REC_FILTER shall be used instead.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_MEASURE_CARRIER_MODE</term>
+    <listitem>
+      <para>Enable (1)/disable (0) measure mode. If enabled, from the next key
+      press on, the driver will send LIRC_MODE2_FREQUENCY packets. By default
+      this should be turned off.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_REC_{DUTY_CYCLE,CARRIER}_RANGE</term>
+    <listitem>
+      <para>To set a range use LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE
+      with the lower bound first and later LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER
+      with the upper bound.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_NOTIFY_DECODE</term>
+    <listitem>
+      <para>This ioctl is called by lircd whenever a successful decoding of an
+      incoming IR signal could be done. This can be used by supporting hardware
+      to give visual feedback to the user e.g. by flashing a LED.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SETUP_{START,END}</term>
+    <listitem>
+      <para>Setting of several driver parameters can be optimized by encapsulating
+      the according ioctl calls with LIRC_SETUP_START/LIRC_SETUP_END. When a
+      driver receives a LIRC_SETUP_START ioctl it can choose to not commit
+      further setting changes to the hardware until a LIRC_SETUP_END is received.
+      But this is open to the driver implementation and every driver must also
+      handle parameter changes which are not encapsulated by LIRC_SETUP_START
+      and LIRC_SETUP_END. Drivers can also choose to ignore these ioctls.</para>
+    </listitem>
+  </varlistentry>
+  <varlistentry>
+    <term>LIRC_SET_WIDEBAND_RECEIVER</term>
+    <listitem>
+      <para>Some receivers are equipped with special wide band receiver which is intended
+      to be used to learn output of existing remote.
+      Calling that ioctl with (1) will enable it, and with (0) disable it.
+      This might be useful of receivers that have otherwise narrow band receiver
+      that prevents them to be used with some remotes.
+      Wide band receiver might also be more precise
+      On the other hand its disadvantage it usually reduced range of reception.
+      Note: wide band receiver might be implictly enabled if you enable
+      carrier reports. In that case it will be disabled as soon as you disable
+      carrier reports. Trying to disable wide band receiver while carrier
+      reports are active will do nothing.</para>
+    </listitem>
+  </varlistentry>
+</variablelist>
+<section id="lirc_dev_errors">
+  &return-value;
+</section>
+</section>
+</section>
diff --git a/Documentation/DocBook/media/v4l/media-controller.xml b/Documentation/DocBook/media/v4l/media-controller.xml
new file mode 100644 (file)
index 0000000..873ac3a
--- /dev/null
@@ -0,0 +1,89 @@
+<partinfo>
+  <authorgroup>
+    <author>
+      <firstname>Laurent</firstname>
+      <surname>Pinchart</surname>
+      <affiliation><address><email>laurent.pinchart@ideasonboard.com</email></address></affiliation>
+      <contrib>Initial version.</contrib>
+    </author>
+  </authorgroup>
+  <copyright>
+    <year>2010</year>
+    <holder>Laurent Pinchart</holder>
+  </copyright>
+
+  <revhistory>
+    <!-- Put document revisions here, newest first. -->
+    <revision>
+      <revnumber>1.0.0</revnumber>
+      <date>2010-11-10</date>
+      <authorinitials>lp</authorinitials>
+      <revremark>Initial revision</revremark>
+    </revision>
+  </revhistory>
+</partinfo>
+
+<title>Media Controller API</title>
+
+<chapter id="media_controller">
+  <title>Media Controller</title>
+
+  <section id="media-controller-intro">
+    <title>Introduction</title>
+    <para>Media devices increasingly handle multiple related functions. Many USB
+    cameras include microphones, video capture hardware can also output video,
+    or SoC camera interfaces also perform memory-to-memory operations similar to
+    video codecs.</para>
+    <para>Independent functions, even when implemented in the same hardware, can
+    be modelled as separate devices. A USB camera with a microphone will be
+    presented to userspace applications as V4L2 and ALSA capture devices. The
+    devices' relationships (when using a webcam, end-users shouldn't have to
+    manually select the associated USB microphone), while not made available
+    directly to applications by the drivers, can usually be retrieved from
+    sysfs.</para>
+    <para>With more and more advanced SoC devices being introduced, the current
+    approach will not scale. Device topologies are getting increasingly complex
+    and can't always be represented by a tree structure. Hardware blocks are
+    shared between different functions, creating dependencies between seemingly
+    unrelated devices.</para>
+    <para>Kernel abstraction APIs such as V4L2 and ALSA provide means for
+    applications to access hardware parameters. As newer hardware expose an
+    increasingly high number of those parameters, drivers need to guess what
+    applications really require based on limited information, thereby
+    implementing policies that belong to userspace.</para>
+    <para>The media controller API aims at solving those problems.</para>
+  </section>
+
+  <section id="media-controller-model">
+    <title>Media device model</title>
+    <para>Discovering a device internal topology, and configuring it at runtime,
+    is one of the goals of the media controller API. To achieve this, hardware
+    devices are modelled as an oriented graph of building blocks called entities
+    connected through pads.</para>
+    <para>An entity is a basic media hardware or software building block. It can
+    correspond to a large variety of logical blocks such as physical hardware
+    devices (CMOS sensor for instance), logical hardware devices (a building
+    block in a System-on-Chip image processing pipeline), DMA channels or
+    physical connectors.</para>
+    <para>A pad is a connection endpoint through which an entity can interact
+    with other entities. Data (not restricted to video) produced by an entity
+    flows from the entity's output to one or more entity inputs. Pads should not
+    be confused with physical pins at chip boundaries.</para>
+    <para>A link is a point-to-point oriented connection between two pads,
+    either on the same entity or on different entities. Data flows from a source
+    pad to a sink pad.</para>
+  </section>
+</chapter>
+
+<appendix id="media-user-func">
+  <title>Function Reference</title>
+  <!-- Keep this alphabetically sorted. -->
+  &sub-media-func-open;
+  &sub-media-func-close;
+  &sub-media-func-ioctl;
+  <!-- All ioctls go here. -->
+  &sub-media-ioc-device-info;
+  &sub-media-ioc-enum-entities;
+  &sub-media-ioc-enum-links;
+  &sub-media-ioc-setup-link;
+</appendix>
diff --git a/Documentation/DocBook/media/v4l/media-func-close.xml b/Documentation/DocBook/media/v4l/media-func-close.xml
new file mode 100644 (file)
index 0000000..be149c8
--- /dev/null
@@ -0,0 +1,59 @@
+<refentry id="media-func-close">
+  <refmeta>
+    <refentrytitle>media close()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>media-close</refname>
+    <refpurpose>Close a media device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>close</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Closes the media device. Resources associated with the file descriptor
+    are freed. The device configuration remain unchanged.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para><function>close</function> returns 0 on success. On error, -1 is
+    returned, and <varname>errno</varname> is set appropriately. Possible error
+    codes are:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBADF</errorcode></term>
+       <listitem>
+         <para><parameter>fd</parameter> is not a valid open file descriptor.
+         </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-func-ioctl.xml b/Documentation/DocBook/media/v4l/media-func-ioctl.xml
new file mode 100644 (file)
index 0000000..39478d0
--- /dev/null
@@ -0,0 +1,73 @@
+<refentry id="media-func-ioctl">
+  <refmeta>
+    <refentrytitle>media ioctl()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>media-ioctl</refname>
+    <refpurpose>Control a media device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>void *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>Media ioctl request code as defined in the media.h header file,
+         for example MEDIA_IOC_SETUP_LINK.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para>Pointer to a request-specific structure.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+    <para>The <function>ioctl()</function> function manipulates media device
+    parameters. The argument <parameter>fd</parameter> must be an open file
+    descriptor.</para>
+    <para>The ioctl <parameter>request</parameter> code specifies the media
+    function to be called. It has encoded in it whether the argument is an
+    input, output or read/write parameter, and the size of the argument
+    <parameter>argp</parameter> in bytes.</para>
+    <para>Macros and structures definitions specifying media ioctl requests and
+    their parameters are located in the media.h header file. All media ioctl
+    requests, their respective function and parameters are specified in
+    <xref linkend="media-user-func" />.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <para>Request-specific error codes are listed in the
+    individual requests descriptions.</para>
+    <para>When an ioctl that takes an output or read/write parameter fails,
+    the parameter remains unmodified.</para>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-func-open.xml b/Documentation/DocBook/media/v4l/media-func-open.xml
new file mode 100644 (file)
index 0000000..f7df034
--- /dev/null
@@ -0,0 +1,94 @@
+<refentry id="media-func-open">
+  <refmeta>
+    <refentrytitle>media open()</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>media-open</refname>
+    <refpurpose>Open a media device</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
+      <funcprototype>
+       <funcdef>int <function>open</function></funcdef>
+       <paramdef>const char *<parameter>device_name</parameter></paramdef>
+       <paramdef>int <parameter>flags</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>device_name</parameter></term>
+       <listitem>
+         <para>Device to be opened.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>flags</parameter></term>
+       <listitem>
+         <para>Open flags. Access mode must be either <constant>O_RDONLY</constant>
+         or <constant>O_RDWR</constant>. Other flags have no effect.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>Description</title>
+    <para>To open a media device applications call <function>open()</function>
+    with the desired device name. The function has no side effects; the device
+    configuration remain unchanged.</para>
+    <para>When the device is opened in read-only mode, attemps to modify its
+    configuration will result in an error, and <varname>errno</varname> will be
+    set to <errorcode>EBADF</errorcode>.</para>
+  </refsect1>
+  <refsect1>
+    <title>Return Value</title>
+
+    <para><function>open</function> returns the new file descriptor on success.
+    On error, -1 is returned, and <varname>errno</varname> is set appropriately.
+    Possible error codes are:</para>
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EACCES</errorcode></term>
+       <listitem>
+         <para>The requested access to the file is not allowed.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EMFILE</errorcode></term>
+       <listitem>
+         <para>The  process  already  has  the  maximum number of files open.
+         </para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENFILE</errorcode></term>
+       <listitem>
+         <para>The system limit on the total number of open files has been
+         reached.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENOMEM</errorcode></term>
+       <listitem>
+         <para>Insufficient kernel memory was available.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENXIO</errorcode></term>
+       <listitem>
+         <para>No device corresponding to this device special file exists.
+         </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-device-info.xml b/Documentation/DocBook/media/v4l/media-ioc-device-info.xml
new file mode 100644 (file)
index 0000000..2ce5214
--- /dev/null
@@ -0,0 +1,132 @@
+<refentry id="media-ioc-device-info">
+  <refmeta>
+    <refentrytitle>ioctl MEDIA_IOC_DEVICE_INFO</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>MEDIA_IOC_DEVICE_INFO</refname>
+    <refpurpose>Query device information</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct media_device_info *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>File descriptor returned by
+         <link linkend='media-func-open'><function>open()</function></link>.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>MEDIA_IOC_DEVICE_INFO</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>All media devices must support the <constant>MEDIA_IOC_DEVICE_INFO</constant>
+    ioctl. To query device information, applications call the ioctl with a
+    pointer to a &media-device-info;. The driver fills the structure and returns
+    the information to the application.
+    The ioctl never fails.</para>
+
+    <table pgwide="1" frame="none" id="media-device-info">
+      <title>struct <structname>media_device_info</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>char</entry>
+           <entry><structfield>driver</structfield>[16]</entry>
+           <entry><para>Name of the driver implementing the media API as a
+           NUL-terminated ASCII string. The driver version is stored in the
+           <structfield>driver_version</structfield> field.</para>
+           <para>Driver specific applications can use this information to
+           verify the driver identity. It is also useful to work around
+           known bugs, or to identify drivers in error reports.</para></entry>
+         </row>
+         <row>
+           <entry>char</entry>
+           <entry><structfield>model</structfield>[32]</entry>
+           <entry>Device model name as a NUL-terminated UTF-8 string. The
+           device version is stored in the <structfield>device_version</structfield>
+           field and is not be appended to the model name.</entry>
+         </row>
+         <row>
+           <entry>char</entry>
+           <entry><structfield>serial</structfield>[40]</entry>
+           <entry>Serial number as a NUL-terminated ASCII string.</entry>
+         </row>
+         <row>
+           <entry>char</entry>
+           <entry><structfield>bus_info</structfield>[32]</entry>
+           <entry>Location of the device in the system as a NUL-terminated
+           ASCII string. This includes the bus type name (PCI, USB, ...) and a
+           bus-specific identifier.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>media_version</structfield></entry>
+           <entry>Media API version, formatted with the
+           <constant>KERNEL_VERSION()</constant> macro.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>hw_revision</structfield></entry>
+           <entry>Hardware device revision in a driver-specific format.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>media_version</structfield></entry>
+           <entry>Media device driver version, formatted with the
+           <constant>KERNEL_VERSION()</constant> macro. Together with the
+           <structfield>driver</structfield> field this identifies a particular
+           driver.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[31]</entry>
+           <entry>Reserved for future extensions. Drivers and applications must
+           set this array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+    <para>The <structfield>serial</structfield> and <structfield>bus_info</structfield>
+    fields can be used to distinguish between multiple instances of otherwise
+    identical hardware. The serial number takes precedence when provided and can
+    be assumed to be unique. If the serial number is an empty string, the
+    <structfield>bus_info</structfield> field can be used instead. The
+    <structfield>bus_info</structfield> field is guaranteed to be unique, but
+    can vary across reboots or device unplug/replug.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml
new file mode 100644 (file)
index 0000000..576b68b
--- /dev/null
@@ -0,0 +1,308 @@
+<refentry id="media-ioc-enum-entities">
+  <refmeta>
+    <refentrytitle>ioctl MEDIA_IOC_ENUM_ENTITIES</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>MEDIA_IOC_ENUM_ENTITIES</refname>
+    <refpurpose>Enumerate entities and their properties</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct media_entity_desc *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>File descriptor returned by
+         <link linkend='media-func-open'><function>open()</function></link>.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>MEDIA_IOC_ENUM_ENTITIES</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+    <para>To query the attributes of an entity, applications set the id field
+    of a &media-entity-desc; structure and call the MEDIA_IOC_ENUM_ENTITIES
+    ioctl with a pointer to this structure. The driver fills the rest of the
+    structure or returns an &EINVAL; when the id is invalid.</para>
+    <para>Entities can be enumerated by or'ing the id with the
+    <constant>MEDIA_ENT_ID_FLAG_NEXT</constant> flag. The driver will return
+    information about the entity with the smallest id strictly larger than the
+    requested one ('next entity'), or the &EINVAL; if there is none.</para>
+    <para>Entity IDs can be non-contiguous. Applications must
+    <emphasis>not</emphasis> try to enumerate entities by calling
+    MEDIA_IOC_ENUM_ENTITIES with increasing id's until they get an error.</para>
+    <para>Two or more entities that share a common non-zero
+    <structfield>group_id</structfield> value are considered as logically
+    grouped. Groups are used to report
+    <itemizedlist>
+      <listitem><para>ALSA, VBI and video nodes that carry the same media
+      stream</para></listitem>
+      <listitem><para>lens and flash controllers associated with a sensor</para></listitem>
+    </itemizedlist>
+    </para>
+
+    <table pgwide="1" frame="none" id="media-entity-desc">
+      <title>struct <structname>media_entity_desc</structname></title>
+      <tgroup cols="5">
+       <colspec colname="c1" />
+       <colspec colname="c2" />
+       <colspec colname="c3" />
+       <colspec colname="c4" />
+       <colspec colname="c5" />
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity id, set by the application. When the id is or'ed with
+           <constant>MEDIA_ENT_ID_FLAG_NEXT</constant>, the driver clears the
+           flag and returns the first entity with a larger id.</entry>
+         </row>
+         <row>
+           <entry>char</entry>
+           <entry><structfield>name</structfield>[32]</entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity name as an UTF-8 NULL-terminated string.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity type, see <xref linkend="media-entity-type" /> for details.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>revision</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity revision in a driver/hardware specific format.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity flags, see <xref linkend="media-entity-flag" /> for details.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>group_id</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Entity group ID</entry>
+         </row>
+         <row>
+           <entry>__u16</entry>
+           <entry><structfield>pads</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Number of pads</entry>
+         </row>
+         <row>
+           <entry>__u16</entry>
+           <entry><structfield>links</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Total number of outbound links. Inbound links are not counted
+           in this field.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct</entry>
+           <entry><structfield>v4l</structfield></entry>
+           <entry></entry>
+           <entry>Valid for V4L sub-devices and nodes only.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>major</structfield></entry>
+           <entry>V4L device node major number. For V4L sub-devices with no
+           device node, set by the driver to 0.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>minor</structfield></entry>
+           <entry>V4L device node minor number. For V4L sub-devices with no
+           device node, set by the driver to 0.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct</entry>
+           <entry><structfield>fb</structfield></entry>
+           <entry></entry>
+           <entry>Valid for frame buffer nodes only.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>major</structfield></entry>
+           <entry>Frame buffer device node major number.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>minor</structfield></entry>
+           <entry>Frame buffer device node minor number.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>struct</entry>
+           <entry><structfield>alsa</structfield></entry>
+           <entry></entry>
+           <entry>Valid for ALSA devices only.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>card</structfield></entry>
+           <entry>ALSA card number</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>device</structfield></entry>
+           <entry>ALSA device number</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>subdevice</structfield></entry>
+           <entry>ALSA sub-device number</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>int</entry>
+           <entry><structfield>dvb</structfield></entry>
+           <entry></entry>
+           <entry>DVB card number</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u8</entry>
+           <entry><structfield>raw</structfield>[180]</entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="media-entity-type">
+      <title>Media entity types</title>
+      <tgroup cols="2">
+        <colspec colname="c1"/>
+        <colspec colname="c2"/>
+       <tbody valign="top">
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE</constant></entry>
+           <entry>Unknown device node</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_V4L</constant></entry>
+           <entry>V4L video, radio or vbi device node</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_FB</constant></entry>
+           <entry>Frame buffer device node</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_ALSA</constant></entry>
+           <entry>ALSA card</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_DEVNODE_DVB</constant></entry>
+           <entry>DVB card</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV</constant></entry>
+           <entry>Unknown V4L sub-device</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_SENSOR</constant></entry>
+           <entry>Video sensor</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_FLASH</constant></entry>
+           <entry>Flash controller</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_LENS</constant></entry>
+           <entry>Lens controller</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="media-entity-flag">
+      <title>Media entity flags</title>
+      <tgroup cols="2">
+        <colspec colname="c1"/>
+        <colspec colname="c2"/>
+       <tbody valign="top">
+         <row>
+           <entry><constant>MEDIA_ENT_FL_DEFAULT</constant></entry>
+           <entry>Default entity for its type. Used to discover the default
+           audio, VBI and video devices, the default camera sensor, ...</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &media-entity-desc; <structfield>id</structfield> references
+         a non-existing entity.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml
new file mode 100644 (file)
index 0000000..355df43
--- /dev/null
@@ -0,0 +1,207 @@
+<refentry id="media-ioc-enum-links">
+  <refmeta>
+    <refentrytitle>ioctl MEDIA_IOC_ENUM_LINKS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>MEDIA_IOC_ENUM_LINKS</refname>
+    <refpurpose>Enumerate all pads and links for a given entity</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct media_links_enum *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>File descriptor returned by
+         <link linkend='media-func-open'><function>open()</function></link>.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>MEDIA_IOC_ENUM_LINKS</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To enumerate pads and/or links for a given entity, applications set
+    the entity field of a &media-links-enum; structure and initialize the
+    &media-pad-desc; and &media-link-desc; structure arrays pointed by the
+    <structfield>pads</structfield> and <structfield>links</structfield> fields.
+    They then call the MEDIA_IOC_ENUM_LINKS ioctl with a pointer to this
+    structure.</para>
+    <para>If the <structfield>pads</structfield> field is not NULL, the driver
+    fills the <structfield>pads</structfield> array with information about the
+    entity's pads. The array must have enough room to store all the entity's
+    pads. The number of pads can be retrieved with the &MEDIA-IOC-ENUM-ENTITIES;
+    ioctl.</para>
+    <para>If the <structfield>links</structfield> field is not NULL, the driver
+    fills the <structfield>links</structfield> array with information about the
+    entity's outbound links. The array must have enough room to store all the
+    entity's outbound links. The number of outbound links can be retrieved with
+    the &MEDIA-IOC-ENUM-ENTITIES; ioctl.</para>
+    <para>Only forward links that originate at one of the entity's source pads
+    are returned during the enumeration process.</para>
+
+    <table pgwide="1" frame="none" id="media-links-enum">
+      <title>struct <structname>media_links_enum</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>entity</structfield></entry>
+           <entry>Entity id, set by the application.</entry>
+         </row>
+         <row>
+           <entry>struct &media-pad-desc;</entry>
+           <entry>*<structfield>pads</structfield></entry>
+           <entry>Pointer to a pads array allocated by the application. Ignored
+           if NULL.</entry>
+         </row>
+         <row>
+           <entry>struct &media-link-desc;</entry>
+           <entry>*<structfield>links</structfield></entry>
+           <entry>Pointer to a links array allocated by the application. Ignored
+           if NULL.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="media-pad-desc">
+      <title>struct <structname>media_pad_desc</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>entity</structfield></entry>
+           <entry>ID of the entity this pad belongs to.</entry>
+         </row>
+         <row>
+           <entry>__u16</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>0-based pad index.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry>Pad flags, see <xref linkend="media-pad-flag" /> for more details.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="media-pad-flag">
+      <title>Media pad flags</title>
+      <tgroup cols="2">
+        <colspec colname="c1"/>
+        <colspec colname="c2"/>
+       <tbody valign="top">
+         <row>
+           <entry><constant>MEDIA_PAD_FL_SINK</constant></entry>
+           <entry>Input pad, relative to the entity. Input pads sink data and
+           are targets of links.</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_PAD_FL_SOURCE</constant></entry>
+           <entry>Output pad, relative to the entity. Output pads source data
+           and are origins of links.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="media-link-desc">
+      <title>struct <structname>media_link_desc</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>struct &media-pad-desc;</entry>
+           <entry><structfield>source</structfield></entry>
+           <entry>Pad at the origin of this link.</entry>
+         </row>
+         <row>
+           <entry>struct &media-pad-desc;</entry>
+           <entry><structfield>sink</structfield></entry>
+           <entry>Pad at the target of this link.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry>Link flags, see <xref linkend="media-link-flag" /> for more details.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="media-link-flag">
+      <title>Media link flags</title>
+      <tgroup cols="2">
+        <colspec colname="c1"/>
+        <colspec colname="c2"/>
+       <tbody valign="top">
+         <row>
+           <entry><constant>MEDIA_LNK_FL_ENABLED</constant></entry>
+           <entry>The link is enabled and can be used to transfer media data.
+           When two or more links target a sink pad, only one of them can be
+           enabled at a time.</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_LNK_FL_IMMUTABLE</constant></entry>
+           <entry>The link enabled state can't be modified at runtime. An
+           immutable link is always enabled.</entry>
+         </row>
+         <row>
+           <entry><constant>MEDIA_LNK_FL_DYNAMIC</constant></entry>
+           <entry>The link enabled state can be modified during streaming. This
+           flag is set by drivers and is read-only for applications.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+    <para>One and only one of <constant>MEDIA_PAD_FL_SINK</constant> and
+    <constant>MEDIA_PAD_FL_SOURCE</constant> must be set for every pad.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &media-links-enum; <structfield>id</structfield> references
+         a non-existing entity.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/media/v4l/media-ioc-setup-link.xml
new file mode 100644 (file)
index 0000000..fc2e522
--- /dev/null
@@ -0,0 +1,84 @@
+<refentry id="media-ioc-setup-link">
+  <refmeta>
+    <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>MEDIA_IOC_SETUP_LINK</refname>
+    <refpurpose>Modify the properties of a link</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct media_link_desc *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>File descriptor returned by
+         <link linkend='media-func-open'><function>open()</function></link>.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>MEDIA_IOC_SETUP_LINK</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To change link properties applications fill a &media-link-desc; with
+    link identification information (source and sink pad) and the new requested
+    link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to
+    that structure.</para>
+    <para>The only configurable property is the <constant>ENABLED</constant>
+    link flag to enable/disable a link. Links marked with the
+    <constant>IMMUTABLE</constant> link flag can not be enabled or disabled.
+    </para>
+    <para>Link configuration has no side effect on other links. If an enabled
+    link at the sink pad prevents the link from being enabled, the driver
+    returns with an &EBUSY;.</para>
+    <para>Only links marked with the <constant>DYNAMIC</constant> link flag can
+    be enabled/disabled while streaming media data. Attempting to enable or
+    disable a streaming non-dynamic link will return an &EBUSY;.</para>
+    <para>If the specified link can't be found the driver returns with an
+    &EINVAL;.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &media-link-desc; references a non-existing link, or the
+         link is immutable and an attempt to modify its configuration was made.
+         </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/pipeline.pdf b/Documentation/DocBook/media/v4l/pipeline.pdf
new file mode 100644 (file)
index 0000000..ee3e37f
Binary files /dev/null and b/Documentation/DocBook/media/v4l/pipeline.pdf differ
diff --git a/Documentation/DocBook/media/v4l/pixfmt-grey.xml b/Documentation/DocBook/media/v4l/pixfmt-grey.xml
new file mode 100644 (file)
index 0000000..3b72bc6
--- /dev/null
@@ -0,0 +1,70 @@
+    <refentry id="V4L2-PIX-FMT-GREY">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_GREY ('GREY')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_GREY</constant></refname>
+       <refpurpose>Grey-scale image</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is a grey-scale image. It is really a degenerate
+Y'CbCr format which simply contains no Cb or Cr data.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_GREY</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-m420.xml b/Documentation/DocBook/media/v4l/pixfmt-m420.xml
new file mode 100644 (file)
index 0000000..ce4bc01
--- /dev/null
@@ -0,0 +1,147 @@
+    <refentry id="V4L2-PIX-FMT-M420">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_M420 ('M420')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_M420</constant></refname>
+       <refpurpose>Format with &frac12; horizontal and vertical chroma
+       resolution, also known as YUV 4:2:0. Hybrid plane line-interleaved
+       layout.</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>M420 is a YUV format with &frac12; horizontal and vertical chroma
+       subsampling (YUV 4:2:0). Pixels are organized as interleaved luma and
+       chroma planes. Two lines of luma data are followed by one line of chroma
+       data.</para>
+       <para>The luma plane has one byte per pixel. The chroma plane contains
+       interleaved CbCr pixels subsampled by &frac12; in the horizontal and
+       vertical directions. Each CbCr pair belongs to four pixels. For example,
+Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
+Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
+Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.</para>
+
+       <para>All line lengths are identical: if the Y lines include pad bytes
+       so do the CbCr lines.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_M420</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;20:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;24:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12.xml
new file mode 100644 (file)
index 0000000..873f670
--- /dev/null
@@ -0,0 +1,151 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-NV12"><constant>V4L2_PIX_FMT_NV12</constant></refname>
+       <refname id="V4L2-PIX-FMT-NV21"><constant>V4L2_PIX_FMT_NV21</constant></refname>
+       <refpurpose>Formats with &frac12; horizontal and vertical
+chroma resolution, also known as YUV 4:2:0. One luminance and one
+chrominance plane with alternating chroma samples as opposed to
+<constant>V4L2_PIX_FMT_YVU420</constant></refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>These are two-plane versions of the YUV 4:2:0 format.
+The three components are separated into two sub-images or planes. The
+Y plane is first. The Y plane has one byte per pixel. For
+<constant>V4L2_PIX_FMT_NV12</constant>, a combined CbCr plane
+immediately follows the Y plane in memory.  The CbCr plane is the same
+width, in bytes, as the Y plane (and of the image), but is half as
+tall in pixels. Each CbCr pair belongs to four pixels. For example,
+Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
+Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
+Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.
+<constant>V4L2_PIX_FMT_NV21</constant> is the same except the Cb and
+Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para>
+
+       <para>If the Y plane has pad bytes after each row, then the
+CbCr plane has as many pad bytes after its rows.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_NV12</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;20:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml
new file mode 100644 (file)
index 0000000..c9e166d
--- /dev/null
@@ -0,0 +1,154 @@
+    <refentry id="V4L2-PIX-FMT-NV12M">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_NV12M ('NV12M')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname> <constant>V4L2_PIX_FMT_NV12M</constant></refname>
+       <refpurpose>Variation of <constant>V4L2_PIX_FMT_NV12</constant> with planes
+         non contiguous in memory. </refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is a multi-planar, two-plane version of the YUV 4:2:0 format.
+The three components are separated into two sub-images or planes.
+<constant>V4L2_PIX_FMT_NV12M</constant> differs from <constant>V4L2_PIX_FMT_NV12
+</constant> in that the two planes are non-contiguous in memory, i.e. the chroma
+plane do not necessarily immediately follows the luma plane.
+The luminance data occupies the first plane. The Y plane has one byte per pixel.
+In the second plane there is a chrominance data with alternating chroma samples.
+The CbCr plane is the same width, in bytes, as the Y plane (and of the image),
+but is half as tall in pixels. Each CbCr pair belongs to four pixels. For example,
+Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
+Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
+Y'<subscript>10</subscript>, Y'<subscript>11</subscript>. </para>
+
+       <para><constant>V4L2_PIX_FMT_NV12M</constant> is intended to be
+used only in drivers and applications that support the multi-planar API,
+described in <xref linkend="planar-apis"/>. </para>
+
+       <para>If the Y plane has pad bytes after each row, then the
+CbCr plane has as many pad bytes after its rows.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_NV12M</constant> 4 &times; 4 pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>start1&nbsp;+&nbsp;0:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start1&nbsp;+&nbsp;4:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml
new file mode 100644 (file)
index 0000000..7a2855a
--- /dev/null
@@ -0,0 +1,74 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_NV12MT ('TM12')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-NV12MT"><constant>V4L2_PIX_FMT_NV12MT
+</constant></refname>
+       <refpurpose>Formats with &frac12; horizontal and vertical
+chroma resolution. This format has two planes - one for luminance and one for
+chrominance. Chroma samples are interleaved. The difference to
+<constant>V4L2_PIX_FMT_NV12</constant> is the memory layout. Pixels are
+grouped in macroblocks of 64x32 size. The order of macroblocks in memory is
+also not standard.
+       </refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is the two-plane versions of the YUV 4:2:0 format where data
+is grouped into 64x32 macroblocks. The three components are separated into two
+sub-images or planes. The Y plane has one byte per pixel and pixels are grouped
+into 64x32 macroblocks. The CbCr plane has the same width, in bytes, as the Y
+plane (and the image), but is half as tall in pixels. The chroma plane is also
+grouped into 64x32 macroblocks.</para>
+       <para>Width of the buffer has to be aligned to the multiple of 128, and
+height alignment is 32. Every four adjactent buffers - two horizontally and two
+vertically are grouped together and are located in memory in Z or flipped Z
+order. </para>
+       <para>Layout of macroblocks in memory is presented in the following
+figure.</para>
+       <para><figure id="nv12mt">
+           <title><constant>V4L2_PIX_FMT_NV12MT</constant> macroblock Z shape
+memory layout</title>
+           <mediaobject>
+             <imageobject>
+               <imagedata fileref="nv12mt.gif" format="GIF" />
+             </imageobject>
+           </mediaobject>
+       </figure>
+       The requirement that width is multiple of 128 is implemented because,
+the Z shape cannot be cut in half horizontally. In case the vertical resolution
+of macroblocks is odd then the last row of macroblocks is arranged in a linear
+order.  </para>
+       <para>In case of chroma the layout is identical. Cb and Cr samples are
+interleaved. Height of the buffer is aligned to 32.
+       </para>
+       <example>
+         <title>Memory layout of macroblocks in <constant>V4L2_PIX_FMT_NV12
+</constant> format pixel image - extreme case</title>
+       <para>
+       <figure id="nv12mt_ex">
+           <title>Example <constant>V4L2_PIX_FMT_NV12MT</constant> memory
+layout of macroblocks</title>
+           <mediaobject>
+             <imageobject>
+               <imagedata fileref="nv12mt_example.gif" format="GIF" />
+             </imageobject>
+           </mediaobject>
+       </figure>
+       Memory layout of macroblocks of <constant>V4L2_PIX_FMT_NV12MT
+</constant> format in most extreme case.
+       </para>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv16.xml b/Documentation/DocBook/media/v4l/pixfmt-nv16.xml
new file mode 100644 (file)
index 0000000..2609403
--- /dev/null
@@ -0,0 +1,174 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_NV16 ('NV16'), V4L2_PIX_FMT_NV61 ('NV61')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-NV16"><constant>V4L2_PIX_FMT_NV16</constant></refname>
+       <refname id="V4L2-PIX-FMT-NV61"><constant>V4L2_PIX_FMT_NV61</constant></refname>
+       <refpurpose>Formats with &frac12; horizontal
+chroma resolution, also known as YUV 4:2:2. One luminance and one
+chrominance plane with alternating chroma samples as opposed to
+<constant>V4L2_PIX_FMT_YVU420</constant></refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>These are two-plane versions of the YUV 4:2:2 format.
+The three components are separated into two sub-images or planes. The
+Y plane is first. The Y plane has one byte per pixel. For
+<constant>V4L2_PIX_FMT_NV16</constant>, a combined CbCr plane
+immediately follows the Y plane in memory.  The CbCr plane is the same
+width and height, in bytes, as the Y plane (and of the image).
+Each CbCr pair belongs to two pixels. For example,
+Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
+Y'<subscript>00</subscript>, Y'<subscript>01</subscript>.
+<constant>V4L2_PIX_FMT_NV61</constant> is the same except the Cb and
+Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para>
+
+       <para>If the Y plane has pad bytes after each row, then the
+CbCr plane has as many pad bytes after its rows.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_NV16</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;20:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;24:</entry>
+                     <entry>Cb<subscript>20</subscript></entry>
+                     <entry>Cr<subscript>20</subscript></entry>
+                     <entry>Cb<subscript>21</subscript></entry>
+                     <entry>Cr<subscript>21</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;28:</entry>
+                     <entry>Cb<subscript>30</subscript></entry>
+                     <entry>Cr<subscript>30</subscript></entry>
+                     <entry>Cb<subscript>31</subscript></entry>
+                     <entry>Cr<subscript>31</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
new file mode 100644 (file)
index 0000000..4db272b
--- /dev/null
@@ -0,0 +1,940 @@
+<refentry id="packed-rgb">
+  <refmeta>
+    <refentrytitle>Packed RGB formats</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname>Packed RGB formats</refname>
+    <refpurpose>Packed RGB formats</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>These formats are designed to match the pixel formats of
+typical PC graphics frame buffers. They occupy 8, 16, 24 or 32 bits
+per pixel. These are all packed-pixel formats, meaning all the data
+for a pixel lie next to each other in memory.</para>
+
+    <para>When one of these formats is used, drivers shall report the
+colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
+
+    <table pgwide="1" frame="none" id="rgb-formats">
+      <title>Packed RGB Image Formats</title>
+      <tgroup cols="37" align="center">
+       <colspec colname="id" align="left" />
+       <colspec colname="fourcc" />
+       <colspec colname="bit" />
+
+       <colspec colnum="4" colname="b07" align="center" />
+       <colspec colnum="5" colname="b06" align="center" />
+       <colspec colnum="6" colname="b05" align="center" />
+       <colspec colnum="7" colname="b04" align="center" />
+       <colspec colnum="8" colname="b03" align="center" />
+       <colspec colnum="9" colname="b02" align="center" />
+       <colspec colnum="10" colname="b01" align="center" />
+       <colspec colnum="11" colname="b00" align="center" />
+
+       <colspec colnum="13" colname="b17" align="center" />
+       <colspec colnum="14" colname="b16" align="center" />
+       <colspec colnum="15" colname="b15" align="center" />
+       <colspec colnum="16" colname="b14" align="center" />
+       <colspec colnum="17" colname="b13" align="center" />
+       <colspec colnum="18" colname="b12" align="center" />
+       <colspec colnum="19" colname="b11" align="center" />
+       <colspec colnum="20" colname="b10" align="center" />
+
+       <colspec colnum="22" colname="b27" align="center" />
+       <colspec colnum="23" colname="b26" align="center" />
+       <colspec colnum="24" colname="b25" align="center" />
+       <colspec colnum="25" colname="b24" align="center" />
+       <colspec colnum="26" colname="b23" align="center" />
+       <colspec colnum="27" colname="b22" align="center" />
+       <colspec colnum="28" colname="b21" align="center" />
+       <colspec colnum="29" colname="b20" align="center" />
+
+       <colspec colnum="31" colname="b37" align="center" />
+       <colspec colnum="32" colname="b36" align="center" />
+       <colspec colnum="33" colname="b35" align="center" />
+       <colspec colnum="34" colname="b34" align="center" />
+       <colspec colnum="35" colname="b33" align="center" />
+       <colspec colnum="36" colname="b32" align="center" />
+       <colspec colnum="37" colname="b31" align="center" />
+       <colspec colnum="38" colname="b30" align="center" />
+
+       <spanspec namest="b07" nameend="b00" spanname="b0" />
+       <spanspec namest="b17" nameend="b10" spanname="b1" />
+       <spanspec namest="b27" nameend="b20" spanname="b2" />
+       <spanspec namest="b37" nameend="b30" spanname="b3" />
+       <thead>
+         <row>
+           <entry>Identifier</entry>
+           <entry>Code</entry>
+           <entry>&nbsp;</entry>
+           <entry spanname="b0">Byte&nbsp;0 in memory</entry>
+           <entry spanname="b1">Byte&nbsp;1</entry>
+           <entry spanname="b2">Byte&nbsp;2</entry>
+           <entry spanname="b3">Byte&nbsp;3</entry>
+         </row>
+         <row>
+           <entry>&nbsp;</entry>
+           <entry>&nbsp;</entry>
+           <entry>Bit</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+           <entry>&nbsp;</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+           <entry>&nbsp;</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+           <entry>&nbsp;</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row id="V4L2-PIX-FMT-RGB332">
+           <entry><constant>V4L2_PIX_FMT_RGB332</constant></entry>
+           <entry>'RGB1'</entry>
+           <entry></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-RGB444">
+           <entry><constant>V4L2_PIX_FMT_RGB444</constant></entry>
+           <entry>'R444'</entry>
+           <entry></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>a<subscript>3</subscript></entry>
+           <entry>a<subscript>2</subscript></entry>
+           <entry>a<subscript>1</subscript></entry>
+           <entry>a<subscript>0</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-RGB555">
+           <entry><constant>V4L2_PIX_FMT_RGB555</constant></entry>
+           <entry>'RGBO'</entry>
+           <entry></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>a</entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-RGB565">
+           <entry><constant>V4L2_PIX_FMT_RGB565</constant></entry>
+           <entry>'RGBP'</entry>
+           <entry></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-RGB555X">
+           <entry><constant>V4L2_PIX_FMT_RGB555X</constant></entry>
+           <entry>'RGBQ'</entry>
+           <entry></entry>
+           <entry>a</entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-RGB565X">
+           <entry><constant>V4L2_PIX_FMT_RGB565X</constant></entry>
+           <entry>'RGBR'</entry>
+           <entry></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-BGR666">
+           <entry><constant>V4L2_PIX_FMT_BGR666</constant></entry>
+           <entry>'BGRH'</entry>
+           <entry></entry>
+           <entry>b<subscript>5</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>r<subscript>5</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-BGR24">
+           <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
+           <entry>'BGR3'</entry>
+           <entry></entry>
+           <entry>b<subscript>7</subscript></entry>
+           <entry>b<subscript>6</subscript></entry>
+           <entry>b<subscript>5</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>7</subscript></entry>
+           <entry>g<subscript>6</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>r<subscript>7</subscript></entry>
+           <entry>r<subscript>6</subscript></entry>
+           <entry>r<subscript>5</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-RGB24">
+           <entry><constant>V4L2_PIX_FMT_RGB24</constant></entry>
+           <entry>'RGB3'</entry>
+           <entry></entry>
+           <entry>r<subscript>7</subscript></entry>
+           <entry>r<subscript>6</subscript></entry>
+           <entry>r<subscript>5</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>7</subscript></entry>
+           <entry>g<subscript>6</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>b<subscript>7</subscript></entry>
+           <entry>b<subscript>6</subscript></entry>
+           <entry>b<subscript>5</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-BGR32">
+           <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
+           <entry>'BGR4'</entry>
+           <entry></entry>
+           <entry>b<subscript>7</subscript></entry>
+           <entry>b<subscript>6</subscript></entry>
+           <entry>b<subscript>5</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>7</subscript></entry>
+           <entry>g<subscript>6</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>r<subscript>7</subscript></entry>
+           <entry>r<subscript>6</subscript></entry>
+           <entry>r<subscript>5</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>a<subscript>7</subscript></entry>
+           <entry>a<subscript>6</subscript></entry>
+           <entry>a<subscript>5</subscript></entry>
+           <entry>a<subscript>4</subscript></entry>
+           <entry>a<subscript>3</subscript></entry>
+           <entry>a<subscript>2</subscript></entry>
+           <entry>a<subscript>1</subscript></entry>
+           <entry>a<subscript>0</subscript></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-RGB32">
+           <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
+           <entry>'RGB4'</entry>
+           <entry></entry>
+           <entry>r<subscript>7</subscript></entry>
+           <entry>r<subscript>6</subscript></entry>
+           <entry>r<subscript>5</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>7</subscript></entry>
+           <entry>g<subscript>6</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>b<subscript>7</subscript></entry>
+           <entry>b<subscript>6</subscript></entry>
+           <entry>b<subscript>5</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>a<subscript>7</subscript></entry>
+           <entry>a<subscript>6</subscript></entry>
+           <entry>a<subscript>5</subscript></entry>
+           <entry>a<subscript>4</subscript></entry>
+           <entry>a<subscript>3</subscript></entry>
+           <entry>a<subscript>2</subscript></entry>
+           <entry>a<subscript>1</subscript></entry>
+           <entry>a<subscript>0</subscript></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <para>Bit 7 is the most significant bit. The value of a = alpha
+bits is undefined when reading from the driver, ignored when writing
+to the driver, except when alpha blending has been negotiated for a
+<link linkend="overlay">Video Overlay</link> or <link
+linkend="osd">Video Output Overlay</link>.</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_BGR24</constant> 4 &times; 4 pixel
+image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte.
+             <informaltable frame="none">
+           <tgroup cols="13" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>B<subscript>00</subscript></entry>
+                 <entry>G<subscript>00</subscript></entry>
+                 <entry>R<subscript>00</subscript></entry>
+                 <entry>B<subscript>01</subscript></entry>
+                 <entry>G<subscript>01</subscript></entry>
+                 <entry>R<subscript>01</subscript></entry>
+                 <entry>B<subscript>02</subscript></entry>
+                 <entry>G<subscript>02</subscript></entry>
+                 <entry>R<subscript>02</subscript></entry>
+                 <entry>B<subscript>03</subscript></entry>
+                 <entry>G<subscript>03</subscript></entry>
+                 <entry>R<subscript>03</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;12:</entry>
+                 <entry>B<subscript>10</subscript></entry>
+                 <entry>G<subscript>10</subscript></entry>
+                 <entry>R<subscript>10</subscript></entry>
+                 <entry>B<subscript>11</subscript></entry>
+                 <entry>G<subscript>11</subscript></entry>
+                 <entry>R<subscript>11</subscript></entry>
+                 <entry>B<subscript>12</subscript></entry>
+                 <entry>G<subscript>12</subscript></entry>
+                 <entry>R<subscript>12</subscript></entry>
+                 <entry>B<subscript>13</subscript></entry>
+                 <entry>G<subscript>13</subscript></entry>
+                 <entry>R<subscript>13</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>B<subscript>20</subscript></entry>
+                 <entry>G<subscript>20</subscript></entry>
+                 <entry>R<subscript>20</subscript></entry>
+                 <entry>B<subscript>21</subscript></entry>
+                 <entry>G<subscript>21</subscript></entry>
+                 <entry>R<subscript>21</subscript></entry>
+                 <entry>B<subscript>22</subscript></entry>
+                 <entry>G<subscript>22</subscript></entry>
+                 <entry>R<subscript>22</subscript></entry>
+                 <entry>B<subscript>23</subscript></entry>
+                 <entry>G<subscript>23</subscript></entry>
+                 <entry>R<subscript>23</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;36:</entry>
+                 <entry>B<subscript>30</subscript></entry>
+                 <entry>G<subscript>30</subscript></entry>
+                 <entry>R<subscript>30</subscript></entry>
+                 <entry>B<subscript>31</subscript></entry>
+                 <entry>G<subscript>31</subscript></entry>
+                 <entry>R<subscript>31</subscript></entry>
+                 <entry>B<subscript>32</subscript></entry>
+                 <entry>G<subscript>32</subscript></entry>
+                 <entry>R<subscript>32</subscript></entry>
+                 <entry>B<subscript>33</subscript></entry>
+                 <entry>G<subscript>33</subscript></entry>
+                 <entry>R<subscript>33</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+             </informaltable>
+           </para>
+      </formalpara>
+    </example>
+
+    <important>
+      <para>Drivers may interpret these formats differently.</para>
+    </important>
+
+    <para>Some RGB formats above are uncommon and were probably
+defined in error. Drivers may interpret them as in <xref
+       linkend="rgb-formats-corrected" />.</para>
+
+    <table pgwide="1" frame="none" id="rgb-formats-corrected">
+      <title>Packed RGB Image Formats (corrected)</title>
+      <tgroup cols="37" align="center">
+       <colspec colname="id" align="left" />
+       <colspec colname="fourcc" />
+       <colspec colname="bit" />
+
+       <colspec colnum="4" colname="b07" align="center" />
+       <colspec colnum="5" colname="b06" align="center" />
+       <colspec colnum="6" colname="b05" align="center" />
+       <colspec colnum="7" colname="b04" align="center" />
+       <colspec colnum="8" colname="b03" align="center" />
+       <colspec colnum="9" colname="b02" align="center" />
+       <colspec colnum="10" colname="b01" align="center" />
+       <colspec colnum="11" colname="b00" align="center" />
+
+       <colspec colnum="13" colname="b17" align="center" />
+       <colspec colnum="14" colname="b16" align="center" />
+       <colspec colnum="15" colname="b15" align="center" />
+       <colspec colnum="16" colname="b14" align="center" />
+       <colspec colnum="17" colname="b13" align="center" />
+       <colspec colnum="18" colname="b12" align="center" />
+       <colspec colnum="19" colname="b11" align="center" />
+       <colspec colnum="20" colname="b10" align="center" />
+
+       <colspec colnum="22" colname="b27" align="center" />
+       <colspec colnum="23" colname="b26" align="center" />
+       <colspec colnum="24" colname="b25" align="center" />
+       <colspec colnum="25" colname="b24" align="center" />
+       <colspec colnum="26" colname="b23" align="center" />
+       <colspec colnum="27" colname="b22" align="center" />
+       <colspec colnum="28" colname="b21" align="center" />
+       <colspec colnum="29" colname="b20" align="center" />
+
+       <colspec colnum="31" colname="b37" align="center" />
+       <colspec colnum="32" colname="b36" align="center" />
+       <colspec colnum="33" colname="b35" align="center" />
+       <colspec colnum="34" colname="b34" align="center" />
+       <colspec colnum="35" colname="b33" align="center" />
+       <colspec colnum="36" colname="b32" align="center" />
+       <colspec colnum="37" colname="b31" align="center" />
+       <colspec colnum="38" colname="b30" align="center" />
+
+       <spanspec namest="b07" nameend="b00" spanname="b0" />
+       <spanspec namest="b17" nameend="b10" spanname="b1" />
+       <spanspec namest="b27" nameend="b20" spanname="b2" />
+       <spanspec namest="b37" nameend="b30" spanname="b3" />
+       <thead>
+         <row>
+           <entry>Identifier</entry>
+           <entry>Code</entry>
+           <entry>&nbsp;</entry>
+           <entry spanname="b0">Byte&nbsp;0 in memory</entry>
+           <entry spanname="b1">Byte&nbsp;1</entry>
+           <entry spanname="b2">Byte&nbsp;2</entry>
+           <entry spanname="b3">Byte&nbsp;3</entry>
+         </row>
+         <row>
+           <entry>&nbsp;</entry>
+           <entry>&nbsp;</entry>
+           <entry>Bit</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+           <entry>&nbsp;</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+           <entry>&nbsp;</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+           <entry>&nbsp;</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row><!-- id="V4L2-PIX-FMT-RGB332" -->
+           <entry><constant>V4L2_PIX_FMT_RGB332</constant></entry>
+           <entry>'RGB1'</entry>
+           <entry></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+         </row>
+         <row><!-- id="V4L2-PIX-FMT-RGB444" -->
+           <entry><constant>V4L2_PIX_FMT_RGB444</constant></entry>
+           <entry>'R444'</entry>
+           <entry></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>a<subscript>3</subscript></entry>
+           <entry>a<subscript>2</subscript></entry>
+           <entry>a<subscript>1</subscript></entry>
+           <entry>a<subscript>0</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+         </row>
+         <row><!-- id="V4L2-PIX-FMT-RGB555" -->
+           <entry><constant>V4L2_PIX_FMT_RGB555</constant></entry>
+           <entry>'RGBO'</entry>
+           <entry></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>a</entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+         </row>
+         <row><!-- id="V4L2-PIX-FMT-RGB565" -->
+           <entry><constant>V4L2_PIX_FMT_RGB565</constant></entry>
+           <entry>'RGBP'</entry>
+           <entry></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+         </row>
+         <row><!-- id="V4L2-PIX-FMT-RGB555X" -->
+           <entry><constant>V4L2_PIX_FMT_RGB555X</constant></entry>
+           <entry>'RGBQ'</entry>
+           <entry></entry>
+           <entry>a</entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+         </row>
+         <row><!-- id="V4L2-PIX-FMT-RGB565X" -->
+           <entry><constant>V4L2_PIX_FMT_RGB565X</constant></entry>
+           <entry>'RGBR'</entry>
+           <entry></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+         </row>
+         <row><!-- id="V4L2-PIX-FMT-BGR666" -->
+           <entry><constant>V4L2_PIX_FMT_BGR666</constant></entry>
+           <entry>'BGRH'</entry>
+           <entry></entry>
+           <entry>b<subscript>5</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry>r<subscript>5</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+         <row><!-- id="V4L2-PIX-FMT-BGR24" -->
+           <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
+           <entry>'BGR3'</entry>
+           <entry></entry>
+           <entry>b<subscript>7</subscript></entry>
+           <entry>b<subscript>6</subscript></entry>
+           <entry>b<subscript>5</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>7</subscript></entry>
+           <entry>g<subscript>6</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>r<subscript>7</subscript></entry>
+           <entry>r<subscript>6</subscript></entry>
+           <entry>r<subscript>5</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+         </row>
+         <row><!-- id="V4L2-PIX-FMT-RGB24" -->
+           <entry><constant>V4L2_PIX_FMT_RGB24</constant></entry>
+           <entry>'RGB3'</entry>
+           <entry></entry>
+           <entry>r<subscript>7</subscript></entry>
+           <entry>r<subscript>6</subscript></entry>
+           <entry>r<subscript>5</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>7</subscript></entry>
+           <entry>g<subscript>6</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>b<subscript>7</subscript></entry>
+           <entry>b<subscript>6</subscript></entry>
+           <entry>b<subscript>5</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+         </row>
+         <row><!-- id="V4L2-PIX-FMT-BGR32" -->
+           <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
+           <entry>'BGR4'</entry>
+           <entry></entry>
+           <entry>b<subscript>7</subscript></entry>
+           <entry>b<subscript>6</subscript></entry>
+           <entry>b<subscript>5</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>7</subscript></entry>
+           <entry>g<subscript>6</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>r<subscript>7</subscript></entry>
+           <entry>r<subscript>6</subscript></entry>
+           <entry>r<subscript>5</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>a<subscript>7</subscript></entry>
+           <entry>a<subscript>6</subscript></entry>
+           <entry>a<subscript>5</subscript></entry>
+           <entry>a<subscript>4</subscript></entry>
+           <entry>a<subscript>3</subscript></entry>
+           <entry>a<subscript>2</subscript></entry>
+           <entry>a<subscript>1</subscript></entry>
+           <entry>a<subscript>0</subscript></entry>
+         </row>
+         <row><!-- id="V4L2-PIX-FMT-RGB32" -->
+           <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
+           <entry>'RGB4'</entry>
+           <entry></entry>
+           <entry>a<subscript>7</subscript></entry>
+           <entry>a<subscript>6</subscript></entry>
+           <entry>a<subscript>5</subscript></entry>
+           <entry>a<subscript>4</subscript></entry>
+           <entry>a<subscript>3</subscript></entry>
+           <entry>a<subscript>2</subscript></entry>
+           <entry>a<subscript>1</subscript></entry>
+           <entry>a<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>r<subscript>7</subscript></entry>
+           <entry>r<subscript>6</subscript></entry>
+           <entry>r<subscript>5</subscript></entry>
+           <entry>r<subscript>4</subscript></entry>
+           <entry>r<subscript>3</subscript></entry>
+           <entry>r<subscript>2</subscript></entry>
+           <entry>r<subscript>1</subscript></entry>
+           <entry>r<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>g<subscript>7</subscript></entry>
+           <entry>g<subscript>6</subscript></entry>
+           <entry>g<subscript>5</subscript></entry>
+           <entry>g<subscript>4</subscript></entry>
+           <entry>g<subscript>3</subscript></entry>
+           <entry>g<subscript>2</subscript></entry>
+           <entry>g<subscript>1</subscript></entry>
+           <entry>g<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>b<subscript>7</subscript></entry>
+           <entry>b<subscript>6</subscript></entry>
+           <entry>b<subscript>5</subscript></entry>
+           <entry>b<subscript>4</subscript></entry>
+           <entry>b<subscript>3</subscript></entry>
+           <entry>b<subscript>2</subscript></entry>
+           <entry>b<subscript>1</subscript></entry>
+           <entry>b<subscript>0</subscript></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <para>A test utility to determine which RGB formats a driver
+actually supports is available from the LinuxTV v4l-dvb repository.
+See &v4l-dvb; for access instructions.</para>
+
+  </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-yuv.xml
new file mode 100644 (file)
index 0000000..3cab5d0
--- /dev/null
@@ -0,0 +1,244 @@
+<refentry id="packed-yuv">
+  <refmeta>
+    <refentrytitle>Packed YUV formats</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname>Packed YUV formats</refname>
+    <refpurpose>Packed YUV formats</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>Similar to the packed RGB formats these formats store
+the Y, Cb and Cr component of each pixel in one 16 or 32 bit
+word.</para>
+
+    <table pgwide="1" frame="none">
+      <title>Packed YUV Image Formats</title>
+      <tgroup cols="37" align="center">
+       <colspec colname="id" align="left" />
+       <colspec colname="fourcc" />
+       <colspec colname="bit" />
+
+       <colspec colnum="4" colname="b07" align="center" />
+       <colspec colnum="5" colname="b06" align="center" />
+       <colspec colnum="6" colname="b05" align="center" />
+       <colspec colnum="7" colname="b04" align="center" />
+       <colspec colnum="8" colname="b03" align="center" />
+       <colspec colnum="9" colname="b02" align="center" />
+       <colspec colnum="10" colname="b01" align="center" />
+       <colspec colnum="11" colname="b00" align="center" />
+
+       <colspec colnum="13" colname="b17" align="center" />
+       <colspec colnum="14" colname="b16" align="center" />
+       <colspec colnum="15" colname="b15" align="center" />
+       <colspec colnum="16" colname="b14" align="center" />
+       <colspec colnum="17" colname="b13" align="center" />
+       <colspec colnum="18" colname="b12" align="center" />
+       <colspec colnum="19" colname="b11" align="center" />
+       <colspec colnum="20" colname="b10" align="center" />
+
+       <colspec colnum="22" colname="b27" align="center" />
+       <colspec colnum="23" colname="b26" align="center" />
+       <colspec colnum="24" colname="b25" align="center" />
+       <colspec colnum="25" colname="b24" align="center" />
+       <colspec colnum="26" colname="b23" align="center" />
+       <colspec colnum="27" colname="b22" align="center" />
+       <colspec colnum="28" colname="b21" align="center" />
+       <colspec colnum="29" colname="b20" align="center" />
+
+       <colspec colnum="31" colname="b37" align="center" />
+       <colspec colnum="32" colname="b36" align="center" />
+       <colspec colnum="33" colname="b35" align="center" />
+       <colspec colnum="34" colname="b34" align="center" />
+       <colspec colnum="35" colname="b33" align="center" />
+       <colspec colnum="36" colname="b32" align="center" />
+       <colspec colnum="37" colname="b31" align="center" />
+       <colspec colnum="38" colname="b30" align="center" />
+
+       <spanspec namest="b07" nameend="b00" spanname="b0" />
+       <spanspec namest="b17" nameend="b10" spanname="b1" />
+       <spanspec namest="b27" nameend="b20" spanname="b2" />
+       <spanspec namest="b37" nameend="b30" spanname="b3" />
+       <thead>
+         <row>
+           <entry>Identifier</entry>
+           <entry>Code</entry>
+           <entry>&nbsp;</entry>
+           <entry spanname="b0">Byte&nbsp;0 in memory</entry>
+           <entry spanname="b1">Byte&nbsp;1</entry>
+           <entry spanname="b2">Byte&nbsp;2</entry>
+           <entry spanname="b3">Byte&nbsp;3</entry>
+         </row>
+         <row>
+           <entry>&nbsp;</entry>
+           <entry>&nbsp;</entry>
+           <entry>Bit</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+           <entry>&nbsp;</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+           <entry>&nbsp;</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+           <entry>&nbsp;</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row id="V4L2-PIX-FMT-YUV444">
+           <entry><constant>V4L2_PIX_FMT_YUV444</constant></entry>
+           <entry>'Y444'</entry>
+           <entry></entry>
+           <entry>Cb<subscript>3</subscript></entry>
+           <entry>Cb<subscript>2</subscript></entry>
+           <entry>Cb<subscript>1</subscript></entry>
+           <entry>Cb<subscript>0</subscript></entry>
+           <entry>Cr<subscript>3</subscript></entry>
+           <entry>Cr<subscript>2</subscript></entry>
+           <entry>Cr<subscript>1</subscript></entry>
+           <entry>Cr<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>a<subscript>3</subscript></entry>
+           <entry>a<subscript>2</subscript></entry>
+           <entry>a<subscript>1</subscript></entry>
+           <entry>a<subscript>0</subscript></entry>
+           <entry>Y'<subscript>3</subscript></entry>
+           <entry>Y'<subscript>2</subscript></entry>
+           <entry>Y'<subscript>1</subscript></entry>
+           <entry>Y'<subscript>0</subscript></entry>
+         </row>
+
+         <row id="V4L2-PIX-FMT-YUV555">
+           <entry><constant>V4L2_PIX_FMT_YUV555</constant></entry>
+           <entry>'YUVO'</entry>
+           <entry></entry>
+           <entry>Cb<subscript>2</subscript></entry>
+           <entry>Cb<subscript>1</subscript></entry>
+           <entry>Cb<subscript>0</subscript></entry>
+           <entry>Cr<subscript>4</subscript></entry>
+           <entry>Cr<subscript>3</subscript></entry>
+           <entry>Cr<subscript>2</subscript></entry>
+           <entry>Cr<subscript>1</subscript></entry>
+           <entry>Cr<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>a</entry>
+           <entry>Y'<subscript>4</subscript></entry>
+           <entry>Y'<subscript>3</subscript></entry>
+           <entry>Y'<subscript>2</subscript></entry>
+           <entry>Y'<subscript>1</subscript></entry>
+           <entry>Y'<subscript>0</subscript></entry>
+           <entry>Cb<subscript>4</subscript></entry>
+           <entry>Cb<subscript>3</subscript></entry>
+         </row>
+
+         <row id="V4L2-PIX-FMT-YUV565">
+           <entry><constant>V4L2_PIX_FMT_YUV565</constant></entry>
+           <entry>'YUVP'</entry>
+           <entry></entry>
+           <entry>Cb<subscript>2</subscript></entry>
+           <entry>Cb<subscript>1</subscript></entry>
+           <entry>Cb<subscript>0</subscript></entry>
+           <entry>Cr<subscript>4</subscript></entry>
+           <entry>Cr<subscript>3</subscript></entry>
+           <entry>Cr<subscript>2</subscript></entry>
+           <entry>Cr<subscript>1</subscript></entry>
+           <entry>Cr<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>Y'<subscript>4</subscript></entry>
+           <entry>Y'<subscript>3</subscript></entry>
+           <entry>Y'<subscript>2</subscript></entry>
+           <entry>Y'<subscript>1</subscript></entry>
+           <entry>Y'<subscript>0</subscript></entry>
+           <entry>Cb<subscript>5</subscript></entry>
+           <entry>Cb<subscript>4</subscript></entry>
+           <entry>Cb<subscript>3</subscript></entry>
+         </row>
+
+         <row id="V4L2-PIX-FMT-YUV32">
+           <entry><constant>V4L2_PIX_FMT_YUV32</constant></entry>
+           <entry>'YUV4'</entry>
+           <entry></entry>
+           <entry>a<subscript>7</subscript></entry>
+           <entry>a<subscript>6</subscript></entry>
+           <entry>a<subscript>5</subscript></entry>
+           <entry>a<subscript>4</subscript></entry>
+           <entry>a<subscript>3</subscript></entry>
+           <entry>a<subscript>2</subscript></entry>
+           <entry>a<subscript>1</subscript></entry>
+           <entry>a<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>Y'<subscript>7</subscript></entry>
+           <entry>Y'<subscript>6</subscript></entry>
+           <entry>Y'<subscript>5</subscript></entry>
+           <entry>Y'<subscript>4</subscript></entry>
+           <entry>Y'<subscript>3</subscript></entry>
+           <entry>Y'<subscript>2</subscript></entry>
+           <entry>Y'<subscript>1</subscript></entry>
+           <entry>Y'<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>Cb<subscript>7</subscript></entry>
+           <entry>Cb<subscript>6</subscript></entry>
+           <entry>Cb<subscript>5</subscript></entry>
+           <entry>Cb<subscript>4</subscript></entry>
+           <entry>Cb<subscript>3</subscript></entry>
+           <entry>Cb<subscript>2</subscript></entry>
+           <entry>Cb<subscript>1</subscript></entry>
+           <entry>Cb<subscript>0</subscript></entry>
+           <entry></entry>
+           <entry>Cr<subscript>7</subscript></entry>
+           <entry>Cr<subscript>6</subscript></entry>
+           <entry>Cr<subscript>5</subscript></entry>
+           <entry>Cr<subscript>4</subscript></entry>
+           <entry>Cr<subscript>3</subscript></entry>
+           <entry>Cr<subscript>2</subscript></entry>
+           <entry>Cr<subscript>1</subscript></entry>
+           <entry>Cr<subscript>0</subscript></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <para>Bit 7 is the most significant bit. The value of a = alpha
+bits is undefined when reading from the driver, ignored when writing
+to the driver, except when alpha blending has been negotiated for a
+<link linkend="overlay">Video Overlay</link> or <link
+linkend="osd">Video Output Overlay</link>.</para>
+
+  </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml b/Documentation/DocBook/media/v4l/pixfmt-sbggr16.xml
new file mode 100644 (file)
index 0000000..519a9ef
--- /dev/null
@@ -0,0 +1,91 @@
+<refentry id="V4L2-PIX-FMT-SBGGR16">
+  <refmeta>
+    <refentrytitle>V4L2_PIX_FMT_SBGGR16 ('BYR2')</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname><constant>V4L2_PIX_FMT_SBGGR16</constant></refname>
+    <refpurpose>Bayer RGB format</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>This format is similar to <link
+linkend="V4L2-PIX-FMT-SBGGR8">
+<constant>V4L2_PIX_FMT_SBGGR8</constant></link>, except each pixel has
+a depth of 16 bits. The least significant byte is stored at lower
+memory addresses (little-endian). Note the actual sampling precision
+may be lower than 16 bits, for example 10 bits per pixel with values
+in range 0 to 1023.</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_SBGGR16</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte.
+         <informaltable frame="none">
+           <tgroup cols="5" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>B<subscript>00low</subscript></entry>
+                 <entry>B<subscript>00high</subscript></entry>
+                 <entry>G<subscript>01low</subscript></entry>
+                 <entry>G<subscript>01high</subscript></entry>
+                 <entry>B<subscript>02low</subscript></entry>
+                 <entry>B<subscript>02high</subscript></entry>
+                 <entry>G<subscript>03low</subscript></entry>
+                 <entry>G<subscript>03high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;8:</entry>
+                 <entry>G<subscript>10low</subscript></entry>
+                 <entry>G<subscript>10high</subscript></entry>
+                 <entry>R<subscript>11low</subscript></entry>
+                 <entry>R<subscript>11high</subscript></entry>
+                 <entry>G<subscript>12low</subscript></entry>
+                 <entry>G<subscript>12high</subscript></entry>
+                 <entry>R<subscript>13low</subscript></entry>
+                 <entry>R<subscript>13high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;16:</entry>
+                 <entry>B<subscript>20low</subscript></entry>
+                 <entry>B<subscript>20high</subscript></entry>
+                 <entry>G<subscript>21low</subscript></entry>
+                 <entry>G<subscript>21high</subscript></entry>
+                 <entry>B<subscript>22low</subscript></entry>
+                 <entry>B<subscript>22high</subscript></entry>
+                 <entry>G<subscript>23low</subscript></entry>
+                 <entry>G<subscript>23high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>G<subscript>30low</subscript></entry>
+                 <entry>G<subscript>30high</subscript></entry>
+                 <entry>R<subscript>31low</subscript></entry>
+                 <entry>R<subscript>31high</subscript></entry>
+                 <entry>G<subscript>32low</subscript></entry>
+                 <entry>G<subscript>32high</subscript></entry>
+                 <entry>R<subscript>33low</subscript></entry>
+                 <entry>R<subscript>33high</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml b/Documentation/DocBook/media/v4l/pixfmt-sbggr8.xml
new file mode 100644 (file)
index 0000000..5fe84ec
--- /dev/null
@@ -0,0 +1,75 @@
+    <refentry id="V4L2-PIX-FMT-SBGGR8">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_SBGGR8 ('BA81')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_SBGGR8</constant></refname>
+       <refpurpose>Bayer RGB format</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is commonly the native format of digital cameras,
+reflecting the arrangement of sensors on the CCD device. Only one red,
+green or blue value is given for each pixel. Missing components must
+be interpolated from neighbouring pixels. From left to right the first
+row consists of a blue and green value, the second row of a green and
+red value. This scheme repeats to the right and down for every two
+columns and rows.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_SBGGR8</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+             <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>B<subscript>00</subscript></entry>
+                     <entry>G<subscript>01</subscript></entry>
+                     <entry>B<subscript>02</subscript></entry>
+                     <entry>G<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>G<subscript>10</subscript></entry>
+                     <entry>R<subscript>11</subscript></entry>
+                     <entry>G<subscript>12</subscript></entry>
+                     <entry>R<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>B<subscript>20</subscript></entry>
+                     <entry>G<subscript>21</subscript></entry>
+                     <entry>B<subscript>22</subscript></entry>
+                     <entry>G<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>G<subscript>30</subscript></entry>
+                     <entry>R<subscript>31</subscript></entry>
+                     <entry>G<subscript>32</subscript></entry>
+                     <entry>R<subscript>33</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+             </informaltable>
+           </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml b/Documentation/DocBook/media/v4l/pixfmt-sgbrg8.xml
new file mode 100644 (file)
index 0000000..d67a472
--- /dev/null
@@ -0,0 +1,75 @@
+    <refentry id="V4L2-PIX-FMT-SGBRG8">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_SGBRG8 ('GBRG')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_SGBRG8</constant></refname>
+       <refpurpose>Bayer RGB format</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is commonly the native format of digital cameras,
+reflecting the arrangement of sensors on the CCD device. Only one red,
+green or blue value is given for each pixel. Missing components must
+be interpolated from neighbouring pixels. From left to right the first
+row consists of a green and blue value, the second row of a red and
+green value. This scheme repeats to the right and down for every two
+columns and rows.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_SGBRG8</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+             <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>G<subscript>00</subscript></entry>
+                     <entry>B<subscript>01</subscript></entry>
+                     <entry>G<subscript>02</subscript></entry>
+                     <entry>B<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>R<subscript>10</subscript></entry>
+                     <entry>G<subscript>11</subscript></entry>
+                     <entry>R<subscript>12</subscript></entry>
+                     <entry>G<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>G<subscript>20</subscript></entry>
+                     <entry>B<subscript>21</subscript></entry>
+                     <entry>G<subscript>22</subscript></entry>
+                     <entry>B<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>R<subscript>30</subscript></entry>
+                     <entry>G<subscript>31</subscript></entry>
+                     <entry>R<subscript>32</subscript></entry>
+                     <entry>G<subscript>33</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+             </informaltable>
+           </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml b/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml
new file mode 100644 (file)
index 0000000..0cdf13b
--- /dev/null
@@ -0,0 +1,75 @@
+    <refentry id="V4L2-PIX-FMT-SGRBG8">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_SGRBG8 ('GRBG')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_SGRBG8</constant></refname>
+       <refpurpose>Bayer RGB format</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is commonly the native format of digital cameras,
+reflecting the arrangement of sensors on the CCD device. Only one red,
+green or blue value is given for each pixel. Missing components must
+be interpolated from neighbouring pixels. From left to right the first
+row consists of a green and blue value, the second row of a red and
+green value. This scheme repeats to the right and down for every two
+columns and rows.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_SGRBG8</constant> 4 &times;
+4 pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+             <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>G<subscript>00</subscript></entry>
+                     <entry>R<subscript>01</subscript></entry>
+                     <entry>G<subscript>02</subscript></entry>
+                     <entry>R<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>R<subscript>10</subscript></entry>
+                     <entry>B<subscript>11</subscript></entry>
+                     <entry>R<subscript>12</subscript></entry>
+                     <entry>B<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>G<subscript>20</subscript></entry>
+                     <entry>R<subscript>21</subscript></entry>
+                     <entry>G<subscript>22</subscript></entry>
+                     <entry>R<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>R<subscript>30</subscript></entry>
+                     <entry>B<subscript>31</subscript></entry>
+                     <entry>R<subscript>32</subscript></entry>
+                     <entry>B<subscript>33</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+             </informaltable>
+           </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml
new file mode 100644 (file)
index 0000000..7b27409
--- /dev/null
@@ -0,0 +1,90 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_SRGGB10 ('RG10'),
+        V4L2_PIX_FMT_SGRBG10 ('BA10'),
+        V4L2_PIX_FMT_SGBRG10 ('GB10'),
+        V4L2_PIX_FMT_SBGGR10 ('BG10'),
+        </refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-SRGGB10"><constant>V4L2_PIX_FMT_SRGGB10</constant></refname>
+       <refname id="V4L2-PIX-FMT-SGRBG10"><constant>V4L2_PIX_FMT_SGRBG10</constant></refname>
+       <refname id="V4L2-PIX-FMT-SGBRG10"><constant>V4L2_PIX_FMT_SGBRG10</constant></refname>
+       <refname id="V4L2-PIX-FMT-SBGGR10"><constant>V4L2_PIX_FMT_SBGGR10</constant></refname>
+       <refpurpose>10-bit Bayer formats expanded to 16 bits</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>The following four pixel formats are raw sRGB / Bayer formats with
+10 bits per colour. Each colour component is stored in a 16-bit word, with 6
+unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
+and n/2 blue or red samples, with alternating red and blue rows. Bytes are
+stored in memory in little endian order. They are conventionally described
+as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an example of one of these
+formats</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_SBGGR10</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte, high 6 bits in high bytes are 0.
+         <informaltable frame="none">
+           <tgroup cols="5" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>B<subscript>00low</subscript></entry>
+                 <entry>B<subscript>00high</subscript></entry>
+                 <entry>G<subscript>01low</subscript></entry>
+                 <entry>G<subscript>01high</subscript></entry>
+                 <entry>B<subscript>02low</subscript></entry>
+                 <entry>B<subscript>02high</subscript></entry>
+                 <entry>G<subscript>03low</subscript></entry>
+                 <entry>G<subscript>03high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;8:</entry>
+                 <entry>G<subscript>10low</subscript></entry>
+                 <entry>G<subscript>10high</subscript></entry>
+                 <entry>R<subscript>11low</subscript></entry>
+                 <entry>R<subscript>11high</subscript></entry>
+                 <entry>G<subscript>12low</subscript></entry>
+                 <entry>G<subscript>12high</subscript></entry>
+                 <entry>R<subscript>13low</subscript></entry>
+                 <entry>R<subscript>13high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;16:</entry>
+                 <entry>B<subscript>20low</subscript></entry>
+                 <entry>B<subscript>20high</subscript></entry>
+                 <entry>G<subscript>21low</subscript></entry>
+                 <entry>G<subscript>21high</subscript></entry>
+                 <entry>B<subscript>22low</subscript></entry>
+                 <entry>B<subscript>22high</subscript></entry>
+                 <entry>G<subscript>23low</subscript></entry>
+                 <entry>G<subscript>23high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>G<subscript>30low</subscript></entry>
+                 <entry>G<subscript>30high</subscript></entry>
+                 <entry>R<subscript>31low</subscript></entry>
+                 <entry>R<subscript>31high</subscript></entry>
+                 <entry>G<subscript>32low</subscript></entry>
+                 <entry>G<subscript>32high</subscript></entry>
+                 <entry>R<subscript>33low</subscript></entry>
+                 <entry>R<subscript>33high</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml
new file mode 100644 (file)
index 0000000..9ba4fb6
--- /dev/null
@@ -0,0 +1,90 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_SRGGB12 ('RG12'),
+        V4L2_PIX_FMT_SGRBG12 ('BA12'),
+        V4L2_PIX_FMT_SGBRG12 ('GB12'),
+        V4L2_PIX_FMT_SBGGR12 ('BG12'),
+        </refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-SRGGB12"><constant>V4L2_PIX_FMT_SRGGB12</constant></refname>
+       <refname id="V4L2-PIX-FMT-SGRBG12"><constant>V4L2_PIX_FMT_SGRBG12</constant></refname>
+       <refname id="V4L2-PIX-FMT-SGBRG12"><constant>V4L2_PIX_FMT_SGBRG12</constant></refname>
+       <refname id="V4L2-PIX-FMT-SBGGR12"><constant>V4L2_PIX_FMT_SBGGR12</constant></refname>
+       <refpurpose>12-bit Bayer formats expanded to 16 bits</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>The following four pixel formats are raw sRGB / Bayer formats with
+12 bits per colour. Each colour component is stored in a 16-bit word, with 6
+unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
+and n/2 blue or red samples, with alternating red and blue rows. Bytes are
+stored in memory in little endian order. They are conventionally described
+as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an example of one of these
+formats</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_SBGGR12</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte, high 6 bits in high bytes are 0.
+         <informaltable frame="none">
+           <tgroup cols="5" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>B<subscript>00low</subscript></entry>
+                 <entry>B<subscript>00high</subscript></entry>
+                 <entry>G<subscript>01low</subscript></entry>
+                 <entry>G<subscript>01high</subscript></entry>
+                 <entry>B<subscript>02low</subscript></entry>
+                 <entry>B<subscript>02high</subscript></entry>
+                 <entry>G<subscript>03low</subscript></entry>
+                 <entry>G<subscript>03high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;8:</entry>
+                 <entry>G<subscript>10low</subscript></entry>
+                 <entry>G<subscript>10high</subscript></entry>
+                 <entry>R<subscript>11low</subscript></entry>
+                 <entry>R<subscript>11high</subscript></entry>
+                 <entry>G<subscript>12low</subscript></entry>
+                 <entry>G<subscript>12high</subscript></entry>
+                 <entry>R<subscript>13low</subscript></entry>
+                 <entry>R<subscript>13high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;16:</entry>
+                 <entry>B<subscript>20low</subscript></entry>
+                 <entry>B<subscript>20high</subscript></entry>
+                 <entry>G<subscript>21low</subscript></entry>
+                 <entry>G<subscript>21high</subscript></entry>
+                 <entry>B<subscript>22low</subscript></entry>
+                 <entry>B<subscript>22high</subscript></entry>
+                 <entry>G<subscript>23low</subscript></entry>
+                 <entry>G<subscript>23high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>G<subscript>30low</subscript></entry>
+                 <entry>G<subscript>30high</subscript></entry>
+                 <entry>R<subscript>31low</subscript></entry>
+                 <entry>R<subscript>31high</subscript></entry>
+                 <entry>G<subscript>32low</subscript></entry>
+                 <entry>G<subscript>32high</subscript></entry>
+                 <entry>R<subscript>33low</subscript></entry>
+                 <entry>R<subscript>33high</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb8.xml
new file mode 100644 (file)
index 0000000..2570e3b
--- /dev/null
@@ -0,0 +1,67 @@
+    <refentry id="V4L2-PIX-FMT-SRGGB8">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_SRGGB8 ('RGGB')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_SRGGB8</constant></refname>
+       <refpurpose>Bayer RGB format</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is commonly the native format of digital cameras,
+reflecting the arrangement of sensors on the CCD device. Only one red,
+green or blue value is given for each pixel. Missing components must
+be interpolated from neighbouring pixels. From left to right the first
+row consists of a red and green value, the second row of a green and
+blue value. This scheme repeats to the right and down for every two
+columns and rows.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_SRGGB8</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+             <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>R<subscript>00</subscript></entry>
+                     <entry>G<subscript>01</subscript></entry>
+                     <entry>R<subscript>02</subscript></entry>
+                     <entry>G<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>G<subscript>10</subscript></entry>
+                     <entry>B<subscript>11</subscript></entry>
+                     <entry>G<subscript>12</subscript></entry>
+                     <entry>B<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>R<subscript>20</subscript></entry>
+                     <entry>G<subscript>21</subscript></entry>
+                     <entry>R<subscript>22</subscript></entry>
+                     <entry>G<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>G<subscript>30</subscript></entry>
+                     <entry>B<subscript>31</subscript></entry>
+                     <entry>G<subscript>32</subscript></entry>
+                     <entry>B<subscript>33</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+             </informaltable>
+           </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-uyvy.xml b/Documentation/DocBook/media/v4l/pixfmt-uyvy.xml
new file mode 100644 (file)
index 0000000..816c8d4
--- /dev/null
@@ -0,0 +1,128 @@
+    <refentry id="V4L2-PIX-FMT-UYVY">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_UYVY ('UYVY')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_UYVY</constant></refname>
+       <refpurpose>Variation of
+<constant>V4L2_PIX_FMT_YUYV</constant> with different order of samples
+in memory</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>In this format each four bytes is two pixels. Each four
+bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
+the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
+components have half the horizontal resolution of the Y
+component.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_UYVY</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="9" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Cb<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Cr<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Cb<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Cr<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;24:</entry>
+                     <entry>Cb<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Cr<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Cb<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Cr<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-vyuy.xml b/Documentation/DocBook/media/v4l/pixfmt-vyuy.xml
new file mode 100644 (file)
index 0000000..61f12a5
--- /dev/null
@@ -0,0 +1,128 @@
+    <refentry id="V4L2-PIX-FMT-VYUY">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_VYUY ('VYUY')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_VYUY</constant></refname>
+       <refpurpose>Variation of
+<constant>V4L2_PIX_FMT_YUYV</constant> with different order of samples
+in memory</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>In this format each four bytes is two pixels. Each four
+bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
+the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
+components have half the horizontal resolution of the Y
+component.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_VYUY</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="9" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Cr<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Cb<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Cr<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Cb<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;24:</entry>
+                     <entry>Cr<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Cb<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Cr<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Cb<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y10.xml b/Documentation/DocBook/media/v4l/pixfmt-y10.xml
new file mode 100644 (file)
index 0000000..d065043
--- /dev/null
@@ -0,0 +1,79 @@
+<refentry id="V4L2-PIX-FMT-Y10">
+  <refmeta>
+    <refentrytitle>V4L2_PIX_FMT_Y10 ('Y10 ')</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname><constant>V4L2_PIX_FMT_Y10</constant></refname>
+    <refpurpose>Grey-scale image</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>This is a grey-scale image with a depth of 10 bits per pixel. Pixels
+are stored in 16-bit words with unused high bits padded with 0. The least
+significant byte is stored at lower memory addresses (little-endian).</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_Y10</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte.
+         <informaltable frame="none">
+           <tgroup cols="9" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>Y'<subscript>00low</subscript></entry>
+                 <entry>Y'<subscript>00high</subscript></entry>
+                 <entry>Y'<subscript>01low</subscript></entry>
+                 <entry>Y'<subscript>01high</subscript></entry>
+                 <entry>Y'<subscript>02low</subscript></entry>
+                 <entry>Y'<subscript>02high</subscript></entry>
+                 <entry>Y'<subscript>03low</subscript></entry>
+                 <entry>Y'<subscript>03high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;8:</entry>
+                 <entry>Y'<subscript>10low</subscript></entry>
+                 <entry>Y'<subscript>10high</subscript></entry>
+                 <entry>Y'<subscript>11low</subscript></entry>
+                 <entry>Y'<subscript>11high</subscript></entry>
+                 <entry>Y'<subscript>12low</subscript></entry>
+                 <entry>Y'<subscript>12high</subscript></entry>
+                 <entry>Y'<subscript>13low</subscript></entry>
+                 <entry>Y'<subscript>13high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;16:</entry>
+                 <entry>Y'<subscript>20low</subscript></entry>
+                 <entry>Y'<subscript>20high</subscript></entry>
+                 <entry>Y'<subscript>21low</subscript></entry>
+                 <entry>Y'<subscript>21high</subscript></entry>
+                 <entry>Y'<subscript>22low</subscript></entry>
+                 <entry>Y'<subscript>22high</subscript></entry>
+                 <entry>Y'<subscript>23low</subscript></entry>
+                 <entry>Y'<subscript>23high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>Y'<subscript>30low</subscript></entry>
+                 <entry>Y'<subscript>30high</subscript></entry>
+                 <entry>Y'<subscript>31low</subscript></entry>
+                 <entry>Y'<subscript>31high</subscript></entry>
+                 <entry>Y'<subscript>32low</subscript></entry>
+                 <entry>Y'<subscript>32high</subscript></entry>
+                 <entry>Y'<subscript>33low</subscript></entry>
+                 <entry>Y'<subscript>33high</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y10b.xml b/Documentation/DocBook/media/v4l/pixfmt-y10b.xml
new file mode 100644 (file)
index 0000000..adb0ad8
--- /dev/null
@@ -0,0 +1,43 @@
+<refentry id="V4L2-PIX-FMT-Y10BPACK">
+  <refmeta>
+    <refentrytitle>V4L2_PIX_FMT_Y10BPACK ('Y10B')</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname><constant>V4L2_PIX_FMT_Y10BPACK</constant></refname>
+    <refpurpose>Grey-scale image as a bit-packed array</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>This is a packed grey-scale image format with a depth of 10 bits per
+      pixel. Pixels are stored in a bit-packed array of 10bit bits per pixel,
+      with no padding between them and with the most significant bits coming
+      first from the left.</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_Y10BPACK</constant> 4 pixel data stream taking 5 bytes</title>
+
+      <formalpara>
+       <title>Bit-packed representation</title>
+       <para>pixels cross the byte boundary and have a ratio of 5 bytes for each 4
+          pixels.
+         <informaltable frame="all">
+           <tgroup cols="5" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>Y'<subscript>00[9:2]</subscript></entry>
+                 <entry>Y'<subscript>00[1:0]</subscript>Y'<subscript>01[9:4]</subscript></entry>
+                 <entry>Y'<subscript>01[3:0]</subscript>Y'<subscript>02[9:6]</subscript></entry>
+                 <entry>Y'<subscript>02[5:0]</subscript>Y'<subscript>03[9:8]</subscript></entry>
+                 <entry>Y'<subscript>03[7:0]</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y12.xml b/Documentation/DocBook/media/v4l/pixfmt-y12.xml
new file mode 100644 (file)
index 0000000..ff417b8
--- /dev/null
@@ -0,0 +1,79 @@
+<refentry id="V4L2-PIX-FMT-Y12">
+  <refmeta>
+    <refentrytitle>V4L2_PIX_FMT_Y12 ('Y12 ')</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname><constant>V4L2_PIX_FMT_Y12</constant></refname>
+    <refpurpose>Grey-scale image</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>This is a grey-scale image with a depth of 12 bits per pixel. Pixels
+are stored in 16-bit words with unused high bits padded with 0. The least
+significant byte is stored at lower memory addresses (little-endian).</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_Y12</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte.
+         <informaltable frame="none">
+           <tgroup cols="9" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>Y'<subscript>00low</subscript></entry>
+                 <entry>Y'<subscript>00high</subscript></entry>
+                 <entry>Y'<subscript>01low</subscript></entry>
+                 <entry>Y'<subscript>01high</subscript></entry>
+                 <entry>Y'<subscript>02low</subscript></entry>
+                 <entry>Y'<subscript>02high</subscript></entry>
+                 <entry>Y'<subscript>03low</subscript></entry>
+                 <entry>Y'<subscript>03high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;8:</entry>
+                 <entry>Y'<subscript>10low</subscript></entry>
+                 <entry>Y'<subscript>10high</subscript></entry>
+                 <entry>Y'<subscript>11low</subscript></entry>
+                 <entry>Y'<subscript>11high</subscript></entry>
+                 <entry>Y'<subscript>12low</subscript></entry>
+                 <entry>Y'<subscript>12high</subscript></entry>
+                 <entry>Y'<subscript>13low</subscript></entry>
+                 <entry>Y'<subscript>13high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;16:</entry>
+                 <entry>Y'<subscript>20low</subscript></entry>
+                 <entry>Y'<subscript>20high</subscript></entry>
+                 <entry>Y'<subscript>21low</subscript></entry>
+                 <entry>Y'<subscript>21high</subscript></entry>
+                 <entry>Y'<subscript>22low</subscript></entry>
+                 <entry>Y'<subscript>22high</subscript></entry>
+                 <entry>Y'<subscript>23low</subscript></entry>
+                 <entry>Y'<subscript>23high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>Y'<subscript>30low</subscript></entry>
+                 <entry>Y'<subscript>30high</subscript></entry>
+                 <entry>Y'<subscript>31low</subscript></entry>
+                 <entry>Y'<subscript>31high</subscript></entry>
+                 <entry>Y'<subscript>32low</subscript></entry>
+                 <entry>Y'<subscript>32high</subscript></entry>
+                 <entry>Y'<subscript>33low</subscript></entry>
+                 <entry>Y'<subscript>33high</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y16.xml b/Documentation/DocBook/media/v4l/pixfmt-y16.xml
new file mode 100644 (file)
index 0000000..d584040
--- /dev/null
@@ -0,0 +1,89 @@
+<refentry id="V4L2-PIX-FMT-Y16">
+  <refmeta>
+    <refentrytitle>V4L2_PIX_FMT_Y16 ('Y16 ')</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname><constant>V4L2_PIX_FMT_Y16</constant></refname>
+    <refpurpose>Grey-scale image</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>This is a grey-scale image with a depth of 16 bits per
+pixel. The least significant byte is stored at lower memory addresses
+(little-endian). Note the actual sampling precision may be lower than
+16 bits, for example 10 bits per pixel with values in range 0 to
+1023.</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_Y16</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+       <title>Byte Order.</title>
+       <para>Each cell is one byte.
+         <informaltable frame="none">
+           <tgroup cols="9" align="center">
+             <colspec align="left" colwidth="2*" />
+             <tbody valign="top">
+               <row>
+                 <entry>start&nbsp;+&nbsp;0:</entry>
+                 <entry>Y'<subscript>00low</subscript></entry>
+                 <entry>Y'<subscript>00high</subscript></entry>
+                 <entry>Y'<subscript>01low</subscript></entry>
+                 <entry>Y'<subscript>01high</subscript></entry>
+                 <entry>Y'<subscript>02low</subscript></entry>
+                 <entry>Y'<subscript>02high</subscript></entry>
+                 <entry>Y'<subscript>03low</subscript></entry>
+                 <entry>Y'<subscript>03high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;8:</entry>
+                 <entry>Y'<subscript>10low</subscript></entry>
+                 <entry>Y'<subscript>10high</subscript></entry>
+                 <entry>Y'<subscript>11low</subscript></entry>
+                 <entry>Y'<subscript>11high</subscript></entry>
+                 <entry>Y'<subscript>12low</subscript></entry>
+                 <entry>Y'<subscript>12high</subscript></entry>
+                 <entry>Y'<subscript>13low</subscript></entry>
+                 <entry>Y'<subscript>13high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;16:</entry>
+                 <entry>Y'<subscript>20low</subscript></entry>
+                 <entry>Y'<subscript>20high</subscript></entry>
+                 <entry>Y'<subscript>21low</subscript></entry>
+                 <entry>Y'<subscript>21high</subscript></entry>
+                 <entry>Y'<subscript>22low</subscript></entry>
+                 <entry>Y'<subscript>22high</subscript></entry>
+                 <entry>Y'<subscript>23low</subscript></entry>
+                 <entry>Y'<subscript>23high</subscript></entry>
+               </row>
+               <row>
+                 <entry>start&nbsp;+&nbsp;24:</entry>
+                 <entry>Y'<subscript>30low</subscript></entry>
+                 <entry>Y'<subscript>30high</subscript></entry>
+                 <entry>Y'<subscript>31low</subscript></entry>
+                 <entry>Y'<subscript>31high</subscript></entry>
+                 <entry>Y'<subscript>32low</subscript></entry>
+                 <entry>Y'<subscript>32high</subscript></entry>
+                 <entry>Y'<subscript>33low</subscript></entry>
+                 <entry>Y'<subscript>33high</subscript></entry>
+               </row>
+             </tbody>
+           </tgroup>
+         </informaltable>
+       </para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-y41p.xml b/Documentation/DocBook/media/v4l/pixfmt-y41p.xml
new file mode 100644 (file)
index 0000000..73c8536
--- /dev/null
@@ -0,0 +1,157 @@
+    <refentry id="V4L2-PIX-FMT-Y41P">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_Y41P ('Y41P')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_Y41P</constant></refname>
+       <refpurpose>Format with &frac14; horizontal chroma
+resolution, also known as YUV 4:1:1</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>In this format each 12 bytes is eight pixels. In the
+twelve bytes are two CbCr pairs and eight Y's. The first CbCr pair
+goes with the first four Y's, and the second CbCr pair goes with the
+other four Y's. The Cb and Cr components have one fourth the
+horizontal resolution of the Y component.</para>
+
+       <para>Do not confuse this format with <link
+linkend="V4L2-PIX-FMT-YUV411P"><constant>V4L2_PIX_FMT_YUV411P</constant></link>.
+Y41P is derived from "YUV 4:1:1 <emphasis>packed</emphasis>", while
+YUV411P stands for "YUV 4:1:1 <emphasis>planar</emphasis>".</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_Y41P</constant> 8 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="13" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                     <entry>Y'<subscript>04</subscript></entry>
+                     <entry>Y'<subscript>05</subscript></entry>
+                     <entry>Y'<subscript>06</subscript></entry>
+                     <entry>Y'<subscript>07</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                     <entry>Y'<subscript>14</subscript></entry>
+                     <entry>Y'<subscript>15</subscript></entry>
+                     <entry>Y'<subscript>16</subscript></entry>
+                     <entry>Y'<subscript>17</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;24:</entry>
+                     <entry>Cb<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Cr<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Cb<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Cr<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                     <entry>Y'<subscript>24</subscript></entry>
+                     <entry>Y'<subscript>25</subscript></entry>
+                     <entry>Y'<subscript>26</subscript></entry>
+                     <entry>Y'<subscript>27</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;36:</entry>
+                     <entry>Cb<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Cr<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Cb<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Cr<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                     <entry>Y'<subscript>34</subscript></entry>
+                     <entry>Y'<subscript>35</subscript></entry>
+                     <entry>Y'<subscript>36</subscript></entry>
+                     <entry>Y'<subscript>37</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+             </informaltable></para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="15" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry><entry></entry>
+                     <entry>4</entry><entry></entry><entry>5</entry><entry></entry>
+                     <entry>6</entry><entry></entry><entry>7</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv410.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv410.xml
new file mode 100644 (file)
index 0000000..8eb4a19
--- /dev/null
@@ -0,0 +1,141 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-YVU410"><constant>V4L2_PIX_FMT_YVU410</constant></refname>
+       <refname id="V4L2-PIX-FMT-YUV410"><constant>V4L2_PIX_FMT_YUV410</constant></refname>
+       <refpurpose>Planar formats with &frac14; horizontal and
+vertical chroma resolution, also known as YUV 4:1:0</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>These are planar formats, as opposed to a packed format.
+The three components are separated into three sub-images or planes.
+The Y plane is first. The Y plane has one byte per pixel. For
+<constant>V4L2_PIX_FMT_YVU410</constant>, the Cr plane immediately
+follows the Y plane in memory. The Cr plane is &frac14; the width and
+&frac14; the height of the Y plane (and of the image). Each Cr belongs
+to 16 pixels, a four-by-four square of the image. Following the Cr
+plane is the Cb plane, just like the Cr plane.
+<constant>V4L2_PIX_FMT_YUV410</constant> is the same, except the Cb
+plane comes first, then the Cr plane.</para>
+
+       <para>If the Y plane has pad bytes after each row, then the Cr
+and Cb planes have &frac14; as many pad bytes after their rows. In
+other words, four Cx rows (including padding) are exactly as long as
+one Y row (including padding).</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_YVU410</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;17:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry></entry><entry></entry><entry>C</entry>
+                     <entry></entry><entry></entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv411p.xml
new file mode 100644 (file)
index 0000000..00e0960
--- /dev/null
@@ -0,0 +1,155 @@
+    <refentry id="V4L2-PIX-FMT-YUV411P">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_YUV411P ('411P')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_YUV411P</constant></refname>
+       <refpurpose>Format with &frac14; horizontal chroma resolution,
+also known as YUV 4:1:1. Planar layout as opposed to
+<constant>V4L2_PIX_FMT_Y41P</constant></refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This format is not commonly used. This is a planar
+format similar to the 4:2:2 planar format except with half as many
+chroma. The three components are separated into three sub-images or
+planes. The Y plane is first. The Y plane has one byte per pixel. The
+Cb plane immediately follows the Y plane in memory. The Cb plane is
+&frac14; the width of the Y plane (and of the image). Each Cb belongs
+to 4 pixels all on the same row. For example,
+Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
+Y'<subscript>01</subscript>, Y'<subscript>02</subscript> and
+Y'<subscript>03</subscript>. Following the Cb plane is the Cr plane,
+just like the Cb plane.</para>
+
+       <para>If the Y plane has pad bytes after each row, then the Cr
+and Cb planes have &frac14; as many pad bytes after their rows. In
+other words, four C x rows (including padding) is exactly as long as
+one Y row (including padding).</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_YUV411P</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;17:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;18:</entry>
+                     <entry>Cb<subscript>20</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;19:</entry>
+                     <entry>Cb<subscript>30</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;20:</entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;21:</entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;22:</entry>
+                     <entry>Cr<subscript>20</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;23:</entry>
+                     <entry>Cr<subscript>30</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv420.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv420.xml
new file mode 100644 (file)
index 0000000..42d7de5
--- /dev/null
@@ -0,0 +1,157 @@
+    <refentry>
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12')</refentrytitle>
+       &manvol;
+     </refmeta>
+      <refnamediv>
+       <refname id="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></refname>
+       <refname id="V4L2-PIX-FMT-YUV420"><constant>V4L2_PIX_FMT_YUV420</constant></refname>
+       <refpurpose>Planar formats with &frac12; horizontal and
+vertical chroma resolution, also known as YUV 4:2:0</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>These are planar formats, as opposed to a packed format.
+The three components are separated into three sub- images or planes.
+The Y plane is first. The Y plane has one byte per pixel. For
+<constant>V4L2_PIX_FMT_YVU420</constant>, the Cr plane immediately
+follows the Y plane in memory. The Cr plane is half the width and half
+the height of the Y plane (and of the image). Each Cr belongs to four
+pixels, a two-by-two square of the image. For example,
+Cr<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
+Y'<subscript>01</subscript>, Y'<subscript>10</subscript>, and
+Y'<subscript>11</subscript>. Following the Cr plane is the Cb plane,
+just like the Cr plane. <constant>V4L2_PIX_FMT_YUV420</constant> is
+the same except the Cb plane comes first, then the Cr plane.</para>
+
+       <para>If the Y plane has pad bytes after each row, then the Cr
+and Cb planes have half as many pad bytes after their rows. In other
+words, two Cx rows (including padding) is exactly as long as one Y row
+(including padding).</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_YVU420</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;18:</entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;20:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;22:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml
new file mode 100644 (file)
index 0000000..f5d8f57
--- /dev/null
@@ -0,0 +1,162 @@
+    <refentry id="V4L2-PIX-FMT-YUV420M">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_YUV420M ('YU12M')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname> <constant>V4L2_PIX_FMT_YUV420M</constant></refname>
+       <refpurpose>Variation of <constant>V4L2_PIX_FMT_YUV420</constant>
+         with planes non contiguous in memory. </refpurpose>
+      </refnamediv>
+
+      <refsect1>
+       <title>Description</title>
+
+       <para>This is a multi-planar format, as opposed to a packed format.
+The three components are separated into three sub- images or planes.
+
+The Y plane is first. The Y plane has one byte per pixel. The Cb data
+constitutes the second plane which is half the width and half
+the height of the Y plane (and of the image). Each Cb belongs to four
+pixels, a two-by-two square of the image. For example,
+Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
+Y'<subscript>01</subscript>, Y'<subscript>10</subscript>, and
+Y'<subscript>11</subscript>. The Cr data, just like the Cb plane, is
+in the third plane. </para>
+
+       <para>If the Y plane has pad bytes after each row, then the Cb
+and Cr planes have half as many pad bytes after their rows. In other
+words, two Cx rows (including padding) is exactly as long as one Y row
+(including padding).</para>
+
+       <para><constant>V4L2_PIX_FMT_NV12M</constant> is intended to be
+used only in drivers and applications that support the multi-planar API,
+described in <xref linkend="planar-apis"/>. </para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_YVU420M</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start0&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row><entry></entry></row>
+                   <row>
+                     <entry>start1&nbsp;+&nbsp;0:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start1&nbsp;+&nbsp;2:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                   </row>
+                   <row><entry></entry></row>
+                   <row>
+                     <entry>start2&nbsp;+&nbsp;0:</entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start2&nbsp;+&nbsp;2:</entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
+                     <entry></entry><entry>C</entry><entry></entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry></entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv422p.xml
new file mode 100644 (file)
index 0000000..4348bd9
--- /dev/null
@@ -0,0 +1,161 @@
+    <refentry id="V4L2-PIX-FMT-YUV422P">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_YUV422P ('422P')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_YUV422P</constant></refname>
+       <refpurpose>Format with &frac12; horizontal chroma resolution,
+also known as YUV 4:2:2. Planar layout as opposed to
+<constant>V4L2_PIX_FMT_YUYV</constant></refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>This format is not commonly used. This is a planar
+version of the YUYV format. The three components are separated into
+three sub-images or planes. The Y plane is first. The Y plane has one
+byte per pixel. The Cb plane immediately follows the Y plane in
+memory. The Cb plane is half the width of the Y plane (and of the
+image). Each Cb belongs to two pixels. For example,
+Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
+Y'<subscript>01</subscript>. Following the Cb plane is the Cr plane,
+just like the Cb plane.</para>
+
+       <para>If the Y plane has pad bytes after each row, then the Cr
+and Cb planes have half as many pad bytes after their rows. In other
+words, two Cx rows (including padding) is exactly as long as one Y row
+(including padding).</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_YUV422P</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="5" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;4:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;12:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;18:</entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;20:</entry>
+                     <entry>Cb<subscript>20</subscript></entry>
+                     <entry>Cb<subscript>21</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;22:</entry>
+                     <entry>Cb<subscript>30</subscript></entry>
+                     <entry>Cb<subscript>31</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;24:</entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;26:</entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;28:</entry>
+                     <entry>Cr<subscript>20</subscript></entry>
+                     <entry>Cr<subscript>21</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;30:</entry>
+                     <entry>Cr<subscript>30</subscript></entry>
+                     <entry>Cr<subscript>31</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuyv.xml b/Documentation/DocBook/media/v4l/pixfmt-yuyv.xml
new file mode 100644 (file)
index 0000000..bdb2ffa
--- /dev/null
@@ -0,0 +1,128 @@
+    <refentry id="V4L2-PIX-FMT-YUYV">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_YUYV ('YUYV')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_YUYV</constant></refname>
+       <refpurpose>Packed format with &frac12; horizontal chroma
+resolution, also known as YUV 4:2:2</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>In this format each four bytes is two pixels. Each four
+bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
+the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
+components have half the horizontal resolution of the Y component.
+<constant>V4L2_PIX_FMT_YUYV </constant> is known in the Windows
+environment as YUY2.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_YUYV</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="9" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Cb<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Cr<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Cb<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                     <entry>Cr<subscript>21</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;24:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Cb<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Cr<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Cb<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                     <entry>Cr<subscript>31</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt-yvyu.xml b/Documentation/DocBook/media/v4l/pixfmt-yvyu.xml
new file mode 100644 (file)
index 0000000..40d17ae
--- /dev/null
@@ -0,0 +1,128 @@
+    <refentry id="V4L2-PIX-FMT-YVYU">
+      <refmeta>
+       <refentrytitle>V4L2_PIX_FMT_YVYU ('YVYU')</refentrytitle>
+       &manvol;
+      </refmeta>
+      <refnamediv>
+       <refname><constant>V4L2_PIX_FMT_YVYU</constant></refname>
+       <refpurpose>Variation of
+<constant>V4L2_PIX_FMT_YUYV</constant> with different order of samples
+in memory</refpurpose>
+      </refnamediv>
+      <refsect1>
+       <title>Description</title>
+
+       <para>In this format each four bytes is two pixels. Each four
+bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
+the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
+components have half the horizontal resolution of the Y
+component.</para>
+
+       <example>
+         <title><constant>V4L2_PIX_FMT_YVYU</constant> 4 &times; 4
+pixel image</title>
+
+         <formalpara>
+           <title>Byte Order.</title>
+           <para>Each cell is one byte.
+               <informaltable frame="none">
+               <tgroup cols="9" align="center">
+                 <colspec align="left" colwidth="2*" />
+                 <tbody valign="top">
+                   <row>
+                     <entry>start&nbsp;+&nbsp;0:</entry>
+                     <entry>Y'<subscript>00</subscript></entry>
+                     <entry>Cr<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>01</subscript></entry>
+                     <entry>Cb<subscript>00</subscript></entry>
+                     <entry>Y'<subscript>02</subscript></entry>
+                     <entry>Cr<subscript>01</subscript></entry>
+                     <entry>Y'<subscript>03</subscript></entry>
+                     <entry>Cb<subscript>01</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;8:</entry>
+                     <entry>Y'<subscript>10</subscript></entry>
+                     <entry>Cr<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>11</subscript></entry>
+                     <entry>Cb<subscript>10</subscript></entry>
+                     <entry>Y'<subscript>12</subscript></entry>
+                     <entry>Cr<subscript>11</subscript></entry>
+                     <entry>Y'<subscript>13</subscript></entry>
+                     <entry>Cb<subscript>11</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;16:</entry>
+                     <entry>Y'<subscript>20</subscript></entry>
+                     <entry>Cr<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>21</subscript></entry>
+                     <entry>Cb<subscript>20</subscript></entry>
+                     <entry>Y'<subscript>22</subscript></entry>
+                     <entry>Cr<subscript>21</subscript></entry>
+                     <entry>Y'<subscript>23</subscript></entry>
+                     <entry>Cb<subscript>21</subscript></entry>
+                   </row>
+                   <row>
+                     <entry>start&nbsp;+&nbsp;24:</entry>
+                     <entry>Y'<subscript>30</subscript></entry>
+                     <entry>Cr<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>31</subscript></entry>
+                     <entry>Cb<subscript>30</subscript></entry>
+                     <entry>Y'<subscript>32</subscript></entry>
+                     <entry>Cr<subscript>31</subscript></entry>
+                     <entry>Y'<subscript>33</subscript></entry>
+                     <entry>Cb<subscript>31</subscript></entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+
+         <formalpara>
+           <title>Color Sample Location.</title>
+           <para>
+               <informaltable frame="none">
+               <tgroup cols="7" align="center">
+                 <tbody valign="top">
+                   <row>
+                     <entry></entry>
+                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+                     <entry>2</entry><entry></entry><entry>3</entry>
+                   </row>
+                   <row>
+                     <entry>0</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>1</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>2</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                   <row>
+                     <entry>3</entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
+                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
+                   </row>
+                 </tbody>
+               </tgroup>
+               </informaltable>
+             </para>
+         </formalpara>
+       </example>
+      </refsect1>
+    </refentry>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
new file mode 100644 (file)
index 0000000..2ff6b77
--- /dev/null
@@ -0,0 +1,1007 @@
+  <title>Image Formats</title>
+
+  <para>The V4L2 API was primarily designed for devices exchanging
+image data with applications. The
+<structname>v4l2_pix_format</structname> and <structname>v4l2_pix_format_mplane
+</structname> structures define the format and layout of an image in memory.
+The former is used with the single-planar API, while the latter is used with the
+multi-planar version (see <xref linkend="planar-apis"/>). Image formats are
+negotiated with the &VIDIOC-S-FMT; ioctl. (The explanations here focus on video
+capturing and output, for overlay frame buffer formats see also
+&VIDIOC-G-FBUF;.)</para>
+
+<section>
+  <title>Single-planar format structure</title>
+  <table pgwide="1" frame="none" id="v4l2-pix-format">
+    <title>struct <structname>v4l2_pix_format</structname></title>
+    <tgroup cols="3">
+      &cs-str;
+      <tbody valign="top">
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>width</structfield></entry>
+         <entry>Image width in pixels.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>height</structfield></entry>
+         <entry>Image height in pixels.</entry>
+       </row>
+       <row>
+         <entry spanname="hspan">Applications set these fields to
+request an image size, drivers return the closest possible values. In
+case of planar formats the <structfield>width</structfield> and
+<structfield>height</structfield> applies to the largest plane. To
+avoid ambiguities drivers must return values rounded up to a multiple
+of the scale factor of any smaller planes. For example when the image
+format is YUV 4:2:0, <structfield>width</structfield> and
+<structfield>height</structfield> must be multiples of two.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>pixelformat</structfield></entry>
+         <entry>The pixel format or type of compression, set by the
+application. This is a little endian <link
+linkend="v4l2-fourcc">four character code</link>. V4L2 defines
+standard RGB formats in <xref linkend="rgb-formats" />, YUV formats in <xref
+linkend="yuv-formats" />, and reserved codes in <xref
+linkend="reserved-formats" /></entry>
+       </row>
+       <row>
+         <entry>&v4l2-field;</entry>
+         <entry><structfield>field</structfield></entry>
+         <entry>Video images are typically interlaced. Applications
+can request to capture or output only the top or bottom field, or both
+fields interlaced or sequentially stored in one buffer or alternating
+in separate buffers. Drivers return the actual field order selected.
+For details see <xref linkend="field-order" />.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>bytesperline</structfield></entry>
+         <entry>Distance in bytes between the leftmost pixels in two
+adjacent lines.</entry>
+       </row>
+       <row>
+         <entry spanname="hspan"><para>Both applications and drivers
+can set this field to request padding bytes at the end of each line.
+Drivers however may ignore the value requested by the application,
+returning <structfield>width</structfield> times bytes per pixel or a
+larger value required by the hardware. That implies applications can
+just set this field to zero to get a reasonable
+default.</para><para>Video hardware may access padding bytes,
+therefore they must reside in accessible memory. Consider cases where
+padding bytes after the last line of an image cross a system page
+boundary. Input devices may write padding bytes, the value is
+undefined. Output devices ignore the contents of padding
+bytes.</para><para>When the image format is planar the
+<structfield>bytesperline</structfield> value applies to the largest
+plane and is divided by the same factor as the
+<structfield>width</structfield> field for any smaller planes. For
+example the Cb and Cr planes of a YUV 4:2:0 image have half as many
+padding bytes following each line as the Y plane. To avoid ambiguities
+drivers must return a <structfield>bytesperline</structfield> value
+rounded up to a multiple of the scale factor.</para></entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>sizeimage</structfield></entry>
+         <entry>Size in bytes of the buffer to hold a complete image,
+set by the driver. Usually this is
+<structfield>bytesperline</structfield> times
+<structfield>height</structfield>. When the image consists of variable
+length compressed data this is the maximum number of bytes required to
+hold an image.</entry>
+       </row>
+       <row>
+         <entry>&v4l2-colorspace;</entry>
+         <entry><structfield>colorspace</structfield></entry>
+         <entry>This information supplements the
+<structfield>pixelformat</structfield> and must be set by the driver,
+see <xref linkend="colorspaces" />.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>priv</structfield></entry>
+         <entry>Reserved for custom (driver defined) additional
+information about formats. When not used drivers and applications must
+set this field to zero.</entry>
+       </row>
+      </tbody>
+    </tgroup>
+  </table>
+</section>
+
+<section>
+  <title>Multi-planar format structures</title>
+  <para>The <structname>v4l2_plane_pix_format</structname> structures define
+    size and layout for each of the planes in a multi-planar format.
+    The <structname>v4l2_pix_format_mplane</structname> structure contains
+    information common to all planes (such as image width and height) and
+    an array of <structname>v4l2_plane_pix_format</structname> structures,
+    describing all planes of that format.</para>
+  <table pgwide="1" frame="none" id="v4l2-plane-pix-format">
+    <title>struct <structname>v4l2_plane_pix_format</structname></title>
+    <tgroup cols="3">
+      &cs-str;
+      <tbody valign="top">
+        <row>
+          <entry>__u32</entry>
+          <entry><structfield>sizeimage</structfield></entry>
+          <entry>Maximum size in bytes required for image data in this plane.
+          </entry>
+        </row>
+        <row>
+          <entry>__u16</entry>
+          <entry><structfield>bytesperline</structfield></entry>
+          <entry>Distance in bytes between the leftmost pixels in two adjacent
+            lines.</entry>
+        </row>
+        <row>
+          <entry>__u16</entry>
+          <entry><structfield>reserved[7]</structfield></entry>
+          <entry>Reserved for future extensions. Should be zeroed by the
+           application.</entry>
+        </row>
+      </tbody>
+    </tgroup>
+  </table>
+  <table pgwide="1" frame="none" id="v4l2-pix-format-mplane">
+    <title>struct <structname>v4l2_pix_format_mplane</structname></title>
+    <tgroup cols="3">
+      &cs-str;
+      <tbody valign="top">
+        <row>
+          <entry>__u32</entry>
+          <entry><structfield>width</structfield></entry>
+          <entry>Image width in pixels.</entry>
+        </row>
+        <row>
+          <entry>__u32</entry>
+          <entry><structfield>height</structfield></entry>
+          <entry>Image height in pixels.</entry>
+        </row>
+        <row>
+          <entry>__u32</entry>
+          <entry><structfield>pixelformat</structfield></entry>
+          <entry>The pixel format. Both single- and multi-planar four character
+codes can be used.</entry>
+        </row>
+        <row>
+          <entry>&v4l2-field;</entry>
+          <entry><structfield>field</structfield></entry>
+          <entry>See &v4l2-pix-format;.</entry>
+        </row>
+        <row>
+          <entry>&v4l2-colorspace;</entry>
+          <entry><structfield>colorspace</structfield></entry>
+          <entry>See &v4l2-pix-format;.</entry>
+        </row>
+        <row>
+          <entry>&v4l2-plane-pix-format;</entry>
+          <entry><structfield>plane_fmt[VIDEO_MAX_PLANES]</structfield></entry>
+          <entry>An array of structures describing format of each plane this
+          pixel format consists of. The number of valid entries in this array
+          has to be put in the <structfield>num_planes</structfield>
+          field.</entry>
+        </row>
+        <row>
+          <entry>__u8</entry>
+          <entry><structfield>num_planes</structfield></entry>
+          <entry>Number of planes (i.e. separate memory buffers) for this format
+          and the number of valid entries in the
+          <structfield>plane_fmt</structfield> array.</entry>
+        </row>
+        <row>
+          <entry>__u8</entry>
+          <entry><structfield>reserved[11]</structfield></entry>
+          <entry>Reserved for future extensions. Should be zeroed by the
+           application.</entry>
+        </row>
+      </tbody>
+    </tgroup>
+  </table>
+</section>
+
+  <section>
+    <title>Standard Image Formats</title>
+
+    <para>In order to exchange images between drivers and
+applications, it is necessary to have standard image data formats
+which both sides will interpret the same way. V4L2 includes several
+such formats, and this section is intended to be an unambiguous
+specification of the standard image data formats in V4L2.</para>
+
+    <para>V4L2 drivers are not limited to these formats, however.
+Driver-specific formats are possible. In that case the application may
+depend on a codec to convert images to one of the standard formats
+when needed. But the data can still be stored and retrieved in the
+proprietary format. For example, a device may support a proprietary
+compressed format. Applications can still capture and save the data in
+the compressed format, saving much disk space, and later use a codec
+to convert the images to the X Windows screen format when the video is
+to be displayed.</para>
+
+    <para>Even so, ultimately, some standard formats are needed, so
+the V4L2 specification would not be complete without well-defined
+standard formats.</para>
+
+    <para>The V4L2 standard formats are mainly uncompressed formats. The
+pixels are always arranged in memory from left to right, and from top
+to bottom. The first byte of data in the image buffer is always for
+the leftmost pixel of the topmost row. Following that is the pixel
+immediately to its right, and so on until the end of the top row of
+pixels. Following the rightmost pixel of the row there may be zero or
+more bytes of padding to guarantee that each row of pixel data has a
+certain alignment. Following the pad bytes, if any, is data for the
+leftmost pixel of the second row from the top, and so on. The last row
+has just as many pad bytes after it as the other rows.</para>
+
+    <para>In V4L2 each format has an identifier which looks like
+<constant>PIX_FMT_XXX</constant>, defined in the <link
+linkend="videodev">videodev.h</link> header file. These identifiers
+represent <link linkend="v4l2-fourcc">four character (FourCC) codes</link>
+which are also listed below, however they are not the same as those
+used in the Windows world.</para>
+
+    <para>For some formats, data is stored in separate, discontiguous
+memory buffers. Those formats are identified by a separate set of FourCC codes
+and are referred to as "multi-planar formats". For example, a YUV422 frame is
+normally stored in one memory buffer, but it can also be placed in two or three
+separate buffers, with Y component in one buffer and CbCr components in another
+in the 2-planar version or with each component in its own buffer in the
+3-planar case. Those sub-buffers are referred to as "planes".</para>
+  </section>
+
+  <section id="colorspaces">
+    <title>Colorspaces</title>
+
+    <para>[intro]</para>
+
+    <!-- See proposal by Billy Biggs, video4linux-list@redhat.com
+on 11 Oct 2002, subject: "Re: [V4L] Re: v4l2 api", and
+http://vektor.theorem.ca/graphics/ycbcr/ and
+http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html -->
+
+    <para>
+      <variablelist>
+       <varlistentry>
+         <term>Gamma Correction</term>
+         <listitem>
+           <para>[to do]</para>
+           <para>E'<subscript>R</subscript> = f(R)</para>
+           <para>E'<subscript>G</subscript> = f(G)</para>
+           <para>E'<subscript>B</subscript> = f(B)</para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>Construction of luminance and color-difference
+signals</term>
+         <listitem>
+           <para>[to do]</para>
+           <para>E'<subscript>Y</subscript> =
+Coeff<subscript>R</subscript> E'<subscript>R</subscript>
++ Coeff<subscript>G</subscript> E'<subscript>G</subscript>
++ Coeff<subscript>B</subscript> E'<subscript>B</subscript></para>
+           <para>(E'<subscript>R</subscript> - E'<subscript>Y</subscript>) = E'<subscript>R</subscript>
+- Coeff<subscript>R</subscript> E'<subscript>R</subscript>
+- Coeff<subscript>G</subscript> E'<subscript>G</subscript>
+- Coeff<subscript>B</subscript> E'<subscript>B</subscript></para>
+           <para>(E'<subscript>B</subscript> - E'<subscript>Y</subscript>) = E'<subscript>B</subscript>
+- Coeff<subscript>R</subscript> E'<subscript>R</subscript>
+- Coeff<subscript>G</subscript> E'<subscript>G</subscript>
+- Coeff<subscript>B</subscript> E'<subscript>B</subscript></para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>Re-normalized color-difference signals</term>
+         <listitem>
+           <para>The color-difference signals are scaled back to unity
+range [-0.5;+0.5]:</para>
+           <para>K<subscript>B</subscript> = 0.5 / (1 - Coeff<subscript>B</subscript>)</para>
+           <para>K<subscript>R</subscript> = 0.5 / (1 - Coeff<subscript>R</subscript>)</para>
+           <para>P<subscript>B</subscript> =
+K<subscript>B</subscript> (E'<subscript>B</subscript> - E'<subscript>Y</subscript>) =
+  0.5 (Coeff<subscript>R</subscript> / Coeff<subscript>B</subscript>) E'<subscript>R</subscript>
++ 0.5 (Coeff<subscript>G</subscript> / Coeff<subscript>B</subscript>) E'<subscript>G</subscript>
++ 0.5 E'<subscript>B</subscript></para>
+           <para>P<subscript>R</subscript> =
+K<subscript>R</subscript> (E'<subscript>R</subscript> - E'<subscript>Y</subscript>) =
+  0.5 E'<subscript>R</subscript>
++ 0.5 (Coeff<subscript>G</subscript> / Coeff<subscript>R</subscript>) E'<subscript>G</subscript>
++ 0.5 (Coeff<subscript>B</subscript> / Coeff<subscript>R</subscript>) E'<subscript>B</subscript></para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term>Quantization</term>
+         <listitem>
+           <para>[to do]</para>
+           <para>Y' = (Lum. Levels - 1) &middot; E'<subscript>Y</subscript> + Lum. Offset</para>
+           <para>C<subscript>B</subscript> = (Chrom. Levels - 1)
+&middot; P<subscript>B</subscript> + Chrom. Offset</para>
+           <para>C<subscript>R</subscript> = (Chrom. Levels - 1)
+&middot; P<subscript>R</subscript> + Chrom. Offset</para>
+           <para>Rounding to the nearest integer and clamping to the range
+[0;255] finally yields the digital color components Y'CbCr
+stored in YUV images.</para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+    </para>
+
+    <example>
+      <title>ITU-R Rec. BT.601 color conversion</title>
+
+      <para>Forward Transformation</para>
+
+      <programlisting>
+int ER, EG, EB;         /* gamma corrected RGB input [0;255] */
+int Y1, Cb, Cr;         /* output [0;255] */
+
+double r, g, b;         /* temporaries */
+double y1, pb, pr;
+
+int
+clamp (double x)
+{
+       int r = x;      /* round to nearest */
+
+       if (r &lt; 0)         return 0;
+       else if (r &gt; 255)  return 255;
+       else               return r;
+}
+
+r = ER / 255.0;
+g = EG / 255.0;
+b = EB / 255.0;
+
+y1  =  0.299  * r + 0.587 * g + 0.114  * b;
+pb  = -0.169  * r - 0.331 * g + 0.5    * b;
+pr  =  0.5    * r - 0.419 * g - 0.081  * b;
+
+Y1 = clamp (219 * y1 + 16);
+Cb = clamp (224 * pb + 128);
+Cr = clamp (224 * pr + 128);
+
+/* or shorter */
+
+y1 = 0.299 * ER + 0.587 * EG + 0.114 * EB;
+
+Y1 = clamp ( (219 / 255.0)                    *       y1  + 16);
+Cb = clamp (((224 / 255.0) / (2 - 2 * 0.114)) * (EB - y1) + 128);
+Cr = clamp (((224 / 255.0) / (2 - 2 * 0.299)) * (ER - y1) + 128);
+      </programlisting>
+
+      <para>Inverse Transformation</para>
+
+      <programlisting>
+int Y1, Cb, Cr;         /* gamma pre-corrected input [0;255] */
+int ER, EG, EB;         /* output [0;255] */
+
+double r, g, b;         /* temporaries */
+double y1, pb, pr;
+
+int
+clamp (double x)
+{
+       int r = x;      /* round to nearest */
+
+       if (r &lt; 0)         return 0;
+       else if (r &gt; 255)  return 255;
+       else               return r;
+}
+
+y1 = (255 / 219.0) * (Y1 - 16);
+pb = (255 / 224.0) * (Cb - 128);
+pr = (255 / 224.0) * (Cr - 128);
+
+r = 1.0 * y1 + 0     * pb + 1.402 * pr;
+g = 1.0 * y1 - 0.344 * pb - 0.714 * pr;
+b = 1.0 * y1 + 1.772 * pb + 0     * pr;
+
+ER = clamp (r * 255); /* [ok? one should prob. limit y1,pb,pr] */
+EG = clamp (g * 255);
+EB = clamp (b * 255);
+      </programlisting>
+    </example>
+
+    <table pgwide="1" id="v4l2-colorspace" orient="land">
+      <title>enum v4l2_colorspace</title>
+      <tgroup cols="11" align="center">
+       <colspec align="left" />
+       <colspec align="center" />
+       <colspec align="left" />
+       <colspec colname="cr" />
+       <colspec colname="cg" />
+       <colspec colname="cb" />
+       <colspec colname="wp" />
+       <colspec colname="gc" />
+       <colspec colname="lum" />
+       <colspec colname="qy" />
+       <colspec colname="qc" />
+       <spanspec namest="cr" nameend="cb" spanname="chrom" />
+       <spanspec namest="qy" nameend="qc" spanname="quant" />
+       <spanspec namest="lum" nameend="qc" spanname="spam" />
+       <thead>
+         <row>
+           <entry morerows="1">Identifier</entry>
+           <entry morerows="1">Value</entry>
+           <entry morerows="1">Description</entry>
+           <entry spanname="chrom">Chromaticities<footnote>
+               <para>The coordinates of the color primaries are
+given in the CIE system (1931)</para>
+             </footnote></entry>
+           <entry morerows="1">White Point</entry>
+           <entry morerows="1">Gamma Correction</entry>
+           <entry morerows="1">Luminance E'<subscript>Y</subscript></entry>
+           <entry spanname="quant">Quantization</entry>
+         </row>
+         <row>
+           <entry>Red</entry>
+           <entry>Green</entry>
+           <entry>Blue</entry>
+           <entry>Y'</entry>
+           <entry>Cb, Cr</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_COLORSPACE_SMPTE170M</constant></entry>
+           <entry>1</entry>
+           <entry>NTSC/PAL according to <xref linkend="smpte170m" />,
+<xref linkend="itu601" /></entry>
+           <entry>x&nbsp;=&nbsp;0.630, y&nbsp;=&nbsp;0.340</entry>
+           <entry>x&nbsp;=&nbsp;0.310, y&nbsp;=&nbsp;0.595</entry>
+           <entry>x&nbsp;=&nbsp;0.155, y&nbsp;=&nbsp;0.070</entry>
+           <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
+           Illuminant D<subscript>65</subscript></entry>
+           <entry>E' = 4.5&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.018,
+1.099&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&lt;&nbsp;I</entry>
+           <entry>0.299&nbsp;E'<subscript>R</subscript>
++&nbsp;0.587&nbsp;E'<subscript>G</subscript>
++&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
+           <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
+           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_COLORSPACE_SMPTE240M</constant></entry>
+           <entry>2</entry>
+           <entry>1125-Line (US) HDTV, see <xref
+linkend="smpte240m" /></entry>
+           <entry>x&nbsp;=&nbsp;0.630, y&nbsp;=&nbsp;0.340</entry>
+           <entry>x&nbsp;=&nbsp;0.310, y&nbsp;=&nbsp;0.595</entry>
+           <entry>x&nbsp;=&nbsp;0.155, y&nbsp;=&nbsp;0.070</entry>
+           <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
+           Illuminant D<subscript>65</subscript></entry>
+           <entry>E' = 4&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.0228,
+1.1115&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.1115&nbsp;for&nbsp;0.0228&nbsp;&lt;&nbsp;I</entry>
+           <entry>0.212&nbsp;E'<subscript>R</subscript>
++&nbsp;0.701&nbsp;E'<subscript>G</subscript>
++&nbsp;0.087&nbsp;E'<subscript>B</subscript></entry>
+           <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
+           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_COLORSPACE_REC709</constant></entry>
+           <entry>3</entry>
+           <entry>HDTV and modern devices, see <xref
+linkend="itu709" /></entry>
+           <entry>x&nbsp;=&nbsp;0.640, y&nbsp;=&nbsp;0.330</entry>
+           <entry>x&nbsp;=&nbsp;0.300, y&nbsp;=&nbsp;0.600</entry>
+           <entry>x&nbsp;=&nbsp;0.150, y&nbsp;=&nbsp;0.060</entry>
+           <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
+           Illuminant D<subscript>65</subscript></entry>
+           <entry>E' = 4.5&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.018,
+1.099&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&lt;&nbsp;I</entry>
+           <entry>0.2125&nbsp;E'<subscript>R</subscript>
++&nbsp;0.7154&nbsp;E'<subscript>G</subscript>
++&nbsp;0.0721&nbsp;E'<subscript>B</subscript></entry>
+           <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
+           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_COLORSPACE_BT878</constant></entry>
+           <entry>4</entry>
+           <entry>Broken Bt878 extents<footnote>
+               <para>The ubiquitous Bt878 video capture chip
+quantizes E'<subscript>Y</subscript> to 238 levels, yielding a range
+of Y' = 16 &hellip; 253, unlike Rec. 601 Y' = 16 &hellip;
+235. This is not a typo in the Bt878 documentation, it has been
+implemented in silicon. The chroma extents are unclear.</para>
+             </footnote>, <xref linkend="itu601" /></entry>
+           <entry>?</entry>
+           <entry>?</entry>
+           <entry>?</entry>
+           <entry>?</entry>
+           <entry>?</entry>
+           <entry>0.299&nbsp;E'<subscript>R</subscript>
++&nbsp;0.587&nbsp;E'<subscript>G</subscript>
++&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
+           <entry><emphasis>237</emphasis>&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
+           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128 (probably)</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_COLORSPACE_470_SYSTEM_M</constant></entry>
+           <entry>5</entry>
+           <entry>M/NTSC<footnote>
+               <para>No identifier exists for M/PAL which uses
+the chromaticities of M/NTSC, the remaining parameters are equal to B and
+G/PAL.</para>
+             </footnote> according to <xref linkend="itu470" />, <xref
+               linkend="itu601" /></entry>
+           <entry>x&nbsp;=&nbsp;0.67, y&nbsp;=&nbsp;0.33</entry>
+           <entry>x&nbsp;=&nbsp;0.21, y&nbsp;=&nbsp;0.71</entry>
+           <entry>x&nbsp;=&nbsp;0.14, y&nbsp;=&nbsp;0.08</entry>
+           <entry>x&nbsp;=&nbsp;0.310, y&nbsp;=&nbsp;0.316, Illuminant C</entry>
+           <entry>?</entry>
+           <entry>0.299&nbsp;E'<subscript>R</subscript>
++&nbsp;0.587&nbsp;E'<subscript>G</subscript>
++&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
+           <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
+           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant></entry>
+           <entry>6</entry>
+           <entry>625-line PAL and SECAM systems according to <xref
+linkend="itu470" />, <xref linkend="itu601" /></entry>
+           <entry>x&nbsp;=&nbsp;0.64, y&nbsp;=&nbsp;0.33</entry>
+           <entry>x&nbsp;=&nbsp;0.29, y&nbsp;=&nbsp;0.60</entry>
+           <entry>x&nbsp;=&nbsp;0.15, y&nbsp;=&nbsp;0.06</entry>
+           <entry>x&nbsp;=&nbsp;0.313, y&nbsp;=&nbsp;0.329,
+Illuminant D<subscript>65</subscript></entry>
+           <entry>?</entry>
+           <entry>0.299&nbsp;E'<subscript>R</subscript>
++&nbsp;0.587&nbsp;E'<subscript>G</subscript>
++&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
+           <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
+           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_COLORSPACE_JPEG</constant></entry>
+           <entry>7</entry>
+           <entry>JPEG Y'CbCr, see <xref linkend="jfif" />, <xref linkend="itu601" /></entry>
+           <entry>?</entry>
+           <entry>?</entry>
+           <entry>?</entry>
+           <entry>?</entry>
+           <entry>?</entry>
+           <entry>0.299&nbsp;E'<subscript>R</subscript>
++&nbsp;0.587&nbsp;E'<subscript>G</subscript>
++&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
+           <entry>256&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16<footnote>
+               <para>Note JFIF quantizes
+Y'P<subscript>B</subscript>P<subscript>R</subscript> in range [0;+1] and
+[-0.5;+0.5] to <emphasis>257</emphasis> levels, however Y'CbCr signals
+are still clamped to [0;255].</para>
+             </footnote></entry>
+           <entry>256&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_COLORSPACE_SRGB</constant></entry>
+           <entry>8</entry>
+           <entry>[?]</entry>
+           <entry>x&nbsp;=&nbsp;0.640, y&nbsp;=&nbsp;0.330</entry>
+           <entry>x&nbsp;=&nbsp;0.300, y&nbsp;=&nbsp;0.600</entry>
+           <entry>x&nbsp;=&nbsp;0.150, y&nbsp;=&nbsp;0.060</entry>
+           <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
+           Illuminant D<subscript>65</subscript></entry>
+           <entry>E' = 4.5&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.018,
+1.099&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&lt;&nbsp;I</entry>
+           <entry spanname="spam">n/a</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </section>
+
+  <section id="pixfmt-indexed">
+    <title>Indexed Format</title>
+
+    <para>In this format each pixel is represented by an 8 bit index
+into a 256 entry ARGB palette. It is intended for <link
+linkend="osd">Video Output Overlays</link> only. There are no ioctls to
+access the palette, this must be done with ioctls of the Linux framebuffer API.</para>
+
+    <table pgwide="0" frame="none">
+      <title>Indexed Image Format</title>
+      <tgroup cols="37" align="center">
+       <colspec colname="id" align="left" />
+       <colspec colname="fourcc" />
+       <colspec colname="bit" />
+
+       <colspec colnum="4" colname="b07" align="center" />
+       <colspec colnum="5" colname="b06" align="center" />
+       <colspec colnum="6" colname="b05" align="center" />
+       <colspec colnum="7" colname="b04" align="center" />
+       <colspec colnum="8" colname="b03" align="center" />
+       <colspec colnum="9" colname="b02" align="center" />
+       <colspec colnum="10" colname="b01" align="center" />
+       <colspec colnum="11" colname="b00" align="center" />
+
+       <spanspec namest="b07" nameend="b00" spanname="b0" />
+       <spanspec namest="b17" nameend="b10" spanname="b1" />
+       <spanspec namest="b27" nameend="b20" spanname="b2" />
+       <spanspec namest="b37" nameend="b30" spanname="b3" />
+       <thead>
+         <row>
+           <entry>Identifier</entry>
+           <entry>Code</entry>
+           <entry>&nbsp;</entry>
+           <entry spanname="b0">Byte&nbsp;0</entry>
+         </row>
+         <row>
+           <entry>&nbsp;</entry>
+           <entry>&nbsp;</entry>
+           <entry>Bit</entry>
+           <entry>7</entry>
+           <entry>6</entry>
+           <entry>5</entry>
+           <entry>4</entry>
+           <entry>3</entry>
+           <entry>2</entry>
+           <entry>1</entry>
+           <entry>0</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row id="V4L2-PIX-FMT-PAL8">
+           <entry><constant>V4L2_PIX_FMT_PAL8</constant></entry>
+           <entry>'PAL8'</entry>
+           <entry></entry>
+           <entry>i<subscript>7</subscript></entry>
+           <entry>i<subscript>6</subscript></entry>
+           <entry>i<subscript>5</subscript></entry>
+           <entry>i<subscript>4</subscript></entry>
+           <entry>i<subscript>3</subscript></entry>
+           <entry>i<subscript>2</subscript></entry>
+           <entry>i<subscript>1</subscript></entry>
+           <entry>i<subscript>0</subscript></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </section>
+
+  <section id="pixfmt-rgb">
+    <title>RGB Formats</title>
+
+    &sub-packed-rgb;
+    &sub-sbggr8;
+    &sub-sgbrg8;
+    &sub-sgrbg8;
+    &sub-srggb8;
+    &sub-sbggr16;
+    &sub-srggb10;
+    &sub-srggb12;
+  </section>
+
+  <section id="yuv-formats">
+    <title>YUV Formats</title>
+
+    <para>YUV is the format native to TV broadcast and composite video
+signals. It separates the brightness information (Y) from the color
+information (U and V or Cb and Cr). The color information consists of
+red and blue <emphasis>color difference</emphasis> signals, this way
+the green component can be reconstructed by subtracting from the
+brightness component. See <xref linkend="colorspaces" /> for conversion
+examples. YUV was chosen because early television would only transmit
+brightness information. To add color in a way compatible with existing
+receivers a new signal carrier was added to transmit the color
+difference signals. Secondary in the YUV format the U and V components
+usually have lower resolution than the Y component. This is an analog
+video compression technique taking advantage of a property of the
+human visual system, being more sensitive to brightness
+information.</para>
+
+    &sub-packed-yuv;
+    &sub-grey;
+    &sub-y10;
+    &sub-y12;
+    &sub-y10b;
+    &sub-y16;
+    &sub-yuyv;
+    &sub-uyvy;
+    &sub-yvyu;
+    &sub-vyuy;
+    &sub-y41p;
+    &sub-yuv420;
+    &sub-yuv420m;
+    &sub-yuv410;
+    &sub-yuv422p;
+    &sub-yuv411p;
+    &sub-nv12;
+    &sub-nv12m;
+    &sub-nv12mt;
+    &sub-nv16;
+    &sub-m420;
+  </section>
+
+  <section>
+    <title>Compressed Formats</title>
+
+    <table pgwide="1" frame="none" id="compressed-formats">
+      <title>Compressed Image Formats</title>
+      <tgroup cols="3" align="left">
+       &cs-def;
+       <thead>
+         <row>
+           <entry>Identifier</entry>
+           <entry>Code</entry>
+           <entry>Details</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+        <row id="V4L2-PIX-FMT-JPEG">
+           <entry><constant>V4L2_PIX_FMT_JPEG</constant></entry>
+           <entry>'JPEG'</entry>
+           <entry>TBD. See also &VIDIOC-G-JPEGCOMP;,
+           &VIDIOC-S-JPEGCOMP;.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-MPEG">
+           <entry><constant>V4L2_PIX_FMT_MPEG</constant></entry>
+           <entry>'MPEG'</entry>
+           <entry>MPEG multiplexed stream. The actual format is determined by
+extended control <constant>V4L2_CID_MPEG_STREAM_TYPE</constant>, see
+<xref linkend="mpeg-control-id" />.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-H264">
+               <entry><constant>V4L2_PIX_FMT_H264</constant></entry>
+               <entry>'H264'</entry>
+               <entry>H264 video elementary stream with start codes.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-H264-NO-SC">
+               <entry><constant>V4L2_PIX_FMT_H264_NO_SC</constant></entry>
+               <entry>'AVC1'</entry>
+               <entry>H264 video elementary stream without start codes.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-H263">
+               <entry><constant>V4L2_PIX_FMT_H263</constant></entry>
+               <entry>'H263'</entry>
+               <entry>H263 video elementary stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-MPEG1">
+               <entry><constant>V4L2_PIX_FMT_MPEG1</constant></entry>
+               <entry>'MPG1'</entry>
+               <entry>MPEG1 video elementary stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-MPEG2">
+               <entry><constant>V4L2_PIX_FMT_MPEG2</constant></entry>
+               <entry>'MPG2'</entry>
+               <entry>MPEG2 video elementary stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-MPEG4">
+               <entry><constant>V4L2_PIX_FMT_MPEG4</constant></entry>
+               <entry>'MPG4'</entry>
+               <entry>MPEG4 video elementary stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-XVID">
+               <entry><constant>V4L2_PIX_FMT_XVID</constant></entry>
+               <entry>'XVID'</entry>
+               <entry>Xvid video elementary stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-VC1-ANNEX-G">
+               <entry><constant>V4L2_PIX_FMT_VC1_ANNEX_G</constant></entry>
+               <entry>'VC1G'</entry>
+               <entry>VC1, SMPTE 421M Annex G compliant stream.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-VC1-ANNEX-L">
+               <entry><constant>V4L2_PIX_FMT_VC1_ANNEX_L</constant></entry>
+               <entry>'VC1L'</entry>
+               <entry>VC1, SMPTE 421M Annex L compliant stream.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </section>
+
+  <section id="pixfmt-reserved">
+    <title>Reserved Format Identifiers</title>
+
+    <para>These formats are not defined by this specification, they
+are just listed for reference and to avoid naming conflicts. If you
+want to register your own format, send an e-mail to the linux-media mailing
+list &v4l-ml; for inclusion in the <filename>videodev2.h</filename>
+file. If you want to share your format with other developers add a
+link to your documentation and send a copy to the linux-media mailing list
+for inclusion in this section. If you think your format should be listed
+in a standard format section please make a proposal on the linux-media mailing
+list.</para>
+
+    <table pgwide="1" frame="none" id="reserved-formats">
+      <title>Reserved Image Formats</title>
+      <tgroup cols="3" align="left">
+       &cs-def;
+       <thead>
+         <row>
+           <entry>Identifier</entry>
+           <entry>Code</entry>
+           <entry>Details</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row id="V4L2-PIX-FMT-DV">
+           <entry><constant>V4L2_PIX_FMT_DV</constant></entry>
+           <entry>'dvsd'</entry>
+           <entry>unknown</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-ET61X251">
+           <entry><constant>V4L2_PIX_FMT_ET61X251</constant></entry>
+           <entry>'E625'</entry>
+           <entry>Compressed format of the ET61X251 driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-HI240">
+           <entry><constant>V4L2_PIX_FMT_HI240</constant></entry>
+           <entry>'HI24'</entry>
+           <entry><para>8 bit RGB format used by the BTTV driver.</para></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-HM12">
+           <entry><constant>V4L2_PIX_FMT_HM12</constant></entry>
+           <entry>'HM12'</entry>
+           <entry><para>YUV 4:2:0 format used by the
+IVTV driver, <ulink url="http://www.ivtvdriver.org/">
+http://www.ivtvdriver.org/</ulink></para><para>The format is documented in the
+kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm12</filename>
+</para></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-CPIA1">
+           <entry><constant>V4L2_PIX_FMT_CPIA1</constant></entry>
+           <entry>'CPIA'</entry>
+           <entry>YUV format used by the gspca cpia1 driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-JPGL">
+           <entry><constant>V4L2_PIX_FMT_JPGL</constant></entry>
+           <entry>'JPGL'</entry>
+           <entry>JPEG-Light format (Pegasus Lossless JPEG)
+                       used in Divio webcams NW 80x.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-SPCA501">
+           <entry><constant>V4L2_PIX_FMT_SPCA501</constant></entry>
+           <entry>'S501'</entry>
+           <entry>YUYV per line used by the gspca driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-SPCA505">
+           <entry><constant>V4L2_PIX_FMT_SPCA505</constant></entry>
+           <entry>'S505'</entry>
+           <entry>YYUV per line used by the gspca driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-SPCA508">
+           <entry><constant>V4L2_PIX_FMT_SPCA508</constant></entry>
+           <entry>'S508'</entry>
+           <entry>YUVY per line used by the gspca driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-SPCA561">
+           <entry><constant>V4L2_PIX_FMT_SPCA561</constant></entry>
+           <entry>'S561'</entry>
+           <entry>Compressed GBRG Bayer format used by the gspca driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-SGRBG10DPCM8">
+           <entry><constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant></entry>
+           <entry>'DB10'</entry>
+           <entry>10 bit raw Bayer DPCM compressed to 8 bits.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-PAC207">
+           <entry><constant>V4L2_PIX_FMT_PAC207</constant></entry>
+           <entry>'P207'</entry>
+           <entry>Compressed BGGR Bayer format used by the gspca driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-MR97310A">
+           <entry><constant>V4L2_PIX_FMT_MR97310A</constant></entry>
+           <entry>'M310'</entry>
+           <entry>Compressed BGGR Bayer format used by the gspca driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-OV511">
+           <entry><constant>V4L2_PIX_FMT_OV511</constant></entry>
+           <entry>'O511'</entry>
+           <entry>OV511 JPEG format used by the gspca driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-OV518">
+           <entry><constant>V4L2_PIX_FMT_OV518</constant></entry>
+           <entry>'O518'</entry>
+           <entry>OV518 JPEG format used by the gspca driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-PJPG">
+           <entry><constant>V4L2_PIX_FMT_PJPG</constant></entry>
+           <entry>'PJPG'</entry>
+           <entry>Pixart 73xx JPEG format used by the gspca driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-SE401">
+           <entry><constant>V4L2_PIX_FMT_SE401</constant></entry>
+           <entry>'S401'</entry>
+           <entry>Compressed RGB format used by the gspca se401 driver</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-SQ905C">
+           <entry><constant>V4L2_PIX_FMT_SQ905C</constant></entry>
+           <entry>'905C'</entry>
+           <entry>Compressed RGGB bayer format used by the gspca driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-MJPEG">
+           <entry><constant>V4L2_PIX_FMT_MJPEG</constant></entry>
+           <entry>'MJPG'</entry>
+           <entry>Compressed format used by the Zoran driver</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-PWC1">
+           <entry><constant>V4L2_PIX_FMT_PWC1</constant></entry>
+           <entry>'PWC1'</entry>
+           <entry>Compressed format of the PWC driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-PWC2">
+           <entry><constant>V4L2_PIX_FMT_PWC2</constant></entry>
+           <entry>'PWC2'</entry>
+           <entry>Compressed format of the PWC driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-SN9C10X">
+           <entry><constant>V4L2_PIX_FMT_SN9C10X</constant></entry>
+           <entry>'S910'</entry>
+           <entry>Compressed format of the SN9C102 driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-SN9C20X-I420">
+           <entry><constant>V4L2_PIX_FMT_SN9C20X_I420</constant></entry>
+           <entry>'S920'</entry>
+           <entry>YUV 4:2:0 format of the gspca sn9c20x driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-SN9C2028">
+           <entry><constant>V4L2_PIX_FMT_SN9C2028</constant></entry>
+           <entry>'SONX'</entry>
+           <entry>Compressed GBRG bayer format of the gspca sn9c2028 driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-STV0680">
+           <entry><constant>V4L2_PIX_FMT_STV0680</constant></entry>
+           <entry>'S680'</entry>
+           <entry>Bayer format of the gspca stv0680 driver.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-WNVA">
+           <entry><constant>V4L2_PIX_FMT_WNVA</constant></entry>
+           <entry>'WNVA'</entry>
+           <entry><para>Used by the Winnov Videum driver, <ulink
+url="http://www.thedirks.org/winnov/">
+http://www.thedirks.org/winnov/</ulink></para></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-TM6000">
+           <entry><constant>V4L2_PIX_FMT_TM6000</constant></entry>
+           <entry>'TM60'</entry>
+           <entry><para>Used by Trident tm6000</para></entry>
+         </row>
+         <row id="V4L2-PIX-FMT-CIT-YYVYUY">
+           <entry><constant>V4L2_PIX_FMT_CIT_YYVYUY</constant></entry>
+           <entry>'CITV'</entry>
+           <entry><para>Used by xirlink CIT, found at IBM webcams.</para>
+                  <para>Uses one line of Y then 1 line of VYUY</para>
+           </entry>
+         </row>
+         <row id="V4L2-PIX-FMT-KONICA420">
+           <entry><constant>V4L2_PIX_FMT_KONICA420</constant></entry>
+           <entry>'KONI'</entry>
+           <entry><para>Used by Konica webcams.</para>
+                  <para>YUV420 planar in blocks of 256 pixels.</para>
+           </entry>
+         </row>
+         <row id="V4L2-PIX-FMT-YYUV">
+           <entry><constant>V4L2_PIX_FMT_YYUV</constant></entry>
+           <entry>'YYUV'</entry>
+           <entry>unknown</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-Y4">
+           <entry><constant>V4L2_PIX_FMT_Y4</constant></entry>
+           <entry>'Y04 '</entry>
+           <entry>Old 4-bit greyscale format. Only the least significant 4 bits of each byte are used,
+the other bits are set to 0.</entry>
+         </row>
+         <row id="V4L2-PIX-FMT-Y6">
+           <entry><constant>V4L2_PIX_FMT_Y6</constant></entry>
+           <entry>'Y06 '</entry>
+           <entry>Old 6-bit greyscale format. Only the least significant 6 bits of each byte are used,
+the other bits are set to 0.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/Documentation/DocBook/media/v4l/planar-apis.xml b/Documentation/DocBook/media/v4l/planar-apis.xml
new file mode 100644 (file)
index 0000000..878ce20
--- /dev/null
@@ -0,0 +1,62 @@
+<section id="planar-apis">
+  <title>Single- and multi-planar APIs</title>
+
+  <para>Some devices require data for each input or output video frame
+  to be placed in discontiguous memory buffers. In such cases, one
+  video frame has to be addressed using more than one memory address, i.e. one
+  pointer per "plane". A plane is a sub-buffer of the current frame. For
+  examples of such formats see <xref linkend="pixfmt" />.</para>
+
+  <para>Initially, V4L2 API did not support multi-planar buffers and a set of
+  extensions has been introduced to handle them. Those extensions constitute
+  what is being referred to as the "multi-planar API".</para>
+
+  <para>Some of the V4L2 API calls and structures are interpreted differently,
+  depending on whether single- or multi-planar API is being used. An application
+  can choose whether to use one or the other by passing a corresponding buffer
+  type to its ioctl calls. Multi-planar versions of buffer types are suffixed
+  with an `_MPLANE' string. For a list of available multi-planar buffer types
+  see &v4l2-buf-type;.
+  </para>
+
+  <section>
+    <title>Multi-planar formats</title>
+    <para>Multi-planar API introduces new multi-planar formats. Those formats
+    use a separate set of FourCC codes. It is important to distinguish between
+    the multi-planar API and a multi-planar format. Multi-planar API calls can
+    handle all single-planar formats as well (as long as they are passed in
+    multi-planar API structures), while the single-planar API cannot
+    handle multi-planar formats.</para>
+  </section>
+
+  <section>
+    <title>Calls that distinguish between single and multi-planar APIs</title>
+    <variablelist>
+      <varlistentry>
+        <term>&VIDIOC-QUERYCAP;</term>
+        <listitem><para>Two additional multi-planar capabilities are added. They can
+        be set together with non-multi-planar ones for devices that handle
+        both single- and multi-planar formats.</para></listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>&VIDIOC-G-FMT;, &VIDIOC-S-FMT;, &VIDIOC-TRY-FMT;</term>
+        <listitem><para>New structures for describing multi-planar formats are added:
+        &v4l2-pix-format-mplane; and &v4l2-plane-pix-format;. Drivers may
+        define new multi-planar formats, which have distinct FourCC codes from
+        the existing single-planar ones.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>&VIDIOC-QBUF;, &VIDIOC-DQBUF;, &VIDIOC-QUERYBUF;</term>
+        <listitem><para>A new &v4l2-plane; structure for describing planes is added.
+        Arrays of this structure are passed in the new
+        <structfield>m.planes</structfield> field of &v4l2-buffer;.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term>&VIDIOC-REQBUFS;</term>
+        <listitem><para>Will allocate multi-planar buffers as requested.</para></listitem>
+      </varlistentry>
+    </variablelist>
+  </section>
+</section>
diff --git a/Documentation/DocBook/media/v4l/remote_controllers.xml b/Documentation/DocBook/media/v4l/remote_controllers.xml
new file mode 100644 (file)
index 0000000..160e464
--- /dev/null
@@ -0,0 +1,177 @@
+<title>Remote Controllers</title>
+<section id="Remote_controllers_Intro">
+<title>Introduction</title>
+
+<para>Currently, most analog and digital devices have a Infrared input for remote controllers. Each
+manufacturer has their own type of control. It is not rare for the same manufacturer to ship different
+types of controls, depending on the device.</para>
+<para>Unfortunately, for several years, there was no effort to create uniform IR keycodes for
+different devices.  This caused the same IR keyname to be mapped completely differently on
+different IR devices. This resulted that the same IR keyname to be mapped completely different on
+different IR's. Due to that, V4L2 API now specifies a standard for mapping Media keys on IR.</para>
+<para>This standard should be used by both V4L/DVB drivers and userspace applications</para>
+<para>The modules register the remote as keyboard within the linux input layer. This means that the IR key strokes will look like normal keyboard key strokes (if CONFIG_INPUT_KEYBOARD is enabled). Using the event devices (CONFIG_INPUT_EVDEV) it is possible for applications to access the remote via /dev/input/event devices.</para>
+
+<table pgwide="1" frame="none" id="rc_standard_keymap">
+<title>IR default keymapping</title>
+<tgroup cols="3">
+&cs-str;
+<tbody valign="top">
+<row>
+<entry>Key code</entry>
+<entry>Meaning</entry>
+<entry>Key examples on IR</entry>
+</row>
+
+<row><entry><emphasis role="bold">Numeric keys</emphasis></entry></row>
+
+<row><entry><constant>KEY_0</constant></entry><entry>Keyboard digit 0</entry><entry>0</entry></row>
+<row><entry><constant>KEY_1</constant></entry><entry>Keyboard digit 1</entry><entry>1</entry></row>
+<row><entry><constant>KEY_2</constant></entry><entry>Keyboard digit 2</entry><entry>2</entry></row>
+<row><entry><constant>KEY_3</constant></entry><entry>Keyboard digit 3</entry><entry>3</entry></row>
+<row><entry><constant>KEY_4</constant></entry><entry>Keyboard digit 4</entry><entry>4</entry></row>
+<row><entry><constant>KEY_5</constant></entry><entry>Keyboard digit 5</entry><entry>5</entry></row>
+<row><entry><constant>KEY_6</constant></entry><entry>Keyboard digit 6</entry><entry>6</entry></row>
+<row><entry><constant>KEY_7</constant></entry><entry>Keyboard digit 7</entry><entry>7</entry></row>
+<row><entry><constant>KEY_8</constant></entry><entry>Keyboard digit 8</entry><entry>8</entry></row>
+<row><entry><constant>KEY_9</constant></entry><entry>Keyboard digit 9</entry><entry>9</entry></row>
+
+<row><entry><emphasis role="bold">Movie play control</emphasis></entry></row>
+
+<row><entry><constant>KEY_FORWARD</constant></entry><entry>Instantly advance in time</entry><entry>&gt;&gt; / FORWARD</entry></row>
+<row><entry><constant>KEY_BACK</constant></entry><entry>Instantly go back in time</entry><entry>&lt;&lt;&lt; / BACK</entry></row>
+<row><entry><constant>KEY_FASTFORWARD</constant></entry><entry>Play movie faster</entry><entry>&gt;&gt;&gt; / FORWARD</entry></row>
+<row><entry><constant>KEY_REWIND</constant></entry><entry>Play movie back</entry><entry>REWIND / BACKWARD</entry></row>
+<row><entry><constant>KEY_NEXT</constant></entry><entry>Select next chapter / sub-chapter / interval</entry><entry>NEXT / SKIP</entry></row>
+<row><entry><constant>KEY_PREVIOUS</constant></entry><entry>Select previous chapter / sub-chapter / interval</entry><entry>&lt;&lt; /  PREV / PREVIOUS</entry></row>
+<row><entry><constant>KEY_AGAIN</constant></entry><entry>Repeat the video or a video interval</entry><entry>REPEAT / LOOP / RECALL</entry></row>
+<row><entry><constant>KEY_PAUSE</constant></entry><entry>Pause sroweam</entry><entry>PAUSE / FREEZE</entry></row>
+<row><entry><constant>KEY_PLAY</constant></entry><entry>Play movie at the normal timeshift</entry><entry>NORMAL TIMESHIFT / LIVE / &gt;</entry></row>
+<row><entry><constant>KEY_PLAYPAUSE</constant></entry><entry>Alternate between play and pause</entry><entry>PLAY / PAUSE</entry></row>
+<row><entry><constant>KEY_STOP</constant></entry><entry>Stop sroweam</entry><entry>STOP</entry></row>
+<row><entry><constant>KEY_RECORD</constant></entry><entry>Start/stop recording sroweam</entry><entry>CAPTURE / REC / RECORD/PAUSE</entry></row>
+<row><entry><constant>KEY_CAMERA</constant></entry><entry>Take a picture of the image</entry><entry>CAMERA ICON / CAPTURE / SNAPSHOT</entry></row>
+<row><entry><constant>KEY_SHUFFLE</constant></entry><entry>Enable shuffle mode</entry><entry>SHUFFLE</entry></row>
+<row><entry><constant>KEY_TIME</constant></entry><entry>Activate time shift mode</entry><entry>TIME SHIFT</entry></row>
+<row><entry><constant>KEY_TITLE</constant></entry><entry>Allow changing the chapter</entry><entry>CHAPTER</entry></row>
+<row><entry><constant>KEY_SUBTITLE</constant></entry><entry>Allow changing the subtitle</entry><entry>SUBTITLE</entry></row>
+
+<row><entry><emphasis role="bold">Image control</emphasis></entry></row>
+
+<row><entry><constant>KEY_BRIGHTNESSDOWN</constant></entry><entry>Decrease Brightness</entry><entry>BRIGHTNESS DECREASE</entry></row>
+<row><entry><constant>KEY_BRIGHTNESSUP</constant></entry><entry>Increase Brightness</entry><entry>BRIGHTNESS INCREASE</entry></row>
+
+<row><entry><constant>KEY_ANGLE</constant></entry><entry>Switch video camera angle (on videos with more than one angle stored)</entry><entry>ANGLE / SWAP</entry></row>
+<row><entry><constant>KEY_EPG</constant></entry><entry>Open the Elecrowonic Play Guide (EPG)</entry><entry>EPG / GUIDE</entry></row>
+<row><entry><constant>KEY_TEXT</constant></entry><entry>Activate/change closed caption mode</entry><entry>CLOSED CAPTION/TELETEXT / DVD TEXT / TELETEXT / TTX</entry></row>
+
+<row><entry><emphasis role="bold">Audio control</emphasis></entry></row>
+
+<row><entry><constant>KEY_AUDIO</constant></entry><entry>Change audio source</entry><entry>AUDIO SOURCE / AUDIO / MUSIC</entry></row>
+<row><entry><constant>KEY_MUTE</constant></entry><entry>Mute/unmute audio</entry><entry>MUTE / DEMUTE / UNMUTE</entry></row>
+<row><entry><constant>KEY_VOLUMEDOWN</constant></entry><entry>Decrease volume</entry><entry>VOLUME- / VOLUME DOWN</entry></row>
+<row><entry><constant>KEY_VOLUMEUP</constant></entry><entry>Increase volume</entry><entry>VOLUME+ / VOLUME UP</entry></row>
+<row><entry><constant>KEY_MODE</constant></entry><entry>Change sound mode</entry><entry>MONO/STEREO</entry></row>
+<row><entry><constant>KEY_LANGUAGE</constant></entry><entry>Select Language</entry><entry>1ST / 2ND LANGUAGE / DVD LANG / MTS/SAP / MTS SEL</entry></row>
+
+<row><entry><emphasis role="bold">Channel control</emphasis></entry></row>
+
+<row><entry><constant>KEY_CHANNEL</constant></entry><entry>Go to the next favorite channel</entry><entry>ALT / CHANNEL / CH SURFING / SURF / FAV</entry></row>
+<row><entry><constant>KEY_CHANNELDOWN</constant></entry><entry>Decrease channel sequencially</entry><entry>CHANNEL - / CHANNEL DOWN / DOWN</entry></row>
+<row><entry><constant>KEY_CHANNELUP</constant></entry><entry>Increase channel sequencially</entry><entry>CHANNEL + / CHANNEL UP / UP</entry></row>
+<row><entry><constant>KEY_DIGITS</constant></entry><entry>Use more than one digit for channel</entry><entry>PLUS / 100/ 1xx / xxx /  -/--  / Single Double Triple Digit</entry></row>
+<row><entry><constant>KEY_SEARCH</constant></entry><entry>Start channel autoscan</entry><entry>SCAN / AUTOSCAN</entry></row>
+
+<row><entry><emphasis role="bold">Colored keys</emphasis></entry></row>
+
+<row><entry><constant>KEY_BLUE</constant></entry><entry>IR Blue key</entry><entry>BLUE</entry></row>
+<row><entry><constant>KEY_GREEN</constant></entry><entry>IR Green Key</entry><entry>GREEN</entry></row>
+<row><entry><constant>KEY_RED</constant></entry><entry>IR Red key</entry><entry>RED</entry></row>
+<row><entry><constant>KEY_YELLOW</constant></entry><entry>IR Yellow key</entry><entry> YELLOW</entry></row>
+
+<row><entry><emphasis role="bold">Media selection</emphasis></entry></row>
+
+<row><entry><constant>KEY_CD</constant></entry><entry>Change input source to Compact Disc</entry><entry>CD</entry></row>
+<row><entry><constant>KEY_DVD</constant></entry><entry>Change input to DVD</entry><entry>DVD / DVD MENU</entry></row>
+<row><entry><constant>KEY_EJECTCLOSECD</constant></entry><entry>Open/close the CD/DVD player</entry><entry>-&gt; ) / CLOSE / OPEN</entry></row>
+
+<row><entry><constant>KEY_MEDIA</constant></entry><entry>Turn on/off Media application</entry><entry>PC/TV /  TURN ON/OFF APP</entry></row>
+<row><entry><constant>KEY_PC</constant></entry><entry>Selects from TV to PC</entry><entry>PC</entry></row>
+<row><entry><constant>KEY_RADIO</constant></entry><entry>Put into AM/FM radio mode</entry><entry>RADIO / TV/FM / TV/RADIO / FM / FM/RADIO</entry></row>
+<row><entry><constant>KEY_TV</constant></entry><entry>Select tv mode</entry><entry>TV / LIVE TV</entry></row>
+<row><entry><constant>KEY_TV2</constant></entry><entry>Select Cable mode</entry><entry>AIR/CBL</entry></row>
+<row><entry><constant>KEY_VCR</constant></entry><entry>Select VCR mode</entry><entry>VCR MODE / DTR</entry></row>
+<row><entry><constant>KEY_VIDEO</constant></entry><entry>Alternate between input modes</entry><entry>SOURCE / SELECT / DISPLAY / SWITCH INPUTS / VIDEO</entry></row>
+
+<row><entry><emphasis role="bold">Power control</emphasis></entry></row>
+
+<row><entry><constant>KEY_POWER</constant></entry><entry>Turn on/off computer</entry><entry>SYSTEM POWER / COMPUTER POWER</entry></row>
+<row><entry><constant>KEY_POWER2</constant></entry><entry>Turn on/off application</entry><entry>TV ON/OFF / POWER</entry></row>
+<row><entry><constant>KEY_SLEEP</constant></entry><entry>Activate sleep timer</entry><entry>SLEEP / SLEEP TIMER</entry></row>
+<row><entry><constant>KEY_SUSPEND</constant></entry><entry>Put computer into suspend mode</entry><entry>STANDBY / SUSPEND</entry></row>
+
+<row><entry><emphasis role="bold">Window control</emphasis></entry></row>
+
+<row><entry><constant>KEY_CLEAR</constant></entry><entry>Stop sroweam and return to default input video/audio</entry><entry>CLEAR / RESET / BOSS KEY</entry></row>
+<row><entry><constant>KEY_CYCLEWINDOWS</constant></entry><entry>Minimize windows and move to the next one</entry><entry>ALT-TAB / MINIMIZE / DESKTOP</entry></row>
+<row><entry><constant>KEY_FAVORITES</constant></entry><entry>Open the favorites sroweam window</entry><entry>TV WALL / Favorites</entry></row>
+<row><entry><constant>KEY_MENU</constant></entry><entry>Call application menu</entry><entry>2ND CONTROLS (USA: MENU) / DVD/MENU / SHOW/HIDE CTRL</entry></row>
+<row><entry><constant>KEY_NEW</constant></entry><entry>Open/Close Picture in Picture</entry><entry>PIP</entry></row>
+<row><entry><constant>KEY_OK</constant></entry><entry>Send a confirmation code to application</entry><entry>OK / ENTER / RETURN</entry></row>
+<row><entry><constant>KEY_SCREEN</constant></entry><entry>Select screen aspect ratio</entry><entry>4:3 16:9 SELECT</entry></row>
+<row><entry><constant>KEY_ZOOM</constant></entry><entry>Put device into zoom/full screen mode</entry><entry>ZOOM / FULL SCREEN / ZOOM+ / HIDE PANNEL / SWITCH</entry></row>
+
+<row><entry><emphasis role="bold">Navigation keys</emphasis></entry></row>
+
+<row><entry><constant>KEY_ESC</constant></entry><entry>Cancel current operation</entry><entry>CANCEL / BACK</entry></row>
+<row><entry><constant>KEY_HELP</constant></entry><entry>Open a Help window</entry><entry>HELP</entry></row>
+<row><entry><constant>KEY_HOMEPAGE</constant></entry><entry>Navigate to Homepage</entry><entry>HOME</entry></row>
+<row><entry><constant>KEY_INFO</constant></entry><entry>Open On Screen Display</entry><entry>DISPLAY INFORMATION / OSD</entry></row>
+<row><entry><constant>KEY_WWW</constant></entry><entry>Open the default browser</entry><entry>WEB</entry></row>
+<row><entry><constant>KEY_UP</constant></entry><entry>Up key</entry><entry>UP</entry></row>
+<row><entry><constant>KEY_DOWN</constant></entry><entry>Down key</entry><entry>DOWN</entry></row>
+<row><entry><constant>KEY_LEFT</constant></entry><entry>Left key</entry><entry>LEFT</entry></row>
+<row><entry><constant>KEY_RIGHT</constant></entry><entry>Right key</entry><entry>RIGHT</entry></row>
+
+<row><entry><emphasis role="bold">Miscellaneous keys</emphasis></entry></row>
+
+<row><entry><constant>KEY_DOT</constant></entry><entry>Return a dot</entry><entry>.</entry></row>
+<row><entry><constant>KEY_FN</constant></entry><entry>Select a function</entry><entry>FUNCTION</entry></row>
+
+</tbody>
+</tgroup>
+</table>
+
+<para>It should be noticed that, sometimes, there some fundamental missing keys at some cheaper IR's. Due to that, it is recommended to:</para>
+
+<table pgwide="1" frame="none" id="rc_keymap_notes">
+<title>Notes</title>
+<tgroup cols="1">
+&cs-str;
+<tbody valign="top">
+<row>
+<entry>On simpler IR's, without separate channel keys, you need to map UP as <constant>KEY_CHANNELUP</constant></entry>
+</row><row>
+<entry>On simpler IR's, without separate channel keys, you need to map DOWN as <constant>KEY_CHANNELDOWN</constant></entry>
+</row><row>
+<entry>On simpler IR's, without separate volume keys, you need to map LEFT as <constant>KEY_VOLUMEDOWN</constant></entry>
+</row><row>
+<entry>On simpler IR's, without separate volume keys, you need to map RIGHT as <constant>KEY_VOLUMEUP</constant></entry>
+</row>
+</tbody>
+</tgroup>
+</table>
+
+</section>
+
+<section id="Remote_controllers_table_change">
+<title>Changing default Remote Controller mappings</title>
+<para>The event interface provides two ioctls to be used against
+the /dev/input/event device, to allow changing the default
+keymapping.</para>
+
+<para>This program demonstrates how to replace the keymap tables.</para>
+&sub-keytable-c;
+</section>
+
+&sub-lirc_device_interface;
diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml
new file mode 100644 (file)
index 0000000..49c532e
--- /dev/null
@@ -0,0 +1,2569 @@
+<section id="v4l2-mbus-format">
+  <title>Media Bus Formats</title>
+
+  <table pgwide="1" frame="none" id="v4l2-mbus-framefmt">
+    <title>struct <structname>v4l2_mbus_framefmt</structname></title>
+    <tgroup cols="3">
+      &cs-str;
+      <tbody valign="top">
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>width</structfield></entry>
+         <entry>Image width, in pixels.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>height</structfield></entry>
+         <entry>Image height, in pixels.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>code</structfield></entry>
+         <entry>Format code, from &v4l2-mbus-pixelcode;.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>field</structfield></entry>
+         <entry>Field order, from &v4l2-field;. See
+         <xref linkend="field-order" /> for details.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>colorspace</structfield></entry>
+         <entry>Image colorspace, from &v4l2-colorspace;. See
+         <xref linkend="colorspaces" /> for details.</entry>
+       </row>
+       <row>
+         <entry>__u32</entry>
+         <entry><structfield>reserved</structfield>[7]</entry>
+         <entry>Reserved for future extensions. Applications and drivers must
+         set the array to zero.</entry>
+       </row>
+      </tbody>
+    </tgroup>
+  </table>
+
+  <section id="v4l2-mbus-pixelcode">
+    <title>Media Bus Pixel Codes</title>
+
+    <para>The media bus pixel codes describe image formats as flowing over
+    physical busses (both between separate physical components and inside SoC
+    devices). This should not be confused with the V4L2 pixel formats that
+    describe, using four character codes, image formats as stored in memory.
+    </para>
+
+    <para>While there is a relationship between image formats on busses and
+    image formats in memory (a raw Bayer image won't be magically converted to
+    JPEG just by storing it to memory), there is no one-to-one correspondance
+    between them.</para>
+
+    <section>
+      <title>Packed RGB Formats</title>
+
+      <para>Those formats transfer pixel data as red, green and blue components.
+      The format code is made of the following information.
+      <itemizedlist>
+       <listitem><para>The red, green and blue components order code, as encoded in a
+       pixel sample. Possible values are RGB and BGR.</para></listitem>
+       <listitem><para>The number of bits per component, for each component. The values
+       can be different for all components. Common values are 555 and 565.</para>
+       </listitem>
+       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
+       the bus width must be transferred in multiple samples. Common values are
+       1 and 2.</para></listitem>
+       <listitem><para>The bus width.</para></listitem>
+       <listitem><para>For formats where the total number of bits per pixel is smaller
+       than the number of bus samples per pixel times the bus width, a padding
+       value stating if the bytes are padded in their most high order bits
+       (PADHI) or low order bits (PADLO).</para></listitem>
+       <listitem><para>For formats where the number of bus samples per pixel is larger
+       than 1, an endianness value stating if the pixel is transferred MSB first
+       (BE) or LSB first (LE).</para></listitem>
+      </itemizedlist>
+      </para>
+
+      <para>For instance, a format where pixels are encoded as 5-bits red, 5-bits
+      green and 5-bit blue values padded on the high bit, transferred as 2 8-bit
+      samples per pixel with the most significant bits (padding, red and half of
+      the green value) transferred first will be named
+      <constant>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</constant>.
+      </para>
+
+      <para>The following tables list existing packet RGB formats.</para>
+
+      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb">
+       <title>RGB formats</title>
+       <tgroup cols="11">
+         <colspec colname="id" align="left" />
+         <colspec colname="code" align="center"/>
+         <colspec colname="bit" />
+         <colspec colnum="4" colname="b07" align="center" />
+         <colspec colnum="5" colname="b06" align="center" />
+         <colspec colnum="6" colname="b05" align="center" />
+         <colspec colnum="7" colname="b04" align="center" />
+         <colspec colnum="8" colname="b03" align="center" />
+         <colspec colnum="9" colname="b02" align="center" />
+         <colspec colnum="10" colname="b01" align="center" />
+         <colspec colnum="11" colname="b00" align="center" />
+         <spanspec namest="b07" nameend="b00" spanname="b0" />
+         <thead>
+           <row>
+             <entry>Identifier</entry>
+             <entry>Code</entry>
+             <entry></entry>
+             <entry spanname="b0">Data organization</entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>Bit</entry>
+             <entry>7</entry>
+             <entry>6</entry>
+             <entry>5</entry>
+             <entry>4</entry>
+             <entry>3</entry>
+             <entry>2</entry>
+             <entry>1</entry>
+             <entry>0</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-BE">
+             <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE</entry>
+             <entry>0x1001</entry>
+             <entry></entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-LE">
+             <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE</entry>
+             <entry>0x1002</entry>
+             <entry></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-BE">
+             <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</entry>
+             <entry>0x1003</entry>
+             <entry></entry>
+             <entry>0</entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-LE">
+             <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE</entry>
+             <entry>0x1004</entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>0</entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-BGR565-2X8-BE">
+             <entry>V4L2_MBUS_FMT_BGR565_2X8_BE</entry>
+             <entry>0x1005</entry>
+             <entry></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-BGR565-2X8-LE">
+             <entry>V4L2_MBUS_FMT_BGR565_2X8_LE</entry>
+             <entry>0x1006</entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-RGB565-2X8-BE">
+             <entry>V4L2_MBUS_FMT_RGB565_2X8_BE</entry>
+             <entry>0x1007</entry>
+             <entry></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-RGB565-2X8-LE">
+             <entry>V4L2_MBUS_FMT_RGB565_2X8_LE</entry>
+             <entry>0x1008</entry>
+             <entry></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
+
+    <section>
+      <title>Bayer Formats</title>
+
+      <para>Those formats transfer pixel data as red, green and blue components.
+      The format code is made of the following information.
+      <itemizedlist>
+       <listitem><para>The red, green and blue components order code, as encoded in a
+       pixel sample. The possible values are shown in <xref
+       linkend="bayer-patterns" />.</para></listitem>
+       <listitem><para>The number of bits per pixel component. All components are
+       transferred on the same number of bits. Common values are 8, 10 and 12.</para>
+       </listitem>
+       <listitem><para>If the pixel components are DPCM-compressed, a mention of the
+       DPCM compression and the number of bits per compressed pixel component.</para>
+       </listitem>
+       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
+       the bus width must be transferred in multiple samples. Common values are
+       1 and 2.</para></listitem>
+       <listitem><para>The bus width.</para></listitem>
+       <listitem><para>For formats where the total number of bits per pixel is smaller
+       than the number of bus samples per pixel times the bus width, a padding
+       value stating if the bytes are padded in their most high order bits
+       (PADHI) or low order bits (PADLO).</para></listitem>
+       <listitem><para>For formats where the number of bus samples per pixel is larger
+       than 1, an endianness value stating if the pixel is transferred MSB first
+       (BE) or LSB first (LE).</para></listitem>
+      </itemizedlist>
+      </para>
+
+      <para>For instance, a format with uncompressed 10-bit Bayer components
+      arranged in a red, green, green, blue pattern transferred as 2 8-bit
+      samples per pixel with the least significant bits transferred first will
+      be named <constant>V4L2_MBUS_FMT_SRGGB10_2X8_PADHI_LE</constant>.
+      </para>
+
+      <figure id="bayer-patterns">
+       <title>Bayer Patterns</title>
+       <mediaobject>
+         <imageobject>
+           <imagedata fileref="bayer.png" format="PNG" />
+         </imageobject>
+         <textobject>
+           <phrase>Bayer filter color patterns</phrase>
+         </textobject>
+       </mediaobject>
+      </figure>
+
+      <para>The following table lists existing packet Bayer formats. The data
+      organization is given as an example for the first pixel only.</para>
+
+      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-bayer">
+       <title>Bayer Formats</title>
+       <tgroup cols="15">
+         <colspec colname="id" align="left" />
+         <colspec colname="code" align="center"/>
+         <colspec colname="bit" />
+         <colspec colnum="4" colname="b11" align="center" />
+         <colspec colnum="5" colname="b10" align="center" />
+         <colspec colnum="6" colname="b09" align="center" />
+         <colspec colnum="7" colname="b08" align="center" />
+         <colspec colnum="8" colname="b07" align="center" />
+         <colspec colnum="9" colname="b06" align="center" />
+         <colspec colnum="10" colname="b05" align="center" />
+         <colspec colnum="11" colname="b04" align="center" />
+         <colspec colnum="12" colname="b03" align="center" />
+         <colspec colnum="13" colname="b02" align="center" />
+         <colspec colnum="14" colname="b01" align="center" />
+         <colspec colnum="15" colname="b00" align="center" />
+         <spanspec namest="b11" nameend="b00" spanname="b0" />
+         <thead>
+           <row>
+             <entry>Identifier</entry>
+             <entry>Code</entry>
+             <entry></entry>
+             <entry spanname="b0">Data organization</entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>Bit</entry>
+             <entry>11</entry>
+             <entry>10</entry>
+             <entry>9</entry>
+             <entry>8</entry>
+             <entry>7</entry>
+             <entry>6</entry>
+             <entry>5</entry>
+             <entry>4</entry>
+             <entry>3</entry>
+             <entry>2</entry>
+             <entry>1</entry>
+             <entry>0</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row id="V4L2-MBUS-FMT-SBGGR8-1X8">
+             <entry>V4L2_MBUS_FMT_SBGGR8_1X8</entry>
+             <entry>0x3001</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGBRG8-1X8">
+             <entry>V4L2_MBUS_FMT_SGBRG8_1X8</entry>
+             <entry>0x3013</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGRBG8-1X8">
+             <entry>V4L2_MBUS_FMT_SGRBG8_1X8</entry>
+             <entry>0x3002</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SRGGB8-1X8">
+             <entry>V4L2_MBUS_FMT_SRGGB8_1X8</entry>
+             <entry>0x3014</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-DPCM8-1X8">
+             <entry>V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8</entry>
+             <entry>0x300b</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGBRG10-DPCM8-1X8">
+             <entry>V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8</entry>
+             <entry>0x300c</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGRBG10-DPCM8-1X8">
+             <entry>V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8</entry>
+             <entry>0x3009</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SRGGB10-DPCM8-1X8">
+             <entry>V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8</entry>
+             <entry>0x300d</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-BE">
+             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE</entry>
+             <entry>0x3003</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-LE">
+             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE</entry>
+             <entry>0x3004</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-BE">
+             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE</entry>
+             <entry>0x3005</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-LE">
+             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE</entry>
+             <entry>0x3006</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+             <entry>0</entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR10-1X10">
+             <entry>V4L2_MBUS_FMT_SBGGR10_1X10</entry>
+             <entry>0x3007</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGBRG10-1X10">
+             <entry>V4L2_MBUS_FMT_SGBRG10_1X10</entry>
+             <entry>0x300e</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>9</subscript></entry>
+             <entry>g<subscript>8</subscript></entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGRBG10-1X10">
+             <entry>V4L2_MBUS_FMT_SGRBG10_1X10</entry>
+             <entry>0x300a</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>g<subscript>9</subscript></entry>
+             <entry>g<subscript>8</subscript></entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SRGGB10-1X10">
+             <entry>V4L2_MBUS_FMT_SRGGB10_1X10</entry>
+             <entry>0x300f</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>r<subscript>9</subscript></entry>
+             <entry>r<subscript>8</subscript></entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SBGGR12-1X12">
+             <entry>V4L2_MBUS_FMT_SBGGR12_1X12</entry>
+             <entry>0x3008</entry>
+             <entry></entry>
+             <entry>b<subscript>11</subscript></entry>
+             <entry>b<subscript>10</subscript></entry>
+             <entry>b<subscript>9</subscript></entry>
+             <entry>b<subscript>8</subscript></entry>
+             <entry>b<subscript>7</subscript></entry>
+             <entry>b<subscript>6</subscript></entry>
+             <entry>b<subscript>5</subscript></entry>
+             <entry>b<subscript>4</subscript></entry>
+             <entry>b<subscript>3</subscript></entry>
+             <entry>b<subscript>2</subscript></entry>
+             <entry>b<subscript>1</subscript></entry>
+             <entry>b<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGBRG12-1X12">
+             <entry>V4L2_MBUS_FMT_SGBRG12_1X12</entry>
+             <entry>0x3010</entry>
+             <entry></entry>
+             <entry>g<subscript>11</subscript></entry>
+             <entry>g<subscript>10</subscript></entry>
+             <entry>g<subscript>9</subscript></entry>
+             <entry>g<subscript>8</subscript></entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SGRBG12-1X12">
+             <entry>V4L2_MBUS_FMT_SGRBG12_1X12</entry>
+             <entry>0x3011</entry>
+             <entry></entry>
+             <entry>g<subscript>11</subscript></entry>
+             <entry>g<subscript>10</subscript></entry>
+             <entry>g<subscript>9</subscript></entry>
+             <entry>g<subscript>8</subscript></entry>
+             <entry>g<subscript>7</subscript></entry>
+             <entry>g<subscript>6</subscript></entry>
+             <entry>g<subscript>5</subscript></entry>
+             <entry>g<subscript>4</subscript></entry>
+             <entry>g<subscript>3</subscript></entry>
+             <entry>g<subscript>2</subscript></entry>
+             <entry>g<subscript>1</subscript></entry>
+             <entry>g<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-SRGGB12-1X12">
+             <entry>V4L2_MBUS_FMT_SRGGB12_1X12</entry>
+             <entry>0x3012</entry>
+             <entry></entry>
+             <entry>r<subscript>11</subscript></entry>
+             <entry>r<subscript>10</subscript></entry>
+             <entry>r<subscript>9</subscript></entry>
+             <entry>r<subscript>8</subscript></entry>
+             <entry>r<subscript>7</subscript></entry>
+             <entry>r<subscript>6</subscript></entry>
+             <entry>r<subscript>5</subscript></entry>
+             <entry>r<subscript>4</subscript></entry>
+             <entry>r<subscript>3</subscript></entry>
+             <entry>r<subscript>2</subscript></entry>
+             <entry>r<subscript>1</subscript></entry>
+             <entry>r<subscript>0</subscript></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
+
+    <section>
+      <title>Packed YUV Formats</title>
+
+      <para>Those data formats transfer pixel data as (possibly downsampled) Y, U
+      and V components. The format code is made of the following information.
+      <itemizedlist>
+       <listitem><para>The Y, U and V components order code, as transferred on the
+       bus. Possible values are YUYV, UYVY, YVYU and VYUY.</para></listitem>
+       <listitem><para>The number of bits per pixel component. All components are
+       transferred on the same number of bits. Common values are 8, 10 and 12.</para>
+       </listitem>
+       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
+       the bus width must be transferred in multiple samples. Common values are
+       1, 1.5 (encoded as 1_5) and 2.</para></listitem>
+       <listitem><para>The bus width. When the bus width is larger than the number of
+       bits per pixel component, several components are packed in a single bus
+       sample. The components are ordered as specified by the order code, with
+       components on the left of the code transferred in the high order bits.
+       Common values are 8 and 16.</para>
+       </listitem>
+      </itemizedlist>
+      </para>
+
+      <para>For instance, a format where pixels are encoded as 8-bit YUV values
+      downsampled to 4:2:2 and transferred as 2 8-bit bus samples per pixel in the
+      U, Y, V, Y order will be named <constant>V4L2_MBUS_FMT_UYVY8_2X8</constant>.
+      </para>
+
+      <para>The following table lisst existing packet YUV formats.</para>
+
+      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-yuv8">
+       <title>YUV Formats</title>
+       <tgroup cols="23">
+         <colspec colname="id" align="left" />
+         <colspec colname="code" align="center"/>
+         <colspec colname="bit" />
+         <colspec colnum="4" colname="b19" align="center" />
+         <colspec colnum="5" colname="b18" align="center" />
+         <colspec colnum="6" colname="b17" align="center" />
+         <colspec colnum="7" colname="b16" align="center" />
+         <colspec colnum="8" colname="b15" align="center" />
+         <colspec colnum="9" colname="b14" align="center" />
+         <colspec colnum="10" colname="b13" align="center" />
+         <colspec colnum="11" colname="b12" align="center" />
+         <colspec colnum="12" colname="b11" align="center" />
+         <colspec colnum="13" colname="b10" align="center" />
+         <colspec colnum="14" colname="b09" align="center" />
+         <colspec colnum="15" colname="b08" align="center" />
+         <colspec colnum="16" colname="b07" align="center" />
+         <colspec colnum="17" colname="b06" align="center" />
+         <colspec colnum="18" colname="b05" align="center" />
+         <colspec colnum="19" colname="b04" align="center" />
+         <colspec colnum="20" colname="b03" align="center" />
+         <colspec colnum="21" colname="b02" align="center" />
+         <colspec colnum="22" colname="b01" align="center" />
+         <colspec colnum="23" colname="b00" align="center" />
+         <spanspec namest="b19" nameend="b00" spanname="b0" />
+         <thead>
+           <row>
+             <entry>Identifier</entry>
+             <entry>Code</entry>
+             <entry></entry>
+             <entry spanname="b0">Data organization</entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>Bit</entry>
+             <entry>19</entry>
+             <entry>18</entry>
+             <entry>17</entry>
+             <entry>16</entry>
+             <entry>15</entry>
+             <entry>14</entry>
+             <entry>13</entry>
+             <entry>12</entry>
+             <entry>11</entry>
+             <entry>10</entry>
+             <entry>9</entry>
+             <entry>8</entry>
+             <entry>7</entry>
+             <entry>6</entry>
+             <entry>5</entry>
+             <entry>4</entry>
+             <entry>3</entry>
+             <entry>2</entry>
+             <entry>1</entry>
+             <entry>0</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row id="V4L2-MBUS-FMT-Y8-1X8">
+             <entry>V4L2_MBUS_FMT_Y8_1X8</entry>
+             <entry>0x2001</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-UYVY8-1_5X8">
+             <entry>V4L2_MBUS_FMT_UYVY8_1_5X8</entry>
+             <entry>0x2002</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-VYUY8-1_5X8">
+             <entry>V4L2_MBUS_FMT_VYUY8_1_5X8</entry>
+             <entry>0x2003</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YUYV8-1_5X8">
+             <entry>V4L2_MBUS_FMT_YUYV8_1_5X8</entry>
+             <entry>0x2004</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YVYU8-1_5X8">
+             <entry>V4L2_MBUS_FMT_YVYU8_1_5X8</entry>
+             <entry>0x2005</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-UYVY8-2X8">
+             <entry>V4L2_MBUS_FMT_UYVY8_2X8</entry>
+             <entry>0x2006</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-VYUY8-2X8">
+             <entry>V4L2_MBUS_FMT_VYUY8_2X8</entry>
+             <entry>0x2007</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YUYV8-2X8">
+             <entry>V4L2_MBUS_FMT_YUYV8_2X8</entry>
+             <entry>0x2008</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YVYU8-2X8">
+             <entry>V4L2_MBUS_FMT_YVYU8_2X8</entry>
+             <entry>0x2009</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-Y10-1X10">
+             <entry>V4L2_MBUS_FMT_Y10_1X10</entry>
+             <entry>0x200a</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YUYV10-2X10">
+             <entry>V4L2_MBUS_FMT_YUYV10_2X10</entry>
+             <entry>0x200b</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>9</subscript></entry>
+             <entry>u<subscript>8</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>9</subscript></entry>
+             <entry>v<subscript>8</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YVYU10-2X10">
+             <entry>V4L2_MBUS_FMT_YVYU10_2X10</entry>
+             <entry>0x200c</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>9</subscript></entry>
+             <entry>v<subscript>8</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>9</subscript></entry>
+             <entry>u<subscript>8</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-Y12-1X12">
+             <entry>V4L2_MBUS_FMT_Y12_1X12</entry>
+             <entry>0x2013</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>11</subscript></entry>
+             <entry>y<subscript>10</subscript></entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-UYVY8-1X16">
+             <entry>V4L2_MBUS_FMT_UYVY8_1X16</entry>
+             <entry>0x200f</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-VYUY8-1X16">
+             <entry>V4L2_MBUS_FMT_VYUY8_1X16</entry>
+             <entry>0x2010</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YUYV8-1X16">
+             <entry>V4L2_MBUS_FMT_YUYV8_1X16</entry>
+             <entry>0x2011</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YVYU8-1X16">
+             <entry>V4L2_MBUS_FMT_YVYU8_1X16</entry>
+             <entry>0x2012</entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>-</entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YUYV10-1X20">
+             <entry>V4L2_MBUS_FMT_YUYV10_1X20</entry>
+             <entry>0x200d</entry>
+             <entry></entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>u<subscript>9</subscript></entry>
+             <entry>u<subscript>8</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>v<subscript>9</subscript></entry>
+             <entry>v<subscript>8</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row id="V4L2-MBUS-FMT-YVYU10-1X20">
+             <entry>V4L2_MBUS_FMT_YVYU10_1X20</entry>
+             <entry>0x200e</entry>
+             <entry></entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>v<subscript>9</subscript></entry>
+             <entry>v<subscript>8</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry></entry>
+             <entry>y<subscript>9</subscript></entry>
+             <entry>y<subscript>8</subscript></entry>
+             <entry>y<subscript>7</subscript></entry>
+             <entry>y<subscript>6</subscript></entry>
+             <entry>y<subscript>5</subscript></entry>
+             <entry>y<subscript>4</subscript></entry>
+             <entry>y<subscript>3</subscript></entry>
+             <entry>y<subscript>2</subscript></entry>
+             <entry>y<subscript>1</subscript></entry>
+             <entry>y<subscript>0</subscript></entry>
+             <entry>u<subscript>9</subscript></entry>
+             <entry>u<subscript>8</subscript></entry>
+             <entry>u<subscript>7</subscript></entry>
+             <entry>u<subscript>6</subscript></entry>
+             <entry>u<subscript>5</subscript></entry>
+             <entry>u<subscript>4</subscript></entry>
+             <entry>u<subscript>3</subscript></entry>
+             <entry>u<subscript>2</subscript></entry>
+             <entry>u<subscript>1</subscript></entry>
+             <entry>u<subscript>0</subscript></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
+
+    <section>
+      <title>JPEG Compressed Formats</title>
+
+      <para>Those data formats consist of an ordered sequence of 8-bit bytes
+       obtained from JPEG compression process. Additionally to the
+       <constant>_JPEG</constant> postfix the format code is made of
+       the following information.
+       <itemizedlist>
+         <listitem><para>The number of bus samples per entropy encoded byte.</para></listitem>
+         <listitem><para>The bus width.</para></listitem>
+       </itemizedlist>
+      </para>
+
+      <para>For instance, for a JPEG baseline process and an 8-bit bus width
+        the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>.
+      </para>
+
+      <para>The following table lists existing JPEG compressed formats.</para>
+
+      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-jpeg">
+       <title>JPEG Formats</title>
+       <tgroup cols="3">
+         <colspec colname="id" align="left" />
+         <colspec colname="code" align="left"/>
+         <colspec colname="remarks" align="left"/>
+         <thead>
+           <row>
+             <entry>Identifier</entry>
+             <entry>Code</entry>
+             <entry>Remarks</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row id="V4L2-MBUS-FMT-JPEG-1X8">
+             <entry>V4L2_MBUS_FMT_JPEG_1X8</entry>
+             <entry>0x4001</entry>
+             <entry>Besides of its usage for the parallel bus this format is
+               recommended for transmission of JPEG data over MIPI CSI bus
+               using the User Defined 8-bit Data types.
+             </entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
+  </section>
+</section>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
new file mode 100644 (file)
index 0000000..0d05e87
--- /dev/null
@@ -0,0 +1,548 @@
+ <partinfo>
+    <authorgroup>
+      <author>
+       <firstname>Michael</firstname>
+       <surname>Schimek</surname>
+       <othername role="mi">H</othername>
+       <affiliation>
+         <address>
+           <email>mschimek@gmx.at</email>
+         </address>
+       </affiliation>
+      </author>
+
+      <author>
+       <firstname>Bill</firstname>
+       <surname>Dirks</surname>
+       <!-- Commented until Bill opts in to be spammed.
+       <affiliation>
+         <address>
+           <email>bill@thedirks.org</email>
+         </address>
+       </affiliation> -->
+       <contrib>Original author of the V4L2 API and
+documentation.</contrib>
+      </author>
+
+      <author>
+       <firstname>Hans</firstname>
+       <surname>Verkuil</surname>
+       <contrib>Designed and documented the VIDIOC_LOG_STATUS ioctl,
+the extended control ioctls and major parts of the sliced VBI
+API.</contrib>
+       <affiliation>
+         <address>
+           <email>hverkuil@xs4all.nl</email>
+         </address>
+       </affiliation>
+      </author>
+
+      <author>
+       <firstname>Martin</firstname>
+       <surname>Rubli</surname>
+       <!--
+       <affiliation>
+         <address>
+           <email>martin_rubli@logitech.com</email>
+         </address>
+       </affiliation> -->
+       <contrib>Designed and documented the VIDIOC_ENUM_FRAMESIZES
+and VIDIOC_ENUM_FRAMEINTERVALS ioctls.</contrib>
+      </author>
+
+      <author>
+       <firstname>Andy</firstname>
+       <surname>Walls</surname>
+       <contrib>Documented the fielded V4L2_MPEG_STREAM_VBI_FMT_IVTV
+MPEG stream embedded, sliced VBI data format in this specification.
+</contrib>
+       <affiliation>
+         <address>
+           <email>awalls@md.metrocast.net</email>
+         </address>
+       </affiliation>
+      </author>
+
+      <author>
+       <firstname>Mauro</firstname>
+       <surname>Carvalho Chehab</surname>
+       <contrib>Documented libv4l, designed and added v4l2grab example,
+Remote Controller chapter.</contrib>
+       <affiliation>
+         <address>
+           <email>mchehab@redhat.com</email>
+         </address>
+       </affiliation>
+      </author>
+
+      <author>
+       <firstname>Muralidharan</firstname>
+       <surname>Karicheri</surname>
+       <contrib>Documented the Digital Video timings API.</contrib>
+       <affiliation>
+         <address>
+           <email>m-karicheri2@ti.com</email>
+         </address>
+       </affiliation>
+      </author>
+
+      <author>
+       <firstname>Pawel</firstname>
+       <surname>Osciak</surname>
+       <contrib>Designed and documented the multi-planar API.</contrib>
+       <affiliation>
+         <address>
+           <email>pawel AT osciak.com</email>
+         </address>
+       </affiliation>
+      </author>
+    </authorgroup>
+
+    <copyright>
+      <year>1999</year>
+      <year>2000</year>
+      <year>2001</year>
+      <year>2002</year>
+      <year>2003</year>
+      <year>2004</year>
+      <year>2005</year>
+      <year>2006</year>
+      <year>2007</year>
+      <year>2008</year>
+      <year>2009</year>
+      <year>2010</year>
+      <year>2011</year>
+      <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
+Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
+       Pawel Osciak</holder>
+    </copyright>
+    <legalnotice>
+    <para>Except when explicitly stated as GPL, programming examples within
+           this part can be used and distributed without restrictions.</para>
+    </legalnotice>
+    <revhistory>
+      <!-- Put document revisions here, newest first. -->
+      <!-- API revisions (changes and additions of defines, enums,
+structs, ioctls) must be noted in more detail in the history chapter
+(compat.xml), along with the possible impact on existing drivers and
+applications. -->
+
+      <revision>
+       <revnumber>3.1</revnumber>
+       <date>2011-06-27</date>
+       <authorinitials>mcc, po, hv</authorinitials>
+       <revremark>Documented that VIDIOC_QUERYCAP now returns a per-subsystem version instead of a per-driver one.
+                  Standardize an error code for invalid ioctl.
+                  Added V4L2_CTRL_TYPE_BITMASK.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>2.6.39</revnumber>
+       <date>2011-03-01</date>
+       <authorinitials>mcc, po</authorinitials>
+       <revremark>Removed VIDIOC_*_OLD from videodev2.h header and update it to reflect latest changes. Added the <link linkend="planar-apis">multi-planar API</link>.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>2.6.37</revnumber>
+       <date>2010-08-06</date>
+       <authorinitials>hv</authorinitials>
+       <revremark>Removed obsolete vtx (videotext) API.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>2.6.33</revnumber>
+       <date>2009-12-03</date>
+       <authorinitials>mk</authorinitials>
+       <revremark>Added documentation for the Digital Video timings API.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>2.6.32</revnumber>
+       <date>2009-08-31</date>
+       <authorinitials>mcc</authorinitials>
+       <revremark>Now, revisions will match the kernel version where
+the V4L2 API changes will be used by the Linux Kernel.
+Also added Remote Controller chapter.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.29</revnumber>
+       <date>2009-08-26</date>
+       <authorinitials>ev</authorinitials>
+       <revremark>Added documentation for string controls and for FM Transmitter controls.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.28</revnumber>
+       <date>2009-08-26</date>
+       <authorinitials>gl</authorinitials>
+       <revremark>Added V4L2_CID_BAND_STOP_FILTER documentation.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.27</revnumber>
+       <date>2009-08-15</date>
+       <authorinitials>mcc</authorinitials>
+       <revremark>Added libv4l and Remote Controller documentation;
+added v4l2grab and keytable application examples.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.26</revnumber>
+       <date>2009-07-23</date>
+       <authorinitials>hv</authorinitials>
+       <revremark>Finalized the RDS capture API. Added modulator and RDS encoder
+capabilities. Added support for string controls.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.25</revnumber>
+       <date>2009-01-18</date>
+       <authorinitials>hv</authorinitials>
+       <revremark>Added pixel formats VYUY, NV16 and NV61, and changed
+the debug ioctls VIDIOC_DBG_G/S_REGISTER and VIDIOC_DBG_G_CHIP_IDENT.
+Added camera controls V4L2_CID_ZOOM_ABSOLUTE, V4L2_CID_ZOOM_RELATIVE,
+V4L2_CID_ZOOM_CONTINUOUS and V4L2_CID_PRIVACY.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.24</revnumber>
+       <date>2008-03-04</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Added pixel formats Y16 and SBGGR16, new controls
+and a camera controls class. Removed VIDIOC_G/S_MPEGCOMP.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.23</revnumber>
+       <date>2007-08-30</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Fixed a typo in VIDIOC_DBG_G/S_REGISTER.
+Clarified the byte order of packed pixel formats.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.22</revnumber>
+       <date>2007-08-29</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Added the Video Output Overlay interface, new MPEG
+controls, V4L2_FIELD_INTERLACED_TB and V4L2_FIELD_INTERLACED_BT,
+VIDIOC_DBG_G/S_REGISTER, VIDIOC_(TRY_)ENCODER_CMD,
+VIDIOC_G_CHIP_IDENT, VIDIOC_G_ENC_INDEX, new pixel formats.
+Clarifications in the cropping chapter, about RGB pixel formats, the
+mmap(), poll(), select(), read() and write() functions. Typographical
+fixes.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.21</revnumber>
+       <date>2006-12-19</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Fixed a link in the VIDIOC_G_EXT_CTRLS section.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.20</revnumber>
+       <date>2006-11-24</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Clarified the purpose of the audioset field in
+struct v4l2_input and v4l2_output.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.19</revnumber>
+       <date>2006-10-19</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Documented V4L2_PIX_FMT_RGB444.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.18</revnumber>
+       <date>2006-10-18</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Added the description of extended controls by Hans
+Verkuil. Linked V4L2_PIX_FMT_MPEG to V4L2_CID_MPEG_STREAM_TYPE.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.17</revnumber>
+       <date>2006-10-12</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Corrected V4L2_PIX_FMT_HM12 description.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.16</revnumber>
+       <date>2006-10-08</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>VIDIOC_ENUM_FRAMESIZES and
+VIDIOC_ENUM_FRAMEINTERVALS are now part of the API.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.15</revnumber>
+       <date>2006-09-23</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Cleaned up the bibliography, added BT.653 and
+BT.1119. capture.c/start_capturing() for user pointer I/O did not
+initialize the buffer index. Documented the V4L MPEG and MJPEG
+VID_TYPEs and V4L2_PIX_FMT_SBGGR8. Updated the list of reserved pixel
+formats. See the history chapter for API changes.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.14</revnumber>
+       <date>2006-09-14</date>
+       <authorinitials>mr</authorinitials>
+       <revremark>Added VIDIOC_ENUM_FRAMESIZES and
+VIDIOC_ENUM_FRAMEINTERVALS proposal for frame format enumeration of
+digital devices.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.13</revnumber>
+       <date>2006-04-07</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Corrected the description of struct v4l2_window
+clips. New V4L2_STD_ and V4L2_TUNER_MODE_LANG1_LANG2
+defines.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.12</revnumber>
+       <date>2006-02-03</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Corrected the description of struct
+v4l2_captureparm and v4l2_outputparm.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.11</revnumber>
+       <date>2006-01-27</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Improved the description of struct
+v4l2_tuner.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.10</revnumber>
+       <date>2006-01-10</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>VIDIOC_G_INPUT and VIDIOC_S_PARM
+clarifications.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.9</revnumber>
+       <date>2005-11-27</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Improved the 525 line numbering diagram. Hans
+Verkuil and I rewrote the sliced VBI section. He also contributed a
+VIDIOC_LOG_STATUS page. Fixed VIDIOC_S_STD call in the video standard
+selection example. Various updates.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.8</revnumber>
+       <date>2004-10-04</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Somehow a piece of junk slipped into the capture
+example, removed.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.7</revnumber>
+       <date>2004-09-19</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Fixed video standard selection, control
+enumeration, downscaling and aspect example. Added read and user
+pointer i/o to video capture example.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.6</revnumber>
+       <date>2004-08-01</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>v4l2_buffer changes, added video capture example,
+various corrections.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.5</revnumber>
+       <date>2003-11-05</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Pixel format erratum.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.4</revnumber>
+       <date>2003-09-17</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Corrected source and Makefile to generate a PDF.
+SGML fixes. Added latest API changes. Closed gaps in the history
+chapter.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.3</revnumber>
+       <date>2003-02-05</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Another draft, more corrections.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.2</revnumber>
+       <date>2003-01-15</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>Second draft, with corrections pointed out by Gerd
+Knorr.</revremark>
+      </revision>
+
+      <revision>
+       <revnumber>0.1</revnumber>
+       <date>2002-12-01</date>
+       <authorinitials>mhs</authorinitials>
+       <revremark>First draft, based on documentation by Bill Dirks
+and discussions on the V4L mailing list.</revremark>
+      </revision>
+    </revhistory>
+</partinfo>
+
+<title>Video for Linux Two API Specification</title>
+ <subtitle>Revision 3.1</subtitle>
+
+  <chapter id="common">
+    &sub-common;
+  </chapter>
+
+  <chapter id="pixfmt">
+    &sub-pixfmt;
+  </chapter>
+
+  <chapter id="io">
+    &sub-io;
+  </chapter>
+
+  <chapter id="devices">
+    <title>Interfaces</title>
+
+    <section id="capture"> &sub-dev-capture; </section>
+    <section id="overlay"> &sub-dev-overlay; </section>
+    <section id="output"> &sub-dev-output; </section>
+    <section id="osd"> &sub-dev-osd; </section>
+    <section id="codec"> &sub-dev-codec; </section>
+    <section id="effect"> &sub-dev-effect; </section>
+    <section id="raw-vbi"> &sub-dev-raw-vbi; </section>
+    <section id="sliced"> &sub-dev-sliced-vbi; </section>
+    <section id="ttx"> &sub-dev-teletext; </section>
+    <section id="radio"> &sub-dev-radio; </section>
+    <section id="rds"> &sub-dev-rds; </section>
+    <section id="event"> &sub-dev-event; </section>
+    <section id="subdev"> &sub-dev-subdev; </section>
+  </chapter>
+
+  <chapter id="driver">
+         &sub-driver;
+  </chapter>
+
+  <chapter id="libv4l">
+         &sub-libv4l;
+  </chapter>
+
+  <chapter id="compat">
+         &sub-compat;
+  </chapter>
+
+  <appendix id="user-func">
+  <title>Function Reference</title>
+
+    <!-- Keep this alphabetically sorted. -->
+
+    &sub-close;
+    &sub-ioctl;
+    <!-- All ioctls go here. -->
+    &sub-cropcap;
+    &sub-dbg-g-chip-ident;
+    &sub-dbg-g-register;
+    &sub-dqevent;
+    &sub-encoder-cmd;
+    &sub-enumaudio;
+    &sub-enumaudioout;
+    &sub-enum-dv-presets;
+    &sub-enum-fmt;
+    &sub-enum-framesizes;
+    &sub-enum-frameintervals;
+    &sub-enuminput;
+    &sub-enumoutput;
+    &sub-enumstd;
+    &sub-g-audio;
+    &sub-g-audioout;
+    &sub-g-crop;
+    &sub-g-ctrl;
+    &sub-g-dv-preset;
+    &sub-g-dv-timings;
+    &sub-g-enc-index;
+    &sub-g-ext-ctrls;
+    &sub-g-fbuf;
+    &sub-g-fmt;
+    &sub-g-frequency;
+    &sub-g-input;
+    &sub-g-jpegcomp;
+    &sub-g-modulator;
+    &sub-g-output;
+    &sub-g-parm;
+    &sub-g-priority;
+    &sub-g-sliced-vbi-cap;
+    &sub-g-std;
+    &sub-g-tuner;
+    &sub-log-status;
+    &sub-overlay;
+    &sub-qbuf;
+    &sub-querybuf;
+    &sub-querycap;
+    &sub-queryctrl;
+    &sub-query-dv-preset;
+    &sub-querystd;
+    &sub-reqbufs;
+    &sub-s-hw-freq-seek;
+    &sub-streamon;
+    &sub-subdev-enum-frame-interval;
+    &sub-subdev-enum-frame-size;
+    &sub-subdev-enum-mbus-code;
+    &sub-subdev-g-crop;
+    &sub-subdev-g-fmt;
+    &sub-subdev-g-frame-interval;
+    &sub-subscribe-event;
+    <!-- End of ioctls. -->
+    &sub-mmap;
+    &sub-munmap;
+    &sub-open;
+    &sub-poll;
+    &sub-read;
+    &sub-select;
+    &sub-write;
+  </appendix>
+
+  <appendix id="videodev">
+    <title>Video For Linux Two Header File</title>
+    &sub-videodev2-h;
+  </appendix>
+
+  <appendix id="capture-example">
+    <title>Video Capture Example</title>
+    &sub-capture-c;
+  </appendix>
+
+  <appendix id="v4l2grab-example">
+    <title>Video Grabber example using libv4l</title>
+    <para>This program demonstrates how to grab V4L2 images in ppm format by
+using libv4l handlers. The advantage is that this grabber can potentially work
+with any V4L2 driver.</para>
+    &sub-v4l2grab-c;
+  </appendix>
+
+  &sub-media-indices;
+
+  &sub-biblio;
+
diff --git a/Documentation/DocBook/media/v4l/v4l2grab.c.xml b/Documentation/DocBook/media/v4l/v4l2grab.c.xml
new file mode 100644 (file)
index 0000000..bed12e4
--- /dev/null
@@ -0,0 +1,164 @@
+<programlisting>
+/* V4L2 video picture grabber
+   Copyright (C) 2009 Mauro Carvalho Chehab &lt;mchehab@infradead.org&gt;
+
+   This 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.
+ */
+
+#include &lt;stdio.h&gt;
+#include &lt;stdlib.h&gt;
+#include &lt;string.h&gt;
+#include &lt;fcntl.h&gt;
+#include &lt;errno.h&gt;
+#include &lt;sys/ioctl.h&gt;
+#include &lt;sys/types.h&gt;
+#include &lt;sys/time.h&gt;
+#include &lt;sys/mman.h&gt;
+#include &lt;linux/videodev2.h&gt;
+#include "../libv4l/include/libv4l2.h"
+
+#define CLEAR(x) memset(&amp;(x), 0, sizeof(x))
+
+struct buffer {
+        void   *start;
+        size_t length;
+};
+
+static void xioctl(int fh, int request, void *arg)
+{
+        int r;
+
+        do {
+                r = v4l2_ioctl(fh, request, arg);
+        } while (r == -1 &amp;&amp; ((errno == EINTR) || (errno == EAGAIN)));
+
+        if (r == -1) {
+                fprintf(stderr, "error %d, %s\n", errno, strerror(errno));
+                exit(EXIT_FAILURE);
+        }
+}
+
+int main(int argc, char **argv)
+{
+        struct <link linkend="v4l2-format">v4l2_format</link>              fmt;
+        struct <link linkend="v4l2-buffer">v4l2_buffer</link>              buf;
+        struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link>      req;
+        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>              type;
+        fd_set                          fds;
+        struct timeval                  tv;
+        int                             r, fd = -1;
+        unsigned int                    i, n_buffers;
+        char                            *dev_name = "/dev/video0";
+        char                            out_name[256];
+        FILE                            *fout;
+        struct buffer                   *buffers;
+
+        fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
+        if (fd &lt; 0) {
+                perror("Cannot open device");
+                exit(EXIT_FAILURE);
+        }
+
+        CLEAR(fmt);
+        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        fmt.fmt.pix.width       = 640;
+        fmt.fmt.pix.height      = 480;
+        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
+        xioctl(fd, VIDIOC_S_FMT, &amp;fmt);
+        if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) {
+                printf("Libv4l didn't accept RGB24 format. Can't proceed.\n");
+                exit(EXIT_FAILURE);
+        }
+        if ((fmt.fmt.pix.width != 640) || (fmt.fmt.pix.height != 480))
+                printf("Warning: driver is sending image at %dx%d\n",
+                        fmt.fmt.pix.width, fmt.fmt.pix.height);
+
+        CLEAR(req);
+        req.count = 2;
+        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        req.memory = V4L2_MEMORY_MMAP;
+        xioctl(fd, VIDIOC_REQBUFS, &amp;req);
+
+        buffers = calloc(req.count, sizeof(*buffers));
+        for (n_buffers = 0; n_buffers &lt; req.count; ++n_buffers) {
+                CLEAR(buf);
+
+                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory      = V4L2_MEMORY_MMAP;
+                buf.index       = n_buffers;
+
+                xioctl(fd, VIDIOC_QUERYBUF, &amp;buf);
+
+                buffers[n_buffers].length = buf.length;
+                buffers[n_buffers].start = v4l2_mmap(NULL, buf.length,
+                              PROT_READ | PROT_WRITE, MAP_SHARED,
+                              fd, buf.m.offset);
+
+                if (MAP_FAILED == buffers[n_buffers].start) {
+                        perror("mmap");
+                        exit(EXIT_FAILURE);
+                }
+        }
+
+        for (i = 0; i &lt; n_buffers; ++i) {
+                CLEAR(buf);
+                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory = V4L2_MEMORY_MMAP;
+                buf.index = i;
+                xioctl(fd, VIDIOC_QBUF, &amp;buf);
+        }
+        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+        xioctl(fd, VIDIOC_STREAMON, &amp;type);
+        for (i = 0; i &lt; 20; i++) {
+                do {
+                        FD_ZERO(&amp;fds);
+                        FD_SET(fd, &amp;fds);
+
+                        /* Timeout. */
+                        tv.tv_sec = 2;
+                        tv.tv_usec = 0;
+
+                        r = select(fd + 1, &amp;fds, NULL, NULL, &amp;tv);
+                } while ((r == -1 &amp;&amp; (errno = EINTR)));
+                if (r == -1) {
+                        perror("select");
+                        return errno;
+                }
+
+                CLEAR(buf);
+                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                buf.memory = V4L2_MEMORY_MMAP;
+                xioctl(fd, VIDIOC_DQBUF, &amp;buf);
+
+                sprintf(out_name, "out%03d.ppm", i);
+                fout = fopen(out_name, "w");
+                if (!fout) {
+                        perror("Cannot open image");
+                        exit(EXIT_FAILURE);
+                }
+                fprintf(fout, "P6\n%d %d 255\n",
+                        fmt.fmt.pix.width, fmt.fmt.pix.height);
+                fwrite(buffers[buf.index].start, buf.bytesused, 1, fout);
+                fclose(fout);
+
+                xioctl(fd, VIDIOC_QBUF, &amp;buf);
+        }
+
+        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        xioctl(fd, VIDIOC_STREAMOFF, &amp;type);
+        for (i = 0; i &lt; n_buffers; ++i)
+                v4l2_munmap(buffers[i].start, buffers[i].length);
+        v4l2_close(fd);
+
+        return 0;
+}
+</programlisting>
diff --git a/Documentation/DocBook/media/v4l/vbi_525.pdf b/Documentation/DocBook/media/v4l/vbi_525.pdf
new file mode 100644 (file)
index 0000000..9e72c25
Binary files /dev/null and b/Documentation/DocBook/media/v4l/vbi_525.pdf differ
diff --git a/Documentation/DocBook/media/v4l/vbi_625.pdf b/Documentation/DocBook/media/v4l/vbi_625.pdf
new file mode 100644 (file)
index 0000000..765235e
Binary files /dev/null and b/Documentation/DocBook/media/v4l/vbi_625.pdf differ
diff --git a/Documentation/DocBook/media/v4l/vbi_hsync.pdf b/Documentation/DocBook/media/v4l/vbi_hsync.pdf
new file mode 100644 (file)
index 0000000..200b668
Binary files /dev/null and b/Documentation/DocBook/media/v4l/vbi_hsync.pdf differ
diff --git a/Documentation/DocBook/media/v4l/vidioc-cropcap.xml b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml
new file mode 100644 (file)
index 0000000..b4f2f25
--- /dev/null
@@ -0,0 +1,165 @@
+<refentry id="vidioc-cropcap">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_CROPCAP</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_CROPCAP</refname>
+    <refpurpose>Information about the video cropping and scaling abilities</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_cropcap
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_CROPCAP</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Applications use this function to query the cropping
+limits, the pixel aspect of images and to calculate scale factors.
+They set the <structfield>type</structfield> field of a v4l2_cropcap
+structure to the respective buffer (stream) type and call the
+<constant>VIDIOC_CROPCAP</constant> ioctl with a pointer to this
+structure. Drivers fill the rest of the structure. The results are
+constant except when switching the video standard. Remember this
+switch can occur implicit when switching the video input or
+output.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-cropcap">
+      <title>struct <structname>v4l2_cropcap</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>&v4l2-buf-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the data stream, set by the application.
+Only these types are valid here:
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
+defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
+and higher.</entry>
+         </row>
+         <row>
+           <entry>struct <link linkend="v4l2-rect-crop">v4l2_rect</link></entry>
+           <entry><structfield>bounds</structfield></entry>
+           <entry>Defines the window within capturing or output is
+possible, this may exclude for example the horizontal and vertical
+blanking areas. The cropping rectangle cannot exceed these limits.
+Width and height are defined in pixels, the driver writer is free to
+choose origin and units of the coordinate system in the analog
+domain.</entry>
+         </row>
+         <row>
+           <entry>struct <link linkend="v4l2-rect-crop">v4l2_rect</link></entry>
+           <entry><structfield>defrect</structfield></entry>
+           <entry>Default cropping rectangle, it shall cover the
+"whole picture". Assuming pixel aspect 1/1 this could be for example a
+640&nbsp;&times;&nbsp;480 rectangle for NTSC, a
+768&nbsp;&times;&nbsp;576 rectangle for PAL and SECAM centered over
+the active picture area. The same co-ordinate system as for
+           <structfield>bounds</structfield> is used.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>pixelaspect</structfield></entry>
+           <entry><para>This is the pixel aspect (y / x) when no
+scaling is applied, the ratio of the actual sampling
+frequency and the frequency required to get square
+pixels.</para><para>When cropping coordinates refer to square pixels,
+the driver sets <structfield>pixelaspect</structfield> to 1/1. Other
+common values are 54/59 for PAL and SECAM, 11/10 for NTSC sampled
+according to [<xref linkend="itu601" />].</para></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <!-- NB this table is duplicated in the overlay chapter. -->
+
+    <table pgwide="1" frame="none" id="v4l2-rect-crop">
+      <title>struct <structname>v4l2_rect</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>left</structfield></entry>
+           <entry>Horizontal offset of the top, left corner of the
+rectangle, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>top</structfield></entry>
+           <entry>Vertical offset of the top, left corner of the
+rectangle, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>width</structfield></entry>
+           <entry>Width of the rectangle, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>height</structfield></entry>
+           <entry>Height of the rectangle, in pixels. Width
+and height cannot be negative, the fields are signed for
+hysterical reasons. <!-- video4linux-list@redhat.com
+on 22 Oct 2002 subject "Re:[V4L][patches!] Re:v4l2/kernel-2.5" -->
+</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-cropcap; <structfield>type</structfield> is
+invalid. This is not permitted for video capture, output and overlay devices,
+which must support <constant>VIDIOC_CROPCAP</constant>.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml
new file mode 100644 (file)
index 0000000..4ecd966
--- /dev/null
@@ -0,0 +1,266 @@
+<refentry id="vidioc-dbg-g-chip-ident">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_DBG_G_CHIP_IDENT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_DBG_G_CHIP_IDENT</refname>
+    <refpurpose>Identify the chips on a TV card</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_dbg_chip_ident
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_DBG_G_CHIP_IDENT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+
+      <para>This is an <link
+linkend="experimental">experimental</link> interface and may change in
+the future.</para>
+    </note>
+
+    <para>For driver debugging purposes this ioctl allows test
+applications to query the driver about the chips present on the TV
+card. Regular applications must not use it. When you found a chip
+specific bug, please contact the linux-media mailing list (&v4l-ml;)
+so it can be fixed.</para>
+
+    <para>To query the driver applications must initialize the
+<structfield>match.type</structfield> and
+<structfield>match.addr</structfield> or <structfield>match.name</structfield>
+fields of a &v4l2-dbg-chip-ident;
+and call <constant>VIDIOC_DBG_G_CHIP_IDENT</constant> with a pointer to
+this structure. On success the driver stores information about the
+selected chip in the <structfield>ident</structfield> and
+<structfield>revision</structfield> fields. On failure the structure
+remains unchanged.</para>
+
+    <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_HOST</constant>,
+<structfield>match.addr</structfield> selects the nth non-&i2c; chip
+on the TV card. You can enumerate all chips by starting at zero and
+incrementing <structfield>match.addr</structfield> by one until
+<constant>VIDIOC_DBG_G_CHIP_IDENT</constant> fails with an &EINVAL;.
+The number zero always selects the host chip, &eg; the chip connected
+to the PCI or USB bus.</para>
+
+    <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant>,
+<structfield>match.name</structfield> contains the I2C driver name.
+For instance
+<constant>"saa7127"</constant> will match any chip
+supported by the saa7127 driver, regardless of its &i2c; bus address.
+When multiple chips supported by the same driver are present, the
+ioctl will return <constant>V4L2_IDENT_AMBIGUOUS</constant> in the
+<structfield>ident</structfield> field.</para>
+
+    <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_I2C_ADDR</constant>,
+<structfield>match.addr</structfield> selects a chip by its 7 bit
+&i2c; bus address.</para>
+
+    <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_AC97</constant>,
+<structfield>match.addr</structfield> selects the nth AC97 chip
+on the TV card. You can enumerate all chips by starting at zero and
+incrementing <structfield>match.addr</structfield> by one until
+<constant>VIDIOC_DBG_G_CHIP_IDENT</constant> fails with an &EINVAL;.</para>
+
+    <para>On success, the <structfield>ident</structfield> field will
+contain a chip ID from the Linux
+<filename>media/v4l2-chip-ident.h</filename> header file, and the
+<structfield>revision</structfield> field will contain a driver
+specific value, or zero if no particular revision is associated with
+this chip.</para>
+
+    <para>When the driver could not identify the selected chip,
+<structfield>ident</structfield> will contain
+<constant>V4L2_IDENT_UNKNOWN</constant>. When no chip matched
+the ioctl will succeed but the
+<structfield>ident</structfield> field will contain
+<constant>V4L2_IDENT_NONE</constant>. If multiple chips matched,
+<structfield>ident</structfield> will contain
+<constant>V4L2_IDENT_AMBIGUOUS</constant>. In all these cases the
+<structfield>revision</structfield> field remains unchanged.</para>
+
+    <para>This ioctl is optional, not all drivers may support it. It
+was introduced in Linux 2.6.21, but the API was changed to the
+one described here in 2.6.29.</para>
+
+    <para>We recommended the <application>v4l2-dbg</application>
+utility over calling this ioctl directly. It is available from the
+LinuxTV v4l-dvb repository; see <ulink
+url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
+access instructions.</para>
+
+    <!-- Note for convenience vidioc-dbg-g-register.sgml
+        contains a duplicate of this table. -->
+    <table pgwide="1" frame="none" id="ident-v4l2-dbg-match">
+      <title>struct <structname>v4l2_dbg_match</structname></title>
+      <tgroup cols="4">
+       &cs-ustr;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>See <xref linkend="ident-chip-match-types" /> for a list of
+possible types.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry>(anonymous)</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>addr</structfield></entry>
+           <entry>Match a chip by this number, interpreted according
+to the <structfield>type</structfield> field.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>char</entry>
+           <entry><structfield>name[32]</structfield></entry>
+           <entry>Match a chip by this name, interpreted according
+to the <structfield>type</structfield> field.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-dbg-chip-ident">
+      <title>struct <structname>v4l2_dbg_chip_ident</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>struct v4l2_dbg_match</entry>
+           <entry><structfield>match</structfield></entry>
+           <entry>How to match the chip, see <xref linkend="ident-v4l2-dbg-match" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>ident</structfield></entry>
+           <entry>A chip identifier as defined in the Linux
+<filename>media/v4l2-chip-ident.h</filename> header file, or one of
+the values from <xref linkend="chip-ids" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>revision</structfield></entry>
+           <entry>A chip revision, chip and driver specific.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <!-- Note for convenience vidioc-dbg-g-register.sgml
+        contains a duplicate of this table. -->
+    <table pgwide="1" frame="none" id="ident-chip-match-types">
+      <title>Chip Match Types</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_CHIP_MATCH_HOST</constant></entry>
+           <entry>0</entry>
+           <entry>Match the nth chip on the card, zero for the
+           host chip. Does not match &i2c; chips.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant></entry>
+           <entry>1</entry>
+           <entry>Match an &i2c; chip by its driver name.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CHIP_MATCH_I2C_ADDR</constant></entry>
+           <entry>2</entry>
+           <entry>Match a chip by its 7 bit &i2c; bus address.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CHIP_MATCH_AC97</constant></entry>
+           <entry>3</entry>
+           <entry>Match the nth anciliary AC97 chip.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <!-- This is an anonymous enum in media/v4l2-chip-ident.h. -->
+    <table pgwide="1" frame="none" id="chip-ids">
+      <title>Chip Identifiers</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_IDENT_NONE</constant></entry>
+           <entry>0</entry>
+           <entry>No chip matched.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IDENT_AMBIGUOUS</constant></entry>
+           <entry>1</entry>
+           <entry>Multiple chips matched.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IDENT_UNKNOWN</constant></entry>
+           <entry>2</entry>
+           <entry>A chip is present at this address, but the driver
+could not identify it.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <structfield>match_type</structfield> is invalid.</para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml
new file mode 100644 (file)
index 0000000..a44aebc
--- /dev/null
@@ -0,0 +1,258 @@
+<refentry id="vidioc-dbg-g-register">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_DBG_G_REGISTER</refname>
+    <refname>VIDIOC_DBG_S_REGISTER</refname>
+    <refpurpose>Read or write hardware registers</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_dbg_register *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const struct v4l2_dbg_register
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+
+      <para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+    </note>
+
+    <para>For driver debugging purposes these ioctls allow test
+applications to access hardware registers directly. Regular
+applications must not use them.</para>
+
+    <para>Since writing or even reading registers can jeopardize the
+system security, its stability and damage the hardware, both ioctls
+require superuser privileges. Additionally the Linux kernel must be
+compiled with the <constant>CONFIG_VIDEO_ADV_DEBUG</constant> option
+to enable these ioctls.</para>
+
+    <para>To write a register applications must initialize all fields
+of a &v4l2-dbg-register; and call
+<constant>VIDIOC_DBG_S_REGISTER</constant> with a pointer to this
+structure. The <structfield>match.type</structfield> and
+<structfield>match.addr</structfield> or <structfield>match.name</structfield>
+fields select a chip on the TV
+card, the <structfield>reg</structfield> field specifies a register
+number and the <structfield>val</structfield> field the value to be
+written into the register.</para>
+
+    <para>To read a register applications must initialize the
+<structfield>match.type</structfield>,
+<structfield>match.chip</structfield> or <structfield>match.name</structfield> and
+<structfield>reg</structfield> fields, and call
+<constant>VIDIOC_DBG_G_REGISTER</constant> with a pointer to this
+structure. On success the driver stores the register value in the
+<structfield>val</structfield> field. On failure the structure remains
+unchanged.</para>
+
+    <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_HOST</constant>,
+<structfield>match.addr</structfield> selects the nth non-&i2c; chip
+on the TV card.  The number zero always selects the host chip, &eg; the
+chip connected to the PCI or USB bus. You can find out which chips are
+present with the &VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
+
+    <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant>,
+<structfield>match.name</structfield> contains the I2C driver name.
+For instance
+<constant>"saa7127"</constant> will match any chip
+supported by the saa7127 driver, regardless of its &i2c; bus address.
+When multiple chips supported by the same driver are present, the
+effect of these ioctls is undefined. Again with the
+&VIDIOC-DBG-G-CHIP-IDENT; ioctl you can find out which &i2c; chips are
+present.</para>
+
+    <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_I2C_ADDR</constant>,
+<structfield>match.addr</structfield> selects a chip by its 7 bit &i2c;
+bus address.</para>
+
+    <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_AC97</constant>,
+<structfield>match.addr</structfield> selects the nth AC97 chip
+on the TV card.</para>
+
+    <note>
+      <title>Success not guaranteed</title>
+
+      <para>Due to a flaw in the Linux &i2c; bus driver these ioctls may
+return successfully without actually reading or writing a register. To
+catch the most likely failure we recommend a &VIDIOC-DBG-G-CHIP-IDENT;
+call confirming the presence of the selected &i2c; chip.</para>
+    </note>
+
+    <para>These ioctls are optional, not all drivers may support them.
+However when a driver supports these ioctls it must also support
+&VIDIOC-DBG-G-CHIP-IDENT;. Conversely it may support
+<constant>VIDIOC_DBG_G_CHIP_IDENT</constant> but not these ioctls.</para>
+
+    <para><constant>VIDIOC_DBG_G_REGISTER</constant> and
+<constant>VIDIOC_DBG_S_REGISTER</constant> were introduced in Linux
+2.6.21, but their API was changed to the one described here in kernel 2.6.29.</para>
+
+    <para>We recommended the <application>v4l2-dbg</application>
+utility over calling these ioctls directly. It is available from the
+LinuxTV v4l-dvb repository; see <ulink
+url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
+access instructions.</para>
+
+    <!-- Note for convenience vidioc-dbg-g-chip-ident.sgml
+        contains a duplicate of this table. -->
+    <table pgwide="1" frame="none" id="v4l2-dbg-match">
+      <title>struct <structname>v4l2_dbg_match</structname></title>
+      <tgroup cols="4">
+       &cs-ustr;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>See <xref linkend="ident-chip-match-types" /> for a list of
+possible types.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry>(anonymous)</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>addr</structfield></entry>
+           <entry>Match a chip by this number, interpreted according
+to the <structfield>type</structfield> field.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>char</entry>
+           <entry><structfield>name[32]</structfield></entry>
+           <entry>Match a chip by this name, interpreted according
+to the <structfield>type</structfield> field.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+
+    <table pgwide="1" frame="none" id="v4l2-dbg-register">
+      <title>struct <structname>v4l2_dbg_register</structname></title>
+      <tgroup cols="4">
+       <colspec colname="c1" />
+       <colspec colname="c2" />
+       <colspec colname="c4" />
+       <tbody valign="top">
+         <row>
+           <entry>struct v4l2_dbg_match</entry>
+           <entry><structfield>match</structfield></entry>
+           <entry>How to match the chip, see <xref linkend="v4l2-dbg-match" />.</entry>
+         </row>
+         <row>
+           <entry>__u64</entry>
+           <entry><structfield>reg</structfield></entry>
+           <entry>A register number.</entry>
+         </row>
+         <row>
+           <entry>__u64</entry>
+           <entry><structfield>val</structfield></entry>
+           <entry>The value read from, or to be written into the
+register.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <!-- Note for convenience vidioc-dbg-g-chip-ident.sgml
+        contains a duplicate of this table. -->
+    <table pgwide="1" frame="none" id="chip-match-types">
+      <title>Chip Match Types</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_CHIP_MATCH_HOST</constant></entry>
+           <entry>0</entry>
+           <entry>Match the nth chip on the card, zero for the
+           host chip. Does not match &i2c; chips.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant></entry>
+           <entry>1</entry>
+           <entry>Match an &i2c; chip by its driver name.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CHIP_MATCH_I2C_ADDR</constant></entry>
+           <entry>2</entry>
+           <entry>Match a chip by its 7 bit &i2c; bus address.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CHIP_MATCH_AC97</constant></entry>
+           <entry>3</entry>
+           <entry>Match the nth anciliary AC97 chip.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EPERM</errorcode></term>
+       <listitem>
+         <para>Insufficient permissions. Root privileges are required
+to execute these ioctls.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
new file mode 100644 (file)
index 0000000..7769642
--- /dev/null
@@ -0,0 +1,142 @@
+<refentry id="vidioc-dqevent">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_DQEVENT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_DQEVENT</refname>
+    <refpurpose>Dequeue event</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_event
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_DQEVENT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Dequeue an event from a video device. No input is required
+    for this ioctl. All the fields of the &v4l2-event; structure are
+    filled by the driver. The file handle will also receive exceptions
+    which the application may get by e.g. using the select system
+    call.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-event">
+      <title>struct <structname>v4l2_event</structname></title>
+      <tgroup cols="4">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+            <entry></entry>
+           <entry>Type of the event.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry><structfield>u</structfield></entry>
+            <entry></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-event-vsync;</entry>
+            <entry><structfield>vsync</structfield></entry>
+           <entry>Event data for event V4L2_EVENT_VSYNC.
+            </entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-event-ctrl;</entry>
+            <entry><structfield>ctrl</structfield></entry>
+           <entry>Event data for event V4L2_EVENT_CTRL.
+            </entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u8</entry>
+            <entry><structfield>data</structfield>[64]</entry>
+           <entry>Event data. Defined by the event type. The union
+            should be used to define easily accessible type for
+            events.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pending</structfield></entry>
+            <entry></entry>
+           <entry>Number of pending events excluding this one.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>sequence</structfield></entry>
+            <entry></entry>
+           <entry>Event sequence number. The sequence number is
+           incremented for every subscribed event that takes place.
+           If sequence numbers are not contiguous it means that
+           events have been lost.
+           </entry>
+         </row>
+         <row>
+           <entry>struct timespec</entry>
+           <entry><structfield>timestamp</structfield></entry>
+            <entry></entry>
+           <entry>Event timestamp.</entry>
+         </row>
+         <row>
+           <entry>u32</entry>
+           <entry><structfield>id</structfield></entry>
+            <entry></entry>
+           <entry>The ID associated with the event source. If the event does not
+               have an associated ID (this depends on the event type), then this
+               is 0.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[8]</entry>
+            <entry></entry>
+           <entry>Reserved for future extensions. Drivers must set
+           the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml b/Documentation/DocBook/media/v4l/vidioc-encoder-cmd.xml
new file mode 100644 (file)
index 0000000..af7f3f2
--- /dev/null
@@ -0,0 +1,195 @@
+<refentry id="vidioc-encoder-cmd">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENCODER_CMD</refname>
+    <refname>VIDIOC_TRY_ENCODER_CMD</refname>
+    <refpurpose>Execute an encoder command</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_encoder_cmd *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+
+      <para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+    </note>
+
+    <para>These ioctls control an audio/video (usually MPEG-) encoder.
+<constant>VIDIOC_ENCODER_CMD</constant> sends a command to the
+encoder, <constant>VIDIOC_TRY_ENCODER_CMD</constant> can be used to
+try a command without actually executing it.</para>
+
+    <para>To send a command applications must initialize all fields of a
+    &v4l2-encoder-cmd; and call
+    <constant>VIDIOC_ENCODER_CMD</constant> or
+    <constant>VIDIOC_TRY_ENCODER_CMD</constant> with a pointer to this
+    structure.</para>
+
+    <para>The <structfield>cmd</structfield> field must contain the
+command code. The <structfield>flags</structfield> field is currently
+only used by the STOP command and contains one bit: If the
+<constant>V4L2_ENC_CMD_STOP_AT_GOP_END</constant> flag is set,
+encoding will continue until the end of the current <wordasword>Group
+Of Pictures</wordasword>, otherwise it will stop immediately.</para>
+
+    <para>A <function>read</function>() call sends a START command to
+the encoder if it has not been started yet. After a STOP command,
+<function>read</function>() calls will read the remaining data
+buffered by the driver. When the buffer is empty,
+<function>read</function>() will return zero and the next
+<function>read</function>() call will restart the encoder.</para>
+
+    <para>A <function>close</function>() call sends an immediate STOP
+to the encoder, and all buffered data is discarded.</para>
+
+    <para>These ioctls are optional, not all drivers may support
+them. They were introduced in Linux 2.6.21.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-encoder-cmd">
+      <title>struct <structname>v4l2_encoder_cmd</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>cmd</structfield></entry>
+           <entry>The encoder command, see <xref linkend="encoder-cmds" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry>Flags to go with the command, see <xref
+               linkend="encoder-flags" />. If no flags are defined for
+this command, drivers and applications must set this field to
+zero.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>data</structfield>[8]</entry>
+           <entry>Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="encoder-cmds">
+      <title>Encoder Commands</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_ENC_CMD_START</constant></entry>
+           <entry>0</entry>
+           <entry>Start the encoder. When the encoder is already
+running or paused, this command does nothing. No flags are defined for
+this command.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_ENC_CMD_STOP</constant></entry>
+           <entry>1</entry>
+           <entry>Stop the encoder. When the
+<constant>V4L2_ENC_CMD_STOP_AT_GOP_END</constant> flag is set,
+encoding will continue until the end of the current <wordasword>Group
+Of Pictures</wordasword>, otherwise encoding will stop immediately.
+When the encoder is already stopped, this command does
+nothing.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_ENC_CMD_PAUSE</constant></entry>
+           <entry>2</entry>
+           <entry>Pause the encoder. When the encoder has not been
+started yet, the driver will return an &EPERM;. When the encoder is
+already paused, this command does nothing. No flags are defined for
+this command.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_ENC_CMD_RESUME</constant></entry>
+           <entry>3</entry>
+           <entry>Resume encoding after a PAUSE command. When the
+encoder has not been started yet, the driver will return an &EPERM;.
+When the encoder is already running, this command does nothing. No
+flags are defined for this command.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="encoder-flags">
+      <title>Encoder Command Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_ENC_CMD_STOP_AT_GOP_END</constant></entry>
+           <entry>0x0001</entry>
+           <entry>Stop encoding at the end of the current <wordasword>Group Of
+Pictures</wordasword>, rather than immediately.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <structfield>cmd</structfield> field is invalid.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EPERM</errorcode></term>
+       <listitem>
+         <para>The application sent a PAUSE or RESUME command when
+the encoder was not running.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml
new file mode 100644 (file)
index 0000000..1d31427
--- /dev/null
@@ -0,0 +1,238 @@
+<refentry id="vidioc-enum-dv-presets">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUM_DV_PRESETS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUM_DV_PRESETS</refname>
+    <refpurpose>Enumerate supported Digital Video presets</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_dv_enum_preset *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_ENUM_DV_PRESETS</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the attributes of a DV preset, applications initialize the
+<structfield>index</structfield> field and zero the reserved array of &v4l2-dv-enum-preset;
+and call the <constant>VIDIOC_ENUM_DV_PRESETS</constant> ioctl with a pointer to this
+structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all DV Presets supported,
+applications shall begin at index zero, incrementing by one until the
+driver returns <errorcode>EINVAL</errorcode>. Drivers may enumerate a
+different set of DV presets after switching the video input or
+output.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-dv-enum-preset">
+      <title>struct <structname>v4l2_dv_enum_presets</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Number of the DV preset, set by the
+application.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>preset</structfield></entry>
+           <entry>This field identifies one of the DV preset values listed in <xref linkend="v4l2-dv-presets-vals"/>.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>name</structfield>[24]</entry>
+           <entry>Name of the preset, a NUL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is
+intended for the user.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>width</structfield></entry>
+           <entry>Width of the active video in pixels for the DV preset.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>height</structfield></entry>
+           <entry>Height of the active video in lines for the DV preset.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[4]</entry>
+           <entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-dv-presets-vals">
+      <title>struct <structname>DV Presets</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>Preset</entry>
+           <entry>Preset value</entry>
+           <entry>Description</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_INVALID</entry>
+           <entry>0</entry>
+           <entry>Invalid preset value.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_480P59_94</entry>
+           <entry>1</entry>
+           <entry>720x480 progressive video at 59.94 fps as per BT.1362.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_576P50</entry>
+           <entry>2</entry>
+           <entry>720x576 progressive video at 50 fps as per BT.1362.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_720P24</entry>
+           <entry>3</entry>
+           <entry>1280x720 progressive video at 24 fps as per SMPTE 296M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_720P25</entry>
+           <entry>4</entry>
+           <entry>1280x720 progressive video at 25 fps as per SMPTE 296M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_720P30</entry>
+           <entry>5</entry>
+           <entry>1280x720 progressive video at 30 fps as per SMPTE 296M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_720P50</entry>
+           <entry>6</entry>
+           <entry>1280x720 progressive video at 50 fps as per SMPTE 296M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_720P59_94</entry>
+           <entry>7</entry>
+           <entry>1280x720 progressive video at 59.94 fps as per SMPTE 274M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_720P60</entry>
+           <entry>8</entry>
+           <entry>1280x720 progressive video at 60 fps as per SMPTE 274M/296M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_1080I29_97</entry>
+           <entry>9</entry>
+           <entry>1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_1080I30</entry>
+           <entry>10</entry>
+           <entry>1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_1080I25</entry>
+           <entry>11</entry>
+           <entry>1920x1080 interlaced video at 25 fps as per BT.1120.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_1080I50</entry>
+           <entry>12</entry>
+           <entry>1920x1080 interlaced video at 50 fps as per SMPTE 296M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_1080I60</entry>
+           <entry>13</entry>
+           <entry>1920x1080 interlaced video at 60 fps as per SMPTE 296M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_1080P24</entry>
+           <entry>14</entry>
+           <entry>1920x1080 progressive video at 24 fps as per SMPTE 296M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_1080P25</entry>
+           <entry>15</entry>
+           <entry>1920x1080 progressive video at 25 fps as per SMPTE 296M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_1080P30</entry>
+           <entry>16</entry>
+           <entry>1920x1080 progressive video at 30 fps as per SMPTE 296M.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_1080P50</entry>
+           <entry>17</entry>
+           <entry>1920x1080 progressive video at 50 fps as per BT.1120.</entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_1080P60</entry>
+           <entry>18</entry>
+           <entry>1920x1080 progressive video at 60 fps as per BT.1120.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-dv-enum-preset; <structfield>index</structfield>
+is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml
new file mode 100644 (file)
index 0000000..71d373b
--- /dev/null
@@ -0,0 +1,166 @@
+<refentry id="vidioc-enum-fmt">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUM_FMT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUM_FMT</refname>
+    <refpurpose>Enumerate image formats</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_fmtdesc
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_ENUM_FMT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To enumerate image formats applications initialize the
+<structfield>type</structfield> and <structfield>index</structfield>
+field of &v4l2-fmtdesc; and call the
+<constant>VIDIOC_ENUM_FMT</constant> ioctl with a pointer to this
+structure. Drivers fill the rest of the structure or return an
+&EINVAL;. All formats are enumerable by beginning at index zero and
+incrementing by one until <errorcode>EINVAL</errorcode> is
+returned.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-fmtdesc">
+      <title>struct <structname>v4l2_fmtdesc</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Number of the format in the enumeration, set by
+the application. This is in no way related to the <structfield>
+pixelformat</structfield> field.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-buf-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the data stream, set by the application.
+Only these types are valid here:
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
+defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
+and higher.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry>See <xref linkend="fmtdesc-flags" /></entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>description</structfield>[32]</entry>
+           <entry>Description of the format, a NUL-terminated ASCII
+string. This information is intended for the user, for example: "YUV
+4:2:2".</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pixelformat</structfield></entry>
+           <entry>The image format identifier. This is a
+four character code as computed by the v4l2_fourcc()
+macro:</entry>
+         </row>
+         <row>
+           <entry spanname="hspan"><para><programlisting id="v4l2-fourcc">
+#define v4l2_fourcc(a,b,c,d) (((__u32)(a)&lt;&lt;0)|((__u32)(b)&lt;&lt;8)|((__u32)(c)&lt;&lt;16)|((__u32)(d)&lt;&lt;24))
+</programlisting></para><para>Several image formats are already
+defined by this specification in <xref linkend="pixfmt" />. Note these
+codes are not the same as those used in the Windows world.</para></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[4]</entry>
+           <entry>Reserved for future extensions. Drivers must set
+the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="fmtdesc-flags">
+      <title>Image Format Description Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_FMT_FLAG_COMPRESSED</constant></entry>
+           <entry>0x0001</entry>
+           <entry>This is a compressed format.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FMT_FLAG_EMULATED</constant></entry>
+           <entry>0x0002</entry>
+           <entry>This format is not native to the device but emulated
+through software (usually libv4l2), where possible try to use a native format
+instead for better performance.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-fmtdesc; <structfield>type</structfield>
+is not supported or the <structfield>index</structfield> is out of
+bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml b/Documentation/DocBook/media/v4l/vidioc-enum-frameintervals.xml
new file mode 100644 (file)
index 0000000..5fd72c4
--- /dev/null
@@ -0,0 +1,259 @@
+<refentry id="vidioc-enum-frameintervals">
+
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUM_FRAMEINTERVALS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUM_FRAMEINTERVALS</refname>
+    <refpurpose>Enumerate frame intervals</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_frmivalenum *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_ENUM_FRAMEINTERVALS</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para>Pointer to a &v4l2-frmivalenum; structure that
+contains a pixel format and size and receives a frame interval.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>This ioctl allows applications to enumerate all frame
+intervals that the device supports for the given pixel format and
+frame size.</para>
+    <para>The supported pixel formats and frame sizes can be obtained
+by using the &VIDIOC-ENUM-FMT; and &VIDIOC-ENUM-FRAMESIZES;
+functions.</para>
+    <para>The return value and the content of the
+<structfield>v4l2_frmivalenum.type</structfield> field depend on the
+type of frame intervals the device supports. Here are the semantics of
+the function for the different cases:</para>
+    <itemizedlist>
+      <listitem>
+       <para><emphasis role="bold">Discrete:</emphasis> The function
+returns success if the given index value (zero-based) is valid. The
+application should increase the index by one for each call until
+<constant>EINVAL</constant> is returned. The `v4l2_frmivalenum.type`
+field is set to `V4L2_FRMIVAL_TYPE_DISCRETE` by the driver. Of the
+union only the `discrete` member is valid.</para>
+      </listitem>
+      <listitem>
+       <para><emphasis role="bold">Step-wise:</emphasis> The function
+returns success if the given index value is zero and
+<constant>EINVAL</constant> for any other index value. The
+<structfield>v4l2_frmivalenum.type</structfield> field is set to
+<constant>V4L2_FRMIVAL_TYPE_STEPWISE</constant> by the driver. Of the
+union only the <structfield>stepwise</structfield> member is
+valid.</para>
+      </listitem>
+      <listitem>
+       <para><emphasis role="bold">Continuous:</emphasis> This is a
+special case of the step-wise type above. The function returns success
+if the given index value is zero and <constant>EINVAL</constant> for
+any other index value. The
+<structfield>v4l2_frmivalenum.type</structfield> field is set to
+<constant>V4L2_FRMIVAL_TYPE_CONTINUOUS</constant> by the driver. Of
+the union only the <structfield>stepwise</structfield> member is valid
+and the <structfield>step</structfield> value is set to 1.</para>
+      </listitem>
+    </itemizedlist>
+
+    <para>When the application calls the function with index zero, it
+must check the <structfield>type</structfield> field to determine the
+type of frame interval enumeration the device supports. Only for the
+<constant>V4L2_FRMIVAL_TYPE_DISCRETE</constant> type does it make
+sense to increase the index value to receive more frame
+intervals.</para>
+    <para>Note that the order in which the frame intervals are
+returned has no special meaning. In particular does it not say
+anything about potential default frame intervals.</para>
+    <para>Applications can assume that the enumeration data does not
+change without any interaction from the application itself. This means
+that the enumeration data is consistent if the application does not
+perform any other ioctl calls while it runs the frame interval
+enumeration.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Notes</title>
+
+    <itemizedlist>
+      <listitem>
+       <para><emphasis role="bold">Frame intervals and frame
+rates:</emphasis> The V4L2 API uses frame intervals instead of frame
+rates. Given the frame interval the frame rate can be computed as
+follows:<screen>frame_rate = 1 / frame_interval</screen></para>
+      </listitem>
+    </itemizedlist>
+
+  </refsect1>
+
+  <refsect1>
+    <title>Structs</title>
+
+    <para>In the structs below, <emphasis>IN</emphasis> denotes a
+value that has to be filled in by the application,
+<emphasis>OUT</emphasis> denotes values that the driver fills in. The
+application should zero out all members except for the
+<emphasis>IN</emphasis> fields.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-frmival-stepwise">
+      <title>struct <structname>v4l2_frmival_stepwise</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>min</structfield></entry>
+           <entry>Minimum frame interval [s].</entry>
+         </row>
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>max</structfield></entry>
+           <entry>Maximum frame interval [s].</entry>
+         </row>
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>step</structfield></entry>
+           <entry>Frame interval step size [s].</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-frmivalenum">
+      <title>struct <structname>v4l2_frmivalenum</structname></title>
+      <tgroup cols="4">
+       <colspec colname="c1" />
+       <colspec colname="c2" />
+       <colspec colname="c3" />
+       <colspec colname="c4" />
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry></entry>
+           <entry>IN: Index of the given frame interval in the
+enumeration.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pixel_format</structfield></entry>
+           <entry></entry>
+           <entry>IN: Pixel format for which the frame intervals are
+enumerated.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>width</structfield></entry>
+           <entry></entry>
+           <entry>IN: Frame width for which the frame intervals are
+enumerated.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>height</structfield></entry>
+           <entry></entry>
+           <entry>IN: Frame height for which the frame intervals are
+enumerated.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry>OUT: Frame interval type the device supports.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>OUT: Frame interval with the given index.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>discrete</structfield></entry>
+           <entry>Frame interval [s].</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-frmival-stepwise;</entry>
+           <entry><structfield>stepwise</structfield></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved[2]</structfield></entry>
+           <entry></entry>
+           <entry>Reserved space for future use.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    <title>Enums</title>
+
+    <table pgwide="1" frame="none" id="v4l2-frmivaltypes">
+      <title>enum <structname>v4l2_frmivaltypes</structname></title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_FRMIVAL_TYPE_DISCRETE</constant></entry>
+           <entry>1</entry>
+           <entry>Discrete frame interval.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FRMIVAL_TYPE_CONTINUOUS</constant></entry>
+           <entry>2</entry>
+           <entry>Continuous frame interval.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FRMIVAL_TYPE_STEPWISE</constant></entry>
+           <entry>3</entry>
+           <entry>Step-wise defined frame interval.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml b/Documentation/DocBook/media/v4l/vidioc-enum-framesizes.xml
new file mode 100644 (file)
index 0000000..f77a13f
--- /dev/null
@@ -0,0 +1,271 @@
+<refentry id="vidioc-enum-framesizes">
+
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUM_FRAMESIZES</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUM_FRAMESIZES</refname>
+    <refpurpose>Enumerate frame sizes</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_frmsizeenum *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_ENUM_FRAMESIZES</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para>Pointer to a &v4l2-frmsizeenum; that contains an index
+and pixel format and receives a frame width and height.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+
+      <para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+    </note>
+
+    <para>This ioctl allows applications to enumerate all frame sizes
+(&ie; width and height in pixels) that the device supports for the
+given pixel format.</para>
+    <para>The supported pixel formats can be obtained by using the
+&VIDIOC-ENUM-FMT; function.</para>
+    <para>The return value and the content of the
+<structfield>v4l2_frmsizeenum.type</structfield> field depend on the
+type of frame sizes the device supports. Here are the semantics of the
+function for the different cases:</para>
+
+    <itemizedlist>
+      <listitem>
+       <para><emphasis role="bold">Discrete:</emphasis> The function
+returns success if the given index value (zero-based) is valid. The
+application should increase the index by one for each call until
+<constant>EINVAL</constant> is returned. The
+<structfield>v4l2_frmsizeenum.type</structfield> field is set to
+<constant>V4L2_FRMSIZE_TYPE_DISCRETE</constant> by the driver. Of the
+union only the <structfield>discrete</structfield> member is
+valid.</para>
+      </listitem>
+      <listitem>
+       <para><emphasis role="bold">Step-wise:</emphasis> The function
+returns success if the given index value is zero and
+<constant>EINVAL</constant> for any other index value. The
+<structfield>v4l2_frmsizeenum.type</structfield> field is set to
+<constant>V4L2_FRMSIZE_TYPE_STEPWISE</constant> by the driver. Of the
+union only the <structfield>stepwise</structfield> member is
+valid.</para>
+      </listitem>
+      <listitem>
+       <para><emphasis role="bold">Continuous:</emphasis> This is a
+special case of the step-wise type above. The function returns success
+if the given index value is zero and <constant>EINVAL</constant> for
+any other index value. The
+<structfield>v4l2_frmsizeenum.type</structfield> field is set to
+<constant>V4L2_FRMSIZE_TYPE_CONTINUOUS</constant> by the driver. Of
+the union only the <structfield>stepwise</structfield> member is valid
+and the <structfield>step_width</structfield> and
+<structfield>step_height</structfield> values are set to 1.</para>
+      </listitem>
+    </itemizedlist>
+
+    <para>When the application calls the function with index zero, it
+must check the <structfield>type</structfield> field to determine the
+type of frame size enumeration the device supports. Only for the
+<constant>V4L2_FRMSIZE_TYPE_DISCRETE</constant> type does it make
+sense to increase the index value to receive more frame sizes.</para>
+    <para>Note that the order in which the frame sizes are returned
+has no special meaning. In particular does it not say anything about
+potential default format sizes.</para>
+    <para>Applications can assume that the enumeration data does not
+change without any interaction from the application itself. This means
+that the enumeration data is consistent if the application does not
+perform any other ioctl calls while it runs the frame size
+enumeration.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Structs</title>
+
+    <para>In the structs below, <emphasis>IN</emphasis> denotes a
+value that has to be filled in by the application,
+<emphasis>OUT</emphasis> denotes values that the driver fills in. The
+application should zero out all members except for the
+<emphasis>IN</emphasis> fields.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-frmsize-discrete">
+      <title>struct <structname>v4l2_frmsize_discrete</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>width</structfield></entry>
+           <entry>Width of the frame [pixel].</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>height</structfield></entry>
+           <entry>Height of the frame [pixel].</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-frmsize-stepwise">
+      <title>struct <structname>v4l2_frmsize_stepwise</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>min_width</structfield></entry>
+           <entry>Minimum frame width [pixel].</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>max_width</structfield></entry>
+           <entry>Maximum frame width [pixel].</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>step_width</structfield></entry>
+           <entry>Frame width step size [pixel].</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>min_height</structfield></entry>
+           <entry>Minimum frame height [pixel].</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>max_height</structfield></entry>
+           <entry>Maximum frame height [pixel].</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>step_height</structfield></entry>
+           <entry>Frame height step size [pixel].</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-frmsizeenum">
+      <title>struct <structname>v4l2_frmsizeenum</structname></title>
+      <tgroup cols="4">
+       <colspec colname="c1" />
+       <colspec colname="c2" />
+       <colspec colname="c3" />
+       <colspec colname="c4" />
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry></entry>
+           <entry>IN: Index of the given frame size in the enumeration.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pixel_format</structfield></entry>
+           <entry></entry>
+           <entry>IN: Pixel format for which the frame sizes are enumerated.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry>OUT: Frame size type the device supports.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>OUT: Frame size with the given index.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-frmsize-discrete;</entry>
+           <entry><structfield>discrete</structfield></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-frmsize-stepwise;</entry>
+           <entry><structfield>stepwise</structfield></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved[2]</structfield></entry>
+           <entry></entry>
+           <entry>Reserved space for future use.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    <title>Enums</title>
+
+    <table pgwide="1" frame="none" id="v4l2-frmsizetypes">
+      <title>enum <structname>v4l2_frmsizetypes</structname></title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_FRMSIZE_TYPE_DISCRETE</constant></entry>
+           <entry>1</entry>
+           <entry>Discrete frame size.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FRMSIZE_TYPE_CONTINUOUS</constant></entry>
+           <entry>2</entry>
+           <entry>Continuous frame size.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FRMSIZE_TYPE_STEPWISE</constant></entry>
+           <entry>3</entry>
+           <entry>Step-wise defined frame size.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumaudio.xml b/Documentation/DocBook/media/v4l/vidioc-enumaudio.xml
new file mode 100644 (file)
index 0000000..ea816ab
--- /dev/null
@@ -0,0 +1,76 @@
+<refentry id="vidioc-enumaudio">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUMAUDIO</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUMAUDIO</refname>
+    <refpurpose>Enumerate audio inputs</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_audio *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_ENUMAUDIO</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the attributes of an audio input applications
+initialize the <structfield>index</structfield> field and zero out the
+<structfield>reserved</structfield> array of a &v4l2-audio;
+and call the <constant>VIDIOC_ENUMAUDIO</constant> ioctl with a pointer
+to this structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all audio
+inputs applications shall begin at index zero, incrementing by one
+until the driver returns <errorcode>EINVAL</errorcode>.</para>
+
+    <para>See <xref linkend="vidioc-g-audio" /> for a description of
+&v4l2-audio;.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The number of the audio input is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumaudioout.xml b/Documentation/DocBook/media/v4l/vidioc-enumaudioout.xml
new file mode 100644 (file)
index 0000000..2e87ced
--- /dev/null
@@ -0,0 +1,79 @@
+<refentry id="vidioc-enumaudioout">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUMAUDOUT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUMAUDOUT</refname>
+    <refpurpose>Enumerate audio outputs</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_audioout *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_ENUMAUDOUT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the attributes of an audio output applications
+initialize the <structfield>index</structfield> field and zero out the
+<structfield>reserved</structfield> array of a &v4l2-audioout; and
+call the <constant>VIDIOC_G_AUDOUT</constant> ioctl with a pointer
+to this structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all audio
+outputs applications shall begin at index zero, incrementing by one
+until the driver returns <errorcode>EINVAL</errorcode>.</para>
+
+    <para>Note connectors on a TV card to loop back the received audio
+signal to a sound card are not audio outputs in this sense.</para>
+
+    <para>See <xref linkend="vidioc-g-audioout" /> for a description of
+&v4l2-audioout;.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The number of the audio output is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
new file mode 100644 (file)
index 0000000..476fe1d
--- /dev/null
@@ -0,0 +1,321 @@
+<refentry id="vidioc-enuminput">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUMINPUT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUMINPUT</refname>
+    <refpurpose>Enumerate video inputs</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_input
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_ENUMINPUT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the attributes of a video input applications
+initialize the <structfield>index</structfield> field of &v4l2-input;
+and call the <constant>VIDIOC_ENUMINPUT</constant> ioctl with a
+pointer to this structure. Drivers fill the rest of the structure or
+return an &EINVAL; when the index is out of bounds. To enumerate all
+inputs applications shall begin at index zero, incrementing by one
+until the driver returns <errorcode>EINVAL</errorcode>.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-input">
+      <title>struct <structname>v4l2_input</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Identifies the input, set by the
+application.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>name</structfield>[32]</entry>
+           <entry>Name of the video input, a NUL-terminated ASCII
+string, for example: "Vin (Composite 2)". This information is intended
+for the user, preferably the connector label on the device itself.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the input, see <xref
+               linkend="input-type" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>audioset</structfield></entry>
+           <entry><para>Drivers can enumerate up to 32 video and
+audio inputs. This field shows which audio inputs were selectable as
+audio source if this was the currently selected video input. It is a
+bit mask. The LSB corresponds to audio input 0, the MSB to input 31.
+Any number of bits can be set, or none.</para><para>When the driver
+does not enumerate audio inputs no bits must be set. Applications
+shall not interpret this as lack of audio support. Some drivers
+automatically select audio sources and do not enumerate them since
+there is no choice anyway.</para><para>For details on audio inputs and
+how to select the current input see <xref
+                 linkend="audio" />.</para></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>tuner</structfield></entry>
+           <entry>Capture devices can have zero or more tuners (RF
+demodulators). When the <structfield>type</structfield> is set to
+<constant>V4L2_INPUT_TYPE_TUNER</constant> this is an RF connector and
+this field identifies the tuner. It corresponds to
+&v4l2-tuner; field <structfield>index</structfield>. For details on
+tuners see <xref linkend="tuner" />.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-std-id;</entry>
+           <entry><structfield>std</structfield></entry>
+           <entry>Every video input supports one or more different
+video standards. This field is a set of all supported standards. For
+details on video standards and how to switch see <xref
+linkend="standard" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>status</structfield></entry>
+           <entry>This field provides status information about the
+input. See <xref linkend="input-status" /> for flags.
+With the exception of the sensor orientation bits <structfield>status</structfield> is only valid when this is the
+current input.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capabilities</structfield></entry>
+           <entry>This field provides capabilities for the
+input. See <xref linkend="input-capabilities" /> for flags.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[3]</entry>
+           <entry>Reserved for future extensions. Drivers must set
+the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="input-type">
+      <title>Input Types</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_INPUT_TYPE_TUNER</constant></entry>
+           <entry>1</entry>
+           <entry>This input uses a tuner (RF demodulator).</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_INPUT_TYPE_CAMERA</constant></entry>
+           <entry>2</entry>
+           <entry>Analog baseband input, for example CVBS /
+Composite Video, S-Video, RGB.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <!-- Status flags based on proposal by Mark McClelland,
+video4linux-list@redhat.com on 18 Oct 2002, subject "Re: [V4L] Re:
+v4l2 api". "Why are some of them inverted? So that the driver doesn't
+have to lie about the status in cases where it can't tell one way or
+the other. Plus, a status of zero would generally mean that everything
+is OK." -->
+
+    <table frame="none" pgwide="1" id="input-status">
+      <title>Input Status Flags</title>
+      <tgroup cols="3">
+       <colspec colname="c1" />
+       <colspec colname="c2" align="center" />
+       <colspec colname="c3" />
+       <spanspec namest="c1" nameend="c3" spanname="hspan"
+         align="left" />
+       <tbody valign="top">
+         <row>
+           <entry spanname="hspan">General</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_NO_POWER</constant></entry>
+           <entry>0x00000001</entry>
+           <entry>Attached device is off.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_NO_SIGNAL</constant></entry>
+           <entry>0x00000002</entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_NO_COLOR</constant></entry>
+           <entry>0x00000004</entry>
+           <entry>The hardware supports color decoding, but does not
+detect color modulation in the signal.</entry>
+         </row>
+         <row>
+           <entry spanname="hspan">Sensor Orientation</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_HFLIP</constant></entry>
+           <entry>0x00000010</entry>
+           <entry>The input is connected to a device that produces a signal
+that is flipped horizontally and does not correct this before passing the
+signal to userspace.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_VFLIP</constant></entry>
+           <entry>0x00000020</entry>
+           <entry>The input is connected to a device that produces a signal
+that is flipped vertically and does not correct this before passing the
+signal to userspace. Note that a 180 degree rotation is the same as HFLIP | VFLIP</entry>
+         </row>
+         <row>
+           <entry spanname="hspan">Analog Video</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_NO_H_LOCK</constant></entry>
+           <entry>0x00000100</entry>
+           <entry>No horizontal sync lock.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_COLOR_KILL</constant></entry>
+           <entry>0x00000200</entry>
+           <entry>A color killer circuit automatically disables color
+decoding when it detects no color modulation. When this flag is set
+the color killer is enabled <emphasis>and</emphasis> has shut off
+color decoding.</entry>
+         </row>
+         <row>
+           <entry spanname="hspan">Digital Video</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_NO_SYNC</constant></entry>
+           <entry>0x00010000</entry>
+           <entry>No synchronization lock.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_NO_EQU</constant></entry>
+           <entry>0x00020000</entry>
+           <entry>No equalizer lock.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_NO_CARRIER</constant></entry>
+           <entry>0x00040000</entry>
+           <entry>Carrier recovery failed.</entry>
+         </row>
+         <row>
+           <entry spanname="hspan">VCR and Set-Top Box</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_MACROVISION</constant></entry>
+           <entry>0x01000000</entry>
+           <entry>Macrovision is an analog copy prevention system
+mangling the video signal to confuse video recorders. When this
+flag is set Macrovision has been detected.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_NO_ACCESS</constant></entry>
+           <entry>0x02000000</entry>
+           <entry>Conditional access denied.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_ST_VTR</constant></entry>
+           <entry>0x04000000</entry>
+           <entry>VTR time constant. [?]</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <!-- Capability flags based on video timings RFC by Muralidharan
+Karicheri, titled RFC (v1.2): V4L - Support for video timings at the
+input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
+       -->
+    <table frame="none" pgwide="1" id="input-capabilities">
+      <title>Input capabilities</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_IN_CAP_PRESETS</constant></entry>
+           <entry>0x00000001</entry>
+           <entry>This input supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_CAP_CUSTOM_TIMINGS</constant></entry>
+           <entry>0x00000002</entry>
+           <entry>This input supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_IN_CAP_STD</constant></entry>
+           <entry>0x00000004</entry>
+           <entry>This input supports setting the TV standard by using VIDIOC_S_STD.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-input; <structfield>index</structfield> is
+out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
new file mode 100644 (file)
index 0000000..a281d26
--- /dev/null
@@ -0,0 +1,206 @@
+<refentry id="vidioc-enumoutput">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUMOUTPUT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUMOUTPUT</refname>
+    <refpurpose>Enumerate video outputs</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_output *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_ENUMOUTPUT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the attributes of a video outputs applications
+initialize the <structfield>index</structfield> field of &v4l2-output;
+and call the <constant>VIDIOC_ENUMOUTPUT</constant> ioctl with a
+pointer to this structure. Drivers fill the rest of the structure or
+return an &EINVAL; when the index is out of bounds. To enumerate all
+outputs applications shall begin at index zero, incrementing by one
+until the driver returns <errorcode>EINVAL</errorcode>.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-output">
+      <title>struct <structname>v4l2_output</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Identifies the output, set by the
+application.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>name</structfield>[32]</entry>
+           <entry>Name of the video output, a NUL-terminated ASCII
+string, for example: "Vout". This information is intended for the
+user, preferably the connector label on the device itself.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the output, see <xref
+               linkend="output-type" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>audioset</structfield></entry>
+           <entry><para>Drivers can enumerate up to 32 video and
+audio outputs. This field shows which audio outputs were
+selectable as the current output if this was the currently selected
+video output. It is a bit mask. The LSB corresponds to audio output 0,
+the MSB to output 31. Any number of bits can be set, or
+none.</para><para>When the driver does not enumerate audio outputs no
+bits must be set. Applications shall not interpret this as lack of
+audio support. Drivers may automatically select audio outputs without
+enumerating them.</para><para>For details on audio outputs and how to
+select the current output see <xref linkend="audio" />.</para></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>modulator</structfield></entry>
+           <entry>Output devices can have zero or more RF modulators.
+When the <structfield>type</structfield> is
+<constant>V4L2_OUTPUT_TYPE_MODULATOR</constant> this is an RF
+connector and this field identifies the modulator. It corresponds to
+&v4l2-modulator; field <structfield>index</structfield>. For details
+on modulators see <xref linkend="tuner" />.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-std-id;</entry>
+           <entry><structfield>std</structfield></entry>
+           <entry>Every video output supports one or more different
+video standards. This field is a set of all supported standards. For
+details on video standards and how to switch see <xref
+               linkend="standard" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capabilities</structfield></entry>
+           <entry>This field provides capabilities for the
+output. See <xref linkend="output-capabilities" /> for flags.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[3]</entry>
+           <entry>Reserved for future extensions. Drivers must set
+the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="output-type">
+      <title>Output Type</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_OUTPUT_TYPE_MODULATOR</constant></entry>
+           <entry>1</entry>
+           <entry>This output is an analog TV modulator.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_OUTPUT_TYPE_ANALOG</constant></entry>
+           <entry>2</entry>
+           <entry>Analog baseband output, for example Composite /
+CVBS, S-Video, RGB.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY</constant></entry>
+           <entry>3</entry>
+           <entry>[?]</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <!-- Capabilities flags based on video timings RFC by Muralidharan
+Karicheri, titled RFC (v1.2): V4L - Support for video timings at the
+input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
+       -->
+    <table frame="none" pgwide="1" id="output-capabilities">
+      <title>Output capabilities</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_OUT_CAP_PRESETS</constant></entry>
+           <entry>0x00000001</entry>
+           <entry>This output supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_OUT_CAP_CUSTOM_TIMINGS</constant></entry>
+           <entry>0x00000002</entry>
+           <entry>This output supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_OUT_CAP_STD</constant></entry>
+           <entry>0x00000004</entry>
+           <entry>This output supports setting the TV standard by using VIDIOC_S_STD.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-output; <structfield>index</structfield>
+is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumstd.xml b/Documentation/DocBook/media/v4l/vidioc-enumstd.xml
new file mode 100644 (file)
index 0000000..95803fe
--- /dev/null
@@ -0,0 +1,391 @@
+<refentry id="vidioc-enumstd">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_ENUMSTD</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_ENUMSTD</refname>
+    <refpurpose>Enumerate supported video standards</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_standard *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_ENUMSTD</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the attributes of a video standard,
+especially a custom (driver defined) one, applications initialize the
+<structfield>index</structfield> field of &v4l2-standard; and call the
+<constant>VIDIOC_ENUMSTD</constant> ioctl with a pointer to this
+structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all standards
+applications shall begin  at index zero, incrementing by one until the
+driver returns <errorcode>EINVAL</errorcode>. Drivers may enumerate a
+different set of standards after switching the video input or
+output.<footnote>
+       <para>The supported standards may overlap and we need an
+unambiguous set to find the current standard returned by
+<constant>VIDIOC_G_STD</constant>.</para>
+      </footnote></para>
+
+    <table pgwide="1" frame="none" id="v4l2-standard">
+      <title>struct <structname>v4l2_standard</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Number of the video standard, set by the
+application.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-std-id;</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry>The bits in this field identify the standard as
+one of the common standards listed in <xref linkend="v4l2-std-id" />,
+or if bits 32 to 63 are set as custom standards. Multiple bits can be
+set if the hardware does not distinguish between these standards,
+however separate indices do not indicate the opposite. The
+<structfield>id</structfield> must be unique. No other enumerated
+<structname>v4l2_standard</structname> structure, for this input or
+output anyway, can contain the same set of bits.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>name</structfield>[24]</entry>
+           <entry>Name of the standard, a NUL-terminated ASCII
+string, for example: "PAL-B/G", "NTSC Japan". This information is
+intended for the user.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>frameperiod</structfield></entry>
+           <entry>The frame period (not field period) is numerator
+/ denominator. For example M/NTSC has a frame period of 1001 /
+30000 seconds.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>framelines</structfield></entry>
+           <entry>Total lines per frame including blanking,
+e.&nbsp;g. 625 for B/PAL.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[4]</entry>
+           <entry>Reserved for future extensions. Drivers must set
+the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-fract">
+      <title>struct <structname>v4l2_fract</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>numerator</structfield></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>denominator</structfield></entry>
+           <entry></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-std-id">
+      <title>typedef <structname>v4l2_std_id</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u64</entry>
+           <entry><structfield>v4l2_std_id</structfield></entry>
+           <entry>This type is a set, each bit representing another
+video standard as listed below and in <xref
+linkend="video-standards" />. The 32 most significant bits are reserved
+for custom (driver defined) video standards.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <para><programlisting>
+#define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
+#define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
+#define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
+#define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
+#define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
+#define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
+#define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
+#define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
+
+#define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
+#define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
+#define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
+#define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
+</programlisting></para><para><constant>V4L2_STD_PAL_60</constant> is
+a hybrid standard with 525 lines, 60 Hz refresh rate, and PAL color
+modulation with a 4.43 MHz color subcarrier. Some PAL video recorders
+can play back NTSC tapes in this mode for display on a 50/60 Hz agnostic
+PAL TV.</para><para><programlisting>
+#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
+#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
+#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
+</programlisting></para><para><constant>V4L2_STD_NTSC_443</constant>
+is a hybrid standard with 525 lines, 60 Hz refresh rate, and NTSC
+color modulation with a 4.43 MHz color
+subcarrier.</para><para><programlisting>
+#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)
+
+#define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
+#define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
+#define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
+#define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
+#define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
+#define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
+#define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
+#define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
+
+/* ATSC/HDTV */
+#define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
+#define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
+</programlisting></para><para><!-- ATSC proposal by Mark McClelland,
+video4linux-list@redhat.com on 17 Oct 2002
+--><constant>V4L2_STD_ATSC_8_VSB</constant> and
+<constant>V4L2_STD_ATSC_16_VSB</constant> are U.S. terrestrial digital
+TV standards. Presently the V4L2 API does not support digital TV. See
+also the Linux DVB API at <ulink
+url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
+<para><programlisting>
+#define V4L2_STD_PAL_BG         (V4L2_STD_PAL_B         |\
+                                V4L2_STD_PAL_B1        |\
+                                V4L2_STD_PAL_G)
+#define V4L2_STD_B              (V4L2_STD_PAL_B         |\
+                                V4L2_STD_PAL_B1        |\
+                                V4L2_STD_SECAM_B)
+#define V4L2_STD_GH             (V4L2_STD_PAL_G         |\
+                                V4L2_STD_PAL_H         |\
+                                V4L2_STD_SECAM_G       |\
+                                V4L2_STD_SECAM_H)
+#define V4L2_STD_PAL_DK         (V4L2_STD_PAL_D         |\
+                                V4L2_STD_PAL_D1        |\
+                                V4L2_STD_PAL_K)
+#define V4L2_STD_PAL            (V4L2_STD_PAL_BG        |\
+                                V4L2_STD_PAL_DK        |\
+                                V4L2_STD_PAL_H         |\
+                                V4L2_STD_PAL_I)
+#define V4L2_STD_NTSC           (V4L2_STD_NTSC_M        |\
+                                V4L2_STD_NTSC_M_JP     |\
+                                V4L2_STD_NTSC_M_KR)
+#define V4L2_STD_MN             (V4L2_STD_PAL_M         |\
+                                V4L2_STD_PAL_N         |\
+                                V4L2_STD_PAL_Nc        |\
+                                V4L2_STD_NTSC)
+#define V4L2_STD_SECAM_DK       (V4L2_STD_SECAM_D       |\
+                                V4L2_STD_SECAM_K       |\
+                                V4L2_STD_SECAM_K1)
+#define V4L2_STD_DK             (V4L2_STD_PAL_DK        |\
+                                V4L2_STD_SECAM_DK)
+
+#define V4L2_STD_SECAM          (V4L2_STD_SECAM_B       |\
+                                V4L2_STD_SECAM_G       |\
+                                V4L2_STD_SECAM_H       |\
+                                V4L2_STD_SECAM_DK      |\
+                                V4L2_STD_SECAM_L       |\
+                                V4L2_STD_SECAM_LC)
+
+#define V4L2_STD_525_60         (V4L2_STD_PAL_M         |\
+                                V4L2_STD_PAL_60        |\
+                                V4L2_STD_NTSC          |\
+                                V4L2_STD_NTSC_443)
+#define V4L2_STD_625_50         (V4L2_STD_PAL           |\
+                                V4L2_STD_PAL_N         |\
+                                V4L2_STD_PAL_Nc        |\
+                                V4L2_STD_SECAM)
+
+#define V4L2_STD_UNKNOWN        0
+#define V4L2_STD_ALL            (V4L2_STD_525_60        |\
+                                V4L2_STD_625_50)
+</programlisting></para>
+
+    <table pgwide="1" id="video-standards" orient="land">
+      <title>Video Standards (based on [<xref linkend="itu470" />])</title>
+      <tgroup cols="12" colsep="1" rowsep="1" align="center">
+       <colspec colname="c1" align="left" />
+       <colspec colname="c2" />
+       <colspec colname="c3" />
+       <colspec colname="c4" />
+       <colspec colname="c5" />
+       <colspec colnum="7" colname="c7" />
+       <colspec colnum="9" colname="c9" />
+       <colspec colnum="12" colname="c12" />
+       <spanspec namest="c2" nameend="c3" spanname="m" align="center" />
+       <spanspec namest="c4" nameend="c12" spanname="x" align="center" />
+       <spanspec namest="c5" nameend="c7" spanname="b" align="center" />
+       <spanspec namest="c9" nameend="c12" spanname="s" align="center" />
+       <thead>
+         <row>
+           <entry>Characteristics</entry>
+           <entry><para>M/NTSC<footnote><para>Japan uses a standard
+similar to M/NTSC
+(V4L2_STD_NTSC_M_JP).</para></footnote></para></entry>
+           <entry>M/PAL</entry>
+           <entry><para>N/PAL<footnote><para> The values in
+brackets apply to the combination N/PAL a.k.a.
+N<subscript>C</subscript> used in Argentina
+(V4L2_STD_PAL_Nc).</para></footnote></para></entry>
+           <entry align="center">B, B1, G/PAL</entry>
+           <entry align="center">D, D1, K/PAL</entry>
+           <entry align="center">H/PAL</entry>
+           <entry align="center">I/PAL</entry>
+           <entry align="center">B, G/SECAM</entry>
+           <entry align="center">D, K/SECAM</entry>
+           <entry align="center">K1/SECAM</entry>
+           <entry align="center">L/SECAM</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry>Frame lines</entry>
+           <entry spanname="m">525</entry>
+           <entry spanname="x">625</entry>
+         </row>
+         <row>
+           <entry>Frame period (s)</entry>
+           <entry spanname="m">1001/30000</entry>
+           <entry spanname="x">1/25</entry>
+         </row>
+         <row>
+           <entry>Chrominance sub-carrier frequency (Hz)</entry>
+           <entry>3579545 &plusmn;&nbsp;10</entry>
+           <entry>3579611.49 &plusmn;&nbsp;10</entry>
+           <entry>4433618.75 &plusmn;&nbsp;5 (3582056.25
+&plusmn;&nbsp;5)</entry>
+           <entry spanname="b">4433618.75 &plusmn;&nbsp;5</entry>
+           <entry>4433618.75 &plusmn;&nbsp;1</entry>
+           <entry spanname="s">f<subscript>OR</subscript>&nbsp;=
+4406250 &plusmn;&nbsp;2000, f<subscript>OB</subscript>&nbsp;= 4250000
+&plusmn;&nbsp;2000</entry>
+         </row>
+         <row>
+           <entry>Nominal radio-frequency channel bandwidth
+(MHz)</entry>
+           <entry>6</entry>
+           <entry>6</entry>
+           <entry>6</entry>
+           <entry>B: 7; B1, G: 8</entry>
+           <entry>8</entry>
+           <entry>8</entry>
+           <entry>8</entry>
+           <entry>8</entry>
+           <entry>8</entry>
+           <entry>8</entry>
+           <entry>8</entry>
+         </row>
+         <row>
+           <entry>Sound carrier relative to vision carrier
+(MHz)</entry>
+           <entry>+&nbsp;4.5</entry>
+           <entry>+&nbsp;4.5</entry>
+           <entry>+&nbsp;4.5</entry>
+           <entry><para>+&nbsp;5.5 &plusmn;&nbsp;0.001
+<footnote><para>In the Federal Republic of Germany, Austria, Italy,
+the Netherlands, Slovakia and Switzerland a system of two sound
+carriers is used, the frequency of the second carrier being
+242.1875&nbsp;kHz above the frequency of the first sound carrier. For
+stereophonic sound transmissions a similar system is used in
+Australia.</para></footnote> <footnote><para>New Zealand uses a sound
+carrier displaced 5.4996 &plusmn;&nbsp;0.0005 MHz from the vision
+carrier.</para></footnote> <footnote><para>In Denmark, Finland, New
+Zealand, Sweden and Spain a system of two sound carriers is used. In
+Iceland, Norway and Poland the same system is being introduced. The
+second carrier is 5.85&nbsp;MHz above the vision carrier and is DQPSK
+modulated with 728&nbsp;kbit/s sound and data multiplex. (NICAM
+system)</para></footnote> <footnote><para>In the United Kingdom, a
+system of two sound carriers is used. The second sound carrier is
+6.552&nbsp;MHz above the vision carrier and is DQPSK modulated with a
+728&nbsp;kbit/s sound and data multiplex able to carry two sound
+channels. (NICAM system)</para></footnote></para></entry>
+           <entry>+&nbsp;6.5 &plusmn;&nbsp;0.001</entry>
+           <entry>+&nbsp;5.5</entry>
+           <entry>+&nbsp;5.9996 &plusmn;&nbsp;0.0005</entry>
+           <entry>+&nbsp;5.5 &plusmn;&nbsp;0.001</entry>
+           <entry>+&nbsp;6.5 &plusmn;&nbsp;0.001</entry>
+           <entry>+&nbsp;6.5</entry>
+           <entry><para>+&nbsp;6.5 <footnote><para>In France, a
+digital carrier 5.85 MHz away from the vision carrier may be used in
+addition to the main sound carrier. It is modulated in differentially
+encoded QPSK with a 728 kbit/s sound and data multiplexer capable of
+carrying two sound channels. (NICAM
+system)</para></footnote></para></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-standard; <structfield>index</structfield>
+is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-audio.xml b/Documentation/DocBook/media/v4l/vidioc-g-audio.xml
new file mode 100644 (file)
index 0000000..d7bb9b3
--- /dev/null
@@ -0,0 +1,172 @@
+<refentry id="vidioc-g-audio">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_AUDIO</refname>
+    <refname>VIDIOC_S_AUDIO</refname>
+    <refpurpose>Query or select the current audio input and its
+attributes</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_audio *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const struct v4l2_audio *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_AUDIO, VIDIOC_S_AUDIO</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the current audio input applications zero out the
+<structfield>reserved</structfield> array of a &v4l2-audio;
+and call the <constant>VIDIOC_G_AUDIO</constant> ioctl with a pointer
+to this structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the device has no audio inputs, or none which combine
+with the current video input.</para>
+
+    <para>Audio inputs have one writable property, the audio mode. To
+select the current audio input <emphasis>and</emphasis> change the
+audio mode, applications initialize the
+<structfield>index</structfield> and <structfield>mode</structfield>
+fields, and the
+<structfield>reserved</structfield> array of a
+<structname>v4l2_audio</structname> structure and call the
+<constant>VIDIOC_S_AUDIO</constant> ioctl. Drivers may switch to a
+different audio mode if the request cannot be satisfied. However, this
+is a write-only ioctl, it does not return the actual new audio
+mode.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-audio">
+      <title>struct <structname>v4l2_audio</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Identifies the audio input, set by the
+driver or application.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>name</structfield>[32]</entry>
+           <entry>Name of the audio input, a NUL-terminated ASCII
+string, for example: "Line In". This information is intended for the
+user, preferably the connector label on the device itself.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capability</structfield></entry>
+           <entry>Audio capability flags, see <xref
+               linkend="audio-capability" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>mode</structfield></entry>
+           <entry>Audio mode flags set by drivers and applications (on
+           <constant>VIDIOC_S_AUDIO</constant> ioctl), see <xref linkend="audio-mode" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[2]</entry>
+           <entry>Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="audio-capability">
+      <title>Audio Capability Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_AUDCAP_STEREO</constant></entry>
+           <entry>0x00001</entry>
+           <entry>This is a stereo input. The flag is intended to
+automatically disable stereo recording etc. when the signal is always
+monaural. The API provides no means to detect if stereo is
+<emphasis>received</emphasis>, unless the audio input belongs to a
+tuner.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_AUDCAP_AVL</constant></entry>
+           <entry>0x00002</entry>
+           <entry>Automatic Volume Level mode is supported.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="audio-mode">
+      <title>Audio Mode Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_AUDMODE_AVL</constant></entry>
+           <entry>0x00001</entry>
+           <entry>AVL mode is on.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>No audio inputs combine with the current video input,
+or the number of the selected audio input is out of bounds or it does
+not combine.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-audioout.xml b/Documentation/DocBook/media/v4l/vidioc-g-audioout.xml
new file mode 100644 (file)
index 0000000..200a270
--- /dev/null
@@ -0,0 +1,138 @@
+<refentry id="vidioc-g-audioout">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_AUDOUT</refname>
+    <refname>VIDIOC_S_AUDOUT</refname>
+    <refpurpose>Query or select the current audio output</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_audioout *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const struct v4l2_audioout *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the current audio output applications zero out the
+<structfield>reserved</structfield> array of a &v4l2-audioout; and
+call the <constant>VIDIOC_G_AUDOUT</constant> ioctl with a pointer
+to this structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the device has no audio inputs, or none which combine
+with the current video output.</para>
+
+    <para>Audio outputs have no writable properties. Nevertheless, to
+select the current audio output applications can initialize the
+<structfield>index</structfield> field and
+<structfield>reserved</structfield> array (which in the future may
+contain writable properties) of a
+<structname>v4l2_audioout</structname> structure and call the
+<constant>VIDIOC_S_AUDOUT</constant> ioctl. Drivers switch to the
+requested output or return the &EINVAL; when the index is out of
+bounds. This is a write-only ioctl, it does not return the current
+audio output attributes as <constant>VIDIOC_G_AUDOUT</constant>
+does.</para>
+
+    <para>Note connectors on a TV card to loop back the received audio
+signal to a sound card are not audio outputs in this sense.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-audioout">
+      <title>struct <structname>v4l2_audioout</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Identifies the audio output, set by the
+driver or application.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>name</structfield>[32]</entry>
+           <entry>Name of the audio output, a NUL-terminated ASCII
+string, for example: "Line Out". This information is intended for the
+user, preferably the connector label on the device itself.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capability</structfield></entry>
+           <entry>Audio capability flags, none defined yet. Drivers
+must set this field to zero.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>mode</structfield></entry>
+           <entry>Audio mode, none defined yet. Drivers and
+applications (on <constant>VIDIOC_S_AUDOUT</constant>) must set this
+field to zero.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[2]</entry>
+           <entry>Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>No audio outputs combine with the current video
+output, or the number of the selected audio output is out of bounds or
+it does not combine.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-g-crop.xml
new file mode 100644 (file)
index 0000000..01a5064
--- /dev/null
@@ -0,0 +1,126 @@
+<refentry id="vidioc-g-crop">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_CROP, VIDIOC_S_CROP</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_CROP</refname>
+    <refname>VIDIOC_S_CROP</refname>
+    <refpurpose>Get or set the current cropping rectangle</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_crop *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const struct v4l2_crop *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_CROP, VIDIOC_S_CROP</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the cropping rectangle size and position
+applications set the <structfield>type</structfield> field of a
+<structname>v4l2_crop</structname> structure to the respective buffer
+(stream) type and call the <constant>VIDIOC_G_CROP</constant> ioctl
+with a pointer to this structure. The driver fills the rest of the
+structure or returns the &EINVAL; if cropping is not supported.</para>
+
+    <para>To change the cropping rectangle applications initialize the
+<structfield>type</structfield> and &v4l2-rect; substructure named
+<structfield>c</structfield> of a v4l2_crop structure and call the
+<constant>VIDIOC_S_CROP</constant> ioctl with a pointer to this
+structure.</para>
+
+    <para>The driver first adjusts the requested dimensions against
+hardware limits, &ie; the bounds given by the capture/output window,
+and it rounds to the closest possible values of horizontal and
+vertical offset, width and height. In particular the driver must round
+the vertical offset of the cropping rectangle to frame lines modulo
+two, such that the field order cannot be confused.</para>
+
+    <para>Second the driver adjusts the image size (the opposite
+rectangle of the scaling process, source or target depending on the
+data direction) to the closest size possible while maintaining the
+current horizontal and vertical scaling factor.</para>
+
+    <para>Finally the driver programs the hardware with the actual
+cropping and image parameters. <constant>VIDIOC_S_CROP</constant> is a
+write-only ioctl, it does not return the actual parameters. To query
+them applications must call <constant>VIDIOC_G_CROP</constant> and
+&VIDIOC-G-FMT;. When the parameters are unsuitable the application may
+modify the cropping or image parameters and repeat the cycle until
+satisfactory parameters have been negotiated.</para>
+
+    <para>When cropping is not supported then no parameters are
+changed and <constant>VIDIOC_S_CROP</constant> returns the
+&EINVAL;.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-crop">
+      <title>struct <structname>v4l2_crop</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>&v4l2-buf-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the data stream, set by the application.
+Only these types are valid here: <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
+defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
+and higher.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-rect;</entry>
+           <entry><structfield>c</structfield></entry>
+           <entry>Cropping rectangle. The same co-ordinate system as
+for &v4l2-cropcap; <structfield>bounds</structfield> is used.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml b/Documentation/DocBook/media/v4l/vidioc-g-ctrl.xml
new file mode 100644 (file)
index 0000000..5146d00
--- /dev/null
@@ -0,0 +1,137 @@
+<refentry id="vidioc-g-ctrl">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_CTRL, VIDIOC_S_CTRL</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_CTRL</refname>
+    <refname>VIDIOC_S_CTRL</refname>
+    <refpurpose>Get or set the value of a control</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_control
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_CTRL, VIDIOC_S_CTRL</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To get the current value of a control applications
+initialize the <structfield>id</structfield> field of a struct
+<structname>v4l2_control</structname> and call the
+<constant>VIDIOC_G_CTRL</constant> ioctl with a pointer to this
+structure. To change the value of a control applications initialize
+the <structfield>id</structfield> and <structfield>value</structfield>
+fields of a struct <structname>v4l2_control</structname> and call the
+<constant>VIDIOC_S_CTRL</constant> ioctl.</para>
+
+    <para>When the <structfield>id</structfield> is invalid drivers
+return an &EINVAL;. When the <structfield>value</structfield> is out
+of bounds drivers can choose to take the closest valid value or return
+an &ERANGE;, whatever seems more appropriate. However,
+<constant>VIDIOC_S_CTRL</constant> is a write-only ioctl, it does not
+return the actual new value.</para>
+
+    <para>These ioctls work only with user controls. For other
+control classes the &VIDIOC-G-EXT-CTRLS;, &VIDIOC-S-EXT-CTRLS; or
+&VIDIOC-TRY-EXT-CTRLS; must be used.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-control">
+      <title>struct <structname>v4l2_control</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry>Identifies the control, set by the
+application.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>value</structfield></entry>
+           <entry>New value or current value.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-control; <structfield>id</structfield> is
+invalid.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ERANGE</errorcode></term>
+       <listitem>
+         <para>The &v4l2-control; <structfield>value</structfield>
+is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The control is temporarily not changeable, possibly
+because another applications took over control of the device function
+this control belongs to.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EACCES</errorcode></term>
+       <listitem>
+         <para>Attempt to set a read-only control or to get a
+         write-only control.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml
new file mode 100644 (file)
index 0000000..7940c11
--- /dev/null
@@ -0,0 +1,104 @@
+<refentry id="vidioc-g-dv-preset">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_DV_PRESET</refname>
+    <refname>VIDIOC_S_DV_PRESET</refname>
+    <refpurpose>Query or select the DV preset of the current input or output</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_dv_preset *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+    <para>To query and select the current DV preset, applications
+use the <constant>VIDIOC_G_DV_PRESET</constant> and <constant>VIDIOC_S_DV_PRESET</constant>
+ioctls which take a pointer to a &v4l2-dv-preset; type as argument.
+Applications must zero the reserved array in &v4l2-dv-preset;.
+<constant>VIDIOC_G_DV_PRESET</constant> returns a dv preset in the field
+<structfield>preset</structfield> of &v4l2-dv-preset;.</para>
+
+    <para><constant>VIDIOC_S_DV_PRESET</constant> accepts a pointer to a &v4l2-dv-preset;
+that has the preset value to be set. Applications must zero the reserved array in &v4l2-dv-preset;.
+If the preset is not supported, it returns an &EINVAL; </para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>This ioctl is not supported, or the
+<constant>VIDIOC_S_DV_PRESET</constant>,<constant>VIDIOC_S_DV_PRESET</constant> parameter was unsuitable.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The device is busy and therefore can not change the preset.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+
+    <table pgwide="1" frame="none" id="v4l2-dv-preset">
+      <title>struct <structname>v4l2_dv_preset</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>preset</structfield></entry>
+           <entry>Preset value to represent the digital video timings</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved[4]</structfield></entry>
+           <entry>Reserved fields for future use</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
new file mode 100644 (file)
index 0000000..4a8648a
--- /dev/null
@@ -0,0 +1,218 @@
+<refentry id="vidioc-g-dv-timings">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_DV_TIMINGS</refname>
+    <refname>VIDIOC_S_DV_TIMINGS</refname>
+    <refpurpose>Get or set custom DV timings for input or output</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_dv_timings *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+    <para>To set custom DV timings for the input or output, applications use the
+<constant>VIDIOC_S_DV_TIMINGS</constant> ioctl and to get the current custom timings,
+applications use the <constant>VIDIOC_G_DV_TIMINGS</constant> ioctl. The detailed timing
+information is filled in using the structure &v4l2-dv-timings;. These ioctls take
+a pointer to the &v4l2-dv-timings; structure as argument. If the ioctl is not supported
+or the timing values are not correct, the driver returns &EINVAL;.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>This ioctl is not supported, or the
+<constant>VIDIOC_S_DV_TIMINGS</constant> parameter was unsuitable.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The device is busy and therefore can not change the timings.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+
+    <table pgwide="1" frame="none" id="v4l2-bt-timings">
+      <title>struct <structname>v4l2_bt_timings</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>width</structfield></entry>
+           <entry>Width of the active video in pixels</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>height</structfield></entry>
+           <entry>Height of the active video in lines</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>interlaced</structfield></entry>
+           <entry>Progressive (0) or interlaced (1)</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>polarities</structfield></entry>
+           <entry>This is a bit mask that defines polarities of sync signals.
+bit 0 (V4L2_DV_VSYNC_POS_POL) is for vertical sync polarity and bit 1 (V4L2_DV_HSYNC_POS_POL) is for horizontal sync polarity. If the bit is set
+(1) it is positive polarity and if is cleared (0), it is negative polarity.</entry>
+         </row>
+         <row>
+           <entry>__u64</entry>
+           <entry><structfield>pixelclock</structfield></entry>
+           <entry>Pixel clock in Hz. Ex. 74.25MHz->74250000</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>hfrontporch</structfield></entry>
+           <entry>Horizontal front porch in pixels</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>hsync</structfield></entry>
+           <entry>Horizontal sync length in pixels</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>hbackporch</structfield></entry>
+           <entry>Horizontal back porch in pixels</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>vfrontporch</structfield></entry>
+           <entry>Vertical front porch in lines</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>vsync</structfield></entry>
+           <entry>Vertical sync length in lines</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>vbackporch</structfield></entry>
+           <entry>Vertical back porch in lines</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>il_vfrontporch</structfield></entry>
+           <entry>Vertical front porch in lines for bottom field of interlaced field formats</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>il_vsync</structfield></entry>
+           <entry>Vertical sync length in lines for bottom field of interlaced field formats</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>il_vbackporch</structfield></entry>
+           <entry>Vertical back porch in lines for bottom field of interlaced field formats</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-dv-timings">
+      <title>struct <structname>v4l2_dv_timings</structname></title>
+      <tgroup cols="4">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry>Type of DV timings as listed in <xref linkend="dv-timing-types"/>.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry><structfield></structfield></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-bt-timings;</entry>
+           <entry><structfield>bt</structfield></entry>
+           <entry>Timings defined by BT.656/1120 specifications</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[32]</entry>
+           <entry></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="dv-timing-types">
+      <title>DV Timing types</title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>Timing type</entry>
+           <entry>value</entry>
+           <entry>Description</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>V4L2_DV_BT_656_1120</entry>
+           <entry>0</entry>
+           <entry>BT.656/1120 timings</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-enc-index.xml b/Documentation/DocBook/media/v4l/vidioc-g-enc-index.xml
new file mode 100644 (file)
index 0000000..2aef02c
--- /dev/null
@@ -0,0 +1,196 @@
+<refentry id="vidioc-g-enc-index">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_ENC_INDEX</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_ENC_INDEX</refname>
+    <refpurpose>Get meta data about a compressed video stream</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_enc_idx *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_ENC_INDEX</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+
+      <para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+    </note>
+
+    <para>The <constant>VIDIOC_G_ENC_INDEX</constant> ioctl provides
+meta data about a compressed video stream the same or another
+application currently reads from the driver, which is useful for
+random access into the stream without decoding it.</para>
+
+    <para>To read the data applications must call
+<constant>VIDIOC_G_ENC_INDEX</constant> with a pointer to a
+&v4l2-enc-idx;. On success the driver fills the
+<structfield>entry</structfield> array, stores the number of elements
+written in the <structfield>entries</structfield> field, and
+initializes the <structfield>entries_cap</structfield> field.</para>
+
+    <para>Each element of the <structfield>entry</structfield> array
+contains meta data about one picture. A
+<constant>VIDIOC_G_ENC_INDEX</constant> call reads up to
+<constant>V4L2_ENC_IDX_ENTRIES</constant> entries from a driver
+buffer, which can hold up to <structfield>entries_cap</structfield>
+entries. This number can be lower or higher than
+<constant>V4L2_ENC_IDX_ENTRIES</constant>, but not zero. When the
+application fails to read the meta data in time the oldest entries
+will be lost. When the buffer is empty or no capturing/encoding is in
+progress, <structfield>entries</structfield> will be zero.</para>
+
+    <para>Currently this ioctl is only defined for MPEG-2 program
+streams and video elementary streams.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-enc-idx">
+      <title>struct <structname>v4l2_enc_idx</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>entries</structfield></entry>
+           <entry>The number of entries the driver stored in the
+<structfield>entry</structfield> array.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>entries_cap</structfield></entry>
+           <entry>The number of entries the driver can
+buffer. Must be greater than zero.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[4]</entry>
+           <entry spanname="hspan">Reserved for future extensions.
+Drivers must set the array to zero.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-enc-idx-entry;</entry>
+           <entry><structfield>entry</structfield>[<constant>V4L2_ENC_IDX_ENTRIES</constant>]</entry>
+           <entry>Meta data about a compressed video stream. Each
+element of the array corresponds to one picture, sorted in ascending
+order by their <structfield>offset</structfield>.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-enc-idx-entry">
+      <title>struct <structname>v4l2_enc_idx_entry</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u64</entry>
+           <entry><structfield>offset</structfield></entry>
+           <entry>The offset in bytes from the beginning of the
+compressed video stream to the beginning of this picture, that is a
+<wordasword>PES packet header</wordasword> as defined in <xref
+           linkend="mpeg2part1" /> or a <wordasword>picture
+header</wordasword> as defined in <xref linkend="mpeg2part2" />. When
+the encoder is stopped, the driver resets the offset to zero.</entry>
+         </row>
+         <row>
+           <entry>__u64</entry>
+           <entry><structfield>pts</structfield></entry>
+           <entry>The 33 bit <wordasword>Presentation Time
+Stamp</wordasword> of this picture as defined in <xref
+               linkend="mpeg2part1" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>length</structfield></entry>
+           <entry>The length of this picture in bytes.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry>Flags containing the coding type of this picture, see <xref
+               linkend="enc-idx-flags" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[2]</entry>
+           <entry>Reserved for future extensions.
+Drivers must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="enc-idx-flags">
+      <title>Index Entry Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_ENC_IDX_FRAME_I</constant></entry>
+           <entry>0x00</entry>
+           <entry>This is an Intra-coded picture.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_ENC_IDX_FRAME_P</constant></entry>
+           <entry>0x01</entry>
+           <entry>This is a Predictive-coded picture.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_ENC_IDX_FRAME_B</constant></entry>
+           <entry>0x02</entry>
+           <entry>This is a Bidirectionally predictive-coded
+picture.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_ENC_IDX_FRAME_MASK</constant></entry>
+           <entry>0x0F</entry>
+           <entry><wordasword>AND</wordasword> the flags field with
+this mask to obtain the picture coding type.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
new file mode 100644 (file)
index 0000000..5122ce8
--- /dev/null
@@ -0,0 +1,321 @@
+<refentry id="vidioc-g-ext-ctrls">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS,
+VIDIOC_TRY_EXT_CTRLS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_EXT_CTRLS</refname>
+    <refname>VIDIOC_S_EXT_CTRLS</refname>
+    <refname>VIDIOC_TRY_EXT_CTRLS</refname>
+    <refpurpose>Get or set the value of several controls, try control
+values</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_ext_controls
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS,
+VIDIOC_TRY_EXT_CTRLS</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>These ioctls allow the caller to get or set multiple
+controls atomically. Control IDs are grouped into control classes (see
+<xref linkend="ctrl-class" />) and all controls in the control array
+must belong to the same control class.</para>
+
+    <para>Applications must always fill in the
+<structfield>count</structfield>,
+<structfield>ctrl_class</structfield>,
+<structfield>controls</structfield> and
+<structfield>reserved</structfield> fields of &v4l2-ext-controls;, and
+initialize the &v4l2-ext-control; array pointed to by the
+<structfield>controls</structfield> fields.</para>
+
+    <para>To get the current value of a set of controls applications
+initialize the <structfield>id</structfield>,
+<structfield>size</structfield> and <structfield>reserved2</structfield> fields
+of each &v4l2-ext-control; and call the
+<constant>VIDIOC_G_EXT_CTRLS</constant> ioctl. String controls controls
+must also set the <structfield>string</structfield> field.</para>
+
+    <para>If the <structfield>size</structfield> is too small to
+receive the control result (only relevant for pointer-type controls
+like strings), then the driver will set <structfield>size</structfield>
+to a valid value and return an &ENOSPC;. You should re-allocate the
+string memory to this new size and try again. It is possible that the
+same issue occurs again if the string has grown in the meantime. It is
+recommended to call &VIDIOC-QUERYCTRL; first and use
+<structfield>maximum</structfield>+1 as the new <structfield>size</structfield>
+value. It is guaranteed that that is sufficient memory.
+</para>
+
+    <para>To change the value of a set of controls applications
+initialize the <structfield>id</structfield>, <structfield>size</structfield>,
+<structfield>reserved2</structfield> and
+<structfield>value/string</structfield> fields of each &v4l2-ext-control; and
+call the <constant>VIDIOC_S_EXT_CTRLS</constant> ioctl. The controls
+will only be set if <emphasis>all</emphasis> control values are
+valid.</para>
+
+    <para>To check if a set of controls have correct values applications
+initialize the <structfield>id</structfield>, <structfield>size</structfield>,
+<structfield>reserved2</structfield> and
+<structfield>value/string</structfield> fields of each &v4l2-ext-control; and
+call the <constant>VIDIOC_TRY_EXT_CTRLS</constant> ioctl. It is up to
+the driver whether wrong values are automatically adjusted to a valid
+value or if an error is returned.</para>
+
+    <para>When the <structfield>id</structfield> or
+<structfield>ctrl_class</structfield> is invalid drivers return an
+&EINVAL;. When the value is out of bounds drivers can choose to take
+the closest valid value or return an &ERANGE;, whatever seems more
+appropriate. In the first case the new value is set in
+&v4l2-ext-control;.</para>
+
+    <para>The driver will only set/get these controls if all control
+values are correct. This prevents the situation where only some of the
+controls were set/get. Only low-level errors (&eg; a failed i2c
+command) can still cause this situation.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-ext-control">
+      <title>struct <structname>v4l2_ext_control</structname></title>
+      <tgroup cols="4">
+       &cs-ustr;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry></entry>
+           <entry>Identifies the control, set by the
+application.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>size</structfield></entry>
+           <entry></entry>
+           <entry>The total size in bytes of the payload of this
+control. This is normally 0, but for pointer controls this should be
+set to the size of the memory containing the payload, or that will
+receive the payload. If <constant>VIDIOC_G_EXT_CTRLS</constant> finds
+that this value is less than is required to store
+the payload result, then it is set to a value large enough to store the
+payload result and ENOSPC is returned. Note that for string controls
+this <structfield>size</structfield> field should not be confused with the length of the string.
+This field refers to the size of the memory that contains the string.
+The actual <emphasis>length</emphasis> of the string may well be much smaller.
+</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved2</structfield>[1]</entry>
+           <entry></entry>
+           <entry>Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry>(anonymous)</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__s32</entry>
+           <entry><structfield>value</structfield></entry>
+           <entry>New value or current value.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__s64</entry>
+           <entry><structfield>value64</structfield></entry>
+           <entry>New value or current value.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>char *</entry>
+           <entry><structfield>string</structfield></entry>
+           <entry>A pointer to a string.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-ext-controls">
+      <title>struct <structname>v4l2_ext_controls</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>ctrl_class</structfield></entry>
+           <entry>The control class to which all controls belong, see
+<xref linkend="ctrl-class" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>count</structfield></entry>
+           <entry>The number of controls in the controls array. May
+also be zero.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>error_idx</structfield></entry>
+           <entry>Set by the driver in case of an error. It is the
+index of the control causing the error or equal to 'count' when the
+error is not associated with a particular control. Undefined when the
+ioctl returns 0 (success).</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[2]</entry>
+           <entry>Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-ext-control; *</entry>
+           <entry><structfield>controls</structfield></entry>
+           <entry>Pointer to an array of
+<structfield>count</structfield> v4l2_ext_control structures. Ignored
+if <structfield>count</structfield> equals zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="ctrl-class">
+      <title>Control classes</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_CTRL_CLASS_USER</constant></entry>
+           <entry>0x980000</entry>
+           <entry>The class containing user controls. These controls
+are described in <xref linkend="control" />. All controls that can be set
+using the &VIDIOC-S-CTRL; and &VIDIOC-G-CTRL; ioctl belong to this
+class.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_CLASS_MPEG</constant></entry>
+           <entry>0x990000</entry>
+           <entry>The class containing MPEG compression controls.
+These controls are described in <xref
+               linkend="mpeg-controls" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_CLASS_CAMERA</constant></entry>
+           <entry>0x9a0000</entry>
+           <entry>The class containing camera controls.
+These controls are described in <xref
+               linkend="camera-controls" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_CLASS_FM_TX</constant></entry>
+           <entry>0x9b0000</entry>
+           <entry>The class containing FM Transmitter (FM TX) controls.
+These controls are described in <xref
+               linkend="fm-tx-controls" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_CLASS_FLASH</constant></entry>
+           <entry>0x9c0000</entry>
+           <entry>The class containing flash device controls.
+These controls are described in <xref
+               linkend="flash-controls" />.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-ext-control; <structfield>id</structfield>
+is invalid or the &v4l2-ext-controls;
+<structfield>ctrl_class</structfield> is invalid. This error code is
+also returned by the <constant>VIDIOC_S_EXT_CTRLS</constant> and
+<constant>VIDIOC_TRY_EXT_CTRLS</constant> ioctls if two or more
+control values are in conflict.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ERANGE</errorcode></term>
+       <listitem>
+         <para>The &v4l2-ext-control; <structfield>value</structfield>
+is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The control is temporarily not changeable, possibly
+because another applications took over control of the device function
+this control belongs to.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>ENOSPC</errorcode></term>
+       <listitem>
+         <para>The space reserved for the control's payload is insufficient.
+The field <structfield>size</structfield> is set to a value that is enough
+to store the payload and this error code is returned.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EACCES</errorcode></term>
+       <listitem>
+         <para>Attempt to try or set a read-only control or to get a
+         write-only control.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml b/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml
new file mode 100644 (file)
index 0000000..0557182
--- /dev/null
@@ -0,0 +1,456 @@
+<refentry id="vidioc-g-fbuf">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_FBUF, VIDIOC_S_FBUF</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_FBUF</refname>
+    <refname>VIDIOC_S_FBUF</refname>
+    <refpurpose>Get or set frame buffer overlay parameters</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_framebuffer *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const struct v4l2_framebuffer *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_FBUF, VIDIOC_S_FBUF</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Applications can use the <constant>VIDIOC_G_FBUF</constant> and
+<constant>VIDIOC_S_FBUF</constant> ioctl to get and set the
+framebuffer parameters for a <link linkend="overlay">Video
+Overlay</link> or <link linkend="osd">Video Output Overlay</link>
+(OSD). The type of overlay is implied by the device type (capture or
+output device) and can be determined with the &VIDIOC-QUERYCAP; ioctl.
+One <filename>/dev/videoN</filename> device must not support both
+kinds of overlay.</para>
+
+    <para>The V4L2 API distinguishes destructive and non-destructive
+overlays. A destructive overlay copies captured video images into the
+video memory of a graphics card. A non-destructive overlay blends
+video images into a VGA signal or graphics into a video signal.
+<wordasword>Video Output Overlays</wordasword> are always
+non-destructive.</para>
+
+    <para>To get the current parameters applications call the
+<constant>VIDIOC_G_FBUF</constant> ioctl with a pointer to a
+<structname>v4l2_framebuffer</structname> structure. The driver fills
+all fields of the structure or returns an &EINVAL; when overlays are
+not supported.</para>
+
+    <para>To set the parameters for a <wordasword>Video Output
+Overlay</wordasword>, applications must initialize the
+<structfield>flags</structfield> field of a struct
+<structname>v4l2_framebuffer</structname>. Since the framebuffer is
+implemented on the TV card all other parameters are determined by the
+driver. When an application calls <constant>VIDIOC_S_FBUF</constant>
+with a pointer to this structure, the driver prepares for the overlay
+and returns the framebuffer parameters as
+<constant>VIDIOC_G_FBUF</constant> does, or it returns an error
+code.</para>
+
+    <para>To set the parameters for a <wordasword>non-destructive
+Video Overlay</wordasword>, applications must initialize the
+<structfield>flags</structfield> field, the
+<structfield>fmt</structfield> substructure, and call
+<constant>VIDIOC_S_FBUF</constant>. Again the driver prepares for the
+overlay and returns the framebuffer parameters as
+<constant>VIDIOC_G_FBUF</constant> does, or it returns an error
+code.</para>
+
+    <para>For a <wordasword>destructive Video Overlay</wordasword>
+applications must additionally provide a
+<structfield>base</structfield> address. Setting up a DMA to a
+random memory location can jeopardize the system security, its
+stability or even damage the hardware, therefore only the superuser
+can set the parameters for a destructive video overlay.</para>
+
+    <!-- NB v4l2_pix_format is also specified in pixfmt.sgml.-->
+
+    <table pgwide="1" frame="none" id="v4l2-framebuffer">
+      <title>struct <structname>v4l2_framebuffer</structname></title>
+      <tgroup cols="4">
+       &cs-ustr;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capability</structfield></entry>
+           <entry></entry>
+           <entry>Overlay capability flags set by the driver, see
+<xref linkend="framebuffer-cap" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry></entry>
+           <entry>Overlay control flags set by application and
+driver, see <xref linkend="framebuffer-flags" /></entry>
+         </row>
+         <row>
+           <entry>void *</entry>
+           <entry><structfield>base</structfield></entry>
+           <entry></entry>
+           <entry>Physical base address of the framebuffer,
+that is the address of the pixel in the top left corner of the
+framebuffer.<footnote><para>A physical base address may not suit all
+platforms. GK notes in theory we should pass something like PCI device
++ memory region + offset instead. If you encounter problems please
+discuss on the linux-media mailing list: &v4l-ml;.</para></footnote></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>This field is irrelevant to
+<wordasword>non-destructive Video Overlays</wordasword>. For
+<wordasword>destructive Video Overlays</wordasword> applications must
+provide a base address. The driver may accept only base addresses
+which are a multiple of two, four or eight bytes. For
+<wordasword>Video Output Overlays</wordasword> the driver must return
+a valid base address, so applications can find the corresponding Linux
+framebuffer device (see <xref linkend="osd" />).</entry>
+         </row>
+         <row>
+           <entry>&v4l2-pix-format;</entry>
+           <entry><structfield>fmt</structfield></entry>
+           <entry></entry>
+           <entry>Layout of the frame buffer. The
+<structname>v4l2_pix_format</structname> structure is defined in <xref
+linkend="pixfmt" />, for clarification the fields and acceptable values
+           are listed below:</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>width</structfield></entry>
+           <entry>Width of the frame buffer in pixels.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>height</structfield></entry>
+           <entry>Height of the frame buffer in pixels.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>pixelformat</structfield></entry>
+           <entry>The pixel format of the
+framebuffer.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>For <wordasword>non-destructive Video
+Overlays</wordasword> this field only defines a format for the
+&v4l2-window; <structfield>chromakey</structfield> field.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>For <wordasword>destructive Video
+Overlays</wordasword> applications must initialize this field. For
+<wordasword>Video Output Overlays</wordasword> the driver must return
+a valid format.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+           <entry>Usually this is an RGB format (for example
+<link linkend="V4L2-PIX-FMT-RGB565"><constant>V4L2_PIX_FMT_RGB565</constant></link>)
+but YUV formats (only packed YUV formats when chroma keying is used,
+not including <constant>V4L2_PIX_FMT_YUYV</constant> and
+<constant>V4L2_PIX_FMT_UYVY</constant>) and the
+<constant>V4L2_PIX_FMT_PAL8</constant> format are also permitted. The
+behavior of the driver when an application requests a compressed
+format is undefined. See <xref linkend="pixfmt" /> for information on
+pixel formats.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-field;</entry>
+           <entry><structfield>field</structfield></entry>
+           <entry>Drivers and applications shall ignore this field.
+If applicable, the field order is selected with the &VIDIOC-S-FMT;
+ioctl, using the <structfield>field</structfield> field of
+&v4l2-window;.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>bytesperline</structfield></entry>
+           <entry>Distance in bytes between the leftmost pixels in
+two adjacent lines.</entry>
+         </row>
+         <row>
+           <entry spanname="hspan"><para>This field is irrelevant to
+<wordasword>non-destructive Video
+Overlays</wordasword>.</para><para>For <wordasword>destructive Video
+Overlays</wordasword> both applications and drivers can set this field
+to request padding bytes at the end of each line. Drivers however may
+ignore the requested value, returning <structfield>width</structfield>
+times bytes-per-pixel or a larger value required by the hardware. That
+implies applications can just set this field to zero to get a
+reasonable default.</para><para>For <wordasword>Video Output
+Overlays</wordasword> the driver must return a valid
+value.</para><para>Video hardware may access padding bytes, therefore
+they must reside in accessible memory. Consider for example the case
+where padding bytes after the last line of an image cross a system
+page boundary. Capture devices may write padding bytes, the value is
+undefined. Output devices ignore the contents of padding
+bytes.</para><para>When the image format is planar the
+<structfield>bytesperline</structfield> value applies to the largest
+plane and is divided by the same factor as the
+<structfield>width</structfield> field for any smaller planes. For
+example the Cb and Cr planes of a YUV 4:2:0 image have half as many
+padding bytes following each line as the Y plane. To avoid ambiguities
+drivers must return a <structfield>bytesperline</structfield> value
+rounded up to a multiple of the scale factor.</para></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>sizeimage</structfield></entry>
+           <entry><para>This field is irrelevant to
+<wordasword>non-destructive Video Overlays</wordasword>. For
+<wordasword>destructive Video Overlays</wordasword> applications must
+initialize this field. For <wordasword>Video Output
+Overlays</wordasword> the driver must return a valid
+format.</para><para>Together with <structfield>base</structfield> it
+defines the framebuffer memory accessible by the
+driver.</para></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-colorspace;</entry>
+           <entry><structfield>colorspace</structfield></entry>
+           <entry>This information supplements the
+<structfield>pixelformat</structfield> and must be set by the driver,
+see <xref linkend="colorspaces" />.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u32</entry>
+           <entry><structfield>priv</structfield></entry>
+           <entry>Reserved for additional information about custom
+(driver defined) formats. When not used drivers and applications must
+set this field to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="framebuffer-cap">
+      <title>Frame Buffer Capability Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_FBUF_CAP_EXTERNOVERLAY</constant></entry>
+           <entry>0x0001</entry>
+           <entry>The device is capable of non-destructive overlays.
+When the driver clears this flag, only destructive overlays are
+supported. There are no drivers yet which support both destructive and
+non-destructive overlays.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_CAP_CHROMAKEY</constant></entry>
+           <entry>0x0002</entry>
+           <entry>The device supports clipping by chroma-keying the
+images. That is, image pixels replace pixels in the VGA or video
+signal only where the latter assume a certain color. Chroma-keying
+makes no sense for destructive overlays.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_CAP_LIST_CLIPPING</constant></entry>
+           <entry>0x0004</entry>
+           <entry>The device supports clipping using a list of clip
+rectangles.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_CAP_BITMAP_CLIPPING</constant></entry>
+           <entry>0x0008</entry>
+           <entry>The device supports clipping using a bit mask.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_CAP_LOCAL_ALPHA</constant></entry>
+           <entry>0x0010</entry>
+           <entry>The device supports clipping/blending using the
+alpha channel of the framebuffer or VGA signal. Alpha blending makes
+no sense for destructive overlays.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_CAP_GLOBAL_ALPHA</constant></entry>
+           <entry>0x0020</entry>
+           <entry>The device supports alpha blending using a global
+alpha value. Alpha blending makes no sense for destructive overlays.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_CAP_LOCAL_INV_ALPHA</constant></entry>
+           <entry>0x0040</entry>
+           <entry>The device supports clipping/blending using the
+inverted alpha channel of the framebuffer or VGA signal. Alpha
+blending makes no sense for destructive overlays.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_CAP_SRC_CHROMAKEY</constant></entry>
+           <entry>0x0080</entry>
+           <entry>The device supports Source Chroma-keying. Framebuffer pixels
+with the chroma-key colors are replaced by video pixels, which is exactly opposite of
+<constant>V4L2_FBUF_CAP_CHROMAKEY</constant></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="framebuffer-flags">
+      <title>Frame Buffer Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_FBUF_FLAG_PRIMARY</constant></entry>
+           <entry>0x0001</entry>
+           <entry>The framebuffer is the primary graphics surface.
+In other words, the overlay is destructive. [?]</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_FLAG_OVERLAY</constant></entry>
+           <entry>0x0002</entry>
+           <entry>The frame buffer is an overlay surface the same
+size as the capture. [?]</entry>
+         </row>
+         <row>
+           <entry spanname="hspan">The purpose of
+<constant>V4L2_FBUF_FLAG_PRIMARY</constant> and
+<constant>V4L2_FBUF_FLAG_OVERLAY</constant> was never quite clear.
+Most drivers seem to ignore these flags. For compatibility with the
+<wordasword>bttv</wordasword> driver applications should set the
+<constant>V4L2_FBUF_FLAG_OVERLAY</constant> flag.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_FLAG_CHROMAKEY</constant></entry>
+           <entry>0x0004</entry>
+           <entry>Use chroma-keying. The chroma-key color is
+determined by the <structfield>chromakey</structfield> field of
+&v4l2-window; and negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
+               linkend="overlay" />
+and
+           <xref linkend="osd" />.</entry>
+         </row>
+         <row>
+           <entry spanname="hspan">There are no flags to enable
+clipping using a list of clip rectangles or a bitmap. These methods
+are negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
+               linkend="overlay" /> and <xref linkend="osd" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_FLAG_LOCAL_ALPHA</constant></entry>
+           <entry>0x0008</entry>
+           <entry>Use the alpha channel of the framebuffer to clip or
+blend framebuffer pixels with video images. The blend
+function is: output = framebuffer pixel * alpha + video pixel * (1 -
+alpha). The actual alpha depth depends on the framebuffer pixel
+format.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_FLAG_GLOBAL_ALPHA</constant></entry>
+           <entry>0x0010</entry>
+           <entry>Use a global alpha value to blend the framebuffer
+with video images. The blend function is: output = (framebuffer pixel
+* alpha + video pixel * (255 - alpha)) / 255. The alpha value is
+determined by the <structfield>global_alpha</structfield> field of
+&v4l2-window; and negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
+               linkend="overlay" />
+and <xref linkend="osd" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_FLAG_LOCAL_INV_ALPHA</constant></entry>
+           <entry>0x0020</entry>
+           <entry>Like
+<constant>V4L2_FBUF_FLAG_LOCAL_ALPHA</constant>, use the alpha channel
+of the framebuffer to clip or blend framebuffer pixels with video
+images, but with an inverted alpha value. The blend function is:
+output = framebuffer pixel * (1 - alpha) + video pixel * alpha. The
+actual alpha depth depends on the framebuffer pixel format.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_FBUF_FLAG_SRC_CHROMAKEY</constant></entry>
+           <entry>0x0040</entry>
+           <entry>Use source chroma-keying. The source chroma-key color is
+determined by the <structfield>chromakey</structfield> field of
+&v4l2-window; and negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
+linkend="overlay" /> and <xref linkend="osd" />.
+Both chroma-keying are mutual exclusive to each other, so same
+<structfield>chromakey</structfield> field of &v4l2-window; is being used.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EPERM</errorcode></term>
+       <listitem>
+         <para><constant>VIDIOC_S_FBUF</constant> can only be called
+by a privileged user to negotiate the parameters for a destructive
+overlay.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <constant>VIDIOC_S_FBUF</constant> parameters are unsuitable.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
new file mode 100644 (file)
index 0000000..17fbda1
--- /dev/null
@@ -0,0 +1,196 @@
+<refentry id="vidioc-g-fmt">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_FMT, VIDIOC_S_FMT,
+VIDIOC_TRY_FMT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_FMT</refname>
+    <refname>VIDIOC_S_FMT</refname>
+    <refname>VIDIOC_TRY_FMT</refname>
+    <refpurpose>Get or set the data format, try a format</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_format
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_FMT, VIDIOC_S_FMT, VIDIOC_TRY_FMT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>These ioctls are used to negotiate the format of data
+(typically image format) exchanged between driver and
+application.</para>
+
+    <para>To query the current parameters applications set the
+<structfield>type</structfield> field of a struct
+<structname>v4l2_format</structname> to the respective buffer (stream)
+type. For example video capture devices use
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> or
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>. When the application
+calls the <constant>VIDIOC_G_FMT</constant> ioctl with a pointer to
+this structure the driver fills the respective member of the
+<structfield>fmt</structfield> union. In case of video capture devices
+that is either the &v4l2-pix-format; <structfield>pix</structfield> or
+the &v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member.
+When the requested buffer type is not supported drivers return an
+&EINVAL;.</para>
+
+    <para>To change the current format parameters applications
+initialize the <structfield>type</structfield> field and all
+fields of the respective <structfield>fmt</structfield>
+union member. For details see the documentation of the various devices
+types in <xref linkend="devices" />. Good practice is to query the
+current parameters first, and to
+modify only those parameters not suitable for the application. When
+the application calls the <constant>VIDIOC_S_FMT</constant> ioctl
+with a pointer to a <structname>v4l2_format</structname> structure
+the driver checks
+and adjusts the parameters against hardware abilities. Drivers
+should not return an error code unless the input is ambiguous, this is
+a mechanism to fathom device capabilities and to approach parameters
+acceptable for both the application and driver. On success the driver
+may program the hardware, allocate resources and generally prepare for
+data exchange.
+Finally the <constant>VIDIOC_S_FMT</constant> ioctl returns the
+current format parameters as <constant>VIDIOC_G_FMT</constant> does.
+Very simple, inflexible devices may even ignore all input and always
+return the default parameters. However all V4L2 devices exchanging
+data with the application must implement the
+<constant>VIDIOC_G_FMT</constant> and
+<constant>VIDIOC_S_FMT</constant> ioctl. When the requested buffer
+type is not supported drivers return an &EINVAL; on a
+<constant>VIDIOC_S_FMT</constant> attempt. When I/O is already in
+progress or the resource is not available for other reasons drivers
+return the &EBUSY;.</para>
+
+    <para>The <constant>VIDIOC_TRY_FMT</constant> ioctl is equivalent
+to <constant>VIDIOC_S_FMT</constant> with one exception: it does not
+change driver state. It can also be called at any time, never
+returning <errorcode>EBUSY</errorcode>. This function is provided to
+negotiate parameters, to learn about hardware limitations, without
+disabling I/O or possibly time consuming hardware preparations.
+Although strongly recommended drivers are not required to implement
+this ioctl.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-format">
+      <title>struct <structname>v4l2_format</structname></title>
+      <tgroup cols="4">
+       <colspec colname="c1" />
+       <colspec colname="c2" />
+       <colspec colname="c3" />
+       <colspec colname="c4" />
+       <tbody valign="top">
+         <row>
+           <entry>&v4l2-buf-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry>Type of the data stream, see <xref
+               linkend="v4l2-buf-type" />.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry><structfield>fmt</structfield></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-pix-format;</entry>
+           <entry><structfield>pix</structfield></entry>
+           <entry>Definition of an image format, see <xref
+               linkend="pixfmt" />, used by video capture and output
+devices.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-pix-format-mplane;</entry>
+           <entry><structfield>pix_mp</structfield></entry>
+           <entry>Definition of an image format, see <xref
+               linkend="pixfmt" />, used by video capture and output
+devices that support the <link linkend="planar-apis">multi-planar
+version of the API</link>.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-window;</entry>
+           <entry><structfield>win</structfield></entry>
+           <entry>Definition of an overlaid image, see <xref
+           linkend="overlay" />, used by video overlay devices.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-vbi-format;</entry>
+           <entry><structfield>vbi</structfield></entry>
+           <entry>Raw VBI capture or output parameters. This is
+discussed in more detail in <xref linkend="raw-vbi" />. Used by raw VBI
+capture and output devices.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-sliced-vbi-format;</entry>
+           <entry><structfield>sliced</structfield></entry>
+           <entry>Sliced VBI capture or output parameters. See
+<xref linkend="sliced" /> for details. Used by sliced VBI
+capture and output devices.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u8</entry>
+           <entry><structfield>raw_data</structfield>[200]</entry>
+           <entry>Place holder for future extensions and custom
+(driver defined) formats with <structfield>type</structfield>
+<constant>V4L2_BUF_TYPE_PRIVATE</constant> and higher.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-format; <structfield>type</structfield>
+field is invalid, the requested buffer type not supported, or the
+format is not supported with this buffer type.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
new file mode 100644 (file)
index 0000000..062d720
--- /dev/null
@@ -0,0 +1,145 @@
+<refentry id="vidioc-g-frequency">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_FREQUENCY</refname>
+    <refname>VIDIOC_S_FREQUENCY</refname>
+    <refpurpose>Get or set tuner or modulator radio
+frequency</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_frequency
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const struct v4l2_frequency
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To get the current tuner or modulator radio frequency
+applications set the <structfield>tuner</structfield> field of a
+&v4l2-frequency; to the respective tuner or modulator number (only
+input devices have tuners, only output devices have modulators), zero
+out the <structfield>reserved</structfield> array and
+call the <constant>VIDIOC_G_FREQUENCY</constant> ioctl with a pointer
+to this structure. The driver stores the current frequency in the
+<structfield>frequency</structfield> field.</para>
+
+    <para>To change the current tuner or modulator radio frequency
+applications initialize the <structfield>tuner</structfield>,
+<structfield>type</structfield> and
+<structfield>frequency</structfield> fields, and the
+<structfield>reserved</structfield> array of a &v4l2-frequency; and
+call the <constant>VIDIOC_S_FREQUENCY</constant> ioctl with a pointer
+to this structure. When the requested frequency is not possible the
+driver assumes the closest possible value. However
+<constant>VIDIOC_S_FREQUENCY</constant> is a write-only ioctl, it does
+not return the actual new frequency.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-frequency">
+      <title>struct <structname>v4l2_frequency</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>tuner</structfield></entry>
+           <entry>The tuner or modulator index number. This is the
+same value as in the &v4l2-input; <structfield>tuner</structfield>
+field and the &v4l2-tuner; <structfield>index</structfield> field, or
+the &v4l2-output; <structfield>modulator</structfield> field and the
+&v4l2-modulator; <structfield>index</structfield> field.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-tuner-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>The tuner type. This is the same value as in the
+&v4l2-tuner; <structfield>type</structfield> field. The field is not
+applicable to modulators, &ie; ignored by drivers.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>frequency</structfield></entry>
+           <entry>Tuning frequency in units of 62.5 kHz, or if the
+&v4l2-tuner; or &v4l2-modulator; <structfield>capabilities</structfield> flag
+<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
+Hz.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[8]</entry>
+           <entry>Reserved for future extensions. Drivers and
+           applications must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <structfield>tuner</structfield> index is out of
+bounds or the value in the <structfield>type</structfield> field is
+wrong.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-input.xml b/Documentation/DocBook/media/v4l/vidioc-g-input.xml
new file mode 100644 (file)
index 0000000..08ae82f
--- /dev/null
@@ -0,0 +1,83 @@
+<refentry id="vidioc-g-input">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_INPUT, VIDIOC_S_INPUT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_INPUT</refname>
+    <refname>VIDIOC_S_INPUT</refname>
+    <refpurpose>Query or select the current video input</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>int *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_INPUT, VIDIOC_S_INPUT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the current video input applications call the
+<constant>VIDIOC_G_INPUT</constant> ioctl with a pointer to an integer
+where the driver stores the number of the input, as in the
+&v4l2-input; <structfield>index</structfield> field. This ioctl will
+fail only when there are no video inputs, returning
+<errorcode>EINVAL</errorcode>.</para>
+
+    <para>To select a video input applications store the number of the
+desired input in an integer and call the
+<constant>VIDIOC_S_INPUT</constant> ioctl with a pointer to this
+integer. Side effects are possible. For example inputs may support
+different video standards, so the driver may implicitly switch the
+current standard. It is good practice to select an input before
+querying or negotiating any other parameters.</para>
+
+    <para>Information about video inputs is available using the
+&VIDIOC-ENUMINPUT; ioctl.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The number of the video input is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml b/Documentation/DocBook/media/v4l/vidioc-g-jpegcomp.xml
new file mode 100644 (file)
index 0000000..01ea24b
--- /dev/null
@@ -0,0 +1,163 @@
+<refentry id="vidioc-g-jpegcomp">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_JPEGCOMP</refname>
+    <refname>VIDIOC_S_JPEGCOMP</refname>
+    <refpurpose></refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>v4l2_jpegcompression *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const v4l2_jpegcompression *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>[to do]</para>
+
+    <para>Ronald Bultje elaborates:</para>
+
+    <!-- See video4linux-list@redhat.com on 16 Oct 2002, subject
+"Re: [V4L] Re: v4l2 api / Zoran v4l2_jpegcompression" -->
+
+    <para>APP is some application-specific information. The
+application can set it itself, and it'll be stored in the JPEG-encoded
+fields (eg; interlacing information for in an AVI or so). COM is the
+same, but it's comments, like 'encoded by me' or so.</para>
+
+    <para>jpeg_markers describes whether the huffman tables,
+quantization tables and the restart interval information (all
+JPEG-specific stuff) should be stored in the JPEG-encoded fields.
+These define how the JPEG field is encoded. If you omit them,
+applications assume you've used standard encoding. You usually do want
+to add them.</para>
+
+    <!-- NB VIDIOC_S_JPEGCOMP is w/o. -->
+
+    <table pgwide="1" frame="none" id="v4l2-jpegcompression">
+      <title>struct <structname>v4l2_jpegcompression</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>int</entry>
+           <entry><structfield>quality</structfield></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>int</entry>
+           <entry><structfield>APPn</structfield></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>int</entry>
+           <entry><structfield>APP_len</structfield></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>char</entry>
+           <entry><structfield>APP_data</structfield>[60]</entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>int</entry>
+           <entry><structfield>COM_len</structfield></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>char</entry>
+           <entry><structfield>COM_data</structfield>[60]</entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>jpeg_markers</structfield></entry>
+           <entry>See <xref linkend="jpeg-markers" />.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="jpeg-markers">
+      <title>JPEG Markers Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_JPEG_MARKER_DHT</constant></entry>
+           <entry>(1&lt;&lt;3)</entry>
+           <entry>Define Huffman Tables</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_JPEG_MARKER_DQT</constant></entry>
+           <entry>(1&lt;&lt;4)</entry>
+           <entry>Define Quantization Tables</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_JPEG_MARKER_DRI</constant></entry>
+           <entry>(1&lt;&lt;5)</entry>
+           <entry>Define Restart Interval</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_JPEG_MARKER_COM</constant></entry>
+           <entry>(1&lt;&lt;6)</entry>
+           <entry>Comment segment</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_JPEG_MARKER_APP</constant></entry>
+           <entry>(1&lt;&lt;7)</entry>
+           <entry>App segment, driver will always use APP0</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
new file mode 100644 (file)
index 0000000..15ce660
--- /dev/null
@@ -0,0 +1,246 @@
+<refentry id="vidioc-g-modulator">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_MODULATOR</refname>
+    <refname>VIDIOC_S_MODULATOR</refname>
+    <refpurpose>Get or set modulator attributes</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_modulator
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const struct v4l2_modulator
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the attributes of a modulator applications initialize
+the <structfield>index</structfield> field and zero out the
+<structfield>reserved</structfield> array of a &v4l2-modulator; and
+call the <constant>VIDIOC_G_MODULATOR</constant> ioctl with a pointer
+to this structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all modulators
+applications shall begin at index zero, incrementing by one until the
+driver returns <errorcode>EINVAL</errorcode>.</para>
+
+    <para>Modulators have two writable properties, an audio
+modulation set and the radio frequency. To change the modulated audio
+subprograms, applications initialize the <structfield>index
+</structfield> and <structfield>txsubchans</structfield> fields and the
+<structfield>reserved</structfield> array and call the
+<constant>VIDIOC_S_MODULATOR</constant> ioctl. Drivers may choose a
+different audio modulation if the request cannot be satisfied. However
+this is a write-only ioctl, it does not return the actual audio
+modulation selected.</para>
+
+    <para>To change the radio frequency the &VIDIOC-S-FREQUENCY; ioctl
+is available.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-modulator">
+      <title>struct <structname>v4l2_modulator</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Identifies the modulator, set by the
+application.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>name</structfield>[32]</entry>
+           <entry>Name of the modulator, a NUL-terminated ASCII
+string. This information is intended for the user.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capability</structfield></entry>
+           <entry>Modulator capability flags. No flags are defined
+for this field, the tuner flags in &v4l2-tuner;
+are used accordingly. The audio flags indicate the ability
+to encode audio subprograms. They will <emphasis>not</emphasis>
+change for example with the current video standard.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>rangelow</structfield></entry>
+           <entry>The lowest tunable frequency in units of 62.5
+KHz, or if the <structfield>capability</structfield> flag
+<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
+Hz.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>rangehigh</structfield></entry>
+           <entry>The highest tunable frequency in units of 62.5
+KHz, or if the <structfield>capability</structfield> flag
+<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
+Hz.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>txsubchans</structfield></entry>
+           <entry>With this field applications can determine how
+audio sub-carriers shall be modulated. It contains a set of flags as
+defined in <xref linkend="modulator-txsubchans" />. Note the tuner
+<structfield>rxsubchans</structfield> flags are reused, but the
+semantics are different. Video output devices are assumed to have an
+analog or PCM audio input with 1-3 channels. The
+<structfield>txsubchans</structfield> flags select one or more
+channels for modulation, together with some audio subprogram
+indicator, for example a stereo pilot tone.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[4]</entry>
+           <entry>Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="modulator-txsubchans">
+      <title>Modulator Audio Transmission Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_MONO</constant></entry>
+           <entry>0x0001</entry>
+           <entry>Modulate channel 1 as mono audio, when the input
+has more channels, a down-mix of channel 1 and 2. This flag does not
+combine with <constant>V4L2_TUNER_SUB_STEREO</constant> or
+<constant>V4L2_TUNER_SUB_LANG1</constant>.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_STEREO</constant></entry>
+           <entry>0x0002</entry>
+           <entry>Modulate channel 1 and 2 as left and right
+channel of a stereo audio signal. When the input has only one channel
+or two channels and <constant>V4L2_TUNER_SUB_SAP</constant> is also
+set, channel 1 is encoded as left and right channel. This flag does
+not combine with <constant>V4L2_TUNER_SUB_MONO</constant> or
+<constant>V4L2_TUNER_SUB_LANG1</constant>. When the driver does not
+support stereo audio it shall fall back to mono.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_LANG1</constant></entry>
+           <entry>0x0008</entry>
+           <entry>Modulate channel 1 and 2 as primary and secondary
+language of a bilingual audio signal. When the input has only one
+channel it is used for both languages. It is not possible to encode
+the primary or secondary language only. This flag does not combine
+with <constant>V4L2_TUNER_SUB_MONO</constant>,
+<constant>V4L2_TUNER_SUB_STEREO</constant> or
+<constant>V4L2_TUNER_SUB_SAP</constant>. If the hardware does not
+support the respective audio matrix, or the current video standard
+does not permit bilingual audio the
+<constant>VIDIOC_S_MODULATOR</constant> ioctl shall return an &EINVAL;
+and the driver shall fall back to mono or stereo mode.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_LANG2</constant></entry>
+           <entry>0x0004</entry>
+           <entry>Same effect as
+<constant>V4L2_TUNER_SUB_SAP</constant>.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_SAP</constant></entry>
+           <entry>0x0004</entry>
+           <entry>When combined with <constant>V4L2_TUNER_SUB_MONO
+</constant> the first channel is encoded as mono audio, the last
+channel as Second Audio Program. When the input has only one channel
+it is used for both audio tracks. When the input has three channels
+the mono track is a down-mix of channel 1 and 2. When combined with
+<constant>V4L2_TUNER_SUB_STEREO</constant> channel 1 and 2 are
+encoded as left and right stereo audio, channel 3 as Second Audio
+Program. When the input has only two channels, the first is encoded as
+left and right channel and the second as SAP. When the input has only
+one channel it is used for all audio tracks. It is not possible to
+encode a Second Audio Program only. This flag must combine with
+<constant>V4L2_TUNER_SUB_MONO</constant> or
+<constant>V4L2_TUNER_SUB_STEREO</constant>. If the hardware does not
+support the respective audio matrix, or the current video standard
+does not permit SAP the <constant>VIDIOC_S_MODULATOR</constant> ioctl
+shall return an &EINVAL; and driver shall fall back to mono or stereo
+mode.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_RDS</constant></entry>
+           <entry>0x0010</entry>
+           <entry>Enable the RDS encoder for a radio FM transmitter.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-modulator;
+<structfield>index</structfield> is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-output.xml b/Documentation/DocBook/media/v4l/vidioc-g-output.xml
new file mode 100644 (file)
index 0000000..fd45f1c
--- /dev/null
@@ -0,0 +1,84 @@
+<refentry id="vidioc-g-output">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_OUTPUT</refname>
+    <refname>VIDIOC_S_OUTPUT</refname>
+    <refpurpose>Query or select the current video output</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>int *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the current video output applications call the
+<constant>VIDIOC_G_OUTPUT</constant> ioctl with a pointer to an integer
+where the driver stores the number of the output, as in the
+&v4l2-output; <structfield>index</structfield> field. This ioctl
+will fail only when there are no video outputs, returning the
+&EINVAL;.</para>
+
+    <para>To select a video output applications store the number of the
+desired output in an integer and call the
+<constant>VIDIOC_S_OUTPUT</constant> ioctl with a pointer to this integer.
+Side effects are possible. For example outputs may support different
+video standards, so the driver may implicitly switch the current
+standard. It is good practice to select an output before querying or
+negotiating any other parameters.</para>
+
+    <para>Information about video outputs is available using the
+&VIDIOC-ENUMOUTPUT; ioctl.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The number of the video output is out of bounds, or
+there are no video outputs at all.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-parm.xml b/Documentation/DocBook/media/v4l/vidioc-g-parm.xml
new file mode 100644 (file)
index 0000000..19b1d85
--- /dev/null
@@ -0,0 +1,315 @@
+<refentry id="vidioc-g-parm">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_PARM, VIDIOC_S_PARM</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_PARM</refname>
+    <refname>VIDIOC_S_PARM</refname>
+    <refpurpose>Get or set streaming parameters</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>v4l2_streamparm *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_PARM, VIDIOC_S_PARM</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The current video standard determines a nominal number of
+frames per second. If less than this number of frames is to be
+captured or output, applications can request frame skipping or
+duplicating on the driver side. This is especially useful when using
+the <function>read()</function> or <function>write()</function>, which
+are not augmented by timestamps or sequence counters, and to avoid
+unnecessary data copying.</para>
+
+    <para>Further these ioctls can be used to determine the number of
+buffers used internally by a driver in read/write mode. For
+implications see the section discussing the &func-read;
+function.</para>
+
+    <para>To get and set the streaming parameters applications call
+the <constant>VIDIOC_G_PARM</constant> and
+<constant>VIDIOC_S_PARM</constant> ioctl, respectively. They take a
+pointer to a struct <structname>v4l2_streamparm</structname> which
+contains a union holding separate parameters for input and output
+devices.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-streamparm">
+      <title>struct <structname>v4l2_streamparm</structname></title>
+      <tgroup cols="4">
+       &cs-ustr;
+       <tbody valign="top">
+         <row>
+           <entry>&v4l2-buf-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry>The buffer (stream) type, same as &v4l2-format;
+<structfield>type</structfield>, set by the application.</entry>
+         </row>
+         <row>
+           <entry>union</entry>
+           <entry><structfield>parm</structfield></entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-captureparm;</entry>
+           <entry><structfield>capture</structfield></entry>
+           <entry>Parameters for capture devices, used when
+<structfield>type</structfield> is
+<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>&v4l2-outputparm;</entry>
+           <entry><structfield>output</structfield></entry>
+           <entry>Parameters for output devices, used when
+<structfield>type</structfield> is
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__u8</entry>
+           <entry><structfield>raw_data</structfield>[200]</entry>
+           <entry>A place holder for future extensions and custom
+(driver defined) buffer types <constant>V4L2_BUF_TYPE_PRIVATE</constant> and
+higher.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-captureparm">
+      <title>struct <structname>v4l2_captureparm</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capability</structfield></entry>
+           <entry>See <xref linkend="parm-caps" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capturemode</structfield></entry>
+           <entry>Set by drivers and applications, see <xref linkend="parm-flags" />.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>timeperframe</structfield></entry>
+           <entry><para>This is is the desired period between
+successive frames captured by the driver, in seconds. The
+field is intended to skip frames on the driver side, saving I/O
+bandwidth.</para><para>Applications store here the desired frame
+period, drivers return the actual frame period, which must be greater
+or equal to the nominal frame period determined by the current video
+standard (&v4l2-standard; <structfield>frameperiod</structfield>
+field). Changing the video standard (also implicitly by switching the
+video input) may reset this parameter to the nominal frame period. To
+reset manually applications can just set this field to
+zero.</para><para>Drivers support this function only when they set the
+<constant>V4L2_CAP_TIMEPERFRAME</constant> flag in the
+<structfield>capability</structfield> field.</para></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>extendedmode</structfield></entry>
+           <entry>Custom (driver specific) streaming parameters. When
+unused, applications and drivers must set this field to zero.
+Applications using this field should check the driver name and
+version, see <xref linkend="querycap" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>readbuffers</structfield></entry>
+           <entry>Applications set this field to the desired number
+of buffers used internally by the driver in &func-read; mode. Drivers
+return the actual number of buffers. When an application requests zero
+buffers, drivers should just return the current setting rather than
+the minimum or an error code. For details see <xref
+               linkend="rw" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[4]</entry>
+           <entry>Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-outputparm">
+      <title>struct <structname>v4l2_outputparm</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capability</structfield></entry>
+           <entry>See <xref linkend="parm-caps" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>outputmode</structfield></entry>
+           <entry>Set by drivers and applications, see <xref
+           linkend="parm-flags" />.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>timeperframe</structfield></entry>
+           <entry>This is is the desired period between
+successive frames output by the driver, in seconds.</entry>
+         </row>
+         <row>
+           <entry spanname="hspan"><para>The field is intended to
+repeat frames on the driver side in &func-write; mode (in streaming
+mode timestamps can be used to throttle the output), saving I/O
+bandwidth.</para><para>Applications store here the desired frame
+period, drivers return the actual frame period, which must be greater
+or equal to the nominal frame period determined by the current video
+standard (&v4l2-standard; <structfield>frameperiod</structfield>
+field). Changing the video standard (also implicitly by switching the
+video output) may reset this parameter to the nominal frame period. To
+reset manually applications can just set this field to
+zero.</para><para>Drivers support this function only when they set the
+<constant>V4L2_CAP_TIMEPERFRAME</constant> flag in the
+<structfield>capability</structfield> field.</para></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>extendedmode</structfield></entry>
+           <entry>Custom (driver specific) streaming parameters. When
+unused, applications and drivers must set this field to zero.
+Applications using this field should check the driver name and
+version, see <xref linkend="querycap" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>writebuffers</structfield></entry>
+           <entry>Applications set this field to the desired number
+of buffers used internally by the driver in
+<function>write()</function> mode. Drivers return the actual number of
+buffers. When an application requests zero buffers, drivers should
+just return the current setting rather than the minimum or an error
+code. For details see <xref linkend="rw" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[4]</entry>
+           <entry>Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="parm-caps">
+      <title>Streaming Parameters Capabilites</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_CAP_TIMEPERFRAME</constant></entry>
+           <entry>0x1000</entry>
+           <entry>The frame skipping/repeating controlled by the
+<structfield>timeperframe</structfield> field is supported.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="parm-flags">
+      <title>Capture Parameters Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_MODE_HIGHQUALITY</constant></entry>
+           <entry>0x0001</entry>
+           <entry><para>High quality imaging mode. High quality mode
+is intended for still imaging applications. The idea is to get the
+best possible image quality that the hardware can deliver. It is not
+defined how the driver writer may achieve that; it will depend on the
+hardware and the ingenuity of the driver writer. High quality mode is
+a different mode from the the regular motion video capture modes. In
+high quality mode:<itemizedlist>
+                 <listitem>
+                   <para>The driver may be able to capture higher
+resolutions than for motion capture.</para>
+                 </listitem>
+                 <listitem>
+                   <para>The driver may support fewer pixel formats
+than motion capture (eg; true color).</para>
+                 </listitem>
+                 <listitem>
+                   <para>The driver may capture and arithmetically
+combine multiple successive fields or frames to remove color edge
+artifacts and reduce the noise in the video data.
+</para>
+                 </listitem>
+                 <listitem>
+                   <para>The driver may capture images in slices like
+a scanner in order to handle larger format images than would otherwise
+be possible. </para>
+                 </listitem>
+                 <listitem>
+                   <para>An image capture operation may be
+significantly slower than motion capture. </para>
+                 </listitem>
+                 <listitem>
+                   <para>Moving objects in the image might have
+excessive motion blur. </para>
+                 </listitem>
+                 <listitem>
+                   <para>Capture might only work through the
+<function>read()</function> call.</para>
+                 </listitem>
+               </itemizedlist></para></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-priority.xml b/Documentation/DocBook/media/v4l/vidioc-g-priority.xml
new file mode 100644 (file)
index 0000000..8f5e3da
--- /dev/null
@@ -0,0 +1,143 @@
+<refentry id="vidioc-g-priority">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_PRIORITY</refname>
+    <refname>VIDIOC_S_PRIORITY</refname>
+    <refpurpose>Query or request the access priority associated with a
+file descriptor</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>enum v4l2_priority *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const enum v4l2_priority *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para>Pointer to an enum v4l2_priority type.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the current access priority
+applications call the <constant>VIDIOC_G_PRIORITY</constant> ioctl
+with a pointer to an enum v4l2_priority variable where the driver stores
+the current priority.</para>
+
+    <para>To request an access priority applications store the
+desired priority in an enum v4l2_priority variable and call
+<constant>VIDIOC_S_PRIORITY</constant> ioctl with a pointer to this
+variable.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-priority">
+      <title>enum v4l2_priority</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_PRIORITY_UNSET</constant></entry>
+           <entry>0</entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_PRIORITY_BACKGROUND</constant></entry>
+           <entry>1</entry>
+           <entry>Lowest priority, usually applications running in
+background, for example monitoring VBI transmissions. A proxy
+application running in user space will be necessary if multiple
+applications want to read from a device at this priority.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_PRIORITY_INTERACTIVE</constant></entry>
+           <entry>2</entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_PRIORITY_DEFAULT</constant></entry>
+           <entry>2</entry>
+           <entry>Medium priority, usually applications started and
+interactively controlled by the user. For example TV viewers, Teletext
+browsers, or just "panel" applications to change the channel or video
+controls. This is the default priority unless an application requests
+another.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_PRIORITY_RECORD</constant></entry>
+           <entry>3</entry>
+           <entry>Highest priority. Only one file descriptor can have
+this priority, it blocks any other fd from changing device properties.
+Usually applications which must not be interrupted, like video
+recording.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The requested priority value is invalid.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>Another application already requested higher
+priority.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml
new file mode 100644 (file)
index 0000000..71741da
--- /dev/null
@@ -0,0 +1,255 @@
+<refentry id="vidioc-g-sliced-vbi-cap">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_SLICED_VBI_CAP</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_SLICED_VBI_CAP</refname>
+    <refpurpose>Query sliced VBI capabilities</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_sliced_vbi_cap *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_SLICED_VBI_CAP</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To find out which data services are supported by a sliced
+VBI capture or output device, applications initialize the
+<structfield>type</structfield> field of a &v4l2-sliced-vbi-cap;,
+clear the <structfield>reserved</structfield> array and
+call the <constant>VIDIOC_G_SLICED_VBI_CAP</constant> ioctl. The
+driver fills in the remaining fields or returns an &EINVAL; if the
+sliced VBI API is unsupported or <structfield>type</structfield>
+is invalid.</para>
+
+    <para>Note the <structfield>type</structfield> field was added,
+and the ioctl changed from read-only to write-read, in Linux 2.6.19.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-sliced-vbi-cap">
+      <title>struct <structname>v4l2_sliced_vbi_cap</structname></title>
+      <tgroup cols="5">
+       <colspec colname="c1" colwidth="3*" />
+       <colspec colname="c2" colwidth="3*" />
+       <colspec colname="c3" colwidth="2*" />
+       <colspec colname="c4" colwidth="2*" />
+       <colspec colname="c5" colwidth="2*" />
+       <spanspec spanname="hspan" namest="c3" nameend="c5" />
+       <tbody valign="top">
+         <row>
+           <entry>__u16</entry>
+           <entry><structfield>service_set</structfield></entry>
+           <entry spanname="hspan">A set of all data services
+supported by the driver. Equal to the union of all elements of the
+<structfield>service_lines </structfield> array.</entry>
+         </row>
+         <row>
+           <entry>__u16</entry>
+           <entry><structfield>service_lines</structfield>[2][24]</entry>
+           <entry spanname="hspan">Each element of this array
+contains a set of data services the hardware can look for or insert
+into a particular scan line. Data services are defined in <xref
+               linkend="vbi-services" />. Array indices map to ITU-R
+line numbers (see also <xref
+               linkend="vbi-525" /> and <xref
+linkend="vbi-625" />) as follows:</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry>Element</entry>
+           <entry>525 line systems</entry>
+           <entry>625 line systems</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><structfield>service_lines</structfield>[0][1]</entry>
+           <entry align="center">1</entry>
+           <entry align="center">1</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><structfield>service_lines</structfield>[0][23]</entry>
+           <entry align="center">23</entry>
+           <entry align="center">23</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><structfield>service_lines</structfield>[1][1]</entry>
+           <entry align="center">264</entry>
+           <entry align="center">314</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><structfield>service_lines</structfield>[1][23]</entry>
+           <entry align="center">286</entry>
+           <entry align="center">336</entry>
+         </row>
+         <row>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry spanname="hspan">The number of VBI lines the
+hardware can capture or output per frame, or the number of services it
+can identify on a given line may be limited. For example on PAL line
+16 the hardware may be able to look for a VPS or Teletext signal, but
+not both at the same time. Applications can learn about these limits
+using the &VIDIOC-S-FMT; ioctl as described in <xref
+               linkend="sliced" />.</entry>
+         </row>
+         <row>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry spanname="hspan">Drivers must set
+<structfield>service_lines</structfield>[0][0] and
+<structfield>service_lines</structfield>[1][0] to zero.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-buf-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the data stream, see <xref
+                 linkend="v4l2-buf-type" />. Should be
+<constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant> or
+<constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant>.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[3]</entry>
+           <entry spanname="hspan">This array is reserved for future
+extensions. Applications and drivers must set it to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <!-- See also dev-sliced-vbi.sgml -->
+    <table pgwide="1" frame="none" id="vbi-services">
+      <title>Sliced VBI services</title>
+      <tgroup cols="5">
+       <colspec colname="c1" colwidth="2*" />
+       <colspec colname="c2" colwidth="1*" />
+       <colspec colname="c3" colwidth="1*" />
+       <colspec colname="c4" colwidth="2*" />
+       <colspec colname="c5" colwidth="2*" />
+       <spanspec spanname='rlp' namest='c3' nameend='c5' />
+       <thead>
+         <row>
+           <entry>Symbol</entry>
+           <entry>Value</entry>
+           <entry>Reference</entry>
+           <entry>Lines, usually</entry>
+           <entry>Payload</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_SLICED_TELETEXT_B</constant> (Teletext
+System B)</entry>
+           <entry>0x0001</entry>
+           <entry><xref linkend="ets300706" />, <xref linkend="itu653" /></entry>
+           <entry>PAL/SECAM line 7-22, 320-335 (second field 7-22)</entry>
+           <entry>Last 42 of the 45 byte Teletext packet, that is
+without clock run-in and framing code, lsb first transmitted.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SLICED_VPS</constant></entry>
+           <entry>0x0400</entry>
+           <entry><xref linkend="ets300231" /></entry>
+           <entry>PAL line 16</entry>
+           <entry>Byte number 3 to 15 according to Figure 9 of
+ETS&nbsp;300&nbsp;231, lsb first transmitted.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SLICED_CAPTION_525</constant></entry>
+           <entry>0x1000</entry>
+           <entry><xref linkend="eia608" /></entry>
+           <entry>NTSC line 21, 284 (second field 21)</entry>
+           <entry>Two bytes in transmission order, including parity
+bit, lsb first transmitted.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SLICED_WSS_625</constant></entry>
+           <entry>0x4000</entry>
+           <entry><xref linkend="en300294" />, <xref linkend="itu1119" /></entry>
+           <entry>PAL/SECAM line 23</entry>
+           <entry><screen>
+Byte        0                 1
+     msb         lsb  msb           lsb
+Bit  7 6 5 4 3 2 1 0  x x 13 12 11 10 9
+</screen></entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SLICED_VBI_525</constant></entry>
+           <entry>0x1000</entry>
+           <entry spanname="rlp">Set of services applicable to 525
+line systems.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_SLICED_VBI_625</constant></entry>
+           <entry>0x4401</entry>
+           <entry spanname="rlp">Set of services applicable to 625
+line systems.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The value in the <structfield>type</structfield> field is
+wrong.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-std.xml b/Documentation/DocBook/media/v4l/vidioc-g-std.xml
new file mode 100644 (file)
index 0000000..37996f2
--- /dev/null
@@ -0,0 +1,98 @@
+<refentry id="vidioc-g-std">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_STD, VIDIOC_S_STD</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_STD</refname>
+    <refname>VIDIOC_S_STD</refname>
+    <refpurpose>Query or select the video standard of the current input</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>v4l2_std_id
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const v4l2_std_id
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_STD, VIDIOC_S_STD</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query and select the current video standard applications
+use the <constant>VIDIOC_G_STD</constant> and <constant>VIDIOC_S_STD</constant> ioctls which take a pointer to a
+&v4l2-std-id; type as argument. <constant>VIDIOC_G_STD</constant> can
+return a single flag or a set of flags as in &v4l2-standard; field
+<structfield>id</structfield>. The flags must be unambiguous such
+that they appear in only one enumerated <structname>v4l2_standard</structname> structure.</para>
+
+    <para><constant>VIDIOC_S_STD</constant> accepts one or more
+flags, being a write-only ioctl it does not return the actual new standard as
+<constant>VIDIOC_G_STD</constant> does. When no flags are given or
+the current input does not support the requested standard the driver
+returns an &EINVAL;. When the standard set is ambiguous drivers may
+return <errorcode>EINVAL</errorcode> or choose any of the requested
+standards.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <constant>VIDIOC_S_STD</constant> parameter was unsuitable.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
new file mode 100644 (file)
index 0000000..bd98c73
--- /dev/null
@@ -0,0 +1,535 @@
+<refentry id="vidioc-g-tuner">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_G_TUNER, VIDIOC_S_TUNER</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_G_TUNER</refname>
+    <refname>VIDIOC_S_TUNER</refname>
+    <refpurpose>Get or set tuner attributes</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_tuner
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const struct v4l2_tuner
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_G_TUNER, VIDIOC_S_TUNER</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the attributes of a tuner applications initialize the
+<structfield>index</structfield> field and zero out the
+<structfield>reserved</structfield> array of a &v4l2-tuner; and call the
+<constant>VIDIOC_G_TUNER</constant> ioctl with a pointer to this
+structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all tuners
+applications shall begin at index zero, incrementing by one until the
+driver returns <errorcode>EINVAL</errorcode>.</para>
+
+    <para>Tuners have two writable properties, the audio mode and
+the radio frequency. To change the audio mode, applications initialize
+the <structfield>index</structfield>,
+<structfield>audmode</structfield> and
+<structfield>reserved</structfield> fields and call the
+<constant>VIDIOC_S_TUNER</constant> ioctl. This will
+<emphasis>not</emphasis> change the current tuner, which is determined
+by the current video input. Drivers may choose a different audio mode
+if the requested mode is invalid or unsupported. Since this is a
+<!-- FIXME -->write-only ioctl, it does not return the actually
+selected audio mode.</para>
+
+    <para>To change the radio frequency the &VIDIOC-S-FREQUENCY; ioctl
+is available.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-tuner">
+      <title>struct <structname>v4l2_tuner</structname></title>
+      <tgroup cols="3">
+       <colspec colname="c1" colwidth="1*" />
+       <colspec colname="c2" colwidth="1*" />
+       <colspec colname="c3" colwidth="1*" />
+       <colspec colname="c4" colwidth="1*" />
+       <spanspec spanname="hspan" namest="c3" nameend="c4" />
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry spanname="hspan">Identifies the tuner, set by the
+application.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>name</structfield>[32]</entry>
+           <entry spanname="hspan"><para>Name of the tuner, a
+NUL-terminated ASCII string. This information is intended for the
+user.<!-- FIXME Video inputs already have a name, the purpose of this
+field is not quite clear.--></para></entry>
+         </row>
+         <row>
+           <entry>&v4l2-tuner-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry spanname="hspan">Type of the tuner, see <xref
+               linkend="v4l2-tuner-type" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capability</structfield></entry>
+           <entry spanname="hspan"><para>Tuner capability flags, see
+<xref linkend="tuner-capability" />. Audio flags indicate the ability
+to decode audio subprograms. They will <emphasis>not</emphasis>
+change, for example with the current video standard.</para><para>When
+the structure refers to a radio tuner only the
+<constant>V4L2_TUNER_CAP_LOW</constant>,
+<constant>V4L2_TUNER_CAP_STEREO</constant> and
+<constant>V4L2_TUNER_CAP_RDS</constant> flags can be set.</para></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>rangelow</structfield></entry>
+           <entry spanname="hspan">The lowest tunable frequency in
+units of 62.5 kHz, or if the <structfield>capability</structfield>
+flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
+Hz.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>rangehigh</structfield></entry>
+           <entry spanname="hspan">The highest tunable frequency in
+units of 62.5 kHz, or if the <structfield>capability</structfield>
+flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
+Hz.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>rxsubchans</structfield></entry>
+           <entry spanname="hspan"><para>Some tuners or audio
+decoders can determine the received audio subprograms by analyzing
+audio carriers, pilot tones or other indicators. To pass this
+information drivers set flags defined in <xref
+                 linkend="tuner-rxsubchans" /> in this field. For
+example:</para></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><constant>V4L2_TUNER_SUB_MONO</constant></entry>
+           <entry>receiving mono audio</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><constant>STEREO | SAP</constant></entry>
+           <entry>receiving stereo audio and a secondary audio
+program</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><constant>MONO | STEREO</constant></entry>
+           <entry>receiving mono or stereo audio, the hardware cannot
+distinguish</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><constant>LANG1 | LANG2</constant></entry>
+           <entry>receiving bilingual audio</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry><constant>MONO | STEREO | LANG1 | LANG2</constant></entry>
+           <entry>receiving mono, stereo or bilingual
+audio</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry></entry>
+           <entry spanname="hspan"><para>When the
+<constant>V4L2_TUNER_CAP_STEREO</constant>,
+<constant>_LANG1</constant>, <constant>_LANG2</constant> or
+<constant>_SAP</constant> flag is cleared in the
+<structfield>capability</structfield> field, the corresponding
+<constant>V4L2_TUNER_SUB_</constant> flag must not be set
+here.</para><para>This field is valid only if this is the tuner of the
+current video input, or when the structure refers to a radio
+tuner.</para></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>audmode</structfield></entry>
+           <entry spanname="hspan"><para>The selected audio mode, see
+<xref linkend="tuner-audmode" /> for valid values. The audio mode does
+not affect audio subprogram detection, and like a <link
+linkend="control">control</link> it does not automatically change
+unless the requested mode is invalid or unsupported. See <xref
+                 linkend="tuner-matrix" /> for possible results when
+the selected and received audio programs do not
+match.</para><para>Currently this is the only field of struct
+<structname>v4l2_tuner</structname> applications can
+change.</para></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>signal</structfield></entry>
+           <entry spanname="hspan">The signal strength if known, ranging
+from 0 to 65535. Higher values indicate a better signal.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>afc</structfield></entry>
+           <entry spanname="hspan">Automatic frequency control: When the
+<structfield>afc</structfield> value is negative, the frequency is too
+low, when positive too high.<!-- FIXME need example what to do when it never
+settles at zero, &ie; range is what? --></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[4]</entry>
+           <entry spanname="hspan">Reserved for future extensions. Drivers and
+applications must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-tuner-type">
+      <title>enum v4l2_tuner_type</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_TUNER_RADIO</constant></entry>
+           <entry>1</entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_ANALOG_TV</constant></entry>
+           <entry>2</entry>
+           <entry></entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="tuner-capability">
+      <title>Tuner and Modulator Capability Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_TUNER_CAP_LOW</constant></entry>
+           <entry>0x0001</entry>
+           <entry>When set, tuning frequencies are expressed in units of
+62.5&nbsp;Hz, otherwise in units of 62.5&nbsp;kHz.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_CAP_NORM</constant></entry>
+           <entry>0x0002</entry>
+           <entry>This is a multi-standard tuner; the video standard
+can or must be switched. (B/G PAL tuners for example are typically not
+      considered multi-standard because the video standard is automatically
+      determined from the frequency band.) The set of supported video
+      standards is available from the &v4l2-input; pointing to this tuner,
+      see the description of ioctl &VIDIOC-ENUMINPUT; for details. Only
+      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
+         </row>
+         <row>
+       <entry><constant>V4L2_TUNER_CAP_STEREO</constant></entry>
+       <entry>0x0010</entry>
+       <entry>Stereo audio reception is supported.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_CAP_LANG1</constant></entry>
+           <entry>0x0040</entry>
+           <entry>Reception of the primary language of a bilingual
+audio program is supported. Bilingual audio is a feature of
+two-channel systems, transmitting the primary language monaural on the
+main audio carrier and a secondary language monaural on a second
+carrier. Only
+      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_CAP_LANG2</constant></entry>
+           <entry>0x0020</entry>
+           <entry>Reception of the secondary language of a bilingual
+audio program is supported. Only
+      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_CAP_SAP</constant></entry>
+           <entry>0x0020</entry>
+           <entry><para>Reception of a secondary audio program is
+supported. This is a feature of the BTSC system which accompanies the
+NTSC video standard. Two audio carriers are available for mono or
+stereo transmissions of a primary language, and an independent third
+carrier for a monaural secondary language. Only
+      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</para><para>Note the
+<constant>V4L2_TUNER_CAP_LANG2</constant> and
+<constant>V4L2_TUNER_CAP_SAP</constant> flags are synonyms.
+<constant>V4L2_TUNER_CAP_SAP</constant> applies when the tuner
+supports the <constant>V4L2_STD_NTSC_M</constant> video
+standard.</para><!-- FIXME what if PAL+NTSC and Bi but not SAP? --></entry>
+         </row>
+         <row>
+       <entry><constant>V4L2_TUNER_CAP_RDS</constant></entry>
+       <entry>0x0080</entry>
+       <entry>RDS capture is supported. This capability is only valid for
+radio tuners.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="tuner-rxsubchans">
+      <title>Tuner Audio Reception Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_MONO</constant></entry>
+           <entry>0x0001</entry>
+           <entry>The tuner receives a mono audio signal.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_STEREO</constant></entry>
+           <entry>0x0002</entry>
+           <entry>The tuner receives a stereo audio signal.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_LANG1</constant></entry>
+           <entry>0x0008</entry>
+           <entry>The tuner receives the primary language of a
+bilingual audio signal. Drivers must clear this flag when the current
+video standard is <constant>V4L2_STD_NTSC_M</constant>.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_LANG2</constant></entry>
+           <entry>0x0004</entry>
+           <entry>The tuner receives the secondary language of a
+bilingual audio signal (or a second audio program).</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_SAP</constant></entry>
+           <entry>0x0004</entry>
+           <entry>The tuner receives a Second Audio Program. Note the
+<constant>V4L2_TUNER_SUB_LANG2</constant> and
+<constant>V4L2_TUNER_SUB_SAP</constant> flags are synonyms. The
+<constant>V4L2_TUNER_SUB_SAP</constant> flag applies when the
+current video standard is <constant>V4L2_STD_NTSC_M</constant>.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_SUB_RDS</constant></entry>
+           <entry>0x0010</entry>
+           <entry>The tuner receives an RDS channel.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="tuner-audmode">
+      <title>Tuner Audio Modes</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_TUNER_MODE_MONO</constant></entry>
+           <entry>0</entry>
+           <entry>Play mono audio. When the tuner receives a stereo
+signal this a down-mix of the left and right channel. When the tuner
+receives a bilingual or SAP signal this mode selects the primary
+language.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_MODE_STEREO</constant></entry>
+           <entry>1</entry>
+           <entry><para>Play stereo audio. When the tuner receives
+bilingual audio it may play different languages on the left and right
+channel or the primary language is played on both channels.</para><para>Playing
+different languages in this mode is
+deprecated. New drivers should do this only in
+<constant>MODE_LANG1_LANG2</constant>.</para><para>When the tuner
+receives no stereo signal or does not support stereo reception the
+driver shall fall back to <constant>MODE_MONO</constant>.</para></entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_MODE_LANG1</constant></entry>
+           <entry>3</entry>
+           <entry>Play the primary language, mono or stereo. Only
+<constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this
+mode.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_MODE_LANG2</constant></entry>
+           <entry>2</entry>
+           <entry>Play the secondary language, mono. When the tuner
+receives no bilingual audio or SAP, or their reception is not
+supported the driver shall fall back to mono or stereo mode. Only
+<constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this
+mode.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_MODE_SAP</constant></entry>
+           <entry>2</entry>
+           <entry>Play the Second Audio Program. When the tuner
+receives no bilingual audio or SAP, or their reception is not
+supported the driver shall fall back to mono or stereo mode. Only
+<constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this mode.
+Note the <constant>V4L2_TUNER_MODE_LANG2</constant> and
+<constant>V4L2_TUNER_MODE_SAP</constant> are synonyms.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_TUNER_MODE_LANG1_LANG2</constant></entry>
+           <entry>4</entry>
+           <entry>Play the primary language on the left channel, the
+secondary language on the right channel. When the tuner receives no
+bilingual audio or SAP, it shall fall back to
+<constant>MODE_LANG1</constant> or <constant>MODE_MONO</constant>.
+Only <constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this
+mode.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="all" id="tuner-matrix">
+      <title>Tuner Audio Matrix</title>
+      <tgroup cols="6" align="center">
+       <colspec align="left" />
+       <colspec colname="c2" colwidth="1*" />
+       <colspec colwidth="1*" />
+       <colspec colwidth="1*" />
+       <colspec colnum="6" colname="c6" colwidth="1*" />
+       <spanspec namest="c2" nameend="c6" spanname="hspan" align="center" />
+       <thead>
+         <row>
+           <entry></entry>
+           <entry spanname="hspan">Selected
+<constant>V4L2_TUNER_MODE_</constant></entry>
+         </row>
+         <row>
+           <entry>Received <constant>V4L2_TUNER_SUB_</constant></entry>
+           <entry><constant>MONO</constant></entry>
+           <entry><constant>STEREO</constant></entry>
+           <entry><constant>LANG1</constant></entry>
+           <entry><constant>LANG2 = SAP</constant></entry>
+           <entry><constant>LANG1_LANG2</constant><footnote><para>This
+mode has been added in Linux 2.6.17 and may not be supported by older
+drivers.</para></footnote></entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry><constant>MONO</constant></entry>
+           <entry>Mono</entry>
+           <entry>Mono/Mono</entry>
+           <entry>Mono</entry>
+           <entry>Mono</entry>
+           <entry>Mono/Mono</entry>
+         </row>
+         <row>
+           <entry><constant>MONO | SAP</constant></entry>
+           <entry>Mono</entry>
+           <entry>Mono/Mono</entry>
+           <entry>Mono</entry>
+           <entry>SAP</entry>
+           <entry>Mono/SAP (preferred) or Mono/Mono</entry>
+         </row>
+         <row>
+           <entry><constant>STEREO</constant></entry>
+           <entry>L+R</entry>
+           <entry>L/R</entry>
+           <entry>Stereo L/R (preferred) or Mono L+R</entry>
+           <entry>Stereo L/R (preferred) or Mono L+R</entry>
+           <entry>L/R (preferred) or L+R/L+R</entry>
+         </row>
+         <row>
+           <entry><constant>STEREO | SAP</constant></entry>
+           <entry>L+R</entry>
+           <entry>L/R</entry>
+           <entry>Stereo L/R (preferred) or Mono L+R</entry>
+           <entry>SAP</entry>
+           <entry>L+R/SAP (preferred) or L/R or L+R/L+R</entry>
+         </row>
+         <row>
+           <entry><constant>LANG1 | LANG2</constant></entry>
+           <entry>Language&nbsp;1</entry>
+           <entry>Lang1/Lang2 (deprecated<footnote><para>Playback of
+both languages in <constant>MODE_STEREO</constant> is deprecated. In
+the future drivers should produce only the primary language in this
+mode. Applications should request
+<constant>MODE_LANG1_LANG2</constant> to record both languages or a
+stereo signal.</para></footnote>) or
+Lang1/Lang1</entry>
+           <entry>Language&nbsp;1</entry>
+           <entry>Language&nbsp;2</entry>
+           <entry>Lang1/Lang2 (preferred) or Lang1/Lang1</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-tuner; <structfield>index</structfield> is
+out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-log-status.xml b/Documentation/DocBook/media/v4l/vidioc-log-status.xml
new file mode 100644 (file)
index 0000000..5ded7d3
--- /dev/null
@@ -0,0 +1,41 @@
+<refentry id="vidioc-log-status">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_LOG_STATUS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_LOG_STATUS</refname>
+    <refpurpose>Log driver status information</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>As the video/audio devices become more complicated it
+becomes harder to debug problems. When this ioctl is called the driver
+will output the current device status to the kernel log. This is
+particular useful when dealing with problems like no sound, no video
+and incorrectly tuned channels. Also many modern devices autodetect
+video and audio standards and this ioctl will report what the device
+thinks what the standard is. Mismatches may give an indication where
+the problem is.</para>
+
+    <para>This ioctl is optional and not all drivers support it. It
+was introduced in Linux 2.6.15.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-overlay.xml b/Documentation/DocBook/media/v4l/vidioc-overlay.xml
new file mode 100644 (file)
index 0000000..250a7de
--- /dev/null
@@ -0,0 +1,74 @@
+<refentry id="vidioc-overlay">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_OVERLAY</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_OVERLAY</refname>
+    <refpurpose>Start or stop video overlay</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const int *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_OVERLAY</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>This ioctl is part of the <link linkend="overlay">video
+    overlay</link> I/O method. Applications call
+    <constant>VIDIOC_OVERLAY</constant> to start or stop the
+    overlay. It takes a pointer to an integer which must be set to
+    zero by the application to stop overlay, to one to start.</para>
+
+    <para>Drivers do not support &VIDIOC-STREAMON; or
+&VIDIOC-STREAMOFF; with <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The overlay parameters have not been set up. See <xref
+linkend="overlay" /> for the necessary steps.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml
new file mode 100644 (file)
index 0000000..9caa49a
--- /dev/null
@@ -0,0 +1,177 @@
+<refentry id="vidioc-qbuf">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_QBUF, VIDIOC_DQBUF</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_QBUF</refname>
+    <refname>VIDIOC_DQBUF</refname>
+    <refpurpose>Exchange a buffer with the driver</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_QBUF, VIDIOC_DQBUF</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Applications call the <constant>VIDIOC_QBUF</constant> ioctl
+to enqueue an empty (capturing) or filled (output) buffer in the
+driver's incoming queue. The semantics depend on the selected I/O
+method.</para>
+
+    <para>To enqueue a buffer applications set the <structfield>type</structfield>
+field of a &v4l2-buffer; to the same buffer type as was previously used
+with &v4l2-format; <structfield>type</structfield> and &v4l2-requestbuffers;
+<structfield>type</structfield>. Applications must also set the
+<structfield>index</structfield> field. Valid index numbers range from
+zero to the number of buffers allocated with &VIDIOC-REQBUFS;
+(&v4l2-requestbuffers; <structfield>count</structfield>) minus one. The
+contents of the struct <structname>v4l2_buffer</structname> returned
+by a &VIDIOC-QUERYBUF; ioctl will do as well. When the buffer is
+intended for output (<structfield>type</structfield> is
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
+<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>, or
+<constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant>) applications must also
+initialize the <structfield>bytesused</structfield>,
+<structfield>field</structfield> and
+<structfield>timestamp</structfield> fields, see <xref
+linkend="buffer" /> for details.
+Applications must also set <structfield>flags</structfield> to 0. If a driver
+supports capturing from specific video inputs and you want to specify a video
+input, then <structfield>flags</structfield> should be set to
+<constant>V4L2_BUF_FLAG_INPUT</constant> and the field
+<structfield>input</structfield> must be initialized to the desired input.
+The <structfield>reserved</structfield> field must be set to 0. When using
+the <link linkend="planar-apis">multi-planar API</link>, the
+<structfield>m.planes</structfield> field must contain a userspace pointer
+to a filled-in array of &v4l2-plane; and the <structfield>length</structfield>
+field must be set to the number of elements in that array.
+</para>
+
+    <para>To enqueue a <link linkend="mmap">memory mapped</link>
+buffer applications set the <structfield>memory</structfield>
+field to <constant>V4L2_MEMORY_MMAP</constant>. When
+<constant>VIDIOC_QBUF</constant> is called with a pointer to this
+structure the driver sets the
+<constant>V4L2_BUF_FLAG_MAPPED</constant> and
+<constant>V4L2_BUF_FLAG_QUEUED</constant> flags and clears the
+<constant>V4L2_BUF_FLAG_DONE</constant> flag in the
+<structfield>flags</structfield> field, or it returns an
+&EINVAL;.</para>
+
+    <para>To enqueue a <link linkend="userp">user pointer</link>
+buffer applications set the <structfield>memory</structfield>
+field to <constant>V4L2_MEMORY_USERPTR</constant>, the
+<structfield>m.userptr</structfield> field to the address of the
+buffer and <structfield>length</structfield> to its size. When the multi-planar
+API is used, <structfield>m.userptr</structfield> and
+<structfield>length</structfield> members of the passed array of &v4l2-plane;
+have to be used instead. When <constant>VIDIOC_QBUF</constant> is called with
+a pointer to this structure the driver sets the
+<constant>V4L2_BUF_FLAG_QUEUED</constant> flag and clears the
+<constant>V4L2_BUF_FLAG_MAPPED</constant> and
+<constant>V4L2_BUF_FLAG_DONE</constant> flags in the
+<structfield>flags</structfield> field, or it returns an error code.
+This ioctl locks the memory pages of the buffer in physical memory,
+they cannot be swapped out to disk. Buffers remain locked until
+dequeued, until the &VIDIOC-STREAMOFF; or &VIDIOC-REQBUFS; ioctl is
+called, or until the device is closed.</para>
+
+    <para>Applications call the <constant>VIDIOC_DQBUF</constant>
+ioctl to dequeue a filled (capturing) or displayed (output) buffer
+from the driver's outgoing queue. They just set the
+<structfield>type</structfield>, <structfield>memory</structfield>
+and <structfield>reserved</structfield>
+fields of a &v4l2-buffer; as above, when <constant>VIDIOC_DQBUF</constant>
+is called with a pointer to this structure the driver fills the
+remaining fields or returns an error code. The driver may also set
+<constant>V4L2_BUF_FLAG_ERROR</constant> in the <structfield>flags</structfield>
+field. It indicates a non-critical (recoverable) streaming error. In such case
+the application may continue as normal, but should be aware that data in the
+dequeued buffer might be corrupted. When using the multi-planar API, the
+planes array does not have to be passed; the <structfield>m.planes</structfield>
+member must be set to NULL in that case.</para>
+
+    <para>By default <constant>VIDIOC_DQBUF</constant> blocks when no
+buffer is in the outgoing queue. When the
+<constant>O_NONBLOCK</constant> flag was given to the &func-open;
+function, <constant>VIDIOC_DQBUF</constant> returns immediately
+with an &EAGAIN; when no buffer is available.</para>
+
+    <para>The <structname>v4l2_buffer</structname> structure is
+specified in <xref linkend="buffer" />.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EAGAIN</errorcode></term>
+       <listitem>
+         <para>Non-blocking I/O has been selected using
+<constant>O_NONBLOCK</constant> and no buffer was in the outgoing
+queue.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The buffer <structfield>type</structfield> is not
+supported, or the <structfield>index</structfield> is out of bounds,
+or no buffers have been allocated yet, or the
+<structfield>userptr</structfield> or
+<structfield>length</structfield> are invalid.</para>
+       </listitem>
+       <term><errorcode>EIO</errorcode></term>
+       <listitem>
+         <para><constant>VIDIOC_DQBUF</constant> failed due to an
+internal error. Can also indicate temporary problems like signal
+loss. Note the driver might dequeue an (empty) buffer despite
+returning an error, or even stop capturing. Reusing such buffer may be unsafe
+though and its details (e.g. <structfield>index</structfield>) may not be
+returned either. It is recommended that drivers indicate recoverable errors
+by setting the <constant>V4L2_BUF_FLAG_ERROR</constant> and returning 0 instead.
+In that case the application should be able to safely reuse the buffer and
+continue streaming.
+       </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml
new file mode 100644 (file)
index 0000000..23b17f6
--- /dev/null
@@ -0,0 +1,65 @@
+<refentry id="vidioc-query-dv-preset">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_QUERY_DV_PRESET</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_QUERY_DV_PRESET</refname>
+    <refpurpose>Sense the DV preset received by the current
+input</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_dv_preset *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+       <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_QUERY_DV_PRESET</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The hardware may be able to detect the current DV preset
+automatically, similar to sensing the video standard. To do so, applications
+call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a
+&v4l2-dv-preset; type. Once the hardware detects a preset, that preset is
+returned in the preset field of &v4l2-dv-preset;. If the preset could not be
+detected because there was no signal, or the signal was unreliable, or the
+signal did not map to a supported preset, then the value V4L2_DV_INVALID is
+returned.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml
new file mode 100644 (file)
index 0000000..5c104d4
--- /dev/null
@@ -0,0 +1,110 @@
+<refentry id="vidioc-querybuf">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_QUERYBUF</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_QUERYBUF</refname>
+    <refpurpose>Query the status of a buffer</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_QUERYBUF</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>This ioctl is part of the <link linkend="mmap">memory
+mapping</link> I/O method. It can be used to query the status of a
+buffer at any time after buffers have been allocated with the
+&VIDIOC-REQBUFS; ioctl.</para>
+
+    <para>Applications set the <structfield>type</structfield> field
+    of a &v4l2-buffer; to the same buffer type as was previously used with
+&v4l2-format; <structfield>type</structfield> and &v4l2-requestbuffers;
+<structfield>type</structfield>, and the <structfield>index</structfield>
+    field. Valid index numbers range from zero
+to the number of buffers allocated with &VIDIOC-REQBUFS;
+    (&v4l2-requestbuffers; <structfield>count</structfield>) minus one.
+The <structfield>reserved</structfield> field should to set to 0.
+When using the <link linkend="planar-apis">multi-planar API</link>, the
+<structfield>m.planes</structfield> field must contain a userspace pointer to an
+array of &v4l2-plane; and the <structfield>length</structfield> field has
+to be set to the number of elements in that array.
+After calling <constant>VIDIOC_QUERYBUF</constant> with a pointer to
+    this structure drivers return an error code or fill the rest of
+the structure.</para>
+
+    <para>In the <structfield>flags</structfield> field the
+<constant>V4L2_BUF_FLAG_MAPPED</constant>,
+<constant>V4L2_BUF_FLAG_QUEUED</constant> and
+<constant>V4L2_BUF_FLAG_DONE</constant> flags will be valid. The
+<structfield>memory</structfield> field will be set to the current
+I/O method. For the single-planar API, the <structfield>m.offset</structfield>
+contains the offset of the buffer from the start of the device memory,
+the <structfield>length</structfield> field its size. For the multi-planar API,
+fields <structfield>m.mem_offset</structfield> and
+<structfield>length</structfield> in the <structfield>m.planes</structfield>
+array elements will be used instead. The driver may or may not set the remaining
+fields and flags, they are meaningless in this context.</para>
+
+    <para>The <structname>v4l2_buffer</structname> structure is
+    specified in <xref linkend="buffer" />.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The buffer <structfield>type</structfield> is not
+supported, or the <structfield>index</structfield> is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-querycap.xml b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
new file mode 100644 (file)
index 0000000..e3664d6
--- /dev/null
@@ -0,0 +1,287 @@
+<refentry id="vidioc-querycap">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_QUERYCAP</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_QUERYCAP</refname>
+    <refpurpose>Query device capabilities</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_capability *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_QUERYCAP</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>All V4L2 devices support the
+<constant>VIDIOC_QUERYCAP</constant> ioctl. It is used to identify
+kernel devices compatible with this specification and to obtain
+information about driver and hardware capabilities. The ioctl takes a
+pointer to a &v4l2-capability; which is filled by the driver. When the
+driver is not compatible with this specification the ioctl returns an
+&EINVAL;.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-capability">
+      <title>struct <structname>v4l2_capability</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>driver</structfield>[16]</entry>
+           <entry><para>Name of the driver, a unique NUL-terminated
+ASCII string. For example: "bttv". Driver specific applications can
+use this information to verify the driver identity. It is also useful
+to work around known bugs, or to identify drivers in error reports.</para>
+<para>Storing strings in fixed sized arrays is bad
+practice but unavoidable here. Drivers and applications should take
+precautions to never read or write beyond the end of the array and to
+make sure the strings are properly NUL-terminated.</para></entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>card</structfield>[32]</entry>
+           <entry>Name of the device, a NUL-terminated ASCII string.
+For example: "Yoyodyne TV/FM". One driver may support different brands
+or models of video hardware. This information is intended for users,
+for example in a menu of available devices. Since multiple TV cards of
+the same brand may be installed which are supported by the same
+driver, this name should be combined with the character device file
+name (&eg; <filename>/dev/video2</filename>) or the
+<structfield>bus_info</structfield> string to avoid
+ambiguities.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>bus_info</structfield>[32]</entry>
+           <entry>Location of the device in the system, a
+NUL-terminated ASCII string. For example: "PCI Slot 4". This
+information is intended for users, to distinguish multiple
+identical devices. If no such information is available the field may
+simply count the devices controlled by the driver, or contain the
+empty string (<structfield>bus_info</structfield>[0] = 0).<!-- XXX pci_dev->slot_name example --></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>version</structfield></entry>
+           <entry><para>Version number of the driver.</para>
+<para>Starting on kernel 3.1, the version reported is provided per
+V4L2 subsystem, following the same Kernel numberation scheme. However, it
+should not always return the same version as the kernel, if, for example,
+an stable or distribution-modified kernel uses the V4L2 stack from a
+newer kernel.</para>
+<para>The version number is formatted using the
+<constant>KERNEL_VERSION()</constant> macro:</para></entry>
+         </row>
+         <row>
+           <entry spanname="hspan"><para>
+<programlisting>
+#define KERNEL_VERSION(a,b,c) (((a) &lt;&lt; 16) + ((b) &lt;&lt; 8) + (c))
+
+__u32 version = KERNEL_VERSION(0, 8, 1);
+
+printf ("Version: %u.%u.%u\n",
+       (version &gt;&gt; 16) &amp; 0xFF,
+       (version &gt;&gt; 8) &amp; 0xFF,
+        version &amp; 0xFF);
+</programlisting></para></entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>capabilities</structfield></entry>
+           <entry>Device capabilities, see <xref
+               linkend="device-capabilities" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[4]</entry>
+           <entry>Reserved for future extensions. Drivers must set
+this array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="device-capabilities">
+      <title>Device Capabilities Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_CAP_VIDEO_CAPTURE</constant></entry>
+           <entry>0x00000001</entry>
+           <entry>The device supports the single-planar API through the <link
+linkend="capture">Video Capture</link> interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_VIDEO_CAPTURE_MPLANE</constant></entry>
+           <entry>0x00001000</entry>
+           <entry>The device supports the
+           <link linkend="planar-apis">multi-planar API</link> through the
+           <link linkend="capture">Video Capture</link> interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_VIDEO_OUTPUT</constant></entry>
+           <entry>0x00000002</entry>
+           <entry>The device supports the single-planar API through the <link
+linkend="output">Video Output</link> interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_VIDEO_OUTPUT_MPLANE</constant></entry>
+           <entry>0x00002000</entry>
+           <entry>The device supports the
+           <link linkend="planar-apis">multi-planar API</link> through the
+           <link linkend="output">Video Output</link> interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_VIDEO_OVERLAY</constant></entry>
+           <entry>0x00000004</entry>
+           <entry>The device supports the <link
+linkend="overlay">Video Overlay</link> interface. A video overlay device
+typically stores captured images directly in the video memory of a
+graphics card, with hardware clipping and scaling.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_VBI_CAPTURE</constant></entry>
+           <entry>0x00000010</entry>
+           <entry>The device supports the <link linkend="raw-vbi">Raw
+VBI Capture</link> interface, providing Teletext and Closed Caption
+data.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_VBI_OUTPUT</constant></entry>
+           <entry>0x00000020</entry>
+           <entry>The device supports the <link linkend="raw-vbi">Raw VBI Output</link> interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_SLICED_VBI_CAPTURE</constant></entry>
+           <entry>0x00000040</entry>
+           <entry>The device supports the <link linkend="sliced">Sliced VBI Capture</link> interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_SLICED_VBI_OUTPUT</constant></entry>
+           <entry>0x00000080</entry>
+           <entry>The device supports the <link linkend="sliced">Sliced VBI Output</link> interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_RDS_CAPTURE</constant></entry>
+           <entry>0x00000100</entry>
+           <entry>The device supports the <link linkend="rds">RDS</link> capture interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant></entry>
+           <entry>0x00000200</entry>
+           <entry>The device supports the <link linkend="osd">Video
+Output Overlay</link> (OSD) interface. Unlike the <wordasword>Video
+Overlay</wordasword> interface, this is a secondary function of video
+output devices and overlays an image onto an outgoing video signal.
+When the driver sets this flag, it must clear the
+<constant>V4L2_CAP_VIDEO_OVERLAY</constant> flag and vice
+versa.<footnote><para>The &v4l2-framebuffer; lacks an
+&v4l2-buf-type; field, therefore the type of overlay is implied by the
+driver capabilities.</para></footnote></entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_HW_FREQ_SEEK</constant></entry>
+           <entry>0x00000400</entry>
+           <entry>The device supports the &VIDIOC-S-HW-FREQ-SEEK; ioctl for
+hardware frequency seeking.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_RDS_OUTPUT</constant></entry>
+           <entry>0x00000800</entry>
+           <entry>The device supports the <link linkend="rds">RDS</link> output interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_TUNER</constant></entry>
+           <entry>0x00010000</entry>
+           <entry>The device has some sort of tuner to
+receive RF-modulated video signals. For more information about
+tuner programming see
+<xref linkend="tuner" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_AUDIO</constant></entry>
+           <entry>0x00020000</entry>
+           <entry>The device has audio inputs or outputs. It may or
+may not support audio recording or playback, in PCM or compressed
+formats. PCM audio support must be implemented as ALSA or OSS
+interface. For more information on audio inputs and outputs see <xref
+               linkend="audio" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_RADIO</constant></entry>
+           <entry>0x00040000</entry>
+           <entry>This is a radio receiver.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_MODULATOR</constant></entry>
+           <entry>0x00080000</entry>
+           <entry>The device has some sort of modulator to
+emit RF-modulated video/audio signals. For more information about
+modulator programming see
+<xref linkend="tuner" />.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_READWRITE</constant></entry>
+           <entry>0x01000000</entry>
+           <entry>The device supports the <link
+linkend="rw">read()</link> and/or <link linkend="rw">write()</link>
+I/O methods.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_ASYNCIO</constant></entry>
+           <entry>0x02000000</entry>
+           <entry>The device supports the <link
+linkend="async">asynchronous</link> I/O methods.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CAP_STREAMING</constant></entry>
+           <entry>0x04000000</entry>
+           <entry>The device supports the <link
+linkend="mmap">streaming</link> I/O method.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
new file mode 100644 (file)
index 0000000..677ea64
--- /dev/null
@@ -0,0 +1,444 @@
+<refentry id="vidioc-queryctrl">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_QUERYCTRL</refname>
+    <refname>VIDIOC_QUERYMENU</refname>
+    <refpurpose>Enumerate controls and menu control items</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_queryctrl *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_querymenu *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the attributes of a control applications set the
+<structfield>id</structfield> field of a &v4l2-queryctrl; and call the
+<constant>VIDIOC_QUERYCTRL</constant> ioctl with a pointer to this
+structure. The driver fills the rest of the structure or returns an
+&EINVAL; when the <structfield>id</structfield> is invalid.</para>
+
+    <para>It is possible to enumerate controls by calling
+<constant>VIDIOC_QUERYCTRL</constant> with successive
+<structfield>id</structfield> values starting from
+<constant>V4L2_CID_BASE</constant> up to and exclusive
+<constant>V4L2_CID_BASE_LASTP1</constant>. Drivers may return
+<errorcode>EINVAL</errorcode> if a control in this range is not
+supported. Further applications can enumerate private controls, which
+are not defined in this specification, by starting at
+<constant>V4L2_CID_PRIVATE_BASE</constant> and incrementing
+<structfield>id</structfield> until the driver returns
+<errorcode>EINVAL</errorcode>.</para>
+
+    <para>In both cases, when the driver sets the
+<constant>V4L2_CTRL_FLAG_DISABLED</constant> flag in the
+<structfield>flags</structfield> field this control is permanently
+disabled and should be ignored by the application.<footnote>
+       <para><constant>V4L2_CTRL_FLAG_DISABLED</constant> was
+intended for two purposes: Drivers can skip predefined controls not
+supported by the hardware (although returning EINVAL would do as
+well), or disable predefined and private controls after hardware
+detection without the trouble of reordering control arrays and indices
+(EINVAL cannot be used to skip private controls because it would
+prematurely end the enumeration).</para></footnote></para>
+
+    <para>When the application ORs <structfield>id</structfield> with
+<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> the driver returns the
+next supported control, or <errorcode>EINVAL</errorcode> if there is
+none. Drivers which do not support this flag yet always return
+<errorcode>EINVAL</errorcode>.</para>
+
+    <para>Additional information is required for menu controls: the
+names of the menu items. To query them applications set the
+<structfield>id</structfield> and <structfield>index</structfield>
+fields of &v4l2-querymenu; and call the
+<constant>VIDIOC_QUERYMENU</constant> ioctl with a pointer to this
+structure. The driver fills the rest of the structure or returns an
+&EINVAL; when the <structfield>id</structfield> or
+<structfield>index</structfield> is invalid. Menu items are enumerated
+by calling <constant>VIDIOC_QUERYMENU</constant> with successive
+<structfield>index</structfield> values from &v4l2-queryctrl;
+<structfield>minimum</structfield> to
+<structfield>maximum</structfield>, inclusive. Note that it is possible
+for <constant>VIDIOC_QUERYMENU</constant> to return an &EINVAL; for some
+indices between <structfield>minimum</structfield> and <structfield>maximum</structfield>.
+In that case that particular menu item is not supported by this driver. Also note that
+the <structfield>minimum</structfield> value is not necessarily 0.</para>
+
+    <para>See also the examples in <xref linkend="control" />.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-queryctrl">
+      <title>struct <structname>v4l2_queryctrl</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry>Identifies the control, set by the application. See
+<xref linkend="control-id" /> for predefined IDs. When the ID is ORed
+with V4L2_CTRL_FLAG_NEXT_CTRL the driver clears the flag and returns
+the first control with a higher ID. Drivers which do not support this
+flag yet always return an &EINVAL;.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-ctrl-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of control, see <xref
+               linkend="v4l2-ctrl-type" />.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>name</structfield>[32]</entry>
+           <entry>Name of the control, a NUL-terminated ASCII
+string. This information is intended for the user.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>minimum</structfield></entry>
+           <entry>Minimum value, inclusive. This field gives a lower
+bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
+lowest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant> controls.
+For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the minimum value
+gives the minimum length of the string. This length <emphasis>does not include the terminating
+zero</emphasis>. It may not be valid for any other type of control, including
+<constant>V4L2_CTRL_TYPE_INTEGER64</constant> controls. Note that this is a
+signed value.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>maximum</structfield></entry>
+           <entry>Maximum value, inclusive. This field gives an upper
+bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
+highest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant>
+controls. For <constant>V4L2_CTRL_TYPE_BITMASK</constant> controls it is the
+set of usable bits.
+For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the maximum value
+gives the maximum length of the string. This length <emphasis>does not include the terminating
+zero</emphasis>. It may not be valid for any other type of control, including
+<constant>V4L2_CTRL_TYPE_INTEGER64</constant> controls. Note that this is a
+signed value.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>step</structfield></entry>
+           <entry><para>This field gives a step size for
+<constant>V4L2_CTRL_TYPE_INTEGER</constant> controls. For
+<constant>V4L2_CTRL_TYPE_STRING</constant> controls this field refers to
+the string length that has to be a multiple of this step size.
+It may not be valid for any other type of control, including
+<constant>V4L2_CTRL_TYPE_INTEGER64</constant>
+controls.</para><para>Generally drivers should not scale hardware
+control values. It may be necessary for example when the
+<structfield>name</structfield> or <structfield>id</structfield> imply
+a particular unit and the hardware actually accepts only multiples of
+said unit. If so, drivers must take care values are properly rounded
+when scaling, such that errors will not accumulate on repeated
+read-write cycles.</para><para>This field gives the smallest change of
+an integer control actually affecting hardware. Often the information
+is needed when the user can change controls by keyboard or GUI
+buttons, rather than a slider. When for example a hardware register
+accepts values 0-511 and the driver reports 0-65535, step should be
+128.</para><para>Note that although signed, the step value is supposed to
+be always positive.</para></entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>default_value</structfield></entry>
+           <entry>The default value of a
+<constant>V4L2_CTRL_TYPE_INTEGER</constant>,
+<constant>_BOOLEAN</constant> or <constant>_MENU</constant> control.
+Not valid for other types of controls. Drivers reset controls only
+when the driver is loaded, not later, in particular not when the
+func-open; is called.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry>Control flags, see <xref
+               linkend="control-flags" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[2]</entry>
+           <entry>Reserved for future extensions. Drivers must set
+the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-querymenu">
+      <title>struct <structname>v4l2_querymenu</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry>Identifies the control, set by the application
+from the respective &v4l2-queryctrl;
+<structfield>id</structfield>.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Index of the menu item, starting at zero, set by
+           the application.</entry>
+         </row>
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>name</structfield>[32]</entry>
+           <entry>Name of the menu item, a NUL-terminated ASCII
+string. This information is intended for the user.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield></entry>
+           <entry>Reserved for future extensions. Drivers must set
+the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-ctrl-type">
+      <title>enum v4l2_ctrl_type</title>
+      <tgroup cols="5" align="left">
+       <colspec colwidth="30*" />
+       <colspec colwidth="5*" align="center" />
+       <colspec colwidth="5*" align="center" />
+       <colspec colwidth="5*" align="center" />
+       <colspec colwidth="55*" />
+       <thead>
+         <row>
+           <entry>Type</entry>
+           <entry><structfield>minimum</structfield></entry>
+           <entry><structfield>step</structfield></entry>
+           <entry><structfield>maximum</structfield></entry>
+           <entry>Description</entry>
+         </row>
+       </thead>
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_CTRL_TYPE_INTEGER</constant></entry>
+           <entry>any</entry>
+           <entry>any</entry>
+           <entry>any</entry>
+           <entry>An integer-valued control ranging from minimum to
+maximum inclusive. The step value indicates the increment between
+values which are actually different on the hardware.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_TYPE_BOOLEAN</constant></entry>
+           <entry>0</entry>
+           <entry>1</entry>
+           <entry>1</entry>
+           <entry>A boolean-valued control. Zero corresponds to
+"disabled", and one means "enabled".</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_TYPE_MENU</constant></entry>
+           <entry>&ge; 0</entry>
+           <entry>1</entry>
+           <entry>N-1</entry>
+           <entry>The control has a menu of N choices. The names of
+the menu items can be enumerated with the
+<constant>VIDIOC_QUERYMENU</constant> ioctl.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_TYPE_BITMASK</constant></entry>
+           <entry>0</entry>
+           <entry>n/a</entry>
+           <entry>any</entry>
+           <entry>A bitmask field. The maximum value is the set of bits that can
+be used, all other bits are to be 0. The maximum value is interpreted as a __u32,
+allowing the use of bit 31 in the bitmask.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_TYPE_BUTTON</constant></entry>
+           <entry>0</entry>
+           <entry>0</entry>
+           <entry>0</entry>
+           <entry>A control which performs an action when set.
+Drivers must ignore the value passed with
+<constant>VIDIOC_S_CTRL</constant> and return an &EINVAL; on a
+<constant>VIDIOC_G_CTRL</constant> attempt.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_TYPE_INTEGER64</constant></entry>
+           <entry>n/a</entry>
+           <entry>n/a</entry>
+           <entry>n/a</entry>
+           <entry>A 64-bit integer valued control. Minimum, maximum
+and step size cannot be queried.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_TYPE_STRING</constant></entry>
+           <entry>&ge; 0</entry>
+           <entry>&ge; 1</entry>
+           <entry>&ge; 0</entry>
+           <entry>The minimum and maximum string lengths. The step size
+means that the string must be (minimum + N * step) characters long for
+N &ge; 0. These lengths do not include the terminating zero, so in order to
+pass a string of length 8 to &VIDIOC-S-EXT-CTRLS; you need to set the
+<structfield>size</structfield> field of &v4l2-ext-control; to 9. For &VIDIOC-G-EXT-CTRLS; you can
+set the <structfield>size</structfield> field to <structfield>maximum</structfield> + 1.
+Which character encoding is used will depend on the string control itself and
+should be part of the control documentation.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_TYPE_CTRL_CLASS</constant></entry>
+           <entry>n/a</entry>
+           <entry>n/a</entry>
+           <entry>n/a</entry>
+           <entry>This is not a control. When
+<constant>VIDIOC_QUERYCTRL</constant> is called with a control ID
+equal to a control class code (see <xref linkend="ctrl-class" />) + 1, the
+ioctl returns the name of the control class and this control type.
+Older drivers which do not support this feature return an
+&EINVAL;.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="control-flags">
+      <title>Control Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_CTRL_FLAG_DISABLED</constant></entry>
+           <entry>0x0001</entry>
+           <entry>This control is permanently disabled and should be
+ignored by the application. Any attempt to change the control will
+result in an &EINVAL;.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_FLAG_GRABBED</constant></entry>
+           <entry>0x0002</entry>
+           <entry>This control is temporarily unchangeable, for
+example because another application took over control of the
+respective resource. Such controls may be displayed specially in a
+user interface. Attempts to change the control may result in an
+&EBUSY;.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_FLAG_READ_ONLY</constant></entry>
+           <entry>0x0004</entry>
+           <entry>This control is permanently readable only. Any
+attempt to change the control will result in an &EINVAL;.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_FLAG_UPDATE</constant></entry>
+           <entry>0x0008</entry>
+           <entry>A hint that changing this control may affect the
+value of other controls within the same control class. Applications
+should update their user interface accordingly.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_FLAG_INACTIVE</constant></entry>
+           <entry>0x0010</entry>
+           <entry>This control is not applicable to the current
+configuration and should be displayed accordingly in a user interface.
+For example the flag may be set on a MPEG audio level 2 bitrate
+control when MPEG audio encoding level 1 was selected with another
+control.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_FLAG_SLIDER</constant></entry>
+           <entry>0x0020</entry>
+           <entry>A hint that this control is best represented as a
+slider-like element in a user interface.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_CTRL_FLAG_WRITE_ONLY</constant></entry>
+           <entry>0x0040</entry>
+           <entry>This control is permanently writable only. Any
+attempt to read the control will result in an &EACCES; error code. This
+flag is typically present for relative controls or action controls where
+writing a value will cause the device to carry out a given action
+(&eg; motor control) but no meaningful value can be returned.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-queryctrl; <structfield>id</structfield>
+is invalid. The &v4l2-querymenu; <structfield>id</structfield> is
+invalid or <structfield>index</structfield> is out of range (less than
+<structfield>minimum</structfield> or greater than <structfield>maximum</structfield>)
+or this particular menu item is not supported by the driver.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EACCES</errorcode></term>
+       <listitem>
+         <para>An attempt was made to read a write-only control.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-querystd.xml b/Documentation/DocBook/media/v4l/vidioc-querystd.xml
new file mode 100644 (file)
index 0000000..4b79c7c
--- /dev/null
@@ -0,0 +1,66 @@
+<refentry id="vidioc-querystd">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_QUERYSTD</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_QUERYSTD</refname>
+    <refpurpose>Sense the video standard received by the current
+input</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>v4l2_std_id *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+       <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_QUERYSTD</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The hardware may be able to detect the current video
+standard automatically. To do so, applications call <constant>
+VIDIOC_QUERYSTD</constant> with a pointer to a &v4l2-std-id; type. The
+driver stores here a set of candidates, this can be a single flag or a
+set of supported standards if for example the hardware can only
+distinguish between 50 and 60 Hz systems. When detection is not
+possible or fails, the set must contain all standards supported by the
+current video input or output.</para>
+
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
new file mode 100644 (file)
index 0000000..7be4b1d
--- /dev/null
@@ -0,0 +1,134 @@
+<refentry id="vidioc-reqbufs">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_REQBUFS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_REQBUFS</refname>
+    <refpurpose>Initiate Memory Mapping or User Pointer I/O</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_requestbuffers *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_REQBUFS</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>This ioctl is used to initiate <link linkend="mmap">memory
+mapped</link> or <link linkend="userp">user pointer</link>
+I/O. Memory mapped buffers are located in device memory and must be
+allocated with this ioctl before they can be mapped into the
+application's address space. User buffers are allocated by
+applications themselves, and this ioctl is merely used to switch the
+driver into user pointer I/O mode and to setup some internal structures.</para>
+
+    <para>To allocate device buffers applications initialize all
+fields of the <structname>v4l2_requestbuffers</structname> structure.
+They set the <structfield>type</structfield> field to the respective
+stream or buffer type, the <structfield>count</structfield> field to
+the desired number of buffers, <structfield>memory</structfield>
+must be set to the requested I/O method and the <structfield>reserved</structfield> array
+must be zeroed. When the ioctl
+is called with a pointer to this structure the driver will attempt to allocate
+the requested number of buffers and it stores the actual number
+allocated in the <structfield>count</structfield> field. It can be
+smaller than the number requested, even zero, when the driver runs out
+of free memory. A larger number is also possible when the driver requires
+more buffers to function correctly. For example video output requires at least two buffers,
+one displayed and one filled by the application.</para>
+    <para>When the I/O method is not supported the ioctl
+returns an &EINVAL;.</para>
+
+    <para>Applications can call <constant>VIDIOC_REQBUFS</constant>
+again to change the number of buffers, however this cannot succeed
+when any buffers are still mapped. A <structfield>count</structfield>
+value of zero frees all buffers, after aborting or finishing any DMA
+in progress, an implicit &VIDIOC-STREAMOFF;. <!-- mhs: I see no
+reason why munmap()ping one or even all buffers must imply
+streamoff.--></para>
+
+    <table pgwide="1" frame="none" id="v4l2-requestbuffers">
+      <title>struct <structname>v4l2_requestbuffers</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>count</structfield></entry>
+           <entry>The number of buffers requested or granted.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-buf-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the stream or buffers, this is the same
+as the &v4l2-format; <structfield>type</structfield> field. See <xref
+               linkend="v4l2-buf-type" /> for valid values.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-memory;</entry>
+           <entry><structfield>memory</structfield></entry>
+           <entry>Applications set this field to
+<constant>V4L2_MEMORY_MMAP</constant> or
+<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[2]</entry>
+           <entry>A place holder for future extensions and custom
+(driver defined) buffer types <constant>V4L2_BUF_TYPE_PRIVATE</constant> and
+higher. This array should be zeroed by applications.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The buffer type (<structfield>type</structfield> field) or the
+requested I/O method (<structfield>memory</structfield>) is not
+supported.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
new file mode 100644 (file)
index 0000000..c30dcc4
--- /dev/null
@@ -0,0 +1,135 @@
+<refentry id="vidioc-s-hw-freq-seek">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_S_HW_FREQ_SEEK</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_S_HW_FREQ_SEEK</refname>
+    <refpurpose>Perform a hardware frequency seek</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_hw_freq_seek
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_S_HW_FREQ_SEEK</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Start a hardware frequency seek from the current frequency.
+To do this applications initialize the <structfield>tuner</structfield>,
+<structfield>type</structfield>, <structfield>seek_upward</structfield>,
+<structfield>spacing</structfield> and
+<structfield>wrap_around</structfield> fields, and zero out the
+<structfield>reserved</structfield> array of a &v4l2-hw-freq-seek; and
+call the <constant>VIDIOC_S_HW_FREQ_SEEK</constant> ioctl with a pointer
+to this structure.</para>
+
+    <para>This ioctl is supported if the <constant>V4L2_CAP_HW_FREQ_SEEK</constant> capability is set.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-hw-freq-seek">
+      <title>struct <structname>v4l2_hw_freq_seek</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>tuner</structfield></entry>
+           <entry>The tuner index number. This is the
+same value as in the &v4l2-input; <structfield>tuner</structfield>
+field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-tuner-type;</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>The tuner type. This is the same value as in the
+&v4l2-tuner; <structfield>type</structfield> field.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>seek_upward</structfield></entry>
+           <entry>If non-zero, seek upward from the current frequency, else seek downward.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>wrap_around</structfield></entry>
+           <entry>If non-zero, wrap around when at the end of the frequency range, else stop seeking.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>spacing</structfield></entry>
+           <entry>If non-zero, defines the hardware seek resolution in Hz. The driver selects the nearest value that is supported by the device. If spacing is zero a reasonable default value is used.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[7]</entry>
+           <entry>Reserved for future extensions. Drivers and
+           applications must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The <structfield>tuner</structfield> index is out of
+bounds or the value in the <structfield>type</structfield> field is
+wrong.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EAGAIN</errorcode></term>
+       <listitem>
+         <para>The ioctl timed-out. Try again.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-streamon.xml b/Documentation/DocBook/media/v4l/vidioc-streamon.xml
new file mode 100644 (file)
index 0000000..81cca45
--- /dev/null
@@ -0,0 +1,107 @@
+<refentry id="vidioc-streamon">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_STREAMON</refname>
+    <refname>VIDIOC_STREAMOFF</refname>
+    <refpurpose>Start or stop streaming I/O</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const int *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_STREAMON, VIDIOC_STREAMOFF</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>The <constant>VIDIOC_STREAMON</constant> and
+<constant>VIDIOC_STREAMOFF</constant> ioctl start and stop the capture
+or output process during streaming (<link linkend="mmap">memory
+mapping</link> or <link linkend="userp">user pointer</link>) I/O.</para>
+
+    <para>Specifically the capture hardware is disabled and no input
+buffers are filled (if there are any empty buffers in the incoming
+queue) until <constant>VIDIOC_STREAMON</constant> has been called.
+Accordingly the output hardware is disabled, no video signal is
+produced until <constant>VIDIOC_STREAMON</constant> has been called.
+The ioctl will succeed only when at least one output buffer is in the
+incoming queue.</para>
+
+    <para>The <constant>VIDIOC_STREAMOFF</constant> ioctl, apart of
+aborting or finishing any DMA in progress, unlocks any user pointer
+buffers locked in physical memory, and it removes all buffers from the
+incoming and outgoing queues. That means all images captured but not
+dequeued yet will be lost, likewise all images enqueued for output but
+not transmitted yet. I/O returns to the same state as after calling
+&VIDIOC-REQBUFS; and can be restarted accordingly.</para>
+
+    <para>Both ioctls take a pointer to an integer, the desired buffer or
+stream type. This is the same as &v4l2-requestbuffers;
+<structfield>type</structfield>.</para>
+
+    <para>Note applications can be preempted for unknown periods right
+before or after the <constant>VIDIOC_STREAMON</constant> or
+<constant>VIDIOC_STREAMOFF</constant> calls, there is no notion of
+starting or stopping "now". Buffer timestamps can be used to
+synchronize with other events.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The buffer<structfield>type</structfield> is not supported,
+         or no buffers have been allocated (memory mapping) or enqueued
+         (output) yet.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EPIPE</errorcode></term>
+       <listitem>
+         <para>The driver implements <link
+         linkend="pad-level-formats">pad-level format configuration</link> and
+         the pipeline configuration is invalid.
+         </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml
new file mode 100644 (file)
index 0000000..2f8f4f0
--- /dev/null
@@ -0,0 +1,152 @@
+<refentry id="vidioc-subdev-enum-frame-interval">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refname>
+    <refpurpose>Enumerate frame intervals</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_frame_interval_enum *
+       <parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>This ioctl lets applications enumerate available frame intervals on a
+    given sub-device pad. Frame intervals only makes sense for sub-devices that
+    can control the frame period on their own. This includes, for instance,
+    image sensors and TV tuners.</para>
+
+    <para>For the common use case of image sensors, the frame intervals
+    available on the sub-device output pad depend on the frame format and size
+    on the same pad. Applications must thus specify the desired format and size
+    when enumerating frame intervals.</para>
+
+    <para>To enumerate frame intervals applications initialize the
+    <structfield>index</structfield>, <structfield>pad</structfield>,
+    <structfield>code</structfield>, <structfield>width</structfield> and
+    <structfield>height</structfield> fields of
+    &v4l2-subdev-frame-interval-enum; and call the
+    <constant>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</constant> ioctl with a pointer
+    to this structure. Drivers fill the rest of the structure or return
+    an &EINVAL; if one of the input fields is invalid. All frame intervals are
+    enumerable by beginning at index zero and incrementing by one until
+    <errorcode>EINVAL</errorcode> is returned.</para>
+
+    <para>Available frame intervals may depend on the current 'try' formats
+    at other pads of the sub-device, as well as on the current active links. See
+    &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
+
+    <para>Sub-devices that support the frame interval enumeration ioctl should
+    implemented it on a single pad only. Its behaviour when supported on
+    multiple pads of the same sub-device is not defined.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval-enum">
+      <title>struct <structname>v4l2_subdev_frame_interval_enum</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Number of the format in the enumeration, set by the
+           application.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media controller API.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>code</structfield></entry>
+           <entry>The media bus format code, as defined in
+           <xref linkend="v4l2-mbus-format" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>width</structfield></entry>
+           <entry>Frame width, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>height</structfield></entry>
+           <entry>Frame height, in pixels.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>interval</structfield></entry>
+           <entry>Period, in seconds, between consecutive video frames.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[9]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-frame-interval-enum;
+         <structfield>pad</structfield> references a non-existing pad, one of
+         the <structfield>code</structfield>, <structfield>width</structfield>
+         or <structfield>height</structfield> fields are invalid for the given
+         pad or the <structfield>index</structfield> field is out of bounds.
+         </para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml
new file mode 100644 (file)
index 0000000..79ce42b
--- /dev/null
@@ -0,0 +1,154 @@
+<refentry id="vidioc-subdev-enum-frame-size">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refname>
+    <refpurpose>Enumerate media bus frame sizes</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_frame_size_enum *
+       <parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>This ioctl allows applications to enumerate all frame sizes
+    supported by a sub-device on the given pad for the given media bus format.
+    Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE;
+    ioctl.</para>
+
+    <para>To enumerate frame sizes applications initialize the
+    <structfield>pad</structfield>, <structfield>code</structfield> and
+    <structfield>index</structfield> fields of the
+    &v4l2-subdev-mbus-code-enum; and call the
+    <constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant> ioctl with a pointer to
+    the structure. Drivers fill the minimum and maximum frame sizes or return
+    an &EINVAL; if one of the input parameters is invalid.</para>
+
+    <para>Sub-devices that only support discrete frame sizes (such as most
+    sensors) will return one or more frame sizes with identical minimum and
+    maximum values.</para>
+
+    <para>Not all possible sizes in given [minimum, maximum] ranges need to be
+    supported. For instance, a scaler that uses a fixed-point scaling ratio
+    might not be able to produce every frame size between the minimum and
+    maximum values. Applications must use the &VIDIOC-SUBDEV-S-FMT; ioctl to
+    try the sub-device for an exact supported frame size.</para>
+
+    <para>Available frame sizes may depend on the current 'try' formats at other
+    pads of the sub-device, as well as on the current active links and the
+    current values of V4L2 controls. See &VIDIOC-SUBDEV-G-FMT; for more
+    information about try formats.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-frame-size-enum">
+      <title>struct <structname>v4l2_subdev_frame_size_enum</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Number of the format in the enumeration, set by the
+           application.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media controller API.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>code</structfield></entry>
+           <entry>The media bus format code, as defined in
+           <xref linkend="v4l2-mbus-format" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>min_width</structfield></entry>
+           <entry>Minimum frame width, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>max_width</structfield></entry>
+           <entry>Maximum frame width, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>min_height</structfield></entry>
+           <entry>Minimum frame height, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>max_height</structfield></entry>
+           <entry>Maximum frame height, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[9]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-frame-size-enum; <structfield>pad</structfield>
+         references a non-existing pad, the <structfield>code</structfield> is
+         invalid for the given pad or the <structfield>index</structfield>
+         field is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml
new file mode 100644 (file)
index 0000000..a6b3432
--- /dev/null
@@ -0,0 +1,119 @@
+<refentry id="vidioc-subdev-enum-mbus-code">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_MBUS_CODE</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_ENUM_MBUS_CODE</refname>
+    <refpurpose>Enumerate media bus formats</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_mbus_code_enum *
+       <parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_ENUM_MBUS_CODE</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>To enumerate media bus formats available at a given sub-device pad
+    applications initialize the <structfield>pad</structfield> and
+    <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and
+    call the <constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant> ioctl with a
+    pointer to this structure. Drivers fill the rest of the structure or return
+    an &EINVAL; if either the <structfield>pad</structfield> or
+    <structfield>index</structfield> are invalid. All media bus formats are
+    enumerable by beginning at index zero and incrementing by one until
+    <errorcode>EINVAL</errorcode> is returned.</para>
+
+    <para>Available media bus formats may depend on the current 'try' formats
+    at other pads of the sub-device, as well as on the current active links. See
+    &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-mbus-code-enum">
+      <title>struct <structname>v4l2_subdev_mbus_code_enum</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media controller API.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>index</structfield></entry>
+           <entry>Number of the format in the enumeration, set by the
+           application.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>code</structfield></entry>
+           <entry>The media bus format code, as defined in
+           <xref linkend="v4l2-mbus-format" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[9]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-mbus-code-enum; <structfield>pad</structfield>
+         references a non-existing pad, or the <structfield>index</structfield>
+         field is out of bounds.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml
new file mode 100644 (file)
index 0000000..0619732
--- /dev/null
@@ -0,0 +1,155 @@
+<refentry id="vidioc-subdev-g-crop">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_G_CROP</refname>
+    <refname>VIDIOC_SUBDEV_S_CROP</refname>
+    <refpurpose>Get or set the crop rectangle on a subdev pad</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_crop *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>const struct v4l2_subdev_crop *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>To retrieve the current crop rectangle applications set the
+    <structfield>pad</structfield> field of a &v4l2-subdev-crop; to the
+    desired pad number as reported by the media API and the
+    <structfield>which</structfield> field to
+    <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. They then call the
+    <constant>VIDIOC_SUBDEV_G_CROP</constant> ioctl with a pointer to this
+    structure. The driver fills the members of the <structfield>rect</structfield>
+    field or returns &EINVAL; if the input arguments are invalid, or if cropping
+    is not supported on the given pad.</para>
+
+    <para>To change the current crop rectangle applications set both the
+    <structfield>pad</structfield> and <structfield>which</structfield> fields
+    and all members of the <structfield>rect</structfield> field. They then call
+    the <constant>VIDIOC_SUBDEV_S_CROP</constant> ioctl with a pointer to this
+    structure. The driver verifies the requested crop rectangle, adjusts it
+    based on the hardware capabilities and configures the device. Upon return
+    the &v4l2-subdev-crop; contains the current format as would be returned
+    by a <constant>VIDIOC_SUBDEV_G_CROP</constant> call.</para>
+
+    <para>Applications can query the device capabilities by setting the
+    <structfield>which</structfield> to
+    <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' crop
+    rectangles are not applied to the device by the driver, but are mangled
+    exactly as active crop rectangles and stored in the sub-device file handle.
+    Two applications querying the same sub-device would thus not interact with
+    each other.</para>
+
+    <para>Drivers must not return an error solely because the requested crop
+    rectangle doesn't match the device capabilities. They must instead modify
+    the rectangle to match what the hardware can provide. The modified format
+    should be as close as possible to the original request.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-crop">
+      <title>struct <structname>v4l2_subdev_crop</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media framework.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>which</structfield></entry>
+           <entry>Crop rectangle to get or set, from
+           &v4l2-subdev-format-whence;.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-rect;</entry>
+           <entry><structfield>rect</structfield></entry>
+           <entry>Crop rectangle boundaries, in pixels.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[8]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The crop rectangle can't be changed because the pad is currently
+         busy. This can be caused, for instance, by an active video stream on
+         the pad. The ioctl must not be retried without performing another
+         action to fix the problem first. Only returned by
+         <constant>VIDIOC_SUBDEV_S_CROP</constant></para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-crop; <structfield>pad</structfield>
+         references a non-existing pad, the <structfield>which</structfield>
+         field references a non-existing format, or cropping is not supported
+         on the given subdev pad.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-fmt.xml
new file mode 100644 (file)
index 0000000..a67cde6
--- /dev/null
@@ -0,0 +1,183 @@
+<refentry id="vidioc-subdev-g-fmt">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_G_FMT</refname>
+    <refname>VIDIOC_SUBDEV_S_FMT</refname>
+    <refpurpose>Get or set the data format on a subdev pad</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_format *<parameter>argp</parameter>
+       </paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>These ioctls are used to negotiate the frame format at specific
+    subdev pads in the image pipeline.</para>
+
+    <para>To retrieve the current format applications set the
+    <structfield>pad</structfield> field of a &v4l2-subdev-format; to the
+    desired pad number as reported by the media API and the
+    <structfield>which</structfield> field to
+    <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. When they call the
+    <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl with a pointer to this
+    structure the driver fills the members of the <structfield>format</structfield>
+    field.</para>
+
+    <para>To change the current format applications set both the
+    <structfield>pad</structfield> and <structfield>which</structfield> fields
+    and all members of the <structfield>format</structfield> field. When they
+    call the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl with a pointer to this
+    structure the driver verifies the requested format, adjusts it based on the
+    hardware capabilities and configures the device. Upon return the
+    &v4l2-subdev-format; contains the current format as would be returned by a
+    <constant>VIDIOC_SUBDEV_G_FMT</constant> call.</para>
+
+    <para>Applications can query the device capabilities by setting the
+    <structfield>which</structfield> to
+    <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' formats are not
+    applied to the device by the driver, but are changed exactly as active
+    formats and stored in the sub-device file handle. Two applications querying
+    the same sub-device would thus not interact with each other.</para>
+
+    <para>For instance, to try a format at the output pad of a sub-device,
+    applications would first set the try format at the sub-device input with the
+    <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl. They would then either
+    retrieve the default format at the output pad with the
+    <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl, or set the desired output
+    pad format with the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl and check
+    the returned value.</para>
+
+    <para>Try formats do not depend on active formats, but can depend on the
+    current links configuration or sub-device controls value. For instance, a
+    low-pass noise filter might crop pixels at the frame boundaries, modifying
+    its output frame size.</para>
+
+    <para>Drivers must not return an error solely because the requested format
+    doesn't match the device capabilities. They must instead modify the format
+    to match what the hardware can provide. The modified format should be as
+    close as possible to the original request.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-format">
+      <title>struct <structname>v4l2_subdev_format</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media controller API.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>which</structfield></entry>
+           <entry>Format to modified, from &v4l2-subdev-format-whence;.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-mbus-framefmt;</entry>
+           <entry><structfield>format</structfield></entry>
+           <entry>Definition of an image format, see <xref
+           linkend="v4l2-mbus-framefmt" /> for details.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[8]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-format-whence">
+      <title>enum <structname>v4l2_subdev_format_whence</structname></title>
+      <tgroup cols="3">
+        &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry>V4L2_SUBDEV_FORMAT_TRY</entry>
+           <entry>0</entry>
+           <entry>Try formats, used for querying device capabilities.</entry>
+         </row>
+         <row>
+           <entry>V4L2_SUBDEV_FORMAT_ACTIVE</entry>
+           <entry>1</entry>
+           <entry>Active formats, applied to the hardware.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The format can't be changed because the pad is currently busy.
+         This can be caused, for instance, by an active video stream on the
+         pad. The ioctl must not be retried without performing another action
+         to fix the problem first. Only returned by
+         <constant>VIDIOC_SUBDEV_S_FMT</constant></para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-format; <structfield>pad</structfield>
+         references a non-existing pad, or the <structfield>which</structfield>
+         field references a non-existing format.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-frame-interval.xml
new file mode 100644 (file)
index 0000000..0bc3ea2
--- /dev/null
@@ -0,0 +1,141 @@
+<refentry id="vidioc-subdev-g-frame-interval">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBDEV_G_FRAME_INTERVAL</refname>
+    <refname>VIDIOC_SUBDEV_S_FRAME_INTERVAL</refname>
+    <refpurpose>Get or set the frame interval on a subdev pad</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_subdev_frame_interval *<parameter>argp</parameter>
+       </paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <note>
+      <title>Experimental</title>
+      <para>This is an <link linkend="experimental">experimental</link>
+      interface and may change in the future.</para>
+    </note>
+
+    <para>These ioctls are used to get and set the frame interval at specific
+    subdev pads in the image pipeline. The frame interval only makes sense for
+    sub-devices that can control the frame period on their own. This includes,
+    for instance, image sensors and TV tuners. Sub-devices that don't support
+    frame intervals must not implement these ioctls.</para>
+
+    <para>To retrieve the current frame interval applications set the
+    <structfield>pad</structfield> field of a &v4l2-subdev-frame-interval; to
+    the desired pad number as reported by the media controller API. When they
+    call the <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> ioctl with a
+    pointer to this structure the driver fills the members of the
+    <structfield>interval</structfield> field.</para>
+
+    <para>To change the current frame interval applications set both the
+    <structfield>pad</structfield> field and all members of the
+    <structfield>interval</structfield> field. When they call the
+    <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant> ioctl with a pointer to
+    this structure the driver verifies the requested interval, adjusts it based
+    on the hardware capabilities and configures the device. Upon return the
+    &v4l2-subdev-frame-interval; contains the current frame interval as would be
+    returned by a <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> call.
+    </para>
+
+    <para>Drivers must not return an error solely because the requested interval
+    doesn't match the device capabilities. They must instead modify the interval
+    to match what the hardware can provide. The modified interval should be as
+    close as possible to the original request.</para>
+
+    <para>Sub-devices that support the frame interval ioctls should implement
+    them on a single pad only. Their behaviour when supported on multiple pads
+    of the same sub-device is not defined.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval">
+      <title>struct <structname>v4l2_subdev_frame_interval</structname></title>
+      <tgroup cols="3">
+        &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>pad</structfield></entry>
+           <entry>Pad number as reported by the media controller API.</entry>
+         </row>
+         <row>
+           <entry>&v4l2-fract;</entry>
+           <entry><structfield>interval</structfield></entry>
+           <entry>Period, in seconds, between consecutive video frames.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[9]</entry>
+           <entry>Reserved for future extensions. Applications and drivers must
+           set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+       <term><errorcode>EBUSY</errorcode></term>
+       <listitem>
+         <para>The frame interval can't be changed because the pad is currently
+         busy. This can be caused, for instance, by an active video stream on
+         the pad. The ioctl must not be retried without performing another
+         action to fix the problem first. Only returned by
+         <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><errorcode>EINVAL</errorcode></term>
+       <listitem>
+         <para>The &v4l2-subdev-frame-interval; <structfield>pad</structfield>
+         references a non-existing pad, or the pad doesn't support frame
+         intervals.</para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
new file mode 100644 (file)
index 0000000..69c0d8a
--- /dev/null
@@ -0,0 +1,297 @@
+<refentry id="vidioc-subscribe-event">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refname>
+    <refpurpose>Subscribe or unsubscribe event</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+       <funcdef>int <function>ioctl</function></funcdef>
+       <paramdef>int <parameter>fd</parameter></paramdef>
+       <paramdef>int <parameter>request</parameter></paramdef>
+       <paramdef>struct v4l2_event_subscription
+*<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+       <term><parameter>fd</parameter></term>
+       <listitem>
+         <para>&fd;</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>request</parameter></term>
+       <listitem>
+         <para>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><parameter>argp</parameter></term>
+       <listitem>
+         <para></para>
+       </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Subscribe or unsubscribe V4L2 event. Subscribed events are
+    dequeued by using the &VIDIOC-DQEVENT; ioctl.</para>
+
+    <table frame="none" pgwide="1" id="v4l2-event-subscription">
+      <title>struct <structname>v4l2_event_subscription</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry>Type of the event.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>id</structfield></entry>
+           <entry>ID of the event source. If there is no ID associated with
+               the event source, then set this to 0. Whether or not an event
+               needs an ID depends on the event type.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry>Event flags, see <xref linkend="event-flags" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>reserved</structfield>[5]</entry>
+           <entry>Reserved for future extensions. Drivers and applications
+           must set the array to zero.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="event-type">
+      <title>Event Types</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_EVENT_ALL</constant></entry>
+           <entry>0</entry>
+           <entry>All events. V4L2_EVENT_ALL is valid only for
+           VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once.
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_VSYNC</constant></entry>
+           <entry>1</entry>
+           <entry>This event is triggered on the vertical sync.
+           This event has a &v4l2-event-vsync; associated with it.
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_EOS</constant></entry>
+           <entry>2</entry>
+           <entry>This event is triggered when the end of a stream is reached.
+           This is typically used with MPEG decoders to report to the application
+           when the last of the MPEG stream has been decoded.
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_CTRL</constant></entry>
+           <entry>3</entry>
+           <entry><para>This event requires that the <structfield>id</structfield>
+               matches the control ID from which you want to receive events.
+               This event is triggered if the control's value changes, if a
+               button control is pressed or if the control's flags change.
+               This event has a &v4l2-event-ctrl; associated with it. This struct
+               contains much of the same information as &v4l2-queryctrl; and
+               &v4l2-control;.</para>
+
+               <para>If the event is generated due to a call to &VIDIOC-S-CTRL; or
+               &VIDIOC-S-EXT-CTRLS;, then the event will <emphasis>not</emphasis> be sent to
+               the file handle that called the ioctl function. This prevents
+               nasty feedback loops. If you <emphasis>do</emphasis> want to get the
+               event, then set the <constant>V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK</constant>
+               flag.
+               </para>
+
+               <para>This event type will ensure that no information is lost when
+               more events are raised than there is room internally. In that
+               case the &v4l2-event-ctrl; of the second-oldest event is kept,
+               but the <structfield>changes</structfield> field of the
+               second-oldest event is ORed with the <structfield>changes</structfield>
+               field of the oldest event.</para>
+           </entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
+           <entry>0x08000000</entry>
+           <entry>Base event number for driver-private events.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="event-flags">
+      <title>Event Flags</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_EVENT_SUB_FL_SEND_INITIAL</constant></entry>
+           <entry>0x0001</entry>
+           <entry>When this event is subscribed an initial event will be sent
+               containing the current status. This only makes sense for events
+               that are triggered by a status change such as <constant>V4L2_EVENT_CTRL</constant>.
+               Other events will ignore this flag.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK</constant></entry>
+           <entry>0x0002</entry>
+           <entry><para>If set, then events directly caused by an ioctl will also be sent to
+               the filehandle that called that ioctl. For example, changing a control using
+               &VIDIOC-S-CTRL; will cause a V4L2_EVENT_CTRL to be sent back to that same
+               filehandle. Normally such events are suppressed to prevent feedback loops
+               where an application changes a control to a one value and then another, and
+               then receives an event telling it that that control has changed to the first
+               value.</para>
+
+               <para>Since it can't tell whether that event was caused by another application
+               or by the &VIDIOC-S-CTRL; call it is hard to decide whether to set the
+               control to the value in the event, or ignore it.</para>
+
+               <para>Think carefully when you set this flag so you won't get into situations
+               like that.</para>
+           </entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-event-vsync">
+      <title>struct <structname>v4l2_event_vsync</structname></title>
+      <tgroup cols="3">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u8</entry>
+           <entry><structfield>field</structfield></entry>
+           <entry>The upcoming field. See &v4l2-field;.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table frame="none" pgwide="1" id="v4l2-event-ctrl">
+      <title>struct <structname>v4l2_event_ctrl</structname></title>
+      <tgroup cols="4">
+       &cs-str;
+       <tbody valign="top">
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>changes</structfield></entry>
+           <entry></entry>
+           <entry>A bitmask that tells what has changed. See <xref linkend="changes-flags" />.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>type</structfield></entry>
+           <entry></entry>
+           <entry>The type of the control. See &v4l2-ctrl-type;.</entry>
+         </row>
+         <row>
+           <entry>union (anonymous)</entry>
+           <entry></entry>
+           <entry></entry>
+           <entry></entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__s32</entry>
+           <entry><structfield>value</structfield></entry>
+           <entry>The 32-bit value of the control for 32-bit control types.
+               This is 0 for string controls since the value of a string
+               cannot be passed using &VIDIOC-DQEVENT;.</entry>
+         </row>
+         <row>
+           <entry></entry>
+           <entry>__s64</entry>
+           <entry><structfield>value64</structfield></entry>
+           <entry>The 64-bit value of the control for 64-bit control types.</entry>
+         </row>
+         <row>
+           <entry>__u32</entry>
+           <entry><structfield>flags</structfield></entry>
+           <entry></entry>
+           <entry>The control flags. See <xref linkend="control-flags" />.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>minimum</structfield></entry>
+           <entry></entry>
+           <entry>The minimum value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>maximum</structfield></entry>
+           <entry></entry>
+           <entry>The maximum value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>step</structfield></entry>
+           <entry></entry>
+           <entry>The step value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+         <row>
+           <entry>__s32</entry>
+           <entry><structfield>default_value</structfield></entry>
+           <entry></entry>
+           <entry>The default value value of the control. See &v4l2-queryctrl;.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="changes-flags">
+      <title>Changes</title>
+      <tgroup cols="3">
+       &cs-def;
+       <tbody valign="top">
+         <row>
+           <entry><constant>V4L2_EVENT_CTRL_CH_VALUE</constant></entry>
+           <entry>0x0001</entry>
+           <entry>This control event was triggered because the value of the control
+               changed. Special case: if a button control is pressed, then this
+               event is sent as well, even though there is not explicit value
+               associated with a button control.</entry>
+         </row>
+         <row>
+           <entry><constant>V4L2_EVENT_CTRL_CH_FLAGS</constant></entry>
+           <entry>0x0002</entry>
+           <entry>This control event was triggered because the control flags
+               changed.</entry>
+         </row>
+       </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/vbi_525.gif.b64 b/Documentation/DocBook/media/vbi_525.gif.b64
new file mode 100644 (file)
index 0000000..d5dcf06
--- /dev/null
@@ -0,0 +1,84 @@
+R0lGODlhKgPIAIAAAAAAAP///yH5BAEAAAEALAAAAAAqA8gAAAL+jI+py+0Po5y02ouz3rz7D4bi
+SJbmiabqWgJs475LLCt0fdy4oeN9/QPuEEFZkXVcJZXDXNP5pC0TgGrMSrRMidhA1/uNbB9j2CZ8
+Kc+qHDXDTT2jK3BuPau13vFpdmc/p6Uh5SeYoXMHyFNomEeYiNEVKCFFx8Wz2Eh56YWp2bfnGXk1
+OEhaKnem2rYa6vp3KIqaBhULmsk4Ufc1KTbq4rfbhxkcOQx22limZ4P8STYH3PsGu8pqe439aw36
+eji9qT1rGCpraf5MkQynyJeuG0c73imvLYzuUAwF/P6WTK8vHDdj2Qia8hYL4bF2o/CpmydOXa6I
+uqQNPFepny/+d+cM0qsH8qNGCI8M3gvG7KG8iSJJVoNIp1w5h/C+gSPjgWE9hR0Lqmzp0RFPjLV+
+hoRki2XNPJyCVmy2U6KnHm6WnboRcOPFkS59xqQpEKZRpkDHfi1rdqlXgTMVKVVL7h/cnmi1rtxq
+t27Yn1n5xrySUi81iYAlvR2MN23Fm/nkyHzp9G9iSof3Ps1pE3PmyV2dhaSL1Jiee3/ZjI5Mkhlj
+xDPXGnkClgns1pxV0K6d4rbYF7pRv44CW7Dtojt6f/YxO7hxrrmVJ3/eZDnd4tCjVw+OPbv27dy7
+e/8OPrz48eTLmz+PPr369ezbu38PP778+fTr27+PP7/+/fz++/v/D2CAAg5IYIEGHohgggouSNFv
+1l2HHIRCACehgw9eOIR0001I4YVq8MJIVZItUpJiG564GG75VJaXb5aVthtljwnV1mauyXijVqtB
+FVRoK7Foxi0kNphaYdhYNRUxQMZDWZKd9IXTQTmmFluUDQln5TcqBrnlYEOhaGJXNZrUpR24sLPN
+kC6uaBGWMywERpWISeUZacIE5iZH8OApJ3FrtvhnY5AdR1iZVOw4p1BTZhljlGNG1aijfgIKl4+f
+kNZjoIL2ySOacX4kYlyyfDgooWBSWmikOH15mU5ksfqiqUVqNsySXN7FqZ5jWdoTr7sSqaOtTH6Y
+EajMNZX+kbC53qopDDMuymhprgLbGaTUbgrtm8smCqOqQRYbZrV58vijtzZgNW2TTHZEag7rHFuU
+Pp4aSq6sc9EJa7jinpVuq/Ruy+xSj9KibL0YyRXrXr7WlC+242qrDMJsEYYSVvAiUzGJwg7c7BqI
+GjyiuQ5f7PG/7j57VqkpqryyyJ0WDDBxC29ymr3+YFEzyRpLE5qG91qYYYVAR4hh0B0WTbTRR1Mn
+NBKTDs0h0lErTTXTSyddNdZabw311ET7nLDTTct2tddmn82bc2V3zbbYazMId9xyz0133XbfjXfe
+eu/Nd99+/w144IIPTnjhhh+OeOKKczcR2CYvDnnkkgf+XoTF2eUCs9uTb85554MrVUjmJGDuuMue
+n4566gKyxM+T2L37cNqqz0577QG2/ikpVxEie7LflW578MIPL1vroVdifOy3outkscD/THz00k+v
+ne46ApQT70o2ZWz1RT5Pffji2w4YWcqLkrzvMhNT/Wjuvy/6+PLPL/w/854vr+t58gP+vufySb8A
+CnB8phEBmo7nhDHwz3vQGKADH0jAT4UgVGZQILjeBsEManB6GqKgP+h0vtFtcIQk5KAJpqAa/znL
+Xc4CXv9KCMP2fMyA8fvDDCdYwzbg7IQbwZ0IqeHCGArRbj4UwgvxgDJSHXEfIUQVEpuIqiLycIhU
+jJv+FNO2RCeJQ4kPuuIHUMi+Kb4piFUso4K8yIQsYm8cIlKj9VrQQyiqUH9mrOPm0DgcN8YsXoLQ
+Ix1HAMY/ArKCdiyk5PDYHD+6qo1dlOPItIXIG0XSkJT02yR5qEg2EqyRHYyjzyrnyEqK8oyhTEgj
+7bFJo13SI2EwzCdDhDP4yXKWtKxYLWWJsVu+L5e6rFkv4bezX9pSmDd0XzdgZkwa7SJnFDMNMX35
+TFdGM5jE5GU1o4kn1WDzmXbg2TaFaSZrgvNks+ymOL9Jy3DesGUiSd5wmEhGt5SiHUipp+naCZL7
+6ZOV+WyixMJhT1MKlJ+CFCP2nmexf9plCZZbJWT+3Cm7MJIxSfGcp0WTglGC9CtL+9RERz3aT3pm
+FFeiuShBHcqNN75ToqjkaBhXqr8XJnSPIC0oHP2JU5FqdKQ2g5jyLNerfgo1qDolKTlMmsqTlrJa
+Km1OAmOGCKa+1KkstRBEUdDQpUpqoEk1KlF2ei2fftQoYyVrSFERUK9aQp4tRakmbXrTqtbUpXD9
+oVw1d9UTZLWiXO0jWnn61Y7xca5mJWxhifpXsKr1IWxV6kQPitc1GnZOTcVqFhRq0Lxmdqp6palb
+L5vYxQL0nkA9rGnVgql9FvWoiu2qX9uqVWxVtrNP/em6lsdZ2t6VbE9ap1B9y9qS9jWwwS2uzvD+
+OdmFDjWoIF0tcZ+7VqTWFLjMpS5Ri6krsaoJpt6M2hFLK7bGuha6DAPsqSi7XNSmV73NDa1xVSLe
+1xLUqlaLbViWCF7vJu27ns2pe8k72rCSq6z3XW+B22ve8rZWvuM9LW/xm13LPo2q9mUufScU3+gm
+OMCiDRtukytVEIcYsRuO44I1LNz5RrTCytXvfo/G3wnTNsOM/S98S+zED1vYwS0WsWxxGkLMbjXF
+DWbvhV185CS/GMm9ky6KOywmHM/xxz7WMY97bFbn3vjENR7ulSVM05QumcljXnGMabwnGysYylO2
+spG/TOUqo1fLa35vl4ksZ7uyeMRmrq8akav+5OI5+c5sFlRaezpgA/P5zXDGLZ05bOc0e5nRD/Zz
+mfscHWYiQdNKAK6n4wfAxSTi09wk5zipqctunvqct1T1L8P5i1GLLtTsdMRBrBvrHNoE18fEL6dH
+CexgC3vYxC62sY+N7GQre9nMbraznw3taEt72tSutrWvje1sa3vb3O62t78N7nCLe9zkLre5z43u
+dKt73exut7vfDe94y3ve9K63ve9t7SBkNdH47re/9Qq6CAP63wQvuGZ2mYneFoPWBm+4w8VUWiMB
+5IIPr7jFX2a/YCZ8zxfvuLnf1VB5QcnjJDd4YTKucN3xuuQsb7nLXw7zmMt85jSvuc1vjvP+nOt8
+5zzvuc9/DvSgC33oRC+60Y+O9KQrfelMb7rTnw71qEt96lSvutWvjvWsa33rXO+6178O9rCLfexk
+L7vZz472scG0vllD24rZzrW28bbtcl873N2uObUfqkQzJFaJPAO9Fm53W34/mcbO+7/t9j1ksfzY
+MiUO+DaXDPCLT9VpKr8yZnpQDM50JcmkyTOdNT5Enx8mxhAPaxApq/CULxjFV9S8kT9yhWts0zL4
+JVnX44uigl1481Cf8KsI3Kf+Er6biMXS18/+gy2JJfBzFw/Mc35U0NcXJxAh+4A1ENC69xdoER38
+34Mf+sZvF/5OP3yQ+QKAt8+14Z9/2dH+H3dnh4d/Als5f1MzMcdsCoj5SfwwqXVb/Mca6qd9WBaA
+R/J+1qddDHeAUZZy85c+mOcp/ndc5QMqGyMawrd5ACVx/8dYKrcsFQg7DAhEu6NAG7g9q3cU3RN4
+zBJV9jdwsXM/GQiCRuZWNWh7Msh3QmaAhoYSIyhja1ALbQJ/obM+L0iExvJry8d8LpiAuPdSN7h9
+3VOD3kdHW1AVsOOAxEclTySEIIQOHViF7XSFZQgUVFiGj8CCYpiGR+g8Axgt24c8Q9gpvTJbHjZg
+IjguFJQVZChbH2h/2rODJjgqxieDGTiFevgyFKWGAYOBj8gtVPF564IpLRKJgziAgAj+ieFniNxX
+fUo4LPcXhn2YEqMnif+TMYNHgKoWeTTYTGoifZzXeAsoivpXJ2f4PaHHik7oMZ1ni4yIi8fDib+I
+gen3g6pohE34gMa4cbO4ixJkh8m4d0HYi5Lniq1XjMqojcqgd2AmNXVnd3g3juRIYXT3dnGXjuZ4
+jl/zjboVjuvIjvB4d/NoUOiYd+qYj/Z4j+6IQXNXj/IojuAYkAK5j/yoZwV5kAa5kA2Zdg8JkREp
+kRNJkRVpkT73ZxwnjASpjwCJkIP0jv3Yke34kSAZjww5kPQ4kiSZkipZkhOkNifpkOWIkjQ5kzZJ
+NqyXi9uYeIrXho8TZtTlCjnEMfn+Z07jN3n3hIuC1ZNKeY2JiD6Zs0gC5iWzliav+Inv51vKx3wo
+WIrTV3uh2IqC9zjZN5ZL2DBgSZW+iI2GBpTT2IwmtpajqJSGIY232JRbuQ1myZZoKZZZmTt8ySV3
+ggapWEHRAJjU2JaL6YVMKYepMpe/GJlH6ZTI2Jdu6ZRcuZGQBJePqTCTmYRG2XyO6Q52Ui5QuJn7
+sA4amC2XOYeJCWukWVugeX2y+ZeiGZSO0ZrncpdGWYKwOZq2mV94SXwzEyymCULIo4u0h5rt95ZD
+uZuuyS2xSJuNeZZ3WJlhBmRQBAhCGVrLmRfGCXF1yTyg2ThkQlZ5eJ3lWYipOZ3+UKmd/uSDrwmf
+ciSY76kuacmY+Hk9lWmEwumJ8BmDSBl9/zKgpEmI6CkjGcOM/MmN3QicnRmX0OBpuvmW3GlD4jkr
+QEmUFuqfHXokUjkPGtoYDSqd+meiE+qMehmf0ZmQComTHtmScSWTMWqjHPmSMPmPMhpRGemjMYmP
+N4mjM0qjMHqjLkmkL5qjIPCjLXqhLqqkSWqSQXqkSFqTLHmlVpqlIrmkF+mlXwqmYSqmY7puiEim
+Zzogj4GEaMqmAIIQmtmmcTofbyqhcqp0GSlD1gCndvpvuqYldSU3dOqkfJpun/VFt1md5sFQjOKn
+hFpu+dObKVMXUnSMx5AfDBX+agfqqH0qQQtkCrMZf81gqBvnmemBTZtacuCyp98yFbyAD/NJSLiD
+p4dKoSuHqu62qJHqlpTYJ5AgcvKBqbfqclroUOUZBynoFP/pHrMqrI8KL2CErB1YQPHBrM06bjwJ
+lxsDJCkkqgD3WNZ6Ro16lT5gq0JCnBPGrfs5SerJcaOKm+BaH+4KC5kkZoR2nTTBrixToKCESTwK
+r2mqkatySi1lr/uJr7nFpJ6kooMWpf8KsHpErwQraed6sIAKLez6SQHrsHAjr6wQsSpGMzzIqp0U
+ZfwKR9W6sfzRsarwsXnWrYDJryurohjbWSibsvohs5MmaBI7se45qQhLq5L+YrIiZLM3ix85i2e/
+oRMHJLJesmfoArVPyWqldnivNrW1hGqvhk5Xi7VcW05ei0u9JrbKNLbS8nioyE1bC7bAtLYIt7Xo
+BLfmBLdWW7Vz20vq9E2mFrZ1u2qihrcdRHq19Vj5CoaFVqIMC2kAdq/U57KWqGh0hWBJu2WG67Q6
+y11AO6WEq6O71WjIhbRSBaubG1OVZrH7R7lAhLhyGWmLO4MHtmOUhoDqhWaJO7mru34YorlBC1mV
+Frr8RmWf61K9q7uaRaO5K1m26xKzq7qKa7CM+7qu27nadVaWC4GnCxXKS2HG+1CYm7nHG717FVnC
+Syuje7mlq0XIK7DUO2T+6Luwvhu97gu7iya7qVu97Fu5khtZ5ju+2ru94uu8v6ux1Oe/BUG8ema8
+A+y9T8Zg9suZCGqZjtu4pfm4wUu/68u8FqzAFwa8H7bBjgZVyAi+vDuo8xvAIVy/F5y++Eu7dZaI
+wym/sQvDL6xc2IvBLFy7C6zBJfxECPV9BIZe+ru/CZy96DfEWHm/DDxGFYyZ1luqcfa+EPy8MQy6
+SsyqXLbCPeti5fq74gq62JWtSMTFwavFUgyPFShlKVxkV7y8ienCkPvEEhzBEkzDS4zEBaq+ZXxp
++RtopEs1MQYwCIzAQJzEZ1zFBPq/8evGiOzEWUbFR4zChZzG5bvHkoz+aWRmyZRsw5mMxRl8w51M
+sYcMvYrsZqFMwiq8xpp8yptcyavMynw8yXrcyqksy7d7x5D8yA46ymScyzKcyKUcySfsyWpMy5Z2
+yZjsyrGMzOBoxlYcsrXsyMHMum28yKSsyz8cub9cw8Kczc1MzK+szHl8zMX8zXVcuNh8uIT8zJ/c
+utUsvVHMyxTszA3MxOWMw8mMx+BcxOIczsY8y9s8zOZsy9DcvOv8zrvcy+zcgI0sz+RsugBdvPic
+z/Z8zxmSoqNT0aq4a1JiI92Q0bm2aqeqt3cb0qk20q1W0iYttbR4ax3N0RsNBBdNQ114QjCNQzLd
+AjRttDmt0zvN0z1u7dM/DdRBLdRDTdRFbdRHjdRJrdRLzdRN7dRPDdVRLdVTTdVVbdVXjdVfVBkx
++APSnNU5bZaaCsVfPdQnR8TkJwlnTdZAnSwXJIidutZBHbhrqpqnuKpx/a9c3RdvndZ43dO+pCSY
+E9gqF8bNWgAAOw==
diff --git a/Documentation/DocBook/media/vbi_625.gif.b64 b/Documentation/DocBook/media/vbi_625.gif.b64
new file mode 100644 (file)
index 0000000..831f49a
--- /dev/null
@@ -0,0 +1,90 @@
+R0lGODlhKgPIAIAAAAAAAP///yH5BAEAAAEALAAAAAAqA8gAAAL+jI+py+0Po5y02ouz3rz7D4bi
+SJbmiabqWgJs475LLCt0fdy4oeN9/QPuEEFZkXVcJZXDXNP5pC0TgGrOCqVMidhAVdqVbLmx73Wc
+FXfNabGFzfbG3Rz0bDO/2G1hzJ7o8ceT56dB+Gb4JciD16fnh3VI97bmOCE4tyhVUSbHKOlg1xnp
+6aWFKDfaecrqQlrK2vqK2bjImPFaiLuKuxvY+2HLq1tniHcLzFmWy6mnitxMeWs5iaZo0xZhTahj
+rdzXHa3m6Eod+h1+LW7MXpx83P7962y+ju4O//5oGr8PHUvs36VjoCBsujTsxp5t0MIB1MZLYb07
+CBt+QlWRHz/+Zto62NLYD+Ouj7Q+ZlMj0J80kCr1iaSHT6WmeAXPAXOVzNs0hw8fHAwzkeLATz9E
+xVo2qCa2o7AA9Wz5cmXIgFAhKu2Yb2q1rFSrDmUZFeUgrQaLdhWriFZKGKt6LNTSlopXthevrIUB
+d9rSp6FGcbnLwCRYe2ELo+VK+CxEwF9XkoypeCtZn05dTiqlNupMxnyWxXkL17OVtHz7loMTdO+4
+pGsMsz0dKbVcyK7LXsWbyKSweTA95qatDHho4T7TqqsdWN1toaFbExNMHMkTzimgR2cSZfpgI9qt
+T8aePbz4IQebeLcsZDz56ecjv2g/9z37+fTNd6+vPb/+/fz++/v/D2CAAg5IYIEGHohgggouyGCD
+Dj4IYYQSTkhhhRZeiGGGGm7IYYcefghiiCKOSGKJJp6IYooqrsjidyrAh9yL+K2nng/31WgjjtzN
+mKOO8lFHxhlJxRjkkEY2tloWy51k2mxAVoaQQkImRiRuIyEmD5ZIomeVYMLIZhMkS6rWm4vJecZl
+cWBsRomUz+Vlymg4bWflYnGWo5FOGZ02FphPYmbkmHQmRxRSgzJXpntl/UlmcIca5ItvilJJx2OS
+TkrZo5k6CgemfBDFKJPF7ZRTIZsMgxUip4qKKFN5UropSKD54xasW9p6a65VBiYmb/dc2qZuwMaH
+laXvZEb+FbKPCKpkm68KutBoTshZWpN6MRqtm6H+8ZmTulabqplhXikuNtBhgqqnM6SLa7jE2nZd
+rGzK5CeUqMxJq6l2YavvTn6yGVG7zGn77aZgvOvuruvGexnCndXLq5YCC2Vsmg2LUzGcTSm8r7fg
+0pUKxMgwdOdY/O4JaMkFf/pqyiv/Jau9CY/asqatOlwnzuM6JvHMOsPsZaQZ/3zzV0NfdnS4HL3c
+KsBZpnIk01NCHbXP1o4MsSjgyAzp0xsddzHRHqOz2289d83wmb46e/aibauZNhXGMWuz3KjNG6Vz
++fooHY/p8Q0ejYDL6PeO9hX+4+DVsRr4DjByPMLjE5v+ILnUJ1Qe9t+Cb855j4d/jrnVfSuOQuii
+N+5555qrbjjrrTt+Y4uyz0577bbfjnvuuu/Oe+++/w588MIPT3zxxh+PfPLKL8+87rWGYLqI0TdP
+ffWwM249oXKDgC/y02cPfvgkkPJ97t137075HKovfvvuQ1KXh9zKJ6V37A7P/vv6739Oa0BFnoRK
+QG9+2PlJMLDnu/zxb4EMxJPJ/DLA/sXvF0EogsgG5hQDkupeCOydAhkIwvcdAYJeqYdfymOMCvLK
+Swe7yKqgkLU4dZB3AaRbCG8YwhrOEGazUaHJNuKboqjQaRBMSDrqBkOu4W9uTAQbDp8IRSV2jFtm
+2Y7+thwIDyzi64VIBKIMvQip+/Gwit5Tkw2jiMbsGcVRPfyhBTdGq7gY6ovoG1UL6ximJSwtVLjT
+YRr/mMZZFctJRZSgLswiR73gMWcsqw0Jx0a8DwJyksAj4CCjRr7T2aSCiQTiIiMGsvg8UorBkyQl
+T7k7S3aNXQJEm2lWxcl9bRGFnWFM2TAIyuOZEpUpOqNHLhgMX9ahXqq02xZTQrCdRQyWdpolq+Yk
+uTdqMoG8BOEnZSSsHYLRRmukFAnFGKOA2ayVsBjhNkUgTVcab5fVNNE1F5fNk33wnY2y2iOBWbQ2
+8rFj9axLNBmZy3W2c4H0vFwXcTmUeXaxmBmUlf3+LkmSdJprn5kb50AvWruCUu6g3gKNQrtZmns+
+dJUU/WE/6bjRgAIUoyx1J0e599I0eNQ+INXVPaEH0ZTeAZzE2QI7WwrU7Hw0KzNdT00rOkqckjSm
+9jynUvMJyaBKVX5MDSJN9jHUj+UzqTCdGtWcOECJyAmf8CqSbWDTxLSiVa1MZA1b5+bWt5ImZHI1
+Dj2YZddgiSyvel1rXc3w17bSNbCiIWxhDUsGwyoWbNdYrGITO1jCJjatRXIsYs/gV7betbJkhZtM
+ndqChkaPJ6fYTdk2g9pyQUmVrJVJQDS6Qnak9pBX1RxXxyfa2o4LmoG7LW6nVdJjgfa3imzc/Ez+
+K9ubKNdiuWytSJz7XKbCliKzxapuE+fJ3k5wHVOoX3AB4tvIAYKnxEUp4Yp7Xj5Od6LLtS5tmYtQ
+8Lo2uq5Fbns5+N7Xei68T82ufl3J2/Tyt78Bxm6BS5fb9HJ0vXI57X2jcUv50pe7842uffOLX/f+
+t3UDPmAS59Xd8X63MR32sD9tO1zxfti4y0phcjEMYdV+dsISpnB9XfzgVuS4xgberk79S+Pdphid
+CRbwkEML3KpKmMH6OC6OYaxjKGtVNdDlMYn1e2ENZ3jLQdbuFxe34grL68hdRa+RyaviQo02g51F
+kpN74WApV0rGFumy0sQs3yxzOcpatjOY/eX+Zbols06wCXSbrwzWPyt5w9hdsHQfHVM0L5POMfPz
+mC09Zj3HWM6XZPToFo3nT7Nv0F7e3KhJ+WNHa5rPe04opUkN4FDf+cZwfnGfWY3pH59am2UGda51
+PZ5dj7glb+4Xp5d66yl3VNax/nVzHx3nZM9ZuCiutrV7vN9gZ3t1xW7xjqct7YoK2dlUZnasV+3q
+Y2cqwsL2tY2vLerrDfu68ea2t40dbmS32nIzfreVkYblJ+d73d8GOLxLzeFtHzzhC1e0qgW+705H
+fJrlJveyLb5sdIN74gSnNsM/DvJ6N1zk2H5dt1Vla45v8tWofjbG+01hjUt80wO/dMgRXvL+nOsc
+CHM1Qs/fw9fhkEtMmrBhovMW2Mn+Vel1Zbpcnf50r7KN6CMpOj6DjoSfZ/3o1dG6Erz+da5Pdexk
+L7vZz472tKt97Wxvu9vfDve4y33udK+73e+O97zrfe9877vf/w74wAt+8IQvvOEPj/jEK37xjG+8
+4x8P+chLfvKUr7zlL4/5zGt+85zvvOfx7sNrXfzzpC89gyQB6zqbfvWsL9Bh7xgyNbd+9rT3zxwr
+3aly1n73vAcdMw7rxt4Lf/iE4+LX2rJH4it/+bLNvSI7JXbmS3/61K++9a+P/exrf/vc7773vw/+
+8It//OQvv/nPj/70q3/97G+/+98P//j+y3/+9K+//e+P//zrf//877///w+AASiAA0iABWiAB4iA
+CaiAC8iADeiADwiBtoc4n+Y6FChvFYg6qaOBG/g6HNiBq3OBE7gua1I1FCd1JKhsXkVa4jaCPRRD
+XoOCKUg1MMeCtVQZ0RdVZQVD/+I1dzImWsMT0AKDUmeCR3I3HHOELXdSahMoP/g0n/GCUdKETvgn
+5MMnJ3MYX4VFRQgoUChIboMmybdSIHOFYqhSfQFoJlWDQGOEYjMLs2A5b7iC6kQzaCJ6ayhLX6VN
+JONAgHVUdSiHu2KFPoaHD5QykrZDsYEq3VQSUzQ5qzUyMniDOTiGNoeFGPE8/DZjQjj+XzhIiXfm
+ibymegeFLBqkiZFYM4XoMXqjiqNHiskSikqIKIX2iDA3K9mSJ9QiiZmAiq3YhrIIjCoYjOrFilQo
+dGamibzoMlxoViozBrhIg8yojDOYjM6hi9XoXZcohf/whVaBWYi4LZXQh7WYhNsiil9Gi6eIe4lY
+KsP4Um6yV+04jKVIV7U4ilVIVKkYKzXGUAZHS3QoGbEniRv0j/tYWpmojqT1h+5yTANZaY5Whc8g
+Q8QEJ/AIjlrTi+aIMkn0M7lgKAupPQTTjWiIexfpDBZhhp+4PQ/Zj2TYUNpYh81CkRsJezKYSUt4
+hi6piDBJkuOYkji5ks5nSUA4JZz+uI1KMpPHyBIjeTVqBpKvcYNRmCTRCJBNmYtPaZV22Ip5cHv8
+xpVEWJVQiZRMKZakYZRS+HNkyYRaqJYtaIRS6Y0zGI/zRmlEJoIKFoIeaIF6mYEg6Jcf+JeNlpd/
+Y0qFGTsY2JeCGZiKCZiNuZeO+ZiMCZnnZZikg2CWaVCYiWSaWV6I6XB8mZiRKZmiGYGlaZqniZqp
+qZqryZqt2WuDOZl4uZikKZux+ZmzGZq5WZu2mZmc2ZueeZm+aZfC2V+wyZupZpy0eZu4uZzHuZlE
+OYUK85UlaJA6uJTSuTXU6IvTeJbwpUw9CDluKTZAWZ3N8TZiWZdulZ7UaY9s6Z3+NqidDjmNmFiR
+ntAtKRiI9qknh+GFgoh842iTqvCR7QmWDmmI79mT6hJKCgpVBkpm5RmewQWODRqSP5mTMWmhFLow
+XyOPzdBCC/VfBVmJBqOS5BlfIPomJeqOGvqd40mX71gL53km8RQscdOi6siRCHqiOMqNDGouwCSi
+TUKCSXmUYLSfRzmHYYmeD3mK98meI+qLKgqhUbqWBEqIDpqhUOqS63mOXfqkPJp6SgpgF+RgTnNv
+6Uil8MiOKcpr9AhHzNgsUjpiSZMRXGqidzqCV7c2ERqkVLqicroXdEozb5qQZNSeikimiSiROEGk
+YMhm+FifPTo5v7dPGNkyWTr+pzJ6oQ6ahy76p16KqSy6oYLqp6DqpTB6qqU4oeeIkBjzhDv5iNMZ
+n1NapUlKq/DplOT4P1+6qTwqXbEoqp7lqakao5qKqz66klwqTFQkWJAzV0Z3V31KosT5msmpm7up
+nMH5OcCprdaKrdn6m9yqU5W5reK6meUKms05mteqruwart7aru46rncZr99qr/farelar/mqr+/K
+nPvqr//qmgNLsAVrsAeLsAl7O8ansNP3U9ZjKaHasID0sNxTsc3Dbi86sfxzaPzRsZOUse62sR9y
+Ho8BI+RUp1KhhlMVshc7sgMSG8N0pUGZi8HET2KRYUxGSS37sh60jMuCZgD+Sqgn6U+xtLLTJqIS
+5bInEkD7+LE9qyASQShBCBX3g0j66KHFZbRDS3CkhkfQtLQu9UqGKrJQmyD+s1O1MpciRrYn9opm
+xkrPMkO0VEVqe7QNdFlm2yIFpoxusap1ezO8lTWdFJVu25U3qjKpeDBhWyI1BKx6CyJJJWltyahW
+dCrRgowf9kKH26s3qXrSAkV+BLm086EvKaYNirIZpyqlK2Lsxbmiij5xG7qjKzwh9oxA8k8eCmtf
+m10+pTFXyrgkEry0GyDd5Q2ykbtmtE1DtFN2YUGY2ranyjzDq3ePi05PO3U+IEzF6rsV8byg25mT
+BpJS+0aryqnTe33mC1P+WUVv+iYE6otUMzss4utNpuu6yGlN6auxWWtUMbFGWZW8S6Gza1hiXHJg
+w4lD1Jt38EtBNOW/NMdN+ysqBYwwFDwXB1ycxCsgDGxV/du+7ssdHAyhFtwuJFy/Ioy4GuyxEjwQ
+7OtpMxfCLEwnJvwyNGxTD6qjKkwjLvy++QjBPVy2UmTD0zTETYXCWqrD9MHDMexxuMbEAdxGAZwJ
+sNoCQOGH2MtZjhVZSWdZr7d0W9x00cqseAV2Z7VXz2pZYNx0XRxXSafGXRzGUwjHbwVZcxzHscfG
+39hEWWzHalXH2/saYsWrxYqSMnxxA6xyhoRviTxpyMqkV/Zy9+iPEMf+v+q2cqaGw8BSxEsGaZyR
+jWsWZmdmyM92xLOGyD9cyfdWc7iBN5Dsb678b6ZMyaWVcqjcY6XcbKfMySAGiqO8iUFMaJncaxh8
+rpucboucyoxMXTksybP2ygZnYzIXRrXsxLfsy3Wmy5A8wGH6Wbh8admMaNesusCMS+AMw7RcawUH
+wgm5otzscs8sy+mMzNW8cSjmzeNmzrkcaUr4yYFGzhh0z738z4c80PaLcvK8yo08nu68o84cy/qM
+0Adtyay8rcRcXsY8yW56buKsptPTzwkX0C6Xzx03zy1MzcccngxdcfDcbNE8yyatziSdbSFdzgX9
+yxqdaRxdZIpm0b/+iaY+PcgeJs2UEW3KjKeQGMmPDM2cHNHJbMv1DNKAbMpYLNKJ2kH1I9W5TNWk
+nNWwTHJ9M9SKnNDL7Mgq7YpevdTa/NJuUNRPjXNvbWQKt3NwPdc8nSNhjRdtTc9wqtQOjdZ+PclN
+jc4TrdBy/dV0bdcjp62SZNYEdtdr3RF6jdKH2s6VLYqN/cuCDdOETdYX2G6f7dmGfdg3F9c7gtex
+FdOXvNCWrV6sDZF3KNGqbNT6FNqKDWyiXdqkXdeL/diazdYnDdXsfNmuXWVq7duRDdznPNqJrdvM
+vdu8XdG4DWan3bypTdFlTdzmNm4ufdzTbN2FbdvFLN3OvdzkHd7RF93bJf3b393ZKZ3dSY3Z2AzZ
+3s3ZAhzd551mNv3Ozw3U5lHGpfPfl3NGA351Rmfgj6XHd7xYUKdZCR51rGE2vVJ1E04eAU45Fl7F
+1htMGv5LHN7hXZ3EIS7iI07iJW7iJ47iKa7iK87iLe7iLw7jMS7jM07jNW7jN47jOa7jO87jPe7j
+Pw7kQV68E+EQhqrAQs6aZmirzYzkQC4aAmmIygHlTS7kP0G3gRJ8VB7kAGCRbQB8uqflTu6Ci4jl
+ehjmPs7laf58XB7Fau6DR56aBQAAOw==
diff --git a/Documentation/DocBook/media/vbi_hsync.gif.b64 b/Documentation/DocBook/media/vbi_hsync.gif.b64
new file mode 100644 (file)
index 0000000..cdafabe
--- /dev/null
@@ -0,0 +1,43 @@
+R0lGODlhBwHJAOcAAAAAAAEBAQICAgMDAwQEBAUFBQYGBgcHBwgICAkJCQoKCgsLCwwMDA0NDQ4O
+Dg8PDxAQEBERERISEhMTExQUFBUVFRYWFhcXFxgYGBkZGRoaGhsbGxwcHB0dHR4eHh8fHyAgICEh
+ISIiIiMjIyQkJCUlJSYmJicnJygoKCkpKSoqKisrKywsLC0tLS4uLi8vLzAwMDExMTIyMjMzMzQ0
+NDU1NTY2Njc3Nzg4ODk5OTo6Ojs7Ozw8PD09PT4+Pj8/P0BAQEFBQUJCQkNDQ0REREVFRUZGRkdH
+R0hISElJSUpKSktLS0xMTE1NTU5OTk9PT1BQUFFRUVJSUlNTU1RUVFVVVVZWVldXV1hYWFlZWVpa
+WltbW1xcXF1dXV5eXl9fX2BgYGFhYWJiYmNjY2RkZGVlZWZmZmdnZ2hoaGlpaWpqamtra2xsbG1t
+bW5ubm9vb3BwcHFxcXJycnNzc3R0dHV1dXZ2dnd3d3h4eHl5eXp6ent7e3x8fH19fX5+fn9/f4CA
+gIGBgYKCgoODg4SEhIWFhYaGhoeHh4iIiImJiYqKiouLi4yMjI2NjY6Ojo+Pj5CQkJGRkZKSkpOT
+k5SUlJWVlZaWlpeXl5iYmJmZmZqampubm5ycnJ2dnZ6enp+fn6CgoKGhoaKioqOjo6SkpKWlpaam
+pqenp6ioqKmpqaqqqqurq6ysrK2tra6urq+vr7CwsLGxsbKysrOzs7S0tLW1tba2tre3t7i4uLm5
+ubq6uru7u7y8vL29vb6+vr+/v8DAwMHBwcLCwsPDw8TExMXFxcbGxsfHx8jIyMnJycrKysvLy8zM
+zM3Nzc7Ozs/Pz9DQ0NHR0dLS0tPT09TU1NXV1dbW1tfX19jY2NnZ2dra2tvb29zc3N3d3d7e3t/f
+3+Dg4OHh4eLi4uPj4+Tk5OXl5ebm5ufn5+jo6Onp6erq6uvr6+zs7O3t7e7u7u/v7/Dw8PHx8fLy
+8vPz8/T09PX19fb29vf39/j4+Pn5+fr6+vv7+/z8/P39/f7+/v///ywAAAAABwHJAAAI/gD/CRxI
+sKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPHjyBDihxJsqTJkyhTqlzJsqXLlzBjypxJs6bN
+mzhz6tzJs6fPn0CDCh1KtKjRo0iTKl3KtKnTp1CjSp1KtarVqyQBYN1aVSvXr1C9gh2rVOxCsV4B
+mE2b0GxDt2TjtnWo9l9du2rrar2bl+BavQL3ApZLeC5du3j77g2MF/FAtIv1AoZb+Gfey5gza97M
+ua/ByJ4XI8b8+PHl0ZkrE6XsuCDr1xD5ip7d2m9pv6IZqxYK+zPC3g/T0mabGLdk4YEH7wYK3PZB
+yqyXSw/++3l139OzS4R+Hbtr7eCp/nv/bp18+PMKuZcfj7792fXm47ufz/52fd308zu/X3u/fv3N
++Sfgf/MFaJ98BLpnIH4IJojegv0d6GB7EEI4oXYVdnfhgxoOyOCG4WXIH4jTidggiSV2KOGHKGa3
+oIUtqvaiijEuNyN8NUp344g5EqYef9H1KNePJwYpJFlEehjhkT7iuCKLTMZl4olRgjWlklV+deWT
+WWpJ45JgdrnVllCKOeaXMJrZFZpfqmkVmWG6SRWcRsoZFZl12hkWmzxemCdXeAr555lOgjnof4de
+tSOVG0KWaFl3GVponH52ZumlmGaq6aaY0pjmhJppmRqQbTaKm6gewgnio2uSOumq/jpO+qmDrE5F
+p6AtSZZeSrf2WOtEoZEmm2C/Astnn6CapKtjbClWZki95lhsbLcRtxmlHkVb47TBWcuYcGvxeiyj
+fp7kGbOJEZscStrGyK1T7bb4blPxojgvU4Hiulu+vto4Lpck3rvUoljCuq+npZp6cKGz0uovwwmX
+u3CRESc7sZINJyhwWbJW7PDFXGZM4MZI1WsvyCF7rDHKZYqMKMuSvmqwS5yOypHJAcP0K8k4z5xr
+RTz/C7DPLO2crdDPEr2S0R31rDDNQB/dMbISQ01R0FOT+/TPV0vtqtZVc21s0wjLLONFJG8XNdkQ
+y5z2UNy+TW3XbN8Ho9xBxa3z/to3lz0i3nljBPhbfG+UZMoqG5db2+KJ9O7gDDHd99dUstpscsgR
+x6CzqC0O0uN70z05xVlHdNpwgvUHGWrFef5RppGHPjawNddue3nB5nYufsKmu/vrhL/3kuRqq1Tr
+6pd/G+6HymGLdvC7Dl+46cYD7aywoSleXGOtj5RnnZALP3vx7Bb2J/iyk6++subTZanz2ZJ2te2R
+st8+9NaFHx/x1Jff5GFz0Z9/+Dc3c9EnSK4ryfLG1z89GaY6AjwQARvnQLfBr24XpFrizGSk+tlv
+aOJbXwULxj3/gTB6DBwhCD2oQLBtkIR66mAEVTe9AqqQhCzMigvNhsIbrnCG/m6ZIAB9+MPqwfCB
+IryhDI14QiQ2kIiUyqH3dqhBHtoJfSZs4gu16CYsGpCKYDyinLz4QS5W8YwcjF0WkxbCJxKRjC0M
+oxnlmCU46tA19BPiCO04xZjM8IBq/GL63hjIMloNitiS4uv+aMUxRk5/ihQXIhMJSUaiUUzgq6RM
+LEmhR5qLk2LsoieVBco5YnKUCiwlG2OIyqyoMoNpPIsm/TjJRMKya698JYZiB7kELq2W6OvlLT8H
+TF62MJfM+R3+lnnIAB5zk8zBHOZks7/BqEuXwXwmLS1DzestDnmNud5MsqlDZPKGWMkzT+9CBc33
+5PGd8IynPOfJwkilLp37/gniN8dZyDgOcienCadudnc6anavnT30p/SKokvH9fOO/+RmqxIK0YUi
+EosBNVz2tnnRR9KzUxyFYjAzqpHehZSQbdxYEBEqUhcVM0WTbGhNZBor+7xNj8SMaT7TJc1Tgcug
+Bf2LNZnlKODp1KYCbR64ujcZ0OBxe5FR3jAfqsSdNiujucMnPnl3uaxiraNI3ep3hro8161uNLbB
+G00fNk3abG+aAiXqcKqlGG8Oy6hgLang+HnUjERyiBFV4VpZitKa5rWEgKJjldgpKs5d9KOQjeym
+XkrSMdnzpYatpWY3y1l6NXGB3RlsZ9eDzp7ydKmnW1dAlTnaQ94zruEkS2tUnfra1iIUdRvlHueu
+iS7N2daic1VncEEz3N/6MbVyNU1TV0tUdL3VuF6aKnQhJdrpWve62M2udrfL3e5697vgDa94x0ve
+8lIkIAA7
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl
new file mode 100644 (file)
index 0000000..4e8e898
--- /dev/null
@@ -0,0 +1,121 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY % media-entities SYSTEM "./media-entities.tmpl"> %media-entities;
+<!ENTITY media-indices SYSTEM "./media-indices.tmpl">
+
+<!ENTITY eg                     "e.&nbsp;g.">
+<!ENTITY ie                     "i.&nbsp;e.">
+<!ENTITY fd                     "File descriptor returned by <link linkend='func-open'><function>open()</function></link>.">
+<!ENTITY i2c                    "I<superscript>2</superscript>C">
+<!ENTITY return-value          "<title>Return Value</title><para>On success <returnvalue>0</returnvalue> is returned, on error <returnvalue>-1</returnvalue> and the <varname>errno</varname> variable is set appropriately. The generic error codes are described at the <link linkend='gen-errors'>Generic Error Codes</link> chapter.</para>">
+<!ENTITY return-value-dvb      "<para>RETURN VALUE</para><para>On success <returnvalue>0</returnvalue> is returned, on error <returnvalue>-1</returnvalue> and the <varname>errno</varname> variable is set appropriately. The generic error codes are described at the <link linkend='gen-errors'>Generic Error Codes</link> chapter.</para>">
+<!ENTITY manvol                 "<manvolnum>2</manvolnum>">
+
+<!-- Table templates: structs, structs w/union, defines. -->
+<!ENTITY cs-str                 "<colspec colname='c1' colwidth='1*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='2*' /><spanspec spanname='hspan' namest='c1' nameend='c3' />">
+<!ENTITY cs-ustr                "<colspec colname='c1' colwidth='1*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='1*' /><colspec colname='c4' colwidth='2*' /><spanspec spanname='hspan' namest='c1' nameend='c4' />">
+<!ENTITY cs-def                 "<colspec colname='c1' colwidth='3*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='4*' /><spanspec spanname='hspan' namest='c1' nameend='c3' />">
+
+<!-- Video for Linux mailing list address. -->
+<!ENTITY v4l-ml                 "<ulink url='http://www.linuxtv.org/lists.php'>http://www.linuxtv.org/lists.php</ulink>">
+
+<!-- LinuxTV v4l-dvb repository. -->
+<!ENTITY v4l-dvb               "<ulink url='http://linuxtv.org/repo/'>http://linuxtv.org/repo/</ulink>">
+]>
+
+<book id="media_api">
+<bookinfo>
+<title>LINUX MEDIA INFRASTRUCTURE API</title>
+
+<copyright>
+       <year>2009-2011</year>
+       <holder>LinuxTV Developers</holder>
+</copyright>
+
+<legalnotice>
+
+<para>Permission is granted to copy, distribute and/or modify
+this document under the terms of the GNU Free Documentation License,
+Version 1.1 or any later version published by the Free Software
+Foundation. A copy of the license is included in the chapter entitled
+"GNU Free Documentation License"</para>
+</legalnotice>
+
+</bookinfo>
+
+<toc></toc> <!-- autogenerated -->
+
+<preface>
+       <title>Introduction</title>
+
+       <para>This document covers the Linux Kernel to Userspace API's used by
+               video and radio straming devices, including video cameras,
+               analog and digital TV receiver cards, AM/FM receiver cards,
+               streaming capture devices.</para>
+       <para>It is divided into three parts.</para>
+       <para>The first part covers radio, capture,
+               cameras and analog TV devices.</para>
+       <para>The second part covers the
+               API used for digital TV and Internet reception via one of the
+               several digital tv standards. While it is called as DVB API,
+               in fact it covers several different video standards including
+               DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated
+               to documment support also for DVB-S2, ISDB-T and ISDB-S.</para>
+       <para>The third part covers Remote Controller API</para>
+       <para>For additional information and for the latest development code,
+               see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
+       <para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
+
+</preface>
+
+<part id="v4l2spec">
+&sub-v4l2;
+</part>
+<part id="dvbapi">
+&sub-dvbapi;
+</part>
+<part id="v4ldvb_common">
+<partinfo>
+<authorgroup>
+<author>
+<firstname>Mauro</firstname>
+<surname>Chehab</surname>
+<othername role="mi">Carvalho</othername>
+<affiliation><address><email>mchehab@redhat.com</email></address></affiliation>
+<contrib>Initial version.</contrib>
+</author>
+</authorgroup>
+<copyright>
+       <year>2009-2011</year>
+       <holder>Mauro Carvalho Chehab</holder>
+</copyright>
+
+<revhistory>
+<!-- Put document revisions here, newest first. -->
+<revision>
+<revnumber>1.0.0</revnumber>
+<date>2009-09-06</date>
+<authorinitials>mcc</authorinitials>
+<revremark>Initial revision</revremark>
+</revision>
+</revhistory>
+</partinfo>
+
+<title>Remote Controller API</title>
+<chapter id="remote_controllers">
+&sub-remote_controllers;
+</chapter>
+</part>
+<part id="media_common">
+&sub-media-controller;
+</part>
+
+<chapter id="gen_errors">
+&sub-gen-errors;
+</chapter>
+
+
+&sub-fdl-appendix;
+
+</book>
diff --git a/Documentation/DocBook/v4l/.gitignore b/Documentation/DocBook/v4l/.gitignore
deleted file mode 100644 (file)
index d7ec32e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-!*.xml
diff --git a/Documentation/DocBook/v4l/bayer.pdf b/Documentation/DocBook/v4l/bayer.pdf
deleted file mode 100644 (file)
index 905e60e..0000000
Binary files a/Documentation/DocBook/v4l/bayer.pdf and /dev/null differ
diff --git a/Documentation/DocBook/v4l/bayer.png b/Documentation/DocBook/v4l/bayer.png
deleted file mode 100644 (file)
index 9b15fb2..0000000
Binary files a/Documentation/DocBook/v4l/bayer.png and /dev/null differ
diff --git a/Documentation/DocBook/v4l/biblio.xml b/Documentation/DocBook/v4l/biblio.xml
deleted file mode 100644 (file)
index afc8a0d..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-  <bibliography>
-    <title>References</title>
-
-    <biblioentry id="eia608">
-      <abbrev>EIA&nbsp;608-B</abbrev>
-      <authorgroup>
-       <corpauthor>Electronic Industries Alliance (<ulink
-url="http://www.eia.org">http://www.eia.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>EIA 608-B "Recommended Practice for Line 21 Data
-Service"</title>
-    </biblioentry>
-
-    <biblioentry id="en300294">
-      <abbrev>EN&nbsp;300&nbsp;294</abbrev>
-      <authorgroup>
-       <corpauthor>European Telecommunication Standards Institute
-(<ulink url="http://www.etsi.org">http://www.etsi.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>EN 300 294 "625-line television Wide Screen Signalling
-(WSS)"</title>
-    </biblioentry>
-
-    <biblioentry id="ets300231">
-      <abbrev>ETS&nbsp;300&nbsp;231</abbrev>
-      <authorgroup>
-       <corpauthor>European Telecommunication Standards Institute
-(<ulink
-url="http://www.etsi.org">http://www.etsi.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ETS 300 231 "Specification of the domestic video
-Programme Delivery Control system (PDC)"</title>
-    </biblioentry>
-
-    <biblioentry id="ets300706">
-      <abbrev>ETS&nbsp;300&nbsp;706</abbrev>
-      <authorgroup>
-       <corpauthor>European Telecommunication Standards Institute
-(<ulink url="http://www.etsi.org">http://www.etsi.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ETS 300 706 "Enhanced Teletext specification"</title>
-    </biblioentry>
-
-    <biblioentry id="mpeg2part1">
-      <abbrev>ISO&nbsp;13818-1</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>), International
-Organisation for Standardisation (<ulink
-url="http://www.iso.ch">http://www.iso.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-T Rec. H.222.0 | ISO/IEC 13818-1 "Information
-technology &mdash; Generic coding of moving pictures and associated
-audio information: Systems"</title>
-    </biblioentry>
-
-    <biblioentry id="mpeg2part2">
-      <abbrev>ISO&nbsp;13818-2</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>), International
-Organisation for Standardisation (<ulink
-url="http://www.iso.ch">http://www.iso.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-T Rec. H.262 | ISO/IEC 13818-2 "Information
-technology &mdash; Generic coding of moving pictures and associated
-audio information: Video"</title>
-    </biblioentry>
-
-    <biblioentry id="itu470">
-      <abbrev>ITU&nbsp;BT.470</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.470-6 "Conventional Television
-Systems"</title>
-    </biblioentry>
-
-    <biblioentry id="itu601">
-      <abbrev>ITU&nbsp;BT.601</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.601-5 "Studio Encoding Parameters
-of Digital Television for Standard 4:3 and Wide-Screen 16:9 Aspect
-Ratios"</title>
-    </biblioentry>
-
-    <biblioentry id="itu653">
-      <abbrev>ITU&nbsp;BT.653</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.653-3 "Teletext systems"</title>
-    </biblioentry>
-
-    <biblioentry id="itu709">
-      <abbrev>ITU&nbsp;BT.709</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.709-5 "Parameter values for the
-HDTV standards for production and international programme
-exchange"</title>
-    </biblioentry>
-
-    <biblioentry id="itu1119">
-      <abbrev>ITU&nbsp;BT.1119</abbrev>
-      <authorgroup>
-       <corpauthor>International Telecommunication Union (<ulink
-url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
-      </authorgroup>
-      <title>ITU-R Recommendation BT.1119 "625-line
-television Wide Screen Signalling (WSS)"</title>
-    </biblioentry>
-
-    <biblioentry id="jfif">
-      <abbrev>JFIF</abbrev>
-      <authorgroup>
-       <corpauthor>Independent JPEG Group (<ulink
-url="http://www.ijg.org">http://www.ijg.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>JPEG File Interchange Format</title>
-      <subtitle>Version 1.02</subtitle>
-    </biblioentry>
-
-    <biblioentry id="smpte12m">
-      <abbrev>SMPTE&nbsp;12M</abbrev>
-      <authorgroup>
-       <corpauthor>Society of Motion Picture and Television Engineers
-(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>SMPTE 12M-1999 "Television, Audio and Film - Time and
-Control Code"</title>
-    </biblioentry>
-
-    <biblioentry id="smpte170m">
-      <abbrev>SMPTE&nbsp;170M</abbrev>
-      <authorgroup>
-       <corpauthor>Society of Motion Picture and Television Engineers
-(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>SMPTE 170M-1999 "Television - Composite Analog Video
-Signal - NTSC for Studio Applications"</title>
-    </biblioentry>
-
-    <biblioentry id="smpte240m">
-      <abbrev>SMPTE&nbsp;240M</abbrev>
-      <authorgroup>
-       <corpauthor>Society of Motion Picture and Television Engineers
-(<ulink url="http://www.smpte.org">http://www.smpte.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>SMPTE 240M-1999 "Television - Signal Parameters -
-1125-Line High-Definition Production"</title>
-    </biblioentry>
-
-    <biblioentry id="en50067">
-      <abbrev>EN&nbsp;50067</abbrev>
-      <authorgroup>
-       <corpauthor>European Committee for Electrotechnical Standardization
-(<ulink url="http://www.cenelec.eu">http://www.cenelec.eu</ulink>)</corpauthor>
-      </authorgroup>
-      <title>Specification of the radio data system (RDS) for VHF/FM sound broadcasting
-in the frequency range from 87,5 to 108,0 MHz</title>
-    </biblioentry>
-
-    <biblioentry id="nrsc4">
-      <abbrev>NRSC-4</abbrev>
-      <authorgroup>
-       <corpauthor>National Radio Systems Committee
-(<ulink url="http://www.nrscstandards.org">http://www.nrscstandards.org</ulink>)</corpauthor>
-      </authorgroup>
-      <title>NTSC-4: United States RBDS Standard</title>
-    </biblioentry>
-
-  </bibliography>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/capture.c.xml b/Documentation/DocBook/v4l/capture.c.xml
deleted file mode 100644 (file)
index 1c5c49a..0000000
+++ /dev/null
@@ -1,659 +0,0 @@
-<programlisting>
-/*
- *  V4L2 video capture example
- *
- *  This program can be used and distributed without restrictions.
- *
- *      This program is provided with the V4L2 API
- * see http://linuxtv.org/docs.php for more information
- */
-
-#include &lt;stdio.h&gt;
-#include &lt;stdlib.h&gt;
-#include &lt;string.h&gt;
-#include &lt;assert.h&gt;
-
-#include &lt;getopt.h&gt;             /* getopt_long() */
-
-#include &lt;fcntl.h&gt;              /* low-level i/o */
-#include &lt;unistd.h&gt;
-#include &lt;errno.h&gt;
-#include &lt;sys/stat.h&gt;
-#include &lt;sys/types.h&gt;
-#include &lt;sys/time.h&gt;
-#include &lt;sys/mman.h&gt;
-#include &lt;sys/ioctl.h&gt;
-
-#include &lt;linux/videodev2.h&gt;
-
-#define CLEAR(x) memset(&amp;(x), 0, sizeof(x))
-
-enum io_method {
-        IO_METHOD_READ,
-        IO_METHOD_MMAP,
-        IO_METHOD_USERPTR,
-};
-
-struct buffer {
-        void   *start;
-        size_t  length;
-};
-
-static char            *dev_name;
-static enum io_method   io = IO_METHOD_MMAP;
-static int              fd = -1;
-struct buffer          *buffers;
-static unsigned int     n_buffers;
-static int              out_buf;
-static int              force_format;
-static int              frame_count = 70;
-
-static void errno_exit(const char *s)
-{
-        fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
-        exit(EXIT_FAILURE);
-}
-
-static int xioctl(int fh, int request, void *arg)
-{
-        int r;
-
-        do {
-                r = ioctl(fh, request, arg);
-        } while (-1 == r &amp;&amp; EINTR == errno);
-
-        return r;
-}
-
-static void process_image(const void *p, int size)
-{
-        if (out_buf)
-                fwrite(p, size, 1, stdout);
-
-        fflush(stderr);
-        fprintf(stderr, ".");
-        fflush(stdout);
-}
-
-static int read_frame(void)
-{
-        struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
-        unsigned int i;
-
-        switch (io) {
-        case IO_METHOD_READ:
-                if (-1 == read(fd, buffers[0].start, buffers[0].length)) {
-                        switch (errno) {
-                        case EAGAIN:
-                                return 0;
-
-                        case EIO:
-                                /* Could ignore EIO, see spec. */
-
-                                /* fall through */
-
-                        default:
-                                errno_exit("read");
-                        }
-                }
-
-                process_image(buffers[0].start, buffers[0].length);
-                break;
-
-        case IO_METHOD_MMAP:
-                CLEAR(buf);
-
-                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory = V4L2_MEMORY_MMAP;
-
-                if (-1 == xioctl(fd, VIDIOC_DQBUF, &amp;buf)) {
-                        switch (errno) {
-                        case EAGAIN:
-                                return 0;
-
-                        case EIO:
-                                /* Could ignore EIO, see spec. */
-
-                                /* fall through */
-
-                        default:
-                                errno_exit("VIDIOC_DQBUF");
-                        }
-                }
-
-                assert(buf.index &lt; n_buffers);
-
-                process_image(buffers[buf.index].start, buf.bytesused);
-
-                if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
-                        errno_exit("VIDIOC_QBUF");
-                break;
-
-        case IO_METHOD_USERPTR:
-                CLEAR(buf);
-
-                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory = V4L2_MEMORY_USERPTR;
-
-                if (-1 == xioctl(fd, VIDIOC_DQBUF, &amp;buf)) {
-                        switch (errno) {
-                        case EAGAIN:
-                                return 0;
-
-                        case EIO:
-                                /* Could ignore EIO, see spec. */
-
-                                /* fall through */
-
-                        default:
-                                errno_exit("VIDIOC_DQBUF");
-                        }
-                }
-
-                for (i = 0; i &lt; n_buffers; ++i)
-                        if (buf.m.userptr == (unsigned long)buffers[i].start
-                            &amp;&amp; buf.length == buffers[i].length)
-                                break;
-
-                assert(i &lt; n_buffers);
-
-                process_image((void *)buf.m.userptr, buf.bytesused);
-
-                if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
-                        errno_exit("VIDIOC_QBUF");
-                break;
-        }
-
-        return 1;
-}
-
-static void mainloop(void)
-{
-        unsigned int count;
-
-        count = frame_count;
-
-        while (count-- &gt; 0) {
-                for (;;) {
-                        fd_set fds;
-                        struct timeval tv;
-                        int r;
-
-                        FD_ZERO(&amp;fds);
-                        FD_SET(fd, &amp;fds);
-
-                        /* Timeout. */
-                        tv.tv_sec = 2;
-                        tv.tv_usec = 0;
-
-                        r = select(fd + 1, &amp;fds, NULL, NULL, &amp;tv);
-
-                        if (-1 == r) {
-                                if (EINTR == errno)
-                                        continue;
-                                errno_exit("select");
-                        }
-
-                        if (0 == r) {
-                                fprintf(stderr, "select timeout\n");
-                                exit(EXIT_FAILURE);
-                        }
-
-                        if (read_frame())
-                                break;
-                        /* EAGAIN - continue select loop. */
-                }
-        }
-}
-
-static void stop_capturing(void)
-{
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
-
-        switch (io) {
-        case IO_METHOD_READ:
-                /* Nothing to do. */
-                break;
-
-        case IO_METHOD_MMAP:
-        case IO_METHOD_USERPTR:
-                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &amp;type))
-                        errno_exit("VIDIOC_STREAMOFF");
-                break;
-        }
-}
-
-static void start_capturing(void)
-{
-        unsigned int i;
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
-
-        switch (io) {
-        case IO_METHOD_READ:
-                /* Nothing to do. */
-                break;
-
-        case IO_METHOD_MMAP:
-                for (i = 0; i &lt; n_buffers; ++i) {
-                        struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
-
-                        CLEAR(buf);
-                        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                        buf.memory = V4L2_MEMORY_MMAP;
-                        buf.index = i;
-
-                        if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
-                                errno_exit("VIDIOC_QBUF");
-                }
-                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                if (-1 == xioctl(fd, VIDIOC_STREAMON, &amp;type))
-                        errno_exit("VIDIOC_STREAMON");
-                break;
-
-        case IO_METHOD_USERPTR:
-                for (i = 0; i &lt; n_buffers; ++i) {
-                        struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
-
-                        CLEAR(buf);
-                        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                        buf.memory = V4L2_MEMORY_USERPTR;
-                        buf.index = i;
-                        buf.m.userptr = (unsigned long)buffers[i].start;
-                        buf.length = buffers[i].length;
-
-                        if (-1 == xioctl(fd, VIDIOC_QBUF, &amp;buf))
-                                errno_exit("VIDIOC_QBUF");
-                }
-                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                if (-1 == xioctl(fd, VIDIOC_STREAMON, &amp;type))
-                        errno_exit("VIDIOC_STREAMON");
-                break;
-        }
-}
-
-static void uninit_device(void)
-{
-        unsigned int i;
-
-        switch (io) {
-        case IO_METHOD_READ:
-                free(buffers[0].start);
-                break;
-
-        case IO_METHOD_MMAP:
-                for (i = 0; i &lt; n_buffers; ++i)
-                        if (-1 == munmap(buffers[i].start, buffers[i].length))
-                                errno_exit("munmap");
-                break;
-
-        case IO_METHOD_USERPTR:
-                for (i = 0; i &lt; n_buffers; ++i)
-                        free(buffers[i].start);
-                break;
-        }
-
-        free(buffers);
-}
-
-static void init_read(unsigned int buffer_size)
-{
-        buffers = calloc(1, sizeof(*buffers));
-
-        if (!buffers) {
-                fprintf(stderr, "Out of memory\n");
-                exit(EXIT_FAILURE);
-        }
-
-        buffers[0].length = buffer_size;
-        buffers[0].start = malloc(buffer_size);
-
-        if (!buffers[0].start) {
-                fprintf(stderr, "Out of memory\n");
-                exit(EXIT_FAILURE);
-        }
-}
-
-static void init_mmap(void)
-{
-        struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> req;
-
-        CLEAR(req);
-
-        req.count = 4;
-        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        req.memory = V4L2_MEMORY_MMAP;
-
-        if (-1 == xioctl(fd, VIDIOC_REQBUFS, &amp;req)) {
-                if (EINVAL == errno) {
-                        fprintf(stderr, "%s does not support "
-                                 "memory mapping\n", dev_name);
-                        exit(EXIT_FAILURE);
-                } else {
-                        errno_exit("VIDIOC_REQBUFS");
-                }
-        }
-
-        if (req.count &lt; 2) {
-                fprintf(stderr, "Insufficient buffer memory on %s\n",
-                         dev_name);
-                exit(EXIT_FAILURE);
-        }
-
-        buffers = calloc(req.count, sizeof(*buffers));
-
-        if (!buffers) {
-                fprintf(stderr, "Out of memory\n");
-                exit(EXIT_FAILURE);
-        }
-
-        for (n_buffers = 0; n_buffers &lt; req.count; ++n_buffers) {
-                struct <link linkend="v4l2-buffer">v4l2_buffer</link> buf;
-
-                CLEAR(buf);
-
-                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory      = V4L2_MEMORY_MMAP;
-                buf.index       = n_buffers;
-
-                if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &amp;buf))
-                        errno_exit("VIDIOC_QUERYBUF");
-
-                buffers[n_buffers].length = buf.length;
-                buffers[n_buffers].start =
-                        mmap(NULL /* start anywhere */,
-                              buf.length,
-                              PROT_READ | PROT_WRITE /* required */,
-                              MAP_SHARED /* recommended */,
-                              fd, buf.m.offset);
-
-                if (MAP_FAILED == buffers[n_buffers].start)
-                        errno_exit("mmap");
-        }
-}
-
-static void init_userp(unsigned int buffer_size)
-{
-        struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> req;
-
-        CLEAR(req);
-
-        req.count  = 4;
-        req.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        req.memory = V4L2_MEMORY_USERPTR;
-
-        if (-1 == xioctl(fd, VIDIOC_REQBUFS, &amp;req)) {
-                if (EINVAL == errno) {
-                        fprintf(stderr, "%s does not support "
-                                 "user pointer i/o\n", dev_name);
-                        exit(EXIT_FAILURE);
-                } else {
-                        errno_exit("VIDIOC_REQBUFS");
-                }
-        }
-
-        buffers = calloc(4, sizeof(*buffers));
-
-        if (!buffers) {
-                fprintf(stderr, "Out of memory\n");
-                exit(EXIT_FAILURE);
-        }
-
-        for (n_buffers = 0; n_buffers &lt; 4; ++n_buffers) {
-                buffers[n_buffers].length = buffer_size;
-                buffers[n_buffers].start = malloc(buffer_size);
-
-                if (!buffers[n_buffers].start) {
-                        fprintf(stderr, "Out of memory\n");
-                        exit(EXIT_FAILURE);
-                }
-        }
-}
-
-static void init_device(void)
-{
-        struct <link linkend="v4l2-capability">v4l2_capability</link> cap;
-        struct <link linkend="v4l2-cropcap">v4l2_cropcap</link> cropcap;
-        struct <link linkend="v4l2-crop">v4l2_crop</link> crop;
-        struct <link linkend="v4l2-format">v4l2_format</link> fmt;
-        unsigned int min;
-
-        if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &amp;cap)) {
-                if (EINVAL == errno) {
-                        fprintf(stderr, "%s is no V4L2 device\n",
-                                 dev_name);
-                        exit(EXIT_FAILURE);
-                } else {
-                        errno_exit("VIDIOC_QUERYCAP");
-                }
-        }
-
-        if (!(cap.capabilities &amp; V4L2_CAP_VIDEO_CAPTURE)) {
-                fprintf(stderr, "%s is no video capture device\n",
-                         dev_name);
-                exit(EXIT_FAILURE);
-        }
-
-        switch (io) {
-        case IO_METHOD_READ:
-                if (!(cap.capabilities &amp; V4L2_CAP_READWRITE)) {
-                        fprintf(stderr, "%s does not support read i/o\n",
-                                 dev_name);
-                        exit(EXIT_FAILURE);
-                }
-                break;
-
-        case IO_METHOD_MMAP:
-        case IO_METHOD_USERPTR:
-                if (!(cap.capabilities &amp; V4L2_CAP_STREAMING)) {
-                        fprintf(stderr, "%s does not support streaming i/o\n",
-                                 dev_name);
-                        exit(EXIT_FAILURE);
-                }
-                break;
-        }
-
-
-        /* Select video input, video standard and tune here. */
-
-
-        CLEAR(cropcap);
-
-        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-        if (0 == xioctl(fd, VIDIOC_CROPCAP, &amp;cropcap)) {
-                crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                crop.c = cropcap.defrect; /* reset to default */
-
-                if (-1 == xioctl(fd, VIDIOC_S_CROP, &amp;crop)) {
-                        switch (errno) {
-                        case EINVAL:
-                                /* Cropping not supported. */
-                                break;
-                        default:
-                                /* Errors ignored. */
-                                break;
-                        }
-                }
-        } else {
-                /* Errors ignored. */
-        }
-
-
-        CLEAR(fmt);
-
-        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        if (force_format) {
-                fmt.fmt.pix.width       = 640;
-                fmt.fmt.pix.height      = 480;
-                fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-                fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
-
-                if (-1 == xioctl(fd, VIDIOC_S_FMT, &amp;fmt))
-                        errno_exit("VIDIOC_S_FMT");
-
-                /* Note VIDIOC_S_FMT may change width and height. */
-        } else {
-                /* Preserve original settings as set by v4l2-ctl for example */
-                if (-1 == xioctl(fd, VIDIOC_G_FMT, &amp;fmt))
-                        errno_exit("VIDIOC_G_FMT");
-        }
-
-        /* Buggy driver paranoia. */
-        min = fmt.fmt.pix.width * 2;
-        if (fmt.fmt.pix.bytesperline &lt; min)
-                fmt.fmt.pix.bytesperline = min;
-        min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
-        if (fmt.fmt.pix.sizeimage &lt; min)
-                fmt.fmt.pix.sizeimage = min;
-
-        switch (io) {
-        case IO_METHOD_READ:
-                init_read(fmt.fmt.pix.sizeimage);
-                break;
-
-        case IO_METHOD_MMAP:
-                init_mmap();
-                break;
-
-        case IO_METHOD_USERPTR:
-                init_userp(fmt.fmt.pix.sizeimage);
-                break;
-        }
-}
-
-static void close_device(void)
-{
-        if (-1 == close(fd))
-                errno_exit("close");
-
-        fd = -1;
-}
-
-static void open_device(void)
-{
-        struct stat st;
-
-        if (-1 == stat(dev_name, &amp;st)) {
-                fprintf(stderr, "Cannot identify '%s': %d, %s\n",
-                         dev_name, errno, strerror(errno));
-                exit(EXIT_FAILURE);
-        }
-
-        if (!S_ISCHR(st.st_mode)) {
-                fprintf(stderr, "%s is no device\n", dev_name);
-                exit(EXIT_FAILURE);
-        }
-
-        fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
-
-        if (-1 == fd) {
-                fprintf(stderr, "Cannot open '%s': %d, %s\n",
-                         dev_name, errno, strerror(errno));
-                exit(EXIT_FAILURE);
-        }
-}
-
-static void usage(FILE *fp, int argc, char **argv)
-{
-        fprintf(fp,
-                 "Usage: %s [options]\n\n"
-                 "Version 1.3\n"
-                 "Options:\n"
-                 "-d | --device name   Video device name [%s]\n"
-                 "-h | --help          Print this message\n"
-                 "-m | --mmap          Use memory mapped buffers [default]\n"
-                 "-r | --read          Use read() calls\n"
-                 "-u | --userp         Use application allocated buffers\n"
-                 "-o | --output        Outputs stream to stdout\n"
-                 "-f | --format        Force format to 640x480 YUYV\n"
-                 "-c | --count         Number of frames to grab [%i]\n"
-                 "",
-                 argv[0], dev_name, frame_count);
-}
-
-static const char short_options[] = "d:hmruofc:";
-
-static const struct option
-long_options[] = {
-        { "device", required_argument, NULL, 'd' },
-        { "help",   no_argument,       NULL, 'h' },
-        { "mmap",   no_argument,       NULL, 'm' },
-        { "read",   no_argument,       NULL, 'r' },
-        { "userp",  no_argument,       NULL, 'u' },
-        { "output", no_argument,       NULL, 'o' },
-        { "format", no_argument,       NULL, 'f' },
-        { "count",  required_argument, NULL, 'c' },
-        { 0, 0, 0, 0 }
-};
-
-int main(int argc, char **argv)
-{
-        dev_name = "/dev/video0";
-
-        for (;;) {
-                int idx;
-                int c;
-
-                c = getopt_long(argc, argv,
-                                short_options, long_options, &amp;idx);
-
-                if (-1 == c)
-                        break;
-
-                switch (c) {
-                case 0: /* getopt_long() flag */
-                        break;
-
-                case 'd':
-                        dev_name = optarg;
-                        break;
-
-                case 'h':
-                        usage(stdout, argc, argv);
-                        exit(EXIT_SUCCESS);
-
-                case 'm':
-                        io = IO_METHOD_MMAP;
-                        break;
-
-                case 'r':
-                        io = IO_METHOD_READ;
-                        break;
-
-                case 'u':
-                        io = IO_METHOD_USERPTR;
-                        break;
-
-                case 'o':
-                        out_buf++;
-                        break;
-
-                case 'f':
-                        force_format++;
-                        break;
-
-                case 'c':
-                        errno = 0;
-                        frame_count = strtol(optarg, NULL, 0);
-                        if (errno)
-                                errno_exit(optarg);
-                        break;
-
-                default:
-                        usage(stderr, argc, argv);
-                        exit(EXIT_FAILURE);
-                }
-        }
-
-        open_device();
-        init_device();
-        start_capturing();
-        mainloop();
-        stop_capturing();
-        uninit_device();
-        close_device();
-        fprintf(stderr, "\n");
-        return 0;
-}
-</programlisting>
diff --git a/Documentation/DocBook/v4l/common.xml b/Documentation/DocBook/v4l/common.xml
deleted file mode 100644 (file)
index 9028721..0000000
+++ /dev/null
@@ -1,1197 +0,0 @@
-  <title>Common API Elements</title>
-
-  <para>Programming a V4L2 device consists of these
-steps:</para>
-
-  <itemizedlist>
-    <listitem>
-      <para>Opening the device</para>
-    </listitem>
-    <listitem>
-      <para>Changing device properties, selecting a video and audio
-input, video standard, picture brightness a.&nbsp;o.</para>
-    </listitem>
-    <listitem>
-      <para>Negotiating a data format</para>
-    </listitem>
-    <listitem>
-      <para>Negotiating an input/output method</para>
-    </listitem>
-    <listitem>
-      <para>The actual input/output loop</para>
-    </listitem>
-    <listitem>
-      <para>Closing the device</para>
-    </listitem>
-  </itemizedlist>
-
-  <para>In practice most steps are optional and can be executed out of
-order. It depends on the V4L2 device type, you can read about the
-details in <xref linkend="devices" />. In this chapter we will discuss
-the basic concepts applicable to all devices.</para>
-
-  <section id="open">
-    <title>Opening and Closing Devices</title>
-
-    <section>
-      <title>Device Naming</title>
-
-      <para>V4L2 drivers are implemented as kernel modules, loaded
-manually by the system administrator or automatically when a device is
-first opened. The driver modules plug into the "videodev" kernel
-module. It provides helper functions and a common application
-interface specified in this document.</para>
-
-      <para>Each driver thus loaded registers one or more device nodes
-with major number 81 and a minor number between 0 and 255. Assigning
-minor numbers to V4L2 devices is entirely up to the system administrator,
-this is primarily intended to solve conflicts between devices.<footnote>
-         <para>Access permissions are associated with character
-device special files, hence we must ensure device numbers cannot
-change with the module load order. To this end minor numbers are no
-longer automatically assigned by the "videodev" module as in V4L but
-requested by the driver. The defaults will suffice for most people
-unless two drivers compete for the same minor numbers.</para>
-       </footnote> The module options to select minor numbers are named
-after the device special file with a "_nr" suffix. For example "video_nr"
-for <filename>/dev/video</filename> video capture devices. The number is
-an offset to the base minor number associated with the device type.
-<footnote>
-         <para>In earlier versions of the V4L2 API the module options
-where named after the device special file with a "unit_" prefix, expressing
-the minor number itself, not an offset. Rationale for this change is unknown.
-Lastly the naming and semantics are just a convention among driver writers,
-the point to note is that minor numbers are not supposed to be hardcoded
-into drivers.</para>
-       </footnote> When the driver supports multiple devices of the same
-type more than one minor number can be assigned, separated by commas:
-<informalexample>
-         <screen>
-&gt; insmod mydriver.o video_nr=0,1 radio_nr=0,1</screen>
-       </informalexample></para>
-
-      <para>In <filename>/etc/modules.conf</filename> this may be
-written as: <informalexample>
-         <screen>
-alias char-major-81-0 mydriver
-alias char-major-81-1 mydriver
-alias char-major-81-64 mydriver              <co id="alias" />
-options mydriver video_nr=0,1 radio_nr=0,1   <co id="options" />
-         </screen>
-         <calloutlist>
-           <callout arearefs="alias">
-             <para>When an application attempts to open a device
-special file with major number 81 and minor number 0, 1, or 64, load
-"mydriver" (and the "videodev" module it depends upon).</para>
-           </callout>
-           <callout arearefs="options">
-             <para>Register the first two video capture devices with
-minor number 0 and 1 (base number is 0), the first two radio device
-with minor number 64 and 65 (base 64).</para>
-           </callout>
-         </calloutlist>
-       </informalexample> When no minor number is given as module
-option the driver supplies a default. <xref linkend="devices" />
-recommends the base minor numbers to be used for the various device
-types. Obviously minor numbers must be unique. When the number is
-already in use the <emphasis>offending device</emphasis> will not be
-registered. <!-- Blessed by Linus Torvalds on
-linux-kernel@vger.kernel.org, 2002-11-20. --></para>
-
-      <para>By convention system administrators create various
-character device special files with these major and minor numbers in
-the <filename>/dev</filename> directory. The names recommended for the
-different V4L2 device types are listed in <xref linkend="devices" />.
-</para>
-
-      <para>The creation of character special files (with
-<application>mknod</application>) is a privileged operation and
-devices cannot be opened by major and minor number. That means
-applications cannot <emphasis>reliable</emphasis> scan for loaded or
-installed drivers. The user must enter a device name, or the
-application can try the conventional device names.</para>
-
-      <para>Under the device filesystem (devfs) the minor number
-options are ignored. V4L2 drivers (or by proxy the "videodev" module)
-automatically create the required device files in the
-<filename>/dev/v4l</filename> directory using the conventional device
-names above.</para>
-    </section>
-
-    <section id="related">
-      <title>Related Devices</title>
-
-      <para>Devices can support several related functions. For example
-video capturing, video overlay and VBI capturing are related because
-these functions share, amongst other, the same video input and tuner
-frequency. V4L and earlier versions of V4L2 used the same device name
-and minor number for video capturing and overlay, but different ones
-for VBI. Experience showed this approach has several problems<footnote>
-         <para>Given a device file name one cannot reliable find
-related devices. For once names are arbitrary and in a system with
-multiple devices, where only some support VBI capturing, a
-<filename>/dev/video2</filename> is not necessarily related to
-<filename>/dev/vbi2</filename>. The V4L
-<constant>VIDIOCGUNIT</constant> ioctl would require a search for a
-device file with a particular major and minor number.</para>
-       </footnote>, and to make things worse the V4L videodev module
-used to prohibit multiple opens of a device.</para>
-
-      <para>As a remedy the present version of the V4L2 API relaxed the
-concept of device types with specific names and minor numbers. For
-compatibility with old applications drivers must still register different
-minor numbers to assign a default function to the device. But if related
-functions are supported by the driver they must be available under all
-registered minor numbers. The desired function can be selected after
-opening the device as described in <xref linkend="devices" />.</para>
-
-      <para>Imagine a driver supporting video capturing, video
-overlay, raw VBI capturing, and FM radio reception. It registers three
-devices with minor number 0, 64 and 224 (this numbering scheme is
-inherited from the V4L API). Regardless if
-<filename>/dev/video</filename> (81, 0) or
-<filename>/dev/vbi</filename> (81, 224) is opened the application can
-select any one of the video capturing, overlay or VBI capturing
-functions. Without programming (e.&nbsp;g. reading from the device
-with <application>dd</application> or <application>cat</application>)
-<filename>/dev/video</filename> captures video images, while
-<filename>/dev/vbi</filename> captures raw VBI data.
-<filename>/dev/radio</filename> (81, 64) is invariable a radio device,
-unrelated to the video functions. Being unrelated does not imply the
-devices can be used at the same time, however. The &func-open;
-function may very well return an &EBUSY;.</para>
-
-      <para>Besides video input or output the hardware may also
-support audio sampling or playback. If so, these functions are
-implemented as OSS or ALSA PCM devices and eventually OSS or ALSA
-audio mixer. The V4L2 API makes no provisions yet to find these
-related devices. If you have an idea please write to the linux-media
-mailing list: &v4l-ml;.</para>
-    </section>
-
-    <section>
-      <title>Multiple Opens</title>
-
-      <para>In general, V4L2 devices can be opened more than once.
-When this is supported by the driver, users can for example start a
-"panel" application to change controls like brightness or audio
-volume, while another application captures video and audio. In other words, panel
-applications are comparable to an OSS or ALSA audio mixer application.
-When a device supports multiple functions like capturing and overlay
-<emphasis>simultaneously</emphasis>, multiple opens allow concurrent
-use of the device by forked processes or specialized applications.</para>
-
-      <para>Multiple opens are optional, although drivers should
-permit at least concurrent accesses without data exchange, &ie; panel
-applications. This implies &func-open; can return an &EBUSY; when the
-device is already in use, as well as &func-ioctl; functions initiating
-data exchange (namely the &VIDIOC-S-FMT; ioctl), and the &func-read;
-and &func-write; functions.</para>
-
-      <para>Mere opening a V4L2 device does not grant exclusive
-access.<footnote>
-         <para>Drivers could recognize the
-<constant>O_EXCL</constant> open flag. Presently this is not required,
-so applications cannot know if it really works.</para>
-       </footnote> Initiating data exchange however assigns the right
-to read or write the requested type of data, and to change related
-properties, to this file descriptor. Applications can request
-additional access privileges using the priority mechanism described in
-<xref linkend="app-pri" />.</para>
-    </section>
-
-    <section>
-      <title>Shared Data Streams</title>
-
-      <para>V4L2 drivers should not support multiple applications
-reading or writing the same data stream on a device by copying
-buffers, time multiplexing or similar means. This is better handled by
-a proxy application in user space. When the driver supports stream
-sharing anyway it must be implemented transparently. The V4L2 API does
-not specify how conflicts are solved. <!-- For example O_EXCL when the
-application does not want to be preempted, PROT_READ mmapped buffers
-which can be mapped twice, what happens when image formats do not
-match etc.--></para>
-    </section>
-
-    <section>
-      <title>Functions</title>
-
-    <para>To open and close V4L2 devices applications use the
-&func-open; and &func-close; function, respectively. Devices are
-programmed using the &func-ioctl; function as explained in the
-following sections.</para>
-    </section>
-  </section>
-
-  <section id="querycap">
-    <title>Querying Capabilities</title>
-
-    <para>Because V4L2 covers a wide variety of devices not all
-aspects of the API are equally applicable to all types of devices.
-Furthermore devices of the same type have different capabilities and
-this specification permits the omission of a few complicated and less
-important parts of the API.</para>
-
-    <para>The &VIDIOC-QUERYCAP; ioctl is available to check if the kernel
-device is compatible with this specification, and to query the <link
-linkend="devices">functions</link> and <link linkend="io">I/O
-methods</link> supported by the device. Other features can be queried
-by calling the respective ioctl, for example &VIDIOC-ENUMINPUT;
-to learn about the number, types and names of video connectors on the
-device. Although abstraction is a major objective of this API, the
-ioctl also allows driver specific applications to reliable identify
-the driver.</para>
-
-    <para>All V4L2 drivers must support
-<constant>VIDIOC_QUERYCAP</constant>. Applications should always call
-this ioctl after opening the device.</para>
-  </section>
-
-  <section id="app-pri">
-    <title>Application Priority</title>
-
-    <para>When multiple applications share a device it may be
-desirable to assign them different priorities. Contrary to the
-traditional "rm -rf /" school of thought a video recording application
-could for example block other applications from changing video
-controls or switching the current TV channel. Another objective is to
-permit low priority applications working in background, which can be
-preempted by user controlled applications and automatically regain
-control of the device at a later time.</para>
-
-    <para>Since these features cannot be implemented entirely in user
-space V4L2 defines the &VIDIOC-G-PRIORITY; and &VIDIOC-S-PRIORITY;
-ioctls to request and query the access priority associate with a file
-descriptor. Opening a device assigns a medium priority, compatible
-with earlier versions of V4L2 and drivers not supporting these ioctls.
-Applications requiring a different priority will usually call
-<constant>VIDIOC_S_PRIORITY</constant> after verifying the device with
-the &VIDIOC-QUERYCAP; ioctl.</para>
-
-    <para>Ioctls changing driver properties, such as &VIDIOC-S-INPUT;,
-return an &EBUSY; after another application obtained higher priority.
-An event mechanism to notify applications about asynchronous property
-changes has been proposed but not added yet.</para>
-  </section>
-
-  <section id="video">
-    <title>Video Inputs and Outputs</title>
-
-    <para>Video inputs and outputs are physical connectors of a
-device. These can be for example RF connectors (antenna/cable), CVBS
-a.k.a. Composite Video, S-Video or RGB connectors. Only video and VBI
-capture devices have inputs, output devices have outputs, at least one
-each. Radio devices have no video inputs or outputs.</para>
-
-    <para>To learn about the number and attributes of the
-available inputs and outputs applications can enumerate them with the
-&VIDIOC-ENUMINPUT; and &VIDIOC-ENUMOUTPUT; ioctl, respectively. The
-&v4l2-input; returned by the <constant>VIDIOC_ENUMINPUT</constant>
-ioctl also contains signal status information applicable when the
-current video input is queried.</para>
-
-    <para>The &VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; ioctl return the
-index of the current video input or output. To select a different
-input or output applications call the &VIDIOC-S-INPUT; and
-&VIDIOC-S-OUTPUT; ioctl. Drivers must implement all the input ioctls
-when the device has one or more inputs, all the output ioctls when the
-device has one or more outputs.</para>
-
-    <!--
-    <figure id=io-tree>
-      <title>Input and output enumeration is the root of most device properties.</title>
-      <mediaobject>
-       <imageobject>
-         <imagedata fileref="links.pdf" format="ps" />
-       </imageobject>
-       <imageobject>
-         <imagedata fileref="links.gif" format="gif" />
-       </imageobject>
-       <textobject>
-         <phrase>Links between various device property structures.</phrase>
-       </textobject>
-      </mediaobject>
-    </figure>
-    -->
-
-    <example>
-      <title>Information about the current video input</title>
-
-      <programlisting>
-&v4l2-input; input;
-int index;
-
-if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &amp;index)) {
-       perror ("VIDIOC_G_INPUT");
-       exit (EXIT_FAILURE);
-}
-
-memset (&amp;input, 0, sizeof (input));
-input.index = index;
-
-if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
-       perror ("VIDIOC_ENUMINPUT");
-       exit (EXIT_FAILURE);
-}
-
-printf ("Current input: %s\n", input.name);
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Switching to the first video input</title>
-
-      <programlisting>
-int index;
-
-index = 0;
-
-if (-1 == ioctl (fd, &VIDIOC-S-INPUT;, &amp;index)) {
-       perror ("VIDIOC_S_INPUT");
-       exit (EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-  </section>
-
-  <section id="audio">
-    <title>Audio Inputs and Outputs</title>
-
-    <para>Audio inputs and outputs are physical connectors of a
-device. Video capture devices have inputs, output devices have
-outputs, zero or more each. Radio devices have no audio inputs or
-outputs. They have exactly one tuner which in fact
-<emphasis>is</emphasis> an audio source, but this API associates
-tuners with video inputs or outputs only, and radio devices have
-none of these.<footnote>
-       <para>Actually &v4l2-audio; ought to have a
-<structfield>tuner</structfield> field like &v4l2-input;, not only
-making the API more consistent but also permitting radio devices with
-multiple tuners.</para>
-      </footnote> A connector on a TV card to loop back the received
-audio signal to a sound card is not considered an audio output.</para>
-
-    <para>Audio and video inputs and outputs are associated. Selecting
-a video source also selects an audio source. This is most evident when
-the video and audio source is a tuner. Further audio connectors can
-combine with more than one video input or output. Assumed two
-composite video inputs and two audio inputs exist, there may be up to
-four valid combinations. The relation of video and audio connectors
-is defined in the <structfield>audioset</structfield> field of the
-respective &v4l2-input; or &v4l2-output;, where each bit represents
-the index number, starting at zero, of one audio input or output.</para>
-
-    <para>To learn about the number and attributes of the
-available inputs and outputs applications can enumerate them with the
-&VIDIOC-ENUMAUDIO; and &VIDIOC-ENUMAUDOUT; ioctl, respectively. The
-&v4l2-audio; returned by the <constant>VIDIOC_ENUMAUDIO</constant> ioctl
-also contains signal status information applicable when the current
-audio input is queried.</para>
-
-    <para>The &VIDIOC-G-AUDIO; and &VIDIOC-G-AUDOUT; ioctl report
-the current audio input and output, respectively. Note that, unlike
-&VIDIOC-G-INPUT; and &VIDIOC-G-OUTPUT; these ioctls return a structure
-as <constant>VIDIOC_ENUMAUDIO</constant> and
-<constant>VIDIOC_ENUMAUDOUT</constant> do, not just an index.</para>
-
-    <para>To select an audio input and change its properties
-applications call the &VIDIOC-S-AUDIO; ioctl. To select an audio
-output (which presently has no changeable properties) applications
-call the &VIDIOC-S-AUDOUT; ioctl.</para>
-
-    <para>Drivers must implement all input ioctls when the device
-has one or more inputs, all output ioctls when the device has one
-or more outputs. When the device has any audio inputs or outputs the
-driver must set the <constant>V4L2_CAP_AUDIO</constant> flag in the
-&v4l2-capability; returned by the &VIDIOC-QUERYCAP; ioctl.</para>
-
-    <example>
-      <title>Information about the current audio input</title>
-
-      <programlisting>
-&v4l2-audio; audio;
-
-memset (&amp;audio, 0, sizeof (audio));
-
-if (-1 == ioctl (fd, &VIDIOC-G-AUDIO;, &amp;audio)) {
-       perror ("VIDIOC_G_AUDIO");
-       exit (EXIT_FAILURE);
-}
-
-printf ("Current input: %s\n", audio.name);
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Switching to the first audio input</title>
-
-      <programlisting>
-&v4l2-audio; audio;
-
-memset (&amp;audio, 0, sizeof (audio)); /* clear audio.mode, audio.reserved */
-
-audio.index = 0;
-
-if (-1 == ioctl (fd, &VIDIOC-S-AUDIO;, &amp;audio)) {
-       perror ("VIDIOC_S_AUDIO");
-       exit (EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-  </section>
-
-  <section id="tuner">
-    <title>Tuners and Modulators</title>
-
-    <section>
-      <title>Tuners</title>
-
-      <para>Video input devices can have one or more tuners
-demodulating a RF signal. Each tuner is associated with one or more
-video inputs, depending on the number of RF connectors on the tuner.
-The <structfield>type</structfield> field of the respective
-&v4l2-input; returned by the &VIDIOC-ENUMINPUT; ioctl is set to
-<constant>V4L2_INPUT_TYPE_TUNER</constant> and its
-<structfield>tuner</structfield> field contains the index number of
-the tuner.</para>
-
-      <para>Radio devices have exactly one tuner with index zero, no
-video inputs.</para>
-
-      <para>To query and change tuner properties applications use the
-&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; ioctl, respectively. The
-&v4l2-tuner; returned by <constant>VIDIOC_G_TUNER</constant> also
-contains signal status information applicable when the tuner of the
-current video input, or a radio tuner is queried. Note that
-<constant>VIDIOC_S_TUNER</constant> does not switch the current tuner,
-when there is more than one at all. The tuner is solely determined by
-the current video input. Drivers must support both ioctls and set the
-<constant>V4L2_CAP_TUNER</constant> flag in the &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl when the device has one or
-more tuners.</para>
-    </section>
-
-    <section>
-      <title>Modulators</title>
-
-      <para>Video output devices can have one or more modulators, uh,
-modulating a video signal for radiation or connection to the antenna
-input of a TV set or video recorder. Each modulator is associated with
-one or more video outputs, depending on the number of RF connectors on
-the modulator. The <structfield>type</structfield> field of the
-respective &v4l2-output; returned by the &VIDIOC-ENUMOUTPUT; ioctl is
-set to <constant>V4L2_OUTPUT_TYPE_MODULATOR</constant> and its
-<structfield>modulator</structfield> field contains the index number
-of the modulator. This specification does not define radio output
-devices.</para>
-
-      <para>To query and change modulator properties applications use
-the &VIDIOC-G-MODULATOR; and &VIDIOC-S-MODULATOR; ioctl. Note that
-<constant>VIDIOC_S_MODULATOR</constant> does not switch the current
-modulator, when there is more than one at all. The modulator is solely
-determined by the current video output. Drivers must support both
-ioctls and set the <constant>V4L2_CAP_MODULATOR</constant> flag in
-the &v4l2-capability; returned by the &VIDIOC-QUERYCAP; ioctl when the
-device has one or more modulators.</para>
-    </section>
-
-    <section>
-      <title>Radio Frequency</title>
-
-      <para>To get and set the tuner or modulator radio frequency
-applications use the &VIDIOC-G-FREQUENCY; and &VIDIOC-S-FREQUENCY;
-ioctl which both take a pointer to a &v4l2-frequency;. These ioctls
-are used for TV and radio devices alike. Drivers must support both
-ioctls when the tuner or modulator ioctls are supported, or
-when the device is a radio device.</para>
-    </section>
-  </section>
-
-  <section id="standard">
-    <title>Video Standards</title>
-
-    <para>Video devices typically support one or more different video
-standards or variations of standards. Each video input and output may
-support another set of standards. This set is reported by the
-<structfield>std</structfield> field of &v4l2-input; and
-&v4l2-output; returned by the &VIDIOC-ENUMINPUT; and
-&VIDIOC-ENUMOUTPUT; ioctl, respectively.</para>
-
-    <para>V4L2 defines one bit for each analog video standard
-currently in use worldwide, and sets aside bits for driver defined
-standards, &eg; hybrid standards to watch NTSC video tapes on PAL TVs
-and vice versa. Applications can use the predefined bits to select a
-particular standard, although presenting the user a menu of supported
-standards is preferred. To enumerate and query the attributes of the
-supported standards applications use the &VIDIOC-ENUMSTD; ioctl.</para>
-
-    <para>Many of the defined standards are actually just variations
-of a few major standards. The hardware may in fact not distinguish
-between them, or do so internal and switch automatically. Therefore
-enumerated standards also contain sets of one or more standard
-bits.</para>
-
-    <para>Assume a hypothetic tuner capable of demodulating B/PAL,
-G/PAL and I/PAL signals. The first enumerated standard is a set of B
-and G/PAL, switched automatically depending on the selected radio
-frequency in UHF or VHF band. Enumeration gives a "PAL-B/G" or "PAL-I"
-choice. Similar a Composite input may collapse standards, enumerating
-"PAL-B/G/H/I", "NTSC-M" and "SECAM-D/K".<footnote>
-       <para>Some users are already confused by technical terms PAL,
-NTSC and SECAM. There is no point asking them to distinguish between
-B, G, D, or K when the software or hardware can do that
-automatically.</para>
-    </footnote></para>
-
-    <para>To query and select the standard used by the current video
-input or output applications call the &VIDIOC-G-STD; and
-&VIDIOC-S-STD; ioctl, respectively. The <emphasis>received</emphasis>
-standard can be sensed with the &VIDIOC-QUERYSTD; ioctl. Note parameter of all these ioctls is a pointer to a &v4l2-std-id; type (a standard set), <emphasis>not</emphasis> an index into the standard enumeration.<footnote>
-       <para>An alternative to the current scheme is to use pointers
-to indices as arguments of <constant>VIDIOC_G_STD</constant> and
-<constant>VIDIOC_S_STD</constant>, the &v4l2-input; and
-&v4l2-output; <structfield>std</structfield> field would be a set of
-indices like <structfield>audioset</structfield>.</para>
-       <para>Indices are consistent with the rest of the API
-and identify the standard unambiguously. In the present scheme of
-things an enumerated standard is looked up by &v4l2-std-id;. Now the
-standards supported by the inputs of a device can overlap. Just
-assume the tuner and composite input in the example above both
-exist on a device. An enumeration of "PAL-B/G", "PAL-H/I" suggests
-a choice which does not exist. We cannot merge or omit sets, because
-applications would be unable to find the standards reported by
-<constant>VIDIOC_G_STD</constant>. That leaves separate enumerations
-for each input. Also selecting a standard by &v4l2-std-id; can be
-ambiguous. Advantage of this method is that applications need not
-identify the standard indirectly, after enumerating.</para><para>So in
-summary, the lookup itself is unavoidable. The difference is only
-whether the lookup is necessary to find an enumerated standard or to
-switch to a standard by &v4l2-std-id;.</para>
-      </footnote> Drivers must implement all video standard ioctls
-when the device has one or more video inputs or outputs.</para>
-
-    <para>Special rules apply to USB cameras where the notion of video
-standards makes little sense. More generally any capture device,
-output devices accordingly, which is <itemizedlist>
-       <listitem>
-         <para>incapable of capturing fields or frames at the nominal
-rate of the video standard, or</para>
-       </listitem>
-       <listitem>
-         <para>where <link linkend="buffer">timestamps</link> refer
-to the instant the field or frame was received by the driver, not the
-capture time, or</para>
-       </listitem>
-       <listitem>
-         <para>where <link linkend="buffer">sequence numbers</link>
-refer to the frames received by the driver, not the captured
-frames.</para>
-       </listitem>
-      </itemizedlist> Here the driver shall set the
-<structfield>std</structfield> field of &v4l2-input; and &v4l2-output;
-to zero, the <constant>VIDIOC_G_STD</constant>,
-<constant>VIDIOC_S_STD</constant>,
-<constant>VIDIOC_QUERYSTD</constant> and
-<constant>VIDIOC_ENUMSTD</constant> ioctls shall return the
-&EINVAL;.<footnote>
-       <para>See <xref linkend="buffer" /> for a rationale. Probably
-even USB cameras follow some well known video standard. It might have
-been better to explicitly indicate elsewhere if a device cannot live
-up to normal expectations, instead of this exception.</para>
-           </footnote></para>
-
-    <example>
-      <title>Information about the current video standard</title>
-
-      <programlisting>
-&v4l2-std-id; std_id;
-&v4l2-standard; standard;
-
-if (-1 == ioctl (fd, &VIDIOC-G-STD;, &amp;std_id)) {
-       /* Note when VIDIOC_ENUMSTD always returns EINVAL this
-          is no video device or it falls under the USB exception,
-          and VIDIOC_G_STD returning EINVAL is no error. */
-
-       perror ("VIDIOC_G_STD");
-       exit (EXIT_FAILURE);
-}
-
-memset (&amp;standard, 0, sizeof (standard));
-standard.index = 0;
-
-while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
-       if (standard.id &amp; std_id) {
-              printf ("Current video standard: %s\n", standard.name);
-              exit (EXIT_SUCCESS);
-       }
-
-       standard.index++;
-}
-
-/* EINVAL indicates the end of the enumeration, which cannot be
-   empty unless this device falls under the USB exception. */
-
-if (errno == EINVAL || standard.index == 0) {
-       perror ("VIDIOC_ENUMSTD");
-       exit (EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Listing the video standards supported by the current
-input</title>
-
-      <programlisting>
-&v4l2-input; input;
-&v4l2-standard; standard;
-
-memset (&amp;input, 0, sizeof (input));
-
-if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &amp;input.index)) {
-       perror ("VIDIOC_G_INPUT");
-       exit (EXIT_FAILURE);
-}
-
-if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
-       perror ("VIDIOC_ENUM_INPUT");
-       exit (EXIT_FAILURE);
-}
-
-printf ("Current input %s supports:\n", input.name);
-
-memset (&amp;standard, 0, sizeof (standard));
-standard.index = 0;
-
-while (0 == ioctl (fd, &VIDIOC-ENUMSTD;, &amp;standard)) {
-       if (standard.id &amp; input.std)
-               printf ("%s\n", standard.name);
-
-       standard.index++;
-}
-
-/* EINVAL indicates the end of the enumeration, which cannot be
-   empty unless this device falls under the USB exception. */
-
-if (errno != EINVAL || standard.index == 0) {
-       perror ("VIDIOC_ENUMSTD");
-       exit (EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Selecting a new video standard</title>
-
-      <programlisting>
-&v4l2-input; input;
-&v4l2-std-id; std_id;
-
-memset (&amp;input, 0, sizeof (input));
-
-if (-1 == ioctl (fd, &VIDIOC-G-INPUT;, &amp;input.index)) {
-       perror ("VIDIOC_G_INPUT");
-       exit (EXIT_FAILURE);
-}
-
-if (-1 == ioctl (fd, &VIDIOC-ENUMINPUT;, &amp;input)) {
-       perror ("VIDIOC_ENUM_INPUT");
-       exit (EXIT_FAILURE);
-}
-
-if (0 == (input.std &amp; V4L2_STD_PAL_BG)) {
-       fprintf (stderr, "Oops. B/G PAL is not supported.\n");
-       exit (EXIT_FAILURE);
-}
-
-/* Note this is also supposed to work when only B
-   <emphasis>or</emphasis> G/PAL is supported. */
-
-std_id = V4L2_STD_PAL_BG;
-
-if (-1 == ioctl (fd, &VIDIOC-S-STD;, &amp;std_id)) {
-       perror ("VIDIOC_S_STD");
-       exit (EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-  <section id="dv-timings">
-       <title>Digital Video (DV) Timings</title>
-       <para>
-       The video standards discussed so far has been dealing with Analog TV and the
-corresponding video timings. Today there are many more different hardware interfaces
-such as High Definition TV interfaces (HDMI), VGA, DVI connectors etc., that carry
-video signals and there is a need to extend the API to select the video timings
-for these interfaces. Since it is not possible to extend the &v4l2-std-id; due to
-the limited bits available, a new set of IOCTLs is added to set/get video timings at
-the input and output: </para><itemizedlist>
-       <listitem>
-       <para>DV Presets: Digital Video (DV) presets. These are IDs representing a
-video timing at the input/output. Presets are pre-defined timings implemented
-by the hardware according to video standards. A __u32 data type is used to represent
-a preset unlike the bit mask that is used in &v4l2-std-id; allowing future extensions
-to support as many different presets as needed.</para>
-       </listitem>
-       <listitem>
-       <para>Custom DV Timings: This will allow applications to define more detailed
-custom video timings for the interface. This includes parameters such as width, height,
-polarities, frontporch, backporch etc.
-       </para>
-       </listitem>
-       </itemizedlist>
-       <para>To enumerate and query the attributes of DV presets supported by a device,
-applications use the &VIDIOC-ENUM-DV-PRESETS; ioctl. To get the current DV preset,
-applications use the &VIDIOC-G-DV-PRESET; ioctl and to set a preset they use the
-&VIDIOC-S-DV-PRESET; ioctl.</para>
-       <para>To set custom DV timings for the device, applications use the
-&VIDIOC-S-DV-TIMINGS; ioctl and to get current custom DV timings they use the
-&VIDIOC-G-DV-TIMINGS; ioctl.</para>
-       <para>Applications can make use of the <xref linkend="input-capabilities" /> and
-<xref linkend="output-capabilities"/> flags to decide what ioctls are available to set the
-video timings for the device.</para>
-       </section>
-  </section>
-
-  &sub-controls;
-
-  <section id="format">
-    <title>Data Formats</title>
-
-    <section>
-      <title>Data Format Negotiation</title>
-
-      <para>Different devices exchange different kinds of data with
-applications, for example video images, raw or sliced VBI data, RDS
-datagrams. Even within one kind many different formats are possible,
-in particular an abundance of image formats. Although drivers must
-provide a default and the selection persists across closing and
-reopening a device, applications should always negotiate a data format
-before engaging in data exchange. Negotiation means the application
-asks for a particular format and the driver selects and reports the
-best the hardware can do to satisfy the request. Of course
-applications can also just query the current selection.</para>
-
-      <para>A single mechanism exists to negotiate all data formats
-using the aggregate &v4l2-format; and the &VIDIOC-G-FMT; and
-&VIDIOC-S-FMT; ioctls. Additionally the &VIDIOC-TRY-FMT; ioctl can be
-used to examine what the hardware <emphasis>could</emphasis> do,
-without actually selecting a new data format. The data formats
-supported by the V4L2 API are covered in the respective device section
-in <xref linkend="devices" />. For a closer look at image formats see
-<xref linkend="pixfmt" />.</para>
-
-      <para>The <constant>VIDIOC_S_FMT</constant> ioctl is a major
-turning-point in the initialization sequence. Prior to this point
-multiple panel applications can access the same device concurrently to
-select the current input, change controls or modify other properties.
-The first <constant>VIDIOC_S_FMT</constant> assigns a logical stream
-(video data, VBI data etc.) exclusively to one file descriptor.</para>
-
-      <para>Exclusive means no other application, more precisely no
-other file descriptor, can grab this stream or change device
-properties inconsistent with the negotiated parameters. A video
-standard change for example, when the new standard uses a different
-number of scan lines, can invalidate the selected image format.
-Therefore only the file descriptor owning the stream can make
-invalidating changes. Accordingly multiple file descriptors which
-grabbed different logical streams prevent each other from interfering
-with their settings. When for example video overlay is about to start
-or already in progress, simultaneous video capturing may be restricted
-to the same cropping and image size.</para>
-
-      <para>When applications omit the
-<constant>VIDIOC_S_FMT</constant> ioctl its locking side effects are
-implied by the next step, the selection of an I/O method with the
-&VIDIOC-REQBUFS; ioctl or implicit with the first &func-read; or
-&func-write; call.</para>
-
-      <para>Generally only one logical stream can be assigned to a
-file descriptor, the exception being drivers permitting simultaneous
-video capturing and overlay using the same file descriptor for
-compatibility with V4L and earlier versions of V4L2. Switching the
-logical stream or returning into "panel mode" is possible by closing
-and reopening the device. Drivers <emphasis>may</emphasis> support a
-switch using <constant>VIDIOC_S_FMT</constant>.</para>
-
-      <para>All drivers exchanging data with
-applications must support the <constant>VIDIOC_G_FMT</constant> and
-<constant>VIDIOC_S_FMT</constant> ioctl. Implementation of the
-<constant>VIDIOC_TRY_FMT</constant> is highly recommended but
-optional.</para>
-    </section>
-
-    <section>
-      <title>Image Format Enumeration</title>
-
-      <para>Apart of the generic format negotiation functions
-a special ioctl to enumerate all image formats supported by video
-capture, overlay or output devices is available.<footnote>
-         <para>Enumerating formats an application has no a-priori
-knowledge of (otherwise it could explicitly ask for them and need not
-enumerate) seems useless, but there are applications serving as proxy
-between drivers and the actual video applications for which this is
-useful.</para>
-       </footnote></para>
-
-      <para>The &VIDIOC-ENUM-FMT; ioctl must be supported
-by all drivers exchanging image data with applications.</para>
-
-      <important>
-       <para>Drivers are not supposed to convert image formats in
-kernel space. They must enumerate only formats directly supported by
-the hardware. If necessary driver writers should publish an example
-conversion routine or library for integration into applications.</para>
-      </important>
-    </section>
-  </section>
-
-  &sub-planar-apis;
-
-  <section id="crop">
-    <title>Image Cropping, Insertion and Scaling</title>
-
-    <para>Some video capture devices can sample a subsection of the
-picture and shrink or enlarge it to an image of arbitrary size. We
-call these abilities cropping and scaling. Some video output devices
-can scale an image up or down and insert it at an arbitrary scan line
-and horizontal offset into a video signal.</para>
-
-    <para>Applications can use the following API to select an area in
-the video signal, query the default area and the hardware limits.
-<emphasis>Despite their name, the &VIDIOC-CROPCAP;, &VIDIOC-G-CROP;
-and &VIDIOC-S-CROP; ioctls apply to input as well as output
-devices.</emphasis></para>
-
-    <para>Scaling requires a source and a target. On a video capture
-or overlay device the source is the video signal, and the cropping
-ioctls determine the area actually sampled. The target are images
-read by the application or overlaid onto the graphics screen. Their
-size (and position for an overlay) is negotiated with the
-&VIDIOC-G-FMT; and &VIDIOC-S-FMT; ioctls.</para>
-
-    <para>On a video output device the source are the images passed in
-by the application, and their size is again negotiated with the
-<constant>VIDIOC_G/S_FMT</constant> ioctls, or may be encoded in a
-compressed video stream. The target is the video signal, and the
-cropping ioctls determine the area where the images are
-inserted.</para>
-
-    <para>Source and target rectangles are defined even if the device
-does not support scaling or the <constant>VIDIOC_G/S_CROP</constant>
-ioctls. Their size (and position where applicable) will be fixed in
-this case. <emphasis>All capture and output device must support the
-<constant>VIDIOC_CROPCAP</constant> ioctl such that applications can
-determine if scaling takes place.</emphasis></para>
-
-    <section>
-      <title>Cropping Structures</title>
-
-      <figure id="crop-scale">
-       <title>Image Cropping, Insertion and Scaling</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="crop.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="crop.gif" format="GIF" />
-         </imageobject>
-         <textobject>
-           <phrase>The cropping, insertion and scaling process</phrase>
-         </textobject>
-       </mediaobject>
-      </figure>
-
-      <para>For capture devices the coordinates of the top left
-corner, width and height of the area which can be sampled is given by
-the <structfield>bounds</structfield> substructure of the
-&v4l2-cropcap; returned by the <constant>VIDIOC_CROPCAP</constant>
-ioctl. To support a wide range of hardware this specification does not
-define an origin or units. However by convention drivers should
-horizontally count unscaled samples relative to 0H (the leading edge
-of the horizontal sync pulse, see <xref linkend="vbi-hsync" />).
-Vertically ITU-R line
-numbers of the first field (<xref linkend="vbi-525" />, <xref
-linkend="vbi-625" />), multiplied by two if the driver can capture both
-fields.</para>
-
-      <para>The top left corner, width and height of the source
-rectangle, that is the area actually sampled, is given by &v4l2-crop;
-using the same coordinate system as &v4l2-cropcap;. Applications can
-use the <constant>VIDIOC_G_CROP</constant> and
-<constant>VIDIOC_S_CROP</constant> ioctls to get and set this
-rectangle. It must lie completely within the capture boundaries and
-the driver may further adjust the requested size and/or position
-according to hardware limitations.</para>
-
-      <para>Each capture device has a default source rectangle, given
-by the <structfield>defrect</structfield> substructure of
-&v4l2-cropcap;. The center of this rectangle shall align with the
-center of the active picture area of the video signal, and cover what
-the driver writer considers the complete picture. Drivers shall reset
-the source rectangle to the default when the driver is first loaded,
-but not later.</para>
-
-      <para>For output devices these structures and ioctls are used
-accordingly, defining the <emphasis>target</emphasis> rectangle where
-the images will be inserted into the video signal.</para>
-
-    </section>
-
-    <section>
-      <title>Scaling Adjustments</title>
-
-      <para>Video hardware can have various cropping, insertion and
-scaling limitations. It may only scale up or down, support only
-discrete scaling factors, or have different scaling abilities in
-horizontal and vertical direction. Also it may not support scaling at
-all. At the same time the &v4l2-crop; rectangle may have to be
-aligned, and both the source and target rectangles may have arbitrary
-upper and lower size limits. In particular the maximum
-<structfield>width</structfield> and <structfield>height</structfield>
-in &v4l2-crop; may be smaller than the
-&v4l2-cropcap;.<structfield>bounds</structfield> area. Therefore, as
-usual, drivers are expected to adjust the requested parameters and
-return the actual values selected.</para>
-
-      <para>Applications can change the source or the target rectangle
-first, as they may prefer a particular image size or a certain area in
-the video signal. If the driver has to adjust both to satisfy hardware
-limitations, the last requested rectangle shall take priority, and the
-driver should preferably adjust the opposite one. The &VIDIOC-TRY-FMT;
-ioctl however shall not change the driver state and therefore only
-adjust the requested rectangle.</para>
-
-      <para>Suppose scaling on a video capture device is restricted to
-a factor 1:1 or 2:1 in either direction and the target image size must
-be a multiple of 16&nbsp;&times;&nbsp;16 pixels. The source cropping
-rectangle is set to defaults, which are also the upper limit in this
-example, of 640&nbsp;&times;&nbsp;400 pixels at offset 0,&nbsp;0. An
-application requests an image size of 300&nbsp;&times;&nbsp;225
-pixels, assuming video will be scaled down from the "full picture"
-accordingly. The driver sets the image size to the closest possible
-values 304&nbsp;&times;&nbsp;224, then chooses the cropping rectangle
-closest to the requested size, that is 608&nbsp;&times;&nbsp;224
-(224&nbsp;&times;&nbsp;2:1 would exceed the limit 400). The offset
-0,&nbsp;0 is still valid, thus unmodified. Given the default cropping
-rectangle reported by <constant>VIDIOC_CROPCAP</constant> the
-application can easily propose another offset to center the cropping
-rectangle.</para>
-
-      <para>Now the application may insist on covering an area using a
-picture aspect ratio closer to the original request, so it asks for a
-cropping rectangle of 608&nbsp;&times;&nbsp;456 pixels. The present
-scaling factors limit cropping to 640&nbsp;&times;&nbsp;384, so the
-driver returns the cropping size 608&nbsp;&times;&nbsp;384 and adjusts
-the image size to closest possible 304&nbsp;&times;&nbsp;192.</para>
-
-    </section>
-
-    <section>
-      <title>Examples</title>
-
-      <para>Source and target rectangles shall remain unchanged across
-closing and reopening a device, such that piping data into or out of a
-device will work without special preparations. More advanced
-applications should ensure the parameters are suitable before starting
-I/O.</para>
-
-      <example>
-       <title>Resetting the cropping parameters</title>
-
-       <para>(A video capture device is assumed; change
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> for other
-devices.)</para>
-
-       <programlisting>
-&v4l2-cropcap; cropcap;
-&v4l2-crop; crop;
-
-memset (&amp;cropcap, 0, sizeof (cropcap));
-cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-if (-1 == ioctl (fd, &VIDIOC-CROPCAP;, &amp;cropcap)) {
-       perror ("VIDIOC_CROPCAP");
-       exit (EXIT_FAILURE);
-}
-
-memset (&amp;crop, 0, sizeof (crop));
-crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-crop.c = cropcap.defrect;
-
-/* Ignore if cropping is not supported (EINVAL). */
-
-if (-1 == ioctl (fd, &VIDIOC-S-CROP;, &amp;crop)
-    &amp;&amp; errno != EINVAL) {
-       perror ("VIDIOC_S_CROP");
-       exit (EXIT_FAILURE);
-}
-      </programlisting>
-      </example>
-
-      <example>
-       <title>Simple downscaling</title>
-
-       <para>(A video capture device is assumed.)</para>
-
-       <programlisting>
-&v4l2-cropcap; cropcap;
-&v4l2-format; format;
-
-reset_cropping_parameters ();
-
-/* Scale down to 1/4 size of full picture. */
-
-memset (&amp;format, 0, sizeof (format)); /* defaults */
-
-format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-format.fmt.pix.width = cropcap.defrect.width &gt;&gt; 1;
-format.fmt.pix.height = cropcap.defrect.height &gt;&gt; 1;
-format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-
-if (-1 == ioctl (fd, &VIDIOC-S-FMT;, &amp;format)) {
-       perror ("VIDIOC_S_FORMAT");
-       exit (EXIT_FAILURE);
-}
-
-/* We could check the actual image size now, the actual scaling factor
-   or if the driver can scale at all. */
-       </programlisting>
-      </example>
-
-      <example>
-       <title>Selecting an output area</title>
-
-       <programlisting>
-&v4l2-cropcap; cropcap;
-&v4l2-crop; crop;
-
-memset (&amp;cropcap, 0, sizeof (cropcap));
-cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-
-if (-1 == ioctl (fd, VIDIOC_CROPCAP;, &amp;cropcap)) {
-       perror ("VIDIOC_CROPCAP");
-       exit (EXIT_FAILURE);
-}
-
-memset (&amp;crop, 0, sizeof (crop));
-
-crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-crop.c = cropcap.defrect;
-
-/* Scale the width and height to 50 % of their original size
-   and center the output. */
-
-crop.c.width /= 2;
-crop.c.height /= 2;
-crop.c.left += crop.c.width / 2;
-crop.c.top += crop.c.height / 2;
-
-/* Ignore if cropping is not supported (EINVAL). */
-
-if (-1 == ioctl (fd, VIDIOC_S_CROP, &amp;crop)
-    &amp;&amp; errno != EINVAL) {
-       perror ("VIDIOC_S_CROP");
-       exit (EXIT_FAILURE);
-}
-</programlisting>
-      </example>
-
-      <example>
-       <title>Current scaling factor and pixel aspect</title>
-
-       <para>(A video capture device is assumed.)</para>
-
-       <programlisting>
-&v4l2-cropcap; cropcap;
-&v4l2-crop; crop;
-&v4l2-format; format;
-double hscale, vscale;
-double aspect;
-int dwidth, dheight;
-
-memset (&amp;cropcap, 0, sizeof (cropcap));
-cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-if (-1 == ioctl (fd, &VIDIOC-CROPCAP;, &amp;cropcap)) {
-       perror ("VIDIOC_CROPCAP");
-       exit (EXIT_FAILURE);
-}
-
-memset (&amp;crop, 0, sizeof (crop));
-crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-if (-1 == ioctl (fd, &VIDIOC-G-CROP;, &amp;crop)) {
-       if (errno != EINVAL) {
-               perror ("VIDIOC_G_CROP");
-               exit (EXIT_FAILURE);
-       }
-
-       /* Cropping not supported. */
-       crop.c = cropcap.defrect;
-}
-
-memset (&amp;format, 0, sizeof (format));
-format.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-if (-1 == ioctl (fd, &VIDIOC-G-FMT;, &amp;format)) {
-       perror ("VIDIOC_G_FMT");
-       exit (EXIT_FAILURE);
-}
-
-/* The scaling applied by the driver. */
-
-hscale = format.fmt.pix.width / (double) crop.c.width;
-vscale = format.fmt.pix.height / (double) crop.c.height;
-
-aspect = cropcap.pixelaspect.numerator /
-        (double) cropcap.pixelaspect.denominator;
-aspect = aspect * hscale / vscale;
-
-/* Devices following ITU-R BT.601 do not capture
-   square pixels. For playback on a computer monitor
-   we should scale the images to this size. */
-
-dwidth = format.fmt.pix.width / aspect;
-dheight = format.fmt.pix.height;
-       </programlisting>
-      </example>
-    </section>
-  </section>
-
-  <section id="streaming-par">
-    <title>Streaming Parameters</title>
-
-    <para>Streaming parameters are intended to optimize the video
-capture process as well as I/O. Presently applications can request a
-high quality capture mode with the &VIDIOC-S-PARM; ioctl.</para>
-
-    <para>The current video standard determines a nominal number of
-frames per second. If less than this number of frames is to be
-captured or output, applications can request frame skipping or
-duplicating on the driver side. This is especially useful when using
-the &func-read; or &func-write;, which are not augmented by timestamps
-or sequence counters, and to avoid unnecessary data copying.</para>
-
-    <para>Finally these ioctls can be used to determine the number of
-buffers used internally by a driver in read/write mode. For
-implications see the section discussing the &func-read;
-function.</para>
-
-    <para>To get and set the streaming parameters applications call
-the &VIDIOC-G-PARM; and &VIDIOC-S-PARM; ioctl, respectively. They take
-a pointer to a &v4l2-streamparm;, which contains a union holding
-separate parameters for input and output devices.</para>
-
-    <para>These ioctls are optional, drivers need not implement
-them. If so, they return the &EINVAL;.</para>
-  </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/compat.xml b/Documentation/DocBook/v4l/compat.xml
deleted file mode 100644 (file)
index 9f7cd4f..0000000
+++ /dev/null
@@ -1,2500 +0,0 @@
-  <title>Changes</title>
-
-  <para>The following chapters document the evolution of the V4L2 API,
-errata or extensions. They are also intended to help application and
-driver writers to port or update their code.</para>
-
-  <section id="diff-v4l">
-    <title>Differences between V4L and V4L2</title>
-
-    <para>The Video For Linux API was first introduced in Linux 2.1 to
-unify and replace various TV and radio device related interfaces,
-developed independently by driver writers in prior years. Starting
-with Linux 2.5 the much improved V4L2 API replaces the V4L API,
-although existing drivers will continue to support V4L applications in
-the future, either directly or through the V4L2 compatibility layer in
-the <filename>videodev</filename> kernel module translating ioctls on
-the fly. For a transition period not all drivers will support the V4L2
-API.</para>
-
-    <section>
-      <title>Opening and Closing Devices</title>
-
-      <para>For compatibility reasons the character device file names
-recommended for V4L2 video capture, overlay, radio and raw
-vbi capture devices did not change from those used by V4L. They are
-listed in <xref linkend="devices" /> and below in <xref
-         linkend="v4l-dev" />.</para>
-
-      <para>The teletext devices (minor range 192-223) have been removed in
-V4L2 and no longer exist. There is no hardware available anymore for handling
-pure teletext. Instead raw or sliced VBI is used.</para>
-
-      <para>The V4L <filename>videodev</filename> module automatically
-assigns minor numbers to drivers in load order, depending on the
-registered device type. We recommend that V4L2 drivers by default
-register devices with the same numbers, but the system administrator
-can assign arbitrary minor numbers using driver module options. The
-major device number remains 81.</para>
-
-      <table id="v4l-dev">
-       <title>V4L Device Types, Names and Numbers</title>
-       <tgroup cols="3">
-         <thead>
-           <row>
-             <entry>Device Type</entry>
-             <entry>File Name</entry>
-             <entry>Minor Numbers</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row>
-             <entry>Video capture and overlay</entry>
-             <entry><para><filename>/dev/video</filename> and
-<filename>/dev/bttv0</filename><footnote> <para>According to
-Documentation/devices.txt these should be symbolic links to
-<filename>/dev/video0</filename>. Note the original bttv interface is
-not compatible with V4L or V4L2.</para> </footnote>,
-<filename>/dev/video0</filename> to
-<filename>/dev/video63</filename></para></entry>
-             <entry>0-63</entry>
-           </row>
-           <row>
-             <entry>Radio receiver</entry>
-             <entry><para><filename>/dev/radio</filename><footnote>
-                   <para>According to
-<filename>Documentation/devices.txt</filename> a symbolic link to
-<filename>/dev/radio0</filename>.</para>
-                 </footnote>, <filename>/dev/radio0</filename> to
-<filename>/dev/radio63</filename></para></entry>
-             <entry>64-127</entry>
-           </row>
-           <row>
-             <entry>Raw VBI capture</entry>
-             <entry><para><filename>/dev/vbi</filename>,
-<filename>/dev/vbi0</filename> to
-<filename>/dev/vbi31</filename></para></entry>
-             <entry>224-255</entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <para>V4L prohibits (or used to prohibit) multiple opens of a
-device file. V4L2 drivers <emphasis>may</emphasis> support multiple
-opens, see <xref linkend="open" /> for details and consequences.</para>
-
-      <para>V4L drivers respond to V4L2 ioctls with an &EINVAL;. The
-compatibility layer in the V4L2 <filename>videodev</filename> module
-can translate V4L ioctl requests to their V4L2 counterpart, however a
-V4L2 driver usually needs more preparation to become fully V4L
-compatible. This is covered in more detail in <xref
-         linkend="driver" />.</para>
-    </section>
-
-    <section>
-      <title>Querying Capabilities</title>
-
-      <para>The V4L <constant>VIDIOCGCAP</constant> ioctl is
-equivalent to V4L2's &VIDIOC-QUERYCAP;.</para>
-
-      <para>The <structfield>name</structfield> field in struct
-<structname>video_capability</structname> became
-<structfield>card</structfield> in &v4l2-capability;,
-<structfield>type</structfield> was replaced by
-<structfield>capabilities</structfield>. Note V4L2 does not
-distinguish between device types like this, better think of basic
-video input, video output and radio devices supporting a set of
-related functions like video capturing, video overlay and VBI
-capturing. See <xref linkend="open" /> for an
-introduction.<informaltable>
-         <tgroup cols="3">
-           <thead>
-             <row>
-               <entry>struct
-<structname>video_capability</structname>
-<structfield>type</structfield></entry>
-               <entry>&v4l2-capability;
-<structfield>capabilities</structfield> flags</entry>
-               <entry>Purpose</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry><constant>VID_TYPE_CAPTURE</constant></entry>
-               <entry><constant>V4L2_CAP_VIDEO_CAPTURE</constant></entry>
-               <entry>The <link linkend="capture">video
-capture</link> interface is supported.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_TUNER</constant></entry>
-               <entry><constant>V4L2_CAP_TUNER</constant></entry>
-               <entry>The device has a <link linkend="tuner">tuner or
-modulator</link>.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_TELETEXT</constant></entry>
-               <entry><constant>V4L2_CAP_VBI_CAPTURE</constant></entry>
-               <entry>The <link linkend="raw-vbi">raw VBI
-capture</link> interface is supported.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_OVERLAY</constant></entry>
-               <entry><constant>V4L2_CAP_VIDEO_OVERLAY</constant></entry>
-               <entry>The <link linkend="overlay">video
-overlay</link> interface is supported.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_CHROMAKEY</constant></entry>
-               <entry><constant>V4L2_FBUF_CAP_CHROMAKEY</constant> in
-field <structfield>capability</structfield> of
-&v4l2-framebuffer;</entry>
-               <entry>Whether chromakey overlay is supported. For
-more information on overlay see
-<xref linkend="overlay" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_CLIPPING</constant></entry>
-               <entry><constant>V4L2_FBUF_CAP_LIST_CLIPPING</constant>
-and <constant>V4L2_FBUF_CAP_BITMAP_CLIPPING</constant> in field
-<structfield>capability</structfield> of &v4l2-framebuffer;</entry>
-               <entry>Whether clipping the overlaid image is
-supported, see <xref linkend="overlay" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_FRAMERAM</constant></entry>
-               <entry><constant>V4L2_FBUF_CAP_EXTERNOVERLAY</constant>
-<emphasis>not set</emphasis> in field
-<structfield>capability</structfield> of &v4l2-framebuffer;</entry>
-               <entry>Whether overlay overwrites frame buffer memory,
-see <xref linkend="overlay" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_SCALES</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>This flag indicates if the hardware can scale
-images. The V4L2 API implies the scale factor by setting the cropping
-dimensions and image size with the &VIDIOC-S-CROP; and &VIDIOC-S-FMT;
-ioctl, respectively. The driver returns the closest sizes possible.
-For more information on cropping and scaling see <xref
-                   linkend="crop" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_MONOCHROME</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>Applications can enumerate the supported image
-formats with the &VIDIOC-ENUM-FMT; ioctl to determine if the device
-supports grey scale capturing only. For more information on image
-formats see <xref linkend="pixfmt" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_SUBCAPTURE</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>Applications can call the &VIDIOC-G-CROP; ioctl
-to determine if the device supports capturing a subsection of the full
-picture ("cropping" in V4L2). If not, the ioctl returns the &EINVAL;.
-For more information on cropping and scaling see <xref
-                   linkend="crop" />.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_MPEG_DECODER</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>Applications can enumerate the supported image
-formats with the &VIDIOC-ENUM-FMT; ioctl to determine if the device
-supports MPEG streams.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_MPEG_ENCODER</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>See above.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_MJPEG_DECODER</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>See above.</entry>
-             </row>
-             <row>
-               <entry><constant>VID_TYPE_MJPEG_ENCODER</constant></entry>
-               <entry><constant>-</constant></entry>
-               <entry>See above.</entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable></para>
-
-      <para>The <structfield>audios</structfield> field was replaced
-by <structfield>capabilities</structfield> flag
-<constant>V4L2_CAP_AUDIO</constant>, indicating
-<emphasis>if</emphasis> the device has any audio inputs or outputs. To
-determine their number applications can enumerate audio inputs with
-the &VIDIOC-G-AUDIO; ioctl. The audio ioctls are described in <xref
-         linkend="audio" />.</para>
-
-      <para>The <structfield>maxwidth</structfield>,
-<structfield>maxheight</structfield>,
-<structfield>minwidth</structfield> and
-<structfield>minheight</structfield> fields were removed. Calling the
-&VIDIOC-S-FMT; or &VIDIOC-TRY-FMT; ioctl with the desired dimensions
-returns the closest size possible, taking into account the current
-video standard, cropping and scaling limitations.</para>
-    </section>
-
-    <section>
-      <title>Video Sources</title>
-
-      <para>V4L provides the <constant>VIDIOCGCHAN</constant> and
-<constant>VIDIOCSCHAN</constant> ioctl using struct
-<structname>video_channel</structname> to enumerate
-the video inputs of a V4L device. The equivalent V4L2 ioctls
-are &VIDIOC-ENUMINPUT;, &VIDIOC-G-INPUT; and &VIDIOC-S-INPUT;
-using &v4l2-input; as discussed in <xref linkend="video" />.</para>
-
-      <para>The <structfield>channel</structfield> field counting
-inputs was renamed to <structfield>index</structfield>, the video
-input types were renamed as follows: <informaltable>
-         <tgroup cols="2">
-           <thead>
-             <row>
-               <entry>struct <structname>video_channel</structname>
-<structfield>type</structfield></entry>
-               <entry>&v4l2-input;
-<structfield>type</structfield></entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry><constant>VIDEO_TYPE_TV</constant></entry>
-               <entry><constant>V4L2_INPUT_TYPE_TUNER</constant></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_TYPE_CAMERA</constant></entry>
-               <entry><constant>V4L2_INPUT_TYPE_CAMERA</constant></entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable></para>
-
-      <para>Unlike the <structfield>tuners</structfield> field
-expressing the number of tuners of this input, V4L2 assumes each video
-input is connected to at most one tuner. However a tuner can have more
-than one input, &ie; RF connectors, and a device can have multiple
-tuners. The index number of the tuner associated with the input, if
-any, is stored in field <structfield>tuner</structfield> of
-&v4l2-input;. Enumeration of tuners is discussed in <xref
-         linkend="tuner" />.</para>
-
-      <para>The redundant <constant>VIDEO_VC_TUNER</constant> flag was
-dropped. Video inputs associated with a tuner are of type
-<constant>V4L2_INPUT_TYPE_TUNER</constant>. The
-<constant>VIDEO_VC_AUDIO</constant> flag was replaced by the
-<structfield>audioset</structfield> field. V4L2 considers devices with
-up to 32 audio inputs. Each set bit in the
-<structfield>audioset</structfield> field represents one audio input
-this video input combines with. For information about audio inputs and
-how to switch between them see <xref linkend="audio" />.</para>
-
-      <para>The <structfield>norm</structfield> field describing the
-supported video standards was replaced by
-<structfield>std</structfield>. The V4L specification mentions a flag
-<constant>VIDEO_VC_NORM</constant> indicating whether the standard can
-be changed. This flag was a later addition together with the
-<structfield>norm</structfield> field and has been removed in the
-meantime. V4L2 has a similar, albeit more comprehensive approach
-to video standards, see <xref linkend="standard" /> for more
-information.</para>
-    </section>
-
-    <section>
-      <title>Tuning</title>
-
-      <para>The V4L <constant>VIDIOCGTUNER</constant> and
-<constant>VIDIOCSTUNER</constant> ioctl and struct
-<structname>video_tuner</structname> can be used to enumerate the
-tuners of a V4L TV or radio device. The equivalent V4L2 ioctls are
-&VIDIOC-G-TUNER; and &VIDIOC-S-TUNER; using &v4l2-tuner;. Tuners are
-covered in <xref linkend="tuner" />.</para>
-
-      <para>The <structfield>tuner</structfield> field counting tuners
-was renamed to <structfield>index</structfield>. The fields
-<structfield>name</structfield>, <structfield>rangelow</structfield>
-and <structfield>rangehigh</structfield> remained unchanged.</para>
-
-      <para>The <constant>VIDEO_TUNER_PAL</constant>,
-<constant>VIDEO_TUNER_NTSC</constant> and
-<constant>VIDEO_TUNER_SECAM</constant> flags indicating the supported
-video standards were dropped. This information is now contained in the
-associated &v4l2-input;. No replacement exists for the
-<constant>VIDEO_TUNER_NORM</constant> flag indicating whether the
-video standard can be switched. The <structfield>mode</structfield>
-field to select a different video standard was replaced by a whole new
-set of ioctls and structures described in <xref linkend="standard" />.
-Due to its ubiquity it should be mentioned the BTTV driver supports
-several standards in addition to the regular
-<constant>VIDEO_MODE_PAL</constant> (0),
-<constant>VIDEO_MODE_NTSC</constant>,
-<constant>VIDEO_MODE_SECAM</constant> and
-<constant>VIDEO_MODE_AUTO</constant> (3). Namely N/PAL Argentina,
-M/PAL, N/PAL, and NTSC Japan with numbers 3-6 (sic).</para>
-
-      <para>The <constant>VIDEO_TUNER_STEREO_ON</constant> flag
-indicating stereo reception became
-<constant>V4L2_TUNER_SUB_STEREO</constant> in field
-<structfield>rxsubchans</structfield>. This field also permits the
-detection of monaural and bilingual audio, see the definition of
-&v4l2-tuner; for details. Presently no replacement exists for the
-<constant>VIDEO_TUNER_RDS_ON</constant> and
-<constant>VIDEO_TUNER_MBS_ON</constant> flags.</para>
-
-      <para> The <constant>VIDEO_TUNER_LOW</constant> flag was renamed
-to <constant>V4L2_TUNER_CAP_LOW</constant> in the &v4l2-tuner;
-<structfield>capability</structfield> field.</para>
-
-      <para>The <constant>VIDIOCGFREQ</constant> and
-<constant>VIDIOCSFREQ</constant> ioctl to change the tuner frequency
-where renamed to &VIDIOC-G-FREQUENCY; and  &VIDIOC-S-FREQUENCY;. They
-take a pointer to a &v4l2-frequency; instead of an unsigned long
-integer.</para>
-    </section>
-
-    <section id="v4l-image-properties">
-      <title>Image Properties</title>
-
-      <para>V4L2 has no equivalent of the
-<constant>VIDIOCGPICT</constant> and <constant>VIDIOCSPICT</constant>
-ioctl and struct <structname>video_picture</structname>. The following
-fields where replaced by V4L2 controls accessible with the
-&VIDIOC-QUERYCTRL;, &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls:<informaltable>
-         <tgroup cols="2">
-           <thead>
-             <row>
-               <entry>struct <structname>video_picture</structname></entry>
-               <entry>V4L2 Control ID</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry><structfield>brightness</structfield></entry>
-               <entry><constant>V4L2_CID_BRIGHTNESS</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>hue</structfield></entry>
-               <entry><constant>V4L2_CID_HUE</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>colour</structfield></entry>
-               <entry><constant>V4L2_CID_SATURATION</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>contrast</structfield></entry>
-               <entry><constant>V4L2_CID_CONTRAST</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>whiteness</structfield></entry>
-               <entry><constant>V4L2_CID_WHITENESS</constant></entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable></para>
-
-      <para>The V4L picture controls are assumed to range from 0 to
-65535 with no particular reset value. The V4L2 API permits arbitrary
-limits and defaults which can be queried with the &VIDIOC-QUERYCTRL;
-ioctl. For general information about controls see <xref
-linkend="control" />.</para>
-
-      <para>The <structfield>depth</structfield> (average number of
-bits per pixel) of a video image is implied by the selected image
-format. V4L2 does not explicitely provide such information assuming
-applications recognizing the format are aware of the image depth and
-others need not know. The <structfield>palette</structfield> field
-moved into the &v4l2-pix-format;:<informaltable>
-         <tgroup cols="2">
-           <thead>
-             <row>
-               <entry>struct <structname>video_picture</structname>
-<structfield>palette</structfield></entry>
-               <entry>&v4l2-pix-format;
-<structfield>pixfmt</structfield></entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry><constant>VIDEO_PALETTE_GREY</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-GREY"><constant>V4L2_PIX_FMT_GREY</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_HI240</constant></entry>
-               <entry><para><link
-linkend="pixfmt-reserved"><constant>V4L2_PIX_FMT_HI240</constant></link><footnote>
-                     <para>This is a custom format used by the BTTV
-driver, not one of the V4L2 standard formats.</para>
-                   </footnote></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_RGB565</constant></entry>
-               <entry><para><link
-linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_RGB565</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_RGB555</constant></entry>
-               <entry><para><link
-linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_RGB555</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_RGB24</constant></entry>
-               <entry><para><link
-linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_BGR24</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_RGB32</constant></entry>
-               <entry><para><link
-linkend="pixfmt-rgb"><constant>V4L2_PIX_FMT_BGR32</constant></link><footnote>
-                     <para>Presumably all V4L RGB formats are
-little-endian, although some drivers might interpret them according to machine endianess. V4L2 defines little-endian, big-endian and red/blue
-swapped variants. For details see <xref linkend="pixfmt-rgb" />.</para>
-                   </footnote></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV422</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YUYV"><constant>V4L2_PIX_FMT_YUYV</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><para><constant>VIDEO_PALETTE_YUYV</constant><footnote>
-                     <para><constant>VIDEO_PALETTE_YUV422</constant>
-and <constant>VIDEO_PALETTE_YUYV</constant> are the same formats. Some
-V4L drivers respond to one, some to the other.</para>
-                   </footnote></para></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YUYV"><constant>V4L2_PIX_FMT_YUYV</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_UYVY</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-UYVY"><constant>V4L2_PIX_FMT_UYVY</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV420</constant></entry>
-               <entry>None</entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV411</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-Y41P"><constant>V4L2_PIX_FMT_Y41P</constant></link><footnote>
-                     <para>Not to be confused with
-<constant>V4L2_PIX_FMT_YUV411P</constant>, which is a planar
-format.</para> </footnote></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_RAW</constant></entry>
-               <entry><para>None<footnote> <para>V4L explains this
-as: "RAW capture (BT848)"</para> </footnote></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV422P</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YUV422P"><constant>V4L2_PIX_FMT_YUV422P</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV411P</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YUV411P"><constant>V4L2_PIX_FMT_YUV411P</constant></link><footnote>
-                     <para>Not to be confused with
-<constant>V4L2_PIX_FMT_Y41P</constant>, which is a packed
-format.</para> </footnote></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV420P</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></link></para></entry>
-             </row>
-             <row>
-               <entry><constant>VIDEO_PALETTE_YUV410P</constant></entry>
-               <entry><para><link
-linkend="V4L2-PIX-FMT-YVU410"><constant>V4L2_PIX_FMT_YVU410</constant></link></para></entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable></para>
-
-      <para>V4L2 image formats are defined in <xref
-linkend="pixfmt" />. The image format can be selected with the
-&VIDIOC-S-FMT; ioctl.</para>
-    </section>
-
-    <section>
-      <title>Audio</title>
-
-      <para>The <constant>VIDIOCGAUDIO</constant> and
-<constant>VIDIOCSAUDIO</constant> ioctl and struct
-<structname>video_audio</structname> are used to enumerate the
-audio inputs of a V4L device. The equivalent V4L2 ioctls are
-&VIDIOC-G-AUDIO; and &VIDIOC-S-AUDIO; using &v4l2-audio; as
-discussed in <xref linkend="audio" />.</para>
-
-      <para>The <structfield>audio</structfield> "channel number"
-field counting audio inputs was renamed to
-<structfield>index</structfield>.</para>
-
-      <para>On <constant>VIDIOCSAUDIO</constant> the
-<structfield>mode</structfield> field selects <emphasis>one</emphasis>
-of the <constant>VIDEO_SOUND_MONO</constant>,
-<constant>VIDEO_SOUND_STEREO</constant>,
-<constant>VIDEO_SOUND_LANG1</constant> or
-<constant>VIDEO_SOUND_LANG2</constant> audio demodulation modes. When
-the current audio standard is BTSC
-<constant>VIDEO_SOUND_LANG2</constant> refers to SAP and
-<constant>VIDEO_SOUND_LANG1</constant> is meaningless. Also
-undocumented in the V4L specification, there is no way to query the
-selected mode. On <constant>VIDIOCGAUDIO</constant> the driver returns
-the <emphasis>actually received</emphasis> audio programmes in this
-field. In the V4L2 API this information is stored in the &v4l2-tuner;
-<structfield>rxsubchans</structfield> and
-<structfield>audmode</structfield> fields, respectively. See <xref
-linkend="tuner" /> for more information on tuners. Related to audio
-modes &v4l2-audio; also reports if this is a mono or stereo
-input, regardless if the source is a tuner.</para>
-
-      <para>The following fields where replaced by V4L2 controls
-accessible with the &VIDIOC-QUERYCTRL;, &VIDIOC-G-CTRL; and
-&VIDIOC-S-CTRL; ioctls:<informaltable>
-         <tgroup cols="2">
-           <thead>
-             <row>
-               <entry>struct
-<structname>video_audio</structname></entry>
-               <entry>V4L2 Control ID</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry><structfield>volume</structfield></entry>
-               <entry><constant>V4L2_CID_AUDIO_VOLUME</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>bass</structfield></entry>
-               <entry><constant>V4L2_CID_AUDIO_BASS</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>treble</structfield></entry>
-               <entry><constant>V4L2_CID_AUDIO_TREBLE</constant></entry>
-             </row>
-             <row>
-               <entry><structfield>balance</structfield></entry>
-               <entry><constant>V4L2_CID_AUDIO_BALANCE</constant></entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable></para>
-
-      <para>To determine which of these controls are supported by a
-driver V4L provides the <structfield>flags</structfield>
-<constant>VIDEO_AUDIO_VOLUME</constant>,
-<constant>VIDEO_AUDIO_BASS</constant>,
-<constant>VIDEO_AUDIO_TREBLE</constant> and
-<constant>VIDEO_AUDIO_BALANCE</constant>. In the V4L2 API the
-&VIDIOC-QUERYCTRL; ioctl reports if the respective control is
-supported. Accordingly the <constant>VIDEO_AUDIO_MUTABLE</constant>
-and <constant>VIDEO_AUDIO_MUTE</constant> flags where replaced by the
-boolean <constant>V4L2_CID_AUDIO_MUTE</constant> control.</para>
-
-      <para>All V4L2 controls have a <structfield>step</structfield>
-attribute replacing the struct <structname>video_audio</structname>
-<structfield>step</structfield> field. The V4L audio controls are
-assumed to range from 0 to 65535 with no particular reset value. The
-V4L2 API permits arbitrary limits and defaults which can be queried
-with the &VIDIOC-QUERYCTRL; ioctl. For general information about
-controls see <xref linkend="control" />.</para>
-    </section>
-
-    <section>
-      <title>Frame Buffer Overlay</title>
-
-      <para>The V4L2 ioctls equivalent to
-<constant>VIDIOCGFBUF</constant> and <constant>VIDIOCSFBUF</constant>
-are &VIDIOC-G-FBUF; and &VIDIOC-S-FBUF;. The
-<structfield>base</structfield> field of struct
-<structname>video_buffer</structname> remained unchanged, except V4L2
-defines a flag to indicate non-destructive overlays instead of a
-<constant>NULL</constant> pointer. All other fields moved into the
-&v4l2-pix-format; <structfield>fmt</structfield> substructure of
-&v4l2-framebuffer;. The <structfield>depth</structfield> field was
-replaced by <structfield>pixelformat</structfield>. See <xref
-         linkend="pixfmt-rgb" /> for a list of RGB formats and their
-respective color depths.</para>
-
-      <para>Instead of the special ioctls
-<constant>VIDIOCGWIN</constant> and <constant>VIDIOCSWIN</constant>
-V4L2 uses the general-purpose data format negotiation ioctls
-&VIDIOC-G-FMT; and &VIDIOC-S-FMT;. They take a pointer to a
-&v4l2-format; as argument. Here the <structfield>win</structfield>
-member of the <structfield>fmt</structfield> union is used, a
-&v4l2-window;.</para>
-
-      <para>The <structfield>x</structfield>,
-<structfield>y</structfield>, <structfield>width</structfield> and
-<structfield>height</structfield> fields of struct
-<structname>video_window</structname> moved into &v4l2-rect;
-substructure <structfield>w</structfield> of struct
-<structname>v4l2_window</structname>. The
-<structfield>chromakey</structfield>,
-<structfield>clips</structfield>, and
-<structfield>clipcount</structfield> fields remained unchanged. Struct
-<structname>video_clip</structname> was renamed to &v4l2-clip;, also
-containing a struct <structname>v4l2_rect</structname>, but the
-semantics are still the same.</para>
-
-      <para>The <constant>VIDEO_WINDOW_INTERLACE</constant> flag was
-dropped. Instead applications must set the
-<structfield>field</structfield> field to
-<constant>V4L2_FIELD_ANY</constant> or
-<constant>V4L2_FIELD_INTERLACED</constant>. The
-<constant>VIDEO_WINDOW_CHROMAKEY</constant> flag moved into
-&v4l2-framebuffer;, under the new name
-<constant>V4L2_FBUF_FLAG_CHROMAKEY</constant>.</para>
-
-      <para>In V4L, storing a bitmap pointer in
-<structfield>clips</structfield> and setting
-<structfield>clipcount</structfield> to
-<constant>VIDEO_CLIP_BITMAP</constant> (-1) requests bitmap
-clipping, using a fixed size bitmap of 1024 &times; 625 bits. Struct
-<structname>v4l2_window</structname> has a separate
-<structfield>bitmap</structfield> pointer field for this purpose and
-the bitmap size is determined by <structfield>w.width</structfield> and
-<structfield>w.height</structfield>.</para>
-
-      <para>The <constant>VIDIOCCAPTURE</constant> ioctl to enable or
-disable overlay was renamed to &VIDIOC-OVERLAY;.</para>
-    </section>
-
-    <section>
-      <title>Cropping</title>
-
-      <para>To capture only a subsection of the full picture V4L
-defines the <constant>VIDIOCGCAPTURE</constant> and
-<constant>VIDIOCSCAPTURE</constant> ioctls using struct
-<structname>video_capture</structname>. The equivalent V4L2 ioctls are
-&VIDIOC-G-CROP; and &VIDIOC-S-CROP; using &v4l2-crop;, and the related
-&VIDIOC-CROPCAP; ioctl. This is a rather complex matter, see
-<xref linkend="crop" /> for details.</para>
-
-      <para>The <structfield>x</structfield>,
-<structfield>y</structfield>, <structfield>width</structfield> and
-<structfield>height</structfield> fields moved into &v4l2-rect;
-substructure <structfield>c</structfield> of struct
-<structname>v4l2_crop</structname>. The
-<structfield>decimation</structfield> field was dropped. In the V4L2
-API the scaling factor is implied by the size of the cropping
-rectangle and the size of the captured or overlaid image.</para>
-
-      <para>The <constant>VIDEO_CAPTURE_ODD</constant>
-and <constant>VIDEO_CAPTURE_EVEN</constant> flags to capture only the
-odd or even field, respectively, were replaced by
-<constant>V4L2_FIELD_TOP</constant> and
-<constant>V4L2_FIELD_BOTTOM</constant> in the field named
-<structfield>field</structfield> of &v4l2-pix-format; and
-&v4l2-window;. These structures are used to select a capture or
-overlay format with the &VIDIOC-S-FMT; ioctl.</para>
-    </section>
-
-    <section>
-      <title>Reading Images, Memory Mapping</title>
-
-      <section>
-       <title>Capturing using the read method</title>
-
-       <para>There is no essential difference between reading images
-from a V4L or V4L2 device using the &func-read; function, however V4L2
-drivers are not required to support this I/O method. Applications can
-determine if the function is available with the &VIDIOC-QUERYCAP;
-ioctl. All V4L2 devices exchanging data with applications must support
-the &func-select; and &func-poll; functions.</para>
-
-       <para>To select an image format and size, V4L provides the
-<constant>VIDIOCSPICT</constant> and <constant>VIDIOCSWIN</constant>
-ioctls. V4L2 uses the general-purpose data format negotiation ioctls
-&VIDIOC-G-FMT; and &VIDIOC-S-FMT;. They take a pointer to a
-&v4l2-format; as argument, here the &v4l2-pix-format; named
-<structfield>pix</structfield> of its <structfield>fmt</structfield>
-union is used.</para>
-
-       <para>For more information about the V4L2 read interface see
-<xref linkend="rw" />.</para>
-      </section>
-      <section>
-       <title>Capturing using memory mapping</title>
-
-       <para>Applications can read from V4L devices by mapping
-buffers in device memory, or more often just buffers allocated in
-DMA-able system memory, into their address space. This avoids the data
-copying overhead of the read method. V4L2 supports memory mapping as
-well, with a few differences.</para>
-
-       <informaltable>
-         <tgroup cols="2">
-           <thead>
-             <row>
-               <entry>V4L</entry>
-               <entry>V4L2</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row>
-               <entry></entry>
-               <entry>The image format must be selected before
-buffers are allocated, with the &VIDIOC-S-FMT; ioctl. When no format
-is selected the driver may use the last, possibly by another
-application requested format.</entry>
-             </row>
-             <row>
-               <entry><para>Applications cannot change the number of
-buffers. The it is built into the driver, unless it has a module
-option to change the number when the driver module is
-loaded.</para></entry>
-               <entry><para>The &VIDIOC-REQBUFS; ioctl allocates the
-desired number of buffers, this is a required step in the initialization
-sequence.</para></entry>
-             </row>
-             <row>
-               <entry><para>Drivers map all buffers as one contiguous
-range of memory. The <constant>VIDIOCGMBUF</constant> ioctl is
-available to query the number of buffers, the offset of each buffer
-from the start of the virtual file, and the overall amount of memory
-used, which can be used as arguments for the &func-mmap;
-function.</para></entry>
-               <entry><para>Buffers are individually mapped. The
-offset and size of each buffer can be determined with the
-&VIDIOC-QUERYBUF; ioctl.</para></entry>
-             </row>
-             <row>
-               <entry><para>The <constant>VIDIOCMCAPTURE</constant>
-ioctl prepares a buffer for capturing. It also determines the image
-format for this buffer. The ioctl returns immediately, eventually with
-an &EAGAIN; if no video signal had been detected. When the driver
-supports more than one buffer applications can call the ioctl multiple
-times and thus have multiple outstanding capture
-requests.</para><para>The <constant>VIDIOCSYNC</constant> ioctl
-suspends execution until a particular buffer has been
-filled.</para></entry>
-               <entry><para>Drivers maintain an incoming and outgoing
-queue. &VIDIOC-QBUF; enqueues any empty buffer into the incoming
-queue. Filled buffers are dequeued from the outgoing queue with the
-&VIDIOC-DQBUF; ioctl. To wait until filled buffers become available this
-function, &func-select; or &func-poll; can be used. The
-&VIDIOC-STREAMON; ioctl must be called once after enqueuing one or
-more buffers to start capturing. Its counterpart
-&VIDIOC-STREAMOFF; stops capturing and dequeues all buffers from both
-queues. Applications can query the signal status, if known, with the
-&VIDIOC-ENUMINPUT; ioctl.</para></entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </informaltable>
-
-       <para>For a more in-depth discussion of memory mapping and
-examples, see <xref linkend="mmap" />.</para>
-      </section>
-    </section>
-
-    <section>
-      <title>Reading Raw VBI Data</title>
-
-      <para>Originally the V4L API did not specify a raw VBI capture
-interface, only the device file <filename>/dev/vbi</filename> was
-reserved for this purpose. The only driver supporting this interface
-was the BTTV driver, de-facto defining the V4L VBI interface. Reading
-from the device yields a raw VBI image with the following
-parameters:<informaltable>
-           <tgroup cols="2">
-             <thead>
-               <row>
-                 <entry>&v4l2-vbi-format;</entry>
-                 <entry>V4L, BTTV driver</entry>
-               </row>
-             </thead>
-             <tbody valign="top">
-               <row>
-                 <entry>sampling_rate</entry>
-                 <entry>28636363&nbsp;Hz NTSC (or any other 525-line
-standard); 35468950&nbsp;Hz PAL and SECAM (625-line standards)</entry>
-               </row>
-               <row>
-                 <entry>offset</entry>
-                 <entry>?</entry>
-               </row>
-               <row>
-                 <entry>samples_per_line</entry>
-                 <entry>2048</entry>
-               </row>
-               <row>
-                 <entry>sample_format</entry>
-                 <entry>V4L2_PIX_FMT_GREY. The last four bytes (a
-machine endianess integer) contain a frame counter.</entry>
-               </row>
-               <row>
-                 <entry>start[]</entry>
-                 <entry>10, 273 NTSC; 22, 335 PAL and SECAM</entry>
-               </row>
-               <row>
-                 <entry>count[]</entry>
-                 <entry><para>16, 16<footnote><para>Old driver
-versions used different values, eventually the custom
-<constant>BTTV_VBISIZE</constant> ioctl was added to query the
-correct values.</para></footnote></para></entry>
-               </row>
-               <row>
-                 <entry>flags</entry>
-                 <entry>0</entry>
-               </row>
-             </tbody>
-           </tgroup>
-       </informaltable></para>
-
-      <para>Undocumented in the V4L specification, in Linux 2.3 the
-<constant>VIDIOCGVBIFMT</constant> and
-<constant>VIDIOCSVBIFMT</constant> ioctls using struct
-<structname>vbi_format</structname> were added to determine the VBI
-image parameters. These ioctls are only partially compatible with the
-V4L2 VBI interface specified in <xref linkend="raw-vbi" />.</para>
-
-      <para>An <structfield>offset</structfield> field does not
-exist, <structfield>sample_format</structfield> is supposed to be
-<constant>VIDEO_PALETTE_RAW</constant>, equivalent to
-<constant>V4L2_PIX_FMT_GREY</constant>. The remaining fields are
-probably equivalent to &v4l2-vbi-format;.</para>
-
-      <para>Apparently only the Zoran (ZR 36120) driver implements
-these ioctls. The semantics differ from those specified for V4L2 in two
-ways. The parameters are reset on &func-open; and
-<constant>VIDIOCSVBIFMT</constant> always returns an &EINVAL; if the
-parameters are invalid.</para>
-    </section>
-
-    <section>
-      <title>Miscellaneous</title>
-
-      <para>V4L2 has no equivalent of the
-<constant>VIDIOCGUNIT</constant> ioctl. Applications can find the VBI
-device associated with a video capture device (or vice versa) by
-reopening the device and requesting VBI data. For details see
-<xref linkend="open" />.</para>
-
-      <para>No replacement exists for <constant>VIDIOCKEY</constant>,
-and the V4L functions for microcode programming. A new interface for
-MPEG compression and playback devices is documented in <xref
-         linkend="extended-controls" />.</para>
-    </section>
-
-  </section>
-
-  <section id="hist-v4l2">
-    <title>Changes of the V4L2 API</title>
-
-    <para>Soon after the V4L API was added to the kernel it was
-criticised as too inflexible. In August 1998 Bill Dirks proposed a
-number of improvements and began to work on documentation, example
-drivers and applications. With the help of other volunteers this
-eventually became the V4L2 API, not just an extension but a
-replacement for the V4L API. However it took another four years and
-two stable kernel releases until the new API was finally accepted for
-inclusion into the kernel in its present form.</para>
-
-    <section>
-      <title>Early Versions</title>
-      <para>1998-08-20: First version.</para>
-
-      <para>1998-08-27: The &func-select; function was introduced.</para>
-
-      <para>1998-09-10: New video standard interface.</para>
-
-      <para>1998-09-18: The <constant>VIDIOC_NONCAP</constant> ioctl
-was replaced by the otherwise meaningless <constant>O_TRUNC</constant>
-&func-open; flag, and the aliases <constant>O_NONCAP</constant> and
-<constant>O_NOIO</constant> were defined. Applications can set this
-flag if they intend to access controls only, as opposed to capture
-applications which need exclusive access. The
-<constant>VIDEO_STD_XXX</constant> identifiers are now ordinals
-instead of flags, and the <function>video_std_construct()</function>
-helper function takes id and transmission arguments.</para>
-
-      <para>1998-09-28: Revamped video standard. Made video controls
-individually enumerable.</para>
-
-      <para>1998-10-02: The <structfield>id</structfield> field was
-removed from struct <structname>video_standard</structname> and the
-color subcarrier fields were renamed. The &VIDIOC-QUERYSTD; ioctl was
-renamed to &VIDIOC-ENUMSTD;, &VIDIOC-G-INPUT; to &VIDIOC-ENUMINPUT;. A
-first draft of the Codec API was released.</para>
-
-      <para>1998-11-08: Many minor changes. Most symbols have been
-renamed. Some material changes to &v4l2-capability;.</para>
-
-      <para>1998-11-12: The read/write directon of some ioctls was misdefined.</para>
-
-      <para>1998-11-14: <constant>V4L2_PIX_FMT_RGB24</constant>
-changed to <constant>V4L2_PIX_FMT_BGR24</constant>, and
-<constant>V4L2_PIX_FMT_RGB32</constant> changed to
-<constant>V4L2_PIX_FMT_BGR32</constant>. Audio controls are now
-accessible with the &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls under
-names starting with <constant>V4L2_CID_AUDIO</constant>. The
-<constant>V4L2_MAJOR</constant> define was removed from
-<filename>videodev.h</filename> since it was only used once in the
-<filename>videodev</filename> kernel module. The
-<constant>YUV422</constant> and <constant>YUV411</constant> planar
-image formats were added.</para>
-
-      <para>1998-11-28: A few ioctl symbols changed. Interfaces for codecs and
-video output devices were added.</para>
-
-      <para>1999-01-14: A raw VBI capture interface was added.</para>
-
-      <para>1999-01-19: The <constant>VIDIOC_NEXTBUF</constant> ioctl
-      was removed.</para>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.16 1999-01-31</title>
-      <para>1999-01-27: There is now one QBUF ioctl, VIDIOC_QWBUF and VIDIOC_QRBUF
-are gone. VIDIOC_QBUF takes a v4l2_buffer as a parameter. Added
-digital zoom (cropping) controls.</para>
-    </section>
-
-    <!-- Where's 0.17? mhs couldn't find that videodev.h, perhaps Bill
-        forgot to bump the version number or never released it. -->
-
-    <section>
-      <title>V4L2 Version 0.18 1999-03-16</title>
-      <para>Added a v4l to V4L2 ioctl compatibility layer to
-videodev.c. Driver writers, this changes how you implement your ioctl
-handler. See the Driver Writer's Guide. Added some more control id
-codes.</para>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.19 1999-06-05</title>
-      <para>1999-03-18: Fill in the category and catname fields of
-v4l2_queryctrl objects before passing them to the driver. Required a
-minor change to the VIDIOC_QUERYCTRL handlers in the sample
-drivers.</para>
-      <para>1999-03-31: Better compatibility for v4l memory capture
-ioctls. Requires changes to drivers to fully support new compatibility
-features, see Driver Writer's Guide and v4l2cap.c. Added new control
-IDs: V4L2_CID_HFLIP, _VFLIP. Changed V4L2_PIX_FMT_YUV422P to _YUV422P,
-and _YUV411P to _YUV411P.</para>
-      <para>1999-04-04: Added a few more control IDs.</para>
-      <para>1999-04-07: Added the button control type.</para>
-      <para>1999-05-02: Fixed a typo in videodev.h, and added the
-V4L2_CTRL_FLAG_GRAYED (later V4L2_CTRL_FLAG_GRABBED) flag.</para>
-      <para>1999-05-20: Definition of VIDIOC_G_CTRL was wrong causing
-a malfunction of this ioctl.</para>
-      <para>1999-06-05: Changed the value of
-V4L2_CID_WHITENESS.</para>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.20 (1999-09-10)</title>
-
-      <para>Version 0.20 introduced a number of changes which were
-<emphasis>not backward compatible</emphasis> with 0.19 and earlier
-versions. Purpose of these changes was to simplify the API, while
-making it more extensible and following common Linux driver API
-conventions.</para>
-
-      <orderedlist>
-       <listitem>
-         <para>Some typos in <constant>V4L2_FMT_FLAG</constant>
-symbols were fixed. &v4l2-clip; was changed for compatibility with
-v4l. (1999-08-30)</para>
-       </listitem>
-
-       <listitem>
-         <para><constant>V4L2_TUNER_SUB_LANG1</constant> was added.
-(1999-09-05)</para>
-       </listitem>
-
-       <listitem>
-         <para>All ioctl() commands that used an integer argument now
-take a pointer to an integer. Where it makes sense, ioctls will return
-the actual new value in the integer pointed to by the argument, a
-common convention in the V4L2 API. The affected ioctls are:
-VIDIOC_PREVIEW, VIDIOC_STREAMON, VIDIOC_STREAMOFF, VIDIOC_S_FREQ,
-VIDIOC_S_INPUT, VIDIOC_S_OUTPUT, VIDIOC_S_EFFECT. For example
-<programlisting>
-err = ioctl (fd, VIDIOC_XXX, V4L2_XXX);
-</programlisting> becomes <programlisting>
-int a = V4L2_XXX; err = ioctl(fd, VIDIOC_XXX, &amp;a);
-</programlisting>
-         </para>
-       </listitem>
-
-       <listitem>
-         <para>All the different get- and set-format commands were
-swept into one &VIDIOC-G-FMT; and &VIDIOC-S-FMT; ioctl taking a union
-and a type field selecting the union member as parameter. Purpose is to
-simplify the API by eliminating several ioctls and to allow new and
-driver private data streams without adding new ioctls.</para>
-
-         <para>This change obsoletes the following ioctls:
-<constant>VIDIOC_S_INFMT</constant>,
-<constant>VIDIOC_G_INFMT</constant>,
-<constant>VIDIOC_S_OUTFMT</constant>,
-<constant>VIDIOC_G_OUTFMT</constant>,
-<constant>VIDIOC_S_VBIFMT</constant> and
-<constant>VIDIOC_G_VBIFMT</constant>. The image format structure
-<structname>v4l2_format</structname> was renamed to &v4l2-pix-format;,
-while &v4l2-format; is now the envelopping structure for all format
-negotiations.</para>
-       </listitem>
-
-       <listitem>
-         <para>Similar to the changes above, the
-<constant>VIDIOC_G_PARM</constant> and
-<constant>VIDIOC_S_PARM</constant> ioctls were merged with
-<constant>VIDIOC_G_OUTPARM</constant> and
-<constant>VIDIOC_S_OUTPARM</constant>. A
-<structfield>type</structfield> field in the new &v4l2-streamparm;
-selects the respective union member.</para>
-
-         <para>This change obsoletes the
-<constant>VIDIOC_G_OUTPARM</constant> and
-<constant>VIDIOC_S_OUTPARM</constant> ioctls.</para>
-       </listitem>
-
-       <listitem>
-         <para>Control enumeration was simplified, and two new
-control flags were introduced and one dropped. The
-<structfield>catname</structfield> field was replaced by a
-<structfield>group</structfield> field.</para>
-
-         <para>Drivers can now flag unsupported and temporarily
-unavailable controls with <constant>V4L2_CTRL_FLAG_DISABLED</constant>
-and <constant>V4L2_CTRL_FLAG_GRABBED</constant> respectively. The
-<structfield>group</structfield> name indicates a possibly narrower
-classification than the <structfield>category</structfield>. In other
-words, there may be multiple groups within a category. Controls within
-a group would typically be drawn within a group box. Controls in
-different categories might have a greater separation, or may even
-appear in separate windows.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &v4l2-buffer; <structfield>timestamp</structfield>
-was changed to a 64 bit integer, containing the sampling or output
-time of the frame in nanoseconds. Additionally timestamps will be in
-absolute system time, not starting from zero at the beginning of a
-stream. The data type name for timestamps is stamp_t, defined as a
-signed 64-bit integer. Output devices should not send a buffer out
-until the time in the timestamp field has arrived. I would like to
-follow SGI's lead, and adopt a multimedia timestamping system like
-their UST (Unadjusted System Time). See
-http://web.archive.org/web/*/http://reality.sgi.com
-/cpirazzi_engr/lg/time/intro.html. 
-UST uses timestamps that are 64-bit signed integers
-(not struct timeval's) and given in nanosecond units. The UST clock
-starts at zero when the system is booted and runs continuously and
-uniformly. It takes a little over 292 years for UST to overflow. There
-is no way to set the UST clock. The regular Linux time-of-day clock
-can be changed periodically, which would cause errors if it were being
-used for timestamping a multimedia stream. A real UST style clock will
-require some support in the kernel that is not there yet. But in
-anticipation, I will change the timestamp field to a 64-bit integer,
-and I will change the v4l2_masterclock_gettime() function (used only
-by drivers) to return a 64-bit integer.</para>
-       </listitem>
-
-       <listitem>
-         <para>A <structfield>sequence</structfield> field was added
-to &v4l2-buffer;. The <structfield>sequence</structfield> field counts
-captured frames, it is ignored by output devices. When a capture
-driver drops a frame, the sequence number of that frame is
-skipped.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.20 incremental changes</title>
-      <!-- Version number didn't change anymore, reason unknown. -->
-
-      <para>1999-12-23: In &v4l2-vbi-format; the
-<structfield>reserved1</structfield> field became
-<structfield>offset</structfield>. Previously drivers were required to
-clear the <structfield>reserved1</structfield> field.</para>
-
-      <para>2000-01-13: The
-      <constant>V4L2_FMT_FLAG_NOT_INTERLACED</constant> flag was added.</para>
-
-      <para>2000-07-31: The <filename>linux/poll.h</filename> header
-is now included by <filename>videodev.h</filename> for compatibility
-with the original <filename>videodev.h</filename> file.</para>
-
-      <para>2000-11-20: <constant>V4L2_TYPE_VBI_OUTPUT</constant> and
-<constant>V4L2_PIX_FMT_Y41P</constant> were added.</para>
-
-      <para>2000-11-25: <constant>V4L2_TYPE_VBI_INPUT</constant> was
-added.</para>
-
-      <para>2000-12-04: A couple typos in symbol names were fixed.</para>
-
-      <para>2001-01-18: To avoid namespace conflicts the
-<constant>fourcc</constant> macro defined in the
-<filename>videodev.h</filename> header file was renamed to
-<constant>v4l2_fourcc</constant>.</para>
-
-      <para>2001-01-25: A possible driver-level compatibility problem
-between the <filename>videodev.h</filename> file in Linux 2.4.0 and
-the <filename>videodev.h</filename> file included in the
-<filename>videodevX</filename> patch was fixed. Users of an earlier
-version of <filename>videodevX</filename> on Linux 2.4.0 should
-recompile their V4L and V4L2 drivers.</para>
-
-      <para>2001-01-26: A possible kernel-level incompatibility
-between the <filename>videodev.h</filename> file in the
-<filename>videodevX</filename> patch and the
-<filename>videodev.h</filename> file in Linux 2.2.x with devfs patches
-applied was fixed.</para>
-
-      <para>2001-03-02: Certain V4L ioctls which pass data in both
-direction although they are defined with read-only parameter, did not
-work correctly through the backward compatibility layer.
-[Solution?]</para>
-
-      <para>2001-04-13: Big endian 16-bit RGB formats were added.</para>
-
-      <para>2001-09-17: New YUV formats and the &VIDIOC-G-FREQUENCY; and
-&VIDIOC-S-FREQUENCY; ioctls were added. (The old
-<constant>VIDIOC_G_FREQ</constant> and
-<constant>VIDIOC_S_FREQ</constant> ioctls did not take multiple tuners
-into account.)</para>
-
-      <para>2000-09-18: <constant>V4L2_BUF_TYPE_VBI</constant> was
-added. This may <emphasis>break compatibility</emphasis> as the
-&VIDIOC-G-FMT; and &VIDIOC-S-FMT; ioctls may fail now if the struct
-<structname>v4l2_fmt</structname> <structfield>type</structfield>
-field does not contain <constant>V4L2_BUF_TYPE_VBI</constant>. In the
-documentation of the &v4l2-vbi-format;
-<structfield>offset</structfield> field the ambiguous phrase "rising
-edge" was changed to "leading edge".</para>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.20 2000-11-23</title>
-
-      <para>A number of changes were made to the raw VBI
-interface.</para>
-
-      <orderedlist>
-       <listitem>
-         <para>Figures clarifying the line numbering scheme were
-added to the V4L2 API specification. The
-<structfield>start</structfield>[0] and
-<structfield>start</structfield>[1] fields no longer count line
-numbers beginning at zero. Rationale: a) The previous definition was
-unclear. b) The <structfield>start</structfield>[] values are ordinal
-numbers. c) There is no point in inventing a new line numbering
-scheme. We now use line number as defined by ITU-R, period.
-Compatibility: Add one to the start values. Applications depending on
-the previous semantics may not function correctly.</para>
-       </listitem>
-
-       <listitem>
-         <para>The restriction "count[0] &gt; 0 and count[1] &gt; 0"
-has been relaxed  to "(count[0] + count[1]) &gt; 0". Rationale:
-Drivers may allocate resources at scan line granularity and some data
-services are transmitted only on the first field. The comment that
-both <structfield>count</structfield> values will usually be equal is
-misleading and pointless and has been removed. This change
-<emphasis>breaks compatibility</emphasis> with earlier versions:
-Drivers may return EINVAL, applications may not function
-correctly.</para>
-       </listitem>
-
-       <listitem>
-         <para>Drivers are again permitted to return negative
-(unknown) start values as proposed earlier. Why this feature was
-dropped is unclear. This change may <emphasis>break
-compatibility</emphasis> with applications depending on the start
-values being positive. The use of <constant>EBUSY</constant> and
-<constant>EINVAL</constant> error codes with the &VIDIOC-S-FMT; ioctl
-was clarified. The &EBUSY; was finally documented, and the
-<structfield>reserved2</structfield> field which was previously
-mentioned only in the <filename>videodev.h</filename> header
-file.</para>
-       </listitem>
-
-       <listitem>
-         <para>New buffer types
-<constant>V4L2_TYPE_VBI_INPUT</constant> and
-<constant>V4L2_TYPE_VBI_OUTPUT</constant> were added. The former is an
-alias for the old <constant>V4L2_TYPE_VBI</constant>, the latter was
-missing in the <filename>videodev.h</filename> file.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 Version 0.20 2002-07-25</title>
-      <para>Added sliced VBI interface proposal.</para>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.5.46, 2002-10</title>
-
-      <para>Around October-November 2002, prior to an announced
-feature freeze of Linux 2.5, the API was revised, drawing from
-experience with V4L2 0.20. This unnamed version was finally merged
-into Linux 2.5.46.</para>
-
-      <orderedlist>
-       <listitem>
-         <para>As specified in <xref linkend="related" />, drivers
-must make related device functions available under all minor device
-numbers.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &func-open; function requires access mode
-<constant>O_RDWR</constant> regardless of the device type. All V4L2
-drivers exchanging data with applications must support the
-<constant>O_NONBLOCK</constant> flag. The <constant>O_NOIO</constant>
-flag, a V4L2 symbol which aliased the meaningless
-<constant>O_TRUNC</constant> to indicate accesses without data
-exchange (panel applications) was dropped. Drivers must stay in "panel
-mode" until the application attempts to initiate a data exchange, see
-<xref linkend="open" />.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &v4l2-capability; changed dramatically. Note that
-also the size of the structure changed, which is encoded in the ioctl
-request code, thus older V4L2 devices will respond with an &EINVAL; to
-the new &VIDIOC-QUERYCAP; ioctl.</para>
-
-         <para>There are new fields to identify the driver, a new RDS
-device function <constant>V4L2_CAP_RDS_CAPTURE</constant>, the
-<constant>V4L2_CAP_AUDIO</constant> flag indicates if the device has
-any audio connectors, another I/O capability
-<constant>V4L2_CAP_ASYNCIO</constant> can be flagged. In response to
-these changes the <structfield>type</structfield> field became a bit
-set and was merged into the <structfield>flags</structfield> field.
-<constant>V4L2_FLAG_TUNER</constant> was renamed to
-<constant>V4L2_CAP_TUNER</constant>,
-<constant>V4L2_CAP_VIDEO_OVERLAY</constant> replaced
-<constant>V4L2_FLAG_PREVIEW</constant> and
-<constant>V4L2_CAP_VBI_CAPTURE</constant> and
-<constant>V4L2_CAP_VBI_OUTPUT</constant> replaced
-<constant>V4L2_FLAG_DATA_SERVICE</constant>.
-<constant>V4L2_FLAG_READ</constant> and
-<constant>V4L2_FLAG_WRITE</constant> were merged into
-<constant>V4L2_CAP_READWRITE</constant>.</para>
-
-         <para>The redundant fields
-<structfield>inputs</structfield>, <structfield>outputs</structfield>
-and <structfield>audios</structfield> were removed. These properties
-can be determined as described in <xref linkend="video" /> and <xref
-linkend="audio" />.</para>
-
-         <para>The somewhat volatile and therefore barely useful
-fields <structfield>maxwidth</structfield>,
-<structfield>maxheight</structfield>,
-<structfield>minwidth</structfield>,
-<structfield>minheight</structfield>,
-<structfield>maxframerate</structfield> were removed. This information
-is available as described in <xref linkend="format" /> and
-<xref linkend="standard" />.</para>
-
-         <para><constant>V4L2_FLAG_SELECT</constant> was removed. We
-believe the select() function is important enough to require support
-of it in all V4L2 drivers exchanging data with applications. The
-redundant <constant>V4L2_FLAG_MONOCHROME</constant> flag was removed,
-this information is available as described in <xref
-             linkend="format" />.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-input; the
-<structfield>assoc_audio</structfield> field and the
-<structfield>capability</structfield> field and its only flag
-<constant>V4L2_INPUT_CAP_AUDIO</constant> was replaced by the new
-<structfield>audioset</structfield> field. Instead of linking one
-video input to one audio input this field reports all audio inputs
-this video input combines with.</para>
-
-         <para>New fields are <structfield>tuner</structfield>
-(reversing the former link from tuners to video inputs),
-<structfield>std</structfield> and
-<structfield>status</structfield>.</para>
-
-         <para>Accordingly &v4l2-output; lost its
-<structfield>capability</structfield> and
-<structfield>assoc_audio</structfield> fields.
-<structfield>audioset</structfield>,
-<structfield>modulator</structfield> and
-<structfield>std</structfield> where added instead.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &v4l2-audio; field
-<structfield>audio</structfield> was renamed to
-<structfield>index</structfield>, for consistency with other
-structures. A new capability flag
-<constant>V4L2_AUDCAP_STEREO</constant> was added to indicated if the
-audio input in question supports stereo sound.
-<constant>V4L2_AUDCAP_EFFECTS</constant> and the corresponding
-<constant>V4L2_AUDMODE</constant> flags where removed. This can be
-easily implemented using controls. (However the same applies to AVL
-which is still there.)</para>
-
-         <para>Again for consistency the &v4l2-audioout; field
-<structfield>audio</structfield> was renamed to
-<structfield>index</structfield>.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &v4l2-tuner;
-<structfield>input</structfield> field was replaced by an
-<structfield>index</structfield> field, permitting devices with
-multiple tuners. The link between video inputs and tuners is now
-reversed, inputs point to their tuner. The
-<structfield>std</structfield> substructure became a
-simple set (more about this below) and moved into &v4l2-input;. A
-<structfield>type</structfield> field was added.</para>
-
-         <para>Accordingly in &v4l2-modulator; the
-<structfield>output</structfield> was replaced by an
-<structfield>index</structfield> field.</para>
-
-         <para>In &v4l2-frequency; the
-<structfield>port</structfield> field was replaced by a
-<structfield>tuner</structfield> field containing the respective tuner
-or modulator index number. A tuner <structfield>type</structfield>
-field was added and the <structfield>reserved</structfield> field
-became larger for future extensions (satellite tuners in
-particular).</para>
-       </listitem>
-
-       <listitem>
-         <para>The idea of completely transparent video standards was
-dropped. Experience showed that applications must be able to work with
-video standards beyond presenting the user a menu. Instead of
-enumerating supported standards with an ioctl applications can now
-refer to standards by &v4l2-std-id; and symbols defined in the
-<filename>videodev2.h</filename> header file. For details see <xref
-             linkend="standard" />. The &VIDIOC-G-STD; and
-&VIDIOC-S-STD; now take a pointer to this type as argument.
-&VIDIOC-QUERYSTD; was added to autodetect the received standard, if
-the hardware has this capability. In &v4l2-standard; an
-<structfield>index</structfield> field was added for &VIDIOC-ENUMSTD;.
-A &v4l2-std-id; field named <structfield>id</structfield> was added as
-machine readable identifier, also replacing the
-<structfield>transmission</structfield> field. The misleading
-<structfield>framerate</structfield> field was renamed
-to <structfield>frameperiod</structfield>. The now obsolete
-<structfield>colorstandard</structfield> information, originally
-needed to distguish between variations of standards, were
-removed.</para>
-
-         <para>Struct <structname>v4l2_enumstd</structname> ceased to
-be. &VIDIOC-ENUMSTD; now takes a pointer to a &v4l2-standard;
-directly. The information which standards are supported by a
-particular video input or output moved into &v4l2-input; and
-&v4l2-output; fields named <structfield>std</structfield>,
-respectively.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &v4l2-queryctrl; fields
-<structfield>category</structfield> and
-<structfield>group</structfield> did not catch on and/or were not
-implemented as expected and therefore removed.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &VIDIOC-TRY-FMT; ioctl was added to negotiate data
-formats as with &VIDIOC-S-FMT;, but without the overhead of
-programming the hardware and regardless of I/O in progress.</para>
-
-         <para>In &v4l2-format; the <structfield>fmt</structfield>
-union was extended to contain &v4l2-window;. All image format
-negotiations are now possible with <constant>VIDIOC_G_FMT</constant>,
-<constant>VIDIOC_S_FMT</constant> and
-<constant>VIDIOC_TRY_FMT</constant>; ioctl. The
-<constant>VIDIOC_G_WIN</constant> and
-<constant>VIDIOC_S_WIN</constant> ioctls to prepare for a video
-overlay were removed. The <structfield>type</structfield> field
-changed to type &v4l2-buf-type; and the buffer type names changed as
-follows.<informaltable>
-             <tgroup cols="2">
-               <thead>
-                 <row>
-                   <entry>Old defines</entry>
-                   <entry>&v4l2-buf-type;</entry>
-                 </row>
-               </thead>
-               <tbody valign="top">
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_CAPTURE</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_CODECIN</constant></entry>
-                   <entry>Omitted for now</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_CODECOUT</constant></entry>
-                   <entry>Omitted for now</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_EFFECTSIN</constant></entry>
-                   <entry>Omitted for now</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_EFFECTSIN2</constant></entry>
-                   <entry>Omitted for now</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_EFFECTSOUT</constant></entry>
-                   <entry>Omitted for now</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_VIDEOOUT</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_VBI_CAPTURE</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_BUF_TYPE_PRIVATE_BASE</constant></entry>
-                   <entry><constant>V4L2_BUF_TYPE_PRIVATE</constant></entry>
-                 </row>
-               </tbody>
-             </tgroup>
-           </informaltable></para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-fmtdesc; a &v4l2-buf-type; field named
-<structfield>type</structfield> was added as in &v4l2-format;. The
-<constant>VIDIOC_ENUM_FBUFFMT</constant> ioctl is no longer needed and
-was removed. These calls can be replaced by &VIDIOC-ENUM-FMT; with
-type <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-pix-format; the
-<structfield>depth</structfield> field was removed, assuming
-applications which recognize the format by its four-character-code
-already know the color depth, and others do not care about it. The
-same rationale lead to the removal of the
-<constant>V4L2_FMT_FLAG_COMPRESSED</constant> flag. The
-<constant>V4L2_FMT_FLAG_SWCONVECOMPRESSED</constant> flag was removed
-because drivers are not supposed to convert images in kernel space. A
-user library of conversion functions should be provided instead. The
-<constant>V4L2_FMT_FLAG_BYTESPERLINE</constant> flag was redundant.
-Applications can set the <structfield>bytesperline</structfield> field
-to zero to get a reasonable default. Since the remaining flags were
-replaced as well, the <structfield>flags</structfield> field itself
-was removed.</para>
-         <para>The interlace flags were replaced by a &v4l2-field;
-value in a newly added <structfield>field</structfield>
-field.<informaltable>
-             <tgroup cols="2">
-               <thead>
-                 <row>
-                   <entry>Old flag</entry>
-                   <entry>&v4l2-field;</entry>
-                 </row>
-               </thead>
-               <tbody valign="top">
-                 <row>
-                   <entry><constant>V4L2_FMT_FLAG_NOT_INTERLACED</constant></entry>
-                   <entry>?</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_FMT_FLAG_INTERLACED</constant>
-= <constant>V4L2_FMT_FLAG_COMBINED</constant></entry>
-                   <entry><constant>V4L2_FIELD_INTERLACED</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_FMT_FLAG_TOPFIELD</constant>
-= <constant>V4L2_FMT_FLAG_ODDFIELD</constant></entry>
-                   <entry><constant>V4L2_FIELD_TOP</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_FMT_FLAG_BOTFIELD</constant>
-= <constant>V4L2_FMT_FLAG_EVENFIELD</constant></entry>
-                   <entry><constant>V4L2_FIELD_BOTTOM</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_FIELD_SEQ_TB</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_FIELD_SEQ_BT</constant></entry>
-                 </row>
-                 <row>
-                   <entry><constant>-</constant></entry>
-                   <entry><constant>V4L2_FIELD_ALTERNATE</constant></entry>
-                 </row>
-               </tbody>
-             </tgroup>
-           </informaltable></para>
-
-         <para>The color space flags were replaced by a
-&v4l2-colorspace; value in a newly added
-<structfield>colorspace</structfield> field, where one of
-<constant>V4L2_COLORSPACE_SMPTE170M</constant>,
-<constant>V4L2_COLORSPACE_BT878</constant>,
-<constant>V4L2_COLORSPACE_470_SYSTEM_M</constant> or
-<constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant> replaces
-<constant>V4L2_FMT_CS_601YUV</constant>.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-requestbuffers; the
-<structfield>type</structfield> field was properly defined as
-&v4l2-buf-type;. Buffer types changed as mentioned above. A new
-<structfield>memory</structfield> field of type &v4l2-memory; was
-added to distinguish between I/O methods using buffers allocated
-by the driver or the application. See <xref linkend="io" /> for
-details.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-buffer; the <structfield>type</structfield>
-field was properly defined as &v4l2-buf-type;. Buffer types changed as
-mentioned above. A <structfield>field</structfield> field of type
-&v4l2-field; was added to indicate if a buffer contains a top or
-bottom field. The old field flags were removed. Since no unadjusted
-system time clock was added to the kernel as planned, the
-<structfield>timestamp</structfield> field changed back from type
-stamp_t, an unsigned 64 bit integer expressing the sample time in
-nanoseconds, to struct <structname>timeval</structname>. With the
-addition of a second memory mapping method the
-<structfield>offset</structfield> field moved into union
-<structfield>m</structfield>, and a new
-<structfield>memory</structfield> field of type &v4l2-memory; was
-added to distinguish between I/O methods. See <xref linkend="io" />
-for details.</para>
-
-         <para>The <constant>V4L2_BUF_REQ_CONTIG</constant>
-flag was used by the V4L compatibility layer, after changes to this
-code it was no longer needed. The
-<constant>V4L2_BUF_ATTR_DEVICEMEM</constant> flag would indicate if
-the buffer was indeed allocated in device memory rather than DMA-able
-system memory. It was barely useful and so was removed.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-framebuffer; the
-<structfield>base[3]</structfield> array anticipating double- and
-triple-buffering in off-screen video memory, however without defining
-a synchronization mechanism, was replaced by a single pointer. The
-<constant>V4L2_FBUF_CAP_SCALEUP</constant> and
-<constant>V4L2_FBUF_CAP_SCALEDOWN</constant> flags were removed.
-Applications can determine this capability more accurately using the
-new cropping and scaling interface. The
-<constant>V4L2_FBUF_CAP_CLIPPING</constant> flag was replaced by
-<constant>V4L2_FBUF_CAP_LIST_CLIPPING</constant> and
-<constant>V4L2_FBUF_CAP_BITMAP_CLIPPING</constant>.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-clip; the <structfield>x</structfield>,
-<structfield>y</structfield>, <structfield>width</structfield> and
-<structfield>height</structfield> field moved into a
-<structfield>c</structfield> substructure of type &v4l2-rect;. The
-<structfield>x</structfield> and <structfield>y</structfield> fields
-were renamed to <structfield>left</structfield> and
-<structfield>top</structfield>, &ie; offsets to a context dependent
-origin.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-window; the <structfield>x</structfield>,
-<structfield>y</structfield>, <structfield>width</structfield> and
-<structfield>height</structfield> field moved into a
-<structfield>w</structfield> substructure as above. A
-<structfield>field</structfield> field of type %v4l2-field; was added
-to distinguish between field and frame (interlaced) overlay.</para>
-       </listitem>
-
-       <listitem>
-         <para>The digital zoom interface, including struct
-<structname>v4l2_zoomcap</structname>, struct
-<structname>v4l2_zoom</structname>,
-<constant>V4L2_ZOOM_NONCAP</constant> and
-<constant>V4L2_ZOOM_WHILESTREAMING</constant> was replaced by a new
-cropping and scaling interface. The previously unused struct
-<structname>v4l2_cropcap</structname> and
-<structname>v4l2_crop</structname> where redefined for this purpose.
-See <xref linkend="crop" /> for details.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-vbi-format; the
-<structfield>SAMPLE_FORMAT</structfield> field now contains a
-four-character-code as used to identify video image formats and
-<constant>V4L2_PIX_FMT_GREY</constant> replaces the
-<constant>V4L2_VBI_SF_UBYTE</constant> define. The
-<structfield>reserved</structfield> field was extended.</para>
-       </listitem>
-
-       <listitem>
-         <para>In &v4l2-captureparm; the type of the
-<structfield>timeperframe</structfield> field changed from unsigned
-long to &v4l2-fract;. This allows the accurate expression of multiples
-of the NTSC-M frame rate 30000 / 1001. A new field
-<structfield>readbuffers</structfield> was added to control the driver
-behaviour in read I/O mode.</para>
-
-         <para>Similar changes were made to &v4l2-outputparm;.</para>
-       </listitem>
-
-       <listitem>
-         <para>The struct <structname>v4l2_performance</structname>
-and <constant>VIDIOC_G_PERF</constant> ioctl were dropped. Except when
-using the <link linkend="rw">read/write I/O method</link>, which is
-limited anyway, this information is already available to
-applications.</para>
-       </listitem>
-
-       <listitem>
-         <para>The example transformation from RGB to YCbCr color
-space in the old V4L2 documentation was inaccurate, this has been
-corrected in <xref linkend="pixfmt" />.<!-- 0.5670G should be
-0.587, and 127/112 != 255/224 --></para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 2003-06-19</title>
-
-      <orderedlist>
-       <listitem>
-         <para>A new capability flag
-<constant>V4L2_CAP_RADIO</constant> was added for radio devices. Prior
-to this change radio devices would identify solely by having exactly one
-tuner whose type field reads <constant>V4L2_TUNER_RADIO</constant>.</para>
-       </listitem>
-
-       <listitem>
-         <para>An optional driver access priority mechanism was
-added, see <xref linkend="app-pri" /> for details.</para>
-       </listitem>
-
-       <listitem>
-         <para>The audio input and output interface was found to be
-incomplete.</para>
-         <para>Previously the &VIDIOC-G-AUDIO;
-ioctl would enumerate the available audio inputs. An ioctl to
-determine the current audio input, if more than one combines with the
-current video input, did not exist. So
-<constant>VIDIOC_G_AUDIO</constant> was renamed to
-<constant>VIDIOC_G_AUDIO_OLD</constant>, this ioctl was removed on
-Kernel 2.6.39. The &VIDIOC-ENUMAUDIO; ioctl was added to enumerate
-audio inputs, while &VIDIOC-G-AUDIO; now reports the current audio
-input.</para>
-         <para>The same changes were made to &VIDIOC-G-AUDOUT; and
-&VIDIOC-ENUMAUDOUT;.</para>
-         <para>Until further the "videodev" module will automatically
-translate between the old and new ioctls, but drivers and applications
-must be updated to successfully compile again.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &VIDIOC-OVERLAY; ioctl was incorrectly defined with
-write-read parameter. It was changed to write-only, while the write-read
-version was renamed to <constant>VIDIOC_OVERLAY_OLD</constant>. The old
-ioctl was removed on Kernel 2.6.39. Until further the "videodev"
-kernel module will automatically translate to the new version, so drivers
-must be recompiled, but not applications.</para>
-       </listitem>
-
-       <listitem>
-         <para><xref linkend="overlay" /> incorrectly stated that
-clipping rectangles define regions where the video can be seen.
-Correct is that clipping rectangles define regions where
-<emphasis>no</emphasis> video shall be displayed and so the graphics
-surface can be seen.</para>
-       </listitem>
-
-       <listitem>
-         <para>The &VIDIOC-S-PARM; and &VIDIOC-S-CTRL; ioctls were
-defined with write-only parameter, inconsistent with other ioctls
-modifying their argument. They were changed to write-read, while a
-<constant>_OLD</constant> suffix was added to the write-only versions.
-The old ioctls were removed on Kernel 2.6.39. Drivers and
-applications assuming a constant parameter need an update.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 2003-11-05</title>
-      <orderedlist>
-       <listitem>
-         <para>In <xref linkend="pixfmt-rgb" /> the following pixel
-formats were incorrectly transferred from Bill Dirks' V4L2
-specification. Descriptions below refer to bytes in memory, in
-ascending address order.<informaltable>
-             <tgroup cols="3">
-               <thead>
-                 <row>
-                   <entry>Symbol</entry>
-                   <entry>In this document prior to revision
-0.5</entry>
-                   <entry>Corrected</entry>
-                 </row>
-               </thead>
-               <tbody valign="top">
-                 <row>
-                   <entry><constant>V4L2_PIX_FMT_RGB24</constant></entry>
-                   <entry>B, G, R</entry>
-                   <entry>R, G, B</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
-                   <entry>R, G, B</entry>
-                   <entry>B, G, R</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
-                   <entry>B, G, R, X</entry>
-                   <entry>R, G, B, X</entry>
-                 </row>
-                 <row>
-                   <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
-                   <entry>R, G, B, X</entry>
-                   <entry>B, G, R, X</entry>
-                 </row>
-               </tbody>
-             </tgroup>
-           </informaltable> The
-<constant>V4L2_PIX_FMT_BGR24</constant> example was always
-correct.</para>
-         <para>In <xref linkend="v4l-image-properties" /> the mapping
-of the V4L <constant>VIDEO_PALETTE_RGB24</constant> and
-<constant>VIDEO_PALETTE_RGB32</constant> formats to V4L2 pixel formats
-was accordingly corrected.</para>
-       </listitem>
-
-       <listitem>
-         <para>Unrelated to the fixes above, drivers may still
-interpret some V4L2 RGB pixel formats differently. These issues have
-yet to be addressed, for details see <xref
-             linkend="pixfmt-rgb" />.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.6, 2004-05-09</title>
-      <orderedlist>
-       <listitem>
-         <para>The &VIDIOC-CROPCAP; ioctl was incorrectly defined
-with read-only parameter. It is now defined as write-read ioctl, while
-the read-only version was renamed to
-<constant>VIDIOC_CROPCAP_OLD</constant>. The old ioctl was removed
-on Kernel 2.6.39.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.8</title>
-      <orderedlist>
-       <listitem>
-         <para>A new field <structfield>input</structfield> (former
-<structfield>reserved[0]</structfield>) was added to the &v4l2-buffer;
-structure. Purpose of this field is to alternate between video inputs
-(&eg; cameras) in step with the video capturing process. This function
-must be enabled with the new <constant>V4L2_BUF_FLAG_INPUT</constant>
-flag. The <structfield>flags</structfield> field is no longer
-read-only.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2004-08-01</title>
-
-      <orderedlist>
-       <listitem>
-         <para>The return value of the
-<xref linkend="func-open" /> function was incorrectly documented.</para>
-       </listitem>
-
-       <listitem>
-         <para>Audio output ioctls end in -AUDOUT, not -AUDIOOUT.</para>
-       </listitem>
-
-       <listitem>
-         <para>In the Current Audio Input example the
-<constant>VIDIOC_G_AUDIO</constant> ioctl took the wrong
-argument.</para>
-       </listitem>
-
-       <listitem>
-         <para>The documentation of the &VIDIOC-QBUF; and
-&VIDIOC-DQBUF; ioctls did not mention the &v4l2-buffer;
-<structfield>memory</structfield> field. It was also missing from
-examples. Also on the <constant>VIDIOC_DQBUF</constant> page the &EIO;
-was not documented.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.14</title>
-      <orderedlist>
-       <listitem>
-         <para>A new sliced VBI interface was added. It is documented
-in <xref linkend="sliced" /> and replaces the interface first
-proposed in V4L2 specification 0.8.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.15</title>
-      <orderedlist>
-       <listitem>
-         <para>The &VIDIOC-LOG-STATUS; ioctl was added.</para>
-       </listitem>
-
-       <listitem>
-         <para>New video standards
-<constant>V4L2_STD_NTSC_443</constant>,
-<constant>V4L2_STD_SECAM_LC</constant>,
-<constant>V4L2_STD_SECAM_DK</constant> (a set of SECAM D, K and K1),
-and <constant>V4L2_STD_ATSC</constant> (a set of
-<constant>V4L2_STD_ATSC_8_VSB</constant> and
-<constant>V4L2_STD_ATSC_16_VSB</constant>) were defined. Note the
-<constant>V4L2_STD_525_60</constant> set now includes
-<constant>V4L2_STD_NTSC_443</constant>. See also <xref
-             linkend="v4l2-std-id" />.</para>
-       </listitem>
-
-       <listitem>
-         <para>The <constant>VIDIOC_G_COMP</constant> and
-<constant>VIDIOC_S_COMP</constant> ioctl were renamed to
-<constant>VIDIOC_G_MPEGCOMP</constant> and
-<constant>VIDIOC_S_MPEGCOMP</constant> respectively. Their argument
-was replaced by a struct
-<structname>v4l2_mpeg_compression</structname> pointer. (The
-<constant>VIDIOC_G_MPEGCOMP</constant> and
-<constant>VIDIOC_S_MPEGCOMP</constant> ioctls where removed in Linux
-2.6.25.)</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2005-11-27</title>
-      <para>The capture example in <xref linkend="capture-example" />
-called the &VIDIOC-S-CROP; ioctl without checking if cropping is
-supported. In the video standard selection example in
-<xref linkend="standard" /> the &VIDIOC-S-STD; call used the wrong
-argument type.</para>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2006-01-10</title>
-      <orderedlist>
-       <listitem>
-         <para>The <constant>V4L2_IN_ST_COLOR_KILL</constant> flag in
-&v4l2-input; not only indicates if the color killer is enabled, but
-also if it is active. (The color killer disables color decoding when
-it detects no color in the video signal to improve the image
-quality.)</para>
-       </listitem>
-
-       <listitem>
-         <para>&VIDIOC-S-PARM; is a write-read ioctl, not write-only as
-stated on its reference page. The ioctl changed in 2003 as noted above.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2006-02-03</title>
-      <orderedlist>
-       <listitem>
-         <para>In &v4l2-captureparm; and &v4l2-outputparm; the
-<structfield>timeperframe</structfield> field gives the time in
-seconds, not microseconds.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2006-02-04</title>
-      <orderedlist>
-       <listitem>
-         <para>The <structfield>clips</structfield> field in
-&v4l2-window; must point to an array of &v4l2-clip;, not a linked
-list, because drivers ignore the struct
-<structname>v4l2_clip</structname>.<structfield>next</structfield>
-pointer.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.17</title>
-      <orderedlist>
-       <listitem>
-         <para>New video standard macros were added:
-<constant>V4L2_STD_NTSC_M_KR</constant> (NTSC M South Korea), and the
-sets <constant>V4L2_STD_MN</constant>,
-<constant>V4L2_STD_B</constant>, <constant>V4L2_STD_GH</constant> and
-<constant>V4L2_STD_DK</constant>. The
-<constant>V4L2_STD_NTSC</constant> and
-<constant>V4L2_STD_SECAM</constant> sets now include
-<constant>V4L2_STD_NTSC_M_KR</constant> and
-<constant>V4L2_STD_SECAM_LC</constant> respectively.</para>
-       </listitem>
-
-       <listitem>
-         <para>A new <constant>V4L2_TUNER_MODE_LANG1_LANG2</constant>
-was defined to record both languages of a bilingual program. The
-use of <constant>V4L2_TUNER_MODE_STEREO</constant> for this purpose
-is deprecated now. See the &VIDIOC-G-TUNER; section for
-details.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2006-09-23 (Draft 0.15)</title>
-      <orderedlist>
-       <listitem>
-         <para>In various places
-<constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant> and
-<constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant> of the sliced VBI
-interface were not mentioned along with other buffer types.</para>
-       </listitem>
-
-       <listitem>
-         <para>In <xref linkend="vidioc-g-audio" /> it was clarified
-that the &v4l2-audio; <structfield>mode</structfield> field is a flags
-field.</para>
-       </listitem>
-
-       <listitem>
-         <para><xref linkend="vidioc-querycap" /> did not mention the
-sliced VBI and radio capability flags.</para>
-       </listitem>
-
-       <listitem>
-         <para>In <xref linkend="vidioc-g-frequency" /> it was
-clarified that applications must initialize the tuner
-<structfield>type</structfield> field of &v4l2-frequency; before
-calling &VIDIOC-S-FREQUENCY;.</para>
-       </listitem>
-
-       <listitem>
-         <para>The <structfield>reserved</structfield> array
-in &v4l2-requestbuffers; has 2 elements, not 32.</para>
-       </listitem>
-
-       <listitem>
-         <para>In <xref linkend="output" /> and <xref
-             linkend="raw-vbi" /> the device file names
-<filename>/dev/vout</filename> which never caught on were replaced
-by <filename>/dev/video</filename>.</para>
-       </listitem>
-
-       <listitem>
-         <para>With Linux 2.6.15 the possible range for VBI device minor
-numbers was extended from 224-239 to 224-255. Accordingly device file names
-<filename>/dev/vbi0</filename> to <filename>/dev/vbi31</filename> are
-possible now.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.18</title>
-      <orderedlist>
-       <listitem>
-         <para>New ioctls &VIDIOC-G-EXT-CTRLS;, &VIDIOC-S-EXT-CTRLS;
-and &VIDIOC-TRY-EXT-CTRLS; were added, a flag to skip unsupported
-controls with &VIDIOC-QUERYCTRL;, new control types
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant> and
-<constant>V4L2_CTRL_TYPE_CTRL_CLASS</constant> (<xref
-             linkend="v4l2-ctrl-type" />), and new control flags
-<constant>V4L2_CTRL_FLAG_READ_ONLY</constant>,
-<constant>V4L2_CTRL_FLAG_UPDATE</constant>,
-<constant>V4L2_CTRL_FLAG_INACTIVE</constant> and
-<constant>V4L2_CTRL_FLAG_SLIDER</constant> (<xref
-             linkend="control-flags" />). See <xref
-             linkend="extended-controls" /> for details.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.19</title>
-      <orderedlist>
-       <listitem>
-         <para>In &v4l2-sliced-vbi-cap; a buffer type field was added
-replacing a reserved field. Note on architectures where the size of
-enum types differs from int types the size of the structure changed.
-The &VIDIOC-G-SLICED-VBI-CAP; ioctl was redefined from being read-only
-to write-read. Applications must initialize the type field and clear
-the reserved fields now. These changes may <emphasis>break the
-compatibility</emphasis> with older drivers and applications.</para>
-       </listitem>
-
-       <listitem>
-         <para>The ioctls &VIDIOC-ENUM-FRAMESIZES; and
-&VIDIOC-ENUM-FRAMEINTERVALS; were added.</para>
-       </listitem>
-
-       <listitem>
-         <para>A new pixel format <constant>V4L2_PIX_FMT_RGB444</constant> (<xref
-linkend="rgb-formats" />) was added.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 spec erratum 2006-10-12 (Draft 0.17)</title>
-      <orderedlist>
-       <listitem>
-         <para><constant>V4L2_PIX_FMT_HM12</constant> (<xref
-linkend="reserved-formats" />) is a YUV 4:2:0, not 4:2:2 format.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.21</title>
-      <orderedlist>
-       <listitem>
-         <para>The <filename>videodev2.h</filename> header file is
-now dual licensed under GNU General Public License version two or
-later, and under a 3-clause BSD-style license.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.22</title>
-      <orderedlist>
-       <listitem>
-         <para>Two new field orders
-         <constant>V4L2_FIELD_INTERLACED_TB</constant> and
-         <constant>V4L2_FIELD_INTERLACED_BT</constant> were
-         added. See <xref linkend="v4l2-field" /> for details.</para>
-       </listitem>
-
-       <listitem>
-         <para>Three new clipping/blending methods with a global or
-straight or inverted local alpha value were added to the video overlay
-interface. See the description of the &VIDIOC-G-FBUF; and
-&VIDIOC-S-FBUF; ioctls for details.</para>
-         <para>A new <structfield>global_alpha</structfield> field
-was added to <link
-linkend="v4l2-window"><structname>v4l2_window</structname></link>,
-extending the structure. This may <emphasis>break
-compatibility</emphasis> with applications using a struct
-<structname>v4l2_window</structname> directly. However the <link
-linkend="vidioc-g-fmt">VIDIOC_G/S/TRY_FMT</link> ioctls, which take a
-pointer to a <link linkend="v4l2-format">v4l2_format</link> parent
-structure with padding bytes at the end, are not affected.</para>
-       </listitem>
-
-       <listitem>
-         <para>The format of the <structfield>chromakey</structfield>
-field in &v4l2-window; changed from "host order RGB32" to a pixel
-value in the same format as the framebuffer. This may <emphasis>break
-compatibility</emphasis> with existing applications. Drivers
-supporting the "host order RGB32" format are not known.</para>
-       </listitem>
-
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.24</title>
-      <orderedlist>
-       <listitem>
-         <para>The pixel formats
-<constant>V4L2_PIX_FMT_PAL8</constant>,
-<constant>V4L2_PIX_FMT_YUV444</constant>,
-<constant>V4L2_PIX_FMT_YUV555</constant>,
-<constant>V4L2_PIX_FMT_YUV565</constant> and
-<constant>V4L2_PIX_FMT_YUV32</constant> were added.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.25</title>
-      <orderedlist>
-       <listitem>
-         <para>The pixel formats <link linkend="V4L2-PIX-FMT-Y16">
-<constant>V4L2_PIX_FMT_Y16</constant></link> and <link
-linkend="V4L2-PIX-FMT-SBGGR16">
-<constant>V4L2_PIX_FMT_SBGGR16</constant></link> were added.</para>
-       </listitem>
-       <listitem>
-         <para>New <link linkend="control">controls</link>
-<constant>V4L2_CID_POWER_LINE_FREQUENCY</constant>,
-<constant>V4L2_CID_HUE_AUTO</constant>,
-<constant>V4L2_CID_WHITE_BALANCE_TEMPERATURE</constant>,
-<constant>V4L2_CID_SHARPNESS</constant> and
-<constant>V4L2_CID_BACKLIGHT_COMPENSATION</constant> were added. The
-controls <constant>V4L2_CID_BLACK_LEVEL</constant>,
-<constant>V4L2_CID_WHITENESS</constant>,
-<constant>V4L2_CID_HCENTER</constant> and
-<constant>V4L2_CID_VCENTER</constant> were deprecated.
-</para>
-       </listitem>
-       <listitem>
-         <para>A <link linkend="camera-controls">Camera controls
-class</link> was added, with the new controls
-<constant>V4L2_CID_EXPOSURE_AUTO</constant>,
-<constant>V4L2_CID_EXPOSURE_ABSOLUTE</constant>,
-<constant>V4L2_CID_EXPOSURE_AUTO_PRIORITY</constant>,
-<constant>V4L2_CID_PAN_RELATIVE</constant>,
-<constant>V4L2_CID_TILT_RELATIVE</constant>,
-<constant>V4L2_CID_PAN_RESET</constant>,
-<constant>V4L2_CID_TILT_RESET</constant>,
-<constant>V4L2_CID_PAN_ABSOLUTE</constant>,
-<constant>V4L2_CID_TILT_ABSOLUTE</constant>,
-<constant>V4L2_CID_FOCUS_ABSOLUTE</constant>,
-<constant>V4L2_CID_FOCUS_RELATIVE</constant> and
-<constant>V4L2_CID_FOCUS_AUTO</constant>.</para>
-       </listitem>
-       <listitem>
-         <para>The <constant>VIDIOC_G_MPEGCOMP</constant> and
-<constant>VIDIOC_S_MPEGCOMP</constant> ioctls, which were superseded
-by the <link linkend="extended-controls">extended controls</link>
-interface in Linux 2.6.18, where finally removed from the
-<filename>videodev2.h</filename> header file.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.26</title>
-      <orderedlist>
-       <listitem>
-         <para>The pixel formats
-<constant>V4L2_PIX_FMT_Y16</constant> and
-<constant>V4L2_PIX_FMT_SBGGR16</constant> were added.</para>
-       </listitem>
-       <listitem>
-         <para>Added user controls
-<constant>V4L2_CID_CHROMA_AGC</constant> and
-<constant>V4L2_CID_COLOR_KILLER</constant>.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.27</title>
-      <orderedlist>
-       <listitem>
-         <para>The &VIDIOC-S-HW-FREQ-SEEK; ioctl and the
-<constant>V4L2_CAP_HW_FREQ_SEEK</constant> capability were added.</para>
-       </listitem>
-       <listitem>
-         <para>The pixel formats
-<constant>V4L2_PIX_FMT_YVYU</constant>,
-<constant>V4L2_PIX_FMT_PCA501</constant>,
-<constant>V4L2_PIX_FMT_PCA505</constant>,
-<constant>V4L2_PIX_FMT_PCA508</constant>,
-<constant>V4L2_PIX_FMT_PCA561</constant>,
-<constant>V4L2_PIX_FMT_SGBRG8</constant>,
-<constant>V4L2_PIX_FMT_PAC207</constant> and
-<constant>V4L2_PIX_FMT_PJPG</constant> were added.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.28</title>
-      <orderedlist>
-       <listitem>
-         <para>Added <constant>V4L2_MPEG_AUDIO_ENCODING_AAC</constant> and
-<constant>V4L2_MPEG_AUDIO_ENCODING_AC3</constant> MPEG audio encodings.</para>
-       </listitem>
-       <listitem>
-         <para>Added <constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC</constant> MPEG
-video encoding.</para>
-       </listitem>
-       <listitem>
-         <para>The pixel formats
-<constant>V4L2_PIX_FMT_SGRBG10</constant> and
-<constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant> were added.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 2.6.29</title>
-      <orderedlist>
-       <listitem>
-         <para>The <constant>VIDIOC_G_CHIP_IDENT</constant> ioctl was renamed
-to <constant>VIDIOC_G_CHIP_IDENT_OLD</constant> and &VIDIOC-DBG-G-CHIP-IDENT;
-was introduced in its place. The old struct <structname>v4l2_chip_ident</structname>
-was renamed to <structname id="v4l2-chip-ident-old">v4l2_chip_ident_old</structname>.</para>
-       </listitem>
-       <listitem>
-         <para>The pixel formats
-<constant>V4L2_PIX_FMT_VYUY</constant>,
-<constant>V4L2_PIX_FMT_NV16</constant> and
-<constant>V4L2_PIX_FMT_NV61</constant> were added.</para>
-       </listitem>
-       <listitem>
-         <para>Added camera controls
-<constant>V4L2_CID_ZOOM_ABSOLUTE</constant>,
-<constant>V4L2_CID_ZOOM_RELATIVE</constant>,
-<constant>V4L2_CID_ZOOM_CONTINUOUS</constant> and
-<constant>V4L2_CID_PRIVACY</constant>.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.30</title>
-      <orderedlist>
-       <listitem>
-         <para>New control flag <constant>V4L2_CTRL_FLAG_WRITE_ONLY</constant> was added.</para>
-       </listitem>
-       <listitem>
-         <para>New control <constant>V4L2_CID_COLORFX</constant> was added.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.32</title>
-      <orderedlist>
-       <listitem>
-         <para>In order to be easier to compare a V4L2 API and a kernel
-version, now V4L2 API is numbered using the Linux Kernel version numeration.</para>
-       </listitem>
-       <listitem>
-         <para>Finalized the RDS capture API. See <xref linkend="rds" /> for
-more information.</para>
-       </listitem>
-       <listitem>
-         <para>Added new capabilities for modulators and RDS encoders.</para>
-       </listitem>
-       <listitem>
-         <para>Add description for libv4l API.</para>
-       </listitem>
-       <listitem>
-         <para>Added support for string controls via new type <constant>V4L2_CTRL_TYPE_STRING</constant>.</para>
-       </listitem>
-       <listitem>
-         <para>Added <constant>V4L2_CID_BAND_STOP_FILTER</constant> documentation.</para>
-       </listitem>
-       <listitem>
-         <para>Added FM Modulator (FM TX) Extended Control Class: <constant>V4L2_CTRL_CLASS_FM_TX</constant> and their Control IDs.</para>
-       </listitem>
-       <listitem>
-         <para>Added Remote Controller chapter, describing the default Remote Controller mapping for media devices.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.33</title>
-      <orderedlist>
-       <listitem>
-         <para>Added support for Digital Video timings in order to support HDTV receivers and transmitters.</para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.34</title>
-      <orderedlist>
-       <listitem>
-         <para>Added
-<constant>V4L2_CID_IRIS_ABSOLUTE</constant> and
-<constant>V4L2_CID_IRIS_RELATIVE</constant> controls to the
-           <link linkend="camera-controls">Camera controls class</link>.
-         </para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.37</title>
-      <orderedlist>
-       <listitem>
-         <para>Remove the vtx (videotext/teletext) API. This API was no longer
-used and no hardware exists to verify the API. Nor were any userspace applications found
-that used it. It was originally scheduled for removal in 2.6.35.
-         </para>
-       </listitem>
-      </orderedlist>
-    </section>
-    <section>
-      <title>V4L2 in Linux 2.6.39</title>
-      <orderedlist>
-        <listitem>
-          <para>The old VIDIOC_*_OLD symbols and V4L1 support were removed.</para>
-        </listitem>
-        <listitem>
-          <para>Multi-planar API added. Does not affect the compatibility of
-          current drivers and applications. See
-          <link linkend="planar-apis">multi-planar API</link>
-          for details.</para>
-        </listitem>
-      </orderedlist>
-    </section>
-
-    <section id="other">
-      <title>Relation of V4L2 to other Linux multimedia APIs</title>
-
-      <section id="xvideo">
-        <title>X Video Extension</title>
-
-        <para>The X Video Extension (abbreviated XVideo or just Xv) is
-an extension of the X Window system, implemented for example by the
-XFree86 project. Its scope is similar to V4L2, an API to video capture
-and output devices for X clients. Xv allows applications to display
-live video in a window, send window contents to a TV output, and
-capture or output still images in XPixmaps<footnote>
-         <para>This is not implemented in XFree86.</para>
-       </footnote>. With their implementation XFree86 makes the
-extension available across many operating systems and
-architectures.</para>
-
-        <para>Because the driver is embedded into the X server Xv has a
-number of advantages over the V4L2 <link linkend="overlay">video
-overlay interface</link>. The driver can easily determine the overlay
-target, &ie; visible graphics memory or off-screen buffers for a
-destructive overlay. It can program the RAMDAC for a non-destructive
-overlay, scaling or color-keying, or the clipping functions of the
-video capture hardware, always in sync with drawing operations or
-windows moving or changing their stacking order.</para>
-
-        <para>To combine the advantages of Xv and V4L a special Xv
-driver exists in XFree86 and XOrg, just programming any overlay capable
-Video4Linux device it finds. To enable it
-<filename>/etc/X11/XF86Config</filename> must contain these lines:</para>
-        <para><screen>
-Section "Module"
-    Load "v4l"
-EndSection</screen></para>
-
-        <para>As of XFree86 4.2 this driver still supports only V4L
-ioctls, however it should work just fine with all V4L2 devices through
-the V4L2 backward-compatibility layer. Since V4L2 permits multiple
-opens it is possible (if supported by the V4L2 driver) to capture
-video while an X client requested video overlay. Restrictions of
-simultaneous capturing and overlay are discussed in <xref
-         linkend="overlay" /> apply.</para>
-
-        <para>Only marginally related to V4L2, XFree86 extended Xv to
-support hardware YUV to RGB conversion and scaling for faster video
-playback, and added an interface to MPEG-2 decoding hardware. This API
-is useful to display images captured with V4L2 devices.</para>
-      </section>
-
-      <section>
-        <title>Digital Video</title>
-
-        <para>V4L2 does not support digital terrestrial, cable or
-satellite broadcast. A separate project aiming at digital receivers
-exists. You can find its homepage at <ulink
-url="http://linuxtv.org">http://linuxtv.org</ulink>. The Linux DVB API
-has no connection to the V4L2 API except that drivers for hybrid
-hardware may support both.</para>
-      </section>
-
-      <section>
-        <title>Audio Interfaces</title>
-
-        <para>[to do - OSS/ALSA]</para>
-      </section>
-    </section>
-
-    <section id="experimental">
-      <title>Experimental API Elements</title>
-
-      <para>The following V4L2 API elements are currently experimental
-and may change in the future.</para>
-
-      <itemizedlist>
-        <listitem>
-         <para>Video Output Overlay (OSD) Interface, <xref
-           linkend="osd" />.</para>
-        </listitem>
-       <listitem>
-         <para><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant>,
-       &v4l2-buf-type;, <xref linkend="v4l2-buf-type" />.</para>
-        </listitem>
-        <listitem>
-         <para><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant>,
-&VIDIOC-QUERYCAP; ioctl, <xref linkend="device-capabilities" />.</para>
-        </listitem>
-        <listitem>
-         <para>&VIDIOC-ENUM-FRAMESIZES; and
-&VIDIOC-ENUM-FRAMEINTERVALS; ioctls.</para>
-        </listitem>
-        <listitem>
-         <para>&VIDIOC-G-ENC-INDEX; ioctl.</para>
-        </listitem>
-        <listitem>
-         <para>&VIDIOC-ENCODER-CMD; and &VIDIOC-TRY-ENCODER-CMD;
-ioctls.</para>
-        </listitem>
-        <listitem>
-         <para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
-ioctls.</para>
-        </listitem>
-        <listitem>
-         <para>&VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
-        </listitem>
-      </itemizedlist>
-    </section>
-
-    <section id="obsolete">
-      <title>Obsolete API Elements</title>
-
-      <para>The following V4L2 API elements were superseded by new
-interfaces and should not be implemented in new drivers.</para>
-
-      <itemizedlist>
-        <listitem>
-         <para><constant>VIDIOC_G_MPEGCOMP</constant> and
-<constant>VIDIOC_S_MPEGCOMP</constant> ioctls. Use Extended Controls,
-<xref linkend="extended-controls" />.</para>
-        </listitem>
-      </itemizedlist>
-    </section>
-  </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/controls.xml b/Documentation/DocBook/v4l/controls.xml
deleted file mode 100644 (file)
index a920ee8..0000000
+++ /dev/null
@@ -1,2103 +0,0 @@
-  <section id="control">
-    <title>User Controls</title>
-
-    <para>Devices typically have a number of user-settable controls
-such as brightness, saturation and so on, which would be presented to
-the user on a graphical user interface. But, different devices
-will have different controls available, and furthermore, the range of
-possible values, and the default value will vary from device to
-device. The control ioctls provide the information and a mechanism to
-create a nice user interface for these controls that will work
-correctly with any device.</para>
-
-    <para>All controls are accessed using an ID value. V4L2 defines
-several IDs for specific purposes. Drivers can also implement their
-own custom controls using <constant>V4L2_CID_PRIVATE_BASE</constant>
-and higher values. The pre-defined control IDs have the prefix
-<constant>V4L2_CID_</constant>, and are listed in <xref
-linkend="control-id" />. The ID is used when querying the attributes of
-a control, and when getting or setting the current value.</para>
-
-    <para>Generally applications should present controls to the user
-without assumptions about their purpose. Each control comes with a
-name string the user is supposed to understand. When the purpose is
-non-intuitive the driver writer should provide a user manual, a user
-interface plug-in or a driver specific panel application. Predefined
-IDs were introduced to change a few controls programmatically, for
-example to mute a device during a channel switch.</para>
-
-    <para>Drivers may enumerate different controls after switching
-the current video input or output, tuner or modulator, or audio input
-or output. Different in the sense of other bounds, another default and
-current value, step size or other menu items. A control with a certain
-<emphasis>custom</emphasis> ID can also change name and
-type.<footnote>
-       <para>It will be more convenient for applications if drivers
-make use of the <constant>V4L2_CTRL_FLAG_DISABLED</constant> flag, but
-that was never required.</para>
-      </footnote> Control values are stored globally, they do not
-change when switching except to stay within the reported bounds. They
-also do not change &eg; when the device is opened or closed, when the
-tuner radio frequency is changed or generally never without
-application request. Since V4L2 specifies no event mechanism, panel
-applications intended to cooperate with other panel applications (be
-they built into a larger application, as a TV viewer) may need to
-regularly poll control values to update their user
-interface.<footnote>
-       <para>Applications could call an ioctl to request events.
-After another process called &VIDIOC-S-CTRL; or another ioctl changing
-shared properties the &func-select; function would indicate
-readability until any ioctl (querying the properties) is
-called.</para>
-      </footnote></para>
-
-    <table pgwide="1" frame="none" id="control-id">
-      <title>Control IDs</title>
-      <tgroup cols="3">
-       &cs-def;
-       <thead>
-         <row>
-           <entry>ID</entry>
-           <entry>Type</entry>
-           <entry>Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CID_BASE</constant></entry>
-           <entry></entry>
-           <entry>First predefined ID, equal to
-<constant>V4L2_CID_BRIGHTNESS</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_USER_BASE</constant></entry>
-           <entry></entry>
-           <entry>Synonym of <constant>V4L2_CID_BASE</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_BRIGHTNESS</constant></entry>
-           <entry>integer</entry>
-           <entry>Picture brightness, or more precisely, the black
-level.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_CONTRAST</constant></entry>
-           <entry>integer</entry>
-           <entry>Picture contrast or luma gain.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_SATURATION</constant></entry>
-           <entry>integer</entry>
-           <entry>Picture color saturation or chroma gain.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_HUE</constant></entry>
-           <entry>integer</entry>
-           <entry>Hue or color balance.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_VOLUME</constant></entry>
-           <entry>integer</entry>
-           <entry>Overall audio volume. Note some drivers also
-provide an OSS or ALSA mixer interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_BALANCE</constant></entry>
-           <entry>integer</entry>
-           <entry>Audio stereo balance. Minimum corresponds to all
-the way left, maximum to right.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_BASS</constant></entry>
-           <entry>integer</entry>
-           <entry>Audio bass adjustment.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_TREBLE</constant></entry>
-           <entry>integer</entry>
-           <entry>Audio treble adjustment.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_MUTE</constant></entry>
-           <entry>boolean</entry>
-           <entry>Mute audio, &ie; set the volume to zero, however
-without affecting <constant>V4L2_CID_AUDIO_VOLUME</constant>. Like
-ALSA drivers, V4L2 drivers must mute at load time to avoid excessive
-noise. Actually the entire device should be reset to a low power
-consumption state.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUDIO_LOUDNESS</constant></entry>
-           <entry>boolean</entry>
-           <entry>Loudness mode (bass boost).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_BLACK_LEVEL</constant></entry>
-           <entry>integer</entry>
-           <entry>Another name for brightness (not a synonym of
-<constant>V4L2_CID_BRIGHTNESS</constant>). This control is deprecated
-and should not be used in new drivers and applications.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUTO_WHITE_BALANCE</constant></entry>
-           <entry>boolean</entry>
-           <entry>Automatic white balance (cameras).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_DO_WHITE_BALANCE</constant></entry>
-           <entry>button</entry>
-           <entry>This is an action control. When set (the value is
-ignored), the device will do a white balance and then hold the current
-setting. Contrast this with the boolean
-<constant>V4L2_CID_AUTO_WHITE_BALANCE</constant>, which, when
-activated, keeps adjusting the white balance.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_RED_BALANCE</constant></entry>
-           <entry>integer</entry>
-           <entry>Red chroma balance.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_BLUE_BALANCE</constant></entry>
-           <entry>integer</entry>
-           <entry>Blue chroma balance.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_GAMMA</constant></entry>
-           <entry>integer</entry>
-           <entry>Gamma adjust.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_WHITENESS</constant></entry>
-           <entry>integer</entry>
-           <entry>Whiteness for grey-scale devices. This is a synonym
-for <constant>V4L2_CID_GAMMA</constant>. This control is deprecated
-and should not be used in new drivers and applications.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_EXPOSURE</constant></entry>
-           <entry>integer</entry>
-           <entry>Exposure (cameras). [Unit?]</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_AUTOGAIN</constant></entry>
-           <entry>boolean</entry>
-           <entry>Automatic gain/exposure control.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_GAIN</constant></entry>
-           <entry>integer</entry>
-           <entry>Gain control.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_HFLIP</constant></entry>
-           <entry>boolean</entry>
-           <entry>Mirror the picture horizontally.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_VFLIP</constant></entry>
-           <entry>boolean</entry>
-           <entry>Mirror the picture vertically.</entry>
-         </row>
-       <row>
-         <entry><constant>V4L2_CID_HCENTER_DEPRECATED</constant> (formerly <constant>V4L2_CID_HCENTER</constant>)</entry>
-           <entry>integer</entry>
-           <entry>Horizontal image centering. This control is
-deprecated. New drivers and applications should use the <link
-linkend="camera-controls">Camera class controls</link>
-<constant>V4L2_CID_PAN_ABSOLUTE</constant>,
-<constant>V4L2_CID_PAN_RELATIVE</constant> and
-<constant>V4L2_CID_PAN_RESET</constant> instead.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_VCENTER_DEPRECATED</constant>
-           (formerly <constant>V4L2_CID_VCENTER</constant>)</entry>
-           <entry>integer</entry>
-           <entry>Vertical image centering. Centering is intended to
-<emphasis>physically</emphasis> adjust cameras. For image cropping see
-<xref linkend="crop" />, for clipping <xref linkend="overlay" />. This
-control is deprecated. New drivers and applications should use the
-<link linkend="camera-controls">Camera class controls</link>
-<constant>V4L2_CID_TILT_ABSOLUTE</constant>,
-<constant>V4L2_CID_TILT_RELATIVE</constant> and
-<constant>V4L2_CID_TILT_RESET</constant> instead.</entry>
-         </row>
-         <row id="v4l2-power-line-frequency">
-           <entry><constant>V4L2_CID_POWER_LINE_FREQUENCY</constant></entry>
-           <entry>enum</entry>
-           <entry>Enables a power line frequency filter to avoid
-flicker. Possible values for <constant>enum v4l2_power_line_frequency</constant> are:
-<constant>V4L2_CID_POWER_LINE_FREQUENCY_DISABLED</constant> (0),
-<constant>V4L2_CID_POWER_LINE_FREQUENCY_50HZ</constant> (1) and
-<constant>V4L2_CID_POWER_LINE_FREQUENCY_60HZ</constant> (2).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_HUE_AUTO</constant></entry>
-           <entry>boolean</entry>
-           <entry>Enables automatic hue control by the device. The
-effect of setting <constant>V4L2_CID_HUE</constant> while automatic
-hue control is enabled is undefined, drivers should ignore such
-request.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_WHITE_BALANCE_TEMPERATURE</constant></entry>
-           <entry>integer</entry>
-           <entry>This control specifies the white balance settings
-as a color temperature in Kelvin. A driver should have a minimum of
-2800 (incandescent) to 6500 (daylight). For more information about
-color temperature see <ulink
-url="http://en.wikipedia.org/wiki/Color_temperature">Wikipedia</ulink>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_SHARPNESS</constant></entry>
-           <entry>integer</entry>
-           <entry>Adjusts the sharpness filters in a camera. The
-minimum value disables the filters, higher values give a sharper
-picture.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_BACKLIGHT_COMPENSATION</constant></entry>
-           <entry>integer</entry>
-           <entry>Adjusts the backlight compensation in a camera. The
-minimum value disables backlight compensation.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_CHROMA_AGC</constant></entry>
-           <entry>boolean</entry>
-           <entry>Chroma automatic gain control.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_CHROMA_GAIN</constant></entry>
-           <entry>integer</entry>
-           <entry>Adjusts the Chroma gain control (for use when chroma AGC
-           is disabled).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_COLOR_KILLER</constant></entry>
-           <entry>boolean</entry>
-           <entry>Enable the color killer (&ie; force a black &amp; white image in case of a weak video signal).</entry>
-         </row>
-         <row id="v4l2-colorfx">
-           <entry><constant>V4L2_CID_COLORFX</constant></entry>
-           <entry>enum</entry>
-           <entry>Selects a color effect. Possible values for
-<constant>enum v4l2_colorfx</constant> are:
-<constant>V4L2_COLORFX_NONE</constant> (0),
-<constant>V4L2_COLORFX_BW</constant> (1),
-<constant>V4L2_COLORFX_SEPIA</constant> (2),
-<constant>V4L2_COLORFX_NEGATIVE</constant> (3),
-<constant>V4L2_COLORFX_EMBOSS</constant> (4),
-<constant>V4L2_COLORFX_SKETCH</constant> (5),
-<constant>V4L2_COLORFX_SKY_BLUE</constant> (6),
-<constant>V4L2_COLORFX_GRASS_GREEN</constant> (7),
-<constant>V4L2_COLORFX_SKIN_WHITEN</constant> (8) and
-<constant>V4L2_COLORFX_VIVID</constant> (9).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_ROTATE</constant></entry>
-           <entry>integer</entry>
-           <entry>Rotates the image by specified angle. Common angles are 90,
-           270 and 180. Rotating the image to 90 and 270 will reverse the height
-           and width of the display window. It is necessary to set the new height and
-           width of the picture using the &VIDIOC-S-FMT; ioctl according to
-           the rotation angle selected.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_BG_COLOR</constant></entry>
-           <entry>integer</entry>
-           <entry>Sets the background color on the current output device.
-           Background color needs to be specified in the RGB24 format. The
-           supplied 32 bit value is interpreted as bits 0-7 Red color information,
-           bits 8-15 Green color information, bits 16-23 Blue color
-           information and bits 24-31 must be zero.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_ILLUMINATORS_1</constant>
-               <constant>V4L2_CID_ILLUMINATORS_2</constant></entry>
-           <entry>boolean</entry>
-           <entry>Switch on or off the illuminator 1 or 2 of the device
-               (usually a microscope).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_LASTP1</constant></entry>
-           <entry></entry>
-           <entry>End of the predefined control IDs (currently
-<constant>V4L2_CID_ILLUMINATORS_2</constant> + 1).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CID_PRIVATE_BASE</constant></entry>
-           <entry></entry>
-           <entry>ID of the first custom (driver specific) control.
-Applications depending on particular custom controls should check the
-driver name and version, see <xref linkend="querycap" />.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Applications can enumerate the available controls with the
-&VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls, get and set a
-control value with the &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls.
-Drivers must implement <constant>VIDIOC_QUERYCTRL</constant>,
-<constant>VIDIOC_G_CTRL</constant> and
-<constant>VIDIOC_S_CTRL</constant> when the device has one or more
-controls, <constant>VIDIOC_QUERYMENU</constant> when it has one or
-more menu type controls.</para>
-
-    <example>
-      <title>Enumerating all controls</title>
-
-      <programlisting>
-&v4l2-queryctrl; queryctrl;
-&v4l2-querymenu; querymenu;
-
-static void
-enumerate_menu (void)
-{
-       printf ("  Menu items:\n");
-
-       memset (&amp;querymenu, 0, sizeof (querymenu));
-       querymenu.id = queryctrl.id;
-
-       for (querymenu.index = queryctrl.minimum;
-            querymenu.index &lt;= queryctrl.maximum;
-             querymenu.index++) {
-               if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &amp;querymenu)) {
-                       printf ("  %s\n", querymenu.name);
-               }
-       }
-}
-
-memset (&amp;queryctrl, 0, sizeof (queryctrl));
-
-for (queryctrl.id = V4L2_CID_BASE;
-     queryctrl.id &lt; V4L2_CID_LASTP1;
-     queryctrl.id++) {
-       if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
-               if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
-                       continue;
-
-               printf ("Control %s\n", queryctrl.name);
-
-               if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
-                       enumerate_menu ();
-       } else {
-               if (errno == EINVAL)
-                       continue;
-
-               perror ("VIDIOC_QUERYCTRL");
-               exit (EXIT_FAILURE);
-       }
-}
-
-for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
-     queryctrl.id++) {
-       if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
-               if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
-                       continue;
-
-               printf ("Control %s\n", queryctrl.name);
-
-               if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
-                       enumerate_menu ();
-       } else {
-               if (errno == EINVAL)
-                       break;
-
-               perror ("VIDIOC_QUERYCTRL");
-               exit (EXIT_FAILURE);
-       }
-}
-</programlisting>
-    </example>
-
-    <example>
-      <title>Changing controls</title>
-
-      <programlisting>
-&v4l2-queryctrl; queryctrl;
-&v4l2-control; control;
-
-memset (&amp;queryctrl, 0, sizeof (queryctrl));
-queryctrl.id = V4L2_CID_BRIGHTNESS;
-
-if (-1 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
-       if (errno != EINVAL) {
-               perror ("VIDIOC_QUERYCTRL");
-               exit (EXIT_FAILURE);
-       } else {
-               printf ("V4L2_CID_BRIGHTNESS is not supported\n");
-       }
-} else if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED) {
-       printf ("V4L2_CID_BRIGHTNESS is not supported\n");
-} else {
-       memset (&amp;control, 0, sizeof (control));
-       control.id = V4L2_CID_BRIGHTNESS;
-       control.value = queryctrl.default_value;
-
-       if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &amp;control)) {
-               perror ("VIDIOC_S_CTRL");
-               exit (EXIT_FAILURE);
-       }
-}
-
-memset (&amp;control, 0, sizeof (control));
-control.id = V4L2_CID_CONTRAST;
-
-if (0 == ioctl (fd, &VIDIOC-G-CTRL;, &amp;control)) {
-       control.value += 1;
-
-       /* The driver may clamp the value or return ERANGE, ignored here */
-
-       if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &amp;control)
-           &amp;&amp; errno != ERANGE) {
-               perror ("VIDIOC_S_CTRL");
-               exit (EXIT_FAILURE);
-       }
-/* Ignore if V4L2_CID_CONTRAST is unsupported */
-} else if (errno != EINVAL) {
-       perror ("VIDIOC_G_CTRL");
-       exit (EXIT_FAILURE);
-}
-
-control.id = V4L2_CID_AUDIO_MUTE;
-control.value = TRUE; /* silence */
-
-/* Errors ignored */
-ioctl (fd, VIDIOC_S_CTRL, &amp;control);
-</programlisting>
-    </example>
-  </section>
-
-  <section id="extended-controls">
-    <title>Extended Controls</title>
-
-    <section>
-      <title>Introduction</title>
-
-      <para>The control mechanism as originally designed was meant
-to be used for user settings (brightness, saturation, etc). However,
-it turned out to be a very useful model for implementing more
-complicated driver APIs where each driver implements only a subset of
-a larger API.</para>
-
-      <para>The MPEG encoding API was the driving force behind
-designing and implementing this extended control mechanism: the MPEG
-standard is quite large and the currently supported hardware MPEG
-encoders each only implement a subset of this standard. Further more,
-many parameters relating to how the video is encoded into an MPEG
-stream are specific to the MPEG encoding chip since the MPEG standard
-only defines the format of the resulting MPEG stream, not how the
-video is actually encoded into that format.</para>
-
-      <para>Unfortunately, the original control API lacked some
-features needed for these new uses and so it was extended into the
-(not terribly originally named) extended control API.</para>
-
-      <para>Even though the MPEG encoding API was the first effort
-to use the Extended Control API, nowadays there are also other classes
-of Extended Controls, such as Camera Controls and FM Transmitter Controls.
-The Extended Controls API as well as all Extended Controls classes are
-described in the following text.</para>
-    </section>
-
-    <section>
-      <title>The Extended Control API</title>
-
-      <para>Three new ioctls are available: &VIDIOC-G-EXT-CTRLS;,
-&VIDIOC-S-EXT-CTRLS; and &VIDIOC-TRY-EXT-CTRLS;. These ioctls act on
-arrays of controls (as opposed to the &VIDIOC-G-CTRL; and
-&VIDIOC-S-CTRL; ioctls that act on a single control). This is needed
-since it is often required to atomically change several controls at
-once.</para>
-
-      <para>Each of the new ioctls expects a pointer to a
-&v4l2-ext-controls;. This structure contains a pointer to the control
-array, a count of the number of controls in that array and a control
-class. Control classes are used to group similar controls into a
-single class. For example, control class
-<constant>V4L2_CTRL_CLASS_USER</constant> contains all user controls
-(&ie; all controls that can also be set using the old
-<constant>VIDIOC_S_CTRL</constant> ioctl). Control class
-<constant>V4L2_CTRL_CLASS_MPEG</constant> contains all controls
-relating to MPEG encoding, etc.</para>
-
-      <para>All controls in the control array must belong to the
-specified control class. An error is returned if this is not the
-case.</para>
-
-      <para>It is also possible to use an empty control array (count
-== 0) to check whether the specified control class is
-supported.</para>
-
-      <para>The control array is a &v4l2-ext-control; array. The
-<structname>v4l2_ext_control</structname> structure is very similar to
-&v4l2-control;, except for the fact that it also allows for 64-bit
-values and pointers to be passed.</para>
-
-      <para>It is important to realize that due to the flexibility of
-controls it is necessary to check whether the control you want to set
-actually is supported in the driver and what the valid range of values
-is. So use the &VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls to
-check this. Also note that it is possible that some of the menu
-indices in a control of type <constant>V4L2_CTRL_TYPE_MENU</constant>
-may not be supported (<constant>VIDIOC_QUERYMENU</constant> will
-return an error). A good example is the list of supported MPEG audio
-bitrates. Some drivers only support one or two bitrates, others
-support a wider range.</para>
-    </section>
-
-    <section>
-      <title>Enumerating Extended Controls</title>
-
-      <para>The recommended way to enumerate over the extended
-controls is by using &VIDIOC-QUERYCTRL; in combination with the
-<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> flag:</para>
-
-      <informalexample>
-       <programlisting>
-&v4l2-queryctrl; qctrl;
-
-qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
-while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
-       /* ... */
-       qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
-}
-</programlisting>
-      </informalexample>
-
-      <para>The initial control ID is set to 0 ORed with the
-<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> flag. The
-<constant>VIDIOC_QUERYCTRL</constant> ioctl will return the first
-control with a higher ID than the specified one. When no such controls
-are found an error is returned.</para>
-
-      <para>If you want to get all controls within a specific control
-class, then you can set the initial
-<structfield>qctrl.id</structfield> value to the control class and add
-an extra check to break out of the loop when a control of another
-control class is found:</para>
-
-      <informalexample>
-       <programlisting>
-qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL;
-while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
-       if (V4L2_CTRL_ID2CLASS (qctrl.id) != V4L2_CTRL_CLASS_MPEG)
-               break;
-               /* ... */
-               qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
-       }
-</programlisting>
-      </informalexample>
-
-      <para>The 32-bit <structfield>qctrl.id</structfield> value is
-subdivided into three bit ranges: the top 4 bits are reserved for
-flags (&eg; <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>) and are not
-actually part of the ID. The remaining 28 bits form the control ID, of
-which the most significant 12 bits define the control class and the
-least significant 16 bits identify the control within the control
-class. It is guaranteed that these last 16 bits are always non-zero
-for controls. The range of 0x1000 and up are reserved for
-driver-specific controls. The macro
-<constant>V4L2_CTRL_ID2CLASS(id)</constant> returns the control class
-ID based on a control ID.</para>
-
-      <para>If the driver does not support extended controls, then
-<constant>VIDIOC_QUERYCTRL</constant> will fail when used in
-combination with <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>. In
-that case the old method of enumerating control should be used (see
-1.8). But if it is supported, then it is guaranteed to enumerate over
-all controls, including driver-private controls.</para>
-    </section>
-
-    <section>
-      <title>Creating Control Panels</title>
-
-      <para>It is possible to create control panels for a graphical
-user interface where the user can select the various controls.
-Basically you will have to iterate over all controls using the method
-described above. Each control class starts with a control of type
-<constant>V4L2_CTRL_TYPE_CTRL_CLASS</constant>.
-<constant>VIDIOC_QUERYCTRL</constant> will return the name of this
-control class which can be used as the title of a tab page within a
-control panel.</para>
-
-      <para>The flags field of &v4l2-queryctrl; also contains hints on
-the behavior of the control. See the &VIDIOC-QUERYCTRL; documentation
-for more details.</para>
-    </section>
-
-    <section id="mpeg-controls">
-      <title>MPEG Control Reference</title>
-
-      <para>Below all controls within the MPEG control class are
-described. First the generic controls, then controls specific for
-certain hardware.</para>
-
-      <section>
-       <title>Generic MPEG Controls</title>
-
-       <table pgwide="1" frame="none" id="mpeg-control-id">
-         <title>MPEG Control IDs</title>
-         <tgroup cols="4">
-           <colspec colname="c1" colwidth="1*" />
-           <colspec colname="c2" colwidth="6*" />
-           <colspec colname="c3" colwidth="2*" />
-           <colspec colname="c4" colwidth="6*" />
-           <spanspec namest="c1" nameend="c2" spanname="id" />
-           <spanspec namest="c2" nameend="c4" spanname="descr" />
-           <thead>
-             <row>
-               <entry spanname="id" align="left">ID</entry>
-               <entry align="left">Type</entry>
-             </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CLASS</constant>&nbsp;</entry>
-               <entry>class</entry>
-             </row><row><entry spanname="descr">The MPEG class
-descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
-description of this control class. This description can be used as the
-caption of a Tab page in a GUI, for example.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-stream-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_stream_type</entry>
-             </row><row><entry spanname="descr">The MPEG-1, -2 or -4
-output stream type. One cannot assume anything here. Each hardware
-MPEG encoder tends to support different subsets of the available MPEG
-stream types. The currently defined stream types are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_PS</constant>&nbsp;</entry>
-                     <entry>MPEG-2 program stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_TS</constant>&nbsp;</entry>
-                     <entry>MPEG-2 transport stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG1_SS</constant>&nbsp;</entry>
-                     <entry>MPEG-1 system stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_DVD</constant>&nbsp;</entry>
-                     <entry>MPEG-2 DVD-compatible stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG1_VCD</constant>&nbsp;</entry>
-                     <entry>MPEG-1 VCD-compatible stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD</constant>&nbsp;</entry>
-                     <entry>MPEG-2 SVCD-compatible stream</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_PMT</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Program Map Table
-Packet ID for the MPEG transport stream (default 16)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_AUDIO</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Audio Packet ID for
-the MPEG transport stream (default 256)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_VIDEO</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Video Packet ID for
-the MPEG transport stream (default 260)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_PCR</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Packet ID for the
-MPEG transport stream carrying PCR fields (default 259)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PES_ID_AUDIO</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Audio ID for MPEG
-PES</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PES_ID_VIDEO</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Video ID for MPEG
-PES</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-stream-vbi-fmt">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_VBI_FMT</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_stream_vbi_fmt</entry>
-             </row><row><entry spanname="descr">Some cards can embed
-VBI data (&eg; Closed Caption, Teletext) into the MPEG stream. This
-control selects whether VBI data should be embedded, and if so, what
-embedding method should be used. The list of possible VBI formats
-depends on the driver. The currently defined VBI format types
-are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_VBI_FMT_NONE</constant>&nbsp;</entry>
-                     <entry>No VBI in the MPEG stream</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant>&nbsp;</entry>
-                     <entry>VBI in private packets, IVTV format (documented
-in the kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.vbi</filename>)</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-sampling-freq">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_sampling_freq</entry>
-             </row><row><entry spanname="descr">MPEG Audio sampling
-frequency. Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100</constant>&nbsp;</entry>
-                     <entry>44.1 kHz</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000</constant>&nbsp;</entry>
-                     <entry>48 kHz</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000</constant>&nbsp;</entry>
-                     <entry>32 kHz</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-encoding">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_ENCODING</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_encoding</entry>
-             </row><row><entry spanname="descr">MPEG Audio encoding.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_1</constant>&nbsp;</entry>
-                     <entry>MPEG-1/2 Layer I encoding</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_2</constant>&nbsp;</entry>
-                     <entry>MPEG-1/2 Layer II encoding</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_3</constant>&nbsp;</entry>
-                     <entry>MPEG-1/2 Layer III encoding</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_AAC</constant>&nbsp;</entry>
-                     <entry>MPEG-2/4 AAC (Advanced Audio Coding)</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_ENCODING_AC3</constant>&nbsp;</entry>
-                     <entry>AC-3 aka ATSC A/52 encoding</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-l1-bitrate">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L1_BITRATE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_l1_bitrate</entry>
-             </row><row><entry spanname="descr">MPEG-1/2 Layer I bitrate.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_32K</constant>&nbsp;</entry>
-                     <entry>32 kbit/s</entry></row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_64K</constant>&nbsp;</entry>
-                     <entry>64 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_96K</constant>&nbsp;</entry>
-                     <entry>96 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_128K</constant>&nbsp;</entry>
-                     <entry>128 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_160K</constant>&nbsp;</entry>
-                     <entry>160 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_192K</constant>&nbsp;</entry>
-                     <entry>192 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_224K</constant>&nbsp;</entry>
-                     <entry>224 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_256K</constant>&nbsp;</entry>
-                     <entry>256 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_288K</constant>&nbsp;</entry>
-                     <entry>288 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_320K</constant>&nbsp;</entry>
-                     <entry>320 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_352K</constant>&nbsp;</entry>
-                     <entry>352 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_384K</constant>&nbsp;</entry>
-                     <entry>384 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_416K</constant>&nbsp;</entry>
-                     <entry>416 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_448K</constant>&nbsp;</entry>
-                     <entry>448 kbit/s</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-l2-bitrate">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L2_BITRATE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_l2_bitrate</entry>
-             </row><row><entry spanname="descr">MPEG-1/2 Layer II bitrate.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_32K</constant>&nbsp;</entry>
-                     <entry>32 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_48K</constant>&nbsp;</entry>
-                     <entry>48 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_56K</constant>&nbsp;</entry>
-                     <entry>56 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_64K</constant>&nbsp;</entry>
-                     <entry>64 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_80K</constant>&nbsp;</entry>
-                     <entry>80 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_96K</constant>&nbsp;</entry>
-                     <entry>96 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_112K</constant>&nbsp;</entry>
-                     <entry>112 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_128K</constant>&nbsp;</entry>
-                     <entry>128 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_160K</constant>&nbsp;</entry>
-                     <entry>160 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_192K</constant>&nbsp;</entry>
-                     <entry>192 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_224K</constant>&nbsp;</entry>
-                     <entry>224 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_256K</constant>&nbsp;</entry>
-                     <entry>256 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_320K</constant>&nbsp;</entry>
-                     <entry>320 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_384K</constant>&nbsp;</entry>
-                     <entry>384 kbit/s</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-l3-bitrate">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L3_BITRATE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_l3_bitrate</entry>
-             </row><row><entry spanname="descr">MPEG-1/2 Layer III bitrate.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_32K</constant>&nbsp;</entry>
-                     <entry>32 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_40K</constant>&nbsp;</entry>
-                     <entry>40 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_48K</constant>&nbsp;</entry>
-                     <entry>48 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_56K</constant>&nbsp;</entry>
-                     <entry>56 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_64K</constant>&nbsp;</entry>
-                     <entry>64 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_80K</constant>&nbsp;</entry>
-                     <entry>80 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_96K</constant>&nbsp;</entry>
-                     <entry>96 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_112K</constant>&nbsp;</entry>
-                     <entry>112 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_128K</constant>&nbsp;</entry>
-                     <entry>128 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_160K</constant>&nbsp;</entry>
-                     <entry>160 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_192K</constant>&nbsp;</entry>
-                     <entry>192 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_224K</constant>&nbsp;</entry>
-                     <entry>224 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_256K</constant>&nbsp;</entry>
-                     <entry>256 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_320K</constant>&nbsp;</entry>
-                     <entry>320 kbit/s</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_AAC_BITRATE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">AAC bitrate in bits per second.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-ac3-bitrate">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_AC3_BITRATE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_ac3_bitrate</entry>
-             </row><row><entry spanname="descr">AC-3 bitrate.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_32K</constant>&nbsp;</entry>
-                     <entry>32 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_40K</constant>&nbsp;</entry>
-                     <entry>40 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_48K</constant>&nbsp;</entry>
-                     <entry>48 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_56K</constant>&nbsp;</entry>
-                     <entry>56 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_64K</constant>&nbsp;</entry>
-                     <entry>64 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_80K</constant>&nbsp;</entry>
-                     <entry>80 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_96K</constant>&nbsp;</entry>
-                     <entry>96 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_112K</constant>&nbsp;</entry>
-                     <entry>112 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_128K</constant>&nbsp;</entry>
-                     <entry>128 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_160K</constant>&nbsp;</entry>
-                     <entry>160 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_192K</constant>&nbsp;</entry>
-                     <entry>192 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_224K</constant>&nbsp;</entry>
-                     <entry>224 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_256K</constant>&nbsp;</entry>
-                     <entry>256 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_320K</constant>&nbsp;</entry>
-                     <entry>320 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_384K</constant>&nbsp;</entry>
-                     <entry>384 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_448K</constant>&nbsp;</entry>
-                     <entry>448 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_512K</constant>&nbsp;</entry>
-                     <entry>512 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_576K</constant>&nbsp;</entry>
-                     <entry>576 kbit/s</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_640K</constant>&nbsp;</entry>
-                     <entry>640 kbit/s</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_mode</entry>
-             </row><row><entry spanname="descr">MPEG Audio mode.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_STEREO</constant>&nbsp;</entry>
-                     <entry>Stereo</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_JOINT_STEREO</constant>&nbsp;</entry>
-                     <entry>Joint Stereo</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_DUAL</constant>&nbsp;</entry>
-                     <entry>Bilingual</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_MONO</constant>&nbsp;</entry>
-                     <entry>Mono</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-mode-extension">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MODE_EXTENSION</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_mode_extension</entry>
-             </row><row><entry spanname="descr">Joint Stereo
-audio mode extension. In Layer I and II they indicate which subbands
-are in intensity stereo. All other subbands are coded in stereo. Layer
-III is not (yet) supported. Possible values
-are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4</constant>&nbsp;</entry>
-                     <entry>Subbands 4-31 in intensity stereo</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8</constant>&nbsp;</entry>
-                     <entry>Subbands 8-31 in intensity stereo</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12</constant>&nbsp;</entry>
-                     <entry>Subbands 12-31 in intensity stereo</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16</constant>&nbsp;</entry>
-                     <entry>Subbands 16-31 in intensity stereo</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-emphasis">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_EMPHASIS</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_emphasis</entry>
-             </row><row><entry spanname="descr">Audio Emphasis.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_NONE</constant>&nbsp;</entry>
-                     <entry>None</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS</constant>&nbsp;</entry>
-                     <entry>50/15 microsecond emphasis</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17</constant>&nbsp;</entry>
-                     <entry>CCITT J.17</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-audio-crc">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_CRC</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_audio_crc</entry>
-             </row><row><entry spanname="descr">CRC method. Possible
-values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_CRC_NONE</constant>&nbsp;</entry>
-                     <entry>None</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_AUDIO_CRC_CRC16</constant>&nbsp;</entry>
-                     <entry>16 bit parity check</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MUTE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Mutes the audio when
-capturing. This is not done by muting audio hardware, which can still
-produce a slight hiss, but in the encoder itself, guaranteeing a fixed
-and reproducible audio bitstream. 0 = unmuted, 1 = muted.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-encoding">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ENCODING</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_encoding</entry>
-             </row><row><entry spanname="descr">MPEG Video encoding
-method. Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_1</constant>&nbsp;</entry>
-                     <entry>MPEG-1 Video encoding</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_2</constant>&nbsp;</entry>
-                     <entry>MPEG-2 Video encoding</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC</constant>&nbsp;</entry>
-                     <entry>MPEG-4 AVC (H.264) Video encoding</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-aspect">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ASPECT</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_aspect</entry>
-             </row><row><entry spanname="descr">Video aspect.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_1x1</constant>&nbsp;</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_4x3</constant>&nbsp;</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_16x9</constant>&nbsp;</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_ASPECT_221x100</constant>&nbsp;</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_B_FRAMES</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Number of B-Frames
-(default 2)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_GOP_SIZE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">GOP size (default
-12)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_GOP_CLOSURE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">GOP closure (default
-1)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_PULLDOWN</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row><row><entry spanname="descr">Enable 3:2 pulldown
-(default 0)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-video-bitrate-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_video_bitrate_mode</entry>
-             </row><row><entry spanname="descr">Video bitrate mode.
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_BITRATE_MODE_VBR</constant>&nbsp;</entry>
-                     <entry>Variable bitrate</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_VIDEO_BITRATE_MODE_CBR</constant>&nbsp;</entry>
-                     <entry>Constant bitrate</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Video bitrate in bits
-per second.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE_PEAK</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Peak video bitrate in
-bits per second. Must be larger or equal to the average video bitrate.
-It is ignored if the video bitrate mode is set to constant
-bitrate.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">For every captured
-frame, skip this many subsequent frames (default 0).</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MUTE</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">"Mutes" the video to a
-fixed color when capturing. This is useful for testing, to produce a
-fixed video bitstream. 0 = unmuted, 1 = muted.</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MUTE_YUV</constant>&nbsp;</entry>
-               <entry>integer</entry>
-             </row><row><entry spanname="descr">Sets the "mute" color
-of the video. The supplied 32-bit integer is interpreted as follows (bit
-0 = least significant bit):</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry>Bit 0:7</entry>
-                     <entry>V chrominance information</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 8:15</entry>
-                     <entry>U chrominance information</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 16:23</entry>
-                     <entry>Y luminance information</entry>
-                   </row>
-                   <row>
-                     <entry>Bit 24:31</entry>
-                     <entry>Must be zero.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-           </tbody>
-         </tgroup>
-       </table>
-      </section>
-
-      <section>
-       <title>CX2341x MPEG Controls</title>
-
-       <para>The following MPEG class controls deal with MPEG
-encoding settings that are specific to the Conexant CX23415 and
-CX23416 MPEG encoding chips.</para>
-
-       <table pgwide="1" frame="none" id="cx2341x-control-id">
-         <title>CX2341x Control IDs</title>
-         <tgroup cols="4">
-           <colspec colname="c1" colwidth="1*" />
-           <colspec colname="c2" colwidth="6*" />
-           <colspec colname="c3" colwidth="2*" />
-           <colspec colname="c4" colwidth="6*" />
-           <spanspec namest="c1" nameend="c2" spanname="id" />
-           <spanspec namest="c2" nameend="c4" spanname="descr" />
-           <thead>
-             <row>
-               <entry spanname="id" align="left">ID</entry>
-               <entry align="left">Type</entry>
-             </row><row><entry spanname="descr" align="left">Description</entry>
-             </row>
-           </thead>
-           <tbody valign="top">
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-cx2341x-video-spatial-filter-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_spatial_filter_mode</entry>
-             </row><row><entry spanname="descr">Sets the Spatial
-Filter mode (default <constant>MANUAL</constant>). Possible values
-are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
-                     <entry>Choose the filter manually</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
-                     <entry>Choose the filter automatically</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-15)</entry>
-             </row><row><entry spanname="descr">The setting for the
-Spatial Filter. 0 = off, 15 = maximum. (Default is 0.)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="luma-spatial-filter-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</entry>
-             </row><row><entry spanname="descr">Select the algorithm
-to use for the Luma Spatial Filter (default
-<constant>1D_HOR</constant>). Possible values:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
-                     <entry>No filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
-                     <entry>One-dimensional horizontal</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT</constant>&nbsp;</entry>
-                     <entry>One-dimensional vertical</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE</constant>&nbsp;</entry>
-                     <entry>Two-dimensional separable</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE</constant>&nbsp;</entry>
-                     <entry>Two-dimensional symmetrical
-non-separable</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="chroma-spatial-filter-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</entry>
-             </row><row><entry spanname="descr">Select the algorithm
-for the Chroma Spatial Filter (default <constant>1D_HOR</constant>).
-Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
-                     <entry>No filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
-                     <entry>One-dimensional horizontal</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-cx2341x-video-temporal-filter-mode">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_temporal_filter_mode</entry>
-             </row><row><entry spanname="descr">Sets the Temporal
-Filter mode (default <constant>MANUAL</constant>). Possible values
-are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
-                     <entry>Choose the filter manually</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
-                     <entry>Choose the filter automatically</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-31)</entry>
-             </row><row><entry spanname="descr">The setting for the
-Temporal Filter. 0 = off, 31 = maximum. (Default is 8 for full-scale
-capturing and 0 for scaled capturing.)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row id="v4l2-mpeg-cx2341x-video-median-filter-type">
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE</constant>&nbsp;</entry>
-               <entry>enum&nbsp;v4l2_mpeg_cx2341x_video_median_filter_type</entry>
-             </row><row><entry spanname="descr">Median Filter Type
-(default <constant>OFF</constant>). Possible values are:</entry>
-             </row>
-             <row>
-               <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF</constant>&nbsp;</entry>
-                     <entry>No filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR</constant>&nbsp;</entry>
-                     <entry>Horizontal filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT</constant>&nbsp;</entry>
-                     <entry>Vertical filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT</constant>&nbsp;</entry>
-                     <entry>Horizontal and vertical filter</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG</constant>&nbsp;</entry>
-                     <entry>Diagonal filter</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold above which
-the luminance median filter is enabled (default 0)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold below which
-the luminance median filter is enabled (default 255)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold above which
-the chroma median filter is enabled (default 0)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
-               <entry>integer&nbsp;(0-255)</entry>
-             </row><row><entry spanname="descr">Threshold below which
-the chroma median filter is enabled (default 255)</entry>
-             </row>
-             <row><entry></entry></row>
-             <row>
-               <entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS</constant>&nbsp;</entry>
-               <entry>boolean</entry>
-             </row>
-             <row><entry spanname="descr">The CX2341X MPEG encoder
-can insert one empty MPEG-2 PES packet into the stream between every
-four video frames. The packet size is 2048 bytes, including the
-packet_start_code_prefix and stream_id fields. The stream_id is 0xBF
-(private stream 2). The payload consists of 0x00 bytes, to be filled
-in by the application. 0 = do not insert, 1 = insert packets.</entry>
-             </row>
-           </tbody>
-         </tgroup>
-       </table>
-      </section>
-    </section>
-
-    <section id="camera-controls">
-      <title>Camera Control Reference</title>
-
-      <para>The Camera class includes controls for mechanical (or
-equivalent digital) features of a device such as controllable lenses
-or sensors.</para>
-
-    <table pgwide="1" frame="none" id="camera-control-id">
-      <title>Camera Control IDs</title>
-      <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="6*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="6*" />
-       <spanspec namest="c1" nameend="c2" spanname="id" />
-       <spanspec namest="c2" nameend="c4" spanname="descr" />
-       <thead>
-         <row>
-           <entry spanname="id" align="left">ID</entry>
-           <entry align="left">Type</entry>
-         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row><entry></entry></row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_CAMERA_CLASS</constant>&nbsp;</entry>
-           <entry>class</entry>
-         </row><row><entry spanname="descr">The Camera class
-descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
-description of this control class.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row id="v4l2-exposure-auto-type">
-           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_AUTO</constant>&nbsp;</entry>
-           <entry>enum&nbsp;v4l2_exposure_auto_type</entry>
-         </row><row><entry spanname="descr">Enables automatic
-adjustments of the exposure time and/or iris aperture. The effect of
-manual changes of the exposure time or iris aperture while these
-features are enabled is undefined, drivers should ignore such
-requests. Possible values are:</entry>
-         </row>
-         <row>
-           <entrytbl spanname="descr" cols="2">
-             <tbody valign="top">
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_AUTO</constant>&nbsp;</entry>
-                     <entry>Automatic exposure time, automatic iris
-aperture.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_MANUAL</constant>&nbsp;</entry>
-                 <entry>Manual exposure time, manual iris.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_SHUTTER_PRIORITY</constant>&nbsp;</entry>
-                 <entry>Manual exposure time, auto iris.</entry>
-               </row>
-               <row>
-                 <entry><constant>V4L2_EXPOSURE_APERTURE_PRIORITY</constant>&nbsp;</entry>
-                 <entry>Auto exposure time, manual iris.</entry>
-               </row>
-             </tbody>
-           </entrytbl>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">Determines the exposure
-time of the camera sensor. The exposure time is limited by the frame
-interval. Drivers should interpret the values as 100 &micro;s units,
-where the value 1 stands for 1/10000th of a second, 10000 for 1 second
-and 100000 for 10 seconds.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_EXPOSURE_AUTO_PRIORITY</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row><row><entry spanname="descr">When
-<constant>V4L2_CID_EXPOSURE_AUTO</constant> is set to
-<constant>AUTO</constant> or <constant>APERTURE_PRIORITY</constant>,
-this control determines if the device may dynamically vary the frame
-rate. By default this feature is disabled (0) and the frame rate must
-remain constant.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PAN_RELATIVE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control turns the
-camera horizontally by the specified amount. The unit is undefined. A
-positive value moves the camera to the right (clockwise when viewed
-from above), a negative value to the left. A value of zero does not
-cause motion. This is a write-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TILT_RELATIVE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control turns the
-camera vertically by the specified amount. The unit is undefined. A
-positive value moves the camera up, a negative value down. A value of
-zero does not cause motion. This is a write-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PAN_RESET</constant>&nbsp;</entry>
-           <entry>button</entry>
-         </row><row><entry spanname="descr">When this control is set,
-the camera moves horizontally to the default position.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TILT_RESET</constant>&nbsp;</entry>
-           <entry>button</entry>
-         </row><row><entry spanname="descr">When this control is set,
-the camera moves vertically to the default position.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PAN_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control
-turns the camera horizontally to the specified position. Positive
-values move the camera to the right (clockwise when viewed from above),
-negative values to the left. Drivers should interpret the values as arc
-seconds, with valid values between -180 * 3600 and +180 * 3600
-inclusive.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TILT_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control
-turns the camera vertically to the specified position. Positive values
-move the camera up, negative values down. Drivers should interpret the
-values as arc seconds, with valid values between -180 * 3600 and +180
-* 3600 inclusive.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FOCUS_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control sets the
-focal point of the camera to the specified position. The unit is
-undefined. Positive values set the focus closer to the camera,
-negative values towards infinity.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FOCUS_RELATIVE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control moves the
-focal point of the camera by the specified amount. The unit is
-undefined. Positive values move the focus closer to the camera,
-negative values towards infinity. This is a write-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FOCUS_AUTO</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row><row><entry spanname="descr">Enables automatic focus
-adjustments. The effect of manual focus adjustments while this feature
-is enabled is undefined, drivers should ignore such requests.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_ZOOM_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">Specify the objective lens
-focal length as an absolute value. The zoom unit is driver-specific and its
-value should be a positive integer.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_ZOOM_RELATIVE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">Specify the objective lens
-focal length relatively to the current value. Positive values move the zoom
-lens group towards the telephoto direction, negative values towards the
-wide-angle direction. The zoom unit is driver-specific. This is a write-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_ZOOM_CONTINUOUS</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">Move the objective lens group
-at the specified speed until it reaches physical device limits or until an
-explicit request to stop the movement. A positive value moves the zoom lens
-group towards the telephoto direction. A value of zero stops the zoom lens
-group movement. A negative value moves the zoom lens group towards the
-wide-angle direction. The zoom speed unit is driver-specific.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_IRIS_ABSOLUTE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control sets the
-camera's aperture to the specified value. The unit is undefined.
-Larger values open the iris wider, smaller values close it.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_IRIS_RELATIVE</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">This control modifies the
-camera's aperture by the specified amount. The unit is undefined.
-Positive values open the iris one step further, negative values close
-it one step further. This is a write-only control.</entry>
-         </row>
-         <row><entry></entry></row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PRIVACY</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row><row><entry spanname="descr">Prevent video from being acquired
-by the camera. When this control is set to <constant>TRUE</constant> (1), no
-image can be captured by the camera. Common means to enforce privacy are
-mechanical obturation of the sensor and firmware image processing, but the
-device is not restricted to these methods. Devices that implement the privacy
-control must support read access and may support write access.</entry>
-         </row>
-
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_BAND_STOP_FILTER</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row><row><entry spanname="descr">Switch the band-stop filter of a
-camera sensor on or off, or specify its strength. Such band-stop filters can
-be used, for example, to filter out the fluorescent light component.</entry>
-         </row>
-         <row><entry></entry></row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-    <section id="fm-tx-controls">
-      <title>FM Transmitter Control Reference</title>
-
-      <para>The FM Transmitter (FM_TX) class includes controls for common features of
-FM transmissions capable devices. Currently this class includes parameters for audio
-compression, pilot tone generation, audio deviation limiter, RDS transmission and
-tuning power features.</para>
-
-      <table pgwide="1" frame="none" id="fm-tx-control-id">
-      <title>FM_TX Control IDs</title>
-
-      <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="6*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="6*" />
-       <spanspec namest="c1" nameend="c2" spanname="id" />
-       <spanspec namest="c2" nameend="c4" spanname="descr" />
-       <thead>
-         <row>
-           <entry spanname="id" align="left">ID</entry>
-           <entry align="left">Type</entry>
-         </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row><entry></entry></row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_FM_TX_CLASS</constant>&nbsp;</entry>
-           <entry>class</entry>
-         </row><row><entry spanname="descr">The FM_TX class
-descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
-description of this control class.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_DEVIATION</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Configures RDS signal frequency deviation level in Hz.
-The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_PI</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the RDS Programme Identification field
-for transmission.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_PTY</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the RDS Programme Type field for transmission.
-This encodes up to 31 pre-defined programme types.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_PS_NAME</constant>&nbsp;</entry>
-           <entry>string</entry>
-         </row>
-         <row><entry spanname="descr">Sets the Programme Service name (PS_NAME) for transmission.
-It is intended for static display on a receiver. It is the primary aid to listeners in programme service
-identification and selection.  In Annex E of <xref linkend="en50067" />, the RDS specification,
-there is a full description of the correct character encoding for Programme Service name strings.
-Also from RDS specification, PS is usually a single eight character text. However, it is also possible
-to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
-with steps of 8 characters. The result is it must always contain a string with size multiple of 8.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_RDS_TX_RADIO_TEXT</constant>&nbsp;</entry>
-           <entry>string</entry>
-         </row>
-         <row><entry spanname="descr">Sets the Radio Text info for transmission. It is a textual description of
-what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
-programme-related information or any other text. In these cases, RadioText should be used in addition to
-<constant>V4L2_CID_RDS_TX_PS_NAME</constant>. The encoding for Radio Text strings is also fully described
-in Annex E of <xref linkend="en50067" />. The length of Radio Text strings depends on which RDS Block is being
-used to transmit it, either 32 (2A block) or 64 (2B block).  However, it is also possible
-to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
-with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_ENABLED</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Enables or disables the audio deviation limiter feature.
-The limiter is useful when trying to maximize the audio volume, minimize receiver-generated
-distortion and prevent overmodulation.
-</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_RELEASE_TIME</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the audio deviation limiter feature release time.
-Unit is in useconds. Step and range are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_DEVIATION</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Configures audio frequency deviation level in Hz.
-The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_ENABLED</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Enables or disables the audio compression feature.
-This feature amplifies signals below the threshold by a fixed gain and compresses audio
-signals above the threshold by the ratio of Threshold/(Gain + Threshold).</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_GAIN</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the gain for audio compression feature. It is
-a dB value. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_THRESHOLD</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the threshold level for audio compression freature.
-It is a dB value. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the attack time for audio compression feature.
-It is a useconds value. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the release time for audio compression feature.
-It is a useconds value. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_ENABLED</constant>&nbsp;</entry>
-           <entry>boolean</entry>
-         </row>
-         <row><entry spanname="descr">Enables or disables the pilot tone generation feature.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_DEVIATION</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Configures pilot tone frequency deviation level. Unit is
-in Hz. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_FREQUENCY</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Configures pilot tone frequency value. Unit is
-in Hz. The range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TUNE_PREEMPHASIS</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row id="v4l2-preemphasis"><entry spanname="descr">Configures the pre-emphasis value for broadcasting.
-A pre-emphasis filter is applied to the broadcast to accentuate the high audio frequencies.
-Depending on the region, a time constant of either 50 or 75 useconds is used. The enum&nbsp;v4l2_preemphasis
-defines possible values for pre-emphasis. Here they are:</entry>
-       </row><row>
-       <entrytbl spanname="descr" cols="2">
-                 <tbody valign="top">
-                   <row>
-                     <entry><constant>V4L2_PREEMPHASIS_DISABLED</constant>&nbsp;</entry>
-                     <entry>No pre-emphasis is applied.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_PREEMPHASIS_50_uS</constant>&nbsp;</entry>
-                     <entry>A pre-emphasis of 50 uS is used.</entry>
-                   </row>
-                   <row>
-                     <entry><constant>V4L2_PREEMPHASIS_75_uS</constant>&nbsp;</entry>
-                     <entry>A pre-emphasis of 75 uS is used.</entry>
-                   </row>
-                 </tbody>
-               </entrytbl>
-
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TUNE_POWER_LEVEL</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">Sets the output power level for signal transmission.
-Unit is in dBuV. Range and step are driver-specific.</entry>
-         </row>
-         <row>
-           <entry spanname="id"><constant>V4L2_CID_TUNE_ANTENNA_CAPACITOR</constant>&nbsp;</entry>
-           <entry>integer</entry>
-         </row>
-         <row><entry spanname="descr">This selects the value of antenna tuning capacitor
-manually or automatically if set to zero. Unit, range and step are driver-specific.</entry>
-         </row>
-         <row><entry></entry></row>
-       </tbody>
-      </tgroup>
-      </table>
-
-<para>For more details about RDS specification, refer to
-<xref linkend="en50067" /> document, from CENELEC.</para>
-    </section>
-</section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "common.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/crop.gif b/Documentation/DocBook/v4l/crop.gif
deleted file mode 100644 (file)
index 3b9e7d8..0000000
Binary files a/Documentation/DocBook/v4l/crop.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/crop.pdf b/Documentation/DocBook/v4l/crop.pdf
deleted file mode 100644 (file)
index c9fb81c..0000000
Binary files a/Documentation/DocBook/v4l/crop.pdf and /dev/null differ
diff --git a/Documentation/DocBook/v4l/dev-capture.xml b/Documentation/DocBook/v4l/dev-capture.xml
deleted file mode 100644 (file)
index 2237c66..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-  <title>Video Capture Interface</title>
-
-  <para>Video capture devices sample an analog video signal and store
-the digitized images in memory. Today nearly all devices can capture
-at full 25 or 30 frames/second. With this interface applications can
-control the capture process and move images from the driver into user
-space.</para>
-
-  <para>Conventionally V4L2 video capture devices are accessed through
-character device special files named <filename>/dev/video</filename>
-and <filename>/dev/video0</filename> to
-<filename>/dev/video63</filename> with major number 81 and minor
-numbers 0 to 63. <filename>/dev/video</filename> is typically a
-symbolic link to the preferred video device. Note the same device
-files are used for video output devices.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the video capture interface set the
-<constant>V4L2_CAP_VIDEO_CAPTURE</constant> or
-<constant>V4L2_CAP_VIDEO_CAPTURE_MPLANE</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. As secondary device functions
-they may also support the <link linkend="overlay">video overlay</link>
-(<constant>V4L2_CAP_VIDEO_OVERLAY</constant>) and the <link
-linkend="raw-vbi">raw VBI capture</link>
-(<constant>V4L2_CAP_VBI_CAPTURE</constant>) interface. At least one of
-the read/write or streaming I/O methods must be supported. Tuners and
-audio inputs are optional.</para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>Video capture devices shall support <link
-linkend="audio">audio input</link>, <link
-linkend="tuner">tuner</link>, <link linkend="control">controls</link>,
-<link linkend="crop">cropping and scaling</link> and <link
-linkend="streaming-par">streaming parameter</link> ioctls as needed.
-The <link linkend="video">video input</link> and <link
-linkend="standard">video standard</link> ioctls must be supported by
-all video capture devices.</para>
-  </section>
-
-  <section>
-    <title>Image Format Negotiation</title>
-
-    <para>The result of a capture operation is determined by
-cropping and image format parameters. The former select an area of the
-video picture to capture, the latter how images are stored in memory,
-&ie; in RGB or YUV format, the number of bits per pixel or width and
-height. Together they also define how images are scaled in the
-process.</para>
-
-    <para>As usual these parameters are <emphasis>not</emphasis> reset
-at &func-open; time to permit Unix tool chains, programming a device
-and then reading from it as if it was a plain file. Well written V4L2
-applications ensure they really get what they want, including cropping
-and scaling.</para>
-
-    <para>Cropping initialization at minimum requires to reset the
-parameters to defaults. An example is given in <xref
-linkend="crop" />.</para>
-
-    <para>To query the current image format applications set the
-<structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> or
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant> and call the
-&VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
-the &v4l2-pix-format; <structfield>pix</structfield> or the
-&v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member of the
-<structfield>fmt</structfield> union.</para>
-
-    <para>To request different parameters applications set the
-<structfield>type</structfield> field of a &v4l2-format; as above and
-initialize all fields of the &v4l2-pix-format;
-<structfield>vbi</structfield> member of the
-<structfield>fmt</structfield> union, or better just modify the
-results of <constant>VIDIOC_G_FMT</constant>, and call the
-&VIDIOC-S-FMT; ioctl with a pointer to this structure. Drivers may
-adjust the parameters and finally return the actual parameters as
-<constant>VIDIOC_G_FMT</constant> does.</para>
-
-    <para>Like <constant>VIDIOC_S_FMT</constant> the
-&VIDIOC-TRY-FMT; ioctl can be used to learn about hardware limitations
-without disabling I/O or possibly time consuming hardware
-preparations.</para>
-
-    <para>The contents of &v4l2-pix-format; and &v4l2-pix-format-mplane;
-are discussed in <xref linkend="pixfmt" />. See also the specification of the
-<constant>VIDIOC_G_FMT</constant>, <constant>VIDIOC_S_FMT</constant>
-and <constant>VIDIOC_TRY_FMT</constant> ioctls for details. Video
-capture devices must implement both the
-<constant>VIDIOC_G_FMT</constant> and
-<constant>VIDIOC_S_FMT</constant> ioctl, even if
-<constant>VIDIOC_S_FMT</constant> ignores all requests and always
-returns default parameters as <constant>VIDIOC_G_FMT</constant> does.
-<constant>VIDIOC_TRY_FMT</constant> is optional.</para>
-  </section>
-
-  <section>
-    <title>Reading Images</title>
-
-    <para>A video capture device may support the <link
-linkend="rw">read() function</link> and/or streaming (<link
-linkend="mmap">memory mapping</link> or <link
-linkend="userp">user pointer</link>) I/O. See <xref
-linkend="io" /> for details.</para>
-  </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/dev-codec.xml b/Documentation/DocBook/v4l/dev-codec.xml
deleted file mode 100644 (file)
index 6e156dc..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-  <title>Codec Interface</title>
-
-  <note>
-    <title>Suspended</title>
-
-    <para>This interface has been be suspended from the V4L2 API
-implemented in Linux 2.6 until we have more experience with codec
-device interfaces.</para>
-  </note>
-
-  <para>A V4L2 codec can compress, decompress, transform, or otherwise
-convert video data from one format into another format, in memory.
-Applications send data to be converted to the driver through a
-&func-write; call, and receive the converted data through a
-&func-read; call. For efficiency a driver may also support streaming
-I/O.</para>
-
-  <para>[to do]</para>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/dev-effect.xml b/Documentation/DocBook/v4l/dev-effect.xml
deleted file mode 100644 (file)
index 9c243be..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-  <title>Effect Devices Interface</title>
-
-  <note>
-    <title>Suspended</title>
-
-    <para>This interface has been be suspended from the V4L2 API
-implemented in Linux 2.6 until we have more experience with effect
-device interfaces.</para>
-  </note>
-
-  <para>A V4L2 video effect device can do image effects, filtering, or
-combine two or more images or image streams. For example video
-transitions or wipes. Applications send data to be processed and
-receive the result data either with &func-read; and &func-write;
-functions, or through the streaming I/O mechanism.</para>
-
-  <para>[to do]</para>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/dev-event.xml b/Documentation/DocBook/v4l/dev-event.xml
deleted file mode 100644 (file)
index be5a98f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-  <title>Event Interface</title>
-
-  <para>The V4L2 event interface provides means for user to get
-  immediately notified on certain conditions taking place on a device.
-  This might include start of frame or loss of signal events, for
-  example.
-  </para>
-
-  <para>To receive events, the events the user is interested in first must
-  be subscribed using the &VIDIOC-SUBSCRIBE-EVENT; ioctl. Once an event is
-  subscribed, the events of subscribed types are dequeueable using the
-  &VIDIOC-DQEVENT; ioctl. Events may be unsubscribed using
-  VIDIOC_UNSUBSCRIBE_EVENT ioctl. The special event type V4L2_EVENT_ALL may
-  be used to unsubscribe all the events the driver supports.</para>
-
-  <para>The event subscriptions and event queues are specific to file
-  handles. Subscribing an event on one file handle does not affect
-  other file handles.
-  </para>
-
-  <para>The information on dequeueable events is obtained by using select or
-  poll system calls on video devices. The V4L2 events use POLLPRI events on
-  poll system call and exceptions on select system call.  </para>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/dev-osd.xml b/Documentation/DocBook/v4l/dev-osd.xml
deleted file mode 100644 (file)
index c9a68a2..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-  <title>Video Output Overlay Interface</title>
-  <subtitle>Also known as On-Screen Display (OSD)</subtitle>
-
-  <note>
-    <title>Experimental</title>
-
-    <para>This is an <link linkend="experimental">experimental</link>
-interface and may change in the future.</para>
-  </note>
-
-  <para>Some video output devices can overlay a framebuffer image onto
-the outgoing video signal. Applications can set up such an overlay
-using this interface, which borrows structures and ioctls of the <link
-linkend="overlay">Video Overlay</link> interface.</para>
-
-  <para>The OSD function is accessible through the same character
-special file as the <link linkend="capture">Video Output</link> function.
-Note the default function of such a <filename>/dev/video</filename> device
-is video capturing or output. The OSD function is only available after
-calling the &VIDIOC-S-FMT; ioctl.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the <wordasword>Video Output
-Overlay</wordasword> interface set the
-<constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl.</para>
-  </section>
-
-  <section>
-    <title>Framebuffer</title>
-
-    <para>Contrary to the <wordasword>Video Overlay</wordasword>
-interface the framebuffer is normally implemented on the TV card and
-not the graphics card. On Linux it is accessible as a framebuffer
-device (<filename>/dev/fbN</filename>). Given a V4L2 device,
-applications can find the corresponding framebuffer device by calling
-the &VIDIOC-G-FBUF; ioctl. It returns, amongst other information, the
-physical address of the framebuffer in the
-<structfield>base</structfield> field of &v4l2-framebuffer;. The
-framebuffer device ioctl <constant>FBIOGET_FSCREENINFO</constant>
-returns the same address in the <structfield>smem_start</structfield>
-field of struct <structname>fb_fix_screeninfo</structname>. The
-<constant>FBIOGET_FSCREENINFO</constant> ioctl and struct
-<structname>fb_fix_screeninfo</structname> are defined in the
-<filename>linux/fb.h</filename> header file.</para>
-
-    <para>The width and height of the framebuffer depends on the
-current video standard. A V4L2 driver may reject attempts to change
-the video standard (or any other ioctl which would imply a framebuffer
-size change) with an &EBUSY; until all applications closed the
-framebuffer device.</para>
-
-    <example>
-      <title>Finding a framebuffer device for OSD</title>
-
-      <programlisting>
-#include &lt;linux/fb.h&gt;
-
-&v4l2-framebuffer; fbuf;
-unsigned int i;
-int fb_fd;
-
-if (-1 == ioctl (fd, VIDIOC_G_FBUF, &amp;fbuf)) {
-       perror ("VIDIOC_G_FBUF");
-       exit (EXIT_FAILURE);
-}
-
-for (i = 0; i &gt; 30; ++i) {
-       char dev_name[16];
-       struct fb_fix_screeninfo si;
-
-       snprintf (dev_name, sizeof (dev_name), "/dev/fb%u", i);
-
-       fb_fd = open (dev_name, O_RDWR);
-       if (-1 == fb_fd) {
-               switch (errno) {
-               case ENOENT: /* no such file */
-               case ENXIO:  /* no driver */
-                       continue;
-
-               default:
-                       perror ("open");
-                       exit (EXIT_FAILURE);
-               }
-       }
-
-       if (0 == ioctl (fb_fd, FBIOGET_FSCREENINFO, &amp;si)) {
-               if (si.smem_start == (unsigned long) fbuf.base)
-                       break;
-       } else {
-               /* Apparently not a framebuffer device. */
-       }
-
-       close (fb_fd);
-       fb_fd = -1;
-}
-
-/* fb_fd is the file descriptor of the framebuffer device
-   for the video output overlay, or -1 if no device was found. */
-</programlisting>
-    </example>
-  </section>
-
-  <section>
-    <title>Overlay Window and Scaling</title>
-
-    <para>The overlay is controlled by source and target rectangles.
-The source rectangle selects a subsection of the framebuffer image to
-be overlaid, the target rectangle an area in the outgoing video signal
-where the image will appear. Drivers may or may not support scaling,
-and arbitrary sizes and positions of these rectangles. Further drivers
-may support any (or none) of the clipping/blending methods defined for
-the <link linkend="overlay">Video Overlay</link> interface.</para>
-
-    <para>A &v4l2-window; defines the size of the source rectangle,
-its position in the framebuffer and the clipping/blending method to be
-used for the overlay. To get the current parameters applications set
-the <structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant> and call the
-&VIDIOC-G-FMT; ioctl. The driver fills the
-<structname>v4l2_window</structname> substructure named
-<structfield>win</structfield>. It is not possible to retrieve a
-previously programmed clipping list or bitmap.</para>
-
-    <para>To program the source rectangle applications set the
-<structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant>, initialize
-the <structfield>win</structfield> substructure and call the
-&VIDIOC-S-FMT; ioctl. The driver adjusts the parameters against
-hardware limits and returns the actual parameters as
-<constant>VIDIOC_G_FMT</constant> does. Like
-<constant>VIDIOC_S_FMT</constant>, the &VIDIOC-TRY-FMT; ioctl can be
-used to learn about driver capabilities without actually changing
-driver state. Unlike <constant>VIDIOC_S_FMT</constant> this also works
-after the overlay has been enabled.</para>
-
-    <para>A &v4l2-crop; defines the size and position of the target
-rectangle. The scaling factor of the overlay is implied by the width
-and height given in &v4l2-window; and &v4l2-crop;. The cropping API
-applies to <wordasword>Video Output</wordasword> and <wordasword>Video
-Output Overlay</wordasword> devices in the same way as to
-<wordasword>Video Capture</wordasword> and <wordasword>Video
-Overlay</wordasword> devices, merely reversing the direction of the
-data flow. For more information see <xref linkend="crop" />.</para>
-  </section>
-
-  <section>
-    <title>Enabling Overlay</title>
-
-    <para>There is no V4L2 ioctl to enable or disable the overlay,
-however the framebuffer interface of the driver may support the
-<constant>FBIOBLANK</constant> ioctl.</para>
-  </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/dev-output.xml b/Documentation/DocBook/v4l/dev-output.xml
deleted file mode 100644 (file)
index 919e22c..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-  <title>Video Output Interface</title>
-
-  <para>Video output devices encode stills or image sequences as
-analog video signal. With this interface applications can
-control the encoding process and move images from user space to
-the driver.</para>
-
-  <para>Conventionally V4L2 video output devices are accessed through
-character device special files named <filename>/dev/video</filename>
-and <filename>/dev/video0</filename> to
-<filename>/dev/video63</filename> with major number 81 and minor
-numbers 0 to 63. <filename>/dev/video</filename> is typically a
-symbolic link to the preferred video device. Note the same device
-files are used for video capture devices.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the video output interface set the
-<constant>V4L2_CAP_VIDEO_OUTPUT</constant> or
-<constant>V4L2_CAP_VIDEO_OUTPUT_MPLANE</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. As secondary device functions
-they may also support the <link linkend="raw-vbi">raw VBI
-output</link> (<constant>V4L2_CAP_VBI_OUTPUT</constant>) interface. At
-least one of the read/write or streaming I/O methods must be
-supported. Modulators and audio outputs are optional.</para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>Video output devices shall support <link
-linkend="audio">audio output</link>, <link
-linkend="tuner">modulator</link>, <link linkend="control">controls</link>,
-<link linkend="crop">cropping and scaling</link> and <link
-linkend="streaming-par">streaming parameter</link> ioctls as needed.
-The <link linkend="video">video output</link> and <link
-linkend="standard">video standard</link> ioctls must be supported by
-all video output devices.</para>
-  </section>
-
-  <section>
-    <title>Image Format Negotiation</title>
-
-    <para>The output is determined by cropping and image format
-parameters. The former select an area of the video picture where the
-image will appear, the latter how images are stored in memory, &ie; in
-RGB or YUV format, the number of bits per pixel or width and height.
-Together they also define how images are scaled in the process.</para>
-
-    <para>As usual these parameters are <emphasis>not</emphasis> reset
-at &func-open; time to permit Unix tool chains, programming a device
-and then writing to it as if it was a plain file. Well written V4L2
-applications ensure they really get what they want, including cropping
-and scaling.</para>
-
-    <para>Cropping initialization at minimum requires to reset the
-parameters to defaults. An example is given in <xref
-linkend="crop" />.</para>
-
-    <para>To query the current image format applications set the
-<structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> or
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant> and call the
-&VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
-the &v4l2-pix-format; <structfield>pix</structfield> or the
-&v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member of the
-<structfield>fmt</structfield> union.</para>
-
-    <para>To request different parameters applications set the
-<structfield>type</structfield> field of a &v4l2-format; as above and
-initialize all fields of the &v4l2-pix-format;
-<structfield>vbi</structfield> member of the
-<structfield>fmt</structfield> union, or better just modify the
-results of <constant>VIDIOC_G_FMT</constant>, and call the
-&VIDIOC-S-FMT; ioctl with a pointer to this structure. Drivers may
-adjust the parameters and finally return the actual parameters as
-<constant>VIDIOC_G_FMT</constant> does.</para>
-
-    <para>Like <constant>VIDIOC_S_FMT</constant> the
-&VIDIOC-TRY-FMT; ioctl can be used to learn about hardware limitations
-without disabling I/O or possibly time consuming hardware
-preparations.</para>
-
-    <para>The contents of &v4l2-pix-format; and &v4l2-pix-format-mplane;
-are discussed in <xref linkend="pixfmt" />. See also the specification of the
-<constant>VIDIOC_G_FMT</constant>, <constant>VIDIOC_S_FMT</constant>
-and <constant>VIDIOC_TRY_FMT</constant> ioctls for details. Video
-output devices must implement both the
-<constant>VIDIOC_G_FMT</constant> and
-<constant>VIDIOC_S_FMT</constant> ioctl, even if
-<constant>VIDIOC_S_FMT</constant> ignores all requests and always
-returns default parameters as <constant>VIDIOC_G_FMT</constant> does.
-<constant>VIDIOC_TRY_FMT</constant> is optional.</para>
-  </section>
-
-  <section>
-    <title>Writing Images</title>
-
-    <para>A video output device may support the <link
-linkend="rw">write() function</link> and/or streaming (<link
-linkend="mmap">memory mapping</link> or <link
-linkend="userp">user pointer</link>) I/O. See <xref
-linkend="io" /> for details.</para>
-  </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/dev-overlay.xml b/Documentation/DocBook/v4l/dev-overlay.xml
deleted file mode 100644 (file)
index 92513cf..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-  <title>Video Overlay Interface</title>
-  <subtitle>Also known as Framebuffer Overlay or Previewing</subtitle>
-
-  <para>Video overlay devices have the ability to genlock (TV-)video
-into the (VGA-)video signal of a graphics card, or to store captured
-images directly in video memory of a graphics card, typically with
-clipping. This can be considerable more efficient than capturing
-images and displaying them by other means. In the old days when only
-nuclear power plants needed cooling towers this used to be the only
-way to put live video into a window.</para>
-
-  <para>Video overlay devices are accessed through the same character
-special files as <link linkend="capture">video capture</link> devices.
-Note the default function of a <filename>/dev/video</filename> device
-is video capturing. The overlay function is only available after
-calling the &VIDIOC-S-FMT; ioctl.</para>
-
-    <para>The driver may support simultaneous overlay and capturing
-using the read/write and streaming I/O methods. If so, operation at
-the nominal frame rate of the video standard is not guaranteed. Frames
-may be directed away from overlay to capture, or one field may be used
-for overlay and the other for capture if the capture parameters permit
-this.</para>
-
-  <para>Applications should use different file descriptors for
-capturing and overlay. This must be supported by all drivers capable
-of simultaneous capturing and overlay. Optionally these drivers may
-also permit capturing and overlay with a single file descriptor for
-compatibility with V4L and earlier versions of V4L2.<footnote>
-       <para>A common application of two file descriptors is the
-XFree86 <link linkend="xvideo">Xv/V4L</link> interface driver and
-a V4L2 application. While the X server controls video overlay, the
-application can take advantage of memory mapping and DMA.</para>
-       <para>In the opinion of the designers of this API, no driver
-writer taking the efforts to support simultaneous capturing and
-overlay will restrict this ability by requiring a single file
-descriptor, as in V4L and earlier versions of V4L2. Making this
-optional means applications depending on two file descriptors need
-backup routines to be compatible with all drivers, which is
-considerable more work than using two fds in applications which do
-not. Also two fd's fit the general concept of one file descriptor for
-each logical stream. Hence as a complexity trade-off drivers
-<emphasis>must</emphasis> support two file descriptors and
-<emphasis>may</emphasis> support single fd operation.</para>
-      </footnote></para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the video overlay interface set the
-<constant>V4L2_CAP_VIDEO_OVERLAY</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. The overlay I/O method specified
-below must be supported. Tuners and audio inputs are optional.</para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>Video overlay devices shall support <link
-linkend="audio">audio input</link>, <link
-linkend="tuner">tuner</link>, <link linkend="control">controls</link>,
-<link linkend="crop">cropping and scaling</link> and <link
-linkend="streaming-par">streaming parameter</link> ioctls as needed.
-The <link linkend="video">video input</link> and <link
-linkend="standard">video standard</link> ioctls must be supported by
-all video overlay devices.</para>
-  </section>
-
-  <section>
-    <title>Setup</title>
-
-    <para>Before overlay can commence applications must program the
-driver with frame buffer parameters, namely the address and size of
-the frame buffer and the image format, for example RGB 5:6:5. The
-&VIDIOC-G-FBUF; and &VIDIOC-S-FBUF; ioctls are available to get
-and set these parameters, respectively. The
-<constant>VIDIOC_S_FBUF</constant> ioctl is privileged because it
-allows to set up DMA into physical memory, bypassing the memory
-protection mechanisms of the kernel. Only the superuser can change the
-frame buffer address and size. Users are not supposed to run TV
-applications as root or with SUID bit set. A small helper application
-with suitable privileges should query the graphics system and program
-the V4L2 driver at the appropriate time.</para>
-
-    <para>Some devices add the video overlay to the output signal
-of the graphics card. In this case the frame buffer is not modified by
-the video device, and the frame buffer address and pixel format are
-not needed by the driver. The <constant>VIDIOC_S_FBUF</constant> ioctl
-is not privileged. An application can check for this type of device by
-calling the <constant>VIDIOC_G_FBUF</constant> ioctl.</para>
-
-    <para>A driver may support any (or none) of five clipping/blending
-methods:<orderedlist>
-       <listitem>
-         <para>Chroma-keying displays the overlaid image only where
-pixels in the primary graphics surface assume a certain color.</para>
-       </listitem>
-       <listitem>
-         <para>A bitmap can be specified where each bit corresponds
-to a pixel in the overlaid image. When the bit is set, the
-corresponding video pixel is displayed, otherwise a pixel of the
-graphics surface.</para>
-       </listitem>
-       <listitem>
-         <para>A list of clipping rectangles can be specified. In
-these regions <emphasis>no</emphasis> video is displayed, so the
-graphics surface can be seen here.</para>
-       </listitem>
-       <listitem>
-         <para>The framebuffer has an alpha channel that can be used
-to clip or blend the framebuffer with the video.</para>
-       </listitem>
-       <listitem>
-         <para>A global alpha value can be specified to blend the
-framebuffer contents with video images.</para>
-       </listitem>
-      </orderedlist></para>
-
-    <para>When simultaneous capturing and overlay is supported and
-the hardware prohibits different image and frame buffer formats, the
-format requested first takes precedence. The attempt to capture
-(&VIDIOC-S-FMT;) or overlay (&VIDIOC-S-FBUF;) may fail with an
-&EBUSY; or return accordingly modified parameters..</para>
-  </section>
-
-  <section>
-    <title>Overlay Window</title>
-
-    <para>The overlaid image is determined by cropping and overlay
-window parameters. The former select an area of the video picture to
-capture, the latter how images are overlaid and clipped. Cropping
-initialization at minimum requires to reset the parameters to
-defaults. An example is given in <xref linkend="crop" />.</para>
-
-    <para>The overlay window is described by a &v4l2-window;. It
-defines the size of the image, its position over the graphics surface
-and the clipping to be applied. To get the current parameters
-applications set the <structfield>type</structfield> field of a
-&v4l2-format; to <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant> and
-call the &VIDIOC-G-FMT; ioctl. The driver fills the
-<structname>v4l2_window</structname> substructure named
-<structfield>win</structfield>. It is not possible to retrieve a
-previously programmed clipping list or bitmap.</para>
-
-    <para>To program the overlay window applications set the
-<structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, initialize the
-<structfield>win</structfield> substructure and call the
-&VIDIOC-S-FMT; ioctl. The driver adjusts the parameters against
-hardware limits and returns the actual parameters as
-<constant>VIDIOC_G_FMT</constant> does. Like
-<constant>VIDIOC_S_FMT</constant>, the &VIDIOC-TRY-FMT; ioctl can be
-used to learn about driver capabilities without actually changing
-driver state. Unlike <constant>VIDIOC_S_FMT</constant> this also works
-after the overlay has been enabled.</para>
-
-    <para>The scaling factor of the overlaid image is implied by the
-width and height given in &v4l2-window; and the size of the cropping
-rectangle. For more information see <xref linkend="crop" />.</para>
-
-    <para>When simultaneous capturing and overlay is supported and
-the hardware prohibits different image and window sizes, the size
-requested first takes precedence. The attempt to capture or overlay as
-well (&VIDIOC-S-FMT;) may fail with an &EBUSY; or return accordingly
-modified parameters.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-window">
-      <title>struct <structname>v4l2_window</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>&v4l2-rect;</entry>
-           <entry><structfield>w</structfield></entry>
-           <entry>Size and position of the window relative to the
-top, left corner of the frame buffer defined with &VIDIOC-S-FBUF;. The
-window can extend the frame buffer width and height, the
-<structfield>x</structfield> and <structfield>y</structfield>
-coordinates can be negative, and it can lie completely outside the
-frame buffer. The driver clips the window accordingly, or if that is
-not possible, modifies its size and/or position.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-field;</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry>Applications set this field to determine which
-video field shall be overlaid, typically one of
-<constant>V4L2_FIELD_ANY</constant> (0),
-<constant>V4L2_FIELD_TOP</constant>,
-<constant>V4L2_FIELD_BOTTOM</constant> or
-<constant>V4L2_FIELD_INTERLACED</constant>. Drivers may have to choose
-a different field order and return the actual setting here.</entry>
-           </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>chromakey</structfield></entry>
-           <entry>When chroma-keying has been negotiated with
-&VIDIOC-S-FBUF; applications set this field to the desired pixel value
-for the chroma key. The format is the same as the pixel format of the
-framebuffer (&v4l2-framebuffer;
-<structfield>fmt.pixelformat</structfield> field), with bytes in host
-order. E.&nbsp;g. for <link
-linkend="V4L2-PIX-FMT-BGR32"><constant>V4L2_PIX_FMT_BGR24</constant></link>
-the value should be 0xRRGGBB on a little endian, 0xBBGGRR on a big
-endian host.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-clip; *</entry>
-           <entry><structfield>clips</structfield></entry>
-           <entry>When chroma-keying has <emphasis>not</emphasis>
-been negotiated and &VIDIOC-G-FBUF; indicated this capability,
-applications can set this field to point to an array of
-clipping rectangles.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>Like the window coordinates
-<structfield>w</structfield>, clipping rectangles are defined relative
-to the top, left corner of the frame buffer. However clipping
-rectangles must not extend the frame buffer width and height, and they
-must not overlap. If possible applications should merge adjacent
-rectangles. Whether this must create x-y or y-x bands, or the order of
-rectangles, is not defined. When clip lists are not supported the
-driver ignores this field. Its contents after calling &VIDIOC-S-FMT;
-are undefined.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>clipcount</structfield></entry>
-           <entry>When the application set the
-<structfield>clips</structfield> field, this field must contain the
-number of clipping rectangles in the list. When clip lists are not
-supported the driver ignores this field, its contents after calling
-<constant>VIDIOC_S_FMT</constant> are undefined. When clip lists are
-supported but no clipping is desired this field must be set to
-zero.</entry>
-         </row>
-         <row>
-           <entry>void *</entry>
-           <entry><structfield>bitmap</structfield></entry>
-           <entry>When chroma-keying has
-<emphasis>not</emphasis> been negotiated and &VIDIOC-G-FBUF; indicated
-this capability, applications can set this field to point to a
-clipping bit mask.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>It must be of the same size
-as the window, <structfield>w.width</structfield> and
-<structfield>w.height</structfield>. Each bit corresponds to a pixel
-in the overlaid image, which is displayed only when the bit is
-<emphasis>set</emphasis>. Pixel coordinates translate to bits like:
-<programlisting>
-((__u8 *) <structfield>bitmap</structfield>)[<structfield>w.width</structfield> * y + x / 8] &amp; (1 &lt;&lt; (x &amp; 7))</programlisting></para><para>where <structfield>0</structfield> &le; x &lt;
-<structfield>w.width</structfield> and <structfield>0</structfield> &le;
-y &lt;<structfield>w.height</structfield>.<footnote>
-                 <para>Should we require
-             <structfield>w.width</structfield> to be a multiple of
-             eight?</para>
-               </footnote></para><para>When a clipping
-bit mask is not supported the driver ignores this field, its contents
-after calling &VIDIOC-S-FMT; are undefined. When a bit mask is supported
-but no clipping is desired this field must be set to
-<constant>NULL</constant>.</para><para>Applications need not create a
-clip list or bit mask. When they pass both, or despite negotiating
-chroma-keying, the results are undefined. Regardless of the chosen
-method, the clipping abilities of the hardware may be limited in
-quantity or quality. The results when these limits are exceeded are
-undefined.<footnote>
-                 <para>When the image is written into frame buffer
-memory it will be undesirable if the driver clips out less pixels
-than expected, because the application and graphics system are not
-aware these regions need to be refreshed. The driver should clip out
-more pixels or not write the image at all.</para>
-               </footnote></para></entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>global_alpha</structfield></entry>
-           <entry>The global alpha value used to blend the
-framebuffer with video images, if global alpha blending has been
-negotiated (<constant>V4L2_FBUF_FLAG_GLOBAL_ALPHA</constant>, see
-&VIDIOC-S-FBUF;, <xref linkend="framebuffer-flags" />).</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>Note this field was added in Linux 2.6.23, extending the structure. However
-the <link linkend="vidioc-g-fmt">VIDIOC_G/S/TRY_FMT</link> ioctls,
-which take a pointer to a <link
-linkend="v4l2-format">v4l2_format</link> parent structure with padding
-bytes at the end, are not affected.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-clip">
-      <title>struct <structname>v4l2_clip</structname><footnote>
-         <para>The X Window system defines "regions" which are
-vectors of struct BoxRec { short x1, y1, x2, y2; } with width = x2 -
-x1 and height = y2 - y1, so one cannot pass X11 clip lists
-directly.</para>
-       </footnote></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>&v4l2-rect;</entry>
-           <entry><structfield>c</structfield></entry>
-           <entry>Coordinates of the clipping rectangle, relative to
-the top, left corner of the frame buffer. Only window pixels
-<emphasis>outside</emphasis> all clipping rectangles are
-displayed.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-clip; *</entry>
-           <entry><structfield>next</structfield></entry>
-           <entry>Pointer to the next clipping rectangle, NULL when
-this is the last rectangle. Drivers ignore this field, it cannot be
-used to pass a linked list of clipping rectangles.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- NB for easier reading this table is duplicated
-    in the vidioc-cropcap chapter.-->
-
-    <table pgwide="1" frame="none" id="v4l2-rect">
-      <title>struct <structname>v4l2_rect</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>left</structfield></entry>
-           <entry>Horizontal offset of the top, left corner of the
-rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>top</structfield></entry>
-           <entry>Vertical offset of the top, left corner of the
-rectangle, in pixels. Offsets increase to the right and down.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the rectangle, in pixels. Width and
-height cannot be negative, the fields are signed for hysterical
-reasons. <!-- video4linux-list@redhat.com on 22 Oct 2002 subject
-"Re:[V4L][patches!] Re:v4l2/kernel-2.5" --></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-  <section>
-    <title>Enabling Overlay</title>
-
-    <para>To start or stop the frame buffer overlay applications call
-the &VIDIOC-OVERLAY; ioctl.</para>
-  </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/dev-radio.xml b/Documentation/DocBook/v4l/dev-radio.xml
deleted file mode 100644 (file)
index 73aa90b..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-  <title>Radio Interface</title>
-
-  <para>This interface is intended for AM and FM (analog) radio
-receivers and transmitters.</para>
-
-  <para>Conventionally V4L2 radio devices are accessed through
-character device special files named <filename>/dev/radio</filename>
-and <filename>/dev/radio0</filename> to
-<filename>/dev/radio63</filename> with major number 81 and minor
-numbers 64 to 127.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the radio interface set the
-<constant>V4L2_CAP_RADIO</constant> and
-<constant>V4L2_CAP_TUNER</constant> or
-<constant>V4L2_CAP_MODULATOR</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. Other combinations of
-capability flags are reserved for future extensions.</para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>Radio devices can support <link
-linkend="control">controls</link>, and must support the <link
-linkend="tuner">tuner or modulator</link> ioctls.</para>
-
-    <para>They do not support the video input or output, audio input
-or output, video standard, cropping and scaling, compression and
-streaming parameter, or overlay ioctls. All other ioctls and I/O
-methods are reserved for future extensions.</para>
-  </section>
-
-  <section>
-    <title>Programming</title>
-
-    <para>Radio devices may have a couple audio controls (as discussed
-in <xref linkend="control" />) such as a volume control, possibly custom
-controls. Further all radio devices have one tuner or modulator (these are
-discussed in <xref linkend="tuner" />) with index number zero to select
-the radio frequency and to determine if a monaural or FM stereo
-program is received/emitted. Drivers switch automatically between AM and FM
-depending on the selected frequency. The &VIDIOC-G-TUNER; or
-&VIDIOC-G-MODULATOR; ioctl
-reports the supported frequency range.</para>
-  </section>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
- -->
diff --git a/Documentation/DocBook/v4l/dev-raw-vbi.xml b/Documentation/DocBook/v4l/dev-raw-vbi.xml
deleted file mode 100644 (file)
index c5a70bd..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-  <title>Raw VBI Data Interface</title>
-
-  <para>VBI is an abbreviation of Vertical Blanking Interval, a gap
-in the sequence of lines of an analog video signal. During VBI
-no picture information is transmitted, allowing some time while the
-electron beam of a cathode ray tube TV returns to the top of the
-screen. Using an oscilloscope you will find here the vertical
-synchronization pulses and short data packages ASK
-modulated<footnote><para>ASK: Amplitude-Shift Keying. A high signal
-level represents a '1' bit, a low level a '0' bit.</para></footnote>
-onto the video signal. These are transmissions of services such as
-Teletext or Closed Caption.</para>
-
-  <para>Subject of this interface type is raw VBI data, as sampled off
-a video signal, or to be added to a signal for output.
-The data format is similar to uncompressed video images, a number of
-lines times a number of samples per line, we call this a VBI image.</para>
-
-  <para>Conventionally V4L2 VBI devices are accessed through character
-device special files named <filename>/dev/vbi</filename> and
-<filename>/dev/vbi0</filename> to <filename>/dev/vbi31</filename> with
-major number 81 and minor numbers 224 to 255.
-<filename>/dev/vbi</filename> is typically a symbolic link to the
-preferred VBI device. This convention applies to both input and output
-devices.</para>
-
-  <para>To address the problems of finding related video and VBI
-devices VBI capturing and output is also available as device function
-under <filename>/dev/video</filename>. To capture or output raw VBI
-data with these devices applications must call the &VIDIOC-S-FMT;
-ioctl. Accessed as <filename>/dev/vbi</filename>, raw VBI capturing
-or output is the default device function.</para>
-
-    <section>
-      <title>Querying Capabilities</title>
-
-      <para>Devices supporting the raw VBI capturing or output API set
-the <constant>V4L2_CAP_VBI_CAPTURE</constant> or
-<constant>V4L2_CAP_VBI_OUTPUT</constant> flags, respectively, in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. At least one of the
-read/write, streaming or asynchronous I/O methods must be
-supported. VBI devices may or may not have a tuner or modulator.</para>
-    </section>
-
-    <section>
-      <title>Supplemental Functions</title>
-
-      <para>VBI devices shall support <link linkend="video">video
-input or output</link>, <link linkend="tuner">tuner or
-modulator</link>, and <link linkend="control">controls</link> ioctls
-as needed. The <link linkend="standard">video standard</link> ioctls provide
-information vital to program a VBI device, therefore must be
-supported.</para>
-    </section>
-
-    <section>
-      <title>Raw VBI Format Negotiation</title>
-
-      <para>Raw VBI sampling abilities can vary, in particular the
-sampling frequency. To properly interpret the data V4L2 specifies an
-ioctl to query the sampling parameters. Moreover, to allow for some
-flexibility applications can also suggest different parameters.</para>
-
-      <para>As usual these parameters are <emphasis>not</emphasis>
-reset at &func-open; time to permit Unix tool chains, programming a
-device and then reading from it as if it was a plain file. Well
-written V4L2 applications should always ensure they really get what
-they want, requesting reasonable parameters and then checking if the
-actual parameters are suitable.</para>
-
-      <para>To query the current raw VBI capture parameters
-applications set the <structfield>type</structfield> field of a
-&v4l2-format; to <constant>V4L2_BUF_TYPE_VBI_CAPTURE</constant> or
-<constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant>, and call the
-&VIDIOC-G-FMT; ioctl with a pointer to this structure. Drivers fill
-the &v4l2-vbi-format; <structfield>vbi</structfield> member of the
-<structfield>fmt</structfield> union.</para>
-
-      <para>To request different parameters applications set the
-<structfield>type</structfield> field of a &v4l2-format; as above and
-initialize all fields of the &v4l2-vbi-format;
-<structfield>vbi</structfield> member of the
-<structfield>fmt</structfield> union, or better just modify the
-results of <constant>VIDIOC_G_FMT</constant>, and call the
-&VIDIOC-S-FMT; ioctl with a pointer to this structure. Drivers return
-an &EINVAL; only when the given parameters are ambiguous, otherwise
-they modify the parameters according to the hardware capabilites and
-return the actual parameters. When the driver allocates resources at
-this point, it may return an &EBUSY; to indicate the returned
-parameters are valid but the required resources are currently not
-available. That may happen for instance when the video and VBI areas
-to capture would overlap, or when the driver supports multiple opens
-and another process already requested VBI capturing or output. Anyway,
-applications must expect other resource allocation points which may
-return <errorcode>EBUSY</errorcode>, at the &VIDIOC-STREAMON; ioctl
-and the first read(), write() and select() call.</para>
-
-      <para>VBI devices must implement both the
-<constant>VIDIOC_G_FMT</constant> and
-<constant>VIDIOC_S_FMT</constant> ioctl, even if
-<constant>VIDIOC_S_FMT</constant> ignores all requests and always
-returns default parameters as <constant>VIDIOC_G_FMT</constant> does.
-<constant>VIDIOC_TRY_FMT</constant> is optional.</para>
-
-      <table pgwide="1" frame="none" id="v4l2-vbi-format">
-       <title>struct <structname>v4l2_vbi_format</structname></title>
-       <tgroup cols="3">
-         &cs-str;
-         <tbody valign="top">
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>sampling_rate</structfield></entry>
-             <entry>Samples per second, i.&nbsp;e. unit 1 Hz.</entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>offset</structfield></entry>
-             <entry><para>Horizontal offset of the VBI image,
-relative to the leading edge of the line synchronization pulse and
-counted in samples: The first sample in the VBI image will be located
-<structfield>offset</structfield> /
-<structfield>sampling_rate</structfield> seconds following the leading
-edge. See also <xref linkend="vbi-hsync" />.</para></entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>samples_per_line</structfield></entry>
-             <entry></entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>sample_format</structfield></entry>
-             <entry><para>Defines the sample format as in <xref
-linkend="pixfmt" />, a four-character-code.<footnote>
-                   <para>A few devices may be unable to
-sample VBI data at all but can extend the video capture window to the
-VBI region.</para>
-                 </footnote> Usually this is
-<constant>V4L2_PIX_FMT_GREY</constant>, i.&nbsp;e. each sample
-consists of 8 bits with lower values oriented towards the black level.
-Do not assume any other correlation of values with the signal level.
-For example, the MSB does not necessarily indicate if the signal is
-'high' or 'low' because 128 may not be the mean value of the
-signal. Drivers shall not convert the sample format by software.</para></entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>start</structfield>[2]</entry>
-             <entry>This is the scanning system line number
-associated with the first line of the VBI image, of the first and the
-second field respectively. See <xref linkend="vbi-525" /> and
-<xref linkend="vbi-625" /> for valid values. VBI input drivers can
-return start values 0 if the hardware cannot reliable identify
-scanning lines, VBI acquisition may not require this
-information.</entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>count</structfield>[2]</entry>
-             <entry>The number of lines in the first and second
-field image, respectively.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>Drivers should be as
-flexibility as possible. For example, it may be possible to extend or
-move the VBI capture window down to the picture area, implementing a
-'full field mode' to capture data service transmissions embedded in
-the picture.</para><para>An application can set the first or second
-<structfield>count</structfield> value to zero if no data is required
-from the respective field; <structfield>count</structfield>[1] if the
-scanning system is progressive, &ie; not interlaced. The
-corresponding start value shall be ignored by the application and
-driver. Anyway, drivers may not support single field capturing and
-return both count values non-zero.</para><para>Both
-<structfield>count</structfield> values set to zero, or line numbers
-outside the bounds depicted in <xref linkend="vbi-525" /> and <xref
-                   linkend="vbi-625" />, or a field image covering
-lines of two fields, are invalid and shall not be returned by the
-driver.</para><para>To initialize the <structfield>start</structfield>
-and <structfield>count</structfield> fields, applications must first
-determine the current video standard selection. The &v4l2-std-id; or
-the <structfield>framelines</structfield> field of &v4l2-standard; can
-be evaluated for this purpose.</para></entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>flags</structfield></entry>
-             <entry>See <xref linkend="vbifmt-flags" /> below. Currently
-only drivers set flags, applications must set this field to
-zero.</entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>reserved</structfield>[2]</entry>
-             <entry>This array is reserved for future extensions.
-Drivers and applications must set it to zero.</entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <table pgwide="1" frame="none" id="vbifmt-flags">
-       <title>Raw VBI Format Flags</title>
-       <tgroup cols="3">
-         &cs-def;
-         <tbody valign="top">
-           <row>
-             <entry><constant>V4L2_VBI_UNSYNC</constant></entry>
-             <entry>0x0001</entry>
-             <entry><para>This flag indicates hardware which does not
-properly distinguish between fields. Normally the VBI image stores the
-first field (lower scanning line numbers) first in memory. This may be
-a top or bottom field depending on the video standard. When this flag
-is set the first or second field may be stored first, however the
-fields are still in correct temporal order with the older field first
-in memory.<footnote>
-                 <para>Most VBI services transmit on both fields, but
-some have different semantics depending on the field number. These
-cannot be reliable decoded or encoded when
-<constant>V4L2_VBI_UNSYNC</constant> is set.</para>
-               </footnote></para></entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_VBI_INTERLACED</constant></entry>
-             <entry>0x0002</entry>
-             <entry>By default the two field images will be passed
-sequentially; all lines of the first field followed by all lines of
-the second field (compare <xref linkend="field-order" />
-<constant>V4L2_FIELD_SEQ_TB</constant> and
-<constant>V4L2_FIELD_SEQ_BT</constant>, whether the top or bottom
-field is first in memory depends on the video standard). When this
-flag is set, the two fields are interlaced (cf.
-<constant>V4L2_FIELD_INTERLACED</constant>). The first line of the
-first field followed by the first line of the second field, then the
-two second lines, and so on. Such a layout may be necessary when the
-hardware has been programmed to capture or output interlaced video
-images and is unable to separate the fields for VBI capturing at
-the same time. For simplicity setting this flag implies that both
-<structfield>count</structfield> values are equal and non-zero.</entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <figure id="vbi-hsync">
-       <title>Line synchronization</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="vbi_hsync.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="vbi_hsync.gif" format="GIF" />
-         </imageobject>
-         <textobject>
-           <phrase>Line synchronization diagram</phrase>
-         </textobject>
-       </mediaobject>
-      </figure>
-
-      <figure id="vbi-525">
-       <title>ITU-R 525 line numbering (M/NTSC and M/PAL)</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="vbi_525.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="vbi_525.gif" format="GIF" />
-         </imageobject>
-         <textobject>
-           <phrase>NTSC field synchronization diagram</phrase>
-         </textobject>
-         <caption>
-           <para>(1) For the purpose of this specification field 2
-starts in line 264 and not 263.5 because half line capturing is not
-supported.</para>
-         </caption>
-       </mediaobject>
-      </figure>
-
-      <figure id="vbi-625">
-       <title>ITU-R 625 line numbering</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="vbi_625.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="vbi_625.gif" format="GIF" />
-         </imageobject>
-         <textobject>
-           <phrase>PAL/SECAM field synchronization diagram</phrase>
-         </textobject>
-         <caption>
-           <para>(1) For the purpose of this specification field 2
-starts in line 314 and not 313.5 because half line capturing is not
-supported.</para>
-         </caption>
-       </mediaobject>
-      </figure>
-
-      <para>Remember the VBI image format depends on the selected
-video standard, therefore the application must choose a new standard or
-query the current standard first. Attempts to read or write data ahead
-of format negotiation, or after switching the video standard which may
-invalidate the negotiated VBI parameters, should be refused by the
-driver. A format change during active I/O is not permitted.</para>
-    </section>
-
-    <section>
-      <title>Reading and writing VBI images</title>
-
-      <para>To assure synchronization with the field number and easier
-implementation, the smallest unit of data passed at a time is one
-frame, consisting of two fields of VBI images immediately following in
-memory.</para>
-
-      <para>The total size of a frame computes as follows:</para>
-
-      <programlisting>
-(<structfield>count</structfield>[0] + <structfield>count</structfield>[1]) *
-<structfield>samples_per_line</structfield> * sample size in bytes</programlisting>
-
-      <para>The sample size is most likely always one byte,
-applications must check the <structfield>sample_format</structfield>
-field though, to function properly with other drivers.</para>
-
-      <para>A VBI device may support <link
-      linkend="rw">read/write</link> and/or streaming (<link
-      linkend="mmap">memory mapping</link> or <link
-      linkend="userp">user pointer</link>) I/O. The latter bears the
-possibility of synchronizing video and
-VBI data by using buffer timestamps.</para>
-
-      <para>Remember the &VIDIOC-STREAMON; ioctl and the first read(),
-write() and select() call can be resource allocation points returning
-an &EBUSY; if the required hardware resources are temporarily
-unavailable, for example the device is already in use by another
-process.</para>
-  </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/dev-rds.xml b/Documentation/DocBook/v4l/dev-rds.xml
deleted file mode 100644 (file)
index 2427f54..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-     <title>RDS Interface</title>
-
-      <para>The Radio Data System transmits supplementary
-information in binary format, for example the station name or travel
-information, on an inaudible audio subcarrier of a radio program. This
-interface is aimed at devices capable of receiving and/or transmitting RDS
-information.</para>
-
-      <para>For more information see the core RDS standard <xref linkend="en50067" />
-and the RBDS standard <xref linkend="nrsc4" />.</para>
-
-      <para>Note that the RBDS standard as is used in the USA is almost identical
-to the RDS standard. Any RDS decoder/encoder can also handle RBDS. Only some of the
-fields have slightly different meanings. See the RBDS standard for more
-information.</para>
-
-      <para>The RBDS standard also specifies support for MMBS (Modified Mobile Search).
-This is a proprietary format which seems to be discontinued. The RDS interface does not
-support this format. Should support for MMBS (or the so-called 'E blocks' in general)
-be needed, then please contact the linux-media mailing list: &v4l-ml;.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the RDS capturing API set
-the <constant>V4L2_CAP_RDS_CAPTURE</constant> flag in
-the <structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl.  Any tuner that supports RDS
-will set the <constant>V4L2_TUNER_CAP_RDS</constant> flag in
-the <structfield>capability</structfield> field of &v4l2-tuner;.  If
-the driver only passes RDS blocks without interpreting the data
-the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be
-set, see <link linkend="reading-rds-data">Reading RDS data</link>.
-For future use the
-flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> has also been
-defined. However, a driver for a radio tuner with this capability does
-not yet exist, so if you are planning to write such a driver you
-should discuss this on the linux-media mailing list: &v4l-ml;.</para>
-
-    <para> Whether an RDS signal is present can be detected by looking
-at the <structfield>rxsubchans</structfield> field of &v4l2-tuner;:
-the <constant>V4L2_TUNER_SUB_RDS</constant> will be set if RDS data
-was detected.</para>
-
-    <para>Devices supporting the RDS output API
-set the <constant>V4L2_CAP_RDS_OUTPUT</constant> flag in
-the <structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl.
-Any modulator that supports RDS will set the
-<constant>V4L2_TUNER_CAP_RDS</constant> flag in the <structfield>capability</structfield>
-field of &v4l2-modulator;.
-In order to enable the RDS transmission one must set the <constant>V4L2_TUNER_SUB_RDS</constant>
-bit in the <structfield>txsubchans</structfield> field of &v4l2-modulator;.
-If the driver only passes RDS blocks without interpreting the data
-the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be set. If the
-tuner is capable of handling RDS entities like program identification codes and radio
-text, the flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> should be set,
-see <link linkend="writing-rds-data">Writing RDS data</link> and
-<link linkend="fm-tx-controls">FM Transmitter Control Reference</link>.</para>
-  </section>
-
-  <section  id="reading-rds-data">
-    <title>Reading RDS data</title>
-
-      <para>RDS data can be read from the radio device
-with the &func-read; function. The data is packed in groups of three bytes.</para>
-  </section>
-
-  <section  id="writing-rds-data">
-    <title>Writing RDS data</title>
-
-      <para>RDS data can be written to the radio device
-with the &func-write; function. The data is packed in groups of three bytes,
-as follows:</para>
-  </section>
-
-  <section>
-    <title>RDS datastructures</title>
-    <table frame="none" pgwide="1" id="v4l2-rds-data">
-      <title>struct
-<structname>v4l2_rds_data</structname></title>
-      <tgroup cols="3">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="5*" />
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>lsb</structfield></entry>
-           <entry>Least Significant Byte of RDS Block</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>msb</structfield></entry>
-           <entry>Most Significant Byte of RDS Block</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>block</structfield></entry>
-           <entry>Block description</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-    <table frame="none" pgwide="1" id="v4l2-rds-block">
-      <title>Block description</title>
-      <tgroup cols="2">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="5*" />
-       <tbody valign="top">
-         <row>
-           <entry>Bits 0-2</entry>
-           <entry>Block (aka offset) of the received data.</entry>
-         </row>
-         <row>
-           <entry>Bits 3-5</entry>
-           <entry>Deprecated. Currently identical to bits 0-2. Do not use these bits.</entry>
-         </row>
-         <row>
-           <entry>Bit 6</entry>
-           <entry>Corrected bit. Indicates that an error was corrected for this data block.</entry>
-         </row>
-         <row>
-           <entry>Bit 7</entry>
-           <entry>Error bit. Indicates that an uncorrectable error occurred during reception of this block.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-rds-block-codes">
-      <title>Block defines</title>
-      <tgroup cols="4">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="1*" />
-       <colspec colname="c4" colwidth="5*" />
-       <tbody valign="top">
-         <row>
-           <entry>V4L2_RDS_BLOCK_MSK</entry>
-           <entry> </entry>
-           <entry>7</entry>
-           <entry>Mask for bits 0-2 to get the block ID.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_A</entry>
-           <entry> </entry>
-           <entry>0</entry>
-           <entry>Block A.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_B</entry>
-           <entry> </entry>
-           <entry>1</entry>
-           <entry>Block B.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_C</entry>
-           <entry> </entry>
-           <entry>2</entry>
-           <entry>Block C.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_D</entry>
-           <entry> </entry>
-           <entry>3</entry>
-           <entry>Block D.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_C_ALT</entry>
-           <entry> </entry>
-           <entry>4</entry>
-           <entry>Block C'.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_INVALID</entry>
-           <entry>read-only</entry>
-           <entry>7</entry>
-           <entry>An invalid block.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_CORRECTED</entry>
-           <entry>read-only</entry>
-           <entry>0x40</entry>
-           <entry>A bit error was detected but corrected.</entry>
-         </row>
-         <row>
-           <entry>V4L2_RDS_BLOCK_ERROR</entry>
-           <entry>read-only</entry>
-           <entry>0x80</entry>
-           <entry>An uncorrectable error occurred.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
- -->
diff --git a/Documentation/DocBook/v4l/dev-sliced-vbi.xml b/Documentation/DocBook/v4l/dev-sliced-vbi.xml
deleted file mode 100644 (file)
index 69e789f..0000000
+++ /dev/null
@@ -1,708 +0,0 @@
-  <title>Sliced VBI Data Interface</title>
-
-  <para>VBI stands for Vertical Blanking Interval, a gap in the
-sequence of lines of an analog video signal. During VBI no picture
-information is transmitted, allowing some time while the electron beam
-of a cathode ray tube TV returns to the top of the screen.</para>
-
-  <para>Sliced VBI devices use hardware to demodulate data transmitted
-in the VBI. V4L2 drivers shall <emphasis>not</emphasis> do this by
-software, see also the <link linkend="raw-vbi">raw VBI
-interface</link>. The data is passed as short packets of fixed size,
-covering one scan line each. The number of packets per video frame is
-variable.</para>
-
-  <para>Sliced VBI capture and output devices are accessed through the
-same character special files as raw VBI devices. When a driver
-supports both interfaces, the default function of a
-<filename>/dev/vbi</filename> device is <emphasis>raw</emphasis> VBI
-capturing or output, and the sliced VBI function is only available
-after calling the &VIDIOC-S-FMT; ioctl as defined below. Likewise a
-<filename>/dev/video</filename> device may support the sliced VBI API,
-however the default function here is video capturing or output.
-Different file descriptors must be used to pass raw and sliced VBI
-data simultaneously, if this is supported by the driver.</para>
-
-  <section>
-    <title>Querying Capabilities</title>
-
-    <para>Devices supporting the sliced VBI capturing or output API
-set the <constant>V4L2_CAP_SLICED_VBI_CAPTURE</constant> or
-<constant>V4L2_CAP_SLICED_VBI_OUTPUT</constant> flag respectively, in
-the <structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl. At least one of the
-read/write, streaming or asynchronous <link linkend="io">I/O
-methods</link> must be supported. Sliced VBI devices may have a tuner
-or modulator.</para>
-  </section>
-
-  <section>
-    <title>Supplemental Functions</title>
-
-    <para>Sliced VBI devices shall support <link linkend="video">video
-input or output</link> and <link linkend="tuner">tuner or
-modulator</link> ioctls if they have these capabilities, and they may
-support <link linkend="control">control</link> ioctls. The <link
-linkend="standard">video standard</link> ioctls provide information
-vital to program a sliced VBI device, therefore must be
-supported.</para>
-  </section>
-
-  <section id="sliced-vbi-format-negotitation">
-    <title>Sliced VBI Format Negotiation</title>
-
-    <para>To find out which data services are supported by the
-hardware applications can call the &VIDIOC-G-SLICED-VBI-CAP; ioctl.
-All drivers implementing the sliced VBI interface must support this
-ioctl. The results may differ from those of the &VIDIOC-S-FMT; ioctl
-when the number of VBI lines the hardware can capture or output per
-frame, or the number of services it can identify on a given line are
-limited. For example on PAL line 16 the hardware may be able to look
-for a VPS or Teletext signal, but not both at the same time.</para>
-
-    <para>To determine the currently selected services applications
-set the <structfield>type </structfield> field of &v4l2-format; to
-<constant> V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant> or <constant>
-V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant>, and the &VIDIOC-G-FMT;
-ioctl fills the <structfield>fmt.sliced</structfield> member, a
-&v4l2-sliced-vbi-format;.</para>
-
-    <para>Applications can request different parameters by
-initializing or modifying the <structfield>fmt.sliced</structfield>
-member and calling the &VIDIOC-S-FMT; ioctl with a pointer to the
-<structname>v4l2_format</structname> structure.</para>
-
-    <para>The sliced VBI API is more complicated than the raw VBI API
-because the hardware must be told which VBI service to expect on each
-scan line. Not all services may be supported by the hardware on all
-lines (this is especially true for VBI output where Teletext is often
-unsupported and other services can only be inserted in one specific
-line). In many cases, however, it is sufficient to just set the
-<structfield>service_set</structfield> field to the required services
-and let the driver fill the <structfield>service_lines</structfield>
-array according to hardware capabilities. Only if more precise control
-is needed should the programmer set the
-<structfield>service_lines</structfield> array explicitly.</para>
-
-    <para>The &VIDIOC-S-FMT; ioctl modifies the parameters
-according to hardware capabilities. When the driver allocates
-resources at this point, it may return an &EBUSY; if the required
-resources are temporarily unavailable. Other resource allocation
-points which may return <errorcode>EBUSY</errorcode> can be the
-&VIDIOC-STREAMON; ioctl and the first &func-read;, &func-write; and
-&func-select; call.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-sliced-vbi-format">
-      <title>struct
-<structname>v4l2_sliced_vbi_format</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" colwidth="3*" />
-       <colspec colname="c2" colwidth="3*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="2*" />
-       <colspec colname="c5" colwidth="2*" />
-       <spanspec namest="c3" nameend="c5" spanname="hspan" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>service_set</structfield></entry>
-           <entry spanname="hspan"><para>If
-<structfield>service_set</structfield> is non-zero when passed with
-&VIDIOC-S-FMT; or &VIDIOC-TRY-FMT;, the
-<structfield>service_lines</structfield> array will be filled by the
-driver according to the services specified in this field. For example,
-if <structfield>service_set</structfield> is initialized with
-<constant>V4L2_SLICED_TELETEXT_B | V4L2_SLICED_WSS_625</constant>, a
-driver for the cx25840 video decoder sets lines 7-22 of both
-fields<footnote><para>According to <link
-linkend="ets300706">ETS&nbsp;300&nbsp;706</link> lines 6-22 of the
-first field and lines 5-22 of the second field may carry Teletext
-data.</para></footnote> to <constant>V4L2_SLICED_TELETEXT_B</constant>
-and line 23 of the first field to
-<constant>V4L2_SLICED_WSS_625</constant>. If
-<structfield>service_set</structfield> is set to zero, then the values
-of <structfield>service_lines</structfield> will be used instead.
-</para><para>On return the driver sets this field to the union of all
-elements of the returned <structfield>service_lines</structfield>
-array. It may contain less services than requested, perhaps just one,
-if the hardware cannot handle more services simultaneously. It may be
-empty (zero) if none of the requested services are supported by the
-hardware.</para></entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>service_lines</structfield>[2][24]</entry>
-           <entry spanname="hspan"><para>Applications initialize this
-array with sets of data services the driver shall look for or insert
-on the respective scan line. Subject to hardware capabilities drivers
-return the requested set, a subset, which may be just a single
-service, or an empty set. When the hardware cannot handle multiple
-services on the same line the driver shall choose one. No assumptions
-can be made on which service the driver chooses.</para><para>Data
-services are defined in <xref linkend="vbi-services2" />. Array indices
-map to ITU-R line numbers (see also <xref linkend="vbi-525" /> and <xref
-                 linkend="vbi-625" />) as follows: <!-- No nested
-tables, sigh. --></para></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>Element</entry>
-           <entry>525 line systems</entry>
-           <entry>625 line systems</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[0][1]</entry>
-           <entry align="center">1</entry>
-           <entry align="center">1</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[0][23]</entry>
-           <entry align="center">23</entry>
-           <entry align="center">23</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[1][1]</entry>
-           <entry align="center">264</entry>
-           <entry align="center">314</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[1][23]</entry>
-           <entry align="center">286</entry>
-           <entry align="center">336</entry>
-         </row>
-         <!-- End of line numbers table. -->
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry spanname="hspan">Drivers must set
-<structfield>service_lines</structfield>[0][0] and
-<structfield>service_lines</structfield>[1][0] to zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>io_size</structfield></entry>
-           <entry spanname="hspan">Maximum number of bytes passed by
-one &func-read; or &func-write; call, and the buffer size in bytes for
-the &VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl. Drivers set this field to
-the size of &v4l2-sliced-vbi-data; times the number of non-zero
-elements in the returned <structfield>service_lines</structfield>
-array (that is the number of lines potentially carrying data).</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry spanname="hspan">This array is reserved for future
-extensions. Applications and drivers must set it to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- See also vidioc-g-sliced-vbi-cap.sgml -->
-    <table frame="none" pgwide="1" id="vbi-services2">
-      <title>Sliced VBI services</title>
-      <tgroup cols="5">
-       <colspec colname="c1" colwidth="2*" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="1*" />
-       <colspec colname="c4" colwidth="2*" />
-       <colspec colname="c5" colwidth="2*" />
-       <spanspec namest="c3" nameend="c5" spanname="rlp" />
-       <thead>
-         <row>
-           <entry>Symbol</entry>
-           <entry>Value</entry>
-           <entry>Reference</entry>
-           <entry>Lines, usually</entry>
-           <entry>Payload</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_SLICED_TELETEXT_B</constant>
-(Teletext System B)</entry>
-           <entry>0x0001</entry>
-           <entry><xref linkend="ets300706" />, <xref linkend="itu653" /></entry>
-           <entry>PAL/SECAM line 7-22, 320-335 (second field 7-22)</entry>
-           <entry>Last 42 of the 45 byte Teletext packet, that is
-without clock run-in and framing code, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VPS</constant></entry>
-           <entry>0x0400</entry>
-           <entry><xref linkend="ets300231" /></entry>
-           <entry>PAL line 16</entry>
-           <entry>Byte number 3 to 15 according to Figure 9 of
-ETS&nbsp;300&nbsp;231, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_CAPTION_525</constant></entry>
-           <entry>0x1000</entry>
-           <entry><xref linkend="eia608" /></entry>
-           <entry>NTSC line 21, 284 (second field 21)</entry>
-           <entry>Two bytes in transmission order, including parity
-bit, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_WSS_625</constant></entry>
-           <entry>0x4000</entry>
-           <entry><xref linkend="itu1119" />, <xref linkend="en300294" /></entry>
-           <entry>PAL/SECAM line 23</entry>
-           <entry><screen>
-Byte         0                 1
-      msb         lsb  msb           lsb
- Bit  7 6 5 4 3 2 1 0  x x 13 12 11 10 9
-</screen></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VBI_525</constant></entry>
-           <entry>0x1000</entry>
-           <entry spanname="rlp">Set of services applicable to 525
-line systems.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VBI_625</constant></entry>
-           <entry>0x4401</entry>
-           <entry spanname="rlp">Set of services applicable to 625
-line systems.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Drivers may return an &EINVAL; when applications attempt to
-read or write data without prior format negotiation, after switching
-the video standard (which may invalidate the negotiated VBI
-parameters) and after switching the video input (which may change the
-video standard as a side effect). The &VIDIOC-S-FMT; ioctl may return
-an &EBUSY; when applications attempt to change the format while i/o is
-in progress (between a &VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; call,
-and after the first &func-read; or &func-write; call).</para>
-  </section>
-
-  <section>
-    <title>Reading and writing sliced VBI data</title>
-
-    <para>A single &func-read; or &func-write; call must pass all data
-belonging to one video frame. That is an array of
-<structname>v4l2_sliced_vbi_data</structname> structures with one or
-more elements and a total size not exceeding
-<structfield>io_size</structfield> bytes. Likewise in streaming I/O
-mode one buffer of <structfield>io_size</structfield> bytes must
-contain data of one video frame. The <structfield>id</structfield> of
-unused <structname>v4l2_sliced_vbi_data</structname> elements must be
-zero.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-sliced-vbi-data">
-      <title>struct
-<structname>v4l2_sliced_vbi_data</structname></title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>A flag from <xref linkend="vbi-services" />
-identifying the type of data in this packet. Only a single bit must be
-set. When the <structfield>id</structfield> of a captured packet is
-zero, the packet is empty and the contents of other fields are
-undefined. Applications shall ignore empty packets. When the
-<structfield>id</structfield> of a packet for output is zero the
-contents of the <structfield>data</structfield> field are undefined
-and the driver must no longer insert data on the requested
-<structfield>field</structfield> and
-<structfield>line</structfield>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry>The video field number this data has been captured
-from, or shall be inserted at. <constant>0</constant> for the first
-field, <constant>1</constant> for the second field.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>line</structfield></entry>
-           <entry>The field (as opposed to frame) line number this
-data has been captured from, or shall be inserted at. See <xref
-           linkend="vbi-525" /> and <xref linkend="vbi-625" /> for valid
-values. Sliced VBI capture devices can set the line number of all
-packets to <constant>0</constant> if the hardware cannot reliably
-identify scan lines. The field number must always be valid.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield></entry>
-           <entry>This field is reserved for future extensions.
-Applications and drivers must set it to zero.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>data</structfield>[48]</entry>
-           <entry>The packet payload. See <xref
-           linkend="vbi-services" /> for the contents and number of
-bytes passed for each data type. The contents of padding bytes at the
-end of this array are undefined, drivers and applications shall ignore
-them.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Packets are always passed in ascending line number order,
-without duplicate line numbers. The &func-write; function and the
-&VIDIOC-QBUF; ioctl must return an &EINVAL; when applications violate
-this rule. They must also return an &EINVAL; when applications pass an
-incorrect field or line number, or a combination of
-<structfield>field</structfield>, <structfield>line</structfield> and
-<structfield>id</structfield> which has not been negotiated with the
-&VIDIOC-G-FMT; or &VIDIOC-S-FMT; ioctl. When the line numbers are
-unknown the driver must pass the packets in transmitted order. The
-driver can insert empty packets with <structfield>id</structfield> set
-to zero anywhere in the packet array.</para>
-
-    <para>To assure synchronization and to distinguish from frame
-dropping, when a captured frame does not carry any of the requested
-data services drivers must pass one or more empty packets. When an
-application fails to pass VBI data in time for output, the driver
-must output the last VPS and WSS packet again, and disable the output
-of Closed Caption and Teletext data, or output data which is ignored
-by Closed Caption and Teletext decoders.</para>
-
-    <para>A sliced VBI device may support <link
-linkend="rw">read/write</link> and/or streaming (<link
-linkend="mmap">memory mapping</link> and/or <link linkend="userp">user
-pointer</link>) I/O. The latter bears the possibility of synchronizing
-video and VBI data by using buffer timestamps.</para>
-
-  </section>
-
-  <section>
-    <title>Sliced VBI Data in MPEG Streams</title>
-
-    <para>If a device can produce an MPEG output stream, it may be
-capable of providing <link
-linkend="sliced-vbi-format-negotitation">negotiated sliced VBI
-services</link> as data embedded in the MPEG stream.  Users or
-applications control this sliced VBI data insertion with the <link
-linkend="v4l2-mpeg-stream-vbi-fmt">V4L2_CID_MPEG_STREAM_VBI_FMT</link>
-control.</para>
-
-    <para>If the driver does not provide the <link
-linkend="v4l2-mpeg-stream-vbi-fmt">V4L2_CID_MPEG_STREAM_VBI_FMT</link>
-control, or only allows that control to be set to <link
-linkend="v4l2-mpeg-stream-vbi-fmt"><constant>
-V4L2_MPEG_STREAM_VBI_FMT_NONE</constant></link>, then the device
-cannot embed sliced VBI data in the MPEG stream.</para>
-
-    <para>The <link linkend="v4l2-mpeg-stream-vbi-fmt">
-V4L2_CID_MPEG_STREAM_VBI_FMT</link> control does not implicitly set
-the device driver to capture nor cease capturing sliced VBI data.  The
-control only indicates to embed sliced VBI data in the MPEG stream, if
-an application has negotiated sliced VBI service be captured.</para>
-
-    <para>It may also be the case that a device can embed sliced VBI
-data in only certain types of MPEG streams: for example in an MPEG-2
-PS but not an MPEG-2 TS.  In this situation, if sliced VBI data
-insertion is requested, the sliced VBI data will be embedded in MPEG
-stream types when supported, and silently omitted from MPEG stream
-types where sliced VBI data insertion is not supported by the device.
-</para>
-
-    <para>The following subsections specify the format of the
-embedded sliced VBI data.</para>
-
-  <section>
-    <title>MPEG Stream Embedded, Sliced VBI Data Format: NONE</title>
-    <para>The <link linkend="v4l2-mpeg-stream-vbi-fmt"><constant>
-V4L2_MPEG_STREAM_VBI_FMT_NONE</constant></link> embedded sliced VBI
-format shall be interpreted by drivers as a control to cease
-embedding sliced VBI data in MPEG streams.  Neither the device nor
-driver shall insert "empty" embedded sliced VBI data packets in the
-MPEG stream when this format is set.  No MPEG stream data structures
-are specified for this format.</para>
-  </section>
-
-  <section>
-    <title>MPEG Stream Embedded, Sliced VBI Data Format: IVTV</title>
-    <para>The <link linkend="v4l2-mpeg-stream-vbi-fmt"><constant>
-V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant></link> embedded sliced VBI
-format, when supported, indicates to the driver to embed up to 36
-lines of sliced VBI data per frame in an MPEG-2 <emphasis>Private
-Stream 1 PES</emphasis> packet encapsulated in an MPEG-2 <emphasis>
-Program Pack</emphasis> in the MPEG stream.</para>
-
-    <para><emphasis>Historical context</emphasis>: This format
-specification originates from a custom, embedded, sliced VBI data
-format used by the <filename>ivtv</filename> driver.  This format
-has already been informally specified in the kernel sources in the
-file <filename>Documentation/video4linux/cx2341x/README.vbi</filename>
-.  The maximum size of the payload and other aspects of this format
-are driven by the CX23415 MPEG decoder's capabilities and limitations
-with respect to extracting, decoding, and displaying sliced VBI data
-embedded within an MPEG stream.</para>
-
-    <para>This format's use is <emphasis>not</emphasis> exclusive to
-the <filename>ivtv</filename> driver <emphasis>nor</emphasis>
-exclusive to CX2341x devices, as the sliced VBI data packet insertion
-into the MPEG stream is implemented in driver software.  At least the
-<filename>cx18</filename> driver provides sliced VBI data insertion
-into an MPEG-2 PS in this format as well.</para>
-
-    <para>The following definitions specify the payload of the
-MPEG-2 <emphasis>Private Stream 1 PES</emphasis> packets that contain
-sliced VBI data when <link linkend="v4l2-mpeg-stream-vbi-fmt">
-<constant>V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant></link> is set.
-(The MPEG-2 <emphasis>Private Stream 1 PES</emphasis> packet header
-and encapsulating MPEG-2 <emphasis>Program Pack</emphasis> header are
-not detailed here.  Please refer to the MPEG-2 specifications for
-details on those packet headers.)</para>
-
-    <para>The payload of the MPEG-2 <emphasis>Private Stream 1 PES
-</emphasis> packets that contain sliced VBI data is specified by
-&v4l2-mpeg-vbi-fmt-ivtv;.  The payload is variable
-length, depending on the actual number of lines of sliced VBI data
-present in a video frame.  The payload may be padded at the end with
-unspecified fill bytes to align the end of the payload to a 4-byte
-boundary.  The payload shall never exceed 1552 bytes (2 fields with
-18 lines/field with 43 bytes of data/line and a 4 byte magic number).
-</para>
-
-    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-fmt-ivtv">
-      <title>struct <structname>v4l2_mpeg_vbi_fmt_ivtv</structname>
-      </title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>magic</structfield>[4]</entry>
-           <entry></entry>
-           <entry>A "magic" constant from <xref
-           linkend="v4l2-mpeg-vbi-fmt-ivtv-magic" /> that indicates
-this is a valid sliced VBI data payload and also indicates which
-member of the anonymous union, <structfield>itv0</structfield> or
-<structfield>ITV0</structfield>, to use for the payload data.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry>(anonymous)</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0">
-             <structname>v4l2_mpeg_vbi_itv0</structname></link>
-           </entry>
-           <entry><structfield>itv0</structfield></entry>
-           <entry>The primary form of the sliced VBI data payload
-that contains anywhere from 1 to 35 lines of sliced VBI data.
-Line masks are provided in this form of the payload indicating
-which VBI lines are provided.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0-1">
-             <structname>v4l2_mpeg_vbi_ITV0</structname></link>
-           </entry>
-           <entry><structfield>ITV0</structfield></entry>
-           <entry>An alternate form of the sliced VBI data payload
-used when 36 lines of sliced VBI data are present.  No line masks are
-provided in this form of the payload; all valid line mask bits are
-implcitly set.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-fmt-ivtv-magic">
-      <title>Magic Constants for &v4l2-mpeg-vbi-fmt-ivtv;
-       <structfield>magic</structfield> field</title>
-      <tgroup cols="3">
-       &cs-def;
-       <thead>
-         <row>
-           <entry align="left">Defined Symbol</entry>
-           <entry align="left">Value</entry>
-           <entry align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_MAGIC0</constant>
-           </entry>
-           <entry>"itv0"</entry>
-           <entry>Indicates the <structfield>itv0</structfield>
-member of the union in &v4l2-mpeg-vbi-fmt-ivtv; is valid.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_MAGIC1</constant>
-           </entry>
-           <entry>"ITV0"</entry>
-           <entry>Indicates the <structfield>ITV0</structfield>
-member of the union in &v4l2-mpeg-vbi-fmt-ivtv; is valid and
-that 36 lines of sliced VBI data are present.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-itv0">
-      <title>struct <structname>v4l2_mpeg_vbi_itv0</structname>
-      </title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__le32</entry>
-           <entry><structfield>linemask</structfield>[2]</entry>
-           <entry><para>Bitmasks indicating the VBI service lines
-present.  These <structfield>linemask</structfield> values are stored
-in little endian byte order in the MPEG stream.  Some reference
-<structfield>linemask</structfield> bit positions with their
-corresponding VBI line number and video field are given below.
-b<subscript>0</subscript> indicates the least significant bit of a
-<structfield>linemask</structfield> value:<screen>
-<structfield>linemask</structfield>[0] b<subscript>0</subscript>:              line  6         first field
-<structfield>linemask</structfield>[0] b<subscript>17</subscript>:             line 23         first field
-<structfield>linemask</structfield>[0] b<subscript>18</subscript>:             line  6         second field
-<structfield>linemask</structfield>[0] b<subscript>31</subscript>:             line 19         second field
-<structfield>linemask</structfield>[1] b<subscript>0</subscript>:              line 20         second field
-<structfield>linemask</structfield>[1] b<subscript>3</subscript>:              line 23         second field
-<structfield>linemask</structfield>[1] b<subscript>4</subscript>-b<subscript>31</subscript>:   unused and set to 0</screen></para></entry>
-         </row>
-         <row>
-           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0-line">
-             <structname>v4l2_mpeg_vbi_itv0_line</structname></link>
-           </entry>
-           <entry><structfield>line</structfield>[35]</entry>
-           <entry>This is a variable length array that holds from 1
-to 35 lines of sliced VBI data.  The sliced VBI data lines present
-correspond to the bits set in the <structfield>linemask</structfield>
-array, starting from b<subscript>0</subscript> of <structfield>
-linemask</structfield>[0] up through b<subscript>31</subscript> of
-<structfield>linemask</structfield>[0], and from b<subscript>0
-</subscript> of <structfield>linemask</structfield>[1] up through b
-<subscript>3</subscript> of <structfield>linemask</structfield>[1].
-<structfield>line</structfield>[0] corresponds to the first bit
-found set in the <structfield>linemask</structfield> array,
-<structfield>line</structfield>[1] corresponds to the second bit
-found set in the <structfield>linemask</structfield> array, etc.
-If no <structfield>linemask</structfield> array bits are set, then
-<structfield>line</structfield>[0] may contain one line of
-unspecified data that should be ignored by applications.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-itv0-1">
-      <title>struct <structname>v4l2_mpeg_vbi_ITV0</structname>
-      </title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>struct <link linkend="v4l2-mpeg-vbi-itv0-line">
-             <structname>v4l2_mpeg_vbi_itv0_line</structname></link>
-           </entry>
-           <entry><structfield>line</structfield>[36]</entry>
-           <entry>A fixed length array of 36 lines of sliced VBI
-data.  <structfield>line</structfield>[0] through <structfield>line
-</structfield>[17] correspond to lines 6 through 23 of the
-first field.  <structfield>line</structfield>[18] through
-<structfield>line</structfield>[35] corresponds to lines 6
-through 23 of the second field.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-mpeg-vbi-itv0-line">
-      <title>struct <structname>v4l2_mpeg_vbi_itv0_line</structname>
-      </title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>A line identifier value from
-<xref linkend="ITV0-Line-Identifier-Constants" /> that indicates
-the type of sliced VBI data stored on this line.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>data</structfield>[42]</entry>
-           <entry>The sliced VBI data for the line.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="ITV0-Line-Identifier-Constants">
-      <title>Line Identifiers for struct <link
-      linkend="v4l2-mpeg-vbi-itv0-line"><structname>
-v4l2_mpeg_vbi_itv0_line</structname></link> <structfield>id
-</structfield> field</title>
-      <tgroup cols="3">
-       &cs-def;
-       <thead>
-         <row>
-           <entry align="left">Defined Symbol</entry>
-           <entry align="left">Value</entry>
-           <entry align="left">Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_TELETEXT_B</constant>
-           </entry>
-           <entry>1</entry>
-           <entry>Refer to <link linkend="vbi-services2">
-Sliced VBI services</link> for a description of the line payload.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_CAPTION_525</constant>
-           </entry>
-           <entry>4</entry>
-           <entry>Refer to <link linkend="vbi-services2">
-Sliced VBI services</link> for a description of the line payload.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_WSS_625</constant>
-           </entry>
-           <entry>5</entry>
-           <entry>Refer to <link linkend="vbi-services2">
-Sliced VBI services</link> for a description of the line payload.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MPEG_VBI_IVTV_VPS</constant>
-           </entry>
-           <entry>7</entry>
-           <entry>Refer to <link linkend="vbi-services2">
-Sliced VBI services</link> for a description of the line payload.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </section>
-  </section>
-
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
- -->
diff --git a/Documentation/DocBook/v4l/dev-subdev.xml b/Documentation/DocBook/v4l/dev-subdev.xml
deleted file mode 100644 (file)
index 05c8fef..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-  <title>Sub-device Interface</title>
-
-  <note>
-    <title>Experimental</title>
-    <para>This is an <link linkend="experimental">experimental</link>
-    interface and may change in the future.</para>
-  </note>
-
-  <para>The complex nature of V4L2 devices, where hardware is often made of
-  several integrated circuits that need to interact with each other in a
-  controlled way, leads to complex V4L2 drivers. The drivers usually reflect
-  the hardware model in software, and model the different hardware components
-  as software blocks called sub-devices.</para>
-
-  <para>V4L2 sub-devices are usually kernel-only objects. If the V4L2 driver
-  implements the media device API, they will automatically inherit from media
-  entities. Applications will be able to enumerate the sub-devices and discover
-  the hardware topology using the media entities, pads and links enumeration
-  API.</para>
-
-  <para>In addition to make sub-devices discoverable, drivers can also choose
-  to make them directly configurable by applications. When both the sub-device
-  driver and the V4L2 device driver support this, sub-devices will feature a
-  character device node on which ioctls can be called to
-  <itemizedlist>
-    <listitem><para>query, read and write sub-devices controls</para></listitem>
-    <listitem><para>subscribe and unsubscribe to events and retrieve them</para></listitem>
-    <listitem><para>negotiate image formats on individual pads</para></listitem>
-  </itemizedlist>
-  </para>
-
-  <para>Sub-device character device nodes, conventionally named
-  <filename>/dev/v4l-subdev*</filename>, use major number 81.</para>
-
-  <section>
-    <title>Controls</title>
-    <para>Most V4L2 controls are implemented by sub-device hardware. Drivers
-    usually merge all controls and expose them through video device nodes.
-    Applications can control all sub-devices through a single interface.</para>
-
-    <para>Complex devices sometimes implement the same control in different
-    pieces of hardware. This situation is common in embedded platforms, where
-    both sensors and image processing hardware implement identical functions,
-    such as contrast adjustment, white balance or faulty pixels correction. As
-    the V4L2 controls API doesn't support several identical controls in a single
-    device, all but one of the identical controls are hidden.</para>
-
-    <para>Applications can access those hidden controls through the sub-device
-    node with the V4L2 control API described in <xref linkend="control" />. The
-    ioctls behave identically as when issued on V4L2 device nodes, with the
-    exception that they deal only with controls implemented in the sub-device.
-    </para>
-
-    <para>Depending on the driver, those controls might also be exposed through
-    one (or several) V4L2 device nodes.</para>
-  </section>
-
-  <section>
-    <title>Events</title>
-    <para>V4L2 sub-devices can notify applications of events as described in
-    <xref linkend="event" />. The API behaves identically as when used on V4L2
-    device nodes, with the exception that it only deals with events generated by
-    the sub-device. Depending on the driver, those events might also be reported
-    on one (or several) V4L2 device nodes.</para>
-  </section>
-
-  <section id="pad-level-formats">
-    <title>Pad-level Formats</title>
-
-    <warning><para>Pad-level formats are only applicable to very complex device that
-    need to expose low-level format configuration to user space. Generic V4L2
-    applications do <emphasis>not</emphasis> need to use the API described in
-    this section.</para></warning>
-
-    <note><para>For the purpose of this section, the term
-    <wordasword>format</wordasword> means the combination of media bus data
-    format, frame width and frame height.</para></note>
-
-    <para>Image formats are typically negotiated on video capture and output
-    devices using the <link linkend="crop">cropping and scaling</link> ioctls.
-    The driver is responsible for configuring every block in the video pipeline
-    according to the requested format at the pipeline input and/or
-    output.</para>
-
-    <para>For complex devices, such as often found in embedded systems,
-    identical image sizes at the output of a pipeline can be achieved using
-    different hardware configurations. One such example is shown on
-    <xref linkend="pipeline-scaling" />, where
-    image scaling can be performed on both the video sensor and the host image
-    processing hardware.</para>
-
-    <figure id="pipeline-scaling">
-      <title>Image Format Negotiation on Pipelines</title>
-      <mediaobject>
-       <imageobject>
-         <imagedata fileref="pipeline.pdf" format="PS" />
-       </imageobject>
-       <imageobject>
-         <imagedata fileref="pipeline.png" format="PNG" />
-       </imageobject>
-       <textobject>
-         <phrase>High quality and high speed pipeline configuration</phrase>
-       </textobject>
-      </mediaobject>
-    </figure>
-
-    <para>The sensor scaler is usually of less quality than the host scaler, but
-    scaling on the sensor is required to achieve higher frame rates. Depending
-    on the use case (quality vs. speed), the pipeline must be configured
-    differently. Applications need to configure the formats at every point in
-    the pipeline explicitly.</para>
-
-    <para>Drivers that implement the <link linkend="media-controller-intro">media
-    API</link> can expose pad-level image format configuration to applications.
-    When they do, applications can use the &VIDIOC-SUBDEV-G-FMT; and
-    &VIDIOC-SUBDEV-S-FMT; ioctls. to negotiate formats on a per-pad basis.</para>
-
-    <para>Applications are responsible for configuring coherent parameters on
-    the whole pipeline and making sure that connected pads have compatible
-    formats. The pipeline is checked for formats mismatch at &VIDIOC-STREAMON;
-    time, and an &EPIPE; is then returned if the configuration is
-    invalid.</para>
-
-    <para>Pad-level image format configuration support can be tested by calling
-    the &VIDIOC-SUBDEV-G-FMT; ioctl on pad 0. If the driver returns an &EINVAL;
-    pad-level format configuration is not supported by the sub-device.</para>
-
-    <section>
-      <title>Format Negotiation</title>
-
-      <para>Acceptable formats on pads can (and usually do) depend on a number
-      of external parameters, such as formats on other pads, active links, or
-      even controls. Finding a combination of formats on all pads in a video
-      pipeline, acceptable to both application and driver, can't rely on formats
-      enumeration only. A format negotiation mechanism is required.</para>
-
-      <para>Central to the format negotiation mechanism are the get/set format
-      operations. When called with the <structfield>which</structfield> argument
-      set to <constant>V4L2_SUBDEV_FORMAT_TRY</constant>, the
-      &VIDIOC-SUBDEV-G-FMT; and &VIDIOC-SUBDEV-S-FMT; ioctls operate on a set of
-      formats parameters that are not connected to the hardware configuration.
-      Modifying those 'try' formats leaves the device state untouched (this
-      applies to both the software state stored in the driver and the hardware
-      state stored in the device itself).</para>
-
-      <para>While not kept as part of the device state, try formats are stored
-      in the sub-device file handles. A &VIDIOC-SUBDEV-G-FMT; call will return
-      the last try format set <emphasis>on the same sub-device file
-      handle</emphasis>. Several applications querying the same sub-device at
-      the same time will thus not interact with each other.</para>
-
-      <para>To find out whether a particular format is supported by the device,
-      applications use the &VIDIOC-SUBDEV-S-FMT; ioctl. Drivers verify and, if
-      needed, change the requested <structfield>format</structfield> based on
-      device requirements and return the possibly modified value. Applications
-      can then choose to try a different format or accept the returned value and
-      continue.</para>
-
-      <para>Formats returned by the driver during a negotiation iteration are
-      guaranteed to be supported by the device. In particular, drivers guarantee
-      that a returned format will not be further changed if passed to an
-      &VIDIOC-SUBDEV-S-FMT; call as-is (as long as external parameters, such as
-      formats on other pads or links' configuration are not changed).</para>
-
-      <para>Drivers automatically propagate formats inside sub-devices. When a
-      try or active format is set on a pad, corresponding formats on other pads
-      of the same sub-device can be modified by the driver. Drivers are free to
-      modify formats as required by the device. However, they should comply with
-      the following rules when possible:
-      <itemizedlist>
-        <listitem><para>Formats should be propagated from sink pads to source pads.
-       Modifying a format on a source pad should not modify the format on any
-       sink pad.</para></listitem>
-        <listitem><para>Sub-devices that scale frames using variable scaling factors
-       should reset the scale factors to default values when sink pads formats
-       are modified. If the 1:1 scaling ratio is supported, this means that
-       source pads formats should be reset to the sink pads formats.</para></listitem>
-      </itemizedlist>
-      </para>
-
-      <para>Formats are not propagated across links, as that would involve
-      propagating them from one sub-device file handle to another. Applications
-      must then take care to configure both ends of every link explicitly with
-      compatible formats. Identical formats on the two ends of a link are
-      guaranteed to be compatible. Drivers are free to accept different formats
-      matching device requirements as being compatible.</para>
-
-      <para><xref linkend="sample-pipeline-config" />
-      shows a sample configuration sequence for the pipeline described in
-      <xref linkend="pipeline-scaling" /> (table
-      columns list entity names and pad numbers).</para>
-
-      <table pgwide="0" frame="none" id="sample-pipeline-config">
-       <title>Sample Pipeline Configuration</title>
-       <tgroup cols="3">
-         <colspec colname="what"/>
-         <colspec colname="sensor-0" />
-         <colspec colname="frontend-0" />
-         <colspec colname="frontend-1" />
-         <colspec colname="scaler-0" />
-         <colspec colname="scaler-1" />
-         <thead>
-           <row>
-             <entry></entry>
-             <entry>Sensor/0</entry>
-             <entry>Frontend/0</entry>
-             <entry>Frontend/1</entry>
-             <entry>Scaler/0</entry>
-             <entry>Scaler/1</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row>
-             <entry>Initial state</entry>
-             <entry>2048x1536</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-           </row>
-           <row>
-             <entry>Configure frontend input</entry>
-             <entry>2048x1536</entry>
-             <entry><emphasis>2048x1536</emphasis></entry>
-             <entry><emphasis>2046x1534</emphasis></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-           </row>
-           <row>
-             <entry>Configure scaler input</entry>
-             <entry>2048x1536</entry>
-             <entry>2048x1536</entry>
-             <entry>2046x1534</entry>
-             <entry><emphasis>2046x1534</emphasis></entry>
-             <entry><emphasis>2046x1534</emphasis></entry>
-           </row>
-           <row>
-             <entry>Configure scaler output</entry>
-             <entry>2048x1536</entry>
-             <entry>2048x1536</entry>
-             <entry>2046x1534</entry>
-             <entry>2046x1534</entry>
-             <entry><emphasis>1280x960</emphasis></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <para>
-      <orderedlist>
-       <listitem><para>Initial state. The sensor output is set to its native 3MP
-       resolution. Resolutions on the host frontend and scaler input and output
-       pads are undefined.</para></listitem>
-       <listitem><para>The application configures the frontend input pad resolution to
-       2048x1536. The driver propagates the format to the frontend output pad.
-       Note that the propagated output format can be different, as in this case,
-       than the input format, as the hardware might need to crop pixels (for
-       instance when converting a Bayer filter pattern to RGB or YUV).</para></listitem>
-       <listitem><para>The application configures the scaler input pad resolution to
-       2046x1534 to match the frontend output resolution. The driver propagates
-       the format to the scaler output pad.</para></listitem>
-       <listitem><para>The application configures the scaler output pad resolution to
-       1280x960.</para></listitem>
-      </orderedlist>
-      </para>
-
-      <para>When satisfied with the try results, applications can set the active
-      formats by setting the <structfield>which</structfield> argument to
-      <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. Active formats are changed
-      exactly as try formats by drivers. To avoid modifying the hardware state
-      during format negotiation, applications should negotiate try formats first
-      and then modify the active settings using the try formats returned during
-      the last negotiation iteration. This guarantees that the active format
-      will be applied as-is by the driver without being modified.
-      </para>
-    </section>
-
-    <section>
-      <title>Cropping and scaling</title>
-
-      <para>Many sub-devices support cropping frames on their input or output
-      pads (or possible even on both). Cropping is used to select the area of
-      interest in an image, typically on a video sensor or video decoder. It can
-      also be used as part of digital zoom implementations to select the area of
-      the image that will be scaled up.</para>
-
-      <para>Crop settings are defined by a crop rectangle and represented in a
-      &v4l2-rect; by the coordinates of the top left corner and the rectangle
-      size. Both the coordinates and sizes are expressed in pixels.</para>
-
-      <para>The crop rectangle is retrieved and set using the
-      &VIDIOC-SUBDEV-G-CROP; and &VIDIOC-SUBDEV-S-CROP; ioctls. Like for pad
-      formats, drivers store try and active crop rectangles. The format
-      negotiation mechanism applies to crop settings as well.</para>
-
-      <para>On input pads, cropping is applied relatively to the current pad
-      format. The pad format represents the image size as received by the
-      sub-device from the previous block in the pipeline, and the crop rectangle
-      represents the sub-image that will be transmitted further inside the
-      sub-device for processing. The crop rectangle be entirely containted
-      inside the input image size.</para>
-
-      <para>Input crop rectangle are reset to their default value when the input
-      image format is modified. Drivers should use the input image size as the
-      crop rectangle default value, but hardware requirements may prevent this.
-      </para>
-
-      <para>Cropping behaviour on output pads is not defined.</para>
-
-    </section>
-  </section>
-
-  &sub-subdev-formats;
diff --git a/Documentation/DocBook/v4l/dev-teletext.xml b/Documentation/DocBook/v4l/dev-teletext.xml
deleted file mode 100644 (file)
index 414b1cf..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-  <title>Teletext Interface</title>
-
-  <para>This interface was aimed at devices receiving and demodulating
-Teletext data [<xref linkend="ets300706" />, <xref linkend="itu653" />], evaluating the
-Teletext packages and storing formatted pages in cache memory. Such
-devices are usually implemented as microcontrollers with serial
-interface (I<superscript>2</superscript>C) and could be found on old
-TV cards, dedicated Teletext decoding cards and home-brew devices
-connected to the PC parallel port.</para>
-
-  <para>The Teletext API was designed by Martin Buck. It was defined in
-the kernel header file <filename>linux/videotext.h</filename>, the
-specification is available from <ulink url="ftp://ftp.gwdg.de/pub/linux/misc/videotext/">
-ftp://ftp.gwdg.de/pub/linux/misc/videotext/</ulink>. (Videotext is the name of
-the German public television Teletext service.)</para>
-
-  <para>Eventually the Teletext API was integrated into the V4L API
-with character device file names <filename>/dev/vtx0</filename> to
-<filename>/dev/vtx31</filename>, device major number 81, minor numbers
-192 to 223.</para>
-
-  <para>However, teletext decoders were quickly replaced by more
-generic VBI demodulators and those dedicated teletext decoders no longer exist.
-For many years the vtx devices were still around, even though nobody used
-them. So the decision was made to finally remove support for the Teletext API in
-kernel 2.6.37.</para>
-
-  <para>Modern devices all use the <link linkend="raw-vbi">raw</link> or
-<link linkend="sliced">sliced</link> VBI API.</para>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/driver.xml b/Documentation/DocBook/v4l/driver.xml
deleted file mode 100644 (file)
index 1f7eea5..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-  <title>V4L2 Driver Programming</title>
-
-  <!-- This part defines the interface between the "videodev"
-    module and individual drivers. -->
-
-  <para>to do</para>
-<!--
-  <para>V4L2 is a two-layer driver system. The top layer is the "videodev"
-kernel module. When videodev initializes it registers as character device
-with major number 81, and it registers a set of file operations. All V4L2
-drivers are really clients of videodev, which calls V4L2 drivers through
-driver method functions. V4L2 drivers are also written as kernel modules.
-After probing the hardware they register one or more devices with
-videodev.</para>
-
-  <section id="driver-modules">
-    <title>Driver Modules</title>
-
-    <para>V4L2 driver modules must have an initialization function which is
-called after the module was loaded into kernel, an exit function whis is
-called before the module is removed.  When the driver is compiled into the
-kernel these functions called at system boot and shutdown time.</para>
-
-    <informalexample>
-      <programlisting>
-#include &lt;linux/module.h&gt;
-
-/* Export information about this module. For details and other useful
-   macros see <filename>linux/module.h</filename>. */
-MODULE_DESCRIPTION("my - driver for my hardware");
-MODULE_AUTHOR("Your name here");
-MODULE_LICENSE("GPL");
-
-static void
-my_module_exit (void)
-{
-       /* Free all resources allocated by my_module_init(). */
-}
-
-static int
-my_module_init (void)
-{
-       /* Bind the driver to the supported hardware, see
-          <link linkend="driver-pci"> and
-          <link linkend="driver-usb"> for examples. */
-
-       return 0; /* a negative value on error, 0 on success. */
-}
-
-/* Export module functions. */
-module_init (my_module_init);
-module_exit (my_module_exit);
-</programlisting>
-    </informalexample>
-
-    <para>Users can add parameters when kernel modules are inserted:</para>
-
-    <informalexample>
-      <programlisting>
-include &lt;linux/moduleparam.h&gt;
-
-static int my_option = 123;
-static int my_option_array[47];
-
-/* Export the symbol, an int, with access permissions 0664.
-   See <filename>linux/moduleparam.h</filename> for other types. */
-module_param (my_option, int, 0644);
-module_param_array (my_option_array, int, NULL, 0644);
-
-MODULE_PARM_DESC (my_option, "Does magic things, default 123");
-</programlisting>
-    </informalexample>
-
-    <para>One parameter should be supported by all V4L2 drivers, the minor
-number of the device it will register. Purpose is to predictably link V4L2
-drivers to device nodes if more than one video device is installed. Use the
-name of the device node followed by a "_nr" suffix, for example "video_nr"
-for <filename>/dev/video</filename>.</para>
-
-    <informalexample>
-      <programlisting>
-/* Minor number of the device, -1 to allocate the first unused. */
-static int video_nr = -1;
-
-module_param (video_nr, int, 0444);
-</programlisting>
-    </informalexample>
-  </section>
-
-  <section id="driver-pci">
-    <title>PCI Devices</title>
-
-    <para>PCI devices are initialized like this:</para>
-
-    <informalexample>
-      <programlisting>
-typedef struct {
-       /* State of one physical device. */
-} my_device;
-
-static int
-my_resume               (struct pci_dev *               pci_dev)
-{
-       /* Restore the suspended device to working state. */
-}
-
-static int
-my_suspend              (struct pci_dev *               pci_dev,
-                        pm_message_t                   state)
-{
-       /* This function is called before the system goes to sleep.
-          Stop all DMAs and disable interrupts, then put the device
-          into a low power state. For details see the kernel
-          sources under <filename>Documentation/power</filename>. */
-
-       return 0; /* a negative value on error, 0 on success. */
-}
-
-static void __devexit
-my_remove               (struct pci_dev *               pci_dev)
-{
-       my_device *my = pci_get_drvdata (pci_dev);
-
-       /* Describe me. */
-}
-
-static int __devinit
-my_probe                (struct pci_dev *               pci_dev,
-                        const struct pci_device_id *   pci_id)
-{
-       my_device *my;
-
-       /* Describe me. */
-
-       /* You can allocate per-device data here and store a pointer
-          to it in the pci_dev structure. */
-       my = ...;
-       pci_set_drvdata (pci_dev, my);
-
-       return 0; /* a negative value on error, 0 on success. */
-}
-
-/* A list of supported PCI devices. */
-static struct pci_device_id
-my_pci_device_ids [] = {
-       { PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-       { 0 } /* end of list */
-};
-
-/* Load our module if supported PCI devices are installed. */
-MODULE_DEVICE_TABLE (pci, my_pci_device_ids);
-
-static struct pci_driver
-my_pci_driver = {
-       .name     = "my",
-       .id_table = my_pci_device_ids,
-
-       .probe    = my_probe,
-       .remove   = __devexit_p (my_remove),
-
-       /* Power management functions. */
-       .suspend  = my_suspend,
-       .resume   = my_resume,
-};
-
-static void
-my_module_exit          (void)
-{
-       pci_unregister_driver (&my_pci_driver);
-}
-
-static int
-my_module_init          (void)
-{
-       return pci_register_driver (&my_pci_driver);
-}
-</programlisting>
-    </informalexample>
-  </section>
-
-  <section id="driver-usb">
-    <title>USB Devices</title>
-    <para>to do</para>
-  </section>
-  <section id="driver-registering">
-    <title>Registering V4L2 Drivers</title>
-
-    <para>After a V4L2 driver probed the hardware it registers one or more
-devices with the videodev module.</para>
-  </section>
-  <section id="driver-file-ops">
-    <title>File Operations</title>
-    <para>to do</para>
-  </section>
-  <section id="driver-internal-api">
-    <title>Internal API</title>
-    <para>to do</para>
-  </section>
--->
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/fdl-appendix.xml b/Documentation/DocBook/v4l/fdl-appendix.xml
deleted file mode 100644 (file)
index ae22394..0000000
+++ /dev/null
@@ -1,671 +0,0 @@
-<!--
-     The GNU Free Documentation License 1.1 in DocBook
-     Markup by Eric Baudais <baudais@okstate.edu>
-     Maintained by the GNOME Documentation Project
-     http://live.gnome.org/DocumentationProject
-     Version: 1.0.1
-     Last Modified: Nov 16, 2000
--->
-
-<appendix id="fdl">
-  <appendixinfo>
-    <releaseinfo>
-      Version 1.1, March 2000
-    </releaseinfo>
-    <copyright>
-      <year>2000</year><holder>Free Software Foundation, Inc.</holder>
-    </copyright>
-    <legalnotice id="fdl-legalnotice">
-      <para>
-       <address>Free Software Foundation, Inc. <street>59 Temple Place,
-       Suite 330</street>, <city>Boston</city>, <state>MA</state>
-       <postcode>02111-1307</postcode>  <country>USA</country></address>
-       Everyone is permitted to copy and distribute verbatim copies of this
-       license document, but changing it is not allowed.
-      </para>
-    </legalnotice>
-  </appendixinfo>
-  <title>GNU Free Documentation License</title>
-
-  <sect1 id="fdl-preamble">
-    <title>0. PREAMBLE</title>
-    <para>
-      The purpose of this License is to make a manual, textbook, or
-      other written document <quote>free</quote> in the sense of
-      freedom: to assure everyone the effective freedom to copy and
-      redistribute it, with or without modifying it, either
-      commercially or noncommercially. Secondarily, this License
-      preserves for the author and publisher a way to get credit for
-      their work, while not being considered responsible for
-      modifications made by others.
-    </para>
-
-    <para>
-      This License is a kind of <quote>copyleft</quote>, which means
-      that derivative works of the document must themselves be free in
-      the same sense. It complements the GNU General Public License,
-      which is a copyleft license designed for free software.
-    </para>
-
-    <para>
-      We have designed this License in order to use it for manuals for
-      free software, because free software needs free documentation: a
-      free program should come with manuals providing the same
-      freedoms that the software does. But this License is not limited
-      to software manuals; it can be used for any textual work,
-      regardless of subject matter or whether it is published as a
-      printed book. We recommend this License principally for works
-      whose purpose is instruction or reference.
-    </para>
-  </sect1>
-  <sect1 id="fdl-section1">
-    <title>1. APPLICABILITY AND DEFINITIONS</title>
-    <para id="fdl-document">
-      This License applies to any manual or other work that contains a
-      notice placed by the copyright holder saying it can be
-      distributed under the terms of this License. The
-      <quote>Document</quote>, below, refers to any such manual or
-      work. Any member of the public is a licensee, and is addressed
-      as <quote>you</quote>.
-    </para>
-
-    <para id="fdl-modified">
-      A <quote>Modified Version</quote> of the Document means any work
-      containing the Document or a portion of it, either copied
-      verbatim, or with modifications and/or translated into another
-      language.
-    </para>
-
-    <para id="fdl-secondary">
-      A <quote>Secondary Section</quote> is a named appendix or a
-      front-matter section of the <link
-      linkend="fdl-document">Document</link> that deals exclusively
-      with the relationship of the publishers or authors of the
-      Document to the Document's overall subject (or to related
-      matters) and contains nothing that could fall directly within
-      that overall subject. (For example, if the Document is in part a
-      textbook of mathematics, a Secondary Section may not explain any
-      mathematics.)  The relationship could be a matter of historical
-      connection with the subject or with related matters, or of
-      legal, commercial, philosophical, ethical or political position
-      regarding them.
-    </para>
-
-    <para id="fdl-invariant">
-      The <quote>Invariant Sections</quote> are certain <link
-      linkend="fdl-secondary"> Secondary Sections</link> whose titles
-      are designated, as being those of Invariant Sections, in the
-      notice that says that the <link
-      linkend="fdl-document">Document</link> is released under this
-      License.
-    </para>
-
-    <para id="fdl-cover-texts">
-      The <quote>Cover Texts</quote> are certain short passages of
-      text that are listed, as Front-Cover Texts or Back-Cover Texts,
-      in the notice that says that the <link
-      linkend="fdl-document">Document</link> is released under this
-      License.
-    </para>
-
-    <para id="fdl-transparent">
-      A <quote>Transparent</quote> copy of the <link
-      linkend="fdl-document"> Document</link> means a machine-readable
-      copy, represented in a format whose specification is available
-      to the general public, whose contents can be viewed and edited
-      directly and straightforwardly with generic text editors or (for
-      images composed of pixels) generic paint programs or (for
-      drawings) some widely available drawing editor, and that is
-      suitable for input to text formatters or for automatic
-      translation to a variety of formats suitable for input to text
-      formatters. A copy made in an otherwise Transparent file format
-      whose markup has been designed to thwart or discourage
-      subsequent modification by readers is not Transparent.  A copy
-      that is not <quote>Transparent</quote> is called
-      <quote>Opaque</quote>.
-    </para>
-
-    <para>
-      Examples of suitable formats for Transparent copies include
-      plain ASCII without markup, Texinfo input format, LaTeX input
-      format, SGML or XML using a publicly available DTD, and
-      standard-conforming simple HTML designed for human
-      modification. Opaque formats include PostScript, PDF,
-      proprietary formats that can be read and edited only by
-      proprietary word processors, SGML or XML for which the DTD
-      and/or processing tools are not generally available, and the
-      machine-generated HTML produced by some word processors for
-      output purposes only.
-    </para>
-
-    <para id="fdl-title-page">
-      The <quote>Title Page</quote> means, for a printed book, the
-      title page itself, plus such following pages as are needed to
-      hold, legibly, the material this License requires to appear in
-      the title page. For works in formats which do not have any title
-      page as such, <quote>Title Page</quote> means the text near the
-      most prominent appearance of the work's title, preceding the
-      beginning of the body of the text.
-    </para>
-  </sect1>
-
-  <sect1 id="fdl-section2">
-    <title>2. VERBATIM COPYING</title>
-    <para>
-      You may copy and distribute the <link
-      linkend="fdl-document">Document</link> in any medium, either
-      commercially or noncommercially, provided that this License, the
-      copyright notices, and the license notice saying this License
-      applies to the Document are reproduced in all copies, and that
-      you add no other conditions whatsoever to those of this
-      License. You may not use technical measures to obstruct or
-      control the reading or further copying of the copies you make or
-      distribute. However, you may accept compensation in exchange for
-      copies. If you distribute a large enough number of copies you
-      must also follow the conditions in <link
-      linkend="fdl-section3">section 3</link>.
-    </para>
-
-    <para>
-      You may also lend copies, under the same conditions stated
-      above, and you may publicly display copies.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section3">
-    <title>3. COPYING IN QUANTITY</title>
-    <para>
-      If you publish printed copies of the <link
-      linkend="fdl-document">Document</link> numbering more than 100,
-      and the Document's license notice requires <link
-      linkend="fdl-cover-texts">Cover Texts</link>, you must enclose
-      the copies in covers that carry, clearly and legibly, all these
-      Cover Texts: Front-Cover Texts on the front cover, and
-      Back-Cover Texts on the back cover. Both covers must also
-      clearly and legibly identify you as the publisher of these
-      copies. The front cover must present the full title with all
-      words of the title equally prominent and visible. You may add
-      other material on the covers in addition. Copying with changes
-      limited to the covers, as long as they preserve the title of the
-      <link linkend="fdl-document">Document</link> and satisfy these
-      conditions, can be treated as verbatim copying in other
-      respects.
-    </para>
-
-    <para>
-      If the required texts for either cover are too voluminous to fit
-      legibly, you should put the first ones listed (as many as fit
-      reasonably) on the actual cover, and continue the rest onto
-      adjacent pages.
-    </para>
-
-    <para>
-      If you publish or distribute <link
-      linkend="fdl-transparent">Opaque</link> copies of the <link
-      linkend="fdl-document">Document</link> numbering more than 100,
-      you must either include a machine-readable <link
-      linkend="fdl-transparent">Transparent</link> copy along with
-      each Opaque copy, or state in or with each Opaque copy a
-      publicly-accessible computer-network location containing a
-      complete Transparent copy of the Document, free of added
-      material, which the general network-using public has access to
-      download anonymously at no charge using public-standard network
-      protocols. If you use the latter option, you must take
-      reasonably prudent steps, when you begin distribution of Opaque
-      copies in quantity, to ensure that this Transparent copy will
-      remain thus accessible at the stated location until at least one
-      year after the last time you distribute an Opaque copy (directly
-      or through your agents or retailers) of that edition to the
-      public.
-    </para>
-
-    <para>
-      It is requested, but not required, that you contact the authors
-      of the <link linkend="fdl-document">Document</link> well before
-      redistributing any large number of copies, to give them a chance
-      to provide you with an updated version of the Document.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section4">
-    <title>4. MODIFICATIONS</title>
-    <para>
-      You may copy and distribute a <link
-      linkend="fdl-modified">Modified Version</link> of the <link
-      linkend="fdl-document">Document</link> under the conditions of
-      sections <link linkend="fdl-section2">2</link> and <link
-      linkend="fdl-section3">3</link> above, provided that you release
-      the Modified Version under precisely this License, with the
-      Modified Version filling the role of the Document, thus
-      licensing distribution and modification of the Modified Version
-      to whoever possesses a copy of it. In addition, you must do
-      these things in the Modified Version:
-    </para>
-
-    <itemizedlist mark="opencircle">
-      <listitem>
-       <formalpara>
-         <title>A</title>
-         <para>
-           Use in the <link linkend="fdl-title-page">Title
-           Page</link> (and on the covers, if any) a title distinct
-           from that of the <link
-           linkend="fdl-document">Document</link>, and from those of
-           previous versions (which should, if there were any, be
-           listed in the History section of the Document). You may
-           use the same title as a previous version if the original
-           publisher of that version gives permission.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>B</title>
-         <para>
-           List on the <link linkend="fdl-title-page">Title
-           Page</link>, as authors, one or more persons or entities
-           responsible for authorship of the modifications in the
-           <link linkend="fdl-modified">Modified Version</link>,
-           together with at least five of the principal authors of
-           the <link linkend="fdl-document">Document</link> (all of
-           its principal authors, if it has less than five).
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>C</title>
-         <para>
-           State on the <link linkend="fdl-title-page">Title
-           Page</link> the name of the publisher of the <link
-           linkend="fdl-modified">Modified Version</link>, as the
-           publisher.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>D</title>
-         <para>
-           Preserve all the copyright notices of the <link
-           linkend="fdl-document">Document</link>.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>E</title>
-         <para>
-           Add an appropriate copyright notice for your modifications
-           adjacent to the other copyright notices.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>F</title>
-         <para>
-           Include, immediately after the copyright notices, a
-           license notice giving the public permission to use the
-           <link linkend="fdl-modified">Modified Version</link> under
-           the terms of this License, in the form shown in the
-           Addendum below.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>G</title>
-         <para>
-           Preserve in that license notice the full lists of <link
-           linkend="fdl-invariant"> Invariant Sections</link> and
-           required <link linkend="fdl-cover-texts">Cover
-           Texts</link> given in the <link
-           linkend="fdl-document">Document's</link> license notice.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>H</title>
-         <para>
-           Include an unaltered copy of this License.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>I</title>
-         <para>
-           Preserve the section entitled <quote>History</quote>, and
-           its title, and add to it an item stating at least the
-           title, year, new authors, and publisher of the <link
-           linkend="fdl-modified">Modified Version </link>as given on
-           the <link linkend="fdl-title-page">Title Page</link>.  If
-           there is no section entitled <quote>History</quote> in the
-           <link linkend="fdl-document">Document</link>, create one
-           stating the title, year, authors, and publisher of the
-           Document as given on its Title Page, then add an item
-           describing the Modified Version as stated in the previous
-           sentence.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>J</title>
-         <para>
-           Preserve the network location, if any, given in the <link
-           linkend="fdl-document">Document</link> for public access
-           to a <link linkend="fdl-transparent">Transparent</link>
-           copy of the Document, and likewise the network locations
-           given in the Document for previous versions it was based
-           on. These may be placed in the <quote>History</quote>
-           section.  You may omit a network location for a work that
-           was published at least four years before the Document
-           itself, or if the original publisher of the version it
-           refers to gives permission.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>K</title>
-         <para>
-           In any section entitled <quote>Acknowledgements</quote> or
-           <quote>Dedications</quote>, preserve the section's title,
-           and preserve in the section all the substance and tone of
-           each of the contributor acknowledgements and/or
-           dedications given therein.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>L</title>
-         <para>
-           Preserve all the <link linkend="fdl-invariant">Invariant
-           Sections</link> of the <link
-           linkend="fdl-document">Document</link>, unaltered in their
-           text and in their titles.  Section numbers or the
-           equivalent are not considered part of the section titles.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>M</title>
-         <para>
-           Delete any section entitled
-           <quote>Endorsements</quote>. Such a section may not be
-           included in the <link linkend="fdl-modified">Modified
-           Version</link>.
-         </para>
-       </formalpara>
-      </listitem>
-
-      <listitem>
-       <formalpara>
-         <title>N</title>
-         <para>
-           Do not retitle any existing section as
-           <quote>Endorsements</quote> or to conflict in title with
-           any <link linkend="fdl-invariant">Invariant
-           Section</link>.
-         </para>
-       </formalpara>
-      </listitem>
-    </itemizedlist>
-
-    <para>
-      If the <link linkend="fdl-modified">Modified Version</link>
-      includes new front-matter sections or appendices that qualify as
-      <link linkend="fdl-secondary">Secondary Sections</link> and
-      contain no material copied from the Document, you may at your
-      option designate some or all of these sections as invariant. To
-      do this, add their titles to the list of <link
-      linkend="fdl-invariant">Invariant Sections</link> in the
-      Modified Version's license notice.  These titles must be
-      distinct from any other section titles.
-    </para>
-
-    <para>
-      You may add a section entitled <quote>Endorsements</quote>,
-      provided it contains nothing but endorsements of your <link
-      linkend="fdl-modified">Modified Version</link> by various
-      parties--for example, statements of peer review or that the text
-      has been approved by an organization as the authoritative
-      definition of a standard.
-    </para>
-
-    <para>
-      You may add a passage of up to five words as a <link
-      linkend="fdl-cover-texts">Front-Cover Text</link>, and a passage
-      of up to 25 words as a <link
-      linkend="fdl-cover-texts">Back-Cover Text</link>, to the end of
-      the list of <link linkend="fdl-cover-texts">Cover Texts</link>
-      in the <link linkend="fdl-modified">Modified Version</link>.
-      Only one passage of Front-Cover Text and one of Back-Cover Text
-      may be added by (or through arrangements made by) any one
-      entity. If the <link linkend="fdl-document">Document</link>
-      already includes a cover text for the same cover, previously
-      added by you or by arrangement made by the same entity you are
-      acting on behalf of, you may not add another; but you may
-      replace the old one, on explicit permission from the previous
-      publisher that added the old one.
-    </para>
-
-    <para>
-      The author(s) and publisher(s) of the <link
-      linkend="fdl-document">Document</link> do not by this License
-      give permission to use their names for publicity for or to
-      assert or imply endorsement of any <link
-      linkend="fdl-modified">Modified Version </link>.
-    </para>
-  </sect1>
-
-  <sect1 id="fdl-section5">
-    <title>5. COMBINING DOCUMENTS</title>
-    <para>
-      You may combine the <link linkend="fdl-document">Document</link>
-      with other documents released under this License, under the
-      terms defined in <link linkend="fdl-section4">section 4</link>
-      above for modified versions, provided that you include in the
-      combination all of the <link linkend="fdl-invariant">Invariant
-      Sections</link> of all of the original documents, unmodified,
-      and list them all as Invariant Sections of your combined work in
-      its license notice.
-    </para>
-
-    <para>
-      The combined work need only contain one copy of this License,
-      and multiple identical <link linkend="fdl-invariant">Invariant
-      Sections</link> may be replaced with a single copy. If there are
-      multiple Invariant Sections with the same name but different
-      contents, make the title of each such section unique by adding
-      at the end of it, in parentheses, the name of the original
-      author or publisher of that section if known, or else a unique
-      number. Make the same adjustment to the section titles in the
-      list of Invariant Sections in the license notice of the combined
-      work.
-    </para>
-
-    <para>
-      In the combination, you must combine any sections entitled
-      <quote>History</quote> in the various original documents,
-      forming one section entitled <quote>History</quote>; likewise
-      combine any sections entitled <quote>Acknowledgements</quote>,
-      and any sections entitled <quote>Dedications</quote>.  You must
-      delete all sections entitled <quote>Endorsements.</quote>
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section6">
-    <title>6. COLLECTIONS OF DOCUMENTS</title>
-    <para>
-      You may make a collection consisting of the <link
-      linkend="fdl-document">Document</link> and other documents
-      released under this License, and replace the individual copies
-      of this License in the various documents with a single copy that
-      is included in the collection, provided that you follow the
-      rules of this License for verbatim copying of each of the
-      documents in all other respects.
-    </para>
-
-    <para>
-      You may extract a single document from such a collection, and
-      dispbibute it individually under this License, provided you
-      insert a copy of this License into the extracted document, and
-      follow this License in all other respects regarding verbatim
-      copying of that document.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section7">
-    <title>7. AGGREGATION WITH INDEPENDENT WORKS</title>
-    <para>
-      A compilation of the <link
-      linkend="fdl-document">Document</link> or its derivatives with
-      other separate and independent documents or works, in or on a
-      volume of a storage or distribution medium, does not as a whole
-      count as a <link linkend="fdl-modified">Modified Version</link>
-      of the Document, provided no compilation copyright is claimed
-      for the compilation.  Such a compilation is called an
-      <quote>aggregate</quote>, and this License does not apply to the
-      other self-contained works thus compiled with the Document , on
-      account of their being thus compiled, if they are not themselves
-      derivative works of the Document.  If the <link
-      linkend="fdl-cover-texts">Cover Text</link> requirement of <link
-      linkend="fdl-section3">section 3</link> is applicable to these
-      copies of the Document, then if the Document is less than one
-      quarter of the entire aggregate, the Document's Cover Texts may
-      be placed on covers that surround only the Document within the
-      aggregate. Otherwise they must appear on covers around the whole
-      aggregate.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section8">
-    <title>8. TRANSLATION</title>
-    <para>
-      Translation is considered a kind of modification, so you may
-      distribute translations of the <link
-      linkend="fdl-document">Document</link> under the terms of <link
-      linkend="fdl-section4">section 4</link>. Replacing <link
-      linkend="fdl-invariant"> Invariant Sections</link> with
-      translations requires special permission from their copyright
-      holders, but you may include translations of some or all
-      Invariant Sections in addition to the original versions of these
-      Invariant Sections. You may include a translation of this
-      License provided that you also include the original English
-      version of this License. In case of a disagreement between the
-      translation and the original English version of this License,
-      the original English version will prevail.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section9">
-    <title>9. TERMINATION</title>
-    <para>
-      You may not copy, modify, sublicense, or distribute the <link
-      linkend="fdl-document">Document</link> except as expressly
-      provided for under this License. Any other attempt to copy,
-      modify, sublicense or distribute the Document is void, and will
-      automatically terminate your rights under this License. However,
-      parties who have received copies, or rights, from you under this
-      License will not have their licenses terminated so long as such
-      parties remain in full compliance.
-    </para>
-    </sect1>
-
-  <sect1 id="fdl-section10">
-    <title>10. FUTURE REVISIONS OF THIS LICENSE</title>
-    <para>
-      The <ulink type="http"
-      url="http://www.gnu.org/fsf/fsf.html">Free Software
-      Foundation</ulink> may publish new, revised versions of the GNU
-      Free Documentation License from time to time. Such new versions
-      will be similar in spirit to the present version, but may differ
-      in detail to address new problems or concerns. See <ulink
-      type="http"
-      url="http://www.gnu.org/copyleft">http://www.gnu.org/copyleft/</ulink>.
-    </para>
-
-    <para>
-      Each version of the License is given a distinguishing version
-      number. If the <link linkend="fdl-document">Document</link>
-      specifies that a particular numbered version of this License
-      <quote>or any later version</quote> applies to it, you have the
-      option of following the terms and conditions either of that
-      specified version or of any later version that has been
-      published (not as a draft) by the Free Software Foundation. If
-      the Document does not specify a version number of this License,
-      you may choose any version ever published (not as a draft) by
-      the Free Software Foundation.
-    </para>
-  </sect1>
-
-  <sect1 id="fdl-using">
-    <title>Addendum</title>
-    <para>
-      To use this License in a document you have written, include a copy of
-      the License in the document and put the following copyright and
-      license notices just after the title page:
-    </para>
-
-    <blockquote>
-      <para>
-       Copyright &copy; YEAR YOUR NAME.
-      </para>
-      <para>
-       Permission is granted to copy, distribute and/or modify this
-       document under the terms of the GNU Free Documentation
-       License, Version 1.1 or any later version published by the
-       Free Software Foundation; with the <link
-       linkend="fdl-invariant">Invariant Sections</link> being LIST
-       THEIR TITLES, with the <link
-       linkend="fdl-cover-texts">Front-Cover Texts</link> being LIST,
-       and with the <link linkend="fdl-cover-texts">Back-Cover
-       Texts</link> being LIST.  A copy of the license is included in
-       the section entitled <quote>GNU Free Documentation
-       License</quote>.
-      </para>
-    </blockquote>
-
-    <para>
-      If you have no <link linkend="fdl-invariant">Invariant
-      Sections</link>, write <quote>with no Invariant Sections</quote>
-      instead of saying which ones are invariant.  If you have no
-      <link linkend="fdl-cover-texts">Front-Cover Texts</link>, write
-      <quote>no Front-Cover Texts</quote> instead of
-      <quote>Front-Cover Texts being LIST</quote>; likewise for <link
-      linkend="fdl-cover-texts">Back-Cover Texts</link>.
-    </para>
-
-    <para>
-      If your document contains nontrivial examples of program code,
-      we recommend releasing these examples in parallel under your
-      choice of free software license, such as the <ulink type="http"
-      url="http://www.gnu.org/copyleft/gpl.html"> GNU General Public
-      License</ulink>, to permit their use in free software.
-    </para>
-  </sect1>
-</appendix>
-
-
-
-
-
-
diff --git a/Documentation/DocBook/v4l/fieldseq_bt.gif b/Documentation/DocBook/v4l/fieldseq_bt.gif
deleted file mode 100644 (file)
index 60e8569..0000000
Binary files a/Documentation/DocBook/v4l/fieldseq_bt.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/fieldseq_bt.pdf b/Documentation/DocBook/v4l/fieldseq_bt.pdf
deleted file mode 100644 (file)
index 26598b2..0000000
Binary files a/Documentation/DocBook/v4l/fieldseq_bt.pdf and /dev/null differ
diff --git a/Documentation/DocBook/v4l/fieldseq_tb.gif b/Documentation/DocBook/v4l/fieldseq_tb.gif
deleted file mode 100644 (file)
index 718492f..0000000
Binary files a/Documentation/DocBook/v4l/fieldseq_tb.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/fieldseq_tb.pdf b/Documentation/DocBook/v4l/fieldseq_tb.pdf
deleted file mode 100644 (file)
index 4965b22..0000000
Binary files a/Documentation/DocBook/v4l/fieldseq_tb.pdf and /dev/null differ
diff --git a/Documentation/DocBook/v4l/func-close.xml b/Documentation/DocBook/v4l/func-close.xml
deleted file mode 100644 (file)
index dfb41cb..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-<refentry id="func-close">
-  <refmeta>
-    <refentrytitle>V4L2 close()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-close</refname>
-    <refpurpose>Close a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>close</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Closes the device. Any I/O in progress is terminated and
-resources associated with the file descriptor are freed. However data
-format parameters, current input or output, control values or other
-properties remain unchanged.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>The function returns <returnvalue>0</returnvalue> on
-success, <returnvalue>-1</returnvalue> on failure and the
-<varname>errno</varname> is set appropriately. Possible error
-codes:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid open file
-descriptor.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/func-ioctl.xml b/Documentation/DocBook/v4l/func-ioctl.xml
deleted file mode 100644 (file)
index b60fd37..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-<refentry id="func-ioctl">
-  <refmeta>
-    <refentrytitle>V4L2 ioctl()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-ioctl</refname>
-    <refpurpose>Program a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>void *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>V4L2 ioctl request code as defined in the <filename>videodev2.h</filename> header file, for example
-VIDIOC_QUERYCAP.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to a function parameter, usually a structure.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The <function>ioctl()</function> function is used to program
-V4L2 devices. The argument <parameter>fd</parameter> must be an open
-file descriptor. An ioctl <parameter>request</parameter> has encoded
-in it whether the argument is an input, output or read/write
-parameter, and the size of the argument <parameter>argp</parameter> in
-bytes. Macros and defines specifying V4L2 ioctl requests are located
-in the <filename>videodev2.h</filename> header file.
-Applications should use their own copy, not include the version in the
-kernel sources on the system they compile on. All V4L2 ioctl requests,
-their respective function and parameters are specified in <xref
-       linkend="user-func" />.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success the <function>ioctl()</function> function returns
-<returnvalue>0</returnvalue> and does not reset the
-<varname>errno</varname> variable. On failure
-<returnvalue>-1</returnvalue> is returned, when the ioctl takes an
-output or read/write parameter it remains unmodified, and the
-<varname>errno</varname> variable is set appropriately. See below for
-possible error codes. Generic errors like <errorcode>EBADF</errorcode>
-or <errorcode>EFAULT</errorcode> are not listed in the sections
-discussing individual ioctl requests.</para>
-    <para>Note ioctls may return undefined error codes. Since errors
-may have side effects such as a driver reset applications should
-abort on unexpected errors.</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid open file
-descriptor.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The property cannot be changed right now. Typically
-this error code is returned when I/O is in progress or the driver
-supports multiple opens and another process locked the property.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>argp</parameter> references an inaccessible
-memory area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOTTY</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is  not  associated  with  a
-character special device.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>request</parameter> or the data pointed
-to by <parameter>argp</parameter> is not valid. This is a very common
-error code, see the individual ioctl requests listed in <xref
-             linkend="user-func" /> for actual causes.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Not enough physical or virtual memory was available to
-complete the request.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ERANGE</errorcode></term>
-       <listitem>
-         <para>The application attempted to set a control with the
-&VIDIOC-S-CTRL; ioctl to a value which is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/func-mmap.xml b/Documentation/DocBook/v4l/func-mmap.xml
deleted file mode 100644 (file)
index 786732b..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-<refentry id="func-mmap">
-  <refmeta>
-    <refentrytitle>V4L2 mmap()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-mmap</refname>
-    <refpurpose>Map device memory into application address space</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>
-#include &lt;unistd.h&gt;
-#include &lt;sys/mman.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>void *<function>mmap</function></funcdef>
-       <paramdef>void *<parameter>start</parameter></paramdef>
-       <paramdef>size_t <parameter>length</parameter></paramdef>
-       <paramdef>int <parameter>prot</parameter></paramdef>
-       <paramdef>int <parameter>flags</parameter></paramdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>off_t <parameter>offset</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-    <variablelist>
-      <varlistentry>
-       <term><parameter>start</parameter></term>
-       <listitem>
-         <para>Map the buffer to this address in the
-application's address space. When the <constant>MAP_FIXED</constant>
-flag is specified, <parameter>start</parameter> must be a multiple of the
-pagesize and mmap will fail when the specified address
-cannot be used. Use of this option is discouraged; applications should
-just specify a <constant>NULL</constant> pointer here.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>length</parameter></term>
-       <listitem>
-         <para>Length of the memory area to map. This must be the
-same value as returned by the driver in the &v4l2-buffer;
-<structfield>length</structfield> field for the
-single-planar API, and the same value as returned by the driver
-in the &v4l2-plane; <structfield>length</structfield> field for the
-multi-planar API.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>prot</parameter></term>
-       <listitem>
-         <para>The <parameter>prot</parameter> argument describes the
-desired memory protection. Regardless of the device type and the
-direction of data exchange it should be set to
-<constant>PROT_READ</constant> | <constant>PROT_WRITE</constant>,
-permitting read and write access to image buffers. Drivers should
-support at least this combination of flags. Note the Linux
-<filename>video-buf</filename> kernel module, which is used by the
-bttv, saa7134, saa7146, cx88 and vivi driver supports only
-<constant>PROT_READ</constant> | <constant>PROT_WRITE</constant>. When
-the driver does not support the desired protection the
-<function>mmap()</function> function fails.</para>
-         <para>Note device memory accesses (&eg; the memory on a
-graphics card with video capturing hardware) may incur a performance
-penalty compared to main memory accesses, or reads may be
-significantly slower than writes or vice versa. Other I/O methods may
-be more efficient in this case.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>flags</parameter></term>
-       <listitem>
-         <para>The <parameter>flags</parameter> parameter
-specifies the type of the mapped object, mapping options and whether
-modifications made to the mapped copy of the page are private to the
-process or are to be shared with other references.</para>
-         <para><constant>MAP_FIXED</constant> requests that the
-driver selects no other address than the one specified. If the
-specified address cannot be used, <function>mmap()</function> will fail. If
-<constant>MAP_FIXED</constant> is specified,
-<parameter>start</parameter> must be a multiple of the pagesize. Use
-of this option is discouraged.</para>
-         <para>One of the <constant>MAP_SHARED</constant> or
-<constant>MAP_PRIVATE</constant> flags must be set.
-<constant>MAP_SHARED</constant> allows applications to share the
-mapped memory with other (&eg; child-) processes. Note the Linux
-<filename>video-buf</filename> module which is used by the bttv,
-saa7134, saa7146, cx88 and vivi driver supports only
-<constant>MAP_SHARED</constant>. <constant>MAP_PRIVATE</constant>
-requests copy-on-write semantics. V4L2 applications should not set the
-<constant>MAP_PRIVATE</constant>, <constant>MAP_DENYWRITE</constant>,
-<constant>MAP_EXECUTABLE</constant> or <constant>MAP_ANON</constant>
-flag.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>offset</parameter></term>
-       <listitem>
-         <para>Offset of the buffer in device memory. This must be the
-same value as returned by the driver in the &v4l2-buffer;
-<structfield>m</structfield> union <structfield>offset</structfield> field for
-the single-planar API, and the same value as returned by the driver
-in the &v4l2-plane; <structfield>m</structfield> union
-<structfield>mem_offset</structfield> field for the multi-planar API.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The <function>mmap()</function> function asks to map
-<parameter>length</parameter> bytes starting at
-<parameter>offset</parameter> in the memory of the device specified by
-<parameter>fd</parameter> into the application address space,
-preferably at address <parameter>start</parameter>. This latter
-address is a hint only, and is usually specified as 0.</para>
-
-    <para>Suitable length and offset parameters are queried with the
-&VIDIOC-QUERYBUF; ioctl. Buffers must be allocated with the
-&VIDIOC-REQBUFS; ioctl before they can be queried.</para>
-
-    <para>To unmap buffers the &func-munmap; function is used.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success <function>mmap()</function> returns a pointer to
-the mapped buffer. On error <constant>MAP_FAILED</constant> (-1) is
-returned, and the <varname>errno</varname> variable is set
-appropriately. Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid file
-descriptor.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is
-not open for reading and writing.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>start</parameter> or
-<parameter>length</parameter> or <parameter>offset</parameter> are not
-suitable. (E.&nbsp;g. they are too large, or not aligned on a
-<constant>PAGESIZE</constant> boundary.)</para>
-         <para>The <parameter>flags</parameter> or
-<parameter>prot</parameter> value is not supported.</para>
-         <para>No buffers have been allocated with the
-&VIDIOC-REQBUFS; ioctl.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Not enough physical or virtual memory was available to
-complete the request.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/func-munmap.xml b/Documentation/DocBook/v4l/func-munmap.xml
deleted file mode 100644 (file)
index e2c4190..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-<refentry id="func-munmap">
-  <refmeta>
-    <refentrytitle>V4L2 munmap()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-munmap</refname>
-    <refpurpose>Unmap device memory</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>
-#include &lt;unistd.h&gt;
-#include &lt;sys/mman.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>munmap</function></funcdef>
-       <paramdef>void *<parameter>start</parameter></paramdef>
-       <paramdef>size_t <parameter>length</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-  <refsect1>
-    <title>Arguments</title>
-    <variablelist>
-      <varlistentry>
-       <term><parameter>start</parameter></term>
-       <listitem>
-         <para>Address of the mapped buffer as returned by the
-&func-mmap; function.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>length</parameter></term>
-       <listitem>
-         <para>Length of the mapped buffer. This must be the same
-value as given to <function>mmap()</function> and returned by the
-driver in the &v4l2-buffer; <structfield>length</structfield>
-field for the single-planar API and in the &v4l2-plane;
-<structfield>length</structfield> field for the multi-planar API.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Unmaps a previously with the &func-mmap; function mapped
-buffer and frees it, if possible. <!-- ? This function (not freeing)
-has no impact on I/O in progress, specifically it does not imply
-&VIDIOC-STREAMOFF; to terminate I/O. Unmapped buffers can still be
-enqueued, dequeued or queried, they are just not accessible by the
-application.--></para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success <function>munmap()</function> returns 0, on
-failure -1 and the <varname>errno</varname> variable is set
-appropriately:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>start</parameter> or
-<parameter>length</parameter> is incorrect, or no buffers have been
-mapped yet.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/func-open.xml b/Documentation/DocBook/v4l/func-open.xml
deleted file mode 100644 (file)
index 7595d07..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-<refentry id="func-open">
-  <refmeta>
-    <refentrytitle>V4L2 open()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-open</refname>
-    <refpurpose>Open a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>open</function></funcdef>
-       <paramdef>const char *<parameter>device_name</parameter></paramdef>
-       <paramdef>int <parameter>flags</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>device_name</parameter></term>
-       <listitem>
-         <para>Device to be opened.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>flags</parameter></term>
-       <listitem>
-         <para>Open flags. Access mode must be
-<constant>O_RDWR</constant>. This is just a technicality, input devices
-still support only reading and output devices only writing.</para>
-         <para>When the <constant>O_NONBLOCK</constant> flag is
-given, the read() function and the &VIDIOC-DQBUF; ioctl will return
-the &EAGAIN; when no data is available or no buffer is in the driver
-outgoing queue, otherwise these functions block until data becomes
-available. All V4L2 drivers exchanging data with applications must
-support the <constant>O_NONBLOCK</constant> flag.</para>
-         <para>Other flags have no effect.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>Description</title>
-
-    <para>To open a V4L2 device applications call
-<function>open()</function> with the desired device name. This
-function has no side effects; all data format parameters, current
-input or output, control values or other properties remain unchanged.
-At the first <function>open()</function> call after loading the driver
-they will be reset to default values, drivers are never in an
-undefined state.</para>
-  </refsect1>
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success <function>open</function> returns the new file
-descriptor. On error -1 is returned, and the <varname>errno</varname>
-variable is set appropriately. Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para>The caller has no permission to access the
-device.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver does not support multiple opens and the
-device is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENXIO</errorcode></term>
-       <listitem>
-         <para>No device corresponding to this device special file
-exists.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Not enough kernel memory was available to complete the
-request.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EMFILE</errorcode></term>
-       <listitem>
-         <para>The  process  already  has  the  maximum number of
-files open.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENFILE</errorcode></term>
-       <listitem>
-         <para>The limit on the total number of files open on the
-system has been reached.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/func-poll.xml b/Documentation/DocBook/v4l/func-poll.xml
deleted file mode 100644 (file)
index ec3c718..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-<refentry id="func-poll">
-  <refmeta>
-    <refentrytitle>V4L2 poll()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-poll</refname>
-    <refpurpose>Wait for some event on a file descriptor</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;sys/poll.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>poll</function></funcdef>
-       <paramdef>struct pollfd *<parameter>ufds</parameter></paramdef>
-       <paramdef>unsigned int <parameter>nfds</parameter></paramdef>
-       <paramdef>int <parameter>timeout</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>With the <function>poll()</function> function applications
-can suspend execution until the driver has captured data or is ready
-to accept data for output.</para>
-
-    <para>When streaming I/O has been negotiated this function waits
-until a buffer has been filled or displayed and can be dequeued with
-the &VIDIOC-DQBUF; ioctl. When buffers are already in the outgoing
-queue of the driver the function returns immediately.</para>
-
-    <para>On success <function>poll()</function> returns the number of
-file descriptors that have been selected (that is, file descriptors
-for which the <structfield>revents</structfield> field of the
-respective <structname>pollfd</structname> structure is non-zero).
-Capture devices set the <constant>POLLIN</constant> and
-<constant>POLLRDNORM</constant> flags in the
-<structfield>revents</structfield> field, output devices the
-<constant>POLLOUT</constant> and <constant>POLLWRNORM</constant>
-flags. When the function timed out it returns a value of zero, on
-failure it returns <returnvalue>-1</returnvalue> and the
-<varname>errno</varname> variable is set appropriately. When the
-application did not call &VIDIOC-QBUF; or &VIDIOC-STREAMON; yet the
-<function>poll()</function> function succeeds, but sets the
-<constant>POLLERR</constant> flag in the
-<structfield>revents</structfield> field.</para>
-
-    <para>When use of the <function>read()</function> function has
-been negotiated and the driver does not capture yet, the
-<function>poll</function> function starts capturing. When that fails
-it returns a <constant>POLLERR</constant> as above. Otherwise it waits
-until data has been captured and can be read. When the driver captures
-continuously (as opposed to, for example, still images) the function
-may return immediately.</para>
-
-    <para>When use of the <function>write()</function> function has
-been negotiated the <function>poll</function> function just waits
-until the driver is ready for a non-blocking
-<function>write()</function> call.</para>
-
-    <para>All drivers implementing the <function>read()</function> or
-<function>write()</function> function or streaming I/O must also
-support the <function>poll()</function> function.</para>
-
-    <para>For more details see the
-<function>poll()</function> manual page.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success, <function>poll()</function> returns the number
-structures which have non-zero <structfield>revents</structfield>
-fields, or zero if the call timed out. On error
-<returnvalue>-1</returnvalue> is returned, and the
-<varname>errno</varname> variable is set appropriately:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para>One or more of the <parameter>ufds</parameter> members
-specify an invalid file descriptor.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver does not support multiple read or write
-streams and the device is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>ufds</parameter> references an inaccessible
-memory area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINTR</errorcode></term>
-       <listitem>
-         <para>The call was interrupted by a signal.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>nfds</parameter> argument is greater
-than <constant>OPEN_MAX</constant>.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/func-read.xml b/Documentation/DocBook/v4l/func-read.xml
deleted file mode 100644 (file)
index a5089bf..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-<refentry id="func-read">
-  <refmeta>
-    <refentrytitle>V4L2 read()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-read</refname>
-    <refpurpose>Read from a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>ssize_t <function>read</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>void *<parameter>buf</parameter></paramdef>
-       <paramdef>size_t <parameter>count</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>buf</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>count</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para><function>read()</function> attempts to read up to
-<parameter>count</parameter> bytes from file descriptor
-<parameter>fd</parameter> into the buffer starting at
-<parameter>buf</parameter>. The layout of the data in the buffer is
-discussed in the respective device interface section, see ##. If <parameter>count</parameter> is zero,
-<function>read()</function> returns zero and has no other results. If
-<parameter>count</parameter> is greater than
-<constant>SSIZE_MAX</constant>, the result is unspecified. Regardless
-of the <parameter>count</parameter> value each
-<function>read()</function> call will provide at most one frame (two
-fields) worth of data.</para>
-
-    <para>By default <function>read()</function> blocks until data
-becomes available. When the <constant>O_NONBLOCK</constant> flag was
-given to the &func-open; function it
-returns immediately with an &EAGAIN; when no data is available. The
-&func-select; or &func-poll; functions
-can always be used to suspend execution until data becomes available. All
-drivers supporting the <function>read()</function> function must also
-support <function>select()</function> and
-<function>poll()</function>.</para>
-
-    <para>Drivers can implement read functionality in different
-ways, using a single or multiple buffers and discarding the oldest or
-newest frames once the internal buffers are filled.</para>
-
-    <para><function>read()</function> never returns a "snapshot" of a
-buffer being filled. Using a single buffer the driver will stop
-capturing when the application starts reading the buffer until the
-read is finished. Thus only the period of the vertical blanking
-interval is available for reading, or the capture rate must fall below
-the nominal frame rate of the video standard.</para>
-
-<para>The behavior of
-<function>read()</function> when called during the active picture
-period or the vertical blanking separating the top and bottom field
-depends on the discarding policy. A driver discarding the oldest
-frames keeps capturing into an internal buffer, continuously
-overwriting the previously, not read frame, and returns the frame
-being received at the time of the <function>read()</function> call as
-soon as it is complete.</para>
-
-    <para>A driver discarding the newest frames stops capturing until
-the next <function>read()</function> call. The frame being received at
-<function>read()</function> time is discarded, returning the following
-frame instead. Again this implies a reduction of the capture rate to
-one half or less of the nominal frame rate. An example of this model
-is the video read mode of the bttv driver, initiating a DMA to user
-memory when <function>read()</function> is called and returning when
-the DMA finished.</para>
-
-    <para>In the multiple buffer model drivers maintain a ring of
-internal buffers, automatically advancing to the next free buffer.
-This allows continuous capturing when the application can empty the
-buffers fast enough. Again, the behavior when the driver runs out of
-free buffers depends on the discarding policy.</para>
-
-    <para>Applications can get and set the number of buffers used
-internally by the driver with the &VIDIOC-G-PARM; and &VIDIOC-S-PARM;
-ioctls. They are optional, however. The discarding policy is not
-reported and cannot be changed. For minimum requirements see <xref
-       linkend="devices" />.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success, the number of bytes read is returned. It is not
-an error if this number is smaller than the number of bytes requested,
-or the amount of data required for one frame. This may happen for
-example because <function>read()</function> was interrupted by a
-signal. On error, -1 is returned, and the <varname>errno</varname>
-variable is set appropriately. In this case the next read will start
-at the beginning of a new frame. Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EAGAIN</errorcode></term>
-       <listitem>
-         <para>Non-blocking I/O has been selected using
-O_NONBLOCK and no data was immediately available for reading.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid file
-descriptor or is not open for reading, or the process already has the
-maximum number of files open.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver does not support multiple read streams and the
-device is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>buf</parameter> references an inaccessible
-memory area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINTR</errorcode></term>
-       <listitem>
-         <para>The call was interrupted by a signal before any
-data was read.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EIO</errorcode></term>
-       <listitem>
-         <para>I/O error. This indicates some hardware problem or a
-failure to communicate with a remote device (USB camera etc.).</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <function>read()</function> function is not
-supported by this driver, not on this device, or generally not on this
-type of device.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/func-select.xml b/Documentation/DocBook/v4l/func-select.xml
deleted file mode 100644 (file)
index b671362..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-<refentry id="func-select">
-  <refmeta>
-    <refentrytitle>V4L2 select()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-select</refname>
-    <refpurpose>Synchronous I/O multiplexing</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>
-#include &lt;sys/time.h&gt;
-#include &lt;sys/types.h&gt;
-#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>select</function></funcdef>
-       <paramdef>int <parameter>nfds</parameter></paramdef>
-       <paramdef>fd_set *<parameter>readfds</parameter></paramdef>
-       <paramdef>fd_set *<parameter>writefds</parameter></paramdef>
-       <paramdef>fd_set *<parameter>exceptfds</parameter></paramdef>
-       <paramdef>struct timeval *<parameter>timeout</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>With the <function>select()</function> function applications
-can suspend execution until the driver has captured data or is ready
-to accept data for output.</para>
-
-    <para>When streaming I/O has been negotiated this function waits
-until a buffer has been filled or displayed and can be dequeued with
-the &VIDIOC-DQBUF; ioctl. When buffers are already in the outgoing
-queue of the driver the function returns immediately.</para>
-
-    <para>On success <function>select()</function> returns the total
-number of bits set in the <structname>fd_set</structname>s. When the
-function timed out it returns a value of zero. On failure it returns
-<returnvalue>-1</returnvalue> and the <varname>errno</varname>
-variable is set appropriately. When the application did not call
-&VIDIOC-QBUF; or &VIDIOC-STREAMON; yet the
-<function>select()</function> function succeeds, setting the bit of
-the file descriptor in <parameter>readfds</parameter> or
-<parameter>writefds</parameter>, but subsequent &VIDIOC-DQBUF; calls
-will fail.<footnote><para>The Linux kernel implements
-<function>select()</function> like the &func-poll; function, but
-<function>select()</function> cannot return a
-<constant>POLLERR</constant>.</para>
-      </footnote></para>
-
-    <para>When use of the <function>read()</function> function has
-been negotiated and the driver does not capture yet, the
-<function>select()</function> function starts capturing. When that
-fails, <function>select()</function> returns successful and a
-subsequent <function>read()</function> call, which also attempts to
-start capturing, will return an appropriate error code. When the
-driver captures continuously (as opposed to, for example, still
-images) and data is already available the
-<function>select()</function> function returns immediately.</para>
-
-    <para>When use of the <function>write()</function> function has
-been negotiated the <function>select()</function> function just waits
-until the driver is ready for a non-blocking
-<function>write()</function> call.</para>
-
-    <para>All drivers implementing the <function>read()</function> or
-<function>write()</function> function or streaming I/O must also
-support the <function>select()</function> function.</para>
-
-    <para>For more details see the <function>select()</function>
-manual page.</para>
-
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success, <function>select()</function> returns the number
-of descriptors contained in the three returned descriptor sets, which
-will be zero if the timeout expired. On error
-<returnvalue>-1</returnvalue> is returned, and the
-<varname>errno</varname> variable is set appropriately; the sets and
-<parameter>timeout</parameter> are undefined. Possible error codes
-are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para>One or more of the file descriptor sets specified a
-file descriptor that is not open.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver does not support multiple read or write
-streams and the device is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para>The <parameter>readfds</parameter>,
-<parameter>writefds</parameter>, <parameter>exceptfds</parameter> or
-<parameter>timeout</parameter> pointer references an inaccessible memory
-area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINTR</errorcode></term>
-       <listitem>
-         <para>The call was interrupted by a signal.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>nfds</parameter> argument is less than
-zero or greater than <constant>FD_SETSIZE</constant>.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/func-write.xml b/Documentation/DocBook/v4l/func-write.xml
deleted file mode 100644 (file)
index 2c09c09..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-<refentry id="func-write">
-  <refmeta>
-    <refentrytitle>V4L2 write()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>v4l2-write</refname>
-    <refpurpose>Write to a V4L2 device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>ssize_t <function>write</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>void *<parameter>buf</parameter></paramdef>
-       <paramdef>size_t <parameter>count</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>buf</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>count</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para><function>write()</function> writes up to
-<parameter>count</parameter> bytes to the device referenced by the
-file descriptor <parameter>fd</parameter> from the buffer starting at
-<parameter>buf</parameter>. When the hardware outputs are not active
-yet, this function enables them. When <parameter>count</parameter> is
-zero, <function>write()</function> returns
-<returnvalue>0</returnvalue> without any other effect.</para>
-
-    <para>When the application does not provide more data in time, the
-previous video frame, raw VBI image, sliced VPS or WSS data is
-displayed again. Sliced Teletext or Closed Caption data is not
-repeated, the driver inserts a blank line instead.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para>On success, the number of bytes written are returned. Zero
-indicates nothing was written. On error, <returnvalue>-1</returnvalue>
-is returned, and the <varname>errno</varname> variable is set
-appropriately. In this case the next write will start at the beginning
-of a new frame. Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EAGAIN</errorcode></term>
-       <listitem>
-         <para>Non-blocking I/O has been selected using the <link
-linkend="func-open"><constant>O_NONBLOCK</constant></link> flag and no
-buffer space was available to write the data immediately.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid file
-descriptor or is not open for writing.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver does not support multiple write streams and the
-device is already in use.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>buf</parameter> references an inaccessible
-memory area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINTR</errorcode></term>
-       <listitem>
-         <para>The call was interrupted by a signal before any
-data was written.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EIO</errorcode></term>
-       <listitem>
-         <para>I/O error. This indicates some hardware problem.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <function>write()</function> function is not
-supported by this driver, not on this device, or generally not on this
-type of device.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/io.xml b/Documentation/DocBook/v4l/io.xml
deleted file mode 100644 (file)
index c57d1ec..0000000
+++ /dev/null
@@ -1,1265 +0,0 @@
-  <title>Input/Output</title>
-
-  <para>The V4L2 API defines several different methods to read from or
-write to a device. All drivers exchanging data with applications must
-support at least one of them.</para>
-
-  <para>The classic I/O method using the <function>read()</function>
-and <function>write()</function> function is automatically selected
-after opening a V4L2 device. When the driver does not support this
-method attempts to read or write will fail at any time.</para>
-
-  <para>Other methods must be negotiated. To select the streaming I/O
-method with memory mapped or user buffers applications call the
-&VIDIOC-REQBUFS; ioctl. The asynchronous I/O method is not defined
-yet.</para>
-
-  <para>Video overlay can be considered another I/O method, although
-the application does not directly receive the image data. It is
-selected by initiating video overlay with the &VIDIOC-S-FMT; ioctl.
-For more information see <xref linkend="overlay" />.</para>
-
-  <para>Generally exactly one I/O method, including overlay, is
-associated with each file descriptor. The only exceptions are
-applications not exchanging data with a driver ("panel applications",
-see <xref linkend="open" />) and drivers permitting simultaneous video capturing
-and overlay using the same file descriptor, for compatibility with V4L
-and earlier versions of V4L2.</para>
-
-  <para><constant>VIDIOC_S_FMT</constant> and
-<constant>VIDIOC_REQBUFS</constant> would permit this to some degree,
-but for simplicity drivers need not support switching the I/O method
-(after first switching away from read/write) other than by closing
-and reopening the device.</para>
-
-  <para>The following sections describe the various I/O methods in
-more detail.</para>
-
-  <section id="rw">
-    <title>Read/Write</title>
-
-    <para>Input and output devices support the
-<function>read()</function> and <function>write()</function> function,
-respectively, when the <constant>V4L2_CAP_READWRITE</constant> flag in
-the <structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl is set.</para>
-
-    <para>Drivers may need the CPU to copy the data, but they may also
-support DMA to or from user memory, so this I/O method is not
-necessarily less efficient than other methods merely exchanging buffer
-pointers. It is considered inferior though because no meta-information
-like frame counters or timestamps are passed. This information is
-necessary to recognize frame dropping and to synchronize with other
-data streams. However this is also the simplest I/O method, requiring
-little or no setup to exchange data. It permits command line stunts
-like this (the <application>vidctrl</application> tool is
-fictitious):</para>
-
-    <informalexample>
-      <screen>
-&gt; vidctrl /dev/video --input=0 --format=YUYV --size=352x288
-&gt; dd if=/dev/video of=myimage.422 bs=202752 count=1
-</screen>
-    </informalexample>
-
-    <para>To read from the device applications use the
-&func-read; function, to write the &func-write; function.
-Drivers must implement one I/O method if they
-exchange data with applications, but it need not be this.<footnote>
-       <para>It would be desirable if applications could depend on
-drivers supporting all I/O interfaces, but as much as the complex
-memory mapping I/O can be inadequate for some devices we have no
-reason to require this interface, which is most useful for simple
-applications capturing still images.</para>
-      </footnote> When reading or writing is supported, the driver
-must also support the &func-select; and &func-poll;
-function.<footnote>
-       <para>At the driver level <function>select()</function> and
-<function>poll()</function> are the same, and
-<function>select()</function> is too important to be optional.</para>
-      </footnote></para>
-  </section>
-
-  <section id="mmap">
-    <title>Streaming I/O (Memory Mapping)</title>
-
-    <para>Input and output devices support this I/O method when the
-<constant>V4L2_CAP_STREAMING</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl is set. There are two
-streaming methods, to determine if the memory mapping flavor is
-supported applications must call the &VIDIOC-REQBUFS; ioctl.</para>
-
-    <para>Streaming is an I/O method where only pointers to buffers
-are exchanged between application and driver, the data itself is not
-copied. Memory mapping is primarily intended to map buffers in device
-memory into the application's address space. Device memory can be for
-example the video memory on a graphics card with a video capture
-add-on. However, being the most efficient I/O method available for a
-long time, many other drivers support streaming as well, allocating
-buffers in DMA-able main memory.</para>
-
-    <para>A driver can support many sets of buffers. Each set is
-identified by a unique buffer type value. The sets are independent and
-each set can hold a different type of data. To access different sets
-at the same time different file descriptors must be used.<footnote>
-       <para>One could use one file descriptor and set the buffer
-type field accordingly when calling &VIDIOC-QBUF; etc., but it makes
-the <function>select()</function> function ambiguous. We also like the
-clean approach of one file descriptor per logical stream. Video
-overlay for example is also a logical stream, although the CPU is not
-needed for continuous operation.</para>
-      </footnote></para>
-
-    <para>To allocate device buffers applications call the
-&VIDIOC-REQBUFS; ioctl with the desired number of buffers and buffer
-type, for example <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>.
-This ioctl can also be used to change the number of buffers or to free
-the allocated memory, provided none of the buffers are still
-mapped.</para>
-
-    <para>Before applications can access the buffers they must map
-them into their address space with the &func-mmap; function. The
-location of the buffers in device memory can be determined with the
-&VIDIOC-QUERYBUF; ioctl. In the single-planar API case, the
-<structfield>m.offset</structfield> and <structfield>length</structfield>
-returned in a &v4l2-buffer; are passed as sixth and second parameter to the
-<function>mmap()</function> function. When using the multi-planar API,
-struct &v4l2-buffer; contains an array of &v4l2-plane; structures, each
-containing its own <structfield>m.offset</structfield> and
-<structfield>length</structfield>. When using the multi-planar API, every
-plane of every buffer has to be mapped separately, so the number of
-calls to &func-mmap; should be equal to number of buffers times number of
-planes in each buffer. The offset and length values must not be modified.
-Remember, the buffers are allocated in physical memory, as opposed to virtual
-memory, which can be swapped out to disk. Applications should free the buffers
-as soon as possible with the &func-munmap; function.</para>
-
-    <example>
-      <title>Mapping buffers in the single-planar API</title>
-      <programlisting>
-&v4l2-requestbuffers; reqbuf;
-struct {
-       void *start;
-       size_t length;
-} *buffers;
-unsigned int i;
-
-memset(&amp;reqbuf, 0, sizeof(reqbuf));
-reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-reqbuf.memory = V4L2_MEMORY_MMAP;
-reqbuf.count = 20;
-
-if (-1 == ioctl (fd, &VIDIOC-REQBUFS;, &amp;reqbuf)) {
-       if (errno == EINVAL)
-               printf("Video capturing or mmap-streaming is not supported\n");
-       else
-               perror("VIDIOC_REQBUFS");
-
-       exit(EXIT_FAILURE);
-}
-
-/* We want at least five buffers. */
-
-if (reqbuf.count &lt; 5) {
-       /* You may need to free the buffers here. */
-       printf("Not enough buffer memory\n");
-       exit(EXIT_FAILURE);
-}
-
-buffers = calloc(reqbuf.count, sizeof(*buffers));
-assert(buffers != NULL);
-
-for (i = 0; i &lt; reqbuf.count; i++) {
-       &v4l2-buffer; buffer;
-
-       memset(&amp;buffer, 0, sizeof(buffer));
-       buffer.type = reqbuf.type;
-       buffer.memory = V4L2_MEMORY_MMAP;
-       buffer.index = i;
-
-       if (-1 == ioctl (fd, &VIDIOC-QUERYBUF;, &amp;buffer)) {
-               perror("VIDIOC_QUERYBUF");
-               exit(EXIT_FAILURE);
-       }
-
-       buffers[i].length = buffer.length; /* remember for munmap() */
-
-       buffers[i].start = mmap(NULL, buffer.length,
-                               PROT_READ | PROT_WRITE, /* recommended */
-                               MAP_SHARED,             /* recommended */
-                               fd, buffer.m.offset);
-
-       if (MAP_FAILED == buffers[i].start) {
-               /* If you do not exit here you should unmap() and free()
-                  the buffers mapped so far. */
-               perror("mmap");
-               exit(EXIT_FAILURE);
-       }
-}
-
-/* Cleanup. */
-
-for (i = 0; i &lt; reqbuf.count; i++)
-       munmap(buffers[i].start, buffers[i].length);
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Mapping buffers in the multi-planar API</title>
-      <programlisting>
-&v4l2-requestbuffers; reqbuf;
-/* Our current format uses 3 planes per buffer */
-#define FMT_NUM_PLANES = 3
-
-struct {
-       void *start[FMT_NUM_PLANES];
-       size_t length[FMT_NUM_PLANES];
-} *buffers;
-unsigned int i, j;
-
-memset(&amp;reqbuf, 0, sizeof(reqbuf));
-reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-reqbuf.memory = V4L2_MEMORY_MMAP;
-reqbuf.count = 20;
-
-if (ioctl(fd, &VIDIOC-REQBUFS;, &amp;reqbuf) &lt; 0) {
-       if (errno == EINVAL)
-               printf("Video capturing or mmap-streaming is not supported\n");
-       else
-               perror("VIDIOC_REQBUFS");
-
-       exit(EXIT_FAILURE);
-}
-
-/* We want at least five buffers. */
-
-if (reqbuf.count &lt; 5) {
-       /* You may need to free the buffers here. */
-       printf("Not enough buffer memory\n");
-       exit(EXIT_FAILURE);
-}
-
-buffers = calloc(reqbuf.count, sizeof(*buffers));
-assert(buffers != NULL);
-
-for (i = 0; i &lt; reqbuf.count; i++) {
-       &v4l2-buffer; buffer;
-       &v4l2-plane; planes[FMT_NUM_PLANES];
-
-       memset(&amp;buffer, 0, sizeof(buffer));
-       buffer.type = reqbuf.type;
-       buffer.memory = V4L2_MEMORY_MMAP;
-       buffer.index = i;
-       /* length in struct v4l2_buffer in multi-planar API stores the size
-        * of planes array. */
-       buffer.length = FMT_NUM_PLANES;
-       buffer.m.planes = planes;
-
-       if (ioctl(fd, &VIDIOC-QUERYBUF;, &amp;buffer) &lt; 0) {
-               perror("VIDIOC_QUERYBUF");
-               exit(EXIT_FAILURE);
-       }
-
-       /* Every plane has to be mapped separately */
-       for (j = 0; j &lt; FMT_NUM_PLANES; j++) {
-               buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */
-
-               buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
-                                PROT_READ | PROT_WRITE, /* recommended */
-                                MAP_SHARED,             /* recommended */
-                                fd, buffer.m.planes[j].m.offset);
-
-               if (MAP_FAILED == buffers[i].start[j]) {
-                       /* If you do not exit here you should unmap() and free()
-                          the buffers and planes mapped so far. */
-                       perror("mmap");
-                       exit(EXIT_FAILURE);
-               }
-       }
-}
-
-/* Cleanup. */
-
-for (i = 0; i &lt; reqbuf.count; i++)
-       for (j = 0; j &lt; FMT_NUM_PLANES; j++)
-               munmap(buffers[i].start[j], buffers[i].length[j]);
-      </programlisting>
-    </example>
-
-    <para>Conceptually streaming drivers maintain two buffer queues, an incoming
-and an outgoing queue. They separate the synchronous capture or output
-operation locked to a video clock from the application which is
-subject to random disk or network delays and preemption by
-other processes, thereby reducing the probability of data loss.
-The queues are organized as FIFOs, buffers will be
-output in the order enqueued in the incoming FIFO, and were
-captured in the order dequeued from the outgoing FIFO.</para>
-
-    <para>The driver may require a minimum number of buffers enqueued
-at all times to function, apart of this no limit exists on the number
-of buffers applications can enqueue in advance, or dequeue and
-process. They can also enqueue in a different order than buffers have
-been dequeued, and the driver can <emphasis>fill</emphasis> enqueued
-<emphasis>empty</emphasis> buffers in any order. <footnote>
-       <para>Random enqueue order permits applications processing
-images out of order (such as video codecs) to return buffers earlier,
-reducing the probability of data loss. Random fill order allows
-drivers to reuse buffers on a LIFO-basis, taking advantage of caches
-holding scatter-gather lists and the like.</para>
-      </footnote> The index number of a buffer (&v4l2-buffer;
-<structfield>index</structfield>) plays no role here, it only
-identifies the buffer.</para>
-
-    <para>Initially all mapped buffers are in dequeued state,
-inaccessible by the driver. For capturing applications it is customary
-to first enqueue all mapped buffers, then to start capturing and enter
-the read loop. Here the application waits until a filled buffer can be
-dequeued, and re-enqueues the buffer when the data is no longer
-needed. Output applications fill and enqueue buffers, when enough
-buffers are stacked up the output is started with
-<constant>VIDIOC_STREAMON</constant>. In the write loop, when
-the application runs out of free buffers, it must wait until an empty
-buffer can be dequeued and reused.</para>
-
-    <para>To enqueue and dequeue a buffer applications use the
-&VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl. The status of a buffer being
-mapped, enqueued, full or empty can be determined at any time using the
-&VIDIOC-QUERYBUF; ioctl. Two methods exist to suspend execution of the
-application until one or more buffers can be dequeued. By default
-<constant>VIDIOC_DQBUF</constant> blocks when no buffer is in the
-outgoing queue. When the <constant>O_NONBLOCK</constant> flag was
-given to the &func-open; function, <constant>VIDIOC_DQBUF</constant>
-returns immediately with an &EAGAIN; when no buffer is available. The
-&func-select; or &func-poll; function are always available.</para>
-
-    <para>To start and stop capturing or output applications call the
-&VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; ioctl. Note
-<constant>VIDIOC_STREAMOFF</constant> removes all buffers from both
-queues as a side effect. Since there is no notion of doing anything
-"now" on a multitasking system, if an application needs to synchronize
-with another event it should examine the &v4l2-buffer;
-<structfield>timestamp</structfield> of captured buffers, or set the
-field before enqueuing buffers for output.</para>
-
-    <para>Drivers implementing memory mapping I/O must
-support the <constant>VIDIOC_REQBUFS</constant>,
-<constant>VIDIOC_QUERYBUF</constant>,
-<constant>VIDIOC_QBUF</constant>, <constant>VIDIOC_DQBUF</constant>,
-<constant>VIDIOC_STREAMON</constant> and
-<constant>VIDIOC_STREAMOFF</constant> ioctl, the
-<function>mmap()</function>, <function>munmap()</function>,
-<function>select()</function> and <function>poll()</function>
-function.<footnote>
-       <para>At the driver level <function>select()</function> and
-<function>poll()</function> are the same, and
-<function>select()</function> is too important to be optional. The
-rest should be evident.</para>
-      </footnote></para>
-
-    <para>[capture example]</para>
-
-  </section>
-
-  <section id="userp">
-    <title>Streaming I/O (User Pointers)</title>
-
-    <para>Input and output devices support this I/O method when the
-<constant>V4L2_CAP_STREAMING</constant> flag in the
-<structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl is set. If the particular user
-pointer method (not only memory mapping) is supported must be
-determined by calling the &VIDIOC-REQBUFS; ioctl.</para>
-
-    <para>This I/O method combines advantages of the read/write and
-memory mapping methods. Buffers (planes) are allocated by the application
-itself, and can reside for example in virtual or shared memory. Only
-pointers to data are exchanged, these pointers and meta-information
-are passed in &v4l2-buffer; (or in &v4l2-plane; in the multi-planar API case).
-The driver must be switched into user pointer I/O mode by calling the
-&VIDIOC-REQBUFS; with the desired buffer type. No buffers (planes) are allocated
-beforehand, consequently they are not indexed and cannot be queried like mapped
-buffers with the <constant>VIDIOC_QUERYBUF</constant> ioctl.</para>
-
-    <example>
-      <title>Initiating streaming I/O with user pointers</title>
-
-      <programlisting>
-&v4l2-requestbuffers; reqbuf;
-
-memset (&amp;reqbuf, 0, sizeof (reqbuf));
-reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-reqbuf.memory = V4L2_MEMORY_USERPTR;
-
-if (ioctl (fd, &VIDIOC-REQBUFS;, &amp;reqbuf) == -1) {
-       if (errno == EINVAL)
-               printf ("Video capturing or user pointer streaming is not supported\n");
-       else
-               perror ("VIDIOC_REQBUFS");
-
-       exit (EXIT_FAILURE);
-}
-      </programlisting>
-    </example>
-
-    <para>Buffer (plane) addresses and sizes are passed on the fly with the
-&VIDIOC-QBUF; ioctl. Although buffers are commonly cycled,
-applications can pass different addresses and sizes at each
-<constant>VIDIOC_QBUF</constant> call. If required by the hardware the
-driver swaps memory pages within physical memory to create a
-continuous area of memory. This happens transparently to the
-application in the virtual memory subsystem of the kernel. When buffer
-pages have been swapped out to disk they are brought back and finally
-locked in physical memory for DMA.<footnote>
-       <para>We expect that frequently used buffers are typically not
-swapped out. Anyway, the process of swapping, locking or generating
-scatter-gather lists may be time consuming. The delay can be masked by
-the depth of the incoming buffer queue, and perhaps by maintaining
-caches assuming a buffer will be soon enqueued again. On the other
-hand, to optimize memory usage drivers can limit the number of buffers
-locked in advance and recycle the most recently used buffers first. Of
-course, the pages of empty buffers in the incoming queue need not be
-saved to disk. Output buffers must be saved on the incoming and
-outgoing queue because an application may share them with other
-processes.</para>
-      </footnote></para>
-
-    <para>Filled or displayed buffers are dequeued with the
-&VIDIOC-DQBUF; ioctl. The driver can unlock the memory pages at any
-time between the completion of the DMA and this ioctl. The memory is
-also unlocked when &VIDIOC-STREAMOFF; is called, &VIDIOC-REQBUFS;, or
-when the device is closed. Applications must take care not to free
-buffers without dequeuing. For once, the buffers remain locked until
-further, wasting physical memory. Second the driver will not be
-notified when the memory is returned to the application's free list
-and subsequently reused for other purposes, possibly completing the
-requested DMA and overwriting valuable data.</para>
-
-    <para>For capturing applications it is customary to enqueue a
-number of empty buffers, to start capturing and enter the read loop.
-Here the application waits until a filled buffer can be dequeued, and
-re-enqueues the buffer when the data is no longer needed. Output
-applications fill and enqueue buffers, when enough buffers are stacked
-up output is started. In the write loop, when the application
-runs out of free buffers it must wait until an empty buffer can be
-dequeued and reused. Two methods exist to suspend execution of the
-application until one or more buffers can be dequeued. By default
-<constant>VIDIOC_DQBUF</constant> blocks when no buffer is in the
-outgoing queue. When the <constant>O_NONBLOCK</constant> flag was
-given to the &func-open; function, <constant>VIDIOC_DQBUF</constant>
-returns immediately with an &EAGAIN; when no buffer is available. The
-&func-select; or &func-poll; function are always available.</para>
-
-    <para>To start and stop capturing or output applications call the
-&VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; ioctl. Note
-<constant>VIDIOC_STREAMOFF</constant> removes all buffers from both
-queues and unlocks all buffers as a side effect. Since there is no
-notion of doing anything "now" on a multitasking system, if an
-application needs to synchronize with another event it should examine
-the &v4l2-buffer; <structfield>timestamp</structfield> of captured
-buffers, or set the field before enqueuing buffers for output.</para>
-
-    <para>Drivers implementing user pointer I/O must
-support the <constant>VIDIOC_REQBUFS</constant>,
-<constant>VIDIOC_QBUF</constant>, <constant>VIDIOC_DQBUF</constant>,
-<constant>VIDIOC_STREAMON</constant> and
-<constant>VIDIOC_STREAMOFF</constant> ioctl, the
-<function>select()</function> and <function>poll()</function> function.<footnote>
-       <para>At the driver level <function>select()</function> and
-<function>poll()</function> are the same, and
-<function>select()</function> is too important to be optional. The
-rest should be evident.</para>
-      </footnote></para>
-  </section>
-
-  <section id="async">
-    <title>Asynchronous I/O</title>
-
-    <para>This method is not defined yet.</para>
-  </section>
-
-  <section id="buffer">
-    <title>Buffers</title>
-
-    <para>A buffer contains data exchanged by application and
-driver using one of the Streaming I/O methods. In the multi-planar API, the
-data is held in planes, while the buffer structure acts as a container
-for the planes. Only pointers to buffers (planes) are exchanged, the data
-itself is not copied. These pointers, together with meta-information like
-timestamps or field parity, are stored in a struct
-<structname>v4l2_buffer</structname>, argument to
-the &VIDIOC-QUERYBUF;, &VIDIOC-QBUF; and &VIDIOC-DQBUF; ioctl.
-In the multi-planar API, some plane-specific members of struct
-<structname>v4l2_buffer</structname>, such as pointers and sizes for each
-plane, are stored in struct <structname>v4l2_plane</structname> instead.
-In that case, struct <structname>v4l2_buffer</structname> contains an array of
-plane structures.</para>
-
-      <para>Nominally timestamps refer to the first data byte transmitted.
-In practice however the wide range of hardware covered by the V4L2 API
-limits timestamp accuracy. Often an interrupt routine will
-sample the system clock shortly after the field or frame was stored
-completely in memory. So applications must expect a constant
-difference up to one field or frame period plus a small (few scan
-lines) random error. The delay and error can be much
-larger due to compression or transmission over an external bus when
-the frames are not properly stamped by the sender. This is frequently
-the case with USB cameras. Here timestamps refer to the instant the
-field or frame was received by the driver, not the capture time. These
-devices identify by not enumerating any video standards, see <xref
-linkend="standard" />.</para>
-
-      <para>Similar limitations apply to output timestamps. Typically
-the video hardware locks to a clock controlling the video timing, the
-horizontal and vertical synchronization pulses. At some point in the
-line sequence, possibly the vertical blanking, an interrupt routine
-samples the system clock, compares against the timestamp and programs
-the hardware to repeat the previous field or frame, or to display the
-buffer contents.</para>
-
-      <para>Apart of limitations of the video device and natural
-inaccuracies of all clocks, it should be noted system time itself is
-not perfectly stable. It can be affected by power saving cycles,
-warped to insert leap seconds, or even turned back or forth by the
-system administrator affecting long term measurements. <footnote>
-         <para>Since no other Linux multimedia
-API supports unadjusted time it would be foolish to introduce here. We
-must use a universally supported clock to synchronize different media,
-hence time of day.</para>
-       </footnote></para>
-
-    <table frame="none" pgwide="1" id="v4l2-buffer">
-      <title>struct <structname>v4l2_buffer</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry></entry>
-           <entry>Number of the buffer, set by the application. This
-field is only used for <link linkend="mmap">memory mapping</link> I/O
-and can range from zero to the number of buffers allocated
-with the &VIDIOC-REQBUFS; ioctl (&v4l2-requestbuffers; <structfield>count</structfield>) minus one.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-buf-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>Type of the buffer, same as &v4l2-format;
-<structfield>type</structfield> or &v4l2-requestbuffers;
-<structfield>type</structfield>, set by the application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>bytesused</structfield></entry>
-           <entry></entry>
-           <entry>The number of bytes occupied by the data in the
-buffer. It depends on the negotiated data format and may change with
-each buffer for compressed variable size data like JPEG images.
-Drivers must set this field when <structfield>type</structfield>
-refers to an input stream, applications when an output stream.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry>Flags set by the application or driver, see <xref
-linkend="buffer-flags" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-field;</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry></entry>
-           <entry>Indicates the field order of the image in the
-buffer, see <xref linkend="v4l2-field" />. This field is not used when
-the buffer contains VBI data. Drivers must set it when
-<structfield>type</structfield> refers to an input stream,
-applications when an output stream.</entry>
-         </row>
-         <row>
-           <entry>struct timeval</entry>
-           <entry><structfield>timestamp</structfield></entry>
-           <entry></entry>
-           <entry><para>For input streams this is the
-system time (as returned by the <function>gettimeofday()</function>
-function) when the first data byte was captured. For output streams
-the data will not be displayed before this time, secondary to the
-nominal frame rate determined by the current video standard in
-enqueued order. Applications can for example zero this field to
-display frames as soon as possible. The driver stores the time at
-which the first data byte was actually sent out in the
-<structfield>timestamp</structfield> field. This permits
-applications to monitor the drift between the video and system
-clock.</para></entry>
-         </row>
-         <row>
-           <entry>&v4l2-timecode;</entry>
-           <entry><structfield>timecode</structfield></entry>
-           <entry></entry>
-           <entry>When <structfield>type</structfield> is
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> and the
-<constant>V4L2_BUF_FLAG_TIMECODE</constant> flag is set in
-<structfield>flags</structfield>, this structure contains a frame
-timecode. In <link linkend="v4l2-field">V4L2_FIELD_ALTERNATE</link>
-mode the top and bottom field contain the same timecode.
-Timecodes are intended to help video editing and are typically recorded on
-video tapes, but also embedded in compressed formats like MPEG. This
-field is independent of the <structfield>timestamp</structfield> and
-<structfield>sequence</structfield> fields.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>sequence</structfield></entry>
-           <entry></entry>
-           <entry>Set by the driver, counting the frames in the
-sequence.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>In <link
-linkend="v4l2-field">V4L2_FIELD_ALTERNATE</link> mode the top and
-bottom field have the same sequence number. The count starts at zero
-and includes dropped or repeated frames. A dropped frame was received
-by an input device but could not be stored due to lack of free buffer
-space. A repeated frame was displayed again by an output device
-because the application did not pass new data in
-time.</para><para>Note this may count the frames received
-e.g. over USB, without taking into account the frames dropped by the
-remote hardware due to limited compression throughput or bus
-bandwidth. These devices identify by not enumerating any video
-standards, see <xref linkend="standard" />.</para></entry>
-         </row>
-         <row>
-           <entry>&v4l2-memory;</entry>
-           <entry><structfield>memory</structfield></entry>
-           <entry></entry>
-           <entry>This field must be set by applications and/or drivers
-in accordance with the selected I/O method.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield>m</structfield></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>offset</structfield></entry>
-           <entry>For the single-planar API and when
-<structfield>memory</structfield> is <constant>V4L2_MEMORY_MMAP</constant> this
-is the offset of the buffer from the start of the device memory. The value is
-returned by the driver and apart of serving as parameter to the &func-mmap;
-function not useful for applications. See <xref linkend="mmap" /> for details
-         </entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>unsigned long</entry>
-           <entry><structfield>userptr</structfield></entry>
-           <entry>For the single-planar API and when
-<structfield>memory</structfield> is <constant>V4L2_MEMORY_USERPTR</constant>
-this is a pointer to the buffer (casted to unsigned long type) in virtual
-memory, set by the application. See <xref linkend="userp" /> for details.
-           </entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct v4l2_plane</entry>
-           <entry><structfield>*planes</structfield></entry>
-           <entry>When using the multi-planar API, contains a userspace pointer
-           to an array of &v4l2-plane;. The size of the array should be put
-           in the <structfield>length</structfield> field of this
-           <structname>v4l2_buffer</structname> structure.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>length</structfield></entry>
-           <entry></entry>
-           <entry>Size of the buffer (not the payload) in bytes for the
-           single-planar API. For the multi-planar API should contain the
-           number of elements in the <structfield>planes</structfield> array.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>input</structfield></entry>
-           <entry></entry>
-           <entry>Some video capture drivers support rapid and
-synchronous video input changes, a function useful for example in
-video surveillance applications. For this purpose applications set the
-<constant>V4L2_BUF_FLAG_INPUT</constant> flag, and this field to the
-number of a video input as in &v4l2-input; field
-<structfield>index</structfield>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield></entry>
-           <entry></entry>
-           <entry>A place holder for future extensions and custom
-(driver defined) buffer types
-<constant>V4L2_BUF_TYPE_PRIVATE</constant> and higher. Applications
-should set this to 0.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-plane">
-      <title>struct <structname>v4l2_plane</structname></title>
-      <tgroup cols="4">
-        &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>bytesused</structfield></entry>
-           <entry></entry>
-           <entry>The number of bytes occupied by data in the plane
-           (its payload).</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>length</structfield></entry>
-           <entry></entry>
-           <entry>Size in bytes of the plane (not its payload).</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield>m</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>mem_offset</structfield></entry>
-           <entry>When the memory type in the containing &v4l2-buffer; is
-             <constant>V4L2_MEMORY_MMAP</constant>, this is the value that
-             should be passed to &func-mmap;, similar to the
-             <structfield>offset</structfield> field in &v4l2-buffer;.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__unsigned long</entry>
-           <entry><structfield>userptr</structfield></entry>
-           <entry>When the memory type in the containing &v4l2-buffer; is
-             <constant>V4L2_MEMORY_USERPTR</constant>, this is a userspace
-             pointer to the memory allocated for this plane by an application.
-             </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>data_offset</structfield></entry>
-           <entry></entry>
-           <entry>Offset in bytes to video data in the plane, if applicable.
-           </entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved[11]</structfield></entry>
-           <entry></entry>
-           <entry>Reserved for future use. Should be zeroed by an
-           application.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-buf-type">
-      <title>enum v4l2_buf_type</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant></entry>
-           <entry>1</entry>
-           <entry>Buffer of a single-planar video capture stream, see <xref
-               linkend="capture" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>
-           </entry>
-           <entry>9</entry>
-           <entry>Buffer of a multi-planar video capture stream, see <xref
-               linkend="capture" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant></entry>
-           <entry>2</entry>
-           <entry>Buffer of a single-planar video output stream, see <xref
-               linkend="output" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>
-           </entry>
-           <entry>10</entry>
-           <entry>Buffer of a multi-planar video output stream, see <xref
-               linkend="output" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant></entry>
-           <entry>3</entry>
-           <entry>Buffer for video overlay, see <xref linkend="overlay" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VBI_CAPTURE</constant></entry>
-           <entry>4</entry>
-           <entry>Buffer of a raw VBI capture stream, see <xref
-               linkend="raw-vbi" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant></entry>
-           <entry>5</entry>
-           <entry>Buffer of a raw VBI output stream, see <xref
-               linkend="raw-vbi" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant></entry>
-           <entry>6</entry>
-           <entry>Buffer of a sliced VBI capture stream, see <xref
-               linkend="sliced" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant></entry>
-           <entry>7</entry>
-           <entry>Buffer of a sliced VBI output stream, see <xref
-               linkend="sliced" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY</constant></entry>
-           <entry>8</entry>
-           <entry>Buffer for video output overlay (OSD), see <xref
-               linkend="osd" />. Status: <link
-linkend="experimental">Experimental</link>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_TYPE_PRIVATE</constant></entry>
-           <entry>0x80</entry>
-         <entry>This and higher values are reserved for custom
-(driver defined) buffer types.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="buffer-flags">
-      <title>Buffer Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_MAPPED</constant></entry>
-           <entry>0x0001</entry>
-           <entry>The buffer resides in device memory and has been mapped
-into the application's address space, see <xref linkend="mmap" /> for details.
-Drivers set or clear this flag when the
-<link linkend="vidioc-querybuf">VIDIOC_QUERYBUF</link>, <link
-         linkend="vidioc-qbuf">VIDIOC_QBUF</link> or <link
-         linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl is called. Set by the driver.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_QUEUED</constant></entry>
-           <entry>0x0002</entry>
-         <entry>Internally drivers maintain two buffer queues, an
-incoming and outgoing queue. When this flag is set, the buffer is
-currently on the incoming queue. It automatically moves to the
-outgoing queue after the buffer has been filled (capture devices) or
-displayed (output devices). Drivers set or clear this flag when the
-<constant>VIDIOC_QUERYBUF</constant> ioctl is called. After
-(successful) calling the <constant>VIDIOC_QBUF </constant>ioctl it is
-always set and after <constant>VIDIOC_DQBUF</constant> always
-cleared.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_DONE</constant></entry>
-           <entry>0x0004</entry>
-           <entry>When this flag is set, the buffer is currently on
-the outgoing queue, ready to be dequeued from the driver. Drivers set
-or clear this flag when the <constant>VIDIOC_QUERYBUF</constant> ioctl
-is called. After calling the <constant>VIDIOC_QBUF</constant> or
-<constant>VIDIOC_DQBUF</constant> it is always cleared. Of course a
-buffer cannot be on both queues at the same time, the
-<constant>V4L2_BUF_FLAG_QUEUED</constant> and
-<constant>V4L2_BUF_FLAG_DONE</constant> flag are mutually exclusive.
-They can be both cleared however, then the buffer is in "dequeued"
-state, in the application domain to say so.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_ERROR</constant></entry>
-           <entry>0x0040</entry>
-           <entry>When this flag is set, the buffer has been dequeued
-           successfully, although the data might have been corrupted.
-           This is recoverable, streaming may continue as normal and
-           the buffer may be reused normally.
-           Drivers set this flag when the <constant>VIDIOC_DQBUF</constant>
-           ioctl is called.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_KEYFRAME</constant></entry>
-           <entry>0x0008</entry>
-         <entry>Drivers set or clear this flag when calling the
-<constant>VIDIOC_DQBUF</constant> ioctl. It may be set by video
-capture devices when the buffer contains a compressed image which is a
-key frame (or field), &ie; can be decompressed on its own.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_PFRAME</constant></entry>
-           <entry>0x0010</entry>
-           <entry>Similar to <constant>V4L2_BUF_FLAG_KEYFRAME</constant>
-this flags predicted frames or fields which contain only differences to a
-previous key frame.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_BFRAME</constant></entry>
-           <entry>0x0020</entry>
-           <entry>Similar to <constant>V4L2_BUF_FLAG_PFRAME</constant>
-       this is a bidirectional predicted frame or field. [ooc tbd]</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_TIMECODE</constant></entry>
-           <entry>0x0100</entry>
-           <entry>The <structfield>timecode</structfield> field is valid.
-Drivers set or clear this flag when the <constant>VIDIOC_DQBUF</constant>
-ioctl is called.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_BUF_FLAG_INPUT</constant></entry>
-           <entry>0x0200</entry>
-           <entry>The <structfield>input</structfield> field is valid.
-Applications set or clear this flag before calling the
-<constant>VIDIOC_QBUF</constant> ioctl.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-memory">
-      <title>enum v4l2_memory</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_MEMORY_MMAP</constant></entry>
-           <entry>1</entry>
-           <entry>The buffer is used for <link linkend="mmap">memory
-mapping</link> I/O.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MEMORY_USERPTR</constant></entry>
-           <entry>2</entry>
-           <entry>The buffer is used for <link linkend="userp">user
-pointer</link> I/O.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_MEMORY_OVERLAY</constant></entry>
-           <entry>3</entry>
-           <entry>[to do]</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <section>
-      <title>Timecodes</title>
-
-      <para>The <structname>v4l2_timecode</structname> structure is
-designed to hold a <xref linkend="smpte12m" /> or similar timecode.
-(struct <structname>timeval</structname> timestamps are stored in
-&v4l2-buffer; field <structfield>timestamp</structfield>.)</para>
-
-      <table frame="none" pgwide="1" id="v4l2-timecode">
-       <title>struct <structname>v4l2_timecode</structname></title>
-       <tgroup cols="3">
-         &cs-str;
-         <tbody valign="top">
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>type</structfield></entry>
-             <entry>Frame rate the timecodes are based on, see <xref
-                 linkend="timecode-type" />.</entry>
-           </row>
-           <row>
-             <entry>__u32</entry>
-             <entry><structfield>flags</structfield></entry>
-             <entry>Timecode flags, see <xref linkend="timecode-flags" />.</entry>
-           </row>
-           <row>
-             <entry>__u8</entry>
-             <entry><structfield>frames</structfield></entry>
-             <entry>Frame count, 0 ... 23/24/29/49/59, depending on the
-           type of timecode.</entry>
-           </row>
-           <row>
-             <entry>__u8</entry>
-             <entry><structfield>seconds</structfield></entry>
-             <entry>Seconds count, 0 ... 59. This is a binary, not BCD number.</entry>
-           </row>
-           <row>
-             <entry>__u8</entry>
-             <entry><structfield>minutes</structfield></entry>
-             <entry>Minutes count, 0 ... 59. This is a binary, not BCD number.</entry>
-           </row>
-           <row>
-             <entry>__u8</entry>
-             <entry><structfield>hours</structfield></entry>
-             <entry>Hours count, 0 ... 29. This is a binary, not BCD number.</entry>
-           </row>
-           <row>
-             <entry>__u8</entry>
-             <entry><structfield>userbits</structfield>[4]</entry>
-             <entry>The "user group" bits from the timecode.</entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <table frame="none" pgwide="1" id="timecode-type">
-       <title>Timecode Types</title>
-       <tgroup cols="3">
-       &cs-def;
-         <tbody valign="top">
-           <row>
-             <entry><constant>V4L2_TC_TYPE_24FPS</constant></entry>
-             <entry>1</entry>
-             <entry>24 frames per second, i.&nbsp;e. film.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_TYPE_25FPS</constant></entry>
-             <entry>2</entry>
-             <entry>25 frames per second, &ie; PAL or SECAM video.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_TYPE_30FPS</constant></entry>
-             <entry>3</entry>
-             <entry>30 frames per second, &ie; NTSC video.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_TYPE_50FPS</constant></entry>
-             <entry>4</entry>
-             <entry></entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_TYPE_60FPS</constant></entry>
-             <entry>5</entry>
-             <entry></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-
-      <table frame="none" pgwide="1" id="timecode-flags">
-       <title>Timecode Flags</title>
-       <tgroup cols="3">
-       &cs-def;
-         <tbody valign="top">
-           <row>
-             <entry><constant>V4L2_TC_FLAG_DROPFRAME</constant></entry>
-             <entry>0x0001</entry>
-             <entry>Indicates "drop frame" semantics for counting frames
-in 29.97 fps material. When set, frame numbers 0 and 1 at the start of
-each minute, except minutes 0, 10, 20, 30, 40, 50 are omitted from the
-count.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_FLAG_COLORFRAME</constant></entry>
-             <entry>0x0002</entry>
-             <entry>The "color frame" flag.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_USERBITS_field</constant></entry>
-             <entry>0x000C</entry>
-             <entry>Field mask for the "binary group flags".</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_USERBITS_USERDEFINED</constant></entry>
-             <entry>0x0000</entry>
-             <entry>Unspecified format.</entry>
-           </row>
-           <row>
-             <entry><constant>V4L2_TC_USERBITS_8BITCHARS</constant></entry>
-             <entry>0x0008</entry>
-             <entry>8-bit ISO characters.</entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-  </section>
-
-  <section id="field-order">
-    <title>Field Order</title>
-
-    <para>We have to distinguish between progressive and interlaced
-video. Progressive video transmits all lines of a video image
-sequentially. Interlaced video divides an image into two fields,
-containing only the odd and even lines of the image, respectively.
-Alternating the so called odd and even field are transmitted, and due
-to a small delay between fields a cathode ray TV displays the lines
-interleaved, yielding the original frame. This curious technique was
-invented because at refresh rates similar to film the image would
-fade out too quickly. Transmitting fields reduces the flicker without
-the necessity of doubling the frame rate and with it the bandwidth
-required for each channel.</para>
-
-    <para>It is important to understand a video camera does not expose
-one frame at a time, merely transmitting the frames separated into
-fields. The fields are in fact captured at two different instances in
-time. An object on screen may well move between one field and the
-next. For applications analysing motion it is of paramount importance
-to recognize which field of a frame is older, the <emphasis>temporal
-order</emphasis>.</para>
-
-    <para>When the driver provides or accepts images field by field
-rather than interleaved, it is also important applications understand
-how the fields combine to frames. We distinguish between top (aka odd) and
-bottom (aka even) fields, the <emphasis>spatial order</emphasis>: The first line
-of the top field is the first line of an interlaced frame, the first
-line of the bottom field is the second line of that frame.</para>
-
-    <para>However because fields were captured one after the other,
-arguing whether a frame commences with the top or bottom field is
-pointless. Any two successive top and bottom, or bottom and top fields
-yield a valid frame. Only when the source was progressive to begin
-with, &eg; when transferring film to video, two fields may come from
-the same frame, creating a natural order.</para>
-
-    <para>Counter to intuition the top field is not necessarily the
-older field. Whether the older field contains the top or bottom lines
-is a convention determined by the video standard. Hence the
-distinction between temporal and spatial order of fields. The diagrams
-below should make this clearer.</para>
-
-    <para>All video capture and output devices must report the current
-field order. Some drivers may permit the selection of a different
-order, to this end applications initialize the
-<structfield>field</structfield> field of &v4l2-pix-format; before
-calling the &VIDIOC-S-FMT; ioctl. If this is not desired it should
-have the value <constant>V4L2_FIELD_ANY</constant> (0).</para>
-
-    <table frame="none" pgwide="1" id="v4l2-field">
-      <title>enum v4l2_field</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FIELD_ANY</constant></entry>
-           <entry>0</entry>
-           <entry>Applications request this field order when any
-one of the <constant>V4L2_FIELD_NONE</constant>,
-<constant>V4L2_FIELD_TOP</constant>,
-<constant>V4L2_FIELD_BOTTOM</constant>, or
-<constant>V4L2_FIELD_INTERLACED</constant> formats is acceptable.
-Drivers choose depending on hardware capabilities or e.&nbsp;g. the
-requested image size, and return the actual field order. &v4l2-buffer;
-<structfield>field</structfield> can never be
-<constant>V4L2_FIELD_ANY</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_NONE</constant></entry>
-           <entry>1</entry>
-           <entry>Images are in progressive format, not interlaced.
-The driver may also indicate this order when it cannot distinguish
-between <constant>V4L2_FIELD_TOP</constant> and
-<constant>V4L2_FIELD_BOTTOM</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_TOP</constant></entry>
-           <entry>2</entry>
-           <entry>Images consist of the top (aka odd) field only.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_BOTTOM</constant></entry>
-           <entry>3</entry>
-           <entry>Images consist of the bottom (aka even) field only.
-Applications may wish to prevent a device from capturing interlaced
-images because they will have "comb" or "feathering" artefacts around
-moving objects.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_INTERLACED</constant></entry>
-           <entry>4</entry>
-           <entry>Images contain both fields, interleaved line by
-line. The temporal order of the fields (whether the top or bottom
-field is first transmitted) depends on the current video standard.
-M/NTSC transmits the bottom field first, all other standards the top
-field first.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_SEQ_TB</constant></entry>
-           <entry>5</entry>
-           <entry>Images contain both fields, the top field lines
-are stored first in memory, immediately followed by the bottom field
-lines. Fields are always stored in temporal order, the older one first
-in memory. Image sizes refer to the frame, not fields.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_SEQ_BT</constant></entry>
-           <entry>6</entry>
-           <entry>Images contain both fields, the bottom field
-lines are stored first in memory, immediately followed by the top
-field lines. Fields are always stored in temporal order, the older one
-first in memory. Image sizes refer to the frame, not fields.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_ALTERNATE</constant></entry>
-           <entry>7</entry>
-           <entry>The two fields of a frame are passed in separate
-buffers, in temporal order, &ie; the older one first. To indicate the field
-parity (whether the current field is a top or bottom field) the driver
-or application, depending on data direction, must set &v4l2-buffer;
-<structfield>field</structfield> to
-<constant>V4L2_FIELD_TOP</constant> or
-<constant>V4L2_FIELD_BOTTOM</constant>. Any two successive fields pair
-to build a frame. If fields are successive, without any dropped fields
-between them (fields can drop individually), can be determined from
-the &v4l2-buffer; <structfield>sequence</structfield> field. Image
-sizes refer to the frame, not fields. This format cannot be selected
-when using the read/write I/O method.<!-- Where it's indistinguishable
-from V4L2_FIELD_SEQ_*. --></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_INTERLACED_TB</constant></entry>
-           <entry>8</entry>
-           <entry>Images contain both fields, interleaved line by
-line, top field first. The top field is transmitted first.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FIELD_INTERLACED_BT</constant></entry>
-           <entry>9</entry>
-           <entry>Images contain both fields, interleaved line by
-line, top field first. The bottom field is transmitted first.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <figure id="fieldseq-tb">
-       <title>Field Order, Top Field First Transmitted</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="fieldseq_tb.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="fieldseq_tb.gif" format="GIF" />
-         </imageobject>
-       </mediaobject>
-    </figure>
-
-    <figure id="fieldseq-bt">
-       <title>Field Order, Bottom Field First Transmitted</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="fieldseq_bt.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="fieldseq_bt.gif" format="GIF" />
-         </imageobject>
-       </mediaobject>
-    </figure>
-  </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/keytable.c.xml b/Documentation/DocBook/v4l/keytable.c.xml
deleted file mode 100644 (file)
index d53254a..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-<programlisting>
-/* keytable.c - This program allows checking/replacing keys at IR
-
-   Copyright (C) 2006-2009 Mauro Carvalho Chehab &lt;mchehab@infradead.org&gt;
-
-   This 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.
- */
-
-#include &lt;ctype.h&gt;
-#include &lt;errno.h&gt;
-#include &lt;fcntl.h&gt;
-#include &lt;stdio.h&gt;
-#include &lt;stdlib.h&gt;
-#include &lt;string.h&gt;
-#include &lt;linux/input.h&gt;
-#include &lt;sys/ioctl.h&gt;
-
-#include "parse.h"
-
-void prtcode (int *codes)
-{
-        struct parse_key *p;
-
-        for (p=keynames;p-&gt;name!=NULL;p++) {
-                if (p-&gt;value == (unsigned)codes[1]) {
-                        printf("scancode 0x%04x = %s (0x%02x)\n", codes[0], p-&gt;name, codes[1]);
-                        return;
-                }
-        }
-
-        if (isprint (codes[1]))
-                printf("scancode %d = '%c' (0x%02x)\n", codes[0], codes[1], codes[1]);
-        else
-                printf("scancode %d = 0x%02x\n", codes[0], codes[1]);
-}
-
-int parse_code(char *string)
-{
-        struct parse_key *p;
-
-        for (p=keynames;p-&gt;name!=NULL;p++) {
-                if (!strcasecmp(p-&gt;name, string)) {
-                        return p-&gt;value;
-                }
-        }
-        return -1;
-}
-
-int main (int argc, char *argv[])
-{
-        int fd;
-        unsigned int i, j;
-        int codes[2];
-
-        if (argc&lt;2 || argc&gt;4) {
-                printf ("usage: %s &lt;device&gt; to get table; or\n"
-                        "       %s &lt;device&gt; &lt;scancode&gt; &lt;keycode&gt;\n"
-                        "       %s &lt;device&gt; &lt;keycode_file&gt;\n",*argv,*argv,*argv);
-                return -1;
-        }
-
-        if ((fd = open(argv[1], O_RDONLY)) &lt; 0) {
-                perror("Couldn't open input device");
-                return(-1);
-        }
-
-        if (argc==4) {
-                int value;
-
-                value=parse_code(argv[3]);
-
-                if (value==-1) {
-                        value = strtol(argv[3], NULL, 0);
-                        if (errno)
-                                perror("value");
-                }
-
-                codes [0] = (unsigned) strtol(argv[2], NULL, 0);
-                codes [1] = (unsigned) value;
-
-                if(ioctl(fd, EVIOCSKEYCODE, codes))
-                        perror ("EVIOCSKEYCODE");
-
-                if(ioctl(fd, EVIOCGKEYCODE, codes)==0)
-                        prtcode(codes);
-                return 0;
-        }
-
-        if (argc==3) {
-                FILE *fin;
-                int value;
-                char *scancode, *keycode, s[2048];
-
-                fin=fopen(argv[2],"r");
-                if (fin==NULL) {
-                        perror ("opening keycode file");
-                        return -1;
-                }
-
-                /* Clears old table */
-                for (j = 0; j &lt; 256; j++) {
-                        for (i = 0; i &lt; 256; i++) {
-                                codes[0] = (j &lt;&lt; 8) | i;
-                                codes[1] = KEY_RESERVED;
-                                ioctl(fd, EVIOCSKEYCODE, codes);
-                        }
-                }
-
-                while (fgets(s,sizeof(s),fin)) {
-                        scancode=strtok(s,"\n\t =:");
-                        if (!scancode) {
-                                perror ("parsing input file scancode");
-                                return -1;
-                        }
-                        if (!strcasecmp(scancode, "scancode")) {
-                                scancode = strtok(NULL,"\n\t =:");
-                                if (!scancode) {
-                                        perror ("parsing input file scancode");
-                                        return -1;
-                                }
-                        }
-
-                        keycode=strtok(NULL,"\n\t =:(");
-                        if (!keycode) {
-                                perror ("parsing input file keycode");
-                                return -1;
-                        }
-
-                        // printf ("parsing %s=%s:", scancode, keycode);
-                        value=parse_code(keycode);
-                        // printf ("\tvalue=%d\n",value);
-
-                        if (value==-1) {
-                                value = strtol(keycode, NULL, 0);
-                                if (errno)
-                                        perror("value");
-                        }
-
-                        codes [0] = (unsigned) strtol(scancode, NULL, 0);
-                        codes [1] = (unsigned) value;
-
-                        // printf("\t%04x=%04x\n",codes[0], codes[1]);
-                        if(ioctl(fd, EVIOCSKEYCODE, codes)) {
-                                fprintf(stderr, "Setting scancode 0x%04x with 0x%04x via ",codes[0], codes[1]);
-                                perror ("EVIOCSKEYCODE");
-                        }
-
-                        if(ioctl(fd, EVIOCGKEYCODE, codes)==0)
-                                prtcode(codes);
-                }
-                return 0;
-        }
-
-        /* Get scancode table */
-        for (j = 0; j &lt; 256; j++) {
-                for (i = 0; i &lt; 256; i++) {
-                        codes[0] = (j &lt;&lt; 8) | i;
-                        if (!ioctl(fd, EVIOCGKEYCODE, codes) &amp;&amp; codes[1] != KEY_RESERVED)
-                                prtcode(codes);
-                }
-        }
-        return 0;
-}
-
-</programlisting>
diff --git a/Documentation/DocBook/v4l/libv4l.xml b/Documentation/DocBook/v4l/libv4l.xml
deleted file mode 100644 (file)
index 3cb10ec..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-<title>Libv4l Userspace Library</title>
-<section id="libv4l-introduction">
-       <title>Introduction</title>
-
-       <para>libv4l is a collection of libraries which adds a thin abstraction
-layer on top of video4linux2 devices. The purpose of this (thin) layer
-is to make it easy for application writers to support a wide variety of
-devices without having to write separate code for different devices in the
-same class.</para>
-<para>An example of using libv4l is provided by
-<link linkend='v4l2grab-example'>v4l2grab</link>.
-</para>
-
-       <para>libv4l consists of 3 different libraries:</para>
-       <section>
-               <title>libv4lconvert</title>
-
-               <para>libv4lconvert is a library that converts several
-different pixelformats found in V4L2 drivers into a few common RGB and
-YUY formats.</para>
-               <para>It currently accepts the following V4L2 driver formats:
-<link linkend="V4L2-PIX-FMT-BGR24"><constant>V4L2_PIX_FMT_BGR24</constant></link>,
-<link linkend="V4L2-PIX-FMT-HM12"><constant>V4L2_PIX_FMT_HM12</constant></link>,
-<link linkend="V4L2-PIX-FMT-JPEG"><constant>V4L2_PIX_FMT_JPEG</constant></link>,
-<link linkend="V4L2-PIX-FMT-MJPEG"><constant>V4L2_PIX_FMT_MJPEG</constant></link>,
-<link linkend="V4L2-PIX-FMT-MR97310A"><constant>V4L2_PIX_FMT_MR97310A</constant></link>,
-<link linkend="V4L2-PIX-FMT-OV511"><constant>V4L2_PIX_FMT_OV511</constant></link>,
-<link linkend="V4L2-PIX-FMT-OV518"><constant>V4L2_PIX_FMT_OV518</constant></link>,
-<link linkend="V4L2-PIX-FMT-PAC207"><constant>V4L2_PIX_FMT_PAC207</constant></link>,
-<link linkend="V4L2-PIX-FMT-PJPG"><constant>V4L2_PIX_FMT_PJPG</constant></link>,
-<link linkend="V4L2-PIX-FMT-RGB24"><constant>V4L2_PIX_FMT_RGB24</constant></link>,
-<link linkend="V4L2-PIX-FMT-SBGGR8"><constant>V4L2_PIX_FMT_SBGGR8</constant></link>,
-<link linkend="V4L2-PIX-FMT-SGBRG8"><constant>V4L2_PIX_FMT_SGBRG8</constant></link>,
-<link linkend="V4L2-PIX-FMT-SGRBG8"><constant>V4L2_PIX_FMT_SGRBG8</constant></link>,
-<link linkend="V4L2-PIX-FMT-SN9C10X"><constant>V4L2_PIX_FMT_SN9C10X</constant></link>,
-<link linkend="V4L2-PIX-FMT-SN9C20X-I420"><constant>V4L2_PIX_FMT_SN9C20X_I420</constant></link>,
-<link linkend="V4L2-PIX-FMT-SPCA501"><constant>V4L2_PIX_FMT_SPCA501</constant></link>,
-<link linkend="V4L2-PIX-FMT-SPCA505"><constant>V4L2_PIX_FMT_SPCA505</constant></link>,
-<link linkend="V4L2-PIX-FMT-SPCA508"><constant>V4L2_PIX_FMT_SPCA508</constant></link>,
-<link linkend="V4L2-PIX-FMT-SPCA561"><constant>V4L2_PIX_FMT_SPCA561</constant></link>,
-<link linkend="V4L2-PIX-FMT-SQ905C"><constant>V4L2_PIX_FMT_SQ905C</constant></link>,
-<constant>V4L2_PIX_FMT_SRGGB8</constant>,
-<link linkend="V4L2-PIX-FMT-UYVY"><constant>V4L2_PIX_FMT_UYVY</constant></link>,
-<link linkend="V4L2-PIX-FMT-YUV420"><constant>V4L2_PIX_FMT_YUV420</constant></link>,
-<link linkend="V4L2-PIX-FMT-YUYV"><constant>V4L2_PIX_FMT_YUYV</constant></link>,
-<link linkend="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></link>,
-and <link linkend="V4L2-PIX-FMT-YVYU"><constant>V4L2_PIX_FMT_YVYU</constant></link>.
-</para>
-               <para>Later on libv4lconvert was expanded to also be able to do
-various        video processing functions to improve webcam video quality.
-The video processing is split in to 2 parts: libv4lconvert/control and
-libv4lconvert/processing.</para>
-
-               <para>The control part is used to offer video controls which can
-be used        to control the video processing functions made available by
-       libv4lconvert/processing. These controls are stored application wide
-(until reboot) by using a persistent shared memory object.</para>
-
-               <para>libv4lconvert/processing offers the actual video
-processing functionality.</para>
-       </section>
-       <section>
-               <title>libv4l1</title>
-               <para>This library offers functions that can be used to quickly
-make v4l1 applications work with v4l2 devices. These functions work exactly
-like the normal open/close/etc, except that libv4l1 does full emulation of
-the v4l1 api on top of v4l2 drivers, in case of v4l1 drivers it
-will just pass calls through.</para>
-               <para>Since those functions are emulations of the old V4L1 API,
-it shouldn't be used for new applications.</para>
-       </section>
-       <section>
-               <title>libv4l2</title>
-               <para>This library should be used for all modern V4L2
-applications.</para>
-               <para>It provides handles to call V4L2 open/ioctl/close/poll
-methods. Instead of just providing the raw output of the device, it enhances
-the calls in the sense that it will use libv4lconvert to provide more video
-formats and to enhance the image quality.</para>
-               <para>In most cases, libv4l2 just passes the calls directly
-through to the v4l2 driver, intercepting the calls to
-<link linkend='vidioc-g-fmt'><constant>VIDIOC_TRY_FMT</constant></link>,
-<link linkend='vidioc-g-fmt'><constant>VIDIOC_G_FMT</constant></link>
-<link linkend='vidioc-g-fmt'><constant>VIDIOC_S_FMT</constant></link>
-<link linkend='vidioc-enum-framesizes'><constant>VIDIOC_ENUM_FRAMESIZES</constant></link>
-and <link linkend='vidioc-enum-frameintervals'><constant>VIDIOC_ENUM_FRAMEINTERVALS</constant></link>
-in order to emulate the formats
-<link linkend="V4L2-PIX-FMT-BGR24"><constant>V4L2_PIX_FMT_BGR24</constant></link>,
-<link linkend="V4L2-PIX-FMT-RGB24"><constant>V4L2_PIX_FMT_RGB24</constant></link>,
-<link linkend="V4L2-PIX-FMT-YUV420"><constant>V4L2_PIX_FMT_YUV420</constant></link>,
-and <link linkend="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></link>,
-if they aren't available in the driver.
-<link linkend='vidioc-enum-fmt'><constant>VIDIOC_ENUM_FMT</constant></link>
-keeps enumerating the hardware supported formats, plus the emulated formats
-offered by libv4l at the end.
-</para>
-               <section id="libv4l-ops">
-                       <title>Libv4l device control functions</title>
-                       <para>The common file operation methods are provided by
-libv4l.</para>
-                       <para>Those functions operate just like glibc
-open/close/dup/ioctl/read/mmap/munmap:</para>
-<itemizedlist><listitem>
-                       <para>int v4l2_open(const char *file, int oflag,
-...) -
-operates like the standard <link linkend='func-open'>open()</link> function.
-</para></listitem><listitem>
-                       <para>int v4l2_close(int fd) -
-operates like the standard <link linkend='func-close'>close()</link> function.
-</para></listitem><listitem>
-                       <para>int v4l2_dup(int fd) -
-operates like the standard dup() function, duplicating a file handler.
-</para></listitem><listitem>
-                       <para>int v4l2_ioctl (int fd, unsigned long int request, ...) -
-operates like the standard <link linkend='func-ioctl'>ioctl()</link> function.
-</para></listitem><listitem>
-                       <para>int v4l2_read (int fd, void* buffer, size_t n) -
-operates like the standard <link linkend='func-read'>read()</link> function.
-</para></listitem><listitem>
-                       <para>void v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, int64_t offset); -
-operates like the standard <link linkend='func-mmap'>mmap()</link> function.
-</para></listitem><listitem>
-                       <para>int v4l2_munmap(void *_start, size_t length); -
-operates like the standard <link linkend='func-munmap'>munmap()</link> function.
-</para></listitem>
-</itemizedlist>
-                       <para>Those functions provide additional control:</para>
-<itemizedlist><listitem>
-                       <para>int v4l2_fd_open(int fd, int v4l2_flags) -
-opens an already opened fd for further use through v4l2lib and possibly
-modify libv4l2's default behavior through the v4l2_flags argument.
-Currently, v4l2_flags can be <constant>V4L2_DISABLE_CONVERSION</constant>,
-to disable format conversion.
-</para></listitem><listitem>
-                       <para>int v4l2_set_control(int fd, int cid, int value) -
-This function takes a value of 0 - 65535, and then scales that range to
-the actual range of the given v4l control id, and then if the cid exists
-and is not locked sets the cid to the scaled value.
-</para></listitem><listitem>
-                       <para>int v4l2_get_control(int fd, int cid) -
-This function returns a value of 0 - 65535, scaled to from the actual range
-of the given v4l control id. when the cid does not exist, could not be
-accessed for some reason, or some error occurred 0 is returned.
-</para></listitem>
-</itemizedlist>
-               </section>
-       </section>
-       <section>
-
-               <title>v4l1compat.so wrapper library</title>
-
-               <para>This library intercepts calls to
-open/close/ioctl/mmap/mmunmap operations and redirects them to the libv4l
-counterparts, by using LD_PRELOAD=/usr/lib/v4l1compat.so. It also
-emulates V4L1 calls via V4L2 API.</para>
-               <para>It allows usage of binary legacy applications that
-still don't use libv4l.</para>
-       </section>
-
-</section>
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/lirc_device_interface.xml b/Documentation/DocBook/v4l/lirc_device_interface.xml
deleted file mode 100644 (file)
index 0e0453f..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-<section id="lirc_dev">
-<title>LIRC Device Interface</title>
-
-
-<section id="lirc_dev_intro">
-<title>Introduction</title>
-
-<para>The LIRC device interface is a bi-directional interface for
-transporting raw IR data between userspace and kernelspace. Fundamentally,
-it is just a chardev (/dev/lircX, for X = 0, 1, 2, ...), with a number
-of standard struct file_operations defined on it. With respect to
-transporting raw IR data to and fro, the essential fops are read, write
-and ioctl.</para>
-
-<para>Example dmesg output upon a driver registering w/LIRC:</para>
-  <blockquote>
-    <para>$ dmesg |grep lirc_dev</para>
-    <para>lirc_dev: IR Remote Control driver registered, major 248</para>
-    <para>rc rc0: lirc_dev: driver ir-lirc-codec (mceusb) registered at minor = 0</para>
-  </blockquote>
-
-<para>What you should see for a chardev:</para>
-  <blockquote>
-    <para>$ ls -l /dev/lirc*</para>
-    <para>crw-rw---- 1 root root 248, 0 Jul  2 22:20 /dev/lirc0</para>
-  </blockquote>
-</section>
-
-<section id="lirc_read">
-<title>LIRC read fop</title>
-
-<para>The lircd userspace daemon reads raw IR data from the LIRC chardev. The
-exact format of the data depends on what modes a driver supports, and what
-mode has been selected. lircd obtains supported modes and sets the active mode
-via the ioctl interface, detailed at <xref linkend="lirc_ioctl"/>. The generally
-preferred mode is LIRC_MODE_MODE2, in which packets containing an int value
-describing an IR signal are read from the chardev.</para>
-
-<para>See also <ulink url="http://www.lirc.org/html/technical.html">http://www.lirc.org/html/technical.html</ulink> for more info.</para>
-</section>
-
-<section id="lirc_write">
-<title>LIRC write fop</title>
-
-<para>The data written to the chardev is a pulse/space sequence of integer
-values. Pulses and spaces are only marked implicitly by their position. The
-data must start and end with a pulse, therefore, the data must always include
-an uneven number of samples. The write function must block until the data has
-been transmitted by the hardware.</para>
-</section>
-
-<section id="lirc_ioctl">
-<title>LIRC ioctl fop</title>
-
-<para>The LIRC device's ioctl definition is bound by the ioctl function
-definition of struct file_operations, leaving us with an unsigned int
-for the ioctl command and an unsigned long for the arg. For the purposes
-of ioctl portability across 32-bit and 64-bit, these values are capped
-to their 32-bit sizes.</para>
-
-<para>The following ioctls can be used to change specific hardware settings.
-In general each driver should have a default set of settings. The driver
-implementation is expected to re-apply the default settings when the device
-is closed by user-space, so that every application opening the device can rely
-on working with the default settings initially.</para>
-
-<variablelist>
-  <varlistentry>
-    <term>LIRC_GET_FEATURES</term>
-    <listitem>
-      <para>Obviously, get the underlying hardware device's features. If a driver
-      does not announce support of certain features, calling of the corresponding
-      ioctls is undefined.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_SEND_MODE</term>
-    <listitem>
-      <para>Get supported transmit mode. Only LIRC_MODE_PULSE is supported by lircd.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_REC_MODE</term>
-    <listitem>
-      <para>Get supported receive modes. Only LIRC_MODE_MODE2 and LIRC_MODE_LIRCCODE
-      are supported by lircd.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_SEND_CARRIER</term>
-    <listitem>
-      <para>Get carrier frequency (in Hz) currently used for transmit.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_REC_CARRIER</term>
-    <listitem>
-      <para>Get carrier frequency (in Hz) currently used for IR reception.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_{G,S}ET_{SEND,REC}_DUTY_CYCLE</term>
-    <listitem>
-      <para>Get/set the duty cycle (from 0 to 100) of the carrier signal. Currently,
-      no special meaning is defined for 0 or 100, but this could be used to switch
-      off carrier generation in the future, so these values should be reserved.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_REC_RESOLUTION</term>
-    <listitem>
-      <para>Some receiver have maximum resolution which is defined by internal
-      sample rate or data format limitations. E.g. it's common that signals can
-      only be reported in 50 microsecond steps. This integer value is used by
-      lircd to automatically adjust the aeps tolerance value in the lircd
-      config file.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_M{IN,AX}_TIMEOUT</term>
-    <listitem>
-      <para>Some devices have internal timers that can be used to detect when
-      there's no IR activity for a long time. This can help lircd in detecting
-      that a IR signal is finished and can speed up the decoding process.
-      Returns an integer value with the minimum/maximum timeout that can be
-      set. Some devices have a fixed timeout, in that case both ioctls will
-      return the same value even though the timeout cannot be changed.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_M{IN,AX}_FILTER_{PULSE,SPACE}</term>
-    <listitem>
-      <para>Some devices are able to filter out spikes in the incoming signal
-      using given filter rules. These ioctls return the hardware capabilities
-      that describe the bounds of the possible filters. Filter settings depend
-      on the IR protocols that are expected. lircd derives the settings from
-      all protocols definitions found in its config file.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_GET_LENGTH</term>
-    <listitem>
-      <para>Retrieves the code length in bits (only for LIRC_MODE_LIRCCODE).
-      Reads on the device must be done in blocks matching the bit count.
-      The bit could should be rounded up so that it matches full bytes.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_{SEND,REC}_MODE</term>
-    <listitem>
-      <para>Set send/receive mode. Largely obsolete for send, as only
-      LIRC_MODE_PULSE is supported.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_{SEND,REC}_CARRIER</term>
-    <listitem>
-      <para>Set send/receive carrier (in Hz).</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_TRANSMITTER_MASK</term>
-    <listitem>
-      <para>This enables the given set of transmitters. The first transmitter
-      is encoded by the least significant bit, etc. When an invalid bit mask
-      is given, i.e. a bit is set, even though the device does not have so many
-      transitters, then this ioctl returns the number of available transitters
-      and does nothing otherwise.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_REC_TIMEOUT</term>
-    <listitem>
-      <para>Sets the integer value for IR inactivity timeout (cf.
-      LIRC_GET_MIN_TIMEOUT and LIRC_GET_MAX_TIMEOUT). A value of 0 (if
-      supported by the hardware) disables all hardware timeouts and data should
-      be reported as soon as possible. If the exact value cannot be set, then
-      the next possible value _greater_ than the given value should be set.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_REC_TIMEOUT_REPORTS</term>
-    <listitem>
-      <para>Enable (1) or disable (0) timeout reports in LIRC_MODE_MODE2. By
-      default, timeout reports should be turned off.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_REC_FILTER_{,PULSE,SPACE}</term>
-    <listitem>
-      <para>Pulses/spaces shorter than this are filtered out by hardware. If
-      filters cannot be set independently for pulse/space, the corresponding
-      ioctls must return an error and LIRC_SET_REC_FILTER shall be used instead.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_MEASURE_CARRIER_MODE</term>
-    <listitem>
-      <para>Enable (1)/disable (0) measure mode. If enabled, from the next key
-      press on, the driver will send LIRC_MODE2_FREQUENCY packets. By default
-      this should be turned off.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_REC_{DUTY_CYCLE,CARRIER}_RANGE</term>
-    <listitem>
-      <para>To set a range use LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE
-      with the lower bound first and later LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER
-      with the upper bound.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_NOTIFY_DECODE</term>
-    <listitem>
-      <para>This ioctl is called by lircd whenever a successful decoding of an
-      incoming IR signal could be done. This can be used by supporting hardware
-      to give visual feedback to the user e.g. by flashing a LED.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SETUP_{START,END}</term>
-    <listitem>
-      <para>Setting of several driver parameters can be optimized by encapsulating
-      the according ioctl calls with LIRC_SETUP_START/LIRC_SETUP_END. When a
-      driver receives a LIRC_SETUP_START ioctl it can choose to not commit
-      further setting changes to the hardware until a LIRC_SETUP_END is received.
-      But this is open to the driver implementation and every driver must also
-      handle parameter changes which are not encapsulated by LIRC_SETUP_START
-      and LIRC_SETUP_END. Drivers can also choose to ignore these ioctls.</para>
-    </listitem>
-  </varlistentry>
-  <varlistentry>
-    <term>LIRC_SET_WIDEBAND_RECEIVER</term>
-    <listitem>
-      <para>Some receivers are equipped with special wide band receiver which is intended
-      to be used to learn output of existing remote.
-      Calling that ioctl with (1) will enable it, and with (0) disable it.
-      This might be useful of receivers that have otherwise narrow band receiver
-      that prevents them to be used with some remotes.
-      Wide band receiver might also be more precise
-      On the other hand its disadvantage it usually reduced range of reception.
-      Note: wide band receiver might be implictly enabled if you enable
-      carrier reports. In that case it will be disabled as soon as you disable
-      carrier reports. Trying to disable wide band receiver while carrier
-      reports are active will do nothing.</para>
-    </listitem>
-  </varlistentry>
-</variablelist>
-
-</section>
-</section>
diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
deleted file mode 100644 (file)
index 873ac3a..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<partinfo>
-  <authorgroup>
-    <author>
-      <firstname>Laurent</firstname>
-      <surname>Pinchart</surname>
-      <affiliation><address><email>laurent.pinchart@ideasonboard.com</email></address></affiliation>
-      <contrib>Initial version.</contrib>
-    </author>
-  </authorgroup>
-  <copyright>
-    <year>2010</year>
-    <holder>Laurent Pinchart</holder>
-  </copyright>
-
-  <revhistory>
-    <!-- Put document revisions here, newest first. -->
-    <revision>
-      <revnumber>1.0.0</revnumber>
-      <date>2010-11-10</date>
-      <authorinitials>lp</authorinitials>
-      <revremark>Initial revision</revremark>
-    </revision>
-  </revhistory>
-</partinfo>
-
-<title>Media Controller API</title>
-
-<chapter id="media_controller">
-  <title>Media Controller</title>
-
-  <section id="media-controller-intro">
-    <title>Introduction</title>
-    <para>Media devices increasingly handle multiple related functions. Many USB
-    cameras include microphones, video capture hardware can also output video,
-    or SoC camera interfaces also perform memory-to-memory operations similar to
-    video codecs.</para>
-    <para>Independent functions, even when implemented in the same hardware, can
-    be modelled as separate devices. A USB camera with a microphone will be
-    presented to userspace applications as V4L2 and ALSA capture devices. The
-    devices' relationships (when using a webcam, end-users shouldn't have to
-    manually select the associated USB microphone), while not made available
-    directly to applications by the drivers, can usually be retrieved from
-    sysfs.</para>
-    <para>With more and more advanced SoC devices being introduced, the current
-    approach will not scale. Device topologies are getting increasingly complex
-    and can't always be represented by a tree structure. Hardware blocks are
-    shared between different functions, creating dependencies between seemingly
-    unrelated devices.</para>
-    <para>Kernel abstraction APIs such as V4L2 and ALSA provide means for
-    applications to access hardware parameters. As newer hardware expose an
-    increasingly high number of those parameters, drivers need to guess what
-    applications really require based on limited information, thereby
-    implementing policies that belong to userspace.</para>
-    <para>The media controller API aims at solving those problems.</para>
-  </section>
-
-  <section id="media-controller-model">
-    <title>Media device model</title>
-    <para>Discovering a device internal topology, and configuring it at runtime,
-    is one of the goals of the media controller API. To achieve this, hardware
-    devices are modelled as an oriented graph of building blocks called entities
-    connected through pads.</para>
-    <para>An entity is a basic media hardware or software building block. It can
-    correspond to a large variety of logical blocks such as physical hardware
-    devices (CMOS sensor for instance), logical hardware devices (a building
-    block in a System-on-Chip image processing pipeline), DMA channels or
-    physical connectors.</para>
-    <para>A pad is a connection endpoint through which an entity can interact
-    with other entities. Data (not restricted to video) produced by an entity
-    flows from the entity's output to one or more entity inputs. Pads should not
-    be confused with physical pins at chip boundaries.</para>
-    <para>A link is a point-to-point oriented connection between two pads,
-    either on the same entity or on different entities. Data flows from a source
-    pad to a sink pad.</para>
-  </section>
-</chapter>
-
-<appendix id="media-user-func">
-  <title>Function Reference</title>
-  <!-- Keep this alphabetically sorted. -->
-  &sub-media-func-open;
-  &sub-media-func-close;
-  &sub-media-func-ioctl;
-  <!-- All ioctls go here. -->
-  &sub-media-ioc-device-info;
-  &sub-media-ioc-enum-entities;
-  &sub-media-ioc-enum-links;
-  &sub-media-ioc-setup-link;
-</appendix>
diff --git a/Documentation/DocBook/v4l/media-func-close.xml b/Documentation/DocBook/v4l/media-func-close.xml
deleted file mode 100644 (file)
index be149c8..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-<refentry id="media-func-close">
-  <refmeta>
-    <refentrytitle>media close()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>media-close</refname>
-    <refpurpose>Close a media device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>close</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Closes the media device. Resources associated with the file descriptor
-    are freed. The device configuration remain unchanged.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para><function>close</function> returns 0 on success. On error, -1 is
-    returned, and <varname>errno</varname> is set appropriately. Possible error
-    codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid open file descriptor.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/media-func-ioctl.xml b/Documentation/DocBook/v4l/media-func-ioctl.xml
deleted file mode 100644 (file)
index bda8604..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-<refentry id="media-func-ioctl">
-  <refmeta>
-    <refentrytitle>media ioctl()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>media-ioctl</refname>
-    <refpurpose>Control a media device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>void *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>Media ioctl request code as defined in the media.h header file,
-         for example MEDIA_IOC_SETUP_LINK.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to a request-specific structure.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-    <para>The <function>ioctl()</function> function manipulates media device
-    parameters. The argument <parameter>fd</parameter> must be an open file
-    descriptor.</para>
-    <para>The ioctl <parameter>request</parameter> code specifies the media
-    function to be called. It has encoded in it whether the argument is an
-    input, output or read/write parameter, and the size of the argument
-    <parameter>argp</parameter> in bytes.</para>
-    <para>Macros and structures definitions specifying media ioctl requests and
-    their parameters are located in the media.h header file. All media ioctl
-    requests, their respective function and parameters are specified in
-    <xref linkend="media-user-func" />.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-
-    <para><function>ioctl()</function> returns <returnvalue>0</returnvalue> on
-    success. On failure, <returnvalue>-1</returnvalue> is returned, and the
-    <varname>errno</varname> variable is set appropriately. Generic error codes
-    are listed below, and request-specific error codes are listed in the
-    individual requests descriptions.</para>
-    <para>When an ioctl that takes an output or read/write parameter fails,
-    the parameter remains unmodified.</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBADF</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is not a valid open file descriptor.
-         </para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EFAULT</errorcode></term>
-       <listitem>
-         <para><parameter>argp</parameter> references an inaccessible memory
-         area.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <parameter>request</parameter> or the data pointed to by
-         <parameter>argp</parameter> is not valid. This is a very common error
-         code, see the individual ioctl requests listed in
-         <xref linkend="media-user-func" /> for actual causes.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Insufficient kernel memory was available to complete the
-         request.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOTTY</errorcode></term>
-       <listitem>
-         <para><parameter>fd</parameter> is  not  associated  with  a character
-         special device.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/media-func-open.xml b/Documentation/DocBook/v4l/media-func-open.xml
deleted file mode 100644 (file)
index f7df034..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-<refentry id="media-func-open">
-  <refmeta>
-    <refentrytitle>media open()</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>media-open</refname>
-    <refpurpose>Open a media device</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
-      <funcprototype>
-       <funcdef>int <function>open</function></funcdef>
-       <paramdef>const char *<parameter>device_name</parameter></paramdef>
-       <paramdef>int <parameter>flags</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>device_name</parameter></term>
-       <listitem>
-         <para>Device to be opened.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>flags</parameter></term>
-       <listitem>
-         <para>Open flags. Access mode must be either <constant>O_RDONLY</constant>
-         or <constant>O_RDWR</constant>. Other flags have no effect.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>Description</title>
-    <para>To open a media device applications call <function>open()</function>
-    with the desired device name. The function has no side effects; the device
-    configuration remain unchanged.</para>
-    <para>When the device is opened in read-only mode, attemps to modify its
-    configuration will result in an error, and <varname>errno</varname> will be
-    set to <errorcode>EBADF</errorcode>.</para>
-  </refsect1>
-  <refsect1>
-    <title>Return Value</title>
-
-    <para><function>open</function> returns the new file descriptor on success.
-    On error, -1 is returned, and <varname>errno</varname> is set appropriately.
-    Possible error codes are:</para>
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para>The requested access to the file is not allowed.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EMFILE</errorcode></term>
-       <listitem>
-         <para>The  process  already  has  the  maximum number of files open.
-         </para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENFILE</errorcode></term>
-       <listitem>
-         <para>The system limit on the total number of open files has been
-         reached.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Insufficient kernel memory was available.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENXIO</errorcode></term>
-       <listitem>
-         <para>No device corresponding to this device special file exists.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-device-info.xml b/Documentation/DocBook/v4l/media-ioc-device-info.xml
deleted file mode 100644 (file)
index 1f32373..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-<refentry id="media-ioc-device-info">
-  <refmeta>
-    <refentrytitle>ioctl MEDIA_IOC_DEVICE_INFO</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>MEDIA_IOC_DEVICE_INFO</refname>
-    <refpurpose>Query device information</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct media_device_info *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='media-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>MEDIA_IOC_DEVICE_INFO</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>All media devices must support the <constant>MEDIA_IOC_DEVICE_INFO</constant>
-    ioctl. To query device information, applications call the ioctl with a
-    pointer to a &media-device-info;. The driver fills the structure and returns
-    the information to the application.
-    The ioctl never fails.</para>
-
-    <table pgwide="1" frame="none" id="media-device-info">
-      <title>struct <structname>media_device_info</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>char</entry>
-           <entry><structfield>driver</structfield>[16]</entry>
-           <entry><para>Name of the driver implementing the media API as a
-           NUL-terminated ASCII string. The driver version is stored in the
-           <structfield>driver_version</structfield> field.</para>
-           <para>Driver specific applications can use this information to
-           verify the driver identity. It is also useful to work around
-           known bugs, or to identify drivers in error reports.</para></entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>model</structfield>[32]</entry>
-           <entry>Device model name as a NUL-terminated UTF-8 string. The
-           device version is stored in the <structfield>device_version</structfield>
-           field and is not be appended to the model name.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>serial</structfield>[40]</entry>
-           <entry>Serial number as a NUL-terminated ASCII string.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>bus_info</structfield>[32]</entry>
-           <entry>Location of the device in the system as a NUL-terminated
-           ASCII string. This includes the bus type name (PCI, USB, ...) and a
-           bus-specific identifier.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>media_version</structfield></entry>
-           <entry>Media API version, formatted with the
-           <constant>KERNEL_VERSION()</constant> macro.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>hw_revision</structfield></entry>
-           <entry>Hardware device revision in a driver-specific format.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>media_version</structfield></entry>
-           <entry>Media device driver version, formatted with the
-           <constant>KERNEL_VERSION()</constant> macro. Together with the
-           <structfield>driver</structfield> field this identifies a particular
-           driver.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[31]</entry>
-           <entry>Reserved for future extensions. Drivers and applications must
-           set this array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-    <para>The <structfield>serial</structfield> and <structfield>bus_info</structfield>
-    fields can be used to distinguish between multiple instances of otherwise
-    identical hardware. The serial number takes precedence when provided and can
-    be assumed to be unique. If the serial number is an empty string, the
-    <structfield>bus_info</structfield> field can be used instead. The
-    <structfield>bus_info</structfield> field is guaranteed to be unique, but
-    can vary across reboots or device unplug/replug.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return value</title>
-    <para>This function doesn't return specific error codes.</para>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/v4l/media-ioc-enum-entities.xml
deleted file mode 100644 (file)
index 576b68b..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-<refentry id="media-ioc-enum-entities">
-  <refmeta>
-    <refentrytitle>ioctl MEDIA_IOC_ENUM_ENTITIES</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>MEDIA_IOC_ENUM_ENTITIES</refname>
-    <refpurpose>Enumerate entities and their properties</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct media_entity_desc *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='media-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>MEDIA_IOC_ENUM_ENTITIES</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-    <para>To query the attributes of an entity, applications set the id field
-    of a &media-entity-desc; structure and call the MEDIA_IOC_ENUM_ENTITIES
-    ioctl with a pointer to this structure. The driver fills the rest of the
-    structure or returns an &EINVAL; when the id is invalid.</para>
-    <para>Entities can be enumerated by or'ing the id with the
-    <constant>MEDIA_ENT_ID_FLAG_NEXT</constant> flag. The driver will return
-    information about the entity with the smallest id strictly larger than the
-    requested one ('next entity'), or the &EINVAL; if there is none.</para>
-    <para>Entity IDs can be non-contiguous. Applications must
-    <emphasis>not</emphasis> try to enumerate entities by calling
-    MEDIA_IOC_ENUM_ENTITIES with increasing id's until they get an error.</para>
-    <para>Two or more entities that share a common non-zero
-    <structfield>group_id</structfield> value are considered as logically
-    grouped. Groups are used to report
-    <itemizedlist>
-      <listitem><para>ALSA, VBI and video nodes that carry the same media
-      stream</para></listitem>
-      <listitem><para>lens and flash controllers associated with a sensor</para></listitem>
-    </itemizedlist>
-    </para>
-
-    <table pgwide="1" frame="none" id="media-entity-desc">
-      <title>struct <structname>media_entity_desc</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity id, set by the application. When the id is or'ed with
-           <constant>MEDIA_ENT_ID_FLAG_NEXT</constant>, the driver clears the
-           flag and returns the first entity with a larger id.</entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity name as an UTF-8 NULL-terminated string.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity type, see <xref linkend="media-entity-type" /> for details.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>revision</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity revision in a driver/hardware specific format.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity flags, see <xref linkend="media-entity-flag" /> for details.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>group_id</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Entity group ID</entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>pads</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Number of pads</entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>links</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Total number of outbound links. Inbound links are not counted
-           in this field.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct</entry>
-           <entry><structfield>v4l</structfield></entry>
-           <entry></entry>
-           <entry>Valid for V4L sub-devices and nodes only.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>major</structfield></entry>
-           <entry>V4L device node major number. For V4L sub-devices with no
-           device node, set by the driver to 0.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>minor</structfield></entry>
-           <entry>V4L device node minor number. For V4L sub-devices with no
-           device node, set by the driver to 0.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct</entry>
-           <entry><structfield>fb</structfield></entry>
-           <entry></entry>
-           <entry>Valid for frame buffer nodes only.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>major</structfield></entry>
-           <entry>Frame buffer device node major number.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>minor</structfield></entry>
-           <entry>Frame buffer device node minor number.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>struct</entry>
-           <entry><structfield>alsa</structfield></entry>
-           <entry></entry>
-           <entry>Valid for ALSA devices only.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>card</structfield></entry>
-           <entry>ALSA card number</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>device</structfield></entry>
-           <entry>ALSA device number</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>subdevice</structfield></entry>
-           <entry>ALSA sub-device number</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>int</entry>
-           <entry><structfield>dvb</structfield></entry>
-           <entry></entry>
-           <entry>DVB card number</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u8</entry>
-           <entry><structfield>raw</structfield>[180]</entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="media-entity-type">
-      <title>Media entity types</title>
-      <tgroup cols="2">
-        <colspec colname="c1"/>
-        <colspec colname="c2"/>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MEDIA_ENT_T_DEVNODE</constant></entry>
-           <entry>Unknown device node</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_T_DEVNODE_V4L</constant></entry>
-           <entry>V4L video, radio or vbi device node</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_T_DEVNODE_FB</constant></entry>
-           <entry>Frame buffer device node</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_T_DEVNODE_ALSA</constant></entry>
-           <entry>ALSA card</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_T_DEVNODE_DVB</constant></entry>
-           <entry>DVB card</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV</constant></entry>
-           <entry>Unknown V4L sub-device</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_SENSOR</constant></entry>
-           <entry>Video sensor</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_FLASH</constant></entry>
-           <entry>Flash controller</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_LENS</constant></entry>
-           <entry>Lens controller</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="media-entity-flag">
-      <title>Media entity flags</title>
-      <tgroup cols="2">
-        <colspec colname="c1"/>
-        <colspec colname="c2"/>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MEDIA_ENT_FL_DEFAULT</constant></entry>
-           <entry>Default entity for its type. Used to discover the default
-           audio, VBI and video devices, the default camera sensor, ...</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &media-entity-desc; <structfield>id</structfield> references
-         a non-existing entity.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml
deleted file mode 100644 (file)
index d2fc73e..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-<refentry id="media-ioc-enum-links">
-  <refmeta>
-    <refentrytitle>ioctl MEDIA_IOC_ENUM_LINKS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>MEDIA_IOC_ENUM_LINKS</refname>
-    <refpurpose>Enumerate all pads and links for a given entity</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct media_links_enum *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='media-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>MEDIA_IOC_ENUM_LINKS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To enumerate pads and/or links for a given entity, applications set
-    the entity field of a &media-links-enum; structure and initialize the
-    &media-pad-desc; and &media-link-desc; structure arrays pointed by the
-    <structfield>pads</structfield> and <structfield>links</structfield> fields.
-    They then call the MEDIA_IOC_ENUM_LINKS ioctl with a pointer to this
-    structure.</para>
-    <para>If the <structfield>pads</structfield> field is not NULL, the driver
-    fills the <structfield>pads</structfield> array with information about the
-    entity's pads. The array must have enough room to store all the entity's
-    pads. The number of pads can be retrieved with the &MEDIA-IOC-ENUM-ENTITIES;
-    ioctl.</para>
-    <para>If the <structfield>links</structfield> field is not NULL, the driver
-    fills the <structfield>links</structfield> array with information about the
-    entity's outbound links. The array must have enough room to store all the
-    entity's outbound links. The number of outbound links can be retrieved with
-    the &MEDIA-IOC-ENUM-ENTITIES; ioctl.</para>
-    <para>Only forward links that originate at one of the entity's source pads
-    are returned during the enumeration process.</para>
-
-    <table pgwide="1" frame="none" id="media-links-enum">
-      <title>struct <structname>media_links_enum</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>entity</structfield></entry>
-           <entry>Entity id, set by the application.</entry>
-         </row>
-         <row>
-           <entry>struct &media-pad-desc;</entry>
-           <entry>*<structfield>pads</structfield></entry>
-           <entry>Pointer to a pads array allocated by the application. Ignored
-           if NULL.</entry>
-         </row>
-         <row>
-           <entry>struct &media-link-desc;</entry>
-           <entry>*<structfield>links</structfield></entry>
-           <entry>Pointer to a links array allocated by the application. Ignored
-           if NULL.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="media-pad-desc">
-      <title>struct <structname>media_pad_desc</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>entity</structfield></entry>
-           <entry>ID of the entity this pad belongs to.</entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>0-based pad index.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Pad flags, see <xref linkend="media-pad-flag" /> for more details.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="media-pad-flag">
-      <title>Media pad flags</title>
-      <tgroup cols="2">
-        <colspec colname="c1"/>
-        <colspec colname="c2"/>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MEDIA_PAD_FL_SINK</constant></entry>
-           <entry>Input pad, relative to the entity. Input pads sink data and
-           are targets of links.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_PAD_FL_SOURCE</constant></entry>
-           <entry>Output pad, relative to the entity. Output pads source data
-           and are origins of links.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="media-link-desc">
-      <title>struct <structname>media_links_desc</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>struct &media-pad-desc;</entry>
-           <entry><structfield>source</structfield></entry>
-           <entry>Pad at the origin of this link.</entry>
-         </row>
-         <row>
-           <entry>struct &media-pad-desc;</entry>
-           <entry><structfield>sink</structfield></entry>
-           <entry>Pad at the target of this link.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Link flags, see <xref linkend="media-link-flag" /> for more details.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="media-link-flag">
-      <title>Media link flags</title>
-      <tgroup cols="2">
-        <colspec colname="c1"/>
-        <colspec colname="c2"/>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MEDIA_LNK_FL_ENABLED</constant></entry>
-           <entry>The link is enabled and can be used to transfer media data.
-           When two or more links target a sink pad, only one of them can be
-           enabled at a time.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_LNK_FL_IMMUTABLE</constant></entry>
-           <entry>The link enabled state can't be modified at runtime. An
-           immutable link is always enabled.</entry>
-         </row>
-         <row>
-           <entry><constant>MEDIA_LNK_FL_DYNAMIC</constant></entry>
-           <entry>The link enabled state can be modified during streaming. This
-           flag is set by drivers and is read-only for applications.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-    <para>One and only one of <constant>MEDIA_PAD_FL_SINK</constant> and
-    <constant>MEDIA_PAD_FL_SOURCE</constant> must be set for every pad.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &media-links-enum; <structfield>id</structfield> references
-         a non-existing entity.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/media-ioc-setup-link.xml b/Documentation/DocBook/v4l/media-ioc-setup-link.xml
deleted file mode 100644 (file)
index cec97af..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-<refentry id="media-ioc-setup-link">
-  <refmeta>
-    <refentrytitle>ioctl MEDIA_IOC_SETUP_LINK</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>MEDIA_IOC_SETUP_LINK</refname>
-    <refpurpose>Modify the properties of a link</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct media_link_desc *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>File descriptor returned by
-         <link linkend='media-func-open'><function>open()</function></link>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>MEDIA_IOC_SETUP_LINK</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To change link properties applications fill a &media-link-desc; with
-    link identification information (source and sink pad) and the new requested
-    link flags. They then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to
-    that structure.</para>
-    <para>The only configurable property is the <constant>ENABLED</constant>
-    link flag to enable/disable a link. Links marked with the
-    <constant>IMMUTABLE</constant> link flag can not be enabled or disabled.
-    </para>
-    <para>Link configuration has no side effect on other links. If an enabled
-    link at the sink pad prevents the link from being enabled, the driver
-    returns with an &EBUSY;.</para>
-    <para>Only links marked with the <constant>DYNAMIC</constant> link flag can
-    be enabled/disabled while streaming media data. Attempting to enable or
-    disable a streaming non-dynamic link will return an &EBUSY;.</para>
-    <para>If the specified link can't be found the driver returns with an
-    &EINVAL;.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The link properties can't be changed because the link is
-         currently busy. This can be caused, for instance, by an active media
-         stream (audio or video) on the link. The ioctl shouldn't be retried if
-         no other action is performed before to fix the problem.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &media-link-desc; references a non-existing link, or the
-         link is immutable and an attempt to modify its configuration was made.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/nv12mt.gif b/Documentation/DocBook/v4l/nv12mt.gif
deleted file mode 100644 (file)
index ef2d4cf..0000000
Binary files a/Documentation/DocBook/v4l/nv12mt.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/nv12mt_example.gif b/Documentation/DocBook/v4l/nv12mt_example.gif
deleted file mode 100644 (file)
index df81d68..0000000
Binary files a/Documentation/DocBook/v4l/nv12mt_example.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/pipeline.pdf b/Documentation/DocBook/v4l/pipeline.pdf
deleted file mode 100644 (file)
index ee3e37f..0000000
Binary files a/Documentation/DocBook/v4l/pipeline.pdf and /dev/null differ
diff --git a/Documentation/DocBook/v4l/pipeline.png b/Documentation/DocBook/v4l/pipeline.png
deleted file mode 100644 (file)
index f19b86c..0000000
Binary files a/Documentation/DocBook/v4l/pipeline.png and /dev/null differ
diff --git a/Documentation/DocBook/v4l/pixfmt-grey.xml b/Documentation/DocBook/v4l/pixfmt-grey.xml
deleted file mode 100644 (file)
index 3b72bc6..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-GREY">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_GREY ('GREY')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_GREY</constant></refname>
-       <refpurpose>Grey-scale image</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is a grey-scale image. It is really a degenerate
-Y'CbCr format which simply contains no Cb or Cr data.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_GREY</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-m420.xml b/Documentation/DocBook/v4l/pixfmt-m420.xml
deleted file mode 100644 (file)
index ce4bc01..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-M420">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_M420 ('M420')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_M420</constant></refname>
-       <refpurpose>Format with &frac12; horizontal and vertical chroma
-       resolution, also known as YUV 4:2:0. Hybrid plane line-interleaved
-       layout.</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>M420 is a YUV format with &frac12; horizontal and vertical chroma
-       subsampling (YUV 4:2:0). Pixels are organized as interleaved luma and
-       chroma planes. Two lines of luma data are followed by one line of chroma
-       data.</para>
-       <para>The luma plane has one byte per pixel. The chroma plane contains
-       interleaved CbCr pixels subsampled by &frac12; in the horizontal and
-       vertical directions. Each CbCr pair belongs to four pixels. For example,
-Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
-Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
-Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.</para>
-
-       <para>All line lengths are identical: if the Y lines include pad bytes
-       so do the CbCr lines.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_M420</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-nv12.xml b/Documentation/DocBook/v4l/pixfmt-nv12.xml
deleted file mode 100644 (file)
index 873f670..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_NV12 ('NV12'), V4L2_PIX_FMT_NV21 ('NV21')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-NV12"><constant>V4L2_PIX_FMT_NV12</constant></refname>
-       <refname id="V4L2-PIX-FMT-NV21"><constant>V4L2_PIX_FMT_NV21</constant></refname>
-       <refpurpose>Formats with &frac12; horizontal and vertical
-chroma resolution, also known as YUV 4:2:0. One luminance and one
-chrominance plane with alternating chroma samples as opposed to
-<constant>V4L2_PIX_FMT_YVU420</constant></refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These are two-plane versions of the YUV 4:2:0 format.
-The three components are separated into two sub-images or planes. The
-Y plane is first. The Y plane has one byte per pixel. For
-<constant>V4L2_PIX_FMT_NV12</constant>, a combined CbCr plane
-immediately follows the Y plane in memory.  The CbCr plane is the same
-width, in bytes, as the Y plane (and of the image), but is half as
-tall in pixels. Each CbCr pair belongs to four pixels. For example,
-Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
-Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
-Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.
-<constant>V4L2_PIX_FMT_NV21</constant> is the same except the Cb and
-Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the
-CbCr plane has as many pad bytes after its rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_NV12</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-nv12m.xml b/Documentation/DocBook/v4l/pixfmt-nv12m.xml
deleted file mode 100644 (file)
index c9e166d..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-NV12M">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_NV12M ('NV12M')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname> <constant>V4L2_PIX_FMT_NV12M</constant></refname>
-       <refpurpose>Variation of <constant>V4L2_PIX_FMT_NV12</constant> with planes
-         non contiguous in memory. </refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is a multi-planar, two-plane version of the YUV 4:2:0 format.
-The three components are separated into two sub-images or planes.
-<constant>V4L2_PIX_FMT_NV12M</constant> differs from <constant>V4L2_PIX_FMT_NV12
-</constant> in that the two planes are non-contiguous in memory, i.e. the chroma
-plane do not necessarily immediately follows the luma plane.
-The luminance data occupies the first plane. The Y plane has one byte per pixel.
-In the second plane there is a chrominance data with alternating chroma samples.
-The CbCr plane is the same width, in bytes, as the Y plane (and of the image),
-but is half as tall in pixels. Each CbCr pair belongs to four pixels. For example,
-Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
-Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
-Y'<subscript>10</subscript>, Y'<subscript>11</subscript>. </para>
-
-       <para><constant>V4L2_PIX_FMT_NV12M</constant> is intended to be
-used only in drivers and applications that support the multi-planar API,
-described in <xref linkend="planar-apis"/>. </para>
-
-       <para>If the Y plane has pad bytes after each row, then the
-CbCr plane has as many pad bytes after its rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_NV12M</constant> 4 &times; 4 pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;4:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-nv12mt.xml b/Documentation/DocBook/v4l/pixfmt-nv12mt.xml
deleted file mode 100644 (file)
index 7a2855a..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_NV12MT ('TM12')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-NV12MT"><constant>V4L2_PIX_FMT_NV12MT
-</constant></refname>
-       <refpurpose>Formats with &frac12; horizontal and vertical
-chroma resolution. This format has two planes - one for luminance and one for
-chrominance. Chroma samples are interleaved. The difference to
-<constant>V4L2_PIX_FMT_NV12</constant> is the memory layout. Pixels are
-grouped in macroblocks of 64x32 size. The order of macroblocks in memory is
-also not standard.
-       </refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is the two-plane versions of the YUV 4:2:0 format where data
-is grouped into 64x32 macroblocks. The three components are separated into two
-sub-images or planes. The Y plane has one byte per pixel and pixels are grouped
-into 64x32 macroblocks. The CbCr plane has the same width, in bytes, as the Y
-plane (and the image), but is half as tall in pixels. The chroma plane is also
-grouped into 64x32 macroblocks.</para>
-       <para>Width of the buffer has to be aligned to the multiple of 128, and
-height alignment is 32. Every four adjactent buffers - two horizontally and two
-vertically are grouped together and are located in memory in Z or flipped Z
-order. </para>
-       <para>Layout of macroblocks in memory is presented in the following
-figure.</para>
-       <para><figure id="nv12mt">
-           <title><constant>V4L2_PIX_FMT_NV12MT</constant> macroblock Z shape
-memory layout</title>
-           <mediaobject>
-             <imageobject>
-               <imagedata fileref="nv12mt.gif" format="GIF" />
-             </imageobject>
-           </mediaobject>
-       </figure>
-       The requirement that width is multiple of 128 is implemented because,
-the Z shape cannot be cut in half horizontally. In case the vertical resolution
-of macroblocks is odd then the last row of macroblocks is arranged in a linear
-order.  </para>
-       <para>In case of chroma the layout is identical. Cb and Cr samples are
-interleaved. Height of the buffer is aligned to 32.
-       </para>
-       <example>
-         <title>Memory layout of macroblocks in <constant>V4L2_PIX_FMT_NV12
-</constant> format pixel image - extreme case</title>
-       <para>
-       <figure id="nv12mt_ex">
-           <title>Example <constant>V4L2_PIX_FMT_NV12MT</constant> memory
-layout of macroblocks</title>
-           <mediaobject>
-             <imageobject>
-               <imagedata fileref="nv12mt_example.gif" format="GIF" />
-             </imageobject>
-           </mediaobject>
-       </figure>
-       Memory layout of macroblocks of <constant>V4L2_PIX_FMT_NV12MT
-</constant> format in most extreme case.
-       </para>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-nv16.xml b/Documentation/DocBook/v4l/pixfmt-nv16.xml
deleted file mode 100644 (file)
index 2609403..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_NV16 ('NV16'), V4L2_PIX_FMT_NV61 ('NV61')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-NV16"><constant>V4L2_PIX_FMT_NV16</constant></refname>
-       <refname id="V4L2-PIX-FMT-NV61"><constant>V4L2_PIX_FMT_NV61</constant></refname>
-       <refpurpose>Formats with &frac12; horizontal
-chroma resolution, also known as YUV 4:2:2. One luminance and one
-chrominance plane with alternating chroma samples as opposed to
-<constant>V4L2_PIX_FMT_YVU420</constant></refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These are two-plane versions of the YUV 4:2:2 format.
-The three components are separated into two sub-images or planes. The
-Y plane is first. The Y plane has one byte per pixel. For
-<constant>V4L2_PIX_FMT_NV16</constant>, a combined CbCr plane
-immediately follows the Y plane in memory.  The CbCr plane is the same
-width and height, in bytes, as the Y plane (and of the image).
-Each CbCr pair belongs to two pixels. For example,
-Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
-Y'<subscript>00</subscript>, Y'<subscript>01</subscript>.
-<constant>V4L2_PIX_FMT_NV61</constant> is the same except the Cb and
-Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the
-CbCr plane has as many pad bytes after its rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_NV16</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;28:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/v4l/pixfmt-packed-rgb.xml
deleted file mode 100644 (file)
index 4db272b..0000000
+++ /dev/null
@@ -1,940 +0,0 @@
-<refentry id="packed-rgb">
-  <refmeta>
-    <refentrytitle>Packed RGB formats</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname>Packed RGB formats</refname>
-    <refpurpose>Packed RGB formats</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>These formats are designed to match the pixel formats of
-typical PC graphics frame buffers. They occupy 8, 16, 24 or 32 bits
-per pixel. These are all packed-pixel formats, meaning all the data
-for a pixel lie next to each other in memory.</para>
-
-    <para>When one of these formats is used, drivers shall report the
-colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
-
-    <table pgwide="1" frame="none" id="rgb-formats">
-      <title>Packed RGB Image Formats</title>
-      <tgroup cols="37" align="center">
-       <colspec colname="id" align="left" />
-       <colspec colname="fourcc" />
-       <colspec colname="bit" />
-
-       <colspec colnum="4" colname="b07" align="center" />
-       <colspec colnum="5" colname="b06" align="center" />
-       <colspec colnum="6" colname="b05" align="center" />
-       <colspec colnum="7" colname="b04" align="center" />
-       <colspec colnum="8" colname="b03" align="center" />
-       <colspec colnum="9" colname="b02" align="center" />
-       <colspec colnum="10" colname="b01" align="center" />
-       <colspec colnum="11" colname="b00" align="center" />
-
-       <colspec colnum="13" colname="b17" align="center" />
-       <colspec colnum="14" colname="b16" align="center" />
-       <colspec colnum="15" colname="b15" align="center" />
-       <colspec colnum="16" colname="b14" align="center" />
-       <colspec colnum="17" colname="b13" align="center" />
-       <colspec colnum="18" colname="b12" align="center" />
-       <colspec colnum="19" colname="b11" align="center" />
-       <colspec colnum="20" colname="b10" align="center" />
-
-       <colspec colnum="22" colname="b27" align="center" />
-       <colspec colnum="23" colname="b26" align="center" />
-       <colspec colnum="24" colname="b25" align="center" />
-       <colspec colnum="25" colname="b24" align="center" />
-       <colspec colnum="26" colname="b23" align="center" />
-       <colspec colnum="27" colname="b22" align="center" />
-       <colspec colnum="28" colname="b21" align="center" />
-       <colspec colnum="29" colname="b20" align="center" />
-
-       <colspec colnum="31" colname="b37" align="center" />
-       <colspec colnum="32" colname="b36" align="center" />
-       <colspec colnum="33" colname="b35" align="center" />
-       <colspec colnum="34" colname="b34" align="center" />
-       <colspec colnum="35" colname="b33" align="center" />
-       <colspec colnum="36" colname="b32" align="center" />
-       <colspec colnum="37" colname="b31" align="center" />
-       <colspec colnum="38" colname="b30" align="center" />
-
-       <spanspec namest="b07" nameend="b00" spanname="b0" />
-       <spanspec namest="b17" nameend="b10" spanname="b1" />
-       <spanspec namest="b27" nameend="b20" spanname="b2" />
-       <spanspec namest="b37" nameend="b30" spanname="b3" />
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>&nbsp;</entry>
-           <entry spanname="b0">Byte&nbsp;0 in memory</entry>
-           <entry spanname="b1">Byte&nbsp;1</entry>
-           <entry spanname="b2">Byte&nbsp;2</entry>
-           <entry spanname="b3">Byte&nbsp;3</entry>
-         </row>
-         <row>
-           <entry>&nbsp;</entry>
-           <entry>&nbsp;</entry>
-           <entry>Bit</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row id="V4L2-PIX-FMT-RGB332">
-           <entry><constant>V4L2_PIX_FMT_RGB332</constant></entry>
-           <entry>'RGB1'</entry>
-           <entry></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB444">
-           <entry><constant>V4L2_PIX_FMT_RGB444</constant></entry>
-           <entry>'R444'</entry>
-           <entry></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB555">
-           <entry><constant>V4L2_PIX_FMT_RGB555</constant></entry>
-           <entry>'RGBO'</entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a</entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB565">
-           <entry><constant>V4L2_PIX_FMT_RGB565</constant></entry>
-           <entry>'RGBP'</entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB555X">
-           <entry><constant>V4L2_PIX_FMT_RGB555X</constant></entry>
-           <entry>'RGBQ'</entry>
-           <entry></entry>
-           <entry>a</entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB565X">
-           <entry><constant>V4L2_PIX_FMT_RGB565X</constant></entry>
-           <entry>'RGBR'</entry>
-           <entry></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-BGR666">
-           <entry><constant>V4L2_PIX_FMT_BGR666</constant></entry>
-           <entry>'BGRH'</entry>
-           <entry></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-BGR24">
-           <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
-           <entry>'BGR3'</entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB24">
-           <entry><constant>V4L2_PIX_FMT_RGB24</constant></entry>
-           <entry>'RGB3'</entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-BGR32">
-           <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
-           <entry>'BGR4'</entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>7</subscript></entry>
-           <entry>a<subscript>6</subscript></entry>
-           <entry>a<subscript>5</subscript></entry>
-           <entry>a<subscript>4</subscript></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-RGB32">
-           <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
-           <entry>'RGB4'</entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>7</subscript></entry>
-           <entry>a<subscript>6</subscript></entry>
-           <entry>a<subscript>5</subscript></entry>
-           <entry>a<subscript>4</subscript></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Bit 7 is the most significant bit. The value of a = alpha
-bits is undefined when reading from the driver, ignored when writing
-to the driver, except when alpha blending has been negotiated for a
-<link linkend="overlay">Video Overlay</link> or <link
-linkend="osd">Video Output Overlay</link>.</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_BGR24</constant> 4 &times; 4 pixel
-image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-             <informaltable frame="none">
-           <tgroup cols="13" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>B<subscript>00</subscript></entry>
-                 <entry>G<subscript>00</subscript></entry>
-                 <entry>R<subscript>00</subscript></entry>
-                 <entry>B<subscript>01</subscript></entry>
-                 <entry>G<subscript>01</subscript></entry>
-                 <entry>R<subscript>01</subscript></entry>
-                 <entry>B<subscript>02</subscript></entry>
-                 <entry>G<subscript>02</subscript></entry>
-                 <entry>R<subscript>02</subscript></entry>
-                 <entry>B<subscript>03</subscript></entry>
-                 <entry>G<subscript>03</subscript></entry>
-                 <entry>R<subscript>03</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;12:</entry>
-                 <entry>B<subscript>10</subscript></entry>
-                 <entry>G<subscript>10</subscript></entry>
-                 <entry>R<subscript>10</subscript></entry>
-                 <entry>B<subscript>11</subscript></entry>
-                 <entry>G<subscript>11</subscript></entry>
-                 <entry>R<subscript>11</subscript></entry>
-                 <entry>B<subscript>12</subscript></entry>
-                 <entry>G<subscript>12</subscript></entry>
-                 <entry>R<subscript>12</subscript></entry>
-                 <entry>B<subscript>13</subscript></entry>
-                 <entry>G<subscript>13</subscript></entry>
-                 <entry>R<subscript>13</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>B<subscript>20</subscript></entry>
-                 <entry>G<subscript>20</subscript></entry>
-                 <entry>R<subscript>20</subscript></entry>
-                 <entry>B<subscript>21</subscript></entry>
-                 <entry>G<subscript>21</subscript></entry>
-                 <entry>R<subscript>21</subscript></entry>
-                 <entry>B<subscript>22</subscript></entry>
-                 <entry>G<subscript>22</subscript></entry>
-                 <entry>R<subscript>22</subscript></entry>
-                 <entry>B<subscript>23</subscript></entry>
-                 <entry>G<subscript>23</subscript></entry>
-                 <entry>R<subscript>23</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;36:</entry>
-                 <entry>B<subscript>30</subscript></entry>
-                 <entry>G<subscript>30</subscript></entry>
-                 <entry>R<subscript>30</subscript></entry>
-                 <entry>B<subscript>31</subscript></entry>
-                 <entry>G<subscript>31</subscript></entry>
-                 <entry>R<subscript>31</subscript></entry>
-                 <entry>B<subscript>32</subscript></entry>
-                 <entry>G<subscript>32</subscript></entry>
-                 <entry>R<subscript>32</subscript></entry>
-                 <entry>B<subscript>33</subscript></entry>
-                 <entry>G<subscript>33</subscript></entry>
-                 <entry>R<subscript>33</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-             </informaltable>
-           </para>
-      </formalpara>
-    </example>
-
-    <important>
-      <para>Drivers may interpret these formats differently.</para>
-    </important>
-
-    <para>Some RGB formats above are uncommon and were probably
-defined in error. Drivers may interpret them as in <xref
-       linkend="rgb-formats-corrected" />.</para>
-
-    <table pgwide="1" frame="none" id="rgb-formats-corrected">
-      <title>Packed RGB Image Formats (corrected)</title>
-      <tgroup cols="37" align="center">
-       <colspec colname="id" align="left" />
-       <colspec colname="fourcc" />
-       <colspec colname="bit" />
-
-       <colspec colnum="4" colname="b07" align="center" />
-       <colspec colnum="5" colname="b06" align="center" />
-       <colspec colnum="6" colname="b05" align="center" />
-       <colspec colnum="7" colname="b04" align="center" />
-       <colspec colnum="8" colname="b03" align="center" />
-       <colspec colnum="9" colname="b02" align="center" />
-       <colspec colnum="10" colname="b01" align="center" />
-       <colspec colnum="11" colname="b00" align="center" />
-
-       <colspec colnum="13" colname="b17" align="center" />
-       <colspec colnum="14" colname="b16" align="center" />
-       <colspec colnum="15" colname="b15" align="center" />
-       <colspec colnum="16" colname="b14" align="center" />
-       <colspec colnum="17" colname="b13" align="center" />
-       <colspec colnum="18" colname="b12" align="center" />
-       <colspec colnum="19" colname="b11" align="center" />
-       <colspec colnum="20" colname="b10" align="center" />
-
-       <colspec colnum="22" colname="b27" align="center" />
-       <colspec colnum="23" colname="b26" align="center" />
-       <colspec colnum="24" colname="b25" align="center" />
-       <colspec colnum="25" colname="b24" align="center" />
-       <colspec colnum="26" colname="b23" align="center" />
-       <colspec colnum="27" colname="b22" align="center" />
-       <colspec colnum="28" colname="b21" align="center" />
-       <colspec colnum="29" colname="b20" align="center" />
-
-       <colspec colnum="31" colname="b37" align="center" />
-       <colspec colnum="32" colname="b36" align="center" />
-       <colspec colnum="33" colname="b35" align="center" />
-       <colspec colnum="34" colname="b34" align="center" />
-       <colspec colnum="35" colname="b33" align="center" />
-       <colspec colnum="36" colname="b32" align="center" />
-       <colspec colnum="37" colname="b31" align="center" />
-       <colspec colnum="38" colname="b30" align="center" />
-
-       <spanspec namest="b07" nameend="b00" spanname="b0" />
-       <spanspec namest="b17" nameend="b10" spanname="b1" />
-       <spanspec namest="b27" nameend="b20" spanname="b2" />
-       <spanspec namest="b37" nameend="b30" spanname="b3" />
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>&nbsp;</entry>
-           <entry spanname="b0">Byte&nbsp;0 in memory</entry>
-           <entry spanname="b1">Byte&nbsp;1</entry>
-           <entry spanname="b2">Byte&nbsp;2</entry>
-           <entry spanname="b3">Byte&nbsp;3</entry>
-         </row>
-         <row>
-           <entry>&nbsp;</entry>
-           <entry>&nbsp;</entry>
-           <entry>Bit</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row><!-- id="V4L2-PIX-FMT-RGB332" -->
-           <entry><constant>V4L2_PIX_FMT_RGB332</constant></entry>
-           <entry>'RGB1'</entry>
-           <entry></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row><!-- id="V4L2-PIX-FMT-RGB444" -->
-           <entry><constant>V4L2_PIX_FMT_RGB444</constant></entry>
-           <entry>'R444'</entry>
-           <entry></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row><!-- id="V4L2-PIX-FMT-RGB555" -->
-           <entry><constant>V4L2_PIX_FMT_RGB555</constant></entry>
-           <entry>'RGBO'</entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a</entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-         </row>
-         <row><!-- id="V4L2-PIX-FMT-RGB565" -->
-           <entry><constant>V4L2_PIX_FMT_RGB565</constant></entry>
-           <entry>'RGBP'</entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-         </row>
-         <row><!-- id="V4L2-PIX-FMT-RGB555X" -->
-           <entry><constant>V4L2_PIX_FMT_RGB555X</constant></entry>
-           <entry>'RGBQ'</entry>
-           <entry></entry>
-           <entry>a</entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row><!-- id="V4L2-PIX-FMT-RGB565X" -->
-           <entry><constant>V4L2_PIX_FMT_RGB565X</constant></entry>
-           <entry>'RGBR'</entry>
-           <entry></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row><!-- id="V4L2-PIX-FMT-BGR666" -->
-           <entry><constant>V4L2_PIX_FMT_BGR666</constant></entry>
-           <entry>'BGRH'</entry>
-           <entry></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row><!-- id="V4L2-PIX-FMT-BGR24" -->
-           <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
-           <entry>'BGR3'</entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-         </row>
-         <row><!-- id="V4L2-PIX-FMT-RGB24" -->
-           <entry><constant>V4L2_PIX_FMT_RGB24</constant></entry>
-           <entry>'RGB3'</entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-         <row><!-- id="V4L2-PIX-FMT-BGR32" -->
-           <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry>
-           <entry>'BGR4'</entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>7</subscript></entry>
-           <entry>a<subscript>6</subscript></entry>
-           <entry>a<subscript>5</subscript></entry>
-           <entry>a<subscript>4</subscript></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-         </row>
-         <row><!-- id="V4L2-PIX-FMT-RGB32" -->
-           <entry><constant>V4L2_PIX_FMT_RGB32</constant></entry>
-           <entry>'RGB4'</entry>
-           <entry></entry>
-           <entry>a<subscript>7</subscript></entry>
-           <entry>a<subscript>6</subscript></entry>
-           <entry>a<subscript>5</subscript></entry>
-           <entry>a<subscript>4</subscript></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>r<subscript>7</subscript></entry>
-           <entry>r<subscript>6</subscript></entry>
-           <entry>r<subscript>5</subscript></entry>
-           <entry>r<subscript>4</subscript></entry>
-           <entry>r<subscript>3</subscript></entry>
-           <entry>r<subscript>2</subscript></entry>
-           <entry>r<subscript>1</subscript></entry>
-           <entry>r<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>g<subscript>7</subscript></entry>
-           <entry>g<subscript>6</subscript></entry>
-           <entry>g<subscript>5</subscript></entry>
-           <entry>g<subscript>4</subscript></entry>
-           <entry>g<subscript>3</subscript></entry>
-           <entry>g<subscript>2</subscript></entry>
-           <entry>g<subscript>1</subscript></entry>
-           <entry>g<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>b<subscript>7</subscript></entry>
-           <entry>b<subscript>6</subscript></entry>
-           <entry>b<subscript>5</subscript></entry>
-           <entry>b<subscript>4</subscript></entry>
-           <entry>b<subscript>3</subscript></entry>
-           <entry>b<subscript>2</subscript></entry>
-           <entry>b<subscript>1</subscript></entry>
-           <entry>b<subscript>0</subscript></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>A test utility to determine which RGB formats a driver
-actually supports is available from the LinuxTV v4l-dvb repository.
-See &v4l-dvb; for access instructions.</para>
-
-  </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-packed-yuv.xml b/Documentation/DocBook/v4l/pixfmt-packed-yuv.xml
deleted file mode 100644 (file)
index 3cab5d0..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-<refentry id="packed-yuv">
-  <refmeta>
-    <refentrytitle>Packed YUV formats</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname>Packed YUV formats</refname>
-    <refpurpose>Packed YUV formats</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>Similar to the packed RGB formats these formats store
-the Y, Cb and Cr component of each pixel in one 16 or 32 bit
-word.</para>
-
-    <table pgwide="1" frame="none">
-      <title>Packed YUV Image Formats</title>
-      <tgroup cols="37" align="center">
-       <colspec colname="id" align="left" />
-       <colspec colname="fourcc" />
-       <colspec colname="bit" />
-
-       <colspec colnum="4" colname="b07" align="center" />
-       <colspec colnum="5" colname="b06" align="center" />
-       <colspec colnum="6" colname="b05" align="center" />
-       <colspec colnum="7" colname="b04" align="center" />
-       <colspec colnum="8" colname="b03" align="center" />
-       <colspec colnum="9" colname="b02" align="center" />
-       <colspec colnum="10" colname="b01" align="center" />
-       <colspec colnum="11" colname="b00" align="center" />
-
-       <colspec colnum="13" colname="b17" align="center" />
-       <colspec colnum="14" colname="b16" align="center" />
-       <colspec colnum="15" colname="b15" align="center" />
-       <colspec colnum="16" colname="b14" align="center" />
-       <colspec colnum="17" colname="b13" align="center" />
-       <colspec colnum="18" colname="b12" align="center" />
-       <colspec colnum="19" colname="b11" align="center" />
-       <colspec colnum="20" colname="b10" align="center" />
-
-       <colspec colnum="22" colname="b27" align="center" />
-       <colspec colnum="23" colname="b26" align="center" />
-       <colspec colnum="24" colname="b25" align="center" />
-       <colspec colnum="25" colname="b24" align="center" />
-       <colspec colnum="26" colname="b23" align="center" />
-       <colspec colnum="27" colname="b22" align="center" />
-       <colspec colnum="28" colname="b21" align="center" />
-       <colspec colnum="29" colname="b20" align="center" />
-
-       <colspec colnum="31" colname="b37" align="center" />
-       <colspec colnum="32" colname="b36" align="center" />
-       <colspec colnum="33" colname="b35" align="center" />
-       <colspec colnum="34" colname="b34" align="center" />
-       <colspec colnum="35" colname="b33" align="center" />
-       <colspec colnum="36" colname="b32" align="center" />
-       <colspec colnum="37" colname="b31" align="center" />
-       <colspec colnum="38" colname="b30" align="center" />
-
-       <spanspec namest="b07" nameend="b00" spanname="b0" />
-       <spanspec namest="b17" nameend="b10" spanname="b1" />
-       <spanspec namest="b27" nameend="b20" spanname="b2" />
-       <spanspec namest="b37" nameend="b30" spanname="b3" />
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>&nbsp;</entry>
-           <entry spanname="b0">Byte&nbsp;0 in memory</entry>
-           <entry spanname="b1">Byte&nbsp;1</entry>
-           <entry spanname="b2">Byte&nbsp;2</entry>
-           <entry spanname="b3">Byte&nbsp;3</entry>
-         </row>
-         <row>
-           <entry>&nbsp;</entry>
-           <entry>&nbsp;</entry>
-           <entry>Bit</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-           <entry>&nbsp;</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row id="V4L2-PIX-FMT-YUV444">
-           <entry><constant>V4L2_PIX_FMT_YUV444</constant></entry>
-           <entry>'Y444'</entry>
-           <entry></entry>
-           <entry>Cb<subscript>3</subscript></entry>
-           <entry>Cb<subscript>2</subscript></entry>
-           <entry>Cb<subscript>1</subscript></entry>
-           <entry>Cb<subscript>0</subscript></entry>
-           <entry>Cr<subscript>3</subscript></entry>
-           <entry>Cr<subscript>2</subscript></entry>
-           <entry>Cr<subscript>1</subscript></entry>
-           <entry>Cr<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry>Y'<subscript>3</subscript></entry>
-           <entry>Y'<subscript>2</subscript></entry>
-           <entry>Y'<subscript>1</subscript></entry>
-           <entry>Y'<subscript>0</subscript></entry>
-         </row>
-
-         <row id="V4L2-PIX-FMT-YUV555">
-           <entry><constant>V4L2_PIX_FMT_YUV555</constant></entry>
-           <entry>'YUVO'</entry>
-           <entry></entry>
-           <entry>Cb<subscript>2</subscript></entry>
-           <entry>Cb<subscript>1</subscript></entry>
-           <entry>Cb<subscript>0</subscript></entry>
-           <entry>Cr<subscript>4</subscript></entry>
-           <entry>Cr<subscript>3</subscript></entry>
-           <entry>Cr<subscript>2</subscript></entry>
-           <entry>Cr<subscript>1</subscript></entry>
-           <entry>Cr<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>a</entry>
-           <entry>Y'<subscript>4</subscript></entry>
-           <entry>Y'<subscript>3</subscript></entry>
-           <entry>Y'<subscript>2</subscript></entry>
-           <entry>Y'<subscript>1</subscript></entry>
-           <entry>Y'<subscript>0</subscript></entry>
-           <entry>Cb<subscript>4</subscript></entry>
-           <entry>Cb<subscript>3</subscript></entry>
-         </row>
-
-         <row id="V4L2-PIX-FMT-YUV565">
-           <entry><constant>V4L2_PIX_FMT_YUV565</constant></entry>
-           <entry>'YUVP'</entry>
-           <entry></entry>
-           <entry>Cb<subscript>2</subscript></entry>
-           <entry>Cb<subscript>1</subscript></entry>
-           <entry>Cb<subscript>0</subscript></entry>
-           <entry>Cr<subscript>4</subscript></entry>
-           <entry>Cr<subscript>3</subscript></entry>
-           <entry>Cr<subscript>2</subscript></entry>
-           <entry>Cr<subscript>1</subscript></entry>
-           <entry>Cr<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>Y'<subscript>4</subscript></entry>
-           <entry>Y'<subscript>3</subscript></entry>
-           <entry>Y'<subscript>2</subscript></entry>
-           <entry>Y'<subscript>1</subscript></entry>
-           <entry>Y'<subscript>0</subscript></entry>
-           <entry>Cb<subscript>5</subscript></entry>
-           <entry>Cb<subscript>4</subscript></entry>
-           <entry>Cb<subscript>3</subscript></entry>
-         </row>
-
-         <row id="V4L2-PIX-FMT-YUV32">
-           <entry><constant>V4L2_PIX_FMT_YUV32</constant></entry>
-           <entry>'YUV4'</entry>
-           <entry></entry>
-           <entry>a<subscript>7</subscript></entry>
-           <entry>a<subscript>6</subscript></entry>
-           <entry>a<subscript>5</subscript></entry>
-           <entry>a<subscript>4</subscript></entry>
-           <entry>a<subscript>3</subscript></entry>
-           <entry>a<subscript>2</subscript></entry>
-           <entry>a<subscript>1</subscript></entry>
-           <entry>a<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>Y'<subscript>7</subscript></entry>
-           <entry>Y'<subscript>6</subscript></entry>
-           <entry>Y'<subscript>5</subscript></entry>
-           <entry>Y'<subscript>4</subscript></entry>
-           <entry>Y'<subscript>3</subscript></entry>
-           <entry>Y'<subscript>2</subscript></entry>
-           <entry>Y'<subscript>1</subscript></entry>
-           <entry>Y'<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>Cb<subscript>7</subscript></entry>
-           <entry>Cb<subscript>6</subscript></entry>
-           <entry>Cb<subscript>5</subscript></entry>
-           <entry>Cb<subscript>4</subscript></entry>
-           <entry>Cb<subscript>3</subscript></entry>
-           <entry>Cb<subscript>2</subscript></entry>
-           <entry>Cb<subscript>1</subscript></entry>
-           <entry>Cb<subscript>0</subscript></entry>
-           <entry></entry>
-           <entry>Cr<subscript>7</subscript></entry>
-           <entry>Cr<subscript>6</subscript></entry>
-           <entry>Cr<subscript>5</subscript></entry>
-           <entry>Cr<subscript>4</subscript></entry>
-           <entry>Cr<subscript>3</subscript></entry>
-           <entry>Cr<subscript>2</subscript></entry>
-           <entry>Cr<subscript>1</subscript></entry>
-           <entry>Cr<subscript>0</subscript></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para>Bit 7 is the most significant bit. The value of a = alpha
-bits is undefined when reading from the driver, ignored when writing
-to the driver, except when alpha blending has been negotiated for a
-<link linkend="overlay">Video Overlay</link> or <link
-linkend="osd">Video Output Overlay</link>.</para>
-
-  </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-sbggr16.xml b/Documentation/DocBook/v4l/pixfmt-sbggr16.xml
deleted file mode 100644 (file)
index 519a9ef..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-<refentry id="V4L2-PIX-FMT-SBGGR16">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_SBGGR16 ('BYR2')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_SBGGR16</constant></refname>
-    <refpurpose>Bayer RGB format</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This format is similar to <link
-linkend="V4L2-PIX-FMT-SBGGR8">
-<constant>V4L2_PIX_FMT_SBGGR8</constant></link>, except each pixel has
-a depth of 16 bits. The least significant byte is stored at lower
-memory addresses (little-endian). Note the actual sampling precision
-may be lower than 16 bits, for example 10 bits per pixel with values
-in range 0 to 1023.</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_SBGGR16</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="5" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>B<subscript>00low</subscript></entry>
-                 <entry>B<subscript>00high</subscript></entry>
-                 <entry>G<subscript>01low</subscript></entry>
-                 <entry>G<subscript>01high</subscript></entry>
-                 <entry>B<subscript>02low</subscript></entry>
-                 <entry>B<subscript>02high</subscript></entry>
-                 <entry>G<subscript>03low</subscript></entry>
-                 <entry>G<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>G<subscript>10low</subscript></entry>
-                 <entry>G<subscript>10high</subscript></entry>
-                 <entry>R<subscript>11low</subscript></entry>
-                 <entry>R<subscript>11high</subscript></entry>
-                 <entry>G<subscript>12low</subscript></entry>
-                 <entry>G<subscript>12high</subscript></entry>
-                 <entry>R<subscript>13low</subscript></entry>
-                 <entry>R<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>B<subscript>20low</subscript></entry>
-                 <entry>B<subscript>20high</subscript></entry>
-                 <entry>G<subscript>21low</subscript></entry>
-                 <entry>G<subscript>21high</subscript></entry>
-                 <entry>B<subscript>22low</subscript></entry>
-                 <entry>B<subscript>22high</subscript></entry>
-                 <entry>G<subscript>23low</subscript></entry>
-                 <entry>G<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>G<subscript>30low</subscript></entry>
-                 <entry>G<subscript>30high</subscript></entry>
-                 <entry>R<subscript>31low</subscript></entry>
-                 <entry>R<subscript>31high</subscript></entry>
-                 <entry>G<subscript>32low</subscript></entry>
-                 <entry>G<subscript>32high</subscript></entry>
-                 <entry>R<subscript>33low</subscript></entry>
-                 <entry>R<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-sbggr8.xml b/Documentation/DocBook/v4l/pixfmt-sbggr8.xml
deleted file mode 100644 (file)
index 5fe84ec..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-SBGGR8">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SBGGR8 ('BA81')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_SBGGR8</constant></refname>
-       <refpurpose>Bayer RGB format</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is commonly the native format of digital cameras,
-reflecting the arrangement of sensors on the CCD device. Only one red,
-green or blue value is given for each pixel. Missing components must
-be interpolated from neighbouring pixels. From left to right the first
-row consists of a blue and green value, the second row of a green and
-red value. This scheme repeats to the right and down for every two
-columns and rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_SBGGR8</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-             <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>B<subscript>00</subscript></entry>
-                     <entry>G<subscript>01</subscript></entry>
-                     <entry>B<subscript>02</subscript></entry>
-                     <entry>G<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>G<subscript>10</subscript></entry>
-                     <entry>R<subscript>11</subscript></entry>
-                     <entry>G<subscript>12</subscript></entry>
-                     <entry>R<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>B<subscript>20</subscript></entry>
-                     <entry>G<subscript>21</subscript></entry>
-                     <entry>B<subscript>22</subscript></entry>
-                     <entry>G<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>G<subscript>30</subscript></entry>
-                     <entry>R<subscript>31</subscript></entry>
-                     <entry>G<subscript>32</subscript></entry>
-                     <entry>R<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-             </informaltable>
-           </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-sgbrg8.xml b/Documentation/DocBook/v4l/pixfmt-sgbrg8.xml
deleted file mode 100644 (file)
index d67a472..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-SGBRG8">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SGBRG8 ('GBRG')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_SGBRG8</constant></refname>
-       <refpurpose>Bayer RGB format</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is commonly the native format of digital cameras,
-reflecting the arrangement of sensors on the CCD device. Only one red,
-green or blue value is given for each pixel. Missing components must
-be interpolated from neighbouring pixels. From left to right the first
-row consists of a green and blue value, the second row of a red and
-green value. This scheme repeats to the right and down for every two
-columns and rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_SGBRG8</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-             <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>G<subscript>00</subscript></entry>
-                     <entry>B<subscript>01</subscript></entry>
-                     <entry>G<subscript>02</subscript></entry>
-                     <entry>B<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>R<subscript>10</subscript></entry>
-                     <entry>G<subscript>11</subscript></entry>
-                     <entry>R<subscript>12</subscript></entry>
-                     <entry>G<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>G<subscript>20</subscript></entry>
-                     <entry>B<subscript>21</subscript></entry>
-                     <entry>G<subscript>22</subscript></entry>
-                     <entry>B<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>R<subscript>30</subscript></entry>
-                     <entry>G<subscript>31</subscript></entry>
-                     <entry>R<subscript>32</subscript></entry>
-                     <entry>G<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-             </informaltable>
-           </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-sgrbg8.xml b/Documentation/DocBook/v4l/pixfmt-sgrbg8.xml
deleted file mode 100644 (file)
index 0cdf13b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-SGRBG8">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SGRBG8 ('GRBG')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_SGRBG8</constant></refname>
-       <refpurpose>Bayer RGB format</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is commonly the native format of digital cameras,
-reflecting the arrangement of sensors on the CCD device. Only one red,
-green or blue value is given for each pixel. Missing components must
-be interpolated from neighbouring pixels. From left to right the first
-row consists of a green and blue value, the second row of a red and
-green value. This scheme repeats to the right and down for every two
-columns and rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_SGRBG8</constant> 4 &times;
-4 pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-             <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>G<subscript>00</subscript></entry>
-                     <entry>R<subscript>01</subscript></entry>
-                     <entry>G<subscript>02</subscript></entry>
-                     <entry>R<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>R<subscript>10</subscript></entry>
-                     <entry>B<subscript>11</subscript></entry>
-                     <entry>R<subscript>12</subscript></entry>
-                     <entry>B<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>G<subscript>20</subscript></entry>
-                     <entry>R<subscript>21</subscript></entry>
-                     <entry>G<subscript>22</subscript></entry>
-                     <entry>R<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>R<subscript>30</subscript></entry>
-                     <entry>B<subscript>31</subscript></entry>
-                     <entry>R<subscript>32</subscript></entry>
-                     <entry>B<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-             </informaltable>
-           </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-srggb10.xml b/Documentation/DocBook/v4l/pixfmt-srggb10.xml
deleted file mode 100644 (file)
index 7b27409..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SRGGB10 ('RG10'),
-        V4L2_PIX_FMT_SGRBG10 ('BA10'),
-        V4L2_PIX_FMT_SGBRG10 ('GB10'),
-        V4L2_PIX_FMT_SBGGR10 ('BG10'),
-        </refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-SRGGB10"><constant>V4L2_PIX_FMT_SRGGB10</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGRBG10"><constant>V4L2_PIX_FMT_SGRBG10</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGBRG10"><constant>V4L2_PIX_FMT_SGBRG10</constant></refname>
-       <refname id="V4L2-PIX-FMT-SBGGR10"><constant>V4L2_PIX_FMT_SBGGR10</constant></refname>
-       <refpurpose>10-bit Bayer formats expanded to 16 bits</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>The following four pixel formats are raw sRGB / Bayer formats with
-10 bits per colour. Each colour component is stored in a 16-bit word, with 6
-unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
-and n/2 blue or red samples, with alternating red and blue rows. Bytes are
-stored in memory in little endian order. They are conventionally described
-as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an example of one of these
-formats</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_SBGGR10</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte, high 6 bits in high bytes are 0.
-         <informaltable frame="none">
-           <tgroup cols="5" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>B<subscript>00low</subscript></entry>
-                 <entry>B<subscript>00high</subscript></entry>
-                 <entry>G<subscript>01low</subscript></entry>
-                 <entry>G<subscript>01high</subscript></entry>
-                 <entry>B<subscript>02low</subscript></entry>
-                 <entry>B<subscript>02high</subscript></entry>
-                 <entry>G<subscript>03low</subscript></entry>
-                 <entry>G<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>G<subscript>10low</subscript></entry>
-                 <entry>G<subscript>10high</subscript></entry>
-                 <entry>R<subscript>11low</subscript></entry>
-                 <entry>R<subscript>11high</subscript></entry>
-                 <entry>G<subscript>12low</subscript></entry>
-                 <entry>G<subscript>12high</subscript></entry>
-                 <entry>R<subscript>13low</subscript></entry>
-                 <entry>R<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>B<subscript>20low</subscript></entry>
-                 <entry>B<subscript>20high</subscript></entry>
-                 <entry>G<subscript>21low</subscript></entry>
-                 <entry>G<subscript>21high</subscript></entry>
-                 <entry>B<subscript>22low</subscript></entry>
-                 <entry>B<subscript>22high</subscript></entry>
-                 <entry>G<subscript>23low</subscript></entry>
-                 <entry>G<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>G<subscript>30low</subscript></entry>
-                 <entry>G<subscript>30high</subscript></entry>
-                 <entry>R<subscript>31low</subscript></entry>
-                 <entry>R<subscript>31high</subscript></entry>
-                 <entry>G<subscript>32low</subscript></entry>
-                 <entry>G<subscript>32high</subscript></entry>
-                 <entry>R<subscript>33low</subscript></entry>
-                 <entry>R<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/pixfmt-srggb12.xml b/Documentation/DocBook/v4l/pixfmt-srggb12.xml
deleted file mode 100644 (file)
index 9ba4fb6..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SRGGB12 ('RG12'),
-        V4L2_PIX_FMT_SGRBG12 ('BA12'),
-        V4L2_PIX_FMT_SGBRG12 ('GB12'),
-        V4L2_PIX_FMT_SBGGR12 ('BG12'),
-        </refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-SRGGB12"><constant>V4L2_PIX_FMT_SRGGB12</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGRBG12"><constant>V4L2_PIX_FMT_SGRBG12</constant></refname>
-       <refname id="V4L2-PIX-FMT-SGBRG12"><constant>V4L2_PIX_FMT_SGBRG12</constant></refname>
-       <refname id="V4L2-PIX-FMT-SBGGR12"><constant>V4L2_PIX_FMT_SBGGR12</constant></refname>
-       <refpurpose>12-bit Bayer formats expanded to 16 bits</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>The following four pixel formats are raw sRGB / Bayer formats with
-12 bits per colour. Each colour component is stored in a 16-bit word, with 6
-unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
-and n/2 blue or red samples, with alternating red and blue rows. Bytes are
-stored in memory in little endian order. They are conventionally described
-as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an example of one of these
-formats</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_SBGGR12</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte, high 6 bits in high bytes are 0.
-         <informaltable frame="none">
-           <tgroup cols="5" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>B<subscript>00low</subscript></entry>
-                 <entry>B<subscript>00high</subscript></entry>
-                 <entry>G<subscript>01low</subscript></entry>
-                 <entry>G<subscript>01high</subscript></entry>
-                 <entry>B<subscript>02low</subscript></entry>
-                 <entry>B<subscript>02high</subscript></entry>
-                 <entry>G<subscript>03low</subscript></entry>
-                 <entry>G<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>G<subscript>10low</subscript></entry>
-                 <entry>G<subscript>10high</subscript></entry>
-                 <entry>R<subscript>11low</subscript></entry>
-                 <entry>R<subscript>11high</subscript></entry>
-                 <entry>G<subscript>12low</subscript></entry>
-                 <entry>G<subscript>12high</subscript></entry>
-                 <entry>R<subscript>13low</subscript></entry>
-                 <entry>R<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>B<subscript>20low</subscript></entry>
-                 <entry>B<subscript>20high</subscript></entry>
-                 <entry>G<subscript>21low</subscript></entry>
-                 <entry>G<subscript>21high</subscript></entry>
-                 <entry>B<subscript>22low</subscript></entry>
-                 <entry>B<subscript>22high</subscript></entry>
-                 <entry>G<subscript>23low</subscript></entry>
-                 <entry>G<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>G<subscript>30low</subscript></entry>
-                 <entry>G<subscript>30high</subscript></entry>
-                 <entry>R<subscript>31low</subscript></entry>
-                 <entry>R<subscript>31high</subscript></entry>
-                 <entry>G<subscript>32low</subscript></entry>
-                 <entry>G<subscript>32high</subscript></entry>
-                 <entry>R<subscript>33low</subscript></entry>
-                 <entry>R<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/pixfmt-srggb8.xml b/Documentation/DocBook/v4l/pixfmt-srggb8.xml
deleted file mode 100644 (file)
index 2570e3b..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-SRGGB8">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_SRGGB8 ('RGGB')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_SRGGB8</constant></refname>
-       <refpurpose>Bayer RGB format</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is commonly the native format of digital cameras,
-reflecting the arrangement of sensors on the CCD device. Only one red,
-green or blue value is given for each pixel. Missing components must
-be interpolated from neighbouring pixels. From left to right the first
-row consists of a red and green value, the second row of a green and
-blue value. This scheme repeats to the right and down for every two
-columns and rows.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_SRGGB8</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-             <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>R<subscript>00</subscript></entry>
-                     <entry>G<subscript>01</subscript></entry>
-                     <entry>R<subscript>02</subscript></entry>
-                     <entry>G<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>G<subscript>10</subscript></entry>
-                     <entry>B<subscript>11</subscript></entry>
-                     <entry>G<subscript>12</subscript></entry>
-                     <entry>B<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>R<subscript>20</subscript></entry>
-                     <entry>G<subscript>21</subscript></entry>
-                     <entry>R<subscript>22</subscript></entry>
-                     <entry>G<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>G<subscript>30</subscript></entry>
-                     <entry>B<subscript>31</subscript></entry>
-                     <entry>G<subscript>32</subscript></entry>
-                     <entry>B<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-             </informaltable>
-           </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
diff --git a/Documentation/DocBook/v4l/pixfmt-uyvy.xml b/Documentation/DocBook/v4l/pixfmt-uyvy.xml
deleted file mode 100644 (file)
index 816c8d4..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-UYVY">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_UYVY ('UYVY')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_UYVY</constant></refname>
-       <refpurpose>Variation of
-<constant>V4L2_PIX_FMT_YUYV</constant> with different order of samples
-in memory</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>In this format each four bytes is two pixels. Each four
-bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
-the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
-components have half the horizontal resolution of the Y
-component.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_UYVY</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="9" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-vyuy.xml b/Documentation/DocBook/v4l/pixfmt-vyuy.xml
deleted file mode 100644 (file)
index 61f12a5..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-VYUY">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_VYUY ('VYUY')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_VYUY</constant></refname>
-       <refpurpose>Variation of
-<constant>V4L2_PIX_FMT_YUYV</constant> with different order of samples
-in memory</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>In this format each four bytes is two pixels. Each four
-bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
-the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
-components have half the horizontal resolution of the Y
-component.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_VYUY</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="9" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-y10.xml b/Documentation/DocBook/v4l/pixfmt-y10.xml
deleted file mode 100644 (file)
index d065043..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y10">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y10 ('Y10 ')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y10</constant></refname>
-    <refpurpose>Grey-scale image</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a grey-scale image with a depth of 10 bits per pixel. Pixels
-are stored in 16-bit words with unused high bits padded with 0. The least
-significant byte is stored at lower memory addresses (little-endian).</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y10</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="9" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>Y'<subscript>00low</subscript></entry>
-                 <entry>Y'<subscript>00high</subscript></entry>
-                 <entry>Y'<subscript>01low</subscript></entry>
-                 <entry>Y'<subscript>01high</subscript></entry>
-                 <entry>Y'<subscript>02low</subscript></entry>
-                 <entry>Y'<subscript>02high</subscript></entry>
-                 <entry>Y'<subscript>03low</subscript></entry>
-                 <entry>Y'<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>Y'<subscript>10low</subscript></entry>
-                 <entry>Y'<subscript>10high</subscript></entry>
-                 <entry>Y'<subscript>11low</subscript></entry>
-                 <entry>Y'<subscript>11high</subscript></entry>
-                 <entry>Y'<subscript>12low</subscript></entry>
-                 <entry>Y'<subscript>12high</subscript></entry>
-                 <entry>Y'<subscript>13low</subscript></entry>
-                 <entry>Y'<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>Y'<subscript>20low</subscript></entry>
-                 <entry>Y'<subscript>20high</subscript></entry>
-                 <entry>Y'<subscript>21low</subscript></entry>
-                 <entry>Y'<subscript>21high</subscript></entry>
-                 <entry>Y'<subscript>22low</subscript></entry>
-                 <entry>Y'<subscript>22high</subscript></entry>
-                 <entry>Y'<subscript>23low</subscript></entry>
-                 <entry>Y'<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>Y'<subscript>30low</subscript></entry>
-                 <entry>Y'<subscript>30high</subscript></entry>
-                 <entry>Y'<subscript>31low</subscript></entry>
-                 <entry>Y'<subscript>31high</subscript></entry>
-                 <entry>Y'<subscript>32low</subscript></entry>
-                 <entry>Y'<subscript>32high</subscript></entry>
-                 <entry>Y'<subscript>33low</subscript></entry>
-                 <entry>Y'<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/pixfmt-y10b.xml b/Documentation/DocBook/v4l/pixfmt-y10b.xml
deleted file mode 100644 (file)
index adb0ad8..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y10BPACK">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y10BPACK ('Y10B')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y10BPACK</constant></refname>
-    <refpurpose>Grey-scale image as a bit-packed array</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a packed grey-scale image format with a depth of 10 bits per
-      pixel. Pixels are stored in a bit-packed array of 10bit bits per pixel,
-      with no padding between them and with the most significant bits coming
-      first from the left.</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y10BPACK</constant> 4 pixel data stream taking 5 bytes</title>
-
-      <formalpara>
-       <title>Bit-packed representation</title>
-       <para>pixels cross the byte boundary and have a ratio of 5 bytes for each 4
-          pixels.
-         <informaltable frame="all">
-           <tgroup cols="5" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>Y'<subscript>00[9:2]</subscript></entry>
-                 <entry>Y'<subscript>00[1:0]</subscript>Y'<subscript>01[9:4]</subscript></entry>
-                 <entry>Y'<subscript>01[3:0]</subscript>Y'<subscript>02[9:6]</subscript></entry>
-                 <entry>Y'<subscript>02[5:0]</subscript>Y'<subscript>03[9:8]</subscript></entry>
-                 <entry>Y'<subscript>03[7:0]</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/pixfmt-y12.xml b/Documentation/DocBook/v4l/pixfmt-y12.xml
deleted file mode 100644 (file)
index ff417b8..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y12">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y12 ('Y12 ')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y12</constant></refname>
-    <refpurpose>Grey-scale image</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a grey-scale image with a depth of 12 bits per pixel. Pixels
-are stored in 16-bit words with unused high bits padded with 0. The least
-significant byte is stored at lower memory addresses (little-endian).</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y12</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="9" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>Y'<subscript>00low</subscript></entry>
-                 <entry>Y'<subscript>00high</subscript></entry>
-                 <entry>Y'<subscript>01low</subscript></entry>
-                 <entry>Y'<subscript>01high</subscript></entry>
-                 <entry>Y'<subscript>02low</subscript></entry>
-                 <entry>Y'<subscript>02high</subscript></entry>
-                 <entry>Y'<subscript>03low</subscript></entry>
-                 <entry>Y'<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>Y'<subscript>10low</subscript></entry>
-                 <entry>Y'<subscript>10high</subscript></entry>
-                 <entry>Y'<subscript>11low</subscript></entry>
-                 <entry>Y'<subscript>11high</subscript></entry>
-                 <entry>Y'<subscript>12low</subscript></entry>
-                 <entry>Y'<subscript>12high</subscript></entry>
-                 <entry>Y'<subscript>13low</subscript></entry>
-                 <entry>Y'<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>Y'<subscript>20low</subscript></entry>
-                 <entry>Y'<subscript>20high</subscript></entry>
-                 <entry>Y'<subscript>21low</subscript></entry>
-                 <entry>Y'<subscript>21high</subscript></entry>
-                 <entry>Y'<subscript>22low</subscript></entry>
-                 <entry>Y'<subscript>22high</subscript></entry>
-                 <entry>Y'<subscript>23low</subscript></entry>
-                 <entry>Y'<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>Y'<subscript>30low</subscript></entry>
-                 <entry>Y'<subscript>30high</subscript></entry>
-                 <entry>Y'<subscript>31low</subscript></entry>
-                 <entry>Y'<subscript>31high</subscript></entry>
-                 <entry>Y'<subscript>32low</subscript></entry>
-                 <entry>Y'<subscript>32high</subscript></entry>
-                 <entry>Y'<subscript>33low</subscript></entry>
-                 <entry>Y'<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/pixfmt-y16.xml b/Documentation/DocBook/v4l/pixfmt-y16.xml
deleted file mode 100644 (file)
index d584040..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<refentry id="V4L2-PIX-FMT-Y16">
-  <refmeta>
-    <refentrytitle>V4L2_PIX_FMT_Y16 ('Y16 ')</refentrytitle>
-    &manvol;
-  </refmeta>
-  <refnamediv>
-    <refname><constant>V4L2_PIX_FMT_Y16</constant></refname>
-    <refpurpose>Grey-scale image</refpurpose>
-  </refnamediv>
-  <refsect1>
-    <title>Description</title>
-
-    <para>This is a grey-scale image with a depth of 16 bits per
-pixel. The least significant byte is stored at lower memory addresses
-(little-endian). Note the actual sampling precision may be lower than
-16 bits, for example 10 bits per pixel with values in range 0 to
-1023.</para>
-
-    <example>
-      <title><constant>V4L2_PIX_FMT_Y16</constant> 4 &times; 4
-pixel image</title>
-
-      <formalpara>
-       <title>Byte Order.</title>
-       <para>Each cell is one byte.
-         <informaltable frame="none">
-           <tgroup cols="9" align="center">
-             <colspec align="left" colwidth="2*" />
-             <tbody valign="top">
-               <row>
-                 <entry>start&nbsp;+&nbsp;0:</entry>
-                 <entry>Y'<subscript>00low</subscript></entry>
-                 <entry>Y'<subscript>00high</subscript></entry>
-                 <entry>Y'<subscript>01low</subscript></entry>
-                 <entry>Y'<subscript>01high</subscript></entry>
-                 <entry>Y'<subscript>02low</subscript></entry>
-                 <entry>Y'<subscript>02high</subscript></entry>
-                 <entry>Y'<subscript>03low</subscript></entry>
-                 <entry>Y'<subscript>03high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;8:</entry>
-                 <entry>Y'<subscript>10low</subscript></entry>
-                 <entry>Y'<subscript>10high</subscript></entry>
-                 <entry>Y'<subscript>11low</subscript></entry>
-                 <entry>Y'<subscript>11high</subscript></entry>
-                 <entry>Y'<subscript>12low</subscript></entry>
-                 <entry>Y'<subscript>12high</subscript></entry>
-                 <entry>Y'<subscript>13low</subscript></entry>
-                 <entry>Y'<subscript>13high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;16:</entry>
-                 <entry>Y'<subscript>20low</subscript></entry>
-                 <entry>Y'<subscript>20high</subscript></entry>
-                 <entry>Y'<subscript>21low</subscript></entry>
-                 <entry>Y'<subscript>21high</subscript></entry>
-                 <entry>Y'<subscript>22low</subscript></entry>
-                 <entry>Y'<subscript>22high</subscript></entry>
-                 <entry>Y'<subscript>23low</subscript></entry>
-                 <entry>Y'<subscript>23high</subscript></entry>
-               </row>
-               <row>
-                 <entry>start&nbsp;+&nbsp;24:</entry>
-                 <entry>Y'<subscript>30low</subscript></entry>
-                 <entry>Y'<subscript>30high</subscript></entry>
-                 <entry>Y'<subscript>31low</subscript></entry>
-                 <entry>Y'<subscript>31high</subscript></entry>
-                 <entry>Y'<subscript>32low</subscript></entry>
-                 <entry>Y'<subscript>32high</subscript></entry>
-                 <entry>Y'<subscript>33low</subscript></entry>
-                 <entry>Y'<subscript>33high</subscript></entry>
-               </row>
-             </tbody>
-           </tgroup>
-         </informaltable>
-       </para>
-      </formalpara>
-    </example>
-  </refsect1>
-</refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-y41p.xml b/Documentation/DocBook/v4l/pixfmt-y41p.xml
deleted file mode 100644 (file)
index 73c8536..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-Y41P">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_Y41P ('Y41P')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_Y41P</constant></refname>
-       <refpurpose>Format with &frac14; horizontal chroma
-resolution, also known as YUV 4:1:1</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>In this format each 12 bytes is eight pixels. In the
-twelve bytes are two CbCr pairs and eight Y's. The first CbCr pair
-goes with the first four Y's, and the second CbCr pair goes with the
-other four Y's. The Cb and Cr components have one fourth the
-horizontal resolution of the Y component.</para>
-
-       <para>Do not confuse this format with <link
-linkend="V4L2-PIX-FMT-YUV411P"><constant>V4L2_PIX_FMT_YUV411P</constant></link>.
-Y41P is derived from "YUV 4:1:1 <emphasis>packed</emphasis>", while
-YUV411P stands for "YUV 4:1:1 <emphasis>planar</emphasis>".</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_Y41P</constant> 8 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="13" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                     <entry>Y'<subscript>04</subscript></entry>
-                     <entry>Y'<subscript>05</subscript></entry>
-                     <entry>Y'<subscript>06</subscript></entry>
-                     <entry>Y'<subscript>07</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                     <entry>Y'<subscript>14</subscript></entry>
-                     <entry>Y'<subscript>15</subscript></entry>
-                     <entry>Y'<subscript>16</subscript></entry>
-                     <entry>Y'<subscript>17</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                     <entry>Y'<subscript>24</subscript></entry>
-                     <entry>Y'<subscript>25</subscript></entry>
-                     <entry>Y'<subscript>26</subscript></entry>
-                     <entry>Y'<subscript>27</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;36:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                     <entry>Y'<subscript>34</subscript></entry>
-                     <entry>Y'<subscript>35</subscript></entry>
-                     <entry>Y'<subscript>36</subscript></entry>
-                     <entry>Y'<subscript>37</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-             </informaltable></para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="15" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry><entry></entry>
-                     <entry>4</entry><entry></entry><entry>5</entry><entry></entry>
-                     <entry>6</entry><entry></entry><entry>7</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-yuv410.xml b/Documentation/DocBook/v4l/pixfmt-yuv410.xml
deleted file mode 100644 (file)
index 8eb4a19..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YVU410 ('YVU9'), V4L2_PIX_FMT_YUV410 ('YUV9')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-YVU410"><constant>V4L2_PIX_FMT_YVU410</constant></refname>
-       <refname id="V4L2-PIX-FMT-YUV410"><constant>V4L2_PIX_FMT_YUV410</constant></refname>
-       <refpurpose>Planar formats with &frac14; horizontal and
-vertical chroma resolution, also known as YUV 4:1:0</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These are planar formats, as opposed to a packed format.
-The three components are separated into three sub-images or planes.
-The Y plane is first. The Y plane has one byte per pixel. For
-<constant>V4L2_PIX_FMT_YVU410</constant>, the Cr plane immediately
-follows the Y plane in memory. The Cr plane is &frac14; the width and
-&frac14; the height of the Y plane (and of the image). Each Cr belongs
-to 16 pixels, a four-by-four square of the image. Following the Cr
-plane is the Cb plane, just like the Cr plane.
-<constant>V4L2_PIX_FMT_YUV410</constant> is the same, except the Cb
-plane comes first, then the Cr plane.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cr
-and Cb planes have &frac14; as many pad bytes after their rows. In
-other words, four Cx rows (including padding) are exactly as long as
-one Y row (including padding).</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YVU410</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;17:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry></entry><entry></entry><entry>C</entry>
-                     <entry></entry><entry></entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-yuv411p.xml b/Documentation/DocBook/v4l/pixfmt-yuv411p.xml
deleted file mode 100644 (file)
index 00e0960..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-YUV411P">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YUV411P ('411P')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_YUV411P</constant></refname>
-       <refpurpose>Format with &frac14; horizontal chroma resolution,
-also known as YUV 4:1:1. Planar layout as opposed to
-<constant>V4L2_PIX_FMT_Y41P</constant></refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This format is not commonly used. This is a planar
-format similar to the 4:2:2 planar format except with half as many
-chroma. The three components are separated into three sub-images or
-planes. The Y plane is first. The Y plane has one byte per pixel. The
-Cb plane immediately follows the Y plane in memory. The Cb plane is
-&frac14; the width of the Y plane (and of the image). Each Cb belongs
-to 4 pixels all on the same row. For example,
-Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
-Y'<subscript>01</subscript>, Y'<subscript>02</subscript> and
-Y'<subscript>03</subscript>. Following the Cb plane is the Cr plane,
-just like the Cb plane.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cr
-and Cb planes have &frac14; as many pad bytes after their rows. In
-other words, four C x rows (including padding) is exactly as long as
-one Y row (including padding).</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YUV411P</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;17:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;18:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;19:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;21:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;22:</entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;23:</entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry>C</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-yuv420.xml b/Documentation/DocBook/v4l/pixfmt-yuv420.xml
deleted file mode 100644 (file)
index 42d7de5..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-    <refentry>
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YVU420 ('YV12'), V4L2_PIX_FMT_YUV420 ('YU12')</refentrytitle>
-       &manvol;
-     </refmeta>
-      <refnamediv>
-       <refname id="V4L2-PIX-FMT-YVU420"><constant>V4L2_PIX_FMT_YVU420</constant></refname>
-       <refname id="V4L2-PIX-FMT-YUV420"><constant>V4L2_PIX_FMT_YUV420</constant></refname>
-       <refpurpose>Planar formats with &frac12; horizontal and
-vertical chroma resolution, also known as YUV 4:2:0</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>These are planar formats, as opposed to a packed format.
-The three components are separated into three sub- images or planes.
-The Y plane is first. The Y plane has one byte per pixel. For
-<constant>V4L2_PIX_FMT_YVU420</constant>, the Cr plane immediately
-follows the Y plane in memory. The Cr plane is half the width and half
-the height of the Y plane (and of the image). Each Cr belongs to four
-pixels, a two-by-two square of the image. For example,
-Cr<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
-Y'<subscript>01</subscript>, Y'<subscript>10</subscript>, and
-Y'<subscript>11</subscript>. Following the Cr plane is the Cb plane,
-just like the Cr plane. <constant>V4L2_PIX_FMT_YUV420</constant> is
-the same except the Cb plane comes first, then the Cr plane.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cr
-and Cb planes have half as many pad bytes after their rows. In other
-words, two Cx rows (including padding) is exactly as long as one Y row
-(including padding).</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YVU420</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;18:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;22:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-yuv420m.xml b/Documentation/DocBook/v4l/pixfmt-yuv420m.xml
deleted file mode 100644 (file)
index f5d8f57..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-YUV420M">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YUV420M ('YU12M')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname> <constant>V4L2_PIX_FMT_YUV420M</constant></refname>
-       <refpurpose>Variation of <constant>V4L2_PIX_FMT_YUV420</constant>
-         with planes non contiguous in memory. </refpurpose>
-      </refnamediv>
-
-      <refsect1>
-       <title>Description</title>
-
-       <para>This is a multi-planar format, as opposed to a packed format.
-The three components are separated into three sub- images or planes.
-
-The Y plane is first. The Y plane has one byte per pixel. The Cb data
-constitutes the second plane which is half the width and half
-the height of the Y plane (and of the image). Each Cb belongs to four
-pixels, a two-by-two square of the image. For example,
-Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
-Y'<subscript>01</subscript>, Y'<subscript>10</subscript>, and
-Y'<subscript>11</subscript>. The Cr data, just like the Cb plane, is
-in the third plane. </para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cb
-and Cr planes have half as many pad bytes after their rows. In other
-words, two Cx rows (including padding) is exactly as long as one Y row
-(including padding).</para>
-
-       <para><constant>V4L2_PIX_FMT_NV12M</constant> is intended to be
-used only in drivers and applications that support the multi-planar API,
-described in <xref linkend="planar-apis"/>. </para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YVU420M</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start0&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row><entry></entry></row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;0:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start1&nbsp;+&nbsp;2:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                   </row>
-                   <row><entry></entry></row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;0:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start2&nbsp;+&nbsp;2:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry><entry></entry>
-                     <entry></entry><entry>C</entry><entry></entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry></entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-yuv422p.xml b/Documentation/DocBook/v4l/pixfmt-yuv422p.xml
deleted file mode 100644 (file)
index 4348bd9..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-YUV422P">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YUV422P ('422P')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_YUV422P</constant></refname>
-       <refpurpose>Format with &frac12; horizontal chroma resolution,
-also known as YUV 4:2:2. Planar layout as opposed to
-<constant>V4L2_PIX_FMT_YUYV</constant></refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>This format is not commonly used. This is a planar
-version of the YUYV format. The three components are separated into
-three sub-images or planes. The Y plane is first. The Y plane has one
-byte per pixel. The Cb plane immediately follows the Y plane in
-memory. The Cb plane is half the width of the Y plane (and of the
-image). Each Cb belongs to two pixels. For example,
-Cb<subscript>0</subscript> belongs to Y'<subscript>00</subscript>,
-Y'<subscript>01</subscript>. Following the Cb plane is the Cr plane,
-just like the Cb plane.</para>
-
-       <para>If the Y plane has pad bytes after each row, then the Cr
-and Cb planes have half as many pad bytes after their rows. In other
-words, two Cx rows (including padding) is exactly as long as one Y row
-(including padding).</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YUV422P</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="5" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;4:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;12:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;18:</entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;20:</entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;22:</entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;26:</entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;28:</entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;30:</entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-yuyv.xml b/Documentation/DocBook/v4l/pixfmt-yuyv.xml
deleted file mode 100644 (file)
index bdb2ffa..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-YUYV">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YUYV ('YUYV')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_YUYV</constant></refname>
-       <refpurpose>Packed format with &frac12; horizontal chroma
-resolution, also known as YUV 4:2:2</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>In this format each four bytes is two pixels. Each four
-bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
-the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
-components have half the horizontal resolution of the Y component.
-<constant>V4L2_PIX_FMT_YUYV </constant> is known in the Windows
-environment as YUY2.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YUYV</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="9" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt-yvyu.xml b/Documentation/DocBook/v4l/pixfmt-yvyu.xml
deleted file mode 100644 (file)
index 40d17ae..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-    <refentry id="V4L2-PIX-FMT-YVYU">
-      <refmeta>
-       <refentrytitle>V4L2_PIX_FMT_YVYU ('YVYU')</refentrytitle>
-       &manvol;
-      </refmeta>
-      <refnamediv>
-       <refname><constant>V4L2_PIX_FMT_YVYU</constant></refname>
-       <refpurpose>Variation of
-<constant>V4L2_PIX_FMT_YUYV</constant> with different order of samples
-in memory</refpurpose>
-      </refnamediv>
-      <refsect1>
-       <title>Description</title>
-
-       <para>In this format each four bytes is two pixels. Each four
-bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and
-the Cb and Cr belong to both pixels. As you can see, the Cr and Cb
-components have half the horizontal resolution of the Y
-component.</para>
-
-       <example>
-         <title><constant>V4L2_PIX_FMT_YVYU</constant> 4 &times; 4
-pixel image</title>
-
-         <formalpara>
-           <title>Byte Order.</title>
-           <para>Each cell is one byte.
-               <informaltable frame="none">
-               <tgroup cols="9" align="center">
-                 <colspec align="left" colwidth="2*" />
-                 <tbody valign="top">
-                   <row>
-                     <entry>start&nbsp;+&nbsp;0:</entry>
-                     <entry>Y'<subscript>00</subscript></entry>
-                     <entry>Cr<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>01</subscript></entry>
-                     <entry>Cb<subscript>00</subscript></entry>
-                     <entry>Y'<subscript>02</subscript></entry>
-                     <entry>Cr<subscript>01</subscript></entry>
-                     <entry>Y'<subscript>03</subscript></entry>
-                     <entry>Cb<subscript>01</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;8:</entry>
-                     <entry>Y'<subscript>10</subscript></entry>
-                     <entry>Cr<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>11</subscript></entry>
-                     <entry>Cb<subscript>10</subscript></entry>
-                     <entry>Y'<subscript>12</subscript></entry>
-                     <entry>Cr<subscript>11</subscript></entry>
-                     <entry>Y'<subscript>13</subscript></entry>
-                     <entry>Cb<subscript>11</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;16:</entry>
-                     <entry>Y'<subscript>20</subscript></entry>
-                     <entry>Cr<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>21</subscript></entry>
-                     <entry>Cb<subscript>20</subscript></entry>
-                     <entry>Y'<subscript>22</subscript></entry>
-                     <entry>Cr<subscript>21</subscript></entry>
-                     <entry>Y'<subscript>23</subscript></entry>
-                     <entry>Cb<subscript>21</subscript></entry>
-                   </row>
-                   <row>
-                     <entry>start&nbsp;+&nbsp;24:</entry>
-                     <entry>Y'<subscript>30</subscript></entry>
-                     <entry>Cr<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>31</subscript></entry>
-                     <entry>Cb<subscript>30</subscript></entry>
-                     <entry>Y'<subscript>32</subscript></entry>
-                     <entry>Cr<subscript>31</subscript></entry>
-                     <entry>Y'<subscript>33</subscript></entry>
-                     <entry>Cb<subscript>31</subscript></entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-
-         <formalpara>
-           <title>Color Sample Location.</title>
-           <para>
-               <informaltable frame="none">
-               <tgroup cols="7" align="center">
-                 <tbody valign="top">
-                   <row>
-                     <entry></entry>
-                     <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
-                     <entry>2</entry><entry></entry><entry>3</entry>
-                   </row>
-                   <row>
-                     <entry>0</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>1</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>2</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                   <row>
-                     <entry>3</entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry><entry></entry>
-                     <entry>Y</entry><entry>C</entry><entry>Y</entry>
-                   </row>
-                 </tbody>
-               </tgroup>
-               </informaltable>
-             </para>
-         </formalpara>
-       </example>
-      </refsect1>
-    </refentry>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "pixfmt.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/pixfmt.xml b/Documentation/DocBook/v4l/pixfmt.xml
deleted file mode 100644 (file)
index deb6602..0000000
+++ /dev/null
@@ -1,951 +0,0 @@
-  <title>Image Formats</title>
-
-  <para>The V4L2 API was primarily designed for devices exchanging
-image data with applications. The
-<structname>v4l2_pix_format</structname> and <structname>v4l2_pix_format_mplane
-</structname> structures define the format and layout of an image in memory.
-The former is used with the single-planar API, while the latter is used with the
-multi-planar version (see <xref linkend="planar-apis"/>). Image formats are
-negotiated with the &VIDIOC-S-FMT; ioctl. (The explanations here focus on video
-capturing and output, for overlay frame buffer formats see also
-&VIDIOC-G-FBUF;.)</para>
-
-<section>
-  <title>Single-planar format structure</title>
-  <table pgwide="1" frame="none" id="v4l2-pix-format">
-    <title>struct <structname>v4l2_pix_format</structname></title>
-    <tgroup cols="3">
-      &cs-str;
-      <tbody valign="top">
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>width</structfield></entry>
-         <entry>Image width in pixels.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>height</structfield></entry>
-         <entry>Image height in pixels.</entry>
-       </row>
-       <row>
-         <entry spanname="hspan">Applications set these fields to
-request an image size, drivers return the closest possible values. In
-case of planar formats the <structfield>width</structfield> and
-<structfield>height</structfield> applies to the largest plane. To
-avoid ambiguities drivers must return values rounded up to a multiple
-of the scale factor of any smaller planes. For example when the image
-format is YUV 4:2:0, <structfield>width</structfield> and
-<structfield>height</structfield> must be multiples of two.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>pixelformat</structfield></entry>
-         <entry>The pixel format or type of compression, set by the
-application. This is a little endian <link
-linkend="v4l2-fourcc">four character code</link>. V4L2 defines
-standard RGB formats in <xref linkend="rgb-formats" />, YUV formats in <xref
-linkend="yuv-formats" />, and reserved codes in <xref
-linkend="reserved-formats" /></entry>
-       </row>
-       <row>
-         <entry>&v4l2-field;</entry>
-         <entry><structfield>field</structfield></entry>
-         <entry>Video images are typically interlaced. Applications
-can request to capture or output only the top or bottom field, or both
-fields interlaced or sequentially stored in one buffer or alternating
-in separate buffers. Drivers return the actual field order selected.
-For details see <xref linkend="field-order" />.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>bytesperline</structfield></entry>
-         <entry>Distance in bytes between the leftmost pixels in two
-adjacent lines.</entry>
-       </row>
-       <row>
-         <entry spanname="hspan"><para>Both applications and drivers
-can set this field to request padding bytes at the end of each line.
-Drivers however may ignore the value requested by the application,
-returning <structfield>width</structfield> times bytes per pixel or a
-larger value required by the hardware. That implies applications can
-just set this field to zero to get a reasonable
-default.</para><para>Video hardware may access padding bytes,
-therefore they must reside in accessible memory. Consider cases where
-padding bytes after the last line of an image cross a system page
-boundary. Input devices may write padding bytes, the value is
-undefined. Output devices ignore the contents of padding
-bytes.</para><para>When the image format is planar the
-<structfield>bytesperline</structfield> value applies to the largest
-plane and is divided by the same factor as the
-<structfield>width</structfield> field for any smaller planes. For
-example the Cb and Cr planes of a YUV 4:2:0 image have half as many
-padding bytes following each line as the Y plane. To avoid ambiguities
-drivers must return a <structfield>bytesperline</structfield> value
-rounded up to a multiple of the scale factor.</para></entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>sizeimage</structfield></entry>
-         <entry>Size in bytes of the buffer to hold a complete image,
-set by the driver. Usually this is
-<structfield>bytesperline</structfield> times
-<structfield>height</structfield>. When the image consists of variable
-length compressed data this is the maximum number of bytes required to
-hold an image.</entry>
-       </row>
-       <row>
-         <entry>&v4l2-colorspace;</entry>
-         <entry><structfield>colorspace</structfield></entry>
-         <entry>This information supplements the
-<structfield>pixelformat</structfield> and must be set by the driver,
-see <xref linkend="colorspaces" />.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>priv</structfield></entry>
-         <entry>Reserved for custom (driver defined) additional
-information about formats. When not used drivers and applications must
-set this field to zero.</entry>
-       </row>
-      </tbody>
-    </tgroup>
-  </table>
-</section>
-
-<section>
-  <title>Multi-planar format structures</title>
-  <para>The <structname>v4l2_plane_pix_format</structname> structures define
-    size and layout for each of the planes in a multi-planar format.
-    The <structname>v4l2_pix_format_mplane</structname> structure contains
-    information common to all planes (such as image width and height) and
-    an array of <structname>v4l2_plane_pix_format</structname> structures,
-    describing all planes of that format.</para>
-  <table pgwide="1" frame="none" id="v4l2-plane-pix-format">
-    <title>struct <structname>vl42_plane_pix_format</structname></title>
-    <tgroup cols="3">
-      &cs-str;
-      <tbody valign="top">
-        <row>
-          <entry>__u32</entry>
-          <entry><structfield>sizeimage</structfield></entry>
-          <entry>Maximum size in bytes required for image data in this plane.
-          </entry>
-        </row>
-        <row>
-          <entry>__u16</entry>
-          <entry><structfield>bytesperline</structfield></entry>
-          <entry>Distance in bytes between the leftmost pixels in two adjacent
-            lines.</entry>
-        </row>
-        <row>
-          <entry>__u16</entry>
-          <entry><structfield>reserved[7]</structfield></entry>
-          <entry>Reserved for future extensions. Should be zeroed by the
-           application.</entry>
-        </row>
-      </tbody>
-    </tgroup>
-  </table>
-  <table pgwide="1" frame="none" id="v4l2-pix-format-mplane">
-    <title>struct <structname>v4l2_pix_format_mplane</structname></title>
-    <tgroup cols="3">
-      &cs-str;
-      <tbody valign="top">
-        <row>
-          <entry>__u32</entry>
-          <entry><structfield>width</structfield></entry>
-          <entry>Image width in pixels.</entry>
-        </row>
-        <row>
-          <entry>__u32</entry>
-          <entry><structfield>height</structfield></entry>
-          <entry>Image height in pixels.</entry>
-        </row>
-        <row>
-          <entry>__u32</entry>
-          <entry><structfield>pixelformat</structfield></entry>
-          <entry>The pixel format. Both single- and multi-planar four character
-codes can be used.</entry>
-        </row>
-        <row>
-          <entry>&v4l2-field;</entry>
-          <entry><structfield>field</structfield></entry>
-          <entry>See &v4l2-pix-format;.</entry>
-        </row>
-        <row>
-          <entry>&v4l2-colorspace;</entry>
-          <entry><structfield>colorspace</structfield></entry>
-          <entry>See &v4l2-pix-format;.</entry>
-        </row>
-        <row>
-          <entry>&v4l2-plane-pix-format;</entry>
-          <entry><structfield>plane_fmt[VIDEO_MAX_PLANES]</structfield></entry>
-          <entry>An array of structures describing format of each plane this
-          pixel format consists of. The number of valid entries in this array
-          has to be put in the <structfield>num_planes</structfield>
-          field.</entry>
-        </row>
-        <row>
-          <entry>__u8</entry>
-          <entry><structfield>num_planes</structfield></entry>
-          <entry>Number of planes (i.e. separate memory buffers) for this format
-          and the number of valid entries in the
-          <structfield>plane_fmt</structfield> array.</entry>
-        </row>
-        <row>
-          <entry>__u8</entry>
-          <entry><structfield>reserved[11]</structfield></entry>
-          <entry>Reserved for future extensions. Should be zeroed by the
-           application.</entry>
-        </row>
-      </tbody>
-    </tgroup>
-  </table>
-</section>
-
-  <section>
-    <title>Standard Image Formats</title>
-
-    <para>In order to exchange images between drivers and
-applications, it is necessary to have standard image data formats
-which both sides will interpret the same way. V4L2 includes several
-such formats, and this section is intended to be an unambiguous
-specification of the standard image data formats in V4L2.</para>
-
-    <para>V4L2 drivers are not limited to these formats, however.
-Driver-specific formats are possible. In that case the application may
-depend on a codec to convert images to one of the standard formats
-when needed. But the data can still be stored and retrieved in the
-proprietary format. For example, a device may support a proprietary
-compressed format. Applications can still capture and save the data in
-the compressed format, saving much disk space, and later use a codec
-to convert the images to the X Windows screen format when the video is
-to be displayed.</para>
-
-    <para>Even so, ultimately, some standard formats are needed, so
-the V4L2 specification would not be complete without well-defined
-standard formats.</para>
-
-    <para>The V4L2 standard formats are mainly uncompressed formats. The
-pixels are always arranged in memory from left to right, and from top
-to bottom. The first byte of data in the image buffer is always for
-the leftmost pixel of the topmost row. Following that is the pixel
-immediately to its right, and so on until the end of the top row of
-pixels. Following the rightmost pixel of the row there may be zero or
-more bytes of padding to guarantee that each row of pixel data has a
-certain alignment. Following the pad bytes, if any, is data for the
-leftmost pixel of the second row from the top, and so on. The last row
-has just as many pad bytes after it as the other rows.</para>
-
-    <para>In V4L2 each format has an identifier which looks like
-<constant>PIX_FMT_XXX</constant>, defined in the <link
-linkend="videodev">videodev.h</link> header file. These identifiers
-represent <link linkend="v4l2-fourcc">four character (FourCC) codes</link>
-which are also listed below, however they are not the same as those
-used in the Windows world.</para>
-
-    <para>For some formats, data is stored in separate, discontiguous
-memory buffers. Those formats are identified by a separate set of FourCC codes
-and are referred to as "multi-planar formats". For example, a YUV422 frame is
-normally stored in one memory buffer, but it can also be placed in two or three
-separate buffers, with Y component in one buffer and CbCr components in another
-in the 2-planar version or with each component in its own buffer in the
-3-planar case. Those sub-buffers are referred to as "planes".</para>
-  </section>
-
-  <section id="colorspaces">
-    <title>Colorspaces</title>
-
-    <para>[intro]</para>
-
-    <!-- See proposal by Billy Biggs, video4linux-list@redhat.com
-on 11 Oct 2002, subject: "Re: [V4L] Re: v4l2 api", and
-http://vektor.theorem.ca/graphics/ycbcr/ and
-http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html -->
-
-    <para>
-      <variablelist>
-       <varlistentry>
-         <term>Gamma Correction</term>
-         <listitem>
-           <para>[to do]</para>
-           <para>E'<subscript>R</subscript> = f(R)</para>
-           <para>E'<subscript>G</subscript> = f(G)</para>
-           <para>E'<subscript>B</subscript> = f(B)</para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-         <term>Construction of luminance and color-difference
-signals</term>
-         <listitem>
-           <para>[to do]</para>
-           <para>E'<subscript>Y</subscript> =
-Coeff<subscript>R</subscript> E'<subscript>R</subscript>
-+ Coeff<subscript>G</subscript> E'<subscript>G</subscript>
-+ Coeff<subscript>B</subscript> E'<subscript>B</subscript></para>
-           <para>(E'<subscript>R</subscript> - E'<subscript>Y</subscript>) = E'<subscript>R</subscript>
-- Coeff<subscript>R</subscript> E'<subscript>R</subscript>
-- Coeff<subscript>G</subscript> E'<subscript>G</subscript>
-- Coeff<subscript>B</subscript> E'<subscript>B</subscript></para>
-           <para>(E'<subscript>B</subscript> - E'<subscript>Y</subscript>) = E'<subscript>B</subscript>
-- Coeff<subscript>R</subscript> E'<subscript>R</subscript>
-- Coeff<subscript>G</subscript> E'<subscript>G</subscript>
-- Coeff<subscript>B</subscript> E'<subscript>B</subscript></para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-         <term>Re-normalized color-difference signals</term>
-         <listitem>
-           <para>The color-difference signals are scaled back to unity
-range [-0.5;+0.5]:</para>
-           <para>K<subscript>B</subscript> = 0.5 / (1 - Coeff<subscript>B</subscript>)</para>
-           <para>K<subscript>R</subscript> = 0.5 / (1 - Coeff<subscript>R</subscript>)</para>
-           <para>P<subscript>B</subscript> =
-K<subscript>B</subscript> (E'<subscript>B</subscript> - E'<subscript>Y</subscript>) =
-  0.5 (Coeff<subscript>R</subscript> / Coeff<subscript>B</subscript>) E'<subscript>R</subscript>
-+ 0.5 (Coeff<subscript>G</subscript> / Coeff<subscript>B</subscript>) E'<subscript>G</subscript>
-+ 0.5 E'<subscript>B</subscript></para>
-           <para>P<subscript>R</subscript> =
-K<subscript>R</subscript> (E'<subscript>R</subscript> - E'<subscript>Y</subscript>) =
-  0.5 E'<subscript>R</subscript>
-+ 0.5 (Coeff<subscript>G</subscript> / Coeff<subscript>R</subscript>) E'<subscript>G</subscript>
-+ 0.5 (Coeff<subscript>B</subscript> / Coeff<subscript>R</subscript>) E'<subscript>B</subscript></para>
-         </listitem>
-       </varlistentry>
-       <varlistentry>
-         <term>Quantization</term>
-         <listitem>
-           <para>[to do]</para>
-           <para>Y' = (Lum. Levels - 1) &middot; E'<subscript>Y</subscript> + Lum. Offset</para>
-           <para>C<subscript>B</subscript> = (Chrom. Levels - 1)
-&middot; P<subscript>B</subscript> + Chrom. Offset</para>
-           <para>C<subscript>R</subscript> = (Chrom. Levels - 1)
-&middot; P<subscript>R</subscript> + Chrom. Offset</para>
-           <para>Rounding to the nearest integer and clamping to the range
-[0;255] finally yields the digital color components Y'CbCr
-stored in YUV images.</para>
-         </listitem>
-       </varlistentry>
-      </variablelist>
-    </para>
-
-    <example>
-      <title>ITU-R Rec. BT.601 color conversion</title>
-
-      <para>Forward Transformation</para>
-
-      <programlisting>
-int ER, EG, EB;         /* gamma corrected RGB input [0;255] */
-int Y1, Cb, Cr;         /* output [0;255] */
-
-double r, g, b;         /* temporaries */
-double y1, pb, pr;
-
-int
-clamp (double x)
-{
-       int r = x;      /* round to nearest */
-
-       if (r &lt; 0)         return 0;
-       else if (r &gt; 255)  return 255;
-       else               return r;
-}
-
-r = ER / 255.0;
-g = EG / 255.0;
-b = EB / 255.0;
-
-y1  =  0.299  * r + 0.587 * g + 0.114  * b;
-pb  = -0.169  * r - 0.331 * g + 0.5    * b;
-pr  =  0.5    * r - 0.419 * g - 0.081  * b;
-
-Y1 = clamp (219 * y1 + 16);
-Cb = clamp (224 * pb + 128);
-Cr = clamp (224 * pr + 128);
-
-/* or shorter */
-
-y1 = 0.299 * ER + 0.587 * EG + 0.114 * EB;
-
-Y1 = clamp ( (219 / 255.0)                    *       y1  + 16);
-Cb = clamp (((224 / 255.0) / (2 - 2 * 0.114)) * (EB - y1) + 128);
-Cr = clamp (((224 / 255.0) / (2 - 2 * 0.299)) * (ER - y1) + 128);
-      </programlisting>
-
-      <para>Inverse Transformation</para>
-
-      <programlisting>
-int Y1, Cb, Cr;         /* gamma pre-corrected input [0;255] */
-int ER, EG, EB;         /* output [0;255] */
-
-double r, g, b;         /* temporaries */
-double y1, pb, pr;
-
-int
-clamp (double x)
-{
-       int r = x;      /* round to nearest */
-
-       if (r &lt; 0)         return 0;
-       else if (r &gt; 255)  return 255;
-       else               return r;
-}
-
-y1 = (255 / 219.0) * (Y1 - 16);
-pb = (255 / 224.0) * (Cb - 128);
-pr = (255 / 224.0) * (Cr - 128);
-
-r = 1.0 * y1 + 0     * pb + 1.402 * pr;
-g = 1.0 * y1 - 0.344 * pb - 0.714 * pr;
-b = 1.0 * y1 + 1.772 * pb + 0     * pr;
-
-ER = clamp (r * 255); /* [ok? one should prob. limit y1,pb,pr] */
-EG = clamp (g * 255);
-EB = clamp (b * 255);
-      </programlisting>
-    </example>
-
-    <table pgwide="1" id="v4l2-colorspace" orient="land">
-      <title>enum v4l2_colorspace</title>
-      <tgroup cols="11" align="center">
-       <colspec align="left" />
-       <colspec align="center" />
-       <colspec align="left" />
-       <colspec colname="cr" />
-       <colspec colname="cg" />
-       <colspec colname="cb" />
-       <colspec colname="wp" />
-       <colspec colname="gc" />
-       <colspec colname="lum" />
-       <colspec colname="qy" />
-       <colspec colname="qc" />
-       <spanspec namest="cr" nameend="cb" spanname="chrom" />
-       <spanspec namest="qy" nameend="qc" spanname="quant" />
-       <spanspec namest="lum" nameend="qc" spanname="spam" />
-       <thead>
-         <row>
-           <entry morerows="1">Identifier</entry>
-           <entry morerows="1">Value</entry>
-           <entry morerows="1">Description</entry>
-           <entry spanname="chrom">Chromaticities<footnote>
-               <para>The coordinates of the color primaries are
-given in the CIE system (1931)</para>
-             </footnote></entry>
-           <entry morerows="1">White Point</entry>
-           <entry morerows="1">Gamma Correction</entry>
-           <entry morerows="1">Luminance E'<subscript>Y</subscript></entry>
-           <entry spanname="quant">Quantization</entry>
-         </row>
-         <row>
-           <entry>Red</entry>
-           <entry>Green</entry>
-           <entry>Blue</entry>
-           <entry>Y'</entry>
-           <entry>Cb, Cr</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_COLORSPACE_SMPTE170M</constant></entry>
-           <entry>1</entry>
-           <entry>NTSC/PAL according to <xref linkend="smpte170m" />,
-<xref linkend="itu601" /></entry>
-           <entry>x&nbsp;=&nbsp;0.630, y&nbsp;=&nbsp;0.340</entry>
-           <entry>x&nbsp;=&nbsp;0.310, y&nbsp;=&nbsp;0.595</entry>
-           <entry>x&nbsp;=&nbsp;0.155, y&nbsp;=&nbsp;0.070</entry>
-           <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
-           Illuminant D<subscript>65</subscript></entry>
-           <entry>E' = 4.5&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.018,
-1.099&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&lt;&nbsp;I</entry>
-           <entry>0.299&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.587&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
-           <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
-           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_SMPTE240M</constant></entry>
-           <entry>2</entry>
-           <entry>1125-Line (US) HDTV, see <xref
-linkend="smpte240m" /></entry>
-           <entry>x&nbsp;=&nbsp;0.630, y&nbsp;=&nbsp;0.340</entry>
-           <entry>x&nbsp;=&nbsp;0.310, y&nbsp;=&nbsp;0.595</entry>
-           <entry>x&nbsp;=&nbsp;0.155, y&nbsp;=&nbsp;0.070</entry>
-           <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
-           Illuminant D<subscript>65</subscript></entry>
-           <entry>E' = 4&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.0228,
-1.1115&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.1115&nbsp;for&nbsp;0.0228&nbsp;&lt;&nbsp;I</entry>
-           <entry>0.212&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.701&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.087&nbsp;E'<subscript>B</subscript></entry>
-           <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
-           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_REC709</constant></entry>
-           <entry>3</entry>
-           <entry>HDTV and modern devices, see <xref
-linkend="itu709" /></entry>
-           <entry>x&nbsp;=&nbsp;0.640, y&nbsp;=&nbsp;0.330</entry>
-           <entry>x&nbsp;=&nbsp;0.300, y&nbsp;=&nbsp;0.600</entry>
-           <entry>x&nbsp;=&nbsp;0.150, y&nbsp;=&nbsp;0.060</entry>
-           <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
-           Illuminant D<subscript>65</subscript></entry>
-           <entry>E' = 4.5&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.018,
-1.099&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&lt;&nbsp;I</entry>
-           <entry>0.2125&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.7154&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.0721&nbsp;E'<subscript>B</subscript></entry>
-           <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
-           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_BT878</constant></entry>
-           <entry>4</entry>
-           <entry>Broken Bt878 extents<footnote>
-               <para>The ubiquitous Bt878 video capture chip
-quantizes E'<subscript>Y</subscript> to 238 levels, yielding a range
-of Y' = 16 &hellip; 253, unlike Rec. 601 Y' = 16 &hellip;
-235. This is not a typo in the Bt878 documentation, it has been
-implemented in silicon. The chroma extents are unclear.</para>
-             </footnote>, <xref linkend="itu601" /></entry>
-           <entry>?</entry>
-           <entry>?</entry>
-           <entry>?</entry>
-           <entry>?</entry>
-           <entry>?</entry>
-           <entry>0.299&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.587&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
-           <entry><emphasis>237</emphasis>&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
-           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128 (probably)</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_470_SYSTEM_M</constant></entry>
-           <entry>5</entry>
-           <entry>M/NTSC<footnote>
-               <para>No identifier exists for M/PAL which uses
-the chromaticities of M/NTSC, the remaining parameters are equal to B and
-G/PAL.</para>
-             </footnote> according to <xref linkend="itu470" />, <xref
-               linkend="itu601" /></entry>
-           <entry>x&nbsp;=&nbsp;0.67, y&nbsp;=&nbsp;0.33</entry>
-           <entry>x&nbsp;=&nbsp;0.21, y&nbsp;=&nbsp;0.71</entry>
-           <entry>x&nbsp;=&nbsp;0.14, y&nbsp;=&nbsp;0.08</entry>
-           <entry>x&nbsp;=&nbsp;0.310, y&nbsp;=&nbsp;0.316, Illuminant C</entry>
-           <entry>?</entry>
-           <entry>0.299&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.587&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
-           <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
-           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant></entry>
-           <entry>6</entry>
-           <entry>625-line PAL and SECAM systems according to <xref
-linkend="itu470" />, <xref linkend="itu601" /></entry>
-           <entry>x&nbsp;=&nbsp;0.64, y&nbsp;=&nbsp;0.33</entry>
-           <entry>x&nbsp;=&nbsp;0.29, y&nbsp;=&nbsp;0.60</entry>
-           <entry>x&nbsp;=&nbsp;0.15, y&nbsp;=&nbsp;0.06</entry>
-           <entry>x&nbsp;=&nbsp;0.313, y&nbsp;=&nbsp;0.329,
-Illuminant D<subscript>65</subscript></entry>
-           <entry>?</entry>
-           <entry>0.299&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.587&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
-           <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
-           <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_JPEG</constant></entry>
-           <entry>7</entry>
-           <entry>JPEG Y'CbCr, see <xref linkend="jfif" />, <xref linkend="itu601" /></entry>
-           <entry>?</entry>
-           <entry>?</entry>
-           <entry>?</entry>
-           <entry>?</entry>
-           <entry>?</entry>
-           <entry>0.299&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.587&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
-           <entry>256&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16<footnote>
-               <para>Note JFIF quantizes
-Y'P<subscript>B</subscript>P<subscript>R</subscript> in range [0;+1] and
-[-0.5;+0.5] to <emphasis>257</emphasis> levels, however Y'CbCr signals
-are still clamped to [0;255].</para>
-             </footnote></entry>
-           <entry>256&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_COLORSPACE_SRGB</constant></entry>
-           <entry>8</entry>
-           <entry>[?]</entry>
-           <entry>x&nbsp;=&nbsp;0.640, y&nbsp;=&nbsp;0.330</entry>
-           <entry>x&nbsp;=&nbsp;0.300, y&nbsp;=&nbsp;0.600</entry>
-           <entry>x&nbsp;=&nbsp;0.150, y&nbsp;=&nbsp;0.060</entry>
-           <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
-           Illuminant D<subscript>65</subscript></entry>
-           <entry>E' = 4.5&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.018,
-1.099&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&lt;&nbsp;I</entry>
-           <entry spanname="spam">n/a</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-  <section id="pixfmt-indexed">
-    <title>Indexed Format</title>
-
-    <para>In this format each pixel is represented by an 8 bit index
-into a 256 entry ARGB palette. It is intended for <link
-linkend="osd">Video Output Overlays</link> only. There are no ioctls to
-access the palette, this must be done with ioctls of the Linux framebuffer API.</para>
-
-    <table pgwide="0" frame="none">
-      <title>Indexed Image Format</title>
-      <tgroup cols="37" align="center">
-       <colspec colname="id" align="left" />
-       <colspec colname="fourcc" />
-       <colspec colname="bit" />
-
-       <colspec colnum="4" colname="b07" align="center" />
-       <colspec colnum="5" colname="b06" align="center" />
-       <colspec colnum="6" colname="b05" align="center" />
-       <colspec colnum="7" colname="b04" align="center" />
-       <colspec colnum="8" colname="b03" align="center" />
-       <colspec colnum="9" colname="b02" align="center" />
-       <colspec colnum="10" colname="b01" align="center" />
-       <colspec colnum="11" colname="b00" align="center" />
-
-       <spanspec namest="b07" nameend="b00" spanname="b0" />
-       <spanspec namest="b17" nameend="b10" spanname="b1" />
-       <spanspec namest="b27" nameend="b20" spanname="b2" />
-       <spanspec namest="b37" nameend="b30" spanname="b3" />
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>&nbsp;</entry>
-           <entry spanname="b0">Byte&nbsp;0</entry>
-         </row>
-         <row>
-           <entry>&nbsp;</entry>
-           <entry>&nbsp;</entry>
-           <entry>Bit</entry>
-           <entry>7</entry>
-           <entry>6</entry>
-           <entry>5</entry>
-           <entry>4</entry>
-           <entry>3</entry>
-           <entry>2</entry>
-           <entry>1</entry>
-           <entry>0</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row id="V4L2-PIX-FMT-PAL8">
-           <entry><constant>V4L2_PIX_FMT_PAL8</constant></entry>
-           <entry>'PAL8'</entry>
-           <entry></entry>
-           <entry>i<subscript>7</subscript></entry>
-           <entry>i<subscript>6</subscript></entry>
-           <entry>i<subscript>5</subscript></entry>
-           <entry>i<subscript>4</subscript></entry>
-           <entry>i<subscript>3</subscript></entry>
-           <entry>i<subscript>2</subscript></entry>
-           <entry>i<subscript>1</subscript></entry>
-           <entry>i<subscript>0</subscript></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-  <section id="pixfmt-rgb">
-    <title>RGB Formats</title>
-
-    &sub-packed-rgb;
-    &sub-sbggr8;
-    &sub-sgbrg8;
-    &sub-sgrbg8;
-    &sub-srggb8;
-    &sub-sbggr16;
-    &sub-srggb10;
-    &sub-srggb12;
-  </section>
-
-  <section id="yuv-formats">
-    <title>YUV Formats</title>
-
-    <para>YUV is the format native to TV broadcast and composite video
-signals. It separates the brightness information (Y) from the color
-information (U and V or Cb and Cr). The color information consists of
-red and blue <emphasis>color difference</emphasis> signals, this way
-the green component can be reconstructed by subtracting from the
-brightness component. See <xref linkend="colorspaces" /> for conversion
-examples. YUV was chosen because early television would only transmit
-brightness information. To add color in a way compatible with existing
-receivers a new signal carrier was added to transmit the color
-difference signals. Secondary in the YUV format the U and V components
-usually have lower resolution than the Y component. This is an analog
-video compression technique taking advantage of a property of the
-human visual system, being more sensitive to brightness
-information.</para>
-
-    &sub-packed-yuv;
-    &sub-grey;
-    &sub-y10;
-    &sub-y12;
-    &sub-y10b;
-    &sub-y16;
-    &sub-yuyv;
-    &sub-uyvy;
-    &sub-yvyu;
-    &sub-vyuy;
-    &sub-y41p;
-    &sub-yuv420;
-    &sub-yuv420m;
-    &sub-yuv410;
-    &sub-yuv422p;
-    &sub-yuv411p;
-    &sub-nv12;
-    &sub-nv12m;
-    &sub-nv12mt;
-    &sub-nv16;
-    &sub-m420;
-  </section>
-
-  <section>
-    <title>Compressed Formats</title>
-
-    <table pgwide="1" frame="none" id="compressed-formats">
-      <title>Compressed Image Formats</title>
-      <tgroup cols="3" align="left">
-       &cs-def;
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>Details</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-        <row id="V4L2-PIX-FMT-JPEG">
-           <entry><constant>V4L2_PIX_FMT_JPEG</constant></entry>
-           <entry>'JPEG'</entry>
-           <entry>TBD. See also &VIDIOC-G-JPEGCOMP;,
-           &VIDIOC-S-JPEGCOMP;.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-MPEG">
-           <entry><constant>V4L2_PIX_FMT_MPEG</constant></entry>
-           <entry>'MPEG'</entry>
-           <entry>MPEG stream. The actual format is determined by
-extended control <constant>V4L2_CID_MPEG_STREAM_TYPE</constant>, see
-<xref linkend="mpeg-control-id" />.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-  <section id="pixfmt-reserved">
-    <title>Reserved Format Identifiers</title>
-
-    <para>These formats are not defined by this specification, they
-are just listed for reference and to avoid naming conflicts. If you
-want to register your own format, send an e-mail to the linux-media mailing
-list &v4l-ml; for inclusion in the <filename>videodev2.h</filename>
-file. If you want to share your format with other developers add a
-link to your documentation and send a copy to the linux-media mailing list
-for inclusion in this section. If you think your format should be listed
-in a standard format section please make a proposal on the linux-media mailing
-list.</para>
-
-    <table pgwide="1" frame="none" id="reserved-formats">
-      <title>Reserved Image Formats</title>
-      <tgroup cols="3" align="left">
-       &cs-def;
-       <thead>
-         <row>
-           <entry>Identifier</entry>
-           <entry>Code</entry>
-           <entry>Details</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row id="V4L2-PIX-FMT-DV">
-           <entry><constant>V4L2_PIX_FMT_DV</constant></entry>
-           <entry>'dvsd'</entry>
-           <entry>unknown</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-ET61X251">
-           <entry><constant>V4L2_PIX_FMT_ET61X251</constant></entry>
-           <entry>'E625'</entry>
-           <entry>Compressed format of the ET61X251 driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-HI240">
-           <entry><constant>V4L2_PIX_FMT_HI240</constant></entry>
-           <entry>'HI24'</entry>
-           <entry><para>8 bit RGB format used by the BTTV driver.</para></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-HM12">
-           <entry><constant>V4L2_PIX_FMT_HM12</constant></entry>
-           <entry>'HM12'</entry>
-           <entry><para>YUV 4:2:0 format used by the
-IVTV driver, <ulink url="http://www.ivtvdriver.org/">
-http://www.ivtvdriver.org/</ulink></para><para>The format is documented in the
-kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm12</filename>
-</para></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-CPIA1">
-           <entry><constant>V4L2_PIX_FMT_CPIA1</constant></entry>
-           <entry>'CPIA'</entry>
-           <entry>YUV format used by the gspca cpia1 driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SPCA501">
-           <entry><constant>V4L2_PIX_FMT_SPCA501</constant></entry>
-           <entry>'S501'</entry>
-           <entry>YUYV per line used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SPCA505">
-           <entry><constant>V4L2_PIX_FMT_SPCA505</constant></entry>
-           <entry>'S505'</entry>
-           <entry>YYUV per line used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SPCA508">
-           <entry><constant>V4L2_PIX_FMT_SPCA508</constant></entry>
-           <entry>'S508'</entry>
-           <entry>YUVY per line used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SPCA561">
-           <entry><constant>V4L2_PIX_FMT_SPCA561</constant></entry>
-           <entry>'S561'</entry>
-           <entry>Compressed GBRG Bayer format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SGRBG10DPCM8">
-           <entry><constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant></entry>
-           <entry>'DB10'</entry>
-           <entry>10 bit raw Bayer DPCM compressed to 8 bits.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-PAC207">
-           <entry><constant>V4L2_PIX_FMT_PAC207</constant></entry>
-           <entry>'P207'</entry>
-           <entry>Compressed BGGR Bayer format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-MR97310A">
-           <entry><constant>V4L2_PIX_FMT_MR97310A</constant></entry>
-           <entry>'M310'</entry>
-           <entry>Compressed BGGR Bayer format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-OV511">
-           <entry><constant>V4L2_PIX_FMT_OV511</constant></entry>
-           <entry>'O511'</entry>
-           <entry>OV511 JPEG format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-OV518">
-           <entry><constant>V4L2_PIX_FMT_OV518</constant></entry>
-           <entry>'O518'</entry>
-           <entry>OV518 JPEG format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-PJPG">
-           <entry><constant>V4L2_PIX_FMT_PJPG</constant></entry>
-           <entry>'PJPG'</entry>
-           <entry>Pixart 73xx JPEG format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SQ905C">
-           <entry><constant>V4L2_PIX_FMT_SQ905C</constant></entry>
-           <entry>'905C'</entry>
-           <entry>Compressed RGGB bayer format used by the gspca driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-MJPEG">
-           <entry><constant>V4L2_PIX_FMT_MJPEG</constant></entry>
-           <entry>'MJPG'</entry>
-           <entry>Compressed format used by the Zoran driver</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-PWC1">
-           <entry><constant>V4L2_PIX_FMT_PWC1</constant></entry>
-           <entry>'PWC1'</entry>
-           <entry>Compressed format of the PWC driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-PWC2">
-           <entry><constant>V4L2_PIX_FMT_PWC2</constant></entry>
-           <entry>'PWC2'</entry>
-           <entry>Compressed format of the PWC driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SN9C10X">
-           <entry><constant>V4L2_PIX_FMT_SN9C10X</constant></entry>
-           <entry>'S910'</entry>
-           <entry>Compressed format of the SN9C102 driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SN9C20X-I420">
-           <entry><constant>V4L2_PIX_FMT_SN9C20X_I420</constant></entry>
-           <entry>'S920'</entry>
-           <entry>YUV 4:2:0 format of the gspca sn9c20x driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-SN9C2028">
-           <entry><constant>V4L2_PIX_FMT_SN9C2028</constant></entry>
-           <entry>'SONX'</entry>
-           <entry>Compressed GBRG bayer format of the gspca sn9c2028 driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-STV0680">
-           <entry><constant>V4L2_PIX_FMT_STV0680</constant></entry>
-           <entry>'S680'</entry>
-           <entry>Bayer format of the gspca stv0680 driver.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-WNVA">
-           <entry><constant>V4L2_PIX_FMT_WNVA</constant></entry>
-           <entry>'WNVA'</entry>
-           <entry><para>Used by the Winnov Videum driver, <ulink
-url="http://www.thedirks.org/winnov/">
-http://www.thedirks.org/winnov/</ulink></para></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-TM6000">
-           <entry><constant>V4L2_PIX_FMT_TM6000</constant></entry>
-           <entry>'TM60'</entry>
-           <entry><para>Used by Trident tm6000</para></entry>
-         </row>
-         <row id="V4L2-PIX-FMT-CIT-YYVYUY">
-           <entry><constant>V4L2_PIX_FMT_CIT_YYVYUY</constant></entry>
-           <entry>'CITV'</entry>
-           <entry><para>Used by xirlink CIT, found at IBM webcams.</para>
-                  <para>Uses one line of Y then 1 line of VYUY</para>
-           </entry>
-         </row>
-         <row id="V4L2-PIX-FMT-KONICA420">
-           <entry><constant>V4L2_PIX_FMT_KONICA420</constant></entry>
-           <entry>'KONI'</entry>
-           <entry><para>Used by Konica webcams.</para>
-                  <para>YUV420 planar in blocks of 256 pixels.</para>
-           </entry>
-         </row>
-         <row id="V4L2-PIX-FMT-YYUV">
-           <entry><constant>V4L2_PIX_FMT_YYUV</constant></entry>
-           <entry>'YYUV'</entry>
-           <entry>unknown</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-Y4">
-           <entry><constant>V4L2_PIX_FMT_Y4</constant></entry>
-           <entry>'Y04 '</entry>
-           <entry>Old 4-bit greyscale format. Only the least significant 4 bits of each byte are used,
-the other bits are set to 0.</entry>
-         </row>
-         <row id="V4L2-PIX-FMT-Y6">
-           <entry><constant>V4L2_PIX_FMT_Y6</constant></entry>
-           <entry>'Y06 '</entry>
-           <entry>Old 6-bit greyscale format. Only the least significant 6 bits of each byte are used,
-the other bits are set to 0.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-  <!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
-  -->
diff --git a/Documentation/DocBook/v4l/planar-apis.xml b/Documentation/DocBook/v4l/planar-apis.xml
deleted file mode 100644 (file)
index 878ce20..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-<section id="planar-apis">
-  <title>Single- and multi-planar APIs</title>
-
-  <para>Some devices require data for each input or output video frame
-  to be placed in discontiguous memory buffers. In such cases, one
-  video frame has to be addressed using more than one memory address, i.e. one
-  pointer per "plane". A plane is a sub-buffer of the current frame. For
-  examples of such formats see <xref linkend="pixfmt" />.</para>
-
-  <para>Initially, V4L2 API did not support multi-planar buffers and a set of
-  extensions has been introduced to handle them. Those extensions constitute
-  what is being referred to as the "multi-planar API".</para>
-
-  <para>Some of the V4L2 API calls and structures are interpreted differently,
-  depending on whether single- or multi-planar API is being used. An application
-  can choose whether to use one or the other by passing a corresponding buffer
-  type to its ioctl calls. Multi-planar versions of buffer types are suffixed
-  with an `_MPLANE' string. For a list of available multi-planar buffer types
-  see &v4l2-buf-type;.
-  </para>
-
-  <section>
-    <title>Multi-planar formats</title>
-    <para>Multi-planar API introduces new multi-planar formats. Those formats
-    use a separate set of FourCC codes. It is important to distinguish between
-    the multi-planar API and a multi-planar format. Multi-planar API calls can
-    handle all single-planar formats as well (as long as they are passed in
-    multi-planar API structures), while the single-planar API cannot
-    handle multi-planar formats.</para>
-  </section>
-
-  <section>
-    <title>Calls that distinguish between single and multi-planar APIs</title>
-    <variablelist>
-      <varlistentry>
-        <term>&VIDIOC-QUERYCAP;</term>
-        <listitem><para>Two additional multi-planar capabilities are added. They can
-        be set together with non-multi-planar ones for devices that handle
-        both single- and multi-planar formats.</para></listitem>
-      </varlistentry>
-      <varlistentry>
-        <term>&VIDIOC-G-FMT;, &VIDIOC-S-FMT;, &VIDIOC-TRY-FMT;</term>
-        <listitem><para>New structures for describing multi-planar formats are added:
-        &v4l2-pix-format-mplane; and &v4l2-plane-pix-format;. Drivers may
-        define new multi-planar formats, which have distinct FourCC codes from
-        the existing single-planar ones.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term>&VIDIOC-QBUF;, &VIDIOC-DQBUF;, &VIDIOC-QUERYBUF;</term>
-        <listitem><para>A new &v4l2-plane; structure for describing planes is added.
-        Arrays of this structure are passed in the new
-        <structfield>m.planes</structfield> field of &v4l2-buffer;.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term>&VIDIOC-REQBUFS;</term>
-        <listitem><para>Will allocate multi-planar buffers as requested.</para></listitem>
-      </varlistentry>
-    </variablelist>
-  </section>
-</section>
diff --git a/Documentation/DocBook/v4l/remote_controllers.xml b/Documentation/DocBook/v4l/remote_controllers.xml
deleted file mode 100644 (file)
index 160e464..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-<title>Remote Controllers</title>
-<section id="Remote_controllers_Intro">
-<title>Introduction</title>
-
-<para>Currently, most analog and digital devices have a Infrared input for remote controllers. Each
-manufacturer has their own type of control. It is not rare for the same manufacturer to ship different
-types of controls, depending on the device.</para>
-<para>Unfortunately, for several years, there was no effort to create uniform IR keycodes for
-different devices.  This caused the same IR keyname to be mapped completely differently on
-different IR devices. This resulted that the same IR keyname to be mapped completely different on
-different IR's. Due to that, V4L2 API now specifies a standard for mapping Media keys on IR.</para>
-<para>This standard should be used by both V4L/DVB drivers and userspace applications</para>
-<para>The modules register the remote as keyboard within the linux input layer. This means that the IR key strokes will look like normal keyboard key strokes (if CONFIG_INPUT_KEYBOARD is enabled). Using the event devices (CONFIG_INPUT_EVDEV) it is possible for applications to access the remote via /dev/input/event devices.</para>
-
-<table pgwide="1" frame="none" id="rc_standard_keymap">
-<title>IR default keymapping</title>
-<tgroup cols="3">
-&cs-str;
-<tbody valign="top">
-<row>
-<entry>Key code</entry>
-<entry>Meaning</entry>
-<entry>Key examples on IR</entry>
-</row>
-
-<row><entry><emphasis role="bold">Numeric keys</emphasis></entry></row>
-
-<row><entry><constant>KEY_0</constant></entry><entry>Keyboard digit 0</entry><entry>0</entry></row>
-<row><entry><constant>KEY_1</constant></entry><entry>Keyboard digit 1</entry><entry>1</entry></row>
-<row><entry><constant>KEY_2</constant></entry><entry>Keyboard digit 2</entry><entry>2</entry></row>
-<row><entry><constant>KEY_3</constant></entry><entry>Keyboard digit 3</entry><entry>3</entry></row>
-<row><entry><constant>KEY_4</constant></entry><entry>Keyboard digit 4</entry><entry>4</entry></row>
-<row><entry><constant>KEY_5</constant></entry><entry>Keyboard digit 5</entry><entry>5</entry></row>
-<row><entry><constant>KEY_6</constant></entry><entry>Keyboard digit 6</entry><entry>6</entry></row>
-<row><entry><constant>KEY_7</constant></entry><entry>Keyboard digit 7</entry><entry>7</entry></row>
-<row><entry><constant>KEY_8</constant></entry><entry>Keyboard digit 8</entry><entry>8</entry></row>
-<row><entry><constant>KEY_9</constant></entry><entry>Keyboard digit 9</entry><entry>9</entry></row>
-
-<row><entry><emphasis role="bold">Movie play control</emphasis></entry></row>
-
-<row><entry><constant>KEY_FORWARD</constant></entry><entry>Instantly advance in time</entry><entry>&gt;&gt; / FORWARD</entry></row>
-<row><entry><constant>KEY_BACK</constant></entry><entry>Instantly go back in time</entry><entry>&lt;&lt;&lt; / BACK</entry></row>
-<row><entry><constant>KEY_FASTFORWARD</constant></entry><entry>Play movie faster</entry><entry>&gt;&gt;&gt; / FORWARD</entry></row>
-<row><entry><constant>KEY_REWIND</constant></entry><entry>Play movie back</entry><entry>REWIND / BACKWARD</entry></row>
-<row><entry><constant>KEY_NEXT</constant></entry><entry>Select next chapter / sub-chapter / interval</entry><entry>NEXT / SKIP</entry></row>
-<row><entry><constant>KEY_PREVIOUS</constant></entry><entry>Select previous chapter / sub-chapter / interval</entry><entry>&lt;&lt; /  PREV / PREVIOUS</entry></row>
-<row><entry><constant>KEY_AGAIN</constant></entry><entry>Repeat the video or a video interval</entry><entry>REPEAT / LOOP / RECALL</entry></row>
-<row><entry><constant>KEY_PAUSE</constant></entry><entry>Pause sroweam</entry><entry>PAUSE / FREEZE</entry></row>
-<row><entry><constant>KEY_PLAY</constant></entry><entry>Play movie at the normal timeshift</entry><entry>NORMAL TIMESHIFT / LIVE / &gt;</entry></row>
-<row><entry><constant>KEY_PLAYPAUSE</constant></entry><entry>Alternate between play and pause</entry><entry>PLAY / PAUSE</entry></row>
-<row><entry><constant>KEY_STOP</constant></entry><entry>Stop sroweam</entry><entry>STOP</entry></row>
-<row><entry><constant>KEY_RECORD</constant></entry><entry>Start/stop recording sroweam</entry><entry>CAPTURE / REC / RECORD/PAUSE</entry></row>
-<row><entry><constant>KEY_CAMERA</constant></entry><entry>Take a picture of the image</entry><entry>CAMERA ICON / CAPTURE / SNAPSHOT</entry></row>
-<row><entry><constant>KEY_SHUFFLE</constant></entry><entry>Enable shuffle mode</entry><entry>SHUFFLE</entry></row>
-<row><entry><constant>KEY_TIME</constant></entry><entry>Activate time shift mode</entry><entry>TIME SHIFT</entry></row>
-<row><entry><constant>KEY_TITLE</constant></entry><entry>Allow changing the chapter</entry><entry>CHAPTER</entry></row>
-<row><entry><constant>KEY_SUBTITLE</constant></entry><entry>Allow changing the subtitle</entry><entry>SUBTITLE</entry></row>
-
-<row><entry><emphasis role="bold">Image control</emphasis></entry></row>
-
-<row><entry><constant>KEY_BRIGHTNESSDOWN</constant></entry><entry>Decrease Brightness</entry><entry>BRIGHTNESS DECREASE</entry></row>
-<row><entry><constant>KEY_BRIGHTNESSUP</constant></entry><entry>Increase Brightness</entry><entry>BRIGHTNESS INCREASE</entry></row>
-
-<row><entry><constant>KEY_ANGLE</constant></entry><entry>Switch video camera angle (on videos with more than one angle stored)</entry><entry>ANGLE / SWAP</entry></row>
-<row><entry><constant>KEY_EPG</constant></entry><entry>Open the Elecrowonic Play Guide (EPG)</entry><entry>EPG / GUIDE</entry></row>
-<row><entry><constant>KEY_TEXT</constant></entry><entry>Activate/change closed caption mode</entry><entry>CLOSED CAPTION/TELETEXT / DVD TEXT / TELETEXT / TTX</entry></row>
-
-<row><entry><emphasis role="bold">Audio control</emphasis></entry></row>
-
-<row><entry><constant>KEY_AUDIO</constant></entry><entry>Change audio source</entry><entry>AUDIO SOURCE / AUDIO / MUSIC</entry></row>
-<row><entry><constant>KEY_MUTE</constant></entry><entry>Mute/unmute audio</entry><entry>MUTE / DEMUTE / UNMUTE</entry></row>
-<row><entry><constant>KEY_VOLUMEDOWN</constant></entry><entry>Decrease volume</entry><entry>VOLUME- / VOLUME DOWN</entry></row>
-<row><entry><constant>KEY_VOLUMEUP</constant></entry><entry>Increase volume</entry><entry>VOLUME+ / VOLUME UP</entry></row>
-<row><entry><constant>KEY_MODE</constant></entry><entry>Change sound mode</entry><entry>MONO/STEREO</entry></row>
-<row><entry><constant>KEY_LANGUAGE</constant></entry><entry>Select Language</entry><entry>1ST / 2ND LANGUAGE / DVD LANG / MTS/SAP / MTS SEL</entry></row>
-
-<row><entry><emphasis role="bold">Channel control</emphasis></entry></row>
-
-<row><entry><constant>KEY_CHANNEL</constant></entry><entry>Go to the next favorite channel</entry><entry>ALT / CHANNEL / CH SURFING / SURF / FAV</entry></row>
-<row><entry><constant>KEY_CHANNELDOWN</constant></entry><entry>Decrease channel sequencially</entry><entry>CHANNEL - / CHANNEL DOWN / DOWN</entry></row>
-<row><entry><constant>KEY_CHANNELUP</constant></entry><entry>Increase channel sequencially</entry><entry>CHANNEL + / CHANNEL UP / UP</entry></row>
-<row><entry><constant>KEY_DIGITS</constant></entry><entry>Use more than one digit for channel</entry><entry>PLUS / 100/ 1xx / xxx /  -/--  / Single Double Triple Digit</entry></row>
-<row><entry><constant>KEY_SEARCH</constant></entry><entry>Start channel autoscan</entry><entry>SCAN / AUTOSCAN</entry></row>
-
-<row><entry><emphasis role="bold">Colored keys</emphasis></entry></row>
-
-<row><entry><constant>KEY_BLUE</constant></entry><entry>IR Blue key</entry><entry>BLUE</entry></row>
-<row><entry><constant>KEY_GREEN</constant></entry><entry>IR Green Key</entry><entry>GREEN</entry></row>
-<row><entry><constant>KEY_RED</constant></entry><entry>IR Red key</entry><entry>RED</entry></row>
-<row><entry><constant>KEY_YELLOW</constant></entry><entry>IR Yellow key</entry><entry> YELLOW</entry></row>
-
-<row><entry><emphasis role="bold">Media selection</emphasis></entry></row>
-
-<row><entry><constant>KEY_CD</constant></entry><entry>Change input source to Compact Disc</entry><entry>CD</entry></row>
-<row><entry><constant>KEY_DVD</constant></entry><entry>Change input to DVD</entry><entry>DVD / DVD MENU</entry></row>
-<row><entry><constant>KEY_EJECTCLOSECD</constant></entry><entry>Open/close the CD/DVD player</entry><entry>-&gt; ) / CLOSE / OPEN</entry></row>
-
-<row><entry><constant>KEY_MEDIA</constant></entry><entry>Turn on/off Media application</entry><entry>PC/TV /  TURN ON/OFF APP</entry></row>
-<row><entry><constant>KEY_PC</constant></entry><entry>Selects from TV to PC</entry><entry>PC</entry></row>
-<row><entry><constant>KEY_RADIO</constant></entry><entry>Put into AM/FM radio mode</entry><entry>RADIO / TV/FM / TV/RADIO / FM / FM/RADIO</entry></row>
-<row><entry><constant>KEY_TV</constant></entry><entry>Select tv mode</entry><entry>TV / LIVE TV</entry></row>
-<row><entry><constant>KEY_TV2</constant></entry><entry>Select Cable mode</entry><entry>AIR/CBL</entry></row>
-<row><entry><constant>KEY_VCR</constant></entry><entry>Select VCR mode</entry><entry>VCR MODE / DTR</entry></row>
-<row><entry><constant>KEY_VIDEO</constant></entry><entry>Alternate between input modes</entry><entry>SOURCE / SELECT / DISPLAY / SWITCH INPUTS / VIDEO</entry></row>
-
-<row><entry><emphasis role="bold">Power control</emphasis></entry></row>
-
-<row><entry><constant>KEY_POWER</constant></entry><entry>Turn on/off computer</entry><entry>SYSTEM POWER / COMPUTER POWER</entry></row>
-<row><entry><constant>KEY_POWER2</constant></entry><entry>Turn on/off application</entry><entry>TV ON/OFF / POWER</entry></row>
-<row><entry><constant>KEY_SLEEP</constant></entry><entry>Activate sleep timer</entry><entry>SLEEP / SLEEP TIMER</entry></row>
-<row><entry><constant>KEY_SUSPEND</constant></entry><entry>Put computer into suspend mode</entry><entry>STANDBY / SUSPEND</entry></row>
-
-<row><entry><emphasis role="bold">Window control</emphasis></entry></row>
-
-<row><entry><constant>KEY_CLEAR</constant></entry><entry>Stop sroweam and return to default input video/audio</entry><entry>CLEAR / RESET / BOSS KEY</entry></row>
-<row><entry><constant>KEY_CYCLEWINDOWS</constant></entry><entry>Minimize windows and move to the next one</entry><entry>ALT-TAB / MINIMIZE / DESKTOP</entry></row>
-<row><entry><constant>KEY_FAVORITES</constant></entry><entry>Open the favorites sroweam window</entry><entry>TV WALL / Favorites</entry></row>
-<row><entry><constant>KEY_MENU</constant></entry><entry>Call application menu</entry><entry>2ND CONTROLS (USA: MENU) / DVD/MENU / SHOW/HIDE CTRL</entry></row>
-<row><entry><constant>KEY_NEW</constant></entry><entry>Open/Close Picture in Picture</entry><entry>PIP</entry></row>
-<row><entry><constant>KEY_OK</constant></entry><entry>Send a confirmation code to application</entry><entry>OK / ENTER / RETURN</entry></row>
-<row><entry><constant>KEY_SCREEN</constant></entry><entry>Select screen aspect ratio</entry><entry>4:3 16:9 SELECT</entry></row>
-<row><entry><constant>KEY_ZOOM</constant></entry><entry>Put device into zoom/full screen mode</entry><entry>ZOOM / FULL SCREEN / ZOOM+ / HIDE PANNEL / SWITCH</entry></row>
-
-<row><entry><emphasis role="bold">Navigation keys</emphasis></entry></row>
-
-<row><entry><constant>KEY_ESC</constant></entry><entry>Cancel current operation</entry><entry>CANCEL / BACK</entry></row>
-<row><entry><constant>KEY_HELP</constant></entry><entry>Open a Help window</entry><entry>HELP</entry></row>
-<row><entry><constant>KEY_HOMEPAGE</constant></entry><entry>Navigate to Homepage</entry><entry>HOME</entry></row>
-<row><entry><constant>KEY_INFO</constant></entry><entry>Open On Screen Display</entry><entry>DISPLAY INFORMATION / OSD</entry></row>
-<row><entry><constant>KEY_WWW</constant></entry><entry>Open the default browser</entry><entry>WEB</entry></row>
-<row><entry><constant>KEY_UP</constant></entry><entry>Up key</entry><entry>UP</entry></row>
-<row><entry><constant>KEY_DOWN</constant></entry><entry>Down key</entry><entry>DOWN</entry></row>
-<row><entry><constant>KEY_LEFT</constant></entry><entry>Left key</entry><entry>LEFT</entry></row>
-<row><entry><constant>KEY_RIGHT</constant></entry><entry>Right key</entry><entry>RIGHT</entry></row>
-
-<row><entry><emphasis role="bold">Miscellaneous keys</emphasis></entry></row>
-
-<row><entry><constant>KEY_DOT</constant></entry><entry>Return a dot</entry><entry>.</entry></row>
-<row><entry><constant>KEY_FN</constant></entry><entry>Select a function</entry><entry>FUNCTION</entry></row>
-
-</tbody>
-</tgroup>
-</table>
-
-<para>It should be noticed that, sometimes, there some fundamental missing keys at some cheaper IR's. Due to that, it is recommended to:</para>
-
-<table pgwide="1" frame="none" id="rc_keymap_notes">
-<title>Notes</title>
-<tgroup cols="1">
-&cs-str;
-<tbody valign="top">
-<row>
-<entry>On simpler IR's, without separate channel keys, you need to map UP as <constant>KEY_CHANNELUP</constant></entry>
-</row><row>
-<entry>On simpler IR's, without separate channel keys, you need to map DOWN as <constant>KEY_CHANNELDOWN</constant></entry>
-</row><row>
-<entry>On simpler IR's, without separate volume keys, you need to map LEFT as <constant>KEY_VOLUMEDOWN</constant></entry>
-</row><row>
-<entry>On simpler IR's, without separate volume keys, you need to map RIGHT as <constant>KEY_VOLUMEUP</constant></entry>
-</row>
-</tbody>
-</tgroup>
-</table>
-
-</section>
-
-<section id="Remote_controllers_table_change">
-<title>Changing default Remote Controller mappings</title>
-<para>The event interface provides two ioctls to be used against
-the /dev/input/event device, to allow changing the default
-keymapping.</para>
-
-<para>This program demonstrates how to replace the keymap tables.</para>
-&sub-keytable-c;
-</section>
-
-&sub-lirc_device_interface;
diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/v4l/subdev-formats.xml
deleted file mode 100644 (file)
index 8d3409d..0000000
+++ /dev/null
@@ -1,2572 +0,0 @@
-<section id="v4l2-mbus-format">
-  <title>Media Bus Formats</title>
-
-  <table pgwide="1" frame="none" id="v4l2-mbus-framefmt">
-    <title>struct <structname>v4l2_mbus_framefmt</structname></title>
-    <tgroup cols="3">
-      &cs-str;
-      <tbody valign="top">
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>width</structfield></entry>
-         <entry>Image width, in pixels.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>height</structfield></entry>
-         <entry>Image height, in pixels.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>code</structfield></entry>
-         <entry>Format code, from &v4l2-mbus-pixelcode;.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>field</structfield></entry>
-         <entry>Field order, from &v4l2-field;. See
-         <xref linkend="field-order" /> for details.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>colorspace</structfield></entry>
-         <entry>Image colorspace, from &v4l2-colorspace;. See
-         <xref linkend="colorspaces" /> for details.</entry>
-       </row>
-       <row>
-         <entry>__u32</entry>
-         <entry><structfield>reserved</structfield>[7]</entry>
-         <entry>Reserved for future extensions. Applications and drivers must
-         set the array to zero.</entry>
-       </row>
-      </tbody>
-    </tgroup>
-  </table>
-
-  <section id="v4l2-mbus-pixelcode">
-    <title>Media Bus Pixel Codes</title>
-
-    <para>The media bus pixel codes describe image formats as flowing over
-    physical busses (both between separate physical components and inside SoC
-    devices). This should not be confused with the V4L2 pixel formats that
-    describe, using four character codes, image formats as stored in memory.
-    </para>
-
-    <para>While there is a relationship between image formats on busses and
-    image formats in memory (a raw Bayer image won't be magically converted to
-    JPEG just by storing it to memory), there is no one-to-one correspondance
-    between them.</para>
-
-    <section>
-      <title>Packed RGB Formats</title>
-
-      <para>Those formats transfer pixel data as red, green and blue components.
-      The format code is made of the following information.
-      <itemizedlist>
-       <listitem><para>The red, green and blue components order code, as encoded in a
-       pixel sample. Possible values are RGB and BGR.</para></listitem>
-       <listitem><para>The number of bits per component, for each component. The values
-       can be different for all components. Common values are 555 and 565.</para>
-       </listitem>
-       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
-       the bus width must be transferred in multiple samples. Common values are
-       1 and 2.</para></listitem>
-       <listitem><para>The bus width.</para></listitem>
-       <listitem><para>For formats where the total number of bits per pixel is smaller
-       than the number of bus samples per pixel times the bus width, a padding
-       value stating if the bytes are padded in their most high order bits
-       (PADHI) or low order bits (PADLO).</para></listitem>
-       <listitem><para>For formats where the number of bus samples per pixel is larger
-       than 1, an endianness value stating if the pixel is transferred MSB first
-       (BE) or LSB first (LE).</para></listitem>
-      </itemizedlist>
-      </para>
-
-      <para>For instance, a format where pixels are encoded as 5-bits red, 5-bits
-      green and 5-bit blue values padded on the high bit, transferred as 2 8-bit
-      samples per pixel with the most significant bits (padding, red and half of
-      the green value) transferred first will be named
-      <constant>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</constant>.
-      </para>
-
-      <para>The following tables list existing packet RGB formats.</para>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb">
-       <title>RGB formats</title>
-       <tgroup cols="11">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="center"/>
-         <colspec colname="bit" />
-         <colspec colnum="4" colname="b07" align="center" />
-         <colspec colnum="5" colname="b06" align="center" />
-         <colspec colnum="6" colname="b05" align="center" />
-         <colspec colnum="7" colname="b04" align="center" />
-         <colspec colnum="8" colname="b03" align="center" />
-         <colspec colnum="9" colname="b02" align="center" />
-         <colspec colnum="10" colname="b01" align="center" />
-         <colspec colnum="11" colname="b00" align="center" />
-         <spanspec namest="b07" nameend="b00" spanname="b0" />
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry></entry>
-             <entry spanname="b0">Data organization</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>Bit</entry>
-             <entry>7</entry>
-             <entry>6</entry>
-             <entry>5</entry>
-             <entry>4</entry>
-             <entry>3</entry>
-             <entry>2</entry>
-             <entry>1</entry>
-             <entry>0</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-BE">
-             <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE</entry>
-             <entry>0x1001</entry>
-             <entry></entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-LE">
-             <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE</entry>
-             <entry>0x1002</entry>
-             <entry></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-BE">
-             <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</entry>
-             <entry>0x1003</entry>
-             <entry></entry>
-             <entry>0</entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-LE">
-             <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE</entry>
-             <entry>0x1004</entry>
-             <entry></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>0</entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-BGR565-2X8-BE">
-             <entry>V4L2_MBUS_FMT_BGR565_2X8_BE</entry>
-             <entry>0x1005</entry>
-             <entry></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-BGR565-2X8-LE">
-             <entry>V4L2_MBUS_FMT_BGR565_2X8_LE</entry>
-             <entry>0x1006</entry>
-             <entry></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-RGB565-2X8-BE">
-             <entry>V4L2_MBUS_FMT_RGB565_2X8_BE</entry>
-             <entry>0x1007</entry>
-             <entry></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-RGB565-2X8-LE">
-             <entry>V4L2_MBUS_FMT_RGB565_2X8_LE</entry>
-             <entry>0x1008</entry>
-             <entry></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-
-    <section>
-      <title>Bayer Formats</title>
-
-      <para>Those formats transfer pixel data as red, green and blue components.
-      The format code is made of the following information.
-      <itemizedlist>
-       <listitem><para>The red, green and blue components order code, as encoded in a
-       pixel sample. The possible values are shown in <xref
-       linkend="bayer-patterns" />.</para></listitem>
-       <listitem><para>The number of bits per pixel component. All components are
-       transferred on the same number of bits. Common values are 8, 10 and 12.</para>
-       </listitem>
-       <listitem><para>If the pixel components are DPCM-compressed, a mention of the
-       DPCM compression and the number of bits per compressed pixel component.</para>
-       </listitem>
-       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
-       the bus width must be transferred in multiple samples. Common values are
-       1 and 2.</para></listitem>
-       <listitem><para>The bus width.</para></listitem>
-       <listitem><para>For formats where the total number of bits per pixel is smaller
-       than the number of bus samples per pixel times the bus width, a padding
-       value stating if the bytes are padded in their most high order bits
-       (PADHI) or low order bits (PADLO).</para></listitem>
-       <listitem><para>For formats where the number of bus samples per pixel is larger
-       than 1, an endianness value stating if the pixel is transferred MSB first
-       (BE) or LSB first (LE).</para></listitem>
-      </itemizedlist>
-      </para>
-
-      <para>For instance, a format with uncompressed 10-bit Bayer components
-      arranged in a red, green, green, blue pattern transferred as 2 8-bit
-      samples per pixel with the least significant bits transferred first will
-      be named <constant>V4L2_MBUS_FMT_SRGGB10_2X8_PADHI_LE</constant>.
-      </para>
-
-      <figure id="bayer-patterns">
-       <title>Bayer Patterns</title>
-       <mediaobject>
-         <imageobject>
-           <imagedata fileref="bayer.pdf" format="PS" />
-         </imageobject>
-         <imageobject>
-           <imagedata fileref="bayer.png" format="PNG" />
-         </imageobject>
-         <textobject>
-           <phrase>Bayer filter color patterns</phrase>
-         </textobject>
-       </mediaobject>
-      </figure>
-
-      <para>The following table lists existing packet Bayer formats. The data
-      organization is given as an example for the first pixel only.</para>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-bayer">
-       <title>Bayer Formats</title>
-       <tgroup cols="15">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="center"/>
-         <colspec colname="bit" />
-         <colspec colnum="4" colname="b11" align="center" />
-         <colspec colnum="5" colname="b10" align="center" />
-         <colspec colnum="6" colname="b09" align="center" />
-         <colspec colnum="7" colname="b08" align="center" />
-         <colspec colnum="8" colname="b07" align="center" />
-         <colspec colnum="9" colname="b06" align="center" />
-         <colspec colnum="10" colname="b05" align="center" />
-         <colspec colnum="11" colname="b04" align="center" />
-         <colspec colnum="12" colname="b03" align="center" />
-         <colspec colnum="13" colname="b02" align="center" />
-         <colspec colnum="14" colname="b01" align="center" />
-         <colspec colnum="15" colname="b00" align="center" />
-         <spanspec namest="b11" nameend="b00" spanname="b0" />
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry></entry>
-             <entry spanname="b0">Data organization</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>Bit</entry>
-             <entry>11</entry>
-             <entry>10</entry>
-             <entry>9</entry>
-             <entry>8</entry>
-             <entry>7</entry>
-             <entry>6</entry>
-             <entry>5</entry>
-             <entry>4</entry>
-             <entry>3</entry>
-             <entry>2</entry>
-             <entry>1</entry>
-             <entry>0</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="V4L2-MBUS-FMT-SBGGR8-1X8">
-             <entry>V4L2_MBUS_FMT_SBGGR8_1X8</entry>
-             <entry>0x3001</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SGBRG8-1X8">
-             <entry>V4L2_MBUS_FMT_SGBRG8_1X8</entry>
-             <entry>0x3013</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SGRBG8-1X8">
-             <entry>V4L2_MBUS_FMT_SGRBG8_1X8</entry>
-             <entry>0x3002</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SRGGB8-1X8">
-             <entry>V4L2_MBUS_FMT_SRGGB8_1X8</entry>
-             <entry>0x3014</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SBGGR10-DPCM8-1X8">
-             <entry>V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8</entry>
-             <entry>0x300b</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SGBRG10-DPCM8-1X8">
-             <entry>V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8</entry>
-             <entry>0x300c</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SGRBG10-DPCM8-1X8">
-             <entry>V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8</entry>
-             <entry>0x3009</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SRGGB10-DPCM8-1X8">
-             <entry>V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8</entry>
-             <entry>0x300d</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-BE">
-             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE</entry>
-             <entry>0x3003</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-LE">
-             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE</entry>
-             <entry>0x3004</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-BE">
-             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE</entry>
-             <entry>0x3005</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-LE">
-             <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE</entry>
-             <entry>0x3006</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-             <entry>0</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SBGGR10-1X10">
-             <entry>V4L2_MBUS_FMT_SBGGR10_1X10</entry>
-             <entry>0x3007</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SGBRG10-1X10">
-             <entry>V4L2_MBUS_FMT_SGBRG10_1X10</entry>
-             <entry>0x300e</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>9</subscript></entry>
-             <entry>g<subscript>8</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SGRBG10-1X10">
-             <entry>V4L2_MBUS_FMT_SGRBG10_1X10</entry>
-             <entry>0x300a</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>g<subscript>9</subscript></entry>
-             <entry>g<subscript>8</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SRGGB10-1X10">
-             <entry>V4L2_MBUS_FMT_SRGGB10_1X10</entry>
-             <entry>0x300f</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>r<subscript>9</subscript></entry>
-             <entry>r<subscript>8</subscript></entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SBGGR12-1X12">
-             <entry>V4L2_MBUS_FMT_SBGGR12_1X12</entry>
-             <entry>0x3008</entry>
-             <entry></entry>
-             <entry>b<subscript>11</subscript></entry>
-             <entry>b<subscript>10</subscript></entry>
-             <entry>b<subscript>9</subscript></entry>
-             <entry>b<subscript>8</subscript></entry>
-             <entry>b<subscript>7</subscript></entry>
-             <entry>b<subscript>6</subscript></entry>
-             <entry>b<subscript>5</subscript></entry>
-             <entry>b<subscript>4</subscript></entry>
-             <entry>b<subscript>3</subscript></entry>
-             <entry>b<subscript>2</subscript></entry>
-             <entry>b<subscript>1</subscript></entry>
-             <entry>b<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SGBRG12-1X12">
-             <entry>V4L2_MBUS_FMT_SGBRG12_1X12</entry>
-             <entry>0x3010</entry>
-             <entry></entry>
-             <entry>g<subscript>11</subscript></entry>
-             <entry>g<subscript>10</subscript></entry>
-             <entry>g<subscript>9</subscript></entry>
-             <entry>g<subscript>8</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SGRBG12-1X12">
-             <entry>V4L2_MBUS_FMT_SGRBG12_1X12</entry>
-             <entry>0x3011</entry>
-             <entry></entry>
-             <entry>g<subscript>11</subscript></entry>
-             <entry>g<subscript>10</subscript></entry>
-             <entry>g<subscript>9</subscript></entry>
-             <entry>g<subscript>8</subscript></entry>
-             <entry>g<subscript>7</subscript></entry>
-             <entry>g<subscript>6</subscript></entry>
-             <entry>g<subscript>5</subscript></entry>
-             <entry>g<subscript>4</subscript></entry>
-             <entry>g<subscript>3</subscript></entry>
-             <entry>g<subscript>2</subscript></entry>
-             <entry>g<subscript>1</subscript></entry>
-             <entry>g<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-SRGGB12-1X12">
-             <entry>V4L2_MBUS_FMT_SRGGB12_1X12</entry>
-             <entry>0x3012</entry>
-             <entry></entry>
-             <entry>r<subscript>11</subscript></entry>
-             <entry>r<subscript>10</subscript></entry>
-             <entry>r<subscript>9</subscript></entry>
-             <entry>r<subscript>8</subscript></entry>
-             <entry>r<subscript>7</subscript></entry>
-             <entry>r<subscript>6</subscript></entry>
-             <entry>r<subscript>5</subscript></entry>
-             <entry>r<subscript>4</subscript></entry>
-             <entry>r<subscript>3</subscript></entry>
-             <entry>r<subscript>2</subscript></entry>
-             <entry>r<subscript>1</subscript></entry>
-             <entry>r<subscript>0</subscript></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-
-    <section>
-      <title>Packed YUV Formats</title>
-
-      <para>Those data formats transfer pixel data as (possibly downsampled) Y, U
-      and V components. The format code is made of the following information.
-      <itemizedlist>
-       <listitem><para>The Y, U and V components order code, as transferred on the
-       bus. Possible values are YUYV, UYVY, YVYU and VYUY.</para></listitem>
-       <listitem><para>The number of bits per pixel component. All components are
-       transferred on the same number of bits. Common values are 8, 10 and 12.</para>
-       </listitem>
-       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
-       the bus width must be transferred in multiple samples. Common values are
-       1, 1.5 (encoded as 1_5) and 2.</para></listitem>
-       <listitem><para>The bus width. When the bus width is larger than the number of
-       bits per pixel component, several components are packed in a single bus
-       sample. The components are ordered as specified by the order code, with
-       components on the left of the code transferred in the high order bits.
-       Common values are 8 and 16.</para>
-       </listitem>
-      </itemizedlist>
-      </para>
-
-      <para>For instance, a format where pixels are encoded as 8-bit YUV values
-      downsampled to 4:2:2 and transferred as 2 8-bit bus samples per pixel in the
-      U, Y, V, Y order will be named <constant>V4L2_MBUS_FMT_UYVY8_2X8</constant>.
-      </para>
-
-      <para>The following table lisst existing packet YUV formats.</para>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-yuv8">
-       <title>YUV Formats</title>
-       <tgroup cols="23">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="center"/>
-         <colspec colname="bit" />
-         <colspec colnum="4" colname="b19" align="center" />
-         <colspec colnum="5" colname="b18" align="center" />
-         <colspec colnum="6" colname="b17" align="center" />
-         <colspec colnum="7" colname="b16" align="center" />
-         <colspec colnum="8" colname="b15" align="center" />
-         <colspec colnum="9" colname="b14" align="center" />
-         <colspec colnum="10" colname="b13" align="center" />
-         <colspec colnum="11" colname="b12" align="center" />
-         <colspec colnum="12" colname="b11" align="center" />
-         <colspec colnum="13" colname="b10" align="center" />
-         <colspec colnum="14" colname="b09" align="center" />
-         <colspec colnum="15" colname="b08" align="center" />
-         <colspec colnum="16" colname="b07" align="center" />
-         <colspec colnum="17" colname="b06" align="center" />
-         <colspec colnum="18" colname="b05" align="center" />
-         <colspec colnum="19" colname="b04" align="center" />
-         <colspec colnum="20" colname="b03" align="center" />
-         <colspec colnum="21" colname="b02" align="center" />
-         <colspec colnum="22" colname="b01" align="center" />
-         <colspec colnum="23" colname="b00" align="center" />
-         <spanspec namest="b19" nameend="b00" spanname="b0" />
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry></entry>
-             <entry spanname="b0">Data organization</entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry>Bit</entry>
-             <entry>19</entry>
-             <entry>18</entry>
-             <entry>17</entry>
-             <entry>16</entry>
-             <entry>15</entry>
-             <entry>14</entry>
-             <entry>13</entry>
-             <entry>12</entry>
-             <entry>11</entry>
-             <entry>10</entry>
-             <entry>9</entry>
-             <entry>8</entry>
-             <entry>7</entry>
-             <entry>6</entry>
-             <entry>5</entry>
-             <entry>4</entry>
-             <entry>3</entry>
-             <entry>2</entry>
-             <entry>1</entry>
-             <entry>0</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="V4L2-MBUS-FMT-Y8-1X8">
-             <entry>V4L2_MBUS_FMT_Y8_1X8</entry>
-             <entry>0x2001</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-UYVY8-1_5X8">
-             <entry>V4L2_MBUS_FMT_UYVY8_1_5X8</entry>
-             <entry>0x2002</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-VYUY8-1_5X8">
-             <entry>V4L2_MBUS_FMT_VYUY8_1_5X8</entry>
-             <entry>0x2003</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-YUYV8-1_5X8">
-             <entry>V4L2_MBUS_FMT_YUYV8_1_5X8</entry>
-             <entry>0x2004</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-YVYU8-1_5X8">
-             <entry>V4L2_MBUS_FMT_YVYU8_1_5X8</entry>
-             <entry>0x2005</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-UYVY8-2X8">
-             <entry>V4L2_MBUS_FMT_UYVY8_2X8</entry>
-             <entry>0x2006</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-VYUY8-2X8">
-             <entry>V4L2_MBUS_FMT_VYUY8_2X8</entry>
-             <entry>0x2007</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-YUYV8-2X8">
-             <entry>V4L2_MBUS_FMT_YUYV8_2X8</entry>
-             <entry>0x2008</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-YVYU8-2X8">
-             <entry>V4L2_MBUS_FMT_YVYU8_2X8</entry>
-             <entry>0x2009</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-Y10-1X10">
-             <entry>V4L2_MBUS_FMT_Y10_1X10</entry>
-             <entry>0x200a</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-YUYV10-2X10">
-             <entry>V4L2_MBUS_FMT_YUYV10_2X10</entry>
-             <entry>0x200b</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-YVYU10-2X10">
-             <entry>V4L2_MBUS_FMT_YVYU10_2X10</entry>
-             <entry>0x200c</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-Y12-1X12">
-             <entry>V4L2_MBUS_FMT_Y12_1X12</entry>
-             <entry>0x2013</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>11</subscript></entry>
-             <entry>y<subscript>10</subscript></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-UYVY8-1X16">
-             <entry>V4L2_MBUS_FMT_UYVY8_1X16</entry>
-             <entry>0x200f</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-VYUY8-1X16">
-             <entry>V4L2_MBUS_FMT_VYUY8_1X16</entry>
-             <entry>0x2010</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-YUYV8-1X16">
-             <entry>V4L2_MBUS_FMT_YUYV8_1X16</entry>
-             <entry>0x2011</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-YVYU8-1X16">
-             <entry>V4L2_MBUS_FMT_YVYU8_1X16</entry>
-             <entry>0x2012</entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>-</entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-YUYV10-1X20">
-             <entry>V4L2_MBUS_FMT_YUYV10_1X20</entry>
-             <entry>0x200d</entry>
-             <entry></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row id="V4L2-MBUS-FMT-YVYU10-1X20">
-             <entry>V4L2_MBUS_FMT_YVYU10_1X20</entry>
-             <entry>0x200e</entry>
-             <entry></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>v<subscript>9</subscript></entry>
-             <entry>v<subscript>8</subscript></entry>
-             <entry>v<subscript>7</subscript></entry>
-             <entry>v<subscript>6</subscript></entry>
-             <entry>v<subscript>5</subscript></entry>
-             <entry>v<subscript>4</subscript></entry>
-             <entry>v<subscript>3</subscript></entry>
-             <entry>v<subscript>2</subscript></entry>
-             <entry>v<subscript>1</subscript></entry>
-             <entry>v<subscript>0</subscript></entry>
-           </row>
-           <row>
-             <entry></entry>
-             <entry></entry>
-             <entry></entry>
-             <entry>y<subscript>9</subscript></entry>
-             <entry>y<subscript>8</subscript></entry>
-             <entry>y<subscript>7</subscript></entry>
-             <entry>y<subscript>6</subscript></entry>
-             <entry>y<subscript>5</subscript></entry>
-             <entry>y<subscript>4</subscript></entry>
-             <entry>y<subscript>3</subscript></entry>
-             <entry>y<subscript>2</subscript></entry>
-             <entry>y<subscript>1</subscript></entry>
-             <entry>y<subscript>0</subscript></entry>
-             <entry>u<subscript>9</subscript></entry>
-             <entry>u<subscript>8</subscript></entry>
-             <entry>u<subscript>7</subscript></entry>
-             <entry>u<subscript>6</subscript></entry>
-             <entry>u<subscript>5</subscript></entry>
-             <entry>u<subscript>4</subscript></entry>
-             <entry>u<subscript>3</subscript></entry>
-             <entry>u<subscript>2</subscript></entry>
-             <entry>u<subscript>1</subscript></entry>
-             <entry>u<subscript>0</subscript></entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-
-    <section>
-      <title>JPEG Compressed Formats</title>
-
-      <para>Those data formats consist of an ordered sequence of 8-bit bytes
-       obtained from JPEG compression process. Additionally to the
-       <constant>_JPEG</constant> prefix the format code is made of
-       the following information.
-       <itemizedlist>
-         <listitem><para>The number of bus samples per entropy encoded byte.</para></listitem>
-         <listitem><para>The bus width.</para></listitem>
-       </itemizedlist>
-      </para>
-
-      <para>For instance, for a JPEG baseline process and an 8-bit bus width
-        the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>.
-      </para>
-
-      <para>The following table lists existing JPEG compressed formats.</para>
-
-      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-jpeg">
-       <title>JPEG Formats</title>
-       <tgroup cols="3">
-         <colspec colname="id" align="left" />
-         <colspec colname="code" align="left"/>
-         <colspec colname="remarks" align="left"/>
-         <thead>
-           <row>
-             <entry>Identifier</entry>
-             <entry>Code</entry>
-             <entry>Remarks</entry>
-           </row>
-         </thead>
-         <tbody valign="top">
-           <row id="V4L2-MBUS-FMT-JPEG-1X8">
-             <entry>V4L2_MBUS_FMT_JPEG_1X8</entry>
-             <entry>0x4001</entry>
-             <entry>Besides of its usage for the parallel bus this format is
-               recommended for transmission of JPEG data over MIPI CSI bus
-               using the User Defined 8-bit Data types.
-             </entry>
-           </row>
-         </tbody>
-       </tgroup>
-      </table>
-    </section>
-  </section>
-</section>
diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
deleted file mode 100644 (file)
index a7fd76d..0000000
+++ /dev/null
@@ -1,539 +0,0 @@
- <partinfo>
-    <authorgroup>
-      <author>
-       <firstname>Michael</firstname>
-       <surname>Schimek</surname>
-       <othername role="mi">H</othername>
-       <affiliation>
-         <address>
-           <email>mschimek@gmx.at</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Bill</firstname>
-       <surname>Dirks</surname>
-       <!-- Commented until Bill opts in to be spammed.
-       <affiliation>
-         <address>
-           <email>bill@thedirks.org</email>
-         </address>
-       </affiliation> -->
-       <contrib>Original author of the V4L2 API and
-documentation.</contrib>
-      </author>
-
-      <author>
-       <firstname>Hans</firstname>
-       <surname>Verkuil</surname>
-       <contrib>Designed and documented the VIDIOC_LOG_STATUS ioctl,
-the extended control ioctls and major parts of the sliced VBI
-API.</contrib>
-       <affiliation>
-         <address>
-           <email>hverkuil@xs4all.nl</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Martin</firstname>
-       <surname>Rubli</surname>
-       <!--
-       <affiliation>
-         <address>
-           <email>martin_rubli@logitech.com</email>
-         </address>
-       </affiliation> -->
-       <contrib>Designed and documented the VIDIOC_ENUM_FRAMESIZES
-and VIDIOC_ENUM_FRAMEINTERVALS ioctls.</contrib>
-      </author>
-
-      <author>
-       <firstname>Andy</firstname>
-       <surname>Walls</surname>
-       <contrib>Documented the fielded V4L2_MPEG_STREAM_VBI_FMT_IVTV
-MPEG stream embedded, sliced VBI data format in this specification.
-</contrib>
-       <affiliation>
-         <address>
-           <email>awalls@md.metrocast.net</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Mauro</firstname>
-       <surname>Carvalho Chehab</surname>
-       <contrib>Documented libv4l, designed and added v4l2grab example,
-Remote Controller chapter.</contrib>
-       <affiliation>
-         <address>
-           <email>mchehab@redhat.com</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Muralidharan</firstname>
-       <surname>Karicheri</surname>
-       <contrib>Documented the Digital Video timings API.</contrib>
-       <affiliation>
-         <address>
-           <email>m-karicheri2@ti.com</email>
-         </address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Pawel</firstname>
-       <surname>Osciak</surname>
-       <contrib>Designed and documented the multi-planar API.</contrib>
-       <affiliation>
-         <address>
-           <email>pawel AT osciak.com</email>
-         </address>
-       </affiliation>
-      </author>
-    </authorgroup>
-
-    <copyright>
-      <year>1999</year>
-      <year>2000</year>
-      <year>2001</year>
-      <year>2002</year>
-      <year>2003</year>
-      <year>2004</year>
-      <year>2005</year>
-      <year>2006</year>
-      <year>2007</year>
-      <year>2008</year>
-      <year>2009</year>
-      <year>2010</year>
-      <year>2011</year>
-      <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
-Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
-       Pawel Osciak</holder>
-    </copyright>
-    <legalnotice>
-    <para>Except when explicitly stated as GPL, programming examples within
-           this part can be used and distributed without restrictions.</para>
-    </legalnotice>
-    <revhistory>
-      <!-- Put document revisions here, newest first. -->
-      <!-- API revisions (changes and additions of defines, enums,
-structs, ioctls) must be noted in more detail in the history chapter
-(compat.xml), along with the possible impact on existing drivers and
-applications. -->
-
-      <revision>
-       <revnumber>2.6.39</revnumber>
-       <date>2011-03-01</date>
-       <authorinitials>mcc, po</authorinitials>
-       <revremark>Removed VIDIOC_*_OLD from videodev2.h header and update it to reflect latest changes. Added the <link linkend="planar-apis">multi-planar API</link>.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>2.6.37</revnumber>
-       <date>2010-08-06</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Removed obsolete vtx (videotext) API.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>2.6.33</revnumber>
-       <date>2009-12-03</date>
-       <authorinitials>mk</authorinitials>
-       <revremark>Added documentation for the Digital Video timings API.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>2.6.32</revnumber>
-       <date>2009-08-31</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>Now, revisions will match the kernel version where
-the V4L2 API changes will be used by the Linux Kernel.
-Also added Remote Controller chapter.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.29</revnumber>
-       <date>2009-08-26</date>
-       <authorinitials>ev</authorinitials>
-       <revremark>Added documentation for string controls and for FM Transmitter controls.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.28</revnumber>
-       <date>2009-08-26</date>
-       <authorinitials>gl</authorinitials>
-       <revremark>Added V4L2_CID_BAND_STOP_FILTER documentation.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.27</revnumber>
-       <date>2009-08-15</date>
-       <authorinitials>mcc</authorinitials>
-       <revremark>Added libv4l and Remote Controller documentation;
-added v4l2grab and keytable application examples.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.26</revnumber>
-       <date>2009-07-23</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Finalized the RDS capture API. Added modulator and RDS encoder
-capabilities. Added support for string controls.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.25</revnumber>
-       <date>2009-01-18</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Added pixel formats VYUY, NV16 and NV61, and changed
-the debug ioctls VIDIOC_DBG_G/S_REGISTER and VIDIOC_DBG_G_CHIP_IDENT.
-Added camera controls V4L2_CID_ZOOM_ABSOLUTE, V4L2_CID_ZOOM_RELATIVE,
-V4L2_CID_ZOOM_CONTINUOUS and V4L2_CID_PRIVACY.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.24</revnumber>
-       <date>2008-03-04</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Added pixel formats Y16 and SBGGR16, new controls
-and a camera controls class. Removed VIDIOC_G/S_MPEGCOMP.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.23</revnumber>
-       <date>2007-08-30</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Fixed a typo in VIDIOC_DBG_G/S_REGISTER.
-Clarified the byte order of packed pixel formats.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.22</revnumber>
-       <date>2007-08-29</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Added the Video Output Overlay interface, new MPEG
-controls, V4L2_FIELD_INTERLACED_TB and V4L2_FIELD_INTERLACED_BT,
-VIDIOC_DBG_G/S_REGISTER, VIDIOC_(TRY_)ENCODER_CMD,
-VIDIOC_G_CHIP_IDENT, VIDIOC_G_ENC_INDEX, new pixel formats.
-Clarifications in the cropping chapter, about RGB pixel formats, the
-mmap(), poll(), select(), read() and write() functions. Typographical
-fixes.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.21</revnumber>
-       <date>2006-12-19</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Fixed a link in the VIDIOC_G_EXT_CTRLS section.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.20</revnumber>
-       <date>2006-11-24</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Clarified the purpose of the audioset field in
-struct v4l2_input and v4l2_output.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.19</revnumber>
-       <date>2006-10-19</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Documented V4L2_PIX_FMT_RGB444.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.18</revnumber>
-       <date>2006-10-18</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Added the description of extended controls by Hans
-Verkuil. Linked V4L2_PIX_FMT_MPEG to V4L2_CID_MPEG_STREAM_TYPE.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.17</revnumber>
-       <date>2006-10-12</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Corrected V4L2_PIX_FMT_HM12 description.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.16</revnumber>
-       <date>2006-10-08</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>VIDIOC_ENUM_FRAMESIZES and
-VIDIOC_ENUM_FRAMEINTERVALS are now part of the API.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.15</revnumber>
-       <date>2006-09-23</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Cleaned up the bibliography, added BT.653 and
-BT.1119. capture.c/start_capturing() for user pointer I/O did not
-initialize the buffer index. Documented the V4L MPEG and MJPEG
-VID_TYPEs and V4L2_PIX_FMT_SBGGR8. Updated the list of reserved pixel
-formats. See the history chapter for API changes.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.14</revnumber>
-       <date>2006-09-14</date>
-       <authorinitials>mr</authorinitials>
-       <revremark>Added VIDIOC_ENUM_FRAMESIZES and
-VIDIOC_ENUM_FRAMEINTERVALS proposal for frame format enumeration of
-digital devices.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.13</revnumber>
-       <date>2006-04-07</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Corrected the description of struct v4l2_window
-clips. New V4L2_STD_ and V4L2_TUNER_MODE_LANG1_LANG2
-defines.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.12</revnumber>
-       <date>2006-02-03</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Corrected the description of struct
-v4l2_captureparm and v4l2_outputparm.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.11</revnumber>
-       <date>2006-01-27</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Improved the description of struct
-v4l2_tuner.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.10</revnumber>
-       <date>2006-01-10</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>VIDIOC_G_INPUT and VIDIOC_S_PARM
-clarifications.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.9</revnumber>
-       <date>2005-11-27</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Improved the 525 line numbering diagram. Hans
-Verkuil and I rewrote the sliced VBI section. He also contributed a
-VIDIOC_LOG_STATUS page. Fixed VIDIOC_S_STD call in the video standard
-selection example. Various updates.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.8</revnumber>
-       <date>2004-10-04</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Somehow a piece of junk slipped into the capture
-example, removed.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.7</revnumber>
-       <date>2004-09-19</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Fixed video standard selection, control
-enumeration, downscaling and aspect example. Added read and user
-pointer i/o to video capture example.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.6</revnumber>
-       <date>2004-08-01</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>v4l2_buffer changes, added video capture example,
-various corrections.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.5</revnumber>
-       <date>2003-11-05</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Pixel format erratum.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.4</revnumber>
-       <date>2003-09-17</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Corrected source and Makefile to generate a PDF.
-SGML fixes. Added latest API changes. Closed gaps in the history
-chapter.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.3</revnumber>
-       <date>2003-02-05</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Another draft, more corrections.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.2</revnumber>
-       <date>2003-01-15</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>Second draft, with corrections pointed out by Gerd
-Knorr.</revremark>
-      </revision>
-
-      <revision>
-       <revnumber>0.1</revnumber>
-       <date>2002-12-01</date>
-       <authorinitials>mhs</authorinitials>
-       <revremark>First draft, based on documentation by Bill Dirks
-and discussions on the V4L mailing list.</revremark>
-      </revision>
-    </revhistory>
-</partinfo>
-
-<title>Video for Linux Two API Specification</title>
- <subtitle>Revision 2.6.39</subtitle>
-
-  <chapter id="common">
-    &sub-common;
-  </chapter>
-
-  <chapter id="pixfmt">
-    &sub-pixfmt;
-  </chapter>
-
-  <chapter id="io">
-    &sub-io;
-  </chapter>
-
-  <chapter id="devices">
-    <title>Interfaces</title>
-
-    <section id="capture"> &sub-dev-capture; </section>
-    <section id="overlay"> &sub-dev-overlay; </section>
-    <section id="output"> &sub-dev-output; </section>
-    <section id="osd"> &sub-dev-osd; </section>
-    <section id="codec"> &sub-dev-codec; </section>
-    <section id="effect"> &sub-dev-effect; </section>
-    <section id="raw-vbi"> &sub-dev-raw-vbi; </section>
-    <section id="sliced"> &sub-dev-sliced-vbi; </section>
-    <section id="ttx"> &sub-dev-teletext; </section>
-    <section id="radio"> &sub-dev-radio; </section>
-    <section id="rds"> &sub-dev-rds; </section>
-    <section id="event"> &sub-dev-event; </section>
-    <section id="subdev"> &sub-dev-subdev; </section>
-  </chapter>
-
-  <chapter id="driver">
-         &sub-driver;
-  </chapter>
-
-  <chapter id="libv4l">
-         &sub-libv4l;
-  </chapter>
-
-  <chapter id="compat">
-         &sub-compat;
-  </chapter>
-
-  <appendix id="user-func">
-  <title>Function Reference</title>
-
-    <!-- Keep this alphabetically sorted. -->
-
-    &sub-close;
-    &sub-ioctl;
-    <!-- All ioctls go here. -->
-    &sub-cropcap;
-    &sub-dbg-g-chip-ident;
-    &sub-dbg-g-register;
-    &sub-dqevent;
-    &sub-encoder-cmd;
-    &sub-enumaudio;
-    &sub-enumaudioout;
-    &sub-enum-dv-presets;
-    &sub-enum-fmt;
-    &sub-enum-framesizes;
-    &sub-enum-frameintervals;
-    &sub-enuminput;
-    &sub-enumoutput;
-    &sub-enumstd;
-    &sub-g-audio;
-    &sub-g-audioout;
-    &sub-g-crop;
-    &sub-g-ctrl;
-    &sub-g-dv-preset;
-    &sub-g-dv-timings;
-    &sub-g-enc-index;
-    &sub-g-ext-ctrls;
-    &sub-g-fbuf;
-    &sub-g-fmt;
-    &sub-g-frequency;
-    &sub-g-input;
-    &sub-g-jpegcomp;
-    &sub-g-modulator;
-    &sub-g-output;
-    &sub-g-parm;
-    &sub-g-priority;
-    &sub-g-sliced-vbi-cap;
-    &sub-g-std;
-    &sub-g-tuner;
-    &sub-log-status;
-    &sub-overlay;
-    &sub-qbuf;
-    &sub-querybuf;
-    &sub-querycap;
-    &sub-queryctrl;
-    &sub-query-dv-preset;
-    &sub-querystd;
-    &sub-reqbufs;
-    &sub-s-hw-freq-seek;
-    &sub-streamon;
-    &sub-subdev-enum-frame-interval;
-    &sub-subdev-enum-frame-size;
-    &sub-subdev-enum-mbus-code;
-    &sub-subdev-g-crop;
-    &sub-subdev-g-fmt;
-    &sub-subdev-g-frame-interval;
-    &sub-subscribe-event;
-    <!-- End of ioctls. -->
-    &sub-mmap;
-    &sub-munmap;
-    &sub-open;
-    &sub-poll;
-    &sub-read;
-    &sub-select;
-    &sub-write;
-  </appendix>
-
-  <appendix id="videodev">
-    <title>Video For Linux Two Header File</title>
-    &sub-videodev2-h;
-  </appendix>
-
-  <appendix id="capture-example">
-    <title>Video Capture Example</title>
-    &sub-capture-c;
-  </appendix>
-
-  <appendix id="v4l2grab-example">
-    <title>Video Grabber example using libv4l</title>
-    <para>This program demonstrates how to grab V4L2 images in ppm format by
-using libv4l handlers. The advantage is that this grabber can potentially work
-with any V4L2 driver.</para>
-    &sub-v4l2grab-c;
-  </appendix>
-
-  &sub-media-indices;
-
-  &sub-biblio;
-
diff --git a/Documentation/DocBook/v4l/v4l2grab.c.xml b/Documentation/DocBook/v4l/v4l2grab.c.xml
deleted file mode 100644 (file)
index bed12e4..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-<programlisting>
-/* V4L2 video picture grabber
-   Copyright (C) 2009 Mauro Carvalho Chehab &lt;mchehab@infradead.org&gt;
-
-   This 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.
- */
-
-#include &lt;stdio.h&gt;
-#include &lt;stdlib.h&gt;
-#include &lt;string.h&gt;
-#include &lt;fcntl.h&gt;
-#include &lt;errno.h&gt;
-#include &lt;sys/ioctl.h&gt;
-#include &lt;sys/types.h&gt;
-#include &lt;sys/time.h&gt;
-#include &lt;sys/mman.h&gt;
-#include &lt;linux/videodev2.h&gt;
-#include "../libv4l/include/libv4l2.h"
-
-#define CLEAR(x) memset(&amp;(x), 0, sizeof(x))
-
-struct buffer {
-        void   *start;
-        size_t length;
-};
-
-static void xioctl(int fh, int request, void *arg)
-{
-        int r;
-
-        do {
-                r = v4l2_ioctl(fh, request, arg);
-        } while (r == -1 &amp;&amp; ((errno == EINTR) || (errno == EAGAIN)));
-
-        if (r == -1) {
-                fprintf(stderr, "error %d, %s\n", errno, strerror(errno));
-                exit(EXIT_FAILURE);
-        }
-}
-
-int main(int argc, char **argv)
-{
-        struct <link linkend="v4l2-format">v4l2_format</link>              fmt;
-        struct <link linkend="v4l2-buffer">v4l2_buffer</link>              buf;
-        struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link>      req;
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>              type;
-        fd_set                          fds;
-        struct timeval                  tv;
-        int                             r, fd = -1;
-        unsigned int                    i, n_buffers;
-        char                            *dev_name = "/dev/video0";
-        char                            out_name[256];
-        FILE                            *fout;
-        struct buffer                   *buffers;
-
-        fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
-        if (fd &lt; 0) {
-                perror("Cannot open device");
-                exit(EXIT_FAILURE);
-        }
-
-        CLEAR(fmt);
-        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        fmt.fmt.pix.width       = 640;
-        fmt.fmt.pix.height      = 480;
-        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
-        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
-        xioctl(fd, VIDIOC_S_FMT, &amp;fmt);
-        if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24) {
-                printf("Libv4l didn't accept RGB24 format. Can't proceed.\n");
-                exit(EXIT_FAILURE);
-        }
-        if ((fmt.fmt.pix.width != 640) || (fmt.fmt.pix.height != 480))
-                printf("Warning: driver is sending image at %dx%d\n",
-                        fmt.fmt.pix.width, fmt.fmt.pix.height);
-
-        CLEAR(req);
-        req.count = 2;
-        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        req.memory = V4L2_MEMORY_MMAP;
-        xioctl(fd, VIDIOC_REQBUFS, &amp;req);
-
-        buffers = calloc(req.count, sizeof(*buffers));
-        for (n_buffers = 0; n_buffers &lt; req.count; ++n_buffers) {
-                CLEAR(buf);
-
-                buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory      = V4L2_MEMORY_MMAP;
-                buf.index       = n_buffers;
-
-                xioctl(fd, VIDIOC_QUERYBUF, &amp;buf);
-
-                buffers[n_buffers].length = buf.length;
-                buffers[n_buffers].start = v4l2_mmap(NULL, buf.length,
-                              PROT_READ | PROT_WRITE, MAP_SHARED,
-                              fd, buf.m.offset);
-
-                if (MAP_FAILED == buffers[n_buffers].start) {
-                        perror("mmap");
-                        exit(EXIT_FAILURE);
-                }
-        }
-
-        for (i = 0; i &lt; n_buffers; ++i) {
-                CLEAR(buf);
-                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory = V4L2_MEMORY_MMAP;
-                buf.index = i;
-                xioctl(fd, VIDIOC_QBUF, &amp;buf);
-        }
-        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-        xioctl(fd, VIDIOC_STREAMON, &amp;type);
-        for (i = 0; i &lt; 20; i++) {
-                do {
-                        FD_ZERO(&amp;fds);
-                        FD_SET(fd, &amp;fds);
-
-                        /* Timeout. */
-                        tv.tv_sec = 2;
-                        tv.tv_usec = 0;
-
-                        r = select(fd + 1, &amp;fds, NULL, NULL, &amp;tv);
-                } while ((r == -1 &amp;&amp; (errno = EINTR)));
-                if (r == -1) {
-                        perror("select");
-                        return errno;
-                }
-
-                CLEAR(buf);
-                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                buf.memory = V4L2_MEMORY_MMAP;
-                xioctl(fd, VIDIOC_DQBUF, &amp;buf);
-
-                sprintf(out_name, "out%03d.ppm", i);
-                fout = fopen(out_name, "w");
-                if (!fout) {
-                        perror("Cannot open image");
-                        exit(EXIT_FAILURE);
-                }
-                fprintf(fout, "P6\n%d %d 255\n",
-                        fmt.fmt.pix.width, fmt.fmt.pix.height);
-                fwrite(buffers[buf.index].start, buf.bytesused, 1, fout);
-                fclose(fout);
-
-                xioctl(fd, VIDIOC_QBUF, &amp;buf);
-        }
-
-        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-        xioctl(fd, VIDIOC_STREAMOFF, &amp;type);
-        for (i = 0; i &lt; n_buffers; ++i)
-                v4l2_munmap(buffers[i].start, buffers[i].length);
-        v4l2_close(fd);
-
-        return 0;
-}
-</programlisting>
diff --git a/Documentation/DocBook/v4l/vbi_525.gif b/Documentation/DocBook/v4l/vbi_525.gif
deleted file mode 100644 (file)
index 5580b69..0000000
Binary files a/Documentation/DocBook/v4l/vbi_525.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/vbi_525.pdf b/Documentation/DocBook/v4l/vbi_525.pdf
deleted file mode 100644 (file)
index 9e72c25..0000000
Binary files a/Documentation/DocBook/v4l/vbi_525.pdf and /dev/null differ
diff --git a/Documentation/DocBook/v4l/vbi_625.gif b/Documentation/DocBook/v4l/vbi_625.gif
deleted file mode 100644 (file)
index 34e3251..0000000
Binary files a/Documentation/DocBook/v4l/vbi_625.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/vbi_625.pdf b/Documentation/DocBook/v4l/vbi_625.pdf
deleted file mode 100644 (file)
index 765235e..0000000
Binary files a/Documentation/DocBook/v4l/vbi_625.pdf and /dev/null differ
diff --git a/Documentation/DocBook/v4l/vbi_hsync.gif b/Documentation/DocBook/v4l/vbi_hsync.gif
deleted file mode 100644 (file)
index b02434d..0000000
Binary files a/Documentation/DocBook/v4l/vbi_hsync.gif and /dev/null differ
diff --git a/Documentation/DocBook/v4l/vbi_hsync.pdf b/Documentation/DocBook/v4l/vbi_hsync.pdf
deleted file mode 100644 (file)
index 200b668..0000000
Binary files a/Documentation/DocBook/v4l/vbi_hsync.pdf and /dev/null differ
diff --git a/Documentation/DocBook/v4l/videodev2.h.xml b/Documentation/DocBook/v4l/videodev2.h.xml
deleted file mode 100644 (file)
index c50536a..0000000
+++ /dev/null
@@ -1,1946 +0,0 @@
-<programlisting>
-/*
- *  Video for Linux Two header file
- *
- *  Copyright (C) 1999-2007 the contributors
- *
- *  This 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.
- *
- *  Alternatively you can redistribute this file under the terms of the
- *  BSD license as stated below:
- *
- *  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 names of its contributors may not be used to endorse or promote
- *     products derived from this software without specific prior written
- *     permission.
- *
- *  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.
- *
- *      Header file for v4l or V4L2 drivers and applications
- * with public API.
- * All kernel-specific stuff were moved to media/v4l2-dev.h, so
- * no #if __KERNEL tests are allowed here
- *
- *      See http://linuxtv.org for more info
- *
- *      Author: Bill Dirks &lt;bill@thedirks.org&gt;
- *              Justin Schoeman
- *              Hans Verkuil &lt;hverkuil@xs4all.nl&gt;
- *              et al.
- */
-#ifndef __LINUX_VIDEODEV2_H
-#define __LINUX_VIDEODEV2_H
-
-#ifdef __KERNEL__
-#include &lt;linux/time.h&gt;     /* need struct timeval */
-#else
-#include &lt;sys/time.h&gt;
-#endif
-#include &lt;linux/compiler.h&gt;
-#include &lt;linux/ioctl.h&gt;
-#include &lt;linux/types.h&gt;
-
-/*
- * Common stuff for both V4L1 and V4L2
- * Moved from videodev.h
- */
-#define VIDEO_MAX_FRAME               32
-#define VIDEO_MAX_PLANES               8
-
-#ifndef __KERNEL__
-
-/* These defines are V4L1 specific and should not be used with the V4L2 API!
-   They will be removed from this header in the future. */
-
-#define VID_TYPE_CAPTURE        1       /* Can capture */
-#define VID_TYPE_TUNER          2       /* Can tune */
-#define VID_TYPE_TELETEXT       4       /* Does teletext */
-#define VID_TYPE_OVERLAY        8       /* Overlay onto frame buffer */
-#define VID_TYPE_CHROMAKEY      16      /* Overlay by chromakey */
-#define VID_TYPE_CLIPPING       32      /* Can clip */
-#define VID_TYPE_FRAMERAM       64      /* Uses the frame buffer memory */
-#define VID_TYPE_SCALES         128     /* Scalable */
-#define VID_TYPE_MONOCHROME     256     /* Monochrome only */
-#define VID_TYPE_SUBCAPTURE     512     /* Can capture subareas of the image */
-#define VID_TYPE_MPEG_DECODER   1024    /* Can decode MPEG streams */
-#define VID_TYPE_MPEG_ENCODER   2048    /* Can encode MPEG streams */
-#define VID_TYPE_MJPEG_DECODER  4096    /* Can decode MJPEG streams */
-#define VID_TYPE_MJPEG_ENCODER  8192    /* Can encode MJPEG streams */
-#endif
-
-/*
- *      M I S C E L L A N E O U S
- */
-
-/*  Four-character-code (FOURCC) */
-#define v4l2_fourcc(a, b, c, d)\
-        ((__u32)(a) | ((__u32)(b) &lt;&lt; 8) | ((__u32)(c) &lt;&lt; 16) | ((__u32)(d) &lt;&lt; 24))
-
-/*
- *      E N U M S
- */
-enum <link linkend="v4l2-field">v4l2_field</link> {
-        V4L2_FIELD_ANY           = 0, /* driver can choose from none,
-                                         top, bottom, interlaced
-                                         depending on whatever it thinks
-                                         is approximate ... */
-        V4L2_FIELD_NONE          = 1, /* this device has no fields ... */
-        V4L2_FIELD_TOP           = 2, /* top field only */
-        V4L2_FIELD_BOTTOM        = 3, /* bottom field only */
-        V4L2_FIELD_INTERLACED    = 4, /* both fields interlaced */
-        V4L2_FIELD_SEQ_TB        = 5, /* both fields sequential into one
-                                         buffer, top-bottom order */
-        V4L2_FIELD_SEQ_BT        = 6, /* same as above + bottom-top order */
-        V4L2_FIELD_ALTERNATE     = 7, /* both fields alternating into
-                                         separate buffers */
-        V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field
-                                         first and the top field is
-                                         transmitted first */
-        V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field
-                                         first and the bottom field is
-                                         transmitted first */
-};
-#define V4L2_FIELD_HAS_TOP(field)       \
-        ((field) == V4L2_FIELD_TOP      ||\
-         (field) == V4L2_FIELD_INTERLACED ||\
-         (field) == V4L2_FIELD_INTERLACED_TB ||\
-         (field) == V4L2_FIELD_INTERLACED_BT ||\
-         (field) == V4L2_FIELD_SEQ_TB   ||\
-         (field) == V4L2_FIELD_SEQ_BT)
-#define V4L2_FIELD_HAS_BOTTOM(field)    \
-        ((field) == V4L2_FIELD_BOTTOM   ||\
-         (field) == V4L2_FIELD_INTERLACED ||\
-         (field) == V4L2_FIELD_INTERLACED_TB ||\
-         (field) == V4L2_FIELD_INTERLACED_BT ||\
-         (field) == V4L2_FIELD_SEQ_TB   ||\
-         (field) == V4L2_FIELD_SEQ_BT)
-#define V4L2_FIELD_HAS_BOTH(field)      \
-        ((field) == V4L2_FIELD_INTERLACED ||\
-         (field) == V4L2_FIELD_INTERLACED_TB ||\
-         (field) == V4L2_FIELD_INTERLACED_BT ||\
-         (field) == V4L2_FIELD_SEQ_TB ||\
-         (field) == V4L2_FIELD_SEQ_BT)
-
-enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> {
-        V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1,
-        V4L2_BUF_TYPE_VIDEO_OUTPUT         = 2,
-        V4L2_BUF_TYPE_VIDEO_OVERLAY        = 3,
-        V4L2_BUF_TYPE_VBI_CAPTURE          = 4,
-        V4L2_BUF_TYPE_VBI_OUTPUT           = 5,
-        V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,
-        V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,
-#if 1
-        /* Experimental */
-        V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
-#endif
-        V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
-        V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 10,
-        V4L2_BUF_TYPE_PRIVATE              = 0x80,
-};
-
-#define V4L2_TYPE_IS_MULTIPLANAR(type)                  \
-        ((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE   \
-         || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-
-#define V4L2_TYPE_IS_OUTPUT(type)                               \
-        ((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT                   \
-         || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE         \
-         || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY               \
-         || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY        \
-         || (type) == V4L2_BUF_TYPE_VBI_OUTPUT                  \
-         || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
-
-enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link> {
-        V4L2_TUNER_RADIO             = 1,
-        V4L2_TUNER_ANALOG_TV         = 2,
-        V4L2_TUNER_DIGITAL_TV        = 3,
-};
-
-enum <link linkend="v4l2-memory">v4l2_memory</link> {
-        V4L2_MEMORY_MMAP             = 1,
-        V4L2_MEMORY_USERPTR          = 2,
-        V4L2_MEMORY_OVERLAY          = 3,
-};
-
-/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
-enum <link linkend="v4l2-colorspace">v4l2_colorspace</link> {
-        /* ITU-R 601 -- broadcast NTSC/PAL */
-        V4L2_COLORSPACE_SMPTE170M     = 1,
-
-        /* 1125-Line (US) HDTV */
-        V4L2_COLORSPACE_SMPTE240M     = 2,
-
-        /* HD and modern captures. */
-        V4L2_COLORSPACE_REC709        = 3,
-
-        /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */
-        V4L2_COLORSPACE_BT878         = 4,
-
-        /* These should be useful.  Assume 601 extents. */
-        V4L2_COLORSPACE_470_SYSTEM_M  = 5,
-        V4L2_COLORSPACE_470_SYSTEM_BG = 6,
-
-        /* I know there will be cameras that send this.  So, this is
-         * unspecified chromaticities and full 0-255 on each of the
-         * Y'CbCr components
-         */
-        V4L2_COLORSPACE_JPEG          = 7,
-
-        /* For RGB colourspaces, this is probably a good start. */
-        V4L2_COLORSPACE_SRGB          = 8,
-};
-
-enum <link linkend="v4l2-priority">v4l2_priority</link> {
-        V4L2_PRIORITY_UNSET       = 0,  /* not initialized */
-        V4L2_PRIORITY_BACKGROUND  = 1,
-        V4L2_PRIORITY_INTERACTIVE = 2,
-        V4L2_PRIORITY_RECORD      = 3,
-        V4L2_PRIORITY_DEFAULT     = V4L2_PRIORITY_INTERACTIVE,
-};
-
-struct <link linkend="v4l2-rect">v4l2_rect</link> {
-        __s32   left;
-        __s32   top;
-        __s32   width;
-        __s32   height;
-};
-
-struct <link linkend="v4l2-fract">v4l2_fract</link> {
-        __u32   numerator;
-        __u32   denominator;
-};
-
-/*
- *      D R I V E R   C A P A B I L I T I E S
- */
-struct <link linkend="v4l2-capability">v4l2_capability</link> {
-        __u8    driver[16];     /* i.e.ie; "bttv" */
-        __u8    card[32];       /* i.e.ie; "Hauppauge WinTV" */
-        __u8    bus_info[32];   /* "PCI:" + pci_name(pci_dev) */
-        __u32   version;        /* should use KERNEL_VERSION() */
-        __u32   capabilities;   /* Device capabilities */
-        __u32   reserved[4];
-};
-
-/* Values for 'capabilities' field */
-#define V4L2_CAP_VIDEO_CAPTURE          0x00000001  /* Is a video capture device */
-#define V4L2_CAP_VIDEO_OUTPUT           0x00000002  /* Is a video output device */
-#define V4L2_CAP_VIDEO_OVERLAY          0x00000004  /* Can do video overlay */
-#define V4L2_CAP_VBI_CAPTURE            0x00000010  /* Is a raw VBI capture device */
-#define V4L2_CAP_VBI_OUTPUT             0x00000020  /* Is a raw VBI output device */
-#define V4L2_CAP_SLICED_VBI_CAPTURE     0x00000040  /* Is a sliced VBI capture device */
-#define V4L2_CAP_SLICED_VBI_OUTPUT      0x00000080  /* Is a sliced VBI output device */
-#define V4L2_CAP_RDS_CAPTURE            0x00000100  /* RDS data capture */
-#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY   0x00000200  /* Can do video output overlay */
-#define V4L2_CAP_HW_FREQ_SEEK           0x00000400  /* Can do hardware frequency seek  */
-#define V4L2_CAP_RDS_OUTPUT             0x00000800  /* Is an RDS encoder */
-
-/* Is a video capture device that supports multiplanar formats */
-#define V4L2_CAP_VIDEO_CAPTURE_MPLANE   0x00001000
-/* Is a video output device that supports multiplanar formats */
-#define V4L2_CAP_VIDEO_OUTPUT_MPLANE    0x00002000
-
-#define V4L2_CAP_TUNER                  0x00010000  /* has a tuner */
-#define V4L2_CAP_AUDIO                  0x00020000  /* has audio support */
-#define V4L2_CAP_RADIO                  0x00040000  /* is a radio device */
-#define V4L2_CAP_MODULATOR              0x00080000  /* has a modulator */
-
-#define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
-#define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
-#define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
-
-/*
- *      V I D E O   I M A G E   F O R M A T
- */
-struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
-        __u32                   width;
-        __u32                   height;
-        __u32                   pixelformat;
-        enum <link linkend="v4l2-field">v4l2_field</link>         field;
-        __u32                   bytesperline;   /* for padding, zero if unused */
-        __u32                   sizeimage;
-        enum <link linkend="v4l2-colorspace">v4l2_colorspace</link>    colorspace;
-        __u32                   priv;           /* private data, depends on pixelformat */
-};
-
-/*      Pixel format         FOURCC                          depth  Description  */
-
-/* RGB formats */
-#define <link linkend="V4L2-PIX-FMT-RGB332">V4L2_PIX_FMT_RGB332</link>  v4l2_fourcc('R', 'G', 'B', '1') /*  8  RGB-3-3-2     */
-#define <link linkend="V4L2-PIX-FMT-RGB444">V4L2_PIX_FMT_RGB444</link>  v4l2_fourcc('R', '4', '4', '4') /* 16  xxxxrrrr ggggbbbb */
-#define <link linkend="V4L2-PIX-FMT-RGB555">V4L2_PIX_FMT_RGB555</link>  v4l2_fourcc('R', 'G', 'B', 'O') /* 16  RGB-5-5-5     */
-#define <link linkend="V4L2-PIX-FMT-RGB565">V4L2_PIX_FMT_RGB565</link>  v4l2_fourcc('R', 'G', 'B', 'P') /* 16  RGB-5-6-5     */
-#define <link linkend="V4L2-PIX-FMT-RGB555X">V4L2_PIX_FMT_RGB555X</link> v4l2_fourcc('R', 'G', 'B', 'Q') /* 16  RGB-5-5-5 BE  */
-#define <link linkend="V4L2-PIX-FMT-RGB565X">V4L2_PIX_FMT_RGB565X</link> v4l2_fourcc('R', 'G', 'B', 'R') /* 16  RGB-5-6-5 BE  */
-#define <link linkend="V4L2-PIX-FMT-BGR666">V4L2_PIX_FMT_BGR666</link>  v4l2_fourcc('B', 'G', 'R', 'H') /* 18  BGR-6-6-6     */
-#define <link linkend="V4L2-PIX-FMT-BGR24">V4L2_PIX_FMT_BGR24</link>   v4l2_fourcc('B', 'G', 'R', '3') /* 24  BGR-8-8-8     */
-#define <link linkend="V4L2-PIX-FMT-RGB24">V4L2_PIX_FMT_RGB24</link>   v4l2_fourcc('R', 'G', 'B', '3') /* 24  RGB-8-8-8     */
-#define <link linkend="V4L2-PIX-FMT-BGR32">V4L2_PIX_FMT_BGR32</link>   v4l2_fourcc('B', 'G', 'R', '4') /* 32  BGR-8-8-8-8   */
-#define <link linkend="V4L2-PIX-FMT-RGB32">V4L2_PIX_FMT_RGB32</link>   v4l2_fourcc('R', 'G', 'B', '4') /* 32  RGB-8-8-8-8   */
-
-/* Grey formats */
-#define <link linkend="V4L2-PIX-FMT-GREY">V4L2_PIX_FMT_GREY</link>    v4l2_fourcc('G', 'R', 'E', 'Y') /*  8  Greyscale     */
-#define <link linkend="V4L2-PIX-FMT-Y4">V4L2_PIX_FMT_Y4</link>      v4l2_fourcc('Y', '0', '4', ' ') /*  4  Greyscale     */
-#define <link linkend="V4L2-PIX-FMT-Y6">V4L2_PIX_FMT_Y6</link>      v4l2_fourcc('Y', '0', '6', ' ') /*  6  Greyscale     */
-#define <link linkend="V4L2-PIX-FMT-Y10">V4L2_PIX_FMT_Y10</link>     v4l2_fourcc('Y', '1', '0', ' ') /* 10  Greyscale     */
-#define <link linkend="V4L2-PIX-FMT-Y16">V4L2_PIX_FMT_Y16</link>     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
-
-/* Grey bit-packed formats */
-#define <link linkend="V4L2-PIX-FMT-Y10BPACK">V4L2_PIX_FMT_Y10BPACK</link>    v4l2_fourcc('Y', '1', '0', 'B') /* 10  Greyscale bit-packed */
-
-/* Palette formats */
-#define <link linkend="V4L2-PIX-FMT-PAL8">V4L2_PIX_FMT_PAL8</link>    v4l2_fourcc('P', 'A', 'L', '8') /*  8  8-bit palette */
-
-/* Luminance+Chrominance formats */
-#define <link linkend="V4L2-PIX-FMT-YVU410">V4L2_PIX_FMT_YVU410</link>  v4l2_fourcc('Y', 'V', 'U', '9') /*  9  YVU 4:1:0     */
-#define <link linkend="V4L2-PIX-FMT-YVU420">V4L2_PIX_FMT_YVU420</link>  v4l2_fourcc('Y', 'V', '1', '2') /* 12  YVU 4:2:0     */
-#define <link linkend="V4L2-PIX-FMT-YUYV">V4L2_PIX_FMT_YUYV</link>    v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16  YUV 4:2:2     */
-#define <link linkend="V4L2-PIX-FMT-YYUV">V4L2_PIX_FMT_YYUV</link>    v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16  YUV 4:2:2     */
-#define <link linkend="V4L2-PIX-FMT-YVYU">V4L2_PIX_FMT_YVYU</link>    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
-#define <link linkend="V4L2-PIX-FMT-UYVY">V4L2_PIX_FMT_UYVY</link>    v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16  YUV 4:2:2     */
-#define <link linkend="V4L2-PIX-FMT-VYUY">V4L2_PIX_FMT_VYUY</link>    v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16  YUV 4:2:2     */
-#define <link linkend="V4L2-PIX-FMT-YUV422P">V4L2_PIX_FMT_YUV422P</link> v4l2_fourcc('4', '2', '2', 'P') /* 16  YVU422 planar */
-#define <link linkend="V4L2-PIX-FMT-YUV411P">V4L2_PIX_FMT_YUV411P</link> v4l2_fourcc('4', '1', '1', 'P') /* 16  YVU411 planar */
-#define <link linkend="V4L2-PIX-FMT-Y41P">V4L2_PIX_FMT_Y41P</link>    v4l2_fourcc('Y', '4', '1', 'P') /* 12  YUV 4:1:1     */
-#define <link linkend="V4L2-PIX-FMT-YUV444">V4L2_PIX_FMT_YUV444</link>  v4l2_fourcc('Y', '4', '4', '4') /* 16  xxxxyyyy uuuuvvvv */
-#define <link linkend="V4L2-PIX-FMT-YUV555">V4L2_PIX_FMT_YUV555</link>  v4l2_fourcc('Y', 'U', 'V', 'O') /* 16  YUV-5-5-5     */
-#define <link linkend="V4L2-PIX-FMT-YUV565">V4L2_PIX_FMT_YUV565</link>  v4l2_fourcc('Y', 'U', 'V', 'P') /* 16  YUV-5-6-5     */
-#define <link linkend="V4L2-PIX-FMT-YUV32">V4L2_PIX_FMT_YUV32</link>   v4l2_fourcc('Y', 'U', 'V', '4') /* 32  YUV-8-8-8-8   */
-#define <link linkend="V4L2-PIX-FMT-YUV410">V4L2_PIX_FMT_YUV410</link>  v4l2_fourcc('Y', 'U', 'V', '9') /*  9  YUV 4:1:0     */
-#define <link linkend="V4L2-PIX-FMT-YUV420">V4L2_PIX_FMT_YUV420</link>  v4l2_fourcc('Y', 'U', '1', '2') /* 12  YUV 4:2:0     */
-#define <link linkend="V4L2-PIX-FMT-HI240">V4L2_PIX_FMT_HI240</link>   v4l2_fourcc('H', 'I', '2', '4') /*  8  8-bit color   */
-#define <link linkend="V4L2-PIX-FMT-HM12">V4L2_PIX_FMT_HM12</link>    v4l2_fourcc('H', 'M', '1', '2') /*  8  YUV 4:2:0 16x16 macroblocks */
-#define <link linkend="V4L2-PIX-FMT-M420">V4L2_PIX_FMT_M420</link>    v4l2_fourcc('M', '4', '2', '0') /* 12  YUV 4:2:0 2 lines y, 1 line uv interleaved */
-
-/* two planes -- one Y, one Cr + Cb interleaved  */
-#define <link linkend="V4L2-PIX-FMT-NV12">V4L2_PIX_FMT_NV12</link>    v4l2_fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 4:2:0  */
-#define <link linkend="V4L2-PIX-FMT-NV21">V4L2_PIX_FMT_NV21</link>    v4l2_fourcc('N', 'V', '2', '1') /* 12  Y/CrCb 4:2:0  */
-#define <link linkend="V4L2-PIX-FMT-NV16">V4L2_PIX_FMT_NV16</link>    v4l2_fourcc('N', 'V', '1', '6') /* 16  Y/CbCr 4:2:2  */
-#define <link linkend="V4L2-PIX-FMT-NV61">V4L2_PIX_FMT_NV61</link>    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 4:2:2  */
-
-/* two non contiguous planes - one Y, one Cr + Cb interleaved  */
-#define <link linkend="V4L2-PIX-FMT-NV12M">V4L2_PIX_FMT_NV12M</link>   v4l2_fourcc('N', 'M', '1', '2') /* 12  Y/CbCr 4:2:0  */
-#define <link linkend="V4L2-PIX-FMT-NV12MT">V4L2_PIX_FMT_NV12MT</link>  v4l2_fourcc('T', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 64x32 macroblocks */
-
-/* three non contiguous planes - Y, Cb, Cr */
-#define <link linkend="V4L2-PIX-FMT-YUV420M">V4L2_PIX_FMT_YUV420M</link> v4l2_fourcc('Y', 'M', '1', '2') /* 12  YUV420 planar */
-
-/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
-#define <link linkend="V4L2-PIX-FMT-SBGGR8">V4L2_PIX_FMT_SBGGR8</link>  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
-#define <link linkend="V4L2-PIX-FMT-SGBRG8">V4L2_PIX_FMT_SGBRG8</link>  v4l2_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
-#define <link linkend="V4L2-PIX-FMT-SGRBG8">V4L2_PIX_FMT_SGRBG8</link>  v4l2_fourcc('G', 'R', 'B', 'G') /*  8  GRGR.. BGBG.. */
-#define <link linkend="V4L2-PIX-FMT-SRGGB8">V4L2_PIX_FMT_SRGGB8</link>  v4l2_fourcc('R', 'G', 'G', 'B') /*  8  RGRG.. GBGB.. */
-#define <link linkend="V4L2-PIX-FMT-SBGGR10">V4L2_PIX_FMT_SBGGR10</link> v4l2_fourcc('B', 'G', '1', '0') /* 10  BGBG.. GRGR.. */
-#define <link linkend="V4L2-PIX-FMT-SGBRG10">V4L2_PIX_FMT_SGBRG10</link> v4l2_fourcc('G', 'B', '1', '0') /* 10  GBGB.. RGRG.. */
-#define <link linkend="V4L2-PIX-FMT-SGRBG10">V4L2_PIX_FMT_SGRBG10</link> v4l2_fourcc('B', 'A', '1', '0') /* 10  GRGR.. BGBG.. */
-#define <link linkend="V4L2-PIX-FMT-SRGGB10">V4L2_PIX_FMT_SRGGB10</link> v4l2_fourcc('R', 'G', '1', '0') /* 10  RGRG.. GBGB.. */
-        /* 10bit raw bayer DPCM compressed to 8 bits */
-#define <link linkend="V4L2-PIX-FMT-SGRBG10DPCM8">V4L2_PIX_FMT_SGRBG10DPCM8</link> v4l2_fourcc('B', 'D', '1', '0')
-        /*
-         * 10bit raw bayer, expanded to 16 bits
-         * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
-         */
-#define <link linkend="V4L2-PIX-FMT-SBGGR16">V4L2_PIX_FMT_SBGGR16</link> v4l2_fourcc('B', 'Y', 'R', '2') /* 16  BGBG.. GRGR.. */
-
-/* compressed formats */
-#define <link linkend="V4L2-PIX-FMT-MJPEG">V4L2_PIX_FMT_MJPEG</link>    v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG   */
-#define <link linkend="V4L2-PIX-FMT-JPEG">V4L2_PIX_FMT_JPEG</link>     v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG     */
-#define <link linkend="V4L2-PIX-FMT-DV">V4L2_PIX_FMT_DV</link>       v4l2_fourcc('d', 'v', 's', 'd') /* 1394          */
-#define <link linkend="V4L2-PIX-FMT-MPEG">V4L2_PIX_FMT_MPEG</link>     v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4    */
-
-/*  Vendor-specific formats   */
-#define <link linkend="V4L2-PIX-FMT-CPIA1">V4L2_PIX_FMT_CPIA1</link>    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
-#define <link linkend="V4L2-PIX-FMT-WNVA">V4L2_PIX_FMT_WNVA</link>     v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */
-#define <link linkend="V4L2-PIX-FMT-SN9C10X">V4L2_PIX_FMT_SN9C10X</link>  v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */
-#define <link linkend="V4L2-PIX-FMT-SN9C20X-I420">V4L2_PIX_FMT_SN9C20X_I420</link> v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */
-#define <link linkend="V4L2-PIX-FMT-PWC1">V4L2_PIX_FMT_PWC1</link>     v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */
-#define <link linkend="V4L2-PIX-FMT-PWC2">V4L2_PIX_FMT_PWC2</link>     v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */
-#define <link linkend="V4L2-PIX-FMT-ET61X251">V4L2_PIX_FMT_ET61X251</link> v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */
-#define <link linkend="V4L2-PIX-FMT-SPCA501">V4L2_PIX_FMT_SPCA501</link>  v4l2_fourcc('S', '5', '0', '1') /* YUYV per line */
-#define <link linkend="V4L2-PIX-FMT-SPCA505">V4L2_PIX_FMT_SPCA505</link>  v4l2_fourcc('S', '5', '0', '5') /* YYUV per line */
-#define <link linkend="V4L2-PIX-FMT-SPCA508">V4L2_PIX_FMT_SPCA508</link>  v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */
-#define <link linkend="V4L2-PIX-FMT-SPCA561">V4L2_PIX_FMT_SPCA561</link>  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
-#define <link linkend="V4L2-PIX-FMT-PAC207">V4L2_PIX_FMT_PAC207</link>   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
-#define <link linkend="V4L2-PIX-FMT-MR97310A">V4L2_PIX_FMT_MR97310A</link> v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
-#define <link linkend="V4L2-PIX-FMT-SN9C2028">V4L2_PIX_FMT_SN9C2028</link> v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */
-#define <link linkend="V4L2-PIX-FMT-SQ905C">V4L2_PIX_FMT_SQ905C</link>   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
-#define <link linkend="V4L2-PIX-FMT-PJPG">V4L2_PIX_FMT_PJPG</link>     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
-#define <link linkend="V4L2-PIX-FMT-OV511">V4L2_PIX_FMT_OV511</link>    v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
-#define <link linkend="V4L2-PIX-FMT-OV518">V4L2_PIX_FMT_OV518</link>    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
-#define <link linkend="V4L2-PIX-FMT-STV0680">V4L2_PIX_FMT_STV0680</link>  v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
-#define <link linkend="V4L2-PIX-FMT-TM6000">V4L2_PIX_FMT_TM6000</link>   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
-#define <link linkend="V4L2-PIX-FMT-CIT-YYVYUY">V4L2_PIX_FMT_CIT_YYVYUY</link> v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
-#define <link linkend="V4L2-PIX-FMT-KONICA420">V4L2_PIX_FMT_KONICA420</link>  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
-
-/*
- *      F O R M A T   E N U M E R A T I O N
- */
-struct <link linkend="v4l2-fmtdesc">v4l2_fmtdesc</link> {
-        __u32               index;             /* Format number      */
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>  type;              /* buffer type        */
-        __u32               flags;
-        __u8                description[32];   /* Description string */
-        __u32               pixelformat;       /* Format fourcc      */
-        __u32               reserved[4];
-};
-
-#define V4L2_FMT_FLAG_COMPRESSED 0x0001
-#define V4L2_FMT_FLAG_EMULATED   0x0002
-
-#if 1
-        /* Experimental Frame Size and frame rate enumeration */
-/*
- *      F R A M E   S I Z E   E N U M E R A T I O N
- */
-enum <link linkend="v4l2-frmsizetypes">v4l2_frmsizetypes</link> {
-        V4L2_FRMSIZE_TYPE_DISCRETE      = 1,
-        V4L2_FRMSIZE_TYPE_CONTINUOUS    = 2,
-        V4L2_FRMSIZE_TYPE_STEPWISE      = 3,
-};
-
-struct <link linkend="v4l2-frmsize-discrete">v4l2_frmsize_discrete</link> {
-        __u32                   width;          /* Frame width [pixel] */
-        __u32                   height;         /* Frame height [pixel] */
-};
-
-struct <link linkend="v4l2-frmsize-stepwise">v4l2_frmsize_stepwise</link> {
-        __u32                   min_width;      /* Minimum frame width [pixel] */
-        __u32                   max_width;      /* Maximum frame width [pixel] */
-        __u32                   step_width;     /* Frame width step size [pixel] */
-        __u32                   min_height;     /* Minimum frame height [pixel] */
-        __u32                   max_height;     /* Maximum frame height [pixel] */
-        __u32                   step_height;    /* Frame height step size [pixel] */
-};
-
-struct <link linkend="v4l2-frmsizeenum">v4l2_frmsizeenum</link> {
-        __u32                   index;          /* Frame size number */
-        __u32                   pixel_format;   /* Pixel format */
-        __u32                   type;           /* Frame size type the device supports. */
-
-        union {                                 /* Frame size */
-                struct <link linkend="v4l2-frmsize-discrete">v4l2_frmsize_discrete</link>    discrete;
-                struct <link linkend="v4l2-frmsize-stepwise">v4l2_frmsize_stepwise</link>    stepwise;
-        };
-
-        __u32   reserved[2];                    /* Reserved space for future use */
-};
-
-/*
- *      F R A M E   R A T E   E N U M E R A T I O N
- */
-enum <link linkend="v4l2-frmivaltypes">v4l2_frmivaltypes</link> {
-        V4L2_FRMIVAL_TYPE_DISCRETE      = 1,
-        V4L2_FRMIVAL_TYPE_CONTINUOUS    = 2,
-        V4L2_FRMIVAL_TYPE_STEPWISE      = 3,
-};
-
-struct <link linkend="v4l2-frmival-stepwise">v4l2_frmival_stepwise</link> {
-        struct <link linkend="v4l2-fract">v4l2_fract</link>       min;            /* Minimum frame interval [s] */
-        struct <link linkend="v4l2-fract">v4l2_fract</link>       max;            /* Maximum frame interval [s] */
-        struct <link linkend="v4l2-fract">v4l2_fract</link>       step;           /* Frame interval step size [s] */
-};
-
-struct <link linkend="v4l2-frmivalenum">v4l2_frmivalenum</link> {
-        __u32                   index;          /* Frame format index */
-        __u32                   pixel_format;   /* Pixel format */
-        __u32                   width;          /* Frame width */
-        __u32                   height;         /* Frame height */
-        __u32                   type;           /* Frame interval type the device supports. */
-
-        union {                                 /* Frame interval */
-                struct <link linkend="v4l2-fract">v4l2_fract</link>               discrete;
-                struct <link linkend="v4l2-frmival-stepwise">v4l2_frmival_stepwise</link>    stepwise;
-        };
-
-        __u32   reserved[2];                    /* Reserved space for future use */
-};
-#endif
-
-/*
- *      T I M E C O D E
- */
-struct <link linkend="v4l2-timecode">v4l2_timecode</link> {
-        __u32   type;
-        __u32   flags;
-        __u8    frames;
-        __u8    seconds;
-        __u8    minutes;
-        __u8    hours;
-        __u8    userbits[4];
-};
-
-/*  Type  */
-#define V4L2_TC_TYPE_24FPS              1
-#define V4L2_TC_TYPE_25FPS              2
-#define V4L2_TC_TYPE_30FPS              3
-#define V4L2_TC_TYPE_50FPS              4
-#define V4L2_TC_TYPE_60FPS              5
-
-/*  Flags  */
-#define V4L2_TC_FLAG_DROPFRAME          0x0001 /* "drop-frame" mode */
-#define V4L2_TC_FLAG_COLORFRAME         0x0002
-#define V4L2_TC_USERBITS_field          0x000C
-#define V4L2_TC_USERBITS_USERDEFINED    0x0000
-#define V4L2_TC_USERBITS_8BITCHARS      0x0008
-/* The above is based on SMPTE timecodes */
-
-struct <link linkend="v4l2-jpegcompression">v4l2_jpegcompression</link> {
-        int quality;
-
-        int  APPn;              /* Number of APP segment to be written,
-                                 * must be 0..15 */
-        int  APP_len;           /* Length of data in JPEG APPn segment */
-        char APP_data[60];      /* Data in the JPEG APPn segment. */
-
-        int  COM_len;           /* Length of data in JPEG COM segment */
-        char COM_data[60];      /* Data in JPEG COM segment */
-
-        __u32 jpeg_markers;     /* Which markers should go into the JPEG
-                                 * output. Unless you exactly know what
-                                 * you do, leave them untouched.
-                                 * Inluding less markers will make the
-                                 * resulting code smaller, but there will
-                                 * be fewer applications which can read it.
-                                 * The presence of the APP and COM marker
-                                 * is influenced by APP_len and COM_len
-                                 * ONLY, not by this property! */
-
-#define V4L2_JPEG_MARKER_DHT (1&lt;&lt;3)    /* Define Huffman Tables */
-#define V4L2_JPEG_MARKER_DQT (1&lt;&lt;4)    /* Define Quantization Tables */
-#define V4L2_JPEG_MARKER_DRI (1&lt;&lt;5)    /* Define Restart Interval */
-#define V4L2_JPEG_MARKER_COM (1&lt;&lt;6)    /* Comment segment */
-#define V4L2_JPEG_MARKER_APP (1&lt;&lt;7)    /* App segment, driver will
-                                        * allways use APP0 */
-};
-
-/*
- *      M E M O R Y - M A P P I N G   B U F F E R S
- */
-struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link> {
-        __u32                   count;
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>      type;
-        enum <link linkend="v4l2-memory">v4l2_memory</link>        memory;
-        __u32                   reserved[2];
-};
-
-/**
- * struct <link linkend="v4l2-plane">v4l2_plane</link> - plane info for multi-planar buffers
- * @bytesused:          number of bytes occupied by data in the plane (payload)
- * @length:             size of this plane (NOT the payload) in bytes
- * @mem_offset:         when memory in the associated struct <link linkend="v4l2-buffer">v4l2_buffer</link> is
- *                      V4L2_MEMORY_MMAP, equals the offset from the start of
- *                      the device memory for this plane (or is a "cookie" that
- *                      should be passed to mmap() called on the video node)
- * @userptr:            when memory is V4L2_MEMORY_USERPTR, a userspace pointer
- *                      pointing to this plane
- * @data_offset:        offset in the plane to the start of data; usually 0,
- *                      unless there is a header in front of the data
- *
- * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
- * with two planes can have one plane for Y, and another for interleaved CbCr
- * components. Each plane can reside in a separate memory buffer, or even in
- * a completely separate memory node (e.g. in embedded devices).
- */
-struct <link linkend="v4l2-plane">v4l2_plane</link> {
-        __u32                   bytesused;
-        __u32                   length;
-        union {
-                __u32           mem_offset;
-                unsigned long   userptr;
-        } m;
-        __u32                   data_offset;
-        __u32                   reserved[11];
-};
-
-/**
- * struct <link linkend="v4l2-buffer">v4l2_buffer</link> - video buffer info
- * @index:      id number of the buffer
- * @type:       buffer type (type == *_MPLANE for multiplanar buffers)
- * @bytesused:  number of bytes occupied by data in the buffer (payload);
- *              unused (set to 0) for multiplanar buffers
- * @flags:      buffer informational flags
- * @field:      field order of the image in the buffer
- * @timestamp:  frame timestamp
- * @timecode:   frame timecode
- * @sequence:   sequence count of this frame
- * @memory:     the method, in which the actual video data is passed
- * @offset:     for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
- *              offset from the start of the device memory for this plane,
- *              (or a "cookie" that should be passed to mmap() as offset)
- * @userptr:    for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
- *              a userspace pointer pointing to this buffer
- * @planes:     for multiplanar buffers; userspace pointer to the array of plane
- *              info structs for this buffer
- * @length:     size in bytes of the buffer (NOT its payload) for single-plane
- *              buffers (when type != *_MPLANE); number of elements in the
- *              planes array for multi-plane buffers
- * @input:      input number from which the video data has has been captured
- *
- * Contains data exchanged by application and driver using one of the Streaming
- * I/O methods.
- */
-struct <link linkend="v4l2-buffer">v4l2_buffer</link> {
-        __u32                   index;
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>      type;
-        __u32                   bytesused;
-        __u32                   flags;
-        enum <link linkend="v4l2-field">v4l2_field</link>         field;
-        struct timeval          timestamp;
-        struct <link linkend="v4l2-timecode">v4l2_timecode</link>    timecode;
-        __u32                   sequence;
-
-        /* memory location */
-        enum <link linkend="v4l2-memory">v4l2_memory</link>        memory;
-        union {
-                __u32           offset;
-                unsigned long   userptr;
-                struct <link linkend="v4l2-plane">v4l2_plane</link> *planes;
-        } m;
-        __u32                   length;
-        __u32                   input;
-        __u32                   reserved;
-};
-
-/*  Flags for 'flags' field */
-#define V4L2_BUF_FLAG_MAPPED    0x0001  /* Buffer is mapped (flag) */
-#define V4L2_BUF_FLAG_QUEUED    0x0002  /* Buffer is queued for processing */
-#define V4L2_BUF_FLAG_DONE      0x0004  /* Buffer is ready */
-#define V4L2_BUF_FLAG_KEYFRAME  0x0008  /* Image is a keyframe (I-frame) */
-#define V4L2_BUF_FLAG_PFRAME    0x0010  /* Image is a P-frame */
-#define V4L2_BUF_FLAG_BFRAME    0x0020  /* Image is a B-frame */
-/* Buffer is ready, but the data contained within is corrupted. */
-#define V4L2_BUF_FLAG_ERROR     0x0040
-#define V4L2_BUF_FLAG_TIMECODE  0x0100  /* timecode field is valid */
-#define V4L2_BUF_FLAG_INPUT     0x0200  /* input field is valid */
-
-/*
- *      O V E R L A Y   P R E V I E W
- */
-struct <link linkend="v4l2-framebuffer">v4l2_framebuffer</link> {
-        __u32                   capability;
-        __u32                   flags;
-/* FIXME: in theory we should pass something like PCI device + memory
- * region + offset instead of some physical address */
-        void                    *base;
-        struct <link linkend="v4l2-pix-format">v4l2_pix_format</link>  fmt;
-};
-/*  Flags for the 'capability' field. Read only */
-#define V4L2_FBUF_CAP_EXTERNOVERLAY     0x0001
-#define V4L2_FBUF_CAP_CHROMAKEY         0x0002
-#define V4L2_FBUF_CAP_LIST_CLIPPING     0x0004
-#define V4L2_FBUF_CAP_BITMAP_CLIPPING   0x0008
-#define V4L2_FBUF_CAP_LOCAL_ALPHA       0x0010
-#define V4L2_FBUF_CAP_GLOBAL_ALPHA      0x0020
-#define V4L2_FBUF_CAP_LOCAL_INV_ALPHA   0x0040
-#define V4L2_FBUF_CAP_SRC_CHROMAKEY     0x0080
-/*  Flags for the 'flags' field. */
-#define V4L2_FBUF_FLAG_PRIMARY          0x0001
-#define V4L2_FBUF_FLAG_OVERLAY          0x0002
-#define V4L2_FBUF_FLAG_CHROMAKEY        0x0004
-#define V4L2_FBUF_FLAG_LOCAL_ALPHA      0x0008
-#define V4L2_FBUF_FLAG_GLOBAL_ALPHA     0x0010
-#define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA  0x0020
-#define V4L2_FBUF_FLAG_SRC_CHROMAKEY    0x0040
-
-struct <link linkend="v4l2-clip">v4l2_clip</link> {
-        struct <link linkend="v4l2-rect">v4l2_rect</link>        c;
-        struct <link linkend="v4l2-clip">v4l2_clip</link>        __user *next;
-};
-
-struct <link linkend="v4l2-window">v4l2_window</link> {
-        struct <link linkend="v4l2-rect">v4l2_rect</link>        w;
-        enum <link linkend="v4l2-field">v4l2_field</link>         field;
-        __u32                   chromakey;
-        struct <link linkend="v4l2-clip">v4l2_clip</link>        __user *clips;
-        __u32                   clipcount;
-        void                    __user *bitmap;
-        __u8                    global_alpha;
-};
-
-/*
- *      C A P T U R E   P A R A M E T E R S
- */
-struct <link linkend="v4l2-captureparm">v4l2_captureparm</link> {
-        __u32              capability;    /*  Supported modes */
-        __u32              capturemode;   /*  Current mode */
-        struct <link linkend="v4l2-fract">v4l2_fract</link>  timeperframe;  /*  Time per frame in .1us units */
-        __u32              extendedmode;  /*  Driver-specific extensions */
-        __u32              readbuffers;   /*  # of buffers for read */
-        __u32              reserved[4];
-};
-
-/*  Flags for 'capability' and 'capturemode' fields */
-#define V4L2_MODE_HIGHQUALITY   0x0001  /*  High quality imaging mode */
-#define V4L2_CAP_TIMEPERFRAME   0x1000  /*  timeperframe field is supported */
-
-struct <link linkend="v4l2-outputparm">v4l2_outputparm</link> {
-        __u32              capability;   /*  Supported modes */
-        __u32              outputmode;   /*  Current mode */
-        struct <link linkend="v4l2-fract">v4l2_fract</link>  timeperframe; /*  Time per frame in seconds */
-        __u32              extendedmode; /*  Driver-specific extensions */
-        __u32              writebuffers; /*  # of buffers for write */
-        __u32              reserved[4];
-};
-
-/*
- *      I N P U T   I M A G E   C R O P P I N G
- */
-struct <link linkend="v4l2-cropcap">v4l2_cropcap</link> {
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>      type;
-        struct <link linkend="v4l2-rect">v4l2_rect</link>        bounds;
-        struct <link linkend="v4l2-rect">v4l2_rect</link>        defrect;
-        struct <link linkend="v4l2-fract">v4l2_fract</link>       pixelaspect;
-};
-
-struct <link linkend="v4l2-crop">v4l2_crop</link> {
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link>      type;
-        struct <link linkend="v4l2-rect">v4l2_rect</link>        c;
-};
-
-/*
- *      A N A L O G   V I D E O   S T A N D A R D
- */
-
-typedef __u64 v4l2_std_id;
-
-/* one bit for each */
-#define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
-#define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
-#define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
-#define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
-#define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
-#define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
-#define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
-#define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
-
-#define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
-#define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
-#define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
-#define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
-
-#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
-#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
-#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
-#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)
-
-#define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
-#define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
-#define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
-#define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
-#define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
-#define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
-#define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
-#define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
-
-/* ATSC/HDTV */
-#define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
-#define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
-
-/* FIXME:
-   Although std_id is 64 bits, there is an issue on PPC32 architecture that
-   makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding
-   this value to 32 bits.
-   As, currently, the max value is for V4L2_STD_ATSC_16_VSB (30 bits wide),
-   it should work fine. However, if needed to add more than two standards,
-   v4l2-common.c should be fixed.
- */
-
-/* some merged standards */
-#define V4L2_STD_MN     (V4L2_STD_PAL_M|V4L2_STD_PAL_N|V4L2_STD_PAL_Nc|V4L2_STD_NTSC)
-#define V4L2_STD_B      (V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_SECAM_B)
-#define V4L2_STD_GH     (V4L2_STD_PAL_G|V4L2_STD_PAL_H|V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)
-#define V4L2_STD_DK     (V4L2_STD_PAL_DK|V4L2_STD_SECAM_DK)
-
-/* some common needed stuff */
-#define V4L2_STD_PAL_BG         (V4L2_STD_PAL_B         |\
-                                 V4L2_STD_PAL_B1        |\
-                                 V4L2_STD_PAL_G)
-#define V4L2_STD_PAL_DK         (V4L2_STD_PAL_D         |\
-                                 V4L2_STD_PAL_D1        |\
-                                 V4L2_STD_PAL_K)
-#define V4L2_STD_PAL            (V4L2_STD_PAL_BG        |\
-                                 V4L2_STD_PAL_DK        |\
-                                 V4L2_STD_PAL_H         |\
-                                 V4L2_STD_PAL_I)
-#define V4L2_STD_NTSC           (V4L2_STD_NTSC_M        |\
-                                 V4L2_STD_NTSC_M_JP     |\
-                                 V4L2_STD_NTSC_M_KR)
-#define V4L2_STD_SECAM_DK       (V4L2_STD_SECAM_D       |\
-                                 V4L2_STD_SECAM_K       |\
-                                 V4L2_STD_SECAM_K1)
-#define V4L2_STD_SECAM          (V4L2_STD_SECAM_B       |\
-                                 V4L2_STD_SECAM_G       |\
-                                 V4L2_STD_SECAM_H       |\
-                                 V4L2_STD_SECAM_DK      |\
-                                 V4L2_STD_SECAM_L       |\
-                                 V4L2_STD_SECAM_LC)
-
-#define V4L2_STD_525_60         (V4L2_STD_PAL_M         |\
-                                 V4L2_STD_PAL_60        |\
-                                 V4L2_STD_NTSC          |\
-                                 V4L2_STD_NTSC_443)
-#define V4L2_STD_625_50         (V4L2_STD_PAL           |\
-                                 V4L2_STD_PAL_N         |\
-                                 V4L2_STD_PAL_Nc        |\
-                                 V4L2_STD_SECAM)
-#define V4L2_STD_ATSC           (V4L2_STD_ATSC_8_VSB    |\
-                                 V4L2_STD_ATSC_16_VSB)
-
-#define V4L2_STD_UNKNOWN        0
-#define V4L2_STD_ALL            (V4L2_STD_525_60        |\
-                                 V4L2_STD_625_50)
-
-struct <link linkend="v4l2-standard">v4l2_standard</link> {
-        __u32                index;
-        v4l2_std_id          id;
-        __u8                 name[24];
-        struct <link linkend="v4l2-fract">v4l2_fract</link>    frameperiod; /* Frames, not fields */
-        __u32                framelines;
-        __u32                reserved[4];
-};
-
-/*
- *      V I D E O       T I M I N G S   D V     P R E S E T
- */
-struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link> {
-        __u32   preset;
-        __u32   reserved[4];
-};
-
-/*
- *      D V     P R E S E T S   E N U M E R A T I O N
- */
-struct <link linkend="v4l2-dv-enum-preset">v4l2_dv_enum_preset</link> {
-        __u32   index;
-        __u32   preset;
-        __u8    name[32]; /* Name of the preset timing */
-        __u32   width;
-        __u32   height;
-        __u32   reserved[4];
-};
-
-/*
- *      D V     P R E S E T     V A L U E S
- */
-#define         V4L2_DV_INVALID         0
-#define         V4L2_DV_480P59_94       1 /* BT.1362 */
-#define         V4L2_DV_576P50          2 /* BT.1362 */
-#define         V4L2_DV_720P24          3 /* SMPTE 296M */
-#define         V4L2_DV_720P25          4 /* SMPTE 296M */
-#define         V4L2_DV_720P30          5 /* SMPTE 296M */
-#define         V4L2_DV_720P50          6 /* SMPTE 296M */
-#define         V4L2_DV_720P59_94       7 /* SMPTE 274M */
-#define         V4L2_DV_720P60          8 /* SMPTE 274M/296M */
-#define         V4L2_DV_1080I29_97      9 /* BT.1120/ SMPTE 274M */
-#define         V4L2_DV_1080I30         10 /* BT.1120/ SMPTE 274M */
-#define         V4L2_DV_1080I25         11 /* BT.1120 */
-#define         V4L2_DV_1080I50         12 /* SMPTE 296M */
-#define         V4L2_DV_1080I60         13 /* SMPTE 296M */
-#define         V4L2_DV_1080P24         14 /* SMPTE 296M */
-#define         V4L2_DV_1080P25         15 /* SMPTE 296M */
-#define         V4L2_DV_1080P30         16 /* SMPTE 296M */
-#define         V4L2_DV_1080P50         17 /* BT.1120 */
-#define         V4L2_DV_1080P60         18 /* BT.1120 */
-
-/*
- *      D V     B T     T I M I N G S
- */
-
-/* BT.656/BT.1120 timing data */
-struct <link linkend="v4l2-bt-timings">v4l2_bt_timings</link> {
-        __u32   width;          /* width in pixels */
-        __u32   height;         /* height in lines */
-        __u32   interlaced;     /* Interlaced or progressive */
-        __u32   polarities;     /* Positive or negative polarity */
-        __u64   pixelclock;     /* Pixel clock in HZ. Ex. 74.25MHz-&gt;74250000 */
-        __u32   hfrontporch;    /* Horizpontal front porch in pixels */
-        __u32   hsync;          /* Horizontal Sync length in pixels */
-        __u32   hbackporch;     /* Horizontal back porch in pixels */
-        __u32   vfrontporch;    /* Vertical front porch in pixels */
-        __u32   vsync;          /* Vertical Sync length in lines */
-        __u32   vbackporch;     /* Vertical back porch in lines */
-        __u32   il_vfrontporch; /* Vertical front porch for bottom field of
-                                 * interlaced field formats
-                                 */
-        __u32   il_vsync;       /* Vertical sync length for bottom field of
-                                 * interlaced field formats
-                                 */
-        __u32   il_vbackporch;  /* Vertical back porch for bottom field of
-                                 * interlaced field formats
-                                 */
-        __u32   reserved[16];
-} __attribute__ ((packed));
-
-/* Interlaced or progressive format */
-#define V4L2_DV_PROGRESSIVE     0
-#define V4L2_DV_INTERLACED      1
-
-/* Polarities. If bit is not set, it is assumed to be negative polarity */
-#define V4L2_DV_VSYNC_POS_POL   0x00000001
-#define V4L2_DV_HSYNC_POS_POL   0x00000002
-
-
-/* DV timings */
-struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link> {
-        __u32 type;
-        union {
-                struct <link linkend="v4l2-bt-timings">v4l2_bt_timings</link>  bt;
-                __u32   reserved[32];
-        };
-} __attribute__ ((packed));
-
-/* Values for the type field */
-#define V4L2_DV_BT_656_1120     0       /* BT.656/1120 timing type */
-
-/*
- *      V I D E O   I N P U T S
- */
-struct <link linkend="v4l2-input">v4l2_input</link> {
-        __u32        index;             /*  Which input */
-        __u8         name[32];          /*  Label */
-        __u32        type;              /*  Type of input */
-        __u32        audioset;          /*  Associated audios (bitfield) */
-        __u32        tuner;             /*  Associated tuner */
-        v4l2_std_id  std;
-        __u32        status;
-        __u32        capabilities;
-        __u32        reserved[3];
-};
-
-/*  Values for the 'type' field */
-#define V4L2_INPUT_TYPE_TUNER           1
-#define V4L2_INPUT_TYPE_CAMERA          2
-
-/* field 'status' - general */
-#define V4L2_IN_ST_NO_POWER    0x00000001  /* Attached device is off */
-#define V4L2_IN_ST_NO_SIGNAL   0x00000002
-#define V4L2_IN_ST_NO_COLOR    0x00000004
-
-/* field 'status' - sensor orientation */
-/* If sensor is mounted upside down set both bits */
-#define V4L2_IN_ST_HFLIP       0x00000010 /* Frames are flipped horizontally */
-#define V4L2_IN_ST_VFLIP       0x00000020 /* Frames are flipped vertically */
-
-/* field 'status' - analog */
-#define V4L2_IN_ST_NO_H_LOCK   0x00000100  /* No horizontal sync lock */
-#define V4L2_IN_ST_COLOR_KILL  0x00000200  /* Color killer is active */
-
-/* field 'status' - digital */
-#define V4L2_IN_ST_NO_SYNC     0x00010000  /* No synchronization lock */
-#define V4L2_IN_ST_NO_EQU      0x00020000  /* No equalizer lock */
-#define V4L2_IN_ST_NO_CARRIER  0x00040000  /* Carrier recovery failed */
-
-/* field 'status' - VCR and set-top box */
-#define V4L2_IN_ST_MACROVISION 0x01000000  /* Macrovision detected */
-#define V4L2_IN_ST_NO_ACCESS   0x02000000  /* Conditional access denied */
-#define V4L2_IN_ST_VTR         0x04000000  /* VTR time constant */
-
-/* capabilities flags */
-#define V4L2_IN_CAP_PRESETS             0x00000001 /* Supports S_DV_PRESET */
-#define V4L2_IN_CAP_CUSTOM_TIMINGS      0x00000002 /* Supports S_DV_TIMINGS */
-#define V4L2_IN_CAP_STD                 0x00000004 /* Supports S_STD */
-
-/*
- *      V I D E O   O U T P U T S
- */
-struct <link linkend="v4l2-output">v4l2_output</link> {
-        __u32        index;             /*  Which output */
-        __u8         name[32];          /*  Label */
-        __u32        type;              /*  Type of output */
-        __u32        audioset;          /*  Associated audios (bitfield) */
-        __u32        modulator;         /*  Associated modulator */
-        v4l2_std_id  std;
-        __u32        capabilities;
-        __u32        reserved[3];
-};
-/*  Values for the 'type' field */
-#define V4L2_OUTPUT_TYPE_MODULATOR              1
-#define V4L2_OUTPUT_TYPE_ANALOG                 2
-#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY       3
-
-/* capabilities flags */
-#define V4L2_OUT_CAP_PRESETS            0x00000001 /* Supports S_DV_PRESET */
-#define V4L2_OUT_CAP_CUSTOM_TIMINGS     0x00000002 /* Supports S_DV_TIMINGS */
-#define V4L2_OUT_CAP_STD                0x00000004 /* Supports S_STD */
-
-/*
- *      C O N T R O L S
- */
-struct <link linkend="v4l2-control">v4l2_control</link> {
-        __u32                id;
-        __s32                value;
-};
-
-struct <link linkend="v4l2-ext-control">v4l2_ext_control</link> {
-        __u32 id;
-        __u32 size;
-        __u32 reserved2[1];
-        union {
-                __s32 value;
-                __s64 value64;
-                char *string;
-        };
-} __attribute__ ((packed));
-
-struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link> {
-        __u32 ctrl_class;
-        __u32 count;
-        __u32 error_idx;
-        __u32 reserved[2];
-        struct <link linkend="v4l2-ext-control">v4l2_ext_control</link> *controls;
-};
-
-/*  Values for ctrl_class field */
-#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */
-#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */
-#define V4L2_CTRL_CLASS_CAMERA 0x009a0000       /* Camera class controls */
-#define V4L2_CTRL_CLASS_FM_TX 0x009b0000        /* FM Modulator control class */
-
-#define V4L2_CTRL_ID_MASK         (0x0fffffff)
-#define V4L2_CTRL_ID2CLASS(id)    ((id) &amp; 0x0fff0000UL)
-#define V4L2_CTRL_DRIVER_PRIV(id) (((id) &amp; 0xffff) &gt;= 0x1000)
-
-enum <link linkend="v4l2-ctrl-type">v4l2_ctrl_type</link> {
-        V4L2_CTRL_TYPE_INTEGER       = 1,
-        V4L2_CTRL_TYPE_BOOLEAN       = 2,
-        V4L2_CTRL_TYPE_MENU          = 3,
-        V4L2_CTRL_TYPE_BUTTON        = 4,
-        V4L2_CTRL_TYPE_INTEGER64     = 5,
-        V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
-        V4L2_CTRL_TYPE_STRING        = 7,
-};
-
-/*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
-struct <link linkend="v4l2-queryctrl">v4l2_queryctrl</link> {
-        __u32                id;
-        enum <link linkend="v4l2-ctrl-type">v4l2_ctrl_type</link>  type;
-        __u8                 name[32];  /* Whatever */
-        __s32                minimum;   /* Note signedness */
-        __s32                maximum;
-        __s32                step;
-        __s32                default_value;
-        __u32                flags;
-        __u32                reserved[2];
-};
-
-/*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
-struct <link linkend="v4l2-querymenu">v4l2_querymenu</link> {
-        __u32           id;
-        __u32           index;
-        __u8            name[32];       /* Whatever */
-        __u32           reserved;
-};
-
-/*  Control flags  */
-#define V4L2_CTRL_FLAG_DISABLED         0x0001
-#define V4L2_CTRL_FLAG_GRABBED          0x0002
-#define V4L2_CTRL_FLAG_READ_ONLY        0x0004
-#define V4L2_CTRL_FLAG_UPDATE           0x0008
-#define V4L2_CTRL_FLAG_INACTIVE         0x0010
-#define V4L2_CTRL_FLAG_SLIDER           0x0020
-#define V4L2_CTRL_FLAG_WRITE_ONLY       0x0040
-
-/*  Query flag, to be ORed with the control ID */
-#define V4L2_CTRL_FLAG_NEXT_CTRL        0x80000000
-
-/*  User-class control IDs defined by V4L2 */
-#define V4L2_CID_BASE                   (V4L2_CTRL_CLASS_USER | 0x900)
-#define V4L2_CID_USER_BASE              V4L2_CID_BASE
-/*  IDs reserved for driver specific controls */
-#define V4L2_CID_PRIVATE_BASE           0x08000000
-
-#define V4L2_CID_USER_CLASS             (V4L2_CTRL_CLASS_USER | 1)
-#define V4L2_CID_BRIGHTNESS             (V4L2_CID_BASE+0)
-#define V4L2_CID_CONTRAST               (V4L2_CID_BASE+1)
-#define V4L2_CID_SATURATION             (V4L2_CID_BASE+2)
-#define V4L2_CID_HUE                    (V4L2_CID_BASE+3)
-#define V4L2_CID_AUDIO_VOLUME           (V4L2_CID_BASE+5)
-#define V4L2_CID_AUDIO_BALANCE          (V4L2_CID_BASE+6)
-#define V4L2_CID_AUDIO_BASS             (V4L2_CID_BASE+7)
-#define V4L2_CID_AUDIO_TREBLE           (V4L2_CID_BASE+8)
-#define V4L2_CID_AUDIO_MUTE             (V4L2_CID_BASE+9)
-#define V4L2_CID_AUDIO_LOUDNESS         (V4L2_CID_BASE+10)
-#define V4L2_CID_BLACK_LEVEL            (V4L2_CID_BASE+11) /* Deprecated */
-#define V4L2_CID_AUTO_WHITE_BALANCE     (V4L2_CID_BASE+12)
-#define V4L2_CID_DO_WHITE_BALANCE       (V4L2_CID_BASE+13)
-#define V4L2_CID_RED_BALANCE            (V4L2_CID_BASE+14)
-#define V4L2_CID_BLUE_BALANCE           (V4L2_CID_BASE+15)
-#define V4L2_CID_GAMMA                  (V4L2_CID_BASE+16)
-#define V4L2_CID_WHITENESS              (V4L2_CID_GAMMA) /* Deprecated */
-#define V4L2_CID_EXPOSURE               (V4L2_CID_BASE+17)
-#define V4L2_CID_AUTOGAIN               (V4L2_CID_BASE+18)
-#define V4L2_CID_GAIN                   (V4L2_CID_BASE+19)
-#define V4L2_CID_HFLIP                  (V4L2_CID_BASE+20)
-#define V4L2_CID_VFLIP                  (V4L2_CID_BASE+21)
-
-/* Deprecated; use V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET */
-#define V4L2_CID_HCENTER                (V4L2_CID_BASE+22)
-#define V4L2_CID_VCENTER                (V4L2_CID_BASE+23)
-
-#define V4L2_CID_POWER_LINE_FREQUENCY   (V4L2_CID_BASE+24)
-enum <link linkend="v4l2-power-line-frequency">v4l2_power_line_frequency</link> {
-        V4L2_CID_POWER_LINE_FREQUENCY_DISABLED  = 0,
-        V4L2_CID_POWER_LINE_FREQUENCY_50HZ      = 1,
-        V4L2_CID_POWER_LINE_FREQUENCY_60HZ      = 2,
-};
-#define V4L2_CID_HUE_AUTO                       (V4L2_CID_BASE+25)
-#define V4L2_CID_WHITE_BALANCE_TEMPERATURE      (V4L2_CID_BASE+26)
-#define V4L2_CID_SHARPNESS                      (V4L2_CID_BASE+27)
-#define V4L2_CID_BACKLIGHT_COMPENSATION         (V4L2_CID_BASE+28)
-#define V4L2_CID_CHROMA_AGC                     (V4L2_CID_BASE+29)
-#define V4L2_CID_COLOR_KILLER                   (V4L2_CID_BASE+30)
-#define V4L2_CID_COLORFX                        (V4L2_CID_BASE+31)
-enum <link linkend="v4l2-colorfx">v4l2_colorfx</link> {
-        V4L2_COLORFX_NONE       = 0,
-        V4L2_COLORFX_BW         = 1,
-        V4L2_COLORFX_SEPIA      = 2,
-        V4L2_COLORFX_NEGATIVE = 3,
-        V4L2_COLORFX_EMBOSS = 4,
-        V4L2_COLORFX_SKETCH = 5,
-        V4L2_COLORFX_SKY_BLUE = 6,
-        V4L2_COLORFX_GRASS_GREEN = 7,
-        V4L2_COLORFX_SKIN_WHITEN = 8,
-        V4L2_COLORFX_VIVID = 9,
-};
-#define V4L2_CID_AUTOBRIGHTNESS                 (V4L2_CID_BASE+32)
-#define V4L2_CID_BAND_STOP_FILTER               (V4L2_CID_BASE+33)
-
-#define V4L2_CID_ROTATE                         (V4L2_CID_BASE+34)
-#define V4L2_CID_BG_COLOR                       (V4L2_CID_BASE+35)
-
-#define V4L2_CID_CHROMA_GAIN                    (V4L2_CID_BASE+36)
-
-#define V4L2_CID_ILLUMINATORS_1                 (V4L2_CID_BASE+37)
-#define V4L2_CID_ILLUMINATORS_2                 (V4L2_CID_BASE+38)
-
-/* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+39)
-
-/*  MPEG-class control IDs defined by V4L2 */
-#define V4L2_CID_MPEG_BASE                      (V4L2_CTRL_CLASS_MPEG | 0x900)
-#define V4L2_CID_MPEG_CLASS                     (V4L2_CTRL_CLASS_MPEG | 1)
-
-/*  MPEG streams */
-#define V4L2_CID_MPEG_STREAM_TYPE               (V4L2_CID_MPEG_BASE+0)
-enum <link linkend="v4l2-mpeg-stream-type">v4l2_mpeg_stream_type</link> {
-        V4L2_MPEG_STREAM_TYPE_MPEG2_PS   = 0, /* MPEG-2 program stream */
-        V4L2_MPEG_STREAM_TYPE_MPEG2_TS   = 1, /* MPEG-2 transport stream */
-        V4L2_MPEG_STREAM_TYPE_MPEG1_SS   = 2, /* MPEG-1 system stream */
-        V4L2_MPEG_STREAM_TYPE_MPEG2_DVD  = 3, /* MPEG-2 DVD-compatible stream */
-        V4L2_MPEG_STREAM_TYPE_MPEG1_VCD  = 4, /* MPEG-1 VCD-compatible stream */
-        V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */
-};
-#define V4L2_CID_MPEG_STREAM_PID_PMT            (V4L2_CID_MPEG_BASE+1)
-#define V4L2_CID_MPEG_STREAM_PID_AUDIO          (V4L2_CID_MPEG_BASE+2)
-#define V4L2_CID_MPEG_STREAM_PID_VIDEO          (V4L2_CID_MPEG_BASE+3)
-#define V4L2_CID_MPEG_STREAM_PID_PCR            (V4L2_CID_MPEG_BASE+4)
-#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO       (V4L2_CID_MPEG_BASE+5)
-#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO       (V4L2_CID_MPEG_BASE+6)
-#define V4L2_CID_MPEG_STREAM_VBI_FMT            (V4L2_CID_MPEG_BASE+7)
-enum <link linkend="v4l2-mpeg-stream-vbi-fmt">v4l2_mpeg_stream_vbi_fmt</link> {
-        V4L2_MPEG_STREAM_VBI_FMT_NONE = 0,  /* No VBI in the MPEG stream */
-        V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1,  /* VBI in private packets, IVTV format */
-};
-
-/*  MPEG audio */
-#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ       (V4L2_CID_MPEG_BASE+100)
-enum <link linkend="v4l2-mpeg-audio-sampling-freq">v4l2_mpeg_audio_sampling_freq</link> {
-        V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
-        V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1,
-        V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2,
-};
-#define V4L2_CID_MPEG_AUDIO_ENCODING            (V4L2_CID_MPEG_BASE+101)
-enum <link linkend="v4l2-mpeg-audio-encoding">v4l2_mpeg_audio_encoding</link> {
-        V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
-        V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
-        V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
-        V4L2_MPEG_AUDIO_ENCODING_AAC     = 3,
-        V4L2_MPEG_AUDIO_ENCODING_AC3     = 4,
-};
-#define V4L2_CID_MPEG_AUDIO_L1_BITRATE          (V4L2_CID_MPEG_BASE+102)
-enum <link linkend="v4l2-mpeg-audio-l1-bitrate">v4l2_mpeg_audio_l1_bitrate</link> {
-        V4L2_MPEG_AUDIO_L1_BITRATE_32K  = 0,
-        V4L2_MPEG_AUDIO_L1_BITRATE_64K  = 1,
-        V4L2_MPEG_AUDIO_L1_BITRATE_96K  = 2,
-        V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3,
-        V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4,
-        V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5,
-        V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6,
-        V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7,
-        V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8,
-        V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9,
-        V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10,
-        V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11,
-        V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12,
-        V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13,
-};
-#define V4L2_CID_MPEG_AUDIO_L2_BITRATE          (V4L2_CID_MPEG_BASE+103)
-enum <link linkend="v4l2-mpeg-audio-l2-bitrate">v4l2_mpeg_audio_l2_bitrate</link> {
-        V4L2_MPEG_AUDIO_L2_BITRATE_32K  = 0,
-        V4L2_MPEG_AUDIO_L2_BITRATE_48K  = 1,
-        V4L2_MPEG_AUDIO_L2_BITRATE_56K  = 2,
-        V4L2_MPEG_AUDIO_L2_BITRATE_64K  = 3,
-        V4L2_MPEG_AUDIO_L2_BITRATE_80K  = 4,
-        V4L2_MPEG_AUDIO_L2_BITRATE_96K  = 5,
-        V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6,
-        V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7,
-        V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8,
-        V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9,
-        V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10,
-        V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11,
-        V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12,
-        V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13,
-};
-#define V4L2_CID_MPEG_AUDIO_L3_BITRATE          (V4L2_CID_MPEG_BASE+104)
-enum <link linkend="v4l2-mpeg-audio-l3-bitrate">v4l2_mpeg_audio_l3_bitrate</link> {
-        V4L2_MPEG_AUDIO_L3_BITRATE_32K  = 0,
-        V4L2_MPEG_AUDIO_L3_BITRATE_40K  = 1,
-        V4L2_MPEG_AUDIO_L3_BITRATE_48K  = 2,
-        V4L2_MPEG_AUDIO_L3_BITRATE_56K  = 3,
-        V4L2_MPEG_AUDIO_L3_BITRATE_64K  = 4,
-        V4L2_MPEG_AUDIO_L3_BITRATE_80K  = 5,
-        V4L2_MPEG_AUDIO_L3_BITRATE_96K  = 6,
-        V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7,
-        V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8,
-        V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9,
-        V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10,
-        V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11,
-        V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12,
-        V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13,
-};
-#define V4L2_CID_MPEG_AUDIO_MODE                (V4L2_CID_MPEG_BASE+105)
-enum <link linkend="v4l2-mpeg-audio-mode">v4l2_mpeg_audio_mode</link> {
-        V4L2_MPEG_AUDIO_MODE_STEREO       = 0,
-        V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1,
-        V4L2_MPEG_AUDIO_MODE_DUAL         = 2,
-        V4L2_MPEG_AUDIO_MODE_MONO         = 3,
-};
-#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION      (V4L2_CID_MPEG_BASE+106)
-enum <link linkend="v4l2-mpeg-audio-mode-extension">v4l2_mpeg_audio_mode_extension</link> {
-        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4  = 0,
-        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8  = 1,
-        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2,
-        V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3,
-};
-#define V4L2_CID_MPEG_AUDIO_EMPHASIS            (V4L2_CID_MPEG_BASE+107)
-enum <link linkend="v4l2-mpeg-audio-emphasis">v4l2_mpeg_audio_emphasis</link> {
-        V4L2_MPEG_AUDIO_EMPHASIS_NONE         = 0,
-        V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1,
-        V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17    = 2,
-};
-#define V4L2_CID_MPEG_AUDIO_CRC                 (V4L2_CID_MPEG_BASE+108)
-enum <link linkend="v4l2-mpeg-audio-crc">v4l2_mpeg_audio_crc</link> {
-        V4L2_MPEG_AUDIO_CRC_NONE  = 0,
-        V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
-};
-#define V4L2_CID_MPEG_AUDIO_MUTE                (V4L2_CID_MPEG_BASE+109)
-#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE         (V4L2_CID_MPEG_BASE+110)
-#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE         (V4L2_CID_MPEG_BASE+111)
-enum <link linkend="v4l2-mpeg-audio-ac3-bitrate">v4l2_mpeg_audio_ac3_bitrate</link> {
-        V4L2_MPEG_AUDIO_AC3_BITRATE_32K  = 0,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_40K  = 1,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_48K  = 2,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_56K  = 3,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_64K  = 4,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_80K  = 5,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_96K  = 6,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17,
-        V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18,
-};
-
-/*  MPEG video */
-#define V4L2_CID_MPEG_VIDEO_ENCODING            (V4L2_CID_MPEG_BASE+200)
-enum <link linkend="v4l2-mpeg-video-encoding">v4l2_mpeg_video_encoding</link> {
-        V4L2_MPEG_VIDEO_ENCODING_MPEG_1     = 0,
-        V4L2_MPEG_VIDEO_ENCODING_MPEG_2     = 1,
-        V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2,
-};
-#define V4L2_CID_MPEG_VIDEO_ASPECT              (V4L2_CID_MPEG_BASE+201)
-enum <link linkend="v4l2-mpeg-video-aspect">v4l2_mpeg_video_aspect</link> {
-        V4L2_MPEG_VIDEO_ASPECT_1x1     = 0,
-        V4L2_MPEG_VIDEO_ASPECT_4x3     = 1,
-        V4L2_MPEG_VIDEO_ASPECT_16x9    = 2,
-        V4L2_MPEG_VIDEO_ASPECT_221x100 = 3,
-};
-#define V4L2_CID_MPEG_VIDEO_B_FRAMES            (V4L2_CID_MPEG_BASE+202)
-#define V4L2_CID_MPEG_VIDEO_GOP_SIZE            (V4L2_CID_MPEG_BASE+203)
-#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE         (V4L2_CID_MPEG_BASE+204)
-#define V4L2_CID_MPEG_VIDEO_PULLDOWN            (V4L2_CID_MPEG_BASE+205)
-#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE        (V4L2_CID_MPEG_BASE+206)
-enum <link linkend="v4l2-mpeg-video-bitrate-mode">v4l2_mpeg_video_bitrate_mode</link> {
-        V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0,
-        V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1,
-};
-#define V4L2_CID_MPEG_VIDEO_BITRATE             (V4L2_CID_MPEG_BASE+207)
-#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK        (V4L2_CID_MPEG_BASE+208)
-#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
-#define V4L2_CID_MPEG_VIDEO_MUTE                (V4L2_CID_MPEG_BASE+210)
-#define V4L2_CID_MPEG_VIDEO_MUTE_YUV            (V4L2_CID_MPEG_BASE+211)
-
-/*  MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
-#define V4L2_CID_MPEG_CX2341X_BASE                              (V4L2_CTRL_CLASS_MPEG | 0x1000)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE         (V4L2_CID_MPEG_CX2341X_BASE+0)
-enum <link linkend="v4l2-mpeg-cx2341x-video-spatial-filter-mode">v4l2_mpeg_cx2341x_video_spatial_filter_mode</link> {
-        V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0,
-        V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO   = 1,
-};
-#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER              (V4L2_CID_MPEG_CX2341X_BASE+1)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE    (V4L2_CID_MPEG_CX2341X_BASE+2)
-enum <link linkend="luma-spatial-filter-type">v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</link> {
-        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF                  = 0,
-        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR               = 1,
-        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT              = 2,
-        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE      = 3,
-        V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4,
-};
-#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE  (V4L2_CID_MPEG_CX2341X_BASE+3)
-enum <link linkend="chroma-spatial-filter-type">v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</link> {
-        V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF    = 0,
-        V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
-};
-#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE        (V4L2_CID_MPEG_CX2341X_BASE+4)
-enum <link linkend="v4l2-mpeg-cx2341x-video-temporal-filter-mode">v4l2_mpeg_cx2341x_video_temporal_filter_mode</link> {
-        V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0,
-        V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO   = 1,
-};
-#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER             (V4L2_CID_MPEG_CX2341X_BASE+5)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE          (V4L2_CID_MPEG_CX2341X_BASE+6)
-enum <link linkend="v4l2-mpeg-cx2341x-video-median-filter-type">v4l2_mpeg_cx2341x_video_median_filter_type</link> {
-        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF      = 0,
-        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR      = 1,
-        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT     = 2,
-        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3,
-        V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG     = 4,
-};
-#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM   (V4L2_CID_MPEG_CX2341X_BASE+7)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP      (V4L2_CID_MPEG_CX2341X_BASE+8)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9)
-#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP    (V4L2_CID_MPEG_CX2341X_BASE+10)
-#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS         (V4L2_CID_MPEG_CX2341X_BASE+11)
-
-/*  Camera class control IDs */
-#define V4L2_CID_CAMERA_CLASS_BASE      (V4L2_CTRL_CLASS_CAMERA | 0x900)
-#define V4L2_CID_CAMERA_CLASS           (V4L2_CTRL_CLASS_CAMERA | 1)
-
-#define V4L2_CID_EXPOSURE_AUTO                  (V4L2_CID_CAMERA_CLASS_BASE+1)
-enum  <link linkend="v4l2-exposure-auto-type">v4l2_exposure_auto_type</link> {
-        V4L2_EXPOSURE_AUTO = 0,
-        V4L2_EXPOSURE_MANUAL = 1,
-        V4L2_EXPOSURE_SHUTTER_PRIORITY = 2,
-        V4L2_EXPOSURE_APERTURE_PRIORITY = 3
-};
-#define V4L2_CID_EXPOSURE_ABSOLUTE              (V4L2_CID_CAMERA_CLASS_BASE+2)
-#define V4L2_CID_EXPOSURE_AUTO_PRIORITY         (V4L2_CID_CAMERA_CLASS_BASE+3)
-
-#define V4L2_CID_PAN_RELATIVE                   (V4L2_CID_CAMERA_CLASS_BASE+4)
-#define V4L2_CID_TILT_RELATIVE                  (V4L2_CID_CAMERA_CLASS_BASE+5)
-#define V4L2_CID_PAN_RESET                      (V4L2_CID_CAMERA_CLASS_BASE+6)
-#define V4L2_CID_TILT_RESET                     (V4L2_CID_CAMERA_CLASS_BASE+7)
-
-#define V4L2_CID_PAN_ABSOLUTE                   (V4L2_CID_CAMERA_CLASS_BASE+8)
-#define V4L2_CID_TILT_ABSOLUTE                  (V4L2_CID_CAMERA_CLASS_BASE+9)
-
-#define V4L2_CID_FOCUS_ABSOLUTE                 (V4L2_CID_CAMERA_CLASS_BASE+10)
-#define V4L2_CID_FOCUS_RELATIVE                 (V4L2_CID_CAMERA_CLASS_BASE+11)
-#define V4L2_CID_FOCUS_AUTO                     (V4L2_CID_CAMERA_CLASS_BASE+12)
-
-#define V4L2_CID_ZOOM_ABSOLUTE                  (V4L2_CID_CAMERA_CLASS_BASE+13)
-#define V4L2_CID_ZOOM_RELATIVE                  (V4L2_CID_CAMERA_CLASS_BASE+14)
-#define V4L2_CID_ZOOM_CONTINUOUS                (V4L2_CID_CAMERA_CLASS_BASE+15)
-
-#define V4L2_CID_PRIVACY                        (V4L2_CID_CAMERA_CLASS_BASE+16)
-
-#define V4L2_CID_IRIS_ABSOLUTE                  (V4L2_CID_CAMERA_CLASS_BASE+17)
-#define V4L2_CID_IRIS_RELATIVE                  (V4L2_CID_CAMERA_CLASS_BASE+18)
-
-/* FM Modulator class control IDs */
-#define V4L2_CID_FM_TX_CLASS_BASE               (V4L2_CTRL_CLASS_FM_TX | 0x900)
-#define V4L2_CID_FM_TX_CLASS                    (V4L2_CTRL_CLASS_FM_TX | 1)
-
-#define V4L2_CID_RDS_TX_DEVIATION               (V4L2_CID_FM_TX_CLASS_BASE + 1)
-#define V4L2_CID_RDS_TX_PI                      (V4L2_CID_FM_TX_CLASS_BASE + 2)
-#define V4L2_CID_RDS_TX_PTY                     (V4L2_CID_FM_TX_CLASS_BASE + 3)
-#define V4L2_CID_RDS_TX_PS_NAME                 (V4L2_CID_FM_TX_CLASS_BASE + 5)
-#define V4L2_CID_RDS_TX_RADIO_TEXT              (V4L2_CID_FM_TX_CLASS_BASE + 6)
-
-#define V4L2_CID_AUDIO_LIMITER_ENABLED          (V4L2_CID_FM_TX_CLASS_BASE + 64)
-#define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME     (V4L2_CID_FM_TX_CLASS_BASE + 65)
-#define V4L2_CID_AUDIO_LIMITER_DEVIATION        (V4L2_CID_FM_TX_CLASS_BASE + 66)
-
-#define V4L2_CID_AUDIO_COMPRESSION_ENABLED      (V4L2_CID_FM_TX_CLASS_BASE + 80)
-#define V4L2_CID_AUDIO_COMPRESSION_GAIN         (V4L2_CID_FM_TX_CLASS_BASE + 81)
-#define V4L2_CID_AUDIO_COMPRESSION_THRESHOLD    (V4L2_CID_FM_TX_CLASS_BASE + 82)
-#define V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME  (V4L2_CID_FM_TX_CLASS_BASE + 83)
-#define V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME (V4L2_CID_FM_TX_CLASS_BASE + 84)
-
-#define V4L2_CID_PILOT_TONE_ENABLED             (V4L2_CID_FM_TX_CLASS_BASE + 96)
-#define V4L2_CID_PILOT_TONE_DEVIATION           (V4L2_CID_FM_TX_CLASS_BASE + 97)
-#define V4L2_CID_PILOT_TONE_FREQUENCY           (V4L2_CID_FM_TX_CLASS_BASE + 98)
-
-#define V4L2_CID_TUNE_PREEMPHASIS               (V4L2_CID_FM_TX_CLASS_BASE + 112)
-enum <link linkend="v4l2-preemphasis">v4l2_preemphasis</link> {
-        V4L2_PREEMPHASIS_DISABLED       = 0,
-        V4L2_PREEMPHASIS_50_uS          = 1,
-        V4L2_PREEMPHASIS_75_uS          = 2,
-};
-#define V4L2_CID_TUNE_POWER_LEVEL               (V4L2_CID_FM_TX_CLASS_BASE + 113)
-#define V4L2_CID_TUNE_ANTENNA_CAPACITOR         (V4L2_CID_FM_TX_CLASS_BASE + 114)
-
-/*
- *      T U N I N G
- */
-struct <link linkend="v4l2-tuner">v4l2_tuner</link> {
-        __u32                   index;
-        __u8                    name[32];
-        enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link>    type;
-        __u32                   capability;
-        __u32                   rangelow;
-        __u32                   rangehigh;
-        __u32                   rxsubchans;
-        __u32                   audmode;
-        __s32                   signal;
-        __s32                   afc;
-        __u32                   reserved[4];
-};
-
-struct <link linkend="v4l2-modulator">v4l2_modulator</link> {
-        __u32                   index;
-        __u8                    name[32];
-        __u32                   capability;
-        __u32                   rangelow;
-        __u32                   rangehigh;
-        __u32                   txsubchans;
-        __u32                   reserved[4];
-};
-
-/*  Flags for the 'capability' field */
-#define V4L2_TUNER_CAP_LOW              0x0001
-#define V4L2_TUNER_CAP_NORM             0x0002
-#define V4L2_TUNER_CAP_STEREO           0x0010
-#define V4L2_TUNER_CAP_LANG2            0x0020
-#define V4L2_TUNER_CAP_SAP              0x0020
-#define V4L2_TUNER_CAP_LANG1            0x0040
-#define V4L2_TUNER_CAP_RDS              0x0080
-#define V4L2_TUNER_CAP_RDS_BLOCK_IO     0x0100
-#define V4L2_TUNER_CAP_RDS_CONTROLS     0x0200
-
-/*  Flags for the 'rxsubchans' field */
-#define V4L2_TUNER_SUB_MONO             0x0001
-#define V4L2_TUNER_SUB_STEREO           0x0002
-#define V4L2_TUNER_SUB_LANG2            0x0004
-#define V4L2_TUNER_SUB_SAP              0x0004
-#define V4L2_TUNER_SUB_LANG1            0x0008
-#define V4L2_TUNER_SUB_RDS              0x0010
-
-/*  Values for the 'audmode' field */
-#define V4L2_TUNER_MODE_MONO            0x0000
-#define V4L2_TUNER_MODE_STEREO          0x0001
-#define V4L2_TUNER_MODE_LANG2           0x0002
-#define V4L2_TUNER_MODE_SAP             0x0002
-#define V4L2_TUNER_MODE_LANG1           0x0003
-#define V4L2_TUNER_MODE_LANG1_LANG2     0x0004
-
-struct <link linkend="v4l2-frequency">v4l2_frequency</link> {
-        __u32                 tuner;
-        enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link>  type;
-        __u32                 frequency;
-        __u32                 reserved[8];
-};
-
-struct <link linkend="v4l2-hw-freq-seek">v4l2_hw_freq_seek</link> {
-        __u32                 tuner;
-        enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link>  type;
-        __u32                 seek_upward;
-        __u32                 wrap_around;
-        __u32                 spacing;
-        __u32                 reserved[7];
-};
-
-/*
- *      R D S
- */
-
-struct <link linkend="v4l2-rds-data">v4l2_rds_data</link> {
-        __u8    lsb;
-        __u8    msb;
-        __u8    block;
-} __attribute__ ((packed));
-
-#define V4L2_RDS_BLOCK_MSK       0x7
-#define V4L2_RDS_BLOCK_A         0
-#define V4L2_RDS_BLOCK_B         1
-#define V4L2_RDS_BLOCK_C         2
-#define V4L2_RDS_BLOCK_D         3
-#define V4L2_RDS_BLOCK_C_ALT     4
-#define V4L2_RDS_BLOCK_INVALID   7
-
-#define V4L2_RDS_BLOCK_CORRECTED 0x40
-#define V4L2_RDS_BLOCK_ERROR     0x80
-
-/*
- *      A U D I O
- */
-struct <link linkend="v4l2-audio">v4l2_audio</link> {
-        __u32   index;
-        __u8    name[32];
-        __u32   capability;
-        __u32   mode;
-        __u32   reserved[2];
-};
-
-/*  Flags for the 'capability' field */
-#define V4L2_AUDCAP_STEREO              0x00001
-#define V4L2_AUDCAP_AVL                 0x00002
-
-/*  Flags for the 'mode' field */
-#define V4L2_AUDMODE_AVL                0x00001
-
-struct <link linkend="v4l2-audioout">v4l2_audioout</link> {
-        __u32   index;
-        __u8    name[32];
-        __u32   capability;
-        __u32   mode;
-        __u32   reserved[2];
-};
-
-/*
- *      M P E G   S E R V I C E S
- *
- *      NOTE: EXPERIMENTAL API
- */
-#if 1
-#define V4L2_ENC_IDX_FRAME_I    (0)
-#define V4L2_ENC_IDX_FRAME_P    (1)
-#define V4L2_ENC_IDX_FRAME_B    (2)
-#define V4L2_ENC_IDX_FRAME_MASK (0xf)
-
-struct <link linkend="v4l2-enc-idx-entry">v4l2_enc_idx_entry</link> {
-        __u64 offset;
-        __u64 pts;
-        __u32 length;
-        __u32 flags;
-        __u32 reserved[2];
-};
-
-#define V4L2_ENC_IDX_ENTRIES (64)
-struct <link linkend="v4l2-enc-idx">v4l2_enc_idx</link> {
-        __u32 entries;
-        __u32 entries_cap;
-        __u32 reserved[4];
-        struct <link linkend="v4l2-enc-idx-entry">v4l2_enc_idx_entry</link> entry[V4L2_ENC_IDX_ENTRIES];
-};
-
-
-#define V4L2_ENC_CMD_START      (0)
-#define V4L2_ENC_CMD_STOP       (1)
-#define V4L2_ENC_CMD_PAUSE      (2)
-#define V4L2_ENC_CMD_RESUME     (3)
-
-/* Flags for V4L2_ENC_CMD_STOP */
-#define V4L2_ENC_CMD_STOP_AT_GOP_END    (1 &lt;&lt; 0)
-
-struct <link linkend="v4l2-encoder-cmd">v4l2_encoder_cmd</link> {
-        __u32 cmd;
-        __u32 flags;
-        union {
-                struct {
-                        __u32 data[8];
-                } raw;
-        };
-};
-
-#endif
-
-
-/*
- *      D A T A   S E R V I C E S   ( V B I )
- *
- *      Data services API by Michael Schimek
- */
-
-/* Raw VBI */
-struct <link linkend="v4l2-vbi-format">v4l2_vbi_format</link> {
-        __u32   sampling_rate;          /* in 1 Hz */
-        __u32   offset;
-        __u32   samples_per_line;
-        __u32   sample_format;          /* V4L2_PIX_FMT_* */
-        __s32   start[2];
-        __u32   count[2];
-        __u32   flags;                  /* V4L2_VBI_* */
-        __u32   reserved[2];            /* must be zero */
-};
-
-/*  VBI flags  */
-#define V4L2_VBI_UNSYNC         (1 &lt;&lt; 0)
-#define V4L2_VBI_INTERLACED     (1 &lt;&lt; 1)
-
-/* Sliced VBI
- *
- *    This implements is a proposal V4L2 API to allow SLICED VBI
- * required for some hardware encoders. It should change without
- * notice in the definitive implementation.
- */
-
-struct <link linkend="v4l2-sliced-vbi-format">v4l2_sliced_vbi_format</link> {
-        __u16   service_set;
-        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
-           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
-                                 (equals frame lines 313-336 for 625 line video
-                                  standards, 263-286 for 525 line standards) */
-        __u16   service_lines[2][24];
-        __u32   io_size;
-        __u32   reserved[2];            /* must be zero */
-};
-
-/* Teletext World System Teletext
-   (WST), defined on ITU-R BT.653-2 */
-#define V4L2_SLICED_TELETEXT_B          (0x0001)
-/* Video Program System, defined on ETS 300 231*/
-#define V4L2_SLICED_VPS                 (0x0400)
-/* Closed Caption, defined on EIA-608 */
-#define V4L2_SLICED_CAPTION_525         (0x1000)
-/* Wide Screen System, defined on ITU-R BT1119.1 */
-#define V4L2_SLICED_WSS_625             (0x4000)
-
-#define V4L2_SLICED_VBI_525             (V4L2_SLICED_CAPTION_525)
-#define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625)
-
-struct <link linkend="v4l2-sliced-vbi-cap">v4l2_sliced_vbi_cap</link> {
-        __u16   service_set;
-        /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
-           service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
-                                 (equals frame lines 313-336 for 625 line video
-                                  standards, 263-286 for 525 line standards) */
-        __u16   service_lines[2][24];
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
-        __u32   reserved[3];    /* must be 0 */
-};
-
-struct <link linkend="v4l2-sliced-vbi-data">v4l2_sliced_vbi_data</link> {
-        __u32   id;
-        __u32   field;          /* 0: first field, 1: second field */
-        __u32   line;           /* 1-23 */
-        __u32   reserved;       /* must be 0 */
-        __u8    data[48];
-};
-
-/*
- * Sliced VBI data inserted into MPEG Streams
- */
-
-/*
- * V4L2_MPEG_STREAM_VBI_FMT_IVTV:
- *
- * Structure of payload contained in an MPEG 2 Private Stream 1 PES Packet in an
- * MPEG-2 Program Pack that contains V4L2_MPEG_STREAM_VBI_FMT_IVTV Sliced VBI
- * data
- *
- * Note, the MPEG-2 Program Pack and Private Stream 1 PES packet header
- * definitions are not included here.  See the MPEG-2 specifications for details
- * on these headers.
- */
-
-/* Line type IDs */
-#define V4L2_MPEG_VBI_IVTV_TELETEXT_B     (1)
-#define V4L2_MPEG_VBI_IVTV_CAPTION_525    (4)
-#define V4L2_MPEG_VBI_IVTV_WSS_625        (5)
-#define V4L2_MPEG_VBI_IVTV_VPS            (7)
-
-struct <link linkend="v4l2-mpeg-vbi-itv0-line">v4l2_mpeg_vbi_itv0_line</link> {
-        __u8 id;        /* One of V4L2_MPEG_VBI_IVTV_* above */
-        __u8 data[42];  /* Sliced VBI data for the line */
-} __attribute__ ((packed));
-
-struct <link linkend="v4l2-mpeg-vbi-itv0">v4l2_mpeg_vbi_itv0</link> {
-        __le32 linemask[2]; /* Bitmasks of VBI service lines present */
-        struct <link linkend="v4l2-mpeg-vbi-itv0-line">v4l2_mpeg_vbi_itv0_line</link> line[35];
-} __attribute__ ((packed));
-
-struct <link linkend="v4l2-mpeg-vbi-itv0-1">v4l2_mpeg_vbi_ITV0</link> {
-        struct <link linkend="v4l2-mpeg-vbi-itv0-line">v4l2_mpeg_vbi_itv0_line</link> line[36];
-} __attribute__ ((packed));
-
-#define V4L2_MPEG_VBI_IVTV_MAGIC0       "itv0"
-#define V4L2_MPEG_VBI_IVTV_MAGIC1       "ITV0"
-
-struct <link linkend="v4l2-mpeg-vbi-fmt-ivtv">v4l2_mpeg_vbi_fmt_ivtv</link> {
-        __u8 magic[4];
-        union {
-                struct <link linkend="v4l2-mpeg-vbi-itv0">v4l2_mpeg_vbi_itv0</link> itv0;
-                struct <link linkend="v4l2-mpeg-vbi-itv0-1">v4l2_mpeg_vbi_ITV0</link> ITV0;
-        };
-} __attribute__ ((packed));
-
-/*
- *      A G G R E G A T E   S T R U C T U R E S
- */
-
-/**
- * struct <link linkend="v4l2-plane-pix-format">v4l2_plane_pix_format</link> - additional, per-plane format definition
- * @sizeimage:          maximum size in bytes required for data, for which
- *                      this plane will be used
- * @bytesperline:       distance in bytes between the leftmost pixels in two
- *                      adjacent lines
- */
-struct <link linkend="v4l2-plane-pix-format">v4l2_plane_pix_format</link> {
-        __u32           sizeimage;
-        __u16           bytesperline;
-        __u16           reserved[7];
-} __attribute__ ((packed));
-
-/**
- * struct <link linkend="v4l2-pix-format-mplane">v4l2_pix_format_mplane</link> - multiplanar format definition
- * @width:              image width in pixels
- * @height:             image height in pixels
- * @pixelformat:        little endian four character code (fourcc)
- * @field:              field order (for interlaced video)
- * @colorspace:         supplemental to pixelformat
- * @plane_fmt:          per-plane information
- * @num_planes:         number of planes for this format
- */
-struct <link linkend="v4l2-pix-format-mplane">v4l2_pix_format_mplane</link> {
-        __u32                           width;
-        __u32                           height;
-        __u32                           pixelformat;
-        enum <link linkend="v4l2-field">v4l2_field</link>                 field;
-        enum <link linkend="v4l2-colorspace">v4l2_colorspace</link>            colorspace;
-
-        struct <link linkend="v4l2-plane-pix-format">v4l2_plane_pix_format</link>    plane_fmt[VIDEO_MAX_PLANES];
-        __u8                            num_planes;
-        __u8                            reserved[11];
-} __attribute__ ((packed));
-
-/**
- * struct <link linkend="v4l2-format">v4l2_format</link> - stream data format
- * @type:       type of the data stream
- * @pix:        definition of an image format
- * @pix_mp:     definition of a multiplanar image format
- * @win:        definition of an overlaid image
- * @vbi:        raw VBI capture or output parameters
- * @sliced:     sliced VBI capture or output parameters
- * @raw_data:   placeholder for future extensions and custom formats
- */
-struct <link linkend="v4l2-format">v4l2_format</link> {
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
-        union {
-                struct <link linkend="v4l2-pix-format">v4l2_pix_format</link>          pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
-                struct <link linkend="v4l2-pix-format-mplane">v4l2_pix_format_mplane</link>   pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
-                struct <link linkend="v4l2-window">v4l2_window</link>              win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
-                struct <link linkend="v4l2-vbi-format">v4l2_vbi_format</link>          vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
-                struct <link linkend="v4l2-sliced-vbi-format">v4l2_sliced_vbi_format</link>   sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
-                __u8    raw_data[200];                   /* user-defined */
-        } fmt;
-};
-
-/*      Stream type-dependent parameters
- */
-struct <link linkend="v4l2-streamparm">v4l2_streamparm</link> {
-        enum <link linkend="v4l2-buf-type">v4l2_buf_type</link> type;
-        union {
-                struct <link linkend="v4l2-captureparm">v4l2_captureparm</link> capture;
-                struct <link linkend="v4l2-outputparm">v4l2_outputparm</link>  output;
-                __u8    raw_data[200];  /* user-defined */
-        } parm;
-};
-
-/*
- *      E V E N T S
- */
-
-#define V4L2_EVENT_ALL                          0
-#define V4L2_EVENT_VSYNC                        1
-#define V4L2_EVENT_EOS                          2
-#define V4L2_EVENT_PRIVATE_START                0x08000000
-
-/* Payload for V4L2_EVENT_VSYNC */
-struct <link linkend="v4l2-event-vsync">v4l2_event_vsync</link> {
-        /* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */
-        __u8 field;
-} __attribute__ ((packed));
-
-struct <link linkend="v4l2-event">v4l2_event</link> {
-        __u32                           type;
-        union {
-                struct <link linkend="v4l2-event-vsync">v4l2_event_vsync</link> vsync;
-                __u8                    data[64];
-        } u;
-        __u32                           pending;
-        __u32                           sequence;
-        struct timespec                 timestamp;
-        __u32                           reserved[9];
-};
-
-struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link> {
-        __u32                           type;
-        __u32                           reserved[7];
-};
-
-/*
- *      A D V A N C E D   D E B U G G I N G
- *
- *      NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS!
- *      FOR DEBUGGING, TESTING AND INTERNAL USE ONLY!
- */
-
-/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */
-
-#define V4L2_CHIP_MATCH_HOST       0  /* Match against chip ID on host (0 for the host) */
-#define V4L2_CHIP_MATCH_I2C_DRIVER 1  /* Match against I2C driver name */
-#define V4L2_CHIP_MATCH_I2C_ADDR   2  /* Match against I2C 7-bit address */
-#define V4L2_CHIP_MATCH_AC97       3  /* Match against anciliary AC97 chip */
-
-struct <link linkend="v4l2-dbg-match">v4l2_dbg_match</link> {
-        __u32 type; /* Match type */
-        union {     /* Match this chip, meaning determined by type */
-                __u32 addr;
-                char name[32];
-        };
-} __attribute__ ((packed));
-
-struct <link linkend="v4l2-dbg-register">v4l2_dbg_register</link> {
-        struct <link linkend="v4l2-dbg-match">v4l2_dbg_match</link> match;
-        __u32 size;     /* register size in bytes */
-        __u64 reg;
-        __u64 val;
-} __attribute__ ((packed));
-
-/* VIDIOC_DBG_G_CHIP_IDENT */
-struct <link linkend="v4l2-dbg-chip-ident">v4l2_dbg_chip_ident</link> {
-        struct <link linkend="v4l2-dbg-match">v4l2_dbg_match</link> match;
-        __u32 ident;       /* chip identifier as specified in &lt;media/v4l2-chip-ident.h&gt; */
-        __u32 revision;    /* chip revision, chip specific */
-} __attribute__ ((packed));
-
-/*
- *      I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
- *
- */
-#define VIDIOC_QUERYCAP          _IOR('V',  0, struct <link linkend="v4l2-capability">v4l2_capability</link>)
-#define VIDIOC_RESERVED           _IO('V',  1)
-#define VIDIOC_ENUM_FMT         _IOWR('V',  2, struct <link linkend="v4l2-fmtdesc">v4l2_fmtdesc</link>)
-#define VIDIOC_G_FMT            _IOWR('V',  4, struct <link linkend="v4l2-format">v4l2_format</link>)
-#define VIDIOC_S_FMT            _IOWR('V',  5, struct <link linkend="v4l2-format">v4l2_format</link>)
-#define VIDIOC_REQBUFS          _IOWR('V',  8, struct <link linkend="v4l2-requestbuffers">v4l2_requestbuffers</link>)
-#define VIDIOC_QUERYBUF         _IOWR('V',  9, struct <link linkend="v4l2-buffer">v4l2_buffer</link>)
-#define VIDIOC_G_FBUF            _IOR('V', 10, struct <link linkend="v4l2-framebuffer">v4l2_framebuffer</link>)
-#define VIDIOC_S_FBUF            _IOW('V', 11, struct <link linkend="v4l2-framebuffer">v4l2_framebuffer</link>)
-#define VIDIOC_OVERLAY           _IOW('V', 14, int)
-#define VIDIOC_QBUF             _IOWR('V', 15, struct <link linkend="v4l2-buffer">v4l2_buffer</link>)
-#define VIDIOC_DQBUF            _IOWR('V', 17, struct <link linkend="v4l2-buffer">v4l2_buffer</link>)
-#define VIDIOC_STREAMON          _IOW('V', 18, int)
-#define VIDIOC_STREAMOFF         _IOW('V', 19, int)
-#define VIDIOC_G_PARM           _IOWR('V', 21, struct <link linkend="v4l2-streamparm">v4l2_streamparm</link>)
-#define VIDIOC_S_PARM           _IOWR('V', 22, struct <link linkend="v4l2-streamparm">v4l2_streamparm</link>)
-#define VIDIOC_G_STD             _IOR('V', 23, v4l2_std_id)
-#define VIDIOC_S_STD             _IOW('V', 24, v4l2_std_id)
-#define VIDIOC_ENUMSTD          _IOWR('V', 25, struct <link linkend="v4l2-standard">v4l2_standard</link>)
-#define VIDIOC_ENUMINPUT        _IOWR('V', 26, struct <link linkend="v4l2-input">v4l2_input</link>)
-#define VIDIOC_G_CTRL           _IOWR('V', 27, struct <link linkend="v4l2-control">v4l2_control</link>)
-#define VIDIOC_S_CTRL           _IOWR('V', 28, struct <link linkend="v4l2-control">v4l2_control</link>)
-#define VIDIOC_G_TUNER          _IOWR('V', 29, struct <link linkend="v4l2-tuner">v4l2_tuner</link>)
-#define VIDIOC_S_TUNER           _IOW('V', 30, struct <link linkend="v4l2-tuner">v4l2_tuner</link>)
-#define VIDIOC_G_AUDIO           _IOR('V', 33, struct <link linkend="v4l2-audio">v4l2_audio</link>)
-#define VIDIOC_S_AUDIO           _IOW('V', 34, struct <link linkend="v4l2-audio">v4l2_audio</link>)
-#define VIDIOC_QUERYCTRL        _IOWR('V', 36, struct <link linkend="v4l2-queryctrl">v4l2_queryctrl</link>)
-#define VIDIOC_QUERYMENU        _IOWR('V', 37, struct <link linkend="v4l2-querymenu">v4l2_querymenu</link>)
-#define VIDIOC_G_INPUT           _IOR('V', 38, int)
-#define VIDIOC_S_INPUT          _IOWR('V', 39, int)
-#define VIDIOC_G_OUTPUT          _IOR('V', 46, int)
-#define VIDIOC_S_OUTPUT         _IOWR('V', 47, int)
-#define VIDIOC_ENUMOUTPUT       _IOWR('V', 48, struct <link linkend="v4l2-output">v4l2_output</link>)
-#define VIDIOC_G_AUDOUT          _IOR('V', 49, struct <link linkend="v4l2-audioout">v4l2_audioout</link>)
-#define VIDIOC_S_AUDOUT          _IOW('V', 50, struct <link linkend="v4l2-audioout">v4l2_audioout</link>)
-#define VIDIOC_G_MODULATOR      _IOWR('V', 54, struct <link linkend="v4l2-modulator">v4l2_modulator</link>)
-#define VIDIOC_S_MODULATOR       _IOW('V', 55, struct <link linkend="v4l2-modulator">v4l2_modulator</link>)
-#define VIDIOC_G_FREQUENCY      _IOWR('V', 56, struct <link linkend="v4l2-frequency">v4l2_frequency</link>)
-#define VIDIOC_S_FREQUENCY       _IOW('V', 57, struct <link linkend="v4l2-frequency">v4l2_frequency</link>)
-#define VIDIOC_CROPCAP          _IOWR('V', 58, struct <link linkend="v4l2-cropcap">v4l2_cropcap</link>)
-#define VIDIOC_G_CROP           _IOWR('V', 59, struct <link linkend="v4l2-crop">v4l2_crop</link>)
-#define VIDIOC_S_CROP            _IOW('V', 60, struct <link linkend="v4l2-crop">v4l2_crop</link>)
-#define VIDIOC_G_JPEGCOMP        _IOR('V', 61, struct <link linkend="v4l2-jpegcompression">v4l2_jpegcompression</link>)
-#define VIDIOC_S_JPEGCOMP        _IOW('V', 62, struct <link linkend="v4l2-jpegcompression">v4l2_jpegcompression</link>)
-#define VIDIOC_QUERYSTD          _IOR('V', 63, v4l2_std_id)
-#define VIDIOC_TRY_FMT          _IOWR('V', 64, struct <link linkend="v4l2-format">v4l2_format</link>)
-#define VIDIOC_ENUMAUDIO        _IOWR('V', 65, struct <link linkend="v4l2-audio">v4l2_audio</link>)
-#define VIDIOC_ENUMAUDOUT       _IOWR('V', 66, struct <link linkend="v4l2-audioout">v4l2_audioout</link>)
-#define VIDIOC_G_PRIORITY        _IOR('V', 67, enum <link linkend="v4l2-priority">v4l2_priority</link>)
-#define VIDIOC_S_PRIORITY        _IOW('V', 68, enum <link linkend="v4l2-priority">v4l2_priority</link>)
-#define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct <link linkend="v4l2-sliced-vbi-cap">v4l2_sliced_vbi_cap</link>)
-#define VIDIOC_LOG_STATUS         _IO('V', 70)
-#define VIDIOC_G_EXT_CTRLS      _IOWR('V', 71, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
-#define VIDIOC_S_EXT_CTRLS      _IOWR('V', 72, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
-#define VIDIOC_TRY_EXT_CTRLS    _IOWR('V', 73, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
-#if 1
-#define VIDIOC_ENUM_FRAMESIZES  _IOWR('V', 74, struct <link linkend="v4l2-frmsizeenum">v4l2_frmsizeenum</link>)
-#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct <link linkend="v4l2-frmivalenum">v4l2_frmivalenum</link>)
-#define VIDIOC_G_ENC_INDEX       _IOR('V', 76, struct <link linkend="v4l2-enc-idx">v4l2_enc_idx</link>)
-#define VIDIOC_ENCODER_CMD      _IOWR('V', 77, struct <link linkend="v4l2-encoder-cmd">v4l2_encoder_cmd</link>)
-#define VIDIOC_TRY_ENCODER_CMD  _IOWR('V', 78, struct <link linkend="v4l2-encoder-cmd">v4l2_encoder_cmd</link>)
-#endif
-
-#if 1
-/* Experimental, meant for debugging, testing and internal use.
-   Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
-   You must be root to use these ioctls. Never use these in applications! */
-#define VIDIOC_DBG_S_REGISTER    _IOW('V', 79, struct <link linkend="v4l2-dbg-register">v4l2_dbg_register</link>)
-#define VIDIOC_DBG_G_REGISTER   _IOWR('V', 80, struct <link linkend="v4l2-dbg-register">v4l2_dbg_register</link>)
-
-/* Experimental, meant for debugging, testing and internal use.
-   Never use this ioctl in applications! */
-#define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct <link linkend="v4l2-dbg-chip-ident">v4l2_dbg_chip_ident</link>)
-#endif
-
-#define VIDIOC_S_HW_FREQ_SEEK    _IOW('V', 82, struct <link linkend="v4l2-hw-freq-seek">v4l2_hw_freq_seek</link>)
-#define VIDIOC_ENUM_DV_PRESETS  _IOWR('V', 83, struct <link linkend="v4l2-dv-enum-preset">v4l2_dv_enum_preset</link>)
-#define VIDIOC_S_DV_PRESET      _IOWR('V', 84, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
-#define VIDIOC_G_DV_PRESET      _IOWR('V', 85, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
-#define VIDIOC_QUERY_DV_PRESET  _IOR('V',  86, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
-#define VIDIOC_S_DV_TIMINGS     _IOWR('V', 87, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>)
-#define VIDIOC_G_DV_TIMINGS     _IOWR('V', 88, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>)
-#define VIDIOC_DQEVENT           _IOR('V', 89, struct <link linkend="v4l2-event">v4l2_event</link>)
-#define VIDIOC_SUBSCRIBE_EVENT   _IOW('V', 90, struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link>)
-#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link>)
-
-/* Reminder: when adding new ioctls please add support for them to
-   drivers/media/video/v4l2-compat-ioctl32.c as well! */
-
-#define BASE_VIDIOC_PRIVATE     192             /* 192-255 are private */
-
-#endif /* __LINUX_VIDEODEV2_H */
-</programlisting>
diff --git a/Documentation/DocBook/v4l/vidioc-cropcap.xml b/Documentation/DocBook/v4l/vidioc-cropcap.xml
deleted file mode 100644 (file)
index 816e90e..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-<refentry id="vidioc-cropcap">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_CROPCAP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_CROPCAP</refname>
-    <refpurpose>Information about the video cropping and scaling abilities</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_cropcap
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_CROPCAP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Applications use this function to query the cropping
-limits, the pixel aspect of images and to calculate scale factors.
-They set the <structfield>type</structfield> field of a v4l2_cropcap
-structure to the respective buffer (stream) type and call the
-<constant>VIDIOC_CROPCAP</constant> ioctl with a pointer to this
-structure. Drivers fill the rest of the structure. The results are
-constant except when switching the video standard. Remember this
-switch can occur implicit when switching the video input or
-output.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-cropcap">
-      <title>struct <structname>v4l2_cropcap</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>&v4l2-buf-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the data stream, set by the application.
-Only these types are valid here:
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
-defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
-and higher.</entry>
-         </row>
-         <row>
-           <entry>struct <link linkend="v4l2-rect-crop">v4l2_rect</link></entry>
-           <entry><structfield>bounds</structfield></entry>
-           <entry>Defines the window within capturing or output is
-possible, this may exclude for example the horizontal and vertical
-blanking areas. The cropping rectangle cannot exceed these limits.
-Width and height are defined in pixels, the driver writer is free to
-choose origin and units of the coordinate system in the analog
-domain.</entry>
-         </row>
-         <row>
-           <entry>struct <link linkend="v4l2-rect-crop">v4l2_rect</link></entry>
-           <entry><structfield>defrect</structfield></entry>
-           <entry>Default cropping rectangle, it shall cover the
-"whole picture". Assuming pixel aspect 1/1 this could be for example a
-640&nbsp;&times;&nbsp;480 rectangle for NTSC, a
-768&nbsp;&times;&nbsp;576 rectangle for PAL and SECAM centered over
-the active picture area. The same co-ordinate system as for
-           <structfield>bounds</structfield> is used.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>pixelaspect</structfield></entry>
-           <entry><para>This is the pixel aspect (y / x) when no
-scaling is applied, the ratio of the actual sampling
-frequency and the frequency required to get square
-pixels.</para><para>When cropping coordinates refer to square pixels,
-the driver sets <structfield>pixelaspect</structfield> to 1/1. Other
-common values are 54/59 for PAL and SECAM, 11/10 for NTSC sampled
-according to [<xref linkend="itu601" />].</para></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- NB this table is duplicated in the overlay chapter. -->
-
-    <table pgwide="1" frame="none" id="v4l2-rect-crop">
-      <title>struct <structname>v4l2_rect</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>left</structfield></entry>
-           <entry>Horizontal offset of the top, left corner of the
-rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>top</structfield></entry>
-           <entry>Vertical offset of the top, left corner of the
-rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the rectangle, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the rectangle, in pixels. Width
-and height cannot be negative, the fields are signed for
-hysterical reasons. <!-- video4linux-list@redhat.com
-on 22 Oct 2002 subject "Re:[V4L][patches!] Re:v4l2/kernel-2.5" -->
-</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-cropcap; <structfield>type</structfield> is
-invalid or the ioctl is not supported. This is not permitted for
-video capture, output and overlay devices, which must support
-<constant>VIDIOC_CROPCAP</constant>.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-dbg-g-chip-ident.xml b/Documentation/DocBook/v4l/vidioc-dbg-g-chip-ident.xml
deleted file mode 100644 (file)
index 4a09e20..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-<refentry id="vidioc-dbg-g-chip-ident">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_DBG_G_CHIP_IDENT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_DBG_G_CHIP_IDENT</refname>
-    <refpurpose>Identify the chips on a TV card</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_dbg_chip_ident
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_DBG_G_CHIP_IDENT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-
-      <para>This is an <link
-linkend="experimental">experimental</link> interface and may change in
-the future.</para>
-    </note>
-
-    <para>For driver debugging purposes this ioctl allows test
-applications to query the driver about the chips present on the TV
-card. Regular applications must not use it. When you found a chip
-specific bug, please contact the linux-media mailing list (&v4l-ml;)
-so it can be fixed.</para>
-
-    <para>To query the driver applications must initialize the
-<structfield>match.type</structfield> and
-<structfield>match.addr</structfield> or <structfield>match.name</structfield>
-fields of a &v4l2-dbg-chip-ident;
-and call <constant>VIDIOC_DBG_G_CHIP_IDENT</constant> with a pointer to
-this structure. On success the driver stores information about the
-selected chip in the <structfield>ident</structfield> and
-<structfield>revision</structfield> fields. On failure the structure
-remains unchanged.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_HOST</constant>,
-<structfield>match.addr</structfield> selects the nth non-&i2c; chip
-on the TV card. You can enumerate all chips by starting at zero and
-incrementing <structfield>match.addr</structfield> by one until
-<constant>VIDIOC_DBG_G_CHIP_IDENT</constant> fails with an &EINVAL;.
-The number zero always selects the host chip, &eg; the chip connected
-to the PCI or USB bus.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant>,
-<structfield>match.name</structfield> contains the I2C driver name.
-For instance
-<constant>"saa7127"</constant> will match any chip
-supported by the saa7127 driver, regardless of its &i2c; bus address.
-When multiple chips supported by the same driver are present, the
-ioctl will return <constant>V4L2_IDENT_AMBIGUOUS</constant> in the
-<structfield>ident</structfield> field.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_I2C_ADDR</constant>,
-<structfield>match.addr</structfield> selects a chip by its 7 bit
-&i2c; bus address.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_AC97</constant>,
-<structfield>match.addr</structfield> selects the nth AC97 chip
-on the TV card. You can enumerate all chips by starting at zero and
-incrementing <structfield>match.addr</structfield> by one until
-<constant>VIDIOC_DBG_G_CHIP_IDENT</constant> fails with an &EINVAL;.</para>
-
-    <para>On success, the <structfield>ident</structfield> field will
-contain a chip ID from the Linux
-<filename>media/v4l2-chip-ident.h</filename> header file, and the
-<structfield>revision</structfield> field will contain a driver
-specific value, or zero if no particular revision is associated with
-this chip.</para>
-
-    <para>When the driver could not identify the selected chip,
-<structfield>ident</structfield> will contain
-<constant>V4L2_IDENT_UNKNOWN</constant>. When no chip matched
-the ioctl will succeed but the
-<structfield>ident</structfield> field will contain
-<constant>V4L2_IDENT_NONE</constant>. If multiple chips matched,
-<structfield>ident</structfield> will contain
-<constant>V4L2_IDENT_AMBIGUOUS</constant>. In all these cases the
-<structfield>revision</structfield> field remains unchanged.</para>
-
-    <para>This ioctl is optional, not all drivers may support it. It
-was introduced in Linux 2.6.21, but the API was changed to the
-one described here in 2.6.29.</para>
-
-    <para>We recommended the <application>v4l2-dbg</application>
-utility over calling this ioctl directly. It is available from the
-LinuxTV v4l-dvb repository; see <ulink
-url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
-access instructions.</para>
-
-    <!-- Note for convenience vidioc-dbg-g-register.sgml
-        contains a duplicate of this table. -->
-    <table pgwide="1" frame="none" id="ident-v4l2-dbg-match">
-      <title>struct <structname>v4l2_dbg_match</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>See <xref linkend="ident-chip-match-types" /> for a list of
-possible types.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry>(anonymous)</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>addr</structfield></entry>
-           <entry>Match a chip by this number, interpreted according
-to the <structfield>type</structfield> field.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>char</entry>
-           <entry><structfield>name[32]</structfield></entry>
-           <entry>Match a chip by this name, interpreted according
-to the <structfield>type</structfield> field.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-dbg-chip-ident">
-      <title>struct <structname>v4l2_dbg_chip_ident</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>struct v4l2_dbg_match</entry>
-           <entry><structfield>match</structfield></entry>
-           <entry>How to match the chip, see <xref linkend="ident-v4l2-dbg-match" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>ident</structfield></entry>
-           <entry>A chip identifier as defined in the Linux
-<filename>media/v4l2-chip-ident.h</filename> header file, or one of
-the values from <xref linkend="chip-ids" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>revision</structfield></entry>
-           <entry>A chip revision, chip and driver specific.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- Note for convenience vidioc-dbg-g-register.sgml
-        contains a duplicate of this table. -->
-    <table pgwide="1" frame="none" id="ident-chip-match-types">
-      <title>Chip Match Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_HOST</constant></entry>
-           <entry>0</entry>
-           <entry>Match the nth chip on the card, zero for the
-           host chip. Does not match &i2c; chips.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant></entry>
-           <entry>1</entry>
-           <entry>Match an &i2c; chip by its driver name.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_I2C_ADDR</constant></entry>
-           <entry>2</entry>
-           <entry>Match a chip by its 7 bit &i2c; bus address.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_AC97</constant></entry>
-           <entry>3</entry>
-           <entry>Match the nth anciliary AC97 chip.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- This is an anonymous enum in media/v4l2-chip-ident.h. -->
-    <table pgwide="1" frame="none" id="chip-ids">
-      <title>Chip Identifiers</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_IDENT_NONE</constant></entry>
-           <entry>0</entry>
-           <entry>No chip matched.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IDENT_AMBIGUOUS</constant></entry>
-           <entry>1</entry>
-           <entry>Multiple chips matched.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IDENT_UNKNOWN</constant></entry>
-           <entry>2</entry>
-           <entry>A chip is present at this address, but the driver
-could not identify it.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The driver does not support this ioctl, or the
-<structfield>match_type</structfield> is invalid.</para>
-       </listitem>
-      </varlistentry>
-     </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-dbg-g-register.xml b/Documentation/DocBook/v4l/vidioc-dbg-g-register.xml
deleted file mode 100644 (file)
index 980c7f3..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-<refentry id="vidioc-dbg-g-register">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_DBG_G_REGISTER</refname>
-    <refname>VIDIOC_DBG_S_REGISTER</refname>
-    <refpurpose>Read or write hardware registers</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_dbg_register *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_dbg_register
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_DBG_G_REGISTER, VIDIOC_DBG_S_REGISTER</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-
-      <para>This is an <link linkend="experimental">experimental</link>
-interface and may change in the future.</para>
-    </note>
-
-    <para>For driver debugging purposes these ioctls allow test
-applications to access hardware registers directly. Regular
-applications must not use them.</para>
-
-    <para>Since writing or even reading registers can jeopardize the
-system security, its stability and damage the hardware, both ioctls
-require superuser privileges. Additionally the Linux kernel must be
-compiled with the <constant>CONFIG_VIDEO_ADV_DEBUG</constant> option
-to enable these ioctls.</para>
-
-    <para>To write a register applications must initialize all fields
-of a &v4l2-dbg-register; and call
-<constant>VIDIOC_DBG_S_REGISTER</constant> with a pointer to this
-structure. The <structfield>match.type</structfield> and
-<structfield>match.addr</structfield> or <structfield>match.name</structfield>
-fields select a chip on the TV
-card, the <structfield>reg</structfield> field specifies a register
-number and the <structfield>val</structfield> field the value to be
-written into the register.</para>
-
-    <para>To read a register applications must initialize the
-<structfield>match.type</structfield>,
-<structfield>match.chip</structfield> or <structfield>match.name</structfield> and
-<structfield>reg</structfield> fields, and call
-<constant>VIDIOC_DBG_G_REGISTER</constant> with a pointer to this
-structure. On success the driver stores the register value in the
-<structfield>val</structfield> field. On failure the structure remains
-unchanged.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_HOST</constant>,
-<structfield>match.addr</structfield> selects the nth non-&i2c; chip
-on the TV card.  The number zero always selects the host chip, &eg; the
-chip connected to the PCI or USB bus. You can find out which chips are
-present with the &VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant>,
-<structfield>match.name</structfield> contains the I2C driver name.
-For instance
-<constant>"saa7127"</constant> will match any chip
-supported by the saa7127 driver, regardless of its &i2c; bus address.
-When multiple chips supported by the same driver are present, the
-effect of these ioctls is undefined. Again with the
-&VIDIOC-DBG-G-CHIP-IDENT; ioctl you can find out which &i2c; chips are
-present.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_I2C_ADDR</constant>,
-<structfield>match.addr</structfield> selects a chip by its 7 bit &i2c;
-bus address.</para>
-
-    <para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_AC97</constant>,
-<structfield>match.addr</structfield> selects the nth AC97 chip
-on the TV card.</para>
-
-    <note>
-      <title>Success not guaranteed</title>
-
-      <para>Due to a flaw in the Linux &i2c; bus driver these ioctls may
-return successfully without actually reading or writing a register. To
-catch the most likely failure we recommend a &VIDIOC-DBG-G-CHIP-IDENT;
-call confirming the presence of the selected &i2c; chip.</para>
-    </note>
-
-    <para>These ioctls are optional, not all drivers may support them.
-However when a driver supports these ioctls it must also support
-&VIDIOC-DBG-G-CHIP-IDENT;. Conversely it may support
-<constant>VIDIOC_DBG_G_CHIP_IDENT</constant> but not these ioctls.</para>
-
-    <para><constant>VIDIOC_DBG_G_REGISTER</constant> and
-<constant>VIDIOC_DBG_S_REGISTER</constant> were introduced in Linux
-2.6.21, but their API was changed to the one described here in kernel 2.6.29.</para>
-
-    <para>We recommended the <application>v4l2-dbg</application>
-utility over calling these ioctls directly. It is available from the
-LinuxTV v4l-dvb repository; see <ulink
-url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
-access instructions.</para>
-
-    <!-- Note for convenience vidioc-dbg-g-chip-ident.sgml
-        contains a duplicate of this table. -->
-    <table pgwide="1" frame="none" id="v4l2-dbg-match">
-      <title>struct <structname>v4l2_dbg_match</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>See <xref linkend="ident-chip-match-types" /> for a list of
-possible types.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry>(anonymous)</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>addr</structfield></entry>
-           <entry>Match a chip by this number, interpreted according
-to the <structfield>type</structfield> field.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>char</entry>
-           <entry><structfield>name[32]</structfield></entry>
-           <entry>Match a chip by this name, interpreted according
-to the <structfield>type</structfield> field.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-
-    <table pgwide="1" frame="none" id="v4l2-dbg-register">
-      <title>struct <structname>v4l2_dbg_register</structname></title>
-      <tgroup cols="4">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c4" />
-       <tbody valign="top">
-         <row>
-           <entry>struct v4l2_dbg_match</entry>
-           <entry><structfield>match</structfield></entry>
-           <entry>How to match the chip, see <xref linkend="v4l2-dbg-match" />.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>reg</structfield></entry>
-           <entry>A register number.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>val</structfield></entry>
-           <entry>The value read from, or to be written into the
-register.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- Note for convenience vidioc-dbg-g-chip-ident.sgml
-        contains a duplicate of this table. -->
-    <table pgwide="1" frame="none" id="chip-match-types">
-      <title>Chip Match Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_HOST</constant></entry>
-           <entry>0</entry>
-           <entry>Match the nth chip on the card, zero for the
-           host chip. Does not match &i2c; chips.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant></entry>
-           <entry>1</entry>
-           <entry>Match an &i2c; chip by its driver name.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_I2C_ADDR</constant></entry>
-           <entry>2</entry>
-           <entry>Match a chip by its 7 bit &i2c; bus address.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CHIP_MATCH_AC97</constant></entry>
-           <entry>3</entry>
-           <entry>Match the nth anciliary AC97 chip.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The driver does not support this ioctl, or the kernel
-was not compiled with the <constant>CONFIG_VIDEO_ADV_DEBUG</constant>
-option, or the <structfield>match_type</structfield> is invalid, or the
-selected chip or register does not exist.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EPERM</errorcode></term>
-       <listitem>
-         <para>Insufficient permissions. Root privileges are required
-to execute these ioctls.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-dqevent.xml b/Documentation/DocBook/v4l/vidioc-dqevent.xml
deleted file mode 100644 (file)
index 4e0a7cc..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-<refentry id="vidioc-dqevent">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_DQEVENT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_DQEVENT</refname>
-    <refpurpose>Dequeue event</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_event
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_DQEVENT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Dequeue an event from a video device. No input is required
-    for this ioctl. All the fields of the &v4l2-event; structure are
-    filled by the driver. The file handle will also receive exceptions
-    which the application may get by e.g. using the select system
-    call.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-event">
-      <title>struct <structname>v4l2_event</structname></title>
-      <tgroup cols="4">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-            <entry></entry>
-           <entry>Type of the event.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield>u</structfield></entry>
-            <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-event-vsync;</entry>
-            <entry><structfield>vsync</structfield></entry>
-           <entry>Event data for event V4L2_EVENT_VSYNC.
-            </entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u8</entry>
-            <entry><structfield>data</structfield>[64]</entry>
-           <entry>Event data. Defined by the event type. The union
-            should be used to define easily accessible type for
-            events.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pending</structfield></entry>
-            <entry></entry>
-           <entry>Number of pending events excluding this one.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>sequence</structfield></entry>
-            <entry></entry>
-           <entry>Event sequence number. The sequence number is
-           incremented for every subscribed event that takes place.
-           If sequence numbers are not contiguous it means that
-           events have been lost.
-           </entry>
-         </row>
-         <row>
-           <entry>struct timespec</entry>
-           <entry><structfield>timestamp</structfield></entry>
-            <entry></entry>
-           <entry>Event timestamp.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[9]</entry>
-            <entry></entry>
-           <entry>Reserved for future extensions. Drivers must set
-           the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-</refentry>
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-encoder-cmd.xml b/Documentation/DocBook/v4l/vidioc-encoder-cmd.xml
deleted file mode 100644 (file)
index b0dde94..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-<refentry id="vidioc-encoder-cmd">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENCODER_CMD</refname>
-    <refname>VIDIOC_TRY_ENCODER_CMD</refname>
-    <refpurpose>Execute an encoder command</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_encoder_cmd *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_ENCODER_CMD, VIDIOC_TRY_ENCODER_CMD</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-
-      <para>This is an <link linkend="experimental">experimental</link>
-interface and may change in the future.</para>
-    </note>
-
-    <para>These ioctls control an audio/video (usually MPEG-) encoder.
-<constant>VIDIOC_ENCODER_CMD</constant> sends a command to the
-encoder, <constant>VIDIOC_TRY_ENCODER_CMD</constant> can be used to
-try a command without actually executing it.</para>
-
-    <para>To send a command applications must initialize all fields of a
-    &v4l2-encoder-cmd; and call
-    <constant>VIDIOC_ENCODER_CMD</constant> or
-    <constant>VIDIOC_TRY_ENCODER_CMD</constant> with a pointer to this
-    structure.</para>
-
-    <para>The <structfield>cmd</structfield> field must contain the
-command code. The <structfield>flags</structfield> field is currently
-only used by the STOP command and contains one bit: If the
-<constant>V4L2_ENC_CMD_STOP_AT_GOP_END</constant> flag is set,
-encoding will continue until the end of the current <wordasword>Group
-Of Pictures</wordasword>, otherwise it will stop immediately.</para>
-
-    <para>A <function>read</function>() call sends a START command to
-the encoder if it has not been started yet. After a STOP command,
-<function>read</function>() calls will read the remaining data
-buffered by the driver. When the buffer is empty,
-<function>read</function>() will return zero and the next
-<function>read</function>() call will restart the encoder.</para>
-
-    <para>A <function>close</function>() call sends an immediate STOP
-to the encoder, and all buffered data is discarded.</para>
-
-    <para>These ioctls are optional, not all drivers may support
-them. They were introduced in Linux 2.6.21.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-encoder-cmd">
-      <title>struct <structname>v4l2_encoder_cmd</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>cmd</structfield></entry>
-           <entry>The encoder command, see <xref linkend="encoder-cmds" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Flags to go with the command, see <xref
-               linkend="encoder-flags" />. If no flags are defined for
-this command, drivers and applications must set this field to
-zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>data</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="encoder-cmds">
-      <title>Encoder Commands</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_ENC_CMD_START</constant></entry>
-           <entry>0</entry>
-           <entry>Start the encoder. When the encoder is already
-running or paused, this command does nothing. No flags are defined for
-this command.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_CMD_STOP</constant></entry>
-           <entry>1</entry>
-           <entry>Stop the encoder. When the
-<constant>V4L2_ENC_CMD_STOP_AT_GOP_END</constant> flag is set,
-encoding will continue until the end of the current <wordasword>Group
-Of Pictures</wordasword>, otherwise encoding will stop immediately.
-When the encoder is already stopped, this command does
-nothing.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_CMD_PAUSE</constant></entry>
-           <entry>2</entry>
-           <entry>Pause the encoder. When the encoder has not been
-started yet, the driver will return an &EPERM;. When the encoder is
-already paused, this command does nothing. No flags are defined for
-this command.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_CMD_RESUME</constant></entry>
-           <entry>3</entry>
-           <entry>Resume encoding after a PAUSE command. When the
-encoder has not been started yet, the driver will return an &EPERM;.
-When the encoder is already running, this command does nothing. No
-flags are defined for this command.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="encoder-flags">
-      <title>Encoder Command Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_ENC_CMD_STOP_AT_GOP_END</constant></entry>
-           <entry>0x0001</entry>
-           <entry>Stop encoding at the end of the current <wordasword>Group Of
-Pictures</wordasword>, rather than immediately.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The driver does not support this ioctl, or the
-<structfield>cmd</structfield> field is invalid.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EPERM</errorcode></term>
-       <listitem>
-         <para>The application sent a PAUSE or RESUME command when
-the encoder was not running.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml b/Documentation/DocBook/v4l/vidioc-enum-dv-presets.xml
deleted file mode 100644 (file)
index 1d31427..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-<refentry id="vidioc-enum-dv-presets">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUM_DV_PRESETS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUM_DV_PRESETS</refname>
-    <refpurpose>Enumerate supported Digital Video presets</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_dv_enum_preset *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_ENUM_DV_PRESETS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a DV preset, applications initialize the
-<structfield>index</structfield> field and zero the reserved array of &v4l2-dv-enum-preset;
-and call the <constant>VIDIOC_ENUM_DV_PRESETS</constant> ioctl with a pointer to this
-structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all DV Presets supported,
-applications shall begin at index zero, incrementing by one until the
-driver returns <errorcode>EINVAL</errorcode>. Drivers may enumerate a
-different set of DV presets after switching the video input or
-output.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-dv-enum-preset">
-      <title>struct <structname>v4l2_dv_enum_presets</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the DV preset, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>preset</structfield></entry>
-           <entry>This field identifies one of the DV preset values listed in <xref linkend="v4l2-dv-presets-vals"/>.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[24]</entry>
-           <entry>Name of the preset, a NUL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is
-intended for the user.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the active video in pixels for the DV preset.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the active video in lines for the DV preset.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-dv-presets-vals">
-      <title>struct <structname>DV Presets</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>Preset</entry>
-           <entry>Preset value</entry>
-           <entry>Description</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_INVALID</entry>
-           <entry>0</entry>
-           <entry>Invalid preset value.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_480P59_94</entry>
-           <entry>1</entry>
-           <entry>720x480 progressive video at 59.94 fps as per BT.1362.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_576P50</entry>
-           <entry>2</entry>
-           <entry>720x576 progressive video at 50 fps as per BT.1362.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_720P24</entry>
-           <entry>3</entry>
-           <entry>1280x720 progressive video at 24 fps as per SMPTE 296M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_720P25</entry>
-           <entry>4</entry>
-           <entry>1280x720 progressive video at 25 fps as per SMPTE 296M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_720P30</entry>
-           <entry>5</entry>
-           <entry>1280x720 progressive video at 30 fps as per SMPTE 296M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_720P50</entry>
-           <entry>6</entry>
-           <entry>1280x720 progressive video at 50 fps as per SMPTE 296M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_720P59_94</entry>
-           <entry>7</entry>
-           <entry>1280x720 progressive video at 59.94 fps as per SMPTE 274M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_720P60</entry>
-           <entry>8</entry>
-           <entry>1280x720 progressive video at 60 fps as per SMPTE 274M/296M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_1080I29_97</entry>
-           <entry>9</entry>
-           <entry>1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_1080I30</entry>
-           <entry>10</entry>
-           <entry>1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_1080I25</entry>
-           <entry>11</entry>
-           <entry>1920x1080 interlaced video at 25 fps as per BT.1120.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_1080I50</entry>
-           <entry>12</entry>
-           <entry>1920x1080 interlaced video at 50 fps as per SMPTE 296M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_1080I60</entry>
-           <entry>13</entry>
-           <entry>1920x1080 interlaced video at 60 fps as per SMPTE 296M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_1080P24</entry>
-           <entry>14</entry>
-           <entry>1920x1080 progressive video at 24 fps as per SMPTE 296M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_1080P25</entry>
-           <entry>15</entry>
-           <entry>1920x1080 progressive video at 25 fps as per SMPTE 296M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_1080P30</entry>
-           <entry>16</entry>
-           <entry>1920x1080 progressive video at 30 fps as per SMPTE 296M.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_1080P50</entry>
-           <entry>17</entry>
-           <entry>1920x1080 progressive video at 50 fps as per BT.1120.</entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_1080P60</entry>
-           <entry>18</entry>
-           <entry>1920x1080 progressive video at 60 fps as per BT.1120.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-dv-enum-preset; <structfield>index</structfield>
-is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-enum-fmt.xml b/Documentation/DocBook/v4l/vidioc-enum-fmt.xml
deleted file mode 100644 (file)
index 71d373b..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-<refentry id="vidioc-enum-fmt">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUM_FMT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUM_FMT</refname>
-    <refpurpose>Enumerate image formats</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_fmtdesc
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_ENUM_FMT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To enumerate image formats applications initialize the
-<structfield>type</structfield> and <structfield>index</structfield>
-field of &v4l2-fmtdesc; and call the
-<constant>VIDIOC_ENUM_FMT</constant> ioctl with a pointer to this
-structure. Drivers fill the rest of the structure or return an
-&EINVAL;. All formats are enumerable by beginning at index zero and
-incrementing by one until <errorcode>EINVAL</errorcode> is
-returned.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-fmtdesc">
-      <title>struct <structname>v4l2_fmtdesc</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the format in the enumeration, set by
-the application. This is in no way related to the <structfield>
-pixelformat</structfield> field.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-buf-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the data stream, set by the application.
-Only these types are valid here:
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
-defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
-and higher.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>See <xref linkend="fmtdesc-flags" /></entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>description</structfield>[32]</entry>
-           <entry>Description of the format, a NUL-terminated ASCII
-string. This information is intended for the user, for example: "YUV
-4:2:2".</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pixelformat</structfield></entry>
-           <entry>The image format identifier. This is a
-four character code as computed by the v4l2_fourcc()
-macro:</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para><programlisting id="v4l2-fourcc">
-#define v4l2_fourcc(a,b,c,d) (((__u32)(a)&lt;&lt;0)|((__u32)(b)&lt;&lt;8)|((__u32)(c)&lt;&lt;16)|((__u32)(d)&lt;&lt;24))
-</programlisting></para><para>Several image formats are already
-defined by this specification in <xref linkend="pixfmt" />. Note these
-codes are not the same as those used in the Windows world.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="fmtdesc-flags">
-      <title>Image Format Description Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FMT_FLAG_COMPRESSED</constant></entry>
-           <entry>0x0001</entry>
-           <entry>This is a compressed format.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FMT_FLAG_EMULATED</constant></entry>
-           <entry>0x0002</entry>
-           <entry>This format is not native to the device but emulated
-through software (usually libv4l2), where possible try to use a native format
-instead for better performance.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-fmtdesc; <structfield>type</structfield>
-is not supported or the <structfield>index</structfield> is out of
-bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-enum-frameintervals.xml b/Documentation/DocBook/v4l/vidioc-enum-frameintervals.xml
deleted file mode 100644 (file)
index 3c216e1..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-<refentry id="vidioc-enum-frameintervals">
-
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUM_FRAMEINTERVALS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUM_FRAMEINTERVALS</refname>
-    <refpurpose>Enumerate frame intervals</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_frmivalenum *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_ENUM_FRAMEINTERVALS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to a &v4l2-frmivalenum; structure that
-contains a pixel format and size and receives a frame interval.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl allows applications to enumerate all frame
-intervals that the device supports for the given pixel format and
-frame size.</para>
-    <para>The supported pixel formats and frame sizes can be obtained
-by using the &VIDIOC-ENUM-FMT; and &VIDIOC-ENUM-FRAMESIZES;
-functions.</para>
-    <para>The return value and the content of the
-<structfield>v4l2_frmivalenum.type</structfield> field depend on the
-type of frame intervals the device supports. Here are the semantics of
-the function for the different cases:</para>
-    <itemizedlist>
-      <listitem>
-       <para><emphasis role="bold">Discrete:</emphasis> The function
-returns success if the given index value (zero-based) is valid. The
-application should increase the index by one for each call until
-<constant>EINVAL</constant> is returned. The `v4l2_frmivalenum.type`
-field is set to `V4L2_FRMIVAL_TYPE_DISCRETE` by the driver. Of the
-union only the `discrete` member is valid.</para>
-      </listitem>
-      <listitem>
-       <para><emphasis role="bold">Step-wise:</emphasis> The function
-returns success if the given index value is zero and
-<constant>EINVAL</constant> for any other index value. The
-<structfield>v4l2_frmivalenum.type</structfield> field is set to
-<constant>V4L2_FRMIVAL_TYPE_STEPWISE</constant> by the driver. Of the
-union only the <structfield>stepwise</structfield> member is
-valid.</para>
-      </listitem>
-      <listitem>
-       <para><emphasis role="bold">Continuous:</emphasis> This is a
-special case of the step-wise type above. The function returns success
-if the given index value is zero and <constant>EINVAL</constant> for
-any other index value. The
-<structfield>v4l2_frmivalenum.type</structfield> field is set to
-<constant>V4L2_FRMIVAL_TYPE_CONTINUOUS</constant> by the driver. Of
-the union only the <structfield>stepwise</structfield> member is valid
-and the <structfield>step</structfield> value is set to 1.</para>
-      </listitem>
-    </itemizedlist>
-
-    <para>When the application calls the function with index zero, it
-must check the <structfield>type</structfield> field to determine the
-type of frame interval enumeration the device supports. Only for the
-<constant>V4L2_FRMIVAL_TYPE_DISCRETE</constant> type does it make
-sense to increase the index value to receive more frame
-intervals.</para>
-    <para>Note that the order in which the frame intervals are
-returned has no special meaning. In particular does it not say
-anything about potential default frame intervals.</para>
-    <para>Applications can assume that the enumeration data does not
-change without any interaction from the application itself. This means
-that the enumeration data is consistent if the application does not
-perform any other ioctl calls while it runs the frame interval
-enumeration.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Notes</title>
-
-    <itemizedlist>
-      <listitem>
-       <para><emphasis role="bold">Frame intervals and frame
-rates:</emphasis> The V4L2 API uses frame intervals instead of frame
-rates. Given the frame interval the frame rate can be computed as
-follows:<screen>frame_rate = 1 / frame_interval</screen></para>
-      </listitem>
-    </itemizedlist>
-
-  </refsect1>
-
-  <refsect1>
-    <title>Structs</title>
-
-    <para>In the structs below, <emphasis>IN</emphasis> denotes a
-value that has to be filled in by the application,
-<emphasis>OUT</emphasis> denotes values that the driver fills in. The
-application should zero out all members except for the
-<emphasis>IN</emphasis> fields.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-frmival-stepwise">
-      <title>struct <structname>v4l2_frmival_stepwise</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>min</structfield></entry>
-           <entry>Minimum frame interval [s].</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>max</structfield></entry>
-           <entry>Maximum frame interval [s].</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>step</structfield></entry>
-           <entry>Frame interval step size [s].</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-frmivalenum">
-      <title>struct <structname>v4l2_frmivalenum</structname></title>
-      <tgroup cols="4">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry></entry>
-           <entry>IN: Index of the given frame interval in the
-enumeration.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pixel_format</structfield></entry>
-           <entry></entry>
-           <entry>IN: Pixel format for which the frame intervals are
-enumerated.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry></entry>
-           <entry>IN: Frame width for which the frame intervals are
-enumerated.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry></entry>
-           <entry>IN: Frame height for which the frame intervals are
-enumerated.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>OUT: Frame interval type the device supports.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>OUT: Frame interval with the given index.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>discrete</structfield></entry>
-           <entry>Frame interval [s].</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-frmival-stepwise;</entry>
-           <entry><structfield>stepwise</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved[2]</structfield></entry>
-           <entry></entry>
-           <entry>Reserved space for future use.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    <title>Enums</title>
-
-    <table pgwide="1" frame="none" id="v4l2-frmivaltypes">
-      <title>enum <structname>v4l2_frmivaltypes</structname></title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FRMIVAL_TYPE_DISCRETE</constant></entry>
-           <entry>1</entry>
-           <entry>Discrete frame interval.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FRMIVAL_TYPE_CONTINUOUS</constant></entry>
-           <entry>2</entry>
-           <entry>Continuous frame interval.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FRMIVAL_TYPE_STEPWISE</constant></entry>
-           <entry>3</entry>
-           <entry>Step-wise defined frame interval.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <para>See the description section above for a list of return
-values that <varname>errno</varname> can have.</para>
-  </refsect1>
-
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-enum-framesizes.xml b/Documentation/DocBook/v4l/vidioc-enum-framesizes.xml
deleted file mode 100644 (file)
index 6afa454..0000000
+++ /dev/null
@@ -1,282 +0,0 @@
-<refentry id="vidioc-enum-framesizes">
-
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUM_FRAMESIZES</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUM_FRAMESIZES</refname>
-    <refpurpose>Enumerate frame sizes</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_frmsizeenum *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_ENUM_FRAMESIZES</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to a &v4l2-frmsizeenum; that contains an index
-and pixel format and receives a frame width and height.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-
-      <para>This is an <link linkend="experimental">experimental</link>
-interface and may change in the future.</para>
-    </note>
-
-    <para>This ioctl allows applications to enumerate all frame sizes
-(&ie; width and height in pixels) that the device supports for the
-given pixel format.</para>
-    <para>The supported pixel formats can be obtained by using the
-&VIDIOC-ENUM-FMT; function.</para>
-    <para>The return value and the content of the
-<structfield>v4l2_frmsizeenum.type</structfield> field depend on the
-type of frame sizes the device supports. Here are the semantics of the
-function for the different cases:</para>
-
-    <itemizedlist>
-      <listitem>
-       <para><emphasis role="bold">Discrete:</emphasis> The function
-returns success if the given index value (zero-based) is valid. The
-application should increase the index by one for each call until
-<constant>EINVAL</constant> is returned. The
-<structfield>v4l2_frmsizeenum.type</structfield> field is set to
-<constant>V4L2_FRMSIZE_TYPE_DISCRETE</constant> by the driver. Of the
-union only the <structfield>discrete</structfield> member is
-valid.</para>
-      </listitem>
-      <listitem>
-       <para><emphasis role="bold">Step-wise:</emphasis> The function
-returns success if the given index value is zero and
-<constant>EINVAL</constant> for any other index value. The
-<structfield>v4l2_frmsizeenum.type</structfield> field is set to
-<constant>V4L2_FRMSIZE_TYPE_STEPWISE</constant> by the driver. Of the
-union only the <structfield>stepwise</structfield> member is
-valid.</para>
-      </listitem>
-      <listitem>
-       <para><emphasis role="bold">Continuous:</emphasis> This is a
-special case of the step-wise type above. The function returns success
-if the given index value is zero and <constant>EINVAL</constant> for
-any other index value. The
-<structfield>v4l2_frmsizeenum.type</structfield> field is set to
-<constant>V4L2_FRMSIZE_TYPE_CONTINUOUS</constant> by the driver. Of
-the union only the <structfield>stepwise</structfield> member is valid
-and the <structfield>step_width</structfield> and
-<structfield>step_height</structfield> values are set to 1.</para>
-      </listitem>
-    </itemizedlist>
-
-    <para>When the application calls the function with index zero, it
-must check the <structfield>type</structfield> field to determine the
-type of frame size enumeration the device supports. Only for the
-<constant>V4L2_FRMSIZE_TYPE_DISCRETE</constant> type does it make
-sense to increase the index value to receive more frame sizes.</para>
-    <para>Note that the order in which the frame sizes are returned
-has no special meaning. In particular does it not say anything about
-potential default format sizes.</para>
-    <para>Applications can assume that the enumeration data does not
-change without any interaction from the application itself. This means
-that the enumeration data is consistent if the application does not
-perform any other ioctl calls while it runs the frame size
-enumeration.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Structs</title>
-
-    <para>In the structs below, <emphasis>IN</emphasis> denotes a
-value that has to be filled in by the application,
-<emphasis>OUT</emphasis> denotes values that the driver fills in. The
-application should zero out all members except for the
-<emphasis>IN</emphasis> fields.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-frmsize-discrete">
-      <title>struct <structname>v4l2_frmsize_discrete</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the frame [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the frame [pixel].</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-frmsize-stepwise">
-      <title>struct <structname>v4l2_frmsize_stepwise</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>min_width</structfield></entry>
-           <entry>Minimum frame width [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>max_width</structfield></entry>
-           <entry>Maximum frame width [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>step_width</structfield></entry>
-           <entry>Frame width step size [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>min_height</structfield></entry>
-           <entry>Minimum frame height [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>max_height</structfield></entry>
-           <entry>Maximum frame height [pixel].</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>step_height</structfield></entry>
-           <entry>Frame height step size [pixel].</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-frmsizeenum">
-      <title>struct <structname>v4l2_frmsizeenum</structname></title>
-      <tgroup cols="4">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry></entry>
-           <entry>IN: Index of the given frame size in the enumeration.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pixel_format</structfield></entry>
-           <entry></entry>
-           <entry>IN: Pixel format for which the frame sizes are enumerated.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>OUT: Frame size type the device supports.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>OUT: Frame size with the given index.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-frmsize-discrete;</entry>
-           <entry><structfield>discrete</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-frmsize-stepwise;</entry>
-           <entry><structfield>stepwise</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved[2]</structfield></entry>
-           <entry></entry>
-           <entry>Reserved space for future use.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    <title>Enums</title>
-
-    <table pgwide="1" frame="none" id="v4l2-frmsizetypes">
-      <title>enum <structname>v4l2_frmsizetypes</structname></title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FRMSIZE_TYPE_DISCRETE</constant></entry>
-           <entry>1</entry>
-           <entry>Discrete frame size.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FRMSIZE_TYPE_CONTINUOUS</constant></entry>
-           <entry>2</entry>
-           <entry>Continuous frame size.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FRMSIZE_TYPE_STEPWISE</constant></entry>
-           <entry>3</entry>
-           <entry>Step-wise defined frame size.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <para>See the description section above for a list of return
-values that <varname>errno</varname> can have.</para>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-enumaudio.xml b/Documentation/DocBook/v4l/vidioc-enumaudio.xml
deleted file mode 100644 (file)
index 9ae8f2d..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-<refentry id="vidioc-enumaudio">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUMAUDIO</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUMAUDIO</refname>
-    <refpurpose>Enumerate audio inputs</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_audio *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_ENUMAUDIO</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of an audio input applications
-initialize the <structfield>index</structfield> field and zero out the
-<structfield>reserved</structfield> array of a &v4l2-audio;
-and call the <constant>VIDIOC_ENUMAUDIO</constant> ioctl with a pointer
-to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all audio
-inputs applications shall begin at index zero, incrementing by one
-until the driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <para>See <xref linkend="vidioc-g-audio" /> for a description of
-&v4l2-audio;.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The number of the audio input is out of bounds, or
-there are no audio inputs at all and this ioctl is not
-supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-enumaudioout.xml b/Documentation/DocBook/v4l/vidioc-enumaudioout.xml
deleted file mode 100644 (file)
index d3d7c0a..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<refentry id="vidioc-enumaudioout">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUMAUDOUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUMAUDOUT</refname>
-    <refpurpose>Enumerate audio outputs</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_audioout *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_ENUMAUDOUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of an audio output applications
-initialize the <structfield>index</structfield> field and zero out the
-<structfield>reserved</structfield> array of a &v4l2-audioout; and
-call the <constant>VIDIOC_G_AUDOUT</constant> ioctl with a pointer
-to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all audio
-outputs applications shall begin at index zero, incrementing by one
-until the driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <para>Note connectors on a TV card to loop back the received audio
-signal to a sound card are not audio outputs in this sense.</para>
-
-    <para>See <xref linkend="vidioc-g-audioout" /> for a description of
-&v4l2-audioout;.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The number of the audio output is out of bounds, or
-there are no audio outputs at all and this ioctl is not
-supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-enuminput.xml b/Documentation/DocBook/v4l/vidioc-enuminput.xml
deleted file mode 100644 (file)
index 476fe1d..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-<refentry id="vidioc-enuminput">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUMINPUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUMINPUT</refname>
-    <refpurpose>Enumerate video inputs</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_input
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_ENUMINPUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a video input applications
-initialize the <structfield>index</structfield> field of &v4l2-input;
-and call the <constant>VIDIOC_ENUMINPUT</constant> ioctl with a
-pointer to this structure. Drivers fill the rest of the structure or
-return an &EINVAL; when the index is out of bounds. To enumerate all
-inputs applications shall begin at index zero, incrementing by one
-until the driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-input">
-      <title>struct <structname>v4l2_input</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the input, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the video input, a NUL-terminated ASCII
-string, for example: "Vin (Composite 2)". This information is intended
-for the user, preferably the connector label on the device itself.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the input, see <xref
-               linkend="input-type" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>audioset</structfield></entry>
-           <entry><para>Drivers can enumerate up to 32 video and
-audio inputs. This field shows which audio inputs were selectable as
-audio source if this was the currently selected video input. It is a
-bit mask. The LSB corresponds to audio input 0, the MSB to input 31.
-Any number of bits can be set, or none.</para><para>When the driver
-does not enumerate audio inputs no bits must be set. Applications
-shall not interpret this as lack of audio support. Some drivers
-automatically select audio sources and do not enumerate them since
-there is no choice anyway.</para><para>For details on audio inputs and
-how to select the current input see <xref
-                 linkend="audio" />.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>tuner</structfield></entry>
-           <entry>Capture devices can have zero or more tuners (RF
-demodulators). When the <structfield>type</structfield> is set to
-<constant>V4L2_INPUT_TYPE_TUNER</constant> this is an RF connector and
-this field identifies the tuner. It corresponds to
-&v4l2-tuner; field <structfield>index</structfield>. For details on
-tuners see <xref linkend="tuner" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-std-id;</entry>
-           <entry><structfield>std</structfield></entry>
-           <entry>Every video input supports one or more different
-video standards. This field is a set of all supported standards. For
-details on video standards and how to switch see <xref
-linkend="standard" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>status</structfield></entry>
-           <entry>This field provides status information about the
-input. See <xref linkend="input-status" /> for flags.
-With the exception of the sensor orientation bits <structfield>status</structfield> is only valid when this is the
-current input.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capabilities</structfield></entry>
-           <entry>This field provides capabilities for the
-input. See <xref linkend="input-capabilities" /> for flags.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[3]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="input-type">
-      <title>Input Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_INPUT_TYPE_TUNER</constant></entry>
-           <entry>1</entry>
-           <entry>This input uses a tuner (RF demodulator).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_INPUT_TYPE_CAMERA</constant></entry>
-           <entry>2</entry>
-           <entry>Analog baseband input, for example CVBS /
-Composite Video, S-Video, RGB.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- Status flags based on proposal by Mark McClelland,
-video4linux-list@redhat.com on 18 Oct 2002, subject "Re: [V4L] Re:
-v4l2 api". "Why are some of them inverted? So that the driver doesn't
-have to lie about the status in cases where it can't tell one way or
-the other. Plus, a status of zero would generally mean that everything
-is OK." -->
-
-    <table frame="none" pgwide="1" id="input-status">
-      <title>Input Status Flags</title>
-      <tgroup cols="3">
-       <colspec colname="c1" />
-       <colspec colname="c2" align="center" />
-       <colspec colname="c3" />
-       <spanspec namest="c1" nameend="c3" spanname="hspan"
-         align="left" />
-       <tbody valign="top">
-         <row>
-           <entry spanname="hspan">General</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_POWER</constant></entry>
-           <entry>0x00000001</entry>
-           <entry>Attached device is off.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_SIGNAL</constant></entry>
-           <entry>0x00000002</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_COLOR</constant></entry>
-           <entry>0x00000004</entry>
-           <entry>The hardware supports color decoding, but does not
-detect color modulation in the signal.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">Sensor Orientation</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_HFLIP</constant></entry>
-           <entry>0x00000010</entry>
-           <entry>The input is connected to a device that produces a signal
-that is flipped horizontally and does not correct this before passing the
-signal to userspace.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_VFLIP</constant></entry>
-           <entry>0x00000020</entry>
-           <entry>The input is connected to a device that produces a signal
-that is flipped vertically and does not correct this before passing the
-signal to userspace. Note that a 180 degree rotation is the same as HFLIP | VFLIP</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">Analog Video</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_H_LOCK</constant></entry>
-           <entry>0x00000100</entry>
-           <entry>No horizontal sync lock.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_COLOR_KILL</constant></entry>
-           <entry>0x00000200</entry>
-           <entry>A color killer circuit automatically disables color
-decoding when it detects no color modulation. When this flag is set
-the color killer is enabled <emphasis>and</emphasis> has shut off
-color decoding.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">Digital Video</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_SYNC</constant></entry>
-           <entry>0x00010000</entry>
-           <entry>No synchronization lock.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_EQU</constant></entry>
-           <entry>0x00020000</entry>
-           <entry>No equalizer lock.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_CARRIER</constant></entry>
-           <entry>0x00040000</entry>
-           <entry>Carrier recovery failed.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">VCR and Set-Top Box</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_MACROVISION</constant></entry>
-           <entry>0x01000000</entry>
-           <entry>Macrovision is an analog copy prevention system
-mangling the video signal to confuse video recorders. When this
-flag is set Macrovision has been detected.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_NO_ACCESS</constant></entry>
-           <entry>0x02000000</entry>
-           <entry>Conditional access denied.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_ST_VTR</constant></entry>
-           <entry>0x04000000</entry>
-           <entry>VTR time constant. [?]</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- Capability flags based on video timings RFC by Muralidharan
-Karicheri, titled RFC (v1.2): V4L - Support for video timings at the
-input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
-       -->
-    <table frame="none" pgwide="1" id="input-capabilities">
-      <title>Input capabilities</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_IN_CAP_PRESETS</constant></entry>
-           <entry>0x00000001</entry>
-           <entry>This input supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_CAP_CUSTOM_TIMINGS</constant></entry>
-           <entry>0x00000002</entry>
-           <entry>This input supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_IN_CAP_STD</constant></entry>
-           <entry>0x00000004</entry>
-           <entry>This input supports setting the TV standard by using VIDIOC_S_STD.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-input; <structfield>index</structfield> is
-out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/v4l/vidioc-enumoutput.xml
deleted file mode 100644 (file)
index a281d26..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-<refentry id="vidioc-enumoutput">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUMOUTPUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUMOUTPUT</refname>
-    <refpurpose>Enumerate video outputs</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_output *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_ENUMOUTPUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a video outputs applications
-initialize the <structfield>index</structfield> field of &v4l2-output;
-and call the <constant>VIDIOC_ENUMOUTPUT</constant> ioctl with a
-pointer to this structure. Drivers fill the rest of the structure or
-return an &EINVAL; when the index is out of bounds. To enumerate all
-outputs applications shall begin at index zero, incrementing by one
-until the driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-output">
-      <title>struct <structname>v4l2_output</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the output, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the video output, a NUL-terminated ASCII
-string, for example: "Vout". This information is intended for the
-user, preferably the connector label on the device itself.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the output, see <xref
-               linkend="output-type" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>audioset</structfield></entry>
-           <entry><para>Drivers can enumerate up to 32 video and
-audio outputs. This field shows which audio outputs were
-selectable as the current output if this was the currently selected
-video output. It is a bit mask. The LSB corresponds to audio output 0,
-the MSB to output 31. Any number of bits can be set, or
-none.</para><para>When the driver does not enumerate audio outputs no
-bits must be set. Applications shall not interpret this as lack of
-audio support. Drivers may automatically select audio outputs without
-enumerating them.</para><para>For details on audio outputs and how to
-select the current output see <xref linkend="audio" />.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>modulator</structfield></entry>
-           <entry>Output devices can have zero or more RF modulators.
-When the <structfield>type</structfield> is
-<constant>V4L2_OUTPUT_TYPE_MODULATOR</constant> this is an RF
-connector and this field identifies the modulator. It corresponds to
-&v4l2-modulator; field <structfield>index</structfield>. For details
-on modulators see <xref linkend="tuner" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-std-id;</entry>
-           <entry><structfield>std</structfield></entry>
-           <entry>Every video output supports one or more different
-video standards. This field is a set of all supported standards. For
-details on video standards and how to switch see <xref
-               linkend="standard" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capabilities</structfield></entry>
-           <entry>This field provides capabilities for the
-output. See <xref linkend="output-capabilities" /> for flags.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[3]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="output-type">
-      <title>Output Type</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_OUTPUT_TYPE_MODULATOR</constant></entry>
-           <entry>1</entry>
-           <entry>This output is an analog TV modulator.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_OUTPUT_TYPE_ANALOG</constant></entry>
-           <entry>2</entry>
-           <entry>Analog baseband output, for example Composite /
-CVBS, S-Video, RGB.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY</constant></entry>
-           <entry>3</entry>
-           <entry>[?]</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- Capabilities flags based on video timings RFC by Muralidharan
-Karicheri, titled RFC (v1.2): V4L - Support for video timings at the
-input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
-       -->
-    <table frame="none" pgwide="1" id="output-capabilities">
-      <title>Output capabilities</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_OUT_CAP_PRESETS</constant></entry>
-           <entry>0x00000001</entry>
-           <entry>This output supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_OUT_CAP_CUSTOM_TIMINGS</constant></entry>
-           <entry>0x00000002</entry>
-           <entry>This output supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_OUT_CAP_STD</constant></entry>
-           <entry>0x00000004</entry>
-           <entry>This output supports setting the TV standard by using VIDIOC_S_STD.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-output; <structfield>index</structfield>
-is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-enumstd.xml b/Documentation/DocBook/v4l/vidioc-enumstd.xml
deleted file mode 100644 (file)
index 95803fe..0000000
+++ /dev/null
@@ -1,391 +0,0 @@
-<refentry id="vidioc-enumstd">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_ENUMSTD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_ENUMSTD</refname>
-    <refpurpose>Enumerate supported video standards</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_standard *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_ENUMSTD</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a video standard,
-especially a custom (driver defined) one, applications initialize the
-<structfield>index</structfield> field of &v4l2-standard; and call the
-<constant>VIDIOC_ENUMSTD</constant> ioctl with a pointer to this
-structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all standards
-applications shall begin  at index zero, incrementing by one until the
-driver returns <errorcode>EINVAL</errorcode>. Drivers may enumerate a
-different set of standards after switching the video input or
-output.<footnote>
-       <para>The supported standards may overlap and we need an
-unambiguous set to find the current standard returned by
-<constant>VIDIOC_G_STD</constant>.</para>
-      </footnote></para>
-
-    <table pgwide="1" frame="none" id="v4l2-standard">
-      <title>struct <structname>v4l2_standard</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the video standard, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-std-id;</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>The bits in this field identify the standard as
-one of the common standards listed in <xref linkend="v4l2-std-id" />,
-or if bits 32 to 63 are set as custom standards. Multiple bits can be
-set if the hardware does not distinguish between these standards,
-however separate indices do not indicate the opposite. The
-<structfield>id</structfield> must be unique. No other enumerated
-<structname>v4l2_standard</structname> structure, for this input or
-output anyway, can contain the same set of bits.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[24]</entry>
-           <entry>Name of the standard, a NUL-terminated ASCII
-string, for example: "PAL-B/G", "NTSC Japan". This information is
-intended for the user.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>frameperiod</structfield></entry>
-           <entry>The frame period (not field period) is numerator
-/ denominator. For example M/NTSC has a frame period of 1001 /
-30000 seconds.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>framelines</structfield></entry>
-           <entry>Total lines per frame including blanking,
-e.&nbsp;g. 625 for B/PAL.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-fract">
-      <title>struct <structname>v4l2_fract</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>numerator</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>denominator</structfield></entry>
-           <entry></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-std-id">
-      <title>typedef <structname>v4l2_std_id</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>v4l2_std_id</structfield></entry>
-           <entry>This type is a set, each bit representing another
-video standard as listed below and in <xref
-linkend="video-standards" />. The 32 most significant bits are reserved
-for custom (driver defined) video standards.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <para><programlisting>
-#define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
-#define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
-#define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
-#define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
-#define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
-#define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
-#define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
-#define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
-
-#define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
-#define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
-#define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
-#define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
-</programlisting></para><para><constant>V4L2_STD_PAL_60</constant> is
-a hybrid standard with 525 lines, 60 Hz refresh rate, and PAL color
-modulation with a 4.43 MHz color subcarrier. Some PAL video recorders
-can play back NTSC tapes in this mode for display on a 50/60 Hz agnostic
-PAL TV.</para><para><programlisting>
-#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)
-#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)
-#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
-</programlisting></para><para><constant>V4L2_STD_NTSC_443</constant>
-is a hybrid standard with 525 lines, 60 Hz refresh rate, and NTSC
-color modulation with a 4.43 MHz color
-subcarrier.</para><para><programlisting>
-#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)
-
-#define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
-#define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
-#define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
-#define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
-#define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
-#define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
-#define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
-#define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
-
-/* ATSC/HDTV */
-#define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
-#define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
-</programlisting></para><para><!-- ATSC proposal by Mark McClelland,
-video4linux-list@redhat.com on 17 Oct 2002
---><constant>V4L2_STD_ATSC_8_VSB</constant> and
-<constant>V4L2_STD_ATSC_16_VSB</constant> are U.S. terrestrial digital
-TV standards. Presently the V4L2 API does not support digital TV. See
-also the Linux DVB API at <ulink
-url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
-<para><programlisting>
-#define V4L2_STD_PAL_BG         (V4L2_STD_PAL_B         |\
-                                V4L2_STD_PAL_B1        |\
-                                V4L2_STD_PAL_G)
-#define V4L2_STD_B              (V4L2_STD_PAL_B         |\
-                                V4L2_STD_PAL_B1        |\
-                                V4L2_STD_SECAM_B)
-#define V4L2_STD_GH             (V4L2_STD_PAL_G         |\
-                                V4L2_STD_PAL_H         |\
-                                V4L2_STD_SECAM_G       |\
-                                V4L2_STD_SECAM_H)
-#define V4L2_STD_PAL_DK         (V4L2_STD_PAL_D         |\
-                                V4L2_STD_PAL_D1        |\
-                                V4L2_STD_PAL_K)
-#define V4L2_STD_PAL            (V4L2_STD_PAL_BG        |\
-                                V4L2_STD_PAL_DK        |\
-                                V4L2_STD_PAL_H         |\
-                                V4L2_STD_PAL_I)
-#define V4L2_STD_NTSC           (V4L2_STD_NTSC_M        |\
-                                V4L2_STD_NTSC_M_JP     |\
-                                V4L2_STD_NTSC_M_KR)
-#define V4L2_STD_MN             (V4L2_STD_PAL_M         |\
-                                V4L2_STD_PAL_N         |\
-                                V4L2_STD_PAL_Nc        |\
-                                V4L2_STD_NTSC)
-#define V4L2_STD_SECAM_DK       (V4L2_STD_SECAM_D       |\
-                                V4L2_STD_SECAM_K       |\
-                                V4L2_STD_SECAM_K1)
-#define V4L2_STD_DK             (V4L2_STD_PAL_DK        |\
-                                V4L2_STD_SECAM_DK)
-
-#define V4L2_STD_SECAM          (V4L2_STD_SECAM_B       |\
-                                V4L2_STD_SECAM_G       |\
-                                V4L2_STD_SECAM_H       |\
-                                V4L2_STD_SECAM_DK      |\
-                                V4L2_STD_SECAM_L       |\
-                                V4L2_STD_SECAM_LC)
-
-#define V4L2_STD_525_60         (V4L2_STD_PAL_M         |\
-                                V4L2_STD_PAL_60        |\
-                                V4L2_STD_NTSC          |\
-                                V4L2_STD_NTSC_443)
-#define V4L2_STD_625_50         (V4L2_STD_PAL           |\
-                                V4L2_STD_PAL_N         |\
-                                V4L2_STD_PAL_Nc        |\
-                                V4L2_STD_SECAM)
-
-#define V4L2_STD_UNKNOWN        0
-#define V4L2_STD_ALL            (V4L2_STD_525_60        |\
-                                V4L2_STD_625_50)
-</programlisting></para>
-
-    <table pgwide="1" id="video-standards" orient="land">
-      <title>Video Standards (based on [<xref linkend="itu470" />])</title>
-      <tgroup cols="12" colsep="1" rowsep="1" align="center">
-       <colspec colname="c1" align="left" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <colspec colname="c5" />
-       <colspec colnum="7" colname="c7" />
-       <colspec colnum="9" colname="c9" />
-       <colspec colnum="12" colname="c12" />
-       <spanspec namest="c2" nameend="c3" spanname="m" align="center" />
-       <spanspec namest="c4" nameend="c12" spanname="x" align="center" />
-       <spanspec namest="c5" nameend="c7" spanname="b" align="center" />
-       <spanspec namest="c9" nameend="c12" spanname="s" align="center" />
-       <thead>
-         <row>
-           <entry>Characteristics</entry>
-           <entry><para>M/NTSC<footnote><para>Japan uses a standard
-similar to M/NTSC
-(V4L2_STD_NTSC_M_JP).</para></footnote></para></entry>
-           <entry>M/PAL</entry>
-           <entry><para>N/PAL<footnote><para> The values in
-brackets apply to the combination N/PAL a.k.a.
-N<subscript>C</subscript> used in Argentina
-(V4L2_STD_PAL_Nc).</para></footnote></para></entry>
-           <entry align="center">B, B1, G/PAL</entry>
-           <entry align="center">D, D1, K/PAL</entry>
-           <entry align="center">H/PAL</entry>
-           <entry align="center">I/PAL</entry>
-           <entry align="center">B, G/SECAM</entry>
-           <entry align="center">D, K/SECAM</entry>
-           <entry align="center">K1/SECAM</entry>
-           <entry align="center">L/SECAM</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry>Frame lines</entry>
-           <entry spanname="m">525</entry>
-           <entry spanname="x">625</entry>
-         </row>
-         <row>
-           <entry>Frame period (s)</entry>
-           <entry spanname="m">1001/30000</entry>
-           <entry spanname="x">1/25</entry>
-         </row>
-         <row>
-           <entry>Chrominance sub-carrier frequency (Hz)</entry>
-           <entry>3579545 &plusmn;&nbsp;10</entry>
-           <entry>3579611.49 &plusmn;&nbsp;10</entry>
-           <entry>4433618.75 &plusmn;&nbsp;5 (3582056.25
-&plusmn;&nbsp;5)</entry>
-           <entry spanname="b">4433618.75 &plusmn;&nbsp;5</entry>
-           <entry>4433618.75 &plusmn;&nbsp;1</entry>
-           <entry spanname="s">f<subscript>OR</subscript>&nbsp;=
-4406250 &plusmn;&nbsp;2000, f<subscript>OB</subscript>&nbsp;= 4250000
-&plusmn;&nbsp;2000</entry>
-         </row>
-         <row>
-           <entry>Nominal radio-frequency channel bandwidth
-(MHz)</entry>
-           <entry>6</entry>
-           <entry>6</entry>
-           <entry>6</entry>
-           <entry>B: 7; B1, G: 8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-           <entry>8</entry>
-         </row>
-         <row>
-           <entry>Sound carrier relative to vision carrier
-(MHz)</entry>
-           <entry>+&nbsp;4.5</entry>
-           <entry>+&nbsp;4.5</entry>
-           <entry>+&nbsp;4.5</entry>
-           <entry><para>+&nbsp;5.5 &plusmn;&nbsp;0.001
-<footnote><para>In the Federal Republic of Germany, Austria, Italy,
-the Netherlands, Slovakia and Switzerland a system of two sound
-carriers is used, the frequency of the second carrier being
-242.1875&nbsp;kHz above the frequency of the first sound carrier. For
-stereophonic sound transmissions a similar system is used in
-Australia.</para></footnote> <footnote><para>New Zealand uses a sound
-carrier displaced 5.4996 &plusmn;&nbsp;0.0005 MHz from the vision
-carrier.</para></footnote> <footnote><para>In Denmark, Finland, New
-Zealand, Sweden and Spain a system of two sound carriers is used. In
-Iceland, Norway and Poland the same system is being introduced. The
-second carrier is 5.85&nbsp;MHz above the vision carrier and is DQPSK
-modulated with 728&nbsp;kbit/s sound and data multiplex. (NICAM
-system)</para></footnote> <footnote><para>In the United Kingdom, a
-system of two sound carriers is used. The second sound carrier is
-6.552&nbsp;MHz above the vision carrier and is DQPSK modulated with a
-728&nbsp;kbit/s sound and data multiplex able to carry two sound
-channels. (NICAM system)</para></footnote></para></entry>
-           <entry>+&nbsp;6.5 &plusmn;&nbsp;0.001</entry>
-           <entry>+&nbsp;5.5</entry>
-           <entry>+&nbsp;5.9996 &plusmn;&nbsp;0.0005</entry>
-           <entry>+&nbsp;5.5 &plusmn;&nbsp;0.001</entry>
-           <entry>+&nbsp;6.5 &plusmn;&nbsp;0.001</entry>
-           <entry>+&nbsp;6.5</entry>
-           <entry><para>+&nbsp;6.5 <footnote><para>In France, a
-digital carrier 5.85 MHz away from the vision carrier may be used in
-addition to the main sound carrier. It is modulated in differentially
-encoded QPSK with a 728 kbit/s sound and data multiplexer capable of
-carrying two sound channels. (NICAM
-system)</para></footnote></para></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-standard; <structfield>index</structfield>
-is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-audio.xml b/Documentation/DocBook/v4l/vidioc-g-audio.xml
deleted file mode 100644 (file)
index 65361a8..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-<refentry id="vidioc-g-audio">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_AUDIO, VIDIOC_S_AUDIO</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_AUDIO</refname>
-    <refname>VIDIOC_S_AUDIO</refname>
-    <refpurpose>Query or select the current audio input and its
-attributes</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_audio *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_audio *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_AUDIO, VIDIOC_S_AUDIO</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the current audio input applications zero out the
-<structfield>reserved</structfield> array of a &v4l2-audio;
-and call the <constant>VIDIOC_G_AUDIO</constant> ioctl with a pointer
-to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the device has no audio inputs, or none which combine
-with the current video input.</para>
-
-    <para>Audio inputs have one writable property, the audio mode. To
-select the current audio input <emphasis>and</emphasis> change the
-audio mode, applications initialize the
-<structfield>index</structfield> and <structfield>mode</structfield>
-fields, and the
-<structfield>reserved</structfield> array of a
-<structname>v4l2_audio</structname> structure and call the
-<constant>VIDIOC_S_AUDIO</constant> ioctl. Drivers may switch to a
-different audio mode if the request cannot be satisfied. However, this
-is a write-only ioctl, it does not return the actual new audio
-mode.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-audio">
-      <title>struct <structname>v4l2_audio</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the audio input, set by the
-driver or application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the audio input, a NUL-terminated ASCII
-string, for example: "Line In". This information is intended for the
-user, preferably the connector label on the device itself.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry>Audio capability flags, see <xref
-               linkend="audio-capability" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>mode</structfield></entry>
-           <entry>Audio mode flags set by drivers and applications (on
-           <constant>VIDIOC_S_AUDIO</constant> ioctl), see <xref linkend="audio-mode" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="audio-capability">
-      <title>Audio Capability Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_AUDCAP_STEREO</constant></entry>
-           <entry>0x00001</entry>
-           <entry>This is a stereo input. The flag is intended to
-automatically disable stereo recording etc. when the signal is always
-monaural. The API provides no means to detect if stereo is
-<emphasis>received</emphasis>, unless the audio input belongs to a
-tuner.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_AUDCAP_AVL</constant></entry>
-           <entry>0x00002</entry>
-           <entry>Automatic Volume Level mode is supported.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="audio-mode">
-      <title>Audio Mode Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_AUDMODE_AVL</constant></entry>
-           <entry>0x00001</entry>
-           <entry>AVL mode is on.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>No audio inputs combine with the current video input,
-or the number of the selected audio input is out of bounds or it does
-not combine, or there are no audio inputs at all and the ioctl is not
-supported.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>I/O is in progress, the input cannot be
-switched.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-audioout.xml b/Documentation/DocBook/v4l/vidioc-g-audioout.xml
deleted file mode 100644 (file)
index 3632730..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-<refentry id="vidioc-g-audioout">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_AUDOUT</refname>
-    <refname>VIDIOC_S_AUDOUT</refname>
-    <refpurpose>Query or select the current audio output</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_audioout *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_audioout *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_AUDOUT, VIDIOC_S_AUDOUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the current audio output applications zero out the
-<structfield>reserved</structfield> array of a &v4l2-audioout; and
-call the <constant>VIDIOC_G_AUDOUT</constant> ioctl with a pointer
-to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the device has no audio inputs, or none which combine
-with the current video output.</para>
-
-    <para>Audio outputs have no writable properties. Nevertheless, to
-select the current audio output applications can initialize the
-<structfield>index</structfield> field and
-<structfield>reserved</structfield> array (which in the future may
-contain writable properties) of a
-<structname>v4l2_audioout</structname> structure and call the
-<constant>VIDIOC_S_AUDOUT</constant> ioctl. Drivers switch to the
-requested output or return the &EINVAL; when the index is out of
-bounds. This is a write-only ioctl, it does not return the current
-audio output attributes as <constant>VIDIOC_G_AUDOUT</constant>
-does.</para>
-
-    <para>Note connectors on a TV card to loop back the received audio
-signal to a sound card are not audio outputs in this sense.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-audioout">
-      <title>struct <structname>v4l2_audioout</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the audio output, set by the
-driver or application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the audio output, a NUL-terminated ASCII
-string, for example: "Line Out". This information is intended for the
-user, preferably the connector label on the device itself.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry>Audio capability flags, none defined yet. Drivers
-must set this field to zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>mode</structfield></entry>
-           <entry>Audio mode, none defined yet. Drivers and
-applications (on <constant>VIDIOC_S_AUDOUT</constant>) must set this
-field to zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>No audio outputs combine with the current video
-output, or the number of the selected audio output is out of bounds or
-it does not combine, or there are no audio outputs at all and the
-ioctl is not supported.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>I/O is in progress, the output cannot be
-switched.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-crop.xml b/Documentation/DocBook/v4l/vidioc-g-crop.xml
deleted file mode 100644 (file)
index d235b1d..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-<refentry id="vidioc-g-crop">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_CROP, VIDIOC_S_CROP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_CROP</refname>
-    <refname>VIDIOC_S_CROP</refname>
-    <refpurpose>Get or set the current cropping rectangle</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_crop *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_crop *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_CROP, VIDIOC_S_CROP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the cropping rectangle size and position
-applications set the <structfield>type</structfield> field of a
-<structname>v4l2_crop</structname> structure to the respective buffer
-(stream) type and call the <constant>VIDIOC_G_CROP</constant> ioctl
-with a pointer to this structure. The driver fills the rest of the
-structure or returns the &EINVAL; if cropping is not supported.</para>
-
-    <para>To change the cropping rectangle applications initialize the
-<structfield>type</structfield> and &v4l2-rect; substructure named
-<structfield>c</structfield> of a v4l2_crop structure and call the
-<constant>VIDIOC_S_CROP</constant> ioctl with a pointer to this
-structure.</para>
-
-    <para>The driver first adjusts the requested dimensions against
-hardware limits, &ie; the bounds given by the capture/output window,
-and it rounds to the closest possible values of horizontal and
-vertical offset, width and height. In particular the driver must round
-the vertical offset of the cropping rectangle to frame lines modulo
-two, such that the field order cannot be confused.</para>
-
-    <para>Second the driver adjusts the image size (the opposite
-rectangle of the scaling process, source or target depending on the
-data direction) to the closest size possible while maintaining the
-current horizontal and vertical scaling factor.</para>
-
-    <para>Finally the driver programs the hardware with the actual
-cropping and image parameters. <constant>VIDIOC_S_CROP</constant> is a
-write-only ioctl, it does not return the actual parameters. To query
-them applications must call <constant>VIDIOC_G_CROP</constant> and
-&VIDIOC-G-FMT;. When the parameters are unsuitable the application may
-modify the cropping or image parameters and repeat the cycle until
-satisfactory parameters have been negotiated.</para>
-
-    <para>When cropping is not supported then no parameters are
-changed and <constant>VIDIOC_S_CROP</constant> returns the
-&EINVAL;.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-crop">
-      <title>struct <structname>v4l2_crop</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>&v4l2-buf-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the data stream, set by the application.
-Only these types are valid here: <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
-defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
-and higher.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-rect;</entry>
-           <entry><structfield>c</structfield></entry>
-           <entry>Cropping rectangle. The same co-ordinate system as
-for &v4l2-cropcap; <structfield>bounds</structfield> is used.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>Cropping is not supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-ctrl.xml b/Documentation/DocBook/v4l/vidioc-g-ctrl.xml
deleted file mode 100644 (file)
index 8b5e6ff..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-<refentry id="vidioc-g-ctrl">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_CTRL, VIDIOC_S_CTRL</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_CTRL</refname>
-    <refname>VIDIOC_S_CTRL</refname>
-    <refpurpose>Get or set the value of a control</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_control
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_CTRL, VIDIOC_S_CTRL</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To get the current value of a control applications
-initialize the <structfield>id</structfield> field of a struct
-<structname>v4l2_control</structname> and call the
-<constant>VIDIOC_G_CTRL</constant> ioctl with a pointer to this
-structure. To change the value of a control applications initialize
-the <structfield>id</structfield> and <structfield>value</structfield>
-fields of a struct <structname>v4l2_control</structname> and call the
-<constant>VIDIOC_S_CTRL</constant> ioctl.</para>
-
-    <para>When the <structfield>id</structfield> is invalid drivers
-return an &EINVAL;. When the <structfield>value</structfield> is out
-of bounds drivers can choose to take the closest valid value or return
-an &ERANGE;, whatever seems more appropriate. However,
-<constant>VIDIOC_S_CTRL</constant> is a write-only ioctl, it does not
-return the actual new value.</para>
-
-    <para>These ioctls work only with user controls. For other
-control classes the &VIDIOC-G-EXT-CTRLS;, &VIDIOC-S-EXT-CTRLS; or
-&VIDIOC-TRY-EXT-CTRLS; must be used.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-control">
-      <title>struct <structname>v4l2_control</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>Identifies the control, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>value</structfield></entry>
-           <entry>New value or current value.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-control; <structfield>id</structfield> is
-invalid.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ERANGE</errorcode></term>
-       <listitem>
-         <para>The &v4l2-control; <structfield>value</structfield>
-is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The control is temporarily not changeable, possibly
-because another applications took over control of the device function
-this control belongs to.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml b/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml
deleted file mode 100644 (file)
index d733721..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-<refentry id="vidioc-g-dv-preset">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_DV_PRESET</refname>
-    <refname>VIDIOC_S_DV_PRESET</refname>
-    <refpurpose>Query or select the DV preset of the current input or output</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_dv_preset *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-    <para>To query and select the current DV preset, applications
-use the <constant>VIDIOC_G_DV_PRESET</constant> and <constant>VIDIOC_S_DV_PRESET</constant>
-ioctls which take a pointer to a &v4l2-dv-preset; type as argument.
-Applications must zero the reserved array in &v4l2-dv-preset;.
-<constant>VIDIOC_G_DV_PRESET</constant> returns a dv preset in the field
-<structfield>preset</structfield> of &v4l2-dv-preset;.</para>
-
-    <para><constant>VIDIOC_S_DV_PRESET</constant> accepts a pointer to a &v4l2-dv-preset;
-that has the preset value to be set. Applications must zero the reserved array in &v4l2-dv-preset;.
-If the preset is not supported, it returns an &EINVAL; </para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported, or the
-<constant>VIDIOC_S_DV_PRESET</constant>,<constant>VIDIOC_S_DV_PRESET</constant> parameter was unsuitable.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The device is busy and therefore can not change the preset.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-
-    <table pgwide="1" frame="none" id="v4l2-dv-preset">
-      <title>struct <structname>v4l2_dv_preset</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>preset</structfield></entry>
-           <entry>Preset value to represent the digital video timings</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved[4]</structfield></entry>
-           <entry>Reserved fields for future use</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml b/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml
deleted file mode 100644 (file)
index d5ec6ab..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-<refentry id="vidioc-g-dv-timings">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_DV_TIMINGS</refname>
-    <refname>VIDIOC_S_DV_TIMINGS</refname>
-    <refpurpose>Get or set custom DV timings for input or output</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_dv_timings *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_DV_TIMINGS, VIDIOC_S_DV_TIMINGS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-    <para>To set custom DV timings for the input or output, applications use the
-<constant>VIDIOC_S_DV_TIMINGS</constant> ioctl and to get the current custom timings,
-applications use the <constant>VIDIOC_G_DV_TIMINGS</constant> ioctl. The detailed timing
-information is filled in using the structure &v4l2-dv-timings;. These ioctls take
-a pointer to the &v4l2-dv-timings; structure as argument. If the ioctl is not supported
-or the timing values are not correct, the driver returns &EINVAL;.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported, or the
-<constant>VIDIOC_S_DV_TIMINGS</constant> parameter was unsuitable.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The device is busy and therefore can not change the timings.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-
-    <table pgwide="1" frame="none" id="v4l2-bt-timings">
-      <title>struct <structname>v4l2_bt_timings</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the active video in pixels</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the active video in lines</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>interlaced</structfield></entry>
-           <entry>Progressive (0) or interlaced (1)</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>polarities</structfield></entry>
-           <entry>This is a bit mask that defines polarities of sync signals.
-bit 0 (V4L2_DV_VSYNC_POS_POL) is for vertical sync polarity and bit 1 (V4L2_DV_HSYNC_POS_POL) is for horizontal sync polarity. If the bit is set
-(1) it is positive polarity and if is cleared (0), it is negative polarity.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>pixelclock</structfield></entry>
-           <entry>Pixel clock in Hz. Ex. 74.25MHz->74250000</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>hfrontporch</structfield></entry>
-           <entry>Horizontal front porch in pixels</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>hsync</structfield></entry>
-           <entry>Horizontal sync length in pixels</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>hbackporch</structfield></entry>
-           <entry>Horizontal back porch in pixels</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>vfrontporch</structfield></entry>
-           <entry>Vertical front porch in lines</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>vsync</structfield></entry>
-           <entry>Vertical sync length in lines</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>vbackporch</structfield></entry>
-           <entry>Vertical back porch in lines</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>il_vfrontporch</structfield></entry>
-           <entry>Vertical front porch in lines for bottom field of interlaced field formats</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>il_vsync</structfield></entry>
-           <entry>Vertical sync length in lines for bottom field of interlaced field formats</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>il_vbackporch</structfield></entry>
-           <entry>Vertical back porch in lines for bottom field of interlaced field formats</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-dv-timings">
-      <title>struct <structname>v4l2_dv_timings</structname></title>
-      <tgroup cols="4">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>Type of DV timings as listed in <xref linkend="dv-timing-types"/>.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield></structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-bt-timings;</entry>
-           <entry><structfield>bt</structfield></entry>
-           <entry>Timings defined by BT.656/1120 specifications</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[32]</entry>
-           <entry></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="dv-timing-types">
-      <title>DV Timing types</title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>Timing type</entry>
-           <entry>value</entry>
-           <entry>Description</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>V4L2_DV_BT_656_1120</entry>
-           <entry>0</entry>
-           <entry>BT.656/1120 timings</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-enc-index.xml b/Documentation/DocBook/v4l/vidioc-g-enc-index.xml
deleted file mode 100644 (file)
index 9f242e4..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-<refentry id="vidioc-g-enc-index">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_ENC_INDEX</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_ENC_INDEX</refname>
-    <refpurpose>Get meta data about a compressed video stream</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_enc_idx *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_ENC_INDEX</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-
-      <para>This is an <link linkend="experimental">experimental</link>
-interface and may change in the future.</para>
-    </note>
-
-    <para>The <constant>VIDIOC_G_ENC_INDEX</constant> ioctl provides
-meta data about a compressed video stream the same or another
-application currently reads from the driver, which is useful for
-random access into the stream without decoding it.</para>
-
-    <para>To read the data applications must call
-<constant>VIDIOC_G_ENC_INDEX</constant> with a pointer to a
-&v4l2-enc-idx;. On success the driver fills the
-<structfield>entry</structfield> array, stores the number of elements
-written in the <structfield>entries</structfield> field, and
-initializes the <structfield>entries_cap</structfield> field.</para>
-
-    <para>Each element of the <structfield>entry</structfield> array
-contains meta data about one picture. A
-<constant>VIDIOC_G_ENC_INDEX</constant> call reads up to
-<constant>V4L2_ENC_IDX_ENTRIES</constant> entries from a driver
-buffer, which can hold up to <structfield>entries_cap</structfield>
-entries. This number can be lower or higher than
-<constant>V4L2_ENC_IDX_ENTRIES</constant>, but not zero. When the
-application fails to read the meta data in time the oldest entries
-will be lost. When the buffer is empty or no capturing/encoding is in
-progress, <structfield>entries</structfield> will be zero.</para>
-
-    <para>Currently this ioctl is only defined for MPEG-2 program
-streams and video elementary streams.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-enc-idx">
-      <title>struct <structname>v4l2_enc_idx</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>entries</structfield></entry>
-           <entry>The number of entries the driver stored in the
-<structfield>entry</structfield> array.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>entries_cap</structfield></entry>
-           <entry>The number of entries the driver can
-buffer. Must be greater than zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry spanname="hspan">Reserved for future extensions.
-Drivers must set the array to zero.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-enc-idx-entry;</entry>
-           <entry><structfield>entry</structfield>[<constant>V4L2_ENC_IDX_ENTRIES</constant>]</entry>
-           <entry>Meta data about a compressed video stream. Each
-element of the array corresponds to one picture, sorted in ascending
-order by their <structfield>offset</structfield>.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-enc-idx-entry">
-      <title>struct <structname>v4l2_enc_idx_entry</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>offset</structfield></entry>
-           <entry>The offset in bytes from the beginning of the
-compressed video stream to the beginning of this picture, that is a
-<wordasword>PES packet header</wordasword> as defined in <xref
-           linkend="mpeg2part1" /> or a <wordasword>picture
-header</wordasword> as defined in <xref linkend="mpeg2part2" />. When
-the encoder is stopped, the driver resets the offset to zero.</entry>
-         </row>
-         <row>
-           <entry>__u64</entry>
-           <entry><structfield>pts</structfield></entry>
-           <entry>The 33 bit <wordasword>Presentation Time
-Stamp</wordasword> of this picture as defined in <xref
-               linkend="mpeg2part1" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>length</structfield></entry>
-           <entry>The length of this picture in bytes.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Flags containing the coding type of this picture, see <xref
-               linkend="enc-idx-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions.
-Drivers must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="enc-idx-flags">
-      <title>Index Entry Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_ENC_IDX_FRAME_I</constant></entry>
-           <entry>0x00</entry>
-           <entry>This is an Intra-coded picture.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_IDX_FRAME_P</constant></entry>
-           <entry>0x01</entry>
-           <entry>This is a Predictive-coded picture.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_IDX_FRAME_B</constant></entry>
-           <entry>0x02</entry>
-           <entry>This is a Bidirectionally predictive-coded
-picture.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_ENC_IDX_FRAME_MASK</constant></entry>
-           <entry>0x0F</entry>
-           <entry><wordasword>AND</wordasword> the flags field with
-this mask to obtain the picture coding type.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The driver does not support this ioctl.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/v4l/vidioc-g-ext-ctrls.xml
deleted file mode 100644 (file)
index 3aa7f8f..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-<refentry id="vidioc-g-ext-ctrls">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS,
-VIDIOC_TRY_EXT_CTRLS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_EXT_CTRLS</refname>
-    <refname>VIDIOC_S_EXT_CTRLS</refname>
-    <refname>VIDIOC_TRY_EXT_CTRLS</refname>
-    <refpurpose>Get or set the value of several controls, try control
-values</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_ext_controls
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS,
-VIDIOC_TRY_EXT_CTRLS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>These ioctls allow the caller to get or set multiple
-controls atomically. Control IDs are grouped into control classes (see
-<xref linkend="ctrl-class" />) and all controls in the control array
-must belong to the same control class.</para>
-
-    <para>Applications must always fill in the
-<structfield>count</structfield>,
-<structfield>ctrl_class</structfield>,
-<structfield>controls</structfield> and
-<structfield>reserved</structfield> fields of &v4l2-ext-controls;, and
-initialize the &v4l2-ext-control; array pointed to by the
-<structfield>controls</structfield> fields.</para>
-
-    <para>To get the current value of a set of controls applications
-initialize the <structfield>id</structfield>,
-<structfield>size</structfield> and <structfield>reserved2</structfield> fields
-of each &v4l2-ext-control; and call the
-<constant>VIDIOC_G_EXT_CTRLS</constant> ioctl. String controls controls
-must also set the <structfield>string</structfield> field.</para>
-
-    <para>If the <structfield>size</structfield> is too small to
-receive the control result (only relevant for pointer-type controls
-like strings), then the driver will set <structfield>size</structfield>
-to a valid value and return an &ENOSPC;. You should re-allocate the
-string memory to this new size and try again. It is possible that the
-same issue occurs again if the string has grown in the meantime. It is
-recommended to call &VIDIOC-QUERYCTRL; first and use
-<structfield>maximum</structfield>+1 as the new <structfield>size</structfield>
-value. It is guaranteed that that is sufficient memory.
-</para>
-
-    <para>To change the value of a set of controls applications
-initialize the <structfield>id</structfield>, <structfield>size</structfield>,
-<structfield>reserved2</structfield> and
-<structfield>value/string</structfield> fields of each &v4l2-ext-control; and
-call the <constant>VIDIOC_S_EXT_CTRLS</constant> ioctl. The controls
-will only be set if <emphasis>all</emphasis> control values are
-valid.</para>
-
-    <para>To check if a set of controls have correct values applications
-initialize the <structfield>id</structfield>, <structfield>size</structfield>,
-<structfield>reserved2</structfield> and
-<structfield>value/string</structfield> fields of each &v4l2-ext-control; and
-call the <constant>VIDIOC_TRY_EXT_CTRLS</constant> ioctl. It is up to
-the driver whether wrong values are automatically adjusted to a valid
-value or if an error is returned.</para>
-
-    <para>When the <structfield>id</structfield> or
-<structfield>ctrl_class</structfield> is invalid drivers return an
-&EINVAL;. When the value is out of bounds drivers can choose to take
-the closest valid value or return an &ERANGE;, whatever seems more
-appropriate. In the first case the new value is set in
-&v4l2-ext-control;.</para>
-
-    <para>The driver will only set/get these controls if all control
-values are correct. This prevents the situation where only some of the
-controls were set/get. Only low-level errors (&eg; a failed i2c
-command) can still cause this situation.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-ext-control">
-      <title>struct <structname>v4l2_ext_control</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry></entry>
-           <entry>Identifies the control, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>size</structfield></entry>
-           <entry></entry>
-           <entry>The total size in bytes of the payload of this
-control. This is normally 0, but for pointer controls this should be
-set to the size of the memory containing the payload, or that will
-receive the payload. If <constant>VIDIOC_G_EXT_CTRLS</constant> finds
-that this value is less than is required to store
-the payload result, then it is set to a value large enough to store the
-payload result and ENOSPC is returned. Note that for string controls
-this <structfield>size</structfield> field should not be confused with the length of the string.
-This field refers to the size of the memory that contains the string.
-The actual <emphasis>length</emphasis> of the string may well be much smaller.
-</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved2</structfield>[1]</entry>
-           <entry></entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry>(anonymous)</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__s32</entry>
-           <entry><structfield>value</structfield></entry>
-           <entry>New value or current value.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__s64</entry>
-           <entry><structfield>value64</structfield></entry>
-           <entry>New value or current value.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>char *</entry>
-           <entry><structfield>string</structfield></entry>
-           <entry>A pointer to a string.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-ext-controls">
-      <title>struct <structname>v4l2_ext_controls</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>ctrl_class</structfield></entry>
-           <entry>The control class to which all controls belong, see
-<xref linkend="ctrl-class" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>count</structfield></entry>
-           <entry>The number of controls in the controls array. May
-also be zero.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>error_idx</structfield></entry>
-           <entry>Set by the driver in case of an error. It is the
-index of the control causing the error or equal to 'count' when the
-error is not associated with a particular control. Undefined when the
-ioctl returns 0 (success).</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-ext-control; *</entry>
-           <entry><structfield>controls</structfield></entry>
-           <entry>Pointer to an array of
-<structfield>count</structfield> v4l2_ext_control structures. Ignored
-if <structfield>count</structfield> equals zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="ctrl-class">
-      <title>Control classes</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_USER</constant></entry>
-           <entry>0x980000</entry>
-           <entry>The class containing user controls. These controls
-are described in <xref linkend="control" />. All controls that can be set
-using the &VIDIOC-S-CTRL; and &VIDIOC-G-CTRL; ioctl belong to this
-class.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_MPEG</constant></entry>
-           <entry>0x990000</entry>
-           <entry>The class containing MPEG compression controls.
-These controls are described in <xref
-               linkend="mpeg-controls" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_CAMERA</constant></entry>
-           <entry>0x9a0000</entry>
-           <entry>The class containing camera controls.
-These controls are described in <xref
-               linkend="camera-controls" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_FM_TX</constant></entry>
-           <entry>0x9b0000</entry>
-           <entry>The class containing FM Transmitter (FM TX) controls.
-These controls are described in <xref
-               linkend="fm-tx-controls" />.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-ext-control; <structfield>id</structfield>
-is invalid or the &v4l2-ext-controls;
-<structfield>ctrl_class</structfield> is invalid. This error code is
-also returned by the <constant>VIDIOC_S_EXT_CTRLS</constant> and
-<constant>VIDIOC_TRY_EXT_CTRLS</constant> ioctls if two or more
-control values are in conflict.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ERANGE</errorcode></term>
-       <listitem>
-         <para>The &v4l2-ext-control; <structfield>value</structfield>
-is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The control is temporarily not changeable, possibly
-because another applications took over control of the device function
-this control belongs to.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOSPC</errorcode></term>
-       <listitem>
-         <para>The space reserved for the control's payload is insufficient.
-The field <structfield>size</structfield> is set to a value that is enough
-to store the payload and this error code is returned.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-fbuf.xml b/Documentation/DocBook/v4l/vidioc-g-fbuf.xml
deleted file mode 100644 (file)
index e7dda48..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
-<refentry id="vidioc-g-fbuf">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_FBUF, VIDIOC_S_FBUF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_FBUF</refname>
-    <refname>VIDIOC_S_FBUF</refname>
-    <refpurpose>Get or set frame buffer overlay parameters</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_framebuffer *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_framebuffer *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_FBUF, VIDIOC_S_FBUF</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Applications can use the <constant>VIDIOC_G_FBUF</constant> and
-<constant>VIDIOC_S_FBUF</constant> ioctl to get and set the
-framebuffer parameters for a <link linkend="overlay">Video
-Overlay</link> or <link linkend="osd">Video Output Overlay</link>
-(OSD). The type of overlay is implied by the device type (capture or
-output device) and can be determined with the &VIDIOC-QUERYCAP; ioctl.
-One <filename>/dev/videoN</filename> device must not support both
-kinds of overlay.</para>
-
-    <para>The V4L2 API distinguishes destructive and non-destructive
-overlays. A destructive overlay copies captured video images into the
-video memory of a graphics card. A non-destructive overlay blends
-video images into a VGA signal or graphics into a video signal.
-<wordasword>Video Output Overlays</wordasword> are always
-non-destructive.</para>
-
-    <para>To get the current parameters applications call the
-<constant>VIDIOC_G_FBUF</constant> ioctl with a pointer to a
-<structname>v4l2_framebuffer</structname> structure. The driver fills
-all fields of the structure or returns an &EINVAL; when overlays are
-not supported.</para>
-
-    <para>To set the parameters for a <wordasword>Video Output
-Overlay</wordasword>, applications must initialize the
-<structfield>flags</structfield> field of a struct
-<structname>v4l2_framebuffer</structname>. Since the framebuffer is
-implemented on the TV card all other parameters are determined by the
-driver. When an application calls <constant>VIDIOC_S_FBUF</constant>
-with a pointer to this structure, the driver prepares for the overlay
-and returns the framebuffer parameters as
-<constant>VIDIOC_G_FBUF</constant> does, or it returns an error
-code.</para>
-
-    <para>To set the parameters for a <wordasword>non-destructive
-Video Overlay</wordasword>, applications must initialize the
-<structfield>flags</structfield> field, the
-<structfield>fmt</structfield> substructure, and call
-<constant>VIDIOC_S_FBUF</constant>. Again the driver prepares for the
-overlay and returns the framebuffer parameters as
-<constant>VIDIOC_G_FBUF</constant> does, or it returns an error
-code.</para>
-
-    <para>For a <wordasword>destructive Video Overlay</wordasword>
-applications must additionally provide a
-<structfield>base</structfield> address. Setting up a DMA to a
-random memory location can jeopardize the system security, its
-stability or even damage the hardware, therefore only the superuser
-can set the parameters for a destructive video overlay.</para>
-
-    <!-- NB v4l2_pix_format is also specified in pixfmt.sgml.-->
-
-    <table pgwide="1" frame="none" id="v4l2-framebuffer">
-      <title>struct <structname>v4l2_framebuffer</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry></entry>
-           <entry>Overlay capability flags set by the driver, see
-<xref linkend="framebuffer-cap" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry></entry>
-           <entry>Overlay control flags set by application and
-driver, see <xref linkend="framebuffer-flags" /></entry>
-         </row>
-         <row>
-           <entry>void *</entry>
-           <entry><structfield>base</structfield></entry>
-           <entry></entry>
-           <entry>Physical base address of the framebuffer,
-that is the address of the pixel in the top left corner of the
-framebuffer.<footnote><para>A physical base address may not suit all
-platforms. GK notes in theory we should pass something like PCI device
-+ memory region + offset instead. If you encounter problems please
-discuss on the linux-media mailing list: &v4l-ml;.</para></footnote></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>This field is irrelevant to
-<wordasword>non-destructive Video Overlays</wordasword>. For
-<wordasword>destructive Video Overlays</wordasword> applications must
-provide a base address. The driver may accept only base addresses
-which are a multiple of two, four or eight bytes. For
-<wordasword>Video Output Overlays</wordasword> the driver must return
-a valid base address, so applications can find the corresponding Linux
-framebuffer device (see <xref linkend="osd" />).</entry>
-         </row>
-         <row>
-           <entry>&v4l2-pix-format;</entry>
-           <entry><structfield>fmt</structfield></entry>
-           <entry></entry>
-           <entry>Layout of the frame buffer. The
-<structname>v4l2_pix_format</structname> structure is defined in <xref
-linkend="pixfmt" />, for clarification the fields and acceptable values
-           are listed below:</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Width of the frame buffer in pixels.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Height of the frame buffer in pixels.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>pixelformat</structfield></entry>
-           <entry>The pixel format of the
-framebuffer.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>For <wordasword>non-destructive Video
-Overlays</wordasword> this field only defines a format for the
-&v4l2-window; <structfield>chromakey</structfield> field.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>For <wordasword>destructive Video
-Overlays</wordasword> applications must initialize this field. For
-<wordasword>Video Output Overlays</wordasword> the driver must return
-a valid format.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry></entry>
-           <entry>Usually this is an RGB format (for example
-<link linkend="V4L2-PIX-FMT-RGB565"><constant>V4L2_PIX_FMT_RGB565</constant></link>)
-but YUV formats (only packed YUV formats when chroma keying is used,
-not including <constant>V4L2_PIX_FMT_YUYV</constant> and
-<constant>V4L2_PIX_FMT_UYVY</constant>) and the
-<constant>V4L2_PIX_FMT_PAL8</constant> format are also permitted. The
-behavior of the driver when an application requests a compressed
-format is undefined. See <xref linkend="pixfmt" /> for information on
-pixel formats.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-field;</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry>Drivers and applications shall ignore this field.
-If applicable, the field order is selected with the &VIDIOC-S-FMT;
-ioctl, using the <structfield>field</structfield> field of
-&v4l2-window;.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>bytesperline</structfield></entry>
-           <entry>Distance in bytes between the leftmost pixels in
-two adjacent lines.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>This field is irrelevant to
-<wordasword>non-destructive Video
-Overlays</wordasword>.</para><para>For <wordasword>destructive Video
-Overlays</wordasword> both applications and drivers can set this field
-to request padding bytes at the end of each line. Drivers however may
-ignore the requested value, returning <structfield>width</structfield>
-times bytes-per-pixel or a larger value required by the hardware. That
-implies applications can just set this field to zero to get a
-reasonable default.</para><para>For <wordasword>Video Output
-Overlays</wordasword> the driver must return a valid
-value.</para><para>Video hardware may access padding bytes, therefore
-they must reside in accessible memory. Consider for example the case
-where padding bytes after the last line of an image cross a system
-page boundary. Capture devices may write padding bytes, the value is
-undefined. Output devices ignore the contents of padding
-bytes.</para><para>When the image format is planar the
-<structfield>bytesperline</structfield> value applies to the largest
-plane and is divided by the same factor as the
-<structfield>width</structfield> field for any smaller planes. For
-example the Cb and Cr planes of a YUV 4:2:0 image have half as many
-padding bytes following each line as the Y plane. To avoid ambiguities
-drivers must return a <structfield>bytesperline</structfield> value
-rounded up to a multiple of the scale factor.</para></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>sizeimage</structfield></entry>
-           <entry><para>This field is irrelevant to
-<wordasword>non-destructive Video Overlays</wordasword>. For
-<wordasword>destructive Video Overlays</wordasword> applications must
-initialize this field. For <wordasword>Video Output
-Overlays</wordasword> the driver must return a valid
-format.</para><para>Together with <structfield>base</structfield> it
-defines the framebuffer memory accessible by the
-driver.</para></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-colorspace;</entry>
-           <entry><structfield>colorspace</structfield></entry>
-           <entry>This information supplements the
-<structfield>pixelformat</structfield> and must be set by the driver,
-see <xref linkend="colorspaces" />.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u32</entry>
-           <entry><structfield>priv</structfield></entry>
-           <entry>Reserved for additional information about custom
-(driver defined) formats. When not used drivers and applications must
-set this field to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="framebuffer-cap">
-      <title>Frame Buffer Capability Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_EXTERNOVERLAY</constant></entry>
-           <entry>0x0001</entry>
-           <entry>The device is capable of non-destructive overlays.
-When the driver clears this flag, only destructive overlays are
-supported. There are no drivers yet which support both destructive and
-non-destructive overlays.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_CHROMAKEY</constant></entry>
-           <entry>0x0002</entry>
-           <entry>The device supports clipping by chroma-keying the
-images. That is, image pixels replace pixels in the VGA or video
-signal only where the latter assume a certain color. Chroma-keying
-makes no sense for destructive overlays.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_LIST_CLIPPING</constant></entry>
-           <entry>0x0004</entry>
-           <entry>The device supports clipping using a list of clip
-rectangles.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_BITMAP_CLIPPING</constant></entry>
-           <entry>0x0008</entry>
-           <entry>The device supports clipping using a bit mask.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_LOCAL_ALPHA</constant></entry>
-           <entry>0x0010</entry>
-           <entry>The device supports clipping/blending using the
-alpha channel of the framebuffer or VGA signal. Alpha blending makes
-no sense for destructive overlays.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_GLOBAL_ALPHA</constant></entry>
-           <entry>0x0020</entry>
-           <entry>The device supports alpha blending using a global
-alpha value. Alpha blending makes no sense for destructive overlays.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_LOCAL_INV_ALPHA</constant></entry>
-           <entry>0x0040</entry>
-           <entry>The device supports clipping/blending using the
-inverted alpha channel of the framebuffer or VGA signal. Alpha
-blending makes no sense for destructive overlays.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_CAP_SRC_CHROMAKEY</constant></entry>
-           <entry>0x0080</entry>
-           <entry>The device supports Source Chroma-keying. Framebuffer pixels
-with the chroma-key colors are replaced by video pixels, which is exactly opposite of
-<constant>V4L2_FBUF_CAP_CHROMAKEY</constant></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="framebuffer-flags">
-      <title>Frame Buffer Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_PRIMARY</constant></entry>
-           <entry>0x0001</entry>
-           <entry>The framebuffer is the primary graphics surface.
-In other words, the overlay is destructive. [?]</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_OVERLAY</constant></entry>
-           <entry>0x0002</entry>
-           <entry>The frame buffer is an overlay surface the same
-size as the capture. [?]</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">The purpose of
-<constant>V4L2_FBUF_FLAG_PRIMARY</constant> and
-<constant>V4L2_FBUF_FLAG_OVERLAY</constant> was never quite clear.
-Most drivers seem to ignore these flags. For compatibility with the
-<wordasword>bttv</wordasword> driver applications should set the
-<constant>V4L2_FBUF_FLAG_OVERLAY</constant> flag.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_CHROMAKEY</constant></entry>
-           <entry>0x0004</entry>
-           <entry>Use chroma-keying. The chroma-key color is
-determined by the <structfield>chromakey</structfield> field of
-&v4l2-window; and negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
-               linkend="overlay" />
-and
-           <xref linkend="osd" />.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan">There are no flags to enable
-clipping using a list of clip rectangles or a bitmap. These methods
-are negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
-               linkend="overlay" /> and <xref linkend="osd" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_LOCAL_ALPHA</constant></entry>
-           <entry>0x0008</entry>
-           <entry>Use the alpha channel of the framebuffer to clip or
-blend framebuffer pixels with video images. The blend
-function is: output = framebuffer pixel * alpha + video pixel * (1 -
-alpha). The actual alpha depth depends on the framebuffer pixel
-format.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_GLOBAL_ALPHA</constant></entry>
-           <entry>0x0010</entry>
-           <entry>Use a global alpha value to blend the framebuffer
-with video images. The blend function is: output = (framebuffer pixel
-* alpha + video pixel * (255 - alpha)) / 255. The alpha value is
-determined by the <structfield>global_alpha</structfield> field of
-&v4l2-window; and negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
-               linkend="overlay" />
-and <xref linkend="osd" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_LOCAL_INV_ALPHA</constant></entry>
-           <entry>0x0020</entry>
-           <entry>Like
-<constant>V4L2_FBUF_FLAG_LOCAL_ALPHA</constant>, use the alpha channel
-of the framebuffer to clip or blend framebuffer pixels with video
-images, but with an inverted alpha value. The blend function is:
-output = framebuffer pixel * (1 - alpha) + video pixel * alpha. The
-actual alpha depth depends on the framebuffer pixel format.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_FBUF_FLAG_SRC_CHROMAKEY</constant></entry>
-           <entry>0x0040</entry>
-           <entry>Use source chroma-keying. The source chroma-key color is
-determined by the <structfield>chromakey</structfield> field of
-&v4l2-window; and negotiated with the &VIDIOC-S-FMT; ioctl, see <xref
-linkend="overlay" /> and <xref linkend="osd" />.
-Both chroma-keying are mutual exclusive to each other, so same
-<structfield>chromakey</structfield> field of &v4l2-window; is being used.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EPERM</errorcode></term>
-       <listitem>
-         <para><constant>VIDIOC_S_FBUF</constant> can only be called
-by a privileged user to negotiate the parameters for a destructive
-overlay.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The framebuffer parameters cannot be changed at this
-time because overlay is already enabled, or capturing is enabled
-and the hardware cannot capture and overlay simultaneously.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The ioctl is not supported or the
-<constant>VIDIOC_S_FBUF</constant> parameters are unsuitable.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-fmt.xml b/Documentation/DocBook/v4l/vidioc-g-fmt.xml
deleted file mode 100644 (file)
index a4ae59b..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-<refentry id="vidioc-g-fmt">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_FMT, VIDIOC_S_FMT,
-VIDIOC_TRY_FMT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_FMT</refname>
-    <refname>VIDIOC_S_FMT</refname>
-    <refname>VIDIOC_TRY_FMT</refname>
-    <refpurpose>Get or set the data format, try a format</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_format
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_FMT, VIDIOC_S_FMT, VIDIOC_TRY_FMT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>These ioctls are used to negotiate the format of data
-(typically image format) exchanged between driver and
-application.</para>
-
-    <para>To query the current parameters applications set the
-<structfield>type</structfield> field of a struct
-<structname>v4l2_format</structname> to the respective buffer (stream)
-type. For example video capture devices use
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> or
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>. When the application
-calls the <constant>VIDIOC_G_FMT</constant> ioctl with a pointer to
-this structure the driver fills the respective member of the
-<structfield>fmt</structfield> union. In case of video capture devices
-that is either the &v4l2-pix-format; <structfield>pix</structfield> or
-the &v4l2-pix-format-mplane; <structfield>pix_mp</structfield> member.
-When the requested buffer type is not supported drivers return an
-&EINVAL;.</para>
-
-    <para>To change the current format parameters applications
-initialize the <structfield>type</structfield> field and all
-fields of the respective <structfield>fmt</structfield>
-union member. For details see the documentation of the various devices
-types in <xref linkend="devices" />. Good practice is to query the
-current parameters first, and to
-modify only those parameters not suitable for the application. When
-the application calls the <constant>VIDIOC_S_FMT</constant> ioctl
-with a pointer to a <structname>v4l2_format</structname> structure
-the driver checks
-and adjusts the parameters against hardware abilities. Drivers
-should not return an error code unless the input is ambiguous, this is
-a mechanism to fathom device capabilities and to approach parameters
-acceptable for both the application and driver. On success the driver
-may program the hardware, allocate resources and generally prepare for
-data exchange.
-Finally the <constant>VIDIOC_S_FMT</constant> ioctl returns the
-current format parameters as <constant>VIDIOC_G_FMT</constant> does.
-Very simple, inflexible devices may even ignore all input and always
-return the default parameters. However all V4L2 devices exchanging
-data with the application must implement the
-<constant>VIDIOC_G_FMT</constant> and
-<constant>VIDIOC_S_FMT</constant> ioctl. When the requested buffer
-type is not supported drivers return an &EINVAL; on a
-<constant>VIDIOC_S_FMT</constant> attempt. When I/O is already in
-progress or the resource is not available for other reasons drivers
-return the &EBUSY;.</para>
-
-    <para>The <constant>VIDIOC_TRY_FMT</constant> ioctl is equivalent
-to <constant>VIDIOC_S_FMT</constant> with one exception: it does not
-change driver state. It can also be called at any time, never
-returning <errorcode>EBUSY</errorcode>. This function is provided to
-negotiate parameters, to learn about hardware limitations, without
-disabling I/O or possibly time consuming hardware preparations.
-Although strongly recommended drivers are not required to implement
-this ioctl.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-format">
-      <title>struct <structname>v4l2_format</structname></title>
-      <tgroup cols="4">
-       <colspec colname="c1" />
-       <colspec colname="c2" />
-       <colspec colname="c3" />
-       <colspec colname="c4" />
-       <tbody valign="top">
-         <row>
-           <entry>&v4l2-buf-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>Type of the data stream, see <xref
-               linkend="v4l2-buf-type" />.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield>fmt</structfield></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-pix-format;</entry>
-           <entry><structfield>pix</structfield></entry>
-           <entry>Definition of an image format, see <xref
-               linkend="pixfmt" />, used by video capture and output
-devices.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-pix-format-mplane;</entry>
-           <entry><structfield>pix_mp</structfield></entry>
-           <entry>Definition of an image format, see <xref
-               linkend="pixfmt" />, used by video capture and output
-devices that support the <link linkend="planar-apis">multi-planar
-version of the API</link>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-window;</entry>
-           <entry><structfield>win</structfield></entry>
-           <entry>Definition of an overlaid image, see <xref
-           linkend="overlay" />, used by video overlay devices.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-vbi-format;</entry>
-           <entry><structfield>vbi</structfield></entry>
-           <entry>Raw VBI capture or output parameters. This is
-discussed in more detail in <xref linkend="raw-vbi" />. Used by raw VBI
-capture and output devices.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-sliced-vbi-format;</entry>
-           <entry><structfield>sliced</structfield></entry>
-           <entry>Sliced VBI capture or output parameters. See
-<xref linkend="sliced" /> for details. Used by sliced VBI
-capture and output devices.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u8</entry>
-           <entry><structfield>raw_data</structfield>[200]</entry>
-           <entry>Place holder for future extensions and custom
-(driver defined) formats with <structfield>type</structfield>
-<constant>V4L2_BUF_TYPE_PRIVATE</constant> and higher.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The data format cannot be changed at this
-time, for example because I/O is already in progress.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-format; <structfield>type</structfield>
-field is invalid, the requested buffer type not supported, or
-<constant>VIDIOC_TRY_FMT</constant> was called and is not
-supported with this buffer type.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-frequency.xml b/Documentation/DocBook/v4l/vidioc-g-frequency.xml
deleted file mode 100644 (file)
index 062d720..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-<refentry id="vidioc-g-frequency">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_FREQUENCY</refname>
-    <refname>VIDIOC_S_FREQUENCY</refname>
-    <refpurpose>Get or set tuner or modulator radio
-frequency</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_frequency
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_frequency
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To get the current tuner or modulator radio frequency
-applications set the <structfield>tuner</structfield> field of a
-&v4l2-frequency; to the respective tuner or modulator number (only
-input devices have tuners, only output devices have modulators), zero
-out the <structfield>reserved</structfield> array and
-call the <constant>VIDIOC_G_FREQUENCY</constant> ioctl with a pointer
-to this structure. The driver stores the current frequency in the
-<structfield>frequency</structfield> field.</para>
-
-    <para>To change the current tuner or modulator radio frequency
-applications initialize the <structfield>tuner</structfield>,
-<structfield>type</structfield> and
-<structfield>frequency</structfield> fields, and the
-<structfield>reserved</structfield> array of a &v4l2-frequency; and
-call the <constant>VIDIOC_S_FREQUENCY</constant> ioctl with a pointer
-to this structure. When the requested frequency is not possible the
-driver assumes the closest possible value. However
-<constant>VIDIOC_S_FREQUENCY</constant> is a write-only ioctl, it does
-not return the actual new frequency.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-frequency">
-      <title>struct <structname>v4l2_frequency</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>tuner</structfield></entry>
-           <entry>The tuner or modulator index number. This is the
-same value as in the &v4l2-input; <structfield>tuner</structfield>
-field and the &v4l2-tuner; <structfield>index</structfield> field, or
-the &v4l2-output; <structfield>modulator</structfield> field and the
-&v4l2-modulator; <structfield>index</structfield> field.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-tuner-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>The tuner type. This is the same value as in the
-&v4l2-tuner; <structfield>type</structfield> field. The field is not
-applicable to modulators, &ie; ignored by drivers.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>frequency</structfield></entry>
-           <entry>Tuning frequency in units of 62.5 kHz, or if the
-&v4l2-tuner; or &v4l2-modulator; <structfield>capabilities</structfield> flag
-<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Drivers and
-           applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <structfield>tuner</structfield> index is out of
-bounds or the value in the <structfield>type</structfield> field is
-wrong.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-input.xml b/Documentation/DocBook/v4l/vidioc-g-input.xml
deleted file mode 100644 (file)
index ed076e9..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-<refentry id="vidioc-g-input">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_INPUT, VIDIOC_S_INPUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_INPUT</refname>
-    <refname>VIDIOC_S_INPUT</refname>
-    <refpurpose>Query or select the current video input</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>int *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_INPUT, VIDIOC_S_INPUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the current video input applications call the
-<constant>VIDIOC_G_INPUT</constant> ioctl with a pointer to an integer
-where the driver stores the number of the input, as in the
-&v4l2-input; <structfield>index</structfield> field. This ioctl will
-fail only when there are no video inputs, returning
-<errorcode>EINVAL</errorcode>.</para>
-
-    <para>To select a video input applications store the number of the
-desired input in an integer and call the
-<constant>VIDIOC_S_INPUT</constant> ioctl with a pointer to this
-integer. Side effects are possible. For example inputs may support
-different video standards, so the driver may implicitly switch the
-current standard. It is good practice to select an input before
-querying or negotiating any other parameters.</para>
-
-    <para>Information about video inputs is available using the
-&VIDIOC-ENUMINPUT; ioctl.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The number of the video input is out of bounds, or
-there are no video inputs at all and this ioctl is not
-supported.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>I/O is in progress, the input cannot be
-switched.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-jpegcomp.xml b/Documentation/DocBook/v4l/vidioc-g-jpegcomp.xml
deleted file mode 100644 (file)
index 77394b2..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-<refentry id="vidioc-g-jpegcomp">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_JPEGCOMP</refname>
-    <refname>VIDIOC_S_JPEGCOMP</refname>
-    <refpurpose></refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>v4l2_jpegcompression *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const v4l2_jpegcompression *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_JPEGCOMP, VIDIOC_S_JPEGCOMP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>[to do]</para>
-
-    <para>Ronald Bultje elaborates:</para>
-
-    <!-- See video4linux-list@redhat.com on 16 Oct 2002, subject
-"Re: [V4L] Re: v4l2 api / Zoran v4l2_jpegcompression" -->
-
-    <para>APP is some application-specific information. The
-application can set it itself, and it'll be stored in the JPEG-encoded
-fields (eg; interlacing information for in an AVI or so). COM is the
-same, but it's comments, like 'encoded by me' or so.</para>
-
-    <para>jpeg_markers describes whether the huffman tables,
-quantization tables and the restart interval information (all
-JPEG-specific stuff) should be stored in the JPEG-encoded fields.
-These define how the JPEG field is encoded. If you omit them,
-applications assume you've used standard encoding. You usually do want
-to add them.</para>
-
-    <!-- NB VIDIOC_S_JPEGCOMP is w/o. -->
-
-    <table pgwide="1" frame="none" id="v4l2-jpegcompression">
-      <title>struct <structname>v4l2_jpegcompression</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>int</entry>
-           <entry><structfield>quality</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>int</entry>
-           <entry><structfield>APPn</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>int</entry>
-           <entry><structfield>APP_len</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>APP_data</structfield>[60]</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>int</entry>
-           <entry><structfield>COM_len</structfield></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>char</entry>
-           <entry><structfield>COM_data</structfield>[60]</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>jpeg_markers</structfield></entry>
-           <entry>See <xref linkend="jpeg-markers" />.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="jpeg-markers">
-      <title>JPEG Markers Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_JPEG_MARKER_DHT</constant></entry>
-           <entry>(1&lt;&lt;3)</entry>
-           <entry>Define Huffman Tables</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_JPEG_MARKER_DQT</constant></entry>
-           <entry>(1&lt;&lt;4)</entry>
-           <entry>Define Quantization Tables</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_JPEG_MARKER_DRI</constant></entry>
-           <entry>(1&lt;&lt;5)</entry>
-           <entry>Define Restart Interval</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_JPEG_MARKER_COM</constant></entry>
-           <entry>(1&lt;&lt;6)</entry>
-           <entry>Comment segment</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_JPEG_MARKER_APP</constant></entry>
-           <entry>(1&lt;&lt;7)</entry>
-           <entry>App segment, driver will always use APP0</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-modulator.xml b/Documentation/DocBook/v4l/vidioc-g-modulator.xml
deleted file mode 100644 (file)
index 15ce660..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-<refentry id="vidioc-g-modulator">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_MODULATOR</refname>
-    <refname>VIDIOC_S_MODULATOR</refname>
-    <refpurpose>Get or set modulator attributes</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_modulator
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_modulator
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_MODULATOR, VIDIOC_S_MODULATOR</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a modulator applications initialize
-the <structfield>index</structfield> field and zero out the
-<structfield>reserved</structfield> array of a &v4l2-modulator; and
-call the <constant>VIDIOC_G_MODULATOR</constant> ioctl with a pointer
-to this structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all modulators
-applications shall begin at index zero, incrementing by one until the
-driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <para>Modulators have two writable properties, an audio
-modulation set and the radio frequency. To change the modulated audio
-subprograms, applications initialize the <structfield>index
-</structfield> and <structfield>txsubchans</structfield> fields and the
-<structfield>reserved</structfield> array and call the
-<constant>VIDIOC_S_MODULATOR</constant> ioctl. Drivers may choose a
-different audio modulation if the request cannot be satisfied. However
-this is a write-only ioctl, it does not return the actual audio
-modulation selected.</para>
-
-    <para>To change the radio frequency the &VIDIOC-S-FREQUENCY; ioctl
-is available.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-modulator">
-      <title>struct <structname>v4l2_modulator</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Identifies the modulator, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the modulator, a NUL-terminated ASCII
-string. This information is intended for the user.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry>Modulator capability flags. No flags are defined
-for this field, the tuner flags in &v4l2-tuner;
-are used accordingly. The audio flags indicate the ability
-to encode audio subprograms. They will <emphasis>not</emphasis>
-change for example with the current video standard.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangelow</structfield></entry>
-           <entry>The lowest tunable frequency in units of 62.5
-KHz, or if the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangehigh</structfield></entry>
-           <entry>The highest tunable frequency in units of 62.5
-KHz, or if the <structfield>capability</structfield> flag
-<constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>txsubchans</structfield></entry>
-           <entry>With this field applications can determine how
-audio sub-carriers shall be modulated. It contains a set of flags as
-defined in <xref linkend="modulator-txsubchans" />. Note the tuner
-<structfield>rxsubchans</structfield> flags are reused, but the
-semantics are different. Video output devices are assumed to have an
-analog or PCM audio input with 1-3 channels. The
-<structfield>txsubchans</structfield> flags select one or more
-channels for modulation, together with some audio subprogram
-indicator, for example a stereo pilot tone.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="modulator-txsubchans">
-      <title>Modulator Audio Transmission Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_MONO</constant></entry>
-           <entry>0x0001</entry>
-           <entry>Modulate channel 1 as mono audio, when the input
-has more channels, a down-mix of channel 1 and 2. This flag does not
-combine with <constant>V4L2_TUNER_SUB_STEREO</constant> or
-<constant>V4L2_TUNER_SUB_LANG1</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_STEREO</constant></entry>
-           <entry>0x0002</entry>
-           <entry>Modulate channel 1 and 2 as left and right
-channel of a stereo audio signal. When the input has only one channel
-or two channels and <constant>V4L2_TUNER_SUB_SAP</constant> is also
-set, channel 1 is encoded as left and right channel. This flag does
-not combine with <constant>V4L2_TUNER_SUB_MONO</constant> or
-<constant>V4L2_TUNER_SUB_LANG1</constant>. When the driver does not
-support stereo audio it shall fall back to mono.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_LANG1</constant></entry>
-           <entry>0x0008</entry>
-           <entry>Modulate channel 1 and 2 as primary and secondary
-language of a bilingual audio signal. When the input has only one
-channel it is used for both languages. It is not possible to encode
-the primary or secondary language only. This flag does not combine
-with <constant>V4L2_TUNER_SUB_MONO</constant>,
-<constant>V4L2_TUNER_SUB_STEREO</constant> or
-<constant>V4L2_TUNER_SUB_SAP</constant>. If the hardware does not
-support the respective audio matrix, or the current video standard
-does not permit bilingual audio the
-<constant>VIDIOC_S_MODULATOR</constant> ioctl shall return an &EINVAL;
-and the driver shall fall back to mono or stereo mode.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_LANG2</constant></entry>
-           <entry>0x0004</entry>
-           <entry>Same effect as
-<constant>V4L2_TUNER_SUB_SAP</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_SAP</constant></entry>
-           <entry>0x0004</entry>
-           <entry>When combined with <constant>V4L2_TUNER_SUB_MONO
-</constant> the first channel is encoded as mono audio, the last
-channel as Second Audio Program. When the input has only one channel
-it is used for both audio tracks. When the input has three channels
-the mono track is a down-mix of channel 1 and 2. When combined with
-<constant>V4L2_TUNER_SUB_STEREO</constant> channel 1 and 2 are
-encoded as left and right stereo audio, channel 3 as Second Audio
-Program. When the input has only two channels, the first is encoded as
-left and right channel and the second as SAP. When the input has only
-one channel it is used for all audio tracks. It is not possible to
-encode a Second Audio Program only. This flag must combine with
-<constant>V4L2_TUNER_SUB_MONO</constant> or
-<constant>V4L2_TUNER_SUB_STEREO</constant>. If the hardware does not
-support the respective audio matrix, or the current video standard
-does not permit SAP the <constant>VIDIOC_S_MODULATOR</constant> ioctl
-shall return an &EINVAL; and driver shall fall back to mono or stereo
-mode.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_RDS</constant></entry>
-           <entry>0x0010</entry>
-           <entry>Enable the RDS encoder for a radio FM transmitter.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-modulator;
-<structfield>index</structfield> is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-output.xml b/Documentation/DocBook/v4l/vidioc-g-output.xml
deleted file mode 100644 (file)
index 3ea8c0e..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-<refentry id="vidioc-g-output">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_OUTPUT</refname>
-    <refname>VIDIOC_S_OUTPUT</refname>
-    <refpurpose>Query or select the current video output</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>int *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the current video output applications call the
-<constant>VIDIOC_G_OUTPUT</constant> ioctl with a pointer to an integer
-where the driver stores the number of the output, as in the
-&v4l2-output; <structfield>index</structfield> field. This ioctl
-will fail only when there are no video outputs, returning the
-&EINVAL;.</para>
-
-    <para>To select a video output applications store the number of the
-desired output in an integer and call the
-<constant>VIDIOC_S_OUTPUT</constant> ioctl with a pointer to this integer.
-Side effects are possible. For example outputs may support different
-video standards, so the driver may implicitly switch the current
-standard. It is good practice to select an output before querying or
-negotiating any other parameters.</para>
-
-    <para>Information about video outputs is available using the
-&VIDIOC-ENUMOUTPUT; ioctl.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The number of the video output is out of bounds, or
-there are no video outputs at all and this ioctl is not
-supported.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>I/O is in progress, the output cannot be
-switched.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-parm.xml b/Documentation/DocBook/v4l/vidioc-g-parm.xml
deleted file mode 100644 (file)
index 392aa9e..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-<refentry id="vidioc-g-parm">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_PARM, VIDIOC_S_PARM</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_PARM</refname>
-    <refname>VIDIOC_S_PARM</refname>
-    <refpurpose>Get or set streaming parameters</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>v4l2_streamparm *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_PARM, VIDIOC_S_PARM</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The current video standard determines a nominal number of
-frames per second. If less than this number of frames is to be
-captured or output, applications can request frame skipping or
-duplicating on the driver side. This is especially useful when using
-the <function>read()</function> or <function>write()</function>, which
-are not augmented by timestamps or sequence counters, and to avoid
-unnecessary data copying.</para>
-
-    <para>Further these ioctls can be used to determine the number of
-buffers used internally by a driver in read/write mode. For
-implications see the section discussing the &func-read;
-function.</para>
-
-    <para>To get and set the streaming parameters applications call
-the <constant>VIDIOC_G_PARM</constant> and
-<constant>VIDIOC_S_PARM</constant> ioctl, respectively. They take a
-pointer to a struct <structname>v4l2_streamparm</structname> which
-contains a union holding separate parameters for input and output
-devices.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-streamparm">
-      <title>struct <structname>v4l2_streamparm</structname></title>
-      <tgroup cols="4">
-       &cs-ustr;
-       <tbody valign="top">
-         <row>
-           <entry>&v4l2-buf-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry></entry>
-           <entry>The buffer (stream) type, same as &v4l2-format;
-<structfield>type</structfield>, set by the application.</entry>
-         </row>
-         <row>
-           <entry>union</entry>
-           <entry><structfield>parm</structfield></entry>
-           <entry></entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-captureparm;</entry>
-           <entry><structfield>capture</structfield></entry>
-           <entry>Parameters for capture devices, used when
-<structfield>type</structfield> is
-<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>&v4l2-outputparm;</entry>
-           <entry><structfield>output</structfield></entry>
-           <entry>Parameters for output devices, used when
-<structfield>type</structfield> is
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>.</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry>__u8</entry>
-           <entry><structfield>raw_data</structfield>[200]</entry>
-           <entry>A place holder for future extensions and custom
-(driver defined) buffer types <constant>V4L2_BUF_TYPE_PRIVATE</constant> and
-higher.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-captureparm">
-      <title>struct <structname>v4l2_captureparm</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry>See <xref linkend="parm-caps" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capturemode</structfield></entry>
-           <entry>Set by drivers and applications, see <xref linkend="parm-flags" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>timeperframe</structfield></entry>
-           <entry><para>This is is the desired period between
-successive frames captured by the driver, in seconds. The
-field is intended to skip frames on the driver side, saving I/O
-bandwidth.</para><para>Applications store here the desired frame
-period, drivers return the actual frame period, which must be greater
-or equal to the nominal frame period determined by the current video
-standard (&v4l2-standard; <structfield>frameperiod</structfield>
-field). Changing the video standard (also implicitly by switching the
-video input) may reset this parameter to the nominal frame period. To
-reset manually applications can just set this field to
-zero.</para><para>Drivers support this function only when they set the
-<constant>V4L2_CAP_TIMEPERFRAME</constant> flag in the
-<structfield>capability</structfield> field.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>extendedmode</structfield></entry>
-           <entry>Custom (driver specific) streaming parameters. When
-unused, applications and drivers must set this field to zero.
-Applications using this field should check the driver name and
-version, see <xref linkend="querycap" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>readbuffers</structfield></entry>
-           <entry>Applications set this field to the desired number
-of buffers used internally by the driver in &func-read; mode. Drivers
-return the actual number of buffers. When an application requests zero
-buffers, drivers should just return the current setting rather than
-the minimum or an error code. For details see <xref
-               linkend="rw" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-outputparm">
-      <title>struct <structname>v4l2_outputparm</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry>See <xref linkend="parm-caps" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>outputmode</structfield></entry>
-           <entry>Set by drivers and applications, see <xref
-           linkend="parm-flags" />.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>timeperframe</structfield></entry>
-           <entry>This is is the desired period between
-successive frames output by the driver, in seconds.</entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>The field is intended to
-repeat frames on the driver side in &func-write; mode (in streaming
-mode timestamps can be used to throttle the output), saving I/O
-bandwidth.</para><para>Applications store here the desired frame
-period, drivers return the actual frame period, which must be greater
-or equal to the nominal frame period determined by the current video
-standard (&v4l2-standard; <structfield>frameperiod</structfield>
-field). Changing the video standard (also implicitly by switching the
-video output) may reset this parameter to the nominal frame period. To
-reset manually applications can just set this field to
-zero.</para><para>Drivers support this function only when they set the
-<constant>V4L2_CAP_TIMEPERFRAME</constant> flag in the
-<structfield>capability</structfield> field.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>extendedmode</structfield></entry>
-           <entry>Custom (driver specific) streaming parameters. When
-unused, applications and drivers must set this field to zero.
-Applications using this field should check the driver name and
-version, see <xref linkend="querycap" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>writebuffers</structfield></entry>
-           <entry>Applications set this field to the desired number
-of buffers used internally by the driver in
-<function>write()</function> mode. Drivers return the actual number of
-buffers. When an application requests zero buffers, drivers should
-just return the current setting rather than the minimum or an error
-code. For details see <xref linkend="rw" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="parm-caps">
-      <title>Streaming Parameters Capabilites</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CAP_TIMEPERFRAME</constant></entry>
-           <entry>0x1000</entry>
-           <entry>The frame skipping/repeating controlled by the
-<structfield>timeperframe</structfield> field is supported.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="parm-flags">
-      <title>Capture Parameters Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_MODE_HIGHQUALITY</constant></entry>
-           <entry>0x0001</entry>
-           <entry><para>High quality imaging mode. High quality mode
-is intended for still imaging applications. The idea is to get the
-best possible image quality that the hardware can deliver. It is not
-defined how the driver writer may achieve that; it will depend on the
-hardware and the ingenuity of the driver writer. High quality mode is
-a different mode from the the regular motion video capture modes. In
-high quality mode:<itemizedlist>
-                 <listitem>
-                   <para>The driver may be able to capture higher
-resolutions than for motion capture.</para>
-                 </listitem>
-                 <listitem>
-                   <para>The driver may support fewer pixel formats
-than motion capture (eg; true color).</para>
-                 </listitem>
-                 <listitem>
-                   <para>The driver may capture and arithmetically
-combine multiple successive fields or frames to remove color edge
-artifacts and reduce the noise in the video data.
-</para>
-                 </listitem>
-                 <listitem>
-                   <para>The driver may capture images in slices like
-a scanner in order to handle larger format images than would otherwise
-be possible. </para>
-                 </listitem>
-                 <listitem>
-                   <para>An image capture operation may be
-significantly slower than motion capture. </para>
-                 </listitem>
-                 <listitem>
-                   <para>Moving objects in the image might have
-excessive motion blur. </para>
-                 </listitem>
-                 <listitem>
-                   <para>Capture might only work through the
-<function>read()</function> call.</para>
-                 </listitem>
-               </itemizedlist></para></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-priority.xml b/Documentation/DocBook/v4l/vidioc-g-priority.xml
deleted file mode 100644 (file)
index 5fb0019..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-<refentry id="vidioc-g-priority">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_PRIORITY</refname>
-    <refname>VIDIOC_S_PRIORITY</refname>
-    <refpurpose>Query or request the access priority associated with a
-file descriptor</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>enum v4l2_priority *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const enum v4l2_priority *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_PRIORITY, VIDIOC_S_PRIORITY</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para>Pointer to an enum v4l2_priority type.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the current access priority
-applications call the <constant>VIDIOC_G_PRIORITY</constant> ioctl
-with a pointer to an enum v4l2_priority variable where the driver stores
-the current priority.</para>
-
-    <para>To request an access priority applications store the
-desired priority in an enum v4l2_priority variable and call
-<constant>VIDIOC_S_PRIORITY</constant> ioctl with a pointer to this
-variable.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-priority">
-      <title>enum v4l2_priority</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_PRIORITY_UNSET</constant></entry>
-           <entry>0</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_PRIORITY_BACKGROUND</constant></entry>
-           <entry>1</entry>
-           <entry>Lowest priority, usually applications running in
-background, for example monitoring VBI transmissions. A proxy
-application running in user space will be necessary if multiple
-applications want to read from a device at this priority.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_PRIORITY_INTERACTIVE</constant></entry>
-           <entry>2</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_PRIORITY_DEFAULT</constant></entry>
-           <entry>2</entry>
-           <entry>Medium priority, usually applications started and
-interactively controlled by the user. For example TV viewers, Teletext
-browsers, or just "panel" applications to change the channel or video
-controls. This is the default priority unless an application requests
-another.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_PRIORITY_RECORD</constant></entry>
-           <entry>3</entry>
-           <entry>Highest priority. Only one file descriptor can have
-this priority, it blocks any other fd from changing device properties.
-Usually applications which must not be interrupted, like video
-recording.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The requested priority value is invalid, or the
-driver does not support access priorities.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>Another application already requested higher
-priority.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-sliced-vbi-cap.xml b/Documentation/DocBook/v4l/vidioc-g-sliced-vbi-cap.xml
deleted file mode 100644 (file)
index 10e721b..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-<refentry id="vidioc-g-sliced-vbi-cap">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_SLICED_VBI_CAP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_SLICED_VBI_CAP</refname>
-    <refpurpose>Query sliced VBI capabilities</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_sliced_vbi_cap *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_SLICED_VBI_CAP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To find out which data services are supported by a sliced
-VBI capture or output device, applications initialize the
-<structfield>type</structfield> field of a &v4l2-sliced-vbi-cap;,
-clear the <structfield>reserved</structfield> array and
-call the <constant>VIDIOC_G_SLICED_VBI_CAP</constant> ioctl. The
-driver fills in the remaining fields or returns an &EINVAL; if the
-sliced VBI API is unsupported or <structfield>type</structfield>
-is invalid.</para>
-
-    <para>Note the <structfield>type</structfield> field was added,
-and the ioctl changed from read-only to write-read, in Linux 2.6.19.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-sliced-vbi-cap">
-      <title>struct <structname>v4l2_sliced_vbi_cap</structname></title>
-      <tgroup cols="5">
-       <colspec colname="c1" colwidth="3*" />
-       <colspec colname="c2" colwidth="3*" />
-       <colspec colname="c3" colwidth="2*" />
-       <colspec colname="c4" colwidth="2*" />
-       <colspec colname="c5" colwidth="2*" />
-       <spanspec spanname="hspan" namest="c3" nameend="c5" />
-       <tbody valign="top">
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>service_set</structfield></entry>
-           <entry spanname="hspan">A set of all data services
-supported by the driver. Equal to the union of all elements of the
-<structfield>service_lines </structfield> array.</entry>
-         </row>
-         <row>
-           <entry>__u16</entry>
-           <entry><structfield>service_lines</structfield>[2][24]</entry>
-           <entry spanname="hspan">Each element of this array
-contains a set of data services the hardware can look for or insert
-into a particular scan line. Data services are defined in <xref
-               linkend="vbi-services" />. Array indices map to ITU-R
-line numbers (see also <xref
-               linkend="vbi-525" /> and <xref
-linkend="vbi-625" />) as follows:</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry>Element</entry>
-           <entry>525 line systems</entry>
-           <entry>625 line systems</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[0][1]</entry>
-           <entry align="center">1</entry>
-           <entry align="center">1</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[0][23]</entry>
-           <entry align="center">23</entry>
-           <entry align="center">23</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[1][1]</entry>
-           <entry align="center">264</entry>
-           <entry align="center">314</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><structfield>service_lines</structfield>[1][23]</entry>
-           <entry align="center">286</entry>
-           <entry align="center">336</entry>
-         </row>
-         <row>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry spanname="hspan">The number of VBI lines the
-hardware can capture or output per frame, or the number of services it
-can identify on a given line may be limited. For example on PAL line
-16 the hardware may be able to look for a VPS or Teletext signal, but
-not both at the same time. Applications can learn about these limits
-using the &VIDIOC-S-FMT; ioctl as described in <xref
-               linkend="sliced" />.</entry>
-         </row>
-         <row>
-           <entry></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry spanname="hspan">Drivers must set
-<structfield>service_lines</structfield>[0][0] and
-<structfield>service_lines</structfield>[1][0] to zero.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-buf-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the data stream, see <xref
-                 linkend="v4l2-buf-type" />. Should be
-<constant>V4L2_BUF_TYPE_SLICED_VBI_CAPTURE</constant> or
-<constant>V4L2_BUF_TYPE_SLICED_VBI_OUTPUT</constant>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[3]</entry>
-           <entry spanname="hspan">This array is reserved for future
-extensions. Applications and drivers must set it to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <!-- See also dev-sliced-vbi.sgml -->
-    <table pgwide="1" frame="none" id="vbi-services">
-      <title>Sliced VBI services</title>
-      <tgroup cols="5">
-       <colspec colname="c1" colwidth="2*" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="1*" />
-       <colspec colname="c4" colwidth="2*" />
-       <colspec colname="c5" colwidth="2*" />
-       <spanspec spanname='rlp' namest='c3' nameend='c5' />
-       <thead>
-         <row>
-           <entry>Symbol</entry>
-           <entry>Value</entry>
-           <entry>Reference</entry>
-           <entry>Lines, usually</entry>
-           <entry>Payload</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_SLICED_TELETEXT_B</constant> (Teletext
-System B)</entry>
-           <entry>0x0001</entry>
-           <entry><xref linkend="ets300706" />, <xref linkend="itu653" /></entry>
-           <entry>PAL/SECAM line 7-22, 320-335 (second field 7-22)</entry>
-           <entry>Last 42 of the 45 byte Teletext packet, that is
-without clock run-in and framing code, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VPS</constant></entry>
-           <entry>0x0400</entry>
-           <entry><xref linkend="ets300231" /></entry>
-           <entry>PAL line 16</entry>
-           <entry>Byte number 3 to 15 according to Figure 9 of
-ETS&nbsp;300&nbsp;231, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_CAPTION_525</constant></entry>
-           <entry>0x1000</entry>
-           <entry><xref linkend="eia608" /></entry>
-           <entry>NTSC line 21, 284 (second field 21)</entry>
-           <entry>Two bytes in transmission order, including parity
-bit, lsb first transmitted.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_WSS_625</constant></entry>
-           <entry>0x4000</entry>
-           <entry><xref linkend="en300294" />, <xref linkend="itu1119" /></entry>
-           <entry>PAL/SECAM line 23</entry>
-           <entry><screen>
-Byte        0                 1
-     msb         lsb  msb           lsb
-Bit  7 6 5 4 3 2 1 0  x x 13 12 11 10 9
-</screen></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VBI_525</constant></entry>
-           <entry>0x1000</entry>
-           <entry spanname="rlp">Set of services applicable to 525
-line systems.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_SLICED_VBI_625</constant></entry>
-           <entry>0x4401</entry>
-           <entry spanname="rlp">Set of services applicable to 625
-line systems.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The device does not support sliced VBI capturing or
-output, or the value in the <structfield>type</structfield> field is
-wrong.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-std.xml b/Documentation/DocBook/v4l/vidioc-g-std.xml
deleted file mode 100644 (file)
index 912f851..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-<refentry id="vidioc-g-std">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_STD, VIDIOC_S_STD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_STD</refname>
-    <refname>VIDIOC_S_STD</refname>
-    <refpurpose>Query or select the video standard of the current input</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>v4l2_std_id
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const v4l2_std_id
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_STD, VIDIOC_S_STD</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query and select the current video standard applications
-use the <constant>VIDIOC_G_STD</constant> and <constant>VIDIOC_S_STD</constant> ioctls which take a pointer to a
-&v4l2-std-id; type as argument. <constant>VIDIOC_G_STD</constant> can
-return a single flag or a set of flags as in &v4l2-standard; field
-<structfield>id</structfield>. The flags must be unambiguous such
-that they appear in only one enumerated <structname>v4l2_standard</structname> structure.</para>
-
-    <para><constant>VIDIOC_S_STD</constant> accepts one or more
-flags, being a write-only ioctl it does not return the actual new standard as
-<constant>VIDIOC_G_STD</constant> does. When no flags are given or
-the current input does not support the requested standard the driver
-returns an &EINVAL;. When the standard set is ambiguous drivers may
-return <errorcode>EINVAL</errorcode> or choose any of the requested
-standards.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported, or the
-<constant>VIDIOC_S_STD</constant> parameter was unsuitable.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The device is busy and therefore can not change the standard</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/v4l/vidioc-g-tuner.xml
deleted file mode 100644 (file)
index bd98c73..0000000
+++ /dev/null
@@ -1,535 +0,0 @@
-<refentry id="vidioc-g-tuner">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_G_TUNER, VIDIOC_S_TUNER</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_G_TUNER</refname>
-    <refname>VIDIOC_S_TUNER</refname>
-    <refpurpose>Get or set tuner attributes</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_tuner
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_tuner
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_G_TUNER, VIDIOC_S_TUNER</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a tuner applications initialize the
-<structfield>index</structfield> field and zero out the
-<structfield>reserved</structfield> array of a &v4l2-tuner; and call the
-<constant>VIDIOC_G_TUNER</constant> ioctl with a pointer to this
-structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all tuners
-applications shall begin at index zero, incrementing by one until the
-driver returns <errorcode>EINVAL</errorcode>.</para>
-
-    <para>Tuners have two writable properties, the audio mode and
-the radio frequency. To change the audio mode, applications initialize
-the <structfield>index</structfield>,
-<structfield>audmode</structfield> and
-<structfield>reserved</structfield> fields and call the
-<constant>VIDIOC_S_TUNER</constant> ioctl. This will
-<emphasis>not</emphasis> change the current tuner, which is determined
-by the current video input. Drivers may choose a different audio mode
-if the requested mode is invalid or unsupported. Since this is a
-<!-- FIXME -->write-only ioctl, it does not return the actually
-selected audio mode.</para>
-
-    <para>To change the radio frequency the &VIDIOC-S-FREQUENCY; ioctl
-is available.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-tuner">
-      <title>struct <structname>v4l2_tuner</structname></title>
-      <tgroup cols="3">
-       <colspec colname="c1" colwidth="1*" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colname="c3" colwidth="1*" />
-       <colspec colname="c4" colwidth="1*" />
-       <spanspec spanname="hspan" namest="c3" nameend="c4" />
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry spanname="hspan">Identifies the tuner, set by the
-application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry spanname="hspan"><para>Name of the tuner, a
-NUL-terminated ASCII string. This information is intended for the
-user.<!-- FIXME Video inputs already have a name, the purpose of this
-field is not quite clear.--></para></entry>
-         </row>
-         <row>
-           <entry>&v4l2-tuner-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry spanname="hspan">Type of the tuner, see <xref
-               linkend="v4l2-tuner-type" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capability</structfield></entry>
-           <entry spanname="hspan"><para>Tuner capability flags, see
-<xref linkend="tuner-capability" />. Audio flags indicate the ability
-to decode audio subprograms. They will <emphasis>not</emphasis>
-change, for example with the current video standard.</para><para>When
-the structure refers to a radio tuner only the
-<constant>V4L2_TUNER_CAP_LOW</constant>,
-<constant>V4L2_TUNER_CAP_STEREO</constant> and
-<constant>V4L2_TUNER_CAP_RDS</constant> flags can be set.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangelow</structfield></entry>
-           <entry spanname="hspan">The lowest tunable frequency in
-units of 62.5 kHz, or if the <structfield>capability</structfield>
-flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rangehigh</structfield></entry>
-           <entry spanname="hspan">The highest tunable frequency in
-units of 62.5 kHz, or if the <structfield>capability</structfield>
-flag <constant>V4L2_TUNER_CAP_LOW</constant> is set, in units of 62.5
-Hz.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>rxsubchans</structfield></entry>
-           <entry spanname="hspan"><para>Some tuners or audio
-decoders can determine the received audio subprograms by analyzing
-audio carriers, pilot tones or other indicators. To pass this
-information drivers set flags defined in <xref
-                 linkend="tuner-rxsubchans" /> in this field. For
-example:</para></entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><constant>V4L2_TUNER_SUB_MONO</constant></entry>
-           <entry>receiving mono audio</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><constant>STEREO | SAP</constant></entry>
-           <entry>receiving stereo audio and a secondary audio
-program</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><constant>MONO | STEREO</constant></entry>
-           <entry>receiving mono or stereo audio, the hardware cannot
-distinguish</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><constant>LANG1 | LANG2</constant></entry>
-           <entry>receiving bilingual audio</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry><constant>MONO | STEREO | LANG1 | LANG2</constant></entry>
-           <entry>receiving mono, stereo or bilingual
-audio</entry>
-         </row>
-         <row>
-           <entry></entry>
-           <entry></entry>
-           <entry spanname="hspan"><para>When the
-<constant>V4L2_TUNER_CAP_STEREO</constant>,
-<constant>_LANG1</constant>, <constant>_LANG2</constant> or
-<constant>_SAP</constant> flag is cleared in the
-<structfield>capability</structfield> field, the corresponding
-<constant>V4L2_TUNER_SUB_</constant> flag must not be set
-here.</para><para>This field is valid only if this is the tuner of the
-current video input, or when the structure refers to a radio
-tuner.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>audmode</structfield></entry>
-           <entry spanname="hspan"><para>The selected audio mode, see
-<xref linkend="tuner-audmode" /> for valid values. The audio mode does
-not affect audio subprogram detection, and like a <link
-linkend="control">control</link> it does not automatically change
-unless the requested mode is invalid or unsupported. See <xref
-                 linkend="tuner-matrix" /> for possible results when
-the selected and received audio programs do not
-match.</para><para>Currently this is the only field of struct
-<structname>v4l2_tuner</structname> applications can
-change.</para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>signal</structfield></entry>
-           <entry spanname="hspan">The signal strength if known, ranging
-from 0 to 65535. Higher values indicate a better signal.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>afc</structfield></entry>
-           <entry spanname="hspan">Automatic frequency control: When the
-<structfield>afc</structfield> value is negative, the frequency is too
-low, when positive too high.<!-- FIXME need example what to do when it never
-settles at zero, &ie; range is what? --></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry spanname="hspan">Reserved for future extensions. Drivers and
-applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-tuner-type">
-      <title>enum v4l2_tuner_type</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_TUNER_RADIO</constant></entry>
-           <entry>1</entry>
-           <entry></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_ANALOG_TV</constant></entry>
-           <entry>2</entry>
-           <entry></entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="tuner-capability">
-      <title>Tuner and Modulator Capability Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_LOW</constant></entry>
-           <entry>0x0001</entry>
-           <entry>When set, tuning frequencies are expressed in units of
-62.5&nbsp;Hz, otherwise in units of 62.5&nbsp;kHz.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_NORM</constant></entry>
-           <entry>0x0002</entry>
-           <entry>This is a multi-standard tuner; the video standard
-can or must be switched. (B/G PAL tuners for example are typically not
-      considered multi-standard because the video standard is automatically
-      determined from the frequency band.) The set of supported video
-      standards is available from the &v4l2-input; pointing to this tuner,
-      see the description of ioctl &VIDIOC-ENUMINPUT; for details. Only
-      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
-         </row>
-         <row>
-       <entry><constant>V4L2_TUNER_CAP_STEREO</constant></entry>
-       <entry>0x0010</entry>
-       <entry>Stereo audio reception is supported.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_LANG1</constant></entry>
-           <entry>0x0040</entry>
-           <entry>Reception of the primary language of a bilingual
-audio program is supported. Bilingual audio is a feature of
-two-channel systems, transmitting the primary language monaural on the
-main audio carrier and a secondary language monaural on a second
-carrier. Only
-      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_LANG2</constant></entry>
-           <entry>0x0020</entry>
-           <entry>Reception of the secondary language of a bilingual
-audio program is supported. Only
-      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_CAP_SAP</constant></entry>
-           <entry>0x0020</entry>
-           <entry><para>Reception of a secondary audio program is
-supported. This is a feature of the BTSC system which accompanies the
-NTSC video standard. Two audio carriers are available for mono or
-stereo transmissions of a primary language, and an independent third
-carrier for a monaural secondary language. Only
-      <constant>V4L2_TUNER_ANALOG_TV</constant> tuners can have this capability.</para><para>Note the
-<constant>V4L2_TUNER_CAP_LANG2</constant> and
-<constant>V4L2_TUNER_CAP_SAP</constant> flags are synonyms.
-<constant>V4L2_TUNER_CAP_SAP</constant> applies when the tuner
-supports the <constant>V4L2_STD_NTSC_M</constant> video
-standard.</para><!-- FIXME what if PAL+NTSC and Bi but not SAP? --></entry>
-         </row>
-         <row>
-       <entry><constant>V4L2_TUNER_CAP_RDS</constant></entry>
-       <entry>0x0080</entry>
-       <entry>RDS capture is supported. This capability is only valid for
-radio tuners.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="tuner-rxsubchans">
-      <title>Tuner Audio Reception Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_MONO</constant></entry>
-           <entry>0x0001</entry>
-           <entry>The tuner receives a mono audio signal.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_STEREO</constant></entry>
-           <entry>0x0002</entry>
-           <entry>The tuner receives a stereo audio signal.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_LANG1</constant></entry>
-           <entry>0x0008</entry>
-           <entry>The tuner receives the primary language of a
-bilingual audio signal. Drivers must clear this flag when the current
-video standard is <constant>V4L2_STD_NTSC_M</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_LANG2</constant></entry>
-           <entry>0x0004</entry>
-           <entry>The tuner receives the secondary language of a
-bilingual audio signal (or a second audio program).</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_SAP</constant></entry>
-           <entry>0x0004</entry>
-           <entry>The tuner receives a Second Audio Program. Note the
-<constant>V4L2_TUNER_SUB_LANG2</constant> and
-<constant>V4L2_TUNER_SUB_SAP</constant> flags are synonyms. The
-<constant>V4L2_TUNER_SUB_SAP</constant> flag applies when the
-current video standard is <constant>V4L2_STD_NTSC_M</constant>.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_SUB_RDS</constant></entry>
-           <entry>0x0010</entry>
-           <entry>The tuner receives an RDS channel.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="tuner-audmode">
-      <title>Tuner Audio Modes</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_MONO</constant></entry>
-           <entry>0</entry>
-           <entry>Play mono audio. When the tuner receives a stereo
-signal this a down-mix of the left and right channel. When the tuner
-receives a bilingual or SAP signal this mode selects the primary
-language.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_STEREO</constant></entry>
-           <entry>1</entry>
-           <entry><para>Play stereo audio. When the tuner receives
-bilingual audio it may play different languages on the left and right
-channel or the primary language is played on both channels.</para><para>Playing
-different languages in this mode is
-deprecated. New drivers should do this only in
-<constant>MODE_LANG1_LANG2</constant>.</para><para>When the tuner
-receives no stereo signal or does not support stereo reception the
-driver shall fall back to <constant>MODE_MONO</constant>.</para></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_LANG1</constant></entry>
-           <entry>3</entry>
-           <entry>Play the primary language, mono or stereo. Only
-<constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this
-mode.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_LANG2</constant></entry>
-           <entry>2</entry>
-           <entry>Play the secondary language, mono. When the tuner
-receives no bilingual audio or SAP, or their reception is not
-supported the driver shall fall back to mono or stereo mode. Only
-<constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this
-mode.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_SAP</constant></entry>
-           <entry>2</entry>
-           <entry>Play the Second Audio Program. When the tuner
-receives no bilingual audio or SAP, or their reception is not
-supported the driver shall fall back to mono or stereo mode. Only
-<constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this mode.
-Note the <constant>V4L2_TUNER_MODE_LANG2</constant> and
-<constant>V4L2_TUNER_MODE_SAP</constant> are synonyms.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_TUNER_MODE_LANG1_LANG2</constant></entry>
-           <entry>4</entry>
-           <entry>Play the primary language on the left channel, the
-secondary language on the right channel. When the tuner receives no
-bilingual audio or SAP, it shall fall back to
-<constant>MODE_LANG1</constant> or <constant>MODE_MONO</constant>.
-Only <constant>V4L2_TUNER_ANALOG_TV</constant> tuners support this
-mode.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="all" id="tuner-matrix">
-      <title>Tuner Audio Matrix</title>
-      <tgroup cols="6" align="center">
-       <colspec align="left" />
-       <colspec colname="c2" colwidth="1*" />
-       <colspec colwidth="1*" />
-       <colspec colwidth="1*" />
-       <colspec colnum="6" colname="c6" colwidth="1*" />
-       <spanspec namest="c2" nameend="c6" spanname="hspan" align="center" />
-       <thead>
-         <row>
-           <entry></entry>
-           <entry spanname="hspan">Selected
-<constant>V4L2_TUNER_MODE_</constant></entry>
-         </row>
-         <row>
-           <entry>Received <constant>V4L2_TUNER_SUB_</constant></entry>
-           <entry><constant>MONO</constant></entry>
-           <entry><constant>STEREO</constant></entry>
-           <entry><constant>LANG1</constant></entry>
-           <entry><constant>LANG2 = SAP</constant></entry>
-           <entry><constant>LANG1_LANG2</constant><footnote><para>This
-mode has been added in Linux 2.6.17 and may not be supported by older
-drivers.</para></footnote></entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>MONO</constant></entry>
-           <entry>Mono</entry>
-           <entry>Mono/Mono</entry>
-           <entry>Mono</entry>
-           <entry>Mono</entry>
-           <entry>Mono/Mono</entry>
-         </row>
-         <row>
-           <entry><constant>MONO | SAP</constant></entry>
-           <entry>Mono</entry>
-           <entry>Mono/Mono</entry>
-           <entry>Mono</entry>
-           <entry>SAP</entry>
-           <entry>Mono/SAP (preferred) or Mono/Mono</entry>
-         </row>
-         <row>
-           <entry><constant>STEREO</constant></entry>
-           <entry>L+R</entry>
-           <entry>L/R</entry>
-           <entry>Stereo L/R (preferred) or Mono L+R</entry>
-           <entry>Stereo L/R (preferred) or Mono L+R</entry>
-           <entry>L/R (preferred) or L+R/L+R</entry>
-         </row>
-         <row>
-           <entry><constant>STEREO | SAP</constant></entry>
-           <entry>L+R</entry>
-           <entry>L/R</entry>
-           <entry>Stereo L/R (preferred) or Mono L+R</entry>
-           <entry>SAP</entry>
-           <entry>L+R/SAP (preferred) or L/R or L+R/L+R</entry>
-         </row>
-         <row>
-           <entry><constant>LANG1 | LANG2</constant></entry>
-           <entry>Language&nbsp;1</entry>
-           <entry>Lang1/Lang2 (deprecated<footnote><para>Playback of
-both languages in <constant>MODE_STEREO</constant> is deprecated. In
-the future drivers should produce only the primary language in this
-mode. Applications should request
-<constant>MODE_LANG1_LANG2</constant> to record both languages or a
-stereo signal.</para></footnote>) or
-Lang1/Lang1</entry>
-           <entry>Language&nbsp;1</entry>
-           <entry>Language&nbsp;2</entry>
-           <entry>Lang1/Lang2 (preferred) or Lang1/Lang1</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-tuner; <structfield>index</structfield> is
-out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-log-status.xml b/Documentation/DocBook/v4l/vidioc-log-status.xml
deleted file mode 100644 (file)
index 2634b7c..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-<refentry id="vidioc-log-status">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_LOG_STATUS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_LOG_STATUS</refname>
-    <refpurpose>Log driver status information</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>As the video/audio devices become more complicated it
-becomes harder to debug problems. When this ioctl is called the driver
-will output the current device status to the kernel log. This is
-particular useful when dealing with problems like no sound, no video
-and incorrectly tuned channels. Also many modern devices autodetect
-video and audio standards and this ioctl will report what the device
-thinks what the standard is. Mismatches may give an indication where
-the problem is.</para>
-
-    <para>This ioctl is optional and not all drivers support it. It
-was introduced in Linux 2.6.15.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The driver does not support this ioctl.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-overlay.xml b/Documentation/DocBook/v4l/vidioc-overlay.xml
deleted file mode 100644 (file)
index 1036c58..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<refentry id="vidioc-overlay">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_OVERLAY</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_OVERLAY</refname>
-    <refpurpose>Start or stop video overlay</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const int *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_OVERLAY</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl is part of the <link linkend="overlay">video
-    overlay</link> I/O method. Applications call
-    <constant>VIDIOC_OVERLAY</constant> to start or stop the
-    overlay. It takes a pointer to an integer which must be set to
-    zero by the application to stop overlay, to one to start.</para>
-
-    <para>Drivers do not support &VIDIOC-STREAMON; or
-&VIDIOC-STREAMOFF; with <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>Video overlay is not supported, or the
-parameters have not been set up. See <xref
-linkend="overlay" /> for the necessary steps.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-qbuf.xml b/Documentation/DocBook/v4l/vidioc-qbuf.xml
deleted file mode 100644 (file)
index f2b11f8..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-<refentry id="vidioc-qbuf">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QBUF, VIDIOC_DQBUF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QBUF</refname>
-    <refname>VIDIOC_DQBUF</refname>
-    <refpurpose>Exchange a buffer with the driver</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_QBUF, VIDIOC_DQBUF</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Applications call the <constant>VIDIOC_QBUF</constant> ioctl
-to enqueue an empty (capturing) or filled (output) buffer in the
-driver's incoming queue. The semantics depend on the selected I/O
-method.</para>
-
-    <para>To enqueue a buffer applications set the <structfield>type</structfield>
-field of a &v4l2-buffer; to the same buffer type as was previously used
-with &v4l2-format; <structfield>type</structfield> and &v4l2-requestbuffers;
-<structfield>type</structfield>. Applications must also set the
-<structfield>index</structfield> field. Valid index numbers range from
-zero to the number of buffers allocated with &VIDIOC-REQBUFS;
-(&v4l2-requestbuffers; <structfield>count</structfield>) minus one. The
-contents of the struct <structname>v4l2_buffer</structname> returned
-by a &VIDIOC-QUERYBUF; ioctl will do as well. When the buffer is
-intended for output (<structfield>type</structfield> is
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
-<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>, or
-<constant>V4L2_BUF_TYPE_VBI_OUTPUT</constant>) applications must also
-initialize the <structfield>bytesused</structfield>,
-<structfield>field</structfield> and
-<structfield>timestamp</structfield> fields, see <xref
-linkend="buffer" /> for details.
-Applications must also set <structfield>flags</structfield> to 0. If a driver
-supports capturing from specific video inputs and you want to specify a video
-input, then <structfield>flags</structfield> should be set to
-<constant>V4L2_BUF_FLAG_INPUT</constant> and the field
-<structfield>input</structfield> must be initialized to the desired input.
-The <structfield>reserved</structfield> field must be set to 0. When using
-the <link linkend="planar-apis">multi-planar API</link>, the
-<structfield>m.planes</structfield> field must contain a userspace pointer
-to a filled-in array of &v4l2-plane; and the <structfield>length</structfield>
-field must be set to the number of elements in that array.
-</para>
-
-    <para>To enqueue a <link linkend="mmap">memory mapped</link>
-buffer applications set the <structfield>memory</structfield>
-field to <constant>V4L2_MEMORY_MMAP</constant>. When
-<constant>VIDIOC_QBUF</constant> is called with a pointer to this
-structure the driver sets the
-<constant>V4L2_BUF_FLAG_MAPPED</constant> and
-<constant>V4L2_BUF_FLAG_QUEUED</constant> flags and clears the
-<constant>V4L2_BUF_FLAG_DONE</constant> flag in the
-<structfield>flags</structfield> field, or it returns an
-&EINVAL;.</para>
-
-    <para>To enqueue a <link linkend="userp">user pointer</link>
-buffer applications set the <structfield>memory</structfield>
-field to <constant>V4L2_MEMORY_USERPTR</constant>, the
-<structfield>m.userptr</structfield> field to the address of the
-buffer and <structfield>length</structfield> to its size. When the multi-planar
-API is used, <structfield>m.userptr</structfield> and
-<structfield>length</structfield> members of the passed array of &v4l2-plane;
-have to be used instead. When <constant>VIDIOC_QBUF</constant> is called with
-a pointer to this structure the driver sets the
-<constant>V4L2_BUF_FLAG_QUEUED</constant> flag and clears the
-<constant>V4L2_BUF_FLAG_MAPPED</constant> and
-<constant>V4L2_BUF_FLAG_DONE</constant> flags in the
-<structfield>flags</structfield> field, or it returns an error code.
-This ioctl locks the memory pages of the buffer in physical memory,
-they cannot be swapped out to disk. Buffers remain locked until
-dequeued, until the &VIDIOC-STREAMOFF; or &VIDIOC-REQBUFS; ioctl is
-called, or until the device is closed.</para>
-
-    <para>Applications call the <constant>VIDIOC_DQBUF</constant>
-ioctl to dequeue a filled (capturing) or displayed (output) buffer
-from the driver's outgoing queue. They just set the
-<structfield>type</structfield>, <structfield>memory</structfield>
-and <structfield>reserved</structfield>
-fields of a &v4l2-buffer; as above, when <constant>VIDIOC_DQBUF</constant>
-is called with a pointer to this structure the driver fills the
-remaining fields or returns an error code. The driver may also set
-<constant>V4L2_BUF_FLAG_ERROR</constant> in the <structfield>flags</structfield>
-field. It indicates a non-critical (recoverable) streaming error. In such case
-the application may continue as normal, but should be aware that data in the
-dequeued buffer might be corrupted. When using the multi-planar API, the
-planes array does not have to be passed; the <structfield>m.planes</structfield>
-member must be set to NULL in that case.</para>
-
-    <para>By default <constant>VIDIOC_DQBUF</constant> blocks when no
-buffer is in the outgoing queue. When the
-<constant>O_NONBLOCK</constant> flag was given to the &func-open;
-function, <constant>VIDIOC_DQBUF</constant> returns immediately
-with an &EAGAIN; when no buffer is available.</para>
-
-    <para>The <structname>v4l2_buffer</structname> structure is
-specified in <xref linkend="buffer" />.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EAGAIN</errorcode></term>
-       <listitem>
-         <para>Non-blocking I/O has been selected using
-<constant>O_NONBLOCK</constant> and no buffer was in the outgoing
-queue.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The buffer <structfield>type</structfield> is not
-supported, or the <structfield>index</structfield> is out of bounds,
-or no buffers have been allocated yet, or the
-<structfield>userptr</structfield> or
-<structfield>length</structfield> are invalid.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>ENOMEM</errorcode></term>
-       <listitem>
-         <para>Not enough physical or virtual memory was available to
-enqueue a user pointer buffer.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EIO</errorcode></term>
-       <listitem>
-         <para><constant>VIDIOC_DQBUF</constant> failed due to an
-internal error. Can also indicate temporary problems like signal
-loss. Note the driver might dequeue an (empty) buffer despite
-returning an error, or even stop capturing. Reusing such buffer may be unsafe
-though and its details (e.g. <structfield>index</structfield>) may not be
-returned either. It is recommended that drivers indicate recoverable errors
-by setting the <constant>V4L2_BUF_FLAG_ERROR</constant> and returning 0 instead.
-In that case the application should be able to safely reuse the buffer and
-continue streaming.
-       </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
deleted file mode 100644 (file)
index d272f7a..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-<refentry id="vidioc-query-dv-preset">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERY_DV_PRESET</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QUERY_DV_PRESET</refname>
-    <refpurpose>Sense the DV preset received by the current
-input</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_dv_preset *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-       <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_QUERY_DV_PRESET</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The hardware may be able to detect the current DV preset
-automatically, similar to sensing the video standard. To do so, applications
-call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a
-&v4l2-dv-preset; type. Once the hardware detects a preset, that preset is
-returned in the preset field of &v4l2-dv-preset;. If the preset could not be
-detected because there was no signal, or the signal was unreliable, or the
-signal did not map to a supported preset, then the value V4L2_DV_INVALID is
-returned.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported.</para>
-       </listitem>
-    </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The device is busy and therefore can not sense the preset</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-querybuf.xml b/Documentation/DocBook/v4l/vidioc-querybuf.xml
deleted file mode 100644 (file)
index 5c104d4..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-<refentry id="vidioc-querybuf">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERYBUF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QUERYBUF</refname>
-    <refpurpose>Query the status of a buffer</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_QUERYBUF</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl is part of the <link linkend="mmap">memory
-mapping</link> I/O method. It can be used to query the status of a
-buffer at any time after buffers have been allocated with the
-&VIDIOC-REQBUFS; ioctl.</para>
-
-    <para>Applications set the <structfield>type</structfield> field
-    of a &v4l2-buffer; to the same buffer type as was previously used with
-&v4l2-format; <structfield>type</structfield> and &v4l2-requestbuffers;
-<structfield>type</structfield>, and the <structfield>index</structfield>
-    field. Valid index numbers range from zero
-to the number of buffers allocated with &VIDIOC-REQBUFS;
-    (&v4l2-requestbuffers; <structfield>count</structfield>) minus one.
-The <structfield>reserved</structfield> field should to set to 0.
-When using the <link linkend="planar-apis">multi-planar API</link>, the
-<structfield>m.planes</structfield> field must contain a userspace pointer to an
-array of &v4l2-plane; and the <structfield>length</structfield> field has
-to be set to the number of elements in that array.
-After calling <constant>VIDIOC_QUERYBUF</constant> with a pointer to
-    this structure drivers return an error code or fill the rest of
-the structure.</para>
-
-    <para>In the <structfield>flags</structfield> field the
-<constant>V4L2_BUF_FLAG_MAPPED</constant>,
-<constant>V4L2_BUF_FLAG_QUEUED</constant> and
-<constant>V4L2_BUF_FLAG_DONE</constant> flags will be valid. The
-<structfield>memory</structfield> field will be set to the current
-I/O method. For the single-planar API, the <structfield>m.offset</structfield>
-contains the offset of the buffer from the start of the device memory,
-the <structfield>length</structfield> field its size. For the multi-planar API,
-fields <structfield>m.mem_offset</structfield> and
-<structfield>length</structfield> in the <structfield>m.planes</structfield>
-array elements will be used instead. The driver may or may not set the remaining
-fields and flags, they are meaningless in this context.</para>
-
-    <para>The <structname>v4l2_buffer</structname> structure is
-    specified in <xref linkend="buffer" />.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The buffer <structfield>type</structfield> is not
-supported, or the <structfield>index</structfield> is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-querycap.xml b/Documentation/DocBook/v4l/vidioc-querycap.xml
deleted file mode 100644 (file)
index f29f1b8..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-<refentry id="vidioc-querycap">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERYCAP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QUERYCAP</refname>
-    <refpurpose>Query device capabilities</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_capability *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_QUERYCAP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>All V4L2 devices support the
-<constant>VIDIOC_QUERYCAP</constant> ioctl. It is used to identify
-kernel devices compatible with this specification and to obtain
-information about driver and hardware capabilities. The ioctl takes a
-pointer to a &v4l2-capability; which is filled by the driver. When the
-driver is not compatible with this specification the ioctl returns an
-&EINVAL;.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-capability">
-      <title>struct <structname>v4l2_capability</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>driver</structfield>[16]</entry>
-           <entry><para>Name of the driver, a unique NUL-terminated
-ASCII string. For example: "bttv". Driver specific applications can
-use this information to verify the driver identity. It is also useful
-to work around known bugs, or to identify drivers in error reports.
-The driver version is stored in the <structfield>version</structfield>
-field.</para><para>Storing strings in fixed sized arrays is bad
-practice but unavoidable here. Drivers and applications should take
-precautions to never read or write beyond the end of the array and to
-make sure the strings are properly NUL-terminated.</para></entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>card</structfield>[32]</entry>
-           <entry>Name of the device, a NUL-terminated ASCII string.
-For example: "Yoyodyne TV/FM". One driver may support different brands
-or models of video hardware. This information is intended for users,
-for example in a menu of available devices. Since multiple TV cards of
-the same brand may be installed which are supported by the same
-driver, this name should be combined with the character device file
-name (&eg; <filename>/dev/video2</filename>) or the
-<structfield>bus_info</structfield> string to avoid
-ambiguities.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>bus_info</structfield>[32]</entry>
-           <entry>Location of the device in the system, a
-NUL-terminated ASCII string. For example: "PCI Slot 4". This
-information is intended for users, to distinguish multiple
-identical devices. If no such information is available the field may
-simply count the devices controlled by the driver, or contain the
-empty string (<structfield>bus_info</structfield>[0] = 0).<!-- XXX pci_dev->slot_name example --></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>version</structfield></entry>
-           <entry><para>Version number of the driver. Together with
-the <structfield>driver</structfield> field this identifies a
-particular driver. The version number is formatted using the
-<constant>KERNEL_VERSION()</constant> macro:</para></entry>
-         </row>
-         <row>
-           <entry spanname="hspan"><para>
-<programlisting>
-#define KERNEL_VERSION(a,b,c) (((a) &lt;&lt; 16) + ((b) &lt;&lt; 8) + (c))
-
-__u32 version = KERNEL_VERSION(0, 8, 1);
-
-printf ("Version: %u.%u.%u\n",
-       (version &gt;&gt; 16) &amp; 0xFF,
-       (version &gt;&gt; 8) &amp; 0xFF,
-        version &amp; 0xFF);
-</programlisting></para></entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>capabilities</structfield></entry>
-           <entry>Device capabilities, see <xref
-               linkend="device-capabilities" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[4]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-this array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="device-capabilities">
-      <title>Device Capabilities Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_CAPTURE</constant></entry>
-           <entry>0x00000001</entry>
-           <entry>The device supports the single-planar API through the <link
-linkend="capture">Video Capture</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_CAPTURE_MPLANE</constant></entry>
-           <entry>0x00001000</entry>
-           <entry>The device supports the
-           <link linkend="planar-apis">multi-planar API</link> through the
-           <link linkend="capture">Video Capture</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_OUTPUT</constant></entry>
-           <entry>0x00000002</entry>
-           <entry>The device supports the single-planar API through the <link
-linkend="output">Video Output</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_OUTPUT_MPLANE</constant></entry>
-           <entry>0x00002000</entry>
-           <entry>The device supports the
-           <link linkend="planar-apis">multi-planar API</link> through the
-           <link linkend="output">Video Output</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_OVERLAY</constant></entry>
-           <entry>0x00000004</entry>
-           <entry>The device supports the <link
-linkend="overlay">Video Overlay</link> interface. A video overlay device
-typically stores captured images directly in the video memory of a
-graphics card, with hardware clipping and scaling.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VBI_CAPTURE</constant></entry>
-           <entry>0x00000010</entry>
-           <entry>The device supports the <link linkend="raw-vbi">Raw
-VBI Capture</link> interface, providing Teletext and Closed Caption
-data.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VBI_OUTPUT</constant></entry>
-           <entry>0x00000020</entry>
-           <entry>The device supports the <link linkend="raw-vbi">Raw VBI Output</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_SLICED_VBI_CAPTURE</constant></entry>
-           <entry>0x00000040</entry>
-           <entry>The device supports the <link linkend="sliced">Sliced VBI Capture</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_SLICED_VBI_OUTPUT</constant></entry>
-           <entry>0x00000080</entry>
-           <entry>The device supports the <link linkend="sliced">Sliced VBI Output</link> interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_RDS_CAPTURE</constant></entry>
-           <entry>0x00000100</entry>
-           <entry>The device supports the <link linkend="rds">RDS</link> capture interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant></entry>
-           <entry>0x00000200</entry>
-           <entry>The device supports the <link linkend="osd">Video
-Output Overlay</link> (OSD) interface. Unlike the <wordasword>Video
-Overlay</wordasword> interface, this is a secondary function of video
-output devices and overlays an image onto an outgoing video signal.
-When the driver sets this flag, it must clear the
-<constant>V4L2_CAP_VIDEO_OVERLAY</constant> flag and vice
-versa.<footnote><para>The &v4l2-framebuffer; lacks an
-&v4l2-buf-type; field, therefore the type of overlay is implied by the
-driver capabilities.</para></footnote></entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_HW_FREQ_SEEK</constant></entry>
-           <entry>0x00000400</entry>
-           <entry>The device supports the &VIDIOC-S-HW-FREQ-SEEK; ioctl for
-hardware frequency seeking.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_RDS_OUTPUT</constant></entry>
-           <entry>0x00000800</entry>
-           <entry>The device supports the <link linkend="rds">RDS</link> output interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_TUNER</constant></entry>
-           <entry>0x00010000</entry>
-           <entry>The device has some sort of tuner to
-receive RF-modulated video signals. For more information about
-tuner programming see
-<xref linkend="tuner" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_AUDIO</constant></entry>
-           <entry>0x00020000</entry>
-           <entry>The device has audio inputs or outputs. It may or
-may not support audio recording or playback, in PCM or compressed
-formats. PCM audio support must be implemented as ALSA or OSS
-interface. For more information on audio inputs and outputs see <xref
-               linkend="audio" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_RADIO</constant></entry>
-           <entry>0x00040000</entry>
-           <entry>This is a radio receiver.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_MODULATOR</constant></entry>
-           <entry>0x00080000</entry>
-           <entry>The device has some sort of modulator to
-emit RF-modulated video/audio signals. For more information about
-modulator programming see
-<xref linkend="tuner" />.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_READWRITE</constant></entry>
-           <entry>0x01000000</entry>
-           <entry>The device supports the <link
-linkend="rw">read()</link> and/or <link linkend="rw">write()</link>
-I/O methods.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_ASYNCIO</constant></entry>
-           <entry>0x02000000</entry>
-           <entry>The device supports the <link
-linkend="async">asynchronous</link> I/O methods.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CAP_STREAMING</constant></entry>
-           <entry>0x04000000</entry>
-           <entry>The device supports the <link
-linkend="mmap">streaming</link> I/O method.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The device is not compatible with this
-specification.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
-
diff --git a/Documentation/DocBook/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/v4l/vidioc-queryctrl.xml
deleted file mode 100644 (file)
index 0d5e828..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-<refentry id="vidioc-queryctrl">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QUERYCTRL</refname>
-    <refname>VIDIOC_QUERYMENU</refname>
-    <refpurpose>Enumerate controls and menu control items</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_queryctrl *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_querymenu *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>To query the attributes of a control applications set the
-<structfield>id</structfield> field of a &v4l2-queryctrl; and call the
-<constant>VIDIOC_QUERYCTRL</constant> ioctl with a pointer to this
-structure. The driver fills the rest of the structure or returns an
-&EINVAL; when the <structfield>id</structfield> is invalid.</para>
-
-    <para>It is possible to enumerate controls by calling
-<constant>VIDIOC_QUERYCTRL</constant> with successive
-<structfield>id</structfield> values starting from
-<constant>V4L2_CID_BASE</constant> up to and exclusive
-<constant>V4L2_CID_BASE_LASTP1</constant>. Drivers may return
-<errorcode>EINVAL</errorcode> if a control in this range is not
-supported. Further applications can enumerate private controls, which
-are not defined in this specification, by starting at
-<constant>V4L2_CID_PRIVATE_BASE</constant> and incrementing
-<structfield>id</structfield> until the driver returns
-<errorcode>EINVAL</errorcode>.</para>
-
-    <para>In both cases, when the driver sets the
-<constant>V4L2_CTRL_FLAG_DISABLED</constant> flag in the
-<structfield>flags</structfield> field this control is permanently
-disabled and should be ignored by the application.<footnote>
-       <para><constant>V4L2_CTRL_FLAG_DISABLED</constant> was
-intended for two purposes: Drivers can skip predefined controls not
-supported by the hardware (although returning EINVAL would do as
-well), or disable predefined and private controls after hardware
-detection without the trouble of reordering control arrays and indices
-(EINVAL cannot be used to skip private controls because it would
-prematurely end the enumeration).</para></footnote></para>
-
-    <para>When the application ORs <structfield>id</structfield> with
-<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> the driver returns the
-next supported control, or <errorcode>EINVAL</errorcode> if there is
-none. Drivers which do not support this flag yet always return
-<errorcode>EINVAL</errorcode>.</para>
-
-    <para>Additional information is required for menu controls: the
-names of the menu items. To query them applications set the
-<structfield>id</structfield> and <structfield>index</structfield>
-fields of &v4l2-querymenu; and call the
-<constant>VIDIOC_QUERYMENU</constant> ioctl with a pointer to this
-structure. The driver fills the rest of the structure or returns an
-&EINVAL; when the <structfield>id</structfield> or
-<structfield>index</structfield> is invalid. Menu items are enumerated
-by calling <constant>VIDIOC_QUERYMENU</constant> with successive
-<structfield>index</structfield> values from &v4l2-queryctrl;
-<structfield>minimum</structfield> to
-<structfield>maximum</structfield>, inclusive. Note that it is possible
-for <constant>VIDIOC_QUERYMENU</constant> to return an &EINVAL; for some
-indices between <structfield>minimum</structfield> and <structfield>maximum</structfield>.
-In that case that particular menu item is not supported by this driver. Also note that
-the <structfield>minimum</structfield> value is not necessarily 0.</para>
-
-    <para>See also the examples in <xref linkend="control" />.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-queryctrl">
-      <title>struct <structname>v4l2_queryctrl</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>Identifies the control, set by the application. See
-<xref linkend="control-id" /> for predefined IDs. When the ID is ORed
-with V4L2_CTRL_FLAG_NEXT_CTRL the driver clears the flag and returns
-the first control with a higher ID. Drivers which do not support this
-flag yet always return an &EINVAL;.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-ctrl-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of control, see <xref
-               linkend="v4l2-ctrl-type" />.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the control, a NUL-terminated ASCII
-string. This information is intended for the user.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>minimum</structfield></entry>
-           <entry>Minimum value, inclusive. This field gives a lower
-bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
-lowest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant> controls.
-For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the minimum value
-gives the minimum length of the string. This length <emphasis>does not include the terminating
-zero</emphasis>. It may not be valid for any other type of control, including
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant> controls. Note that this is a
-signed value.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>maximum</structfield></entry>
-           <entry>Maximum value, inclusive. This field gives an upper
-bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
-highest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant>
-controls.
-For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the maximum value
-gives the maximum length of the string. This length <emphasis>does not include the terminating
-zero</emphasis>. It may not be valid for any other type of control, including
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant> controls. Note that this is a
-signed value.</entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>step</structfield></entry>
-           <entry><para>This field gives a step size for
-<constant>V4L2_CTRL_TYPE_INTEGER</constant> controls. For
-<constant>V4L2_CTRL_TYPE_STRING</constant> controls this field refers to
-the string length that has to be a multiple of this step size.
-It may not be valid for any other type of control, including
-<constant>V4L2_CTRL_TYPE_INTEGER64</constant>
-controls.</para><para>Generally drivers should not scale hardware
-control values. It may be necessary for example when the
-<structfield>name</structfield> or <structfield>id</structfield> imply
-a particular unit and the hardware actually accepts only multiples of
-said unit. If so, drivers must take care values are properly rounded
-when scaling, such that errors will not accumulate on repeated
-read-write cycles.</para><para>This field gives the smallest change of
-an integer control actually affecting hardware. Often the information
-is needed when the user can change controls by keyboard or GUI
-buttons, rather than a slider. When for example a hardware register
-accepts values 0-511 and the driver reports 0-65535, step should be
-128.</para><para>Note that although signed, the step value is supposed to
-be always positive.</para></entry>
-         </row>
-         <row>
-           <entry>__s32</entry>
-           <entry><structfield>default_value</structfield></entry>
-           <entry>The default value of a
-<constant>V4L2_CTRL_TYPE_INTEGER</constant>,
-<constant>_BOOLEAN</constant> or <constant>_MENU</constant> control.
-Not valid for other types of controls. Drivers reset controls only
-when the driver is loaded, not later, in particular not when the
-func-open; is called.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>flags</structfield></entry>
-           <entry>Control flags, see <xref
-               linkend="control-flags" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-querymenu">
-      <title>struct <structname>v4l2_querymenu</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>id</structfield></entry>
-           <entry>Identifies the control, set by the application
-from the respective &v4l2-queryctrl;
-<structfield>id</structfield>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Index of the menu item, starting at zero, set by
-           the application.</entry>
-         </row>
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>name</structfield>[32]</entry>
-           <entry>Name of the menu item, a NUL-terminated ASCII
-string. This information is intended for the user.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield></entry>
-           <entry>Reserved for future extensions. Drivers must set
-the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-ctrl-type">
-      <title>enum v4l2_ctrl_type</title>
-      <tgroup cols="5" align="left">
-       <colspec colwidth="30*" />
-       <colspec colwidth="5*" align="center" />
-       <colspec colwidth="5*" align="center" />
-       <colspec colwidth="5*" align="center" />
-       <colspec colwidth="55*" />
-       <thead>
-         <row>
-           <entry>Type</entry>
-           <entry><structfield>minimum</structfield></entry>
-           <entry><structfield>step</structfield></entry>
-           <entry><structfield>maximum</structfield></entry>
-           <entry>Description</entry>
-         </row>
-       </thead>
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_INTEGER</constant></entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>any</entry>
-           <entry>An integer-valued control ranging from minimum to
-maximum inclusive. The step value indicates the increment between
-values which are actually different on the hardware.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_BOOLEAN</constant></entry>
-           <entry>0</entry>
-           <entry>1</entry>
-           <entry>1</entry>
-           <entry>A boolean-valued control. Zero corresponds to
-"disabled", and one means "enabled".</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_MENU</constant></entry>
-           <entry>&ge; 0</entry>
-           <entry>1</entry>
-           <entry>N-1</entry>
-           <entry>The control has a menu of N choices. The names of
-the menu items can be enumerated with the
-<constant>VIDIOC_QUERYMENU</constant> ioctl.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_BUTTON</constant></entry>
-           <entry>0</entry>
-           <entry>0</entry>
-           <entry>0</entry>
-           <entry>A control which performs an action when set.
-Drivers must ignore the value passed with
-<constant>VIDIOC_S_CTRL</constant> and return an &EINVAL; on a
-<constant>VIDIOC_G_CTRL</constant> attempt.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_INTEGER64</constant></entry>
-           <entry>n/a</entry>
-           <entry>n/a</entry>
-           <entry>n/a</entry>
-           <entry>A 64-bit integer valued control. Minimum, maximum
-and step size cannot be queried.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_STRING</constant></entry>
-           <entry>&ge; 0</entry>
-           <entry>&ge; 1</entry>
-           <entry>&ge; 0</entry>
-           <entry>The minimum and maximum string lengths. The step size
-means that the string must be (minimum + N * step) characters long for
-N &ge; 0. These lengths do not include the terminating zero, so in order to
-pass a string of length 8 to &VIDIOC-S-EXT-CTRLS; you need to set the
-<structfield>size</structfield> field of &v4l2-ext-control; to 9. For &VIDIOC-G-EXT-CTRLS; you can
-set the <structfield>size</structfield> field to <structfield>maximum</structfield> + 1.
-Which character encoding is used will depend on the string control itself and
-should be part of the control documentation.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_TYPE_CTRL_CLASS</constant></entry>
-           <entry>n/a</entry>
-           <entry>n/a</entry>
-           <entry>n/a</entry>
-           <entry>This is not a control. When
-<constant>VIDIOC_QUERYCTRL</constant> is called with a control ID
-equal to a control class code (see <xref linkend="ctrl-class" />) + 1, the
-ioctl returns the name of the control class and this control type.
-Older drivers which do not support this feature return an
-&EINVAL;.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="control-flags">
-      <title>Control Flags</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_DISABLED</constant></entry>
-           <entry>0x0001</entry>
-           <entry>This control is permanently disabled and should be
-ignored by the application. Any attempt to change the control will
-result in an &EINVAL;.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_GRABBED</constant></entry>
-           <entry>0x0002</entry>
-           <entry>This control is temporarily unchangeable, for
-example because another application took over control of the
-respective resource. Such controls may be displayed specially in a
-user interface. Attempts to change the control may result in an
-&EBUSY;.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_READ_ONLY</constant></entry>
-           <entry>0x0004</entry>
-           <entry>This control is permanently readable only. Any
-attempt to change the control will result in an &EINVAL;.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_UPDATE</constant></entry>
-           <entry>0x0008</entry>
-           <entry>A hint that changing this control may affect the
-value of other controls within the same control class. Applications
-should update their user interface accordingly.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_INACTIVE</constant></entry>
-           <entry>0x0010</entry>
-           <entry>This control is not applicable to the current
-configuration and should be displayed accordingly in a user interface.
-For example the flag may be set on a MPEG audio level 2 bitrate
-control when MPEG audio encoding level 1 was selected with another
-control.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_SLIDER</constant></entry>
-           <entry>0x0020</entry>
-           <entry>A hint that this control is best represented as a
-slider-like element in a user interface.</entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_CTRL_FLAG_WRITE_ONLY</constant></entry>
-           <entry>0x0040</entry>
-           <entry>This control is permanently writable only. Any
-attempt to read the control will result in an &EACCES; error code. This
-flag is typically present for relative controls or action controls where
-writing a value will cause the device to carry out a given action
-(&eg; motor control) but no meaningful value can be returned.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-queryctrl; <structfield>id</structfield>
-is invalid. The &v4l2-querymenu; <structfield>id</structfield> is
-invalid or <structfield>index</structfield> is out of range (less than
-<structfield>minimum</structfield> or greater than <structfield>maximum</structfield>)
-or this particular menu item is not supported by the driver.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EACCES</errorcode></term>
-       <listitem>
-         <para>An attempt was made to read a write-only control.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-querystd.xml b/Documentation/DocBook/v4l/vidioc-querystd.xml
deleted file mode 100644 (file)
index 1a9e603..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<refentry id="vidioc-querystd">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_QUERYSTD</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_QUERYSTD</refname>
-    <refpurpose>Sense the video standard received by the current
-input</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>v4l2_std_id *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-       <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_QUERYSTD</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The hardware may be able to detect the current video
-standard automatically. To do so, applications call <constant>
-VIDIOC_QUERYSTD</constant> with a pointer to a &v4l2-std-id; type. The
-driver stores here a set of candidates, this can be a single flag or a
-set of supported standards if for example the hardware can only
-distinguish between 50 and 60 Hz systems. When detection is not
-possible or fails, the set must contain all standards supported by the
-current video input or output.</para>
-
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>This ioctl is not supported.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The device is busy and therefore can not detect the standard</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-reqbufs.xml b/Documentation/DocBook/v4l/vidioc-reqbufs.xml
deleted file mode 100644 (file)
index 69800ae..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-<refentry id="vidioc-reqbufs">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_REQBUFS</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_REQBUFS</refname>
-    <refpurpose>Initiate Memory Mapping or User Pointer I/O</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_requestbuffers *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_REQBUFS</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>This ioctl is used to initiate <link linkend="mmap">memory
-mapped</link> or <link linkend="userp">user pointer</link>
-I/O. Memory mapped buffers are located in device memory and must be
-allocated with this ioctl before they can be mapped into the
-application's address space. User buffers are allocated by
-applications themselves, and this ioctl is merely used to switch the
-driver into user pointer I/O mode and to setup some internal structures.</para>
-
-    <para>To allocate device buffers applications initialize all
-fields of the <structname>v4l2_requestbuffers</structname> structure.
-They set the <structfield>type</structfield> field to the respective
-stream or buffer type, the <structfield>count</structfield> field to
-the desired number of buffers, <structfield>memory</structfield>
-must be set to the requested I/O method and the <structfield>reserved</structfield> array
-must be zeroed. When the ioctl
-is called with a pointer to this structure the driver will attempt to allocate
-the requested number of buffers and it stores the actual number
-allocated in the <structfield>count</structfield> field. It can be
-smaller than the number requested, even zero, when the driver runs out
-of free memory. A larger number is also possible when the driver requires
-more buffers to function correctly. For example video output requires at least two buffers,
-one displayed and one filled by the application.</para>
-    <para>When the I/O method is not supported the ioctl
-returns an &EINVAL;.</para>
-
-    <para>Applications can call <constant>VIDIOC_REQBUFS</constant>
-again to change the number of buffers, however this cannot succeed
-when any buffers are still mapped. A <structfield>count</structfield>
-value of zero frees all buffers, after aborting or finishing any DMA
-in progress, an implicit &VIDIOC-STREAMOFF;. <!-- mhs: I see no
-reason why munmap()ping one or even all buffers must imply
-streamoff.--></para>
-
-    <table pgwide="1" frame="none" id="v4l2-requestbuffers">
-      <title>struct <structname>v4l2_requestbuffers</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>count</structfield></entry>
-           <entry>The number of buffers requested or granted.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-buf-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the stream or buffers, this is the same
-as the &v4l2-format; <structfield>type</structfield> field. See <xref
-               linkend="v4l2-buf-type" /> for valid values.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-memory;</entry>
-           <entry><structfield>memory</structfield></entry>
-           <entry>Applications set this field to
-<constant>V4L2_MEMORY_MMAP</constant> or
-<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[2]</entry>
-           <entry>A place holder for future extensions and custom
-(driver defined) buffer types <constant>V4L2_BUF_TYPE_PRIVATE</constant> and
-higher. This array should be zeroed by applications.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The driver supports multiple opens and I/O is already
-in progress, or reallocation of buffers was attempted although one or
-more are still mapped.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The buffer type (<structfield>type</structfield> field) or the
-requested I/O method (<structfield>memory</structfield>) is not
-supported.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml
deleted file mode 100644 (file)
index c30dcc4..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-<refentry id="vidioc-s-hw-freq-seek">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_S_HW_FREQ_SEEK</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_S_HW_FREQ_SEEK</refname>
-    <refpurpose>Perform a hardware frequency seek</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_hw_freq_seek
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_S_HW_FREQ_SEEK</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Start a hardware frequency seek from the current frequency.
-To do this applications initialize the <structfield>tuner</structfield>,
-<structfield>type</structfield>, <structfield>seek_upward</structfield>,
-<structfield>spacing</structfield> and
-<structfield>wrap_around</structfield> fields, and zero out the
-<structfield>reserved</structfield> array of a &v4l2-hw-freq-seek; and
-call the <constant>VIDIOC_S_HW_FREQ_SEEK</constant> ioctl with a pointer
-to this structure.</para>
-
-    <para>This ioctl is supported if the <constant>V4L2_CAP_HW_FREQ_SEEK</constant> capability is set.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-hw-freq-seek">
-      <title>struct <structname>v4l2_hw_freq_seek</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>tuner</structfield></entry>
-           <entry>The tuner index number. This is the
-same value as in the &v4l2-input; <structfield>tuner</structfield>
-field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-tuner-type;</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>The tuner type. This is the same value as in the
-&v4l2-tuner; <structfield>type</structfield> field.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>seek_upward</structfield></entry>
-           <entry>If non-zero, seek upward from the current frequency, else seek downward.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>wrap_around</structfield></entry>
-           <entry>If non-zero, wrap around when at the end of the frequency range, else stop seeking.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>spacing</structfield></entry>
-           <entry>If non-zero, defines the hardware seek resolution in Hz. The driver selects the nearest value that is supported by the device. If spacing is zero a reasonable default value is used.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[7]</entry>
-           <entry>Reserved for future extensions. Drivers and
-           applications must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The <structfield>tuner</structfield> index is out of
-bounds or the value in the <structfield>type</structfield> field is
-wrong.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EAGAIN</errorcode></term>
-       <listitem>
-         <para>The ioctl timed-out. Try again.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-streamon.xml b/Documentation/DocBook/v4l/vidioc-streamon.xml
deleted file mode 100644 (file)
index 75ed39b..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-<refentry id="vidioc-streamon">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_STREAMON</refname>
-    <refname>VIDIOC_STREAMOFF</refname>
-    <refpurpose>Start or stop streaming I/O</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const int *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_STREAMON, VIDIOC_STREAMOFF</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>The <constant>VIDIOC_STREAMON</constant> and
-<constant>VIDIOC_STREAMOFF</constant> ioctl start and stop the capture
-or output process during streaming (<link linkend="mmap">memory
-mapping</link> or <link linkend="userp">user pointer</link>) I/O.</para>
-
-    <para>Specifically the capture hardware is disabled and no input
-buffers are filled (if there are any empty buffers in the incoming
-queue) until <constant>VIDIOC_STREAMON</constant> has been called.
-Accordingly the output hardware is disabled, no video signal is
-produced until <constant>VIDIOC_STREAMON</constant> has been called.
-The ioctl will succeed only when at least one output buffer is in the
-incoming queue.</para>
-
-    <para>The <constant>VIDIOC_STREAMOFF</constant> ioctl, apart of
-aborting or finishing any DMA in progress, unlocks any user pointer
-buffers locked in physical memory, and it removes all buffers from the
-incoming and outgoing queues. That means all images captured but not
-dequeued yet will be lost, likewise all images enqueued for output but
-not transmitted yet. I/O returns to the same state as after calling
-&VIDIOC-REQBUFS; and can be restarted accordingly.</para>
-
-    <para>Both ioctls take a pointer to an integer, the desired buffer or
-stream type. This is the same as &v4l2-requestbuffers;
-<structfield>type</structfield>.</para>
-
-    <para>Note applications can be preempted for unknown periods right
-before or after the <constant>VIDIOC_STREAMON</constant> or
-<constant>VIDIOC_STREAMOFF</constant> calls, there is no notion of
-starting or stopping "now". Buffer timestamps can be used to
-synchronize with other events.</para>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>Streaming I/O is not supported, the buffer
-<structfield>type</structfield> is not supported, or no buffers have
-been allocated (memory mapping) or enqueued (output) yet.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EPIPE</errorcode></term>
-       <listitem>
-         <para>The driver implements <link
-         linkend="pad-level-formats">pad-level format configuration</link> and
-         the pipeline configuration is invalid.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
-
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-interval.xml
deleted file mode 100644 (file)
index 2f8f4f0..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-<refentry id="vidioc-subdev-enum-frame-interval">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</refname>
-    <refpurpose>Enumerate frame intervals</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_subdev_frame_interval_enum *
-       <parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
-    <para>This ioctl lets applications enumerate available frame intervals on a
-    given sub-device pad. Frame intervals only makes sense for sub-devices that
-    can control the frame period on their own. This includes, for instance,
-    image sensors and TV tuners.</para>
-
-    <para>For the common use case of image sensors, the frame intervals
-    available on the sub-device output pad depend on the frame format and size
-    on the same pad. Applications must thus specify the desired format and size
-    when enumerating frame intervals.</para>
-
-    <para>To enumerate frame intervals applications initialize the
-    <structfield>index</structfield>, <structfield>pad</structfield>,
-    <structfield>code</structfield>, <structfield>width</structfield> and
-    <structfield>height</structfield> fields of
-    &v4l2-subdev-frame-interval-enum; and call the
-    <constant>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</constant> ioctl with a pointer
-    to this structure. Drivers fill the rest of the structure or return
-    an &EINVAL; if one of the input fields is invalid. All frame intervals are
-    enumerable by beginning at index zero and incrementing by one until
-    <errorcode>EINVAL</errorcode> is returned.</para>
-
-    <para>Available frame intervals may depend on the current 'try' formats
-    at other pads of the sub-device, as well as on the current active links. See
-    &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
-
-    <para>Sub-devices that support the frame interval enumeration ioctl should
-    implemented it on a single pad only. Its behaviour when supported on
-    multiple pads of the same sub-device is not defined.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval-enum">
-      <title>struct <structname>v4l2_subdev_frame_interval_enum</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the format in the enumeration, set by the
-           application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>code</structfield></entry>
-           <entry>The media bus format code, as defined in
-           <xref linkend="v4l2-mbus-format" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>width</structfield></entry>
-           <entry>Frame width, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>height</structfield></entry>
-           <entry>Frame height, in pixels.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>interval</structfield></entry>
-           <entry>Period, in seconds, between consecutive video frames.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[9]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-frame-interval-enum;
-         <structfield>pad</structfield> references a non-existing pad, one of
-         the <structfield>code</structfield>, <structfield>width</structfield>
-         or <structfield>height</structfield> fields are invalid for the given
-         pad or the <structfield>index</structfield> field is out of bounds.
-         </para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-frame-size.xml
deleted file mode 100644 (file)
index 79ce42b..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-<refentry id="vidioc-subdev-enum-frame-size">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</refname>
-    <refpurpose>Enumerate media bus frame sizes</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_subdev_frame_size_enum *
-       <parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
-    <para>This ioctl allows applications to enumerate all frame sizes
-    supported by a sub-device on the given pad for the given media bus format.
-    Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE;
-    ioctl.</para>
-
-    <para>To enumerate frame sizes applications initialize the
-    <structfield>pad</structfield>, <structfield>code</structfield> and
-    <structfield>index</structfield> fields of the
-    &v4l2-subdev-mbus-code-enum; and call the
-    <constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant> ioctl with a pointer to
-    the structure. Drivers fill the minimum and maximum frame sizes or return
-    an &EINVAL; if one of the input parameters is invalid.</para>
-
-    <para>Sub-devices that only support discrete frame sizes (such as most
-    sensors) will return one or more frame sizes with identical minimum and
-    maximum values.</para>
-
-    <para>Not all possible sizes in given [minimum, maximum] ranges need to be
-    supported. For instance, a scaler that uses a fixed-point scaling ratio
-    might not be able to produce every frame size between the minimum and
-    maximum values. Applications must use the &VIDIOC-SUBDEV-S-FMT; ioctl to
-    try the sub-device for an exact supported frame size.</para>
-
-    <para>Available frame sizes may depend on the current 'try' formats at other
-    pads of the sub-device, as well as on the current active links and the
-    current values of V4L2 controls. See &VIDIOC-SUBDEV-G-FMT; for more
-    information about try formats.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-frame-size-enum">
-      <title>struct <structname>v4l2_subdev_frame_size_enum</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the format in the enumeration, set by the
-           application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>code</structfield></entry>
-           <entry>The media bus format code, as defined in
-           <xref linkend="v4l2-mbus-format" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>min_width</structfield></entry>
-           <entry>Minimum frame width, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>max_width</structfield></entry>
-           <entry>Maximum frame width, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>min_height</structfield></entry>
-           <entry>Minimum frame height, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>max_height</structfield></entry>
-           <entry>Maximum frame height, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[9]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-frame-size-enum; <structfield>pad</structfield>
-         references a non-existing pad, the <structfield>code</structfield> is
-         invalid for the given pad or the <structfield>index</structfield>
-         field is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml b/Documentation/DocBook/v4l/vidioc-subdev-enum-mbus-code.xml
deleted file mode 100644 (file)
index a6b3432..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-<refentry id="vidioc-subdev-enum-mbus-code">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_ENUM_MBUS_CODE</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_ENUM_MBUS_CODE</refname>
-    <refpurpose>Enumerate media bus formats</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_subdev_mbus_code_enum *
-       <parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_SUBDEV_ENUM_MBUS_CODE</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
-    <para>To enumerate media bus formats available at a given sub-device pad
-    applications initialize the <structfield>pad</structfield> and
-    <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and
-    call the <constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant> ioctl with a
-    pointer to this structure. Drivers fill the rest of the structure or return
-    an &EINVAL; if either the <structfield>pad</structfield> or
-    <structfield>index</structfield> are invalid. All media bus formats are
-    enumerable by beginning at index zero and incrementing by one until
-    <errorcode>EINVAL</errorcode> is returned.</para>
-
-    <para>Available media bus formats may depend on the current 'try' formats
-    at other pads of the sub-device, as well as on the current active links. See
-    &VIDIOC-SUBDEV-G-FMT; for more information about the try formats.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-mbus-code-enum">
-      <title>struct <structname>v4l2_subdev_mbus_code_enum</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>index</structfield></entry>
-           <entry>Number of the format in the enumeration, set by the
-           application.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>code</structfield></entry>
-           <entry>The media bus format code, as defined in
-           <xref linkend="v4l2-mbus-format" />.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[9]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-mbus-code-enum; <structfield>pad</structfield>
-         references a non-existing pad, or the <structfield>index</structfield>
-         field is out of bounds.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-crop.xml
deleted file mode 100644 (file)
index 0619732..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-<refentry id="vidioc-subdev-g-crop">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_G_CROP</refname>
-    <refname>VIDIOC_SUBDEV_S_CROP</refname>
-    <refpurpose>Get or set the crop rectangle on a subdev pad</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_subdev_crop *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>const struct v4l2_subdev_crop *<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_SUBDEV_G_CROP, VIDIOC_SUBDEV_S_CROP</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
-    <para>To retrieve the current crop rectangle applications set the
-    <structfield>pad</structfield> field of a &v4l2-subdev-crop; to the
-    desired pad number as reported by the media API and the
-    <structfield>which</structfield> field to
-    <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. They then call the
-    <constant>VIDIOC_SUBDEV_G_CROP</constant> ioctl with a pointer to this
-    structure. The driver fills the members of the <structfield>rect</structfield>
-    field or returns &EINVAL; if the input arguments are invalid, or if cropping
-    is not supported on the given pad.</para>
-
-    <para>To change the current crop rectangle applications set both the
-    <structfield>pad</structfield> and <structfield>which</structfield> fields
-    and all members of the <structfield>rect</structfield> field. They then call
-    the <constant>VIDIOC_SUBDEV_S_CROP</constant> ioctl with a pointer to this
-    structure. The driver verifies the requested crop rectangle, adjusts it
-    based on the hardware capabilities and configures the device. Upon return
-    the &v4l2-subdev-crop; contains the current format as would be returned
-    by a <constant>VIDIOC_SUBDEV_G_CROP</constant> call.</para>
-
-    <para>Applications can query the device capabilities by setting the
-    <structfield>which</structfield> to
-    <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' crop
-    rectangles are not applied to the device by the driver, but are mangled
-    exactly as active crop rectangles and stored in the sub-device file handle.
-    Two applications querying the same sub-device would thus not interact with
-    each other.</para>
-
-    <para>Drivers must not return an error solely because the requested crop
-    rectangle doesn't match the device capabilities. They must instead modify
-    the rectangle to match what the hardware can provide. The modified format
-    should be as close as possible to the original request.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-crop">
-      <title>struct <structname>v4l2_subdev_crop</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media framework.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>which</structfield></entry>
-           <entry>Crop rectangle to get or set, from
-           &v4l2-subdev-format-whence;.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-rect;</entry>
-           <entry><structfield>rect</structfield></entry>
-           <entry>Crop rectangle boundaries, in pixels.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The crop rectangle can't be changed because the pad is currently
-         busy. This can be caused, for instance, by an active video stream on
-         the pad. The ioctl must not be retried without performing another
-         action to fix the problem first. Only returned by
-         <constant>VIDIOC_SUBDEV_S_CROP</constant></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-crop; <structfield>pad</structfield>
-         references a non-existing pad, the <structfield>which</structfield>
-         field references a non-existing format, or cropping is not supported
-         on the given subdev pad.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-fmt.xml
deleted file mode 100644 (file)
index f367c57..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-<refentry id="vidioc-subdev-g-fmt">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_G_FMT</refname>
-    <refname>VIDIOC_SUBDEV_S_FMT</refname>
-    <refpurpose>Get or set the data format on a subdev pad</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_subdev_format *<parameter>argp</parameter>
-       </paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
-    <para>These ioctls are used to negotiate the frame format at specific
-    subdev pads in the image pipeline.</para>
-
-    <para>To retrieve the current format applications set the
-    <structfield>pad</structfield> field of a &v4l2-subdev-format; to the
-    desired pad number as reported by the media API and the
-    <structfield>which</structfield> field to
-    <constant>V4L2_SUBDEV_FORMAT_ACTIVE</constant>. When they call the
-    <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl with a pointer to this
-    structure the driver fills the members of the <structfield>format</structfield>
-    field.</para>
-
-    <para>To change the current format applications set both the
-    <structfield>pad</structfield> and <structfield>which</structfield> fields
-    and all members of the <structfield>format</structfield> field. When they
-    call the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl with a pointer to this
-    structure the driver verifies the requested format, adjusts it based on the
-    hardware capabilities and configures the device. Upon return the
-    &v4l2-subdev-format; contains the current format as would be returned by a
-    <constant>VIDIOC_SUBDEV_G_FMT</constant> call.</para>
-
-    <para>Applications can query the device capabilities by setting the
-    <structfield>which</structfield> to
-    <constant>V4L2_SUBDEV_FORMAT_TRY</constant>. When set, 'try' formats are not
-    applied to the device by the driver, but are changed exactly as active
-    formats and stored in the sub-device file handle. Two applications querying
-    the same sub-device would thus not interact with each other.</para>
-
-    <para>For instance, to try a format at the output pad of a sub-device,
-    applications would first set the try format at the sub-device input with the
-    <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl. They would then either
-    retrieve the default format at the output pad with the
-    <constant>VIDIOC_SUBDEV_G_FMT</constant> ioctl, or set the desired output
-    pad format with the <constant>VIDIOC_SUBDEV_S_FMT</constant> ioctl and check
-    the returned value.</para>
-
-    <para>Try formats do not depend on active formats, but can depend on the
-    current links configuration or sub-device controls value. For instance, a
-    low-pass noise filter might crop pixels at the frame boundaries, modifying
-    its output frame size.</para>
-
-    <para>Drivers must not return an error solely because the requested format
-    doesn't match the device capabilities. They must instead modify the format
-    to match what the hardware can provide. The modified format should be as
-    close as possible to the original request.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-format">
-      <title>struct <structname>v4l2_subdev_format</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>which</structfield></entry>
-           <entry>Format to modified, from &v4l2-subdev-format-whence;.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-mbus-framefmt;</entry>
-           <entry><structfield>format</structfield></entry>
-           <entry>Definition of an image format, see <xref
-           linkend="v4l2-mbus-framefmt" /> for details.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[8]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-format-whence">
-      <title>enum <structname>v4l2_subdev_format_whence</structname></title>
-      <tgroup cols="3">
-        &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry>V4L2_SUBDEV_FORMAT_TRY</entry>
-           <entry>0</entry>
-           <entry>Try formats, used for querying device capabilities.</entry>
-         </row>
-         <row>
-           <entry>V4L2_SUBDEV_FORMAT_ACTIVE</entry>
-           <entry>1</entry>
-           <entry>Active formats, applied to the hardware.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The format can't be changed because the pad is currently busy.
-         This can be caused, for instance, by an active video stream on the
-         pad. The ioctl must not be retried without performing another action
-         to fix the problem first. Only returned by
-         <constant>VIDIOC_SUBDEV_S_FMT</constant></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-format; <structfield>pad</structfield>
-         references a non-existing pad, or the <structfield>which</structfield>
-         field references a non-existing format.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml b/Documentation/DocBook/v4l/vidioc-subdev-g-frame-interval.xml
deleted file mode 100644 (file)
index 0bc3ea2..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-<refentry id="vidioc-subdev-g-frame-interval">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBDEV_G_FRAME_INTERVAL</refname>
-    <refname>VIDIOC_SUBDEV_S_FRAME_INTERVAL</refname>
-    <refpurpose>Get or set the frame interval on a subdev pad</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_subdev_frame_interval *<parameter>argp</parameter>
-       </paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_SUBDEV_G_FRAME_INTERVAL, VIDIOC_SUBDEV_S_FRAME_INTERVAL</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <note>
-      <title>Experimental</title>
-      <para>This is an <link linkend="experimental">experimental</link>
-      interface and may change in the future.</para>
-    </note>
-
-    <para>These ioctls are used to get and set the frame interval at specific
-    subdev pads in the image pipeline. The frame interval only makes sense for
-    sub-devices that can control the frame period on their own. This includes,
-    for instance, image sensors and TV tuners. Sub-devices that don't support
-    frame intervals must not implement these ioctls.</para>
-
-    <para>To retrieve the current frame interval applications set the
-    <structfield>pad</structfield> field of a &v4l2-subdev-frame-interval; to
-    the desired pad number as reported by the media controller API. When they
-    call the <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> ioctl with a
-    pointer to this structure the driver fills the members of the
-    <structfield>interval</structfield> field.</para>
-
-    <para>To change the current frame interval applications set both the
-    <structfield>pad</structfield> field and all members of the
-    <structfield>interval</structfield> field. When they call the
-    <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant> ioctl with a pointer to
-    this structure the driver verifies the requested interval, adjusts it based
-    on the hardware capabilities and configures the device. Upon return the
-    &v4l2-subdev-frame-interval; contains the current frame interval as would be
-    returned by a <constant>VIDIOC_SUBDEV_G_FRAME_INTERVAL</constant> call.
-    </para>
-
-    <para>Drivers must not return an error solely because the requested interval
-    doesn't match the device capabilities. They must instead modify the interval
-    to match what the hardware can provide. The modified interval should be as
-    close as possible to the original request.</para>
-
-    <para>Sub-devices that support the frame interval ioctls should implement
-    them on a single pad only. Their behaviour when supported on multiple pads
-    of the same sub-device is not defined.</para>
-
-    <table pgwide="1" frame="none" id="v4l2-subdev-frame-interval">
-      <title>struct <structname>v4l2_subdev_frame_interval</structname></title>
-      <tgroup cols="3">
-        &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>pad</structfield></entry>
-           <entry>Pad number as reported by the media controller API.</entry>
-         </row>
-         <row>
-           <entry>&v4l2-fract;</entry>
-           <entry><structfield>interval</structfield></entry>
-           <entry>Period, in seconds, between consecutive video frames.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[9]</entry>
-           <entry>Reserved for future extensions. Applications and drivers must
-           set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-  </refsect1>
-
-  <refsect1>
-    &return-value;
-
-    <variablelist>
-      <varlistentry>
-       <term><errorcode>EBUSY</errorcode></term>
-       <listitem>
-         <para>The frame interval can't be changed because the pad is currently
-         busy. This can be caused, for instance, by an active video stream on
-         the pad. The ioctl must not be retried without performing another
-         action to fix the problem first. Only returned by
-         <constant>VIDIOC_SUBDEV_S_FRAME_INTERVAL</constant></para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><errorcode>EINVAL</errorcode></term>
-       <listitem>
-         <para>The &v4l2-subdev-frame-interval; <structfield>pad</structfield>
-         references a non-existing pad, or the pad doesn't support frame
-         intervals.</para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/v4l/vidioc-subscribe-event.xml
deleted file mode 100644 (file)
index 8b50179..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-<refentry id="vidioc-subscribe-event">
-  <refmeta>
-    <refentrytitle>ioctl VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refentrytitle>
-    &manvol;
-  </refmeta>
-
-  <refnamediv>
-    <refname>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</refname>
-    <refpurpose>Subscribe or unsubscribe event</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-      <funcprototype>
-       <funcdef>int <function>ioctl</function></funcdef>
-       <paramdef>int <parameter>fd</parameter></paramdef>
-       <paramdef>int <parameter>request</parameter></paramdef>
-       <paramdef>struct v4l2_event_subscription
-*<parameter>argp</parameter></paramdef>
-      </funcprototype>
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Arguments</title>
-
-    <variablelist>
-      <varlistentry>
-       <term><parameter>fd</parameter></term>
-       <listitem>
-         <para>&fd;</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>request</parameter></term>
-       <listitem>
-         <para>VIDIOC_SUBSCRIBE_EVENT, VIDIOC_UNSUBSCRIBE_EVENT</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><parameter>argp</parameter></term>
-       <listitem>
-         <para></para>
-       </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Subscribe or unsubscribe V4L2 event. Subscribed events are
-    dequeued by using the &VIDIOC-DQEVENT; ioctl.</para>
-
-    <table frame="none" pgwide="1" id="v4l2-event-subscription">
-      <title>struct <structname>v4l2_event_subscription</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>type</structfield></entry>
-           <entry>Type of the event.</entry>
-         </row>
-         <row>
-           <entry>__u32</entry>
-           <entry><structfield>reserved</structfield>[7]</entry>
-           <entry>Reserved for future extensions. Drivers and applications
-           must set the array to zero.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="event-type">
-      <title>Event Types</title>
-      <tgroup cols="3">
-       &cs-def;
-       <tbody valign="top">
-         <row>
-           <entry><constant>V4L2_EVENT_ALL</constant></entry>
-           <entry>0</entry>
-           <entry>All events. V4L2_EVENT_ALL is valid only for
-           VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_VSYNC</constant></entry>
-           <entry>1</entry>
-           <entry>This event is triggered on the vertical sync.
-           This event has &v4l2-event-vsync; associated with it.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_EOS</constant></entry>
-           <entry>2</entry>
-           <entry>This event is triggered when the end of a stream is reached.
-           This is typically used with MPEG decoders to report to the application
-           when the last of the MPEG stream has been decoded.
-           </entry>
-         </row>
-         <row>
-           <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry>
-           <entry>0x08000000</entry>
-           <entry>Base event number for driver-private events.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-    <table frame="none" pgwide="1" id="v4l2-event-vsync">
-      <title>struct <structname>v4l2_event_vsync</structname></title>
-      <tgroup cols="3">
-       &cs-str;
-       <tbody valign="top">
-         <row>
-           <entry>__u8</entry>
-           <entry><structfield>field</structfield></entry>
-           <entry>The upcoming field. See &v4l2-field;.</entry>
-         </row>
-       </tbody>
-      </tgroup>
-    </table>
-
-  </refsect1>
-</refentry>
-<!--
-Local Variables:
-mode: sgml
-sgml-parent-document: "v4l2.sgml"
-indent-tabs-mode: nil
-End:
--->
diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards
new file mode 100644 (file)
index 0000000..91f2614
--- /dev/null
@@ -0,0 +1,20 @@
+ARM Versatile Application and Platform Baseboards
+-------------------------------------------------
+ARM's development hardware platform with connectors for customizable
+core tiles.  The hardware configuration of the Versatile boards is
+highly customizable.
+
+Required properties (in root node):
+       compatible = "arm,versatile-ab";  /* Application baseboard */
+       compatible = "arm,versatile-pb";  /* Platform baseboard */
+
+Interrupt controllers:
+- VIC required properties:
+       compatible = "arm,versatile-vic";
+       interrupt-controller;
+       #interrupt-cells = <1>;
+
+- SIC required properties:
+       compatible = "arm,versatile-sic";
+       interrupt-controller;
+       #interrupt-cells = <1>;
diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
new file mode 100644 (file)
index 0000000..d1e3f44
--- /dev/null
@@ -0,0 +1,17 @@
+* Freescale Smart Direct Memory Access (SDMA) Controller for i.MX
+
+Required properties:
+- compatible : Should be "fsl,<chip>-sdma"
+- reg : Should contain SDMA registers location and length
+- interrupts : Should contain SDMA interrupt
+- fsl,sdma-ram-script-name : Should contain the full path of SDMA RAM
+  scripts firmware
+
+Examples:
+
+sdma@83fb0000 {
+       compatible = "fsl,imx51-sdma", "fsl,imx35-sdma";
+       reg = <0x83fb0000 0x4000>;
+       interrupts = <6>;
+       fsl,sdma-ram-script-name = "sdma-imx51.bin";
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
new file mode 100644 (file)
index 0000000..7190c99
--- /dev/null
@@ -0,0 +1,36 @@
+Device-Tree bindings for input/gpio_keys.c keyboard driver
+
+Required properties:
+       - compatible = "gpio-keys";
+
+Optional properties:
+       - autorepeat: Boolean, Enable auto repeat feature of Linux input
+         subsystem.
+
+Each button (key) is represented as a sub-node of "gpio-keys":
+Subnode properties:
+
+       - gpios: OF devcie-tree gpio specificatin.
+       - label: Descriptive name of the key.
+       - linux,code: Keycode to emit.
+
+Optional subnode-properties:
+       - linux,input-type: Specify event type this button/key generates.
+         If not specified defaults to <1> == EV_KEY.
+       - debounce-interval: Debouncing interval time in milliseconds.
+         If not specified defaults to 5.
+       - gpio-key,wakeup: Boolean, button can wake-up the system.
+
+Example nodes:
+
+       gpio_keys {
+                       compatible = "gpio-keys";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       autorepeat;
+                       button@21 {
+                               label = "GPIO Key UP";
+                               linux,code = <103>;
+                               gpios = <&gpio1 0 1>;
+                       };
+                       ...
diff --git a/Documentation/devicetree/bindings/i2c/arm-versatile.txt b/Documentation/devicetree/bindings/i2c/arm-versatile.txt
new file mode 100644 (file)
index 0000000..361d31c
--- /dev/null
@@ -0,0 +1,10 @@
+i2c Controller on ARM Versatile platform:
+
+Required properties:
+- compatible : Must be "arm,versatile-i2c";
+- reg
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties:
+- Child nodes conforming to i2c bus binding
diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
new file mode 100644 (file)
index 0000000..ab22fe6
--- /dev/null
@@ -0,0 +1,34 @@
+* Freescale Enhanced Secure Digital Host Controller (eSDHC) for i.MX
+
+The Enhanced Secure Digital Host Controller on Freescale i.MX family
+provides an interface for MMC, SD, and SDIO types of memory cards.
+
+Required properties:
+- compatible : Should be "fsl,<chip>-esdhc"
+- reg : Should contain eSDHC registers location and length
+- interrupts : Should contain eSDHC interrupt
+
+Optional properties:
+- fsl,card-wired : Indicate the card is wired to host permanently
+- fsl,cd-internal : Indicate to use controller internal card detection
+- fsl,wp-internal : Indicate to use controller internal write protection
+- cd-gpios : Specify GPIOs for card detection
+- wp-gpios : Specify GPIOs for write protection
+
+Examples:
+
+esdhc@70004000 {
+       compatible = "fsl,imx51-esdhc";
+       reg = <0x70004000 0x4000>;
+       interrupts = <1>;
+       fsl,cd-internal;
+       fsl,wp-internal;
+};
+
+esdhc@70008000 {
+       compatible = "fsl,imx51-esdhc";
+       reg = <0x70008000 0x4000>;
+       interrupts = <2>;
+       cd-gpios = <&gpio0 6 0>; /* GPIO1_6 */
+       wp-gpios = <&gpio0 5 0>; /* GPIO1_5 */
+};
diff --git a/Documentation/devicetree/bindings/mtd/arm-versatile.txt b/Documentation/devicetree/bindings/mtd/arm-versatile.txt
new file mode 100644 (file)
index 0000000..476845d
--- /dev/null
@@ -0,0 +1,8 @@
+Flash device on ARM Versatile board
+
+Required properties:
+- compatible : must be "arm,versatile-flash";
+- bank-width : width in bytes of flash interface.
+
+Optional properties:
+- Subnode partition map from mtd flash binding
diff --git a/Documentation/devicetree/bindings/net/fsl-fec.txt b/Documentation/devicetree/bindings/net/fsl-fec.txt
new file mode 100644 (file)
index 0000000..de43951
--- /dev/null
@@ -0,0 +1,24 @@
+* Freescale Fast Ethernet Controller (FEC)
+
+Required properties:
+- compatible : Should be "fsl,<soc>-fec"
+- reg : Address and length of the register set for the device
+- interrupts : Should contain fec interrupt
+- phy-mode : String, operation mode of the PHY interface.
+  Supported values are: "mii", "gmii", "sgmii", "tbi", "rmii",
+  "rgmii", "rgmii-id", "rgmii-rxid", "rgmii-txid", "rtbi", "smii".
+- phy-reset-gpios : Should specify the gpio for phy reset
+
+Optional properties:
+- local-mac-address : 6 bytes, mac address
+
+Example:
+
+fec@83fec000 {
+       compatible = "fsl,imx51-fec", "fsl,imx27-fec";
+       reg = <0x83fec000 0x4000>;
+       interrupts = <87>;
+       phy-mode = "mii";
+       phy-reset-gpios = <&gpio1 14 0>; /* GPIO2_14 */
+       local-mac-address = [00 04 9F 01 1B B9];
+};
diff --git a/Documentation/devicetree/bindings/net/smsc-lan91c111.txt b/Documentation/devicetree/bindings/net/smsc-lan91c111.txt
new file mode 100644 (file)
index 0000000..953049b
--- /dev/null
@@ -0,0 +1,10 @@
+SMSC LAN91c111 Ethernet mac
+
+Required properties:
+- compatible = "smsc,lan91c111";
+- reg : physical address and size of registers
+- interrupts : interrupt connection
+
+Optional properties:
+- phy-device : phandle to Ethernet phy
+- local-mac-address : Ethernet mac address to use
diff --git a/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt
new file mode 100644 (file)
index 0000000..a9c0406
--- /dev/null
@@ -0,0 +1,19 @@
+* Freescale i.MX Universal Asynchronous Receiver/Transmitter (UART)
+
+Required properties:
+- compatible : Should be "fsl,<soc>-uart"
+- reg : Address and length of the register set for the device
+- interrupts : Should contain uart interrupt
+
+Optional properties:
+- fsl,uart-has-rtscts : Indicate the uart has rts and cts
+- fsl,irda-mode : Indicate the uart supports irda mode
+
+Example:
+
+uart@73fbc000 {
+       compatible = "fsl,imx51-uart", "fsl,imx21-uart";
+       reg = <0x73fbc000 0x4000>;
+       interrupts = <31>;
+       fsl,uart-has-rtscts;
+};
diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt b/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt
new file mode 100644 (file)
index 0000000..2144af1
--- /dev/null
@@ -0,0 +1,14 @@
+* Freescale i.MX Watchdog Timer (WDT) Controller
+
+Required properties:
+- compatible : Should be "fsl,<soc>-wdt"
+- reg : Should contain WDT registers location and length
+- interrupts : Should contain WDT interrupt
+
+Examples:
+
+wdt@73f98000 {
+       compatible = "fsl,imx51-wdt", "fsl,imx21-wdt";
+       reg = <0x73f98000 0x4000>;
+       interrupts = <58>;
+};
diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
new file mode 100644 (file)
index 0000000..79ead82
--- /dev/null
@@ -0,0 +1,11 @@
+* Samsung's Watchdog Timer Controller
+
+The Samsung's Watchdog controller is used for resuming system operation
+after a preset amount of time during which the WDT reset event has not
+occured.
+
+Required properties:
+- compatible : should be "samsung,s3c2410-wdt"
+- reg : base physical address of the controller and length of memory mapped
+       region.
+- interrupts : interrupt number to the cpu.
old mode 100644 (file)
new mode 100755 (executable)
index 3348d31..c466f58
@@ -27,7 +27,7 @@ use IO::Handle;
                "or51211", "or51132_qam", "or51132_vsb", "bluebird",
                "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
                "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
-               "lme2510c_s7395_old");
+               "lme2510c_s7395_old", "drxk", "drxk_terratec_h5");
 
 # Check args
 syntax() if (scalar(@ARGV) != 1);
@@ -634,6 +634,37 @@ sub lme2510c_s7395_old {
     $outfile;
 }
 
+sub drxk {
+    my $url = "http://l4m-daten.de/files/";
+    my $zipfile = "DDTuner.zip";
+    my $hash = "f5a37b9a20a3534997997c0b1382a3e5";
+    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+    my $drvfile = "DDTuner.sys";
+    my $fwfile = "drxk_a3.mc";
+
+    checkstandard();
+
+    wgetfile($zipfile, $url . $zipfile);
+    verify($zipfile, $hash);
+    unzip($zipfile, $tmpdir);
+    extract("$tmpdir/$drvfile", 0x14dd8, 15634, "$fwfile");
+
+    "$fwfile"
+}
+
+sub drxk_terratec_h5 {
+    my $url = "http://www.linuxtv.org/downloads/firmware/";
+    my $hash = "19000dada8e2741162ccc50cc91fa7f1";
+    my $fwfile = "dvb-usb-terratec-h5-drxk.fw";
+
+    checkstandard();
+
+    wgetfile($fwfile, $url . $fwfile);
+    verify($fwfile, $hash);
+
+    "$fwfile"
+}
+
 # ---------------------------------------------------------------
 # Utilities
 
index dfd6a9f4a58338ea5cc5d42fede7b826382685dc..ea0bace0124ad7db95b43f3e8f30c872584bc66b 100644 (file)
@@ -527,6 +527,41 @@ Who:       Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 
 ----------------------------
 
+What:  Support for driver specific ioctls in the pwc driver (everything
+       defined in media/pwc-ioctl.h)
+When:  3.3
+Why:   This stems from the v4l1 era, with v4l2 everything can be done with
+       standardized v4l2 API calls
+Who:   Hans de Goede <hdegoede@redhat.com>
+
+----------------------------
+
+What:  Driver specific sysfs API in the pwc driver
+When:  3.3
+Why:   Setting pan/tilt should be done with v4l2 controls, like with other
+       cams. The button is available as a standard input device
+Who:   Hans de Goede <hdegoede@redhat.com>
+
+----------------------------
+
+What:  Driver specific use of pixfmt.priv in the pwc driver
+When:  3.3
+Why:   The .priv field never was intended for this, setting a framerate is
+       support using the standardized S_PARM ioctl
+Who:   Hans de Goede <hdegoede@redhat.com>
+
+----------------------------
+
+What:  Software emulation of arbritary resolutions in the pwc driver
+When:  3.3
+Why:   The pwc driver claims to support any resolution between 160x120
+       and 640x480, but emulates this by simply drawing a black border
+       around the image. Userspace can draw its own black border if it
+       really wants one.
+Who:   Hans de Goede <hdegoede@redhat.com>
+
+----------------------------
+
 What:  For VIDIOC_S_FREQUENCY the type field must match the device node's type.
        If not, return -EINVAL.
 When:  3.2
index 6a3a6476cf207891895441205e3c2a180f8c38cd..097b3ccc4be767fd02a8c205e09812ed8982c5d5 100644 (file)
@@ -43,8 +43,8 @@ Documentation/hwmon/pmbus for details.
 Sysfs entries
 -------------
 
-The following attributes are supported. Limits are read-write; all other
-attributes are read-only.
+The following attributes are supported. Limits are read-write, history reset
+attributes are write-only, all other attributes are read-only.
 
 in1_label              "vin1" or "vout1" depending on chip variant and
                        configuration.
@@ -53,8 +53,12 @@ in1_min                      Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
 in1_max                        Maximum voltage. From VOUT_OV_WARN_LIMIT register.
 in1_min_alarm          Voltage low alarm. From VOLTAGE_UV_WARNING status.
 in1_max_alarm          Voltage high alarm. From VOLTAGE_OV_WARNING status.
+in1_highest            Historical maximum voltage.
+in1_reset_history      Write any value to reset history.
 
 curr1_label            "iout1"
 curr1_input            Measured current. From READ_IOUT register.
 curr1_max              Maximum current. From IOUT_OC_WARN_LIMIT register.
 curr1_max_alarm                Current high alarm. From IOUT_OC_WARN_LIMIT register.
+curr1_highest          Historical maximum current.
+curr1_reset_history    Write any value to reset history.
index f85e913a34011525f24d839e5e82aa3c295b552f..fa8776ab9b189d52d40c57ed0badbda64835b819 100644 (file)
@@ -35,6 +35,13 @@ the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
 All Sysfs entries are named with their core_id (represented here by 'X').
 tempX_input     - Core temperature (in millidegrees Celsius).
 tempX_max       - All cooling devices should be turned on (on Core2).
+                  Initialized with IA32_THERM_INTERRUPT. When the CPU
+                  temperature reaches this temperature, an interrupt is
+                  generated and tempX_max_alarm is set.
+tempX_max_hyst   - If the CPU temperature falls below than temperature,
+                  an interrupt is generated and tempX_max_alarm is reset.
+tempX_max_alarm  - Set if the temperature reaches or exceeds tempX_max.
+                  Reset if the temperature drops to or below tempX_max_hyst.
 tempX_crit      - Maximum junction temperature (in millidegrees Celsius).
 tempX_crit_alarm - Set when Out-of-spec bit is set, never clears.
                   Correct CPU operation is no longer guaranteed.
diff --git a/Documentation/hwmon/lm25066 b/Documentation/hwmon/lm25066
new file mode 100644 (file)
index 0000000..a21db81
--- /dev/null
@@ -0,0 +1,90 @@
+Kernel driver max8688
+=====================
+
+Supported chips:
+  * National Semiconductor LM25066
+    Prefix: 'lm25066'
+    Addresses scanned: -
+    Datasheets:
+       http://www.national.com/pf/LM/LM25066.html
+       http://www.national.com/pf/LM/LM25066A.html
+  * National Semiconductor LM5064
+    Prefix: 'lm5064'
+    Addresses scanned: -
+    Datasheet:
+       http://www.national.com/pf/LM/LM5064.html
+  * National Semiconductor LM5066
+    Prefix: 'lm5066'
+    Addresses scanned: -
+    Datasheet:
+       http://www.national.com/pf/LM/LM5066.html
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+This driver supports hardware montoring for National Semiconductor LM25066,
+LM5064, and LM5064 Power Management, Monitoring, Control, and Protection ICs.
+
+The driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in1_label              "vin"
+in1_input              Measured input voltage.
+in1_average            Average measured input voltage.
+in1_min                        Minimum input voltage.
+in1_max                        Maximum input voltage.
+in1_min_alarm          Input voltage low alarm.
+in1_max_alarm          Input voltage high alarm.
+
+in2_label              "vout1"
+in2_input              Measured output voltage.
+in2_average            Average measured output voltage.
+in2_min                        Minimum output voltage.
+in2_min_alarm          Output voltage low alarm.
+
+in3_label              "vout2"
+in3_input              Measured voltage on vaux pin
+
+curr1_label            "iin"
+curr1_input            Measured input current.
+curr1_average          Average measured input current.
+curr1_max              Maximum input current.
+curr1_max_alarm                Input current high alarm.
+
+power1_label           "pin"
+power1_input           Measured input power.
+power1_average         Average measured input power.
+power1_max             Maximum input power limit.
+power1_alarm           Input power alarm
+power1_input_highest   Historical maximum power.
+power1_reset_history   Write any value to reset maximum power history.
+
+temp1_input            Measured temperature.
+temp1_max              Maximum temperature.
+temp1_crit             Critical high temperature.
+temp1_max_alarm                Chip temperature high alarm.
+temp1_crit_alarm       Chip temperature critical high alarm.
index f3efd18e87f402ac3ba346ae15da07119f392fa6..9cd14cfe6515e34cdcceffc231b1996f141172b3 100644 (file)
@@ -113,7 +113,11 @@ Supported chips:
     Prefix: 'w83l771'
     Addresses scanned: I2C 0x4c
     Datasheet: Not publicly available, can be requested from Nuvoton
-
+  * Philips/NXP SA56004X
+    Prefix: 'sa56004'
+    Addresses scanned: I2C 0x48 through 0x4F
+    Datasheet: Publicly available at NXP website
+               http://ics.nxp.com/products/interface/datasheet/sa56004x.pdf
 
 Author: Jean Delvare <khali@linux-fr.org>
 
@@ -193,6 +197,9 @@ W83L771AWG/ASG
   * The AWG and ASG variants only differ in package format.
   * Diode ideality factor configuration (remote sensor) at 0xE3
 
+SA56004X:
+  * Better local resolution
+
 All temperature values are given in degrees Celsius. Resolution
 is 1.0 degree for the local temperature, 0.125 degree for the remote
 temperature, except for the MAX6657, MAX6658 and MAX6659 which have a
diff --git a/Documentation/hwmon/lm95245 b/Documentation/hwmon/lm95245
new file mode 100644 (file)
index 0000000..cbd8aea
--- /dev/null
@@ -0,0 +1,33 @@
+Kernel driver lm95245
+==================
+
+Supported chips:
+  * National Semiconductor LM95245
+    Addresses scanned: I2C 0x18, 0x19, 0x29, 0x4c, 0x4d
+    Datasheet: Publicly available at the National Semiconductor website
+               http://www.national.com/mpf/LM/LM95245.html
+
+
+Author: Alexander Stein <alexander.stein@systec-electronic.com>
+
+Description
+-----------
+
+The LM95245 is an 11-bit digital temperature sensor with a 2-wire System
+Management Bus (SMBus) interface and TruTherm technology that can monitor
+the temperature of a remote diode as well as its own temperature.
+The LM95245 can be used to very accurately monitor the temperature of
+external devices such as microprocessors.
+
+All temperature values are given in millidegrees Celsius. Local temperature
+is given within a range of -127 to +127.875 degrees. Remote temperatures are
+given within a range of -127 to +255 degrees. Resolution depends on
+temperature input and range.
+
+Each sensor has its own critical limit, but the hysteresis is common to all
+two channels.
+
+The lm95245 driver can change its update interval to a fixed set of values.
+It will round up to the next selectable interval. See the datasheet for exact
+values. Reading sensor values more often will do no harm, but will return
+'old' values.
index 41728999e142e525f89dd2c14233eebe6f2d1e94..f6e8bcbfaccfb4cd2c31671741fbb56b42b7cb7d 100644 (file)
@@ -50,6 +50,8 @@ in[1-4]_min_alarm     Voltage low alarm. From VOLTAGE_UV_WARNING status.
 in[1-4]_max_alarm      Voltage high alarm. From VOLTAGE_OV_WARNING status.
 in[1-4]_lcrit_alarm    Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
 in[1-4]_crit_alarm     Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+in[1-4]_highest                Historical maximum voltage.
+in[1-4]_reset_history  Write any value to reset history.
 
 temp1_input            Measured temperature. From READ_TEMPERATURE_1 register.
 temp1_max              Maximum temperature. From OT_WARN_LIMIT register.
@@ -60,3 +62,5 @@ temp1_max_alarm               Chip temperature high alarm. Set by comparing
 temp1_crit_alarm       Chip temperature critical high alarm. Set by comparing
                        READ_TEMPERATURE_1 with OT_FAULT_LIMIT if TEMP_OT_FAULT
                        status is set.
+temp1_highest          Historical maximum temperature.
+temp1_reset_history    Write any value to reset history.
diff --git a/Documentation/hwmon/max1668 b/Documentation/hwmon/max1668
new file mode 100644 (file)
index 0000000..0616ed9
--- /dev/null
@@ -0,0 +1,60 @@
+Kernel driver max1668
+=====================
+
+Supported chips:
+  * Maxim MAX1668, MAX1805 and MAX1989
+    Prefix: 'max1668'
+    Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e
+    Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX1668-MAX1989.pdf
+
+Author:
+    David George <david.george@ska.ac.za>
+
+Description
+-----------
+
+This driver implements support for the Maxim MAX1668, MAX1805 and MAX1989
+chips.
+
+The three devices are very similar, but the MAX1805 has a reduced feature
+set; only two remote temperature inputs vs the four avaible on the other
+two ICs.
+
+The driver is able to distinguish between the devices and creates sysfs
+entries as follows:
+
+MAX1805, MAX1668 and MAX1989:
+
+temp1_input     ro local (ambient) temperature
+temp1_max       rw local temperature maximum threshold for alarm
+temp1_max_alarm ro local temperature maximum threshold alarm
+temp1_min       rw local temperature minimum threshold for alarm
+temp1_min_alarm ro local temperature minimum threshold alarm
+temp2_input     ro remote temperature 1
+temp2_max       rw remote temperature 1 maximum threshold for alarm
+temp2_max_alarm ro remote temperature 1 maximum threshold alarm
+temp2_min       rw remote temperature 1 minimum threshold for alarm
+temp2_min_alarm ro remote temperature 1 minimum threshold alarm
+temp3_input     ro remote temperature 2
+temp3_max       rw remote temperature 2 maximum threshold for alarm
+temp3_max_alarm ro remote temperature 2 maximum threshold alarm
+temp3_min       rw remote temperature 2 minimum threshold for alarm
+temp3_min_alarm ro remote temperature 2 minimum threshold alarm
+
+MAX1668 and MAX1989 only:
+temp4_input     ro remote temperature 3
+temp4_max       rw remote temperature 3 maximum threshold for alarm
+temp4_max_alarm ro remote temperature 3 maximum threshold alarm
+temp4_min       rw remote temperature 3 minimum threshold for alarm
+temp4_min_alarm ro remote temperature 3 minimum threshold alarm
+temp5_input     ro remote temperature 4
+temp5_max       rw remote temperature 4 maximum threshold for alarm
+temp5_max_alarm ro remote temperature 4 maximum threshold alarm
+temp5_min       rw remote temperature 4 minimum threshold for alarm
+temp5_min_alarm ro remote temperature 4 minimum threshold alarm
+
+Module Parameters
+-----------------
+
+* read_only: int
+  Set to non-zero if you wish to prevent write access to alarm thresholds.
index 6c525dd07d5990891f8aba47d457cffaf1e30b97..8ab51536a1eb2b5dca0220bf45b7b6891b4e1213 100644 (file)
@@ -56,6 +56,8 @@ in[1-6]_min_alarm     Voltage low alarm. From VOLTAGE_UV_WARNING status.
 in[1-6]_max_alarm      Voltage high alarm. From VOLTAGE_OV_WARNING status.
 in[1-6]_lcrit_alarm    Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
 in[1-6]_crit_alarm     Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+in[1-6]_highest                Historical maximum voltage.
+in[1-6]_reset_history  Write any value to reset history.
 
 curr[1-6]_label                "iout[1-6]".
 curr[1-6]_input                Measured current. From READ_IOUT register.
@@ -63,6 +65,8 @@ curr[1-6]_max         Maximum current. From IOUT_OC_WARN_LIMIT register.
 curr[1-6]_crit         Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
 curr[1-6]_max_alarm    Current high alarm. From IOUT_OC_WARNING status.
 curr[1-6]_crit_alarm   Current critical high alarm. From IOUT_OC_FAULT status.
+curr[1-6]_highest      Historical maximum current.
+curr[1-6]_reset_history        Write any value to reset history.
 
                        in6 and curr6 attributes only exist for MAX34440.
 
@@ -75,5 +79,7 @@ temp[1-8]_max         Maximum temperature. From OT_WARN_LIMIT register.
 temp[1-8]_crit         Critical high temperature. From OT_FAULT_LIMIT register.
 temp[1-8]_max_alarm    Temperature high alarm.
 temp[1-8]_crit_alarm   Temperature critical high alarm.
+temp[1-8]_highest      Historical maximum temperature.
+temp[1-8]_reset_history        Write any value to reset history.
 
                        temp7 and temp8 attributes only exist for MAX34440.
index 0ddd3a4120306331864c8678a5a83f1c95cd3465..71ed10a3c94e7d6ad63db3ccd5edbd054d38ec60 100644 (file)
@@ -50,6 +50,8 @@ in1_min_alarm         Voltage low alarm. From VOLTAGE_UV_WARNING status.
 in1_max_alarm          Voltage high alarm. From VOLTAGE_OV_WARNING status.
 in1_lcrit_alarm                Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
 in1_crit_alarm         Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+in1_highest            Historical maximum voltage.
+in1_reset_history      Write any value to reset history.
 
 curr1_label            "iout1"
 curr1_input            Measured current. From READ_IOUT register.
@@ -57,6 +59,8 @@ curr1_max             Maximum current. From IOUT_OC_WARN_LIMIT register.
 curr1_crit             Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
 curr1_max_alarm                Current high alarm. From IOUT_OC_WARN_LIMIT register.
 curr1_crit_alarm       Current critical high alarm. From IOUT_OC_FAULT status.
+curr1_highest          Historical maximum current.
+curr1_reset_history    Write any value to reset history.
 
 temp1_input            Measured temperature. From READ_TEMPERATURE_1 register.
 temp1_max              Maximum temperature. From OT_WARN_LIMIT register.
@@ -67,3 +71,5 @@ temp1_max_alarm               Chip temperature high alarm. Set by comparing
 temp1_crit_alarm       Chip temperature critical high alarm. Set by comparing
                        READ_TEMPERATURE_1 with OT_FAULT_LIMIT if TEMP_OT_FAULT
                        status is set.
+temp1_highest          Historical maximum temperature.
+temp1_reset_history    Write any value to reset history.
diff --git a/Documentation/hwmon/ntc_thermistor b/Documentation/hwmon/ntc_thermistor
new file mode 100644 (file)
index 0000000..3bfda94
--- /dev/null
@@ -0,0 +1,93 @@
+Kernel driver ntc_thermistor
+=================
+
+Supported thermistors:
+* Murata NTC Thermistors NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, NCP15WL333
+  Prefixes: 'ncp15wb473', 'ncp18wb473', 'ncp21wb473', 'ncp03wb473', 'ncp15wl333'
+  Datasheet: Publicly available at Murata
+
+Other NTC thermistors can be supported simply by adding compensation
+tables; e.g., NCP15WL333 support is added by the table ncpXXwl333.
+
+Authors:
+       MyungJoo Ham <myungjoo.ham@samsung.com>
+
+Description
+-----------
+
+The NTC thermistor is a simple thermistor that requires users to provide the
+resistance and lookup the corresponding compensation table to get the
+temperature input.
+
+The NTC driver provides lookup tables with a linear approximation function
+and four circuit models with an option not to use any of the four models.
+
+The four circuit models provided are:
+
+       $: resister, [TH]: the thermistor
+
+ 1. connect = NTC_CONNECTED_POSITIVE, pullup_ohm > 0
+
+   [pullup_uV]
+       |    |
+      [TH]  $ (pullup_ohm)
+       |    |
+       +----+-----------------------[read_uV]
+       |
+       $ (pulldown_ohm)
+       |
+      --- (ground)
+
+ 2. connect = NTC_CONNECTED_POSITIVE, pullup_ohm = 0 (not-connected)
+
+   [pullup_uV]
+       |
+      [TH]
+       |
+       +----------------------------[read_uV]
+       |
+       $ (pulldown_ohm)
+       |
+      --- (ground)
+
+ 3. connect = NTC_CONNECTED_GROUND, pulldown_ohm > 0
+
+   [pullup_uV]
+       |
+       $ (pullup_ohm)
+       |
+       +----+-----------------------[read_uV]
+       |    |
+      [TH]  $ (pulldown_ohm)
+       |    |
+      -------- (ground)
+
+ 4. connect = NTC_CONNECTED_GROUND, pulldown_ohm = 0 (not-connected)
+
+   [pullup_uV]
+       |
+       $ (pullup_ohm)
+       |
+       +----------------------------[read_uV]
+       |
+      [TH]
+       |
+      --- (ground)
+
+When one of the four circuit models is used, read_uV, pullup_uV, pullup_ohm,
+pulldown_ohm, and connect should be provided. When none of the four models
+are suitable or the user can get the resistance directly, the user should
+provide read_ohm and _not_ provide the others.
+
+Sysfs Interface
+---------------
+name           the mandatory global attribute, the thermistor name.
+
+temp1_type     always 4 (thermistor)
+               RO
+
+temp1_input    measure the temperature and provide the measured value.
+               (reading this file initiates the reading procedure.)
+               RO
+
+Note that each NTC thermistor has only _one_ thermistor; thus, only temp1 exists.
index 5e462fc7f99b5f2e0f42c4edb92ebc1ac6c7571f..c36c1c1a62bb3915ea47cb865c970720825d0ce3 100644 (file)
@@ -13,6 +13,13 @@ Supported chips:
     Prefix: 'ltc2978'
     Addresses scanned: -
     Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf
+  * ON Semiconductor ADP4000, NCP4200, NCP4208
+    Prefixes: 'adp4000', 'ncp4200', 'ncp4208'
+    Addresses scanned: -
+    Datasheets:
+       http://www.onsemi.com/pub_link/Collateral/ADP4000-D.PDF
+       http://www.onsemi.com/pub_link/Collateral/NCP4200-D.PDF
+       http://www.onsemi.com/pub_link/Collateral/JUNE%202009-%20REV.%200.PDF
   * Generic PMBus devices
     Prefix: 'pmbus'
     Addresses scanned: -
index 8f63c244f1aab95b610c711abdaddc5e4335e7ee..a4aa8f600e09643beb6a2b505c9c08d00f28166a 100644 (file)
@@ -139,6 +139,29 @@ in[0-*]_input      Voltage input value.
                thumb: drivers should report the voltage values at the
                "pins" of the chip.
 
+in[0-*]_average
+               Average voltage
+               Unit: millivolt
+               RO
+
+in[0-*]_lowest
+               Historical minimum voltage
+               Unit: millivolt
+               RO
+
+in[0-*]_highest
+               Historical maximum voltage
+               Unit: millivolt
+               RO
+
+in[0-*]_reset_history
+               Reset inX_lowest and inX_highest
+               WO
+
+in_reset_history
+               Reset inX_lowest and inX_highest for all sensors
+               WO
+
 in[0-*]_label  Suggested voltage channel label.
                Text string
                Should only be created if the driver has hints about what
@@ -407,6 +430,29 @@ curr[1-*]_input    Current input value
                Unit: milliampere
                RO
 
+curr[1-*]_average
+               Average current use
+               Unit: milliampere
+               RO
+
+curr[1-*]_lowest
+               Historical minimum current
+               Unit: milliampere
+               RO
+
+curr[1-*]_highest
+               Historical maximum current
+               Unit: milliampere
+               RO
+
+curr[1-*]_reset_history
+               Reset currX_lowest and currX_highest
+               WO
+
+curr_reset_history
+               Reset currX_lowest and currX_highest for all sensors
+               WO
+
 Also see the Alarms section for status flags associated with currents.
 
 *********
index f0eee83ff78a61801e7d0cf293a2090180f208e8..fc94770f44abaf661f12577773cd803c6fd41370 100644 (file)
@@ -360,18 +360,20 @@ Each directory contains:
         A file recording the current state of the device in the array
        which can be a comma separated list of
              faulty   - device has been kicked from active use due to
-                         a detected fault
+                         a detected fault or it has unacknowledged bad
+                         blocks
              in_sync  - device is a fully in-sync member of the array
              writemostly - device will only be subject to read
                         requests if there are no other options.
                         This applies only to raid1 arrays.
-             blocked  - device has failed, metadata is "external",
-                        and the failure hasn't been acknowledged yet.
+             blocked  - device has failed, and the failure hasn't been
+                        acknowledged yet by the metadata handler.
                         Writes that would write to this device if
                         it were not faulty are blocked.
              spare    - device is working, but not a full member.
                         This includes spares that are in the process
                         of being recovered to
+             write_error - device has ever seen a write error.
        This list may grow in future.
        This can be written to.
        Writing "faulty"  simulates a failure on the device.
@@ -379,9 +381,11 @@ Each directory contains:
        Writing "writemostly" sets the writemostly flag.
        Writing "-writemostly" clears the writemostly flag.
        Writing "blocked" sets the "blocked" flag.
-       Writing "-blocked" clears the "blocked" flag and allows writes
-               to complete.
+       Writing "-blocked" clears the "blocked" flags and allows writes
+               to complete and possibly simulates an error.
        Writing "in_sync" sets the in_sync flag.
+       Writing "write_error" sets writeerrorseen flag.
+       Writing "-write_error" clears writeerrorseen flag.
 
        This file responds to select/poll. Any change to 'faulty'
        or 'blocked' causes an event.
@@ -419,7 +423,6 @@ Each directory contains:
         written, it will be rejected.
 
       recovery_start
-
         When the device is not 'in_sync', this records the number of
        sectors from the start of the device which are known to be
        correct.  This is normally zero, but during a recovery
@@ -435,6 +438,20 @@ Each directory contains:
        Setting this to 'none' is equivalent to setting 'in_sync'.
        Setting to any other value also clears the 'in_sync' flag.
        
+      bad_blocks
+       This gives the list of all known bad blocks in the form of
+       start address and length (in sectors respectively). If output
+       is too big to fit in a page, it will be truncated. Writing
+       "sector length" to this file adds new acknowledged (i.e.
+       recorded to disk safely) bad blocks.
+
+      unacknowledged_bad_blocks
+       This gives the list of known-but-not-yet-saved-to-disk bad
+       blocks in the same form of 'bad_blocks'. If output is too big
+       to fit in a page, it will be truncated. Writing to this file
+       adds bad blocks without acknowledging them. This is largely
+       for testing.
+
 
 
 An active md device will also contain and entry for each active device
index 76a2087db20578e587ba2b63f70109939324b3fc..669b5fb03a868c32f2a3e36fc2380727b66d1636 100644 (file)
@@ -310,7 +310,7 @@ is non-immutable. The operation must either configure the hardware or store
 the configuration information to be applied later.
 
 Link configuration must not have any side effect on other links. If an enabled
-link at a sink pad prevents another link at the same pad from being disabled,
+link at a sink pad prevents another link at the same pad from being enabled,
 the link_setup operation must return -EBUSY and can't implicitly disable the
 first enabled link.
 
index 9ed1d9d96783cbf8992b9a91f7f38221dc8f6dc1..1b6e27ddb7f3db06fd0dc935f953a66ae4cd77f2 100644 (file)
@@ -1,3 +1,11 @@
+Release Date    : Tue. Jul 26, 2011 17:00:00 PST 2010 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Adam Radford
+Current Version : 00.00.05.40-rc1
+Old Version     : 00.00.05.38-rc1
+    1. Fix FastPath I/O to work with degraded RAID 1.
+    2. Add .change_queue_depth support.
+-------------------------------------------------------------------------------
 Release Date    : Wed. May 11, 2011 17:00:00 PST 2010 -
                        (emaild-id:megaraidlinux@lsi.com)
                        Adam Radford
diff --git a/Documentation/security/keys-ecryptfs.txt b/Documentation/security/keys-ecryptfs.txt
new file mode 100644 (file)
index 0000000..c3bbeba
--- /dev/null
@@ -0,0 +1,68 @@
+               Encrypted keys for the eCryptfs filesystem
+
+ECryptfs is a stacked filesystem which transparently encrypts and decrypts each
+file using a randomly generated File Encryption Key (FEK).
+
+Each FEK is in turn encrypted with a File Encryption Key Encryption Key (FEFEK)
+either in kernel space or in user space with a daemon called 'ecryptfsd'.  In
+the former case the operation is performed directly by the kernel CryptoAPI
+using a key, the FEFEK, derived from a user prompted passphrase;  in the latter
+the FEK is encrypted by 'ecryptfsd' with the help of external libraries in order
+to support other mechanisms like public key cryptography, PKCS#11 and TPM based
+operations.
+
+The data structure defined by eCryptfs to contain information required for the
+FEK decryption is called authentication token and, currently, can be stored in a
+kernel key of the 'user' type, inserted in the user's session specific keyring
+by the userspace utility 'mount.ecryptfs' shipped with the package
+'ecryptfs-utils'.
+
+The 'encrypted' key type has been extended with the introduction of the new
+format 'ecryptfs' in order to be used in conjunction with the eCryptfs
+filesystem.  Encrypted keys of the newly introduced format store an
+authentication token in its payload with a FEFEK randomly generated by the
+kernel and protected by the parent master key.
+
+In order to avoid known-plaintext attacks, the datablob obtained through
+commands 'keyctl print' or 'keyctl pipe' does not contain the overall
+authentication token, which content is well known, but only the FEFEK in
+encrypted form.
+
+The eCryptfs filesystem may really benefit from using encrypted keys in that the
+required key can be securely generated by an Administrator and provided at boot
+time after the unsealing of a 'trusted' key in order to perform the mount in a
+controlled environment.  Another advantage is that the key is not exposed to
+threats of malicious software, because it is available in clear form only at
+kernel level.
+
+Usage:
+   keyctl add encrypted name "new ecryptfs key-type:master-key-name keylen" ring
+   keyctl add encrypted name "load hex_blob" ring
+   keyctl update keyid "update key-type:master-key-name"
+
+name:= '<16 hexadecimal characters>'
+key-type:= 'trusted' | 'user'
+keylen:= 64
+
+
+Example of encrypted key usage with the eCryptfs filesystem:
+
+Create an encrypted key "1000100010001000" of length 64 bytes with format
+'ecryptfs' and save it using a previously loaded user key "test":
+
+    $ keyctl add encrypted 1000100010001000 "new ecryptfs user:test 64" @u
+    19184530
+
+    $ keyctl print 19184530
+    ecryptfs user:test 64 490045d4bfe48c99f0d465fbbbb79e7500da954178e2de0697
+    dd85091f5450a0511219e9f7cd70dcd498038181466f78ac8d4c19504fcc72402bfc41c2
+    f253a41b7507ccaa4b2b03fff19a69d1cc0b16e71746473f023a95488b6edfd86f7fdd40
+    9d292e4bacded1258880122dd553a661
+
+    $ keyctl pipe 19184530 > ecryptfs.blob
+
+Mount an eCryptfs filesystem using the created encrypted key "1000100010001000"
+into the '/secret' directory:
+
+    $ mount -i -t ecryptfs -oecryptfs_sig=1000100010001000,\
+      ecryptfs_cipher=aes,ecryptfs_key_bytes=32 /secret /secret
index 8fb79bc1ac4b7f91fed15f7c0c58a8026291836d..5f50ccabfc8a45d992314774a5de80c20fa49ace 100644 (file)
@@ -53,12 +53,19 @@ they are only as secure as the user key encrypting them.  The master user key
 should therefore be loaded in as secure a way as possible, preferably early in
 boot.
 
+The decrypted portion of encrypted keys can contain either a simple symmetric
+key or a more complex structure. The format of the more complex structure is
+application specific, which is identified by 'format'.
+
 Usage:
-  keyctl add encrypted name "new key-type:master-key-name keylen" ring
-  keyctl add encrypted name "load hex_blob" ring
-  keyctl update keyid "update key-type:master-key-name"
+    keyctl add encrypted name "new [format] key-type:master-key-name keylen"
+        ring
+    keyctl add encrypted name "load hex_blob" ring
+    keyctl update keyid "update key-type:master-key-name"
+
+format:= 'default | ecryptfs'
+key-type:= 'trusted' | 'user'
 
-where 'key-type' is either 'trusted' or 'user'.
 
 Examples of trusted and encrypted key usage:
 
@@ -114,15 +121,25 @@ Reseal a trusted key under new pcr values:
     7ef6a24defe4846104209bf0c3eced7fa1a672ed5b125fc9d8cd88b476a658a4434644ef
     df8ae9a178e9f83ba9f08d10fa47e4226b98b0702f06b3b8
 
-Create and save an encrypted key "evm" using the above trusted key "kmk":
+The initial consumer of trusted keys is EVM, which at boot time needs a high
+quality symmetric key for HMAC protection of file metadata.  The use of a
+trusted key provides strong guarantees that the EVM key has not been
+compromised by a user level problem, and when sealed to specific boot PCR
+values, protects against boot and offline attacks.  Create and save an
+encrypted key "evm" using the above trusted key "kmk":
 
+option 1: omitting 'format'
     $ keyctl add encrypted evm "new trusted:kmk 32" @u
     159771175
 
+option 2: explicitly defining 'format' as 'default'
+    $ keyctl add encrypted evm "new default trusted:kmk 32" @u
+    159771175
+
     $ keyctl print 159771175
-    trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382dbbc55
-    be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e024717c64
-    5972dcb82ab2dde83376d82b2e3c09ffc
+    default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3
+    82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
+    24717c64 5972dcb82ab2dde83376d82b2e3c09ffc
 
     $ keyctl pipe 159771175 > evm.blob
 
@@ -132,14 +149,11 @@ Load an encrypted key "evm" from saved blob:
     831684262
 
     $ keyctl print 831684262
-    trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382dbbc55
-    be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e024717c64
-    5972dcb82ab2dde83376d82b2e3c09ffc
-
-
-The initial consumer of trusted keys is EVM, which at boot time needs a high
-quality symmetric key for HMAC protection of file metadata.  The use of a
-trusted key provides strong guarantees that the EVM key has not been
-compromised by a user level problem, and when sealed to specific boot PCR
-values, protects against boot and offline attacks.  Other uses for trusted and
-encrypted keys, such as for disk and file encryption are anticipated.
+    default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3
+    82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
+    24717c64 5972dcb82ab2dde83376d82b2e3c09ffc
+
+Other uses for trusted and encrypted keys, such as for disk and file encryption
+are anticipated.  In particular the new format 'ecryptfs' has been defined in
+in order to use encrypted keys to mount an eCryptfs filesystem.  More details
+about the usage can be found in the file 'Documentation/keys-ecryptfs.txt'.
index d72fd2aa9158d84748d7fb48afc072a2ec27ce27..256f8efa992c27a30c34bcbeca0c9bc3053f9e2e 100644 (file)
@@ -9,7 +9,7 @@
   <table border="0">
    <tr>
     <td>
-     <a href="http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html">V4L original API</a>
+     <a href="http://linuxtv.org/downloads/legacy/video4linux/API/V4L1_API.html">V4L original API</a>
     </td>
     <td>
      Obsoleted by V4L2 API
index 87c46347bd6362f0f20927646387cb05444536e3..8910449d23a8e355cc1fc86dd400638224166fc4 100644 (file)
@@ -27,3 +27,5 @@
  26 -> Hauppauge WinTV-HVR1290                             [0070:8551]
  27 -> Mygica X8558 PRO DMB-TH                             [14f1:8578]
  28 -> LEADTEK WinFast PxTV1200                            [107d:6f22]
+ 29 -> GoTView X5 3D Hybrid                                [5654:2390]
+ 30 -> NetUP Dual DVB-T/C-CI RF                            [1b55:e2e4]
index 42517d9121ded5df58774558eca89721afc8272d..d9c0f119196d0f2ef15dc1f3a70e40fd46e3524b 100644 (file)
@@ -84,3 +84,4 @@
  83 -> Prof 7301 DVB-S/S2                                  [b034:3034]
  84 -> Samsung SMT 7020 DVB-S                              [18ac:dc00,18ac:dccd]
  85 -> Twinhan VP-1027 DVB-S                               [1822:0023]
+ 86 -> TeVii S464 DVB-S/S2                                 [d464:9022]
index 9aae449440dc465c02780d72600f3496670cbc84..4a7b3df6d8bd7695a0cee2417d3d849b43912345 100644 (file)
@@ -74,3 +74,5 @@
  74 -> Actionmaster/LinXcel/Digitus VC211A      (em2800)
  75 -> Dikom DK300                              (em2882)
  76 -> KWorld PlusTV 340U or UB435-Q (ATSC)     (em2870)        [1b80:a340]
+ 77 -> EM2874 Leadership ISDBT                  (em2874)
+ 78 -> PCTV nanoStick T2 290e                   (em28174)
index 6b4c72d8862d294a5ee2cf8d85a4b63c7845cdaf..7efae9bd73eda9445ce6db29c079a20510d53a49 100644 (file)
 181 -> TechoTrend TT-budget T-3000              [13c2:2804]
 182 -> Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid  [17de:b136]
 183 -> Compro VideoMate Vista M1F               [185b:c900]
+184 -> Encore ENLTV-FM 3                        [1a7f:2108]
+185 -> MagicPro ProHDTV Pro2 DMB-TH/Hybrid      [17de:d136]
+186 -> Beholder BeholdTV 501                    [5ace:5010]
+187 -> Beholder BeholdTV 503 FM                 [5ace:5030]
index e67c1db968544ede6ddf80514b97ad96866f6ff7..6323b7a20719eb309d86ba6b736efb5ee09ee03a 100644 (file)
@@ -78,8 +78,10 @@ tuner=77 - TCL tuner MF02GIP-5N-E
 tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
 tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
 tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
+tuner=81 - Xceive 4000 tuner
 tuner=81 - Partsnic (Daewoo) PTI-5NF05
 tuner=82 - Philips CU1216L
 tuner=83 - NXP TDA18271
 tuner=84 - Sony BTF-Pxn01Z
 tuner=85 - Philips FQ1236 MK5
+tuner=86 - Tena TNF5337 MFD
index 0b72d3fee17ef4bb02a8d37c763a5d73fb84f4d0..6fd1af36514233b1aec68fa575538af85d5faf61 100644 (file)
@@ -63,3 +63,5 @@
  62 -> Pinnacle PCTV Bungee USB (PAL) FM                        [2304:0419]
  63 -> Hauppauge WinTv-USB                                      [2400:4200]
  64 -> Pinnacle Studio PCTV USB (NTSC) FM V3                    [2304:0113]
+ 65 -> Nogatech USB MicroCam NTSC (NV3000N)                     [0573:3000]
+ 66 -> Nogatech USB MicroCam PAL (NV3001P)                      [0573:3001]
diff --git a/Documentation/video4linux/README.davinci-vpbe b/Documentation/video4linux/README.davinci-vpbe
new file mode 100644 (file)
index 0000000..7a460b0
--- /dev/null
@@ -0,0 +1,93 @@
+
+                VPBE V4L2 driver design
+ ======================================================================
+
+ File partitioning
+ -----------------
+ V4L2 display device driver
+         drivers/media/video/davinci/vpbe_display.c
+         drivers/media/video/davinci/vpbe_display.h
+
+ VPBE display controller
+         drivers/media/video/davinci/vpbe.c
+         drivers/media/video/davinci/vpbe.h
+
+ VPBE venc sub device driver
+         drivers/media/video/davinci/vpbe_venc.c
+         drivers/media/video/davinci/vpbe_venc.h
+         drivers/media/video/davinci/vpbe_venc_regs.h
+
+ VPBE osd driver
+         drivers/media/video/davinci/vpbe_osd.c
+         drivers/media/video/davinci/vpbe_osd.h
+         drivers/media/video/davinci/vpbe_osd_regs.h
+
+ Functional partitioning
+ -----------------------
+
+ Consists of the following (in the same order as the list under file
+ partitioning):-
+
+ 1. V4L2 display driver
+    Implements creation of video2 and video3 device nodes and
+    provides v4l2 device interface to manage VID0 and VID1 layers.
+
+ 2. Display controller
+    Loads up VENC, OSD and external encoders such as ths8200. It provides
+    a set of API calls to V4L2 drivers to set the output/standards
+    in the VENC or external sub devices. It also provides
+    a device object to access the services from OSD subdevice
+    using sub device ops. The connection of external encoders to VENC LCD
+    controller port is done at init time based on default output and standard
+    selection or at run time when application change the output through
+    V4L2 IOCTLs.
+
+    When connected to an external encoder, vpbe controller is also responsible
+    for setting up the interface between VENC and external encoders based on
+    board specific settings (specified in board-xxx-evm.c). This allows
+    interfacing external encoders such as ths8200. The setup_if_config()
+    is implemented for this as well as configure_venc() (part of the next patch)
+    API to set timings in VENC for a specific display resolution. As of this
+    patch series, the interconnection and enabling and setting of the external
+    encoders is not present, and would be a part of the next patch series.
+
+ 3. VENC subdevice module
+    Responsible for setting outputs provided through internal DACs and also
+    setting timings at LCD controller port when external encoders are connected
+    at the port or LCD panel timings required. When external encoder/LCD panel
+    is connected, the timings for a specific standard/preset is retrieved from
+    the board specific table and the values are used to set the timings in
+    venc using non-standard timing mode.
+
+    Support LCD Panel displays using the VENC. For example to support a Logic
+    PD display, it requires setting up the LCD controller port with a set of
+    timings for the resolution supported and setting the dot clock. So we could
+    add the available outputs as a board specific entry (i.e add the "LogicPD"
+    output name to board-xxx-evm.c). A table of timings for various LCDs
+    supported can be maintained in the board specific setup file to support
+    various LCD displays.As of this patch a basic driver is present, and this
+    support for external encoders and displays forms a part of the next
+    patch series.
+
+ 4. OSD module
+    OSD module implements all OSD layer management and hardware specific
+    features. The VPBE module interacts with the OSD for enabling and
+    disabling appropriate features of the OSD.
+
+ Current status:-
+
+ A fully functional working version of the V4L2 driver is available. This
+ driver has been tested with NTSC and PAL standards and buffer streaming.
+
+ Following are TBDs.
+
+ vpbe display controller
+    - Add support for external encoders.
+    - add support for selecting external encoder as default at probe time.
+
+ vpbe venc sub device
+    - add timings for supporting ths8200
+    - add support for LogicPD LCD.
+
+ FB drivers
+    - Add support for fbdev drivers.- Ready and part of subsequent patches.
index 881e7f44491b70a6c803fa68f6185cb4f158b87f..9346fc8cbf2b2323e205f1f8669fd626cfc1047a 100644 (file)
@@ -277,16 +277,13 @@ implement g_volatile_ctrl like this:
        {
                switch (ctrl->id) {
                case V4L2_CID_BRIGHTNESS:
-                       ctrl->cur.val = read_reg(0x123);
+                       ctrl->val = read_reg(0x123);
                        break;
                }
        }
 
-The 'new value' union is not used in g_volatile_ctrl. In general controls
-that need to implement g_volatile_ctrl are read-only controls.
-
-Note that if one or more controls in a control cluster are marked as volatile,
-then all the controls in the cluster are seen as volatile.
+Note that you use the 'new value' union as well in g_volatile_ctrl. In general
+controls that need to implement g_volatile_ctrl are read-only controls.
 
 To mark a control as volatile you have to set the is_volatile flag:
 
@@ -453,6 +450,25 @@ In the example above the following are equivalent for the VOLUME case:
        ctrl == ctrl->cluster[AUDIO_CL_VOLUME] == state->audio_cluster[AUDIO_CL_VOLUME]
        ctrl->cluster[AUDIO_CL_MUTE] == state->audio_cluster[AUDIO_CL_MUTE]
 
+In practice using cluster arrays like this becomes very tiresome. So instead
+the following equivalent method is used:
+
+       struct {
+               /* audio cluster */
+               struct v4l2_ctrl *volume;
+               struct v4l2_ctrl *mute;
+       };
+
+The anonymous struct is used to clearly 'cluster' these two control pointers,
+but it serves no other purpose. The effect is the same as creating an
+array with two control pointers. So you can just do:
+
+       state->volume = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
+       state->mute = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
+       v4l2_ctrl_cluster(2, &state->volume);
+
+And in foo_s_ctrl you can use these pointers directly: state->mute->val.
+
 Note that controls in a cluster may be NULL. For example, if for some
 reason mute was never added (because the hardware doesn't support that
 particular feature), then mute will be NULL. So in that case we have a
@@ -475,6 +491,43 @@ controls, then the 'is_new' flag would be 1 for both controls.
 The 'is_new' flag is always 1 when called from v4l2_ctrl_handler_setup().
 
 
+Handling autogain/gain-type Controls with Auto Clusters
+=======================================================
+
+A common type of control cluster is one that handles 'auto-foo/foo'-type
+controls. Typical examples are autogain/gain, autoexposure/exposure,
+autowhitebalance/red balance/blue balance. In all cases you have one controls
+that determines whether another control is handled automatically by the hardware,
+or whether it is under manual control from the user.
+
+If the cluster is in automatic mode, then the manual controls should be
+marked inactive. When the volatile controls are read the g_volatile_ctrl
+operation should return the value that the hardware's automatic mode set up
+automatically.
+
+If the cluster is put in manual mode, then the manual controls should become
+active again and the is_volatile flag should be ignored (so g_volatile_ctrl is
+no longer called while in manual mode).
+
+Finally the V4L2_CTRL_FLAG_UPDATE should be set for the auto control since
+changing that control affects the control flags of the manual controls.
+
+In order to simplify this a special variation of v4l2_ctrl_cluster was
+introduced:
+
+void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
+                       u8 manual_val, bool set_volatile);
+
+The first two arguments are identical to v4l2_ctrl_cluster. The third argument
+tells the framework which value switches the cluster into manual mode. The
+last argument will optionally set the is_volatile flag for the non-auto controls.
+
+The first control of the cluster is assumed to be the 'auto' control.
+
+Using this function will ensure that you don't need to handle all the complex
+flag and volatile handling.
+
+
 VIDIOC_LOG_STATUS Support
 =========================
 
@@ -636,9 +689,7 @@ button controls are write-only controls.
 -EINVAL as the spec says.
 
 5) The spec does not mention what should happen when you try to set/get a
-control class controls. ivtv currently returns -EINVAL (indicating that the
-control ID does not exist) while the framework will return -EACCES, which
-makes more sense.
+control class controls. The framework will return -EACCES.
 
 
 Proposals for Extensions
index cf21f7aae976a903b43b7d12a69855acfef101e0..f8dcabf7852cfa1f26ef5103703083539e14f7ab 100644 (file)
@@ -817,11 +817,7 @@ int my_open(struct file *file)
 
        ...
 
-       ret = v4l2_fh_init(&my_fh->fh, vfd);
-       if (ret) {
-               kfree(my_fh);
-               return ret;
-       }
+       v4l2_fh_init(&my_fh->fh, vfd);
 
        ...
 
@@ -844,7 +840,7 @@ int my_release(struct file *file)
 
 Below is a short description of the v4l2_fh functions used:
 
-int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
+void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
 
   Initialise the file handle. This *MUST* be performed in the driver's
   v4l2_file_operations->open() handler.
@@ -901,14 +897,38 @@ V4L2 events
 The V4L2 events provide a generic way to pass events to user space.
 The driver must use v4l2_fh to be able to support V4L2 events.
 
-Useful functions:
+Events are defined by a type and an optional ID. The ID may refer to a V4L2
+object such as a control ID. If unused, then the ID is 0.
+
+When the user subscribes to an event the driver will allocate a number of
+kevent structs for that event. So every (type, ID) event tuple will have
+its own set of kevent structs. This guarantees that if a driver is generating
+lots of events of one type in a short time, then that will not overwrite
+events of another type.
+
+But if you get more events of one type than the number of kevents that were
+reserved, then the oldest event will be dropped and the new one added.
+
+Furthermore, the internal struct v4l2_subscribed_event has merge() and
+replace() callbacks which drivers can set. These callbacks are called when
+a new event is raised and there is no more room. The replace() callback
+allows you to replace the payload of the old event with that of the new event,
+merging any relevant data from the old payload into the new payload that
+replaces it. It is called when this event type has only one kevent struct
+allocated. The merge() callback allows you to merge the oldest event payload
+into that of the second-oldest event payload. It is called when there are two
+or more kevent structs allocated.
 
-- v4l2_event_alloc()
+This way no status information is lost, just the intermediate steps leading
+up to that state.
 
-  To use events, the driver must allocate events for the file handle. By
-  calling the function more than once, the driver may assure that at least n
-  events in total have been allocated. The function may not be called in
-  atomic context.
+A good example of these replace/merge callbacks is in v4l2-event.c:
+ctrls_replace() and ctrls_merge() callbacks for the control event.
+
+Note: these callbacks can be called from interrupt context, so they must be
+fast.
+
+Useful functions:
 
 - v4l2_event_queue()
 
@@ -920,7 +940,9 @@ Useful functions:
 
   The video_device->ioctl_ops->vidioc_subscribe_event must check the driver
   is able to produce events with specified event id. Then it calls
-  v4l2_event_subscribe() to subscribe the event.
+  v4l2_event_subscribe() to subscribe the event. The last argument is the
+  size of the event queue for this event. If it is 0, then the framework
+  will fill in a default value (this depends on the event type).
 
 - v4l2_event_unsubscribe()
 
@@ -935,14 +957,8 @@ Useful functions:
 
   Returns the number of pending events. Useful when implementing poll.
 
-Drivers do not initialise events directly. The events are initialised
-through v4l2_fh_init() if video_device->ioctl_ops->vidioc_subscribe_event is
-non-NULL. This *MUST* be performed in the driver's
-v4l2_file_operations->open() handler.
-
 Events are delivered to user space through the poll system call. The driver
-can use v4l2_fh->events->wait wait_queue_head_t as the argument for
-poll_wait().
+can use v4l2_fh->wait (a wait_queue_head_t) as the argument for poll_wait().
 
 There are standard and private events. New standard events must use the
 smallest available event type. The drivers must allocate their events from
@@ -952,5 +968,4 @@ The first event type in the class is reserved for future use, so the first
 available event type is 'class base + 1'.
 
 An example on how the V4L2 events may be used can be found in the OMAP
-3 ISP driver available at <URL:http://gitorious.org/omap3camera> as of
-writing this.
+3 ISP driver (drivers/media/video/omap3isp).
index ee994513a9b1dff1799361d10ad56c7c6cf50128..fc51128071c27c332f65c254806e9b1f0f95992e 100644 (file)
@@ -8,6 +8,8 @@ src/
        - directory holding watchdog related example programs.
 watchdog-api.txt
        - description of the Linux Watchdog driver API.
+watchdog-kernel-api.txt
+       - description of the Linux WatchDog Timer Driver Core kernel API.
 watchdog-parameters.txt
        - information on driver parameters (for drivers other than
          the ones that have driver-specific files here)
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
new file mode 100644 (file)
index 0000000..4f7c894
--- /dev/null
@@ -0,0 +1,162 @@
+The Linux WatchDog Timer Driver Core kernel API.
+===============================================
+Last reviewed: 22-Jul-2011
+
+Wim Van Sebroeck <wim@iguana.be>
+
+Introduction
+------------
+This document does not describe what a WatchDog Timer (WDT) Driver or Device is.
+It also does not describe the API which can be used by user space to communicate
+with a WatchDog Timer. If you want to know this then please read the following
+file: Documentation/watchdog/watchdog-api.txt .
+
+So what does this document describe? It describes the API that can be used by
+WatchDog Timer Drivers that want to use the WatchDog Timer Driver Core
+Framework. This framework provides all interfacing towards user space so that
+the same code does not have to be reproduced each time. This also means that
+a watchdog timer driver then only needs to provide the different routines
+(operations) that control the watchdog timer (WDT).
+
+The API
+-------
+Each watchdog timer driver that wants to use the WatchDog Timer Driver Core
+must #include <linux/watchdog.h> (you would have to do this anyway when
+writing a watchdog device driver). This include file contains following
+register/unregister routines:
+
+extern int watchdog_register_device(struct watchdog_device *);
+extern void watchdog_unregister_device(struct watchdog_device *);
+
+The watchdog_register_device routine registers a watchdog timer device.
+The parameter of this routine is a pointer to a watchdog_device structure.
+This routine returns zero on success and a negative errno code for failure.
+
+The watchdog_unregister_device routine deregisters a registered watchdog timer
+device. The parameter of this routine is the pointer to the registered
+watchdog_device structure.
+
+The watchdog device structure looks like this:
+
+struct watchdog_device {
+       const struct watchdog_info *info;
+       const struct watchdog_ops *ops;
+       unsigned int bootstatus;
+       unsigned int timeout;
+       unsigned int min_timeout;
+       unsigned int max_timeout;
+       void *driver_data;
+       unsigned long status;
+};
+
+It contains following fields:
+* info: a pointer to a watchdog_info structure. This structure gives some
+  additional information about the watchdog timer itself. (Like it's unique name)
+* ops: a pointer to the list of watchdog operations that the watchdog supports.
+* timeout: the watchdog timer's timeout value (in seconds).
+* min_timeout: the watchdog timer's minimum timeout value (in seconds).
+* max_timeout: the watchdog timer's maximum timeout value (in seconds).
+* bootstatus: status of the device after booting (reported with watchdog
+  WDIOF_* status bits).
+* driver_data: a pointer to the drivers private data of a watchdog device.
+  This data should only be accessed via the watchdog_set_drvadata and
+  watchdog_get_drvdata routines.
+* status: this field contains a number of status bits that give extra
+  information about the status of the device (Like: is the watchdog timer
+  running/active, is the nowayout bit set, is the device opened via
+  the /dev/watchdog interface or not, ...).
+
+The list of watchdog operations is defined as:
+
+struct watchdog_ops {
+       struct module *owner;
+       /* mandatory operations */
+       int (*start)(struct watchdog_device *);
+       int (*stop)(struct watchdog_device *);
+       /* optional operations */
+       int (*ping)(struct watchdog_device *);
+       unsigned int (*status)(struct watchdog_device *);
+       int (*set_timeout)(struct watchdog_device *, unsigned int);
+       long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
+};
+
+It is important that you first define the module owner of the watchdog timer
+driver's operations. This module owner will be used to lock the module when
+the watchdog is active. (This to avoid a system crash when you unload the
+module and /dev/watchdog is still open).
+Some operations are mandatory and some are optional. The mandatory operations
+are:
+* start: this is a pointer to the routine that starts the watchdog timer
+  device.
+  The routine needs a pointer to the watchdog timer device structure as a
+  parameter. It returns zero on success or a negative errno code for failure.
+* stop: with this routine the watchdog timer device is being stopped.
+  The routine needs a pointer to the watchdog timer device structure as a
+  parameter. It returns zero on success or a negative errno code for failure.
+  Some watchdog timer hardware can only be started and not be stopped. The
+  driver supporting this hardware needs to make sure that a start and stop
+  routine is being provided. This can be done by using a timer in the driver
+  that regularly sends a keepalive ping to the watchdog timer hardware.
+
+Not all watchdog timer hardware supports the same functionality. That's why
+all other routines/operations are optional. They only need to be provided if
+they are supported. These optional routines/operations are:
+* ping: this is the routine that sends a keepalive ping to the watchdog timer
+  hardware.
+  The routine needs a pointer to the watchdog timer device structure as a
+  parameter. It returns zero on success or a negative errno code for failure.
+  Most hardware that does not support this as a separate function uses the
+  start function to restart the watchdog timer hardware. And that's also what
+  the watchdog timer driver core does: to send a keepalive ping to the watchdog
+  timer hardware it will either use the ping operation (when available) or the
+  start operation (when the ping operation is not available).
+  (Note: the WDIOC_KEEPALIVE ioctl call will only be active when the
+  WDIOF_KEEPALIVEPING bit has been set in the option field on the watchdog's
+  info structure).
+* status: this routine checks the status of the watchdog timer device. The
+  status of the device is reported with watchdog WDIOF_* status flags/bits.
+* set_timeout: this routine checks and changes the timeout of the watchdog
+  timer device. It returns 0 on success, -EINVAL for "parameter out of range"
+  and -EIO for "could not write value to the watchdog". On success the timeout
+  value of the watchdog_device will be changed to the value that was just used
+  to re-program the watchdog timer device.
+  (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
+  watchdog's info structure).
+* ioctl: if this routine is present then it will be called first before we do
+  our own internal ioctl call handling. This routine should return -ENOIOCTLCMD
+  if a command is not supported. The parameters that are passed to the ioctl
+  call are: watchdog_device, cmd and arg.
+
+The status bits should (preferably) be set with the set_bit and clear_bit alike
+bit-operations. The status bits that are defined are:
+* WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device
+  is active or not. When the watchdog is active after booting, then you should
+  set this status bit (Note: when you register the watchdog timer device with
+  this bit set, then opening /dev/watchdog will skip the start operation)
+* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device
+  was opened via /dev/watchdog.
+  (This bit should only be used by the WatchDog Timer Driver Core).
+* WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character
+  has been sent (so that we can support the magic close feature).
+  (This bit should only be used by the WatchDog Timer Driver Core).
+* WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog.
+  If this bit is set then the watchdog timer will not be able to stop.
+
+Note: The WatchDog Timer Driver Core supports the magic close feature and
+the nowayout feature. To use the magic close feature you must set the
+WDIOF_MAGICCLOSE bit in the options field of the watchdog's info structure.
+The nowayout feature will overrule the magic close feature.
+
+To get or set driver specific data the following two helper functions should be
+used:
+
+static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data)
+static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
+
+The watchdog_set_drvdata function allows you to add driver specific data. The
+arguments of this function are the watchdog device where you want to add the
+driver specific data to and a pointer to the data itself.
+
+The watchdog_get_drvdata function allows you to retrieve driver specific data.
+The argument of this function is the watchdog device where you want to retrieve
+data from. The function retruns the pointer to the driver specific data.
index 7b2e9e85e427e50d77d41ddad93281461134f47c..c9c6324a7a9f887e930b6fabfdb7039af3a02dae 100644 (file)
@@ -1925,6 +1925,12 @@ S:       Maintained
 F:     arch/x86/kernel/cpuid.c
 F:     arch/x86/kernel/msr.c
 
+CPU POWER MONITORING SUBSYSTEM
+M:     Dominik Brodowski <linux@dominikbrodowski.net>
+M:     Thomas Renninger <trenn@suse.de>
+S:     Maintained
+F:     tools/power/cpupower
+
 CPUSETS
 M:     Paul Menage <menage@google.com>
 W:     http://www.bullopensource.org/cpuset/
@@ -4150,6 +4156,13 @@ S:       Orphan
 F:     drivers/video/matrox/matroxfb_*
 F:     include/linux/matroxfb.h
 
+MAX1668 TEMPERATURE SENSOR DRIVER
+M:     "David George" <david.george@ska.ac.za>
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+F:     Documentation/hwmon/max1668
+F:     drivers/hwmon/max1668.c
+
 MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 M:     "Hans J. Koch" <hjk@hansjkoch.de>
 L:     lm-sensors@lm-sensors.org
@@ -4999,6 +5012,17 @@ F:       drivers/i2c/busses/i2c-puv3.c
 F:     drivers/video/fb-puv3.c
 F:     drivers/rtc/rtc-puv3.c
 
+PMBUS HARDWARE MONITORING DRIVERS
+M:     Guenter Roeck <guenter.roeck@ericsson.com>
+L:     lm-sensors@lm-sensors.org
+W:     http://www.lm-sensors.org/
+W:     http://www.roeck-us.net/linux/drivers/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
+S:     Maintained
+F:     Documentation/hwmon/pmbus
+F:     drivers/hwmon/pmbus/
+F:     include/linux/i2c/pmbus.h
+
 PMC SIERRA MaxRAID DRIVER
 M:     Anil Ravindranath <anil_ravindranath@pmc-sierra.com>
 L:     linux-scsi@vger.kernel.org
@@ -6408,7 +6432,7 @@ L:        tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for users in English)
 L:     tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
 L:     tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
 W:     http://tomoyo.sourceforge.jp/
-T:     quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.3.x/tomoyo-lsm/patches/
+T:     quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.4.x/tomoyo-lsm/patches/
 S:     Maintained
 F:     security/tomoyo/
 
index d0189560613cd715b70674540fb2b824d1f5c9eb..f676d15cd34839fc9232a0479753aff457dab7ae 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -360,7 +360,7 @@ CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
 LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include \
                    -Iarch/$(hdr-arch)/include/generated -Iinclude \
                    $(if $(KBUILD_SRC), -I$(srctree)/include) \
-                   -include include/generated/autoconf.h
+                   -include $(srctree)/include/linux/kconfig.h
 
 KBUILD_CPPFLAGS := -D__KERNEL__
 
index 0e1439904cdb7031c8036a5875ad5d71998a0bbb..8606d77e5163355e280c1f6ac7d040724cd69bc5 100644 (file)
@@ -183,7 +183,7 @@ alcor_init_irq(void)
  */
 
 static int __init
-alcor_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+alcor_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[7][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index c8c112d5158485013b148effc52d6905a8da164c..1029619fb6c0770de71da08028004805135aa7fc 100644 (file)
@@ -175,7 +175,7 @@ pc164_init_irq(void)
  */
 
 static inline int __init
-eb66p_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+eb66p_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[5][5] __initdata = {
                /*INT  INTA  INTB  INTC   INTD */
@@ -205,7 +205,7 @@ eb66p_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
  */
 
 static inline int __init
-cabriolet_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+cabriolet_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[5][5] __initdata = {
                /*INT   INTA  INTB  INTC   INTD */
@@ -289,7 +289,7 @@ cia_cab_init_pci(void)
  */
 
 static inline int __init
-alphapc164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+alphapc164_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[7][5] __initdata = {
                /*INT   INTA  INTB   INTC   INTD */
index f8856829c22a96bdff7ce25eab5a4c012c07cae9..bb7f0c7cb17a6c1abd5cdb07c30d080a4b30d9ff 100644 (file)
@@ -382,7 +382,7 @@ isa_irq_fixup(struct pci_dev *dev, int irq)
 }
 
 static int __init
-dp264_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+dp264_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[6][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
@@ -404,7 +404,7 @@ dp264_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 static int __init
-monet_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+monet_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[13][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
@@ -466,7 +466,7 @@ monet_swizzle(struct pci_dev *dev, u8 *pinp)
 }
 
 static int __init
-webbrick_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+webbrick_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[13][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
@@ -488,7 +488,7 @@ webbrick_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 static int __init
-clipper_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+clipper_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[7][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index a7a23b40eec53f9319e4502c30d7b99557d71a72..3c6c13cd8b19ff39b395ee02dda443a593a97d47 100644 (file)
@@ -169,7 +169,7 @@ eb64p_init_irq(void)
  */
 
 static int __init
-eb64p_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+eb64p_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[5][5] __initdata = {
                /*INT  INTA  INTB  INTC   INTD */
index a60cd5b2621eb4650041b45db5d907a78049c6a7..35f480db7719605eb8743b9ce467231846c46948 100644 (file)
@@ -144,7 +144,7 @@ eiger_init_irq(void)
 }
 
 static int __init
-eiger_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+eiger_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        u8 irq_orig;
 
index 388b99d1779d5e21a41bbc77860fe6fd5cae8baf..95cfc83ece8f7e771fc62f6567d1a2d0f948fffc 100644 (file)
@@ -318,7 +318,7 @@ marvel_init_irq(void)
 }
 
 static int 
-marvel_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+marvel_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct pci_controller *hose = dev->sysdata;
        struct io7_port *io7_port = hose->sysdata;
index 61ccd95579ecdbde1799d62c7d1c7b3ee515ba24..258da684670b34bba8fbec093e365d38e2cf45b3 100644 (file)
@@ -151,7 +151,7 @@ miata_init_irq(void)
  */
 
 static int __init
-miata_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+miata_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
         static char irq_tab[18][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index 0e6e4697a02590c02b4789b58cc2d7c3a120f589..c0fd7284dec318beba90ece97475de61ba48860e 100644 (file)
@@ -146,7 +146,7 @@ mikasa_init_irq(void)
  */
 
 static int __init
-mikasa_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+mikasa_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[8][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index 99c0f46f6b9cc75007499c10f4fb84f8a2c6d1ee..4112200307c73eac73f6bff9ccf10a534b1c16b6 100644 (file)
@@ -65,7 +65,7 @@ nautilus_init_irq(void)
 }
 
 static int __init
-nautilus_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+nautilus_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        /* Preserve the IRQ set up by the console.  */
 
index a00ac7087167a88d39f54aa41e47747f11752d28..21725283cdd7dac5847c25ae7ec07c115afd3c69 100644 (file)
@@ -194,7 +194,7 @@ noritake_init_irq(void)
  */
 
 static int __init
-noritake_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+noritake_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[15][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index 7f52161f3d88996a3eacaaeb1c9c3c9d29a398dc..a125d6bea7e1d97a665f6db6c337109f560d7730 100644 (file)
@@ -223,7 +223,7 @@ rawhide_init_irq(void)
  */
 
 static int __init
-rawhide_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+rawhide_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[5][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index f33648e4e8cf1a69e2845266cab8c372638db0ed..2581cbec6fc21bce1625677a5e58fd52a2db4287 100644 (file)
@@ -119,7 +119,7 @@ ruffian_kill_arch (int mode)
  */
 
 static int __init
-ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+ruffian_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
         static char irq_tab[11][5] __initdata = {
              /*INT  INTA INTB INTC INTD */
index 216d94d9c0c12e2aac9ab92de50c895cdf64b32e..b172b27555a768006b6b3151bec8c923ba4d2cb3 100644 (file)
@@ -144,7 +144,7 @@ rx164_init_irq(void)
  */
 
 static int __init
-rx164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+rx164_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
 #if 0
        static char irq_tab_pass1[6][5] __initdata = {
index da714e427c5fcc383a420d41812ed991c67316a1..98d1dbffe98f546667c55587e19145dc31de4c63 100644 (file)
@@ -194,7 +194,7 @@ sable_init_irq(void)
  */
 
 static int __init
-sable_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+sable_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[9][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
@@ -376,7 +376,7 @@ lynx_init_irq(void)
  */
 
 static int __init
-lynx_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+lynx_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[19][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index 85b4aea01ef8bcfee02fdcae4ddd9bd44d0cc91d..47bec1e97d1ca9e0cbdbb4bde0c75cb9d3e06dcf 100644 (file)
@@ -146,7 +146,7 @@ sio_fixup_irq_levels(unsigned int level_bits)
 }
 
 static inline int __init
-noname_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+noname_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        /*
         * The Noname board has 5 PCI slots with each of the 4
@@ -185,7 +185,7 @@ noname_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 static inline int __init
-p2k_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+p2k_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[][5] __initdata = {
                /*INT A   B   C   D */
index 41d4ad4c7c444b292dd485206fa92bee5d1267e8..73e1c317afcb4f86870a4a8ab026dd09ad61ec8c 100644 (file)
@@ -95,7 +95,7 @@ sx164_init_irq(void)
  */
 
 static int __init
-sx164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+sx164_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[5][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index a31f8cd9bd6bbde4a3e691bdff3eb52100d0c144..2ae99ad6975e270513eabfd07f024d6b5f818b86 100644 (file)
@@ -157,7 +157,7 @@ takara_init_irq(void)
  */
 
 static int __init
-takara_map_irq_srm(struct pci_dev *dev, u8 slot, u8 pin)
+takara_map_irq_srm(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[15][5] __initdata = {
                { 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot  6 == device 3 */
@@ -188,7 +188,7 @@ takara_map_irq_srm(struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 static int __init
-takara_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+takara_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[15][5] __initdata = {
                { 16+3, 16+3, 16+3, 16+3, 16+3},   /* slot  6 == device 3 */
index 6994407e242aec27f243f08860c247b1162ddf70..f47b30a2a117036db3cd877db99fcc72ca26203d 100644 (file)
@@ -305,7 +305,7 @@ titan_late_init(void)
 }
 
 static int __devinit
-titan_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+titan_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        u8 intline;
        int irq;
index d92cdc715c6530150563259e6fbc4c859f3e1d9f..17c85a65e7b0307e5741d0c395ac392719773a80 100644 (file)
@@ -290,7 +290,7 @@ wildfire_device_interrupt(unsigned long vector)
  */
 
 static int __init
-wildfire_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+wildfire_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static char irq_tab[8][5] __initdata = {
                /*INT    INTA   INTB   INTC   INTD */
index 09ebf0ba64fa5699a5703c6677ebb5e0fd26cb5a..2c71a8f3535a1400c2d187e7fa612e00995e6927 100644 (file)
@@ -1716,6 +1716,7 @@ config USE_OF
        bool "Flattened Device Tree support"
        select OF
        select OF_EARLY_FLATTREE
+       select IRQ_DOMAIN
        help
          Include support for flattened device tree machine descriptions.
 
index 3a4a04b33d0f7761ca4963e28bac99ff64960238..70c424eaf7b0d84db6af6431279a835ba71094c2 100644 (file)
@@ -282,6 +282,12 @@ zImage Image xipImage bootpImage uImage: vmlinux
 zinstall uinstall install: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
 
+%.dtb:
+       $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+
+dtbs:
+       $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
@@ -298,6 +304,7 @@ define archhelp
   echo  '  uImage        - U-Boot wrapped zImage'
   echo  '  bootpImage    - Combined zImage and initial RAM disk' 
   echo  '                  (supply initrd image via make variable INITRD=<path>)'
+  echo  '  dtbs          - Build device tree blobs for enabled boards'
   echo  '  install       - Install uncompressed kernel'
   echo  '  zinstall      - Install compressed kernel'
   echo  '  uinstall      - Install U-Boot wrapped compressed kernel'
index 9128fddf110965eb76cd73fefbeb07d5570bf0a4..a1edfd5a129a653ba847b5fb310a88bacfecfc1d 100644 (file)
@@ -59,6 +59,12 @@ $(obj)/zImage:       $(obj)/compressed/vmlinux FORCE
 
 endif
 
+# Rule to build device tree blobs
+$(obj)/%.dtb: $(src)/dts/%.dts
+       $(call cmd,dtc)
+
+$(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y))
+
 quiet_cmd_uimage = UIMAGE  $@
       cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
                   -C none -a $(LOADADDR) -e $(STARTADDR) \
diff --git a/arch/arm/boot/dts/skeleton.dtsi b/arch/arm/boot/dts/skeleton.dtsi
new file mode 100644 (file)
index 0000000..b41d241
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Skeleton device tree; the bare minimum needed to boot; just include and
+ * add a compatible value.  The bootloader will typically populate the memory
+ * node.
+ */
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       chosen { };
+       aliases { };
+       memory { device_type = "memory"; reg = <0 0>; };
+};
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts
new file mode 100644 (file)
index 0000000..4c05334
--- /dev/null
@@ -0,0 +1,70 @@
+/dts-v1/;
+
+/memreserve/ 0x1c000000 0x04000000;
+/include/ "tegra20.dtsi"
+
+/ {
+       model = "NVIDIA Tegra2 Harmony evaluation board";
+       compatible = "nvidia,harmony", "nvidia,tegra20";
+
+       chosen {
+               bootargs = "vmalloc=192M video=tegrafb console=ttyS0,115200n8 root=/dev/mmcblk0p2 rw rootwait";
+       };
+
+       memory@0 {
+               reg = < 0x00000000 0x40000000 >;
+       };
+
+       i2c@7000c000 {
+               clock-frequency = <400000>;
+
+               codec: wm8903@1a {
+                       compatible = "wlf,wm8903";
+                       reg = <0x1a>;
+                       interrupts = < 347 >;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       /* 0x8000 = Not configured */
+                       gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;
+               };
+       };
+
+       i2c@7000c400 {
+               clock-frequency = <400000>;
+       };
+
+       i2c@7000c500 {
+               clock-frequency = <400000>;
+       };
+
+       i2c@7000d000 {
+               clock-frequency = <400000>;
+       };
+
+       sound {
+               compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903";
+
+               spkr-en-gpios = <&codec 2 0>;
+               hp-det-gpios = <&gpio 178 0>;
+               int-mic-en-gpios = <&gpio 184 0>;
+               ext-mic-en-gpios = <&gpio 185 0>;
+       };
+
+       serial@70006300 {
+               clock-frequency = < 216000000 >;
+       };
+
+       sdhci@c8000200 {
+               gpios = <&gpio 69 0>, /* cd, gpio PI5 */
+                       <&gpio 57 0>, /* wp, gpio PH1 */
+                       <&gpio 155 0>; /* power, gpio PT3 */
+       };
+
+       sdhci@c8000600 {
+               gpios = <&gpio 58 0>, /* cd, gpio PH2 */
+                       <&gpio 59 0>, /* wp, gpio PH3 */
+                       <&gpio 70 0>; /* power, gpio PI6 */
+       };
+};
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts
new file mode 100644 (file)
index 0000000..1940cae
--- /dev/null
@@ -0,0 +1,28 @@
+/dts-v1/;
+
+/memreserve/ 0x1c000000 0x04000000;
+/include/ "tegra20.dtsi"
+
+/ {
+       model = "NVIDIA Seaboard";
+       compatible = "nvidia,seaboard", "nvidia,tegra20";
+
+       chosen {
+               bootargs = "vmalloc=192M video=tegrafb console=ttyS0,115200n8 root=/dev/mmcblk1p3 rw rootwait";
+       };
+
+       memory {
+               device_type = "memory";
+               reg = < 0x00000000 0x40000000 >;
+       };
+
+       serial@70006300 {
+               clock-frequency = < 216000000 >;
+       };
+
+       sdhci@c8000400 {
+               gpios = <&gpio 69 0>, /* cd, gpio PI5 */
+                       <&gpio 57 0>, /* wp, gpio PH1 */
+                       <&gpio 70 0>; /* power, gpio PI6 */
+       };
+};
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
new file mode 100644 (file)
index 0000000..5727595
--- /dev/null
@@ -0,0 +1,139 @@
+/include/ "skeleton.dtsi"
+
+/ {
+       compatible = "nvidia,tegra20";
+       interrupt-parent = <&intc>;
+
+       intc: interrupt-controller@50041000 {
+               compatible = "nvidia,tegra20-gic";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = < 0x50041000 0x1000 >,
+                     < 0x50040100 0x0100 >;
+       };
+
+       i2c@7000c000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2c";
+               reg = <0x7000C000 0x100>;
+               interrupts = < 70 >;
+       };
+
+       i2c@7000c400 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2c";
+               reg = <0x7000C400 0x100>;
+               interrupts = < 116 >;
+       };
+
+       i2c@7000c500 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2c";
+               reg = <0x7000C500 0x100>;
+               interrupts = < 124 >;
+       };
+
+       i2c@7000d000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2c";
+               reg = <0x7000D000 0x200>;
+               interrupts = < 85 >;
+       };
+
+       i2s@70002800 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2s";
+               reg = <0x70002800 0x200>;
+               interrupts = < 45 >;
+               dma-channel = < 2 >;
+       };
+
+       i2s@70002a00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-i2s";
+               reg = <0x70002a00 0x200>;
+               interrupts = < 35 >;
+               dma-channel = < 1 >;
+       };
+
+       das@70000c00 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-das";
+               reg = <0x70000c00 0x80>;
+       };
+
+       gpio: gpio@6000d000 {
+               compatible = "nvidia,tegra20-gpio";
+               reg = < 0x6000d000 0x1000 >;
+               interrupts = < 64 65 66 67 87 119 121 >;
+               #gpio-cells = <2>;
+               gpio-controller;
+       };
+
+       serial@70006000 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006000 0x40>;
+               reg-shift = <2>;
+               interrupts = < 68 >;
+       };
+
+       serial@70006040 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006040 0x40>;
+               reg-shift = <2>;
+               interrupts = < 69 >;
+       };
+
+       serial@70006200 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006200 0x100>;
+               reg-shift = <2>;
+               interrupts = < 78 >;
+       };
+
+       serial@70006300 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006300 0x100>;
+               reg-shift = <2>;
+               interrupts = < 122 >;
+       };
+
+       serial@70006400 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006400 0x100>;
+               reg-shift = <2>;
+               interrupts = < 123 >;
+       };
+
+       sdhci@c8000000 {
+               compatible = "nvidia,tegra20-sdhci";
+               reg = <0xc8000000 0x200>;
+               interrupts = < 46 >;
+       };
+
+       sdhci@c8000200 {
+               compatible = "nvidia,tegra20-sdhci";
+               reg = <0xc8000200 0x200>;
+               interrupts = < 47 >;
+       };
+
+       sdhci@c8000400 {
+               compatible = "nvidia,tegra20-sdhci";
+               reg = <0xc8000400 0x200>;
+               interrupts = < 51 >;
+       };
+
+       sdhci@c8000600 {
+               compatible = "nvidia,tegra20-sdhci";
+               reg = <0xc8000600 0x200>;
+               interrupts = < 63 >;
+       };
+};
+
diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts
new file mode 100644 (file)
index 0000000..0b32925
--- /dev/null
@@ -0,0 +1,192 @@
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+       model = "ARM Versatile AB";
+       compatible = "arm,versatile-ab";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&vic>;
+
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart1;
+               serial2 = &uart2;
+               i2c0 = &i2c0;
+       };
+
+       memory {
+               reg = <0x0 0x08000000>;
+       };
+
+       flash@34000000 {
+               compatible = "arm,versatile-flash";
+               reg = <0x34000000 0x4000000>;
+               bank-width = <4>;
+       };
+
+       i2c0: i2c@10002000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "arm,versatile-i2c";
+               reg = <0x10002000 0x1000>;
+
+               rtc@68 {
+                       compatible = "dallas,ds1338";
+                       reg = <0x68>;
+               };
+       };
+
+       net@10010000 {
+               compatible = "smsc,lan91c111";
+               reg = <0x10010000 0x10000>;
+               interrupts = <25>;
+       };
+
+       lcd@10008000 {
+               compatible = "arm,versatile-lcd";
+               reg = <0x10008000 0x1000>;
+       };
+
+       amba {
+               compatible = "arm,amba-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               vic: intc@10140000 {
+                       compatible = "arm,versatile-vic";
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       reg = <0x10140000 0x1000>;
+               };
+
+               sic: intc@10003000 {
+                       compatible = "arm,versatile-sic";
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       reg = <0x10003000 0x1000>;
+                       interrupt-parent = <&vic>;
+                       interrupts = <31>; /* Cascaded to vic */
+               };
+
+               dma@10130000 {
+                       compatible = "arm,pl081", "arm,primecell";
+                       reg = <0x10130000 0x1000>;
+                       interrupts = <17>;
+               };
+
+               uart0: uart@101f1000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x101f1000 0x1000>;
+                       interrupts = <12>;
+               };
+
+               uart1: uart@101f2000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x101f2000 0x1000>;
+                       interrupts = <13>;
+               };
+
+               uart2: uart@101f3000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x101f3000 0x1000>;
+                       interrupts = <14>;
+               };
+
+               smc@10100000 {
+                       compatible = "arm,primecell";
+                       reg = <0x10100000 0x1000>;
+               };
+
+               mpmc@10110000 {
+                       compatible = "arm,primecell";
+                       reg = <0x10110000 0x1000>;
+               };
+
+               display@10120000 {
+                       compatible = "arm,pl110", "arm,primecell";
+                       reg = <0x10120000 0x1000>;
+                       interrupts = <16>;
+               };
+
+               sctl@101e0000 {
+                       compatible = "arm,primecell";
+                       reg = <0x101e0000 0x1000>;
+               };
+
+               watchdog@101e1000 {
+                       compatible = "arm,primecell";
+                       reg = <0x101e1000 0x1000>;
+                       interrupts = <0>;
+               };
+
+               gpio0: gpio@101e4000 {
+                       compatible = "arm,pl061", "arm,primecell";
+                       reg = <0x101e4000 0x1000>;
+                       gpio-controller;
+                       interrupts = <6>;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio1: gpio@101e5000 {
+                       compatible = "arm,pl061", "arm,primecell";
+                       reg = <0x101e5000 0x1000>;
+                       interrupts = <7>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               rtc@101e8000 {
+                       compatible = "arm,pl030", "arm,primecell";
+                       reg = <0x101e8000 0x1000>;
+                       interrupts = <10>;
+               };
+
+               sci@101f0000 {
+                       compatible = "arm,primecell";
+                       reg = <0x101f0000 0x1000>;
+                       interrupts = <15>;
+               };
+
+               ssp@101f4000 {
+                       compatible = "arm,pl022", "arm,primecell";
+                       reg = <0x101f4000 0x1000>;
+                       interrupts = <11>;
+               };
+
+               fpga {
+                       compatible = "arm,versatile-fpga", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0 0x10000000 0x10000>;
+
+                       aaci@4000 {
+                               compatible = "arm,primecell";
+                               reg = <0x4000 0x1000>;
+                               interrupts = <24>;
+                       };
+                       mmc@5000 {
+                               compatible = "arm,primecell";
+                               reg = < 0x5000 0x1000>;
+                               interrupts = <22>;
+                       };
+                       kmi@6000 {
+                               compatible = "arm,pl050", "arm,primecell";
+                               reg = <0x6000 0x1000>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <3>;
+                       };
+                       kmi@7000 {
+                               compatible = "arm,pl050", "arm,primecell";
+                               reg = <0x7000 0x1000>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <4>;
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts
new file mode 100644 (file)
index 0000000..8a614e3
--- /dev/null
@@ -0,0 +1,48 @@
+/include/ "versatile-ab.dts"
+
+/ {
+       model = "ARM Versatile PB";
+       compatible = "arm,versatile-pb";
+
+       amba {
+               gpio2: gpio@101e6000 {
+                       compatible = "arm,pl061", "arm,primecell";
+                       reg = <0x101e6000 0x1000>;
+                       interrupts = <8>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               gpio3: gpio@101e7000 {
+                       compatible = "arm,pl061", "arm,primecell";
+                       reg = <0x101e7000 0x1000>;
+                       interrupts = <9>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               fpga {
+                       uart@9000 {
+                               compatible = "arm,pl011", "arm,primecell";
+                               reg = <0x9000 0x1000>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <6>;
+                       };
+                       sci@a000 {
+                               compatible = "arm,primecell";
+                               reg = <0xa000 0x1000>;
+                               interrupt-parent = <&sic>;
+                               interrupts = <5>;
+                       };
+                       mmc@b000 {
+                               compatible = "arm,primecell";
+                               reg = <0xb000 0x1000>;
+                               interrupts = <23>;
+                       };
+               };
+       };
+};
index 14ad62e16dd1f1de122ceb83e5b16a96d69cf1b6..a7934ba9e1dfcc89ce97812d8b361b5375e1cc43 100644 (file)
@@ -144,7 +144,7 @@ void it8152_irq_demux(unsigned int irq, struct irq_desc *desc)
 }
 
 /* mapping for on-chip devices */
-int __init it8152_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int __init it8152_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if ((dev->vendor == PCI_VENDOR_ID_ITE) &&
            (dev->device == PCI_DEVICE_ID_ITE_8152)) {
index b2f95c72287c861dc03c09e110242982bb51a5c5..b3fea38d55c6ca49d145d8e4723183707629c9a8 100644 (file)
@@ -105,7 +105,7 @@ struct pci_sys_data;
 
 extern void it8152_irq_demux(unsigned int irq, struct irq_desc *desc);
 extern void it8152_init_irq(void);
-extern int it8152_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
+extern int it8152_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 extern int it8152_pci_setup(int nr, struct pci_sys_data *sys);
 extern struct pci_bus *it8152_pci_scan_bus(int nr, struct pci_sys_data *sys);
 
index 3281fb4b12e3342a6dd45af7c17bcf5d16aec4fe..217aa1911dd7a01641a8d9e85220c2128d263b0b 100644 (file)
@@ -74,4 +74,11 @@ static const struct machine_desc __mach_desc_##_type \
 #define MACHINE_END                            \
 };
 
+#define DT_MACHINE_START(_name, _namestr)              \
+static const struct machine_desc __mach_desc_##_name   \
+ __used                                                        \
+ __attribute__((__section__(".arch.info.init"))) = {   \
+       .nr             = ~0,                           \
+       .name           = _namestr,
+
 #endif
index 16330bd0657cb172f5ff2d736ceb78c22dbdc23b..186efd4e05c9975253a6a5b1d95ef4fb1718ace4 100644 (file)
@@ -25,7 +25,7 @@ struct hw_pci {
        void            (*preinit)(void);
        void            (*postinit)(void);
        u8              (*swizzle)(struct pci_dev *dev, u8 *pin);
-       int             (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin);
+       int             (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
 };
 
 /*
@@ -44,7 +44,7 @@ struct pci_sys_data {
                                        /* Bridge swizzling                     */
        u8              (*swizzle)(struct pci_dev *, u8 *);
                                        /* IRQ mapping                          */
-       int             (*map_irq)(struct pci_dev *, u8, u8);
+       int             (*map_irq)(const struct pci_dev *, u8, u8);
        struct hw_pci   *hw;
        void            *private_data;  /* platform controller private data     */
 };
index 11b8708fc4dbb0eaa0a07ffc5c983af8d5576adb..6f65ca86a5ec03347ea3305874437120680f77e1 100644 (file)
 #include <asm/setup.h>
 #include <asm/irq.h>
 
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-       return;
-}
-
 extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
 extern void arm_dt_memblock_reserve(void);
 
index e4ee050aad7db0981a9f0fd47d69bf7a7d4fe5fc..d6df359408f096f84c408740e5fef895a0d05a78 100644 (file)
@@ -476,7 +476,7 @@ static u8 __devinit pcibios_swizzle(struct pci_dev *dev, u8 *pin)
 /*
  * Map a slot/pin to an IRQ.
  */
-static int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct pci_sys_data *sys = dev->sysdata;
        int irq = -1;
index 0cdd7b456cb2a072ce3902f2a6d7934967b083d7..1a33e9d6bb1fbfb083b602e74f0a4b5f0da7cded 100644 (file)
@@ -132,17 +132,3 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
 
        return mdesc_best;
 }
-
-/**
- * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
- *
- * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
- * mapped 1:1 onto Linux irq numbers.  Cascaded irq controllers are not
- * supported.
- */
-unsigned int irq_create_of_mapping(struct device_node *controller,
-                                  const u32 *intspec, unsigned int intsize)
-{
-       return intspec[0];
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
index 96966231920cb5af2b18a15677ef14494b2e39dd..bf57e8b1c9d0b513e604ed356d391a095cbbf10e 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel.
 #
 
-obj-y          := irq.o gpio.o
+obj-y          := irq.o gpio.o setup.o
 obj-m          :=
 obj-n          :=
 obj-           :=
index f1013d08bb5738b7670264841b6e8723c4c64f70..bfc684441ef8db534154c15e05ac3f08de50ada7 100644 (file)
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91cap9_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91CAP9_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT91CAP9_SRAM_BASE),
-               .length         = AT91CAP9_SRAM_SIZE,
-               .type           = MT_DEVICE,
-       },
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -339,24 +326,17 @@ static void at91cap9_poweroff(void)
  *  AT91CAP9 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91cap9_map_io(void)
+static void __init at91cap9_map_io(void)
 {
-       /* Map peripherals */
-       iotable_init(at91cap9_io_desc, ARRAY_SIZE(at91cap9_io_desc));
+       at91_init_sram(0, AT91CAP9_SRAM_BASE, AT91CAP9_SRAM_SIZE);
 }
 
-void __init at91cap9_initialize(unsigned long main_clock)
+static void __init at91cap9_initialize(void)
 {
        at91_arch_reset = at91cap9_reset;
        pm_power_off = at91cap9_poweroff;
        at91_extern_irq = (1 << AT91CAP9_ID_IRQ0) | (1 << AT91CAP9_ID_IRQ1);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91cap9_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91cap9_gpio, 4);
 
@@ -409,14 +389,9 @@ static unsigned int at91cap9_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller (IRQ1) */
 };
 
-void __init at91cap9_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91cap9_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91cap9_soc = {
+       .map_io = at91cap9_map_io,
+       .default_irq_priority = at91cap9_default_irq_priority,
+       .register_clocks = at91cap9_register_clocks,
+       .init = at91cap9_initialize,
+};
index 83a1a3fee5549be3f7cb92a8bb50335e9150509e..f73302dbc6a547272624bee244224aa2fa06e520 100644 (file)
 #include <mach/at91_st.h>
 #include <mach/cpu.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
 static struct map_desc at91rm9200_io_desc[] __initdata = {
        {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
                .virtual        = AT91_VA_BASE_EMAC,
                .pfn            = __phys_to_pfn(AT91RM9200_BASE_EMAC),
                .length         = SZ_16K,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT91RM9200_SRAM_BASE),
-               .length         = AT91RM9200_SRAM_SIZE,
-               .type           = MT_DEVICE,
        },
 };
 
@@ -304,24 +295,17 @@ static void at91rm9200_reset(void)
        at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
-int rm9200_type;
-EXPORT_SYMBOL(rm9200_type);
-
-void __init at91rm9200_set_type(int type)
-{
-       rm9200_type = type;
-}
-
 /* --------------------------------------------------------------------
  *  AT91RM9200 processor initialization
  * -------------------------------------------------------------------- */
-void __init at91rm9200_map_io(void)
+static void __init at91rm9200_map_io(void)
 {
        /* Map peripherals */
+       at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE);
        iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
 }
 
-void __init at91rm9200_initialize(unsigned long main_clock)
+static void __init at91rm9200_initialize(void)
 {
        at91_arch_reset = at91rm9200_reset;
        at91_extern_irq = (1 << AT91RM9200_ID_IRQ0) | (1 << AT91RM9200_ID_IRQ1)
@@ -329,12 +313,6 @@ void __init at91rm9200_initialize(unsigned long main_clock)
                        | (1 << AT91RM9200_ID_IRQ4) | (1 << AT91RM9200_ID_IRQ5)
                        | (1 << AT91RM9200_ID_IRQ6);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91rm9200_register_clocks();
-
        /* Initialize GPIO subsystem */
        at91_gpio_init(at91rm9200_gpio,
                cpu_is_at91rm9200_bga() ? AT91RM9200_BGA : AT91RM9200_PQFP);
@@ -383,14 +361,9 @@ static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0       /* Advanced Interrupt Controller (IRQ6) */
 };
 
-void __init at91rm9200_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91rm9200_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91rm9200_soc = {
+       .map_io = at91rm9200_map_io,
+       .default_irq_priority = at91rm9200_default_irq_priority,
+       .register_clocks = at91rm9200_register_clocks,
+       .init = at91rm9200_initialize,
+};
index 7d606b04d313c5800359849ddff022a827655d87..cb397be14448eaa767ddbfd94bdf4fbdf8c25254 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <mach/cpu.h>
+#include <mach/at91_dbgu.h>
 #include <mach/at91sam9260.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91sam9260_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }
-};
-
-static struct map_desc at91sam9260_sram_desc[] __initdata = {
-       {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9260_SRAM0_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9260_SRAM0_BASE),
-               .length         = AT91SAM9260_SRAM0_SIZE,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9260_SRAM0_SIZE - AT91SAM9260_SRAM1_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9260_SRAM1_BASE),
-               .length         = AT91SAM9260_SRAM1_SIZE,
-               .type           = MT_DEVICE,
-       }
-};
-
-static struct map_desc at91sam9g20_sram_desc[] __initdata = {
-       {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9G20_SRAM0_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9G20_SRAM0_BASE),
-               .length         = AT91SAM9G20_SRAM0_SIZE,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9G20_SRAM0_SIZE - AT91SAM9G20_SRAM1_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9G20_SRAM1_BASE),
-               .length         = AT91SAM9G20_SRAM1_SIZE,
-               .type           = MT_DEVICE,
-       }
-};
-
-static struct map_desc at91sam9xe_sram_desc[] __initdata = {
-       {
-               .pfn            = __phys_to_pfn(AT91SAM9XE_SRAM_BASE),
-               .type           = MT_DEVICE,
-       }
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -330,11 +288,9 @@ static void at91sam9260_poweroff(void)
 
 static void __init at91sam9xe_map_io(void)
 {
-       unsigned long cidr, sram_size;
-
-       cidr = at91_sys_read(AT91_DBGU_CIDR);
+       unsigned long sram_size;
 
-       switch (cidr & AT91_CIDR_SRAMSIZ) {
+       switch (at91_soc_initdata.cidr & AT91_CIDR_SRAMSIZ) {
                case AT91_CIDR_SRAMSIZ_32K:
                        sram_size = 2 * SZ_16K;
                        break;
@@ -343,38 +299,29 @@ static void __init at91sam9xe_map_io(void)
                        sram_size = SZ_16K;
        }
 
-       at91sam9xe_sram_desc->virtual = AT91_IO_VIRT_BASE - sram_size;
-       at91sam9xe_sram_desc->length = sram_size;
-
-       iotable_init(at91sam9xe_sram_desc, ARRAY_SIZE(at91sam9xe_sram_desc));
+       at91_init_sram(0, AT91SAM9XE_SRAM_BASE, sram_size);
 }
 
-void __init at91sam9260_map_io(void)
+static void __init at91sam9260_map_io(void)
 {
-       /* Map peripherals */
-       iotable_init(at91sam9260_io_desc, ARRAY_SIZE(at91sam9260_io_desc));
-
-       if (cpu_is_at91sam9xe())
+       if (cpu_is_at91sam9xe()) {
                at91sam9xe_map_io();
-       else if (cpu_is_at91sam9g20())
-               iotable_init(at91sam9g20_sram_desc, ARRAY_SIZE(at91sam9g20_sram_desc));
-       else
-               iotable_init(at91sam9260_sram_desc, ARRAY_SIZE(at91sam9260_sram_desc));
+       } else if (cpu_is_at91sam9g20()) {
+               at91_init_sram(0, AT91SAM9G20_SRAM0_BASE, AT91SAM9G20_SRAM0_SIZE);
+               at91_init_sram(1, AT91SAM9G20_SRAM1_BASE, AT91SAM9G20_SRAM1_SIZE);
+       } else {
+               at91_init_sram(0, AT91SAM9260_SRAM0_BASE, AT91SAM9260_SRAM0_SIZE);
+               at91_init_sram(1, AT91SAM9260_SRAM1_BASE, AT91SAM9260_SRAM1_SIZE);
+       }
 }
 
-void __init at91sam9260_initialize(unsigned long main_clock)
+static void __init at91sam9260_initialize(void)
 {
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9260_poweroff;
        at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
                        | (1 << AT91SAM9260_ID_IRQ2);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91sam9260_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91sam9260_gpio, 3);
 }
@@ -421,14 +368,9 @@ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
-void __init at91sam9260_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91sam9260_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91sam9260_soc = {
+       .map_io = at91sam9260_map_io,
+       .default_irq_priority = at91sam9260_default_irq_priority,
+       .register_clocks = at91sam9260_register_clocks,
+       .init = at91sam9260_initialize,
+};
index c1483168c97a523569ff04676cf7f964e7282313..d522b47e30b5a82322da83f6fed63d7d110dab5a 100644 (file)
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91sam9261_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc at91sam9261_sram_desc[] __initdata = {
-       {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9261_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9261_SRAM_BASE),
-               .length         = AT91SAM9261_SRAM_SIZE,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc at91sam9g10_sram_desc[] __initdata = {
-       {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9G10_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9G10_SRAM_BASE),
-               .length         = AT91SAM9G10_SRAM_SIZE,
-               .type           = MT_DEVICE,
-       },
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -302,30 +276,21 @@ static void at91sam9261_poweroff(void)
  *  AT91SAM9261 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9261_map_io(void)
+static void __init at91sam9261_map_io(void)
 {
-       /* Map peripherals */
-       iotable_init(at91sam9261_io_desc, ARRAY_SIZE(at91sam9261_io_desc));
-
        if (cpu_is_at91sam9g10())
-               iotable_init(at91sam9g10_sram_desc, ARRAY_SIZE(at91sam9g10_sram_desc));
+               at91_init_sram(0, AT91SAM9G10_SRAM_BASE, AT91SAM9G10_SRAM_SIZE);
        else
-               iotable_init(at91sam9261_sram_desc, ARRAY_SIZE(at91sam9261_sram_desc));
+               at91_init_sram(0, AT91SAM9261_SRAM_BASE, AT91SAM9261_SRAM_SIZE);
 }
 
-void __init at91sam9261_initialize(unsigned long main_clock)
+static void __init at91sam9261_initialize(void)
 {
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9261_poweroff;
        at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
                        | (1 << AT91SAM9261_ID_IRQ2);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91sam9261_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91sam9261_gpio, 3);
 }
@@ -372,14 +337,9 @@ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
-void __init at91sam9261_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91sam9261_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91sam9261_soc = {
+       .map_io = at91sam9261_map_io,
+       .default_irq_priority = at91sam9261_default_irq_priority,
+       .register_clocks = at91sam9261_register_clocks,
+       .init = at91sam9261_initialize,
+};
index dc28477d14ffa158e0e0ae8031815ada848b9c51..044f3c927e64723e6ef8f6733ef90b386ebaecb7 100644 (file)
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91sam9263_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9263_SRAM0_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9263_SRAM0_BASE),
-               .length         = AT91SAM9263_SRAM0_SIZE,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9263_SRAM0_SIZE - AT91SAM9263_SRAM1_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9263_SRAM1_BASE),
-               .length         = AT91SAM9263_SRAM1_SIZE,
-               .type           = MT_DEVICE,
-       },
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -313,24 +295,18 @@ static void at91sam9263_poweroff(void)
  *  AT91SAM9263 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9263_map_io(void)
+static void __init at91sam9263_map_io(void)
 {
-       /* Map peripherals */
-       iotable_init(at91sam9263_io_desc, ARRAY_SIZE(at91sam9263_io_desc));
+       at91_init_sram(0, AT91SAM9263_SRAM0_BASE, AT91SAM9263_SRAM0_SIZE);
+       at91_init_sram(1, AT91SAM9263_SRAM1_BASE, AT91SAM9263_SRAM1_SIZE);
 }
 
-void __init at91sam9263_initialize(unsigned long main_clock)
+static void __init at91sam9263_initialize(void)
 {
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9263_poweroff;
        at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91sam9263_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91sam9263_gpio, 5);
 }
@@ -377,14 +353,9 @@ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller (IRQ1) */
 };
 
-void __init at91sam9263_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91sam9263_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91sam9263_soc = {
+       .map_io = at91sam9263_map_io,
+       .default_irq_priority = at91sam9263_default_irq_priority,
+       .register_clocks = at91sam9263_register_clocks,
+       .init = at91sam9263_initialize,
+};
index 11e214121b23cd45d413f2b19273b61ce039f940..e04c5fb6f1ee36bd4e652dc3640f776fd31a9bf4 100644 (file)
 #include <mach/at91_shdwc.h>
 #include <mach/cpu.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91sam9g45_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT91SAM9G45_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT91SAM9G45_SRAM_BASE),
-               .length         = AT91SAM9G45_SRAM_SIZE,
-               .type           = MT_DEVICE,
-       }
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -329,24 +316,17 @@ static void at91sam9g45_poweroff(void)
  *  AT91SAM9G45 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9g45_map_io(void)
+static void __init at91sam9g45_map_io(void)
 {
-       /* Map peripherals */
-       iotable_init(at91sam9g45_io_desc, ARRAY_SIZE(at91sam9g45_io_desc));
+       at91_init_sram(0, AT91SAM9G45_SRAM_BASE, AT91SAM9G45_SRAM_SIZE);
 }
 
-void __init at91sam9g45_initialize(unsigned long main_clock)
+static void __init at91sam9g45_initialize(void)
 {
        at91_arch_reset = at91sam9g45_reset;
        pm_power_off = at91sam9g45_poweroff;
        at91_extern_irq = (1 << AT91SAM9G45_ID_IRQ0);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91sam9g45_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91sam9g45_gpio, 5);
 }
@@ -393,14 +373,9 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller (IRQ0) */
 };
 
-void __init at91sam9g45_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91sam9g45_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91sam9g45_soc = {
+       .map_io = at91sam9g45_map_io,
+       .default_irq_priority = at91sam9g45_default_irq_priority,
+       .register_clocks = at91sam9g45_register_clocks,
+       .init = at91sam9g45_initialize,
+};
index 29dff18ed1309bb7442e4078c5e01a60ff056134..a238105d2c11dabb385c7f8bbbcfa20be87b2982 100644 (file)
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <mach/cpu.h>
+#include <mach/at91_dbgu.h>
 #include <mach/at91sam9rl.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
 #include <mach/at91_shdwc.h>
 
+#include "soc.h"
 #include "generic.h"
 #include "clock.h"
 
-static struct map_desc at91sam9rl_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       },
-};
-
-static struct map_desc at91sam9rl_sram_desc[] __initdata = {
-       {
-               .pfn            = __phys_to_pfn(AT91SAM9RL_SRAM_BASE),
-               .type           = MT_DEVICE,
-       }
-};
-
 /* --------------------------------------------------------------------
  *  Clocks
  * -------------------------------------------------------------------- */
@@ -287,16 +273,11 @@ static void at91sam9rl_poweroff(void)
  *  AT91SAM9RL processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9rl_map_io(void)
+static void __init at91sam9rl_map_io(void)
 {
-       unsigned long cidr, sram_size;
-
-       /* Map peripherals */
-       iotable_init(at91sam9rl_io_desc, ARRAY_SIZE(at91sam9rl_io_desc));
-
-       cidr = at91_sys_read(AT91_DBGU_CIDR);
+       unsigned long sram_size;
 
-       switch (cidr & AT91_CIDR_SRAMSIZ) {
+       switch (at91_soc_initdata.cidr & AT91_CIDR_SRAMSIZ) {
                case AT91_CIDR_SRAMSIZ_32K:
                        sram_size = 2 * SZ_16K;
                        break;
@@ -305,25 +286,16 @@ void __init at91sam9rl_map_io(void)
                        sram_size = SZ_16K;
        }
 
-       at91sam9rl_sram_desc->virtual = AT91_IO_VIRT_BASE - sram_size;
-       at91sam9rl_sram_desc->length = sram_size;
-
        /* Map SRAM */
-       iotable_init(at91sam9rl_sram_desc, ARRAY_SIZE(at91sam9rl_sram_desc));
+       at91_init_sram(0, AT91SAM9RL_SRAM_BASE, sram_size);
 }
 
-void __init at91sam9rl_initialize(unsigned long main_clock)
+static void __init at91sam9rl_initialize(void)
 {
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9rl_poweroff;
        at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0);
 
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at91sam9rl_register_clocks();
-
        /* Register GPIO subsystem */
        at91_gpio_init(at91sam9rl_gpio, 4);
 }
@@ -370,14 +342,9 @@ static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
-void __init at91sam9rl_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at91sam9rl_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
+struct at91_init_soc __initdata at91sam9rl_soc = {
+       .map_io = at91sam9rl_map_io,
+       .default_irq_priority = at91sam9rl_default_irq_priority,
+       .register_clocks = at91sam9rl_register_clocks,
+       .init = at91sam9rl_initialize,
+};
index ab1d463aa47d4c3c72d6df44f590bec8a767d24e..5aa58851eb394b43c1c0f972465e766d5bab4a38 100644 (file)
@@ -46,7 +46,7 @@ static void __init onearm_init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -63,11 +63,6 @@ static void __init onearm_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init onearm_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata onearm_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -97,8 +92,8 @@ static void __init onearm_board_init(void)
 MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = onearm_init_early,
-       .init_irq       = onearm_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = onearm_board_init,
 MACHINE_END
index a4924de48c36300e0121371ef0435e1ff4a8e43d..b0c796d42e495bf1158da2d19fda3c8cb0bf90dc 100644 (file)
@@ -51,7 +51,7 @@
 static void __init afeb9260_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -70,12 +70,6 @@ static void __init afeb9260_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init afeb9260_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -219,9 +213,9 @@ static void __init afeb9260_board_init(void)
 MACHINE_START(AFEB9260, "Custom afeb9260 board")
        /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = afeb9260_init_early,
-       .init_irq       = afeb9260_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = afeb9260_board_init,
 MACHINE_END
 
index 148fccb9a25a4e9c5d10ec2740bd4e3a48195af0..d1abd5898e85bb53c8f48b9c703f393a9f86776c 100644 (file)
@@ -48,7 +48,7 @@
 static void __init cam60_init_early(void)
 {
        /* Initialize processor: 10 MHz crystal */
-       at91sam9260_initialize(10000000);
+       at91_initialize(10000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -57,12 +57,6 @@ static void __init cam60_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init cam60_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host
  */
@@ -199,8 +193,8 @@ static void __init cam60_board_init(void)
 MACHINE_START(CAM60, "KwikByte CAM60")
        /* Maintainer: KwikByte */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = cam60_init_early,
-       .init_irq       = cam60_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = cam60_board_init,
 MACHINE_END
index cdb65d483250f8b8acf5a91495a878710f716cec..679b0b743e9277d1e7994c314359f5db6a844603 100644 (file)
@@ -53,7 +53,7 @@
 static void __init cap9adk_init_early(void)
 {
        /* Initialize processor: 12 MHz crystal */
-       at91cap9_initialize(12000000);
+       at91_initialize(12000000);
 
        /* Setup the LEDs: USER1 and USER2 LED for cpu/timer... */
        at91_init_leds(AT91_PIN_PA10, AT91_PIN_PA11);
@@ -65,12 +65,6 @@ static void __init cap9adk_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init cap9adk_init_irq(void)
-{
-       at91cap9_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -397,8 +391,8 @@ static void __init cap9adk_board_init(void)
 MACHINE_START(AT91CAP9ADK, "Atmel AT91CAP9A-DK")
        /* Maintainer: Stelian Pop <stelian.pop@leadtechdesign.com> */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91cap9_map_io,
+       .map_io         = at91_map_io,
        .init_early     = cap9adk_init_early,
-       .init_irq       = cap9adk_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = cap9adk_board_init,
 MACHINE_END
index f36b18687494a5548ace1b4a534cee7cb284aa1d..c578c5d9072887334e3a4e354de5d80b0fa18c8d 100644 (file)
@@ -43,7 +43,7 @@
 static void __init carmeva_init_early(void)
 {
        /* Initialize processor: 20.000 MHz crystal */
-       at91rm9200_initialize(20000000);
+       at91_initialize(20000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -57,11 +57,6 @@ static void __init carmeva_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init carmeva_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata carmeva_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -163,8 +158,8 @@ static void __init carmeva_board_init(void)
 MACHINE_START(CARMEVA, "Carmeva")
        /* Maintainer: Conitec Datasystems */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = carmeva_init_early,
-       .init_irq       = carmeva_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = carmeva_board_init,
 MACHINE_END
index 980511084fe4179e9965568f26cb9a6d174380e9..f4da8a16d5dc14fa0c558bb2b66e2392a2d150e7 100644 (file)
@@ -50,7 +50,7 @@
 static void __init cpu9krea_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DGBU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -81,11 +81,6 @@ static void __init cpu9krea_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init cpu9krea_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
 /*
  * USB Host port
  */
@@ -376,8 +371,8 @@ MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
 #endif
        /* Maintainer: Eric Benard - EUKREA Electromatique */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = cpu9krea_init_early,
-       .init_irq       = cpu9krea_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = cpu9krea_board_init,
 MACHINE_END
index 6daabe3907a1d7cdaa033147de021114ce6727d2..2d919f5a4f571cfcfcf884c13d8a4465cfd88e02 100644 (file)
@@ -57,7 +57,7 @@ static void __init cpuat91_init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -82,11 +82,6 @@ static void __init cpuat91_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init cpuat91_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata cpuat91_eth_data = {
        .is_rmii        = 1,
 };
@@ -180,8 +175,8 @@ static void __init cpuat91_board_init(void)
 MACHINE_START(CPUAT91, "Eukrea")
        /* Maintainer: Eric Benard - EUKREA Electromatique */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = cpuat91_init_early,
-       .init_irq       = cpuat91_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = cpuat91_board_init,
 MACHINE_END
index d98bcec1dfe000d6dc667081f36655a6206bf5fa..17654d5e94e6fd3aefe8055227246e9222878c3c 100644 (file)
@@ -46,7 +46,7 @@
 static void __init csb337_init_early(void)
 {
        /* Initialize processor: 3.6864 MHz crystal */
-       at91rm9200_initialize(3686400);
+       at91_initialize(3686400);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
@@ -58,11 +58,6 @@ static void __init csb337_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init csb337_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata csb337_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC2,
        .is_rmii        = 0,
@@ -258,8 +253,8 @@ static void __init csb337_board_init(void)
 MACHINE_START(CSB337, "Cogent CSB337")
        /* Maintainer: Bill Gatliff */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = csb337_init_early,
-       .init_irq       = csb337_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = csb337_board_init,
 MACHINE_END
index 019aab4e20b01394aba18eb89580e2ed729b08a6..72b55674616c30d0ab08b0f465e5fc891744d94c 100644 (file)
@@ -43,7 +43,7 @@
 static void __init csb637_init_early(void)
 {
        /* Initialize processor: 3.6864 MHz crystal */
-       at91rm9200_initialize(3686400);
+       at91_initialize(3686400);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -52,11 +52,6 @@ static void __init csb637_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init csb637_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata csb637_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC0,
        .is_rmii        = 0,
@@ -139,8 +134,8 @@ static void __init csb637_board_init(void)
 MACHINE_START(CSB637, "Cogent CSB637")
        /* Maintainer: Bill Gatliff */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = csb637_init_early,
-       .init_irq       = csb637_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = csb637_board_init,
 MACHINE_END
index e9484535cbc81f213b77bf617068721a037a3b9a..01170a2766a82e5169b0ef35ae8dacc94867a9ae 100644 (file)
@@ -43,7 +43,7 @@
 static void __init eb9200_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -60,11 +60,6 @@ static void __init eb9200_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init eb9200_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata eb9200_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -121,8 +116,8 @@ static void __init eb9200_board_init(void)
 
 MACHINE_START(ATEB9200, "Embest ATEB9200")
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = eb9200_init_early,
-       .init_irq       = eb9200_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = eb9200_board_init,
 MACHINE_END
index a6f57faa10a7f1dbc202c6d320c03854fff54982..7c0313c51f2673f8491ebb97e681c1b21a2cef35 100644 (file)
@@ -49,7 +49,7 @@ static void __init ecb_at91init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
@@ -64,11 +64,6 @@ static void __init ecb_at91init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ecb_at91init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata ecb_at91eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 0,
@@ -173,8 +168,8 @@ static void __init ecb_at91board_init(void)
 MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
        /* Maintainer: emQbit.com */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ecb_at91init_early,
-       .init_irq       = ecb_at91init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ecb_at91board_init,
 MACHINE_END
index bfc0062d1483f61e0a1d7026ca9a859a41253840..8252c722607b978007efe922f4480052d1902019 100644 (file)
@@ -35,7 +35,7 @@ static void __init eco920_init_early(void)
        /* Set cpu type: PQFP */
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
@@ -47,11 +47,6 @@ static void __init eco920_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init eco920_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata eco920_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC2,
        .is_rmii        = 1,
@@ -135,8 +130,8 @@ static void __init eco920_board_init(void)
 MACHINE_START(ECO920, "eco920")
        /* Maintainer: Sascha Hauer */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = eco920_init_early,
-       .init_irq       = eco920_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = eco920_board_init,
 MACHINE_END
index 466c063b8d218257eae472407a24c5b58773b9b9..4c3f65d9c59b6732bc403f3e33a1f837c009658b 100644 (file)
@@ -40,7 +40,7 @@
 static void __init flexibity_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -49,11 +49,6 @@ static void __init flexibity_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init flexibity_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
 /* USB Host port */
 static struct at91_usbh_data __initdata flexibity_usbh_data = {
        .ports          = 2,
@@ -155,8 +150,8 @@ static void __init flexibity_board_init(void)
 MACHINE_START(FLEXIBITY, "Flexibity Connect")
        /* Maintainer: Maxim Osipov */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = flexibity_init_early,
-       .init_irq       = flexibity_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = flexibity_board_init,
 MACHINE_END
index e2d1dc9eff452f09d0459b3191ebaaac387709c0..f27d1a780cfa35ef815f6298519d69ea22105019 100644 (file)
@@ -60,7 +60,7 @@
 static void __init foxg20_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -101,12 +101,6 @@ static void __init foxg20_init_early(void)
 
 }
 
-static void __init foxg20_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -267,8 +261,8 @@ static void __init foxg20_board_init(void)
 MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
        /* Maintainer: Sergio Tanzilli */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = foxg20_init_early,
-       .init_irq       = foxg20_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = foxg20_board_init,
 MACHINE_END
index 1d4f36b3cb275d0b27ce83e8a187201efc36402b..2e95949737e69d91e6ca5f23fcfed44ac4325155 100644 (file)
@@ -75,11 +75,6 @@ static void __init gsia18s_init_early(void)
        at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
 }
 
-static void __init init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
 /*
  * Two USB Host ports
  */
@@ -577,8 +572,8 @@ static void __init gsia18s_board_init(void)
 
 MACHINE_START(GSIA18S, "GS_IA18_S")
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = gsia18s_init_early,
-       .init_irq       = init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = gsia18s_board_init,
 MACHINE_END
index 9b003ff744ba4c87d3746001de09125a36fe7657..4a170890b3b1c9976036d4e527c91c9370550ac9 100644 (file)
@@ -46,7 +46,7 @@ static void __init kafa_init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Set up the LEDs */
        at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
@@ -61,11 +61,6 @@ static void __init kafa_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init kafa_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata kafa_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 0,
@@ -99,8 +94,8 @@ static void __init kafa_board_init(void)
 MACHINE_START(KAFA, "Sperry-Sun KAFA")
        /* Maintainer: Sergei Sharonov */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = kafa_init_early,
-       .init_irq       = kafa_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = kafa_board_init,
 MACHINE_END
index a813a74b65f9e296aba3d4d31af7f48913dd87e2..9dc8d496ead1bfa6c796c8fc445c23c76f944a28 100644 (file)
@@ -48,7 +48,7 @@ static void __init kb9202_init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 10 MHz crystal */
-       at91rm9200_initialize(10000000);
+       at91_initialize(10000000);
 
        /* Set up the LEDs */
        at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
@@ -69,11 +69,6 @@ static void __init kb9202_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init kb9202_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata kb9202_eth_data = {
        .phy_irq_pin    = AT91_PIN_PB29,
        .is_rmii        = 0,
@@ -140,8 +135,8 @@ static void __init kb9202_board_init(void)
 MACHINE_START(KB9200, "KB920x")
        /* Maintainer: KwikByte, Inc. */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = kb9202_init_early,
-       .init_irq       = kb9202_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = kb9202_board_init,
 MACHINE_END
index 961e805db68c21f7bde7db486d43126e57e31cd5..9bc6ab32e0acd2bb9b7d3f60ebd8c0a77d8980b3 100644 (file)
@@ -54,7 +54,7 @@
 static void __init neocore926_init_early(void)
 {
        /* Initialize processor: 20 MHz crystal */
-       at91sam9263_initialize(20000000);
+       at91_initialize(20000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -66,12 +66,6 @@ static void __init neocore926_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init neocore926_init_irq(void)
-{
-       at91sam9263_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -388,8 +382,8 @@ static void __init neocore926_board_init(void)
 MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
        /* Maintainer: ADENEO */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9263_map_io,
+       .map_io         = at91_map_io,
        .init_early     = neocore926_init_early,
-       .init_irq       = neocore926_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = neocore926_board_init,
 MACHINE_END
index 21a21af258784336c94a7b374b883a26f6652d82..49e3f699b48e1edff3d73921c178f4426b056896 100644 (file)
@@ -53,13 +53,6 @@ static void __init pcontrol_g20_init_early(void)
        at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
 }
 
-
-static void __init init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { {
        .ncs_read_setup         = 16,
        .nrd_setup              = 18,
@@ -223,8 +216,8 @@ static void __init pcontrol_g20_board_init(void)
 MACHINE_START(PCONTROL_G20, "PControl G20")
        /* Maintainer: pgsellmann@portner-elektronik.at */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = pcontrol_g20_init_early,
-       .init_irq       = init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = pcontrol_g20_board_init,
 MACHINE_END
index 756cc2a745ddd16c5ac5f1f3a23cc10aac4fe158..b7b8390e8a00b732f882fefd3b64673880de285d 100644 (file)
@@ -46,7 +46,7 @@
 static void __init picotux200_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -60,11 +60,6 @@ static void __init picotux200_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init picotux200_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata picotux200_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -124,8 +119,8 @@ static void __init picotux200_board_init(void)
 MACHINE_START(PICOTUX2XX, "picotux 200")
        /* Maintainer: Kleinhenz Elektronik GmbH */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = picotux200_init_early,
-       .init_irq       = picotux200_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = picotux200_board_init,
 MACHINE_END
index d1a6001b0bd86b7a931ff0c8f86e710a85ae67eb..81f911033681004be055a80a84ded42874644af5 100644 (file)
@@ -51,7 +51,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
-       at91sam9260_initialize(12000000);
+       at91_initialize(12000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -72,12 +72,6 @@ static void __init ek_init_early(void)
 
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -269,8 +263,8 @@ static void __init ek_board_init(void)
 MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
        /* Maintainer: calao-systems */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index aef9627710b0cee79ce885abb8b6e1be60df1bf5..6f08faadb4742b8faef2de1f84e90cb5ca137454 100644 (file)
@@ -48,7 +48,7 @@
 static void __init dk_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
@@ -65,11 +65,6 @@ static void __init dk_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init dk_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata dk_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -228,8 +223,8 @@ static void __init dk_board_init(void)
 MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
        /* Maintainer: SAN People/Atmel */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = dk_init_early,
-       .init_irq       = dk_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = dk_board_init,
 MACHINE_END
index 015a02183080973619b389bf406c98ee87ba91af..85bcccd7b9e40118b7c8a72eb12c64609d38c287 100644 (file)
@@ -48,7 +48,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
@@ -65,11 +65,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
 static struct at91_eth_data __initdata ek_eth_data = {
        .phy_irq_pin    = AT91_PIN_PC4,
        .is_rmii        = 1,
@@ -194,8 +189,8 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
        /* Maintainer: SAN People/Atmel */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index aaf1bf0989b3c1635e40e6314456cd7189594d77..4d3a02f1289e87fd9c025170240364d4ef2f7a44 100644 (file)
@@ -47,7 +47,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
@@ -67,12 +67,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -213,8 +207,8 @@ static void __init ek_board_init(void)
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
        /* Maintainer: Olimex */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index 5c240743c5b7ebec2650c8871ac4ba1a45b418c0..8a50c3e67186f1e8b8d4b0a962ab245aac6d51d6 100644 (file)
@@ -53,7 +53,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -70,12 +70,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -354,8 +348,8 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index b60c22b6e2411ad35455825b2ff4f916b62e66e4..5096a0ec50c13c8a64ab041b064e960c5f4aa0d4 100644 (file)
@@ -57,7 +57,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9261_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
@@ -69,12 +69,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9261_init_interrupts(NULL);
-}
-
-
 /*
  * DM9000 ethernet device
  */
@@ -621,8 +615,8 @@ MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
 #endif
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9261_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index 9bbdc92ea194b5a5f898c727e65fce60fae5bcf2..ea8f185d3b9d342b7cdcf19e1c8bff5e54af0574 100644 (file)
@@ -56,7 +56,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 16.367 MHz crystal */
-       at91sam9263_initialize(16367660);
+       at91_initialize(16367660);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -68,12 +68,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9263_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -452,8 +446,8 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9263_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index 1325a50101a812065aa617f245987a50a6198c41..817f59d7251bcc9dfc8ab9dbae37c18b85f840d2 100644 (file)
@@ -64,7 +64,7 @@ static int inline ek_have_2mmc(void)
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -81,12 +81,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -404,17 +398,17 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
 
 MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index 33eaa135f2480a4fc58df6db1eaeb82133fbd1d6..ad234ccbf57e5214d8e0ebb0eec63a00fa80ef68 100644 (file)
@@ -50,7 +50,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
-       at91sam9g45_initialize(12000000);
+       at91_initialize(12000000);
 
        /* DGBU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -63,12 +63,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9g45_init_interrupts(NULL);
-}
-
-
 /*
  * USB HS Host port (common to OHCI & EHCI)
  */
@@ -422,8 +416,8 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9g45_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index effb399a80a689ce5993e7526715ebb875b0d4a3..4f14b54b93a88278bef0ad5ab854d3bd497cce92 100644 (file)
@@ -41,7 +41,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
-       at91sam9rl_initialize(12000000);
+       at91_initialize(12000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -53,12 +53,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9rl_init_interrupts(NULL);
-}
-
-
 /*
  * USB HS Device port
  */
@@ -330,8 +324,8 @@ static void __init ek_board_init(void)
 MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9rl_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index 6010ce16b3cf79674ab9ca6cd44b345e810df05d..c73d25e5faea84c876b4b7e539aa0f68eb3e2271 100644 (file)
@@ -42,7 +42,7 @@
 
 static void __init snapper9260_init_early(void)
 {
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Debug on ttyS0 */
        at91_register_uart(0, 0, 0);
@@ -55,11 +55,6 @@ static void __init snapper9260_init_early(void)
        at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
 }
 
-static void __init snapper9260_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
 static struct at91_usbh_data __initdata snapper9260_usbh_data = {
        .ports          = 2,
 };
@@ -179,9 +174,9 @@ static void __init snapper9260_board_init(void)
 
 MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = snapper9260_init_early,
-       .init_irq       = snapper9260_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = snapper9260_board_init,
 MACHINE_END
 
index 5e5c85688f5f5a59ade095ec246952ef4750419e..936e5fd7f40696d6db2680fde276344a7e3950cb 100644 (file)
@@ -35,7 +35,7 @@
 void __init stamp9g20_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
+       at91_initialize(18432000);
 
        /* DGBU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -76,12 +76,6 @@ static void __init portuxg20_init_early(void)
        at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
 }
 
-static void __init init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * NAND flash
  */
@@ -299,17 +293,17 @@ static void __init stamp9g20evb_board_init(void)
 MACHINE_START(PORTUXG20, "taskit PortuxG20")
        /* Maintainer: taskit GmbH */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = portuxg20_init_early,
-       .init_irq       = init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = portuxg20_board_init,
 MACHINE_END
 
 MACHINE_START(STAMP9G20, "taskit Stamp9G20")
        /* Maintainer: taskit GmbH */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = stamp9g20evb_init_early,
-       .init_irq       = init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = stamp9g20evb_board_init,
 MACHINE_END
index 0e784e6fedec3641acf2b2ebf502b4d682fe91dc..8c4c1a02c4bebb45e8b11bb22905a744975f0f75 100644 (file)
@@ -51,7 +51,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
-       at91sam9260_initialize(12000000);
+       at91_initialize(12000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -60,12 +60,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -229,8 +223,8 @@ static void __init ek_board_init(void)
 MACHINE_START(USB_A9260, "CALAO USB_A9260")
        /* Maintainer: calao-systems */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9260_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index cf626dd14b2ccc6c914790641e523989cfe66413..25e793782a4e94c3ac49f9f9bc1c3a71a7c60d22 100644 (file)
@@ -50,7 +50,7 @@
 static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.00 MHz crystal */
-       at91sam9263_initialize(12000000);
+       at91_initialize(12000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -59,12 +59,6 @@ static void __init ek_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init ek_init_irq(void)
-{
-       at91sam9263_init_interrupts(NULL);
-}
-
-
 /*
  * USB Host port
  */
@@ -245,8 +239,8 @@ static void __init ek_board_init(void)
 MACHINE_START(USB_A9263, "CALAO USB_A9263")
        /* Maintainer: calao-systems */
        .timer          = &at91sam926x_timer,
-       .map_io         = at91sam9263_map_io,
+       .map_io         = at91_map_io,
        .init_early     = ek_init_early,
-       .init_irq       = ek_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
 MACHINE_END
index c208cc334d7df8421e34ea004b8380c374159791..95edcbd2aec64c0107e8dab5ca233706af65ca76 100644 (file)
@@ -56,7 +56,7 @@ static void __init yl9200_init_early(void)
        at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
 
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000);
+       at91_initialize(18432000);
 
        /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
        at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
@@ -79,12 +79,6 @@ static void __init yl9200_init_early(void)
        at91_set_serial_console(0);
 }
 
-static void __init yl9200_init_irq(void)
-{
-       at91rm9200_init_interrupts(NULL);
-}
-
-
 /*
  * LEDs
  */
@@ -599,8 +593,8 @@ static void __init yl9200_board_init(void)
 MACHINE_START(YL9200, "uCdragon YL-9200")
        /* Maintainer: S.Birtles */
        .timer          = &at91rm9200_timer,
-       .map_io         = at91rm9200_map_io,
+       .map_io         = at91_map_io,
        .init_early     = yl9200_init_early,
-       .init_irq       = yl9200_init_irq,
+       .init_irq       = at91_init_irq_default,
        .init_machine   = yl9200_board_init,
 MACHINE_END
index 8ff3418f3430d91e8b5ab765e8beff54db127be9..938b34f577419b9dba43f466c3d59dfe4b73fe69 100644 (file)
 #include <linux/clkdev.h>
 
  /* Map io */
-extern void __init at91rm9200_map_io(void);
-extern void __init at91sam9260_map_io(void);
-extern void __init at91sam9261_map_io(void);
-extern void __init at91sam9263_map_io(void);
-extern void __init at91sam9rl_map_io(void);
-extern void __init at91sam9g45_map_io(void);
-extern void __init at91x40_map_io(void);
-extern void __init at91cap9_map_io(void);
+extern void __init at91_map_io(void);
+extern void __init at91_init_sram(int bank, unsigned long base,
+                                 unsigned int length);
 
  /* Processors */
 extern void __init at91rm9200_set_type(int type);
-extern void __init at91rm9200_initialize(unsigned long main_clock);
-extern void __init at91sam9260_initialize(unsigned long main_clock);
-extern void __init at91sam9261_initialize(unsigned long main_clock);
-extern void __init at91sam9263_initialize(unsigned long main_clock);
-extern void __init at91sam9rl_initialize(unsigned long main_clock);
-extern void __init at91sam9g45_initialize(unsigned long main_clock);
+extern void __init at91_initialize(unsigned long main_clock);
 extern void __init at91x40_initialize(unsigned long main_clock);
-extern void __init at91cap9_initialize(unsigned long main_clock);
 
  /* Interrupts */
-extern void __init at91rm9200_init_interrupts(unsigned int priority[]);
-extern void __init at91sam9260_init_interrupts(unsigned int priority[]);
-extern void __init at91sam9261_init_interrupts(unsigned int priority[]);
-extern void __init at91sam9263_init_interrupts(unsigned int priority[]);
-extern void __init at91sam9rl_init_interrupts(unsigned int priority[]);
-extern void __init at91sam9g45_init_interrupts(unsigned int priority[]);
+extern void __init at91_init_irq_default(void);
+extern void __init at91_init_interrupts(unsigned int priority[]);
 extern void __init at91x40_init_interrupts(unsigned int priority[]);
-extern void __init at91cap9_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
 
  /* Timer */
@@ -49,7 +33,6 @@ extern struct sys_timer at91sam926x_timer;
 extern struct sys_timer at91x40_timer;
 
  /* Clocks */
-extern int __init at91_clock_init(unsigned long main_clock);
 /*
  * function to specify the clock of the default console. As we do not
  * use the device/driver bus, the dev_name is not intialize. So we need
@@ -62,6 +45,11 @@ extern void __init at91sam9263_set_console_clock(int id);
 extern void __init at91sam9rl_set_console_clock(int id);
 extern void __init at91sam9g45_set_console_clock(int id);
 extern void __init at91cap9_set_console_clock(int id);
+#ifdef CONFIG_AT91_PMC_UNIT
+extern int __init at91_clock_init(unsigned long main_clock);
+#else
+static int inline at91_clock_init(unsigned long main_clock) { return 0; }
+#endif
 struct device;
 
  /* Power Management */
index 6dcaa7716871807d906b07b6a8cef70762c6a115..dbfe455a4c410a1dab1756b967acbf6dd15ddaec 100644 (file)
 #ifndef AT91_DBGU_H
 #define AT91_DBGU_H
 
+#define dbgu_readl(dbgu, field) \
+       __raw_readl(AT91_VA_BASE_SYS + dbgu + AT91_DBGU_ ## field)
+
 #ifdef AT91_DBGU
-#define AT91_DBGU_CR           (AT91_DBGU + 0x00)      /* Control Register */
-#define AT91_DBGU_MR           (AT91_DBGU + 0x04)      /* Mode Register */
-#define AT91_DBGU_IER          (AT91_DBGU + 0x08)      /* Interrupt Enable Register */
+#define AT91_DBGU_CR           (0x00)  /* Control Register */
+#define AT91_DBGU_MR           (0x04)  /* Mode Register */
+#define AT91_DBGU_IER          (0x08)  /* Interrupt Enable Register */
 #define                AT91_DBGU_TXRDY         (1 << 1)                /* Transmitter Ready */
 #define                AT91_DBGU_TXEMPTY       (1 << 9)                /* Transmitter Empty */
-#define AT91_DBGU_IDR          (AT91_DBGU + 0x0c)      /* Interrupt Disable Register */
-#define AT91_DBGU_IMR          (AT91_DBGU + 0x10)      /* Interrupt Mask Register */
-#define AT91_DBGU_SR           (AT91_DBGU + 0x14)      /* Status Register */
-#define AT91_DBGU_RHR          (AT91_DBGU + 0x18)      /* Receiver Holding Register */
-#define AT91_DBGU_THR          (AT91_DBGU + 0x1c)      /* Transmitter Holding Register */
-#define AT91_DBGU_BRGR         (AT91_DBGU + 0x20)      /* Baud Rate Generator Register */
+#define AT91_DBGU_IDR          (0x0c)  /* Interrupt Disable Register */
+#define AT91_DBGU_IMR          (0x10)  /* Interrupt Mask Register */
+#define AT91_DBGU_SR           (0x14)  /* Status Register */
+#define AT91_DBGU_RHR          (0x18)  /* Receiver Holding Register */
+#define AT91_DBGU_THR          (0x1c)  /* Transmitter Holding Register */
+#define AT91_DBGU_BRGR         (0x20)  /* Baud Rate Generator Register */
 
-#define AT91_DBGU_CIDR         (AT91_DBGU + 0x40)      /* Chip ID Register */
-#define AT91_DBGU_EXID         (AT91_DBGU + 0x44)      /* Chip ID Extension Register */
-#define AT91_DBGU_FNR          (AT91_DBGU + 0x48)      /* Force NTRST Register [SAM9 only] */
+#define AT91_DBGU_CIDR         (0x40)  /* Chip ID Register */
+#define AT91_DBGU_EXID         (0x44)  /* Chip ID Extension Register */
+#define AT91_DBGU_FNR          (0x48)  /* Force NTRST Register [SAM9 only] */
 #define                AT91_DBGU_FNTRST        (1 << 0)                /* Force NTRST */
 
 #endif /* AT91_DBGU */
diff --git a/arch/arm/mach-at91/include/mach/at91_wdt.h b/arch/arm/mach-at91/include/mach/at91_wdt.h
deleted file mode 100644 (file)
index fecc2e9..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_wdt.h
- *
- * Copyright (C) 2007 Andrew Victor
- * Copyright (C) 2007 Atmel Corporation.
- *
- * Watchdog Timer (WDT) - System peripherals regsters.
- * Based on AT91SAM9261 datasheet revision D.
- *
- * This 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 AT91_WDT_H
-#define AT91_WDT_H
-
-#define AT91_WDT_CR            (AT91_WDT + 0x00)       /* Watchdog Control Register */
-#define                AT91_WDT_WDRSTT         (1    << 0)             /* Restart */
-#define                AT91_WDT_KEY            (0xa5 << 24)            /* KEY Password */
-
-#define AT91_WDT_MR            (AT91_WDT + 0x04)       /* Watchdog Mode Register */
-#define                AT91_WDT_WDV            (0xfff << 0)            /* Counter Value */
-#define                AT91_WDT_WDFIEN         (1     << 12)           /* Fault Interrupt Enable */
-#define                AT91_WDT_WDRSTEN        (1     << 13)           /* Reset Processor */
-#define                AT91_WDT_WDRPROC        (1     << 14)           /* Timer Restart */
-#define                AT91_WDT_WDDIS          (1     << 15)           /* Watchdog Disable */
-#define                AT91_WDT_WDD            (0xfff << 16)           /* Delta Value */
-#define                AT91_WDT_WDDBGHLT       (1     << 28)           /* Debug Halt */
-#define                AT91_WDT_WDIDLEHLT      (1     << 29)           /* Idle Halt */
-
-#define AT91_WDT_SR            (AT91_WDT + 0x08)       /* Watchdog Status Register */
-#define                AT91_WDT_WDUNF          (1 << 0)                /* Watchdog Underflow */
-#define                AT91_WDT_WDERR          (1 << 1)                /* Watchdog Error */
-
-#endif
index 665993849a7b99f44fc97a8d06578b0578971ecc..c5df1e8f19557854199b08b767935f358d4307c0 100644 (file)
@@ -75,7 +75,6 @@
 #define AT91CAP9_BASE_EMAC             0xfffbc000
 #define AT91CAP9_BASE_ADC              0xfffc0000
 #define AT91CAP9_BASE_ISI              0xfffc4000
-#define AT91_BASE_SYS                  0xffffe200
 
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
index 99e0f8d02d7bc492727def41a71dfbe8e11e2536..e4037b500302d1571701937c4547bc4f33e53e14 100644 (file)
@@ -74,7 +74,6 @@
 #define AT91RM9200_BASE_SSC1   0xfffd4000
 #define AT91RM9200_BASE_SSC2   0xfffd8000
 #define AT91RM9200_BASE_SPI    0xfffe0000
-#define AT91_BASE_SYS          0xfffff000
 
 
 /*
index 8b6bf835cd733cf88ebc9fab564381d125b2a40a..9a791165913f07f2a50489130a4fd9fecbb681b2 100644 (file)
@@ -76,7 +76,6 @@
 #define AT91SAM9260_BASE_TC4           0xfffdc040
 #define AT91SAM9260_BASE_TC5           0xfffdc080
 #define AT91SAM9260_BASE_ADC           0xfffe0000
-#define AT91_BASE_SYS                  0xffffe800
 
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
index eafbddaf523c9e702d2316f66b62bd07e01f2df6..ce596204cefa6c23cde9de020693a9ebe77fcabb 100644 (file)
@@ -60,7 +60,6 @@
 #define AT91SAM9261_BASE_SSC2          0xfffc4000
 #define AT91SAM9261_BASE_SPI0          0xfffc8000
 #define AT91SAM9261_BASE_SPI1          0xfffcc000
-#define AT91_BASE_SYS                  0xffffea00
 
 
 /*
index e2d348213a7be7ca8796aa3dff77efda48e56f06..f1b92961a2b19a5d883d503dead47d70e0e4e5cd 100644 (file)
@@ -70,7 +70,6 @@
 #define AT91SAM9263_BASE_EMAC          0xfffbc000
 #define AT91SAM9263_BASE_ISI           0xfffc4000
 #define AT91SAM9263_BASE_2DGE          0xfffc8000
-#define AT91_BASE_SYS                  0xffffe000
 
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
index 659304aa73d939176d6197acd548e50370e0e821..2c611b9a01389a7915734e590bbd7caee2acebf9 100644 (file)
@@ -82,7 +82,6 @@
 #define AT91SAM9G45_BASE_TC3           0xfffd4000
 #define AT91SAM9G45_BASE_TC4           0xfffd4040
 #define AT91SAM9G45_BASE_TC5           0xfffd4080
-#define AT91_BASE_SYS                  0xffffe200
 
 /*
  * System Peripherals (offset from AT91_BASE_SYS)
index 41dbbe61055c5c5ad50d1d66c1e7e0f08805af5c..1aabacd315d4adb74874fbd71e2532081e58e941 100644 (file)
@@ -64,7 +64,6 @@
 #define AT91SAM9RL_BASE_TSC    0xfffd0000
 #define AT91SAM9RL_BASE_UDPHS  0xfffd4000
 #define AT91SAM9RL_BASE_AC97C  0xfffd8000
-#define AT91_BASE_SYS          0xffffc000
 
 
 /*
index df966c2bc2d448e032333ac566a5a2adbe3ee034..f6ce936dba2bdd646aaafabf42a08d952918c0ce 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * arch/arm/mach-at91/include/mach/cpu.h
  *
- *  Copyright (C) 2006 SAN People
+ * Copyright (C) 2006 SAN People
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.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
  *
  */
 
-#ifndef __ASM_ARCH_CPU_H
-#define __ASM_ARCH_CPU_H
-
-#include <mach/hardware.h>
-#include <mach/at91_dbgu.h>
-
+#ifndef __MACH_CPU_H__
+#define __MACH_CPU_H__
 
 #define ARCH_ID_AT91RM9200     0x09290780
 #define ARCH_ID_AT91SAM9260    0x019803a0
 #define ARCH_ID_AT91M40807     0x14080745
 #define ARCH_ID_AT91R40008     0x44000840
 
-static inline unsigned long at91_cpu_identify(void)
-{
-       return (at91_sys_read(AT91_DBGU_CIDR) & ~AT91_CIDR_VERSION);
-}
-
-static inline unsigned long at91_cpu_fully_identify(void)
-{
-       return at91_sys_read(AT91_DBGU_CIDR);
-}
-
 #define ARCH_EXID_AT91SAM9M11  0x00000001
 #define ARCH_EXID_AT91SAM9M10  0x00000002
 #define ARCH_EXID_AT91SAM9G46  0x00000003
@@ -60,40 +47,80 @@ static inline unsigned long at91_cpu_fully_identify(void)
 #define ARCH_EXID_AT91SAM9G25  0x00000003
 #define ARCH_EXID_AT91SAM9X25  0x00000004
 
-static inline unsigned long at91_exid_identify(void)
-{
-       return at91_sys_read(AT91_DBGU_EXID);
-}
-
-
 #define ARCH_FAMILY_AT91X92    0x09200000
 #define ARCH_FAMILY_AT91SAM9   0x01900000
 #define ARCH_FAMILY_AT91SAM9XE 0x02900000
 
-static inline unsigned long at91_arch_identify(void)
-{
-       return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH);
-}
-
-#ifdef CONFIG_ARCH_AT91CAP9
-#include <mach/at91_pmc.h>
-
+/* PMC revision */
 #define ARCH_REVISION_CAP9_B   0x399
 #define ARCH_REVISION_CAP9_C   0x601
 
-static inline unsigned long at91cap9_rev_identify(void)
+/* RM9200 type */
+#define ARCH_REVISON_9200_BGA  (0 << 0)
+#define ARCH_REVISON_9200_PQFP (1 << 0)
+
+enum at91_soc_type {
+       /* 920T */
+       AT91_SOC_RM9200,
+
+       /* CAP */
+       AT91_SOC_CAP9,
+
+       /* SAM92xx */
+       AT91_SOC_SAM9260, AT91_SOC_SAM9261, AT91_SOC_SAM9263,
+
+       /* SAM9Gxx */
+       AT91_SOC_SAM9G10, AT91_SOC_SAM9G20, AT91_SOC_SAM9G45,
+
+       /* SAM9RL */
+       AT91_SOC_SAM9RL,
+
+       /* SAM9X5 */
+       AT91_SOC_SAM9X5,
+
+       /* Unknown type */
+       AT91_SOC_NONE
+};
+
+enum at91_soc_subtype {
+       /* RM9200 */
+       AT91_SOC_RM9200_BGA, AT91_SOC_RM9200_PQFP,
+
+       /* CAP9 */
+       AT91_SOC_CAP9_REV_B, AT91_SOC_CAP9_REV_C,
+
+       /* SAM9260 */
+       AT91_SOC_SAM9XE,
+
+       /* SAM9G45 */
+       AT91_SOC_SAM9G45ES, AT91_SOC_SAM9M10, AT91_SOC_SAM9G46, AT91_SOC_SAM9M11,
+
+       /* SAM9X5 */
+       AT91_SOC_SAM9G15, AT91_SOC_SAM9G35, AT91_SOC_SAM9X35,
+       AT91_SOC_SAM9G25, AT91_SOC_SAM9X25,
+
+       /* Unknown subtype */
+       AT91_SOC_SUBTYPE_NONE
+};
+
+struct at91_socinfo {
+       unsigned int type, subtype;
+       unsigned int cidr, exid;
+};
+
+extern struct at91_socinfo at91_soc_initdata;
+const char *at91_get_soc_type(struct at91_socinfo *c);
+const char *at91_get_soc_subtype(struct at91_socinfo *c);
+
+static inline int at91_soc_is_detected(void)
 {
-       return (at91_sys_read(AT91_PMC_VER));
+       return at91_soc_initdata.type != AT91_SOC_NONE;
 }
-#endif
 
 #ifdef CONFIG_ARCH_AT91RM9200
-extern int rm9200_type;
-#define ARCH_REVISON_9200_BGA  (0 << 0)
-#define ARCH_REVISON_9200_PQFP (1 << 0)
-#define cpu_is_at91rm9200()    (at91_cpu_identify() == ARCH_ID_AT91RM9200)
-#define cpu_is_at91rm9200_bga()        (!cpu_is_at91rm9200_pqfp())
-#define cpu_is_at91rm9200_pqfp() (cpu_is_at91rm9200() && rm9200_type & ARCH_REVISON_9200_PQFP)
+#define cpu_is_at91rm9200()    (at91_soc_initdata.type == AT91_SOC_RM9200)
+#define cpu_is_at91rm9200_bga()        (at91_soc_initdata.subtype == AT91_SOC_RM9200_BGA)
+#define cpu_is_at91rm9200_pqfp() (at91_soc_initdata.subtype == AT91_SOC_RM9200_PQFP)
 #else
 #define cpu_is_at91rm9200()    (0)
 #define cpu_is_at91rm9200_bga()        (0)
@@ -101,52 +128,49 @@ extern int rm9200_type;
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9260
-#define cpu_is_at91sam9xe()    (at91_arch_identify() == ARCH_FAMILY_AT91SAM9XE)
-#define cpu_is_at91sam9260()   ((at91_cpu_identify() == ARCH_ID_AT91SAM9260) || cpu_is_at91sam9xe())
+#define cpu_is_at91sam9xe()    (at91_soc_initdata.subtype == AT91_SOC_SAM9XE)
+#define cpu_is_at91sam9260()   (at91_soc_initdata.type == AT91_SOC_SAM9260)
 #else
 #define cpu_is_at91sam9xe()    (0)
 #define cpu_is_at91sam9260()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9G20
-#define cpu_is_at91sam9g20()   (at91_cpu_identify() == ARCH_ID_AT91SAM9G20)
+#define cpu_is_at91sam9g20()   (at91_soc_initdata.type == AT91_SOC_SAM9G20)
 #else
 #define cpu_is_at91sam9g20()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9261
-#define cpu_is_at91sam9261()   (at91_cpu_identify() == ARCH_ID_AT91SAM9261)
+#define cpu_is_at91sam9261()   (at91_soc_initdata.type == AT91_SOC_SAM9261)
 #else
 #define cpu_is_at91sam9261()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9G10
-#define cpu_is_at91sam9g10()   ((at91_cpu_identify() & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10)
+#define cpu_is_at91sam9g10()   (at91_soc_initdata.type == AT91_SOC_SAM9G10)
 #else
 #define cpu_is_at91sam9g10()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9263
-#define cpu_is_at91sam9263()   (at91_cpu_identify() == ARCH_ID_AT91SAM9263)
+#define cpu_is_at91sam9263()   (at91_soc_initdata.type == AT91_SOC_SAM9263)
 #else
 #define cpu_is_at91sam9263()   (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9RL
-#define cpu_is_at91sam9rl()    (at91_cpu_identify() == ARCH_ID_AT91SAM9RL64)
+#define cpu_is_at91sam9rl()    (at91_soc_initdata.type == AT91_SOC_SAM9RL)
 #else
 #define cpu_is_at91sam9rl()    (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9G45
-#define cpu_is_at91sam9g45()   (at91_cpu_identify() == ARCH_ID_AT91SAM9G45)
-#define cpu_is_at91sam9g45es() (at91_cpu_fully_identify() == ARCH_ID_AT91SAM9G45ES)
-#define cpu_is_at91sam9m10()    (cpu_is_at91sam9g45() && \
-                                (at91_exid_identify() == ARCH_EXID_AT91SAM9M10))
-#define cpu_is_at91sam9m46()    (cpu_is_at91sam9g45() && \
-                                (at91_exid_identify() == ARCH_EXID_AT91SAM9G46))
-#define cpu_is_at91sam9m11()    (cpu_is_at91sam9g45() && \
-                                (at91_exid_identify() == ARCH_EXID_AT91SAM9M11))
+#define cpu_is_at91sam9g45()   (at91_soc_initdata.type == AT91_SOC_SAM9G45)
+#define cpu_is_at91sam9g45es() (at91_soc_initdata.subtype == AT91_SOC_SAM9G45ES)
+#define cpu_is_at91sam9m10()   (at91_soc_initdata.subtype == AT91_SOC_SAM9M10)
+#define cpu_is_at91sam9g46()   (at91_soc_initdata.subtype == AT91_SOC_SAM9G46)
+#define cpu_is_at91sam9m11()   (at91_soc_initdata.subtype == AT91_SOC_SAM9M11)
 #else
 #define cpu_is_at91sam9g45()   (0)
 #define cpu_is_at91sam9g45es() (0)
@@ -156,17 +180,12 @@ extern int rm9200_type;
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9X5
-#define cpu_is_at91sam9x5()    (at91_cpu_identify() == ARCH_ID_AT91SAM9X5)
-#define cpu_is_at91sam9g15()   (cpu_is_at91sam9x5() && \
-                               (at91_exid_identify() == ARCH_EXID_AT91SAM9G15))
-#define cpu_is_at91sam9g35()   (cpu_is_at91sam9x5() && \
-                               (at91_exid_identify() == ARCH_EXID_AT91SAM9G35))
-#define cpu_is_at91sam9x35()   (cpu_is_at91sam9x5() && \
-                               (at91_exid_identify() == ARCH_EXID_AT91SAM9X35))
-#define cpu_is_at91sam9g25()   (cpu_is_at91sam9x5() && \
-                               (at91_exid_identify() == ARCH_EXID_AT91SAM9G25))
-#define cpu_is_at91sam9x25()   (cpu_is_at91sam9x5() && \
-                               (at91_exid_identify() == ARCH_EXID_AT91SAM9X25))
+#define cpu_is_at91sam9x5()    (at91_soc_initdata.type == AT91_SOC_SAM9X5)
+#define cpu_is_at91sam9g15()   (at91_soc_initdata.subtype == AT91_SOC_SAM9G15)
+#define cpu_is_at91sam9g35()   (at91_soc_initdata.subtype == AT91_SOC_SAM9G35)
+#define cpu_is_at91sam9x35()   (at91_soc_initdata.subtype == AT91_SOC_SAM9X35)
+#define cpu_is_at91sam9g25()   (at91_soc_initdata.subtype == AT91_SOC_SAM9G25)
+#define cpu_is_at91sam9x25()   (at91_soc_initdata.subtype == AT91_SOC_SAM9X25)
 #else
 #define cpu_is_at91sam9x5()    (0)
 #define cpu_is_at91sam9g15()   (0)
@@ -177,9 +196,9 @@ extern int rm9200_type;
 #endif
 
 #ifdef CONFIG_ARCH_AT91CAP9
-#define cpu_is_at91cap9()      (at91_cpu_identify() == ARCH_ID_AT91CAP9)
-#define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B)
-#define cpu_is_at91cap9_revC() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_C)
+#define cpu_is_at91cap9()      (at91_soc_initdata.type == AT91_SOC_CAP9)
+#define cpu_is_at91cap9_revB() (at91_soc_initdata.subtype == AT91_SOC_CAP9_REV_B)
+#define cpu_is_at91cap9_revC() (at91_soc_initdata.subtype == AT91_SOC_CAP9_REV_C)
 #else
 #define cpu_is_at91cap9()      (0)
 #define cpu_is_at91cap9_revB() (0)
@@ -192,4 +211,4 @@ extern int rm9200_type;
  */
 #define cpu_is_at32ap7000()    (0)
 
-#endif
+#endif /* __MACH_CPU_H__ */
index 0f959faf74a9ffe7eb9ddc02ee6d6fddebcae419..bc1e0b2e2f4f21ab2fe38463a58d3c00016b2949 100644 (file)
 #include <mach/at91_dbgu.h>
 
        .macro  addruart, rp, rv
-       ldr     \rp, =(AT91_BASE_SYS + AT91_DBGU)               @ System peripherals (phys address)
-       ldr     \rv, =(AT91_VA_BASE_SYS + AT91_DBGU)            @ System peripherals (virt address)
+       ldr     \rp, =(AT91_BASE_SYS + AT91_DBGU)       @ System peripherals (phys address)
+       ldr     \rv, =(AT91_VA_BASE_SYS + AT91_DBGU)    @ System peripherals (virt address)
        .endm
 
        .macro  senduart,rd,rx
-       strb    \rd, [\rx, #(AT91_DBGU_THR - AT91_DBGU)]        @ Write to Transmitter Holding Register
+       strb    \rd, [\rx, #(AT91_DBGU_THR)]            @ Write to Transmitter Holding Register
        .endm
 
        .macro  waituart,rd,rx
-1001:  ldr     \rd, [\rx, #(AT91_DBGU_SR - AT91_DBGU)]         @ Read Status Register
-       tst     \rd, #AT91_DBGU_TXRDY                           @ DBGU_TXRDY = 1 when ready to transmit
+1001:  ldr     \rd, [\rx, #(AT91_DBGU_SR)]             @ Read Status Register
+       tst     \rd, #AT91_DBGU_TXRDY                   @ DBGU_TXRDY = 1 when ready to transmit
        beq     1001b
        .endm
 
        .macro  busyuart,rd,rx
-1001:  ldr     \rd, [\rx, #(AT91_DBGU_SR - AT91_DBGU)]         @ Read Status Register
-       tst     \rd, #AT91_DBGU_TXEMPTY                         @ DBGU_TXEMPTY = 1 when transmission complete
+1001:  ldr     \rd, [\rx, #(AT91_DBGU_SR)]             @ Read Status Register
+       tst     \rd, #AT91_DBGU_TXEMPTY                 @ DBGU_TXEMPTY = 1 when transmission complete
        beq     1001b
        .endm
 
index 1008b9fb50741ecf77a979ff2fc239f78f781632..483478d8be6b06ccf7debddb61ac8a2b26145918 100644 (file)
 #error "Unsupported AT91 processor"
 #endif
 
+#if !defined(CONFIG_ARCH_AT91X40)
+/*
+ * On all at91 except rm9200 and x40 have the System Controller starts
+ * at address 0xffffc000 and has a size of 16KiB.
+ *
+ * On rm9200 it's start at 0xfffe4000 of 111KiB with non reserved data starting
+ * at 0xfffff000
+ *
+ * Removes the individual definitions of AT91_BASE_SYS and
+ * replaces them with a common version at base 0xfffffc000 and size 16KiB
+ * and map the same memory space
+ */
+#define AT91_BASE_SYS  0xffffc000
+#endif
 
 /*
  * Peripheral identifiers/interrupts.
index 0b0cccc46e68497dd399c6ab283f4009ad5c92a7..4298e7806c766efcde674ce92a97b26499516454 100644 (file)
 #ifndef __ASM_ARCH_IO_H
 #define __ASM_ARCH_IO_H
 
+#include <mach/hardware.h>
+
 #define IO_SPACE_LIMIT         0xFFFFFFFF
 
 #define __io(a)                __typesafe_io(a)
 #define __mem_pci(a)   (a)
 
-
 #ifndef __ASSEMBLY__
 
+#ifndef CONFIG_ARCH_AT91X40
+#define __arch_ioremap at91_ioremap
+#define __arch_iounmap at91_iounmap
+#endif
+
+void __iomem *at91_ioremap(unsigned long phys, size_t size, unsigned int type);
+void at91_iounmap(volatile void __iomem *addr);
+
 static inline unsigned int at91_sys_read(unsigned int reg_offset)
 {
        void __iomem *addr = (void __iomem *)AT91_VA_BASE_SYS;
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
new file mode 100644 (file)
index 0000000..aa64294
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2007 Atmel Corporation.
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/cpu.h>
+#include <mach/at91_dbgu.h>
+#include <mach/at91_pmc.h>
+
+#include "soc.h"
+#include "generic.h"
+
+struct at91_init_soc __initdata at91_boot_soc;
+
+struct at91_socinfo at91_soc_initdata;
+EXPORT_SYMBOL(at91_soc_initdata);
+
+void __init at91rm9200_set_type(int type)
+{
+       if (type == ARCH_REVISON_9200_PQFP)
+               at91_soc_initdata.subtype = AT91_SOC_RM9200_BGA;
+       else
+               at91_soc_initdata.subtype = AT91_SOC_RM9200_PQFP;
+}
+
+void __init at91_init_irq_default(void)
+{
+       at91_init_interrupts(at91_boot_soc.default_irq_priority);
+}
+
+void __init at91_init_interrupts(unsigned int *priority)
+{
+       /* Initialize the AIC interrupt controller */
+       at91_aic_init(priority);
+
+       /* Enable GPIO interrupts */
+       at91_gpio_irq_setup();
+}
+
+static struct map_desc sram_desc[2] __initdata;
+
+void __init at91_init_sram(int bank, unsigned long base, unsigned int length)
+{
+       struct map_desc *desc = &sram_desc[bank];
+
+       desc->virtual = AT91_IO_VIRT_BASE - length;
+       if (bank > 0)
+               desc->virtual -= sram_desc[bank - 1].length;
+
+       desc->pfn = __phys_to_pfn(base);
+       desc->length = length;
+       desc->type = MT_DEVICE;
+
+       pr_info("AT91: sram at 0x%lx of 0x%x mapped at 0x%lx\n",
+               base, length, desc->virtual);
+
+       iotable_init(desc, 1);
+}
+
+static struct map_desc at91_io_desc __initdata = {
+       .virtual        = AT91_VA_BASE_SYS,
+       .pfn            = __phys_to_pfn(AT91_BASE_SYS),
+       .length         = SZ_16K,
+       .type           = MT_DEVICE,
+};
+
+void __iomem *at91_ioremap(unsigned long p, size_t size, unsigned int type)
+{
+       if (p >= AT91_BASE_SYS && p <= (AT91_BASE_SYS + SZ_16K - 1))
+               return (void __iomem *)AT91_IO_P2V(p);
+
+       return __arm_ioremap_caller(p, size, type, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(at91_ioremap);
+
+void at91_iounmap(volatile void __iomem *addr)
+{
+       unsigned long virt = (unsigned long)addr;
+
+       if (virt >= VMALLOC_START && virt < VMALLOC_END)
+               __iounmap(addr);
+}
+EXPORT_SYMBOL(at91_iounmap);
+
+#define AT91_DBGU0     0xfffff200
+#define AT91_DBGU1     0xffffee00
+
+static void __init soc_detect(u32 dbgu_base)
+{
+       u32 cidr, socid;
+
+       cidr = __raw_readl(AT91_IO_P2V(dbgu_base) + AT91_DBGU_CIDR);
+       socid = cidr & ~AT91_CIDR_VERSION;
+
+       switch (socid) {
+       case ARCH_ID_AT91CAP9: {
+#ifdef CONFIG_AT91_PMC_UNIT
+               u32 pmc_ver = at91_sys_read(AT91_PMC_VER);
+
+               if (pmc_ver == ARCH_REVISION_CAP9_B)
+                       at91_soc_initdata.subtype = AT91_SOC_CAP9_REV_B;
+               else if (pmc_ver == ARCH_REVISION_CAP9_C)
+                       at91_soc_initdata.subtype = AT91_SOC_CAP9_REV_C;
+#endif
+               at91_soc_initdata.type = AT91_SOC_CAP9;
+               at91_boot_soc = at91cap9_soc;
+               break;
+       }
+
+       case ARCH_ID_AT91RM9200:
+               at91_soc_initdata.type = AT91_SOC_RM9200;
+               at91_boot_soc = at91rm9200_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9260:
+               at91_soc_initdata.type = AT91_SOC_SAM9260;
+               at91_boot_soc = at91sam9260_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9261:
+               at91_soc_initdata.type = AT91_SOC_SAM9261;
+               at91_boot_soc = at91sam9261_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9263:
+               at91_soc_initdata.type = AT91_SOC_SAM9263;
+               at91_boot_soc = at91sam9263_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9G20:
+               at91_soc_initdata.type = AT91_SOC_SAM9G20;
+               at91_boot_soc = at91sam9260_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9G45:
+               at91_soc_initdata.type = AT91_SOC_SAM9G45;
+               if (cidr == ARCH_ID_AT91SAM9G45ES)
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9G45ES;
+               at91_boot_soc = at91sam9g45_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9RL64:
+               at91_soc_initdata.type = AT91_SOC_SAM9RL;
+               at91_boot_soc = at91sam9rl_soc;
+               break;
+
+       case ARCH_ID_AT91SAM9X5:
+               at91_soc_initdata.type = AT91_SOC_SAM9X5;
+               at91_boot_soc = at91sam9x5_soc;
+               break;
+       }
+
+       /* at91sam9g10 */
+       if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) {
+               at91_soc_initdata.type = AT91_SOC_SAM9G10;
+               at91_boot_soc = at91sam9261_soc;
+       }
+       /* at91sam9xe */
+       else if ((cidr & AT91_CIDR_ARCH) == ARCH_FAMILY_AT91SAM9XE) {
+               at91_soc_initdata.type = AT91_SOC_SAM9260;
+               at91_soc_initdata.subtype = AT91_SOC_SAM9XE;
+               at91_boot_soc = at91sam9260_soc;
+       }
+
+       if (!at91_soc_is_detected())
+               return;
+
+       at91_soc_initdata.cidr = cidr;
+
+       /* sub version of soc */
+       at91_soc_initdata.exid = __raw_readl(AT91_IO_P2V(dbgu_base) + AT91_DBGU_EXID);
+
+       if (at91_soc_initdata.type == AT91_SOC_SAM9G45) {
+               switch (at91_soc_initdata.exid) {
+               case ARCH_EXID_AT91SAM9M10:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9M10;
+                       break;
+               case ARCH_EXID_AT91SAM9G46:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9G46;
+                       break;
+               case ARCH_EXID_AT91SAM9M11:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9M11;
+                       break;
+               }
+       }
+
+       if (at91_soc_initdata.type == AT91_SOC_SAM9X5) {
+               switch (at91_soc_initdata.exid) {
+               case ARCH_EXID_AT91SAM9G15:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9G15;
+                       break;
+               case ARCH_EXID_AT91SAM9G35:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9G35;
+                       break;
+               case ARCH_EXID_AT91SAM9X35:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9X35;
+                       break;
+               case ARCH_EXID_AT91SAM9G25:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9G25;
+                       break;
+               case ARCH_EXID_AT91SAM9X25:
+                       at91_soc_initdata.subtype = AT91_SOC_SAM9X25;
+                       break;
+               }
+       }
+}
+
+static const char *soc_name[] = {
+       [AT91_SOC_RM9200]       = "at91rm9200",
+       [AT91_SOC_CAP9]         = "at91cap9",
+       [AT91_SOC_SAM9260]      = "at91sam9260",
+       [AT91_SOC_SAM9261]      = "at91sam9261",
+       [AT91_SOC_SAM9263]      = "at91sam9263",
+       [AT91_SOC_SAM9G10]      = "at91sam9g10",
+       [AT91_SOC_SAM9G20]      = "at91sam9g20",
+       [AT91_SOC_SAM9G45]      = "at91sam9g45",
+       [AT91_SOC_SAM9RL]       = "at91sam9rl",
+       [AT91_SOC_SAM9X5]       = "at91sam9x5",
+       [AT91_SOC_NONE]         = "Unknown"
+};
+
+const char *at91_get_soc_type(struct at91_socinfo *c)
+{
+       return soc_name[c->type];
+}
+EXPORT_SYMBOL(at91_get_soc_type);
+
+static const char *soc_subtype_name[] = {
+       [AT91_SOC_RM9200_BGA]   = "at91rm9200 BGA",
+       [AT91_SOC_RM9200_PQFP]  = "at91rm9200 PQFP",
+       [AT91_SOC_CAP9_REV_B]   = "at91cap9 revB",
+       [AT91_SOC_CAP9_REV_C]   = "at91cap9 revC",
+       [AT91_SOC_SAM9XE]       = "at91sam9xe",
+       [AT91_SOC_SAM9G45ES]    = "at91sam9g45es",
+       [AT91_SOC_SAM9M10]      = "at91sam9m10",
+       [AT91_SOC_SAM9G46]      = "at91sam9g46",
+       [AT91_SOC_SAM9M11]      = "at91sam9m11",
+       [AT91_SOC_SAM9G15]      = "at91sam9g15",
+       [AT91_SOC_SAM9G35]      = "at91sam9g35",
+       [AT91_SOC_SAM9X35]      = "at91sam9x35",
+       [AT91_SOC_SAM9G25]      = "at91sam9g25",
+       [AT91_SOC_SAM9X25]      = "at91sam9x25",
+       [AT91_SOC_SUBTYPE_NONE] = "Unknown"
+};
+
+const char *at91_get_soc_subtype(struct at91_socinfo *c)
+{
+       return soc_subtype_name[c->subtype];
+}
+EXPORT_SYMBOL(at91_get_soc_subtype);
+
+void __init at91_map_io(void)
+{
+       /* Map peripherals */
+       iotable_init(&at91_io_desc, 1);
+
+       at91_soc_initdata.type = AT91_SOC_NONE;
+       at91_soc_initdata.subtype = AT91_SOC_SUBTYPE_NONE;
+
+       soc_detect(AT91_DBGU0);
+       if (!at91_soc_is_detected())
+               soc_detect(AT91_DBGU1);
+
+       if (!at91_soc_is_detected())
+               panic("AT91: Impossible to detect the SOC type");
+
+       pr_info("AT91: Detected soc type: %s\n",
+               at91_get_soc_type(&at91_soc_initdata));
+       pr_info("AT91: Detected soc subtype: %s\n",
+               at91_get_soc_subtype(&at91_soc_initdata));
+
+       if (!at91_soc_is_enabled())
+               panic("AT91: Soc not enabled");
+
+       if (at91_boot_soc.map_io)
+               at91_boot_soc.map_io();
+}
+
+void __init at91_initialize(unsigned long main_clock)
+{
+       /* Init clock subsystem */
+       at91_clock_init(main_clock);
+
+       /* Register the processor-specific clocks */
+       at91_boot_soc.register_clocks();
+
+       at91_boot_soc.init();
+}
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
new file mode 100644 (file)
index 0000000..21ed881
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+struct at91_init_soc {
+       unsigned int *default_irq_priority;
+       void (*map_io)(void);
+       void (*register_clocks)(void);
+       void (*init)(void);
+};
+
+extern struct at91_init_soc at91_boot_soc;
+extern struct at91_init_soc at91cap9_soc;
+extern struct at91_init_soc at91rm9200_soc;
+extern struct at91_init_soc at91sam9260_soc;
+extern struct at91_init_soc at91sam9261_soc;
+extern struct at91_init_soc at91sam9263_soc;
+extern struct at91_init_soc at91sam9g45_soc;
+extern struct at91_init_soc at91sam9rl_soc;
+extern struct at91_init_soc at91sam9x5_soc;
+
+static inline int at91_soc_is_enabled(void)
+{
+       return at91_boot_soc.init != NULL;
+}
+
+#if !defined(CONFIG_ARCH_AT91CAP9)
+#define at91cap9_soc   at91_boot_soc
+#endif
+
+#if !defined(CONFIG_ARCH_AT91RM9200)
+#define at91rm9200_soc at91_boot_soc
+#endif
+
+#if !(defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20))
+#define at91sam9260_soc        at91_boot_soc
+#endif
+
+#if !(defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10))
+#define at91sam9261_soc        at91_boot_soc
+#endif
+
+#if !defined(CONFIG_ARCH_AT91SAM9263)
+#define at91sam9263_soc        at91_boot_soc
+#endif
+
+#if !defined(CONFIG_ARCH_AT91SAM9G45)
+#define at91sam9g45_soc        at91_boot_soc
+#endif
+
+#if !defined(CONFIG_ARCH_AT91SAM9RL)
+#define at91sam9rl_soc at91_boot_soc
+#endif
+
+#if !defined(CONFIG_ARCH_AT91SAM9X5)
+#define at91sam9x5_soc at91_boot_soc
+#endif
index a4ec080908b8f60f9181672b41380278264ca696..06fd25d70aec8064912eb1b70d82678b4b891f6d 100644 (file)
@@ -172,7 +172,7 @@ static struct pci_bus *cns3xxx_pci_scan_bus(int nr, struct pci_sys_data *sys)
        return pci_scan_bus(sys->busnr, &cns3xxx_pcie_ops, sys);
 }
 
-static int cns3xxx_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct cns3xxx_pcie *cnspci = pdev_to_cnspci(dev);
        int irq = cnspci->irqs[slot];
index c2f1c4767f219a8c20ef6f9592db9676133e07ee..aa2b3a09a51dcdbd4efab8f33c72850eef6ef69b 100644 (file)
@@ -193,7 +193,7 @@ dove_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        return bus;
 }
 
-static int __init dove_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init dove_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct pcie_port *pp = bus_to_port(dev->bus->number);
 
index ae3e1c8c75832419fd070d6f53a3c16db5a6c5c7..32321f66dec48c9715c83206d315b986841ae51c 100644 (file)
@@ -16,7 +16,7 @@
 /* cats host-specific stuff */
 static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 };
 
-static int __init cats_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init cats_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (dev->irq >= 255)
                return -1;      /* not a valid interrupt. */
index e5ab5bddbc8c87613ddc1e14e644b913b859d54f..511c673ffa9d7b653373d780cf6e77f368a3b3e0 100644 (file)
@@ -15,7 +15,7 @@
 
 static int irqmap_ebsa285[] __initdata = { IRQ_IN3, IRQ_IN1, IRQ_IN0, IRQ_PCI };
 
-static int __init ebsa285_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ebsa285_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (dev->vendor == PCI_VENDOR_ID_CONTAQ &&
            dev->device == PCI_DEVICE_ID_CONTAQ_82C693)
index e263d6d54a0fbcc8cb6c4ac287894d4b5c6c2865..62187610e17ec0dba84954ea8e39a07b49e9c1be 100644 (file)
@@ -17,7 +17,7 @@
  * We now use the slot ID instead of the device identifiers to select
  * which interrupt is routed where.
  */
-static int __init netwinder_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init netwinder_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        switch (slot) {
        case 0:  /* host bridge */
index d5fca95afdad26a340e4b08c13d6486a259babac..aeb651d914a607d1c0b3f799185bc7b80dc46b4d 100644 (file)
@@ -18,7 +18,8 @@ static int irqmap_personal_server[] __initdata = {
        IRQ_DOORBELLHOST, IRQ_DMA1, IRQ_DMA2, IRQ_PCI
 };
 
-static int __init personal_server_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init personal_server_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        unsigned char line;
 
index dcc41728fe721a17a75fa08c5995240c0d53e23c..4aabeb2415639a04ef0cdcf95da99343aa8dea7b 100644 (file)
@@ -587,9 +587,9 @@ static struct clk_lookup lookups[] __initdata = {
        _REGISTER_CLOCK(NULL, "mma", mma_clk)
        _REGISTER_CLOCK("imx_udc.0", NULL, usbd_clk)
        _REGISTER_CLOCK(NULL, "gpt", gpt_clk)
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk)
+       _REGISTER_CLOCK("imx1-uart.0", NULL, uart_clk)
+       _REGISTER_CLOCK("imx1-uart.1", NULL, uart_clk)
+       _REGISTER_CLOCK("imx1-uart.2", NULL, uart_clk)
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
        _REGISTER_CLOCK("imx1-cspi.0", NULL, spi_clk)
        _REGISTER_CLOCK("imx1-cspi.1", NULL, spi_clk)
index bf30a8c7ce6fdddb1c66d4733dce25a8ca04ae27..ee15d8c9db08ecaa60153925bc986cc7d9aec020 100644 (file)
@@ -1162,10 +1162,10 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "perclk3", per_clk[2])
        _REGISTER_CLOCK(NULL, "perclk4", per_clk[3])
        _REGISTER_CLOCK(NULL, "clko", clko_clk)
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0])
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[1])
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[2])
-       _REGISTER_CLOCK("imx-uart.3", NULL, uart_clk[3])
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart_clk[0])
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart_clk[1])
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart_clk[2])
+       _REGISTER_CLOCK("imx21-uart.3", NULL, uart_clk[3])
        _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[0])
        _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[1])
        _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[2])
index af1c580b06bc4846ad5425f50a2a8eca4034c1b5..0fc7ba56d6165862ae44817adbd0df9e701a2e32 100644 (file)
@@ -272,11 +272,12 @@ DEFINE_CLOCK(can2_clk,     1, CCM_CGCR1,  3, get_rate_ipg, NULL, NULL);
        },
 
 static struct clk_lookup lookups[] = {
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
-       _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk)
-       _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk)
+       /* i.mx25 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
+       _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk)
+       _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk)
        _REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk)
        _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk)
        _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
@@ -295,19 +296,20 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
        _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk)
        _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       _REGISTER_CLOCK("imx25-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK("imxdi_rtc.0", NULL, dryice_clk)
        _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
        _REGISTER_CLOCK("imx2-wdt.0", NULL, wdt_clk)
        _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
        _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx25.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx25.1", NULL, esdhc2_clk)
        _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk)
        _REGISTER_CLOCK(NULL, "audmux", audmux_clk)
        _REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
        _REGISTER_CLOCK("flexcan.1", NULL, can2_clk)
-       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
+       /* i.mx25 has the i.mx35 type sdma */
+       _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk)
 };
 
 int __init mx25_clocks_init(void)
index 583f2515c1d58fdfabfb4f122cfbf069769adb5b..6912b821b37bcff07ca40df884c807c0187dd05e 100644 (file)
@@ -624,12 +624,13 @@ DEFINE_CLOCK1(csi_clk,     0, NULL,   0, parent, &csi_clk1, &per4_clk);
        },
 
 static struct clk_lookup lookups[] = {
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
-       _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk)
-       _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk)
-       _REGISTER_CLOCK("imx-uart.5", NULL, uart6_clk)
+       /* i.mx27 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
+       _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk)
+       _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk)
+       _REGISTER_CLOCK("imx21-uart.5", NULL, uart6_clk)
        _REGISTER_CLOCK(NULL, "gpt1", gpt1_clk)
        _REGISTER_CLOCK(NULL, "gpt2", gpt2_clk)
        _REGISTER_CLOCK(NULL, "gpt3", gpt3_clk)
@@ -662,7 +663,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "brom", brom_clk)
        _REGISTER_CLOCK(NULL, "emma", emma_clk)
        _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK(NULL, "emi", emi_clk)
        _REGISTER_CLOCK(NULL, "sahara2", sahara2_clk)
        _REGISTER_CLOCK(NULL, "ata", ata_clk)
index 25f343fca2b9041cbc25ee2dc87af5d436b43da6..d973770b1f9673da62708476138b14413475b9b4 100644 (file)
@@ -547,11 +547,12 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk1)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk2)
        _REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk)
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
-       _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk)
-       _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk)
+       /* i.mx31 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
+       _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk)
+       _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk)
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
        _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
        _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk)
@@ -564,7 +565,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "ata", ata_clk)
        _REGISTER_CLOCK(NULL, "rtic", rtic_clk)
        _REGISTER_CLOCK(NULL, "rng", rng_clk)
-       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk1)
+       _REGISTER_CLOCK("imx31-sdma", NULL, sdma_clk1)
        _REGISTER_CLOCK(NULL, "sdma_ipg", sdma_clk2)
        _REGISTER_CLOCK(NULL, "mstick", mstick1_clk)
        _REGISTER_CLOCK(NULL, "mstick", mstick2_clk)
index 5a4cc1ea405b46ad613ba17c64f938f5eb72263e..88b62a071aead0aac8093f38eff3bdb5fb7be4f3 100644 (file)
@@ -458,10 +458,11 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("imx-epit.0", NULL, epit1_clk)
        _REGISTER_CLOCK("imx-epit.1", NULL, epit2_clk)
        _REGISTER_CLOCK(NULL, "esai", esai_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx35.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx35.1", NULL, esdhc2_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx35.2", NULL, esdhc3_clk)
+       /* i.mx35 has the i.mx27 type fec */
+       _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK(NULL, "gpio", gpio1_clk)
        _REGISTER_CLOCK(NULL, "gpio", gpio2_clk)
        _REGISTER_CLOCK(NULL, "gpio", gpio3_clk)
@@ -481,14 +482,15 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "rtc", rtc_clk)
        _REGISTER_CLOCK(NULL, "rtic", rtic_clk)
        _REGISTER_CLOCK(NULL, "scc", scc_clk)
-       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
+       _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk)
        _REGISTER_CLOCK(NULL, "spba", spba_clk)
        _REGISTER_CLOCK(NULL, "spdif", spdif_clk)
        _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
        _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
+       /* i.mx35 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
        _REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk)
        _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk)
        _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
index 01ebcb31e4820fa976cd54e2263c597688c55c87..66e8726253faa5370dd23443110b472b7671ba13 100644 (file)
@@ -225,7 +225,8 @@ struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = {
 
 static struct esdhc_platform_data sd1_pdata = {
        .cd_gpio = GPIO_SD1CD,
-       .wp_gpio = -EINVAL,
+       .cd_type = ESDHC_CD_GPIO,
+       .wp_type = ESDHC_WP_NONE,
 };
 
 /*
index 558eb526ba56fdb0a738587681c913373a63cd61..0f0af02b31821528185ff69401784a76c9e0efe6 100644 (file)
@@ -236,7 +236,8 @@ struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = {
 
 static struct esdhc_platform_data sd1_pdata = {
        .cd_gpio = GPIO_SD1CD,
-       .wp_gpio = -EINVAL,
+       .cd_type = ESDHC_CD_GPIO,
+       .wp_type = ESDHC_WP_NONE,
 };
 
 /*
index 01534bb613051432e4ae26d97b4642d5b658aa40..7f66a91df3616d2b20f724963eb97e8db956c58a 100644 (file)
@@ -215,6 +215,8 @@ static const struct imxi2c_platform_data mx25_3ds_i2c0_data __initconst = {
 static const struct esdhc_platform_data mx25pdk_esdhc_pdata __initconst = {
        .wp_gpio = SD1_GPIO_WP,
        .cd_gpio = SD1_GPIO_CD,
+       .wp_type = ESDHC_WP_GPIO,
+       .cd_type = ESDHC_CD_GPIO,
 };
 
 static void __init mx25pdk_init(void)
index 163cc318cafb5ac2019b47b508b91742ed52063a..660ec3e80cf86bbbc8ed722813c8a622a963e85b 100644 (file)
@@ -349,6 +349,8 @@ __setup("otg_mode=", pcm043_otg_mode);
 static struct esdhc_platform_data sd1_pdata = {
        .wp_gpio = SD1_GPIO_WP,
        .cd_gpio = SD1_GPIO_CD,
+       .wp_type = ESDHC_WP_GPIO,
+       .cd_type = ESDHC_CD_GPIO,
 };
 
 /*
index 8bf0291646528d935020b112f39a957faf3ab096..cc4d152bd9bd9342d1c0ff53e6b9cfd0a52c9a90 100644 (file)
@@ -79,7 +79,6 @@ static struct sdma_script_start_addrs imx25_sdma_script __initdata = {
 };
 
 static struct sdma_platform_data imx25_sdma_pdata __initdata = {
-       .sdma_version = 2,
        .fw_name = "sdma-imx25.bin",
        .script_addrs = &imx25_sdma_script,
 };
@@ -92,5 +91,6 @@ void __init imx25_soc_init(void)
        mxc_register_gpio("imx31-gpio", 2, MX25_GPIO3_BASE_ADDR, SZ_16K, MX25_INT_GPIO3, 0);
        mxc_register_gpio("imx31-gpio", 3, MX25_GPIO4_BASE_ADDR, SZ_16K, MX25_INT_GPIO4, 0);
 
-       imx_add_imx_sdma(MX25_SDMA_BASE_ADDR, MX25_INT_SDMA, &imx25_sdma_pdata);
+       /* i.mx25 has the i.mx35 type sdma */
+       imx_add_imx_sdma("imx35-sdma", MX25_SDMA_BASE_ADDR, MX25_INT_SDMA, &imx25_sdma_pdata);
 }
index 61bff38cb9552efa7648ce6a811c748f174b50e9..b7c55e7db0007a137c1695b7577cab20fccbdde9 100644 (file)
@@ -69,7 +69,6 @@ static struct sdma_script_start_addrs imx31_to2_sdma_script __initdata = {
 };
 
 static struct sdma_platform_data imx31_sdma_pdata __initdata = {
-       .sdma_version = 1,
        .fw_name = "sdma-imx31-to2.bin",
        .script_addrs = &imx31_to2_sdma_script,
 };
@@ -88,5 +87,5 @@ void __init imx31_soc_init(void)
                imx31_sdma_pdata.script_addrs = &imx31_to1_sdma_script;
        }
 
-       imx_add_imx_sdma(MX31_SDMA_BASE_ADDR, MX31_INT_SDMA, &imx31_sdma_pdata);
+       imx_add_imx_sdma("imx31-sdma", MX31_SDMA_BASE_ADDR, MX31_INT_SDMA, &imx31_sdma_pdata);
 }
index 98769ae34377ddb46afd2ad56958ee853e23ba47..f49bac7a1ede0190bf170ee055015e79aab17be2 100644 (file)
@@ -86,7 +86,6 @@ static struct sdma_script_start_addrs imx35_to2_sdma_script __initdata = {
 };
 
 static struct sdma_platform_data imx35_sdma_pdata __initdata = {
-       .sdma_version = 2,
        .fw_name = "sdma-imx35-to2.bin",
        .script_addrs = &imx35_to2_sdma_script,
 };
@@ -106,5 +105,5 @@ void __init imx35_soc_init(void)
                imx35_sdma_pdata.script_addrs = &imx35_to1_sdma_script;
        }
 
-       imx_add_imx_sdma(MX35_SDMA_BASE_ADDR, MX35_INT_SDMA, &imx35_sdma_pdata);
+       imx_add_imx_sdma("imx35-sdma", MX35_SDMA_BASE_ADDR, MX35_INT_SDMA, &imx35_sdma_pdata);
 }
index 2fdb95433f0ae5beb02721724720c063ad0940db..520b6bf81bb1c5ebb0a671700ad5fe40686307e4 100644 (file)
@@ -95,7 +95,7 @@ static int irq_tab[4] __initdata = {
  * map the specified device/slot/pin to an IRQ.  This works out such
  * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1.
  */
-static int __init integrator_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init integrator_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int intnr = ((slot - 9) + (pin - 1)) & 3;
 
index 9b5a63f5d07d4368fcc6247d8815a2e272ac1ebf..23dfaffc586c85ad8aa637de2764d2abd43fdef0 100644 (file)
@@ -30,7 +30,7 @@
 extern int init_atu; /* Flag to select which ATU(s) to initialize / disable */
 
 static int __init
-iq81340mc_pcix_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+iq81340mc_pcix_map_irq(const struct pci_dev *dev, u8 idsel, u8 pin)
 {
        switch (idsel) {
        case 1:
index 0690b1d7fd3e9f1b803f7449c9e6b1886ddfde0f..251c40897dad44085f23e9850bf29c23540c0a65 100644 (file)
@@ -388,7 +388,7 @@ static int iop13xx_atue_pci_status(int clear)
 }
 
 static int
-iop13xx_pcie_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+iop13xx_pcie_map_irq(const struct pci_dev *dev, u8 idsel, u8 pin)
 {
        WARN_ON(idsel != 0);
 
index 779f924af302d6894b50484d15d31370485be9b6..6cbffbfc2bbab139907cbe9708707c5cedca3c2b 100644 (file)
@@ -81,7 +81,7 @@ void __init em7210_map_io(void)
 #define INTD   IRQ_IOP32X_XINT3
 
 static int __init
-em7210_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+em7210_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[][4] = {
                /*
index c6b6f9c5650d11183678163dc05799c9512955d8..ceef5d4dce1a713be462a429d4191dc5421e7217 100644 (file)
@@ -77,7 +77,7 @@ void __init glantank_map_io(void)
 #define INTD   IRQ_IOP32X_XINT3
 
 static int __init
-glantank_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+glantank_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[][4] = {
                /*
index fde962c057f0e8489ce61c074c707a562337add1..3a62514dae7cfee42d4b3f51052e9ccebaf28ccc 100644 (file)
@@ -103,7 +103,7 @@ void __init iq31244_map_io(void)
  * EP80219/IQ31244 PCI.
  */
 static int __init
-ep80219_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+ep80219_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
@@ -139,7 +139,7 @@ static struct hw_pci ep80219_pci __initdata = {
 };
 
 static int __init
-iq31244_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+iq31244_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 3a95950e8737a05095ec02a91646ea6c6bc0674f..35b7e6914d3b781d3eacdb1489fa07b34eeb8a6e 100644 (file)
@@ -71,7 +71,7 @@ void __init iq80321_map_io(void)
  * IQ80321 PCI.
  */
 static int __init
-iq80321_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+iq80321_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 626aa375915dcf06fb841fa90129a514bbf1aac6..1a374eab60071d83a812ba20935b9366b3653a1e 100644 (file)
@@ -78,7 +78,7 @@ void __init n2100_map_io(void)
  * N2100 PCI.
  */
 static int __init
-n2100_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+n2100_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index c565f8d1e3a46826d66c2a4d5718d3732c7bb2eb..637c0272d5e0f2059e12c8454e26ef192df72ab9 100644 (file)
@@ -54,7 +54,7 @@ static struct sys_timer iq80331_timer = {
  * IQ80331 PCI.
  */
 static int __init
-iq80331_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+iq80331_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 36a9efb254c25e69aa532ec70bcf6334352c33ff..90a0436d7255600b333f290235ab4ae9d4dfe0fd 100644 (file)
@@ -54,7 +54,7 @@ static struct sys_timer iq80332_timer = {
  * IQ80332 PCI.
  */
 static int __init
-iq80332_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+iq80332_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 88663ab1d2ad949cdca45c4a1ae49e71bec35b58..62c60ade5274f200e4b426f1fff6c9bfd4886af4 100644 (file)
@@ -148,7 +148,8 @@ static struct pci_bus * __init enp2611_pci_scan_bus(int nr,
        return pci_scan_bus(sys->busnr, &enp2611_pci_ops, sys);
 }
 
-static int __init enp2611_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init enp2611_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index dfffc1e817faaa1a478653c5cba9077500237998..5bad1a8419b7c7980a5ee28a56457b8246d2f45e 100644 (file)
@@ -78,7 +78,8 @@ int ixdp2400_pci_setup(int nr, struct pci_sys_data *sys)
        return 1;
 }
 
-static int __init ixdp2400_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdp2400_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        if (ixdp2x00_master_npu()) {
 
index cd4c9bcff2b512f9571af54f3734a2b790bae614..3d3cef876467021670f771fcd9b8a642c71ae8e9 100644 (file)
@@ -161,7 +161,8 @@ static int __init ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
        return 1;
 }
 
-static int __init ixdp2800_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdp2800_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        if (ixdp2x00_master_npu()) {
 
index 84835b2095579a671d8bfb4a270d22c712a52bbb..be2a254f1374d0a283bf78de8b6afbd2a89db530 100644 (file)
@@ -252,7 +252,8 @@ void __init ixdp2x01_pci_preinit(void)
 
 #define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
 
-static int __init ixdp2x01_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdp2x01_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        u8 bus = dev->bus->number;
        u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
index 8dcba17c81e78489f751058506b1fc959d477d0c..ec028e35f4013df8bafa802c2eafd105d4dca67c 100644 (file)
@@ -168,7 +168,7 @@ void __init ixdp2351_init_irq(void)
  */
 #define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
 
-static int __init ixdp2351_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdp2351_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        u8 bus = dev->bus->number;
        u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
index 8fe0c6273262bbe26029736fc968a55d074b2495..844551d2368b0c6066f84c33fadc0573accf49ce 100644 (file)
@@ -56,7 +56,8 @@
 #define INTC_PIN       IXP23XX_GPIO_PIN_11
 #define INTD_PIN       IXP23XX_GPIO_PIN_12
 
-static int __init roadrunner_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
+static int __init roadrunner_map_irq(const struct pci_dev *dev, u8 idsel,
+       u8 pin)
 {
        static int pci_card_slot_irq[] = {INTB, INTC, INTD, INTA};
        static int pmc_card_slot_irq[] = {INTA, INTB, INTC, INTD};
index 162043ff29ff5af56ac045ec55732c205f048d81..8fea0a3c5246a531641409ddc6bd14ee78c7a648 100644 (file)
@@ -46,7 +46,7 @@ void __init avila_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init avila_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init avila_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[IRQ_LINES] = {
                IXP4XX_GPIO_IRQ(INTA),
index 37fda7d6e83da4896746b60552e411e0265ff022..71f5c9c60fc3ae97e1eca398c4db064c2b18f7f1 100644 (file)
@@ -37,7 +37,7 @@ void __init coyote_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init coyote_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init coyote_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (slot == SLOT0_DEVID)
                return IXP4XX_GPIO_IRQ(SLOT0_INTA);
index c7612010b3fc982c9cdc002ab3b998356e7e95b9..0532510b5e8c68c471719b7dd6b04c44070fcd0f 100644 (file)
@@ -44,7 +44,7 @@ void __init dsmg600_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init dsmg600_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init dsmg600_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[MAX_DEV][IRQ_LINES] = {
                { IXP4XX_GPIO_IRQ(INTE), -1, -1 },
index 44ccde9d4879b02c79eec491e8864677de8c4853..d2ac803328f7d8db220257edf545c42d5a2328e4 100644 (file)
@@ -38,7 +38,7 @@ void __init fsg_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init fsg_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init fsg_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[IRQ_LINES] = {
                IXP4XX_GPIO_IRQ(INTC),
index fc11241688740df0077c036f1cc4f46574d3ff74..76581fb467c4feb451cf9cb0b8a938d28f2aac1f 100644 (file)
@@ -35,7 +35,8 @@ void __init gateway7001_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init gateway7001_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init gateway7001_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        if (slot == 1)
                return IRQ_IXP4XX_GPIO11;
index 5f00ad224fe03ff8b76c8bc8d82cd876599a6aaf..7548d9a2efe21499031c8e0b02f98070a151a9e9 100644 (file)
@@ -462,7 +462,7 @@ static void __init gmlr_pci_postinit(void)
        }
 }
 
-static int __init gmlr_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init gmlr_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        switch(slot) {
        case SLOT_ETHA: return IXP4XX_GPIO_IRQ(GPIO_IRQ_ETHA);
index 38cc0725dbd855cc4a6d147450ec5c0176479626..d68fc068c38db14403308f3505b04853c2f4e783 100644 (file)
@@ -49,7 +49,7 @@ void __init gtwx5715_pci_preinit(void)
 }
 
 
-static int __init gtwx5715_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init gtwx5715_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int rc = -1;
 
index 58f400417eaff182302164431a6dce138fccd527..fffd8c5e40bfa324d40c7b856a4c8e71c2401cf7 100644 (file)
@@ -43,7 +43,7 @@ void __init ixdp425_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init ixdp425_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdp425_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[IRQ_LINES] = {
                IXP4XX_GPIO_IRQ(INTA),
index e64f6d04148866fe321ee5e9c91c29baa07a6495..34efe75015ec97aed368bb9c469473b617387e6a 100644 (file)
@@ -31,7 +31,7 @@ void __init ixdpg425_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init ixdpg425_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init ixdpg425_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (slot == 12 || slot == 13)
                return IRQ_IXP4XX_GPIO7;
index 428d1202b7990e0df6c29f59a24e9df923ebc556..5434ccf553ebc7b7ebd59f514f0fb8b766410b7c 100644 (file)
@@ -41,7 +41,7 @@ void __init nas100d_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init nas100d_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init nas100d_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[MAX_DEV][IRQ_LINES] = {
                { IXP4XX_GPIO_IRQ(INTA), -1, -1 },
index 2e85f76b950de0711c3e94f6d176dba22961ba9a..b57160535e477530e087978bfecfe8b49789729c 100644 (file)
@@ -38,7 +38,7 @@ void __init nslu2_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init nslu2_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init nslu2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        static int pci_irq_table[IRQ_LINES] = {
                IXP4XX_GPIO_IRQ(INTA),
index 03bdec5140a79f4515b8ed17018ab4fb77e3e68e..0bc3f34c282ffbd9a20c922926c8cb5dac9a3ff6 100644 (file)
@@ -43,7 +43,7 @@ void __init vulcan_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init vulcan_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init vulcan_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (slot == 1)
                return IXP4XX_GPIO_IRQ(INTA);
index 17f3cf59a31beb95e6651c6c01aa0de070709090..f27dfcfe811b122dc6f7e971a484d419ee50f5c4 100644 (file)
@@ -35,7 +35,7 @@ void __init wg302v2_pci_preinit(void)
        ixp4xx_pci_preinit();
 }
 
-static int __init wg302v2_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init wg302v2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (slot == 1)
                return IRQ_IXP4XX_GPIO8;
index bfeb9c900cec0573ba49e0237228bc80721ff58e..74b992d810ea0137c4919a13f18c68cd937422d2 100644 (file)
@@ -245,7 +245,8 @@ kirkwood_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        return bus;
 }
 
-static int __init kirkwood_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init kirkwood_pcie_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        struct pcie_port *pp = bus_to_port(dev->bus);
 
index ada92b6bed24793aa2485ead10b1f03f03e19b63..1338cb3e98274641557667e5be5b808be22e009b 100644 (file)
@@ -34,7 +34,7 @@
 #include "generic.h"
 
 #ifdef CONFIG_PCI
-static int dsm320_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int dsm320_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        switch (slot) {
        case 0:
index c7ad09bd6ea21a02e6f95968f9d79625add4cd33..e2e3cba8dcdb437f04aa19e9b7091f09386b4989 100644 (file)
@@ -24,7 +24,7 @@
 #include "generic.h"
 
 #ifdef CONFIG_PCI
-static int micrel_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int micrel_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        return KS8695_IRQ_EXTERN0;
 }
index 2744fecb429cd44bf14a9b7c83e02c697660abcd..85a3c9aa7d1361e18d3407739be8a1b710b88956 100644 (file)
@@ -30,7 +30,7 @@ extern void __init ks8695_init_leds(u8 cpu_led, u8 timer_led);
 
 struct ks8695_pci_cfg {
        short mode;
-       int (*map_irq)(struct pci_dev *, u8, u8);
+       int (*map_irq)(const struct pci_dev *, u8, u8);
 };
 extern __init void ks8695_init_pci(struct ks8695_pci_cfg *);
 
index 888e92502e1515edb896272be63dfe8e7e576c88..ebde97f5d5f0d94035792972722331862a0ebdd6 100644 (file)
@@ -11,6 +11,7 @@ config ARCH_MSM7X00A
        select MSM_SMD
        select MSM_SMD_PKG3
        select CPU_V6
+       select GPIO_MSM_V1
        select MSM_PROC_COMM
        select HAS_MSM_DEBUG_UART_PHYS
 
@@ -22,6 +23,7 @@ config ARCH_MSM7X30
        select MSM_VIC
        select CPU_V7
        select MSM_GPIOMUX
+       select GPIO_MSM_V1
        select MSM_PROC_COMM
        select HAS_MSM_DEBUG_UART_PHYS
 
@@ -33,6 +35,7 @@ config ARCH_QSD8X50
        select MSM_VIC
        select CPU_V7
        select MSM_GPIOMUX
+       select GPIO_MSM_V1
        select MSM_PROC_COMM
        select HAS_MSM_DEBUG_UART_PHYS
 
@@ -44,6 +47,7 @@ config ARCH_MSM8X60
        select ARM_GIC
        select CPU_V7
        select MSM_V2_TLMM
+       select GPIO_MSM_V2
        select MSM_GPIOMUX
        select MSM_SCM if SMP
 
index b70658c5ae0038ef93b62255dc2de84a4f7f36bf..4285dfd80b6ff30d36eaa378699dc709670e0e8f 100644 (file)
@@ -29,11 +29,3 @@ obj-$(CONFIG_ARCH_MSM8960) += board-msm8960.o devices-msm8960.o
 obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_QSD8X50) += gpiomux-8x50.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM8X60) += gpiomux-8x60.o gpiomux-v2.o gpiomux.o
-ifdef CONFIG_MSM_V2_TLMM
-ifndef CONFIG_ARCH_MSM8960
-# TODO: TLMM Mapping issues need to be resolved
-obj-y  += gpio-v2.o
-endif
-else
-obj-y  += gpio.o
-endif
diff --git a/arch/arm/mach-msm/gpio-v2.c b/arch/arm/mach-msm/gpio-v2.c
deleted file mode 100644 (file)
index cc9c4fd..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. 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 version 2 and
- * only 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/bitmap.h>
-#include <linux/bitops.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-
-#include <asm/mach/irq.h>
-
-#include <mach/msm_iomap.h>
-#include "gpiomux.h"
-
-/* Bits of interest in the GPIO_IN_OUT register.
- */
-enum {
-       GPIO_IN  = 0,
-       GPIO_OUT = 1
-};
-
-/* Bits of interest in the GPIO_INTR_STATUS register.
- */
-enum {
-       INTR_STATUS = 0,
-};
-
-/* Bits of interest in the GPIO_CFG register.
- */
-enum {
-       GPIO_OE = 9,
-};
-
-/* Bits of interest in the GPIO_INTR_CFG register.
- * When a GPIO triggers, two separate decisions are made, controlled
- * by two separate flags.
- *
- * - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS
- * register for that GPIO will be updated to reflect the triggering of that
- * gpio.  If this bit is 0, this register will not be updated.
- * - Second, INTR_ENABLE controls whether an interrupt is triggered.
- *
- * If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt
- * can be triggered but the status register will not reflect it.
- */
-enum {
-       INTR_ENABLE        = 0,
-       INTR_POL_CTL       = 1,
-       INTR_DECT_CTL      = 2,
-       INTR_RAW_STATUS_EN = 3,
-};
-
-/* Codes of interest in GPIO_INTR_CFG_SU.
- */
-enum {
-       TARGET_PROC_SCORPION = 4,
-       TARGET_PROC_NONE     = 7,
-};
-
-
-#define GPIO_INTR_CFG_SU(gpio)    (MSM_TLMM_BASE + 0x0400 + (0x04 * (gpio)))
-#define GPIO_CONFIG(gpio)         (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
-#define GPIO_IN_OUT(gpio)         (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
-#define GPIO_INTR_CFG(gpio)       (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
-#define GPIO_INTR_STATUS(gpio)    (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
-
-/**
- * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
- *
- * @enabled_irqs: a bitmap used to optimize the summary-irq handler.  By
- * keeping track of which gpios are unmasked as irq sources, we avoid
- * having to do readl calls on hundreds of iomapped registers each time
- * the summary interrupt fires in order to locate the active interrupts.
- *
- * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
- * as wakeup sources.  When the device is suspended, interrupts which are
- * not wakeup sources are disabled.
- *
- * @dual_edge_irqs: a bitmap used to track which irqs are configured
- * as dual-edge, as this is not supported by the hardware and requires
- * some special handling in the driver.
- */
-struct msm_gpio_dev {
-       struct gpio_chip gpio_chip;
-       DECLARE_BITMAP(enabled_irqs, NR_GPIO_IRQS);
-       DECLARE_BITMAP(wake_irqs, NR_GPIO_IRQS);
-       DECLARE_BITMAP(dual_edge_irqs, NR_GPIO_IRQS);
-};
-
-static DEFINE_SPINLOCK(tlmm_lock);
-
-static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
-{
-       return container_of(chip, struct msm_gpio_dev, gpio_chip);
-}
-
-static inline void set_gpio_bits(unsigned n, void __iomem *reg)
-{
-       writel(readl(reg) | n, reg);
-}
-
-static inline void clear_gpio_bits(unsigned n, void __iomem *reg)
-{
-       writel(readl(reg) & ~n, reg);
-}
-
-static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       return readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN);
-}
-
-static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
-{
-       writel(val ? BIT(GPIO_OUT) : 0, GPIO_IN_OUT(offset));
-}
-
-static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-       unsigned long irq_flags;
-
-       spin_lock_irqsave(&tlmm_lock, irq_flags);
-       clear_gpio_bits(BIT(GPIO_OE), GPIO_CONFIG(offset));
-       spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-       return 0;
-}
-
-static int msm_gpio_direction_output(struct gpio_chip *chip,
-                               unsigned offset,
-                               int val)
-{
-       unsigned long irq_flags;
-
-       spin_lock_irqsave(&tlmm_lock, irq_flags);
-       msm_gpio_set(chip, offset, val);
-       set_gpio_bits(BIT(GPIO_OE), GPIO_CONFIG(offset));
-       spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-       return 0;
-}
-
-static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
-       return msm_gpiomux_get(chip->base + offset);
-}
-
-static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
-       msm_gpiomux_put(chip->base + offset);
-}
-
-static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-       return MSM_GPIO_TO_INT(chip->base + offset);
-}
-
-static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
-{
-       return irq - MSM_GPIO_TO_INT(chip->base);
-}
-
-static struct msm_gpio_dev msm_gpio = {
-       .gpio_chip = {
-               .base             = 0,
-               .ngpio            = NR_GPIO_IRQS,
-               .direction_input  = msm_gpio_direction_input,
-               .direction_output = msm_gpio_direction_output,
-               .get              = msm_gpio_get,
-               .set              = msm_gpio_set,
-               .to_irq           = msm_gpio_to_irq,
-               .request          = msm_gpio_request,
-               .free             = msm_gpio_free,
-       },
-};
-
-/* For dual-edge interrupts in software, since the hardware has no
- * such support:
- *
- * At appropriate moments, this function may be called to flip the polarity
- * settings of both-edge irq lines to try and catch the next edge.
- *
- * The attempt is considered successful if:
- * - the status bit goes high, indicating that an edge was caught, or
- * - the input value of the gpio doesn't change during the attempt.
- * If the value changes twice during the process, that would cause the first
- * test to fail but would force the second, as two opposite
- * transitions would cause a detection no matter the polarity setting.
- *
- * The do-loop tries to sledge-hammer closed the timing hole between
- * the initial value-read and the polarity-write - if the line value changes
- * during that window, an interrupt is lost, the new polarity setting is
- * incorrect, and the first success test will fail, causing a retry.
- *
- * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
- */
-static void msm_gpio_update_dual_edge_pos(unsigned gpio)
-{
-       int loop_limit = 100;
-       unsigned val, val2, intstat;
-
-       do {
-               val = readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN);
-               if (val)
-                       clear_gpio_bits(BIT(INTR_POL_CTL), GPIO_INTR_CFG(gpio));
-               else
-                       set_gpio_bits(BIT(INTR_POL_CTL), GPIO_INTR_CFG(gpio));
-               val2 = readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN);
-               intstat = readl(GPIO_INTR_STATUS(gpio)) & BIT(INTR_STATUS);
-               if (intstat || val == val2)
-                       return;
-       } while (loop_limit-- > 0);
-       pr_err("dual-edge irq failed to stabilize, "
-              "interrupts dropped. %#08x != %#08x\n",
-              val, val2);
-}
-
-static void msm_gpio_irq_ack(struct irq_data *d)
-{
-       int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-
-       writel(BIT(INTR_STATUS), GPIO_INTR_STATUS(gpio));
-       if (test_bit(gpio, msm_gpio.dual_edge_irqs))
-               msm_gpio_update_dual_edge_pos(gpio);
-}
-
-static void msm_gpio_irq_mask(struct irq_data *d)
-{
-       int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-       unsigned long irq_flags;
-
-       spin_lock_irqsave(&tlmm_lock, irq_flags);
-       writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
-       clear_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
-       __clear_bit(gpio, msm_gpio.enabled_irqs);
-       spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-}
-
-static void msm_gpio_irq_unmask(struct irq_data *d)
-{
-       int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-       unsigned long irq_flags;
-
-       spin_lock_irqsave(&tlmm_lock, irq_flags);
-       __set_bit(gpio, msm_gpio.enabled_irqs);
-       set_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
-       writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
-       spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-}
-
-static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
-{
-       int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-       unsigned long irq_flags;
-       uint32_t bits;
-
-       spin_lock_irqsave(&tlmm_lock, irq_flags);
-
-       bits = readl(GPIO_INTR_CFG(gpio));
-
-       if (flow_type & IRQ_TYPE_EDGE_BOTH) {
-               bits |= BIT(INTR_DECT_CTL);
-               __irq_set_handler_locked(d->irq, handle_edge_irq);
-               if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
-                       __set_bit(gpio, msm_gpio.dual_edge_irqs);
-               else
-                       __clear_bit(gpio, msm_gpio.dual_edge_irqs);
-       } else {
-               bits &= ~BIT(INTR_DECT_CTL);
-               __irq_set_handler_locked(d->irq, handle_level_irq);
-               __clear_bit(gpio, msm_gpio.dual_edge_irqs);
-       }
-
-       if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
-               bits |= BIT(INTR_POL_CTL);
-       else
-               bits &= ~BIT(INTR_POL_CTL);
-
-       writel(bits, GPIO_INTR_CFG(gpio));
-
-       if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
-               msm_gpio_update_dual_edge_pos(gpio);
-
-       spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-
-       return 0;
-}
-
-/*
- * When the summary IRQ is raised, any number of GPIO lines may be high.
- * It is the job of the summary handler to find all those GPIO lines
- * which have been set as summary IRQ lines and which are triggered,
- * and to call their interrupt handlers.
- */
-static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       unsigned long i;
-       struct irq_chip *chip = irq_desc_get_chip(desc);
-
-       chained_irq_enter(chip, desc);
-
-       for (i = find_first_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
-            i < NR_GPIO_IRQS;
-            i = find_next_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS, i + 1)) {
-               if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS))
-                       generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
-                                                          i));
-       }
-
-       chained_irq_exit(chip, desc);
-}
-
-static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
-{
-       int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-
-       if (on) {
-               if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS))
-                       irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 1);
-               set_bit(gpio, msm_gpio.wake_irqs);
-       } else {
-               clear_bit(gpio, msm_gpio.wake_irqs);
-               if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS))
-                       irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 0);
-       }
-
-       return 0;
-}
-
-static struct irq_chip msm_gpio_irq_chip = {
-       .name           = "msmgpio",
-       .irq_mask       = msm_gpio_irq_mask,
-       .irq_unmask     = msm_gpio_irq_unmask,
-       .irq_ack        = msm_gpio_irq_ack,
-       .irq_set_type   = msm_gpio_irq_set_type,
-       .irq_set_wake   = msm_gpio_irq_set_wake,
-};
-
-static int __devinit msm_gpio_probe(struct platform_device *dev)
-{
-       int i, irq, ret;
-
-       bitmap_zero(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
-       bitmap_zero(msm_gpio.wake_irqs, NR_GPIO_IRQS);
-       bitmap_zero(msm_gpio.dual_edge_irqs, NR_GPIO_IRQS);
-       msm_gpio.gpio_chip.label = dev->name;
-       ret = gpiochip_add(&msm_gpio.gpio_chip);
-       if (ret < 0)
-               return ret;
-
-       for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
-               irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
-               irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
-                                        handle_level_irq);
-               set_irq_flags(irq, IRQF_VALID);
-       }
-
-       irq_set_chained_handler(TLMM_SCSS_SUMMARY_IRQ,
-                               msm_summary_irq_handler);
-       return 0;
-}
-
-static int __devexit msm_gpio_remove(struct platform_device *dev)
-{
-       int ret = gpiochip_remove(&msm_gpio.gpio_chip);
-
-       if (ret < 0)
-               return ret;
-
-       irq_set_handler(TLMM_SCSS_SUMMARY_IRQ, NULL);
-
-       return 0;
-}
-
-static struct platform_driver msm_gpio_driver = {
-       .probe = msm_gpio_probe,
-       .remove = __devexit_p(msm_gpio_remove),
-       .driver = {
-               .name = "msmgpio",
-               .owner = THIS_MODULE,
-       },
-};
-
-static struct platform_device msm_device_gpio = {
-       .name = "msmgpio",
-       .id   = -1,
-};
-
-static int __init msm_gpio_init(void)
-{
-       int rc;
-
-       rc = platform_driver_register(&msm_gpio_driver);
-       if (!rc) {
-               rc = platform_device_register(&msm_device_gpio);
-               if (rc)
-                       platform_driver_unregister(&msm_gpio_driver);
-       }
-
-       return rc;
-}
-
-static void __exit msm_gpio_exit(void)
-{
-       platform_device_unregister(&msm_device_gpio);
-       platform_driver_unregister(&msm_gpio_driver);
-}
-
-postcore_initcall(msm_gpio_init);
-module_exit(msm_gpio_exit);
-
-MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
-MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:msmgpio");
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
deleted file mode 100644 (file)
index 5ea273b..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-/* linux/arch/arm/mach-msm/gpio.c
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#include <linux/bitops.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include "gpio_hw.h"
-#include "gpiomux.h"
-
-#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
-
-#define MSM_GPIO_BANK(bank, first, last)                               \
-       {                                                               \
-               .regs = {                                               \
-                       .out =         MSM_GPIO_OUT_##bank,             \
-                       .in =          MSM_GPIO_IN_##bank,              \
-                       .int_status =  MSM_GPIO_INT_STATUS_##bank,      \
-                       .int_clear =   MSM_GPIO_INT_CLEAR_##bank,       \
-                       .int_en =      MSM_GPIO_INT_EN_##bank,          \
-                       .int_edge =    MSM_GPIO_INT_EDGE_##bank,        \
-                       .int_pos =     MSM_GPIO_INT_POS_##bank,         \
-                       .oe =          MSM_GPIO_OE_##bank,              \
-               },                                                      \
-               .chip = {                                               \
-                       .base = (first),                                \
-                       .ngpio = (last) - (first) + 1,                  \
-                       .get = msm_gpio_get,                            \
-                       .set = msm_gpio_set,                            \
-                       .direction_input = msm_gpio_direction_input,    \
-                       .direction_output = msm_gpio_direction_output,  \
-                       .to_irq = msm_gpio_to_irq,                      \
-                       .request = msm_gpio_request,                    \
-                       .free = msm_gpio_free,                          \
-               }                                                       \
-       }
-
-#define MSM_GPIO_BROKEN_INT_CLEAR 1
-
-struct msm_gpio_regs {
-       void __iomem *out;
-       void __iomem *in;
-       void __iomem *int_status;
-       void __iomem *int_clear;
-       void __iomem *int_en;
-       void __iomem *int_edge;
-       void __iomem *int_pos;
-       void __iomem *oe;
-};
-
-struct msm_gpio_chip {
-       spinlock_t              lock;
-       struct gpio_chip        chip;
-       struct msm_gpio_regs    regs;
-#if MSM_GPIO_BROKEN_INT_CLEAR
-       unsigned                int_status_copy;
-#endif
-       unsigned int            both_edge_detect;
-       unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
-};
-
-static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
-                         unsigned offset, unsigned on)
-{
-       unsigned mask = BIT(offset);
-       unsigned val;
-
-       val = readl(msm_chip->regs.out);
-       if (on)
-               writel(val | mask, msm_chip->regs.out);
-       else
-               writel(val & ~mask, msm_chip->regs.out);
-       return 0;
-}
-
-static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
-{
-       int loop_limit = 100;
-       unsigned pol, val, val2, intstat;
-       do {
-               val = readl(msm_chip->regs.in);
-               pol = readl(msm_chip->regs.int_pos);
-               pol = (pol & ~msm_chip->both_edge_detect) |
-                     (~val & msm_chip->both_edge_detect);
-               writel(pol, msm_chip->regs.int_pos);
-               intstat = readl(msm_chip->regs.int_status);
-               val2 = readl(msm_chip->regs.in);
-               if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
-                       return;
-       } while (loop_limit-- > 0);
-       printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
-              "failed to reach stable state %x != %x\n", val, val2);
-}
-
-static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
-                                       unsigned offset)
-{
-       unsigned bit = BIT(offset);
-
-#if MSM_GPIO_BROKEN_INT_CLEAR
-       /* Save interrupts that already triggered before we loose them. */
-       /* Any interrupt that triggers between the read of int_status */
-       /* and the write to int_clear will still be lost though. */
-       msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
-       msm_chip->int_status_copy &= ~bit;
-#endif
-       writel(bit, msm_chip->regs.int_clear);
-       msm_gpio_update_both_edge_detect(msm_chip);
-       return 0;
-}
-
-static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-       struct msm_gpio_chip *msm_chip;
-       unsigned long irq_flags;
-
-       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       writel(readl(msm_chip->regs.oe) & ~BIT(offset), msm_chip->regs.oe);
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-       return 0;
-}
-
-static int
-msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct msm_gpio_chip *msm_chip;
-       unsigned long irq_flags;
-
-       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       msm_gpio_write(msm_chip, offset, value);
-       writel(readl(msm_chip->regs.oe) | BIT(offset), msm_chip->regs.oe);
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-       return 0;
-}
-
-static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct msm_gpio_chip *msm_chip;
-
-       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
-       return (readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
-}
-
-static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct msm_gpio_chip *msm_chip;
-       unsigned long irq_flags;
-
-       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       msm_gpio_write(msm_chip, offset, value);
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-       return MSM_GPIO_TO_INT(chip->base + offset);
-}
-
-#ifdef CONFIG_MSM_GPIOMUX
-static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
-       return msm_gpiomux_get(chip->base + offset);
-}
-
-static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
-       msm_gpiomux_put(chip->base + offset);
-}
-#else
-#define msm_gpio_request NULL
-#define msm_gpio_free NULL
-#endif
-
-struct msm_gpio_chip msm_gpio_chips[] = {
-#if defined(CONFIG_ARCH_MSM7X00A)
-       MSM_GPIO_BANK(0,   0,  15),
-       MSM_GPIO_BANK(1,  16,  42),
-       MSM_GPIO_BANK(2,  43,  67),
-       MSM_GPIO_BANK(3,  68,  94),
-       MSM_GPIO_BANK(4,  95, 106),
-       MSM_GPIO_BANK(5, 107, 121),
-#elif defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X27)
-       MSM_GPIO_BANK(0,   0,  15),
-       MSM_GPIO_BANK(1,  16,  42),
-       MSM_GPIO_BANK(2,  43,  67),
-       MSM_GPIO_BANK(3,  68,  94),
-       MSM_GPIO_BANK(4,  95, 106),
-       MSM_GPIO_BANK(5, 107, 132),
-#elif defined(CONFIG_ARCH_MSM7X30)
-       MSM_GPIO_BANK(0,   0,  15),
-       MSM_GPIO_BANK(1,  16,  43),
-       MSM_GPIO_BANK(2,  44,  67),
-       MSM_GPIO_BANK(3,  68,  94),
-       MSM_GPIO_BANK(4,  95, 106),
-       MSM_GPIO_BANK(5, 107, 133),
-       MSM_GPIO_BANK(6, 134, 150),
-       MSM_GPIO_BANK(7, 151, 181),
-#elif defined(CONFIG_ARCH_QSD8X50)
-       MSM_GPIO_BANK(0,   0,  15),
-       MSM_GPIO_BANK(1,  16,  42),
-       MSM_GPIO_BANK(2,  43,  67),
-       MSM_GPIO_BANK(3,  68,  94),
-       MSM_GPIO_BANK(4,  95, 103),
-       MSM_GPIO_BANK(5, 104, 121),
-       MSM_GPIO_BANK(6, 122, 152),
-       MSM_GPIO_BANK(7, 153, 164),
-#endif
-};
-
-static void msm_gpio_irq_ack(struct irq_data *d)
-{
-       unsigned long irq_flags;
-       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       msm_gpio_clear_detect_status(msm_chip,
-                                    d->irq - gpio_to_irq(msm_chip->chip.base));
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static void msm_gpio_irq_mask(struct irq_data *d)
-{
-       unsigned long irq_flags;
-       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
-       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       /* level triggered interrupts are also latched */
-       if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
-               msm_gpio_clear_detect_status(msm_chip, offset);
-       msm_chip->int_enable[0] &= ~BIT(offset);
-       writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static void msm_gpio_irq_unmask(struct irq_data *d)
-{
-       unsigned long irq_flags;
-       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
-       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       /* level triggered interrupts are also latched */
-       if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
-               msm_gpio_clear_detect_status(msm_chip, offset);
-       msm_chip->int_enable[0] |= BIT(offset);
-       writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
-{
-       unsigned long irq_flags;
-       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
-       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-
-       if (on)
-               msm_chip->int_enable[1] |= BIT(offset);
-       else
-               msm_chip->int_enable[1] &= ~BIT(offset);
-
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-       return 0;
-}
-
-static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
-{
-       unsigned long irq_flags;
-       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
-       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-       unsigned val, mask = BIT(offset);
-
-       spin_lock_irqsave(&msm_chip->lock, irq_flags);
-       val = readl(msm_chip->regs.int_edge);
-       if (flow_type & IRQ_TYPE_EDGE_BOTH) {
-               writel(val | mask, msm_chip->regs.int_edge);
-               __irq_set_handler_locked(d->irq, handle_edge_irq);
-       } else {
-               writel(val & ~mask, msm_chip->regs.int_edge);
-               __irq_set_handler_locked(d->irq, handle_level_irq);
-       }
-       if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
-               msm_chip->both_edge_detect |= mask;
-               msm_gpio_update_both_edge_detect(msm_chip);
-       } else {
-               msm_chip->both_edge_detect &= ~mask;
-               val = readl(msm_chip->regs.int_pos);
-               if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
-                       writel(val | mask, msm_chip->regs.int_pos);
-               else
-                       writel(val & ~mask, msm_chip->regs.int_pos);
-       }
-       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-       return 0;
-}
-
-static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       int i, j, mask;
-       unsigned val;
-
-       for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
-               struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
-               val = readl(msm_chip->regs.int_status);
-               val &= msm_chip->int_enable[0];
-               while (val) {
-                       mask = val & -val;
-                       j = fls(mask) - 1;
-                       /* printk("%s %08x %08x bit %d gpio %d irq %d\n",
-                               __func__, v, m, j, msm_chip->chip.start + j,
-                               FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
-                       val &= ~mask;
-                       generic_handle_irq(FIRST_GPIO_IRQ +
-                                          msm_chip->chip.base + j);
-               }
-       }
-       desc->irq_data.chip->irq_ack(&desc->irq_data);
-}
-
-static struct irq_chip msm_gpio_irq_chip = {
-       .name          = "msmgpio",
-       .irq_ack       = msm_gpio_irq_ack,
-       .irq_mask      = msm_gpio_irq_mask,
-       .irq_unmask    = msm_gpio_irq_unmask,
-       .irq_set_wake  = msm_gpio_irq_set_wake,
-       .irq_set_type  = msm_gpio_irq_set_type,
-};
-
-static int __init msm_init_gpio(void)
-{
-       int i, j = 0;
-
-       for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
-               if (i - FIRST_GPIO_IRQ >=
-                       msm_gpio_chips[j].chip.base +
-                       msm_gpio_chips[j].chip.ngpio)
-                       j++;
-               irq_set_chip_data(i, &msm_gpio_chips[j]);
-               irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
-                                        handle_edge_irq);
-               set_irq_flags(i, IRQF_VALID);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
-               spin_lock_init(&msm_gpio_chips[i].lock);
-               writel(0, msm_gpio_chips[i].regs.int_en);
-               gpiochip_add(&msm_gpio_chips[i].chip);
-       }
-
-       irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
-       irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
-       irq_set_irq_wake(INT_GPIO_GROUP1, 1);
-       irq_set_irq_wake(INT_GPIO_GROUP2, 2);
-       return 0;
-}
-
-postcore_initcall(msm_init_gpio);
diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
deleted file mode 100644 (file)
index 6b50660..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/* arch/arm/mach-msm/gpio_hw.h
- *
- * Copyright (C) 2007 Google, Inc.
- * Author: Brian Swetland <swetland@google.com>
- * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
-#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
-
-#include <mach/msm_iomap.h>
-
-/* see 80-VA736-2 Rev C pp 695-751
-**
-** These are actually the *shadow* gpio registers, since the
-** real ones (which allow full access) are only available to the
-** ARM9 side of the world.
-**
-** Since the _BASE need to be page-aligned when we're mapping them
-** to virtual addresses, adjust for the additional offset in these
-** macros.
-*/
-
-#if defined(CONFIG_ARCH_MSM7X30)
-#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + (off))
-#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off))
-#else
-#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
-#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
-#endif
-
-#if defined(CONFIG_ARCH_MSM7X00A) || defined(CONFIG_ARCH_MSM7X25) ||\
-    defined(CONFIG_ARCH_MSM7X27)
-
-/* output value */
-#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)  /* gpio  15-0  */
-#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)  /* gpio  42-16 */
-#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)  /* gpio  67-43 */
-#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)  /* gpio  94-68 */
-#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)  /* gpio 106-95 */
-#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x50)  /* gpio 107-121 */
-
-/* same pin map as above, output enable */
-#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x10)
-#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
-#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x14)
-#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x18)
-#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x1C)
-#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x54)
-
-/* same pin map as above, input read */
-#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x34)
-#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
-#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x38)
-#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x3C)
-#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x40)
-#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x44)
-
-/* same pin map as above, 1=edge 0=level interrup */
-#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x60)
-#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
-#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x64)
-#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x68)
-#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x6C)
-#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0xC0)
-
-/* same pin map as above, 1=positive 0=negative */
-#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x70)
-#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
-#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x74)
-#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x78)
-#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x7C)
-#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xBC)
-
-/* same pin map as above, interrupt enable */
-#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0x80)
-#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
-#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0x84)
-#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0x88)
-#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0x8C)
-#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xB8)
-
-/* same pin map as above, write 1 to clear interrupt */
-#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0x90)
-#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
-#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0x94)
-#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0x98)
-#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0x9C)
-#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xB4)
-
-/* same pin map as above, 1=interrupt pending */
-#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xA0)
-#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
-#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xA4)
-#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xA8)
-#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xAC)
-#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0xB0)
-
-#endif
-
-#if defined(CONFIG_ARCH_QSD8X50)
-/* output value */
-#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)  /* gpio  15-0   */
-#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)  /* gpio  42-16  */
-#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)  /* gpio  67-43  */
-#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)  /* gpio  94-68  */
-#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)  /* gpio 103-95  */
-#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x10)  /* gpio 121-104 */
-#define MSM_GPIO_OUT_6         MSM_GPIO1_REG(0x14)  /* gpio 152-122 */
-#define MSM_GPIO_OUT_7         MSM_GPIO1_REG(0x18)  /* gpio 164-153 */
-
-/* same pin map as above, output enable */
-#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x20)
-#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
-#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x24)
-#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x28)
-#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x2C)
-#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x30)
-#define MSM_GPIO_OE_6          MSM_GPIO1_REG(0x34)
-#define MSM_GPIO_OE_7          MSM_GPIO1_REG(0x38)
-
-/* same pin map as above, input read */
-#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x50)
-#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
-#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x54)
-#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x58)
-#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x5C)
-#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x60)
-#define MSM_GPIO_IN_6          MSM_GPIO1_REG(0x64)
-#define MSM_GPIO_IN_7          MSM_GPIO1_REG(0x68)
-
-/* same pin map as above, 1=edge 0=level interrup */
-#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x70)
-#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
-#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x74)
-#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x78)
-#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x7C)
-#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0x80)
-#define MSM_GPIO_INT_EDGE_6    MSM_GPIO1_REG(0x84)
-#define MSM_GPIO_INT_EDGE_7    MSM_GPIO1_REG(0x88)
-
-/* same pin map as above, 1=positive 0=negative */
-#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x90)
-#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
-#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x94)
-#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x98)
-#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x9C)
-#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xA0)
-#define MSM_GPIO_INT_POS_6     MSM_GPIO1_REG(0xA4)
-#define MSM_GPIO_INT_POS_7     MSM_GPIO1_REG(0xA8)
-
-/* same pin map as above, interrupt enable */
-#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0xB0)
-#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
-#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0xB4)
-#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0xB8)
-#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0xBC)
-#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xC0)
-#define MSM_GPIO_INT_EN_6      MSM_GPIO1_REG(0xC4)
-#define MSM_GPIO_INT_EN_7      MSM_GPIO1_REG(0xC8)
-
-/* same pin map as above, write 1 to clear interrupt */
-#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0xD0)
-#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
-#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0xD4)
-#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0xD8)
-#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0xDC)
-#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xE0)
-#define MSM_GPIO_INT_CLEAR_6   MSM_GPIO1_REG(0xE4)
-#define MSM_GPIO_INT_CLEAR_7   MSM_GPIO1_REG(0xE8)
-
-/* same pin map as above, 1=interrupt pending */
-#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xF0)
-#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
-#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xF4)
-#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xF8)
-#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xFC)
-#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0x100)
-#define MSM_GPIO_INT_STATUS_6  MSM_GPIO1_REG(0x104)
-#define MSM_GPIO_INT_STATUS_7  MSM_GPIO1_REG(0x108)
-
-#endif
-
-#if defined(CONFIG_ARCH_MSM7X30)
-
-/* output value */
-#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)   /* gpio  15-0   */
-#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)   /* gpio  43-16  */
-#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)   /* gpio  67-44  */
-#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)   /* gpio  94-68  */
-#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)   /* gpio 106-95  */
-#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x50)   /* gpio 133-107 */
-#define MSM_GPIO_OUT_6         MSM_GPIO1_REG(0xC4)   /* gpio 150-134 */
-#define MSM_GPIO_OUT_7         MSM_GPIO1_REG(0x214)  /* gpio 181-151 */
-
-/* same pin map as above, output enable */
-#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x10)
-#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
-#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x14)
-#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x18)
-#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x1C)
-#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x54)
-#define MSM_GPIO_OE_6          MSM_GPIO1_REG(0xC8)
-#define MSM_GPIO_OE_7          MSM_GPIO1_REG(0x218)
-
-/* same pin map as above, input read */
-#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x34)
-#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
-#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x38)
-#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x3C)
-#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x40)
-#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x44)
-#define MSM_GPIO_IN_6          MSM_GPIO1_REG(0xCC)
-#define MSM_GPIO_IN_7          MSM_GPIO1_REG(0x21C)
-
-/* same pin map as above, 1=edge 0=level interrup */
-#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x60)
-#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
-#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x64)
-#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x68)
-#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x6C)
-#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0xC0)
-#define MSM_GPIO_INT_EDGE_6    MSM_GPIO1_REG(0xD0)
-#define MSM_GPIO_INT_EDGE_7    MSM_GPIO1_REG(0x240)
-
-/* same pin map as above, 1=positive 0=negative */
-#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x70)
-#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
-#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x74)
-#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x78)
-#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x7C)
-#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xBC)
-#define MSM_GPIO_INT_POS_6     MSM_GPIO1_REG(0xD4)
-#define MSM_GPIO_INT_POS_7     MSM_GPIO1_REG(0x228)
-
-/* same pin map as above, interrupt enable */
-#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0x80)
-#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
-#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0x84)
-#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0x88)
-#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0x8C)
-#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xB8)
-#define MSM_GPIO_INT_EN_6      MSM_GPIO1_REG(0xD8)
-#define MSM_GPIO_INT_EN_7      MSM_GPIO1_REG(0x22C)
-
-/* same pin map as above, write 1 to clear interrupt */
-#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0x90)
-#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
-#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0x94)
-#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0x98)
-#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0x9C)
-#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xB4)
-#define MSM_GPIO_INT_CLEAR_6   MSM_GPIO1_REG(0xDC)
-#define MSM_GPIO_INT_CLEAR_7   MSM_GPIO1_REG(0x230)
-
-/* same pin map as above, 1=interrupt pending */
-#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xA0)
-#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
-#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xA4)
-#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xA8)
-#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xAC)
-#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0xB0)
-#define MSM_GPIO_INT_STATUS_6  MSM_GPIO1_REG(0xE0)
-#define MSM_GPIO_INT_STATUS_7  MSM_GPIO1_REG(0x234)
-
-#endif
-
-#endif
index b178d9cb742fbe191cf511f16188e21400bd6772..00459f6ee13c337ede196e8f512234128b2a391a 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/bitops.h>
 #include <linux/errno.h>
+#include <mach/msm_gpiomux.h>
 
 #if defined(CONFIG_MSM_V2_TLMM)
 #include "gpiomux-v2.h"
@@ -71,12 +72,6 @@ enum {
  */
 extern struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS];
 
-/* Increment a gpio's reference count, possibly activating the line. */
-int __must_check msm_gpiomux_get(unsigned gpio);
-
-/* Decrement a gpio's reference count, possibly suspending the line. */
-int msm_gpiomux_put(unsigned gpio);
-
 /* Install a new configuration to the gpio line.  To avoid overwriting
  * a configuration, leave the VALID bit out.
  */
@@ -94,16 +89,6 @@ int msm_gpiomux_write(unsigned gpio,
  */
 void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val);
 #else
-static inline int __must_check msm_gpiomux_get(unsigned gpio)
-{
-       return -ENOSYS;
-}
-
-static inline int msm_gpiomux_put(unsigned gpio)
-{
-       return -ENOSYS;
-}
-
 static inline int msm_gpiomux_write(unsigned gpio,
                                    gpiomux_config_t active,
                                    gpiomux_config_t suspended)
diff --git a/arch/arm/mach-msm/include/mach/msm_gpiomux.h b/arch/arm/mach-msm/include/mach/msm_gpiomux.h
new file mode 100644 (file)
index 0000000..0c7d393
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#ifndef _LINUX_MSM_GPIOMUX_H
+#define _LINUX_MSM_GPIOMUX_H
+
+#ifdef CONFIG_MSM_GPIOMUX
+
+/* Increment a gpio's reference count, possibly activating the line. */
+int __must_check msm_gpiomux_get(unsigned gpio);
+
+/* Decrement a gpio's reference count, possibly suspending the line. */
+int msm_gpiomux_put(unsigned gpio);
+
+#else
+
+static inline int __must_check msm_gpiomux_get(unsigned gpio)
+{
+       return -ENOSYS;
+}
+
+static inline int msm_gpiomux_put(unsigned gpio)
+{
+       return -ENOSYS;
+}
+
+#endif
+
+#endif /* _LINUX_MSM_GPIOMUX_H */
index 8f99d97615a0b25f9c3636e3313af016b38d4648..94fe9fe6feb35e207a48b88685f143985d6910d1 100644 (file)
 #define MSM_DMOV_PHYS         0xA9700000
 #define MSM_DMOV_SIZE         SZ_4K
 
-#define MSM_GPIO1_BASE        IOMEM(0xE0003000)
-#define MSM_GPIO1_PHYS        0xA9200000
-#define MSM_GPIO1_SIZE        SZ_4K
+#define MSM7X00_GPIO1_PHYS        0xA9200000
+#define MSM7X00_GPIO1_SIZE        SZ_4K
 
-#define MSM_GPIO2_BASE        IOMEM(0xE0004000)
-#define MSM_GPIO2_PHYS        0xA9300000
-#define MSM_GPIO2_SIZE        SZ_4K
+#define MSM7X00_GPIO2_PHYS        0xA9300000
+#define MSM7X00_GPIO2_SIZE        SZ_4K
 
 #define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
 #define MSM_CLK_CTL_PHYS      0xA8600000
index 4d84be15955ea6856829af2e16be5ccf3aac9162..37694442d1bda079bb1475e71a511cf27ad825f3 100644 (file)
 #define MSM_DMOV_PHYS         0xAC400000
 #define MSM_DMOV_SIZE         SZ_4K
 
-#define MSM_GPIO1_BASE        IOMEM(0xE0003000)
-#define MSM_GPIO1_PHYS        0xAC001000
-#define MSM_GPIO1_SIZE        SZ_4K
+#define MSM7X30_GPIO1_PHYS        0xAC001000
+#define MSM7X30_GPIO1_SIZE        SZ_4K
 
-#define MSM_GPIO2_BASE        IOMEM(0xE0004000)
-#define MSM_GPIO2_PHYS        0xAC101000
-#define MSM_GPIO2_SIZE        SZ_4K
+#define MSM7X30_GPIO2_PHYS        0xAC101000
+#define MSM7X30_GPIO2_SIZE        SZ_4K
 
 #define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
 #define MSM_CLK_CTL_PHYS      0xAB800000
index d4143201999f2d8675e29a142d4290f2fef75f2e..d67cd73316f456eaaf7258fc8ea3444ebd884b9d 100644 (file)
 #define MSM_DMOV_PHYS         0xA9700000
 #define MSM_DMOV_SIZE         SZ_4K
 
-#define MSM_GPIO1_BASE        IOMEM(0xE0003000)
-#define MSM_GPIO1_PHYS        0xA9000000
-#define MSM_GPIO1_SIZE        SZ_4K
+#define QSD8X50_GPIO1_PHYS        0xA9000000
+#define QSD8X50_GPIO1_SIZE        SZ_4K
 
-#define MSM_GPIO2_BASE        IOMEM(0xE0004000)
-#define MSM_GPIO2_PHYS        0xA9100000
-#define MSM_GPIO2_SIZE        SZ_4K
+#define QSD8X50_GPIO2_PHYS        0xA9100000
+#define QSD8X50_GPIO2_SIZE        SZ_4K
 
 #define MSM_CLK_CTL_BASE      IOMEM(0xE0005000)
 #define MSM_CLK_CTL_PHYS      0xA8600000
index 2f494b6a9d0a969f4411d3adc306fcbfce407eb7..4ded15238b60267442f4f7aec2f640e131dfd6dd 100644 (file)
@@ -61,5 +61,7 @@
 #define MSM_QGIC_CPU_BASE      IOMEM(0xF0001000)
 #define MSM_TMR_BASE           IOMEM(0xF0200000)
 #define MSM_TMR0_BASE          IOMEM(0xF0201000)
+#define MSM_GPIO1_BASE         IOMEM(0xE0003000)
+#define MSM_GPIO2_BASE         IOMEM(0xE0004000)
 
 #endif
index cec6ed1c91d3ed602733d93127d8b5fc2340275d..140ddbbc3a8a5509ddbabb6520bb1605ae038d70 100644 (file)
@@ -43,8 +43,8 @@ static struct map_desc msm_io_desc[] __initdata = {
        MSM_DEVICE(VIC),
        MSM_CHIP_DEVICE(CSR, MSM7X00),
        MSM_DEVICE(DMOV),
-       MSM_DEVICE(GPIO1),
-       MSM_DEVICE(GPIO2),
+       MSM_CHIP_DEVICE(GPIO1, MSM7X00),
+       MSM_CHIP_DEVICE(GPIO2, MSM7X00),
        MSM_DEVICE(CLK_CTL),
 #ifdef CONFIG_MSM_DEBUG_UART
        MSM_DEVICE(DEBUG_UART),
@@ -76,8 +76,8 @@ static struct map_desc qsd8x50_io_desc[] __initdata = {
        MSM_DEVICE(VIC),
        MSM_CHIP_DEVICE(CSR, QSD8X50),
        MSM_DEVICE(DMOV),
-       MSM_DEVICE(GPIO1),
-       MSM_DEVICE(GPIO2),
+       MSM_CHIP_DEVICE(GPIO1, QSD8X50),
+       MSM_CHIP_DEVICE(GPIO2, QSD8X50),
        MSM_DEVICE(CLK_CTL),
        MSM_DEVICE(SIRC),
        MSM_DEVICE(SCPLL),
@@ -135,8 +135,8 @@ static struct map_desc msm7x30_io_desc[] __initdata = {
        MSM_DEVICE(VIC),
        MSM_CHIP_DEVICE(CSR, MSM7X30),
        MSM_DEVICE(DMOV),
-       MSM_DEVICE(GPIO1),
-       MSM_DEVICE(GPIO2),
+       MSM_CHIP_DEVICE(GPIO1, MSM7X30),
+       MSM_CHIP_DEVICE(GPIO2, MSM7X30),
        MSM_DEVICE(CLK_CTL),
        MSM_DEVICE(CLK_CTL_SH2),
        MSM_DEVICE(AD5),
index d6336afe994836f5e3e870d2962738f292bd54f8..c51af1cac30040ee312f6416491c7535cb944d55 100644 (file)
@@ -260,7 +260,8 @@ mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys)
        return bus;
 }
 
-static int __init mv78xx0_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init mv78xx0_pcie_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        struct pcie_port *pp = bus_to_port(dev->bus->number);
 
index 15c600026aeeb683b6d30836fec658db1a12f39d..e400b09109ceb423c6e5ea041fd67102df6470b2 100644 (file)
@@ -41,8 +41,6 @@
 #define BABBAGE_POWER_KEY      IMX_GPIO_NR(2, 21)
 #define BABBAGE_ECSPI1_CS0     IMX_GPIO_NR(4, 24)
 #define BABBAGE_ECSPI1_CS1     IMX_GPIO_NR(4, 25)
-#define BABBAGE_SD1_CD         IMX_GPIO_NR(1, 0)
-#define BABBAGE_SD1_WP         IMX_GPIO_NR(1, 1)
 #define BABBAGE_SD2_CD         IMX_GPIO_NR(1, 6)
 #define BABBAGE_SD2_WP         IMX_GPIO_NR(1, 5)
 
@@ -146,8 +144,9 @@ static iomux_v3_cfg_t mx51babbage_pads[] = {
        MX51_PAD_SD1_DATA1__SD1_DATA1,
        MX51_PAD_SD1_DATA2__SD1_DATA2,
        MX51_PAD_SD1_DATA3__SD1_DATA3,
-       MX51_PAD_GPIO1_0__GPIO1_0,
-       MX51_PAD_GPIO1_1__GPIO1_1,
+       /* CD/WP from controller */
+       MX51_PAD_GPIO1_0__SD1_CD,
+       MX51_PAD_GPIO1_1__SD1_WP,
 
        /* SD 2 */
        MX51_PAD_SD2_CMD__SD2_CMD,
@@ -156,6 +155,7 @@ static iomux_v3_cfg_t mx51babbage_pads[] = {
        MX51_PAD_SD2_DATA1__SD2_DATA1,
        MX51_PAD_SD2_DATA2__SD2_DATA2,
        MX51_PAD_SD2_DATA3__SD2_DATA3,
+       /* CD/WP gpio */
        MX51_PAD_GPIO1_6__GPIO1_6,
        MX51_PAD_GPIO1_5__GPIO1_5,
 
@@ -340,13 +340,15 @@ static const struct spi_imx_master mx51_babbage_spi_pdata __initconst = {
 };
 
 static const struct esdhc_platform_data mx51_babbage_sd1_data __initconst = {
-       .cd_gpio = BABBAGE_SD1_CD,
-       .wp_gpio = BABBAGE_SD1_WP,
+       .cd_type = ESDHC_CD_CONTROLLER,
+       .wp_type = ESDHC_WP_CONTROLLER,
 };
 
 static const struct esdhc_platform_data mx51_babbage_sd2_data __initconst = {
        .cd_gpio = BABBAGE_SD2_CD,
        .wp_gpio = BABBAGE_SD2_WP,
+       .cd_type = ESDHC_CD_GPIO,
+       .wp_type = ESDHC_WP_GPIO,
 };
 
 /*
index 54be525e2bd75bb6eed97eefbd5e9bd9f181784f..4e1d51d252dc4cfd9dcf9f3e9fd2b7aea521451f 100644 (file)
@@ -210,11 +210,15 @@ static const struct gpio_keys_platform_data loco_button_data __initconst = {
 
 static const struct esdhc_platform_data mx53_loco_sd1_data __initconst = {
        .cd_gpio = LOCO_SD1_CD,
+       .cd_type = ESDHC_CD_GPIO,
+       .wp_type = ESDHC_WP_NONE,
 };
 
 static const struct esdhc_platform_data mx53_loco_sd3_data __initconst = {
        .cd_gpio = LOCO_SD3_CD,
        .wp_gpio = LOCO_SD3_WP,
+       .cd_type = ESDHC_CD_GPIO,
+       .wp_type = ESDHC_WP_GPIO,
 };
 
 static inline void mx53_loco_fec_reset(void)
index 23cd809fa8b8dab1f02c7d36e3f9e74effc0ec82..7f20308c4dbd3f2a949a77ab0d96e8555a6d9ad2 100644 (file)
@@ -1422,11 +1422,13 @@ DEFINE_CLOCK(ipu_di1_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG6_OFFSET,
        },
 
 static struct clk_lookup mx51_lookups[] = {
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
+       /* i.mx51 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
        _REGISTER_CLOCK(NULL, "gpt", gpt_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       /* i.mx51 has the i.mx27 type fec */
+       _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK("mxc_pwm.0", "pwm", pwm1_clk)
        _REGISTER_CLOCK("mxc_pwm.1", "pwm", pwm2_clk)
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
@@ -1446,7 +1448,8 @@ static struct clk_lookup mx51_lookups[] = {
        _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
        _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
        _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk)
-       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
+       /* i.mx51 has the i.mx35 type sdma */
+       _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk)
        _REGISTER_CLOCK(NULL, "ckih", ckih_clk)
        _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk)
        _REGISTER_CLOCK(NULL, "gpt_32k", gpt_32k_clk)
@@ -1454,10 +1457,10 @@ static struct clk_lookup mx51_lookups[] = {
        _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk)
        /* i.mx51 has the i.mx35 type cspi */
        _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx51.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx51.1", NULL, esdhc2_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx51.2", NULL, esdhc3_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx51.3", NULL, esdhc4_clk)
        _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk)
        _REGISTER_CLOCK(NULL, "iim_clk", iim_clk)
        _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
@@ -1470,29 +1473,32 @@ static struct clk_lookup mx51_lookups[] = {
 };
 
 static struct clk_lookup mx53_lookups[] = {
-       _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
-       _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
-       _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
-       _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk)
-       _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk)
+       /* i.mx53 has the i.mx21 type uart */
+       _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk)
+       _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk)
+       _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk)
+       _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk)
+       _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk)
        _REGISTER_CLOCK(NULL, "gpt", gpt_clk)
-       _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+       /* i.mx53 has the i.mx25 type fec */
+       _REGISTER_CLOCK("imx25-fec.0", NULL, fec_clk)
        _REGISTER_CLOCK(NULL, "iim_clk", iim_clk)
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
        _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
        _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_mx53_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_mx53_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_mx53_clk)
-       _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_mx53_clk)
        /* i.mx53 has the i.mx51 type ecspi */
        _REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk)
        _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk)
        /* i.mx53 has the i.mx25 type cspi */
        _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx53.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx53.1", NULL, esdhc2_mx53_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx53.2", NULL, esdhc3_mx53_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx53.3", NULL, esdhc4_mx53_clk)
        _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
        _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk)
-       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
+       /* i.mx53 has the i.mx35 type sdma */
+       _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk)
        _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
        _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
        _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk)
index ef8aec9319b63e45fa7adcbcd3b267dda62aac1c..baea6e5cddd96f782009daaebe72062557cb1b20 100644 (file)
@@ -115,7 +115,6 @@ static struct sdma_script_start_addrs imx51_sdma_script __initdata = {
 };
 
 static struct sdma_platform_data imx51_sdma_pdata __initdata = {
-       .sdma_version = 2,
        .fw_name = "sdma-imx51.bin",
        .script_addrs = &imx51_sdma_script,
 };
@@ -135,7 +134,6 @@ static struct sdma_script_start_addrs imx53_sdma_script __initdata = {
 };
 
 static struct sdma_platform_data imx53_sdma_pdata __initdata = {
-       .sdma_version = 2,
        .fw_name = "sdma-imx53.bin",
        .script_addrs = &imx53_sdma_script,
 };
@@ -148,7 +146,8 @@ void __init imx51_soc_init(void)
        mxc_register_gpio("imx31-gpio", 2, MX51_GPIO3_BASE_ADDR, SZ_16K, MX51_MXC_INT_GPIO3_LOW, MX51_MXC_INT_GPIO3_HIGH);
        mxc_register_gpio("imx31-gpio", 3, MX51_GPIO4_BASE_ADDR, SZ_16K, MX51_MXC_INT_GPIO4_LOW, MX51_MXC_INT_GPIO4_HIGH);
 
-       imx_add_imx_sdma(MX51_SDMA_BASE_ADDR, MX51_INT_SDMA, &imx51_sdma_pdata);
+       /* i.mx51 has the i.mx35 type sdma */
+       imx_add_imx_sdma("imx35-sdma", MX51_SDMA_BASE_ADDR, MX51_INT_SDMA, &imx51_sdma_pdata);
 }
 
 void __init imx53_soc_init(void)
@@ -162,5 +161,6 @@ void __init imx53_soc_init(void)
        mxc_register_gpio("imx31-gpio", 5, MX53_GPIO6_BASE_ADDR, SZ_16K, MX53_INT_GPIO6_LOW, MX53_INT_GPIO6_HIGH);
        mxc_register_gpio("imx31-gpio", 6, MX53_GPIO7_BASE_ADDR, SZ_16K, MX53_INT_GPIO7_LOW, MX53_INT_GPIO7_HIGH);
 
-       imx_add_imx_sdma(MX53_SDMA_BASE_ADDR, MX53_INT_SDMA, &imx53_sdma_pdata);
+       /* i.mx53 has the i.mx35 type sdma */
+       imx_add_imx_sdma("imx35-sdma", MX53_SDMA_BASE_ADDR, MX53_INT_SDMA, &imx53_sdma_pdata);
 }
index 56739c23aca7868f43c42b0af94042632f8f5084..4435e03cea5d844b77263829b03919c3d6ddd2d1 100644 (file)
@@ -260,8 +260,8 @@ static struct regulator_consumer_supply vvideo_consumers[] = {
 };
 
 static struct regulator_consumer_supply vsd_consumers[] = {
-       REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.0"),
-       REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"),
+       REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx51.0"),
+       REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx51.1"),
 };
 
 static struct regulator_consumer_supply pwgt1_consumer[] = {
index cc503aa89c5e3685b6cc5901a2329a67c6926d99..5a886cd2c598c408f3e007e01a5f5e2b0ae9ca94 100644 (file)
@@ -418,6 +418,10 @@ static struct regulator_consumer_supply rx51_vmmc1_supply[] = {
        REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
 };
 
+static struct regulator_consumer_supply rx51_vaux2_supply[] = {
+       REGULATOR_SUPPLY("vdds_csib", "omap3isp"),
+};
+
 static struct regulator_consumer_supply rx51_vaux3_supply[] = {
        REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
 };
@@ -479,6 +483,8 @@ static struct regulator_init_data rx51_vaux2 = {
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
                                        | REGULATOR_CHANGE_STATUS,
        },
+       .num_consumer_supplies  = ARRAY_SIZE(rx51_vaux2_supply),
+       .consumer_supplies      = rx51_vaux2_supply,
 };
 
 /* VAUX3 - adds more power to VIO_18 rail */
index 543fcb8b518cb227d967f32a03a0ed8d68b63400..a5b7a236aa5bf97867136373068765447e7b9838 100644 (file)
@@ -25,6 +25,7 @@
 #include <video/omapdss.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
+#include <plat/omap-pm.h>
 
 static struct platform_device omap_display_device = {
        .name          = "omapdss",
@@ -42,20 +43,6 @@ static struct omap_device_pm_latency omap_dss_latency[] = {
        },
 };
 
-/* oh_core is used for getting opt-clocks */
-static struct omap_hwmod       *oh_core;
-
-static bool opt_clock_available(const char *clk_role)
-{
-       int i;
-
-       for (i = 0; i < oh_core->opt_clks_cnt; i++) {
-               if (!strcmp(oh_core->opt_clks[i].role, clk_role))
-                       return true;
-       }
-       return false;
-}
-
 struct omap_dss_hwmod_data {
        const char *oh_name;
        const char *dev_name;
@@ -109,16 +96,9 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
                oh_count = ARRAY_SIZE(omap4_dss_hwmod_data);
        }
 
-       /* opt_clks are always associated with dss hwmod */
-       oh_core = omap_hwmod_lookup("dss_core");
-       if (!oh_core) {
-               pr_err("Could not look up dss_core.\n");
-               return -ENODEV;
-       }
-
        pdata.board_data = board_data;
-       pdata.board_data->get_last_off_on_transaction_id = NULL;
-       pdata.opt_clock_available = opt_clock_available;
+       pdata.board_data->get_context_loss_count =
+               omap_pm_get_dev_context_loss_count;
 
        for (i = 0; i < oh_count; i++) {
                oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name);
index f2b2b35e8646869332ff805224c0698631ca22f7..3e5499dda49a94482f7ef88b53600051d214c0e3 100644 (file)
@@ -51,7 +51,7 @@ void orion5x_pci_disable(void);
 void orion5x_pci_set_cardbus_mode(void);
 int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys);
 struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys);
-int orion5x_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
+int orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 
 struct machine_desc;
 struct meminfo;
index f95d3cb01cbf150cca8128f32d208ca3ec37b9ff..a3e3e9e5e328c7534ac2c1e753e52be7afaeb067 100644 (file)
@@ -237,7 +237,8 @@ void __init db88f5281_pci_preinit(void)
        }
 }
 
-static int __init db88f5281_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init db88f5281_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 855e0e77d56364f0ded6fd35c046458fe6ceacbc..a6eddae82a0b5b236db29658bbeb2c8b8a1d30ff 100644 (file)
@@ -70,14 +70,14 @@ enum {
  * PCI setup
  */
 
-static int __init dns323_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init dns323_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
        /*
         * Check for devices with hard-wired IRQs.
         */
-       irq = orion5x_pci_map_irq(dev, slot, pin);
+       irq = orion5x_pci_map_irq(const dev, slot, pin);
        if (irq != -1)
                return irq;
 
index c0eb6462633f067927297442942ce3e0c942eaba..00381249d7665ef6fea66d57f53cc2127d09814b 100644 (file)
@@ -119,7 +119,8 @@ static struct platform_device kurobox_pro_nor_flash = {
  * PCI
  ****************************************************************************/
 
-static int __init kurobox_pro_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init kurobox_pro_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 59263b73d1e4b20d1f9137189b54a249bfbc20fe..ef3bb8e9a4c2dd8bf55ce41ecc9c23f944e46a8e 100644 (file)
@@ -73,7 +73,7 @@ static struct platform_device mss2_nor_flash = {
 /****************************************************************************
  * PCI setup
  ****************************************************************************/
-static int __init mss2_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init mss2_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index f64965d4f8e8c277ae94b363e104e98beaf1144a..28b8760ab9fa07c6e09128811bbfa3dd1ba1cffb 100644 (file)
@@ -589,7 +589,7 @@ struct pci_bus __init *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys
        return bus;
 }
 
-int __init orion5x_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int __init orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int bus = dev->bus->number;
 
index 9eec7c2375e9bbf5cdb059d96859c0495ece997f..291d22bf44c9bf8d4a91b0d00b2e5c0ecbe63828 100644 (file)
@@ -131,7 +131,7 @@ static void __init rd88f5181l_fxo_init(void)
 }
 
 static int __init
-rd88f5181l_fxo_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+rd88f5181l_fxo_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 0cc90bbfd32670bc4bf4017f956893628d40ea4f..3f02362e1632bdfca2b4679557f899e1def14464 100644 (file)
@@ -140,7 +140,7 @@ static void __init rd88f5181l_ge_init(void)
 }
 
 static int __init
-rd88f5181l_ge_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+rd88f5181l_ge_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 48da39b9bdb0ca0e1f6f484c03b7cf7c84936b6b..27fd38e658bd882f620999f80bd702ec32feff30 100644 (file)
@@ -172,7 +172,8 @@ void __init rd88f5182_pci_preinit(void)
        }
 }
 
-static int __init rd88f5182_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init rd88f5182_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 29ce826c3c214e445324b3ed93a06a6b2a40c175..a34e4fac72b00993ac60ab69b1f0822810157a52 100644 (file)
@@ -100,7 +100,7 @@ void __init tsp2_pci_preinit(void)
        }
 }
 
-static int __init tsp2_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init tsp2_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 47162fd5f0447264af65d8713eca042ce2010d0d..c9831614e355c9dcc22090766bc8136972a8d71e 100644 (file)
@@ -143,7 +143,8 @@ void __init qnap_ts209_pci_preinit(void)
        }
 }
 
-static int __init qnap_ts209_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init qnap_ts209_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 5aacc7ac5cf4dac165b000f9bc54541b6cc18a7d..cc33b2222bad74858444466a9c939113876ac461 100644 (file)
@@ -121,7 +121,8 @@ static struct platform_device qnap_ts409_nor_flash = {
  * PCI
  ****************************************************************************/
 
-static int __init qnap_ts409_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init qnap_ts409_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 444a1c7fdfd6689e486e0380382825ee35b69579..2653595f901c598e012f6e5ae77f97a03d201157 100644 (file)
@@ -133,7 +133,8 @@ static void __init wnr854t_init(void)
        platform_device_register(&wnr854t_nor_flash);
 }
 
-static int __init wnr854t_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init wnr854t_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index d1952be0ae1c8c8a8d13c3fa5d6215b9c12b4ebe..251ef1543e53d3f0c2e3742a76183bf839204954 100644 (file)
@@ -221,7 +221,8 @@ static void __init wrt350n_v2_init(void)
        platform_device_register(&wrt350n_v2_button_device);
 }
 
-static int __init wrt350n_v2_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init wrt350n_v2_pci_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        int irq;
 
index 4eb7660a279d3f5d04407b44c09808dca90ac2b4..6bf479d9b5ac5ffd154dc281d407d76ce1817a86 100644 (file)
@@ -77,7 +77,7 @@ void cmx2xx_pci_resume(void) {}
 #endif
 
 /* PCI IRQ mapping*/
-static int __init cmx2xx_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init cmx2xx_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 5fc074fe3eeee535f0d3909a9036ad190752d20c..964c6c3cd7a668285b53a3ebcc7eed15bce2bf91 100644 (file)
@@ -122,7 +122,8 @@ static struct pci_ops pci_nano_ops = {
        .write  = nanoengine_write_config,
 };
 
-static int __init pci_nanoengine_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init pci_nanoengine_map_irq(const struct pci_dev *dev, u8 slot,
+       u8 pin)
 {
        return NANOENGINE_IRQ_GPIO_PCI;
 }
index 92d7227de0ac5648cc42a1097343d2f0a71e8779..7cb79a092f316571e68b8352d85bf0b8c42c14b5 100644 (file)
@@ -14,7 +14,7 @@
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
-static int __init shark_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init shark_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (dev->bus->number == 0)
                if (dev->devfn == 0)
index 837138e369bc162ca46e94327bfbe0e2fde84ea6..9e0856b2f9e9fcc8adb4455267e0ec4964efa56d 100644 (file)
@@ -957,19 +957,16 @@ static struct resource csi2_resources[] = {
        },
 };
 
-static struct platform_device csi2_device = {
-       .name   = "sh-mobile-csi2",
-       .id     = 0,
+static struct sh_mobile_ceu_companion csi2 = {
+       .id             = 0,
        .num_resources  = ARRAY_SIZE(csi2_resources),
        .resource       = csi2_resources,
-       .dev    = {
-               .platform_data = &csi2_info,
-       },
+       .platform_data  = &csi2_info,
 };
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
        .flags = SH_CEU_FLAG_USE_8BIT_BUS,
-       .csi2_dev = &csi2_device.dev,
+       .csi2 = &csi2,
 };
 
 static struct resource ceu_resources[] = {
@@ -1013,7 +1010,6 @@ static struct platform_device *ap4evb_devices[] __initdata = {
        &lcdc1_device,
        &lcdc_device,
        &hdmi_device,
-       &csi2_device,
        &ceu_device,
        &ap4evb_camera,
        &meram_device,
index 5b36b6c5b448714d044fe1eb7fd8c9c2827cd95b..d41c01f83f152f75589cc228a186a6f98da59a5e 100644 (file)
@@ -1192,8 +1192,8 @@ static struct platform_device sh_mmcif_device = {
 };
 
 
-static int mackerel_camera_add(struct soc_camera_link *icl, struct device *dev);
-static void mackerel_camera_del(struct soc_camera_link *icl);
+static int mackerel_camera_add(struct soc_camera_device *icd);
+static void mackerel_camera_del(struct soc_camera_device *icd);
 
 static int camera_set_capture(struct soc_camera_platform_info *info,
                              int enable)
@@ -1232,16 +1232,15 @@ static void mackerel_camera_release(struct device *dev)
        soc_camera_platform_release(&camera_device);
 }
 
-static int mackerel_camera_add(struct soc_camera_link *icl,
-                              struct device *dev)
+static int mackerel_camera_add(struct soc_camera_device *icd)
 {
-       return soc_camera_platform_add(icl, dev, &camera_device, &camera_link,
+       return soc_camera_platform_add(icd, &camera_device, &camera_link,
                                       mackerel_camera_release, 0);
 }
 
-static void mackerel_camera_del(struct soc_camera_link *icl)
+static void mackerel_camera_del(struct soc_camera_device *icd)
 {
-       soc_camera_platform_del(icl, camera_device, &camera_link);
+       soc_camera_platform_del(icd, camera_device, &camera_link);
 }
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
index 6b186aefcbd63792e22167e47fda0d02a9d9fcef..5218c34a9cc6b77994d1f51966679a9b2e5fee73 100644 (file)
@@ -259,9 +259,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [CMMSTP003] = MSTP(&r_clk, CMMSTPCR0, 3, 0), /* KEYSC */
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("r_clk", &r_clk),
index 91f5779abdd34c9160a79a60916a31bfd714888a..6b1619a65dbac16bf4535f106ab3b2c03016ed9f 100644 (file)
@@ -561,10 +561,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
-#define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("dv_clki_div2_clk", &sh7372_dv_clki_div2_clk),
index 95942466e63f212fb89c8d7392c15b7507afcb34..8cee7b151ae3fed0eec3840fdde5fe7f05195027 100644 (file)
@@ -267,9 +267,6 @@ static struct clk mstp_clks[] = {
        [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("r_clk", &r_clk),
index bcacb1e8cf85148e79d75b423de47d0f8e61ccbc..6db2ccabc2bf95fe0cf4d99a90b382d0271d116c 100644 (file)
@@ -306,10 +306,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
-#define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("r_clk", &r_clk),
index 5ec1846aa1d0d13c17b143cd72235919b8bc5f26..d82ebab50e1129950c9a29891e103e8854066b83 100644 (file)
@@ -27,14 +27,14 @@ comment "Tegra board type"
 
 config MACH_HARMONY
        bool "Harmony board"
-       select MACH_HAS_SND_SOC_TEGRA_WM8903
+       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
        help
          Support for nVidia Harmony development platform
 
 config MACH_KAEN
        bool "Kaen board"
        select MACH_SEABOARD
-       select MACH_HAS_SND_SOC_TEGRA_WM8903
+       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
        help
          Support for the Kaen version of Seaboard
 
@@ -45,12 +45,18 @@ config MACH_PAZ00
 
 config MACH_SEABOARD
        bool "Seaboard board"
-       select MACH_HAS_SND_SOC_TEGRA_WM8903
+       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
        help
          Support for nVidia Seaboard development platform. It will
         also be included for some of the derivative boards that
         have large similarities with the seaboard design.
 
+config MACH_TEGRA_DT
+       bool "Generic Tegra board (FDT support)"
+       select USE_OF
+       help
+         Support for generic nVidia Tegra boards using Flattened Device Tree
+
 config MACH_TRIMSLICE
        bool "TrimSlice board"
        select TEGRA_PCI
index ed58ef9019b51141009b87acab3fafcb66749bbe..f11b9100114a2b8ff212fcb5292849f63279483e 100644 (file)
@@ -29,5 +29,8 @@ obj-${CONFIG_MACH_PAZ00}              += board-paz00-pinmux.o
 obj-${CONFIG_MACH_SEABOARD}             += board-seaboard.o
 obj-${CONFIG_MACH_SEABOARD}             += board-seaboard-pinmux.o
 
+obj-${CONFIG_MACH_TEGRA_DT}             += board-dt.o
+obj-${CONFIG_MACH_TEGRA_DT}             += board-harmony-pinmux.o
+
 obj-${CONFIG_MACH_TRIMSLICE}            += board-trimslice.o
 obj-${CONFIG_MACH_TRIMSLICE}            += board-trimslice-pinmux.o
index db52d61a73860cb0b4c19fa6c488303cbe15c210..428ad122be0394ca3b61b01c3d2159a1c83457bf 100644 (file)
@@ -1,3 +1,6 @@
 zreladdr-$(CONFIG_ARCH_TEGRA_2x_SOC)   := 0x00008000
 params_phys-$(CONFIG_ARCH_TEGRA_2x_SOC)        := 0x00000100
 initrd_phys-$(CONFIG_ARCH_TEGRA_2x_SOC)        := 0x00800000
+
+dtb-$(CONFIG_MACH_HARMONY) += tegra-harmony.dtb
+dtb-$(CONFIG_MACH_SEABOARD) += tegra-seaboard.dtb
diff --git a/arch/arm/mach-tegra/board-dt.c b/arch/arm/mach-tegra/board-dt.c
new file mode 100644 (file)
index 0000000..9f47e04
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * nVidia Tegra device tree board support
+ *
+ * Copyright (C) 2010 Secret Lab Technologies, Ltd.
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/pda_power.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/setup.h>
+
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+
+#include "board.h"
+#include "board-harmony.h"
+#include "clock.h"
+#include "devices.h"
+
+void harmony_pinmux_init(void);
+void seaboard_pinmux_init(void);
+
+
+struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC4_BASE, "sdhci-tegra.3", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C_BASE, "tegra-i2c.0", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_DVC_BASE, "tegra-i2c.3", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.1", NULL),
+       OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL),
+       {}
+};
+
+static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
+       /* name         parent          rate            enabled */
+       { "uartd",      "pll_p",        216000000,      true },
+       { NULL,         NULL,           0,              0},
+};
+
+static struct of_device_id tegra_dt_match_table[] __initdata = {
+       { .compatible = "simple-bus", },
+       {}
+};
+
+static struct of_device_id tegra_dt_gic_match[] __initdata = {
+       { .compatible = "nvidia,tegra20-gic", },
+       {}
+};
+
+static void __init tegra_dt_init(void)
+{
+       struct device_node *node;
+
+       node = of_find_matching_node_by_address(NULL, tegra_dt_gic_match,
+                                               TEGRA_ARM_INT_DIST_BASE);
+       if (node)
+               irq_domain_add_simple(node, INT_GIC_BASE);
+
+       tegra_clk_init_from_table(tegra_dt_clk_init_table);
+
+       if (of_machine_is_compatible("nvidia,harmony"))
+               harmony_pinmux_init();
+       else if (of_machine_is_compatible("nvidia,seaboard"))
+               seaboard_pinmux_init();
+
+       /*
+        * Finished with the static registrations now; fill in the missing
+        * devices
+        */
+       of_platform_populate(NULL, tegra_dt_match_table, tegra20_auxdata_lookup, NULL);
+}
+
+static const char * tegra_dt_board_compat[] = {
+       "nvidia,harmony",
+       "nvidia,seaboard",
+       NULL
+};
+
+DT_MACHINE_START(TEGRA_DT, "nVidia Tegra (Flattened Device Tree)")
+       .map_io         = tegra_map_common_io,
+       .init_early     = tegra_init_early,
+       .init_irq       = tegra_init_irq,
+       .timer          = &tegra_timer,
+       .init_machine   = tegra_dt_init,
+       .dt_compat      = tegra_dt_board_compat,
+MACHINE_END
index 031cd0a7d71d7a22cd6cfb00e321d060ac192b98..f1f699d86c3278c90c514bd7ac3daec35b2fc7cb 100644 (file)
@@ -449,7 +449,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        return 1;
 }
 
-static int tegra_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int tegra_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        return INT_PCIE_INTR;
 }
index 9cdec5aa04a04bf57eb66a5bcc2c5966c3f99629..c1f38f6625b21a22dc4b620bae6838901b7eb97b 100644 (file)
@@ -17,4 +17,12 @@ config MACH_VERSATILE_AB
          Include support for the ARM(R) Versatile Application Baseboard
          for the ARM926EJ-S.
 
+config MACH_VERSATILE_DT
+       bool "Support Versatile platform from device tree"
+       select USE_OF
+       select CPU_ARM926T
+       help
+         Include support for the ARM(R) Versatile/PB platform,
+         using the device tree for discovery
+
 endmenu
index 97cf4d831b0c5bf6de35653f574b1788952a10fe..81fa3fe25e1aedbacdd9f8de8c5640fe548bf80b 100644 (file)
@@ -5,4 +5,5 @@
 obj-y                                  := core.o
 obj-$(CONFIG_ARCH_VERSATILE_PB)                += versatile_pb.o
 obj-$(CONFIG_MACH_VERSATILE_AB)                += versatile_ab.o
+obj-$(CONFIG_MACH_VERSATILE_DT)                += versatile_dt.o
 obj-$(CONFIG_PCI)                      += pci.o
index 0c99cf076c63a2a24c824d61c1fd1912065f0cd5..e340a54251df5d1245f1e913c91587fb23f48fd7 100644 (file)
@@ -24,6 +24,9 @@
 #include <linux/platform_device.h>
 #include <linux/sysdev.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
 #include <linux/amba/pl061.h>
@@ -83,13 +86,26 @@ static struct fpga_irq_data sic_irq = {
 #define PIC_MASK       0
 #endif
 
+/* Lookup table for finding a DT node that represents the vic instance */
+static const struct of_device_id vic_of_match[] __initconst = {
+       { .compatible = "arm,versatile-vic", },
+       {}
+};
+
+static const struct of_device_id sic_of_match[] __initconst = {
+       { .compatible = "arm,versatile-sic", },
+       {}
+};
+
 void __init versatile_init_irq(void)
 {
        vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0);
+       irq_domain_generate_simple(vic_of_match, VERSATILE_VIC_BASE, IRQ_VIC_START);
 
        writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
 
        fpga_irq_init(IRQ_VICSOURCE31, ~PIC_MASK, &sic_irq);
+       irq_domain_generate_simple(sic_of_match, VERSATILE_SIC_BASE, IRQ_SIC_START);
 
        /*
         * Interrupts on secondary controller from 0 to 8 are routed to
@@ -646,6 +662,52 @@ static struct amba_device *amba_devs[] __initdata = {
        &kmi1_device,
 };
 
+#ifdef CONFIG_OF
+/*
+ * Lookup table for attaching a specific name and platform_data pointer to
+ * devices as they get created by of_platform_populate().  Ideally this table
+ * would not exist, but the current clock implementation depends on some devices
+ * having a specific name.
+ */
+struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = {
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_KMI0_BASE, "fpga:06", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_KMI1_BASE, "fpga:07", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART3_BASE, "fpga:09", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", NULL),
+
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_CLCD_BASE, "dev:20", &clcd_plat_data),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART0_BASE, "dev:f1", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART1_BASE, "dev:f2", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_UART2_BASE, "dev:f3", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_SSP_BASE, "dev:f4", NULL),
+
+#if 0
+       /*
+        * These entries are unnecessary because no clocks referencing
+        * them.  I've left them in for now as place holders in case
+        * any of them need to be added back, but they should be
+        * removed before actually committing this patch.  --gcl
+        */
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_AACI_BASE, "fpga:04", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCI1_BASE, "fpga:0a", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_SMC_BASE, "dev:00", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_MPMC_BASE, "dev:10", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_DMAC_BASE, "dev:30", NULL),
+
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCTL_BASE, "dev:e0", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_WATCHDOG_BASE, "dev:e1", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO0_BASE, "dev:e4", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO1_BASE, "dev:e5", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO2_BASE, "dev:e6", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_GPIO3_BASE, "dev:e7", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_RTC_BASE, "dev:e8", NULL),
+       OF_DEV_AUXDATA("arm,primecell", VERSATILE_SCI_BASE, "dev:f0", NULL),
+#endif
+       {}
+};
+#endif
+
 #ifdef CONFIG_LEDS
 #define VA_LEDS_BASE (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET)
 
index fd6404e5d788245174cfcbb9bf0e143f5c44950e..e01422700ebb50a3621943276a054b1f74d5b6ed 100644 (file)
@@ -23,6 +23,7 @@
 #define __ASM_ARCH_VERSATILE_H
 
 #include <linux/amba/bus.h>
+#include <linux/of_platform.h>
 
 extern void __init versatile_init(void);
 extern void __init versatile_init_early(void);
@@ -30,6 +31,9 @@ extern void __init versatile_init_irq(void);
 extern void __init versatile_map_io(void);
 extern struct sys_timer versatile_timer;
 extern unsigned int mmc_status(struct device *dev);
+#ifdef CONFIG_OF
+extern struct of_dev_auxdata versatile_auxdata_lookup[];
+#endif
 
 #define AMBA_DEVICE(name,busid,base,plat)                      \
 static struct amba_device name##_device = {                    \
index 7848a177b1f0eb27ccf031e817168599a58f6d16..c898deb3ada01f2b5dacd1cd93e3e99dd8a7e3a7 100644 (file)
@@ -328,7 +328,7 @@ void __init pci_versatile_preinit(void)
 /*
  * map the specified device/slot/pin to an IRQ.   Different backplanes may need to modify this.
  */
-static int __init versatile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init versatile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
        int devslot = PCI_SLOT(dev->devfn);
diff --git a/arch/arm/mach-versatile/versatile_dt.c b/arch/arm/mach-versatile/versatile_dt.c
new file mode 100644 (file)
index 0000000..54e037c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Versatile board support using the device tree
+ *
+ *  Copyright (C) 2010 Secret Lab Technologies Ltd.
+ *  Copyright (C) 2009 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *  Copyright (C) 2004 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This 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/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include "core.h"
+
+static void __init versatile_dt_init(void)
+{
+       of_platform_populate(NULL, of_default_bus_match_table,
+                            versatile_auxdata_lookup, NULL);
+}
+
+static const char *versatile_dt_match[] __initconst = {
+       "arm,versatile-ab",
+       "arm,versatile-pb",
+       NULL,
+};
+
+DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)")
+       .map_io         = versatile_map_io,
+       .init_early     = versatile_init_early,
+       .init_irq       = versatile_init_irq,
+       .timer          = &versatile_timer,
+       .init_machine   = versatile_dt_init,
+       .dt_compat      = versatile_dt_match,
+MACHINE_END
index c550c67aa8934ddf3548923d56df7a62a384d813..397268c1b2501ac0291d8344ef3098735468f0fa 100644 (file)
@@ -3,4 +3,4 @@
 #
 
 # Common support
-obj-y                          := common.o timer.o board_dt.o
+obj-y                          := common.o timer.o
diff --git a/arch/arm/mach-zynq/board_dt.c b/arch/arm/mach-zynq/board_dt.c
deleted file mode 100644 (file)
index e69de29..0000000
index 4fc6ffc2a13e08590895ce2a3878a5c8b971a305..0bae44e890db14e262cfdb46c50b09fb12279bf6 100644 (file)
 #include <mach/hardware.h>
 #include <mach/devices-common.h>
 
-#define imx_fec_data_entry_single(soc)                                 \
+#define imx_fec_data_entry_single(soc, _devid)                         \
        {                                                               \
+               .devid = _devid,                                        \
                .iobase = soc ## _FEC_BASE_ADDR,                        \
                .irq = soc ## _INT_FEC,                                 \
        }
 
 #ifdef CONFIG_SOC_IMX25
 const struct imx_fec_data imx25_fec_data __initconst =
-       imx_fec_data_entry_single(MX25);
+       imx_fec_data_entry_single(MX25, "imx25-fec");
 #endif /* ifdef CONFIG_SOC_IMX25 */
 
 #ifdef CONFIG_SOC_IMX27
 const struct imx_fec_data imx27_fec_data __initconst =
-       imx_fec_data_entry_single(MX27);
+       imx_fec_data_entry_single(MX27, "imx27-fec");
 #endif /* ifdef CONFIG_SOC_IMX27 */
 
 #ifdef CONFIG_SOC_IMX35
+/* i.mx35 has the i.mx27 type fec */
 const struct imx_fec_data imx35_fec_data __initconst =
-       imx_fec_data_entry_single(MX35);
+       imx_fec_data_entry_single(MX35, "imx27-fec");
 #endif
 
 #ifdef CONFIG_SOC_IMX50
+/* i.mx50 has the i.mx25 type fec */
 const struct imx_fec_data imx50_fec_data __initconst =
-       imx_fec_data_entry_single(MX50);
+       imx_fec_data_entry_single(MX50, "imx25-fec");
 #endif
 
 #ifdef CONFIG_SOC_IMX51
+/* i.mx51 has the i.mx27 type fec */
 const struct imx_fec_data imx51_fec_data __initconst =
-       imx_fec_data_entry_single(MX51);
+       imx_fec_data_entry_single(MX51, "imx27-fec");
 #endif
 
 #ifdef CONFIG_SOC_IMX53
+/* i.mx53 has the i.mx25 type fec */
 const struct imx_fec_data imx53_fec_data __initconst =
-       imx_fec_data_entry_single(MX53);
+       imx_fec_data_entry_single(MX53, "imx25-fec");
 #endif
 
 struct platform_device *__init imx_add_fec(
@@ -63,7 +68,7 @@ struct platform_device *__init imx_add_fec(
                },
        };
 
-       return imx_add_platform_device_dmamask("fec", 0,
+       return imx_add_platform_device_dmamask(data->devid, 0,
                        res, ARRAY_SIZE(res),
                        pdata, sizeof(*pdata), DMA_BIT_MASK(32));
 }
index 2b0fdb23beb873221531086c8fd14ef22e9631a9..7fa7e9c9246803f74e95c97719009b3387ad660a 100644 (file)
@@ -14,7 +14,7 @@ struct platform_device __init __maybe_unused *imx_add_imx_dma(void)
                        "imx-dma", -1, NULL, 0, NULL, 0);
 }
 
-struct platform_device __init __maybe_unused *imx_add_imx_sdma(
+struct platform_device __init __maybe_unused *imx_add_imx_sdma(char *name,
        resource_size_t iobase, int irq, struct sdma_platform_data *pdata)
 {
        struct resource res[] = {
@@ -29,6 +29,6 @@ struct platform_device __init __maybe_unused *imx_add_imx_sdma(
                },
        };
 
-       return platform_device_register_resndata(&mxc_ahb_bus, "imx-sdma",
+       return platform_device_register_resndata(&mxc_ahb_bus, name,
                        -1, res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
index cfce8c918b73521e4261b3018cf55f11462113c8..2020d84956c34c4f13662d5e867c064b21ef4dc9 100644 (file)
@@ -152,7 +152,7 @@ struct platform_device *__init imx_add_imx_uart_3irq(
                },
        };
 
-       return imx_add_platform_device("imx-uart", data->id, res,
+       return imx_add_platform_device("imx1-uart", data->id, res,
                        ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
 
@@ -172,6 +172,7 @@ struct platform_device *__init imx_add_imx_uart_1irq(
                },
        };
 
-       return imx_add_platform_device("imx-uart", data->id, res, ARRAY_SIZE(res),
-                       pdata, sizeof(*pdata));
+       /* i.mx21 type uart runs on all i.mx except i.mx1 */
+       return imx_add_platform_device("imx21-uart", data->id,
+                       res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
index 6b2940b93d943a416361202dee46dcca92d40567..5955f5da82ee8796e199cbe11f2473c9df718ca5 100644 (file)
 #include <mach/devices-common.h>
 #include <mach/esdhc.h>
 
-#define imx_sdhci_esdhc_imx_data_entry_single(soc, _id, hwid) \
+#define imx_sdhci_esdhc_imx_data_entry_single(soc, _devid, _id, hwid) \
        {                                                               \
+               .devid = _devid,                                        \
                .id = _id,                                              \
                .iobase = soc ## _ESDHC ## hwid ## _BASE_ADDR,  \
                .irq = soc ## _INT_ESDHC ## hwid,                       \
        }
 
-#define imx_sdhci_esdhc_imx_data_entry(soc, id, hwid)  \
-       [id] = imx_sdhci_esdhc_imx_data_entry_single(soc, id, hwid)
+#define imx_sdhci_esdhc_imx_data_entry(soc, devid, id, hwid)   \
+       [id] = imx_sdhci_esdhc_imx_data_entry_single(soc, devid, id, hwid)
 
 #ifdef CONFIG_SOC_IMX25
 const struct imx_sdhci_esdhc_imx_data
 imx25_sdhci_esdhc_imx_data[] __initconst = {
 #define imx25_sdhci_esdhc_imx_data_entry(_id, _hwid)                   \
-       imx_sdhci_esdhc_imx_data_entry(MX25, _id, _hwid)
+       imx_sdhci_esdhc_imx_data_entry(MX25, "sdhci-esdhc-imx25", _id, _hwid)
        imx25_sdhci_esdhc_imx_data_entry(0, 1),
        imx25_sdhci_esdhc_imx_data_entry(1, 2),
 };
@@ -34,7 +35,7 @@ imx25_sdhci_esdhc_imx_data[] __initconst = {
 const struct imx_sdhci_esdhc_imx_data
 imx35_sdhci_esdhc_imx_data[] __initconst = {
 #define imx35_sdhci_esdhc_imx_data_entry(_id, _hwid)                   \
-       imx_sdhci_esdhc_imx_data_entry(MX35, _id, _hwid)
+       imx_sdhci_esdhc_imx_data_entry(MX35, "sdhci-esdhc-imx35", _id, _hwid)
        imx35_sdhci_esdhc_imx_data_entry(0, 1),
        imx35_sdhci_esdhc_imx_data_entry(1, 2),
        imx35_sdhci_esdhc_imx_data_entry(2, 3),
@@ -45,7 +46,7 @@ imx35_sdhci_esdhc_imx_data[] __initconst = {
 const struct imx_sdhci_esdhc_imx_data
 imx51_sdhci_esdhc_imx_data[] __initconst = {
 #define imx51_sdhci_esdhc_imx_data_entry(_id, _hwid)                   \
-       imx_sdhci_esdhc_imx_data_entry(MX51, _id, _hwid)
+       imx_sdhci_esdhc_imx_data_entry(MX51, "sdhci-esdhc-imx51", _id, _hwid)
        imx51_sdhci_esdhc_imx_data_entry(0, 1),
        imx51_sdhci_esdhc_imx_data_entry(1, 2),
        imx51_sdhci_esdhc_imx_data_entry(2, 3),
@@ -57,7 +58,7 @@ imx51_sdhci_esdhc_imx_data[] __initconst = {
 const struct imx_sdhci_esdhc_imx_data
 imx53_sdhci_esdhc_imx_data[] __initconst = {
 #define imx53_sdhci_esdhc_imx_data_entry(_id, _hwid)                   \
-       imx_sdhci_esdhc_imx_data_entry(MX53, _id, _hwid)
+       imx_sdhci_esdhc_imx_data_entry(MX53, "sdhci-esdhc-imx53", _id, _hwid)
        imx53_sdhci_esdhc_imx_data_entry(0, 1),
        imx53_sdhci_esdhc_imx_data_entry(1, 2),
        imx53_sdhci_esdhc_imx_data_entry(2, 3),
@@ -65,6 +66,11 @@ imx53_sdhci_esdhc_imx_data[] __initconst = {
 };
 #endif /* ifdef CONFIG_SOC_IMX53 */
 
+static const struct esdhc_platform_data default_esdhc_pdata __initconst = {
+       .wp_type = ESDHC_WP_NONE,
+       .cd_type = ESDHC_CD_NONE,
+};
+
 struct platform_device *__init imx_add_sdhci_esdhc_imx(
                const struct imx_sdhci_esdhc_imx_data *data,
                const struct esdhc_platform_data *pdata)
@@ -81,6 +87,13 @@ struct platform_device *__init imx_add_sdhci_esdhc_imx(
                },
        };
 
-       return imx_add_platform_device("sdhci-esdhc-imx", data->id, res,
+       /*
+        * If machine does not provide pdata, use the default one
+        * which means no WP/CD support
+        */
+       if (!pdata)
+               pdata = &default_esdhc_pdata;
+
+       return imx_add_platform_device(data->devid, data->id, res,
                        ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
index bf93820ab61cd03ac5f4c1d57fef094e388aa8cd..524538aabc4bd2b5da340d963a4030aea5095e73 100644 (file)
@@ -30,6 +30,7 @@ static inline struct platform_device *imx_add_platform_device(
 
 #include <linux/fec.h>
 struct imx_fec_data {
+       const char *devid;
        resource_size_t iobase;
        resource_size_t irq;
 };
@@ -276,6 +277,7 @@ struct platform_device *__init imx_add_mxc_w1(
 
 #include <mach/esdhc.h>
 struct imx_sdhci_esdhc_imx_data {
+       const char *devid;
        int id;
        resource_size_t iobase;
        resource_size_t irq;
@@ -297,5 +299,5 @@ struct platform_device *__init imx_add_spi_imx(
                const struct spi_imx_master *pdata);
 
 struct platform_device *imx_add_imx_dma(void);
-struct platform_device *imx_add_imx_sdma(
+struct platform_device *imx_add_imx_sdma(char *name,
        resource_size_t iobase, int irq, struct sdma_platform_data *pdata);
index ef7751546f5f0fa45bbd83fab25d19226c3e15dd..233d0a5e2d68f1451b29ce18e331a384fabaf5a5 100644 (file)
@@ -60,7 +60,8 @@ static inline int imx_dma_is_ipu(struct dma_chan *chan)
 
 static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
 {
-       return !strcmp(dev_name(chan->device->dev), "imx-sdma") ||
+       return !strcmp(dev_name(chan->device->dev), "imx31-sdma") ||
+               !strcmp(dev_name(chan->device->dev), "imx35-sdma") ||
                !strcmp(dev_name(chan->device->dev), "imx-dma");
 }
 
index 86003f411755f02d29a937e547b9191a39cf4b77..aaf97481f41384650a7a3272e283ee68b9cfd1c7 100644 (file)
 #ifndef __ASM_ARCH_IMX_ESDHC_H
 #define __ASM_ARCH_IMX_ESDHC_H
 
+enum wp_types {
+       ESDHC_WP_NONE,          /* no WP, neither controller nor gpio */
+       ESDHC_WP_CONTROLLER,    /* mmc controller internal WP */
+       ESDHC_WP_GPIO,          /* external gpio pin for WP */
+};
+
+enum cd_types {
+       ESDHC_CD_NONE,          /* no CD, neither controller nor gpio */
+       ESDHC_CD_CONTROLLER,    /* mmc controller internal CD */
+       ESDHC_CD_GPIO,          /* external gpio pin for CD */
+       ESDHC_CD_PERMANENT,     /* no CD, card permanently wired to host */
+};
+
 /**
- * struct esdhc_platform_data - optional platform data for esdhc on i.MX
+ * struct esdhc_platform_data - platform data for esdhc on i.MX
  *
- * strongly recommended for i.MX25/35, not needed for other variants
+ * ESDHC_WP(CD)_CONTROLLER type is not available on i.MX25/35.
  *
- * @wp_gpio:   gpio for write_protect (-EINVAL if unused)
- * @cd_gpio:   gpio for card_detect interrupt (-EINVAL if unused)
+ * @wp_gpio:   gpio for write_protect
+ * @cd_gpio:   gpio for card_detect interrupt
+ * @wp_type:   type of write_protect method (see wp_types enum above)
+ * @cd_type:   type of card_detect method (see cd_types enum above)
  */
 
 struct esdhc_platform_data {
        unsigned int wp_gpio;
        unsigned int cd_gpio;
+       enum wp_types wp_type;
+       enum cd_types cd_type;
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */
index f495c87c113fc269020d0ec49397c2bfc24d3ff0..3a3942823c209163501b1dcd49a550d1664c56da 100644 (file)
@@ -48,12 +48,10 @@ struct sdma_script_start_addrs {
 /**
  * struct sdma_platform_data - platform specific data for SDMA engine
  *
- * @sdma_version       The version of this SDMA engine
  * @fw_name            The firmware name
  * @script_addrs       SDMA scripts addresses in SDMA ROM
  */
 struct sdma_platform_data {
-       int sdma_version;
        char *fw_name;
        struct sdma_script_start_addrs *script_addrs;
 };
index c42c83d507bc42c2208b21ff978d92e84c42d161..4fb63a36bd52ff0333f9d849a0a75479008aaa5e 100644 (file)
@@ -133,13 +133,7 @@ void pgd_dtor(void *pgd)
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-       pgd_t *pgd;
-
-       pgd = quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
-       if (!pgd)
-               return pgd;
-
-       return pgd;
+       return quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
 }
 
 void pgd_free(struct mm_struct *mm, pgd_t *pgd)
index 16539b1d5d3a9d06b86bce31690a38f28818c983..13e20bbc4079d9def59115f4462b4a93bbc53fed 100644 (file)
@@ -372,12 +372,6 @@ config AMIGA_PCMCIA
          Include support in the kernel for pcmcia on Amiga 1200 and Amiga
          600. If you intend to use pcmcia cards say Y; otherwise say N.
 
-config STRAM_PROC
-       bool "ST-RAM statistics in /proc"
-       depends on ATARI
-       help
-         Say Y here to report ST-RAM usage statistics in /proc/stram.
-
 config HEARTBEAT
        bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
        default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
index dd0447db1c90517b33d855a614b28b3cfc2d2d44..99449fbf9a726834ec2b2c268956a13f0ab0b99d 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
+#include <asm/atomic.h>
 #include <asm/page.h>
 #include <asm/amigahw.h>
 
@@ -23,111 +24,100 @@ unsigned long amiga_chip_size;
 EXPORT_SYMBOL(amiga_chip_size);
 
 static struct resource chipram_res = {
-    .name = "Chip RAM", .start = CHIP_PHYSADDR
+       .name = "Chip RAM", .start = CHIP_PHYSADDR
 };
-static unsigned long chipavail;
+static atomic_t chipavail;
 
 
 void __init amiga_chip_init(void)
 {
-    if (!AMIGAHW_PRESENT(CHIP_RAM))
-       return;
+       if (!AMIGAHW_PRESENT(CHIP_RAM))
+               return;
 
-    chipram_res.end = amiga_chip_size-1;
-    request_resource(&iomem_resource, &chipram_res);
+       chipram_res.end = CHIP_PHYSADDR + amiga_chip_size - 1;
+       request_resource(&iomem_resource, &chipram_res);
 
-    chipavail = amiga_chip_size;
+       atomic_set(&chipavail, amiga_chip_size);
 }
 
 
 void *amiga_chip_alloc(unsigned long size, const char *name)
 {
-    struct resource *res;
+       struct resource *res;
+       void *p;
 
-    /* round up */
-    size = PAGE_ALIGN(size);
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       if (!res)
+               return NULL;
 
-#ifdef DEBUG
-    printk("amiga_chip_alloc: allocate %ld bytes\n", size);
-#endif
-    res = kzalloc(sizeof(struct resource), GFP_KERNEL);
-    if (!res)
-       return NULL;
-    res->name = name;
+       res->name = name;
+       p = amiga_chip_alloc_res(size, res);
+       if (!p) {
+               kfree(res);
+               return NULL;
+       }
 
-    if (allocate_resource(&chipram_res, res, size, 0, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) {
-       kfree(res);
-       return NULL;
-    }
-    chipavail -= size;
-#ifdef DEBUG
-    printk("amiga_chip_alloc: returning %lx\n", res->start);
-#endif
-    return (void *)ZTWO_VADDR(res->start);
+       return p;
 }
 EXPORT_SYMBOL(amiga_chip_alloc);
 
 
-    /*
-     *  Warning:
-     *  amiga_chip_alloc_res is meant only for drivers that need to allocate
-     *  Chip RAM before kmalloc() is functional. As a consequence, those
-      drivers must not free that Chip RAM afterwards.
-     */
+       /*
+        *  Warning:
+        *  amiga_chip_alloc_res is meant only for drivers that need to
+        *  allocate Chip RAM before kmalloc() is functional. As a consequence,
+        *  those drivers must not free that Chip RAM afterwards.
+        */
 
-void * __init amiga_chip_alloc_res(unsigned long size, struct resource *res)
+void *amiga_chip_alloc_res(unsigned long size, struct resource *res)
 {
-    unsigned long start;
-
-    /* round up */
-    size = PAGE_ALIGN(size);
-    /* dmesg into chipmem prefers memory at the safe end */
-    start = CHIP_PHYSADDR + chipavail - size;
-
-#ifdef DEBUG
-    printk("amiga_chip_alloc_res: allocate %ld bytes\n", size);
-#endif
-    if (allocate_resource(&chipram_res, res, size, start, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0) {
-       printk("amiga_chip_alloc_res: first alloc failed!\n");
-       if (allocate_resource(&chipram_res, res, size, 0, UINT_MAX, PAGE_SIZE, NULL, NULL) < 0)
-           return NULL;
-    }
-    chipavail -= size;
-#ifdef DEBUG
-    printk("amiga_chip_alloc_res: returning %lx\n", res->start);
-#endif
-    return (void *)ZTWO_VADDR(res->start);
+       int error;
+
+       /* round up */
+       size = PAGE_ALIGN(size);
+
+       pr_debug("amiga_chip_alloc_res: allocate %lu bytes\n", size);
+       error = allocate_resource(&chipram_res, res, size, 0, UINT_MAX,
+                                 PAGE_SIZE, NULL, NULL);
+       if (error < 0) {
+               pr_err("amiga_chip_alloc_res: allocate_resource() failed %d!\n",
+                      error);
+               return NULL;
+       }
+
+       atomic_sub(size, &chipavail);
+       pr_debug("amiga_chip_alloc_res: returning %pR\n", res);
+       return (void *)ZTWO_VADDR(res->start);
 }
 
 void amiga_chip_free(void *ptr)
 {
-    unsigned long start = ZTWO_PADDR(ptr);
-    struct resource **p, *res;
-    unsigned long size;
-
-    for (p = &chipram_res.child; (res = *p); p = &res->sibling) {
-       if (res->start != start)
-           continue;
-       *p = res->sibling;
-       size = res->end-start;
-#ifdef DEBUG
-       printk("amiga_chip_free: free %ld bytes at %p\n", size, ptr);
-#endif
-       chipavail += size;
+       unsigned long start = ZTWO_PADDR(ptr);
+       struct resource *res;
+       unsigned long size;
+
+       res = lookup_resource(&chipram_res, start);
+       if (!res) {
+               pr_err("amiga_chip_free: trying to free nonexistent region at "
+                      "%p\n", ptr);
+               return;
+       }
+
+       size = resource_size(res);
+       pr_debug("amiga_chip_free: free %lu bytes at %p\n", size, ptr);
+       atomic_add(size, &chipavail);
+       release_resource(res);
        kfree(res);
-       return;
-    }
-    printk("amiga_chip_free: trying to free nonexistent region at %p\n", ptr);
 }
 EXPORT_SYMBOL(amiga_chip_free);
 
 
 unsigned long amiga_chip_avail(void)
 {
-#ifdef DEBUG
-       printk("amiga_chip_avail : %ld bytes\n", chipavail);
-#endif
-       return chipavail;
+       unsigned long n = atomic_read(&chipavail);
+
+       pr_debug("amiga_chip_avail : %lu bytes\n", n);
+       return n;
 }
 EXPORT_SYMBOL(amiga_chip_avail);
 
index 6ec3b7f33779bcef5bb00ffea045d8dce7f3e46b..0810c8d56e599b3e282af8a16ee003dab90ce8f4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/m68k/atari/stram.c: Functions for ST-RAM allocations
+ * Functions for ST-RAM allocations
  *
  * Copyright 1994-97 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
  *
 #include <asm/atari_stram.h>
 #include <asm/io.h>
 
-#undef DEBUG
-
-#ifdef DEBUG
-#define        DPRINTK(fmt,args...) printk( fmt, ##args )
-#else
-#define DPRINTK(fmt,args...)
-#endif
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_STRAM_PROC)
-/* abbrev for the && above... */
-#define DO_PROC
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#endif
 
 /*
- * ++roman:
- *
- * New version of ST-Ram buffer allocation. Instead of using the
- * 1 MB - 4 KB that remain when the ST-Ram chunk starts at $1000
- * (1 MB granularity!), such buffers are reserved like this:
- *
- *  - If the kernel resides in ST-Ram anyway, we can take the buffer
- *    from behind the current kernel data space the normal way
- *    (incrementing start_mem).
- *
- *  - If the kernel is in TT-Ram, stram_init() initializes start and
- *    end of the available region. Buffers are allocated from there
- *    and mem_init() later marks the such used pages as reserved.
- *    Since each TT-Ram chunk is at least 4 MB in size, I hope there
- *    won't be an overrun of the ST-Ram region by normal kernel data
- *    space.
- *
- * For that, ST-Ram may only be allocated while kernel initialization
- * is going on, or exactly: before mem_init() is called. There is also
- * no provision now for freeing ST-Ram buffers. It seems that isn't
- * really needed.
- *
+ * The ST-RAM allocator allocates memory from a pool of reserved ST-RAM of
+ * configurable size, set aside on ST-RAM init.
+ * As long as this pool is not exhausted, allocation of real ST-RAM can be
+ * guaranteed.
  */
 
-/* Start and end (virtual) of ST-RAM */
-static void *stram_start, *stram_end;
-
-/* set after memory_init() executed and allocations via start_mem aren't
- * possible anymore */
-static int mem_init_done;
-
 /* set if kernel is in ST-RAM */
 static int kernel_in_stram;
 
-typedef struct stram_block {
-       struct stram_block *next;
-       void *start;
-       unsigned long size;
-       unsigned flags;
-       const char *owner;
-} BLOCK;
-
-/* values for flags field */
-#define BLOCK_FREE     0x01    /* free structure in the BLOCKs pool */
-#define BLOCK_KMALLOCED        0x02    /* structure allocated by kmalloc() */
-#define BLOCK_GFP      0x08    /* block allocated with __get_dma_pages() */
+static struct resource stram_pool = {
+       .name = "ST-RAM Pool"
+};
 
-/* list of allocated blocks */
-static BLOCK *alloc_list;
+static unsigned long pool_size = 1024*1024;
 
-/* We can't always use kmalloc() to allocate BLOCK structures, since
- * stram_alloc() can be called rather early. So we need some pool of
- * statically allocated structures. 20 of them is more than enough, so in most
- * cases we never should need to call kmalloc(). */
-#define N_STATIC_BLOCKS        20
-static BLOCK static_blocks[N_STATIC_BLOCKS];
 
-/***************************** Prototypes *****************************/
+static int __init atari_stram_setup(char *arg)
+{
+       if (!MACH_IS_ATARI)
+               return 0;
 
-static BLOCK *add_region( void *addr, unsigned long size );
-static BLOCK *find_region( void *addr );
-static int remove_region( BLOCK *block );
+       pool_size = memparse(arg, NULL);
+       return 0;
+}
 
-/************************* End of Prototypes **************************/
+early_param("stram_pool", atari_stram_setup);
 
-\f
-/* ------------------------------------------------------------------------ */
-/*                                                        Public Interface                                                             */
-/* ------------------------------------------------------------------------ */
 
 /*
  * This init function is called very early by atari/config.c
@@ -123,25 +67,23 @@ static int remove_region( BLOCK *block );
 void __init atari_stram_init(void)
 {
        int i;
+       void *stram_start;
 
-       /* initialize static blocks */
-       for( i = 0; i < N_STATIC_BLOCKS; ++i )
-               static_blocks[i].flags = BLOCK_FREE;
-
-       /* determine whether kernel code resides in ST-RAM (then ST-RAM is the
-        * first memory block at virtual 0x0) */
+       /*
+        * determine whether kernel code resides in ST-RAM
+        * (then ST-RAM is the first memory block at virtual 0x0)
+        */
        stram_start = phys_to_virt(0);
        kernel_in_stram = (stram_start == 0);
 
-       for( i = 0; i < m68k_num_memory; ++i ) {
+       for (i = 0; i < m68k_num_memory; ++i) {
                if (m68k_memory[i].addr == 0) {
-                       /* skip first 2kB or page (supervisor-only!) */
-                       stram_end = stram_start + m68k_memory[i].size;
                        return;
                }
        }
+
        /* Should never come here! (There is always ST-Ram!) */
-       panic( "atari_stram_init: no ST-RAM found!" );
+       panic("atari_stram_init: no ST-RAM found!");
 }
 
 
@@ -151,226 +93,68 @@ void __init atari_stram_init(void)
  */
 void __init atari_stram_reserve_pages(void *start_mem)
 {
-       /* always reserve first page of ST-RAM, the first 2 kB are
-        * supervisor-only! */
+       /*
+        * always reserve first page of ST-RAM, the first 2 KiB are
+        * supervisor-only!
+        */
        if (!kernel_in_stram)
                reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT);
 
-}
+       stram_pool.start = (resource_size_t)alloc_bootmem_low_pages(pool_size);
+       stram_pool.end = stram_pool.start + pool_size - 1;
+       request_resource(&iomem_resource, &stram_pool);
 
-void atari_stram_mem_init_hook (void)
-{
-       mem_init_done = 1;
+       pr_debug("atari_stram pool: size = %lu bytes, resource = %pR\n",
+                pool_size, &stram_pool);
 }
 
 
-/*
- * This is main public interface: somehow allocate a ST-RAM block
- *
- *  - If we're before mem_init(), we have to make a static allocation. The
- *    region is taken in the kernel data area (if the kernel is in ST-RAM) or
- *    from the start of ST-RAM (if the kernel is in TT-RAM) and added to the
- *    rsvd_stram_* region. The ST-RAM is somewhere in the middle of kernel
- *    address space in the latter case.
- *
- *  - If mem_init() already has been called, try with __get_dma_pages().
- *    This has the disadvantage that it's very hard to get more than 1 page,
- *    and it is likely to fail :-(
- *
- */
-void *atari_stram_alloc(long size, const char *owner)
+void *atari_stram_alloc(unsigned long size, const char *owner)
 {
-       void *addr = NULL;
-       BLOCK *block;
-       int flags;
-
-       DPRINTK("atari_stram_alloc(size=%08lx,owner=%s)\n", size, owner);
-
-       if (!mem_init_done)
-               return alloc_bootmem_low(size);
-       else {
-               /* After mem_init(): can only resort to __get_dma_pages() */
-               addr = (void *)__get_dma_pages(GFP_KERNEL, get_order(size));
-               flags = BLOCK_GFP;
-               DPRINTK( "atari_stram_alloc: after mem_init, "
-                                "get_pages=%p\n", addr );
+       struct resource *res;
+       int error;
+
+       pr_debug("atari_stram_alloc: allocate %lu bytes\n", size);
+
+       /* round up */
+       size = PAGE_ALIGN(size);
+
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       if (!res)
+               return NULL;
+
+       res->name = owner;
+       error = allocate_resource(&stram_pool, res, size, 0, UINT_MAX,
+                                 PAGE_SIZE, NULL, NULL);
+       if (error < 0) {
+               pr_err("atari_stram_alloc: allocate_resource() failed %d!\n",
+                      error);
+               kfree(res);
+               return NULL;
        }
 
-       if (addr) {
-               if (!(block = add_region( addr, size ))) {
-                       /* out of memory for BLOCK structure :-( */
-                       DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- "
-                                        "freeing again\n" );
-                       free_pages((unsigned long)addr, get_order(size));
-                       return( NULL );
-               }
-               block->owner = owner;
-               block->flags |= flags;
-       }
-       return( addr );
+       pr_debug("atari_stram_alloc: returning %pR\n", res);
+       return (void *)res->start;
 }
 EXPORT_SYMBOL(atari_stram_alloc);
 
-void atari_stram_free( void *addr )
 
+void atari_stram_free(void *addr)
 {
-       BLOCK *block;
-
-       DPRINTK( "atari_stram_free(addr=%p)\n", addr );
+       unsigned long start = (unsigned long)addr;
+       struct resource *res;
+       unsigned long size;
 
-       if (!(block = find_region( addr ))) {
-               printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p "
-                               "from %p\n", addr, __builtin_return_address(0) );
+       res = lookup_resource(&stram_pool, start);
+       if (!res) {
+               pr_err("atari_stram_free: trying to free nonexistent region "
+                      "at %p\n", addr);
                return;
        }
-       DPRINTK( "atari_stram_free: found block (%p): size=%08lx, owner=%s, "
-                        "flags=%02x\n", block, block->size, block->owner, block->flags );
-
-       if (!(block->flags & BLOCK_GFP))
-               goto fail;
 
-       DPRINTK("atari_stram_free: is kmalloced, order_size=%d\n",
-               get_order(block->size));
-       free_pages((unsigned long)addr, get_order(block->size));
-       remove_region( block );
-       return;
-
-  fail:
-       printk( KERN_ERR "atari_stram_free: cannot free block at %p "
-                       "(called from %p)\n", addr, __builtin_return_address(0) );
+       size = resource_size(res);
+       pr_debug("atari_stram_free: free %lu bytes at %p\n", size, addr);
+       release_resource(res);
+       kfree(res);
 }
 EXPORT_SYMBOL(atari_stram_free);
-
-\f
-/* ------------------------------------------------------------------------ */
-/*                                                       Region Management                                                             */
-/* ------------------------------------------------------------------------ */
-
-
-/* insert a region into the alloced list (sorted) */
-static BLOCK *add_region( void *addr, unsigned long size )
-{
-       BLOCK **p, *n = NULL;
-       int i;
-
-       for( i = 0; i < N_STATIC_BLOCKS; ++i ) {
-               if (static_blocks[i].flags & BLOCK_FREE) {
-                       n = &static_blocks[i];
-                       n->flags = 0;
-                       break;
-               }
-       }
-       if (!n && mem_init_done) {
-               /* if statics block pool exhausted and we can call kmalloc() already
-                * (after mem_init()), try that */
-               n = kmalloc( sizeof(BLOCK), GFP_KERNEL );
-               if (n)
-                       n->flags = BLOCK_KMALLOCED;
-       }
-       if (!n) {
-               printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" );
-               return( NULL );
-       }
-       n->start = addr;
-       n->size  = size;
-
-       for( p = &alloc_list; *p; p = &((*p)->next) )
-               if ((*p)->start > addr) break;
-       n->next = *p;
-       *p = n;
-
-       return( n );
-}
-
-
-/* find a region (by start addr) in the alloced list */
-static BLOCK *find_region( void *addr )
-{
-       BLOCK *p;
-
-       for( p = alloc_list; p; p = p->next ) {
-               if (p->start == addr)
-                       return( p );
-               if (p->start > addr)
-                       break;
-       }
-       return( NULL );
-}
-
-
-/* remove a block from the alloced list */
-static int remove_region( BLOCK *block )
-{
-       BLOCK **p;
-
-       for( p = &alloc_list; *p; p = &((*p)->next) )
-               if (*p == block) break;
-       if (!*p)
-               return( 0 );
-
-       *p = block->next;
-       if (block->flags & BLOCK_KMALLOCED)
-               kfree( block );
-       else
-               block->flags |= BLOCK_FREE;
-       return( 1 );
-}
-
-
-\f
-/* ------------------------------------------------------------------------ */
-/*                                              /proc statistics file stuff                                            */
-/* ------------------------------------------------------------------------ */
-
-#ifdef DO_PROC
-
-#define        PRINT_PROC(fmt,args...) seq_printf( m, fmt, ##args )
-
-static int stram_proc_show(struct seq_file *m, void *v)
-{
-       BLOCK *p;
-
-       PRINT_PROC("Total ST-RAM:      %8u kB\n",
-                          (stram_end - stram_start) >> 10);
-       PRINT_PROC( "Allocated regions:\n" );
-       for( p = alloc_list; p; p = p->next ) {
-               PRINT_PROC("0x%08lx-0x%08lx: %s (",
-                          virt_to_phys(p->start),
-                          virt_to_phys(p->start+p->size-1),
-                          p->owner);
-               if (p->flags & BLOCK_GFP)
-                       PRINT_PROC( "page-alloced)\n" );
-               else
-                       PRINT_PROC( "??)\n" );
-       }
-
-       return 0;
-}
-
-static int stram_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, stram_proc_show, NULL);
-}
-
-static const struct file_operations stram_proc_fops = {
-       .open           = stram_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static int __init proc_stram_init(void)
-{
-       proc_create("stram", 0, NULL, &stram_proc_fops);
-       return 0;
-}
-module_init(proc_stram_init);
-#endif
-
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  tab-width: 4
- * End:
- */
index 7546d13963be046b525ae056f862670d7bbf3535..62e27598af91e5104c22aea3ac171dd9e10d4136 100644 (file)
@@ -6,12 +6,11 @@
  */
 
 /* public interface */
-void *atari_stram_alloc(long size, const char *owner);
+void *atari_stram_alloc(unsigned long size, const char *owner);
 void atari_stram_free(void *);
 
 /* functions called internally by other parts of the kernel */
 void atari_stram_init(void);
 void atari_stram_reserve_pages(void *start_mem);
-void atari_stram_mem_init_hook (void);
 
 #endif /*_M68K_ATARI_STRAM_H */
index f51f709bbf3036f8ee7438eafe64226c1c02b043..0392b28656abb306e330fe5d4edcf44a9b5f2a7e 100644 (file)
@@ -399,8 +399,8 @@ struct CODEC
 #define CODEC_OVERFLOW_LEFT     2
   u_char unused2, unused3, unused4, unused5;
   u_char gpio_directions;
-#define GPIO_IN                 0
-#define GPIO_OUT                1
+#define CODEC_GPIO_IN           0
+#define CODEC_GPIO_OUT          1
   u_char unused6;
   u_char gpio_data;
 };
index 334d83640376762b058a7a4010e2878fffe21439..c3b45061dd08d3f6981f3c19e0867f5d16ee62fe 100644 (file)
@@ -216,7 +216,9 @@ static void __init m68k_parse_bootinfo(const struct bi_record *record)
 
 void __init setup_arch(char **cmdline_p)
 {
+#ifndef CONFIG_SUN3
        int i;
+#endif
 
        /* The bootinfo is located right after the kernel bss */
        m68k_parse_bootinfo((const struct bi_record *)_end);
index 367ecee2f981db6a5763ed4ac69452f20afbd79d..3384a5244fbdc147155278729ef979eca593c3b2 100644 (file)
@@ -105,9 +105,6 @@ fp_fetoxm1(struct fp_ext *dest, struct fp_ext *src)
 
        fp_monadic_check(dest, src);
 
-       if (IS_ZERO(dest))
-               return dest;
-
        return dest;
 }
 
index 4ad0ca918e2e3e08426c5dd012adec1c29781b9e..4b5eb3d85638e576346e535ea103d15a3b3bf2cc 100644 (file)
 #ifndef MULTI_ARITH_H
 #define MULTI_ARITH_H
 
-#if 0  /* old code... */
-
-/* Unsigned only, because we don't need signs to multiply and divide. */
-typedef unsigned int int128[4];
-
-/* Word order */
-enum {
-       MSW128,
-       NMSW128,
-       NLSW128,
-       LSW128
-};
-
-/* big-endian */
-#define LO_WORD(ll) (((unsigned int *) &ll)[1])
-#define HI_WORD(ll) (((unsigned int *) &ll)[0])
-
-/* Convenience functions to stuff various integer values into int128s */
-
-static inline void zero128(int128 a)
-{
-       a[LSW128] = a[NLSW128] = a[NMSW128] = a[MSW128] = 0;
-}
-
-/* Human-readable word order in the arguments */
-static inline void set128(unsigned int i3, unsigned int i2, unsigned int i1,
-                         unsigned int i0, int128 a)
-{
-       a[LSW128] = i0;
-       a[NLSW128] = i1;
-       a[NMSW128] = i2;
-       a[MSW128] = i3;
-}
-
-/* Convenience functions (for testing as well) */
-static inline void int64_to_128(unsigned long long src, int128 dest)
-{
-       dest[LSW128] = (unsigned int) src;
-       dest[NLSW128] = src >> 32;
-       dest[NMSW128] = dest[MSW128] = 0;
-}
-
-static inline void int128_to_64(const int128 src, unsigned long long *dest)
-{
-       *dest = src[LSW128] | (long long) src[NLSW128] << 32;
-}
-
-static inline void put_i128(const int128 a)
-{
-       printk("%08x %08x %08x %08x\n", a[MSW128], a[NMSW128],
-              a[NLSW128], a[LSW128]);
-}
-
-/* Internal shifters:
-
-   Note that these are only good for 0 < count < 32.
- */
-
-static inline void _lsl128(unsigned int count, int128 a)
-{
-       a[MSW128] = (a[MSW128] << count) | (a[NMSW128] >> (32 - count));
-       a[NMSW128] = (a[NMSW128] << count) | (a[NLSW128] >> (32 - count));
-       a[NLSW128] = (a[NLSW128] << count) | (a[LSW128] >> (32 - count));
-       a[LSW128] <<= count;
-}
-
-static inline void _lsr128(unsigned int count, int128 a)
-{
-       a[LSW128] = (a[LSW128] >> count) | (a[NLSW128] << (32 - count));
-       a[NLSW128] = (a[NLSW128] >> count) | (a[NMSW128] << (32 - count));
-       a[NMSW128] = (a[NMSW128] >> count) | (a[MSW128] << (32 - count));
-       a[MSW128] >>= count;
-}
-
-/* Should be faster, one would hope */
-
-static inline void lslone128(int128 a)
-{
-       asm volatile ("lsl.l #1,%0\n"
-                     "roxl.l #1,%1\n"
-                     "roxl.l #1,%2\n"
-                     "roxl.l #1,%3\n"
-                     :
-                     "=d" (a[LSW128]),
-                     "=d"(a[NLSW128]),
-                     "=d"(a[NMSW128]),
-                     "=d"(a[MSW128])
-                     :
-                     "0"(a[LSW128]),
-                     "1"(a[NLSW128]),
-                     "2"(a[NMSW128]),
-                     "3"(a[MSW128]));
-}
-
-static inline void lsrone128(int128 a)
-{
-       asm volatile ("lsr.l #1,%0\n"
-                     "roxr.l #1,%1\n"
-                     "roxr.l #1,%2\n"
-                     "roxr.l #1,%3\n"
-                     :
-                     "=d" (a[MSW128]),
-                     "=d"(a[NMSW128]),
-                     "=d"(a[NLSW128]),
-                     "=d"(a[LSW128])
-                     :
-                     "0"(a[MSW128]),
-                     "1"(a[NMSW128]),
-                     "2"(a[NLSW128]),
-                     "3"(a[LSW128]));
-}
-
-/* Generalized 128-bit shifters:
-
-   These bit-shift to a multiple of 32, then move whole longwords.  */
-
-static inline void lsl128(unsigned int count, int128 a)
-{
-       int wordcount, i;
-
-       if (count % 32)
-               _lsl128(count % 32, a);
-
-       if (0 == (wordcount = count / 32))
-               return;
-
-       /* argh, gak, endian-sensitive */
-       for (i = 0; i < 4 - wordcount; i++) {
-               a[i] = a[i + wordcount];
-       }
-       for (i = 3; i >= 4 - wordcount; --i) {
-               a[i] = 0;
-       }
-}
-
-static inline void lsr128(unsigned int count, int128 a)
-{
-       int wordcount, i;
-
-       if (count % 32)
-               _lsr128(count % 32, a);
-
-       if (0 == (wordcount = count / 32))
-               return;
-
-       for (i = 3; i >= wordcount; --i) {
-               a[i] = a[i - wordcount];
-       }
-       for (i = 0; i < wordcount; i++) {
-               a[i] = 0;
-       }
-}
-
-static inline int orl128(int a, int128 b)
-{
-       b[LSW128] |= a;
-}
-
-static inline int btsthi128(const int128 a)
-{
-       return a[MSW128] & 0x80000000;
-}
-
-/* test bits (numbered from 0 = LSB) up to and including "top" */
-static inline int bftestlo128(int top, const int128 a)
-{
-       int r = 0;
-
-       if (top > 31)
-               r |= a[LSW128];
-       if (top > 63)
-               r |= a[NLSW128];
-       if (top > 95)
-               r |= a[NMSW128];
-
-       r |= a[3 - (top / 32)] & ((1 << (top % 32 + 1)) - 1);
-
-       return (r != 0);
-}
-
-/* Aargh.  We need these because GCC is broken */
-/* FIXME: do them in assembly, for goodness' sake! */
-static inline void mask64(int pos, unsigned long long *mask)
-{
-       *mask = 0;
-
-       if (pos < 32) {
-               LO_WORD(*mask) = (1 << pos) - 1;
-               return;
-       }
-       LO_WORD(*mask) = -1;
-       HI_WORD(*mask) = (1 << (pos - 32)) - 1;
-}
-
-static inline void bset64(int pos, unsigned long long *dest)
-{
-       /* This conditional will be optimized away.  Thanks, GCC! */
-       if (pos < 32)
-               asm volatile ("bset %1,%0":"=m"
-                             (LO_WORD(*dest)):"id"(pos));
-       else
-               asm volatile ("bset %1,%0":"=m"
-                             (HI_WORD(*dest)):"id"(pos - 32));
-}
-
-static inline int btst64(int pos, unsigned long long dest)
-{
-       if (pos < 32)
-               return (0 != (LO_WORD(dest) & (1 << pos)));
-       else
-               return (0 != (HI_WORD(dest) & (1 << (pos - 32))));
-}
-
-static inline void lsl64(int count, unsigned long long *dest)
-{
-       if (count < 32) {
-               HI_WORD(*dest) = (HI_WORD(*dest) << count)
-                   | (LO_WORD(*dest) >> count);
-               LO_WORD(*dest) <<= count;
-               return;
-       }
-       count -= 32;
-       HI_WORD(*dest) = LO_WORD(*dest) << count;
-       LO_WORD(*dest) = 0;
-}
-
-static inline void lsr64(int count, unsigned long long *dest)
-{
-       if (count < 32) {
-               LO_WORD(*dest) = (LO_WORD(*dest) >> count)
-                   | (HI_WORD(*dest) << (32 - count));
-               HI_WORD(*dest) >>= count;
-               return;
-       }
-       count -= 32;
-       LO_WORD(*dest) = HI_WORD(*dest) >> count;
-       HI_WORD(*dest) = 0;
-}
-#endif
-
 static inline void fp_denormalize(struct fp_ext *reg, unsigned int cnt)
 {
        reg->exp += cnt;
@@ -481,117 +241,6 @@ static inline void fp_dividemant(union fp_mant128 *dest, struct fp_ext *src,
        }
 }
 
-#if 0
-static inline unsigned int fp_fls128(union fp_mant128 *src)
-{
-       unsigned long data;
-       unsigned int res, off;
-
-       if ((data = src->m32[0]))
-               off = 0;
-       else if ((data = src->m32[1]))
-               off = 32;
-       else if ((data = src->m32[2]))
-               off = 64;
-       else if ((data = src->m32[3]))
-               off = 96;
-       else
-               return 128;
-
-       asm ("bfffo %1{#0,#32},%0" : "=d" (res) : "dm" (data));
-       return res + off;
-}
-
-static inline void fp_shiftmant128(union fp_mant128 *src, int shift)
-{
-       unsigned long sticky;
-
-       switch (shift) {
-       case 0:
-               return;
-       case 1:
-               asm volatile ("lsl.l #1,%0"
-                       : "=d" (src->m32[3]) : "0" (src->m32[3]));
-               asm volatile ("roxl.l #1,%0"
-                       : "=d" (src->m32[2]) : "0" (src->m32[2]));
-               asm volatile ("roxl.l #1,%0"
-                       : "=d" (src->m32[1]) : "0" (src->m32[1]));
-               asm volatile ("roxl.l #1,%0"
-                       : "=d" (src->m32[0]) : "0" (src->m32[0]));
-               return;
-       case 2 ... 31:
-               src->m32[0] = (src->m32[0] << shift) | (src->m32[1] >> (32 - shift));
-               src->m32[1] = (src->m32[1] << shift) | (src->m32[2] >> (32 - shift));
-               src->m32[2] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift));
-               src->m32[3] = (src->m32[3] << shift);
-               return;
-       case 32 ... 63:
-               shift -= 32;
-               src->m32[0] = (src->m32[1] << shift) | (src->m32[2] >> (32 - shift));
-               src->m32[1] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift));
-               src->m32[2] = (src->m32[3] << shift);
-               src->m32[3] = 0;
-               return;
-       case 64 ... 95:
-               shift -= 64;
-               src->m32[0] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift));
-               src->m32[1] = (src->m32[3] << shift);
-               src->m32[2] = src->m32[3] = 0;
-               return;
-       case 96 ... 127:
-               shift -= 96;
-               src->m32[0] = (src->m32[3] << shift);
-               src->m32[1] = src->m32[2] = src->m32[3] = 0;
-               return;
-       case -31 ... -1:
-               shift = -shift;
-               sticky = 0;
-               if (src->m32[3] << (32 - shift))
-                       sticky = 1;
-               src->m32[3] = (src->m32[3] >> shift) | (src->m32[2] << (32 - shift)) | sticky;
-               src->m32[2] = (src->m32[2] >> shift) | (src->m32[1] << (32 - shift));
-               src->m32[1] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift));
-               src->m32[0] = (src->m32[0] >> shift);
-               return;
-       case -63 ... -32:
-               shift = -shift - 32;
-               sticky = 0;
-               if ((src->m32[2] << (32 - shift)) || src->m32[3])
-                       sticky = 1;
-               src->m32[3] = (src->m32[2] >> shift) | (src->m32[1] << (32 - shift)) | sticky;
-               src->m32[2] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift));
-               src->m32[1] = (src->m32[0] >> shift);
-               src->m32[0] = 0;
-               return;
-       case -95 ... -64:
-               shift = -shift - 64;
-               sticky = 0;
-               if ((src->m32[1] << (32 - shift)) || src->m32[2] || src->m32[3])
-                       sticky = 1;
-               src->m32[3] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift)) | sticky;
-               src->m32[2] = (src->m32[0] >> shift);
-               src->m32[1] = src->m32[0] = 0;
-               return;
-       case -127 ... -96:
-               shift = -shift - 96;
-               sticky = 0;
-               if ((src->m32[0] << (32 - shift)) || src->m32[1] || src->m32[2] || src->m32[3])
-                       sticky = 1;
-               src->m32[3] = (src->m32[0] >> shift) | sticky;
-               src->m32[2] = src->m32[1] = src->m32[0] = 0;
-               return;
-       }
-
-       if (shift < 0 && (src->m32[0] || src->m32[1] || src->m32[2] || src->m32[3]))
-               src->m32[3] = 1;
-       else
-               src->m32[3] = 0;
-       src->m32[2] = 0;
-       src->m32[1] = 0;
-       src->m32[0] = 0;
-}
-#endif
-
 static inline void fp_putmant128(struct fp_ext *dest, union fp_mant128 *src,
                                 int shift)
 {
@@ -637,183 +286,4 @@ static inline void fp_putmant128(struct fp_ext *dest, union fp_mant128 *src,
        }
 }
 
-#if 0 /* old code... */
-static inline int fls(unsigned int a)
-{
-       int r;
-
-       asm volatile ("bfffo %1{#0,#32},%0"
-                     : "=d" (r) : "md" (a));
-       return r;
-}
-
-/* fls = "find last set" (cf. ffs(3)) */
-static inline int fls128(const int128 a)
-{
-       if (a[MSW128])
-               return fls(a[MSW128]);
-       if (a[NMSW128])
-               return fls(a[NMSW128]) + 32;
-       /* XXX: it probably never gets beyond this point in actual
-          use, but that's indicative of a more general problem in the
-          algorithm (i.e. as per the actual 68881 implementation, we
-          really only need at most 67 bits of precision [plus
-          overflow]) so I'm not going to fix it. */
-       if (a[NLSW128])
-               return fls(a[NLSW128]) + 64;
-       if (a[LSW128])
-               return fls(a[LSW128]) + 96;
-       else
-               return -1;
-}
-
-static inline int zerop128(const int128 a)
-{
-       return !(a[LSW128] | a[NLSW128] | a[NMSW128] | a[MSW128]);
-}
-
-static inline int nonzerop128(const int128 a)
-{
-       return (a[LSW128] | a[NLSW128] | a[NMSW128] | a[MSW128]);
-}
-
-/* Addition and subtraction */
-/* Do these in "pure" assembly, because "extended" asm is unmanageable
-   here */
-static inline void add128(const int128 a, int128 b)
-{
-       /* rotating carry flags */
-       unsigned int carry[2];
-
-       carry[0] = a[LSW128] > (0xffffffff - b[LSW128]);
-       b[LSW128] += a[LSW128];
-
-       carry[1] = a[NLSW128] > (0xffffffff - b[NLSW128] - carry[0]);
-       b[NLSW128] = a[NLSW128] + b[NLSW128] + carry[0];
-
-       carry[0] = a[NMSW128] > (0xffffffff - b[NMSW128] - carry[1]);
-       b[NMSW128] = a[NMSW128] + b[NMSW128] + carry[1];
-
-       b[MSW128] = a[MSW128] + b[MSW128] + carry[0];
-}
-
-/* Note: assembler semantics: "b -= a" */
-static inline void sub128(const int128 a, int128 b)
-{
-       /* rotating borrow flags */
-       unsigned int borrow[2];
-
-       borrow[0] = b[LSW128] < a[LSW128];
-       b[LSW128] -= a[LSW128];
-
-       borrow[1] = b[NLSW128] < a[NLSW128] + borrow[0];
-       b[NLSW128] = b[NLSW128] - a[NLSW128] - borrow[0];
-
-       borrow[0] = b[NMSW128] < a[NMSW128] + borrow[1];
-       b[NMSW128] = b[NMSW128] - a[NMSW128] - borrow[1];
-
-       b[MSW128] = b[MSW128] - a[MSW128] - borrow[0];
-}
-
-/* Poor man's 64-bit expanding multiply */
-static inline void mul64(unsigned long long a, unsigned long long b, int128 c)
-{
-       unsigned long long acc;
-       int128 acc128;
-
-       zero128(acc128);
-       zero128(c);
-
-       /* first the low words */
-       if (LO_WORD(a) && LO_WORD(b)) {
-               acc = (long long) LO_WORD(a) * LO_WORD(b);
-               c[NLSW128] = HI_WORD(acc);
-               c[LSW128] = LO_WORD(acc);
-       }
-       /* Next the high words */
-       if (HI_WORD(a) && HI_WORD(b)) {
-               acc = (long long) HI_WORD(a) * HI_WORD(b);
-               c[MSW128] = HI_WORD(acc);
-               c[NMSW128] = LO_WORD(acc);
-       }
-       /* The middle words */
-       if (LO_WORD(a) && HI_WORD(b)) {
-               acc = (long long) LO_WORD(a) * HI_WORD(b);
-               acc128[NMSW128] = HI_WORD(acc);
-               acc128[NLSW128] = LO_WORD(acc);
-               add128(acc128, c);
-       }
-       /* The first and last words */
-       if (HI_WORD(a) && LO_WORD(b)) {
-               acc = (long long) HI_WORD(a) * LO_WORD(b);
-               acc128[NMSW128] = HI_WORD(acc);
-               acc128[NLSW128] = LO_WORD(acc);
-               add128(acc128, c);
-       }
-}
-
-/* Note: unsigned */
-static inline int cmp128(int128 a, int128 b)
-{
-       if (a[MSW128] < b[MSW128])
-               return -1;
-       if (a[MSW128] > b[MSW128])
-               return 1;
-       if (a[NMSW128] < b[NMSW128])
-               return -1;
-       if (a[NMSW128] > b[NMSW128])
-               return 1;
-       if (a[NLSW128] < b[NLSW128])
-               return -1;
-       if (a[NLSW128] > b[NLSW128])
-               return 1;
-
-       return (signed) a[LSW128] - b[LSW128];
-}
-
-inline void div128(int128 a, int128 b, int128 c)
-{
-       int128 mask;
-
-       /* Algorithm:
-
-          Shift the divisor until it's at least as big as the
-          dividend, keeping track of the position to which we've
-          shifted it, i.e. the power of 2 which we've multiplied it
-          by.
-
-          Then, for this power of 2 (the mask), and every one smaller
-          than it, subtract the mask from the dividend and add it to
-          the quotient until the dividend is smaller than the raised
-          divisor.  At this point, divide the dividend and the mask
-          by 2 (i.e. shift one place to the right).  Lather, rinse,
-          and repeat, until there are no more powers of 2 left. */
-
-       /* FIXME: needless to say, there's room for improvement here too. */
-
-       /* Shift up */
-       /* XXX: since it just has to be "at least as big", we can
-          probably eliminate this horribly wasteful loop.  I will
-          have to prove this first, though */
-       set128(0, 0, 0, 1, mask);
-       while (cmp128(b, a) < 0 && !btsthi128(b)) {
-               lslone128(b);
-               lslone128(mask);
-       }
-
-       /* Shift down */
-       zero128(c);
-       do {
-               if (cmp128(a, b) >= 0) {
-                       sub128(b, a);
-                       add128(mask, c);
-               }
-               lsrone128(mask);
-               lsrone128(b);
-       } while (nonzerop128(mask));
-
-       /* The remainder is in a... */
-}
-#endif
-
 #endif /* MULTI_ARITH_H */
index 9113c2f1760735f8134aee0ab0e6ff7a8aea9b7a..bbe525434ccb677fe19af015a1b21b3d057095c4 100644 (file)
@@ -83,11 +83,6 @@ void __init mem_init(void)
        int initpages = 0;
        int i;
 
-#ifdef CONFIG_ATARI
-       if (MACH_IS_ATARI)
-               atari_stram_mem_init_hook();
-#endif
-
        /* this will put all memory onto the freelists */
        totalram_pages = num_physpages = 0;
        for_each_online_pgdat(pgdat) {
index d8f013347a9e63c617ccf3d46c78fb582cf42ddf..7d6831ac8a46eec66c4f1fc00ac28aa48000ed64 100644 (file)
@@ -38,6 +38,7 @@ struct cpuinfo {
        u32 use_exc;
        u32 ver_code;
        u32 mmu;
+       u32 mmu_privins;
        u32 endian;
 
        /* CPU caches */
index c4532f032b3b3ad2b082332132a0d90a6ba94868..c9a6262832c4671134b31b7aab9b41cfc9783fac 100644 (file)
@@ -14,7 +14,7 @@
 
 #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
 
-static inline unsigned long arch_local_irq_save(void)
+static inline notrace unsigned long arch_local_irq_save(void)
 {
        unsigned long flags;
        asm volatile("  msrclr %0, %1   \n"
@@ -25,7 +25,7 @@ static inline unsigned long arch_local_irq_save(void)
        return flags;
 }
 
-static inline void arch_local_irq_disable(void)
+static inline notrace void arch_local_irq_disable(void)
 {
        /* this uses r0 without declaring it - is that correct? */
        asm volatile("  msrclr r0, %0   \n"
@@ -35,7 +35,7 @@ static inline void arch_local_irq_disable(void)
                     : "memory");
 }
 
-static inline void arch_local_irq_enable(void)
+static inline notrace void arch_local_irq_enable(void)
 {
        /* this uses r0 without declaring it - is that correct? */
        asm volatile("  msrset  r0, %0  \n"
@@ -47,7 +47,7 @@ static inline void arch_local_irq_enable(void)
 
 #else /* !CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
 
-static inline unsigned long arch_local_irq_save(void)
+static inline notrace unsigned long arch_local_irq_save(void)
 {
        unsigned long flags, tmp;
        asm volatile (" mfs     %0, rmsr        \n"
@@ -61,7 +61,7 @@ static inline unsigned long arch_local_irq_save(void)
        return flags;
 }
 
-static inline void arch_local_irq_disable(void)
+static inline notrace void arch_local_irq_disable(void)
 {
        unsigned long tmp;
        asm volatile("  mfs     %0, rmsr        \n"
@@ -74,7 +74,7 @@ static inline void arch_local_irq_disable(void)
                     : "memory");
 }
 
-static inline void arch_local_irq_enable(void)
+static inline notrace void arch_local_irq_enable(void)
 {
        unsigned long tmp;
        asm volatile("  mfs     %0, rmsr        \n"
@@ -89,7 +89,7 @@ static inline void arch_local_irq_enable(void)
 
 #endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
 
-static inline unsigned long arch_local_save_flags(void)
+static inline notrace unsigned long arch_local_save_flags(void)
 {
        unsigned long flags;
        asm volatile("  mfs     %0, rmsr        \n"
@@ -100,7 +100,7 @@ static inline unsigned long arch_local_save_flags(void)
        return flags;
 }
 
-static inline void arch_local_irq_restore(unsigned long flags)
+static inline notrace void arch_local_irq_restore(unsigned long flags)
 {
        asm volatile("  mts     rmsr, %0        \n"
                     "  nop                     \n"
@@ -109,12 +109,12 @@ static inline void arch_local_irq_restore(unsigned long flags)
                     : "memory");
 }
 
-static inline bool arch_irqs_disabled_flags(unsigned long flags)
+static inline notrace bool arch_irqs_disabled_flags(unsigned long flags)
 {
        return (flags & MSR_IE) == 0;
 }
 
-static inline bool arch_irqs_disabled(void)
+static inline notrace bool arch_irqs_disabled(void)
 {
        return arch_irqs_disabled_flags(arch_local_save_flags());
 }
index aed2a6be8e270566c73092646802efdc6a22736f..7283bfb2f7e4770b37e441d33066945fcfc53087 100644 (file)
@@ -125,9 +125,6 @@ struct thread_struct {
        .pgdir = swapper_pg_dir, \
 }
 
-/* Do necessary setup to start up a newly executed thread.  */
-void start_thread(struct pt_regs *regs,
-               unsigned long pc, unsigned long usp);
 
 /* Free all resources held by a thread. */
 extern inline void release_thread(struct task_struct *dead_task)
index 9ad567e2d425eae6a2628774b27da824bb0b0bb4..20c5e8e5121bc6a807262870cb199a43c18fd15b 100644 (file)
 #define HAVE_ARCH_DEVTREE_FIXUPS
 
 /* Other Prototypes */
-extern int early_uartlite_console(void);
-extern int early_uart16550_console(void);
+enum early_consoles {
+       UARTLITE = 1,
+       UART16550 = 2,
+};
+
+extern int of_early_console(void *version);
 
 /*
  * OF address retreival & translation
index a10bec62e8579ac1d5dab2dfd1c7f6a395f3ae91..4bbdb4c03b57837d5df1e4bfb91258ef7e5eeb65 100644 (file)
@@ -111,16 +111,16 @@ struct pvr_s {
 /* Target family PVR mask */
 #define PVR10_TARGET_FAMILY_MASK       0xFF000000
 
-/* MMU descrtiption */
+/* MMU description */
 #define PVR11_USE_MMU                  0xC0000000
 #define PVR11_MMU_ITLB_SIZE            0x38000000
 #define PVR11_MMU_DTLB_SIZE            0x07000000
 #define PVR11_MMU_TLB_ACCESS           0x00C00000
 #define PVR11_MMU_ZONES                        0x003C0000
+#define PVR11_MMU_PRIVINS              0x00010000
 /* MSR Reset value PVR mask */
 #define PVR11_MSR_RESET_VALUE_MASK     0x000007FF
 
-
 /* PVR access macros */
 #define PVR_IS_FULL(_pvr)      (_pvr.pvr[0] & PVR0_PVR_FULL_MASK)
 #define PVR_USE_BARREL(_pvr)   (_pvr.pvr[0] & PVR0_USE_BARREL_MASK)
@@ -216,6 +216,7 @@ struct pvr_s {
 #define PVR_MMU_DTLB_SIZE(_pvr)                (_pvr.pvr[11] & PVR11_MMU_DTLB_SIZE)
 #define PVR_MMU_TLB_ACCESS(_pvr)       (_pvr.pvr[11] & PVR11_MMU_TLB_ACCESS)
 #define PVR_MMU_ZONES(_pvr)            (_pvr.pvr[11] & PVR11_MMU_ZONES)
+#define PVR_MMU_PRIVINS(pvr)           (pvr.pvr[11] & PVR11_MMU_PRIVINS)
 
 /* endian */
 #define PVR_ENDIAN(_pvr)       (_pvr.pvr[0] & PVR0_ENDI)
index 8f3968971e4eef6334b5f014fd1d0aef1cf27537..904e5ef6a11b2e958f0b33c29b4f7d3794cecb38 100644 (file)
@@ -23,6 +23,7 @@ extern char cmd_line[COMMAND_LINE_SIZE];
 void early_printk(const char *fmt, ...);
 
 int setup_early_printk(char *opt);
+void remap_early_printk(void);
 void disable_early_printk(void);
 
 #if defined(CONFIG_EARLY_PRINTK)
index f70a6047f08e3e581b32dd65866ad4ebf45e5423..916aaedf1945df8880e3a99066358b0105041d1d 100644 (file)
@@ -72,6 +72,7 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
        CI(pvr_user2, USER2);
 
        CI(mmu, USE_MMU);
+       CI(mmu_privins, MMU_PRIVINS);
        CI(endian, ENDIAN);
 
        CI(use_icache, USE_ICACHE);
index b16b994ca3d25b81165b1d95492e0c550cc9d14e..592bb2e838c4f5e0d0d25685d59373a73b7a579a 100644 (file)
@@ -119,6 +119,7 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
        ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2");
 
        ci->mmu = fcpu(cpu, "xlnx,use-mmu");
+       ci->mmu_privins = fcpu(cpu, "xlnx,mmu-privileged-instr");
        ci->endian = fcpu(cpu, "xlnx,endianness");
 
        ci->ver_code = 0;
index c1640c52711fe9a056ebd63450c51e54ad26d5d2..44394d80a6836c4118254eab4ce24d7b9c2b91ab 100644 (file)
@@ -88,4 +88,8 @@ void __init setup_cpuinfo(void)
                printk(KERN_WARNING "%s: Unsupported PVR setting\n", __func__);
                set_cpuinfo_static(&cpuinfo, cpu);
        }
+
+       if (cpuinfo.mmu_privins)
+               printk(KERN_WARNING "%s: Stream instructions enabled"
+                       " - USERSPACE CAN LOCK THIS KERNEL!\n", __func__);
 }
index b4048af026158e79c1422b0553d540d30f53da13..7b5dca7ed39db70779c216afcaf2196e45412217 100644 (file)
@@ -97,6 +97,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                (cpuinfo.use_exc & PVR2_FPU_EXC_MASK) ? "fpu " : "",
                (cpuinfo.use_exc & PVR2_USE_FSL_EXC) ? "fsl " : "");
 
+       count += seq_printf(m,
+                       "Stream-insns:\t%sprivileged\n",
+                       cpuinfo.mmu_privins ? "un" : "");
+
        if (cpuinfo.use_icache)
                count += seq_printf(m,
                                "Icache:\t\t%ukB\tline length:\t%dB\n",
@@ -110,10 +114,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                                "Dcache:\t\t%ukB\tline length:\t%dB\n",
                                cpuinfo.dcache_size >> 10,
                                cpuinfo.dcache_line_length);
+               seq_printf(m, "Dcache-Policy:\t");
                if (cpuinfo.dcache_wb)
-                       count += seq_printf(m, "\t\twrite-back\n");
+                       count += seq_printf(m, "write-back\n");
                else
-                       count += seq_printf(m, "\t\twrite-through\n");
+                       count += seq_printf(m, "write-through\n");
        } else
                count += seq_printf(m, "Dcache:\t\tno\n");
 
index c3616a080ebfcad71bbc9b950b40ba64e6da8218..d26d92d47754a067481fa40eb78ef2eadba04317 100644 (file)
@@ -35,7 +35,7 @@ static void early_printk_uartlite_putc(char c)
         * we'll never timeout on a working UART.
         */
 
-       unsigned retries = 10000;
+       unsigned retries = 1000000;
        /* read status bit - 0x8 offset */
        while (--retries && (in_be32(base_addr + 8) & (1 << 3)))
                ;
@@ -60,7 +60,7 @@ static void early_printk_uartlite_write(struct console *unused,
 static struct console early_serial_uartlite_console = {
        .name = "earlyser",
        .write = early_printk_uartlite_write,
-       .flags = CON_PRINTBUFFER,
+       .flags = CON_PRINTBUFFER | CON_BOOT,
        .index = -1,
 };
 #endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
@@ -104,7 +104,7 @@ static void early_printk_uart16550_write(struct console *unused,
 static struct console early_serial_uart16550_console = {
        .name = "earlyser",
        .write = early_printk_uart16550_write,
-       .flags = CON_PRINTBUFFER,
+       .flags = CON_PRINTBUFFER | CON_BOOT,
        .index = -1,
 };
 #endif /* CONFIG_SERIAL_8250_CONSOLE */
@@ -127,48 +127,56 @@ void early_printk(const char *fmt, ...)
 
 int __init setup_early_printk(char *opt)
 {
+       int version = 0;
+
        if (early_console_initialized)
                return 1;
 
-#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
-       base_addr = early_uartlite_console();
+       base_addr = of_early_console(&version);
        if (base_addr) {
-               early_console_initialized = 1;
 #ifdef CONFIG_MMU
                early_console_reg_tlb_alloc(base_addr);
 #endif
-               early_console = &early_serial_uartlite_console;
-               early_printk("early_printk_console is enabled at 0x%08x\n",
-                                                       base_addr);
-
-               /* register_console(early_console); */
-
-               return 0;
-       }
-#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
-
+               switch (version) {
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+               case UARTLITE:
+                       printk(KERN_INFO "Early console on uartlite "
+                                               "at 0x%08x\n", base_addr);
+                       early_console = &early_serial_uartlite_console;
+                       break;
+#endif
 #ifdef CONFIG_SERIAL_8250_CONSOLE
-       base_addr = early_uart16550_console();
-       base_addr &= ~3; /* clear register offset */
-       if (base_addr) {
-               early_console_initialized = 1;
-#ifdef CONFIG_MMU
-               early_console_reg_tlb_alloc(base_addr);
+               case UART16550:
+                       printk(KERN_INFO "Early console on uart16650 "
+                                               "at 0x%08x\n", base_addr);
+                       early_console = &early_serial_uart16550_console;
+                       break;
 #endif
-               early_console = &early_serial_uart16550_console;
-
-               early_printk("early_printk_console is enabled at 0x%08x\n",
-                                                       base_addr);
-
-               /* register_console(early_console); */
+               default:
+                       printk(KERN_INFO  "Unsupported early console %d\n",
+                                                               version);
+                       return 1;
+               }
 
+               register_console(early_console);
+               early_console_initialized = 1;
                return 0;
        }
-#endif /* CONFIG_SERIAL_8250_CONSOLE */
-
        return 1;
 }
 
+/* Remap early console to virtual address and do not allocate one TLB
+ * only for early console because of performance degression */
+void __init remap_early_printk(void)
+{
+       if (!early_console_initialized || !early_console)
+               return;
+       printk(KERN_INFO "early_printk_console remaping from 0x%x to ",
+                                                               base_addr);
+       base_addr = (u32) ioremap(base_addr, PAGE_SIZE);
+       printk(KERN_CONT "0x%x\n", base_addr);
+}
+
 void __init disable_early_printk(void)
 {
        if (!early_console_initialized || !early_console)
index 56572e923a83b118d657d24a1b53a143715b76e8..e62be83796044876d6708a8f960ce554c0dfbecc 100644 (file)
@@ -1113,23 +1113,23 @@ lw_r10_vm:      R3_TO_LWREG_VM_V        (10);
 lw_r11_vm:     R3_TO_LWREG_VM_V        (11);
 lw_r12_vm:     R3_TO_LWREG_VM_V        (12);
 lw_r13_vm:     R3_TO_LWREG_VM_V        (13);
-lw_r14_vm:     R3_TO_LWREG_VM          (14);
+lw_r14_vm:     R3_TO_LWREG_VM_V        (14);
 lw_r15_vm:     R3_TO_LWREG_VM_V        (15);
-lw_r16_vm:     R3_TO_LWREG_VM          (16);
+lw_r16_vm:     R3_TO_LWREG_VM_V        (16);
 lw_r17_vm:     R3_TO_LWREG_VM_V        (17);
 lw_r18_vm:     R3_TO_LWREG_VM_V        (18);
-lw_r19_vm:     R3_TO_LWREG_VM          (19);
-lw_r20_vm:     R3_TO_LWREG_VM          (20);
-lw_r21_vm:     R3_TO_LWREG_VM          (21);
-lw_r22_vm:     R3_TO_LWREG_VM          (22);
-lw_r23_vm:     R3_TO_LWREG_VM          (23);
-lw_r24_vm:     R3_TO_LWREG_VM          (24);
-lw_r25_vm:     R3_TO_LWREG_VM          (25);
-lw_r26_vm:     R3_TO_LWREG_VM          (26);
-lw_r27_vm:     R3_TO_LWREG_VM          (27);
-lw_r28_vm:     R3_TO_LWREG_VM          (28);
-lw_r29_vm:     R3_TO_LWREG_VM          (29);
-lw_r30_vm:     R3_TO_LWREG_VM          (30);
+lw_r19_vm:     R3_TO_LWREG_VM_V        (19);
+lw_r20_vm:     R3_TO_LWREG_VM_V        (20);
+lw_r21_vm:     R3_TO_LWREG_VM_V        (21);
+lw_r22_vm:     R3_TO_LWREG_VM_V        (22);
+lw_r23_vm:     R3_TO_LWREG_VM_V        (23);
+lw_r24_vm:     R3_TO_LWREG_VM_V        (24);
+lw_r25_vm:     R3_TO_LWREG_VM_V        (25);
+lw_r26_vm:     R3_TO_LWREG_VM_V        (26);
+lw_r27_vm:     R3_TO_LWREG_VM_V        (27);
+lw_r28_vm:     R3_TO_LWREG_VM_V        (28);
+lw_r29_vm:     R3_TO_LWREG_VM_V        (29);
+lw_r30_vm:     R3_TO_LWREG_VM_V        (30);
 lw_r31_vm:     R3_TO_LWREG_VM_V        (31);
 
 sw_table_vm:
@@ -1147,23 +1147,23 @@ sw_r10_vm:      SWREG_TO_R3_VM_V        (10);
 sw_r11_vm:     SWREG_TO_R3_VM_V        (11);
 sw_r12_vm:     SWREG_TO_R3_VM_V        (12);
 sw_r13_vm:     SWREG_TO_R3_VM_V        (13);
-sw_r14_vm:     SWREG_TO_R3_VM          (14);
+sw_r14_vm:     SWREG_TO_R3_VM_V        (14);
 sw_r15_vm:     SWREG_TO_R3_VM_V        (15);
-sw_r16_vm:     SWREG_TO_R3_VM          (16);
+sw_r16_vm:     SWREG_TO_R3_VM_V        (16);
 sw_r17_vm:     SWREG_TO_R3_VM_V        (17);
 sw_r18_vm:     SWREG_TO_R3_VM_V        (18);
-sw_r19_vm:     SWREG_TO_R3_VM          (19);
-sw_r20_vm:     SWREG_TO_R3_VM          (20);
-sw_r21_vm:     SWREG_TO_R3_VM          (21);
-sw_r22_vm:     SWREG_TO_R3_VM          (22);
-sw_r23_vm:     SWREG_TO_R3_VM          (23);
-sw_r24_vm:     SWREG_TO_R3_VM          (24);
-sw_r25_vm:     SWREG_TO_R3_VM          (25);
-sw_r26_vm:     SWREG_TO_R3_VM          (26);
-sw_r27_vm:     SWREG_TO_R3_VM          (27);
-sw_r28_vm:     SWREG_TO_R3_VM          (28);
-sw_r29_vm:     SWREG_TO_R3_VM          (29);
-sw_r30_vm:     SWREG_TO_R3_VM          (30);
+sw_r19_vm:     SWREG_TO_R3_VM_V        (19);
+sw_r20_vm:     SWREG_TO_R3_VM_V        (20);
+sw_r21_vm:     SWREG_TO_R3_VM_V        (21);
+sw_r22_vm:     SWREG_TO_R3_VM_V        (22);
+sw_r23_vm:     SWREG_TO_R3_VM_V        (23);
+sw_r24_vm:     SWREG_TO_R3_VM_V        (24);
+sw_r25_vm:     SWREG_TO_R3_VM_V        (25);
+sw_r26_vm:     SWREG_TO_R3_VM_V        (26);
+sw_r27_vm:     SWREG_TO_R3_VM_V        (27);
+sw_r28_vm:     SWREG_TO_R3_VM_V        (28);
+sw_r29_vm:     SWREG_TO_R3_VM_V        (29);
+sw_r30_vm:     SWREG_TO_R3_VM_V        (30);
 sw_r31_vm:     SWREG_TO_R3_VM_V        (31);
 #endif /* CONFIG_MMU */
 
index c88f066f41bda9bfc0e9a323fb15b8a279c75e5f..eb41441c7fd0288a84e8f7e38c3dfddfae5b55bd 100644 (file)
@@ -134,7 +134,7 @@ void __init init_IRQ(void)
        intr_type =
                be32_to_cpup(of_get_property(intc,
                                                "xlnx,kind-of-intr", NULL));
-       if (intr_type >= (1 << (nr_irq + 1)))
+       if (intr_type > (u32)((1ULL << nr_irq) - 1))
                printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n");
 
 #ifdef CONFIG_SELFMOD_INTC
index 968648a81c1ebbda34c1565b61a25571f9cd55e7..dbb812421d8a15629dd051cd931aea24c625c58f 100644 (file)
@@ -237,7 +237,6 @@ unsigned long get_wchan(struct task_struct *p)
 /* Set up a thread for executing a new program */
 void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
 {
-       set_fs(USER_DS);
        regs->pc = pc;
        regs->r1 = usp;
        regs->pt_mode = 0;
index b15cc219b1d98ed86eeb6375b596bb3caaa789dd..977484add216913f9073841c033ed4abe5b0bd9f 100644 (file)
@@ -53,69 +53,58 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
 }
 
 #ifdef CONFIG_EARLY_PRINTK
-/* MS this is Microblaze specifig function */
-static int __init early_init_dt_scan_serial(unsigned long node,
-                               const char *uname, int depth, void *data)
-{
-       unsigned long l;
-       char *p;
-       const __be32 *addr;
-
-       pr_debug("search \"serial\", depth: %d, uname: %s\n", depth, uname);
-
-/* find all serial nodes */
-       if (strncmp(uname, "serial", 6) != 0)
-               return 0;
-
-/* find compatible node with uartlite */
-       p = of_get_flat_dt_prop(node, "compatible", &l);
-       if ((strncmp(p, "xlnx,xps-uartlite", 17) != 0) &&
-                       (strncmp(p, "xlnx,opb-uartlite", 17) != 0) &&
-                       (strncmp(p, "xlnx,axi-uartlite", 17) != 0))
-               return 0;
-
-       addr = of_get_flat_dt_prop(node, "reg", &l);
-       return be32_to_cpup(addr); /* return address */
-}
+char *stdout;
 
-/* this function is looking for early uartlite console - Microblaze specific */
-int __init early_uartlite_console(void)
-{
-       return of_scan_flat_dt(early_init_dt_scan_serial, NULL);
-}
-
-/* MS this is Microblaze specifig function */
-static int __init early_init_dt_scan_serial_full(unsigned long node,
+int __init early_init_dt_scan_chosen_serial(unsigned long node,
                                const char *uname, int depth, void *data)
 {
        unsigned long l;
        char *p;
-       unsigned int addr;
-
-       pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
-
-/* find all serial nodes */
-       if (strncmp(uname, "serial", 6) != 0)
-               return 0;
 
-       early_init_dt_check_for_initrd(node);
-
-/* find compatible node with uartlite */
-       p = of_get_flat_dt_prop(node, "compatible", &l);
-
-       if ((strncmp(p, "xlnx,xps-uart16550", 18) != 0) &&
-               (strncmp(p, "xlnx,axi-uart16550", 18) != 0))
-               return 0;
-
-       addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l);
-       addr += *(u32 *)of_get_flat_dt_prop(node, "reg-offset", &l);
-       return be32_to_cpu(addr); /* return address */
+       pr_debug("%s: depth: %d, uname: %s\n", __func__, depth, uname);
+
+       if (depth == 1 && (strcmp(uname, "chosen") == 0 ||
+                               strcmp(uname, "chosen@0") == 0)) {
+               p = of_get_flat_dt_prop(node, "linux,stdout-path", &l);
+               if (p != NULL && l > 0)
+                       stdout = p; /* store pointer to stdout-path */
+       }
+
+       if (stdout && strstr(stdout, uname)) {
+               p = of_get_flat_dt_prop(node, "compatible", &l);
+               pr_debug("Compatible string: %s\n", p);
+
+               if ((strncmp(p, "xlnx,xps-uart16550", 18) == 0) ||
+                       (strncmp(p, "xlnx,axi-uart16550", 18) == 0)) {
+                       unsigned int addr;
+
+                       *(u32 *)data = UART16550;
+
+                       addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l);
+                       addr += *(u32 *)of_get_flat_dt_prop(node,
+                                                       "reg-offset", &l);
+                       /* clear register offset */
+                       return be32_to_cpu(addr) & ~3;
+               }
+               if ((strncmp(p, "xlnx,xps-uartlite", 17) == 0) ||
+                               (strncmp(p, "xlnx,opb-uartlite", 17) == 0) ||
+                               (strncmp(p, "xlnx,axi-uartlite", 17) == 0) ||
+                               (strncmp(p, "xlnx,mdm", 8) == 0)) {
+                       unsigned int *addrp;
+
+                       *(u32 *)data = UARTLITE;
+
+                       addrp = of_get_flat_dt_prop(node, "reg", &l);
+                       return be32_to_cpup(addrp); /* return address */
+               }
+       }
+       return 0;
 }
 
-/* this function is looking for early uartlite console - Microblaze specific */
-int __init early_uart16550_console(void)
+/* this function is looking for early console - Microblaze specific */
+int __init of_early_console(void *version)
 {
-       return of_scan_flat_dt(early_init_dt_scan_serial_full, NULL);
+       return of_scan_flat_dt(early_init_dt_scan_chosen_serial, version);
 }
 #endif
 
index 8e2c09b7ff2679db8ad0ce903519cced7a3ec7f8..0e654a12d37e18136caa965bfbbe729f87349d60 100644 (file)
@@ -59,6 +59,11 @@ void __init setup_arch(char **cmdline_p)
 
        setup_memory();
 
+#ifdef CONFIG_EARLY_PRINTK
+       /* remap early console to virtual address */
+       remap_early_printk();
+#endif
+
        xilinx_pci_init();
 
 #if defined(CONFIG_SELFMOD_INTC) || defined(CONFIG_SELFMOD_TIMER)
index e3d8170ad00b98a8739d572fea653c22582a6953..99385d0b3f3b64bb08d894a91295f6639784c2de 100644 (file)
@@ -173,6 +173,7 @@ core-$(CONFIG_HD6446X_SERIES)       += arch/sh/cchips/hd6446x/
 cpuincdir-$(CONFIG_CPU_SH2A)   += cpu-sh2a
 cpuincdir-$(CONFIG_CPU_SH2)    += cpu-sh2
 cpuincdir-$(CONFIG_CPU_SH3)    += cpu-sh3
+cpuincdir-$(CONFIG_CPU_SH4A)   += cpu-sh4a
 cpuincdir-$(CONFIG_CPU_SH4)    += cpu-sh4
 cpuincdir-$(CONFIG_CPU_SH5)    += cpu-sh5
 cpuincdir-y                    += cpu-common   # Must be last
index 8e2a27057bc929dd0e6af00b9ccee249b97d7542..2823619c600672a71f0bf79854fd6c213cf45418 100644 (file)
@@ -116,7 +116,7 @@ static int apsh4a3a_clk_init(void)
        int ret;
 
        clk = clk_get(NULL, "extal");
-       if (!clk || IS_ERR(clk))
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_set_rate(clk, 33333000);
        clk_put(clk);
index e2bd218a054e6c63307f4f745d9f500edfa410a8..b4d6292a9247bb40682c470b0cad78b0a72b1f95 100644 (file)
@@ -94,7 +94,7 @@ static int apsh4ad0a_clk_init(void)
        int ret;
 
        clk = clk_get(NULL, "extal");
-       if (!clk || IS_ERR(clk))
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_set_rate(clk, 33333000);
        clk_put(clk);
index ee65ff05c558d401ce844fed329ee2cc24be683f..d879848f3cdd49ac533502064b7025c39cf53ecb 100644 (file)
@@ -299,7 +299,7 @@ static int sh7785lcr_clk_init(void)
        int ret;
 
        clk = clk_get(NULL, "extal");
-       if (!clk || IS_ERR(clk))
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_set_rate(clk, 33333333);
        clk_put(clk);
index d81c609decc7af6105360361631ebf3ff943bd75..24e3316c5c179067839ca956da29f685b87246c2 100644 (file)
@@ -190,7 +190,7 @@ static int urquell_clk_init(void)
                return -EINVAL;
 
        clk = clk_get(NULL, "extal");
-       if (!clk || IS_ERR(clk))
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_set_rate(clk, 33333333);
        clk_put(clk);
index 1dc924b2f5087ffa9b1bf8ff212644752fe23fd7..d36265758911faced2e4df8f2d13fa1ab30c816b 100644 (file)
@@ -332,8 +332,8 @@ static int camera_set_capture(struct soc_camera_platform_info *info,
        return ret;
 }
 
-static int ap325rxa_camera_add(struct soc_camera_link *icl, struct device *dev);
-static void ap325rxa_camera_del(struct soc_camera_link *icl);
+static int ap325rxa_camera_add(struct soc_camera_device *icd);
+static void ap325rxa_camera_del(struct soc_camera_device *icd);
 
 static struct soc_camera_platform_info camera_info = {
        .format_name = "UYVY",
@@ -366,24 +366,23 @@ static void ap325rxa_camera_release(struct device *dev)
        soc_camera_platform_release(&camera_device);
 }
 
-static int ap325rxa_camera_add(struct soc_camera_link *icl,
-                              struct device *dev)
+static int ap325rxa_camera_add(struct soc_camera_device *icd)
 {
-       int ret = soc_camera_platform_add(icl, dev, &camera_device, &camera_link,
+       int ret = soc_camera_platform_add(icd, &camera_device, &camera_link,
                                          ap325rxa_camera_release, 0);
        if (ret < 0)
                return ret;
 
        ret = camera_probe();
        if (ret < 0)
-               soc_camera_platform_del(icl, camera_device, &camera_link);
+               soc_camera_platform_del(icd, camera_device, &camera_link);
 
        return ret;
 }
 
-static void ap325rxa_camera_del(struct soc_camera_link *icl)
+static void ap325rxa_camera_del(struct soc_camera_device *icd)
 {
-       soc_camera_platform_del(icl, camera_device, &camera_link);
+       soc_camera_platform_del(icd, camera_device, &camera_link);
 }
 #endif /* CONFIG_I2C */
 
index 87618c91d1781881140d7e55fbf7e2a718d1c142..74b8db1b74a9d9bd27d7dec2afea771f5beb9d4c 100644 (file)
@@ -335,8 +335,6 @@ static struct clk *r7780rp_clocks[] = {
        &ivdr_clk,
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("ivdr_clk", &ivdr_clk),
index 1521aa75ee3ac0517a2094c27bb448e31ccbbd99..486d1ac3694c2638d810c718b83d0ede65f1cd75 100644 (file)
@@ -194,7 +194,7 @@ static int sdk7786_clk_init(void)
                return -EINVAL;
 
        clk = clk_get(NULL, "extal");
-       if (!clk || IS_ERR(clk))
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
        ret = clk_set_rate(clk, 33333333);
        clk_put(clk);
index b68b61d22c6cd4aab727f2754fbe20617c872c1c..edc2fb7a5bb25540e75cf42b86877b8c16ed8558 100644 (file)
@@ -5,7 +5,7 @@
 #include <cpu/irq.h>
 #include "pci-sh5.h"
 
-int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int result = -1;
 
index 942ef4f155f534ebe46aa77ca8279c95002b8d35..edeea8960c303840c2a81483a91ea17a2e22672a 100644 (file)
@@ -64,7 +64,7 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources);
 
-int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        /*
         * The interrupt routing semantics here are quite trivial.
index 95c6e2d94a0a2b283568b5090b0d92be6dfa1da3..ecb1d106063813badede4185d636230f2f00e879 100644 (file)
@@ -19,7 +19,7 @@
 #define PCIMCR_MRSET_OFF       0xBFFFFFFF
 #define PCIMCR_RFSH_OFF                0xFFFFFFFB
 
-int pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        /*
         * slot0: pin1-4 = irq5,6,7,8
index 08b2d8658a00b525acb13bd3662fc5fd2583c2c3..f9370dce0b70a710f8340e62f09f87a422d7eda4 100644 (file)
@@ -18,7 +18,7 @@ static char irq_tab[] __initdata = {
        65, 66, 67, 68,
 };
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        return irq_tab[slot];
 }
index e248516118a960fb3789d1cd2ea63a61d744ba50..eaddb56c45c612493e0c996183d092df25efa882 100644 (file)
@@ -31,7 +31,7 @@ static char lboxre2_irq_tab[] __initdata = {
        IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD,
 };
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        if (mach_is_lboxre2())
                return lboxre2_irq_tab[slot];
index 0930f988ac29914a1a34af4993d0a09d4756f88a..0b8472501b885044b33ebaaaee4b4b8fb5065f9e 100644 (file)
@@ -27,7 +27,7 @@ static char sdk7780_irq_tab[4][16] __initdata = {
        { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
 };
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        return sdk7780_irq_tab[pin-1][slot];
 }
index fd3e6b02f2898c2bbd2c166fc6cafda33487372d..2ec146c3fa4468453e946c026ae2f58a0d803e61 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/io.h>
 #include "pci-sh4.h"
 
-int __init pcibios_map_platform_irq(struct pci_dev *, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
 {
         switch (slot) {
         case 0: return 13;
index 2e8a18b7ee53e48941bc3671776c01908070e1e0..1615e5906168117c7a81ae73b42f7f2c42b1137a 100644 (file)
@@ -3,7 +3,7 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 
-int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
index 5a39ecc1adb8005a1a7bfb38f5944bbe94987059..4a093c648d124099a4df0d775cc23ad2980f5951 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/pci.h>
 #include "pci-sh4.h"
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        int irq = -1;
 
index 3a79fa8254a6317a0b0c3020ecd3fdd2ac39f28c..bd1addb1b8be4f91c8f25d3bdf3d58346450712b 100644 (file)
@@ -27,7 +27,7 @@ static char titan_irq_tab[] __initdata = {
        TITAN_IRQ_USB,
 };
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
        int irq = titan_irq_tab[slot];
 
index 4418f9070ed171e9d679d1e6868cbbf10396d4e9..4df27c4fbf999e68d03e598175b50d84c22aaa81 100644 (file)
@@ -466,7 +466,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
        return 0;
 }
 
-int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
 {
         return 71;
 }
index f0efe97f17506394f03255d30784bd061c8913ac..cb21e2399dc1829a13045531711a91a77eefc311 100644 (file)
@@ -112,7 +112,7 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 #endif
 
 /* Board-specific fixup routines. */
-int pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin);
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin);
 
 extern void pcibios_resource_to_bus(struct pci_dev *dev,
        struct pci_bus_region *region, struct resource *res);
diff --git a/arch/sh/include/cpu-sh3/cpu/serial.h b/arch/sh/include/cpu-sh3/cpu/serial.h
new file mode 100644 (file)
index 0000000..7766329
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __CPU_SH3_SERIAL_H
+#define __CPU_SH3_SERIAL_H
+
+#include <linux/serial_sci.h>
+
+extern struct plat_sci_port_ops sh770x_sci_port_ops;
+extern struct plat_sci_port_ops sh7710_sci_port_ops;
+extern struct plat_sci_port_ops sh7720_sci_port_ops;
+
+#endif /* __CPU_SH3_SERIAL_H */
diff --git a/arch/sh/include/cpu-sh4a/cpu/serial.h b/arch/sh/include/cpu-sh4a/cpu/serial.h
new file mode 100644 (file)
index 0000000..ff1bc27
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __CPU_SH4A_SERIAL_H
+#define __CPU_SH4A_SERIAL_H
+
+/* arch/sh/kernel/cpu/sh4a/serial-sh7722.c */
+extern struct plat_sci_port_ops sh7722_sci_port_ops;
+
+#endif /* __CPU_SH4A_SERIAL_H */
index 8f63a264a84277bda29a94ea88ca0e42fbd4d202..f59b1f30d44ba37f39b687cc19cfed409a17413f 100644 (file)
@@ -35,8 +35,6 @@ static struct clk *onchip_clocks[] = {
        &cpu_clk,
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("master_clk", &master_clk),
index ecab274141a8bbda716b5669e450636e851fa445..6f13f33a35ffce3d0877deff87c3547a74754e60 100644 (file)
@@ -7,15 +7,15 @@ obj-y := ex.o probe.o entry.o setup-sh3.o
 obj-$(CONFIG_HIBERNATION)              += swsusp.o
 
 # CPU subtype setup
-obj-$(CONFIG_CPU_SUBTYPE_SH7705)       += setup-sh7705.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7706)       += setup-sh770x.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7707)       += setup-sh770x.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7708)       += setup-sh770x.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7709)       += setup-sh770x.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7710)       += setup-sh7710.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7712)       += setup-sh7710.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7720)       += setup-sh7720.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7721)       += setup-sh7720.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7705)       += setup-sh7705.o serial-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7706)       += setup-sh770x.o serial-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7707)       += setup-sh770x.o serial-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7708)       += setup-sh770x.o serial-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7709)       += setup-sh770x.o serial-sh770x.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7710)       += setup-sh7710.o serial-sh7710.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7712)       += setup-sh7710.o serial-sh7710.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7720)       += setup-sh7720.o serial-sh7720.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7721)       += setup-sh7720.o serial-sh7720.o
 
 # Primary on-chip clocks (common)
 clock-$(CONFIG_CPU_SH3)                        := clock-sh3.o
diff --git a/arch/sh/kernel/cpu/sh3/serial-sh770x.c b/arch/sh/kernel/cpu/sh3/serial-sh770x.c
new file mode 100644 (file)
index 0000000..4f7242c
--- /dev/null
@@ -0,0 +1,33 @@
+#include <linux/serial_sci.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <cpu/serial.h>
+
+#define SCPCR 0xA4000116
+#define SCPDR 0xA4000136
+
+static void sh770x_sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       /* We need to set SCPCR to enable RTS/CTS */
+       data = __raw_readw(SCPCR);
+       /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
+       __raw_writew(data & 0x0fcf, SCPCR);
+
+       if (!(cflag & CRTSCTS)) {
+               /* We need to set SCPCR to enable RTS/CTS */
+               data = __raw_readw(SCPCR);
+               /* Clear out SCP7MD1,0, SCP4MD1,0,
+                  Set SCP6MD1,0 = {01} (output)  */
+               __raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
+
+               data = __raw_readb(SCPDR);
+               /* Set /RTS2 (bit6) = 0 */
+               __raw_writeb(data & 0xbf, SCPDR);
+       }
+}
+
+struct plat_sci_port_ops sh770x_sci_port_ops = {
+       .init_pins      = sh770x_sci_init_pins,
+};
diff --git a/arch/sh/kernel/cpu/sh3/serial-sh7710.c b/arch/sh/kernel/cpu/sh3/serial-sh7710.c
new file mode 100644 (file)
index 0000000..42190ef
--- /dev/null
@@ -0,0 +1,20 @@
+#include <linux/serial_sci.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <cpu/serial.h>
+
+#define PACR 0xa4050100
+#define PBCR 0xa4050102
+
+static void sh7710_sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       if (port->mapbase == 0xA4400000) {
+               __raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
+               __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
+       } else if (port->mapbase == 0xA4410000)
+               __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
+}
+
+struct plat_sci_port_ops sh7710_sci_port_ops = {
+       .init_pins      = sh7710_sci_init_pins,
+};
diff --git a/arch/sh/kernel/cpu/sh3/serial-sh7720.c b/arch/sh/kernel/cpu/sh3/serial-sh7720.c
new file mode 100644 (file)
index 0000000..8832c52
--- /dev/null
@@ -0,0 +1,37 @@
+#include <linux/serial_sci.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <cpu/serial.h>
+#include <asm/gpio.h>
+
+static void sh7720_sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       if (cflag & CRTSCTS) {
+               /* enable RTS/CTS */
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
+                       data = __raw_readw(PORT_PTCR);
+                       __raw_writew((data & 0xfc03), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 9-2 */
+                       data = __raw_readw(PORT_PVCR);
+                       __raw_writew((data & 0xfc03), PORT_PVCR);
+               }
+       } else {
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 5-2; enable only tx and rx  */
+                       data = __raw_readw(PORT_PTCR);
+                       __raw_writew((data & 0xffc3), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 5-2 */
+                       data = __raw_readw(PORT_PVCR);
+                       __raw_writew((data & 0xffc3), PORT_PVCR);
+               }
+       }
+}
+
+struct plat_sci_port_ops sh7720_sci_port_ops = {
+       .init_pins      = sh7720_sci_init_pins,
+};
index cd2e702feb7e113202f30be7b826d2cbfcc4caf3..2309618c015d06ec8b86d75882a21ce036db2cce 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <asm/rtc.h>
+#include <cpu/serial.h>
 
 enum {
        UNUSED = 0,
@@ -75,6 +76,8 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
        .irqs           = { 56, 56, 56 },
+       .ops            = &sh770x_sci_port_ops,
+       .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -92,6 +95,8 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
        .irqs           = { 52, 52, 52 },
+       .ops            = &sh770x_sci_port_ops,
+       .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
index 4551ad647c2ccd8c9ea465caf58a4b6194663f52..3f3d5fe5892d08c32671c382f9371d71f056e5e9 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <cpu/serial.h>
 
 enum {
        UNUSED = 0,
@@ -108,11 +109,14 @@ static struct platform_device rtc_device = {
 
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xfffffe80,
+       .port_reg       = 0xa4000136,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCI,
        .irqs           = { 23, 23, 23, 0 },
+       .ops            = &sh770x_sci_port_ops,
+       .regshift       = 1,
 };
 
 static struct platform_device scif0_device = {
@@ -132,6 +136,8 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 56, 56, 56, 56 },
+       .ops            = &sh770x_sci_port_ops,
+       .regtype        = SCIx_SH3_SCIF_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -146,11 +152,14 @@ static struct platform_device scif1_device = {
     defined(CONFIG_CPU_SUBTYPE_SH7709)
 static struct plat_sci_port scif2_platform_data = {
        .mapbase        = 0xa4000140,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_IRDA,
        .irqs           = { 52, 52, 52, 52 },
+       .ops            = &sh770x_sci_port_ops,
+       .regshift       = 1,
 };
 
 static struct platform_device scif2_device = {
index 365b94a6fcb7da7c4c9eddd82bc92df585a561ef..94920345c14db53d144e9dc2513eaa7c67fd690b 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <asm/rtc.h>
+#include <cpu/serial.h>
 
 static struct resource rtc_resources[] = {
        [0] = {
@@ -55,6 +56,8 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
        .irqs           = { 80, 80, 80, 80 },
+       .ops            = &sh7720_sci_port_ops,
+       .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -72,6 +75,8 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_4,
        .type           = PORT_SCIF,
        .irqs           = { 81, 81, 81, 81 },
+       .ops            = &sh7720_sci_port_ops,
+       .regtype        = SCIx_SH7705_SCIF_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
index 3f6f8e98635ce65a4737b07a71cd600096f5b58f..f4e262adb39ed9ed8a450a9ec370bb8b533cf53a 100644 (file)
@@ -147,8 +147,6 @@ static struct clk *sh4202_onchip_clocks[] = {
        &sh4202_shoc_clk,
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("emi_clk", &sh4202_emi_clk),
index e53b4b38bd11f954fd3d23b9e72e74d1540ea78e..98cc0c794c765abc4d7397086058c69a20c9e3d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * SH7750/SH7751 Setup
+ * SH7091/SH7750/SH7750S/SH7750R/SH7751/SH7751R Setup
  *
  *  Copyright (C) 2006  Paul Mundt
  *  Copyright (C) 2006  Jamie Lenehan
@@ -38,11 +38,13 @@ static struct platform_device rtc_device = {
 
 static struct plat_sci_port sci_platform_data = {
        .mapbase        = 0xffe00000,
+       .port_reg       = 0xffe0001C,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_TE | SCSCR_RE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCI,
        .irqs           = { 23, 23, 23, 0 },
+       .regshift       = 2,
 };
 
 static struct platform_device sci_device = {
index 78bbf232e3916b68b1373b4bbbba302471e173c7..c0b4c774700ec4fd07bf4def628f6dd80ceafd4b 100644 (file)
@@ -133,6 +133,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 52, 53, 55, 54 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -150,6 +151,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .irqs           = { 72, 73, 75, 74 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -167,6 +169,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 76, 77, 79, 78 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -184,6 +187,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCI,
        .irqs           = { 80, 81, 82, 0 },
+       .regshift       = 2,
 };
 
 static struct platform_device scif3_device = {
index cc122b1d303540ea6fcf13182c6d5f834901481b..c57fb287011e0a87278eecb5c0226a53fd70bc3b 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7780)      += setup-sh7780.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7785)       += setup-sh7785.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7786)       += setup-sh7786.o intc-shx3.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7343)       += setup-sh7343.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7722)       += setup-sh7722.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7722)       += setup-sh7722.o serial-sh7722.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7723)       += setup-sh7723.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7724)       += setup-sh7724.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7366)       += setup-sh7366.o
index 93c646072c1b93005bb6b13dff60c5afeb882854..70e45bdaadc7991805de4fdc3672d95f3fb76afc 100644 (file)
@@ -194,8 +194,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP200] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("rclk", &r_clk),
@@ -233,32 +231,17 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("rwdt0", &mstp_clks[MSTP013]),
        CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
        CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
-       {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP007],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP006],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP005],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP004],
-       },
+
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP004]),
+
        CLKDEV_CON_ID("sio0", &mstp_clks[MSTP003]),
        CLKDEV_CON_ID("siof0", &mstp_clks[MSTP002]),
        CLKDEV_CON_ID("siof1", &mstp_clks[MSTP001]),
-       CLKDEV_CON_ID("i2c0", &mstp_clks[MSTP109]),
-       CLKDEV_CON_ID("i2c1", &mstp_clks[MSTP108]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP109]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP108]),
        CLKDEV_CON_ID("tpu0", &mstp_clks[MSTP225]),
        CLKDEV_CON_ID("irda0", &mstp_clks[MSTP224]),
        CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP218]),
index 049dc0628ccc196d48c75a0aa4f8a2469f0575f2..3c3165000c52b2c76ce6447fa922349a89c23fa2 100644 (file)
@@ -192,8 +192,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP200] = MSTP(&div4_clks[DIV4_B], MSTPCR2, 0, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("rclk", &r_clk),
@@ -231,25 +229,14 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("rwdt0", &mstp_clks[MSTP013]),
        CLKDEV_CON_ID("mfi0", &mstp_clks[MSTP011]),
        CLKDEV_CON_ID("flctl0", &mstp_clks[MSTP010]),
-       {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP007],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP006],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP005],
-       },
+
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP007]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP006]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP005]),
+
        CLKDEV_CON_ID("msiof0", &mstp_clks[MSTP002]),
        CLKDEV_CON_ID("sbr0", &mstp_clks[MSTP001]),
-       CLKDEV_CON_ID("i2c0", &mstp_clks[MSTP109]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP109]),
        CLKDEV_CON_ID("icb0", &mstp_clks[MSTP227]),
        CLKDEV_CON_ID("meram0", &mstp_clks[MSTP226]),
        CLKDEV_CON_ID("dacy1", &mstp_clks[MSTP224]),
index 9d23a36f0647b97a6b5afc24ac4f7078262f57b1..c9a48088ad47f05eecf08a59f6725bd3f45876c1 100644 (file)
@@ -175,8 +175,6 @@ static struct clk mstp_clks[HWBLK_NR] = {
        SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_P], 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("rclk", &r_clk),
@@ -201,42 +199,20 @@ static struct clk_lookup lookups[] = {
        /* MSTP clocks */
        CLKDEV_CON_ID("uram0", &mstp_clks[HWBLK_URAM]),
        CLKDEV_CON_ID("xymem0", &mstp_clks[HWBLK_XYMEM]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[HWBLK_TMU]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[HWBLK_TMU]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[HWBLK_TMU]),
+
        CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
        CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
        CLKDEV_CON_ID("flctl0", &mstp_clks[HWBLK_FLCTL]),
-       {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF0],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF1],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF2],
-       },
-       CLKDEV_CON_ID("i2c0", &mstp_clks[HWBLK_IIC]),
+
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+
+       CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC]),
        CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
        CLKDEV_CON_ID("sdhi0", &mstp_clks[HWBLK_SDHI]),
        CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),
index 55493cd5bd8f3b5ce3860431882c6341539d2efb..3cc3827380e3251c1d053c1a8ea8431d49a831b3 100644 (file)
@@ -200,8 +200,6 @@ static struct clk mstp_clks[] = {
        SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_B], 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("rclk", &r_clk),
@@ -305,7 +303,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("msiof0", &mstp_clks[HWBLK_MSIOF0]),
        CLKDEV_CON_ID("msiof1", &mstp_clks[HWBLK_MSIOF1]),
        CLKDEV_CON_ID("meram0", &mstp_clks[HWBLK_MERAM]),
-       CLKDEV_CON_ID("i2c0", &mstp_clks[HWBLK_IIC]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC]),
        CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
        CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
        CLKDEV_CON_ID("adc0", &mstp_clks[HWBLK_ADC]),
index d08fa953c88b75939893de0083681bad61d666fb..8668f557e0aca654d72a049eeb3b0016202be3bf 100644 (file)
@@ -252,8 +252,6 @@ static struct clk mstp_clks[HWBLK_NR] = {
        SH_HWBLK_CLK(HWBLK_LCDC, &div4_clks[DIV4_B], 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("rclk", &r_clk),
@@ -289,77 +287,31 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("sh0", &mstp_clks[HWBLK_SHYWAY]),
        CLKDEV_CON_ID("hudi0", &mstp_clks[HWBLK_HUDI]),
        CLKDEV_CON_ID("ubc0", &mstp_clks[HWBLK_UBC]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU0],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU0],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU0],
-       }, {
-               /* TMU3 */
-               .dev_id         = "sh_tmu.3",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU1],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[HWBLK_TMU0]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[HWBLK_TMU0]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[HWBLK_TMU0]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[HWBLK_TMU1]),
+
        CLKDEV_CON_ID("cmt_fck", &mstp_clks[HWBLK_CMT]),
        CLKDEV_CON_ID("rwdt0", &mstp_clks[HWBLK_RWDT]),
        CLKDEV_CON_ID("dmac1", &mstp_clks[HWBLK_DMAC1]),
-       {
-               /* TMU4 */
-               .dev_id         = "sh_tmu.4",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU1],
-       }, {
-               /* TMU5 */
-               .dev_id         = "sh_tmu.5",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[HWBLK_TMU1],
-       }, {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF0],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF1],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF2],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF3],
-       }, {
-               /* SCIF4 */
-               .dev_id         = "sh-sci.4",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF4],
-       }, {
-               /* SCIF5 */
-               .dev_id         = "sh-sci.5",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[HWBLK_SCIF5],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[HWBLK_TMU1]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[HWBLK_TMU1]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[HWBLK_SCIF0]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[HWBLK_SCIF1]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[HWBLK_SCIF2]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[HWBLK_SCIF3]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[HWBLK_SCIF4]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[HWBLK_SCIF5]),
+
        CLKDEV_CON_ID("msiof0", &mstp_clks[HWBLK_MSIOF0]),
        CLKDEV_CON_ID("msiof1", &mstp_clks[HWBLK_MSIOF1]),
        CLKDEV_CON_ID("keysc0", &mstp_clks[HWBLK_KEYSC]),
        CLKDEV_CON_ID("rtc0", &mstp_clks[HWBLK_RTC]),
-       CLKDEV_CON_ID("i2c0", &mstp_clks[HWBLK_IIC0]),
-       CLKDEV_CON_ID("i2c1", &mstp_clks[HWBLK_IIC1]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC0]),
+       CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[HWBLK_IIC1]),
        CLKDEV_CON_ID("mmc0", &mstp_clks[HWBLK_MMC]),
        CLKDEV_CON_ID("eth0", &mstp_clks[HWBLK_ETHER]),
        CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
index eedddad138354fd85854f8b902128fe415fe221d..3b097b09a3ba3c31d0cde0165cf3ce2d2d747274 100644 (file)
@@ -101,8 +101,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP220] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR2, 20, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("extal", &extal_clk),
@@ -116,33 +114,13 @@ static struct clk_lookup lookups[] = {
        /* MSTP32 clocks */
        CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP004]),
        CLKDEV_CON_ID("riic", &mstp_clks[MSTP000]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP113],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP114],
-       },
-       {
-               /* SCIF4 (But, ID is 2) */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP112],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP111],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP110],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP113]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP114]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP112]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP111]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP110]),
+
        CLKDEV_CON_ID("usb0", &mstp_clks[MSTP102]),
        CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP220]),
 };
index 599630fc4d3bd952ae04bd4fb11565f7a0546a30..2d4c7fd79c025515adcca670a0d5bbccc6ab04f1 100644 (file)
@@ -91,8 +91,6 @@ static struct clk *sh7763_onchip_clocks[] = {
        &sh7763_shyway_clk,
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("shyway_clk", &sh7763_shyway_clk),
index 8894926479a614234302af0f7f51fbc3e9f56266..3b53348fe2fcdac7cd2bf2239fa3741be6d98e62 100644 (file)
@@ -97,8 +97,6 @@ static struct clk *sh7780_onchip_clocks[] = {
        &sh7780_shyway_clk,
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("shyway_clk", &sh7780_shyway_clk),
index 2d960247f3ebff7e8e4b55865176ed3244b0aa56..e5b420cc12654fd38d245370e08f3d2d1c875c2a 100644 (file)
@@ -116,8 +116,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP100] = SH_CLK_MSTP32(NULL, MSTPCR1, 0, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("extal", &extal_clk),
@@ -134,74 +132,27 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 
        /* MSTP32 clocks */
-       {
-               /* SCIF5 */
-               .dev_id         = "sh-sci.5",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP029],
-       }, {
-               /* SCIF4 */
-               .dev_id         = "sh-sci.4",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP028],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP027],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP026],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP025],
-       }, {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP024],
-       },
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+
        CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]),
        CLKDEV_CON_ID("ssi0_fck", &mstp_clks[MSTP020]),
        CLKDEV_CON_ID("hac1_fck", &mstp_clks[MSTP017]),
        CLKDEV_CON_ID("hac0_fck", &mstp_clks[MSTP016]),
        CLKDEV_CON_ID("mmcif_fck", &mstp_clks[MSTP013]),
        CLKDEV_CON_ID("flctl_fck", &mstp_clks[MSTP012]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU3 */
-               .dev_id         = "sh_tmu.3",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU4 */
-               .dev_id         = "sh_tmu.4",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU5 */
-               .dev_id         = "sh_tmu.5",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[MSTP009]),
+
        CLKDEV_CON_ID("siof_fck", &mstp_clks[MSTP003]),
        CLKDEV_CON_ID("hspi_fck", &mstp_clks[MSTP002]),
        CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
index 42e403be9076da889384ec7544627bd144e47f1a..f6c0c3d5599f663a860a8a6aa38a46c5e654cba9 100644 (file)
@@ -125,8 +125,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP102] = SH_CLK_MSTP32(NULL, MSTPCR1, 2, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("extal", &extal_clk),
@@ -141,37 +139,13 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 
        /* MSTP32 clocks */
-       {
-               /* SCIF5 */
-               .dev_id         = "sh-sci.5",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP029],
-       }, {
-               /* SCIF4 */
-               .dev_id         = "sh-sci.4",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP028],
-       }, {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP027],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP026],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP025],
-       }, {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP024],
-       },
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP029]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP028]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+
        CLKDEV_CON_ID("ssi3_fck", &mstp_clks[MSTP023]),
        CLKDEV_CON_ID("ssi2_fck", &mstp_clks[MSTP022]),
        CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]),
@@ -180,67 +154,20 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("hac0_fck", &mstp_clks[MSTP016]),
        CLKDEV_CON_ID("i2c1_fck", &mstp_clks[MSTP015]),
        CLKDEV_CON_ID("i2c0_fck", &mstp_clks[MSTP014]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU3 */
-               .dev_id         = "sh_tmu.3",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU4 */
-               .dev_id         = "sh_tmu.4",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU5 */
-               .dev_id         = "sh_tmu.5",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU6 */
-               .dev_id         = "sh_tmu.6",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP010],
-       }, {
-               /* TMU7 */
-               .dev_id         = "sh_tmu.7",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP010],
-       }, {
-               /* TMU8 */
-               .dev_id         = "sh_tmu.8",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP010],
-       }, {
-               /* TMU9 */
-               .dev_id         = "sh_tmu.9",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP011],
-       }, {
-               /* TMU10 */
-               .dev_id         = "sh_tmu.10",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP011],
-       }, {
-               /* TMU11 */
-               .dev_id         = "sh_tmu.11",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP011],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.6", &mstp_clks[MSTP010]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.7", &mstp_clks[MSTP010]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.8", &mstp_clks[MSTP010]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.9", &mstp_clks[MSTP011]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.10", &mstp_clks[MSTP011]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.11", &mstp_clks[MSTP011]),
+
        CLKDEV_CON_ID("sdif1_fck", &mstp_clks[MSTP005]),
        CLKDEV_CON_ID("sdif0_fck", &mstp_clks[MSTP004]),
        CLKDEV_CON_ID("hspi_fck", &mstp_clks[MSTP002]),
index 1afdb93b8ccb28d9c3ce42517288934496a718cc..bf2d00b8b908705ee49504c99691ddb2268abf5d 100644 (file)
@@ -100,8 +100,6 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0),
 };
 
-#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
-
 static struct clk_lookup lookups[] = {
        /* main clocks */
        CLKDEV_CON_ID("extal", &extal_clk),
@@ -116,62 +114,23 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 
        /* MSTP32 clocks */
-       {
-               /* SCIF3 */
-               .dev_id         = "sh-sci.3",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP027],
-       }, {
-               /* SCIF2 */
-               .dev_id         = "sh-sci.2",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP026],
-       }, {
-               /* SCIF1 */
-               .dev_id         = "sh-sci.1",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP025],
-       }, {
-               /* SCIF0 */
-               .dev_id         = "sh-sci.0",
-               .con_id         = "sci_fck",
-               .clk            = &mstp_clks[MSTP024],
-       },
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP027]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP026]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
+       CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP024]),
+
        CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]),
        CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]),
        CLKDEV_CON_ID("fe1_fck", &mstp_clks[MSTP001]),
        CLKDEV_CON_ID("fe0_fck", &mstp_clks[MSTP000]),
-       {
-               /* TMU0 */
-               .dev_id         = "sh_tmu.0",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU1 */
-               .dev_id         = "sh_tmu.1",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU2 */
-               .dev_id         = "sh_tmu.2",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP008],
-       }, {
-               /* TMU3 */
-               .dev_id         = "sh_tmu.3",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU4 */
-               .dev_id         = "sh_tmu.4",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       }, {
-               /* TMU5 */
-               .dev_id         = "sh_tmu.5",
-               .con_id         = "tmu_fck",
-               .clk            = &mstp_clks[MSTP009],
-       },
+
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[MSTP008]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[MSTP009]),
+       CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[MSTP009]),
+
        CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
        CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
        CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
diff --git a/arch/sh/kernel/cpu/sh4a/serial-sh7722.c b/arch/sh/kernel/cpu/sh4a/serial-sh7722.c
new file mode 100644 (file)
index 0000000..59bc3a7
--- /dev/null
@@ -0,0 +1,23 @@
+#include <linux/serial_sci.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#define PSCR 0xA405011E
+
+static void sh7722_sci_init_pins(struct uart_port *port, unsigned int cflag)
+{
+       unsigned short data;
+
+       if (port->mapbase == 0xffe00000) {
+               data = __raw_readw(PSCR);
+               data &= ~0x03cf;
+               if (!(cflag & CRTSCTS))
+                       data |= 0x0340;
+
+               __raw_writew(data, PSCR);
+       }
+}
+
+struct plat_sci_port_ops sh7722_sci_port_ops = {
+       .init_pins      = sh7722_sci_init_pins,
+};
index 82616af64d62279465402d4d296171ee8f34e6be..87773869a2f3e952f8eb18a10b700f01cfe14e6e 100644 (file)
@@ -20,6 +20,7 @@
 
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xffe00000,
+       .port_reg       = 0xa405013e,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
index 5813d8023619d1f0e0da06bb51808017d30f2d97..278a0e572158697793d76404b6ffb87eb4c9a7c2 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <cpu/dma-register.h>
 #include <cpu/sh7722.h>
+#include <cpu/serial.h>
 
 static const struct sh_dmae_slave_config sh7722_dmae_slaves[] = {
        {
@@ -185,6 +186,8 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 80, 80, 80, 80 },
+       .ops            = &sh7722_sci_port_ops,
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -202,6 +205,8 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 81, 81, 81, 81 },
+       .ops            = &sh7722_sci_port_ops,
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -219,6 +224,8 @@ static struct plat_sci_port scif2_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 82, 82, 82, 82 },
+       .ops            = &sh7722_sci_port_ops,
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
index 072382280f96b8650c6f565bc181c60275152a53..3c2810d8f72e3caf81643baef9fabff588747736 100644 (file)
 /* Serial */
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xffe00000,
+       .port_reg       = 0xa4050160,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 80, 80, 80, 80 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -40,11 +42,13 @@ static struct platform_device scif0_device = {
 
 static struct plat_sci_port scif1_platform_data = {
        .mapbase        = 0xffe10000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 81, 81, 81, 81 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -57,11 +61,13 @@ static struct platform_device scif1_device = {
 
 static struct plat_sci_port scif2_platform_data = {
        .mapbase        = 0xffe20000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 82, 82, 82, 82 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -75,6 +81,7 @@ static struct platform_device scif2_device = {
 static struct plat_sci_port scif3_platform_data = {
        .mapbase        = 0xa4e30000,
        .flags          = UPF_BOOT_AUTOCONF,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
        .type           = PORT_SCIFA,
@@ -91,6 +98,7 @@ static struct platform_device scif3_device = {
 
 static struct plat_sci_port scif4_platform_data = {
        .mapbase        = 0xa4e40000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
@@ -108,6 +116,7 @@ static struct platform_device scif4_device = {
 
 static struct plat_sci_port scif5_platform_data = {
        .mapbase        = 0xa4e50000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
index 134a397b1918e0898c6f839503fe0d9a4411c08c..a37dd72c36719d06c938431691b48a9c56023790 100644 (file)
@@ -296,11 +296,13 @@ static struct platform_device dma1_device = {
 /* Serial */
 static struct plat_sci_port scif0_platform_data = {
        .mapbase        = 0xffe00000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 80, 80, 80, 80 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -313,11 +315,13 @@ static struct platform_device scif0_device = {
 
 static struct plat_sci_port scif1_platform_data = {
        .mapbase        = 0xffe10000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 81, 81, 81, 81 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -330,11 +334,13 @@ static struct platform_device scif1_device = {
 
 static struct plat_sci_port scif2_platform_data = {
        .mapbase        = 0xffe20000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 82, 82, 82, 82 },
+       .regtype        = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -347,6 +353,7 @@ static struct platform_device scif2_device = {
 
 static struct plat_sci_port scif3_platform_data = {
        .mapbase        = 0xa4e30000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
@@ -364,6 +371,7 @@ static struct platform_device scif3_device = {
 
 static struct plat_sci_port scif4_platform_data = {
        .mapbase        = 0xa4e40000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
@@ -381,6 +389,7 @@ static struct platform_device scif4_device = {
 
 static struct plat_sci_port scif5_platform_data = {
        .mapbase        = 0xa4e50000,
+       .port_reg       = SCIx_NOT_SUPPORTED,
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_3,
index 593eca6509b55c480787b704bca03cb8ebaa9ef0..00113515f23389d82baeab61841fc5c2a54d2e4b 100644 (file)
@@ -23,6 +23,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 40, 40, 40, 40 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -40,6 +41,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 76, 76, 76, 76 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -57,6 +59,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_2,
        .type           = PORT_SCIF,
        .irqs           = { 104, 104, 104, 104 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
index 08add7fa684979f8d6f02231ba2b784ca00c7e95..3d4d2075c19ad334ac40b8803b8e7ecffced0a96 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
-
 #include <cpu/dma-register.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -24,6 +23,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 40, 40, 40, 40 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -41,6 +41,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 76, 76, 76, 76 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
index 18d8fc136fb2b63c5d0ad3e9c80b87cfa695e27c..b29e6340414ab82ec54dd5f4c1c652eb50053aa5 100644 (file)
@@ -15,9 +15,7 @@
 #include <linux/mm.h>
 #include <linux/sh_dma.h>
 #include <linux/sh_timer.h>
-
 #include <asm/mmzone.h>
-
 #include <cpu/dma-register.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -27,6 +25,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 40, 40, 40, 40 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -44,6 +43,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 44, 44, 44, 44 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -61,6 +61,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 60, 60, 60, 60 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -78,6 +79,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 61, 61, 61, 61 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif3_device = {
@@ -95,6 +97,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 62, 62, 62, 62 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif4_device = {
@@ -112,6 +115,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 63, 63, 63, 63 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif5_device = {
index beba32beb6d9899f95f9e8aad01c44845835bcf9..dd5e709f982163f809e8650c791dd6668ddc3264 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SH7786 Setup
  *
- * Copyright (C) 2009 - 2010  Renesas Solutions Corp.
+ * Copyright (C) 2009 - 2011  Renesas Solutions Corp.
  * Kuninori Morimoto <morimoto.kuninori@renesas.com>
  * Paul Mundt <paul.mundt@renesas.com>
  *
@@ -33,6 +33,7 @@ static struct plat_sci_port scif0_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 40, 41, 43, 42 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif0_device = {
@@ -53,6 +54,7 @@ static struct plat_sci_port scif1_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 44, 44, 44, 44 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif1_device = {
@@ -70,6 +72,7 @@ static struct plat_sci_port scif2_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 50, 50, 50, 50 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif2_device = {
@@ -87,6 +90,7 @@ static struct plat_sci_port scif3_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 51, 51, 51, 51 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif3_device = {
@@ -104,6 +108,7 @@ static struct plat_sci_port scif4_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 52, 52, 52, 52 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif4_device = {
@@ -121,6 +126,7 @@ static struct plat_sci_port scif5_platform_data = {
        .scbrr_algo_id  = SCBRR_ALGO_1,
        .type           = PORT_SCIF,
        .irqs           = { 53, 53, 53, 53 },
+       .regtype        = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
 };
 
 static struct platform_device scif5_device = {
index cfa9cd2e5519b65f620048d2836f9c91c5d070c8..64f7a00b37479d905dfa41c0629a8d11548c1660 100644 (file)
@@ -177,9 +177,11 @@ static inline unsigned int sparc64_elf_hwcap(void)
                cap |= HWCAP_SPARC_ULTRA3;
        else if (tlb_type == hypervisor) {
                if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
-                   sun4v_chip_type == SUN4V_CHIP_NIAGARA2)
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
                        cap |= HWCAP_SPARC_BLKINIT;
-               if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2)
+               if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
                        cap |= HWCAP_SPARC_N2;
        }
 
index 75686409be245b4f11f7e675008f4e6e8f5bdf04..7a5f80df15d0e9745c1be67cda304dd6432caeb5 100644 (file)
@@ -2950,6 +2950,7 @@ extern unsigned long sun4v_ncs_request(unsigned long request,
 #define HV_GRP_N2_CPU                  0x0202
 #define HV_GRP_NIU                     0x0204
 #define HV_GRP_VF_CPU                  0x0205
+#define HV_GRP_KT_CPU                  0x0209
 #define HV_GRP_DIAG                    0x0300
 
 #ifndef __ASSEMBLY__
index 42b4b31a82fe55052e3bfe033bc294b6c9d1214f..f48527ebdd8f1011eacc97bfca29ef56af5387a5 100644 (file)
@@ -12,7 +12,7 @@ struct leon_pci_info {
        struct pci_ops *ops;
        struct resource io_space;
        struct resource mem_space;
-       int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin);
+       int (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
 };
 
 extern void leon_pci_init(struct platform_device *ofdev,
index f0d0c40c44da9c98bd83f573d6d8374d2c44172b..55a17c6efeb8d1ff5f592109e103aaee193885e0 100644 (file)
@@ -42,6 +42,7 @@
 #define SUN4V_CHIP_INVALID     0x00
 #define SUN4V_CHIP_NIAGARA1    0x01
 #define SUN4V_CHIP_NIAGARA2    0x02
+#define SUN4V_CHIP_NIAGARA3    0x03
 #define SUN4V_CHIP_UNKNOWN     0xff
 
 #ifndef __ASSEMBLY__
index bee4bf4be3af8cb4a41df1554252381eaddf952b..9ed6ff679ab7a5890f202fd67ca3a56b2b57def5 100644 (file)
@@ -65,6 +65,7 @@ static struct xor_block_template xor_block_niagara = {
 #define XOR_SELECT_TEMPLATE(FASTEST) \
        ((tlb_type == hypervisor && \
          (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 || \
-          sun4v_chip_type == SUN4V_CHIP_NIAGARA2)) ? \
+          sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || \
+          sun4v_chip_type == SUN4V_CHIP_NIAGARA3)) ? \
         &xor_block_niagara : \
         &xor_block_VIS)
index 138dbbc8dc8475d477119420fec89d582577006f..17cf290dc2bcc219631323e8c2c4c1e00e4d761d 100644 (file)
@@ -474,11 +474,18 @@ static void __init sun4v_cpu_probe(void)
                sparc_pmu_type = "niagara2";
                break;
 
+       case SUN4V_CHIP_NIAGARA3:
+               sparc_cpu_type = "UltraSparc T3 (Niagara3)";
+               sparc_fpu_type = "UltraSparc T3 integrated FPU";
+               sparc_pmu_type = "niagara3";
+               break;
+
        default:
                printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
                       prom_cpu_compatible);
                sparc_cpu_type = "Unknown SUN4V CPU";
                sparc_fpu_type = "Unknown SUN4V FPU";
+               sparc_pmu_type = "Unknown SUN4V PMU";
                break;
        }
 }
index d91fd782743a1ed1cd5c001407dec13f428922a5..4197e8d62d4c27890d1fac8b3b944b68020a553e 100644 (file)
@@ -324,6 +324,7 @@ static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
        switch (sun4v_chip_type) {
        case SUN4V_CHIP_NIAGARA1:
        case SUN4V_CHIP_NIAGARA2:
+       case SUN4V_CHIP_NIAGARA3:
                rover_inc_table = niagara_iterate_method;
                break;
        default:
index aa594c792d19f4dbc1fb5f0c34c307048ac17905..c752603a7c0dc4a4ca5b560dcbd0189b3eb4b329 100644 (file)
@@ -132,6 +132,8 @@ prom_sun4v_name:
        .asciz  "sun4v"
 prom_niagara_prefix:
        .asciz  "SUNW,UltraSPARC-T"
+prom_sparc_prefix:
+       .asciz  "SPARC-T"
        .align  4
 prom_root_compatible:
        .skip   64
@@ -379,6 +381,22 @@ sun4v_chip_type:
        sethi   %hi(prom_niagara_prefix), %g7
        or      %g7, %lo(prom_niagara_prefix), %g7
        mov     17, %g3
+90:    ldub    [%g7], %g2
+       ldub    [%g1], %g4
+       cmp     %g2, %g4
+       bne,pn  %icc, 89f
+        add    %g7, 1, %g7
+       subcc   %g3, 1, %g3
+       bne,pt  %xcc, 90b
+        add    %g1, 1, %g1
+       ba,pt   %xcc, 91f
+        nop
+
+89:    sethi   %hi(prom_cpu_compatible), %g1
+       or      %g1, %lo(prom_cpu_compatible), %g1
+       sethi   %hi(prom_sparc_prefix), %g7
+       or      %g7, %lo(prom_sparc_prefix), %g7
+       mov     7, %g3
 90:    ldub    [%g7], %g2
        ldub    [%g1], %g4
        cmp     %g2, %g4
@@ -389,6 +407,15 @@ sun4v_chip_type:
         add    %g1, 1, %g1
 
        sethi   %hi(prom_cpu_compatible), %g1
+       or      %g1, %lo(prom_cpu_compatible), %g1
+       ldub    [%g1 + 7], %g2
+       cmp     %g2, '3'
+       be,pt   %xcc, 5f
+        mov    SUN4V_CHIP_NIAGARA3, %g4
+       ba,pt   %xcc, 4f
+        nop
+
+91:    sethi   %hi(prom_cpu_compatible), %g1
        or      %g1, %lo(prom_cpu_compatible), %g1
        ldub    [%g1 + 17], %g2
        cmp     %g2, '1'
@@ -397,6 +424,7 @@ sun4v_chip_type:
        cmp     %g2, '2'
        be,pt   %xcc, 5f
         mov    SUN4V_CHIP_NIAGARA2, %g4
+       
 4:
        mov     SUN4V_CHIP_UNKNOWN, %g4
 5:     sethi   %hi(sun4v_chip_type), %g2
@@ -514,6 +542,9 @@ niagara_tlb_fixup:
         cmp    %g1, SUN4V_CHIP_NIAGARA2
        be,pt   %xcc, niagara2_patch
         nop
+       cmp     %g1, SUN4V_CHIP_NIAGARA3
+       be,pt   %xcc, niagara2_patch
+        nop
 
        call    generic_patch_copyops
         nop
index 7c60afb835b0426571654fb5aa719e84e6cc9bec..d306e648c33cb15ee2cdab960a906bdccf32df61 100644 (file)
@@ -38,6 +38,7 @@ static struct api_info api_table[] = {
        { .group = HV_GRP_N2_CPU,                               },
        { .group = HV_GRP_NIU,                                  },
        { .group = HV_GRP_VF_CPU,                               },
+       { .group = HV_GRP_KT_CPU,                               },
        { .group = HV_GRP_DIAG,         .flags = FLAG_PRE_API   },
 };
 
index 6ffccd6e0156aa87e9d5ca4134bf15a4b036d89f..d0479e2163faa8615b4a3cc6d75c1c87bb33d660 100644 (file)
@@ -65,9 +65,6 @@ static inline void dma_make_coherent(unsigned long pa, unsigned long len)
 }
 #endif
 
-static struct resource *_sparc_find_resource(struct resource *r,
-                                            unsigned long);
-
 static void __iomem *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz);
 static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys,
     unsigned long size, char *name);
@@ -143,7 +140,11 @@ void iounmap(volatile void __iomem *virtual)
        unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
        struct resource *res;
 
-       if ((res = _sparc_find_resource(&sparc_iomap, vaddr)) == NULL) {
+       /*
+        * XXX Too slow. Can have 8192 DVMA pages on sun4m in the worst case.
+        * This probably warrants some sort of hashing.
+       */
+       if ((res = lookup_resource(&sparc_iomap, vaddr)) == NULL) {
                printk("free_io/iounmap: cannot free %lx\n", vaddr);
                return;
        }
@@ -319,7 +320,7 @@ static void sbus_free_coherent(struct device *dev, size_t n, void *p,
        struct resource *res;
        struct page *pgv;
 
-       if ((res = _sparc_find_resource(&_sparc_dvma,
+       if ((res = lookup_resource(&_sparc_dvma,
            (unsigned long)p)) == NULL) {
                printk("sbus_free_consistent: cannot free %p\n", p);
                return;
@@ -492,7 +493,7 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p,
 {
        struct resource *res;
 
-       if ((res = _sparc_find_resource(&_sparc_dvma,
+       if ((res = lookup_resource(&_sparc_dvma,
            (unsigned long)p)) == NULL) {
                printk("pci_free_consistent: cannot free %p\n", p);
                return;
@@ -715,25 +716,6 @@ static const struct file_operations sparc_io_proc_fops = {
 };
 #endif /* CONFIG_PROC_FS */
 
-/*
- * This is a version of find_resource and it belongs to kernel/resource.c.
- * Until we have agreement with Linus and Martin, it lingers here.
- *
- * XXX Too slow. Can have 8192 DVMA pages on sun4m in the worst case.
- * This probably warrants some sort of hashing.
- */
-static struct resource *_sparc_find_resource(struct resource *root,
-                                            unsigned long hit)
-{
-       struct resource *tmp;
-
-       for (tmp = root->child; tmp != 0; tmp = tmp->sibling) {
-               if (tmp->start <= hit && tmp->end >= hit)
-                       return tmp;
-       }
-       return NULL;
-}
-
 static void register_proc_sparc_ioport(void)
 {
 #ifdef CONFIG_PROC_FS
index 44dc093ee33a4b0948c83e84b73d9eabb33c1bb7..fad1bd07cb56d76608d5545716e074cb99c77608 100644 (file)
@@ -215,7 +215,7 @@ struct grpci2_priv {
 DEFINE_SPINLOCK(grpci2_dev_lock);
 struct grpci2_priv *grpci2priv;
 
-int grpci2_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+int grpci2_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct grpci2_priv *priv = dev->bus->sysdata;
        int irq_group;
index 8ac23e6600804a7975ed59e238dfe707087e807c..343b0f9e2e7b704678e6f1d4b83609fe19cd6bbe 100644 (file)
@@ -80,8 +80,11 @@ static void n2_pcr_write(u64 val)
 {
        unsigned long ret;
 
-       ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
-       if (ret != HV_EOK)
+       if (val & PCR_N2_HTRACE) {
+               ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
+               if (ret != HV_EOK)
+                       write_pcr(val);
+       } else
                write_pcr(val);
 }
 
@@ -106,6 +109,10 @@ static int __init register_perf_hsvc(void)
                        perf_hsvc_group = HV_GRP_N2_CPU;
                        break;
 
+               case SUN4V_CHIP_NIAGARA3:
+                       perf_hsvc_group = HV_GRP_KT_CPU;
+                       break;
+
                default:
                        return -ENODEV;
                }
index 171e8d84dc3f32daa3dc1c46893ee022f9da77f7..614da624330c5057b9ad4d4b6a77ca1c51e4e123 100644 (file)
@@ -1343,7 +1343,8 @@ static bool __init supported_pmu(void)
                sparc_pmu = &niagara1_pmu;
                return true;
        }
-       if (!strcmp(sparc_pmu_type, "niagara2")) {
+       if (!strcmp(sparc_pmu_type, "niagara2") ||
+           !strcmp(sparc_pmu_type, "niagara3")) {
                sparc_pmu = &niagara2_pmu;
                return true;
        }
index 1a371f8ae0b0f57f9babb4ede85b910c528140f0..8600eb2461b5628f6569d731c5713944c8a1c242 100644 (file)
@@ -55,7 +55,7 @@ int atomic_cmpxchg(atomic_t *v, int old, int new)
 }
 EXPORT_SYMBOL(atomic_cmpxchg);
 
-int atomic_add_unless(atomic_t *v, int a, int u)
+int __atomic_add_unless(atomic_t *v, int a, int u)
 {
        int ret;
        unsigned long flags;
@@ -67,7 +67,7 @@ int atomic_add_unless(atomic_t *v, int a, int u)
        spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
        return ret != u;
 }
-EXPORT_SYMBOL(atomic_add_unless);
+EXPORT_SYMBOL(__atomic_add_unless);
 
 /* Atomic operations are already serializing */
 void atomic_set(atomic_t *v, int i)
index 6d4cb5d7a9fd0da47f0f78235c44072c310e57ba..2a8014cb1ff52f0ef3e24a58a5e20ddcfeb3c8cc 100644 (file)
@@ -228,7 +228,7 @@ err_cont:
  * (pin - 1) converts from the PCI standard's [1:4] convention to
  * a normal [0:3] range.
  */
-static int tile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int tile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct pci_controller *controller =
                (struct pci_controller *)dev->sysdata;
index 100eab842e6667d5c9248f3e3dc8cdf428028e54..4892fbb54ebfd508a4c0738d2df73af2c3bbafae 100644 (file)
@@ -102,7 +102,7 @@ void pci_puv3_preinit(void)
        writel(readl(PCIBRI_CMD) | PCIBRI_CMD_IO | PCIBRI_CMD_MEM, PCIBRI_CMD);
 }
 
-static int __init pci_puv3_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init pci_puv3_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (dev->bus->number == 0) {
 #ifdef CONFIG_ARCH_FPGA /* 4 pci slots */
index 153aa6f78299ea60210044409ce78d1f4b98743b..7cf916fc1ce7e4920204a184a15b6e5ef2cfd1a4 100644 (file)
@@ -1905,7 +1905,7 @@ config PCI_BIOS
 # x86-64 doesn't support PCI BIOS access from long mode so always go direct.
 config PCI_DIRECT
        def_bool y
-       depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC))
+       depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC || PCI_GOMMCONFIG))
 
 config PCI_MMCONFIG
        def_bool y
index 68c3c1395202eec5ad68bfc584d14ee9f4c1975e..ae3cb23cd89b86cdecbc6e202fb7e2d912079cf5 100644 (file)
@@ -246,10 +246,9 @@ static void add_resources(struct pci_root_info *info)
 
                conflict = insert_resource_conflict(root, res);
                if (conflict)
-                       dev_err(&info->bridge->dev,
-                               "address space collision: host bridge window %pR "
-                               "conflicts with %s %pR\n",
-                               res, conflict->name, conflict);
+                       dev_info(&info->bridge->dev,
+                                "ignoring host bridge window %pR (conflicts with %s %pR)\n",
+                                res, conflict->name, conflict);
                else
                        pci_bus_add_resource(info->bus, res, 0);
        }
index 67858be4b52b8066201cd5f5cfda657806476e32..99176094500b02aab75b8f8ba591ac50220b1186 100644 (file)
@@ -257,6 +257,7 @@ static int ce4100_conf_read(unsigned int seg, unsigned int bus,
 {
        int i;
 
+       WARN_ON(seg);
        if (bus == 1) {
                for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
                        if (bus1_fixups[i].dev_func == devfn &&
@@ -282,6 +283,7 @@ static int ce4100_conf_write(unsigned int seg, unsigned int bus,
 {
        int i;
 
+       WARN_ON(seg);
        if (bus == 1) {
                for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
                        if (bus1_fixups[i].dev_func == devfn &&
index 5fe75026ecc29a89a914b2c8a8c5cc367d96477d..92df322e0b571a09c49aa236e7dae3118fe353cb 100644 (file)
@@ -246,13 +246,6 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {
                },
        },
 #endif         /* __i386__ */
-       {
-               .callback = find_sort_method,
-               .ident = "Dell System",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
-               },
-       },
        {
                .callback = set_bf_sort,
                .ident = "Dell PowerEdge 1950",
@@ -293,6 +286,13 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"),
                },
        },
+       {
+               .callback = find_sort_method,
+               .ident = "Dell System",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+               },
+       },
        {
                .callback = set_bf_sort,
                .ident = "HP ProLiant BL20p G3",
index e6fd8473fb7bb4a245452959df4965d739365d66..4f2c70439d7fbb352993c4b8b9f3a76d39dfc438 100644 (file)
@@ -22,7 +22,7 @@ static int pci_conf1_read(unsigned int seg, unsigned int bus,
 {
        unsigned long flags;
 
-       if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
+       if (seg || (bus > 255) || (devfn > 255) || (reg > 4095)) {
                *value = -1;
                return -EINVAL;
        }
@@ -53,7 +53,7 @@ static int pci_conf1_write(unsigned int seg, unsigned int bus,
 {
        unsigned long flags;
 
-       if ((bus > 255) || (devfn > 255) || (reg > 4095))
+       if (seg || (bus > 255) || (devfn > 255) || (reg > 4095))
                return -EINVAL;
 
        raw_spin_lock_irqsave(&pci_config_lock, flags);
@@ -97,6 +97,7 @@ static int pci_conf2_read(unsigned int seg, unsigned int bus,
        unsigned long flags;
        int dev, fn;
 
+       WARN_ON(seg);
        if ((bus > 255) || (devfn > 255) || (reg > 255)) {
                *value = -1;
                return -EINVAL;
@@ -138,6 +139,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus,
        unsigned long flags;
        int dev, fn;
 
+       WARN_ON(seg);
        if ((bus > 255) || (devfn > 255) || (reg > 255)) 
                return -EINVAL;
 
index 5c9e2458df4e1cf28bb500e1256b4f3aa1e399e2..512a88c4150139027709645e797746f0555c5fb7 100644 (file)
@@ -34,6 +34,7 @@ static int pci_conf1_mq_read(unsigned int seg, unsigned int bus,
        unsigned long flags;
        void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
 
+       WARN_ON(seg);
        if (!value || (bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255))
                return -EINVAL;
 
@@ -73,6 +74,7 @@ static int pci_conf1_mq_write(unsigned int seg, unsigned int bus,
        unsigned long flags;
        void *adr __iomem = XQUAD_PORT_ADDR(0xcfc, BUS2QUAD(bus));
 
+       WARN_ON(seg);
        if ((bus >= MAX_MP_BUSSES) || (devfn > 255) || (reg > 255)) 
                return -EINVAL;
 
index 13700ec8e2e43587010594fe4e361ac88d29cb85..5262603b04d9d0b849df61ab98890705c1bed155 100644 (file)
@@ -206,6 +206,8 @@ static int pci_olpc_read(unsigned int seg, unsigned int bus,
 {
        uint32_t *addr;
 
+       WARN_ON(seg);
+
        /* Use the hardware mechanism for non-simulated devices */
        if (!is_simulated(bus, devfn))
                return pci_direct_conf1.read(seg, bus, devfn, reg, len, value);
@@ -264,6 +266,8 @@ static int pci_olpc_read(unsigned int seg, unsigned int bus,
 static int pci_olpc_write(unsigned int seg, unsigned int bus,
                unsigned int devfn, int reg, int len, uint32_t value)
 {
+       WARN_ON(seg);
+
        /* Use the hardware mechanism for non-simulated devices */
        if (!is_simulated(bus, devfn))
                return pci_direct_conf1.write(seg, bus, devfn, reg, len, value);
index a5f7d0d63de0def1481382f785d0fc34d553f0f6..f68553551467a0cbe6dd11a2cba04c6afaff5172 100644 (file)
@@ -181,6 +181,7 @@ static int pci_bios_read(unsigned int seg, unsigned int bus,
        unsigned long flags;
        unsigned long bx = (bus << 8) | devfn;
 
+       WARN_ON(seg);
        if (!value || (bus > 255) || (devfn > 255) || (reg > 255))
                return -EINVAL;
 
@@ -247,6 +248,7 @@ static int pci_bios_write(unsigned int seg, unsigned int bus,
        unsigned long flags;
        unsigned long bx = (bus << 8) | devfn;
 
+       WARN_ON(seg);
        if ((bus > 255) || (devfn > 255) || (reg > 255)) 
                return -EINVAL;
 
index 03008f72eb04a156450955174e7f112e9daa0070..6f2f8eeed17143276bb6352841e02fc7abbcc406 100644 (file)
@@ -24,7 +24,7 @@ static void pci_visws_disable_irq(struct pci_dev *dev) { }
 
 unsigned int pci_bus0, pci_bus1;
 
-static int __init visws_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static int __init visws_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq, bus = dev->bus->number;
 
index ccf73b2f3e6992d6cec20f8db6042f8538913c6b..45e94aca5bcef5aed5546c4a0cd25e1de5521e4e 100644 (file)
@@ -13,7 +13,9 @@ CFLAGS_mmu.o                  := $(nostackp)
 obj-y          := enlighten.o setup.o multicalls.o mmu.o irq.o \
                        time.o xen-asm.o xen-asm_$(BITS).o \
                        grant-table.o suspend.o platform-pci-unplug.o \
-                       p2m.o trace.o
+                       p2m.o
+
+obj-$(CONFIG_FUNCTION_TRACER) += trace.o
 
 obj-$(CONFIG_SMP)              += smp.o
 obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
index ac6739e085e3cede7ede5588854aeca8503f1c7c..c3de70de00d4c13f4d50e2a7e455bda2a4434fc6 100644 (file)
@@ -1,6 +1,6 @@
 /* n2-drv.c: Niagara-2 RNG driver.
  *
- * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2008, 2011 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/kernel.h>
@@ -22,8 +22,8 @@
 
 #define DRV_MODULE_NAME                "n2rng"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "0.1"
-#define DRV_MODULE_RELDATE     "May 15, 2008"
+#define DRV_MODULE_VERSION     "0.2"
+#define DRV_MODULE_RELDATE     "July 27, 2011"
 
 static char version[] __devinitdata =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -623,14 +623,14 @@ static const struct of_device_id n2rng_match[];
 static int __devinit n2rng_probe(struct platform_device *op)
 {
        const struct of_device_id *match;
-       int victoria_falls;
+       int multi_capable;
        int err = -ENOMEM;
        struct n2rng *np;
 
        match = of_match_device(n2rng_match, &op->dev);
        if (!match)
                return -EINVAL;
-       victoria_falls = (match->data != NULL);
+       multi_capable = (match->data != NULL);
 
        n2rng_driver_version();
        np = kzalloc(sizeof(*np), GFP_KERNEL);
@@ -640,8 +640,8 @@ static int __devinit n2rng_probe(struct platform_device *op)
 
        INIT_DELAYED_WORK(&np->work, n2rng_work);
 
-       if (victoria_falls)
-               np->flags |= N2RNG_FLAG_VF;
+       if (multi_capable)
+               np->flags |= N2RNG_FLAG_MULTI;
 
        err = -ENODEV;
        np->hvapi_major = 2;
@@ -658,10 +658,10 @@ static int __devinit n2rng_probe(struct platform_device *op)
                }
        }
 
-       if (np->flags & N2RNG_FLAG_VF) {
+       if (np->flags & N2RNG_FLAG_MULTI) {
                if (np->hvapi_major < 2) {
-                       dev_err(&op->dev, "VF RNG requires HVAPI major "
-                               "version 2 or later, got %lu\n",
+                       dev_err(&op->dev, "multi-unit-capable RNG requires "
+                               "HVAPI major version 2 or later, got %lu\n",
                                np->hvapi_major);
                        goto out_hvapi_unregister;
                }
@@ -688,8 +688,8 @@ static int __devinit n2rng_probe(struct platform_device *op)
                goto out_free_units;
 
        dev_info(&op->dev, "Found %s RNG, units: %d\n",
-                ((np->flags & N2RNG_FLAG_VF) ?
-                 "Victoria Falls" : "Niagara2"),
+                ((np->flags & N2RNG_FLAG_MULTI) ?
+                 "multi-unit-capable" : "single-unit"),
                 np->num_units);
 
        np->hwrng.name = "n2rng";
@@ -751,6 +751,11 @@ static const struct of_device_id n2rng_match[] = {
                .compatible     = "SUNW,vf-rng",
                .data           = (void *) 1,
        },
+       {
+               .name           = "random-number-generator",
+               .compatible     = "SUNW,kt-rng",
+               .data           = (void *) 1,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, n2rng_match);
index 4bea07f30978e7ae95a2a94f69c8b3d03955dd7f..f244ac89087fd1f38e4d191dc15c3b7e41c488ff 100644 (file)
@@ -68,7 +68,7 @@ struct n2rng {
        struct platform_device  *op;
 
        unsigned long           flags;
-#define N2RNG_FLAG_VF          0x00000001 /* Victoria Falls RNG, else N2 */
+#define N2RNG_FLAG_MULTI       0x00000001 /* Multi-unit capable RNG */
 #define N2RNG_FLAG_CONTROL     0x00000002 /* Operating in control domain */
 #define N2RNG_FLAG_READY       0x00000008 /* Ready for hw-rng layer      */
 #define N2RNG_FLAG_SHUTDOWN    0x00000010 /* Driver unregistering        */
index bd9b94b518f39da6e16ca9f080b9d1ce32a95993..fca0c51bbc90c92bb605588840f5bdf9bfdc5c2f 100644 (file)
@@ -22,6 +22,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/kmsg_dump.h>
 #include <linux/time.h>
index 7beb0e25f1e1e2ca192ae563eb43f6dc0147f8f8..caf8012ef47ce1c69af6f07df4f62e7c5676a581 100644 (file)
@@ -534,6 +534,7 @@ void tpm_get_timeouts(struct tpm_chip *chip)
        struct duration_t *duration_cap;
        ssize_t rc;
        u32 timeout;
+       unsigned int scale = 1;
 
        tpm_cmd.header.in = tpm_getcap_header;
        tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
@@ -545,24 +546,30 @@ void tpm_get_timeouts(struct tpm_chip *chip)
        if (rc)
                goto duration;
 
-       if (be32_to_cpu(tpm_cmd.header.out.length)
-           != 4 * sizeof(u32))
-               goto duration;
+       if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
+           be32_to_cpu(tpm_cmd.header.out.length)
+           != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
+               return;
 
        timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
        /* Don't overwrite default if value is 0 */
        timeout = be32_to_cpu(timeout_cap->a);
+       if (timeout && timeout < 1000) {
+               /* timeouts in msec rather usec */
+               scale = 1000;
+               chip->vendor.timeout_adjusted = true;
+       }
        if (timeout)
-               chip->vendor.timeout_a = usecs_to_jiffies(timeout);
+               chip->vendor.timeout_a = usecs_to_jiffies(timeout * scale);
        timeout = be32_to_cpu(timeout_cap->b);
        if (timeout)
-               chip->vendor.timeout_b = usecs_to_jiffies(timeout);
+               chip->vendor.timeout_b = usecs_to_jiffies(timeout * scale);
        timeout = be32_to_cpu(timeout_cap->c);
        if (timeout)
-               chip->vendor.timeout_c = usecs_to_jiffies(timeout);
+               chip->vendor.timeout_c = usecs_to_jiffies(timeout * scale);
        timeout = be32_to_cpu(timeout_cap->d);
        if (timeout)
-               chip->vendor.timeout_d = usecs_to_jiffies(timeout);
+               chip->vendor.timeout_d = usecs_to_jiffies(timeout * scale);
 
 duration:
        tpm_cmd.header.in = tpm_getcap_header;
@@ -575,23 +582,31 @@ duration:
        if (rc)
                return;
 
-       if (be32_to_cpu(tpm_cmd.header.out.return_code)
-           != 3 * sizeof(u32))
+       if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
+           be32_to_cpu(tpm_cmd.header.out.length)
+           != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
                return;
+
        duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
        chip->vendor.duration[TPM_SHORT] =
            usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
+       chip->vendor.duration[TPM_MEDIUM] =
+           usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
+       chip->vendor.duration[TPM_LONG] =
+           usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
+
        /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
         * value wrong and apparently reports msecs rather than usecs. So we
         * fix up the resulting too-small TPM_SHORT value to make things work.
+        * We also scale the TPM_MEDIUM and -_LONG values by 1000.
         */
-       if (chip->vendor.duration[TPM_SHORT] < (HZ/100))
+       if (chip->vendor.duration[TPM_SHORT] < (HZ / 100)) {
                chip->vendor.duration[TPM_SHORT] = HZ;
-
-       chip->vendor.duration[TPM_MEDIUM] =
-           usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
-       chip->vendor.duration[TPM_LONG] =
-           usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
+               chip->vendor.duration[TPM_MEDIUM] *= 1000;
+               chip->vendor.duration[TPM_LONG] *= 1000;
+               chip->vendor.duration_adjusted = true;
+               dev_info(chip->dev, "Adjusting TPM timeout parameters.");
+       }
 }
 EXPORT_SYMBOL_GPL(tpm_get_timeouts);
 
@@ -600,7 +615,7 @@ void tpm_continue_selftest(struct tpm_chip *chip)
        u8 data[] = {
                0, 193,                 /* TPM_TAG_RQU_COMMAND */
                0, 0, 0, 10,            /* length */
-               0, 0, 0, 83,            /* TPM_ORD_GetCapability */
+               0, 0, 0, 83,            /* TPM_ORD_ContinueSelfTest */
        };
 
        tpm_transmit(chip, data, sizeof(data));
@@ -863,18 +878,24 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
        data = tpm_cmd.params.readpubek_out_buffer;
        str +=
            sprintf(str,
-                   "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
-                   "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
-                   " %02X %02X %02X %02X %02X %02X %02X %02X\n"
-                   "Modulus length: %d\nModulus: \n",
-                   data[10], data[11], data[12], data[13], data[14],
-                   data[15], data[16], data[17], data[22], data[23],
-                   data[24], data[25], data[26], data[27], data[28],
-                   data[29], data[30], data[31], data[32], data[33],
-                   be32_to_cpu(*((__be32 *) (data + 34))));
+                   "Algorithm: %02X %02X %02X %02X\n"
+                   "Encscheme: %02X %02X\n"
+                   "Sigscheme: %02X %02X\n"
+                   "Parameters: %02X %02X %02X %02X "
+                   "%02X %02X %02X %02X "
+                   "%02X %02X %02X %02X\n"
+                   "Modulus length: %d\n"
+                   "Modulus:\n",
+                   data[0], data[1], data[2], data[3],
+                   data[4], data[5],
+                   data[6], data[7],
+                   data[12], data[13], data[14], data[15],
+                   data[16], data[17], data[18], data[19],
+                   data[20], data[21], data[22], data[23],
+                   be32_to_cpu(*((__be32 *) (data + 24))));
 
        for (i = 0; i < 256; i++) {
-               str += sprintf(str, "%02X ", data[i + 38]);
+               str += sprintf(str, "%02X ", data[i + 28]);
                if ((i + 1) % 16 == 0)
                        str += sprintf(str, "\n");
        }
@@ -937,6 +958,35 @@ ssize_t tpm_show_caps_1_2(struct device * dev,
 }
 EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
 
+ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d %d %d [%s]\n",
+                      jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]),
+                      jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]),
+                      jiffies_to_usecs(chip->vendor.duration[TPM_LONG]),
+                      chip->vendor.duration_adjusted
+                      ? "adjusted" : "original");
+}
+EXPORT_SYMBOL_GPL(tpm_show_durations);
+
+ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d %d %d %d [%s]\n",
+                      jiffies_to_usecs(chip->vendor.timeout_a),
+                      jiffies_to_usecs(chip->vendor.timeout_b),
+                      jiffies_to_usecs(chip->vendor.timeout_c),
+                      jiffies_to_usecs(chip->vendor.timeout_d),
+                      chip->vendor.timeout_adjusted
+                      ? "adjusted" : "original");
+}
+EXPORT_SYMBOL_GPL(tpm_show_timeouts);
+
 ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
index 72ddb031b69a24e425a22d5892283b91f6cc1eec..9c4163cfa3ce94ab230ff3b9a58d568206634561 100644 (file)
@@ -56,6 +56,10 @@ extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr,
                                char *);
 extern ssize_t tpm_show_temp_deactivated(struct device *,
                                         struct device_attribute *attr, char *);
+extern ssize_t tpm_show_durations(struct device *,
+                                 struct device_attribute *attr, char *);
+extern ssize_t tpm_show_timeouts(struct device *,
+                                struct device_attribute *attr, char *);
 
 struct tpm_chip;
 
@@ -67,6 +71,7 @@ struct tpm_vendor_specific {
        unsigned long base;             /* TPM base address */
 
        int irq;
+       int probed_irq;
 
        int region_size;
        int have_region;
@@ -81,7 +86,9 @@ struct tpm_vendor_specific {
        struct list_head list;
        int locality;
        unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
+       bool timeout_adjusted;
        unsigned long duration[3]; /* jiffies */
+       bool duration_adjusted;
 
        wait_queue_head_t read_queue;
        wait_queue_head_t int_queue;
index a605cb7dd89887676d3af3102fde78b2ccbd3c51..82facc9104c761562419d488cfca0f81ac8b7ced 100644 (file)
@@ -330,12 +330,12 @@ static int __init init_nsc(void)
        pdev->dev.driver = &nsc_drv.driver;
        pdev->dev.release = tpm_nsc_remove;
 
-       if ((rc = platform_device_register(pdev)) < 0)
-               goto err_free_dev;
+       if ((rc = platform_device_add(pdev)) < 0)
+               goto err_put_dev;
 
        if (request_region(base, 2, "tpm_nsc0") == NULL ) {
                rc = -EBUSY;
-               goto err_unreg_dev;
+               goto err_del_dev;
        }
 
        if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
@@ -382,10 +382,10 @@ static int __init init_nsc(void)
 
 err_rel_reg:
        release_region(base, 2);
-err_unreg_dev:
-       platform_device_unregister(pdev);
-err_free_dev:
-       kfree(pdev);
+err_del_dev:
+       platform_device_del(pdev);
+err_put_dev:
+       platform_device_put(pdev);
 err_unreg_drv:
        platform_driver_unregister(&nsc_drv);
        return rc;
index dd21df55689d96a39d5fea3f66d2161dfec44467..7fc2f108f4904debbc306664816fa8259d8d354b 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/wait.h>
 #include <linux/acpi.h>
+#include <linux/freezer.h>
 #include "tpm.h"
 
 #define TPM_HEADER_SIZE 10
@@ -79,7 +80,7 @@ enum tis_defaults {
 static LIST_HEAD(tis_chips);
 static DEFINE_SPINLOCK(tis_lock);
 
-#ifdef CONFIG_ACPI
+#ifdef CONFIG_PNP
 static int is_itpm(struct pnp_dev *dev)
 {
        struct acpi_device *acpi = pnp_acpi_device(dev);
@@ -92,11 +93,6 @@ static int is_itpm(struct pnp_dev *dev)
 
        return 0;
 }
-#else
-static int is_itpm(struct pnp_dev *dev)
-{
-       return 0;
-}
 #endif
 
 static int check_locality(struct tpm_chip *chip, int l)
@@ -120,7 +116,7 @@ static void release_locality(struct tpm_chip *chip, int l, int force)
 
 static int request_locality(struct tpm_chip *chip, int l)
 {
-       unsigned long stop;
+       unsigned long stop, timeout;
        long rc;
 
        if (check_locality(chip, l) >= 0)
@@ -129,17 +125,25 @@ static int request_locality(struct tpm_chip *chip, int l)
        iowrite8(TPM_ACCESS_REQUEST_USE,
                 chip->vendor.iobase + TPM_ACCESS(l));
 
+       stop = jiffies + chip->vendor.timeout_a;
+
        if (chip->vendor.irq) {
+again:
+               timeout = stop - jiffies;
+               if ((long)timeout <= 0)
+                       return -1;
                rc = wait_event_interruptible_timeout(chip->vendor.int_queue,
                                                      (check_locality
                                                       (chip, l) >= 0),
-                                                     chip->vendor.timeout_a);
+                                                     timeout);
                if (rc > 0)
                        return l;
-
+               if (rc == -ERESTARTSYS && freezing(current)) {
+                       clear_thread_flag(TIF_SIGPENDING);
+                       goto again;
+               }
        } else {
                /* wait for burstcount */
-               stop = jiffies + chip->vendor.timeout_a;
                do {
                        if (check_locality(chip, l) >= 0)
                                return l;
@@ -196,15 +200,24 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
        if ((status & mask) == mask)
                return 0;
 
+       stop = jiffies + timeout;
+
        if (chip->vendor.irq) {
+again:
+               timeout = stop - jiffies;
+               if ((long)timeout <= 0)
+                       return -ETIME;
                rc = wait_event_interruptible_timeout(*queue,
                                                      ((tpm_tis_status
                                                        (chip) & mask) ==
                                                       mask), timeout);
                if (rc > 0)
                        return 0;
+               if (rc == -ERESTARTSYS && freezing(current)) {
+                       clear_thread_flag(TIF_SIGPENDING);
+                       goto again;
+               }
        } else {
-               stop = jiffies + timeout;
                do {
                        msleep(TPM_TIMEOUT);
                        status = tpm_tis_status(chip);
@@ -288,11 +301,10 @@ MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)");
  * tpm.c can skip polling for the data to be available as the interrupt is
  * waited for here
  */
-static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
+static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
 {
        int rc, status, burstcnt;
        size_t count = 0;
-       u32 ordinal;
 
        if (request_locality(chip, 0) < 0)
                return -EBUSY;
@@ -327,8 +339,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
 
        /* write last byte */
        iowrite8(buf[count],
-                chip->vendor.iobase +
-                TPM_DATA_FIFO(chip->vendor.locality));
+                chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
        wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
                      &chip->vendor.int_queue);
        status = tpm_tis_status(chip);
@@ -337,6 +348,28 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
                goto out_err;
        }
 
+       return 0;
+
+out_err:
+       tpm_tis_ready(chip);
+       release_locality(chip, chip->vendor.locality, 0);
+       return rc;
+}
+
+/*
+ * If interrupts are used (signaled by an irq set in the vendor structure)
+ * tpm.c can skip polling for the data to be available as the interrupt is
+ * waited for here
+ */
+static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
+{
+       int rc;
+       u32 ordinal;
+
+       rc = tpm_tis_send_data(chip, buf, len);
+       if (rc < 0)
+               return rc;
+
        /* go and do it */
        iowrite8(TPM_STS_GO,
                 chip->vendor.iobase + TPM_STS(chip->vendor.locality));
@@ -358,6 +391,47 @@ out_err:
        return rc;
 }
 
+/*
+ * Early probing for iTPM with STS_DATA_EXPECT flaw.
+ * Try sending command without itpm flag set and if that
+ * fails, repeat with itpm flag set.
+ */
+static int probe_itpm(struct tpm_chip *chip)
+{
+       int rc = 0;
+       u8 cmd_getticks[] = {
+               0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a,
+               0x00, 0x00, 0x00, 0xf1
+       };
+       size_t len = sizeof(cmd_getticks);
+       int rem_itpm = itpm;
+
+       itpm = 0;
+
+       rc = tpm_tis_send_data(chip, cmd_getticks, len);
+       if (rc == 0)
+               goto out;
+
+       tpm_tis_ready(chip);
+       release_locality(chip, chip->vendor.locality, 0);
+
+       itpm = 1;
+
+       rc = tpm_tis_send_data(chip, cmd_getticks, len);
+       if (rc == 0) {
+               dev_info(chip->dev, "Detected an iTPM.\n");
+               rc = 1;
+       } else
+               rc = -EFAULT;
+
+out:
+       itpm = rem_itpm;
+       tpm_tis_ready(chip);
+       release_locality(chip, chip->vendor.locality, 0);
+
+       return rc;
+}
+
 static const struct file_operations tis_ops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
@@ -376,6 +450,8 @@ static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
                   NULL);
 static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL);
 static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
+static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
+static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
 
 static struct attribute *tis_attrs[] = {
        &dev_attr_pubek.attr,
@@ -385,7 +461,9 @@ static struct attribute *tis_attrs[] = {
        &dev_attr_owned.attr,
        &dev_attr_temp_deactivated.attr,
        &dev_attr_caps.attr,
-       &dev_attr_cancel.attr, NULL,
+       &dev_attr_cancel.attr,
+       &dev_attr_durations.attr,
+       &dev_attr_timeouts.attr, NULL,
 };
 
 static struct attribute_group tis_attr_grp = {
@@ -416,7 +494,7 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id)
        if (interrupt == 0)
                return IRQ_NONE;
 
-       chip->vendor.irq = irq;
+       chip->vendor.probed_irq = irq;
 
        /* Clear interrupts handled with TPM_EOI */
        iowrite32(interrupt,
@@ -464,7 +542,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
                        resource_size_t len, unsigned int irq)
 {
        u32 vendor, intfcaps, intmask;
-       int rc, i;
+       int rc, i, irq_s, irq_e;
        struct tpm_chip *chip;
 
        if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
@@ -493,6 +571,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
                 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
                 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
 
+       if (!itpm) {
+               itpm = probe_itpm(chip);
+               if (itpm < 0) {
+                       rc = -ENODEV;
+                       goto out_err;
+               }
+       }
+
        if (itpm)
                dev_info(dev, "Intel iTPM workaround enabled\n");
 
@@ -522,6 +608,9 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
        if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
                dev_dbg(dev, "\tData Avail Int Support\n");
 
+       /* get the timeouts before testing for irqs */
+       tpm_get_timeouts(chip);
+
        /* INTERRUPT Setup */
        init_waitqueue_head(&chip->vendor.read_queue);
        init_waitqueue_head(&chip->vendor.int_queue);
@@ -540,13 +629,19 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
        if (interrupts)
                chip->vendor.irq = irq;
        if (interrupts && !chip->vendor.irq) {
-               chip->vendor.irq =
+               irq_s =
                    ioread8(chip->vendor.iobase +
                            TPM_INT_VECTOR(chip->vendor.locality));
+               if (irq_s) {
+                       irq_e = irq_s;
+               } else {
+                       irq_s = 3;
+                       irq_e = 15;
+               }
 
-               for (i = 3; i < 16 && chip->vendor.irq == 0; i++) {
+               for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
                        iowrite8(i, chip->vendor.iobase +
-                                   TPM_INT_VECTOR(chip->vendor.locality));
+                                TPM_INT_VECTOR(chip->vendor.locality));
                        if (request_irq
                            (i, tis_int_probe, IRQF_SHARED,
                             chip->vendor.miscdev.name, chip) != 0) {
@@ -568,9 +663,22 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
                                  chip->vendor.iobase +
                                  TPM_INT_ENABLE(chip->vendor.locality));
 
+                       chip->vendor.probed_irq = 0;
+
                        /* Generate Interrupts */
                        tpm_gen_interrupt(chip);
 
+                       chip->vendor.irq = chip->vendor.probed_irq;
+
+                       /* free_irq will call into tis_int_probe;
+                          clear all irqs we haven't seen while doing
+                          tpm_gen_interrupt */
+                       iowrite32(ioread32
+                                 (chip->vendor.iobase +
+                                  TPM_INT_STATUS(chip->vendor.locality)),
+                                 chip->vendor.iobase +
+                                 TPM_INT_STATUS(chip->vendor.locality));
+
                        /* Turn off */
                        iowrite32(intmask,
                                  chip->vendor.iobase +
@@ -609,7 +717,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
        list_add(&chip->vendor.list, &tis_chips);
        spin_unlock(&tis_lock);
 
-       tpm_get_timeouts(chip);
        tpm_continue_selftest(chip);
 
        return 0;
@@ -619,6 +726,29 @@ out_err:
        tpm_remove_hardware(chip->dev);
        return rc;
 }
+
+static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
+{
+       u32 intmask;
+
+       /* reenable interrupts that device may have lost or
+          BIOS/firmware may have disabled */
+       iowrite8(chip->vendor.irq, chip->vendor.iobase +
+                TPM_INT_VECTOR(chip->vendor.locality));
+
+       intmask =
+           ioread32(chip->vendor.iobase +
+                    TPM_INT_ENABLE(chip->vendor.locality));
+
+       intmask |= TPM_INTF_CMD_READY_INT
+           | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
+           | TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE;
+
+       iowrite32(intmask,
+                 chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
+}
+
+
 #ifdef CONFIG_PNP
 static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
                                      const struct pnp_device_id *pnp_id)
@@ -650,6 +780,9 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev)
        struct tpm_chip *chip = pnp_get_drvdata(dev);
        int ret;
 
+       if (chip->vendor.irq)
+               tpm_tis_reenable_interrupts(chip);
+
        ret = tpm_pm_resume(&dev->dev);
        if (!ret)
                tpm_continue_selftest(chip);
@@ -702,6 +835,11 @@ static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg)
 
 static int tpm_tis_resume(struct platform_device *dev)
 {
+       struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
+
+       if (chip->vendor.irq)
+               tpm_tis_reenable_interrupts(chip);
+
        return tpm_pm_resume(&dev->dev);
 }
 static struct platform_driver tis_drv = {
index 2e5b2044c96f7a2cb6311a03c79d972aee49d287..d0183ddb3076d1dec3b668e355e2967eb5046bc7 100644 (file)
@@ -1,6 +1,6 @@
 /* n2_core.c: Niagara2 Stream Processing Unit (SPU) crypto support.
  *
- * Copyright (C) 2010 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2010, 2011 David S. Miller <davem@davemloft.net>
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -31,8 +31,8 @@
 #include "n2_core.h"
 
 #define DRV_MODULE_NAME                "n2_crypto"
-#define DRV_MODULE_VERSION     "0.1"
-#define DRV_MODULE_RELDATE     "April 29, 2010"
+#define DRV_MODULE_VERSION     "0.2"
+#define DRV_MODULE_RELDATE     "July 28, 2011"
 
 static char version[] __devinitdata =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -1823,22 +1823,17 @@ static int spu_mdesc_scan(struct mdesc_handle *mdesc, struct platform_device *de
 static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
                                   struct spu_mdesc_info *ip)
 {
-       const u64 *intr, *ino;
-       int intr_len, ino_len;
+       const u64 *ino;
+       int ino_len;
        int i;
 
-       intr = mdesc_get_property(mdesc, node, "intr", &intr_len);
-       if (!intr)
-               return -ENODEV;
-
        ino = mdesc_get_property(mdesc, node, "ino", &ino_len);
-       if (!ino)
+       if (!ino) {
+               printk("NO 'ino'\n");
                return -ENODEV;
+       }
 
-       if (intr_len != ino_len)
-               return -EINVAL;
-
-       ip->num_intrs = intr_len / sizeof(u64);
+       ip->num_intrs = ino_len / sizeof(u64);
        ip->ino_table = kzalloc((sizeof(struct ino_blob) *
                                 ip->num_intrs),
                                GFP_KERNEL);
@@ -1847,7 +1842,7 @@ static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
 
        for (i = 0; i < ip->num_intrs; i++) {
                struct ino_blob *b = &ip->ino_table[i];
-               b->intr = intr[i];
+               b->intr = i + 1;
                b->ino = ino[i];
        }
 
@@ -2204,6 +2199,10 @@ static struct of_device_id n2_crypto_match[] = {
                .name = "n2cp",
                .compatible = "SUNW,vf-cwq",
        },
+       {
+               .name = "n2cp",
+               .compatible = "SUNW,kt-cwq",
+       },
        {},
 };
 
@@ -2228,6 +2227,10 @@ static struct of_device_id n2_mau_match[] = {
                .name = "ncp",
                .compatible = "SUNW,vf-mau",
        },
+       {
+               .name = "ncp",
+               .compatible = "SUNW,kt-mau",
+       },
        {},
 };
 
index 1ea47db2ff0630e6cb90f429f7008398597902e3..1eb60ded2f0de21b29bdd672b3609f8a3b7d716b 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/irq.h>
 #include <mach/sdma.h>
@@ -65,8 +67,8 @@
 #define SDMA_ONCE_RTB          0x060
 #define SDMA_XTRIG_CONF1       0x070
 #define SDMA_XTRIG_CONF2       0x074
-#define SDMA_CHNENBL0_V2       0x200
-#define SDMA_CHNENBL0_V1       0x080
+#define SDMA_CHNENBL0_IMX35    0x200
+#define SDMA_CHNENBL0_IMX31    0x080
 #define SDMA_CHNPRI_0          0x100
 
 /*
@@ -299,13 +301,18 @@ struct sdma_firmware_header {
        u32     ram_code_size;
 };
 
+enum sdma_devtype {
+       IMX31_SDMA,     /* runs on i.mx31 */
+       IMX35_SDMA,     /* runs on i.mx35 and later */
+};
+
 struct sdma_engine {
        struct device                   *dev;
        struct device_dma_parameters    dma_parms;
        struct sdma_channel             channel[MAX_DMA_CHANNELS];
        struct sdma_channel_control     *channel_control;
        void __iomem                    *regs;
-       unsigned int                    version;
+       enum sdma_devtype               devtype;
        unsigned int                    num_events;
        struct sdma_context_data        *context;
        dma_addr_t                      context_phys;
@@ -314,6 +321,26 @@ struct sdma_engine {
        struct sdma_script_start_addrs  *script_addrs;
 };
 
+static struct platform_device_id sdma_devtypes[] = {
+       {
+               .name = "imx31-sdma",
+               .driver_data = IMX31_SDMA,
+       }, {
+               .name = "imx35-sdma",
+               .driver_data = IMX35_SDMA,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, sdma_devtypes);
+
+static const struct of_device_id sdma_dt_ids[] = {
+       { .compatible = "fsl,imx31-sdma", .data = &sdma_devtypes[IMX31_SDMA], },
+       { .compatible = "fsl,imx35-sdma", .data = &sdma_devtypes[IMX35_SDMA], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sdma_dt_ids);
+
 #define SDMA_H_CONFIG_DSPDMA   (1 << 12) /* indicates if the DSPDMA is used */
 #define SDMA_H_CONFIG_RTD_PINS (1 << 11) /* indicates if Real-Time Debug pins are enabled */
 #define SDMA_H_CONFIG_ACR      (1 << 4)  /* indicates if AHB freq /core freq = 2 or 1 */
@@ -321,8 +348,8 @@ struct sdma_engine {
 
 static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
 {
-       u32 chnenbl0 = (sdma->version == 2 ? SDMA_CHNENBL0_V2 : SDMA_CHNENBL0_V1);
-
+       u32 chnenbl0 = (sdma->devtype == IMX31_SDMA ? SDMA_CHNENBL0_IMX31 :
+                                                     SDMA_CHNENBL0_IMX35);
        return chnenbl0 + event * 4;
 }
 
@@ -1108,22 +1135,14 @@ static int __init sdma_get_firmware(struct sdma_engine *sdma,
                const char *fw_name)
 {
        const struct firmware *fw;
-       char *fwname;
        const struct sdma_firmware_header *header;
        int ret;
        const struct sdma_script_start_addrs *addr;
        unsigned short *ram_code;
 
-       fwname = kasprintf(GFP_KERNEL, "%s", fw_name);
-       if (!fwname)
-               return -ENOMEM;
-
-       ret = request_firmware(&fw, fwname, sdma->dev);
-       if (ret) {
-               kfree(fwname);
+       ret = request_firmware(&fw, fw_name, sdma->dev);
+       if (ret)
                return ret;
-       }
-       kfree(fwname);
 
        if (fw->size < sizeof(*header))
                goto err_firmware;
@@ -1162,15 +1181,16 @@ static int __init sdma_init(struct sdma_engine *sdma)
        int i, ret;
        dma_addr_t ccb_phys;
 
-       switch (sdma->version) {
-       case 1:
+       switch (sdma->devtype) {
+       case IMX31_SDMA:
                sdma->num_events = 32;
                break;
-       case 2:
+       case IMX35_SDMA:
                sdma->num_events = 48;
                break;
        default:
-               dev_err(sdma->dev, "Unknown version %d. aborting\n", sdma->version);
+               dev_err(sdma->dev, "Unknown sdma type %d. aborting\n",
+                       sdma->devtype);
                return -ENODEV;
        }
 
@@ -1239,6 +1259,10 @@ err_dma_alloc:
 
 static int __init sdma_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *of_id =
+                       of_match_device(sdma_dt_ids, &pdev->dev);
+       struct device_node *np = pdev->dev.of_node;
+       const char *fw_name;
        int ret;
        int irq;
        struct resource *iores;
@@ -1254,7 +1278,7 @@ static int __init sdma_probe(struct platform_device *pdev)
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if (!iores || irq < 0 || !pdata) {
+       if (!iores || irq < 0) {
                ret = -EINVAL;
                goto err_irq;
        }
@@ -1284,7 +1308,9 @@ static int __init sdma_probe(struct platform_device *pdev)
        if (!sdma->script_addrs)
                goto err_alloc;
 
-       sdma->version = pdata->sdma_version;
+       if (of_id)
+               pdev->id_entry = of_id->data;
+       sdma->devtype = pdev->id_entry->driver_data;
 
        dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
        dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
@@ -1314,10 +1340,30 @@ static int __init sdma_probe(struct platform_device *pdev)
        if (ret)
                goto err_init;
 
-       if (pdata->script_addrs)
+       if (pdata && pdata->script_addrs)
                sdma_add_scripts(sdma, pdata->script_addrs);
 
-       sdma_get_firmware(sdma, pdata->fw_name);
+       if (pdata) {
+               sdma_get_firmware(sdma, pdata->fw_name);
+       } else {
+               /*
+                * Because that device tree does not encode ROM script address,
+                * the RAM script in firmware is mandatory for device tree
+                * probe, otherwise it fails.
+                */
+               ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
+                                             &fw_name);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to get firmware name\n");
+                       goto err_init;
+               }
+
+               ret = sdma_get_firmware(sdma, fw_name);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to get firmware\n");
+                       goto err_init;
+               }
+       }
 
        sdma->dma_device.dev = &pdev->dev;
 
@@ -1365,7 +1411,9 @@ static int __exit sdma_remove(struct platform_device *pdev)
 static struct platform_driver sdma_driver = {
        .driver         = {
                .name   = "imx-sdma",
+               .of_match_table = sdma_dt_ids,
        },
+       .id_table       = sdma_devtypes,
        .remove         = __exit_p(sdma_remove),
 };
 
index 02833004420151fac42fdbb07e6cebd86d29df70..7f49235d14b91a75cc5518d795c5c117c9de729b 100644 (file)
@@ -70,12 +70,36 @@ static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg)
 
 static u16 dmaor_read(struct sh_dmae_device *shdev)
 {
-       return __raw_readw(shdev->chan_reg + DMAOR / sizeof(u32));
+       u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
+
+       if (shdev->pdata->dmaor_is_32bit)
+               return __raw_readl(addr);
+       else
+               return __raw_readw(addr);
 }
 
 static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
 {
-       __raw_writew(data, shdev->chan_reg + DMAOR / sizeof(u32));
+       u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
+
+       if (shdev->pdata->dmaor_is_32bit)
+               __raw_writel(data, addr);
+       else
+               __raw_writew(data, addr);
+}
+
+static void chcr_write(struct sh_dmae_chan *sh_dc, u32 data)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+
+       __raw_writel(data, sh_dc->base + shdev->chcr_offset / sizeof(u32));
+}
+
+static u32 chcr_read(struct sh_dmae_chan *sh_dc)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+
+       return __raw_readl(sh_dc->base + shdev->chcr_offset / sizeof(u32));
 }
 
 /*
@@ -120,7 +144,7 @@ static int sh_dmae_rst(struct sh_dmae_device *shdev)
 
 static bool dmae_is_busy(struct sh_dmae_chan *sh_chan)
 {
-       u32 chcr = sh_dmae_readl(sh_chan, CHCR);
+       u32 chcr = chcr_read(sh_chan);
 
        if ((chcr & (CHCR_DE | CHCR_TE)) == CHCR_DE)
                return true; /* working */
@@ -130,8 +154,7 @@ static bool dmae_is_busy(struct sh_dmae_chan *sh_chan)
 
 static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
 {
-       struct sh_dmae_device *shdev = container_of(sh_chan->common.device,
-                                               struct sh_dmae_device, common);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
        struct sh_dmae_pdata *pdata = shdev->pdata;
        int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) |
                ((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift);
@@ -144,8 +167,7 @@ static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
 
 static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size)
 {
-       struct sh_dmae_device *shdev = container_of(sh_chan->common.device,
-                                               struct sh_dmae_device, common);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
        struct sh_dmae_pdata *pdata = shdev->pdata;
        int i;
 
@@ -169,18 +191,23 @@ static void dmae_set_reg(struct sh_dmae_chan *sh_chan, struct sh_dmae_regs *hw)
 
 static void dmae_start(struct sh_dmae_chan *sh_chan)
 {
-       u32 chcr = sh_dmae_readl(sh_chan, CHCR);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+       u32 chcr = chcr_read(sh_chan);
+
+       if (shdev->pdata->needs_tend_set)
+               sh_dmae_writel(sh_chan, 0xFFFFFFFF, TEND);
 
-       chcr |= CHCR_DE | CHCR_IE;
-       sh_dmae_writel(sh_chan, chcr & ~CHCR_TE, CHCR);
+       chcr |= CHCR_DE | shdev->chcr_ie_bit;
+       chcr_write(sh_chan, chcr & ~CHCR_TE);
 }
 
 static void dmae_halt(struct sh_dmae_chan *sh_chan)
 {
-       u32 chcr = sh_dmae_readl(sh_chan, CHCR);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+       u32 chcr = chcr_read(sh_chan);
 
-       chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
-       sh_dmae_writel(sh_chan, chcr, CHCR);
+       chcr &= ~(CHCR_DE | CHCR_TE | shdev->chcr_ie_bit);
+       chcr_write(sh_chan, chcr);
 }
 
 static void dmae_init(struct sh_dmae_chan *sh_chan)
@@ -192,7 +219,7 @@ static void dmae_init(struct sh_dmae_chan *sh_chan)
        u32 chcr = DM_INC | SM_INC | 0x400 | log2size_to_chcr(sh_chan,
                                                   LOG2_DEFAULT_XFER_SIZE);
        sh_chan->xmit_shift = calc_xmit_shift(sh_chan, chcr);
-       sh_dmae_writel(sh_chan, chcr, CHCR);
+       chcr_write(sh_chan, chcr);
 }
 
 static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
@@ -202,23 +229,25 @@ static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
                return -EBUSY;
 
        sh_chan->xmit_shift = calc_xmit_shift(sh_chan, val);
-       sh_dmae_writel(sh_chan, val, CHCR);
+       chcr_write(sh_chan, val);
 
        return 0;
 }
 
 static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
 {
-       struct sh_dmae_device *shdev = container_of(sh_chan->common.device,
-                                               struct sh_dmae_device, common);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
        struct sh_dmae_pdata *pdata = shdev->pdata;
        const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->id];
        u16 __iomem *addr = shdev->dmars;
-       int shift = chan_pdata->dmars_bit;
+       unsigned int shift = chan_pdata->dmars_bit;
 
        if (dmae_is_busy(sh_chan))
                return -EBUSY;
 
+       if (pdata->no_dmars)
+               return 0;
+
        /* in the case of a missing DMARS resource use first memory window */
        if (!addr)
                addr = (u16 __iomem *)shdev->chan_reg;
@@ -296,9 +325,7 @@ static struct sh_desc *sh_dmae_get_desc(struct sh_dmae_chan *sh_chan)
 static const struct sh_dmae_slave_config *sh_dmae_find_slave(
        struct sh_dmae_chan *sh_chan, struct sh_dmae_slave *param)
 {
-       struct dma_device *dma_dev = sh_chan->common.device;
-       struct sh_dmae_device *shdev = container_of(dma_dev,
-                                       struct sh_dmae_device, common);
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
        struct sh_dmae_pdata *pdata = shdev->pdata;
        int i;
 
@@ -771,10 +798,8 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
 
        spin_lock_bh(&sh_chan->desc_lock);
        /* DMA work check */
-       if (dmae_is_busy(sh_chan)) {
-               spin_unlock_bh(&sh_chan->desc_lock);
-               return;
-       }
+       if (dmae_is_busy(sh_chan))
+               goto sh_chan_xfer_ld_queue_end;
 
        /* Find the first not transferred descriptor */
        list_for_each_entry(desc, &sh_chan->ld_queue, node)
@@ -788,6 +813,7 @@ static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
                        break;
                }
 
+sh_chan_xfer_ld_queue_end:
        spin_unlock_bh(&sh_chan->desc_lock);
 }
 
@@ -846,7 +872,7 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data)
 
        spin_lock(&sh_chan->desc_lock);
 
-       chcr = sh_dmae_readl(sh_chan, CHCR);
+       chcr = chcr_read(sh_chan);
 
        if (chcr & CHCR_TE) {
                /* DMA stop */
@@ -1144,6 +1170,16 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
        /* platform data */
        shdev->pdata = pdata;
 
+       if (pdata->chcr_offset)
+               shdev->chcr_offset = pdata->chcr_offset;
+       else
+               shdev->chcr_offset = CHCR;
+
+       if (pdata->chcr_ie_bit)
+               shdev->chcr_ie_bit = pdata->chcr_ie_bit;
+       else
+               shdev->chcr_ie_bit = CHCR_IE;
+
        platform_set_drvdata(pdev, shdev);
 
        pm_runtime_enable(&pdev->dev);
index 5ae9fc512180c979deac5bbad5687b266778032a..dc56576f9fdb6bfd9ea05c17e0deaa2416a3b91d 100644 (file)
@@ -47,10 +47,14 @@ struct sh_dmae_device {
        struct list_head node;
        u32 __iomem *chan_reg;
        u16 __iomem *dmars;
+       unsigned int chcr_offset;
+       u32 chcr_ie_bit;
 };
 
 #define to_sh_chan(chan) container_of(chan, struct sh_dmae_chan, common)
 #define to_sh_desc(lh) container_of(lh, struct sh_desc, node)
 #define tx_to_sh_desc(tx) container_of(tx, struct sh_desc, async_tx)
+#define to_sh_dev(chan) container_of(chan->common.device,\
+                                    struct sh_dmae_device, common)
 
 #endif /* __DMA_SHDMA_H */
index 363498697c2c15d2f7fa4fec367ff75a1bfa090a..d539efd96d4b8d5b7c032c5c0767543da7413cd7 100644 (file)
@@ -103,6 +103,22 @@ config GPIO_MPC5200
        def_bool y
        depends on PPC_MPC52xx
 
+config GPIO_MSM_V1
+       tristate "Qualcomm MSM GPIO v1"
+       depends on GPIOLIB && ARCH_MSM
+       help
+         Say yes here to support the GPIO interface on ARM v6 based
+         Qualcomm MSM chips.  Most of the pins on the MSM can be
+         selected for GPIO, and are controlled by this driver.
+
+config GPIO_MSM_V2
+       tristate "Qualcomm MSM GPIO v2"
+       depends on GPIOLIB && ARCH_MSM
+       help
+         Say yes here to support the GPIO interface on ARM v7 based
+         Qualcomm MSM chips.  Most of the pins on the MSM can be
+         selected for GPIO, and are controlled by this driver.
+
 config GPIO_MXC
        def_bool y
        depends on ARCH_MXC
@@ -280,6 +296,12 @@ config GPIO_TC3589X
          This enables support for the GPIOs found on the TC3589X
          I/O Expander.
 
+config GPIO_TPS65912
+       tristate "TI TPS65912 GPIO"
+       depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI)
+       help
+         This driver supports TPS65912 gpio chip
+
 config GPIO_TWL4030
        tristate "TWL4030, TWL5030, and TPS659x0 GPIOs"
        depends on TWL4030_CORE
index 7207112513913a457b8b9b8e45c5ede7ae0453b9..9588948c96f08b2e8487b6333d7151fd1e914267 100644 (file)
@@ -27,6 +27,8 @@ obj-$(CONFIG_GPIO_MC33880)    += gpio-mc33880.o
 obj-$(CONFIG_GPIO_MCP23S08)    += gpio-mcp23s08.o
 obj-$(CONFIG_GPIO_ML_IOH)      += gpio-ml-ioh.o
 obj-$(CONFIG_GPIO_MPC5200)     += gpio-mpc5200.o
+obj-$(CONFIG_GPIO_MSM_V1)      += gpio-msm-v1.o
+obj-$(CONFIG_GPIO_MSM_V2)      += gpio-msm-v2.o
 obj-$(CONFIG_GPIO_MXC)         += gpio-mxc.o
 obj-$(CONFIG_GPIO_MXS)         += gpio-mxs.o
 obj-$(CONFIG_PLAT_NOMADIK)     += gpio-nomadik.o
@@ -48,6 +50,7 @@ obj-$(CONFIG_GPIO_TC3589X)    += gpio-tc3589x.o
 obj-$(CONFIG_ARCH_TEGRA)       += gpio-tegra.o
 obj-$(CONFIG_GPIO_TIMBERDALE)  += gpio-timberdale.o
 obj-$(CONFIG_GPIO_TPS65910)    += gpio-tps65910.o
+obj-$(CONFIG_GPIO_TPS65912)    += gpio-tps65912.o
 obj-$(CONFIG_GPIO_TWL4030)     += gpio-twl4030.o
 obj-$(CONFIG_MACH_U300)                += gpio-u300.o
 obj-$(CONFIG_GPIO_UCB1400)     += gpio-ucb1400.o
index ed795e64eea7d68eaca749832225e3c3ef01108b..050c05d91896b638df5072aec10c0f1e69f9bda7 100644 (file)
@@ -516,5 +516,5 @@ module_exit(ab8500_gpio_exit);
 
 MODULE_AUTHOR("BIBEK BASU <bibek.basu@stericsson.com>");
 MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins to be used as GPIO");
-MODULE_ALIAS("AB8500 GPIO driver");
+MODULE_ALIAS("platform:ab8500-gpio");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
new file mode 100644 (file)
index 0000000..52a4d42
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <mach/cpu.h>
+#include <mach/msm_gpiomux.h>
+#include <mach/msm_iomap.h>
+
+/* see 80-VA736-2 Rev C pp 695-751
+**
+** These are actually the *shadow* gpio registers, since the
+** real ones (which allow full access) are only available to the
+** ARM9 side of the world.
+**
+** Since the _BASE need to be page-aligned when we're mapping them
+** to virtual addresses, adjust for the additional offset in these
+** macros.
+*/
+
+#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + (off))
+#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off))
+#define MSM_GPIO1_SHADOW_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
+#define MSM_GPIO2_SHADOW_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+
+/*
+ * MSM7X00 registers
+ */
+/* output value */
+#define MSM7X00_GPIO_OUT_0     MSM_GPIO1_SHADOW_REG(0x00)  /* gpio  15-0  */
+#define MSM7X00_GPIO_OUT_1     MSM_GPIO2_SHADOW_REG(0x00)  /* gpio  42-16 */
+#define MSM7X00_GPIO_OUT_2     MSM_GPIO1_SHADOW_REG(0x04)  /* gpio  67-43 */
+#define MSM7X00_GPIO_OUT_3     MSM_GPIO1_SHADOW_REG(0x08)  /* gpio  94-68 */
+#define MSM7X00_GPIO_OUT_4     MSM_GPIO1_SHADOW_REG(0x0C)  /* gpio 106-95 */
+#define MSM7X00_GPIO_OUT_5     MSM_GPIO1_SHADOW_REG(0x50)  /* gpio 107-121 */
+
+/* same pin map as above, output enable */
+#define MSM7X00_GPIO_OE_0      MSM_GPIO1_SHADOW_REG(0x10)
+#define MSM7X00_GPIO_OE_1      MSM_GPIO2_SHADOW_REG(0x08)
+#define MSM7X00_GPIO_OE_2      MSM_GPIO1_SHADOW_REG(0x14)
+#define MSM7X00_GPIO_OE_3      MSM_GPIO1_SHADOW_REG(0x18)
+#define MSM7X00_GPIO_OE_4      MSM_GPIO1_SHADOW_REG(0x1C)
+#define MSM7X00_GPIO_OE_5      MSM_GPIO1_SHADOW_REG(0x54)
+
+/* same pin map as above, input read */
+#define MSM7X00_GPIO_IN_0      MSM_GPIO1_SHADOW_REG(0x34)
+#define MSM7X00_GPIO_IN_1      MSM_GPIO2_SHADOW_REG(0x20)
+#define MSM7X00_GPIO_IN_2      MSM_GPIO1_SHADOW_REG(0x38)
+#define MSM7X00_GPIO_IN_3      MSM_GPIO1_SHADOW_REG(0x3C)
+#define MSM7X00_GPIO_IN_4      MSM_GPIO1_SHADOW_REG(0x40)
+#define MSM7X00_GPIO_IN_5      MSM_GPIO1_SHADOW_REG(0x44)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define MSM7X00_GPIO_INT_EDGE_0        MSM_GPIO1_SHADOW_REG(0x60)
+#define MSM7X00_GPIO_INT_EDGE_1        MSM_GPIO2_SHADOW_REG(0x50)
+#define MSM7X00_GPIO_INT_EDGE_2        MSM_GPIO1_SHADOW_REG(0x64)
+#define MSM7X00_GPIO_INT_EDGE_3        MSM_GPIO1_SHADOW_REG(0x68)
+#define MSM7X00_GPIO_INT_EDGE_4        MSM_GPIO1_SHADOW_REG(0x6C)
+#define MSM7X00_GPIO_INT_EDGE_5        MSM_GPIO1_SHADOW_REG(0xC0)
+
+/* same pin map as above, 1=positive 0=negative */
+#define MSM7X00_GPIO_INT_POS_0 MSM_GPIO1_SHADOW_REG(0x70)
+#define MSM7X00_GPIO_INT_POS_1 MSM_GPIO2_SHADOW_REG(0x58)
+#define MSM7X00_GPIO_INT_POS_2 MSM_GPIO1_SHADOW_REG(0x74)
+#define MSM7X00_GPIO_INT_POS_3 MSM_GPIO1_SHADOW_REG(0x78)
+#define MSM7X00_GPIO_INT_POS_4 MSM_GPIO1_SHADOW_REG(0x7C)
+#define MSM7X00_GPIO_INT_POS_5 MSM_GPIO1_SHADOW_REG(0xBC)
+
+/* same pin map as above, interrupt enable */
+#define MSM7X00_GPIO_INT_EN_0  MSM_GPIO1_SHADOW_REG(0x80)
+#define MSM7X00_GPIO_INT_EN_1  MSM_GPIO2_SHADOW_REG(0x60)
+#define MSM7X00_GPIO_INT_EN_2  MSM_GPIO1_SHADOW_REG(0x84)
+#define MSM7X00_GPIO_INT_EN_3  MSM_GPIO1_SHADOW_REG(0x88)
+#define MSM7X00_GPIO_INT_EN_4  MSM_GPIO1_SHADOW_REG(0x8C)
+#define MSM7X00_GPIO_INT_EN_5  MSM_GPIO1_SHADOW_REG(0xB8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define MSM7X00_GPIO_INT_CLEAR_0       MSM_GPIO1_SHADOW_REG(0x90)
+#define MSM7X00_GPIO_INT_CLEAR_1       MSM_GPIO2_SHADOW_REG(0x68)
+#define MSM7X00_GPIO_INT_CLEAR_2       MSM_GPIO1_SHADOW_REG(0x94)
+#define MSM7X00_GPIO_INT_CLEAR_3       MSM_GPIO1_SHADOW_REG(0x98)
+#define MSM7X00_GPIO_INT_CLEAR_4       MSM_GPIO1_SHADOW_REG(0x9C)
+#define MSM7X00_GPIO_INT_CLEAR_5       MSM_GPIO1_SHADOW_REG(0xB4)
+
+/* same pin map as above, 1=interrupt pending */
+#define MSM7X00_GPIO_INT_STATUS_0      MSM_GPIO1_SHADOW_REG(0xA0)
+#define MSM7X00_GPIO_INT_STATUS_1      MSM_GPIO2_SHADOW_REG(0x70)
+#define MSM7X00_GPIO_INT_STATUS_2      MSM_GPIO1_SHADOW_REG(0xA4)
+#define MSM7X00_GPIO_INT_STATUS_3      MSM_GPIO1_SHADOW_REG(0xA8)
+#define MSM7X00_GPIO_INT_STATUS_4      MSM_GPIO1_SHADOW_REG(0xAC)
+#define MSM7X00_GPIO_INT_STATUS_5      MSM_GPIO1_SHADOW_REG(0xB0)
+
+/*
+ * QSD8X50 registers
+ */
+/* output value */
+#define QSD8X50_GPIO_OUT_0     MSM_GPIO1_SHADOW_REG(0x00)  /* gpio  15-0   */
+#define QSD8X50_GPIO_OUT_1     MSM_GPIO2_SHADOW_REG(0x00)  /* gpio  42-16  */
+#define QSD8X50_GPIO_OUT_2     MSM_GPIO1_SHADOW_REG(0x04)  /* gpio  67-43  */
+#define QSD8X50_GPIO_OUT_3     MSM_GPIO1_SHADOW_REG(0x08)  /* gpio  94-68  */
+#define QSD8X50_GPIO_OUT_4     MSM_GPIO1_SHADOW_REG(0x0C)  /* gpio 103-95  */
+#define QSD8X50_GPIO_OUT_5     MSM_GPIO1_SHADOW_REG(0x10)  /* gpio 121-104 */
+#define QSD8X50_GPIO_OUT_6     MSM_GPIO1_SHADOW_REG(0x14)  /* gpio 152-122 */
+#define QSD8X50_GPIO_OUT_7     MSM_GPIO1_SHADOW_REG(0x18)  /* gpio 164-153 */
+
+/* same pin map as above, output enable */
+#define QSD8X50_GPIO_OE_0      MSM_GPIO1_SHADOW_REG(0x20)
+#define QSD8X50_GPIO_OE_1      MSM_GPIO2_SHADOW_REG(0x08)
+#define QSD8X50_GPIO_OE_2      MSM_GPIO1_SHADOW_REG(0x24)
+#define QSD8X50_GPIO_OE_3      MSM_GPIO1_SHADOW_REG(0x28)
+#define QSD8X50_GPIO_OE_4      MSM_GPIO1_SHADOW_REG(0x2C)
+#define QSD8X50_GPIO_OE_5      MSM_GPIO1_SHADOW_REG(0x30)
+#define QSD8X50_GPIO_OE_6      MSM_GPIO1_SHADOW_REG(0x34)
+#define QSD8X50_GPIO_OE_7      MSM_GPIO1_SHADOW_REG(0x38)
+
+/* same pin map as above, input read */
+#define QSD8X50_GPIO_IN_0      MSM_GPIO1_SHADOW_REG(0x50)
+#define QSD8X50_GPIO_IN_1      MSM_GPIO2_SHADOW_REG(0x20)
+#define QSD8X50_GPIO_IN_2      MSM_GPIO1_SHADOW_REG(0x54)
+#define QSD8X50_GPIO_IN_3      MSM_GPIO1_SHADOW_REG(0x58)
+#define QSD8X50_GPIO_IN_4      MSM_GPIO1_SHADOW_REG(0x5C)
+#define QSD8X50_GPIO_IN_5      MSM_GPIO1_SHADOW_REG(0x60)
+#define QSD8X50_GPIO_IN_6      MSM_GPIO1_SHADOW_REG(0x64)
+#define QSD8X50_GPIO_IN_7      MSM_GPIO1_SHADOW_REG(0x68)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define QSD8X50_GPIO_INT_EDGE_0        MSM_GPIO1_SHADOW_REG(0x70)
+#define QSD8X50_GPIO_INT_EDGE_1        MSM_GPIO2_SHADOW_REG(0x50)
+#define QSD8X50_GPIO_INT_EDGE_2        MSM_GPIO1_SHADOW_REG(0x74)
+#define QSD8X50_GPIO_INT_EDGE_3        MSM_GPIO1_SHADOW_REG(0x78)
+#define QSD8X50_GPIO_INT_EDGE_4        MSM_GPIO1_SHADOW_REG(0x7C)
+#define QSD8X50_GPIO_INT_EDGE_5        MSM_GPIO1_SHADOW_REG(0x80)
+#define QSD8X50_GPIO_INT_EDGE_6        MSM_GPIO1_SHADOW_REG(0x84)
+#define QSD8X50_GPIO_INT_EDGE_7        MSM_GPIO1_SHADOW_REG(0x88)
+
+/* same pin map as above, 1=positive 0=negative */
+#define QSD8X50_GPIO_INT_POS_0 MSM_GPIO1_SHADOW_REG(0x90)
+#define QSD8X50_GPIO_INT_POS_1 MSM_GPIO2_SHADOW_REG(0x58)
+#define QSD8X50_GPIO_INT_POS_2 MSM_GPIO1_SHADOW_REG(0x94)
+#define QSD8X50_GPIO_INT_POS_3 MSM_GPIO1_SHADOW_REG(0x98)
+#define QSD8X50_GPIO_INT_POS_4 MSM_GPIO1_SHADOW_REG(0x9C)
+#define QSD8X50_GPIO_INT_POS_5 MSM_GPIO1_SHADOW_REG(0xA0)
+#define QSD8X50_GPIO_INT_POS_6 MSM_GPIO1_SHADOW_REG(0xA4)
+#define QSD8X50_GPIO_INT_POS_7 MSM_GPIO1_SHADOW_REG(0xA8)
+
+/* same pin map as above, interrupt enable */
+#define QSD8X50_GPIO_INT_EN_0  MSM_GPIO1_SHADOW_REG(0xB0)
+#define QSD8X50_GPIO_INT_EN_1  MSM_GPIO2_SHADOW_REG(0x60)
+#define QSD8X50_GPIO_INT_EN_2  MSM_GPIO1_SHADOW_REG(0xB4)
+#define QSD8X50_GPIO_INT_EN_3  MSM_GPIO1_SHADOW_REG(0xB8)
+#define QSD8X50_GPIO_INT_EN_4  MSM_GPIO1_SHADOW_REG(0xBC)
+#define QSD8X50_GPIO_INT_EN_5  MSM_GPIO1_SHADOW_REG(0xC0)
+#define QSD8X50_GPIO_INT_EN_6  MSM_GPIO1_SHADOW_REG(0xC4)
+#define QSD8X50_GPIO_INT_EN_7  MSM_GPIO1_SHADOW_REG(0xC8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define QSD8X50_GPIO_INT_CLEAR_0       MSM_GPIO1_SHADOW_REG(0xD0)
+#define QSD8X50_GPIO_INT_CLEAR_1       MSM_GPIO2_SHADOW_REG(0x68)
+#define QSD8X50_GPIO_INT_CLEAR_2       MSM_GPIO1_SHADOW_REG(0xD4)
+#define QSD8X50_GPIO_INT_CLEAR_3       MSM_GPIO1_SHADOW_REG(0xD8)
+#define QSD8X50_GPIO_INT_CLEAR_4       MSM_GPIO1_SHADOW_REG(0xDC)
+#define QSD8X50_GPIO_INT_CLEAR_5       MSM_GPIO1_SHADOW_REG(0xE0)
+#define QSD8X50_GPIO_INT_CLEAR_6       MSM_GPIO1_SHADOW_REG(0xE4)
+#define QSD8X50_GPIO_INT_CLEAR_7       MSM_GPIO1_SHADOW_REG(0xE8)
+
+/* same pin map as above, 1=interrupt pending */
+#define QSD8X50_GPIO_INT_STATUS_0      MSM_GPIO1_SHADOW_REG(0xF0)
+#define QSD8X50_GPIO_INT_STATUS_1      MSM_GPIO2_SHADOW_REG(0x70)
+#define QSD8X50_GPIO_INT_STATUS_2      MSM_GPIO1_SHADOW_REG(0xF4)
+#define QSD8X50_GPIO_INT_STATUS_3      MSM_GPIO1_SHADOW_REG(0xF8)
+#define QSD8X50_GPIO_INT_STATUS_4      MSM_GPIO1_SHADOW_REG(0xFC)
+#define QSD8X50_GPIO_INT_STATUS_5      MSM_GPIO1_SHADOW_REG(0x100)
+#define QSD8X50_GPIO_INT_STATUS_6      MSM_GPIO1_SHADOW_REG(0x104)
+#define QSD8X50_GPIO_INT_STATUS_7      MSM_GPIO1_SHADOW_REG(0x108)
+
+/*
+ * MSM7X30 registers
+ */
+/* output value */
+#define MSM7X30_GPIO_OUT_0     MSM_GPIO1_REG(0x00)   /* gpio  15-0   */
+#define MSM7X30_GPIO_OUT_1     MSM_GPIO2_REG(0x00)   /* gpio  43-16  */
+#define MSM7X30_GPIO_OUT_2     MSM_GPIO1_REG(0x04)   /* gpio  67-44  */
+#define MSM7X30_GPIO_OUT_3     MSM_GPIO1_REG(0x08)   /* gpio  94-68  */
+#define MSM7X30_GPIO_OUT_4     MSM_GPIO1_REG(0x0C)   /* gpio 106-95  */
+#define MSM7X30_GPIO_OUT_5     MSM_GPIO1_REG(0x50)   /* gpio 133-107 */
+#define MSM7X30_GPIO_OUT_6     MSM_GPIO1_REG(0xC4)   /* gpio 150-134 */
+#define MSM7X30_GPIO_OUT_7     MSM_GPIO1_REG(0x214)  /* gpio 181-151 */
+
+/* same pin map as above, output enable */
+#define MSM7X30_GPIO_OE_0      MSM_GPIO1_REG(0x10)
+#define MSM7X30_GPIO_OE_1      MSM_GPIO2_REG(0x08)
+#define MSM7X30_GPIO_OE_2      MSM_GPIO1_REG(0x14)
+#define MSM7X30_GPIO_OE_3      MSM_GPIO1_REG(0x18)
+#define MSM7X30_GPIO_OE_4      MSM_GPIO1_REG(0x1C)
+#define MSM7X30_GPIO_OE_5      MSM_GPIO1_REG(0x54)
+#define MSM7X30_GPIO_OE_6      MSM_GPIO1_REG(0xC8)
+#define MSM7X30_GPIO_OE_7      MSM_GPIO1_REG(0x218)
+
+/* same pin map as above, input read */
+#define MSM7X30_GPIO_IN_0      MSM_GPIO1_REG(0x34)
+#define MSM7X30_GPIO_IN_1      MSM_GPIO2_REG(0x20)
+#define MSM7X30_GPIO_IN_2      MSM_GPIO1_REG(0x38)
+#define MSM7X30_GPIO_IN_3      MSM_GPIO1_REG(0x3C)
+#define MSM7X30_GPIO_IN_4      MSM_GPIO1_REG(0x40)
+#define MSM7X30_GPIO_IN_5      MSM_GPIO1_REG(0x44)
+#define MSM7X30_GPIO_IN_6      MSM_GPIO1_REG(0xCC)
+#define MSM7X30_GPIO_IN_7      MSM_GPIO1_REG(0x21C)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define MSM7X30_GPIO_INT_EDGE_0        MSM_GPIO1_REG(0x60)
+#define MSM7X30_GPIO_INT_EDGE_1        MSM_GPIO2_REG(0x50)
+#define MSM7X30_GPIO_INT_EDGE_2        MSM_GPIO1_REG(0x64)
+#define MSM7X30_GPIO_INT_EDGE_3        MSM_GPIO1_REG(0x68)
+#define MSM7X30_GPIO_INT_EDGE_4        MSM_GPIO1_REG(0x6C)
+#define MSM7X30_GPIO_INT_EDGE_5        MSM_GPIO1_REG(0xC0)
+#define MSM7X30_GPIO_INT_EDGE_6        MSM_GPIO1_REG(0xD0)
+#define MSM7X30_GPIO_INT_EDGE_7        MSM_GPIO1_REG(0x240)
+
+/* same pin map as above, 1=positive 0=negative */
+#define MSM7X30_GPIO_INT_POS_0 MSM_GPIO1_REG(0x70)
+#define MSM7X30_GPIO_INT_POS_1 MSM_GPIO2_REG(0x58)
+#define MSM7X30_GPIO_INT_POS_2 MSM_GPIO1_REG(0x74)
+#define MSM7X30_GPIO_INT_POS_3 MSM_GPIO1_REG(0x78)
+#define MSM7X30_GPIO_INT_POS_4 MSM_GPIO1_REG(0x7C)
+#define MSM7X30_GPIO_INT_POS_5 MSM_GPIO1_REG(0xBC)
+#define MSM7X30_GPIO_INT_POS_6 MSM_GPIO1_REG(0xD4)
+#define MSM7X30_GPIO_INT_POS_7 MSM_GPIO1_REG(0x228)
+
+/* same pin map as above, interrupt enable */
+#define MSM7X30_GPIO_INT_EN_0  MSM_GPIO1_REG(0x80)
+#define MSM7X30_GPIO_INT_EN_1  MSM_GPIO2_REG(0x60)
+#define MSM7X30_GPIO_INT_EN_2  MSM_GPIO1_REG(0x84)
+#define MSM7X30_GPIO_INT_EN_3  MSM_GPIO1_REG(0x88)
+#define MSM7X30_GPIO_INT_EN_4  MSM_GPIO1_REG(0x8C)
+#define MSM7X30_GPIO_INT_EN_5  MSM_GPIO1_REG(0xB8)
+#define MSM7X30_GPIO_INT_EN_6  MSM_GPIO1_REG(0xD8)
+#define MSM7X30_GPIO_INT_EN_7  MSM_GPIO1_REG(0x22C)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define MSM7X30_GPIO_INT_CLEAR_0       MSM_GPIO1_REG(0x90)
+#define MSM7X30_GPIO_INT_CLEAR_1       MSM_GPIO2_REG(0x68)
+#define MSM7X30_GPIO_INT_CLEAR_2       MSM_GPIO1_REG(0x94)
+#define MSM7X30_GPIO_INT_CLEAR_3       MSM_GPIO1_REG(0x98)
+#define MSM7X30_GPIO_INT_CLEAR_4       MSM_GPIO1_REG(0x9C)
+#define MSM7X30_GPIO_INT_CLEAR_5       MSM_GPIO1_REG(0xB4)
+#define MSM7X30_GPIO_INT_CLEAR_6       MSM_GPIO1_REG(0xDC)
+#define MSM7X30_GPIO_INT_CLEAR_7       MSM_GPIO1_REG(0x230)
+
+/* same pin map as above, 1=interrupt pending */
+#define MSM7X30_GPIO_INT_STATUS_0      MSM_GPIO1_REG(0xA0)
+#define MSM7X30_GPIO_INT_STATUS_1      MSM_GPIO2_REG(0x70)
+#define MSM7X30_GPIO_INT_STATUS_2      MSM_GPIO1_REG(0xA4)
+#define MSM7X30_GPIO_INT_STATUS_3      MSM_GPIO1_REG(0xA8)
+#define MSM7X30_GPIO_INT_STATUS_4      MSM_GPIO1_REG(0xAC)
+#define MSM7X30_GPIO_INT_STATUS_5      MSM_GPIO1_REG(0xB0)
+#define MSM7X30_GPIO_INT_STATUS_6      MSM_GPIO1_REG(0xE0)
+#define MSM7X30_GPIO_INT_STATUS_7      MSM_GPIO1_REG(0x234)
+
+#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
+
+#define MSM_GPIO_BANK(soc, bank, first, last)                          \
+       {                                                               \
+               .regs = {                                               \
+                       .out =         soc##_GPIO_OUT_##bank,           \
+                       .in =          soc##_GPIO_IN_##bank,            \
+                       .int_status =  soc##_GPIO_INT_STATUS_##bank,    \
+                       .int_clear =   soc##_GPIO_INT_CLEAR_##bank,     \
+                       .int_en =      soc##_GPIO_INT_EN_##bank,        \
+                       .int_edge =    soc##_GPIO_INT_EDGE_##bank,      \
+                       .int_pos =     soc##_GPIO_INT_POS_##bank,       \
+                       .oe =          soc##_GPIO_OE_##bank,            \
+               },                                                      \
+               .chip = {                                               \
+                       .base = (first),                                \
+                       .ngpio = (last) - (first) + 1,                  \
+                       .get = msm_gpio_get,                            \
+                       .set = msm_gpio_set,                            \
+                       .direction_input = msm_gpio_direction_input,    \
+                       .direction_output = msm_gpio_direction_output,  \
+                       .to_irq = msm_gpio_to_irq,                      \
+                       .request = msm_gpio_request,                    \
+                       .free = msm_gpio_free,                          \
+               }                                                       \
+       }
+
+#define MSM_GPIO_BROKEN_INT_CLEAR 1
+
+struct msm_gpio_regs {
+       void __iomem *out;
+       void __iomem *in;
+       void __iomem *int_status;
+       void __iomem *int_clear;
+       void __iomem *int_en;
+       void __iomem *int_edge;
+       void __iomem *int_pos;
+       void __iomem *oe;
+};
+
+struct msm_gpio_chip {
+       spinlock_t              lock;
+       struct gpio_chip        chip;
+       struct msm_gpio_regs    regs;
+#if MSM_GPIO_BROKEN_INT_CLEAR
+       unsigned                int_status_copy;
+#endif
+       unsigned int            both_edge_detect;
+       unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
+};
+
+static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
+                         unsigned offset, unsigned on)
+{
+       unsigned mask = BIT(offset);
+       unsigned val;
+
+       val = readl(msm_chip->regs.out);
+       if (on)
+               writel(val | mask, msm_chip->regs.out);
+       else
+               writel(val & ~mask, msm_chip->regs.out);
+       return 0;
+}
+
+static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
+{
+       int loop_limit = 100;
+       unsigned pol, val, val2, intstat;
+       do {
+               val = readl(msm_chip->regs.in);
+               pol = readl(msm_chip->regs.int_pos);
+               pol = (pol & ~msm_chip->both_edge_detect) |
+                     (~val & msm_chip->both_edge_detect);
+               writel(pol, msm_chip->regs.int_pos);
+               intstat = readl(msm_chip->regs.int_status);
+               val2 = readl(msm_chip->regs.in);
+               if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
+                       return;
+       } while (loop_limit-- > 0);
+       printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
+              "failed to reach stable state %x != %x\n", val, val2);
+}
+
+static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
+                                       unsigned offset)
+{
+       unsigned bit = BIT(offset);
+
+#if MSM_GPIO_BROKEN_INT_CLEAR
+       /* Save interrupts that already triggered before we loose them. */
+       /* Any interrupt that triggers between the read of int_status */
+       /* and the write to int_clear will still be lost though. */
+       msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+       msm_chip->int_status_copy &= ~bit;
+#endif
+       writel(bit, msm_chip->regs.int_clear);
+       msm_gpio_update_both_edge_detect(msm_chip);
+       return 0;
+}
+
+static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct msm_gpio_chip *msm_chip;
+       unsigned long irq_flags;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       writel(readl(msm_chip->regs.oe) & ~BIT(offset), msm_chip->regs.oe);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static int
+msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct msm_gpio_chip *msm_chip;
+       unsigned long irq_flags;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       msm_gpio_write(msm_chip, offset, value);
+       writel(readl(msm_chip->regs.oe) | BIT(offset), msm_chip->regs.oe);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct msm_gpio_chip *msm_chip;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       return (readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
+}
+
+static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct msm_gpio_chip *msm_chip;
+       unsigned long irq_flags;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       msm_gpio_write(msm_chip, offset, value);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       return MSM_GPIO_TO_INT(chip->base + offset);
+}
+
+#ifdef CONFIG_MSM_GPIOMUX
+static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       return msm_gpiomux_get(chip->base + offset);
+}
+
+static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       msm_gpiomux_put(chip->base + offset);
+}
+#else
+#define msm_gpio_request NULL
+#define msm_gpio_free NULL
+#endif
+
+static struct msm_gpio_chip *msm_gpio_chips;
+static int msm_gpio_count;
+
+static struct msm_gpio_chip msm_gpio_chips_msm7x01[] = {
+       MSM_GPIO_BANK(MSM7X00, 0,   0,  15),
+       MSM_GPIO_BANK(MSM7X00, 1,  16,  42),
+       MSM_GPIO_BANK(MSM7X00, 2,  43,  67),
+       MSM_GPIO_BANK(MSM7X00, 3,  68,  94),
+       MSM_GPIO_BANK(MSM7X00, 4,  95, 106),
+       MSM_GPIO_BANK(MSM7X00, 5, 107, 121),
+};
+
+static struct msm_gpio_chip msm_gpio_chips_msm7x30[] = {
+       MSM_GPIO_BANK(MSM7X30, 0,   0,  15),
+       MSM_GPIO_BANK(MSM7X30, 1,  16,  43),
+       MSM_GPIO_BANK(MSM7X30, 2,  44,  67),
+       MSM_GPIO_BANK(MSM7X30, 3,  68,  94),
+       MSM_GPIO_BANK(MSM7X30, 4,  95, 106),
+       MSM_GPIO_BANK(MSM7X30, 5, 107, 133),
+       MSM_GPIO_BANK(MSM7X30, 6, 134, 150),
+       MSM_GPIO_BANK(MSM7X30, 7, 151, 181),
+};
+
+static struct msm_gpio_chip msm_gpio_chips_qsd8x50[] = {
+       MSM_GPIO_BANK(QSD8X50, 0,   0,  15),
+       MSM_GPIO_BANK(QSD8X50, 1,  16,  42),
+       MSM_GPIO_BANK(QSD8X50, 2,  43,  67),
+       MSM_GPIO_BANK(QSD8X50, 3,  68,  94),
+       MSM_GPIO_BANK(QSD8X50, 4,  95, 103),
+       MSM_GPIO_BANK(QSD8X50, 5, 104, 121),
+       MSM_GPIO_BANK(QSD8X50, 6, 122, 152),
+       MSM_GPIO_BANK(QSD8X50, 7, 153, 164),
+};
+
+static void msm_gpio_irq_ack(struct irq_data *d)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       msm_gpio_clear_detect_status(msm_chip,
+                                    d->irq - gpio_to_irq(msm_chip->chip.base));
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_mask(struct irq_data *d)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       /* level triggered interrupts are also latched */
+       if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+               msm_gpio_clear_detect_status(msm_chip, offset);
+       msm_chip->int_enable[0] &= ~BIT(offset);
+       writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_unmask(struct irq_data *d)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       /* level triggered interrupts are also latched */
+       if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+               msm_gpio_clear_detect_status(msm_chip, offset);
+       msm_chip->int_enable[0] |= BIT(offset);
+       writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+       if (on)
+               msm_chip->int_enable[1] |= BIT(offset);
+       else
+               msm_chip->int_enable[1] &= ~BIT(offset);
+
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+       unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
+       unsigned val, mask = BIT(offset);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       val = readl(msm_chip->regs.int_edge);
+       if (flow_type & IRQ_TYPE_EDGE_BOTH) {
+               writel(val | mask, msm_chip->regs.int_edge);
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
+       } else {
+               writel(val & ~mask, msm_chip->regs.int_edge);
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+       }
+       if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
+               msm_chip->both_edge_detect |= mask;
+               msm_gpio_update_both_edge_detect(msm_chip);
+       } else {
+               msm_chip->both_edge_detect &= ~mask;
+               val = readl(msm_chip->regs.int_pos);
+               if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
+                       writel(val | mask, msm_chip->regs.int_pos);
+               else
+                       writel(val & ~mask, msm_chip->regs.int_pos);
+       }
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       int i, j, mask;
+       unsigned val;
+
+       for (i = 0; i < msm_gpio_count; i++) {
+               struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
+               val = readl(msm_chip->regs.int_status);
+               val &= msm_chip->int_enable[0];
+               while (val) {
+                       mask = val & -val;
+                       j = fls(mask) - 1;
+                       /* printk("%s %08x %08x bit %d gpio %d irq %d\n",
+                               __func__, v, m, j, msm_chip->chip.start + j,
+                               FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
+                       val &= ~mask;
+                       generic_handle_irq(FIRST_GPIO_IRQ +
+                                          msm_chip->chip.base + j);
+               }
+       }
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
+}
+
+static struct irq_chip msm_gpio_irq_chip = {
+       .name          = "msmgpio",
+       .irq_ack       = msm_gpio_irq_ack,
+       .irq_mask      = msm_gpio_irq_mask,
+       .irq_unmask    = msm_gpio_irq_unmask,
+       .irq_set_wake  = msm_gpio_irq_set_wake,
+       .irq_set_type  = msm_gpio_irq_set_type,
+};
+
+static int __init msm_init_gpio(void)
+{
+       int i, j = 0;
+
+       if (cpu_is_msm7x01()) {
+               msm_gpio_chips = msm_gpio_chips_msm7x01;
+               msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_msm7x01);
+       } else if (cpu_is_msm7x30()) {
+               msm_gpio_chips = msm_gpio_chips_msm7x30;
+               msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_msm7x30);
+       } else if (cpu_is_qsd8x50()) {
+               msm_gpio_chips = msm_gpio_chips_qsd8x50;
+               msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_qsd8x50);
+       } else {
+               return 0;
+       }
+
+       for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
+               if (i - FIRST_GPIO_IRQ >=
+                       msm_gpio_chips[j].chip.base +
+                       msm_gpio_chips[j].chip.ngpio)
+                       j++;
+               irq_set_chip_data(i, &msm_gpio_chips[j]);
+               irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
+                                        handle_edge_irq);
+               set_irq_flags(i, IRQF_VALID);
+       }
+
+       for (i = 0; i < msm_gpio_count; i++) {
+               spin_lock_init(&msm_gpio_chips[i].lock);
+               writel(0, msm_gpio_chips[i].regs.int_en);
+               gpiochip_add(&msm_gpio_chips[i].chip);
+       }
+
+       irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
+       irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
+       irq_set_irq_wake(INT_GPIO_GROUP1, 1);
+       irq_set_irq_wake(INT_GPIO_GROUP2, 2);
+       return 0;
+}
+
+postcore_initcall(msm_init_gpio);
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
new file mode 100644 (file)
index 0000000..5cb1227
--- /dev/null
@@ -0,0 +1,433 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. 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 version 2 and
+ * only 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/msm_gpiomux.h>
+#include <mach/msm_iomap.h>
+
+/* Bits of interest in the GPIO_IN_OUT register.
+ */
+enum {
+       GPIO_IN  = 0,
+       GPIO_OUT = 1
+};
+
+/* Bits of interest in the GPIO_INTR_STATUS register.
+ */
+enum {
+       INTR_STATUS = 0,
+};
+
+/* Bits of interest in the GPIO_CFG register.
+ */
+enum {
+       GPIO_OE = 9,
+};
+
+/* Bits of interest in the GPIO_INTR_CFG register.
+ * When a GPIO triggers, two separate decisions are made, controlled
+ * by two separate flags.
+ *
+ * - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS
+ * register for that GPIO will be updated to reflect the triggering of that
+ * gpio.  If this bit is 0, this register will not be updated.
+ * - Second, INTR_ENABLE controls whether an interrupt is triggered.
+ *
+ * If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt
+ * can be triggered but the status register will not reflect it.
+ */
+enum {
+       INTR_ENABLE        = 0,
+       INTR_POL_CTL       = 1,
+       INTR_DECT_CTL      = 2,
+       INTR_RAW_STATUS_EN = 3,
+};
+
+/* Codes of interest in GPIO_INTR_CFG_SU.
+ */
+enum {
+       TARGET_PROC_SCORPION = 4,
+       TARGET_PROC_NONE     = 7,
+};
+
+
+#define GPIO_INTR_CFG_SU(gpio)    (MSM_TLMM_BASE + 0x0400 + (0x04 * (gpio)))
+#define GPIO_CONFIG(gpio)         (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
+#define GPIO_IN_OUT(gpio)         (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
+#define GPIO_INTR_CFG(gpio)       (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
+#define GPIO_INTR_STATUS(gpio)    (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
+
+/**
+ * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
+ *
+ * @enabled_irqs: a bitmap used to optimize the summary-irq handler.  By
+ * keeping track of which gpios are unmasked as irq sources, we avoid
+ * having to do readl calls on hundreds of iomapped registers each time
+ * the summary interrupt fires in order to locate the active interrupts.
+ *
+ * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
+ * as wakeup sources.  When the device is suspended, interrupts which are
+ * not wakeup sources are disabled.
+ *
+ * @dual_edge_irqs: a bitmap used to track which irqs are configured
+ * as dual-edge, as this is not supported by the hardware and requires
+ * some special handling in the driver.
+ */
+struct msm_gpio_dev {
+       struct gpio_chip gpio_chip;
+       DECLARE_BITMAP(enabled_irqs, NR_GPIO_IRQS);
+       DECLARE_BITMAP(wake_irqs, NR_GPIO_IRQS);
+       DECLARE_BITMAP(dual_edge_irqs, NR_GPIO_IRQS);
+};
+
+static DEFINE_SPINLOCK(tlmm_lock);
+
+static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
+{
+       return container_of(chip, struct msm_gpio_dev, gpio_chip);
+}
+
+static inline void set_gpio_bits(unsigned n, void __iomem *reg)
+{
+       writel(readl(reg) | n, reg);
+}
+
+static inline void clear_gpio_bits(unsigned n, void __iomem *reg)
+{
+       writel(readl(reg) & ~n, reg);
+}
+
+static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       return readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN);
+}
+
+static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+       writel(val ? BIT(GPIO_OUT) : 0, GPIO_IN_OUT(offset));
+}
+
+static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&tlmm_lock, irq_flags);
+       clear_gpio_bits(BIT(GPIO_OE), GPIO_CONFIG(offset));
+       spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+       return 0;
+}
+
+static int msm_gpio_direction_output(struct gpio_chip *chip,
+                               unsigned offset,
+                               int val)
+{
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&tlmm_lock, irq_flags);
+       msm_gpio_set(chip, offset, val);
+       set_gpio_bits(BIT(GPIO_OE), GPIO_CONFIG(offset));
+       spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+       return 0;
+}
+
+static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       return msm_gpiomux_get(chip->base + offset);
+}
+
+static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       msm_gpiomux_put(chip->base + offset);
+}
+
+static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       return MSM_GPIO_TO_INT(chip->base + offset);
+}
+
+static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
+{
+       return irq - MSM_GPIO_TO_INT(chip->base);
+}
+
+static struct msm_gpio_dev msm_gpio = {
+       .gpio_chip = {
+               .base             = 0,
+               .ngpio            = NR_GPIO_IRQS,
+               .direction_input  = msm_gpio_direction_input,
+               .direction_output = msm_gpio_direction_output,
+               .get              = msm_gpio_get,
+               .set              = msm_gpio_set,
+               .to_irq           = msm_gpio_to_irq,
+               .request          = msm_gpio_request,
+               .free             = msm_gpio_free,
+       },
+};
+
+/* For dual-edge interrupts in software, since the hardware has no
+ * such support:
+ *
+ * At appropriate moments, this function may be called to flip the polarity
+ * settings of both-edge irq lines to try and catch the next edge.
+ *
+ * The attempt is considered successful if:
+ * - the status bit goes high, indicating that an edge was caught, or
+ * - the input value of the gpio doesn't change during the attempt.
+ * If the value changes twice during the process, that would cause the first
+ * test to fail but would force the second, as two opposite
+ * transitions would cause a detection no matter the polarity setting.
+ *
+ * The do-loop tries to sledge-hammer closed the timing hole between
+ * the initial value-read and the polarity-write - if the line value changes
+ * during that window, an interrupt is lost, the new polarity setting is
+ * incorrect, and the first success test will fail, causing a retry.
+ *
+ * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
+ */
+static void msm_gpio_update_dual_edge_pos(unsigned gpio)
+{
+       int loop_limit = 100;
+       unsigned val, val2, intstat;
+
+       do {
+               val = readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN);
+               if (val)
+                       clear_gpio_bits(BIT(INTR_POL_CTL), GPIO_INTR_CFG(gpio));
+               else
+                       set_gpio_bits(BIT(INTR_POL_CTL), GPIO_INTR_CFG(gpio));
+               val2 = readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN);
+               intstat = readl(GPIO_INTR_STATUS(gpio)) & BIT(INTR_STATUS);
+               if (intstat || val == val2)
+                       return;
+       } while (loop_limit-- > 0);
+       pr_err("dual-edge irq failed to stabilize, "
+              "interrupts dropped. %#08x != %#08x\n",
+              val, val2);
+}
+
+static void msm_gpio_irq_ack(struct irq_data *d)
+{
+       int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+
+       writel(BIT(INTR_STATUS), GPIO_INTR_STATUS(gpio));
+       if (test_bit(gpio, msm_gpio.dual_edge_irqs))
+               msm_gpio_update_dual_edge_pos(gpio);
+}
+
+static void msm_gpio_irq_mask(struct irq_data *d)
+{
+       int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&tlmm_lock, irq_flags);
+       writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
+       clear_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
+       __clear_bit(gpio, msm_gpio.enabled_irqs);
+       spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+}
+
+static void msm_gpio_irq_unmask(struct irq_data *d)
+{
+       int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&tlmm_lock, irq_flags);
+       __set_bit(gpio, msm_gpio.enabled_irqs);
+       set_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
+       writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
+       spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+}
+
+static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+       int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+       unsigned long irq_flags;
+       uint32_t bits;
+
+       spin_lock_irqsave(&tlmm_lock, irq_flags);
+
+       bits = readl(GPIO_INTR_CFG(gpio));
+
+       if (flow_type & IRQ_TYPE_EDGE_BOTH) {
+               bits |= BIT(INTR_DECT_CTL);
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
+               if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+                       __set_bit(gpio, msm_gpio.dual_edge_irqs);
+               else
+                       __clear_bit(gpio, msm_gpio.dual_edge_irqs);
+       } else {
+               bits &= ~BIT(INTR_DECT_CTL);
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+               __clear_bit(gpio, msm_gpio.dual_edge_irqs);
+       }
+
+       if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
+               bits |= BIT(INTR_POL_CTL);
+       else
+               bits &= ~BIT(INTR_POL_CTL);
+
+       writel(bits, GPIO_INTR_CFG(gpio));
+
+       if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+               msm_gpio_update_dual_edge_pos(gpio);
+
+       spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+
+       return 0;
+}
+
+/*
+ * When the summary IRQ is raised, any number of GPIO lines may be high.
+ * It is the job of the summary handler to find all those GPIO lines
+ * which have been set as summary IRQ lines and which are triggered,
+ * and to call their interrupt handlers.
+ */
+static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned long i;
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+
+       chained_irq_enter(chip, desc);
+
+       for (i = find_first_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
+            i < NR_GPIO_IRQS;
+            i = find_next_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS, i + 1)) {
+               if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS))
+                       generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
+                                                          i));
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+       int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+
+       if (on) {
+               if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS))
+                       irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 1);
+               set_bit(gpio, msm_gpio.wake_irqs);
+       } else {
+               clear_bit(gpio, msm_gpio.wake_irqs);
+               if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS))
+                       irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 0);
+       }
+
+       return 0;
+}
+
+static struct irq_chip msm_gpio_irq_chip = {
+       .name           = "msmgpio",
+       .irq_mask       = msm_gpio_irq_mask,
+       .irq_unmask     = msm_gpio_irq_unmask,
+       .irq_ack        = msm_gpio_irq_ack,
+       .irq_set_type   = msm_gpio_irq_set_type,
+       .irq_set_wake   = msm_gpio_irq_set_wake,
+};
+
+static int __devinit msm_gpio_probe(struct platform_device *dev)
+{
+       int i, irq, ret;
+
+       bitmap_zero(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
+       bitmap_zero(msm_gpio.wake_irqs, NR_GPIO_IRQS);
+       bitmap_zero(msm_gpio.dual_edge_irqs, NR_GPIO_IRQS);
+       msm_gpio.gpio_chip.label = dev->name;
+       ret = gpiochip_add(&msm_gpio.gpio_chip);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
+               irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
+               irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
+                                        handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       irq_set_chained_handler(TLMM_SCSS_SUMMARY_IRQ,
+                               msm_summary_irq_handler);
+       return 0;
+}
+
+static int __devexit msm_gpio_remove(struct platform_device *dev)
+{
+       int ret = gpiochip_remove(&msm_gpio.gpio_chip);
+
+       if (ret < 0)
+               return ret;
+
+       irq_set_handler(TLMM_SCSS_SUMMARY_IRQ, NULL);
+
+       return 0;
+}
+
+static struct platform_driver msm_gpio_driver = {
+       .probe = msm_gpio_probe,
+       .remove = __devexit_p(msm_gpio_remove),
+       .driver = {
+               .name = "msmgpio",
+               .owner = THIS_MODULE,
+       },
+};
+
+static struct platform_device msm_device_gpio = {
+       .name = "msmgpio",
+       .id   = -1,
+};
+
+static int __init msm_gpio_init(void)
+{
+       int rc;
+
+       rc = platform_driver_register(&msm_gpio_driver);
+       if (!rc) {
+               rc = platform_device_register(&msm_device_gpio);
+               if (rc)
+                       platform_driver_unregister(&msm_gpio_driver);
+       }
+
+       return rc;
+}
+
+static void __exit msm_gpio_exit(void)
+{
+       platform_device_unregister(&msm_device_gpio);
+       platform_driver_unregister(&msm_gpio_driver);
+}
+
+postcore_initcall(msm_gpio_init);
+module_exit(msm_gpio_exit);
+
+MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
+MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:msmgpio");
diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c
new file mode 100644 (file)
index 0000000..79e66c0
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya <magi@slimlogic.co.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 of the License, or (at your
+ *  option) any later version.
+ *
+ * This driver is based on wm8350 implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/mfd/tps65912.h>
+
+struct tps65912_gpio_data {
+       struct tps65912 *tps65912;
+       struct gpio_chip gpio_chip;
+};
+
+static int tps65912_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+       int val;
+
+       val = tps65912_reg_read(tps65912, TPS65912_GPIO1 + offset);
+
+       if (val & GPIO_STS_MASK)
+               return 1;
+
+       return 0;
+}
+
+static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
+                             int value)
+{
+       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+
+       if (value)
+               tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
+                                                       GPIO_SET_MASK);
+       else
+               tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
+                                                               GPIO_SET_MASK);
+}
+
+static int tps65912_gpio_output(struct gpio_chip *gc, unsigned offset,
+                               int value)
+{
+       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+
+       /* Set the initial value */
+       tps65912_gpio_set(gc, offset, value);
+
+       return tps65912_set_bits(tps65912, TPS65912_GPIO1 + offset,
+                                                               GPIO_CFG_MASK);
+}
+
+static int tps65912_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+       struct tps65912 *tps65912 = container_of(gc, struct tps65912, gpio);
+
+       return tps65912_clear_bits(tps65912, TPS65912_GPIO1 + offset,
+                                                               GPIO_CFG_MASK);
+
+}
+
+static struct gpio_chip template_chip = {
+       .label                  = "tps65912",
+       .owner                  = THIS_MODULE,
+       .direction_input        = tps65912_gpio_input,
+       .direction_output       = tps65912_gpio_output,
+       .get                    = tps65912_gpio_get,
+       .set                    = tps65912_gpio_set,
+       .can_sleep              = 1,
+       .ngpio                  = 5,
+       .base                   = -1,
+};
+
+static int __devinit tps65912_gpio_probe(struct platform_device *pdev)
+{
+       struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent);
+       struct tps65912_board *pdata = tps65912->dev->platform_data;
+       struct tps65912_gpio_data *tps65912_gpio;
+       int ret;
+
+       tps65912_gpio = kzalloc(sizeof(*tps65912_gpio), GFP_KERNEL);
+       if (tps65912_gpio == NULL)
+               return -ENOMEM;
+
+       tps65912_gpio->tps65912 = tps65912;
+       tps65912_gpio->gpio_chip = template_chip;
+       tps65912_gpio->gpio_chip.dev = &pdev->dev;
+       if (pdata && pdata->gpio_base)
+               tps65912_gpio->gpio_chip.base = pdata->gpio_base;
+
+       ret = gpiochip_add(&tps65912_gpio->gpio_chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret);
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, tps65912_gpio);
+
+       return ret;
+
+err:
+       kfree(tps65912_gpio);
+       return ret;
+}
+
+static int __devexit tps65912_gpio_remove(struct platform_device *pdev)
+{
+       struct tps65912_gpio_data  *tps65912_gpio = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = gpiochip_remove(&tps65912_gpio->gpio_chip);
+       if (ret == 0)
+               kfree(tps65912_gpio);
+
+       return ret;
+}
+
+static struct platform_driver tps65912_gpio_driver = {
+       .driver = {
+               .name = "tps65912-gpio",
+               .owner = THIS_MODULE,
+       },
+       .probe = tps65912_gpio_probe,
+       .remove = __devexit_p(tps65912_gpio_remove),
+};
+
+static int __init tps65912_gpio_init(void)
+{
+       return platform_driver_register(&tps65912_gpio_driver);
+}
+subsys_initcall(tps65912_gpio_init);
+
+static void __exit tps65912_gpio_exit(void)
+{
+       platform_driver_unregister(&tps65912_gpio_driver);
+}
+module_exit(tps65912_gpio_exit);
+
+MODULE_AUTHOR("Margarita Olaya Cabrera <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("GPIO interface for TPS65912 PMICs");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65912-gpio");
index 0598cd22edf2d80fbe28d89f61df98beaa0a6755..0b62c3c6b7cefc2e603cdf2ed9a7972434e1e443 100644 (file)
@@ -623,7 +623,7 @@ config SENSORS_LM90
          LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
          Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
          MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008,
-         and Winbond/Nuvoton W83L771W/G/AWG/ASG sensor chips.
+         Winbond/Nuvoton W83L771W/G/AWG/ASG and Philips SA56004 sensor chips.
 
          This driver can also be built as a module.  If so, the module
          will be called lm90.
@@ -694,14 +694,24 @@ config SENSORS_LTC4261
          be called ltc4261.
 
 config SENSORS_LM95241
-       tristate "National Semiconductor LM95241 sensor chip"
+       tristate "National Semiconductor LM95241 and compatibles"
        depends on I2C
        help
-         If you say yes here you get support for LM95241 sensor chip.
+         If you say yes here you get support for LM95231 and LM95241 sensor
+         chips.
 
          This driver can also be built as a module.  If so, the module
          will be called lm95241.
 
+config SENSORS_LM95245
+       tristate "National Semiconductor LM95245 sensor chip"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for LM95245 sensor chip.
+
+         This driver can also be built as a module.  If so, the module
+         will be called lm95245.
+
 config SENSORS_MAX1111
        tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip"
        depends on SPI_MASTER
@@ -736,6 +746,16 @@ config SENSORS_MAX1619
          This driver can also be built as a module.  If so, the module
          will be called max1619.
 
+config SENSORS_MAX1668
+       tristate "Maxim MAX1668 and compatibles"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for MAX1668, MAX1989 and
+         MAX1805 chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called max1668.
+
 config SENSORS_MAX6639
        tristate "Maxim MAX6639 sensor chip"
        depends on I2C && EXPERIMENTAL
@@ -767,6 +787,20 @@ config SENSORS_MAX6650
          This driver can also be built as a module.  If so, the module
          will be called max6650.
 
+config SENSORS_NTC_THERMISTOR
+       tristate "NTC thermistor support"
+       depends on EXPERIMENTAL
+       help
+         This driver supports NTC thermistors sensor reading and its
+         interpretation. The driver can also monitor the temperature and
+         send notifications about the temperature.
+
+         Currently, this driver supports
+         NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, and NCP15WL333.
+
+         This driver can also be built as a module.  If so, the module
+         will be called ntc-thermistor.
+
 config SENSORS_PC87360
        tristate "National Semiconductor PC87360 family"
        select HWMON_VID
@@ -807,92 +841,7 @@ config SENSORS_PCF8591
          These devices are hard to detect and rarely found on mainstream
          hardware.  If unsure, say N.
 
-config PMBUS
-       tristate "PMBus support"
-       depends on I2C && EXPERIMENTAL
-       default n
-       help
-         Say yes here if you want to enable PMBus support.
-
-         This driver can also be built as a module. If so, the module will
-         be called pmbus_core.
-
-if PMBUS
-
-config SENSORS_PMBUS
-       tristate "Generic PMBus devices"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for generic
-         PMBus devices, including but not limited to BMR450, BMR451, BMR453,
-         BMR454, and LTC2978.
-
-         This driver can also be built as a module. If so, the module will
-         be called pmbus.
-
-config SENSORS_ADM1275
-       tristate "Analog Devices ADM1275"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for Analog
-         Devices ADM1275 Hot-Swap Controller and Digital Power Monitor.
-
-         This driver can also be built as a module. If so, the module will
-         be called adm1275.
-
-config SENSORS_MAX16064
-       tristate "Maxim MAX16064"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for Maxim
-         MAX16064.
-
-         This driver can also be built as a module. If so, the module will
-         be called max16064.
-
-config SENSORS_MAX34440
-       tristate "Maxim MAX34440/MAX34441"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for Maxim
-         MAX34440 and MAX34441.
-
-         This driver can also be built as a module. If so, the module will
-         be called max34440.
-
-config SENSORS_MAX8688
-       tristate "Maxim MAX8688"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for Maxim
-         MAX8688.
-
-         This driver can also be built as a module. If so, the module will
-         be called max8688.
-
-config SENSORS_UCD9000
-       tristate "TI UCD90120, UCD90124, UCD9090, UCD90910"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for TI
-         UCD90120, UCD90124, UCD9090, UCD90910 Sequencer and System Health
-         Controllers.
-
-         This driver can also be built as a module. If so, the module will
-         be called ucd9000.
-
-config SENSORS_UCD9200
-       tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248"
-       default n
-       help
-         If you say yes here you get hardware monitoring support for TI
-         UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
-         Digital PWM System Controllers.
-
-         This driver can also be built as a module. If so, the module will
-         be called ucd9200.
-
-endif # PMBUS
+source drivers/hwmon/pmbus/Kconfig
 
 config SENSORS_SHT15
        tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
index d7995a1d0784fa829465e116f00e168312291c3f..3c9ccefea7919bae3e6cec9097f5d8ab6be48575 100644 (file)
@@ -80,6 +80,7 @@ obj-$(CONFIG_SENSORS_LM90)    += lm90.o
 obj-$(CONFIG_SENSORS_LM92)     += lm92.o
 obj-$(CONFIG_SENSORS_LM93)     += lm93.o
 obj-$(CONFIG_SENSORS_LM95241)  += lm95241.o
+obj-$(CONFIG_SENSORS_LM95245)  += lm95245.o
 obj-$(CONFIG_SENSORS_LTC4151)  += ltc4151.o
 obj-$(CONFIG_SENSORS_LTC4215)  += ltc4215.o
 obj-$(CONFIG_SENSORS_LTC4245)  += ltc4245.o
@@ -87,10 +88,12 @@ obj-$(CONFIG_SENSORS_LTC4261)       += ltc4261.o
 obj-$(CONFIG_SENSORS_MAX1111)  += max1111.o
 obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
 obj-$(CONFIG_SENSORS_MAX1619)  += max1619.o
+obj-$(CONFIG_SENSORS_MAX1668)  += max1668.o
 obj-$(CONFIG_SENSORS_MAX6639)  += max6639.o
 obj-$(CONFIG_SENSORS_MAX6642)  += max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)  += max6650.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
+obj-$(CONFIG_SENSORS_NTC_THERMISTOR)   += ntc_thermistor.o
 obj-$(CONFIG_SENSORS_PC87360)  += pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)  += pc87427.o
 obj-$(CONFIG_SENSORS_PCF8591)  += pcf8591.o
@@ -121,15 +124,7 @@ obj-$(CONFIG_SENSORS_W83L786NG)    += w83l786ng.o
 obj-$(CONFIG_SENSORS_WM831X)   += wm831x-hwmon.o
 obj-$(CONFIG_SENSORS_WM8350)   += wm8350-hwmon.o
 
-# PMBus drivers
-obj-$(CONFIG_PMBUS)            += pmbus_core.o
-obj-$(CONFIG_SENSORS_PMBUS)    += pmbus.o
-obj-$(CONFIG_SENSORS_ADM1275)  += adm1275.o
-obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
-obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
-obj-$(CONFIG_SENSORS_MAX8688)  += max8688.o
-obj-$(CONFIG_SENSORS_UCD9000)  += ucd9000.o
-obj-$(CONFIG_SENSORS_UCD9200)  += ucd9200.o
+obj-$(CONFIG_PMBUS)            += pmbus/
 
 ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG
 
diff --git a/drivers/hwmon/adm1275.c b/drivers/hwmon/adm1275.c
deleted file mode 100644 (file)
index 8bc1bd6..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller
- * and Digital Power Monitor
- *
- * Copyright (c) 2011 Ericsson AB.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include "pmbus.h"
-
-#define ADM1275_PMON_CONFIG            0xd4
-
-#define ADM1275_VIN_VOUT_SELECT                (1 << 6)
-#define ADM1275_VRANGE                 (1 << 5)
-
-static int adm1275_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
-{
-       int config;
-       int ret;
-       struct pmbus_driver_info *info;
-
-       if (!i2c_check_functionality(client->adapter,
-                                    I2C_FUNC_SMBUS_READ_BYTE_DATA))
-               return -ENODEV;
-
-       info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
-       if (config < 0) {
-               ret = config;
-               goto err_mem;
-       }
-
-       info->pages = 1;
-       info->direct[PSC_VOLTAGE_IN] = true;
-       info->direct[PSC_VOLTAGE_OUT] = true;
-       info->direct[PSC_CURRENT_OUT] = true;
-       info->m[PSC_CURRENT_OUT] = 807;
-       info->b[PSC_CURRENT_OUT] = 20475;
-       info->R[PSC_CURRENT_OUT] = -1;
-       info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
-
-       if (config & ADM1275_VRANGE) {
-               info->m[PSC_VOLTAGE_IN] = 19199;
-               info->b[PSC_VOLTAGE_IN] = 0;
-               info->R[PSC_VOLTAGE_IN] = -2;
-               info->m[PSC_VOLTAGE_OUT] = 19199;
-               info->b[PSC_VOLTAGE_OUT] = 0;
-               info->R[PSC_VOLTAGE_OUT] = -2;
-       } else {
-               info->m[PSC_VOLTAGE_IN] = 6720;
-               info->b[PSC_VOLTAGE_IN] = 0;
-               info->R[PSC_VOLTAGE_IN] = -1;
-               info->m[PSC_VOLTAGE_OUT] = 6720;
-               info->b[PSC_VOLTAGE_OUT] = 0;
-               info->R[PSC_VOLTAGE_OUT] = -1;
-       }
-
-       if (config & ADM1275_VIN_VOUT_SELECT)
-               info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
-       else
-               info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
-
-       ret = pmbus_do_probe(client, id, info);
-       if (ret)
-               goto err_mem;
-       return 0;
-
-err_mem:
-       kfree(info);
-       return ret;
-}
-
-static int adm1275_remove(struct i2c_client *client)
-{
-       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
-       int ret;
-
-       ret = pmbus_do_remove(client);
-       kfree(info);
-       return ret;
-}
-
-static const struct i2c_device_id adm1275_id[] = {
-       {"adm1275", 0},
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, adm1275_id);
-
-static struct i2c_driver adm1275_driver = {
-       .driver = {
-                  .name = "adm1275",
-                  },
-       .probe = adm1275_probe,
-       .remove = adm1275_remove,
-       .id_table = adm1275_id,
-};
-
-static int __init adm1275_init(void)
-{
-       return i2c_add_driver(&adm1275_driver);
-}
-
-static void __exit adm1275_exit(void)
-{
-       i2c_del_driver(&adm1275_driver);
-}
-
-MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275");
-MODULE_LICENSE("GPL");
-module_init(adm1275_init);
-module_exit(adm1275_exit);
index 0070d5476dd0b5ee96bba29259c821d5419bf117..59d83e83da7fe0b5de39f7ce6e001899babfb7be 100644 (file)
@@ -44,7 +44,9 @@
 #define BASE_SYSFS_ATTR_NO     2       /* Sysfs Base attr no for coretemp */
 #define NUM_REAL_CORES         16      /* Number of Real cores per cpu */
 #define CORETEMP_NAME_LENGTH   17      /* String Length of attrs */
-#define MAX_ATTRS              5       /* Maximum no of per-core attrs */
+#define MAX_CORE_ATTRS         4       /* Maximum no of basic attrs */
+#define MAX_THRESH_ATTRS       3       /* Maximum no of Threshold attrs */
+#define TOTAL_ATTRS            (MAX_CORE_ATTRS + MAX_THRESH_ATTRS)
 #define MAX_CORE_DATA          (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
 
 #ifdef CONFIG_SMP
@@ -67,6 +69,9 @@
  *             This value is passed as "id" field to rdmsr/wrmsr functions.
  * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS,
  *             from where the temperature values should be read.
+ * @intrpt_reg: One of IA32_THERM_INTERRUPT or IA32_PACKAGE_THERM_INTERRUPT,
+ *             from where the thresholds are read.
+ * @attr_size:  Total number of pre-core attrs displayed in the sysfs.
  * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
  *             Otherwise, temp_data holds coretemp data.
  * @valid: If this is 1, the current temperature is valid.
 struct temp_data {
        int temp;
        int ttarget;
+       int tmin;
        int tjmax;
        unsigned long last_updated;
        unsigned int cpu;
        u32 cpu_core_id;
        u32 status_reg;
+       u32 intrpt_reg;
+       int attr_size;
        bool is_pkg_data;
        bool valid;
-       struct sensor_device_attribute sd_attrs[MAX_ATTRS];
-       char attr_name[MAX_ATTRS][CORETEMP_NAME_LENGTH];
+       struct sensor_device_attribute sd_attrs[TOTAL_ATTRS];
+       char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH];
        struct mutex update_lock;
 };
 
@@ -135,6 +143,19 @@ static ssize_t show_crit_alarm(struct device *dev,
        return sprintf(buf, "%d\n", (eax >> 5) & 1);
 }
 
+static ssize_t show_max_alarm(struct device *dev,
+                               struct device_attribute *devattr, char *buf)
+{
+       u32 eax, edx;
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct platform_data *pdata = dev_get_drvdata(dev);
+       struct temp_data *tdata = pdata->core_data[attr->index];
+
+       rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
+
+       return sprintf(buf, "%d\n", !!(eax & THERM_STATUS_THRESHOLD1));
+}
+
 static ssize_t show_tjmax(struct device *dev,
                        struct device_attribute *devattr, char *buf)
 {
@@ -153,6 +174,83 @@ static ssize_t show_ttarget(struct device *dev,
        return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
 }
 
+static ssize_t store_ttarget(struct device *dev,
+                               struct device_attribute *devattr,
+                               const char *buf, size_t count)
+{
+       struct platform_data *pdata = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct temp_data *tdata = pdata->core_data[attr->index];
+       u32 eax, edx;
+       unsigned long val;
+       int diff;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+
+       /*
+        * THERM_MASK_THRESHOLD1 is 7 bits wide. Values are entered in terms
+        * of milli degree celsius. Hence don't accept val > (127 * 1000)
+        */
+       if (val > tdata->tjmax || val > 127000)
+               return -EINVAL;
+
+       diff = (tdata->tjmax - val) / 1000;
+
+       mutex_lock(&tdata->update_lock);
+       rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
+       eax = (eax & ~THERM_MASK_THRESHOLD1) |
+                               (diff << THERM_SHIFT_THRESHOLD1);
+       wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
+       tdata->ttarget = val;
+       mutex_unlock(&tdata->update_lock);
+
+       return count;
+}
+
+static ssize_t show_tmin(struct device *dev,
+                       struct device_attribute *devattr, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct platform_data *pdata = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tmin);
+}
+
+static ssize_t store_tmin(struct device *dev,
+                               struct device_attribute *devattr,
+                               const char *buf, size_t count)
+{
+       struct platform_data *pdata = dev_get_drvdata(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct temp_data *tdata = pdata->core_data[attr->index];
+       u32 eax, edx;
+       unsigned long val;
+       int diff;
+
+       if (strict_strtoul(buf, 10, &val))
+               return -EINVAL;
+
+       /*
+        * THERM_MASK_THRESHOLD0 is 7 bits wide. Values are entered in terms
+        * of milli degree celsius. Hence don't accept val > (127 * 1000)
+        */
+       if (val > tdata->tjmax || val > 127000)
+               return -EINVAL;
+
+       diff = (tdata->tjmax - val) / 1000;
+
+       mutex_lock(&tdata->update_lock);
+       rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
+       eax = (eax & ~THERM_MASK_THRESHOLD0) |
+                               (diff << THERM_SHIFT_THRESHOLD0);
+       wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
+       tdata->tmin = val;
+       mutex_unlock(&tdata->update_lock);
+
+       return count;
+}
+
 static ssize_t show_temp(struct device *dev,
                        struct device_attribute *devattr, char *buf)
 {
@@ -344,23 +442,31 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
                                int attr_no)
 {
        int err, i;
-       static ssize_t (*rd_ptr[MAX_ATTRS]) (struct device *dev,
+       static ssize_t (*rd_ptr[TOTAL_ATTRS]) (struct device *dev,
                        struct device_attribute *devattr, char *buf) = {
-                       show_label, show_crit_alarm, show_ttarget,
-                       show_temp, show_tjmax };
-       static const char *names[MAX_ATTRS] = {
+                       show_label, show_crit_alarm, show_temp, show_tjmax,
+                       show_max_alarm, show_ttarget, show_tmin };
+       static ssize_t (*rw_ptr[TOTAL_ATTRS]) (struct device *dev,
+                       struct device_attribute *devattr, const char *buf,
+                       size_t count) = { NULL, NULL, NULL, NULL, NULL,
+                                       store_ttarget, store_tmin };
+       static const char *names[TOTAL_ATTRS] = {
                                        "temp%d_label", "temp%d_crit_alarm",
-                                       "temp%d_max", "temp%d_input",
-                                       "temp%d_crit" };
+                                       "temp%d_input", "temp%d_crit",
+                                       "temp%d_max_alarm", "temp%d_max",
+                                       "temp%d_max_hyst" };
 
-       for (i = 0; i < MAX_ATTRS; i++) {
+       for (i = 0; i < tdata->attr_size; i++) {
                snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
                        attr_no);
                sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
                tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
                tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
+               if (rw_ptr[i]) {
+                       tdata->sd_attrs[i].dev_attr.attr.mode |= S_IWUSR;
+                       tdata->sd_attrs[i].dev_attr.store = rw_ptr[i];
+               }
                tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
-               tdata->sd_attrs[i].dev_attr.store = NULL;
                tdata->sd_attrs[i].index = attr_no;
                err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
                if (err)
@@ -374,38 +480,6 @@ exit_free:
        return err;
 }
 
-static void update_ttarget(__u8 cpu_model, struct temp_data *tdata,
-                               struct device *dev)
-{
-       int err;
-       u32 eax, edx;
-
-       /*
-        * Initialize ttarget value. Eventually this will be
-        * initialized with the value from MSR_IA32_THERM_INTERRUPT
-        * register. If IA32_TEMPERATURE_TARGET is supported, this
-        * value will be over written below.
-        * To Do: Patch to initialize ttarget from MSR_IA32_THERM_INTERRUPT
-        */
-       tdata->ttarget = tdata->tjmax - 20000;
-
-       /*
-        * Read the still undocumented IA32_TEMPERATURE_TARGET. It exists
-        * on older CPUs but not in this register,
-        * Atoms don't have it either.
-        */
-       if (cpu_model > 0xe && cpu_model != 0x1c) {
-               err = rdmsr_safe_on_cpu(tdata->cpu,
-                               MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
-               if (err) {
-                       dev_warn(dev,
-                       "Unable to read IA32_TEMPERATURE_TARGET MSR\n");
-               } else {
-                       tdata->ttarget = tdata->tjmax -
-                                       ((eax >> 8) & 0xff) * 1000;
-               }
-       }
-}
 
 static int __devinit chk_ucode_version(struct platform_device *pdev)
 {
@@ -464,9 +538,12 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
 
        tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
                                                        MSR_IA32_THERM_STATUS;
+       tdata->intrpt_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_INTERRUPT :
+                                               MSR_IA32_THERM_INTERRUPT;
        tdata->is_pkg_data = pkg_flag;
        tdata->cpu = cpu;
        tdata->cpu_core_id = TO_CORE_ID(cpu);
+       tdata->attr_size = MAX_CORE_ATTRS;
        mutex_init(&tdata->update_lock);
        return tdata;
 }
@@ -516,7 +593,17 @@ static int create_core_data(struct platform_data *pdata,
        else
                tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
 
-       update_ttarget(c->x86_model, tdata, &pdev->dev);
+       /*
+        * Test if we can access the intrpt register. If so, increase the
+        * 'size' enough to have ttarget/tmin/max_alarm interfaces.
+        * Initialize ttarget with bits 16:22 of MSR_IA32_THERM_INTERRUPT
+        */
+       err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx);
+       if (!err) {
+               tdata->attr_size += MAX_THRESH_ATTRS;
+               tdata->ttarget = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000;
+       }
+
        pdata->core_data[attr_no] = tdata;
 
        /* Create sysfs interfaces */
@@ -553,7 +640,7 @@ static void coretemp_remove_core(struct platform_data *pdata,
        struct temp_data *tdata = pdata->core_data[indx];
 
        /* Remove the sysfs attributes */
-       for (i = 0; i < MAX_ATTRS; i++)
+       for (i = 0; i < tdata->attr_size; i++)
                device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
 
        kfree(pdata->core_data[indx]);
index 2f94f9504804f29963a17b9327abd860be851436..90ddb8774210cd2b83b231859ac77839d66d9bc4 100644 (file)
@@ -54,6 +54,9 @@
  * and extended mode. They are mostly compatible with LM90 except for a data
  * format difference for the temperature value registers.
  *
+ * This driver also supports the SA56004 from Philips. This device is
+ * pin-compatible with the LM86, the ED/EDP parts are also address-compatible.
+ *
  * Since the LM90 was the first chipset supported by this driver, most
  * comments will refer to this chipset, but are actually general and
  * concern all supported chipsets, unless mentioned otherwise.
  * MAX6659 can have address 0x4c, 0x4d or 0x4e.
  * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
  * 0x4c, 0x4d or 0x4e.
+ * SA56004 can have address 0x48 through 0x4F.
  */
 
 static const unsigned short normal_i2c[] = {
-       0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
+       0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+       0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 
 enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
-       max6646, w83l771, max6696 };
+       max6646, w83l771, max6696, sa56004 };
 
 /*
  * The LM90 registers
@@ -152,6 +157,10 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
 #define MAX6659_REG_R_LOCAL_EMERG      0x17
 #define MAX6659_REG_W_LOCAL_EMERG      0x17
 
+/*  SA56004 registers */
+
+#define SA56004_REG_R_LOCAL_TEMPL 0x22
+
 #define LM90_DEF_CONVRATE_RVAL 6       /* Def conversion rate register value */
 #define LM90_MAX_CONVRATE_MS   16000   /* Maximum conversion rate in ms */
 
@@ -161,7 +170,6 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
 #define LM90_FLAG_ADT7461_EXT  (1 << 0) /* ADT7461 extended mode       */
 /* Device features */
 #define LM90_HAVE_OFFSET       (1 << 1) /* temperature offset register */
-#define LM90_HAVE_LOCAL_EXT    (1 << 2) /* extended local temperature  */
 #define LM90_HAVE_REM_LIMIT_EXT        (1 << 3) /* extended remote limit       */
 #define LM90_HAVE_EMERGENCY    (1 << 4) /* 3rd upper (emergency) limit */
 #define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm           */
@@ -192,6 +200,7 @@ static const struct i2c_device_id lm90_id[] = {
        { "max6696", max6696 },
        { "nct1008", adt7461 },
        { "w83l771", w83l771 },
+       { "sa56004", sa56004 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm90_id);
@@ -204,6 +213,7 @@ struct lm90_params {
        u16 alert_alarms;       /* Which alarm bits trigger ALERT# */
                                /* Upper 8 bits for max6695/96 */
        u8 max_convrate;        /* Maximum conversion rate register value */
+       u8 reg_local_ext;       /* Extended local temp register (optional) */
 };
 
 static const struct lm90_params lm90_params[] = {
@@ -235,19 +245,20 @@ static const struct lm90_params lm90_params[] = {
                .max_convrate = 9,
        },
        [max6646] = {
-               .flags = LM90_HAVE_LOCAL_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 6,
+               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6657] = {
-               .flags = LM90_HAVE_LOCAL_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
+               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6659] = {
-               .flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY,
+               .flags = LM90_HAVE_EMERGENCY,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
+               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [max6680] = {
                .flags = LM90_HAVE_OFFSET,
@@ -255,16 +266,23 @@ static const struct lm90_params lm90_params[] = {
                .max_convrate = 7,
        },
        [max6696] = {
-               .flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY
+               .flags = LM90_HAVE_EMERGENCY
                  | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3,
                .alert_alarms = 0x187c,
                .max_convrate = 6,
+               .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
        },
        [w83l771] = {
                .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
                .alert_alarms = 0x7c,
                .max_convrate = 8,
        },
+       [sa56004] = {
+               .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+               .alert_alarms = 0x7b,
+               .max_convrate = 9,
+               .reg_local_ext = SA56004_REG_R_LOCAL_TEMPL,
+       },
 };
 
 /*
@@ -286,6 +304,7 @@ struct lm90_data {
        u16 alert_alarms;       /* Which alarm bits trigger ALERT# */
                                /* Upper 8 bits for max6695/96 */
        u8 max_convrate;        /* Maximum conversion rate */
+       u8 reg_local_ext;       /* local extension register offset */
 
        /* registers values */
        s8 temp8[8];    /* 0: local low limit
@@ -452,9 +471,9 @@ static struct lm90_data *lm90_update_device(struct device *dev)
                lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[3]);
                lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst);
 
-               if (data->flags & LM90_HAVE_LOCAL_EXT) {
+               if (data->reg_local_ext) {
                        lm90_read16(client, LM90_REG_R_LOCAL_TEMP,
-                                   MAX6657_REG_R_LOCAL_TEMPL,
+                                   data->reg_local_ext,
                                    &data->temp11[4]);
                } else {
                        if (lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP,
@@ -1092,7 +1111,7 @@ static int lm90_detect(struct i2c_client *new_client,
        struct i2c_adapter *adapter = new_client->adapter;
        int address = new_client->addr;
        const char *name = NULL;
-       int man_id, chip_id, reg_config1, reg_convrate;
+       int man_id, chip_id, reg_config1, reg_config2, reg_convrate;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
@@ -1108,15 +1127,16 @@ static int lm90_detect(struct i2c_client *new_client,
                                                LM90_REG_R_CONVRATE)) < 0)
                return -ENODEV;
 
-       if ((address == 0x4C || address == 0x4D)
-        && man_id == 0x01) { /* National Semiconductor */
-               int reg_config2;
-
+       if (man_id == 0x01 || man_id == 0x5C || man_id == 0x41) {
                reg_config2 = i2c_smbus_read_byte_data(new_client,
                                                LM90_REG_R_CONFIG2);
                if (reg_config2 < 0)
                        return -ENODEV;
+       } else
+               reg_config2 = 0;        /* Make compiler happy */
 
+       if ((address == 0x4C || address == 0x4D)
+        && man_id == 0x01) { /* National Semiconductor */
                if ((reg_config1 & 0x2A) == 0x00
                 && (reg_config2 & 0xF8) == 0x00
                 && reg_convrate <= 0x09) {
@@ -1245,13 +1265,6 @@ static int lm90_detect(struct i2c_client *new_client,
        } else
        if (address == 0x4C
         && man_id == 0x5C) { /* Winbond/Nuvoton */
-               int reg_config2;
-
-               reg_config2 = i2c_smbus_read_byte_data(new_client,
-                                               LM90_REG_R_CONFIG2);
-               if (reg_config2 < 0)
-                       return -ENODEV;
-
                if ((reg_config1 & 0x2A) == 0x00
                 && (reg_config2 & 0xF8) == 0x00) {
                        if (chip_id == 0x01 /* W83L771W/G */
@@ -1263,6 +1276,15 @@ static int lm90_detect(struct i2c_client *new_client,
                                name = "w83l771";
                        }
                }
+       } else
+       if (address >= 0x48 && address <= 0x4F
+        && man_id == 0xA1) { /*  NXP Semiconductor/Philips */
+               if (chip_id == 0x00
+                && (reg_config1 & 0x2A) == 0x00
+                && (reg_config2 & 0xFE) == 0x00
+                && reg_convrate <= 0x09) {
+                       name = "sa56004";
+               }
        }
 
        if (!name) { /* identification failed */
@@ -1368,6 +1390,7 @@ static int lm90_probe(struct i2c_client *new_client,
 
        /* Set chip capabilities */
        data->flags = lm90_params[data->kind].flags;
+       data->reg_local_ext = lm90_params[data->kind].reg_local_ext;
 
        /* Set maximum conversion rate */
        data->max_convrate = lm90_params[data->kind].max_convrate;
index d3b464b74ced3b743969e2f0377523b0883243f2..513901d592a9b71630865d8ac71e37b2931a1e0f 100644 (file)
@@ -74,8 +74,9 @@ static const unsigned short normal_i2c[] = {
 #define TT_OFF 0
 #define TT_ON 1
 #define TT_MASK 7
-#define MANUFACTURER_ID 0x01
-#define DEFAULT_REVISION 0xA4
+#define NATSEMI_MAN_ID 0x01
+#define LM95231_CHIP_ID        0xA1
+#define LM95241_CHIP_ID        0xA4
 
 static const u8 lm95241_reg_address[] = {
        LM95241_REG_R_LOCAL_TEMPH,
@@ -338,20 +339,25 @@ static int lm95241_detect(struct i2c_client *new_client,
                          struct i2c_board_info *info)
 {
        struct i2c_adapter *adapter = new_client->adapter;
-       int address = new_client->addr;
        const char *name;
+       int mfg_id, chip_id;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID)
-            == MANUFACTURER_ID)
-           && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID)
-               == DEFAULT_REVISION)) {
-               name = DEVNAME;
-       } else {
-               dev_dbg(&adapter->dev, "LM95241 detection failed at 0x%02x\n",
-                       address);
+       mfg_id = i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID);
+       if (mfg_id != NATSEMI_MAN_ID)
+               return -ENODEV;
+
+       chip_id = i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID);
+       switch (chip_id) {
+       case LM95231_CHIP_ID:
+               name = "lm95231";
+               break;
+       case LM95241_CHIP_ID:
+               name = "lm95241";
+               break;
+       default:
                return -ENODEV;
        }
 
@@ -431,7 +437,8 @@ static int lm95241_remove(struct i2c_client *client)
 
 /* Driver data (common to all clients) */
 static const struct i2c_device_id lm95241_id[] = {
-       { DEVNAME, 0 },
+       { "lm95231", 0 },
+       { "lm95241", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lm95241_id);
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
new file mode 100644 (file)
index 0000000..dce9e68
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) 2011 Alexander Stein <alexander.stein@systec-electronic.com>
+ *
+ * The LM95245 is a sensor chip made by National Semiconductors.
+ * It reports up to two temperatures (its own plus an external one).
+ * Complete datasheet can be obtained from National's website at:
+ *   http://www.national.com/ds.cgi/LM/LM95245.pdf
+ *
+ * This driver is based on lm95241.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., 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/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+#define DEVNAME "lm95245"
+
+static const unsigned short normal_i2c[] = {
+       0x18, 0x19, 0x29, 0x4c, 0x4d, I2C_CLIENT_END };
+
+/* LM95245 registers */
+/* general registers */
+#define LM95245_REG_RW_CONFIG1         0x03
+#define LM95245_REG_RW_CONVERS_RATE    0x04
+#define LM95245_REG_W_ONE_SHOT         0x0F
+
+/* diode configuration */
+#define LM95245_REG_RW_CONFIG2         0xBF
+#define LM95245_REG_RW_REMOTE_OFFH     0x11
+#define LM95245_REG_RW_REMOTE_OFFL     0x12
+
+/* status registers */
+#define LM95245_REG_R_STATUS1          0x02
+#define LM95245_REG_R_STATUS2          0x33
+
+/* limit registers */
+#define LM95245_REG_RW_REMOTE_OS_LIMIT         0x07
+#define LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT    0x20
+#define LM95245_REG_RW_REMOTE_TCRIT_LIMIT      0x19
+#define LM95245_REG_RW_COMMON_HYSTERESIS       0x21
+
+/* temperature signed */
+#define LM95245_REG_R_LOCAL_TEMPH_S    0x00
+#define LM95245_REG_R_LOCAL_TEMPL_S    0x30
+#define LM95245_REG_R_REMOTE_TEMPH_S   0x01
+#define LM95245_REG_R_REMOTE_TEMPL_S   0x10
+/* temperature unsigned */
+#define LM95245_REG_R_REMOTE_TEMPH_U   0x31
+#define LM95245_REG_R_REMOTE_TEMPL_U   0x32
+
+/* id registers */
+#define LM95245_REG_R_MAN_ID           0xFE
+#define LM95245_REG_R_CHIP_ID          0xFF
+
+/* LM95245 specific bitfields */
+#define CFG_STOP               0x40
+#define CFG_REMOTE_TCRIT_MASK  0x10
+#define CFG_REMOTE_OS_MASK     0x08
+#define CFG_LOCAL_TCRIT_MASK   0x04
+#define CFG_LOCAL_OS_MASK      0x02
+
+#define CFG2_OS_A0             0x40
+#define CFG2_DIODE_FAULT_OS    0x20
+#define CFG2_DIODE_FAULT_TCRIT 0x10
+#define CFG2_REMOTE_TT         0x08
+#define CFG2_REMOTE_FILTER_DIS 0x00
+#define CFG2_REMOTE_FILTER_EN  0x06
+
+/* conversation rate in ms */
+#define RATE_CR0063    0x00
+#define RATE_CR0364    0x01
+#define RATE_CR1000    0x02
+#define RATE_CR2500    0x03
+
+#define STATUS1_DIODE_FAULT    0x04
+#define STATUS1_RTCRIT         0x02
+#define STATUS1_LOC            0x01
+
+#define MANUFACTURER_ID                0x01
+#define DEFAULT_REVISION       0xB3
+
+static const u8 lm95245_reg_address[] = {
+       LM95245_REG_R_LOCAL_TEMPH_S,
+       LM95245_REG_R_LOCAL_TEMPL_S,
+       LM95245_REG_R_REMOTE_TEMPH_S,
+       LM95245_REG_R_REMOTE_TEMPL_S,
+       LM95245_REG_R_REMOTE_TEMPH_U,
+       LM95245_REG_R_REMOTE_TEMPL_U,
+       LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT,
+       LM95245_REG_RW_REMOTE_TCRIT_LIMIT,
+       LM95245_REG_RW_COMMON_HYSTERESIS,
+       LM95245_REG_R_STATUS1,
+};
+
+/* Client data (each client gets its own) */
+struct lm95245_data {
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       unsigned long last_updated;     /* in jiffies */
+       unsigned long interval; /* in msecs */
+       bool valid;             /* zero until following fields are valid */
+       /* registers values */
+       u8 regs[ARRAY_SIZE(lm95245_reg_address)];
+       u8 config1, config2;
+};
+
+/* Conversions */
+static int temp_from_reg_unsigned(u8 val_h, u8 val_l)
+{
+       return val_h * 1000 + val_l * 1000 / 256;
+}
+
+static int temp_from_reg_signed(u8 val_h, u8 val_l)
+{
+       if (val_h & 0x80)
+               return (val_h - 0x100) * 1000;
+       return temp_from_reg_unsigned(val_h, val_l);
+}
+
+static struct lm95245_data *lm95245_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated
+               + msecs_to_jiffies(data->interval)) || !data->valid) {
+               int i;
+
+               dev_dbg(&client->dev, "Updating lm95245 data.\n");
+               for (i = 0; i < ARRAY_SIZE(lm95245_reg_address); i++)
+                       data->regs[i]
+                         = i2c_smbus_read_byte_data(client,
+                                                    lm95245_reg_address[i]);
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+static unsigned long lm95245_read_conversion_rate(struct i2c_client *client)
+{
+       int rate;
+       unsigned long interval;
+
+       rate = i2c_smbus_read_byte_data(client, LM95245_REG_RW_CONVERS_RATE);
+
+       switch (rate) {
+       case RATE_CR0063:
+               interval = 63;
+               break;
+       case RATE_CR0364:
+               interval = 364;
+               break;
+       case RATE_CR1000:
+               interval = 1000;
+               break;
+       case RATE_CR2500:
+       default:
+               interval = 2500;
+               break;
+       }
+
+       return interval;
+}
+
+static unsigned long lm95245_set_conversion_rate(struct i2c_client *client,
+                       unsigned long interval)
+{
+       int rate;
+
+       if (interval <= 63) {
+               interval = 63;
+               rate = RATE_CR0063;
+       } else if (interval <= 364) {
+               interval = 364;
+               rate = RATE_CR0364;
+       } else if (interval <= 1000) {
+               interval = 1000;
+               rate = RATE_CR1000;
+       } else {
+               interval = 2500;
+               rate = RATE_CR2500;
+       }
+
+       i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONVERS_RATE, rate);
+
+       return interval;
+}
+
+/* Sysfs stuff */
+static ssize_t show_input(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct lm95245_data *data = lm95245_update_device(dev);
+       int temp;
+       int index = to_sensor_dev_attr(attr)->index;
+
+       /*
+        * Index 0 (Local temp) is always signed
+        * Index 2 (Remote temp) has both signed and unsigned data
+        * use signed calculation for remote if signed bit is set
+        */
+       if (index == 0 || data->regs[index] & 0x80)
+               temp = temp_from_reg_signed(data->regs[index],
+                           data->regs[index + 1]);
+       else
+               temp = temp_from_reg_unsigned(data->regs[index + 2],
+                           data->regs[index + 3]);
+
+       return snprintf(buf, PAGE_SIZE - 1, "%d\n", temp);
+}
+
+static ssize_t show_limit(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct lm95245_data *data = lm95245_update_device(dev);
+       int index = to_sensor_dev_attr(attr)->index;
+
+       return snprintf(buf, PAGE_SIZE - 1, "%d\n",
+                       data->regs[index] * 1000);
+}
+
+static ssize_t set_limit(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+       int index = to_sensor_dev_attr(attr)->index;
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       val /= 1000;
+
+       val = SENSORS_LIMIT(val, 0, (index == 6 ? 127 : 255));
+
+       mutex_lock(&data->update_lock);
+
+       data->valid = 0;
+
+       i2c_smbus_write_byte_data(client, lm95245_reg_address[index], val);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t set_crit_hyst(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       val /= 1000;
+
+       val = SENSORS_LIMIT(val, 0, 31);
+
+       mutex_lock(&data->update_lock);
+
+       data->valid = 0;
+
+       /* shared crit hysteresis */
+       i2c_smbus_write_byte_data(client, LM95245_REG_RW_COMMON_HYSTERESIS,
+               val);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+
+       return snprintf(buf, PAGE_SIZE - 1,
+               data->config2 & CFG2_REMOTE_TT ? "1\n" : "2\n");
+}
+
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+       if (val != 1 && val != 2)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+
+       if (val == 1)
+               data->config2 |= CFG2_REMOTE_TT;
+       else
+               data->config2 &= ~CFG2_REMOTE_TT;
+
+       data->valid = 0;
+
+       i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONFIG2,
+                                 data->config2);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct lm95245_data *data = lm95245_update_device(dev);
+       int index = to_sensor_dev_attr(attr)->index;
+
+       return snprintf(buf, PAGE_SIZE - 1, "%d\n",
+                       !!(data->regs[9] & index));
+}
+
+static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct lm95245_data *data = lm95245_update_device(dev);
+
+       return snprintf(buf, PAGE_SIZE - 1, "%lu\n", data->interval);
+}
+
+static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lm95245_data *data = i2c_get_clientdata(client);
+       unsigned long val;
+
+       if (strict_strtoul(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+
+       data->interval = lm95245_set_conversion_rate(client, val);
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_limit,
+               set_limit, 6);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
+               set_crit_hyst, 8);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
+               STATUS1_LOC);
+
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_limit,
+               set_limit, 7);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_limit,
+               set_crit_hyst, 8);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
+               STATUS1_RTCRIT);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type,
+               set_type, 0);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
+               STATUS1_DIODE_FAULT);
+
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
+               set_interval);
+
+static struct attribute *lm95245_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_type.dev_attr.attr,
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+       &dev_attr_update_interval.attr,
+       NULL
+};
+
+static const struct attribute_group lm95245_group = {
+       .attrs = lm95245_attributes,
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int lm95245_detect(struct i2c_client *new_client,
+                         struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = new_client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       if (i2c_smbus_read_byte_data(new_client, LM95245_REG_R_MAN_ID)
+                       != MANUFACTURER_ID
+               || i2c_smbus_read_byte_data(new_client, LM95245_REG_R_CHIP_ID)
+                       != DEFAULT_REVISION)
+               return -ENODEV;
+
+       strlcpy(info->type, DEVNAME, I2C_NAME_SIZE);
+       return 0;
+}
+
+static void lm95245_init_client(struct i2c_client *client)
+{
+       struct lm95245_data *data = i2c_get_clientdata(client);
+
+       data->valid = 0;
+       data->interval = lm95245_read_conversion_rate(client);
+
+       data->config1 = i2c_smbus_read_byte_data(client,
+               LM95245_REG_RW_CONFIG1);
+       data->config2 = i2c_smbus_read_byte_data(client,
+               LM95245_REG_RW_CONFIG2);
+
+       if (data->config1 & CFG_STOP) {
+               /* Clear the standby bit */
+               data->config1 &= ~CFG_STOP;
+               i2c_smbus_write_byte_data(client, LM95245_REG_RW_CONFIG1,
+                       data->config1);
+       }
+}
+
+static int lm95245_probe(struct i2c_client *new_client,
+                        const struct i2c_device_id *id)
+{
+       struct lm95245_data *data;
+       int err;
+
+       data = kzalloc(sizeof(struct lm95245_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(new_client, data);
+       mutex_init(&data->update_lock);
+
+       /* Initialize the LM95245 chip */
+       lm95245_init_client(new_client);
+
+       /* Register sysfs hooks */
+       err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group);
+       if (err)
+               goto exit_free;
+
+       data->hwmon_dev = hwmon_device_register(&new_client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_files;
+       }
+
+       return 0;
+
+exit_remove_files:
+       sysfs_remove_group(&new_client->dev.kobj, &lm95245_group);
+exit_free:
+       kfree(data);
+exit:
+       return err;
+}
+
+static int lm95245_remove(struct i2c_client *client)
+{
+       struct lm95245_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &lm95245_group);
+
+       kfree(data);
+       return 0;
+}
+
+/* Driver data (common to all clients) */
+static const struct i2c_device_id lm95245_id[] = {
+       { DEVNAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lm95245_id);
+
+static struct i2c_driver lm95245_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = DEVNAME,
+       },
+       .probe          = lm95245_probe,
+       .remove         = lm95245_remove,
+       .id_table       = lm95245_id,
+       .detect         = lm95245_detect,
+       .address_list   = normal_i2c,
+};
+
+static int __init sensors_lm95245_init(void)
+{
+       return i2c_add_driver(&lm95245_driver);
+}
+
+static void __exit sensors_lm95245_exit(void)
+{
+       i2c_del_driver(&lm95245_driver);
+}
+
+MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
+MODULE_DESCRIPTION("LM95245 sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_lm95245_init);
+module_exit(sensors_lm95245_exit);
diff --git a/drivers/hwmon/max16064.c b/drivers/hwmon/max16064.c
deleted file mode 100644 (file)
index 1d6d717..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Hardware monitoring driver for Maxim MAX16064
- *
- * Copyright (c) 2011 Ericsson AB.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include "pmbus.h"
-
-static struct pmbus_driver_info max16064_info = {
-       .pages = 4,
-       .direct[PSC_VOLTAGE_IN] = true,
-       .direct[PSC_VOLTAGE_OUT] = true,
-       .direct[PSC_TEMPERATURE] = true,
-       .m[PSC_VOLTAGE_IN] = 19995,
-       .b[PSC_VOLTAGE_IN] = 0,
-       .R[PSC_VOLTAGE_IN] = -1,
-       .m[PSC_VOLTAGE_OUT] = 19995,
-       .b[PSC_VOLTAGE_OUT] = 0,
-       .R[PSC_VOLTAGE_OUT] = -1,
-       .m[PSC_TEMPERATURE] = -7612,
-       .b[PSC_TEMPERATURE] = 335,
-       .R[PSC_TEMPERATURE] = -3,
-       .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_TEMP
-               | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_TEMP,
-       .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
-       .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
-       .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
-};
-
-static int max16064_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
-{
-       return pmbus_do_probe(client, id, &max16064_info);
-}
-
-static int max16064_remove(struct i2c_client *client)
-{
-       return pmbus_do_remove(client);
-}
-
-static const struct i2c_device_id max16064_id[] = {
-       {"max16064", 0},
-       {}
-};
-
-MODULE_DEVICE_TABLE(i2c, max16064_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver max16064_driver = {
-       .driver = {
-                  .name = "max16064",
-                  },
-       .probe = max16064_probe,
-       .remove = max16064_remove,
-       .id_table = max16064_id,
-};
-
-static int __init max16064_init(void)
-{
-       return i2c_add_driver(&max16064_driver);
-}
-
-static void __exit max16064_exit(void)
-{
-       i2c_del_driver(&max16064_driver);
-}
-
-MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for Maxim MAX16064");
-MODULE_LICENSE("GPL");
-module_init(max16064_init);
-module_exit(max16064_exit);
diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c
new file mode 100644 (file)
index 0000000..20d1b2d
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+    Copyright (c) 2011 David George <david.george@ska.ac.za>
+
+    based on adm1021.c
+    some credit to Christoph Scheurer, but largely a rewrite
+
+    This 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/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Addresses to scan */
+static unsigned short max1668_addr_list[] = {
+       0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
+
+/* max1668 registers */
+
+#define MAX1668_REG_TEMP(nr)   (nr)
+#define MAX1668_REG_STAT1      0x05
+#define MAX1668_REG_STAT2      0x06
+#define MAX1668_REG_MAN_ID     0xfe
+#define MAX1668_REG_DEV_ID     0xff
+
+/* limits */
+
+/* write high limits */
+#define MAX1668_REG_LIMH_WR(nr)        (0x13 + 2 * (nr))
+/* write low limits */
+#define MAX1668_REG_LIML_WR(nr)        (0x14 + 2 * (nr))
+/* read high limits */
+#define MAX1668_REG_LIMH_RD(nr)        (0x08 + 2 * (nr))
+/* read low limits */
+#define MAX1668_REG_LIML_RD(nr)        (0x09 + 2 * (nr))
+
+/* manufacturer and device ID Constants */
+#define MAN_ID_MAXIM           0x4d
+#define DEV_ID_MAX1668         0x3
+#define DEV_ID_MAX1805         0x5
+#define DEV_ID_MAX1989         0xb
+
+/* read only mode module parameter */
+static int read_only;
+module_param(read_only, bool, 0);
+MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
+
+enum chips { max1668, max1805, max1989 };
+
+struct max1668_data {
+       struct device *hwmon_dev;
+       enum chips type;
+
+       struct mutex update_lock;
+       char valid;             /* !=0 if following fields are valid */
+       unsigned long last_updated;     /* In jiffies */
+
+       /* 1x local and 4x remote */
+       s8 temp_max[5];
+       s8 temp_min[5];
+       s8 temp[5];
+       u16 alarms;
+};
+
+static struct max1668_data *max1668_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct max1668_data *data = i2c_get_clientdata(client);
+       struct max1668_data *ret = data;
+       s32 val;
+       int i;
+
+       mutex_lock(&data->update_lock);
+
+       if (data->valid && !time_after(jiffies,
+                       data->last_updated + HZ + HZ / 2))
+               goto abort;
+
+       for (i = 0; i < 5; i++) {
+               val = i2c_smbus_read_byte_data(client, MAX1668_REG_TEMP(i));
+               if (unlikely(val < 0)) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->temp[i] = (s8) val;
+
+               val = i2c_smbus_read_byte_data(client, MAX1668_REG_LIMH_RD(i));
+               if (unlikely(val < 0)) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->temp_max[i] = (s8) val;
+
+               val = i2c_smbus_read_byte_data(client, MAX1668_REG_LIML_RD(i));
+               if (unlikely(val < 0)) {
+                       ret = ERR_PTR(val);
+                       goto abort;
+               }
+               data->temp_min[i] = (s8) val;
+       }
+
+       val = i2c_smbus_read_byte_data(client, MAX1668_REG_STAT1);
+       if (unlikely(val < 0)) {
+               ret = ERR_PTR(val);
+               goto abort;
+       }
+       data->alarms = val << 8;
+
+       val = i2c_smbus_read_byte_data(client, MAX1668_REG_STAT2);
+       if (unlikely(val < 0)) {
+               ret = ERR_PTR(val);
+               goto abort;
+       }
+       data->alarms |= val;
+
+       data->last_updated = jiffies;
+       data->valid = 1;
+abort:
+       mutex_unlock(&data->update_lock);
+
+       return ret;
+}
+
+static ssize_t show_temp(struct device *dev,
+                        struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct max1668_data *data = max1668_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", data->temp[index] * 1000);
+}
+
+static ssize_t show_temp_max(struct device *dev,
+                            struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct max1668_data *data = max1668_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", data->temp_max[index] * 1000);
+}
+
+static ssize_t show_temp_min(struct device *dev,
+                            struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct max1668_data *data = max1668_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", data->temp_min[index] * 1000);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int index = to_sensor_dev_attr(attr)->index;
+       struct max1668_data *data = max1668_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%u\n", (data->alarms >> index) & 0x1);
+}
+
+static ssize_t show_fault(struct device *dev,
+                         struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct max1668_data *data = max1668_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%u\n",
+                      (data->alarms & (1 << 12)) && data->temp[index] == 127);
+}
+
+static ssize_t set_temp_max(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct max1668_data *data = i2c_get_clientdata(client);
+       long temp;
+       int ret;
+
+       ret = kstrtol(buf, 10, &temp);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&data->update_lock);
+       data->temp_max[index] = SENSORS_LIMIT(temp/1000, -128, 127);
+       if (i2c_smbus_write_byte_data(client,
+                                       MAX1668_REG_LIMH_WR(index),
+                                       data->temp_max[index]))
+               count = -EIO;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t set_temp_min(struct device *dev,
+                           struct device_attribute *devattr,
+                           const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct max1668_data *data = i2c_get_clientdata(client);
+       long temp;
+       int ret;
+
+       ret = kstrtol(buf, 10, &temp);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&data->update_lock);
+       data->temp_min[index] = SENSORS_LIMIT(temp/1000, -128, 127);
+       if (i2c_smbus_write_byte_data(client,
+                                       MAX1668_REG_LIML_WR(index),
+                                       data->temp_max[index]))
+               count = -EIO;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max,
+                               set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp_min,
+                               set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max,
+                               set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp_min,
+                               set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max,
+                               set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp_min,
+                               set_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max,
+                               set_temp_max, 3);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO, show_temp_min,
+                               set_temp_min, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max,
+                               set_temp_max, 4);
+static SENSOR_DEVICE_ATTR(temp5_min, S_IRUGO, show_temp_min,
+                               set_temp_min, 4);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp5_min_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL, 0);
+
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_fault, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_fault, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_fault, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_fault, NULL, 4);
+
+/* Attributes common to MAX1668, MAX1989 and MAX1805 */
+static struct attribute *max1668_attribute_common[] = {
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_temp2_fault.dev_attr.attr,
+       &sensor_dev_attr_temp3_fault.dev_attr.attr,
+       NULL
+};
+
+/* Attributes not present on MAX1805 */
+static struct attribute *max1668_attribute_unique[] = {
+       &sensor_dev_attr_temp4_max.dev_attr.attr,
+       &sensor_dev_attr_temp4_min.dev_attr.attr,
+       &sensor_dev_attr_temp4_input.dev_attr.attr,
+       &sensor_dev_attr_temp5_max.dev_attr.attr,
+       &sensor_dev_attr_temp5_min.dev_attr.attr,
+       &sensor_dev_attr_temp5_input.dev_attr.attr,
+
+       &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp5_min_alarm.dev_attr.attr,
+
+       &sensor_dev_attr_temp4_fault.dev_attr.attr,
+       &sensor_dev_attr_temp5_fault.dev_attr.attr,
+       NULL
+};
+
+static mode_t max1668_attribute_mode(struct kobject *kobj,
+                                    struct attribute *attr, int index)
+{
+       int ret = S_IRUGO;
+       if (read_only)
+               return ret;
+       if (attr == &sensor_dev_attr_temp1_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp2_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp3_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp4_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp5_max.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp1_min.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp2_min.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp3_min.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp4_min.dev_attr.attr ||
+           attr == &sensor_dev_attr_temp5_min.dev_attr.attr)
+               ret |= S_IWUSR;
+       return ret;
+}
+
+static const struct attribute_group max1668_group_common = {
+       .attrs = max1668_attribute_common,
+       .is_visible = max1668_attribute_mode
+};
+
+static const struct attribute_group max1668_group_unique = {
+       .attrs = max1668_attribute_unique,
+       .is_visible = max1668_attribute_mode
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max1668_detect(struct i2c_client *client,
+                         struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       const char *type_name;
+       int man_id, dev_id;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       /* Check for unsupported part */
+       man_id = i2c_smbus_read_byte_data(client, MAX1668_REG_MAN_ID);
+       if (man_id != MAN_ID_MAXIM)
+               return -ENODEV;
+
+       dev_id = i2c_smbus_read_byte_data(client, MAX1668_REG_DEV_ID);
+       if (dev_id < 0)
+               return -ENODEV;
+
+       type_name = NULL;
+       if (dev_id == DEV_ID_MAX1668)
+               type_name = "max1668";
+       else if (dev_id == DEV_ID_MAX1805)
+               type_name = "max1805";
+       else if (dev_id == DEV_ID_MAX1989)
+               type_name = "max1989";
+
+       if (!type_name)
+               return -ENODEV;
+
+       strlcpy(info->type, type_name, I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int max1668_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       struct max1668_data *data;
+       int err;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       data = kzalloc(sizeof(struct max1668_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+       data->type = id->driver_data;
+       mutex_init(&data->update_lock);
+
+       /* Register sysfs hooks */
+       err = sysfs_create_group(&client->dev.kobj, &max1668_group_common);
+       if (err)
+               goto error_free;
+
+       if (data->type == max1668 || data->type == max1989) {
+               err = sysfs_create_group(&client->dev.kobj,
+                                        &max1668_group_unique);
+               if (err)
+                       goto error_sysrem0;
+       }
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto error_sysrem1;
+       }
+
+       return 0;
+
+error_sysrem1:
+       if (data->type == max1668 || data->type == max1989)
+               sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
+error_sysrem0:
+       sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
+error_free:
+       kfree(data);
+       return err;
+}
+
+static int max1668_remove(struct i2c_client *client)
+{
+       struct max1668_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       if (data->type == max1668 || data->type == max1989)
+               sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
+
+       sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
+
+       kfree(data);
+       return 0;
+}
+
+static const struct i2c_device_id max1668_id[] = {
+       { "max1668", max1668 },
+       { "max1805", max1805 },
+       { "max1989", max1989 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max1668_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max1668_driver = {
+       .class = I2C_CLASS_HWMON,
+       .driver = {
+                 .name = "max1668",
+                 },
+       .probe = max1668_probe,
+       .remove = max1668_remove,
+       .id_table = max1668_id,
+       .detect = max1668_detect,
+       .address_list = max1668_addr_list,
+};
+
+static int __init sensors_max1668_init(void)
+{
+       return i2c_add_driver(&max1668_driver);
+}
+
+static void __exit sensors_max1668_exit(void)
+{
+       i2c_del_driver(&max1668_driver);
+}
+
+MODULE_AUTHOR("David George <david.george@ska.ac.za>");
+MODULE_DESCRIPTION("MAX1668 remote temperature sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_max1668_init)
+module_exit(sensors_max1668_exit)
diff --git a/drivers/hwmon/max34440.c b/drivers/hwmon/max34440.c
deleted file mode 100644 (file)
index db11e1a..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Hardware monitoring driver for Maxim MAX34440/MAX34441
- *
- * Copyright (c) 2011 Ericsson AB.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include "pmbus.h"
-
-enum chips { max34440, max34441 };
-
-#define MAX34440_STATUS_OC_WARN                (1 << 0)
-#define MAX34440_STATUS_OC_FAULT       (1 << 1)
-#define MAX34440_STATUS_OT_FAULT       (1 << 5)
-#define MAX34440_STATUS_OT_WARN                (1 << 6)
-
-static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
-{
-       int ret;
-       int mfg_status;
-
-       ret = pmbus_set_page(client, page);
-       if (ret < 0)
-               return ret;
-
-       switch (reg) {
-       case PMBUS_STATUS_IOUT:
-               mfg_status = pmbus_read_word_data(client, 0,
-                                                 PMBUS_STATUS_MFR_SPECIFIC);
-               if (mfg_status < 0)
-                       return mfg_status;
-               if (mfg_status & MAX34440_STATUS_OC_WARN)
-                       ret |= PB_IOUT_OC_WARNING;
-               if (mfg_status & MAX34440_STATUS_OC_FAULT)
-                       ret |= PB_IOUT_OC_FAULT;
-               break;
-       case PMBUS_STATUS_TEMPERATURE:
-               mfg_status = pmbus_read_word_data(client, 0,
-                                                 PMBUS_STATUS_MFR_SPECIFIC);
-               if (mfg_status < 0)
-                       return mfg_status;
-               if (mfg_status & MAX34440_STATUS_OT_WARN)
-                       ret |= PB_TEMP_OT_WARNING;
-               if (mfg_status & MAX34440_STATUS_OT_FAULT)
-                       ret |= PB_TEMP_OT_FAULT;
-               break;
-       default:
-               ret = -ENODATA;
-               break;
-       }
-       return ret;
-}
-
-static struct pmbus_driver_info max34440_info[] = {
-       [max34440] = {
-               .pages = 14,
-               .direct[PSC_VOLTAGE_IN] = true,
-               .direct[PSC_VOLTAGE_OUT] = true,
-               .direct[PSC_TEMPERATURE] = true,
-               .direct[PSC_CURRENT_OUT] = true,
-               .m[PSC_VOLTAGE_IN] = 1,
-               .b[PSC_VOLTAGE_IN] = 0,
-               .R[PSC_VOLTAGE_IN] = 3,     /* R = 0 in datasheet reflects mV */
-               .m[PSC_VOLTAGE_OUT] = 1,
-               .b[PSC_VOLTAGE_OUT] = 0,
-               .R[PSC_VOLTAGE_OUT] = 3,    /* R = 0 in datasheet reflects mV */
-               .m[PSC_CURRENT_OUT] = 1,
-               .b[PSC_CURRENT_OUT] = 0,
-               .R[PSC_CURRENT_OUT] = 3,    /* R = 0 in datasheet reflects mA */
-               .m[PSC_TEMPERATURE] = 1,
-               .b[PSC_TEMPERATURE] = 0,
-               .R[PSC_TEMPERATURE] = 2,
-               .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .read_byte_data = max34440_read_byte_data,
-       },
-       [max34441] = {
-               .pages = 12,
-               .direct[PSC_VOLTAGE_IN] = true,
-               .direct[PSC_VOLTAGE_OUT] = true,
-               .direct[PSC_TEMPERATURE] = true,
-               .direct[PSC_CURRENT_OUT] = true,
-               .direct[PSC_FAN] = true,
-               .m[PSC_VOLTAGE_IN] = 1,
-               .b[PSC_VOLTAGE_IN] = 0,
-               .R[PSC_VOLTAGE_IN] = 3,
-               .m[PSC_VOLTAGE_OUT] = 1,
-               .b[PSC_VOLTAGE_OUT] = 0,
-               .R[PSC_VOLTAGE_OUT] = 3,
-               .m[PSC_CURRENT_OUT] = 1,
-               .b[PSC_CURRENT_OUT] = 0,
-               .R[PSC_CURRENT_OUT] = 3,
-               .m[PSC_TEMPERATURE] = 1,
-               .b[PSC_TEMPERATURE] = 0,
-               .R[PSC_TEMPERATURE] = 2,
-               .m[PSC_FAN] = 1,
-               .b[PSC_FAN] = 0,
-               .R[PSC_FAN] = 0,
-               .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
-               .func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
-               .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
-               .read_byte_data = max34440_read_byte_data,
-       },
-};
-
-static int max34440_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
-{
-       return pmbus_do_probe(client, id, &max34440_info[id->driver_data]);
-}
-
-static int max34440_remove(struct i2c_client *client)
-{
-       return pmbus_do_remove(client);
-}
-
-static const struct i2c_device_id max34440_id[] = {
-       {"max34440", max34440},
-       {"max34441", max34441},
-       {}
-};
-
-MODULE_DEVICE_TABLE(i2c, max34440_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver max34440_driver = {
-       .driver = {
-                  .name = "max34440",
-                  },
-       .probe = max34440_probe,
-       .remove = max34440_remove,
-       .id_table = max34440_id,
-};
-
-static int __init max34440_init(void)
-{
-       return i2c_add_driver(&max34440_driver);
-}
-
-static void __exit max34440_exit(void)
-{
-       i2c_del_driver(&max34440_driver);
-}
-
-MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441");
-MODULE_LICENSE("GPL");
-module_init(max34440_init);
-module_exit(max34440_exit);
diff --git a/drivers/hwmon/max8688.c b/drivers/hwmon/max8688.c
deleted file mode 100644 (file)
index 7fb93f4..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Hardware monitoring driver for Maxim MAX8688
- *
- * Copyright (c) 2011 Ericsson AB.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include "pmbus.h"
-
-#define MAX8688_MFG_STATUS             0xd8
-
-#define MAX8688_STATUS_OC_FAULT                (1 << 4)
-#define MAX8688_STATUS_OV_FAULT                (1 << 5)
-#define MAX8688_STATUS_OV_WARNING      (1 << 8)
-#define MAX8688_STATUS_UV_FAULT                (1 << 9)
-#define MAX8688_STATUS_UV_WARNING      (1 << 10)
-#define MAX8688_STATUS_UC_FAULT                (1 << 11)
-#define MAX8688_STATUS_OC_WARNING      (1 << 12)
-#define MAX8688_STATUS_OT_FAULT                (1 << 13)
-#define MAX8688_STATUS_OT_WARNING      (1 << 14)
-
-static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
-{
-       int ret = 0;
-       int mfg_status;
-
-       if (page)
-               return -EINVAL;
-
-       switch (reg) {
-       case PMBUS_STATUS_VOUT:
-               mfg_status = pmbus_read_word_data(client, 0,
-                                                 MAX8688_MFG_STATUS);
-               if (mfg_status < 0)
-                       return mfg_status;
-               if (mfg_status & MAX8688_STATUS_UV_WARNING)
-                       ret |= PB_VOLTAGE_UV_WARNING;
-               if (mfg_status & MAX8688_STATUS_UV_FAULT)
-                       ret |= PB_VOLTAGE_UV_FAULT;
-               if (mfg_status & MAX8688_STATUS_OV_WARNING)
-                       ret |= PB_VOLTAGE_OV_WARNING;
-               if (mfg_status & MAX8688_STATUS_OV_FAULT)
-                       ret |= PB_VOLTAGE_OV_FAULT;
-               break;
-       case PMBUS_STATUS_IOUT:
-               mfg_status = pmbus_read_word_data(client, 0,
-                                                 MAX8688_MFG_STATUS);
-               if (mfg_status < 0)
-                       return mfg_status;
-               if (mfg_status & MAX8688_STATUS_UC_FAULT)
-                       ret |= PB_IOUT_UC_FAULT;
-               if (mfg_status & MAX8688_STATUS_OC_WARNING)
-                       ret |= PB_IOUT_OC_WARNING;
-               if (mfg_status & MAX8688_STATUS_OC_FAULT)
-                       ret |= PB_IOUT_OC_FAULT;
-               break;
-       case PMBUS_STATUS_TEMPERATURE:
-               mfg_status = pmbus_read_word_data(client, 0,
-                                                 MAX8688_MFG_STATUS);
-               if (mfg_status < 0)
-                       return mfg_status;
-               if (mfg_status & MAX8688_STATUS_OT_WARNING)
-                       ret |= PB_TEMP_OT_WARNING;
-               if (mfg_status & MAX8688_STATUS_OT_FAULT)
-                       ret |= PB_TEMP_OT_FAULT;
-               break;
-       default:
-               ret = -ENODATA;
-               break;
-       }
-       return ret;
-}
-
-static struct pmbus_driver_info max8688_info = {
-       .pages = 1,
-       .direct[PSC_VOLTAGE_IN] = true,
-       .direct[PSC_VOLTAGE_OUT] = true,
-       .direct[PSC_TEMPERATURE] = true,
-       .direct[PSC_CURRENT_OUT] = true,
-       .m[PSC_VOLTAGE_IN] = 19995,
-       .b[PSC_VOLTAGE_IN] = 0,
-       .R[PSC_VOLTAGE_IN] = -1,
-       .m[PSC_VOLTAGE_OUT] = 19995,
-       .b[PSC_VOLTAGE_OUT] = 0,
-       .R[PSC_VOLTAGE_OUT] = -1,
-       .m[PSC_CURRENT_OUT] = 23109,
-       .b[PSC_CURRENT_OUT] = 0,
-       .R[PSC_CURRENT_OUT] = -2,
-       .m[PSC_TEMPERATURE] = -7612,
-       .b[PSC_TEMPERATURE] = 335,
-       .R[PSC_TEMPERATURE] = -3,
-       .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP
-               | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
-               | PMBUS_HAVE_STATUS_TEMP,
-       .read_byte_data = max8688_read_byte_data,
-};
-
-static int max8688_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
-{
-       return pmbus_do_probe(client, id, &max8688_info);
-}
-
-static int max8688_remove(struct i2c_client *client)
-{
-       return pmbus_do_remove(client);
-}
-
-static const struct i2c_device_id max8688_id[] = {
-       {"max8688", 0},
-       { }
-};
-
-MODULE_DEVICE_TABLE(i2c, max8688_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver max8688_driver = {
-       .driver = {
-                  .name = "max8688",
-                  },
-       .probe = max8688_probe,
-       .remove = max8688_remove,
-       .id_table = max8688_id,
-};
-
-static int __init max8688_init(void)
-{
-       return i2c_add_driver(&max8688_driver);
-}
-
-static void __exit max8688_exit(void)
-{
-       i2c_del_driver(&max8688_driver);
-}
-
-MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688");
-MODULE_LICENSE("GPL");
-module_init(max8688_init);
-module_exit(max8688_exit);
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
new file mode 100644 (file)
index 0000000..d7926f4
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * ntc_thermistor.c - NTC Thermistors
+ *
+ *  Copyright (C) 2010 Samsung Electronics
+ *  MyungJoo Ham <myungjoo.ham@samsung.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/slab.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/math64.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
+#include <linux/platform_data/ntc_thermistor.h>
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+struct ntc_compensation {
+       int             temp_C;
+       unsigned int    ohm;
+};
+
+/*
+ * A compensation table should be sorted by the values of .ohm
+ * in descending order.
+ * The following compensation tables are from the specification of Murata NTC
+ * Thermistors Datasheet
+ */
+const struct ntc_compensation ncpXXwb473[] = {
+       { .temp_C       = -40, .ohm     = 1747920 },
+       { .temp_C       = -35, .ohm     = 1245428 },
+       { .temp_C       = -30, .ohm     = 898485 },
+       { .temp_C       = -25, .ohm     = 655802 },
+       { .temp_C       = -20, .ohm     = 483954 },
+       { .temp_C       = -15, .ohm     = 360850 },
+       { .temp_C       = -10, .ohm     = 271697 },
+       { .temp_C       = -5, .ohm      = 206463 },
+       { .temp_C       = 0, .ohm       = 158214 },
+       { .temp_C       = 5, .ohm       = 122259 },
+       { .temp_C       = 10, .ohm      = 95227 },
+       { .temp_C       = 15, .ohm      = 74730 },
+       { .temp_C       = 20, .ohm      = 59065 },
+       { .temp_C       = 25, .ohm      = 47000 },
+       { .temp_C       = 30, .ohm      = 37643 },
+       { .temp_C       = 35, .ohm      = 30334 },
+       { .temp_C       = 40, .ohm      = 24591 },
+       { .temp_C       = 45, .ohm      = 20048 },
+       { .temp_C       = 50, .ohm      = 16433 },
+       { .temp_C       = 55, .ohm      = 13539 },
+       { .temp_C       = 60, .ohm      = 11209 },
+       { .temp_C       = 65, .ohm      = 9328 },
+       { .temp_C       = 70, .ohm      = 7798 },
+       { .temp_C       = 75, .ohm      = 6544 },
+       { .temp_C       = 80, .ohm      = 5518 },
+       { .temp_C       = 85, .ohm      = 4674 },
+       { .temp_C       = 90, .ohm      = 3972 },
+       { .temp_C       = 95, .ohm      = 3388 },
+       { .temp_C       = 100, .ohm     = 2902 },
+       { .temp_C       = 105, .ohm     = 2494 },
+       { .temp_C       = 110, .ohm     = 2150 },
+       { .temp_C       = 115, .ohm     = 1860 },
+       { .temp_C       = 120, .ohm     = 1615 },
+       { .temp_C       = 125, .ohm     = 1406 },
+};
+const struct ntc_compensation ncpXXwl333[] = {
+       { .temp_C       = -40, .ohm     = 1610154 },
+       { .temp_C       = -35, .ohm     = 1130850 },
+       { .temp_C       = -30, .ohm     = 802609 },
+       { .temp_C       = -25, .ohm     = 575385 },
+       { .temp_C       = -20, .ohm     = 416464 },
+       { .temp_C       = -15, .ohm     = 304219 },
+       { .temp_C       = -10, .ohm     = 224193 },
+       { .temp_C       = -5, .ohm      = 166623 },
+       { .temp_C       = 0, .ohm       = 124850 },
+       { .temp_C       = 5, .ohm       = 94287 },
+       { .temp_C       = 10, .ohm      = 71747 },
+       { .temp_C       = 15, .ohm      = 54996 },
+       { .temp_C       = 20, .ohm      = 42455 },
+       { .temp_C       = 25, .ohm      = 33000 },
+       { .temp_C       = 30, .ohm      = 25822 },
+       { .temp_C       = 35, .ohm      = 20335 },
+       { .temp_C       = 40, .ohm      = 16115 },
+       { .temp_C       = 45, .ohm      = 12849 },
+       { .temp_C       = 50, .ohm      = 10306 },
+       { .temp_C       = 55, .ohm      = 8314 },
+       { .temp_C       = 60, .ohm      = 6746 },
+       { .temp_C       = 65, .ohm      = 5503 },
+       { .temp_C       = 70, .ohm      = 4513 },
+       { .temp_C       = 75, .ohm      = 3721 },
+       { .temp_C       = 80, .ohm      = 3084 },
+       { .temp_C       = 85, .ohm      = 2569 },
+       { .temp_C       = 90, .ohm      = 2151 },
+       { .temp_C       = 95, .ohm      = 1809 },
+       { .temp_C       = 100, .ohm     = 1529 },
+       { .temp_C       = 105, .ohm     = 1299 },
+       { .temp_C       = 110, .ohm     = 1108 },
+       { .temp_C       = 115, .ohm     = 949 },
+       { .temp_C       = 120, .ohm     = 817 },
+       { .temp_C       = 125, .ohm     = 707 },
+};
+
+struct ntc_data {
+       struct device *hwmon_dev;
+       struct ntc_thermistor_platform_data *pdata;
+       const struct ntc_compensation *comp;
+       struct device *dev;
+       int n_comp;
+       char name[PLATFORM_NAME_SIZE];
+};
+
+static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
+{
+       if (divisor == 0 && dividend == 0)
+               return 0;
+       if (divisor == 0)
+               return UINT_MAX;
+       return div64_u64(dividend, divisor);
+}
+
+static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
+               unsigned int uV)
+{
+       struct ntc_thermistor_platform_data *pdata = data->pdata;
+       u64 mV = uV / 1000;
+       u64 pmV = pdata->pullup_uV / 1000;
+       u64 N, puO, pdO;
+       puO = pdata->pullup_ohm;
+       pdO = pdata->pulldown_ohm;
+
+       if (mV == 0) {
+               if (pdata->connect == NTC_CONNECTED_POSITIVE)
+                       return UINT_MAX;
+               return 0;
+       }
+       if (mV >= pmV)
+               return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
+                       0 : UINT_MAX;
+
+       if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
+               N = div64_u64_safe(pdO * (pmV - mV), mV);
+       else if (pdata->connect == NTC_CONNECTED_GROUND && pdO == 0)
+               N = div64_u64_safe(puO * mV, pmV - mV);
+       else if (pdata->connect == NTC_CONNECTED_POSITIVE)
+               N = div64_u64_safe(pdO * puO * (pmV - mV),
+                               puO * mV - pdO * (pmV - mV));
+       else
+               N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
+
+       return (unsigned int) N;
+}
+
+static int lookup_comp(struct ntc_data *data,
+               unsigned int ohm, int *i_low, int *i_high)
+{
+       int start, end, mid = -1;
+
+       /* Do a binary search on compensation table */
+       start = 0;
+       end = data->n_comp;
+
+       while (end > start) {
+               mid = start + (end - start) / 2;
+               if (data->comp[mid].ohm < ohm)
+                       end = mid;
+               else if (data->comp[mid].ohm > ohm)
+                       start = mid + 1;
+               else
+                       break;
+       }
+
+       if (mid == 0) {
+               if (data->comp[mid].ohm > ohm) {
+                       *i_high = mid;
+                       *i_low = mid + 1;
+                       return 0;
+               } else {
+                       *i_low = mid;
+                       *i_high = -1;
+                       return -EINVAL;
+               }
+       }
+       if (mid == (data->n_comp - 1)) {
+               if (data->comp[mid].ohm <= ohm) {
+                       *i_low = mid;
+                       *i_high = mid - 1;
+                       return 0;
+               } else {
+                       *i_low = -1;
+                       *i_high = mid;
+                       return -EINVAL;
+               }
+       }
+
+       if (data->comp[mid].ohm <= ohm) {
+               *i_low = mid;
+               *i_high = mid - 1;
+       }
+       if (data->comp[mid].ohm > ohm) {
+               *i_low = mid + 1;
+               *i_high = mid;
+       }
+
+       return 0;
+}
+
+static int get_temp_mC(struct ntc_data *data, unsigned int ohm, int *temp)
+{
+       int low, high;
+       int ret;
+
+       ret = lookup_comp(data, ohm, &low, &high);
+       if (ret) {
+               /* Unable to use linear approximation */
+               if (low != -1)
+                       *temp = data->comp[low].temp_C * 1000;
+               else if (high != -1)
+                       *temp = data->comp[high].temp_C * 1000;
+               else
+                       return ret;
+       } else {
+               *temp = data->comp[low].temp_C * 1000 +
+                       ((data->comp[high].temp_C - data->comp[low].temp_C) *
+                        1000 * ((int)ohm - (int)data->comp[low].ohm)) /
+                       ((int)data->comp[high].ohm - (int)data->comp[low].ohm);
+       }
+
+       return 0;
+}
+
+static int ntc_thermistor_read(struct ntc_data *data, int *temp)
+{
+       int ret;
+       int read_ohm, read_uV;
+       unsigned int ohm = 0;
+
+       if (data->pdata->read_ohm) {
+               read_ohm = data->pdata->read_ohm();
+               if (read_ohm < 0)
+                       return read_ohm;
+               ohm = (unsigned int)read_ohm;
+       }
+
+       if (data->pdata->read_uV) {
+               read_uV = data->pdata->read_uV();
+               if (read_uV < 0)
+                       return read_uV;
+               ohm = get_ohm_of_thermistor(data, (unsigned int)read_uV);
+       }
+
+       ret = get_temp_mC(data, ohm, temp);
+       if (ret) {
+               dev_dbg(data->dev, "Sensor reading function not available.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static ssize_t ntc_show_name(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct ntc_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", data->name);
+}
+
+static ssize_t ntc_show_type(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "4\n");
+}
+
+static ssize_t ntc_show_temp(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct ntc_data *data = dev_get_drvdata(dev);
+       int temp, ret;
+
+       ret = ntc_thermistor_read(data, &temp);
+       if (ret)
+               return ret;
+       return sprintf(buf, "%d\n", temp);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ntc_show_temp, NULL, 0);
+static DEVICE_ATTR(name, S_IRUGO, ntc_show_name, NULL);
+
+static struct attribute *ntc_attributes[] = {
+       &dev_attr_name.attr,
+       &sensor_dev_attr_temp1_type.dev_attr.attr,
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ntc_attr_group = {
+       .attrs = ntc_attributes,
+};
+
+static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
+{
+       struct ntc_data *data;
+       struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data;
+       int ret = 0;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform init data supplied.\n");
+               return -ENODEV;
+       }
+
+       /* Either one of the two is required. */
+       if (!pdata->read_uV && !pdata->read_ohm) {
+               dev_err(&pdev->dev, "Both read_uV and read_ohm missing."
+                               "Need either one of the two.\n");
+               return -EINVAL;
+       }
+
+       if (pdata->read_uV && pdata->read_ohm) {
+               dev_warn(&pdev->dev, "Only one of read_uV and read_ohm "
+                               "is needed; ignoring read_uV.\n");
+               pdata->read_uV = NULL;
+       }
+
+       if (pdata->read_uV && (pdata->pullup_uV == 0 ||
+                               (pdata->pullup_ohm == 0 && pdata->connect ==
+                                NTC_CONNECTED_GROUND) ||
+                               (pdata->pulldown_ohm == 0 && pdata->connect ==
+                                NTC_CONNECTED_POSITIVE) ||
+                               (pdata->connect != NTC_CONNECTED_POSITIVE &&
+                                pdata->connect != NTC_CONNECTED_GROUND))) {
+               dev_err(&pdev->dev, "Required data to use read_uV not "
+                               "supplied.\n");
+               return -EINVAL;
+       }
+
+       data = kzalloc(sizeof(struct ntc_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->dev = &pdev->dev;
+       data->pdata = pdata;
+       strncpy(data->name, pdev->id_entry->name, PLATFORM_NAME_SIZE);
+
+       switch (pdev->id_entry->driver_data) {
+       case TYPE_NCPXXWB473:
+               data->comp = ncpXXwb473;
+               data->n_comp = ARRAY_SIZE(ncpXXwb473);
+               break;
+       case TYPE_NCPXXWL333:
+               data->comp = ncpXXwl333;
+               data->n_comp = ARRAY_SIZE(ncpXXwl333);
+               break;
+       default:
+               dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
+                               pdev->id_entry->driver_data,
+                               pdev->id_entry->name);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, data);
+
+       ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group);
+       if (ret) {
+               dev_err(data->dev, "unable to create sysfs files\n");
+               goto err;
+       }
+
+       data->hwmon_dev = hwmon_device_register(data->dev);
+       if (IS_ERR_OR_NULL(data->hwmon_dev)) {
+               dev_err(data->dev, "unable to register as hwmon device.\n");
+               ret = -EINVAL;
+               goto err_after_sysfs;
+       }
+
+       dev_info(&pdev->dev, "Thermistor %s:%d (type: %s/%lu) successfully probed.\n",
+                       pdev->name, pdev->id, pdev->id_entry->name,
+                       pdev->id_entry->driver_data);
+       return 0;
+err_after_sysfs:
+       sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
+err:
+       kfree(data);
+       return ret;
+}
+
+static int __devexit ntc_thermistor_remove(struct platform_device *pdev)
+{
+       struct ntc_data *data = platform_get_drvdata(pdev);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(data);
+
+       return 0;
+}
+
+static const struct platform_device_id ntc_thermistor_id[] = {
+       { "ncp15wb473", TYPE_NCPXXWB473 },
+       { "ncp18wb473", TYPE_NCPXXWB473 },
+       { "ncp21wb473", TYPE_NCPXXWB473 },
+       { "ncp03wb473", TYPE_NCPXXWB473 },
+       { "ncp15wl333", TYPE_NCPXXWL333 },
+       { },
+};
+
+static struct platform_driver ntc_thermistor_driver = {
+       .driver = {
+               .name = "ntc-thermistor",
+               .owner = THIS_MODULE,
+       },
+       .probe = ntc_thermistor_probe,
+       .remove = __devexit_p(ntc_thermistor_remove),
+       .id_table = ntc_thermistor_id,
+};
+
+static int __init ntc_thermistor_init(void)
+{
+       return platform_driver_register(&ntc_thermistor_driver);
+}
+
+module_init(ntc_thermistor_init);
+
+static void __exit ntc_thermistor_cleanup(void)
+{
+       platform_driver_unregister(&ntc_thermistor_driver);
+}
+
+module_exit(ntc_thermistor_cleanup);
+
+MODULE_DESCRIPTION("NTC Thermistor Driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ntc-thermistor");
diff --git a/drivers/hwmon/pmbus.c b/drivers/hwmon/pmbus.c
deleted file mode 100644 (file)
index 9b1f0c3..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Hardware monitoring driver for PMBus devices
- *
- * Copyright (c) 2010, 2011 Ericsson AB.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/i2c.h>
-#include "pmbus.h"
-
-/*
- * Find sensor groups and status registers on each page.
- */
-static void pmbus_find_sensor_groups(struct i2c_client *client,
-                                    struct pmbus_driver_info *info)
-{
-       int page;
-
-       /* Sensors detected on page 0 only */
-       if (pmbus_check_word_register(client, 0, PMBUS_READ_VIN))
-               info->func[0] |= PMBUS_HAVE_VIN;
-       if (pmbus_check_word_register(client, 0, PMBUS_READ_VCAP))
-               info->func[0] |= PMBUS_HAVE_VCAP;
-       if (pmbus_check_word_register(client, 0, PMBUS_READ_IIN))
-               info->func[0] |= PMBUS_HAVE_IIN;
-       if (pmbus_check_word_register(client, 0, PMBUS_READ_PIN))
-               info->func[0] |= PMBUS_HAVE_PIN;
-       if (info->func[0]
-           && pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT))
-               info->func[0] |= PMBUS_HAVE_STATUS_INPUT;
-       if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_12) &&
-           pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) {
-               info->func[0] |= PMBUS_HAVE_FAN12;
-               if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12))
-                       info->func[0] |= PMBUS_HAVE_STATUS_FAN12;
-       }
-       if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) &&
-           pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) {
-               info->func[0] |= PMBUS_HAVE_FAN34;
-               if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34))
-                       info->func[0] |= PMBUS_HAVE_STATUS_FAN34;
-       }
-       if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1))
-               info->func[0] |= PMBUS_HAVE_TEMP;
-       if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2))
-               info->func[0] |= PMBUS_HAVE_TEMP2;
-       if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3))
-               info->func[0] |= PMBUS_HAVE_TEMP3;
-       if (info->func[0] & (PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2
-                            | PMBUS_HAVE_TEMP3)
-           && pmbus_check_byte_register(client, 0,
-                                        PMBUS_STATUS_TEMPERATURE))
-                       info->func[0] |= PMBUS_HAVE_STATUS_TEMP;
-
-       /* Sensors detected on all pages */
-       for (page = 0; page < info->pages; page++) {
-               if (pmbus_check_word_register(client, page, PMBUS_READ_VOUT)) {
-                       info->func[page] |= PMBUS_HAVE_VOUT;
-                       if (pmbus_check_byte_register(client, page,
-                                                     PMBUS_STATUS_VOUT))
-                               info->func[page] |= PMBUS_HAVE_STATUS_VOUT;
-               }
-               if (pmbus_check_word_register(client, page, PMBUS_READ_IOUT)) {
-                       info->func[page] |= PMBUS_HAVE_IOUT;
-                       if (pmbus_check_byte_register(client, 0,
-                                                     PMBUS_STATUS_IOUT))
-                               info->func[page] |= PMBUS_HAVE_STATUS_IOUT;
-               }
-               if (pmbus_check_word_register(client, page, PMBUS_READ_POUT))
-                       info->func[page] |= PMBUS_HAVE_POUT;
-       }
-}
-
-/*
- * Identify chip parameters.
- */
-static int pmbus_identify(struct i2c_client *client,
-                         struct pmbus_driver_info *info)
-{
-       if (!info->pages) {
-               /*
-                * Check if the PAGE command is supported. If it is,
-                * keep setting the page number until it fails or until the
-                * maximum number of pages has been reached. Assume that
-                * this is the number of pages supported by the chip.
-                */
-               if (pmbus_check_byte_register(client, 0, PMBUS_PAGE)) {
-                       int page;
-
-                       for (page = 1; page < PMBUS_PAGES; page++) {
-                               if (pmbus_set_page(client, page) < 0)
-                                       break;
-                       }
-                       pmbus_set_page(client, 0);
-                       info->pages = page;
-               } else {
-                       info->pages = 1;
-               }
-       }
-
-       /*
-        * We should check if the COEFFICIENTS register is supported.
-        * If it is, and the chip is configured for direct mode, we can read
-        * the coefficients from the chip, one set per group of sensor
-        * registers.
-        *
-        * To do this, we will need access to a chip which actually supports the
-        * COEFFICIENTS command, since the command is too complex to implement
-        * without testing it.
-        */
-
-       /* Try to find sensor groups  */
-       pmbus_find_sensor_groups(client, info);
-
-       return 0;
-}
-
-static int pmbus_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
-{
-       struct pmbus_driver_info *info;
-       int ret;
-
-       info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       info->pages = id->driver_data;
-       info->identify = pmbus_identify;
-
-       ret = pmbus_do_probe(client, id, info);
-       if (ret < 0)
-               goto out;
-       return 0;
-
-out:
-       kfree(info);
-       return ret;
-}
-
-static int pmbus_remove(struct i2c_client *client)
-{
-       int ret;
-       const struct pmbus_driver_info *info;
-
-       info = pmbus_get_driver_info(client);
-       ret = pmbus_do_remove(client);
-       kfree(info);
-       return ret;
-}
-
-/*
- * Use driver_data to set the number of pages supported by the chip.
- */
-static const struct i2c_device_id pmbus_id[] = {
-       {"bmr450", 1},
-       {"bmr451", 1},
-       {"bmr453", 1},
-       {"bmr454", 1},
-       {"ltc2978", 8},
-       {"pmbus", 0},
-       {}
-};
-
-MODULE_DEVICE_TABLE(i2c, pmbus_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver pmbus_driver = {
-       .driver = {
-                  .name = "pmbus",
-                  },
-       .probe = pmbus_probe,
-       .remove = pmbus_remove,
-       .id_table = pmbus_id,
-};
-
-static int __init pmbus_init(void)
-{
-       return i2c_add_driver(&pmbus_driver);
-}
-
-static void __exit pmbus_exit(void)
-{
-       i2c_del_driver(&pmbus_driver);
-}
-
-MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("Generic PMBus driver");
-MODULE_LICENSE("GPL");
-module_init(pmbus_init);
-module_exit(pmbus_exit);
diff --git a/drivers/hwmon/pmbus.h b/drivers/hwmon/pmbus.h
deleted file mode 100644 (file)
index 50647ab..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * pmbus.h - Common defines and structures for PMBus devices
- *
- * Copyright (c) 2010, 2011 Ericsson AB.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (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 PMBUS_H
-#define PMBUS_H
-
-/*
- * Registers
- */
-#define PMBUS_PAGE                     0x00
-#define PMBUS_OPERATION                        0x01
-#define PMBUS_ON_OFF_CONFIG            0x02
-#define PMBUS_CLEAR_FAULTS             0x03
-#define PMBUS_PHASE                    0x04
-
-#define PMBUS_CAPABILITY               0x19
-#define PMBUS_QUERY                    0x1A
-
-#define PMBUS_VOUT_MODE                        0x20
-#define PMBUS_VOUT_COMMAND             0x21
-#define PMBUS_VOUT_TRIM                        0x22
-#define PMBUS_VOUT_CAL_OFFSET          0x23
-#define PMBUS_VOUT_MAX                 0x24
-#define PMBUS_VOUT_MARGIN_HIGH         0x25
-#define PMBUS_VOUT_MARGIN_LOW          0x26
-#define PMBUS_VOUT_TRANSITION_RATE     0x27
-#define PMBUS_VOUT_DROOP               0x28
-#define PMBUS_VOUT_SCALE_LOOP          0x29
-#define PMBUS_VOUT_SCALE_MONITOR       0x2A
-
-#define PMBUS_COEFFICIENTS             0x30
-#define PMBUS_POUT_MAX                 0x31
-
-#define PMBUS_FAN_CONFIG_12            0x3A
-#define PMBUS_FAN_COMMAND_1            0x3B
-#define PMBUS_FAN_COMMAND_2            0x3C
-#define PMBUS_FAN_CONFIG_34            0x3D
-#define PMBUS_FAN_COMMAND_3            0x3E
-#define PMBUS_FAN_COMMAND_4            0x3F
-
-#define PMBUS_VOUT_OV_FAULT_LIMIT      0x40
-#define PMBUS_VOUT_OV_FAULT_RESPONSE   0x41
-#define PMBUS_VOUT_OV_WARN_LIMIT       0x42
-#define PMBUS_VOUT_UV_WARN_LIMIT       0x43
-#define PMBUS_VOUT_UV_FAULT_LIMIT      0x44
-#define PMBUS_VOUT_UV_FAULT_RESPONSE   0x45
-#define PMBUS_IOUT_OC_FAULT_LIMIT      0x46
-#define PMBUS_IOUT_OC_FAULT_RESPONSE   0x47
-#define PMBUS_IOUT_OC_LV_FAULT_LIMIT   0x48
-#define PMBUS_IOUT_OC_LV_FAULT_RESPONSE        0x49
-#define PMBUS_IOUT_OC_WARN_LIMIT       0x4A
-#define PMBUS_IOUT_UC_FAULT_LIMIT      0x4B
-#define PMBUS_IOUT_UC_FAULT_RESPONSE   0x4C
-
-#define PMBUS_OT_FAULT_LIMIT           0x4F
-#define PMBUS_OT_FAULT_RESPONSE                0x50
-#define PMBUS_OT_WARN_LIMIT            0x51
-#define PMBUS_UT_WARN_LIMIT            0x52
-#define PMBUS_UT_FAULT_LIMIT           0x53
-#define PMBUS_UT_FAULT_RESPONSE                0x54
-#define PMBUS_VIN_OV_FAULT_LIMIT       0x55
-#define PMBUS_VIN_OV_FAULT_RESPONSE    0x56
-#define PMBUS_VIN_OV_WARN_LIMIT                0x57
-#define PMBUS_VIN_UV_WARN_LIMIT                0x58
-#define PMBUS_VIN_UV_FAULT_LIMIT       0x59
-
-#define PMBUS_IIN_OC_FAULT_LIMIT       0x5B
-#define PMBUS_IIN_OC_WARN_LIMIT                0x5D
-
-#define PMBUS_POUT_OP_FAULT_LIMIT      0x68
-#define PMBUS_POUT_OP_WARN_LIMIT       0x6A
-#define PMBUS_PIN_OP_WARN_LIMIT                0x6B
-
-#define PMBUS_STATUS_BYTE              0x78
-#define PMBUS_STATUS_WORD              0x79
-#define PMBUS_STATUS_VOUT              0x7A
-#define PMBUS_STATUS_IOUT              0x7B
-#define PMBUS_STATUS_INPUT             0x7C
-#define PMBUS_STATUS_TEMPERATURE       0x7D
-#define PMBUS_STATUS_CML               0x7E
-#define PMBUS_STATUS_OTHER             0x7F
-#define PMBUS_STATUS_MFR_SPECIFIC      0x80
-#define PMBUS_STATUS_FAN_12            0x81
-#define PMBUS_STATUS_FAN_34            0x82
-
-#define PMBUS_READ_VIN                 0x88
-#define PMBUS_READ_IIN                 0x89
-#define PMBUS_READ_VCAP                        0x8A
-#define PMBUS_READ_VOUT                        0x8B
-#define PMBUS_READ_IOUT                        0x8C
-#define PMBUS_READ_TEMPERATURE_1       0x8D
-#define PMBUS_READ_TEMPERATURE_2       0x8E
-#define PMBUS_READ_TEMPERATURE_3       0x8F
-#define PMBUS_READ_FAN_SPEED_1         0x90
-#define PMBUS_READ_FAN_SPEED_2         0x91
-#define PMBUS_READ_FAN_SPEED_3         0x92
-#define PMBUS_READ_FAN_SPEED_4         0x93
-#define PMBUS_READ_DUTY_CYCLE          0x94
-#define PMBUS_READ_FREQUENCY           0x95
-#define PMBUS_READ_POUT                        0x96
-#define PMBUS_READ_PIN                 0x97
-
-#define PMBUS_REVISION                 0x98
-#define PMBUS_MFR_ID                   0x99
-#define PMBUS_MFR_MODEL                        0x9A
-#define PMBUS_MFR_REVISION             0x9B
-#define PMBUS_MFR_LOCATION             0x9C
-#define PMBUS_MFR_DATE                 0x9D
-#define PMBUS_MFR_SERIAL               0x9E
-
-/*
- * CAPABILITY
- */
-#define PB_CAPABILITY_SMBALERT         (1<<4)
-#define PB_CAPABILITY_ERROR_CHECK      (1<<7)
-
-/*
- * VOUT_MODE
- */
-#define PB_VOUT_MODE_MODE_MASK         0xe0
-#define PB_VOUT_MODE_PARAM_MASK                0x1f
-
-#define PB_VOUT_MODE_LINEAR            0x00
-#define PB_VOUT_MODE_VID               0x20
-#define PB_VOUT_MODE_DIRECT            0x40
-
-/*
- * Fan configuration
- */
-#define PB_FAN_2_PULSE_MASK            ((1 << 0) | (1 << 1))
-#define PB_FAN_2_RPM                   (1 << 2)
-#define PB_FAN_2_INSTALLED             (1 << 3)
-#define PB_FAN_1_PULSE_MASK            ((1 << 4) | (1 << 5))
-#define PB_FAN_1_RPM                   (1 << 6)
-#define PB_FAN_1_INSTALLED             (1 << 7)
-
-/*
- * STATUS_BYTE, STATUS_WORD (lower)
- */
-#define PB_STATUS_NONE_ABOVE           (1<<0)
-#define PB_STATUS_CML                  (1<<1)
-#define PB_STATUS_TEMPERATURE          (1<<2)
-#define PB_STATUS_VIN_UV               (1<<3)
-#define PB_STATUS_IOUT_OC              (1<<4)
-#define PB_STATUS_VOUT_OV              (1<<5)
-#define PB_STATUS_OFF                  (1<<6)
-#define PB_STATUS_BUSY                 (1<<7)
-
-/*
- * STATUS_WORD (upper)
- */
-#define PB_STATUS_UNKNOWN              (1<<8)
-#define PB_STATUS_OTHER                        (1<<9)
-#define PB_STATUS_FANS                 (1<<10)
-#define PB_STATUS_POWER_GOOD_N         (1<<11)
-#define PB_STATUS_WORD_MFR             (1<<12)
-#define PB_STATUS_INPUT                        (1<<13)
-#define PB_STATUS_IOUT_POUT            (1<<14)
-#define PB_STATUS_VOUT                 (1<<15)
-
-/*
- * STATUS_IOUT
- */
-#define PB_POUT_OP_WARNING             (1<<0)
-#define PB_POUT_OP_FAULT               (1<<1)
-#define PB_POWER_LIMITING              (1<<2)
-#define PB_CURRENT_SHARE_FAULT         (1<<3)
-#define PB_IOUT_UC_FAULT               (1<<4)
-#define PB_IOUT_OC_WARNING             (1<<5)
-#define PB_IOUT_OC_LV_FAULT            (1<<6)
-#define PB_IOUT_OC_FAULT               (1<<7)
-
-/*
- * STATUS_VOUT, STATUS_INPUT
- */
-#define PB_VOLTAGE_UV_FAULT            (1<<4)
-#define PB_VOLTAGE_UV_WARNING          (1<<5)
-#define PB_VOLTAGE_OV_WARNING          (1<<6)
-#define PB_VOLTAGE_OV_FAULT            (1<<7)
-
-/*
- * STATUS_INPUT
- */
-#define PB_PIN_OP_WARNING              (1<<0)
-#define PB_IIN_OC_WARNING              (1<<1)
-#define PB_IIN_OC_FAULT                        (1<<2)
-
-/*
- * STATUS_TEMPERATURE
- */
-#define PB_TEMP_UT_FAULT               (1<<4)
-#define PB_TEMP_UT_WARNING             (1<<5)
-#define PB_TEMP_OT_WARNING             (1<<6)
-#define PB_TEMP_OT_FAULT               (1<<7)
-
-/*
- * STATUS_FAN
- */
-#define PB_FAN_AIRFLOW_WARNING         (1<<0)
-#define PB_FAN_AIRFLOW_FAULT           (1<<1)
-#define PB_FAN_FAN2_SPEED_OVERRIDE     (1<<2)
-#define PB_FAN_FAN1_SPEED_OVERRIDE     (1<<3)
-#define PB_FAN_FAN2_WARNING            (1<<4)
-#define PB_FAN_FAN1_WARNING            (1<<5)
-#define PB_FAN_FAN2_FAULT              (1<<6)
-#define PB_FAN_FAN1_FAULT              (1<<7)
-
-/*
- * CML_FAULT_STATUS
- */
-#define PB_CML_FAULT_OTHER_MEM_LOGIC   (1<<0)
-#define PB_CML_FAULT_OTHER_COMM                (1<<1)
-#define PB_CML_FAULT_PROCESSOR         (1<<3)
-#define PB_CML_FAULT_MEMORY            (1<<4)
-#define PB_CML_FAULT_PACKET_ERROR      (1<<5)
-#define PB_CML_FAULT_INVALID_DATA      (1<<6)
-#define PB_CML_FAULT_INVALID_COMMAND   (1<<7)
-
-enum pmbus_sensor_classes {
-       PSC_VOLTAGE_IN = 0,
-       PSC_VOLTAGE_OUT,
-       PSC_CURRENT_IN,
-       PSC_CURRENT_OUT,
-       PSC_POWER,
-       PSC_TEMPERATURE,
-       PSC_FAN,
-       PSC_NUM_CLASSES         /* Number of power sensor classes */
-};
-
-#define PMBUS_PAGES    32      /* Per PMBus specification */
-
-/* Functionality bit mask */
-#define PMBUS_HAVE_VIN         (1 << 0)
-#define PMBUS_HAVE_VCAP                (1 << 1)
-#define PMBUS_HAVE_VOUT                (1 << 2)
-#define PMBUS_HAVE_IIN         (1 << 3)
-#define PMBUS_HAVE_IOUT                (1 << 4)
-#define PMBUS_HAVE_PIN         (1 << 5)
-#define PMBUS_HAVE_POUT                (1 << 6)
-#define PMBUS_HAVE_FAN12       (1 << 7)
-#define PMBUS_HAVE_FAN34       (1 << 8)
-#define PMBUS_HAVE_TEMP                (1 << 9)
-#define PMBUS_HAVE_TEMP2       (1 << 10)
-#define PMBUS_HAVE_TEMP3       (1 << 11)
-#define PMBUS_HAVE_STATUS_VOUT (1 << 12)
-#define PMBUS_HAVE_STATUS_IOUT (1 << 13)
-#define PMBUS_HAVE_STATUS_INPUT        (1 << 14)
-#define PMBUS_HAVE_STATUS_TEMP (1 << 15)
-#define PMBUS_HAVE_STATUS_FAN12        (1 << 16)
-#define PMBUS_HAVE_STATUS_FAN34        (1 << 17)
-
-struct pmbus_driver_info {
-       int pages;              /* Total number of pages */
-       bool direct[PSC_NUM_CLASSES];
-                               /* true if device uses direct data format
-                                  for the given sensor class */
-       /*
-        * Support one set of coefficients for each sensor type
-        * Used for chips providing data in direct mode.
-        */
-       int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */
-       int b[PSC_NUM_CLASSES]; /* offset */
-       int R[PSC_NUM_CLASSES]; /* exponent */
-
-       u32 func[PMBUS_PAGES];  /* Functionality, per page */
-       /*
-        * The following functions map manufacturing specific register values
-        * to PMBus standard register values. Specify only if mapping is
-        * necessary.
-        */
-       int (*read_byte_data)(struct i2c_client *client, int page, int reg);
-       /*
-        * The identify function determines supported PMBus functionality.
-        * This function is only necessary if a chip driver supports multiple
-        * chips, and the chip functionality is not pre-determined.
-        */
-       int (*identify)(struct i2c_client *client,
-                       struct pmbus_driver_info *info);
-};
-
-/* Function declarations */
-
-int pmbus_set_page(struct i2c_client *client, u8 page);
-int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
-void pmbus_clear_faults(struct i2c_client *client);
-bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
-bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
-int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
-                  struct pmbus_driver_info *info);
-int pmbus_do_remove(struct i2c_client *client);
-const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client
-                                                     *client);
-
-#endif /* PMBUS_H */
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
new file mode 100644 (file)
index 0000000..c9237b9
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# PMBus chip drivers configuration
+#
+
+menuconfig PMBUS
+       tristate "PMBus support"
+       depends on I2C && EXPERIMENTAL
+       default n
+       help
+         Say yes here if you want to enable PMBus support.
+
+         This driver can also be built as a module. If so, the module will
+         be called pmbus_core.
+
+if PMBUS
+
+config SENSORS_PMBUS
+       tristate "Generic PMBus devices"
+       default y
+       help
+         If you say yes here you get hardware monitoring support for generic
+         PMBus devices, including but not limited to ADP4000, BMR450, BMR451,
+         BMR453, BMR454, LTC2978, NCP4200, and NCP4208.
+
+         This driver can also be built as a module. If so, the module will
+         be called pmbus.
+
+config SENSORS_ADM1275
+       tristate "Analog Devices ADM1275"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Analog
+         Devices ADM1275 Hot-Swap Controller and Digital Power Monitor.
+
+         This driver can also be built as a module. If so, the module will
+         be called adm1275.
+
+config SENSORS_LM25066
+       tristate "National Semiconductor LM25066 and compatibles"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for National
+         Semiconductor LM25066, LM5064, and LM5066.
+
+         This driver can also be built as a module. If so, the module will
+         be called lm25066.
+
+config SENSORS_MAX16064
+       tristate "Maxim MAX16064"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Maxim
+         MAX16064.
+
+         This driver can also be built as a module. If so, the module will
+         be called max16064.
+
+config SENSORS_MAX34440
+       tristate "Maxim MAX34440/MAX34441"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Maxim
+         MAX34440 and MAX34441.
+
+         This driver can also be built as a module. If so, the module will
+         be called max34440.
+
+config SENSORS_MAX8688
+       tristate "Maxim MAX8688"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for Maxim
+         MAX8688.
+
+         This driver can also be built as a module. If so, the module will
+         be called max8688.
+
+config SENSORS_UCD9000
+       tristate "TI UCD90120, UCD90124, UCD9090, UCD90910"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for TI
+         UCD90120, UCD90124, UCD9090, UCD90910 Sequencer and System Health
+         Controllers.
+
+         This driver can also be built as a module. If so, the module will
+         be called ucd9000.
+
+config SENSORS_UCD9200
+       tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248"
+       default n
+       help
+         If you say yes here you get hardware monitoring support for TI
+         UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
+         Digital PWM System Controllers.
+
+         This driver can also be built as a module. If so, the module will
+         be called ucd9200.
+
+endif # PMBUS
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
new file mode 100644 (file)
index 0000000..623eedb
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for PMBus chip drivers.
+#
+
+obj-$(CONFIG_PMBUS)            += pmbus_core.o
+obj-$(CONFIG_SENSORS_PMBUS)    += pmbus.o
+obj-$(CONFIG_SENSORS_ADM1275)  += adm1275.o
+obj-$(CONFIG_SENSORS_LM25066)  += lm25066.o
+obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
+obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
+obj-$(CONFIG_SENSORS_MAX8688)  += max8688.o
+obj-$(CONFIG_SENSORS_UCD9000)  += ucd9000.o
+obj-$(CONFIG_SENSORS_UCD9200)  += ucd9200.o
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c
new file mode 100644 (file)
index 0000000..c936e27
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller
+ * and Digital Power Monitor
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+#define ADM1275_PEAK_IOUT              0xd0
+#define ADM1275_PEAK_VIN               0xd1
+#define ADM1275_PEAK_VOUT              0xd2
+#define ADM1275_PMON_CONFIG            0xd4
+
+#define ADM1275_VIN_VOUT_SELECT                (1 << 6)
+#define ADM1275_VRANGE                 (1 << 5)
+
+static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       if (page)
+               return -EINVAL;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_IOUT_MAX:
+               ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
+               break;
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT);
+               break;
+       case PMBUS_VIRT_READ_VIN_MAX:
+               ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
+               break;
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+       case PMBUS_VIRT_RESET_VIN_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
+                                  u16 word)
+{
+       int ret;
+
+       if (page)
+               return -EINVAL;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+               ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+               ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0);
+               break;
+       case PMBUS_VIRT_RESET_VIN_HISTORY:
+               ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int adm1275_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       int config;
+       int ret;
+       struct pmbus_driver_info *info;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_READ_BYTE_DATA))
+               return -ENODEV;
+
+       info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
+       if (config < 0) {
+               ret = config;
+               goto err_mem;
+       }
+
+       info->pages = 1;
+       info->format[PSC_VOLTAGE_IN] = direct;
+       info->format[PSC_VOLTAGE_OUT] = direct;
+       info->format[PSC_CURRENT_OUT] = direct;
+       info->m[PSC_CURRENT_OUT] = 807;
+       info->b[PSC_CURRENT_OUT] = 20475;
+       info->R[PSC_CURRENT_OUT] = -1;
+       info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+
+       info->read_word_data = adm1275_read_word_data;
+       info->write_word_data = adm1275_write_word_data;
+
+       if (config & ADM1275_VRANGE) {
+               info->m[PSC_VOLTAGE_IN] = 19199;
+               info->b[PSC_VOLTAGE_IN] = 0;
+               info->R[PSC_VOLTAGE_IN] = -2;
+               info->m[PSC_VOLTAGE_OUT] = 19199;
+               info->b[PSC_VOLTAGE_OUT] = 0;
+               info->R[PSC_VOLTAGE_OUT] = -2;
+       } else {
+               info->m[PSC_VOLTAGE_IN] = 6720;
+               info->b[PSC_VOLTAGE_IN] = 0;
+               info->R[PSC_VOLTAGE_IN] = -1;
+               info->m[PSC_VOLTAGE_OUT] = 6720;
+               info->b[PSC_VOLTAGE_OUT] = 0;
+               info->R[PSC_VOLTAGE_OUT] = -1;
+       }
+
+       if (config & ADM1275_VIN_VOUT_SELECT)
+               info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+       else
+               info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
+
+       ret = pmbus_do_probe(client, id, info);
+       if (ret)
+               goto err_mem;
+       return 0;
+
+err_mem:
+       kfree(info);
+       return ret;
+}
+
+static int adm1275_remove(struct i2c_client *client)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       int ret;
+
+       ret = pmbus_do_remove(client);
+       kfree(info);
+       return ret;
+}
+
+static const struct i2c_device_id adm1275_id[] = {
+       {"adm1275", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adm1275_id);
+
+static struct i2c_driver adm1275_driver = {
+       .driver = {
+                  .name = "adm1275",
+                  },
+       .probe = adm1275_probe,
+       .remove = adm1275_remove,
+       .id_table = adm1275_id,
+};
+
+static int __init adm1275_init(void)
+{
+       return i2c_add_driver(&adm1275_driver);
+}
+
+static void __exit adm1275_exit(void)
+{
+       i2c_del_driver(&adm1275_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275");
+MODULE_LICENSE("GPL");
+module_init(adm1275_init);
+module_exit(adm1275_exit);
diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
new file mode 100644 (file)
index 0000000..d4bc114
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Hardware monitoring driver for LM25066 / LM5064 / LM5066
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+enum chips { lm25066, lm5064, lm5066 };
+
+#define LM25066_READ_VAUX              0xd0
+#define LM25066_MFR_READ_IIN           0xd1
+#define LM25066_MFR_READ_PIN           0xd2
+#define LM25066_MFR_IIN_OC_WARN_LIMIT  0xd3
+#define LM25066_MFR_PIN_OP_WARN_LIMIT  0xd4
+#define LM25066_READ_PIN_PEAK          0xd5
+#define LM25066_CLEAR_PIN_PEAK         0xd6
+#define LM25066_DEVICE_SETUP           0xd9
+#define LM25066_READ_AVG_VIN           0xdc
+#define LM25066_READ_AVG_VOUT          0xdd
+#define LM25066_READ_AVG_IIN           0xde
+#define LM25066_READ_AVG_PIN           0xdf
+
+#define LM25066_DEV_SETUP_CL           (1 << 4)        /* Current limit */
+
+struct lm25066_data {
+       int id;
+       struct pmbus_driver_info info;
+};
+
+#define to_lm25066_data(x)  container_of(x, struct lm25066_data, info)
+
+static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       const struct lm25066_data *data = to_lm25066_data(info);
+       int ret;
+
+       if (page > 1)
+               return -EINVAL;
+
+       /* Map READ_VAUX into READ_VOUT register on page 1 */
+       if (page == 1) {
+               switch (reg) {
+               case PMBUS_READ_VOUT:
+                       ret = pmbus_read_word_data(client, 0,
+                                                  LM25066_READ_VAUX);
+                       if (ret < 0)
+                               break;
+                       /* Adjust returned value to match VOUT coefficients */
+                       switch (data->id) {
+                       case lm25066:
+                               /* VOUT: 4.54 mV VAUX: 283.2 uV LSB */
+                               ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
+                               break;
+                       case lm5064:
+                               /* VOUT: 4.53 mV VAUX: 700 uV LSB */
+                               ret = DIV_ROUND_CLOSEST(ret * 70, 453);
+                               break;
+                       case lm5066:
+                               /* VOUT: 2.18 mV VAUX: 725 uV LSB */
+                               ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
+                               break;
+                       }
+                       break;
+               default:
+                       /* No other valid registers on page 1 */
+                       ret = -EINVAL;
+                       break;
+               }
+               goto done;
+       }
+
+       switch (reg) {
+       case PMBUS_READ_IIN:
+               ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
+               break;
+       case PMBUS_READ_PIN:
+               ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN);
+               break;
+       case PMBUS_IIN_OC_WARN_LIMIT:
+               ret = pmbus_read_word_data(client, 0,
+                                          LM25066_MFR_IIN_OC_WARN_LIMIT);
+               break;
+       case PMBUS_PIN_OP_WARN_LIMIT:
+               ret = pmbus_read_word_data(client, 0,
+                                          LM25066_MFR_PIN_OP_WARN_LIMIT);
+               break;
+       case PMBUS_VIRT_READ_VIN_AVG:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN);
+               break;
+       case PMBUS_VIRT_READ_VOUT_AVG:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT);
+               break;
+       case PMBUS_VIRT_READ_IIN_AVG:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN);
+               break;
+       case PMBUS_VIRT_READ_PIN_AVG:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN);
+               break;
+       case PMBUS_VIRT_READ_PIN_MAX:
+               ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_PIN_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+done:
+       return ret;
+}
+
+static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
+                                  u16 word)
+{
+       int ret;
+
+       if (page > 1)
+               return -EINVAL;
+
+       switch (reg) {
+       case PMBUS_IIN_OC_WARN_LIMIT:
+               ret = pmbus_write_word_data(client, 0,
+                                           LM25066_MFR_IIN_OC_WARN_LIMIT,
+                                           word);
+               break;
+       case PMBUS_PIN_OP_WARN_LIMIT:
+               ret = pmbus_write_word_data(client, 0,
+                                           LM25066_MFR_PIN_OP_WARN_LIMIT,
+                                           word);
+               break;
+       case PMBUS_VIRT_RESET_PIN_HISTORY:
+               ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int lm25066_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       int config;
+       int ret;
+       struct lm25066_data *data;
+       struct pmbus_driver_info *info;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_READ_BYTE_DATA))
+               return -ENODEV;
+
+       data = kzalloc(sizeof(struct lm25066_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       config = i2c_smbus_read_byte_data(client, LM25066_DEVICE_SETUP);
+       if (config < 0) {
+               ret = config;
+               goto err_mem;
+       }
+
+       data->id = id->driver_data;
+       info = &data->info;
+
+       info->pages = 2;
+       info->format[PSC_VOLTAGE_IN] = direct;
+       info->format[PSC_VOLTAGE_OUT] = direct;
+       info->format[PSC_CURRENT_IN] = direct;
+       info->format[PSC_TEMPERATURE] = direct;
+       info->format[PSC_POWER] = direct;
+
+       info->m[PSC_TEMPERATURE] = 16;
+       info->b[PSC_TEMPERATURE] = 0;
+       info->R[PSC_TEMPERATURE] = 0;
+
+       info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT
+         | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN
+         | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+       info->func[1] = PMBUS_HAVE_VOUT;
+
+       info->read_word_data = lm25066_read_word_data;
+       info->write_word_data = lm25066_write_word_data;
+
+       switch (id->driver_data) {
+       case lm25066:
+               info->m[PSC_VOLTAGE_IN] = 22070;
+               info->b[PSC_VOLTAGE_IN] = 0;
+               info->R[PSC_VOLTAGE_IN] = -2;
+               info->m[PSC_VOLTAGE_OUT] = 22070;
+               info->b[PSC_VOLTAGE_OUT] = 0;
+               info->R[PSC_VOLTAGE_OUT] = -2;
+
+               if (config & LM25066_DEV_SETUP_CL) {
+                       info->m[PSC_CURRENT_IN] = 6852;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 369;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -2;
+               } else {
+                       info->m[PSC_CURRENT_IN] = 13661;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 736;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -2;
+               }
+               break;
+       case lm5064:
+               info->m[PSC_VOLTAGE_IN] = 22075;
+               info->b[PSC_VOLTAGE_IN] = 0;
+               info->R[PSC_VOLTAGE_IN] = -2;
+               info->m[PSC_VOLTAGE_OUT] = 22075;
+               info->b[PSC_VOLTAGE_OUT] = 0;
+               info->R[PSC_VOLTAGE_OUT] = -2;
+
+               if (config & LM25066_DEV_SETUP_CL) {
+                       info->m[PSC_CURRENT_IN] = 6713;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 3619;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -3;
+               } else {
+                       info->m[PSC_CURRENT_IN] = 13426;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 7238;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -3;
+               }
+               break;
+       case lm5066:
+               info->m[PSC_VOLTAGE_IN] = 4587;
+               info->b[PSC_VOLTAGE_IN] = 0;
+               info->R[PSC_VOLTAGE_IN] = -2;
+               info->m[PSC_VOLTAGE_OUT] = 4587;
+               info->b[PSC_VOLTAGE_OUT] = 0;
+               info->R[PSC_VOLTAGE_OUT] = -2;
+
+               if (config & LM25066_DEV_SETUP_CL) {
+                       info->m[PSC_CURRENT_IN] = 10753;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 1204;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -3;
+               } else {
+                       info->m[PSC_CURRENT_IN] = 5405;
+                       info->b[PSC_CURRENT_IN] = 0;
+                       info->R[PSC_CURRENT_IN] = -2;
+                       info->m[PSC_POWER] = 605;
+                       info->b[PSC_POWER] = 0;
+                       info->R[PSC_POWER] = -3;
+               }
+               break;
+       default:
+               ret = -ENODEV;
+               goto err_mem;
+       }
+
+       ret = pmbus_do_probe(client, id, info);
+       if (ret)
+               goto err_mem;
+       return 0;
+
+err_mem:
+       kfree(data);
+       return ret;
+}
+
+static int lm25066_remove(struct i2c_client *client)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       const struct lm25066_data *data = to_lm25066_data(info);
+       int ret;
+
+       ret = pmbus_do_remove(client);
+       kfree(data);
+       return ret;
+}
+
+static const struct i2c_device_id lm25066_id[] = {
+       {"lm25066", lm25066},
+       {"lm5064", lm5064},
+       {"lm5066", lm5066},
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, lm25066_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver lm25066_driver = {
+       .driver = {
+                  .name = "lm25066",
+                  },
+       .probe = lm25066_probe,
+       .remove = lm25066_remove,
+       .id_table = lm25066_id,
+};
+
+static int __init lm25066_init(void)
+{
+       return i2c_add_driver(&lm25066_driver);
+}
+
+static void __exit lm25066_exit(void)
+{
+       i2c_del_driver(&lm25066_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for LM25066/LM5064/LM5066");
+MODULE_LICENSE("GPL");
+module_init(lm25066_init);
+module_exit(lm25066_exit);
diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c
new file mode 100644 (file)
index 0000000..e50b296
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Hardware monitoring driver for Maxim MAX16064
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+#define MAX16064_MFR_VOUT_PEAK         0xd4
+#define MAX16064_MFR_TEMPERATURE_PEAK  0xd6
+
+static int max16064_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, page,
+                                          MAX16064_MFR_VOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_TEMP_MAX:
+               ret = pmbus_read_word_data(client, page,
+                                          MAX16064_MFR_TEMPERATURE_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int max16064_write_word_data(struct i2c_client *client, int page,
+                                   int reg, u16 word)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           MAX16064_MFR_VOUT_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           MAX16064_MFR_TEMPERATURE_PEAK,
+                                           0xffff);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static struct pmbus_driver_info max16064_info = {
+       .pages = 4,
+       .format[PSC_VOLTAGE_IN] = direct,
+       .format[PSC_VOLTAGE_OUT] = direct,
+       .format[PSC_TEMPERATURE] = direct,
+       .m[PSC_VOLTAGE_IN] = 19995,
+       .b[PSC_VOLTAGE_IN] = 0,
+       .R[PSC_VOLTAGE_IN] = -1,
+       .m[PSC_VOLTAGE_OUT] = 19995,
+       .b[PSC_VOLTAGE_OUT] = 0,
+       .R[PSC_VOLTAGE_OUT] = -1,
+       .m[PSC_TEMPERATURE] = -7612,
+       .b[PSC_TEMPERATURE] = 335,
+       .R[PSC_TEMPERATURE] = -3,
+       .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_TEMP
+               | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_TEMP,
+       .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+       .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+       .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT,
+       .read_word_data = max16064_read_word_data,
+       .write_word_data = max16064_write_word_data,
+};
+
+static int max16064_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       return pmbus_do_probe(client, id, &max16064_info);
+}
+
+static int max16064_remove(struct i2c_client *client)
+{
+       return pmbus_do_remove(client);
+}
+
+static const struct i2c_device_id max16064_id[] = {
+       {"max16064", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, max16064_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max16064_driver = {
+       .driver = {
+                  .name = "max16064",
+                  },
+       .probe = max16064_probe,
+       .remove = max16064_remove,
+       .id_table = max16064_id,
+};
+
+static int __init max16064_init(void)
+{
+       return i2c_add_driver(&max16064_driver);
+}
+
+static void __exit max16064_exit(void)
+{
+       i2c_del_driver(&max16064_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX16064");
+MODULE_LICENSE("GPL");
+module_init(max16064_init);
+module_exit(max16064_exit);
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c
new file mode 100644 (file)
index 0000000..fda621d
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Hardware monitoring driver for Maxim MAX34440/MAX34441
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+enum chips { max34440, max34441 };
+
+#define MAX34440_MFR_VOUT_PEAK         0xd4
+#define MAX34440_MFR_IOUT_PEAK         0xd5
+#define MAX34440_MFR_TEMPERATURE_PEAK  0xd6
+
+#define MAX34440_STATUS_OC_WARN                (1 << 0)
+#define MAX34440_STATUS_OC_FAULT       (1 << 1)
+#define MAX34440_STATUS_OT_FAULT       (1 << 5)
+#define MAX34440_STATUS_OT_WARN                (1 << 6)
+
+static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, page,
+                                          MAX34440_MFR_VOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_IOUT_MAX:
+               ret = pmbus_read_word_data(client, page,
+                                          MAX34440_MFR_IOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_TEMP_MAX:
+               ret = pmbus_read_word_data(client, page,
+                                          MAX34440_MFR_TEMPERATURE_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int max34440_write_word_data(struct i2c_client *client, int page,
+                                   int reg, u16 word)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           MAX34440_MFR_VOUT_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           MAX34440_MFR_IOUT_PEAK, 0);
+               break;
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = pmbus_write_word_data(client, page,
+                                           MAX34440_MFR_TEMPERATURE_PEAK,
+                                           0xffff);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+       int mfg_status;
+
+       ret = pmbus_set_page(client, page);
+       if (ret < 0)
+               return ret;
+
+       switch (reg) {
+       case PMBUS_STATUS_IOUT:
+               mfg_status = pmbus_read_word_data(client, 0,
+                                                 PMBUS_STATUS_MFR_SPECIFIC);
+               if (mfg_status < 0)
+                       return mfg_status;
+               if (mfg_status & MAX34440_STATUS_OC_WARN)
+                       ret |= PB_IOUT_OC_WARNING;
+               if (mfg_status & MAX34440_STATUS_OC_FAULT)
+                       ret |= PB_IOUT_OC_FAULT;
+               break;
+       case PMBUS_STATUS_TEMPERATURE:
+               mfg_status = pmbus_read_word_data(client, 0,
+                                                 PMBUS_STATUS_MFR_SPECIFIC);
+               if (mfg_status < 0)
+                       return mfg_status;
+               if (mfg_status & MAX34440_STATUS_OT_WARN)
+                       ret |= PB_TEMP_OT_WARNING;
+               if (mfg_status & MAX34440_STATUS_OT_FAULT)
+                       ret |= PB_TEMP_OT_FAULT;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static struct pmbus_driver_info max34440_info[] = {
+       [max34440] = {
+               .pages = 14,
+               .format[PSC_VOLTAGE_IN] = direct,
+               .format[PSC_VOLTAGE_OUT] = direct,
+               .format[PSC_TEMPERATURE] = direct,
+               .format[PSC_CURRENT_OUT] = direct,
+               .m[PSC_VOLTAGE_IN] = 1,
+               .b[PSC_VOLTAGE_IN] = 0,
+               .R[PSC_VOLTAGE_IN] = 3,     /* R = 0 in datasheet reflects mV */
+               .m[PSC_VOLTAGE_OUT] = 1,
+               .b[PSC_VOLTAGE_OUT] = 0,
+               .R[PSC_VOLTAGE_OUT] = 3,    /* R = 0 in datasheet reflects mV */
+               .m[PSC_CURRENT_OUT] = 1,
+               .b[PSC_CURRENT_OUT] = 0,
+               .R[PSC_CURRENT_OUT] = 3,    /* R = 0 in datasheet reflects mA */
+               .m[PSC_TEMPERATURE] = 1,
+               .b[PSC_TEMPERATURE] = 0,
+               .R[PSC_TEMPERATURE] = 2,
+               .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .read_byte_data = max34440_read_byte_data,
+               .read_word_data = max34440_read_word_data,
+               .write_word_data = max34440_write_word_data,
+       },
+       [max34441] = {
+               .pages = 12,
+               .format[PSC_VOLTAGE_IN] = direct,
+               .format[PSC_VOLTAGE_OUT] = direct,
+               .format[PSC_TEMPERATURE] = direct,
+               .format[PSC_CURRENT_OUT] = direct,
+               .format[PSC_FAN] = direct,
+               .m[PSC_VOLTAGE_IN] = 1,
+               .b[PSC_VOLTAGE_IN] = 0,
+               .R[PSC_VOLTAGE_IN] = 3,
+               .m[PSC_VOLTAGE_OUT] = 1,
+               .b[PSC_VOLTAGE_OUT] = 0,
+               .R[PSC_VOLTAGE_OUT] = 3,
+               .m[PSC_CURRENT_OUT] = 1,
+               .b[PSC_CURRENT_OUT] = 0,
+               .R[PSC_CURRENT_OUT] = 3,
+               .m[PSC_TEMPERATURE] = 1,
+               .b[PSC_TEMPERATURE] = 0,
+               .R[PSC_TEMPERATURE] = 2,
+               .m[PSC_FAN] = 1,
+               .b[PSC_FAN] = 0,
+               .R[PSC_FAN] = 0,
+               .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
+               .func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
+               .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+               .read_byte_data = max34440_read_byte_data,
+               .read_word_data = max34440_read_word_data,
+               .write_word_data = max34440_write_word_data,
+       },
+};
+
+static int max34440_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       return pmbus_do_probe(client, id, &max34440_info[id->driver_data]);
+}
+
+static int max34440_remove(struct i2c_client *client)
+{
+       return pmbus_do_remove(client);
+}
+
+static const struct i2c_device_id max34440_id[] = {
+       {"max34440", max34440},
+       {"max34441", max34441},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, max34440_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max34440_driver = {
+       .driver = {
+                  .name = "max34440",
+                  },
+       .probe = max34440_probe,
+       .remove = max34440_remove,
+       .id_table = max34440_id,
+};
+
+static int __init max34440_init(void)
+{
+       return i2c_add_driver(&max34440_driver);
+}
+
+static void __exit max34440_exit(void)
+{
+       i2c_del_driver(&max34440_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441");
+MODULE_LICENSE("GPL");
+module_init(max34440_init);
+module_exit(max34440_exit);
diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c
new file mode 100644 (file)
index 0000000..c3e72f1
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Hardware monitoring driver for Maxim MAX8688
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+#define MAX8688_MFR_VOUT_PEAK          0xd4
+#define MAX8688_MFR_IOUT_PEAK          0xd5
+#define MAX8688_MFR_TEMPERATURE_PEAK   0xd6
+#define MAX8688_MFG_STATUS             0xd8
+
+#define MAX8688_STATUS_OC_FAULT                (1 << 4)
+#define MAX8688_STATUS_OV_FAULT                (1 << 5)
+#define MAX8688_STATUS_OV_WARNING      (1 << 8)
+#define MAX8688_STATUS_UV_FAULT                (1 << 9)
+#define MAX8688_STATUS_UV_WARNING      (1 << 10)
+#define MAX8688_STATUS_UC_FAULT                (1 << 11)
+#define MAX8688_STATUS_OC_WARNING      (1 << 12)
+#define MAX8688_STATUS_OT_FAULT                (1 << 13)
+#define MAX8688_STATUS_OT_WARNING      (1 << 14)
+
+static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       int ret;
+
+       if (page)
+               return -EINVAL;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_VOUT_MAX:
+               ret = pmbus_read_word_data(client, 0, MAX8688_MFR_VOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_IOUT_MAX:
+               ret = pmbus_read_word_data(client, 0, MAX8688_MFR_IOUT_PEAK);
+               break;
+       case PMBUS_VIRT_READ_TEMP_MAX:
+               ret = pmbus_read_word_data(client, 0,
+                                          MAX8688_MFR_TEMPERATURE_PEAK);
+               break;
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int max8688_write_word_data(struct i2c_client *client, int page, int reg,
+                                  u16 word)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_RESET_VOUT_HISTORY:
+               ret = pmbus_write_word_data(client, 0, MAX8688_MFR_VOUT_PEAK,
+                                           0);
+               break;
+       case PMBUS_VIRT_RESET_IOUT_HISTORY:
+               ret = pmbus_write_word_data(client, 0, MAX8688_MFR_IOUT_PEAK,
+                                           0);
+               break;
+       case PMBUS_VIRT_RESET_TEMP_HISTORY:
+               ret = pmbus_write_word_data(client, 0,
+                                           MAX8688_MFR_TEMPERATURE_PEAK,
+                                           0xffff);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       int ret = 0;
+       int mfg_status;
+
+       if (page)
+               return -EINVAL;
+
+       switch (reg) {
+       case PMBUS_STATUS_VOUT:
+               mfg_status = pmbus_read_word_data(client, 0,
+                                                 MAX8688_MFG_STATUS);
+               if (mfg_status < 0)
+                       return mfg_status;
+               if (mfg_status & MAX8688_STATUS_UV_WARNING)
+                       ret |= PB_VOLTAGE_UV_WARNING;
+               if (mfg_status & MAX8688_STATUS_UV_FAULT)
+                       ret |= PB_VOLTAGE_UV_FAULT;
+               if (mfg_status & MAX8688_STATUS_OV_WARNING)
+                       ret |= PB_VOLTAGE_OV_WARNING;
+               if (mfg_status & MAX8688_STATUS_OV_FAULT)
+                       ret |= PB_VOLTAGE_OV_FAULT;
+               break;
+       case PMBUS_STATUS_IOUT:
+               mfg_status = pmbus_read_word_data(client, 0,
+                                                 MAX8688_MFG_STATUS);
+               if (mfg_status < 0)
+                       return mfg_status;
+               if (mfg_status & MAX8688_STATUS_UC_FAULT)
+                       ret |= PB_IOUT_UC_FAULT;
+               if (mfg_status & MAX8688_STATUS_OC_WARNING)
+                       ret |= PB_IOUT_OC_WARNING;
+               if (mfg_status & MAX8688_STATUS_OC_FAULT)
+                       ret |= PB_IOUT_OC_FAULT;
+               break;
+       case PMBUS_STATUS_TEMPERATURE:
+               mfg_status = pmbus_read_word_data(client, 0,
+                                                 MAX8688_MFG_STATUS);
+               if (mfg_status < 0)
+                       return mfg_status;
+               if (mfg_status & MAX8688_STATUS_OT_WARNING)
+                       ret |= PB_TEMP_OT_WARNING;
+               if (mfg_status & MAX8688_STATUS_OT_FAULT)
+                       ret |= PB_TEMP_OT_FAULT;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static struct pmbus_driver_info max8688_info = {
+       .pages = 1,
+       .format[PSC_VOLTAGE_IN] = direct,
+       .format[PSC_VOLTAGE_OUT] = direct,
+       .format[PSC_TEMPERATURE] = direct,
+       .format[PSC_CURRENT_OUT] = direct,
+       .m[PSC_VOLTAGE_IN] = 19995,
+       .b[PSC_VOLTAGE_IN] = 0,
+       .R[PSC_VOLTAGE_IN] = -1,
+       .m[PSC_VOLTAGE_OUT] = 19995,
+       .b[PSC_VOLTAGE_OUT] = 0,
+       .R[PSC_VOLTAGE_OUT] = -1,
+       .m[PSC_CURRENT_OUT] = 23109,
+       .b[PSC_CURRENT_OUT] = 0,
+       .R[PSC_CURRENT_OUT] = -2,
+       .m[PSC_TEMPERATURE] = -7612,
+       .b[PSC_TEMPERATURE] = 335,
+       .R[PSC_TEMPERATURE] = -3,
+       .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP
+               | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
+               | PMBUS_HAVE_STATUS_TEMP,
+       .read_byte_data = max8688_read_byte_data,
+       .read_word_data = max8688_read_word_data,
+       .write_word_data = max8688_write_word_data,
+};
+
+static int max8688_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       return pmbus_do_probe(client, id, &max8688_info);
+}
+
+static int max8688_remove(struct i2c_client *client)
+{
+       return pmbus_do_remove(client);
+}
+
+static const struct i2c_device_id max8688_id[] = {
+       {"max8688", 0},
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, max8688_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max8688_driver = {
+       .driver = {
+                  .name = "max8688",
+                  },
+       .probe = max8688_probe,
+       .remove = max8688_remove,
+       .id_table = max8688_id,
+};
+
+static int __init max8688_init(void)
+{
+       return i2c_add_driver(&max8688_driver);
+}
+
+static void __exit max8688_exit(void)
+{
+       i2c_del_driver(&max8688_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688");
+MODULE_LICENSE("GPL");
+module_init(max8688_init);
+module_exit(max8688_exit);
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c
new file mode 100644 (file)
index 0000000..73de9f1
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Hardware monitoring driver for PMBus devices
+ *
+ * Copyright (c) 2010, 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+/*
+ * Find sensor groups and status registers on each page.
+ */
+static void pmbus_find_sensor_groups(struct i2c_client *client,
+                                    struct pmbus_driver_info *info)
+{
+       int page;
+
+       /* Sensors detected on page 0 only */
+       if (pmbus_check_word_register(client, 0, PMBUS_READ_VIN))
+               info->func[0] |= PMBUS_HAVE_VIN;
+       if (pmbus_check_word_register(client, 0, PMBUS_READ_VCAP))
+               info->func[0] |= PMBUS_HAVE_VCAP;
+       if (pmbus_check_word_register(client, 0, PMBUS_READ_IIN))
+               info->func[0] |= PMBUS_HAVE_IIN;
+       if (pmbus_check_word_register(client, 0, PMBUS_READ_PIN))
+               info->func[0] |= PMBUS_HAVE_PIN;
+       if (info->func[0]
+           && pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT))
+               info->func[0] |= PMBUS_HAVE_STATUS_INPUT;
+       if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_12) &&
+           pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) {
+               info->func[0] |= PMBUS_HAVE_FAN12;
+               if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12))
+                       info->func[0] |= PMBUS_HAVE_STATUS_FAN12;
+       }
+       if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) &&
+           pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) {
+               info->func[0] |= PMBUS_HAVE_FAN34;
+               if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34))
+                       info->func[0] |= PMBUS_HAVE_STATUS_FAN34;
+       }
+       if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1))
+               info->func[0] |= PMBUS_HAVE_TEMP;
+       if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2))
+               info->func[0] |= PMBUS_HAVE_TEMP2;
+       if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3))
+               info->func[0] |= PMBUS_HAVE_TEMP3;
+       if (info->func[0] & (PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2
+                            | PMBUS_HAVE_TEMP3)
+           && pmbus_check_byte_register(client, 0,
+                                        PMBUS_STATUS_TEMPERATURE))
+                       info->func[0] |= PMBUS_HAVE_STATUS_TEMP;
+
+       /* Sensors detected on all pages */
+       for (page = 0; page < info->pages; page++) {
+               if (pmbus_check_word_register(client, page, PMBUS_READ_VOUT)) {
+                       info->func[page] |= PMBUS_HAVE_VOUT;
+                       if (pmbus_check_byte_register(client, page,
+                                                     PMBUS_STATUS_VOUT))
+                               info->func[page] |= PMBUS_HAVE_STATUS_VOUT;
+               }
+               if (pmbus_check_word_register(client, page, PMBUS_READ_IOUT)) {
+                       info->func[page] |= PMBUS_HAVE_IOUT;
+                       if (pmbus_check_byte_register(client, 0,
+                                                     PMBUS_STATUS_IOUT))
+                               info->func[page] |= PMBUS_HAVE_STATUS_IOUT;
+               }
+               if (pmbus_check_word_register(client, page, PMBUS_READ_POUT))
+                       info->func[page] |= PMBUS_HAVE_POUT;
+       }
+}
+
+/*
+ * Identify chip parameters.
+ */
+static int pmbus_identify(struct i2c_client *client,
+                         struct pmbus_driver_info *info)
+{
+       int ret = 0;
+
+       if (!info->pages) {
+               /*
+                * Check if the PAGE command is supported. If it is,
+                * keep setting the page number until it fails or until the
+                * maximum number of pages has been reached. Assume that
+                * this is the number of pages supported by the chip.
+                */
+               if (pmbus_check_byte_register(client, 0, PMBUS_PAGE)) {
+                       int page;
+
+                       for (page = 1; page < PMBUS_PAGES; page++) {
+                               if (pmbus_set_page(client, page) < 0)
+                                       break;
+                       }
+                       pmbus_set_page(client, 0);
+                       info->pages = page;
+               } else {
+                       info->pages = 1;
+               }
+       }
+
+       if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) {
+               int vout_mode;
+
+               vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
+               if (vout_mode >= 0 && vout_mode != 0xff) {
+                       switch (vout_mode >> 5) {
+                       case 0:
+                               break;
+                       case 1:
+                               info->format[PSC_VOLTAGE_OUT] = vid;
+                               break;
+                       case 2:
+                               info->format[PSC_VOLTAGE_OUT] = direct;
+                               break;
+                       default:
+                               ret = -ENODEV;
+                               goto abort;
+                       }
+               }
+       }
+
+       /*
+        * We should check if the COEFFICIENTS register is supported.
+        * If it is, and the chip is configured for direct mode, we can read
+        * the coefficients from the chip, one set per group of sensor
+        * registers.
+        *
+        * To do this, we will need access to a chip which actually supports the
+        * COEFFICIENTS command, since the command is too complex to implement
+        * without testing it. Until then, abort if a chip configured for direct
+        * mode was detected.
+        */
+       if (info->format[PSC_VOLTAGE_OUT] == direct) {
+               ret = -ENODEV;
+               goto abort;
+       }
+
+       /* Try to find sensor groups  */
+       pmbus_find_sensor_groups(client, info);
+abort:
+       return ret;
+}
+
+static int pmbus_probe(struct i2c_client *client,
+                      const struct i2c_device_id *id)
+{
+       struct pmbus_driver_info *info;
+       int ret;
+
+       info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->pages = id->driver_data;
+       info->identify = pmbus_identify;
+
+       ret = pmbus_do_probe(client, id, info);
+       if (ret < 0)
+               goto out;
+       return 0;
+
+out:
+       kfree(info);
+       return ret;
+}
+
+static int pmbus_remove(struct i2c_client *client)
+{
+       int ret;
+       const struct pmbus_driver_info *info;
+
+       info = pmbus_get_driver_info(client);
+       ret = pmbus_do_remove(client);
+       kfree(info);
+       return ret;
+}
+
+/*
+ * Use driver_data to set the number of pages supported by the chip.
+ */
+static const struct i2c_device_id pmbus_id[] = {
+       {"adp4000", 1},
+       {"bmr450", 1},
+       {"bmr451", 1},
+       {"bmr453", 1},
+       {"bmr454", 1},
+       {"ltc2978", 8},
+       {"ncp4200", 1},
+       {"ncp4208", 1},
+       {"pmbus", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, pmbus_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver pmbus_driver = {
+       .driver = {
+                  .name = "pmbus",
+                  },
+       .probe = pmbus_probe,
+       .remove = pmbus_remove,
+       .id_table = pmbus_id,
+};
+
+static int __init pmbus_init(void)
+{
+       return i2c_add_driver(&pmbus_driver);
+}
+
+static void __exit pmbus_exit(void)
+{
+       i2c_del_driver(&pmbus_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("Generic PMBus driver");
+MODULE_LICENSE("GPL");
+module_init(pmbus_init);
+module_exit(pmbus_exit);
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
new file mode 100644 (file)
index 0000000..0808d98
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * pmbus.h - Common defines and structures for PMBus devices
+ *
+ * Copyright (c) 2010, 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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 PMBUS_H
+#define PMBUS_H
+
+/*
+ * Registers
+ */
+#define PMBUS_PAGE                     0x00
+#define PMBUS_OPERATION                        0x01
+#define PMBUS_ON_OFF_CONFIG            0x02
+#define PMBUS_CLEAR_FAULTS             0x03
+#define PMBUS_PHASE                    0x04
+
+#define PMBUS_CAPABILITY               0x19
+#define PMBUS_QUERY                    0x1A
+
+#define PMBUS_VOUT_MODE                        0x20
+#define PMBUS_VOUT_COMMAND             0x21
+#define PMBUS_VOUT_TRIM                        0x22
+#define PMBUS_VOUT_CAL_OFFSET          0x23
+#define PMBUS_VOUT_MAX                 0x24
+#define PMBUS_VOUT_MARGIN_HIGH         0x25
+#define PMBUS_VOUT_MARGIN_LOW          0x26
+#define PMBUS_VOUT_TRANSITION_RATE     0x27
+#define PMBUS_VOUT_DROOP               0x28
+#define PMBUS_VOUT_SCALE_LOOP          0x29
+#define PMBUS_VOUT_SCALE_MONITOR       0x2A
+
+#define PMBUS_COEFFICIENTS             0x30
+#define PMBUS_POUT_MAX                 0x31
+
+#define PMBUS_FAN_CONFIG_12            0x3A
+#define PMBUS_FAN_COMMAND_1            0x3B
+#define PMBUS_FAN_COMMAND_2            0x3C
+#define PMBUS_FAN_CONFIG_34            0x3D
+#define PMBUS_FAN_COMMAND_3            0x3E
+#define PMBUS_FAN_COMMAND_4            0x3F
+
+#define PMBUS_VOUT_OV_FAULT_LIMIT      0x40
+#define PMBUS_VOUT_OV_FAULT_RESPONSE   0x41
+#define PMBUS_VOUT_OV_WARN_LIMIT       0x42
+#define PMBUS_VOUT_UV_WARN_LIMIT       0x43
+#define PMBUS_VOUT_UV_FAULT_LIMIT      0x44
+#define PMBUS_VOUT_UV_FAULT_RESPONSE   0x45
+#define PMBUS_IOUT_OC_FAULT_LIMIT      0x46
+#define PMBUS_IOUT_OC_FAULT_RESPONSE   0x47
+#define PMBUS_IOUT_OC_LV_FAULT_LIMIT   0x48
+#define PMBUS_IOUT_OC_LV_FAULT_RESPONSE        0x49
+#define PMBUS_IOUT_OC_WARN_LIMIT       0x4A
+#define PMBUS_IOUT_UC_FAULT_LIMIT      0x4B
+#define PMBUS_IOUT_UC_FAULT_RESPONSE   0x4C
+
+#define PMBUS_OT_FAULT_LIMIT           0x4F
+#define PMBUS_OT_FAULT_RESPONSE                0x50
+#define PMBUS_OT_WARN_LIMIT            0x51
+#define PMBUS_UT_WARN_LIMIT            0x52
+#define PMBUS_UT_FAULT_LIMIT           0x53
+#define PMBUS_UT_FAULT_RESPONSE                0x54
+#define PMBUS_VIN_OV_FAULT_LIMIT       0x55
+#define PMBUS_VIN_OV_FAULT_RESPONSE    0x56
+#define PMBUS_VIN_OV_WARN_LIMIT                0x57
+#define PMBUS_VIN_UV_WARN_LIMIT                0x58
+#define PMBUS_VIN_UV_FAULT_LIMIT       0x59
+
+#define PMBUS_IIN_OC_FAULT_LIMIT       0x5B
+#define PMBUS_IIN_OC_WARN_LIMIT                0x5D
+
+#define PMBUS_POUT_OP_FAULT_LIMIT      0x68
+#define PMBUS_POUT_OP_WARN_LIMIT       0x6A
+#define PMBUS_PIN_OP_WARN_LIMIT                0x6B
+
+#define PMBUS_STATUS_BYTE              0x78
+#define PMBUS_STATUS_WORD              0x79
+#define PMBUS_STATUS_VOUT              0x7A
+#define PMBUS_STATUS_IOUT              0x7B
+#define PMBUS_STATUS_INPUT             0x7C
+#define PMBUS_STATUS_TEMPERATURE       0x7D
+#define PMBUS_STATUS_CML               0x7E
+#define PMBUS_STATUS_OTHER             0x7F
+#define PMBUS_STATUS_MFR_SPECIFIC      0x80
+#define PMBUS_STATUS_FAN_12            0x81
+#define PMBUS_STATUS_FAN_34            0x82
+
+#define PMBUS_READ_VIN                 0x88
+#define PMBUS_READ_IIN                 0x89
+#define PMBUS_READ_VCAP                        0x8A
+#define PMBUS_READ_VOUT                        0x8B
+#define PMBUS_READ_IOUT                        0x8C
+#define PMBUS_READ_TEMPERATURE_1       0x8D
+#define PMBUS_READ_TEMPERATURE_2       0x8E
+#define PMBUS_READ_TEMPERATURE_3       0x8F
+#define PMBUS_READ_FAN_SPEED_1         0x90
+#define PMBUS_READ_FAN_SPEED_2         0x91
+#define PMBUS_READ_FAN_SPEED_3         0x92
+#define PMBUS_READ_FAN_SPEED_4         0x93
+#define PMBUS_READ_DUTY_CYCLE          0x94
+#define PMBUS_READ_FREQUENCY           0x95
+#define PMBUS_READ_POUT                        0x96
+#define PMBUS_READ_PIN                 0x97
+
+#define PMBUS_REVISION                 0x98
+#define PMBUS_MFR_ID                   0x99
+#define PMBUS_MFR_MODEL                        0x9A
+#define PMBUS_MFR_REVISION             0x9B
+#define PMBUS_MFR_LOCATION             0x9C
+#define PMBUS_MFR_DATE                 0x9D
+#define PMBUS_MFR_SERIAL               0x9E
+
+/*
+ * Virtual registers.
+ * Useful to support attributes which are not supported by standard PMBus
+ * registers but exist as manufacturer specific registers on individual chips.
+ * Must be mapped to real registers in device specific code.
+ *
+ * Semantics:
+ * Virtual registers are all word size.
+ * READ registers are read-only; writes are either ignored or return an error.
+ * RESET registers are read/write. Reading returns zero (used for detection),
+ * writing any value causes the associated history to be reset.
+ */
+#define PMBUS_VIRT_BASE                        0x100
+#define PMBUS_VIRT_READ_TEMP_MIN       (PMBUS_VIRT_BASE + 0)
+#define PMBUS_VIRT_READ_TEMP_MAX       (PMBUS_VIRT_BASE + 1)
+#define PMBUS_VIRT_RESET_TEMP_HISTORY  (PMBUS_VIRT_BASE + 2)
+#define PMBUS_VIRT_READ_VIN_AVG                (PMBUS_VIRT_BASE + 3)
+#define PMBUS_VIRT_READ_VIN_MIN                (PMBUS_VIRT_BASE + 4)
+#define PMBUS_VIRT_READ_VIN_MAX                (PMBUS_VIRT_BASE + 5)
+#define PMBUS_VIRT_RESET_VIN_HISTORY   (PMBUS_VIRT_BASE + 6)
+#define PMBUS_VIRT_READ_IIN_AVG                (PMBUS_VIRT_BASE + 7)
+#define PMBUS_VIRT_READ_IIN_MIN                (PMBUS_VIRT_BASE + 8)
+#define PMBUS_VIRT_READ_IIN_MAX                (PMBUS_VIRT_BASE + 9)
+#define PMBUS_VIRT_RESET_IIN_HISTORY   (PMBUS_VIRT_BASE + 10)
+#define PMBUS_VIRT_READ_PIN_AVG                (PMBUS_VIRT_BASE + 11)
+#define PMBUS_VIRT_READ_PIN_MAX                (PMBUS_VIRT_BASE + 12)
+#define PMBUS_VIRT_RESET_PIN_HISTORY   (PMBUS_VIRT_BASE + 13)
+#define PMBUS_VIRT_READ_VOUT_AVG       (PMBUS_VIRT_BASE + 14)
+#define PMBUS_VIRT_READ_VOUT_MIN       (PMBUS_VIRT_BASE + 15)
+#define PMBUS_VIRT_READ_VOUT_MAX       (PMBUS_VIRT_BASE + 16)
+#define PMBUS_VIRT_RESET_VOUT_HISTORY  (PMBUS_VIRT_BASE + 17)
+#define PMBUS_VIRT_READ_IOUT_AVG       (PMBUS_VIRT_BASE + 18)
+#define PMBUS_VIRT_READ_IOUT_MIN       (PMBUS_VIRT_BASE + 19)
+#define PMBUS_VIRT_READ_IOUT_MAX       (PMBUS_VIRT_BASE + 20)
+#define PMBUS_VIRT_RESET_IOUT_HISTORY  (PMBUS_VIRT_BASE + 21)
+
+/*
+ * CAPABILITY
+ */
+#define PB_CAPABILITY_SMBALERT         (1<<4)
+#define PB_CAPABILITY_ERROR_CHECK      (1<<7)
+
+/*
+ * VOUT_MODE
+ */
+#define PB_VOUT_MODE_MODE_MASK         0xe0
+#define PB_VOUT_MODE_PARAM_MASK                0x1f
+
+#define PB_VOUT_MODE_LINEAR            0x00
+#define PB_VOUT_MODE_VID               0x20
+#define PB_VOUT_MODE_DIRECT            0x40
+
+/*
+ * Fan configuration
+ */
+#define PB_FAN_2_PULSE_MASK            ((1 << 0) | (1 << 1))
+#define PB_FAN_2_RPM                   (1 << 2)
+#define PB_FAN_2_INSTALLED             (1 << 3)
+#define PB_FAN_1_PULSE_MASK            ((1 << 4) | (1 << 5))
+#define PB_FAN_1_RPM                   (1 << 6)
+#define PB_FAN_1_INSTALLED             (1 << 7)
+
+/*
+ * STATUS_BYTE, STATUS_WORD (lower)
+ */
+#define PB_STATUS_NONE_ABOVE           (1<<0)
+#define PB_STATUS_CML                  (1<<1)
+#define PB_STATUS_TEMPERATURE          (1<<2)
+#define PB_STATUS_VIN_UV               (1<<3)
+#define PB_STATUS_IOUT_OC              (1<<4)
+#define PB_STATUS_VOUT_OV              (1<<5)
+#define PB_STATUS_OFF                  (1<<6)
+#define PB_STATUS_BUSY                 (1<<7)
+
+/*
+ * STATUS_WORD (upper)
+ */
+#define PB_STATUS_UNKNOWN              (1<<8)
+#define PB_STATUS_OTHER                        (1<<9)
+#define PB_STATUS_FANS                 (1<<10)
+#define PB_STATUS_POWER_GOOD_N         (1<<11)
+#define PB_STATUS_WORD_MFR             (1<<12)
+#define PB_STATUS_INPUT                        (1<<13)
+#define PB_STATUS_IOUT_POUT            (1<<14)
+#define PB_STATUS_VOUT                 (1<<15)
+
+/*
+ * STATUS_IOUT
+ */
+#define PB_POUT_OP_WARNING             (1<<0)
+#define PB_POUT_OP_FAULT               (1<<1)
+#define PB_POWER_LIMITING              (1<<2)
+#define PB_CURRENT_SHARE_FAULT         (1<<3)
+#define PB_IOUT_UC_FAULT               (1<<4)
+#define PB_IOUT_OC_WARNING             (1<<5)
+#define PB_IOUT_OC_LV_FAULT            (1<<6)
+#define PB_IOUT_OC_FAULT               (1<<7)
+
+/*
+ * STATUS_VOUT, STATUS_INPUT
+ */
+#define PB_VOLTAGE_UV_FAULT            (1<<4)
+#define PB_VOLTAGE_UV_WARNING          (1<<5)
+#define PB_VOLTAGE_OV_WARNING          (1<<6)
+#define PB_VOLTAGE_OV_FAULT            (1<<7)
+
+/*
+ * STATUS_INPUT
+ */
+#define PB_PIN_OP_WARNING              (1<<0)
+#define PB_IIN_OC_WARNING              (1<<1)
+#define PB_IIN_OC_FAULT                        (1<<2)
+
+/*
+ * STATUS_TEMPERATURE
+ */
+#define PB_TEMP_UT_FAULT               (1<<4)
+#define PB_TEMP_UT_WARNING             (1<<5)
+#define PB_TEMP_OT_WARNING             (1<<6)
+#define PB_TEMP_OT_FAULT               (1<<7)
+
+/*
+ * STATUS_FAN
+ */
+#define PB_FAN_AIRFLOW_WARNING         (1<<0)
+#define PB_FAN_AIRFLOW_FAULT           (1<<1)
+#define PB_FAN_FAN2_SPEED_OVERRIDE     (1<<2)
+#define PB_FAN_FAN1_SPEED_OVERRIDE     (1<<3)
+#define PB_FAN_FAN2_WARNING            (1<<4)
+#define PB_FAN_FAN1_WARNING            (1<<5)
+#define PB_FAN_FAN2_FAULT              (1<<6)
+#define PB_FAN_FAN1_FAULT              (1<<7)
+
+/*
+ * CML_FAULT_STATUS
+ */
+#define PB_CML_FAULT_OTHER_MEM_LOGIC   (1<<0)
+#define PB_CML_FAULT_OTHER_COMM                (1<<1)
+#define PB_CML_FAULT_PROCESSOR         (1<<3)
+#define PB_CML_FAULT_MEMORY            (1<<4)
+#define PB_CML_FAULT_PACKET_ERROR      (1<<5)
+#define PB_CML_FAULT_INVALID_DATA      (1<<6)
+#define PB_CML_FAULT_INVALID_COMMAND   (1<<7)
+
+enum pmbus_sensor_classes {
+       PSC_VOLTAGE_IN = 0,
+       PSC_VOLTAGE_OUT,
+       PSC_CURRENT_IN,
+       PSC_CURRENT_OUT,
+       PSC_POWER,
+       PSC_TEMPERATURE,
+       PSC_FAN,
+       PSC_NUM_CLASSES         /* Number of power sensor classes */
+};
+
+#define PMBUS_PAGES    32      /* Per PMBus specification */
+
+/* Functionality bit mask */
+#define PMBUS_HAVE_VIN         (1 << 0)
+#define PMBUS_HAVE_VCAP                (1 << 1)
+#define PMBUS_HAVE_VOUT                (1 << 2)
+#define PMBUS_HAVE_IIN         (1 << 3)
+#define PMBUS_HAVE_IOUT                (1 << 4)
+#define PMBUS_HAVE_PIN         (1 << 5)
+#define PMBUS_HAVE_POUT                (1 << 6)
+#define PMBUS_HAVE_FAN12       (1 << 7)
+#define PMBUS_HAVE_FAN34       (1 << 8)
+#define PMBUS_HAVE_TEMP                (1 << 9)
+#define PMBUS_HAVE_TEMP2       (1 << 10)
+#define PMBUS_HAVE_TEMP3       (1 << 11)
+#define PMBUS_HAVE_STATUS_VOUT (1 << 12)
+#define PMBUS_HAVE_STATUS_IOUT (1 << 13)
+#define PMBUS_HAVE_STATUS_INPUT        (1 << 14)
+#define PMBUS_HAVE_STATUS_TEMP (1 << 15)
+#define PMBUS_HAVE_STATUS_FAN12        (1 << 16)
+#define PMBUS_HAVE_STATUS_FAN34        (1 << 17)
+
+enum pmbus_data_format { linear = 0, direct, vid };
+
+struct pmbus_driver_info {
+       int pages;              /* Total number of pages */
+       enum pmbus_data_format format[PSC_NUM_CLASSES];
+       /*
+        * Support one set of coefficients for each sensor type
+        * Used for chips providing data in direct mode.
+        */
+       int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */
+       int b[PSC_NUM_CLASSES]; /* offset */
+       int R[PSC_NUM_CLASSES]; /* exponent */
+
+       u32 func[PMBUS_PAGES];  /* Functionality, per page */
+       /*
+        * The following functions map manufacturing specific register values
+        * to PMBus standard register values. Specify only if mapping is
+        * necessary.
+        */
+       int (*read_byte_data)(struct i2c_client *client, int page, int reg);
+       int (*read_word_data)(struct i2c_client *client, int page, int reg);
+       int (*write_word_data)(struct i2c_client *client, int page, int reg,
+                              u16 word);
+       /*
+        * The identify function determines supported PMBus functionality.
+        * This function is only necessary if a chip driver supports multiple
+        * chips, and the chip functionality is not pre-determined.
+        */
+       int (*identify)(struct i2c_client *client,
+                       struct pmbus_driver_info *info);
+};
+
+/* Function declarations */
+
+int pmbus_set_page(struct i2c_client *client, u8 page);
+int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
+int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
+int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
+int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
+void pmbus_clear_faults(struct i2c_client *client);
+bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
+bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
+int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
+                  struct pmbus_driver_info *info);
+int pmbus_do_remove(struct i2c_client *client);
+const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client
+                                                     *client);
+
+#endif /* PMBUS_H */
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
new file mode 100644 (file)
index 0000000..5c1b6cf
--- /dev/null
@@ -0,0 +1,1758 @@
+/*
+ * Hardware monitoring driver for PMBus devices
+ *
+ * Copyright (c) 2010, 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/delay.h>
+#include <linux/i2c/pmbus.h>
+#include "pmbus.h"
+
+/*
+ * Constants needed to determine number of sensors, booleans, and labels.
+ */
+#define PMBUS_MAX_INPUT_SENSORS                22      /* 10*volt, 7*curr, 5*power */
+#define PMBUS_VOUT_SENSORS_PER_PAGE    9       /* input, min, max, lcrit,
+                                                  crit, lowest, highest, avg,
+                                                  reset */
+#define PMBUS_IOUT_SENSORS_PER_PAGE    8       /* input, min, max, crit,
+                                                  lowest, highest, avg,
+                                                  reset */
+#define PMBUS_POUT_SENSORS_PER_PAGE    4       /* input, cap, max, crit */
+#define PMBUS_MAX_SENSORS_PER_FAN      1       /* input */
+#define PMBUS_MAX_SENSORS_PER_TEMP     8       /* input, min, max, lcrit,
+                                                  crit, lowest, highest,
+                                                  reset */
+
+#define PMBUS_MAX_INPUT_BOOLEANS       7       /* v: min_alarm, max_alarm,
+                                                  lcrit_alarm, crit_alarm;
+                                                  c: alarm, crit_alarm;
+                                                  p: crit_alarm */
+#define PMBUS_VOUT_BOOLEANS_PER_PAGE   4       /* min_alarm, max_alarm,
+                                                  lcrit_alarm, crit_alarm */
+#define PMBUS_IOUT_BOOLEANS_PER_PAGE   3       /* alarm, lcrit_alarm,
+                                                  crit_alarm */
+#define PMBUS_POUT_BOOLEANS_PER_PAGE   2       /* alarm, crit_alarm */
+#define PMBUS_MAX_BOOLEANS_PER_FAN     2       /* alarm, fault */
+#define PMBUS_MAX_BOOLEANS_PER_TEMP    4       /* min_alarm, max_alarm,
+                                                  lcrit_alarm, crit_alarm */
+
+#define PMBUS_MAX_INPUT_LABELS         4       /* vin, vcap, iin, pin */
+
+/*
+ * status, status_vout, status_iout, status_fans, status_fan34, and status_temp
+ * are paged. status_input is unpaged.
+ */
+#define PB_NUM_STATUS_REG      (PMBUS_PAGES * 6 + 1)
+
+/*
+ * Index into status register array, per status register group
+ */
+#define PB_STATUS_BASE         0
+#define PB_STATUS_VOUT_BASE    (PB_STATUS_BASE + PMBUS_PAGES)
+#define PB_STATUS_IOUT_BASE    (PB_STATUS_VOUT_BASE + PMBUS_PAGES)
+#define PB_STATUS_FAN_BASE     (PB_STATUS_IOUT_BASE + PMBUS_PAGES)
+#define PB_STATUS_FAN34_BASE   (PB_STATUS_FAN_BASE + PMBUS_PAGES)
+#define PB_STATUS_INPUT_BASE   (PB_STATUS_FAN34_BASE + PMBUS_PAGES)
+#define PB_STATUS_TEMP_BASE    (PB_STATUS_INPUT_BASE + 1)
+
+#define PMBUS_NAME_SIZE                24
+
+struct pmbus_sensor {
+       char name[PMBUS_NAME_SIZE];     /* sysfs sensor name */
+       struct sensor_device_attribute attribute;
+       u8 page;                /* page number */
+       u16 reg;                /* register */
+       enum pmbus_sensor_classes class;        /* sensor class */
+       bool update;            /* runtime sensor update needed */
+       int data;               /* Sensor data.
+                                  Negative if there was a read error */
+};
+
+struct pmbus_boolean {
+       char name[PMBUS_NAME_SIZE];     /* sysfs boolean name */
+       struct sensor_device_attribute attribute;
+};
+
+struct pmbus_label {
+       char name[PMBUS_NAME_SIZE];     /* sysfs label name */
+       struct sensor_device_attribute attribute;
+       char label[PMBUS_NAME_SIZE];    /* label */
+};
+
+struct pmbus_data {
+       struct device *hwmon_dev;
+
+       u32 flags;              /* from platform data */
+
+       int exponent;           /* linear mode: exponent for output voltages */
+
+       const struct pmbus_driver_info *info;
+
+       int max_attributes;
+       int num_attributes;
+       struct attribute **attributes;
+       struct attribute_group group;
+
+       /*
+        * Sensors cover both sensor and limit registers.
+        */
+       int max_sensors;
+       int num_sensors;
+       struct pmbus_sensor *sensors;
+       /*
+        * Booleans are used for alarms.
+        * Values are determined from status registers.
+        */
+       int max_booleans;
+       int num_booleans;
+       struct pmbus_boolean *booleans;
+       /*
+        * Labels are used to map generic names (e.g., "in1")
+        * to PMBus specific names (e.g., "vin" or "vout1").
+        */
+       int max_labels;
+       int num_labels;
+       struct pmbus_label *labels;
+
+       struct mutex update_lock;
+       bool valid;
+       unsigned long last_updated;     /* in jiffies */
+
+       /*
+        * A single status register covers multiple attributes,
+        * so we keep them all together.
+        */
+       u8 status[PB_NUM_STATUS_REG];
+
+       u8 currpage;
+};
+
+int pmbus_set_page(struct i2c_client *client, u8 page)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       int rv = 0;
+       int newpage;
+
+       if (page != data->currpage) {
+               rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
+               newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
+               if (newpage != page)
+                       rv = -EINVAL;
+               else
+                       data->currpage = page;
+       }
+       return rv;
+}
+EXPORT_SYMBOL_GPL(pmbus_set_page);
+
+int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
+{
+       int rv;
+
+       if (page >= 0) {
+               rv = pmbus_set_page(client, page);
+               if (rv < 0)
+                       return rv;
+       }
+
+       return i2c_smbus_write_byte(client, value);
+}
+EXPORT_SYMBOL_GPL(pmbus_write_byte);
+
+int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word)
+{
+       int rv;
+
+       rv = pmbus_set_page(client, page);
+       if (rv < 0)
+               return rv;
+
+       return i2c_smbus_write_word_data(client, reg, word);
+}
+EXPORT_SYMBOL_GPL(pmbus_write_word_data);
+
+/*
+ * _pmbus_write_word_data() is similar to pmbus_write_word_data(), but checks if
+ * a device specific mapping function exists and calls it if necessary.
+ */
+static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg,
+                                 u16 word)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       const struct pmbus_driver_info *info = data->info;
+       int status;
+
+       if (info->write_word_data) {
+               status = info->write_word_data(client, page, reg, word);
+               if (status != -ENODATA)
+                       return status;
+       }
+       if (reg >= PMBUS_VIRT_BASE)
+               return -EINVAL;
+       return pmbus_write_word_data(client, page, reg, word);
+}
+
+int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg)
+{
+       int rv;
+
+       rv = pmbus_set_page(client, page);
+       if (rv < 0)
+               return rv;
+
+       return i2c_smbus_read_word_data(client, reg);
+}
+EXPORT_SYMBOL_GPL(pmbus_read_word_data);
+
+/*
+ * _pmbus_read_word_data() is similar to pmbus_read_word_data(), but checks if
+ * a device specific mapping function exists and calls it if necessary.
+ */
+static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       const struct pmbus_driver_info *info = data->info;
+       int status;
+
+       if (info->read_word_data) {
+               status = info->read_word_data(client, page, reg);
+               if (status != -ENODATA)
+                       return status;
+       }
+       if (reg >= PMBUS_VIRT_BASE)
+               return -EINVAL;
+       return pmbus_read_word_data(client, page, reg);
+}
+
+int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
+{
+       int rv;
+
+       if (page >= 0) {
+               rv = pmbus_set_page(client, page);
+               if (rv < 0)
+                       return rv;
+       }
+
+       return i2c_smbus_read_byte_data(client, reg);
+}
+EXPORT_SYMBOL_GPL(pmbus_read_byte_data);
+
+/*
+ * _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if
+ * a device specific mapping function exists and calls it if necessary.
+ */
+static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       const struct pmbus_driver_info *info = data->info;
+       int status;
+
+       if (info->read_byte_data) {
+               status = info->read_byte_data(client, page, reg);
+               if (status != -ENODATA)
+                       return status;
+       }
+       return pmbus_read_byte_data(client, page, reg);
+}
+
+static void pmbus_clear_fault_page(struct i2c_client *client, int page)
+{
+       pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
+}
+
+void pmbus_clear_faults(struct i2c_client *client)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < data->info->pages; i++)
+               pmbus_clear_fault_page(client, i);
+}
+EXPORT_SYMBOL_GPL(pmbus_clear_faults);
+
+static int pmbus_check_status_cml(struct i2c_client *client)
+{
+       int status, status2;
+
+       status = pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE);
+       if (status < 0 || (status & PB_STATUS_CML)) {
+               status2 = pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML);
+               if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND))
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
+{
+       int rv;
+       struct pmbus_data *data = i2c_get_clientdata(client);
+
+       rv = _pmbus_read_byte_data(client, page, reg);
+       if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
+               rv = pmbus_check_status_cml(client);
+       pmbus_clear_fault_page(client, -1);
+       return rv >= 0;
+}
+EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
+
+bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
+{
+       int rv;
+       struct pmbus_data *data = i2c_get_clientdata(client);
+
+       rv = _pmbus_read_word_data(client, page, reg);
+       if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
+               rv = pmbus_check_status_cml(client);
+       pmbus_clear_fault_page(client, -1);
+       return rv >= 0;
+}
+EXPORT_SYMBOL_GPL(pmbus_check_word_register);
+
+const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+
+       return data->info;
+}
+EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
+
+static struct pmbus_data *pmbus_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       const struct pmbus_driver_info *info = data->info;
+
+       mutex_lock(&data->update_lock);
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               int i;
+
+               for (i = 0; i < info->pages; i++)
+                       data->status[PB_STATUS_BASE + i]
+                           = pmbus_read_byte_data(client, i,
+                                                  PMBUS_STATUS_BYTE);
+               for (i = 0; i < info->pages; i++) {
+                       if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT))
+                               continue;
+                       data->status[PB_STATUS_VOUT_BASE + i]
+                         = _pmbus_read_byte_data(client, i, PMBUS_STATUS_VOUT);
+               }
+               for (i = 0; i < info->pages; i++) {
+                       if (!(info->func[i] & PMBUS_HAVE_STATUS_IOUT))
+                               continue;
+                       data->status[PB_STATUS_IOUT_BASE + i]
+                         = _pmbus_read_byte_data(client, i, PMBUS_STATUS_IOUT);
+               }
+               for (i = 0; i < info->pages; i++) {
+                       if (!(info->func[i] & PMBUS_HAVE_STATUS_TEMP))
+                               continue;
+                       data->status[PB_STATUS_TEMP_BASE + i]
+                         = _pmbus_read_byte_data(client, i,
+                                                 PMBUS_STATUS_TEMPERATURE);
+               }
+               for (i = 0; i < info->pages; i++) {
+                       if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN12))
+                               continue;
+                       data->status[PB_STATUS_FAN_BASE + i]
+                         = _pmbus_read_byte_data(client, i,
+                                                 PMBUS_STATUS_FAN_12);
+               }
+
+               for (i = 0; i < info->pages; i++) {
+                       if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN34))
+                               continue;
+                       data->status[PB_STATUS_FAN34_BASE + i]
+                         = _pmbus_read_byte_data(client, i,
+                                                 PMBUS_STATUS_FAN_34);
+               }
+
+               if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
+                       data->status[PB_STATUS_INPUT_BASE]
+                         = _pmbus_read_byte_data(client, 0,
+                                                 PMBUS_STATUS_INPUT);
+
+               for (i = 0; i < data->num_sensors; i++) {
+                       struct pmbus_sensor *sensor = &data->sensors[i];
+
+                       if (!data->valid || sensor->update)
+                               sensor->data
+                                   = _pmbus_read_word_data(client,
+                                                           sensor->page,
+                                                           sensor->reg);
+               }
+               pmbus_clear_faults(client);
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+       mutex_unlock(&data->update_lock);
+       return data;
+}
+
+/*
+ * Convert linear sensor values to milli- or micro-units
+ * depending on sensor type.
+ */
+static long pmbus_reg2data_linear(struct pmbus_data *data,
+                                 struct pmbus_sensor *sensor)
+{
+       s16 exponent;
+       s32 mantissa;
+       long val;
+
+       if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */
+               exponent = data->exponent;
+               mantissa = (u16) sensor->data;
+       } else {                                /* LINEAR11 */
+               exponent = (sensor->data >> 11) & 0x001f;
+               mantissa = sensor->data & 0x07ff;
+
+               if (exponent > 0x0f)
+                       exponent |= 0xffe0;     /* sign extend exponent */
+               if (mantissa > 0x03ff)
+                       mantissa |= 0xfffff800; /* sign extend mantissa */
+       }
+
+       val = mantissa;
+
+       /* scale result to milli-units for all sensors except fans */
+       if (sensor->class != PSC_FAN)
+               val = val * 1000L;
+
+       /* scale result to micro-units for power sensors */
+       if (sensor->class == PSC_POWER)
+               val = val * 1000L;
+
+       if (exponent >= 0)
+               val <<= exponent;
+       else
+               val >>= -exponent;
+
+       return val;
+}
+
+/*
+ * Convert direct sensor values to milli- or micro-units
+ * depending on sensor type.
+ */
+static long pmbus_reg2data_direct(struct pmbus_data *data,
+                                 struct pmbus_sensor *sensor)
+{
+       long val = (s16) sensor->data;
+       long m, b, R;
+
+       m = data->info->m[sensor->class];
+       b = data->info->b[sensor->class];
+       R = data->info->R[sensor->class];
+
+       if (m == 0)
+               return 0;
+
+       /* X = 1/m * (Y * 10^-R - b) */
+       R = -R;
+       /* scale result to milli-units for everything but fans */
+       if (sensor->class != PSC_FAN) {
+               R += 3;
+               b *= 1000;
+       }
+
+       /* scale result to micro-units for power sensors */
+       if (sensor->class == PSC_POWER) {
+               R += 3;
+               b *= 1000;
+       }
+
+       while (R > 0) {
+               val *= 10;
+               R--;
+       }
+       while (R < 0) {
+               val = DIV_ROUND_CLOSEST(val, 10);
+               R++;
+       }
+
+       return (val - b) / m;
+}
+
+/*
+ * Convert VID sensor values to milli- or micro-units
+ * depending on sensor type.
+ * We currently only support VR11.
+ */
+static long pmbus_reg2data_vid(struct pmbus_data *data,
+                              struct pmbus_sensor *sensor)
+{
+       long val = sensor->data;
+
+       if (val < 0x02 || val > 0xb2)
+               return 0;
+       return DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100);
+}
+
+static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
+{
+       long val;
+
+       switch (data->info->format[sensor->class]) {
+       case direct:
+               val = pmbus_reg2data_direct(data, sensor);
+               break;
+       case vid:
+               val = pmbus_reg2data_vid(data, sensor);
+               break;
+       case linear:
+       default:
+               val = pmbus_reg2data_linear(data, sensor);
+               break;
+       }
+       return val;
+}
+
+#define MAX_MANTISSA   (1023 * 1000)
+#define MIN_MANTISSA   (511 * 1000)
+
+static u16 pmbus_data2reg_linear(struct pmbus_data *data,
+                                enum pmbus_sensor_classes class, long val)
+{
+       s16 exponent = 0, mantissa;
+       bool negative = false;
+
+       /* simple case */
+       if (val == 0)
+               return 0;
+
+       if (class == PSC_VOLTAGE_OUT) {
+               /* LINEAR16 does not support negative voltages */
+               if (val < 0)
+                       return 0;
+
+               /*
+                * For a static exponents, we don't have a choice
+                * but to adjust the value to it.
+                */
+               if (data->exponent < 0)
+                       val <<= -data->exponent;
+               else
+                       val >>= data->exponent;
+               val = DIV_ROUND_CLOSEST(val, 1000);
+               return val & 0xffff;
+       }
+
+       if (val < 0) {
+               negative = true;
+               val = -val;
+       }
+
+       /* Power is in uW. Convert to mW before converting. */
+       if (class == PSC_POWER)
+               val = DIV_ROUND_CLOSEST(val, 1000L);
+
+       /*
+        * For simplicity, convert fan data to milli-units
+        * before calculating the exponent.
+        */
+       if (class == PSC_FAN)
+               val = val * 1000;
+
+       /* Reduce large mantissa until it fits into 10 bit */
+       while (val >= MAX_MANTISSA && exponent < 15) {
+               exponent++;
+               val >>= 1;
+       }
+       /* Increase small mantissa to improve precision */
+       while (val < MIN_MANTISSA && exponent > -15) {
+               exponent--;
+               val <<= 1;
+       }
+
+       /* Convert mantissa from milli-units to units */
+       mantissa = DIV_ROUND_CLOSEST(val, 1000);
+
+       /* Ensure that resulting number is within range */
+       if (mantissa > 0x3ff)
+               mantissa = 0x3ff;
+
+       /* restore sign */
+       if (negative)
+               mantissa = -mantissa;
+
+       /* Convert to 5 bit exponent, 11 bit mantissa */
+       return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
+}
+
+static u16 pmbus_data2reg_direct(struct pmbus_data *data,
+                                enum pmbus_sensor_classes class, long val)
+{
+       long m, b, R;
+
+       m = data->info->m[class];
+       b = data->info->b[class];
+       R = data->info->R[class];
+
+       /* Power is in uW. Adjust R and b. */
+       if (class == PSC_POWER) {
+               R -= 3;
+               b *= 1000;
+       }
+
+       /* Calculate Y = (m * X + b) * 10^R */
+       if (class != PSC_FAN) {
+               R -= 3;         /* Adjust R and b for data in milli-units */
+               b *= 1000;
+       }
+       val = val * m + b;
+
+       while (R > 0) {
+               val *= 10;
+               R--;
+       }
+       while (R < 0) {
+               val = DIV_ROUND_CLOSEST(val, 10);
+               R++;
+       }
+
+       return val;
+}
+
+static u16 pmbus_data2reg_vid(struct pmbus_data *data,
+                             enum pmbus_sensor_classes class, long val)
+{
+       val = SENSORS_LIMIT(val, 500, 1600);
+
+       return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625);
+}
+
+static u16 pmbus_data2reg(struct pmbus_data *data,
+                         enum pmbus_sensor_classes class, long val)
+{
+       u16 regval;
+
+       switch (data->info->format[class]) {
+       case direct:
+               regval = pmbus_data2reg_direct(data, class, val);
+               break;
+       case vid:
+               regval = pmbus_data2reg_vid(data, class, val);
+               break;
+       case linear:
+       default:
+               regval = pmbus_data2reg_linear(data, class, val);
+               break;
+       }
+       return regval;
+}
+
+/*
+ * Return boolean calculated from converted data.
+ * <index> defines a status register index and mask, and optionally
+ * two sensor indexes.
+ * The upper half-word references the two sensors,
+ * two sensor indices.
+ * The upper half-word references the two optional sensors,
+ * the lower half word references status register and mask.
+ * The function returns true if (status[reg] & mask) is true and,
+ * if specified, if v1 >= v2.
+ * To determine if an object exceeds upper limits, specify <v, limit>.
+ * To determine if an object exceeds lower limits, specify <limit, v>.
+ *
+ * For booleans created with pmbus_add_boolean_reg(), only the lower 16 bits of
+ * index are set. s1 and s2 (the sensor index values) are zero in this case.
+ * The function returns true if (status[reg] & mask) is true.
+ *
+ * If the boolean was created with pmbus_add_boolean_cmp(), a comparison against
+ * a specified limit has to be performed to determine the boolean result.
+ * In this case, the function returns true if v1 >= v2 (where v1 and v2 are
+ * sensor values referenced by sensor indices s1 and s2).
+ *
+ * To determine if an object exceeds upper limits, specify <s1,s2> = <v,limit>.
+ * To determine if an object exceeds lower limits, specify <s1,s2> = <limit,v>.
+ *
+ * If a negative value is stored in any of the referenced registers, this value
+ * reflects an error code which will be returned.
+ */
+static int pmbus_get_boolean(struct pmbus_data *data, int index, int *val)
+{
+       u8 s1 = (index >> 24) & 0xff;
+       u8 s2 = (index >> 16) & 0xff;
+       u8 reg = (index >> 8) & 0xff;
+       u8 mask = index & 0xff;
+       int status;
+       u8 regval;
+
+       status = data->status[reg];
+       if (status < 0)
+               return status;
+
+       regval = status & mask;
+       if (!s1 && !s2)
+               *val = !!regval;
+       else {
+               long v1, v2;
+               struct pmbus_sensor *sensor1, *sensor2;
+
+               sensor1 = &data->sensors[s1];
+               if (sensor1->data < 0)
+                       return sensor1->data;
+               sensor2 = &data->sensors[s2];
+               if (sensor2->data < 0)
+                       return sensor2->data;
+
+               v1 = pmbus_reg2data(data, sensor1);
+               v2 = pmbus_reg2data(data, sensor2);
+               *val = !!(regval && v1 >= v2);
+       }
+       return 0;
+}
+
+static ssize_t pmbus_show_boolean(struct device *dev,
+                                 struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct pmbus_data *data = pmbus_update_device(dev);
+       int val;
+       int err;
+
+       err = pmbus_get_boolean(data, attr->index, &val);
+       if (err)
+               return err;
+       return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t pmbus_show_sensor(struct device *dev,
+                                struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct pmbus_data *data = pmbus_update_device(dev);
+       struct pmbus_sensor *sensor;
+
+       sensor = &data->sensors[attr->index];
+       if (sensor->data < 0)
+               return sensor->data;
+
+       return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor));
+}
+
+static ssize_t pmbus_set_sensor(struct device *dev,
+                               struct device_attribute *devattr,
+                               const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       struct pmbus_sensor *sensor = &data->sensors[attr->index];
+       ssize_t rv = count;
+       long val = 0;
+       int ret;
+       u16 regval;
+
+       if (strict_strtol(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       mutex_lock(&data->update_lock);
+       regval = pmbus_data2reg(data, sensor->class, val);
+       ret = _pmbus_write_word_data(client, sensor->page, sensor->reg, regval);
+       if (ret < 0)
+               rv = ret;
+       else
+               data->sensors[attr->index].data = regval;
+       mutex_unlock(&data->update_lock);
+       return rv;
+}
+
+static ssize_t pmbus_show_label(struct device *dev,
+                               struct device_attribute *da, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       data->labels[attr->index].label);
+}
+
+#define PMBUS_ADD_ATTR(data, _name, _idx, _mode, _type, _show, _set)   \
+do {                                                                   \
+       struct sensor_device_attribute *a                               \
+           = &data->_type##s[data->num_##_type##s].attribute;          \
+       BUG_ON(data->num_attributes >= data->max_attributes);           \
+       sysfs_attr_init(&a->dev_attr.attr);                             \
+       a->dev_attr.attr.name = _name;                                  \
+       a->dev_attr.attr.mode = _mode;                                  \
+       a->dev_attr.show = _show;                                       \
+       a->dev_attr.store = _set;                                       \
+       a->index = _idx;                                                \
+       data->attributes[data->num_attributes] = &a->dev_attr.attr;     \
+       data->num_attributes++;                                         \
+} while (0)
+
+#define PMBUS_ADD_GET_ATTR(data, _name, _type, _idx)                   \
+       PMBUS_ADD_ATTR(data, _name, _idx, S_IRUGO, _type,               \
+                      pmbus_show_##_type,  NULL)
+
+#define PMBUS_ADD_SET_ATTR(data, _name, _type, _idx)                   \
+       PMBUS_ADD_ATTR(data, _name, _idx, S_IWUSR | S_IRUGO, _type,     \
+                      pmbus_show_##_type, pmbus_set_##_type)
+
+static void pmbus_add_boolean(struct pmbus_data *data,
+                             const char *name, const char *type, int seq,
+                             int idx)
+{
+       struct pmbus_boolean *boolean;
+
+       BUG_ON(data->num_booleans >= data->max_booleans);
+
+       boolean = &data->booleans[data->num_booleans];
+
+       snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s",
+                name, seq, type);
+       PMBUS_ADD_GET_ATTR(data, boolean->name, boolean, idx);
+       data->num_booleans++;
+}
+
+static void pmbus_add_boolean_reg(struct pmbus_data *data,
+                                 const char *name, const char *type,
+                                 int seq, int reg, int bit)
+{
+       pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit);
+}
+
+static void pmbus_add_boolean_cmp(struct pmbus_data *data,
+                                 const char *name, const char *type,
+                                 int seq, int i1, int i2, int reg, int mask)
+{
+       pmbus_add_boolean(data, name, type, seq,
+                         (i1 << 24) | (i2 << 16) | (reg << 8) | mask);
+}
+
+static void pmbus_add_sensor(struct pmbus_data *data,
+                            const char *name, const char *type, int seq,
+                            int page, int reg, enum pmbus_sensor_classes class,
+                            bool update, bool readonly)
+{
+       struct pmbus_sensor *sensor;
+
+       BUG_ON(data->num_sensors >= data->max_sensors);
+
+       sensor = &data->sensors[data->num_sensors];
+       snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s",
+                name, seq, type);
+       sensor->page = page;
+       sensor->reg = reg;
+       sensor->class = class;
+       sensor->update = update;
+       if (readonly)
+               PMBUS_ADD_GET_ATTR(data, sensor->name, sensor,
+                                  data->num_sensors);
+       else
+               PMBUS_ADD_SET_ATTR(data, sensor->name, sensor,
+                                  data->num_sensors);
+       data->num_sensors++;
+}
+
+static void pmbus_add_label(struct pmbus_data *data,
+                           const char *name, int seq,
+                           const char *lstring, int index)
+{
+       struct pmbus_label *label;
+
+       BUG_ON(data->num_labels >= data->max_labels);
+
+       label = &data->labels[data->num_labels];
+       snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
+       if (!index)
+               strncpy(label->label, lstring, sizeof(label->label) - 1);
+       else
+               snprintf(label->label, sizeof(label->label), "%s%d", lstring,
+                        index);
+
+       PMBUS_ADD_GET_ATTR(data, label->name, label, data->num_labels);
+       data->num_labels++;
+}
+
+/*
+ * Determine maximum number of sensors, booleans, and labels.
+ * To keep things simple, only make a rough high estimate.
+ */
+static void pmbus_find_max_attr(struct i2c_client *client,
+                               struct pmbus_data *data)
+{
+       const struct pmbus_driver_info *info = data->info;
+       int page, max_sensors, max_booleans, max_labels;
+
+       max_sensors = PMBUS_MAX_INPUT_SENSORS;
+       max_booleans = PMBUS_MAX_INPUT_BOOLEANS;
+       max_labels = PMBUS_MAX_INPUT_LABELS;
+
+       for (page = 0; page < info->pages; page++) {
+               if (info->func[page] & PMBUS_HAVE_VOUT) {
+                       max_sensors += PMBUS_VOUT_SENSORS_PER_PAGE;
+                       max_booleans += PMBUS_VOUT_BOOLEANS_PER_PAGE;
+                       max_labels++;
+               }
+               if (info->func[page] & PMBUS_HAVE_IOUT) {
+                       max_sensors += PMBUS_IOUT_SENSORS_PER_PAGE;
+                       max_booleans += PMBUS_IOUT_BOOLEANS_PER_PAGE;
+                       max_labels++;
+               }
+               if (info->func[page] & PMBUS_HAVE_POUT) {
+                       max_sensors += PMBUS_POUT_SENSORS_PER_PAGE;
+                       max_booleans += PMBUS_POUT_BOOLEANS_PER_PAGE;
+                       max_labels++;
+               }
+               if (info->func[page] & PMBUS_HAVE_FAN12) {
+                       max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
+                       max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
+               }
+               if (info->func[page] & PMBUS_HAVE_FAN34) {
+                       max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
+                       max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
+               }
+               if (info->func[page] & PMBUS_HAVE_TEMP) {
+                       max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
+                       max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
+               }
+               if (info->func[page] & PMBUS_HAVE_TEMP2) {
+                       max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
+                       max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
+               }
+               if (info->func[page] & PMBUS_HAVE_TEMP3) {
+                       max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
+                       max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
+               }
+       }
+       data->max_sensors = max_sensors;
+       data->max_booleans = max_booleans;
+       data->max_labels = max_labels;
+       data->max_attributes = max_sensors + max_booleans + max_labels;
+}
+
+/*
+ * Search for attributes. Allocate sensors, booleans, and labels as needed.
+ */
+
+/*
+ * The pmbus_limit_attr structure describes a single limit attribute
+ * and its associated alarm attribute.
+ */
+struct pmbus_limit_attr {
+       u16 reg;                /* Limit register */
+       bool update;            /* True if register needs updates */
+       const char *attr;       /* Attribute name */
+       const char *alarm;      /* Alarm attribute name */
+       u32 sbit;               /* Alarm attribute status bit */
+};
+
+/*
+ * The pmbus_sensor_attr structure describes one sensor attribute. This
+ * description includes a reference to the associated limit attributes.
+ */
+struct pmbus_sensor_attr {
+       u8 reg;                         /* sensor register */
+       enum pmbus_sensor_classes class;/* sensor class */
+       const char *label;              /* sensor label */
+       bool paged;                     /* true if paged sensor */
+       bool update;                    /* true if update needed */
+       bool compare;                   /* true if compare function needed */
+       u32 func;                       /* sensor mask */
+       u32 sfunc;                      /* sensor status mask */
+       int sbase;                      /* status base register */
+       u32 gbit;                       /* generic status bit */
+       const struct pmbus_limit_attr *limit;/* limit registers */
+       int nlimit;                     /* # of limit registers */
+};
+
+/*
+ * Add a set of limit attributes and, if supported, the associated
+ * alarm attributes.
+ */
+static bool pmbus_add_limit_attrs(struct i2c_client *client,
+                                 struct pmbus_data *data,
+                                 const struct pmbus_driver_info *info,
+                                 const char *name, int index, int page,
+                                 int cbase,
+                                 const struct pmbus_sensor_attr *attr)
+{
+       const struct pmbus_limit_attr *l = attr->limit;
+       int nlimit = attr->nlimit;
+       bool have_alarm = false;
+       int i, cindex;
+
+       for (i = 0; i < nlimit; i++) {
+               if (pmbus_check_word_register(client, page, l->reg)) {
+                       cindex = data->num_sensors;
+                       pmbus_add_sensor(data, name, l->attr, index, page,
+                                        l->reg, attr->class,
+                                        attr->update || l->update,
+                                        false);
+                       if (l->sbit && (info->func[page] & attr->sfunc)) {
+                               if (attr->compare) {
+                                       pmbus_add_boolean_cmp(data, name,
+                                               l->alarm, index,
+                                               cbase, cindex,
+                                               attr->sbase + page, l->sbit);
+                               } else {
+                                       pmbus_add_boolean_reg(data, name,
+                                               l->alarm, index,
+                                               attr->sbase + page, l->sbit);
+                               }
+                               have_alarm = true;
+                       }
+               }
+               l++;
+       }
+       return have_alarm;
+}
+
+static void pmbus_add_sensor_attrs_one(struct i2c_client *client,
+                                      struct pmbus_data *data,
+                                      const struct pmbus_driver_info *info,
+                                      const char *name,
+                                      int index, int page,
+                                      const struct pmbus_sensor_attr *attr)
+{
+       bool have_alarm;
+       int cbase = data->num_sensors;
+
+       if (attr->label)
+               pmbus_add_label(data, name, index, attr->label,
+                               attr->paged ? page + 1 : 0);
+       pmbus_add_sensor(data, name, "input", index, page, attr->reg,
+                        attr->class, true, true);
+       if (attr->sfunc) {
+               have_alarm = pmbus_add_limit_attrs(client, data, info, name,
+                                                  index, page, cbase, attr);
+               /*
+                * Add generic alarm attribute only if there are no individual
+                * alarm attributes, if there is a global alarm bit, and if
+                * the generic status register for this page is accessible.
+                */
+               if (!have_alarm && attr->gbit &&
+                   pmbus_check_byte_register(client, page, PMBUS_STATUS_BYTE))
+                       pmbus_add_boolean_reg(data, name, "alarm", index,
+                                             PB_STATUS_BASE + page,
+                                             attr->gbit);
+       }
+}
+
+static void pmbus_add_sensor_attrs(struct i2c_client *client,
+                                  struct pmbus_data *data,
+                                  const char *name,
+                                  const struct pmbus_sensor_attr *attrs,
+                                  int nattrs)
+{
+       const struct pmbus_driver_info *info = data->info;
+       int index, i;
+
+       index = 1;
+       for (i = 0; i < nattrs; i++) {
+               int page, pages;
+
+               pages = attrs->paged ? info->pages : 1;
+               for (page = 0; page < pages; page++) {
+                       if (!(info->func[page] & attrs->func))
+                               continue;
+                       pmbus_add_sensor_attrs_one(client, data, info, name,
+                                                  index, page, attrs);
+                       index++;
+               }
+               attrs++;
+       }
+}
+
+static const struct pmbus_limit_attr vin_limit_attrs[] = {
+       {
+               .reg = PMBUS_VIN_UV_WARN_LIMIT,
+               .attr = "min",
+               .alarm = "min_alarm",
+               .sbit = PB_VOLTAGE_UV_WARNING,
+       }, {
+               .reg = PMBUS_VIN_UV_FAULT_LIMIT,
+               .attr = "lcrit",
+               .alarm = "lcrit_alarm",
+               .sbit = PB_VOLTAGE_UV_FAULT,
+       }, {
+               .reg = PMBUS_VIN_OV_WARN_LIMIT,
+               .attr = "max",
+               .alarm = "max_alarm",
+               .sbit = PB_VOLTAGE_OV_WARNING,
+       }, {
+               .reg = PMBUS_VIN_OV_FAULT_LIMIT,
+               .attr = "crit",
+               .alarm = "crit_alarm",
+               .sbit = PB_VOLTAGE_OV_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_READ_VIN_AVG,
+               .update = true,
+               .attr = "average",
+       }, {
+               .reg = PMBUS_VIRT_READ_VIN_MIN,
+               .update = true,
+               .attr = "lowest",
+       }, {
+               .reg = PMBUS_VIRT_READ_VIN_MAX,
+               .update = true,
+               .attr = "highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_VIN_HISTORY,
+               .attr = "reset_history",
+       },
+};
+
+static const struct pmbus_limit_attr vout_limit_attrs[] = {
+       {
+               .reg = PMBUS_VOUT_UV_WARN_LIMIT,
+               .attr = "min",
+               .alarm = "min_alarm",
+               .sbit = PB_VOLTAGE_UV_WARNING,
+       }, {
+               .reg = PMBUS_VOUT_UV_FAULT_LIMIT,
+               .attr = "lcrit",
+               .alarm = "lcrit_alarm",
+               .sbit = PB_VOLTAGE_UV_FAULT,
+       }, {
+               .reg = PMBUS_VOUT_OV_WARN_LIMIT,
+               .attr = "max",
+               .alarm = "max_alarm",
+               .sbit = PB_VOLTAGE_OV_WARNING,
+       }, {
+               .reg = PMBUS_VOUT_OV_FAULT_LIMIT,
+               .attr = "crit",
+               .alarm = "crit_alarm",
+               .sbit = PB_VOLTAGE_OV_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_READ_VOUT_AVG,
+               .update = true,
+               .attr = "average",
+       }, {
+               .reg = PMBUS_VIRT_READ_VOUT_MIN,
+               .update = true,
+               .attr = "lowest",
+       }, {
+               .reg = PMBUS_VIRT_READ_VOUT_MAX,
+               .update = true,
+               .attr = "highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_VOUT_HISTORY,
+               .attr = "reset_history",
+       }
+};
+
+static const struct pmbus_sensor_attr voltage_attributes[] = {
+       {
+               .reg = PMBUS_READ_VIN,
+               .class = PSC_VOLTAGE_IN,
+               .label = "vin",
+               .func = PMBUS_HAVE_VIN,
+               .sfunc = PMBUS_HAVE_STATUS_INPUT,
+               .sbase = PB_STATUS_INPUT_BASE,
+               .gbit = PB_STATUS_VIN_UV,
+               .limit = vin_limit_attrs,
+               .nlimit = ARRAY_SIZE(vin_limit_attrs),
+       }, {
+               .reg = PMBUS_READ_VCAP,
+               .class = PSC_VOLTAGE_IN,
+               .label = "vcap",
+               .func = PMBUS_HAVE_VCAP,
+       }, {
+               .reg = PMBUS_READ_VOUT,
+               .class = PSC_VOLTAGE_OUT,
+               .label = "vout",
+               .paged = true,
+               .func = PMBUS_HAVE_VOUT,
+               .sfunc = PMBUS_HAVE_STATUS_VOUT,
+               .sbase = PB_STATUS_VOUT_BASE,
+               .gbit = PB_STATUS_VOUT_OV,
+               .limit = vout_limit_attrs,
+               .nlimit = ARRAY_SIZE(vout_limit_attrs),
+       }
+};
+
+/* Current attributes */
+
+static const struct pmbus_limit_attr iin_limit_attrs[] = {
+       {
+               .reg = PMBUS_IIN_OC_WARN_LIMIT,
+               .attr = "max",
+               .alarm = "max_alarm",
+               .sbit = PB_IIN_OC_WARNING,
+       }, {
+               .reg = PMBUS_IIN_OC_FAULT_LIMIT,
+               .attr = "crit",
+               .alarm = "crit_alarm",
+               .sbit = PB_IIN_OC_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_READ_IIN_AVG,
+               .update = true,
+               .attr = "average",
+       }, {
+               .reg = PMBUS_VIRT_READ_IIN_MIN,
+               .update = true,
+               .attr = "lowest",
+       }, {
+               .reg = PMBUS_VIRT_READ_IIN_MAX,
+               .update = true,
+               .attr = "highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_IIN_HISTORY,
+               .attr = "reset_history",
+       }
+};
+
+static const struct pmbus_limit_attr iout_limit_attrs[] = {
+       {
+               .reg = PMBUS_IOUT_OC_WARN_LIMIT,
+               .attr = "max",
+               .alarm = "max_alarm",
+               .sbit = PB_IOUT_OC_WARNING,
+       }, {
+               .reg = PMBUS_IOUT_UC_FAULT_LIMIT,
+               .attr = "lcrit",
+               .alarm = "lcrit_alarm",
+               .sbit = PB_IOUT_UC_FAULT,
+       }, {
+               .reg = PMBUS_IOUT_OC_FAULT_LIMIT,
+               .attr = "crit",
+               .alarm = "crit_alarm",
+               .sbit = PB_IOUT_OC_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_READ_IOUT_AVG,
+               .update = true,
+               .attr = "average",
+       }, {
+               .reg = PMBUS_VIRT_READ_IOUT_MIN,
+               .update = true,
+               .attr = "lowest",
+       }, {
+               .reg = PMBUS_VIRT_READ_IOUT_MAX,
+               .update = true,
+               .attr = "highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_IOUT_HISTORY,
+               .attr = "reset_history",
+       }
+};
+
+static const struct pmbus_sensor_attr current_attributes[] = {
+       {
+               .reg = PMBUS_READ_IIN,
+               .class = PSC_CURRENT_IN,
+               .label = "iin",
+               .func = PMBUS_HAVE_IIN,
+               .sfunc = PMBUS_HAVE_STATUS_INPUT,
+               .sbase = PB_STATUS_INPUT_BASE,
+               .limit = iin_limit_attrs,
+               .nlimit = ARRAY_SIZE(iin_limit_attrs),
+       }, {
+               .reg = PMBUS_READ_IOUT,
+               .class = PSC_CURRENT_OUT,
+               .label = "iout",
+               .paged = true,
+               .func = PMBUS_HAVE_IOUT,
+               .sfunc = PMBUS_HAVE_STATUS_IOUT,
+               .sbase = PB_STATUS_IOUT_BASE,
+               .gbit = PB_STATUS_IOUT_OC,
+               .limit = iout_limit_attrs,
+               .nlimit = ARRAY_SIZE(iout_limit_attrs),
+       }
+};
+
+/* Power attributes */
+
+static const struct pmbus_limit_attr pin_limit_attrs[] = {
+       {
+               .reg = PMBUS_PIN_OP_WARN_LIMIT,
+               .attr = "max",
+               .alarm = "alarm",
+               .sbit = PB_PIN_OP_WARNING,
+       }, {
+               .reg = PMBUS_VIRT_READ_PIN_AVG,
+               .update = true,
+               .attr = "average",
+       }, {
+               .reg = PMBUS_VIRT_READ_PIN_MAX,
+               .update = true,
+               .attr = "input_highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_PIN_HISTORY,
+               .attr = "reset_history",
+       }
+};
+
+static const struct pmbus_limit_attr pout_limit_attrs[] = {
+       {
+               .reg = PMBUS_POUT_MAX,
+               .attr = "cap",
+               .alarm = "cap_alarm",
+               .sbit = PB_POWER_LIMITING,
+       }, {
+               .reg = PMBUS_POUT_OP_WARN_LIMIT,
+               .attr = "max",
+               .alarm = "max_alarm",
+               .sbit = PB_POUT_OP_WARNING,
+       }, {
+               .reg = PMBUS_POUT_OP_FAULT_LIMIT,
+               .attr = "crit",
+               .alarm = "crit_alarm",
+               .sbit = PB_POUT_OP_FAULT,
+       }
+};
+
+static const struct pmbus_sensor_attr power_attributes[] = {
+       {
+               .reg = PMBUS_READ_PIN,
+               .class = PSC_POWER,
+               .label = "pin",
+               .func = PMBUS_HAVE_PIN,
+               .sfunc = PMBUS_HAVE_STATUS_INPUT,
+               .sbase = PB_STATUS_INPUT_BASE,
+               .limit = pin_limit_attrs,
+               .nlimit = ARRAY_SIZE(pin_limit_attrs),
+       }, {
+               .reg = PMBUS_READ_POUT,
+               .class = PSC_POWER,
+               .label = "pout",
+               .paged = true,
+               .func = PMBUS_HAVE_POUT,
+               .sfunc = PMBUS_HAVE_STATUS_IOUT,
+               .sbase = PB_STATUS_IOUT_BASE,
+               .limit = pout_limit_attrs,
+               .nlimit = ARRAY_SIZE(pout_limit_attrs),
+       }
+};
+
+/* Temperature atributes */
+
+static const struct pmbus_limit_attr temp_limit_attrs[] = {
+       {
+               .reg = PMBUS_UT_WARN_LIMIT,
+               .attr = "min",
+               .alarm = "min_alarm",
+               .sbit = PB_TEMP_UT_WARNING,
+       }, {
+               .reg = PMBUS_UT_FAULT_LIMIT,
+               .attr = "lcrit",
+               .alarm = "lcrit_alarm",
+               .sbit = PB_TEMP_UT_FAULT,
+       }, {
+               .reg = PMBUS_OT_WARN_LIMIT,
+               .attr = "max",
+               .alarm = "max_alarm",
+               .sbit = PB_TEMP_OT_WARNING,
+       }, {
+               .reg = PMBUS_OT_FAULT_LIMIT,
+               .attr = "crit",
+               .alarm = "crit_alarm",
+               .sbit = PB_TEMP_OT_FAULT,
+       }, {
+               .reg = PMBUS_VIRT_READ_TEMP_MIN,
+               .attr = "lowest",
+       }, {
+               .reg = PMBUS_VIRT_READ_TEMP_MAX,
+               .attr = "highest",
+       }, {
+               .reg = PMBUS_VIRT_RESET_TEMP_HISTORY,
+               .attr = "reset_history",
+       }
+};
+
+static const struct pmbus_limit_attr temp_limit_attrs23[] = {
+       {
+               .reg = PMBUS_UT_WARN_LIMIT,
+               .attr = "min",
+               .alarm = "min_alarm",
+               .sbit = PB_TEMP_UT_WARNING,
+       }, {
+               .reg = PMBUS_UT_FAULT_LIMIT,
+               .attr = "lcrit",
+               .alarm = "lcrit_alarm",
+               .sbit = PB_TEMP_UT_FAULT,
+       }, {
+               .reg = PMBUS_OT_WARN_LIMIT,
+               .attr = "max",
+               .alarm = "max_alarm",
+               .sbit = PB_TEMP_OT_WARNING,
+       }, {
+               .reg = PMBUS_OT_FAULT_LIMIT,
+               .attr = "crit",
+               .alarm = "crit_alarm",
+               .sbit = PB_TEMP_OT_FAULT,
+       }
+};
+
+static const struct pmbus_sensor_attr temp_attributes[] = {
+       {
+               .reg = PMBUS_READ_TEMPERATURE_1,
+               .class = PSC_TEMPERATURE,
+               .paged = true,
+               .update = true,
+               .compare = true,
+               .func = PMBUS_HAVE_TEMP,
+               .sfunc = PMBUS_HAVE_STATUS_TEMP,
+               .sbase = PB_STATUS_TEMP_BASE,
+               .gbit = PB_STATUS_TEMPERATURE,
+               .limit = temp_limit_attrs,
+               .nlimit = ARRAY_SIZE(temp_limit_attrs),
+       }, {
+               .reg = PMBUS_READ_TEMPERATURE_2,
+               .class = PSC_TEMPERATURE,
+               .paged = true,
+               .update = true,
+               .compare = true,
+               .func = PMBUS_HAVE_TEMP2,
+               .sfunc = PMBUS_HAVE_STATUS_TEMP,
+               .sbase = PB_STATUS_TEMP_BASE,
+               .gbit = PB_STATUS_TEMPERATURE,
+               .limit = temp_limit_attrs23,
+               .nlimit = ARRAY_SIZE(temp_limit_attrs23),
+       }, {
+               .reg = PMBUS_READ_TEMPERATURE_3,
+               .class = PSC_TEMPERATURE,
+               .paged = true,
+               .update = true,
+               .compare = true,
+               .func = PMBUS_HAVE_TEMP3,
+               .sfunc = PMBUS_HAVE_STATUS_TEMP,
+               .sbase = PB_STATUS_TEMP_BASE,
+               .gbit = PB_STATUS_TEMPERATURE,
+               .limit = temp_limit_attrs23,
+               .nlimit = ARRAY_SIZE(temp_limit_attrs23),
+       }
+};
+
+static const int pmbus_fan_registers[] = {
+       PMBUS_READ_FAN_SPEED_1,
+       PMBUS_READ_FAN_SPEED_2,
+       PMBUS_READ_FAN_SPEED_3,
+       PMBUS_READ_FAN_SPEED_4
+};
+
+static const int pmbus_fan_config_registers[] = {
+       PMBUS_FAN_CONFIG_12,
+       PMBUS_FAN_CONFIG_12,
+       PMBUS_FAN_CONFIG_34,
+       PMBUS_FAN_CONFIG_34
+};
+
+static const int pmbus_fan_status_registers[] = {
+       PMBUS_STATUS_FAN_12,
+       PMBUS_STATUS_FAN_12,
+       PMBUS_STATUS_FAN_34,
+       PMBUS_STATUS_FAN_34
+};
+
+static const u32 pmbus_fan_flags[] = {
+       PMBUS_HAVE_FAN12,
+       PMBUS_HAVE_FAN12,
+       PMBUS_HAVE_FAN34,
+       PMBUS_HAVE_FAN34
+};
+
+static const u32 pmbus_fan_status_flags[] = {
+       PMBUS_HAVE_STATUS_FAN12,
+       PMBUS_HAVE_STATUS_FAN12,
+       PMBUS_HAVE_STATUS_FAN34,
+       PMBUS_HAVE_STATUS_FAN34
+};
+
+/* Fans */
+static void pmbus_add_fan_attributes(struct i2c_client *client,
+                                    struct pmbus_data *data)
+{
+       const struct pmbus_driver_info *info = data->info;
+       int index = 1;
+       int page;
+
+       for (page = 0; page < info->pages; page++) {
+               int f;
+
+               for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) {
+                       int regval;
+
+                       if (!(info->func[page] & pmbus_fan_flags[f]))
+                               break;
+
+                       if (!pmbus_check_word_register(client, page,
+                                                      pmbus_fan_registers[f]))
+                               break;
+
+                       /*
+                        * Skip fan if not installed.
+                        * Each fan configuration register covers multiple fans,
+                        * so we have to do some magic.
+                        */
+                       regval = _pmbus_read_byte_data(client, page,
+                               pmbus_fan_config_registers[f]);
+                       if (regval < 0 ||
+                           (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
+                               continue;
+
+                       pmbus_add_sensor(data, "fan", "input", index, page,
+                                        pmbus_fan_registers[f], PSC_FAN, true,
+                                        true);
+
+                       /*
+                        * Each fan status register covers multiple fans,
+                        * so we have to do some magic.
+                        */
+                       if ((info->func[page] & pmbus_fan_status_flags[f]) &&
+                           pmbus_check_byte_register(client,
+                                       page, pmbus_fan_status_registers[f])) {
+                               int base;
+
+                               if (f > 1)      /* fan 3, 4 */
+                                       base = PB_STATUS_FAN34_BASE + page;
+                               else
+                                       base = PB_STATUS_FAN_BASE + page;
+                               pmbus_add_boolean_reg(data, "fan", "alarm",
+                                       index, base,
+                                       PB_FAN_FAN1_WARNING >> (f & 1));
+                               pmbus_add_boolean_reg(data, "fan", "fault",
+                                       index, base,
+                                       PB_FAN_FAN1_FAULT >> (f & 1));
+                       }
+                       index++;
+               }
+       }
+}
+
+static void pmbus_find_attributes(struct i2c_client *client,
+                                 struct pmbus_data *data)
+{
+       /* Voltage sensors */
+       pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
+                              ARRAY_SIZE(voltage_attributes));
+
+       /* Current sensors */
+       pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
+                              ARRAY_SIZE(current_attributes));
+
+       /* Power sensors */
+       pmbus_add_sensor_attrs(client, data, "power", power_attributes,
+                              ARRAY_SIZE(power_attributes));
+
+       /* Temperature sensors */
+       pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
+                              ARRAY_SIZE(temp_attributes));
+
+       /* Fans */
+       pmbus_add_fan_attributes(client, data);
+}
+
+/*
+ * Identify chip parameters.
+ * This function is called for all chips.
+ */
+static int pmbus_identify_common(struct i2c_client *client,
+                                struct pmbus_data *data)
+{
+       int vout_mode = -1, exponent;
+
+       if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE))
+               vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
+       if (vout_mode >= 0 && vout_mode != 0xff) {
+               /*
+                * Not all chips support the VOUT_MODE command,
+                * so a failure to read it is not an error.
+                */
+               switch (vout_mode >> 5) {
+               case 0: /* linear mode      */
+                       if (data->info->format[PSC_VOLTAGE_OUT] != linear)
+                               return -ENODEV;
+
+                       exponent = vout_mode & 0x1f;
+                       /* and sign-extend it */
+                       if (exponent & 0x10)
+                               exponent |= ~0x1f;
+                       data->exponent = exponent;
+                       break;
+               case 1: /* VID mode         */
+                       if (data->info->format[PSC_VOLTAGE_OUT] != vid)
+                               return -ENODEV;
+                       break;
+               case 2: /* direct mode      */
+                       if (data->info->format[PSC_VOLTAGE_OUT] != direct)
+                               return -ENODEV;
+                       break;
+               default:
+                       return -ENODEV;
+               }
+       }
+
+       /* Determine maximum number of sensors, booleans, and labels */
+       pmbus_find_max_attr(client, data);
+       pmbus_clear_fault_page(client, 0);
+       return 0;
+}
+
+int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
+                  struct pmbus_driver_info *info)
+{
+       const struct pmbus_platform_data *pdata = client->dev.platform_data;
+       struct pmbus_data *data;
+       int ret;
+
+       if (!info) {
+               dev_err(&client->dev, "Missing chip information");
+               return -ENODEV;
+       }
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
+                                    | I2C_FUNC_SMBUS_BYTE_DATA
+                                    | I2C_FUNC_SMBUS_WORD_DATA))
+               return -ENODEV;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               dev_err(&client->dev, "No memory to allocate driver data\n");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* Bail out if PMBus status register does not exist. */
+       if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) {
+               dev_err(&client->dev, "PMBus status register not found\n");
+               ret = -ENODEV;
+               goto out_data;
+       }
+
+       if (pdata)
+               data->flags = pdata->flags;
+       data->info = info;
+
+       pmbus_clear_faults(client);
+
+       if (info->identify) {
+               ret = (*info->identify)(client, info);
+               if (ret < 0) {
+                       dev_err(&client->dev, "Chip identification failed\n");
+                       goto out_data;
+               }
+       }
+
+       if (info->pages <= 0 || info->pages > PMBUS_PAGES) {
+               dev_err(&client->dev, "Bad number of PMBus pages: %d\n",
+                       info->pages);
+               ret = -EINVAL;
+               goto out_data;
+       }
+
+       ret = pmbus_identify_common(client, data);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to identify chip capabilities\n");
+               goto out_data;
+       }
+
+       ret = -ENOMEM;
+       data->sensors = kzalloc(sizeof(struct pmbus_sensor) * data->max_sensors,
+                               GFP_KERNEL);
+       if (!data->sensors) {
+               dev_err(&client->dev, "No memory to allocate sensor data\n");
+               goto out_data;
+       }
+
+       data->booleans = kzalloc(sizeof(struct pmbus_boolean)
+                                * data->max_booleans, GFP_KERNEL);
+       if (!data->booleans) {
+               dev_err(&client->dev, "No memory to allocate boolean data\n");
+               goto out_sensors;
+       }
+
+       data->labels = kzalloc(sizeof(struct pmbus_label) * data->max_labels,
+                              GFP_KERNEL);
+       if (!data->labels) {
+               dev_err(&client->dev, "No memory to allocate label data\n");
+               goto out_booleans;
+       }
+
+       data->attributes = kzalloc(sizeof(struct attribute *)
+                                  * data->max_attributes, GFP_KERNEL);
+       if (!data->attributes) {
+               dev_err(&client->dev, "No memory to allocate attribute data\n");
+               goto out_labels;
+       }
+
+       pmbus_find_attributes(client, data);
+
+       /*
+        * If there are no attributes, something is wrong.
+        * Bail out instead of trying to register nothing.
+        */
+       if (!data->num_attributes) {
+               dev_err(&client->dev, "No attributes found\n");
+               ret = -ENODEV;
+               goto out_attributes;
+       }
+
+       /* Register sysfs hooks */
+       data->group.attrs = data->attributes;
+       ret = sysfs_create_group(&client->dev.kobj, &data->group);
+       if (ret) {
+               dev_err(&client->dev, "Failed to create sysfs entries\n");
+               goto out_attributes;
+       }
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               ret = PTR_ERR(data->hwmon_dev);
+               dev_err(&client->dev, "Failed to register hwmon device\n");
+               goto out_hwmon_device_register;
+       }
+       return 0;
+
+out_hwmon_device_register:
+       sysfs_remove_group(&client->dev.kobj, &data->group);
+out_attributes:
+       kfree(data->attributes);
+out_labels:
+       kfree(data->labels);
+out_booleans:
+       kfree(data->booleans);
+out_sensors:
+       kfree(data->sensors);
+out_data:
+       kfree(data);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(pmbus_do_probe);
+
+int pmbus_do_remove(struct i2c_client *client)
+{
+       struct pmbus_data *data = i2c_get_clientdata(client);
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &data->group);
+       kfree(data->attributes);
+       kfree(data->labels);
+       kfree(data->booleans);
+       kfree(data->sensors);
+       kfree(data);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pmbus_do_remove);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c
new file mode 100644 (file)
index 0000000..ace1c73
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Hardware monitoring driver for UCD90xxx Sequencer and System Health
+ * Controller series
+ *
+ * Copyright (C) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pmbus.h>
+#include "pmbus.h"
+
+enum chips { ucd9000, ucd90120, ucd90124, ucd9090, ucd90910 };
+
+#define UCD9000_MONITOR_CONFIG         0xd5
+#define UCD9000_NUM_PAGES              0xd6
+#define UCD9000_FAN_CONFIG_INDEX       0xe7
+#define UCD9000_FAN_CONFIG             0xe8
+#define UCD9000_DEVICE_ID              0xfd
+
+#define UCD9000_MON_TYPE(x)    (((x) >> 5) & 0x07)
+#define UCD9000_MON_PAGE(x)    ((x) & 0x0f)
+
+#define UCD9000_MON_VOLTAGE    1
+#define UCD9000_MON_TEMPERATURE        2
+#define UCD9000_MON_CURRENT    3
+#define UCD9000_MON_VOLTAGE_HW 4
+
+#define UCD9000_NUM_FAN                4
+
+struct ucd9000_data {
+       u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX];
+       struct pmbus_driver_info info;
+};
+#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info)
+
+static int ucd9000_get_fan_config(struct i2c_client *client, int fan)
+{
+       int fan_config = 0;
+       struct ucd9000_data *data
+         = to_ucd9000_data(pmbus_get_driver_info(client));
+
+       if (data->fan_data[fan][3] & 1)
+               fan_config |= PB_FAN_2_INSTALLED;   /* Use lower bit position */
+
+       /* Pulses/revolution */
+       fan_config |= (data->fan_data[fan][3] & 0x06) >> 1;
+
+       return fan_config;
+}
+
+static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+       int ret = 0;
+       int fan_config;
+
+       switch (reg) {
+       case PMBUS_FAN_CONFIG_12:
+               if (page)
+                       return -EINVAL;
+
+               ret = ucd9000_get_fan_config(client, 0);
+               if (ret < 0)
+                       return ret;
+               fan_config = ret << 4;
+               ret = ucd9000_get_fan_config(client, 1);
+               if (ret < 0)
+                       return ret;
+               fan_config |= ret;
+               ret = fan_config;
+               break;
+       case PMBUS_FAN_CONFIG_34:
+               if (page)
+                       return -EINVAL;
+
+               ret = ucd9000_get_fan_config(client, 2);
+               if (ret < 0)
+                       return ret;
+               fan_config = ret << 4;
+               ret = ucd9000_get_fan_config(client, 3);
+               if (ret < 0)
+                       return ret;
+               fan_config |= ret;
+               ret = fan_config;
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+       return ret;
+}
+
+static const struct i2c_device_id ucd9000_id[] = {
+       {"ucd9000", ucd9000},
+       {"ucd90120", ucd90120},
+       {"ucd90124", ucd90124},
+       {"ucd9090", ucd9090},
+       {"ucd90910", ucd90910},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ucd9000_id);
+
+static int ucd9000_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
+       struct ucd9000_data *data;
+       struct pmbus_driver_info *info;
+       const struct i2c_device_id *mid;
+       int i, ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_BYTE_DATA |
+                                    I2C_FUNC_SMBUS_BLOCK_DATA))
+               return -ENODEV;
+
+       ret = i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID,
+                                       block_buffer);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to read device ID\n");
+               return ret;
+       }
+       block_buffer[ret] = '\0';
+       dev_info(&client->dev, "Device ID %s\n", block_buffer);
+
+       mid = NULL;
+       for (i = 0; i < ARRAY_SIZE(ucd9000_id); i++) {
+               mid = &ucd9000_id[i];
+               if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
+                       break;
+       }
+       if (!mid || !strlen(mid->name)) {
+               dev_err(&client->dev, "Unsupported device\n");
+               return -ENODEV;
+       }
+
+       if (id->driver_data != ucd9000 && id->driver_data != mid->driver_data)
+               dev_notice(&client->dev,
+                          "Device mismatch: Configured %s, detected %s\n",
+                          id->name, mid->name);
+
+       data = kzalloc(sizeof(struct ucd9000_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+       info = &data->info;
+
+       ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "Failed to read number of active pages\n");
+               goto out;
+       }
+       info->pages = ret;
+       if (!info->pages) {
+               dev_err(&client->dev, "No pages configured\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       /* The internal temperature sensor is always active */
+       info->func[0] = PMBUS_HAVE_TEMP;
+
+       /* Everything else is configurable */
+       ret = i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG,
+                                       block_buffer);
+       if (ret <= 0) {
+               dev_err(&client->dev, "Failed to read configuration data\n");
+               ret = -ENODEV;
+               goto out;
+       }
+       for (i = 0; i < ret; i++) {
+               int page = UCD9000_MON_PAGE(block_buffer[i]);
+
+               if (page >= info->pages)
+                       continue;
+
+               switch (UCD9000_MON_TYPE(block_buffer[i])) {
+               case UCD9000_MON_VOLTAGE:
+               case UCD9000_MON_VOLTAGE_HW:
+                       info->func[page] |= PMBUS_HAVE_VOUT
+                         | PMBUS_HAVE_STATUS_VOUT;
+                       break;
+               case UCD9000_MON_TEMPERATURE:
+                       info->func[page] |= PMBUS_HAVE_TEMP2
+                         | PMBUS_HAVE_STATUS_TEMP;
+                       break;
+               case UCD9000_MON_CURRENT:
+                       info->func[page] |= PMBUS_HAVE_IOUT
+                         | PMBUS_HAVE_STATUS_IOUT;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /* Fan configuration */
+       if (mid->driver_data == ucd90124) {
+               for (i = 0; i < UCD9000_NUM_FAN; i++) {
+                       i2c_smbus_write_byte_data(client,
+                                                 UCD9000_FAN_CONFIG_INDEX, i);
+                       ret = i2c_smbus_read_block_data(client,
+                                                       UCD9000_FAN_CONFIG,
+                                                       data->fan_data[i]);
+                       if (ret < 0)
+                               goto out;
+               }
+               i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0);
+
+               info->read_byte_data = ucd9000_read_byte_data;
+               info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12
+                 | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34;
+       }
+
+       ret = pmbus_do_probe(client, mid, info);
+       if (ret < 0)
+               goto out;
+       return 0;
+
+out:
+       kfree(data);
+       return ret;
+}
+
+static int ucd9000_remove(struct i2c_client *client)
+{
+       int ret;
+       struct ucd9000_data *data;
+
+       data = to_ucd9000_data(pmbus_get_driver_info(client));
+       ret = pmbus_do_remove(client);
+       kfree(data);
+       return ret;
+}
+
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ucd9000_driver = {
+       .driver = {
+               .name = "ucd9000",
+       },
+       .probe = ucd9000_probe,
+       .remove = ucd9000_remove,
+       .id_table = ucd9000_id,
+};
+
+static int __init ucd9000_init(void)
+{
+       return i2c_add_driver(&ucd9000_driver);
+}
+
+static void __exit ucd9000_exit(void)
+{
+       i2c_del_driver(&ucd9000_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx");
+MODULE_LICENSE("GPL");
+module_init(ucd9000_init);
+module_exit(ucd9000_exit);
diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c
new file mode 100644 (file)
index 0000000..ffcc1cf
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Hardware monitoring driver for ucd9200 series Digital PWM System Controllers
+ *
+ * Copyright (C) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pmbus.h>
+#include "pmbus.h"
+
+#define UCD9200_PHASE_INFO     0xd2
+#define UCD9200_DEVICE_ID      0xfd
+
+enum chips { ucd9200, ucd9220, ucd9222, ucd9224, ucd9240, ucd9244, ucd9246,
+            ucd9248 };
+
+static const struct i2c_device_id ucd9200_id[] = {
+       {"ucd9200", ucd9200},
+       {"ucd9220", ucd9220},
+       {"ucd9222", ucd9222},
+       {"ucd9224", ucd9224},
+       {"ucd9240", ucd9240},
+       {"ucd9244", ucd9244},
+       {"ucd9246", ucd9246},
+       {"ucd9248", ucd9248},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ucd9200_id);
+
+static int ucd9200_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
+       struct pmbus_driver_info *info;
+       const struct i2c_device_id *mid;
+       int i, j, ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_BYTE_DATA |
+                                    I2C_FUNC_SMBUS_BLOCK_DATA))
+               return -ENODEV;
+
+       ret = i2c_smbus_read_block_data(client, UCD9200_DEVICE_ID,
+                                       block_buffer);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to read device ID\n");
+               return ret;
+       }
+       block_buffer[ret] = '\0';
+       dev_info(&client->dev, "Device ID %s\n", block_buffer);
+
+       mid = NULL;
+       for (i = 0; i < ARRAY_SIZE(ucd9200_id); i++) {
+               mid = &ucd9200_id[i];
+               if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
+                       break;
+       }
+       if (!mid || !strlen(mid->name)) {
+               dev_err(&client->dev, "Unsupported device\n");
+               return -ENODEV;
+       }
+       if (id->driver_data != ucd9200 && id->driver_data != mid->driver_data)
+               dev_notice(&client->dev,
+                          "Device mismatch: Configured %s, detected %s\n",
+                          id->name, mid->name);
+
+       info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       ret = i2c_smbus_read_block_data(client, UCD9200_PHASE_INFO,
+                                       block_buffer);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to read phase information\n");
+               goto out;
+       }
+
+       /*
+        * Calculate number of configured pages (rails) from PHASE_INFO
+        * register.
+        * Rails have to be sequential, so we can abort after finding
+        * the first unconfigured rail.
+        */
+       info->pages = 0;
+       for (i = 0; i < ret; i++) {
+               if (!block_buffer[i])
+                       break;
+               info->pages++;
+       }
+       if (!info->pages) {
+               dev_err(&client->dev, "No rails configured\n");
+               ret = -ENODEV;
+               goto out;
+       }
+       dev_info(&client->dev, "%d rails configured\n", info->pages);
+
+       /*
+        * Set PHASE registers on all pages to 0xff to ensure that phase
+        * specific commands will apply to all phases of a given page (rail).
+        * This only affects the READ_IOUT and READ_TEMPERATURE2 registers.
+        * READ_IOUT will return the sum of currents of all phases of a rail,
+        * and READ_TEMPERATURE2 will return the maximum temperature detected
+        * for the the phases of the rail.
+        */
+       for (i = 0; i < info->pages; i++) {
+               /*
+                * Setting PAGE & PHASE fails once in a while for no obvious
+                * reason, so we need to retry a couple of times.
+                */
+               for (j = 0; j < 3; j++) {
+                       ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
+                       if (ret < 0)
+                               continue;
+                       ret = i2c_smbus_write_byte_data(client, PMBUS_PHASE,
+                                                       0xff);
+                       if (ret < 0)
+                               continue;
+                       break;
+               }
+               if (ret < 0) {
+                       dev_err(&client->dev,
+                               "Failed to initialize PHASE registers\n");
+                       goto out;
+               }
+       }
+       if (info->pages > 1)
+               i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+
+       info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT |
+                       PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
+                       PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+                       PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+                       PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP |
+                       PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
+
+       for (i = 1; i < info->pages; i++)
+               info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+                       PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+                       PMBUS_HAVE_POUT |
+                       PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
+
+       /* ucd9240 supports a single fan */
+       if (mid->driver_data == ucd9240)
+               info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12;
+
+       ret = pmbus_do_probe(client, mid, info);
+       if (ret < 0)
+               goto out;
+       return 0;
+out:
+       kfree(info);
+       return ret;
+}
+
+static int ucd9200_remove(struct i2c_client *client)
+{
+       int ret;
+       const struct pmbus_driver_info *info;
+
+       info = pmbus_get_driver_info(client);
+       ret = pmbus_do_remove(client);
+       kfree(info);
+       return ret;
+}
+
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ucd9200_driver = {
+       .driver = {
+               .name = "ucd9200",
+       },
+       .probe = ucd9200_probe,
+       .remove = ucd9200_remove,
+       .id_table = ucd9200_id,
+};
+
+static int __init ucd9200_init(void)
+{
+       return i2c_add_driver(&ucd9200_driver);
+}
+
+static void __exit ucd9200_exit(void)
+{
+       i2c_del_driver(&ucd9200_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x");
+MODULE_LICENSE("GPL");
+module_init(ucd9200_init);
+module_exit(ucd9200_exit);
diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c
deleted file mode 100644 (file)
index 8e31a8e..0000000
+++ /dev/null
@@ -1,1567 +0,0 @@
-/*
- * Hardware monitoring driver for PMBus devices
- *
- * Copyright (c) 2010, 2011 Ericsson AB.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/delay.h>
-#include <linux/i2c/pmbus.h>
-#include "pmbus.h"
-
-/*
- * Constants needed to determine number of sensors, booleans, and labels.
- */
-#define PMBUS_MAX_INPUT_SENSORS                11      /* 6*volt, 3*curr, 2*power */
-#define PMBUS_VOUT_SENSORS_PER_PAGE    5       /* input, min, max, lcrit,
-                                                  crit */
-#define PMBUS_IOUT_SENSORS_PER_PAGE    4       /* input, min, max, crit */
-#define PMBUS_POUT_SENSORS_PER_PAGE    4       /* input, cap, max, crit */
-#define PMBUS_MAX_SENSORS_PER_FAN      1       /* input */
-#define PMBUS_MAX_SENSORS_PER_TEMP     5       /* input, min, max, lcrit,
-                                                  crit */
-
-#define PMBUS_MAX_INPUT_BOOLEANS       7       /* v: min_alarm, max_alarm,
-                                                  lcrit_alarm, crit_alarm;
-                                                  c: alarm, crit_alarm;
-                                                  p: crit_alarm */
-#define PMBUS_VOUT_BOOLEANS_PER_PAGE   4       /* min_alarm, max_alarm,
-                                                  lcrit_alarm, crit_alarm */
-#define PMBUS_IOUT_BOOLEANS_PER_PAGE   3       /* alarm, lcrit_alarm,
-                                                  crit_alarm */
-#define PMBUS_POUT_BOOLEANS_PER_PAGE   2       /* alarm, crit_alarm */
-#define PMBUS_MAX_BOOLEANS_PER_FAN     2       /* alarm, fault */
-#define PMBUS_MAX_BOOLEANS_PER_TEMP    4       /* min_alarm, max_alarm,
-                                                  lcrit_alarm, crit_alarm */
-
-#define PMBUS_MAX_INPUT_LABELS         4       /* vin, vcap, iin, pin */
-
-/*
- * status, status_vout, status_iout, status_fans, status_fan34, and status_temp
- * are paged. status_input is unpaged.
- */
-#define PB_NUM_STATUS_REG      (PMBUS_PAGES * 6 + 1)
-
-/*
- * Index into status register array, per status register group
- */
-#define PB_STATUS_BASE         0
-#define PB_STATUS_VOUT_BASE    (PB_STATUS_BASE + PMBUS_PAGES)
-#define PB_STATUS_IOUT_BASE    (PB_STATUS_VOUT_BASE + PMBUS_PAGES)
-#define PB_STATUS_FAN_BASE     (PB_STATUS_IOUT_BASE + PMBUS_PAGES)
-#define PB_STATUS_FAN34_BASE   (PB_STATUS_FAN_BASE + PMBUS_PAGES)
-#define PB_STATUS_INPUT_BASE   (PB_STATUS_FAN34_BASE + PMBUS_PAGES)
-#define PB_STATUS_TEMP_BASE    (PB_STATUS_INPUT_BASE + 1)
-
-struct pmbus_sensor {
-       char name[I2C_NAME_SIZE];       /* sysfs sensor name */
-       struct sensor_device_attribute attribute;
-       u8 page;                /* page number */
-       u8 reg;                 /* register */
-       enum pmbus_sensor_classes class;        /* sensor class */
-       bool update;            /* runtime sensor update needed */
-       int data;               /* Sensor data.
-                                  Negative if there was a read error */
-};
-
-struct pmbus_boolean {
-       char name[I2C_NAME_SIZE];       /* sysfs boolean name */
-       struct sensor_device_attribute attribute;
-};
-
-struct pmbus_label {
-       char name[I2C_NAME_SIZE];       /* sysfs label name */
-       struct sensor_device_attribute attribute;
-       char label[I2C_NAME_SIZE];      /* label */
-};
-
-struct pmbus_data {
-       struct device *hwmon_dev;
-
-       u32 flags;              /* from platform data */
-
-       int exponent;           /* linear mode: exponent for output voltages */
-
-       const struct pmbus_driver_info *info;
-
-       int max_attributes;
-       int num_attributes;
-       struct attribute **attributes;
-       struct attribute_group group;
-
-       /*
-        * Sensors cover both sensor and limit registers.
-        */
-       int max_sensors;
-       int num_sensors;
-       struct pmbus_sensor *sensors;
-       /*
-        * Booleans are used for alarms.
-        * Values are determined from status registers.
-        */
-       int max_booleans;
-       int num_booleans;
-       struct pmbus_boolean *booleans;
-       /*
-        * Labels are used to map generic names (e.g., "in1")
-        * to PMBus specific names (e.g., "vin" or "vout1").
-        */
-       int max_labels;
-       int num_labels;
-       struct pmbus_label *labels;
-
-       struct mutex update_lock;
-       bool valid;
-       unsigned long last_updated;     /* in jiffies */
-
-       /*
-        * A single status register covers multiple attributes,
-        * so we keep them all together.
-        */
-       u8 status[PB_NUM_STATUS_REG];
-
-       u8 currpage;
-};
-
-int pmbus_set_page(struct i2c_client *client, u8 page)
-{
-       struct pmbus_data *data = i2c_get_clientdata(client);
-       int rv = 0;
-       int newpage;
-
-       if (page != data->currpage) {
-               rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
-               newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
-               if (newpage != page)
-                       rv = -EINVAL;
-               else
-                       data->currpage = page;
-       }
-       return rv;
-}
-EXPORT_SYMBOL_GPL(pmbus_set_page);
-
-static int pmbus_write_byte(struct i2c_client *client, u8 page, u8 value)
-{
-       int rv;
-
-       rv = pmbus_set_page(client, page);
-       if (rv < 0)
-               return rv;
-
-       return i2c_smbus_write_byte(client, value);
-}
-
-static int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg,
-                                u16 word)
-{
-       int rv;
-
-       rv = pmbus_set_page(client, page);
-       if (rv < 0)
-               return rv;
-
-       return i2c_smbus_write_word_data(client, reg, word);
-}
-
-int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg)
-{
-       int rv;
-
-       rv = pmbus_set_page(client, page);
-       if (rv < 0)
-               return rv;
-
-       return i2c_smbus_read_word_data(client, reg);
-}
-EXPORT_SYMBOL_GPL(pmbus_read_word_data);
-
-static int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg)
-{
-       int rv;
-
-       rv = pmbus_set_page(client, page);
-       if (rv < 0)
-               return rv;
-
-       return i2c_smbus_read_byte_data(client, reg);
-}
-
-static void pmbus_clear_fault_page(struct i2c_client *client, int page)
-{
-       pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
-}
-
-void pmbus_clear_faults(struct i2c_client *client)
-{
-       struct pmbus_data *data = i2c_get_clientdata(client);
-       int i;
-
-       for (i = 0; i < data->info->pages; i++)
-               pmbus_clear_fault_page(client, i);
-}
-EXPORT_SYMBOL_GPL(pmbus_clear_faults);
-
-static int pmbus_check_status_cml(struct i2c_client *client, int page)
-{
-       int status, status2;
-
-       status = pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE);
-       if (status < 0 || (status & PB_STATUS_CML)) {
-               status2 = pmbus_read_byte_data(client, page, PMBUS_STATUS_CML);
-               if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND))
-                       return -EINVAL;
-       }
-       return 0;
-}
-
-bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg)
-{
-       int rv;
-       struct pmbus_data *data = i2c_get_clientdata(client);
-
-       rv = pmbus_read_byte_data(client, page, reg);
-       if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
-               rv = pmbus_check_status_cml(client, page);
-       pmbus_clear_fault_page(client, page);
-       return rv >= 0;
-}
-EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
-
-bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
-{
-       int rv;
-       struct pmbus_data *data = i2c_get_clientdata(client);
-
-       rv = pmbus_read_word_data(client, page, reg);
-       if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK))
-               rv = pmbus_check_status_cml(client, page);
-       pmbus_clear_fault_page(client, page);
-       return rv >= 0;
-}
-EXPORT_SYMBOL_GPL(pmbus_check_word_register);
-
-const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
-{
-       struct pmbus_data *data = i2c_get_clientdata(client);
-
-       return data->info;
-}
-EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
-
-/*
- * _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if
- * a device specific mapping funcion exists and calls it if necessary.
- */
-static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg)
-{
-       struct pmbus_data *data = i2c_get_clientdata(client);
-       const struct pmbus_driver_info *info = data->info;
-       int status;
-
-       if (info->read_byte_data) {
-               status = info->read_byte_data(client, page, reg);
-               if (status != -ENODATA)
-                       return status;
-       }
-       return pmbus_read_byte_data(client, page, reg);
-}
-
-static struct pmbus_data *pmbus_update_device(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pmbus_data *data = i2c_get_clientdata(client);
-       const struct pmbus_driver_info *info = data->info;
-
-       mutex_lock(&data->update_lock);
-       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
-               int i;
-
-               for (i = 0; i < info->pages; i++)
-                       data->status[PB_STATUS_BASE + i]
-                           = pmbus_read_byte_data(client, i,
-                                                  PMBUS_STATUS_BYTE);
-               for (i = 0; i < info->pages; i++) {
-                       if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT))
-                               continue;
-                       data->status[PB_STATUS_VOUT_BASE + i]
-                         = _pmbus_read_byte_data(client, i, PMBUS_STATUS_VOUT);
-               }
-               for (i = 0; i < info->pages; i++) {
-                       if (!(info->func[i] & PMBUS_HAVE_STATUS_IOUT))
-                               continue;
-                       data->status[PB_STATUS_IOUT_BASE + i]
-                         = _pmbus_read_byte_data(client, i, PMBUS_STATUS_IOUT);
-               }
-               for (i = 0; i < info->pages; i++) {
-                       if (!(info->func[i] & PMBUS_HAVE_STATUS_TEMP))
-                               continue;
-                       data->status[PB_STATUS_TEMP_BASE + i]
-                         = _pmbus_read_byte_data(client, i,
-                                                 PMBUS_STATUS_TEMPERATURE);
-               }
-               for (i = 0; i < info->pages; i++) {
-                       if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN12))
-                               continue;
-                       data->status[PB_STATUS_FAN_BASE + i]
-                         = _pmbus_read_byte_data(client, i,
-                                                 PMBUS_STATUS_FAN_12);
-               }
-
-               for (i = 0; i < info->pages; i++) {
-                       if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN34))
-                               continue;
-                       data->status[PB_STATUS_FAN34_BASE + i]
-                         = _pmbus_read_byte_data(client, i,
-                                                 PMBUS_STATUS_FAN_34);
-               }
-
-               if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
-                       data->status[PB_STATUS_INPUT_BASE]
-                         = _pmbus_read_byte_data(client, 0,
-                                                 PMBUS_STATUS_INPUT);
-
-               for (i = 0; i < data->num_sensors; i++) {
-                       struct pmbus_sensor *sensor = &data->sensors[i];
-
-                       if (!data->valid || sensor->update)
-                               sensor->data
-                                   = pmbus_read_word_data(client, sensor->page,
-                                                          sensor->reg);
-               }
-               pmbus_clear_faults(client);
-               data->last_updated = jiffies;
-               data->valid = 1;
-       }
-       mutex_unlock(&data->update_lock);
-       return data;
-}
-
-/*
- * Convert linear sensor values to milli- or micro-units
- * depending on sensor type.
- */
-static long pmbus_reg2data_linear(struct pmbus_data *data,
-                                 struct pmbus_sensor *sensor)
-{
-       s16 exponent;
-       s32 mantissa;
-       long val;
-
-       if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */
-               exponent = data->exponent;
-               mantissa = (u16) sensor->data;
-       } else {                                /* LINEAR11 */
-               exponent = (sensor->data >> 11) & 0x001f;
-               mantissa = sensor->data & 0x07ff;
-
-               if (exponent > 0x0f)
-                       exponent |= 0xffe0;     /* sign extend exponent */
-               if (mantissa > 0x03ff)
-                       mantissa |= 0xfffff800; /* sign extend mantissa */
-       }
-
-       val = mantissa;
-
-       /* scale result to milli-units for all sensors except fans */
-       if (sensor->class != PSC_FAN)
-               val = val * 1000L;
-
-       /* scale result to micro-units for power sensors */
-       if (sensor->class == PSC_POWER)
-               val = val * 1000L;
-
-       if (exponent >= 0)
-               val <<= exponent;
-       else
-               val >>= -exponent;
-
-       return val;
-}
-
-/*
- * Convert direct sensor values to milli- or micro-units
- * depending on sensor type.
- */
-static long pmbus_reg2data_direct(struct pmbus_data *data,
-                                 struct pmbus_sensor *sensor)
-{
-       long val = (s16) sensor->data;
-       long m, b, R;
-
-       m = data->info->m[sensor->class];
-       b = data->info->b[sensor->class];
-       R = data->info->R[sensor->class];
-
-       if (m == 0)
-               return 0;
-
-       /* X = 1/m * (Y * 10^-R - b) */
-       R = -R;
-       /* scale result to milli-units for everything but fans */
-       if (sensor->class != PSC_FAN) {
-               R += 3;
-               b *= 1000;
-       }
-
-       /* scale result to micro-units for power sensors */
-       if (sensor->class == PSC_POWER) {
-               R += 3;
-               b *= 1000;
-       }
-
-       while (R > 0) {
-               val *= 10;
-               R--;
-       }
-       while (R < 0) {
-               val = DIV_ROUND_CLOSEST(val, 10);
-               R++;
-       }
-
-       return (val - b) / m;
-}
-
-static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
-{
-       long val;
-
-       if (data->info->direct[sensor->class])
-               val = pmbus_reg2data_direct(data, sensor);
-       else
-               val = pmbus_reg2data_linear(data, sensor);
-
-       return val;
-}
-
-#define MAX_MANTISSA   (1023 * 1000)
-#define MIN_MANTISSA   (511 * 1000)
-
-static u16 pmbus_data2reg_linear(struct pmbus_data *data,
-                                enum pmbus_sensor_classes class, long val)
-{
-       s16 exponent = 0, mantissa;
-       bool negative = false;
-
-       /* simple case */
-       if (val == 0)
-               return 0;
-
-       if (class == PSC_VOLTAGE_OUT) {
-               /* LINEAR16 does not support negative voltages */
-               if (val < 0)
-                       return 0;
-
-               /*
-                * For a static exponents, we don't have a choice
-                * but to adjust the value to it.
-                */
-               if (data->exponent < 0)
-                       val <<= -data->exponent;
-               else
-                       val >>= data->exponent;
-               val = DIV_ROUND_CLOSEST(val, 1000);
-               return val & 0xffff;
-       }
-
-       if (val < 0) {
-               negative = true;
-               val = -val;
-       }
-
-       /* Power is in uW. Convert to mW before converting. */
-       if (class == PSC_POWER)
-               val = DIV_ROUND_CLOSEST(val, 1000L);
-
-       /*
-        * For simplicity, convert fan data to milli-units
-        * before calculating the exponent.
-        */
-       if (class == PSC_FAN)
-               val = val * 1000;
-
-       /* Reduce large mantissa until it fits into 10 bit */
-       while (val >= MAX_MANTISSA && exponent < 15) {
-               exponent++;
-               val >>= 1;
-       }
-       /* Increase small mantissa to improve precision */
-       while (val < MIN_MANTISSA && exponent > -15) {
-               exponent--;
-               val <<= 1;
-       }
-
-       /* Convert mantissa from milli-units to units */
-       mantissa = DIV_ROUND_CLOSEST(val, 1000);
-
-       /* Ensure that resulting number is within range */
-       if (mantissa > 0x3ff)
-               mantissa = 0x3ff;
-
-       /* restore sign */
-       if (negative)
-               mantissa = -mantissa;
-
-       /* Convert to 5 bit exponent, 11 bit mantissa */
-       return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
-}
-
-static u16 pmbus_data2reg_direct(struct pmbus_data *data,
-                                enum pmbus_sensor_classes class, long val)
-{
-       long m, b, R;
-
-       m = data->info->m[class];
-       b = data->info->b[class];
-       R = data->info->R[class];
-
-       /* Power is in uW. Adjust R and b. */
-       if (class == PSC_POWER) {
-               R -= 3;
-               b *= 1000;
-       }
-
-       /* Calculate Y = (m * X + b) * 10^R */
-       if (class != PSC_FAN) {
-               R -= 3;         /* Adjust R and b for data in milli-units */
-               b *= 1000;
-       }
-       val = val * m + b;
-
-       while (R > 0) {
-               val *= 10;
-               R--;
-       }
-       while (R < 0) {
-               val = DIV_ROUND_CLOSEST(val, 10);
-               R++;
-       }
-
-       return val;
-}
-
-static u16 pmbus_data2reg(struct pmbus_data *data,
-                         enum pmbus_sensor_classes class, long val)
-{
-       u16 regval;
-
-       if (data->info->direct[class])
-               regval = pmbus_data2reg_direct(data, class, val);
-       else
-               regval = pmbus_data2reg_linear(data, class, val);
-
-       return regval;
-}
-
-/*
- * Return boolean calculated from converted data.
- * <index> defines a status register index and mask, and optionally
- * two sensor indexes.
- * The upper half-word references the two sensors,
- * two sensor indices.
- * The upper half-word references the two optional sensors,
- * the lower half word references status register and mask.
- * The function returns true if (status[reg] & mask) is true and,
- * if specified, if v1 >= v2.
- * To determine if an object exceeds upper limits, specify <v, limit>.
- * To determine if an object exceeds lower limits, specify <limit, v>.
- *
- * For booleans created with pmbus_add_boolean_reg(), only the lower 16 bits of
- * index are set. s1 and s2 (the sensor index values) are zero in this case.
- * The function returns true if (status[reg] & mask) is true.
- *
- * If the boolean was created with pmbus_add_boolean_cmp(), a comparison against
- * a specified limit has to be performed to determine the boolean result.
- * In this case, the function returns true if v1 >= v2 (where v1 and v2 are
- * sensor values referenced by sensor indices s1 and s2).
- *
- * To determine if an object exceeds upper limits, specify <s1,s2> = <v,limit>.
- * To determine if an object exceeds lower limits, specify <s1,s2> = <limit,v>.
- *
- * If a negative value is stored in any of the referenced registers, this value
- * reflects an error code which will be returned.
- */
-static int pmbus_get_boolean(struct pmbus_data *data, int index, int *val)
-{
-       u8 s1 = (index >> 24) & 0xff;
-       u8 s2 = (index >> 16) & 0xff;
-       u8 reg = (index >> 8) & 0xff;
-       u8 mask = index & 0xff;
-       int status;
-       u8 regval;
-
-       status = data->status[reg];
-       if (status < 0)
-               return status;
-
-       regval = status & mask;
-       if (!s1 && !s2)
-               *val = !!regval;
-       else {
-               long v1, v2;
-               struct pmbus_sensor *sensor1, *sensor2;
-
-               sensor1 = &data->sensors[s1];
-               if (sensor1->data < 0)
-                       return sensor1->data;
-               sensor2 = &data->sensors[s2];
-               if (sensor2->data < 0)
-                       return sensor2->data;
-
-               v1 = pmbus_reg2data(data, sensor1);
-               v2 = pmbus_reg2data(data, sensor2);
-               *val = !!(regval && v1 >= v2);
-       }
-       return 0;
-}
-
-static ssize_t pmbus_show_boolean(struct device *dev,
-                                 struct device_attribute *da, char *buf)
-{
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-       struct pmbus_data *data = pmbus_update_device(dev);
-       int val;
-       int err;
-
-       err = pmbus_get_boolean(data, attr->index, &val);
-       if (err)
-               return err;
-       return snprintf(buf, PAGE_SIZE, "%d\n", val);
-}
-
-static ssize_t pmbus_show_sensor(struct device *dev,
-                                struct device_attribute *da, char *buf)
-{
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-       struct pmbus_data *data = pmbus_update_device(dev);
-       struct pmbus_sensor *sensor;
-
-       sensor = &data->sensors[attr->index];
-       if (sensor->data < 0)
-               return sensor->data;
-
-       return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor));
-}
-
-static ssize_t pmbus_set_sensor(struct device *dev,
-                               struct device_attribute *devattr,
-                               const char *buf, size_t count)
-{
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pmbus_data *data = i2c_get_clientdata(client);
-       struct pmbus_sensor *sensor = &data->sensors[attr->index];
-       ssize_t rv = count;
-       long val = 0;
-       int ret;
-       u16 regval;
-
-       if (strict_strtol(buf, 10, &val) < 0)
-               return -EINVAL;
-
-       mutex_lock(&data->update_lock);
-       regval = pmbus_data2reg(data, sensor->class, val);
-       ret = pmbus_write_word_data(client, sensor->page, sensor->reg, regval);
-       if (ret < 0)
-               rv = ret;
-       else
-               data->sensors[attr->index].data = regval;
-       mutex_unlock(&data->update_lock);
-       return rv;
-}
-
-static ssize_t pmbus_show_label(struct device *dev,
-                               struct device_attribute *da, char *buf)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct pmbus_data *data = i2c_get_clientdata(client);
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
-
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       data->labels[attr->index].label);
-}
-
-#define PMBUS_ADD_ATTR(data, _name, _idx, _mode, _type, _show, _set)   \
-do {                                                                   \
-       struct sensor_device_attribute *a                               \
-           = &data->_type##s[data->num_##_type##s].attribute;          \
-       BUG_ON(data->num_attributes >= data->max_attributes);           \
-       sysfs_attr_init(&a->dev_attr.attr);                             \
-       a->dev_attr.attr.name = _name;                                  \
-       a->dev_attr.attr.mode = _mode;                                  \
-       a->dev_attr.show = _show;                                       \
-       a->dev_attr.store = _set;                                       \
-       a->index = _idx;                                                \
-       data->attributes[data->num_attributes] = &a->dev_attr.attr;     \
-       data->num_attributes++;                                         \
-} while (0)
-
-#define PMBUS_ADD_GET_ATTR(data, _name, _type, _idx)                   \
-       PMBUS_ADD_ATTR(data, _name, _idx, S_IRUGO, _type,               \
-                      pmbus_show_##_type,  NULL)
-
-#define PMBUS_ADD_SET_ATTR(data, _name, _type, _idx)                   \
-       PMBUS_ADD_ATTR(data, _name, _idx, S_IWUSR | S_IRUGO, _type,     \
-                      pmbus_show_##_type, pmbus_set_##_type)
-
-static void pmbus_add_boolean(struct pmbus_data *data,
-                             const char *name, const char *type, int seq,
-                             int idx)
-{
-       struct pmbus_boolean *boolean;
-
-       BUG_ON(data->num_booleans >= data->max_booleans);
-
-       boolean = &data->booleans[data->num_booleans];
-
-       snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s",
-                name, seq, type);
-       PMBUS_ADD_GET_ATTR(data, boolean->name, boolean, idx);
-       data->num_booleans++;
-}
-
-static void pmbus_add_boolean_reg(struct pmbus_data *data,
-                                 const char *name, const char *type,
-                                 int seq, int reg, int bit)
-{
-       pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit);
-}
-
-static void pmbus_add_boolean_cmp(struct pmbus_data *data,
-                                 const char *name, const char *type,
-                                 int seq, int i1, int i2, int reg, int mask)
-{
-       pmbus_add_boolean(data, name, type, seq,
-                         (i1 << 24) | (i2 << 16) | (reg << 8) | mask);
-}
-
-static void pmbus_add_sensor(struct pmbus_data *data,
-                            const char *name, const char *type, int seq,
-                            int page, int reg, enum pmbus_sensor_classes class,
-                            bool update, bool readonly)
-{
-       struct pmbus_sensor *sensor;
-
-       BUG_ON(data->num_sensors >= data->max_sensors);
-
-       sensor = &data->sensors[data->num_sensors];
-       snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s",
-                name, seq, type);
-       sensor->page = page;
-       sensor->reg = reg;
-       sensor->class = class;
-       sensor->update = update;
-       if (readonly)
-               PMBUS_ADD_GET_ATTR(data, sensor->name, sensor,
-                                  data->num_sensors);
-       else
-               PMBUS_ADD_SET_ATTR(data, sensor->name, sensor,
-                                  data->num_sensors);
-       data->num_sensors++;
-}
-
-static void pmbus_add_label(struct pmbus_data *data,
-                           const char *name, int seq,
-                           const char *lstring, int index)
-{
-       struct pmbus_label *label;
-
-       BUG_ON(data->num_labels >= data->max_labels);
-
-       label = &data->labels[data->num_labels];
-       snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
-       if (!index)
-               strncpy(label->label, lstring, sizeof(label->label) - 1);
-       else
-               snprintf(label->label, sizeof(label->label), "%s%d", lstring,
-                        index);
-
-       PMBUS_ADD_GET_ATTR(data, label->name, label, data->num_labels);
-       data->num_labels++;
-}
-
-/*
- * Determine maximum number of sensors, booleans, and labels.
- * To keep things simple, only make a rough high estimate.
- */
-static void pmbus_find_max_attr(struct i2c_client *client,
-                               struct pmbus_data *data)
-{
-       const struct pmbus_driver_info *info = data->info;
-       int page, max_sensors, max_booleans, max_labels;
-
-       max_sensors = PMBUS_MAX_INPUT_SENSORS;
-       max_booleans = PMBUS_MAX_INPUT_BOOLEANS;
-       max_labels = PMBUS_MAX_INPUT_LABELS;
-
-       for (page = 0; page < info->pages; page++) {
-               if (info->func[page] & PMBUS_HAVE_VOUT) {
-                       max_sensors += PMBUS_VOUT_SENSORS_PER_PAGE;
-                       max_booleans += PMBUS_VOUT_BOOLEANS_PER_PAGE;
-                       max_labels++;
-               }
-               if (info->func[page] & PMBUS_HAVE_IOUT) {
-                       max_sensors += PMBUS_IOUT_SENSORS_PER_PAGE;
-                       max_booleans += PMBUS_IOUT_BOOLEANS_PER_PAGE;
-                       max_labels++;
-               }
-               if (info->func[page] & PMBUS_HAVE_POUT) {
-                       max_sensors += PMBUS_POUT_SENSORS_PER_PAGE;
-                       max_booleans += PMBUS_POUT_BOOLEANS_PER_PAGE;
-                       max_labels++;
-               }
-               if (info->func[page] & PMBUS_HAVE_FAN12) {
-                       max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
-                       max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
-               }
-               if (info->func[page] & PMBUS_HAVE_FAN34) {
-                       max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN;
-                       max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN;
-               }
-               if (info->func[page] & PMBUS_HAVE_TEMP) {
-                       max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
-                       max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
-               }
-               if (info->func[page] & PMBUS_HAVE_TEMP2) {
-                       max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
-                       max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
-               }
-               if (info->func[page] & PMBUS_HAVE_TEMP3) {
-                       max_sensors += PMBUS_MAX_SENSORS_PER_TEMP;
-                       max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP;
-               }
-       }
-       data->max_sensors = max_sensors;
-       data->max_booleans = max_booleans;
-       data->max_labels = max_labels;
-       data->max_attributes = max_sensors + max_booleans + max_labels;
-}
-
-/*
- * Search for attributes. Allocate sensors, booleans, and labels as needed.
- */
-
-/*
- * The pmbus_limit_attr structure describes a single limit attribute
- * and its associated alarm attribute.
- */
-struct pmbus_limit_attr {
-       u8 reg;                 /* Limit register */
-       const char *attr;       /* Attribute name */
-       const char *alarm;      /* Alarm attribute name */
-       u32 sbit;               /* Alarm attribute status bit */
-};
-
-/*
- * The pmbus_sensor_attr structure describes one sensor attribute. This
- * description includes a reference to the associated limit attributes.
- */
-struct pmbus_sensor_attr {
-       u8 reg;                         /* sensor register */
-       enum pmbus_sensor_classes class;/* sensor class */
-       const char *label;              /* sensor label */
-       bool paged;                     /* true if paged sensor */
-       bool update;                    /* true if update needed */
-       bool compare;                   /* true if compare function needed */
-       u32 func;                       /* sensor mask */
-       u32 sfunc;                      /* sensor status mask */
-       int sbase;                      /* status base register */
-       u32 gbit;                       /* generic status bit */
-       const struct pmbus_limit_attr *limit;/* limit registers */
-       int nlimit;                     /* # of limit registers */
-};
-
-/*
- * Add a set of limit attributes and, if supported, the associated
- * alarm attributes.
- */
-static bool pmbus_add_limit_attrs(struct i2c_client *client,
-                                 struct pmbus_data *data,
-                                 const struct pmbus_driver_info *info,
-                                 const char *name, int index, int page,
-                                 int cbase,
-                                 const struct pmbus_sensor_attr *attr)
-{
-       const struct pmbus_limit_attr *l = attr->limit;
-       int nlimit = attr->nlimit;
-       bool have_alarm = false;
-       int i, cindex;
-
-       for (i = 0; i < nlimit; i++) {
-               if (pmbus_check_word_register(client, page, l->reg)) {
-                       cindex = data->num_sensors;
-                       pmbus_add_sensor(data, name, l->attr, index, page,
-                                        l->reg, attr->class, attr->update,
-                                        false);
-                       if (info->func[page] & attr->sfunc) {
-                               if (attr->compare) {
-                                       pmbus_add_boolean_cmp(data, name,
-                                               l->alarm, index,
-                                               cbase, cindex,
-                                               attr->sbase + page, l->sbit);
-                               } else {
-                                       pmbus_add_boolean_reg(data, name,
-                                               l->alarm, index,
-                                               attr->sbase + page, l->sbit);
-                               }
-                               have_alarm = true;
-                       }
-               }
-               l++;
-       }
-       return have_alarm;
-}
-
-static void pmbus_add_sensor_attrs_one(struct i2c_client *client,
-                                      struct pmbus_data *data,
-                                      const struct pmbus_driver_info *info,
-                                      const char *name,
-                                      int index, int page,
-                                      const struct pmbus_sensor_attr *attr)
-{
-       bool have_alarm;
-       int cbase = data->num_sensors;
-
-       if (attr->label)
-               pmbus_add_label(data, name, index, attr->label,
-                               attr->paged ? page + 1 : 0);
-       pmbus_add_sensor(data, name, "input", index, page, attr->reg,
-                        attr->class, true, true);
-       if (attr->sfunc) {
-               have_alarm = pmbus_add_limit_attrs(client, data, info, name,
-                                                  index, page, cbase, attr);
-               /*
-                * Add generic alarm attribute only if there are no individual
-                * alarm attributes, and if there is a global alarm bit.
-                */
-               if (!have_alarm && attr->gbit)
-                       pmbus_add_boolean_reg(data, name, "alarm", index,
-                                             PB_STATUS_BASE + page,
-                                             attr->gbit);
-       }
-}
-
-static void pmbus_add_sensor_attrs(struct i2c_client *client,
-                                  struct pmbus_data *data,
-                                  const char *name,
-                                  const struct pmbus_sensor_attr *attrs,
-                                  int nattrs)
-{
-       const struct pmbus_driver_info *info = data->info;
-       int index, i;
-
-       index = 1;
-       for (i = 0; i < nattrs; i++) {
-               int page, pages;
-
-               pages = attrs->paged ? info->pages : 1;
-               for (page = 0; page < pages; page++) {
-                       if (!(info->func[page] & attrs->func))
-                               continue;
-                       pmbus_add_sensor_attrs_one(client, data, info, name,
-                                                  index, page, attrs);
-                       index++;
-               }
-               attrs++;
-       }
-}
-
-static const struct pmbus_limit_attr vin_limit_attrs[] = {
-       {
-               .reg = PMBUS_VIN_UV_WARN_LIMIT,
-               .attr = "min",
-               .alarm = "min_alarm",
-               .sbit = PB_VOLTAGE_UV_WARNING,
-       }, {
-               .reg = PMBUS_VIN_UV_FAULT_LIMIT,
-               .attr = "lcrit",
-               .alarm = "lcrit_alarm",
-               .sbit = PB_VOLTAGE_UV_FAULT,
-       }, {
-               .reg = PMBUS_VIN_OV_WARN_LIMIT,
-               .attr = "max",
-               .alarm = "max_alarm",
-               .sbit = PB_VOLTAGE_OV_WARNING,
-       }, {
-               .reg = PMBUS_VIN_OV_FAULT_LIMIT,
-               .attr = "crit",
-               .alarm = "crit_alarm",
-               .sbit = PB_VOLTAGE_OV_FAULT,
-       },
-};
-
-static const struct pmbus_limit_attr vout_limit_attrs[] = {
-       {
-               .reg = PMBUS_VOUT_UV_WARN_LIMIT,
-               .attr = "min",
-               .alarm = "min_alarm",
-               .sbit = PB_VOLTAGE_UV_WARNING,
-       }, {
-               .reg = PMBUS_VOUT_UV_FAULT_LIMIT,
-               .attr = "lcrit",
-               .alarm = "lcrit_alarm",
-               .sbit = PB_VOLTAGE_UV_FAULT,
-       }, {
-               .reg = PMBUS_VOUT_OV_WARN_LIMIT,
-               .attr = "max",
-               .alarm = "max_alarm",
-               .sbit = PB_VOLTAGE_OV_WARNING,
-       }, {
-               .reg = PMBUS_VOUT_OV_FAULT_LIMIT,
-               .attr = "crit",
-               .alarm = "crit_alarm",
-               .sbit = PB_VOLTAGE_OV_FAULT,
-       }
-};
-
-static const struct pmbus_sensor_attr voltage_attributes[] = {
-       {
-               .reg = PMBUS_READ_VIN,
-               .class = PSC_VOLTAGE_IN,
-               .label = "vin",
-               .func = PMBUS_HAVE_VIN,
-               .sfunc = PMBUS_HAVE_STATUS_INPUT,
-               .sbase = PB_STATUS_INPUT_BASE,
-               .gbit = PB_STATUS_VIN_UV,
-               .limit = vin_limit_attrs,
-               .nlimit = ARRAY_SIZE(vin_limit_attrs),
-       }, {
-               .reg = PMBUS_READ_VCAP,
-               .class = PSC_VOLTAGE_IN,
-               .label = "vcap",
-               .func = PMBUS_HAVE_VCAP,
-       }, {
-               .reg = PMBUS_READ_VOUT,
-               .class = PSC_VOLTAGE_OUT,
-               .label = "vout",
-               .paged = true,
-               .func = PMBUS_HAVE_VOUT,
-               .sfunc = PMBUS_HAVE_STATUS_VOUT,
-               .sbase = PB_STATUS_VOUT_BASE,
-               .gbit = PB_STATUS_VOUT_OV,
-               .limit = vout_limit_attrs,
-               .nlimit = ARRAY_SIZE(vout_limit_attrs),
-       }
-};
-
-/* Current attributes */
-
-static const struct pmbus_limit_attr iin_limit_attrs[] = {
-       {
-               .reg = PMBUS_IIN_OC_WARN_LIMIT,
-               .attr = "max",
-               .alarm = "max_alarm",
-               .sbit = PB_IIN_OC_WARNING,
-       }, {
-               .reg = PMBUS_IIN_OC_FAULT_LIMIT,
-               .attr = "crit",
-               .alarm = "crit_alarm",
-               .sbit = PB_IIN_OC_FAULT,
-       }
-};
-
-static const struct pmbus_limit_attr iout_limit_attrs[] = {
-       {
-               .reg = PMBUS_IOUT_OC_WARN_LIMIT,
-               .attr = "max",
-               .alarm = "max_alarm",
-               .sbit = PB_IOUT_OC_WARNING,
-       }, {
-               .reg = PMBUS_IOUT_UC_FAULT_LIMIT,
-               .attr = "lcrit",
-               .alarm = "lcrit_alarm",
-               .sbit = PB_IOUT_UC_FAULT,
-       }, {
-               .reg = PMBUS_IOUT_OC_FAULT_LIMIT,
-               .attr = "crit",
-               .alarm = "crit_alarm",
-               .sbit = PB_IOUT_OC_FAULT,
-       }
-};
-
-static const struct pmbus_sensor_attr current_attributes[] = {
-       {
-               .reg = PMBUS_READ_IIN,
-               .class = PSC_CURRENT_IN,
-               .label = "iin",
-               .func = PMBUS_HAVE_IIN,
-               .sfunc = PMBUS_HAVE_STATUS_INPUT,
-               .sbase = PB_STATUS_INPUT_BASE,
-               .limit = iin_limit_attrs,
-               .nlimit = ARRAY_SIZE(iin_limit_attrs),
-       }, {
-               .reg = PMBUS_READ_IOUT,
-               .class = PSC_CURRENT_OUT,
-               .label = "iout",
-               .paged = true,
-               .func = PMBUS_HAVE_IOUT,
-               .sfunc = PMBUS_HAVE_STATUS_IOUT,
-               .sbase = PB_STATUS_IOUT_BASE,
-               .gbit = PB_STATUS_IOUT_OC,
-               .limit = iout_limit_attrs,
-               .nlimit = ARRAY_SIZE(iout_limit_attrs),
-       }
-};
-
-/* Power attributes */
-
-static const struct pmbus_limit_attr pin_limit_attrs[] = {
-       {
-               .reg = PMBUS_PIN_OP_WARN_LIMIT,
-               .attr = "max",
-               .alarm = "alarm",
-               .sbit = PB_PIN_OP_WARNING,
-       }
-};
-
-static const struct pmbus_limit_attr pout_limit_attrs[] = {
-       {
-               .reg = PMBUS_POUT_MAX,
-               .attr = "cap",
-               .alarm = "cap_alarm",
-               .sbit = PB_POWER_LIMITING,
-       }, {
-               .reg = PMBUS_POUT_OP_WARN_LIMIT,
-               .attr = "max",
-               .alarm = "max_alarm",
-               .sbit = PB_POUT_OP_WARNING,
-       }, {
-               .reg = PMBUS_POUT_OP_FAULT_LIMIT,
-               .attr = "crit",
-               .alarm = "crit_alarm",
-               .sbit = PB_POUT_OP_FAULT,
-       }
-};
-
-static const struct pmbus_sensor_attr power_attributes[] = {
-       {
-               .reg = PMBUS_READ_PIN,
-               .class = PSC_POWER,
-               .label = "pin",
-               .func = PMBUS_HAVE_PIN,
-               .sfunc = PMBUS_HAVE_STATUS_INPUT,
-               .sbase = PB_STATUS_INPUT_BASE,
-               .limit = pin_limit_attrs,
-               .nlimit = ARRAY_SIZE(pin_limit_attrs),
-       }, {
-               .reg = PMBUS_READ_POUT,
-               .class = PSC_POWER,
-               .label = "pout",
-               .paged = true,
-               .func = PMBUS_HAVE_POUT,
-               .sfunc = PMBUS_HAVE_STATUS_IOUT,
-               .sbase = PB_STATUS_IOUT_BASE,
-               .limit = pout_limit_attrs,
-               .nlimit = ARRAY_SIZE(pout_limit_attrs),
-       }
-};
-
-/* Temperature atributes */
-
-static const struct pmbus_limit_attr temp_limit_attrs[] = {
-       {
-               .reg = PMBUS_UT_WARN_LIMIT,
-               .attr = "min",
-               .alarm = "min_alarm",
-               .sbit = PB_TEMP_UT_WARNING,
-       }, {
-               .reg = PMBUS_UT_FAULT_LIMIT,
-               .attr = "lcrit",
-               .alarm = "lcrit_alarm",
-               .sbit = PB_TEMP_UT_FAULT,
-       }, {
-               .reg = PMBUS_OT_WARN_LIMIT,
-               .attr = "max",
-               .alarm = "max_alarm",
-               .sbit = PB_TEMP_OT_WARNING,
-       }, {
-               .reg = PMBUS_OT_FAULT_LIMIT,
-               .attr = "crit",
-               .alarm = "crit_alarm",
-               .sbit = PB_TEMP_OT_FAULT,
-       }
-};
-
-static const struct pmbus_sensor_attr temp_attributes[] = {
-       {
-               .reg = PMBUS_READ_TEMPERATURE_1,
-               .class = PSC_TEMPERATURE,
-               .paged = true,
-               .update = true,
-               .compare = true,
-               .func = PMBUS_HAVE_TEMP,
-               .sfunc = PMBUS_HAVE_STATUS_TEMP,
-               .sbase = PB_STATUS_TEMP_BASE,
-               .gbit = PB_STATUS_TEMPERATURE,
-               .limit = temp_limit_attrs,
-               .nlimit = ARRAY_SIZE(temp_limit_attrs),
-       }, {
-               .reg = PMBUS_READ_TEMPERATURE_2,
-               .class = PSC_TEMPERATURE,
-               .paged = true,
-               .update = true,
-               .compare = true,
-               .func = PMBUS_HAVE_TEMP2,
-               .sfunc = PMBUS_HAVE_STATUS_TEMP,
-               .sbase = PB_STATUS_TEMP_BASE,
-               .gbit = PB_STATUS_TEMPERATURE,
-               .limit = temp_limit_attrs,
-               .nlimit = ARRAY_SIZE(temp_limit_attrs),
-       }, {
-               .reg = PMBUS_READ_TEMPERATURE_3,
-               .class = PSC_TEMPERATURE,
-               .paged = true,
-               .update = true,
-               .compare = true,
-               .func = PMBUS_HAVE_TEMP3,
-               .sfunc = PMBUS_HAVE_STATUS_TEMP,
-               .sbase = PB_STATUS_TEMP_BASE,
-               .gbit = PB_STATUS_TEMPERATURE,
-               .limit = temp_limit_attrs,
-               .nlimit = ARRAY_SIZE(temp_limit_attrs),
-       }
-};
-
-static const int pmbus_fan_registers[] = {
-       PMBUS_READ_FAN_SPEED_1,
-       PMBUS_READ_FAN_SPEED_2,
-       PMBUS_READ_FAN_SPEED_3,
-       PMBUS_READ_FAN_SPEED_4
-};
-
-static const int pmbus_fan_config_registers[] = {
-       PMBUS_FAN_CONFIG_12,
-       PMBUS_FAN_CONFIG_12,
-       PMBUS_FAN_CONFIG_34,
-       PMBUS_FAN_CONFIG_34
-};
-
-static const int pmbus_fan_status_registers[] = {
-       PMBUS_STATUS_FAN_12,
-       PMBUS_STATUS_FAN_12,
-       PMBUS_STATUS_FAN_34,
-       PMBUS_STATUS_FAN_34
-};
-
-static const u32 pmbus_fan_flags[] = {
-       PMBUS_HAVE_FAN12,
-       PMBUS_HAVE_FAN12,
-       PMBUS_HAVE_FAN34,
-       PMBUS_HAVE_FAN34
-};
-
-static const u32 pmbus_fan_status_flags[] = {
-       PMBUS_HAVE_STATUS_FAN12,
-       PMBUS_HAVE_STATUS_FAN12,
-       PMBUS_HAVE_STATUS_FAN34,
-       PMBUS_HAVE_STATUS_FAN34
-};
-
-/* Fans */
-static void pmbus_add_fan_attributes(struct i2c_client *client,
-                                    struct pmbus_data *data)
-{
-       const struct pmbus_driver_info *info = data->info;
-       int index = 1;
-       int page;
-
-       for (page = 0; page < info->pages; page++) {
-               int f;
-
-               for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) {
-                       int regval;
-
-                       if (!(info->func[page] & pmbus_fan_flags[f]))
-                               break;
-
-                       if (!pmbus_check_word_register(client, page,
-                                                      pmbus_fan_registers[f]))
-                               break;
-
-                       /*
-                        * Skip fan if not installed.
-                        * Each fan configuration register covers multiple fans,
-                        * so we have to do some magic.
-                        */
-                       regval = _pmbus_read_byte_data(client, page,
-                               pmbus_fan_config_registers[f]);
-                       if (regval < 0 ||
-                           (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
-                               continue;
-
-                       pmbus_add_sensor(data, "fan", "input", index, page,
-                                        pmbus_fan_registers[f], PSC_FAN, true,
-                                        true);
-
-                       /*
-                        * Each fan status register covers multiple fans,
-                        * so we have to do some magic.
-                        */
-                       if ((info->func[page] & pmbus_fan_status_flags[f]) &&
-                           pmbus_check_byte_register(client,
-                                       page, pmbus_fan_status_registers[f])) {
-                               int base;
-
-                               if (f > 1)      /* fan 3, 4 */
-                                       base = PB_STATUS_FAN34_BASE + page;
-                               else
-                                       base = PB_STATUS_FAN_BASE + page;
-                               pmbus_add_boolean_reg(data, "fan", "alarm",
-                                       index, base,
-                                       PB_FAN_FAN1_WARNING >> (f & 1));
-                               pmbus_add_boolean_reg(data, "fan", "fault",
-                                       index, base,
-                                       PB_FAN_FAN1_FAULT >> (f & 1));
-                       }
-                       index++;
-               }
-       }
-}
-
-static void pmbus_find_attributes(struct i2c_client *client,
-                                 struct pmbus_data *data)
-{
-       /* Voltage sensors */
-       pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
-                              ARRAY_SIZE(voltage_attributes));
-
-       /* Current sensors */
-       pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
-                              ARRAY_SIZE(current_attributes));
-
-       /* Power sensors */
-       pmbus_add_sensor_attrs(client, data, "power", power_attributes,
-                              ARRAY_SIZE(power_attributes));
-
-       /* Temperature sensors */
-       pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
-                              ARRAY_SIZE(temp_attributes));
-
-       /* Fans */
-       pmbus_add_fan_attributes(client, data);
-}
-
-/*
- * Identify chip parameters.
- * This function is called for all chips.
- */
-static int pmbus_identify_common(struct i2c_client *client,
-                                struct pmbus_data *data)
-{
-       int vout_mode = -1, exponent;
-
-       if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE))
-               vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
-       if (vout_mode >= 0 && vout_mode != 0xff) {
-               /*
-                * Not all chips support the VOUT_MODE command,
-                * so a failure to read it is not an error.
-                */
-               switch (vout_mode >> 5) {
-               case 0: /* linear mode      */
-                       if (data->info->direct[PSC_VOLTAGE_OUT])
-                               return -ENODEV;
-
-                       exponent = vout_mode & 0x1f;
-                       /* and sign-extend it */
-                       if (exponent & 0x10)
-                               exponent |= ~0x1f;
-                       data->exponent = exponent;
-                       break;
-               case 2: /* direct mode      */
-                       if (!data->info->direct[PSC_VOLTAGE_OUT])
-                               return -ENODEV;
-                       break;
-               default:
-                       return -ENODEV;
-               }
-       }
-
-       /* Determine maximum number of sensors, booleans, and labels */
-       pmbus_find_max_attr(client, data);
-       pmbus_clear_fault_page(client, 0);
-       return 0;
-}
-
-int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
-                  struct pmbus_driver_info *info)
-{
-       const struct pmbus_platform_data *pdata = client->dev.platform_data;
-       struct pmbus_data *data;
-       int ret;
-
-       if (!info) {
-               dev_err(&client->dev, "Missing chip information");
-               return -ENODEV;
-       }
-
-       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
-                                    | I2C_FUNC_SMBUS_BYTE_DATA
-                                    | I2C_FUNC_SMBUS_WORD_DATA))
-               return -ENODEV;
-
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               dev_err(&client->dev, "No memory to allocate driver data\n");
-               return -ENOMEM;
-       }
-
-       i2c_set_clientdata(client, data);
-       mutex_init(&data->update_lock);
-
-       /* Bail out if PMBus status register does not exist. */
-       if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) {
-               dev_err(&client->dev, "PMBus status register not found\n");
-               ret = -ENODEV;
-               goto out_data;
-       }
-
-       if (pdata)
-               data->flags = pdata->flags;
-       data->info = info;
-
-       pmbus_clear_faults(client);
-
-       if (info->identify) {
-               ret = (*info->identify)(client, info);
-               if (ret < 0) {
-                       dev_err(&client->dev, "Chip identification failed\n");
-                       goto out_data;
-               }
-       }
-
-       if (info->pages <= 0 || info->pages > PMBUS_PAGES) {
-               dev_err(&client->dev, "Bad number of PMBus pages: %d\n",
-                       info->pages);
-               ret = -EINVAL;
-               goto out_data;
-       }
-       /*
-        * Bail out if more than one page was configured, but we can not
-        * select the highest page. This is an indication that the wrong
-        * chip type was selected. Better bail out now than keep
-        * returning errors later on.
-        */
-       if (info->pages > 1 && pmbus_set_page(client, info->pages - 1) < 0) {
-               dev_err(&client->dev, "Failed to select page %d\n",
-                       info->pages - 1);
-               ret = -EINVAL;
-               goto out_data;
-       }
-
-       ret = pmbus_identify_common(client, data);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed to identify chip capabilities\n");
-               goto out_data;
-       }
-
-       ret = -ENOMEM;
-       data->sensors = kzalloc(sizeof(struct pmbus_sensor) * data->max_sensors,
-                               GFP_KERNEL);
-       if (!data->sensors) {
-               dev_err(&client->dev, "No memory to allocate sensor data\n");
-               goto out_data;
-       }
-
-       data->booleans = kzalloc(sizeof(struct pmbus_boolean)
-                                * data->max_booleans, GFP_KERNEL);
-       if (!data->booleans) {
-               dev_err(&client->dev, "No memory to allocate boolean data\n");
-               goto out_sensors;
-       }
-
-       data->labels = kzalloc(sizeof(struct pmbus_label) * data->max_labels,
-                              GFP_KERNEL);
-       if (!data->labels) {
-               dev_err(&client->dev, "No memory to allocate label data\n");
-               goto out_booleans;
-       }
-
-       data->attributes = kzalloc(sizeof(struct attribute *)
-                                  * data->max_attributes, GFP_KERNEL);
-       if (!data->attributes) {
-               dev_err(&client->dev, "No memory to allocate attribute data\n");
-               goto out_labels;
-       }
-
-       pmbus_find_attributes(client, data);
-
-       /*
-        * If there are no attributes, something is wrong.
-        * Bail out instead of trying to register nothing.
-        */
-       if (!data->num_attributes) {
-               dev_err(&client->dev, "No attributes found\n");
-               ret = -ENODEV;
-               goto out_attributes;
-       }
-
-       /* Register sysfs hooks */
-       data->group.attrs = data->attributes;
-       ret = sysfs_create_group(&client->dev.kobj, &data->group);
-       if (ret) {
-               dev_err(&client->dev, "Failed to create sysfs entries\n");
-               goto out_attributes;
-       }
-       data->hwmon_dev = hwmon_device_register(&client->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               ret = PTR_ERR(data->hwmon_dev);
-               dev_err(&client->dev, "Failed to register hwmon device\n");
-               goto out_hwmon_device_register;
-       }
-       return 0;
-
-out_hwmon_device_register:
-       sysfs_remove_group(&client->dev.kobj, &data->group);
-out_attributes:
-       kfree(data->attributes);
-out_labels:
-       kfree(data->labels);
-out_booleans:
-       kfree(data->booleans);
-out_sensors:
-       kfree(data->sensors);
-out_data:
-       kfree(data);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(pmbus_do_probe);
-
-int pmbus_do_remove(struct i2c_client *client)
-{
-       struct pmbus_data *data = i2c_get_clientdata(client);
-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&client->dev.kobj, &data->group);
-       kfree(data->attributes);
-       kfree(data->labels);
-       kfree(data->booleans);
-       kfree(data->sensors);
-       kfree(data);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(pmbus_do_remove);
-
-MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus core driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ucd9000.c b/drivers/hwmon/ucd9000.c
deleted file mode 100644 (file)
index ace1c73..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Hardware monitoring driver for UCD90xxx Sequencer and System Health
- * Controller series
- *
- * Copyright (C) 2011 Ericsson AB.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/i2c/pmbus.h>
-#include "pmbus.h"
-
-enum chips { ucd9000, ucd90120, ucd90124, ucd9090, ucd90910 };
-
-#define UCD9000_MONITOR_CONFIG         0xd5
-#define UCD9000_NUM_PAGES              0xd6
-#define UCD9000_FAN_CONFIG_INDEX       0xe7
-#define UCD9000_FAN_CONFIG             0xe8
-#define UCD9000_DEVICE_ID              0xfd
-
-#define UCD9000_MON_TYPE(x)    (((x) >> 5) & 0x07)
-#define UCD9000_MON_PAGE(x)    ((x) & 0x0f)
-
-#define UCD9000_MON_VOLTAGE    1
-#define UCD9000_MON_TEMPERATURE        2
-#define UCD9000_MON_CURRENT    3
-#define UCD9000_MON_VOLTAGE_HW 4
-
-#define UCD9000_NUM_FAN                4
-
-struct ucd9000_data {
-       u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX];
-       struct pmbus_driver_info info;
-};
-#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info)
-
-static int ucd9000_get_fan_config(struct i2c_client *client, int fan)
-{
-       int fan_config = 0;
-       struct ucd9000_data *data
-         = to_ucd9000_data(pmbus_get_driver_info(client));
-
-       if (data->fan_data[fan][3] & 1)
-               fan_config |= PB_FAN_2_INSTALLED;   /* Use lower bit position */
-
-       /* Pulses/revolution */
-       fan_config |= (data->fan_data[fan][3] & 0x06) >> 1;
-
-       return fan_config;
-}
-
-static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg)
-{
-       int ret = 0;
-       int fan_config;
-
-       switch (reg) {
-       case PMBUS_FAN_CONFIG_12:
-               if (page)
-                       return -EINVAL;
-
-               ret = ucd9000_get_fan_config(client, 0);
-               if (ret < 0)
-                       return ret;
-               fan_config = ret << 4;
-               ret = ucd9000_get_fan_config(client, 1);
-               if (ret < 0)
-                       return ret;
-               fan_config |= ret;
-               ret = fan_config;
-               break;
-       case PMBUS_FAN_CONFIG_34:
-               if (page)
-                       return -EINVAL;
-
-               ret = ucd9000_get_fan_config(client, 2);
-               if (ret < 0)
-                       return ret;
-               fan_config = ret << 4;
-               ret = ucd9000_get_fan_config(client, 3);
-               if (ret < 0)
-                       return ret;
-               fan_config |= ret;
-               ret = fan_config;
-               break;
-       default:
-               ret = -ENODATA;
-               break;
-       }
-       return ret;
-}
-
-static const struct i2c_device_id ucd9000_id[] = {
-       {"ucd9000", ucd9000},
-       {"ucd90120", ucd90120},
-       {"ucd90124", ucd90124},
-       {"ucd9090", ucd9090},
-       {"ucd90910", ucd90910},
-       {}
-};
-MODULE_DEVICE_TABLE(i2c, ucd9000_id);
-
-static int ucd9000_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
-{
-       u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
-       struct ucd9000_data *data;
-       struct pmbus_driver_info *info;
-       const struct i2c_device_id *mid;
-       int i, ret;
-
-       if (!i2c_check_functionality(client->adapter,
-                                    I2C_FUNC_SMBUS_BYTE_DATA |
-                                    I2C_FUNC_SMBUS_BLOCK_DATA))
-               return -ENODEV;
-
-       ret = i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID,
-                                       block_buffer);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed to read device ID\n");
-               return ret;
-       }
-       block_buffer[ret] = '\0';
-       dev_info(&client->dev, "Device ID %s\n", block_buffer);
-
-       mid = NULL;
-       for (i = 0; i < ARRAY_SIZE(ucd9000_id); i++) {
-               mid = &ucd9000_id[i];
-               if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
-                       break;
-       }
-       if (!mid || !strlen(mid->name)) {
-               dev_err(&client->dev, "Unsupported device\n");
-               return -ENODEV;
-       }
-
-       if (id->driver_data != ucd9000 && id->driver_data != mid->driver_data)
-               dev_notice(&client->dev,
-                          "Device mismatch: Configured %s, detected %s\n",
-                          id->name, mid->name);
-
-       data = kzalloc(sizeof(struct ucd9000_data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-       info = &data->info;
-
-       ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES);
-       if (ret < 0) {
-               dev_err(&client->dev,
-                       "Failed to read number of active pages\n");
-               goto out;
-       }
-       info->pages = ret;
-       if (!info->pages) {
-               dev_err(&client->dev, "No pages configured\n");
-               ret = -ENODEV;
-               goto out;
-       }
-
-       /* The internal temperature sensor is always active */
-       info->func[0] = PMBUS_HAVE_TEMP;
-
-       /* Everything else is configurable */
-       ret = i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG,
-                                       block_buffer);
-       if (ret <= 0) {
-               dev_err(&client->dev, "Failed to read configuration data\n");
-               ret = -ENODEV;
-               goto out;
-       }
-       for (i = 0; i < ret; i++) {
-               int page = UCD9000_MON_PAGE(block_buffer[i]);
-
-               if (page >= info->pages)
-                       continue;
-
-               switch (UCD9000_MON_TYPE(block_buffer[i])) {
-               case UCD9000_MON_VOLTAGE:
-               case UCD9000_MON_VOLTAGE_HW:
-                       info->func[page] |= PMBUS_HAVE_VOUT
-                         | PMBUS_HAVE_STATUS_VOUT;
-                       break;
-               case UCD9000_MON_TEMPERATURE:
-                       info->func[page] |= PMBUS_HAVE_TEMP2
-                         | PMBUS_HAVE_STATUS_TEMP;
-                       break;
-               case UCD9000_MON_CURRENT:
-                       info->func[page] |= PMBUS_HAVE_IOUT
-                         | PMBUS_HAVE_STATUS_IOUT;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       /* Fan configuration */
-       if (mid->driver_data == ucd90124) {
-               for (i = 0; i < UCD9000_NUM_FAN; i++) {
-                       i2c_smbus_write_byte_data(client,
-                                                 UCD9000_FAN_CONFIG_INDEX, i);
-                       ret = i2c_smbus_read_block_data(client,
-                                                       UCD9000_FAN_CONFIG,
-                                                       data->fan_data[i]);
-                       if (ret < 0)
-                               goto out;
-               }
-               i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0);
-
-               info->read_byte_data = ucd9000_read_byte_data;
-               info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12
-                 | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34;
-       }
-
-       ret = pmbus_do_probe(client, mid, info);
-       if (ret < 0)
-               goto out;
-       return 0;
-
-out:
-       kfree(data);
-       return ret;
-}
-
-static int ucd9000_remove(struct i2c_client *client)
-{
-       int ret;
-       struct ucd9000_data *data;
-
-       data = to_ucd9000_data(pmbus_get_driver_info(client));
-       ret = pmbus_do_remove(client);
-       kfree(data);
-       return ret;
-}
-
-
-/* This is the driver that will be inserted */
-static struct i2c_driver ucd9000_driver = {
-       .driver = {
-               .name = "ucd9000",
-       },
-       .probe = ucd9000_probe,
-       .remove = ucd9000_remove,
-       .id_table = ucd9000_id,
-};
-
-static int __init ucd9000_init(void)
-{
-       return i2c_add_driver(&ucd9000_driver);
-}
-
-static void __exit ucd9000_exit(void)
-{
-       i2c_del_driver(&ucd9000_driver);
-}
-
-MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx");
-MODULE_LICENSE("GPL");
-module_init(ucd9000_init);
-module_exit(ucd9000_exit);
diff --git a/drivers/hwmon/ucd9200.c b/drivers/hwmon/ucd9200.c
deleted file mode 100644 (file)
index ffcc1cf..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Hardware monitoring driver for ucd9200 series Digital PWM System Controllers
- *
- * Copyright (C) 2011 Ericsson AB.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/i2c/pmbus.h>
-#include "pmbus.h"
-
-#define UCD9200_PHASE_INFO     0xd2
-#define UCD9200_DEVICE_ID      0xfd
-
-enum chips { ucd9200, ucd9220, ucd9222, ucd9224, ucd9240, ucd9244, ucd9246,
-            ucd9248 };
-
-static const struct i2c_device_id ucd9200_id[] = {
-       {"ucd9200", ucd9200},
-       {"ucd9220", ucd9220},
-       {"ucd9222", ucd9222},
-       {"ucd9224", ucd9224},
-       {"ucd9240", ucd9240},
-       {"ucd9244", ucd9244},
-       {"ucd9246", ucd9246},
-       {"ucd9248", ucd9248},
-       {}
-};
-MODULE_DEVICE_TABLE(i2c, ucd9200_id);
-
-static int ucd9200_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
-{
-       u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
-       struct pmbus_driver_info *info;
-       const struct i2c_device_id *mid;
-       int i, j, ret;
-
-       if (!i2c_check_functionality(client->adapter,
-                                    I2C_FUNC_SMBUS_BYTE_DATA |
-                                    I2C_FUNC_SMBUS_BLOCK_DATA))
-               return -ENODEV;
-
-       ret = i2c_smbus_read_block_data(client, UCD9200_DEVICE_ID,
-                                       block_buffer);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed to read device ID\n");
-               return ret;
-       }
-       block_buffer[ret] = '\0';
-       dev_info(&client->dev, "Device ID %s\n", block_buffer);
-
-       mid = NULL;
-       for (i = 0; i < ARRAY_SIZE(ucd9200_id); i++) {
-               mid = &ucd9200_id[i];
-               if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
-                       break;
-       }
-       if (!mid || !strlen(mid->name)) {
-               dev_err(&client->dev, "Unsupported device\n");
-               return -ENODEV;
-       }
-       if (id->driver_data != ucd9200 && id->driver_data != mid->driver_data)
-               dev_notice(&client->dev,
-                          "Device mismatch: Configured %s, detected %s\n",
-                          id->name, mid->name);
-
-       info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       ret = i2c_smbus_read_block_data(client, UCD9200_PHASE_INFO,
-                                       block_buffer);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed to read phase information\n");
-               goto out;
-       }
-
-       /*
-        * Calculate number of configured pages (rails) from PHASE_INFO
-        * register.
-        * Rails have to be sequential, so we can abort after finding
-        * the first unconfigured rail.
-        */
-       info->pages = 0;
-       for (i = 0; i < ret; i++) {
-               if (!block_buffer[i])
-                       break;
-               info->pages++;
-       }
-       if (!info->pages) {
-               dev_err(&client->dev, "No rails configured\n");
-               ret = -ENODEV;
-               goto out;
-       }
-       dev_info(&client->dev, "%d rails configured\n", info->pages);
-
-       /*
-        * Set PHASE registers on all pages to 0xff to ensure that phase
-        * specific commands will apply to all phases of a given page (rail).
-        * This only affects the READ_IOUT and READ_TEMPERATURE2 registers.
-        * READ_IOUT will return the sum of currents of all phases of a rail,
-        * and READ_TEMPERATURE2 will return the maximum temperature detected
-        * for the the phases of the rail.
-        */
-       for (i = 0; i < info->pages; i++) {
-               /*
-                * Setting PAGE & PHASE fails once in a while for no obvious
-                * reason, so we need to retry a couple of times.
-                */
-               for (j = 0; j < 3; j++) {
-                       ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
-                       if (ret < 0)
-                               continue;
-                       ret = i2c_smbus_write_byte_data(client, PMBUS_PHASE,
-                                                       0xff);
-                       if (ret < 0)
-                               continue;
-                       break;
-               }
-               if (ret < 0) {
-                       dev_err(&client->dev,
-                               "Failed to initialize PHASE registers\n");
-                       goto out;
-               }
-       }
-       if (info->pages > 1)
-               i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
-
-       info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT |
-                       PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
-                       PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
-                       PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
-                       PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP |
-                       PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
-
-       for (i = 1; i < info->pages; i++)
-               info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
-                       PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
-                       PMBUS_HAVE_POUT |
-                       PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
-
-       /* ucd9240 supports a single fan */
-       if (mid->driver_data == ucd9240)
-               info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12;
-
-       ret = pmbus_do_probe(client, mid, info);
-       if (ret < 0)
-               goto out;
-       return 0;
-out:
-       kfree(info);
-       return ret;
-}
-
-static int ucd9200_remove(struct i2c_client *client)
-{
-       int ret;
-       const struct pmbus_driver_info *info;
-
-       info = pmbus_get_driver_info(client);
-       ret = pmbus_do_remove(client);
-       kfree(info);
-       return ret;
-}
-
-
-/* This is the driver that will be inserted */
-static struct i2c_driver ucd9200_driver = {
-       .driver = {
-               .name = "ucd9200",
-       },
-       .probe = ucd9200_probe,
-       .remove = ucd9200_remove,
-       .id_table = ucd9200_id,
-};
-
-static int __init ucd9200_init(void)
-{
-       return i2c_add_driver(&ucd9200_driver);
-}
-
-static void __exit ucd9200_exit(void)
-{
-       i2c_del_driver(&ucd9200_driver);
-}
-
-MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x");
-MODULE_LICENSE("GPL");
-module_init(ucd9200_init);
-module_exit(ucd9200_exit);
index 95a08a8ca8aab9fe3532cb877a38ba0026767bb0..5745b7fe158c0e4178ae240dea6c3c4a8894d60f 100644 (file)
@@ -271,7 +271,7 @@ int iser_send_command(struct iscsi_conn *conn,
        unsigned long edtl;
        int err;
        struct iser_data_buf *data_buf;
-       struct iscsi_cmd *hdr =  (struct iscsi_cmd *)task->hdr;
+       struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr;
        struct scsi_cmnd *sc  =  task->sc;
        struct iser_tx_desc *tx_desc = &iser_task->desc;
 
index 56abf3d0e911236d4d2972860ba1521072a4a4d2..d72887585a14d5ba12cce8666dc80eb1f2dbf5ab 100644 (file)
@@ -154,10 +154,13 @@ static const struct xpad_device {
        { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
        { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
        { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+       { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
        { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
        { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
+       { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
        { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
@@ -236,9 +239,10 @@ static struct usb_device_id xpad_table [] = {
        XPAD_XBOX360_VENDOR(0x046d),            /* Logitech X-Box 360 style controllers */
        XPAD_XBOX360_VENDOR(0x0738),            /* Mad Catz X-Box 360 controllers */
        XPAD_XBOX360_VENDOR(0x0e6f),            /* 0x0e6f X-Box 360 controllers */
+       XPAD_XBOX360_VENDOR(0x12ab),            /* X-Box 360 dance pads */
        XPAD_XBOX360_VENDOR(0x1430),            /* RedOctane X-Box 360 controllers */
        XPAD_XBOX360_VENDOR(0x146b),            /* BigBen Interactive Controllers */
-       XPAD_XBOX360_VENDOR(0x1bad),            /* Rock Band Drums */
+       XPAD_XBOX360_VENDOR(0x1bad),            /* Harminix Rock Band Guitar and Drums */
        XPAD_XBOX360_VENDOR(0x0f0d),            /* Hori Controllers */
        { }
 };
@@ -545,7 +549,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
        struct usb_endpoint_descriptor *ep_irq_out;
        int error;
 
-       if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
+       if (xpad->xtype == XTYPE_UNKNOWN)
                return 0;
 
        xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
@@ -579,13 +583,13 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
 
 static void xpad_stop_output(struct usb_xpad *xpad)
 {
-       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX)
+       if (xpad->xtype != XTYPE_UNKNOWN)
                usb_kill_urb(xpad->irq_out);
 }
 
 static void xpad_deinit_output(struct usb_xpad *xpad)
 {
-       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) {
+       if (xpad->xtype != XTYPE_UNKNOWN) {
                usb_free_urb(xpad->irq_out);
                usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
                                xpad->odata, xpad->odata_dma);
@@ -632,6 +636,23 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
 
                        return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
 
+               case XTYPE_XBOX360W:
+                       xpad->odata[0] = 0x00;
+                       xpad->odata[1] = 0x01;
+                       xpad->odata[2] = 0x0F;
+                       xpad->odata[3] = 0xC0;
+                       xpad->odata[4] = 0x00;
+                       xpad->odata[5] = strong / 256;
+                       xpad->odata[6] = weak / 256;
+                       xpad->odata[7] = 0x00;
+                       xpad->odata[8] = 0x00;
+                       xpad->odata[9] = 0x00;
+                       xpad->odata[10] = 0x00;
+                       xpad->odata[11] = 0x00;
+                       xpad->irq_out->transfer_buffer_length = 12;
+
+                       return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
+
                default:
                        dbg("%s - rumble command sent to unsupported xpad type: %d",
                                __func__, xpad->xtype);
@@ -644,7 +665,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
 
 static int xpad_init_ff(struct usb_xpad *xpad)
 {
-       if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
+       if (xpad->xtype == XTYPE_UNKNOWN)
                return 0;
 
        input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
index af45d275f6862924979f48def9b1aa43ece095eb..7b404e5443ed15fa4bc2ba98eebd390e3b3f700b 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index 631598663aab33f2f54923c18a0edfe2f067d019..c7708263051bceffb1cb0dd098a3eb3bbf27fdeb 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index 11478eb2c27de1ec332b8f3e4a5b1a56408b49ce..19cfc0cf558c99b18875ca0fd0b6aac26134e356 100644 (file)
@@ -1578,14 +1578,14 @@ static int __init atkbd_setup_forced_release(const struct dmi_system_id *id)
        atkbd_platform_fixup = atkbd_apply_forced_release_keylist;
        atkbd_platform_fixup_data = id->driver_data;
 
-       return 0;
+       return 1;
 }
 
 static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
 {
        atkbd_platform_scancode_fixup = id->driver_data;
 
-       return 0;
+       return 1;
 }
 
 static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
index 6e6145b9a4c10b2d84bfd3cce75b1ea12a100b43..ce281d152275783a8c27893d177b41fb9654a2a2 100644 (file)
@@ -2,6 +2,7 @@
  * Driver for keys on GPIO lines capable of generating interrupts.
  *
  * Copyright 2005 Phil Blundell
+ * Copyright 2010, 2011 David Jander <david@protonic.nl>
  *
  * 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
@@ -25,6 +26,8 @@
 #include <linux/gpio_keys.h>
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 
 struct gpio_button_data {
        struct gpio_keys_button *button;
@@ -415,7 +418,7 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
        if (!button->can_disable)
                irqflags |= IRQF_SHARED;
 
-       error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
+       error = request_threaded_irq(irq, NULL, gpio_keys_isr, irqflags, desc, bdata);
        if (error < 0) {
                dev_err(dev, "Unable to claim irq %d; error %d\n",
                        irq, error);
@@ -445,15 +448,120 @@ static void gpio_keys_close(struct input_dev *input)
                ddata->disable(input->dev.parent);
 }
 
+/*
+ * Handlers for alternative sources of platform_data
+ */
+#ifdef CONFIG_OF
+/*
+ * Translate OpenFirmware node properties into platform_data
+ */
+static int gpio_keys_get_devtree_pdata(struct device *dev,
+                           struct gpio_keys_platform_data *pdata)
+{
+       struct device_node *node, *pp;
+       int i;
+       struct gpio_keys_button *buttons;
+       const u32 *reg;
+       int len;
+
+       node = dev->of_node;
+       if (node == NULL)
+               return -ENODEV;
+
+       memset(pdata, 0, sizeof *pdata);
+
+       pdata->rep = !!of_get_property(node, "autorepeat", &len);
+
+       /* First count the subnodes */
+       pdata->nbuttons = 0;
+       pp = NULL;
+       while ((pp = of_get_next_child(node, pp)))
+               pdata->nbuttons++;
+
+       if (pdata->nbuttons == 0)
+               return -ENODEV;
+
+       buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL);
+       if (!buttons)
+               return -ENODEV;
+
+       pp = NULL;
+       i = 0;
+       while ((pp = of_get_next_child(node, pp))) {
+               enum of_gpio_flags flags;
+
+               if (!of_find_property(pp, "gpios", NULL)) {
+                       pdata->nbuttons--;
+                       dev_warn(dev, "Found button without gpios\n");
+                       continue;
+               }
+               buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags);
+               buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW;
+
+               reg = of_get_property(pp, "linux,code", &len);
+               if (!reg) {
+                       dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio);
+                       goto out_fail;
+               }
+               buttons[i].code = be32_to_cpup(reg);
+
+               buttons[i].desc = of_get_property(pp, "label", &len);
+
+               reg = of_get_property(pp, "linux,input-type", &len);
+               buttons[i].type = reg ? be32_to_cpup(reg) : EV_KEY;
+
+               buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+
+               reg = of_get_property(pp, "debounce-interval", &len);
+               buttons[i].debounce_interval = reg ? be32_to_cpup(reg) : 5;
+
+               i++;
+       }
+
+       pdata->buttons = buttons;
+
+       return 0;
+
+out_fail:
+       kfree(buttons);
+       return -ENODEV;
+}
+
+static struct of_device_id gpio_keys_of_match[] = {
+       { .compatible = "gpio-keys", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
+
+#else
+
+static int gpio_keys_get_devtree_pdata(struct device *dev,
+                           struct gpio_keys_platform_data *altp)
+{
+       return -ENODEV;
+}
+
+#define gpio_keys_of_match NULL
+
+#endif
+
 static int __devinit gpio_keys_probe(struct platform_device *pdev)
 {
        struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
        struct gpio_keys_drvdata *ddata;
        struct device *dev = &pdev->dev;
+       struct gpio_keys_platform_data alt_pdata;
        struct input_dev *input;
        int i, error;
        int wakeup = 0;
 
+       if (!pdata) {
+               error = gpio_keys_get_devtree_pdata(dev, &alt_pdata);
+               if (error)
+                       return error;
+               pdata = &alt_pdata;
+       }
+
        ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
                        pdata->nbuttons * sizeof(struct gpio_button_data),
                        GFP_KERNEL);
@@ -544,13 +652,15 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
  fail1:
        input_free_device(input);
        kfree(ddata);
+       /* If we have no platform_data, we allocated buttons dynamically. */
+       if (!pdev->dev.platform_data)
+               kfree(pdata->buttons);
 
        return error;
 }
 
 static int __devexit gpio_keys_remove(struct platform_device *pdev)
 {
-       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
        struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
        struct input_dev *input = ddata->input;
        int i;
@@ -559,31 +669,39 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 
        device_init_wakeup(&pdev->dev, 0);
 
-       for (i = 0; i < pdata->nbuttons; i++) {
-               int irq = gpio_to_irq(pdata->buttons[i].gpio);
+       for (i = 0; i < ddata->n_buttons; i++) {
+               int irq = gpio_to_irq(ddata->data[i].button->gpio);
                free_irq(irq, &ddata->data[i]);
                if (ddata->data[i].timer_debounce)
                        del_timer_sync(&ddata->data[i].timer);
                cancel_work_sync(&ddata->data[i].work);
-               gpio_free(pdata->buttons[i].gpio);
+               gpio_free(ddata->data[i].button->gpio);
        }
 
        input_unregister_device(input);
 
+       /*
+        * If we had no platform_data, we allocated buttons dynamically, and
+        * must free them here. ddata->data[0].button is the pointer to the
+        * beginning of the allocated array.
+        */
+       if (!pdev->dev.platform_data)
+               kfree(ddata->data[0].button);
+
+       kfree(ddata);
+
        return 0;
 }
 
-
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int gpio_keys_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
        int i;
 
-       if (device_may_wakeup(&pdev->dev)) {
-               for (i = 0; i < pdata->nbuttons; i++) {
-                       struct gpio_keys_button *button = &pdata->buttons[i];
+       if (device_may_wakeup(dev)) {
+               for (i = 0; i < ddata->n_buttons; i++) {
+                       struct gpio_keys_button *button = ddata->data[i].button;
                        if (button->wakeup) {
                                int irq = gpio_to_irq(button->gpio);
                                enable_irq_wake(irq);
@@ -596,15 +714,13 @@ static int gpio_keys_suspend(struct device *dev)
 
 static int gpio_keys_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
-       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
        int i;
 
-       for (i = 0; i < pdata->nbuttons; i++) {
+       for (i = 0; i < ddata->n_buttons; i++) {
 
-               struct gpio_keys_button *button = &pdata->buttons[i];
-               if (button->wakeup && device_may_wakeup(&pdev->dev)) {
+               struct gpio_keys_button *button = ddata->data[i].button;
+               if (button->wakeup && device_may_wakeup(dev)) {
                        int irq = gpio_to_irq(button->gpio);
                        disable_irq_wake(irq);
                }
@@ -615,22 +731,18 @@ static int gpio_keys_resume(struct device *dev)
 
        return 0;
 }
-
-static const struct dev_pm_ops gpio_keys_pm_ops = {
-       .suspend        = gpio_keys_suspend,
-       .resume         = gpio_keys_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
+
 static struct platform_driver gpio_keys_device_driver = {
        .probe          = gpio_keys_probe,
        .remove         = __devexit_p(gpio_keys_remove),
        .driver         = {
                .name   = "gpio-keys",
                .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
                .pm     = &gpio_keys_pm_ops,
-#endif
+               .of_match_table = gpio_keys_of_match,
        }
 };
 
@@ -644,10 +756,10 @@ static void __exit gpio_keys_exit(void)
        platform_driver_unregister(&gpio_keys_device_driver);
 }
 
-module_init(gpio_keys_init);
+late_initcall(gpio_keys_init);
 module_exit(gpio_keys_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
-MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
+MODULE_DESCRIPTION("Keyboard driver for GPIOs");
 MODULE_ALIAS("platform:gpio-keys");
index 71f744a8e686232bd85156e4bc8b0f04fe3980ee..ab0acaf7fe8fdbc26ddb42a906db9f832826145d 100644 (file)
@@ -146,7 +146,6 @@ struct lm8323_chip {
        /* device lock */
        struct mutex            lock;
        struct i2c_client       *client;
-       struct work_struct      work;
        struct input_dev        *idev;
        bool                    kp_enabled;
        bool                    pm_suspend;
@@ -162,7 +161,6 @@ struct lm8323_chip {
 
 #define client_to_lm8323(c)    container_of(c, struct lm8323_chip, client)
 #define dev_to_lm8323(d)       container_of(d, struct lm8323_chip, client->dev)
-#define work_to_lm8323(w)      container_of(w, struct lm8323_chip, work)
 #define cdev_to_pwm(c)         container_of(c, struct lm8323_pwm, cdev)
 #define work_to_pwm(w)         container_of(w, struct lm8323_pwm, work)
 
@@ -375,9 +373,9 @@ static void pwm_done(struct lm8323_pwm *pwm)
  * Bottom half: handle the interrupt by posting key events, or dealing with
  * errors appropriately.
  */
-static void lm8323_work(struct work_struct *work)
+static irqreturn_t lm8323_irq(int irq, void *_lm)
 {
-       struct lm8323_chip *lm = work_to_lm8323(work);
+       struct lm8323_chip *lm = _lm;
        u8 ints;
        int i;
 
@@ -409,16 +407,6 @@ static void lm8323_work(struct work_struct *work)
        }
 
        mutex_unlock(&lm->lock);
-}
-
-/*
- * We cannot use I2C in interrupt context, so we just schedule work.
- */
-static irqreturn_t lm8323_irq(int irq, void *data)
-{
-       struct lm8323_chip *lm = data;
-
-       schedule_work(&lm->work);
 
        return IRQ_HANDLED;
 }
@@ -675,7 +663,6 @@ static int __devinit lm8323_probe(struct i2c_client *client,
        lm->client = client;
        lm->idev = idev;
        mutex_init(&lm->lock);
-       INIT_WORK(&lm->work, lm8323_work);
 
        lm->size_x = pdata->size_x;
        lm->size_y = pdata->size_y;
@@ -746,9 +733,8 @@ static int __devinit lm8323_probe(struct i2c_client *client,
                goto fail3;
        }
 
-       err = request_irq(client->irq, lm8323_irq,
-                         IRQF_TRIGGER_FALLING | IRQF_DISABLED,
-                         "lm8323", lm);
+       err = request_threaded_irq(client->irq, NULL, lm8323_irq,
+                         IRQF_TRIGGER_LOW|IRQF_ONESHOT, "lm8323", lm);
        if (err) {
                dev_err(&client->dev, "could not get IRQ %d\n", client->irq);
                goto fail4;
@@ -783,7 +769,6 @@ static int __devexit lm8323_remove(struct i2c_client *client)
 
        disable_irq_wake(client->irq);
        free_irq(client->irq, lm);
-       cancel_work_sync(&lm->work);
 
        input_unregister_device(lm->idev);
 
index 0a9e811948881864033efda02a353c01b9d5a435..1c1615d9a7f96ad340cfbdc24e1fe43ce1871ca1 100644 (file)
  * enabled capacitance sensing inputs and its run/suspend mode.
  */
 #define ELECTRODE_CONF_ADDR            0x5e
+#define ELECTRODE_CONF_QUICK_CHARGE    0x80
 #define AUTO_CONFIG_CTRL_ADDR          0x7b
 #define AUTO_CONFIG_USL_ADDR           0x7d
 #define AUTO_CONFIG_LSL_ADDR           0x7e
 #define AUTO_CONFIG_TL_ADDR            0x7f
 
 /* Threshold of touch/release trigger */
-#define TOUCH_THRESHOLD                        0x0f
-#define RELEASE_THRESHOLD              0x0a
+#define TOUCH_THRESHOLD                        0x08
+#define RELEASE_THRESHOLD              0x05
 /* Masks for touch and release triggers */
 #define TOUCH_STATUS_MASK              0xfff
 /* MPR121 has 12 keys */
@@ -127,7 +128,7 @@ static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
                                      struct i2c_client *client)
 {
        const struct mpr121_init_register *reg;
-       unsigned char usl, lsl, tl;
+       unsigned char usl, lsl, tl, eleconf;
        int i, t, vdd, ret;
 
        /* Set up touch/release threshold for ele0-ele11 */
@@ -163,8 +164,15 @@ static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
        ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl);
        ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl);
        ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl);
+
+       /*
+        * Quick charge bit will let the capacitive charge to ready
+        * state quickly, or the buttons may not function after system
+        * boot.
+        */
+       eleconf = mpr121->keycount | ELECTRODE_CONF_QUICK_CHARGE;
        ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
-                                        mpr121->keycount);
+                                        eleconf);
        if (ret != 0)
                goto err_i2c_write;
 
index 6229c3e8e78b807c90ab1a8f549e8b250601679e..e7cc51d0fb34adb6834381cffbdc0e9eed94f902 100644 (file)
@@ -700,9 +700,9 @@ static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
        return 0;
 
 err_pmic_reg_read:
-       free_irq(kp->key_stuck_irq, NULL);
+       free_irq(kp->key_stuck_irq, kp);
 err_req_stuck_irq:
-       free_irq(kp->key_sense_irq, NULL);
+       free_irq(kp->key_sense_irq, kp);
 err_gpio_config:
 err_get_irq:
        input_free_device(kp->input);
@@ -717,8 +717,8 @@ static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev)
        struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
 
        device_init_wakeup(&pdev->dev, 0);
-       free_irq(kp->key_stuck_irq, NULL);
-       free_irq(kp->key_sense_irq, NULL);
+       free_irq(kp->key_stuck_irq, kp);
+       free_irq(kp->key_sense_irq, kp);
        input_unregister_device(kp->input);
        kfree(kp);
 
index ca7b89196ab79a4ceee7b05ebe2ce65044c055b3..b21bf5b876bb8763037646442d3aa33d1ec85d66 100644 (file)
@@ -239,8 +239,6 @@ static int __devexit qt1070_remove(struct i2c_client *client)
        input_unregister_device(data->input);
        kfree(data);
 
-       i2c_set_clientdata(client, NULL);
-
        return 0;
 }
 
index 6876700a4469d191446a20a9c81dc2606279b9d2..934aeb583b3035205e8c141573cbce685c812db9 100644 (file)
@@ -291,7 +291,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#if CONFIG_PM_SLEEP
+#ifdef CONFIG_PM_SLEEP
 static int sh_keysc_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
index 2b3b73ec6689599596704a5bd175ee98d7b2d23b..da3828fc2c09fc151b129ebf4086cad8ecdf9bc3 100644 (file)
@@ -657,7 +657,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
 
        input_set_drvdata(input_dev, kbc);
 
-       input_dev->evbit[0] = BIT_MASK(EV_KEY);
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
        input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 
        input_dev->keycode = kbc->keycode;
index c8f097a15d89a4865ba0c324cc63b76cec2646f9..1c58681de81fe541338b6ec655ca8a008c305e01 100644 (file)
@@ -337,5 +337,5 @@ module_exit(keypad_exit);
 
 MODULE_AUTHOR("Cyril Chemparathy");
 MODULE_DESCRIPTION("TNETV107X Keypad Driver");
-MODULE_ALIAS("platform: tnetv107x-keypad");
+MODULE_ALIAS("platform:tnetv107x-keypad");
 MODULE_LICENSE("GPL");
index d1bf8724b58f79a7a8bed9cf567a0f24e53e6fed..c9104bb4db060061f4bc4dbdc6068dbfd7eeafa3 100644 (file)
@@ -100,6 +100,27 @@ config INPUT_MAX8925_ONKEY
          To compile this driver as a module, choose M here: the module
          will be called max8925_onkey.
 
+config INPUT_MMA8450
+       tristate "MMA8450 - Freescale's 3-Axis, 8/12-bit Digital Accelerometer"
+       depends on I2C
+       select INPUT_POLLDEV
+       help
+         Say Y here if you want to support Freescale's MMA8450 Accelerometer
+         through I2C interface.
+
+         To compile this driver as a module, choose M here: the
+         module will be called mma8450.
+
+config INPUT_MPU3050
+       tristate "MPU3050 Triaxial gyroscope sensor"
+       depends on I2C
+       help
+         Say Y here if you want to support InvenSense MPU3050
+         connected via an I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called mpu3050.
+
 config INPUT_APANEL
        tristate "Fujitsu Lifebook Application Panel buttons"
        depends on X86 && I2C && LEDS_CLASS
@@ -209,6 +230,23 @@ config INPUT_KEYSPAN_REMOTE
          To compile this driver as a module, choose M here: the module will
          be called keyspan_remote.
 
+config INPUT_KXTJ9
+       tristate "Kionix KXTJ9 tri-axis digital accelerometer"
+       depends on I2C
+       help
+         Say Y here to enable support for the Kionix KXTJ9 digital tri-axis
+         accelerometer.
+
+         To compile this driver as a module, choose M here: the module will
+         be called kxtj9.
+
+config INPUT_KXTJ9_POLLED_MODE
+       bool "Enable polling mode support"
+       depends on INPUT_KXTJ9
+       select INPUT_POLLDEV
+       help
+         Say Y here if you need accelerometer to work in polling mode.
+
 config INPUT_POWERMATE
        tristate "Griffin PowerMate and Contour Jog support"
        depends on USB_ARCH_HAS_HCD
index 4da7c3a60e04b2b0f77832d6b31a3424c5c3d9d6..299ad5edba846e18c57aebf2c6b9dddb78df943a 100644 (file)
@@ -25,8 +25,11 @@ obj-$(CONFIG_INPUT_DM355EVM)         += dm355evm_keys.o
 obj-$(CONFIG_HP_SDC_RTC)               += hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_IXP4XX_BEEPER)      += ixp4xx-beeper.o
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)     += keyspan_remote.o
+obj-$(CONFIG_INPUT_KXTJ9)              += kxtj9.o
 obj-$(CONFIG_INPUT_M68K_BEEP)          += m68kspkr.o
 obj-$(CONFIG_INPUT_MAX8925_ONKEY)      += max8925_onkey.o
+obj-$(CONFIG_INPUT_MMA8450)            += mma8450.o
+obj-$(CONFIG_INPUT_MPU3050)            += mpu3050.o
 obj-$(CONFIG_INPUT_PCAP)               += pcap_keys.o
 obj-$(CONFIG_INPUT_PCF50633_PMU)       += pcf50633-input.o
 obj-$(CONFIG_INPUT_PCF8574)            += pcf8574_keypad.o
@@ -46,4 +49,3 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS)      += wistron_btns.o
 obj-$(CONFIG_INPUT_WM831X_ON)          += wm831x-on.o
 obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)        += xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)            += yealink.o
-
index 4f72bdd694102eb626011956d1b3b642d6d1ae63..d00edc9f39d10e38a455579d3a58c8deb96c4216 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
new file mode 100644 (file)
index 0000000..c456f63
--- /dev/null
@@ -0,0 +1,671 @@
+/*
+ * Copyright (C) 2011 Kionix, Inc.
+ * Written by Chris Hudson <chudson@kionix.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
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/input/kxtj9.h>
+#include <linux/input-polldev.h>
+
+#define NAME                   "kxtj9"
+#define G_MAX                  8000
+/* OUTPUT REGISTERS */
+#define XOUT_L                 0x06
+#define WHO_AM_I               0x0F
+/* CONTROL REGISTERS */
+#define INT_REL                        0x1A
+#define CTRL_REG1              0x1B
+#define INT_CTRL1              0x1E
+#define DATA_CTRL              0x21
+/* CONTROL REGISTER 1 BITS */
+#define PC1_OFF                        0x7F
+#define PC1_ON                 (1 << 7)
+/* Data ready funtion enable bit: set during probe if using irq mode */
+#define DRDYE                  (1 << 5)
+/* INTERRUPT CONTROL REGISTER 1 BITS */
+/* Set these during probe if using irq mode */
+#define KXTJ9_IEL              (1 << 3)
+#define KXTJ9_IEA              (1 << 4)
+#define KXTJ9_IEN              (1 << 5)
+/* INPUT_ABS CONSTANTS */
+#define FUZZ                   3
+#define FLAT                   3
+/* RESUME STATE INDICES */
+#define RES_DATA_CTRL          0
+#define RES_CTRL_REG1          1
+#define RES_INT_CTRL1          2
+#define RESUME_ENTRIES         3
+
+/*
+ * The following table lists the maximum appropriate poll interval for each
+ * available output data rate.
+ */
+static const struct {
+       unsigned int cutoff;
+       u8 mask;
+} kxtj9_odr_table[] = {
+       { 3,    ODR800F },
+       { 5,    ODR400F },
+       { 10,   ODR200F },
+       { 20,   ODR100F },
+       { 40,   ODR50F  },
+       { 80,   ODR25F  },
+       { 0,    ODR12_5F},
+};
+
+struct kxtj9_data {
+       struct i2c_client *client;
+       struct kxtj9_platform_data pdata;
+       struct input_dev *input_dev;
+#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE
+       struct input_polled_dev *poll_dev;
+#endif
+       unsigned int last_poll_interval;
+       u8 shift;
+       u8 ctrl_reg1;
+       u8 data_ctrl;
+       u8 int_ctrl;
+};
+
+static int kxtj9_i2c_read(struct kxtj9_data *tj9, u8 addr, u8 *data, int len)
+{
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = tj9->client->addr,
+                       .flags = tj9->client->flags,
+                       .len = 1,
+                       .buf = &addr,
+               },
+               {
+                       .addr = tj9->client->addr,
+                       .flags = tj9->client->flags | I2C_M_RD,
+                       .len = len,
+                       .buf = data,
+               },
+       };
+
+       return i2c_transfer(tj9->client->adapter, msgs, 2);
+}
+
+static void kxtj9_report_acceleration_data(struct kxtj9_data *tj9)
+{
+       s16 acc_data[3]; /* Data bytes from hardware xL, xH, yL, yH, zL, zH */
+       s16 x, y, z;
+       int err;
+
+       err = kxtj9_i2c_read(tj9, XOUT_L, (u8 *)acc_data, 6);
+       if (err < 0)
+               dev_err(&tj9->client->dev, "accelerometer data read failed\n");
+
+       x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]) >> tj9->shift;
+       y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]) >> tj9->shift;
+       z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]) >> tj9->shift;
+
+       input_report_abs(tj9->input_dev, ABS_X, tj9->pdata.negate_x ? -x : x);
+       input_report_abs(tj9->input_dev, ABS_Y, tj9->pdata.negate_y ? -y : y);
+       input_report_abs(tj9->input_dev, ABS_Z, tj9->pdata.negate_z ? -z : z);
+       input_sync(tj9->input_dev);
+}
+
+static irqreturn_t kxtj9_isr(int irq, void *dev)
+{
+       struct kxtj9_data *tj9 = dev;
+       int err;
+
+       /* data ready is the only possible interrupt type */
+       kxtj9_report_acceleration_data(tj9);
+
+       err = i2c_smbus_read_byte_data(tj9->client, INT_REL);
+       if (err < 0)
+               dev_err(&tj9->client->dev,
+                       "error clearing interrupt status: %d\n", err);
+
+       return IRQ_HANDLED;
+}
+
+static int kxtj9_update_g_range(struct kxtj9_data *tj9, u8 new_g_range)
+{
+       switch (new_g_range) {
+       case KXTJ9_G_2G:
+               tj9->shift = 4;
+               break;
+       case KXTJ9_G_4G:
+               tj9->shift = 3;
+               break;
+       case KXTJ9_G_8G:
+               tj9->shift = 2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       tj9->ctrl_reg1 &= 0xe7;
+       tj9->ctrl_reg1 |= new_g_range;
+
+       return 0;
+}
+
+static int kxtj9_update_odr(struct kxtj9_data *tj9, unsigned int poll_interval)
+{
+       int err;
+       int i;
+
+       /* Use the lowest ODR that can support the requested poll interval */
+       for (i = 0; i < ARRAY_SIZE(kxtj9_odr_table); i++) {
+               tj9->data_ctrl = kxtj9_odr_table[i].mask;
+               if (poll_interval < kxtj9_odr_table[i].cutoff)
+                       break;
+       }
+
+       err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0);
+       if (err < 0)
+               return err;
+
+       err = i2c_smbus_write_byte_data(tj9->client, DATA_CTRL, tj9->data_ctrl);
+       if (err < 0)
+               return err;
+
+       err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int kxtj9_device_power_on(struct kxtj9_data *tj9)
+{
+       if (tj9->pdata.power_on)
+               return tj9->pdata.power_on();
+
+       return 0;
+}
+
+static void kxtj9_device_power_off(struct kxtj9_data *tj9)
+{
+       int err;
+
+       tj9->ctrl_reg1 &= PC1_OFF;
+       err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
+       if (err < 0)
+               dev_err(&tj9->client->dev, "soft power off failed\n");
+
+       if (tj9->pdata.power_off)
+               tj9->pdata.power_off();
+}
+
+static int kxtj9_enable(struct kxtj9_data *tj9)
+{
+       int err;
+
+       err = kxtj9_device_power_on(tj9);
+       if (err < 0)
+               return err;
+
+       /* ensure that PC1 is cleared before updating control registers */
+       err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0);
+       if (err < 0)
+               return err;
+
+       /* only write INT_CTRL_REG1 if in irq mode */
+       if (tj9->client->irq) {
+               err = i2c_smbus_write_byte_data(tj9->client,
+                                               INT_CTRL1, tj9->int_ctrl);
+               if (err < 0)
+                       return err;
+       }
+
+       err = kxtj9_update_g_range(tj9, tj9->pdata.g_range);
+       if (err < 0)
+               return err;
+
+       /* turn on outputs */
+       tj9->ctrl_reg1 |= PC1_ON;
+       err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
+       if (err < 0)
+               return err;
+
+       err = kxtj9_update_odr(tj9, tj9->last_poll_interval);
+       if (err < 0)
+               return err;
+
+       /* clear initial interrupt if in irq mode */
+       if (tj9->client->irq) {
+               err = i2c_smbus_read_byte_data(tj9->client, INT_REL);
+               if (err < 0) {
+                       dev_err(&tj9->client->dev,
+                               "error clearing interrupt: %d\n", err);
+                       goto fail;
+               }
+       }
+
+       return 0;
+
+fail:
+       kxtj9_device_power_off(tj9);
+       return err;
+}
+
+static void kxtj9_disable(struct kxtj9_data *tj9)
+{
+       kxtj9_device_power_off(tj9);
+}
+
+static int kxtj9_input_open(struct input_dev *input)
+{
+       struct kxtj9_data *tj9 = input_get_drvdata(input);
+
+       return kxtj9_enable(tj9);
+}
+
+static void kxtj9_input_close(struct input_dev *dev)
+{
+       struct kxtj9_data *tj9 = input_get_drvdata(dev);
+
+       kxtj9_disable(tj9);
+}
+
+static void __devinit kxtj9_init_input_device(struct kxtj9_data *tj9,
+                                             struct input_dev *input_dev)
+{
+       __set_bit(EV_ABS, input_dev->evbit);
+       input_set_abs_params(input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT);
+       input_set_abs_params(input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT);
+       input_set_abs_params(input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT);
+
+       input_dev->name = "kxtj9_accel";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &tj9->client->dev;
+}
+
+static int __devinit kxtj9_setup_input_device(struct kxtj9_data *tj9)
+{
+       struct input_dev *input_dev;
+       int err;
+
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               dev_err(&tj9->client->dev, "input device allocate failed\n");
+               return -ENOMEM;
+       }
+
+       tj9->input_dev = input_dev;
+
+       input_dev->open = kxtj9_input_open;
+       input_dev->close = kxtj9_input_close;
+       input_set_drvdata(input_dev, tj9);
+
+       kxtj9_init_input_device(tj9, input_dev);
+
+       err = input_register_device(tj9->input_dev);
+       if (err) {
+               dev_err(&tj9->client->dev,
+                       "unable to register input polled device %s: %d\n",
+                       tj9->input_dev->name, err);
+               input_free_device(tj9->input_dev);
+               return err;
+       }
+
+       return 0;
+}
+
+/*
+ * When IRQ mode is selected, we need to provide an interface to allow the user
+ * to change the output data rate of the part.  For consistency, we are using
+ * the set_poll method, which accepts a poll interval in milliseconds, and then
+ * calls update_odr() while passing this value as an argument.  In IRQ mode, the
+ * data outputs will not be read AT the requested poll interval, rather, the
+ * lowest ODR that can support the requested interval.  The client application
+ * will be responsible for retrieving data from the input node at the desired
+ * interval.
+ */
+
+/* Returns currently selected poll interval (in ms) */
+static ssize_t kxtj9_get_poll(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct kxtj9_data *tj9 = i2c_get_clientdata(client);
+
+       return sprintf(buf, "%d\n", tj9->last_poll_interval);
+}
+
+/* Allow users to select a new poll interval (in ms) */
+static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct kxtj9_data *tj9 = i2c_get_clientdata(client);
+       struct input_dev *input_dev = tj9->input_dev;
+       unsigned int interval;
+       int error;
+
+       error = kstrtouint(buf, 10, &interval);
+       if (error < 0)
+               return error;
+
+       /* Lock the device to prevent races with open/close (and itself) */
+       mutex_lock(&input_dev->mutex);
+
+       disable_irq(client->irq);
+
+       /*
+        * Set current interval to the greater of the minimum interval or
+        * the requested interval
+        */
+       tj9->last_poll_interval = max(interval, tj9->pdata.min_interval);
+
+       kxtj9_update_odr(tj9, tj9->last_poll_interval);
+
+       enable_irq(client->irq);
+       mutex_unlock(&input_dev->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(poll, S_IRUGO|S_IWUSR, kxtj9_get_poll, kxtj9_set_poll);
+
+static struct attribute *kxtj9_attributes[] = {
+       &dev_attr_poll.attr,
+       NULL
+};
+
+static struct attribute_group kxtj9_attribute_group = {
+       .attrs = kxtj9_attributes
+};
+
+
+#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE
+static void kxtj9_poll(struct input_polled_dev *dev)
+{
+       struct kxtj9_data *tj9 = dev->private;
+       unsigned int poll_interval = dev->poll_interval;
+
+       kxtj9_report_acceleration_data(tj9);
+
+       if (poll_interval != tj9->last_poll_interval) {
+               kxtj9_update_odr(tj9, poll_interval);
+               tj9->last_poll_interval = poll_interval;
+       }
+}
+
+static void kxtj9_polled_input_open(struct input_polled_dev *dev)
+{
+       struct kxtj9_data *tj9 = dev->private;
+
+       kxtj9_enable(tj9);
+}
+
+static void kxtj9_polled_input_close(struct input_polled_dev *dev)
+{
+       struct kxtj9_data *tj9 = dev->private;
+
+       kxtj9_disable(tj9);
+}
+
+static int __devinit kxtj9_setup_polled_device(struct kxtj9_data *tj9)
+{
+       int err;
+       struct input_polled_dev *poll_dev;
+       poll_dev = input_allocate_polled_device();
+
+       if (!poll_dev) {
+               dev_err(&tj9->client->dev,
+                       "Failed to allocate polled device\n");
+               return -ENOMEM;
+       }
+
+       tj9->poll_dev = poll_dev;
+       tj9->input_dev = poll_dev->input;
+
+       poll_dev->private = tj9;
+       poll_dev->poll = kxtj9_poll;
+       poll_dev->open = kxtj9_polled_input_open;
+       poll_dev->close = kxtj9_polled_input_close;
+
+       kxtj9_init_input_device(tj9, poll_dev->input);
+
+       err = input_register_polled_device(poll_dev);
+       if (err) {
+               dev_err(&tj9->client->dev,
+                       "Unable to register polled device, err=%d\n", err);
+               input_free_polled_device(poll_dev);
+               return err;
+       }
+
+       return 0;
+}
+
+static void __devexit kxtj9_teardown_polled_device(struct kxtj9_data *tj9)
+{
+       input_unregister_polled_device(tj9->poll_dev);
+       input_free_polled_device(tj9->poll_dev);
+}
+
+#else
+
+static inline int kxtj9_setup_polled_device(struct kxtj9_data *tj9)
+{
+       return -ENOSYS;
+}
+
+static inline void kxtj9_teardown_polled_device(struct kxtj9_data *tj9)
+{
+}
+
+#endif
+
+static int __devinit kxtj9_verify(struct kxtj9_data *tj9)
+{
+       int retval;
+
+       retval = kxtj9_device_power_on(tj9);
+       if (retval < 0)
+               return retval;
+
+       retval = i2c_smbus_read_byte_data(tj9->client, WHO_AM_I);
+       if (retval < 0) {
+               dev_err(&tj9->client->dev, "read err int source\n");
+               goto out;
+       }
+
+       retval = retval != 0x06 ? -EIO : 0;
+
+out:
+       kxtj9_device_power_off(tj9);
+       return retval;
+}
+
+static int __devinit kxtj9_probe(struct i2c_client *client,
+                                const struct i2c_device_id *id)
+{
+       const struct kxtj9_platform_data *pdata = client->dev.platform_data;
+       struct kxtj9_data *tj9;
+       int err;
+
+       if (!i2c_check_functionality(client->adapter,
+                               I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "client is not i2c capable\n");
+               return -ENXIO;
+       }
+
+       if (!pdata) {
+               dev_err(&client->dev, "platform data is NULL; exiting\n");
+               return -EINVAL;
+       }
+
+       tj9 = kzalloc(sizeof(*tj9), GFP_KERNEL);
+       if (!tj9) {
+               dev_err(&client->dev,
+                       "failed to allocate memory for module data\n");
+               return -ENOMEM;
+       }
+
+       tj9->client = client;
+       tj9->pdata = *pdata;
+
+       if (pdata->init) {
+               err = pdata->init();
+               if (err < 0)
+                       goto err_free_mem;
+       }
+
+       err = kxtj9_verify(tj9);
+       if (err < 0) {
+               dev_err(&client->dev, "device not recognized\n");
+               goto err_pdata_exit;
+       }
+
+       i2c_set_clientdata(client, tj9);
+
+       tj9->ctrl_reg1 = tj9->pdata.res_12bit | tj9->pdata.g_range;
+       tj9->data_ctrl = tj9->pdata.data_odr_init;
+
+       if (client->irq) {
+               /* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */
+               tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL;
+               tj9->ctrl_reg1 |= DRDYE;
+
+               err = kxtj9_setup_input_device(tj9);
+               if (err)
+                       goto err_pdata_exit;
+
+               err = request_threaded_irq(client->irq, NULL, kxtj9_isr,
+                                          IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                          "kxtj9-irq", tj9);
+               if (err) {
+                       dev_err(&client->dev, "request irq failed: %d\n", err);
+                       goto err_destroy_input;
+               }
+
+               err = sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group);
+               if (err) {
+                       dev_err(&client->dev, "sysfs create failed: %d\n", err);
+                       goto err_free_irq;
+               }
+
+       } else {
+               err = kxtj9_setup_polled_device(tj9);
+               if (err)
+                       goto err_pdata_exit;
+       }
+
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, tj9);
+err_destroy_input:
+       input_unregister_device(tj9->input_dev);
+err_pdata_exit:
+       if (tj9->pdata.exit)
+               tj9->pdata.exit();
+err_free_mem:
+       kfree(tj9);
+       return err;
+}
+
+static int __devexit kxtj9_remove(struct i2c_client *client)
+{
+       struct kxtj9_data *tj9 = i2c_get_clientdata(client);
+
+       if (client->irq) {
+               sysfs_remove_group(&client->dev.kobj, &kxtj9_attribute_group);
+               free_irq(client->irq, tj9);
+               input_unregister_device(tj9->input_dev);
+       } else {
+               kxtj9_teardown_polled_device(tj9);
+       }
+
+       if (tj9->pdata.exit)
+               tj9->pdata.exit();
+
+       kfree(tj9);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int kxtj9_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct kxtj9_data *tj9 = i2c_get_clientdata(client);
+       struct input_dev *input_dev = tj9->input_dev;
+
+       mutex_lock(&input_dev->mutex);
+
+       if (input_dev->users)
+               kxtj9_disable(tj9);
+
+       mutex_unlock(&input_dev->mutex);
+       return 0;
+}
+
+static int kxtj9_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct kxtj9_data *tj9 = i2c_get_clientdata(client);
+       struct input_dev *input_dev = tj9->input_dev;
+       int retval = 0;
+
+       mutex_lock(&input_dev->mutex);
+
+       if (input_dev->users)
+               kxtj9_enable(tj9);
+
+       mutex_unlock(&input_dev->mutex);
+       return retval;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
+
+static const struct i2c_device_id kxtj9_id[] = {
+       { NAME, 0 },
+       { },
+};
+
+MODULE_DEVICE_TABLE(i2c, kxtj9_id);
+
+static struct i2c_driver kxtj9_driver = {
+       .driver = {
+               .name   = NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &kxtj9_pm_ops,
+       },
+       .probe          = kxtj9_probe,
+       .remove         = __devexit_p(kxtj9_remove),
+       .id_table       = kxtj9_id,
+};
+
+static int __init kxtj9_init(void)
+{
+       return i2c_add_driver(&kxtj9_driver);
+}
+module_init(kxtj9_init);
+
+static void __exit kxtj9_exit(void)
+{
+       i2c_del_driver(&kxtj9_driver);
+}
+module_exit(kxtj9_exit);
+
+MODULE_DESCRIPTION("KXTJ9 accelerometer driver");
+MODULE_AUTHOR("Chris Hudson <chudson@kionix.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c
new file mode 100644 (file)
index 0000000..20f8f92
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ *  Driver for Freescale's 3-Axis Accelerometer MMA8450
+ *
+ *  Copyright (C) 2011 Freescale Semiconductor, 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
+ *  (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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input-polldev.h>
+
+#define MMA8450_DRV_NAME       "mma8450"
+
+#define MODE_CHANGE_DELAY_MS   100
+#define POLL_INTERVAL          100
+#define POLL_INTERVAL_MAX      500
+
+/* register definitions */
+#define MMA8450_STATUS         0x00
+#define MMA8450_STATUS_ZXYDR   0x08
+
+#define MMA8450_OUT_X8         0x01
+#define MMA8450_OUT_Y8         0x02
+#define MMA8450_OUT_Z8         0x03
+
+#define MMA8450_OUT_X_LSB      0x05
+#define MMA8450_OUT_X_MSB      0x06
+#define MMA8450_OUT_Y_LSB      0x07
+#define MMA8450_OUT_Y_MSB      0x08
+#define MMA8450_OUT_Z_LSB      0x09
+#define MMA8450_OUT_Z_MSB      0x0a
+
+#define MMA8450_XYZ_DATA_CFG   0x16
+
+#define MMA8450_CTRL_REG1      0x38
+#define MMA8450_CTRL_REG2      0x39
+
+/* mma8450 status */
+struct mma8450 {
+       struct i2c_client       *client;
+       struct input_polled_dev *idev;
+};
+
+static int mma8450_read(struct mma8450 *m, unsigned off)
+{
+       struct i2c_client *c = m->client;
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(c, off);
+       if (ret < 0)
+               dev_err(&c->dev,
+                       "failed to read register 0x%02x, error %d\n",
+                       off, ret);
+
+       return ret;
+}
+
+static int mma8450_write(struct mma8450 *m, unsigned off, u8 v)
+{
+       struct i2c_client *c = m->client;
+       int error;
+
+       error = i2c_smbus_write_byte_data(c, off, v);
+       if (error < 0) {
+               dev_err(&c->dev,
+                       "failed to write to register 0x%02x, error %d\n",
+                       off, error);
+               return error;
+       }
+
+       return 0;
+}
+
+static int mma8450_read_xyz(struct mma8450 *m, int *x, int *y, int *z)
+{
+       struct i2c_client *c = m->client;
+       u8 buff[6];
+       int err;
+
+       err = i2c_smbus_read_i2c_block_data(c, MMA8450_OUT_X_LSB, 6, buff);
+       if (err < 0) {
+               dev_err(&c->dev,
+                       "failed to read block data at 0x%02x, error %d\n",
+                       MMA8450_OUT_X_LSB, err);
+               return err;
+       }
+
+       *x = ((buff[1] << 4) & 0xff0) | (buff[0] & 0xf);
+       *y = ((buff[3] << 4) & 0xff0) | (buff[2] & 0xf);
+       *z = ((buff[5] << 4) & 0xff0) | (buff[4] & 0xf);
+
+       return 0;
+}
+
+static void mma8450_poll(struct input_polled_dev *dev)
+{
+       struct mma8450 *m = dev->private;
+       int x, y, z;
+       int ret;
+       int err;
+
+       ret = mma8450_read(m, MMA8450_STATUS);
+       if (ret < 0)
+               return;
+
+       if (!(ret & MMA8450_STATUS_ZXYDR))
+               return;
+
+       err = mma8450_read_xyz(m, &x, &y, &z);
+       if (err)
+               return;
+
+       input_report_abs(dev->input, ABS_X, x);
+       input_report_abs(dev->input, ABS_Y, y);
+       input_report_abs(dev->input, ABS_Z, z);
+       input_sync(dev->input);
+}
+
+/* Initialize the MMA8450 chip */
+static void mma8450_open(struct input_polled_dev *dev)
+{
+       struct mma8450 *m = dev->private;
+       int err;
+
+       /* enable all events from X/Y/Z, no FIFO */
+       err = mma8450_write(m, MMA8450_XYZ_DATA_CFG, 0x07);
+       if (err)
+               return;
+
+       /*
+        * Sleep mode poll rate - 50Hz
+        * System output data rate - 400Hz
+        * Full scale selection - Active, +/- 2G
+        */
+       err = mma8450_write(m, MMA8450_CTRL_REG1, 0x01);
+       if (err < 0)
+               return;
+
+       msleep(MODE_CHANGE_DELAY_MS);
+}
+
+static void mma8450_close(struct input_polled_dev *dev)
+{
+       struct mma8450 *m = dev->private;
+
+       mma8450_write(m, MMA8450_CTRL_REG1, 0x00);
+       mma8450_write(m, MMA8450_CTRL_REG2, 0x01);
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int __devinit mma8450_probe(struct i2c_client *c,
+                                  const struct i2c_device_id *id)
+{
+       struct input_polled_dev *idev;
+       struct mma8450 *m;
+       int err;
+
+       m = kzalloc(sizeof(struct mma8450), GFP_KERNEL);
+       idev = input_allocate_polled_device();
+       if (!m || !idev) {
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       m->client = c;
+       m->idev = idev;
+
+       idev->private           = m;
+       idev->input->name       = MMA8450_DRV_NAME;
+       idev->input->id.bustype = BUS_I2C;
+       idev->poll              = mma8450_poll;
+       idev->poll_interval     = POLL_INTERVAL;
+       idev->poll_interval_max = POLL_INTERVAL_MAX;
+       idev->open              = mma8450_open;
+       idev->close             = mma8450_close;
+
+       __set_bit(EV_ABS, idev->input->evbit);
+       input_set_abs_params(idev->input, ABS_X, -2048, 2047, 32, 32);
+       input_set_abs_params(idev->input, ABS_Y, -2048, 2047, 32, 32);
+       input_set_abs_params(idev->input, ABS_Z, -2048, 2047, 32, 32);
+
+       err = input_register_polled_device(idev);
+       if (err) {
+               dev_err(&c->dev, "failed to register polled input device\n");
+               goto err_free_mem;
+       }
+
+       return 0;
+
+err_free_mem:
+       input_free_polled_device(idev);
+       kfree(m);
+       return err;
+}
+
+static int __devexit mma8450_remove(struct i2c_client *c)
+{
+       struct mma8450 *m = i2c_get_clientdata(c);
+       struct input_polled_dev *idev = m->idev;
+
+       input_unregister_polled_device(idev);
+       input_free_polled_device(idev);
+       kfree(m);
+
+       return 0;
+}
+
+static const struct i2c_device_id mma8450_id[] = {
+       { MMA8450_DRV_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, mma8450_id);
+
+static struct i2c_driver mma8450_driver = {
+       .driver = {
+               .name   = MMA8450_DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = mma8450_probe,
+       .remove         = __devexit_p(mma8450_remove),
+       .id_table       = mma8450_id,
+};
+
+static int __init mma8450_init(void)
+{
+       return i2c_add_driver(&mma8450_driver);
+}
+module_init(mma8450_init);
+
+static void __exit mma8450_exit(void)
+{
+       i2c_del_driver(&mma8450_driver);
+}
+module_exit(mma8450_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
new file mode 100644 (file)
index 0000000..b95fac1
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * MPU3050 Tri-axis gyroscope driver
+ *
+ * Copyright (C) 2011 Wistron Co.Ltd
+ * Joseph Lai <joseph_lai@wistron.com>
+ *
+ * Trimmed down by Alan Cox <alan@linux.intel.com> to produce this version
+ *
+ * This is a 'lite' version of the driver, while we consider the right way
+ * to present the other features to user space. In particular it requires the
+ * device has an IRQ, and it only provides an input interface, so is not much
+ * use for device orientation. A fuller version is available from the Meego
+ * tree.
+ *
+ * This program is based on bma023.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; 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/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#define MPU3050_CHIP_ID_REG    0x00
+#define MPU3050_CHIP_ID                0x69
+#define MPU3050_XOUT_H         0x1D
+#define MPU3050_PWR_MGM                0x3E
+#define MPU3050_PWR_MGM_POS    6
+#define MPU3050_PWR_MGM_MASK   0x40
+
+#define MPU3050_AUTO_DELAY     1000
+
+#define MPU3050_MIN_VALUE      -32768
+#define MPU3050_MAX_VALUE      32767
+
+struct axis_data {
+       s16 x;
+       s16 y;
+       s16 z;
+};
+
+struct mpu3050_sensor {
+       struct i2c_client *client;
+       struct device *dev;
+       struct input_dev *idev;
+};
+
+/**
+ *     mpu3050_xyz_read_reg    -       read the axes values
+ *     @buffer: provide register addr and get register
+ *     @length: length of register
+ *
+ *     Reads the register values in one transaction or returns a negative
+ *     error code on failure.
+ */
+static int mpu3050_xyz_read_reg(struct i2c_client *client,
+                              u8 *buffer, int length)
+{
+       /*
+        * Annoying we can't make this const because the i2c layer doesn't
+        * declare input buffers const.
+        */
+       char cmd = MPU3050_XOUT_H;
+       struct i2c_msg msg[] = {
+               {
+                       .addr = client->addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &cmd,
+               },
+               {
+                       .addr = client->addr,
+                       .flags = I2C_M_RD,
+                       .len = length,
+                       .buf = buffer,
+               },
+       };
+
+       return i2c_transfer(client->adapter, msg, 2);
+}
+
+/**
+ *     mpu3050_read_xyz        -       get co-ordinates from device
+ *     @client: i2c address of sensor
+ *     @coords: co-ordinates to update
+ *
+ *     Return the converted X Y and Z co-ordinates from the sensor device
+ */
+static void mpu3050_read_xyz(struct i2c_client *client,
+                            struct axis_data *coords)
+{
+       u16 buffer[3];
+
+       mpu3050_xyz_read_reg(client, (u8 *)buffer, 6);
+       coords->x = be16_to_cpu(buffer[0]);
+       coords->y = be16_to_cpu(buffer[1]);
+       coords->z = be16_to_cpu(buffer[2]);
+       dev_dbg(&client->dev, "%s: x %d, y %d, z %d\n", __func__,
+                                       coords->x, coords->y, coords->z);
+}
+
+/**
+ *     mpu3050_set_power_mode  -       set the power mode
+ *     @client: i2c client for the sensor
+ *     @val: value to switch on/off of power, 1: normal power, 0: low power
+ *
+ *     Put device to normal-power mode or low-power mode.
+ */
+static void mpu3050_set_power_mode(struct i2c_client *client, u8 val)
+{
+       u8 value;
+
+       value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
+       value = (value & ~MPU3050_PWR_MGM_MASK) |
+               (((val << MPU3050_PWR_MGM_POS) & MPU3050_PWR_MGM_MASK) ^
+                MPU3050_PWR_MGM_MASK);
+       i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM, value);
+}
+
+/**
+ *     mpu3050_input_open      -       called on input event open
+ *     @input: input dev of opened device
+ *
+ *     The input layer calls this function when input event is opened. The
+ *     function will push the device to resume. Then, the device is ready
+ *     to provide data.
+ */
+static int mpu3050_input_open(struct input_dev *input)
+{
+       struct mpu3050_sensor *sensor = input_get_drvdata(input);
+
+       pm_runtime_get(sensor->dev);
+
+       return 0;
+}
+
+/**
+ *     mpu3050_input_close     -       called on input event close
+ *     @input: input dev of closed device
+ *
+ *     The input layer calls this function when input event is closed. The
+ *     function will push the device to suspend.
+ */
+static void mpu3050_input_close(struct input_dev *input)
+{
+       struct mpu3050_sensor *sensor = input_get_drvdata(input);
+
+       pm_runtime_put(sensor->dev);
+}
+
+/**
+ *     mpu3050_interrupt_thread        -       handle an IRQ
+ *     @irq: interrupt numner
+ *     @data: the sensor
+ *
+ *     Called by the kernel single threaded after an interrupt occurs. Read
+ *     the sensor data and generate an input event for it.
+ */
+static irqreturn_t mpu3050_interrupt_thread(int irq, void *data)
+{
+       struct mpu3050_sensor *sensor = data;
+       struct axis_data axis;
+
+       mpu3050_read_xyz(sensor->client, &axis);
+
+       input_report_abs(sensor->idev, ABS_X, axis.x);
+       input_report_abs(sensor->idev, ABS_Y, axis.y);
+       input_report_abs(sensor->idev, ABS_Z, axis.z);
+       input_sync(sensor->idev);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ *     mpu3050_probe   -       device detection callback
+ *     @client: i2c client of found device
+ *     @id: id match information
+ *
+ *     The I2C layer calls us when it believes a sensor is present at this
+ *     address. Probe to see if this is correct and to validate the device.
+ *
+ *     If present install the relevant sysfs interfaces and input device.
+ */
+static int __devinit mpu3050_probe(struct i2c_client *client,
+                                  const struct i2c_device_id *id)
+{
+       struct mpu3050_sensor *sensor;
+       struct input_dev *idev;
+       int ret;
+       int error;
+
+       sensor = kzalloc(sizeof(struct mpu3050_sensor), GFP_KERNEL);
+       idev = input_allocate_device();
+       if (!sensor || !idev) {
+               dev_err(&client->dev, "failed to allocate driver data\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       sensor->client = client;
+       sensor->dev = &client->dev;
+       sensor->idev = idev;
+
+       mpu3050_set_power_mode(client, 1);
+       msleep(10);
+
+       ret = i2c_smbus_read_byte_data(client, MPU3050_CHIP_ID_REG);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed to detect device\n");
+               error = -ENXIO;
+               goto err_free_mem;
+       }
+
+       if (ret != MPU3050_CHIP_ID) {
+               dev_err(&client->dev, "unsupported chip id\n");
+               error = -ENXIO;
+               goto err_free_mem;
+       }
+
+       idev->name = "MPU3050";
+       idev->id.bustype = BUS_I2C;
+       idev->dev.parent = &client->dev;
+
+       idev->open = mpu3050_input_open;
+       idev->close = mpu3050_input_close;
+
+       __set_bit(EV_ABS, idev->evbit);
+       input_set_abs_params(idev, ABS_X,
+                            MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
+       input_set_abs_params(idev, ABS_Y,
+                            MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
+       input_set_abs_params(idev, ABS_Z,
+                            MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
+
+       input_set_drvdata(idev, sensor);
+
+       pm_runtime_set_active(&client->dev);
+
+       error = request_threaded_irq(client->irq,
+                                    NULL, mpu3050_interrupt_thread,
+                                    IRQF_TRIGGER_RISING,
+                                    "mpu_int", sensor);
+       if (error) {
+               dev_err(&client->dev,
+                       "can't get IRQ %d, error %d\n", client->irq, error);
+               goto err_pm_set_suspended;
+       }
+
+       error = input_register_device(idev);
+       if (error) {
+               dev_err(&client->dev, "failed to register input device\n");
+               goto err_free_irq;
+       }
+
+       pm_runtime_enable(&client->dev);
+       pm_runtime_set_autosuspend_delay(&client->dev, MPU3050_AUTO_DELAY);
+
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, sensor);
+err_pm_set_suspended:
+       pm_runtime_set_suspended(&client->dev);
+err_free_mem:
+       input_unregister_device(idev);
+       kfree(sensor);
+       return error;
+}
+
+/**
+ *     mpu3050_remove  -       remove a sensor
+ *     @client: i2c client of sensor being removed
+ *
+ *     Our sensor is going away, clean up the resources.
+ */
+static int __devexit mpu3050_remove(struct i2c_client *client)
+{
+       struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+
+       free_irq(client->irq, sensor);
+       input_unregister_device(sensor->idev);
+       kfree(sensor);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ *     mpu3050_suspend         -       called on device suspend
+ *     @dev: device being suspended
+ *
+ *     Put the device into sleep mode before we suspend the machine.
+ */
+static int mpu3050_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       mpu3050_set_power_mode(client, 0);
+
+       return 0;
+}
+
+/**
+ *     mpu3050_resume          -       called on device resume
+ *     @dev: device being resumed
+ *
+ *     Put the device into powered mode on resume.
+ */
+static int mpu3050_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       mpu3050_set_power_mode(client, 1);
+       msleep(100);  /* wait for gyro chip resume */
+
+       return 0;
+}
+#endif
+
+static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL);
+
+static const struct i2c_device_id mpu3050_ids[] = {
+       { "mpu3050", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mpu3050_ids);
+
+static struct i2c_driver mpu3050_i2c_driver = {
+       .driver = {
+               .name   = "mpu3050",
+               .owner  = THIS_MODULE,
+               .pm     = &mpu3050_pm,
+       },
+       .probe          = mpu3050_probe,
+       .remove         = __devexit_p(mpu3050_remove),
+       .id_table       = mpu3050_ids,
+};
+
+static int __init mpu3050_init(void)
+{
+       return i2c_add_driver(&mpu3050_i2c_driver);
+}
+module_init(mpu3050_init);
+
+static void __exit mpu3050_exit(void)
+{
+       i2c_del_driver(&mpu3050_i2c_driver);
+}
+module_exit(mpu3050_exit);
+
+MODULE_AUTHOR("Wistron Corp.");
+MODULE_DESCRIPTION("MPU3050 Tri-axis gyroscope driver");
+MODULE_LICENSE("GPL");
index 62bae99424e6e436defda3723654816c44be2609..ad2e51c04db89c06faa30b0e07ef70db12221fc1 100644 (file)
@@ -373,7 +373,7 @@ static struct xenbus_driver xenkbd_driver = {
 
 static int __init xenkbd_init(void)
 {
-       if (!xen_pv_domain())
+       if (!xen_domain())
                return -ENODEV;
 
        /* Nothing to do if running in dom0. */
index 7b6ce178f1b67d64c92e2e969d256bbe381a86e7..58902fbb98967a7b456fa71d0155ee65b51003bd 100644 (file)
@@ -191,7 +191,7 @@ static void __exit gpio_mouse_exit(void)
 }
 module_exit(gpio_mouse_exit);
 
-MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
 MODULE_DESCRIPTION("GPIO mouse driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */
index c31ad11df6bb11f5a3dbf77d000670ebd655ffbd..83bcaba96b895b8a06b5217507f902b1c4066c5f 100644 (file)
@@ -33,7 +33,7 @@ static const char *desired_serio_phys;
 static int lifebook_limit_serio3(const struct dmi_system_id *d)
 {
        desired_serio_phys = "isa0060/serio3";
-       return 0;
+       return 1;
 }
 
 static bool lifebook_use_6byte_proto;
@@ -41,7 +41,7 @@ static bool lifebook_use_6byte_proto;
 static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
 {
        lifebook_use_6byte_proto = true;
-       return 0;
+       return 1;
 }
 
 static const struct dmi_system_id __initconst lifebook_dmi_table[] = {
index 943cfec15665f336c2d21a481f55ffe4251d4ae5..6c5d84fcdea1a666126eedec63e6e739db1ed29a 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/init.h>
 #include <linux/input.h>
-#include <linux/version.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
index 1242775fee1938c498b3dda6da6e8acb6990c67b..2fc887a51066ccbd1c67fb1ab11bb12b822eaaaf 100644 (file)
@@ -20,7 +20,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/input.h>
 #include <linux/ctype.h>
 #include <linux/libps2.h>
index e06e045bf907a4a77ed33998b94ad29438e6c542..5538fc657af176b265cda6178dad06e0e8b51705 100644 (file)
@@ -207,27 +207,37 @@ static int synaptics_identify(struct psmouse *psmouse)
 static int synaptics_resolution(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
-       unsigned char res[3];
-       unsigned char max[3];
+       unsigned char resp[3];
 
        if (SYN_ID_MAJOR(priv->identity) < 4)
                return 0;
 
-       if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res) == 0) {
-               if (res[0] != 0 && (res[1] & 0x80) && res[2] != 0) {
-                       priv->x_res = res[0]; /* x resolution in units/mm */
-                       priv->y_res = res[2]; /* y resolution in units/mm */
+       if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp) == 0) {
+               if (resp[0] != 0 && (resp[1] & 0x80) && resp[2] != 0) {
+                       priv->x_res = resp[0]; /* x resolution in units/mm */
+                       priv->y_res = resp[2]; /* y resolution in units/mm */
                }
        }
 
        if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
            SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
-               if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_DIMENSIONS, max)) {
-                       printk(KERN_ERR "Synaptics claims to have dimensions query,"
-                              " but I'm not able to read it.\n");
+               if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
+                       printk(KERN_ERR "Synaptics claims to have max coordinates"
+                              " query, but I'm not able to read it.\n");
+               } else {
+                       priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
+                       priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
+               }
+       }
+
+       if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 &&
+           SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) {
+               if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) {
+                       printk(KERN_ERR "Synaptics claims to have min coordinates"
+                              " query, but I'm not able to read it.\n");
                } else {
-                       priv->x_max = (max[0] << 5) | ((max[1] & 0x0f) << 1);
-                       priv->y_max = (max[2] << 5) | ((max[1] & 0xf0) >> 3);
+                       priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
+                       priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
                }
        }
 
@@ -406,26 +416,10 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
        memset(hw, 0, sizeof(struct synaptics_hw_state));
 
        if (SYN_MODEL_NEWABS(priv->model_id)) {
-               hw->x = (((buf[3] & 0x10) << 8) |
-                        ((buf[1] & 0x0f) << 8) |
-                        buf[4]);
-               hw->y = (((buf[3] & 0x20) << 7) |
-                        ((buf[1] & 0xf0) << 4) |
-                        buf[5]);
-
-               hw->z = buf[2];
                hw->w = (((buf[0] & 0x30) >> 2) |
                         ((buf[0] & 0x04) >> 1) |
                         ((buf[3] & 0x04) >> 2));
 
-               if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) {
-                       /* Gesture packet: (x, y, z) at half resolution */
-                       priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
-                       priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
-                       priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
-                       return 1;
-               }
-
                hw->left  = (buf[0] & 0x01) ? 1 : 0;
                hw->right = (buf[0] & 0x02) ? 1 : 0;
 
@@ -448,6 +442,22 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
                        hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
                }
 
+               if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) {
+                       /* Gesture packet: (x, y, z) at half resolution */
+                       priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
+                       priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
+                       priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
+                       return 1;
+               }
+
+               hw->x = (((buf[3] & 0x10) << 8) |
+                        ((buf[1] & 0x0f) << 8) |
+                        buf[4]);
+               hw->y = (((buf[3] & 0x20) << 7) |
+                        ((buf[1] & 0xf0) << 4) |
+                        buf[5]);
+               hw->z = buf[2];
+
                if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
                    ((buf[0] ^ buf[3]) & 0x02)) {
                        switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
@@ -485,7 +495,8 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
        return 0;
 }
 
-static void set_slot(struct input_dev *dev, int slot, bool active, int x, int y)
+static void synaptics_report_semi_mt_slot(struct input_dev *dev, int slot,
+                                         bool active, int x, int y)
 {
        input_mt_slot(dev, slot);
        input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
@@ -502,14 +513,16 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev,
                                          int num_fingers)
 {
        if (num_fingers >= 2) {
-               set_slot(dev, 0, true, min(a->x, b->x), min(a->y, b->y));
-               set_slot(dev, 1, true, max(a->x, b->x), max(a->y, b->y));
+               synaptics_report_semi_mt_slot(dev, 0, true, min(a->x, b->x),
+                                             min(a->y, b->y));
+               synaptics_report_semi_mt_slot(dev, 1, true, max(a->x, b->x),
+                                             max(a->y, b->y));
        } else if (num_fingers == 1) {
-               set_slot(dev, 0, true, a->x, a->y);
-               set_slot(dev, 1, false, 0, 0);
+               synaptics_report_semi_mt_slot(dev, 0, true, a->x, a->y);
+               synaptics_report_semi_mt_slot(dev, 1, false, 0, 0);
        } else {
-               set_slot(dev, 0, false, 0, 0);
-               set_slot(dev, 1, false, 0, 0);
+               synaptics_report_semi_mt_slot(dev, 0, false, 0, 0);
+               synaptics_report_semi_mt_slot(dev, 1, false, 0, 0);
        }
 }
 
@@ -684,23 +697,36 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
 static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
 {
        int i;
+       int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ?
+                       SYN_REDUCED_FILTER_FUZZ : 0;
 
        __set_bit(INPUT_PROP_POINTER, dev->propbit);
 
        __set_bit(EV_ABS, dev->evbit);
        input_set_abs_params(dev, ABS_X,
-                            XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0);
+                            priv->x_min ?: XMIN_NOMINAL,
+                            priv->x_max ?: XMAX_NOMINAL,
+                            fuzz, 0);
        input_set_abs_params(dev, ABS_Y,
-                            YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
+                            priv->y_min ?: YMIN_NOMINAL,
+                            priv->y_max ?: YMAX_NOMINAL,
+                            fuzz, 0);
        input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 
        if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
                __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
                input_mt_init_slots(dev, 2);
-               input_set_abs_params(dev, ABS_MT_POSITION_X, XMIN_NOMINAL,
-                                    priv->x_max ?: XMAX_NOMINAL, 0, 0);
-               input_set_abs_params(dev, ABS_MT_POSITION_Y, YMIN_NOMINAL,
-                                    priv->y_max ?: YMAX_NOMINAL, 0, 0);
+               input_set_abs_params(dev, ABS_MT_POSITION_X,
+                                    priv->x_min ?: XMIN_NOMINAL,
+                                    priv->x_max ?: XMAX_NOMINAL,
+                                    fuzz, 0);
+               input_set_abs_params(dev, ABS_MT_POSITION_Y,
+                                    priv->y_min ?: YMIN_NOMINAL,
+                                    priv->y_max ?: YMAX_NOMINAL,
+                                    fuzz, 0);
+
+               input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res);
+               input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res);
        }
 
        if (SYN_CAP_PALMDETECT(priv->capabilities))
@@ -971,4 +997,3 @@ bool synaptics_supported(void)
 }
 
 #endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
-
index 7453938bf5efb4f9c6903316349d9f29f0761ae6..ca040aa80fa74016e6cd19bfaf4766b1045b7e58 100644 (file)
@@ -19,7 +19,8 @@
 #define SYN_QUE_RESOLUTION             0x08
 #define SYN_QUE_EXT_CAPAB              0x09
 #define SYN_QUE_EXT_CAPAB_0C           0x0c
-#define SYN_QUE_EXT_DIMENSIONS         0x0d
+#define SYN_QUE_EXT_MAX_COORDS         0x0d
+#define SYN_QUE_EXT_MIN_COORDS         0x0f
 
 /* synatics modes */
 #define SYN_BIT_ABSOLUTE_MODE          (1 << 7)
  * 1   0x60    multifinger mode        identifies firmware finger counting
  *                                     (not reporting!) algorithm.
  *                                     Not particularly meaningful
- * 1   0x80    covered pad             W clipped to 14, 15 == pad mostly covered
- * 2   0x01    clickpad bit 1          2-button ClickPad
- * 2   0x02    deluxe LED controls     touchpad support LED commands
+ * 1   0x80    covered pad             W clipped to 14, 15 == pad mostly covered
+ * 2   0x01    clickpad bit 1          2-button ClickPad
+ * 2   0x02    deluxe LED controls     touchpad support LED commands
  *                                     ala multimedia control bar
  * 2   0x04    reduced filtering       firmware does less filtering on
  *                                     position data, driver should watch
  *                                     for noise.
+ * 2   0x20    report min              query 0x0f gives min coord reported
  */
 #define SYN_CAP_CLICKPAD(ex0c)         ((ex0c) & 0x100000) /* 1-button ClickPad */
 #define SYN_CAP_CLICKPAD2BTN(ex0c)     ((ex0c) & 0x000100) /* 2-button ClickPad */
 #define SYN_CAP_MAX_DIMENSIONS(ex0c)   ((ex0c) & 0x020000)
+#define SYN_CAP_MIN_DIMENSIONS(ex0c)   ((ex0c) & 0x002000)
 #define SYN_CAP_ADV_GESTURE(ex0c)      ((ex0c) & 0x080000)
+#define SYN_CAP_REDUCED_FILTERING(ex0c)        ((ex0c) & 0x000400)
 
 /* synaptics modes query bits */
 #define SYN_MODE_ABSOLUTE(m)           ((m) & (1 << 7))
 #define SYN_NEWABS_RELAXED             2
 #define SYN_OLDABS                     3
 
+/* amount to fuzz position data when touchpad reports reduced filtering */
+#define SYN_REDUCED_FILTER_FUZZ                8
+
 /*
  * A structure to describe the state of the touchpad hardware (buttons and pad)
  */
@@ -130,7 +137,8 @@ struct synaptics_data {
        unsigned long int ext_cap_0c;           /* Ext Caps from 0x0c query */
        unsigned long int identity;             /* Identification */
        unsigned int x_res, y_res;              /* X/Y resolution in units/mm */
-       unsigned int x_max, y_max;              /* Max dimensions (from FW) */
+       unsigned int x_max, y_max;              /* Max coordinates (from FW) */
+       unsigned int x_min, y_min;              /* Min coordinates (from FW) */
 
        unsigned char pkt_type;                 /* packet type - old, new, etc */
        unsigned char mode;                     /* current mode byte */
index 6ee8f0ddad51abe615325f8335a02ec99fb311e2..95280f9207e14cf4d552aaa7cf8b7b3704fc123f 100644 (file)
@@ -372,6 +372,6 @@ static void __exit psif_exit(void)
 module_init(psif_init);
 module_exit(psif_exit);
 
-MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
+MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
 MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver");
 MODULE_LICENSE("GPL");
index 42206205e4f53700a9fcfb13200666381c3402c1..979c443bf1efa78fc150cd190073e111d907b842 100644 (file)
@@ -795,7 +795,7 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback)
 
 /************************* Keepalive timer task *********************/
 
-void hp_sdc_kicker (unsigned long data)
+static void hp_sdc_kicker(unsigned long data)
 {
        tasklet_schedule(&hp_sdc.task);
        /* Re-insert the periodic task. */
index 0a619c558bfb40a8223c94301462d6387f7dc388..6d89fd1842c32a9a577a6d7c424f00be3cfec340 100644 (file)
        /* toolMode codes
         */
 #define AIPTEK_TOOL_BUTTON_PEN_MODE                    BTN_TOOL_PEN
-#define AIPTEK_TOOL_BUTTON_PEN_MODE                    BTN_TOOL_PEN
 #define AIPTEK_TOOL_BUTTON_PENCIL_MODE                 BTN_TOOL_PENCIL
 #define AIPTEK_TOOL_BUTTON_BRUSH_MODE                  BTN_TOOL_BRUSH
 #define AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE               BTN_TOOL_AIRBRUSH
index 08ba5ad9c9be76a232effefffd6dba4fd7be0429..03ebcc8b24b59bc1ec5efa8f2d5d5465c53e3e56 100644 (file)
@@ -15,6 +15,7 @@
 #include "wacom_wac.h"
 #include "wacom.h"
 #include <linux/input/mt.h>
+#include <linux/hid.h>
 
 /* resolution for penabled devices */
 #define WACOM_PL_RES           20
@@ -264,6 +265,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                        wacom->id[0] = 0;
                input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
                input_report_key(input, wacom->tool[0], prox);
+               input_event(input, EV_MSC, MSC_SERIAL, 1);
                input_sync(input); /* sync last event */
        }
 
@@ -273,11 +275,10 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                prox = data[7] & 0xf8;
                if (prox || wacom->id[1]) {
                        wacom->id[1] = PAD_DEVICE_ID;
-                       input_report_key(input, BTN_0, (data[7] & 0x40));
-                       input_report_key(input, BTN_4, (data[7] & 0x80));
+                       input_report_key(input, BTN_BACK, (data[7] & 0x40));
+                       input_report_key(input, BTN_FORWARD, (data[7] & 0x80));
                        rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
                        input_report_rel(input, REL_WHEEL, rw);
-                       input_report_key(input, BTN_TOOL_FINGER, 0xf0);
                        if (!prox)
                                wacom->id[1] = 0;
                        input_report_abs(input, ABS_MISC, wacom->id[1]);
@@ -290,18 +291,17 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                prox = (data[7] & 0xf8) || data[8];
                if (prox || wacom->id[1]) {
                        wacom->id[1] = PAD_DEVICE_ID;
-                       input_report_key(input, BTN_0, (data[7] & 0x08));
-                       input_report_key(input, BTN_1, (data[7] & 0x20));
-                       input_report_key(input, BTN_4, (data[7] & 0x10));
-                       input_report_key(input, BTN_5, (data[7] & 0x40));
+                       input_report_key(input, BTN_BACK, (data[7] & 0x08));
+                       input_report_key(input, BTN_LEFT, (data[7] & 0x20));
+                       input_report_key(input, BTN_FORWARD, (data[7] & 0x10));
+                       input_report_key(input, BTN_RIGHT, (data[7] & 0x40));
                        input_report_abs(input, ABS_WHEEL, (data[8] & 0x7f));
-                       input_report_key(input, BTN_TOOL_FINGER, 0xf0);
                        if (!prox)
                                wacom->id[1] = 0;
                        input_report_abs(input, ABS_MISC, wacom->id[1]);
                        input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+                       retval = 1;
                }
-               retval = 1;
                break;
        }
 exit:
@@ -494,10 +494,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
 
        /* pad packets. Works as a second tool and is always in prox */
        if (data[0] == WACOM_REPORT_INTUOSPAD) {
-               /* initiate the pad as a device */
-               if (wacom->tool[1] != BTN_TOOL_FINGER)
-                       wacom->tool[1] = BTN_TOOL_FINGER;
-
                if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
                        input_report_key(input, BTN_0, (data[2] & 0x01));
                        input_report_key(input, BTN_1, (data[3] & 0x01));
@@ -1080,18 +1076,14 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
 
        switch (wacom_wac->features.type) {
        case WACOM_MO:
-               __set_bit(BTN_1, input_dev->keybit);
-               __set_bit(BTN_5, input_dev->keybit);
-
                input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
                /* fall through */
 
        case WACOM_G4:
                input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
 
-               __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
-               __set_bit(BTN_0, input_dev->keybit);
-               __set_bit(BTN_4, input_dev->keybit);
+               __set_bit(BTN_BACK, input_dev->keybit);
+               __set_bit(BTN_FORWARD, input_dev->keybit);
                /* fall through */
 
        case GRAPHIRE:
@@ -1127,10 +1119,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
        case CINTIQ:
                for (i = 0; i < 8; i++)
                        __set_bit(BTN_0 + i, input_dev->keybit);
-               __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
 
-               input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
-               input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
+               if (wacom_wac->features.type != WACOM_21UX2) {
+                       input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
+                       input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
+               }
+
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                wacom_setup_cintiq(wacom_wac);
                break;
@@ -1151,8 +1145,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                __set_bit(BTN_2, input_dev->keybit);
                __set_bit(BTN_3, input_dev->keybit);
 
-               __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
-
                input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                /* fall through */
@@ -1170,7 +1162,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
        case INTUOS4S:
                for (i = 0; i < 7; i++)
                        __set_bit(BTN_0 + i, input_dev->keybit);
-               __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
 
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
                wacom_setup_intuos(wacom_wac);
@@ -1295,6 +1286,12 @@ static const struct wacom_features wacom_features_0x65 =
 static const struct wacom_features wacom_features_0x69 =
        { "Wacom Bamboo1",        WACOM_PKGLEN_GRAPHIRE,   5104,  3712,  511,
          63, GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
+static const struct wacom_features wacom_features_0x6A =
+       { "Wacom Bamboo1 4x6",    WACOM_PKGLEN_GRAPHIRE,  14760,  9225, 1023,
+         63, GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x6B =
+       { "Wacom Bamboo1 5x8",    WACOM_PKGLEN_GRAPHIRE,  21648, 13530, 1023,
+         63, GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x20 =
        { "Wacom Intuos 4x5",     WACOM_PKGLEN_INTUOS,    12700, 10600, 1023,
          31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1427,6 +1424,9 @@ static const struct wacom_features wacom_features_0x90 =
 static const struct wacom_features wacom_features_0x93 =
        { "Wacom ISDv4 93",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
          0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x97 =
+       { "Wacom ISDv4 97",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  511,
+         0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x9A =
        { "Wacom ISDv4 9A",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
          0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1458,7 +1458,7 @@ static const struct wacom_features wacom_features_0xD3 =
        { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN,     21648, 13530, 1023,
          63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD4 =
-       { "Wacom Bamboo Pen",     WACOM_PKGLEN_BBFUN,     14720,  9200,  255,
+       { "Wacom Bamboo Pen",     WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
          63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0xD6 =
        { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN,   14720,  9200, 1023,
@@ -1483,6 +1483,11 @@ static const struct wacom_features wacom_features_0x6004 =
        USB_DEVICE(USB_VENDOR_ID_WACOM, prod),                  \
        .driver_info = (kernel_ulong_t)&wacom_features_##prod
 
+#define USB_DEVICE_DETAILED(prod, class, sub, proto)                   \
+       USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_WACOM, prod, class, \
+                                     sub, proto),                      \
+       .driver_info = (kernel_ulong_t)&wacom_features_##prod
+
 #define USB_DEVICE_LENOVO(prod)                                        \
        USB_DEVICE(USB_VENDOR_ID_LENOVO, prod),                 \
        .driver_info = (kernel_ulong_t)&wacom_features_##prod
@@ -1506,6 +1511,8 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x64) },
        { USB_DEVICE_WACOM(0x65) },
        { USB_DEVICE_WACOM(0x69) },
+       { USB_DEVICE_WACOM(0x6A) },
+       { USB_DEVICE_WACOM(0x6B) },
        { USB_DEVICE_WACOM(0x20) },
        { USB_DEVICE_WACOM(0x21) },
        { USB_DEVICE_WACOM(0x22) },
@@ -1545,7 +1552,13 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xC5) },
        { USB_DEVICE_WACOM(0xC6) },
        { USB_DEVICE_WACOM(0xC7) },
-       { USB_DEVICE_WACOM(0xCE) },
+       /*
+        * DTU-2231 has two interfaces on the same configuration,
+        * only one is used.
+        */
+       { USB_DEVICE_DETAILED(0xCE, USB_CLASS_HID,
+                             USB_INTERFACE_SUBCLASS_BOOT,
+                             USB_INTERFACE_PROTOCOL_MOUSE) },
        { USB_DEVICE_WACOM(0xD0) },
        { USB_DEVICE_WACOM(0xD1) },
        { USB_DEVICE_WACOM(0xD2) },
@@ -1560,6 +1573,7 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xCC) },
        { USB_DEVICE_WACOM(0x90) },
        { USB_DEVICE_WACOM(0x93) },
+       { USB_DEVICE_WACOM(0x97) },
        { USB_DEVICE_WACOM(0x9A) },
        { USB_DEVICE_WACOM(0x9F) },
        { USB_DEVICE_WACOM(0xE2) },
index 5196861b86ef2d8c2d4d559b5471caa4e1e464b4..d507b9b678063031e988ef907308801ff0aa8df1 100644 (file)
@@ -967,17 +967,12 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784
                ts->get_pendown_state = pdata->get_pendown_state;
        } else if (gpio_is_valid(pdata->gpio_pendown)) {
 
-               err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
+               err = gpio_request_one(pdata->gpio_pendown, GPIOF_IN,
+                                      "ads7846_pendown");
                if (err) {
-                       dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
-                               pdata->gpio_pendown);
-                       return err;
-               }
-               err = gpio_direction_input(pdata->gpio_pendown);
-               if (err) {
-                       dev_err(&spi->dev, "failed to setup pendown GPIO%d\n",
-                               pdata->gpio_pendown);
-                       gpio_free(pdata->gpio_pendown);
+                       dev_err(&spi->dev,
+                               "failed to request/setup pendown GPIO%d: %d\n",
+                               pdata->gpio_pendown, err);
                        return err;
                }
 
index fa8e56bd9094ec8df9ac43119a5a2213c4785f09..8034cbb20f74c8d8bcd426aa27b998e8bd8fcf20 100644 (file)
@@ -164,7 +164,7 @@ static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id)
 
                data = ac97c_readl(atmel_wm97xx, CBRHR);
                value = data & 0x0fff;
-               source = data & WM97XX_ADCSRC_MASK;
+               source = data & WM97XX_ADCSEL_MASK;
                pen_down = (data & WM97XX_PEN_DOWN) >> 8;
 
                if (source == WM97XX_ADCSEL_X)
@@ -442,6 +442,6 @@ static void __exit atmel_wm97xx_exit(void)
 }
 module_exit(atmel_wm97xx_exit);
 
-MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
+MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
 MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
 MODULE_LICENSE("GPL");
index 1e61387c73cafa01f40825a710427414a4a7e2aa..ae00604a6a81d8c1cf37d65823d14eb728e36e3a 100644 (file)
 #define MXT_OBJECT_SIZE                6
 
 /* Object types */
-#define MXT_DEBUG_DIAGNOSTIC   37
-#define MXT_GEN_MESSAGE                5
-#define MXT_GEN_COMMAND                6
-#define MXT_GEN_POWER          7
-#define MXT_GEN_ACQUIRE                8
-#define MXT_TOUCH_MULTI                9
-#define MXT_TOUCH_KEYARRAY     15
-#define MXT_TOUCH_PROXIMITY    23
-#define MXT_PROCI_GRIPFACE     20
-#define MXT_PROCG_NOISE                22
-#define MXT_PROCI_ONETOUCH     24
-#define MXT_PROCI_TWOTOUCH     27
-#define MXT_PROCI_GRIP         40
-#define MXT_PROCI_PALM         41
-#define MXT_SPT_COMMSCONFIG    18
-#define MXT_SPT_GPIOPWM                19
-#define MXT_SPT_SELFTEST       25
-#define MXT_SPT_CTECONFIG      28
-#define MXT_SPT_USERDATA       38
-#define MXT_SPT_DIGITIZER      43
-#define MXT_SPT_MESSAGECOUNT   44
-
-/* MXT_GEN_COMMAND field */
+#define MXT_DEBUG_DIAGNOSTIC_T37       37
+#define MXT_GEN_MESSAGE_T5             5
+#define MXT_GEN_COMMAND_T6             6
+#define MXT_GEN_POWER_T7               7
+#define MXT_GEN_ACQUIRE_T8             8
+#define MXT_GEN_DATASOURCE_T53         53
+#define MXT_TOUCH_MULTI_T9             9
+#define MXT_TOUCH_KEYARRAY_T15         15
+#define MXT_TOUCH_PROXIMITY_T23                23
+#define MXT_TOUCH_PROXKEY_T52          52
+#define MXT_PROCI_GRIPFACE_T20         20
+#define MXT_PROCG_NOISE_T22            22
+#define MXT_PROCI_ONETOUCH_T24         24
+#define MXT_PROCI_TWOTOUCH_T27         27
+#define MXT_PROCI_GRIP_T40             40
+#define MXT_PROCI_PALM_T41             41
+#define MXT_PROCI_TOUCHSUPPRESSION_T42 42
+#define MXT_PROCI_STYLUS_T47           47
+#define MXT_PROCG_NOISESUPPRESSION_T48 48
+#define MXT_SPT_COMMSCONFIG_T18                18
+#define MXT_SPT_GPIOPWM_T19            19
+#define MXT_SPT_SELFTEST_T25           25
+#define MXT_SPT_CTECONFIG_T28          28
+#define MXT_SPT_USERDATA_T38           38
+#define MXT_SPT_DIGITIZER_T43          43
+#define MXT_SPT_MESSAGECOUNT_T44       44
+#define MXT_SPT_CTECONFIG_T46          46
+
+/* MXT_GEN_COMMAND_T6 field */
 #define MXT_COMMAND_RESET      0
 #define MXT_COMMAND_BACKUPNV   1
 #define MXT_COMMAND_CALIBRATE  2
 #define MXT_COMMAND_REPORTALL  3
 #define MXT_COMMAND_DIAGNOSTIC 5
 
-/* MXT_GEN_POWER field */
+/* MXT_GEN_POWER_T7 field */
 #define MXT_POWER_IDLEACQINT   0
 #define MXT_POWER_ACTVACQINT   1
 #define MXT_POWER_ACTV2IDLETO  2
 
-/* MXT_GEN_ACQUIRE field */
+/* MXT_GEN_ACQUIRE_T8 field */
 #define MXT_ACQUIRE_CHRGTIME   0
 #define MXT_ACQUIRE_TCHDRIFT   2
 #define MXT_ACQUIRE_DRIFTST    3
@@ -91,7 +97,7 @@
 #define MXT_ACQUIRE_ATCHCALST  6
 #define MXT_ACQUIRE_ATCHCALSTHR        7
 
-/* MXT_TOUCH_MULTI field */
+/* MXT_TOUCH_MULTI_T9 field */
 #define MXT_TOUCH_CTRL         0
 #define MXT_TOUCH_XORIGIN      1
 #define MXT_TOUCH_YORIGIN      2
 #define MXT_TOUCH_YEDGEDIST    29
 #define MXT_TOUCH_JUMPLIMIT    30
 
-/* MXT_PROCI_GRIPFACE field */
+/* MXT_PROCI_GRIPFACE_T20 field */
 #define MXT_GRIPFACE_CTRL      0
 #define MXT_GRIPFACE_XLOGRIP   1
 #define MXT_GRIPFACE_XHIGRIP   2
 #define MXT_NOISE_FREQ4                15
 #define MXT_NOISE_IDLEGCAFVALID        16
 
-/* MXT_SPT_COMMSCONFIG */
+/* MXT_SPT_COMMSCONFIG_T18 */
 #define MXT_COMMS_CTRL         0
 #define MXT_COMMS_CMD          1
 
-/* MXT_SPT_CTECONFIG field */
+/* MXT_SPT_CTECONFIG_T28 field */
 #define MXT_CTE_CTRL           0
 #define MXT_CTE_CMD            1
 #define MXT_CTE_MODE           2
 #define MXT_VOLTAGE_DEFAULT    2700000
 #define MXT_VOLTAGE_STEP       10000
 
-/* Define for MXT_GEN_COMMAND */
+/* Define for MXT_GEN_COMMAND_T6 */
 #define MXT_BOOT_VALUE         0xa5
 #define MXT_BACKUP_VALUE       0x55
 #define MXT_BACKUP_TIME                25      /* msec */
@@ -256,24 +262,31 @@ struct mxt_data {
 static bool mxt_object_readable(unsigned int type)
 {
        switch (type) {
-       case MXT_GEN_MESSAGE:
-       case MXT_GEN_COMMAND:
-       case MXT_GEN_POWER:
-       case MXT_GEN_ACQUIRE:
-       case MXT_TOUCH_MULTI:
-       case MXT_TOUCH_KEYARRAY:
-       case MXT_TOUCH_PROXIMITY:
-       case MXT_PROCI_GRIPFACE:
-       case MXT_PROCG_NOISE:
-       case MXT_PROCI_ONETOUCH:
-       case MXT_PROCI_TWOTOUCH:
-       case MXT_PROCI_GRIP:
-       case MXT_PROCI_PALM:
-       case MXT_SPT_COMMSCONFIG:
-       case MXT_SPT_GPIOPWM:
-       case MXT_SPT_SELFTEST:
-       case MXT_SPT_CTECONFIG:
-       case MXT_SPT_USERDATA:
+       case MXT_GEN_MESSAGE_T5:
+       case MXT_GEN_COMMAND_T6:
+       case MXT_GEN_POWER_T7:
+       case MXT_GEN_ACQUIRE_T8:
+       case MXT_GEN_DATASOURCE_T53:
+       case MXT_TOUCH_MULTI_T9:
+       case MXT_TOUCH_KEYARRAY_T15:
+       case MXT_TOUCH_PROXIMITY_T23:
+       case MXT_TOUCH_PROXKEY_T52:
+       case MXT_PROCI_GRIPFACE_T20:
+       case MXT_PROCG_NOISE_T22:
+       case MXT_PROCI_ONETOUCH_T24:
+       case MXT_PROCI_TWOTOUCH_T27:
+       case MXT_PROCI_GRIP_T40:
+       case MXT_PROCI_PALM_T41:
+       case MXT_PROCI_TOUCHSUPPRESSION_T42:
+       case MXT_PROCI_STYLUS_T47:
+       case MXT_PROCG_NOISESUPPRESSION_T48:
+       case MXT_SPT_COMMSCONFIG_T18:
+       case MXT_SPT_GPIOPWM_T19:
+       case MXT_SPT_SELFTEST_T25:
+       case MXT_SPT_CTECONFIG_T28:
+       case MXT_SPT_USERDATA_T38:
+       case MXT_SPT_DIGITIZER_T43:
+       case MXT_SPT_CTECONFIG_T46:
                return true;
        default:
                return false;
@@ -283,21 +296,28 @@ static bool mxt_object_readable(unsigned int type)
 static bool mxt_object_writable(unsigned int type)
 {
        switch (type) {
-       case MXT_GEN_COMMAND:
-       case MXT_GEN_POWER:
-       case MXT_GEN_ACQUIRE:
-       case MXT_TOUCH_MULTI:
-       case MXT_TOUCH_KEYARRAY:
-       case MXT_TOUCH_PROXIMITY:
-       case MXT_PROCI_GRIPFACE:
-       case MXT_PROCG_NOISE:
-       case MXT_PROCI_ONETOUCH:
-       case MXT_PROCI_TWOTOUCH:
-       case MXT_PROCI_GRIP:
-       case MXT_PROCI_PALM:
-       case MXT_SPT_GPIOPWM:
-       case MXT_SPT_SELFTEST:
-       case MXT_SPT_CTECONFIG:
+       case MXT_GEN_COMMAND_T6:
+       case MXT_GEN_POWER_T7:
+       case MXT_GEN_ACQUIRE_T8:
+       case MXT_TOUCH_MULTI_T9:
+       case MXT_TOUCH_KEYARRAY_T15:
+       case MXT_TOUCH_PROXIMITY_T23:
+       case MXT_TOUCH_PROXKEY_T52:
+       case MXT_PROCI_GRIPFACE_T20:
+       case MXT_PROCG_NOISE_T22:
+       case MXT_PROCI_ONETOUCH_T24:
+       case MXT_PROCI_TWOTOUCH_T27:
+       case MXT_PROCI_GRIP_T40:
+       case MXT_PROCI_PALM_T41:
+       case MXT_PROCI_TOUCHSUPPRESSION_T42:
+       case MXT_PROCI_STYLUS_T47:
+       case MXT_PROCG_NOISESUPPRESSION_T48:
+       case MXT_SPT_COMMSCONFIG_T18:
+       case MXT_SPT_GPIOPWM_T19:
+       case MXT_SPT_SELFTEST_T25:
+       case MXT_SPT_CTECONFIG_T28:
+       case MXT_SPT_DIGITIZER_T43:
+       case MXT_SPT_CTECONFIG_T46:
                return true;
        default:
                return false;
@@ -455,7 +475,7 @@ static int mxt_read_message(struct mxt_data *data,
        struct mxt_object *object;
        u16 reg;
 
-       object = mxt_get_object(data, MXT_GEN_MESSAGE);
+       object = mxt_get_object(data, MXT_GEN_MESSAGE_T5);
        if (!object)
                return -EINVAL;
 
@@ -597,8 +617,8 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 
                reportid = message.reportid;
 
-               /* whether reportid is thing of MXT_TOUCH_MULTI */
-               object = mxt_get_object(data, MXT_TOUCH_MULTI);
+               /* whether reportid is thing of MXT_TOUCH_MULTI_T9 */
+               object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
                if (!object)
                        goto end;
 
@@ -635,7 +655,9 @@ static int mxt_check_reg_init(struct mxt_data *data)
                if (!mxt_object_writable(object->type))
                        continue;
 
-               for (j = 0; j < object->size + 1; j++) {
+               for (j = 0;
+                    j < (object->size + 1) * (object->instances + 1);
+                    j++) {
                        config_offset = index + j;
                        if (config_offset > pdata->config_length) {
                                dev_err(dev, "Not enough config data!\n");
@@ -644,7 +666,7 @@ static int mxt_check_reg_init(struct mxt_data *data)
                        mxt_write_object(data, object->type, j,
                                         pdata->config[config_offset]);
                }
-               index += object->size + 1;
+               index += (object->size + 1) * (object->instances + 1);
        }
 
        return 0;
@@ -678,31 +700,31 @@ static void mxt_handle_pdata(struct mxt_data *data)
        u8 voltage;
 
        /* Set touchscreen lines */
-       mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_XSIZE,
+       mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_XSIZE,
                        pdata->x_line);
-       mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_YSIZE,
+       mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_YSIZE,
                        pdata->y_line);
 
        /* Set touchscreen orient */
-       mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_ORIENT,
+       mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_ORIENT,
                        pdata->orient);
 
        /* Set touchscreen burst length */
-       mxt_write_object(data, MXT_TOUCH_MULTI,
+       mxt_write_object(data, MXT_TOUCH_MULTI_T9,
                        MXT_TOUCH_BLEN, pdata->blen);
 
        /* Set touchscreen threshold */
-       mxt_write_object(data, MXT_TOUCH_MULTI,
+       mxt_write_object(data, MXT_TOUCH_MULTI_T9,
                        MXT_TOUCH_TCHTHR, pdata->threshold);
 
        /* Set touchscreen resolution */
-       mxt_write_object(data, MXT_TOUCH_MULTI,
+       mxt_write_object(data, MXT_TOUCH_MULTI_T9,
                        MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
-       mxt_write_object(data, MXT_TOUCH_MULTI,
+       mxt_write_object(data, MXT_TOUCH_MULTI_T9,
                        MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
-       mxt_write_object(data, MXT_TOUCH_MULTI,
+       mxt_write_object(data, MXT_TOUCH_MULTI_T9,
                        MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
-       mxt_write_object(data, MXT_TOUCH_MULTI,
+       mxt_write_object(data, MXT_TOUCH_MULTI_T9,
                        MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
 
        /* Set touchscreen voltage */
@@ -715,7 +737,7 @@ static void mxt_handle_pdata(struct mxt_data *data)
                        voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) /
                                MXT_VOLTAGE_STEP;
 
-               mxt_write_object(data, MXT_SPT_CTECONFIG,
+               mxt_write_object(data, MXT_SPT_CTECONFIG_T28,
                                MXT_CTE_VOLTAGE, voltage);
        }
 }
@@ -819,13 +841,13 @@ static int mxt_initialize(struct mxt_data *data)
        mxt_handle_pdata(data);
 
        /* Backup to memory */
-       mxt_write_object(data, MXT_GEN_COMMAND,
+       mxt_write_object(data, MXT_GEN_COMMAND_T6,
                        MXT_COMMAND_BACKUPNV,
                        MXT_BACKUP_VALUE);
        msleep(MXT_BACKUP_TIME);
 
        /* Soft reset */
-       mxt_write_object(data, MXT_GEN_COMMAND,
+       mxt_write_object(data, MXT_GEN_COMMAND_T6,
                        MXT_COMMAND_RESET, 1);
        msleep(MXT_RESET_TIME);
 
@@ -921,7 +943,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
        }
 
        /* Change to the bootloader mode */
-       mxt_write_object(data, MXT_GEN_COMMAND,
+       mxt_write_object(data, MXT_GEN_COMMAND_T6,
                        MXT_COMMAND_RESET, MXT_BOOT_VALUE);
        msleep(MXT_RESET_TIME);
 
@@ -1027,14 +1049,14 @@ static void mxt_start(struct mxt_data *data)
 {
        /* Touch enable */
        mxt_write_object(data,
-                       MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0x83);
+                       MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0x83);
 }
 
 static void mxt_stop(struct mxt_data *data)
 {
        /* Touch disable */
        mxt_write_object(data,
-                       MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0);
+                       MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0);
 }
 
 static int mxt_input_open(struct input_dev *dev)
@@ -1182,7 +1204,7 @@ static int mxt_resume(struct device *dev)
        struct input_dev *input_dev = data->input_dev;
 
        /* Soft reset */
-       mxt_write_object(data, MXT_GEN_COMMAND,
+       mxt_write_object(data, MXT_GEN_COMMAND_T6,
                        MXT_COMMAND_RESET, 1);
 
        msleep(MXT_RESET_TIME);
index a93c5c26ab3fa7d858238d13b1c27e919958c8c9..d8815c5d54add6766c6583cdcdced63779bbf0a4 100644 (file)
@@ -84,9 +84,9 @@ static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
        memcpy(i2c_data + 1, value, len);
 
        ret = i2c_master_send(client, i2c_data, len + 1);
-       if (ret != 1) {
+       if (ret != len + 1) {
                dev_err(&client->dev, "i2c write data cmd failed\n");
-               return ret ? ret : -EIO;
+               return ret < 0 ? ret : -EIO;
        }
 
        return 0;
@@ -193,6 +193,8 @@ static int __devinit cy8ctmg110_probe(struct i2c_client *client,
 
        ts->client = client;
        ts->input = input_dev;
+       ts->reset_pin = pdata->reset_pin;
+       ts->irq_pin = pdata->irq_pin;
 
        snprintf(ts->phys, sizeof(ts->phys),
                 "%s/input0", dev_name(&client->dev));
@@ -328,7 +330,7 @@ static int __devexit cy8ctmg110_remove(struct i2c_client *client)
        return 0;
 }
 
-static struct i2c_device_id cy8ctmg110_idtable[] = {
+static const struct i2c_device_id cy8ctmg110_idtable[] = {
        { CY8CTMG110_DRIVER_NAME, 1 },
        { }
 };
index 66c96bfc5522d64f79298c9a2ea5a61a9ce3d1e5..327695268e06ed2413ddbb8e02e4079ed3eee231 100644 (file)
@@ -448,15 +448,11 @@ static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev)
  */
 static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
 {
-       int err, i, found;
+       int found = 0;
+       int err, i;
        u8 r8;
 
-       found = -1;
-
        for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
-               if (found >= 0)
-                       break;
-
                err = intel_scu_ipc_ioread8(PMICADDR0 + i, &r8);
                if (err)
                        return err;
@@ -466,16 +462,15 @@ static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
                        break;
                }
        }
-       if (found < 0)
-               return 0;
 
        if (tsdev->vendor == PMIC_VENDOR_FS) {
-               if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
+               if (found > MRSTOUCH_MAX_CHANNELS - 18)
                        return -ENOSPC;
        } else {
-               if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
+               if (found > MRSTOUCH_MAX_CHANNELS - 4)
                        return -ENOSPC;
        }
+
        return found;
 }
 
index 3242e7076258ebed157c3a3219fb559dee9b34dd..e966c29ff1bb1f81e035eaeb8a5a4144828119aa 100644 (file)
@@ -157,9 +157,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
                        x, y, p);
 
                /* are samples valid */
-               if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
-                   (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
-                   (p & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_PRES)
+               if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
+                   (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
+                   (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
                        goto up;
 
                /* coordinate is good */
index 22a3411e93c56bf7f8577334ab19d7a4e2003111..089b0a0f3d8c3f51174bb9e31c5326c61e66d679 100644 (file)
@@ -393,5 +393,5 @@ module_exit(tsc_exit);
 
 MODULE_AUTHOR("Cyril Chemparathy");
 MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
-MODULE_ALIAS("platform: tnetv107x-ts");
+MODULE_ALIAS("platform:tnetv107x-ts");
 MODULE_LICENSE("GPL");
index 98e61175d3f516ae23ca39de24435426e2bd5298..adc13a523ab5f250a929d4f6b0997ad7891780ea 100644 (file)
@@ -215,8 +215,9 @@ static inline int is_pden(struct wm97xx *wm)
 static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
 {
        int timeout = 5 * delay;
+       bool wants_pen = adcsel & WM97XX_PEN_DOWN;
 
-       if (!wm->pen_probably_down) {
+       if (wants_pen && !wm->pen_probably_down) {
                u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
                if (!(data & WM97XX_PEN_DOWN))
                        return RC_PENUP;
@@ -224,13 +225,10 @@ static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
        }
 
        /* set up digitiser */
-       if (adcsel & 0x8000)
-               adcsel = ((adcsel & 0x7fff) + 3) << 12;
-
        if (wm->mach_ops && wm->mach_ops->pre_sample)
                wm->mach_ops->pre_sample(adcsel);
-       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
-                        adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
+       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK)
+                               | WM97XX_POLL | WM97XX_DELAY(delay));
 
        /* wait 3 AC97 time slots + delay for conversion */
        poll_delay(delay);
@@ -256,13 +254,14 @@ static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
                wm->mach_ops->post_sample(adcsel);
 
        /* check we have correct sample */
-       if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
-               dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
-               *sample & WM97XX_ADCSEL_MASK);
+       if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
+               dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
+                       adcsel & WM97XX_ADCSEL_MASK,
+                       *sample & WM97XX_ADCSEL_MASK);
                return RC_PENUP;
        }
 
-       if (!(*sample & WM97XX_PEN_DOWN)) {
+       if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
                wm->pen_probably_down = 0;
                return RC_PENUP;
        }
@@ -277,14 +276,14 @@ static int wm9705_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
 {
        int rc;
 
-       rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
+       rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x);
        if (rc != RC_VALID)
                return rc;
-       rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
+       rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y);
        if (rc != RC_VALID)
                return rc;
        if (pil) {
-               rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p);
+               rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN, &data->p);
                if (rc != RC_VALID)
                        return rc;
        } else
index 2bc2fb801009d47211e6f4f6bc4d0a987c44a3a2..6e743e3dfda4a54900d12c7fd9a9a567d80d7751 100644 (file)
@@ -255,8 +255,9 @@ static inline int is_pden(struct wm97xx *wm)
 static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
 {
        int timeout = 5 * delay;
+       bool wants_pen = adcsel & WM97XX_PEN_DOWN;
 
-       if (!wm->pen_probably_down) {
+       if (wants_pen && !wm->pen_probably_down) {
                u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
                if (!(data & WM97XX_PEN_DOWN))
                        return RC_PENUP;
@@ -264,13 +265,10 @@ static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
        }
 
        /* set up digitiser */
-       if (adcsel & 0x8000)
-               adcsel = ((adcsel & 0x7fff) + 3) << 12;
-
        if (wm->mach_ops && wm->mach_ops->pre_sample)
                wm->mach_ops->pre_sample(adcsel);
-       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
-                        adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
+       wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK)
+                               | WM97XX_POLL | WM97XX_DELAY(delay));
 
        /* wait 3 AC97 time slots + delay for conversion */
        poll_delay(delay);
@@ -296,13 +294,14 @@ static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
                wm->mach_ops->post_sample(adcsel);
 
        /* check we have correct sample */
-       if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
-               dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
-               *sample & WM97XX_ADCSEL_MASK);
+       if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
+               dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
+                       adcsel & WM97XX_ADCSEL_MASK,
+                       *sample & WM97XX_ADCSEL_MASK);
                return RC_PENUP;
        }
 
-       if (!(*sample & WM97XX_PEN_DOWN)) {
+       if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
                wm->pen_probably_down = 0;
                return RC_PENUP;
        }
@@ -387,16 +386,18 @@ static int wm9712_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
                if (rc != RC_VALID)
                        return rc;
        } else {
-               rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
+               rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN,
+                                       &data->x);
                if (rc != RC_VALID)
                        return rc;
 
-               rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
+               rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN,
+                                       &data->y);
                if (rc != RC_VALID)
                        return rc;
 
                if (pil && !five_wire) {
-                       rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES,
+                       rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN,
                                                &data->p);
                        if (rc != RC_VALID)
                                return rc;
index 73ec99568f1285dd8176428e512e6042b83e7f9f..7405353199d7353e31e1bfac4b2f39db3b222fc3 100644 (file)
@@ -261,8 +261,9 @@ static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
 {
        u16 dig1;
        int timeout = 5 * delay;
+       bool wants_pen = adcsel & WM97XX_PEN_DOWN;
 
-       if (!wm->pen_probably_down) {
+       if (wants_pen && !wm->pen_probably_down) {
                u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
                if (!(data & WM97XX_PEN_DOWN))
                        return RC_PENUP;
@@ -270,15 +271,14 @@ static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
        }
 
        /* set up digitiser */
-       if (adcsel & 0x8000)
-               adcsel = 1 << ((adcsel & 0x7fff) + 3);
-
        dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
        dig1 &= ~WM9713_ADCSEL_MASK;
+       /* WM97XX_ADCSEL_* channels need to be converted to WM9713 format */
+       dig1 |= 1 << ((adcsel & WM97XX_ADCSEL_MASK) >> 12);
 
        if (wm->mach_ops && wm->mach_ops->pre_sample)
                wm->mach_ops->pre_sample(adcsel);
-       wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | adcsel | WM9713_POLL);
+       wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | WM9713_POLL);
 
        /* wait 3 AC97 time slots + delay for conversion */
        poll_delay(delay);
@@ -304,13 +304,14 @@ static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
                wm->mach_ops->post_sample(adcsel);
 
        /* check we have correct sample */
-       if ((*sample & WM97XX_ADCSRC_MASK) != ffs(adcsel >> 1) << 12) {
-               dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
-                       *sample & WM97XX_ADCSRC_MASK);
+       if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
+               dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
+                       adcsel & WM97XX_ADCSEL_MASK,
+                       *sample & WM97XX_ADCSEL_MASK);
                return RC_PENUP;
        }
 
-       if (!(*sample & WM97XX_PEN_DOWN)) {
+       if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
                wm->pen_probably_down = 0;
                return RC_PENUP;
        }
@@ -400,14 +401,14 @@ static int wm9713_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
                if (rc != RC_VALID)
                        return rc;
        } else {
-               rc = wm9713_poll_sample(wm, WM9713_ADCSEL_X, &data->x);
+               rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x);
                if (rc != RC_VALID)
                        return rc;
-               rc = wm9713_poll_sample(wm, WM9713_ADCSEL_Y, &data->y);
+               rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y);
                if (rc != RC_VALID)
                        return rc;
                if (pil) {
-                       rc = wm9713_poll_sample(wm, WM9713_ADCSEL_PRES,
+                       rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN,
                                                &data->p);
                        if (rc != RC_VALID)
                                return rc;
index 5b0f15ec874a9d97798d686b8a3bac3ac00be9f6..f6328c0cded625f10eb7ef0b1418a331fb5df175 100644 (file)
@@ -122,9 +122,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
                        x, y, p);
 
                /* are samples valid */
-               if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
-                   (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
-                   (p & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_PRES)
+               if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
+                   (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
+                   (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
                        goto up;
 
                /* coordinate is good */
index 48e9cc0369b10214d798b4a857248340e444a7b3..1f73d7f7e0242e4e73d55582935f4ff0a11f6646 100644 (file)
@@ -2532,6 +2532,9 @@ static void _isdn_setup(struct net_device *dev)
 
        /* Setup the generic properties */
        dev->flags = IFF_NOARP|IFF_POINTOPOINT;
+
+       /* isdn prepends a header in the tx path, can't share skbs */
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->header_ops = NULL;
        dev->netdev_ops = &isdn_netdev_ops;
 
index 574b09afedd32ff1f8f30ddefab722fb01edd17d..0dc6546b77a8765301b1cdf9003214ced5945ad9 100644 (file)
@@ -29,7 +29,6 @@
 #include "md.h"
 #include "bitmap.h"
 
-#include <linux/dm-dirty-log.h>
 /* debug macros */
 
 #define DEBUG 0
@@ -775,10 +774,8 @@ static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned lon
  * 0 or page 1
  */
 static inline struct page *filemap_get_page(struct bitmap *bitmap,
-                                       unsigned long chunk)
+                                           unsigned long chunk)
 {
-       if (bitmap->filemap == NULL)
-               return NULL;
        if (file_page_index(bitmap, chunk) >= bitmap->file_pages)
                return NULL;
        return bitmap->filemap[file_page_index(bitmap, chunk)
@@ -878,28 +875,19 @@ enum bitmap_page_attr {
 static inline void set_page_attr(struct bitmap *bitmap, struct page *page,
                                enum bitmap_page_attr attr)
 {
-       if (page)
-               __set_bit((page->index<<2) + attr, bitmap->filemap_attr);
-       else
-               __set_bit(attr, &bitmap->logattrs);
+       __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)
 {
-       if (page)
-               __clear_bit((page->index<<2) + attr, bitmap->filemap_attr);
-       else
-               __clear_bit(attr, &bitmap->logattrs);
+       __clear_bit((page->index<<2) + attr, bitmap->filemap_attr);
 }
 
 static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page,
                                           enum bitmap_page_attr attr)
 {
-       if (page)
-               return test_bit((page->index<<2) + attr, bitmap->filemap_attr);
-       else
-               return test_bit(attr, &bitmap->logattrs);
+       return test_bit((page->index<<2) + attr, bitmap->filemap_attr);
 }
 
 /*
@@ -912,30 +900,26 @@ static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *p
 static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
 {
        unsigned long bit;
-       struct page *page = NULL;
+       struct page *page;
        void *kaddr;
        unsigned long chunk = block >> CHUNK_BLOCK_SHIFT(bitmap);
 
-       if (!bitmap->filemap) {
-               struct dm_dirty_log *log = bitmap->mddev->bitmap_info.log;
-               if (log)
-                       log->type->mark_region(log, chunk);
-       } else {
+       if (!bitmap->filemap)
+               return;
 
-               page = filemap_get_page(bitmap, chunk);
-               if (!page)
-                       return;
-               bit = file_page_offset(bitmap, chunk);
+       page = filemap_get_page(bitmap, chunk);
+       if (!page)
+               return;
+       bit = file_page_offset(bitmap, chunk);
 
-               /* set the bit */
-               kaddr = kmap_atomic(page, KM_USER0);
-               if (bitmap->flags & BITMAP_HOSTENDIAN)
-                       set_bit(bit, kaddr);
-               else
-                       __test_and_set_bit_le(bit, kaddr);
-               kunmap_atomic(kaddr, KM_USER0);
-               PRINTK("set file bit %lu page %lu\n", bit, page->index);
-       }
+       /* set the bit */
+       kaddr = kmap_atomic(page, KM_USER0);
+       if (bitmap->flags & BITMAP_HOSTENDIAN)
+               set_bit(bit, kaddr);
+       else
+               __set_bit_le(bit, kaddr);
+       kunmap_atomic(kaddr, KM_USER0);
+       PRINTK("set file bit %lu page %lu\n", bit, page->index);
        /* record page number so it gets flushed to disk when unplug occurs */
        set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
 }
@@ -952,16 +936,6 @@ void bitmap_unplug(struct bitmap *bitmap)
 
        if (!bitmap)
                return;
-       if (!bitmap->filemap) {
-               /* Must be using a dirty_log */
-               struct dm_dirty_log *log = bitmap->mddev->bitmap_info.log;
-               dirty = test_and_clear_bit(BITMAP_PAGE_DIRTY, &bitmap->logattrs);
-               need_write = test_and_clear_bit(BITMAP_PAGE_NEEDWRITE, &bitmap->logattrs);
-               if (dirty || need_write)
-                       if (log->type->flush(log))
-                               bitmap->flags |= BITMAP_WRITE_ERROR;
-               goto out;
-       }
 
        /* look at each page to see if there are any set bits that need to be
         * flushed out to disk */
@@ -990,7 +964,6 @@ void bitmap_unplug(struct bitmap *bitmap)
                else
                        md_super_wait(bitmap->mddev);
        }
-out:
        if (bitmap->flags & BITMAP_WRITE_ERROR)
                bitmap_file_kick(bitmap);
 }
@@ -1199,7 +1172,6 @@ void bitmap_daemon_work(mddev_t *mddev)
        struct page *page = NULL, *lastpage = NULL;
        sector_t blocks;
        void *paddr;
-       struct dm_dirty_log *log = mddev->bitmap_info.log;
 
        /* Use a mutex to guard daemon_work against
         * bitmap_destroy.
@@ -1224,12 +1196,11 @@ void bitmap_daemon_work(mddev_t *mddev)
        spin_lock_irqsave(&bitmap->lock, flags);
        for (j = 0; j < bitmap->chunks; j++) {
                bitmap_counter_t *bmc;
-               if (!bitmap->filemap) {
-                       if (!log)
-                               /* error or shutdown */
-                               break;
-               } else
-                       page = filemap_get_page(bitmap, j);
+               if (!bitmap->filemap)
+                       /* error or shutdown */
+                       break;
+
+               page = filemap_get_page(bitmap, j);
 
                if (page != lastpage) {
                        /* skip this page unless it's marked as needing cleaning */
@@ -1298,17 +1269,16 @@ void bitmap_daemon_work(mddev_t *mddev)
                                                  -1);
 
                                /* clear the bit */
-                               if (page) {
-                                       paddr = kmap_atomic(page, KM_USER0);
-                                       if (bitmap->flags & BITMAP_HOSTENDIAN)
-                                               clear_bit(file_page_offset(bitmap, j),
-                                                         paddr);
-                                       else
-                                               __test_and_clear_bit_le(file_page_offset(bitmap, j),
-                                                              paddr);
-                                       kunmap_atomic(paddr, KM_USER0);
-                               } else
-                                       log->type->clear_region(log, j);
+                               paddr = kmap_atomic(page, KM_USER0);
+                               if (bitmap->flags & BITMAP_HOSTENDIAN)
+                                       clear_bit(file_page_offset(bitmap, j),
+                                                 paddr);
+                               else
+                                       __clear_bit_le(
+                                                       file_page_offset(bitmap,
+                                                                        j),
+                                                       paddr);
+                               kunmap_atomic(paddr, KM_USER0);
                        }
                } else
                        j |= PAGE_COUNTER_MASK;
@@ -1316,16 +1286,12 @@ void bitmap_daemon_work(mddev_t *mddev)
        spin_unlock_irqrestore(&bitmap->lock, flags);
 
        /* now sync the final page */
-       if (lastpage != NULL || log != NULL) {
+       if (lastpage != NULL) {
                spin_lock_irqsave(&bitmap->lock, flags);
                if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
                        clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
                        spin_unlock_irqrestore(&bitmap->lock, flags);
-                       if (lastpage)
-                               write_page(bitmap, lastpage, 0);
-                       else
-                               if (log->type->flush(log))
-                                       bitmap->flags |= BITMAP_WRITE_ERROR;
+                       write_page(bitmap, lastpage, 0);
                } else {
                        set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
                        spin_unlock_irqrestore(&bitmap->lock, flags);
@@ -1767,12 +1733,10 @@ int bitmap_create(mddev_t *mddev)
        BUILD_BUG_ON(sizeof(bitmap_super_t) != 256);
 
        if (!file
-           && !mddev->bitmap_info.offset
-           && !mddev->bitmap_info.log) /* bitmap disabled, nothing to do */
+           && !mddev->bitmap_info.offset) /* bitmap disabled, nothing to do */
                return 0;
 
        BUG_ON(file && mddev->bitmap_info.offset);
-       BUG_ON(mddev->bitmap_info.offset && mddev->bitmap_info.log);
 
        bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL);
        if (!bitmap)
@@ -1863,6 +1827,7 @@ int bitmap_create(mddev_t *mddev)
 int bitmap_load(mddev_t *mddev)
 {
        int err = 0;
+       sector_t start = 0;
        sector_t sector = 0;
        struct bitmap *bitmap = mddev->bitmap;
 
@@ -1881,24 +1846,14 @@ int bitmap_load(mddev_t *mddev)
        }
        bitmap_close_sync(bitmap);
 
-       if (mddev->bitmap_info.log) {
-               unsigned long i;
-               struct dm_dirty_log *log = mddev->bitmap_info.log;
-               for (i = 0; i < bitmap->chunks; i++)
-                       if (!log->type->in_sync(log, i, 1))
-                               bitmap_set_memory_bits(bitmap,
-                                                      (sector_t)i << CHUNK_BLOCK_SHIFT(bitmap),
-                                                      1);
-       } else {
-               sector_t start = 0;
-               if (mddev->degraded == 0
-                   || bitmap->events_cleared == mddev->events)
-                       /* no need to keep dirty bits to optimise a
-                        * re-add of a missing device */
-                       start = mddev->recovery_cp;
-
-               err = bitmap_init_from_disk(bitmap, start);
-       }
+       if (mddev->degraded == 0
+           || bitmap->events_cleared == mddev->events)
+               /* no need to keep dirty bits to optimise a
+                * re-add of a missing device */
+               start = mddev->recovery_cp;
+
+       err = bitmap_init_from_disk(bitmap, start);
+
        if (err)
                goto out;
 
index b2a127e891acedc9843ff4b61e1e8c62b2456a48..a28f2e5588c6f222f747f4cb7810cf4c48210be1 100644 (file)
@@ -212,10 +212,6 @@ struct bitmap {
        unsigned long file_pages; /* number of pages in the file */
        int last_page_size; /* bytes in the last page */
 
-       unsigned long logattrs; /* used when filemap_attr doesn't exist
-                                * because we are working with a dirty_log
-                                */
-
        unsigned long flags;
 
        int allclean;
@@ -237,7 +233,6 @@ struct bitmap {
        wait_queue_head_t behind_wait;
 
        struct sysfs_dirent *sysfs_can_clear;
-
 };
 
 /* the bitmap API */
index dfc9425db70bc7214f0735a4e3b8c9f5cf366176..8e221a20f5d98b362e8f49660454add87a5e3b38 100644 (file)
@@ -215,6 +215,55 @@ struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask,
 }
 EXPORT_SYMBOL_GPL(bio_clone_mddev);
 
+void md_trim_bio(struct bio *bio, int offset, int size)
+{
+       /* 'bio' is a cloned bio which we need to trim to match
+        * the given offset and size.
+        * This requires adjusting bi_sector, bi_size, and bi_io_vec
+        */
+       int i;
+       struct bio_vec *bvec;
+       int sofar = 0;
+
+       size <<= 9;
+       if (offset == 0 && size == bio->bi_size)
+               return;
+
+       bio->bi_sector += offset;
+       bio->bi_size = size;
+       offset <<= 9;
+       clear_bit(BIO_SEG_VALID, &bio->bi_flags);
+
+       while (bio->bi_idx < bio->bi_vcnt &&
+              bio->bi_io_vec[bio->bi_idx].bv_len <= offset) {
+               /* remove this whole bio_vec */
+               offset -= bio->bi_io_vec[bio->bi_idx].bv_len;
+               bio->bi_idx++;
+       }
+       if (bio->bi_idx < bio->bi_vcnt) {
+               bio->bi_io_vec[bio->bi_idx].bv_offset += offset;
+               bio->bi_io_vec[bio->bi_idx].bv_len -= offset;
+       }
+       /* avoid any complications with bi_idx being non-zero*/
+       if (bio->bi_idx) {
+               memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx,
+                       (bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec));
+               bio->bi_vcnt -= bio->bi_idx;
+               bio->bi_idx = 0;
+       }
+       /* Make sure vcnt and last bv are not too big */
+       bio_for_each_segment(bvec, bio, i) {
+               if (sofar + bvec->bv_len > size)
+                       bvec->bv_len = size - sofar;
+               if (bvec->bv_len == 0) {
+                       bio->bi_vcnt = i;
+                       break;
+               }
+               sofar += bvec->bv_len;
+       }
+}
+EXPORT_SYMBOL_GPL(md_trim_bio);
+
 /*
  * We have a system wide 'event count' that is incremented
  * on any 'interesting' event, and readers of /proc/mdstat
@@ -757,6 +806,10 @@ static void free_disk_sb(mdk_rdev_t * rdev)
                rdev->sb_start = 0;
                rdev->sectors = 0;
        }
+       if (rdev->bb_page) {
+               put_page(rdev->bb_page);
+               rdev->bb_page = NULL;
+       }
 }
 
 
@@ -1025,7 +1078,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
        ret = -EINVAL;
 
        bdevname(rdev->bdev, b);
-       sb = (mdp_super_t*)page_address(rdev->sb_page);
+       sb = page_address(rdev->sb_page);
 
        if (sb->md_magic != MD_SB_MAGIC) {
                printk(KERN_ERR "md: invalid raid superblock magic on %s\n",
@@ -1054,6 +1107,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
        rdev->preferred_minor = sb->md_minor;
        rdev->data_offset = 0;
        rdev->sb_size = MD_SB_BYTES;
+       rdev->badblocks.shift = -1;
 
        if (sb->level == LEVEL_MULTIPATH)
                rdev->desc_nr = -1;
@@ -1064,7 +1118,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
                ret = 1;
        } else {
                __u64 ev1, ev2;
-               mdp_super_t *refsb = (mdp_super_t*)page_address(refdev->sb_page);
+               mdp_super_t *refsb = page_address(refdev->sb_page);
                if (!uuid_equal(refsb, sb)) {
                        printk(KERN_WARNING "md: %s has different UUID to %s\n",
                                b, bdevname(refdev->bdev,b2));
@@ -1099,7 +1153,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
 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);
+       mdp_super_t *sb = page_address(rdev->sb_page);
        __u64 ev1 = md_event(sb);
 
        rdev->raid_disk = -1;
@@ -1230,7 +1284,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
 
        rdev->sb_size = MD_SB_BYTES;
 
-       sb = (mdp_super_t*)page_address(rdev->sb_page);
+       sb = page_address(rdev->sb_page);
 
        memset(sb, 0, sizeof(*sb));
 
@@ -1395,6 +1449,8 @@ static __le32 calc_sb_1_csum(struct mdp_superblock_1 * sb)
        return cpu_to_le32(csum);
 }
 
+static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
+                           int acknowledged);
 static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
 {
        struct mdp_superblock_1 *sb;
@@ -1435,7 +1491,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
        if (ret) return ret;
 
 
-       sb = (struct mdp_superblock_1*)page_address(rdev->sb_page);
+       sb = page_address(rdev->sb_page);
 
        if (sb->magic != cpu_to_le32(MD_SB_MAGIC) ||
            sb->major_version != cpu_to_le32(1) ||
@@ -1473,12 +1529,52 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
        else
                rdev->desc_nr = le32_to_cpu(sb->dev_number);
 
+       if (!rdev->bb_page) {
+               rdev->bb_page = alloc_page(GFP_KERNEL);
+               if (!rdev->bb_page)
+                       return -ENOMEM;
+       }
+       if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BAD_BLOCKS) &&
+           rdev->badblocks.count == 0) {
+               /* need to load the bad block list.
+                * Currently we limit it to one page.
+                */
+               s32 offset;
+               sector_t bb_sector;
+               u64 *bbp;
+               int i;
+               int sectors = le16_to_cpu(sb->bblog_size);
+               if (sectors > (PAGE_SIZE / 512))
+                       return -EINVAL;
+               offset = le32_to_cpu(sb->bblog_offset);
+               if (offset == 0)
+                       return -EINVAL;
+               bb_sector = (long long)offset;
+               if (!sync_page_io(rdev, bb_sector, sectors << 9,
+                                 rdev->bb_page, READ, true))
+                       return -EIO;
+               bbp = (u64 *)page_address(rdev->bb_page);
+               rdev->badblocks.shift = sb->bblog_shift;
+               for (i = 0 ; i < (sectors << (9-3)) ; i++, bbp++) {
+                       u64 bb = le64_to_cpu(*bbp);
+                       int count = bb & (0x3ff);
+                       u64 sector = bb >> 10;
+                       sector <<= sb->bblog_shift;
+                       count <<= sb->bblog_shift;
+                       if (bb + 1 == 0)
+                               break;
+                       if (md_set_badblocks(&rdev->badblocks,
+                                            sector, count, 1) == 0)
+                               return -EINVAL;
+               }
+       } else if (sb->bblog_offset == 0)
+               rdev->badblocks.shift = -1;
+
        if (!refdev) {
                ret = 1;
        } else {
                __u64 ev1, ev2;
-               struct mdp_superblock_1 *refsb = 
-                       (struct mdp_superblock_1*)page_address(refdev->sb_page);
+               struct mdp_superblock_1 *refsb = page_address(refdev->sb_page);
 
                if (memcmp(sb->set_uuid, refsb->set_uuid, 16) != 0 ||
                    sb->level != refsb->level ||
@@ -1513,7 +1609,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);
+       struct mdp_superblock_1 *sb = page_address(rdev->sb_page);
        __u64 ev1 = le64_to_cpu(sb->events);
 
        rdev->raid_disk = -1;
@@ -1619,13 +1715,12 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
        int max_dev, i;
        /* make rdev->sb match mddev and rdev data. */
 
-       sb = (struct mdp_superblock_1*)page_address(rdev->sb_page);
+       sb = page_address(rdev->sb_page);
 
        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));
 
        sb->utime = cpu_to_le64((__u64)mddev->utime);
@@ -1665,6 +1760,40 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
                sb->new_chunk = cpu_to_le32(mddev->new_chunk_sectors);
        }
 
+       if (rdev->badblocks.count == 0)
+               /* Nothing to do for bad blocks*/ ;
+       else if (sb->bblog_offset == 0)
+               /* Cannot record bad blocks on this device */
+               md_error(mddev, rdev);
+       else {
+               struct badblocks *bb = &rdev->badblocks;
+               u64 *bbp = (u64 *)page_address(rdev->bb_page);
+               u64 *p = bb->page;
+               sb->feature_map |= cpu_to_le32(MD_FEATURE_BAD_BLOCKS);
+               if (bb->changed) {
+                       unsigned seq;
+
+retry:
+                       seq = read_seqbegin(&bb->lock);
+
+                       memset(bbp, 0xff, PAGE_SIZE);
+
+                       for (i = 0 ; i < bb->count ; i++) {
+                               u64 internal_bb = *p++;
+                               u64 store_bb = ((BB_OFFSET(internal_bb) << 10)
+                                               | BB_LEN(internal_bb));
+                               *bbp++ = cpu_to_le64(store_bb);
+                       }
+                       if (read_seqretry(&bb->lock, seq))
+                               goto retry;
+
+                       bb->sector = (rdev->sb_start +
+                                     (int)le32_to_cpu(sb->bblog_offset));
+                       bb->size = le16_to_cpu(sb->bblog_size);
+                       bb->changed = 0;
+               }
+       }
+
        max_dev = 0;
        list_for_each_entry(rdev2, &mddev->disks, same_set)
                if (rdev2->desc_nr+1 > max_dev)
@@ -1724,7 +1853,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
                        num_sectors = max_sectors;
                rdev->sb_start = sb_start;
        }
-       sb = (struct mdp_superblock_1 *) page_address(rdev->sb_page);
+       sb = page_address(rdev->sb_page);
        sb->data_size = cpu_to_le64(num_sectors);
        sb->super_offset = rdev->sb_start;
        sb->sb_csum = calc_sb_1_csum(sb);
@@ -1922,7 +2051,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
        bd_link_disk_holder(rdev->bdev, mddev->gendisk);
 
        /* May as well allow recovery to be retried once */
-       mddev->recovery_disabled = 0;
+       mddev->recovery_disabled++;
 
        return 0;
 
@@ -1953,6 +2082,9 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
        sysfs_remove_link(&rdev->kobj, "block");
        sysfs_put(rdev->sysfs_state);
        rdev->sysfs_state = NULL;
+       kfree(rdev->badblocks.page);
+       rdev->badblocks.count = 0;
+       rdev->badblocks.page = NULL;
        /* We need to delay this, otherwise we can deadlock when
         * writing to 'remove' to "dev/state".  We also need
         * to delay it due to rcu usage.
@@ -2127,10 +2259,10 @@ static void print_rdev(mdk_rdev_t *rdev, int major_version)
                printk(KERN_INFO "md: rdev superblock (MJ:%d):\n", major_version);
                switch (major_version) {
                case 0:
-                       print_sb_90((mdp_super_t*)page_address(rdev->sb_page));
+                       print_sb_90(page_address(rdev->sb_page));
                        break;
                case 1:
-                       print_sb_1((struct mdp_superblock_1 *)page_address(rdev->sb_page));
+                       print_sb_1(page_address(rdev->sb_page));
                        break;
                }
        } else
@@ -2194,6 +2326,7 @@ static void md_update_sb(mddev_t * mddev, int force_change)
        mdk_rdev_t *rdev;
        int sync_req;
        int nospares = 0;
+       int any_badblocks_changed = 0;
 
 repeat:
        /* First make sure individual recovery_offsets are correct */
@@ -2208,8 +2341,18 @@ repeat:
        if (!mddev->persistent) {
                clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
                clear_bit(MD_CHANGE_DEVS, &mddev->flags);
-               if (!mddev->external)
+               if (!mddev->external) {
                        clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+                       list_for_each_entry(rdev, &mddev->disks, same_set) {
+                               if (rdev->badblocks.changed) {
+                                       md_ack_all_badblocks(&rdev->badblocks);
+                                       md_error(mddev, rdev);
+                               }
+                               clear_bit(Blocked, &rdev->flags);
+                               clear_bit(BlockedBadBlocks, &rdev->flags);
+                               wake_up(&rdev->blocked_wait);
+                       }
+               }
                wake_up(&mddev->sb_wait);
                return;
        }
@@ -2265,6 +2408,14 @@ repeat:
                MD_BUG();
                mddev->events --;
        }
+
+       list_for_each_entry(rdev, &mddev->disks, same_set) {
+               if (rdev->badblocks.changed)
+                       any_badblocks_changed++;
+               if (test_bit(Faulty, &rdev->flags))
+                       set_bit(FaultRecorded, &rdev->flags);
+       }
+
        sync_sbs(mddev, nospares);
        spin_unlock_irq(&mddev->write_lock);
 
@@ -2290,6 +2441,13 @@ repeat:
                                bdevname(rdev->bdev,b),
                                (unsigned long long)rdev->sb_start);
                        rdev->sb_events = mddev->events;
+                       if (rdev->badblocks.size) {
+                               md_super_write(mddev, rdev,
+                                              rdev->badblocks.sector,
+                                              rdev->badblocks.size << 9,
+                                              rdev->bb_page);
+                               rdev->badblocks.size = 0;
+                       }
 
                } else
                        dprintk(")\n");
@@ -2313,6 +2471,15 @@ repeat:
        if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
                sysfs_notify(&mddev->kobj, NULL, "sync_completed");
 
+       list_for_each_entry(rdev, &mddev->disks, same_set) {
+               if (test_and_clear_bit(FaultRecorded, &rdev->flags))
+                       clear_bit(Blocked, &rdev->flags);
+
+               if (any_badblocks_changed)
+                       md_ack_all_badblocks(&rdev->badblocks);
+               clear_bit(BlockedBadBlocks, &rdev->flags);
+               wake_up(&rdev->blocked_wait);
+       }
 }
 
 /* words written to sysfs files may, or may not, be \n terminated.
@@ -2347,7 +2514,8 @@ state_show(mdk_rdev_t *rdev, char *page)
        char *sep = "";
        size_t len = 0;
 
-       if (test_bit(Faulty, &rdev->flags)) {
+       if (test_bit(Faulty, &rdev->flags) ||
+           rdev->badblocks.unacked_exist) {
                len+= sprintf(page+len, "%sfaulty",sep);
                sep = ",";
        }
@@ -2359,7 +2527,8 @@ state_show(mdk_rdev_t *rdev, char *page)
                len += sprintf(page+len, "%swrite_mostly",sep);
                sep = ",";
        }
-       if (test_bit(Blocked, &rdev->flags)) {
+       if (test_bit(Blocked, &rdev->flags) ||
+           rdev->badblocks.unacked_exist) {
                len += sprintf(page+len, "%sblocked", sep);
                sep = ",";
        }
@@ -2368,6 +2537,10 @@ state_show(mdk_rdev_t *rdev, char *page)
                len += sprintf(page+len, "%sspare", sep);
                sep = ",";
        }
+       if (test_bit(WriteErrorSeen, &rdev->flags)) {
+               len += sprintf(page+len, "%swrite_error", sep);
+               sep = ",";
+       }
        return len+sprintf(page+len, "\n");
 }
 
@@ -2375,13 +2548,15 @@ static ssize_t
 state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 {
        /* can write
-        *  faulty  - simulates and error
+        *  faulty  - simulates an error
         *  remove  - disconnects the device
         *  writemostly - sets write_mostly
         *  -writemostly - clears write_mostly
-        *  blocked - sets the Blocked flag
-        *  -blocked - clears the Blocked flag
+        *  blocked - sets the Blocked flags
+        *  -blocked - clears the Blocked and possibly simulates an error
         *  insync - sets Insync providing device isn't active
+        *  write_error - sets WriteErrorSeen
+        *  -write_error - clears WriteErrorSeen
         */
        int err = -EINVAL;
        if (cmd_match(buf, "faulty") && rdev->mddev->pers) {
@@ -2408,7 +2583,15 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                set_bit(Blocked, &rdev->flags);
                err = 0;
        } else if (cmd_match(buf, "-blocked")) {
+               if (!test_bit(Faulty, &rdev->flags) &&
+                   test_bit(BlockedBadBlocks, &rdev->flags)) {
+                       /* metadata handler doesn't understand badblocks,
+                        * so we need to fail the device
+                        */
+                       md_error(rdev->mddev, rdev);
+               }
                clear_bit(Blocked, &rdev->flags);
+               clear_bit(BlockedBadBlocks, &rdev->flags);
                wake_up(&rdev->blocked_wait);
                set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
                md_wakeup_thread(rdev->mddev->thread);
@@ -2417,6 +2600,12 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
        } else if (cmd_match(buf, "insync") && rdev->raid_disk == -1) {
                set_bit(In_sync, &rdev->flags);
                err = 0;
+       } else if (cmd_match(buf, "write_error")) {
+               set_bit(WriteErrorSeen, &rdev->flags);
+               err = 0;
+       } else if (cmd_match(buf, "-write_error")) {
+               clear_bit(WriteErrorSeen, &rdev->flags);
+               err = 0;
        }
        if (!err)
                sysfs_notify_dirent_safe(rdev->sysfs_state);
@@ -2459,7 +2648,6 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
 {
        char *e;
        int err;
-       char nm[20];
        int slot = simple_strtoul(buf, &e, 10);
        if (strncmp(buf, "none", 4)==0)
                slot = -1;
@@ -2482,8 +2670,7 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                        hot_remove_disk(rdev->mddev, rdev->raid_disk);
                if (err)
                        return err;
-               sprintf(nm, "rd%d", rdev->raid_disk);
-               sysfs_remove_link(&rdev->mddev->kobj, nm);
+               sysfs_unlink_rdev(rdev->mddev, rdev);
                rdev->raid_disk = -1;
                set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
                md_wakeup_thread(rdev->mddev->thread);
@@ -2522,8 +2709,7 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                        return err;
                } else
                        sysfs_notify_dirent_safe(rdev->sysfs_state);
-               sprintf(nm, "rd%d", rdev->raid_disk);
-               if (sysfs_create_link(&rdev->mddev->kobj, &rdev->kobj, nm))
+               if (sysfs_link_rdev(rdev->mddev, rdev))
                        /* failure here is OK */;
                /* don't wakeup anyone, leave that to userspace. */
        } else {
@@ -2712,6 +2898,39 @@ static ssize_t recovery_start_store(mdk_rdev_t *rdev, const char *buf, size_t le
 static struct rdev_sysfs_entry rdev_recovery_start =
 __ATTR(recovery_start, S_IRUGO|S_IWUSR, recovery_start_show, recovery_start_store);
 
+
+static ssize_t
+badblocks_show(struct badblocks *bb, char *page, int unack);
+static ssize_t
+badblocks_store(struct badblocks *bb, const char *page, size_t len, int unack);
+
+static ssize_t bb_show(mdk_rdev_t *rdev, char *page)
+{
+       return badblocks_show(&rdev->badblocks, page, 0);
+}
+static ssize_t bb_store(mdk_rdev_t *rdev, const char *page, size_t len)
+{
+       int rv = badblocks_store(&rdev->badblocks, page, len, 0);
+       /* Maybe that ack was all we needed */
+       if (test_and_clear_bit(BlockedBadBlocks, &rdev->flags))
+               wake_up(&rdev->blocked_wait);
+       return rv;
+}
+static struct rdev_sysfs_entry rdev_bad_blocks =
+__ATTR(bad_blocks, S_IRUGO|S_IWUSR, bb_show, bb_store);
+
+
+static ssize_t ubb_show(mdk_rdev_t *rdev, char *page)
+{
+       return badblocks_show(&rdev->badblocks, page, 1);
+}
+static ssize_t ubb_store(mdk_rdev_t *rdev, const char *page, size_t len)
+{
+       return badblocks_store(&rdev->badblocks, page, len, 1);
+}
+static struct rdev_sysfs_entry rdev_unack_bad_blocks =
+__ATTR(unacknowledged_bad_blocks, S_IRUGO|S_IWUSR, ubb_show, ubb_store);
+
 static struct attribute *rdev_default_attrs[] = {
        &rdev_state.attr,
        &rdev_errors.attr,
@@ -2719,6 +2938,8 @@ static struct attribute *rdev_default_attrs[] = {
        &rdev_offset.attr,
        &rdev_size.attr,
        &rdev_recovery_start.attr,
+       &rdev_bad_blocks.attr,
+       &rdev_unack_bad_blocks.attr,
        NULL,
 };
 static ssize_t
@@ -2782,7 +3003,7 @@ static struct kobj_type rdev_ktype = {
        .default_attrs  = rdev_default_attrs,
 };
 
-void md_rdev_init(mdk_rdev_t *rdev)
+int md_rdev_init(mdk_rdev_t *rdev)
 {
        rdev->desc_nr = -1;
        rdev->saved_raid_disk = -1;
@@ -2792,12 +3013,27 @@ void md_rdev_init(mdk_rdev_t *rdev)
        rdev->sb_events = 0;
        rdev->last_read_error.tv_sec  = 0;
        rdev->last_read_error.tv_nsec = 0;
+       rdev->sb_loaded = 0;
+       rdev->bb_page = NULL;
        atomic_set(&rdev->nr_pending, 0);
        atomic_set(&rdev->read_errors, 0);
        atomic_set(&rdev->corrected_errors, 0);
 
        INIT_LIST_HEAD(&rdev->same_set);
        init_waitqueue_head(&rdev->blocked_wait);
+
+       /* Add space to store bad block list.
+        * This reserves the space even on arrays where it cannot
+        * be used - I wonder if that matters
+        */
+       rdev->badblocks.count = 0;
+       rdev->badblocks.shift = 0;
+       rdev->badblocks.page = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       seqlock_init(&rdev->badblocks.lock);
+       if (rdev->badblocks.page == NULL)
+               return -ENOMEM;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(md_rdev_init);
 /*
@@ -2823,8 +3059,11 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
                return ERR_PTR(-ENOMEM);
        }
 
-       md_rdev_init(rdev);
-       if ((err = alloc_disk_sb(rdev)))
+       err = md_rdev_init(rdev);
+       if (err)
+               goto abort_free;
+       err = alloc_disk_sb(rdev);
+       if (err)
                goto abort_free;
 
        err = lock_rdev(rdev, newdev, super_format == -2);
@@ -2860,15 +3099,17 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
                        goto abort_free;
                }
        }
+       if (super_format == -1)
+               /* hot-add for 0.90, or non-persistent: so no badblocks */
+               rdev->badblocks.shift = -1;
 
        return rdev;
 
 abort_free:
-       if (rdev->sb_page) {
-               if (rdev->bdev)
-                       unlock_rdev(rdev);
-               free_disk_sb(rdev);
-       }
+       if (rdev->bdev)
+               unlock_rdev(rdev);
+       free_disk_sb(rdev);
+       kfree(rdev->badblocks.page);
        kfree(rdev);
        return ERR_PTR(err);
 }
@@ -3149,15 +3390,13 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
        }
 
        list_for_each_entry(rdev, &mddev->disks, same_set) {
-               char nm[20];
                if (rdev->raid_disk < 0)
                        continue;
                if (rdev->new_raid_disk >= mddev->raid_disks)
                        rdev->new_raid_disk = -1;
                if (rdev->new_raid_disk == rdev->raid_disk)
                        continue;
-               sprintf(nm, "rd%d", rdev->raid_disk);
-               sysfs_remove_link(&mddev->kobj, nm);
+               sysfs_unlink_rdev(mddev, rdev);
        }
        list_for_each_entry(rdev, &mddev->disks, same_set) {
                if (rdev->raid_disk < 0)
@@ -3168,11 +3407,10 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
                if (rdev->raid_disk < 0)
                        clear_bit(In_sync, &rdev->flags);
                else {
-                       char nm[20];
-                       sprintf(nm, "rd%d", rdev->raid_disk);
-                       if(sysfs_create_link(&mddev->kobj, &rdev->kobj, nm))
-                               printk("md: cannot register %s for %s after level change\n",
-                                      nm, mdname(mddev));
+                       if (sysfs_link_rdev(mddev, rdev))
+                               printk(KERN_WARNING "md: cannot register rd%d"
+                                      " for %s after level change\n",
+                                      rdev->raid_disk, mdname(mddev));
                }
        }
 
@@ -4504,7 +4742,8 @@ int md_run(mddev_t *mddev)
        }
 
        if (mddev->bio_set == NULL)
-               mddev->bio_set = bioset_create(BIO_POOL_SIZE, sizeof(mddev));
+               mddev->bio_set = bioset_create(BIO_POOL_SIZE,
+                                              sizeof(mddev_t *));
 
        spin_lock(&pers_lock);
        pers = find_pers(mddev->level, mddev->clevel);
@@ -4621,12 +4860,9 @@ int md_run(mddev_t *mddev)
        smp_wmb();
        mddev->ready = 1;
        list_for_each_entry(rdev, &mddev->disks, same_set)
-               if (rdev->raid_disk >= 0) {
-                       char nm[20];
-                       sprintf(nm, "rd%d", rdev->raid_disk);
-                       if (sysfs_create_link(&mddev->kobj, &rdev->kobj, nm))
+               if (rdev->raid_disk >= 0)
+                       if (sysfs_link_rdev(mddev, rdev))
                                /* failure here is OK */;
-               }
        
        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        
@@ -4854,11 +5090,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
                sysfs_notify_dirent_safe(mddev->sysfs_state);
 
                list_for_each_entry(rdev, &mddev->disks, same_set)
-                       if (rdev->raid_disk >= 0) {
-                               char nm[20];
-                               sprintf(nm, "rd%d", rdev->raid_disk);
-                               sysfs_remove_link(&mddev->kobj, nm);
-                       }
+                       if (rdev->raid_disk >= 0)
+                               sysfs_unlink_rdev(mddev, rdev);
 
                set_capacity(disk, 0);
                mutex_unlock(&mddev->open_mutex);
@@ -6198,18 +6431,7 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
        if (!rdev || test_bit(Faulty, &rdev->flags))
                return;
 
-       if (mddev->external)
-               set_bit(Blocked, &rdev->flags);
-/*
-       dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
-               mdname(mddev),
-               MAJOR(rdev->bdev->bd_dev), MINOR(rdev->bdev->bd_dev),
-               __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)
+       if (!mddev->pers || !mddev->pers->error_handler)
                return;
        mddev->pers->error_handler(mddev,rdev);
        if (mddev->degraded)
@@ -6933,11 +7155,14 @@ void md_do_sync(mddev_t *mddev)
                        atomic_add(sectors, &mddev->recovery_active);
                }
 
+               if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+                       break;
+
                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
+                       /* this is the earliest that rebuild will be
                         * visible in /proc/mdstat
                         */
                        md_new_event(mddev);
@@ -6946,10 +7171,6 @@ void md_do_sync(mddev_t *mddev)
                        continue;
 
                last_check = io_sectors;
-
-               if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
-                       break;
-
        repeat:
                if (time_after_eq(jiffies, mark[last_mark] + SYNC_MARK_STEP )) {
                        /* step marks */
@@ -7067,29 +7288,23 @@ static int remove_and_add_spares(mddev_t *mddev)
                    atomic_read(&rdev->nr_pending)==0) {
                        if (mddev->pers->hot_remove_disk(
                                    mddev, rdev->raid_disk)==0) {
-                               char nm[20];
-                               sprintf(nm,"rd%d", rdev->raid_disk);
-                               sysfs_remove_link(&mddev->kobj, nm);
+                               sysfs_unlink_rdev(mddev, rdev);
                                rdev->raid_disk = -1;
                        }
                }
 
-       if (mddev->degraded && !mddev->recovery_disabled) {
+       if (mddev->degraded) {
                list_for_each_entry(rdev, &mddev->disks, same_set) {
                        if (rdev->raid_disk >= 0 &&
                            !test_bit(In_sync, &rdev->flags) &&
-                           !test_bit(Faulty, &rdev->flags) &&
-                           !test_bit(Blocked, &rdev->flags))
+                           !test_bit(Faulty, &rdev->flags))
                                spares++;
                        if (rdev->raid_disk < 0
                            && !test_bit(Faulty, &rdev->flags)) {
                                rdev->recovery_offset = 0;
                                if (mddev->pers->
                                    hot_add_disk(mddev, rdev) == 0) {
-                                       char nm[20];
-                                       sprintf(nm, "rd%d", rdev->raid_disk);
-                                       if (sysfs_create_link(&mddev->kobj,
-                                                             &rdev->kobj, nm))
+                                       if (sysfs_link_rdev(mddev, rdev))
                                                /* failure here is OK */;
                                        spares++;
                                        md_new_event(mddev);
@@ -7138,6 +7353,8 @@ static void reap_sync_thread(mddev_t *mddev)
        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        sysfs_notify_dirent_safe(mddev->sysfs_action);
        md_new_event(mddev);
+       if (mddev->event_work.func)
+               queue_work(md_misc_wq, &mddev->event_work);
 }
 
 /*
@@ -7170,9 +7387,6 @@ void md_check_recovery(mddev_t *mddev)
        if (mddev->bitmap)
                bitmap_daemon_work(mddev);
 
-       if (mddev->ro)
-               return;
-
        if (signal_pending(current)) {
                if (mddev->pers->sync_request && !mddev->external) {
                        printk(KERN_INFO "md: %s in immediate safe mode\n",
@@ -7209,9 +7423,7 @@ void md_check_recovery(mddev_t *mddev)
                                    atomic_read(&rdev->nr_pending)==0) {
                                        if (mddev->pers->hot_remove_disk(
                                                    mddev, rdev->raid_disk)==0) {
-                                               char nm[20];
-                                               sprintf(nm,"rd%d", rdev->raid_disk);
-                                               sysfs_remove_link(&mddev->kobj, nm);
+                                               sysfs_unlink_rdev(mddev, rdev);
                                                rdev->raid_disk = -1;
                                        }
                                }
@@ -7331,12 +7543,499 @@ void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev)
 {
        sysfs_notify_dirent_safe(rdev->sysfs_state);
        wait_event_timeout(rdev->blocked_wait,
-                          !test_bit(Blocked, &rdev->flags),
+                          !test_bit(Blocked, &rdev->flags) &&
+                          !test_bit(BlockedBadBlocks, &rdev->flags),
                           msecs_to_jiffies(5000));
        rdev_dec_pending(rdev, mddev);
 }
 EXPORT_SYMBOL(md_wait_for_blocked_rdev);
 
+
+/* Bad block management.
+ * We can record which blocks on each device are 'bad' and so just
+ * fail those blocks, or that stripe, rather than the whole device.
+ * Entries in the bad-block table are 64bits wide.  This comprises:
+ * Length of bad-range, in sectors: 0-511 for lengths 1-512
+ * Start of bad-range, sector offset, 54 bits (allows 8 exbibytes)
+ *  A 'shift' can be set so that larger blocks are tracked and
+ *  consequently larger devices can be covered.
+ * 'Acknowledged' flag - 1 bit. - the most significant bit.
+ *
+ * Locking of the bad-block table uses a seqlock so md_is_badblock
+ * might need to retry if it is very unlucky.
+ * We will sometimes want to check for bad blocks in a bi_end_io function,
+ * so we use the write_seqlock_irq variant.
+ *
+ * When looking for a bad block we specify a range and want to
+ * know if any block in the range is bad.  So we binary-search
+ * to the last range that starts at-or-before the given endpoint,
+ * (or "before the sector after the target range")
+ * then see if it ends after the given start.
+ * We return
+ *  0 if there are no known bad blocks in the range
+ *  1 if there are known bad block which are all acknowledged
+ * -1 if there are bad blocks which have not yet been acknowledged in metadata.
+ * plus the start/length of the first bad section we overlap.
+ */
+int md_is_badblock(struct badblocks *bb, sector_t s, int sectors,
+                  sector_t *first_bad, int *bad_sectors)
+{
+       int hi;
+       int lo = 0;
+       u64 *p = bb->page;
+       int rv = 0;
+       sector_t target = s + sectors;
+       unsigned seq;
+
+       if (bb->shift > 0) {
+               /* round the start down, and the end up */
+               s >>= bb->shift;
+               target += (1<<bb->shift) - 1;
+               target >>= bb->shift;
+               sectors = target - s;
+       }
+       /* 'target' is now the first block after the bad range */
+
+retry:
+       seq = read_seqbegin(&bb->lock);
+
+       hi = bb->count;
+
+       /* Binary search between lo and hi for 'target'
+        * i.e. for the last range that starts before 'target'
+        */
+       /* INVARIANT: ranges before 'lo' and at-or-after 'hi'
+        * are known not to be the last range before target.
+        * VARIANT: hi-lo is the number of possible
+        * ranges, and decreases until it reaches 1
+        */
+       while (hi - lo > 1) {
+               int mid = (lo + hi) / 2;
+               sector_t a = BB_OFFSET(p[mid]);
+               if (a < target)
+                       /* This could still be the one, earlier ranges
+                        * could not. */
+                       lo = mid;
+               else
+                       /* This and later ranges are definitely out. */
+                       hi = mid;
+       }
+       /* 'lo' might be the last that started before target, but 'hi' isn't */
+       if (hi > lo) {
+               /* need to check all range that end after 's' to see if
+                * any are unacknowledged.
+                */
+               while (lo >= 0 &&
+                      BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
+                       if (BB_OFFSET(p[lo]) < target) {
+                               /* starts before the end, and finishes after
+                                * the start, so they must overlap
+                                */
+                               if (rv != -1 && BB_ACK(p[lo]))
+                                       rv = 1;
+                               else
+                                       rv = -1;
+                               *first_bad = BB_OFFSET(p[lo]);
+                               *bad_sectors = BB_LEN(p[lo]);
+                       }
+                       lo--;
+               }
+       }
+
+       if (read_seqretry(&bb->lock, seq))
+               goto retry;
+
+       return rv;
+}
+EXPORT_SYMBOL_GPL(md_is_badblock);
+
+/*
+ * Add a range of bad blocks to the table.
+ * This might extend the table, or might contract it
+ * if two adjacent ranges can be merged.
+ * We binary-search to find the 'insertion' point, then
+ * decide how best to handle it.
+ */
+static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
+                           int acknowledged)
+{
+       u64 *p;
+       int lo, hi;
+       int rv = 1;
+
+       if (bb->shift < 0)
+               /* badblocks are disabled */
+               return 0;
+
+       if (bb->shift) {
+               /* round the start down, and the end up */
+               sector_t next = s + sectors;
+               s >>= bb->shift;
+               next += (1<<bb->shift) - 1;
+               next >>= bb->shift;
+               sectors = next - s;
+       }
+
+       write_seqlock_irq(&bb->lock);
+
+       p = bb->page;
+       lo = 0;
+       hi = bb->count;
+       /* Find the last range that starts at-or-before 's' */
+       while (hi - lo > 1) {
+               int mid = (lo + hi) / 2;
+               sector_t a = BB_OFFSET(p[mid]);
+               if (a <= s)
+                       lo = mid;
+               else
+                       hi = mid;
+       }
+       if (hi > lo && BB_OFFSET(p[lo]) > s)
+               hi = lo;
+
+       if (hi > lo) {
+               /* we found a range that might merge with the start
+                * of our new range
+                */
+               sector_t a = BB_OFFSET(p[lo]);
+               sector_t e = a + BB_LEN(p[lo]);
+               int ack = BB_ACK(p[lo]);
+               if (e >= s) {
+                       /* Yes, we can merge with a previous range */
+                       if (s == a && s + sectors >= e)
+                               /* new range covers old */
+                               ack = acknowledged;
+                       else
+                               ack = ack && acknowledged;
+
+                       if (e < s + sectors)
+                               e = s + sectors;
+                       if (e - a <= BB_MAX_LEN) {
+                               p[lo] = BB_MAKE(a, e-a, ack);
+                               s = e;
+                       } else {
+                               /* does not all fit in one range,
+                                * make p[lo] maximal
+                                */
+                               if (BB_LEN(p[lo]) != BB_MAX_LEN)
+                                       p[lo] = BB_MAKE(a, BB_MAX_LEN, ack);
+                               s = a + BB_MAX_LEN;
+                       }
+                       sectors = e - s;
+               }
+       }
+       if (sectors && hi < bb->count) {
+               /* 'hi' points to the first range that starts after 's'.
+                * Maybe we can merge with the start of that range */
+               sector_t a = BB_OFFSET(p[hi]);
+               sector_t e = a + BB_LEN(p[hi]);
+               int ack = BB_ACK(p[hi]);
+               if (a <= s + sectors) {
+                       /* merging is possible */
+                       if (e <= s + sectors) {
+                               /* full overlap */
+                               e = s + sectors;
+                               ack = acknowledged;
+                       } else
+                               ack = ack && acknowledged;
+
+                       a = s;
+                       if (e - a <= BB_MAX_LEN) {
+                               p[hi] = BB_MAKE(a, e-a, ack);
+                               s = e;
+                       } else {
+                               p[hi] = BB_MAKE(a, BB_MAX_LEN, ack);
+                               s = a + BB_MAX_LEN;
+                       }
+                       sectors = e - s;
+                       lo = hi;
+                       hi++;
+               }
+       }
+       if (sectors == 0 && hi < bb->count) {
+               /* we might be able to combine lo and hi */
+               /* Note: 's' is at the end of 'lo' */
+               sector_t a = BB_OFFSET(p[hi]);
+               int lolen = BB_LEN(p[lo]);
+               int hilen = BB_LEN(p[hi]);
+               int newlen = lolen + hilen - (s - a);
+               if (s >= a && newlen < BB_MAX_LEN) {
+                       /* yes, we can combine them */
+                       int ack = BB_ACK(p[lo]) && BB_ACK(p[hi]);
+                       p[lo] = BB_MAKE(BB_OFFSET(p[lo]), newlen, ack);
+                       memmove(p + hi, p + hi + 1,
+                               (bb->count - hi - 1) * 8);
+                       bb->count--;
+               }
+       }
+       while (sectors) {
+               /* didn't merge (it all).
+                * Need to add a range just before 'hi' */
+               if (bb->count >= MD_MAX_BADBLOCKS) {
+                       /* No room for more */
+                       rv = 0;
+                       break;
+               } else {
+                       int this_sectors = sectors;
+                       memmove(p + hi + 1, p + hi,
+                               (bb->count - hi) * 8);
+                       bb->count++;
+
+                       if (this_sectors > BB_MAX_LEN)
+                               this_sectors = BB_MAX_LEN;
+                       p[hi] = BB_MAKE(s, this_sectors, acknowledged);
+                       sectors -= this_sectors;
+                       s += this_sectors;
+               }
+       }
+
+       bb->changed = 1;
+       if (!acknowledged)
+               bb->unacked_exist = 1;
+       write_sequnlock_irq(&bb->lock);
+
+       return rv;
+}
+
+int rdev_set_badblocks(mdk_rdev_t *rdev, sector_t s, int sectors,
+                      int acknowledged)
+{
+       int rv = md_set_badblocks(&rdev->badblocks,
+                                 s + rdev->data_offset, sectors, acknowledged);
+       if (rv) {
+               /* Make sure they get written out promptly */
+               set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags);
+               md_wakeup_thread(rdev->mddev->thread);
+       }
+       return rv;
+}
+EXPORT_SYMBOL_GPL(rdev_set_badblocks);
+
+/*
+ * Remove a range of bad blocks from the table.
+ * This may involve extending the table if we spilt a region,
+ * but it must not fail.  So if the table becomes full, we just
+ * drop the remove request.
+ */
+static int md_clear_badblocks(struct badblocks *bb, sector_t s, int sectors)
+{
+       u64 *p;
+       int lo, hi;
+       sector_t target = s + sectors;
+       int rv = 0;
+
+       if (bb->shift > 0) {
+               /* When clearing we round the start up and the end down.
+                * This should not matter as the shift should align with
+                * the block size and no rounding should ever be needed.
+                * However it is better the think a block is bad when it
+                * isn't than to think a block is not bad when it is.
+                */
+               s += (1<<bb->shift) - 1;
+               s >>= bb->shift;
+               target >>= bb->shift;
+               sectors = target - s;
+       }
+
+       write_seqlock_irq(&bb->lock);
+
+       p = bb->page;
+       lo = 0;
+       hi = bb->count;
+       /* Find the last range that starts before 'target' */
+       while (hi - lo > 1) {
+               int mid = (lo + hi) / 2;
+               sector_t a = BB_OFFSET(p[mid]);
+               if (a < target)
+                       lo = mid;
+               else
+                       hi = mid;
+       }
+       if (hi > lo) {
+               /* p[lo] is the last range that could overlap the
+                * current range.  Earlier ranges could also overlap,
+                * but only this one can overlap the end of the range.
+                */
+               if (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) {
+                       /* Partial overlap, leave the tail of this range */
+                       int ack = BB_ACK(p[lo]);
+                       sector_t a = BB_OFFSET(p[lo]);
+                       sector_t end = a + BB_LEN(p[lo]);
+
+                       if (a < s) {
+                               /* we need to split this range */
+                               if (bb->count >= MD_MAX_BADBLOCKS) {
+                                       rv = 0;
+                                       goto out;
+                               }
+                               memmove(p+lo+1, p+lo, (bb->count - lo) * 8);
+                               bb->count++;
+                               p[lo] = BB_MAKE(a, s-a, ack);
+                               lo++;
+                       }
+                       p[lo] = BB_MAKE(target, end - target, ack);
+                       /* there is no longer an overlap */
+                       hi = lo;
+                       lo--;
+               }
+               while (lo >= 0 &&
+                      BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
+                       /* This range does overlap */
+                       if (BB_OFFSET(p[lo]) < s) {
+                               /* Keep the early parts of this range. */
+                               int ack = BB_ACK(p[lo]);
+                               sector_t start = BB_OFFSET(p[lo]);
+                               p[lo] = BB_MAKE(start, s - start, ack);
+                               /* now low doesn't overlap, so.. */
+                               break;
+                       }
+                       lo--;
+               }
+               /* 'lo' is strictly before, 'hi' is strictly after,
+                * anything between needs to be discarded
+                */
+               if (hi - lo > 1) {
+                       memmove(p+lo+1, p+hi, (bb->count - hi) * 8);
+                       bb->count -= (hi - lo - 1);
+               }
+       }
+
+       bb->changed = 1;
+out:
+       write_sequnlock_irq(&bb->lock);
+       return rv;
+}
+
+int rdev_clear_badblocks(mdk_rdev_t *rdev, sector_t s, int sectors)
+{
+       return md_clear_badblocks(&rdev->badblocks,
+                                 s + rdev->data_offset,
+                                 sectors);
+}
+EXPORT_SYMBOL_GPL(rdev_clear_badblocks);
+
+/*
+ * Acknowledge all bad blocks in a list.
+ * This only succeeds if ->changed is clear.  It is used by
+ * in-kernel metadata updates
+ */
+void md_ack_all_badblocks(struct badblocks *bb)
+{
+       if (bb->page == NULL || bb->changed)
+               /* no point even trying */
+               return;
+       write_seqlock_irq(&bb->lock);
+
+       if (bb->changed == 0) {
+               u64 *p = bb->page;
+               int i;
+               for (i = 0; i < bb->count ; i++) {
+                       if (!BB_ACK(p[i])) {
+                               sector_t start = BB_OFFSET(p[i]);
+                               int len = BB_LEN(p[i]);
+                               p[i] = BB_MAKE(start, len, 1);
+                       }
+               }
+               bb->unacked_exist = 0;
+       }
+       write_sequnlock_irq(&bb->lock);
+}
+EXPORT_SYMBOL_GPL(md_ack_all_badblocks);
+
+/* sysfs access to bad-blocks list.
+ * We present two files.
+ * 'bad-blocks' lists sector numbers and lengths of ranges that
+ *    are recorded as bad.  The list is truncated to fit within
+ *    the one-page limit of sysfs.
+ *    Writing "sector length" to this file adds an acknowledged
+ *    bad block list.
+ * 'unacknowledged-bad-blocks' lists bad blocks that have not yet
+ *    been acknowledged.  Writing to this file adds bad blocks
+ *    without acknowledging them.  This is largely for testing.
+ */
+
+static ssize_t
+badblocks_show(struct badblocks *bb, char *page, int unack)
+{
+       size_t len;
+       int i;
+       u64 *p = bb->page;
+       unsigned seq;
+
+       if (bb->shift < 0)
+               return 0;
+
+retry:
+       seq = read_seqbegin(&bb->lock);
+
+       len = 0;
+       i = 0;
+
+       while (len < PAGE_SIZE && i < bb->count) {
+               sector_t s = BB_OFFSET(p[i]);
+               unsigned int length = BB_LEN(p[i]);
+               int ack = BB_ACK(p[i]);
+               i++;
+
+               if (unack && ack)
+                       continue;
+
+               len += snprintf(page+len, PAGE_SIZE-len, "%llu %u\n",
+                               (unsigned long long)s << bb->shift,
+                               length << bb->shift);
+       }
+       if (unack && len == 0)
+               bb->unacked_exist = 0;
+
+       if (read_seqretry(&bb->lock, seq))
+               goto retry;
+
+       return len;
+}
+
+#define DO_DEBUG 1
+
+static ssize_t
+badblocks_store(struct badblocks *bb, const char *page, size_t len, int unack)
+{
+       unsigned long long sector;
+       int length;
+       char newline;
+#ifdef DO_DEBUG
+       /* Allow clearing via sysfs *only* for testing/debugging.
+        * Normally only a successful write may clear a badblock
+        */
+       int clear = 0;
+       if (page[0] == '-') {
+               clear = 1;
+               page++;
+       }
+#endif /* DO_DEBUG */
+
+       switch (sscanf(page, "%llu %d%c", &sector, &length, &newline)) {
+       case 3:
+               if (newline != '\n')
+                       return -EINVAL;
+       case 2:
+               if (length <= 0)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+#ifdef DO_DEBUG
+       if (clear) {
+               md_clear_badblocks(bb, sector, length);
+               return len;
+       }
+#endif /* DO_DEBUG */
+       if (md_set_badblocks(bb, sector, length, !unack))
+               return len;
+       else
+               return -ENOSPC;
+}
+
 static int md_notify_reboot(struct notifier_block *this,
                            unsigned long code, void *x)
 {
index 1c26c7a08ae6c053524cbee6c751c84935c5cfe3..1e586bb4452e3011a71cc59ae31e5e96ed63488e 100644 (file)
 typedef struct mddev_s mddev_t;
 typedef struct mdk_rdev_s mdk_rdev_t;
 
+/* Bad block numbers are stored sorted in a single page.
+ * 64bits is used for each block or extent.
+ * 54 bits are sector number, 9 bits are extent size,
+ * 1 bit is an 'acknowledged' flag.
+ */
+#define MD_MAX_BADBLOCKS       (PAGE_SIZE/8)
+
 /*
  * MD's 'extended' device
  */
@@ -48,7 +55,7 @@ struct mdk_rdev_s
        struct block_device *meta_bdev;
        struct block_device *bdev;      /* block device handle */
 
-       struct page     *sb_page;
+       struct page     *sb_page, *bb_page;
        int             sb_loaded;
        __u64           sb_events;
        sector_t        data_offset;    /* start of data in array */
@@ -74,9 +81,29 @@ struct mdk_rdev_s
 #define        In_sync         2               /* device is in_sync with rest of array */
 #define        WriteMostly     4               /* Avoid reading if at all possible */
 #define        AutoDetected    7               /* added by auto-detect */
-#define Blocked                8               /* An error occurred on an externally
-                                        * managed array, don't allow writes
+#define Blocked                8               /* An error occurred but has not yet
+                                        * been acknowledged by the metadata
+                                        * handler, so don't allow writes
                                         * until it is cleared */
+#define WriteErrorSeen 9               /* A write error has been seen on this
+                                        * device
+                                        */
+#define FaultRecorded  10              /* Intermediate state for clearing
+                                        * Blocked.  The Fault is/will-be
+                                        * recorded in the metadata, but that
+                                        * metadata hasn't been stored safely
+                                        * on disk yet.
+                                        */
+#define BlockedBadBlocks 11            /* A writer is blocked because they
+                                        * found an unacknowledged bad-block.
+                                        * This can safely be cleared at any
+                                        * time, and the writer will re-check.
+                                        * It may be set at any time, and at
+                                        * worst the writer will timeout and
+                                        * re-check.  So setting it as
+                                        * accurately as possible is good, but
+                                        * not absolutely critical.
+                                        */
        wait_queue_head_t blocked_wait;
 
        int desc_nr;                    /* descriptor index in the superblock */
@@ -111,8 +138,54 @@ struct mdk_rdev_s
 
        struct sysfs_dirent *sysfs_state; /* handle for 'state'
                                           * sysfs entry */
+
+       struct badblocks {
+               int     count;          /* count of bad blocks */
+               int     unacked_exist;  /* there probably are unacknowledged
+                                        * bad blocks.  This is only cleared
+                                        * when a read discovers none
+                                        */
+               int     shift;          /* shift from sectors to block size
+                                        * a -ve shift means badblocks are
+                                        * disabled.*/
+               u64     *page;          /* badblock list */
+               int     changed;
+               seqlock_t lock;
+
+               sector_t sector;
+               sector_t size;          /* in sectors */
+       } badblocks;
 };
 
+#define BB_LEN_MASK    (0x00000000000001FFULL)
+#define BB_OFFSET_MASK (0x7FFFFFFFFFFFFE00ULL)
+#define BB_ACK_MASK    (0x8000000000000000ULL)
+#define BB_MAX_LEN     512
+#define BB_OFFSET(x)   (((x) & BB_OFFSET_MASK) >> 9)
+#define BB_LEN(x)      (((x) & BB_LEN_MASK) + 1)
+#define BB_ACK(x)      (!!((x) & BB_ACK_MASK))
+#define BB_MAKE(a, l, ack) (((a)<<9) | ((l)-1) | ((u64)(!!(ack)) << 63))
+
+extern int md_is_badblock(struct badblocks *bb, sector_t s, int sectors,
+                         sector_t *first_bad, int *bad_sectors);
+static inline int is_badblock(mdk_rdev_t *rdev, sector_t s, int sectors,
+                             sector_t *first_bad, int *bad_sectors)
+{
+       if (unlikely(rdev->badblocks.count)) {
+               int rv = md_is_badblock(&rdev->badblocks, rdev->data_offset + s,
+                                       sectors,
+                                       first_bad, bad_sectors);
+               if (rv)
+                       *first_bad -= rdev->data_offset;
+               return rv;
+       }
+       return 0;
+}
+extern int rdev_set_badblocks(mdk_rdev_t *rdev, sector_t s, int sectors,
+                             int acknowledged);
+extern int rdev_clear_badblocks(mdk_rdev_t *rdev, sector_t s, int sectors);
+extern void md_ack_all_badblocks(struct badblocks *bb);
+
 struct mddev_s
 {
        void                            *private;
@@ -239,9 +312,12 @@ struct mddev_s
 #define        MD_RECOVERY_FROZEN      9
 
        unsigned long                   recovery;
-       int                             recovery_disabled; /* if we detect that recovery
-                                                           * will always fail, set this
-                                                           * so we don't loop trying */
+       /* If a RAID personality determines that recovery (of a particular
+        * device) will fail due to a read error on the source device, it
+        * takes a copy of this number and does not attempt recovery again
+        * until this number changes.
+        */
+       int                             recovery_disabled;
 
        int                             in_sync;        /* know to not need resync */
        /* 'open_mutex' avoids races between 'md_open' and 'do_md_stop', so
@@ -304,11 +380,6 @@ struct mddev_s
                                                         * hot-adding a bitmap.  It should
                                                         * eventually be settable by sysfs.
                                                         */
-               /* When md is serving under dm, it might use a
-                * dirty_log to store the bits.
-                */
-               struct dm_dirty_log *log;
-
                struct mutex            mutex;
                unsigned long           chunksize;
                unsigned long           daemon_sleep; /* how many jiffies between updates? */
@@ -413,6 +484,20 @@ static inline char * mdname (mddev_t * mddev)
        return mddev->gendisk ? mddev->gendisk->disk_name : "mdX";
 }
 
+static inline int sysfs_link_rdev(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+       char nm[20];
+       sprintf(nm, "rd%d", rdev->raid_disk);
+       return sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
+}
+
+static inline void sysfs_unlink_rdev(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+       char nm[20];
+       sprintf(nm, "rd%d", rdev->raid_disk);
+       sysfs_remove_link(&mddev->kobj, nm);
+}
+
 /*
  * iterates through some rdev ringlist. It's safe to remove the
  * current 'rdev'. Dont touch 'tmp' though.
@@ -505,7 +590,7 @@ extern void mddev_init(mddev_t *mddev);
 extern int md_run(mddev_t *mddev);
 extern void md_stop(mddev_t *mddev);
 extern void md_stop_writes(mddev_t *mddev);
-extern void md_rdev_init(mdk_rdev_t *rdev);
+extern int md_rdev_init(mdk_rdev_t *rdev);
 
 extern void mddev_suspend(mddev_t *mddev);
 extern void mddev_resume(mddev_t *mddev);
@@ -514,4 +599,5 @@ extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask,
 extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
                                   mddev_t *mddev);
 extern int mddev_check_plugged(mddev_t *mddev);
+extern void md_trim_bio(struct bio *bio, int offset, int size);
 #endif /* _MD_MD_H */
index f7431b6d8447df5979c0b80a5ded841f61a16cc1..32323f0afd8954714401cb8ed8c5b455b32a9743 100644 (file)
 #include <linux/delay.h>
 #include <linux/blkdev.h>
 #include <linux/seq_file.h>
+#include <linux/ratelimit.h>
 #include "md.h"
 #include "raid1.h"
 #include "bitmap.h"
 
 #define DEBUG 0
-#if DEBUG
-#define PRINTK(x...) printk(x)
-#else
-#define PRINTK(x...)
-#endif
+#define PRINTK(x...) do { if (DEBUG) printk(x); } while (0)
 
 /*
  * Number of guaranteed r1bios in case of extreme VM load:
@@ -166,7 +163,7 @@ static void put_all_bios(conf_t *conf, r1bio_t *r1_bio)
 
        for (i = 0; i < conf->raid_disks; i++) {
                struct bio **bio = r1_bio->bios + i;
-               if (*bio && *bio != IO_BLOCKED)
+               if (!BIO_SPECIAL(*bio))
                        bio_put(*bio);
                *bio = NULL;
        }
@@ -176,12 +173,6 @@ static void free_r1bio(r1bio_t *r1_bio)
 {
        conf_t *conf = r1_bio->mddev->private;
 
-       /*
-        * Wake up any possible resync thread that waits for the device
-        * to go idle.
-        */
-       allow_barrier(conf);
-
        put_all_bios(conf, r1_bio);
        mempool_free(r1_bio, conf->r1bio_pool);
 }
@@ -222,6 +213,33 @@ static void reschedule_retry(r1bio_t *r1_bio)
  * operation and are ready to return a success/failure code to the buffer
  * cache layer.
  */
+static void call_bio_endio(r1bio_t *r1_bio)
+{
+       struct bio *bio = r1_bio->master_bio;
+       int done;
+       conf_t *conf = r1_bio->mddev->private;
+
+       if (bio->bi_phys_segments) {
+               unsigned long flags;
+               spin_lock_irqsave(&conf->device_lock, flags);
+               bio->bi_phys_segments--;
+               done = (bio->bi_phys_segments == 0);
+               spin_unlock_irqrestore(&conf->device_lock, flags);
+       } else
+               done = 1;
+
+       if (!test_bit(R1BIO_Uptodate, &r1_bio->state))
+               clear_bit(BIO_UPTODATE, &bio->bi_flags);
+       if (done) {
+               bio_endio(bio, 0);
+               /*
+                * Wake up any possible resync thread that waits for the device
+                * to go idle.
+                */
+               allow_barrier(conf);
+       }
+}
+
 static void raid_end_bio_io(r1bio_t *r1_bio)
 {
        struct bio *bio = r1_bio->master_bio;
@@ -234,8 +252,7 @@ static void raid_end_bio_io(r1bio_t *r1_bio)
                        (unsigned long long) bio->bi_sector +
                                (bio->bi_size >> 9) - 1);
 
-               bio_endio(bio,
-                       test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO);
+               call_bio_endio(r1_bio);
        }
        free_r1bio(r1_bio);
 }
@@ -287,36 +304,52 @@ static void raid1_end_read_request(struct bio *bio, int error)
                 * oops, read error:
                 */
                char b[BDEVNAME_SIZE];
-               if (printk_ratelimit())
-                       printk(KERN_ERR "md/raid1:%s: %s: rescheduling sector %llu\n",
-                              mdname(conf->mddev),
-                              bdevname(conf->mirrors[mirror].rdev->bdev,b), (unsigned long long)r1_bio->sector);
+               printk_ratelimited(
+                       KERN_ERR "md/raid1:%s: %s: "
+                       "rescheduling sector %llu\n",
+                       mdname(conf->mddev),
+                       bdevname(conf->mirrors[mirror].rdev->bdev,
+                                b),
+                       (unsigned long long)r1_bio->sector);
+               set_bit(R1BIO_ReadError, &r1_bio->state);
                reschedule_retry(r1_bio);
        }
 
        rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
 }
 
+static void close_write(r1bio_t *r1_bio)
+{
+       /* 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 = r1_bio->behind_page_count;
+               while (i--)
+                       safe_put_page(r1_bio->behind_bvecs[i].bv_page);
+               kfree(r1_bio->behind_bvecs);
+               r1_bio->behind_bvecs = NULL;
+       }
+       /* 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),
+                       test_bit(R1BIO_BehindIO, &r1_bio->state));
+       md_write_end(r1_bio->mddev);
+}
+
 static void r1_bio_write_done(r1bio_t *r1_bio)
 {
-       if (atomic_dec_and_test(&r1_bio->remaining))
-       {
-               /* 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 = r1_bio->behind_page_count;
-                       while (i--)
-                               safe_put_page(r1_bio->behind_pages[i]);
-                       kfree(r1_bio->behind_pages);
-                       r1_bio->behind_pages = NULL;
-               }
-               /* 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),
-                               test_bit(R1BIO_BehindIO, &r1_bio->state));
-               md_write_end(r1_bio->mddev);
-               raid_end_bio_io(r1_bio);
+       if (!atomic_dec_and_test(&r1_bio->remaining))
+               return;
+
+       if (test_bit(R1BIO_WriteError, &r1_bio->state))
+               reschedule_retry(r1_bio);
+       else {
+               close_write(r1_bio);
+               if (test_bit(R1BIO_MadeGood, &r1_bio->state))
+                       reschedule_retry(r1_bio);
+               else
+                       raid_end_bio_io(r1_bio);
        }
 }
 
@@ -336,13 +369,11 @@ static void raid1_end_write_request(struct bio *bio, int error)
        /*
         * 'one mirror IO has finished' event handler:
         */
-       r1_bio->bios[mirror] = NULL;
-       to_put = bio;
        if (!uptodate) {
-               md_error(r1_bio->mddev, conf->mirrors[mirror].rdev);
-               /* an I/O failed, we can't clear the bitmap */
-               set_bit(R1BIO_Degraded, &r1_bio->state);
-       } else
+               set_bit(WriteErrorSeen,
+                       &conf->mirrors[mirror].rdev->flags);
+               set_bit(R1BIO_WriteError, &r1_bio->state);
+       } else {
                /*
                 * Set R1BIO_Uptodate in our master bio, so that we
                 * will return a good error code for to the higher
@@ -353,8 +384,22 @@ static void raid1_end_write_request(struct bio *bio, int error)
                 * to user-side. So if something waits for IO, then it
                 * will wait for the 'master' bio.
                 */
+               sector_t first_bad;
+               int bad_sectors;
+
+               r1_bio->bios[mirror] = NULL;
+               to_put = bio;
                set_bit(R1BIO_Uptodate, &r1_bio->state);
 
+               /* Maybe we can clear some bad blocks. */
+               if (is_badblock(conf->mirrors[mirror].rdev,
+                               r1_bio->sector, r1_bio->sectors,
+                               &first_bad, &bad_sectors)) {
+                       r1_bio->bios[mirror] = IO_MADE_GOOD;
+                       set_bit(R1BIO_MadeGood, &r1_bio->state);
+               }
+       }
+
        update_head_pos(mirror, r1_bio);
 
        if (behind) {
@@ -377,11 +422,13 @@ static void raid1_end_write_request(struct bio *bio, int error)
                                       (unsigned long long) mbio->bi_sector,
                                       (unsigned long long) mbio->bi_sector +
                                       (mbio->bi_size >> 9) - 1);
-                               bio_endio(mbio, 0);
+                               call_bio_endio(r1_bio);
                        }
                }
        }
-       rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
+       if (r1_bio->bios[mirror] == NULL)
+               rdev_dec_pending(conf->mirrors[mirror].rdev,
+                                conf->mddev);
 
        /*
         * Let's see if all mirrored write operations have finished
@@ -408,10 +455,11 @@ static void raid1_end_write_request(struct bio *bio, int error)
  *
  * The rdev for the device selected will have nr_pending incremented.
  */
-static int read_balance(conf_t *conf, r1bio_t *r1_bio)
+static int read_balance(conf_t *conf, r1bio_t *r1_bio, int *max_sectors)
 {
        const sector_t this_sector = r1_bio->sector;
-       const int sectors = r1_bio->sectors;
+       int sectors;
+       int best_good_sectors;
        int start_disk;
        int best_disk;
        int i;
@@ -426,8 +474,11 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
         * We take the first readable disk when above the resync window.
         */
  retry:
+       sectors = r1_bio->sectors;
        best_disk = -1;
        best_dist = MaxSector;
+       best_good_sectors = 0;
+
        if (conf->mddev->recovery_cp < MaxSector &&
            (this_sector + sectors >= conf->next_resync)) {
                choose_first = 1;
@@ -439,6 +490,9 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
 
        for (i = 0 ; i < conf->raid_disks ; i++) {
                sector_t dist;
+               sector_t first_bad;
+               int bad_sectors;
+
                int disk = start_disk + i;
                if (disk >= conf->raid_disks)
                        disk -= conf->raid_disks;
@@ -461,6 +515,35 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
                /* This is a reasonable device to use.  It might
                 * even be best.
                 */
+               if (is_badblock(rdev, this_sector, sectors,
+                               &first_bad, &bad_sectors)) {
+                       if (best_dist < MaxSector)
+                               /* already have a better device */
+                               continue;
+                       if (first_bad <= this_sector) {
+                               /* cannot read here. If this is the 'primary'
+                                * device, then we must not read beyond
+                                * bad_sectors from another device..
+                                */
+                               bad_sectors -= (this_sector - first_bad);
+                               if (choose_first && sectors > bad_sectors)
+                                       sectors = bad_sectors;
+                               if (best_good_sectors > sectors)
+                                       best_good_sectors = sectors;
+
+                       } else {
+                               sector_t good_sectors = first_bad - this_sector;
+                               if (good_sectors > best_good_sectors) {
+                                       best_good_sectors = good_sectors;
+                                       best_disk = disk;
+                               }
+                               if (choose_first)
+                                       break;
+                       }
+                       continue;
+               } else
+                       best_good_sectors = sectors;
+
                dist = abs(this_sector - conf->mirrors[disk].head_position);
                if (choose_first
                    /* Don't change to another disk for sequential reads */
@@ -489,10 +572,12 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
                        rdev_dec_pending(rdev, conf->mddev);
                        goto retry;
                }
+               sectors = best_good_sectors;
                conf->next_seq_sect = this_sector + sectors;
                conf->last_used = best_disk;
        }
        rcu_read_unlock();
+       *max_sectors = sectors;
 
        return best_disk;
 }
@@ -672,30 +757,31 @@ static void alloc_behind_pages(struct bio *bio, r1bio_t *r1_bio)
 {
        int i;
        struct bio_vec *bvec;
-       struct page **pages = kzalloc(bio->bi_vcnt * sizeof(struct page*),
+       struct bio_vec *bvecs = kzalloc(bio->bi_vcnt * sizeof(struct bio_vec),
                                        GFP_NOIO);
-       if (unlikely(!pages))
+       if (unlikely(!bvecs))
                return;
 
        bio_for_each_segment(bvec, bio, i) {
-               pages[i] = alloc_page(GFP_NOIO);
-               if (unlikely(!pages[i]))
+               bvecs[i] = *bvec;
+               bvecs[i].bv_page = alloc_page(GFP_NOIO);
+               if (unlikely(!bvecs[i].bv_page))
                        goto do_sync_io;
-               memcpy(kmap(pages[i]) + bvec->bv_offset,
-                       kmap(bvec->bv_page) + bvec->bv_offset, bvec->bv_len);
-               kunmap(pages[i]);
+               memcpy(kmap(bvecs[i].bv_page) + bvec->bv_offset,
+                      kmap(bvec->bv_page) + bvec->bv_offset, bvec->bv_len);
+               kunmap(bvecs[i].bv_page);
                kunmap(bvec->bv_page);
        }
-       r1_bio->behind_pages = pages;
+       r1_bio->behind_bvecs = bvecs;
        r1_bio->behind_page_count = bio->bi_vcnt;
        set_bit(R1BIO_BehindIO, &r1_bio->state);
        return;
 
 do_sync_io:
        for (i = 0; i < bio->bi_vcnt; i++)
-               if (pages[i])
-                       put_page(pages[i]);
-       kfree(pages);
+               if (bvecs[i].bv_page)
+                       put_page(bvecs[i].bv_page);
+       kfree(bvecs);
        PRINTK("%dB behind alloc failed, doing sync I/O\n", bio->bi_size);
 }
 
@@ -705,7 +791,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        mirror_info_t *mirror;
        r1bio_t *r1_bio;
        struct bio *read_bio;
-       int i, targets = 0, disks;
+       int i, disks;
        struct bitmap *bitmap;
        unsigned long flags;
        const int rw = bio_data_dir(bio);
@@ -713,6 +799,9 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA));
        mdk_rdev_t *blocked_rdev;
        int plugged;
+       int first_clone;
+       int sectors_handled;
+       int max_sectors;
 
        /*
         * Register the new request and wait if the reconstruction
@@ -759,11 +848,24 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        r1_bio->mddev = mddev;
        r1_bio->sector = bio->bi_sector;
 
+       /* We might need to issue multiple reads to different
+        * devices if there are bad blocks around, so we keep
+        * track of the number of reads in bio->bi_phys_segments.
+        * If this is 0, there is only one r1_bio and no locking
+        * will be needed when requests complete.  If it is
+        * non-zero, then it is the number of not-completed requests.
+        */
+       bio->bi_phys_segments = 0;
+       clear_bit(BIO_SEG_VALID, &bio->bi_flags);
+
        if (rw == READ) {
                /*
                 * read balancing logic:
                 */
-               int rdisk = read_balance(conf, r1_bio);
+               int rdisk;
+
+read_again:
+               rdisk = read_balance(conf, r1_bio, &max_sectors);
 
                if (rdisk < 0) {
                        /* couldn't find anywhere to read from */
@@ -784,6 +886,8 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                r1_bio->read_disk = rdisk;
 
                read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
+               md_trim_bio(read_bio, r1_bio->sector - bio->bi_sector,
+                           max_sectors);
 
                r1_bio->bios[rdisk] = read_bio;
 
@@ -793,16 +897,52 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                read_bio->bi_rw = READ | do_sync;
                read_bio->bi_private = r1_bio;
 
-               generic_make_request(read_bio);
+               if (max_sectors < r1_bio->sectors) {
+                       /* could not read all from this device, so we will
+                        * need another r1_bio.
+                        */
+
+                       sectors_handled = (r1_bio->sector + max_sectors
+                                          - bio->bi_sector);
+                       r1_bio->sectors = max_sectors;
+                       spin_lock_irq(&conf->device_lock);
+                       if (bio->bi_phys_segments == 0)
+                               bio->bi_phys_segments = 2;
+                       else
+                               bio->bi_phys_segments++;
+                       spin_unlock_irq(&conf->device_lock);
+                       /* Cannot call generic_make_request directly
+                        * as that will be queued in __make_request
+                        * and subsequent mempool_alloc might block waiting
+                        * for it.  So hand bio over to raid1d.
+                        */
+                       reschedule_retry(r1_bio);
+
+                       r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
+
+                       r1_bio->master_bio = bio;
+                       r1_bio->sectors = (bio->bi_size >> 9) - sectors_handled;
+                       r1_bio->state = 0;
+                       r1_bio->mddev = mddev;
+                       r1_bio->sector = bio->bi_sector + sectors_handled;
+                       goto read_again;
+               } else
+                       generic_make_request(read_bio);
                return 0;
        }
 
        /*
         * WRITE:
         */
-       /* first select target devices under spinlock and
+       /* first select target devices under rcu_lock and
         * inc refcount on their rdev.  Record them by setting
         * bios[x] to bio
+        * If there are known/acknowledged bad blocks on any device on
+        * which we have seen a write error, we want to avoid writing those
+        * blocks.
+        * This potentially requires several writes to write around
+        * the bad blocks.  Each set of writes gets it's own r1bio
+        * with a set of bios attached.
         */
        plugged = mddev_check_plugged(mddev);
 
@@ -810,6 +950,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
  retry_write:
        blocked_rdev = NULL;
        rcu_read_lock();
+       max_sectors = r1_bio->sectors;
        for (i = 0;  i < disks; i++) {
                mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
                if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
@@ -817,17 +958,56 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                        blocked_rdev = rdev;
                        break;
                }
-               if (rdev && !test_bit(Faulty, &rdev->flags)) {
-                       atomic_inc(&rdev->nr_pending);
-                       if (test_bit(Faulty, &rdev->flags)) {
+               r1_bio->bios[i] = NULL;
+               if (!rdev || test_bit(Faulty, &rdev->flags)) {
+                       set_bit(R1BIO_Degraded, &r1_bio->state);
+                       continue;
+               }
+
+               atomic_inc(&rdev->nr_pending);
+               if (test_bit(WriteErrorSeen, &rdev->flags)) {
+                       sector_t first_bad;
+                       int bad_sectors;
+                       int is_bad;
+
+                       is_bad = is_badblock(rdev, r1_bio->sector,
+                                            max_sectors,
+                                            &first_bad, &bad_sectors);
+                       if (is_bad < 0) {
+                               /* mustn't write here until the bad block is
+                                * acknowledged*/
+                               set_bit(BlockedBadBlocks, &rdev->flags);
+                               blocked_rdev = rdev;
+                               break;
+                       }
+                       if (is_bad && first_bad <= r1_bio->sector) {
+                               /* Cannot write here at all */
+                               bad_sectors -= (r1_bio->sector - first_bad);
+                               if (bad_sectors < max_sectors)
+                                       /* mustn't write more than bad_sectors
+                                        * to other devices yet
+                                        */
+                                       max_sectors = bad_sectors;
                                rdev_dec_pending(rdev, mddev);
-                               r1_bio->bios[i] = NULL;
-                       } else {
-                               r1_bio->bios[i] = bio;
-                               targets++;
+                               /* We don't set R1BIO_Degraded as that
+                                * only applies if the disk is
+                                * missing, so it might be re-added,
+                                * and we want to know to recover this
+                                * chunk.
+                                * In this case the device is here,
+                                * and the fact that this chunk is not
+                                * in-sync is recorded in the bad
+                                * block log
+                                */
+                               continue;
                        }
-               } else
-                       r1_bio->bios[i] = NULL;
+                       if (is_bad) {
+                               int good_sectors = first_bad - r1_bio->sector;
+                               if (good_sectors < max_sectors)
+                                       max_sectors = good_sectors;
+                       }
+               }
+               r1_bio->bios[i] = bio;
        }
        rcu_read_unlock();
 
@@ -838,51 +1018,57 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                for (j = 0; j < i; j++)
                        if (r1_bio->bios[j])
                                rdev_dec_pending(conf->mirrors[j].rdev, mddev);
-
+               r1_bio->state = 0;
                allow_barrier(conf);
                md_wait_for_blocked_rdev(blocked_rdev, mddev);
                wait_barrier(conf);
                goto retry_write;
        }
 
-       BUG_ON(targets == 0); /* we never fail the last device */
-
-       if (targets < conf->raid_disks) {
-               /* array is degraded, we will not clear the bitmap
-                * on I/O completion (see raid1_end_write_request) */
-               set_bit(R1BIO_Degraded, &r1_bio->state);
+       if (max_sectors < r1_bio->sectors) {
+               /* We are splitting this write into multiple parts, so
+                * we need to prepare for allocating another r1_bio.
+                */
+               r1_bio->sectors = max_sectors;
+               spin_lock_irq(&conf->device_lock);
+               if (bio->bi_phys_segments == 0)
+                       bio->bi_phys_segments = 2;
+               else
+                       bio->bi_phys_segments++;
+               spin_unlock_irq(&conf->device_lock);
        }
-
-       /* do behind I/O ?
-        * Not if there are too many, or cannot allocate memory,
-        * or a reader on WriteMostly is waiting for behind writes 
-        * to flush */
-       if (bitmap &&
-           (atomic_read(&bitmap->behind_writes)
-            < mddev->bitmap_info.max_write_behind) &&
-           !waitqueue_active(&bitmap->behind_wait))
-               alloc_behind_pages(bio, r1_bio);
+       sectors_handled = r1_bio->sector + max_sectors - bio->bi_sector;
 
        atomic_set(&r1_bio->remaining, 1);
        atomic_set(&r1_bio->behind_remaining, 0);
 
-       bitmap_startwrite(bitmap, bio->bi_sector, r1_bio->sectors,
-                               test_bit(R1BIO_BehindIO, &r1_bio->state));
+       first_clone = 1;
        for (i = 0; i < disks; i++) {
                struct bio *mbio;
                if (!r1_bio->bios[i])
                        continue;
 
                mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
-               r1_bio->bios[i] = mbio;
-
-               mbio->bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset;
-               mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
-               mbio->bi_end_io = raid1_end_write_request;
-               mbio->bi_rw = WRITE | do_flush_fua | do_sync;
-               mbio->bi_private = r1_bio;
-
-               if (r1_bio->behind_pages) {
+               md_trim_bio(mbio, r1_bio->sector - bio->bi_sector, max_sectors);
+
+               if (first_clone) {
+                       /* do behind I/O ?
+                        * Not if there are too many, or cannot
+                        * allocate memory, or a reader on WriteMostly
+                        * is waiting for behind writes to flush */
+                       if (bitmap &&
+                           (atomic_read(&bitmap->behind_writes)
+                            < mddev->bitmap_info.max_write_behind) &&
+                           !waitqueue_active(&bitmap->behind_wait))
+                               alloc_behind_pages(mbio, r1_bio);
+
+                       bitmap_startwrite(bitmap, r1_bio->sector,
+                                         r1_bio->sectors,
+                                         test_bit(R1BIO_BehindIO,
+                                                  &r1_bio->state));
+                       first_clone = 0;
+               }
+               if (r1_bio->behind_bvecs) {
                        struct bio_vec *bvec;
                        int j;
 
@@ -894,11 +1080,20 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                         * them all
                         */
                        __bio_for_each_segment(bvec, mbio, j, 0)
-                               bvec->bv_page = r1_bio->behind_pages[j];
+                               bvec->bv_page = r1_bio->behind_bvecs[j].bv_page;
                        if (test_bit(WriteMostly, &conf->mirrors[i].rdev->flags))
                                atomic_inc(&r1_bio->behind_remaining);
                }
 
+               r1_bio->bios[i] = mbio;
+
+               mbio->bi_sector = (r1_bio->sector +
+                                  conf->mirrors[i].rdev->data_offset);
+               mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
+               mbio->bi_end_io = raid1_end_write_request;
+               mbio->bi_rw = WRITE | do_flush_fua | do_sync;
+               mbio->bi_private = r1_bio;
+
                atomic_inc(&r1_bio->remaining);
                spin_lock_irqsave(&conf->device_lock, flags);
                bio_list_add(&conf->pending_bio_list, mbio);
@@ -909,6 +1104,19 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        /* In case raid1d snuck in to freeze_array */
        wake_up(&conf->wait_barrier);
 
+       if (sectors_handled < (bio->bi_size >> 9)) {
+               /* We need another r1_bio.  It has already been counted
+                * in bio->bi_phys_segments
+                */
+               r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
+               r1_bio->master_bio = bio;
+               r1_bio->sectors = (bio->bi_size >> 9) - sectors_handled;
+               r1_bio->state = 0;
+               r1_bio->mddev = mddev;
+               r1_bio->sector = bio->bi_sector + sectors_handled;
+               goto retry_write;
+       }
+
        if (do_sync || !bitmap || !plugged)
                md_wakeup_thread(mddev->thread);
 
@@ -952,9 +1160,10 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
                 * However don't try a recovery from this drive as
                 * it is very likely to fail.
                 */
-               mddev->recovery_disabled = 1;
+               conf->recovery_disabled = mddev->recovery_disabled;
                return;
        }
+       set_bit(Blocked, &rdev->flags);
        if (test_and_clear_bit(In_sync, &rdev->flags)) {
                unsigned long flags;
                spin_lock_irqsave(&conf->device_lock, flags);
@@ -1027,7 +1236,7 @@ static int raid1_spare_active(mddev_t *mddev)
                    && !test_bit(Faulty, &rdev->flags)
                    && !test_and_set_bit(In_sync, &rdev->flags)) {
                        count++;
-                       sysfs_notify_dirent(rdev->sysfs_state);
+                       sysfs_notify_dirent_safe(rdev->sysfs_state);
                }
        }
        spin_lock_irqsave(&conf->device_lock, flags);
@@ -1048,6 +1257,9 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        int first = 0;
        int last = mddev->raid_disks - 1;
 
+       if (mddev->recovery_disabled == conf->recovery_disabled)
+               return -EBUSY;
+
        if (rdev->raid_disk >= 0)
                first = last = rdev->raid_disk;
 
@@ -1103,7 +1315,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number)
                 * is not possible.
                 */
                if (!test_bit(Faulty, &rdev->flags) &&
-                   !mddev->recovery_disabled &&
+                   mddev->recovery_disabled != conf->recovery_disabled &&
                    mddev->degraded < conf->raid_disks) {
                        err = -EBUSY;
                        goto abort;
@@ -1155,6 +1367,8 @@ static void end_sync_write(struct bio *bio, int error)
        conf_t *conf = mddev->private;
        int i;
        int mirror=0;
+       sector_t first_bad;
+       int bad_sectors;
 
        for (i = 0; i < conf->raid_disks; i++)
                if (r1_bio->bios[i] == bio) {
@@ -1172,18 +1386,48 @@ static void end_sync_write(struct bio *bio, int error)
                        s += sync_blocks;
                        sectors_to_go -= sync_blocks;
                } while (sectors_to_go > 0);
-               md_error(mddev, conf->mirrors[mirror].rdev);
-       }
+               set_bit(WriteErrorSeen,
+                       &conf->mirrors[mirror].rdev->flags);
+               set_bit(R1BIO_WriteError, &r1_bio->state);
+       } else if (is_badblock(conf->mirrors[mirror].rdev,
+                              r1_bio->sector,
+                              r1_bio->sectors,
+                              &first_bad, &bad_sectors) &&
+                  !is_badblock(conf->mirrors[r1_bio->read_disk].rdev,
+                               r1_bio->sector,
+                               r1_bio->sectors,
+                               &first_bad, &bad_sectors)
+               )
+               set_bit(R1BIO_MadeGood, &r1_bio->state);
 
        update_head_pos(mirror, r1_bio);
 
        if (atomic_dec_and_test(&r1_bio->remaining)) {
-               sector_t s = r1_bio->sectors;
-               put_buf(r1_bio);
-               md_done_sync(mddev, s, uptodate);
+               int s = r1_bio->sectors;
+               if (test_bit(R1BIO_MadeGood, &r1_bio->state) ||
+                   test_bit(R1BIO_WriteError, &r1_bio->state))
+                       reschedule_retry(r1_bio);
+               else {
+                       put_buf(r1_bio);
+                       md_done_sync(mddev, s, uptodate);
+               }
        }
 }
 
+static int r1_sync_page_io(mdk_rdev_t *rdev, sector_t sector,
+                           int sectors, struct page *page, int rw)
+{
+       if (sync_page_io(rdev, sector, sectors << 9, page, rw, false))
+               /* success */
+               return 1;
+       if (rw == WRITE)
+               set_bit(WriteErrorSeen, &rdev->flags);
+       /* need to record an error - either for the block or the device */
+       if (!rdev_set_badblocks(rdev, sector, sectors, 0))
+               md_error(rdev->mddev, rdev);
+       return 0;
+}
+
 static int fix_sync_read_error(r1bio_t *r1_bio)
 {
        /* Try some synchronous reads of other devices to get
@@ -1193,6 +1437,9 @@ static int fix_sync_read_error(r1bio_t *r1_bio)
         * We don't need to freeze the array, because being in an
         * active sync request, there is no normal IO, and
         * no overlapping syncs.
+        * We don't need to check is_badblock() again as we
+        * made sure that anything with a bad block in range
+        * will have bi_end_io clear.
         */
        mddev_t *mddev = r1_bio->mddev;
        conf_t *conf = mddev->private;
@@ -1217,9 +1464,7 @@ static int fix_sync_read_error(r1bio_t *r1_bio)
                                 * active, and resync is currently active
                                 */
                                rdev = conf->mirrors[d].rdev;
-                               if (sync_page_io(rdev,
-                                                sect,
-                                                s<<9,
+                               if (sync_page_io(rdev, sect, s<<9,
                                                 bio->bi_io_vec[idx].bv_page,
                                                 READ, false)) {
                                        success = 1;
@@ -1233,16 +1478,36 @@ static int fix_sync_read_error(r1bio_t *r1_bio)
 
                if (!success) {
                        char b[BDEVNAME_SIZE];
-                       /* Cannot read from anywhere, array is toast */
-                       md_error(mddev, conf->mirrors[r1_bio->read_disk].rdev);
+                       int abort = 0;
+                       /* Cannot read from anywhere, this block is lost.
+                        * Record a bad block on each device.  If that doesn't
+                        * work just disable and interrupt the recovery.
+                        * Don't fail devices as that won't really help.
+                        */
                        printk(KERN_ALERT "md/raid1:%s: %s: unrecoverable I/O read error"
                               " for block %llu\n",
                               mdname(mddev),
                               bdevname(bio->bi_bdev, b),
                               (unsigned long long)r1_bio->sector);
-                       md_done_sync(mddev, r1_bio->sectors, 0);
-                       put_buf(r1_bio);
-                       return 0;
+                       for (d = 0; d < conf->raid_disks; d++) {
+                               rdev = conf->mirrors[d].rdev;
+                               if (!rdev || test_bit(Faulty, &rdev->flags))
+                                       continue;
+                               if (!rdev_set_badblocks(rdev, sect, s, 0))
+                                       abort = 1;
+                       }
+                       if (abort) {
+                               mddev->recovery_disabled = 1;
+                               set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+                               md_done_sync(mddev, r1_bio->sectors, 0);
+                               put_buf(r1_bio);
+                               return 0;
+                       }
+                       /* Try next page */
+                       sectors -= s;
+                       sect += s;
+                       idx++;
+                       continue;
                }
 
                start = d;
@@ -1254,16 +1519,12 @@ static int fix_sync_read_error(r1bio_t *r1_bio)
                        if (r1_bio->bios[d]->bi_end_io != end_sync_read)
                                continue;
                        rdev = conf->mirrors[d].rdev;
-                       if (sync_page_io(rdev,
-                                        sect,
-                                        s<<9,
-                                        bio->bi_io_vec[idx].bv_page,
-                                        WRITE, false) == 0) {
+                       if (r1_sync_page_io(rdev, sect, s,
+                                           bio->bi_io_vec[idx].bv_page,
+                                           WRITE) == 0) {
                                r1_bio->bios[d]->bi_end_io = NULL;
                                rdev_dec_pending(rdev, mddev);
-                               md_error(mddev, rdev);
-                       } else
-                               atomic_add(s, &rdev->corrected_errors);
+                       }
                }
                d = start;
                while (d != r1_bio->read_disk) {
@@ -1273,12 +1534,10 @@ static int fix_sync_read_error(r1bio_t *r1_bio)
                        if (r1_bio->bios[d]->bi_end_io != end_sync_read)
                                continue;
                        rdev = conf->mirrors[d].rdev;
-                       if (sync_page_io(rdev,
-                                        sect,
-                                        s<<9,
-                                        bio->bi_io_vec[idx].bv_page,
-                                        READ, false) == 0)
-                               md_error(mddev, rdev);
+                       if (r1_sync_page_io(rdev, sect, s,
+                                           bio->bi_io_vec[idx].bv_page,
+                                           READ) != 0)
+                               atomic_add(s, &rdev->corrected_errors);
                }
                sectors -= s;
                sect += s;
@@ -1420,7 +1679,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
  *
  *     1.      Retries failed read operations on working mirrors.
  *     2.      Updates the raid superblock when problems encounter.
- *     3.      Performs writes following reads for array syncronising.
+ *     3.      Performs writes following reads for array synchronising.
  */
 
 static void fix_read_error(conf_t *conf, int read_disk,
@@ -1443,9 +1702,14 @@ static void fix_read_error(conf_t *conf, int read_disk,
                         * which is the thread that might remove
                         * a device.  If raid1d ever becomes multi-threaded....
                         */
+                       sector_t first_bad;
+                       int bad_sectors;
+
                        rdev = conf->mirrors[d].rdev;
                        if (rdev &&
                            test_bit(In_sync, &rdev->flags) &&
+                           is_badblock(rdev, sect, s,
+                                       &first_bad, &bad_sectors) == 0 &&
                            sync_page_io(rdev, sect, s<<9,
                                         conf->tmppage, READ, false))
                                success = 1;
@@ -1457,8 +1721,10 @@ static void fix_read_error(conf_t *conf, int read_disk,
                } while (!success && d != read_disk);
 
                if (!success) {
-                       /* Cannot read from anywhere -- bye bye array */
-                       md_error(mddev, conf->mirrors[read_disk].rdev);
+                       /* Cannot read from anywhere - mark it bad */
+                       mdk_rdev_t *rdev = conf->mirrors[read_disk].rdev;
+                       if (!rdev_set_badblocks(rdev, sect, s, 0))
+                               md_error(mddev, rdev);
                        break;
                }
                /* write it back and re-read */
@@ -1469,13 +1735,9 @@ static void fix_read_error(conf_t *conf, int read_disk,
                        d--;
                        rdev = conf->mirrors[d].rdev;
                        if (rdev &&
-                           test_bit(In_sync, &rdev->flags)) {
-                               if (sync_page_io(rdev, sect, s<<9,
-                                                conf->tmppage, WRITE, false)
-                                   == 0)
-                                       /* Well, this device is dead */
-                                       md_error(mddev, rdev);
-                       }
+                           test_bit(In_sync, &rdev->flags))
+                               r1_sync_page_io(rdev, sect, s,
+                                               conf->tmppage, WRITE);
                }
                d = start;
                while (d != read_disk) {
@@ -1486,12 +1748,8 @@ static void fix_read_error(conf_t *conf, int read_disk,
                        rdev = conf->mirrors[d].rdev;
                        if (rdev &&
                            test_bit(In_sync, &rdev->flags)) {
-                               if (sync_page_io(rdev, sect, s<<9,
-                                                conf->tmppage, READ, false)
-                                   == 0)
-                                       /* Well, this device is dead */
-                                       md_error(mddev, rdev);
-                               else {
+                               if (r1_sync_page_io(rdev, sect, s,
+                                                   conf->tmppage, READ)) {
                                        atomic_add(s, &rdev->corrected_errors);
                                        printk(KERN_INFO
                                               "md/raid1:%s: read error corrected "
@@ -1508,21 +1766,255 @@ static void fix_read_error(conf_t *conf, int read_disk,
        }
 }
 
+static void bi_complete(struct bio *bio, int error)
+{
+       complete((struct completion *)bio->bi_private);
+}
+
+static int submit_bio_wait(int rw, struct bio *bio)
+{
+       struct completion event;
+       rw |= REQ_SYNC;
+
+       init_completion(&event);
+       bio->bi_private = &event;
+       bio->bi_end_io = bi_complete;
+       submit_bio(rw, bio);
+       wait_for_completion(&event);
+
+       return test_bit(BIO_UPTODATE, &bio->bi_flags);
+}
+
+static int narrow_write_error(r1bio_t *r1_bio, int i)
+{
+       mddev_t *mddev = r1_bio->mddev;
+       conf_t *conf = mddev->private;
+       mdk_rdev_t *rdev = conf->mirrors[i].rdev;
+       int vcnt, idx;
+       struct bio_vec *vec;
+
+       /* bio has the data to be written to device 'i' where
+        * we just recently had a write error.
+        * We repeatedly clone the bio and trim down to one block,
+        * then try the write.  Where the write fails we record
+        * a bad block.
+        * It is conceivable that the bio doesn't exactly align with
+        * blocks.  We must handle this somehow.
+        *
+        * We currently own a reference on the rdev.
+        */
+
+       int block_sectors;
+       sector_t sector;
+       int sectors;
+       int sect_to_write = r1_bio->sectors;
+       int ok = 1;
+
+       if (rdev->badblocks.shift < 0)
+               return 0;
+
+       block_sectors = 1 << rdev->badblocks.shift;
+       sector = r1_bio->sector;
+       sectors = ((sector + block_sectors)
+                  & ~(sector_t)(block_sectors - 1))
+               - sector;
+
+       if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
+               vcnt = r1_bio->behind_page_count;
+               vec = r1_bio->behind_bvecs;
+               idx = 0;
+               while (vec[idx].bv_page == NULL)
+                       idx++;
+       } else {
+               vcnt = r1_bio->master_bio->bi_vcnt;
+               vec = r1_bio->master_bio->bi_io_vec;
+               idx = r1_bio->master_bio->bi_idx;
+       }
+       while (sect_to_write) {
+               struct bio *wbio;
+               if (sectors > sect_to_write)
+                       sectors = sect_to_write;
+               /* Write at 'sector' for 'sectors'*/
+
+               wbio = bio_alloc_mddev(GFP_NOIO, vcnt, mddev);
+               memcpy(wbio->bi_io_vec, vec, vcnt * sizeof(struct bio_vec));
+               wbio->bi_sector = r1_bio->sector;
+               wbio->bi_rw = WRITE;
+               wbio->bi_vcnt = vcnt;
+               wbio->bi_size = r1_bio->sectors << 9;
+               wbio->bi_idx = idx;
+
+               md_trim_bio(wbio, sector - r1_bio->sector, sectors);
+               wbio->bi_sector += rdev->data_offset;
+               wbio->bi_bdev = rdev->bdev;
+               if (submit_bio_wait(WRITE, wbio) == 0)
+                       /* failure! */
+                       ok = rdev_set_badblocks(rdev, sector,
+                                               sectors, 0)
+                               && ok;
+
+               bio_put(wbio);
+               sect_to_write -= sectors;
+               sector += sectors;
+               sectors = block_sectors;
+       }
+       return ok;
+}
+
+static void handle_sync_write_finished(conf_t *conf, r1bio_t *r1_bio)
+{
+       int m;
+       int s = r1_bio->sectors;
+       for (m = 0; m < conf->raid_disks ; m++) {
+               mdk_rdev_t *rdev = conf->mirrors[m].rdev;
+               struct bio *bio = r1_bio->bios[m];
+               if (bio->bi_end_io == NULL)
+                       continue;
+               if (test_bit(BIO_UPTODATE, &bio->bi_flags) &&
+                   test_bit(R1BIO_MadeGood, &r1_bio->state)) {
+                       rdev_clear_badblocks(rdev, r1_bio->sector, s);
+               }
+               if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
+                   test_bit(R1BIO_WriteError, &r1_bio->state)) {
+                       if (!rdev_set_badblocks(rdev, r1_bio->sector, s, 0))
+                               md_error(conf->mddev, rdev);
+               }
+       }
+       put_buf(r1_bio);
+       md_done_sync(conf->mddev, s, 1);
+}
+
+static void handle_write_finished(conf_t *conf, r1bio_t *r1_bio)
+{
+       int m;
+       for (m = 0; m < conf->raid_disks ; m++)
+               if (r1_bio->bios[m] == IO_MADE_GOOD) {
+                       mdk_rdev_t *rdev = conf->mirrors[m].rdev;
+                       rdev_clear_badblocks(rdev,
+                                            r1_bio->sector,
+                                            r1_bio->sectors);
+                       rdev_dec_pending(rdev, conf->mddev);
+               } else if (r1_bio->bios[m] != NULL) {
+                       /* This drive got a write error.  We need to
+                        * narrow down and record precise write
+                        * errors.
+                        */
+                       if (!narrow_write_error(r1_bio, m)) {
+                               md_error(conf->mddev,
+                                        conf->mirrors[m].rdev);
+                               /* an I/O failed, we can't clear the bitmap */
+                               set_bit(R1BIO_Degraded, &r1_bio->state);
+                       }
+                       rdev_dec_pending(conf->mirrors[m].rdev,
+                                        conf->mddev);
+               }
+       if (test_bit(R1BIO_WriteError, &r1_bio->state))
+               close_write(r1_bio);
+       raid_end_bio_io(r1_bio);
+}
+
+static void handle_read_error(conf_t *conf, r1bio_t *r1_bio)
+{
+       int disk;
+       int max_sectors;
+       mddev_t *mddev = conf->mddev;
+       struct bio *bio;
+       char b[BDEVNAME_SIZE];
+       mdk_rdev_t *rdev;
+
+       clear_bit(R1BIO_ReadError, &r1_bio->state);
+       /* we got a read error. Maybe the drive is bad.  Maybe just
+        * the block and we can fix it.
+        * We freeze all other IO, and try reading the block from
+        * other devices.  When we find one, we re-write
+        * and check it that fixes the read error.
+        * This is all done synchronously while the array is
+        * frozen
+        */
+       if (mddev->ro == 0) {
+               freeze_array(conf);
+               fix_read_error(conf, r1_bio->read_disk,
+                              r1_bio->sector, r1_bio->sectors);
+               unfreeze_array(conf);
+       } else
+               md_error(mddev, conf->mirrors[r1_bio->read_disk].rdev);
+
+       bio = r1_bio->bios[r1_bio->read_disk];
+       bdevname(bio->bi_bdev, b);
+read_more:
+       disk = read_balance(conf, r1_bio, &max_sectors);
+       if (disk == -1) {
+               printk(KERN_ALERT "md/raid1:%s: %s: unrecoverable I/O"
+                      " read error for block %llu\n",
+                      mdname(mddev), b, (unsigned long long)r1_bio->sector);
+               raid_end_bio_io(r1_bio);
+       } else {
+               const unsigned long do_sync
+                       = r1_bio->master_bio->bi_rw & REQ_SYNC;
+               if (bio) {
+                       r1_bio->bios[r1_bio->read_disk] =
+                               mddev->ro ? IO_BLOCKED : NULL;
+                       bio_put(bio);
+               }
+               r1_bio->read_disk = disk;
+               bio = bio_clone_mddev(r1_bio->master_bio, GFP_NOIO, mddev);
+               md_trim_bio(bio, r1_bio->sector - bio->bi_sector, max_sectors);
+               r1_bio->bios[r1_bio->read_disk] = bio;
+               rdev = conf->mirrors[disk].rdev;
+               printk_ratelimited(KERN_ERR
+                                  "md/raid1:%s: redirecting sector %llu"
+                                  " to other mirror: %s\n",
+                                  mdname(mddev),
+                                  (unsigned long long)r1_bio->sector,
+                                  bdevname(rdev->bdev, b));
+               bio->bi_sector = r1_bio->sector + rdev->data_offset;
+               bio->bi_bdev = rdev->bdev;
+               bio->bi_end_io = raid1_end_read_request;
+               bio->bi_rw = READ | do_sync;
+               bio->bi_private = r1_bio;
+               if (max_sectors < r1_bio->sectors) {
+                       /* Drat - have to split this up more */
+                       struct bio *mbio = r1_bio->master_bio;
+                       int sectors_handled = (r1_bio->sector + max_sectors
+                                              - mbio->bi_sector);
+                       r1_bio->sectors = max_sectors;
+                       spin_lock_irq(&conf->device_lock);
+                       if (mbio->bi_phys_segments == 0)
+                               mbio->bi_phys_segments = 2;
+                       else
+                               mbio->bi_phys_segments++;
+                       spin_unlock_irq(&conf->device_lock);
+                       generic_make_request(bio);
+                       bio = NULL;
+
+                       r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
+
+                       r1_bio->master_bio = mbio;
+                       r1_bio->sectors = (mbio->bi_size >> 9)
+                                         - sectors_handled;
+                       r1_bio->state = 0;
+                       set_bit(R1BIO_ReadError, &r1_bio->state);
+                       r1_bio->mddev = mddev;
+                       r1_bio->sector = mbio->bi_sector + sectors_handled;
+
+                       goto read_more;
+               } else
+                       generic_make_request(bio);
+       }
+}
+
 static void raid1d(mddev_t *mddev)
 {
        r1bio_t *r1_bio;
-       struct bio *bio;
        unsigned long flags;
        conf_t *conf = mddev->private;
        struct list_head *head = &conf->retry_list;
-       mdk_rdev_t *rdev;
        struct blk_plug plug;
 
        md_check_recovery(mddev);
 
        blk_start_plug(&plug);
        for (;;) {
-               char b[BDEVNAME_SIZE];
 
                if (atomic_read(&mddev->plug_cnt) == 0)
                        flush_pending_writes(conf);
@@ -1539,62 +2031,26 @@ static void raid1d(mddev_t *mddev)
 
                mddev = r1_bio->mddev;
                conf = mddev->private;
-               if (test_bit(R1BIO_IsSync, &r1_bio->state))
-                       sync_request_write(mddev, r1_bio);
-               else {
-                       int disk;
-
-                       /* we got a read error. Maybe the drive is bad.  Maybe just
-                        * the block and we can fix it.
-                        * We freeze all other IO, and try reading the block from
-                        * other devices.  When we find one, we re-write
-                        * and check it that fixes the read error.
-                        * This is all done synchronously while the array is
-                        * frozen
+               if (test_bit(R1BIO_IsSync, &r1_bio->state)) {
+                       if (test_bit(R1BIO_MadeGood, &r1_bio->state) ||
+                           test_bit(R1BIO_WriteError, &r1_bio->state))
+                               handle_sync_write_finished(conf, r1_bio);
+                       else
+                               sync_request_write(mddev, r1_bio);
+               } else if (test_bit(R1BIO_MadeGood, &r1_bio->state) ||
+                          test_bit(R1BIO_WriteError, &r1_bio->state))
+                       handle_write_finished(conf, r1_bio);
+               else if (test_bit(R1BIO_ReadError, &r1_bio->state))
+                       handle_read_error(conf, r1_bio);
+               else
+                       /* just a partial read to be scheduled from separate
+                        * context
                         */
-                       if (mddev->ro == 0) {
-                               freeze_array(conf);
-                               fix_read_error(conf, r1_bio->read_disk,
-                                              r1_bio->sector,
-                                              r1_bio->sectors);
-                               unfreeze_array(conf);
-                       } else
-                               md_error(mddev,
-                                        conf->mirrors[r1_bio->read_disk].rdev);
-
-                       bio = r1_bio->bios[r1_bio->read_disk];
-                       if ((disk=read_balance(conf, r1_bio)) == -1) {
-                               printk(KERN_ALERT "md/raid1:%s: %s: unrecoverable I/O"
-                                      " read error for block %llu\n",
-                                      mdname(mddev),
-                                      bdevname(bio->bi_bdev,b),
-                                      (unsigned long long)r1_bio->sector);
-                               raid_end_bio_io(r1_bio);
-                       } else {
-                               const unsigned long do_sync = r1_bio->master_bio->bi_rw & REQ_SYNC;
-                               r1_bio->bios[r1_bio->read_disk] =
-                                       mddev->ro ? IO_BLOCKED : NULL;
-                               r1_bio->read_disk = disk;
-                               bio_put(bio);
-                               bio = bio_clone_mddev(r1_bio->master_bio,
-                                                     GFP_NOIO, mddev);
-                               r1_bio->bios[r1_bio->read_disk] = bio;
-                               rdev = conf->mirrors[disk].rdev;
-                               if (printk_ratelimit())
-                                       printk(KERN_ERR "md/raid1:%s: redirecting sector %llu to"
-                                              " other mirror: %s\n",
-                                              mdname(mddev),
-                                              (unsigned long long)r1_bio->sector,
-                                              bdevname(rdev->bdev,b));
-                               bio->bi_sector = r1_bio->sector + rdev->data_offset;
-                               bio->bi_bdev = rdev->bdev;
-                               bio->bi_end_io = raid1_end_read_request;
-                               bio->bi_rw = READ | do_sync;
-                               bio->bi_private = r1_bio;
-                               generic_make_request(bio);
-                       }
-               }
+                       generic_make_request(r1_bio->bios[r1_bio->read_disk]);
+
                cond_resched();
+               if (mddev->flags & ~(1<<MD_CHANGE_PENDING))
+                       md_check_recovery(mddev);
        }
        blk_finish_plug(&plug);
 }
@@ -1636,6 +2092,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        int write_targets = 0, read_targets = 0;
        sector_t sync_blocks;
        int still_degraded = 0;
+       int good_sectors = RESYNC_SECTORS;
+       int min_bad = 0; /* number of sectors that are bad in all devices */
 
        if (!conf->r1buf_pool)
                if (init_resync(conf))
@@ -1723,36 +2181,89 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
 
                rdev = rcu_dereference(conf->mirrors[i].rdev);
                if (rdev == NULL ||
-                          test_bit(Faulty, &rdev->flags)) {
+                   test_bit(Faulty, &rdev->flags)) {
                        still_degraded = 1;
-                       continue;
                } else if (!test_bit(In_sync, &rdev->flags)) {
                        bio->bi_rw = WRITE;
                        bio->bi_end_io = end_sync_write;
                        write_targets ++;
                } else {
                        /* may need to read from here */
-                       bio->bi_rw = READ;
-                       bio->bi_end_io = end_sync_read;
-                       if (test_bit(WriteMostly, &rdev->flags)) {
-                               if (wonly < 0)
-                                       wonly = i;
-                       } else {
-                               if (disk < 0)
-                                       disk = i;
+                       sector_t first_bad = MaxSector;
+                       int bad_sectors;
+
+                       if (is_badblock(rdev, sector_nr, good_sectors,
+                                       &first_bad, &bad_sectors)) {
+                               if (first_bad > sector_nr)
+                                       good_sectors = first_bad - sector_nr;
+                               else {
+                                       bad_sectors -= (sector_nr - first_bad);
+                                       if (min_bad == 0 ||
+                                           min_bad > bad_sectors)
+                                               min_bad = bad_sectors;
+                               }
+                       }
+                       if (sector_nr < first_bad) {
+                               if (test_bit(WriteMostly, &rdev->flags)) {
+                                       if (wonly < 0)
+                                               wonly = i;
+                               } else {
+                                       if (disk < 0)
+                                               disk = i;
+                               }
+                               bio->bi_rw = READ;
+                               bio->bi_end_io = end_sync_read;
+                               read_targets++;
                        }
-                       read_targets++;
                }
-               atomic_inc(&rdev->nr_pending);
-               bio->bi_sector = sector_nr + rdev->data_offset;
-               bio->bi_bdev = rdev->bdev;
-               bio->bi_private = r1_bio;
+               if (bio->bi_end_io) {
+                       atomic_inc(&rdev->nr_pending);
+                       bio->bi_sector = sector_nr + rdev->data_offset;
+                       bio->bi_bdev = rdev->bdev;
+                       bio->bi_private = r1_bio;
+               }
        }
        rcu_read_unlock();
        if (disk < 0)
                disk = wonly;
        r1_bio->read_disk = disk;
 
+       if (read_targets == 0 && min_bad > 0) {
+               /* These sectors are bad on all InSync devices, so we
+                * need to mark them bad on all write targets
+                */
+               int ok = 1;
+               for (i = 0 ; i < conf->raid_disks ; i++)
+                       if (r1_bio->bios[i]->bi_end_io == end_sync_write) {
+                               mdk_rdev_t *rdev =
+                                       rcu_dereference(conf->mirrors[i].rdev);
+                               ok = rdev_set_badblocks(rdev, sector_nr,
+                                                       min_bad, 0
+                                       ) && ok;
+                       }
+               set_bit(MD_CHANGE_DEVS, &mddev->flags);
+               *skipped = 1;
+               put_buf(r1_bio);
+
+               if (!ok) {
+                       /* Cannot record the badblocks, so need to
+                        * abort the resync.
+                        * If there are multiple read targets, could just
+                        * fail the really bad ones ???
+                        */
+                       conf->recovery_disabled = mddev->recovery_disabled;
+                       set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+                       return 0;
+               } else
+                       return min_bad;
+
+       }
+       if (min_bad > 0 && min_bad < good_sectors) {
+               /* only resync enough to reach the next bad->good
+                * transition */
+               good_sectors = min_bad;
+       }
+
        if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) && read_targets > 0)
                /* extra read targets are also write targets */
                write_targets += read_targets-1;
@@ -1769,6 +2280,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
 
        if (max_sector > mddev->resync_max)
                max_sector = mddev->resync_max; /* Don't do IO beyond here */
+       if (max_sector > sector_nr + good_sectors)
+               max_sector = sector_nr + good_sectors;
        nr_sectors = 0;
        sync_blocks = 0;
        do {
@@ -2154,18 +2667,13 @@ static int raid1_reshape(mddev_t *mddev)
        for (d = d2 = 0; d < conf->raid_disks; d++) {
                mdk_rdev_t *rdev = conf->mirrors[d].rdev;
                if (rdev && rdev->raid_disk != d2) {
-                       char nm[20];
-                       sprintf(nm, "rd%d", rdev->raid_disk);
-                       sysfs_remove_link(&mddev->kobj, nm);
+                       sysfs_unlink_rdev(mddev, rdev);
                        rdev->raid_disk = d2;
-                       sprintf(nm, "rd%d", rdev->raid_disk);
-                       sysfs_remove_link(&mddev->kobj, nm);
-                       if (sysfs_create_link(&mddev->kobj,
-                                             &rdev->kobj, nm))
+                       sysfs_unlink_rdev(mddev, rdev);
+                       if (sysfs_link_rdev(mddev, rdev))
                                printk(KERN_WARNING
-                                      "md/raid1:%s: cannot register "
-                                      "%s\n",
-                                      mdname(mddev), nm);
+                                      "md/raid1:%s: cannot register rd%d\n",
+                                      mdname(mddev), rdev->raid_disk);
                }
                if (rdev)
                        newmirrors[d2++].rdev = rdev;
index e743a64fac4f10f2dbc27f2c194658fdd35f3fa7..e0d676b4897498d22390600012da67e751b185ea 100644 (file)
@@ -48,6 +48,12 @@ struct r1_private_data_s {
                                            * (fresh device added).
                                            * Cleared when a sync completes.
                                            */
+       int                     recovery_disabled; /* when the same as
+                                                   * mddev->recovery_disabled
+                                                   * we don't allow recovery
+                                                   * to be attempted as we
+                                                   * expect a read error
+                                                   */
 
        wait_queue_head_t       wait_barrier;
 
@@ -95,7 +101,7 @@ struct r1bio_s {
 
        struct list_head        retry_list;
        /* Next two are only valid when R1BIO_BehindIO is set */
-       struct page             **behind_pages;
+       struct bio_vec          *behind_bvecs;
        int                     behind_page_count;
        /*
         * if the IO is in WRITE direction, then multiple bios are used.
@@ -110,13 +116,24 @@ struct r1bio_s {
  * correct the read error.  To keep track of bad blocks on a per-bio
  * level, we store IO_BLOCKED in the appropriate 'bios' pointer
  */
-#define IO_BLOCKED ((struct bio*)1)
+#define IO_BLOCKED ((struct bio *)1)
+/* When we successfully write to a known bad-block, we need to remove the
+ * bad-block marking which must be done from process context.  So we record
+ * the success by setting bios[n] to IO_MADE_GOOD
+ */
+#define IO_MADE_GOOD ((struct bio *)2)
+
+#define BIO_SPECIAL(bio) ((unsigned long)bio <= 2)
 
 /* bits for r1bio.state */
 #define        R1BIO_Uptodate  0
 #define        R1BIO_IsSync    1
 #define        R1BIO_Degraded  2
 #define        R1BIO_BehindIO  3
+/* Set ReadError on bios that experience a readerror so that
+ * raid1d knows what to do with them.
+ */
+#define R1BIO_ReadError 4
 /* For write-behind requests, we call bi_end_io when
  * the last non-write-behind device completes, providing
  * any write was successful.  Otherwise we call when
@@ -125,6 +142,11 @@ struct r1bio_s {
  * Record that bi_end_io was called with this flag...
  */
 #define        R1BIO_Returned 6
+/* If a write for this request means we can clear some
+ * known-bad-block records, we set this flag
+ */
+#define        R1BIO_MadeGood 7
+#define        R1BIO_WriteError 8
 
 extern int md_raid1_congested(mddev_t *mddev, int bits);
 
index 6e846688962fccfd9c7ceddd645192047f7d4d87..8b29cd4f01c89f8213d7dcc43cd1aaf6dd5799c7 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/blkdev.h>
 #include <linux/seq_file.h>
+#include <linux/ratelimit.h>
 #include "md.h"
 #include "raid10.h"
 #include "raid0.h"
@@ -123,7 +124,14 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
        for (j = 0 ; j < nalloc; j++) {
                bio = r10_bio->devs[j].bio;
                for (i = 0; i < RESYNC_PAGES; i++) {
-                       page = alloc_page(gfp_flags);
+                       if (j == 1 && !test_bit(MD_RECOVERY_SYNC,
+                                               &conf->mddev->recovery)) {
+                               /* we can share bv_page's during recovery */
+                               struct bio *rbio = r10_bio->devs[0].bio;
+                               page = rbio->bi_io_vec[i].bv_page;
+                               get_page(page);
+                       } else
+                               page = alloc_page(gfp_flags);
                        if (unlikely(!page))
                                goto out_free_pages;
 
@@ -173,7 +181,7 @@ static void put_all_bios(conf_t *conf, r10bio_t *r10_bio)
 
        for (i = 0; i < conf->copies; i++) {
                struct bio **bio = & r10_bio->devs[i].bio;
-               if (*bio && *bio != IO_BLOCKED)
+               if (!BIO_SPECIAL(*bio))
                        bio_put(*bio);
                *bio = NULL;
        }
@@ -183,12 +191,6 @@ static void free_r10bio(r10bio_t *r10_bio)
 {
        conf_t *conf = r10_bio->mddev->private;
 
-       /*
-        * Wake up any possible resync thread that waits for the device
-        * to go idle.
-        */
-       allow_barrier(conf);
-
        put_all_bios(conf, r10_bio);
        mempool_free(r10_bio, conf->r10bio_pool);
 }
@@ -227,9 +229,27 @@ static void reschedule_retry(r10bio_t *r10_bio)
 static void raid_end_bio_io(r10bio_t *r10_bio)
 {
        struct bio *bio = r10_bio->master_bio;
+       int done;
+       conf_t *conf = r10_bio->mddev->private;
 
-       bio_endio(bio,
-               test_bit(R10BIO_Uptodate, &r10_bio->state) ? 0 : -EIO);
+       if (bio->bi_phys_segments) {
+               unsigned long flags;
+               spin_lock_irqsave(&conf->device_lock, flags);
+               bio->bi_phys_segments--;
+               done = (bio->bi_phys_segments == 0);
+               spin_unlock_irqrestore(&conf->device_lock, flags);
+       } else
+               done = 1;
+       if (!test_bit(R10BIO_Uptodate, &r10_bio->state))
+               clear_bit(BIO_UPTODATE, &bio->bi_flags);
+       if (done) {
+               bio_endio(bio, 0);
+               /*
+                * Wake up any possible resync thread that waits for the device
+                * to go idle.
+                */
+               allow_barrier(conf);
+       }
        free_r10bio(r10_bio);
 }
 
@@ -244,6 +264,26 @@ static inline void update_head_pos(int slot, r10bio_t *r10_bio)
                r10_bio->devs[slot].addr + (r10_bio->sectors);
 }
 
+/*
+ * Find the disk number which triggered given bio
+ */
+static int find_bio_disk(conf_t *conf, r10bio_t *r10_bio,
+                        struct bio *bio, int *slotp)
+{
+       int slot;
+
+       for (slot = 0; slot < conf->copies; slot++)
+               if (r10_bio->devs[slot].bio == bio)
+                       break;
+
+       BUG_ON(slot == conf->copies);
+       update_head_pos(slot, r10_bio);
+
+       if (slotp)
+               *slotp = slot;
+       return r10_bio->devs[slot].devnum;
+}
+
 static void raid10_end_read_request(struct bio *bio, int error)
 {
        int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
@@ -277,34 +317,45 @@ static void raid10_end_read_request(struct bio *bio, int error)
                 * oops, read error - keep the refcount on the rdev
                 */
                char b[BDEVNAME_SIZE];
-               if (printk_ratelimit())
-                       printk(KERN_ERR "md/raid10:%s: %s: rescheduling sector %llu\n",
-                              mdname(conf->mddev),
-                              bdevname(conf->mirrors[dev].rdev->bdev,b), (unsigned long long)r10_bio->sector);
+               printk_ratelimited(KERN_ERR
+                                  "md/raid10:%s: %s: rescheduling sector %llu\n",
+                                  mdname(conf->mddev),
+                                  bdevname(conf->mirrors[dev].rdev->bdev, b),
+                                  (unsigned long long)r10_bio->sector);
+               set_bit(R10BIO_ReadError, &r10_bio->state);
                reschedule_retry(r10_bio);
        }
 }
 
+static void close_write(r10bio_t *r10_bio)
+{
+       /* clear the bitmap if all writes complete successfully */
+       bitmap_endwrite(r10_bio->mddev->bitmap, r10_bio->sector,
+                       r10_bio->sectors,
+                       !test_bit(R10BIO_Degraded, &r10_bio->state),
+                       0);
+       md_write_end(r10_bio->mddev);
+}
+
 static void raid10_end_write_request(struct bio *bio, int error)
 {
        int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        r10bio_t *r10_bio = bio->bi_private;
-       int slot, dev;
+       int dev;
+       int dec_rdev = 1;
        conf_t *conf = r10_bio->mddev->private;
+       int slot;
 
-       for (slot = 0; slot < conf->copies; slot++)
-               if (r10_bio->devs[slot].bio == bio)
-                       break;
-       dev = r10_bio->devs[slot].devnum;
+       dev = find_bio_disk(conf, r10_bio, bio, &slot);
 
        /*
         * this branch is our 'one mirror IO has finished' event handler:
         */
        if (!uptodate) {
-               md_error(r10_bio->mddev, conf->mirrors[dev].rdev);
-               /* an I/O failed, we can't clear the bitmap */
-               set_bit(R10BIO_Degraded, &r10_bio->state);
-       } else
+               set_bit(WriteErrorSeen, &conf->mirrors[dev].rdev->flags);
+               set_bit(R10BIO_WriteError, &r10_bio->state);
+               dec_rdev = 0;
+       } else {
                /*
                 * Set R10BIO_Uptodate in our master bio, so that
                 * we will return a good error code for to the higher
@@ -314,9 +365,22 @@ static void raid10_end_write_request(struct bio *bio, int error)
                 * user-side. So if something waits for IO, then it will
                 * wait for the 'master' bio.
                 */
+               sector_t first_bad;
+               int bad_sectors;
+
                set_bit(R10BIO_Uptodate, &r10_bio->state);
 
-       update_head_pos(slot, r10_bio);
+               /* Maybe we can clear some bad blocks. */
+               if (is_badblock(conf->mirrors[dev].rdev,
+                               r10_bio->devs[slot].addr,
+                               r10_bio->sectors,
+                               &first_bad, &bad_sectors)) {
+                       bio_put(bio);
+                       r10_bio->devs[slot].bio = IO_MADE_GOOD;
+                       dec_rdev = 0;
+                       set_bit(R10BIO_MadeGood, &r10_bio->state);
+               }
+       }
 
        /*
         *
@@ -324,16 +388,18 @@ static void raid10_end_write_request(struct bio *bio, int error)
         * already.
         */
        if (atomic_dec_and_test(&r10_bio->remaining)) {
-               /* clear the bitmap if all writes complete successfully */
-               bitmap_endwrite(r10_bio->mddev->bitmap, r10_bio->sector,
-                               r10_bio->sectors,
-                               !test_bit(R10BIO_Degraded, &r10_bio->state),
-                               0);
-               md_write_end(r10_bio->mddev);
-               raid_end_bio_io(r10_bio);
+               if (test_bit(R10BIO_WriteError, &r10_bio->state))
+                       reschedule_retry(r10_bio);
+               else {
+                       close_write(r10_bio);
+                       if (test_bit(R10BIO_MadeGood, &r10_bio->state))
+                               reschedule_retry(r10_bio);
+                       else
+                               raid_end_bio_io(r10_bio);
+               }
        }
-
-       rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
+       if (dec_rdev)
+               rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
 }
 
 
@@ -484,11 +550,12 @@ static int raid10_mergeable_bvec(struct request_queue *q,
  * FIXME: possibly should rethink readbalancing and do it differently
  * depending on near_copies / far_copies geometry.
  */
-static int read_balance(conf_t *conf, r10bio_t *r10_bio)
+static int read_balance(conf_t *conf, r10bio_t *r10_bio, int *max_sectors)
 {
        const sector_t this_sector = r10_bio->sector;
        int disk, slot;
-       const int sectors = r10_bio->sectors;
+       int sectors = r10_bio->sectors;
+       int best_good_sectors;
        sector_t new_distance, best_dist;
        mdk_rdev_t *rdev;
        int do_balance;
@@ -497,8 +564,10 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
        raid10_find_phys(conf, r10_bio);
        rcu_read_lock();
 retry:
+       sectors = r10_bio->sectors;
        best_slot = -1;
        best_dist = MaxSector;
+       best_good_sectors = 0;
        do_balance = 1;
        /*
         * Check if we can balance. We can balance on the whole
@@ -511,6 +580,10 @@ retry:
                do_balance = 0;
 
        for (slot = 0; slot < conf->copies ; slot++) {
+               sector_t first_bad;
+               int bad_sectors;
+               sector_t dev_sector;
+
                if (r10_bio->devs[slot].bio == IO_BLOCKED)
                        continue;
                disk = r10_bio->devs[slot].devnum;
@@ -520,6 +593,37 @@ retry:
                if (!test_bit(In_sync, &rdev->flags))
                        continue;
 
+               dev_sector = r10_bio->devs[slot].addr;
+               if (is_badblock(rdev, dev_sector, sectors,
+                               &first_bad, &bad_sectors)) {
+                       if (best_dist < MaxSector)
+                               /* Already have a better slot */
+                               continue;
+                       if (first_bad <= dev_sector) {
+                               /* Cannot read here.  If this is the
+                                * 'primary' device, then we must not read
+                                * beyond 'bad_sectors' from another device.
+                                */
+                               bad_sectors -= (dev_sector - first_bad);
+                               if (!do_balance && sectors > bad_sectors)
+                                       sectors = bad_sectors;
+                               if (best_good_sectors > sectors)
+                                       best_good_sectors = sectors;
+                       } else {
+                               sector_t good_sectors =
+                                       first_bad - dev_sector;
+                               if (good_sectors > best_good_sectors) {
+                                       best_good_sectors = good_sectors;
+                                       best_slot = slot;
+                               }
+                               if (!do_balance)
+                                       /* Must read from here */
+                                       break;
+                       }
+                       continue;
+               } else
+                       best_good_sectors = sectors;
+
                if (!do_balance)
                        break;
 
@@ -561,6 +665,7 @@ retry:
        } else
                disk = -1;
        rcu_read_unlock();
+       *max_sectors = best_good_sectors;
 
        return disk;
 }
@@ -734,6 +839,8 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        unsigned long flags;
        mdk_rdev_t *blocked_rdev;
        int plugged;
+       int sectors_handled;
+       int max_sectors;
 
        if (unlikely(bio->bi_rw & REQ_FLUSH)) {
                md_flush_request(mddev, bio);
@@ -808,12 +915,26 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        r10_bio->sector = bio->bi_sector;
        r10_bio->state = 0;
 
+       /* We might need to issue multiple reads to different
+        * devices if there are bad blocks around, so we keep
+        * track of the number of reads in bio->bi_phys_segments.
+        * If this is 0, there is only one r10_bio and no locking
+        * will be needed when the request completes.  If it is
+        * non-zero, then it is the number of not-completed requests.
+        */
+       bio->bi_phys_segments = 0;
+       clear_bit(BIO_SEG_VALID, &bio->bi_flags);
+
        if (rw == READ) {
                /*
                 * read balancing logic:
                 */
-               int disk = read_balance(conf, r10_bio);
-               int slot = r10_bio->read_slot;
+               int disk;
+               int slot;
+
+read_again:
+               disk = read_balance(conf, r10_bio, &max_sectors);
+               slot = r10_bio->read_slot;
                if (disk < 0) {
                        raid_end_bio_io(r10_bio);
                        return 0;
@@ -821,6 +942,8 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                mirror = conf->mirrors + disk;
 
                read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
+               md_trim_bio(read_bio, r10_bio->sector - bio->bi_sector,
+                           max_sectors);
 
                r10_bio->devs[slot].bio = read_bio;
 
@@ -831,7 +954,37 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                read_bio->bi_rw = READ | do_sync;
                read_bio->bi_private = r10_bio;
 
-               generic_make_request(read_bio);
+               if (max_sectors < r10_bio->sectors) {
+                       /* Could not read all from this device, so we will
+                        * need another r10_bio.
+                        */
+                       sectors_handled = (r10_bio->sectors + max_sectors
+                                          - bio->bi_sector);
+                       r10_bio->sectors = max_sectors;
+                       spin_lock_irq(&conf->device_lock);
+                       if (bio->bi_phys_segments == 0)
+                               bio->bi_phys_segments = 2;
+                       else
+                               bio->bi_phys_segments++;
+                       spin_unlock(&conf->device_lock);
+                       /* Cannot call generic_make_request directly
+                        * as that will be queued in __generic_make_request
+                        * and subsequent mempool_alloc might block
+                        * waiting for it.  so hand bio over to raid10d.
+                        */
+                       reschedule_retry(r10_bio);
+
+                       r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
+
+                       r10_bio->master_bio = bio;
+                       r10_bio->sectors = ((bio->bi_size >> 9)
+                                           - sectors_handled);
+                       r10_bio->state = 0;
+                       r10_bio->mddev = mddev;
+                       r10_bio->sector = bio->bi_sector + sectors_handled;
+                       goto read_again;
+               } else
+                       generic_make_request(read_bio);
                return 0;
        }
 
@@ -841,13 +994,22 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        /* first select target devices under rcu_lock and
         * inc refcount on their rdev.  Record them by setting
         * bios[x] to bio
+        * If there are known/acknowledged bad blocks on any device
+        * on which we have seen a write error, we want to avoid
+        * writing to those blocks.  This potentially requires several
+        * writes to write around the bad blocks.  Each set of writes
+        * gets its own r10_bio with a set of bios attached.  The number
+        * of r10_bios is recored in bio->bi_phys_segments just as with
+        * the read case.
         */
        plugged = mddev_check_plugged(mddev);
 
        raid10_find_phys(conf, r10_bio);
- retry_write:
+retry_write:
        blocked_rdev = NULL;
        rcu_read_lock();
+       max_sectors = r10_bio->sectors;
+
        for (i = 0;  i < conf->copies; i++) {
                int d = r10_bio->devs[i].devnum;
                mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[d].rdev);
@@ -856,13 +1018,55 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                        blocked_rdev = rdev;
                        break;
                }
-               if (rdev && !test_bit(Faulty, &rdev->flags)) {
-                       atomic_inc(&rdev->nr_pending);
-                       r10_bio->devs[i].bio = bio;
-               } else {
-                       r10_bio->devs[i].bio = NULL;
+               r10_bio->devs[i].bio = NULL;
+               if (!rdev || test_bit(Faulty, &rdev->flags)) {
                        set_bit(R10BIO_Degraded, &r10_bio->state);
+                       continue;
                }
+               if (test_bit(WriteErrorSeen, &rdev->flags)) {
+                       sector_t first_bad;
+                       sector_t dev_sector = r10_bio->devs[i].addr;
+                       int bad_sectors;
+                       int is_bad;
+
+                       is_bad = is_badblock(rdev, dev_sector,
+                                            max_sectors,
+                                            &first_bad, &bad_sectors);
+                       if (is_bad < 0) {
+                               /* Mustn't write here until the bad block
+                                * is acknowledged
+                                */
+                               atomic_inc(&rdev->nr_pending);
+                               set_bit(BlockedBadBlocks, &rdev->flags);
+                               blocked_rdev = rdev;
+                               break;
+                       }
+                       if (is_bad && first_bad <= dev_sector) {
+                               /* Cannot write here at all */
+                               bad_sectors -= (dev_sector - first_bad);
+                               if (bad_sectors < max_sectors)
+                                       /* Mustn't write more than bad_sectors
+                                        * to other devices yet
+                                        */
+                                       max_sectors = bad_sectors;
+                               /* We don't set R10BIO_Degraded as that
+                                * only applies if the disk is missing,
+                                * so it might be re-added, and we want to
+                                * know to recover this chunk.
+                                * In this case the device is here, and the
+                                * fact that this chunk is not in-sync is
+                                * recorded in the bad block log.
+                                */
+                               continue;
+                       }
+                       if (is_bad) {
+                               int good_sectors = first_bad - dev_sector;
+                               if (good_sectors < max_sectors)
+                                       max_sectors = good_sectors;
+                       }
+               }
+               r10_bio->devs[i].bio = bio;
+               atomic_inc(&rdev->nr_pending);
        }
        rcu_read_unlock();
 
@@ -882,8 +1086,22 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                goto retry_write;
        }
 
+       if (max_sectors < r10_bio->sectors) {
+               /* We are splitting this into multiple parts, so
+                * we need to prepare for allocating another r10_bio.
+                */
+               r10_bio->sectors = max_sectors;
+               spin_lock_irq(&conf->device_lock);
+               if (bio->bi_phys_segments == 0)
+                       bio->bi_phys_segments = 2;
+               else
+                       bio->bi_phys_segments++;
+               spin_unlock_irq(&conf->device_lock);
+       }
+       sectors_handled = r10_bio->sector + max_sectors - bio->bi_sector;
+
        atomic_set(&r10_bio->remaining, 1);
-       bitmap_startwrite(mddev->bitmap, bio->bi_sector, r10_bio->sectors, 0);
+       bitmap_startwrite(mddev->bitmap, r10_bio->sector, r10_bio->sectors, 0);
 
        for (i = 0; i < conf->copies; i++) {
                struct bio *mbio;
@@ -892,10 +1110,12 @@ static int make_request(mddev_t *mddev, struct bio * bio)
                        continue;
 
                mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
+               md_trim_bio(mbio, r10_bio->sector - bio->bi_sector,
+                           max_sectors);
                r10_bio->devs[i].bio = mbio;
 
-               mbio->bi_sector = r10_bio->devs[i].addr+
-                       conf->mirrors[d].rdev->data_offset;
+               mbio->bi_sector = (r10_bio->devs[i].addr+
+                                  conf->mirrors[d].rdev->data_offset);
                mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
                mbio->bi_end_io = raid10_end_write_request;
                mbio->bi_rw = WRITE | do_sync | do_fua;
@@ -920,6 +1140,21 @@ static int make_request(mddev_t *mddev, struct bio * bio)
        /* In case raid10d snuck in to freeze_array */
        wake_up(&conf->wait_barrier);
 
+       if (sectors_handled < (bio->bi_size >> 9)) {
+               /* We need another r10_bio.  It has already been counted
+                * in bio->bi_phys_segments.
+                */
+               r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
+
+               r10_bio->master_bio = bio;
+               r10_bio->sectors = (bio->bi_size >> 9) - sectors_handled;
+
+               r10_bio->mddev = mddev;
+               r10_bio->sector = bio->bi_sector + sectors_handled;
+               r10_bio->state = 0;
+               goto retry_write;
+       }
+
        if (do_sync || !mddev->bitmap || !plugged)
                md_wakeup_thread(mddev->thread);
        return 0;
@@ -949,6 +1184,30 @@ static void status(struct seq_file *seq, mddev_t *mddev)
        seq_printf(seq, "]");
 }
 
+/* check if there are enough drives for
+ * every block to appear on atleast one.
+ * Don't consider the device numbered 'ignore'
+ * as we might be about to remove it.
+ */
+static int enough(conf_t *conf, int ignore)
+{
+       int first = 0;
+
+       do {
+               int n = conf->copies;
+               int cnt = 0;
+               while (n--) {
+                       if (conf->mirrors[first].rdev &&
+                           first != ignore)
+                               cnt++;
+                       first = (first+1) % conf->raid_disks;
+               }
+               if (cnt == 0)
+                       return 0;
+       } while (first != 0);
+       return 1;
+}
+
 static void error(mddev_t *mddev, mdk_rdev_t *rdev)
 {
        char b[BDEVNAME_SIZE];
@@ -961,13 +1220,9 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
         * else mark the drive as failed
         */
        if (test_bit(In_sync, &rdev->flags)
-           && conf->raid_disks-mddev->degraded == 1)
+           && !enough(conf, rdev->raid_disk))
                /*
                 * Don't fail the drive, just return an IO error.
-                * The test should really be more sophisticated than
-                * "working_disks == 1", but it isn't critical, and
-                * can wait until we do more sophisticated "is the drive
-                * really dead" tests...
                 */
                return;
        if (test_and_clear_bit(In_sync, &rdev->flags)) {
@@ -980,6 +1235,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
                 */
                set_bit(MD_RECOVERY_INTR, &mddev->recovery);
        }
+       set_bit(Blocked, &rdev->flags);
        set_bit(Faulty, &rdev->flags);
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
        printk(KERN_ALERT
@@ -1022,27 +1278,6 @@ static void close_sync(conf_t *conf)
        conf->r10buf_pool = NULL;
 }
 
-/* check if there are enough drives for
- * every block to appear on atleast one
- */
-static int enough(conf_t *conf)
-{
-       int first = 0;
-
-       do {
-               int n = conf->copies;
-               int cnt = 0;
-               while (n--) {
-                       if (conf->mirrors[first].rdev)
-                               cnt++;
-                       first = (first+1) % conf->raid_disks;
-               }
-               if (cnt == 0)
-                       return 0;
-       } while (first != 0);
-       return 1;
-}
-
 static int raid10_spare_active(mddev_t *mddev)
 {
        int i;
@@ -1078,7 +1313,6 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        conf_t *conf = mddev->private;
        int err = -EEXIST;
        int mirror;
-       mirror_info_t *p;
        int first = 0;
        int last = conf->raid_disks - 1;
 
@@ -1087,44 +1321,47 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
                 * very different from resync
                 */
                return -EBUSY;
-       if (!enough(conf))
+       if (!enough(conf, -1))
                return -EINVAL;
 
        if (rdev->raid_disk >= 0)
                first = last = rdev->raid_disk;
 
-       if (rdev->saved_raid_disk >= 0 &&
-           rdev->saved_raid_disk >= first &&
+       if (rdev->saved_raid_disk >= first &&
            conf->mirrors[rdev->saved_raid_disk].rdev == NULL)
                mirror = rdev->saved_raid_disk;
        else
                mirror = first;
-       for ( ; mirror <= last ; mirror++)
-               if ( !(p=conf->mirrors+mirror)->rdev) {
-
-                       disk_stack_limits(mddev->gendisk, rdev->bdev,
-                                         rdev->data_offset << 9);
-                       /* as we don't honour merge_bvec_fn, we must
-                        * never risk violating it, so limit
-                        * ->max_segments to one lying with a single
-                        * page, as a one page request is never in
-                        * violation.
-                        */
-                       if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
-                               blk_queue_max_segments(mddev->queue, 1);
-                               blk_queue_segment_boundary(mddev->queue,
-                                                          PAGE_CACHE_SIZE - 1);
-                       }
+       for ( ; mirror <= last ; mirror++) {
+               mirror_info_t *p = &conf->mirrors[mirror];
+               if (p->recovery_disabled == mddev->recovery_disabled)
+                       continue;
+               if (!p->rdev)
+                       continue;
 
-                       p->head_position = 0;
-                       rdev->raid_disk = mirror;
-                       err = 0;
-                       if (rdev->saved_raid_disk != mirror)
-                               conf->fullsync = 1;
-                       rcu_assign_pointer(p->rdev, rdev);
-                       break;
+               disk_stack_limits(mddev->gendisk, rdev->bdev,
+                                 rdev->data_offset << 9);
+               /* as we don't honour merge_bvec_fn, we must
+                * never risk violating it, so limit
+                * ->max_segments to one lying with a single
+                * page, as a one page request is never in
+                * violation.
+                */
+               if (rdev->bdev->bd_disk->queue->merge_bvec_fn) {
+                       blk_queue_max_segments(mddev->queue, 1);
+                       blk_queue_segment_boundary(mddev->queue,
+                                                  PAGE_CACHE_SIZE - 1);
                }
 
+               p->head_position = 0;
+               rdev->raid_disk = mirror;
+               err = 0;
+               if (rdev->saved_raid_disk != mirror)
+                       conf->fullsync = 1;
+               rcu_assign_pointer(p->rdev, rdev);
+               break;
+       }
+
        md_integrity_add_rdev(rdev, mddev);
        print_conf(conf);
        return err;
@@ -1149,7 +1386,8 @@ static int raid10_remove_disk(mddev_t *mddev, int number)
                 * is not possible.
                 */
                if (!test_bit(Faulty, &rdev->flags) &&
-                   enough(conf)) {
+                   mddev->recovery_disabled != p->recovery_disabled &&
+                   enough(conf, -1)) {
                        err = -EBUSY;
                        goto abort;
                }
@@ -1174,24 +1412,18 @@ static void end_sync_read(struct bio *bio, int error)
 {
        r10bio_t *r10_bio = bio->bi_private;
        conf_t *conf = r10_bio->mddev->private;
-       int i,d;
+       int d;
 
-       for (i=0; i<conf->copies; i++)
-               if (r10_bio->devs[i].bio == bio)
-                       break;
-       BUG_ON(i == conf->copies);
-       update_head_pos(i, r10_bio);
-       d = r10_bio->devs[i].devnum;
+       d = find_bio_disk(conf, r10_bio, bio, NULL);
 
        if (test_bit(BIO_UPTODATE, &bio->bi_flags))
                set_bit(R10BIO_Uptodate, &r10_bio->state);
-       else {
+       else
+               /* The write handler will notice the lack of
+                * R10BIO_Uptodate and record any errors etc
+                */
                atomic_add(r10_bio->sectors,
                           &conf->mirrors[d].rdev->corrected_errors);
-               if (!test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery))
-                       md_error(r10_bio->mddev,
-                                conf->mirrors[d].rdev);
-       }
 
        /* for reconstruct, we always reschedule after a read.
         * for resync, only after all reads
@@ -1206,40 +1438,60 @@ static void end_sync_read(struct bio *bio, int error)
        }
 }
 
-static void end_sync_write(struct bio *bio, int error)
+static void end_sync_request(r10bio_t *r10_bio)
 {
-       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       r10bio_t *r10_bio = bio->bi_private;
        mddev_t *mddev = r10_bio->mddev;
-       conf_t *conf = mddev->private;
-       int i,d;
-
-       for (i = 0; i < conf->copies; i++)
-               if (r10_bio->devs[i].bio == bio)
-                       break;
-       d = r10_bio->devs[i].devnum;
 
-       if (!uptodate)
-               md_error(mddev, conf->mirrors[d].rdev);
-
-       update_head_pos(i, r10_bio);
-
-       rdev_dec_pending(conf->mirrors[d].rdev, mddev);
        while (atomic_dec_and_test(&r10_bio->remaining)) {
                if (r10_bio->master_bio == NULL) {
                        /* the primary of several recovery bios */
                        sector_t s = r10_bio->sectors;
-                       put_buf(r10_bio);
+                       if (test_bit(R10BIO_MadeGood, &r10_bio->state) ||
+                           test_bit(R10BIO_WriteError, &r10_bio->state))
+                               reschedule_retry(r10_bio);
+                       else
+                               put_buf(r10_bio);
                        md_done_sync(mddev, s, 1);
                        break;
                } else {
                        r10bio_t *r10_bio2 = (r10bio_t *)r10_bio->master_bio;
-                       put_buf(r10_bio);
+                       if (test_bit(R10BIO_MadeGood, &r10_bio->state) ||
+                           test_bit(R10BIO_WriteError, &r10_bio->state))
+                               reschedule_retry(r10_bio);
+                       else
+                               put_buf(r10_bio);
                        r10_bio = r10_bio2;
                }
        }
 }
 
+static void end_sync_write(struct bio *bio, int error)
+{
+       int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       r10bio_t *r10_bio = bio->bi_private;
+       mddev_t *mddev = r10_bio->mddev;
+       conf_t *conf = mddev->private;
+       int d;
+       sector_t first_bad;
+       int bad_sectors;
+       int slot;
+
+       d = find_bio_disk(conf, r10_bio, bio, &slot);
+
+       if (!uptodate) {
+               set_bit(WriteErrorSeen, &conf->mirrors[d].rdev->flags);
+               set_bit(R10BIO_WriteError, &r10_bio->state);
+       } else if (is_badblock(conf->mirrors[d].rdev,
+                            r10_bio->devs[slot].addr,
+                            r10_bio->sectors,
+                            &first_bad, &bad_sectors))
+               set_bit(R10BIO_MadeGood, &r10_bio->state);
+
+       rdev_dec_pending(conf->mirrors[d].rdev, mddev);
+
+       end_sync_request(r10_bio);
+}
+
 /*
  * Note: sync and recover and handled very differently for raid10
  * This code is for resync.
@@ -1299,11 +1551,12 @@ static void sync_request_write(mddev_t *mddev, r10bio_t *r10_bio)
                        if (j == vcnt)
                                continue;
                        mddev->resync_mismatches += r10_bio->sectors;
+                       if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
+                               /* Don't fix anything. */
+                               continue;
                }
-               if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
-                       /* Don't fix anything. */
-                       continue;
-               /* Ok, we need to write this bio
+               /* Ok, we need to write this bio, either to correct an
+                * inconsistency or to correct an unreadable block.
                 * First we need to fixup bv_offset, bv_len and
                 * bi_vecs, as the read request might have corrupted these
                 */
@@ -1355,32 +1608,107 @@ done:
  * The second for writing.
  *
  */
+static void fix_recovery_read_error(r10bio_t *r10_bio)
+{
+       /* We got a read error during recovery.
+        * We repeat the read in smaller page-sized sections.
+        * If a read succeeds, write it to the new device or record
+        * a bad block if we cannot.
+        * If a read fails, record a bad block on both old and
+        * new devices.
+        */
+       mddev_t *mddev = r10_bio->mddev;
+       conf_t *conf = mddev->private;
+       struct bio *bio = r10_bio->devs[0].bio;
+       sector_t sect = 0;
+       int sectors = r10_bio->sectors;
+       int idx = 0;
+       int dr = r10_bio->devs[0].devnum;
+       int dw = r10_bio->devs[1].devnum;
+
+       while (sectors) {
+               int s = sectors;
+               mdk_rdev_t *rdev;
+               sector_t addr;
+               int ok;
+
+               if (s > (PAGE_SIZE>>9))
+                       s = PAGE_SIZE >> 9;
+
+               rdev = conf->mirrors[dr].rdev;
+               addr = r10_bio->devs[0].addr + sect,
+               ok = sync_page_io(rdev,
+                                 addr,
+                                 s << 9,
+                                 bio->bi_io_vec[idx].bv_page,
+                                 READ, false);
+               if (ok) {
+                       rdev = conf->mirrors[dw].rdev;
+                       addr = r10_bio->devs[1].addr + sect;
+                       ok = sync_page_io(rdev,
+                                         addr,
+                                         s << 9,
+                                         bio->bi_io_vec[idx].bv_page,
+                                         WRITE, false);
+                       if (!ok)
+                               set_bit(WriteErrorSeen, &rdev->flags);
+               }
+               if (!ok) {
+                       /* We don't worry if we cannot set a bad block -
+                        * it really is bad so there is no loss in not
+                        * recording it yet
+                        */
+                       rdev_set_badblocks(rdev, addr, s, 0);
+
+                       if (rdev != conf->mirrors[dw].rdev) {
+                               /* need bad block on destination too */
+                               mdk_rdev_t *rdev2 = conf->mirrors[dw].rdev;
+                               addr = r10_bio->devs[1].addr + sect;
+                               ok = rdev_set_badblocks(rdev2, addr, s, 0);
+                               if (!ok) {
+                                       /* just abort the recovery */
+                                       printk(KERN_NOTICE
+                                              "md/raid10:%s: recovery aborted"
+                                              " due to read error\n",
+                                              mdname(mddev));
+
+                                       conf->mirrors[dw].recovery_disabled
+                                               = mddev->recovery_disabled;
+                                       set_bit(MD_RECOVERY_INTR,
+                                               &mddev->recovery);
+                                       break;
+                               }
+                       }
+               }
+
+               sectors -= s;
+               sect += s;
+               idx++;
+       }
+}
 
 static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio)
 {
        conf_t *conf = mddev->private;
-       int i, d;
-       struct bio *bio, *wbio;
+       int d;
+       struct bio *wbio;
 
+       if (!test_bit(R10BIO_Uptodate, &r10_bio->state)) {
+               fix_recovery_read_error(r10_bio);
+               end_sync_request(r10_bio);
+               return;
+       }
 
-       /* move the pages across to the second bio
+       /*
+        * share the pages with the first bio
         * and submit the write request
         */
-       bio = r10_bio->devs[0].bio;
        wbio = r10_bio->devs[1].bio;
-       for (i=0; i < wbio->bi_vcnt; i++) {
-               struct page *p = bio->bi_io_vec[i].bv_page;
-               bio->bi_io_vec[i].bv_page = wbio->bi_io_vec[i].bv_page;
-               wbio->bi_io_vec[i].bv_page = p;
-       }
        d = r10_bio->devs[1].devnum;
 
        atomic_inc(&conf->mirrors[d].rdev->nr_pending);
        md_sync_acct(conf->mirrors[d].rdev->bdev, wbio->bi_size >> 9);
-       if (test_bit(R10BIO_Uptodate, &r10_bio->state))
-               generic_make_request(wbio);
-       else
-               bio_endio(wbio, -EIO);
+       generic_make_request(wbio);
 }
 
 
@@ -1421,6 +1749,26 @@ static void check_decay_read_errors(mddev_t *mddev, mdk_rdev_t *rdev)
                atomic_set(&rdev->read_errors, read_errors >> hours_since_last);
 }
 
+static int r10_sync_page_io(mdk_rdev_t *rdev, sector_t sector,
+                           int sectors, struct page *page, int rw)
+{
+       sector_t first_bad;
+       int bad_sectors;
+
+       if (is_badblock(rdev, sector, sectors, &first_bad, &bad_sectors)
+           && (rw == READ || test_bit(WriteErrorSeen, &rdev->flags)))
+               return -1;
+       if (sync_page_io(rdev, sector, sectors << 9, page, rw, false))
+               /* success */
+               return 1;
+       if (rw == WRITE)
+               set_bit(WriteErrorSeen, &rdev->flags);
+       /* need to record an error - either for the block or the device */
+       if (!rdev_set_badblocks(rdev, sector, sectors, 0))
+               md_error(rdev->mddev, rdev);
+       return 0;
+}
+
 /*
  * This is a kernel thread which:
  *
@@ -1476,10 +1824,15 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
 
                rcu_read_lock();
                do {
+                       sector_t first_bad;
+                       int bad_sectors;
+
                        d = r10_bio->devs[sl].devnum;
                        rdev = rcu_dereference(conf->mirrors[d].rdev);
                        if (rdev &&
-                           test_bit(In_sync, &rdev->flags)) {
+                           test_bit(In_sync, &rdev->flags) &&
+                           is_badblock(rdev, r10_bio->devs[sl].addr + sect, s,
+                                       &first_bad, &bad_sectors) == 0) {
                                atomic_inc(&rdev->nr_pending);
                                rcu_read_unlock();
                                success = sync_page_io(rdev,
@@ -1499,9 +1852,19 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
                rcu_read_unlock();
 
                if (!success) {
-                       /* Cannot read from anywhere -- bye bye array */
+                       /* Cannot read from anywhere, just mark the block
+                        * as bad on the first device to discourage future
+                        * reads.
+                        */
                        int dn = r10_bio->devs[r10_bio->read_slot].devnum;
-                       md_error(mddev, conf->mirrors[dn].rdev);
+                       rdev = conf->mirrors[dn].rdev;
+
+                       if (!rdev_set_badblocks(
+                                   rdev,
+                                   r10_bio->devs[r10_bio->read_slot].addr
+                                   + sect,
+                                   s, 0))
+                               md_error(mddev, rdev);
                        break;
                }
 
@@ -1516,80 +1879,82 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
                        sl--;
                        d = r10_bio->devs[sl].devnum;
                        rdev = rcu_dereference(conf->mirrors[d].rdev);
-                       if (rdev &&
-                           test_bit(In_sync, &rdev->flags)) {
-                               atomic_inc(&rdev->nr_pending);
-                               rcu_read_unlock();
-                               atomic_add(s, &rdev->corrected_errors);
-                               if (sync_page_io(rdev,
-                                                r10_bio->devs[sl].addr +
-                                                sect,
-                                                s<<9, conf->tmppage, WRITE, false)
-                                   == 0) {
-                                       /* Well, this device is dead */
-                                       printk(KERN_NOTICE
-                                              "md/raid10:%s: read correction "
-                                              "write failed"
-                                              " (%d sectors at %llu on %s)\n",
-                                              mdname(mddev), s,
-                                              (unsigned long long)(
-                                                      sect + rdev->data_offset),
-                                              bdevname(rdev->bdev, b));
-                                       printk(KERN_NOTICE "md/raid10:%s: %s: failing "
-                                              "drive\n",
-                                              mdname(mddev),
-                                              bdevname(rdev->bdev, b));
-                                       md_error(mddev, rdev);
-                               }
-                               rdev_dec_pending(rdev, mddev);
-                               rcu_read_lock();
+                       if (!rdev ||
+                           !test_bit(In_sync, &rdev->flags))
+                               continue;
+
+                       atomic_inc(&rdev->nr_pending);
+                       rcu_read_unlock();
+                       if (r10_sync_page_io(rdev,
+                                            r10_bio->devs[sl].addr +
+                                            sect,
+                                            s<<9, conf->tmppage, WRITE)
+                           == 0) {
+                               /* Well, this device is dead */
+                               printk(KERN_NOTICE
+                                      "md/raid10:%s: read correction "
+                                      "write failed"
+                                      " (%d sectors at %llu on %s)\n",
+                                      mdname(mddev), s,
+                                      (unsigned long long)(
+                                              sect + rdev->data_offset),
+                                      bdevname(rdev->bdev, b));
+                               printk(KERN_NOTICE "md/raid10:%s: %s: failing "
+                                      "drive\n",
+                                      mdname(mddev),
+                                      bdevname(rdev->bdev, b));
                        }
+                       rdev_dec_pending(rdev, mddev);
+                       rcu_read_lock();
                }
                sl = start;
                while (sl != r10_bio->read_slot) {
+                       char b[BDEVNAME_SIZE];
 
                        if (sl==0)
                                sl = conf->copies;
                        sl--;
                        d = r10_bio->devs[sl].devnum;
                        rdev = rcu_dereference(conf->mirrors[d].rdev);
-                       if (rdev &&
-                           test_bit(In_sync, &rdev->flags)) {
-                               char b[BDEVNAME_SIZE];
-                               atomic_inc(&rdev->nr_pending);
-                               rcu_read_unlock();
-                               if (sync_page_io(rdev,
-                                                r10_bio->devs[sl].addr +
-                                                sect,
-                                                s<<9, conf->tmppage,
-                                                READ, false) == 0) {
-                                       /* Well, this device is dead */
-                                       printk(KERN_NOTICE
-                                              "md/raid10:%s: unable to read back "
-                                              "corrected sectors"
-                                              " (%d sectors at %llu on %s)\n",
-                                              mdname(mddev), s,
-                                              (unsigned long long)(
-                                                      sect + rdev->data_offset),
-                                              bdevname(rdev->bdev, b));
-                                       printk(KERN_NOTICE "md/raid10:%s: %s: failing drive\n",
-                                              mdname(mddev),
-                                              bdevname(rdev->bdev, b));
-
-                                       md_error(mddev, rdev);
-                               } else {
-                                       printk(KERN_INFO
-                                              "md/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));
-                               }
+                       if (!rdev ||
+                           !test_bit(In_sync, &rdev->flags))
+                               continue;
 
-                               rdev_dec_pending(rdev, mddev);
-                               rcu_read_lock();
+                       atomic_inc(&rdev->nr_pending);
+                       rcu_read_unlock();
+                       switch (r10_sync_page_io(rdev,
+                                            r10_bio->devs[sl].addr +
+                                            sect,
+                                            s<<9, conf->tmppage,
+                                                READ)) {
+                       case 0:
+                               /* Well, this device is dead */
+                               printk(KERN_NOTICE
+                                      "md/raid10:%s: unable to read back "
+                                      "corrected sectors"
+                                      " (%d sectors at %llu on %s)\n",
+                                      mdname(mddev), s,
+                                      (unsigned long long)(
+                                              sect + rdev->data_offset),
+                                      bdevname(rdev->bdev, b));
+                               printk(KERN_NOTICE "md/raid10:%s: %s: failing "
+                                      "drive\n",
+                                      mdname(mddev),
+                                      bdevname(rdev->bdev, b));
+                               break;
+                       case 1:
+                               printk(KERN_INFO
+                                      "md/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));
+                               atomic_add(s, &rdev->corrected_errors);
                        }
+
+                       rdev_dec_pending(rdev, mddev);
+                       rcu_read_lock();
                }
                rcu_read_unlock();
 
@@ -1598,21 +1963,254 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
        }
 }
 
+static void bi_complete(struct bio *bio, int error)
+{
+       complete((struct completion *)bio->bi_private);
+}
+
+static int submit_bio_wait(int rw, struct bio *bio)
+{
+       struct completion event;
+       rw |= REQ_SYNC;
+
+       init_completion(&event);
+       bio->bi_private = &event;
+       bio->bi_end_io = bi_complete;
+       submit_bio(rw, bio);
+       wait_for_completion(&event);
+
+       return test_bit(BIO_UPTODATE, &bio->bi_flags);
+}
+
+static int narrow_write_error(r10bio_t *r10_bio, int i)
+{
+       struct bio *bio = r10_bio->master_bio;
+       mddev_t *mddev = r10_bio->mddev;
+       conf_t *conf = mddev->private;
+       mdk_rdev_t *rdev = conf->mirrors[r10_bio->devs[i].devnum].rdev;
+       /* bio has the data to be written to slot 'i' where
+        * we just recently had a write error.
+        * We repeatedly clone the bio and trim down to one block,
+        * then try the write.  Where the write fails we record
+        * a bad block.
+        * It is conceivable that the bio doesn't exactly align with
+        * blocks.  We must handle this.
+        *
+        * We currently own a reference to the rdev.
+        */
+
+       int block_sectors;
+       sector_t sector;
+       int sectors;
+       int sect_to_write = r10_bio->sectors;
+       int ok = 1;
+
+       if (rdev->badblocks.shift < 0)
+               return 0;
+
+       block_sectors = 1 << rdev->badblocks.shift;
+       sector = r10_bio->sector;
+       sectors = ((r10_bio->sector + block_sectors)
+                  & ~(sector_t)(block_sectors - 1))
+               - sector;
+
+       while (sect_to_write) {
+               struct bio *wbio;
+               if (sectors > sect_to_write)
+                       sectors = sect_to_write;
+               /* Write at 'sector' for 'sectors' */
+               wbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
+               md_trim_bio(wbio, sector - bio->bi_sector, sectors);
+               wbio->bi_sector = (r10_bio->devs[i].addr+
+                                  rdev->data_offset+
+                                  (sector - r10_bio->sector));
+               wbio->bi_bdev = rdev->bdev;
+               if (submit_bio_wait(WRITE, wbio) == 0)
+                       /* Failure! */
+                       ok = rdev_set_badblocks(rdev, sector,
+                                               sectors, 0)
+                               && ok;
+
+               bio_put(wbio);
+               sect_to_write -= sectors;
+               sector += sectors;
+               sectors = block_sectors;
+       }
+       return ok;
+}
+
+static void handle_read_error(mddev_t *mddev, r10bio_t *r10_bio)
+{
+       int slot = r10_bio->read_slot;
+       int mirror = r10_bio->devs[slot].devnum;
+       struct bio *bio;
+       conf_t *conf = mddev->private;
+       mdk_rdev_t *rdev;
+       char b[BDEVNAME_SIZE];
+       unsigned long do_sync;
+       int max_sectors;
+
+       /* we got a read error. Maybe the drive is bad.  Maybe just
+        * the block and we can fix it.
+        * We freeze all other IO, and try reading the block from
+        * other devices.  When we find one, we re-write
+        * and check it that fixes the read error.
+        * This is all done synchronously while the array is
+        * frozen.
+        */
+       if (mddev->ro == 0) {
+               freeze_array(conf);
+               fix_read_error(conf, mddev, r10_bio);
+               unfreeze_array(conf);
+       }
+       rdev_dec_pending(conf->mirrors[mirror].rdev, mddev);
+
+       bio = r10_bio->devs[slot].bio;
+       bdevname(bio->bi_bdev, b);
+       r10_bio->devs[slot].bio =
+               mddev->ro ? IO_BLOCKED : NULL;
+read_more:
+       mirror = read_balance(conf, r10_bio, &max_sectors);
+       if (mirror == -1) {
+               printk(KERN_ALERT "md/raid10:%s: %s: unrecoverable I/O"
+                      " read error for block %llu\n",
+                      mdname(mddev), b,
+                      (unsigned long long)r10_bio->sector);
+               raid_end_bio_io(r10_bio);
+               bio_put(bio);
+               return;
+       }
+
+       do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC);
+       if (bio)
+               bio_put(bio);
+       slot = r10_bio->read_slot;
+       rdev = conf->mirrors[mirror].rdev;
+       printk_ratelimited(
+               KERN_ERR
+               "md/raid10:%s: %s: redirecting"
+               "sector %llu to another mirror\n",
+               mdname(mddev),
+               bdevname(rdev->bdev, b),
+               (unsigned long long)r10_bio->sector);
+       bio = bio_clone_mddev(r10_bio->master_bio,
+                             GFP_NOIO, mddev);
+       md_trim_bio(bio,
+                   r10_bio->sector - bio->bi_sector,
+                   max_sectors);
+       r10_bio->devs[slot].bio = bio;
+       bio->bi_sector = r10_bio->devs[slot].addr
+               + rdev->data_offset;
+       bio->bi_bdev = rdev->bdev;
+       bio->bi_rw = READ | do_sync;
+       bio->bi_private = r10_bio;
+       bio->bi_end_io = raid10_end_read_request;
+       if (max_sectors < r10_bio->sectors) {
+               /* Drat - have to split this up more */
+               struct bio *mbio = r10_bio->master_bio;
+               int sectors_handled =
+                       r10_bio->sector + max_sectors
+                       - mbio->bi_sector;
+               r10_bio->sectors = max_sectors;
+               spin_lock_irq(&conf->device_lock);
+               if (mbio->bi_phys_segments == 0)
+                       mbio->bi_phys_segments = 2;
+               else
+                       mbio->bi_phys_segments++;
+               spin_unlock_irq(&conf->device_lock);
+               generic_make_request(bio);
+               bio = NULL;
+
+               r10_bio = mempool_alloc(conf->r10bio_pool,
+                                       GFP_NOIO);
+               r10_bio->master_bio = mbio;
+               r10_bio->sectors = (mbio->bi_size >> 9)
+                       - sectors_handled;
+               r10_bio->state = 0;
+               set_bit(R10BIO_ReadError,
+                       &r10_bio->state);
+               r10_bio->mddev = mddev;
+               r10_bio->sector = mbio->bi_sector
+                       + sectors_handled;
+
+               goto read_more;
+       } else
+               generic_make_request(bio);
+}
+
+static void handle_write_completed(conf_t *conf, r10bio_t *r10_bio)
+{
+       /* Some sort of write request has finished and it
+        * succeeded in writing where we thought there was a
+        * bad block.  So forget the bad block.
+        * Or possibly if failed and we need to record
+        * a bad block.
+        */
+       int m;
+       mdk_rdev_t *rdev;
+
+       if (test_bit(R10BIO_IsSync, &r10_bio->state) ||
+           test_bit(R10BIO_IsRecover, &r10_bio->state)) {
+               for (m = 0; m < conf->copies; m++) {
+                       int dev = r10_bio->devs[m].devnum;
+                       rdev = conf->mirrors[dev].rdev;
+                       if (r10_bio->devs[m].bio == NULL)
+                               continue;
+                       if (test_bit(BIO_UPTODATE,
+                                    &r10_bio->devs[m].bio->bi_flags)) {
+                               rdev_clear_badblocks(
+                                       rdev,
+                                       r10_bio->devs[m].addr,
+                                       r10_bio->sectors);
+                       } else {
+                               if (!rdev_set_badblocks(
+                                           rdev,
+                                           r10_bio->devs[m].addr,
+                                           r10_bio->sectors, 0))
+                                       md_error(conf->mddev, rdev);
+                       }
+               }
+               put_buf(r10_bio);
+       } else {
+               for (m = 0; m < conf->copies; m++) {
+                       int dev = r10_bio->devs[m].devnum;
+                       struct bio *bio = r10_bio->devs[m].bio;
+                       rdev = conf->mirrors[dev].rdev;
+                       if (bio == IO_MADE_GOOD) {
+                               rdev_clear_badblocks(
+                                       rdev,
+                                       r10_bio->devs[m].addr,
+                                       r10_bio->sectors);
+                               rdev_dec_pending(rdev, conf->mddev);
+                       } else if (bio != NULL &&
+                                  !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+                               if (!narrow_write_error(r10_bio, m)) {
+                                       md_error(conf->mddev, rdev);
+                                       set_bit(R10BIO_Degraded,
+                                               &r10_bio->state);
+                               }
+                               rdev_dec_pending(rdev, conf->mddev);
+                       }
+               }
+               if (test_bit(R10BIO_WriteError,
+                            &r10_bio->state))
+                       close_write(r10_bio);
+               raid_end_bio_io(r10_bio);
+       }
+}
+
 static void raid10d(mddev_t *mddev)
 {
        r10bio_t *r10_bio;
-       struct bio *bio;
        unsigned long flags;
        conf_t *conf = mddev->private;
        struct list_head *head = &conf->retry_list;
-       mdk_rdev_t *rdev;
        struct blk_plug plug;
 
        md_check_recovery(mddev);
 
        blk_start_plug(&plug);
        for (;;) {
-               char b[BDEVNAME_SIZE];
 
                flush_pending_writes(conf);
 
@@ -1628,64 +2226,26 @@ static void raid10d(mddev_t *mddev)
 
                mddev = r10_bio->mddev;
                conf = mddev->private;
-               if (test_bit(R10BIO_IsSync, &r10_bio->state))
+               if (test_bit(R10BIO_MadeGood, &r10_bio->state) ||
+                   test_bit(R10BIO_WriteError, &r10_bio->state))
+                       handle_write_completed(conf, r10_bio);
+               else if (test_bit(R10BIO_IsSync, &r10_bio->state))
                        sync_request_write(mddev, r10_bio);
                else if (test_bit(R10BIO_IsRecover, &r10_bio->state))
                        recovery_request_write(mddev, r10_bio);
+               else if (test_bit(R10BIO_ReadError, &r10_bio->state))
+                       handle_read_error(mddev, r10_bio);
                else {
-                       int slot = r10_bio->read_slot;
-                       int mirror = r10_bio->devs[slot].devnum;
-                       /* we got a read error. Maybe the drive is bad.  Maybe just
-                        * the block and we can fix it.
-                        * We freeze all other IO, and try reading the block from
-                        * other devices.  When we find one, we re-write
-                        * and check it that fixes the read error.
-                        * This is all done synchronously while the array is
-                        * frozen.
+                       /* just a partial read to be scheduled from a
+                        * separate context
                         */
-                       if (mddev->ro == 0) {
-                               freeze_array(conf);
-                               fix_read_error(conf, mddev, r10_bio);
-                               unfreeze_array(conf);
-                       }
-                       rdev_dec_pending(conf->mirrors[mirror].rdev, mddev);
-
-                       bio = r10_bio->devs[slot].bio;
-                       r10_bio->devs[slot].bio =
-                               mddev->ro ? IO_BLOCKED : NULL;
-                       mirror = read_balance(conf, r10_bio);
-                       if (mirror == -1) {
-                               printk(KERN_ALERT "md/raid10:%s: %s: unrecoverable I/O"
-                                      " read error for block %llu\n",
-                                      mdname(mddev),
-                                      bdevname(bio->bi_bdev,b),
-                                      (unsigned long long)r10_bio->sector);
-                               raid_end_bio_io(r10_bio);
-                               bio_put(bio);
-                       } else {
-                               const unsigned long do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC);
-                               bio_put(bio);
-                               slot = r10_bio->read_slot;
-                               rdev = conf->mirrors[mirror].rdev;
-                               if (printk_ratelimit())
-                                       printk(KERN_ERR "md/raid10:%s: %s: redirecting sector %llu to"
-                                              " another mirror\n",
-                                              mdname(mddev),
-                                              bdevname(rdev->bdev,b),
-                                              (unsigned long long)r10_bio->sector);
-                               bio = bio_clone_mddev(r10_bio->master_bio,
-                                                     GFP_NOIO, mddev);
-                               r10_bio->devs[slot].bio = bio;
-                               bio->bi_sector = r10_bio->devs[slot].addr
-                                       + rdev->data_offset;
-                               bio->bi_bdev = rdev->bdev;
-                               bio->bi_rw = READ | do_sync;
-                               bio->bi_private = r10_bio;
-                               bio->bi_end_io = raid10_end_read_request;
-                               generic_make_request(bio);
-                       }
+                       int slot = r10_bio->read_slot;
+                       generic_make_request(r10_bio->devs[slot].bio);
                }
+
                cond_resched();
+               if (mddev->flags & ~(1<<MD_CHANGE_PENDING))
+                       md_check_recovery(mddev);
        }
        blk_finish_plug(&plug);
 }
@@ -1746,7 +2306,6 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
        int i;
        int max_sync;
        sector_t sync_blocks;
-
        sector_t sectors_skipped = 0;
        int chunks_skipped = 0;
 
@@ -1828,7 +2387,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
        max_sync = RESYNC_PAGES << (PAGE_SHIFT-9);
        if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
                /* recovery... the complicated one */
-               int j, k;
+               int j;
                r10_bio = NULL;
 
                for (i=0 ; i<conf->raid_disks; i++) {
@@ -1836,6 +2395,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
                        r10bio_t *rb2;
                        sector_t sect;
                        int must_sync;
+                       int any_working;
 
                        if (conf->mirrors[i].rdev == NULL ||
                            test_bit(In_sync, &conf->mirrors[i].rdev->flags)) 
@@ -1887,19 +2447,42 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
                        must_sync = bitmap_start_sync(mddev->bitmap, sect,
                                                      &sync_blocks, still_degraded);
 
+                       any_working = 0;
                        for (j=0; j<conf->copies;j++) {
+                               int k;
                                int d = r10_bio->devs[j].devnum;
+                               sector_t from_addr, to_addr;
+                               mdk_rdev_t *rdev;
+                               sector_t sector, first_bad;
+                               int bad_sectors;
                                if (!conf->mirrors[d].rdev ||
                                    !test_bit(In_sync, &conf->mirrors[d].rdev->flags))
                                        continue;
                                /* This is where we read from */
+                               any_working = 1;
+                               rdev = conf->mirrors[d].rdev;
+                               sector = r10_bio->devs[j].addr;
+
+                               if (is_badblock(rdev, sector, max_sync,
+                                               &first_bad, &bad_sectors)) {
+                                       if (first_bad > sector)
+                                               max_sync = first_bad - sector;
+                                       else {
+                                               bad_sectors -= (sector
+                                                               - first_bad);
+                                               if (max_sync > bad_sectors)
+                                                       max_sync = bad_sectors;
+                                               continue;
+                                       }
+                               }
                                bio = r10_bio->devs[0].bio;
                                bio->bi_next = biolist;
                                biolist = bio;
                                bio->bi_private = r10_bio;
                                bio->bi_end_io = end_sync_read;
                                bio->bi_rw = READ;
-                               bio->bi_sector = r10_bio->devs[j].addr +
+                               from_addr = r10_bio->devs[j].addr;
+                               bio->bi_sector = from_addr +
                                        conf->mirrors[d].rdev->data_offset;
                                bio->bi_bdev = conf->mirrors[d].rdev->bdev;
                                atomic_inc(&conf->mirrors[d].rdev->nr_pending);
@@ -1916,26 +2499,48 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
                                bio->bi_private = r10_bio;
                                bio->bi_end_io = end_sync_write;
                                bio->bi_rw = WRITE;
-                               bio->bi_sector = r10_bio->devs[k].addr +
+                               to_addr = r10_bio->devs[k].addr;
+                               bio->bi_sector = to_addr +
                                        conf->mirrors[i].rdev->data_offset;
                                bio->bi_bdev = conf->mirrors[i].rdev->bdev;
 
                                r10_bio->devs[0].devnum = d;
+                               r10_bio->devs[0].addr = from_addr;
                                r10_bio->devs[1].devnum = i;
+                               r10_bio->devs[1].addr = to_addr;
 
                                break;
                        }
                        if (j == conf->copies) {
-                               /* Cannot recover, so abort the recovery */
+                               /* Cannot recover, so abort the recovery or
+                                * record a bad block */
                                put_buf(r10_bio);
                                if (rb2)
                                        atomic_dec(&rb2->remaining);
                                r10_bio = rb2;
-                               if (!test_and_set_bit(MD_RECOVERY_INTR,
-                                                     &mddev->recovery))
-                                       printk(KERN_INFO "md/raid10:%s: insufficient "
-                                              "working devices for recovery.\n",
-                                              mdname(mddev));
+                               if (any_working) {
+                                       /* problem is that there are bad blocks
+                                        * on other device(s)
+                                        */
+                                       int k;
+                                       for (k = 0; k < conf->copies; k++)
+                                               if (r10_bio->devs[k].devnum == i)
+                                                       break;
+                                       if (!rdev_set_badblocks(
+                                                   conf->mirrors[i].rdev,
+                                                   r10_bio->devs[k].addr,
+                                                   max_sync, 0))
+                                               any_working = 0;
+                               }
+                               if (!any_working)  {
+                                       if (!test_and_set_bit(MD_RECOVERY_INTR,
+                                                             &mddev->recovery))
+                                               printk(KERN_INFO "md/raid10:%s: insufficient "
+                                                      "working devices for recovery.\n",
+                                                      mdname(mddev));
+                                       conf->mirrors[i].recovery_disabled
+                                               = mddev->recovery_disabled;
+                               }
                                break;
                        }
                }
@@ -1979,12 +2584,28 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
 
                for (i=0; i<conf->copies; i++) {
                        int d = r10_bio->devs[i].devnum;
+                       sector_t first_bad, sector;
+                       int bad_sectors;
+
                        bio = r10_bio->devs[i].bio;
                        bio->bi_end_io = NULL;
                        clear_bit(BIO_UPTODATE, &bio->bi_flags);
                        if (conf->mirrors[d].rdev == NULL ||
                            test_bit(Faulty, &conf->mirrors[d].rdev->flags))
                                continue;
+                       sector = r10_bio->devs[i].addr;
+                       if (is_badblock(conf->mirrors[d].rdev,
+                                       sector, max_sync,
+                                       &first_bad, &bad_sectors)) {
+                               if (first_bad > sector)
+                                       max_sync = first_bad - sector;
+                               else {
+                                       bad_sectors -= (sector - first_bad);
+                                       if (max_sync > bad_sectors)
+                                               max_sync = max_sync;
+                                       continue;
+                               }
+                       }
                        atomic_inc(&conf->mirrors[d].rdev->nr_pending);
                        atomic_inc(&r10_bio->remaining);
                        bio->bi_next = biolist;
@@ -1992,7 +2613,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
                        bio->bi_private = r10_bio;
                        bio->bi_end_io = end_sync_read;
                        bio->bi_rw = READ;
-                       bio->bi_sector = r10_bio->devs[i].addr +
+                       bio->bi_sector = sector +
                                conf->mirrors[d].rdev->data_offset;
                        bio->bi_bdev = conf->mirrors[d].rdev->bdev;
                        count++;
@@ -2079,7 +2700,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
        return sectors_skipped + nr_sectors;
  giveup:
        /* There is nowhere to write, so all non-sync
-        * drives must be failed, so try the next chunk...
+        * drives must be failed or in resync, all drives
+        * have a bad block, so try the next chunk...
         */
        if (sector_nr + max_sync < max_sector)
                max_sector = sector_nr + max_sync;
@@ -2249,6 +2871,7 @@ static int run(mddev_t *mddev)
                                 (conf->raid_disks / conf->near_copies));
 
        list_for_each_entry(rdev, &mddev->disks, same_set) {
+
                disk_idx = rdev->raid_disk;
                if (disk_idx >= conf->raid_disks
                    || disk_idx < 0)
@@ -2271,7 +2894,7 @@ static int run(mddev_t *mddev)
                disk->head_position = 0;
        }
        /* need to check that every block has at least one working mirror */
-       if (!enough(conf)) {
+       if (!enough(conf, -1)) {
                printk(KERN_ERR "md/raid10:%s: not enough operational mirrors.\n",
                       mdname(mddev));
                goto out_free_conf;
index 944b1104d3b447c4437e847ad9e268e5c3fb0715..79cb52a0d4a223189924ecb4ed20aa4005316772 100644 (file)
@@ -6,6 +6,11 @@ typedef struct mirror_info mirror_info_t;
 struct mirror_info {
        mdk_rdev_t      *rdev;
        sector_t        head_position;
+       int             recovery_disabled;      /* matches
+                                                * mddev->recovery_disabled
+                                                * when we shouldn't try
+                                                * recovering this device.
+                                                */
 };
 
 typedef struct r10bio_s r10bio_t;
@@ -113,10 +118,26 @@ struct r10bio_s {
  * level, we store IO_BLOCKED in the appropriate 'bios' pointer
  */
 #define IO_BLOCKED ((struct bio*)1)
+/* When we successfully write to a known bad-block, we need to remove the
+ * bad-block marking which must be done from process context.  So we record
+ * the success by setting devs[n].bio to IO_MADE_GOOD
+ */
+#define IO_MADE_GOOD ((struct bio *)2)
+
+#define BIO_SPECIAL(bio) ((unsigned long)bio <= 2)
 
 /* bits for r10bio.state */
 #define        R10BIO_Uptodate 0
 #define        R10BIO_IsSync   1
 #define        R10BIO_IsRecover 2
 #define        R10BIO_Degraded 3
+/* Set ReadError on bios that experience a read error
+ * so that raid10d knows what to do with them.
+ */
+#define        R10BIO_ReadError 4
+/* If a write for this request means we can clear some
+ * known-bad-block records, we set this flag.
+ */
+#define        R10BIO_MadeGood 5
+#define        R10BIO_WriteError 6
 #endif
index b72edf35ec544d0da66346107cededa933ed20dc..dbae459fb02d7171291e1d8dcc3d7fa538ab02f4 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/seq_file.h>
 #include <linux/cpu.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #include "md.h"
 #include "raid5.h"
 #include "raid0.h"
@@ -96,8 +97,6 @@
 #define __inline__
 #endif
 
-#define printk_rl(args...) ((void) (printk_ratelimit() && printk(args)))
-
 /*
  * We maintain a biased count of active stripes in the bottom 16 bits of
  * bi_phys_segments, and a count of processed stripes in the upper 16 bits
@@ -341,7 +340,7 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int previous)
                               (unsigned long long)sh->sector, i, dev->toread,
                               dev->read, dev->towrite, dev->written,
                               test_bit(R5_LOCKED, &dev->flags));
-                       BUG();
+                       WARN_ON(1);
                }
                dev->flags = 0;
                raid5_build_block(sh, i, previous);
@@ -527,6 +526,36 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                        atomic_inc(&rdev->nr_pending);
                rcu_read_unlock();
 
+               /* We have already checked bad blocks for reads.  Now
+                * need to check for writes.
+                */
+               while ((rw & WRITE) && rdev &&
+                      test_bit(WriteErrorSeen, &rdev->flags)) {
+                       sector_t first_bad;
+                       int bad_sectors;
+                       int bad = is_badblock(rdev, sh->sector, STRIPE_SECTORS,
+                                             &first_bad, &bad_sectors);
+                       if (!bad)
+                               break;
+
+                       if (bad < 0) {
+                               set_bit(BlockedBadBlocks, &rdev->flags);
+                               if (!conf->mddev->external &&
+                                   conf->mddev->flags) {
+                                       /* It is very unlikely, but we might
+                                        * still need to write out the
+                                        * bad block log - better give it
+                                        * a chance*/
+                                       md_check_recovery(conf->mddev);
+                               }
+                               md_wait_for_blocked_rdev(rdev, conf->mddev);
+                       } else {
+                               /* Acknowledged bad block - skip the write */
+                               rdev_dec_pending(rdev, conf->mddev);
+                               rdev = NULL;
+                       }
+               }
+
                if (rdev) {
                        if (s->syncing || s->expanding || s->expanded)
                                md_sync_acct(rdev->bdev, STRIPE_SECTORS);
@@ -548,10 +577,6 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                        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 & WRITE)
@@ -1020,12 +1045,12 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
                if (test_and_clear_bit(R5_Wantdrain, &dev->flags)) {
                        struct bio *wbi;
 
-                       spin_lock(&sh->lock);
+                       spin_lock_irq(&sh->raid_conf->device_lock);
                        chosen = dev->towrite;
                        dev->towrite = NULL;
                        BUG_ON(dev->written);
                        wbi = dev->written = chosen;
-                       spin_unlock(&sh->lock);
+                       spin_unlock_irq(&sh->raid_conf->device_lock);
 
                        while (wbi && wbi->bi_sector <
                                dev->sector + STRIPE_SECTORS) {
@@ -1315,12 +1340,11 @@ static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request)
 static int grow_one_stripe(raid5_conf_t *conf)
 {
        struct stripe_head *sh;
-       sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL);
+       sh = kmem_cache_zalloc(conf->slab_cache, GFP_KERNEL);
        if (!sh)
                return 0;
-       memset(sh, 0, sizeof(*sh) + (conf->pool_size-1)*sizeof(struct r5dev));
+
        sh->raid_conf = conf;
-       spin_lock_init(&sh->lock);
        #ifdef CONFIG_MULTICORE_RAID456
        init_waitqueue_head(&sh->ops.wait_for_ops);
        #endif
@@ -1435,14 +1459,11 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
                return -ENOMEM;
 
        for (i = conf->max_nr_stripes; i; i--) {
-               nsh = kmem_cache_alloc(sc, GFP_KERNEL);
+               nsh = kmem_cache_zalloc(sc, GFP_KERNEL);
                if (!nsh)
                        break;
 
-               memset(nsh, 0, sizeof(*nsh) + (newsize-1)*sizeof(struct r5dev));
-
                nsh->raid_conf = conf;
-               spin_lock_init(&nsh->lock);
                #ifdef CONFIG_MULTICORE_RAID456
                init_waitqueue_head(&nsh->ops.wait_for_ops);
                #endif
@@ -1587,12 +1608,15 @@ static void raid5_end_read_request(struct bio * bi, int error)
                set_bit(R5_UPTODATE, &sh->dev[i].flags);
                if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
                        rdev = conf->disks[i].rdev;
-                       printk_rl(KERN_INFO "md/raid:%s: read error corrected"
-                                 " (%lu sectors at %llu on %s)\n",
-                                 mdname(conf->mddev), STRIPE_SECTORS,
-                                 (unsigned long long)(sh->sector
-                                                      + rdev->data_offset),
-                                 bdevname(rdev->bdev, b));
+                       printk_ratelimited(
+                               KERN_INFO
+                               "md/raid:%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));
+                       atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
                        clear_bit(R5_ReadError, &sh->dev[i].flags);
                        clear_bit(R5_ReWrite, &sh->dev[i].flags);
                }
@@ -1606,22 +1630,24 @@ static void raid5_end_read_request(struct bio * bi, int error)
                clear_bit(R5_UPTODATE, &sh->dev[i].flags);
                atomic_inc(&rdev->read_errors);
                if (conf->mddev->degraded >= conf->max_degraded)
-                       printk_rl(KERN_WARNING
-                                 "md/raid:%s: read error not correctable "
-                                 "(sector %llu on %s).\n",
-                                 mdname(conf->mddev),
-                                 (unsigned long long)(sh->sector
-                                                      + rdev->data_offset),
-                                 bdn);
+                       printk_ratelimited(
+                               KERN_WARNING
+                               "md/raid:%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_rl(KERN_WARNING
-                                 "md/raid:%s: read error NOT corrected!! "
-                                 "(sector %llu on %s).\n",
-                                 mdname(conf->mddev),
-                                 (unsigned long long)(sh->sector
-                                                      + rdev->data_offset),
-                                 bdn);
+                       printk_ratelimited(
+                               KERN_WARNING
+                               "md/raid:%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
@@ -1649,6 +1675,8 @@ static void raid5_end_write_request(struct bio *bi, int error)
        raid5_conf_t *conf = sh->raid_conf;
        int disks = sh->disks, i;
        int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
+       sector_t first_bad;
+       int bad_sectors;
 
        for (i=0 ; i<disks; i++)
                if (bi == &sh->dev[i].req)
@@ -1662,8 +1690,12 @@ static void raid5_end_write_request(struct bio *bi, int error)
                return;
        }
 
-       if (!uptodate)
-               md_error(conf->mddev, conf->disks[i].rdev);
+       if (!uptodate) {
+               set_bit(WriteErrorSeen, &conf->disks[i].rdev->flags);
+               set_bit(R5_WriteError, &sh->dev[i].flags);
+       } else if (is_badblock(conf->disks[i].rdev, sh->sector, STRIPE_SECTORS,
+                              &first_bad, &bad_sectors))
+               set_bit(R5_MadeGood, &sh->dev[i].flags);
 
        rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
        
@@ -1710,6 +1742,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
                 */
                set_bit(MD_RECOVERY_INTR, &mddev->recovery);
        }
+       set_bit(Blocked, &rdev->flags);
        set_bit(Faulty, &rdev->flags);
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
        printk(KERN_ALERT
@@ -1760,7 +1793,7 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector,
        /*
         * Select the parity disk based on the user selected algorithm.
         */
-       pd_idx = qd_idx = ~0;
+       pd_idx = qd_idx = -1;
        switch(conf->level) {
        case 4:
                pd_idx = data_disks;
@@ -2143,12 +2176,11 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
        raid5_conf_t *conf = sh->raid_conf;
        int firstwrite=0;
 
-       pr_debug("adding bh b#%llu to stripe s#%llu\n",
+       pr_debug("adding bi 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;
@@ -2169,19 +2201,6 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
                bi->bi_next = *bip;
        *bip = bi;
        bi->bi_phys_segments++;
-       spin_unlock_irq(&conf->device_lock);
-       spin_unlock(&sh->lock);
-
-       pr_debug("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) {
-               bitmap_startwrite(conf->mddev->bitmap, sh->sector,
-                                 STRIPE_SECTORS, 0);
-               sh->bm_seq = conf->seq_flush+1;
-               set_bit(STRIPE_BIT_DELAY, &sh->state);
-       }
 
        if (forwrite) {
                /* check if page is covered */
@@ -2196,12 +2215,23 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
                if (sector >= sh->dev[dd_idx].sector + STRIPE_SECTORS)
                        set_bit(R5_OVERWRITE, &sh->dev[dd_idx].flags);
        }
+       spin_unlock_irq(&conf->device_lock);
+
+       pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
+               (unsigned long long)(*bip)->bi_sector,
+               (unsigned long long)sh->sector, dd_idx);
+
+       if (conf->mddev->bitmap && firstwrite) {
+               bitmap_startwrite(conf->mddev->bitmap, sh->sector,
+                                 STRIPE_SECTORS, 0);
+               sh->bm_seq = conf->seq_flush+1;
+               set_bit(STRIPE_BIT_DELAY, &sh->state);
+       }
        return 1;
 
  overlap:
        set_bit(R5_Overlap, &sh->dev[dd_idx].flags);
        spin_unlock_irq(&conf->device_lock);
-       spin_unlock(&sh->lock);
        return 0;
 }
 
@@ -2238,9 +2268,18 @@ handle_failed_stripe(raid5_conf_t *conf, struct stripe_head *sh,
                        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);
+                               atomic_inc(&rdev->nr_pending);
+                       else
+                               rdev = NULL;
                        rcu_read_unlock();
+                       if (rdev) {
+                               if (!rdev_set_badblocks(
+                                           rdev,
+                                           sh->sector,
+                                           STRIPE_SECTORS, 0))
+                                       md_error(conf->mddev, rdev);
+                               rdev_dec_pending(rdev, conf->mddev);
+                       }
                }
                spin_lock_irq(&conf->device_lock);
                /* fail all writes first */
@@ -2308,6 +2347,10 @@ handle_failed_stripe(raid5_conf_t *conf, struct stripe_head *sh,
                if (bitmap_end)
                        bitmap_endwrite(conf->mddev->bitmap, sh->sector,
                                        STRIPE_SECTORS, 0, 0);
+               /* If we were in the middle of a write the parity block might
+                * still be locked - so just clear all R5_LOCKED flags
+                */
+               clear_bit(R5_LOCKED, &sh->dev[i].flags);
        }
 
        if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state))
@@ -2315,109 +2358,73 @@ handle_failed_stripe(raid5_conf_t *conf, struct stripe_head *sh,
                        md_wakeup_thread(conf->mddev->thread);
 }
 
-/* fetch_block5 - checks the given member device to see if its data needs
- * to be read or computed to satisfy a request.
- *
- * Returns 1 when no more member devices need to be checked, otherwise returns
- * 0 to tell the loop in handle_stripe_fill5 to continue
- */
-static int fetch_block5(struct stripe_head *sh, struct stripe_head_state *s,
-                       int disk_idx, int disks)
-{
-       struct r5dev *dev = &sh->dev[disk_idx];
-       struct r5dev *failed_dev = &sh->dev[s->failed_num];
-
-       /* is the data in this block needed, and can we get it? */
-       if (!test_bit(R5_LOCKED, &dev->flags) &&
-           !test_bit(R5_UPTODATE, &dev->flags) &&
-           (dev->toread ||
-            (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
-            s->syncing || s->expanding ||
-            (s->failed &&
-             (failed_dev->toread ||
-              (failed_dev->towrite &&
-               !test_bit(R5_OVERWRITE, &failed_dev->flags)))))) {
-               /* We would like to get this block, possibly by computing it,
-                * otherwise read it if the backing disk is insync
-                */
-               if ((s->uptodate == disks - 1) &&
-                   (s->failed && disk_idx == s->failed_num)) {
-                       set_bit(STRIPE_COMPUTE_RUN, &sh->state);
-                       set_bit(STRIPE_OP_COMPUTE_BLK, &s->ops_request);
-                       set_bit(R5_Wantcompute, &dev->flags);
-                       sh->ops.target = disk_idx;
-                       sh->ops.target2 = -1;
-                       s->req_compute = 1;
-                       /* Careful: from this point on 'uptodate' is in the eye
-                        * of raid_run_ops which services 'compute' operations
-                        * before writes. R5_Wantcompute flags a block that will
-                        * be R5_UPTODATE by the time it is needed for a
-                        * subsequent operation.
-                        */
-                       s->uptodate++;
-                       return 1; /* uptodate + compute == disks */
-               } else if (test_bit(R5_Insync, &dev->flags)) {
-                       set_bit(R5_LOCKED, &dev->flags);
-                       set_bit(R5_Wantread, &dev->flags);
-                       s->locked++;
-                       pr_debug("Reading block %d (sync=%d)\n", disk_idx,
-                               s->syncing);
-               }
-       }
-
-       return 0;
-}
-
-/**
- * handle_stripe_fill5 - read or compute data to satisfy pending requests.
- */
-static void handle_stripe_fill5(struct stripe_head *sh,
-                       struct stripe_head_state *s, int disks)
+static void
+handle_failed_sync(raid5_conf_t *conf, struct stripe_head *sh,
+                  struct stripe_head_state *s)
 {
+       int abort = 0;
        int i;
 
-       /* look for blocks to read/compute, skip this if a compute
-        * is already in flight, or if the stripe contents are in the
-        * midst of changing due to a write
+       md_done_sync(conf->mddev, STRIPE_SECTORS, 0);
+       clear_bit(STRIPE_SYNCING, &sh->state);
+       s->syncing = 0;
+       /* There is nothing more to do for sync/check/repair.
+        * For recover we need to record a bad block on all
+        * non-sync devices, or abort the recovery
         */
-       if (!test_bit(STRIPE_COMPUTE_RUN, &sh->state) && !sh->check_state &&
-           !sh->reconstruct_state)
-               for (i = disks; i--; )
-                       if (fetch_block5(sh, s, i, disks))
-                               break;
-       set_bit(STRIPE_HANDLE, &sh->state);
+       if (!test_bit(MD_RECOVERY_RECOVER, &conf->mddev->recovery))
+               return;
+       /* During recovery devices cannot be removed, so locking and
+        * refcounting of rdevs is not needed
+        */
+       for (i = 0; i < conf->raid_disks; i++) {
+               mdk_rdev_t *rdev = conf->disks[i].rdev;
+               if (!rdev
+                   || test_bit(Faulty, &rdev->flags)
+                   || test_bit(In_sync, &rdev->flags))
+                       continue;
+               if (!rdev_set_badblocks(rdev, sh->sector,
+                                       STRIPE_SECTORS, 0))
+                       abort = 1;
+       }
+       if (abort) {
+               conf->recovery_disabled = conf->mddev->recovery_disabled;
+               set_bit(MD_RECOVERY_INTR, &conf->mddev->recovery);
+       }
 }
 
-/* fetch_block6 - checks the given member device to see if its data needs
+/* fetch_block - checks the given member device to see if its data needs
  * to be read or computed to satisfy a request.
  *
  * Returns 1 when no more member devices need to be checked, otherwise returns
- * 0 to tell the loop in handle_stripe_fill6 to continue
+ * 0 to tell the loop in handle_stripe_fill to continue
  */
-static int fetch_block6(struct stripe_head *sh, struct stripe_head_state *s,
-                        struct r6_state *r6s, int disk_idx, int disks)
+static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s,
+                      int disk_idx, int disks)
 {
        struct r5dev *dev = &sh->dev[disk_idx];
-       struct r5dev *fdev[2] = { &sh->dev[r6s->failed_num[0]],
-                                 &sh->dev[r6s->failed_num[1]] };
+       struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]],
+                                 &sh->dev[s->failed_num[1]] };
 
+       /* is the data in this block needed, and can we get it? */
        if (!test_bit(R5_LOCKED, &dev->flags) &&
            !test_bit(R5_UPTODATE, &dev->flags) &&
            (dev->toread ||
             (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
             s->syncing || s->expanding ||
-            (s->failed >= 1 &&
-             (fdev[0]->toread || s->to_write)) ||
-            (s->failed >= 2 &&
-             (fdev[1]->toread || s->to_write)))) {
+            (s->failed >= 1 && fdev[0]->toread) ||
+            (s->failed >= 2 && fdev[1]->toread) ||
+            (sh->raid_conf->level <= 5 && s->failed && fdev[0]->towrite &&
+             !test_bit(R5_OVERWRITE, &fdev[0]->flags)) ||
+            (sh->raid_conf->level == 6 && s->failed && s->to_write))) {
                /* we would like to get this block, possibly by computing it,
                 * otherwise read it if the backing disk is insync
                 */
                BUG_ON(test_bit(R5_Wantcompute, &dev->flags));
                BUG_ON(test_bit(R5_Wantread, &dev->flags));
                if ((s->uptodate == disks - 1) &&
-                   (s->failed && (disk_idx == r6s->failed_num[0] ||
-                                  disk_idx == r6s->failed_num[1]))) {
+                   (s->failed && (disk_idx == s->failed_num[0] ||
+                                  disk_idx == s->failed_num[1]))) {
                        /* have disk failed, and we're requested to fetch it;
                         * do compute it
                         */
@@ -2429,6 +2436,12 @@ static int fetch_block6(struct stripe_head *sh, struct stripe_head_state *s,
                        sh->ops.target = disk_idx;
                        sh->ops.target2 = -1; /* no 2nd target */
                        s->req_compute = 1;
+                       /* Careful: from this point on 'uptodate' is in the eye
+                        * of raid_run_ops which services 'compute' operations
+                        * before writes. R5_Wantcompute flags a block that will
+                        * be R5_UPTODATE by the time it is needed for a
+                        * subsequent operation.
+                        */
                        s->uptodate++;
                        return 1;
                } else if (s->uptodate == disks-2 && s->failed >= 2) {
@@ -2469,11 +2482,11 @@ static int fetch_block6(struct stripe_head *sh, struct stripe_head_state *s,
 }
 
 /**
- * handle_stripe_fill6 - read or compute data to satisfy pending requests.
+ * handle_stripe_fill - read or compute data to satisfy pending requests.
  */
-static void handle_stripe_fill6(struct stripe_head *sh,
-                       struct stripe_head_state *s, struct r6_state *r6s,
-                       int disks)
+static void handle_stripe_fill(struct stripe_head *sh,
+                              struct stripe_head_state *s,
+                              int disks)
 {
        int i;
 
@@ -2484,7 +2497,7 @@ static void handle_stripe_fill6(struct stripe_head *sh,
        if (!test_bit(STRIPE_COMPUTE_RUN, &sh->state) && !sh->check_state &&
            !sh->reconstruct_state)
                for (i = disks; i--; )
-                       if (fetch_block6(sh, s, r6s, i, disks))
+                       if (fetch_block(sh, s, i, disks))
                                break;
        set_bit(STRIPE_HANDLE, &sh->state);
 }
@@ -2540,11 +2553,19 @@ static void handle_stripe_clean_event(raid5_conf_t *conf,
                        md_wakeup_thread(conf->mddev->thread);
 }
 
-static void handle_stripe_dirtying5(raid5_conf_t *conf,
-               struct stripe_head *sh, struct stripe_head_state *s, int disks)
+static void handle_stripe_dirtying(raid5_conf_t *conf,
+                                  struct stripe_head *sh,
+                                  struct stripe_head_state *s,
+                                  int disks)
 {
        int rmw = 0, rcw = 0, i;
-       for (i = disks; i--; ) {
+       if (conf->max_degraded == 2) {
+               /* RAID6 requires 'rcw' in current implementation
+                * Calculate the real rcw later - for now fake it
+                * look like rcw is cheaper
+                */
+               rcw = 1; rmw = 2;
+       } else for (i = disks; i--; ) {
                /* would I have to read this buffer for read_modify_write */
                struct r5dev *dev = &sh->dev[i];
                if ((dev->towrite || i == sh->pd_idx) &&
@@ -2591,16 +2612,19 @@ static void handle_stripe_dirtying5(raid5_conf_t *conf,
                                }
                        }
                }
-       if (rcw <= rmw && rcw > 0)
+       if (rcw <= rmw && rcw > 0) {
                /* want reconstruct write, but need to get some data */
+               rcw = 0;
                for (i = disks; i--; ) {
                        struct r5dev *dev = &sh->dev[i];
                        if (!test_bit(R5_OVERWRITE, &dev->flags) &&
-                           i != sh->pd_idx &&
+                           i != sh->pd_idx && i != sh->qd_idx &&
                            !test_bit(R5_LOCKED, &dev->flags) &&
                            !(test_bit(R5_UPTODATE, &dev->flags) ||
-                           test_bit(R5_Wantcompute, &dev->flags)) &&
-                           test_bit(R5_Insync, &dev->flags)) {
+                             test_bit(R5_Wantcompute, &dev->flags))) {
+                               rcw++;
+                               if (!test_bit(R5_Insync, &dev->flags))
+                                       continue; /* it's a failed drive */
                                if (
                                  test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
                                        pr_debug("Read_old block "
@@ -2614,6 +2638,7 @@ static void handle_stripe_dirtying5(raid5_conf_t *conf,
                                }
                        }
                }
+       }
        /* now if nothing is locked, and if we have enough data,
         * we can start a write request
         */
@@ -2630,53 +2655,6 @@ static void handle_stripe_dirtying5(raid5_conf_t *conf,
                schedule_reconstruction(sh, s, rcw == 0, 0);
 }
 
-static void handle_stripe_dirtying6(raid5_conf_t *conf,
-               struct stripe_head *sh, struct stripe_head_state *s,
-               struct r6_state *r6s, int disks)
-{
-       int rcw = 0, pd_idx = sh->pd_idx, i;
-       int qd_idx = sh->qd_idx;
-
-       set_bit(STRIPE_HANDLE, &sh->state);
-       for (i = disks; i--; ) {
-               struct r5dev *dev = &sh->dev[i];
-               /* check if we haven't enough data */
-               if (!test_bit(R5_OVERWRITE, &dev->flags) &&
-                   i != pd_idx && i != qd_idx &&
-                   !test_bit(R5_LOCKED, &dev->flags) &&
-                   !(test_bit(R5_UPTODATE, &dev->flags) ||
-                     test_bit(R5_Wantcompute, &dev->flags))) {
-                       rcw++;
-                       if (!test_bit(R5_Insync, &dev->flags))
-                               continue; /* it's a failed drive */
-
-                       if (
-                         test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
-                               pr_debug("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);
-                               s->locked++;
-                       } else {
-                               pr_debug("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 ((s->req_compute || !test_bit(STRIPE_COMPUTE_RUN, &sh->state)) &&
-           s->locked == 0 && rcw == 0 &&
-           !test_bit(STRIPE_BIT_DELAY, &sh->state)) {
-               schedule_reconstruction(sh, s, 1, 0);
-       }
-}
-
 static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh,
                                struct stripe_head_state *s, int disks)
 {
@@ -2695,7 +2673,7 @@ static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh,
                        s->uptodate--;
                        break;
                }
-               dev = &sh->dev[s->failed_num];
+               dev = &sh->dev[s->failed_num[0]];
                /* fall through */
        case check_state_compute_result:
                sh->check_state = check_state_idle;
@@ -2767,7 +2745,7 @@ static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh,
 
 static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh,
                                  struct stripe_head_state *s,
-                                 struct r6_state *r6s, int disks)
+                                 int disks)
 {
        int pd_idx = sh->pd_idx;
        int qd_idx = sh->qd_idx;
@@ -2786,14 +2764,14 @@ static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh,
        switch (sh->check_state) {
        case check_state_idle:
                /* start a new check operation if there are < 2 failures */
-               if (s->failed == r6s->q_failed) {
+               if (s->failed == s->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).
                         */
                        sh->check_state = check_state_run;
                }
-               if (!r6s->q_failed && s->failed < 2) {
+               if (!s->q_failed && s->failed < 2) {
                        /* Q is not failed, and we didn't use it to generate
                         * anything, so it makes sense to check it
                         */
@@ -2835,13 +2813,13 @@ static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh,
                 */
                BUG_ON(s->uptodate < disks - 1); /* We don't need Q to recover */
                if (s->failed == 2) {
-                       dev = &sh->dev[r6s->failed_num[1]];
+                       dev = &sh->dev[s->failed_num[1]];
                        s->locked++;
                        set_bit(R5_LOCKED, &dev->flags);
                        set_bit(R5_Wantwrite, &dev->flags);
                }
                if (s->failed >= 1) {
-                       dev = &sh->dev[r6s->failed_num[0]];
+                       dev = &sh->dev[s->failed_num[0]];
                        s->locked++;
                        set_bit(R5_LOCKED, &dev->flags);
                        set_bit(R5_Wantwrite, &dev->flags);
@@ -2928,8 +2906,7 @@ static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh,
        }
 }
 
-static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
-                               struct r6_state *r6s)
+static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh)
 {
        int i;
 
@@ -2971,7 +2948,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
                        set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags);
                        for (j = 0; j < conf->raid_disks; j++)
                                if (j != sh2->pd_idx &&
-                                   (!r6s || j != sh2->qd_idx) &&
+                                   j != sh2->qd_idx &&
                                    !test_bit(R5_Expanded, &sh2->dev[j].flags))
                                        break;
                        if (j == conf->raid_disks) {
@@ -3006,43 +2983,35 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
  *
  */
 
-static void handle_stripe5(struct stripe_head *sh)
+static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
 {
        raid5_conf_t *conf = sh->raid_conf;
-       int disks = sh->disks, i;
-       struct bio *return_bi = NULL;
-       struct stripe_head_state s;
+       int disks = sh->disks;
        struct r5dev *dev;
-       mdk_rdev_t *blocked_rdev = NULL;
-       int prexor;
-       int dec_preread_active = 0;
+       int i;
 
-       memset(&s, 0, sizeof(s));
-       pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d check:%d "
-                "reconstruct:%d\n", (unsigned long long)sh->sector, sh->state,
-                atomic_read(&sh->count), sh->pd_idx, sh->check_state,
-                sh->reconstruct_state);
+       memset(s, 0, sizeof(*s));
 
-       spin_lock(&sh->lock);
-       clear_bit(STRIPE_HANDLE, &sh->state);
-       clear_bit(STRIPE_DELAYED, &sh->state);
-
-       s.syncing = test_bit(STRIPE_SYNCING, &sh->state);
-       s.expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
-       s.expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
+       s->syncing = test_bit(STRIPE_SYNCING, &sh->state);
+       s->expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+       s->expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
+       s->failed_num[0] = -1;
+       s->failed_num[1] = -1;
 
        /* Now to look around and see what can be done */
        rcu_read_lock();
+       spin_lock_irq(&conf->device_lock);
        for (i=disks; i--; ) {
                mdk_rdev_t *rdev;
+               sector_t first_bad;
+               int bad_sectors;
+               int is_bad = 0;
 
                dev = &sh->dev[i];
 
-               pr_debug("check %d: state 0x%lx toread %p read %p write %p "
-                       "written %p\n", i, dev->flags, dev->toread, dev->read,
-                       dev->towrite, dev->written);
-
-               /* maybe we can request a biofill operation
+               pr_debug("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
                 *
                 * new wantfill requests are only permitted while
                 * ops_complete_biofill is guaranteed to be inactive
@@ -3052,37 +3021,74 @@ static void handle_stripe5(struct stripe_head *sh)
                        set_bit(R5_Wantfill, &dev->flags);
 
                /* now count some things */
-               if (test_bit(R5_LOCKED, &dev->flags)) s.locked++;
-               if (test_bit(R5_UPTODATE, &dev->flags)) s.uptodate++;
-               if (test_bit(R5_Wantcompute, &dev->flags)) s.compute++;
+               if (test_bit(R5_LOCKED, &dev->flags))
+                       s->locked++;
+               if (test_bit(R5_UPTODATE, &dev->flags))
+                       s->uptodate++;
+               if (test_bit(R5_Wantcompute, &dev->flags)) {
+                       s->compute++;
+                       BUG_ON(s->compute > 2);
+               }
 
                if (test_bit(R5_Wantfill, &dev->flags))
-                       s.to_fill++;
+                       s->to_fill++;
                else if (dev->toread)
-                       s.to_read++;
+                       s->to_read++;
                if (dev->towrite) {
-                       s.to_write++;
+                       s->to_write++;
                        if (!test_bit(R5_OVERWRITE, &dev->flags))
-                               s.non_overwrite++;
+                               s->non_overwrite++;
                }
                if (dev->written)
-                       s.written++;
+                       s->written++;
                rdev = rcu_dereference(conf->disks[i].rdev);
-               if (blocked_rdev == NULL &&
-                   rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
-                       blocked_rdev = rdev;
-                       atomic_inc(&rdev->nr_pending);
+               if (rdev) {
+                       is_bad = is_badblock(rdev, sh->sector, STRIPE_SECTORS,
+                                            &first_bad, &bad_sectors);
+                       if (s->blocked_rdev == NULL
+                           && (test_bit(Blocked, &rdev->flags)
+                               || is_bad < 0)) {
+                               if (is_bad < 0)
+                                       set_bit(BlockedBadBlocks,
+                                               &rdev->flags);
+                               s->blocked_rdev = rdev;
+                               atomic_inc(&rdev->nr_pending);
+                       }
                }
                clear_bit(R5_Insync, &dev->flags);
                if (!rdev)
                        /* Not in-sync */;
-               else if (test_bit(In_sync, &rdev->flags))
+               else if (is_bad) {
+                       /* also not in-sync */
+                       if (!test_bit(WriteErrorSeen, &rdev->flags)) {
+                               /* treat as in-sync, but with a read error
+                                * which we can now try to correct
+                                */
+                               set_bit(R5_Insync, &dev->flags);
+                               set_bit(R5_ReadError, &dev->flags);
+                       }
+               } else if (test_bit(In_sync, &rdev->flags))
                        set_bit(R5_Insync, &dev->flags);
                else {
-                       /* could be in-sync depending on recovery/reshape status */
+                       /* in sync if before recovery_offset */
                        if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset)
                                set_bit(R5_Insync, &dev->flags);
                }
+               if (test_bit(R5_WriteError, &dev->flags)) {
+                       clear_bit(R5_Insync, &dev->flags);
+                       if (!test_bit(Faulty, &rdev->flags)) {
+                               s->handle_bad_blocks = 1;
+                               atomic_inc(&rdev->nr_pending);
+                       } else
+                               clear_bit(R5_WriteError, &dev->flags);
+               }
+               if (test_bit(R5_MadeGood, &dev->flags)) {
+                       if (!test_bit(Faulty, &rdev->flags)) {
+                               s->handle_bad_blocks = 1;
+                               atomic_inc(&rdev->nr_pending);
+                       } else
+                               clear_bit(R5_MadeGood, &dev->flags);
+               }
                if (!test_bit(R5_Insync, &dev->flags)) {
                        /* The ReadError flag will just be confusing now */
                        clear_bit(R5_ReadError, &dev->flags);
@@ -3091,313 +3097,60 @@ static void handle_stripe5(struct stripe_head *sh)
                if (test_bit(R5_ReadError, &dev->flags))
                        clear_bit(R5_Insync, &dev->flags);
                if (!test_bit(R5_Insync, &dev->flags)) {
-                       s.failed++;
-                       s.failed_num = i;
+                       if (s->failed < 2)
+                               s->failed_num[s->failed] = i;
+                       s->failed++;
                }
        }
+       spin_unlock_irq(&conf->device_lock);
        rcu_read_unlock();
-
-       if (unlikely(blocked_rdev)) {
-               if (s.syncing || s.expanding || s.expanded ||
-                   s.to_write || s.written) {
-                       set_bit(STRIPE_HANDLE, &sh->state);
-                       goto unlock;
-               }
-               /* There is nothing for the blocked_rdev to block */
-               rdev_dec_pending(blocked_rdev, conf->mddev);
-               blocked_rdev = NULL;
-       }
-
-       if (s.to_fill && !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) {
-               set_bit(STRIPE_OP_BIOFILL, &s.ops_request);
-               set_bit(STRIPE_BIOFILL_RUN, &sh->state);
-       }
-
-       pr_debug("locked=%d uptodate=%d to_read=%d"
-               " to_write=%d failed=%d failed_num=%d\n",
-               s.locked, s.uptodate, s.to_read, s.to_write,
-               s.failed, s.failed_num);
-       /* check if the array has lost two devices and, if so, some requests might
-        * need to be failed
-        */
-       if (s.failed > 1 && s.to_read+s.to_write+s.written)
-               handle_failed_stripe(conf, sh, &s, disks, &return_bi);
-       if (s.failed > 1 && s.syncing) {
-               md_done_sync(conf->mddev, STRIPE_SECTORS,0);
-               clear_bit(STRIPE_SYNCING, &sh->state);
-               s.syncing = 0;
-       }
-
-       /* might be able to return some write requests if the parity block
-        * is safe, or on a failed drive
-        */
-       dev = &sh->dev[sh->pd_idx];
-       if ( s.written &&
-            ((test_bit(R5_Insync, &dev->flags) &&
-              !test_bit(R5_LOCKED, &dev->flags) &&
-              test_bit(R5_UPTODATE, &dev->flags)) ||
-              (s.failed == 1 && s.failed_num == sh->pd_idx)))
-               handle_stripe_clean_event(conf, sh, disks, &return_bi);
-
-       /* 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 (s.to_read || s.non_overwrite ||
-           (s.syncing && (s.uptodate + s.compute < disks)) || s.expanding)
-               handle_stripe_fill5(sh, &s, disks);
-
-       /* Now we check to see if any write operations have recently
-        * completed
-        */
-       prexor = 0;
-       if (sh->reconstruct_state == reconstruct_state_prexor_drain_result)
-               prexor = 1;
-       if (sh->reconstruct_state == reconstruct_state_drain_result ||
-           sh->reconstruct_state == reconstruct_state_prexor_drain_result) {
-               sh->reconstruct_state = reconstruct_state_idle;
-
-               /* All the 'written' buffers and the parity block are ready to
-                * be written back to disk
-                */
-               BUG_ON(!test_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags));
-               for (i = disks; i--; ) {
-                       dev = &sh->dev[i];
-                       if (test_bit(R5_LOCKED, &dev->flags) &&
-                               (i == sh->pd_idx || dev->written)) {
-                               pr_debug("Writing block %d\n", i);
-                               set_bit(R5_Wantwrite, &dev->flags);
-                               if (prexor)
-                                       continue;
-                               if (!test_bit(R5_Insync, &dev->flags) ||
-                                   (i == sh->pd_idx && s.failed == 0))
-                                       set_bit(STRIPE_INSYNC, &sh->state);
-                       }
-               }
-               if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
-                       dec_preread_active = 1;
-       }
-
-       /* Now to consider new write requests and what else, if anything
-        * should be read.  We do not handle new writes when:
-        * 1/ A 'write' operation (copy+xor) is already in flight.
-        * 2/ A 'check' operation is in flight, as it may clobber the parity
-        *    block.
-        */
-       if (s.to_write && !sh->reconstruct_state && !sh->check_state)
-               handle_stripe_dirtying5(conf, sh, &s, disks);
-
-       /* 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.  The parity check is held off while parity
-        * dependent operations are in flight.
-        */
-       if (sh->check_state ||
-           (s.syncing && s.locked == 0 &&
-            !test_bit(STRIPE_COMPUTE_RUN, &sh->state) &&
-            !test_bit(STRIPE_INSYNC, &sh->state)))
-               handle_parity_checks5(conf, sh, &s, disks);
-
-       if (s.syncing && s.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 drive is just a ReadError, then we might need to progress
-        * the repair/check process
-        */
-       if (s.failed == 1 && !conf->mddev->ro &&
-           test_bit(R5_ReadError, &sh->dev[s.failed_num].flags)
-           && !test_bit(R5_LOCKED, &sh->dev[s.failed_num].flags)
-           && test_bit(R5_UPTODATE, &sh->dev[s.failed_num].flags)
-               ) {
-               dev = &sh->dev[s.failed_num];
-               if (!test_bit(R5_ReWrite, &dev->flags)) {
-                       set_bit(R5_Wantwrite, &dev->flags);
-                       set_bit(R5_ReWrite, &dev->flags);
-                       set_bit(R5_LOCKED, &dev->flags);
-                       s.locked++;
-               } else {
-                       /* let's read it back */
-                       set_bit(R5_Wantread, &dev->flags);
-                       set_bit(R5_LOCKED, &dev->flags);
-                       s.locked++;
-               }
-       }
-
-       /* Finish reconstruct operations initiated by the expansion process */
-       if (sh->reconstruct_state == reconstruct_state_result) {
-               struct stripe_head *sh2
-                       = get_active_stripe(conf, sh->sector, 1, 1, 1);
-               if (sh2 && test_bit(STRIPE_EXPAND_SOURCE, &sh2->state)) {
-                       /* sh cannot be written until sh2 has been read.
-                        * so arrange for sh to be delayed a little
-                        */
-                       set_bit(STRIPE_DELAYED, &sh->state);
-                       set_bit(STRIPE_HANDLE, &sh->state);
-                       if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE,
-                                             &sh2->state))
-                               atomic_inc(&conf->preread_active_stripes);
-                       release_stripe(sh2);
-                       goto unlock;
-               }
-               if (sh2)
-                       release_stripe(sh2);
-
-               sh->reconstruct_state = reconstruct_state_idle;
-               clear_bit(STRIPE_EXPANDING, &sh->state);
-               for (i = conf->raid_disks; i--; ) {
-                       set_bit(R5_Wantwrite, &sh->dev[i].flags);
-                       set_bit(R5_LOCKED, &sh->dev[i].flags);
-                       s.locked++;
-               }
-       }
-
-       if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state) &&
-           !sh->reconstruct_state) {
-               /* Need to write out all blocks after computing parity */
-               sh->disks = conf->raid_disks;
-               stripe_set_idx(sh->sector, conf, 0, sh);
-               schedule_reconstruction(sh, &s, 1, 1);
-       } else if (s.expanded && !sh->reconstruct_state && s.locked == 0) {
-               clear_bit(STRIPE_EXPAND_READY, &sh->state);
-               atomic_dec(&conf->reshape_stripes);
-               wake_up(&conf->wait_for_overlap);
-               md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
-       }
-
-       if (s.expanding && s.locked == 0 &&
-           !test_bit(STRIPE_COMPUTE_RUN, &sh->state))
-               handle_stripe_expansion(conf, sh, NULL);
-
- unlock:
-       spin_unlock(&sh->lock);
-
-       /* wait for this device to become unblocked */
-       if (unlikely(blocked_rdev))
-               md_wait_for_blocked_rdev(blocked_rdev, conf->mddev);
-
-       if (s.ops_request)
-               raid_run_ops(sh, s.ops_request);
-
-       ops_run_io(sh, &s);
-
-       if (dec_preread_active) {
-               /* We delay this until after ops_run_io so that if make_request
-                * is waiting on a flush, it won't continue until the writes
-                * have actually been submitted.
-                */
-               atomic_dec(&conf->preread_active_stripes);
-               if (atomic_read(&conf->preread_active_stripes) <
-                   IO_THRESHOLD)
-                       md_wakeup_thread(conf->mddev->thread);
-       }
-       return_io(return_bi);
 }
 
-static void handle_stripe6(struct stripe_head *sh)
+static void handle_stripe(struct stripe_head *sh)
 {
+       struct stripe_head_state s;
        raid5_conf_t *conf = sh->raid_conf;
+       int i;
+       int prexor;
        int disks = sh->disks;
-       struct bio *return_bi = NULL;
-       int i, pd_idx = sh->pd_idx, qd_idx = sh->qd_idx;
-       struct stripe_head_state s;
-       struct r6_state r6s;
-       struct r5dev *dev, *pdev, *qdev;
-       mdk_rdev_t *blocked_rdev = NULL;
-       int dec_preread_active = 0;
+       struct r5dev *pdev, *qdev;
+
+       clear_bit(STRIPE_HANDLE, &sh->state);
+       if (test_and_set_bit(STRIPE_ACTIVE, &sh->state)) {
+               /* already being handled, ensure it gets handled
+                * again when current action finishes */
+               set_bit(STRIPE_HANDLE, &sh->state);
+               return;
+       }
+
+       if (test_and_clear_bit(STRIPE_SYNC_REQUESTED, &sh->state)) {
+               set_bit(STRIPE_SYNCING, &sh->state);
+               clear_bit(STRIPE_INSYNC, &sh->state);
+       }
+       clear_bit(STRIPE_DELAYED, &sh->state);
 
        pr_debug("handling stripe %llu, state=%#lx cnt=%d, "
                "pd_idx=%d, qd_idx=%d\n, check:%d, reconstruct:%d\n",
               (unsigned long long)sh->sector, sh->state,
-              atomic_read(&sh->count), pd_idx, qd_idx,
+              atomic_read(&sh->count), sh->pd_idx, sh->qd_idx,
               sh->check_state, sh->reconstruct_state);
-       memset(&s, 0, sizeof(s));
-
-       spin_lock(&sh->lock);
-       clear_bit(STRIPE_HANDLE, &sh->state);
-       clear_bit(STRIPE_DELAYED, &sh->state);
-
-       s.syncing = test_bit(STRIPE_SYNCING, &sh->state);
-       s.expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
-       s.expanded = test_bit(STRIPE_EXPAND_READY, &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];
 
-               pr_debug("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
-                *
-                * new wantfill requests are only permitted while
-                * ops_complete_biofill is guaranteed to be inactive
-                */
-               if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread &&
-                   !test_bit(STRIPE_BIOFILL_RUN, &sh->state))
-                       set_bit(R5_Wantfill, &dev->flags);
+       analyse_stripe(sh, &s);
 
-               /* now count some things */
-               if (test_bit(R5_LOCKED, &dev->flags)) s.locked++;
-               if (test_bit(R5_UPTODATE, &dev->flags)) s.uptodate++;
-               if (test_bit(R5_Wantcompute, &dev->flags)) {
-                       s.compute++;
-                       BUG_ON(s.compute > 2);
-               }
-
-               if (test_bit(R5_Wantfill, &dev->flags)) {
-                       s.to_fill++;
-               } else if (dev->toread)
-                       s.to_read++;
-               if (dev->towrite) {
-                       s.to_write++;
-                       if (!test_bit(R5_OVERWRITE, &dev->flags))
-                               s.non_overwrite++;
-               }
-               if (dev->written)
-                       s.written++;
-               rdev = rcu_dereference(conf->disks[i].rdev);
-               if (blocked_rdev == NULL &&
-                   rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
-                       blocked_rdev = rdev;
-                       atomic_inc(&rdev->nr_pending);
-               }
-               clear_bit(R5_Insync, &dev->flags);
-               if (!rdev)
-                       /* Not in-sync */;
-               else if (test_bit(In_sync, &rdev->flags))
-                       set_bit(R5_Insync, &dev->flags);
-               else {
-                       /* in sync if before recovery_offset */
-                       if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset)
-                               set_bit(R5_Insync, &dev->flags);
-               }
-               if (!test_bit(R5_Insync, &dev->flags)) {
-                       /* The ReadError flag will just be confusing now */
-                       clear_bit(R5_ReadError, &dev->flags);
-                       clear_bit(R5_ReWrite, &dev->flags);
-               }
-               if (test_bit(R5_ReadError, &dev->flags))
-                       clear_bit(R5_Insync, &dev->flags);
-               if (!test_bit(R5_Insync, &dev->flags)) {
-                       if (s.failed < 2)
-                               r6s.failed_num[s.failed] = i;
-                       s.failed++;
-               }
+       if (s.handle_bad_blocks) {
+               set_bit(STRIPE_HANDLE, &sh->state);
+               goto finish;
        }
-       rcu_read_unlock();
 
-       if (unlikely(blocked_rdev)) {
+       if (unlikely(s.blocked_rdev)) {
                if (s.syncing || s.expanding || s.expanded ||
                    s.to_write || s.written) {
                        set_bit(STRIPE_HANDLE, &sh->state);
-                       goto unlock;
+                       goto finish;
                }
                /* There is nothing for the blocked_rdev to block */
-               rdev_dec_pending(blocked_rdev, conf->mddev);
-               blocked_rdev = NULL;
+               rdev_dec_pending(s.blocked_rdev, conf->mddev);
+               s.blocked_rdev = NULL;
        }
 
        if (s.to_fill && !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) {
@@ -3408,83 +3161,88 @@ static void handle_stripe6(struct stripe_head *sh)
        pr_debug("locked=%d uptodate=%d to_read=%d"
               " to_write=%d failed=%d failed_num=%d,%d\n",
               s.locked, s.uptodate, s.to_read, s.to_write, s.failed,
-              r6s.failed_num[0], r6s.failed_num[1]);
-       /* check if the array has lost >2 devices and, if so, some requests
-        * might need to be failed
+              s.failed_num[0], s.failed_num[1]);
+       /* check if the array has lost more than max_degraded devices and,
+        * if so, some requests might need to be failed.
         */
-       if (s.failed > 2 && s.to_read+s.to_write+s.written)
-               handle_failed_stripe(conf, sh, &s, disks, &return_bi);
-       if (s.failed > 2 && s.syncing) {
-               md_done_sync(conf->mddev, STRIPE_SECTORS,0);
-               clear_bit(STRIPE_SYNCING, &sh->state);
-               s.syncing = 0;
-       }
+       if (s.failed > conf->max_degraded && s.to_read+s.to_write+s.written)
+               handle_failed_stripe(conf, sh, &s, disks, &s.return_bi);
+       if (s.failed > conf->max_degraded && s.syncing)
+               handle_failed_sync(conf, sh, &s);
 
        /*
         * might be able to return some write requests if the parity blocks
         * are safe, or on a failed drive
         */
-       pdev = &sh->dev[pd_idx];
-       r6s.p_failed = (s.failed >= 1 && r6s.failed_num[0] == pd_idx)
-               || (s.failed >= 2 && r6s.failed_num[1] == pd_idx);
-       qdev = &sh->dev[qd_idx];
-       r6s.q_failed = (s.failed >= 1 && r6s.failed_num[0] == qd_idx)
-               || (s.failed >= 2 && r6s.failed_num[1] == qd_idx);
-
-       if ( s.written &&
-            ( r6s.p_failed || ((test_bit(R5_Insync, &pdev->flags)
+       pdev = &sh->dev[sh->pd_idx];
+       s.p_failed = (s.failed >= 1 && s.failed_num[0] == sh->pd_idx)
+               || (s.failed >= 2 && s.failed_num[1] == sh->pd_idx);
+       qdev = &sh->dev[sh->qd_idx];
+       s.q_failed = (s.failed >= 1 && s.failed_num[0] == sh->qd_idx)
+               || (s.failed >= 2 && s.failed_num[1] == sh->qd_idx)
+               || conf->level < 6;
+
+       if (s.written &&
+           (s.p_failed || ((test_bit(R5_Insync, &pdev->flags)
                             && !test_bit(R5_LOCKED, &pdev->flags)
                             && test_bit(R5_UPTODATE, &pdev->flags)))) &&
-            ( r6s.q_failed || ((test_bit(R5_Insync, &qdev->flags)
+           (s.q_failed || ((test_bit(R5_Insync, &qdev->flags)
                             && !test_bit(R5_LOCKED, &qdev->flags)
                             && test_bit(R5_UPTODATE, &qdev->flags)))))
-               handle_stripe_clean_event(conf, sh, disks, &return_bi);
+               handle_stripe_clean_event(conf, sh, disks, &s.return_bi);
 
        /* 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 (s.to_read || s.non_overwrite || (s.to_write && s.failed) ||
-           (s.syncing && (s.uptodate + s.compute < disks)) || s.expanding)
-               handle_stripe_fill6(sh, &s, &r6s, disks);
+       if (s.to_read || s.non_overwrite
+           || (conf->level == 6 && s.to_write && s.failed)
+           || (s.syncing && (s.uptodate + s.compute < disks)) || s.expanding)
+               handle_stripe_fill(sh, &s, disks);
 
        /* Now we check to see if any write operations have recently
         * completed
         */
-       if (sh->reconstruct_state == reconstruct_state_drain_result) {
-
+       prexor = 0;
+       if (sh->reconstruct_state == reconstruct_state_prexor_drain_result)
+               prexor = 1;
+       if (sh->reconstruct_state == reconstruct_state_drain_result ||
+           sh->reconstruct_state == reconstruct_state_prexor_drain_result) {
                sh->reconstruct_state = reconstruct_state_idle;
-               /* All the 'written' buffers and the parity blocks are ready to
+
+               /* All the 'written' buffers and the parity block are ready to
                 * be written back to disk
                 */
                BUG_ON(!test_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags));
-               BUG_ON(!test_bit(R5_UPTODATE, &sh->dev[qd_idx].flags));
+               BUG_ON(sh->qd_idx >= 0 &&
+                      !test_bit(R5_UPTODATE, &sh->dev[sh->qd_idx].flags));
                for (i = disks; i--; ) {
-                       dev = &sh->dev[i];
+                       struct r5dev *dev = &sh->dev[i];
                        if (test_bit(R5_LOCKED, &dev->flags) &&
-                           (i == sh->pd_idx || i == qd_idx ||
-                            dev->written)) {
+                               (i == sh->pd_idx || i == sh->qd_idx ||
+                                dev->written)) {
                                pr_debug("Writing block %d\n", i);
-                               BUG_ON(!test_bit(R5_UPTODATE, &dev->flags));
                                set_bit(R5_Wantwrite, &dev->flags);
+                               if (prexor)
+                                       continue;
                                if (!test_bit(R5_Insync, &dev->flags) ||
-                                   ((i == sh->pd_idx || i == qd_idx) &&
-                                     s.failed == 0))
+                                   ((i == sh->pd_idx || i == sh->qd_idx)  &&
+                                    s.failed == 0))
                                        set_bit(STRIPE_INSYNC, &sh->state);
                        }
                }
                if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
-                       dec_preread_active = 1;
+                       s.dec_preread_active = 1;
        }
 
        /* Now to consider new write requests and what else, if anything
         * should be read.  We do not handle new writes when:
-        * 1/ A 'write' operation (copy+gen_syndrome) is already in flight.
+        * 1/ A 'write' operation (copy+xor) is already in flight.
         * 2/ A 'check' operation is in flight, as it may clobber the parity
         *    block.
         */
        if (s.to_write && !sh->reconstruct_state && !sh->check_state)
-               handle_stripe_dirtying6(conf, sh, &s, &r6s, disks);
+               handle_stripe_dirtying(conf, sh, &s, disks);
 
        /* 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
@@ -3494,20 +3252,24 @@ static void handle_stripe6(struct stripe_head *sh)
        if (sh->check_state ||
            (s.syncing && s.locked == 0 &&
             !test_bit(STRIPE_COMPUTE_RUN, &sh->state) &&
-            !test_bit(STRIPE_INSYNC, &sh->state)))
-               handle_parity_checks6(conf, sh, &s, &r6s, disks);
+            !test_bit(STRIPE_INSYNC, &sh->state))) {
+               if (conf->level == 6)
+                       handle_parity_checks6(conf, sh, &s, disks);
+               else
+                       handle_parity_checks5(conf, sh, &s, disks);
+       }
 
        if (s.syncing && s.locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
-               md_done_sync(conf->mddev, STRIPE_SECTORS,1);
+               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 (s.failed <= 2 && !conf->mddev->ro)
+       if (s.failed <= conf->max_degraded && !conf->mddev->ro)
                for (i = 0; i < s.failed; i++) {
-                       dev = &sh->dev[r6s.failed_num[i]];
+                       struct r5dev *dev = &sh->dev[s.failed_num[i]];
                        if (test_bit(R5_ReadError, &dev->flags)
                            && !test_bit(R5_LOCKED, &dev->flags)
                            && test_bit(R5_UPTODATE, &dev->flags)
@@ -3526,8 +3288,26 @@ static void handle_stripe6(struct stripe_head *sh)
                        }
                }
 
+
        /* Finish reconstruct operations initiated by the expansion process */
        if (sh->reconstruct_state == reconstruct_state_result) {
+               struct stripe_head *sh_src
+                       = get_active_stripe(conf, sh->sector, 1, 1, 1);
+               if (sh_src && test_bit(STRIPE_EXPAND_SOURCE, &sh_src->state)) {
+                       /* sh cannot be written until sh_src has been read.
+                        * so arrange for sh to be delayed a little
+                        */
+                       set_bit(STRIPE_DELAYED, &sh->state);
+                       set_bit(STRIPE_HANDLE, &sh->state);
+                       if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE,
+                                             &sh_src->state))
+                               atomic_inc(&conf->preread_active_stripes);
+                       release_stripe(sh_src);
+                       goto finish;
+               }
+               if (sh_src)
+                       release_stripe(sh_src);
+
                sh->reconstruct_state = reconstruct_state_idle;
                clear_bit(STRIPE_EXPANDING, &sh->state);
                for (i = conf->raid_disks; i--; ) {
@@ -3539,24 +3319,7 @@ static void handle_stripe6(struct stripe_head *sh)
 
        if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state) &&
            !sh->reconstruct_state) {
-               struct stripe_head *sh2
-                       = get_active_stripe(conf, sh->sector, 1, 1, 1);
-               if (sh2 && test_bit(STRIPE_EXPAND_SOURCE, &sh2->state)) {
-                       /* sh cannot be written until sh2 has been read.
-                        * so arrange for sh to be delayed a little
-                        */
-                       set_bit(STRIPE_DELAYED, &sh->state);
-                       set_bit(STRIPE_HANDLE, &sh->state);
-                       if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE,
-                                             &sh2->state))
-                               atomic_inc(&conf->preread_active_stripes);
-                       release_stripe(sh2);
-                       goto unlock;
-               }
-               if (sh2)
-                       release_stripe(sh2);
-
-               /* Need to write out all blocks after computing P&Q */
+               /* Need to write out all blocks after computing parity */
                sh->disks = conf->raid_disks;
                stripe_set_idx(sh->sector, conf, 0, sh);
                schedule_reconstruction(sh, &s, 1, 1);
@@ -3569,22 +3332,39 @@ static void handle_stripe6(struct stripe_head *sh)
 
        if (s.expanding && s.locked == 0 &&
            !test_bit(STRIPE_COMPUTE_RUN, &sh->state))
-               handle_stripe_expansion(conf, sh, &r6s);
-
- unlock:
-       spin_unlock(&sh->lock);
+               handle_stripe_expansion(conf, sh);
 
+finish:
        /* wait for this device to become unblocked */
-       if (unlikely(blocked_rdev))
-               md_wait_for_blocked_rdev(blocked_rdev, conf->mddev);
+       if (unlikely(s.blocked_rdev))
+               md_wait_for_blocked_rdev(s.blocked_rdev, conf->mddev);
+
+       if (s.handle_bad_blocks)
+               for (i = disks; i--; ) {
+                       mdk_rdev_t *rdev;
+                       struct r5dev *dev = &sh->dev[i];
+                       if (test_and_clear_bit(R5_WriteError, &dev->flags)) {
+                               /* We own a safe reference to the rdev */
+                               rdev = conf->disks[i].rdev;
+                               if (!rdev_set_badblocks(rdev, sh->sector,
+                                                       STRIPE_SECTORS, 0))
+                                       md_error(conf->mddev, rdev);
+                               rdev_dec_pending(rdev, conf->mddev);
+                       }
+                       if (test_and_clear_bit(R5_MadeGood, &dev->flags)) {
+                               rdev = conf->disks[i].rdev;
+                               rdev_clear_badblocks(rdev, sh->sector,
+                                                    STRIPE_SECTORS);
+                               rdev_dec_pending(rdev, conf->mddev);
+                       }
+               }
 
        if (s.ops_request)
                raid_run_ops(sh, s.ops_request);
 
        ops_run_io(sh, &s);
 
-
-       if (dec_preread_active) {
+       if (s.dec_preread_active) {
                /* We delay this until after ops_run_io so that if make_request
                 * is waiting on a flush, it won't continue until the writes
                 * have actually been submitted.
@@ -3595,15 +3375,9 @@ static void handle_stripe6(struct stripe_head *sh)
                        md_wakeup_thread(conf->mddev->thread);
        }
 
-       return_io(return_bi);
-}
+       return_io(s.return_bi);
 
-static void handle_stripe(struct stripe_head *sh)
-{
-       if (sh->raid_conf->level == 6)
-               handle_stripe6(sh);
-       else
-               handle_stripe5(sh);
+       clear_bit(STRIPE_ACTIVE, &sh->state);
 }
 
 static void raid5_activate_delayed(raid5_conf_t *conf)
@@ -3833,6 +3607,9 @@ static int chunk_aligned_read(mddev_t *mddev, struct bio * raid_bio)
        rcu_read_lock();
        rdev = rcu_dereference(conf->disks[dd_idx].rdev);
        if (rdev && test_bit(In_sync, &rdev->flags)) {
+               sector_t first_bad;
+               int bad_sectors;
+
                atomic_inc(&rdev->nr_pending);
                rcu_read_unlock();
                raid_bio->bi_next = (void*)rdev;
@@ -3840,8 +3617,10 @@ static int chunk_aligned_read(mddev_t *mddev, struct bio * raid_bio)
                align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
                align_bi->bi_sector += rdev->data_offset;
 
-               if (!bio_fits_rdev(align_bi)) {
-                       /* too big in some way */
+               if (!bio_fits_rdev(align_bi) ||
+                   is_badblock(rdev, align_bi->bi_sector, align_bi->bi_size>>9,
+                               &first_bad, &bad_sectors)) {
+                       /* too big in some way, or has a known bad block */
                        bio_put(align_bi);
                        rdev_dec_pending(rdev, mddev);
                        return 0;
@@ -4016,7 +3795,7 @@ static int make_request(mddev_t *mddev, struct bio * bi)
                                }
                        }
 
-                       if (bio_data_dir(bi) == WRITE &&
+                       if (rw == WRITE &&
                            logical_sector >= mddev->suspend_lo &&
                            logical_sector < mddev->suspend_hi) {
                                release_stripe(sh);
@@ -4034,7 +3813,7 @@ static int make_request(mddev_t *mddev, struct bio * bi)
                        }
 
                        if (test_bit(STRIPE_EXPANDING, &sh->state) ||
-                           !add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) {
+                           !add_stripe_bio(sh, bi, dd_idx, rw)) {
                                /* Stripe is busy expanding or
                                 * add failed due to overlap.  Flush everything
                                 * and wait a while
@@ -4375,10 +4154,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski
 
        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);
+       set_bit(STRIPE_SYNC_REQUESTED, &sh->state);
 
        handle_stripe(sh);
        release_stripe(sh);
@@ -4509,6 +4285,9 @@ static void raid5d(mddev_t *mddev)
                release_stripe(sh);
                cond_resched();
 
+               if (mddev->flags & ~(1<<MD_CHANGE_PENDING))
+                       md_check_recovery(mddev);
+
                spin_lock_irq(&conf->device_lock);
        }
        pr_debug("%d stripes handled\n", handled);
@@ -5313,6 +5092,7 @@ static int raid5_remove_disk(mddev_t *mddev, int number)
                 * isn't possible.
                 */
                if (!test_bit(Faulty, &rdev->flags) &&
+                   mddev->recovery_disabled != conf->recovery_disabled &&
                    !has_failed(conf) &&
                    number < conf->raid_disks) {
                        err = -EBUSY;
@@ -5341,6 +5121,9 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
        int first = 0;
        int last = conf->raid_disks - 1;
 
+       if (mddev->recovery_disabled == conf->recovery_disabled)
+               return -EBUSY;
+
        if (has_failed(conf))
                /* no point adding a device */
                return -EINVAL;
@@ -5519,16 +5302,14 @@ static int raid5_start_reshape(mddev_t *mddev)
                        if (rdev->raid_disk < 0 &&
                            !test_bit(Faulty, &rdev->flags)) {
                                if (raid5_add_disk(mddev, rdev) == 0) {
-                                       char nm[20];
                                        if (rdev->raid_disk
                                            >= conf->previous_raid_disks) {
                                                set_bit(In_sync, &rdev->flags);
                                                added_devices++;
                                        } else
                                                rdev->recovery_offset = 0;
-                                       sprintf(nm, "rd%d", rdev->raid_disk);
-                                       if (sysfs_create_link(&mddev->kobj,
-                                                             &rdev->kobj, nm))
+
+                                       if (sysfs_link_rdev(mddev, rdev))
                                                /* Failure here is OK */;
                                }
                        } else if (rdev->raid_disk >= conf->previous_raid_disks
@@ -5624,9 +5405,7 @@ static void raid5_finish_reshape(mddev_t *mddev)
                             d++) {
                                mdk_rdev_t *rdev = conf->disks[d].rdev;
                                if (rdev && raid5_remove_disk(mddev, d) == 0) {
-                                       char nm[20];
-                                       sprintf(nm, "rd%d", rdev->raid_disk);
-                                       sysfs_remove_link(&mddev->kobj, nm);
+                                       sysfs_unlink_rdev(mddev, rdev);
                                        rdev->raid_disk = -1;
                                }
                        }
index 3ca77a2613ba0a544ffa9c4aca4e12122d77cc96..11b9566184b2508cc5c5d892abae8e120df867b1 100644 (file)
@@ -6,11 +6,11 @@
 
 /*
  *
- * Each stripe contains one buffer per disc.  Each buffer can be in
+ * Each stripe contains one buffer per device.  Each buffer can be in
  * one of a number of states stored in "flags".  Changes between
- * these states happen *almost* exclusively under a per-stripe
- * spinlock.  Some very specific changes can happen in bi_end_io, and
- * these are not protected by the spin lock.
+ * these states happen *almost* exclusively under the protection of the
+ * STRIPE_ACTIVE flag.  Some very specific changes can happen in bi_end_io, and
+ * these are not protected by STRIPE_ACTIVE.
  *
  * The flag bits that are used to represent these states are:
  *   R5_UPTODATE and R5_LOCKED
  * block and the cached buffer are successfully written, any buffer on
  * a written list can be returned with b_end_io.
  *
- * The write list and read list both act as fifos.  The read list is
- * protected by the device_lock.  The write and written lists are
- * protected by the stripe lock.  The device_lock, which can be
- * claimed while the stipe lock is held, is only for list
- * manipulations and will only be held for a very short time.  It can
- * be claimed from interrupts.
+ * The write list and read list both act as fifos.  The read list,
+ * write list and written list are protected by the device_lock.
+ * The device_lock is only for list manipulations and will only be
+ * held for a very short time.  It can be claimed from interrupts.
  *
  *
  * Stripes in the stripe cache can be on one of two lists (or on
@@ -96,7 +94,6 @@
  *
  * The inactive_list, handle_list and hash bucket lists are all protected by the
  * device_lock.
- *  - stripes on the inactive_list never have their stripe_lock held.
  *  - stripes have a reference counter. If count==0, they are on a list.
  *  - If a stripe might need handling, STRIPE_HANDLE is set.
  *  - When refcount reaches zero, then if STRIPE_HANDLE it is put on
  *  attach a request to an active stripe (add_stripe_bh())
  *     lockdev attach-buffer unlockdev
  *  handle a stripe (handle_stripe())
- *     lockstripe clrSTRIPE_HANDLE ...
+ *     setSTRIPE_ACTIVE,  clrSTRIPE_HANDLE ...
  *             (lockdev check-buffers unlockdev) ..
  *             change-state ..
- *             record io/ops needed unlockstripe schedule io/ops
+ *             record io/ops needed clearSTRIPE_ACTIVE schedule io/ops
  *  release an active stripe (release_stripe())
  *     lockdev if (!--cnt) { if  STRIPE_HANDLE, add to handle_list else add to inactive-list } unlockdev
  *
  * on a cached buffer, and plus one if the stripe is undergoing stripe
  * operations.
  *
- * Stripe operations are performed outside the stripe lock,
- * the stripe operations are:
+ * The stripe operations are:
  * -copying data between the stripe cache and user application buffers
  * -computing blocks to save a disk access, or to recover a missing block
  * -updating the parity on a write operation (reconstruct write and
  */
 
 /*
- * Operations state - intermediate states that are visible outside of sh->lock
+ * Operations state - intermediate states that are visible outside of 
+ *   STRIPE_ACTIVE.
  * In general _idle indicates nothing is running, _run indicates a data
  * processing operation is active, and _result means the data processing result
  * is stable and can be acted upon.  For simple operations like biofill and
@@ -209,7 +206,6 @@ struct stripe_head {
        short                   ddf_layout;/* use DDF ordering to calculate Q */
        unsigned long           state;          /* state flags */
        atomic_t                count;        /* nr of active thread/requests */
-       spinlock_t              lock;
        int                     bm_seq; /* sequence number for bitmap flushes */
        int                     disks;          /* disks in stripe */
        enum check_states       check_state;
@@ -240,19 +236,20 @@ struct stripe_head {
 };
 
 /* stripe_head_state - collects and tracks the dynamic state of a stripe_head
- *     for handle_stripe.  It is only valid under spin_lock(sh->lock);
+ *     for handle_stripe.
  */
 struct stripe_head_state {
        int syncing, expanding, expanded;
        int locked, uptodate, to_read, to_write, failed, written;
        int to_fill, compute, req_compute, non_overwrite;
-       int failed_num;
+       int failed_num[2];
+       int p_failed, q_failed;
+       int dec_preread_active;
        unsigned long ops_request;
-};
 
-/* r6_state - extra state data only relevant to r6 */
-struct r6_state {
-       int p_failed, q_failed, failed_num[2];
+       struct bio *return_bi;
+       mdk_rdev_t *blocked_rdev;
+       int handle_bad_blocks;
 };
 
 /* Flags */
@@ -268,14 +265,16 @@ struct r6_state {
 #define        R5_ReWrite      9       /* have tried to over-write the readerror */
 
 #define        R5_Expanded     10      /* This block now has post-expand data */
-#define        R5_Wantcompute  11 /* compute_block in progress treat as
-                                   * uptodate
-                                   */
-#define        R5_Wantfill     12 /* dev->toread contains a bio that needs
-                                   * filling
-                                   */
-#define R5_Wantdrain   13 /* dev->towrite needs to be drained */
-#define R5_WantFUA     14      /* Write should be FUA */
+#define        R5_Wantcompute  11      /* compute_block in progress treat as
+                                * uptodate
+                                */
+#define        R5_Wantfill     12      /* dev->toread contains a bio that needs
+                                * filling
+                                */
+#define        R5_Wantdrain    13      /* dev->towrite needs to be drained */
+#define        R5_WantFUA      14      /* Write should be FUA */
+#define        R5_WriteError   15      /* got a write error - need to record it */
+#define        R5_MadeGood     16      /* A bad block has been fixed by writing to it*/
 /*
  * Write method
  */
@@ -289,21 +288,25 @@ struct r6_state {
 /*
  * Stripe state
  */
-#define STRIPE_HANDLE          2
-#define        STRIPE_SYNCING          3
-#define        STRIPE_INSYNC           4
-#define        STRIPE_PREREAD_ACTIVE   5
-#define        STRIPE_DELAYED          6
-#define        STRIPE_DEGRADED         7
-#define        STRIPE_BIT_DELAY        8
-#define        STRIPE_EXPANDING        9
-#define        STRIPE_EXPAND_SOURCE    10
-#define        STRIPE_EXPAND_READY     11
-#define        STRIPE_IO_STARTED       12 /* do not count towards 'bypass_count' */
-#define        STRIPE_FULL_WRITE       13 /* all blocks are set to be overwritten */
-#define        STRIPE_BIOFILL_RUN      14
-#define        STRIPE_COMPUTE_RUN      15
-#define        STRIPE_OPS_REQ_PENDING  16
+enum {
+       STRIPE_ACTIVE,
+       STRIPE_HANDLE,
+       STRIPE_SYNC_REQUESTED,
+       STRIPE_SYNCING,
+       STRIPE_INSYNC,
+       STRIPE_PREREAD_ACTIVE,
+       STRIPE_DELAYED,
+       STRIPE_DEGRADED,
+       STRIPE_BIT_DELAY,
+       STRIPE_EXPANDING,
+       STRIPE_EXPAND_SOURCE,
+       STRIPE_EXPAND_READY,
+       STRIPE_IO_STARTED,      /* do not count towards 'bypass_count' */
+       STRIPE_FULL_WRITE,      /* all blocks are set to be overwritten */
+       STRIPE_BIOFILL_RUN,
+       STRIPE_COMPUTE_RUN,
+       STRIPE_OPS_REQ_PENDING,
+};
 
 /*
  * Operation request flags
@@ -336,7 +339,7 @@ struct r6_state {
  * PREREAD_ACTIVE.
  * In stripe_handle, if we find pre-reading is necessary, we do it if
  * PREREAD_ACTIVE is set, else we set DELAYED which will send it to the delayed queue.
- * HANDLE gets cleared if stripe_handle leave nothing locked.
+ * HANDLE gets cleared if stripe_handle leaves nothing locked.
  */
 
 
@@ -399,7 +402,7 @@ struct raid5_private_data {
                                            * (fresh device added).
                                            * Cleared when a sync completes.
                                            */
-
+       int                     recovery_disabled;
        /* per cpu variables */
        struct raid5_percpu {
                struct page     *spare_page; /* Used when checking P/Q in raid6 */
index 6995940b633a92b1197249d9c3f593c15edf644f..9575db429df46648c25007a6de5395ef22e080f8 100644 (file)
@@ -68,7 +68,6 @@ config VIDEO_V4L2_SUBDEV_API
 
 config DVB_CORE
        tristate "DVB for Linux"
-       depends on NET && INET
        select CRC32
        help
          DVB core utility functions for device handling, software fallbacks etc.
@@ -85,6 +84,19 @@ config DVB_CORE
 
          If unsure say N.
 
+config DVB_NET
+       bool "DVB Network Support"
+       default (NET && INET)
+       depends on NET && INET && DVB_CORE
+       help
+         This option enables DVB Network Support which is a part of the DVB
+         standard. It is used, for example, by automatic firmware updates used
+         on Set-Top-Boxes. It can also be used to access the Internet via the
+         DVB card, if the network provider supports it.
+
+         You may want to disable the network support on embedded devices. If
+         unsure say Y.
+
 config VIDEO_MEDIA
        tristate
        default (DVB_CORE && (VIDEO_DEV = n)) || (VIDEO_DEV && (DVB_CORE = n)) || (DVB_CORE && VIDEO_DEV)
index 22d3ca36370ec63bc7c9725b228603bb1d1fb940..996302ae210e7b1fe9686a6425662d49f83c4dc3 100644 (file)
@@ -23,6 +23,7 @@ config MEDIA_TUNER
        depends on VIDEO_MEDIA && I2C
        select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE
@@ -152,6 +153,15 @@ config MEDIA_TUNER_XC5000
          This device is only used inside a SiP called together with a
          demodulator for now.
 
+config MEDIA_TUNER_XC4000
+       tristate "Xceive XC4000 silicon tuner"
+       depends on VIDEO_MEDIA && I2C
+       default m if MEDIA_TUNER_CUSTOMISE
+       help
+         A driver for the silicon tuner XC4000 from Xceive.
+         This device is only used inside a SiP called together with a
+         demodulator for now.
+
 config MEDIA_TUNER_MXL5005S
        tristate "MaxLinear MSL5005S silicon tuner"
        depends on VIDEO_MEDIA && I2C
index 2cb4f5327843eba24d9309a839829e0c17454414..20d24fca2cfbae8bea894665b7918bb890748d66 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o
 obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o
 obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
+obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o
 obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o
 obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
 obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
index afba6dc5e080396eb1aaade3c5d6ef0872251f08..94a603a60842d815d6a5ac2b271ce48b14eca974 100644 (file)
@@ -1805,6 +1805,10 @@ struct tunertype tuners[] = {
                .name   = "Xceive 5000 tuner",
                /* see xc5000.c for details */
        },
+       [TUNER_XC4000] = { /* Xceive 4000 */
+               .name   = "Xceive 4000 tuner",
+               /* see xc4000.c for details */
+       },
        [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */
                .name   = "TCL tuner MF02GIP-5N-E",
                .params = tuner_tcl_mf02gip_5n_params,
diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c
new file mode 100644 (file)
index 0000000..634f4d9
--- /dev/null
@@ -0,0 +1,1691 @@
+/*
+ *  Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Xceive Corporation
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
+ *  Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it>
+ *  Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu>
+ *
+ *  This 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/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <asm/unaligned.h>
+
+#include "dvb_frontend.h"
+
+#include "xc4000.h"
+#include "tuner-i2c.h"
+#include "tuner-xc2028-types.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off)).");
+
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, "
+       "0 (default): use device-specific default mode).");
+
+static int audio_std;
+module_param(audio_std, int, 0644);
+MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly "
+       "needs to know what audio standard is needed for some video standards "
+       "with audio A2 or NICAM. The valid settings are a sum of:\n"
+       " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n"
+       " 2: use A2 instead of NICAM or BTSC\n"
+       " 4: use SECAM/K3 instead of K1\n"
+       " 8: use PAL-D/K audio for SECAM-D/K\n"
+       "16: use FM radio input 1 instead of input 2\n"
+       "32: use mono audio (the lower three bits are ignored)");
+
+static char firmware_name[30];
+module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
+MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
+       "default firmware name.");
+
+static DEFINE_MUTEX(xc4000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+       printk(KERN_INFO "%s: " fmt, "xc4000", ## arg)
+
+/* struct for storing firmware table */
+struct firmware_description {
+       unsigned int  type;
+       v4l2_std_id   id;
+       __u16         int_freq;
+       unsigned char *ptr;
+       unsigned int  size;
+};
+
+struct firmware_properties {
+       unsigned int    type;
+       v4l2_std_id     id;
+       v4l2_std_id     std_req;
+       __u16           int_freq;
+       unsigned int    scode_table;
+       int             scode_nr;
+};
+
+struct xc4000_priv {
+       struct tuner_i2c_props i2c_props;
+       struct list_head hybrid_tuner_instance_list;
+       struct firmware_description *firm;
+       int     firm_size;
+       u32     if_khz;
+       u32     freq_hz;
+       u32     bandwidth;
+       u8      video_standard;
+       u8      rf_mode;
+       u8      default_pm;
+       u8      dvb_amplitude;
+       u8      set_smoothedcvbs;
+       u8      ignore_i2c_write_errors;
+       __u16   firm_version;
+       struct firmware_properties cur_fw;
+       __u16   hwmodel;
+       __u16   hwvers;
+       struct mutex    lock;
+};
+
+#define XC4000_AUDIO_STD_B              1
+#define XC4000_AUDIO_STD_A2             2
+#define XC4000_AUDIO_STD_K3             4
+#define XC4000_AUDIO_STD_L              8
+#define XC4000_AUDIO_STD_INPUT1                16
+#define XC4000_AUDIO_STD_MONO          32
+
+#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw"
+
+/* Misc Defines */
+#define MAX_TV_STANDARD                        24
+#define XC_MAX_I2C_WRITE_LENGTH                64
+#define XC_POWERED_DOWN                        0x80000000U
+
+/* Signal Types */
+#define XC_RF_MODE_AIR                 0
+#define XC_RF_MODE_CABLE               1
+
+/* Product id */
+#define XC_PRODUCT_ID_FW_NOT_LOADED    0x2000
+#define XC_PRODUCT_ID_XC4000           0x0FA0
+#define XC_PRODUCT_ID_XC4100           0x1004
+
+/* Registers (Write-only) */
+#define XREG_INIT         0x00
+#define XREG_VIDEO_MODE   0x01
+#define XREG_AUDIO_MODE   0x02
+#define XREG_RF_FREQ      0x03
+#define XREG_D_CODE       0x04
+#define XREG_DIRECTSITTING_MODE 0x05
+#define XREG_SEEK_MODE    0x06
+#define XREG_POWER_DOWN   0x08
+#define XREG_SIGNALSOURCE 0x0A
+#define XREG_SMOOTHEDCVBS 0x0E
+#define XREG_AMPLITUDE    0x10
+
+/* Registers (Read-only) */
+#define XREG_ADC_ENV      0x00
+#define XREG_QUALITY      0x01
+#define XREG_FRAME_LINES  0x02
+#define XREG_HSYNC_FREQ   0x03
+#define XREG_LOCK         0x04
+#define XREG_FREQ_ERROR   0x05
+#define XREG_SNR          0x06
+#define XREG_VERSION      0x07
+#define XREG_PRODUCT_ID   0x08
+
+/*
+   Basic firmware description. This will remain with
+   the driver for documentation purposes.
+
+   This represents an I2C firmware file encoded as a
+   string of unsigned char. Format is as follows:
+
+   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
+   char[1  ]=len0_LSB  -> length of first write transaction
+   char[2  ]=data0 -> first byte to be sent
+   char[3  ]=data1
+   char[4  ]=data2
+   char[   ]=...
+   char[M  ]=dataN  -> last byte to be sent
+   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
+   char[M+2]=len1_LSB  -> length of second write transaction
+   char[M+3]=data0
+   char[M+4]=data1
+   ...
+   etc.
+
+   The [len] value should be interpreted as follows:
+
+   len= len_MSB _ len_LSB
+   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
+   len=0000_0000_0000_0000   : Reset command: Do hardware reset
+   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
+   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
+
+   For the RESET and WAIT commands, the two following bytes will contain
+   immediately the length of the following transaction.
+*/
+
+struct XC_TV_STANDARD {
+       const char  *Name;
+       u16         audio_mode;
+       u16         video_mode;
+       u16         int_freq;
+};
+
+/* Tuner standards */
+#define XC4000_MN_NTSC_PAL_BTSC                0
+#define XC4000_MN_NTSC_PAL_A2          1
+#define XC4000_MN_NTSC_PAL_EIAJ                2
+#define XC4000_MN_NTSC_PAL_Mono                3
+#define XC4000_BG_PAL_A2               4
+#define XC4000_BG_PAL_NICAM            5
+#define XC4000_BG_PAL_MONO             6
+#define XC4000_I_PAL_NICAM             7
+#define XC4000_I_PAL_NICAM_MONO                8
+#define XC4000_DK_PAL_A2               9
+#define XC4000_DK_PAL_NICAM            10
+#define XC4000_DK_PAL_MONO             11
+#define XC4000_DK_SECAM_A2DK1          12
+#define XC4000_DK_SECAM_A2LDK3         13
+#define XC4000_DK_SECAM_A2MONO         14
+#define XC4000_DK_SECAM_NICAM          15
+#define XC4000_L_SECAM_NICAM           16
+#define XC4000_LC_SECAM_NICAM          17
+#define XC4000_DTV6                    18
+#define XC4000_DTV8                    19
+#define XC4000_DTV7_8                  20
+#define XC4000_DTV7                    21
+#define XC4000_FM_Radio_INPUT2         22
+#define XC4000_FM_Radio_INPUT1         23
+
+static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = {
+       {"M/N-NTSC/PAL-BTSC",   0x0000, 0x80A0, 4500},
+       {"M/N-NTSC/PAL-A2",     0x0000, 0x80A0, 4600},
+       {"M/N-NTSC/PAL-EIAJ",   0x0040, 0x80A0, 4500},
+       {"M/N-NTSC/PAL-Mono",   0x0078, 0x80A0, 4500},
+       {"B/G-PAL-A2",          0x0000, 0x8159, 5640},
+       {"B/G-PAL-NICAM",       0x0004, 0x8159, 5740},
+       {"B/G-PAL-MONO",        0x0078, 0x8159, 5500},
+       {"I-PAL-NICAM",         0x0080, 0x8049, 6240},
+       {"I-PAL-NICAM-MONO",    0x0078, 0x8049, 6000},
+       {"D/K-PAL-A2",          0x0000, 0x8049, 6380},
+       {"D/K-PAL-NICAM",       0x0080, 0x8049, 6200},
+       {"D/K-PAL-MONO",        0x0078, 0x8049, 6500},
+       {"D/K-SECAM-A2 DK1",    0x0000, 0x8049, 6340},
+       {"D/K-SECAM-A2 L/DK3",  0x0000, 0x8049, 6000},
+       {"D/K-SECAM-A2 MONO",   0x0078, 0x8049, 6500},
+       {"D/K-SECAM-NICAM",     0x0080, 0x8049, 6200},
+       {"L-SECAM-NICAM",       0x8080, 0x0009, 6200},
+       {"L'-SECAM-NICAM",      0x8080, 0x4009, 6200},
+       {"DTV6",                0x00C0, 0x8002,    0},
+       {"DTV8",                0x00C0, 0x800B,    0},
+       {"DTV7/8",              0x00C0, 0x801B,    0},
+       {"DTV7",                0x00C0, 0x8007,    0},
+       {"FM Radio-INPUT2",     0x0008, 0x9800, 10700},
+       {"FM Radio-INPUT1",     0x0008, 0x9000, 10700}
+};
+
+static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val);
+static int xc4000_tuner_reset(struct dvb_frontend *fe);
+static void xc_debug_dump(struct xc4000_priv *priv);
+
+static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len)
+{
+       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+                              .flags = 0, .buf = buf, .len = len };
+       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+               if (priv->ignore_i2c_write_errors == 0) {
+                       printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n",
+                              len);
+                       if (len == 4) {
+                               printk(KERN_ERR "bytes %02x %02x %02x %02x\n", buf[0],
+                                      buf[1], buf[2], buf[3]);
+                       }
+                       return -EREMOTEIO;
+               }
+       }
+       return 0;
+}
+
+static int xc4000_tuner_reset(struct dvb_frontend *fe)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       int ret;
+
+       dprintk(1, "%s()\n", __func__);
+
+       if (fe->callback) {
+               ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+                                          fe->dvb->priv :
+                                          priv->i2c_props.adap->algo_data,
+                                          DVB_FRONTEND_COMPONENT_TUNER,
+                                          XC4000_TUNER_RESET, 0);
+               if (ret) {
+                       printk(KERN_ERR "xc4000: reset failed\n");
+                       return -EREMOTEIO;
+               }
+       } else {
+               printk(KERN_ERR "xc4000: no tuner reset callback function, "
+                               "fatal\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData)
+{
+       u8 buf[4];
+       int result;
+
+       buf[0] = (regAddr >> 8) & 0xFF;
+       buf[1] = regAddr & 0xFF;
+       buf[2] = (i2cData >> 8) & 0xFF;
+       buf[3] = i2cData & 0xFF;
+       result = xc_send_i2c_data(priv, buf, 4);
+
+       return result;
+}
+
+static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+
+       int i, nbytes_to_send, result;
+       unsigned int len, pos, index;
+       u8 buf[XC_MAX_I2C_WRITE_LENGTH];
+
+       index = 0;
+       while ((i2c_sequence[index] != 0xFF) ||
+               (i2c_sequence[index + 1] != 0xFF)) {
+               len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
+               if (len == 0x0000) {
+                       /* RESET command */
+                       /* NOTE: this is ignored, as the reset callback was */
+                       /* already called by check_firmware() */
+                       index += 2;
+               } else if (len & 0x8000) {
+                       /* WAIT command */
+                       msleep(len & 0x7FFF);
+                       index += 2;
+               } else {
+                       /* Send i2c data whilst ensuring individual transactions
+                        * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
+                        */
+                       index += 2;
+                       buf[0] = i2c_sequence[index];
+                       buf[1] = i2c_sequence[index + 1];
+                       pos = 2;
+                       while (pos < len) {
+                               if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
+                                       nbytes_to_send =
+                                               XC_MAX_I2C_WRITE_LENGTH;
+                               else
+                                       nbytes_to_send = (len - pos + 2);
+                               for (i = 2; i < nbytes_to_send; i++) {
+                                       buf[i] = i2c_sequence[index + pos +
+                                               i - 2];
+                               }
+                               result = xc_send_i2c_data(priv, buf,
+                                       nbytes_to_send);
+
+                               if (result != 0)
+                                       return result;
+
+                               pos += nbytes_to_send - 2;
+                       }
+                       index += len;
+               }
+       }
+       return 0;
+}
+
+static int xc_set_tv_standard(struct xc4000_priv *priv,
+       u16 video_mode, u16 audio_mode)
+{
+       int ret;
+       dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode);
+       dprintk(1, "%s() Standard = %s\n",
+               __func__,
+               xc4000_standard[priv->video_standard].Name);
+
+       /* Don't complain when the request fails because of i2c stretching */
+       priv->ignore_i2c_write_errors = 1;
+
+       ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode);
+       if (ret == 0)
+               ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode);
+
+       priv->ignore_i2c_write_errors = 0;
+
+       return ret;
+}
+
+static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode)
+{
+       dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
+               rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
+
+       if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
+               rf_mode = XC_RF_MODE_CABLE;
+               printk(KERN_ERR
+                       "%s(), Invalid mode, defaulting to CABLE",
+                       __func__);
+       }
+       return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
+}
+
+static const struct dvb_tuner_ops xc4000_tuner_ops;
+
+static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz)
+{
+       u16 freq_code;
+
+       dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+       if ((freq_hz > xc4000_tuner_ops.info.frequency_max) ||
+           (freq_hz < xc4000_tuner_ops.info.frequency_min))
+               return -EINVAL;
+
+       freq_code = (u16)(freq_hz / 15625);
+
+       /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the
+          FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
+          only be used for fast scanning for channel lock) */
+       /* WAS: XREG_FINERFREQ */
+       return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+}
+
+static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope)
+{
+       return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope);
+}
+
+static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz)
+{
+       int result;
+       u16 regData;
+       u32 tmp;
+
+       result = xc4000_readreg(priv, XREG_FREQ_ERROR, &regData);
+       if (result != 0)
+               return result;
+
+       tmp = (u32)regData & 0xFFFFU;
+       tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp);
+       (*freq_error_hz) = tmp * 15625;
+       return result;
+}
+
+static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status)
+{
+       return xc4000_readreg(priv, XREG_LOCK, lock_status);
+}
+
+static int xc_get_version(struct xc4000_priv *priv,
+       u8 *hw_majorversion, u8 *hw_minorversion,
+       u8 *fw_majorversion, u8 *fw_minorversion)
+{
+       u16 data;
+       int result;
+
+       result = xc4000_readreg(priv, XREG_VERSION, &data);
+       if (result != 0)
+               return result;
+
+       (*hw_majorversion) = (data >> 12) & 0x0F;
+       (*hw_minorversion) = (data >>  8) & 0x0F;
+       (*fw_majorversion) = (data >>  4) & 0x0F;
+       (*fw_minorversion) = data & 0x0F;
+
+       return 0;
+}
+
+static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz)
+{
+       u16 regData;
+       int result;
+
+       result = xc4000_readreg(priv, XREG_HSYNC_FREQ, &regData);
+       if (result != 0)
+               return result;
+
+       (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+       return result;
+}
+
+static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines)
+{
+       return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines);
+}
+
+static int xc_get_quality(struct xc4000_priv *priv, u16 *quality)
+{
+       return xc4000_readreg(priv, XREG_QUALITY, quality);
+}
+
+static u16 xc_wait_for_lock(struct xc4000_priv *priv)
+{
+       u16     lock_state = 0;
+       int     watchdog_count = 40;
+
+       while ((lock_state == 0) && (watchdog_count > 0)) {
+               xc_get_lock_status(priv, &lock_state);
+               if (lock_state != 1) {
+                       msleep(5);
+                       watchdog_count--;
+               }
+       }
+       return lock_state;
+}
+
+static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz)
+{
+       int     found = 1;
+       int     result;
+
+       dprintk(1, "%s(%u)\n", __func__, freq_hz);
+
+       /* Don't complain when the request fails because of i2c stretching */
+       priv->ignore_i2c_write_errors = 1;
+       result = xc_set_rf_frequency(priv, freq_hz);
+       priv->ignore_i2c_write_errors = 0;
+
+       if (result != 0)
+               return 0;
+
+       /* wait for lock only in analog TV mode */
+       if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) {
+               if (xc_wait_for_lock(priv) != 1)
+                       found = 0;
+       }
+
+       /* Wait for stats to stabilize.
+        * Frame Lines needs two frame times after initial lock
+        * before it is valid.
+        */
+       msleep(debug ? 100 : 10);
+
+       if (debug)
+               xc_debug_dump(priv);
+
+       return found;
+}
+
+static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val)
+{
+       u8 buf[2] = { reg >> 8, reg & 0xff };
+       u8 bval[2] = { 0, 0 };
+       struct i2c_msg msg[2] = {
+               { .addr = priv->i2c_props.addr,
+                       .flags = 0, .buf = &buf[0], .len = 2 },
+               { .addr = priv->i2c_props.addr,
+                       .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+       };
+
+       if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
+               printk(KERN_ERR "xc4000: I2C read failed\n");
+               return -EREMOTEIO;
+       }
+
+       *val = (bval[0] << 8) | bval[1];
+       return 0;
+}
+
+#define dump_firm_type(t)      dump_firm_type_and_int_freq(t, 0)
+static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+{
+        if (type & BASE)
+               printk(KERN_CONT "BASE ");
+        if (type & INIT1)
+               printk(KERN_CONT "INIT1 ");
+        if (type & F8MHZ)
+               printk(KERN_CONT "F8MHZ ");
+        if (type & MTS)
+               printk(KERN_CONT "MTS ");
+        if (type & D2620)
+               printk(KERN_CONT "D2620 ");
+        if (type & D2633)
+               printk(KERN_CONT "D2633 ");
+        if (type & DTV6)
+               printk(KERN_CONT "DTV6 ");
+        if (type & QAM)
+               printk(KERN_CONT "QAM ");
+        if (type & DTV7)
+               printk(KERN_CONT "DTV7 ");
+        if (type & DTV78)
+               printk(KERN_CONT "DTV78 ");
+        if (type & DTV8)
+               printk(KERN_CONT "DTV8 ");
+        if (type & FM)
+               printk(KERN_CONT "FM ");
+        if (type & INPUT1)
+               printk(KERN_CONT "INPUT1 ");
+        if (type & LCD)
+               printk(KERN_CONT "LCD ");
+        if (type & NOGD)
+               printk(KERN_CONT "NOGD ");
+        if (type & MONO)
+               printk(KERN_CONT "MONO ");
+        if (type & ATSC)
+               printk(KERN_CONT "ATSC ");
+        if (type & IF)
+               printk(KERN_CONT "IF ");
+        if (type & LG60)
+               printk(KERN_CONT "LG60 ");
+        if (type & ATI638)
+               printk(KERN_CONT "ATI638 ");
+        if (type & OREN538)
+               printk(KERN_CONT "OREN538 ");
+        if (type & OREN36)
+               printk(KERN_CONT "OREN36 ");
+        if (type & TOYOTA388)
+               printk(KERN_CONT "TOYOTA388 ");
+        if (type & TOYOTA794)
+               printk(KERN_CONT "TOYOTA794 ");
+        if (type & DIBCOM52)
+               printk(KERN_CONT "DIBCOM52 ");
+        if (type & ZARLINK456)
+               printk(KERN_CONT "ZARLINK456 ");
+        if (type & CHINA)
+               printk(KERN_CONT "CHINA ");
+        if (type & F6MHZ)
+               printk(KERN_CONT "F6MHZ ");
+        if (type & INPUT2)
+               printk(KERN_CONT "INPUT2 ");
+        if (type & SCODE)
+               printk(KERN_CONT "SCODE ");
+        if (type & HAS_IF)
+               printk(KERN_CONT "HAS_IF_%d ", int_freq);
+}
+
+static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       int             i, best_i = -1;
+       unsigned int    best_nr_diffs = 255U;
+
+       if (!priv->firm) {
+               printk(KERN_ERR "Error! firmware not loaded\n");
+               return -EINVAL;
+       }
+
+       if (((type & ~SCODE) == 0) && (*id == 0))
+               *id = V4L2_STD_PAL;
+
+       /* Seek for generic video standard match */
+       for (i = 0; i < priv->firm_size; i++) {
+               v4l2_std_id     id_diff_mask =
+                       (priv->firm[i].id ^ (*id)) & (*id);
+               unsigned int    type_diff_mask =
+                       (priv->firm[i].type ^ type)
+                       & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE);
+               unsigned int    nr_diffs;
+
+               if (type_diff_mask
+                   & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE))
+                       continue;
+
+               nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask);
+               if (!nr_diffs)  /* Supports all the requested standards */
+                       goto found;
+
+               if (nr_diffs < best_nr_diffs) {
+                       best_nr_diffs = nr_diffs;
+                       best_i = i;
+               }
+       }
+
+       /* FIXME: Would make sense to seek for type "hint" match ? */
+       if (best_i < 0) {
+               i = -ENOENT;
+               goto ret;
+       }
+
+       if (best_nr_diffs > 0U) {
+               printk(KERN_WARNING
+                      "Selecting best matching firmware (%u bits differ) for "
+                      "type=(%x), id %016llx:\n",
+                      best_nr_diffs, type, (unsigned long long)*id);
+               i = best_i;
+       }
+
+found:
+       *id = priv->firm[i].id;
+
+ret:
+       if (debug) {
+               printk(KERN_DEBUG "%s firmware for type=",
+                      (i < 0) ? "Can't find" : "Found");
+               dump_firm_type(type);
+               printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id);
+       }
+       return i;
+}
+
+static int load_firmware(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       int                pos, rc;
+       unsigned char      *p;
+
+       pos = seek_firmware(fe, type, id);
+       if (pos < 0)
+               return pos;
+
+       p = priv->firm[pos].ptr;
+
+       /* Don't complain when the request fails because of i2c stretching */
+       priv->ignore_i2c_write_errors = 1;
+
+       rc = xc_load_i2c_sequence(fe, p);
+
+       priv->ignore_i2c_write_errors = 0;
+
+       return rc;
+}
+
+static int xc4000_fwupload(struct dvb_frontend *fe)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       const struct firmware *fw   = NULL;
+       const unsigned char   *p, *endp;
+       int                   rc = 0;
+       int                   n, n_array;
+       char                  name[33];
+       const char            *fname;
+
+       if (firmware_name[0] != '\0')
+               fname = firmware_name;
+       else
+               fname = XC4000_DEFAULT_FIRMWARE;
+
+       dprintk(1, "Reading firmware %s\n", fname);
+       rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
+       if (rc < 0) {
+               if (rc == -ENOENT)
+                       printk(KERN_ERR "Error: firmware %s not found.\n", fname);
+               else
+                       printk(KERN_ERR "Error %d while requesting firmware %s\n",
+                              rc, fname);
+
+               return rc;
+       }
+       p = fw->data;
+       endp = p + fw->size;
+
+       if (fw->size < sizeof(name) - 1 + 2 + 2) {
+               printk(KERN_ERR "Error: firmware file %s has invalid size!\n",
+                      fname);
+               goto corrupt;
+       }
+
+       memcpy(name, p, sizeof(name) - 1);
+       name[sizeof(name) - 1] = '\0';
+       p += sizeof(name) - 1;
+
+       priv->firm_version = get_unaligned_le16(p);
+       p += 2;
+
+       n_array = get_unaligned_le16(p);
+       p += 2;
+
+       dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n",
+               n_array, fname, name,
+               priv->firm_version >> 8, priv->firm_version & 0xff);
+
+       priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
+       if (priv->firm == NULL) {
+               printk(KERN_ERR "Not enough memory to load firmware file.\n");
+               rc = -ENOMEM;
+               goto done;
+       }
+       priv->firm_size = n_array;
+
+       n = -1;
+       while (p < endp) {
+               __u32 type, size;
+               v4l2_std_id id;
+               __u16 int_freq = 0;
+
+               n++;
+               if (n >= n_array) {
+                       printk(KERN_ERR "More firmware images in file than "
+                              "were expected!\n");
+                       goto corrupt;
+               }
+
+               /* Checks if there's enough bytes to read */
+               if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
+                       goto header;
+
+               type = get_unaligned_le32(p);
+               p += sizeof(type);
+
+               id = get_unaligned_le64(p);
+               p += sizeof(id);
+
+               if (type & HAS_IF) {
+                       int_freq = get_unaligned_le16(p);
+                       p += sizeof(int_freq);
+                       if (endp - p < sizeof(size))
+                               goto header;
+               }
+
+               size = get_unaligned_le32(p);
+               p += sizeof(size);
+
+               if (!size || size > endp - p) {
+                       printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n",
+                              type, (unsigned long long)id,
+                              (unsigned)(endp - p), size);
+                       goto corrupt;
+               }
+
+               priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
+               if (priv->firm[n].ptr == NULL) {
+                       printk(KERN_ERR "Not enough memory to load firmware file.\n");
+                       rc = -ENOMEM;
+                       goto done;
+               }
+
+               if (debug) {
+                       printk(KERN_DEBUG "Reading firmware type ");
+                       dump_firm_type_and_int_freq(type, int_freq);
+                       printk(KERN_DEBUG "(%x), id %llx, size=%d.\n",
+                              type, (unsigned long long)id, size);
+               }
+
+               memcpy(priv->firm[n].ptr, p, size);
+               priv->firm[n].type = type;
+               priv->firm[n].id   = id;
+               priv->firm[n].size = size;
+               priv->firm[n].int_freq = int_freq;
+
+               p += size;
+       }
+
+       if (n + 1 != priv->firm_size) {
+               printk(KERN_ERR "Firmware file is incomplete!\n");
+               goto corrupt;
+       }
+
+       goto done;
+
+header:
+       printk(KERN_ERR "Firmware header is incomplete!\n");
+corrupt:
+       rc = -EINVAL;
+       printk(KERN_ERR "Error: firmware file is corrupted!\n");
+
+done:
+       release_firmware(fw);
+       if (rc == 0)
+               dprintk(1, "Firmware files loaded.\n");
+
+       return rc;
+}
+
+static int load_scode(struct dvb_frontend *fe, unsigned int type,
+                        v4l2_std_id *id, __u16 int_freq, int scode)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       int             pos, rc;
+       unsigned char   *p;
+       u8              scode_buf[13];
+       u8              indirect_mode[5];
+
+       dprintk(1, "%s called int_freq=%d\n", __func__, int_freq);
+
+       if (!int_freq) {
+               pos = seek_firmware(fe, type, id);
+               if (pos < 0)
+                       return pos;
+       } else {
+               for (pos = 0; pos < priv->firm_size; pos++) {
+                       if ((priv->firm[pos].int_freq == int_freq) &&
+                           (priv->firm[pos].type & HAS_IF))
+                               break;
+               }
+               if (pos == priv->firm_size)
+                       return -ENOENT;
+       }
+
+       p = priv->firm[pos].ptr;
+
+       if (priv->firm[pos].size != 12 * 16 || scode >= 16)
+               return -EINVAL;
+       p += 12 * scode;
+
+       if (debug) {
+               tuner_info("Loading SCODE for type=");
+               dump_firm_type_and_int_freq(priv->firm[pos].type,
+                                           priv->firm[pos].int_freq);
+               printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type,
+                      (unsigned long long)*id);
+       }
+
+       scode_buf[0] = 0x00;
+       memcpy(&scode_buf[1], p, 12);
+
+       /* Enter direct-mode */
+       rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0);
+       if (rc < 0) {
+               printk(KERN_ERR "failed to put device into direct mode!\n");
+               return -EIO;
+       }
+
+       rc = xc_send_i2c_data(priv, scode_buf, 13);
+       if (rc != 0) {
+               /* Even if the send failed, make sure we set back to indirect
+                  mode */
+               printk(KERN_ERR "Failed to set scode %d\n", rc);
+       }
+
+       /* Switch back to indirect-mode */
+       memset(indirect_mode, 0, sizeof(indirect_mode));
+       indirect_mode[4] = 0x88;
+       xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode));
+       msleep(10);
+
+       return 0;
+}
+
+static int check_firmware(struct dvb_frontend *fe, unsigned int type,
+                         v4l2_std_id std, __u16 int_freq)
+{
+       struct xc4000_priv         *priv = fe->tuner_priv;
+       struct firmware_properties new_fw;
+       int                        rc = 0, is_retry = 0;
+       u16                        hwmodel;
+       v4l2_std_id                std0;
+       u8                         hw_major, hw_minor, fw_major, fw_minor;
+
+       dprintk(1, "%s called\n", __func__);
+
+       if (!priv->firm) {
+               rc = xc4000_fwupload(fe);
+               if (rc < 0)
+                       return rc;
+       }
+
+retry:
+       new_fw.type = type;
+       new_fw.id = std;
+       new_fw.std_req = std;
+       new_fw.scode_table = SCODE;
+       new_fw.scode_nr = 0;
+       new_fw.int_freq = int_freq;
+
+       dprintk(1, "checking firmware, user requested type=");
+       if (debug) {
+               dump_firm_type(new_fw.type);
+               printk(KERN_CONT "(%x), id %016llx, ", new_fw.type,
+                      (unsigned long long)new_fw.std_req);
+               if (!int_freq)
+                       printk(KERN_CONT "scode_tbl ");
+               else
+                       printk(KERN_CONT "int_freq %d, ", new_fw.int_freq);
+               printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr);
+       }
+
+       /* No need to reload base firmware if it matches */
+       if (priv->cur_fw.type & BASE) {
+               dprintk(1, "BASE firmware not changed.\n");
+               goto skip_base;
+       }
+
+       /* Updating BASE - forget about all currently loaded firmware */
+       memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+
+       /* Reset is needed before loading firmware */
+       rc = xc4000_tuner_reset(fe);
+       if (rc < 0)
+               goto fail;
+
+       /* BASE firmwares are all std0 */
+       std0 = 0;
+       rc = load_firmware(fe, BASE, &std0);
+       if (rc < 0) {
+               printk(KERN_ERR "Error %d while loading base firmware\n", rc);
+               goto fail;
+       }
+
+       /* Load INIT1, if needed */
+       dprintk(1, "Load init1 firmware, if exists\n");
+
+       rc = load_firmware(fe, BASE | INIT1, &std0);
+       if (rc == -ENOENT)
+               rc = load_firmware(fe, BASE | INIT1, &std0);
+       if (rc < 0 && rc != -ENOENT) {
+               tuner_err("Error %d while loading init1 firmware\n",
+                         rc);
+               goto fail;
+       }
+
+skip_base:
+       /*
+        * No need to reload standard specific firmware if base firmware
+        * was not reloaded and requested video standards have not changed.
+        */
+       if (priv->cur_fw.type == (BASE | new_fw.type) &&
+           priv->cur_fw.std_req == std) {
+               dprintk(1, "Std-specific firmware already loaded.\n");
+               goto skip_std_specific;
+       }
+
+       /* Reloading std-specific firmware forces a SCODE update */
+       priv->cur_fw.scode_table = 0;
+
+       /* Load the standard firmware */
+       rc = load_firmware(fe, new_fw.type, &new_fw.id);
+
+       if (rc < 0)
+               goto fail;
+
+skip_std_specific:
+       if (priv->cur_fw.scode_table == new_fw.scode_table &&
+           priv->cur_fw.scode_nr == new_fw.scode_nr) {
+               dprintk(1, "SCODE firmware already loaded.\n");
+               goto check_device;
+       }
+
+       /* Load SCODE firmware, if exists */
+       rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
+                       new_fw.int_freq, new_fw.scode_nr);
+       if (rc != 0)
+               dprintk(1, "load scode failed %d\n", rc);
+
+check_device:
+       rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel);
+
+       if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major,
+                          &fw_minor) != 0) {
+               printk(KERN_ERR "Unable to read tuner registers.\n");
+               goto fail;
+       }
+
+       dprintk(1, "Device is Xceive %d version %d.%d, "
+               "firmware version %d.%d\n",
+               hwmodel, hw_major, hw_minor, fw_major, fw_minor);
+
+       /* Check firmware version against what we downloaded. */
+       if (priv->firm_version != ((fw_major << 8) | fw_minor)) {
+               printk(KERN_WARNING
+                      "Incorrect readback of firmware version %d.%d.\n",
+                      fw_major, fw_minor);
+               goto fail;
+       }
+
+       /* Check that the tuner hardware model remains consistent over time. */
+       if (priv->hwmodel == 0 &&
+           (hwmodel == XC_PRODUCT_ID_XC4000 ||
+            hwmodel == XC_PRODUCT_ID_XC4100)) {
+               priv->hwmodel = hwmodel;
+               priv->hwvers = (hw_major << 8) | hw_minor;
+       } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
+                  priv->hwvers != ((hw_major << 8) | hw_minor)) {
+               printk(KERN_WARNING
+                      "Read invalid device hardware information - tuner "
+                      "hung?\n");
+               goto fail;
+       }
+
+       memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
+
+       /*
+        * By setting BASE in cur_fw.type only after successfully loading all
+        * firmwares, we can:
+        * 1. Identify that BASE firmware with type=0 has been loaded;
+        * 2. Tell whether BASE firmware was just changed the next time through.
+        */
+       priv->cur_fw.type |= BASE;
+
+       return 0;
+
+fail:
+       memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+       if (!is_retry) {
+               msleep(50);
+               is_retry = 1;
+               dprintk(1, "Retrying firmware load\n");
+               goto retry;
+       }
+
+       if (rc == -ENOENT)
+               rc = -EINVAL;
+       return rc;
+}
+
+static void xc_debug_dump(struct xc4000_priv *priv)
+{
+       u16     adc_envelope;
+       u32     freq_error_hz = 0;
+       u16     lock_status;
+       u32     hsync_freq_hz = 0;
+       u16     frame_lines;
+       u16     quality;
+       u8      hw_majorversion = 0, hw_minorversion = 0;
+       u8      fw_majorversion = 0, fw_minorversion = 0;
+
+       xc_get_adc_envelope(priv, &adc_envelope);
+       dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
+
+       xc_get_frequency_error(priv, &freq_error_hz);
+       dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
+
+       xc_get_lock_status(priv, &lock_status);
+       dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
+               lock_status);
+
+       xc_get_version(priv, &hw_majorversion, &hw_minorversion,
+                      &fw_majorversion, &fw_minorversion);
+       dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+               hw_majorversion, hw_minorversion,
+               fw_majorversion, fw_minorversion);
+
+       if (priv->video_standard < XC4000_DTV6) {
+               xc_get_hsync_freq(priv, &hsync_freq_hz);
+               dprintk(1, "*** Horizontal sync frequency = %d Hz\n",
+                       hsync_freq_hz);
+
+               xc_get_frame_lines(priv, &frame_lines);
+               dprintk(1, "*** Frame lines = %d\n", frame_lines);
+       }
+
+       xc_get_quality(priv, &quality);
+       dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+}
+
+static int xc4000_set_params(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       unsigned int type;
+       int     ret = -EREMOTEIO;
+
+       dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
+
+       mutex_lock(&priv->lock);
+
+       if (fe->ops.info.type == FE_ATSC) {
+               dprintk(1, "%s() ATSC\n", __func__);
+               switch (params->u.vsb.modulation) {
+               case VSB_8:
+               case VSB_16:
+                       dprintk(1, "%s() VSB modulation\n", __func__);
+                       priv->rf_mode = XC_RF_MODE_AIR;
+                       priv->freq_hz = params->frequency - 1750000;
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = XC4000_DTV6;
+                       type = DTV6;
+                       break;
+               case QAM_64:
+               case QAM_256:
+               case QAM_AUTO:
+                       dprintk(1, "%s() QAM modulation\n", __func__);
+                       priv->rf_mode = XC_RF_MODE_CABLE;
+                       priv->freq_hz = params->frequency - 1750000;
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = XC4000_DTV6;
+                       type = DTV6;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto fail;
+               }
+       } else if (fe->ops.info.type == FE_OFDM) {
+               dprintk(1, "%s() OFDM\n", __func__);
+               switch (params->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = XC4000_DTV6;
+                       priv->freq_hz = params->frequency - 1750000;
+                       type = DTV6;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       priv->bandwidth = BANDWIDTH_7_MHZ;
+                       priv->video_standard = XC4000_DTV7;
+                       priv->freq_hz = params->frequency - 2250000;
+                       type = DTV7;
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       priv->bandwidth = BANDWIDTH_8_MHZ;
+                       priv->video_standard = XC4000_DTV8;
+                       priv->freq_hz = params->frequency - 2750000;
+                       type = DTV8;
+                       break;
+               case BANDWIDTH_AUTO:
+                       if (params->frequency < 400000000) {
+                               priv->bandwidth = BANDWIDTH_7_MHZ;
+                               priv->freq_hz = params->frequency - 2250000;
+                       } else {
+                               priv->bandwidth = BANDWIDTH_8_MHZ;
+                               priv->freq_hz = params->frequency - 2750000;
+                       }
+                       priv->video_standard = XC4000_DTV7_8;
+                       type = DTV78;
+                       break;
+               default:
+                       printk(KERN_ERR "xc4000 bandwidth not set!\n");
+                       ret = -EINVAL;
+                       goto fail;
+               }
+               priv->rf_mode = XC_RF_MODE_AIR;
+       } else {
+               printk(KERN_ERR "xc4000 modulation type not supported!\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       dprintk(1, "%s() frequency=%d (compensated)\n",
+               __func__, priv->freq_hz);
+
+       /* Make sure the correct firmware type is loaded */
+       if (check_firmware(fe, type, 0, priv->if_khz) != 0)
+               goto fail;
+
+       ret = xc_set_signal_source(priv, priv->rf_mode);
+       if (ret != 0) {
+               printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n",
+                      priv->rf_mode);
+               goto fail;
+       } else {
+               u16     video_mode, audio_mode;
+               video_mode = xc4000_standard[priv->video_standard].video_mode;
+               audio_mode = xc4000_standard[priv->video_standard].audio_mode;
+               if (type == DTV6 && priv->firm_version != 0x0102)
+                       video_mode |= 0x0001;
+               ret = xc_set_tv_standard(priv, video_mode, audio_mode);
+               if (ret != 0) {
+                       printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
+                       /* DJH - do not return when it fails... */
+                       /* goto fail; */
+               }
+       }
+
+       if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
+               ret = 0;
+       if (priv->dvb_amplitude != 0) {
+               if (xc_write_reg(priv, XREG_AMPLITUDE,
+                                (priv->firm_version != 0x0102 ||
+                                 priv->dvb_amplitude != 134 ?
+                                 priv->dvb_amplitude : 132)) != 0)
+                       ret = -EREMOTEIO;
+       }
+       if (priv->set_smoothedcvbs != 0) {
+               if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
+                       ret = -EREMOTEIO;
+       }
+       if (ret != 0) {
+               printk(KERN_ERR "xc4000: setting registers failed\n");
+               /* goto fail; */
+       }
+
+       xc_tune_channel(priv, priv->freq_hz);
+
+       ret = 0;
+
+fail:
+       mutex_unlock(&priv->lock);
+
+       return ret;
+}
+
+static int xc4000_set_analog_params(struct dvb_frontend *fe,
+       struct analog_parameters *params)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       unsigned int type = 0;
+       int     ret = -EREMOTEIO;
+
+       if (params->mode == V4L2_TUNER_RADIO) {
+               dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n",
+                       __func__, params->frequency);
+
+               mutex_lock(&priv->lock);
+
+               params->std = 0;
+               priv->freq_hz = params->frequency * 125L / 2;
+
+               if (audio_std & XC4000_AUDIO_STD_INPUT1) {
+                       priv->video_standard = XC4000_FM_Radio_INPUT1;
+                       type = FM | INPUT1;
+               } else {
+                       priv->video_standard = XC4000_FM_Radio_INPUT2;
+                       type = FM | INPUT2;
+               }
+
+               goto tune_channel;
+       }
+
+       dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+               __func__, params->frequency);
+
+       mutex_lock(&priv->lock);
+
+       /* params->frequency is in units of 62.5khz */
+       priv->freq_hz = params->frequency * 62500;
+
+       params->std &= V4L2_STD_ALL;
+       /* if std is not defined, choose one */
+       if (!params->std)
+               params->std = V4L2_STD_PAL_BG;
+
+       if (audio_std & XC4000_AUDIO_STD_MONO)
+               type = MONO;
+
+       if (params->std & V4L2_STD_MN) {
+               params->std = V4L2_STD_MN;
+               if (audio_std & XC4000_AUDIO_STD_MONO) {
+                       priv->video_standard = XC4000_MN_NTSC_PAL_Mono;
+               } else if (audio_std & XC4000_AUDIO_STD_A2) {
+                       params->std |= V4L2_STD_A2;
+                       priv->video_standard = XC4000_MN_NTSC_PAL_A2;
+               } else {
+                       params->std |= V4L2_STD_BTSC;
+                       priv->video_standard = XC4000_MN_NTSC_PAL_BTSC;
+               }
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_PAL_BG) {
+               params->std = V4L2_STD_PAL_BG;
+               if (audio_std & XC4000_AUDIO_STD_MONO) {
+                       priv->video_standard = XC4000_BG_PAL_MONO;
+               } else if (!(audio_std & XC4000_AUDIO_STD_A2)) {
+                       if (!(audio_std & XC4000_AUDIO_STD_B)) {
+                               params->std |= V4L2_STD_NICAM_A;
+                               priv->video_standard = XC4000_BG_PAL_NICAM;
+                       } else {
+                               params->std |= V4L2_STD_NICAM_B;
+                               priv->video_standard = XC4000_BG_PAL_NICAM;
+                       }
+               } else {
+                       if (!(audio_std & XC4000_AUDIO_STD_B)) {
+                               params->std |= V4L2_STD_A2_A;
+                               priv->video_standard = XC4000_BG_PAL_A2;
+                       } else {
+                               params->std |= V4L2_STD_A2_B;
+                               priv->video_standard = XC4000_BG_PAL_A2;
+                       }
+               }
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_PAL_I) {
+               /* default to NICAM audio standard */
+               params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM;
+               if (audio_std & XC4000_AUDIO_STD_MONO)
+                       priv->video_standard = XC4000_I_PAL_NICAM_MONO;
+               else
+                       priv->video_standard = XC4000_I_PAL_NICAM;
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_PAL_DK) {
+               params->std = V4L2_STD_PAL_DK;
+               if (audio_std & XC4000_AUDIO_STD_MONO) {
+                       priv->video_standard = XC4000_DK_PAL_MONO;
+               } else if (audio_std & XC4000_AUDIO_STD_A2) {
+                       params->std |= V4L2_STD_A2;
+                       priv->video_standard = XC4000_DK_PAL_A2;
+               } else {
+                       params->std |= V4L2_STD_NICAM;
+                       priv->video_standard = XC4000_DK_PAL_NICAM;
+               }
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_SECAM_DK) {
+               /* default to A2 audio standard */
+               params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2;
+               if (audio_std & XC4000_AUDIO_STD_L) {
+                       type = 0;
+                       priv->video_standard = XC4000_DK_SECAM_NICAM;
+               } else if (audio_std & XC4000_AUDIO_STD_MONO) {
+                       priv->video_standard = XC4000_DK_SECAM_A2MONO;
+               } else if (audio_std & XC4000_AUDIO_STD_K3) {
+                       params->std |= V4L2_STD_SECAM_K3;
+                       priv->video_standard = XC4000_DK_SECAM_A2LDK3;
+               } else {
+                       priv->video_standard = XC4000_DK_SECAM_A2DK1;
+               }
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_SECAM_L) {
+               /* default to NICAM audio standard */
+               type = 0;
+               params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM;
+               priv->video_standard = XC4000_L_SECAM_NICAM;
+               goto tune_channel;
+       }
+
+       if (params->std & V4L2_STD_SECAM_LC) {
+               /* default to NICAM audio standard */
+               type = 0;
+               params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM;
+               priv->video_standard = XC4000_LC_SECAM_NICAM;
+               goto tune_channel;
+       }
+
+tune_channel:
+       /* FIXME: it could be air. */
+       priv->rf_mode = XC_RF_MODE_CABLE;
+
+       if (check_firmware(fe, type, params->std,
+                          xc4000_standard[priv->video_standard].int_freq) != 0)
+               goto fail;
+
+       ret = xc_set_signal_source(priv, priv->rf_mode);
+       if (ret != 0) {
+               printk(KERN_ERR
+                      "xc4000: xc_set_signal_source(%d) failed\n",
+                      priv->rf_mode);
+               goto fail;
+       } else {
+               u16     video_mode, audio_mode;
+               video_mode = xc4000_standard[priv->video_standard].video_mode;
+               audio_mode = xc4000_standard[priv->video_standard].audio_mode;
+               if (priv->video_standard < XC4000_BG_PAL_A2) {
+                       if (type & NOGD)
+                               video_mode &= 0xFF7F;
+               } else if (priv->video_standard < XC4000_I_PAL_NICAM) {
+                       if (priv->firm_version == 0x0102)
+                               video_mode &= 0xFEFF;
+                       if (audio_std & XC4000_AUDIO_STD_B)
+                               video_mode |= 0x0080;
+               }
+               ret = xc_set_tv_standard(priv, video_mode, audio_mode);
+               if (ret != 0) {
+                       printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
+                       goto fail;
+               }
+       }
+
+       if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
+               ret = 0;
+       if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0)
+               ret = -EREMOTEIO;
+       if (priv->set_smoothedcvbs != 0) {
+               if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
+                       ret = -EREMOTEIO;
+       }
+       if (ret != 0) {
+               printk(KERN_ERR "xc4000: setting registers failed\n");
+               goto fail;
+       }
+
+       xc_tune_channel(priv, priv->freq_hz);
+
+       ret = 0;
+
+fail:
+       mutex_unlock(&priv->lock);
+
+       return ret;
+}
+
+static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+
+       *freq = priv->freq_hz;
+
+       if (debug) {
+               mutex_lock(&priv->lock);
+               if ((priv->cur_fw.type
+                    & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) {
+                       u16     snr = 0;
+                       if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) {
+                               mutex_unlock(&priv->lock);
+                               dprintk(1, "%s() freq = %u, SNR = %d\n",
+                                       __func__, *freq, snr);
+                               return 0;
+                       }
+               }
+               mutex_unlock(&priv->lock);
+       }
+
+       dprintk(1, "%s()\n", __func__);
+
+       return 0;
+}
+
+static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       dprintk(1, "%s()\n", __func__);
+
+       *bw = priv->bandwidth;
+       return 0;
+}
+
+static int xc4000_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       u16     lock_status = 0;
+
+       mutex_lock(&priv->lock);
+
+       if (priv->cur_fw.type & BASE)
+               xc_get_lock_status(priv, &lock_status);
+
+       *status = (lock_status == 1 ?
+                  TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0);
+       if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8))
+               *status &= (~TUNER_STATUS_STEREO);
+
+       mutex_unlock(&priv->lock);
+
+       dprintk(2, "%s() lock_status = %d\n", __func__, lock_status);
+
+       return 0;
+}
+
+static int xc4000_sleep(struct dvb_frontend *fe)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+       int     ret = 0;
+
+       dprintk(1, "%s()\n", __func__);
+
+       mutex_lock(&priv->lock);
+
+       /* Avoid firmware reload on slow devices */
+       if ((no_poweroff == 2 ||
+            (no_poweroff == 0 && priv->default_pm != 0)) &&
+           (priv->cur_fw.type & BASE) != 0) {
+               /* force reset and firmware reload */
+               priv->cur_fw.type = XC_POWERED_DOWN;
+
+               if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) {
+                       printk(KERN_ERR
+                              "xc4000: %s() unable to shutdown tuner\n",
+                              __func__);
+                       ret = -EREMOTEIO;
+               }
+               msleep(20);
+       }
+
+       mutex_unlock(&priv->lock);
+
+       return ret;
+}
+
+static int xc4000_init(struct dvb_frontend *fe)
+{
+       dprintk(1, "%s()\n", __func__);
+
+       return 0;
+}
+
+static int xc4000_release(struct dvb_frontend *fe)
+{
+       struct xc4000_priv *priv = fe->tuner_priv;
+
+       dprintk(1, "%s()\n", __func__);
+
+       mutex_lock(&xc4000_list_mutex);
+
+       if (priv)
+               hybrid_tuner_release_state(priv);
+
+       mutex_unlock(&xc4000_list_mutex);
+
+       fe->tuner_priv = NULL;
+
+       return 0;
+}
+
+static const struct dvb_tuner_ops xc4000_tuner_ops = {
+       .info = {
+               .name           = "Xceive XC4000",
+               .frequency_min  =    1000000,
+               .frequency_max  = 1023000000,
+               .frequency_step =      50000,
+       },
+
+       .release           = xc4000_release,
+       .init              = xc4000_init,
+       .sleep             = xc4000_sleep,
+
+       .set_params        = xc4000_set_params,
+       .set_analog_params = xc4000_set_analog_params,
+       .get_frequency     = xc4000_get_frequency,
+       .get_bandwidth     = xc4000_get_bandwidth,
+       .get_status        = xc4000_get_status
+};
+
+struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
+                                  struct i2c_adapter *i2c,
+                                  struct xc4000_config *cfg)
+{
+       struct xc4000_priv *priv = NULL;
+       int     instance;
+       u16     id = 0;
+
+       dprintk(1, "%s(%d-%04x)\n", __func__,
+               i2c ? i2c_adapter_id(i2c) : -1,
+               cfg ? cfg->i2c_address : -1);
+
+       mutex_lock(&xc4000_list_mutex);
+
+       instance = hybrid_tuner_request_state(struct xc4000_priv, priv,
+                                             hybrid_tuner_instance_list,
+                                             i2c, cfg->i2c_address, "xc4000");
+       switch (instance) {
+       case 0:
+               goto fail;
+               break;
+       case 1:
+               /* new tuner instance */
+               priv->bandwidth = BANDWIDTH_6_MHZ;
+               /* set default configuration */
+               priv->if_khz = 4560;
+               priv->default_pm = 0;
+               priv->dvb_amplitude = 134;
+               priv->set_smoothedcvbs = 1;
+               mutex_init(&priv->lock);
+               fe->tuner_priv = priv;
+               break;
+       default:
+               /* existing tuner instance */
+               fe->tuner_priv = priv;
+               break;
+       }
+
+       if (cfg->if_khz != 0) {
+               /* copy configuration if provided by the caller */
+               priv->if_khz = cfg->if_khz;
+               priv->default_pm = cfg->default_pm;
+               priv->dvb_amplitude = cfg->dvb_amplitude;
+               priv->set_smoothedcvbs = cfg->set_smoothedcvbs;
+       }
+
+       /* Check if firmware has been loaded. It is possible that another
+          instance of the driver has loaded the firmware.
+        */
+
+       if (instance == 1) {
+               if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+                       goto fail;
+       } else {
+               id = ((priv->cur_fw.type & BASE) != 0 ?
+                     priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED);
+       }
+
+       switch (id) {
+       case XC_PRODUCT_ID_XC4000:
+       case XC_PRODUCT_ID_XC4100:
+               printk(KERN_INFO
+                       "xc4000: Successfully identified at address 0x%02x\n",
+                       cfg->i2c_address);
+               printk(KERN_INFO
+                       "xc4000: Firmware has been loaded previously\n");
+               break;
+       case XC_PRODUCT_ID_FW_NOT_LOADED:
+               printk(KERN_INFO
+                       "xc4000: Successfully identified at address 0x%02x\n",
+                       cfg->i2c_address);
+               printk(KERN_INFO
+                       "xc4000: Firmware has not been loaded previously\n");
+               break;
+       default:
+               printk(KERN_ERR
+                       "xc4000: Device not found at addr 0x%02x (0x%x)\n",
+                       cfg->i2c_address, id);
+               goto fail;
+       }
+
+       mutex_unlock(&xc4000_list_mutex);
+
+       memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops,
+               sizeof(struct dvb_tuner_ops));
+
+       if (instance == 1) {
+               int     ret;
+               mutex_lock(&priv->lock);
+               ret = xc4000_fwupload(fe);
+               mutex_unlock(&priv->lock);
+               if (ret != 0)
+                       goto fail2;
+       }
+
+       return fe;
+fail:
+       mutex_unlock(&xc4000_list_mutex);
+fail2:
+       xc4000_release(fe);
+       return NULL;
+}
+EXPORT_SYMBOL(xc4000_attach);
+
+MODULE_AUTHOR("Steven Toth, Davide Ferri");
+MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/xc4000.h b/drivers/media/common/tuners/xc4000.h
new file mode 100644 (file)
index 0000000..e6a44d1
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, 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 __XC4000_H__
+#define __XC4000_H__
+
+#include <linux/firmware.h>
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct xc4000_config {
+       u8      i2c_address;
+       /* if non-zero, power management is enabled by default */
+       u8      default_pm;
+       /* value to be written to XREG_AMPLITUDE in DVB-T mode (0: no write) */
+       u8      dvb_amplitude;
+       /* if non-zero, register 0x0E is set to filter analog TV video output */
+       u8      set_smoothedcvbs;
+       /* IF for DVB-T */
+       u32     if_khz;
+};
+
+/* xc4000 callback command */
+#define XC4000_TUNER_RESET             0
+
+/* For each bridge framework, when it attaches either analog or digital,
+ * it has to store a reference back to its _core equivalent structure,
+ * so that it can service the hardware by steering gpio's etc.
+ * Each bridge implementation is different so cast devptr accordingly.
+ * The xc4000 driver cares not for this value, other than ensuring
+ * it's passed back to a bridge during tuner_callback().
+ */
+
+#if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
+                                         struct i2c_adapter *i2c,
+                                         struct xc4000_config *cfg);
+#else
+static inline struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
+                                                struct i2c_adapter *i2c,
+                                                struct xc4000_config *cfg)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
index ee214c3b63d7050c8629f14ee8a6f148a1d881d2..f6e40b3a44cc2204f842969deec3ea72c3170b21 100644 (file)
@@ -80,6 +80,10 @@ comment "Supported nGene Adapters"
        depends on DVB_CORE && PCI && I2C
        source "drivers/media/dvb/ngene/Kconfig"
 
+comment "Supported ddbridge ('Octopus') Adapters"
+       depends on DVB_CORE && PCI && I2C
+       source "drivers/media/dvb/ddbridge/Kconfig"
+
 comment "Supported DVB Frontends"
        depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
index a1a08758a6f28122439381cf7f19eb5daa028029..b2cefe637a6410e42bb3ccc762beaa3c3b28901f 100644 (file)
@@ -15,6 +15,7 @@ obj-y        := dvb-core/     \
                dm1105/         \
                pt1/            \
                mantis/         \
-               ngene/
+               ngene/          \
+               ddbridge/
 
 obj-$(CONFIG_DVB_FIREDTV)      += firewire/
index 1e1106dcd063ebd687d552bcc493873fcd5c8a8b..521d691049824523f7229335bf0eb267f976376f 100644 (file)
@@ -892,7 +892,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
        if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
                printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr);
                kfree(card);
-               return -EFAULT;
+               return -ENODEV;
        }
 
        if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
@@ -902,7 +902,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
                       "installed, try removing it.\n");
 
                kfree(card);
-               return -EFAULT;
+               return -ENODEV;
        }
 
        mutex_init(&card->bt->gpio_lock);
diff --git a/drivers/media/dvb/ddbridge/Kconfig b/drivers/media/dvb/ddbridge/Kconfig
new file mode 100644 (file)
index 0000000..d099e1a
--- /dev/null
@@ -0,0 +1,18 @@
+config DVB_DDBRIDGE
+       tristate "Digital Devices bridge support"
+       depends on DVB_CORE && PCI && I2C
+       select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+       select DVB_STV6110x if !DVB_FE_CUSTOMISE
+       select DVB_STV090x if !DVB_FE_CUSTOMISE
+       select DVB_DRXK if !DVB_FE_CUSTOMISE
+       select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
+       ---help---
+         Support for cards with the Digital Devices PCI express bridge:
+         - Octopus PCIe Bridge
+         - Octopus mini PCIe Bridge
+         - Octopus LE
+         - DuoFlex S2 Octopus
+         - DuoFlex CT Octopus
+         - cineS2(v6)
+
+         Say Y if you own such a card and want to use it.
diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile
new file mode 100644 (file)
index 0000000..de4fe19
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for the ddbridge device driver
+#
+
+ddbridge-objs := ddbridge-core.o
+
+obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/common/tuners/
+
+# For the staging CI driver cxd2099
+EXTRA_CFLAGS += -Idrivers/staging/cxd2099/
diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c
new file mode 100644 (file)
index 0000000..573d540
--- /dev/null
@@ -0,0 +1,1719 @@
+/*
+ * ddbridge.c: Digital Devices PCIe bridge driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/swab.h>
+#include <linux/vmalloc.h>
+#include "ddbridge.h"
+
+#include "ddbridge-regs.h"
+
+#include "tda18271c2dd.h"
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "lnbh24.h"
+#include "drxk.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* MSI had problems with lost interrupts, fixed but needs testing */
+#undef CONFIG_PCI_MSI
+
+/******************************************************************************/
+
+static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
+{
+       struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
+                                  .buf  = val,  .len   = 1 } };
+       return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val)
+{
+       struct i2c_msg msgs[2] = {{.addr = adr,  .flags = 0,
+                                  .buf  = &reg, .len   = 1 },
+                                 {.addr = adr,  .flags = I2C_M_RD,
+                                  .buf  = val,  .len   = 1 } };
+       return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
+                         u16 reg, u8 *val)
+{
+       u8 msg[2] = {reg>>8, reg&0xff};
+       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+                                  .buf  = msg, .len   = 2},
+                                 {.addr = adr, .flags = I2C_M_RD,
+                                  .buf  = val, .len   = 1} };
+       return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
+{
+       struct ddb *dev = i2c->dev;
+       int stat;
+       u32 val;
+
+       i2c->done = 0;
+       ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND);
+       stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ);
+       if (stat <= 0) {
+               printk(KERN_ERR "I2C timeout\n");
+               { /* MSI debugging*/
+                       u32 istat = ddbreadl(INTERRUPT_STATUS);
+                       printk(KERN_ERR "IRS %08x\n", istat);
+                       ddbwritel(istat, INTERRUPT_ACK);
+               }
+               return -EIO;
+       }
+       val = ddbreadl(i2c->regs+I2C_COMMAND);
+       if (val & 0x70000)
+               return -EIO;
+       return 0;
+}
+
+static int ddb_i2c_master_xfer(struct i2c_adapter *adapter,
+                              struct i2c_msg msg[], int num)
+{
+       struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter);
+       struct ddb *dev = i2c->dev;
+       u8 addr = 0;
+
+       if (num)
+               addr = msg[0].addr;
+
+       if (num == 2 && msg[1].flags & I2C_M_RD &&
+           !(msg[0].flags & I2C_M_RD)) {
+               memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf,
+                           msg[0].buf, msg[0].len);
+               ddbwritel(msg[0].len|(msg[1].len << 16),
+                         i2c->regs+I2C_TASKLENGTH);
+               if (!ddb_i2c_cmd(i2c, addr, 1)) {
+                       memcpy_fromio(msg[1].buf,
+                                     dev->regs + I2C_TASKMEM_BASE + i2c->rbuf,
+                                     msg[1].len);
+                       return num;
+               }
+       }
+
+       if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+               ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len);
+               ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH);
+               if (!ddb_i2c_cmd(i2c, addr, 2))
+                       return num;
+       }
+       if (num == 1 && (msg[0].flags & I2C_M_RD)) {
+               ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH);
+               if (!ddb_i2c_cmd(i2c, addr, 3)) {
+                       ddbcpyfrom(msg[0].buf,
+                                  I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len);
+                       return num;
+               }
+       }
+       return -EIO;
+}
+
+
+static u32 ddb_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_EMUL;
+}
+
+struct i2c_algorithm ddb_i2c_algo = {
+       .master_xfer   = ddb_i2c_master_xfer,
+       .functionality = ddb_i2c_functionality,
+};
+
+static void ddb_i2c_release(struct ddb *dev)
+{
+       int i;
+       struct ddb_i2c *i2c;
+       struct i2c_adapter *adap;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               i2c = &dev->i2c[i];
+               adap = &i2c->adap;
+               i2c_del_adapter(adap);
+       }
+}
+
+static int ddb_i2c_init(struct ddb *dev)
+{
+       int i, j, stat = 0;
+       struct ddb_i2c *i2c;
+       struct i2c_adapter *adap;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               i2c = &dev->i2c[i];
+               i2c->dev = dev;
+               i2c->nr = i;
+               i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4);
+               i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8);
+               i2c->regs = 0x80 + i * 0x20;
+               ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING);
+               ddbwritel((i2c->rbuf << 16) | i2c->wbuf,
+                         i2c->regs + I2C_TASKADDRESS);
+               init_waitqueue_head(&i2c->wq);
+
+               adap = &i2c->adap;
+               i2c_set_adapdata(adap, i2c);
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+               adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG;
+#else
+#ifdef I2C_CLASS_TV_ANALOG
+               adap->class = I2C_CLASS_TV_ANALOG;
+#endif
+#endif
+               strcpy(adap->name, "ddbridge");
+               adap->algo = &ddb_i2c_algo;
+               adap->algo_data = (void *)i2c;
+               adap->dev.parent = &dev->pdev->dev;
+               stat = i2c_add_adapter(adap);
+               if (stat)
+                       break;
+       }
+       if (stat)
+               for (j = 0; j < i; j++) {
+                       i2c = &dev->i2c[j];
+                       adap = &i2c->adap;
+                       i2c_del_adapter(adap);
+               }
+       return stat;
+}
+
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+#if 0
+static void set_table(struct ddb *dev, u32 off,
+                     dma_addr_t *pbuf, u32 num)
+{
+       u32 i, base;
+       u64 mem;
+
+       base = DMA_BASE_ADDRESS_TABLE + off;
+       for (i = 0; i < num; i++) {
+               mem = pbuf[i];
+               ddbwritel(mem & 0xffffffff, base + i * 8);
+               ddbwritel(mem >> 32, base + i * 8 + 4);
+       }
+}
+#endif
+
+static void ddb_address_table(struct ddb *dev)
+{
+       u32 i, j, base;
+       u64 mem;
+       dma_addr_t *pbuf;
+
+       for (i = 0; i < dev->info->port_num * 2; i++) {
+               base = DMA_BASE_ADDRESS_TABLE + i * 0x100;
+               pbuf = dev->input[i].pbuf;
+               for (j = 0; j < dev->input[i].dma_buf_num; j++) {
+                       mem = pbuf[j];
+                       ddbwritel(mem & 0xffffffff, base + j * 8);
+                       ddbwritel(mem >> 32, base + j * 8 + 4);
+               }
+       }
+       for (i = 0; i < dev->info->port_num; i++) {
+               base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100;
+               pbuf = dev->output[i].pbuf;
+               for (j = 0; j < dev->output[i].dma_buf_num; j++) {
+                       mem = pbuf[j];
+                       ddbwritel(mem & 0xffffffff, base + j * 8);
+                       ddbwritel(mem >> 32, base + j * 8 + 4);
+               }
+       }
+}
+
+static void io_free(struct pci_dev *pdev, u8 **vbuf,
+                   dma_addr_t *pbuf, u32 size, int num)
+{
+       int i;
+
+       for (i = 0; i < num; i++) {
+               if (vbuf[i]) {
+                       pci_free_consistent(pdev, size, vbuf[i], pbuf[i]);
+                       vbuf[i] = 0;
+               }
+       }
+}
+
+static int io_alloc(struct pci_dev *pdev, u8 **vbuf,
+                   dma_addr_t *pbuf, u32 size, int num)
+{
+       int i;
+
+       for (i = 0; i < num; i++) {
+               vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]);
+               if (!vbuf[i])
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+static int ddb_buffers_alloc(struct ddb *dev)
+{
+       int i;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               switch (port->class) {
+               case DDB_PORT_TUNER:
+                       if (io_alloc(dev->pdev, port->input[0]->vbuf,
+                                    port->input[0]->pbuf,
+                                    port->input[0]->dma_buf_size,
+                                    port->input[0]->dma_buf_num) < 0)
+                               return -1;
+                       if (io_alloc(dev->pdev, port->input[1]->vbuf,
+                                    port->input[1]->pbuf,
+                                    port->input[1]->dma_buf_size,
+                                    port->input[1]->dma_buf_num) < 0)
+                               return -1;
+                       break;
+               case DDB_PORT_CI:
+                       if (io_alloc(dev->pdev, port->input[0]->vbuf,
+                                    port->input[0]->pbuf,
+                                    port->input[0]->dma_buf_size,
+                                    port->input[0]->dma_buf_num) < 0)
+                               return -1;
+                       if (io_alloc(dev->pdev, port->output->vbuf,
+                                    port->output->pbuf,
+                                    port->output->dma_buf_size,
+                                    port->output->dma_buf_num) < 0)
+                               return -1;
+                       break;
+               default:
+                       break;
+               }
+       }
+       ddb_address_table(dev);
+       return 0;
+}
+
+static void ddb_buffers_free(struct ddb *dev)
+{
+       int i;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               io_free(dev->pdev, port->input[0]->vbuf,
+                       port->input[0]->pbuf,
+                       port->input[0]->dma_buf_size,
+                       port->input[0]->dma_buf_num);
+               io_free(dev->pdev, port->input[1]->vbuf,
+                       port->input[1]->pbuf,
+                       port->input[1]->dma_buf_size,
+                       port->input[1]->dma_buf_num);
+               io_free(dev->pdev, port->output->vbuf,
+                       port->output->pbuf,
+                       port->output->dma_buf_size,
+                       port->output->dma_buf_num);
+       }
+}
+
+static void ddb_input_start(struct ddb_input *input)
+{
+       struct ddb *dev = input->port->dev;
+
+       spin_lock_irq(&input->lock);
+       input->cbuf = 0;
+       input->coff = 0;
+
+       /* reset */
+       ddbwritel(0, TS_INPUT_CONTROL(input->nr));
+       ddbwritel(2, TS_INPUT_CONTROL(input->nr));
+       ddbwritel(0, TS_INPUT_CONTROL(input->nr));
+
+       ddbwritel((1 << 16) |
+                 (input->dma_buf_num << 11) |
+                 (input->dma_buf_size >> 7),
+                 DMA_BUFFER_SIZE(input->nr));
+       ddbwritel(0, DMA_BUFFER_ACK(input->nr));
+
+       ddbwritel(1, DMA_BASE_WRITE);
+       ddbwritel(3, DMA_BUFFER_CONTROL(input->nr));
+       ddbwritel(9, TS_INPUT_CONTROL(input->nr));
+       input->running = 1;
+       spin_unlock_irq(&input->lock);
+}
+
+static void ddb_input_stop(struct ddb_input *input)
+{
+       struct ddb *dev = input->port->dev;
+
+       spin_lock_irq(&input->lock);
+       ddbwritel(0, TS_INPUT_CONTROL(input->nr));
+       ddbwritel(0, DMA_BUFFER_CONTROL(input->nr));
+       input->running = 0;
+       spin_unlock_irq(&input->lock);
+}
+
+static void ddb_output_start(struct ddb_output *output)
+{
+       struct ddb *dev = output->port->dev;
+
+       spin_lock_irq(&output->lock);
+       output->cbuf = 0;
+       output->coff = 0;
+       ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
+       ddbwritel(2, TS_OUTPUT_CONTROL(output->nr));
+       ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
+       ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr));
+       ddbwritel((1 << 16) |
+                 (output->dma_buf_num << 11) |
+                 (output->dma_buf_size >> 7),
+                 DMA_BUFFER_SIZE(output->nr + 8));
+       ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8));
+
+       ddbwritel(1, DMA_BASE_READ);
+       ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8));
+       /* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */
+       ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr));
+       output->running = 1;
+       spin_unlock_irq(&output->lock);
+}
+
+static void ddb_output_stop(struct ddb_output *output)
+{
+       struct ddb *dev = output->port->dev;
+
+       spin_lock_irq(&output->lock);
+       ddbwritel(0, TS_OUTPUT_CONTROL(output->nr));
+       ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8));
+       output->running = 0;
+       spin_unlock_irq(&output->lock);
+}
+
+static u32 ddb_output_free(struct ddb_output *output)
+{
+       u32 idx, off, stat = output->stat;
+       s32 diff;
+
+       idx = (stat >> 11) & 0x1f;
+       off = (stat & 0x7ff) << 7;
+
+       if (output->cbuf != idx) {
+               if ((((output->cbuf + 1) % output->dma_buf_num) == idx) &&
+                   (output->dma_buf_size - output->coff <= 188))
+                       return 0;
+               return 188;
+       }
+       diff = off - output->coff;
+       if (diff <= 0 || diff > 188)
+               return 188;
+       return 0;
+}
+
+static ssize_t ddb_output_write(struct ddb_output *output,
+                               const u8 *buf, size_t count)
+{
+       struct ddb *dev = output->port->dev;
+       u32 idx, off, stat = output->stat;
+       u32 left = count, len;
+
+       idx = (stat >> 11) & 0x1f;
+       off = (stat & 0x7ff) << 7;
+
+       while (left) {
+               len = output->dma_buf_size - output->coff;
+               if ((((output->cbuf + 1) % output->dma_buf_num) == idx) &&
+                   (off == 0)) {
+                       if (len <= 188)
+                               break;
+                       len -= 188;
+               }
+               if (output->cbuf == idx) {
+                       if (off > output->coff) {
+#if 1
+                               len = off - output->coff;
+                               len -= (len % 188);
+                               if (len <= 188)
+
+#endif
+                                       break;
+                               len -= 188;
+                       }
+               }
+               if (len > left)
+                       len = left;
+               if (copy_from_user(output->vbuf[output->cbuf] + output->coff,
+                                  buf, len))
+                       return -EIO;
+               left -= len;
+               buf += len;
+               output->coff += len;
+               if (output->coff == output->dma_buf_size) {
+                       output->coff = 0;
+                       output->cbuf = ((output->cbuf + 1) % output->dma_buf_num);
+               }
+               ddbwritel((output->cbuf << 11) | (output->coff >> 7),
+                         DMA_BUFFER_ACK(output->nr + 8));
+       }
+       return count - left;
+}
+
+static u32 ddb_input_avail(struct ddb_input *input)
+{
+       struct ddb *dev = input->port->dev;
+       u32 idx, off, stat = input->stat;
+       u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr));
+
+       idx = (stat >> 11) & 0x1f;
+       off = (stat & 0x7ff) << 7;
+
+       if (ctrl & 4) {
+               printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl);
+               ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr));
+               return 0;
+       }
+       if (input->cbuf != idx)
+               return 188;
+       return 0;
+}
+
+static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
+{
+       struct ddb *dev = input->port->dev;
+       u32 left = count;
+       u32 idx, off, free, stat = input->stat;
+       int ret;
+
+       idx = (stat >> 11) & 0x1f;
+       off = (stat & 0x7ff) << 7;
+
+       while (left) {
+               if (input->cbuf == idx)
+                       return count - left;
+               free = input->dma_buf_size - input->coff;
+               if (free > left)
+                       free = left;
+               ret = copy_to_user(buf, input->vbuf[input->cbuf] +
+                                  input->coff, free);
+               input->coff += free;
+               if (input->coff == input->dma_buf_size) {
+                       input->coff = 0;
+                       input->cbuf = (input->cbuf+1) % input->dma_buf_num;
+               }
+               left -= free;
+               ddbwritel((input->cbuf << 11) | (input->coff >> 7),
+                         DMA_BUFFER_ACK(input->nr));
+       }
+       return count;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+#if 0
+static struct ddb_input *fe2input(struct ddb *dev, struct dvb_frontend *fe)
+{
+       int i;
+
+       for (i = 0; i < dev->info->port_num * 2; i++) {
+               if (dev->input[i].fe == fe)
+                       return &dev->input[i];
+       }
+       return NULL;
+}
+#endif
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct ddb_input *input = fe->sec_priv;
+       struct ddb_port *port = input->port;
+       int status;
+
+       if (enable) {
+               mutex_lock(&port->i2c_gate_lock);
+               status = input->gate_ctrl(fe, 1);
+       } else {
+               status = input->gate_ctrl(fe, 0);
+               mutex_unlock(&port->i2c_gate_lock);
+       }
+       return status;
+}
+
+static int demod_attach_drxk(struct ddb_input *input)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct dvb_frontend *fe;
+       struct drxk_config config;
+
+       memset(&config, 0, sizeof(config));
+       config.adr = 0x29 + (input->nr & 1);
+
+       fe = input->fe = dvb_attach(drxk_attach, &config, i2c, &input->fe2);
+       if (!input->fe) {
+               printk(KERN_ERR "No DRXK found!\n");
+               return -ENODEV;
+       }
+       fe->sec_priv = input;
+       input->gate_ctrl = fe->ops.i2c_gate_ctrl;
+       fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+       return 0;
+}
+
+static int tuner_attach_tda18271(struct ddb_input *input)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct dvb_frontend *fe;
+
+       if (input->fe->ops.i2c_gate_ctrl)
+               input->fe->ops.i2c_gate_ctrl(input->fe, 1);
+       fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60);
+       if (!fe) {
+               printk(KERN_ERR "No TDA18271 found!\n");
+               return -ENODEV;
+       }
+       if (input->fe->ops.i2c_gate_ctrl)
+               input->fe->ops.i2c_gate_ctrl(input->fe, 0);
+       return 0;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+static struct stv090x_config stv0900 = {
+       .device         = STV0900,
+       .demod_mode     = STV090x_DUAL,
+       .clk_mode       = STV090x_CLK_EXT,
+
+       .xtal           = 27000000,
+       .address        = 0x69,
+
+       .ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+       .ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+       .repeater_level = STV090x_RPTLEVEL_16,
+
+       .adc1_range     = STV090x_ADC_1Vpp,
+       .adc2_range     = STV090x_ADC_1Vpp,
+
+       .diseqc_envelope_mode = true,
+};
+
+static struct stv090x_config stv0900_aa = {
+       .device         = STV0900,
+       .demod_mode     = STV090x_DUAL,
+       .clk_mode       = STV090x_CLK_EXT,
+
+       .xtal           = 27000000,
+       .address        = 0x68,
+
+       .ts1_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+       .ts2_mode       = STV090x_TSMODE_SERIAL_PUNCTURED,
+
+       .repeater_level = STV090x_RPTLEVEL_16,
+
+       .adc1_range     = STV090x_ADC_1Vpp,
+       .adc2_range     = STV090x_ADC_1Vpp,
+
+       .diseqc_envelope_mode = true,
+};
+
+static struct stv6110x_config stv6110a = {
+       .addr    = 0x60,
+       .refclk  = 27000000,
+       .clk_div = 1,
+};
+
+static struct stv6110x_config stv6110b = {
+       .addr    = 0x63,
+       .refclk  = 27000000,
+       .clk_div = 1,
+};
+
+static int demod_attach_stv0900(struct ddb_input *input, int type)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
+
+       input->fe = dvb_attach(stv090x_attach, feconf, i2c,
+                              (input->nr & 1) ? STV090x_DEMODULATOR_1
+                              : STV090x_DEMODULATOR_0);
+       if (!input->fe) {
+               printk(KERN_ERR "No STV0900 found!\n");
+               return -ENODEV;
+       }
+       if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0,
+                       0, (input->nr & 1) ?
+                       (0x09 - type) : (0x0b - type))) {
+               printk(KERN_ERR "No LNBH24 found!\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int tuner_attach_stv6110(struct ddb_input *input, int type)
+{
+       struct i2c_adapter *i2c = &input->port->i2c->adap;
+       struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900;
+       struct stv6110x_config *tunerconf = (input->nr & 1) ?
+               &stv6110b : &stv6110a;
+       struct stv6110x_devctl *ctl;
+
+       ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c);
+       if (!ctl) {
+               printk(KERN_ERR "No STV6110X found!\n");
+               return -ENODEV;
+       }
+       printk(KERN_INFO "attach tuner input %d adr %02x\n",
+                        input->nr, tunerconf->addr);
+
+       feconf->tuner_init          = ctl->tuner_init;
+       feconf->tuner_sleep         = ctl->tuner_sleep;
+       feconf->tuner_set_mode      = ctl->tuner_set_mode;
+       feconf->tuner_set_frequency = ctl->tuner_set_frequency;
+       feconf->tuner_get_frequency = ctl->tuner_get_frequency;
+       feconf->tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+       feconf->tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+       feconf->tuner_set_bbgain    = ctl->tuner_set_bbgain;
+       feconf->tuner_get_bbgain    = ctl->tuner_get_bbgain;
+       feconf->tuner_set_refclk    = ctl->tuner_set_refclk;
+       feconf->tuner_get_status    = ctl->tuner_get_status;
+
+       return 0;
+}
+
+static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
+                           int (*start_feed)(struct dvb_demux_feed *),
+                           int (*stop_feed)(struct dvb_demux_feed *),
+                           void *priv)
+{
+       dvbdemux->priv = priv;
+
+       dvbdemux->filternum = 256;
+       dvbdemux->feednum = 256;
+       dvbdemux->start_feed = start_feed;
+       dvbdemux->stop_feed = stop_feed;
+       dvbdemux->write_to_decoder = NULL;
+       dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+                                     DMX_SECTION_FILTERING |
+                                     DMX_MEMORY_BASED_FILTERING);
+       return dvb_dmx_init(dvbdemux);
+}
+
+static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
+                              struct dvb_demux *dvbdemux,
+                              struct dmx_frontend *hw_frontend,
+                              struct dmx_frontend *mem_frontend,
+                              struct dvb_adapter *dvb_adapter)
+{
+       int ret;
+
+       dmxdev->filternum = 256;
+       dmxdev->demux = &dvbdemux->dmx;
+       dmxdev->capabilities = 0;
+       ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
+       if (ret < 0)
+               return ret;
+
+       hw_frontend->source = DMX_FRONTEND_0;
+       dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
+       mem_frontend->source = DMX_MEMORY_FE;
+       dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
+       return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
+}
+
+static int start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+       struct ddb_input *input = dvbdmx->priv;
+
+       if (!input->users)
+               ddb_input_start(input);
+
+       return ++input->users;
+}
+
+static int stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+       struct ddb_input *input = dvbdmx->priv;
+
+       if (--input->users)
+               return input->users;
+
+       ddb_input_stop(input);
+       return 0;
+}
+
+
+static void dvb_input_detach(struct ddb_input *input)
+{
+       struct dvb_adapter *adap = &input->adap;
+       struct dvb_demux *dvbdemux = &input->demux;
+
+       switch (input->attached) {
+       case 5:
+               if (input->fe2)
+                       dvb_unregister_frontend(input->fe2);
+               if (input->fe) {
+                       dvb_unregister_frontend(input->fe);
+                       dvb_frontend_detach(input->fe);
+                       input->fe = NULL;
+               }
+       case 4:
+               dvb_net_release(&input->dvbnet);
+
+       case 3:
+               dvbdemux->dmx.close(&dvbdemux->dmx);
+               dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+                                             &input->hw_frontend);
+               dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
+                                             &input->mem_frontend);
+               dvb_dmxdev_release(&input->dmxdev);
+
+       case 2:
+               dvb_dmx_release(&input->demux);
+
+       case 1:
+               dvb_unregister_adapter(adap);
+       }
+       input->attached = 0;
+}
+
+static int dvb_input_attach(struct ddb_input *input)
+{
+       int ret;
+       struct ddb_port *port = input->port;
+       struct dvb_adapter *adap = &input->adap;
+       struct dvb_demux *dvbdemux = &input->demux;
+
+       ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE,
+                                  &input->port->dev->pdev->dev,
+                                  adapter_nr);
+       if (ret < 0) {
+               printk(KERN_ERR "ddbridge: Could not register adapter."
+                      "Check if you enabled enough adapters in dvb-core!\n");
+               return ret;
+       }
+       input->attached = 1;
+
+       ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
+                                     start_feed,
+                                     stop_feed, input);
+       if (ret < 0)
+               return ret;
+       input->attached = 2;
+
+       ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux,
+                                        &input->hw_frontend,
+                                        &input->mem_frontend, adap);
+       if (ret < 0)
+               return ret;
+       input->attached = 3;
+
+       ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux);
+       if (ret < 0)
+               return ret;
+       input->attached = 4;
+
+       input->fe = 0;
+       switch (port->type) {
+       case DDB_TUNER_DVBS_ST:
+               if (demod_attach_stv0900(input, 0) < 0)
+                       return -ENODEV;
+               if (tuner_attach_stv6110(input, 0) < 0)
+                       return -ENODEV;
+               if (input->fe) {
+                       if (dvb_register_frontend(adap, input->fe) < 0)
+                               return -ENODEV;
+               }
+               break;
+       case DDB_TUNER_DVBS_ST_AA:
+               if (demod_attach_stv0900(input, 1) < 0)
+                       return -ENODEV;
+               if (tuner_attach_stv6110(input, 1) < 0)
+                       return -ENODEV;
+               if (input->fe) {
+                       if (dvb_register_frontend(adap, input->fe) < 0)
+                               return -ENODEV;
+               }
+               break;
+       case DDB_TUNER_DVBCT_TR:
+               if (demod_attach_drxk(input) < 0)
+                       return -ENODEV;
+               if (tuner_attach_tda18271(input) < 0)
+                       return -ENODEV;
+               if (input->fe) {
+                       if (dvb_register_frontend(adap, input->fe) < 0)
+                               return -ENODEV;
+               }
+               if (input->fe2) {
+                       if (dvb_register_frontend(adap, input->fe2) < 0)
+                               return -ENODEV;
+                       input->fe2->tuner_priv = input->fe->tuner_priv;
+                       memcpy(&input->fe2->ops.tuner_ops,
+                              &input->fe->ops.tuner_ops,
+                              sizeof(struct dvb_tuner_ops));
+               }
+               break;
+       }
+       input->attached = 5;
+       return 0;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
+static ssize_t ts_write(struct file *file, const char *buf,
+                       size_t count, loff_t *ppos)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct ddb_output *output = dvbdev->priv;
+       size_t left = count;
+       int stat;
+
+       while (left) {
+               if (ddb_output_free(output) < 188) {
+                       if (file->f_flags & O_NONBLOCK)
+                               break;
+                       if (wait_event_interruptible(
+                                   output->wq, ddb_output_free(output) >= 188) < 0)
+                               break;
+               }
+               stat = ddb_output_write(output, buf, left);
+               if (stat < 0)
+                       break;
+               buf += stat;
+               left -= stat;
+       }
+       return (left == count) ? -EAGAIN : (count - left);
+}
+
+static ssize_t ts_read(struct file *file, char *buf,
+                      size_t count, loff_t *ppos)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct ddb_output *output = dvbdev->priv;
+       struct ddb_input *input = output->port->input[0];
+       int left, read;
+
+       count -= count % 188;
+       left = count;
+       while (left) {
+               if (ddb_input_avail(input) < 188) {
+                       if (file->f_flags & O_NONBLOCK)
+                               break;
+                       if (wait_event_interruptible(
+                                   input->wq, ddb_input_avail(input) >= 188) < 0)
+                               break;
+               }
+               read = ddb_input_read(input, buf, left);
+               left -= read;
+               buf += read;
+       }
+       return (left == count) ? -EAGAIN : (count - left);
+}
+
+static unsigned int ts_poll(struct file *file, poll_table *wait)
+{
+       /*
+       struct dvb_device *dvbdev = file->private_data;
+       struct ddb_output *output = dvbdev->priv;
+       struct ddb_input *input = output->port->input[0];
+       */
+       unsigned int mask = 0;
+
+#if 0
+       if (data_avail_to_read)
+               mask |= POLLIN | POLLRDNORM;
+       if (data_avail_to_write)
+               mask |= POLLOUT | POLLWRNORM;
+
+       poll_wait(file, &read_queue, wait);
+       poll_wait(file, &write_queue, wait);
+#endif
+       return mask;
+}
+
+static const struct file_operations ci_fops = {
+       .owner   = THIS_MODULE,
+       .read    = ts_read,
+       .write   = ts_write,
+       .open    = dvb_generic_open,
+       .release = dvb_generic_release,
+       .poll    = ts_poll,
+       .mmap    = 0,
+};
+
+static struct dvb_device dvbdev_ci = {
+       .priv    = 0,
+       .readers = -1,
+       .writers = -1,
+       .users   = -1,
+       .fops    = &ci_fops,
+};
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void input_tasklet(unsigned long data)
+{
+       struct ddb_input *input = (struct ddb_input *) data;
+       struct ddb *dev = input->port->dev;
+
+       spin_lock(&input->lock);
+       if (!input->running) {
+               spin_unlock(&input->lock);
+               return;
+       }
+       input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr));
+
+       if (input->port->class == DDB_PORT_TUNER) {
+               if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))
+                       printk(KERN_ERR "Overflow input %d\n", input->nr);
+               while (input->cbuf != ((input->stat >> 11) & 0x1f)
+                      || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))) {
+                       dvb_dmx_swfilter_packets(&input->demux,
+                                                input->vbuf[input->cbuf],
+                                                input->dma_buf_size / 188);
+
+                       input->cbuf = (input->cbuf + 1) % input->dma_buf_num;
+                       ddbwritel((input->cbuf << 11),
+                                 DMA_BUFFER_ACK(input->nr));
+                       input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr));
+                      }
+       }
+       if (input->port->class == DDB_PORT_CI)
+               wake_up(&input->wq);
+       spin_unlock(&input->lock);
+}
+
+static void output_tasklet(unsigned long data)
+{
+       struct ddb_output *output = (struct ddb_output *) data;
+       struct ddb *dev = output->port->dev;
+
+       spin_lock(&output->lock);
+       if (!output->running) {
+               spin_unlock(&output->lock);
+               return;
+       }
+       output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8));
+       wake_up(&output->wq);
+       spin_unlock(&output->lock);
+}
+
+
+struct cxd2099_cfg cxd_cfg = {
+       .bitrate =  62000,
+       .adr     =  0x40,
+       .polarity = 1,
+       .clock_mode = 1,
+};
+
+static int ddb_ci_attach(struct ddb_port *port)
+{
+       int ret;
+
+       ret = dvb_register_adapter(&port->output->adap,
+                                  "DDBridge",
+                                  THIS_MODULE,
+                                  &port->dev->pdev->dev,
+                                  adapter_nr);
+       if (ret < 0)
+               return ret;
+       port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap);
+       if (!port->en) {
+               dvb_unregister_adapter(&port->output->adap);
+               return -ENODEV;
+       }
+       ddb_input_start(port->input[0]);
+       ddb_output_start(port->output);
+       dvb_ca_en50221_init(&port->output->adap,
+                           port->en, 0, 1);
+       ret = dvb_register_device(&port->output->adap, &port->output->dev,
+                                 &dvbdev_ci, (void *) port->output,
+                                 DVB_DEVICE_SEC);
+       return ret;
+}
+
+static int ddb_port_attach(struct ddb_port *port)
+{
+       int ret = 0;
+
+       switch (port->class) {
+       case DDB_PORT_TUNER:
+               ret = dvb_input_attach(port->input[0]);
+               if (ret < 0)
+                       break;
+               ret = dvb_input_attach(port->input[1]);
+               break;
+       case DDB_PORT_CI:
+               ret = ddb_ci_attach(port);
+               break;
+       default:
+               break;
+       }
+       if (ret < 0)
+               printk(KERN_ERR "port_attach on port %d failed\n", port->nr);
+       return ret;
+}
+
+static int ddb_ports_attach(struct ddb *dev)
+{
+       int i, ret = 0;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               ret = ddb_port_attach(port);
+               if (ret < 0)
+                       break;
+       }
+       return ret;
+}
+
+static void ddb_ports_detach(struct ddb *dev)
+{
+       int i;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               switch (port->class) {
+               case DDB_PORT_TUNER:
+                       dvb_input_detach(port->input[0]);
+                       dvb_input_detach(port->input[1]);
+                       break;
+               case DDB_PORT_CI:
+                       if (port->output->dev)
+                               dvb_unregister_device(port->output->dev);
+                       if (port->en) {
+                               ddb_input_stop(port->input[0]);
+                               ddb_output_stop(port->output);
+                               dvb_ca_en50221_release(port->en);
+                               kfree(port->en);
+                               port->en = 0;
+                               dvb_unregister_adapter(&port->output->adap);
+                       }
+                       break;
+               }
+       }
+}
+
+/****************************************************************************/
+/****************************************************************************/
+
+static int port_has_ci(struct ddb_port *port)
+{
+       u8 val;
+       return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1;
+}
+
+static int port_has_stv0900(struct ddb_port *port)
+{
+       u8 val;
+       if (i2c_read_reg16(&port->i2c->adap, 0x69, 0xf100, &val) < 0)
+               return 0;
+       return 1;
+}
+
+static int port_has_stv0900_aa(struct ddb_port *port)
+{
+       u8 val;
+       if (i2c_read_reg16(&port->i2c->adap, 0x68, 0xf100, &val) < 0)
+               return 0;
+       return 1;
+}
+
+static int port_has_drxks(struct ddb_port *port)
+{
+       u8 val;
+       if (i2c_read(&port->i2c->adap, 0x29, &val) < 0)
+               return 0;
+       if (i2c_read(&port->i2c->adap, 0x2a, &val) < 0)
+               return 0;
+       return 1;
+}
+
+static void ddb_port_probe(struct ddb_port *port)
+{
+       struct ddb *dev = port->dev;
+       char *modname = "NO MODULE";
+
+       port->class = DDB_PORT_NONE;
+
+       if (port_has_ci(port)) {
+               modname = "CI";
+               port->class = DDB_PORT_CI;
+               ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
+       } else if (port_has_stv0900(port)) {
+               modname = "DUAL DVB-S2";
+               port->class = DDB_PORT_TUNER;
+               port->type = DDB_TUNER_DVBS_ST;
+               ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
+       } else if (port_has_stv0900_aa(port)) {
+               modname = "DUAL DVB-S2";
+               port->class = DDB_PORT_TUNER;
+               port->type = DDB_TUNER_DVBS_ST_AA;
+               ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING);
+       } else if (port_has_drxks(port)) {
+               modname = "DUAL DVB-C/T";
+               port->class = DDB_PORT_TUNER;
+               port->type = DDB_TUNER_DVBCT_TR;
+               ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING);
+       }
+       printk(KERN_INFO "Port %d (TAB %d): %s\n",
+                        port->nr, port->nr+1, modname);
+}
+
+static void ddb_input_init(struct ddb_port *port, int nr)
+{
+       struct ddb *dev = port->dev;
+       struct ddb_input *input = &dev->input[nr];
+
+       input->nr = nr;
+       input->port = port;
+       input->dma_buf_num = INPUT_DMA_BUFS;
+       input->dma_buf_size = INPUT_DMA_SIZE;
+       ddbwritel(0, TS_INPUT_CONTROL(nr));
+       ddbwritel(2, TS_INPUT_CONTROL(nr));
+       ddbwritel(0, TS_INPUT_CONTROL(nr));
+       ddbwritel(0, DMA_BUFFER_ACK(nr));
+       tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input);
+       spin_lock_init(&input->lock);
+       init_waitqueue_head(&input->wq);
+}
+
+static void ddb_output_init(struct ddb_port *port, int nr)
+{
+       struct ddb *dev = port->dev;
+       struct ddb_output *output = &dev->output[nr];
+       output->nr = nr;
+       output->port = port;
+       output->dma_buf_num = OUTPUT_DMA_BUFS;
+       output->dma_buf_size = OUTPUT_DMA_SIZE;
+
+       ddbwritel(0, TS_OUTPUT_CONTROL(nr));
+       ddbwritel(2, TS_OUTPUT_CONTROL(nr));
+       ddbwritel(0, TS_OUTPUT_CONTROL(nr));
+       tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output);
+       init_waitqueue_head(&output->wq);
+}
+
+static void ddb_ports_init(struct ddb *dev)
+{
+       int i;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               port->dev = dev;
+               port->nr = i;
+               port->i2c = &dev->i2c[i];
+               port->input[0] = &dev->input[2 * i];
+               port->input[1] = &dev->input[2 * i + 1];
+               port->output = &dev->output[i];
+
+               mutex_init(&port->i2c_gate_lock);
+               ddb_port_probe(port);
+               ddb_input_init(port, 2 * i);
+               ddb_input_init(port, 2 * i + 1);
+               ddb_output_init(port, i);
+       }
+}
+
+static void ddb_ports_release(struct ddb *dev)
+{
+       int i;
+       struct ddb_port *port;
+
+       for (i = 0; i < dev->info->port_num; i++) {
+               port = &dev->port[i];
+               port->dev = dev;
+               tasklet_kill(&port->input[0]->tasklet);
+               tasklet_kill(&port->input[1]->tasklet);
+               tasklet_kill(&port->output->tasklet);
+       }
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void irq_handle_i2c(struct ddb *dev, int n)
+{
+       struct ddb_i2c *i2c = &dev->i2c[n];
+
+       i2c->done = 1;
+       wake_up(&i2c->wq);
+}
+
+static irqreturn_t irq_handler(int irq, void *dev_id)
+{
+       struct ddb *dev = (struct ddb *) dev_id;
+       u32 s = ddbreadl(INTERRUPT_STATUS);
+
+       if (!s)
+               return IRQ_NONE;
+
+       do {
+               ddbwritel(s, INTERRUPT_ACK);
+
+               if (s & 0x00000001)
+                       irq_handle_i2c(dev, 0);
+               if (s & 0x00000002)
+                       irq_handle_i2c(dev, 1);
+               if (s & 0x00000004)
+                       irq_handle_i2c(dev, 2);
+               if (s & 0x00000008)
+                       irq_handle_i2c(dev, 3);
+
+               if (s & 0x00000100)
+                       tasklet_schedule(&dev->input[0].tasklet);
+               if (s & 0x00000200)
+                       tasklet_schedule(&dev->input[1].tasklet);
+               if (s & 0x00000400)
+                       tasklet_schedule(&dev->input[2].tasklet);
+               if (s & 0x00000800)
+                       tasklet_schedule(&dev->input[3].tasklet);
+               if (s & 0x00001000)
+                       tasklet_schedule(&dev->input[4].tasklet);
+               if (s & 0x00002000)
+                       tasklet_schedule(&dev->input[5].tasklet);
+               if (s & 0x00004000)
+                       tasklet_schedule(&dev->input[6].tasklet);
+               if (s & 0x00008000)
+                       tasklet_schedule(&dev->input[7].tasklet);
+
+               if (s & 0x00010000)
+                       tasklet_schedule(&dev->output[0].tasklet);
+               if (s & 0x00020000)
+                       tasklet_schedule(&dev->output[1].tasklet);
+               if (s & 0x00040000)
+                       tasklet_schedule(&dev->output[2].tasklet);
+               if (s & 0x00080000)
+                       tasklet_schedule(&dev->output[3].tasklet);
+
+               /* if (s & 0x000f0000)  printk(KERN_DEBUG "%08x\n", istat); */
+       } while ((s = ddbreadl(INTERRUPT_STATUS)));
+
+       return IRQ_HANDLED;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
+{
+       u32 data, shift;
+
+       if (wlen > 4)
+               ddbwritel(1, SPI_CONTROL);
+       while (wlen > 4) {
+               /* FIXME: check for big-endian */
+               data = swab32(*(u32 *)wbuf);
+               wbuf += 4;
+               wlen -= 4;
+               ddbwritel(data, SPI_DATA);
+               while (ddbreadl(SPI_CONTROL) & 0x0004)
+                       ;
+       }
+
+       if (rlen)
+               ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL);
+       else
+               ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL);
+
+       data = 0;
+       shift = ((4 - wlen) * 8);
+       while (wlen) {
+               data <<= 8;
+               data |= *wbuf;
+               wlen--;
+               wbuf++;
+       }
+       if (shift)
+               data <<= shift;
+       ddbwritel(data, SPI_DATA);
+       while (ddbreadl(SPI_CONTROL) & 0x0004)
+               ;
+
+       if (!rlen) {
+               ddbwritel(0, SPI_CONTROL);
+               return 0;
+       }
+       if (rlen > 4)
+               ddbwritel(1, SPI_CONTROL);
+
+       while (rlen > 4) {
+               ddbwritel(0xffffffff, SPI_DATA);
+               while (ddbreadl(SPI_CONTROL) & 0x0004)
+                       ;
+               data = ddbreadl(SPI_DATA);
+               *(u32 *) rbuf = swab32(data);
+               rbuf += 4;
+               rlen -= 4;
+       }
+       ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL);
+       ddbwritel(0xffffffff, SPI_DATA);
+       while (ddbreadl(SPI_CONTROL) & 0x0004)
+               ;
+
+       data = ddbreadl(SPI_DATA);
+       ddbwritel(0, SPI_CONTROL);
+
+       if (rlen < 4)
+               data <<= ((4 - rlen) * 8);
+
+       while (rlen > 0) {
+               *rbuf = ((data >> 24) & 0xff);
+               data <<= 8;
+               rbuf++;
+               rlen--;
+       }
+       return 0;
+}
+
+#define DDB_MAGIC 'd'
+
+struct ddb_flashio {
+       __u8 *write_buf;
+       __u32 write_len;
+       __u8 *read_buf;
+       __u32 read_len;
+};
+
+#define IOCTL_DDB_FLASHIO  _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio)
+
+#define DDB_NAME "ddbridge"
+
+static u32 ddb_num;
+static struct ddb *ddbs[32];
+static struct class *ddb_class;
+static int ddb_major;
+
+static int ddb_open(struct inode *inode, struct file *file)
+{
+       struct ddb *dev = ddbs[iminor(inode)];
+
+       file->private_data = dev;
+       return 0;
+}
+
+static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct ddb *dev = file->private_data;
+       void *parg = (void *)arg;
+       int res = -EFAULT;
+
+       switch (cmd) {
+       case IOCTL_DDB_FLASHIO:
+       {
+               struct ddb_flashio fio;
+               u8 *rbuf, *wbuf;
+
+               if (copy_from_user(&fio, parg, sizeof(fio)))
+                       break;
+               if (fio.write_len + fio.read_len > 1028) {
+                       printk(KERN_ERR "IOBUF too small\n");
+                       return -ENOMEM;
+               }
+               wbuf = &dev->iobuf[0];
+               if (!wbuf)
+                       return -ENOMEM;
+               rbuf = wbuf + fio.write_len;
+               if (copy_from_user(wbuf, fio.write_buf, fio.write_len)) {
+                       vfree(wbuf);
+                       break;
+               }
+               res = flashio(dev, wbuf, fio.write_len,
+                             rbuf, fio.read_len);
+               if (copy_to_user(fio.read_buf, rbuf, fio.read_len))
+                       res = -EFAULT;
+               break;
+       }
+       default:
+               break;
+       }
+       return res;
+}
+
+static const struct file_operations ddb_fops = {
+       .unlocked_ioctl = ddb_ioctl,
+       .open           = ddb_open,
+};
+
+static char *ddb_devnode(struct device *device, mode_t *mode)
+{
+       struct ddb *dev = dev_get_drvdata(device);
+
+       return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr);
+}
+
+static int ddb_class_create(void)
+{
+       ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops);
+       if (ddb_major < 0)
+               return ddb_major;
+
+       ddb_class = class_create(THIS_MODULE, DDB_NAME);
+       if (IS_ERR(ddb_class)) {
+               unregister_chrdev(ddb_major, DDB_NAME);
+               return -1;
+       }
+       ddb_class->devnode = ddb_devnode;
+       return 0;
+}
+
+static void ddb_class_destroy(void)
+{
+       class_destroy(ddb_class);
+       unregister_chrdev(ddb_major, DDB_NAME);
+}
+
+static int ddb_device_create(struct ddb *dev)
+{
+       dev->nr = ddb_num++;
+       dev->ddb_dev = device_create(ddb_class, NULL,
+                                    MKDEV(ddb_major, dev->nr),
+                                    dev, "ddbridge%d", dev->nr);
+       ddbs[dev->nr] = dev;
+       if (IS_ERR(dev->ddb_dev))
+               return -1;
+       return 0;
+}
+
+static void ddb_device_destroy(struct ddb *dev)
+{
+       ddb_num--;
+       if (IS_ERR(dev->ddb_dev))
+               return;
+       device_destroy(ddb_class, MKDEV(ddb_major, 0));
+}
+
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static void ddb_unmap(struct ddb *dev)
+{
+       if (dev->regs)
+               iounmap(dev->regs);
+       vfree(dev);
+}
+
+
+static void __devexit ddb_remove(struct pci_dev *pdev)
+{
+       struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev);
+
+       ddb_ports_detach(dev);
+       ddb_i2c_release(dev);
+
+       ddbwritel(0, INTERRUPT_ENABLE);
+       free_irq(dev->pdev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+       if (dev->msi)
+               pci_disable_msi(dev->pdev);
+#endif
+       ddb_ports_release(dev);
+       ddb_buffers_free(dev);
+       ddb_device_destroy(dev);
+
+       ddb_unmap(dev);
+       pci_set_drvdata(pdev, 0);
+       pci_disable_device(pdev);
+}
+
+
+static int __devinit ddb_probe(struct pci_dev *pdev,
+                              const struct pci_device_id *id)
+{
+       struct ddb *dev;
+       int stat = 0;
+       int irq_flag = IRQF_SHARED;
+
+       if (pci_enable_device(pdev) < 0)
+               return -ENODEV;
+
+       dev = vmalloc(sizeof(struct ddb));
+       if (dev == NULL)
+               return -ENOMEM;
+       memset(dev, 0, sizeof(struct ddb));
+
+       dev->pdev = pdev;
+       pci_set_drvdata(pdev, dev);
+       dev->info = (struct ddb_info *) id->driver_data;
+       printk(KERN_INFO "DDBridge driver detected: %s\n", dev->info->name);
+
+       dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
+                           pci_resource_len(dev->pdev, 0));
+       if (!dev->regs) {
+               stat = -ENOMEM;
+               goto fail;
+       }
+       printk(KERN_INFO "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4));
+
+#ifdef CONFIG_PCI_MSI
+       if (pci_msi_enabled())
+               stat = pci_enable_msi(dev->pdev);
+       if (stat) {
+               printk(KERN_INFO ": MSI not available.\n");
+       } else {
+               irq_flag = 0;
+               dev->msi = 1;
+       }
+#endif
+       stat = request_irq(dev->pdev->irq, irq_handler,
+                          irq_flag, "DDBridge", (void *) dev);
+       if (stat < 0)
+               goto fail1;
+       ddbwritel(0, DMA_BASE_WRITE);
+       ddbwritel(0, DMA_BASE_READ);
+       ddbwritel(0xffffffff, INTERRUPT_ACK);
+       ddbwritel(0xfff0f, INTERRUPT_ENABLE);
+       ddbwritel(0, MSI1_ENABLE);
+
+       if (ddb_i2c_init(dev) < 0)
+               goto fail1;
+       ddb_ports_init(dev);
+       if (ddb_buffers_alloc(dev) < 0) {
+               printk(KERN_INFO ": Could not allocate buffer memory\n");
+               goto fail2;
+       }
+       if (ddb_ports_attach(dev) < 0)
+               goto fail3;
+       ddb_device_create(dev);
+       return 0;
+
+fail3:
+       ddb_ports_detach(dev);
+       printk(KERN_ERR "fail3\n");
+       ddb_ports_release(dev);
+fail2:
+       printk(KERN_ERR "fail2\n");
+       ddb_buffers_free(dev);
+fail1:
+       printk(KERN_ERR "fail1\n");
+       if (dev->msi)
+               pci_disable_msi(dev->pdev);
+       free_irq(dev->pdev->irq, dev);
+fail:
+       printk(KERN_ERR "fail\n");
+       ddb_unmap(dev);
+       pci_set_drvdata(pdev, 0);
+       pci_disable_device(pdev);
+       return -1;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+
+static struct ddb_info ddb_none = {
+       .type     = DDB_NONE,
+       .name     = "Digital Devices PCIe bridge",
+};
+
+static struct ddb_info ddb_octopus = {
+       .type     = DDB_OCTOPUS,
+       .name     = "Digital Devices Octopus DVB adapter",
+       .port_num = 4,
+};
+
+static struct ddb_info ddb_octopus_le = {
+       .type     = DDB_OCTOPUS,
+       .name     = "Digital Devices Octopus LE DVB adapter",
+       .port_num = 2,
+};
+
+static struct ddb_info ddb_v6 = {
+       .type     = DDB_OCTOPUS,
+       .name     = "Digital Devices Cine S2 V6 DVB adapter",
+       .port_num = 3,
+};
+
+#define DDVID 0xdd01 /* Digital Devices Vendor ID */
+
+#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) {  \
+       .vendor      = _vend,    .device    = _dev, \
+       .subvendor   = _subvend, .subdevice = _subdev, \
+       .driver_data = (unsigned long)&_driverdata }
+
+static const struct pci_device_id ddb_id_tbl[] __devinitdata = {
+       DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus),
+       DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus),
+       DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le),
+       DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus),
+       DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6),
+       /* in case sub-ids got deleted in flash */
+       DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
+       {0}
+};
+MODULE_DEVICE_TABLE(pci, ddb_id_tbl);
+
+
+static struct pci_driver ddb_pci_driver = {
+       .name        = "DDBridge",
+       .id_table    = ddb_id_tbl,
+       .probe       = ddb_probe,
+       .remove      = ddb_remove,
+};
+
+static __init int module_init_ddbridge(void)
+{
+       printk(KERN_INFO "Digital Devices PCIE bridge driver, "
+              "Copyright (C) 2010-11 Digital Devices GmbH\n");
+       if (ddb_class_create())
+               return -1;
+       return pci_register_driver(&ddb_pci_driver);
+}
+
+static __exit void module_exit_ddbridge(void)
+{
+       pci_unregister_driver(&ddb_pci_driver);
+       ddb_class_destroy();
+}
+
+module_init(module_init_ddbridge);
+module_exit(module_exit_ddbridge);
+
+MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
+MODULE_AUTHOR("Ralph Metzler");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.5");
diff --git a/drivers/media/dvb/ddbridge/ddbridge-regs.h b/drivers/media/dvb/ddbridge/ddbridge-regs.h
new file mode 100644 (file)
index 0000000..a3ccb31
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * ddbridge-regs.h: Digital Devices PCIe bridge driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */
+
+/* Register Definitions */
+
+#define CUR_REGISTERMAP_VERSION 0x10000
+
+#define HARDWARE_VERSION       0x00
+#define REGISTERMAP_VERSION    0x04
+
+/* ------------------------------------------------------------------------- */
+/* SPI Controller */
+
+#define SPI_CONTROL     0x10
+#define SPI_DATA        0x14
+
+/* ------------------------------------------------------------------------- */
+
+/* Interrupt controller                                     */
+/* How many MSI's are available depends on HW (Min 2 max 8) */
+/* How many are usable also depends on Host platform        */
+
+#define INTERRUPT_BASE   (0x40)
+
+#define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00)
+#define MSI0_ENABLE      (INTERRUPT_BASE + 0x00)
+#define MSI1_ENABLE      (INTERRUPT_BASE + 0x04)
+#define MSI2_ENABLE      (INTERRUPT_BASE + 0x08)
+#define MSI3_ENABLE      (INTERRUPT_BASE + 0x0C)
+#define MSI4_ENABLE      (INTERRUPT_BASE + 0x10)
+#define MSI5_ENABLE      (INTERRUPT_BASE + 0x14)
+#define MSI6_ENABLE      (INTERRUPT_BASE + 0x18)
+#define MSI7_ENABLE      (INTERRUPT_BASE + 0x1C)
+
+#define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20)
+#define INTERRUPT_ACK    (INTERRUPT_BASE + 0x20)
+
+#define INTMASK_I2C1        (0x00000001)
+#define INTMASK_I2C2        (0x00000002)
+#define INTMASK_I2C3        (0x00000004)
+#define INTMASK_I2C4        (0x00000008)
+
+#define INTMASK_CIRQ1       (0x00000010)
+#define INTMASK_CIRQ2       (0x00000020)
+#define INTMASK_CIRQ3       (0x00000040)
+#define INTMASK_CIRQ4       (0x00000080)
+
+#define INTMASK_TSINPUT1    (0x00000100)
+#define INTMASK_TSINPUT2    (0x00000200)
+#define INTMASK_TSINPUT3    (0x00000400)
+#define INTMASK_TSINPUT4    (0x00000800)
+#define INTMASK_TSINPUT5    (0x00001000)
+#define INTMASK_TSINPUT6    (0x00002000)
+#define INTMASK_TSINPUT7    (0x00004000)
+#define INTMASK_TSINPUT8    (0x00008000)
+
+#define INTMASK_TSOUTPUT1   (0x00010000)
+#define INTMASK_TSOUTPUT2   (0x00020000)
+#define INTMASK_TSOUTPUT3   (0x00040000)
+#define INTMASK_TSOUTPUT4   (0x00080000)
+
+/* ------------------------------------------------------------------------- */
+/* I2C Master Controller */
+
+#define I2C_BASE        (0x80)  /* Byte offset */
+
+#define I2C_COMMAND     (0x00)
+#define I2C_TIMING      (0x04)
+#define I2C_TASKLENGTH  (0x08)     /* High read, low write */
+#define I2C_TASKADDRESS (0x0C)     /* High read, low write */
+
+#define I2C_MONITOR     (0x1C)
+
+#define I2C_BASE_1      (I2C_BASE + 0x00)
+#define I2C_BASE_2      (I2C_BASE + 0x20)
+#define I2C_BASE_3      (I2C_BASE + 0x40)
+#define I2C_BASE_4      (I2C_BASE + 0x60)
+
+#define I2C_BASE_N(i)   (I2C_BASE + (i) * 0x20)
+
+#define I2C_TASKMEM_BASE    (0x1000)    /* Byte offset */
+#define I2C_TASKMEM_SIZE    (0x1000)
+
+#define I2C_SPEED_400   (0x04030404)
+#define I2C_SPEED_200   (0x09080909)
+#define I2C_SPEED_154   (0x0C0B0C0C)
+#define I2C_SPEED_100   (0x13121313)
+#define I2C_SPEED_77    (0x19181919)
+#define I2C_SPEED_50    (0x27262727)
+
+
+/* ------------------------------------------------------------------------- */
+/* DMA  Controller */
+
+#define DMA_BASE_WRITE        (0x100)
+#define DMA_BASE_READ         (0x140)
+
+#define DMA_CONTROL     (0x00)                  /* 64 */
+#define DMA_ERROR       (0x04)                  /* 65 ( only read instance ) */
+
+#define DMA_DIAG_CONTROL                (0x1C)  /* 71 */
+#define DMA_DIAG_PACKETCOUNTER_LOW      (0x20)  /* 72 */
+#define DMA_DIAG_PACKETCOUNTER_HIGH     (0x24)  /* 73 */
+#define DMA_DIAG_TIMECOUNTER_LOW        (0x28)  /* 74 */
+#define DMA_DIAG_TIMECOUNTER_HIGH       (0x2C)  /* 75 */
+#define DMA_DIAG_RECHECKCOUNTER         (0x30)  /* 76  ( Split completions on read ) */
+#define DMA_DIAG_WAITTIMEOUTINIT        (0x34)  /* 77 */
+#define DMA_DIAG_WAITOVERFLOWCOUNTER    (0x38)  /* 78 */
+#define DMA_DIAG_WAITCOUNTER            (0x3C)  /* 79 */
+
+/* ------------------------------------------------------------------------- */
+/* DMA  Buffer */
+
+#define TS_INPUT_BASE       (0x200)
+#define TS_INPUT_CONTROL(i)         (TS_INPUT_BASE + (i) * 16 + 0x00)
+
+#define TS_OUTPUT_BASE       (0x280)
+#define TS_OUTPUT_CONTROL(i)         (TS_OUTPUT_BASE + (i) * 16 + 0x00)
+
+#define DMA_BUFFER_BASE     (0x300)
+
+#define DMA_BUFFER_CONTROL(i)       (DMA_BUFFER_BASE + (i) * 16 + 0x00)
+#define DMA_BUFFER_ACK(i)           (DMA_BUFFER_BASE + (i) * 16 + 0x04)
+#define DMA_BUFFER_CURRENT(i)       (DMA_BUFFER_BASE + (i) * 16 + 0x08)
+#define DMA_BUFFER_SIZE(i)          (DMA_BUFFER_BASE + (i) * 16 + 0x0c)
+
+#define DMA_BASE_ADDRESS_TABLE  (0x2000)
+#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512)
+
diff --git a/drivers/media/dvb/ddbridge/ddbridge.h b/drivers/media/dvb/ddbridge/ddbridge.h
new file mode 100644 (file)
index 0000000..6d14893
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * ddbridge.h: Digital Devices PCIe bridge driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _DDBRIDGE_H_
+#define _DDBRIDGE_H_
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <asm/dma.h>
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/ca.h>
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <linux/socket.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_ringbuffer.h"
+#include "dvb_ca_en50221.h"
+#include "dvb_net.h"
+#include "cxd2099.h"
+
+#define DDB_MAX_I2C     4
+#define DDB_MAX_PORT    4
+#define DDB_MAX_INPUT   8
+#define DDB_MAX_OUTPUT  4
+
+struct ddb_info {
+       int   type;
+#define DDB_NONE         0
+#define DDB_OCTOPUS      1
+       char *name;
+       int   port_num;
+       u32   port_type[DDB_MAX_PORT];
+};
+
+/* DMA_SIZE MUST be divisible by 188 and 128 !!! */
+
+#define INPUT_DMA_MAX_BUFS 32      /* hardware table limit */
+#define INPUT_DMA_BUFS 8
+#define INPUT_DMA_SIZE (128*47*21)
+
+#define OUTPUT_DMA_MAX_BUFS 32
+#define OUTPUT_DMA_BUFS 8
+#define OUTPUT_DMA_SIZE (128*47*21)
+
+struct ddb;
+struct ddb_port;
+
+struct ddb_input {
+       struct ddb_port       *port;
+       u32                    nr;
+       int                    attached;
+
+       dma_addr_t             pbuf[INPUT_DMA_MAX_BUFS];
+       u8                    *vbuf[INPUT_DMA_MAX_BUFS];
+       u32                    dma_buf_num;
+       u32                    dma_buf_size;
+
+       struct tasklet_struct  tasklet;
+       spinlock_t             lock;
+       wait_queue_head_t      wq;
+       int                    running;
+       u32                    stat;
+       u32                    cbuf;
+       u32                    coff;
+
+       struct dvb_adapter     adap;
+       struct dvb_device     *dev;
+       struct dvb_frontend   *fe;
+       struct dvb_frontend   *fe2;
+       struct dmxdev          dmxdev;
+       struct dvb_demux       demux;
+       struct dvb_net         dvbnet;
+       struct dmx_frontend    hw_frontend;
+       struct dmx_frontend    mem_frontend;
+       int                    users;
+       int (*gate_ctrl)(struct dvb_frontend *, int);
+};
+
+struct ddb_output {
+       struct ddb_port       *port;
+       u32                    nr;
+       dma_addr_t             pbuf[OUTPUT_DMA_MAX_BUFS];
+       u8                    *vbuf[OUTPUT_DMA_MAX_BUFS];
+       u32                    dma_buf_num;
+       u32                    dma_buf_size;
+       struct tasklet_struct  tasklet;
+       spinlock_t             lock;
+       wait_queue_head_t      wq;
+       int                    running;
+       u32                    stat;
+       u32                    cbuf;
+       u32                    coff;
+
+       struct dvb_adapter     adap;
+       struct dvb_device     *dev;
+};
+
+struct ddb_i2c {
+       struct ddb            *dev;
+       u32                    nr;
+       struct i2c_adapter     adap;
+       struct i2c_adapter     adap2;
+       u32                    regs;
+       u32                    rbuf;
+       u32                    wbuf;
+       int                    done;
+       wait_queue_head_t      wq;
+};
+
+struct ddb_port {
+       struct ddb            *dev;
+       u32                    nr;
+       struct ddb_i2c        *i2c;
+       struct mutex           i2c_gate_lock;
+       u32                    class;
+#define DDB_PORT_NONE           0
+#define DDB_PORT_CI             1
+#define DDB_PORT_TUNER          2
+       u32                    type;
+#define DDB_TUNER_NONE          0
+#define DDB_TUNER_DVBS_ST       1
+#define DDB_TUNER_DVBS_ST_AA    2
+#define DDB_TUNER_DVBCT_TR     16
+#define DDB_TUNER_DVBCT_ST     17
+       u32                    adr;
+
+       struct ddb_input      *input[2];
+       struct ddb_output     *output;
+       struct dvb_ca_en50221 *en;
+};
+
+struct ddb {
+       struct pci_dev        *pdev;
+       unsigned char         *regs;
+       struct ddb_port        port[DDB_MAX_PORT];
+       struct ddb_i2c         i2c[DDB_MAX_I2C];
+       struct ddb_input       input[DDB_MAX_INPUT];
+       struct ddb_output      output[DDB_MAX_OUTPUT];
+
+       struct device         *ddb_dev;
+       int                    nr;
+       u8                     iobuf[1028];
+
+       struct ddb_info       *info;
+       int                    msi;
+};
+
+/****************************************************************************/
+
+#define ddbwritel(_val, _adr)        writel((_val), \
+                                    (char *) (dev->regs+(_adr)))
+#define ddbreadl(_adr)               readl((char *) (dev->regs+(_adr)))
+#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *)      \
+                                    (dev->regs+(_adr)), (_src), (_count))
+#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \
+                                      (dev->regs+(_adr)), (_count))
+
+/****************************************************************************/
+
+#endif
index 0b5182835cc82d4205b06ac473073d3e1b6e0ac2..8f22bcd7c1f9122694e552cb1c39688ee95b1518 100644 (file)
@@ -2,8 +2,10 @@
 # Makefile for the kernel DVB device drivers.
 #
 
+dvb-net-$(CONFIG_DVB_NET) := dvb_net.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
+                $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
 
 obj-$(CONFIG_DVB_CORE) += dvb-core.o
index 5b6b451d46940db41b8d2b3fd4473e7a1429383a..efe9c30605e890688b6a7557156436fe0c4611a9 100644 (file)
@@ -904,7 +904,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
        .buffer = b \
 }
 
-static struct dtv_cmds_h dtv_cmds[] = {
+static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
        _DTV_CMD(DTV_TUNE, 1, 0),
        _DTV_CMD(DTV_CLEAR, 1, 0),
 
@@ -966,6 +966,7 @@ static struct dtv_cmds_h dtv_cmds[] = {
        _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0),
 
        _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
+       _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
 
        /* Get */
        _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
index 3a3126cae03b0c26d81b1f639017a1c87b0554c4..1e53acd50cf40fa22d2e15f7d1932aadcbb03df7 100644 (file)
@@ -32,6 +32,8 @@
 
 #define DVB_NET_DEVICES_MAX 10
 
+#ifdef CONFIG_DVB_NET
+
 struct dvb_net {
        struct dvb_device *dvbdev;
        struct net_device *device[DVB_NET_DEVICES_MAX];
@@ -40,8 +42,25 @@ struct dvb_net {
        struct dmx_demux *demux;
 };
 
-
 void dvb_net_release(struct dvb_net *);
 int  dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
 
+#else
+
+struct dvb_net {
+       struct dvb_device *dvbdev;
+};
+
+static inline void dvb_net_release(struct dvb_net *dvbnet)
+{
+}
+
+static inline int dvb_net_init(struct dvb_adapter *adap,
+                              struct dvb_net *dvbnet, struct dmx_demux *dmx)
+{
+       return 0;
+}
+
+#endif /* ifdef CONFIG_DVB_NET */
+
 #endif
index e85304c59a2bcea78273f4b316d241aa6c49152c..5d73dec8ac0724a557a8ba8a223e8edc0c9e2651 100644 (file)
@@ -81,6 +81,7 @@ config DVB_USB_DIB0700
        select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
        help
          Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
index 100ebc37e99e2293699816a15556fdc672640e05..d7ad05fc383b7a8422fb8d1b8425bb87862790ed 100644 (file)
@@ -91,7 +91,6 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
        case GET_CONFIG:
        case READ_MEMORY:
        case RECONNECT_USB:
-       case GET_IR_CODE:
                write = 0;
                break;
        case READ_I2C:
@@ -164,13 +163,6 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
        deb_xfer("<<< ");
        debug_dump(buf, act_len, deb_xfer);
 
-       /* remote controller query status is 1 if remote code is not received */
-       if (req->cmd == GET_IR_CODE && buf[1] == 1) {
-               buf[1] = 0; /* clear command "error" status */
-               memset(&buf[2], 0, req->data_len);
-               buf[3] = 1; /* no remote code received mark */
-       }
-
        /* check status */
        if (buf[1]) {
                err("command failed:%d", buf[1]);
@@ -292,6 +284,10 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                }
 
                if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+                       if (msg[i].len > 3 || msg[i+1].len > 61) {
+                               ret = -EOPNOTSUPP;
+                               goto error;
+                       }
                        if (msg[i].addr ==
                                af9015_af9013_config[0].demod_address)
                                req.cmd = READ_MEMORY;
@@ -306,12 +302,16 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                        ret = af9015_ctrl_msg(d, &req);
                        i += 2;
                } else if (msg[i].flags & I2C_M_RD) {
-                       ret = -EINVAL;
+                       if (msg[i].len > 61) {
+                               ret = -EOPNOTSUPP;
+                               goto error;
+                       }
                        if (msg[i].addr ==
-                               af9015_af9013_config[0].demod_address)
+                               af9015_af9013_config[0].demod_address) {
+                               ret = -EINVAL;
                                goto error;
-                       else
-                               req.cmd = READ_I2C;
+                       }
+                       req.cmd = READ_I2C;
                        req.i2c_addr = msg[i].addr;
                        req.addr = addr;
                        req.mbox = mbox;
@@ -321,6 +321,10 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
                        ret = af9015_ctrl_msg(d, &req);
                        i += 1;
                } else {
+                       if (msg[i].len > 21) {
+                               ret = -EOPNOTSUPP;
+                               goto error;
+                       }
                        if (msg[i].addr ==
                                af9015_af9013_config[0].demod_address)
                                req.cmd = WRITE_MEMORY;
@@ -735,6 +739,7 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
        { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
        { 0xa3703d00, RC_MAP_ALINK_DTU_M },
        { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
+       { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */
        { }
 };
 
@@ -749,6 +754,8 @@ static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
                RC_MAP_AZUREWAVE_AD_TU700 },
        { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III,
                RC_MAP_MSI_DIGIVOX_III },
+       { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGIVOX_DUO,
+               RC_MAP_MSI_DIGIVOX_III },
        { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD,
                RC_MAP_LEADTEK_Y04G0051 },
        { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X,
@@ -759,6 +766,8 @@ static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
                RC_MAP_DIGITALNOW_TINYTWIN },
        { (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3,
                RC_MAP_DIGITALNOW_TINYTWIN },
+       { (USB_VID_KWORLD_2 << 16) + USB_PID_SVEON_STV22,
+               RC_MAP_MSI_DIGIVOX_III },
        { }
 };
 
@@ -1082,44 +1091,11 @@ error:
        return ret;
 }
 
-/* init 2nd I2C adapter */
-static int af9015_i2c_init(struct dvb_usb_device *d)
-{
-       int ret;
-       struct af9015_state *state = d->priv;
-       deb_info("%s:\n", __func__);
-
-       strncpy(state->i2c_adap.name, d->desc->name,
-               sizeof(state->i2c_adap.name));
-       state->i2c_adap.algo      = d->props.i2c_algo;
-       state->i2c_adap.algo_data = NULL;
-       state->i2c_adap.dev.parent = &d->udev->dev;
-
-       i2c_set_adapdata(&state->i2c_adap, d);
-
-       ret = i2c_add_adapter(&state->i2c_adap);
-       if (ret < 0)
-               err("could not add i2c adapter");
-
-       return ret;
-}
-
 static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
-       struct af9015_state *state = adap->dev->priv;
-       struct i2c_adapter *i2c_adap;
-
-       if (adap->id == 0) {
-               /* select I2C adapter */
-               i2c_adap = &adap->dev->i2c_adap;
-
-               deb_info("%s: init I2C\n", __func__);
-               ret = af9015_i2c_init(adap->dev);
-       } else {
-               /* select I2C adapter */
-               i2c_adap = &state->i2c_adap;
 
+       if (adap->id == 1) {
                /* copy firmware to 2nd demodulator */
                if (af9015_config.dual_mode) {
                        ret = af9015_copy_firmware(adap->dev);
@@ -1136,7 +1112,7 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
 
        /* attach demodulator */
        adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
-               i2c_adap);
+               &adap->dev->i2c_adap);
 
        return adap->fe == NULL ? -ENODEV : 0;
 }
@@ -1206,57 +1182,56 @@ static struct mxl5007t_config af9015_mxl5007t_config = {
 
 static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       struct af9015_state *state = adap->dev->priv;
-       struct i2c_adapter *i2c_adap;
        int ret;
        deb_info("%s:\n", __func__);
 
-       /* select I2C adapter */
-       if (adap->id == 0)
-               i2c_adap = &adap->dev->i2c_adap;
-       else
-               i2c_adap = &state->i2c_adap;
-
        switch (af9015_af9013_config[adap->id].tuner) {
        case AF9013_TUNER_MT2060:
        case AF9013_TUNER_MT2060_2:
-               ret = dvb_attach(mt2060_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(mt2060_attach, adap->fe, &adap->dev->i2c_adap,
                        &af9015_mt2060_config,
                        af9015_config.mt2060_if1[adap->id])
                        == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_QT1010:
        case AF9013_TUNER_QT1010A:
-               ret = dvb_attach(qt1010_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap,
                        &af9015_qt1010_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_TDA18271:
-               ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap,
+               ret = dvb_attach(tda18271_attach, adap->fe, 0xc0,
+                       &adap->dev->i2c_adap,
                        &af9015_tda18271_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_TDA18218:
-               ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(tda18218_attach, adap->fe,
+                       &adap->dev->i2c_adap,
                        &af9015_tda18218_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MXL5003D:
-               ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(mxl5005s_attach, adap->fe,
+                       &adap->dev->i2c_adap,
                        &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MXL5005D:
        case AF9013_TUNER_MXL5005R:
-               ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(mxl5005s_attach, adap->fe,
+                       &adap->dev->i2c_adap,
                        &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_ENV77H11D5:
-               ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, i2c_adap,
+               ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
+                       &adap->dev->i2c_adap,
                        DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MC44S803:
-               ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(mc44s803_attach, adap->fe,
+                       &adap->dev->i2c_adap,
                        &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_MXL5007T:
-               ret = dvb_attach(mxl5007t_attach, adap->fe, i2c_adap,
+               ret = dvb_attach(mxl5007t_attach, adap->fe,
+                       &adap->dev->i2c_adap,
                        0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
                break;
        case AF9013_TUNER_UNKNOWN:
@@ -1309,6 +1284,7 @@ static struct usb_device_id af9015_usb_table[] = {
                USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
 /* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
        {USB_DEVICE(USB_VID_GTEK,      USB_PID_TINYTWIN_3)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_SVEON_STV22)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1502,7 +1478,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 9, /* check max from dvb-usb.h */
+               .num_device_descs = 10, /* check max from dvb-usb.h */
                .devices = {
                        {
                                .name = "Xtensions XD-380",
@@ -1554,6 +1530,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                .cold_ids = {&af9015_usb_table[20], NULL},
                                .warm_ids = {NULL},
                        },
+                       {
+                               .name = "Sveon STV22 Dual USB DVB-T Tuner HDTV",
+                               .cold_ids = {&af9015_usb_table[37], NULL},
+                               .warm_ids = {NULL},
+                       },
                }
        }, {
                .caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -1704,33 +1685,11 @@ static int af9015_usb_probe(struct usb_interface *intf,
        return ret;
 }
 
-static void af9015_i2c_exit(struct dvb_usb_device *d)
-{
-       struct af9015_state *state = d->priv;
-       deb_info("%s:\n", __func__);
-
-       /* remove 2nd I2C adapter */
-       if (d->state & DVB_USB_STATE_I2C)
-               i2c_del_adapter(&state->i2c_adap);
-}
-
-static void af9015_usb_device_exit(struct usb_interface *intf)
-{
-       struct dvb_usb_device *d = usb_get_intfdata(intf);
-       deb_info("%s:\n", __func__);
-
-       /* remove 2nd I2C adapter */
-       if (d != NULL && d->desc != NULL)
-               af9015_i2c_exit(d);
-
-       dvb_usb_device_exit(intf);
-}
-
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver af9015_usb_driver = {
        .name = "dvb_usb_af9015",
        .probe = af9015_usb_probe,
-       .disconnect = af9015_usb_device_exit,
+       .disconnect = dvb_usb_device_exit,
        .id_table = af9015_usb_table,
 };
 
index beb3004f00ba31640aab86399fd7ef4889469d14..6252ea6c19042b75a92e6aee88b3d9ec258f24da 100644 (file)
@@ -99,7 +99,6 @@ enum af9015_ir_mode {
 };
 
 struct af9015_state {
-       struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
        u8 rc_repeat;
        u32 rc_keycode;
        u8 rc_last[4];
index 7c327b54308e30312848d7b9c4c289f28fe2d937..2cbf19a52e38d5124be4b7f805e70f4ce6e8d62f 100644 (file)
@@ -347,15 +347,17 @@ static struct isl6423_config anysee_isl6423_config = {
  * PCB: ?
  * parts: DNOS404ZH102A(MT352, DTT7579(?))
  *
- * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
- * PCB: ?
+ * E30 VID=04b4 PID=861f HW=2 FW=2.1 "anysee-T(LP)"
+ * PCB: PCB 507T (rev1.61)
  * parts: DNOS404ZH103A(ZL10353, DTT7579(?))
+ * OEA=0a OEB=00 OEC=00 OED=ff OEE=00
+ * IOA=45 IOB=ff IOC=00 IOD=ff IOE=00
  *
  * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee"
  * PCB: 507CD (rev1.1)
  * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01
- * OEA=80 OEB=00 OEC=00 OED=ff OEF=fe
- * IOA=4f IOB=ff IOC=00 IOD=06 IOF=01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
+ * IOA=4f IOB=ff IOC=00 IOD=06 IOE=01
  * IOD[0] ZL10353 1=enabled
  * IOA[7] TS 0=enabled
  * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not)
@@ -363,30 +365,30 @@ static struct isl6423_config anysee_isl6423_config = {
  * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)"
  * PCB: 507DC (rev0.2)
  * parts: TDA10023, DTOS403IH102B TM, CST56I01
- * OEA=80 OEB=00 OEC=00 OED=ff OEF=fe
- * IOA=4f IOB=ff IOC=00 IOD=26 IOF=01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEE=fe
+ * IOA=4f IOB=ff IOC=00 IOD=26 IOE=01
  * IOD[0] TDA10023 1=enabled
  *
  * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)"
  * PCB: 507SI (rev2.1)
  * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEF=fe
- * IOA=4d IOB=ff IOC=00 IOD=26 IOF=01
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=fe
+ * IOA=4d IOB=ff IOC=00 IOD=26 IOE=01
  * IOD[0] CX24116 1=enabled
  *
  * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
  * PCB: 507FA (rev0.4)
  * parts: TDA10023, DTOS403IH102B TM, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEF=ff
- * IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
  * IOD[5] TDA10023 1=enabled
  * IOE[0] tuner 1=enabled
  *
  * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
  * PCB: 507FA (rev1.1)
  * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024
- * OEA=80 OEB=00 OEC=ff OED=ff OEF=ff
- * IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0
+ * OEA=80 OEB=00 OEC=ff OED=ff OEE=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOE=c0
  * DVB-C:
  * IOD[5] TDA10023 1=enabled
  * IOE[0] tuner 1=enabled
@@ -398,8 +400,8 @@ static struct isl6423_config anysee_isl6423_config = {
  * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
  * PCB: 508TC (rev0.6)
  * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
- * OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff
- * IOA=4d IOB=00 IOC=cc IOD=48 IOF=e4
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
  * IOA[7] TS 1=enabled
  * IOE[4] TDA18212 1=enabled
  * DVB-C:
@@ -414,11 +416,34 @@ static struct isl6423_config anysee_isl6423_config = {
  * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)"
  * PCB: 508S2 (rev0.7)
  * parts: DNBU10512IST(STV0903, STV6110), ISL6423
- * OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff
- * IOA=4d IOB=00 IOC=c4 IOD=08 IOF=e4
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
  * IOA[7] TS 1=enabled
  * IOE[5] STV0903 1=enabled
  *
+ * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)"
+ * PCB: 508PTC (rev0.5)
+ * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[4] TDA18212 1=enabled
+ * DVB-C:
+ * IOD[6] ZL10353 0=disabled
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] IF 1=enabled
+ * DVB-T:
+ * IOD[5] TDA10023 0=disabled
+ * IOD[6] ZL10353 1=enabled
+ * IOE[0] IF 0=enabled
+ *
+ * E7 S2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)"
+ * PCB: 508PS2 (rev0.4)
+ * parts: DNBU10512IST(STV0903, STV6110), ISL6423
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff
+ * IOA=4d IOB=00 IOC=c4 IOD=08 IOE=e4
+ * IOA[7] TS 1=enabled
+ * IOE[5] STV0903 1=enabled
  */
 
 static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
@@ -459,7 +484,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
        state->hw = hw_info[0];
 
        switch (state->hw) {
-       case ANYSEE_HW_02: /* 2 */
+       case ANYSEE_HW_507T: /* 2 */
                /* E30 */
 
                /* attach demod */
@@ -593,7 +618,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 
                break;
        case ANYSEE_HW_508TC: /* 18 */
+       case ANYSEE_HW_508PTC: /* 21 */
                /* E7 TC */
+               /* E7 PTC */
 
                /* enable transport stream on IOA[7] */
                ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
@@ -650,7 +677,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 
                break;
        case ANYSEE_HW_508S2: /* 19 */
+       case ANYSEE_HW_508PS2: /* 22 */
                /* E7 S2 */
+               /* E7 PS2 */
 
                /* enable transport stream on IOA[7] */
                ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
@@ -687,7 +716,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
        deb_info("%s:\n", __func__);
 
        switch (state->hw) {
-       case ANYSEE_HW_02: /* 2 */
+       case ANYSEE_HW_507T: /* 2 */
                /* E30 */
 
                /* attach tuner */
@@ -762,7 +791,9 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
 
                break;
        case ANYSEE_HW_508TC: /* 18 */
+       case ANYSEE_HW_508PTC: /* 21 */
                /* E7 TC */
+               /* E7 PTC */
 
                /* enable tuner on IOE[4] */
                ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
@@ -775,7 +806,9 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
 
                break;
        case ANYSEE_HW_508S2: /* 19 */
+       case ANYSEE_HW_508PS2: /* 22 */
                /* E7 S2 */
+               /* E7 PS2 */
 
                /* attach tuner */
                fe = dvb_attach(stv6110_attach, adap->fe,
index a7673aa1e007810627876ad9702ec4662607c003..ad6ccd1ea2d9bdabe67a3a88e7e22262db72e425 100644 (file)
@@ -61,13 +61,15 @@ struct anysee_state {
        u8 seq;
 };
 
-#define ANYSEE_HW_02     2 /* E30 */
-#define ANYSEE_HW_507CD  6 /* E30 Plus */
-#define ANYSEE_HW_507DC 10 /* E30 C Plus */
-#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */
-#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */
-#define ANYSEE_HW_508TC 18 /* E7 TC */
-#define ANYSEE_HW_508S2 19 /* E7 S2 */
+#define ANYSEE_HW_507T    2 /* E30 */
+#define ANYSEE_HW_507CD   6 /* E30 Plus */
+#define ANYSEE_HW_507DC  10 /* E30 C Plus */
+#define ANYSEE_HW_507SI  11 /* E30 S2 Plus */
+#define ANYSEE_HW_507FA  15 /* E30 Combo Plus / E30 C Plus */
+#define ANYSEE_HW_508TC  18 /* E7 TC */
+#define ANYSEE_HW_508S2  19 /* E7 S2 */
+#define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */
+#define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */
 
 #define REG_IOA       0x80 /* Port A (bit addressable) */
 #define REG_IOB       0x90 /* Port B (bit addressable) */
index c519ad5eb731f4672b7d4ff65ab9ea40777ecafc..d0ea5b64f6b4e10f6e028b99915d3100c94d61a3 100644 (file)
@@ -17,6 +17,7 @@
 #include "mt2266.h"
 #include "tuner-xc2028.h"
 #include "xc5000.h"
+#include "xc4000.h"
 #include "s5h1411.h"
 #include "dib0070.h"
 #include "dib0090.h"
@@ -2655,6 +2656,156 @@ static int xc5000_tuner_attach(struct dvb_usb_adapter *adap)
                == NULL ? -ENODEV : 0;
 }
 
+static int dib0700_xc4000_tuner_callback(void *priv, int component,
+                                        int command, int arg)
+{
+       struct dvb_usb_adapter *adap = priv;
+
+       if (command == XC4000_TUNER_RESET) {
+               /* Reset the tuner */
+               dib7000p_set_gpio(adap->fe, 8, 0, 0);
+               msleep(10);
+               dib7000p_set_gpio(adap->fe, 8, 0, 1);
+       } else {
+               err("xc4000: unknown tuner callback command: %d\n", command);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct dibx000_agc_config stk7700p_7000p_xc4000_agc_config = {
+       .band_caps = BAND_UHF | BAND_VHF,
+       .setup = 0x64,
+       .inv_gain = 0x02c8,
+       .time_stabiliz = 0x15,
+       .alpha_level = 0x00,
+       .thlock = 0x76,
+       .wbd_inv = 0x01,
+       .wbd_ref = 0x0b33,
+       .wbd_sel = 0x00,
+       .wbd_alpha = 0x02,
+       .agc1_max = 0x00,
+       .agc1_min = 0x00,
+       .agc2_max = 0x9b26,
+       .agc2_min = 0x26ca,
+       .agc1_pt1 = 0x00,
+       .agc1_pt2 = 0x00,
+       .agc1_pt3 = 0x00,
+       .agc1_slope1 = 0x00,
+       .agc1_slope2 = 0x00,
+       .agc2_pt1 = 0x00,
+       .agc2_pt2 = 0x80,
+       .agc2_slope1 = 0x1d,
+       .agc2_slope2 = 0x1d,
+       .alpha_mant = 0x11,
+       .alpha_exp = 0x1b,
+       .beta_mant = 0x17,
+       .beta_exp = 0x33,
+       .perform_agc_softsplit = 0x00,
+};
+
+static struct dibx000_bandwidth_config stk7700p_xc4000_pll_config = {
+       60000, 30000,   /* internal, sampling */
+       1, 8, 3, 1, 0,  /* pll_cfg: prediv, ratio, range, reset, bypass */
+       0, 0, 1, 1, 0,  /* misc: refdiv, bypclk_div, IO_CLK_en_core, */
+                       /* ADClkSrc, modulo */
+       (3 << 14) | (1 << 12) | 524,    /* sad_cfg: refsel, sel, freq_15k */
+       39370534,       /* ifreq */
+       20452225,       /* timf */
+       30000000        /* xtal */
+};
+
+/* FIXME: none of these inputs are validated yet */
+static struct dib7000p_config pctv_340e_config = {
+       .output_mpeg2_in_188_bytes = 1,
+
+       .agc_config_count = 1,
+       .agc = &stk7700p_7000p_xc4000_agc_config,
+       .bw  = &stk7700p_xc4000_pll_config,
+
+       .gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
+};
+
+/* PCTV 340e GPIOs map:
+   dib0700:
+   GPIO2  - CX25843 sleep
+   GPIO3  - CS5340 reset
+   GPIO5  - IRD
+   GPIO6  - Power Supply
+   GPIO8  - LNA (1=off 0=on)
+   GPIO10 - CX25843 reset
+   dib7000:
+   GPIO8  - xc4000 reset
+ */
+static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_state *st = adap->dev->priv;
+
+       /* Power Supply on */
+       dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0);
+       msleep(50);
+       dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1);
+       msleep(100); /* Allow power supply to settle before probing */
+
+       /* cx25843 reset */
+       dib0700_set_gpio(adap->dev, GPIO10,  GPIO_OUT, 0);
+       msleep(1); /* cx25843 datasheet say 350us required */
+       dib0700_set_gpio(adap->dev, GPIO10,  GPIO_OUT, 1);
+
+       /* LNA off for now */
+       dib0700_set_gpio(adap->dev, GPIO8,  GPIO_OUT, 1);
+
+       /* Put the CX25843 to sleep for now since we're in digital mode */
+       dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1);
+
+       /* FIXME: not verified yet */
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(500);
+
+       if (dib7000pc_detection(&adap->dev->i2c_adap) == 0) {
+               /* Demodulator not found for some reason? */
+               return -ENODEV;
+       }
+
+       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12,
+                             &pctv_340e_config);
+       st->is_dib7000pc = 1;
+
+       return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static struct xc4000_config dib7000p_xc4000_tunerconfig = {
+       .i2c_address      = 0x61,
+       .default_pm       = 1,
+       .dvb_amplitude    = 0,
+       .set_smoothedcvbs = 0,
+       .if_khz           = 5400
+};
+
+static int xc4000_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct i2c_adapter *tun_i2c;
+
+       /* The xc4000 is not on the main i2c bus */
+       tun_i2c = dib7000p_get_i2c_master(adap->fe,
+                                         DIBX000_I2C_INTERFACE_TUNER, 1);
+       if (tun_i2c == NULL) {
+               printk(KERN_ERR "Could not reach tuner i2c bus\n");
+               return 0;
+       }
+
+       /* Setup the reset callback */
+       adap->fe->callback = dib0700_xc4000_tuner_callback;
+
+       return dvb_attach(xc4000_attach, adap->fe, tun_i2c,
+                         &dib7000p_xc4000_tunerconfig)
+               == NULL ? -ENODEV : 0;
+}
+
 static struct lgdt3305_config hcw_lgdt3305_config = {
        .i2c_addr           = 0x0e,
        .mpeg_mode          = LGDT3305_MPEG_PARALLEL,
@@ -2802,6 +2953,8 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090PVR) },
        { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) },
 /* 75 */{ USB_DEVICE(USB_VID_MEDION,    USB_PID_CREATIX_CTX1921) },
+       { USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV340E) },
+       { USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV340E_SE) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3762,6 +3915,41 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .frontend_attach  = pctv340e_frontend_attach,
+                               .tuner_attach     = xc4000_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv = sizeof(struct
+                                               dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 2,
+               .devices = {
+                       {   "Pinnacle PCTV 340e HD Pro USB Stick",
+                               { &dib0700_usb_id_table[76], NULL },
+                               { NULL },
+                       },
+                       {   "Pinnacle PCTV Hybrid Stick Solo",
+                               { &dib0700_usb_id_table[77], NULL },
+                               { NULL },
+                       },
+               },
                .rc.core = {
                        .rc_interval      = DEFAULT_RC_INTERVAL,
                        .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
index 21b15495d2d7c588f4acb04875303c88fea196f1..2a79b8fb3e8dc283ddb8ee8a466b9696440eb620 100644 (file)
 #define USB_PID_PINNACLE_PCTV310E                      0x3211
 #define USB_PID_PINNACLE_PCTV801E                      0x023a
 #define USB_PID_PINNACLE_PCTV801E_SE                   0x023b
+#define USB_PID_PINNACLE_PCTV340E                      0x023d
+#define USB_PID_PINNACLE_PCTV340E_SE                   0x023e
 #define USB_PID_PINNACLE_PCTV73A                       0x0243
 #define USB_PID_PINNACLE_PCTV73ESE                     0x0245
 #define USB_PID_PINNACLE_PCTV74E                       0x0246
 #define USB_PID_FRIIO_WHITE                            0x0001
 #define USB_PID_TVWAY_PLUS                             0x0002
 #define USB_PID_SVEON_STV20                            0xe39d
+#define USB_PID_SVEON_STV22                            0xe401
 #define USB_PID_AZUREWAVE_AZ6027                       0x3275
 #define USB_PID_TERRATEC_DVBS2CI_V1                    0x10a4
 #define USB_PID_TERRATEC_DVBS2CI_V2                    0x10ac
index 76a80968482a602033cfead87ddd029301a832d2..7d35d078342b41522443868a2436fadc550ad92c 100644 (file)
@@ -85,7 +85,7 @@ static inline u8 rc5_data(struct rc_map_table *key)
        return key->scancode & 0xff;
 }
 
-static inline u8 rc5_scan(struct rc_map_table *key)
+static inline u16 rc5_scan(struct rc_map_table *key)
 {
        return key->scancode & 0xffff;
 }
index 831749a518cbed7dbf05700fa890add6dd16489f..ed32b9da484364d8f49e94f4c29342149ef563da 100644 (file)
@@ -78,9 +78,6 @@ extern int dvb_usb_gp8psk_debug;
 #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
 
index 08f8842ad280861c7f6acb6c756939147f9d5879..473b95ed4d52759339b7b9f4b0c20541b76a569c 100644 (file)
@@ -765,10 +765,8 @@ static void technisat_usb2_disconnect(struct usb_interface *intf)
        /* work and stuff was only created when the device is is hot-state */
        if (dev != NULL) {
                struct technisat_usb2_state *state = dev->priv;
-               if (state != NULL) {
+               if (state != NULL)
                        cancel_delayed_work_sync(&state->green_led_work);
-                       flush_scheduled_work();
-               }
        }
 
        dvb_usb_device_exit(intf);
index 969688f8526750c8c9b8ea74d535ef1371885a49..cf5ec46f8bb1bbc40138af764be3f0a79f763aa1 100644 (file)
@@ -36,9 +36,6 @@
  #define Tuner_Power_OFF                  0
 
 #define GET_USB_SPEED                     0x07
- #define USB_SPEED_LOW                    0
- #define USB_SPEED_FULL                   1
- #define USB_SPEED_HIGH                   2
 
 #define LOCK_TUNER_COMMAND                0x09
 
index 21c52e3b522e18df7ba3ff30412fc6f9650991af..489ae8245867bc51d83cfa062c71fc09952531b9 100644 (file)
@@ -1208,7 +1208,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
        if (r->response != AVC_RESPONSE_ACCEPTED) {
                dev_err(fdtv->device,
                        "CA PMT failed with response 0x%x\n", r->response);
-               ret = -EFAULT;
+               ret = -EACCES;
        }
 out:
        mutex_unlock(&fdtv->avc_mutex);
index 8ffb565f0704112cb10c63edc6cafb0aed6a3cd0..e5ebdbfe8c19e45c9f12b98639b44860d6a8b83e 100644 (file)
@@ -45,11 +45,6 @@ static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat)
        return flags;
 }
 
-static int fdtv_ca_reset(struct firedtv *fdtv)
-{
-       return avc_ca_reset(fdtv) ? -EFAULT : 0;
-}
-
 static int fdtv_ca_get_caps(void *arg)
 {
        struct ca_caps *cap = arg;
@@ -65,12 +60,14 @@ static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg)
 {
        struct firedtv_tuner_status stat;
        struct ca_slot_info *slot = arg;
+       int err;
 
-       if (avc_tuner_status(fdtv, &stat))
-               return -EFAULT;
+       err = avc_tuner_status(fdtv, &stat);
+       if (err)
+               return err;
 
        if (slot->num != 0)
-               return -EFAULT;
+               return -EACCES;
 
        slot->type = CA_CI;
        slot->flags = fdtv_get_ca_flags(&stat);
@@ -81,21 +78,21 @@ static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg)
 {
        struct ca_msg *reply = arg;
 
-       return avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
+       return avc_ca_app_info(fdtv, reply->msg, &reply->length);
 }
 
 static int fdtv_ca_info(struct firedtv *fdtv, void *arg)
 {
        struct ca_msg *reply = arg;
 
-       return avc_ca_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
+       return avc_ca_info(fdtv, reply->msg, &reply->length);
 }
 
 static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg)
 {
        struct ca_msg *reply = arg;
 
-       return avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
+       return avc_ca_get_mmi(fdtv, reply->msg, &reply->length);
 }
 
 static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
@@ -111,14 +108,15 @@ static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
                err = fdtv_ca_info(fdtv, arg);
                break;
        default:
-               if (avc_tuner_status(fdtv, &stat))
-                       err = -EFAULT;
-               else if (stat.ca_mmi == 1)
+               err = avc_tuner_status(fdtv, &stat);
+               if (err)
+                       break;
+               if (stat.ca_mmi == 1)
                        err = fdtv_ca_get_mmi(fdtv, arg);
                else {
                        dev_info(fdtv->device, "unhandled CA message 0x%08x\n",
                                 fdtv->ca_last_command);
-                       err = -EFAULT;
+                       err = -EACCES;
                }
        }
        fdtv->ca_last_command = 0;
@@ -141,7 +139,7 @@ static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
                data_length = msg->msg[3];
        }
 
-       return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? -EFAULT : 0;
+       return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length);
 }
 
 static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
@@ -170,7 +168,7 @@ static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
        default:
                dev_err(fdtv->device, "unhandled CA message 0x%08x\n",
                        fdtv->ca_last_command);
-               err = -EFAULT;
+               err = -EACCES;
        }
        return err;
 }
@@ -184,7 +182,7 @@ static int fdtv_ca_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        switch (cmd) {
        case CA_RESET:
-               err = fdtv_ca_reset(fdtv);
+               err = avc_ca_reset(fdtv);
                break;
        case CA_GET_CAP:
                err = fdtv_ca_get_caps(arg);
index 44b816f2601e7994c241fcdc3d0f782fbe29214c..32e08e35152525386b2b8c48ac9422b23913c59f 100644 (file)
@@ -49,6 +49,27 @@ config DVB_STV6110x
        help
          A Silicon tuner that supports DVB-S and DVB-S2 modes
 
+comment "Multistandard (cable + terrestrial) frontends"
+       depends on DVB_CORE
+
+config DVB_DRXK
+       tristate "Micronas DRXK based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         Micronas DRX-K DVB-C/T demodulator.
+
+         Say Y when you want to support this frontend.
+
+config DVB_TDA18271C2DD
+       tristate "NXP TDA18271C2 silicon tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         NXP TDA18271 silicon tuner.
+
+         Say Y when you want to support this tuner.
+
 comment "DVB-S (satellite) frontends"
        depends on DVB_CORE
 
index 2f3a6f736d641c1c59203a693a2c3f2b926e9ba4..6a6ba053ead4692eee52a9376e127f94c433ff7f 100644 (file)
@@ -10,6 +10,7 @@ stv0900-objs = stv0900_core.o stv0900_sw.o
 au8522-objs = au8522_dig.o au8522_decoder.o
 drxd-objs = drxd_firm.o drxd_hard.o
 cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
+drxk-objs := drxk_hard.o
 
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -88,4 +89,6 @@ obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
 obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
 obj-$(CONFIG_DVB_STV0367) += stv0367.o
 obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
+obj-$(CONFIG_DVB_DRXK) += drxk.o
+obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o
 
index b537891a4cc9d8c2e647c68eec420a1e9aaa1723..2b248c12f404a96f839610040752e881a2a54fbf 100644 (file)
@@ -692,7 +692,7 @@ static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
        /* Interrogate the decoder to see if we are getting a real signal */
        lock_status = au8522_readreg(state, 0x00);
        if (lock_status == 0xa2)
-               vt->signal = 0x01;
+               vt->signal = 0xffff;
        else
                vt->signal = 0x00;
 
index e9ee55592fd31cbcf72c3c8edd3ca773112b1f21..c341d57d5e818d9c57d34e09e790eb937f0e5475 100644 (file)
@@ -31,8 +31,8 @@
 
 static int debug;
 
-#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
-#define err(args...)  do { printk(KERN_ERR  "CX24113: " args); } while (0)
+#define cx_info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
+#define cx_err(args...)  do { printk(KERN_ERR  "CX24113: " args); } while (0)
 
 #define dprintk(args...) \
        do { \
@@ -341,7 +341,7 @@ static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
        } while (N < 6 && R < 3);
 
        if (N < 6) {
-               err("strange frequency: N < 6\n");
+               cx_err("strange frequency: N < 6\n");
                return;
        }
        F = freq_hz;
@@ -563,7 +563,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
                kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
        int rc;
        if (state == NULL) {
-               err("Unable to kzalloc\n");
+               cx_err("Unable to kzalloc\n");
                goto error;
        }
 
@@ -571,7 +571,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
        state->config = config;
        state->i2c = i2c;
 
-       info("trying to detect myself\n");
+       cx_info("trying to detect myself\n");
 
        /* making a dummy read, because of some expected troubles
         * after power on */
@@ -579,24 +579,24 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
 
        rc = cx24113_readreg(state, 0x00);
        if (rc < 0) {
-               info("CX24113 not found.\n");
+               cx_info("CX24113 not found.\n");
                goto error;
        }
        state->rev = rc;
 
        switch (rc) {
        case 0x43:
-               info("detected CX24113 variant\n");
+               cx_info("detected CX24113 variant\n");
                break;
        case REV_CX24113:
-               info("successfully detected\n");
+               cx_info("successfully detected\n");
                break;
        default:
-               err("unsupported device id: %x\n", state->rev);
+               cx_err("unsupported device id: %x\n", state->rev);
                goto error;
        }
        state->ver = cx24113_readreg(state, 0x01);
-       info("version: %x\n", state->ver);
+       cx_info("version: %x\n", state->ver);
 
        /* create dvb_frontend */
        memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
index 95c6465b87a12b71e39015f6bf896dd84c766db4..ccd05255d52730225530580b6bedec2a8df99336 100644 (file)
@@ -1452,11 +1452,7 @@ tuned:  /* Set/Reset B/W */
        cmd.args[0x00] = CMD_BANDWIDTH;
        cmd.args[0x01] = 0x00;
        cmd.len = 0x02;
-       ret = cx24116_cmd_execute(fe, &cmd);
-       if (ret != 0)
-               return ret;
-
-       return ret;
+       return cx24116_cmd_execute(fe, &cmd);
 }
 
 static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
index ad17845123d9e41881a99b65dd908f043aee40bb..2906582dc94c20a5ed58460b4d4b3a59e0332e84 100644 (file)
@@ -55,13 +55,13 @@ struct cxd2820r_config {
         * Default: 0
         * Values: 0, 1
         */
-       int if_agc_polarity:1;
+       bool if_agc_polarity;
 
        /* Spectrum inversion.
         * Default: 0
         * Values: 0, 1
         */
-       int spec_inv:1;
+       bool spec_inv;
 
        /* IFs for all used modes.
         * Default: none, must set
index 0779f69db793501302aa1df7c02ef0311b78fa30..d416e85589e1150fe57c7b204a86b6c62ef8b6d2 100644 (file)
@@ -314,6 +314,8 @@ static int cxd2820r_set_frontend(struct dvb_frontend *fe,
                        } else if (c->delivery_system == SYS_DVBT2) {
                                /* DVB-T => DVB-T2 */
                                ret = cxd2820r_sleep_t(fe);
+                               if (ret)
+                                       break;
                                ret = cxd2820r_set_frontend_t2(fe, p);
                        }
                        break;
@@ -324,6 +326,8 @@ static int cxd2820r_set_frontend(struct dvb_frontend *fe,
                        } else if (c->delivery_system == SYS_DVBT) {
                                /* DVB-T2 => DVB-T */
                                ret = cxd2820r_sleep_t2(fe);
+                               if (ret)
+                                       break;
                                ret = cxd2820r_set_frontend_t(fe, p);
                        }
                        break;
@@ -740,12 +744,13 @@ static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
        struct i2c_msg msg[], int num)
 {
        struct cxd2820r_priv *priv = i2c_get_adapdata(i2c_adap);
-       u8 obuf[msg[0].len + 2];
+       int ret;
+       u8 *obuf = kmalloc(msg[0].len + 2, GFP_KERNEL);
        struct i2c_msg msg2[2] = {
                {
                        .addr = priv->cfg.i2c_address,
                        .flags = 0,
-                       .len = sizeof(obuf),
+                       .len = msg[0].len + 2,
                        .buf = obuf,
                }, {
                        .addr = priv->cfg.i2c_address,
@@ -755,15 +760,24 @@ static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
                }
        };
 
+       if (!obuf)
+               return -ENOMEM;
+
        obuf[0] = 0x09;
        obuf[1] = (msg[0].addr << 1);
        if (num == 2) { /* I2C read */
                obuf[1] = (msg[0].addr << 1) | I2C_M_RD; /* I2C RD flag */
-               msg2[0].len = sizeof(obuf) - 1; /* maybe HW bug ? */
+               msg2[0].len = msg[0].len + 2 - 1; /* '-1' maybe HW bug ? */
        }
        memcpy(&obuf[2], msg[0].buf, msg[0].len);
 
-       return i2c_transfer(priv->i2c, msg2, num);
+       ret = i2c_transfer(priv->i2c, msg2, num);
+       if (ret < 0)
+               warn("tuner i2c failed ret:%d", ret);
+
+       kfree(obuf);
+
+       return ret;
 }
 
 static struct i2c_algorithm cxd2820r_tuner_i2c_algo = {
index 25adbeefa6d3b1df632d89246cd99bd92a83d88f..0c0ebc9d5c4ac0ca7a051fa0c64b55dc23d6aa70 100644 (file)
@@ -55,13 +55,13 @@ struct cxd2820r_priv {
        struct mutex fe_lock; /* FE lock */
        int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */
 
-       int ber_running:1;
+       bool ber_running;
 
        u8 bank[2];
        u8 gpio[3];
 
        fe_delivery_system_t delivery_system;
-       int last_tune_failed:1; /* for switch between T and T2 tune */
+       bool last_tune_failed; /* for switch between T and T2 tune */
 };
 
 /* cxd2820r_core.c */
index 0c9f40c2a251fbaad72fe3520e6f6ec48d76cb13..a64a538ba36439b5723650905f434d8fba8ae58b 100644 (file)
@@ -2336,6 +2336,11 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
                request_firmware() will hit an OOPS (this should be moved somewhere
                more common) */
 
+       /* FIXME: make sure the dev.parent field is initialized, or else
+          request_firmware() will hit an OOPS (this should be moved somewhere
+          more common) */
+       st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
+
        dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
 
        /* init 7090 tuner adapter */
index ea4c1c361d2b7a12473cd1d9ff6ec19a0aa977a8..2238bf0be95936320feccbfc65f30c1503167e08 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <asm/div64.h>
 
 #include "dvb_frontend.h"
@@ -233,7 +232,7 @@ static int i2c_read(struct i2c_adapter *adap,
        return 0;
 }
 
-inline u32 MulDiv32(u32 a, u32 b, u32 c)
+static inline u32 MulDiv32(u32 a, u32 b, u32 c)
 {
        u64 tmp64;
 
@@ -910,14 +909,16 @@ static int load_firmware(struct drxd_state *state, const char *fw_name)
                return -EIO;
        }
 
-       state->microcode = kzalloc(fw->size, GFP_KERNEL);
+       state->microcode = kmalloc(fw->size, GFP_KERNEL);
        if (state->microcode == NULL) {
-               printk(KERN_ERR "drxd: firmware load failure: nomemory\n");
+               release_firmware(fw);
+               printk(KERN_ERR "drxd: firmware load failure: no memory\n");
                return -ENOMEM;
        }
 
        memcpy(state->microcode, fw->data, fw->size);
        state->microcode_length = fw->size;
+       release_firmware(fw);
        return 0;
 }
 
diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb/frontends/drxk.h
new file mode 100644 (file)
index 0000000..58baf41
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _DRXK_H_
+#define _DRXK_H_
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+/**
+ * struct drxk_config - Configure the initial parameters for DRX-K
+ *
+ * adr:                        I2C Address of the DRX-K
+ * single_master:      Device is on the single master mode
+ * no_i2c_bridge:      Don't switch the I2C bridge to talk with tuner
+ * antenna_gpio:       GPIO bit used to control the antenna
+ * antenna_dvbt:       GPIO bit for changing antenna to DVB-C. A value of 1
+ *                     means that 1=DVBC, 0 = DVBT. Zero means the opposite.
+ * microcode_name:     Name of the firmware file with the microcode
+ *
+ * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
+ * UIO-3.
+ */
+struct drxk_config {
+       u8      adr;
+       bool    single_master;
+       bool    no_i2c_bridge;
+
+       bool    antenna_dvbt;
+       u16     antenna_gpio;
+
+       const char *microcode_name;
+};
+
+#if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \
+        && defined(MODULE))
+extern struct dvb_frontend *drxk_attach(const struct drxk_config *config,
+                                       struct i2c_adapter *i2c,
+                                       struct dvb_frontend **fe_t);
+#else
+static inline struct dvb_frontend *drxk_attach(const struct drxk_config *config,
+                                       struct i2c_adapter *i2c,
+                                       struct dvb_frontend **fe_t)
+{
+        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+        return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c
new file mode 100644 (file)
index 0000000..41b0838
--- /dev/null
@@ -0,0 +1,6454 @@
+/*
+ * drxk_hard: DRX-K DVB-C/T demodulator driver
+ *
+ * Copyright (C) 2010-2011 Digital Devices GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "drxk.h"
+#include "drxk_hard.h"
+
+static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode);
+static int PowerDownQAM(struct drxk_state *state);
+static int SetDVBTStandard(struct drxk_state *state,
+                          enum OperationMode oMode);
+static int SetQAMStandard(struct drxk_state *state,
+                         enum OperationMode oMode);
+static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
+                 s32 tunerFreqOffset);
+static int SetDVBTStandard(struct drxk_state *state,
+                          enum OperationMode oMode);
+static int DVBTStart(struct drxk_state *state);
+static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
+                  s32 tunerFreqOffset);
+static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus);
+static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus);
+static int SwitchAntennaToQAM(struct drxk_state *state);
+static int SwitchAntennaToDVBT(struct drxk_state *state);
+
+static bool IsDVBT(struct drxk_state *state)
+{
+       return state->m_OperationMode == OM_DVBT;
+}
+
+static bool IsQAM(struct drxk_state *state)
+{
+       return state->m_OperationMode == OM_QAM_ITU_A ||
+           state->m_OperationMode == OM_QAM_ITU_B ||
+           state->m_OperationMode == OM_QAM_ITU_C;
+}
+
+bool IsA1WithPatchCode(struct drxk_state *state)
+{
+       return state->m_DRXK_A1_PATCH_CODE;
+}
+
+bool IsA1WithRomCode(struct drxk_state *state)
+{
+       return state->m_DRXK_A1_ROM_CODE;
+}
+
+#define NOA1ROM 0
+
+#define DRXDAP_FASI_SHORT_FORMAT(addr) (((addr) & 0xFC30FF80) == 0)
+#define DRXDAP_FASI_LONG_FORMAT(addr)  (((addr) & 0xFC30FF80) != 0)
+
+#define DEFAULT_MER_83  165
+#define DEFAULT_MER_93  250
+
+#ifndef DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH
+#define DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH (0x02)
+#endif
+
+#ifndef DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH
+#define DRXK_MPEG_PARALLEL_OUTPUT_PIN_DRIVE_STRENGTH (0x03)
+#endif
+
+#ifndef DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH
+#define DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH (0x06)
+#endif
+
+#define DEFAULT_DRXK_MPEG_LOCK_TIMEOUT 700
+#define DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT 500
+
+#ifndef DRXK_KI_RAGC_ATV
+#define DRXK_KI_RAGC_ATV   4
+#endif
+#ifndef DRXK_KI_IAGC_ATV
+#define DRXK_KI_IAGC_ATV   6
+#endif
+#ifndef DRXK_KI_DAGC_ATV
+#define DRXK_KI_DAGC_ATV   7
+#endif
+
+#ifndef DRXK_KI_RAGC_QAM
+#define DRXK_KI_RAGC_QAM   3
+#endif
+#ifndef DRXK_KI_IAGC_QAM
+#define DRXK_KI_IAGC_QAM   4
+#endif
+#ifndef DRXK_KI_DAGC_QAM
+#define DRXK_KI_DAGC_QAM   7
+#endif
+#ifndef DRXK_KI_RAGC_DVBT
+#define DRXK_KI_RAGC_DVBT  (IsA1WithPatchCode(state) ? 3 : 2)
+#endif
+#ifndef DRXK_KI_IAGC_DVBT
+#define DRXK_KI_IAGC_DVBT  (IsA1WithPatchCode(state) ? 4 : 2)
+#endif
+#ifndef DRXK_KI_DAGC_DVBT
+#define DRXK_KI_DAGC_DVBT  (IsA1WithPatchCode(state) ? 10 : 7)
+#endif
+
+#ifndef DRXK_AGC_DAC_OFFSET
+#define DRXK_AGC_DAC_OFFSET (0x800)
+#endif
+
+#ifndef DRXK_BANDWIDTH_8MHZ_IN_HZ
+#define DRXK_BANDWIDTH_8MHZ_IN_HZ  (0x8B8249L)
+#endif
+
+#ifndef DRXK_BANDWIDTH_7MHZ_IN_HZ
+#define DRXK_BANDWIDTH_7MHZ_IN_HZ  (0x7A1200L)
+#endif
+
+#ifndef DRXK_BANDWIDTH_6MHZ_IN_HZ
+#define DRXK_BANDWIDTH_6MHZ_IN_HZ  (0x68A1B6L)
+#endif
+
+#ifndef DRXK_QAM_SYMBOLRATE_MAX
+#define DRXK_QAM_SYMBOLRATE_MAX         (7233000)
+#endif
+
+#define DRXK_BL_ROM_OFFSET_TAPS_DVBT    56
+#define DRXK_BL_ROM_OFFSET_TAPS_ITU_A   64
+#define DRXK_BL_ROM_OFFSET_TAPS_ITU_C   0x5FE0
+#define DRXK_BL_ROM_OFFSET_TAPS_BG      24
+#define DRXK_BL_ROM_OFFSET_TAPS_DKILLP  32
+#define DRXK_BL_ROM_OFFSET_TAPS_NTSC    40
+#define DRXK_BL_ROM_OFFSET_TAPS_FM      48
+#define DRXK_BL_ROM_OFFSET_UCODE        0
+
+#define DRXK_BLC_TIMEOUT                100
+
+#define DRXK_BLCC_NR_ELEMENTS_TAPS      2
+#define DRXK_BLCC_NR_ELEMENTS_UCODE     6
+
+#define DRXK_BLDC_NR_ELEMENTS_TAPS      28
+
+#ifndef DRXK_OFDM_NE_NOTCH_WIDTH
+#define DRXK_OFDM_NE_NOTCH_WIDTH             (4)
+#endif
+
+#define DRXK_QAM_SL_SIG_POWER_QAM16       (40960)
+#define DRXK_QAM_SL_SIG_POWER_QAM32       (20480)
+#define DRXK_QAM_SL_SIG_POWER_QAM64       (43008)
+#define DRXK_QAM_SL_SIG_POWER_QAM128      (20992)
+#define DRXK_QAM_SL_SIG_POWER_QAM256      (43520)
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+#define dprintk(level, fmt, arg...) do {                       \
+if (debug >= level)                                            \
+       printk(KERN_DEBUG "drxk: %s" fmt, __func__, ## arg);    \
+} while (0)
+
+
+static inline u32 MulDiv32(u32 a, u32 b, u32 c)
+{
+       u64 tmp64;
+
+       tmp64 = (u64) a * (u64) b;
+       do_div(tmp64, c);
+
+       return (u32) tmp64;
+}
+
+inline u32 Frac28a(u32 a, u32 c)
+{
+       int i = 0;
+       u32 Q1 = 0;
+       u32 R0 = 0;
+
+       R0 = (a % c) << 4;      /* 32-28 == 4 shifts possible at max */
+       Q1 = a / c;             /* integer part, only the 4 least significant bits
+                                  will be visible in the result */
+
+       /* division using radix 16, 7 nibbles in the result */
+       for (i = 0; i < 7; i++) {
+               Q1 = (Q1 << 4) | (R0 / c);
+               R0 = (R0 % c) << 4;
+       }
+       /* rounding */
+       if ((R0 >> 3) >= c)
+               Q1++;
+
+       return Q1;
+}
+
+static u32 Log10Times100(u32 x)
+{
+       static const u8 scale = 15;
+       static const u8 indexWidth = 5;
+       u8 i = 0;
+       u32 y = 0;
+       u32 d = 0;
+       u32 k = 0;
+       u32 r = 0;
+       /*
+          log2lut[n] = (1<<scale) * 200 * log2(1.0 + ((1.0/(1<<INDEXWIDTH)) * n))
+          0 <= n < ((1<<INDEXWIDTH)+1)
+        */
+
+       static const u32 log2lut[] = {
+               0,              /* 0.000000 */
+               290941,         /* 290941.300628 */
+               573196,         /* 573196.476418 */
+               847269,         /* 847269.179851 */
+               1113620,        /* 1113620.489452 */
+               1372674,        /* 1372673.576986 */
+               1624818,        /* 1624817.752104 */
+               1870412,        /* 1870411.981536 */
+               2109788,        /* 2109787.962654 */
+               2343253,        /* 2343252.817465 */
+               2571091,        /* 2571091.461923 */
+               2793569,        /* 2793568.696416 */
+               3010931,        /* 3010931.055901 */
+               3223408,        /* 3223408.452106 */
+               3431216,        /* 3431215.635215 */
+               3634553,        /* 3634553.498355 */
+               3833610,        /* 3833610.244726 */
+               4028562,        /* 4028562.434393 */
+               4219576,        /* 4219575.925308 */
+               4406807,        /* 4406806.721144 */
+               4590402,        /* 4590401.736809 */
+               4770499,        /* 4770499.491025 */
+               4947231,        /* 4947230.734179 */
+               5120719,        /* 5120719.018555 */
+               5291081,        /* 5291081.217197 */
+               5458428,        /* 5458427.996830 */
+               5622864,        /* 5622864.249668 */
+               5784489,        /* 5784489.488298 */
+               5943398,        /* 5943398.207380 */
+               6099680,        /* 6099680.215452 */
+               6253421,        /* 6253420.939751 */
+               6404702,        /* 6404701.706649 */
+               6553600,        /* 6553600.000000 */
+       };
+
+
+       if (x == 0)
+               return 0;
+
+       /* Scale x (normalize) */
+       /* computing y in log(x/y) = log(x) - log(y) */
+       if ((x & ((0xffffffff) << (scale + 1))) == 0) {
+               for (k = scale; k > 0; k--) {
+                       if (x & (((u32) 1) << scale))
+                               break;
+                       x <<= 1;
+               }
+       } else {
+               for (k = scale; k < 31; k++) {
+                       if ((x & (((u32) (-1)) << (scale + 1))) == 0)
+                               break;
+                       x >>= 1;
+               }
+       }
+       /*
+          Now x has binary point between bit[scale] and bit[scale-1]
+          and 1.0 <= x < 2.0 */
+
+       /* correction for divison: log(x) = log(x/y)+log(y) */
+       y = k * ((((u32) 1) << scale) * 200);
+
+       /* remove integer part */
+       x &= ((((u32) 1) << scale) - 1);
+       /* get index */
+       i = (u8) (x >> (scale - indexWidth));
+       /* compute delta (x - a) */
+       d = x & ((((u32) 1) << (scale - indexWidth)) - 1);
+       /* compute log, multiplication (d* (..)) must be within range ! */
+       y += log2lut[i] +
+           ((d * (log2lut[i + 1] - log2lut[i])) >> (scale - indexWidth));
+       /* Conver to log10() */
+       y /= 108853;            /* (log2(10) << scale) */
+       r = (y >> 1);
+       /* rounding */
+       if (y & ((u32) 1))
+               r++;
+       return r;
+}
+
+/****************************************************************************/
+/* I2C **********************************************************************/
+/****************************************************************************/
+
+static int i2c_read1(struct i2c_adapter *adapter, u8 adr, u8 *val)
+{
+       struct i2c_msg msgs[1] = { {.addr = adr, .flags = I2C_M_RD,
+                                   .buf = val, .len = 1}
+       };
+
+       return i2c_transfer(adapter, msgs, 1);
+}
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
+{
+       int status;
+       struct i2c_msg msg = {
+           .addr = adr, .flags = 0, .buf = data, .len = len };
+
+       dprintk(3, ":");
+       if (debug > 2) {
+               int i;
+               for (i = 0; i < len; i++)
+                       printk(KERN_CONT " %02x", data[i]);
+               printk(KERN_CONT "\n");
+       }
+       status = i2c_transfer(adap, &msg, 1);
+       if (status >= 0 && status != 1)
+               status = -EIO;
+
+       if (status < 0)
+               printk(KERN_ERR "drxk: i2c write error at addr 0x%02x\n", adr);
+
+       return status;
+}
+
+static int i2c_read(struct i2c_adapter *adap,
+                   u8 adr, u8 *msg, int len, u8 *answ, int alen)
+{
+       int status;
+       struct i2c_msg msgs[2] = {
+               {.addr = adr, .flags = 0,
+                                   .buf = msg, .len = len},
+               {.addr = adr, .flags = I2C_M_RD,
+                .buf = answ, .len = alen}
+       };
+
+       status = i2c_transfer(adap, msgs, 2);
+       if (status != 2) {
+               if (debug > 2)
+                       printk(KERN_CONT ": ERROR!\n");
+               if (status >= 0)
+                       status = -EIO;
+
+               printk(KERN_ERR "drxk: i2c read error at addr 0x%02x\n", adr);
+               return status;
+       }
+       if (debug > 2) {
+               int i;
+               dprintk(2, ": read from ");
+               for (i = 0; i < len; i++)
+                       printk(KERN_CONT " %02x", msg[i]);
+               printk(KERN_CONT "Value = ");
+               for (i = 0; i < alen; i++)
+                       printk(KERN_CONT " %02x", answ[i]);
+               printk(KERN_CONT "\n");
+       }
+       return 0;
+}
+
+static int read16_flags(struct drxk_state *state, u32 reg, u16 *data, u8 flags)
+{
+       int status;
+       u8 adr = state->demod_address, mm1[4], mm2[2], len;
+
+       if (state->single_master)
+               flags |= 0xC0;
+
+       if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+               mm1[0] = (((reg << 1) & 0xFF) | 0x01);
+               mm1[1] = ((reg >> 16) & 0xFF);
+               mm1[2] = ((reg >> 24) & 0xFF) | flags;
+               mm1[3] = ((reg >> 7) & 0xFF);
+               len = 4;
+       } else {
+               mm1[0] = ((reg << 1) & 0xFF);
+               mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+               len = 2;
+       }
+       dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
+       status = i2c_read(state->i2c, adr, mm1, len, mm2, 2);
+       if (status < 0)
+               return status;
+       if (data)
+               *data = mm2[0] | (mm2[1] << 8);
+
+       return 0;
+}
+
+static int read16(struct drxk_state *state, u32 reg, u16 *data)
+{
+       return read16_flags(state, reg, data, 0);
+}
+
+static int read32_flags(struct drxk_state *state, u32 reg, u32 *data, u8 flags)
+{
+       int status;
+       u8 adr = state->demod_address, mm1[4], mm2[4], len;
+
+       if (state->single_master)
+               flags |= 0xC0;
+
+       if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+               mm1[0] = (((reg << 1) & 0xFF) | 0x01);
+               mm1[1] = ((reg >> 16) & 0xFF);
+               mm1[2] = ((reg >> 24) & 0xFF) | flags;
+               mm1[3] = ((reg >> 7) & 0xFF);
+               len = 4;
+       } else {
+               mm1[0] = ((reg << 1) & 0xFF);
+               mm1[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+               len = 2;
+       }
+       dprintk(2, "(0x%08x, 0x%02x)\n", reg, flags);
+       status = i2c_read(state->i2c, adr, mm1, len, mm2, 4);
+       if (status < 0)
+               return status;
+       if (data)
+               *data = mm2[0] | (mm2[1] << 8) |
+                   (mm2[2] << 16) | (mm2[3] << 24);
+
+       return 0;
+}
+
+static int read32(struct drxk_state *state, u32 reg, u32 *data)
+{
+       return read32_flags(state, reg, data, 0);
+}
+
+static int write16_flags(struct drxk_state *state, u32 reg, u16 data, u8 flags)
+{
+       u8 adr = state->demod_address, mm[6], len;
+
+       if (state->single_master)
+               flags |= 0xC0;
+       if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+               mm[0] = (((reg << 1) & 0xFF) | 0x01);
+               mm[1] = ((reg >> 16) & 0xFF);
+               mm[2] = ((reg >> 24) & 0xFF) | flags;
+               mm[3] = ((reg >> 7) & 0xFF);
+               len = 4;
+       } else {
+               mm[0] = ((reg << 1) & 0xFF);
+               mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+               len = 2;
+       }
+       mm[len] = data & 0xff;
+       mm[len + 1] = (data >> 8) & 0xff;
+
+       dprintk(2, "(0x%08x, 0x%04x, 0x%02x)\n", reg, data, flags);
+       return i2c_write(state->i2c, adr, mm, len + 2);
+}
+
+static int write16(struct drxk_state *state, u32 reg, u16 data)
+{
+       return write16_flags(state, reg, data, 0);
+}
+
+static int write32_flags(struct drxk_state *state, u32 reg, u32 data, u8 flags)
+{
+       u8 adr = state->demod_address, mm[8], len;
+
+       if (state->single_master)
+               flags |= 0xC0;
+       if (DRXDAP_FASI_LONG_FORMAT(reg) || (flags != 0)) {
+               mm[0] = (((reg << 1) & 0xFF) | 0x01);
+               mm[1] = ((reg >> 16) & 0xFF);
+               mm[2] = ((reg >> 24) & 0xFF) | flags;
+               mm[3] = ((reg >> 7) & 0xFF);
+               len = 4;
+       } else {
+               mm[0] = ((reg << 1) & 0xFF);
+               mm[1] = (((reg >> 16) & 0x0F) | ((reg >> 18) & 0xF0));
+               len = 2;
+       }
+       mm[len] = data & 0xff;
+       mm[len + 1] = (data >> 8) & 0xff;
+       mm[len + 2] = (data >> 16) & 0xff;
+       mm[len + 3] = (data >> 24) & 0xff;
+       dprintk(2, "(0x%08x, 0x%08x, 0x%02x)\n", reg, data, flags);
+
+       return i2c_write(state->i2c, adr, mm, len + 4);
+}
+
+static int write32(struct drxk_state *state, u32 reg, u32 data)
+{
+       return write32_flags(state, reg, data, 0);
+}
+
+static int write_block(struct drxk_state *state, u32 Address,
+                     const int BlockSize, const u8 pBlock[])
+{
+       int status = 0, BlkSize = BlockSize;
+       u8 Flags = 0;
+
+       if (state->single_master)
+               Flags |= 0xC0;
+
+       while (BlkSize > 0) {
+               int Chunk = BlkSize > state->m_ChunkSize ?
+                   state->m_ChunkSize : BlkSize;
+               u8 *AdrBuf = &state->Chunk[0];
+               u32 AdrLength = 0;
+
+               if (DRXDAP_FASI_LONG_FORMAT(Address) || (Flags != 0)) {
+                       AdrBuf[0] = (((Address << 1) & 0xFF) | 0x01);
+                       AdrBuf[1] = ((Address >> 16) & 0xFF);
+                       AdrBuf[2] = ((Address >> 24) & 0xFF);
+                       AdrBuf[3] = ((Address >> 7) & 0xFF);
+                       AdrBuf[2] |= Flags;
+                       AdrLength = 4;
+                       if (Chunk == state->m_ChunkSize)
+                               Chunk -= 2;
+               } else {
+                       AdrBuf[0] = ((Address << 1) & 0xFF);
+                       AdrBuf[1] = (((Address >> 16) & 0x0F) |
+                                    ((Address >> 18) & 0xF0));
+                       AdrLength = 2;
+               }
+               memcpy(&state->Chunk[AdrLength], pBlock, Chunk);
+               dprintk(2, "(0x%08x, 0x%02x)\n", Address, Flags);
+               if (debug > 1) {
+                       int i;
+                       if (pBlock)
+                               for (i = 0; i < Chunk; i++)
+                                       printk(KERN_CONT " %02x", pBlock[i]);
+                       printk(KERN_CONT "\n");
+               }
+               status = i2c_write(state->i2c, state->demod_address,
+                                  &state->Chunk[0], Chunk + AdrLength);
+               if (status < 0) {
+                       printk(KERN_ERR "drxk: %s: i2c write error at addr 0x%02x\n",
+                              __func__, Address);
+                       break;
+               }
+               pBlock += Chunk;
+               Address += (Chunk >> 1);
+               BlkSize -= Chunk;
+       }
+       return status;
+}
+
+#ifndef DRXK_MAX_RETRIES_POWERUP
+#define DRXK_MAX_RETRIES_POWERUP 20
+#endif
+
+int PowerUpDevice(struct drxk_state *state)
+{
+       int status;
+       u8 data = 0;
+       u16 retryCount = 0;
+
+       dprintk(1, "\n");
+
+       status = i2c_read1(state->i2c, state->demod_address, &data);
+       if (status < 0) {
+               do {
+                       data = 0;
+                       status = i2c_write(state->i2c, state->demod_address,
+                                          &data, 1);
+                       msleep(10);
+                       retryCount++;
+                       if (status < 0)
+                               continue;
+                       status = i2c_read1(state->i2c, state->demod_address,
+                                          &data);
+               } while (status < 0 &&
+                        (retryCount < DRXK_MAX_RETRIES_POWERUP));
+               if (status < 0 && retryCount >= DRXK_MAX_RETRIES_POWERUP)
+                       goto error;
+       }
+
+       /* Make sure all clk domains are active */
+       status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_NONE);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+       if (status < 0)
+               goto error;
+       /* Enable pll lock tests */
+       status = write16(state, SIO_CC_PLL_LOCK__A, 1);
+       if (status < 0)
+               goto error;
+
+       state->m_currentPowerMode = DRX_POWER_UP;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+
+static int init_state(struct drxk_state *state)
+{
+       /*
+        * FIXME: most (all?) of the values bellow should be moved into
+        * struct drxk_config, as they are probably board-specific
+        */
+       u32 ulVSBIfAgcMode = DRXK_AGC_CTRL_AUTO;
+       u32 ulVSBIfAgcOutputLevel = 0;
+       u32 ulVSBIfAgcMinLevel = 0;
+       u32 ulVSBIfAgcMaxLevel = 0x7FFF;
+       u32 ulVSBIfAgcSpeed = 3;
+
+       u32 ulVSBRfAgcMode = DRXK_AGC_CTRL_AUTO;
+       u32 ulVSBRfAgcOutputLevel = 0;
+       u32 ulVSBRfAgcMinLevel = 0;
+       u32 ulVSBRfAgcMaxLevel = 0x7FFF;
+       u32 ulVSBRfAgcSpeed = 3;
+       u32 ulVSBRfAgcTop = 9500;
+       u32 ulVSBRfAgcCutOffCurrent = 4000;
+
+       u32 ulATVIfAgcMode = DRXK_AGC_CTRL_AUTO;
+       u32 ulATVIfAgcOutputLevel = 0;
+       u32 ulATVIfAgcMinLevel = 0;
+       u32 ulATVIfAgcMaxLevel = 0;
+       u32 ulATVIfAgcSpeed = 3;
+
+       u32 ulATVRfAgcMode = DRXK_AGC_CTRL_OFF;
+       u32 ulATVRfAgcOutputLevel = 0;
+       u32 ulATVRfAgcMinLevel = 0;
+       u32 ulATVRfAgcMaxLevel = 0;
+       u32 ulATVRfAgcTop = 9500;
+       u32 ulATVRfAgcCutOffCurrent = 4000;
+       u32 ulATVRfAgcSpeed = 3;
+
+       u32 ulQual83 = DEFAULT_MER_83;
+       u32 ulQual93 = DEFAULT_MER_93;
+
+       u32 ulDVBTStaticTSClock = 1;
+       u32 ulDVBCStaticTSClock = 1;
+
+       u32 ulMpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
+       u32 ulDemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
+
+       /* io_pad_cfg register (8 bit reg.) MSB bit is 1 (default value) */
+       /* io_pad_cfg_mode output mode is drive always */
+       /* io_pad_cfg_drive is set to power 2 (23 mA) */
+       u32 ulGPIOCfg = 0x0113;
+       u32 ulSerialMode = 1;
+       u32 ulInvertTSClock = 0;
+       u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH;
+       u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH;
+       u32 ulDVBTBitrate = 50000000;
+       u32 ulDVBCBitrate = DRXK_QAM_SYMBOLRATE_MAX * 8;
+
+       u32 ulInsertRSByte = 0;
+
+       u32 ulRfMirror = 1;
+       u32 ulPowerDown = 0;
+
+       dprintk(1, "\n");
+
+       state->m_hasLNA = false;
+       state->m_hasDVBT = false;
+       state->m_hasDVBC = false;
+       state->m_hasATV = false;
+       state->m_hasOOB = false;
+       state->m_hasAudio = false;
+
+       state->m_ChunkSize = 124;
+
+       state->m_oscClockFreq = 0;
+       state->m_smartAntInverted = false;
+       state->m_bPDownOpenBridge = false;
+
+       /* real system clock frequency in kHz */
+       state->m_sysClockFreq = 151875;
+       /* Timing div, 250ns/Psys */
+       /* Timing div, = (delay (nano seconds) * sysclk (kHz))/ 1000 */
+       state->m_HICfgTimingDiv = ((state->m_sysClockFreq / 1000) *
+                                  HI_I2C_DELAY) / 1000;
+       /* Clipping */
+       if (state->m_HICfgTimingDiv > SIO_HI_RA_RAM_PAR_2_CFG_DIV__M)
+               state->m_HICfgTimingDiv = SIO_HI_RA_RAM_PAR_2_CFG_DIV__M;
+       state->m_HICfgWakeUpKey = (state->demod_address << 1);
+       /* port/bridge/power down ctrl */
+       state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
+
+       state->m_bPowerDown = (ulPowerDown != 0);
+
+       state->m_DRXK_A1_PATCH_CODE = false;
+       state->m_DRXK_A1_ROM_CODE = false;
+       state->m_DRXK_A2_ROM_CODE = false;
+       state->m_DRXK_A3_ROM_CODE = false;
+       state->m_DRXK_A2_PATCH_CODE = false;
+       state->m_DRXK_A3_PATCH_CODE = false;
+
+       /* Init AGC and PGA parameters */
+       /* VSB IF */
+       state->m_vsbIfAgcCfg.ctrlMode = (ulVSBIfAgcMode);
+       state->m_vsbIfAgcCfg.outputLevel = (ulVSBIfAgcOutputLevel);
+       state->m_vsbIfAgcCfg.minOutputLevel = (ulVSBIfAgcMinLevel);
+       state->m_vsbIfAgcCfg.maxOutputLevel = (ulVSBIfAgcMaxLevel);
+       state->m_vsbIfAgcCfg.speed = (ulVSBIfAgcSpeed);
+       state->m_vsbPgaCfg = 140;
+
+       /* VSB RF */
+       state->m_vsbRfAgcCfg.ctrlMode = (ulVSBRfAgcMode);
+       state->m_vsbRfAgcCfg.outputLevel = (ulVSBRfAgcOutputLevel);
+       state->m_vsbRfAgcCfg.minOutputLevel = (ulVSBRfAgcMinLevel);
+       state->m_vsbRfAgcCfg.maxOutputLevel = (ulVSBRfAgcMaxLevel);
+       state->m_vsbRfAgcCfg.speed = (ulVSBRfAgcSpeed);
+       state->m_vsbRfAgcCfg.top = (ulVSBRfAgcTop);
+       state->m_vsbRfAgcCfg.cutOffCurrent = (ulVSBRfAgcCutOffCurrent);
+       state->m_vsbPreSawCfg.reference = 0x07;
+       state->m_vsbPreSawCfg.usePreSaw = true;
+
+       state->m_Quality83percent = DEFAULT_MER_83;
+       state->m_Quality93percent = DEFAULT_MER_93;
+       if (ulQual93 <= 500 && ulQual83 < ulQual93) {
+               state->m_Quality83percent = ulQual83;
+               state->m_Quality93percent = ulQual93;
+       }
+
+       /* ATV IF */
+       state->m_atvIfAgcCfg.ctrlMode = (ulATVIfAgcMode);
+       state->m_atvIfAgcCfg.outputLevel = (ulATVIfAgcOutputLevel);
+       state->m_atvIfAgcCfg.minOutputLevel = (ulATVIfAgcMinLevel);
+       state->m_atvIfAgcCfg.maxOutputLevel = (ulATVIfAgcMaxLevel);
+       state->m_atvIfAgcCfg.speed = (ulATVIfAgcSpeed);
+
+       /* ATV RF */
+       state->m_atvRfAgcCfg.ctrlMode = (ulATVRfAgcMode);
+       state->m_atvRfAgcCfg.outputLevel = (ulATVRfAgcOutputLevel);
+       state->m_atvRfAgcCfg.minOutputLevel = (ulATVRfAgcMinLevel);
+       state->m_atvRfAgcCfg.maxOutputLevel = (ulATVRfAgcMaxLevel);
+       state->m_atvRfAgcCfg.speed = (ulATVRfAgcSpeed);
+       state->m_atvRfAgcCfg.top = (ulATVRfAgcTop);
+       state->m_atvRfAgcCfg.cutOffCurrent = (ulATVRfAgcCutOffCurrent);
+       state->m_atvPreSawCfg.reference = 0x04;
+       state->m_atvPreSawCfg.usePreSaw = true;
+
+
+       /* DVBT RF */
+       state->m_dvbtRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
+       state->m_dvbtRfAgcCfg.outputLevel = 0;
+       state->m_dvbtRfAgcCfg.minOutputLevel = 0;
+       state->m_dvbtRfAgcCfg.maxOutputLevel = 0xFFFF;
+       state->m_dvbtRfAgcCfg.top = 0x2100;
+       state->m_dvbtRfAgcCfg.cutOffCurrent = 4000;
+       state->m_dvbtRfAgcCfg.speed = 1;
+
+
+       /* DVBT IF */
+       state->m_dvbtIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
+       state->m_dvbtIfAgcCfg.outputLevel = 0;
+       state->m_dvbtIfAgcCfg.minOutputLevel = 0;
+       state->m_dvbtIfAgcCfg.maxOutputLevel = 9000;
+       state->m_dvbtIfAgcCfg.top = 13424;
+       state->m_dvbtIfAgcCfg.cutOffCurrent = 0;
+       state->m_dvbtIfAgcCfg.speed = 3;
+       state->m_dvbtIfAgcCfg.FastClipCtrlDelay = 30;
+       state->m_dvbtIfAgcCfg.IngainTgtMax = 30000;
+       /* state->m_dvbtPgaCfg = 140; */
+
+       state->m_dvbtPreSawCfg.reference = 4;
+       state->m_dvbtPreSawCfg.usePreSaw = false;
+
+       /* QAM RF */
+       state->m_qamRfAgcCfg.ctrlMode = DRXK_AGC_CTRL_OFF;
+       state->m_qamRfAgcCfg.outputLevel = 0;
+       state->m_qamRfAgcCfg.minOutputLevel = 6023;
+       state->m_qamRfAgcCfg.maxOutputLevel = 27000;
+       state->m_qamRfAgcCfg.top = 0x2380;
+       state->m_qamRfAgcCfg.cutOffCurrent = 4000;
+       state->m_qamRfAgcCfg.speed = 3;
+
+       /* QAM IF */
+       state->m_qamIfAgcCfg.ctrlMode = DRXK_AGC_CTRL_AUTO;
+       state->m_qamIfAgcCfg.outputLevel = 0;
+       state->m_qamIfAgcCfg.minOutputLevel = 0;
+       state->m_qamIfAgcCfg.maxOutputLevel = 9000;
+       state->m_qamIfAgcCfg.top = 0x0511;
+       state->m_qamIfAgcCfg.cutOffCurrent = 0;
+       state->m_qamIfAgcCfg.speed = 3;
+       state->m_qamIfAgcCfg.IngainTgtMax = 5119;
+       state->m_qamIfAgcCfg.FastClipCtrlDelay = 50;
+
+       state->m_qamPgaCfg = 140;
+       state->m_qamPreSawCfg.reference = 4;
+       state->m_qamPreSawCfg.usePreSaw = false;
+
+       state->m_OperationMode = OM_NONE;
+       state->m_DrxkState = DRXK_UNINITIALIZED;
+
+       /* MPEG output configuration */
+       state->m_enableMPEGOutput = true;       /* If TRUE; enable MPEG ouput */
+       state->m_insertRSByte = false;  /* If TRUE; insert RS byte */
+       state->m_enableParallel = true; /* If TRUE;
+                                          parallel out otherwise serial */
+       state->m_invertDATA = false;    /* If TRUE; invert DATA signals */
+       state->m_invertERR = false;     /* If TRUE; invert ERR signal */
+       state->m_invertSTR = false;     /* If TRUE; invert STR signals */
+       state->m_invertVAL = false;     /* If TRUE; invert VAL signals */
+       state->m_invertCLK = (ulInvertTSClock != 0);    /* If TRUE; invert CLK signals */
+       state->m_DVBTStaticCLK = (ulDVBTStaticTSClock != 0);
+       state->m_DVBCStaticCLK = (ulDVBCStaticTSClock != 0);
+       /* If TRUE; static MPEG clockrate will be used;
+          otherwise clockrate will adapt to the bitrate of the TS */
+
+       state->m_DVBTBitrate = ulDVBTBitrate;
+       state->m_DVBCBitrate = ulDVBCBitrate;
+
+       state->m_TSDataStrength = (ulTSDataStrength & 0x07);
+       state->m_TSClockkStrength = (ulTSClockkStrength & 0x07);
+
+       /* Maximum bitrate in b/s in case static clockrate is selected */
+       state->m_mpegTsStaticBitrate = 19392658;
+       state->m_disableTEIhandling = false;
+
+       if (ulInsertRSByte)
+               state->m_insertRSByte = true;
+
+       state->m_MpegLockTimeOut = DEFAULT_DRXK_MPEG_LOCK_TIMEOUT;
+       if (ulMpegLockTimeOut < 10000)
+               state->m_MpegLockTimeOut = ulMpegLockTimeOut;
+       state->m_DemodLockTimeOut = DEFAULT_DRXK_DEMOD_LOCK_TIMEOUT;
+       if (ulDemodLockTimeOut < 10000)
+               state->m_DemodLockTimeOut = ulDemodLockTimeOut;
+
+       /* QAM defaults */
+       state->m_Constellation = DRX_CONSTELLATION_AUTO;
+       state->m_qamInterleaveMode = DRXK_QAM_I12_J17;
+       state->m_fecRsPlen = 204 * 8;   /* fecRsPlen  annex A */
+       state->m_fecRsPrescale = 1;
+
+       state->m_sqiSpeed = DRXK_DVBT_SQI_SPEED_MEDIUM;
+       state->m_agcFastClipCtrlDelay = 0;
+
+       state->m_GPIOCfg = (ulGPIOCfg);
+
+       state->m_bPowerDown = false;
+       state->m_currentPowerMode = DRX_POWER_DOWN;
+
+       state->m_enableParallel = (ulSerialMode == 0);
+
+       state->m_rfmirror = (ulRfMirror == 0);
+       state->m_IfAgcPol = false;
+       return 0;
+}
+
+static int DRXX_Open(struct drxk_state *state)
+{
+       int status = 0;
+       u32 jtag = 0;
+       u16 bid = 0;
+       u16 key = 0;
+
+       dprintk(1, "\n");
+       /* stop lock indicator process */
+       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       if (status < 0)
+               goto error;
+       /* Check device id */
+       status = read16(state, SIO_TOP_COMM_KEY__A, &key);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
+       if (status < 0)
+               goto error;
+       status = read32(state, SIO_TOP_JTAGID_LO__A, &jtag);
+       if (status < 0)
+               goto error;
+       status = read16(state, SIO_PDR_UIO_IN_HI__A, &bid);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_TOP_COMM_KEY__A, key);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int GetDeviceCapabilities(struct drxk_state *state)
+{
+       u16 sioPdrOhwCfg = 0;
+       u32 sioTopJtagidLo = 0;
+       int status;
+       const char *spin = "";
+
+       dprintk(1, "\n");
+
+       /* driver 0.9.0 */
+       /* stop lock indicator process */
+       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA);
+       if (status < 0)
+               goto error;
+       status = read16(state, SIO_PDR_OHW_CFG__A, &sioPdrOhwCfg);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
+       if (status < 0)
+               goto error;
+
+       switch ((sioPdrOhwCfg & SIO_PDR_OHW_CFG_FREF_SEL__M)) {
+       case 0:
+               /* ignore (bypass ?) */
+               break;
+       case 1:
+               /* 27 MHz */
+               state->m_oscClockFreq = 27000;
+               break;
+       case 2:
+               /* 20.25 MHz */
+               state->m_oscClockFreq = 20250;
+               break;
+       case 3:
+               /* 4 MHz */
+               state->m_oscClockFreq = 20250;
+               break;
+       default:
+               printk(KERN_ERR "drxk: Clock Frequency is unkonwn\n");
+               return -EINVAL;
+       }
+       /*
+               Determine device capabilities
+               Based on pinning v14
+               */
+       status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo);
+       if (status < 0)
+               goto error;
+       /* driver 0.9.0 */
+       switch ((sioTopJtagidLo >> 29) & 0xF) {
+       case 0:
+               state->m_deviceSpin = DRXK_SPIN_A1;
+               spin = "A1";
+               break;
+       case 2:
+               state->m_deviceSpin = DRXK_SPIN_A2;
+               spin = "A2";
+               break;
+       case 3:
+               state->m_deviceSpin = DRXK_SPIN_A3;
+               spin = "A3";
+               break;
+       default:
+               state->m_deviceSpin = DRXK_SPIN_UNKNOWN;
+               status = -EINVAL;
+               printk(KERN_ERR "drxk: Spin unknown\n");
+               goto error2;
+       }
+       switch ((sioTopJtagidLo >> 12) & 0xFF) {
+       case 0x13:
+               /* typeId = DRX3913K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = false;
+               state->m_hasAudio = false;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = true;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = false;
+               state->m_hasGPIO1 = false;
+               state->m_hasIRQN = false;
+               break;
+       case 0x15:
+               /* typeId = DRX3915K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = false;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = false;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x16:
+               /* typeId = DRX3916K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = false;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = false;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x18:
+               /* typeId = DRX3918K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = true;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = false;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x21:
+               /* typeId = DRX3921K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = true;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = true;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x23:
+               /* typeId = DRX3923K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = true;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = true;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x25:
+               /* typeId = DRX3925K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = true;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = true;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       case 0x26:
+               /* typeId = DRX3926K_TYPE_ID */
+               state->m_hasLNA = false;
+               state->m_hasOOB = false;
+               state->m_hasATV = true;
+               state->m_hasAudio = false;
+               state->m_hasDVBT = true;
+               state->m_hasDVBC = true;
+               state->m_hasSAWSW = true;
+               state->m_hasGPIO2 = true;
+               state->m_hasGPIO1 = true;
+               state->m_hasIRQN = false;
+               break;
+       default:
+               printk(KERN_ERR "drxk: DeviceID 0x%02x not supported\n",
+                       ((sioTopJtagidLo >> 12) & 0xFF));
+               status = -EINVAL;
+               goto error2;
+       }
+
+       printk(KERN_INFO
+              "drxk: detected a drx-39%02xk, spin %s, xtal %d.%03d MHz\n",
+              ((sioTopJtagidLo >> 12) & 0xFF), spin,
+              state->m_oscClockFreq / 1000,
+              state->m_oscClockFreq % 1000);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+error2:
+       return status;
+}
+
+static int HI_Command(struct drxk_state *state, u16 cmd, u16 *pResult)
+{
+       int status;
+       bool powerdown_cmd;
+
+       dprintk(1, "\n");
+
+       /* Write command */
+       status = write16(state, SIO_HI_RA_RAM_CMD__A, cmd);
+       if (status < 0)
+               goto error;
+       if (cmd == SIO_HI_RA_RAM_CMD_RESET)
+               msleep(1);
+
+       powerdown_cmd =
+           (bool) ((cmd == SIO_HI_RA_RAM_CMD_CONFIG) &&
+                   ((state->m_HICfgCtrl) &
+                    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) ==
+                   SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ);
+       if (powerdown_cmd == false) {
+               /* Wait until command rdy */
+               u32 retryCount = 0;
+               u16 waitCmd;
+
+               do {
+                       msleep(1);
+                       retryCount += 1;
+                       status = read16(state, SIO_HI_RA_RAM_CMD__A,
+                                         &waitCmd);
+               } while ((status < 0) && (retryCount < DRXK_MAX_RETRIES)
+                        && (waitCmd != 0));
+               if (status < 0)
+                       goto error;
+               status = read16(state, SIO_HI_RA_RAM_RES__A, pResult);
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int HI_CfgCommand(struct drxk_state *state)
+{
+       int status;
+
+       dprintk(1, "\n");
+
+       mutex_lock(&state->mutex);
+
+       status = write16(state, SIO_HI_RA_RAM_PAR_6__A, state->m_HICfgTimeout);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_HI_RA_RAM_PAR_5__A, state->m_HICfgCtrl);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_HI_RA_RAM_PAR_4__A, state->m_HICfgWakeUpKey);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_HI_RA_RAM_PAR_3__A, state->m_HICfgBridgeDelay);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_HI_RA_RAM_PAR_2__A, state->m_HICfgTimingDiv);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
+       if (status < 0)
+               goto error;
+       status = HI_Command(state, SIO_HI_RA_RAM_CMD_CONFIG, 0);
+       if (status < 0)
+               goto error;
+
+       state->m_HICfgCtrl &= ~SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+error:
+       mutex_unlock(&state->mutex);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int InitHI(struct drxk_state *state)
+{
+       dprintk(1, "\n");
+
+       state->m_HICfgWakeUpKey = (state->demod_address << 1);
+       state->m_HICfgTimeout = 0x96FF;
+       /* port/bridge/power down ctrl */
+       state->m_HICfgCtrl = SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE;
+
+       return HI_CfgCommand(state);
+}
+
+static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable)
+{
+       int status = -1;
+       u16 sioPdrMclkCfg = 0;
+       u16 sioPdrMdxCfg = 0;
+
+       dprintk(1, "\n");
+
+       /* stop lock indicator process */
+       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       if (status < 0)
+               goto error;
+
+       /*  MPEG TS pad configuration */
+       status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA);
+       if (status < 0)
+               goto error;
+
+       if (mpegEnable == false) {
+               /*  Set MPEG TS pads to inputmode */
+               status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MCLK_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD0_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000);
+               if (status < 0)
+                       goto error;
+       } else {
+               /* Enable MPEG output */
+               sioPdrMdxCfg =
+                       ((state->m_TSDataStrength <<
+                       SIO_PDR_MD0_CFG_DRIVE__B) | 0x0003);
+               sioPdrMclkCfg = ((state->m_TSClockkStrength <<
+                                       SIO_PDR_MCLK_CFG_DRIVE__B) |
+                                       0x0003);
+
+               status = write16(state, SIO_PDR_MSTRT_CFG__A, sioPdrMdxCfg);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MERR_CFG__A, 0x0000);   /* Disable */
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MVAL_CFG__A, 0x0000);   /* Disable */
+               if (status < 0)
+                       goto error;
+               if (state->m_enableParallel == true) {
+                       /* paralel -> enable MD1 to MD7 */
+                       status = write16(state, SIO_PDR_MD1_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD2_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD3_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD4_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD5_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD6_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD7_CFG__A, sioPdrMdxCfg);
+                       if (status < 0)
+                               goto error;
+               } else {
+                       sioPdrMdxCfg = ((state->m_TSDataStrength <<
+                                               SIO_PDR_MD0_CFG_DRIVE__B)
+                                       | 0x0003);
+                       /* serial -> disable MD1 to MD7 */
+                       status = write16(state, SIO_PDR_MD1_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD2_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD3_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD4_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD5_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD6_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+                       status = write16(state, SIO_PDR_MD7_CFG__A, 0x0000);
+                       if (status < 0)
+                               goto error;
+               }
+               status = write16(state, SIO_PDR_MCLK_CFG__A, sioPdrMclkCfg);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_PDR_MD0_CFG__A, sioPdrMdxCfg);
+               if (status < 0)
+                       goto error;
+       }
+       /*  Enable MB output over MPEG pads and ctl input */
+       status = write16(state, SIO_PDR_MON_CFG__A, 0x0000);
+       if (status < 0)
+               goto error;
+       /*  Write nomagic word to enable pdr reg write */
+       status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int MPEGTSDisable(struct drxk_state *state)
+{
+       dprintk(1, "\n");
+
+       return MPEGTSConfigurePins(state, false);
+}
+
+static int BLChainCmd(struct drxk_state *state,
+                     u16 romOffset, u16 nrOfElements, u32 timeOut)
+{
+       u16 blStatus = 0;
+       int status;
+       unsigned long end;
+
+       dprintk(1, "\n");
+       mutex_lock(&state->mutex);
+       status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_CHAIN);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_CHAIN_ADDR__A, romOffset);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_CHAIN_LEN__A, nrOfElements);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
+       if (status < 0)
+               goto error;
+
+       end = jiffies + msecs_to_jiffies(timeOut);
+       do {
+               msleep(1);
+               status = read16(state, SIO_BL_STATUS__A, &blStatus);
+               if (status < 0)
+                       goto error;
+       } while ((blStatus == 0x1) &&
+                       ((time_is_after_jiffies(end))));
+
+       if (blStatus == 0x1) {
+               printk(KERN_ERR "drxk: SIO not ready\n");
+               status = -EINVAL;
+               goto error2;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+error2:
+       mutex_unlock(&state->mutex);
+       return status;
+}
+
+
+static int DownloadMicrocode(struct drxk_state *state,
+                            const u8 pMCImage[], u32 Length)
+{
+       const u8 *pSrc = pMCImage;
+       u16 Flags;
+       u16 Drain;
+       u32 Address;
+       u16 nBlocks;
+       u16 BlockSize;
+       u16 BlockCRC;
+       u32 offset = 0;
+       u32 i;
+       int status = 0;
+
+       dprintk(1, "\n");
+
+       /* down the drain (we don care about MAGIC_WORD) */
+       Drain = (pSrc[0] << 8) | pSrc[1];
+       pSrc += sizeof(u16);
+       offset += sizeof(u16);
+       nBlocks = (pSrc[0] << 8) | pSrc[1];
+       pSrc += sizeof(u16);
+       offset += sizeof(u16);
+
+       for (i = 0; i < nBlocks; i += 1) {
+               Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
+                   (pSrc[2] << 8) | pSrc[3];
+               pSrc += sizeof(u32);
+               offset += sizeof(u32);
+
+               BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
+               pSrc += sizeof(u16);
+               offset += sizeof(u16);
+
+               Flags = (pSrc[0] << 8) | pSrc[1];
+               pSrc += sizeof(u16);
+               offset += sizeof(u16);
+
+               BlockCRC = (pSrc[0] << 8) | pSrc[1];
+               pSrc += sizeof(u16);
+               offset += sizeof(u16);
+
+               if (offset + BlockSize > Length) {
+                       printk(KERN_ERR "drxk: Firmware is corrupted.\n");
+                       return -EINVAL;
+               }
+
+               status = write_block(state, Address, BlockSize, pSrc);
+               if (status < 0) {
+                       printk(KERN_ERR "drxk: Error %d while loading firmware\n", status);
+                       break;
+               }
+               pSrc += BlockSize;
+               offset += BlockSize;
+       }
+       return status;
+}
+
+static int DVBTEnableOFDMTokenRing(struct drxk_state *state, bool enable)
+{
+       int status;
+       u16 data = 0;
+       u16 desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_ON;
+       u16 desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED;
+       unsigned long end;
+
+       dprintk(1, "\n");
+
+       if (enable == false) {
+               desiredCtrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF;
+               desiredStatus = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN;
+       }
+
+       status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
+       if (status >= 0 && data == desiredStatus) {
+               /* tokenring already has correct status */
+               return status;
+       }
+       /* Disable/enable dvbt tokenring bridge   */
+       status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, desiredCtrl);
+
+       end = jiffies + msecs_to_jiffies(DRXK_OFDM_TR_SHUTDOWN_TIMEOUT);
+       do {
+               status = read16(state, SIO_OFDM_SH_OFDM_RING_STATUS__A, &data);
+               if ((status >= 0 && data == desiredStatus) || time_is_after_jiffies(end))
+                       break;
+               msleep(1);
+       } while (1);
+       if (data != desiredStatus) {
+               printk(KERN_ERR "drxk: SIO not ready\n");
+               return -EINVAL;
+       }
+       return status;
+}
+
+static int MPEGTSStop(struct drxk_state *state)
+{
+       int status = 0;
+       u16 fecOcSncMode = 0;
+       u16 fecOcIprMode = 0;
+
+       dprintk(1, "\n");
+
+       /* Gracefull shutdown (byte boundaries) */
+       status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
+       if (status < 0)
+               goto error;
+       fecOcSncMode |= FEC_OC_SNC_MODE_SHUTDOWN__M;
+       status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
+       if (status < 0)
+               goto error;
+
+       /* Suppress MCLK during absence of data */
+       status = read16(state, FEC_OC_IPR_MODE__A, &fecOcIprMode);
+       if (status < 0)
+               goto error;
+       fecOcIprMode |= FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M;
+       status = write16(state, FEC_OC_IPR_MODE__A, fecOcIprMode);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int scu_command(struct drxk_state *state,
+                      u16 cmd, u8 parameterLen,
+                      u16 *parameter, u8 resultLen, u16 *result)
+{
+#if (SCU_RAM_PARAM_0__A - SCU_RAM_PARAM_15__A) != 15
+#error DRXK register mapping no longer compatible with this routine!
+#endif
+       u16 curCmd = 0;
+       int status = -EINVAL;
+       unsigned long end;
+       u8 buffer[34];
+       int cnt = 0, ii;
+       const char *p;
+       char errname[30];
+
+       dprintk(1, "\n");
+
+       if ((cmd == 0) || ((parameterLen > 0) && (parameter == NULL)) ||
+           ((resultLen > 0) && (result == NULL)))
+               goto error;
+
+       mutex_lock(&state->mutex);
+
+       /* assume that the command register is ready
+               since it is checked afterwards */
+       for (ii = parameterLen - 1; ii >= 0; ii -= 1) {
+               buffer[cnt++] = (parameter[ii] & 0xFF);
+               buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
+       }
+       buffer[cnt++] = (cmd & 0xFF);
+       buffer[cnt++] = ((cmd >> 8) & 0xFF);
+
+       write_block(state, SCU_RAM_PARAM_0__A -
+                       (parameterLen - 1), cnt, buffer);
+       /* Wait until SCU has processed command */
+       end = jiffies + msecs_to_jiffies(DRXK_MAX_WAITTIME);
+       do {
+               msleep(1);
+               status = read16(state, SCU_RAM_COMMAND__A, &curCmd);
+               if (status < 0)
+                       goto error;
+       } while (!(curCmd == DRX_SCU_READY) && (time_is_after_jiffies(end)));
+       if (curCmd != DRX_SCU_READY) {
+               printk(KERN_ERR "drxk: SCU not ready\n");
+               status = -EIO;
+               goto error2;
+       }
+       /* read results */
+       if ((resultLen > 0) && (result != NULL)) {
+               s16 err;
+               int ii;
+
+               for (ii = resultLen - 1; ii >= 0; ii -= 1) {
+                       status = read16(state, SCU_RAM_PARAM_0__A - ii, &result[ii]);
+                       if (status < 0)
+                               goto error;
+               }
+
+               /* Check if an error was reported by SCU */
+               err = (s16)result[0];
+               if (err >= 0)
+                       goto error;
+
+               /* check for the known error codes */
+               switch (err) {
+               case SCU_RESULT_UNKCMD:
+                       p = "SCU_RESULT_UNKCMD";
+                       break;
+               case SCU_RESULT_UNKSTD:
+                       p = "SCU_RESULT_UNKSTD";
+                       break;
+               case SCU_RESULT_SIZE:
+                       p = "SCU_RESULT_SIZE";
+                       break;
+               case SCU_RESULT_INVPAR:
+                       p = "SCU_RESULT_INVPAR";
+                       break;
+               default: /* Other negative values are errors */
+                       sprintf(errname, "ERROR: %d\n", err);
+                       p = errname;
+               }
+               printk(KERN_ERR "drxk: %s while sending cmd 0x%04x with params:", p, cmd);
+               print_hex_dump_bytes("drxk: ", DUMP_PREFIX_NONE, buffer, cnt);
+               status = -EINVAL;
+               goto error2;
+       }
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+error2:
+       mutex_unlock(&state->mutex);
+       return status;
+}
+
+static int SetIqmAf(struct drxk_state *state, bool active)
+{
+       u16 data = 0;
+       int status;
+
+       dprintk(1, "\n");
+
+       /* Configure IQM */
+       status = read16(state, IQM_AF_STDBY__A, &data);
+       if (status < 0)
+               goto error;
+
+       if (!active) {
+               data |= (IQM_AF_STDBY_STDBY_ADC_STANDBY
+                               | IQM_AF_STDBY_STDBY_AMP_STANDBY
+                               | IQM_AF_STDBY_STDBY_PD_STANDBY
+                               | IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY
+                               | IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY);
+       } else {
+               data &= ((~IQM_AF_STDBY_STDBY_ADC_STANDBY)
+                               & (~IQM_AF_STDBY_STDBY_AMP_STANDBY)
+                               & (~IQM_AF_STDBY_STDBY_PD_STANDBY)
+                               & (~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY)
+                               & (~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY)
+                       );
+       }
+       status = write16(state, IQM_AF_STDBY__A, data);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int CtrlPowerMode(struct drxk_state *state, enum DRXPowerMode *mode)
+{
+       int status = 0;
+       u16 sioCcPwdMode = 0;
+
+       dprintk(1, "\n");
+
+       /* Check arguments */
+       if (mode == NULL)
+               return -EINVAL;
+
+       switch (*mode) {
+       case DRX_POWER_UP:
+               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_NONE;
+               break;
+       case DRXK_POWER_DOWN_OFDM:
+               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OFDM;
+               break;
+       case DRXK_POWER_DOWN_CORE:
+               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_CLOCK;
+               break;
+       case DRXK_POWER_DOWN_PLL:
+               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_PLL;
+               break;
+       case DRX_POWER_DOWN:
+               sioCcPwdMode = SIO_CC_PWD_MODE_LEVEL_OSC;
+               break;
+       default:
+               /* Unknow sleep mode */
+               return -EINVAL;
+       }
+
+       /* If already in requested power mode, do nothing */
+       if (state->m_currentPowerMode == *mode)
+               return 0;
+
+       /* For next steps make sure to start from DRX_POWER_UP mode */
+       if (state->m_currentPowerMode != DRX_POWER_UP) {
+               status = PowerUpDevice(state);
+               if (status < 0)
+                       goto error;
+               status = DVBTEnableOFDMTokenRing(state, true);
+               if (status < 0)
+                       goto error;
+       }
+
+       if (*mode == DRX_POWER_UP) {
+               /* Restore analog & pin configuartion */
+       } else {
+               /* Power down to requested mode */
+               /* Backup some register settings */
+               /* Set pins with possible pull-ups connected
+                  to them in input mode */
+               /* Analog power down */
+               /* ADC power down */
+               /* Power down device */
+               /* stop all comm_exec */
+               /* Stop and power down previous standard */
+               switch (state->m_OperationMode) {
+               case OM_DVBT:
+                       status = MPEGTSStop(state);
+                       if (status < 0)
+                               goto error;
+                       status = PowerDownDVBT(state, false);
+                       if (status < 0)
+                               goto error;
+                       break;
+               case OM_QAM_ITU_A:
+               case OM_QAM_ITU_C:
+                       status = MPEGTSStop(state);
+                       if (status < 0)
+                               goto error;
+                       status = PowerDownQAM(state);
+                       if (status < 0)
+                               goto error;
+                       break;
+               default:
+                       break;
+               }
+               status = DVBTEnableOFDMTokenRing(state, false);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_CC_PWD_MODE__A, sioCcPwdMode);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+               if (status < 0)
+                       goto error;
+
+               if (*mode != DRXK_POWER_DOWN_OFDM) {
+                       state->m_HICfgCtrl |=
+                               SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+                       status = HI_CfgCommand(state);
+                       if (status < 0)
+                               goto error;
+               }
+       }
+       state->m_currentPowerMode = *mode;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int PowerDownDVBT(struct drxk_state *state, bool setPowerMode)
+{
+       enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+       u16 cmdResult = 0;
+       u16 data = 0;
+       int status;
+
+       dprintk(1, "\n");
+
+       status = read16(state, SCU_COMM_EXEC__A, &data);
+       if (status < 0)
+               goto error;
+       if (data == SCU_COMM_EXEC_ACTIVE) {
+               /* Send OFDM stop command */
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+               if (status < 0)
+                       goto error;
+               /* Send OFDM reset command */
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+               if (status < 0)
+                       goto error;
+       }
+
+       /* Reset datapath for OFDM, processors first */
+       status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
+       if (status < 0)
+               goto error;
+
+       /* powerdown AFE                   */
+       status = SetIqmAf(state, false);
+       if (status < 0)
+               goto error;
+
+       /* powerdown to OFDM mode          */
+       if (setPowerMode) {
+               status = CtrlPowerMode(state, &powerMode);
+               if (status < 0)
+                       goto error;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SetOperationMode(struct drxk_state *state,
+                           enum OperationMode oMode)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+       /*
+          Stop and power down previous standard
+          TODO investigate total power down instead of partial
+          power down depending on "previous" standard.
+        */
+
+       /* disable HW lock indicator */
+       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       if (status < 0)
+               goto error;
+
+       /* Device is already at the required mode */
+       if (state->m_OperationMode == oMode)
+               return 0;
+
+       switch (state->m_OperationMode) {
+               /* OM_NONE was added for start up */
+       case OM_NONE:
+               break;
+       case OM_DVBT:
+               status = MPEGTSStop(state);
+               if (status < 0)
+                       goto error;
+               status = PowerDownDVBT(state, true);
+               if (status < 0)
+                       goto error;
+               state->m_OperationMode = OM_NONE;
+               break;
+       case OM_QAM_ITU_A:      /* fallthrough */
+       case OM_QAM_ITU_C:
+               status = MPEGTSStop(state);
+               if (status < 0)
+                       goto error;
+               status = PowerDownQAM(state);
+               if (status < 0)
+                       goto error;
+               state->m_OperationMode = OM_NONE;
+               break;
+       case OM_QAM_ITU_B:
+       default:
+               status = -EINVAL;
+               goto error;
+       }
+
+       /*
+               Power up new standard
+               */
+       switch (oMode) {
+       case OM_DVBT:
+               state->m_OperationMode = oMode;
+               status = SetDVBTStandard(state, oMode);
+               if (status < 0)
+                       goto error;
+               break;
+       case OM_QAM_ITU_A:      /* fallthrough */
+       case OM_QAM_ITU_C:
+               state->m_OperationMode = oMode;
+               status = SetQAMStandard(state, oMode);
+               if (status < 0)
+                       goto error;
+               break;
+       case OM_QAM_ITU_B:
+       default:
+               status = -EINVAL;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int Start(struct drxk_state *state, s32 offsetFreq,
+                s32 IntermediateFrequency)
+{
+       int status = -EINVAL;
+
+       u16 IFreqkHz;
+       s32 OffsetkHz = offsetFreq / 1000;
+
+       dprintk(1, "\n");
+       if (state->m_DrxkState != DRXK_STOPPED &&
+               state->m_DrxkState != DRXK_DTV_STARTED)
+               goto error;
+
+       state->m_bMirrorFreqSpect = (state->param.inversion == INVERSION_ON);
+
+       if (IntermediateFrequency < 0) {
+               state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect;
+               IntermediateFrequency = -IntermediateFrequency;
+       }
+
+       switch (state->m_OperationMode) {
+       case OM_QAM_ITU_A:
+       case OM_QAM_ITU_C:
+               IFreqkHz = (IntermediateFrequency / 1000);
+               status = SetQAM(state, IFreqkHz, OffsetkHz);
+               if (status < 0)
+                       goto error;
+               state->m_DrxkState = DRXK_DTV_STARTED;
+               break;
+       case OM_DVBT:
+               IFreqkHz = (IntermediateFrequency / 1000);
+               status = MPEGTSStop(state);
+               if (status < 0)
+                       goto error;
+               status = SetDVBT(state, IFreqkHz, OffsetkHz);
+               if (status < 0)
+                       goto error;
+               status = DVBTStart(state);
+               if (status < 0)
+                       goto error;
+               state->m_DrxkState = DRXK_DTV_STARTED;
+               break;
+       default:
+               break;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int ShutDown(struct drxk_state *state)
+{
+       dprintk(1, "\n");
+
+       MPEGTSStop(state);
+       return 0;
+}
+
+static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus,
+                        u32 Time)
+{
+       int status = -EINVAL;
+
+       dprintk(1, "\n");
+
+       if (pLockStatus == NULL)
+               goto error;
+
+       *pLockStatus = NOT_LOCKED;
+
+       /* define the SCU command code */
+       switch (state->m_OperationMode) {
+       case OM_QAM_ITU_A:
+       case OM_QAM_ITU_B:
+       case OM_QAM_ITU_C:
+               status = GetQAMLockStatus(state, pLockStatus);
+               break;
+       case OM_DVBT:
+               status = GetDVBTLockStatus(state, pLockStatus);
+               break;
+       default:
+               break;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int MPEGTSStart(struct drxk_state *state)
+{
+       int status;
+
+       u16 fecOcSncMode = 0;
+
+       /* Allow OC to sync again */
+       status = read16(state, FEC_OC_SNC_MODE__A, &fecOcSncMode);
+       if (status < 0)
+               goto error;
+       fecOcSncMode &= ~FEC_OC_SNC_MODE_SHUTDOWN__M;
+       status = write16(state, FEC_OC_SNC_MODE__A, fecOcSncMode);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_SNC_UNLOCK__A, 1);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int MPEGTSDtoInit(struct drxk_state *state)
+{
+       int status;
+
+       dprintk(1, "\n");
+
+       /* Rate integration settings */
+       status = write16(state, FEC_OC_RCN_CTL_STEP_LO__A, 0x0000);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_RCN_CTL_STEP_HI__A, 0x000C);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_RCN_GAIN__A, 0x000A);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_AVR_PARM_A__A, 0x0008);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_AVR_PARM_B__A, 0x0006);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_TMD_HI_MARGIN__A, 0x0680);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_TMD_LO_MARGIN__A, 0x0080);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_TMD_COUNT__A, 0x03F4);
+       if (status < 0)
+               goto error;
+
+       /* Additional configuration */
+       status = write16(state, FEC_OC_OCR_INVERT__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_SNC_LWM__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_SNC_HWM__A, 12);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int MPEGTSDtoSetup(struct drxk_state *state,
+                         enum OperationMode oMode)
+{
+       int status;
+
+       u16 fecOcRegMode = 0;   /* FEC_OC_MODE       register value */
+       u16 fecOcRegIprMode = 0;        /* FEC_OC_IPR_MODE   register value */
+       u16 fecOcDtoMode = 0;   /* FEC_OC_IPR_INVERT register value */
+       u16 fecOcFctMode = 0;   /* FEC_OC_IPR_INVERT register value */
+       u16 fecOcDtoPeriod = 2; /* FEC_OC_IPR_INVERT register value */
+       u16 fecOcDtoBurstLen = 188;     /* FEC_OC_IPR_INVERT register value */
+       u32 fecOcRcnCtlRate = 0;        /* FEC_OC_IPR_INVERT register value */
+       u16 fecOcTmdMode = 0;
+       u16 fecOcTmdIntUpdRate = 0;
+       u32 maxBitRate = 0;
+       bool staticCLK = false;
+
+       dprintk(1, "\n");
+
+       /* Check insertion of the Reed-Solomon parity bytes */
+       status = read16(state, FEC_OC_MODE__A, &fecOcRegMode);
+       if (status < 0)
+               goto error;
+       status = read16(state, FEC_OC_IPR_MODE__A, &fecOcRegIprMode);
+       if (status < 0)
+               goto error;
+       fecOcRegMode &= (~FEC_OC_MODE_PARITY__M);
+       fecOcRegIprMode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M);
+       if (state->m_insertRSByte == true) {
+               /* enable parity symbol forward */
+               fecOcRegMode |= FEC_OC_MODE_PARITY__M;
+               /* MVAL disable during parity bytes */
+               fecOcRegIprMode |= FEC_OC_IPR_MODE_MVAL_DIS_PAR__M;
+               /* TS burst length to 204 */
+               fecOcDtoBurstLen = 204;
+       }
+
+       /* Check serial or parrallel output */
+       fecOcRegIprMode &= (~(FEC_OC_IPR_MODE_SERIAL__M));
+       if (state->m_enableParallel == false) {
+               /* MPEG data output is serial -> set ipr_mode[0] */
+               fecOcRegIprMode |= FEC_OC_IPR_MODE_SERIAL__M;
+       }
+
+       switch (oMode) {
+       case OM_DVBT:
+               maxBitRate = state->m_DVBTBitrate;
+               fecOcTmdMode = 3;
+               fecOcRcnCtlRate = 0xC00000;
+               staticCLK = state->m_DVBTStaticCLK;
+               break;
+       case OM_QAM_ITU_A:      /* fallthrough */
+       case OM_QAM_ITU_C:
+               fecOcTmdMode = 0x0004;
+               fecOcRcnCtlRate = 0xD2B4EE;     /* good for >63 Mb/s */
+               maxBitRate = state->m_DVBCBitrate;
+               staticCLK = state->m_DVBCStaticCLK;
+               break;
+       default:
+               status = -EINVAL;
+       }               /* switch (standard) */
+       if (status < 0)
+               goto error;
+
+       /* Configure DTO's */
+       if (staticCLK) {
+               u32 bitRate = 0;
+
+               /* Rational DTO for MCLK source (static MCLK rate),
+                       Dynamic DTO for optimal grouping
+                       (avoid intra-packet gaps),
+                       DTO offset enable to sync TS burst with MSTRT */
+               fecOcDtoMode = (FEC_OC_DTO_MODE_DYNAMIC__M |
+                               FEC_OC_DTO_MODE_OFFSET_ENABLE__M);
+               fecOcFctMode = (FEC_OC_FCT_MODE_RAT_ENA__M |
+                               FEC_OC_FCT_MODE_VIRT_ENA__M);
+
+               /* Check user defined bitrate */
+               bitRate = maxBitRate;
+               if (bitRate > 75900000UL) {     /* max is 75.9 Mb/s */
+                       bitRate = 75900000UL;
+               }
+               /* Rational DTO period:
+                       dto_period = (Fsys / bitrate) - 2
+
+                       Result should be floored,
+                       to make sure >= requested bitrate
+                       */
+               fecOcDtoPeriod = (u16) (((state->m_sysClockFreq)
+                                               * 1000) / bitRate);
+               if (fecOcDtoPeriod <= 2)
+                       fecOcDtoPeriod = 0;
+               else
+                       fecOcDtoPeriod -= 2;
+               fecOcTmdIntUpdRate = 8;
+       } else {
+               /* (commonAttr->staticCLK == false) => dynamic mode */
+               fecOcDtoMode = FEC_OC_DTO_MODE_DYNAMIC__M;
+               fecOcFctMode = FEC_OC_FCT_MODE__PRE;
+               fecOcTmdIntUpdRate = 5;
+       }
+
+       /* Write appropriate registers with requested configuration */
+       status = write16(state, FEC_OC_DTO_BURST_LEN__A, fecOcDtoBurstLen);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_DTO_PERIOD__A, fecOcDtoPeriod);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_DTO_MODE__A, fecOcDtoMode);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_FCT_MODE__A, fecOcFctMode);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_MODE__A, fecOcRegMode);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_IPR_MODE__A, fecOcRegIprMode);
+       if (status < 0)
+               goto error;
+
+       /* Rate integration settings */
+       status = write32(state, FEC_OC_RCN_CTL_RATE_LO__A, fecOcRcnCtlRate);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_TMD_INT_UPD_RATE__A, fecOcTmdIntUpdRate);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_TMD_MODE__A, fecOcTmdMode);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int MPEGTSConfigurePolarity(struct drxk_state *state)
+{
+       u16 fecOcRegIprInvert = 0;
+
+       /* Data mask for the output data byte */
+       u16 InvertDataMask =
+           FEC_OC_IPR_INVERT_MD7__M | FEC_OC_IPR_INVERT_MD6__M |
+           FEC_OC_IPR_INVERT_MD5__M | FEC_OC_IPR_INVERT_MD4__M |
+           FEC_OC_IPR_INVERT_MD3__M | FEC_OC_IPR_INVERT_MD2__M |
+           FEC_OC_IPR_INVERT_MD1__M | FEC_OC_IPR_INVERT_MD0__M;
+
+       dprintk(1, "\n");
+
+       /* Control selective inversion of output bits */
+       fecOcRegIprInvert &= (~(InvertDataMask));
+       if (state->m_invertDATA == true)
+               fecOcRegIprInvert |= InvertDataMask;
+       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MERR__M));
+       if (state->m_invertERR == true)
+               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MERR__M;
+       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MSTRT__M));
+       if (state->m_invertSTR == true)
+               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MSTRT__M;
+       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MVAL__M));
+       if (state->m_invertVAL == true)
+               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MVAL__M;
+       fecOcRegIprInvert &= (~(FEC_OC_IPR_INVERT_MCLK__M));
+       if (state->m_invertCLK == true)
+               fecOcRegIprInvert |= FEC_OC_IPR_INVERT_MCLK__M;
+
+       return write16(state, FEC_OC_IPR_INVERT__A, fecOcRegIprInvert);
+}
+
+#define   SCU_RAM_AGC_KI_INV_RF_POL__M 0x4000
+
+static int SetAgcRf(struct drxk_state *state,
+                   struct SCfgAgc *pAgcCfg, bool isDTV)
+{
+       int status = -EINVAL;
+       u16 data = 0;
+       struct SCfgAgc *pIfAgcSettings;
+
+       dprintk(1, "\n");
+
+       if (pAgcCfg == NULL)
+               goto error;
+
+       switch (pAgcCfg->ctrlMode) {
+       case DRXK_AGC_CTRL_AUTO:
+               /* Enable RF AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+
+               /* Enable SCU RF AGC loop */
+               data &= ~SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
+
+               /* Polarity */
+               if (state->m_RfAgcPol)
+                       data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+               else
+                       data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Set speed (using complementary reduction value) */
+               status = read16(state, SCU_RAM_AGC_KI_RED__A, &data);
+               if (status < 0)
+                       goto error;
+
+               data &= ~SCU_RAM_AGC_KI_RED_RAGC_RED__M;
+               data |= (~(pAgcCfg->speed <<
+                               SCU_RAM_AGC_KI_RED_RAGC_RED__B)
+                               & SCU_RAM_AGC_KI_RED_RAGC_RED__M);
+
+               status = write16(state, SCU_RAM_AGC_KI_RED__A, data);
+               if (status < 0)
+                       goto error;
+
+               if (IsDVBT(state))
+                       pIfAgcSettings = &state->m_dvbtIfAgcCfg;
+               else if (IsQAM(state))
+                       pIfAgcSettings = &state->m_qamIfAgcCfg;
+               else
+                       pIfAgcSettings = &state->m_atvIfAgcCfg;
+               if (pIfAgcSettings == NULL) {
+                       status = -EINVAL;
+                       goto error;
+               }
+
+               /* Set TOP, only if IF-AGC is in AUTO mode */
+               if (pIfAgcSettings->ctrlMode == DRXK_AGC_CTRL_AUTO)
+                       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->top);
+                       if (status < 0)
+                               goto error;
+
+               /* Cut-Off current */
+               status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, pAgcCfg->cutOffCurrent);
+               if (status < 0)
+                       goto error;
+
+               /* Max. output level */
+               status = write16(state, SCU_RAM_AGC_RF_MAX__A, pAgcCfg->maxOutputLevel);
+               if (status < 0)
+                       goto error;
+
+               break;
+
+       case DRXK_AGC_CTRL_USER:
+               /* Enable RF AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data &= ~IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Disable SCU RF AGC loop */
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+               data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
+               if (state->m_RfAgcPol)
+                       data |= SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+               else
+                       data &= ~SCU_RAM_AGC_CONFIG_INV_RF_POL__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* SCU c.o.c. to 0, enabling full control range */
+               status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, 0);
+               if (status < 0)
+                       goto error;
+
+               /* Write value to output pin */
+               status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, pAgcCfg->outputLevel);
+               if (status < 0)
+                       goto error;
+               break;
+
+       case DRXK_AGC_CTRL_OFF:
+               /* Disable RF AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data |= IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Disable SCU RF AGC loop */
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+               data |= SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+               break;
+
+       default:
+               status = -EINVAL;
+
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+#define SCU_RAM_AGC_KI_INV_IF_POL__M 0x2000
+
+static int SetAgcIf(struct drxk_state *state,
+                   struct SCfgAgc *pAgcCfg, bool isDTV)
+{
+       u16 data = 0;
+       int status = 0;
+       struct SCfgAgc *pRfAgcSettings;
+
+       dprintk(1, "\n");
+
+       switch (pAgcCfg->ctrlMode) {
+       case DRXK_AGC_CTRL_AUTO:
+
+               /* Enable IF AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+
+               /* Enable SCU IF AGC loop */
+               data &= ~SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
+
+               /* Polarity */
+               if (state->m_IfAgcPol)
+                       data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+               else
+                       data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Set speed (using complementary reduction value) */
+               status = read16(state, SCU_RAM_AGC_KI_RED__A, &data);
+               if (status < 0)
+                       goto error;
+               data &= ~SCU_RAM_AGC_KI_RED_IAGC_RED__M;
+               data |= (~(pAgcCfg->speed <<
+                               SCU_RAM_AGC_KI_RED_IAGC_RED__B)
+                               & SCU_RAM_AGC_KI_RED_IAGC_RED__M);
+
+               status = write16(state, SCU_RAM_AGC_KI_RED__A, data);
+               if (status < 0)
+                       goto error;
+
+               if (IsQAM(state))
+                       pRfAgcSettings = &state->m_qamRfAgcCfg;
+               else
+                       pRfAgcSettings = &state->m_atvRfAgcCfg;
+               if (pRfAgcSettings == NULL)
+                       return -1;
+               /* Restore TOP */
+               status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pRfAgcSettings->top);
+               if (status < 0)
+                       goto error;
+               break;
+
+       case DRXK_AGC_CTRL_USER:
+
+               /* Enable IF AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data &= ~IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+
+               /* Disable SCU IF AGC loop */
+               data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
+
+               /* Polarity */
+               if (state->m_IfAgcPol)
+                       data |= SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+               else
+                       data &= ~SCU_RAM_AGC_CONFIG_INV_IF_POL__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Write value to output pin */
+               status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, pAgcCfg->outputLevel);
+               if (status < 0)
+                       goto error;
+               break;
+
+       case DRXK_AGC_CTRL_OFF:
+
+               /* Disable If AGC DAC */
+               status = read16(state, IQM_AF_STDBY__A, &data);
+               if (status < 0)
+                       goto error;
+               data |= IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY;
+               status = write16(state, IQM_AF_STDBY__A, data);
+               if (status < 0)
+                       goto error;
+
+               /* Disable SCU IF AGC loop */
+               status = read16(state, SCU_RAM_AGC_CONFIG__A, &data);
+               if (status < 0)
+                       goto error;
+               data |= SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M;
+               status = write16(state, SCU_RAM_AGC_CONFIG__A, data);
+               if (status < 0)
+                       goto error;
+               break;
+       }               /* switch (agcSettingsIf->ctrlMode) */
+
+       /* always set the top to support
+               configurations without if-loop */
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, pAgcCfg->top);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int ReadIFAgc(struct drxk_state *state, u32 *pValue)
+{
+       u16 agcDacLvl;
+       int status;
+       u16 Level = 0;
+
+       dprintk(1, "\n");
+
+       status = read16(state, IQM_AF_AGC_IF__A, &agcDacLvl);
+       if (status < 0) {
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               return status;
+       }
+
+       *pValue = 0;
+
+       if (agcDacLvl > DRXK_AGC_DAC_OFFSET)
+               Level = agcDacLvl - DRXK_AGC_DAC_OFFSET;
+       if (Level < 14000)
+               *pValue = (14000 - Level) / 4;
+       else
+               *pValue = 0;
+
+       return status;
+}
+
+static int GetQAMSignalToNoise(struct drxk_state *state,
+                              s32 *pSignalToNoise)
+{
+       int status = 0;
+       u16 qamSlErrPower = 0;  /* accum. error between
+                                       raw and sliced symbols */
+       u32 qamSlSigPower = 0;  /* used for MER, depends of
+                                       QAM constellation */
+       u32 qamSlMer = 0;       /* QAM MER */
+
+       dprintk(1, "\n");
+
+       /* MER calculation */
+
+       /* get the register value needed for MER */
+       status = read16(state, QAM_SL_ERR_POWER__A, &qamSlErrPower);
+       if (status < 0) {
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+               return -EINVAL;
+       }
+
+       switch (state->param.u.qam.modulation) {
+       case QAM_16:
+               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2;
+               break;
+       case QAM_32:
+               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM32 << 2;
+               break;
+       case QAM_64:
+               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM64 << 2;
+               break;
+       case QAM_128:
+               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM128 << 2;
+               break;
+       default:
+       case QAM_256:
+               qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM256 << 2;
+               break;
+       }
+
+       if (qamSlErrPower > 0) {
+               qamSlMer = Log10Times100(qamSlSigPower) -
+                       Log10Times100((u32) qamSlErrPower);
+       }
+       *pSignalToNoise = qamSlMer;
+
+       return status;
+}
+
+static int GetDVBTSignalToNoise(struct drxk_state *state,
+                               s32 *pSignalToNoise)
+{
+       int status;
+       u16 regData = 0;
+       u32 EqRegTdSqrErrI = 0;
+       u32 EqRegTdSqrErrQ = 0;
+       u16 EqRegTdSqrErrExp = 0;
+       u16 EqRegTdTpsPwrOfs = 0;
+       u16 EqRegTdReqSmbCnt = 0;
+       u32 tpsCnt = 0;
+       u32 SqrErrIQ = 0;
+       u32 a = 0;
+       u32 b = 0;
+       u32 c = 0;
+       u32 iMER = 0;
+       u16 transmissionParams = 0;
+
+       dprintk(1, "\n");
+
+       status = read16(state, OFDM_EQ_TOP_TD_TPS_PWR_OFS__A, &EqRegTdTpsPwrOfs);
+       if (status < 0)
+               goto error;
+       status = read16(state, OFDM_EQ_TOP_TD_REQ_SMB_CNT__A, &EqRegTdReqSmbCnt);
+       if (status < 0)
+               goto error;
+       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_EXP__A, &EqRegTdSqrErrExp);
+       if (status < 0)
+               goto error;
+       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_I__A, &regData);
+       if (status < 0)
+               goto error;
+       /* Extend SQR_ERR_I operational range */
+       EqRegTdSqrErrI = (u32) regData;
+       if ((EqRegTdSqrErrExp > 11) &&
+               (EqRegTdSqrErrI < 0x00000FFFUL)) {
+               EqRegTdSqrErrI += 0x00010000UL;
+       }
+       status = read16(state, OFDM_EQ_TOP_TD_SQR_ERR_Q__A, &regData);
+       if (status < 0)
+               goto error;
+       /* Extend SQR_ERR_Q operational range */
+       EqRegTdSqrErrQ = (u32) regData;
+       if ((EqRegTdSqrErrExp > 11) &&
+               (EqRegTdSqrErrQ < 0x00000FFFUL))
+               EqRegTdSqrErrQ += 0x00010000UL;
+
+       status = read16(state, OFDM_SC_RA_RAM_OP_PARAM__A, &transmissionParams);
+       if (status < 0)
+               goto error;
+
+       /* Check input data for MER */
+
+       /* MER calculation (in 0.1 dB) without math.h */
+       if ((EqRegTdTpsPwrOfs == 0) || (EqRegTdReqSmbCnt == 0))
+               iMER = 0;
+       else if ((EqRegTdSqrErrI + EqRegTdSqrErrQ) == 0) {
+               /* No error at all, this must be the HW reset value
+                       * Apparently no first measurement yet
+                       * Set MER to 0.0 */
+               iMER = 0;
+       } else {
+               SqrErrIQ = (EqRegTdSqrErrI + EqRegTdSqrErrQ) <<
+                       EqRegTdSqrErrExp;
+               if ((transmissionParams &
+                       OFDM_SC_RA_RAM_OP_PARAM_MODE__M)
+                       == OFDM_SC_RA_RAM_OP_PARAM_MODE_2K)
+                       tpsCnt = 17;
+               else
+                       tpsCnt = 68;
+
+               /* IMER = 100 * log10 (x)
+                       where x = (EqRegTdTpsPwrOfs^2 *
+                       EqRegTdReqSmbCnt * tpsCnt)/SqrErrIQ
+
+                       => IMER = a + b -c
+                       where a = 100 * log10 (EqRegTdTpsPwrOfs^2)
+                       b = 100 * log10 (EqRegTdReqSmbCnt * tpsCnt)
+                       c = 100 * log10 (SqrErrIQ)
+                       */
+
+               /* log(x) x = 9bits * 9bits->18 bits  */
+               a = Log10Times100(EqRegTdTpsPwrOfs *
+                                       EqRegTdTpsPwrOfs);
+               /* log(x) x = 16bits * 7bits->23 bits  */
+               b = Log10Times100(EqRegTdReqSmbCnt * tpsCnt);
+               /* log(x) x = (16bits + 16bits) << 15 ->32 bits  */
+               c = Log10Times100(SqrErrIQ);
+
+               iMER = a + b;
+               /* No negative MER, clip to zero */
+               if (iMER > c)
+                       iMER -= c;
+               else
+                       iMER = 0;
+       }
+       *pSignalToNoise = iMER;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int GetSignalToNoise(struct drxk_state *state, s32 *pSignalToNoise)
+{
+       dprintk(1, "\n");
+
+       *pSignalToNoise = 0;
+       switch (state->m_OperationMode) {
+       case OM_DVBT:
+               return GetDVBTSignalToNoise(state, pSignalToNoise);
+       case OM_QAM_ITU_A:
+       case OM_QAM_ITU_C:
+               return GetQAMSignalToNoise(state, pSignalToNoise);
+       default:
+               break;
+       }
+       return 0;
+}
+
+#if 0
+static int GetDVBTQuality(struct drxk_state *state, s32 *pQuality)
+{
+       /* SNR Values for quasi errorfree reception rom Nordig 2.2 */
+       int status = 0;
+
+       dprintk(1, "\n");
+
+       static s32 QE_SN[] = {
+               51,             /* QPSK 1/2 */
+               69,             /* QPSK 2/3 */
+               79,             /* QPSK 3/4 */
+               89,             /* QPSK 5/6 */
+               97,             /* QPSK 7/8 */
+               108,            /* 16-QAM 1/2 */
+               131,            /* 16-QAM 2/3 */
+               146,            /* 16-QAM 3/4 */
+               156,            /* 16-QAM 5/6 */
+               160,            /* 16-QAM 7/8 */
+               165,            /* 64-QAM 1/2 */
+               187,            /* 64-QAM 2/3 */
+               202,            /* 64-QAM 3/4 */
+               216,            /* 64-QAM 5/6 */
+               225,            /* 64-QAM 7/8 */
+       };
+
+       *pQuality = 0;
+
+       do {
+               s32 SignalToNoise = 0;
+               u16 Constellation = 0;
+               u16 CodeRate = 0;
+               u32 SignalToNoiseRel;
+               u32 BERQuality;
+
+               status = GetDVBTSignalToNoise(state, &SignalToNoise);
+               if (status < 0)
+                       break;
+               status = read16(state, OFDM_EQ_TOP_TD_TPS_CONST__A, &Constellation);
+               if (status < 0)
+                       break;
+               Constellation &= OFDM_EQ_TOP_TD_TPS_CONST__M;
+
+               status = read16(state, OFDM_EQ_TOP_TD_TPS_CODE_HP__A, &CodeRate);
+               if (status < 0)
+                       break;
+               CodeRate &= OFDM_EQ_TOP_TD_TPS_CODE_HP__M;
+
+               if (Constellation > OFDM_EQ_TOP_TD_TPS_CONST_64QAM ||
+                   CodeRate > OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8)
+                       break;
+               SignalToNoiseRel = SignalToNoise -
+                   QE_SN[Constellation * 5 + CodeRate];
+               BERQuality = 100;
+
+               if (SignalToNoiseRel < -70)
+                       *pQuality = 0;
+               else if (SignalToNoiseRel < 30)
+                       *pQuality = ((SignalToNoiseRel + 70) *
+                                    BERQuality) / 100;
+               else
+                       *pQuality = BERQuality;
+       } while (0);
+       return 0;
+};
+
+static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality)
+{
+       int status = 0;
+       *pQuality = 0;
+
+       dprintk(1, "\n");
+
+       do {
+               u32 SignalToNoise = 0;
+               u32 BERQuality = 100;
+               u32 SignalToNoiseRel = 0;
+
+               status = GetQAMSignalToNoise(state, &SignalToNoise);
+               if (status < 0)
+                       break;
+
+               switch (state->param.u.qam.modulation) {
+               case QAM_16:
+                       SignalToNoiseRel = SignalToNoise - 200;
+                       break;
+               case QAM_32:
+                       SignalToNoiseRel = SignalToNoise - 230;
+                       break;  /* Not in NorDig */
+               case QAM_64:
+                       SignalToNoiseRel = SignalToNoise - 260;
+                       break;
+               case QAM_128:
+                       SignalToNoiseRel = SignalToNoise - 290;
+                       break;
+               default:
+               case QAM_256:
+                       SignalToNoiseRel = SignalToNoise - 320;
+                       break;
+               }
+
+               if (SignalToNoiseRel < -70)
+                       *pQuality = 0;
+               else if (SignalToNoiseRel < 30)
+                       *pQuality = ((SignalToNoiseRel + 70) *
+                                    BERQuality) / 100;
+               else
+                       *pQuality = BERQuality;
+       } while (0);
+
+       return status;
+}
+
+static int GetQuality(struct drxk_state *state, s32 *pQuality)
+{
+       dprintk(1, "\n");
+
+       switch (state->m_OperationMode) {
+       case OM_DVBT:
+               return GetDVBTQuality(state, pQuality);
+       case OM_QAM_ITU_A:
+               return GetDVBCQuality(state, pQuality);
+       default:
+               break;
+       }
+
+       return 0;
+}
+#endif
+
+/* Free data ram in SIO HI */
+#define SIO_HI_RA_RAM_USR_BEGIN__A 0x420040
+#define SIO_HI_RA_RAM_USR_END__A   0x420060
+
+#define DRXK_HI_ATOMIC_BUF_START (SIO_HI_RA_RAM_USR_BEGIN__A)
+#define DRXK_HI_ATOMIC_BUF_END   (SIO_HI_RA_RAM_USR_BEGIN__A + 7)
+#define DRXK_HI_ATOMIC_READ      SIO_HI_RA_RAM_PAR_3_ACP_RW_READ
+#define DRXK_HI_ATOMIC_WRITE     SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE
+
+#define DRXDAP_FASI_ADDR2BLOCK(addr)  (((addr) >> 22) & 0x3F)
+#define DRXDAP_FASI_ADDR2BANK(addr)   (((addr) >> 16) & 0x3F)
+#define DRXDAP_FASI_ADDR2OFFSET(addr) ((addr) & 0x7FFF)
+
+static int ConfigureI2CBridge(struct drxk_state *state, bool bEnableBridge)
+{
+       int status = -EINVAL;
+
+       dprintk(1, "\n");
+
+       if (state->m_DrxkState == DRXK_UNINITIALIZED)
+               goto error;
+       if (state->m_DrxkState == DRXK_POWERED_DOWN)
+               goto error;
+
+       if (state->no_i2c_bridge)
+               return 0;
+
+       status = write16(state, SIO_HI_RA_RAM_PAR_1__A, SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY);
+       if (status < 0)
+               goto error;
+       if (bEnableBridge) {
+               status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED);
+               if (status < 0)
+                       goto error;
+       } else {
+               status = write16(state, SIO_HI_RA_RAM_PAR_2__A, SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN);
+               if (status < 0)
+                       goto error;
+       }
+
+       status = HI_Command(state, SIO_HI_RA_RAM_CMD_BRDCTRL, 0);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SetPreSaw(struct drxk_state *state,
+                    struct SCfgPreSaw *pPreSawCfg)
+{
+       int status = -EINVAL;
+
+       dprintk(1, "\n");
+
+       if ((pPreSawCfg == NULL)
+           || (pPreSawCfg->reference > IQM_AF_PDREF__M))
+               goto error;
+
+       status = write16(state, IQM_AF_PDREF__A, pPreSawCfg->reference);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int BLDirectCmd(struct drxk_state *state, u32 targetAddr,
+                      u16 romOffset, u16 nrOfElements, u32 timeOut)
+{
+       u16 blStatus = 0;
+       u16 offset = (u16) ((targetAddr >> 0) & 0x00FFFF);
+       u16 blockbank = (u16) ((targetAddr >> 16) & 0x000FFF);
+       int status;
+       unsigned long end;
+
+       dprintk(1, "\n");
+
+       mutex_lock(&state->mutex);
+       status = write16(state, SIO_BL_MODE__A, SIO_BL_MODE_DIRECT);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_TGT_HDR__A, blockbank);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_TGT_ADDR__A, offset);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_SRC_ADDR__A, romOffset);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_SRC_LEN__A, nrOfElements);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_BL_ENABLE__A, SIO_BL_ENABLE_ON);
+       if (status < 0)
+               goto error;
+
+       end = jiffies + msecs_to_jiffies(timeOut);
+       do {
+               status = read16(state, SIO_BL_STATUS__A, &blStatus);
+               if (status < 0)
+                       goto error;
+       } while ((blStatus == 0x1) && time_is_after_jiffies(end));
+       if (blStatus == 0x1) {
+               printk(KERN_ERR "drxk: SIO not ready\n");
+               status = -EINVAL;
+               goto error2;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+error2:
+       mutex_unlock(&state->mutex);
+       return status;
+
+}
+
+static int ADCSyncMeasurement(struct drxk_state *state, u16 *count)
+{
+       u16 data = 0;
+       int status;
+
+       dprintk(1, "\n");
+
+       /* Start measurement */
+       status = write16(state, IQM_AF_COMM_EXEC__A, IQM_AF_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_START_LOCK__A, 1);
+       if (status < 0)
+               goto error;
+
+       *count = 0;
+       status = read16(state, IQM_AF_PHASE0__A, &data);
+       if (status < 0)
+               goto error;
+       if (data == 127)
+               *count = *count + 1;
+       status = read16(state, IQM_AF_PHASE1__A, &data);
+       if (status < 0)
+               goto error;
+       if (data == 127)
+               *count = *count + 1;
+       status = read16(state, IQM_AF_PHASE2__A, &data);
+       if (status < 0)
+               goto error;
+       if (data == 127)
+               *count = *count + 1;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int ADCSynchronization(struct drxk_state *state)
+{
+       u16 count = 0;
+       int status;
+
+       dprintk(1, "\n");
+
+       status = ADCSyncMeasurement(state, &count);
+       if (status < 0)
+               goto error;
+
+       if (count == 1) {
+               /* Try sampling on a diffrent edge */
+               u16 clkNeg = 0;
+
+               status = read16(state, IQM_AF_CLKNEG__A, &clkNeg);
+               if (status < 0)
+                       goto error;
+               if ((clkNeg | IQM_AF_CLKNEG_CLKNEGDATA__M) ==
+                       IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS) {
+                       clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
+                       clkNeg |=
+                               IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG;
+               } else {
+                       clkNeg &= (~(IQM_AF_CLKNEG_CLKNEGDATA__M));
+                       clkNeg |=
+                               IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS;
+               }
+               status = write16(state, IQM_AF_CLKNEG__A, clkNeg);
+               if (status < 0)
+                       goto error;
+               status = ADCSyncMeasurement(state, &count);
+               if (status < 0)
+                       goto error;
+       }
+
+       if (count < 2)
+               status = -EINVAL;
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SetFrequencyShifter(struct drxk_state *state,
+                              u16 intermediateFreqkHz,
+                              s32 tunerFreqOffset, bool isDTV)
+{
+       bool selectPosImage = false;
+       u32 rfFreqResidual = tunerFreqOffset;
+       u32 fmFrequencyShift = 0;
+       bool tunerMirror = !state->m_bMirrorFreqSpect;
+       u32 adcFreq;
+       bool adcFlip;
+       int status;
+       u32 ifFreqActual;
+       u32 samplingFrequency = (u32) (state->m_sysClockFreq / 3);
+       u32 frequencyShift;
+       bool imageToSelect;
+
+       dprintk(1, "\n");
+
+       /*
+          Program frequency shifter
+          No need to account for mirroring on RF
+        */
+       if (isDTV) {
+               if ((state->m_OperationMode == OM_QAM_ITU_A) ||
+                   (state->m_OperationMode == OM_QAM_ITU_C) ||
+                   (state->m_OperationMode == OM_DVBT))
+                       selectPosImage = true;
+               else
+                       selectPosImage = false;
+       }
+       if (tunerMirror)
+               /* tuner doesn't mirror */
+               ifFreqActual = intermediateFreqkHz +
+                   rfFreqResidual + fmFrequencyShift;
+       else
+               /* tuner mirrors */
+               ifFreqActual = intermediateFreqkHz -
+                   rfFreqResidual - fmFrequencyShift;
+       if (ifFreqActual > samplingFrequency / 2) {
+               /* adc mirrors */
+               adcFreq = samplingFrequency - ifFreqActual;
+               adcFlip = true;
+       } else {
+               /* adc doesn't mirror */
+               adcFreq = ifFreqActual;
+               adcFlip = false;
+       }
+
+       frequencyShift = adcFreq;
+       imageToSelect = state->m_rfmirror ^ tunerMirror ^
+           adcFlip ^ selectPosImage;
+       state->m_IqmFsRateOfs =
+           Frac28a((frequencyShift), samplingFrequency);
+
+       if (imageToSelect)
+               state->m_IqmFsRateOfs = ~state->m_IqmFsRateOfs + 1;
+
+       /* Program frequency shifter with tuner offset compensation */
+       /* frequencyShift += tunerFreqOffset; TODO */
+       status = write32(state, IQM_FS_RATE_OFS_LO__A,
+                        state->m_IqmFsRateOfs);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int InitAGC(struct drxk_state *state, bool isDTV)
+{
+       u16 ingainTgt = 0;
+       u16 ingainTgtMin = 0;
+       u16 ingainTgtMax = 0;
+       u16 clpCyclen = 0;
+       u16 clpSumMin = 0;
+       u16 clpDirTo = 0;
+       u16 snsSumMin = 0;
+       u16 snsSumMax = 0;
+       u16 clpSumMax = 0;
+       u16 snsDirTo = 0;
+       u16 kiInnergainMin = 0;
+       u16 ifIaccuHiTgt = 0;
+       u16 ifIaccuHiTgtMin = 0;
+       u16 ifIaccuHiTgtMax = 0;
+       u16 data = 0;
+       u16 fastClpCtrlDelay = 0;
+       u16 clpCtrlMode = 0;
+       int status = 0;
+
+       dprintk(1, "\n");
+
+       /* Common settings */
+       snsSumMax = 1023;
+       ifIaccuHiTgtMin = 2047;
+       clpCyclen = 500;
+       clpSumMax = 1023;
+
+       /* AGCInit() not available for DVBT; init done in microcode */
+       if (!IsQAM(state)) {
+               printk(KERN_ERR "drxk: %s: mode %d is not DVB-C\n", __func__, state->m_OperationMode);
+               return -EINVAL;
+       }
+
+       /* FIXME: Analog TV AGC require different settings */
+
+       /* Standard specific settings */
+       clpSumMin = 8;
+       clpDirTo = (u16) -9;
+       clpCtrlMode = 0;
+       snsSumMin = 8;
+       snsDirTo = (u16) -9;
+       kiInnergainMin = (u16) -1030;
+       ifIaccuHiTgtMax = 0x2380;
+       ifIaccuHiTgt = 0x2380;
+       ingainTgtMin = 0x0511;
+       ingainTgt = 0x0511;
+       ingainTgtMax = 5119;
+       fastClpCtrlDelay = state->m_qamIfAgcCfg.FastClipCtrlDelay;
+
+       status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, fastClpCtrlDelay);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_AGC_CLP_CTRL_MODE__A, clpCtrlMode);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT__A, ingainTgt);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, ingainTgtMin);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, ingainTgtMax);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A, ifIaccuHiTgtMin);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, ifIaccuHiTgtMax);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_LO__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_RF_IACCU_HI__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_RF_IACCU_LO__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_SUM_MAX__A, clpSumMax);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_SUM_MAX__A, snsSumMax);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_AGC_KI_INNERGAIN_MIN__A, kiInnergainMin);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT__A, ifIaccuHiTgt);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_CYCLEN__A, clpCyclen);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_AGC_RF_SNS_DEV_MAX__A, 1023);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_RF_SNS_DEV_MIN__A, (u16) -1023);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A, 50);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_AGC_KI_MAXMINGAIN_TH__A, 20);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_SUM_MIN__A, clpSumMin);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_SUM_MIN__A, snsSumMin);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_DIR_TO__A, clpDirTo);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_DIR_TO__A, snsDirTo);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_KI_MINGAIN__A, 0x7fff);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_KI_MAXGAIN__A, 0x0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_KI_MIN__A, 0x0117);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_KI_MAX__A, 0x0657);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_SUM__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_CYCCNT__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_DIR_WD__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_CLP_DIR_STP__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_SUM__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_CYCCNT__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_DIR_WD__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_DIR_STP__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_SNS_CYCLEN__A, 500);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_KI_CYCLEN__A, 500);
+       if (status < 0)
+               goto error;
+
+       /* Initialize inner-loop KI gain factors */
+       status = read16(state, SCU_RAM_AGC_KI__A, &data);
+       if (status < 0)
+               goto error;
+
+       data = 0x0657;
+       data &= ~SCU_RAM_AGC_KI_RF__M;
+       data |= (DRXK_KI_RAGC_QAM << SCU_RAM_AGC_KI_RF__B);
+       data &= ~SCU_RAM_AGC_KI_IF__M;
+       data |= (DRXK_KI_IAGC_QAM << SCU_RAM_AGC_KI_IF__B);
+
+       status = write16(state, SCU_RAM_AGC_KI__A, data);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int DVBTQAMGetAccPktErr(struct drxk_state *state, u16 *packetErr)
+{
+       int status;
+
+       dprintk(1, "\n");
+       if (packetErr == NULL)
+               status = write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0);
+       else
+               status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, packetErr);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int DVBTScCommand(struct drxk_state *state,
+                        u16 cmd, u16 subcmd,
+                        u16 param0, u16 param1, u16 param2,
+                        u16 param3, u16 param4)
+{
+       u16 curCmd = 0;
+       u16 errCode = 0;
+       u16 retryCnt = 0;
+       u16 scExec = 0;
+       int status;
+
+       dprintk(1, "\n");
+       status = read16(state, OFDM_SC_COMM_EXEC__A, &scExec);
+       if (scExec != 1) {
+               /* SC is not running */
+               status = -EINVAL;
+       }
+       if (status < 0)
+               goto error;
+
+       /* Wait until sc is ready to receive command */
+       retryCnt = 0;
+       do {
+               msleep(1);
+               status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
+               retryCnt++;
+       } while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
+       if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
+               goto error;
+
+       /* Write sub-command */
+       switch (cmd) {
+               /* All commands using sub-cmd */
+       case OFDM_SC_RA_RAM_CMD_PROC_START:
+       case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
+       case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
+               status = write16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, subcmd);
+               if (status < 0)
+                       goto error;
+               break;
+       default:
+               /* Do nothing */
+               break;
+       }
+
+       /* Write needed parameters and the command */
+       switch (cmd) {
+               /* All commands using 5 parameters */
+               /* All commands using 4 parameters */
+               /* All commands using 3 parameters */
+               /* All commands using 2 parameters */
+       case OFDM_SC_RA_RAM_CMD_PROC_START:
+       case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
+       case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
+               status = write16(state, OFDM_SC_RA_RAM_PARAM1__A, param1);
+               /* All commands using 1 parameters */
+       case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
+       case OFDM_SC_RA_RAM_CMD_USER_IO:
+               status = write16(state, OFDM_SC_RA_RAM_PARAM0__A, param0);
+               /* All commands using 0 parameters */
+       case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
+       case OFDM_SC_RA_RAM_CMD_NULL:
+               /* Write command */
+               status = write16(state, OFDM_SC_RA_RAM_CMD__A, cmd);
+               break;
+       default:
+               /* Unknown command */
+               status = -EINVAL;
+       }
+       if (status < 0)
+               goto error;
+
+       /* Wait until sc is ready processing command */
+       retryCnt = 0;
+       do {
+               msleep(1);
+               status = read16(state, OFDM_SC_RA_RAM_CMD__A, &curCmd);
+               retryCnt++;
+       } while ((curCmd != 0) && (retryCnt < DRXK_MAX_RETRIES));
+       if (retryCnt >= DRXK_MAX_RETRIES && (status < 0))
+               goto error;
+
+       /* Check for illegal cmd */
+       status = read16(state, OFDM_SC_RA_RAM_CMD_ADDR__A, &errCode);
+       if (errCode == 0xFFFF) {
+               /* illegal command */
+               status = -EINVAL;
+       }
+       if (status < 0)
+               goto error;
+
+       /* Retreive results parameters from SC */
+       switch (cmd) {
+               /* All commands yielding 5 results */
+               /* All commands yielding 4 results */
+               /* All commands yielding 3 results */
+               /* All commands yielding 2 results */
+               /* All commands yielding 1 result */
+       case OFDM_SC_RA_RAM_CMD_USER_IO:
+       case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
+               status = read16(state, OFDM_SC_RA_RAM_PARAM0__A, &(param0));
+               /* All commands yielding 0 results */
+       case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
+       case OFDM_SC_RA_RAM_CMD_SET_TIMER:
+       case OFDM_SC_RA_RAM_CMD_PROC_START:
+       case OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM:
+       case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
+       case OFDM_SC_RA_RAM_CMD_NULL:
+               break;
+       default:
+               /* Unknown command */
+               status = -EINVAL;
+               break;
+       }                       /* switch (cmd->cmd) */
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int PowerUpDVBT(struct drxk_state *state)
+{
+       enum DRXPowerMode powerMode = DRX_POWER_UP;
+       int status;
+
+       dprintk(1, "\n");
+       status = CtrlPowerMode(state, &powerMode);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int DVBTCtrlSetIncEnable(struct drxk_state *state, bool *enabled)
+{
+       int status;
+
+       dprintk(1, "\n");
+       if (*enabled == true)
+               status = write16(state, IQM_CF_BYPASSDET__A, 0);
+       else
+               status = write16(state, IQM_CF_BYPASSDET__A, 1);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+#define DEFAULT_FR_THRES_8K     4000
+static int DVBTCtrlSetFrEnable(struct drxk_state *state, bool *enabled)
+{
+
+       int status;
+
+       dprintk(1, "\n");
+       if (*enabled == true) {
+               /* write mask to 1 */
+               status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A,
+                                  DEFAULT_FR_THRES_8K);
+       } else {
+               /* write mask to 0 */
+               status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A, 0);
+       }
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int DVBTCtrlSetEchoThreshold(struct drxk_state *state,
+                                   struct DRXKCfgDvbtEchoThres_t *echoThres)
+{
+       u16 data = 0;
+       int status;
+
+       dprintk(1, "\n");
+       status = read16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, &data);
+       if (status < 0)
+               goto error;
+
+       switch (echoThres->fftMode) {
+       case DRX_FFTMODE_2K:
+               data &= ~OFDM_SC_RA_RAM_ECHO_THRES_2K__M;
+               data |= ((echoThres->threshold <<
+                       OFDM_SC_RA_RAM_ECHO_THRES_2K__B)
+                       & (OFDM_SC_RA_RAM_ECHO_THRES_2K__M));
+               break;
+       case DRX_FFTMODE_8K:
+               data &= ~OFDM_SC_RA_RAM_ECHO_THRES_8K__M;
+               data |= ((echoThres->threshold <<
+                       OFDM_SC_RA_RAM_ECHO_THRES_8K__B)
+                       & (OFDM_SC_RA_RAM_ECHO_THRES_8K__M));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       status = write16(state, OFDM_SC_RA_RAM_ECHO_THRES__A, data);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int DVBTCtrlSetSqiSpeed(struct drxk_state *state,
+                              enum DRXKCfgDvbtSqiSpeed *speed)
+{
+       int status = -EINVAL;
+
+       dprintk(1, "\n");
+
+       switch (*speed) {
+       case DRXK_DVBT_SQI_SPEED_FAST:
+       case DRXK_DVBT_SQI_SPEED_MEDIUM:
+       case DRXK_DVBT_SQI_SPEED_SLOW:
+               break;
+       default:
+               goto error;
+       }
+       status = write16(state, SCU_RAM_FEC_PRE_RS_BER_FILTER_SH__A,
+                          (u16) *speed);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Activate DVBT specific presets
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+*
+* Called in DVBTSetStandard
+*
+*/
+static int DVBTActivatePresets(struct drxk_state *state)
+{
+       int status;
+       bool setincenable = false;
+       bool setfrenable = true;
+
+       struct DRXKCfgDvbtEchoThres_t echoThres2k = { 0, DRX_FFTMODE_2K };
+       struct DRXKCfgDvbtEchoThres_t echoThres8k = { 0, DRX_FFTMODE_8K };
+
+       dprintk(1, "\n");
+       status = DVBTCtrlSetIncEnable(state, &setincenable);
+       if (status < 0)
+               goto error;
+       status = DVBTCtrlSetFrEnable(state, &setfrenable);
+       if (status < 0)
+               goto error;
+       status = DVBTCtrlSetEchoThreshold(state, &echoThres2k);
+       if (status < 0)
+               goto error;
+       status = DVBTCtrlSetEchoThreshold(state, &echoThres8k);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_AGC_INGAIN_TGT_MAX__A, state->m_dvbtIfAgcCfg.IngainTgtMax);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Initialize channelswitch-independent settings for DVBT.
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+*
+* For ROM code channel filter taps are loaded from the bootloader. For microcode
+* the DVB-T taps from the drxk_filters.h are used.
+*/
+static int SetDVBTStandard(struct drxk_state *state,
+                          enum OperationMode oMode)
+{
+       u16 cmdResult = 0;
+       u16 data = 0;
+       int status;
+
+       dprintk(1, "\n");
+
+       PowerUpDVBT(state);
+       /* added antenna switch */
+       SwitchAntennaToDVBT(state);
+       /* send OFDM reset command */
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+       if (status < 0)
+               goto error;
+
+       /* send OFDM setenv command */
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 0, NULL, 1, &cmdResult);
+       if (status < 0)
+               goto error;
+
+       /* reset datapath for OFDM, processors first */
+       status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
+       if (status < 0)
+               goto error;
+
+       /* IQM setup */
+       /* synchronize on ofdstate->m_festart */
+       status = write16(state, IQM_AF_UPD_SEL__A, 1);
+       if (status < 0)
+               goto error;
+       /* window size for clipping ADC detection */
+       status = write16(state, IQM_AF_CLP_LEN__A, 0);
+       if (status < 0)
+               goto error;
+       /* window size for for sense pre-SAW detection */
+       status = write16(state, IQM_AF_SNS_LEN__A, 0);
+       if (status < 0)
+               goto error;
+       /* sense threshold for sense pre-SAW detection */
+       status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC);
+       if (status < 0)
+               goto error;
+       status = SetIqmAf(state, true);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_AF_AGC_RF__A, 0);
+       if (status < 0)
+               goto error;
+
+       /* Impulse noise cruncher setup */
+       status = write16(state, IQM_AF_INC_LCT__A, 0);  /* crunch in IQM_CF */
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_DET_LCT__A, 0);  /* detect in IQM_CF */
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_WND_LEN__A, 3);  /* peak detector window length */
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_RC_STRETCH__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_OUT_ENA__A, 0x4);        /* enable output 2 */
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_DS_ENA__A, 0x4); /* decimate output 2 */
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_SCALE__A, 1600);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_SCALE_SH__A, 0);
+       if (status < 0)
+               goto error;
+
+       /* virtual clipping threshold for clipping ADC detection */
+       status = write16(state, IQM_AF_CLP_TH__A, 448);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_DATATH__A, 495); /* crunching threshold */
+       if (status < 0)
+               goto error;
+
+       status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_DVBT, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_CF_PKDTH__A, 2);    /* peak detector threshold */
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_POW_MEAS_LEN__A, 2);
+       if (status < 0)
+               goto error;
+       /* enable power measurement interrupt */
+       status = write16(state, IQM_CF_COMM_INT_MSK__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_ACTIVE);
+       if (status < 0)
+               goto error;
+
+       /* IQM will not be reset from here, sync ADC and update/init AGC */
+       status = ADCSynchronization(state);
+       if (status < 0)
+               goto error;
+       status = SetPreSaw(state, &state->m_dvbtPreSawCfg);
+       if (status < 0)
+               goto error;
+
+       /* Halt SCU to enable safe non-atomic accesses */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+       if (status < 0)
+               goto error;
+
+       status = SetAgcRf(state, &state->m_dvbtRfAgcCfg, true);
+       if (status < 0)
+               goto error;
+       status = SetAgcIf(state, &state->m_dvbtIfAgcCfg, true);
+       if (status < 0)
+               goto error;
+
+       /* Set Noise Estimation notch width and enable DC fix */
+       status = read16(state, OFDM_SC_RA_RAM_CONFIG__A, &data);
+       if (status < 0)
+               goto error;
+       data |= OFDM_SC_RA_RAM_CONFIG_NE_FIX_ENABLE__M;
+       status = write16(state, OFDM_SC_RA_RAM_CONFIG__A, data);
+       if (status < 0)
+               goto error;
+
+       /* Activate SCU to enable SCU commands */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+
+       if (!state->m_DRXK_A3_ROM_CODE) {
+               /* AGCInit() is not done for DVBT, so set agcFastClipCtrlDelay  */
+               status = write16(state, SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A, state->m_dvbtIfAgcCfg.FastClipCtrlDelay);
+               if (status < 0)
+                       goto error;
+       }
+
+       /* OFDM_SC setup */
+#ifdef COMPILE_FOR_NONRT
+       status = write16(state, OFDM_SC_RA_RAM_BE_OPT_DELAY__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, OFDM_SC_RA_RAM_BE_OPT_INIT_DELAY__A, 2);
+       if (status < 0)
+               goto error;
+#endif
+
+       /* FEC setup */
+       status = write16(state, FEC_DI_INPUT_CTL__A, 1);        /* OFDM input */
+       if (status < 0)
+               goto error;
+
+
+#ifdef COMPILE_FOR_NONRT
+       status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, 0x400);
+       if (status < 0)
+               goto error;
+#else
+       status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, 0x1000);
+       if (status < 0)
+               goto error;
+#endif
+       status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, 0x0001);
+       if (status < 0)
+               goto error;
+
+       /* Setup MPEG bus */
+       status = MPEGTSDtoSetup(state, OM_DVBT);
+       if (status < 0)
+               goto error;
+       /* Set DVBT Presets */
+       status = DVBTActivatePresets(state);
+       if (status < 0)
+               goto error;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+/**
+* \brief Start dvbt demodulating for channel.
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+*/
+static int DVBTStart(struct drxk_state *state)
+{
+       u16 param1;
+       int status;
+       /* DRXKOfdmScCmd_t scCmd; */
+
+       dprintk(1, "\n");
+       /* Start correct processes to get in lock */
+       /* DRXK: OFDM_SC_RA_RAM_PROC_LOCKTRACK is no longer in mapfile! */
+       param1 = OFDM_SC_RA_RAM_LOCKTRACK_MIN;
+       status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_PROC_START, 0, OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M, param1, 0, 0, 0);
+       if (status < 0)
+               goto error;
+       /* Start FEC OC */
+       status = MPEGTSStart(state);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+
+/*============================================================================*/
+
+/**
+* \brief Set up dvbt demodulator for channel.
+* \param demod instance of demodulator.
+* \return DRXStatus_t.
+* // original DVBTSetChannel()
+*/
+static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz,
+                  s32 tunerFreqOffset)
+{
+       u16 cmdResult = 0;
+       u16 transmissionParams = 0;
+       u16 operationMode = 0;
+       u32 iqmRcRateOfs = 0;
+       u32 bandwidth = 0;
+       u16 param1;
+       int status;
+
+       dprintk(1, "IF =%d, TFO = %d\n", IntermediateFreqkHz, tunerFreqOffset);
+
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+       if (status < 0)
+               goto error;
+
+       /* Halt SCU to enable safe non-atomic accesses */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+       if (status < 0)
+               goto error;
+
+       /* Stop processors */
+       status = write16(state, OFDM_SC_COMM_EXEC__A, OFDM_SC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, OFDM_LC_COMM_EXEC__A, OFDM_LC_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+
+       /* Mandatory fix, always stop CP, required to set spl offset back to
+               hardware default (is set to 0 by ucode during pilot detection */
+       status = write16(state, OFDM_CP_COMM_EXEC__A, OFDM_CP_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+
+       /*== Write channel settings to device =====================================*/
+
+       /* mode */
+       switch (state->param.u.ofdm.transmission_mode) {
+       case TRANSMISSION_MODE_AUTO:
+       default:
+               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
+               /* fall through , try first guess DRX_FFTMODE_8K */
+       case TRANSMISSION_MODE_8K:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
+               break;
+       case TRANSMISSION_MODE_2K:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_2K;
+               break;
+       }
+
+       /* guard */
+       switch (state->param.u.ofdm.guard_interval) {
+       default:
+       case GUARD_INTERVAL_AUTO:
+               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
+               /* fall through , try first guess DRX_GUARD_1DIV4 */
+       case GUARD_INTERVAL_1_4:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
+               break;
+       case GUARD_INTERVAL_1_32:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_32;
+               break;
+       case GUARD_INTERVAL_1_16:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_16;
+               break;
+       case GUARD_INTERVAL_1_8:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_8;
+               break;
+       }
+
+       /* hierarchy */
+       switch (state->param.u.ofdm.hierarchy_information) {
+       case HIERARCHY_AUTO:
+       case HIERARCHY_NONE:
+       default:
+               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
+               /* fall through , try first guess SC_RA_RAM_OP_PARAM_HIER_NO */
+               /* transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */
+               /* break; */
+       case HIERARCHY_1:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
+               break;
+       case HIERARCHY_2:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A2;
+               break;
+       case HIERARCHY_4:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A4;
+               break;
+       }
+
+
+       /* constellation */
+       switch (state->param.u.ofdm.constellation) {
+       case QAM_AUTO:
+       default:
+               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
+               /* fall through , try first guess DRX_CONSTELLATION_QAM64 */
+       case QAM_64:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
+               break;
+       case QPSK:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK;
+               break;
+       case QAM_16:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16;
+               break;
+       }
+#if 0
+       /* No hierachical channels support in BDA */
+       /* Priority (only for hierarchical channels) */
+       switch (channel->priority) {
+       case DRX_PRIORITY_LOW:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO;
+               WR16(devAddr, OFDM_EC_SB_PRIOR__A,
+                       OFDM_EC_SB_PRIOR_LO);
+               break;
+       case DRX_PRIORITY_HIGH:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
+               WR16(devAddr, OFDM_EC_SB_PRIOR__A,
+                       OFDM_EC_SB_PRIOR_HI));
+               break;
+       case DRX_PRIORITY_UNKNOWN:      /* fall through */
+       default:
+               status = -EINVAL;
+               goto error;
+       }
+#else
+       /* Set Priorty high */
+       transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI;
+       status = write16(state, OFDM_EC_SB_PRIOR__A, OFDM_EC_SB_PRIOR_HI);
+       if (status < 0)
+               goto error;
+#endif
+
+       /* coderate */
+       switch (state->param.u.ofdm.code_rate_HP) {
+       case FEC_AUTO:
+       default:
+               operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
+               /* fall through , try first guess DRX_CODERATE_2DIV3 */
+       case FEC_2_3:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
+               break;
+       case FEC_1_2:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2;
+               break;
+       case FEC_3_4:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4;
+               break;
+       case FEC_5_6:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6;
+               break;
+       case FEC_7_8:
+               transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8;
+               break;
+       }
+
+       /* SAW filter selection: normaly not necesarry, but if wanted
+               the application can select a SAW filter via the driver by using UIOs */
+       /* First determine real bandwidth (Hz) */
+       /* Also set delay for impulse noise cruncher */
+       /* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed
+               by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC
+               functions */
+       switch (state->param.u.ofdm.bandwidth) {
+       case BANDWIDTH_AUTO:
+       case BANDWIDTH_8_MHZ:
+               bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ;
+               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052);
+               if (status < 0)
+                       goto error;
+               /* cochannel protection for PAL 8 MHz */
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 7);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 7);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 7);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+               if (status < 0)
+                       goto error;
+               break;
+       case BANDWIDTH_7_MHZ:
+               bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ;
+               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491);
+               if (status < 0)
+                       goto error;
+               /* cochannel protection for PAL 7 MHz */
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 8);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 8);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 4);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+               if (status < 0)
+                       goto error;
+               break;
+       case BANDWIDTH_6_MHZ:
+               bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ;
+               status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073);
+               if (status < 0)
+                       goto error;
+               /* cochannel protection for NTSC 6 MHz */
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A, 19);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A, 19);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A, 14);
+               if (status < 0)
+                       goto error;
+               status = write16(state, OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A, 1);
+               if (status < 0)
+                       goto error;
+               break;
+       default:
+               status = -EINVAL;
+               goto error;
+       }
+
+       if (iqmRcRateOfs == 0) {
+               /* Now compute IQM_RC_RATE_OFS
+                       (((SysFreq/BandWidth)/2)/2) -1) * 2^23)
+                       =>
+                       ((SysFreq / BandWidth) * (2^21)) - (2^23)
+                       */
+               /* (SysFreq / BandWidth) * (2^28)  */
+               /* assert (MAX(sysClk)/MIN(bandwidth) < 16)
+                       => assert(MAX(sysClk) < 16*MIN(bandwidth))
+                       => assert(109714272 > 48000000) = true so Frac 28 can be used  */
+               iqmRcRateOfs = Frac28a((u32)
+                                       ((state->m_sysClockFreq *
+                                               1000) / 3), bandwidth);
+               /* (SysFreq / BandWidth) * (2^21), rounding before truncating  */
+               if ((iqmRcRateOfs & 0x7fL) >= 0x40)
+                       iqmRcRateOfs += 0x80L;
+               iqmRcRateOfs = iqmRcRateOfs >> 7;
+               /* ((SysFreq / BandWidth) * (2^21)) - (2^23)  */
+               iqmRcRateOfs = iqmRcRateOfs - (1 << 23);
+       }
+
+       iqmRcRateOfs &=
+               ((((u32) IQM_RC_RATE_OFS_HI__M) <<
+               IQM_RC_RATE_OFS_LO__W) | IQM_RC_RATE_OFS_LO__M);
+       status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRateOfs);
+       if (status < 0)
+               goto error;
+
+       /* Bandwidth setting done */
+
+#if 0
+       status = DVBTSetFrequencyShift(demod, channel, tunerOffset);
+       if (status < 0)
+               goto error;
+#endif
+       status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
+       if (status < 0)
+               goto error;
+
+       /*== Start SC, write channel settings to SC ===============================*/
+
+       /* Activate SCU to enable SCU commands */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+
+       /* Enable SC after setting all other parameters */
+       status = write16(state, OFDM_SC_COMM_STATE__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, OFDM_SC_COMM_EXEC__A, 1);
+       if (status < 0)
+               goto error;
+
+
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_OFDM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
+       if (status < 0)
+               goto error;
+
+       /* Write SC parameter registers, set all AUTO flags in operation mode */
+       param1 = (OFDM_SC_RA_RAM_OP_AUTO_MODE__M |
+                       OFDM_SC_RA_RAM_OP_AUTO_GUARD__M |
+                       OFDM_SC_RA_RAM_OP_AUTO_CONST__M |
+                       OFDM_SC_RA_RAM_OP_AUTO_HIER__M |
+                       OFDM_SC_RA_RAM_OP_AUTO_RATE__M);
+       status = DVBTScCommand(state, OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM,
+                               0, transmissionParams, param1, 0, 0, 0);
+       if (status < 0)
+               goto error;
+
+       if (!state->m_DRXK_A3_ROM_CODE)
+               status = DVBTCtrlSetSqiSpeed(state, &state->m_sqiSpeed);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+
+/*============================================================================*/
+
+/**
+* \brief Retreive lock status .
+* \param demod    Pointer to demodulator instance.
+* \param lockStat Pointer to lock status structure.
+* \return DRXStatus_t.
+*
+*/
+static int GetDVBTLockStatus(struct drxk_state *state, u32 *pLockStatus)
+{
+       int status;
+       const u16 mpeg_lock_mask = (OFDM_SC_RA_RAM_LOCK_MPEG__M |
+                                   OFDM_SC_RA_RAM_LOCK_FEC__M);
+       const u16 fec_lock_mask = (OFDM_SC_RA_RAM_LOCK_FEC__M);
+       const u16 demod_lock_mask = OFDM_SC_RA_RAM_LOCK_DEMOD__M;
+
+       u16 ScRaRamLock = 0;
+       u16 ScCommExec = 0;
+
+       dprintk(1, "\n");
+
+       *pLockStatus = NOT_LOCKED;
+       /* driver 0.9.0 */
+       /* Check if SC is running */
+       status = read16(state, OFDM_SC_COMM_EXEC__A, &ScCommExec);
+       if (status < 0)
+               goto end;
+       if (ScCommExec == OFDM_SC_COMM_EXEC_STOP)
+               goto end;
+
+       status = read16(state, OFDM_SC_RA_RAM_LOCK__A, &ScRaRamLock);
+       if (status < 0)
+               goto end;
+
+       if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask)
+               *pLockStatus = MPEG_LOCK;
+       else if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
+               *pLockStatus = FEC_LOCK;
+       else if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
+               *pLockStatus = DEMOD_LOCK;
+       else if (ScRaRamLock & OFDM_SC_RA_RAM_LOCK_NODVBT__M)
+               *pLockStatus = NEVER_LOCK;
+end:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int PowerUpQAM(struct drxk_state *state)
+{
+       enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+       int status;
+
+       dprintk(1, "\n");
+       status = CtrlPowerMode(state, &powerMode);
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+
+/** Power Down QAM */
+static int PowerDownQAM(struct drxk_state *state)
+{
+       u16 data = 0;
+       u16 cmdResult;
+       int status = 0;
+
+       dprintk(1, "\n");
+       status = read16(state, SCU_COMM_EXEC__A, &data);
+       if (status < 0)
+               goto error;
+       if (data == SCU_COMM_EXEC_ACTIVE) {
+               /*
+                       STOP demodulator
+                       QAM and HW blocks
+                       */
+               /* stop all comstate->m_exec */
+               status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP);
+               if (status < 0)
+                       goto error;
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_STOP, 0, NULL, 1, &cmdResult);
+               if (status < 0)
+                       goto error;
+       }
+       /* powerdown AFE                   */
+       status = SetIqmAf(state, false);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Setup of the QAM Measurement intervals for signal quality
+* \param demod instance of demod.
+* \param constellation current constellation.
+* \return DRXStatus_t.
+*
+*  NOTE:
+*  Take into account that for certain settings the errorcounters can overflow.
+*  The implementation does not check this.
+*
+*/
+static int SetQAMMeasurement(struct drxk_state *state,
+                            enum EDrxkConstellation constellation,
+                            u32 symbolRate)
+{
+       u32 fecBitsDesired = 0; /* BER accounting period */
+       u32 fecRsPeriodTotal = 0;       /* Total period */
+       u16 fecRsPrescale = 0;  /* ReedSolomon Measurement Prescale */
+       u16 fecRsPeriod = 0;    /* Value for corresponding I2C register */
+       int status = 0;
+
+       dprintk(1, "\n");
+
+       fecRsPrescale = 1;
+       /* fecBitsDesired = symbolRate [kHz] *
+               FrameLenght [ms] *
+               (constellation + 1) *
+               SyncLoss (== 1) *
+               ViterbiLoss (==1)
+               */
+       switch (constellation) {
+       case DRX_CONSTELLATION_QAM16:
+               fecBitsDesired = 4 * symbolRate;
+               break;
+       case DRX_CONSTELLATION_QAM32:
+               fecBitsDesired = 5 * symbolRate;
+               break;
+       case DRX_CONSTELLATION_QAM64:
+               fecBitsDesired = 6 * symbolRate;
+               break;
+       case DRX_CONSTELLATION_QAM128:
+               fecBitsDesired = 7 * symbolRate;
+               break;
+       case DRX_CONSTELLATION_QAM256:
+               fecBitsDesired = 8 * symbolRate;
+               break;
+       default:
+               status = -EINVAL;
+       }
+       if (status < 0)
+               goto error;
+
+       fecBitsDesired /= 1000; /* symbolRate [Hz] -> symbolRate [kHz]  */
+       fecBitsDesired *= 500;  /* meas. period [ms] */
+
+       /* Annex A/C: bits/RsPeriod = 204 * 8 = 1632 */
+       /* fecRsPeriodTotal = fecBitsDesired / 1632 */
+       fecRsPeriodTotal = (fecBitsDesired / 1632UL) + 1;       /* roughly ceil */
+
+       /* fecRsPeriodTotal =  fecRsPrescale * fecRsPeriod  */
+       fecRsPrescale = 1 + (u16) (fecRsPeriodTotal >> 16);
+       if (fecRsPrescale == 0) {
+               /* Divide by zero (though impossible) */
+               status = -EINVAL;
+               if (status < 0)
+                       goto error;
+       }
+       fecRsPeriod =
+               ((u16) fecRsPeriodTotal +
+               (fecRsPrescale >> 1)) / fecRsPrescale;
+
+       /* write corresponding registers */
+       status = write16(state, FEC_RS_MEASUREMENT_PERIOD__A, fecRsPeriod);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_RS_MEASUREMENT_PRESCALE__A, fecRsPrescale);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_OC_SNC_FAIL_PERIOD__A, fecRsPeriod);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SetQAM16(struct drxk_state *state)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+       /* QAM Equalizer Setup */
+       /* Equalizer */
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 13517);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 13517);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 13517);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 13517);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13517);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 13517);
+       if (status < 0)
+               goto error;
+       /* Decision Feedback Equalizer */
+       status = write16(state, QAM_DQ_QUAL_FUN0__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN1__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN2__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN3__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN4__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_SY_SYNC_HWM__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_AWM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+       if (status < 0)
+               goto error;
+
+       /* QAM Slicer Settings */
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM16);
+       if (status < 0)
+               goto error;
+
+       /* QAM Loop Controller Coeficients */
+       status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 32);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM State Machine (FSM) Thresholds */
+
+       status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 140);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 95);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 120);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 230);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 105);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 24);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM FSM Tracking Parameters */
+
+       status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 220);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 25);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -65);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -127);
+       if (status < 0)
+               goto error;
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM32 specific setup
+* \param demod instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM32(struct drxk_state *state)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+
+       /* QAM Equalizer Setup */
+       /* Equalizer */
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 6707);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 6707);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 6707);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 6707);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 6707);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 6707);
+       if (status < 0)
+               goto error;
+
+       /* Decision Feedback Equalizer */
+       status = write16(state, QAM_DQ_QUAL_FUN0__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN1__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN2__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN3__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN4__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_SY_SYNC_HWM__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_AWM__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+       if (status < 0)
+               goto error;
+
+       /* QAM Slicer Settings */
+
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM32);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM Loop Controller Coeficients */
+
+       status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 20);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 20);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 0);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM State Machine (FSM) Thresholds */
+
+       status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 90);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 170);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 100);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 10);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM FSM Tracking Parameters */
+
+       status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 140);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) -8);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) -16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -26);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -56);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -86);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM64 specific setup
+* \param demod instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM64(struct drxk_state *state)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+       /* QAM Equalizer Setup */
+       /* Equalizer */
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 13336);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 12618);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 11988);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 13809);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13809);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 15609);
+       if (status < 0)
+               goto error;
+
+       /* Decision Feedback Equalizer */
+       status = write16(state, QAM_DQ_QUAL_FUN0__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN1__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN2__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN3__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN4__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_SY_SYNC_HWM__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_AWM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+       if (status < 0)
+               goto error;
+
+       /* QAM Slicer Settings */
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM64);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM Loop Controller Coeficients */
+
+       status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 30);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 100);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 30);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 48);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM State Machine (FSM) Thresholds */
+
+       status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 100);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 110);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 200);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 95);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 15);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM FSM Tracking Parameters */
+
+       status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 141);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 7);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -45);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -80);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM128 specific setup
+* \param demod: instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM128(struct drxk_state *state)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+       /* QAM Equalizer Setup */
+       /* Equalizer */
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 6564);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 6598);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 6394);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 6409);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 6656);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 7238);
+       if (status < 0)
+               goto error;
+
+       /* Decision Feedback Equalizer */
+       status = write16(state, QAM_DQ_QUAL_FUN0__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN1__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN2__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN3__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN4__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_SY_SYNC_HWM__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_AWM__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM Slicer Settings */
+
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM128);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM Loop Controller Coeficients */
+
+       status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 120);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 60);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 64);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 0);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM State Machine (FSM) Thresholds */
+
+       status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 140);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 100);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 5);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 12);
+       if (status < 0)
+               goto error;
+
+       /* QAM FSM Tracking Parameters */
+
+       status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 65);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) -1);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) -12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -23);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief QAM256 specific setup
+* \param demod: instance of demod.
+* \return DRXStatus_t.
+*/
+static int SetQAM256(struct drxk_state *state)
+{
+       int status = 0;
+
+       dprintk(1, "\n");
+       /* QAM Equalizer Setup */
+       /* Equalizer */
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD0__A, 11502);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD1__A, 12084);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD2__A, 12543);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD3__A, 12931);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD4__A, 13629);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_EQ_CMA_RAD5__A, 15385);
+       if (status < 0)
+               goto error;
+
+       /* Decision Feedback Equalizer */
+       status = write16(state, QAM_DQ_QUAL_FUN0__A, 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN1__A, 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN2__A, 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN3__A, 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN4__A, 6);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_DQ_QUAL_FUN5__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_SY_SYNC_HWM__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_AWM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_SYNC_LWM__A, 3);
+       if (status < 0)
+               goto error;
+
+       /* QAM Slicer Settings */
+
+       status = write16(state, SCU_RAM_QAM_SL_SIG_POWER__A, DRXK_QAM_SL_SIG_POWER_QAM256);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM Loop Controller Coeficients */
+
+       status = write16(state, SCU_RAM_QAM_LC_CA_FINE__A, 15);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CA_COARSE__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_MEDIUM__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EP_COARSE__A, 24);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_FINE__A, 12);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_MEDIUM__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_EI_COARSE__A, 16);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_LC_CP_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_MEDIUM__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CP_COARSE__A, 250);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_MEDIUM__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CI_COARSE__A, 125);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_FINE__A, 16);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_MEDIUM__A, 25);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF_COARSE__A, 48);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_FINE__A, 5);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_MEDIUM__A, 10);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_LC_CF1_COARSE__A, 10);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM State Machine (FSM) Thresholds */
+
+       status = write16(state, SCU_RAM_QAM_FSM_RTH__A, 50);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FTH__A, 60);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_CTH__A, 80);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_PTH__A, 100);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_QTH__A, 150);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_MTH__A, 110);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SCU_RAM_QAM_FSM_RATE_LIM__A, 40);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_COUNT_LIM__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_FREQ_LIM__A, 12);
+       if (status < 0)
+               goto error;
+
+
+       /* QAM FSM Tracking Parameters */
+
+       status = write16(state, SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A, (u16) 8);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A, (u16) 74);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A, (u16) 18);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A, (u16) 13);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A, (u16) 7);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A, (u16) 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A, (u16) -8);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+
+/*============================================================================*/
+/**
+* \brief Reset QAM block.
+* \param demod:   instance of demod.
+* \param channel: pointer to channel data.
+* \return DRXStatus_t.
+*/
+static int QAMResetQAM(struct drxk_state *state)
+{
+       int status;
+       u16 cmdResult;
+
+       dprintk(1, "\n");
+       /* Stop QAM comstate->m_exec */
+       status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_RESET, 0, NULL, 1, &cmdResult);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Set QAM symbolrate.
+* \param demod:   instance of demod.
+* \param channel: pointer to channel data.
+* \return DRXStatus_t.
+*/
+static int QAMSetSymbolrate(struct drxk_state *state)
+{
+       u32 adcFrequency = 0;
+       u32 symbFreq = 0;
+       u32 iqmRcRate = 0;
+       u16 ratesel = 0;
+       u32 lcSymbRate = 0;
+       int status;
+
+       dprintk(1, "\n");
+       /* Select & calculate correct IQM rate */
+       adcFrequency = (state->m_sysClockFreq * 1000) / 3;
+       ratesel = 0;
+       /* printk(KERN_DEBUG "drxk: SR %d\n", state->param.u.qam.symbol_rate); */
+       if (state->param.u.qam.symbol_rate <= 1188750)
+               ratesel = 3;
+       else if (state->param.u.qam.symbol_rate <= 2377500)
+               ratesel = 2;
+       else if (state->param.u.qam.symbol_rate <= 4755000)
+               ratesel = 1;
+       status = write16(state, IQM_FD_RATESEL__A, ratesel);
+       if (status < 0)
+               goto error;
+
+       /*
+               IqmRcRate = ((Fadc / (symbolrate * (4<<ratesel))) - 1) * (1<<23)
+               */
+       symbFreq = state->param.u.qam.symbol_rate * (1 << ratesel);
+       if (symbFreq == 0) {
+               /* Divide by zero */
+               status = -EINVAL;
+               goto error;
+       }
+       iqmRcRate = (adcFrequency / symbFreq) * (1 << 21) +
+               (Frac28a((adcFrequency % symbFreq), symbFreq) >> 7) -
+               (1 << 23);
+       status = write32(state, IQM_RC_RATE_OFS_LO__A, iqmRcRate);
+       if (status < 0)
+               goto error;
+       state->m_iqmRcRate = iqmRcRate;
+       /*
+               LcSymbFreq = round (.125 *  symbolrate / adcFreq * (1<<15))
+               */
+       symbFreq = state->param.u.qam.symbol_rate;
+       if (adcFrequency == 0) {
+               /* Divide by zero */
+               status = -EINVAL;
+               goto error;
+       }
+       lcSymbRate = (symbFreq / adcFrequency) * (1 << 12) +
+               (Frac28a((symbFreq % adcFrequency), adcFrequency) >>
+               16);
+       if (lcSymbRate > 511)
+               lcSymbRate = 511;
+       status = write16(state, QAM_LC_SYMBOL_FREQ__A, (u16) lcSymbRate);
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+/*============================================================================*/
+
+/**
+* \brief Get QAM lock status.
+* \param demod:   instance of demod.
+* \param channel: pointer to channel data.
+* \return DRXStatus_t.
+*/
+
+static int GetQAMLockStatus(struct drxk_state *state, u32 *pLockStatus)
+{
+       int status;
+       u16 Result[2] = { 0, 0 };
+
+       dprintk(1, "\n");
+       *pLockStatus = NOT_LOCKED;
+       status = scu_command(state,
+                       SCU_RAM_COMMAND_STANDARD_QAM |
+                       SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK, 0, NULL, 2,
+                       Result);
+       if (status < 0)
+               printk(KERN_ERR "drxk: %s status = %08x\n", __func__, status);
+
+       if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED) {
+               /* 0x0000 NOT LOCKED */
+       } else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_LOCKED) {
+               /* 0x4000 DEMOD LOCKED */
+               *pLockStatus = DEMOD_LOCK;
+       } else if (Result[1] < SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK) {
+               /* 0x8000 DEMOD + FEC LOCKED (system lock) */
+               *pLockStatus = MPEG_LOCK;
+       } else {
+               /* 0xC000 NEVER LOCKED */
+               /* (system will never be able to lock to the signal) */
+               /* TODO: check this, intermediate & standard specific lock states are not
+                  taken into account here */
+               *pLockStatus = NEVER_LOCK;
+       }
+       return status;
+}
+
+#define QAM_MIRROR__M         0x03
+#define QAM_MIRROR_NORMAL     0x00
+#define QAM_MIRRORED          0x01
+#define QAM_MIRROR_AUTO_ON    0x02
+#define QAM_LOCKRANGE__M      0x10
+#define QAM_LOCKRANGE_NORMAL  0x10
+
+static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz,
+                 s32 tunerFreqOffset)
+{
+       int status;
+       u16 setParamParameters[4] = { 0, 0, 0, 0 };
+       u16 cmdResult;
+
+       dprintk(1, "\n");
+       /*
+        * STEP 1: reset demodulator
+        *      resets FEC DI and FEC RS
+        *      resets QAM block
+        *      resets SCU variables
+        */
+       status = write16(state, FEC_DI_COMM_EXEC__A, FEC_DI_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_RS_COMM_EXEC__A, FEC_RS_COMM_EXEC_STOP);
+       if (status < 0)
+               goto error;
+       status = QAMResetQAM(state);
+       if (status < 0)
+               goto error;
+
+       /*
+        * STEP 2: configure demodulator
+        *      -set params; resets IQM,QAM,FEC HW; initializes some
+        *       SCU variables
+        */
+       status = QAMSetSymbolrate(state);
+       if (status < 0)
+               goto error;
+
+       /* Set params */
+       switch (state->param.u.qam.modulation) {
+       case QAM_256:
+               state->m_Constellation = DRX_CONSTELLATION_QAM256;
+               break;
+       case QAM_AUTO:
+       case QAM_64:
+               state->m_Constellation = DRX_CONSTELLATION_QAM64;
+               break;
+       case QAM_16:
+               state->m_Constellation = DRX_CONSTELLATION_QAM16;
+               break;
+       case QAM_32:
+               state->m_Constellation = DRX_CONSTELLATION_QAM32;
+               break;
+       case QAM_128:
+               state->m_Constellation = DRX_CONSTELLATION_QAM128;
+               break;
+       default:
+               status = -EINVAL;
+               break;
+       }
+       if (status < 0)
+               goto error;
+       setParamParameters[0] = state->m_Constellation; /* constellation     */
+       setParamParameters[1] = DRXK_QAM_I12_J17;       /* interleave mode   */
+       if (state->m_OperationMode == OM_QAM_ITU_C)
+               setParamParameters[2] = QAM_TOP_ANNEX_C;
+       else
+               setParamParameters[2] = QAM_TOP_ANNEX_A;
+       setParamParameters[3] |= (QAM_MIRROR_AUTO_ON);
+       /* Env parameters */
+       /* check for LOCKRANGE Extented */
+       /* setParamParameters[3] |= QAM_LOCKRANGE_NORMAL; */
+
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 4, setParamParameters, 1, &cmdResult);
+       if (status < 0) {
+               /* Fall-back to the simpler call */
+               if (state->m_OperationMode == OM_QAM_ITU_C)
+                       setParamParameters[0] = QAM_TOP_ANNEX_C;
+               else
+                       setParamParameters[0] = QAM_TOP_ANNEX_A;
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV, 1, setParamParameters, 1, &cmdResult);
+               if (status < 0)
+                       goto error;
+
+               setParamParameters[0] = state->m_Constellation; /* constellation     */
+               setParamParameters[1] = DRXK_QAM_I12_J17;       /* interleave mode   */
+               status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 2, setParamParameters, 1, &cmdResult);
+       }
+       if (status < 0)
+               goto error;
+
+       /*
+        * STEP 3: enable the system in a mode where the ADC provides valid
+        * signal setup constellation independent registers
+        */
+#if 0
+       status = SetFrequency(channel, tunerFreqOffset));
+       if (status < 0)
+               goto error;
+#endif
+       status = SetFrequencyShifter(state, IntermediateFreqkHz, tunerFreqOffset, true);
+       if (status < 0)
+               goto error;
+
+       /* Setup BER measurement */
+       status = SetQAMMeasurement(state, state->m_Constellation, state->param.u. qam.symbol_rate);
+       if (status < 0)
+               goto error;
+
+       /* Reset default values */
+       status = write16(state, IQM_CF_SCALE_SH__A, IQM_CF_SCALE_SH__PRE);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_SY_TIMEOUT__A, QAM_SY_TIMEOUT__PRE);
+       if (status < 0)
+               goto error;
+
+       /* Reset default LC values */
+       status = write16(state, QAM_LC_RATE_LIMIT__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_LPF_FACTORP__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_LPF_FACTORI__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_MODE__A, 7);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, QAM_LC_QUAL_TAB0__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB1__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB2__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB3__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB4__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB5__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB6__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB8__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB9__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB10__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB12__A, 2);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB15__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB16__A, 3);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB20__A, 4);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_LC_QUAL_TAB25__A, 4);
+       if (status < 0)
+               goto error;
+
+       /* Mirroring, QAM-block starting point not inverted */
+       status = write16(state, QAM_SY_SP_INV__A, QAM_SY_SP_INV_SPECTRUM_INV_DIS);
+       if (status < 0)
+               goto error;
+
+       /* Halt SCU to enable safe non-atomic accesses */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+       if (status < 0)
+               goto error;
+
+       /* STEP 4: constellation specific setup */
+       switch (state->param.u.qam.modulation) {
+       case QAM_16:
+               status = SetQAM16(state);
+               break;
+       case QAM_32:
+               status = SetQAM32(state);
+               break;
+       case QAM_AUTO:
+       case QAM_64:
+               status = SetQAM64(state);
+               break;
+       case QAM_128:
+               status = SetQAM128(state);
+               break;
+       case QAM_256:
+               status = SetQAM256(state);
+               break;
+       default:
+               status = -EINVAL;
+               break;
+       }
+       if (status < 0)
+               goto error;
+
+       /* Activate SCU to enable SCU commands */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+
+       /* Re-configure MPEG output, requires knowledge of channel bitrate */
+       /* extAttr->currentChannel.constellation = channel->constellation; */
+       /* extAttr->currentChannel.symbolrate    = channel->symbolrate; */
+       status = MPEGTSDtoSetup(state, state->m_OperationMode);
+       if (status < 0)
+               goto error;
+
+       /* Start processes */
+       status = MPEGTSStart(state);
+       if (status < 0)
+               goto error;
+       status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+       status = write16(state, QAM_COMM_EXEC__A, QAM_COMM_EXEC_ACTIVE);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_ACTIVE);
+       if (status < 0)
+               goto error;
+
+       /* STEP 5: start QAM demodulator (starts FEC, QAM and IQM HW) */
+       status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_START, 0, NULL, 1, &cmdResult);
+       if (status < 0)
+               goto error;
+
+       /* update global DRXK data container */
+/*?     extAttr->qamInterleaveMode = DRXK_QAM_I12_J17; */
+
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SetQAMStandard(struct drxk_state *state,
+                         enum OperationMode oMode)
+{
+       int status;
+#ifdef DRXK_QAM_TAPS
+#define DRXK_QAMA_TAPS_SELECT
+#include "drxk_filters.h"
+#undef DRXK_QAMA_TAPS_SELECT
+#endif
+
+       dprintk(1, "\n");
+
+       /* added antenna switch */
+       SwitchAntennaToQAM(state);
+
+       /* Ensure correct power-up mode */
+       status = PowerUpQAM(state);
+       if (status < 0)
+               goto error;
+       /* Reset QAM block */
+       status = QAMResetQAM(state);
+       if (status < 0)
+               goto error;
+
+       /* Setup IQM */
+
+       status = write16(state, IQM_COMM_EXEC__A, IQM_COMM_EXEC_B_STOP);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_AMUX__A, IQM_AF_AMUX_SIGNAL2ADC);
+       if (status < 0)
+               goto error;
+
+       /* Upload IQM Channel Filter settings by
+               boot loader from ROM table */
+       switch (oMode) {
+       case OM_QAM_ITU_A:
+               status = BLChainCmd(state, DRXK_BL_ROM_OFFSET_TAPS_ITU_A, DRXK_BLCC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+               break;
+       case OM_QAM_ITU_C:
+               status = BLDirectCmd(state, IQM_CF_TAP_RE0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+               if (status < 0)
+                       goto error;
+               status = BLDirectCmd(state, IQM_CF_TAP_IM0__A, DRXK_BL_ROM_OFFSET_TAPS_ITU_C, DRXK_BLDC_NR_ELEMENTS_TAPS, DRXK_BLC_TIMEOUT);
+               break;
+       default:
+               status = -EINVAL;
+       }
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_CF_OUT_ENA__A, (1 << IQM_CF_OUT_ENA_QAM__B));
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_SYMMETRIC__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_MIDTAP__A, ((1 << IQM_CF_MIDTAP_RE__B) | (1 << IQM_CF_MIDTAP_IM__B)));
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_RC_STRETCH__A, 21);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_CLP_LEN__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_CLP_TH__A, 448);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_SNS_LEN__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_POW_MEAS_LEN__A, 0);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, IQM_FS_ADJ_SEL__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_RC_ADJ_SEL__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_ADJ_SEL__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_UPD_SEL__A, 0);
+       if (status < 0)
+               goto error;
+
+       /* IQM Impulse Noise Processing Unit */
+       status = write16(state, IQM_CF_CLP_VAL__A, 500);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_DATATH__A, 1000);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_BYPASSDET__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_DET_LCT__A, 0);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_WND_LEN__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_CF_PKDTH__A, 1);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_INC_BYPASS__A, 1);
+       if (status < 0)
+               goto error;
+
+       /* turn on IQMAF. Must be done before setAgc**() */
+       status = SetIqmAf(state, true);
+       if (status < 0)
+               goto error;
+       status = write16(state, IQM_AF_START_LOCK__A, 0x01);
+       if (status < 0)
+               goto error;
+
+       /* IQM will not be reset from here, sync ADC and update/init AGC */
+       status = ADCSynchronization(state);
+       if (status < 0)
+               goto error;
+
+       /* Set the FSM step period */
+       status = write16(state, SCU_RAM_QAM_FSM_STEP_PERIOD__A, 2000);
+       if (status < 0)
+               goto error;
+
+       /* Halt SCU to enable safe non-atomic accesses */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_HOLD);
+       if (status < 0)
+               goto error;
+
+       /* No more resets of the IQM, current standard correctly set =>
+               now AGCs can be configured. */
+
+       status = InitAGC(state, true);
+       if (status < 0)
+               goto error;
+       status = SetPreSaw(state, &(state->m_qamPreSawCfg));
+       if (status < 0)
+               goto error;
+
+       /* Configure AGC's */
+       status = SetAgcRf(state, &(state->m_qamRfAgcCfg), true);
+       if (status < 0)
+               goto error;
+       status = SetAgcIf(state, &(state->m_qamIfAgcCfg), true);
+       if (status < 0)
+               goto error;
+
+       /* Activate SCU to enable SCU commands */
+       status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int WriteGPIO(struct drxk_state *state)
+{
+       int status;
+       u16 value = 0;
+
+       dprintk(1, "\n");
+       /* stop lock indicator process */
+       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+       if (status < 0)
+               goto error;
+
+       /*  Write magic word to enable pdr reg write               */
+       status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY);
+       if (status < 0)
+               goto error;
+
+       if (state->m_hasSAWSW) {
+               if (state->UIO_mask & 0x0001) { /* UIO-1 */
+                       /* write to io pad configuration register - output mode */
+                       status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+                       if (status < 0)
+                               goto error;
+
+                       /* use corresponding bit in io data output registar */
+                       status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
+                       if (status < 0)
+                               goto error;
+                       if ((state->m_GPIO & 0x0001) == 0)
+                               value &= 0x7FFF;        /* write zero to 15th bit - 1st UIO */
+                       else
+                               value |= 0x8000;        /* write one to 15th bit - 1st UIO */
+                       /* write back to io data output register */
+                       status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
+                       if (status < 0)
+                               goto error;
+               }
+               if (state->UIO_mask & 0x0002) { /* UIO-2 */
+                       /* write to io pad configuration register - output mode */
+                       status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+                       if (status < 0)
+                               goto error;
+
+                       /* use corresponding bit in io data output registar */
+                       status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
+                       if (status < 0)
+                               goto error;
+                       if ((state->m_GPIO & 0x0002) == 0)
+                               value &= 0xBFFF;        /* write zero to 14th bit - 2st UIO */
+                       else
+                               value |= 0x4000;        /* write one to 14th bit - 2st UIO */
+                       /* write back to io data output register */
+                       status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
+                       if (status < 0)
+                               goto error;
+               }
+               if (state->UIO_mask & 0x0004) { /* UIO-3 */
+                       /* write to io pad configuration register - output mode */
+                       status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+                       if (status < 0)
+                               goto error;
+
+                       /* use corresponding bit in io data output registar */
+                       status = read16(state, SIO_PDR_UIO_OUT_LO__A, &value);
+                       if (status < 0)
+                               goto error;
+                       if ((state->m_GPIO & 0x0004) == 0)
+                               value &= 0xFFFB;            /* write zero to 2nd bit - 3rd UIO */
+                       else
+                               value |= 0x0004;            /* write one to 2nd bit - 3rd UIO */
+                       /* write back to io data output register */
+                       status = write16(state, SIO_PDR_UIO_OUT_LO__A, value);
+                       if (status < 0)
+                               goto error;
+               }
+       }
+       /*  Write magic word to disable pdr reg write               */
+       status = write16(state, SIO_TOP_COMM_KEY__A, 0x0000);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SwitchAntennaToQAM(struct drxk_state *state)
+{
+       int status = 0;
+       bool gpio_state;
+
+       dprintk(1, "\n");
+
+       if (!state->antenna_gpio)
+               return 0;
+
+       gpio_state = state->m_GPIO & state->antenna_gpio;
+
+       if (state->antenna_dvbt ^ gpio_state) {
+               /* Antenna is on DVB-T mode. Switch */
+               if (state->antenna_dvbt)
+                       state->m_GPIO &= ~state->antenna_gpio;
+               else
+                       state->m_GPIO |= state->antenna_gpio;
+               status = WriteGPIO(state);
+       }
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+static int SwitchAntennaToDVBT(struct drxk_state *state)
+{
+       int status = 0;
+       bool gpio_state;
+
+       dprintk(1, "\n");
+
+       if (!state->antenna_gpio)
+               return 0;
+
+       gpio_state = state->m_GPIO & state->antenna_gpio;
+
+       if (!(state->antenna_dvbt ^ gpio_state)) {
+               /* Antenna is on DVB-C mode. Switch */
+               if (state->antenna_dvbt)
+                       state->m_GPIO |= state->antenna_gpio;
+               else
+                       state->m_GPIO &= ~state->antenna_gpio;
+               status = WriteGPIO(state);
+       }
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+       return status;
+}
+
+
+static int PowerDownDevice(struct drxk_state *state)
+{
+       /* Power down to requested mode */
+       /* Backup some register settings */
+       /* Set pins with possible pull-ups connected to them in input mode */
+       /* Analog power down */
+       /* ADC power down */
+       /* Power down device */
+       int status;
+
+       dprintk(1, "\n");
+       if (state->m_bPDownOpenBridge) {
+               /* Open I2C bridge before power down of DRXK */
+               status = ConfigureI2CBridge(state, true);
+               if (status < 0)
+                       goto error;
+       }
+       /* driver 0.9.0 */
+       status = DVBTEnableOFDMTokenRing(state, false);
+       if (status < 0)
+               goto error;
+
+       status = write16(state, SIO_CC_PWD_MODE__A, SIO_CC_PWD_MODE_LEVEL_CLOCK);
+       if (status < 0)
+               goto error;
+       status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+       if (status < 0)
+               goto error;
+       state->m_HICfgCtrl |= SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ;
+       status = HI_CfgCommand(state);
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static int load_microcode(struct drxk_state *state, const char *mc_name)
+{
+       const struct firmware *fw = NULL;
+       int err = 0;
+
+       dprintk(1, "\n");
+
+       err = request_firmware(&fw, mc_name, state->i2c->dev.parent);
+       if (err < 0) {
+               printk(KERN_ERR
+                      "drxk: Could not load firmware file %s.\n", mc_name);
+               printk(KERN_INFO
+                      "drxk: Copy %s to your hotplug directory!\n", mc_name);
+               return err;
+       }
+       err = DownloadMicrocode(state, fw->data, fw->size);
+       release_firmware(fw);
+       return err;
+}
+
+static int init_drxk(struct drxk_state *state)
+{
+       int status = 0;
+       enum DRXPowerMode powerMode = DRXK_POWER_DOWN_OFDM;
+       u16 driverVersion;
+
+       dprintk(1, "\n");
+       if ((state->m_DrxkState == DRXK_UNINITIALIZED)) {
+               status = PowerUpDevice(state);
+               if (status < 0)
+                       goto error;
+               status = DRXX_Open(state);
+               if (status < 0)
+                       goto error;
+               /* Soft reset of OFDM-, sys- and osc-clockdomain */
+               status = write16(state, SIO_CC_SOFT_RST__A, SIO_CC_SOFT_RST_OFDM__M | SIO_CC_SOFT_RST_SYS__M | SIO_CC_SOFT_RST_OSC__M);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SIO_CC_UPDATE__A, SIO_CC_UPDATE_KEY);
+               if (status < 0)
+                       goto error;
+               /* TODO is this needed, if yes how much delay in worst case scenario */
+               msleep(1);
+               state->m_DRXK_A3_PATCH_CODE = true;
+               status = GetDeviceCapabilities(state);
+               if (status < 0)
+                       goto error;
+
+               /* Bridge delay, uses oscilator clock */
+               /* Delay = (delay (nano seconds) * oscclk (kHz))/ 1000 */
+               /* SDA brdige delay */
+               state->m_HICfgBridgeDelay =
+                       (u16) ((state->m_oscClockFreq / 1000) *
+                               HI_I2C_BRIDGE_DELAY) / 1000;
+               /* Clipping */
+               if (state->m_HICfgBridgeDelay >
+                       SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M) {
+                       state->m_HICfgBridgeDelay =
+                               SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M;
+               }
+               /* SCL bridge delay, same as SDA for now */
+               state->m_HICfgBridgeDelay +=
+                       state->m_HICfgBridgeDelay <<
+                       SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B;
+
+               status = InitHI(state);
+               if (status < 0)
+                       goto error;
+               /* disable various processes */
+#if NOA1ROM
+               if (!(state->m_DRXK_A1_ROM_CODE)
+                       && !(state->m_DRXK_A2_ROM_CODE))
+#endif
+               {
+                       status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE);
+                       if (status < 0)
+                               goto error;
+               }
+
+               /* disable MPEG port */
+               status = MPEGTSDisable(state);
+               if (status < 0)
+                       goto error;
+
+               /* Stop AUD and SCU */
+               status = write16(state, AUD_COMM_EXEC__A, AUD_COMM_EXEC_STOP);
+               if (status < 0)
+                       goto error;
+               status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_STOP);
+               if (status < 0)
+                       goto error;
+
+               /* enable token-ring bus through OFDM block for possible ucode upload */
+               status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_ON);
+               if (status < 0)
+                       goto error;
+
+               /* include boot loader section */
+               status = write16(state, SIO_BL_COMM_EXEC__A, SIO_BL_COMM_EXEC_ACTIVE);
+               if (status < 0)
+                       goto error;
+               status = BLChainCmd(state, 0, 6, 100);
+               if (status < 0)
+                       goto error;
+
+               if (!state->microcode_name)
+                       load_microcode(state, "drxk_a3.mc");
+               else
+                       load_microcode(state, state->microcode_name);
+
+               /* disable token-ring bus through OFDM block for possible ucode upload */
+               status = write16(state, SIO_OFDM_SH_OFDM_RING_ENABLE__A, SIO_OFDM_SH_OFDM_RING_ENABLE_OFF);
+               if (status < 0)
+                       goto error;
+
+               /* Run SCU for a little while to initialize microcode version numbers */
+               status = write16(state, SCU_COMM_EXEC__A, SCU_COMM_EXEC_ACTIVE);
+               if (status < 0)
+                       goto error;
+               status = DRXX_Open(state);
+               if (status < 0)
+                       goto error;
+               /* added for test */
+               msleep(30);
+
+               powerMode = DRXK_POWER_DOWN_OFDM;
+               status = CtrlPowerMode(state, &powerMode);
+               if (status < 0)
+                       goto error;
+
+               /* Stamp driver version number in SCU data RAM in BCD code
+                       Done to enable field application engineers to retreive drxdriver version
+                       via I2C from SCU RAM.
+                       Not using SCU command interface for SCU register access since no
+                       microcode may be present.
+                       */
+               driverVersion =
+                       (((DRXK_VERSION_MAJOR / 100) % 10) << 12) +
+                       (((DRXK_VERSION_MAJOR / 10) % 10) << 8) +
+                       ((DRXK_VERSION_MAJOR % 10) << 4) +
+                       (DRXK_VERSION_MINOR % 10);
+               status = write16(state, SCU_RAM_DRIVER_VER_HI__A, driverVersion);
+               if (status < 0)
+                       goto error;
+               driverVersion =
+                       (((DRXK_VERSION_PATCH / 1000) % 10) << 12) +
+                       (((DRXK_VERSION_PATCH / 100) % 10) << 8) +
+                       (((DRXK_VERSION_PATCH / 10) % 10) << 4) +
+                       (DRXK_VERSION_PATCH % 10);
+               status = write16(state, SCU_RAM_DRIVER_VER_LO__A, driverVersion);
+               if (status < 0)
+                       goto error;
+
+               printk(KERN_INFO "DRXK driver version %d.%d.%d\n",
+                       DRXK_VERSION_MAJOR, DRXK_VERSION_MINOR,
+                       DRXK_VERSION_PATCH);
+
+               /* Dirty fix of default values for ROM/PATCH microcode
+                       Dirty because this fix makes it impossible to setup suitable values
+                       before calling DRX_Open. This solution requires changes to RF AGC speed
+                       to be done via the CTRL function after calling DRX_Open */
+
+               /* m_dvbtRfAgcCfg.speed = 3; */
+
+               /* Reset driver debug flags to 0 */
+               status = write16(state, SCU_RAM_DRIVER_DEBUG__A, 0);
+               if (status < 0)
+                       goto error;
+               /* driver 0.9.0 */
+               /* Setup FEC OC:
+                       NOTE: No more full FEC resets allowed afterwards!! */
+               status = write16(state, FEC_COMM_EXEC__A, FEC_COMM_EXEC_STOP);
+               if (status < 0)
+                       goto error;
+               /* MPEGTS functions are still the same */
+               status = MPEGTSDtoInit(state);
+               if (status < 0)
+                       goto error;
+               status = MPEGTSStop(state);
+               if (status < 0)
+                       goto error;
+               status = MPEGTSConfigurePolarity(state);
+               if (status < 0)
+                       goto error;
+               status = MPEGTSConfigurePins(state, state->m_enableMPEGOutput);
+               if (status < 0)
+                       goto error;
+               /* added: configure GPIO */
+               status = WriteGPIO(state);
+               if (status < 0)
+                       goto error;
+
+               state->m_DrxkState = DRXK_STOPPED;
+
+               if (state->m_bPowerDown) {
+                       status = PowerDownDevice(state);
+                       if (status < 0)
+                               goto error;
+                       state->m_DrxkState = DRXK_POWERED_DOWN;
+               } else
+                       state->m_DrxkState = DRXK_STOPPED;
+       }
+error:
+       if (status < 0)
+               printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
+
+       return status;
+}
+
+static void drxk_c_release(struct dvb_frontend *fe)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "\n");
+       kfree(state);
+}
+
+static int drxk_c_init(struct dvb_frontend *fe)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "\n");
+       if (mutex_trylock(&state->ctlock) == 0)
+               return -EBUSY;
+       SetOperationMode(state, OM_QAM_ITU_A);
+       return 0;
+}
+
+static int drxk_c_sleep(struct dvb_frontend *fe)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "\n");
+       ShutDown(state);
+       mutex_unlock(&state->ctlock);
+       return 0;
+}
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "%s\n", enable ? "enable" : "disable");
+       return ConfigureI2CBridge(state, enable ? true : false);
+}
+
+static int drxk_set_parameters(struct dvb_frontend *fe,
+                              struct dvb_frontend_parameters *p)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+       u32 IF;
+
+       dprintk(1, "\n");
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       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);
+       state->param = *p;
+       fe->ops.tuner_ops.get_frequency(fe, &IF);
+       Start(state, 0, IF);
+
+       /* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */
+
+       return 0;
+}
+
+static int drxk_c_get_frontend(struct dvb_frontend *fe,
+                              struct dvb_frontend_parameters *p)
+{
+       dprintk(1, "\n");
+       return 0;
+}
+
+static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+       u32 stat;
+
+       dprintk(1, "\n");
+       *status = 0;
+       GetLockStatus(state, &stat, 0);
+       if (stat == MPEG_LOCK)
+               *status |= 0x1f;
+       if (stat == FEC_LOCK)
+               *status |= 0x0f;
+       if (stat == DEMOD_LOCK)
+               *status |= 0x07;
+       return 0;
+}
+
+static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       dprintk(1, "\n");
+
+       *ber = 0;
+       return 0;
+}
+
+static int drxk_read_signal_strength(struct dvb_frontend *fe,
+                                    u16 *strength)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+       u32 val = 0;
+
+       dprintk(1, "\n");
+       ReadIFAgc(state, &val);
+       *strength = val & 0xffff;
+       return 0;
+}
+
+static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+       s32 snr2;
+
+       dprintk(1, "\n");
+       GetSignalToNoise(state, &snr2);
+       *snr = snr2 & 0xffff;
+       return 0;
+}
+
+static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+       u16 err;
+
+       dprintk(1, "\n");
+       DVBTQAMGetAccPktErr(state, &err);
+       *ucblocks = (u32) err;
+       return 0;
+}
+
+static int drxk_c_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings
+                                   *sets)
+{
+       dprintk(1, "\n");
+       sets->min_delay_ms = 3000;
+       sets->max_drift = 0;
+       sets->step_size = 0;
+       return 0;
+}
+
+static void drxk_t_release(struct dvb_frontend *fe)
+{
+       /*
+        * There's nothing to release here, as the state struct
+        * is already freed by drxk_c_release.
+        */
+}
+
+static int drxk_t_init(struct dvb_frontend *fe)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "\n");
+       if (mutex_trylock(&state->ctlock) == 0)
+               return -EBUSY;
+       SetOperationMode(state, OM_DVBT);
+       return 0;
+}
+
+static int drxk_t_sleep(struct dvb_frontend *fe)
+{
+       struct drxk_state *state = fe->demodulator_priv;
+
+       dprintk(1, "\n");
+       mutex_unlock(&state->ctlock);
+       return 0;
+}
+
+static int drxk_t_get_frontend(struct dvb_frontend *fe,
+                              struct dvb_frontend_parameters *p)
+{
+       dprintk(1, "\n");
+
+       return 0;
+}
+
+static struct dvb_frontend_ops drxk_c_ops = {
+       .info = {
+                .name = "DRXK DVB-C",
+                .type = FE_QAM,
+                .frequency_stepsize = 62500,
+                .frequency_min = 47000000,
+                .frequency_max = 862000000,
+                .symbol_rate_min = 870000,
+                .symbol_rate_max = 11700000,
+                .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+                FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO},
+       .release = drxk_c_release,
+       .init = drxk_c_init,
+       .sleep = drxk_c_sleep,
+       .i2c_gate_ctrl = drxk_gate_ctrl,
+
+       .set_frontend = drxk_set_parameters,
+       .get_frontend = drxk_c_get_frontend,
+       .get_tune_settings = drxk_c_get_tune_settings,
+
+       .read_status = drxk_read_status,
+       .read_ber = drxk_read_ber,
+       .read_signal_strength = drxk_read_signal_strength,
+       .read_snr = drxk_read_snr,
+       .read_ucblocks = drxk_read_ucblocks,
+};
+
+static struct dvb_frontend_ops drxk_t_ops = {
+       .info = {
+                .name = "DRXK DVB-T",
+                .type = FE_OFDM,
+                .frequency_min = 47125000,
+                .frequency_max = 865000000,
+                .frequency_stepsize = 166667,
+                .frequency_tolerance = 0,
+                .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+                FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+                FE_CAN_FEC_AUTO |
+                FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+                FE_CAN_QAM_AUTO |
+                FE_CAN_TRANSMISSION_MODE_AUTO |
+                FE_CAN_GUARD_INTERVAL_AUTO |
+                FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS},
+       .release = drxk_t_release,
+       .init = drxk_t_init,
+       .sleep = drxk_t_sleep,
+       .i2c_gate_ctrl = drxk_gate_ctrl,
+
+       .set_frontend = drxk_set_parameters,
+       .get_frontend = drxk_t_get_frontend,
+
+       .read_status = drxk_read_status,
+       .read_ber = drxk_read_ber,
+       .read_signal_strength = drxk_read_signal_strength,
+       .read_snr = drxk_read_snr,
+       .read_ucblocks = drxk_read_ucblocks,
+};
+
+struct dvb_frontend *drxk_attach(const struct drxk_config *config,
+                                struct i2c_adapter *i2c,
+                                struct dvb_frontend **fe_t)
+{
+       struct drxk_state *state = NULL;
+       u8 adr = config->adr;
+
+       dprintk(1, "\n");
+       state = kzalloc(sizeof(struct drxk_state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       state->i2c = i2c;
+       state->demod_address = adr;
+       state->single_master = config->single_master;
+       state->microcode_name = config->microcode_name;
+       state->no_i2c_bridge = config->no_i2c_bridge;
+       state->antenna_gpio = config->antenna_gpio;
+       state->antenna_dvbt = config->antenna_dvbt;
+
+       /* NOTE: as more UIO bits will be used, add them to the mask */
+       state->UIO_mask = config->antenna_gpio;
+
+       /* Default gpio to DVB-C */
+       if (!state->antenna_dvbt && state->antenna_gpio)
+               state->m_GPIO |= state->antenna_gpio;
+       else
+               state->m_GPIO &= ~state->antenna_gpio;
+
+       mutex_init(&state->mutex);
+       mutex_init(&state->ctlock);
+
+       memcpy(&state->c_frontend.ops, &drxk_c_ops,
+              sizeof(struct dvb_frontend_ops));
+       memcpy(&state->t_frontend.ops, &drxk_t_ops,
+              sizeof(struct dvb_frontend_ops));
+       state->c_frontend.demodulator_priv = state;
+       state->t_frontend.demodulator_priv = state;
+
+       init_state(state);
+       if (init_drxk(state) < 0)
+               goto error;
+       *fe_t = &state->t_frontend;
+
+       return &state->c_frontend;
+
+error:
+       printk(KERN_ERR "drxk: not found\n");
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(drxk_attach);
+
+MODULE_DESCRIPTION("DRX-K driver");
+MODULE_AUTHOR("Ralph Metzler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h
new file mode 100644 (file)
index 0000000..a05c32e
--- /dev/null
@@ -0,0 +1,348 @@
+#include "drxk_map.h"
+
+#define DRXK_VERSION_MAJOR 0
+#define DRXK_VERSION_MINOR 9
+#define DRXK_VERSION_PATCH 4300
+
+#define HI_I2C_DELAY        42
+#define HI_I2C_BRIDGE_DELAY 350
+#define DRXK_MAX_RETRIES    100
+
+#define DRIVER_4400 1
+
+#define DRXX_JTAGID   0x039210D9
+#define DRXX_J_JTAGID 0x239310D9
+#define DRXX_K_JTAGID 0x039210D9
+
+#define DRX_UNKNOWN     254
+#define DRX_AUTO        255
+
+#define DRX_SCU_READY   0
+#define DRXK_MAX_WAITTIME (200)
+#define SCU_RESULT_OK      0
+#define SCU_RESULT_SIZE   -4
+#define SCU_RESULT_INVPAR -3
+#define SCU_RESULT_UNKSTD -2
+#define SCU_RESULT_UNKCMD -1
+
+#ifndef DRXK_OFDM_TR_SHUTDOWN_TIMEOUT
+#define DRXK_OFDM_TR_SHUTDOWN_TIMEOUT (200)
+#endif
+
+#define DRXK_8VSB_MPEG_BIT_RATE     19392658UL  /*bps*/
+#define DRXK_DVBT_MPEG_BIT_RATE     32000000UL  /*bps*/
+#define DRXK_QAM16_MPEG_BIT_RATE    27000000UL  /*bps*/
+#define DRXK_QAM32_MPEG_BIT_RATE    33000000UL  /*bps*/
+#define DRXK_QAM64_MPEG_BIT_RATE    40000000UL  /*bps*/
+#define DRXK_QAM128_MPEG_BIT_RATE   46000000UL  /*bps*/
+#define DRXK_QAM256_MPEG_BIT_RATE   52000000UL  /*bps*/
+#define DRXK_MAX_MPEG_BIT_RATE      52000000UL  /*bps*/
+
+#define   IQM_CF_OUT_ENA_OFDM__M                                            0x4
+#define     IQM_FS_ADJ_SEL_B_QAM                                            0x1
+#define     IQM_FS_ADJ_SEL_B_OFF                                            0x0
+#define     IQM_FS_ADJ_SEL_B_VSB                                            0x2
+#define     IQM_RC_ADJ_SEL_B_OFF                                            0x0
+#define     IQM_RC_ADJ_SEL_B_QAM                                            0x1
+#define     IQM_RC_ADJ_SEL_B_VSB                                            0x2
+
+enum OperationMode {
+       OM_NONE,
+       OM_QAM_ITU_A,
+       OM_QAM_ITU_B,
+       OM_QAM_ITU_C,
+       OM_DVBT
+};
+
+enum DRXPowerMode {
+       DRX_POWER_UP = 0,
+       DRX_POWER_MODE_1,
+       DRX_POWER_MODE_2,
+       DRX_POWER_MODE_3,
+       DRX_POWER_MODE_4,
+       DRX_POWER_MODE_5,
+       DRX_POWER_MODE_6,
+       DRX_POWER_MODE_7,
+       DRX_POWER_MODE_8,
+
+       DRX_POWER_MODE_9,
+       DRX_POWER_MODE_10,
+       DRX_POWER_MODE_11,
+       DRX_POWER_MODE_12,
+       DRX_POWER_MODE_13,
+       DRX_POWER_MODE_14,
+       DRX_POWER_MODE_15,
+       DRX_POWER_MODE_16,
+       DRX_POWER_DOWN = 255
+};
+
+
+/** /brief Intermediate power mode for DRXK, power down OFDM clock domain */
+#ifndef DRXK_POWER_DOWN_OFDM
+#define DRXK_POWER_DOWN_OFDM        DRX_POWER_MODE_1
+#endif
+
+/** /brief Intermediate power mode for DRXK, power down core (sysclk) */
+#ifndef DRXK_POWER_DOWN_CORE
+#define DRXK_POWER_DOWN_CORE        DRX_POWER_MODE_9
+#endif
+
+/** /brief Intermediate power mode for DRXK, power down pll (only osc runs) */
+#ifndef DRXK_POWER_DOWN_PLL
+#define DRXK_POWER_DOWN_PLL         DRX_POWER_MODE_10
+#endif
+
+
+enum AGC_CTRL_MODE { DRXK_AGC_CTRL_AUTO = 0, DRXK_AGC_CTRL_USER, DRXK_AGC_CTRL_OFF };
+enum EDrxkState { DRXK_UNINITIALIZED = 0, DRXK_STOPPED, DRXK_DTV_STARTED, DRXK_ATV_STARTED, DRXK_POWERED_DOWN };
+enum EDrxkCoefArrayIndex {
+       DRXK_COEF_IDX_MN = 0,
+       DRXK_COEF_IDX_FM    ,
+       DRXK_COEF_IDX_L     ,
+       DRXK_COEF_IDX_LP    ,
+       DRXK_COEF_IDX_BG    ,
+       DRXK_COEF_IDX_DK    ,
+       DRXK_COEF_IDX_I     ,
+       DRXK_COEF_IDX_MAX
+};
+enum EDrxkSifAttenuation {
+       DRXK_SIF_ATTENUATION_0DB,
+       DRXK_SIF_ATTENUATION_3DB,
+       DRXK_SIF_ATTENUATION_6DB,
+       DRXK_SIF_ATTENUATION_9DB
+};
+enum EDrxkConstellation {
+       DRX_CONSTELLATION_BPSK = 0,
+       DRX_CONSTELLATION_QPSK,
+       DRX_CONSTELLATION_PSK8,
+       DRX_CONSTELLATION_QAM16,
+       DRX_CONSTELLATION_QAM32,
+       DRX_CONSTELLATION_QAM64,
+       DRX_CONSTELLATION_QAM128,
+       DRX_CONSTELLATION_QAM256,
+       DRX_CONSTELLATION_QAM512,
+       DRX_CONSTELLATION_QAM1024,
+       DRX_CONSTELLATION_UNKNOWN = DRX_UNKNOWN,
+       DRX_CONSTELLATION_AUTO    = DRX_AUTO
+};
+enum EDrxkInterleaveMode {
+       DRXK_QAM_I12_J17    = 16,
+       DRXK_QAM_I_UNKNOWN  = DRX_UNKNOWN
+};
+enum {
+       DRXK_SPIN_A1 = 0,
+       DRXK_SPIN_A2,
+       DRXK_SPIN_A3,
+       DRXK_SPIN_UNKNOWN
+};
+
+enum DRXKCfgDvbtSqiSpeed {
+       DRXK_DVBT_SQI_SPEED_FAST = 0,
+       DRXK_DVBT_SQI_SPEED_MEDIUM,
+       DRXK_DVBT_SQI_SPEED_SLOW,
+       DRXK_DVBT_SQI_SPEED_UNKNOWN = DRX_UNKNOWN
+} ;
+
+enum DRXFftmode_t {
+       DRX_FFTMODE_2K = 0,
+       DRX_FFTMODE_4K,
+       DRX_FFTMODE_8K,
+       DRX_FFTMODE_UNKNOWN = DRX_UNKNOWN,
+       DRX_FFTMODE_AUTO    = DRX_AUTO
+};
+
+enum DRXMPEGStrWidth_t {
+       DRX_MPEG_STR_WIDTH_1,
+       DRX_MPEG_STR_WIDTH_8
+};
+
+enum DRXQamLockRange_t {
+       DRX_QAM_LOCKRANGE_NORMAL,
+       DRX_QAM_LOCKRANGE_EXTENDED
+};
+
+struct DRXKCfgDvbtEchoThres_t {
+       u16             threshold;
+       enum DRXFftmode_t      fftMode;
+} ;
+
+struct SCfgAgc {
+       enum AGC_CTRL_MODE     ctrlMode;        /* off, user, auto */
+       u16            outputLevel;     /* range dependent on AGC */
+       u16            minOutputLevel;  /* range dependent on AGC */
+       u16            maxOutputLevel;  /* range dependent on AGC */
+       u16            speed;           /* range dependent on AGC */
+       u16            top;             /* rf-agc take over point */
+       u16            cutOffCurrent;   /* rf-agc is accelerated if output current
+                                          is below cut-off current */
+       u16            IngainTgtMax;
+       u16            FastClipCtrlDelay;
+};
+
+struct SCfgPreSaw {
+       u16        reference; /* pre SAW reference value, range 0 .. 31 */
+       bool          usePreSaw; /* TRUE algorithms must use pre SAW sense */
+};
+
+struct DRXKOfdmScCmd_t {
+       u16 cmd;        /**< Command number */
+       u16 subcmd;     /**< Sub-command parameter*/
+       u16 param0;     /**< General purpous param */
+       u16 param1;     /**< General purpous param */
+       u16 param2;     /**< General purpous param */
+       u16 param3;     /**< General purpous param */
+       u16 param4;     /**< General purpous param */
+};
+
+struct drxk_state {
+       struct dvb_frontend c_frontend;
+       struct dvb_frontend t_frontend;
+       struct dvb_frontend_parameters param;
+       struct device *dev;
+
+       struct i2c_adapter *i2c;
+       u8     demod_address;
+       void  *priv;
+
+       struct mutex mutex;
+       struct mutex ctlock;
+
+       u32    m_Instance;           /**< Channel 1,2,3 or 4 */
+
+       int    m_ChunkSize;
+       u8 Chunk[256];
+
+       bool   m_hasLNA;
+       bool   m_hasDVBT;
+       bool   m_hasDVBC;
+       bool   m_hasAudio;
+       bool   m_hasATV;
+       bool   m_hasOOB;
+       bool   m_hasSAWSW;         /**< TRUE if mat_tx is available */
+       bool   m_hasGPIO1;         /**< TRUE if mat_rx is available */
+       bool   m_hasGPIO2;         /**< TRUE if GPIO is available */
+       bool   m_hasIRQN;          /**< TRUE if IRQN is available */
+       u16    m_oscClockFreq;
+       u16    m_HICfgTimingDiv;
+       u16    m_HICfgBridgeDelay;
+       u16    m_HICfgWakeUpKey;
+       u16    m_HICfgTimeout;
+       u16    m_HICfgCtrl;
+       s32    m_sysClockFreq;      /**< system clock frequency in kHz */
+
+       enum EDrxkState    m_DrxkState;      /**< State of Drxk (init,stopped,started) */
+       enum OperationMode m_OperationMode;  /**< digital standards */
+       struct SCfgAgc     m_vsbRfAgcCfg;    /**< settings for VSB RF-AGC */
+       struct SCfgAgc     m_vsbIfAgcCfg;    /**< settings for VSB IF-AGC */
+       u16                m_vsbPgaCfg;      /**< settings for VSB PGA */
+       struct SCfgPreSaw  m_vsbPreSawCfg;   /**< settings for pre SAW sense */
+       s32    m_Quality83percent;  /**< MER level (*0.1 dB) for 83% quality indication */
+       s32    m_Quality93percent;  /**< MER level (*0.1 dB) for 93% quality indication */
+       bool   m_smartAntInverted;
+       bool   m_bDebugEnableBridge;
+       bool   m_bPDownOpenBridge;  /**< only open DRXK bridge before power-down once it has been accessed */
+       bool   m_bPowerDown;        /**< Power down when not used */
+
+       u32    m_IqmFsRateOfs;      /**< frequency shift as written to DRXK register (28bit fixpoint) */
+
+       bool   m_enableMPEGOutput;  /**< If TRUE, enable MPEG output */
+       bool   m_insertRSByte;      /**< If TRUE, insert RS byte */
+       bool   m_enableParallel;    /**< If TRUE, parallel out otherwise serial */
+       bool   m_invertDATA;        /**< If TRUE, invert DATA signals */
+       bool   m_invertERR;         /**< If TRUE, invert ERR signal */
+       bool   m_invertSTR;         /**< If TRUE, invert STR signals */
+       bool   m_invertVAL;         /**< If TRUE, invert VAL signals */
+       bool   m_invertCLK;         /**< If TRUE, invert CLK signals */
+       bool   m_DVBCStaticCLK;
+       bool   m_DVBTStaticCLK;     /**< If TRUE, static MPEG clockrate will
+                                        be used, otherwise clockrate will
+                                        adapt to the bitrate of the TS */
+       u32    m_DVBTBitrate;
+       u32    m_DVBCBitrate;
+
+       u8     m_TSDataStrength;
+       u8     m_TSClockkStrength;
+
+       enum DRXMPEGStrWidth_t  m_widthSTR;    /**< MPEG start width */
+       u32    m_mpegTsStaticBitrate;          /**< Maximum bitrate in b/s in case
+                                                   static clockrate is selected */
+
+       /* LARGE_INTEGER   m_StartTime; */     /**< Contains the time of the last demod start */
+       s32    m_MpegLockTimeOut;      /**< WaitForLockStatus Timeout (counts from start time) */
+       s32    m_DemodLockTimeOut;     /**< WaitForLockStatus Timeout (counts from start time) */
+
+       bool   m_disableTEIhandling;
+
+       bool   m_RfAgcPol;
+       bool   m_IfAgcPol;
+
+       struct SCfgAgc    m_atvRfAgcCfg;  /**< settings for ATV RF-AGC */
+       struct SCfgAgc    m_atvIfAgcCfg;  /**< settings for ATV IF-AGC */
+       struct SCfgPreSaw m_atvPreSawCfg; /**< settings for ATV pre SAW sense */
+       bool              m_phaseCorrectionBypass;
+       s16               m_atvTopVidPeak;
+       u16               m_atvTopNoiseTh;
+       enum EDrxkSifAttenuation m_sifAttenuation;
+       bool              m_enableCVBSOutput;
+       bool              m_enableSIFOutput;
+       bool              m_bMirrorFreqSpect;
+       enum EDrxkConstellation  m_Constellation; /**< Constellation type of the channel */
+       u32               m_CurrSymbolRate;       /**< Current QAM symbol rate */
+       struct SCfgAgc    m_qamRfAgcCfg;          /**< settings for QAM RF-AGC */
+       struct SCfgAgc    m_qamIfAgcCfg;          /**< settings for QAM IF-AGC */
+       u16               m_qamPgaCfg;            /**< settings for QAM PGA */
+       struct SCfgPreSaw m_qamPreSawCfg;         /**< settings for QAM pre SAW sense */
+       enum EDrxkInterleaveMode m_qamInterleaveMode; /**< QAM Interleave mode */
+       u16               m_fecRsPlen;
+       u16               m_fecRsPrescale;
+
+       enum DRXKCfgDvbtSqiSpeed m_sqiSpeed;
+
+       u16               m_GPIO;
+       u16               m_GPIOCfg;
+
+       struct SCfgAgc    m_dvbtRfAgcCfg;     /**< settings for QAM RF-AGC */
+       struct SCfgAgc    m_dvbtIfAgcCfg;     /**< settings for QAM IF-AGC */
+       struct SCfgPreSaw m_dvbtPreSawCfg;    /**< settings for QAM pre SAW sense */
+
+       u16               m_agcFastClipCtrlDelay;
+       bool              m_adcCompPassed;
+       u16               m_adcCompCoef[64];
+       u16               m_adcState;
+
+       u8               *m_microcode;
+       int               m_microcode_length;
+       bool              m_DRXK_A1_PATCH_CODE;
+       bool              m_DRXK_A1_ROM_CODE;
+       bool              m_DRXK_A2_ROM_CODE;
+       bool              m_DRXK_A3_ROM_CODE;
+       bool              m_DRXK_A2_PATCH_CODE;
+       bool              m_DRXK_A3_PATCH_CODE;
+
+       bool              m_rfmirror;
+       u8                m_deviceSpin;
+       u32               m_iqmRcRate;
+
+       enum DRXPowerMode m_currentPowerMode;
+
+       /*
+        * Configurable parameters at the driver. They stores the values found
+        * at struct drxk_config.
+        */
+
+       u16     UIO_mask;       /* Bits used by UIO */
+
+       bool    single_master;
+       bool    no_i2c_bridge;
+       bool    antenna_dvbt;
+       u16     antenna_gpio;
+
+       const char *microcode_name;
+};
+
+#define NEVER_LOCK 0
+#define NOT_LOCKED 1
+#define DEMOD_LOCK 2
+#define FEC_LOCK   3
+#define MPEG_LOCK  4
+
diff --git a/drivers/media/dvb/frontends/drxk_map.h b/drivers/media/dvb/frontends/drxk_map.h
new file mode 100644 (file)
index 0000000..9b11a83
--- /dev/null
@@ -0,0 +1,449 @@
+#define  AUD_COMM_EXEC__A                                                  0x1000000
+#define    AUD_COMM_EXEC_STOP                                              0x0
+#define  FEC_COMM_EXEC__A                                                  0x1C00000
+#define    FEC_COMM_EXEC_STOP                                              0x0
+#define    FEC_COMM_EXEC_ACTIVE                                            0x1
+#define  FEC_DI_COMM_EXEC__A                                               0x1C20000
+#define    FEC_DI_COMM_EXEC_STOP                                           0x0
+#define  FEC_DI_INPUT_CTL__A                                               0x1C20016
+#define  FEC_RS_COMM_EXEC__A                                               0x1C30000
+#define    FEC_RS_COMM_EXEC_STOP                                           0x0
+#define  FEC_RS_MEASUREMENT_PERIOD__A                                      0x1C30012
+#define  FEC_RS_MEASUREMENT_PRESCALE__A                                    0x1C30013
+#define  FEC_OC_MODE__A                                                    0x1C40011
+#define    FEC_OC_MODE_PARITY__M                                           0x1
+#define  FEC_OC_DTO_MODE__A                                                0x1C40014
+#define    FEC_OC_DTO_MODE_DYNAMIC__M                                      0x1
+#define    FEC_OC_DTO_MODE_OFFSET_ENABLE__M                                0x4
+#define  FEC_OC_DTO_PERIOD__A                                              0x1C40015
+#define  FEC_OC_DTO_BURST_LEN__A                                           0x1C40018
+#define  FEC_OC_FCT_MODE__A                                                0x1C4001A
+#define  FEC_OC_FCT_MODE__PRE                                              0x0
+#define    FEC_OC_FCT_MODE_RAT_ENA__M                                      0x1
+#define    FEC_OC_FCT_MODE_VIRT_ENA__M                                     0x2
+#define  FEC_OC_TMD_MODE__A                                                0x1C4001E
+#define  FEC_OC_TMD_COUNT__A                                               0x1C4001F
+#define  FEC_OC_TMD_HI_MARGIN__A                                           0x1C40020
+#define  FEC_OC_TMD_LO_MARGIN__A                                           0x1C40021
+#define  FEC_OC_TMD_INT_UPD_RATE__A                                        0x1C40023
+#define  FEC_OC_AVR_PARM_A__A                                              0x1C40026
+#define  FEC_OC_AVR_PARM_B__A                                              0x1C40027
+#define  FEC_OC_RCN_GAIN__A                                                0x1C4002E
+#define  FEC_OC_RCN_CTL_RATE_LO__A                                         0x1C40030
+#define  FEC_OC_RCN_CTL_STEP_LO__A                                         0x1C40032
+#define  FEC_OC_RCN_CTL_STEP_HI__A                                         0x1C40033
+#define  FEC_OC_SNC_MODE__A                                                0x1C40040
+#define    FEC_OC_SNC_MODE_SHUTDOWN__M                                     0x10
+#define  FEC_OC_SNC_LWM__A                                                 0x1C40041
+#define  FEC_OC_SNC_HWM__A                                                 0x1C40042
+#define  FEC_OC_SNC_UNLOCK__A                                              0x1C40043
+#define  FEC_OC_SNC_FAIL_PERIOD__A                                         0x1C40046
+#define  FEC_OC_IPR_MODE__A                                                0x1C40048
+#define    FEC_OC_IPR_MODE_SERIAL__M                                       0x1
+#define    FEC_OC_IPR_MODE_MCLK_DIS_DAT_ABS__M                             0x4
+#define    FEC_OC_IPR_MODE_MVAL_DIS_PAR__M                                 0x10
+#define  FEC_OC_IPR_INVERT__A                                              0x1C40049
+#define    FEC_OC_IPR_INVERT_MD0__M                                        0x1
+#define    FEC_OC_IPR_INVERT_MD1__M                                        0x2
+#define    FEC_OC_IPR_INVERT_MD2__M                                        0x4
+#define    FEC_OC_IPR_INVERT_MD3__M                                        0x8
+#define    FEC_OC_IPR_INVERT_MD4__M                                        0x10
+#define    FEC_OC_IPR_INVERT_MD5__M                                        0x20
+#define    FEC_OC_IPR_INVERT_MD6__M                                        0x40
+#define    FEC_OC_IPR_INVERT_MD7__M                                        0x80
+#define    FEC_OC_IPR_INVERT_MERR__M                                       0x100
+#define    FEC_OC_IPR_INVERT_MSTRT__M                                      0x200
+#define    FEC_OC_IPR_INVERT_MVAL__M                                       0x400
+#define    FEC_OC_IPR_INVERT_MCLK__M                                       0x800
+#define  FEC_OC_OCR_INVERT__A                                              0x1C40052
+#define  IQM_COMM_EXEC__A                                                  0x1800000
+#define      IQM_COMM_EXEC_B_STOP                                          0x0
+#define      IQM_COMM_EXEC_B_ACTIVE                                        0x1
+#define  IQM_FS_RATE_OFS_LO__A                                             0x1820010
+#define  IQM_FS_ADJ_SEL__A                                                 0x1820014
+#define      IQM_FS_ADJ_SEL_B_OFF                                          0x0
+#define      IQM_FS_ADJ_SEL_B_QAM                                          0x1
+#define      IQM_FS_ADJ_SEL_B_VSB                                          0x2
+#define  IQM_FD_RATESEL__A                                                 0x1830010
+#define  IQM_RC_RATE_OFS_LO__A                                             0x1840010
+#define  IQM_RC_RATE_OFS_LO__W                                             16
+#define  IQM_RC_RATE_OFS_LO__M                                             0xFFFF
+#define  IQM_RC_RATE_OFS_HI__M                                             0xFF
+#define  IQM_RC_ADJ_SEL__A                                                 0x1840014
+#define      IQM_RC_ADJ_SEL_B_OFF                                          0x0
+#define      IQM_RC_ADJ_SEL_B_QAM                                          0x1
+#define      IQM_RC_ADJ_SEL_B_VSB                                          0x2
+#define  IQM_RC_STRETCH__A                                                 0x1840016
+#define  IQM_CF_COMM_INT_MSK__A                                            0x1860006
+#define  IQM_CF_SYMMETRIC__A                                               0x1860010
+#define  IQM_CF_MIDTAP__A                                                  0x1860011
+#define    IQM_CF_MIDTAP_RE__B                                             0
+#define    IQM_CF_MIDTAP_IM__B                                             1
+#define  IQM_CF_OUT_ENA__A                                                 0x1860012
+#define    IQM_CF_OUT_ENA_QAM__B                                           1
+#define    IQM_CF_OUT_ENA_OFDM__M                                          0x4
+#define  IQM_CF_ADJ_SEL__A                                                 0x1860013
+#define  IQM_CF_SCALE__A                                                   0x1860014
+#define  IQM_CF_SCALE_SH__A                                                0x1860015
+#define  IQM_CF_SCALE_SH__PRE                                              0x0
+#define  IQM_CF_POW_MEAS_LEN__A                                            0x1860017
+#define  IQM_CF_DS_ENA__A                                                  0x1860019
+#define  IQM_CF_TAP_RE0__A                                                 0x1860020
+#define  IQM_CF_TAP_IM0__A                                                 0x1860040
+#define  IQM_CF_CLP_VAL__A                                                 0x1860060
+#define  IQM_CF_DATATH__A                                                  0x1860061
+#define  IQM_CF_PKDTH__A                                                   0x1860062
+#define  IQM_CF_WND_LEN__A                                                 0x1860063
+#define  IQM_CF_DET_LCT__A                                                 0x1860064
+#define  IQM_CF_BYPASSDET__A                                               0x1860067
+#define  IQM_AF_COMM_EXEC__A                                               0x1870000
+#define    IQM_AF_COMM_EXEC_ACTIVE                                         0x1
+#define  IQM_AF_CLKNEG__A                                                  0x1870012
+#define    IQM_AF_CLKNEG_CLKNEGDATA__M                                     0x2
+#define      IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_POS                     0x0
+#define      IQM_AF_CLKNEG_CLKNEGDATA_CLK_ADC_DATA_NEG                     0x2
+#define  IQM_AF_START_LOCK__A                                              0x187001B
+#define  IQM_AF_PHASE0__A                                                  0x187001C
+#define  IQM_AF_PHASE1__A                                                  0x187001D
+#define  IQM_AF_PHASE2__A                                                  0x187001E
+#define  IQM_AF_CLP_LEN__A                                                 0x1870023
+#define  IQM_AF_CLP_TH__A                                                  0x1870024
+#define  IQM_AF_SNS_LEN__A                                                 0x1870026
+#define  IQM_AF_AGC_IF__A                                                  0x1870028
+#define  IQM_AF_AGC_RF__A                                                  0x1870029
+#define  IQM_AF_PDREF__A                                                   0x187002B
+#define  IQM_AF_PDREF__M                                                   0x1F
+#define  IQM_AF_STDBY__A                                                   0x187002C
+#define      IQM_AF_STDBY_STDBY_ADC_STANDBY                                0x2
+#define      IQM_AF_STDBY_STDBY_AMP_STANDBY                                0x4
+#define      IQM_AF_STDBY_STDBY_PD_STANDBY                                 0x8
+#define      IQM_AF_STDBY_STDBY_TAGC_IF_STANDBY                            0x10
+#define      IQM_AF_STDBY_STDBY_TAGC_RF_STANDBY                            0x20
+#define  IQM_AF_AMUX__A                                                    0x187002D
+#define    IQM_AF_AMUX_SIGNAL2ADC                                          0x1
+#define  IQM_AF_UPD_SEL__A                                                 0x187002F
+#define  IQM_AF_INC_LCT__A                                                 0x1870034
+#define  IQM_AF_INC_BYPASS__A                                              0x1870036
+#define  OFDM_CP_COMM_EXEC__A                                              0x2800000
+#define    OFDM_CP_COMM_EXEC_STOP                                          0x0
+#define  OFDM_EC_SB_PRIOR__A                                               0x3410013
+#define    OFDM_EC_SB_PRIOR_HI                                             0x0
+#define    OFDM_EC_SB_PRIOR_LO                                             0x1
+#define  OFDM_EQ_TOP_TD_TPS_CONST__A                                       0x3010054
+#define  OFDM_EQ_TOP_TD_TPS_CONST__M                                       0x3
+#define    OFDM_EQ_TOP_TD_TPS_CONST_64QAM                                  0x2
+#define  OFDM_EQ_TOP_TD_TPS_CODE_HP__A                                     0x3010056
+#define  OFDM_EQ_TOP_TD_TPS_CODE_HP__M                                     0x7
+#define    OFDM_EQ_TOP_TD_TPS_CODE_LP_7_8                                  0x4
+#define  OFDM_EQ_TOP_TD_SQR_ERR_I__A                                       0x301005E
+#define  OFDM_EQ_TOP_TD_SQR_ERR_Q__A                                       0x301005F
+#define  OFDM_EQ_TOP_TD_SQR_ERR_EXP__A                                     0x3010060
+#define  OFDM_EQ_TOP_TD_REQ_SMB_CNT__A                                     0x3010061
+#define  OFDM_EQ_TOP_TD_TPS_PWR_OFS__A                                     0x3010062
+#define  OFDM_LC_COMM_EXEC__A                                              0x3800000
+#define    OFDM_LC_COMM_EXEC_STOP                                          0x0
+#define  OFDM_SC_COMM_EXEC__A                                              0x3C00000
+#define    OFDM_SC_COMM_EXEC_STOP                                          0x0
+#define  OFDM_SC_COMM_STATE__A                                             0x3C00001
+#define  OFDM_SC_RA_RAM_PARAM0__A                                          0x3C20040
+#define  OFDM_SC_RA_RAM_PARAM1__A                                          0x3C20041
+#define  OFDM_SC_RA_RAM_CMD_ADDR__A                                        0x3C20042
+#define  OFDM_SC_RA_RAM_CMD__A                                             0x3C20043
+#define    OFDM_SC_RA_RAM_CMD_NULL                                         0x0
+#define    OFDM_SC_RA_RAM_CMD_PROC_START                                   0x1
+#define    OFDM_SC_RA_RAM_CMD_SET_PREF_PARAM                               0x3
+#define    OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM                                0x4
+#define    OFDM_SC_RA_RAM_CMD_GET_OP_PARAM                                 0x5
+#define    OFDM_SC_RA_RAM_CMD_USER_IO                                      0x6
+#define    OFDM_SC_RA_RAM_CMD_SET_TIMER                                    0x7
+#define    OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING                              0x8
+#define    OFDM_SC_RA_RAM_SW_EVENT_RUN_NMASK__M                            0x1
+#define    OFDM_SC_RA_RAM_LOCKTRACK_MIN                                    0x1
+#define  OFDM_SC_RA_RAM_OP_PARAM__A                                        0x3C20048
+#define    OFDM_SC_RA_RAM_OP_PARAM_MODE__M                                 0x3
+#define      OFDM_SC_RA_RAM_OP_PARAM_MODE_2K                               0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_MODE_8K                               0x1
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_32                              0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_16                              0x4
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_8                               0x8
+#define      OFDM_SC_RA_RAM_OP_PARAM_GUARD_4                               0xC
+#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QPSK                            0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM16                           0x10
+#define      OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64                           0x20
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_NO                               0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A1                               0x40
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A2                               0x80
+#define      OFDM_SC_RA_RAM_OP_PARAM_HIER_A4                               0xC0
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_1_2                              0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3                              0x200
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_3_4                              0x400
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_5_6                              0x600
+#define      OFDM_SC_RA_RAM_OP_PARAM_RATE_7_8                              0x800
+#define      OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI                               0x0
+#define      OFDM_SC_RA_RAM_OP_PARAM_PRIO_LO                               0x1000
+#define    OFDM_SC_RA_RAM_OP_AUTO_MODE__M                                  0x1
+#define    OFDM_SC_RA_RAM_OP_AUTO_GUARD__M                                 0x2
+#define    OFDM_SC_RA_RAM_OP_AUTO_CONST__M                                 0x4
+#define    OFDM_SC_RA_RAM_OP_AUTO_HIER__M                                  0x8
+#define    OFDM_SC_RA_RAM_OP_AUTO_RATE__M                                  0x10
+#define  OFDM_SC_RA_RAM_LOCK__A                                            0x3C2004B
+#define    OFDM_SC_RA_RAM_LOCK_DEMOD__M                                    0x1
+#define    OFDM_SC_RA_RAM_LOCK_FEC__M                                      0x2
+#define    OFDM_SC_RA_RAM_LOCK_MPEG__M                                     0x4
+#define    OFDM_SC_RA_RAM_LOCK_NODVBT__M                                   0x8
+#define  OFDM_SC_RA_RAM_BE_OPT_DELAY__A                                    0x3C2004D
+#define  OFDM_SC_RA_RAM_BE_OPT_INIT_DELAY__A                               0x3C2004E
+#define  OFDM_SC_RA_RAM_ECHO_THRES__A                                      0x3C2004F
+#define    OFDM_SC_RA_RAM_ECHO_THRES_8K__B                                 0
+#define    OFDM_SC_RA_RAM_ECHO_THRES_8K__M                                 0xFF
+#define    OFDM_SC_RA_RAM_ECHO_THRES_2K__B                                 8
+#define    OFDM_SC_RA_RAM_ECHO_THRES_2K__M                                 0xFF00
+#define  OFDM_SC_RA_RAM_CONFIG__A                                          0x3C20050
+#define    OFDM_SC_RA_RAM_CONFIG_NE_FIX_ENABLE__M                          0x800
+#define  OFDM_SC_RA_RAM_FR_THRES_8K__A                                     0x3C2007D
+#define  OFDM_SC_RA_RAM_NI_INIT_2K_PER_LEFT__A                             0x3C200E0
+#define  OFDM_SC_RA_RAM_NI_INIT_2K_PER_RIGHT__A                            0x3C200E1
+#define  OFDM_SC_RA_RAM_NI_INIT_8K_PER_LEFT__A                             0x3C200E3
+#define  OFDM_SC_RA_RAM_NI_INIT_8K_PER_RIGHT__A                            0x3C200E4
+#define  OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A                                0x3C200F8
+#define  QAM_COMM_EXEC__A                                                  0x1400000
+#define    QAM_COMM_EXEC_STOP                                              0x0
+#define    QAM_COMM_EXEC_ACTIVE                                            0x1
+#define    QAM_TOP_ANNEX_A                                                 0x0
+#define    QAM_TOP_ANNEX_C                                                 0x2
+#define  QAM_SL_ERR_POWER__A                                               0x1430017
+#define  QAM_DQ_QUAL_FUN0__A                                               0x1440018
+#define  QAM_DQ_QUAL_FUN1__A                                               0x1440019
+#define  QAM_DQ_QUAL_FUN2__A                                               0x144001A
+#define  QAM_DQ_QUAL_FUN3__A                                               0x144001B
+#define  QAM_DQ_QUAL_FUN4__A                                               0x144001C
+#define  QAM_DQ_QUAL_FUN5__A                                               0x144001D
+#define  QAM_LC_MODE__A                                                    0x1450010
+#define  QAM_LC_QUAL_TAB0__A                                               0x1450018
+#define  QAM_LC_QUAL_TAB1__A                                               0x1450019
+#define  QAM_LC_QUAL_TAB2__A                                               0x145001A
+#define  QAM_LC_QUAL_TAB3__A                                               0x145001B
+#define  QAM_LC_QUAL_TAB4__A                                               0x145001C
+#define  QAM_LC_QUAL_TAB5__A                                               0x145001D
+#define  QAM_LC_QUAL_TAB6__A                                               0x145001E
+#define  QAM_LC_QUAL_TAB8__A                                               0x145001F
+#define  QAM_LC_QUAL_TAB9__A                                               0x1450020
+#define  QAM_LC_QUAL_TAB10__A                                              0x1450021
+#define  QAM_LC_QUAL_TAB12__A                                              0x1450022
+#define  QAM_LC_QUAL_TAB15__A                                              0x1450023
+#define  QAM_LC_QUAL_TAB16__A                                              0x1450024
+#define  QAM_LC_QUAL_TAB20__A                                              0x1450025
+#define  QAM_LC_QUAL_TAB25__A                                              0x1450026
+#define  QAM_LC_LPF_FACTORP__A                                             0x1450028
+#define  QAM_LC_LPF_FACTORI__A                                             0x1450029
+#define  QAM_LC_RATE_LIMIT__A                                              0x145002A
+#define  QAM_LC_SYMBOL_FREQ__A                                             0x145002B
+#define  QAM_SY_TIMEOUT__A                                                 0x1470011
+#define  QAM_SY_TIMEOUT__PRE                                               0x3A98
+#define  QAM_SY_SYNC_LWM__A                                                0x1470012
+#define  QAM_SY_SYNC_AWM__A                                                0x1470013
+#define  QAM_SY_SYNC_HWM__A                                                0x1470014
+#define  QAM_SY_SP_INV__A                                                  0x1470017
+#define    QAM_SY_SP_INV_SPECTRUM_INV_DIS                                  0x0
+#define  SCU_COMM_EXEC__A                                                  0x800000
+#define    SCU_COMM_EXEC_STOP                                              0x0
+#define    SCU_COMM_EXEC_ACTIVE                                            0x1
+#define    SCU_COMM_EXEC_HOLD                                              0x2
+#define  SCU_RAM_DRIVER_DEBUG__A                                           0x831EBF
+#define  SCU_RAM_QAM_FSM_STEP_PERIOD__A                                    0x831EC4
+#define  SCU_RAM_GPIO__A                                                   0x831EC7
+#define      SCU_RAM_GPIO_HW_LOCK_IND_DISABLE                              0x0
+#define  SCU_RAM_AGC_CLP_CTRL_MODE__A                                      0x831EC8
+#define  SCU_RAM_FEC_ACCUM_PKT_FAILURES__A                                 0x831ECB
+#define  SCU_RAM_FEC_PRE_RS_BER_FILTER_SH__A                               0x831F05
+#define  SCU_RAM_AGC_FAST_SNS_CTRL_DELAY__A                                0x831F15
+#define  SCU_RAM_AGC_KI_CYCLEN__A                                          0x831F17
+#define  SCU_RAM_AGC_SNS_CYCLEN__A                                         0x831F18
+#define  SCU_RAM_AGC_RF_SNS_DEV_MAX__A                                     0x831F19
+#define  SCU_RAM_AGC_RF_SNS_DEV_MIN__A                                     0x831F1A
+#define  SCU_RAM_AGC_RF_MAX__A                                             0x831F1B
+#define  SCU_RAM_AGC_CONFIG__A                                             0x831F24
+#define    SCU_RAM_AGC_CONFIG_DISABLE_RF_AGC__M                            0x1
+#define    SCU_RAM_AGC_CONFIG_DISABLE_IF_AGC__M                            0x2
+#define    SCU_RAM_AGC_CONFIG_INV_IF_POL__M                                0x100
+#define    SCU_RAM_AGC_CONFIG_INV_RF_POL__M                                0x200
+#define  SCU_RAM_AGC_KI__A                                                 0x831F25
+#define    SCU_RAM_AGC_KI_RF__B                                            4
+#define    SCU_RAM_AGC_KI_RF__M                                            0xF0
+#define    SCU_RAM_AGC_KI_IF__B                                            8
+#define    SCU_RAM_AGC_KI_IF__M                                            0xF00
+#define  SCU_RAM_AGC_KI_RED__A                                             0x831F26
+#define    SCU_RAM_AGC_KI_RED_RAGC_RED__B                                  2
+#define    SCU_RAM_AGC_KI_RED_RAGC_RED__M                                  0xC
+#define    SCU_RAM_AGC_KI_RED_IAGC_RED__B                                  4
+#define    SCU_RAM_AGC_KI_RED_IAGC_RED__M                                  0x30
+#define  SCU_RAM_AGC_KI_INNERGAIN_MIN__A                                   0x831F27
+#define  SCU_RAM_AGC_KI_MINGAIN__A                                         0x831F28
+#define  SCU_RAM_AGC_KI_MAXGAIN__A                                         0x831F29
+#define  SCU_RAM_AGC_KI_MAXMINGAIN_TH__A                                   0x831F2A
+#define  SCU_RAM_AGC_KI_MIN__A                                             0x831F2B
+#define  SCU_RAM_AGC_KI_MAX__A                                             0x831F2C
+#define  SCU_RAM_AGC_CLP_SUM__A                                            0x831F2D
+#define  SCU_RAM_AGC_CLP_SUM_MIN__A                                        0x831F2E
+#define  SCU_RAM_AGC_CLP_SUM_MAX__A                                        0x831F2F
+#define  SCU_RAM_AGC_CLP_CYCLEN__A                                         0x831F30
+#define  SCU_RAM_AGC_CLP_CYCCNT__A                                         0x831F31
+#define  SCU_RAM_AGC_CLP_DIR_TO__A                                         0x831F32
+#define  SCU_RAM_AGC_CLP_DIR_WD__A                                         0x831F33
+#define  SCU_RAM_AGC_CLP_DIR_STP__A                                        0x831F34
+#define  SCU_RAM_AGC_SNS_SUM__A                                            0x831F35
+#define  SCU_RAM_AGC_SNS_SUM_MIN__A                                        0x831F36
+#define  SCU_RAM_AGC_SNS_SUM_MAX__A                                        0x831F37
+#define  SCU_RAM_AGC_SNS_CYCCNT__A                                         0x831F38
+#define  SCU_RAM_AGC_SNS_DIR_TO__A                                         0x831F39
+#define  SCU_RAM_AGC_SNS_DIR_WD__A                                         0x831F3A
+#define  SCU_RAM_AGC_SNS_DIR_STP__A                                        0x831F3B
+#define  SCU_RAM_AGC_INGAIN_TGT__A                                         0x831F3D
+#define  SCU_RAM_AGC_INGAIN_TGT_MIN__A                                     0x831F3E
+#define  SCU_RAM_AGC_INGAIN_TGT_MAX__A                                     0x831F3F
+#define  SCU_RAM_AGC_IF_IACCU_HI__A                                        0x831F40
+#define  SCU_RAM_AGC_IF_IACCU_LO__A                                        0x831F41
+#define  SCU_RAM_AGC_IF_IACCU_HI_TGT__A                                    0x831F42
+#define  SCU_RAM_AGC_IF_IACCU_HI_TGT_MIN__A                                0x831F43
+#define  SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A                                0x831F44
+#define  SCU_RAM_AGC_RF_IACCU_HI__A                                        0x831F45
+#define  SCU_RAM_AGC_RF_IACCU_LO__A                                        0x831F46
+#define  SCU_RAM_AGC_RF_IACCU_HI_CO__A                                     0x831F47
+#define  SCU_RAM_QAM_FSM_MEDIAN_AV_MULT__A                                 0x831F84
+#define  SCU_RAM_QAM_FSM_RADIUS_AV_LIMIT__A                                0x831F85
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET1__A                                  0x831F86
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET2__A                                  0x831F87
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET3__A                                  0x831F88
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET4__A                                  0x831F89
+#define  SCU_RAM_QAM_FSM_LCAVG_OFFSET5__A                                  0x831F8A
+#define  SCU_RAM_QAM_FSM_RTH__A                                            0x831F8E
+#define  SCU_RAM_QAM_FSM_FTH__A                                            0x831F8F
+#define  SCU_RAM_QAM_FSM_PTH__A                                            0x831F90
+#define  SCU_RAM_QAM_FSM_MTH__A                                            0x831F91
+#define  SCU_RAM_QAM_FSM_CTH__A                                            0x831F92
+#define  SCU_RAM_QAM_FSM_QTH__A                                            0x831F93
+#define  SCU_RAM_QAM_FSM_RATE_LIM__A                                       0x831F94
+#define  SCU_RAM_QAM_FSM_FREQ_LIM__A                                       0x831F95
+#define  SCU_RAM_QAM_FSM_COUNT_LIM__A                                      0x831F96
+#define  SCU_RAM_QAM_LC_CA_COARSE__A                                       0x831F97
+#define  SCU_RAM_QAM_LC_CA_FINE__A                                         0x831F99
+#define  SCU_RAM_QAM_LC_CP_COARSE__A                                       0x831F9A
+#define  SCU_RAM_QAM_LC_CP_MEDIUM__A                                       0x831F9B
+#define  SCU_RAM_QAM_LC_CP_FINE__A                                         0x831F9C
+#define  SCU_RAM_QAM_LC_CI_COARSE__A                                       0x831F9D
+#define  SCU_RAM_QAM_LC_CI_MEDIUM__A                                       0x831F9E
+#define  SCU_RAM_QAM_LC_CI_FINE__A                                         0x831F9F
+#define  SCU_RAM_QAM_LC_EP_COARSE__A                                       0x831FA0
+#define  SCU_RAM_QAM_LC_EP_MEDIUM__A                                       0x831FA1
+#define  SCU_RAM_QAM_LC_EP_FINE__A                                         0x831FA2
+#define  SCU_RAM_QAM_LC_EI_COARSE__A                                       0x831FA3
+#define  SCU_RAM_QAM_LC_EI_MEDIUM__A                                       0x831FA4
+#define  SCU_RAM_QAM_LC_EI_FINE__A                                         0x831FA5
+#define  SCU_RAM_QAM_LC_CF_COARSE__A                                       0x831FA6
+#define  SCU_RAM_QAM_LC_CF_MEDIUM__A                                       0x831FA7
+#define  SCU_RAM_QAM_LC_CF_FINE__A                                         0x831FA8
+#define  SCU_RAM_QAM_LC_CF1_COARSE__A                                      0x831FA9
+#define  SCU_RAM_QAM_LC_CF1_MEDIUM__A                                      0x831FAA
+#define  SCU_RAM_QAM_LC_CF1_FINE__A                                        0x831FAB
+#define  SCU_RAM_QAM_SL_SIG_POWER__A                                       0x831FAC
+#define  SCU_RAM_QAM_EQ_CMA_RAD0__A                                        0x831FAD
+#define  SCU_RAM_QAM_EQ_CMA_RAD1__A                                        0x831FAE
+#define  SCU_RAM_QAM_EQ_CMA_RAD2__A                                        0x831FAF
+#define  SCU_RAM_QAM_EQ_CMA_RAD3__A                                        0x831FB0
+#define  SCU_RAM_QAM_EQ_CMA_RAD4__A                                        0x831FB1
+#define  SCU_RAM_QAM_EQ_CMA_RAD5__A                                        0x831FB2
+#define      SCU_RAM_QAM_LOCKED_LOCKED_DEMOD_LOCKED                        0x4000
+#define      SCU_RAM_QAM_LOCKED_LOCKED_LOCKED                              0x8000
+#define      SCU_RAM_QAM_LOCKED_LOCKED_NEVER_LOCK                          0xC000
+#define  SCU_RAM_AGC_FAST_CLP_CTRL_DELAY__A                                0x831FEA
+#define  SCU_RAM_DRIVER_VER_HI__A                                          0x831FEB
+#define  SCU_RAM_DRIVER_VER_LO__A                                          0x831FEC
+#define  SCU_RAM_PARAM_15__A                                               0x831FED
+#define  SCU_RAM_PARAM_0__A                                                0x831FFC
+#define  SCU_RAM_COMMAND__A                                                0x831FFD
+#define    SCU_RAM_COMMAND_CMD_DEMOD_RESET                                 0x1
+#define    SCU_RAM_COMMAND_CMD_DEMOD_SET_ENV                               0x2
+#define    SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM                             0x3
+#define    SCU_RAM_COMMAND_CMD_DEMOD_START                                 0x4
+#define    SCU_RAM_COMMAND_CMD_DEMOD_GET_LOCK                              0x5
+#define    SCU_RAM_COMMAND_CMD_DEMOD_STOP                                  0x9
+#define      SCU_RAM_COMMAND_STANDARD_QAM                                  0x200
+#define      SCU_RAM_COMMAND_STANDARD_OFDM                                 0x400
+#define  SIO_TOP_COMM_KEY__A                                               0x41000F
+#define    SIO_TOP_COMM_KEY_KEY                                            0xFABA
+#define  SIO_TOP_JTAGID_LO__A                                              0x410012
+#define  SIO_HI_RA_RAM_RES__A                                              0x420031
+#define  SIO_HI_RA_RAM_CMD__A                                              0x420032
+#define    SIO_HI_RA_RAM_CMD_RESET                                         0x2
+#define    SIO_HI_RA_RAM_CMD_CONFIG                                        0x3
+#define    SIO_HI_RA_RAM_CMD_BRDCTRL                                       0x7
+#define  SIO_HI_RA_RAM_PAR_1__A                                            0x420033
+#define      SIO_HI_RA_RAM_PAR_1_PAR1_SEC_KEY                              0x3945
+#define  SIO_HI_RA_RAM_PAR_2__A                                            0x420034
+#define    SIO_HI_RA_RAM_PAR_2_CFG_DIV__M                                  0x7F
+#define      SIO_HI_RA_RAM_PAR_2_BRD_CFG_OPEN                              0x0
+#define      SIO_HI_RA_RAM_PAR_2_BRD_CFG_CLOSED                            0x4
+#define  SIO_HI_RA_RAM_PAR_3__A                                            0x420035
+#define    SIO_HI_RA_RAM_PAR_3_CFG_DBL_SDA__M                              0x7F
+#define    SIO_HI_RA_RAM_PAR_3_CFG_DBL_SCL__B                              7
+#define      SIO_HI_RA_RAM_PAR_3_ACP_RW_READ                               0x0
+#define      SIO_HI_RA_RAM_PAR_3_ACP_RW_WRITE                              0x8
+#define  SIO_HI_RA_RAM_PAR_4__A                                            0x420036
+#define  SIO_HI_RA_RAM_PAR_5__A                                            0x420037
+#define      SIO_HI_RA_RAM_PAR_5_CFG_SLV0_SLAVE                            0x1
+#define    SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M                                0x8
+#define      SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ                             0x8
+#define  SIO_HI_RA_RAM_PAR_6__A                                            0x420038
+#define  SIO_CC_PLL_LOCK__A                                                0x450012
+#define  SIO_CC_PWD_MODE__A                                                0x450015
+#define      SIO_CC_PWD_MODE_LEVEL_NONE                                    0x0
+#define      SIO_CC_PWD_MODE_LEVEL_OFDM                                    0x1
+#define      SIO_CC_PWD_MODE_LEVEL_CLOCK                                   0x2
+#define      SIO_CC_PWD_MODE_LEVEL_PLL                                     0x3
+#define      SIO_CC_PWD_MODE_LEVEL_OSC                                     0x4
+#define  SIO_CC_SOFT_RST__A                                                0x450016
+#define    SIO_CC_SOFT_RST_OFDM__M                                         0x1
+#define    SIO_CC_SOFT_RST_SYS__M                                          0x2
+#define    SIO_CC_SOFT_RST_OSC__M                                          0x4
+#define  SIO_CC_UPDATE__A                                                  0x450017
+#define    SIO_CC_UPDATE_KEY                                               0xFABA
+#define  SIO_OFDM_SH_OFDM_RING_ENABLE__A                                   0x470010
+#define    SIO_OFDM_SH_OFDM_RING_ENABLE_OFF                                0x0
+#define    SIO_OFDM_SH_OFDM_RING_ENABLE_ON                                 0x1
+#define  SIO_OFDM_SH_OFDM_RING_STATUS__A                                   0x470012
+#define    SIO_OFDM_SH_OFDM_RING_STATUS_DOWN                               0x0
+#define    SIO_OFDM_SH_OFDM_RING_STATUS_ENABLED                            0x1
+#define  SIO_BL_COMM_EXEC__A                                               0x480000
+#define    SIO_BL_COMM_EXEC_ACTIVE                                         0x1
+#define  SIO_BL_STATUS__A                                                  0x480010
+#define  SIO_BL_MODE__A                                                    0x480011
+#define    SIO_BL_MODE_DIRECT                                              0x0
+#define    SIO_BL_MODE_CHAIN                                               0x1
+#define  SIO_BL_ENABLE__A                                                  0x480012
+#define    SIO_BL_ENABLE_ON                                                0x1
+#define  SIO_BL_TGT_HDR__A                                                 0x480014
+#define  SIO_BL_TGT_ADDR__A                                                0x480015
+#define  SIO_BL_SRC_ADDR__A                                                0x480016
+#define  SIO_BL_SRC_LEN__A                                                 0x480017
+#define  SIO_BL_CHAIN_ADDR__A                                              0x480018
+#define  SIO_BL_CHAIN_LEN__A                                               0x480019
+#define  SIO_PDR_MON_CFG__A                                                0x7F0010
+#define  SIO_PDR_UIO_IN_HI__A                                              0x7F0015
+#define  SIO_PDR_UIO_OUT_LO__A                                             0x7F0016
+#define  SIO_PDR_OHW_CFG__A                                                0x7F001F
+#define    SIO_PDR_OHW_CFG_FREF_SEL__M                                     0x3
+#define  SIO_PDR_MSTRT_CFG__A                                              0x7F0025
+#define  SIO_PDR_MERR_CFG__A                                               0x7F0026
+#define  SIO_PDR_MCLK_CFG__A                                               0x7F0028
+#define    SIO_PDR_MCLK_CFG_DRIVE__B                                       3
+#define  SIO_PDR_MVAL_CFG__A                                               0x7F0029
+#define  SIO_PDR_MD0_CFG__A                                                0x7F002A
+#define    SIO_PDR_MD0_CFG_DRIVE__B                                        3
+#define  SIO_PDR_MD1_CFG__A                                                0x7F002B
+#define  SIO_PDR_MD2_CFG__A                                                0x7F002C
+#define  SIO_PDR_MD3_CFG__A                                                0x7F002D
+#define  SIO_PDR_MD4_CFG__A                                                0x7F002F
+#define  SIO_PDR_MD5_CFG__A                                                0x7F0030
+#define  SIO_PDR_MD6_CFG__A                                                0x7F0031
+#define  SIO_PDR_MD7_CFG__A                                                0x7F0032
+#define  SIO_PDR_SMA_TX_CFG__A                                             0x7F0038
index f7a40a18777a0e13a90dfdc7f4e75ce87a952955..aa9ccb821fa51fe9a6f8612c5cbb491f065f7c2f 100644 (file)
@@ -35,21 +35,18 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
-#define deb(args...)  do { \
+#define itd_dbg(args...)  do { \
        if (debug) { \
                printk(KERN_DEBUG   "ITD1000: " args);\
-               printk("\n"); \
        } \
 } while (0)
 
-#define warn(args...) do { \
+#define itd_warn(args...) do { \
        printk(KERN_WARNING "ITD1000: " args); \
-       printk("\n"); \
 } while (0)
 
-#define info(args...) do { \
+#define itd_info(args...) do { \
        printk(KERN_INFO    "ITD1000: " args); \
-       printk("\n"); \
 } while (0)
 
 /* don't write more than one byte with flexcop behind */
@@ -62,7 +59,7 @@ static int itd1000_write_regs(struct itd1000_state *state, u8 reg, u8 v[], u8 le
        buf[0] = reg;
        memcpy(&buf[1], v, len);
 
-       /* deb("wr %02x: %02x", reg, v[0]); */
+       /* itd_dbg("wr %02x: %02x\n", reg, v[0]); */
 
        if (i2c_transfer(state->i2c, &msg, 1) != 1) {
                printk(KERN_WARNING "itd1000 I2C write failed\n");
@@ -83,7 +80,7 @@ static int itd1000_read_reg(struct itd1000_state *state, u8 reg)
        itd1000_write_regs(state, (reg - 1) & 0xff, &state->shadow[(reg - 1) & 0xff], 1);
 
        if (i2c_transfer(state->i2c, msg, 2) != 2) {
-               warn("itd1000 I2C read failed");
+               itd_warn("itd1000 I2C read failed\n");
                return -EREMOTEIO;
        }
        return val;
@@ -127,14 +124,14 @@ static void itd1000_set_lpf_bw(struct itd1000_state *state, u32 symbol_rate)
        u8 bbgvmin = itd1000_read_reg(state, BBGVMIN) & 0xf0;
        u8 bw      = itd1000_read_reg(state, BW)      & 0xf0;
 
-       deb("symbol_rate = %d", symbol_rate);
+       itd_dbg("symbol_rate = %d\n", symbol_rate);
 
        /* not sure what is that ? - starting to download the table */
        itd1000_write_reg(state, CON1, con1 | (1 << 1));
 
        for (i = 0; i < ARRAY_SIZE(itd1000_lpf_pga); i++)
                if (symbol_rate < itd1000_lpf_pga[i].symbol_rate) {
-                       deb("symrate: index: %d pgaext: %x, bbgvmin: %x", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin);
+                       itd_dbg("symrate: index: %d pgaext: %x, bbgvmin: %x\n", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin);
                        itd1000_write_reg(state, PLLFH,   pllfh | (itd1000_lpf_pga[i].pgaext << 4));
                        itd1000_write_reg(state, BBGVMIN, bbgvmin | (itd1000_lpf_pga[i].bbgvmin));
                        itd1000_write_reg(state, BW,      bw | (i & 0x0f));
@@ -182,7 +179,7 @@ static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz)
 
                        adcout = itd1000_read_reg(state, PLLLOCK) & 0x0f;
 
-                       deb("VCO: %dkHz: %d -> ADCOUT: %d %02x", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c);
+                       itd_dbg("VCO: %dkHz: %d -> ADCOUT: %d %02x\n", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c);
 
                        if (adcout > 13) {
                                if (!(itd1000_vcorg[i].vcorg == 7 || itd1000_vcorg[i].vcorg == 15))
@@ -232,7 +229,7 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz)
        pllf = (u32) tmp;
 
        state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF;
-       deb("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d", freq_khz, state->frequency, pllf, plln);
+       itd_dbg("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d\n", freq_khz, state->frequency, pllf, plln);
 
        itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */;
        itd1000_write_reg(state, PLLNL, plln & 0xff);
@@ -242,7 +239,7 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz)
 
        for (i = 0; i < ARRAY_SIZE(itd1000_fre_values); i++) {
                if (freq_khz <= itd1000_fre_values[i].freq) {
-                       deb("fre_values: %d", i);
+                       itd_dbg("fre_values: %d\n", i);
                        itd1000_write_reg(state, RFTR, itd1000_fre_values[i].values[0]);
                        for (j = 0; j < 9; j++)
                                itd1000_write_reg(state, RFST1+j, itd1000_fre_values[i].values[j+1]);
@@ -382,7 +379,7 @@ struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter
                kfree(state);
                return NULL;
        }
-       info("successfully identified (ID: %d)", i);
+       itd_info("successfully identified (ID: %d)\n", i);
 
        memset(state->shadow, 0xff, sizeof(state->shadow));
        for (i = 0x65; i < 0x9c; i++)
index a763ec756f7f84df840bcb38bfb3816ee016e174..6599b8fea9e9ad0d2c3bad2560565670b5e2486c 100644 (file)
@@ -50,7 +50,7 @@ static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data)
        if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1)
                dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret);
 
-       return (ret != 1) ? -EFAULT : 0;
+       return (ret != 1) ? -EIO : 0;
 }
 
 static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg)
index 17f8cdf8afefe041a3be5ecbd11cf009f93f0e3f..3879d2e378aa73da4ac1b923a7e163c6c54a48a6 100644 (file)
@@ -634,7 +634,7 @@ 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;
-       uint8_t clock_settting;
+       uint8_t clock_setting;
 
        dprintk("enter %s\n", __func__);
 
@@ -684,19 +684,19 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
        switch (state->fclk) {
        default:
        case 88000000:
-               clock_settting = 80;
+               clock_setting = 80;
                break;
        case 86000000:
-               clock_settting = 78;
+               clock_setting = 78;
                break;
        case 80000000:
-               clock_settting = 72;
+               clock_setting = 72;
                break;
        case 59000000:
-               clock_settting = 51;
+               clock_setting = 51;
                break;
        case 44000000:
-               clock_settting = 36;
+               clock_setting = 36;
                break;
        }
        dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
diff --git a/drivers/media/dvb/frontends/tda18271c2dd.c b/drivers/media/dvb/frontends/tda18271c2dd.c
new file mode 100644 (file)
index 0000000..0384e8d
--- /dev/null
@@ -0,0 +1,1251 @@
+/*
+ * tda18271c2dd: Driver for the TDA18271C2 tuner
+ *
+ * Copyright (C) 2010 Digital Devices GmbH
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+
+struct SStandardParam {
+       s32   m_IFFrequency;
+       u32   m_BandWidth;
+       u8    m_EP3_4_0;
+       u8    m_EB22;
+};
+
+struct SMap {
+       u32   m_Frequency;
+       u8    m_Param;
+};
+
+struct SMapI {
+       u32   m_Frequency;
+       s32    m_Param;
+};
+
+struct SMap2 {
+       u32   m_Frequency;
+       u8    m_Param1;
+       u8    m_Param2;
+};
+
+struct SRFBandMap {
+       u32   m_RF_max;
+       u32   m_RF1_Default;
+       u32   m_RF2_Default;
+       u32   m_RF3_Default;
+};
+
+enum ERegister {
+       ID = 0,
+       TM,
+       PL,
+       EP1, EP2, EP3, EP4, EP5,
+       CPD, CD1, CD2, CD3,
+       MPD, MD1, MD2, MD3,
+       EB1, EB2, EB3, EB4, EB5, EB6, EB7, EB8, EB9, EB10,
+       EB11, EB12, EB13, EB14, EB15, EB16, EB17, EB18, EB19, EB20,
+       EB21, EB22, EB23,
+       NUM_REGS
+};
+
+struct tda_state {
+       struct i2c_adapter *i2c;
+       u8 adr;
+
+       u32   m_Frequency;
+       u32   IF;
+
+       u8    m_IFLevelAnalog;
+       u8    m_IFLevelDigital;
+       u8    m_IFLevelDVBC;
+       u8    m_IFLevelDVBT;
+
+       u8    m_EP4;
+       u8    m_EP3_Standby;
+
+       bool  m_bMaster;
+
+       s32   m_SettlingTime;
+
+       u8    m_Regs[NUM_REGS];
+
+       /* Tracking filter settings for band 0..6 */
+       u32   m_RF1[7];
+       s32   m_RF_A1[7];
+       s32   m_RF_B1[7];
+       u32   m_RF2[7];
+       s32   m_RF_A2[7];
+       s32   m_RF_B2[7];
+       u32   m_RF3[7];
+
+       u8    m_TMValue_RFCal;    /* Calibration temperatur */
+
+       bool  m_bFMInput;         /* true to use Pin 8 for FM Radio */
+
+};
+
+static int PowerScan(struct tda_state *state,
+                    u8 RFBand, u32 RF_in,
+                    u32 *pRF_Out, bool *pbcal);
+
+static int i2c_readn(struct i2c_adapter *adapter, u8 adr, u8 *data, int len)
+{
+       struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
+                                  .buf  = data, .len   = len} };
+       return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
+{
+       struct i2c_msg msg = {.addr = adr, .flags = 0,
+                             .buf = data, .len = len};
+
+       if (i2c_transfer(adap, &msg, 1) != 1) {
+               printk(KERN_ERR "tda18271c2dd: i2c write error at addr %i\n", adr);
+               return -1;
+       }
+       return 0;
+}
+
+static int WriteRegs(struct tda_state *state,
+                    u8 SubAddr, u8 *Regs, u16 nRegs)
+{
+       u8 data[nRegs+1];
+
+       data[0] = SubAddr;
+       memcpy(data + 1, Regs, nRegs);
+       return i2c_write(state->i2c, state->adr, data, nRegs+1);
+}
+
+static int WriteReg(struct tda_state *state, u8 SubAddr, u8 Reg)
+{
+       u8 msg[2] = {SubAddr, Reg};
+
+       return i2c_write(state->i2c, state->adr, msg, 2);
+}
+
+static int Read(struct tda_state *state, u8 * Regs)
+{
+       return i2c_readn(state->i2c, state->adr, Regs, 16);
+}
+
+static int ReadExtented(struct tda_state *state, u8 * Regs)
+{
+       return i2c_readn(state->i2c, state->adr, Regs, NUM_REGS);
+}
+
+static int UpdateRegs(struct tda_state *state, u8 RegFrom, u8 RegTo)
+{
+       return WriteRegs(state, RegFrom,
+                        &state->m_Regs[RegFrom], RegTo-RegFrom+1);
+}
+static int UpdateReg(struct tda_state *state, u8 Reg)
+{
+       return WriteReg(state, Reg, state->m_Regs[Reg]);
+}
+
+#include "tda18271c2dd_maps.h"
+
+static void reset(struct tda_state *state)
+{
+       u32   ulIFLevelAnalog = 0;
+       u32   ulIFLevelDigital = 2;
+       u32   ulIFLevelDVBC = 7;
+       u32   ulIFLevelDVBT = 6;
+       u32   ulXTOut = 0;
+       u32   ulStandbyMode = 0x06;    /* Send in stdb, but leave osc on */
+       u32   ulSlave = 0;
+       u32   ulFMInput = 0;
+       u32   ulSettlingTime = 100;
+
+       state->m_Frequency         = 0;
+       state->m_SettlingTime = 100;
+       state->m_IFLevelAnalog = (ulIFLevelAnalog & 0x07) << 2;
+       state->m_IFLevelDigital = (ulIFLevelDigital & 0x07) << 2;
+       state->m_IFLevelDVBC = (ulIFLevelDVBC & 0x07) << 2;
+       state->m_IFLevelDVBT = (ulIFLevelDVBT & 0x07) << 2;
+
+       state->m_EP4 = 0x20;
+       if (ulXTOut != 0)
+               state->m_EP4 |= 0x40;
+
+       state->m_EP3_Standby = ((ulStandbyMode & 0x07) << 5) | 0x0F;
+       state->m_bMaster = (ulSlave == 0);
+
+       state->m_SettlingTime = ulSettlingTime;
+
+       state->m_bFMInput = (ulFMInput == 2);
+}
+
+static bool SearchMap1(struct SMap Map[],
+                      u32 Frequency, u8 *pParam)
+{
+       int i = 0;
+
+       while ((Map[i].m_Frequency != 0) && (Frequency > Map[i].m_Frequency))
+               i += 1;
+       if (Map[i].m_Frequency == 0)
+               return false;
+       *pParam = Map[i].m_Param;
+       return true;
+}
+
+static bool SearchMap2(struct SMapI Map[],
+                      u32 Frequency, s32 *pParam)
+{
+       int i = 0;
+
+       while ((Map[i].m_Frequency != 0) &&
+              (Frequency > Map[i].m_Frequency))
+               i += 1;
+       if (Map[i].m_Frequency == 0)
+               return false;
+       *pParam = Map[i].m_Param;
+       return true;
+}
+
+static bool SearchMap3(struct SMap2 Map[], u32 Frequency,
+                      u8 *pParam1, u8 *pParam2)
+{
+       int i = 0;
+
+       while ((Map[i].m_Frequency != 0) &&
+              (Frequency > Map[i].m_Frequency))
+               i += 1;
+       if (Map[i].m_Frequency == 0)
+               return false;
+       *pParam1 = Map[i].m_Param1;
+       *pParam2 = Map[i].m_Param2;
+       return true;
+}
+
+static bool SearchMap4(struct SRFBandMap Map[],
+                      u32 Frequency, u8 *pRFBand)
+{
+       int i = 0;
+
+       while (i < 7 && (Frequency > Map[i].m_RF_max))
+               i += 1;
+       if (i == 7)
+               return false;
+       *pRFBand = i;
+       return true;
+}
+
+static int ThermometerRead(struct tda_state *state, u8 *pTM_Value)
+{
+       int status = 0;
+
+       do {
+               u8 Regs[16];
+               state->m_Regs[TM] |= 0x10;
+               status = UpdateReg(state, TM);
+               if (status < 0)
+                       break;
+               status = Read(state, Regs);
+               if (status < 0)
+                       break;
+               if (((Regs[TM] & 0x0F) == 0 && (Regs[TM] & 0x20) == 0x20) ||
+                   ((Regs[TM] & 0x0F) == 8 && (Regs[TM] & 0x20) == 0x00)) {
+                       state->m_Regs[TM] ^= 0x20;
+                       status = UpdateReg(state, TM);
+                       if (status < 0)
+                               break;
+                       msleep(10);
+                       status = Read(state, Regs);
+                       if (status < 0)
+                               break;
+               }
+               *pTM_Value = (Regs[TM] & 0x20)
+                               ? m_Thermometer_Map_2[Regs[TM] & 0x0F]
+                               : m_Thermometer_Map_1[Regs[TM] & 0x0F] ;
+               state->m_Regs[TM] &= ~0x10;        /* Thermometer off */
+               status = UpdateReg(state, TM);
+               if (status < 0)
+                       break;
+               state->m_Regs[EP4] &= ~0x03;       /* CAL_mode = 0 ????????? */
+               status = UpdateReg(state, EP4);
+               if (status < 0)
+                       break;
+       } while (0);
+
+       return status;
+}
+
+static int StandBy(struct tda_state *state)
+{
+       int status = 0;
+       do {
+               state->m_Regs[EB12] &= ~0x20;  /* PD_AGC1_Det = 0 */
+               status = UpdateReg(state, EB12);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB18] &= ~0x83;  /* AGC1_loop_off = 0, AGC1_Gain = 6 dB */
+               status = UpdateReg(state, EB18);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB21] |= 0x03; /* AGC2_Gain = -6 dB */
+               state->m_Regs[EP3] = state->m_EP3_Standby;
+               status = UpdateReg(state, EP3);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LP_Fc[2] = 0 */
+               status = UpdateRegs(state, EB21, EB23);
+               if (status < 0)
+                       break;
+       } while (0);
+       return status;
+}
+
+static int CalcMainPLL(struct tda_state *state, u32 freq)
+{
+
+       u8  PostDiv;
+       u8  Div;
+       u64 OscFreq;
+       u32 MainDiv;
+
+       if (!SearchMap3(m_Main_PLL_Map, freq, &PostDiv, &Div))
+               return -EINVAL;
+
+       OscFreq = (u64) freq * (u64) Div;
+       OscFreq *= (u64) 16384;
+       do_div(OscFreq, (u64)16000000);
+       MainDiv = OscFreq;
+
+       state->m_Regs[MPD] = PostDiv & 0x77;
+       state->m_Regs[MD1] = ((MainDiv >> 16) & 0x7F);
+       state->m_Regs[MD2] = ((MainDiv >>  8) & 0xFF);
+       state->m_Regs[MD3] = (MainDiv & 0xFF);
+
+       return UpdateRegs(state, MPD, MD3);
+}
+
+static int CalcCalPLL(struct tda_state *state, u32 freq)
+{
+       u8 PostDiv;
+       u8 Div;
+       u64 OscFreq;
+       u32 CalDiv;
+
+       if (!SearchMap3(m_Cal_PLL_Map, freq, &PostDiv, &Div))
+               return -EINVAL;
+
+       OscFreq = (u64)freq * (u64)Div;
+       /* CalDiv = u32( OscFreq * 16384 / 16000000 ); */
+       OscFreq *= (u64)16384;
+       do_div(OscFreq, (u64)16000000);
+       CalDiv = OscFreq;
+
+       state->m_Regs[CPD] = PostDiv;
+       state->m_Regs[CD1] = ((CalDiv >> 16) & 0xFF);
+       state->m_Regs[CD2] = ((CalDiv >>  8) & 0xFF);
+       state->m_Regs[CD3] = (CalDiv & 0xFF);
+
+       return UpdateRegs(state, CPD, CD3);
+}
+
+static int CalibrateRF(struct tda_state *state,
+                      u8 RFBand, u32 freq, s32 *pCprog)
+{
+       int status = 0;
+       u8 Regs[NUM_REGS];
+       do {
+               u8 BP_Filter = 0;
+               u8 GainTaper = 0;
+               u8 RFC_K = 0;
+               u8 RFC_M = 0;
+
+               state->m_Regs[EP4] &= ~0x03; /* CAL_mode = 0 */
+               status = UpdateReg(state, EP4);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB18] |= 0x03;  /* AGC1_Gain = 3 */
+               status = UpdateReg(state, EB18);
+               if (status < 0)
+                       break;
+
+               /* Switching off LT (as datasheet says) causes calibration on C1 to fail */
+               /* (Readout of Cprog is allways 255) */
+               if (state->m_Regs[ID] != 0x83)    /* C1: ID == 83, C2: ID == 84 */
+                       state->m_Regs[EP3] |= 0x40; /* SM_LT = 1 */
+
+               if (!(SearchMap1(m_BP_Filter_Map, freq, &BP_Filter) &&
+                       SearchMap1(m_GainTaper_Map, freq, &GainTaper) &&
+                       SearchMap3(m_KM_Map, freq, &RFC_K, &RFC_M)))
+                       return -EINVAL;
+
+               state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | BP_Filter;
+               state->m_Regs[EP2] = (RFBand << 5) | GainTaper;
+
+               state->m_Regs[EB13] = (state->m_Regs[EB13] & ~0x7C) | (RFC_K << 4) | (RFC_M << 2);
+
+               status = UpdateRegs(state, EP1, EP3);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EB13);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB4] |= 0x20;    /* LO_ForceSrce = 1 */
+               status = UpdateReg(state, EB4);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB7] |= 0x20;    /* CAL_ForceSrce = 1 */
+               status = UpdateReg(state, EB7);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB14] = 0; /* RFC_Cprog = 0 */
+               status = UpdateReg(state, EB14);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB20] &= ~0x20;  /* ForceLock = 0; */
+               status = UpdateReg(state, EB20);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EP4] |= 0x03;  /* CAL_Mode = 3 */
+               status = UpdateRegs(state, EP4, EP5);
+               if (status < 0)
+                       break;
+
+               status = CalcCalPLL(state, freq);
+               if (status < 0)
+                       break;
+               status = CalcMainPLL(state, freq + 1000000);
+               if (status < 0)
+                       break;
+
+               msleep(5);
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB4] &= ~0x20;    /* LO_ForceSrce = 0 */
+               status = UpdateReg(state, EB4);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EB7] &= ~0x20;    /* CAL_ForceSrce = 0 */
+               status = UpdateReg(state, EB7);
+               if (status < 0)
+                       break;
+               msleep(10);
+
+               state->m_Regs[EB20] |= 0x20;  /* ForceLock = 1; */
+               status = UpdateReg(state, EB20);
+               if (status < 0)
+                       break;
+               msleep(60);
+
+               state->m_Regs[EP4] &= ~0x03;  /* CAL_Mode = 0 */
+               state->m_Regs[EP3] &= ~0x40; /* SM_LT = 0 */
+               state->m_Regs[EB18] &= ~0x03;  /* AGC1_Gain = 0 */
+               status = UpdateReg(state, EB18);
+               if (status < 0)
+                       break;
+               status = UpdateRegs(state, EP3, EP4);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+
+               status = ReadExtented(state, Regs);
+               if (status < 0)
+                       break;
+
+               *pCprog = Regs[EB14];
+
+       } while (0);
+       return status;
+}
+
+static int RFTrackingFiltersInit(struct tda_state *state,
+                                u8 RFBand)
+{
+       int status = 0;
+
+       u32   RF1 = m_RF_Band_Map[RFBand].m_RF1_Default;
+       u32   RF2 = m_RF_Band_Map[RFBand].m_RF2_Default;
+       u32   RF3 = m_RF_Band_Map[RFBand].m_RF3_Default;
+       bool    bcal = false;
+
+       s32    Cprog_cal1 = 0;
+       s32    Cprog_table1 = 0;
+       s32    Cprog_cal2 = 0;
+       s32    Cprog_table2 = 0;
+       s32    Cprog_cal3 = 0;
+       s32    Cprog_table3 = 0;
+
+       state->m_RF_A1[RFBand] = 0;
+       state->m_RF_B1[RFBand] = 0;
+       state->m_RF_A2[RFBand] = 0;
+       state->m_RF_B2[RFBand] = 0;
+
+       do {
+               status = PowerScan(state, RFBand, RF1, &RF1, &bcal);
+               if (status < 0)
+                       break;
+               if (bcal) {
+                       status = CalibrateRF(state, RFBand, RF1, &Cprog_cal1);
+                       if (status < 0)
+                               break;
+               }
+               SearchMap2(m_RF_Cal_Map, RF1, &Cprog_table1);
+               if (!bcal)
+                       Cprog_cal1 = Cprog_table1;
+               state->m_RF_B1[RFBand] = Cprog_cal1 - Cprog_table1;
+               /* state->m_RF_A1[RF_Band] = ???? */
+
+               if (RF2 == 0)
+                       break;
+
+               status = PowerScan(state, RFBand, RF2, &RF2, &bcal);
+               if (status < 0)
+                       break;
+               if (bcal) {
+                       status = CalibrateRF(state, RFBand, RF2, &Cprog_cal2);
+                       if (status < 0)
+                               break;
+               }
+               SearchMap2(m_RF_Cal_Map, RF2, &Cprog_table2);
+               if (!bcal)
+                       Cprog_cal2 = Cprog_table2;
+
+               state->m_RF_A1[RFBand] =
+                       (Cprog_cal2 - Cprog_table2 - Cprog_cal1 + Cprog_table1) /
+                       ((s32)(RF2) - (s32)(RF1));
+
+               if (RF3 == 0)
+                       break;
+
+               status = PowerScan(state, RFBand, RF3, &RF3, &bcal);
+               if (status < 0)
+                       break;
+               if (bcal) {
+                       status = CalibrateRF(state, RFBand, RF3, &Cprog_cal3);
+                       if (status < 0)
+                               break;
+               }
+               SearchMap2(m_RF_Cal_Map, RF3, &Cprog_table3);
+               if (!bcal)
+                       Cprog_cal3 = Cprog_table3;
+               state->m_RF_A2[RFBand] = (Cprog_cal3 - Cprog_table3 - Cprog_cal2 + Cprog_table2) / ((s32)(RF3) - (s32)(RF2));
+               state->m_RF_B2[RFBand] = Cprog_cal2 - Cprog_table2;
+
+       } while (0);
+
+       state->m_RF1[RFBand] = RF1;
+       state->m_RF2[RFBand] = RF2;
+       state->m_RF3[RFBand] = RF3;
+
+#if 0
+       printk(KERN_ERR "tda18271c2dd: %s %d RF1 = %d A1 = %d B1 = %d RF2 = %d A2 = %d B2 = %d RF3 = %d\n", __func__,
+              RFBand, RF1, state->m_RF_A1[RFBand], state->m_RF_B1[RFBand], RF2,
+              state->m_RF_A2[RFBand], state->m_RF_B2[RFBand], RF3);
+#endif
+
+       return status;
+}
+
+static int PowerScan(struct tda_state *state,
+                    u8 RFBand, u32 RF_in, u32 *pRF_Out, bool *pbcal)
+{
+       int status = 0;
+       do {
+               u8   Gain_Taper = 0;
+               s32  RFC_Cprog = 0;
+               u8   CID_Target = 0;
+               u8   CountLimit = 0;
+               u32  freq_MainPLL;
+               u8   Regs[NUM_REGS];
+               u8   CID_Gain;
+               s32  Count = 0;
+               int  sign  = 1;
+               bool wait = false;
+
+               if (!(SearchMap2(m_RF_Cal_Map, RF_in, &RFC_Cprog) &&
+                     SearchMap1(m_GainTaper_Map, RF_in, &Gain_Taper) &&
+                     SearchMap3(m_CID_Target_Map, RF_in, &CID_Target, &CountLimit))) {
+
+                       printk(KERN_ERR "tda18271c2dd: %s Search map failed\n", __func__);
+                       return -EINVAL;
+               }
+
+               state->m_Regs[EP2] = (RFBand << 5) | Gain_Taper;
+               state->m_Regs[EB14] = (RFC_Cprog);
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EB14);
+               if (status < 0)
+                       break;
+
+               freq_MainPLL = RF_in + 1000000;
+               status = CalcMainPLL(state, freq_MainPLL);
+               if (status < 0)
+                       break;
+               msleep(5);
+               state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x03) | 1;    /* CAL_mode = 1 */
+               status = UpdateReg(state, EP4);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP2);  /* Launch power measurement */
+               if (status < 0)
+                       break;
+               status = ReadExtented(state, Regs);
+               if (status < 0)
+                       break;
+               CID_Gain = Regs[EB10] & 0x3F;
+               state->m_Regs[ID] = Regs[ID];  /* Chip version, (needed for C1 workarround in CalibrateRF) */
+
+               *pRF_Out = RF_in;
+
+               while (CID_Gain < CID_Target) {
+                       freq_MainPLL = RF_in + sign * Count + 1000000;
+                       status = CalcMainPLL(state, freq_MainPLL);
+                       if (status < 0)
+                               break;
+                       msleep(wait ? 5 : 1);
+                       wait = false;
+                       status = UpdateReg(state, EP2);  /* Launch power measurement */
+                       if (status < 0)
+                               break;
+                       status = ReadExtented(state, Regs);
+                       if (status < 0)
+                               break;
+                       CID_Gain = Regs[EB10] & 0x3F;
+                       Count += 200000;
+
+                       if (Count < CountLimit * 100000)
+                               continue;
+                       if (sign < 0)
+                               break;
+
+                       sign = -sign;
+                       Count = 200000;
+                       wait = true;
+               }
+               status = status;
+               if (status < 0)
+                       break;
+               if (CID_Gain >= CID_Target) {
+                       *pbcal = true;
+                       *pRF_Out = freq_MainPLL - 1000000;
+               } else
+                       *pbcal = false;
+       } while (0);
+
+       return status;
+}
+
+static int PowerScanInit(struct tda_state *state)
+{
+       int status = 0;
+       do {
+               state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | 0x12;
+               state->m_Regs[EP4] = (state->m_Regs[EP4] & ~0x1F); /* If level = 0, Cal mode = 0 */
+               status = UpdateRegs(state, EP3, EP4);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB18] = (state->m_Regs[EB18] & ~0x03); /* AGC 1 Gain = 0 */
+               status = UpdateReg(state, EB18);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB21] = (state->m_Regs[EB21] & ~0x03); /* AGC 2 Gain = 0 (Datasheet = 3) */
+               state->m_Regs[EB23] = (state->m_Regs[EB23] | 0x06); /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */
+               status = UpdateRegs(state, EB21, EB23);
+               if (status < 0)
+                       break;
+       } while (0);
+       return status;
+}
+
+static int CalcRFFilterCurve(struct tda_state *state)
+{
+       int status = 0;
+       do {
+               msleep(200);      /* Temperature stabilisation */
+               status = PowerScanInit(state);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 0);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 1);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 2);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 3);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 4);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 5);
+               if (status < 0)
+                       break;
+               status = RFTrackingFiltersInit(state, 6);
+               if (status < 0)
+                       break;
+               status = ThermometerRead(state, &state->m_TMValue_RFCal); /* also switches off Cal mode !!! */
+               if (status < 0)
+                       break;
+       } while (0);
+
+       return status;
+}
+
+static int FixedContentsI2CUpdate(struct tda_state *state)
+{
+       static u8 InitRegs[] = {
+               0x08, 0x80, 0xC6,
+               0xDF, 0x16, 0x60, 0x80,
+               0x80, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00,
+               0xFC, 0x01, 0x84, 0x41,
+               0x01, 0x84, 0x40, 0x07,
+               0x00, 0x00, 0x96, 0x3F,
+               0xC1, 0x00, 0x8F, 0x00,
+               0x00, 0x8C, 0x00, 0x20,
+               0xB3, 0x48, 0xB0,
+       };
+       int status = 0;
+       memcpy(&state->m_Regs[TM], InitRegs, EB23 - TM + 1);
+       do {
+               status = UpdateRegs(state, TM, EB23);
+               if (status < 0)
+                       break;
+
+               /* AGC1 gain setup */
+               state->m_Regs[EB17] = 0x00;
+               status = UpdateReg(state, EB17);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB17] = 0x03;
+               status = UpdateReg(state, EB17);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB17] = 0x43;
+               status = UpdateReg(state, EB17);
+               if (status < 0)
+                       break;
+               state->m_Regs[EB17] = 0x4C;
+               status = UpdateReg(state, EB17);
+               if (status < 0)
+                       break;
+
+               /* IRC Cal Low band */
+               state->m_Regs[EP3] = 0x1F;
+               state->m_Regs[EP4] = 0x66;
+               state->m_Regs[EP5] = 0x81;
+               state->m_Regs[CPD] = 0xCC;
+               state->m_Regs[CD1] = 0x6C;
+               state->m_Regs[CD2] = 0x00;
+               state->m_Regs[CD3] = 0x00;
+               state->m_Regs[MPD] = 0xC5;
+               state->m_Regs[MD1] = 0x77;
+               state->m_Regs[MD2] = 0x08;
+               state->m_Regs[MD3] = 0x00;
+               status = UpdateRegs(state, EP2, MD3); /* diff between sw and datasheet (ep3-md3) */
+               if (status < 0)
+                       break;
+
+#if 0
+               state->m_Regs[EB4] = 0x61;          /* missing in sw */
+               status = UpdateReg(state, EB4);
+               if (status < 0)
+                       break;
+               msleep(1);
+               state->m_Regs[EB4] = 0x41;
+               status = UpdateReg(state, EB4);
+               if (status < 0)
+                       break;
+#endif
+
+               msleep(5);
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+               msleep(5);
+
+               state->m_Regs[EP5] = 0x85;
+               state->m_Regs[CPD] = 0xCB;
+               state->m_Regs[CD1] = 0x66;
+               state->m_Regs[CD2] = 0x70;
+               status = UpdateRegs(state, EP3, CD3);
+               if (status < 0)
+                       break;
+               msleep(5);
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               msleep(30);
+
+               /* IRC Cal mid band */
+               state->m_Regs[EP5] = 0x82;
+               state->m_Regs[CPD] = 0xA8;
+               state->m_Regs[CD2] = 0x00;
+               state->m_Regs[MPD] = 0xA1; /* Datasheet = 0xA9 */
+               state->m_Regs[MD1] = 0x73;
+               state->m_Regs[MD2] = 0x1A;
+               status = UpdateRegs(state, EP3, MD3);
+               if (status < 0)
+                       break;
+
+               msleep(5);
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+               msleep(5);
+
+               state->m_Regs[EP5] = 0x86;
+               state->m_Regs[CPD] = 0xA8;
+               state->m_Regs[CD1] = 0x66;
+               state->m_Regs[CD2] = 0xA0;
+               status = UpdateRegs(state, EP3, CD3);
+               if (status < 0)
+                       break;
+               msleep(5);
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               msleep(30);
+
+               /* IRC Cal high band */
+               state->m_Regs[EP5] = 0x83;
+               state->m_Regs[CPD] = 0x98;
+               state->m_Regs[CD1] = 0x65;
+               state->m_Regs[CD2] = 0x00;
+               state->m_Regs[MPD] = 0x91;  /* Datasheet = 0x91 */
+               state->m_Regs[MD1] = 0x71;
+               state->m_Regs[MD2] = 0xCD;
+               status = UpdateRegs(state, EP3, MD3);
+               if (status < 0)
+                       break;
+               msleep(5);
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+               msleep(5);
+               state->m_Regs[EP5] = 0x87;
+               state->m_Regs[CD1] = 0x65;
+               state->m_Regs[CD2] = 0x50;
+               status = UpdateRegs(state, EP3, CD3);
+               if (status < 0)
+                       break;
+               msleep(5);
+               status = UpdateReg(state, EP2);
+               if (status < 0)
+                       break;
+               msleep(30);
+
+               /* Back to normal */
+               state->m_Regs[EP4] = 0x64;
+               status = UpdateReg(state, EP4);
+               if (status < 0)
+                       break;
+               status = UpdateReg(state, EP1);
+               if (status < 0)
+                       break;
+
+       } while (0);
+       return status;
+}
+
+static int InitCal(struct tda_state *state)
+{
+       int status = 0;
+
+       do {
+               status = FixedContentsI2CUpdate(state);
+               if (status < 0)
+                       break;
+               status = CalcRFFilterCurve(state);
+               if (status < 0)
+                       break;
+               status = StandBy(state);
+               if (status < 0)
+                       break;
+               /* m_bInitDone = true; */
+       } while (0);
+       return status;
+};
+
+static int RFTrackingFiltersCorrection(struct tda_state *state,
+                                      u32 Frequency)
+{
+       int status = 0;
+       s32 Cprog_table;
+       u8 RFBand;
+       u8 dCoverdT;
+
+       if (!SearchMap2(m_RF_Cal_Map, Frequency, &Cprog_table) ||
+           !SearchMap4(m_RF_Band_Map, Frequency, &RFBand) ||
+           !SearchMap1(m_RF_Cal_DC_Over_DT_Map, Frequency, &dCoverdT))
+
+               return -EINVAL;
+
+       do {
+               u8 TMValue_Current;
+               u32   RF1 = state->m_RF1[RFBand];
+               u32   RF2 = state->m_RF1[RFBand];
+               u32   RF3 = state->m_RF1[RFBand];
+               s32    RF_A1 = state->m_RF_A1[RFBand];
+               s32    RF_B1 = state->m_RF_B1[RFBand];
+               s32    RF_A2 = state->m_RF_A2[RFBand];
+               s32    RF_B2 = state->m_RF_B2[RFBand];
+               s32 Capprox = 0;
+               int TComp;
+
+               state->m_Regs[EP3] &= ~0xE0;  /* Power up */
+               status = UpdateReg(state, EP3);
+               if (status < 0)
+                       break;
+
+               status = ThermometerRead(state, &TMValue_Current);
+               if (status < 0)
+                       break;
+
+               if (RF3 == 0 || Frequency < RF2)
+                       Capprox = RF_A1 * ((s32)(Frequency) - (s32)(RF1)) + RF_B1 + Cprog_table;
+               else
+                       Capprox = RF_A2 * ((s32)(Frequency) - (s32)(RF2)) + RF_B2 + Cprog_table;
+
+               TComp = (int)(dCoverdT) * ((int)(TMValue_Current) - (int)(state->m_TMValue_RFCal))/1000;
+
+               Capprox += TComp;
+
+               if (Capprox < 0)
+                       Capprox = 0;
+               else if (Capprox > 255)
+                       Capprox = 255;
+
+
+               /* TODO Temperature compensation. There is defenitely a scale factor */
+               /*      missing in the datasheet, so leave it out for now.           */
+               state->m_Regs[EB14] = Capprox;
+
+               status = UpdateReg(state, EB14);
+               if (status < 0)
+                       break;
+
+       } while (0);
+       return status;
+}
+
+static int ChannelConfiguration(struct tda_state *state,
+                               u32 Frequency, int Standard)
+{
+
+       s32 IntermediateFrequency = m_StandardTable[Standard].m_IFFrequency;
+       int status = 0;
+
+       u8 BP_Filter = 0;
+       u8 RF_Band = 0;
+       u8 GainTaper = 0;
+       u8 IR_Meas = 0;
+
+       state->IF = IntermediateFrequency;
+       /* printk("tda18271c2dd: %s Freq = %d Standard = %d IF = %d\n", __func__, Frequency, Standard, IntermediateFrequency); */
+       /* get values from tables */
+
+       if (!(SearchMap1(m_BP_Filter_Map, Frequency, &BP_Filter) &&
+              SearchMap1(m_GainTaper_Map, Frequency, &GainTaper) &&
+              SearchMap1(m_IR_Meas_Map, Frequency, &IR_Meas) &&
+              SearchMap4(m_RF_Band_Map, Frequency, &RF_Band))) {
+
+               printk(KERN_ERR "tda18271c2dd: %s SearchMap failed\n", __func__);
+               return -EINVAL;
+       }
+
+       do {
+               state->m_Regs[EP3] = (state->m_Regs[EP3] & ~0x1F) | m_StandardTable[Standard].m_EP3_4_0;
+               state->m_Regs[EP3] &= ~0x04;   /* switch RFAGC to high speed mode */
+
+               /* m_EP4 default for XToutOn, CAL_Mode (0) */
+               state->m_Regs[EP4] = state->m_EP4 | ((Standard > HF_AnalogMax) ? state->m_IFLevelDigital : state->m_IFLevelAnalog);
+               /* state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital; */
+               if (Standard <= HF_AnalogMax)
+                       state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelAnalog;
+               else if (Standard <= HF_ATSC)
+                       state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBT;
+               else if (Standard <= HF_DVBC)
+                       state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDVBC;
+               else
+                       state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital;
+
+               if ((Standard == HF_FM_Radio) && state->m_bFMInput)
+                       state->m_Regs[EP4] |= 80;
+
+               state->m_Regs[MPD] &= ~0x80;
+               if (Standard > HF_AnalogMax)
+                       state->m_Regs[MPD] |= 0x80; /* Add IF_notch for digital */
+
+               state->m_Regs[EB22] = m_StandardTable[Standard].m_EB22;
+
+               /* Note: This is missing from flowchart in TDA18271 specification ( 1.5 MHz cutoff for FM ) */
+               if (Standard == HF_FM_Radio)
+                       state->m_Regs[EB23] |=  0x06; /* ForceLP_Fc2_En = 1, LPFc[2] = 1 */
+               else
+                       state->m_Regs[EB23] &= ~0x06; /* ForceLP_Fc2_En = 0, LPFc[2] = 0 */
+
+               status = UpdateRegs(state, EB22, EB23);
+               if (status < 0)
+                       break;
+
+               state->m_Regs[EP1] = (state->m_Regs[EP1] & ~0x07) | 0x40 | BP_Filter;   /* Dis_Power_level = 1, Filter */
+               state->m_Regs[EP5] = (state->m_Regs[EP5] & ~0x07) | IR_Meas;
+               state->m_Regs[EP2] = (RF_Band << 5) | GainTaper;
+
+               state->m_Regs[EB1] = (state->m_Regs[EB1] & ~0x07) |
+                       (state->m_bMaster ? 0x04 : 0x00); /* CALVCO_FortLOn = MS */
+               /* AGC1_always_master = 0 */
+               /* AGC_firstn = 0 */
+               status = UpdateReg(state, EB1);
+               if (status < 0)
+                       break;
+
+               if (state->m_bMaster) {
+                       status = CalcMainPLL(state, Frequency + IntermediateFrequency);
+                       if (status < 0)
+                               break;
+                       status = UpdateRegs(state, TM, EP5);
+                       if (status < 0)
+                               break;
+                       state->m_Regs[EB4] |= 0x20;    /* LO_forceSrce = 1 */
+                       status = UpdateReg(state, EB4);
+                       if (status < 0)
+                               break;
+                       msleep(1);
+                       state->m_Regs[EB4] &= ~0x20;   /* LO_forceSrce = 0 */
+                       status = UpdateReg(state, EB4);
+                       if (status < 0)
+                               break;
+               } else {
+                       u8 PostDiv = 0;
+                       u8 Div;
+                       status = CalcCalPLL(state, Frequency + IntermediateFrequency);
+                       if (status < 0)
+                               break;
+
+                       SearchMap3(m_Cal_PLL_Map, Frequency + IntermediateFrequency, &PostDiv, &Div);
+                       state->m_Regs[MPD] = (state->m_Regs[MPD] & ~0x7F) | (PostDiv & 0x77);
+                       status = UpdateReg(state, MPD);
+                       if (status < 0)
+                               break;
+                       status = UpdateRegs(state, TM, EP5);
+                       if (status < 0)
+                               break;
+
+                       state->m_Regs[EB7] |= 0x20;    /* CAL_forceSrce = 1 */
+                       status = UpdateReg(state, EB7);
+                       if (status < 0)
+                               break;
+                       msleep(1);
+                       state->m_Regs[EB7] &= ~0x20;   /* CAL_forceSrce = 0 */
+                       status = UpdateReg(state, EB7);
+                       if (status < 0)
+                               break;
+               }
+               msleep(20);
+               if (Standard != HF_FM_Radio)
+                       state->m_Regs[EP3] |= 0x04;    /* RFAGC to normal mode */
+               status = UpdateReg(state, EP3);
+               if (status < 0)
+                       break;
+
+       } while (0);
+       return status;
+}
+
+static int sleep(struct dvb_frontend *fe)
+{
+       struct tda_state *state = fe->tuner_priv;
+
+       StandBy(state);
+       return 0;
+}
+
+static int init(struct dvb_frontend *fe)
+{
+       return 0;
+}
+
+static int release(struct dvb_frontend *fe)
+{
+       kfree(fe->tuner_priv);
+       fe->tuner_priv = NULL;
+       return 0;
+}
+
+/*
+ * As defined on EN 300 429 Annex A and on ITU-T J.83 annex A, the DVB-C
+ * roll-off factor is 0.15.
+ * According with the specs, the amount of the needed bandwith is given by:
+ *     Bw = Symbol_rate * (1 + 0.15)
+ * As such, the maximum symbol rate supported by 6 MHz is
+ *     max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
+ *NOTE: For ITU-T J.83 Annex C, the roll-off factor is 0.13. So:
+ *     max_symbol_rate = 6 MHz / 1.13 = 5309735 Baud
+ *     That means that an adjustment is needed for Japan,
+ *     but, as currently DRX-K is hardcoded to Annex A, let's stick
+ *     with 0.15 roll-off factor.
+ */
+#define MAX_SYMBOL_RATE_6MHz   5217391
+
+static int set_params(struct dvb_frontend *fe,
+                     struct dvb_frontend_parameters *params)
+{
+       struct tda_state *state = fe->tuner_priv;
+       int status = 0;
+       int Standard;
+
+       state->m_Frequency = params->frequency;
+
+       if (fe->ops.info.type == FE_OFDM)
+               switch (params->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       Standard = HF_DVBT_6MHZ;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       Standard = HF_DVBT_7MHZ;
+                       break;
+               default:
+               case BANDWIDTH_8_MHZ:
+                       Standard = HF_DVBT_8MHZ;
+                       break;
+               }
+       else if (fe->ops.info.type == FE_QAM) {
+               if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz)
+                       Standard = HF_DVBC_6MHZ;
+               else
+                       Standard = HF_DVBC_8MHZ;
+       } else
+               return -EINVAL;
+       do {
+               status = RFTrackingFiltersCorrection(state, params->frequency);
+               if (status < 0)
+                       break;
+               status = ChannelConfiguration(state, params->frequency, Standard);
+               if (status < 0)
+                       break;
+
+               msleep(state->m_SettlingTime);  /* Allow AGC's to settle down */
+       } while (0);
+       return status;
+}
+
+#if 0
+static int GetSignalStrength(s32 *pSignalStrength, u32 RFAgc, u32 IFAgc)
+{
+       if (IFAgc < 500) {
+               /* Scale this from 0 to 50000 */
+               *pSignalStrength = IFAgc * 100;
+       } else {
+               /* Scale range 500-1500 to 50000-80000 */
+               *pSignalStrength = 50000 + (IFAgc - 500) * 30;
+       }
+
+       return 0;
+}
+#endif
+
+static int get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct tda_state *state = fe->tuner_priv;
+
+       *frequency = state->IF;
+       return 0;
+}
+
+static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       /* struct tda_state *state = fe->tuner_priv; */
+       /* *bandwidth = priv->bandwidth; */
+       return 0;
+}
+
+
+static struct dvb_tuner_ops tuner_ops = {
+       .info = {
+               .name = "NXP TDA18271C2D",
+               .frequency_min  =  47125000,
+               .frequency_max  = 865000000,
+               .frequency_step =     62500
+       },
+       .init              = init,
+       .sleep             = sleep,
+       .set_params        = set_params,
+       .release           = release,
+       .get_frequency     = get_frequency,
+       .get_bandwidth     = get_bandwidth,
+};
+
+struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
+                                        struct i2c_adapter *i2c, u8 adr)
+{
+       struct tda_state *state;
+
+       state = kzalloc(sizeof(struct tda_state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       fe->tuner_priv = state;
+       state->adr = adr;
+       state->i2c = i2c;
+       memcpy(&fe->ops.tuner_ops, &tuner_ops, sizeof(struct dvb_tuner_ops));
+       reset(state);
+       InitCal(state);
+
+       return fe;
+}
+EXPORT_SYMBOL_GPL(tda18271c2dd_attach);
+
+MODULE_DESCRIPTION("TDA18271C2 driver");
+MODULE_AUTHOR("DD");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda18271c2dd.h b/drivers/media/dvb/frontends/tda18271c2dd.h
new file mode 100644 (file)
index 0000000..1389c74
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _TDA18271C2DD_H_
+#define _TDA18271C2DD_H_
+#if defined(CONFIG_DVB_TDA18271C2DD) || (defined(CONFIG_DVB_TDA18271C2DD_MODULE) \
+        && defined(MODULE))
+struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
+                                        struct i2c_adapter *i2c, u8 adr);
+#else
+static inline struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
+                                        struct i2c_adapter *i2c, u8 adr)
+{
+        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+        return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb/frontends/tda18271c2dd_maps.h b/drivers/media/dvb/frontends/tda18271c2dd_maps.h
new file mode 100644 (file)
index 0000000..b87661b
--- /dev/null
@@ -0,0 +1,814 @@
+enum HF_S {
+       HF_None = 0, HF_B, HF_DK, HF_G, HF_I, HF_L, HF_L1, HF_MN, HF_FM_Radio,
+       HF_AnalogMax, HF_DVBT_6MHZ, HF_DVBT_7MHZ, HF_DVBT_8MHZ,
+       HF_DVBT, HF_ATSC,  HF_DVBC_6MHZ,  HF_DVBC_7MHZ,
+       HF_DVBC_8MHZ, HF_DVBC
+};
+
+struct SStandardParam m_StandardTable[] = {
+       {       0,        0, 0x00, 0x00 },    /* HF_None */
+       { 6000000,  7000000, 0x1D, 0x2C },    /* HF_B, */
+       { 6900000,  8000000, 0x1E, 0x2C },    /* HF_DK, */
+       { 7100000,  8000000, 0x1E, 0x2C },    /* HF_G, */
+       { 7250000,  8000000, 0x1E, 0x2C },    /* HF_I, */
+       { 6900000,  8000000, 0x1E, 0x2C },    /* HF_L, */
+       { 1250000,  8000000, 0x1E, 0x2C },    /* HF_L1, */
+       { 5400000,  6000000, 0x1C, 0x2C },    /* HF_MN, */
+       { 1250000,   500000, 0x18, 0x2C },    /* HF_FM_Radio, */
+       {       0,        0, 0x00, 0x00 },    /* HF_AnalogMax (Unused) */
+       { 3300000,  6000000, 0x1C, 0x58 },    /* HF_DVBT_6MHZ */
+       { 3500000,  7000000, 0x1C, 0x37 },    /* HF_DVBT_7MHZ */
+       { 4000000,  8000000, 0x1D, 0x37 },    /* HF_DVBT_8MHZ */
+       {       0,        0, 0x00, 0x00 },    /* HF_DVBT (Unused) */
+       { 5000000,  6000000, 0x1C, 0x37 },    /* HF_ATSC  (center = 3.25 MHz) */
+       { 4000000,  6000000, 0x1D, 0x58 },    /* HF_DVBC_6MHZ (Chicago) */
+       { 4500000,  7000000, 0x1E, 0x37 },    /* HF_DVBC_7MHZ (not documented by NXP) */
+       { 5000000,  8000000, 0x1F, 0x37 },    /* HF_DVBC_8MHZ */
+       {       0,        0, 0x00, 0x00 },    /* HF_DVBC (Unused) */
+};
+
+struct SMap  m_BP_Filter_Map[] = {
+       {   62000000,  0x00 },
+       {   84000000,  0x01 },
+       {  100000000,  0x02 },
+       {  140000000,  0x03 },
+       {  170000000,  0x04 },
+       {  180000000,  0x05 },
+       {  865000000,  0x06 },
+       {          0,  0x00 },    /* Table End */
+};
+
+static struct SMapI m_RF_Cal_Map[] = {
+       {   41000000,  0x0F },
+       {   43000000,  0x1C },
+       {   45000000,  0x2F },
+       {   46000000,  0x39 },
+       {   47000000,  0x40 },
+       {   47900000,  0x50 },
+       {   49100000,  0x16 },
+       {   50000000,  0x18 },
+       {   51000000,  0x20 },
+       {   53000000,  0x28 },
+       {   55000000,  0x2B },
+       {   56000000,  0x32 },
+       {   57000000,  0x35 },
+       {   58000000,  0x3E },
+       {   59000000,  0x43 },
+       {   60000000,  0x4E },
+       {   61100000,  0x55 },
+       {   63000000,  0x0F },
+       {   64000000,  0x11 },
+       {   65000000,  0x12 },
+       {   66000000,  0x15 },
+       {   67000000,  0x16 },
+       {   68000000,  0x17 },
+       {   70000000,  0x19 },
+       {   71000000,  0x1C },
+       {   72000000,  0x1D },
+       {   73000000,  0x1F },
+       {   74000000,  0x20 },
+       {   75000000,  0x21 },
+       {   76000000,  0x24 },
+       {   77000000,  0x25 },
+       {   78000000,  0x27 },
+       {   80000000,  0x28 },
+       {   81000000,  0x29 },
+       {   82000000,  0x2D },
+       {   83000000,  0x2E },
+       {   84000000,  0x2F },
+       {   85000000,  0x31 },
+       {   86000000,  0x33 },
+       {   87000000,  0x34 },
+       {   88000000,  0x35 },
+       {   89000000,  0x37 },
+       {   90000000,  0x38 },
+       {   91000000,  0x39 },
+       {   93000000,  0x3C },
+       {   94000000,  0x3E },
+       {   95000000,  0x3F },
+       {   96000000,  0x40 },
+       {   97000000,  0x42 },
+       {   99000000,  0x45 },
+       {  100000000,  0x46 },
+       {  102000000,  0x48 },
+       {  103000000,  0x4A },
+       {  105000000,  0x4D },
+       {  106000000,  0x4E },
+       {  107000000,  0x50 },
+       {  108000000,  0x51 },
+       {  110000000,  0x54 },
+       {  111000000,  0x56 },
+       {  112000000,  0x57 },
+       {  113000000,  0x58 },
+       {  114000000,  0x59 },
+       {  115000000,  0x5C },
+       {  116000000,  0x5D },
+       {  117000000,  0x5F },
+       {  119000000,  0x60 },
+       {  120000000,  0x64 },
+       {  121000000,  0x65 },
+       {  122000000,  0x66 },
+       {  123000000,  0x68 },
+       {  124000000,  0x69 },
+       {  125000000,  0x6C },
+       {  126000000,  0x6D },
+       {  127000000,  0x6E },
+       {  128000000,  0x70 },
+       {  129000000,  0x71 },
+       {  130000000,  0x75 },
+       {  131000000,  0x77 },
+       {  132000000,  0x78 },
+       {  133000000,  0x7B },
+       {  134000000,  0x7E },
+       {  135000000,  0x81 },
+       {  136000000,  0x82 },
+       {  137000000,  0x87 },
+       {  138000000,  0x88 },
+       {  139000000,  0x8D },
+       {  140000000,  0x8E },
+       {  141000000,  0x91 },
+       {  142000000,  0x95 },
+       {  143000000,  0x9A },
+       {  144000000,  0x9D },
+       {  145000000,  0xA1 },
+       {  146000000,  0xA2 },
+       {  147000000,  0xA4 },
+       {  148000000,  0xA9 },
+       {  149000000,  0xAE },
+       {  150000000,  0xB0 },
+       {  151000000,  0xB1 },
+       {  152000000,  0xB7 },
+       {  152600000,  0xBD },
+       {  154000000,  0x20 },
+       {  155000000,  0x22 },
+       {  156000000,  0x24 },
+       {  157000000,  0x25 },
+       {  158000000,  0x27 },
+       {  159000000,  0x29 },
+       {  160000000,  0x2C },
+       {  161000000,  0x2D },
+       {  163000000,  0x2E },
+       {  164000000,  0x2F },
+       {  164700000,  0x30 },
+       {  166000000,  0x11 },
+       {  167000000,  0x12 },
+       {  168000000,  0x13 },
+       {  169000000,  0x14 },
+       {  170000000,  0x15 },
+       {  172000000,  0x16 },
+       {  173000000,  0x17 },
+       {  174000000,  0x18 },
+       {  175000000,  0x1A },
+       {  176000000,  0x1B },
+       {  178000000,  0x1D },
+       {  179000000,  0x1E },
+       {  180000000,  0x1F },
+       {  181000000,  0x20 },
+       {  182000000,  0x21 },
+       {  183000000,  0x22 },
+       {  184000000,  0x24 },
+       {  185000000,  0x25 },
+       {  186000000,  0x26 },
+       {  187000000,  0x27 },
+       {  188000000,  0x29 },
+       {  189000000,  0x2A },
+       {  190000000,  0x2C },
+       {  191000000,  0x2D },
+       {  192000000,  0x2E },
+       {  193000000,  0x2F },
+       {  194000000,  0x30 },
+       {  195000000,  0x33 },
+       {  196000000,  0x35 },
+       {  198000000,  0x36 },
+       {  200000000,  0x38 },
+       {  201000000,  0x3C },
+       {  202000000,  0x3D },
+       {  203500000,  0x3E },
+       {  206000000,  0x0E },
+       {  208000000,  0x0F },
+       {  212000000,  0x10 },
+       {  216000000,  0x11 },
+       {  217000000,  0x12 },
+       {  218000000,  0x13 },
+       {  220000000,  0x14 },
+       {  222000000,  0x15 },
+       {  225000000,  0x16 },
+       {  228000000,  0x17 },
+       {  231000000,  0x18 },
+       {  234000000,  0x19 },
+       {  235000000,  0x1A },
+       {  236000000,  0x1B },
+       {  237000000,  0x1C },
+       {  240000000,  0x1D },
+       {  242000000,  0x1E },
+       {  244000000,  0x1F },
+       {  247000000,  0x20 },
+       {  249000000,  0x21 },
+       {  252000000,  0x22 },
+       {  253000000,  0x23 },
+       {  254000000,  0x24 },
+       {  256000000,  0x25 },
+       {  259000000,  0x26 },
+       {  262000000,  0x27 },
+       {  264000000,  0x28 },
+       {  267000000,  0x29 },
+       {  269000000,  0x2A },
+       {  271000000,  0x2B },
+       {  273000000,  0x2C },
+       {  275000000,  0x2D },
+       {  277000000,  0x2E },
+       {  279000000,  0x2F },
+       {  282000000,  0x30 },
+       {  284000000,  0x31 },
+       {  286000000,  0x32 },
+       {  287000000,  0x33 },
+       {  290000000,  0x34 },
+       {  293000000,  0x35 },
+       {  295000000,  0x36 },
+       {  297000000,  0x37 },
+       {  300000000,  0x38 },
+       {  303000000,  0x39 },
+       {  305000000,  0x3A },
+       {  306000000,  0x3B },
+       {  307000000,  0x3C },
+       {  310000000,  0x3D },
+       {  312000000,  0x3E },
+       {  315000000,  0x3F },
+       {  318000000,  0x40 },
+       {  320000000,  0x41 },
+       {  323000000,  0x42 },
+       {  324000000,  0x43 },
+       {  325000000,  0x44 },
+       {  327000000,  0x45 },
+       {  331000000,  0x46 },
+       {  334000000,  0x47 },
+       {  337000000,  0x48 },
+       {  339000000,  0x49 },
+       {  340000000,  0x4A },
+       {  341000000,  0x4B },
+       {  343000000,  0x4C },
+       {  345000000,  0x4D },
+       {  349000000,  0x4E },
+       {  352000000,  0x4F },
+       {  353000000,  0x50 },
+       {  355000000,  0x51 },
+       {  357000000,  0x52 },
+       {  359000000,  0x53 },
+       {  361000000,  0x54 },
+       {  362000000,  0x55 },
+       {  364000000,  0x56 },
+       {  368000000,  0x57 },
+       {  370000000,  0x58 },
+       {  372000000,  0x59 },
+       {  375000000,  0x5A },
+       {  376000000,  0x5B },
+       {  377000000,  0x5C },
+       {  379000000,  0x5D },
+       {  382000000,  0x5E },
+       {  384000000,  0x5F },
+       {  385000000,  0x60 },
+       {  386000000,  0x61 },
+       {  388000000,  0x62 },
+       {  390000000,  0x63 },
+       {  393000000,  0x64 },
+       {  394000000,  0x65 },
+       {  396000000,  0x66 },
+       {  397000000,  0x67 },
+       {  398000000,  0x68 },
+       {  400000000,  0x69 },
+       {  402000000,  0x6A },
+       {  403000000,  0x6B },
+       {  407000000,  0x6C },
+       {  408000000,  0x6D },
+       {  409000000,  0x6E },
+       {  410000000,  0x6F },
+       {  411000000,  0x70 },
+       {  412000000,  0x71 },
+       {  413000000,  0x72 },
+       {  414000000,  0x73 },
+       {  417000000,  0x74 },
+       {  418000000,  0x75 },
+       {  420000000,  0x76 },
+       {  422000000,  0x77 },
+       {  423000000,  0x78 },
+       {  424000000,  0x79 },
+       {  427000000,  0x7A },
+       {  428000000,  0x7B },
+       {  429000000,  0x7D },
+       {  432000000,  0x7F },
+       {  434000000,  0x80 },
+       {  435000000,  0x81 },
+       {  436000000,  0x83 },
+       {  437000000,  0x84 },
+       {  438000000,  0x85 },
+       {  439000000,  0x86 },
+       {  440000000,  0x87 },
+       {  441000000,  0x88 },
+       {  442000000,  0x89 },
+       {  445000000,  0x8A },
+       {  446000000,  0x8B },
+       {  447000000,  0x8C },
+       {  448000000,  0x8E },
+       {  449000000,  0x8F },
+       {  450000000,  0x90 },
+       {  452000000,  0x91 },
+       {  453000000,  0x93 },
+       {  454000000,  0x94 },
+       {  456000000,  0x96 },
+       {  457800000,  0x98 },
+       {  461000000,  0x11 },
+       {  468000000,  0x12 },
+       {  472000000,  0x13 },
+       {  473000000,  0x14 },
+       {  474000000,  0x15 },
+       {  481000000,  0x16 },
+       {  486000000,  0x17 },
+       {  491000000,  0x18 },
+       {  498000000,  0x19 },
+       {  499000000,  0x1A },
+       {  501000000,  0x1B },
+       {  506000000,  0x1C },
+       {  511000000,  0x1D },
+       {  516000000,  0x1E },
+       {  520000000,  0x1F },
+       {  521000000,  0x20 },
+       {  525000000,  0x21 },
+       {  529000000,  0x22 },
+       {  533000000,  0x23 },
+       {  539000000,  0x24 },
+       {  541000000,  0x25 },
+       {  547000000,  0x26 },
+       {  549000000,  0x27 },
+       {  551000000,  0x28 },
+       {  556000000,  0x29 },
+       {  561000000,  0x2A },
+       {  563000000,  0x2B },
+       {  565000000,  0x2C },
+       {  569000000,  0x2D },
+       {  571000000,  0x2E },
+       {  577000000,  0x2F },
+       {  580000000,  0x30 },
+       {  582000000,  0x31 },
+       {  584000000,  0x32 },
+       {  588000000,  0x33 },
+       {  591000000,  0x34 },
+       {  596000000,  0x35 },
+       {  598000000,  0x36 },
+       {  603000000,  0x37 },
+       {  604000000,  0x38 },
+       {  606000000,  0x39 },
+       {  612000000,  0x3A },
+       {  615000000,  0x3B },
+       {  617000000,  0x3C },
+       {  621000000,  0x3D },
+       {  622000000,  0x3E },
+       {  625000000,  0x3F },
+       {  632000000,  0x40 },
+       {  633000000,  0x41 },
+       {  634000000,  0x42 },
+       {  642000000,  0x43 },
+       {  643000000,  0x44 },
+       {  647000000,  0x45 },
+       {  650000000,  0x46 },
+       {  652000000,  0x47 },
+       {  657000000,  0x48 },
+       {  661000000,  0x49 },
+       {  662000000,  0x4A },
+       {  665000000,  0x4B },
+       {  667000000,  0x4C },
+       {  670000000,  0x4D },
+       {  673000000,  0x4E },
+       {  676000000,  0x4F },
+       {  677000000,  0x50 },
+       {  681000000,  0x51 },
+       {  683000000,  0x52 },
+       {  686000000,  0x53 },
+       {  688000000,  0x54 },
+       {  689000000,  0x55 },
+       {  691000000,  0x56 },
+       {  695000000,  0x57 },
+       {  698000000,  0x58 },
+       {  703000000,  0x59 },
+       {  704000000,  0x5A },
+       {  705000000,  0x5B },
+       {  707000000,  0x5C },
+       {  710000000,  0x5D },
+       {  712000000,  0x5E },
+       {  717000000,  0x5F },
+       {  718000000,  0x60 },
+       {  721000000,  0x61 },
+       {  722000000,  0x62 },
+       {  723000000,  0x63 },
+       {  725000000,  0x64 },
+       {  727000000,  0x65 },
+       {  730000000,  0x66 },
+       {  732000000,  0x67 },
+       {  735000000,  0x68 },
+       {  740000000,  0x69 },
+       {  741000000,  0x6A },
+       {  742000000,  0x6B },
+       {  743000000,  0x6C },
+       {  745000000,  0x6D },
+       {  747000000,  0x6E },
+       {  748000000,  0x6F },
+       {  750000000,  0x70 },
+       {  752000000,  0x71 },
+       {  754000000,  0x72 },
+       {  757000000,  0x73 },
+       {  758000000,  0x74 },
+       {  760000000,  0x75 },
+       {  763000000,  0x76 },
+       {  764000000,  0x77 },
+       {  766000000,  0x78 },
+       {  767000000,  0x79 },
+       {  768000000,  0x7A },
+       {  773000000,  0x7B },
+       {  774000000,  0x7C },
+       {  776000000,  0x7D },
+       {  777000000,  0x7E },
+       {  778000000,  0x7F },
+       {  779000000,  0x80 },
+       {  781000000,  0x81 },
+       {  783000000,  0x82 },
+       {  784000000,  0x83 },
+       {  785000000,  0x84 },
+       {  786000000,  0x85 },
+       {  793000000,  0x86 },
+       {  794000000,  0x87 },
+       {  795000000,  0x88 },
+       {  797000000,  0x89 },
+       {  799000000,  0x8A },
+       {  801000000,  0x8B },
+       {  802000000,  0x8C },
+       {  803000000,  0x8D },
+       {  804000000,  0x8E },
+       {  810000000,  0x90 },
+       {  811000000,  0x91 },
+       {  812000000,  0x92 },
+       {  814000000,  0x93 },
+       {  816000000,  0x94 },
+       {  817000000,  0x96 },
+       {  818000000,  0x97 },
+       {  820000000,  0x98 },
+       {  821000000,  0x99 },
+       {  822000000,  0x9A },
+       {  828000000,  0x9B },
+       {  829000000,  0x9D },
+       {  830000000,  0x9F },
+       {  831000000,  0xA0 },
+       {  833000000,  0xA1 },
+       {  835000000,  0xA2 },
+       {  836000000,  0xA3 },
+       {  837000000,  0xA4 },
+       {  838000000,  0xA6 },
+       {  840000000,  0xA8 },
+       {  842000000,  0xA9 },
+       {  845000000,  0xAA },
+       {  846000000,  0xAB },
+       {  847000000,  0xAD },
+       {  848000000,  0xAE },
+       {  852000000,  0xAF },
+       {  853000000,  0xB0 },
+       {  858000000,  0xB1 },
+       {  860000000,  0xB2 },
+       {  861000000,  0xB3 },
+       {  862000000,  0xB4 },
+       {  863000000,  0xB6 },
+       {  864000000,  0xB8 },
+       {  865000000,  0xB9 },
+       {          0,  0x00 },    /* Table End */
+};
+
+
+static struct SMap2  m_KM_Map[] = {
+       {   47900000,  3, 2 },
+       {   61100000,  3, 1 },
+       {  350000000,  3, 0 },
+       {  720000000,  2, 1 },
+       {  865000000,  3, 3 },
+       {          0,  0x00 },    /* Table End */
+};
+
+static struct SMap2 m_Main_PLL_Map[] = {
+       {  33125000, 0x57, 0xF0 },
+       {  35500000, 0x56, 0xE0 },
+       {  38188000, 0x55, 0xD0 },
+       {  41375000, 0x54, 0xC0 },
+       {  45125000, 0x53, 0xB0 },
+       {  49688000, 0x52, 0xA0 },
+       {  55188000, 0x51, 0x90 },
+       {  62125000, 0x50, 0x80 },
+       {  66250000, 0x47, 0x78 },
+       {  71000000, 0x46, 0x70 },
+       {  76375000, 0x45, 0x68 },
+       {  82750000, 0x44, 0x60 },
+       {  90250000, 0x43, 0x58 },
+       {  99375000, 0x42, 0x50 },
+       { 110375000, 0x41, 0x48 },
+       { 124250000, 0x40, 0x40 },
+       { 132500000, 0x37, 0x3C },
+       { 142000000, 0x36, 0x38 },
+       { 152750000, 0x35, 0x34 },
+       { 165500000, 0x34, 0x30 },
+       { 180500000, 0x33, 0x2C },
+       { 198750000, 0x32, 0x28 },
+       { 220750000, 0x31, 0x24 },
+       { 248500000, 0x30, 0x20 },
+       { 265000000, 0x27, 0x1E },
+       { 284000000, 0x26, 0x1C },
+       { 305500000, 0x25, 0x1A },
+       { 331000000, 0x24, 0x18 },
+       { 361000000, 0x23, 0x16 },
+       { 397500000, 0x22, 0x14 },
+       { 441500000, 0x21, 0x12 },
+       { 497000000, 0x20, 0x10 },
+       { 530000000, 0x17, 0x0F },
+       { 568000000, 0x16, 0x0E },
+       { 611000000, 0x15, 0x0D },
+       { 662000000, 0x14, 0x0C },
+       { 722000000, 0x13, 0x0B },
+       { 795000000, 0x12, 0x0A },
+       { 883000000, 0x11, 0x09 },
+       { 994000000, 0x10, 0x08 },
+       {         0, 0x00, 0x00 },    /* Table End */
+};
+
+static struct SMap2 m_Cal_PLL_Map[] = {
+       {  33813000, 0xDD, 0xD0 },
+       {  36625000, 0xDC, 0xC0 },
+       {  39938000, 0xDB, 0xB0 },
+       {  43938000, 0xDA, 0xA0 },
+       {  48813000, 0xD9, 0x90 },
+       {  54938000, 0xD8, 0x80 },
+       {  62813000, 0xD3, 0x70 },
+       {  67625000, 0xCD, 0x68 },
+       {  73250000, 0xCC, 0x60 },
+       {  79875000, 0xCB, 0x58 },
+       {  87875000, 0xCA, 0x50 },
+       {  97625000, 0xC9, 0x48 },
+       { 109875000, 0xC8, 0x40 },
+       { 125625000, 0xC3, 0x38 },
+       { 135250000, 0xBD, 0x34 },
+       { 146500000, 0xBC, 0x30 },
+       { 159750000, 0xBB, 0x2C },
+       { 175750000, 0xBA, 0x28 },
+       { 195250000, 0xB9, 0x24 },
+       { 219750000, 0xB8, 0x20 },
+       { 251250000, 0xB3, 0x1C },
+       { 270500000, 0xAD, 0x1A },
+       { 293000000, 0xAC, 0x18 },
+       { 319500000, 0xAB, 0x16 },
+       { 351500000, 0xAA, 0x14 },
+       { 390500000, 0xA9, 0x12 },
+       { 439500000, 0xA8, 0x10 },
+       { 502500000, 0xA3, 0x0E },
+       { 541000000, 0x9D, 0x0D },
+       { 586000000, 0x9C, 0x0C },
+       { 639000000, 0x9B, 0x0B },
+       { 703000000, 0x9A, 0x0A },
+       { 781000000, 0x99, 0x09 },
+       { 879000000, 0x98, 0x08 },
+       {         0, 0x00, 0x00 },    /* Table End */
+};
+
+static struct SMap  m_GainTaper_Map[] = {
+       {  45400000, 0x1F },
+       {  45800000, 0x1E },
+       {  46200000, 0x1D },
+       {  46700000, 0x1C },
+       {  47100000, 0x1B },
+       {  47500000, 0x1A },
+       {  47900000, 0x19 },
+       {  49600000, 0x17 },
+       {  51200000, 0x16 },
+       {  52900000, 0x15 },
+       {  54500000, 0x14 },
+       {  56200000, 0x13 },
+       {  57800000, 0x12 },
+       {  59500000, 0x11 },
+       {  61100000, 0x10 },
+       {  67600000, 0x0D },
+       {  74200000, 0x0C },
+       {  80700000, 0x0B },
+       {  87200000, 0x0A },
+       {  93800000, 0x09 },
+       { 100300000, 0x08 },
+       { 106900000, 0x07 },
+       { 113400000, 0x06 },
+       { 119900000, 0x05 },
+       { 126500000, 0x04 },
+       { 133000000, 0x03 },
+       { 139500000, 0x02 },
+       { 146100000, 0x01 },
+       { 152600000, 0x00 },
+       { 154300000, 0x1F },
+       { 156100000, 0x1E },
+       { 157800000, 0x1D },
+       { 159500000, 0x1C },
+       { 161200000, 0x1B },
+       { 163000000, 0x1A },
+       { 164700000, 0x19 },
+       { 170200000, 0x17 },
+       { 175800000, 0x16 },
+       { 181300000, 0x15 },
+       { 186900000, 0x14 },
+       { 192400000, 0x13 },
+       { 198000000, 0x12 },
+       { 203500000, 0x11 },
+       { 216200000, 0x14 },
+       { 228900000, 0x13 },
+       { 241600000, 0x12 },
+       { 254400000, 0x11 },
+       { 267100000, 0x10 },
+       { 279800000, 0x0F },
+       { 292500000, 0x0E },
+       { 305200000, 0x0D },
+       { 317900000, 0x0C },
+       { 330700000, 0x0B },
+       { 343400000, 0x0A },
+       { 356100000, 0x09 },
+       { 368800000, 0x08 },
+       { 381500000, 0x07 },
+       { 394200000, 0x06 },
+       { 406900000, 0x05 },
+       { 419700000, 0x04 },
+       { 432400000, 0x03 },
+       { 445100000, 0x02 },
+       { 457800000, 0x01 },
+       { 476300000, 0x19 },
+       { 494800000, 0x18 },
+       { 513300000, 0x17 },
+       { 531800000, 0x16 },
+       { 550300000, 0x15 },
+       { 568900000, 0x14 },
+       { 587400000, 0x13 },
+       { 605900000, 0x12 },
+       { 624400000, 0x11 },
+       { 642900000, 0x10 },
+       { 661400000, 0x0F },
+       { 679900000, 0x0E },
+       { 698400000, 0x0D },
+       { 716900000, 0x0C },
+       { 735400000, 0x0B },
+       { 753900000, 0x0A },
+       { 772500000, 0x09 },
+       { 791000000, 0x08 },
+       { 809500000, 0x07 },
+       { 828000000, 0x06 },
+       { 846500000, 0x05 },
+       { 865000000, 0x04 },
+       {         0, 0x00 },    /* Table End */
+};
+
+static struct SMap m_RF_Cal_DC_Over_DT_Map[] = {
+       {  47900000, 0x00 },
+       {  55000000, 0x00 },
+       {  61100000, 0x0A },
+       {  64000000, 0x0A },
+       {  82000000, 0x14 },
+       {  84000000, 0x19 },
+       { 119000000, 0x1C },
+       { 124000000, 0x20 },
+       { 129000000, 0x2A },
+       { 134000000, 0x32 },
+       { 139000000, 0x39 },
+       { 144000000, 0x3E },
+       { 149000000, 0x3F },
+       { 152600000, 0x40 },
+       { 154000000, 0x40 },
+       { 164700000, 0x41 },
+       { 203500000, 0x32 },
+       { 353000000, 0x19 },
+       { 356000000, 0x1A },
+       { 359000000, 0x1B },
+       { 363000000, 0x1C },
+       { 366000000, 0x1D },
+       { 369000000, 0x1E },
+       { 373000000, 0x1F },
+       { 376000000, 0x20 },
+       { 379000000, 0x21 },
+       { 383000000, 0x22 },
+       { 386000000, 0x23 },
+       { 389000000, 0x24 },
+       { 393000000, 0x25 },
+       { 396000000, 0x26 },
+       { 399000000, 0x27 },
+       { 402000000, 0x28 },
+       { 404000000, 0x29 },
+       { 407000000, 0x2A },
+       { 409000000, 0x2B },
+       { 412000000, 0x2C },
+       { 414000000, 0x2D },
+       { 417000000, 0x2E },
+       { 419000000, 0x2F },
+       { 422000000, 0x30 },
+       { 424000000, 0x31 },
+       { 427000000, 0x32 },
+       { 429000000, 0x33 },
+       { 432000000, 0x34 },
+       { 434000000, 0x35 },
+       { 437000000, 0x36 },
+       { 439000000, 0x37 },
+       { 442000000, 0x38 },
+       { 444000000, 0x39 },
+       { 447000000, 0x3A },
+       { 449000000, 0x3B },
+       { 457800000, 0x3C },
+       { 465000000, 0x0F },
+       { 477000000, 0x12 },
+       { 483000000, 0x14 },
+       { 502000000, 0x19 },
+       { 508000000, 0x1B },
+       { 519000000, 0x1C },
+       { 522000000, 0x1D },
+       { 524000000, 0x1E },
+       { 534000000, 0x1F },
+       { 549000000, 0x20 },
+       { 554000000, 0x22 },
+       { 584000000, 0x24 },
+       { 589000000, 0x26 },
+       { 658000000, 0x27 },
+       { 664000000, 0x2C },
+       { 669000000, 0x2D },
+       { 699000000, 0x2E },
+       { 704000000, 0x30 },
+       { 709000000, 0x31 },
+       { 714000000, 0x32 },
+       { 724000000, 0x33 },
+       { 729000000, 0x36 },
+       { 739000000, 0x38 },
+       { 744000000, 0x39 },
+       { 749000000, 0x3B },
+       { 754000000, 0x3C },
+       { 759000000, 0x3D },
+       { 764000000, 0x3E },
+       { 769000000, 0x3F },
+       { 774000000, 0x40 },
+       { 779000000, 0x41 },
+       { 784000000, 0x43 },
+       { 789000000, 0x46 },
+       { 794000000, 0x48 },
+       { 799000000, 0x4B },
+       { 804000000, 0x4F },
+       { 809000000, 0x54 },
+       { 814000000, 0x59 },
+       { 819000000, 0x5D },
+       { 824000000, 0x61 },
+       { 829000000, 0x68 },
+       { 834000000, 0x6E },
+       { 839000000, 0x75 },
+       { 844000000, 0x7E },
+       { 849000000, 0x82 },
+       { 854000000, 0x84 },
+       { 859000000, 0x8F },
+       { 865000000, 0x9A },
+       {         0, 0x00 },    /* Table End */
+};
+
+
+static struct SMap  m_IR_Meas_Map[] = {
+       { 200000000, 0x05 },
+       { 400000000, 0x06 },
+       { 865000000, 0x07 },
+       {         0, 0x00 },    /* Table End */
+};
+
+static struct SMap2 m_CID_Target_Map[] = {
+       {  46000000, 0x04, 18 },
+       {  52200000, 0x0A, 15 },
+       {  70100000, 0x01, 40 },
+       { 136800000, 0x18, 40 },
+       { 156700000, 0x18, 40 },
+       { 186250000, 0x0A, 40 },
+       { 230000000, 0x0A, 40 },
+       { 345000000, 0x18, 40 },
+       { 426000000, 0x0E, 40 },
+       { 489500000, 0x1E, 40 },
+       { 697500000, 0x32, 40 },
+       { 842000000, 0x3A, 40 },
+       {         0, 0x00,  0 },    /* Table End */
+};
+
+static struct SRFBandMap  m_RF_Band_Map[7] = {
+       {   47900000,   46000000,           0,          0},
+       {   61100000,   52200000,           0,          0},
+       {  152600000,   70100000,   136800000,          0},
+       {  164700000,  156700000,           0,          0},
+       {  203500000,  186250000,           0,          0},
+       {  457800000,  230000000,   345000000,  426000000},
+       {  865000000,  489500000,   697500000,  842000000},
+};
+
+u8 m_Thermometer_Map_1[16] = {
+       60, 62, 66, 64,
+       74, 72, 68, 70,
+       90, 88, 84, 86,
+       76, 78, 82, 80,
+};
+
+u8 m_Thermometer_Map_2[16] = {
+       92, 94, 98, 96,
+       106, 104, 100, 102,
+       122, 120, 116, 118,
+       108, 110, 114, 112,
+};
index cec242b7c00d18e535fddca037f5f56ddc3762a3..64c84702ba5cf66be59300f89bfa1cc83c98fb5c 100644 (file)
@@ -5,6 +5,8 @@ config DVB_NGENE
        select DVB_STV6110x if !DVB_FE_CUSTOMISE
        select DVB_STV090x if !DVB_FE_CUSTOMISE
        select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+       select DVB_DRXK if !DVB_FE_CUSTOMISE
+       select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE
        ---help---
          Support for Micronas PCI express cards with nGene bridge.
index fcf4be901ec8675bed8d9346b3e4ca22e73264fa..056419228363f8344eefbab82ef8b05eb24feace 100644 (file)
@@ -40,6 +40,8 @@
 #include "lnbh24.h"
 #include "lgdt330x.h"
 #include "mt2131.h"
+#include "tda18271c2dd.h"
+#include "drxk.h"
 
 
 /****************************************************************************/
@@ -83,6 +85,49 @@ static int tuner_attach_stv6110(struct ngene_channel *chan)
 }
 
 
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct ngene_channel *chan = fe->sec_priv;
+       int status;
+
+       if (enable) {
+               down(&chan->dev->pll_mutex);
+               status = chan->gate_ctrl(fe, 1);
+       } else {
+               status = chan->gate_ctrl(fe, 0);
+               up(&chan->dev->pll_mutex);
+       }
+       return status;
+}
+
+static int tuner_attach_tda18271(struct ngene_channel *chan)
+{
+       struct i2c_adapter *i2c;
+       struct dvb_frontend *fe;
+
+       i2c = &chan->dev->channel[0].i2c_adapter;
+       if (chan->fe->ops.i2c_gate_ctrl)
+               chan->fe->ops.i2c_gate_ctrl(chan->fe, 1);
+       fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60);
+       if (chan->fe->ops.i2c_gate_ctrl)
+               chan->fe->ops.i2c_gate_ctrl(chan->fe, 0);
+       if (!fe) {
+               printk(KERN_ERR "No TDA18271 found!\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int tuner_attach_probe(struct ngene_channel *chan)
+{
+       if (chan->demod_type == 0)
+               return tuner_attach_stv6110(chan);
+       if (chan->demod_type == 1)
+               return tuner_attach_tda18271(chan);
+       return -EINVAL;
+}
+
 static int demod_attach_stv0900(struct ngene_channel *chan)
 {
        struct i2c_adapter *i2c;
@@ -130,6 +175,60 @@ static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock)
                up(&chan->dev->pll_mutex);
 }
 
+static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
+{
+       struct i2c_msg msgs[1] = {{.addr = adr,  .flags = I2C_M_RD,
+                                  .buf  = val,  .len   = 1 } };
+       return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
+}
+
+static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
+                         u16 reg, u8 *val)
+{
+       u8 msg[2] = {reg>>8, reg&0xff};
+       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+                                  .buf  = msg, .len   = 2},
+                                 {.addr = adr, .flags = I2C_M_RD,
+                                  .buf  = val, .len   = 1} };
+       return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
+}
+
+static int port_has_stv0900(struct i2c_adapter *i2c, int port)
+{
+       u8 val;
+       if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0)
+               return 0;
+       return 1;
+}
+
+static int port_has_drxk(struct i2c_adapter *i2c, int port)
+{
+       u8 val;
+
+       if (i2c_read(i2c, 0x29+port, &val) < 0)
+               return 0;
+       return 1;
+}
+
+static int demod_attach_drxk(struct ngene_channel *chan,
+                            struct i2c_adapter *i2c)
+{
+       struct drxk_config config;
+
+       memset(&config, 0, sizeof(config));
+       config.adr = 0x29 + (chan->number ^ 2);
+
+       chan->fe = dvb_attach(drxk_attach, &config, i2c, &chan->fe2);
+       if (!chan->fe) {
+               printk(KERN_ERR "No DRXK found!\n");
+               return -ENODEV;
+       }
+       chan->fe->sec_priv = chan;
+       chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl;
+       chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+       return 0;
+}
+
 static int cineS2_probe(struct ngene_channel *chan)
 {
        struct i2c_adapter *i2c;
@@ -144,43 +243,42 @@ static int cineS2_probe(struct ngene_channel *chan)
        else
                i2c = &chan->dev->channel[1].i2c_adapter;
 
-       fe_conf = chan->dev->card_info->fe_config[chan->number];
-       i2c_msg.addr = fe_conf->address;
-
-       /* probe demod */
-       i2c_msg.len = 2;
-       buf[0] = 0xf1;
-       buf[1] = 0x00;
-       rc = i2c_transfer(i2c, &i2c_msg, 1);
-       if (rc != 1)
-               return -ENODEV;
-
-       /* demod found, attach it */
-       rc = demod_attach_stv0900(chan);
-       if (rc < 0 || chan->number < 2)
-               return rc;
-
-       /* demod #2: reprogram outputs DPN1 & DPN2 */
-       i2c_msg.len = 3;
-       buf[0] = 0xf1;
-       switch (chan->number) {
-       case 2:
-               buf[1] = 0x5c;
-               buf[2] = 0xc2;
-               break;
-       case 3:
-               buf[1] = 0x61;
-               buf[2] = 0xcc;
-               break;
-       default:
+       if (port_has_stv0900(i2c, chan->number)) {
+               chan->demod_type = 0;
+               fe_conf = chan->dev->card_info->fe_config[chan->number];
+               /* demod found, attach it */
+               rc = demod_attach_stv0900(chan);
+               if (rc < 0 || chan->number < 2)
+                       return rc;
+
+               /* demod #2: reprogram outputs DPN1 & DPN2 */
+               i2c_msg.addr = fe_conf->address;
+               i2c_msg.len = 3;
+               buf[0] = 0xf1;
+               switch (chan->number) {
+               case 2:
+                       buf[1] = 0x5c;
+                       buf[2] = 0xc2;
+                       break;
+               case 3:
+                       buf[1] = 0x61;
+                       buf[2] = 0xcc;
+                       break;
+               default:
+                       return -ENODEV;
+               }
+               rc = i2c_transfer(i2c, &i2c_msg, 1);
+               if (rc != 1) {
+                       printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");
+                       return -EIO;
+               }
+       } else if (port_has_drxk(i2c, chan->number^2)) {
+               chan->demod_type = 1;
+               demod_attach_drxk(chan, i2c);
+       } else {
+               printk(KERN_ERR "No demod found on chan %d\n", chan->number);
                return -ENODEV;
        }
-       rc = i2c_transfer(i2c, &i2c_msg, 1);
-       if (rc != 1) {
-               printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n");
-               return -EIO;
-       }
-
        return 0;
 }
 
@@ -306,7 +404,7 @@ static struct ngene_info ngene_info_satixS2v2 = {
        .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
                           NGENE_IO_TSOUT},
        .demod_attach   = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
-       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},
+       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
        .fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
        .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
        .lnb            = {0x0a, 0x08, 0x0b, 0x09},
@@ -321,7 +419,7 @@ static struct ngene_info ngene_info_cineS2v5 = {
        .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
                           NGENE_IO_TSOUT},
        .demod_attach   = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe},
-       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},
+       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_probe, tuner_attach_probe},
        .fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
        .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
        .lnb            = {0x0a, 0x08, 0x0b, 0x09},
@@ -331,13 +429,13 @@ static struct ngene_info ngene_info_cineS2v5 = {
 };
 
 
-static struct ngene_info ngene_info_duoFlexS2 = {
+static struct ngene_info ngene_info_duoFlex = {
        .type           = NGENE_SIDEWINDER,
-       .name           = "Digital Devices DuoFlex S2 miniPCIe",
+       .name           = "Digital Devices DuoFlex PCIe or miniPCIe",
        .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN,
                           NGENE_IO_TSOUT},
        .demod_attach   = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe},
-       .tuner_attach   = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110},
+       .tuner_attach   = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe},
        .fe_config      = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2},
        .tuner_config   = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1},
        .lnb            = {0x0a, 0x08, 0x0b, 0x09},
@@ -385,8 +483,8 @@ static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
        NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
        NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
        NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
-       NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2),
-       NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2),
+       NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex),
+       NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex),
        NGENE_ID(0x1461, 0x062e, ngene_info_m780),
        {0}
 };
index 6927c726ce35b4ec1c8139eb838e7822dded28da..f129a9303f80a364f0956fb17033169f8a11a659 100644 (file)
@@ -41,7 +41,7 @@
 
 #include "ngene.h"
 
-static int one_adapter = 1;
+static int one_adapter;
 module_param(one_adapter, int, 0444);
 MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
 
@@ -461,7 +461,7 @@ static u8 TSFeatureDecoderSetup[8 * 5] = {
        0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,
        0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */
        0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */
-       0x72, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */
+       0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */
        0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */
 };
 
@@ -507,7 +507,7 @@ void FillTSBuffer(void *Buffer, int Length, u32 Flags)
 {
        u32 *ptr = Buffer;
 
-       memset(Buffer, 0xff, Length);
+       memset(Buffer, TS_FILLER, Length);
        while (Length > 0) {
                if (Flags & DF_SWAP32)
                        *ptr = 0x471FFF10;
@@ -1443,6 +1443,9 @@ static void release_channel(struct ngene_channel *chan)
                chan->ci_dev = NULL;
        }
 
+       if (chan->fe2)
+               dvb_unregister_frontend(chan->fe2);
+
        if (chan->fe) {
                dvb_unregister_frontend(chan->fe);
                dvb_frontend_detach(chan->fe);
@@ -1534,6 +1537,14 @@ static int init_channel(struct ngene_channel *chan)
                        goto err;
                chan->has_demux = true;
        }
+       if (chan->fe2) {
+               if (dvb_register_frontend(adapter, chan->fe2) < 0)
+                       goto err;
+               chan->fe2->tuner_priv = chan->fe->tuner_priv;
+               memcpy(&chan->fe2->ops.tuner_ops,
+                      &chan->fe->ops.tuner_ops,
+                      sizeof(struct dvb_tuner_ops));
+       }
 
        if (chan->has_demux) {
                ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
@@ -1571,11 +1582,18 @@ static int init_channels(struct ngene *dev)
        return 0;
 }
 
+static struct cxd2099_cfg cxd_cfg = {
+       .bitrate = 62000,
+       .adr = 0x40,
+       .polarity = 0,
+       .clock_mode = 0,
+};
+
 static void cxd_attach(struct ngene *dev)
 {
        struct ngene_ci *ci = &dev->ci;
 
-       ci->en = cxd2099_attach(0x40, dev, &dev->channel[0].i2c_adapter);
+       ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter);
        ci->dev = dev;
        return;
 }
index 0b4943233166e67824ff39cbebb5a859fe4b1497..fcb16a615aab002768f80b3e7d6c5cf66ac5f123 100644 (file)
@@ -118,6 +118,16 @@ static void swap_buffer(u32 *p, u32 len)
        }
 }
 
+/* start of filler packet */
+static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
+
+/* #define DEBUG_CI_XFER */
+#ifdef DEBUG_CI_XFER
+static u32 ok;
+static u32 overflow;
+static u32 stripped;
+#endif
+
 void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
 {
        struct ngene_channel *chan = priv;
@@ -126,21 +136,41 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
 
        if (flags & DF_SWAP32)
                swap_buffer(buf, len);
+
        if (dev->ci.en && chan->number == 2) {
-               if (dvb_ringbuffer_free(&dev->tsin_rbuf) > len) {
-                       dvb_ringbuffer_write(&dev->tsin_rbuf, buf, len);
-                       wake_up_interruptible(&dev->tsin_rbuf.queue);
+               while (len >= 188) {
+                       if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) {
+                               if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
+                                       dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
+                                       wake_up(&dev->tsin_rbuf.queue);
+#ifdef DEBUG_CI_XFER
+                                       ok++;
+#endif
+                               }
+#ifdef DEBUG_CI_XFER
+                               else
+                                       overflow++;
+#endif
+                       }
+#ifdef DEBUG_CI_XFER
+                       else
+                               stripped++;
+
+                       if (ok % 100 == 0 && overflow)
+                               printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped);
+#endif
+                       buf += 188;
+                       len -= 188;
                }
-               return 0;
+               return NULL;
        }
-       if (chan->users > 0) {
+
+       if (chan->users > 0)
                dvb_dmx_swfilter(&chan->demux, buf, len);
-       }
+
        return NULL;
 }
 
-u8 fill_ts[188] = { 0x47, 0x1f, 0xff, 0x10 };
-
 void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
 {
        struct ngene_channel *chan = priv;
index 40fce9e3ae66323435ec36cfb75d1049361a85f7..5443dc0caea50e2067a68c5df66d6563d79f7f58 100644 (file)
@@ -641,8 +641,11 @@ struct ngene_channel {
        int                   mode;
        bool                  has_adapter;
        bool                  has_demux;
+       int                   demod_type;
+       int (*gate_ctrl)(struct dvb_frontend *, int);
 
        struct dvb_frontend  *fe;
+       struct dvb_frontend  *fe2;
        struct dmxdev         dmxdev;
        struct dvb_demux      demux;
        struct dvb_net        dvbnet;
@@ -786,6 +789,8 @@ struct ngene {
        u8                    uart_rbuf[UART_RBUF_LEN];
        int                   uart_rp, uart_wp;
 
+#define TS_FILLER  0x6f
+
        u8                   *tsout_buf;
 #define TSOUT_BUF_SIZE (512*188*8)
        struct dvb_ringbuffer tsout_rbuf;
@@ -852,7 +857,7 @@ struct ngene_info {
 };
 
 #ifdef NGENE_V4L
-struct ngene_format{
+struct ngene_format {
        char *name;
        int   fourcc;          /* video4linux 2      */
        int   btformat;        /* BT848_COLOR_FMT_*  */
index 78765ed280631126abdabca42035eff8fe95dcc5..7331e8450d1a7d96caa64b2ba88e3d13be622b6f 100644 (file)
@@ -1147,7 +1147,7 @@ static int smscore_validate_client(struct smscore_device_t *coredev,
 
        if (!client) {
                sms_err("bad parameter.");
-               return -EFAULT;
+               return -EINVAL;
        }
        registered_client = smscore_find_client(coredev, data_type, id);
        if (registered_client == client)
index 8ecadecaa9d0d9aa7de49612a4e7c0845162a4c2..c592ae090397932f24168267bb937261248a71ac 100644 (file)
@@ -22,7 +22,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #ifndef __SMS_CORE_API_H__
 #define __SMS_CORE_API_H__
 
-#include <linux/version.h>
 #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/mm.h>
index 3d8cc425fa6b6206e394548e8abdf482f7aa3a73..25e58cbf35f0281c5c0bdad2d63d1075531d870a 100644 (file)
 /*
  * Version Information
  */
-#include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
-
-#define DRIVER_VERSION "v0.46"
-#define RADIO_VERSION KERNEL_VERSION(0, 4, 6)
+#define DRIVER_VERSION "0.4.7"
 
 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
@@ -335,7 +332,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "dsbr100", sizeof(v->driver));
        strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
        usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
@@ -647,3 +643,4 @@ module_exit (dsbr100_exit);
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
index 4ce10dbeadd861c587ad274ccdd09e784b9a729e..1c3f8440a55cf113d7a9fc1850680ca0f16da869 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* msleep                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -41,6 +40,7 @@
 MODULE_AUTHOR("M.Kirkwood");
 MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 #ifndef CONFIG_RADIO_RTRACK_PORT
 #define CONFIG_RADIO_RTRACK_PORT -1
@@ -53,8 +53,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct rtrack
 {
        struct v4l2_device v4l2_dev;
@@ -223,7 +221,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-aimslab", sizeof(v->driver));
        strlcpy(v->card, "RadioTrack", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index dd8a6ab0d437ab10022d1b65f1d802cc8d2b006c..eed7b08407340e3baebc12dd3493b0afd2e1cd44 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -38,6 +37,7 @@
 MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the Aztech radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
 
@@ -53,8 +53,6 @@ module_param(io, int, 0);
 module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct aztech
 {
        struct v4l2_device v4l2_dev;
@@ -188,7 +186,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-aztech", sizeof(v->driver));
        strlcpy(v->card, "Aztech Radio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index bc9ad0897c559b9142aea9ba7cbf486caaf1d5c4..16a089fad909f241f76d6f5a8a1eb8b22f9358bb 100644 (file)
@@ -30,7 +30,6 @@
  *             Changed API to V4L2
  */
 
-#include <linux/version.h>
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
@@ -46,6 +45,7 @@
 MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.3.4");
 
 static int io = -1;            /* default to isapnp activation */
 static int radio_nr = -1;
@@ -54,8 +54,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
 module_param(radio_nr, int, 0);
 
-#define CADET_VERSION KERNEL_VERSION(0, 3, 3)
-
 #define RDS_BUFFER 256
 #define RDS_RX_FLAG 1
 #define MBS_RX_FLAG 2
@@ -361,7 +359,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "ADS Cadet", sizeof(v->driver));
        strlcpy(v->card, "ADS Cadet", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = CADET_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
                          V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
        return 0;
index 259936422e493b4dcf6dd6742d17bc5acd5b2995..edadc8449a3d109ab736afdd24f71058fb07b171 100644 (file)
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/delay.h>       /* udelay                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
-#include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
 #include <linux/mutex.h>
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 3)
-
 /*
  * Module info.
  */
 
-MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
+MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
 MODULE_DESCRIPTION("A driver for the GemTek Radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.4");
 
 /*
  * Module params.
@@ -387,7 +385,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
        strlcpy(v->card, "GemTek", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index e83e84003025222f4a74d95024fa5df80f658ca8..f872a54cf3d9ae9baa03bdf9c5170664b9295d8f 100644 (file)
 #include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/videodev2.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
+#define DRIVER_VERSION "0.7.8"
+
+
 MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
 MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
 
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
@@ -58,10 +61,6 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "activates debug info");
 
-#define DRIVER_VERSION "0.77"
-
-#define RADIO_VERSION KERNEL_VERSION(0, 7, 7)
-
 #define dprintk(dev, num, fmt, arg...) \
        v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg)
 
@@ -195,7 +194,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver));
        strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card));
        snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index b3a635b9582013d92fd91f8f5aa51c3e0ce48d01..1742bd8110bdb3b28b175dcd2e9613e6aba9e189 100644 (file)
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <linux/usb.h>
-#include <linux/version.h>     /* for KERNEL_VERSION MACRO */
 #include <linux/mutex.h>
 
 /* driver and module definitions */
 #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
 #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
-#define DRIVER_VERSION "0.11"
-#define RADIO_VERSION KERNEL_VERSION(0, 1, 1)
+#define DRIVER_VERSION "0.1.2"
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
 
 #define USB_AMRADIO_VENDOR 0x07ca
 #define USB_AMRADIO_PRODUCT 0xb800
@@ -301,7 +300,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
        strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
        usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
index 8d6ea591bd188815c374ddf5c5e603a5aa3d6e8e..3628be617ee9fb99c395f511b166b61c96798db1 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/delay.h>       /* udelay                       */
 #include <linux/videodev2.h>   /* kernel radio structs         */
 #include <linux/mutex.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -23,6 +22,7 @@
 MODULE_AUTHOR("Ben Pfaff");
 MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 #ifndef CONFIG_RADIO_RTRACK2_PORT
 #define CONFIG_RADIO_RTRACK2_PORT -1
@@ -35,8 +35,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct rtrack2
 {
        struct v4l2_device v4l2_dev;
@@ -121,7 +119,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver));
        strlcpy(v->card, "RadioTrack II", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index b5a5f89e238a91fe432326d0da9487cf32ad9943..22c5743bf9db1d77a58bfa77949f14103892bcb8 100644 (file)
@@ -16,7 +16,6 @@
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>      /* __setup                      */
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
@@ -32,6 +31,7 @@
 MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
 MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 static int io = -1;
 static int radio_nr = -1;
@@ -40,8 +40,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct fmi
 {
        struct v4l2_device v4l2_dev;
@@ -134,7 +132,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
        strlcpy(v->card, "SF16-FMx radio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index 87bad7678d92f63bab822d6e8a244a6d6729fd69..2dd485996ba8e05ddd94b127e205590c1f34f6a9 100644 (file)
-/* SF16FMR2 radio driver for Linux radio support
- * heavily based on fmi driver...
- * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
+/* SF16-FMR2 radio driver for Linux
+ * Copyright (c) 2011 Ondrej Zary
  *
- * Notes on the hardware
- *
- *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
- *  No volume control - only mute/unmute - you have to use line volume
- *
- *  For read stereo/mono you must wait 0.1 sec after set frequency and
- *  card unmuted so I set frequency on unmute
- *  Signal handling seem to work only on autoscanning (not implemented)
- *
- *  Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ * Original driver was (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
+ * but almost nothing remained here after conversion to generic TEA575x
+ * implementation
  */
 
+#include <linux/delay.h>
 #include <linux/module.h>      /* Modules                      */
 #include <linux/init.h>                /* Initdata                     */
 #include <linux/ioport.h>      /* request_region               */
-#include <linux/delay.h>       /* udelay                       */
-#include <linux/videodev2.h>   /* kernel radio structs         */
-#include <linux/mutex.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
+#include <sound/tea575x-tuner.h>
 
-MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com");
-MODULE_DESCRIPTION("A driver for the SF16FMR2 radio.");
+MODULE_AUTHOR("Ondrej Zary");
+MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver");
 MODULE_LICENSE("GPL");
 
-static int io = 0x384;
-static int radio_nr = -1;
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)");
-module_param(radio_nr, int, 0);
-
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
-
-#define AUD_VOL_INDEX 1
-
-#undef DEBUG
-//#define DEBUG 1
-
-#ifdef DEBUG
-# define  debug_print(s) printk s
-#else
-# define  debug_print(s)
-#endif
-
-/* this should be static vars for module size */
-struct fmr2
-{
-       struct v4l2_device v4l2_dev;
-       struct video_device vdev;
-       struct mutex lock;
+struct fmr2 {
        int io;
-       int curvol; /* 0-15 */
-       int mute;
-       int stereo; /* card is producing stereo audio */
-       unsigned long curfreq; /* freq in kHz */
-       int card_type;
+       struct snd_tea575x tea;
+       struct v4l2_ctrl *volume;
+       struct v4l2_ctrl *balance;
 };
 
+/* the port is hardwired so no need to support multiple cards */
+#define FMR2_PORT      0x384
 static struct fmr2 fmr2_card;
 
-/* hw precision is 12.5 kHz
- * It is only useful to give freq in interval of 200 (=0.0125Mhz),
- * other bits will be truncated
- */
-#define RSF16_ENCODE(x)        ((x) / 200 + 856)
-#define RSF16_MINFREQ (87 * 16000)
-#define RSF16_MAXFREQ (108 * 16000)
-
-static inline void wait(int n, int io)
-{
-       for (; n; --n)
-               inb(io);
-}
-
-static void outbits(int bits, unsigned int data, int nWait, int io)
-{
-       int bit;
-
-       for (; --bits >= 0;) {
-               bit = (data >> bits) & 1;
-               outb(bit, io);
-               wait(nWait, io);
-               outb(bit | 2, io);
-               wait(nWait, io);
-               outb(bit, io);
-               wait(nWait, io);
-       }
-}
-
-static inline void fmr2_mute(int io)
-{
-       outb(0x00, io);
-       wait(4, io);
-}
-
-static inline void fmr2_unmute(int io)
-{
-       outb(0x04, io);
-       wait(4, io);
-}
-
-static inline int fmr2_stereo_mode(int io)
-{
-       int n = inb(io);
-
-       outb(6, io);
-       inb(io);
-       n = ((n >> 3) & 1) ^ 1;
-       debug_print((KERN_DEBUG "stereo: %d\n", n));
-       return n;
-}
-
-static int fmr2_product_info(struct fmr2 *dev)
-{
-       int n = inb(dev->io);
-
-       n &= 0xC1;
-       if (n == 0) {
-               /* this should support volume set */
-               dev->card_type = 12;
-               return 0;
-       }
-       /* not volume (mine is 11) */
-       dev->card_type = (n == 128) ? 11 : 0;
-       return n;
-}
+/* TEA575x tuner pins */
+#define STR_DATA       (1 << 0)
+#define STR_CLK                (1 << 1)
+#define STR_WREN       (1 << 2)
+#define STR_MOST       (1 << 3)
+/* PT2254A/TC9154A volume control pins */
+#define PT_ST          (1 << 4)
+#define PT_CK          (1 << 5)
+#define PT_DATA                (1 << 6)
+/* volume control presence pin */
+#define FMR2_HASVOL    (1 << 7)
 
-static inline int fmr2_getsigstr(struct fmr2 *dev)
+static void fmr2_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
 {
-       /* !!! works only if scanning freq */
-       int res = 0xffff;
-
-       outb(5, dev->io);
-       wait(4, dev->io);
-       if (!(inb(dev->io) & 1))
-               res = 0;
-       debug_print((KERN_DEBUG "signal: %d\n", res));
-       return res;
-}
-
-/* set frequency and unmute card */
-static int fmr2_setfreq(struct fmr2 *dev)
-{
-       unsigned long freq = dev->curfreq;
-
-       fmr2_mute(dev->io);
-
-       /* 0x42 for mono output
-        * 0x102 forward scanning
-        * 0x182 scansione avanti
-        */
-       outbits(9, 0x2, 3, dev->io);
-       outbits(16, RSF16_ENCODE(freq), 2, dev->io);
-
-       fmr2_unmute(dev->io);
+       struct fmr2 *fmr2 = tea->private_data;
+       u8 bits = 0;
 
-       /* wait 0.11 sec */
-       msleep(110);
+       bits |= (pins & TEA575X_DATA) ? STR_DATA : 0;
+       bits |= (pins & TEA575X_CLK)  ? STR_CLK  : 0;
+       /* WRITE_ENABLE is inverted, DATA must be high during read */
+       bits |= (pins & TEA575X_WREN) ? 0 : STR_WREN | STR_DATA;
 
-       /* NOTE if mute this stop radio
-          you must set freq on unmute */
-       dev->stereo = fmr2_stereo_mode(dev->io);
-       return 0;
-}
-
-/* !!! not tested, in my card this doesn't work !!! */
-static int fmr2_setvolume(struct fmr2 *dev)
-{
-       int vol[16] = { 0x021, 0x084, 0x090, 0x104,
-                       0x110, 0x204, 0x210, 0x402,
-                       0x404, 0x408, 0x410, 0x801,
-                       0x802, 0x804, 0x808, 0x810 };
-       int i, a;
-       int n = vol[dev->curvol & 0x0f];
-
-       if (dev->card_type != 11)
-               return 1;
-
-       for (i = 12; --i >= 0; ) {
-               a = ((n >> i) & 1) << 6; /* if (a==0) a = 0; else a = 0x40; */
-               outb(a | 4, dev->io);
-               wait(4, dev->io);
-               outb(a | 0x24, dev->io);
-               wait(4, dev->io);
-               outb(a | 4, dev->io);
-               wait(4, dev->io);
-       }
-       for (i = 6; --i >= 0; ) {
-               a = ((0x18 >> i) & 1) << 6;
-               outb(a | 4, dev->io);
-               wait(4, dev->io);
-               outb(a | 0x24, dev->io);
-               wait(4, dev->io);
-               outb(a | 4, dev->io);
-               wait(4, dev->io);
-       }
-       wait(4, dev->io);
-       outb(0x14, dev->io);
-       return 0;
+       outb(bits, fmr2->io);
 }
 
-static int vidioc_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *v)
+static u8 fmr2_tea575x_get_pins(struct snd_tea575x *tea)
 {
-       strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver));
-       strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card));
-       strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
-       v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
-       return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
-{
-       struct fmr2 *fmr2 = video_drvdata(file);
-
-       if (v->index > 0)
-               return -EINVAL;
+       struct fmr2 *fmr2 = tea->private_data;
+       u8 bits = inb(fmr2->io);
 
-       strlcpy(v->name, "FM", sizeof(v->name));
-       v->type = V4L2_TUNER_RADIO;
-
-       v->rangelow = RSF16_MINFREQ;
-       v->rangehigh = RSF16_MAXFREQ;
-       v->rxsubchans = fmr2->stereo ? V4L2_TUNER_SUB_STEREO :
-                                       V4L2_TUNER_SUB_MONO;
-       v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
-       v->audmode = V4L2_TUNER_MODE_STEREO;
-       mutex_lock(&fmr2->lock);
-       v->signal = fmr2_getsigstr(fmr2);
-       mutex_unlock(&fmr2->lock);
-       return 0;
+       return  (bits & STR_DATA) ? TEA575X_DATA : 0 |
+               (bits & STR_MOST) ? TEA575X_MOST : 0;
 }
 
-static int vidioc_s_tuner(struct file *file, void *priv,
-                                       struct v4l2_tuner *v)
+static void fmr2_tea575x_set_direction(struct snd_tea575x *tea, bool output)
 {
-       return v->index ? -EINVAL : 0;
 }
 
-static int vidioc_s_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct fmr2 *fmr2 = video_drvdata(file);
+static struct snd_tea575x_ops fmr2_tea_ops = {
+       .set_pins = fmr2_tea575x_set_pins,
+       .get_pins = fmr2_tea575x_get_pins,
+       .set_direction = fmr2_tea575x_set_direction,
+};
 
-       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
-               return -EINVAL;
-       if (f->frequency < RSF16_MINFREQ ||
-                       f->frequency > RSF16_MAXFREQ)
-               return -EINVAL;
-       /* rounding in steps of 200 to match the freq
-          that will be used */
-       fmr2->curfreq = (f->frequency / 200) * 200;
-
-       /* set card freq (if not muted) */
-       if (fmr2->curvol && !fmr2->mute) {
-               mutex_lock(&fmr2->lock);
-               fmr2_setfreq(fmr2);
-               mutex_unlock(&fmr2->lock);
+/* TC9154A/PT2254A volume control */
+
+/* 18-bit shift register bit definitions */
+#define TC9154A_ATT_MAJ_0DB    (1 << 0)
+#define TC9154A_ATT_MAJ_10DB   (1 << 1)
+#define TC9154A_ATT_MAJ_20DB   (1 << 2)
+#define TC9154A_ATT_MAJ_30DB   (1 << 3)
+#define TC9154A_ATT_MAJ_40DB   (1 << 4)
+#define TC9154A_ATT_MAJ_50DB   (1 << 5)
+#define TC9154A_ATT_MAJ_60DB   (1 << 6)
+
+#define TC9154A_ATT_MIN_0DB    (1 << 7)
+#define TC9154A_ATT_MIN_2DB    (1 << 8)
+#define TC9154A_ATT_MIN_4DB    (1 << 9)
+#define TC9154A_ATT_MIN_6DB    (1 << 10)
+#define TC9154A_ATT_MIN_8DB    (1 << 11)
+/* bit 12 is ignored */
+#define TC9154A_CHANNEL_LEFT   (1 << 13)
+#define TC9154A_CHANNEL_RIGHT  (1 << 14)
+/* bits 15, 16, 17 must be 0 */
+
+#define        TC9154A_ATT_MAJ(x)      (1 << x)
+#define TC9154A_ATT_MIN(x)     (1 << (7 + x))
+
+static void tc9154a_set_pins(struct fmr2 *fmr2, u8 pins)
+{
+       if (!fmr2->tea.mute)
+               pins |= STR_WREN;
+
+       outb(pins, fmr2->io);
+}
+
+static void tc9154a_set_attenuation(struct fmr2 *fmr2, int att, u32 channel)
+{
+       int i;
+       u32 reg;
+       u8 bit;
+
+       reg = TC9154A_ATT_MAJ(att / 10) | TC9154A_ATT_MIN((att % 10) / 2);
+       reg |= channel;
+       /* write 18-bit shift register, LSB first */
+       for (i = 0; i < 18; i++) {
+               bit = reg & (1 << i) ? PT_DATA : 0;
+               tc9154a_set_pins(fmr2, bit);
+               udelay(5);
+               tc9154a_set_pins(fmr2, bit | PT_CK);
+               udelay(5);
+               tc9154a_set_pins(fmr2, bit);
        }
-       return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
-                                       struct v4l2_frequency *f)
-{
-       struct fmr2 *fmr2 = video_drvdata(file);
-
-       if (f->tuner != 0)
-               return -EINVAL;
-       f->type = V4L2_TUNER_RADIO;
-       f->frequency = fmr2->curfreq;
-       return 0;
-}
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
-{
-       struct fmr2 *fmr2 = video_drvdata(file);
-
-       switch (qc->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-       case V4L2_CID_AUDIO_VOLUME:
-               /* Only card_type == 11 implements volume */
-               if (fmr2->card_type == 11)
-                       return v4l2_ctrl_query_fill(qc, 0, 15, 1, 0);
-               return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-       }
-       return -EINVAL;
+       /* latch register data */
+       udelay(5);
+       tc9154a_set_pins(fmr2, PT_ST);
+       udelay(5);
+       tc9154a_set_pins(fmr2, 0);
 }
 
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
+static int fmr2_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct fmr2 *fmr2 = video_drvdata(file);
+       struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler);
+       struct fmr2 *fmr2 = tea->private_data;
+       int volume, balance, left, right;
 
        switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = fmr2->mute;
-               return 0;
        case V4L2_CID_AUDIO_VOLUME:
-               ctrl->value = fmr2->curvol;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct fmr2 *fmr2 = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               fmr2->mute = ctrl->value;
+               volume = ctrl->val;
+               balance = fmr2->balance->cur.val;
                break;
-       case V4L2_CID_AUDIO_VOLUME:
-               fmr2->curvol = ctrl->value;
+       case V4L2_CID_AUDIO_BALANCE:
+               balance = ctrl->val;
+               volume = fmr2->volume->cur.val;
                break;
        default:
                return -EINVAL;
        }
 
-#ifdef DEBUG
-       if (fmr2->curvol && !fmr2->mute)
-               printk(KERN_DEBUG "unmute\n");
-       else
-               printk(KERN_DEBUG "mute\n");
-#endif
-
-       mutex_lock(&fmr2->lock);
-       if (fmr2->curvol && !fmr2->mute) {
-               fmr2_setvolume(fmr2);
-               /* Set frequency and unmute card */
-               fmr2_setfreq(fmr2);
-       } else
-               fmr2_mute(fmr2->io);
-       mutex_unlock(&fmr2->lock);
-       return 0;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
+       left = right = volume;
+       if (balance < 0)
+               right = max(0, right + balance);
+       if (balance > 0)
+               left = max(0, left - balance);
 
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return i ? -EINVAL : 0;
-}
+       tc9154a_set_attenuation(fmr2, abs(left - 68), TC9154A_CHANNEL_LEFT);
+       tc9154a_set_attenuation(fmr2, abs(right - 68), TC9154A_CHANNEL_RIGHT);
 
-static int vidioc_g_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
-{
-       a->index = 0;
-       strlcpy(a->name, "Radio", sizeof(a->name));
-       a->capability = V4L2_AUDCAP_STEREO;
        return 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
-                                       struct v4l2_audio *a)
+static const struct v4l2_ctrl_ops fmr2_ctrl_ops = {
+       .s_ctrl = fmr2_s_ctrl,
+};
+
+static int fmr2_tea_ext_init(struct snd_tea575x *tea)
 {
-       return a->index ? -EINVAL : 0;
-}
+       struct fmr2 *fmr2 = tea->private_data;
 
-static const struct v4l2_file_operations fmr2_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = video_ioctl2,
-};
+       if (inb(fmr2->io) & FMR2_HASVOL) {
+               fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56);
+               fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0);
+               if (tea->ctrl_handler.error) {
+                       printk(KERN_ERR "radio-sf16fmr2: can't initialize contrls\n");
+                       return tea->ctrl_handler.error;
+               }
+       }
 
-static const struct v4l2_ioctl_ops fmr2_ioctl_ops = {
-       .vidioc_querycap    = vidioc_querycap,
-       .vidioc_g_tuner     = vidioc_g_tuner,
-       .vidioc_s_tuner     = vidioc_s_tuner,
-       .vidioc_g_audio     = vidioc_g_audio,
-       .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
-       .vidioc_g_frequency = vidioc_g_frequency,
-       .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
-};
+       return 0;
+}
 
 static int __init fmr2_init(void)
 {
        struct fmr2 *fmr2 = &fmr2_card;
-       struct v4l2_device *v4l2_dev = &fmr2->v4l2_dev;
-       int res;
 
-       strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name));
-       fmr2->io = io;
-       fmr2->stereo = 1;
-       mutex_init(&fmr2->lock);
+       fmr2->io = FMR2_PORT;
 
-       if (!request_region(fmr2->io, 2, "sf16fmr2")) {
-               v4l2_err(v4l2_dev, "request_region failed!\n");
+       if (!request_region(fmr2->io, 2, "SF16-FMR2")) {
+               printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io);
                return -EBUSY;
        }
 
-       res = v4l2_device_register(NULL, v4l2_dev);
-       if (res < 0) {
-               release_region(fmr2->io, 2);
-               v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
-               return res;
-       }
+       fmr2->tea.private_data = fmr2;
+       fmr2->tea.ops = &fmr2_tea_ops;
+       fmr2->tea.ext_init = fmr2_tea_ext_init;
+       strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card));
+       strcpy(fmr2->tea.bus_info, "ISA");
 
-       strlcpy(fmr2->vdev.name, v4l2_dev->name, sizeof(fmr2->vdev.name));
-       fmr2->vdev.v4l2_dev = v4l2_dev;
-       fmr2->vdev.fops = &fmr2_fops;
-       fmr2->vdev.ioctl_ops = &fmr2_ioctl_ops;
-       fmr2->vdev.release = video_device_release_empty;
-       video_set_drvdata(&fmr2->vdev, fmr2);
-
-       /* mute card - prevents noisy bootups */
-       fmr2_mute(fmr2->io);
-       fmr2_product_info(fmr2);
-
-       if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               v4l2_device_unregister(v4l2_dev);
+       if (snd_tea575x_init(&fmr2->tea)) {
+               printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n");
                release_region(fmr2->io, 2);
-               return -EINVAL;
+               return -ENODEV;
        }
 
-       v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io);
-       debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type));
+       printk(KERN_INFO "radio-sf16fmr2: SF16-FMR2 radio card at 0x%x.\n", fmr2->io);
        return 0;
 }
 
@@ -443,22 +211,9 @@ static void __exit fmr2_exit(void)
 {
        struct fmr2 *fmr2 = &fmr2_card;
 
-       video_unregister_device(&fmr2->vdev);
-       v4l2_device_unregister(&fmr2->v4l2_dev);
+       snd_tea575x_exit(&fmr2->tea);
        release_region(fmr2->io, 2);
 }
 
 module_init(fmr2_init);
 module_exit(fmr2_exit);
-
-#ifndef MODULE
-
-static int __init fmr2_setup_io(char *str)
-{
-       get_option(&str, &io);
-       return 1;
-}
-
-__setup("sf16fmr2=", fmr2_setup_io);
-
-#endif
index 0e71d816c725885535cc4d1da4f992809d0d6257..95ddcc4845d34d7563b6843ea5f51d8255555cdc 100644 (file)
 #include <linux/i2c.h>                 /* I2C                          */
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
-#include <linux/version.h>             /* for KERNEL_VERSION MACRO     */
 
-#define DRIVER_VERSION "v0.01"
-#define RADIO_VERSION  KERNEL_VERSION(0, 0, 1)
+#define DRIVER_VERSION "0.0.2"
 
 #define DRIVER_AUTHOR  "Fabio Belavenuto <belavenuto@gmail.com>"
 #define DRIVER_DESC    "A driver for the TEA5764 radio chip for EZX Phones."
@@ -300,7 +298,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->card, dev->name, sizeof(v->card));
        snprintf(v->bus_info, sizeof(v->bus_info),
                 "I2C:%s", dev_name(&dev->dev));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
@@ -595,8 +592,9 @@ static void __exit tea5764_exit(void)
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
 
-module_param(use_xtal, int, 1);
+module_param(use_xtal, int, 0);
 MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board");
 module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(radio_nr, "video4linux device number to use");
index a32663917059c1cd4734247452c33444c02ad5d2..f2ed9cc3cf3b7d6fcdd462f5ee82ff6dd414558e 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/ioport.h>      /* request_region               */
 #include <linux/videodev2.h>   /* kernel radio structs         */
 #include <linux/mutex.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -37,6 +36,7 @@
 MODULE_AUTHOR("R.OFFERMANNS & others");
 MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 #ifndef CONFIG_RADIO_TERRATEC_PORT
 #define CONFIG_RADIO_TERRATEC_PORT 0x590
@@ -49,8 +49,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 static struct v4l2_queryctrl radio_qctrl[] = {
        {
                .id            = V4L2_CID_AUDIO_MUTE,
@@ -205,7 +203,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "radio-terratec", sizeof(v->driver));
        strlcpy(v->card, "ActiveRadio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index a185610b376be1a14e79b52751c7f95aab777dd0..f17b540d68a5e257662ab82afd1020ebce70872c 100644 (file)
@@ -16,7 +16,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
 #include <linux/io.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
@@ -44,7 +43,6 @@ static int timbradio_vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver));
        strlcpy(v->card, "Timberdale Radio", sizeof(v->card));
        snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME);
-       v->version = KERNEL_VERSION(0, 0, 1);
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
@@ -245,4 +243,5 @@ module_exit(timbradio_exit);
 MODULE_DESCRIPTION("Timberdale Radio driver");
 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
 MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.0.2");
 MODULE_ALIAS("platform:"DRIVER_NAME);
index 22fa9cc28abed060cff57e1e3a78227575c9ee36..b3f45a019d82c875432e1d6c1c3ca6f47179af9e 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/videodev2.h>
 #include <linux/io.h>
 #include <media/v4l2-device.h>
@@ -28,6 +27,7 @@
 MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
 MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
 
@@ -42,8 +42,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct trust {
        struct v4l2_device v4l2_dev;
        struct video_device vdev;
@@ -196,7 +194,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "radio-trust", sizeof(v->driver));
        strlcpy(v->card, "Trust FM Radio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index 8dbbf08f22077ad2b7c84e8e3992d3b33eab88e7..398726abc0c863947bdf873bd4ff075880904fc4 100644 (file)
 #include <linux/module.h>      /* Modules                        */
 #include <linux/init.h>                /* Initdata                       */
 #include <linux/ioport.h>      /* request_region                 */
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/videodev2.h>   /* kernel radio structs           */
 #include <linux/io.h>          /* outb, outb_p                   */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
+#define DRIVER_VERSION "0.1.2"
+
 MODULE_AUTHOR("Dr. Henrik Seidel");
 MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio).");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
 
 #ifndef CONFIG_RADIO_TYPHOON_PORT
 #define CONFIG_RADIO_TYPHOON_PORT -1
@@ -61,9 +63,7 @@ static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ;
 module_param(mutefreq, ulong, 0);
 MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
 
-#define RADIO_VERSION KERNEL_VERSION(0, 1, 1)
-
-#define BANNER "Typhoon Radio Card driver v0.1.1\n"
+#define BANNER "Typhoon Radio Card driver v" DRIVER_VERSION "\n"
 
 struct typhoon {
        struct v4l2_device v4l2_dev;
@@ -171,7 +171,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-typhoon", sizeof(v->driver));
        strlcpy(v->card, "Typhoon Radio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index 459f7272d32634d67143ee679a5375fc85f37f99..46cacf845049941c5ad0efc687e23fd2ad4236d7 100644 (file)
@@ -1382,7 +1382,7 @@ static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case  V4L2_CID_TUNE_ANTENNA_CAPACITOR:
-               ctrl->cur.val = wl1273_fm_get_tx_ctune(radio);
+               ctrl->val = wl1273_fm_get_tx_ctune(radio);
                break;
 
        default:
index af99c5bd88c1f0ce15311ec63c137aeee2ce42ab..f5613b94820353f1744d4f7fff50c42e9be77a69 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/delay.h>       /* udelay, msleep                 */
 #include <linux/videodev2.h>   /* kernel radio structs           */
 #include <linux/mutex.h>
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
 #include <linux/io.h>          /* outb, outb_p                   */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -43,6 +42,7 @@
 MODULE_AUTHOR("C.van Schaik");
 MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
 
 #ifndef CONFIG_RADIO_ZOLTRIX_PORT
 #define CONFIG_RADIO_ZOLTRIX_PORT -1
@@ -55,8 +55,6 @@ module_param(io, int, 0);
 MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
 module_param(radio_nr, int, 0);
 
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
 struct zoltrix {
        struct v4l2_device v4l2_dev;
        struct video_device vdev;
@@ -228,7 +226,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver));
        strlcpy(v->card, "Zoltrix Radio", sizeof(v->card));
        strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
-       v->version = RADIO_VERSION;
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index a2a67772c42c93695881f7f421fc78a1f6e220fe..fd3541b0e91c74e8fd4515437dad483344e49a45 100644 (file)
 
 /* driver definitions */
 #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>";
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1)
 #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
 #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers"
-#define DRIVER_VERSION "1.0.1"
+#define DRIVER_VERSION "1.0.2"
 
 /* kernel includes */
 #include <linux/i2c.h>
@@ -248,7 +247,6 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
 {
        strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
        strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
-       capability->version = DRIVER_KERNEL_VERSION;
        capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
                V4L2_CAP_TUNER | V4L2_CAP_RADIO;
 
index 392e84fe90ef9f4c1ffee33c99197f776ad338b6..4cf537043f99ec420ae8ebb6f960642a72bf9a5c 100644 (file)
@@ -29,7 +29,6 @@
 
 /* driver definitions */
 #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 10)
 #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
 #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
 #define DRIVER_VERSION "1.0.10"
@@ -626,7 +625,6 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
        strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
        usb_make_path(radio->usbdev, capability->bus_info,
                        sizeof(capability->bus_info));
-       capability->version = DRIVER_KERNEL_VERSION;
        capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
                V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
 
@@ -699,7 +697,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        radio->videodev = video_device_alloc();
        if (!radio->videodev) {
                retval = -ENOMEM;
-               goto err_intbuffer;
+               goto err_urb;
        }
        memcpy(radio->videodev, &si470x_viddev_template,
                        sizeof(si470x_viddev_template));
@@ -790,6 +788,8 @@ err_all:
        kfree(radio->buffer);
 err_video:
        video_device_release(radio->videodev);
+err_urb:
+       usb_free_urb(radio->int_in_urb);
 err_intbuffer:
        kfree(radio->int_in_buffer);
 err_radio:
index 68da001b09dc48f97b110f1602eaee1102443444..f300a55ed85ccee217f3a8ff37565e0fcc5a7d6f 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/input.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <linux/mutex.h>
 #include <media/v4l2-common.h>
index 1a45a5d847b089d1b7752ecf3c7e61cf9b115d05..d84ad9dad323c25bea0e7b0972c1e3f72295ff28 100644 (file)
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <linux/timer.h>
-#include <linux/version.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
 
-#define FM_DRV_VERSION            "0.10"
-/* Should match with FM_DRV_VERSION */
-#define FM_DRV_RADIO_VERSION      KERNEL_VERSION(0, 0, 1)
+#define FM_DRV_VERSION            "0.1.1"
 #define FM_DRV_NAME               "ti_fmdrv"
 #define FM_DRV_CARD_SHORT_NAME    "TI FM Radio"
 #define FM_DRV_CARD_LONG_NAME     "Texas Instruments FM Radio"
index 87010724f9147b53170dc59f1e603115ae2fd72c..8c0e19276970543490fa02b07209825c897e2828 100644 (file)
@@ -175,7 +175,6 @@ static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
        strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME,
                        sizeof(capability->card));
        sprintf(capability->bus_info, "UART");
-       capability->version = FM_DRV_RADIO_VERSION;
        capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
                V4L2_CAP_RADIO | V4L2_CAP_MODULATOR |
                V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
@@ -191,7 +190,7 @@ static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case  V4L2_CID_TUNE_ANTENNA_CAPACITOR:
-               ctrl->cur.val = fm_tx_get_tune_cap_val(fmdev);
+               ctrl->val = fm_tx_get_tune_cap_val(fmdev);
                break;
        default:
                fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id);
index 7d4bbc226d068dd263a18b9ee69c70793245669f..899f783d92fbb4e91d35fd1e8395a86a1732794c 100644 (file)
@@ -87,6 +87,17 @@ config IR_RC5_SZ_DECODER
           uses an IR protocol that is almost standard RC-5, but not quite,
           as it uses an additional bit).
 
+config IR_MCE_KBD_DECODER
+       tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
+       depends on RC_CORE
+       select BITREVERSE
+       default y
+
+       ---help---
+          Enable this option if you have a Microsoft Remote Keyboard for
+          Windows Media Center Edition, which you would like to use with
+          a raw IR receiver in your system.
+
 config IR_LIRC_CODEC
        tristate "Enable IR to LIRC bridge"
        depends on RC_CORE
index 52830e5f4eaaa4ee184fc20ff0ece6e3f3809ace..f224db027c411ecdaf8ddfa69f5bec43e2b1d05f 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
 obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
 obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
 obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
+obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
 obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
 
 # stand-alone IR receivers/transmitters
index a43ed6c41bfc475361fd9b0155826dfd69a3746e..2b9c2569d74a2163888769e41045e97a7a5fc642 100644 (file)
@@ -953,13 +953,13 @@ static void ene_set_idle(struct rc_dev *rdev, bool idle)
 }
 
 /* outside interface: transmit */
-static int ene_transmit(struct rc_dev *rdev, int *buf, u32 n)
+static int ene_transmit(struct rc_dev *rdev, unsigned *buf, unsigned n)
 {
        struct ene_device *dev = rdev->priv;
        unsigned long flags;
 
        dev->tx_buffer = buf;
-       dev->tx_len = n / sizeof(int);
+       dev->tx_len = n;
        dev->tx_pos = 0;
        dev->tx_reg = 0;
        dev->tx_done = 0;
index 337a41d4450ba2aee45171cfc7e92117baf7e24e..017c209cdf8a2ac51ae7365908102e8dc4e8a10d 100644 (file)
@@ -235,7 +235,7 @@ struct ene_device {
        bool tx_sample_pulse;                   /* current sample is pulse */
 
        /* TX buffer */
-       int *tx_buffer;                         /* input samples buffer*/
+       unsigned *tx_buffer;                    /* input samples buffer*/
        int tx_pos;                             /* position in that bufer */
        int tx_len;                             /* current len of tx buffer */
        int tx_done;                            /* done transmitting */
index 1c5cc65ea1e11463c9ba6998f48c1947988e842a..e5eeec4da76ea776972cc202ac4367605dd999bb 100644 (file)
@@ -103,19 +103,19 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
 {
        struct lirc_codec *lirc;
        struct rc_dev *dev;
-       int *txbuf; /* buffer with values to transmit */
-       int ret = 0;
+       unsigned int *txbuf; /* buffer with values to transmit */
+       ssize_t ret = 0;
        size_t count;
 
        lirc = lirc_get_pdata(file);
        if (!lirc)
                return -EFAULT;
 
-       if (n % sizeof(int))
+       if (n < sizeof(unsigned) || n % sizeof(unsigned))
                return -EINVAL;
 
-       count = n / sizeof(int);
-       if (count > LIRCBUF_SIZE || count % 2 == 0 || n % sizeof(int) != 0)
+       count = n / sizeof(unsigned);
+       if (count > LIRCBUF_SIZE || count % 2 == 0)
                return -EINVAL;
 
        txbuf = memdup_user(buf, n);
@@ -129,7 +129,10 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
        }
 
        if (dev->tx_ir)
-               ret = dev->tx_ir(dev, txbuf, (u32)n);
+               ret = dev->tx_ir(dev, txbuf, count);
+
+       if (ret > 0)
+               ret *= sizeof(unsigned);
 
 out:
        kfree(txbuf);
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
new file mode 100644 (file)
index 0000000..3784ebf
--- /dev/null
@@ -0,0 +1,449 @@
+/* ir-mce_kbd-decoder.c - A decoder for the RC6-ish keyboard/mouse IR protocol
+ * used by the Microsoft Remote Keyboard for Windows Media Center Edition,
+ * referred to by Microsoft's Windows Media Center remote specification docs
+ * as "an internal protocol called MCIR-2".
+ *
+ * Copyright (C) 2011 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 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.
+ */
+#include <linux/module.h>
+
+#include "rc-core-priv.h"
+
+/*
+ * This decoder currently supports:
+ * - MCIR-2 29-bit IR signals used for mouse movement and buttons
+ * - MCIR-2 32-bit IR signals used for standard keyboard keys
+ *
+ * The media keys on the keyboard send RC-6 signals that are inditinguishable
+ * from the keys of the same name on the stock MCE remote, and will be handled
+ * by the standard RC-6 decoder, and be made available to the system via the
+ * input device for the remote, rather than the keyboard/mouse one.
+ */
+
+#define MCIR2_UNIT             333333  /* ns */
+#define MCIR2_HEADER_NBITS     5
+#define MCIR2_MOUSE_NBITS      29
+#define MCIR2_KEYBOARD_NBITS   32
+#define MCIR2_PREFIX_PULSE     (8 * MCIR2_UNIT)
+#define MCIR2_PREFIX_SPACE     (1 * MCIR2_UNIT)
+#define MCIR2_MAX_LEN          (3 * MCIR2_UNIT)
+#define MCIR2_BIT_START                (1 * MCIR2_UNIT)
+#define MCIR2_BIT_END          (1 * MCIR2_UNIT)
+#define MCIR2_BIT_0            (1 * MCIR2_UNIT)
+#define MCIR2_BIT_SET          (2 * MCIR2_UNIT)
+#define MCIR2_MODE_MASK                0xf     /* for the header bits */
+#define MCIR2_KEYBOARD_HEADER  0x4
+#define MCIR2_MOUSE_HEADER     0x1
+#define MCIR2_MASK_KEYS_START  0xe0
+
+enum mce_kbd_mode {
+       MCIR2_MODE_KEYBOARD,
+       MCIR2_MODE_MOUSE,
+       MCIR2_MODE_UNKNOWN,
+};
+
+enum mce_kbd_state {
+       STATE_INACTIVE,
+       STATE_HEADER_BIT_START,
+       STATE_HEADER_BIT_END,
+       STATE_BODY_BIT_START,
+       STATE_BODY_BIT_END,
+       STATE_FINISHED,
+};
+
+static unsigned char kbd_keycodes[256] = {
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_A,
+       KEY_B,          KEY_C,          KEY_D,          KEY_E,          KEY_F,
+       KEY_G,          KEY_H,          KEY_I,          KEY_J,          KEY_K,
+       KEY_L,          KEY_M,          KEY_N,          KEY_O,          KEY_P,
+       KEY_Q,          KEY_R,          KEY_S,          KEY_T,          KEY_U,
+       KEY_V,          KEY_W,          KEY_X,          KEY_Y,          KEY_Z,
+       KEY_1,          KEY_2,          KEY_3,          KEY_4,          KEY_5,
+       KEY_6,          KEY_7,          KEY_8,          KEY_9,          KEY_0,
+       KEY_ENTER,      KEY_ESC,        KEY_BACKSPACE,  KEY_TAB,        KEY_SPACE,
+       KEY_MINUS,      KEY_EQUAL,      KEY_LEFTBRACE,  KEY_RIGHTBRACE, KEY_BACKSLASH,
+       KEY_RESERVED,   KEY_SEMICOLON,  KEY_APOSTROPHE, KEY_GRAVE,      KEY_COMMA,
+       KEY_DOT,        KEY_SLASH,      KEY_CAPSLOCK,   KEY_F1,         KEY_F2,
+       KEY_F3,         KEY_F4,         KEY_F5,         KEY_F6,         KEY_F7,
+       KEY_F8,         KEY_F9,         KEY_F10,        KEY_F11,        KEY_F12,
+       KEY_SYSRQ,      KEY_SCROLLLOCK, KEY_PAUSE,      KEY_INSERT,     KEY_HOME,
+       KEY_PAGEUP,     KEY_DELETE,     KEY_END,        KEY_PAGEDOWN,   KEY_RIGHT,
+       KEY_LEFT,       KEY_DOWN,       KEY_UP,         KEY_NUMLOCK,    KEY_KPSLASH,
+       KEY_KPASTERISK, KEY_KPMINUS,    KEY_KPPLUS,     KEY_KPENTER,    KEY_KP1,
+       KEY_KP2,        KEY_KP3,        KEY_KP4,        KEY_KP5,        KEY_KP6,
+       KEY_KP7,        KEY_KP8,        KEY_KP9,        KEY_KP0,        KEY_KPDOT,
+       KEY_102ND,      KEY_COMPOSE,    KEY_POWER,      KEY_KPEQUAL,    KEY_F13,
+       KEY_F14,        KEY_F15,        KEY_F16,        KEY_F17,        KEY_F18,
+       KEY_F19,        KEY_F20,        KEY_F21,        KEY_F22,        KEY_F23,
+       KEY_F24,        KEY_OPEN,       KEY_HELP,       KEY_PROPS,      KEY_FRONT,
+       KEY_STOP,       KEY_AGAIN,      KEY_UNDO,       KEY_CUT,        KEY_COPY,
+       KEY_PASTE,      KEY_FIND,       KEY_MUTE,       KEY_VOLUMEUP,   KEY_VOLUMEDOWN,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_KPCOMMA,    KEY_RESERVED,
+       KEY_RO,         KEY_KATAKANAHIRAGANA, KEY_YEN,  KEY_HENKAN,     KEY_MUHENKAN,
+       KEY_KPJPCOMMA,  KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_HANGUEL,
+       KEY_HANJA,      KEY_KATAKANA,   KEY_HIRAGANA,   KEY_ZENKAKUHANKAKU, KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,   KEY_LEFTCTRL,
+       KEY_LEFTSHIFT,  KEY_LEFTALT,    KEY_LEFTMETA,   KEY_RIGHTCTRL,  KEY_RIGHTSHIFT,
+       KEY_RIGHTALT,   KEY_RIGHTMETA,  KEY_PLAYPAUSE,  KEY_STOPCD,     KEY_PREVIOUSSONG,
+       KEY_NEXTSONG,   KEY_EJECTCD,    KEY_VOLUMEUP,   KEY_VOLUMEDOWN, KEY_MUTE,
+       KEY_WWW,        KEY_BACK,       KEY_FORWARD,    KEY_STOP,       KEY_FIND,
+       KEY_SCROLLUP,   KEY_SCROLLDOWN, KEY_EDIT,       KEY_SLEEP,      KEY_COFFEE,
+       KEY_REFRESH,    KEY_CALC,       KEY_RESERVED,   KEY_RESERVED,   KEY_RESERVED,
+       KEY_RESERVED
+};
+
+static void mce_kbd_rx_timeout(unsigned long data)
+{
+       struct mce_kbd_dec *mce_kbd = (struct mce_kbd_dec *)data;
+       int i;
+       unsigned char maskcode;
+
+       IR_dprintk(2, "timer callback clearing all keys\n");
+
+       for (i = 0; i < 7; i++) {
+               maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
+               input_report_key(mce_kbd->idev, maskcode, 0);
+       }
+
+       for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
+               input_report_key(mce_kbd->idev, kbd_keycodes[i], 0);
+}
+
+static enum mce_kbd_mode mce_kbd_mode(struct mce_kbd_dec *data)
+{
+       switch (data->header & MCIR2_MODE_MASK) {
+       case MCIR2_KEYBOARD_HEADER:
+               return MCIR2_MODE_KEYBOARD;
+       case MCIR2_MOUSE_HEADER:
+               return MCIR2_MODE_MOUSE;
+       default:
+               return MCIR2_MODE_UNKNOWN;
+       }
+}
+
+static void ir_mce_kbd_process_keyboard_data(struct input_dev *idev,
+                                            u32 scancode)
+{
+       u8 keydata   = (scancode >> 8) & 0xff;
+       u8 shiftmask = scancode & 0xff;
+       unsigned char keycode, maskcode;
+       int i, keystate;
+
+       IR_dprintk(1, "keyboard: keydata = 0x%02x, shiftmask = 0x%02x\n",
+                  keydata, shiftmask);
+
+       for (i = 0; i < 7; i++) {
+               maskcode = kbd_keycodes[MCIR2_MASK_KEYS_START + i];
+               if (shiftmask & (1 << i))
+                       keystate = 1;
+               else
+                       keystate = 0;
+               input_report_key(idev, maskcode, keystate);
+       }
+
+       if (keydata) {
+               keycode = kbd_keycodes[keydata];
+               input_report_key(idev, keycode, 1);
+       } else {
+               for (i = 0; i < MCIR2_MASK_KEYS_START; i++)
+                       input_report_key(idev, kbd_keycodes[i], 0);
+       }
+}
+
+static void ir_mce_kbd_process_mouse_data(struct input_dev *idev, u32 scancode)
+{
+       /* raw mouse coordinates */
+       u8 xdata = (scancode >> 7) & 0x7f;
+       u8 ydata = (scancode >> 14) & 0x7f;
+       int x, y;
+       /* mouse buttons */
+       bool right = scancode & 0x40;
+       bool left  = scancode & 0x20;
+
+       if (xdata & 0x40)
+               x = -((~xdata & 0x7f) + 1);
+       else
+               x = xdata;
+
+       if (ydata & 0x40)
+               y = -((~ydata & 0x7f) + 1);
+       else
+               y = ydata;
+
+       IR_dprintk(1, "mouse: x = %d, y = %d, btns = %s%s\n",
+                  x, y, left ? "L" : "", right ? "R" : "");
+
+       input_report_rel(idev, REL_X, x);
+       input_report_rel(idev, REL_Y, y);
+
+       input_report_key(idev, BTN_LEFT, left);
+       input_report_key(idev, BTN_RIGHT, right);
+}
+
+/**
+ * ir_mce_kbd_decode() - Decode one mce_kbd pulse or space
+ * @dev:       the struct rc_dev descriptor of the device
+ * @ev:                the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
+{
+       struct mce_kbd_dec *data = &dev->raw->mce_kbd;
+       u32 scancode;
+       unsigned long delay;
+
+       if (!(dev->raw->enabled_protocols & RC_TYPE_MCE_KBD))
+               return 0;
+
+       if (!is_timing_event(ev)) {
+               if (ev.reset)
+                       data->state = STATE_INACTIVE;
+               return 0;
+       }
+
+       if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
+               goto out;
+
+again:
+       IR_dprintk(2, "started at state %i (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+       if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
+               return 0;
+
+       switch (data->state) {
+
+       case STATE_INACTIVE:
+               if (!ev.pulse)
+                       break;
+
+               /* Note: larger margin on first pulse since each MCIR2_UNIT
+                  is quite short and some hardware takes some time to
+                  adjust to the signal */
+               if (!eq_margin(ev.duration, MCIR2_PREFIX_PULSE, MCIR2_UNIT))
+                       break;
+
+               data->state = STATE_HEADER_BIT_START;
+               data->count = 0;
+               data->header = 0;
+               return 0;
+
+       case STATE_HEADER_BIT_START:
+               if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
+                       break;
+
+               data->header <<= 1;
+               if (ev.pulse)
+                       data->header |= 1;
+               data->count++;
+               data->state = STATE_HEADER_BIT_END;
+               return 0;
+
+       case STATE_HEADER_BIT_END:
+               if (!is_transition(&ev, &dev->raw->prev_ev))
+                       break;
+
+               decrease_duration(&ev, MCIR2_BIT_END);
+
+               if (data->count != MCIR2_HEADER_NBITS) {
+                       data->state = STATE_HEADER_BIT_START;
+                       goto again;
+               }
+
+               switch (mce_kbd_mode(data)) {
+               case MCIR2_MODE_KEYBOARD:
+                       data->wanted_bits = MCIR2_KEYBOARD_NBITS;
+                       break;
+               case MCIR2_MODE_MOUSE:
+                       data->wanted_bits = MCIR2_MOUSE_NBITS;
+                       break;
+               default:
+                       IR_dprintk(1, "not keyboard or mouse data\n");
+                       goto out;
+               }
+
+               data->count = 0;
+               data->body = 0;
+               data->state = STATE_BODY_BIT_START;
+               goto again;
+
+       case STATE_BODY_BIT_START:
+               if (geq_margin(ev.duration, MCIR2_MAX_LEN, MCIR2_UNIT / 2))
+                       break;
+
+               data->body <<= 1;
+               if (ev.pulse)
+                       data->body |= 1;
+               data->count++;
+               data->state = STATE_BODY_BIT_END;
+               return 0;
+
+       case STATE_BODY_BIT_END:
+               if (!is_transition(&ev, &dev->raw->prev_ev))
+                       break;
+
+               if (data->count == data->wanted_bits)
+                       data->state = STATE_FINISHED;
+               else
+                       data->state = STATE_BODY_BIT_START;
+
+               decrease_duration(&ev, MCIR2_BIT_END);
+               goto again;
+
+       case STATE_FINISHED:
+               if (ev.pulse)
+                       break;
+
+               switch (data->wanted_bits) {
+               case MCIR2_KEYBOARD_NBITS:
+                       scancode = data->body & 0xffff;
+                       IR_dprintk(1, "keyboard data 0x%08x\n", data->body);
+                       if (dev->timeout)
+                               delay = usecs_to_jiffies(dev->timeout / 1000);
+                       else
+                               delay = msecs_to_jiffies(100);
+                       mod_timer(&data->rx_timeout, jiffies + delay);
+                       /* Pass data to keyboard buffer parser */
+                       ir_mce_kbd_process_keyboard_data(data->idev, scancode);
+                       break;
+               case MCIR2_MOUSE_NBITS:
+                       scancode = data->body & 0x1fffff;
+                       IR_dprintk(1, "mouse data 0x%06x\n", scancode);
+                       /* Pass data to mouse buffer parser */
+                       ir_mce_kbd_process_mouse_data(data->idev, scancode);
+                       break;
+               default:
+                       IR_dprintk(1, "not keyboard or mouse data\n");
+                       goto out;
+               }
+
+               data->state = STATE_INACTIVE;
+               input_sync(data->idev);
+               return 0;
+       }
+
+out:
+       IR_dprintk(1, "failed at state %i (%uus %s)\n",
+                  data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+       data->state = STATE_INACTIVE;
+       input_sync(data->idev);
+       return -EINVAL;
+}
+
+static int ir_mce_kbd_register(struct rc_dev *dev)
+{
+       struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd;
+       struct input_dev *idev;
+       int i, ret;
+
+       idev = input_allocate_device();
+       if (!idev)
+               return -ENOMEM;
+
+       snprintf(mce_kbd->name, sizeof(mce_kbd->name),
+                "MCE IR Keyboard/Mouse (%s)", dev->driver_name);
+       strlcat(mce_kbd->phys, "/input0", sizeof(mce_kbd->phys));
+
+       idev->name = mce_kbd->name;
+       idev->phys = mce_kbd->phys;
+
+       /* Keyboard bits */
+       set_bit(EV_KEY, idev->evbit);
+       set_bit(EV_REP, idev->evbit);
+       for (i = 0; i < sizeof(kbd_keycodes); i++)
+               set_bit(kbd_keycodes[i], idev->keybit);
+
+       /* Mouse bits */
+       set_bit(EV_REL, idev->evbit);
+       set_bit(REL_X, idev->relbit);
+       set_bit(REL_Y, idev->relbit);
+       set_bit(BTN_LEFT, idev->keybit);
+       set_bit(BTN_RIGHT, idev->keybit);
+
+       /* Report scancodes too */
+       set_bit(EV_MSC, idev->evbit);
+       set_bit(MSC_SCAN, idev->mscbit);
+
+       setup_timer(&mce_kbd->rx_timeout, mce_kbd_rx_timeout,
+                   (unsigned long)mce_kbd);
+
+       input_set_drvdata(idev, mce_kbd);
+
+#if 0
+       /* Adding this reference means two input devices are associated with
+        * this rc-core device, which ir-keytable doesn't cope with yet */
+       idev->dev.parent = &dev->dev;
+#endif
+
+       ret = input_register_device(idev);
+       if (ret < 0) {
+               input_free_device(idev);
+               return -EIO;
+       }
+
+       mce_kbd->idev = idev;
+
+       return 0;
+}
+
+static int ir_mce_kbd_unregister(struct rc_dev *dev)
+{
+       struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd;
+       struct input_dev *idev = mce_kbd->idev;
+
+       del_timer_sync(&mce_kbd->rx_timeout);
+       input_unregister_device(idev);
+
+       return 0;
+}
+
+static struct ir_raw_handler mce_kbd_handler = {
+       .protocols      = RC_TYPE_MCE_KBD,
+       .decode         = ir_mce_kbd_decode,
+       .raw_register   = ir_mce_kbd_register,
+       .raw_unregister = ir_mce_kbd_unregister,
+};
+
+static int __init ir_mce_kbd_decode_init(void)
+{
+       ir_raw_handler_register(&mce_kbd_handler);
+
+       printk(KERN_INFO "IR MCE Keyboard/mouse protocol handler initialized\n");
+       return 0;
+}
+
+static void __exit ir_mce_kbd_decode_exit(void)
+{
+       ir_raw_handler_unregister(&mce_kbd_handler);
+}
+
+module_init(ir_mce_kbd_decode_init);
+module_exit(ir_mce_kbd_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_DESCRIPTION("MCE Keyboard/mouse IR protocol decoder");
index 423ed45d6c55a4e3ccb43f3ae1284bcf55d952da..27808bb59eba3874ee7c1c07f79ba67f82abfd78 100644 (file)
@@ -355,6 +355,7 @@ static void init_decoders(struct work_struct *work)
        load_rc6_decode();
        load_jvc_decode();
        load_sony_decode();
+       load_mce_kbd_decode();
        load_lirc_codec();
 
        /* If needed, we may later add some init code. In this case,
index d20168fe4c40a673301af4ea985c9c1f18e4ce72..682009d76cdfe487ffe950c17235075808893795 100644 (file)
@@ -382,7 +382,7 @@ static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle)
 /* transmit out IR pulses; what you get here is a batch of alternating
  * pulse/space/pulse/space lengths that we should write out completely through
  * the FIFO, blocking on a full FIFO */
-static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
+static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n)
 {
        unsigned long flags;
        struct ite_dev *dev = rcdev->priv;
@@ -398,9 +398,6 @@ static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
        /* clear the array just in case */
        memset(last_sent, 0, ARRAY_SIZE(last_sent));
 
-       /* n comes in bytes; convert to ints */
-       n /= sizeof(int);
-
        spin_lock_irqsave(&dev->lock, flags);
 
        /* let everybody know we're now transmitting */
index 01b69bcc86667e9e40bbb75eaeabdbe6994afa53..c3907e211d397bd7dadb36b46ec184d3b29d1884 100644 (file)
@@ -29,7 +29,7 @@ static struct rc_map_table rc6_mce[] = {
 
        { 0x800f040a, KEY_DELETE },
        { 0x800f040b, KEY_ENTER },
-       { 0x800f040c, KEY_POWER },              /* PC Power */
+       { 0x800f040c, KEY_SLEEP },              /* Formerly PC Power */
        { 0x800f040d, KEY_MEDIA },              /* Windows MCE button */
        { 0x800f040e, KEY_MUTE },
        { 0x800f040f, KEY_INFO },
@@ -44,7 +44,6 @@ static struct rc_map_table rc6_mce[] = {
        { 0x800f0416, KEY_PLAY },
        { 0x800f0417, KEY_RECORD },
        { 0x800f0418, KEY_PAUSE },
-       { 0x800f046e, KEY_PLAYPAUSE },
        { 0x800f0419, KEY_STOP },
        { 0x800f041a, KEY_NEXT },
        { 0x800f041b, KEY_PREVIOUS },
index ec972dc25790ea8b18e2641a0e045e1f5858bc3f..85ff9a1ffb391b4ccfa291539e027ffa2c8d10da 100644 (file)
@@ -692,20 +692,18 @@ static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size)
 }
 
 /* Send data out the IR blaster port(s) */
-static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
+static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 {
        struct mceusb_dev *ir = dev->priv;
        int i, ret = 0;
-       int count, cmdcount = 0;
+       int cmdcount = 0;
        unsigned char *cmdbuf; /* MCE command buffer */
        long signal_duration = 0; /* Singnal length in us */
        struct timeval start_time, end_time;
 
        do_gettimeofday(&start_time);
 
-       count = n / sizeof(int);
-
-       cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL);
+       cmdbuf = kzalloc(sizeof(unsigned) * MCE_CMDBUF_SIZE, GFP_KERNEL);
        if (!cmdbuf)
                return -ENOMEM;
 
@@ -774,7 +772,7 @@ static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
 
 out:
        kfree(cmdbuf);
-       return ret ? ret : n;
+       return ret ? ret : count;
 }
 
 /* Sets active IR outputs -- mce devices typically have two */
index ce595f9ab4c7a41c16ff0d69ecc33faf9fc3c4f4..eae05b5004761d334519a8aca4784b2db815f959 100644 (file)
@@ -546,24 +546,18 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
  * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to
  * set TXFCONT as 0xff, until buf_count less than 0xff.
  */
-static int nvt_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
+static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n)
 {
        struct nvt_dev *nvt = dev->priv;
        unsigned long flags;
-       size_t cur_count;
        unsigned int i;
        u8 iren;
        int ret;
 
        spin_lock_irqsave(&nvt->tx.lock, flags);
 
-       if (n >= TX_BUF_LEN) {
-               nvt->tx.buf_count = cur_count = TX_BUF_LEN;
-               ret = TX_BUF_LEN;
-       } else {
-               nvt->tx.buf_count = cur_count = n;
-               ret = n;
-       }
+       ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n);
+       nvt->tx.buf_count = (ret * sizeof(unsigned));
 
        memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count);
 
index 873b387897511f59b446bfe4a9a94659a8f0611c..04c2c722b6ece48d9ead508e952b6e4ab4927328 100644 (file)
@@ -84,6 +84,17 @@ struct ir_raw_event_ctrl {
                unsigned count;
                unsigned wanted_bits;
        } rc5_sz;
+       struct mce_kbd_dec {
+               struct input_dev *idev;
+               struct timer_list rx_timeout;
+               char name[64];
+               char phys[64];
+               int state;
+               u8 header;
+               u32 body;
+               unsigned count;
+               unsigned wanted_bits;
+       } mce_kbd;
        struct lirc_codec {
                struct rc_dev *dev;
                struct lirc_driver *drv;
@@ -182,6 +193,13 @@ void ir_raw_init(void);
 #define load_sony_decode()     0
 #endif
 
+/* from ir-mce_kbd-decoder.c */
+#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE
+#define load_mce_kbd_decode()  request_module("ir-mce_kbd-decoder")
+#else
+#define load_mce_kbd_decode()  0
+#endif
+
 /* from ir-lirc-codec.c */
 #ifdef CONFIG_IR_LIRC_CODEC_MODULE
 #define load_lirc_codec()      request_module("ir-lirc-codec")
index cc846b2619cf38bb6f77d2a35ad8d2167dfc5bf1..efc6a514348afc394836026ddb885b328b6bc1ac 100644 (file)
@@ -101,21 +101,14 @@ static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
        return 0;
 }
 
-static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
+static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
 {
        struct loopback_dev *lodev = dev->priv;
        u32 rxmask;
-       unsigned count;
        unsigned total_duration = 0;
        unsigned i;
        DEFINE_IR_RAW_EVENT(rawir);
 
-       if (n == 0 || n % sizeof(int)) {
-               dprintk("invalid tx buffer size\n");
-               return -EINVAL;
-       }
-
-       count = n / sizeof(int);
        for (i = 0; i < count; i++)
                total_duration += abs(txbuf[i]);
 
@@ -142,7 +135,7 @@ static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
 
        for (i = 0; i < count; i++) {
                rawir.pulse = i % 2 ? false : true;
-               rawir.duration = abs(txbuf[i]) * 1000;
+               rawir.duration = txbuf[i] * 1000;
                if (rawir.duration)
                        ir_raw_event_store_with_filter(dev, &rawir);
        }
@@ -158,7 +151,7 @@ out:
        /* Lirc expects this function to take as long as the total duration */
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(usecs_to_jiffies(total_duration));
-       return n;
+       return count;
 }
 
 static void loop_set_idle(struct rc_dev *dev, bool enable)
index 3186ac7c2c108c00d4346076d4bc20fc0d765df2..51a23f48bc7d83f99eed629a32188083f22786c3 100644 (file)
@@ -735,6 +735,7 @@ static struct {
        { RC_TYPE_JVC,          "jvc"           },
        { RC_TYPE_SONY,         "sony"          },
        { RC_TYPE_RC5_SZ,       "rc-5-sz"       },
+       { RC_TYPE_MCE_KBD,      "mce_kbd"       },
        { RC_TYPE_LIRC,         "lirc"          },
        { RC_TYPE_OTHER,        "other"         },
 };
@@ -1099,7 +1100,6 @@ int rc_register_device(struct rc_dev *dev)
                if (rc < 0)
                        goto out_input;
        }
-       mutex_unlock(&dev->lock);
 
        if (dev->change_protocol) {
                rc = dev->change_protocol(dev, rc_map->rc_type);
@@ -1107,6 +1107,8 @@ int rc_register_device(struct rc_dev *dev)
                        goto out_raw;
        }
 
+       mutex_unlock(&dev->lock);
+
        IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n",
                   dev->devno,
                   dev->driver_name ? dev->driver_name : "unknown",
index 5147767ccb78045523bbd7f37dd732063a86c388..a166044779174bd4349572a052af3b16ff3b3c6d 100644 (file)
@@ -205,6 +205,7 @@ struct redrat3_dev {
 
        /* rx signal timeout timer */
        struct timer_list rx_timeout;
+       u32 hw_timeout;
 
        /* Is the device currently receiving? */
        bool recv_in_progress;
@@ -414,20 +415,10 @@ static u32 redrat3_us_to_len(u32 microsec)
 
 }
 
-/* timer callback to send long trailing space on receive timeout */
+/* timer callback to send reset event */
 static void redrat3_rx_timeout(unsigned long data)
 {
        struct redrat3_dev *rr3 = (struct redrat3_dev *)data;
-       DEFINE_IR_RAW_EVENT(rawir);
-
-       rawir.pulse = false;
-       rawir.duration = rr3->rc->timeout;
-       rr3_dbg(rr3->dev, "storing trailing space with duration %d\n",
-               rawir.duration);
-       ir_raw_event_store_with_filter(rr3->rc, &rawir);
-
-       rr3_dbg(rr3->dev, "calling ir_raw_event_handle\n");
-       ir_raw_event_handle(rr3->rc);
 
        rr3_dbg(rr3->dev, "calling ir_raw_event_reset\n");
        ir_raw_event_reset(rr3->rc);
@@ -438,7 +429,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
        DEFINE_IR_RAW_EVENT(rawir);
        struct redrat3_signal_header header;
        struct device *dev;
-       int i;
+       int i, trailer = 0;
        unsigned long delay;
        u32 mod_freq, single_len;
        u16 *len_vals;
@@ -464,7 +455,8 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
        if (!(header.length >= RR3_HEADER_LENGTH))
                dev_warn(dev, "read returned less than rr3 header len\n");
 
-       delay = usecs_to_jiffies(rr3->rc->timeout / 1000);
+       /* Make sure we reset the IR kfifo after a bit of inactivity */
+       delay = usecs_to_jiffies(rr3->hw_timeout);
        mod_timer(&rr3->rx_timeout, jiffies + delay);
 
        memcpy(&tmp32, sig_data + RR3_PAUSE_OFFSET, sizeof(tmp32));
@@ -506,9 +498,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
                u16 val = len_vals[data_vals[i]];
                single_len = redrat3_len_to_us((u32)be16_to_cpu(val));
 
-               /* cap the value to IR_MAX_DURATION */
-               single_len &= IR_MAX_DURATION;
-
                /* we should always get pulse/space/pulse/space samples */
                if (i % 2)
                        rawir.pulse = false;
@@ -516,6 +505,12 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
                        rawir.pulse = true;
 
                rawir.duration = US_TO_NS(single_len);
+               /* Save initial pulse length to fudge trailer */
+               if (i == 0)
+                       trailer = rawir.duration;
+               /* cap the value to IR_MAX_DURATION */
+               rawir.duration &= IR_MAX_DURATION;
+
                rr3_dbg(dev, "storing %s with duration %d (i: %d)\n",
                        rawir.pulse ? "pulse" : "space", rawir.duration, i);
                ir_raw_event_store_with_filter(rr3->rc, &rawir);
@@ -525,7 +520,10 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
        if (i % 2) {
                rawir.pulse = false;
                /* this duration is made up, and may not be ideal... */
-               rawir.duration = rr3->rc->timeout / 2;
+               if (trailer < US_TO_NS(1000))
+                       rawir.duration = US_TO_NS(2800);
+               else
+                       rawir.duration = trailer;
                rr3_dbg(dev, "storing trailing space with duration %d\n",
                        rawir.duration);
                ir_raw_event_store_with_filter(rr3->rc, &rawir);
@@ -629,36 +627,31 @@ static inline void redrat3_delete(struct redrat3_dev *rr3,
        kfree(rr3);
 }
 
-static u32 redrat3_get_timeout(struct device *dev,
-                              struct rc_dev *rc, struct usb_device *udev)
+static u32 redrat3_get_timeout(struct redrat3_dev *rr3)
 {
        u32 *tmp;
-       u32 timeout = MS_TO_NS(150); /* a sane default, if things go haywire */
+       u32 timeout = MS_TO_US(150); /* a sane default, if things go haywire */
        int len, ret, pipe;
 
        len = sizeof(*tmp);
        tmp = kzalloc(len, GFP_KERNEL);
        if (!tmp) {
-               dev_warn(dev, "Memory allocation faillure\n");
+               dev_warn(rr3->dev, "Memory allocation faillure\n");
                return timeout;
        }
 
-       pipe = usb_rcvctrlpipe(udev, 0);
-       ret = usb_control_msg(udev, pipe, RR3_GET_IR_PARAM,
+       pipe = usb_rcvctrlpipe(rr3->udev, 0);
+       ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM,
                              USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                              RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5);
        if (ret != len) {
-               dev_warn(dev, "Failed to read timeout from hardware\n");
+               dev_warn(rr3->dev, "Failed to read timeout from hardware\n");
                return timeout;
        }
 
-       timeout = US_TO_NS(redrat3_len_to_us(be32_to_cpu(*tmp)));
-       if (timeout < rc->min_timeout)
-               timeout = rc->min_timeout;
-       else if (timeout > rc->max_timeout)
-               timeout = rc->max_timeout;
+       timeout = redrat3_len_to_us(be32_to_cpu(*tmp));
 
-       rr3_dbg(dev, "Got timeout of %d ms\n", timeout / (1000 * 1000));
+       rr3_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000);
        return timeout;
 }
 
@@ -1110,9 +1103,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
        rc->priv = rr3;
        rc->driver_type = RC_DRIVER_IR_RAW;
        rc->allowed_protos = RC_TYPE_ALL;
-       rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT);
-       rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT);
-       rc->timeout = redrat3_get_timeout(dev, rc, rr3->udev);
+       rc->timeout = US_TO_NS(2750);
        rc->tx_ir = redrat3_transmit_ir;
        rc->s_tx_carrier = redrat3_set_tx_carrier;
        rc->driver_name = DRIVER_NAME;
@@ -1186,7 +1177,7 @@ static int __devinit redrat3_dev_probe(struct usb_interface *intf,
        rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL);
        if (rr3 == NULL) {
                dev_err(dev, "Memory allocation failure\n");
-               goto error;
+               goto no_endpoints;
        }
 
        rr3->dev = &intf->dev;
@@ -1242,6 +1233,9 @@ static int __devinit redrat3_dev_probe(struct usb_interface *intf,
        if (retval < 0)
                goto error;
 
+       /* store current hardware timeout, in us, will use for kfifo resets */
+       rr3->hw_timeout = redrat3_get_timeout(rr3);
+
        /* default.. will get overridden by any sends with a freq defined */
        rr3->carrier = 38000;
 
@@ -1280,6 +1274,7 @@ static void __devexit redrat3_dev_disconnect(struct usb_interface *intf)
 
        usb_set_intfdata(intf, NULL);
        rc_unregister_device(rr3->rc);
+       del_timer_sync(&rr3->rx_timeout);
        redrat3_delete(rr3, udev);
 
        rr3_ftr(&intf->dev, "RedRat3 IR Transceiver now disconnected\n");
index 5d06b899e85959a97e75fea8478b74897f36a0ef..bec8abc965f78061e7238bad7eda1adf58bd8b92 100644 (file)
@@ -6,8 +6,8 @@
  *  could probably support others (Winbond WEC102X, NatSemi, etc)
  *  with minor modifications.
  *
- *  Original Author: David Härdeman <david@hardeman.nu>
- *     Copyright (C) 2009 - 2010 David Härdeman <david@hardeman.nu>
+ *  Original Author: David Härdeman <david@hardeman.nu>
+ *     Copyright (C) 2009 - 2011 David Härdeman <david@hardeman.nu>
  *
  *  Dedicated to my daughter Matilda, without whose loving attention this
  *  driver would have been finished in half the time and with a fraction
@@ -577,16 +577,12 @@ wbcir_txmask(struct rc_dev *dev, u32 mask)
 }
 
 static int
-wbcir_tx(struct rc_dev *dev, int *buf, u32 bufsize)
+wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count)
 {
        struct wbcir_data *data = dev->priv;
-       u32 count;
        unsigned i;
        unsigned long flags;
 
-       /* bufsize has been sanity checked by the caller */
-       count = bufsize / sizeof(int);
-
        /* Not sure if this is possible, but better safe than sorry */
        spin_lock_irqsave(&data->spinlock, flags);
        if (data->txstate != WBCIR_TXSTATE_INACTIVE) {
@@ -876,18 +872,8 @@ wbcir_init_hw(struct wbcir_data *data)
        /* prescaler 1.0, tx/rx fifo lvl 16 */
        outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
 
-       /* Set baud divisor to generate one byte per bit/cell */
-       switch (protocol) {
-       case IR_PROTOCOL_RC5:
-               outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       case IR_PROTOCOL_RC6:
-               outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       case IR_PROTOCOL_NEC:
-               outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
-               break;
-       }
+       /* Set baud divisor to sample every 10 us */
+       outb(0x0F, data->sbase + WBCIR_REG_SP3_BGDL);
        outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
 
        /* Set CEIR mode */
@@ -896,9 +882,9 @@ wbcir_init_hw(struct wbcir_data *data)
        inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
        inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
 
-       /* Disable RX demod, run-length encoding/decoding, set freq span */
+       /* Disable RX demod, enable run-length enc/dec, set freq span */
        wbcir_select_bank(data, WBCIR_BANK_7);
-       outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
+       outb(0x90, data->sbase + WBCIR_REG_SP3_RCCFG);
 
        /* Disable timer */
        wbcir_select_bank(data, WBCIR_BANK_4);
index bb53de7fe4087b227f98b63cdc15b035d28f008c..f574dc012cad047a817201b00676ff1497ac255c 100644 (file)
@@ -489,6 +489,15 @@ config VIDEO_TCM825X
          This is a driver for the Toshiba TCM825x VGA camera sensor.
          It is used for example in Nokia N800.
 
+comment "Flash devices"
+
+config VIDEO_ADP1653
+       tristate "ADP1653 flash support"
+       depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER
+       ---help---
+         This is a driver for the ADP1653 flash controller. It is used for
+         example in Nokia N900.
+
 comment "Video improvement chips"
 
 config VIDEO_UPD64031A
@@ -707,6 +716,8 @@ source "drivers/media/video/cx18/Kconfig"
 
 source "drivers/media/video/saa7164/Kconfig"
 
+source "drivers/media/video/marvell-ccic/Kconfig"
+
 config VIDEO_M32R_AR
        tristate "AR devices"
        depends on M32R && VIDEO_V4L2
@@ -726,15 +737,6 @@ config VIDEO_M32R_AR_M64278
          To compile this driver as a module, choose M here: the
          module will be called arv.
 
-config VIDEO_CAFE_CCIC
-       tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
-       depends on PCI && I2C && VIDEO_V4L2
-       select VIDEO_OV7670
-       ---help---
-         This is a video4linux2 driver for the Marvell 88ALP01 integrated
-         CMOS camera controller.  This is the controller found on first-
-         generation OLPC systems.
-
 config VIDEO_SR030PC30
        tristate "SR030PC30 VGA camera sensor support"
        depends on I2C && VIDEO_V4L2
@@ -846,6 +848,12 @@ config SOC_CAMERA_OV2640
        help
          This is a ov2640 camera driver
 
+config SOC_CAMERA_OV5642
+       tristate "ov5642 camera support"
+       depends on SOC_CAMERA && I2C
+       help
+         This is a V4L2 camera driver for the OmniVision OV5642 sensor
+
 config SOC_CAMERA_OV6650
        tristate "ov6650 sensor support"
        depends on SOC_CAMERA && I2C
@@ -952,6 +960,14 @@ config  VIDEO_SAMSUNG_S5P_FIMC
          To compile this driver as a module, choose M here: the
          module will be called s5p-fimc.
 
+config VIDEO_ATMEL_ISI
+       tristate "ATMEL Image Sensor Interface (ISI) support"
+       depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
+       select VIDEOBUF2_DMA_CONTIG
+       ---help---
+         This module makes the ATMEL Image Sensor Interface available
+         as a v4l2 device.
+
 config VIDEO_S5P_MIPI_CSIS
        tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
        depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API
@@ -961,6 +977,8 @@ config VIDEO_S5P_MIPI_CSIS
          To compile this driver as a module, choose M here: the
          module will be called s5p-csis.
 
+source "drivers/media/video/s5p-tv/Kconfig"
+
 #
 # USB Multimedia device configuration
 #
@@ -1056,4 +1074,12 @@ config VIDEO_MEM2MEM_TESTDEV
          framework.
 
 
+config VIDEO_SAMSUNG_S5P_MFC
+       tristate "Samsung S5P MFC 5.1 Video Codec"
+       depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+       select VIDEOBUF2_DMA_CONTIG
+       default n
+       help
+           MFC 5.1 driver for V4L2.
+
 endif # V4L_MEM2MEM_DRIVERS
index f0fecd6f6a33e818c4f4713d2b62e1ecd762e4a9..272390072aef7142b5e419e4443d7a5a3927533f 100644 (file)
@@ -70,6 +70,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
 obj-$(CONFIG_VIDEO_SR030PC30)  += sr030pc30.o
 obj-$(CONFIG_VIDEO_NOON010PC30)        += noon010pc30.o
 obj-$(CONFIG_VIDEO_M5MOLS)     += m5mols/
+obj-$(CONFIG_VIDEO_ADP1653)    += adp1653.o
 
 obj-$(CONFIG_SOC_CAMERA_IMX074)                += imx074.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
@@ -78,6 +79,7 @@ obj-$(CONFIG_SOC_CAMERA_MT9T031)      += mt9t031.o
 obj-$(CONFIG_SOC_CAMERA_MT9T112)       += mt9t112.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)       += mt9v022.o
 obj-$(CONFIG_SOC_CAMERA_OV2640)                += ov2640.o
+obj-$(CONFIG_SOC_CAMERA_OV5642)                += ov5642.o
 obj-$(CONFIG_SOC_CAMERA_OV6650)                += ov6650.o
 obj-$(CONFIG_SOC_CAMERA_OV772X)                += ov772x.o
 obj-$(CONFIG_SOC_CAMERA_OV9640)                += ov9640.o
@@ -127,7 +129,8 @@ obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
 obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 
-obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
+obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/
 
 obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
 
@@ -166,8 +169,11 @@ obj-$(CONFIG_VIDEO_PXA27x)         += pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2)     += sh_mobile_csi2.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_OMAP1)              += omap1_camera.o
+obj-$(CONFIG_VIDEO_ATMEL_ISI)          += atmel-isi.o
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC)   += s5p-fimc/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC)    += s5p-mfc/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV)     += s5p-tv/
 
 obj-$(CONFIG_ARCH_DAVINCI)             += davinci/
 
diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c
new file mode 100644 (file)
index 0000000..be7befd
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * drivers/media/video/adp1653.c
+ *
+ * Copyright (C) 2008--2011 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Contributors:
+ *     Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *     Tuukka Toivonen <tuukkat76@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.
+ *
+ * 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
+ *
+ * TODO:
+ * - fault interrupt handling
+ * - hardware strobe
+ * - power doesn't need to be ON if all lights are off
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <media/adp1653.h>
+#include <media/v4l2-device.h>
+
+#define TIMEOUT_MAX            820000
+#define TIMEOUT_STEP           54600
+#define TIMEOUT_MIN            (TIMEOUT_MAX - ADP1653_REG_CONFIG_TMR_SET_MAX \
+                                * TIMEOUT_STEP)
+#define TIMEOUT_US_TO_CODE(t)  ((TIMEOUT_MAX + (TIMEOUT_STEP / 2) - (t)) \
+                                / TIMEOUT_STEP)
+#define TIMEOUT_CODE_TO_US(c)  (TIMEOUT_MAX - (c) * TIMEOUT_STEP)
+
+/* Write values into ADP1653 registers. */
+static int adp1653_update_hw(struct adp1653_flash *flash)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       u8 out_sel;
+       u8 config = 0;
+       int rval;
+
+       out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG(
+               flash->indicator_intensity->val)
+               << ADP1653_REG_OUT_SEL_ILED_SHIFT;
+
+       switch (flash->led_mode->val) {
+       case V4L2_FLASH_LED_MODE_NONE:
+               break;
+       case V4L2_FLASH_LED_MODE_FLASH:
+               /* Flash mode, light on with strobe, duration from timer */
+               config = ADP1653_REG_CONFIG_TMR_CFG;
+               config |= TIMEOUT_US_TO_CODE(flash->flash_timeout->val)
+                         << ADP1653_REG_CONFIG_TMR_SET_SHIFT;
+               break;
+       case V4L2_FLASH_LED_MODE_TORCH:
+               /* Torch mode, light immediately on, duration indefinite */
+               out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG(
+                       flash->torch_intensity->val)
+                       << ADP1653_REG_OUT_SEL_HPLED_SHIFT;
+               break;
+       }
+
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel);
+       if (rval < 0)
+               return rval;
+
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_CONFIG, config);
+       if (rval < 0)
+               return rval;
+
+       return 0;
+}
+
+static int adp1653_get_fault(struct adp1653_flash *flash)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       int fault;
+       int rval;
+
+       fault = i2c_smbus_read_byte_data(client, ADP1653_REG_FAULT);
+       if (IS_ERR_VALUE(fault))
+               return fault;
+
+       flash->fault |= fault;
+
+       if (!flash->fault)
+               return 0;
+
+       /* Clear faults. */
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
+       if (IS_ERR_VALUE(rval))
+               return rval;
+
+       flash->led_mode->val = V4L2_FLASH_LED_MODE_NONE;
+
+       rval = adp1653_update_hw(flash);
+       if (IS_ERR_VALUE(rval))
+               return rval;
+
+       return flash->fault;
+}
+
+static int adp1653_strobe(struct adp1653_flash *flash, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       u8 out_sel = ADP1653_INDICATOR_INTENSITY_uA_TO_REG(
+               flash->indicator_intensity->val)
+               << ADP1653_REG_OUT_SEL_ILED_SHIFT;
+       int rval;
+
+       if (flash->led_mode->val != V4L2_FLASH_LED_MODE_FLASH)
+               return -EBUSY;
+
+       if (!enable)
+               return i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL,
+                                                out_sel);
+
+       out_sel |= ADP1653_FLASH_INTENSITY_mA_TO_REG(
+               flash->flash_intensity->val)
+               << ADP1653_REG_OUT_SEL_HPLED_SHIFT;
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, out_sel);
+       if (rval)
+               return rval;
+
+       /* Software strobe using i2c */
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE,
+               ADP1653_REG_SW_STROBE_SW_STROBE);
+       if (rval)
+               return rval;
+       return i2c_smbus_write_byte_data(client, ADP1653_REG_SW_STROBE, 0);
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static int adp1653_get_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct adp1653_flash *flash =
+               container_of(ctrl->handler, struct adp1653_flash, ctrls);
+       int rval;
+
+       rval = adp1653_get_fault(flash);
+       if (IS_ERR_VALUE(rval))
+               return rval;
+
+       ctrl->cur.val = 0;
+
+       if (flash->fault & ADP1653_REG_FAULT_FLT_SCP)
+               ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
+       if (flash->fault & ADP1653_REG_FAULT_FLT_OT)
+               ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
+       if (flash->fault & ADP1653_REG_FAULT_FLT_TMR)
+               ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT;
+       if (flash->fault & ADP1653_REG_FAULT_FLT_OV)
+               ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE;
+
+       flash->fault = 0;
+
+       return 0;
+}
+
+static int adp1653_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct adp1653_flash *flash =
+               container_of(ctrl->handler, struct adp1653_flash, ctrls);
+       int rval;
+
+       rval = adp1653_get_fault(flash);
+       if (IS_ERR_VALUE(rval))
+               return rval;
+       if ((rval & (ADP1653_REG_FAULT_FLT_SCP |
+                    ADP1653_REG_FAULT_FLT_OT |
+                    ADP1653_REG_FAULT_FLT_OV)) &&
+           (ctrl->id == V4L2_CID_FLASH_STROBE ||
+            ctrl->id == V4L2_CID_FLASH_TORCH_INTENSITY ||
+            ctrl->id == V4L2_CID_FLASH_LED_MODE))
+               return -EBUSY;
+
+       switch (ctrl->id) {
+       case V4L2_CID_FLASH_STROBE:
+               return adp1653_strobe(flash, 1);
+       case V4L2_CID_FLASH_STROBE_STOP:
+               return adp1653_strobe(flash, 0);
+       }
+
+       return adp1653_update_hw(flash);
+}
+
+static const struct v4l2_ctrl_ops adp1653_ctrl_ops = {
+       .g_volatile_ctrl = adp1653_get_ctrl,
+       .s_ctrl = adp1653_set_ctrl,
+};
+
+static int adp1653_init_controls(struct adp1653_flash *flash)
+{
+       struct v4l2_ctrl *fault;
+
+       v4l2_ctrl_handler_init(&flash->ctrls, 9);
+
+       flash->led_mode =
+               v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops,
+                                      V4L2_CID_FLASH_LED_MODE,
+                                      V4L2_FLASH_LED_MODE_TORCH, ~0x7, 0);
+       v4l2_ctrl_new_std_menu(&flash->ctrls, &adp1653_ctrl_ops,
+                              V4L2_CID_FLASH_STROBE_SOURCE,
+                              V4L2_FLASH_STROBE_SOURCE_SOFTWARE, ~0x1, 0);
+       v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                         V4L2_CID_FLASH_STROBE, 0, 0, 0, 0);
+       v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                         V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0);
+       flash->flash_timeout =
+               v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                                 V4L2_CID_FLASH_TIMEOUT, TIMEOUT_MIN,
+                                 flash->platform_data->max_flash_timeout,
+                                 TIMEOUT_STEP,
+                                 flash->platform_data->max_flash_timeout);
+       flash->flash_intensity =
+               v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                                 V4L2_CID_FLASH_INTENSITY,
+                                 ADP1653_FLASH_INTENSITY_MIN,
+                                 flash->platform_data->max_flash_intensity,
+                                 1, flash->platform_data->max_flash_intensity);
+       flash->torch_intensity =
+               v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                                 V4L2_CID_FLASH_TORCH_INTENSITY,
+                                 ADP1653_TORCH_INTENSITY_MIN,
+                                 flash->platform_data->max_torch_intensity,
+                                 ADP1653_FLASH_INTENSITY_STEP,
+                                 flash->platform_data->max_torch_intensity);
+       flash->indicator_intensity =
+               v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                                 V4L2_CID_FLASH_INDICATOR_INTENSITY,
+                                 ADP1653_INDICATOR_INTENSITY_MIN,
+                                 flash->platform_data->max_indicator_intensity,
+                                 ADP1653_INDICATOR_INTENSITY_STEP,
+                                 ADP1653_INDICATOR_INTENSITY_MIN);
+       fault = v4l2_ctrl_new_std(&flash->ctrls, &adp1653_ctrl_ops,
+                                 V4L2_CID_FLASH_FAULT, 0,
+                                 V4L2_FLASH_FAULT_OVER_VOLTAGE
+                                 | V4L2_FLASH_FAULT_OVER_TEMPERATURE
+                                 | V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0);
+
+       if (flash->ctrls.error)
+               return flash->ctrls.error;
+
+       fault->is_volatile = 1;
+
+       flash->subdev.ctrl_handler = &flash->ctrls;
+       return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static int
+adp1653_init_device(struct adp1653_flash *flash)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev);
+       int rval;
+
+       /* Clear FAULT register by writing zero to OUT_SEL */
+       rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
+       if (rval < 0) {
+               dev_err(&client->dev, "failed writing fault register\n");
+               return -EIO;
+       }
+
+       mutex_lock(&flash->ctrls.lock);
+       /* Reset faults before reading new ones. */
+       flash->fault = 0;
+       rval = adp1653_get_fault(flash);
+       mutex_unlock(&flash->ctrls.lock);
+       if (rval > 0) {
+               dev_err(&client->dev, "faults detected: 0x%1.1x\n", rval);
+               return -EIO;
+       }
+
+       mutex_lock(&flash->ctrls.lock);
+       rval = adp1653_update_hw(flash);
+       mutex_unlock(&flash->ctrls.lock);
+       if (rval) {
+               dev_err(&client->dev,
+                       "adp1653_update_hw failed at %s\n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int
+__adp1653_set_power(struct adp1653_flash *flash, int on)
+{
+       int ret;
+
+       ret = flash->platform_data->power(&flash->subdev, on);
+       if (ret < 0)
+               return ret;
+
+       if (!on)
+               return 0;
+
+       ret = adp1653_init_device(flash);
+       if (ret < 0)
+               flash->platform_data->power(&flash->subdev, 0);
+
+       return ret;
+}
+
+static int
+adp1653_set_power(struct v4l2_subdev *subdev, int on)
+{
+       struct adp1653_flash *flash = to_adp1653_flash(subdev);
+       int ret = 0;
+
+       mutex_lock(&flash->power_lock);
+
+       /* If the power count is modified from 0 to != 0 or from != 0 to 0,
+        * update the power state.
+        */
+       if (flash->power_count == !on) {
+               ret = __adp1653_set_power(flash, !!on);
+               if (ret < 0)
+                       goto done;
+       }
+
+       /* Update the power count. */
+       flash->power_count += on ? 1 : -1;
+       WARN_ON(flash->power_count < 0);
+
+done:
+       mutex_unlock(&flash->power_lock);
+       return ret;
+}
+
+static int adp1653_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       return adp1653_set_power(sd, 1);
+}
+
+static int adp1653_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       return adp1653_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_core_ops adp1653_core_ops = {
+       .s_power = adp1653_set_power,
+};
+
+static const struct v4l2_subdev_ops adp1653_ops = {
+       .core = &adp1653_core_ops,
+};
+
+static const struct v4l2_subdev_internal_ops adp1653_internal_ops = {
+       .open = adp1653_open,
+       .close = adp1653_close,
+};
+
+/* --------------------------------------------------------------------------
+ * I2C driver
+ */
+#ifdef CONFIG_PM
+
+static int adp1653_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+       if (!flash->power_count)
+               return 0;
+
+       return __adp1653_set_power(flash, 0);
+}
+
+static int adp1653_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+       if (!flash->power_count)
+               return 0;
+
+       return __adp1653_set_power(flash, 1);
+}
+
+#else
+
+#define adp1653_suspend        NULL
+#define adp1653_resume NULL
+
+#endif /* CONFIG_PM */
+
+static int adp1653_probe(struct i2c_client *client,
+                        const struct i2c_device_id *devid)
+{
+       struct adp1653_flash *flash;
+       int ret;
+
+       flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+       if (flash == NULL)
+               return -ENOMEM;
+
+       flash->platform_data = client->dev.platform_data;
+
+       mutex_init(&flash->power_lock);
+
+       v4l2_i2c_subdev_init(&flash->subdev, client, &adp1653_ops);
+       flash->subdev.internal_ops = &adp1653_internal_ops;
+       flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       adp1653_init_controls(flash);
+
+       ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0);
+       if (ret < 0)
+               kfree(flash);
+
+       return ret;
+}
+
+static int __exit adp1653_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct adp1653_flash *flash = to_adp1653_flash(subdev);
+
+       v4l2_device_unregister_subdev(&flash->subdev);
+       v4l2_ctrl_handler_free(&flash->ctrls);
+       media_entity_cleanup(&flash->subdev.entity);
+       kfree(flash);
+       return 0;
+}
+
+static const struct i2c_device_id adp1653_id_table[] = {
+       { ADP1653_NAME, 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, adp1653_id_table);
+
+static struct dev_pm_ops adp1653_pm_ops = {
+       .suspend        = adp1653_suspend,
+       .resume         = adp1653_resume,
+};
+
+static struct i2c_driver adp1653_i2c_driver = {
+       .driver         = {
+               .name   = ADP1653_NAME,
+               .pm     = &adp1653_pm_ops,
+       },
+       .probe          = adp1653_probe,
+       .remove         = __exit_p(adp1653_remove),
+       .id_table       = adp1653_id_table,
+};
+
+static int __init adp1653_init(void)
+{
+       int rval;
+
+       rval = i2c_add_driver(&adp1653_i2c_driver);
+       if (rval)
+               printk(KERN_ALERT "%s: failed at i2c_add_driver\n", __func__);
+
+       return rval;
+}
+
+static void __exit adp1653_exit(void)
+{
+       i2c_del_driver(&adp1653_i2c_driver);
+}
+
+module_init(adp1653_init);
+module_exit(adp1653_exit);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("Analog Devices ADP1653 LED flash driver");
+MODULE_LICENSE("GPL");
index f989f2820d88e90f49f5b4fc6081002126c0c3c2..b6ed44aebe30bcf1c186bd877125bca353e6bb96 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
@@ -54,7 +53,7 @@
  */
 #define USE_INT                0       /* Don't modify */
 
-#define VERSION        "0.04"
+#define VERSION        "0.0.5"
 
 #define ar_inl(addr)           inl((unsigned long)(addr))
 #define ar_outl(val, addr)     outl((unsigned long)(val), (unsigned long)(addr))
@@ -404,7 +403,6 @@ static int ar_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, ar->vdev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, "Colour AR VGA", sizeof(vcap->card));
        strlcpy(vcap->bus_info, "Platform", sizeof(vcap->bus_info));
-       vcap->version = KERNEL_VERSION(0, 0, 4);
        vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
 }
@@ -879,3 +877,4 @@ module_exit(ar_cleanup_module);
 MODULE_AUTHOR("Takeo Takahashi <takahashi.takeo@renesas.com>");
 MODULE_DESCRIPTION("Colour AR M64278(VGA) for Video4Linux");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION);
diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
new file mode 100644 (file)
index 0000000..7b89f00
--- /dev/null
@@ -0,0 +1,1048 @@
+/*
+ * Copyright (c) 2011 Atmel Corporation
+ * Josh Wu, <josh.wu@atmel.com>
+ *
+ * Based on previous work by Lars Haring, <lars.haring@atmel.com>
+ * and Sedji Gaouaou
+ * Based on the bttv driver for Bt848 with respective copyright holders
+ *
+ * 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/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <media/atmel-isi.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define MAX_BUFFER_NUM                 32
+#define MAX_SUPPORT_WIDTH              2048
+#define MAX_SUPPORT_HEIGHT             2048
+#define VID_LIMIT_BYTES                        (16 * 1024 * 1024)
+#define MIN_FRAME_RATE                 15
+#define FRAME_INTERVAL_MILLI_SEC       (1000 / MIN_FRAME_RATE)
+
+/* ISI states */
+enum {
+       ISI_STATE_IDLE = 0,
+       ISI_STATE_READY,
+       ISI_STATE_WAIT_SOF,
+};
+
+/* Frame buffer descriptor */
+struct fbd {
+       /* Physical address of the frame buffer */
+       u32 fb_address;
+       /* DMA Control Register(only in HISI2) */
+       u32 dma_ctrl;
+       /* Physical address of the next fbd */
+       u32 next_fbd_address;
+};
+
+static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl)
+{
+       fb_desc->dma_ctrl = ctrl;
+}
+
+struct isi_dma_desc {
+       struct list_head list;
+       struct fbd *p_fbd;
+       u32 fbd_phys;
+};
+
+/* Frame buffer data */
+struct frame_buffer {
+       struct vb2_buffer vb;
+       struct isi_dma_desc *p_dma_desc;
+       struct list_head list;
+};
+
+struct atmel_isi {
+       /* Protects the access of variables shared with the ISR */
+       spinlock_t                      lock;
+       void __iomem                    *regs;
+
+       int                             sequence;
+       /* State of the ISI module in capturing mode */
+       int                             state;
+
+       /* Wait queue for waiting for SOF */
+       wait_queue_head_t               vsync_wq;
+
+       struct vb2_alloc_ctx            *alloc_ctx;
+
+       /* Allocate descriptors for dma buffer use */
+       struct fbd                      *p_fb_descriptors;
+       u32                             fb_descriptors_phys;
+       struct                          list_head dma_desc_head;
+       struct isi_dma_desc             dma_desc[MAX_BUFFER_NUM];
+
+       struct completion               complete;
+       struct clk                      *pclk;
+       unsigned int                    irq;
+
+       struct isi_platform_data        *pdata;
+
+       struct list_head                video_buffer_list;
+       struct frame_buffer             *active;
+
+       struct soc_camera_device        *icd;
+       struct soc_camera_host          soc_host;
+};
+
+static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val)
+{
+       writel(val, isi->regs + reg);
+}
+static u32 isi_readl(struct atmel_isi *isi, u32 reg)
+{
+       return readl(isi->regs + reg);
+}
+
+static int configure_geometry(struct atmel_isi *isi, u32 width,
+                       u32 height, enum v4l2_mbus_pixelcode code)
+{
+       u32 cfg2, cr;
+
+       switch (code) {
+       /* YUV, including grey */
+       case V4L2_MBUS_FMT_Y8_1X8:
+               cr = ISI_CFG2_GRAYSCALE;
+               break;
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+               cr = ISI_CFG2_YCC_SWAP_MODE_3;
+               break;
+       case V4L2_MBUS_FMT_VYUY8_2X8:
+               cr = ISI_CFG2_YCC_SWAP_MODE_2;
+               break;
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+               cr = ISI_CFG2_YCC_SWAP_MODE_1;
+               break;
+       case V4L2_MBUS_FMT_YVYU8_2X8:
+               cr = ISI_CFG2_YCC_SWAP_DEFAULT;
+               break;
+       /* RGB, TODO */
+       default:
+               return -EINVAL;
+       }
+
+       isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+
+       cfg2 = isi_readl(isi, ISI_CFG2);
+       cfg2 |= cr;
+       /* Set width */
+       cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK);
+       cfg2 |= ((width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) &
+                       ISI_CFG2_IM_HSIZE_MASK;
+       /* Set height */
+       cfg2 &= ~(ISI_CFG2_IM_VSIZE_MASK);
+       cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET)
+                       & ISI_CFG2_IM_VSIZE_MASK;
+       isi_writel(isi, ISI_CFG2, cfg2);
+
+       return 0;
+}
+
+static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
+{
+       if (isi->active) {
+               struct vb2_buffer *vb = &isi->active->vb;
+               struct frame_buffer *buf = isi->active;
+
+               list_del_init(&buf->list);
+               do_gettimeofday(&vb->v4l2_buf.timestamp);
+               vb->v4l2_buf.sequence = isi->sequence++;
+               vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+       }
+
+       if (list_empty(&isi->video_buffer_list)) {
+               isi->active = NULL;
+       } else {
+               /* start next dma frame. */
+               isi->active = list_entry(isi->video_buffer_list.next,
+                                       struct frame_buffer, list);
+               isi_writel(isi, ISI_DMA_C_DSCR,
+                       isi->active->p_dma_desc->fbd_phys);
+               isi_writel(isi, ISI_DMA_C_CTRL,
+                       ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+               isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+       }
+       return IRQ_HANDLED;
+}
+
+/* ISI interrupt service routine */
+static irqreturn_t isi_interrupt(int irq, void *dev_id)
+{
+       struct atmel_isi *isi = dev_id;
+       u32 status, mask, pending;
+       irqreturn_t ret = IRQ_NONE;
+
+       spin_lock(&isi->lock);
+
+       status = isi_readl(isi, ISI_STATUS);
+       mask = isi_readl(isi, ISI_INTMASK);
+       pending = status & mask;
+
+       if (pending & ISI_CTRL_SRST) {
+               complete(&isi->complete);
+               isi_writel(isi, ISI_INTDIS, ISI_CTRL_SRST);
+               ret = IRQ_HANDLED;
+       } else if (pending & ISI_CTRL_DIS) {
+               complete(&isi->complete);
+               isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS);
+               ret = IRQ_HANDLED;
+       } else {
+               if ((pending & ISI_SR_VSYNC) &&
+                               (isi->state == ISI_STATE_IDLE)) {
+                       isi->state = ISI_STATE_READY;
+                       wake_up_interruptible(&isi->vsync_wq);
+                       ret = IRQ_HANDLED;
+               }
+               if (likely(pending & ISI_SR_CXFR_DONE))
+                       ret = atmel_isi_handle_streaming(isi);
+       }
+
+       spin_unlock(&isi->lock);
+       return ret;
+}
+
+#define        WAIT_ISI_RESET          1
+#define        WAIT_ISI_DISABLE        0
+static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset)
+{
+       unsigned long timeout;
+       /*
+        * The reset or disable will only succeed if we have a
+        * pixel clock from the camera.
+        */
+       init_completion(&isi->complete);
+
+       if (wait_reset) {
+               isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST);
+               isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST);
+       } else {
+               isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS);
+               isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+       }
+
+       timeout = wait_for_completion_timeout(&isi->complete,
+                       msecs_to_jiffies(100));
+       if (timeout == 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+/* ------------------------------------------------------------------
+       Videobuf operations
+   ------------------------------------------------------------------*/
+static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                               unsigned int *nplanes, unsigned long sizes[],
+                               void *alloc_ctxs[])
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       unsigned long size;
+       int ret, bytes_per_line;
+
+       /* Reset ISI */
+       ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET);
+       if (ret < 0) {
+               dev_err(icd->parent, "Reset ISI timed out\n");
+               return ret;
+       }
+       /* Disable all interrupts */
+       isi_writel(isi, ISI_INTDIS, ~0UL);
+
+       bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                                               icd->current_fmt->host_fmt);
+
+       if (bytes_per_line < 0)
+               return bytes_per_line;
+
+       size = bytes_per_line * icd->user_height;
+
+       if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM)
+               *nbuffers = MAX_BUFFER_NUM;
+
+       if (size * *nbuffers > VID_LIMIT_BYTES)
+               *nbuffers = VID_LIMIT_BYTES / size;
+
+       *nplanes = 1;
+       sizes[0] = size;
+       alloc_ctxs[0] = isi->alloc_ctx;
+
+       isi->sequence = 0;
+       isi->active = NULL;
+
+       dev_dbg(icd->parent, "%s, count=%d, size=%ld\n", __func__,
+               *nbuffers, size);
+
+       return 0;
+}
+
+static int buffer_init(struct vb2_buffer *vb)
+{
+       struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+
+       buf->p_dma_desc = NULL;
+       INIT_LIST_HEAD(&buf->list);
+
+       return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+       struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       unsigned long size;
+       struct isi_dma_desc *desc;
+       int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                                               icd->current_fmt->host_fmt);
+
+       if (bytes_per_line < 0)
+               return bytes_per_line;
+
+       size = bytes_per_line * icd->user_height;
+
+       if (vb2_plane_size(vb, 0) < size) {
+               dev_err(icd->parent, "%s data will not fit into plane (%lu < %lu)\n",
+                               __func__, vb2_plane_size(vb, 0), size);
+               return -EINVAL;
+       }
+
+       vb2_set_plane_payload(&buf->vb, 0, size);
+
+       if (!buf->p_dma_desc) {
+               if (list_empty(&isi->dma_desc_head)) {
+                       dev_err(icd->parent, "Not enough dma descriptors.\n");
+                       return -EINVAL;
+               } else {
+                       /* Get an available descriptor */
+                       desc = list_entry(isi->dma_desc_head.next,
+                                               struct isi_dma_desc, list);
+                       /* Delete the descriptor since now it is used */
+                       list_del_init(&desc->list);
+
+                       /* Initialize the dma descriptor */
+                       desc->p_fbd->fb_address =
+                                       vb2_dma_contig_plane_paddr(vb, 0);
+                       desc->p_fbd->next_fbd_address = 0;
+                       set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB);
+
+                       buf->p_dma_desc = desc;
+               }
+       }
+       return 0;
+}
+
+static void buffer_cleanup(struct vb2_buffer *vb)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+
+       /* This descriptor is available now and we add to head list */
+       if (buf->p_dma_desc)
+               list_add(&buf->p_dma_desc->list, &isi->dma_desc_head);
+}
+
+static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
+{
+       u32 ctrl, cfg1;
+
+       cfg1 = isi_readl(isi, ISI_CFG1);
+       /* Enable irq: cxfr for the codec path, pxfr for the preview path */
+       isi_writel(isi, ISI_INTEN,
+                       ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
+
+       /* Check if already in a frame */
+       if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
+               dev_err(isi->icd->parent, "Already in frame handling.\n");
+               return;
+       }
+
+       isi_writel(isi, ISI_DMA_C_DSCR, buffer->p_dma_desc->fbd_phys);
+       isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+       isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+
+       /* Enable linked list */
+       cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR;
+
+       /* Enable codec path and ISI */
+       ctrl = ISI_CTRL_CDC | ISI_CTRL_EN;
+       isi_writel(isi, ISI_CTRL, ctrl);
+       isi_writel(isi, ISI_CFG1, cfg1);
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       struct frame_buffer *buf = container_of(vb, struct frame_buffer, vb);
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&isi->lock, flags);
+       list_add_tail(&buf->list, &isi->video_buffer_list);
+
+       if (isi->active == NULL) {
+               isi->active = buf;
+               start_dma(isi, buf);
+       }
+       spin_unlock_irqrestore(&isi->lock, flags);
+}
+
+static int start_streaming(struct vb2_queue *vq)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+
+       u32 sr = 0;
+       int ret;
+
+       spin_lock_irq(&isi->lock);
+       isi->state = ISI_STATE_IDLE;
+       /* Clear any pending SOF interrupt */
+       sr = isi_readl(isi, ISI_STATUS);
+       /* Enable VSYNC interrupt for SOF */
+       isi_writel(isi, ISI_INTEN, ISI_SR_VSYNC);
+       isi_writel(isi, ISI_CTRL, ISI_CTRL_EN);
+       spin_unlock_irq(&isi->lock);
+
+       dev_dbg(icd->parent, "Waiting for SOF\n");
+       ret = wait_event_interruptible(isi->vsync_wq,
+                                      isi->state != ISI_STATE_IDLE);
+       if (ret)
+               return ret;
+
+       if (isi->state != ISI_STATE_READY)
+               return -EIO;
+
+       spin_lock_irq(&isi->lock);
+       isi->state = ISI_STATE_WAIT_SOF;
+       isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC);
+       spin_unlock_irq(&isi->lock);
+
+       return 0;
+}
+
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+       struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       struct frame_buffer *buf, *node;
+       int ret = 0;
+       unsigned long timeout;
+
+       spin_lock_irq(&isi->lock);
+       isi->active = NULL;
+       /* Release all active buffers */
+       list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) {
+               list_del_init(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+       spin_unlock_irq(&isi->lock);
+
+       timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ;
+       /* Wait until the end of the current frame. */
+       while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) &&
+                       time_before(jiffies, timeout))
+               msleep(1);
+
+       if (time_after(jiffies, timeout)) {
+               dev_err(icd->parent,
+                       "Timeout waiting for finishing codec request\n");
+               return -ETIMEDOUT;
+       }
+
+       /* Disable interrupts */
+       isi_writel(isi, ISI_INTDIS,
+                       ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
+
+       /* Disable ISI and wait for it is done */
+       ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE);
+       if (ret < 0)
+               dev_err(icd->parent, "Disable ISI timed out\n");
+
+       return ret;
+}
+
+static struct vb2_ops isi_video_qops = {
+       .queue_setup            = queue_setup,
+       .buf_init               = buffer_init,
+       .buf_prepare            = buffer_prepare,
+       .buf_cleanup            = buffer_cleanup,
+       .buf_queue              = buffer_queue,
+       .start_streaming        = start_streaming,
+       .stop_streaming         = stop_streaming,
+       .wait_prepare           = soc_camera_unlock,
+       .wait_finish            = soc_camera_lock,
+};
+
+/* ------------------------------------------------------------------
+       SOC camera operations for the device
+   ------------------------------------------------------------------*/
+static int isi_camera_init_videobuf(struct vb2_queue *q,
+                                    struct soc_camera_device *icd)
+{
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP;
+       q->drv_priv = icd;
+       q->buf_struct_size = sizeof(struct frame_buffer);
+       q->ops = &isi_video_qops;
+       q->mem_ops = &vb2_dma_contig_memops;
+
+       return vb2_queue_init(q);
+}
+
+static int isi_camera_set_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       const struct soc_camera_format_xlate *xlate;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_mbus_framefmt mf;
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+       if (!xlate) {
+               dev_warn(icd->parent, "Format %x not found\n",
+                        pix->pixelformat);
+               return -EINVAL;
+       }
+
+       dev_dbg(icd->parent, "Plan to set format %dx%d\n",
+                       pix->width, pix->height);
+
+       mf.width        = pix->width;
+       mf.height       = pix->height;
+       mf.field        = pix->field;
+       mf.colorspace   = pix->colorspace;
+       mf.code         = xlate->code;
+
+       ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+       if (ret < 0)
+               return ret;
+
+       if (mf.code != xlate->code)
+               return -EINVAL;
+
+       ret = configure_geometry(isi, pix->width, pix->height, xlate->code);
+       if (ret < 0)
+               return ret;
+
+       pix->width              = mf.width;
+       pix->height             = mf.height;
+       pix->field              = mf.field;
+       pix->colorspace         = mf.colorspace;
+       icd->current_fmt        = xlate;
+
+       dev_dbg(icd->parent, "Finally set format %dx%d\n",
+               pix->width, pix->height);
+
+       return ret;
+}
+
+static int isi_camera_try_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       const struct soc_camera_format_xlate *xlate;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_mbus_framefmt mf;
+       u32 pixfmt = pix->pixelformat;
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       if (pixfmt && !xlate) {
+               dev_warn(icd->parent, "Format %x not found\n", pixfmt);
+               return -EINVAL;
+       }
+
+       /* limit to Atmel ISI hardware capabilities */
+       if (pix->height > MAX_SUPPORT_HEIGHT)
+               pix->height = MAX_SUPPORT_HEIGHT;
+       if (pix->width > MAX_SUPPORT_WIDTH)
+               pix->width = MAX_SUPPORT_WIDTH;
+
+       /* limit to sensor capabilities */
+       mf.width        = pix->width;
+       mf.height       = pix->height;
+       mf.field        = pix->field;
+       mf.colorspace   = pix->colorspace;
+       mf.code         = xlate->code;
+
+       ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+       if (ret < 0)
+               return ret;
+
+       pix->width      = mf.width;
+       pix->height     = mf.height;
+       pix->colorspace = mf.colorspace;
+
+       switch (mf.field) {
+       case V4L2_FIELD_ANY:
+               pix->field = V4L2_FIELD_NONE;
+               break;
+       case V4L2_FIELD_NONE:
+               break;
+       default:
+               dev_err(icd->parent, "Field type %d unsupported.\n",
+                       mf.field);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct soc_mbus_pixelfmt isi_camera_formats[] = {
+       {
+               .fourcc                 = V4L2_PIX_FMT_YUYV,
+               .name                   = "Packed YUV422 16 bit",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },
+};
+
+/* This will be corrected as we get more formats */
+static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
+{
+       return  fmt->packing == SOC_MBUS_PACKING_NONE ||
+               (fmt->bits_per_sample == 8 &&
+                fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
+               (fmt->bits_per_sample > 8 &&
+                fmt->packing == SOC_MBUS_PACKING_EXTEND16);
+}
+
+static unsigned long make_bus_param(struct atmel_isi *isi)
+{
+       unsigned long flags;
+       /*
+        * Platform specified synchronization and pixel clock polarities are
+        * only a recommendation and are only used during probing. Atmel ISI
+        * camera interface only works in master mode, i.e., uses HSYNC and
+        * VSYNC signals from the sensor
+        */
+       flags = SOCAM_MASTER |
+               SOCAM_HSYNC_ACTIVE_HIGH |
+               SOCAM_HSYNC_ACTIVE_LOW |
+               SOCAM_VSYNC_ACTIVE_HIGH |
+               SOCAM_VSYNC_ACTIVE_LOW |
+               SOCAM_PCLK_SAMPLE_RISING |
+               SOCAM_PCLK_SAMPLE_FALLING |
+               SOCAM_DATA_ACTIVE_HIGH;
+
+       if (isi->pdata->data_width_flags & ISI_DATAWIDTH_10)
+               flags |= SOCAM_DATAWIDTH_10;
+
+       if (isi->pdata->data_width_flags & ISI_DATAWIDTH_8)
+               flags |= SOCAM_DATAWIDTH_8;
+
+       if (flags & SOCAM_DATAWIDTH_MASK)
+               return flags;
+
+       return 0;
+}
+
+static int isi_camera_try_bus_param(struct soc_camera_device *icd,
+                                   unsigned char buswidth)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       unsigned long camera_flags;
+       int ret;
+
+       camera_flags = icd->ops->query_bus_param(icd);
+       ret = soc_camera_bus_param_compatible(camera_flags,
+                                       make_bus_param(isi));
+       if (!ret)
+               return -EINVAL;
+       return 0;
+}
+
+
+static int isi_camera_get_formats(struct soc_camera_device *icd,
+                                 unsigned int idx,
+                                 struct soc_camera_format_xlate *xlate)
+{
+       struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+       int formats = 0, ret;
+       /* sensor format */
+       enum v4l2_mbus_pixelcode code;
+       /* soc camera host format */
+       const struct soc_mbus_pixelfmt *fmt;
+
+       ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+       if (ret < 0)
+               /* No more formats */
+               return 0;
+
+       fmt = soc_mbus_get_fmtdesc(code);
+       if (!fmt) {
+               dev_err(icd->parent,
+                       "Invalid format code #%u: %d\n", idx, code);
+               return 0;
+       }
+
+       /* This also checks support for the requested bits-per-sample */
+       ret = isi_camera_try_bus_param(icd, fmt->bits_per_sample);
+       if (ret < 0) {
+               dev_err(icd->parent,
+                       "Fail to try the bus parameters.\n");
+               return 0;
+       }
+
+       switch (code) {
+       case V4L2_MBUS_FMT_UYVY8_2X8:
+       case V4L2_MBUS_FMT_VYUY8_2X8:
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+       case V4L2_MBUS_FMT_YVYU8_2X8:
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = &isi_camera_formats[0];
+                       xlate->code     = code;
+                       xlate++;
+                       dev_dbg(icd->parent, "Providing format %s using code %d\n",
+                               isi_camera_formats[0].name, code);
+               }
+               break;
+       default:
+               if (!isi_camera_packing_supported(fmt))
+                       return 0;
+               if (xlate)
+                       dev_dbg(icd->parent,
+                               "Providing format %s in pass-through mode\n",
+                               fmt->name);
+       }
+
+       /* Generic pass-through */
+       formats++;
+       if (xlate) {
+               xlate->host_fmt = fmt;
+               xlate->code     = code;
+               xlate++;
+       }
+
+       return formats;
+}
+
+/* Called with .video_lock held */
+static int isi_camera_add_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       int ret;
+
+       if (isi->icd)
+               return -EBUSY;
+
+       ret = clk_enable(isi->pclk);
+       if (ret)
+               return ret;
+
+       isi->icd = icd;
+       dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
+                icd->devnum);
+       return 0;
+}
+/* Called with .video_lock held */
+static void isi_camera_remove_device(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+
+       BUG_ON(icd != isi->icd);
+
+       clk_disable(isi->pclk);
+       isi->icd = NULL;
+
+       dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n",
+                icd->devnum);
+}
+
+static unsigned int isi_camera_poll(struct file *file, poll_table *pt)
+{
+       struct soc_camera_device *icd = file->private_data;
+
+       return vb2_poll(&icd->vb2_vidq, file, pt);
+}
+
+static int isi_camera_querycap(struct soc_camera_host *ici,
+                              struct v4l2_capability *cap)
+{
+       strcpy(cap->driver, "atmel-isi");
+       strcpy(cap->card, "Atmel Image Sensor Interface");
+       cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE |
+                               V4L2_CAP_STREAMING);
+       return 0;
+}
+
+static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       struct atmel_isi *isi = ici->priv;
+       unsigned long bus_flags, camera_flags, common_flags;
+       int ret;
+       u32 cfg1 = 0;
+
+       camera_flags = icd->ops->query_bus_param(icd);
+
+       bus_flags = make_bus_param(isi);
+       common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+       dev_dbg(icd->parent, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n",
+               camera_flags, bus_flags, common_flags);
+       if (!common_flags)
+               return -EINVAL;
+
+       /* Make choises, based on platform preferences */
+       if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+           (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+               if (isi->pdata->hsync_act_low)
+                       common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+               else
+                       common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+       }
+
+       if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
+           (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
+               if (isi->pdata->vsync_act_low)
+                       common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+               else
+                       common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+       }
+
+       if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+           (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+               if (isi->pdata->pclk_act_falling)
+                       common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+               else
+                       common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+       }
+
+       ret = icd->ops->set_bus_param(icd, common_flags);
+       if (ret < 0) {
+               dev_dbg(icd->parent, "Camera set_bus_param(%lx) returned %d\n",
+                       common_flags, ret);
+               return ret;
+       }
+
+       /* set bus param for ISI */
+       if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
+               cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW;
+       if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
+               cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW;
+       if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
+               cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING;
+
+       if (isi->pdata->has_emb_sync)
+               cfg1 |= ISI_CFG1_EMB_SYNC;
+       if (isi->pdata->isi_full_mode)
+               cfg1 |= ISI_CFG1_FULL_MODE;
+
+       isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+       isi_writel(isi, ISI_CFG1, cfg1);
+
+       return 0;
+}
+
+static struct soc_camera_host_ops isi_soc_camera_host_ops = {
+       .owner          = THIS_MODULE,
+       .add            = isi_camera_add_device,
+       .remove         = isi_camera_remove_device,
+       .set_fmt        = isi_camera_set_fmt,
+       .try_fmt        = isi_camera_try_fmt,
+       .get_formats    = isi_camera_get_formats,
+       .init_videobuf2 = isi_camera_init_videobuf,
+       .poll           = isi_camera_poll,
+       .querycap       = isi_camera_querycap,
+       .set_bus_param  = isi_camera_set_bus_param,
+};
+
+/* -----------------------------------------------------------------------*/
+static int __devexit atmel_isi_remove(struct platform_device *pdev)
+{
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct atmel_isi *isi = container_of(soc_host,
+                                       struct atmel_isi, soc_host);
+
+       free_irq(isi->irq, isi);
+       soc_camera_host_unregister(soc_host);
+       vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);
+       dma_free_coherent(&pdev->dev,
+                       sizeof(struct fbd) * MAX_BUFFER_NUM,
+                       isi->p_fb_descriptors,
+                       isi->fb_descriptors_phys);
+
+       iounmap(isi->regs);
+       clk_put(isi->pclk);
+       kfree(isi);
+
+       return 0;
+}
+
+static int __devinit atmel_isi_probe(struct platform_device *pdev)
+{
+       unsigned int irq;
+       struct atmel_isi *isi;
+       struct clk *pclk;
+       struct resource *regs;
+       int ret, i;
+       struct device *dev = &pdev->dev;
+       struct soc_camera_host *soc_host;
+       struct isi_platform_data *pdata;
+
+       pdata = dev->platform_data;
+       if (!pdata || !pdata->data_width_flags) {
+               dev_err(&pdev->dev,
+                       "No config available for Atmel ISI\n");
+               return -EINVAL;
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs)
+               return -ENXIO;
+
+       pclk = clk_get(&pdev->dev, "isi_clk");
+       if (IS_ERR(pclk))
+               return PTR_ERR(pclk);
+
+       isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL);
+       if (!isi) {
+               ret = -ENOMEM;
+               dev_err(&pdev->dev, "Can't allocate interface!\n");
+               goto err_alloc_isi;
+       }
+
+       isi->pclk = pclk;
+       isi->pdata = pdata;
+       isi->active = NULL;
+       spin_lock_init(&isi->lock);
+       init_waitqueue_head(&isi->vsync_wq);
+       INIT_LIST_HEAD(&isi->video_buffer_list);
+       INIT_LIST_HEAD(&isi->dma_desc_head);
+
+       isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev,
+                               sizeof(struct fbd) * MAX_BUFFER_NUM,
+                               &isi->fb_descriptors_phys,
+                               GFP_KERNEL);
+       if (!isi->p_fb_descriptors) {
+               ret = -ENOMEM;
+               dev_err(&pdev->dev, "Can't allocate descriptors!\n");
+               goto err_alloc_descriptors;
+       }
+
+       for (i = 0; i < MAX_BUFFER_NUM; i++) {
+               isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i;
+               isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys +
+                                       i * sizeof(struct fbd);
+               list_add(&isi->dma_desc[i].list, &isi->dma_desc_head);
+       }
+
+       isi->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(isi->alloc_ctx)) {
+               ret = PTR_ERR(isi->alloc_ctx);
+               goto err_alloc_ctx;
+       }
+
+       isi->regs = ioremap(regs->start, resource_size(regs));
+       if (!isi->regs) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto err_req_irq;
+       }
+
+       ret = request_irq(irq, isi_interrupt, 0, "isi", isi);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
+               goto err_req_irq;
+       }
+       isi->irq = irq;
+
+       soc_host                = &isi->soc_host;
+       soc_host->drv_name      = "isi-camera";
+       soc_host->ops           = &isi_soc_camera_host_ops;
+       soc_host->priv          = isi;
+       soc_host->v4l2_dev.dev  = &pdev->dev;
+       soc_host->nr            = pdev->id;
+
+       ret = soc_camera_host_register(soc_host);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to register soc camera host\n");
+               goto err_register_soc_camera_host;
+       }
+       return 0;
+
+err_register_soc_camera_host:
+       free_irq(isi->irq, isi);
+err_req_irq:
+       iounmap(isi->regs);
+err_ioremap:
+       vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);
+err_alloc_ctx:
+       dma_free_coherent(&pdev->dev,
+                       sizeof(struct fbd) * MAX_BUFFER_NUM,
+                       isi->p_fb_descriptors,
+                       isi->fb_descriptors_phys);
+err_alloc_descriptors:
+       kfree(isi);
+err_alloc_isi:
+       clk_put(isi->pclk);
+
+       return ret;
+}
+
+static struct platform_driver atmel_isi_driver = {
+       .probe          = atmel_isi_probe,
+       .remove         = __devexit_p(atmel_isi_remove),
+       .driver         = {
+               .name = "atmel_isi",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init atmel_isi_init_module(void)
+{
+       return  platform_driver_probe(&atmel_isi_driver, &atmel_isi_probe);
+}
+
+static void __exit atmel_isi_exit(void)
+{
+       platform_driver_unregister(&atmel_isi_driver);
+}
+module_init(atmel_isi_init_module);
+module_exit(atmel_isi_exit);
+
+MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>");
+MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("video");
index ca342e4c61fcdc5bf59108a5a2bb38ebbbea81b0..1e4ce5068ec2db52ca634f9a90e12ad66f755f6b 100644 (file)
@@ -292,3 +292,4 @@ module_exit(au0828_exit);
 MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.2");
index c03eb29a9ee6976fba68ae19b8a9dd6ebcb4b6b7..0b3e481ffe8c5b4bafb18f96fafc4632e5ff839d 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/suspend.h>
-#include <linux/version.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-chip-ident.h>
@@ -43,8 +42,6 @@
 
 static DEFINE_MUTEX(au0828_sysfs_lock);
 
-#define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1)
-
 /* ------------------------------------------------------------------
        Videobuf operations
    ------------------------------------------------------------------*/
@@ -1254,8 +1251,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, dev->board.name, sizeof(cap->card));
        strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
 
-       cap->version = AU0828_VERSION_CODE;
-
        /*set the device capabilities */
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_VBI_CAPTURE |
index 3c9e6c7e7b52313b82a229535fc23d7962fbfc62..5b15f63bf065cc8646753c5e1dc6f9c19d348da0 100644 (file)
@@ -2892,13 +2892,10 @@ void __devinit bttv_idcard(struct bttv *btv)
 {
        unsigned int gpiobits;
        int i,type;
-       unsigned short tmp;
 
        /* read PCI subsystem ID */
-       pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_ID, &tmp);
-       btv->cardid = tmp << 16;
-       pci_read_config_word(btv->c.pci, PCI_SUBSYSTEM_VENDOR_ID, &tmp);
-       btv->cardid |= tmp;
+       btv->cardid  = btv->c.pci->subsystem_device << 16;
+       btv->cardid |= btv->c.pci->subsystem_vendor;
 
        if (0 != btv->cardid && 0xffffffff != btv->cardid) {
                /* look for the card */
index 834a48394bce1bc4546f2754c24553a54119d862..14444de67d5e6d5ab8c618886529815eadf090cd 100644 (file)
@@ -57,6 +57,7 @@
 
 #include <media/saa6588.h>
 
+#define BTTV_VERSION "0.9.19"
 
 unsigned int bttv_num;                 /* number of Bt848s in use */
 struct bttv *bttvs[BTTV_MAX];
@@ -163,6 +164,7 @@ MODULE_PARM_DESC(radio_nr, "radio device numbers");
 MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
 MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(BTTV_VERSION);
 
 /* ----------------------------------------------------------------------- */
 /* sysfs                                                                   */
@@ -2616,7 +2618,6 @@ static int bttv_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));
        snprintf(cap->bus_info, sizeof(cap->bus_info),
                 "PCI:%s", pci_name(btv->c.pci));
-       cap->version = BTTV_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_VBI_CAPTURE |
@@ -3416,7 +3417,6 @@ static int radio_querycap(struct file *file, void *priv,
        strcpy(cap->driver, "bttv");
        strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));
        sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));
-       cap->version = BTTV_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
 
        return 0;
@@ -4585,14 +4585,8 @@ static int __init bttv_init_module(void)
 
        bttv_num = 0;
 
-       printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
-              (BTTV_VERSION_CODE >> 16) & 0xff,
-              (BTTV_VERSION_CODE >> 8) & 0xff,
-              BTTV_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "bttv: driver version %s loaded\n",
+              BTTV_VERSION);
        if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
                gbuffers = 2;
        if (gbufsize > BTTV_MAX_FBUF)
index 9b776faf07416084896ecf94baef9f4906dd5875..318edf2830b4e7bfb0cde61582cadcd0b19ef3f6 100644 (file)
@@ -25,9 +25,6 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-#include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,18)
-
 #include <linux/types.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
index c1193506131c3a37e3c347a8703771a98f3938af..f09df9dffaae50d3db2ac887757e53d4fb2ff61d 100644 (file)
@@ -71,7 +71,6 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <linux/mm.h>
 #include <linux/parport.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
@@ -647,7 +646,6 @@ static int qcam_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card));
        strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
-       vcap->version = KERNEL_VERSION(0, 0, 2);
        vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
 }
@@ -895,6 +893,7 @@ static struct qcam *qcam_init(struct parport *port)
 
        if (v4l2_device_register(NULL, v4l2_dev) < 0) {
                v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               kfree(qcam);
                return NULL;
        }
 
@@ -1092,3 +1091,4 @@ module_init(init_bw_qcams);
 module_exit(exit_bw_qcams);
 
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.3");
index 24fc00965a12d048be055498230b734b794283fa..cd8ff0473184ea06a14bf38f0b97bfc82db91917 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/sched.h>
 #include <linux/mutex.h>
 #include <linux/jiffies.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <asm/uaccess.h>
 #include <media/v4l2-device.h>
@@ -517,7 +516,6 @@ static int qcam_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
        strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
-       vcap->version = KERNEL_VERSION(0, 0, 3);
        vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
 }
@@ -752,6 +750,7 @@ static struct qcam *qcam_init(struct parport *port)
 
        if (v4l2_device_register(NULL, v4l2_dev) < 0) {
                v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+               kfree(qcam);
                return NULL;
        }
 
@@ -886,6 +885,7 @@ static void __exit cqcam_cleanup(void)
 MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
 MODULE_DESCRIPTION(BANNER);
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.4");
 
 module_init(cqcam_init);
 module_exit(cqcam_cleanup);
diff --git a/drivers/media/video/cafe_ccic-regs.h b/drivers/media/video/cafe_ccic-regs.h
deleted file mode 100644 (file)
index 8e2a87c..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Register definitions for the m88alp01 camera interface.  Offsets in bytes
- * as given in the spec.
- *
- * Copyright 2006 One Laptop Per Child Association, Inc.
- *
- * Written by Jonathan Corbet, corbet@lwn.net.
- *
- * This file may be distributed under the terms of the GNU General
- * Public License, version 2.
- */
-#define REG_Y0BAR      0x00
-#define REG_Y1BAR      0x04
-#define REG_Y2BAR      0x08
-/* ... */
-
-#define REG_IMGPITCH   0x24    /* Image pitch register */
-#define   IMGP_YP_SHFT   2             /* Y pitch params */
-#define   IMGP_YP_MASK   0x00003ffc    /* Y pitch field */
-#define          IMGP_UVP_SHFT   18            /* UV pitch (planar) */
-#define   IMGP_UVP_MASK   0x3ffc0000
-#define REG_IRQSTATRAW 0x28    /* RAW IRQ Status */
-#define   IRQ_EOF0       0x00000001    /* End of frame 0 */
-#define   IRQ_EOF1       0x00000002    /* End of frame 1 */
-#define   IRQ_EOF2       0x00000004    /* End of frame 2 */
-#define   IRQ_SOF0       0x00000008    /* Start of frame 0 */
-#define   IRQ_SOF1       0x00000010    /* Start of frame 1 */
-#define   IRQ_SOF2       0x00000020    /* Start of frame 2 */
-#define   IRQ_OVERFLOW   0x00000040    /* FIFO overflow */
-#define   IRQ_TWSIW      0x00010000    /* TWSI (smbus) write */
-#define   IRQ_TWSIR      0x00020000    /* TWSI read */
-#define   IRQ_TWSIE      0x00040000    /* TWSI error */
-#define   TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE)
-#define   FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2)
-#define   ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW)
-#define REG_IRQMASK    0x2c    /* IRQ mask - same bits as IRQSTAT */
-#define REG_IRQSTAT    0x30    /* IRQ status / clear */
-
-#define REG_IMGSIZE    0x34    /* Image size */
-#define  IMGSZ_V_MASK    0x1fff0000
-#define  IMGSZ_V_SHIFT   16
-#define         IMGSZ_H_MASK     0x00003fff
-#define REG_IMGOFFSET  0x38    /* IMage offset */
-
-#define REG_CTRL0      0x3c    /* Control 0 */
-#define   C0_ENABLE      0x00000001    /* Makes the whole thing go */
-
-/* Mask for all the format bits */
-#define   C0_DF_MASK     0x00fffffc    /* Bits 2-23 */
-
-/* RGB ordering */
-#define   C0_RGB4_RGBX   0x00000000
-#define          C0_RGB4_XRGB    0x00000004
-#define          C0_RGB4_BGRX    0x00000008
-#define   C0_RGB4_XBGR   0x0000000c
-#define   C0_RGB5_RGGB   0x00000000
-#define          C0_RGB5_GRBG    0x00000004
-#define          C0_RGB5_GBRG    0x00000008
-#define   C0_RGB5_BGGR   0x0000000c
-
-/* Spec has two fields for DIN and DOUT, but they must match, so
-   combine them here. */
-#define   C0_DF_YUV      0x00000000    /* Data is YUV      */
-#define   C0_DF_RGB      0x000000a0    /* ... RGB                  */
-#define   C0_DF_BAYER     0x00000140   /* ... Bayer                */
-/* 8-8-8 must be missing from the below - ask */
-#define   C0_RGBF_565    0x00000000
-#define   C0_RGBF_444    0x00000800
-#define   C0_RGB_BGR     0x00001000    /* Blue comes first */
-#define   C0_YUV_PLANAR          0x00000000    /* YUV 422 planar format */
-#define   C0_YUV_PACKED          0x00008000    /* YUV 422 packed       */
-#define   C0_YUV_420PL   0x0000a000    /* YUV 420 planar       */
-/* Think that 420 packed must be 111 - ask */
-#define          C0_YUVE_YUYV    0x00000000    /* Y1CbY0Cr             */
-#define          C0_YUVE_YVYU    0x00010000    /* Y1CrY0Cb             */
-#define          C0_YUVE_VYUY    0x00020000    /* CrY1CbY0             */
-#define          C0_YUVE_UYVY    0x00030000    /* CbY1CrY0             */
-#define   C0_YUVE_XYUV   0x00000000    /* 420: .YUV            */
-#define          C0_YUVE_XYVU    0x00010000    /* 420: .YVU            */
-#define          C0_YUVE_XUVY    0x00020000    /* 420: .UVY            */
-#define          C0_YUVE_XVUY    0x00030000    /* 420: .VUY            */
-/* Bayer bits 18,19 if needed */
-#define   C0_HPOL_LOW    0x01000000    /* HSYNC polarity active low */
-#define   C0_VPOL_LOW    0x02000000    /* VSYNC polarity active low */
-#define   C0_VCLK_LOW    0x04000000    /* VCLK on falling edge */
-#define   C0_DOWNSCALE   0x08000000    /* Enable downscaler */
-#define          C0_SIFM_MASK    0xc0000000    /* SIF mode bits */
-#define   C0_SIF_HVSYNC          0x00000000    /* Use H/VSYNC */
-#define   CO_SOF_NOSYNC          0x40000000    /* Use inband active signaling */
-
-
-#define REG_CTRL1      0x40    /* Control 1 */
-#define   C1_444ALPHA    0x00f00000    /* Alpha field in RGB444 */
-#define   C1_ALPHA_SHFT          20
-#define   C1_DMAB32      0x00000000    /* 32-byte DMA burst */
-#define   C1_DMAB16      0x02000000    /* 16-byte DMA burst */
-#define          C1_DMAB64       0x04000000    /* 64-byte DMA burst */
-#define          C1_DMAB_MASK    0x06000000
-#define   C1_TWOBUFS     0x08000000    /* Use only two DMA buffers */
-#define   C1_PWRDWN      0x10000000    /* Power down */
-
-#define REG_CLKCTRL    0x88    /* Clock control */
-#define   CLK_DIV_MASK   0x0000ffff    /* Upper bits RW "reserved" */
-
-#define REG_GPR                0xb4    /* General purpose register.  This
-                                  controls inputs to the power and reset
-                                  pins on the OV7670 used with OLPC;
-                                  other deployments could differ.  */
-#define   GPR_C1EN       0x00000020    /* Pad 1 (power down) enable */
-#define   GPR_C0EN       0x00000010    /* Pad 0 (reset) enable */
-#define          GPR_C1          0x00000002    /* Control 1 value */
-/*
- * Control 0 is wired to reset on OLPC machines.  For ov7x sensors,
- * it is active low, for 0v6x, instead, it's active high.  What
- * fun.
- */
-#define   GPR_C0         0x00000001    /* Control 0 value */
-
-#define REG_TWSIC0     0xb8    /* TWSI (smbus) control 0 */
-#define   TWSIC0_EN       0x00000001   /* TWSI enable */
-#define   TWSIC0_MODE    0x00000002    /* 1 = 16-bit, 0 = 8-bit */
-#define   TWSIC0_SID     0x000003fc    /* Slave ID */
-#define   TWSIC0_SID_SHIFT 2
-#define   TWSIC0_CLKDIV   0x0007fc00   /* Clock divider */
-#define   TWSIC0_MASKACK  0x00400000   /* Mask ack from sensor */
-#define   TWSIC0_OVMAGIC  0x00800000   /* Make it work on OV sensors */
-
-#define REG_TWSIC1     0xbc    /* TWSI control 1 */
-#define   TWSIC1_DATA    0x0000ffff    /* Data to/from camchip */
-#define   TWSIC1_ADDR    0x00ff0000    /* Address (register) */
-#define   TWSIC1_ADDR_SHIFT 16
-#define   TWSIC1_READ    0x01000000    /* Set for read op */
-#define   TWSIC1_WSTAT   0x02000000    /* Write status */
-#define   TWSIC1_RVALID          0x04000000    /* Read data valid */
-#define   TWSIC1_ERROR   0x08000000    /* Something screwed up */
-
-
-#define REG_UBAR       0xc4    /* Upper base address register */
-
-/*
- * Here's the weird global control registers which are said to live
- * way up here.
- */
-#define REG_GL_CSR     0x3004  /* Control/status register */
-#define   GCSR_SRS      0x00000001     /* SW Reset set */
-#define   GCSR_SRC      0x00000002     /* SW Reset clear */
-#define          GCSR_MRS       0x00000004     /* Master reset set */
-#define          GCSR_MRC       0x00000008     /* HW Reset clear */
-#define   GCSR_CCIC_EN   0x00004000    /* CCIC Clock enable */
-#define REG_GL_IMASK   0x300c  /* Interrupt mask register */
-#define   GIMSK_CCIC_EN          0x00000004    /* CCIC Interrupt enable */
-
-#define REG_GL_FCR     0x3038  /* GPIO functional control register */
-#define          GFCR_GPIO_ON    0x08          /* Camera GPIO enabled */
-#define REG_GL_GPIOR   0x315c  /* GPIO register */
-#define   GGPIO_OUT            0x80000 /* GPIO output */
-#define   GGPIO_VAL            0x00008 /* Output pin value */
-
-#define REG_LEN                REG_GL_IMASK + 4
-
-
-/*
- * Useful stuff that probably belongs somewhere global.
- */
-#define VGA_WIDTH      640
-#define VGA_HEIGHT     480
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
deleted file mode 100644 (file)
index 6647033..0000000
+++ /dev/null
@@ -1,2267 +0,0 @@
-/*
- * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe"
- * multifunction chip.  Currently works with the Omnivision OV7670
- * sensor.
- *
- * The data sheet for this device can be found at:
- *    http://www.marvell.com/products/pc_connectivity/88alp01/ 
- *
- * Copyright 2006 One Laptop Per Child Association, Inc.
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- *
- * Written by Jonathan Corbet, corbet@lwn.net.
- *
- * v4l2_device/v4l2_subdev conversion by:
- * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
- *
- * Note: this conversion is untested! Please contact the linux-media
- * mailinglist if you can test this, together with the test results.
- *
- * This file may be distributed under the terms of the GNU General
- * Public License, version 2.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/dmi.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-chip-ident.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include "ov7670.h"
-#include "cafe_ccic-regs.h"
-
-#define CAFE_VERSION 0x000002
-
-
-/*
- * Parameters.
- */
-MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
-MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("Video");
-
-/*
- * Internal DMA buffer management.  Since the controller cannot do S/G I/O,
- * we must have physically contiguous buffers to bring frames into.
- * These parameters control how many buffers we use, whether we
- * allocate them at load time (better chance of success, but nails down
- * memory) or when somebody tries to use the camera (riskier), and,
- * for load-time allocation, how big they should be.
- *
- * The controller can cycle through three buffers.  We could use
- * more by flipping pointers around, but it probably makes little
- * sense.
- */
-
-#define MAX_DMA_BUFS 3
-static int alloc_bufs_at_read;
-module_param(alloc_bufs_at_read, bool, 0444);
-MODULE_PARM_DESC(alloc_bufs_at_read,
-               "Non-zero value causes DMA buffers to be allocated when the "
-               "video capture device is read, rather than at module load "
-               "time.  This saves memory, but decreases the chances of "
-               "successfully getting those buffers.");
-
-static int n_dma_bufs = 3;
-module_param(n_dma_bufs, uint, 0644);
-MODULE_PARM_DESC(n_dma_bufs,
-               "The number of DMA buffers to allocate.  Can be either two "
-               "(saves memory, makes timing tighter) or three.");
-
-static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2;  /* Worst case */
-module_param(dma_buf_size, uint, 0444);
-MODULE_PARM_DESC(dma_buf_size,
-               "The size of the allocated DMA buffers.  If actual operating "
-               "parameters require larger buffers, an attempt to reallocate "
-               "will be made.");
-
-static int min_buffers = 1;
-module_param(min_buffers, uint, 0644);
-MODULE_PARM_DESC(min_buffers,
-               "The minimum number of streaming I/O buffers we are willing "
-               "to work with.");
-
-static int max_buffers = 10;
-module_param(max_buffers, uint, 0644);
-MODULE_PARM_DESC(max_buffers,
-               "The maximum number of streaming I/O buffers an application "
-               "will be allowed to allocate.  These buffers are big and live "
-               "in vmalloc space.");
-
-static int flip;
-module_param(flip, bool, 0444);
-MODULE_PARM_DESC(flip,
-               "If set, the sensor will be instructed to flip the image "
-               "vertically.");
-
-
-enum cafe_state {
-       S_NOTREADY,     /* Not yet initialized */
-       S_IDLE,         /* Just hanging around */
-       S_FLAKED,       /* Some sort of problem */
-       S_SINGLEREAD,   /* In read() */
-       S_SPECREAD,     /* Speculative read (for future read()) */
-       S_STREAMING     /* Streaming data */
-};
-
-/*
- * Tracking of streaming I/O buffers.
- */
-struct cafe_sio_buffer {
-       struct list_head list;
-       struct v4l2_buffer v4lbuf;
-       char *buffer;   /* Where it lives in kernel space */
-       int mapcount;
-       struct cafe_camera *cam;
-};
-
-/*
- * A description of one of our devices.
- * Locking: controlled by s_mutex.  Certain fields, however, require
- *         the dev_lock spinlock; they are marked as such by comments.
- *         dev_lock is also required for access to device registers.
- */
-struct cafe_camera
-{
-       struct v4l2_device v4l2_dev;
-       enum cafe_state state;
-       unsigned long flags;            /* Buffer status, mainly (dev_lock) */
-       int users;                      /* How many open FDs */
-       struct file *owner;             /* Who has data access (v4l2) */
-
-       /*
-        * Subsystem structures.
-        */
-       struct pci_dev *pdev;
-       struct video_device vdev;
-       struct i2c_adapter i2c_adapter;
-       struct v4l2_subdev *sensor;
-       unsigned short sensor_addr;
-
-       unsigned char __iomem *regs;
-       struct list_head dev_list;      /* link to other devices */
-
-       /* DMA buffers */
-       unsigned int nbufs;             /* How many are alloc'd */
-       int next_buf;                   /* Next to consume (dev_lock) */
-       unsigned int dma_buf_size;      /* allocated size */
-       void *dma_bufs[MAX_DMA_BUFS];   /* Internal buffer addresses */
-       dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
-       unsigned int specframes;        /* Unconsumed spec frames (dev_lock) */
-       unsigned int sequence;          /* Frame sequence number */
-       unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */
-
-       /* Streaming buffers */
-       unsigned int n_sbufs;           /* How many we have */
-       struct cafe_sio_buffer *sb_bufs; /* The array of housekeeping structs */
-       struct list_head sb_avail;      /* Available for data (we own) (dev_lock) */
-       struct list_head sb_full;       /* With data (user space owns) (dev_lock) */
-       struct tasklet_struct s_tasklet;
-
-       /* Current operating parameters */
-       u32 sensor_type;                /* Currently ov7670 only */
-       struct v4l2_pix_format pix_format;
-       enum v4l2_mbus_pixelcode mbus_code;
-
-       /* Locks */
-       struct mutex s_mutex; /* Access to this structure */
-       spinlock_t dev_lock;  /* Access to device */
-
-       /* Misc */
-       wait_queue_head_t smbus_wait;   /* Waiting on i2c events */
-       wait_queue_head_t iowait;       /* Waiting on frame data */
-};
-
-/*
- * Status flags.  Always manipulated with bit operations.
- */
-#define CF_BUF0_VALID   0      /* Buffers valid - first three */
-#define CF_BUF1_VALID   1
-#define CF_BUF2_VALID   2
-#define CF_DMA_ACTIVE   3      /* A frame is incoming */
-#define CF_CONFIG_NEEDED 4     /* Must configure hardware */
-
-#define sensor_call(cam, o, f, args...) \
-       v4l2_subdev_call(cam->sensor, o, f, ##args)
-
-static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
-{
-       return container_of(dev, struct cafe_camera, v4l2_dev);
-}
-
-static struct cafe_format_struct {
-       __u8 *desc;
-       __u32 pixelformat;
-       int bpp;   /* Bytes per pixel */
-       enum v4l2_mbus_pixelcode mbus_code;
-} cafe_formats[] = {
-       {
-               .desc           = "YUYV 4:2:2",
-               .pixelformat    = V4L2_PIX_FMT_YUYV,
-               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
-               .bpp            = 2,
-       },
-       {
-               .desc           = "RGB 444",
-               .pixelformat    = V4L2_PIX_FMT_RGB444,
-               .mbus_code      = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
-               .bpp            = 2,
-       },
-       {
-               .desc           = "RGB 565",
-               .pixelformat    = V4L2_PIX_FMT_RGB565,
-               .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
-               .bpp            = 2,
-       },
-       {
-               .desc           = "Raw RGB Bayer",
-               .pixelformat    = V4L2_PIX_FMT_SBGGR8,
-               .mbus_code      = V4L2_MBUS_FMT_SBGGR8_1X8,
-               .bpp            = 1
-       },
-};
-#define N_CAFE_FMTS ARRAY_SIZE(cafe_formats)
-
-static struct cafe_format_struct *cafe_find_format(u32 pixelformat)
-{
-       unsigned i;
-
-       for (i = 0; i < N_CAFE_FMTS; i++)
-               if (cafe_formats[i].pixelformat == pixelformat)
-                       return cafe_formats + i;
-       /* Not found? Then return the first format. */
-       return cafe_formats;
-}
-
-/*
- * Start over with DMA buffers - dev_lock needed.
- */
-static void cafe_reset_buffers(struct cafe_camera *cam)
-{
-       int i;
-
-       cam->next_buf = -1;
-       for (i = 0; i < cam->nbufs; i++)
-               clear_bit(i, &cam->flags);
-       cam->specframes = 0;
-}
-
-static inline int cafe_needs_config(struct cafe_camera *cam)
-{
-       return test_bit(CF_CONFIG_NEEDED, &cam->flags);
-}
-
-static void cafe_set_config_needed(struct cafe_camera *cam, int needed)
-{
-       if (needed)
-               set_bit(CF_CONFIG_NEEDED, &cam->flags);
-       else
-               clear_bit(CF_CONFIG_NEEDED, &cam->flags);
-}
-
-
-
-
-/*
- * Debugging and related.
- */
-#define cam_err(cam, fmt, arg...) \
-       dev_err(&(cam)->pdev->dev, fmt, ##arg);
-#define cam_warn(cam, fmt, arg...) \
-       dev_warn(&(cam)->pdev->dev, fmt, ##arg);
-#define cam_dbg(cam, fmt, arg...) \
-       dev_dbg(&(cam)->pdev->dev, fmt, ##arg);
-
-
-/* ---------------------------------------------------------------------*/
-
-/*
- * Device register I/O
- */
-static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg,
-               unsigned int val)
-{
-       iowrite32(val, cam->regs + reg);
-}
-
-static inline unsigned int cafe_reg_read(struct cafe_camera *cam,
-               unsigned int reg)
-{
-       return ioread32(cam->regs + reg);
-}
-
-
-static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg,
-               unsigned int val, unsigned int mask)
-{
-       unsigned int v = cafe_reg_read(cam, reg);
-
-       v = (v & ~mask) | (val & mask);
-       cafe_reg_write(cam, reg, v);
-}
-
-static inline void cafe_reg_clear_bit(struct cafe_camera *cam,
-               unsigned int reg, unsigned int val)
-{
-       cafe_reg_write_mask(cam, reg, 0, val);
-}
-
-static inline void cafe_reg_set_bit(struct cafe_camera *cam,
-               unsigned int reg, unsigned int val)
-{
-       cafe_reg_write_mask(cam, reg, val, val);
-}
-
-
-
-/* -------------------------------------------------------------------- */
-/*
- * The I2C/SMBUS interface to the camera itself starts here.  The
- * controller handles SMBUS itself, presenting a relatively simple register
- * interface; all we have to do is to tell it where to route the data.
- */
-#define CAFE_SMBUS_TIMEOUT (HZ)  /* generous */
-
-static int cafe_smbus_write_done(struct cafe_camera *cam)
-{
-       unsigned long flags;
-       int c1;
-
-       /*
-        * We must delay after the interrupt, or the controller gets confused
-        * and never does give us good status.  Fortunately, we don't do this
-        * often.
-        */
-       udelay(20);
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       c1 = cafe_reg_read(cam, REG_TWSIC1);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT;
-}
-
-static int cafe_smbus_write_data(struct cafe_camera *cam,
-               u16 addr, u8 command, u8 value)
-{
-       unsigned int rval;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
-       rval |= TWSIC0_OVMAGIC;  /* Make OV sensors work */
-       /*
-        * Marvell sez set clkdiv to all 1's for now.
-        */
-       rval |= TWSIC0_CLKDIV;
-       cafe_reg_write(cam, REG_TWSIC0, rval);
-       (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
-       rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
-       cafe_reg_write(cam, REG_TWSIC1, rval);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-       /* Unfortunately, reading TWSIC1 too soon after sending a command
-        * causes the device to die.
-        * Use a busy-wait because we often send a large quantity of small
-        * commands at-once; using msleep() would cause a lot of context
-        * switches which take longer than 2ms, resulting in a noticeable
-        * boot-time and capture-start delays.
-        */
-       mdelay(2);
-
-       /*
-        * Another sad fact is that sometimes, commands silently complete but
-        * cafe_smbus_write_done() never becomes aware of this.
-        * This happens at random and appears to possible occur with any
-        * command.
-        * We don't understand why this is. We work around this issue
-        * with the timeout in the wait below, assuming that all commands
-        * complete within the timeout.
-        */
-       wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
-                       CAFE_SMBUS_TIMEOUT);
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       rval = cafe_reg_read(cam, REG_TWSIC1);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-       if (rval & TWSIC1_WSTAT) {
-               cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr,
-                               command, value);
-               return -EIO;
-       }
-       if (rval & TWSIC1_ERROR) {
-               cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr,
-                               command, value);
-               return -EIO;
-       }
-       return 0;
-}
-
-
-
-static int cafe_smbus_read_done(struct cafe_camera *cam)
-{
-       unsigned long flags;
-       int c1;
-
-       /*
-        * We must delay after the interrupt, or the controller gets confused
-        * and never does give us good status.  Fortunately, we don't do this
-        * often.
-        */
-       udelay(20);
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       c1 = cafe_reg_read(cam, REG_TWSIC1);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       return c1 & (TWSIC1_RVALID|TWSIC1_ERROR);
-}
-
-
-
-static int cafe_smbus_read_data(struct cafe_camera *cam,
-               u16 addr, u8 command, u8 *value)
-{
-       unsigned int rval;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
-       rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
-       /*
-        * Marvel sez set clkdiv to all 1's for now.
-        */
-       rval |= TWSIC0_CLKDIV;
-       cafe_reg_write(cam, REG_TWSIC0, rval);
-       (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */
-       rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
-       cafe_reg_write(cam, REG_TWSIC1, rval);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-       wait_event_timeout(cam->smbus_wait,
-                       cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT);
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       rval = cafe_reg_read(cam, REG_TWSIC1);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-       if (rval & TWSIC1_ERROR) {
-               cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command);
-               return -EIO;
-       }
-       if (! (rval & TWSIC1_RVALID)) {
-               cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr,
-                               command);
-               return -EIO;
-       }
-       *value = rval & 0xff;
-       return 0;
-}
-
-/*
- * Perform a transfer over SMBUS.  This thing is called under
- * the i2c bus lock, so we shouldn't race with ourselves...
- */
-static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
-               unsigned short flags, char rw, u8 command,
-               int size, union i2c_smbus_data *data)
-{
-       struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
-       struct cafe_camera *cam = to_cam(v4l2_dev);
-       int ret = -EINVAL;
-
-       /*
-        * This interface would appear to only do byte data ops.  OK
-        * it can do word too, but the cam chip has no use for that.
-        */
-       if (size != I2C_SMBUS_BYTE_DATA) {
-               cam_err(cam, "funky xfer size %d\n", size);
-               return -EINVAL;
-       }
-
-       if (rw == I2C_SMBUS_WRITE)
-               ret = cafe_smbus_write_data(cam, addr, command, data->byte);
-       else if (rw == I2C_SMBUS_READ)
-               ret = cafe_smbus_read_data(cam, addr, command, &data->byte);
-       return ret;
-}
-
-
-static void cafe_smbus_enable_irq(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-static u32 cafe_smbus_func(struct i2c_adapter *adapter)
-{
-       return I2C_FUNC_SMBUS_READ_BYTE_DATA  |
-              I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-static struct i2c_algorithm cafe_smbus_algo = {
-       .smbus_xfer = cafe_smbus_xfer,
-       .functionality = cafe_smbus_func
-};
-
-/* Somebody is on the bus */
-static void cafe_ctlr_stop_dma(struct cafe_camera *cam);
-static void cafe_ctlr_power_down(struct cafe_camera *cam);
-
-static int cafe_smbus_setup(struct cafe_camera *cam)
-{
-       struct i2c_adapter *adap = &cam->i2c_adapter;
-       int ret;
-
-       cafe_smbus_enable_irq(cam);
-       adap->owner = THIS_MODULE;
-       adap->algo = &cafe_smbus_algo;
-       strcpy(adap->name, "cafe_ccic");
-       adap->dev.parent = &cam->pdev->dev;
-       i2c_set_adapdata(adap, &cam->v4l2_dev);
-       ret = i2c_add_adapter(adap);
-       if (ret)
-               printk(KERN_ERR "Unable to register cafe i2c adapter\n");
-       return ret;
-}
-
-static void cafe_smbus_shutdown(struct cafe_camera *cam)
-{
-       i2c_del_adapter(&cam->i2c_adapter);
-}
-
-
-/* ------------------------------------------------------------------- */
-/*
- * Deal with the controller.
- */
-
-/*
- * Do everything we think we need to have the interface operating
- * according to the desired format.
- */
-static void cafe_ctlr_dma(struct cafe_camera *cam)
-{
-       /*
-        * Store the first two Y buffers (we aren't supporting
-        * planar formats for now, so no UV bufs).  Then either
-        * set the third if it exists, or tell the controller
-        * to just use two.
-        */
-       cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]);
-       cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]);
-       if (cam->nbufs > 2) {
-               cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]);
-               cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
-       }
-       else
-               cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
-       cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */
-}
-
-static void cafe_ctlr_image(struct cafe_camera *cam)
-{
-       int imgsz;
-       struct v4l2_pix_format *fmt = &cam->pix_format;
-
-       imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
-               (fmt->bytesperline & IMGSZ_H_MASK);
-       cafe_reg_write(cam, REG_IMGSIZE, imgsz);
-       cafe_reg_write(cam, REG_IMGOFFSET, 0);
-       /* YPITCH just drops the last two bits */
-       cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
-                       IMGP_YP_MASK);
-       /*
-        * Tell the controller about the image format we are using.
-        */
-       switch (cam->pix_format.pixelformat) {
-       case V4L2_PIX_FMT_YUYV:
-           cafe_reg_write_mask(cam, REG_CTRL0,
-                           C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
-                           C0_DF_MASK);
-           break;
-
-       case V4L2_PIX_FMT_RGB444:
-           cafe_reg_write_mask(cam, REG_CTRL0,
-                           C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
-                           C0_DF_MASK);
-               /* Alpha value? */
-           break;
-
-       case V4L2_PIX_FMT_RGB565:
-           cafe_reg_write_mask(cam, REG_CTRL0,
-                           C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
-                           C0_DF_MASK);
-           break;
-
-       default:
-           cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
-           break;
-       }
-       /*
-        * Make sure it knows we want to use hsync/vsync.
-        */
-       cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
-                       C0_SIFM_MASK);
-}
-
-
-/*
- * Configure the controller for operation; caller holds the
- * device mutex.
- */
-static int cafe_ctlr_configure(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_ctlr_dma(cam);
-       cafe_ctlr_image(cam);
-       cafe_set_config_needed(cam, 0);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       return 0;
-}
-
-static void cafe_ctlr_irq_enable(struct cafe_camera *cam)
-{
-       /*
-        * Clear any pending interrupts, since we do not
-        * expect to have I/O active prior to enabling.
-        */
-       cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS);
-       cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS);
-}
-
-static void cafe_ctlr_irq_disable(struct cafe_camera *cam)
-{
-       cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
-}
-
-/*
- * Make the controller start grabbing images.  Everything must
- * be set up before doing this.
- */
-static void cafe_ctlr_start(struct cafe_camera *cam)
-{
-       /* set_bit performs a read, so no other barrier should be
-          needed here */
-       cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
-}
-
-static void cafe_ctlr_stop(struct cafe_camera *cam)
-{
-       cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
-}
-
-static void cafe_ctlr_init(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       /*
-        * Added magic to bring up the hardware on the B-Test board
-        */
-       cafe_reg_write(cam, 0x3038, 0x8);
-       cafe_reg_write(cam, 0x315c, 0x80008);
-       /*
-        * Go through the dance needed to wake the device up.
-        * Note that these registers are global and shared
-        * with the NAND and SD devices.  Interaction between the
-        * three still needs to be examined.
-        */
-       cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
-       cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
-       cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
-       /*
-        * Here we must wait a bit for the controller to come around.
-        */
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       msleep(5);
-       spin_lock_irqsave(&cam->dev_lock, flags);
-
-       cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
-       cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN);
-       /*
-        * Make sure it's not powered down.
-        */
-       cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
-       /*
-        * Turn off the enable bit.  It sure should be off anyway,
-        * but it's good to be sure.
-        */
-       cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
-       /*
-        * Mask all interrupts.
-        */
-       cafe_reg_write(cam, REG_IRQMASK, 0);
-       /*
-        * Clock the sensor appropriately.  Controller clock should
-        * be 48MHz, sensor "typical" value is half that.
-        */
-       cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-
-/*
- * Stop the controller, and don't return until we're really sure that no
- * further DMA is going on.
- */
-static void cafe_ctlr_stop_dma(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       /*
-        * Theory: stop the camera controller (whether it is operating
-        * or not).  Delay briefly just in case we race with the SOF
-        * interrupt, then wait until no DMA is active.
-        */
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_ctlr_stop(cam);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       mdelay(1);
-       wait_event_timeout(cam->iowait,
-                       !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ);
-       if (test_bit(CF_DMA_ACTIVE, &cam->flags))
-               cam_err(cam, "Timeout waiting for DMA to end\n");
-               /* This would be bad news - what now? */
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cam->state = S_IDLE;
-       cafe_ctlr_irq_disable(cam);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-/*
- * Power up and down.
- */
-static void cafe_ctlr_power_up(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
-       /*
-        * Part one of the sensor dance: turn the global
-        * GPIO signal on.
-        */
-       cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON);
-       cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL);
-       /*
-        * Put the sensor into operational mode (assumes OLPC-style
-        * wiring).  Control 0 is reset - set to 1 to operate.
-        * Control 1 is power down, set to 0 to operate.
-        */
-       cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
-/*     mdelay(1); */ /* Marvell says 1ms will do it */
-       cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
-/*     mdelay(1); */ /* Enough? */
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       msleep(5); /* Just to be sure */
-}
-
-static void cafe_ctlr_power_down(struct cafe_camera *cam)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
-       cafe_reg_write(cam, REG_GL_FCR, GFCR_GPIO_ON);
-       cafe_reg_write(cam, REG_GL_GPIOR, GGPIO_OUT);
-       cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-/* -------------------------------------------------------------------- */
-/*
- * Communications with the sensor.
- */
-
-static int __cafe_cam_reset(struct cafe_camera *cam)
-{
-       return sensor_call(cam, core, reset, 0);
-}
-
-/*
- * We have found the sensor on the i2c.  Let's try to have a
- * conversation.
- */
-static int cafe_cam_init(struct cafe_camera *cam)
-{
-       struct v4l2_dbg_chip_ident chip;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       if (cam->state != S_NOTREADY)
-               cam_warn(cam, "Cam init with device in funky state %d",
-                               cam->state);
-       ret = __cafe_cam_reset(cam);
-       if (ret)
-               goto out;
-       chip.ident = V4L2_IDENT_NONE;
-       chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
-       chip.match.addr = cam->sensor_addr;
-       ret = sensor_call(cam, core, g_chip_ident, &chip);
-       if (ret)
-               goto out;
-       cam->sensor_type = chip.ident;
-       if (cam->sensor_type != V4L2_IDENT_OV7670) {
-               cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type);
-               ret = -EINVAL;
-               goto out;
-       }
-/* Get/set parameters? */
-       ret = 0;
-       cam->state = S_IDLE;
-  out:
-       cafe_ctlr_power_down(cam);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-/*
- * Configure the sensor to match the parameters we have.  Caller should
- * hold s_mutex
- */
-static int cafe_cam_set_flip(struct cafe_camera *cam)
-{
-       struct v4l2_control ctrl;
-
-       memset(&ctrl, 0, sizeof(ctrl));
-       ctrl.id = V4L2_CID_VFLIP;
-       ctrl.value = flip;
-       return sensor_call(cam, core, s_ctrl, &ctrl);
-}
-
-
-static int cafe_cam_configure(struct cafe_camera *cam)
-{
-       struct v4l2_mbus_framefmt mbus_fmt;
-       int ret;
-
-       v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code);
-       ret = sensor_call(cam, core, init, 0);
-       if (ret == 0)
-               ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
-       /*
-        * OV7670 does weird things if flip is set *before* format...
-        */
-       ret += cafe_cam_set_flip(cam);
-       return ret;
-}
-
-/* -------------------------------------------------------------------- */
-/*
- * DMA buffer management.  These functions need s_mutex held.
- */
-
-/* FIXME: this is inefficient as hell, since dma_alloc_coherent just
- * does a get_free_pages() call, and we waste a good chunk of an orderN
- * allocation.  Should try to allocate the whole set in one chunk.
- */
-static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime)
-{
-       int i;
-
-       cafe_set_config_needed(cam, 1);
-       if (loadtime)
-               cam->dma_buf_size = dma_buf_size;
-       else
-               cam->dma_buf_size = cam->pix_format.sizeimage;
-       if (n_dma_bufs > 3)
-               n_dma_bufs = 3;
-
-       cam->nbufs = 0;
-       for (i = 0; i < n_dma_bufs; i++) {
-               cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev,
-                               cam->dma_buf_size, cam->dma_handles + i,
-                               GFP_KERNEL);
-               if (cam->dma_bufs[i] == NULL) {
-                       cam_warn(cam, "Failed to allocate DMA buffer\n");
-                       break;
-               }
-               /* For debug, remove eventually */
-               memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size);
-               (cam->nbufs)++;
-       }
-
-       switch (cam->nbufs) {
-       case 1:
-           dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
-                           cam->dma_bufs[0], cam->dma_handles[0]);
-           cam->nbufs = 0;
-       case 0:
-           cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
-           return -ENOMEM;
-
-       case 2:
-           if (n_dma_bufs > 2)
-                   cam_warn(cam, "Will limp along with only 2 buffers\n");
-           break;
-       }
-       return 0;
-}
-
-static void cafe_free_dma_bufs(struct cafe_camera *cam)
-{
-       int i;
-
-       for (i = 0; i < cam->nbufs; i++) {
-               dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size,
-                               cam->dma_bufs[i], cam->dma_handles[i]);
-               cam->dma_bufs[i] = NULL;
-       }
-       cam->nbufs = 0;
-}
-
-
-
-
-
-/* ----------------------------------------------------------------------- */
-/*
- * Here starts the V4L2 interface code.
- */
-
-/*
- * Read an image from the device.
- */
-static ssize_t cafe_deliver_buffer(struct cafe_camera *cam,
-               char __user *buffer, size_t len, loff_t *pos)
-{
-       int bufno;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       if (cam->next_buf < 0) {
-               cam_err(cam, "deliver_buffer: No next buffer\n");
-               spin_unlock_irqrestore(&cam->dev_lock, flags);
-               return -EIO;
-       }
-       bufno = cam->next_buf;
-       clear_bit(bufno, &cam->flags);
-       if (++(cam->next_buf) >= cam->nbufs)
-               cam->next_buf = 0;
-       if (! test_bit(cam->next_buf, &cam->flags))
-               cam->next_buf = -1;
-       cam->specframes = 0;
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-
-       if (len > cam->pix_format.sizeimage)
-               len = cam->pix_format.sizeimage;
-       if (copy_to_user(buffer, cam->dma_bufs[bufno], len))
-               return -EFAULT;
-       (*pos) += len;
-       return len;
-}
-
-/*
- * Get everything ready, and start grabbing frames.
- */
-static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state)
-{
-       int ret;
-       unsigned long flags;
-
-       /*
-        * Configuration.  If we still don't have DMA buffers,
-        * make one last, desperate attempt.
-        */
-       if (cam->nbufs == 0)
-               if (cafe_alloc_dma_bufs(cam, 0))
-                       return -ENOMEM;
-
-       if (cafe_needs_config(cam)) {
-               cafe_cam_configure(cam);
-               ret = cafe_ctlr_configure(cam);
-               if (ret)
-                       return ret;
-       }
-
-       /*
-        * Turn it loose.
-        */
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       cafe_reset_buffers(cam);
-       cafe_ctlr_irq_enable(cam);
-       cam->state = state;
-       cafe_ctlr_start(cam);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       return 0;
-}
-
-
-static ssize_t cafe_v4l_read(struct file *filp,
-               char __user *buffer, size_t len, loff_t *pos)
-{
-       struct cafe_camera *cam = filp->private_data;
-       int ret = 0;
-
-       /*
-        * Perhaps we're in speculative read mode and already
-        * have data?
-        */
-       mutex_lock(&cam->s_mutex);
-       if (cam->state == S_SPECREAD) {
-               if (cam->next_buf >= 0) {
-                       ret = cafe_deliver_buffer(cam, buffer, len, pos);
-                       if (ret != 0)
-                               goto out_unlock;
-               }
-       } else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) {
-               ret = -EIO;
-               goto out_unlock;
-       } else if (cam->state != S_IDLE) {
-               ret = -EBUSY;
-               goto out_unlock;
-       }
-
-       /*
-        * v4l2: multiple processes can open the device, but only
-        * one gets to grab data from it.
-        */
-       if (cam->owner && cam->owner != filp) {
-               ret = -EBUSY;
-               goto out_unlock;
-       }
-       cam->owner = filp;
-
-       /*
-        * Do setup if need be.
-        */
-       if (cam->state != S_SPECREAD) {
-               ret = cafe_read_setup(cam, S_SINGLEREAD);
-               if (ret)
-                       goto out_unlock;
-       }
-       /*
-        * Wait for something to happen.  This should probably
-        * be interruptible (FIXME).
-        */
-       wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ);
-       if (cam->next_buf < 0) {
-               cam_err(cam, "read() operation timed out\n");
-               cafe_ctlr_stop_dma(cam);
-               ret = -EIO;
-               goto out_unlock;
-       }
-       /*
-        * Give them their data and we should be done.
-        */
-       ret = cafe_deliver_buffer(cam, buffer, len, pos);
-
-  out_unlock:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-
-
-
-
-
-
-/*
- * Streaming I/O support.
- */
-
-
-
-static int cafe_vidioc_streamon(struct file *filp, void *priv,
-               enum v4l2_buf_type type)
-{
-       struct cafe_camera *cam = filp->private_data;
-       int ret = -EINVAL;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               goto out;
-       mutex_lock(&cam->s_mutex);
-       if (cam->state != S_IDLE || cam->n_sbufs == 0)
-               goto out_unlock;
-
-       cam->sequence = 0;
-       ret = cafe_read_setup(cam, S_STREAMING);
-
-  out_unlock:
-       mutex_unlock(&cam->s_mutex);
-  out:
-       return ret;
-}
-
-
-static int cafe_vidioc_streamoff(struct file *filp, void *priv,
-               enum v4l2_buf_type type)
-{
-       struct cafe_camera *cam = filp->private_data;
-       int ret = -EINVAL;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               goto out;
-       mutex_lock(&cam->s_mutex);
-       if (cam->state != S_STREAMING)
-               goto out_unlock;
-
-       cafe_ctlr_stop_dma(cam);
-       ret = 0;
-
-  out_unlock:
-       mutex_unlock(&cam->s_mutex);
-  out:
-       return ret;
-}
-
-
-
-static int cafe_setup_siobuf(struct cafe_camera *cam, int index)
-{
-       struct cafe_sio_buffer *buf = cam->sb_bufs + index;
-
-       INIT_LIST_HEAD(&buf->list);
-       buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage);
-       buf->buffer = vmalloc_user(buf->v4lbuf.length);
-       if (buf->buffer == NULL)
-               return -ENOMEM;
-       buf->mapcount = 0;
-       buf->cam = cam;
-
-       buf->v4lbuf.index = index;
-       buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       buf->v4lbuf.field = V4L2_FIELD_NONE;
-       buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
-       /*
-        * Offset: must be 32-bit even on a 64-bit system.  videobuf-dma-sg
-        * just uses the length times the index, but the spec warns
-        * against doing just that - vma merging problems.  So we
-        * leave a gap between each pair of buffers.
-        */
-       buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
-       return 0;
-}
-
-static int cafe_free_sio_buffers(struct cafe_camera *cam)
-{
-       int i;
-
-       /*
-        * If any buffers are mapped, we cannot free them at all.
-        */
-       for (i = 0; i < cam->n_sbufs; i++)
-               if (cam->sb_bufs[i].mapcount > 0)
-                       return -EBUSY;
-       /*
-        * OK, let's do it.
-        */
-       for (i = 0; i < cam->n_sbufs; i++)
-               vfree(cam->sb_bufs[i].buffer);
-       cam->n_sbufs = 0;
-       kfree(cam->sb_bufs);
-       cam->sb_bufs = NULL;
-       INIT_LIST_HEAD(&cam->sb_avail);
-       INIT_LIST_HEAD(&cam->sb_full);
-       return 0;
-}
-
-
-
-static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
-               struct v4l2_requestbuffers *req)
-{
-       struct cafe_camera *cam = filp->private_data;
-       int ret = 0;  /* Silence warning */
-
-       /*
-        * Make sure it's something we can do.  User pointers could be
-        * implemented without great pain, but that's not been done yet.
-        */
-       if (req->memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-       /*
-        * If they ask for zero buffers, they really want us to stop streaming
-        * (if it's happening) and free everything.  Should we check owner?
-        */
-       mutex_lock(&cam->s_mutex);
-       if (req->count == 0) {
-               if (cam->state == S_STREAMING)
-                       cafe_ctlr_stop_dma(cam);
-               ret = cafe_free_sio_buffers (cam);
-               goto out;
-       }
-       /*
-        * Device needs to be idle and working.  We *could* try to do the
-        * right thing in S_SPECREAD by shutting things down, but it
-        * probably doesn't matter.
-        */
-       if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) {
-               ret = -EBUSY;
-               goto out;
-       }
-       cam->owner = filp;
-
-       if (req->count < min_buffers)
-               req->count = min_buffers;
-       else if (req->count > max_buffers)
-               req->count = max_buffers;
-       if (cam->n_sbufs > 0) {
-               ret = cafe_free_sio_buffers(cam);
-               if (ret)
-                       goto out;
-       }
-
-       cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer),
-                       GFP_KERNEL);
-       if (cam->sb_bufs == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) {
-               ret = cafe_setup_siobuf(cam, cam->n_sbufs);
-               if (ret)
-                       break;
-       }
-
-       if (cam->n_sbufs == 0)  /* no luck at all - ret already set */
-               kfree(cam->sb_bufs);
-       req->count = cam->n_sbufs;  /* In case of partial success */
-
-  out:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-static int cafe_vidioc_querybuf(struct file *filp, void *priv,
-               struct v4l2_buffer *buf)
-{
-       struct cafe_camera *cam = filp->private_data;
-       int ret = -EINVAL;
-
-       mutex_lock(&cam->s_mutex);
-       if (buf->index >= cam->n_sbufs)
-               goto out;
-       *buf = cam->sb_bufs[buf->index].v4lbuf;
-       ret = 0;
-  out:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-static int cafe_vidioc_qbuf(struct file *filp, void *priv,
-               struct v4l2_buffer *buf)
-{
-       struct cafe_camera *cam = filp->private_data;
-       struct cafe_sio_buffer *sbuf;
-       int ret = -EINVAL;
-       unsigned long flags;
-
-       mutex_lock(&cam->s_mutex);
-       if (buf->index >= cam->n_sbufs)
-               goto out;
-       sbuf = cam->sb_bufs + buf->index;
-       if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) {
-               ret = 0; /* Already queued?? */
-               goto out;
-       }
-       if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) {
-               /* Spec doesn't say anything, seems appropriate tho */
-               ret = -EBUSY;
-               goto out;
-       }
-       sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       list_add(&sbuf->list, &cam->sb_avail);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-       ret = 0;
-  out:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-static int cafe_vidioc_dqbuf(struct file *filp, void *priv,
-               struct v4l2_buffer *buf)
-{
-       struct cafe_camera *cam = filp->private_data;
-       struct cafe_sio_buffer *sbuf;
-       int ret = -EINVAL;
-       unsigned long flags;
-
-       mutex_lock(&cam->s_mutex);
-       if (cam->state != S_STREAMING)
-               goto out_unlock;
-       if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) {
-               ret = -EAGAIN;
-               goto out_unlock;
-       }
-
-       while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) {
-               mutex_unlock(&cam->s_mutex);
-               if (wait_event_interruptible(cam->iowait,
-                                               !list_empty(&cam->sb_full))) {
-                       ret = -ERESTARTSYS;
-                       goto out;
-               }
-               mutex_lock(&cam->s_mutex);
-       }
-
-       if (cam->state != S_STREAMING)
-               ret = -EINTR;
-       else {
-               spin_lock_irqsave(&cam->dev_lock, flags);
-               /* Should probably recheck !list_empty() here */
-               sbuf = list_entry(cam->sb_full.next,
-                               struct cafe_sio_buffer, list);
-               list_del_init(&sbuf->list);
-               spin_unlock_irqrestore(&cam->dev_lock, flags);
-               sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
-               *buf = sbuf->v4lbuf;
-               ret = 0;
-       }
-
-  out_unlock:
-       mutex_unlock(&cam->s_mutex);
-  out:
-       return ret;
-}
-
-
-
-static void cafe_v4l_vm_open(struct vm_area_struct *vma)
-{
-       struct cafe_sio_buffer *sbuf = vma->vm_private_data;
-       /*
-        * Locking: done under mmap_sem, so we don't need to
-        * go back to the camera lock here.
-        */
-       sbuf->mapcount++;
-}
-
-
-static void cafe_v4l_vm_close(struct vm_area_struct *vma)
-{
-       struct cafe_sio_buffer *sbuf = vma->vm_private_data;
-
-       mutex_lock(&sbuf->cam->s_mutex);
-       sbuf->mapcount--;
-       /* Docs say we should stop I/O too... */
-       if (sbuf->mapcount == 0)
-               sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
-       mutex_unlock(&sbuf->cam->s_mutex);
-}
-
-static const struct vm_operations_struct cafe_v4l_vm_ops = {
-       .open = cafe_v4l_vm_open,
-       .close = cafe_v4l_vm_close
-};
-
-
-static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
-{
-       struct cafe_camera *cam = filp->private_data;
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-       int ret = -EINVAL;
-       int i;
-       struct cafe_sio_buffer *sbuf = NULL;
-
-       if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
-               return -EINVAL;
-       /*
-        * Find the buffer they are looking for.
-        */
-       mutex_lock(&cam->s_mutex);
-       for (i = 0; i < cam->n_sbufs; i++)
-               if (cam->sb_bufs[i].v4lbuf.m.offset == offset) {
-                       sbuf = cam->sb_bufs + i;
-                       break;
-               }
-       if (sbuf == NULL)
-               goto out;
-
-       ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
-       if (ret)
-               goto out;
-       vma->vm_flags |= VM_DONTEXPAND;
-       vma->vm_private_data = sbuf;
-       vma->vm_ops = &cafe_v4l_vm_ops;
-       sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
-       cafe_v4l_vm_open(vma);
-       ret = 0;
-  out:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-
-static int cafe_v4l_open(struct file *filp)
-{
-       struct cafe_camera *cam = video_drvdata(filp);
-
-       filp->private_data = cam;
-
-       mutex_lock(&cam->s_mutex);
-       if (cam->users == 0) {
-               cafe_ctlr_power_up(cam);
-               __cafe_cam_reset(cam);
-               cafe_set_config_needed(cam, 1);
-       /* FIXME make sure this is complete */
-       }
-       (cam->users)++;
-       mutex_unlock(&cam->s_mutex);
-       return 0;
-}
-
-
-static int cafe_v4l_release(struct file *filp)
-{
-       struct cafe_camera *cam = filp->private_data;
-
-       mutex_lock(&cam->s_mutex);
-       (cam->users)--;
-       if (filp == cam->owner) {
-               cafe_ctlr_stop_dma(cam);
-               cafe_free_sio_buffers(cam);
-               cam->owner = NULL;
-       }
-       if (cam->users == 0) {
-               cafe_ctlr_power_down(cam);
-               if (alloc_bufs_at_read)
-                       cafe_free_dma_bufs(cam);
-       }
-       mutex_unlock(&cam->s_mutex);
-       return 0;
-}
-
-
-
-static unsigned int cafe_v4l_poll(struct file *filp,
-               struct poll_table_struct *pt)
-{
-       struct cafe_camera *cam = filp->private_data;
-
-       poll_wait(filp, &cam->iowait, pt);
-       if (cam->next_buf >= 0)
-               return POLLIN | POLLRDNORM;
-       return 0;
-}
-
-
-
-static int cafe_vidioc_queryctrl(struct file *filp, void *priv,
-               struct v4l2_queryctrl *qc)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, core, queryctrl, qc);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-static int cafe_vidioc_g_ctrl(struct file *filp, void *priv,
-               struct v4l2_control *ctrl)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, core, g_ctrl, ctrl);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-static int cafe_vidioc_s_ctrl(struct file *filp, void *priv,
-               struct v4l2_control *ctrl)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, core, s_ctrl, ctrl);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-
-
-
-
-static int cafe_vidioc_querycap(struct file *file, void *priv,
-               struct v4l2_capability *cap)
-{
-       strcpy(cap->driver, "cafe_ccic");
-       strcpy(cap->card, "cafe_ccic");
-       cap->version = CAFE_VERSION;
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-               V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
-       return 0;
-}
-
-
-/*
- * The default format we use until somebody says otherwise.
- */
-static const struct v4l2_pix_format cafe_def_pix_format = {
-       .width          = VGA_WIDTH,
-       .height         = VGA_HEIGHT,
-       .pixelformat    = V4L2_PIX_FMT_YUYV,
-       .field          = V4L2_FIELD_NONE,
-       .bytesperline   = VGA_WIDTH*2,
-       .sizeimage      = VGA_WIDTH*VGA_HEIGHT*2,
-};
-
-static const enum v4l2_mbus_pixelcode cafe_def_mbus_code =
-                                       V4L2_MBUS_FMT_YUYV8_2X8;
-
-static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
-               void *priv, struct v4l2_fmtdesc *fmt)
-{
-       if (fmt->index >= N_CAFE_FMTS)
-               return -EINVAL;
-       strlcpy(fmt->description, cafe_formats[fmt->index].desc,
-                       sizeof(fmt->description));
-       fmt->pixelformat = cafe_formats[fmt->index].pixelformat;
-       return 0;
-}
-
-static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
-               struct v4l2_format *fmt)
-{
-       struct cafe_camera *cam = priv;
-       struct cafe_format_struct *f;
-       struct v4l2_pix_format *pix = &fmt->fmt.pix;
-       struct v4l2_mbus_framefmt mbus_fmt;
-       int ret;
-
-       f = cafe_find_format(pix->pixelformat);
-       pix->pixelformat = f->pixelformat;
-       v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code);
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
-       mutex_unlock(&cam->s_mutex);
-       v4l2_fill_pix_format(pix, &mbus_fmt);
-       pix->bytesperline = pix->width * f->bpp;
-       pix->sizeimage = pix->height * pix->bytesperline;
-       return ret;
-}
-
-static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
-               struct v4l2_format *fmt)
-{
-       struct cafe_camera *cam = priv;
-       struct cafe_format_struct *f;
-       int ret;
-
-       /*
-        * Can't do anything if the device is not idle
-        * Also can't if there are streaming buffers in place.
-        */
-       if (cam->state != S_IDLE || cam->n_sbufs > 0)
-               return -EBUSY;
-
-       f = cafe_find_format(fmt->fmt.pix.pixelformat);
-
-       /*
-        * See if the formatting works in principle.
-        */
-       ret = cafe_vidioc_try_fmt_vid_cap(filp, priv, fmt);
-       if (ret)
-               return ret;
-       /*
-        * Now we start to change things for real, so let's do it
-        * under lock.
-        */
-       mutex_lock(&cam->s_mutex);
-       cam->pix_format = fmt->fmt.pix;
-       cam->mbus_code = f->mbus_code;
-
-       /*
-        * Make sure we have appropriate DMA buffers.
-        */
-       ret = -ENOMEM;
-       if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)
-               cafe_free_dma_bufs(cam);
-       if (cam->nbufs == 0) {
-               if (cafe_alloc_dma_bufs(cam, 0))
-                       goto out;
-       }
-       /*
-        * It looks like this might work, so let's program the sensor.
-        */
-       ret = cafe_cam_configure(cam);
-       if (! ret)
-               ret = cafe_ctlr_configure(cam);
-  out:
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-/*
- * Return our stored notion of how the camera is/should be configured.
- * The V4l2 spec wants us to be smarter, and actually get this from
- * the camera (and not mess with it at open time).  Someday.
- */
-static int cafe_vidioc_g_fmt_vid_cap(struct file *filp, void *priv,
-               struct v4l2_format *f)
-{
-       struct cafe_camera *cam = priv;
-
-       f->fmt.pix = cam->pix_format;
-       return 0;
-}
-
-/*
- * We only have one input - the sensor - so minimize the nonsense here.
- */
-static int cafe_vidioc_enum_input(struct file *filp, void *priv,
-               struct v4l2_input *input)
-{
-       if (input->index != 0)
-               return -EINVAL;
-
-       input->type = V4L2_INPUT_TYPE_CAMERA;
-       input->std = V4L2_STD_ALL; /* Not sure what should go here */
-       strcpy(input->name, "Camera");
-       return 0;
-}
-
-static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       if (i != 0)
-               return -EINVAL;
-       return 0;
-}
-
-/* from vivi.c */
-static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
-{
-       return 0;
-}
-
-/*
- * G/S_PARM.  Most of this is done by the sensor, but we are
- * the level which controls the number of read buffers.
- */
-static int cafe_vidioc_g_parm(struct file *filp, void *priv,
-               struct v4l2_streamparm *parms)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, g_parm, parms);
-       mutex_unlock(&cam->s_mutex);
-       parms->parm.capture.readbuffers = n_dma_bufs;
-       return ret;
-}
-
-static int cafe_vidioc_s_parm(struct file *filp, void *priv,
-               struct v4l2_streamparm *parms)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, s_parm, parms);
-       mutex_unlock(&cam->s_mutex);
-       parms->parm.capture.readbuffers = n_dma_bufs;
-       return ret;
-}
-
-static int cafe_vidioc_g_chip_ident(struct file *file, void *priv,
-               struct v4l2_dbg_chip_ident *chip)
-{
-       struct cafe_camera *cam = priv;
-
-       chip->ident = V4L2_IDENT_NONE;
-       chip->revision = 0;
-       if (v4l2_chip_match_host(&chip->match)) {
-               chip->ident = V4L2_IDENT_CAFE;
-               return 0;
-       }
-       return sensor_call(cam, core, g_chip_ident, chip);
-}
-
-static int cafe_vidioc_enum_framesizes(struct file *filp, void *priv,
-               struct v4l2_frmsizeenum *sizes)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, enum_framesizes, sizes);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-static int cafe_vidioc_enum_frameintervals(struct file *filp, void *priv,
-               struct v4l2_frmivalenum *interval)
-{
-       struct cafe_camera *cam = priv;
-       int ret;
-
-       mutex_lock(&cam->s_mutex);
-       ret = sensor_call(cam, video, enum_frameintervals, interval);
-       mutex_unlock(&cam->s_mutex);
-       return ret;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int cafe_vidioc_g_register(struct file *file, void *priv,
-               struct v4l2_dbg_register *reg)
-{
-       struct cafe_camera *cam = priv;
-
-       if (v4l2_chip_match_host(&reg->match)) {
-               reg->val = cafe_reg_read(cam, reg->reg);
-               reg->size = 4;
-               return 0;
-       }
-       return sensor_call(cam, core, g_register, reg);
-}
-
-static int cafe_vidioc_s_register(struct file *file, void *priv,
-               struct v4l2_dbg_register *reg)
-{
-       struct cafe_camera *cam = priv;
-
-       if (v4l2_chip_match_host(&reg->match)) {
-               cafe_reg_write(cam, reg->reg, reg->val);
-               return 0;
-       }
-       return sensor_call(cam, core, s_register, reg);
-}
-#endif
-
-/*
- * This template device holds all of those v4l2 methods; we
- * clone it for specific real devices.
- */
-
-static const struct v4l2_file_operations cafe_v4l_fops = {
-       .owner = THIS_MODULE,
-       .open = cafe_v4l_open,
-       .release = cafe_v4l_release,
-       .read = cafe_v4l_read,
-       .poll = cafe_v4l_poll,
-       .mmap = cafe_v4l_mmap,
-       .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
-       .vidioc_querycap        = cafe_vidioc_querycap,
-       .vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap,
-       .vidioc_try_fmt_vid_cap = cafe_vidioc_try_fmt_vid_cap,
-       .vidioc_s_fmt_vid_cap   = cafe_vidioc_s_fmt_vid_cap,
-       .vidioc_g_fmt_vid_cap   = cafe_vidioc_g_fmt_vid_cap,
-       .vidioc_enum_input      = cafe_vidioc_enum_input,
-       .vidioc_g_input         = cafe_vidioc_g_input,
-       .vidioc_s_input         = cafe_vidioc_s_input,
-       .vidioc_s_std           = cafe_vidioc_s_std,
-       .vidioc_reqbufs         = cafe_vidioc_reqbufs,
-       .vidioc_querybuf        = cafe_vidioc_querybuf,
-       .vidioc_qbuf            = cafe_vidioc_qbuf,
-       .vidioc_dqbuf           = cafe_vidioc_dqbuf,
-       .vidioc_streamon        = cafe_vidioc_streamon,
-       .vidioc_streamoff       = cafe_vidioc_streamoff,
-       .vidioc_queryctrl       = cafe_vidioc_queryctrl,
-       .vidioc_g_ctrl          = cafe_vidioc_g_ctrl,
-       .vidioc_s_ctrl          = cafe_vidioc_s_ctrl,
-       .vidioc_g_parm          = cafe_vidioc_g_parm,
-       .vidioc_s_parm          = cafe_vidioc_s_parm,
-       .vidioc_enum_framesizes = cafe_vidioc_enum_framesizes,
-       .vidioc_enum_frameintervals = cafe_vidioc_enum_frameintervals,
-       .vidioc_g_chip_ident    = cafe_vidioc_g_chip_ident,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .vidioc_g_register      = cafe_vidioc_g_register,
-       .vidioc_s_register      = cafe_vidioc_s_register,
-#endif
-};
-
-static struct video_device cafe_v4l_template = {
-       .name = "cafe",
-       .tvnorms = V4L2_STD_NTSC_M,
-       .current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */
-
-       .fops = &cafe_v4l_fops,
-       .ioctl_ops = &cafe_v4l_ioctl_ops,
-       .release = video_device_release_empty,
-};
-
-
-/* ---------------------------------------------------------------------- */
-/*
- * Interrupt handler stuff
- */
-
-
-
-static void cafe_frame_tasklet(unsigned long data)
-{
-       struct cafe_camera *cam = (struct cafe_camera *) data;
-       int i;
-       unsigned long flags;
-       struct cafe_sio_buffer *sbuf;
-
-       spin_lock_irqsave(&cam->dev_lock, flags);
-       for (i = 0; i < cam->nbufs; i++) {
-               int bufno = cam->next_buf;
-               if (bufno < 0) {  /* "will never happen" */
-                       cam_err(cam, "No valid bufs in tasklet!\n");
-                       break;
-               }
-               if (++(cam->next_buf) >= cam->nbufs)
-                       cam->next_buf = 0;
-               if (! test_bit(bufno, &cam->flags))
-                       continue;
-               if (list_empty(&cam->sb_avail))
-                       break;  /* Leave it valid, hope for better later */
-               clear_bit(bufno, &cam->flags);
-               sbuf = list_entry(cam->sb_avail.next,
-                               struct cafe_sio_buffer, list);
-               /*
-                * Drop the lock during the big copy.  This *should* be safe...
-                */
-               spin_unlock_irqrestore(&cam->dev_lock, flags);
-               memcpy(sbuf->buffer, cam->dma_bufs[bufno],
-                               cam->pix_format.sizeimage);
-               sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;
-               sbuf->v4lbuf.sequence = cam->buf_seq[bufno];
-               sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
-               sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
-               spin_lock_irqsave(&cam->dev_lock, flags);
-               list_move_tail(&sbuf->list, &cam->sb_full);
-       }
-       if (! list_empty(&cam->sb_full))
-               wake_up(&cam->iowait);
-       spin_unlock_irqrestore(&cam->dev_lock, flags);
-}
-
-
-
-static void cafe_frame_complete(struct cafe_camera *cam, int frame)
-{
-       /*
-        * Basic frame housekeeping.
-        */
-       if (test_bit(frame, &cam->flags) && printk_ratelimit())
-               cam_err(cam, "Frame overrun on %d, frames lost\n", frame);
-       set_bit(frame, &cam->flags);
-       clear_bit(CF_DMA_ACTIVE, &cam->flags);
-       if (cam->next_buf < 0)
-               cam->next_buf = frame;
-       cam->buf_seq[frame] = ++(cam->sequence);
-
-       switch (cam->state) {
-       /*
-        * If in single read mode, try going speculative.
-        */
-           case S_SINGLEREAD:
-               cam->state = S_SPECREAD;
-               cam->specframes = 0;
-               wake_up(&cam->iowait);
-               break;
-
-       /*
-        * If we are already doing speculative reads, and nobody is
-        * reading them, just stop.
-        */
-           case S_SPECREAD:
-               if (++(cam->specframes) >= cam->nbufs) {
-                       cafe_ctlr_stop(cam);
-                       cafe_ctlr_irq_disable(cam);
-                       cam->state = S_IDLE;
-               }
-               wake_up(&cam->iowait);
-               break;
-       /*
-        * For the streaming case, we defer the real work to the
-        * camera tasklet.
-        *
-        * FIXME: if the application is not consuming the buffers,
-        * we should eventually put things on hold and restart in
-        * vidioc_dqbuf().
-        */
-           case S_STREAMING:
-               tasklet_schedule(&cam->s_tasklet);
-               break;
-
-           default:
-               cam_err(cam, "Frame interrupt in non-operational state\n");
-               break;
-       }
-}
-
-
-
-
-static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs)
-{
-       unsigned int frame;
-
-       cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */
-       /*
-        * Handle any frame completions.  There really should
-        * not be more than one of these, or we have fallen
-        * far behind.
-        */
-       for (frame = 0; frame < cam->nbufs; frame++)
-               if (irqs & (IRQ_EOF0 << frame))
-                       cafe_frame_complete(cam, frame);
-       /*
-        * If a frame starts, note that we have DMA active.  This
-        * code assumes that we won't get multiple frame interrupts
-        * at once; may want to rethink that.
-        */
-       if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2))
-               set_bit(CF_DMA_ACTIVE, &cam->flags);
-}
-
-
-
-static irqreturn_t cafe_irq(int irq, void *data)
-{
-       struct cafe_camera *cam = data;
-       unsigned int irqs;
-
-       spin_lock(&cam->dev_lock);
-       irqs = cafe_reg_read(cam, REG_IRQSTAT);
-       if ((irqs & ALLIRQS) == 0) {
-               spin_unlock(&cam->dev_lock);
-               return IRQ_NONE;
-       }
-       if (irqs & FRAMEIRQS)
-               cafe_frame_irq(cam, irqs);
-       if (irqs & TWSIIRQS) {
-               cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS);
-               wake_up(&cam->smbus_wait);
-       }
-       spin_unlock(&cam->dev_lock);
-       return IRQ_HANDLED;
-}
-
-
-/* -------------------------------------------------------------------------- */
-/*
- * PCI interface stuff.
- */
-
-static const struct dmi_system_id olpc_xo1_dmi[] = {
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "OLPC"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "XO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "1"),
-               },
-       },
-       { }
-};
-
-static int cafe_pci_probe(struct pci_dev *pdev,
-               const struct pci_device_id *id)
-{
-       int ret;
-       struct cafe_camera *cam;
-       struct ov7670_config sensor_cfg = {
-               /* This controller only does SMBUS */
-               .use_smbus = true,
-
-               /*
-                * Exclude QCIF mode, because it only captures a tiny portion
-                * of the sensor FOV
-                */
-               .min_width = 320,
-               .min_height = 240,
-       };
-       struct i2c_board_info ov7670_info = {
-               .type = "ov7670",
-               .addr = 0x42,
-               .platform_data = &sensor_cfg,
-       };
-
-       /*
-        * Start putting together one of our big camera structures.
-        */
-       ret = -ENOMEM;
-       cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
-       if (cam == NULL)
-               goto out;
-       ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
-       if (ret)
-               goto out_free;
-
-       mutex_init(&cam->s_mutex);
-       spin_lock_init(&cam->dev_lock);
-       cam->state = S_NOTREADY;
-       cafe_set_config_needed(cam, 1);
-       init_waitqueue_head(&cam->smbus_wait);
-       init_waitqueue_head(&cam->iowait);
-       cam->pdev = pdev;
-       cam->pix_format = cafe_def_pix_format;
-       cam->mbus_code = cafe_def_mbus_code;
-       INIT_LIST_HEAD(&cam->dev_list);
-       INIT_LIST_HEAD(&cam->sb_avail);
-       INIT_LIST_HEAD(&cam->sb_full);
-       tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam);
-       /*
-        * Get set up on the PCI bus.
-        */
-       ret = pci_enable_device(pdev);
-       if (ret)
-               goto out_unreg;
-       pci_set_master(pdev);
-
-       ret = -EIO;
-       cam->regs = pci_iomap(pdev, 0, 0);
-       if (! cam->regs) {
-               printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
-               goto out_unreg;
-       }
-       ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
-       if (ret)
-               goto out_iounmap;
-       /*
-        * Initialize the controller and leave it powered up.  It will
-        * stay that way until the sensor driver shows up.
-        */
-       cafe_ctlr_init(cam);
-       cafe_ctlr_power_up(cam);
-       /*
-        * Set up I2C/SMBUS communications.  We have to drop the mutex here
-        * because the sensor could attach in this call chain, leading to
-        * unsightly deadlocks.
-        */
-       ret = cafe_smbus_setup(cam);
-       if (ret)
-               goto out_freeirq;
-
-       /* Apply XO-1 clock speed */
-       if (dmi_check_system(olpc_xo1_dmi))
-               sensor_cfg.clock_speed = 45;
-
-       cam->sensor_addr = ov7670_info.addr;
-       cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, &cam->i2c_adapter,
-                       &ov7670_info, NULL);
-       if (cam->sensor == NULL) {
-               ret = -ENODEV;
-               goto out_smbus;
-       }
-
-       ret = cafe_cam_init(cam);
-       if (ret)
-               goto out_smbus;
-
-       /*
-        * Get the v4l2 setup done.
-        */
-       mutex_lock(&cam->s_mutex);
-       cam->vdev = cafe_v4l_template;
-       cam->vdev.debug = 0;
-/*     cam->vdev.debug = V4L2_DEBUG_IOCTL_ARG;*/
-       cam->vdev.v4l2_dev = &cam->v4l2_dev;
-       ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
-       if (ret)
-               goto out_unlock;
-       video_set_drvdata(&cam->vdev, cam);
-
-       /*
-        * If so requested, try to get our DMA buffers now.
-        */
-       if (!alloc_bufs_at_read) {
-               if (cafe_alloc_dma_bufs(cam, 1))
-                       cam_warn(cam, "Unable to alloc DMA buffers at load"
-                                       " will try again later.");
-       }
-
-       mutex_unlock(&cam->s_mutex);
-       return 0;
-
-out_unlock:
-       mutex_unlock(&cam->s_mutex);
-out_smbus:
-       cafe_smbus_shutdown(cam);
-out_freeirq:
-       cafe_ctlr_power_down(cam);
-       free_irq(pdev->irq, cam);
-out_iounmap:
-       pci_iounmap(pdev, cam->regs);
-out_free:
-       v4l2_device_unregister(&cam->v4l2_dev);
-out_unreg:
-       kfree(cam);
-out:
-       return ret;
-}
-
-
-/*
- * Shut down an initialized device
- */
-static void cafe_shutdown(struct cafe_camera *cam)
-{
-/* FIXME: Make sure we take care of everything here */
-       if (cam->n_sbufs > 0)
-               /* What if they are still mapped?  Shouldn't be, but... */
-               cafe_free_sio_buffers(cam);
-       cafe_ctlr_stop_dma(cam);
-       cafe_ctlr_power_down(cam);
-       cafe_smbus_shutdown(cam);
-       cafe_free_dma_bufs(cam);
-       free_irq(cam->pdev->irq, cam);
-       pci_iounmap(cam->pdev, cam->regs);
-       video_unregister_device(&cam->vdev);
-}
-
-
-static void cafe_pci_remove(struct pci_dev *pdev)
-{
-       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
-       struct cafe_camera *cam = to_cam(v4l2_dev);
-
-       if (cam == NULL) {
-               printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
-               return;
-       }
-       mutex_lock(&cam->s_mutex);
-       if (cam->users > 0)
-               cam_warn(cam, "Removing a device with users!\n");
-       cafe_shutdown(cam);
-       v4l2_device_unregister(&cam->v4l2_dev);
-       kfree(cam);
-/* No unlock - it no longer exists */
-}
-
-
-#ifdef CONFIG_PM
-/*
- * Basic power management.
- */
-static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
-       struct cafe_camera *cam = to_cam(v4l2_dev);
-       int ret;
-       enum cafe_state cstate;
-
-       ret = pci_save_state(pdev);
-       if (ret)
-               return ret;
-       cstate = cam->state; /* HACK - stop_dma sets to idle */
-       cafe_ctlr_stop_dma(cam);
-       cafe_ctlr_power_down(cam);
-       pci_disable_device(pdev);
-       cam->state = cstate;
-       return 0;
-}
-
-
-static int cafe_pci_resume(struct pci_dev *pdev)
-{
-       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
-       struct cafe_camera *cam = to_cam(v4l2_dev);
-       int ret = 0;
-
-       pci_restore_state(pdev);
-       ret = pci_enable_device(pdev);
-
-       if (ret) {
-               cam_warn(cam, "Unable to re-enable device on resume!\n");
-               return ret;
-       }
-       cafe_ctlr_init(cam);
-
-       mutex_lock(&cam->s_mutex);
-       if (cam->users > 0) {
-               cafe_ctlr_power_up(cam);
-               __cafe_cam_reset(cam);
-       } else {
-               cafe_ctlr_power_down(cam);
-       }
-       mutex_unlock(&cam->s_mutex);
-
-       set_bit(CF_CONFIG_NEEDED, &cam->flags);
-       if (cam->state == S_SPECREAD)
-               cam->state = S_IDLE;  /* Don't bother restarting */
-       else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING)
-               ret = cafe_read_setup(cam, cam->state);
-       return ret;
-}
-
-#endif  /* CONFIG_PM */
-
-
-static struct pci_device_id cafe_ids[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL,
-                    PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, cafe_ids);
-
-static struct pci_driver cafe_pci_driver = {
-       .name = "cafe1000-ccic",
-       .id_table = cafe_ids,
-       .probe = cafe_pci_probe,
-       .remove = cafe_pci_remove,
-#ifdef CONFIG_PM
-       .suspend = cafe_pci_suspend,
-       .resume = cafe_pci_resume,
-#endif
-};
-
-
-
-
-static int __init cafe_init(void)
-{
-       int ret;
-
-       printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
-                       CAFE_VERSION);
-       ret = pci_register_driver(&cafe_pci_driver);
-       if (ret) {
-               printk(KERN_ERR "Unable to register cafe_ccic driver\n");
-               goto out;
-       }
-       ret = 0;
-
-  out:
-       return ret;
-}
-
-
-static void __exit cafe_exit(void)
-{
-       pci_unregister_driver(&cafe_pci_driver);
-}
-
-module_init(cafe_init);
-module_exit(cafe_exit);
index 6d6d1843791ce0a7ef880211b33f92c85bee4922..ab252188981b688605f8dd1c852bce9422b09122 100644 (file)
@@ -31,7 +31,6 @@
 #ifndef __CPIA2_H__
 #define __CPIA2_H__
 
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <linux/usb.h>
 /* define for verbose debug output */
 //#define _CPIA2_DEBUG_
 
-#define CPIA2_MAJ_VER  3
-#define CPIA2_MIN_VER   0
-#define CPIA2_PATCH_VER        0
-
 /***
  * Image defines
  ***/
index 40eb6326e48a8ab95ca7c476999772bd3e76ff3b..077eb1db80a1b4d926c77cac24c979ab255982a0 100644 (file)
@@ -29,8 +29,7 @@
  *             Alan Cox <alan@lxorguk.ukuu.org.uk>
  ****************************************************************************/
 
-#include <linux/version.h>
-
+#define CPIA_VERSION "3.0.1"
 
 #include <linux/module.h>
 #include <linux/time.h>
@@ -80,6 +79,7 @@ MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
 MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
 MODULE_SUPPORTED_DEVICE("video");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CPIA_VERSION);
 
 #define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
 
@@ -465,9 +465,6 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
        if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
                memset(vc->bus_info,0, sizeof(vc->bus_info));
 
-       vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER,
-                                    CPIA2_PATCH_VER);
-
        vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
                           V4L2_CAP_READWRITE |
                           V4L2_CAP_STREAMING;
@@ -1558,8 +1555,8 @@ static void __init check_parameters(void)
  *****************************************************************************/
 static int __init cpia2_init(void)
 {
-       LOG("%s v%d.%d.%d\n",
-           ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER);
+       LOG("%s v%s\n",
+           ABOUT, CPIA_VERSION);
        check_parameters();
        cpia2_usb_init();
        return 0;
@@ -1579,4 +1576,3 @@ static void __exit cpia2_exit(void)
 
 module_init(cpia2_init);
 module_exit(cpia2_exit);
-
index d50d69da387b5d0ea30fb6be335c7fb23523e55b..a1e6c2a32478225ef0860f61ea1688f723ab2443 100644 (file)
@@ -192,6 +192,7 @@ static int snd_cx18_init(struct v4l2_device *v4l2_dev)
 err_exit_free:
        if (sc != NULL)
                snd_card_free(sc);
+       kfree(cxsc);
 err_exit:
        return ret;
 }
index 086427288de80417ced9c1a23299f7f2623bda06..1834207230607a5ce714ce1492b6855bb56bed44 100644 (file)
@@ -25,7 +25,6 @@
 #ifndef CX18_DRIVER_H
 #define CX18_DRIVER_H
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
index e80134f52ef5c3ba41b00a4d3751d4ba95db3365..afe0a29e7200b9cdbb21447f7f0d7a5256ed0c8f 100644 (file)
@@ -469,7 +469,6 @@ static int cx18_querycap(struct file *file, void *fh,
        strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
        snprintf(vcap->bus_info, sizeof(vcap->bus_info),
                 "PCI:%s", pci_name(cx->pci_dev));
-       vcap->version = CX18_DRIVER_VERSION;        /* version */
        vcap->capabilities = cx->v4l2_cap;          /* capabilities */
        return 0;
 }
index cd189b6bbe208ce401e0b596426b6215f783a612..fed48b6bb67b622b981532be129a5834ecdd8547 100644 (file)
 #define CX18_VERSION_H
 
 #define CX18_DRIVER_NAME "cx18"
-#define CX18_DRIVER_VERSION_MAJOR 1
-#define CX18_DRIVER_VERSION_MINOR 5
-#define CX18_DRIVER_VERSION_PATCHLEVEL 0
-
-#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
-#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
-       CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL)
+#define CX18_VERSION "1.5.1"
 
 #endif
index 8d7813415760e5f1cf753368f86b0f124e642b55..53ff26e7abf77036136b60f2a5520e41623fbd14 100644 (file)
@@ -355,6 +355,8 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
        case CX231XX_BOARD_HAUPPAUGE_EXETER:
        case CX231XX_BOARD_HAUPPAUGE_USBLIVE2:
        case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
                if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
                        while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
                                                FLD_PWRDN_ENABLE_PLL)) {
@@ -1733,6 +1735,8 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard)
                break;
        case CX231XX_BOARD_CNXT_RDE_253S:
        case CX231XX_BOARD_CNXT_RDU_253S:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
                func_mode = 0x01;
                break;
        default:
index 22703815a31fdfa506c6f8a6a72866dee907d1a7..53dae2a8272dc60569e8056803a436295175cd20 100644 (file)
@@ -387,6 +387,7 @@ struct cx231xx_board cx231xx_boards[] = {
                .norm = V4L2_STD_NTSC,
                .no_alt_vanc = 1,
                .external_av = 1,
+               .dont_use_port_3 = 1,
                .input = {{
                        .type = CX231XX_VMUX_COMPOSITE1,
                        .vmux = CX231XX_VIN_2_1,
@@ -532,6 +533,76 @@ struct cx231xx_board cx231xx_boards[] = {
                        .gpio = NULL,
                } },
        },
+       [CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL] = {
+               .name = "Hauppauge WinTV USB2 FM (PAL)",
+               .tuner_type = TUNER_NXP_TDA18271,
+               .tuner_addr = 0x60,
+               .tuner_gpio = RDE250_XCV_TUNER,
+               .tuner_sif_gpio = 0x05,
+               .tuner_scl_gpio = 0x1a,
+               .tuner_sda_gpio = 0x1b,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x0c,
+               .gpio_pin_status_mask = 0x4001000,
+               .tuner_i2c_master = 1,
+               .norm = V4L2_STD_PAL,
+
+               .input = {{
+                       .type = CX231XX_VMUX_TELEVISION,
+                       .vmux = CX231XX_VIN_3_1,
+                       .amux = CX231XX_AMUX_VIDEO,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_COMPOSITE1,
+                       .vmux = CX231XX_VIN_2_1,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_SVIDEO,
+                       .vmux = CX231XX_VIN_1_1 |
+                               (CX231XX_VIN_1_2 << 8) |
+                               CX25840_SVIDEO_ON,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               } },
+       },
+       [CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC] = {
+               .name = "Hauppauge WinTV USB2 FM (NTSC)",
+               .tuner_type = TUNER_NXP_TDA18271,
+               .tuner_addr = 0x60,
+               .tuner_gpio = RDE250_XCV_TUNER,
+               .tuner_sif_gpio = 0x05,
+               .tuner_scl_gpio = 0x1a,
+               .tuner_sda_gpio = 0x1b,
+               .decoder = CX231XX_AVDECODER,
+               .output_mode = OUT_MODE_VIP11,
+               .ctl_pin_status_mask = 0xFFFFFFC4,
+               .agc_analog_digital_select_gpio = 0x0c,
+               .gpio_pin_status_mask = 0x4001000,
+               .tuner_i2c_master = 1,
+               .norm = V4L2_STD_NTSC,
+
+               .input = {{
+                       .type = CX231XX_VMUX_TELEVISION,
+                       .vmux = CX231XX_VIN_3_1,
+                       .amux = CX231XX_AMUX_VIDEO,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_COMPOSITE1,
+                       .vmux = CX231XX_VIN_2_1,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               }, {
+                       .type = CX231XX_VMUX_SVIDEO,
+                       .vmux = CX231XX_VIN_1_1 |
+                               (CX231XX_VIN_1_2 << 8) |
+                               CX25840_SVIDEO_ON,
+                       .amux = CX231XX_AMUX_LINE_IN,
+                       .gpio = NULL,
+               } },
+       },
 };
 const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
 
@@ -553,6 +624,10 @@ struct usb_device_id cx231xx_id_table[] = {
         .driver_info = CX231XX_BOARD_CNXT_RDE_250},
        {USB_DEVICE(0x0572, 0x58A0),
         .driver_info = CX231XX_BOARD_CNXT_RDU_250},
+       {USB_DEVICE(0x2040, 0xb110),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL},
+       {USB_DEVICE(0x2040, 0xb111),
+        .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC},
        {USB_DEVICE(0x2040, 0xb120),
         .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
        {USB_DEVICE(0x2040, 0xb140),
@@ -1051,6 +1126,9 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        if (assoc_desc->bFirstInterface != ifnum) {
                cx231xx_err(DRIVER_NAME ": Not found "
                            "matching IAD interface\n");
+               cx231xx_devused &= ~(1 << nr);
+               kfree(dev);
+               dev = NULL;
                return -ENODEV;
        }
 
index abe500feb7dd8adad785380eaa1a86ad4b5d5440..d4457f9488eee6c6e06feb1dd7c7ef727d6b91b8 100644 (file)
@@ -742,6 +742,8 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
                case CX231XX_BOARD_CNXT_RDU_253S:
                case CX231XX_BOARD_HAUPPAUGE_EXETER:
                case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+               case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+               case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
                errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
                        break;
                default:
@@ -1381,6 +1383,8 @@ int cx231xx_dev_init(struct cx231xx *dev)
        case CX231XX_BOARD_CNXT_RDU_253S:
        case CX231XX_BOARD_HAUPPAUGE_EXETER:
        case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
+       case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
        errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
                break;
        default:
index a69c24d8db060c93f41f2085212304220de0a462..6e81f970dc7d8e35d48975e141c5e75fbfdf878f 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/bitmap.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
@@ -45,7 +44,7 @@
 #include "cx231xx.h"
 #include "cx231xx-vbi.h"
 
-#define CX231XX_VERSION_CODE            KERNEL_VERSION(0, 0, 1)
+#define CX231XX_VERSION "0.0.2"
 
 #define DRIVER_AUTHOR   "Srinivasa Deevi <srinivasa.deevi@conexant.com>"
 #define DRIVER_DESC     "Conexant cx231xx based USB video device driver"
@@ -70,6 +69,7 @@ do {\
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX231XX_VERSION);
 
 static unsigned int card[]     = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET };
@@ -1179,7 +1179,8 @@ static int vidioc_enum_input(struct file *file, void *priv,
 {
        struct cx231xx_fh *fh = priv;
        struct cx231xx *dev = fh->dev;
-       unsigned int n;
+       u32 gen_stat;
+       unsigned int ret, n;
 
        n = i->index;
        if (n >= MAX_CX231XX_INPUT)
@@ -1198,6 +1199,18 @@ static int vidioc_enum_input(struct file *file, void *priv,
 
        i->std = dev->vdev->tvnorms;
 
+       /* If they are asking about the active input, read signal status */
+       if (n == dev->video_input) {
+               ret = cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
+                                           GEN_STAT, 2, &gen_stat, 4);
+               if (ret > 0) {
+                       if ((gen_stat & FLD_VPRES) == 0x00)
+                               i->status |= V4L2_IN_ST_NO_SIGNAL;
+                       if ((gen_stat & FLD_HLOCK) == 0x00)
+                               i->status |= V4L2_IN_ST_NO_H_LOCK;
+               }
+       }
+
        return 0;
 }
 
@@ -1869,8 +1882,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
-       cap->version = CX231XX_VERSION_CODE;
-
        cap->capabilities = V4L2_CAP_VBI_CAPTURE |
 #if 0
                V4L2_CAP_SLICED_VBI_CAPTURE |
@@ -2057,7 +2068,6 @@ static int radio_querycap(struct file *file, void *priv,
        strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
-       cap->version = CX231XX_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
@@ -2570,11 +2580,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
 {
        int ret;
 
-       cx231xx_info("%s: v4l2 driver version %d.%d.%d\n",
-                    dev->name,
-                    (CX231XX_VERSION_CODE >> 16) & 0xff,
-                    (CX231XX_VERSION_CODE >> 8) & 0xff,
-                    CX231XX_VERSION_CODE & 0xff);
+       cx231xx_info("%s: v4l2 driver version %s\n",
+                    dev->name, CX231XX_VERSION);
 
        /* set default norm */
        /*dev->norm = cx231xx_video_template.current_norm; */
index 46dd8406781695d50d1855dabe5af90565ad89bd..2000bc64c49784af168855f9dfab150b078a6d48 100644 (file)
@@ -43,7 +43,7 @@
 #include "cx231xx-conf-reg.h"
 
 #define DRIVER_NAME                     "cx231xx"
-#define PWR_SLEEP_INTERVAL              5
+#define PWR_SLEEP_INTERVAL              10
 
 /* I2C addresses for control block in Cx231xx */
 #define     AFE_DEVICE_ADDRESS         0x60
@@ -67,6 +67,8 @@
 #define CX231XX_BOARD_PV_XCAPTURE_USB 11
 #define CX231XX_BOARD_KWORLD_UB430_USB_HYBRID 12
 #define CX231XX_BOARD_ICONBIT_U100 13
+#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL 14
+#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC 15
 
 /* Limits minimum and default number of buffers */
 #define CX231XX_MIN_BUF                 4
        V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
        V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_Nc   | \
        V4L2_STD_PAL_60 |  V4L2_STD_SECAM_L   |  V4L2_STD_SECAM_DK)
-#define CX231xx_VERSION_CODE KERNEL_VERSION(0, 0, 2)
 
 #define SLEEP_S5H1432    30
 #define CX23417_OSC_EN   8
index 678539b2acfa70dde346378c47332abaf857f5fd..1fa8927f0d36eecb3946b7c7c48467eb3d540640 100644 (file)
@@ -52,7 +52,6 @@
  * |  DATA7|  DATA6|  DATA5|  DATA4|  DATA3|  DATA2|  DATA1|  DATA0|
  * +-------+-------+-------+-------+-------+-------+-------+-------+
  */
-#include <linux/version.h>
 #include <media/videobuf-dma-sg.h>
 #include <media/videobuf-dvb.h>
 #include "altera-ci.h"
index 9a98dc55f6572fac82e0c6e0936d1af8a03218d9..67c4a59bd8825800cda0bd1e657c92673ab4c944 100644 (file)
@@ -1359,7 +1359,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
                sizeof(cap->card));
        sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-       cap->version = CX23885_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_READWRITE     |
index 934185cca758d7461e3bc96bead9f64db90625c0..76b7563de39c9eadec8a492a7e01ad77138e776c 100644 (file)
 #include "../../../staging/altera-stapl/altera.h"
 #include "cx23885.h"
 #include "tuner-xc2028.h"
+#include "netup-eeprom.h"
 #include "netup-init.h"
 #include "altera-ci.h"
+#include "xc4000.h"
 #include "xc5000.h"
 #include "cx23888-ir.h"
 
+static unsigned int netup_card_rev = 1;
+module_param(netup_card_rev, int, 0644);
+MODULE_PARM_DESC(netup_card_rev,
+               "NetUP Dual DVB-T/C CI card revision");
 static unsigned int enable_885_ir;
 module_param(enable_885_ir, int, 0644);
 MODULE_PARM_DESC(enable_885_ir,
@@ -175,6 +181,34 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "Leadtek Winfast PxDVR3200 H",
                .portc          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000] = {
+               .name           = "Leadtek Winfast PxDVR3200 H XC4000",
+               .porta          = CX23885_ANALOG_VIDEO,
+               .portc          = CX23885_MPEG_DVB,
+               .tuner_type     = TUNER_XC4000,
+               .tuner_addr     = 0x61,
+               .radio_type     = TUNER_XC4000,
+               .radio_addr     = 0x61,
+               .input          = {{
+                       .type   = CX23885_VMUX_TELEVISION,
+                       .vmux   = CX25840_VIN2_CH1 |
+                                 CX25840_VIN5_CH2 |
+                                 CX25840_NONE0_CH3,
+               }, {
+                       .type   = CX23885_VMUX_COMPOSITE1,
+                       .vmux   = CX25840_COMPOSITE1,
+               }, {
+                       .type   = CX23885_VMUX_SVIDEO,
+                       .vmux   = CX25840_SVIDEO_LUMA3 |
+                                 CX25840_SVIDEO_CHROMA4,
+               }, {
+                       .type   = CX23885_VMUX_COMPONENT,
+                       .vmux   = CX25840_VIN7_CH1 |
+                                 CX25840_VIN6_CH2 |
+                                 CX25840_VIN8_CH3 |
+                                 CX25840_COMPONENT_ON,
+               } },
+       },
        [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = {
                .name           = "Compro VideoMate E650F",
                .portc          = CX23885_MPEG_DVB,
@@ -432,6 +466,10 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x6681,
                .card      = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
+       }, {
+               .subvendor = 0x107d,
+               .subdevice = 0x6f39,
+               .card      = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000,
        }, {
                .subvendor = 0x185b,
                .subdevice = 0xe800,
@@ -749,6 +787,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
        case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
@@ -909,6 +948,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                cx_set(GP0_IO, 0x000f000f);
                break;
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
        case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
@@ -1097,12 +1137,19 @@ int cx23885_ir_init(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
        case CX23885_BOARD_HAUPPAUGE_HVR1200:
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
-       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
        case CX23885_BOARD_HAUPPAUGE_HVR1210:
                /* FIXME: Implement me */
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+               ret = cx23888_ir_probe(dev);
+               if (ret)
+                       break;
+               dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
+               v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+                                ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
                ret = cx23888_ir_probe(dev);
@@ -1156,6 +1203,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
 void cx23885_ir_fini(struct cx23885_dev *dev)
 {
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
                cx23885_irq_remove(dev, PCI_MSK_IR);
@@ -1199,6 +1247,7 @@ int netup_jtag_io(void *device, int tms, int tdi, int read_tdo)
 void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
 {
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
                if (dev->sd_ir)
@@ -1325,6 +1374,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
@@ -1353,10 +1403,12 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
        case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_MYGICA_X8506:
        case CX23885_BOARD_MAGICPRO_PROHDTVE2:
@@ -1383,6 +1435,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                const struct firmware *fw;
                const char *filename = "dvb-netup-altera-01.fw";
                char *action = "configure";
+               static struct netup_card_info cinfo;
                struct altera_config netup_config = {
                        .dev = dev,
                        .action = action,
@@ -1391,6 +1444,21 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 
                netup_initialize(dev);
 
+               netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+               if (netup_card_rev)
+                       cinfo.rev = netup_card_rev;
+
+               switch (cinfo.rev) {
+               case 0x4:
+                       filename = "dvb-netup-altera-04.fw";
+                       break;
+               default:
+                       filename = "dvb-netup-altera-01.fw";
+                       break;
+               }
+               printk(KERN_INFO "NetUP card rev=0x%x fw_filename=%s\n",
+                               cinfo.rev, filename);
+
                ret = request_firmware(&fw, filename, &dev->pci->dev);
                if (ret != 0)
                        printk(KERN_ERR "did not find the firmware file. (%s) "
index 419777a832ee2fd929bf0e087add45ad7d09e973..ee41a8882f58470db0f77057c318ca055bcb3802 100644 (file)
@@ -42,6 +42,7 @@
 MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX23885_VERSION);
 
 static unsigned int debug;
 module_param(debug, int, 0644);
@@ -2147,14 +2148,8 @@ static struct pci_driver cx23885_pci_driver = {
 
 static int __init cx23885_init(void)
 {
-       printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n",
-              (CX23885_VERSION_CODE >> 16) & 0xff,
-              (CX23885_VERSION_CODE >>  8) & 0xff,
-              CX23885_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx23885 driver version %s loaded\n",
+               CX23885_VERSION);
        return pci_register_driver(&cx23885_pci_driver);
 }
 
@@ -2165,5 +2160,3 @@ static void __exit cx23885_fini(void)
 
 module_init(cx23885_init);
 module_exit(cx23885_fini);
-
-/* ----------------------------------------------------------- */
index 3c315f94cc8512c33f6a43a264722411fcf43a93..aa83f07b1b0f7bac44c7b72f1893c9346fabecb0 100644 (file)
@@ -37,6 +37,7 @@
 #include "tda8290.h"
 #include "tda18271.h"
 #include "lgdt330x.h"
+#include "xc4000.h"
 #include "xc5000.h"
 #include "max2165.h"
 #include "tda10048.h"
@@ -921,6 +922,26 @@ static int dvb_register(struct cx23885_tsport *port)
                                fe->ops.tuner_ops.set_config(fe, &ctl);
                }
                break;
+       case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
+               i2c_bus = &dev->i2c_bus[0];
+
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
+                                              &dvico_fusionhdtv_xc3028,
+                                              &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       struct dvb_frontend     *fe;
+                       struct xc4000_config    cfg = {
+                               .i2c_address      = 0x61,
+                               .default_pm       = 0,
+                               .dvb_amplitude    = 134,
+                               .set_smoothedcvbs = 1,
+                               .if_khz           = 4560
+                       };
+
+                       fe = dvb_attach(xc4000_attach, fe0->dvb.frontend,
+                                       &dev->i2c_bus[1].i2c_adap, &cfg);
+               }
+               break;
        case CX23885_BOARD_TBS_6920:
                i2c_bus = &dev->i2c_bus[1];
 
@@ -1249,7 +1270,7 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
         * implement MFE support.
         */
        fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
-       if (fe0->dvb.frontend)
+       if (fe0 && fe0->dvb.frontend)
                videobuf_dvb_unregister_bus(&port->frontends);
 
        switch (port->dev->board) {
index e97cafd839846ed89d63e5ea0391af97ae990320..ce765e3f77bdf6b679ba1b56900035f4f38d51c2 100644 (file)
@@ -82,6 +82,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
                return;
 
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_TEVII_S470:
@@ -133,6 +134,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
 
        v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
@@ -229,6 +231,9 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev)
                v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
                v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
        }
+       flush_work_sync(&dev->cx25840_work);
+       flush_work_sync(&dev->ir_rx_work);
+       flush_work_sync(&dev->ir_tx_work);
 }
 
 static void cx23885_input_ir_close(struct rc_dev *rc)
@@ -257,6 +262,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
                return -ENODEV;
 
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
index ee57f6bedbe3dd186d4f3255d55a0e82d8f4d151..896bb32dbf0301c53863dfae3ae7ae4d8a123fc1 100644 (file)
@@ -1000,7 +1000,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, cx23885_boards[dev->board].name,
                sizeof(cap->card));
        sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
-       cap->version = CX23885_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_READWRITE     |
index c186473fc5706207c3abd529e994b549b44ced0b..d86bc0b1317baca5fdd32b23fb6a1401396c1000 100644 (file)
 #include "cx23885-reg.h"
 #include "media/cx2341x.h"
 
-#include <linux/version.h>
 #include <linux/mutex.h>
 
-#define CX23885_VERSION_CODE KERNEL_VERSION(0, 0, 2)
+#define CX23885_VERSION "0.0.3"
 
 #define UNSET (-1U)
 
@@ -86,6 +85,7 @@
 #define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28
 #define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID     29
 #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30
+#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
index 423c1af8a782473d21d6bb6eccfe97d3be9effb0..68d1240f493c98f9327858dd9170d75ee232c802 100644 (file)
@@ -113,6 +113,8 @@ MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Ricardo Cerqueira");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
+
 MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
                        "{{Conexant,23882},"
                        "{{Conexant,23883}");
@@ -973,14 +975,8 @@ static struct pci_driver cx88_audio_pci_driver = {
  */
 static int __init cx88_audio_init(void)
 {
-       printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
-              (CX88_VERSION_CODE >> 16) & 0xff,
-              (CX88_VERSION_CODE >>  8) & 0xff,
-              CX88_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx2388x alsa driver version %s loaded\n",
+              CX88_VERSION);
        return pci_register_driver(&cx88_audio_pci_driver);
 }
 
@@ -994,10 +990,3 @@ static void __exit cx88_audio_fini(void)
 
 module_init(cx88_audio_init);
 module_exit(cx88_audio_fini);
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 11e49bbc4a668e4b03e780ddf18649760927d58c..e46446a449c090c91dc43e4eeb1e34e2baf2c16f 100644 (file)
@@ -42,6 +42,7 @@
 MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
 MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
 
 static unsigned int mpegbufs = 32;
 module_param(mpegbufs,int,0644);
@@ -730,7 +731,6 @@ static int vidioc_querycap (struct file *file, void  *priv,
        strcpy(cap->driver, "cx88_blackbird");
        strlcpy(cap->card, core->board.name, sizeof(cap->card));
        sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-       cap->version = CX88_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_READWRITE     |
@@ -1368,14 +1368,8 @@ static struct cx8802_driver cx8802_blackbird_driver = {
 
 static int __init blackbird_init(void)
 {
-       printk(KERN_INFO "cx2388x blackbird driver version %d.%d.%d loaded\n",
-              (CX88_VERSION_CODE >> 16) & 0xff,
-              (CX88_VERSION_CODE >>  8) & 0xff,
-              CX88_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx2388x blackbird driver version %s loaded\n",
+              CX88_VERSION);
        return cx8802_register_driver(&cx8802_blackbird_driver);
 }
 
@@ -1389,11 +1383,3 @@ module_exit(blackbird_fini);
 
 module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644);
 MODULE_PARM_DESC(debug,"enable debug messages [video]");
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
index 27222c92b603cf140419f7ba1448a62e2cfa3c11..0d719faafd8aeb32e0a260d080622355d8fafa68 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "cx88.h"
 #include "tea5767.h"
+#include "xc4000.h"
 
 static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
 static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
@@ -2119,6 +2120,99 @@ static const struct cx88_board cx88_boards[] = {
                },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_WINFAST_DTV1800H_XC4000] = {
+               .name           = "Leadtek WinFast DTV1800 H (XC4000)",
+               .tuner_type     = TUNER_XC4000,
+               .radio_type     = TUNER_XC4000,
+               .tuner_addr     = 0x61,
+               .radio_addr     = 0x61,
+               /*
+                * GPIO setting
+                *
+                *  2: mute (0=off,1=on)
+                * 12: tuner reset pin
+                * 13: audio source (0=tuner audio,1=line in)
+                * 14: FM (0=on,1=off ???)
+                */
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6040,       /* pin 13 = 0, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               }},
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6000,       /* pin 13 = 0, pin 14 = 0 */
+                       .gpio2  = 0x0000,
+               },
+               .mpeg           = CX88_MPEG_DVB,
+       },
+       [CX88_BOARD_WINFAST_DTV2000H_PLUS] = {
+               .name           = "Leadtek WinFast DTV2000 H PLUS",
+               .tuner_type     = TUNER_XC4000,
+               .radio_type     = TUNER_XC4000,
+               .tuner_addr     = 0x61,
+               .radio_addr     = 0x61,
+               /*
+                * GPIO
+                *   2: 1: mute audio
+                *  12: 0: reset XC4000
+                *  13: 1: audio input is line in (0: tuner)
+                *  14: 0: FM radio
+                *  16: 0: RF input is cable
+                */
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0403,
+                       .gpio1  = 0xF0D7,
+                       .gpio2  = 0x0101,
+                       .gpio3  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_CABLE,
+                       .vmux   = 0,
+                       .gpio0  = 0x0403,
+                       .gpio1  = 0xF0D7,
+                       .gpio2  = 0x0100,
+                       .gpio3  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0403,       /* was 0x0407 */
+                       .gpio1  = 0xF0F7,
+                       .gpio2  = 0x0101,
+                       .gpio3  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0403,       /* was 0x0407 */
+                       .gpio1  = 0xF0F7,
+                       .gpio2  = 0x0101,
+                       .gpio3  = 0x0000,
+               }},
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x0403,
+                       .gpio1  = 0xF097,
+                       .gpio2  = 0x0100,
+                       .gpio3  = 0x0000,
+               },
+               .mpeg           = CX88_MPEG_DVB,
+       },
        [CX88_BOARD_PROF_7301] = {
                .name           = "Prof 7301 DVB-S/S2",
                .tuner_type     = UNSET,
@@ -2580,6 +2674,15 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x6654,
                .card      = CX88_BOARD_WINFAST_DTV1800H,
+       }, {
+               /* WinFast DTV1800 H with XC4000 tuner */
+               .subvendor = 0x107d,
+               .subdevice = 0x6f38,
+               .card      = CX88_BOARD_WINFAST_DTV1800H_XC4000,
+       }, {
+               .subvendor = 0x107d,
+               .subdevice = 0x6f42,
+               .card      = CX88_BOARD_WINFAST_DTV2000H_PLUS,
        }, {
                /* PVR2000 PAL Model [107d:6630] */
                .subvendor = 0x107d,
@@ -2846,6 +2949,23 @@ static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core,
        return -EINVAL;
 }
 
+static int cx88_xc4000_winfast2000h_plus_callback(struct cx88_core *core,
+                                                 int command, int arg)
+{
+       switch (command) {
+       case XC4000_TUNER_RESET:
+               /* GPIO 12 (xc4000 tuner reset) */
+               cx_set(MO_GP1_IO, 0x1010);
+               mdelay(50);
+               cx_clear(MO_GP1_IO, 0x10);
+               mdelay(75);
+               cx_set(MO_GP1_IO, 0x10);
+               mdelay(75);
+               return 0;
+       }
+       return -EINVAL;
+}
+
 /* ------------------------------------------------------------------- */
 /* some Divco specific stuff                                           */
 static int cx88_pv_8000gt_callback(struct cx88_core *core,
@@ -2948,6 +3068,19 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
        return -EINVAL;
 }
 
+static int cx88_xc4000_tuner_callback(struct cx88_core *core,
+                                     int command, int arg)
+{
+       /* Board-specific callbacks */
+       switch (core->boardnr) {
+       case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+               return cx88_xc4000_winfast2000h_plus_callback(core,
+                                                             command, arg);
+       }
+       return -EINVAL;
+}
+
 /* ----------------------------------------------------------------------- */
 /* Tuner callback function. Currently only needed for the Pinnacle        *
  * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both      *
@@ -3022,6 +3155,9 @@ int cx88_tuner_callback(void *priv, int component, int command, int arg)
                case TUNER_XC2028:
                        info_printk(core, "Calling XC2028/3028 callback\n");
                        return cx88_xc2028_tuner_callback(core, command, arg);
+               case TUNER_XC4000:
+                       info_printk(core, "Calling XC4000 callback\n");
+                       return cx88_xc4000_tuner_callback(core, command, arg);
                case TUNER_XC5000:
                        info_printk(core, "Calling XC5000 callback\n");
                        return cx88_xc5000_tuner_callback(core, command, arg);
@@ -3109,13 +3245,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
 
        case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
        case CX88_BOARD_WINFAST_DTV1800H:
-               /* GPIO 12 (xc3028 tuner reset) */
-               cx_set(MO_GP1_IO, 0x1010);
-               mdelay(50);
-               cx_clear(MO_GP1_IO, 0x10);
-               mdelay(50);
-               cx_set(MO_GP1_IO, 0x10);
-               mdelay(50);
+               cx88_xc3028_winfast1800h_callback(core, XC2028_TUNER_RESET, 0);
+               break;
+
+       case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+               cx88_xc4000_winfast2000h_plus_callback(core,
+                                                      XC4000_TUNER_RESET, 0);
                break;
 
        case CX88_BOARD_TWINHAN_VP1027_DVBS:
index 2e145f0a5fd99d7c3077c1ab47828db497737663..fbcaa1c5b09da7b43b7f54024a56c4ba7297e55f 100644 (file)
@@ -636,6 +636,9 @@ int cx88_reset(struct cx88_core *core)
        cx_write(MO_PCI_INTSTAT,   0xFFFFFFFF); // Clear PCI int
        cx_write(MO_INT1_STAT,     0xFFFFFFFF); // Clear RISC int
 
+       /* set default notch filter */
+       cx_andor(MO_HTOTAL, 0x1800, (HLNotchFilter4xFsc << 11));
+
        /* Reset on-board parts */
        cx_write(MO_SRST_IO, 0);
        msleep(10);
@@ -759,8 +762,8 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
        if (nocomb)
                value |= (3 << 5); // disable comb filter
 
-       cx_write(MO_FILTER_EVEN,  value);
-       cx_write(MO_FILTER_ODD,   value);
+       cx_andor(MO_FILTER_EVEN,  0x7ffc7f, value); /* preserve PEAKEN, PSEL */
+       cx_andor(MO_FILTER_ODD,   0x7ffc7f, value);
        dprintk(1,"set_scale: filter  0x%04x\n", value);
 
        return 0;
@@ -994,10 +997,10 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
        // htotal
        tmp64 = norm_htotal(norm) * (u64)vdec_clock;
        do_div(tmp64, fsc8);
-       htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11);
+       htotal = (u32)tmp64;
        dprintk(1,"set_tvnorm: MO_HTOTAL        0x%08x [old=0x%08x,htotal=%d]\n",
                htotal, cx_read(MO_HTOTAL), (u32)tmp64);
-       cx_write(MO_HTOTAL, htotal);
+       cx_andor(MO_HTOTAL, 0x07ff, htotal);
 
        // 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
index c69df7ebb6a7575f0478a34c7b41142aa83c4cc9..cf3d33ab541b8ee190dcd7fbdaefc6130895a002 100644 (file)
@@ -41,6 +41,7 @@
 #include "or51132.h"
 #include "lgdt330x.h"
 #include "s5h1409.h"
+#include "xc4000.h"
 #include "xc5000.h"
 #include "nxt200x.h"
 #include "cx24123.h"
@@ -63,6 +64,7 @@ MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
 
 static unsigned int debug;
 module_param(debug, int, 0644);
@@ -605,6 +607,39 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
        return 0;
 }
 
+static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg)
+{
+       struct dvb_frontend *fe;
+       struct videobuf_dvb_frontend *fe0 = NULL;
+
+       /* Get the first frontend */
+       fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+       if (!fe0)
+               return -EINVAL;
+
+       if (!fe0->dvb.frontend) {
+               printk(KERN_ERR "%s/2: dvb frontend not attached. "
+                               "Can't attach xc4000\n",
+                      dev->core->name);
+               return -EINVAL;
+       }
+
+       fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->core->i2c_adap,
+                       cfg);
+       if (!fe) {
+               printk(KERN_ERR "%s/2: xc4000 attach failed\n",
+                      dev->core->name);
+               dvb_frontend_detach(fe0->dvb.frontend);
+               dvb_unregister_frontend(fe0->dvb.frontend);
+               fe0->dvb.frontend = NULL;
+               return -EINVAL;
+       }
+
+       printk(KERN_INFO "%s/2: xc4000 attached\n", dev->core->name);
+
+       return 0;
+}
+
 static int cx24116_set_ts_param(struct dvb_frontend *fe,
        int is_punctured)
 {
@@ -1294,7 +1329,25 @@ static int dvb_register(struct cx8802_dev *dev)
                                goto frontend_detach;
                }
                break;
-        case CX88_BOARD_GENIATECH_X8000_MT:
+       case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
+                                              &cx88_pinnacle_hybrid_pctv,
+                                              &core->i2c_adap);
+               if (fe0->dvb.frontend) {
+                       struct xc4000_config cfg = {
+                               .i2c_address      = 0x61,
+                               .default_pm       = 0,
+                               .dvb_amplitude    = 134,
+                               .set_smoothedcvbs = 1,
+                               .if_khz           = 4560
+                       };
+                       fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+                       if (attach_xc4000(dev, &cfg) < 0)
+                               goto frontend_detach;
+               }
+               break;
+       case CX88_BOARD_GENIATECH_X8000_MT:
                dev->ts_gen_cntrl = 0x00;
 
                fe0->dvb.frontend = dvb_attach(zl10353_attach,
@@ -1577,6 +1630,11 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
                udelay(1000);
                break;
 
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
+               /* set RF input to AIR for DVB-T (GPIO 16) */
+               cx_write(MO_GP2_IO, 0x0101);
+               break;
+
        default:
                err = -ENODEV;
        }
@@ -1692,14 +1750,8 @@ static struct cx8802_driver cx8802_dvb_driver = {
 
 static int __init dvb_init(void)
 {
-       printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n",
-              (CX88_VERSION_CODE >> 16) & 0xff,
-              (CX88_VERSION_CODE >>  8) & 0xff,
-              CX88_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx88/2: cx2388x dvb driver version %s loaded\n",
+              CX88_VERSION);
        return cx8802_register_driver(&cx8802_dvb_driver);
 }
 
@@ -1710,10 +1762,3 @@ static void __exit dvb_fini(void)
 
 module_init(dvb_init);
 module_exit(dvb_fini);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * compile-command: "make DVB=1"
- * End:
- */
index 3f442003623d30494cf63632355bd35e174cc97c..e614201b5ed33b5994ec4528ece3574e7f90919d 100644 (file)
@@ -100,6 +100,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
                break;
        case CX88_BOARD_WINFAST_DTV1000:
        case CX88_BOARD_WINFAST_DTV1800H:
+       case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
        case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
                gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
                auxgpio = gpio;
@@ -289,6 +291,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_WINFAST_DTV2000H:
        case CX88_BOARD_WINFAST_DTV2000H_J:
        case CX88_BOARD_WINFAST_DTV1800H:
+       case CX88_BOARD_WINFAST_DTV1800H_XC4000:
+       case CX88_BOARD_WINFAST_DTV2000H_PLUS:
                ir_codes = RC_MAP_WINFAST;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
index 1a7b983f82976eeb5b66a0da1fc6316104faee45..cd5386ee210cf02f79fbfb4abaeb86895e88ab99 100644 (file)
@@ -39,6 +39,7 @@ MODULE_AUTHOR("Jelle Foks <jelle@foks.us>");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
 
 static unsigned int debug;
 module_param(debug,int,0644);
@@ -613,13 +614,17 @@ static int cx8802_request_acquire(struct cx8802_driver *drv)
            core->active_type_id != drv->type_id)
                return -EBUSY;
 
-       core->input = 0;
-       for (i = 0;
-            i < (sizeof(core->board.input) / sizeof(struct cx88_input));
-            i++) {
-               if (core->board.input[i].type == CX88_VMUX_DVB) {
-                       core->input = i;
-                       break;
+       if (drv->type_id == CX88_MPEG_DVB) {
+               /* When switching to DVB, always set the input to the tuner */
+               core->last_analog_input = core->input;
+               core->input = 0;
+               for (i = 0;
+                    i < (sizeof(core->board.input) / sizeof(struct cx88_input));
+                    i++) {
+                       if (core->board.input[i].type == CX88_VMUX_DVB) {
+                               core->input = i;
+                               break;
+                       }
                }
        }
 
@@ -644,6 +649,12 @@ static int cx8802_request_release(struct cx8802_driver *drv)
 
        if (drv->advise_release && --core->active_ref == 0)
        {
+               if (drv->type_id == CX88_MPEG_DVB) {
+                       /* If the DVB driver is releasing, reset the input
+                          state to the last configured analog input */
+                       core->input = core->last_analog_input;
+               }
+
                drv->advise_release(drv);
                core->active_type_id = CX88_BOARD_NONE;
                mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
@@ -890,14 +901,8 @@ static struct pci_driver cx8802_pci_driver = {
 
 static int __init cx8802_init(void)
 {
-       printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n",
-              (CX88_VERSION_CODE >> 16) & 0xff,
-              (CX88_VERSION_CODE >>  8) & 0xff,
-              CX88_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %s loaded\n",
+              CX88_VERSION);
        return pci_register_driver(&cx8802_pci_driver);
 }
 
index cef4f282e5aae97c28eaa5515ad03db206cb8664..60d28fdd77911c286a1d9ec365aa37e976f5cdee 100644 (file)
@@ -45,6 +45,7 @@
 MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(CX88_VERSION);
 
 /* ------------------------------------------------------------------ */
 
@@ -220,7 +221,23 @@ static const struct cx88_ctrl cx8800_ctls[] = {
                .reg                   = MO_UV_SATURATION,
                .mask                  = 0x00ff,
                .shift                 = 0,
-       },{
+       }, {
+               .v = {
+                       .id            = V4L2_CID_SHARPNESS,
+                       .name          = "Sharpness",
+                       .minimum       = 0,
+                       .maximum       = 4,
+                       .step          = 1,
+                       .default_value = 0x0,
+                       .type          = V4L2_CTRL_TYPE_INTEGER,
+               },
+               .off                   = 0,
+               /* NOTE: the value is converted and written to both even
+                  and odd registers in the code */
+               .reg                   = MO_FILTER_ODD,
+               .mask                  = 7 << 7,
+               .shift                 = 7,
+       }, {
                .v = {
                        .id            = V4L2_CID_CHROMA_AGC,
                        .name          = "Chroma AGC",
@@ -244,6 +261,20 @@ static const struct cx88_ctrl cx8800_ctls[] = {
                .reg                   = MO_INPUT_FORMAT,
                .mask                  = 1 << 9,
                .shift                 = 9,
+       }, {
+               .v = {
+                       .id            = V4L2_CID_BAND_STOP_FILTER,
+                       .name          = "Notch filter",
+                       .minimum       = 0,
+                       .maximum       = 3,
+                       .step          = 1,
+                       .default_value = 0x0,
+                       .type          = V4L2_CTRL_TYPE_INTEGER,
+               },
+               .off                   = 0,
+               .reg                   = MO_HTOTAL,
+               .mask                  = 3 << 11,
+               .shift                 = 11,
        }, {
        /* --- audio --- */
                .v = {
@@ -300,8 +331,10 @@ const u32 cx88_user_ctrls[] = {
        V4L2_CID_AUDIO_VOLUME,
        V4L2_CID_AUDIO_BALANCE,
        V4L2_CID_AUDIO_MUTE,
+       V4L2_CID_SHARPNESS,
        V4L2_CID_CHROMA_AGC,
        V4L2_CID_COLOR_KILLER,
+       V4L2_CID_BAND_STOP_FILTER,
        0
 };
 EXPORT_SYMBOL(cx88_user_ctrls);
@@ -962,6 +995,10 @@ int cx88_get_control (struct cx88_core  *core, struct v4l2_control *ctl)
        case V4L2_CID_AUDIO_VOLUME:
                ctl->value = 0x3f - (value & 0x3f);
                break;
+       case V4L2_CID_SHARPNESS:
+               ctl->value = ((value & 0x0200) ? (((value & 0x0180) >> 7) + 1)
+                                                : 0);
+               break;
        default:
                ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift;
                break;
@@ -1039,6 +1076,12 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
                }
                mask=0xffff;
                break;
+       case V4L2_CID_SHARPNESS:
+               /* 0b000, 0b100, 0b101, 0b110, or 0b111 */
+               value = (ctl->value < 1 ? 0 : ((ctl->value + 3) << 7));
+               /* needs to be set for both fields */
+               cx_andor(MO_FILTER_EVEN, mask, value);
+               break;
        case V4L2_CID_CHROMA_AGC:
                /* Do not allow chroma AGC to be enabled for SECAM */
                value = ((ctl->value - c->off) << c->shift) & c->mask;
@@ -1161,7 +1204,6 @@ static int vidioc_querycap (struct file *file, void  *priv,
        strcpy(cap->driver, "cx8800");
        strlcpy(cap->card, core->board.name, sizeof(cap->card));
        sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-       cap->version = CX88_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_READWRITE     |
@@ -1480,7 +1522,6 @@ static int radio_querycap (struct file *file, void  *priv,
        strcpy(cap->driver, "cx8800");
        strlcpy(cap->card, core->board.name, sizeof(cap->card));
        sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
-       cap->version = CX88_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
@@ -2139,14 +2180,8 @@ static struct pci_driver cx8800_pci_driver = {
 
 static int __init cx8800_init(void)
 {
-       printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n",
-              (CX88_VERSION_CODE >> 16) & 0xff,
-              (CX88_VERSION_CODE >>  8) & 0xff,
-              CX88_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %s loaded\n",
+              CX88_VERSION);
        return pci_register_driver(&cx8800_pci_driver);
 }
 
@@ -2157,11 +2192,3 @@ static void __exit cx8800_fini(void)
 
 module_init(cx8800_init);
 module_exit(cx8800_fini);
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
index a399a8b086babf4e9facf27a690cdb577a5b6427..fa8d307e1a3d2299618bdf5266aea118b68f7670 100644 (file)
@@ -39,9 +39,9 @@
 #include "cx88-reg.h"
 #include "tuner-xc2028.h"
 
-#include <linux/version.h>
 #include <linux/mutex.h>
-#define CX88_VERSION_CODE KERNEL_VERSION(0, 0, 8)
+
+#define CX88_VERSION "0.0.9"
 
 #define UNSET (-1U)
 
@@ -242,6 +242,8 @@ extern const struct sram_channel const cx88_sram_channels[];
 #define CX88_BOARD_SAMSUNG_SMT_7020        84
 #define CX88_BOARD_TWINHAN_VP1027_DVBS     85
 #define CX88_BOARD_TEVII_S464              86
+#define CX88_BOARD_WINFAST_DTV2000H_PLUS   87
+#define CX88_BOARD_WINFAST_DTV1800H_XC4000 88
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -375,6 +377,7 @@ struct cx88_core {
        u32                        audiomode_manual;
        u32                        audiomode_current;
        u32                        input;
+       u32                        last_analog_input;
        u32                        astat;
        u32                        use_nicam;
        unsigned long              last_change;
index 6b1954035649c9589c4e246e8be6d453f8be67d9..60a456ebdc7cd7b2972643a43695e89388c2f0ee 100644 (file)
@@ -91,3 +91,26 @@ config VIDEO_ISIF
 
           To compile this driver as a module, choose M here: the
           module will be called vpfe.
+
+config VIDEO_DM644X_VPBE
+       tristate "DM644X VPBE HW module"
+       depends on ARCH_DAVINCI_DM644x
+       select VIDEO_VPSS_SYSTEM
+       select VIDEOBUF_DMA_CONTIG
+       help
+           Enables VPBE modules used for display on a DM644x
+           SoC.
+
+           To compile this driver as a module, choose M here: the
+           module will be called vpbe.
+
+
+config VIDEO_VPBE_DISPLAY
+       tristate "VPBE V4L2 Display driver"
+       depends on ARCH_DAVINCI_DM644x
+       select VIDEO_DM644X_VPBE
+       help
+           Enables VPBE V4L2 Display driver on a DM644x device
+
+           To compile this driver as a module, choose M here: the
+           module will be called vpbe_display.
index a37955745aaa45fbe7778c67e729f53f49316b7f..ae7dafb689ab9917678f16a81fb00072f337bff4 100644 (file)
@@ -16,3 +16,5 @@ obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o
 obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o
 obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
 obj-$(CONFIG_VIDEO_ISIF) += isif.o
+obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o
+obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o
diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c
new file mode 100644 (file)
index 0000000..d773d30
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2010 Texas Instruments 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe.h>
+#include <media/davinci/vpss.h>
+#include <media/davinci/vpbe_venc.h>
+
+#define VPBE_DEFAULT_OUTPUT    "Composite"
+#define VPBE_DEFAULT_MODE      "ntsc"
+
+static char *def_output = VPBE_DEFAULT_OUTPUT;
+static char *def_mode = VPBE_DEFAULT_MODE;
+static int debug;
+
+module_param(def_output, charp, S_IRUGO);
+module_param(def_mode, charp, S_IRUGO);
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)");
+MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc");
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+MODULE_DESCRIPTION("TI DMXXX VPBE Display controller");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
+
+/**
+ * vpbe_current_encoder_info - Get config info for current encoder
+ * @vpbe_dev - vpbe device ptr
+ *
+ * Return ptr to current encoder config info
+ */
+static struct encoder_config_info*
+vpbe_current_encoder_info(struct vpbe_device *vpbe_dev)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int index = vpbe_dev->current_sd_index;
+
+       return ((index == 0) ? &cfg->venc :
+                               &cfg->ext_encoders[index-1]);
+}
+
+/**
+ * vpbe_find_encoder_sd_index - Given a name find encoder sd index
+ *
+ * @vpbe_config - ptr to vpbe cfg
+ * @output_index - index used by application
+ *
+ * Return sd index of the encoder
+ */
+static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg,
+                            int index)
+{
+       char *encoder_name = cfg->outputs[index].subdev_name;
+       int i;
+
+       /* Venc is always first */
+       if (!strcmp(encoder_name, cfg->venc.module_name))
+               return 0;
+
+       for (i = 0; i < cfg->num_ext_encoders; i++) {
+               if (!strcmp(encoder_name,
+                    cfg->ext_encoders[i].module_name))
+                       return i+1;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vpbe_g_cropcap - Get crop capabilities of the display
+ * @vpbe_dev - vpbe device ptr
+ * @cropcap - cropcap is a ptr to struct v4l2_cropcap
+ *
+ * Update the crop capabilities in crop cap for current
+ * mode
+ */
+static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev,
+                         struct v4l2_cropcap *cropcap)
+{
+       if (NULL == cropcap)
+               return -EINVAL;
+       cropcap->bounds.left = 0;
+       cropcap->bounds.top = 0;
+       cropcap->bounds.width = vpbe_dev->current_timings.xres;
+       cropcap->bounds.height = vpbe_dev->current_timings.yres;
+       cropcap->defrect = cropcap->bounds;
+
+       return 0;
+}
+
+/**
+ * vpbe_enum_outputs - enumerate outputs
+ * @vpbe_dev - vpbe device ptr
+ * @output - ptr to v4l2_output structure
+ *
+ * Enumerates the outputs available at the vpbe display
+ * returns the status, -EINVAL if end of output list
+ */
+static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev,
+                            struct v4l2_output *output)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int temp_index = output->index;
+
+       if (temp_index >= cfg->num_outputs)
+               return -EINVAL;
+
+       *output = cfg->outputs[temp_index].output;
+       output->index = temp_index;
+
+       return 0;
+}
+
+static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct vpbe_enc_mode_info var;
+       int curr_output = vpbe_dev->current_out_index;
+       int i;
+
+       if (NULL == mode)
+               return -EINVAL;
+
+       for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) {
+               var = cfg->outputs[curr_output].modes[i];
+               if (!strcmp(mode, var.name)) {
+                       vpbe_dev->current_timings = var;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev,
+                                     struct vpbe_enc_mode_info *mode_info)
+{
+       if (NULL == mode_info)
+               return -EINVAL;
+
+       *mode_info = vpbe_dev->current_timings;
+
+       return 0;
+}
+
+static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev,
+                                  unsigned int dv_preset)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct vpbe_enc_mode_info var;
+       int curr_output = vpbe_dev->current_out_index;
+       int i;
+
+       for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
+               var = cfg->outputs[curr_output].modes[i];
+               if ((var.timings_type & VPBE_ENC_DV_PRESET) &&
+                 (var.timings.dv_preset == dv_preset)) {
+                       vpbe_dev->current_timings = var;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+/* Get std by std id */
+static int vpbe_get_std_info(struct vpbe_device *vpbe_dev,
+                            v4l2_std_id std_id)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct vpbe_enc_mode_info var;
+       int curr_output = vpbe_dev->current_out_index;
+       int i;
+
+       for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
+               var = cfg->outputs[curr_output].modes[i];
+               if ((var.timings_type & VPBE_ENC_STD) &&
+                 (var.timings.std_id & std_id)) {
+                       vpbe_dev->current_timings = var;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev,
+                               char *std_name)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct vpbe_enc_mode_info var;
+       int curr_output = vpbe_dev->current_out_index;
+       int i;
+
+       for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) {
+               var = cfg->outputs[curr_output].modes[i];
+               if (!strcmp(var.name, std_name)) {
+                       vpbe_dev->current_timings = var;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vpbe_set_output - Set output
+ * @vpbe_dev - vpbe device ptr
+ * @index - index of output
+ *
+ * Set vpbe output to the output specified by the index
+ */
+static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
+{
+       struct encoder_config_info *curr_enc_info =
+                       vpbe_current_encoder_info(vpbe_dev);
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int enc_out_index;
+       int sd_index;
+       int ret = 0;
+
+       if (index >= cfg->num_outputs)
+               return -EINVAL;
+
+       mutex_lock(&vpbe_dev->lock);
+
+       sd_index = vpbe_dev->current_sd_index;
+       enc_out_index = cfg->outputs[index].output.index;
+       /*
+        * Currently we switch the encoder based on output selected
+        * by the application. If media controller is implemented later
+        * there is will be an API added to setup_link between venc
+        * and external encoder. So in that case below comparison always
+        * match and encoder will not be switched. But if application
+        * chose not to use media controller, then this provides current
+        * way of switching encoder at the venc output.
+        */
+       if (strcmp(curr_enc_info->module_name,
+                  cfg->outputs[index].subdev_name)) {
+               /* Need to switch the encoder at the output */
+               sd_index = vpbe_find_encoder_sd_index(cfg, index);
+               if (sd_index < 0) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (ret)
+                       goto out;
+       }
+
+       /* Set output at the encoder */
+       ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
+                                      s_routing, 0, enc_out_index, 0);
+       if (ret)
+               goto out;
+
+       /*
+        * It is assumed that venc or extenal encoder will set a default
+        * mode in the sub device. For external encoder or LCD pannel output,
+        * we also need to set up the lcd port for the required mode. So setup
+        * the lcd port for the default mode that is configured in the board
+        * arch/arm/mach-davinci/board-dm355-evm.setup file for the external
+        * encoder.
+        */
+       ret = vpbe_get_mode_info(vpbe_dev,
+                                cfg->outputs[index].default_mode);
+       if (!ret) {
+               struct osd_state *osd_device = vpbe_dev->osd_device;
+
+               osd_device->ops.set_left_margin(osd_device,
+                       vpbe_dev->current_timings.left_margin);
+               osd_device->ops.set_top_margin(osd_device,
+               vpbe_dev->current_timings.upper_margin);
+               vpbe_dev->current_sd_index = sd_index;
+               vpbe_dev->current_out_index = index;
+       }
+out:
+       mutex_unlock(&vpbe_dev->lock);
+       return ret;
+}
+
+static int vpbe_set_default_output(struct vpbe_device *vpbe_dev)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int ret = 0;
+       int i;
+
+       for (i = 0; i < cfg->num_outputs; i++) {
+               if (!strcmp(def_output,
+                           cfg->outputs[i].output.name)) {
+                       ret = vpbe_set_output(vpbe_dev, i);
+                       if (!ret)
+                               vpbe_dev->current_out_index = i;
+                       return ret;
+               }
+       }
+       return ret;
+}
+
+/**
+ * vpbe_get_output - Get output
+ * @vpbe_dev - vpbe device ptr
+ *
+ * return current vpbe output to the the index
+ */
+static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev)
+{
+       return vpbe_dev->current_out_index;
+}
+
+/**
+ * vpbe_s_dv_preset - Set the given preset timings in the encoder
+ *
+ * Sets the preset if supported by the current encoder. Return the status.
+ * 0 - success & -EINVAL on error
+ */
+static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev,
+                    struct v4l2_dv_preset *dv_preset)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int out_index = vpbe_dev->current_out_index;
+       int sd_index = vpbe_dev->current_sd_index;
+       int ret;
+
+
+       if (!(cfg->outputs[out_index].output.capabilities &
+           V4L2_OUT_CAP_PRESETS))
+               return -EINVAL;
+
+       ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset);
+
+       if (ret)
+               return ret;
+
+       mutex_lock(&vpbe_dev->lock);
+
+
+       ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
+                                       s_dv_preset, dv_preset);
+       /* set the lcd controller output for the given mode */
+       if (!ret) {
+               struct osd_state *osd_device = vpbe_dev->osd_device;
+
+               osd_device->ops.set_left_margin(osd_device,
+               vpbe_dev->current_timings.left_margin);
+               osd_device->ops.set_top_margin(osd_device,
+               vpbe_dev->current_timings.upper_margin);
+       }
+       mutex_unlock(&vpbe_dev->lock);
+
+       return ret;
+}
+
+/**
+ * vpbe_g_dv_preset - Get the preset in the current encoder
+ *
+ * Get the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev,
+                    struct v4l2_dv_preset *dv_preset)
+{
+       if (vpbe_dev->current_timings.timings_type &
+         VPBE_ENC_DV_PRESET) {
+               dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder
+ *
+ * Get the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev,
+                        struct v4l2_dv_enum_preset *preset_info)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int out_index = vpbe_dev->current_out_index;
+       struct vpbe_output *output = &cfg->outputs[out_index];
+       int j = 0;
+       int i;
+
+       if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS))
+               return -EINVAL;
+
+       for (i = 0; i < output->num_modes; i++) {
+               if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) {
+                       if (j == preset_info->index)
+                               break;
+                       j++;
+               }
+       }
+
+       if (i == output->num_modes)
+               return -EINVAL;
+
+       return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset,
+                                       preset_info);
+}
+
+/**
+ * vpbe_s_std - Set the given standard in the encoder
+ *
+ * Sets the standard if supported by the current encoder. Return the status.
+ * 0 - success & -EINVAL on error
+ */
+static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id)
+{
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       int out_index = vpbe_dev->current_out_index;
+       int sd_index = vpbe_dev->current_sd_index;
+       int ret;
+
+       if (!(cfg->outputs[out_index].output.capabilities &
+               V4L2_OUT_CAP_STD))
+               return -EINVAL;
+
+       ret = vpbe_get_std_info(vpbe_dev, *std_id);
+       if (ret)
+               return ret;
+
+       mutex_lock(&vpbe_dev->lock);
+
+       ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
+                              s_std_output, *std_id);
+       /* set the lcd controller output for the given mode */
+       if (!ret) {
+               struct osd_state *osd_device = vpbe_dev->osd_device;
+
+               osd_device->ops.set_left_margin(osd_device,
+               vpbe_dev->current_timings.left_margin);
+               osd_device->ops.set_top_margin(osd_device,
+               vpbe_dev->current_timings.upper_margin);
+       }
+       mutex_unlock(&vpbe_dev->lock);
+
+       return ret;
+}
+
+/**
+ * vpbe_g_std - Get the standard in the current encoder
+ *
+ * Get the standard in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id)
+{
+       struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings;
+
+       if (cur_timings.timings_type & VPBE_ENC_STD) {
+               *std_id = cur_timings.timings.std_id;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vpbe_set_mode - Set mode in the current encoder using mode info
+ *
+ * Use the mode string to decide what timings to set in the encoder
+ * This is typically useful when fbset command is used to change the current
+ * timings by specifying a string to indicate the timings.
+ */
+static int vpbe_set_mode(struct vpbe_device *vpbe_dev,
+                        struct vpbe_enc_mode_info *mode_info)
+{
+       struct vpbe_enc_mode_info *preset_mode = NULL;
+       struct vpbe_config *cfg = vpbe_dev->cfg;
+       struct v4l2_dv_preset dv_preset;
+       struct osd_state *osd_device;
+       int out_index = vpbe_dev->current_out_index;
+       int ret = 0;
+       int i;
+
+       if ((NULL == mode_info) || (NULL == mode_info->name))
+               return -EINVAL;
+
+       for (i = 0; i < cfg->outputs[out_index].num_modes; i++) {
+               if (!strcmp(mode_info->name,
+                    cfg->outputs[out_index].modes[i].name)) {
+                       preset_mode = &cfg->outputs[out_index].modes[i];
+                       /*
+                        * it may be one of the 3 timings type. Check and
+                        * invoke right API
+                        */
+                       if (preset_mode->timings_type & VPBE_ENC_STD)
+                               return vpbe_s_std(vpbe_dev,
+                                                &preset_mode->timings.std_id);
+                       if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) {
+                               dv_preset.preset =
+                                       preset_mode->timings.dv_preset;
+                               return vpbe_s_dv_preset(vpbe_dev, &dv_preset);
+                       }
+               }
+       }
+
+       /* Only custom timing should reach here */
+       if (preset_mode == NULL)
+               return -EINVAL;
+
+       mutex_lock(&vpbe_dev->lock);
+
+       osd_device = vpbe_dev->osd_device;
+       vpbe_dev->current_timings = *preset_mode;
+       osd_device->ops.set_left_margin(osd_device,
+               vpbe_dev->current_timings.left_margin);
+       osd_device->ops.set_top_margin(osd_device,
+               vpbe_dev->current_timings.upper_margin);
+
+       mutex_unlock(&vpbe_dev->lock);
+
+       return ret;
+}
+
+static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev)
+{
+       int ret;
+
+       ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode);
+       if (ret)
+               return ret;
+
+       /* set the default mode in the encoder */
+       return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings);
+}
+
+static int platform_device_get(struct device *dev, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct vpbe_device *vpbe_dev = data;
+
+       if (strcmp("vpbe-osd", pdev->name) == 0)
+               vpbe_dev->osd_device = platform_get_drvdata(pdev);
+
+       return 0;
+}
+
+/**
+ * vpbe_initialize() - Initialize the vpbe display controller
+ * @vpbe_dev - vpbe device ptr
+ *
+ * Master frame buffer device drivers calls this to initialize vpbe
+ * display controller. This will then registers v4l2 device and the sub
+ * devices and sets a current encoder sub device for display. v4l2 display
+ * device driver is the master and frame buffer display device driver is
+ * the slave. Frame buffer display driver checks the initialized during
+ * probe and exit if not initialized. Returns status.
+ */
+static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
+{
+       struct encoder_config_info *enc_info;
+       struct v4l2_subdev **enc_subdev;
+       struct osd_state *osd_device;
+       struct i2c_adapter *i2c_adap;
+       int output_index;
+       int num_encoders;
+       int ret = 0;
+       int err;
+       int i;
+
+       /*
+        * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer
+        * from the platform device by iteration of platform drivers and
+        * matching with device name
+        */
+       if (NULL == vpbe_dev || NULL == dev) {
+               printk(KERN_ERR "Null device pointers.\n");
+               return -ENODEV;
+       }
+
+       if (vpbe_dev->initialized)
+               return 0;
+
+       mutex_lock(&vpbe_dev->lock);
+
+       if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) {
+               /* We have dac clock available for platform */
+               vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac");
+               if (IS_ERR(vpbe_dev->dac_clk)) {
+                       ret =  PTR_ERR(vpbe_dev->dac_clk);
+                       goto vpbe_unlock;
+               }
+               if (clk_enable(vpbe_dev->dac_clk)) {
+                       ret =  -ENODEV;
+                       goto vpbe_unlock;
+               }
+       }
+
+       /* first enable vpss clocks */
+       vpss_enable_clock(VPSS_VPBE_CLOCK, 1);
+
+       /* First register a v4l2 device */
+       ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev);
+       if (ret) {
+               v4l2_err(dev->driver,
+                       "Unable to register v4l2 device.\n");
+               goto vpbe_fail_clock;
+       }
+       v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n");
+
+       err = bus_for_each_dev(&platform_bus_type, NULL, vpbe_dev,
+                              platform_device_get);
+       if (err < 0)
+               return err;
+
+       vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev,
+                                          vpbe_dev->cfg->venc.module_name);
+       /* register venc sub device */
+       if (vpbe_dev->venc == NULL) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "vpbe unable to init venc sub device\n");
+               ret = -ENODEV;
+               goto vpbe_fail_v4l2_device;
+       }
+       /* initialize osd device */
+       osd_device = vpbe_dev->osd_device;
+
+       if (NULL != osd_device->ops.initialize) {
+               err = osd_device->ops.initialize(osd_device);
+               if (err) {
+                       v4l2_err(&vpbe_dev->v4l2_dev,
+                                "unable to initialize the OSD device");
+                       err = -ENOMEM;
+                       goto vpbe_fail_v4l2_device;
+               }
+       }
+
+       /*
+        * Register any external encoders that are configured. At index 0 we
+        * store venc sd index.
+        */
+       num_encoders = vpbe_dev->cfg->num_ext_encoders + 1;
+       vpbe_dev->encoders = kmalloc(
+                               sizeof(struct v4l2_subdev *)*num_encoders,
+                               GFP_KERNEL);
+       if (NULL == vpbe_dev->encoders) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "unable to allocate memory for encoders sub devices");
+               ret = -ENOMEM;
+               goto vpbe_fail_v4l2_device;
+       }
+
+       i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id);
+       for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) {
+               if (i == 0) {
+                       /* venc is at index 0 */
+                       enc_subdev = &vpbe_dev->encoders[i];
+                       *enc_subdev = vpbe_dev->venc;
+                       continue;
+               }
+               enc_info = &vpbe_dev->cfg->ext_encoders[i];
+               if (enc_info->is_i2c) {
+                       enc_subdev = &vpbe_dev->encoders[i];
+                       *enc_subdev = v4l2_i2c_new_subdev_board(
+                                               &vpbe_dev->v4l2_dev, i2c_adap,
+                                               &enc_info->board_info, NULL);
+                       if (*enc_subdev)
+                               v4l2_info(&vpbe_dev->v4l2_dev,
+                                         "v4l2 sub device %s registered\n",
+                                         enc_info->module_name);
+                       else {
+                               v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s"
+                                        " failed to register",
+                                        enc_info->module_name);
+                               ret = -ENODEV;
+                               goto vpbe_fail_sd_register;
+                       }
+               } else
+                       v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders"
+                                " currently not supported");
+       }
+
+       /* set the current encoder and output to that of venc by default */
+       vpbe_dev->current_sd_index = 0;
+       vpbe_dev->current_out_index = 0;
+       output_index = 0;
+
+       mutex_unlock(&vpbe_dev->lock);
+
+       printk(KERN_NOTICE "Setting default output to %s\n", def_output);
+       ret = vpbe_set_default_output(vpbe_dev);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s",
+                        def_output);
+               return ret;
+       }
+
+       printk(KERN_NOTICE "Setting default mode to %s\n", def_mode);
+       ret = vpbe_set_default_mode(vpbe_dev);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s",
+                        def_mode);
+               return ret;
+       }
+       vpbe_dev->initialized = 1;
+       /* TBD handling of bootargs for default output and mode */
+       return 0;
+
+vpbe_fail_sd_register:
+       kfree(vpbe_dev->encoders);
+vpbe_fail_v4l2_device:
+       v4l2_device_unregister(&vpbe_dev->v4l2_dev);
+vpbe_fail_clock:
+       if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0)
+               clk_put(vpbe_dev->dac_clk);
+vpbe_unlock:
+       mutex_unlock(&vpbe_dev->lock);
+       return ret;
+}
+
+/**
+ * vpbe_deinitialize() - de-initialize the vpbe display controller
+ * @dev - Master and slave device ptr
+ *
+ * vpbe_master and slave frame buffer devices calls this to de-initialize
+ * the display controller. It is called when master and slave device
+ * driver modules are removed and no longer requires the display controller.
+ */
+static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev)
+{
+       v4l2_device_unregister(&vpbe_dev->v4l2_dev);
+       if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0)
+               clk_put(vpbe_dev->dac_clk);
+
+       kfree(vpbe_dev->encoders);
+       vpbe_dev->initialized = 0;
+       /* disable vpss clocks */
+       vpss_enable_clock(VPSS_VPBE_CLOCK, 0);
+}
+
+static struct vpbe_device_ops vpbe_dev_ops = {
+       .g_cropcap = vpbe_g_cropcap,
+       .enum_outputs = vpbe_enum_outputs,
+       .set_output = vpbe_set_output,
+       .get_output = vpbe_get_output,
+       .s_dv_preset = vpbe_s_dv_preset,
+       .g_dv_preset = vpbe_g_dv_preset,
+       .enum_dv_presets = vpbe_enum_dv_presets,
+       .s_std = vpbe_s_std,
+       .g_std = vpbe_g_std,
+       .initialize = vpbe_initialize,
+       .deinitialize = vpbe_deinitialize,
+       .get_mode_info = vpbe_get_current_mode_info,
+       .set_mode = vpbe_set_mode,
+};
+
+static __devinit int vpbe_probe(struct platform_device *pdev)
+{
+       struct vpbe_device *vpbe_dev;
+       struct vpbe_config *cfg;
+       int ret = -EINVAL;
+
+       if (pdev->dev.platform_data == NULL) {
+               v4l2_err(pdev->dev.driver, "No platform data\n");
+               return -ENODEV;
+       }
+       cfg = pdev->dev.platform_data;
+
+       if (!cfg->module_name[0] ||
+           !cfg->osd.module_name[0] ||
+           !cfg->venc.module_name[0]) {
+               v4l2_err(pdev->dev.driver, "vpbe display module names not"
+                        " defined\n");
+               return ret;
+       }
+
+       vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL);
+       if (vpbe_dev == NULL) {
+               v4l2_err(pdev->dev.driver, "Unable to allocate memory"
+                        " for vpbe_device\n");
+               return -ENOMEM;
+       }
+       vpbe_dev->cfg = cfg;
+       vpbe_dev->ops = vpbe_dev_ops;
+       vpbe_dev->pdev = &pdev->dev;
+
+       if (cfg->outputs->num_modes > 0)
+               vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0];
+       else
+               return -ENODEV;
+
+       /* set the driver data in platform device */
+       platform_set_drvdata(pdev, vpbe_dev);
+       mutex_init(&vpbe_dev->lock);
+
+       return 0;
+}
+
+static int vpbe_remove(struct platform_device *device)
+{
+       struct vpbe_device *vpbe_dev = platform_get_drvdata(device);
+
+       kfree(vpbe_dev);
+
+       return 0;
+}
+
+static struct platform_driver vpbe_driver = {
+       .driver = {
+               .name   = "vpbe_controller",
+               .owner  = THIS_MODULE,
+       },
+       .probe = vpbe_probe,
+       .remove = vpbe_remove,
+};
+
+/**
+ * vpbe_init: initialize the vpbe driver
+ *
+ * This function registers device and driver to the kernel
+ */
+static __init int vpbe_init(void)
+{
+       return platform_driver_register(&vpbe_driver);
+}
+
+/**
+ * vpbe_cleanup : cleanup function for vpbe driver
+ *
+ * This will un-registers the device and driver to the kernel
+ */
+static void vpbe_cleanup(void)
+{
+       platform_driver_unregister(&vpbe_driver);
+}
+
+/* Function for module initialization and cleanup */
+module_init(vpbe_init);
+module_exit(vpbe_cleanup);
diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c
new file mode 100644 (file)
index 0000000..7f1d83a
--- /dev/null
@@ -0,0 +1,1860 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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 program is distributed WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+
+#include <asm/pgtable.h>
+#include <mach/cputype.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_display.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpbe_osd.h>
+#include "vpbe_venc_regs.h"
+
+#define VPBE_DISPLAY_DRIVER "vpbe-v4l2"
+
+static int debug;
+
+#define VPBE_DISPLAY_SD_BUF_SIZE (720*576*2)
+#define VPBE_DEFAULT_NUM_BUFS 3
+
+module_param(debug, int, 0644);
+
+static int venc_is_second_field(struct vpbe_display *disp_dev)
+{
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       int ret;
+       int val;
+
+       ret = v4l2_subdev_call(vpbe_dev->venc,
+                              core,
+                              ioctl,
+                              VENC_GET_FLD,
+                              &val);
+       if (ret < 0) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                        "Error in getting Field ID 0\n");
+       }
+       return val;
+}
+
+static void vpbe_isr_even_field(struct vpbe_display *disp_obj,
+                               struct vpbe_layer *layer)
+{
+       struct timespec timevalue;
+
+       if (layer->cur_frm == layer->next_frm)
+               return;
+       ktime_get_ts(&timevalue);
+       layer->cur_frm->ts.tv_sec = timevalue.tv_sec;
+       layer->cur_frm->ts.tv_usec = timevalue.tv_nsec / NSEC_PER_USEC;
+       layer->cur_frm->state = VIDEOBUF_DONE;
+       wake_up_interruptible(&layer->cur_frm->done);
+       /* Make cur_frm pointing to next_frm */
+       layer->cur_frm = layer->next_frm;
+}
+
+static void vpbe_isr_odd_field(struct vpbe_display *disp_obj,
+                               struct vpbe_layer *layer)
+{
+       struct osd_state *osd_device = disp_obj->osd_device;
+       unsigned long addr;
+
+       spin_lock(&disp_obj->dma_queue_lock);
+       if (list_empty(&layer->dma_queue) ||
+               (layer->cur_frm != layer->next_frm)) {
+               spin_unlock(&disp_obj->dma_queue_lock);
+               return;
+       }
+       /*
+        * one field is displayed configure
+        * the next frame if it is available
+        * otherwise hold on current frame
+        * Get next from the buffer queue
+        */
+       layer->next_frm = list_entry(
+                               layer->dma_queue.next,
+                               struct  videobuf_buffer,
+                               queue);
+       /* Remove that from the buffer queue */
+       list_del(&layer->next_frm->queue);
+       spin_unlock(&disp_obj->dma_queue_lock);
+       /* Mark state of the frame to active */
+       layer->next_frm->state = VIDEOBUF_ACTIVE;
+       addr = videobuf_to_dma_contig(layer->next_frm);
+       osd_device->ops.start_layer(osd_device,
+                       layer->layer_info.id,
+                       addr,
+                       disp_obj->cbcr_ofst);
+}
+
+/* interrupt service routine */
+static irqreturn_t venc_isr(int irq, void *arg)
+{
+       struct vpbe_display *disp_dev = (struct vpbe_display *)arg;
+       struct vpbe_layer *layer;
+       static unsigned last_event;
+       unsigned event = 0;
+       int fid;
+       int i;
+
+       if ((NULL == arg) || (NULL == disp_dev->dev[0]))
+               return IRQ_HANDLED;
+
+       if (venc_is_second_field(disp_dev))
+               event |= VENC_SECOND_FIELD;
+       else
+               event |= VENC_FIRST_FIELD;
+
+       if (event == (last_event & ~VENC_END_OF_FRAME)) {
+               /*
+               * If the display is non-interlaced, then we need to flag the
+               * end-of-frame event at every interrupt regardless of the
+               * value of the FIDST bit.  We can conclude that the display is
+               * non-interlaced if the value of the FIDST bit is unchanged
+               * from the previous interrupt.
+               */
+               event |= VENC_END_OF_FRAME;
+       } else if (event == VENC_SECOND_FIELD) {
+               /* end-of-frame for interlaced display */
+               event |= VENC_END_OF_FRAME;
+       }
+       last_event = event;
+
+       for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+               layer = disp_dev->dev[i];
+               /* If streaming is started in this layer */
+               if (!layer->started)
+                       continue;
+
+               if (layer->layer_first_int) {
+                       layer->layer_first_int = 0;
+                       continue;
+               }
+               /* Check the field format */
+               if ((V4L2_FIELD_NONE == layer->pix_fmt.field) &&
+                       (event & VENC_END_OF_FRAME)) {
+                       /* Progressive mode */
+
+                       vpbe_isr_even_field(disp_dev, layer);
+                       vpbe_isr_odd_field(disp_dev, layer);
+               } else {
+               /* Interlaced mode */
+
+                       layer->field_id ^= 1;
+                       if (event & VENC_FIRST_FIELD)
+                               fid = 0;
+                       else
+                               fid = 1;
+
+                       /*
+                       * If field id does not match with store
+                       * field id
+                       */
+                       if (fid != layer->field_id) {
+                               /* Make them in sync */
+                               layer->field_id = fid;
+                               continue;
+                       }
+                       /*
+                       * device field id and local field id are
+                       * in sync. If this is even field
+                       */
+                       if (0 == fid)
+                               vpbe_isr_even_field(disp_dev, layer);
+                       else  /* odd field */
+                               vpbe_isr_odd_field(disp_dev, layer);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * vpbe_buffer_prepare()
+ * This is the callback function called from videobuf_qbuf() function
+ * the buffer is prepared and user space virtual address is converted into
+ * physical address
+ */
+static int vpbe_buffer_prepare(struct videobuf_queue *q,
+                                 struct videobuf_buffer *vb,
+                                 enum v4l2_field field)
+{
+       struct vpbe_fh *fh = q->priv_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       unsigned long addr;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                               "vpbe_buffer_prepare\n");
+
+       /* If buffer is not initialized, initialize it */
+       if (VIDEOBUF_NEEDS_INIT == vb->state) {
+               vb->width = layer->pix_fmt.width;
+               vb->height = layer->pix_fmt.height;
+               vb->size = layer->pix_fmt.sizeimage;
+               vb->field = field;
+
+               ret = videobuf_iolock(q, vb, NULL);
+               if (ret < 0) {
+                       v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \
+                               user address\n");
+                       return -EINVAL;
+               }
+
+               addr = videobuf_to_dma_contig(vb);
+
+               if (q->streaming) {
+                       if (!IS_ALIGNED(addr, 8)) {
+                               v4l2_err(&vpbe_dev->v4l2_dev,
+                                       "buffer_prepare:offset is \
+                                       not aligned to 32 bytes\n");
+                               return -EINVAL;
+                       }
+               }
+               vb->state = VIDEOBUF_PREPARED;
+       }
+       return 0;
+}
+
+/*
+ * vpbe_buffer_setup()
+ * This function allocates memory for the buffers
+ */
+static int vpbe_buffer_setup(struct videobuf_queue *q,
+                               unsigned int *count,
+                               unsigned int *size)
+{
+       /* Get the file handle object and layer object */
+       struct vpbe_fh *fh = q->priv_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n");
+
+       *size = layer->pix_fmt.sizeimage;
+
+       /* Store number of buffers allocated in numbuffer member */
+       if (*count < VPBE_DEFAULT_NUM_BUFS)
+               *count = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS;
+
+       return 0;
+}
+
+/*
+ * vpbe_buffer_queue()
+ * This function adds the buffer to DMA queue
+ */
+static void vpbe_buffer_queue(struct videobuf_queue *q,
+                                struct videobuf_buffer *vb)
+{
+       /* Get the file handle object and layer object */
+       struct vpbe_fh *fh = q->priv_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_display *disp = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       unsigned long flags;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "vpbe_buffer_queue\n");
+
+       /* add the buffer to the DMA queue */
+       spin_lock_irqsave(&disp->dma_queue_lock, flags);
+       list_add_tail(&vb->queue, &layer->dma_queue);
+       spin_unlock_irqrestore(&disp->dma_queue_lock, flags);
+       /* Change state of the buffer */
+       vb->state = VIDEOBUF_QUEUED;
+}
+
+/*
+ * vpbe_buffer_release()
+ * This function is called from the videobuf layer to free memory allocated to
+ * the buffers
+ */
+static void vpbe_buffer_release(struct videobuf_queue *q,
+                                  struct videobuf_buffer *vb)
+{
+       /* Get the file handle object and layer object */
+       struct vpbe_fh *fh = q->priv_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "vpbe_buffer_release\n");
+
+       if (V4L2_MEMORY_USERPTR != layer->memory)
+               videobuf_dma_contig_free(q, vb);
+
+       vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops video_qops = {
+       .buf_setup = vpbe_buffer_setup,
+       .buf_prepare = vpbe_buffer_prepare,
+       .buf_queue = vpbe_buffer_queue,
+       .buf_release = vpbe_buffer_release,
+};
+
+static
+struct vpbe_layer*
+_vpbe_display_get_other_win_layer(struct vpbe_display *disp_dev,
+                       struct vpbe_layer *layer)
+{
+       enum vpbe_display_device_id thiswin, otherwin;
+       thiswin = layer->device_id;
+
+       otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ?
+       VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0;
+       return disp_dev->dev[otherwin];
+}
+
+static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev,
+                       struct vpbe_layer *layer)
+{
+       struct osd_layer_config *cfg  = &layer->layer_info.config;
+       struct osd_state *osd_device = disp_dev->osd_device;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       unsigned long addr;
+       int ret;
+
+       addr = videobuf_to_dma_contig(layer->cur_frm);
+       /* Set address in the display registers */
+       osd_device->ops.start_layer(osd_device,
+                                   layer->layer_info.id,
+                                   addr,
+                                   disp_dev->cbcr_ofst);
+
+       ret = osd_device->ops.enable_layer(osd_device,
+                               layer->layer_info.id, 0);
+       if (ret < 0) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Error in enabling osd window layer 0\n");
+               return -1;
+       }
+
+       /* Enable the window */
+       layer->layer_info.enable = 1;
+       if (cfg->pixfmt == PIXFMT_NV12) {
+               struct vpbe_layer *otherlayer =
+                       _vpbe_display_get_other_win_layer(disp_dev, layer);
+
+               ret = osd_device->ops.enable_layer(osd_device,
+                               otherlayer->layer_info.id, 1);
+               if (ret < 0) {
+                       v4l2_err(&vpbe_dev->v4l2_dev,
+                               "Error in enabling osd window layer 1\n");
+                       return -1;
+               }
+               otherlayer->layer_info.enable = 1;
+       }
+       return 0;
+}
+
+static void
+vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev,
+                       struct vpbe_layer *layer,
+                       int expected_xsize, int expected_ysize)
+{
+       struct display_layer_info *layer_info = &layer->layer_info;
+       struct v4l2_pix_format *pixfmt = &layer->pix_fmt;
+       struct osd_layer_config *cfg  = &layer->layer_info.config;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       int calculated_xsize;
+       int h_exp = 0;
+       int v_exp = 0;
+       int h_scale;
+       int v_scale;
+
+       v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id;
+
+       /*
+        * Application initially set the image format. Current display
+        * size is obtained from the vpbe display controller. expected_xsize
+        * and expected_ysize are set through S_CROP ioctl. Based on this,
+        * driver will calculate the scale factors for vertical and
+        * horizontal direction so that the image is displayed scaled
+        * and expanded. Application uses expansion to display the image
+        * in a square pixel. Otherwise it is displayed using displays
+        * pixel aspect ratio.It is expected that application chooses
+        * the crop coordinates for cropped or scaled display. if crop
+        * size is less than the image size, it is displayed cropped or
+        * it is displayed scaled and/or expanded.
+        *
+        * to begin with, set the crop window same as expected. Later we
+        * will override with scaled window size
+        */
+
+       cfg->xsize = pixfmt->width;
+       cfg->ysize = pixfmt->height;
+       layer_info->h_zoom = ZOOM_X1;   /* no horizontal zoom */
+       layer_info->v_zoom = ZOOM_X1;   /* no horizontal zoom */
+       layer_info->h_exp = H_EXP_OFF;  /* no horizontal zoom */
+       layer_info->v_exp = V_EXP_OFF;  /* no horizontal zoom */
+
+       if (pixfmt->width < expected_xsize) {
+               h_scale = vpbe_dev->current_timings.xres / pixfmt->width;
+               if (h_scale < 2)
+                       h_scale = 1;
+               else if (h_scale >= 4)
+                       h_scale = 4;
+               else
+                       h_scale = 2;
+               cfg->xsize *= h_scale;
+               if (cfg->xsize < expected_xsize) {
+                       if ((standard_id & V4L2_STD_525_60) ||
+                       (standard_id & V4L2_STD_625_50)) {
+                               calculated_xsize = (cfg->xsize *
+                                       VPBE_DISPLAY_H_EXP_RATIO_N) /
+                                       VPBE_DISPLAY_H_EXP_RATIO_D;
+                               if (calculated_xsize <= expected_xsize) {
+                                       h_exp = 1;
+                                       cfg->xsize = calculated_xsize;
+                               }
+                       }
+               }
+               if (h_scale == 2)
+                       layer_info->h_zoom = ZOOM_X2;
+               else if (h_scale == 4)
+                       layer_info->h_zoom = ZOOM_X4;
+               if (h_exp)
+                       layer_info->h_exp = H_EXP_9_OVER_8;
+       } else {
+               /* no scaling, only cropping. Set display area to crop area */
+               cfg->xsize = expected_xsize;
+       }
+
+       if (pixfmt->height < expected_ysize) {
+               v_scale = expected_ysize / pixfmt->height;
+               if (v_scale < 2)
+                       v_scale = 1;
+               else if (v_scale >= 4)
+                       v_scale = 4;
+               else
+                       v_scale = 2;
+               cfg->ysize *= v_scale;
+               if (cfg->ysize < expected_ysize) {
+                       if ((standard_id & V4L2_STD_625_50)) {
+                               calculated_xsize = (cfg->ysize *
+                                       VPBE_DISPLAY_V_EXP_RATIO_N) /
+                                       VPBE_DISPLAY_V_EXP_RATIO_D;
+                               if (calculated_xsize <= expected_ysize) {
+                                       v_exp = 1;
+                                       cfg->ysize = calculated_xsize;
+                               }
+                       }
+               }
+               if (v_scale == 2)
+                       layer_info->v_zoom = ZOOM_X2;
+               else if (v_scale == 4)
+                       layer_info->v_zoom = ZOOM_X4;
+               if (v_exp)
+                       layer_info->h_exp = V_EXP_6_OVER_5;
+       } else {
+               /* no scaling, only cropping. Set display area to crop area */
+               cfg->ysize = expected_ysize;
+       }
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "crop display xsize = %d, ysize = %d\n",
+               cfg->xsize, cfg->ysize);
+}
+
+static void vpbe_disp_adj_position(struct vpbe_display *disp_dev,
+                       struct vpbe_layer *layer,
+                       int top, int left)
+{
+       struct osd_layer_config *cfg = &layer->layer_info.config;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+
+       cfg->xpos = min((unsigned int)left,
+                       vpbe_dev->current_timings.xres - cfg->xsize);
+       cfg->ypos = min((unsigned int)top,
+                       vpbe_dev->current_timings.yres - cfg->ysize);
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "new xpos = %d, ypos = %d\n",
+               cfg->xpos, cfg->ypos);
+}
+
+static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev,
+                       struct v4l2_rect *c)
+{
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+
+       if ((c->width == 0) ||
+         ((c->width + c->left) > vpbe_dev->current_timings.xres))
+               c->width = vpbe_dev->current_timings.xres - c->left;
+
+       if ((c->height == 0) || ((c->height + c->top) >
+         vpbe_dev->current_timings.yres))
+               c->height = vpbe_dev->current_timings.yres - c->top;
+
+       /* window height must be even for interlaced display */
+       if (vpbe_dev->current_timings.interlaced)
+               c->height &= (~0x01);
+
+}
+
+/**
+ * vpbe_try_format()
+ * If user application provides width and height, and have bytesperline set
+ * to zero, driver calculates bytesperline and sizeimage based on hardware
+ * limits.
+ */
+static int vpbe_try_format(struct vpbe_display *disp_dev,
+                       struct v4l2_pix_format *pixfmt, int check)
+{
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       int min_height = 1;
+       int min_width = 32;
+       int max_height;
+       int max_width;
+       int bpp;
+
+       if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) &&
+           (pixfmt->pixelformat != V4L2_PIX_FMT_NV12))
+               /* choose default as V4L2_PIX_FMT_UYVY */
+               pixfmt->pixelformat = V4L2_PIX_FMT_UYVY;
+
+       /* Check the field format */
+       if ((pixfmt->field != V4L2_FIELD_INTERLACED) &&
+               (pixfmt->field != V4L2_FIELD_NONE)) {
+               if (vpbe_dev->current_timings.interlaced)
+                       pixfmt->field = V4L2_FIELD_INTERLACED;
+               else
+                       pixfmt->field = V4L2_FIELD_NONE;
+       }
+
+       if (pixfmt->field == V4L2_FIELD_INTERLACED)
+               min_height = 2;
+
+       if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+               bpp = 1;
+       else
+               bpp = 2;
+
+       max_width = vpbe_dev->current_timings.xres;
+       max_height = vpbe_dev->current_timings.yres;
+
+       min_width /= bpp;
+
+       if (!pixfmt->width || (pixfmt->width < min_width) ||
+               (pixfmt->width > max_width)) {
+               pixfmt->width = vpbe_dev->current_timings.xres;
+       }
+
+       if (!pixfmt->height || (pixfmt->height  < min_height) ||
+               (pixfmt->height  > max_height)) {
+               pixfmt->height = vpbe_dev->current_timings.yres;
+       }
+
+       if (pixfmt->bytesperline < (pixfmt->width * bpp))
+               pixfmt->bytesperline = pixfmt->width * bpp;
+
+       /* Make the bytesperline 32 byte aligned */
+       pixfmt->bytesperline = ((pixfmt->width * bpp + 31) & ~31);
+
+       if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12)
+               pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height +
+                               (pixfmt->bytesperline * pixfmt->height >> 1);
+       else
+               pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+
+       return 0;
+}
+
+static int vpbe_display_g_priority(struct file *file, void *priv,
+                               enum v4l2_priority *p)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+
+       *p = v4l2_prio_max(&layer->prio);
+
+       return 0;
+}
+
+static int vpbe_display_s_priority(struct file *file, void *priv,
+                               enum v4l2_priority p)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       int ret;
+
+       ret = v4l2_prio_change(&layer->prio, &fh->prio, p);
+
+       return ret;
+}
+
+static int vpbe_display_querycap(struct file *file, void  *priv,
+                              struct v4l2_capability *cap)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       cap->version = VPBE_DISPLAY_VERSION_CODE;
+       cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+       strlcpy(cap->driver, VPBE_DISPLAY_DRIVER, sizeof(cap->driver));
+       strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info));
+       strlcpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card));
+
+       return 0;
+}
+
+static int vpbe_display_s_crop(struct file *file, void *priv,
+                            struct v4l2_crop *crop)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_display *disp_dev = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       struct osd_layer_config *cfg = &layer->layer_info.config;
+       struct osd_state *osd_device = disp_dev->osd_device;
+       struct v4l2_rect *rect = &crop->c;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "VIDIOC_S_CROP, layer id = %d\n", layer->device_id);
+
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
+               return -EINVAL;
+       }
+
+       if (rect->top < 0)
+               rect->top = 0;
+       if (rect->left < 0)
+               rect->left = 0;
+
+       vpbe_disp_check_window_params(disp_dev, rect);
+
+       osd_device->ops.get_layer_config(osd_device,
+                       layer->layer_info.id, cfg);
+
+       vpbe_disp_calculate_scale_factor(disp_dev, layer,
+                                       rect->width,
+                                       rect->height);
+       vpbe_disp_adj_position(disp_dev, layer, rect->top,
+                                       rect->left);
+       ret = osd_device->ops.set_layer_config(osd_device,
+                               layer->layer_info.id, cfg);
+       if (ret < 0) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Error in set layer config:\n");
+               return -EINVAL;
+       }
+
+       /* apply zooming and h or v expansion */
+       osd_device->ops.set_zoom(osd_device,
+                       layer->layer_info.id,
+                       layer->layer_info.h_zoom,
+                       layer->layer_info.v_zoom);
+       ret = osd_device->ops.set_vid_expansion(osd_device,
+                       layer->layer_info.h_exp,
+                       layer->layer_info.v_exp);
+       if (ret < 0) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+               "Error in set vid expansion:\n");
+               return -EINVAL;
+       }
+
+       if ((layer->layer_info.h_zoom != ZOOM_X1) ||
+               (layer->layer_info.v_zoom != ZOOM_X1) ||
+               (layer->layer_info.h_exp != H_EXP_OFF) ||
+               (layer->layer_info.v_exp != V_EXP_OFF))
+               /* Enable expansion filter */
+               osd_device->ops.set_interpolation_filter(osd_device, 1);
+       else
+               osd_device->ops.set_interpolation_filter(osd_device, 0);
+
+       return 0;
+}
+
+static int vpbe_display_g_crop(struct file *file, void *priv,
+                            struct v4l2_crop *crop)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct osd_layer_config *cfg = &layer->layer_info.config;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       struct osd_state *osd_device = fh->disp_dev->osd_device;
+       struct v4l2_rect *rect = &crop->c;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "VIDIOC_G_CROP, layer id = %d\n",
+                       layer->device_id);
+
+       if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n");
+               ret = -EINVAL;
+       }
+       osd_device->ops.get_layer_config(osd_device,
+                               layer->layer_info.id, cfg);
+       rect->top = cfg->ypos;
+       rect->left = cfg->xpos;
+       rect->width = cfg->xsize;
+       rect->height = cfg->ysize;
+
+       return 0;
+}
+
+static int vpbe_display_cropcap(struct file *file, void *priv,
+                             struct v4l2_cropcap *cropcap)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n");
+
+       cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       cropcap->bounds.left = 0;
+       cropcap->bounds.top = 0;
+       cropcap->bounds.width = vpbe_dev->current_timings.xres;
+       cropcap->bounds.height = vpbe_dev->current_timings.yres;
+       cropcap->pixelaspect = vpbe_dev->current_timings.aspect;
+       cropcap->defrect = cropcap->bounds;
+       return 0;
+}
+
+static int vpbe_display_g_fmt(struct file *file, void *priv,
+                               struct v4l2_format *fmt)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "VIDIOC_G_FMT, layer id = %d\n",
+                       layer->device_id);
+
+       /* If buffer type is video output */
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n");
+               return -EINVAL;
+       }
+       /* Fill in the information about format */
+       fmt->fmt.pix = layer->pix_fmt;
+
+       return 0;
+}
+
+static int vpbe_display_enum_fmt(struct file *file, void  *priv,
+                                  struct v4l2_fmtdesc *fmt)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       unsigned int index = 0;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                               "VIDIOC_ENUM_FMT, layer id = %d\n",
+                               layer->device_id);
+       if (fmt->index > 1) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n");
+               return -EINVAL;
+       }
+
+       /* Fill in the information about format */
+       index = fmt->index;
+       memset(fmt, 0, sizeof(*fmt));
+       fmt->index = index;
+       fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       if (index == 0) {
+               strcpy(fmt->description, "YUV 4:2:2 - UYVY");
+               fmt->pixelformat = V4L2_PIX_FMT_UYVY;
+       } else {
+               strcpy(fmt->description, "Y/CbCr 4:2:0");
+               fmt->pixelformat = V4L2_PIX_FMT_NV12;
+       }
+
+       return 0;
+}
+
+static int vpbe_display_s_fmt(struct file *file, void *priv,
+                               struct v4l2_format *fmt)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_display *disp_dev = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       struct osd_layer_config *cfg  = &layer->layer_info.config;
+       struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+       struct osd_state *osd_device = disp_dev->osd_device;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "VIDIOC_S_FMT, layer id = %d\n",
+                       layer->device_id);
+
+       /* If streaming is started, return error */
+       if (layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+               return -EBUSY;
+       }
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+               v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n");
+               return -EINVAL;
+       }
+       /* Check for valid pixel format */
+       ret = vpbe_try_format(disp_dev, pixfmt, 1);
+       if (ret)
+               return ret;
+
+       /* YUV420 is requested, check availability of the
+       other video window */
+
+       layer->pix_fmt = *pixfmt;
+
+       /* Get osd layer config */
+       osd_device->ops.get_layer_config(osd_device,
+                       layer->layer_info.id, cfg);
+       /* Store the pixel format in the layer object */
+       cfg->xsize = pixfmt->width;
+       cfg->ysize = pixfmt->height;
+       cfg->line_length = pixfmt->bytesperline;
+       cfg->ypos = 0;
+       cfg->xpos = 0;
+       cfg->interlaced = vpbe_dev->current_timings.interlaced;
+
+       if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat)
+               cfg->pixfmt = PIXFMT_YCbCrI;
+
+       /* Change of the default pixel format for both video windows */
+       if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) {
+               struct vpbe_layer *otherlayer;
+               cfg->pixfmt = PIXFMT_NV12;
+               otherlayer = _vpbe_display_get_other_win_layer(disp_dev,
+                                                               layer);
+               otherlayer->layer_info.config.pixfmt = PIXFMT_NV12;
+       }
+
+       /* Set the layer config in the osd window */
+       ret = osd_device->ops.set_layer_config(osd_device,
+                               layer->layer_info.id, cfg);
+       if (ret < 0) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                               "Error in S_FMT params:\n");
+               return -EINVAL;
+       }
+
+       /* Readback and fill the local copy of current pix format */
+       osd_device->ops.get_layer_config(osd_device,
+                       layer->layer_info.id, cfg);
+
+       return 0;
+}
+
+static int vpbe_display_try_fmt(struct file *file, void *priv,
+                                 struct v4l2_format *fmt)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_display *disp_dev = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n");
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n");
+               return -EINVAL;
+       }
+
+       /* Check for valid field format */
+       return  vpbe_try_format(disp_dev, pixfmt, 0);
+
+}
+
+/**
+ * vpbe_display_s_std - Set the given standard in the encoder
+ *
+ * Sets the standard if supported by the current encoder. Return the status.
+ * 0 - success & -EINVAL on error
+ */
+static int vpbe_display_s_std(struct file *file, void *priv,
+                               v4l2_std_id *std_id)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n");
+
+       /* If streaming is started, return error */
+       if (layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+               return -EBUSY;
+       }
+       if (NULL != vpbe_dev->ops.s_std) {
+               ret = vpbe_dev->ops.s_std(vpbe_dev, std_id);
+               if (ret) {
+                       v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Failed to set standard for sub devices\n");
+                       return -EINVAL;
+               }
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * vpbe_display_g_std - Get the standard in the current encoder
+ *
+ * Get the standard in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int vpbe_display_g_std(struct file *file, void *priv,
+                               v4l2_std_id *std_id)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n");
+
+       /* Get the standard from the current encoder */
+       if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) {
+               *std_id = vpbe_dev->current_timings.timings.std_id;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+/**
+ * vpbe_display_enum_output - enumerate outputs
+ *
+ * Enumerates the outputs available at the vpbe display
+ * returns the status, -EINVAL if end of output list
+ */
+static int vpbe_display_enum_output(struct file *file, void *priv,
+                                   struct v4l2_output *output)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n");
+
+       /* Enumerate outputs */
+
+       if (NULL == vpbe_dev->ops.enum_outputs)
+               return -EINVAL;
+
+       ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output);
+       if (ret) {
+               v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "Failed to enumerate outputs\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * vpbe_display_s_output - Set output to
+ * the output specified by the index
+ */
+static int vpbe_display_s_output(struct file *file, void *priv,
+                               unsigned int i)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n");
+       /* If streaming is started, return error */
+       if (layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+               return -EBUSY;
+       }
+       if (NULL == vpbe_dev->ops.set_output)
+               return -EINVAL;
+
+       ret = vpbe_dev->ops.set_output(vpbe_dev, i);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Failed to set output for sub devices\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * vpbe_display_g_output - Get output from subdevice
+ * for a given by the index
+ */
+static int vpbe_display_g_output(struct file *file, void *priv,
+                               unsigned int *i)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n");
+       /* Get the standard from the current encoder */
+       *i = vpbe_dev->current_out_index;
+
+       return 0;
+}
+
+/**
+ * vpbe_display_enum_dv_presets - Enumerate the dv presets
+ *
+ * enum the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_enum_dv_presets(struct file *file, void *priv,
+                       struct v4l2_dv_enum_preset *preset)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n");
+
+       /* Enumerate outputs */
+       if (NULL == vpbe_dev->ops.enum_dv_presets)
+               return -EINVAL;
+
+       ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Failed to enumerate dv presets info\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * vpbe_display_s_dv_preset - Set the dv presets
+ *
+ * Set the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_s_dv_preset(struct file *file, void *priv,
+                               struct v4l2_dv_preset *preset)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n");
+
+
+       /* If streaming is started, return error */
+       if (layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+               return -EBUSY;
+       }
+
+       /* Set the given standard in the encoder */
+       if (NULL != vpbe_dev->ops.s_dv_preset)
+               return -EINVAL;
+
+       ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "Failed to set the dv presets info\n");
+               return -EINVAL;
+       }
+       /* set the current norm to zero to be consistent. If STD is used
+        * v4l2 layer will set the norm properly on successful s_std call
+        */
+       layer->video_dev.current_norm = 0;
+
+       return 0;
+}
+
+/**
+ * vpbe_display_g_dv_preset - Set the dv presets
+ *
+ * Get the preset in the current encoder. Return the status. 0 - success
+ * -EINVAL on error
+ */
+static int
+vpbe_display_g_dv_preset(struct file *file, void *priv,
+                               struct v4l2_dv_preset *dv_preset)
+{
+       struct vpbe_fh *fh = priv;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n");
+
+       /* Get the given standard in the encoder */
+
+       if (vpbe_dev->current_timings.timings_type &
+                               VPBE_ENC_DV_PRESET) {
+               dv_preset->preset =
+                       vpbe_dev->current_timings.timings.dv_preset;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int vpbe_display_streamoff(struct file *file, void *priv,
+                               enum v4l2_buf_type buf_type)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       struct osd_state *osd_device = fh->disp_dev->osd_device;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "VIDIOC_STREAMOFF,layer id = %d\n",
+                       layer->device_id);
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       /* If io is allowed for this file handle, return error */
+       if (!fh->io_allowed) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+               return -EACCES;
+       }
+
+       /* If streaming is not started, return error */
+       if (!layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer"
+                       " id = %d\n", layer->device_id);
+               return -EINVAL;
+       }
+
+       osd_device->ops.disable_layer(osd_device,
+                       layer->layer_info.id);
+       layer->started = 0;
+       ret = videobuf_streamoff(&layer->buffer_queue);
+
+       return ret;
+}
+
+static int vpbe_display_streamon(struct file *file, void *priv,
+                        enum v4l2_buf_type buf_type)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_display *disp_dev = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       struct osd_state *osd_device = disp_dev->osd_device;
+       int ret;
+
+       osd_device->ops.disable_layer(osd_device,
+                       layer->layer_info.id);
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n",
+                                               layer->device_id);
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       /* If file handle is not allowed IO, return error */
+       if (!fh->io_allowed) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+               return -EACCES;
+       }
+       /* If Streaming is already started, return error */
+       if (layer->started) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n");
+               return -EBUSY;
+       }
+
+       /*
+        * Call videobuf_streamon to start streaming
+        * in videobuf
+        */
+       ret = videobuf_streamon(&layer->buffer_queue);
+       if (ret) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+               "error in videobuf_streamon\n");
+               return ret;
+       }
+       /* If buffer queue is empty, return error */
+       if (list_empty(&layer->dma_queue)) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n");
+               goto streamoff;
+       }
+       /* Get the next frame from the buffer queue */
+       layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,
+                               struct videobuf_buffer, queue);
+       /* Remove buffer from the buffer queue */
+       list_del(&layer->cur_frm->queue);
+       /* Mark state of the current frame to active */
+       layer->cur_frm->state = VIDEOBUF_ACTIVE;
+       /* Initialize field_id and started member */
+       layer->field_id = 0;
+
+       /* Set parameters in OSD and VENC */
+       ret = vpbe_set_osd_display_params(disp_dev, layer);
+       if (ret < 0)
+               goto streamoff;
+
+       /*
+        * if request format is yuv420 semiplanar, need to
+        * enable both video windows
+        */
+       layer->started = 1;
+
+       layer->layer_first_int = 1;
+
+       return ret;
+streamoff:
+       ret = videobuf_streamoff(&layer->buffer_queue);
+       return ret;
+}
+
+static int vpbe_display_dqbuf(struct file *file, void *priv,
+                     struct v4l2_buffer *buf)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "VIDIOC_DQBUF, layer id = %d\n",
+               layer->device_id);
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+       /* If this file handle is not allowed to do IO, return error */
+       if (!fh->io_allowed) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+               return -EACCES;
+       }
+       if (file->f_flags & O_NONBLOCK)
+               /* Call videobuf_dqbuf for non blocking mode */
+               ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1);
+       else
+               /* Call videobuf_dqbuf for blocking mode */
+               ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0);
+
+       return ret;
+}
+
+static int vpbe_display_qbuf(struct file *file, void *priv,
+                    struct v4l2_buffer *p)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "VIDIOC_QBUF, layer id = %d\n",
+               layer->device_id);
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       /* If this file handle is not allowed to do IO, return error */
+       if (!fh->io_allowed) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
+               return -EACCES;
+       }
+
+       return videobuf_qbuf(&layer->buffer_queue, p);
+}
+
+static int vpbe_display_querybuf(struct file *file, void *priv,
+                        struct v4l2_buffer *buf)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+               "VIDIOC_QUERYBUF, layer id = %d\n",
+               layer->device_id);
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       /* Call videobuf_querybuf to get information */
+       ret = videobuf_querybuf(&layer->buffer_queue, buf);
+
+       return ret;
+}
+
+static int vpbe_display_reqbufs(struct file *file, void *priv,
+                       struct v4l2_requestbuffers *req_buf)
+{
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n");
+
+       if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
+               return -EINVAL;
+       }
+
+       /* If io users of the layer is not zero, return error */
+       if (0 != layer->io_usrs) {
+               v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n");
+               return -EBUSY;
+       }
+       /* Initialize videobuf queue as per the buffer type */
+       videobuf_queue_dma_contig_init(&layer->buffer_queue,
+                               &video_qops,
+                               vpbe_dev->pdev,
+                               &layer->irqlock,
+                               V4L2_BUF_TYPE_VIDEO_OUTPUT,
+                               layer->pix_fmt.field,
+                               sizeof(struct videobuf_buffer),
+                               fh, NULL);
+
+       /* Set io allowed member of file handle to TRUE */
+       fh->io_allowed = 1;
+       /* Increment io usrs member of layer object to 1 */
+       layer->io_usrs = 1;
+       /* Store type of memory requested in layer object */
+       layer->memory = req_buf->memory;
+       /* Initialize buffer queue */
+       INIT_LIST_HEAD(&layer->dma_queue);
+       /* Allocate buffers */
+       ret = videobuf_reqbufs(&layer->buffer_queue, req_buf);
+
+       return ret;
+}
+
+/*
+ * vpbe_display_mmap()
+ * It is used to map kernel space buffers into user spaces
+ */
+static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+       /* Get the layer object and file handle object */
+       struct vpbe_fh *fh = filep->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n");
+
+       return videobuf_mmap_mapper(&layer->buffer_queue, vma);
+}
+
+/* vpbe_display_poll(): It is used for select/poll system call
+ */
+static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait)
+{
+       struct vpbe_fh *fh = filep->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       unsigned int err = 0;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n");
+       if (layer->started)
+               err = videobuf_poll_stream(filep, &layer->buffer_queue, wait);
+       return err;
+}
+
+/*
+ * vpbe_display_open()
+ * It creates object of file handle structure and stores it in private_data
+ * member of filepointer
+ */
+static int vpbe_display_open(struct file *file)
+{
+       struct vpbe_fh *fh = NULL;
+       struct vpbe_layer *layer = video_drvdata(file);
+       struct vpbe_display *disp_dev = layer->disp_dev;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       struct osd_state *osd_device = disp_dev->osd_device;
+       int err;
+
+       /* Allocate memory for the file handle object */
+       fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL);
+       if (fh == NULL) {
+               v4l2_err(&vpbe_dev->v4l2_dev,
+                       "unable to allocate memory for file handle object\n");
+               return -ENOMEM;
+       }
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "vpbe display open plane = %d\n",
+                       layer->device_id);
+
+       /* store pointer to fh in private_data member of filep */
+       file->private_data = fh;
+       fh->layer = layer;
+       fh->disp_dev = disp_dev;
+
+       if (!layer->usrs) {
+
+               /* First claim the layer for this device */
+               err = osd_device->ops.request_layer(osd_device,
+                                               layer->layer_info.id);
+               if (err < 0) {
+                       /* Couldn't get layer */
+                       v4l2_err(&vpbe_dev->v4l2_dev,
+                               "Display Manager failed to allocate layer\n");
+                       kfree(fh);
+                       return -EINVAL;
+               }
+       }
+       /* Increment layer usrs counter */
+       layer->usrs++;
+       /* Set io_allowed member to false */
+       fh->io_allowed = 0;
+       /* Initialize priority of this instance to default priority */
+       fh->prio = V4L2_PRIORITY_UNSET;
+       v4l2_prio_open(&layer->prio, &fh->prio);
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
+                       "vpbe display device opened successfully\n");
+       return 0;
+}
+
+/*
+ * vpbe_display_release()
+ * This function deletes buffer queue, frees the buffers and the davinci
+ * display file * handle
+ */
+static int vpbe_display_release(struct file *file)
+{
+       /* Get the layer object and file handle object */
+       struct vpbe_fh *fh = file->private_data;
+       struct vpbe_layer *layer = fh->layer;
+       struct osd_layer_config *cfg  = &layer->layer_info.config;
+       struct vpbe_display *disp_dev = fh->disp_dev;
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       struct osd_state *osd_device = disp_dev->osd_device;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n");
+
+       /* if this instance is doing IO */
+       if (fh->io_allowed) {
+               /* Reset io_usrs member of layer object */
+               layer->io_usrs = 0;
+
+               osd_device->ops.disable_layer(osd_device,
+                               layer->layer_info.id);
+               layer->started = 0;
+               /* Free buffers allocated */
+               videobuf_queue_cancel(&layer->buffer_queue);
+               videobuf_mmap_free(&layer->buffer_queue);
+       }
+
+       /* Decrement layer usrs counter */
+       layer->usrs--;
+       /* If this file handle has initialize encoder device, reset it */
+       if (!layer->usrs) {
+               if (cfg->pixfmt == PIXFMT_NV12) {
+                       struct vpbe_layer *otherlayer;
+                       otherlayer =
+                       _vpbe_display_get_other_win_layer(disp_dev, layer);
+                       osd_device->ops.disable_layer(osd_device,
+                                       otherlayer->layer_info.id);
+                       osd_device->ops.release_layer(osd_device,
+                                       otherlayer->layer_info.id);
+               }
+               osd_device->ops.disable_layer(osd_device,
+                               layer->layer_info.id);
+               osd_device->ops.release_layer(osd_device,
+                               layer->layer_info.id);
+       }
+       /* Close the priority */
+       v4l2_prio_close(&layer->prio, fh->prio);
+       file->private_data = NULL;
+
+       /* Free memory allocated to file handle object */
+       kfree(fh);
+
+       disp_dev->cbcr_ofst = 0;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vpbe_display_g_register(struct file *file, void *priv,
+                       struct v4l2_dbg_register *reg)
+{
+       struct v4l2_dbg_match *match = &reg->match;
+
+       if (match->type >= 2) {
+               v4l2_subdev_call(vpbe_dev->venc,
+                                core,
+                                g_register,
+                                reg);
+       }
+
+       return 0;
+}
+
+static int vpbe_display_s_register(struct file *file, void *priv,
+                       struct v4l2_dbg_register *reg)
+{
+       return 0;
+}
+#endif
+
+/* vpbe capture ioctl operations */
+static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
+       .vidioc_querycap         = vpbe_display_querycap,
+       .vidioc_g_fmt_vid_out    = vpbe_display_g_fmt,
+       .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt,
+       .vidioc_s_fmt_vid_out    = vpbe_display_s_fmt,
+       .vidioc_try_fmt_vid_out  = vpbe_display_try_fmt,
+       .vidioc_reqbufs          = vpbe_display_reqbufs,
+       .vidioc_querybuf         = vpbe_display_querybuf,
+       .vidioc_qbuf             = vpbe_display_qbuf,
+       .vidioc_dqbuf            = vpbe_display_dqbuf,
+       .vidioc_streamon         = vpbe_display_streamon,
+       .vidioc_streamoff        = vpbe_display_streamoff,
+       .vidioc_cropcap          = vpbe_display_cropcap,
+       .vidioc_g_crop           = vpbe_display_g_crop,
+       .vidioc_s_crop           = vpbe_display_s_crop,
+       .vidioc_g_priority       = vpbe_display_g_priority,
+       .vidioc_s_priority       = vpbe_display_s_priority,
+       .vidioc_s_std            = vpbe_display_s_std,
+       .vidioc_g_std            = vpbe_display_g_std,
+       .vidioc_enum_output      = vpbe_display_enum_output,
+       .vidioc_s_output         = vpbe_display_s_output,
+       .vidioc_g_output         = vpbe_display_g_output,
+       .vidioc_s_dv_preset      = vpbe_display_s_dv_preset,
+       .vidioc_g_dv_preset      = vpbe_display_g_dv_preset,
+       .vidioc_enum_dv_presets  = vpbe_display_enum_dv_presets,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register       = vpbe_display_g_register,
+       .vidioc_s_register       = vpbe_display_s_register,
+#endif
+};
+
+static struct v4l2_file_operations vpbe_fops = {
+       .owner = THIS_MODULE,
+       .open = vpbe_display_open,
+       .release = vpbe_display_release,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap = vpbe_display_mmap,
+       .poll = vpbe_display_poll
+};
+
+static int vpbe_device_get(struct device *dev, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct vpbe_display *vpbe_disp  = data;
+
+       if (strcmp("vpbe_controller", pdev->name) == 0)
+               vpbe_disp->vpbe_dev = platform_get_drvdata(pdev);
+
+       if (strcmp("vpbe-osd", pdev->name) == 0)
+               vpbe_disp->osd_device = platform_get_drvdata(pdev);
+
+       return 0;
+}
+
+static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
+                                    struct platform_device *pdev)
+{
+       struct vpbe_layer *vpbe_display_layer = NULL;
+       struct video_device *vbd = NULL;
+
+       /* Allocate memory for four plane display objects */
+
+       disp_dev->dev[i] =
+               kzalloc(sizeof(struct vpbe_layer), GFP_KERNEL);
+
+       /* If memory allocation fails, return error */
+       if (!disp_dev->dev[i]) {
+               printk(KERN_ERR "ran out of memory\n");
+               return  -ENOMEM;
+       }
+       spin_lock_init(&disp_dev->dev[i]->irqlock);
+       mutex_init(&disp_dev->dev[i]->opslock);
+
+       /* Get the pointer to the layer object */
+       vpbe_display_layer = disp_dev->dev[i];
+       vbd = &vpbe_display_layer->video_dev;
+       /* Initialize field of video device */
+       vbd->release    = video_device_release_empty;
+       vbd->fops       = &vpbe_fops;
+       vbd->ioctl_ops  = &vpbe_ioctl_ops;
+       vbd->minor      = -1;
+       vbd->v4l2_dev   = &disp_dev->vpbe_dev->v4l2_dev;
+       vbd->lock       = &vpbe_display_layer->opslock;
+
+       if (disp_dev->vpbe_dev->current_timings.timings_type &
+                       VPBE_ENC_STD) {
+               vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50);
+               vbd->current_norm =
+                       disp_dev->vpbe_dev->
+                       current_timings.timings.std_id;
+       } else
+               vbd->current_norm = 0;
+
+       snprintf(vbd->name, sizeof(vbd->name),
+                       "DaVinci_VPBE Display_DRIVER_V%d.%d.%d",
+                       (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff,
+                       (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff,
+                       (VPBE_DISPLAY_VERSION_CODE) & 0xff);
+
+       vpbe_display_layer->device_id = i;
+
+       vpbe_display_layer->layer_info.id =
+               ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1);
+
+       /* Initialize prio member of layer object */
+       v4l2_prio_init(&vpbe_display_layer->prio);
+
+       return 0;
+}
+
+static __devinit int register_device(struct vpbe_layer *vpbe_display_layer,
+                                       struct vpbe_display *disp_dev,
+                                       struct platform_device *pdev) {
+       int err;
+
+       v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
+                 "Trying to register VPBE display device.\n");
+       v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
+                 "layer=%x,layer->video_dev=%x\n",
+                 (int)vpbe_display_layer,
+                 (int)&vpbe_display_layer->video_dev);
+
+       err = video_register_device(&vpbe_display_layer->video_dev,
+                                   VFL_TYPE_GRABBER,
+                                   -1);
+       if (err)
+               return -ENODEV;
+
+       vpbe_display_layer->disp_dev = disp_dev;
+       /* set the driver data in platform device */
+       platform_set_drvdata(pdev, disp_dev);
+       video_set_drvdata(&vpbe_display_layer->video_dev,
+                         vpbe_display_layer);
+
+       return 0;
+}
+
+
+
+/*
+ * vpbe_display_probe()
+ * This function creates device entries by register itself to the V4L2 driver
+ * and initializes fields of each layer objects
+ */
+static __devinit int vpbe_display_probe(struct platform_device *pdev)
+{
+       struct vpbe_layer *vpbe_display_layer;
+       struct vpbe_display *disp_dev;
+       struct resource *res = NULL;
+       int k;
+       int i;
+       int err;
+       int irq;
+
+       printk(KERN_DEBUG "vpbe_display_probe\n");
+       /* Allocate memory for vpbe_display */
+       disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL);
+       if (!disp_dev) {
+               printk(KERN_ERR "ran out of memory\n");
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&disp_dev->dma_queue_lock);
+       /*
+        * Scan all the platform devices to find the vpbe
+        * controller device and get the vpbe_dev object
+        */
+       err = bus_for_each_dev(&platform_bus_type, NULL, disp_dev,
+                       vpbe_device_get);
+       if (err < 0)
+               return err;
+       /* Initialize the vpbe display controller */
+       if (NULL != disp_dev->vpbe_dev->ops.initialize) {
+               err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev,
+                                                        disp_dev->vpbe_dev);
+               if (err) {
+                       v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+                                       "Error initing vpbe\n");
+                       err = -ENOMEM;
+                       goto probe_out;
+               }
+       }
+
+       for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+               if (init_vpbe_layer(i, disp_dev, pdev)) {
+                       err = -ENODEV;
+                       goto probe_out;
+               }
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+                        "Unable to get VENC interrupt resource\n");
+               err = -ENODEV;
+               goto probe_out;
+       }
+
+       irq = res->start;
+       if (request_irq(irq, venc_isr,  IRQF_DISABLED, VPBE_DISPLAY_DRIVER,
+               disp_dev)) {
+               v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
+                               "Unable to request interrupt\n");
+               err = -ENODEV;
+               goto probe_out;
+       }
+
+       for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+               if (register_device(disp_dev->dev[i], disp_dev, pdev)) {
+                       err = -ENODEV;
+                       goto probe_out;
+               }
+       }
+
+       printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n");
+       return 0;
+
+probe_out:
+       free_irq(res->start, disp_dev);
+       for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) {
+               /* Get the pointer to the layer object */
+               vpbe_display_layer = disp_dev->dev[k];
+               /* Unregister video device */
+               if (vpbe_display_layer) {
+                       video_unregister_device(
+                               &vpbe_display_layer->video_dev);
+                               kfree(disp_dev->dev[k]);
+               }
+       }
+       kfree(disp_dev);
+       return err;
+}
+
+/*
+ * vpbe_display_remove()
+ * It un-register hardware layer from V4L2 driver
+ */
+static int vpbe_display_remove(struct platform_device *pdev)
+{
+       struct vpbe_layer *vpbe_display_layer;
+       struct vpbe_display *disp_dev = platform_get_drvdata(pdev);
+       struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
+       struct resource *res;
+       int i;
+
+       v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n");
+
+       /* unregister irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       free_irq(res->start, disp_dev);
+
+       /* deinitialize the vpbe display controller */
+       if (NULL != vpbe_dev->ops.deinitialize)
+               vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev);
+       /* un-register device */
+       for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+               /* Get the pointer to the layer object */
+               vpbe_display_layer = disp_dev->dev[i];
+               /* Unregister video device */
+               video_unregister_device(&vpbe_display_layer->video_dev);
+
+       }
+       for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+               kfree(disp_dev->dev[i]);
+               disp_dev->dev[i] = NULL;
+       }
+
+       return 0;
+}
+
+static struct platform_driver vpbe_display_driver = {
+       .driver = {
+               .name = VPBE_DISPLAY_DRIVER,
+               .owner = THIS_MODULE,
+               .bus = &platform_bus_type,
+       },
+       .probe = vpbe_display_probe,
+       .remove = __devexit_p(vpbe_display_remove),
+};
+
+/*
+ * vpbe_display_init()
+ * This function registers device and driver to the kernel, requests irq
+ * handler and allocates memory for layer objects
+ */
+static __devinit int vpbe_display_init(void)
+{
+       int err;
+
+       printk(KERN_DEBUG "vpbe_display_init\n");
+
+       /* Register driver to the kernel */
+       err = platform_driver_register(&vpbe_display_driver);
+       if (0 != err)
+               return err;
+
+       printk(KERN_DEBUG "vpbe_display_init:"
+                       "VPBE V4L2 Display Driver V1.0 loaded\n");
+       return 0;
+}
+
+/*
+ * vpbe_display_cleanup()
+ * This function un-registers device and driver to the kernel, frees requested
+ * irq handler and de-allocates memory allocated for layer objects.
+ */
+static void vpbe_display_cleanup(void)
+{
+       printk(KERN_DEBUG "vpbe_display_cleanup\n");
+
+       /* platform driver unregister */
+       platform_driver_unregister(&vpbe_display_driver);
+}
+
+/* Function for module initialization and cleanup */
+module_init(vpbe_display_init);
+module_exit(vpbe_display_cleanup);
+
+MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c
new file mode 100644 (file)
index 0000000..5352884
--- /dev/null
@@ -0,0 +1,1231 @@
+/*
+ * Copyright (C) 2007-2010 Texas Instruments Inc
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * Andy Lowe (alowe@mvista.com), MontaVista Software
+ * - Initial version
+ * Murali Karicheri (mkaricheri@gmail.com), Texas Instruments Ltd.
+ * - ported to sub device interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <mach/io.h>
+#include <mach/cputype.h>
+#include <mach/hardware.h>
+
+#include <media/davinci/vpss.h>
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe_osd.h>
+
+#include <linux/io.h>
+#include "vpbe_osd_regs.h"
+
+#define MODULE_NAME    VPBE_OSD_SUBDEV_NAME
+
+/* register access routines */
+static inline u32 osd_read(struct osd_state *sd, u32 offset)
+{
+       struct osd_state *osd = sd;
+
+       return readl(osd->osd_base + offset);
+}
+
+static inline u32 osd_write(struct osd_state *sd, u32 val, u32 offset)
+{
+       struct osd_state *osd = sd;
+
+       writel(val, osd->osd_base + offset);
+
+       return val;
+}
+
+static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset)
+{
+       struct osd_state *osd = sd;
+
+       u32 addr = osd->osd_base + offset;
+       u32 val = readl(addr) | mask;
+
+       writel(val, addr);
+
+       return val;
+}
+
+static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset)
+{
+       struct osd_state *osd = sd;
+
+       u32 addr = osd->osd_base + offset;
+       u32 val = readl(addr) & ~mask;
+
+       writel(val, addr);
+
+       return val;
+}
+
+static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val,
+                                u32 offset)
+{
+       struct osd_state *osd = sd;
+
+       u32 addr = osd->osd_base + offset;
+       u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+       writel(new_val, addr);
+
+       return new_val;
+}
+
+/* define some macros for layer and pixfmt classification */
+#define is_osd_win(layer) (((layer) == WIN_OSD0) || ((layer) == WIN_OSD1))
+#define is_vid_win(layer) (((layer) == WIN_VID0) || ((layer) == WIN_VID1))
+#define is_rgb_pixfmt(pixfmt) \
+       (((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888))
+#define is_yc_pixfmt(pixfmt) \
+       (((pixfmt) == PIXFMT_YCbCrI) || ((pixfmt) == PIXFMT_YCrCbI) || \
+       ((pixfmt) == PIXFMT_NV12))
+#define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X
+#define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5)
+
+/**
+ * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446
+ * @sd - ptr to struct osd_state
+ * @field_inversion - inversion flag
+ * @fb_base_phys - frame buffer address
+ * @lconfig - ptr to layer config
+ *
+ * This routine implements a workaround for the field signal inversion silicon
+ * erratum described in Advisory 1.3.8 for the DM6446.  The fb_base_phys and
+ * lconfig parameters apply to the vid0 window.  This routine should be called
+ * whenever the vid0 layer configuration or start address is modified, or when
+ * the OSD field inversion setting is modified.
+ * Returns: 1 if the ping-pong buffers need to be toggled in the vsync isr, or
+ *          0 otherwise
+ */
+static int _osd_dm6446_vid0_pingpong(struct osd_state *sd,
+                                    int field_inversion,
+                                    unsigned long fb_base_phys,
+                                    const struct osd_layer_config *lconfig)
+{
+       struct osd_platform_data *pdata;
+
+       pdata = (struct osd_platform_data *)sd->dev->platform_data;
+       if (pdata->field_inv_wa_enable) {
+
+               if (!field_inversion || !lconfig->interlaced) {
+                       osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
+                       osd_write(sd, fb_base_phys & ~0x1F, OSD_PPVWIN0ADR);
+                       osd_modify(sd, OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, 0,
+                                  OSD_MISCCTL);
+                       return 0;
+               } else {
+                       unsigned miscctl = OSD_MISCCTL_PPRV;
+
+                       osd_write(sd,
+                               (fb_base_phys & ~0x1F) - lconfig->line_length,
+                               OSD_VIDWIN0ADR);
+                       osd_write(sd,
+                               (fb_base_phys & ~0x1F) + lconfig->line_length,
+                               OSD_PPVWIN0ADR);
+                       osd_modify(sd,
+                               OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, miscctl,
+                               OSD_MISCCTL);
+
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static void _osd_set_field_inversion(struct osd_state *sd, int enable)
+{
+       unsigned fsinv = 0;
+
+       if (enable)
+               fsinv = OSD_MODE_FSINV;
+
+       osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE);
+}
+
+static void _osd_set_blink_attribute(struct osd_state *sd, int enable,
+                                    enum osd_blink_interval blink)
+{
+       u32 osdatrmd = 0;
+
+       if (enable) {
+               osdatrmd |= OSD_OSDATRMD_BLNK;
+               osdatrmd |= blink << OSD_OSDATRMD_BLNKINT_SHIFT;
+       }
+       /* caller must ensure that OSD1 is configured in attribute mode */
+       osd_modify(sd, OSD_OSDATRMD_BLNKINT | OSD_OSDATRMD_BLNK, osdatrmd,
+                 OSD_OSDATRMD);
+}
+
+static void _osd_set_rom_clut(struct osd_state *sd,
+                             enum osd_rom_clut rom_clut)
+{
+       if (rom_clut == ROM_CLUT0)
+               osd_clear(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL);
+       else
+               osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL);
+}
+
+static void _osd_set_palette_map(struct osd_state *sd,
+                                enum osd_win_layer osdwin,
+                                unsigned char pixel_value,
+                                unsigned char clut_index,
+                                enum osd_pix_format pixfmt)
+{
+       static const int map_2bpp[] = { 0, 5, 10, 15 };
+       static const int map_1bpp[] = { 0, 15 };
+       int bmp_offset;
+       int bmp_shift;
+       int bmp_mask;
+       int bmp_reg;
+
+       switch (pixfmt) {
+       case PIXFMT_1BPP:
+               bmp_reg = map_1bpp[pixel_value & 0x1];
+               break;
+       case PIXFMT_2BPP:
+               bmp_reg = map_2bpp[pixel_value & 0x3];
+               break;
+       case PIXFMT_4BPP:
+               bmp_reg = pixel_value & 0xf;
+               break;
+       default:
+               return;
+       }
+
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               bmp_offset = OSD_W0BMP01 + (bmp_reg >> 1) * sizeof(u32);
+               break;
+       case OSDWIN_OSD1:
+               bmp_offset = OSD_W1BMP01 + (bmp_reg >> 1) * sizeof(u32);
+               break;
+       default:
+               return;
+       }
+
+       if (bmp_reg & 1) {
+               bmp_shift = 8;
+               bmp_mask = 0xff << 8;
+       } else {
+               bmp_shift = 0;
+               bmp_mask = 0xff;
+       }
+
+       osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset);
+}
+
+static void _osd_set_rec601_attenuation(struct osd_state *sd,
+                                       enum osd_win_layer osdwin, int enable)
+{
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               osd_modify(sd, OSD_OSDWIN0MD_ATN0E,
+                         enable ? OSD_OSDWIN0MD_ATN0E : 0,
+                         OSD_OSDWIN0MD);
+               break;
+       case OSDWIN_OSD1:
+               osd_modify(sd, OSD_OSDWIN1MD_ATN1E,
+                         enable ? OSD_OSDWIN1MD_ATN1E : 0,
+                         OSD_OSDWIN1MD);
+               break;
+       }
+}
+
+static void _osd_set_blending_factor(struct osd_state *sd,
+                                    enum osd_win_layer osdwin,
+                                    enum osd_blending_factor blend)
+{
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               osd_modify(sd, OSD_OSDWIN0MD_BLND0,
+                         blend << OSD_OSDWIN0MD_BLND0_SHIFT, OSD_OSDWIN0MD);
+               break;
+       case OSDWIN_OSD1:
+               osd_modify(sd, OSD_OSDWIN1MD_BLND1,
+                         blend << OSD_OSDWIN1MD_BLND1_SHIFT, OSD_OSDWIN1MD);
+               break;
+       }
+}
+
+static void _osd_enable_color_key(struct osd_state *sd,
+                                 enum osd_win_layer osdwin,
+                                 unsigned colorkey,
+                                 enum osd_pix_format pixfmt)
+{
+       switch (pixfmt) {
+       case PIXFMT_RGB565:
+               osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS,
+                         OSD_TRANSPVAL);
+               break;
+       default:
+               break;
+       }
+
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               osd_set(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD);
+               break;
+       case OSDWIN_OSD1:
+               osd_set(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD);
+               break;
+       }
+}
+
+static void _osd_disable_color_key(struct osd_state *sd,
+                                  enum osd_win_layer osdwin)
+{
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               osd_clear(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD);
+               break;
+       case OSDWIN_OSD1:
+               osd_clear(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD);
+               break;
+       }
+}
+
+static void _osd_set_osd_clut(struct osd_state *sd,
+                             enum osd_win_layer osdwin,
+                             enum osd_clut clut)
+{
+       u32 winmd = 0;
+
+       switch (osdwin) {
+       case OSDWIN_OSD0:
+               if (clut == RAM_CLUT)
+                       winmd |= OSD_OSDWIN0MD_CLUTS0;
+               osd_modify(sd, OSD_OSDWIN0MD_CLUTS0, winmd, OSD_OSDWIN0MD);
+               break;
+       case OSDWIN_OSD1:
+               if (clut == RAM_CLUT)
+                       winmd |= OSD_OSDWIN1MD_CLUTS1;
+               osd_modify(sd, OSD_OSDWIN1MD_CLUTS1, winmd, OSD_OSDWIN1MD);
+               break;
+       }
+}
+
+static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer,
+                         enum osd_zoom_factor h_zoom,
+                         enum osd_zoom_factor v_zoom)
+{
+       u32 winmd = 0;
+
+       switch (layer) {
+       case WIN_OSD0:
+               winmd |= (h_zoom << OSD_OSDWIN0MD_OHZ0_SHIFT);
+               winmd |= (v_zoom << OSD_OSDWIN0MD_OVZ0_SHIFT);
+               osd_modify(sd, OSD_OSDWIN0MD_OHZ0 | OSD_OSDWIN0MD_OVZ0, winmd,
+                         OSD_OSDWIN0MD);
+               break;
+       case WIN_VID0:
+               winmd |= (h_zoom << OSD_VIDWINMD_VHZ0_SHIFT);
+               winmd |= (v_zoom << OSD_VIDWINMD_VVZ0_SHIFT);
+               osd_modify(sd, OSD_VIDWINMD_VHZ0 | OSD_VIDWINMD_VVZ0, winmd,
+                         OSD_VIDWINMD);
+               break;
+       case WIN_OSD1:
+               winmd |= (h_zoom << OSD_OSDWIN1MD_OHZ1_SHIFT);
+               winmd |= (v_zoom << OSD_OSDWIN1MD_OVZ1_SHIFT);
+               osd_modify(sd, OSD_OSDWIN1MD_OHZ1 | OSD_OSDWIN1MD_OVZ1, winmd,
+                         OSD_OSDWIN1MD);
+               break;
+       case WIN_VID1:
+               winmd |= (h_zoom << OSD_VIDWINMD_VHZ1_SHIFT);
+               winmd |= (v_zoom << OSD_VIDWINMD_VVZ1_SHIFT);
+               osd_modify(sd, OSD_VIDWINMD_VHZ1 | OSD_VIDWINMD_VVZ1, winmd,
+                         OSD_VIDWINMD);
+               break;
+       }
+}
+
+static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       switch (layer) {
+       case WIN_OSD0:
+               osd_clear(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD);
+               break;
+       case WIN_VID0:
+               osd_clear(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD);
+               break;
+       case WIN_OSD1:
+               /* disable attribute mode as well as disabling the window */
+               osd_clear(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1,
+                         OSD_OSDWIN1MD);
+               break;
+       case WIN_VID1:
+               osd_clear(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD);
+               break;
+       }
+}
+
+static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       if (!win->is_enabled) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return;
+       }
+       win->is_enabled = 0;
+
+       _osd_disable_layer(sd, layer);
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void _osd_enable_attribute_mode(struct osd_state *sd)
+{
+       /* enable attribute mode for OSD1 */
+       osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD);
+}
+
+static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       switch (layer) {
+       case WIN_OSD0:
+               osd_set(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD);
+               break;
+       case WIN_VID0:
+               osd_set(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD);
+               break;
+       case WIN_OSD1:
+               /* enable OSD1 and disable attribute mode */
+               osd_modify(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1,
+                         OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD);
+               break;
+       case WIN_VID1:
+               osd_set(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD);
+               break;
+       }
+}
+
+static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer,
+                           int otherwin)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       struct osd_layer_config *cfg = &win->lconfig;
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       /*
+        * use otherwin flag to know this is the other vid window
+        * in YUV420 mode, if is, skip this check
+        */
+       if (!otherwin && (!win->is_allocated ||
+                       !win->fb_base_phys ||
+                       !cfg->line_length ||
+                       !cfg->xsize ||
+                       !cfg->ysize)) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return -1;
+       }
+
+       if (win->is_enabled) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return 0;
+       }
+       win->is_enabled = 1;
+
+       if (cfg->pixfmt != PIXFMT_OSD_ATTR)
+               _osd_enable_layer(sd, layer);
+       else {
+               _osd_enable_attribute_mode(sd);
+               _osd_set_blink_attribute(sd, osd->is_blinking, osd->blink);
+       }
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+
+       return 0;
+}
+
+static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer,
+                            unsigned long fb_base_phys,
+                            unsigned long cbcr_ofst)
+{
+       switch (layer) {
+       case WIN_OSD0:
+               osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR);
+               break;
+       case WIN_VID0:
+               osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR);
+               break;
+       case WIN_OSD1:
+               osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR);
+               break;
+       case WIN_VID1:
+               osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR);
+               break;
+       }
+}
+
+static void osd_start_layer(struct osd_state *sd, enum osd_layer layer,
+                           unsigned long fb_base_phys,
+                           unsigned long cbcr_ofst)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       struct osd_layer_config *cfg = &win->lconfig;
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       win->fb_base_phys = fb_base_phys & ~0x1F;
+       _osd_start_layer(sd, layer, fb_base_phys, cbcr_ofst);
+
+       if (layer == WIN_VID0) {
+               osd->pingpong =
+                   _osd_dm6446_vid0_pingpong(sd, osd->field_inversion,
+                                                      win->fb_base_phys,
+                                                      cfg);
+       }
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer,
+                                struct osd_layer_config *lconfig)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       *lconfig = win->lconfig;
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+/**
+ * try_layer_config() - Try a specific configuration for the layer
+ * @sd  - ptr to struct osd_state
+ * @layer - layer to configure
+ * @lconfig - layer configuration to try
+ *
+ * If the requested lconfig is completely rejected and the value of lconfig on
+ * exit is the current lconfig, then try_layer_config() returns 1.  Otherwise,
+ * try_layer_config() returns 0.  A return value of 0 does not necessarily mean
+ * that the value of lconfig on exit is identical to the value of lconfig on
+ * entry, but merely that it represents a change from the current lconfig.
+ */
+static int try_layer_config(struct osd_state *sd, enum osd_layer layer,
+                           struct osd_layer_config *lconfig)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       int bad_config;
+
+       /* verify that the pixel format is compatible with the layer */
+       switch (lconfig->pixfmt) {
+       case PIXFMT_1BPP:
+       case PIXFMT_2BPP:
+       case PIXFMT_4BPP:
+       case PIXFMT_8BPP:
+       case PIXFMT_RGB565:
+               bad_config = !is_osd_win(layer);
+               break;
+       case PIXFMT_YCbCrI:
+       case PIXFMT_YCrCbI:
+               bad_config = !is_vid_win(layer);
+               break;
+       case PIXFMT_RGB888:
+               bad_config = !is_vid_win(layer);
+               break;
+       case PIXFMT_NV12:
+               bad_config = 1;
+               break;
+       case PIXFMT_OSD_ATTR:
+               bad_config = (layer != WIN_OSD1);
+               break;
+       default:
+               bad_config = 1;
+               break;
+       }
+       if (bad_config) {
+               /*
+                * The requested pixel format is incompatible with the layer,
+                * so keep the current layer configuration.
+                */
+               *lconfig = win->lconfig;
+               return bad_config;
+       }
+
+       /* DM6446: */
+       /* only one OSD window at a time can use RGB pixel formats */
+       if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) {
+               enum osd_pix_format pixfmt;
+               if (layer == WIN_OSD0)
+                       pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt;
+               else
+                       pixfmt = osd->win[WIN_OSD0].lconfig.pixfmt;
+
+               if (is_rgb_pixfmt(pixfmt)) {
+                       /*
+                        * The other OSD window is already configured for an
+                        * RGB, so keep the current layer configuration.
+                        */
+                       *lconfig = win->lconfig;
+                       return 1;
+               }
+       }
+
+       /* DM6446: only one video window at a time can use RGB888 */
+       if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) {
+               enum osd_pix_format pixfmt;
+
+               if (layer == WIN_VID0)
+                       pixfmt = osd->win[WIN_VID1].lconfig.pixfmt;
+               else
+                       pixfmt = osd->win[WIN_VID0].lconfig.pixfmt;
+
+               if (pixfmt == PIXFMT_RGB888) {
+                       /*
+                        * The other video window is already configured for
+                        * RGB888, so keep the current layer configuration.
+                        */
+                       *lconfig = win->lconfig;
+                       return 1;
+               }
+       }
+
+       /* window dimensions must be non-zero */
+       if (!lconfig->line_length || !lconfig->xsize || !lconfig->ysize) {
+               *lconfig = win->lconfig;
+               return 1;
+       }
+
+       /* round line_length up to a multiple of 32 */
+       lconfig->line_length = ((lconfig->line_length + 31) / 32) * 32;
+       lconfig->line_length =
+           min(lconfig->line_length, (unsigned)MAX_LINE_LENGTH);
+       lconfig->xsize = min(lconfig->xsize, (unsigned)MAX_WIN_SIZE);
+       lconfig->ysize = min(lconfig->ysize, (unsigned)MAX_WIN_SIZE);
+       lconfig->xpos = min(lconfig->xpos, (unsigned)MAX_WIN_SIZE);
+       lconfig->ypos = min(lconfig->ypos, (unsigned)MAX_WIN_SIZE);
+       lconfig->interlaced = (lconfig->interlaced != 0);
+       if (lconfig->interlaced) {
+               /* ysize and ypos must be even for interlaced displays */
+               lconfig->ysize &= ~1;
+               lconfig->ypos &= ~1;
+       }
+
+       return 0;
+}
+
+static void _osd_disable_vid_rgb888(struct osd_state *sd)
+{
+       /*
+        * The DM6446 supports RGB888 pixel format in a single video window.
+        * This routine disables RGB888 pixel format for both video windows.
+        * The caller must ensure that neither video window is currently
+        * configured for RGB888 pixel format.
+        */
+       osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL);
+}
+
+static void _osd_enable_vid_rgb888(struct osd_state *sd,
+                                  enum osd_layer layer)
+{
+       /*
+        * The DM6446 supports RGB888 pixel format in a single video window.
+        * This routine enables RGB888 pixel format for the specified video
+        * window.  The caller must ensure that the other video window is not
+        * currently configured for RGB888 pixel format, as this routine will
+        * disable RGB888 pixel format for the other window.
+        */
+       if (layer == WIN_VID0) {
+               osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+                         OSD_MISCCTL_RGBEN, OSD_MISCCTL);
+       } else if (layer == WIN_VID1) {
+               osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+                         OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN,
+                         OSD_MISCCTL);
+       }
+}
+
+static void _osd_set_cbcr_order(struct osd_state *sd,
+                               enum osd_pix_format pixfmt)
+{
+       /*
+        * The caller must ensure that all windows using YC pixfmt use the same
+        * Cb/Cr order.
+        */
+       if (pixfmt == PIXFMT_YCbCrI)
+               osd_clear(sd, OSD_MODE_CS, OSD_MODE);
+       else if (pixfmt == PIXFMT_YCrCbI)
+               osd_set(sd, OSD_MODE_CS, OSD_MODE);
+}
+
+static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
+                                 const struct osd_layer_config *lconfig)
+{
+       u32 winmd = 0, winmd_mask = 0, bmw = 0;
+
+       _osd_set_cbcr_order(sd, lconfig->pixfmt);
+
+       switch (layer) {
+       case WIN_OSD0:
+               winmd_mask |= OSD_OSDWIN0MD_RGB0E;
+               if (lconfig->pixfmt == PIXFMT_RGB565)
+                       winmd |= OSD_OSDWIN0MD_RGB0E;
+
+               winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0;
+
+               switch (lconfig->pixfmt) {
+               case PIXFMT_1BPP:
+                       bmw = 0;
+                       break;
+               case PIXFMT_2BPP:
+                       bmw = 1;
+                       break;
+               case PIXFMT_4BPP:
+                       bmw = 2;
+                       break;
+               case PIXFMT_8BPP:
+                       bmw = 3;
+                       break;
+               default:
+                       break;
+               }
+               winmd |= (bmw << OSD_OSDWIN0MD_BMW0_SHIFT);
+
+               if (lconfig->interlaced)
+                       winmd |= OSD_OSDWIN0MD_OFF0;
+
+               osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN0MD);
+               osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN0OFST);
+               osd_write(sd, lconfig->xpos, OSD_OSDWIN0XP);
+               osd_write(sd, lconfig->xsize, OSD_OSDWIN0XL);
+               if (lconfig->interlaced) {
+                       osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN0YP);
+                       osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN0YL);
+               } else {
+                       osd_write(sd, lconfig->ypos, OSD_OSDWIN0YP);
+                       osd_write(sd, lconfig->ysize, OSD_OSDWIN0YL);
+               }
+               break;
+       case WIN_VID0:
+               winmd_mask |= OSD_VIDWINMD_VFF0;
+               if (lconfig->interlaced)
+                       winmd |= OSD_VIDWINMD_VFF0;
+
+               osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD);
+               osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN0OFST);
+               osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP);
+               osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL);
+               /*
+                * For YUV420P format the register contents are
+                * duplicated in both VID registers
+                */
+               if (lconfig->interlaced) {
+                       osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP);
+                       osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL);
+               } else {
+                       osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP);
+                       osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL);
+               }
+               break;
+       case WIN_OSD1:
+               /*
+                * The caller must ensure that OSD1 is disabled prior to
+                * switching from a normal mode to attribute mode or from
+                * attribute mode to a normal mode.
+                */
+               if (lconfig->pixfmt == PIXFMT_OSD_ATTR) {
+                       winmd_mask |=
+                           OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E |
+                           OSD_OSDWIN1MD_CLUTS1 |
+                           OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1;
+               } else {
+                       winmd_mask |= OSD_OSDWIN1MD_RGB1E;
+                       if (lconfig->pixfmt == PIXFMT_RGB565)
+                               winmd |= OSD_OSDWIN1MD_RGB1E;
+
+                       winmd_mask |= OSD_OSDWIN1MD_BMW1;
+                       switch (lconfig->pixfmt) {
+                       case PIXFMT_1BPP:
+                               bmw = 0;
+                               break;
+                       case PIXFMT_2BPP:
+                               bmw = 1;
+                               break;
+                       case PIXFMT_4BPP:
+                               bmw = 2;
+                               break;
+                       case PIXFMT_8BPP:
+                               bmw = 3;
+                               break;
+                       default:
+                               break;
+                       }
+                       winmd |= (bmw << OSD_OSDWIN1MD_BMW1_SHIFT);
+               }
+
+               winmd_mask |= OSD_OSDWIN1MD_OFF1;
+               if (lconfig->interlaced)
+                       winmd |= OSD_OSDWIN1MD_OFF1;
+
+               osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN1MD);
+               osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN1OFST);
+               osd_write(sd, lconfig->xpos, OSD_OSDWIN1XP);
+               osd_write(sd, lconfig->xsize, OSD_OSDWIN1XL);
+               if (lconfig->interlaced) {
+                       osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN1YP);
+                       osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN1YL);
+               } else {
+                       osd_write(sd, lconfig->ypos, OSD_OSDWIN1YP);
+                       osd_write(sd, lconfig->ysize, OSD_OSDWIN1YL);
+               }
+               break;
+       case WIN_VID1:
+               winmd_mask |= OSD_VIDWINMD_VFF1;
+               if (lconfig->interlaced)
+                       winmd |= OSD_VIDWINMD_VFF1;
+
+               osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD);
+               osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN1OFST);
+               osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP);
+               osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL);
+               /*
+                * For YUV420P format the register contents are
+                * duplicated in both VID registers
+                */
+               osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D,
+                          OSD_MISCCTL);
+
+               if (lconfig->interlaced) {
+                       osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP);
+                       osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL);
+               } else {
+                       osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP);
+                       osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL);
+               }
+               break;
+       }
+}
+
+static int osd_set_layer_config(struct osd_state *sd, enum osd_layer layer,
+                               struct osd_layer_config *lconfig)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       struct osd_layer_config *cfg = &win->lconfig;
+       unsigned long flags;
+       int reject_config;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       reject_config = try_layer_config(sd, layer, lconfig);
+       if (reject_config) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return reject_config;
+       }
+
+       /* update the current Cb/Cr order */
+       if (is_yc_pixfmt(lconfig->pixfmt))
+               osd->yc_pixfmt = lconfig->pixfmt;
+
+       /*
+        * If we are switching OSD1 from normal mode to attribute mode or from
+        * attribute mode to normal mode, then we must disable the window.
+        */
+       if (layer == WIN_OSD1) {
+               if (((lconfig->pixfmt == PIXFMT_OSD_ATTR) &&
+                 (cfg->pixfmt != PIXFMT_OSD_ATTR)) ||
+                 ((lconfig->pixfmt != PIXFMT_OSD_ATTR) &&
+                 (cfg->pixfmt == PIXFMT_OSD_ATTR))) {
+                       win->is_enabled = 0;
+                       _osd_disable_layer(sd, layer);
+               }
+       }
+
+       _osd_set_layer_config(sd, layer, lconfig);
+
+       if (layer == WIN_OSD1) {
+               struct osd_osdwin_state *osdwin_state =
+                   &osd->osdwin[OSDWIN_OSD1];
+
+               if ((lconfig->pixfmt != PIXFMT_OSD_ATTR) &&
+                 (cfg->pixfmt == PIXFMT_OSD_ATTR)) {
+                       /*
+                        * We just switched OSD1 from attribute mode to normal
+                        * mode, so we must initialize the CLUT select, the
+                        * blend factor, transparency colorkey enable, and
+                        * attenuation enable (DM6446 only) bits in the
+                        * OSDWIN1MD register.
+                        */
+                       _osd_set_osd_clut(sd, OSDWIN_OSD1,
+                                                  osdwin_state->clut);
+                       _osd_set_blending_factor(sd, OSDWIN_OSD1,
+                                                         osdwin_state->blend);
+                       if (osdwin_state->colorkey_blending) {
+                               _osd_enable_color_key(sd, OSDWIN_OSD1,
+                                                              osdwin_state->
+                                                              colorkey,
+                                                              lconfig->pixfmt);
+                       } else
+                               _osd_disable_color_key(sd, OSDWIN_OSD1);
+                       _osd_set_rec601_attenuation(sd, OSDWIN_OSD1,
+                                                   osdwin_state->
+                                                   rec601_attenuation);
+               } else if ((lconfig->pixfmt == PIXFMT_OSD_ATTR) &&
+                 (cfg->pixfmt != PIXFMT_OSD_ATTR)) {
+                       /*
+                        * We just switched OSD1 from normal mode to attribute
+                        * mode, so we must initialize the blink enable and
+                        * blink interval bits in the OSDATRMD register.
+                        */
+                       _osd_set_blink_attribute(sd, osd->is_blinking,
+                                                         osd->blink);
+               }
+       }
+
+       /*
+        * If we just switched to a 1-, 2-, or 4-bits-per-pixel bitmap format
+        * then configure a default palette map.
+        */
+       if ((lconfig->pixfmt != cfg->pixfmt) &&
+         ((lconfig->pixfmt == PIXFMT_1BPP) ||
+         (lconfig->pixfmt == PIXFMT_2BPP) ||
+         (lconfig->pixfmt == PIXFMT_4BPP))) {
+               enum osd_win_layer osdwin =
+                   ((layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1);
+               struct osd_osdwin_state *osdwin_state =
+                   &osd->osdwin[osdwin];
+               unsigned char clut_index;
+               unsigned char clut_entries = 0;
+
+               switch (lconfig->pixfmt) {
+               case PIXFMT_1BPP:
+                       clut_entries = 2;
+                       break;
+               case PIXFMT_2BPP:
+                       clut_entries = 4;
+                       break;
+               case PIXFMT_4BPP:
+                       clut_entries = 16;
+                       break;
+               default:
+                       break;
+               }
+               /*
+                * The default palette map maps the pixel value to the clut
+                * index, i.e. pixel value 0 maps to clut entry 0, pixel value
+                * 1 maps to clut entry 1, etc.
+                */
+               for (clut_index = 0; clut_index < 16; clut_index++) {
+                       osdwin_state->palette_map[clut_index] = clut_index;
+                       if (clut_index < clut_entries) {
+                               _osd_set_palette_map(sd, osdwin, clut_index,
+                                                    clut_index,
+                                                    lconfig->pixfmt);
+                       }
+               }
+       }
+
+       *cfg = *lconfig;
+       /* DM6446: configure the RGB888 enable and window selection */
+       if (osd->win[WIN_VID0].lconfig.pixfmt == PIXFMT_RGB888)
+               _osd_enable_vid_rgb888(sd, WIN_VID0);
+       else if (osd->win[WIN_VID1].lconfig.pixfmt == PIXFMT_RGB888)
+               _osd_enable_vid_rgb888(sd, WIN_VID1);
+       else
+               _osd_disable_vid_rgb888(sd);
+
+       if (layer == WIN_VID0) {
+               osd->pingpong =
+                   _osd_dm6446_vid0_pingpong(sd, osd->field_inversion,
+                                                      win->fb_base_phys,
+                                                      cfg);
+       }
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+
+       return 0;
+}
+
+static void osd_init_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       enum osd_win_layer osdwin;
+       struct osd_osdwin_state *osdwin_state;
+       struct osd_layer_config *cfg = &win->lconfig;
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       win->is_enabled = 0;
+       _osd_disable_layer(sd, layer);
+
+       win->h_zoom = ZOOM_X1;
+       win->v_zoom = ZOOM_X1;
+       _osd_set_zoom(sd, layer, win->h_zoom, win->v_zoom);
+
+       win->fb_base_phys = 0;
+       _osd_start_layer(sd, layer, win->fb_base_phys, 0);
+
+       cfg->line_length = 0;
+       cfg->xsize = 0;
+       cfg->ysize = 0;
+       cfg->xpos = 0;
+       cfg->ypos = 0;
+       cfg->interlaced = 0;
+       switch (layer) {
+       case WIN_OSD0:
+       case WIN_OSD1:
+               osdwin = (layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1;
+               osdwin_state = &osd->osdwin[osdwin];
+               /*
+                * Other code relies on the fact that OSD windows default to a
+                * bitmap pixel format when they are deallocated, so don't
+                * change this default pixel format.
+                */
+               cfg->pixfmt = PIXFMT_8BPP;
+               _osd_set_layer_config(sd, layer, cfg);
+               osdwin_state->clut = RAM_CLUT;
+               _osd_set_osd_clut(sd, osdwin, osdwin_state->clut);
+               osdwin_state->colorkey_blending = 0;
+               _osd_disable_color_key(sd, osdwin);
+               osdwin_state->blend = OSD_8_VID_0;
+               _osd_set_blending_factor(sd, osdwin, osdwin_state->blend);
+               osdwin_state->rec601_attenuation = 0;
+               _osd_set_rec601_attenuation(sd, osdwin,
+                                                    osdwin_state->
+                                                    rec601_attenuation);
+               if (osdwin == OSDWIN_OSD1) {
+                       osd->is_blinking = 0;
+                       osd->blink = BLINK_X1;
+               }
+               break;
+       case WIN_VID0:
+       case WIN_VID1:
+               cfg->pixfmt = osd->yc_pixfmt;
+               _osd_set_layer_config(sd, layer, cfg);
+               break;
+       }
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static void osd_release_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       if (!win->is_allocated) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return;
+       }
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+       osd_init_layer(sd, layer);
+       spin_lock_irqsave(&osd->lock, flags);
+
+       win->is_allocated = 0;
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+}
+
+static int osd_request_layer(struct osd_state *sd, enum osd_layer layer)
+{
+       struct osd_state *osd = sd;
+       struct osd_window_state *win = &osd->win[layer];
+       unsigned long flags;
+
+       spin_lock_irqsave(&osd->lock, flags);
+
+       if (win->is_allocated) {
+               spin_unlock_irqrestore(&osd->lock, flags);
+               return -1;
+       }
+       win->is_allocated = 1;
+
+       spin_unlock_irqrestore(&osd->lock, flags);
+
+       return 0;
+}
+
+static void _osd_init(struct osd_state *sd)
+{
+       osd_write(sd, 0, OSD_MODE);
+       osd_write(sd, 0, OSD_VIDWINMD);
+       osd_write(sd, 0, OSD_OSDWIN0MD);
+       osd_write(sd, 0, OSD_OSDWIN1MD);
+       osd_write(sd, 0, OSD_RECTCUR);
+       osd_write(sd, 0, OSD_MISCCTL);
+}
+
+static void osd_set_left_margin(struct osd_state *sd, u32 val)
+{
+       osd_write(sd, val, OSD_BASEPX);
+}
+
+static void osd_set_top_margin(struct osd_state *sd, u32 val)
+{
+       osd_write(sd, val, OSD_BASEPY);
+}
+
+static int osd_initialize(struct osd_state *osd)
+{
+       if (osd == NULL)
+               return -ENODEV;
+       _osd_init(osd);
+
+       /* set default Cb/Cr order */
+       osd->yc_pixfmt = PIXFMT_YCbCrI;
+
+       _osd_set_field_inversion(osd, osd->field_inversion);
+       _osd_set_rom_clut(osd, osd->rom_clut);
+
+       osd_init_layer(osd, WIN_OSD0);
+       osd_init_layer(osd, WIN_VID0);
+       osd_init_layer(osd, WIN_OSD1);
+       osd_init_layer(osd, WIN_VID1);
+
+       return 0;
+}
+
+static const struct vpbe_osd_ops osd_ops = {
+       .initialize = osd_initialize,
+       .request_layer = osd_request_layer,
+       .release_layer = osd_release_layer,
+       .enable_layer = osd_enable_layer,
+       .disable_layer = osd_disable_layer,
+       .set_layer_config = osd_set_layer_config,
+       .get_layer_config = osd_get_layer_config,
+       .start_layer = osd_start_layer,
+       .set_left_margin = osd_set_left_margin,
+       .set_top_margin = osd_set_top_margin,
+};
+
+static int osd_probe(struct platform_device *pdev)
+{
+       struct osd_platform_data *pdata;
+       struct osd_state *osd;
+       struct resource *res;
+       int ret = 0;
+
+       osd = kzalloc(sizeof(struct osd_state), GFP_KERNEL);
+       if (osd == NULL)
+               return -ENOMEM;
+
+       osd->dev = &pdev->dev;
+       pdata = (struct osd_platform_data *)pdev->dev.platform_data;
+       osd->vpbe_type = (enum vpbe_version)pdata->vpbe_type;
+       if (NULL == pdev->dev.platform_data) {
+               dev_err(osd->dev, "No platform data defined for OSD"
+                       " sub device\n");
+               ret = -ENOENT;
+               goto free_mem;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(osd->dev, "Unable to get OSD register address map\n");
+               ret = -ENODEV;
+               goto free_mem;
+       }
+       osd->osd_base_phys = res->start;
+       osd->osd_size = res->end - res->start + 1;
+       if (!request_mem_region(osd->osd_base_phys, osd->osd_size,
+                               MODULE_NAME)) {
+               dev_err(osd->dev, "Unable to reserve OSD MMIO region\n");
+               ret = -ENODEV;
+               goto free_mem;
+       }
+       osd->osd_base = (unsigned long)ioremap_nocache(res->start,
+                                                       osd->osd_size);
+       if (!osd->osd_base) {
+               dev_err(osd->dev, "Unable to map the OSD region\n");
+               ret = -ENODEV;
+               goto release_mem_region;
+       }
+       spin_lock_init(&osd->lock);
+       osd->ops = osd_ops;
+       platform_set_drvdata(pdev, osd);
+       dev_notice(osd->dev, "OSD sub device probe success\n");
+       return ret;
+
+release_mem_region:
+       release_mem_region(osd->osd_base_phys, osd->osd_size);
+free_mem:
+       kfree(osd);
+       return ret;
+}
+
+static int osd_remove(struct platform_device *pdev)
+{
+       struct osd_state *osd = platform_get_drvdata(pdev);
+
+       iounmap((void *)osd->osd_base);
+       release_mem_region(osd->osd_base_phys, osd->osd_size);
+       kfree(osd);
+       return 0;
+}
+
+static struct platform_driver osd_driver = {
+       .probe          = osd_probe,
+       .remove         = osd_remove,
+       .driver         = {
+               .name   = MODULE_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int osd_init(void)
+{
+       if (platform_driver_register(&osd_driver)) {
+               printk(KERN_ERR "Unable to register davinci osd driver\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void osd_exit(void)
+{
+       platform_driver_unregister(&osd_driver);
+}
+
+module_init(osd_init);
+module_exit(osd_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DaVinci OSD Manager Driver");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/video/davinci/vpbe_osd_regs.h b/drivers/media/video/davinci/vpbe_osd_regs.h
new file mode 100644 (file)
index 0000000..584520f
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2006-2010 Texas Instruments 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_OSD_REGS_H
+#define _VPBE_OSD_REGS_H
+
+/* VPBE Global Registers */
+#define VPBE_PID                               0x0
+#define VPBE_PCR                               0x4
+
+/* VPSS CLock Registers */
+#define VPSSCLK_PID                            0x00
+#define VPSSCLK_CLKCTRL                                0x04
+
+/* VPSS Buffer Logic Registers */
+#define VPSSBL_PID                             0x00
+#define VPSSBL_PCR                             0x04
+#define VPSSBL_BCR                             0x08
+#define VPSSBL_INTSTAT                         0x0C
+#define VPSSBL_INTSEL                          0x10
+#define VPSSBL_EVTSEL                          0x14
+#define VPSSBL_MEMCTRL                         0x18
+#define VPSSBL_CCDCMUX                         0x1C
+
+/* DM365 ISP5 system configuration */
+#define ISP5_PID                               0x0
+#define ISP5_PCCR                              0x4
+#define ISP5_BCR                               0x8
+#define ISP5_INTSTAT                           0xC
+#define ISP5_INTSEL1                           0x10
+#define ISP5_INTSEL2                           0x14
+#define ISP5_INTSEL3                           0x18
+#define ISP5_EVTSEL                            0x1c
+#define ISP5_CCDCMUX                           0x20
+
+/* VPBE On-Screen Display Subsystem Registers (OSD) */
+#define OSD_MODE                               0x00
+#define OSD_VIDWINMD                           0x04
+#define OSD_OSDWIN0MD                          0x08
+#define OSD_OSDWIN1MD                          0x0C
+#define OSD_OSDATRMD                           0x0C
+#define OSD_RECTCUR                            0x10
+#define OSD_VIDWIN0OFST                                0x18
+#define OSD_VIDWIN1OFST                                0x1C
+#define OSD_OSDWIN0OFST                                0x20
+#define OSD_OSDWIN1OFST                                0x24
+#define OSD_VIDWINADH                          0x28
+#define OSD_VIDWIN0ADL                         0x2C
+#define OSD_VIDWIN0ADR                         0x2C
+#define OSD_VIDWIN1ADL                         0x30
+#define OSD_VIDWIN1ADR                         0x30
+#define OSD_OSDWINADH                          0x34
+#define OSD_OSDWIN0ADL                         0x38
+#define OSD_OSDWIN0ADR                         0x38
+#define OSD_OSDWIN1ADL                         0x3C
+#define OSD_OSDWIN1ADR                         0x3C
+#define OSD_BASEPX                             0x40
+#define OSD_BASEPY                             0x44
+#define OSD_VIDWIN0XP                          0x48
+#define OSD_VIDWIN0YP                          0x4C
+#define OSD_VIDWIN0XL                          0x50
+#define OSD_VIDWIN0YL                          0x54
+#define OSD_VIDWIN1XP                          0x58
+#define OSD_VIDWIN1YP                          0x5C
+#define OSD_VIDWIN1XL                          0x60
+#define OSD_VIDWIN1YL                          0x64
+#define OSD_OSDWIN0XP                          0x68
+#define OSD_OSDWIN0YP                          0x6C
+#define OSD_OSDWIN0XL                          0x70
+#define OSD_OSDWIN0YL                          0x74
+#define OSD_OSDWIN1XP                          0x78
+#define OSD_OSDWIN1YP                          0x7C
+#define OSD_OSDWIN1XL                          0x80
+#define OSD_OSDWIN1YL                          0x84
+#define OSD_CURXP                              0x88
+#define OSD_CURYP                              0x8C
+#define OSD_CURXL                              0x90
+#define OSD_CURYL                              0x94
+#define OSD_W0BMP01                            0xA0
+#define OSD_W0BMP23                            0xA4
+#define OSD_W0BMP45                            0xA8
+#define OSD_W0BMP67                            0xAC
+#define OSD_W0BMP89                            0xB0
+#define OSD_W0BMPAB                            0xB4
+#define OSD_W0BMPCD                            0xB8
+#define OSD_W0BMPEF                            0xBC
+#define OSD_W1BMP01                            0xC0
+#define OSD_W1BMP23                            0xC4
+#define OSD_W1BMP45                            0xC8
+#define OSD_W1BMP67                            0xCC
+#define OSD_W1BMP89                            0xD0
+#define OSD_W1BMPAB                            0xD4
+#define OSD_W1BMPCD                            0xD8
+#define OSD_W1BMPEF                            0xDC
+#define OSD_VBNDRY                             0xE0
+#define OSD_EXTMODE                            0xE4
+#define OSD_MISCCTL                            0xE8
+#define OSD_CLUTRAMYCB                         0xEC
+#define OSD_CLUTRAMCR                          0xF0
+#define OSD_TRANSPVAL                          0xF4
+#define OSD_TRANSPVALL                         0xF4
+#define OSD_TRANSPVALU                         0xF8
+#define OSD_TRANSPBMPIDX                       0xFC
+#define OSD_PPVWIN0ADR                         0xFC
+
+/* bit definitions */
+#define VPBE_PCR_VENC_DIV                      (1 << 1)
+#define VPBE_PCR_CLK_OFF                       (1 << 0)
+
+#define VPSSBL_INTSTAT_HSSIINT                 (1 << 14)
+#define VPSSBL_INTSTAT_CFALDINT                        (1 << 13)
+#define VPSSBL_INTSTAT_IPIPE_INT5              (1 << 12)
+#define VPSSBL_INTSTAT_IPIPE_INT4              (1 << 11)
+#define VPSSBL_INTSTAT_IPIPE_INT3              (1 << 10)
+#define VPSSBL_INTSTAT_IPIPE_INT2              (1 << 9)
+#define VPSSBL_INTSTAT_IPIPE_INT1              (1 << 8)
+#define VPSSBL_INTSTAT_IPIPE_INT0              (1 << 7)
+#define VPSSBL_INTSTAT_IPIPEIFINT              (1 << 6)
+#define VPSSBL_INTSTAT_OSDINT                  (1 << 5)
+#define VPSSBL_INTSTAT_VENCINT                 (1 << 4)
+#define VPSSBL_INTSTAT_H3AINT                  (1 << 3)
+#define VPSSBL_INTSTAT_CCDC_VDINT2             (1 << 2)
+#define VPSSBL_INTSTAT_CCDC_VDINT1             (1 << 1)
+#define VPSSBL_INTSTAT_CCDC_VDINT0             (1 << 0)
+
+/* DM365 ISP5 bit definitions */
+#define ISP5_INTSTAT_VENCINT                   (1 << 21)
+#define ISP5_INTSTAT_OSDINT                    (1 << 20)
+
+/* VMOD TVTYP options for HDMD=0 */
+#define SDTV_NTSC                              0
+#define SDTV_PAL                               1
+/* VMOD TVTYP options for HDMD=1 */
+#define HDTV_525P                              0
+#define HDTV_625P                              1
+#define HDTV_1080I                             2
+#define HDTV_720P                              3
+
+#define OSD_MODE_CS                            (1 << 15)
+#define OSD_MODE_OVRSZ                         (1 << 14)
+#define OSD_MODE_OHRSZ                         (1 << 13)
+#define OSD_MODE_EF                            (1 << 12)
+#define OSD_MODE_VVRSZ                         (1 << 11)
+#define OSD_MODE_VHRSZ                         (1 << 10)
+#define OSD_MODE_FSINV                         (1 << 9)
+#define OSD_MODE_BCLUT                         (1 << 8)
+#define OSD_MODE_CABG_SHIFT                    0
+#define OSD_MODE_CABG                          (0xff << 0)
+
+#define OSD_VIDWINMD_VFINV                     (1 << 15)
+#define OSD_VIDWINMD_V1EFC                     (1 << 14)
+#define OSD_VIDWINMD_VHZ1_SHIFT                        12
+#define OSD_VIDWINMD_VHZ1                      (3 << 12)
+#define OSD_VIDWINMD_VVZ1_SHIFT                        10
+#define OSD_VIDWINMD_VVZ1                      (3 << 10)
+#define OSD_VIDWINMD_VFF1                      (1 << 9)
+#define OSD_VIDWINMD_ACT1                      (1 << 8)
+#define OSD_VIDWINMD_V0EFC                     (1 << 6)
+#define OSD_VIDWINMD_VHZ0_SHIFT                        4
+#define OSD_VIDWINMD_VHZ0                      (3 << 4)
+#define OSD_VIDWINMD_VVZ0_SHIFT                        2
+#define OSD_VIDWINMD_VVZ0                      (3 << 2)
+#define OSD_VIDWINMD_VFF0                      (1 << 1)
+#define OSD_VIDWINMD_ACT0                      (1 << 0)
+
+#define OSD_OSDWIN0MD_ATN0E                    (1 << 14)
+#define OSD_OSDWIN0MD_RGB0E                    (1 << 13)
+#define OSD_OSDWIN0MD_BMP0MD_SHIFT             13
+#define OSD_OSDWIN0MD_BMP0MD                   (3 << 13)
+#define OSD_OSDWIN0MD_CLUTS0                   (1 << 12)
+#define OSD_OSDWIN0MD_OHZ0_SHIFT               10
+#define OSD_OSDWIN0MD_OHZ0                     (3 << 10)
+#define OSD_OSDWIN0MD_OVZ0_SHIFT               8
+#define OSD_OSDWIN0MD_OVZ0                     (3 << 8)
+#define OSD_OSDWIN0MD_BMW0_SHIFT               6
+#define OSD_OSDWIN0MD_BMW0                     (3 << 6)
+#define OSD_OSDWIN0MD_BLND0_SHIFT              3
+#define OSD_OSDWIN0MD_BLND0                    (7 << 3)
+#define OSD_OSDWIN0MD_TE0                      (1 << 2)
+#define OSD_OSDWIN0MD_OFF0                     (1 << 1)
+#define OSD_OSDWIN0MD_OACT0                    (1 << 0)
+
+#define OSD_OSDWIN1MD_OASW                     (1 << 15)
+#define OSD_OSDWIN1MD_ATN1E                    (1 << 14)
+#define OSD_OSDWIN1MD_RGB1E                    (1 << 13)
+#define OSD_OSDWIN1MD_BMP1MD_SHIFT             13
+#define OSD_OSDWIN1MD_BMP1MD                   (3 << 13)
+#define OSD_OSDWIN1MD_CLUTS1                   (1 << 12)
+#define OSD_OSDWIN1MD_OHZ1_SHIFT               10
+#define OSD_OSDWIN1MD_OHZ1                     (3 << 10)
+#define OSD_OSDWIN1MD_OVZ1_SHIFT               8
+#define OSD_OSDWIN1MD_OVZ1                     (3 << 8)
+#define OSD_OSDWIN1MD_BMW1_SHIFT               6
+#define OSD_OSDWIN1MD_BMW1                     (3 << 6)
+#define OSD_OSDWIN1MD_BLND1_SHIFT              3
+#define OSD_OSDWIN1MD_BLND1                    (7 << 3)
+#define OSD_OSDWIN1MD_TE1                      (1 << 2)
+#define OSD_OSDWIN1MD_OFF1                     (1 << 1)
+#define OSD_OSDWIN1MD_OACT1                    (1 << 0)
+
+#define OSD_OSDATRMD_OASW                      (1 << 15)
+#define OSD_OSDATRMD_OHZA_SHIFT                        10
+#define OSD_OSDATRMD_OHZA                      (3 << 10)
+#define OSD_OSDATRMD_OVZA_SHIFT                        8
+#define OSD_OSDATRMD_OVZA                      (3 << 8)
+#define OSD_OSDATRMD_BLNKINT_SHIFT             6
+#define OSD_OSDATRMD_BLNKINT                   (3 << 6)
+#define OSD_OSDATRMD_OFFA                      (1 << 1)
+#define OSD_OSDATRMD_BLNK                      (1 << 0)
+
+#define OSD_RECTCUR_RCAD_SHIFT                 8
+#define OSD_RECTCUR_RCAD                       (0xff << 8)
+#define OSD_RECTCUR_CLUTSR                     (1 << 7)
+#define OSD_RECTCUR_RCHW_SHIFT                 4
+#define OSD_RECTCUR_RCHW                       (7 << 4)
+#define OSD_RECTCUR_RCVW_SHIFT                 1
+#define OSD_RECTCUR_RCVW                       (7 << 1)
+#define OSD_RECTCUR_RCACT                      (1 << 0)
+
+#define OSD_VIDWIN0OFST_V0LO                   (0x1ff << 0)
+
+#define OSD_VIDWIN1OFST_V1LO                   (0x1ff << 0)
+
+#define OSD_OSDWIN0OFST_O0LO                   (0x1ff << 0)
+
+#define OSD_OSDWIN1OFST_O1LO                   (0x1ff << 0)
+
+#define OSD_WINOFST_AH_SHIFT                   9
+
+#define OSD_VIDWIN0OFST_V0AH                   (0xf << 9)
+#define OSD_VIDWIN1OFST_V1AH                   (0xf << 9)
+#define OSD_OSDWIN0OFST_O0AH                   (0xf << 9)
+#define OSD_OSDWIN1OFST_O1AH                   (0xf << 9)
+
+#define OSD_VIDWINADH_V1AH_SHIFT               8
+#define OSD_VIDWINADH_V1AH                     (0x7f << 8)
+#define OSD_VIDWINADH_V0AH_SHIFT               0
+#define OSD_VIDWINADH_V0AH                     (0x7f << 0)
+
+#define OSD_VIDWIN0ADL_V0AL                    (0xffff << 0)
+
+#define OSD_VIDWIN1ADL_V1AL                    (0xffff << 0)
+
+#define OSD_OSDWINADH_O1AH_SHIFT               8
+#define OSD_OSDWINADH_O1AH                     (0x7f << 8)
+#define OSD_OSDWINADH_O0AH_SHIFT               0
+#define OSD_OSDWINADH_O0AH                     (0x7f << 0)
+
+#define OSD_OSDWIN0ADL_O0AL                    (0xffff << 0)
+
+#define OSD_OSDWIN1ADL_O1AL                    (0xffff << 0)
+
+#define OSD_BASEPX_BPX                         (0x3ff << 0)
+
+#define OSD_BASEPY_BPY                         (0x1ff << 0)
+
+#define OSD_VIDWIN0XP_V0X                      (0x7ff << 0)
+
+#define OSD_VIDWIN0YP_V0Y                      (0x7ff << 0)
+
+#define OSD_VIDWIN0XL_V0W                      (0x7ff << 0)
+
+#define OSD_VIDWIN0YL_V0H                      (0x7ff << 0)
+
+#define OSD_VIDWIN1XP_V1X                      (0x7ff << 0)
+
+#define OSD_VIDWIN1YP_V1Y                      (0x7ff << 0)
+
+#define OSD_VIDWIN1XL_V1W                      (0x7ff << 0)
+
+#define OSD_VIDWIN1YL_V1H                      (0x7ff << 0)
+
+#define OSD_OSDWIN0XP_W0X                      (0x7ff << 0)
+
+#define OSD_OSDWIN0YP_W0Y                      (0x7ff << 0)
+
+#define OSD_OSDWIN0XL_W0W                      (0x7ff << 0)
+
+#define OSD_OSDWIN0YL_W0H                      (0x7ff << 0)
+
+#define OSD_OSDWIN1XP_W1X                      (0x7ff << 0)
+
+#define OSD_OSDWIN1YP_W1Y                      (0x7ff << 0)
+
+#define OSD_OSDWIN1XL_W1W                      (0x7ff << 0)
+
+#define OSD_OSDWIN1YL_W1H                      (0x7ff << 0)
+
+#define OSD_CURXP_RCSX                         (0x7ff << 0)
+
+#define OSD_CURYP_RCSY                         (0x7ff << 0)
+
+#define OSD_CURXL_RCSW                         (0x7ff << 0)
+
+#define OSD_CURYL_RCSH                         (0x7ff << 0)
+
+#define OSD_EXTMODE_EXPMDSEL                   (1 << 15)
+#define OSD_EXTMODE_SCRNHEXP_SHIFT             13
+#define OSD_EXTMODE_SCRNHEXP                   (3 << 13)
+#define OSD_EXTMODE_SCRNVEXP                   (1 << 12)
+#define OSD_EXTMODE_OSD1BLDCHR                 (1 << 11)
+#define OSD_EXTMODE_OSD0BLDCHR                 (1 << 10)
+#define OSD_EXTMODE_ATNOSD1EN                  (1 << 9)
+#define OSD_EXTMODE_ATNOSD0EN                  (1 << 8)
+#define OSD_EXTMODE_OSDHRSZ15                  (1 << 7)
+#define OSD_EXTMODE_VIDHRSZ15                  (1 << 6)
+#define OSD_EXTMODE_ZMFILV1HEN                 (1 << 5)
+#define OSD_EXTMODE_ZMFILV1VEN                 (1 << 4)
+#define OSD_EXTMODE_ZMFILV0HEN                 (1 << 3)
+#define OSD_EXTMODE_ZMFILV0VEN                 (1 << 2)
+#define OSD_EXTMODE_EXPFILHEN                  (1 << 1)
+#define OSD_EXTMODE_EXPFILVEN                  (1 << 0)
+
+#define OSD_MISCCTL_BLDSEL                     (1 << 15)
+#define OSD_MISCCTL_S420D                      (1 << 14)
+#define OSD_MISCCTL_BMAPT                      (1 << 13)
+#define OSD_MISCCTL_DM365M                     (1 << 12)
+#define OSD_MISCCTL_RGBEN                      (1 << 7)
+#define OSD_MISCCTL_RGBWIN                     (1 << 6)
+#define OSD_MISCCTL_DMANG                      (1 << 6)
+#define OSD_MISCCTL_TMON                       (1 << 5)
+#define OSD_MISCCTL_RSEL                       (1 << 4)
+#define OSD_MISCCTL_CPBSY                      (1 << 3)
+#define OSD_MISCCTL_PPSW                       (1 << 2)
+#define OSD_MISCCTL_PPRV                       (1 << 1)
+
+#define OSD_CLUTRAMYCB_Y_SHIFT                 8
+#define OSD_CLUTRAMYCB_Y                       (0xff << 8)
+#define OSD_CLUTRAMYCB_CB_SHIFT                        0
+#define OSD_CLUTRAMYCB_CB                      (0xff << 0)
+
+#define OSD_CLUTRAMCR_CR_SHIFT                 8
+#define OSD_CLUTRAMCR_CR                       (0xff << 8)
+#define OSD_CLUTRAMCR_CADDR_SHIFT              0
+#define OSD_CLUTRAMCR_CADDR                    (0xff << 0)
+
+#define OSD_TRANSPVAL_RGBTRANS                 (0xffff << 0)
+
+#define OSD_TRANSPVALL_RGBL                    (0xffff << 0)
+
+#define OSD_TRANSPVALU_Y_SHIFT                 8
+#define OSD_TRANSPVALU_Y                       (0xff << 8)
+#define OSD_TRANSPVALU_RGBU_SHIFT              0
+#define OSD_TRANSPVALU_RGBU                    (0xff << 0)
+
+#define OSD_TRANSPBMPIDX_BMP1_SHIFT            8
+#define OSD_TRANSPBMPIDX_BMP1                  (0xff << 8)
+#define OSD_TRANSPBMPIDX_BMP0_SHIFT            0
+#define OSD_TRANSPBMPIDX_BMP0                  0xff
+
+#endif                         /* _DAVINCI_VPBE_H_ */
diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c
new file mode 100644 (file)
index 0000000..03a3e5c
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2010 Texas Instruments 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/mux.h>
+#include <mach/io.h>
+#include <mach/i2c.h>
+
+#include <linux/io.h>
+
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpss.h>
+#include <media/v4l2-device.h>
+
+#include "vpbe_venc_regs.h"
+
+#define MODULE_NAME    VPBE_VENC_SUBDEV_NAME
+
+static int debug = 2;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-2");
+
+struct venc_state {
+       struct v4l2_subdev sd;
+       struct venc_callback *callback;
+       struct venc_platform_data *pdata;
+       struct device *pdev;
+       u32 output;
+       v4l2_std_id std;
+       spinlock_t lock;
+       void __iomem *venc_base;
+       void __iomem *vdaccfg_reg;
+};
+
+static inline struct venc_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct venc_state, sd);
+}
+
+static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset)
+{
+       struct venc_state *venc = to_state(sd);
+
+       return readl(venc->venc_base + offset);
+}
+
+static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val)
+{
+       struct venc_state *venc = to_state(sd);
+
+       writel(val, (venc->venc_base + offset));
+
+       return val;
+}
+
+static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset,
+                                u32 val, u32 mask)
+{
+       u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask);
+
+       venc_write(sd, offset, new_val);
+
+       return new_val;
+}
+
+static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val)
+{
+       struct venc_state *venc = to_state(sd);
+
+       writel(val, venc->vdaccfg_reg);
+
+       val = readl(venc->vdaccfg_reg);
+
+       return val;
+}
+
+/* This function sets the dac of the VPBE for various outputs
+ */
+static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index)
+{
+       switch (out_index) {
+       case 0:
+               v4l2_dbg(debug, 1, sd, "Setting output to Composite\n");
+               venc_write(sd, VENC_DACSEL, 0);
+               break;
+       case 1:
+               v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n");
+               venc_write(sd, VENC_DACSEL, 0x210);
+               break;
+       case  2:
+               venc_write(sd, VENC_DACSEL, 0x543);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
+{
+       v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n");
+
+       if (benable) {
+               venc_write(sd, VENC_VMOD, 0);
+               venc_write(sd, VENC_CVBS, 0);
+               venc_write(sd, VENC_LCDOUT, 0);
+               venc_write(sd, VENC_HSPLS, 0);
+               venc_write(sd, VENC_HSTART, 0);
+               venc_write(sd, VENC_HVALID, 0);
+               venc_write(sd, VENC_HINT, 0);
+               venc_write(sd, VENC_VSPLS, 0);
+               venc_write(sd, VENC_VSTART, 0);
+               venc_write(sd, VENC_VVALID, 0);
+               venc_write(sd, VENC_VINT, 0);
+               venc_write(sd, VENC_YCCCTL, 0);
+               venc_write(sd, VENC_DACSEL, 0);
+
+       } else {
+               venc_write(sd, VENC_VMOD, 0);
+               /* disable VCLK output pin enable */
+               venc_write(sd, VENC_VIDCTL, 0x141);
+
+               /* Disable output sync pins */
+               venc_write(sd, VENC_SYNCCTL, 0);
+
+               /* Disable DCLOCK */
+               venc_write(sd, VENC_DCLKCTL, 0);
+               venc_write(sd, VENC_DRGBX1, 0x0000057C);
+
+               /* Disable LCD output control (accepting default polarity) */
+               venc_write(sd, VENC_LCDOUT, 0);
+               venc_write(sd, VENC_CMPNT, 0x100);
+               venc_write(sd, VENC_HSPLS, 0);
+               venc_write(sd, VENC_HINT, 0);
+               venc_write(sd, VENC_HSTART, 0);
+               venc_write(sd, VENC_HVALID, 0);
+
+               venc_write(sd, VENC_VSPLS, 0);
+               venc_write(sd, VENC_VINT, 0);
+               venc_write(sd, VENC_VSTART, 0);
+               venc_write(sd, VENC_VVALID, 0);
+
+               venc_write(sd, VENC_HSDLY, 0);
+               venc_write(sd, VENC_VSDLY, 0);
+
+               venc_write(sd, VENC_YCCCTL, 0);
+               venc_write(sd, VENC_VSTARTA, 0);
+
+               /* Set OSD clock and OSD Sync Adavance registers */
+               venc_write(sd, VENC_OSDCLK0, 1);
+               venc_write(sd, VENC_OSDCLK1, 2);
+       }
+}
+
+/*
+ * setting NTSC mode
+ */
+static int venc_set_ntsc(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+       struct venc_platform_data *pdata = venc->pdata;
+
+       v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n");
+
+       /* Setup clock at VPSS & VENC for SD */
+       vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1);
+       if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0)
+               return -EINVAL;
+
+       venc_enabledigitaloutput(sd, 0);
+
+       /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
+       venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
+       /* Set REC656 Mode */
+       venc_write(sd, VENC_YCCCTL, 0x1);
+       venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ);
+       venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS);
+
+       venc_write(sd, VENC_VMOD, 0);
+       venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+                       VENC_VMOD_VIE);
+       venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD);
+       venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT),
+                       VENC_VMOD_TVTYP);
+       venc_write(sd, VENC_DACTST, 0x0);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+       return 0;
+}
+
+/*
+ * setting PAL mode
+ */
+static int venc_set_pal(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+
+       v4l2_dbg(debug, 2, sd, "venc_set_pal\n");
+
+       /* Setup clock at VPSS & VENC for SD */
+       vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1);
+       if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0)
+               return -EINVAL;
+
+       venc_enabledigitaloutput(sd, 0);
+
+       /* to set VENC CLK DIV to 1 - final clock is 54 MHz */
+       venc_modify(sd, VENC_VIDCTL, 0, 1 << 1);
+       /* Set REC656 Mode */
+       venc_write(sd, VENC_YCCCTL, 0x1);
+
+       venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT,
+                       VENC_SYNCCTL_OVD);
+       venc_write(sd, VENC_VMOD, 0);
+       venc_modify(sd, VENC_VMOD,
+                       (1 << VENC_VMOD_VIE_SHIFT),
+                       VENC_VMOD_VIE);
+       venc_modify(sd, VENC_VMOD,
+                       (0 << VENC_VMOD_VMD), VENC_VMOD_VMD);
+       venc_modify(sd, VENC_VMOD,
+                       (1 << VENC_VMOD_TVTYP_SHIFT),
+                       VENC_VMOD_TVTYP);
+       venc_write(sd, VENC_DACTST, 0x0);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+       return 0;
+}
+
+/*
+ * venc_set_480p59_94
+ *
+ * This function configures the video encoder to EDTV(525p) component setting.
+ */
+static int venc_set_480p59_94(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+       struct venc_platform_data *pdata = venc->pdata;
+
+       v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n");
+
+       /* Setup clock at VPSS & VENC for SD */
+       if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0)
+               return -EINVAL;
+
+       venc_enabledigitaloutput(sd, 0);
+
+       venc_write(sd, VENC_OSDCLK0, 0);
+       venc_write(sd, VENC_OSDCLK1, 1);
+       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
+                   VENC_VDPRO_DAFRQ);
+       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
+                   VENC_VDPRO_DAUPS);
+       venc_write(sd, VENC_VMOD, 0);
+       venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+                   VENC_VMOD_VIE);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+       venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT),
+                   VENC_VMOD_TVTYP);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 <<
+                   VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD);
+
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+       return 0;
+}
+
+/*
+ * venc_set_625p
+ *
+ * This function configures the video encoder to HDTV(625p) component setting
+ */
+static int venc_set_576p50(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+       struct venc_platform_data *pdata = venc->pdata;
+
+       v4l2_dbg(debug, 2, sd, "venc_set_576p50\n");
+
+       /* Setup clock at VPSS & VENC for SD */
+       if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0)
+               return -EINVAL;
+
+       venc_enabledigitaloutput(sd, 0);
+
+       venc_write(sd, VENC_OSDCLK0, 0);
+       venc_write(sd, VENC_OSDCLK1, 1);
+
+       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ,
+                   VENC_VDPRO_DAFRQ);
+       venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS,
+                   VENC_VDPRO_DAUPS);
+
+       venc_write(sd, VENC_VMOD, 0);
+       venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT),
+                   VENC_VMOD_VIE);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD);
+       venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT),
+                   VENC_VMOD_TVTYP);
+
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 <<
+                   VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD);
+       venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC);
+
+       return 0;
+}
+
+static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+       v4l2_dbg(debug, 1, sd, "venc_s_std_output\n");
+
+       if (norm & V4L2_STD_525_60)
+               return venc_set_ntsc(sd);
+       else if (norm & V4L2_STD_625_50)
+               return venc_set_pal(sd);
+
+       return -EINVAL;
+}
+
+static int venc_s_dv_preset(struct v4l2_subdev *sd,
+                           struct v4l2_dv_preset *dv_preset)
+{
+       v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n");
+
+       if (dv_preset->preset == V4L2_DV_576P50)
+               return venc_set_576p50(sd);
+       else if (dv_preset->preset == V4L2_DV_480P59_94)
+               return venc_set_480p59_94(sd);
+
+       return -EINVAL;
+}
+
+static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
+                         u32 config)
+{
+       struct venc_state *venc = to_state(sd);
+       int ret;
+
+       v4l2_dbg(debug, 1, sd, "venc_s_routing\n");
+
+       ret = venc_set_dac(sd, output);
+       if (!ret)
+               venc->output = output;
+
+       return ret;
+}
+
+static long venc_ioctl(struct v4l2_subdev *sd,
+                       unsigned int cmd,
+                       void *arg)
+{
+       u32 val;
+
+       switch (cmd) {
+       case VENC_GET_FLD:
+               val = venc_read(sd, VENC_VSTAT);
+               *((int *)arg) = ((val & VENC_VSTAT_FIDST) ==
+               VENC_VSTAT_FIDST);
+               break;
+       default:
+               v4l2_err(sd, "Wrong IOCTL cmd\n");
+               break;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops venc_core_ops = {
+       .ioctl      = venc_ioctl,
+};
+
+static const struct v4l2_subdev_video_ops venc_video_ops = {
+       .s_routing = venc_s_routing,
+       .s_std_output = venc_s_std_output,
+       .s_dv_preset = venc_s_dv_preset,
+};
+
+static const struct v4l2_subdev_ops venc_ops = {
+       .core = &venc_core_ops,
+       .video = &venc_video_ops,
+};
+
+static int venc_initialize(struct v4l2_subdev *sd)
+{
+       struct venc_state *venc = to_state(sd);
+       int ret;
+
+       /* Set default to output to composite and std to NTSC */
+       venc->output = 0;
+       venc->std = V4L2_STD_525_60;
+
+       ret = venc_s_routing(sd, 0, venc->output, 0);
+       if (ret < 0) {
+               v4l2_err(sd, "Error setting output during init\n");
+               return -EINVAL;
+       }
+
+       ret = venc_s_std_output(sd, venc->std);
+       if (ret < 0) {
+               v4l2_err(sd, "Error setting std during init\n");
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+static int venc_device_get(struct device *dev, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct venc_state **venc = data;
+
+       if (strcmp(MODULE_NAME, pdev->name) == 0)
+               *venc = platform_get_drvdata(pdev);
+
+       return 0;
+}
+
+struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev,
+               const char *venc_name)
+{
+       struct venc_state *venc;
+       int err;
+
+       err = bus_for_each_dev(&platform_bus_type, NULL, &venc,
+                       venc_device_get);
+       if (venc == NULL)
+               return NULL;
+
+       v4l2_subdev_init(&venc->sd, &venc_ops);
+
+       strcpy(venc->sd.name, venc_name);
+       if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) {
+               v4l2_err(v4l2_dev,
+                       "vpbe unable to register venc sub device\n");
+               return NULL;
+       }
+       if (venc_initialize(&venc->sd)) {
+               v4l2_err(v4l2_dev,
+                       "vpbe venc initialization failed\n");
+               return NULL;
+       }
+
+       return &venc->sd;
+}
+EXPORT_SYMBOL(venc_sub_dev_init);
+
+static int venc_probe(struct platform_device *pdev)
+{
+       struct venc_state *venc;
+       struct resource *res;
+       int ret;
+
+       venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL);
+       if (venc == NULL)
+               return -ENOMEM;
+
+       venc->pdev = &pdev->dev;
+       venc->pdata = pdev->dev.platform_data;
+       if (NULL == venc->pdata) {
+               dev_err(venc->pdev, "Unable to get platform data for"
+                       " VENC sub device");
+               ret = -ENOENT;
+               goto free_mem;
+       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(venc->pdev,
+                       "Unable to get VENC register address map\n");
+               ret = -ENODEV;
+               goto free_mem;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res), "venc")) {
+               dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n");
+               ret = -ENODEV;
+               goto free_mem;
+       }
+
+       venc->venc_base = ioremap_nocache(res->start, resource_size(res));
+       if (!venc->venc_base) {
+               dev_err(venc->pdev, "Unable to map VENC IO space\n");
+               ret = -ENODEV;
+               goto release_venc_mem_region;
+       }
+
+       spin_lock_init(&venc->lock);
+       platform_set_drvdata(pdev, venc);
+       dev_notice(venc->pdev, "VENC sub device probe success\n");
+       return 0;
+
+release_venc_mem_region:
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, resource_size(res));
+free_mem:
+       kfree(venc);
+       return ret;
+}
+
+static int venc_remove(struct platform_device *pdev)
+{
+       struct venc_state *venc = platform_get_drvdata(pdev);
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       iounmap((void *)venc->venc_base);
+       release_mem_region(res->start, resource_size(res));
+       kfree(venc);
+
+       return 0;
+}
+
+static struct platform_driver venc_driver = {
+       .probe          = venc_probe,
+       .remove         = venc_remove,
+       .driver         = {
+               .name   = MODULE_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int venc_init(void)
+{
+       if (platform_driver_register(&venc_driver)) {
+               printk(KERN_ERR "Unable to register venc driver\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void venc_exit(void)
+{
+       platform_driver_unregister(&venc_driver);
+       return;
+}
+
+module_init(venc_init);
+module_exit(venc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VPBE VENC Driver");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/media/video/davinci/vpbe_venc_regs.h b/drivers/media/video/davinci/vpbe_venc_regs.h
new file mode 100644 (file)
index 0000000..947cb15
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2006-2010 Texas Instruments 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 version 2..
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_VENC_REGS_H
+#define _VPBE_VENC_REGS_H
+
+/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */
+#define VENC_VMOD                              0x00
+#define VENC_VIDCTL                            0x04
+#define VENC_VDPRO                             0x08
+#define VENC_SYNCCTL                           0x0C
+#define VENC_HSPLS                             0x10
+#define VENC_VSPLS                             0x14
+#define VENC_HINT                              0x18
+#define VENC_HSTART                            0x1C
+#define VENC_HVALID                            0x20
+#define VENC_VINT                              0x24
+#define VENC_VSTART                            0x28
+#define VENC_VVALID                            0x2C
+#define VENC_HSDLY                             0x30
+#define VENC_VSDLY                             0x34
+#define VENC_YCCCTL                            0x38
+#define VENC_RGBCTL                            0x3C
+#define VENC_RGBCLP                            0x40
+#define VENC_LINECTL                           0x44
+#define VENC_CULLLINE                          0x48
+#define VENC_LCDOUT                            0x4C
+#define VENC_BRTS                              0x50
+#define VENC_BRTW                              0x54
+#define VENC_ACCTL                             0x58
+#define VENC_PWMP                              0x5C
+#define VENC_PWMW                              0x60
+#define VENC_DCLKCTL                           0x64
+#define VENC_DCLKPTN0                          0x68
+#define VENC_DCLKPTN1                          0x6C
+#define VENC_DCLKPTN2                          0x70
+#define VENC_DCLKPTN3                          0x74
+#define VENC_DCLKPTN0A                         0x78
+#define VENC_DCLKPTN1A                         0x7C
+#define VENC_DCLKPTN2A                         0x80
+#define VENC_DCLKPTN3A                         0x84
+#define VENC_DCLKHS                            0x88
+#define VENC_DCLKHSA                           0x8C
+#define VENC_DCLKHR                            0x90
+#define VENC_DCLKVS                            0x94
+#define VENC_DCLKVR                            0x98
+#define VENC_CAPCTL                            0x9C
+#define VENC_CAPDO                             0xA0
+#define VENC_CAPDE                             0xA4
+#define VENC_ATR0                              0xA8
+#define VENC_ATR1                              0xAC
+#define VENC_ATR2                              0xB0
+#define VENC_VSTAT                             0xB8
+#define VENC_RAMADR                            0xBC
+#define VENC_RAMPORT                           0xC0
+#define VENC_DACTST                            0xC4
+#define VENC_YCOLVL                            0xC8
+#define VENC_SCPROG                            0xCC
+#define VENC_CVBS                              0xDC
+#define VENC_CMPNT                             0xE0
+#define VENC_ETMG0                             0xE4
+#define VENC_ETMG1                             0xE8
+#define VENC_ETMG2                             0xEC
+#define VENC_ETMG3                             0xF0
+#define VENC_DACSEL                            0xF4
+#define VENC_ARGBX0                            0x100
+#define VENC_ARGBX1                            0x104
+#define VENC_ARGBX2                            0x108
+#define VENC_ARGBX3                            0x10C
+#define VENC_ARGBX4                            0x110
+#define VENC_DRGBX0                            0x114
+#define VENC_DRGBX1                            0x118
+#define VENC_DRGBX2                            0x11C
+#define VENC_DRGBX3                            0x120
+#define VENC_DRGBX4                            0x124
+#define VENC_VSTARTA                           0x128
+#define VENC_OSDCLK0                           0x12C
+#define VENC_OSDCLK1                           0x130
+#define VENC_HVLDCL0                           0x134
+#define VENC_HVLDCL1                           0x138
+#define VENC_OSDHADV                           0x13C
+#define VENC_CLKCTL                            0x140
+#define VENC_GAMCTL                            0x144
+#define VENC_XHINTVL                           0x174
+
+/* bit definitions */
+#define VPBE_PCR_VENC_DIV                      (1 << 1)
+#define VPBE_PCR_CLK_OFF                       (1 << 0)
+
+#define VENC_VMOD_VDMD_SHIFT                   12
+#define VENC_VMOD_VDMD_YCBCR16                 0
+#define VENC_VMOD_VDMD_YCBCR8                  1
+#define VENC_VMOD_VDMD_RGB666                  2
+#define VENC_VMOD_VDMD_RGB8                    3
+#define VENC_VMOD_VDMD_EPSON                   4
+#define VENC_VMOD_VDMD_CASIO                   5
+#define VENC_VMOD_VDMD_UDISPQVGA               6
+#define VENC_VMOD_VDMD_STNLCD                  7
+#define VENC_VMOD_VIE_SHIFT                    1
+#define VENC_VMOD_VDMD                         (7 << 12)
+#define VENC_VMOD_ITLCL                                (1 << 11)
+#define VENC_VMOD_ITLC                         (1 << 10)
+#define VENC_VMOD_NSIT                         (1 << 9)
+#define VENC_VMOD_HDMD                         (1 << 8)
+#define VENC_VMOD_TVTYP_SHIFT                  6
+#define VENC_VMOD_TVTYP                                (3 << 6)
+#define VENC_VMOD_SLAVE                                (1 << 5)
+#define VENC_VMOD_VMD                          (1 << 4)
+#define VENC_VMOD_BLNK                         (1 << 3)
+#define VENC_VMOD_VIE                          (1 << 1)
+#define VENC_VMOD_VENC                         (1 << 0)
+
+/* VMOD TVTYP options for HDMD=0 */
+#define SDTV_NTSC                              0
+#define SDTV_PAL                               1
+/* VMOD TVTYP options for HDMD=1 */
+#define HDTV_525P                              0
+#define HDTV_625P                              1
+#define HDTV_1080I                             2
+#define HDTV_720P                              3
+
+#define VENC_VIDCTL_VCLKP                      (1 << 14)
+#define VENC_VIDCTL_VCLKE_SHIFT                        13
+#define VENC_VIDCTL_VCLKE                      (1 << 13)
+#define VENC_VIDCTL_VCLKZ_SHIFT                        12
+#define VENC_VIDCTL_VCLKZ                      (1 << 12)
+#define VENC_VIDCTL_SYDIR_SHIFT                        8
+#define VENC_VIDCTL_SYDIR                      (1 << 8)
+#define VENC_VIDCTL_DOMD_SHIFT                 4
+#define VENC_VIDCTL_DOMD                       (3 << 4)
+#define VENC_VIDCTL_YCDIR_SHIFT                        0
+#define VENC_VIDCTL_YCDIR                      (1 << 0)
+
+#define VENC_VDPRO_ATYCC_SHIFT                 5
+#define VENC_VDPRO_ATYCC                       (1 << 5)
+#define VENC_VDPRO_ATCOM_SHIFT                 4
+#define VENC_VDPRO_ATCOM                       (1 << 4)
+#define VENC_VDPRO_DAFRQ                       (1 << 3)
+#define VENC_VDPRO_DAUPS                       (1 << 2)
+#define VENC_VDPRO_CUPS                                (1 << 1)
+#define VENC_VDPRO_YUPS                                (1 << 0)
+
+#define VENC_SYNCCTL_VPL_SHIFT                 3
+#define VENC_SYNCCTL_VPL                       (1 << 3)
+#define VENC_SYNCCTL_HPL_SHIFT                 2
+#define VENC_SYNCCTL_HPL                       (1 << 2)
+#define VENC_SYNCCTL_SYEV_SHIFT                        1
+#define VENC_SYNCCTL_SYEV                      (1 << 1)
+#define VENC_SYNCCTL_SYEH_SHIFT                        0
+#define VENC_SYNCCTL_SYEH                      (1 << 0)
+#define VENC_SYNCCTL_OVD_SHIFT                 14
+#define VENC_SYNCCTL_OVD                       (1 << 14)
+
+#define VENC_DCLKCTL_DCKEC_SHIFT               11
+#define VENC_DCLKCTL_DCKEC                     (1 << 11)
+#define VENC_DCLKCTL_DCKPW_SHIFT               0
+#define VENC_DCLKCTL_DCKPW                     (0x3f << 0)
+
+#define VENC_VSTAT_FIDST                       (1 << 4)
+
+#define VENC_CMPNT_MRGB_SHIFT                  14
+#define VENC_CMPNT_MRGB                                (1 << 14)
+
+#endif                         /* _VPBE_VENC_REGS_H */
index d93ad74a34c5fbe46631bb579836b03b6e4bb42a..49e4deb500430faf3be60475b5062cf7e5141921 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -44,6 +43,7 @@
 
 MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(VPIF_CAPTURE_VERSION);
 
 #define vpif_err(fmt, arg...)  v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg)
 #define vpif_dbg(level, debug, fmt, arg...)    \
@@ -1677,7 +1677,6 @@ static int vpif_querycap(struct file *file, void  *priv,
 {
        struct vpif_capture_config *config = vpif_dev->platform_data;
 
-       cap->version = VPIF_CAPTURE_VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
        strlcpy(cap->driver, "vpif capture", sizeof(cap->driver));
        strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info));
@@ -2211,10 +2210,8 @@ static __init int vpif_probe(struct platform_device *pdev)
                vfd->v4l2_dev = &vpif_obj.v4l2_dev;
                vfd->release = video_device_release;
                snprintf(vfd->name, sizeof(vfd->name),
-                        "DM646x_VPIFCapture_DRIVER_V%d.%d.%d",
-                        (VPIF_CAPTURE_VERSION_CODE >> 16) & 0xff,
-                        (VPIF_CAPTURE_VERSION_CODE >> 8) & 0xff,
-                        (VPIF_CAPTURE_VERSION_CODE) & 0xff);
+                        "DM646x_VPIFCapture_DRIVER_V%s",
+                        VPIF_CAPTURE_VERSION);
                /* Set video_dev to the video device */
                ch->video_dev = vfd;
        }
index 7a4196dfdce19c649acb61b07e5f3600b719fc33..064550f5ce4adcdf638d943e6d2a7bdfbdf39451 100644 (file)
@@ -23,7 +23,6 @@
 
 /* Header files */
 #include <linux/videodev2.h>
-#include <linux/version.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/videobuf-core.h>
 #include "vpif.h"
 
 /* Macros */
-#define VPIF_MAJOR_RELEASE             0
-#define VPIF_MINOR_RELEASE             0
-#define VPIF_BUILD                     1
-#define VPIF_CAPTURE_VERSION_CODE      ((VPIF_MAJOR_RELEASE << 16) | \
-       (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD)
+#define VPIF_CAPTURE_VERSION           "0.0.2"
 
 #define VPIF_VALID_FIELD(field)                (((V4L2_FIELD_ANY == field) || \
        (V4L2_FIELD_NONE == field)) || \
index cdf659abdc2ab73ba172d85fc6a6aa75db4390c1..286f029100447552550d81c5b6c1d6b716fcf8e7 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/version.h>
 #include <linux/slab.h>
 
 #include <asm/irq.h>
@@ -47,6 +46,7 @@
 
 MODULE_DESCRIPTION("TI DaVinci VPIF Display driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(VPIF_DISPLAY_VERSION);
 
 #define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50)
 
@@ -701,7 +701,6 @@ static int vpif_querycap(struct file *file, void  *priv,
 {
        struct vpif_display_config *config = vpif_dev->platform_data;
 
-       cap->version = VPIF_DISPLAY_VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
        strlcpy(cap->driver, "vpif display", sizeof(cap->driver));
        strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info));
@@ -1740,10 +1739,8 @@ static __init int vpif_probe(struct platform_device *pdev)
                vfd->v4l2_dev = &vpif_obj.v4l2_dev;
                vfd->release = video_device_release;
                snprintf(vfd->name, sizeof(vfd->name),
-                        "DM646x_VPIFDisplay_DRIVER_V%d.%d.%d",
-                        (VPIF_DISPLAY_VERSION_CODE >> 16) & 0xff,
-                        (VPIF_DISPLAY_VERSION_CODE >> 8) & 0xff,
-                        (VPIF_DISPLAY_VERSION_CODE) & 0xff);
+                        "DM646x_VPIFDisplay_DRIVER_V%s",
+                        VPIF_DISPLAY_VERSION);
 
                /* Set video_dev to the video device */
                ch->video_dev = vfd;
index b53aaa8830753bc18937d672d1fe2c5c046348a2..5d1936dafed25af340cb1ef91c261fd8fb76caa4 100644 (file)
@@ -18,7 +18,6 @@
 
 /* Header files */
 #include <linux/videodev2.h>
-#include <linux/version.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/videobuf-core.h>
 #include "vpif.h"
 
 /* Macros */
-#define VPIF_MAJOR_RELEASE     (0)
-#define VPIF_MINOR_RELEASE     (0)
-#define VPIF_BUILD             (1)
-
-#define VPIF_DISPLAY_VERSION_CODE \
-       ((VPIF_MAJOR_RELEASE << 16) | (VPIF_MINOR_RELEASE << 8) | VPIF_BUILD)
+#define VPIF_DISPLAY_VERSION   "0.0.2"
 
 #define VPIF_VALID_FIELD(field) \
        (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \
index 3cb78f26df9033bb9068053f3ab80308d1a6ad04..281ee427c2ab6a20734b6af8082b3340cfbee144 100644 (file)
@@ -3,7 +3,6 @@ config VIDEO_EM28XX
        depends on VIDEO_DEV && I2C
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
-       depends on RC_CORE
        select VIDEOBUF_VMALLOC
        select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
@@ -40,7 +39,18 @@ config VIDEO_EM28XX_DVB
        select DVB_S921 if !DVB_FE_CUSTOMISE
        select DVB_DRXD if !DVB_FE_CUSTOMISE
        select DVB_CXD2820R if !DVB_FE_CUSTOMISE
+       select DVB_DRXK if !DVB_FE_CUSTOMISE
+       select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE
        select VIDEOBUF_DVB
        ---help---
          This adds support for DVB cards based on the
          Empiatech em28xx chips.
+
+config VIDEO_EM28XX_RC
+        bool "EM28XX Remote Controller support"
+        depends on RC_CORE
+        depends on VIDEO_EM28XX
+        depends on !(RC_CORE=m && VIDEO_EM28XX=y)
+        default y
+        ---help---
+          Enables Remote Controller support on em28xx driver.
index d0f093d1d0df23c887b7b5865d5fee5f4e74c794..38aaa004f57d6b64e6f6dd57ca3c85ddc2f31221 100644 (file)
@@ -1,5 +1,7 @@
-em28xx-objs     := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
-                  em28xx-input.o em28xx-vbi.o
+em28xx-y :=    em28xx-video.o em28xx-i2c.o em28xx-cards.o
+em28xx-y +=    em28xx-core.o  em28xx-vbi.o
+
+em28xx-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-input.o
 
 em28xx-alsa-objs := em28xx-audio.o
 
index 3c48a72eb7de844138deff618c2d24ac062d5a42..cff0768afbf514183b50ba0e35e3bfdcbde43a6f 100644 (file)
@@ -3,9 +3,9 @@
  *
  *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
  *
- *  Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
  *     - Port to work with the in-kernel driver
- *     - Several cleanups
+ *     - Cleanups, fixes, alsa-controls, etc.
  *
  *  This driver is based on my previous au600 usb pstn audio driver
  *  and inherits all the copyrights
@@ -41,6 +41,7 @@
 #include <sound/info.h>
 #include <sound/initval.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <media/v4l2-common.h>
 #include "em28xx.h"
 
@@ -212,9 +213,12 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
        for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
                errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
                if (errCode) {
+                       em28xx_errdev("submit of audio urb failed\n");
                        em28xx_deinit_isoc_audio(dev);
+                       atomic_set(&dev->stream_started, 0);
                        return errCode;
                }
+
        }
 
        return 0;
@@ -245,6 +249,7 @@ static struct snd_pcm_hardware snd_em28xx_hw_capture = {
        .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
                SNDRV_PCM_INFO_MMAP           |
                SNDRV_PCM_INFO_INTERLEAVED    |
+               SNDRV_PCM_INFO_BATCH          |
                SNDRV_PCM_INFO_MMAP_VALID,
 
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
@@ -276,24 +281,27 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
                return -ENODEV;
        }
 
-       /* Sets volume, mute, etc */
+       runtime->hw = snd_em28xx_hw_capture;
+       if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
+               if (dev->audio_ifnum)
+                       dev->alt = 1;
+               else
+                       dev->alt = 7;
 
-       dev->mute = 0;
-       mutex_lock(&dev->lock);
-       ret = em28xx_audio_analog_set(dev);
-       if (ret < 0)
-               goto err;
+               dprintk("changing alternate number on interface %d to %d\n",
+                       dev->audio_ifnum, dev->alt);
+               usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt);
 
-       runtime->hw = snd_em28xx_hw_capture;
-       if (dev->alt == 0 && dev->adev.users == 0) {
-               int errCode;
-               dev->alt = 7;
-               dprintk("changing alternate number to 7\n");
-               errCode = usb_set_interface(dev->udev, 0, 7);
-       }
+               /* Sets volume, mute, etc */
+               dev->mute = 0;
+               mutex_lock(&dev->lock);
+               ret = em28xx_audio_analog_set(dev);
+               if (ret < 0)
+                       goto err;
 
-       dev->adev.users++;
-       mutex_unlock(&dev->lock);
+               dev->adev.users++;
+               mutex_unlock(&dev->lock);
+       }
 
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
        dev->adev.capture_pcm_substream = substream;
@@ -342,6 +350,8 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
 
        ret = snd_pcm_alloc_vmalloc_buffer(substream,
                                params_buffer_bytes(hw_params));
+       if (ret < 0)
+               return ret;
        format = params_format(hw_params);
        rate = params_rate(hw_params);
        channels = params_channels(hw_params);
@@ -393,20 +403,24 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
                                      int cmd)
 {
        struct em28xx *dev = snd_pcm_substream_chip(substream);
-       int retval;
+       int retval = 0;
 
        switch (cmd) {
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+       case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
        case SNDRV_PCM_TRIGGER_START:
                atomic_set(&dev->stream_started, 1);
                break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+       case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
        case SNDRV_PCM_TRIGGER_STOP:
-               atomic_set(&dev->stream_started, 1);
+               atomic_set(&dev->stream_started, 0);
                break;
        default:
                retval = -EINVAL;
        }
        schedule_work(&dev->wq_trigger);
-       return 0;
+       return retval;
 }
 
 static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
@@ -432,6 +446,179 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
        return vmalloc_to_page(pageptr);
 }
 
+/*
+ * AC97 volume control support
+ */
+static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 2;
+       info->value.integer.min = 0;
+       info->value.integer.max = 0x1f;
+
+       return 0;
+}
+
+static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) |
+                 (0x1f - (value->value.integer.value[1] & 0x1f)) << 8;
+       int rc;
+
+       mutex_lock(&dev->lock);
+       rc = em28xx_read_ac97(dev, kcontrol->private_value);
+       if (rc < 0)
+               goto err;
+
+       val |= rc & 0x8000;     /* Preserve the mute flag */
+
+       rc = em28xx_write_ac97(dev, kcontrol->private_value, val);
+       if (rc < 0)
+               goto err;
+
+       dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
+               (val & 0x8000) ? "muted " : "",
+               0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+               val, (int)kcontrol->private_value);
+
+err:
+       mutex_unlock(&dev->lock);
+       return rc;
+}
+
+static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       int val;
+
+       mutex_lock(&dev->lock);
+       val = em28xx_read_ac97(dev, kcontrol->private_value);
+       mutex_unlock(&dev->lock);
+       if (val < 0)
+               return val;
+
+       dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
+               (val & 0x8000) ? "muted " : "",
+               0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+               val, (int)kcontrol->private_value);
+
+       value->value.integer.value[0] = 0x1f - (val & 0x1f);
+       value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f);
+
+       return 0;
+}
+
+static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       u16 val = value->value.integer.value[0];
+       int rc;
+
+       mutex_lock(&dev->lock);
+       rc = em28xx_read_ac97(dev, kcontrol->private_value);
+       if (rc < 0)
+               goto err;
+
+       if (val)
+               rc &= 0x1f1f;
+       else
+               rc |= 0x8000;
+
+       rc = em28xx_write_ac97(dev, kcontrol->private_value, rc);
+       if (rc < 0)
+               goto err;
+
+       dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
+               (val & 0x8000) ? "muted " : "",
+               0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+               val, (int)kcontrol->private_value);
+
+err:
+       mutex_unlock(&dev->lock);
+       return rc;
+}
+
+static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *value)
+{
+       struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       int val;
+
+       mutex_lock(&dev->lock);
+       val = em28xx_read_ac97(dev, kcontrol->private_value);
+       mutex_unlock(&dev->lock);
+       if (val < 0)
+               return val;
+
+       if (val & 0x8000)
+               value->value.integer.value[0] = 0;
+       else
+               value->value.integer.value[0] = 1;
+
+       dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
+               (val & 0x8000) ? "muted " : "",
+               0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
+               val, (int)kcontrol->private_value);
+
+       return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0);
+
+static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev,
+                          char *name, int id)
+{
+       int err;
+       char ctl_name[44];
+       struct snd_kcontrol *kctl;
+       struct snd_kcontrol_new tmp;
+
+       memset (&tmp, 0, sizeof(tmp));
+       tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       tmp.private_value = id,
+       tmp.name  = ctl_name,
+
+       /* Add Mute Control */
+       sprintf(ctl_name, "%s Switch", name);
+       tmp.get  = em28xx_vol_get_mute;
+       tmp.put  = em28xx_vol_put_mute;
+       tmp.info = snd_ctl_boolean_mono_info;
+       kctl = snd_ctl_new1(&tmp, dev);
+       err = snd_ctl_add(card, kctl);
+       if (err < 0)
+               return err;
+       dprintk("Added control %s for ac97 volume control 0x%04x\n",
+               ctl_name, id);
+
+       memset (&tmp, 0, sizeof(tmp));
+       tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       tmp.private_value = id,
+       tmp.name  = ctl_name,
+
+       /* Add Volume Control */
+       sprintf(ctl_name, "%s Volume", name);
+       tmp.get   = em28xx_vol_get;
+       tmp.put   = em28xx_vol_put;
+       tmp.info  = em28xx_vol_info;
+       tmp.tlv.p = em28xx_db_scale,
+       kctl = snd_ctl_new1(&tmp, dev);
+       err = snd_ctl_add(card, kctl);
+       if (err < 0)
+               return err;
+       dprintk("Added control %s for ac97 volume control 0x%04x\n",
+               ctl_name, id);
+
+       return 0;
+}
+
+/*
+ * register/unregister code and data
+ */
 static struct snd_pcm_ops snd_em28xx_pcm_capture = {
        .open      = snd_em28xx_capture_open,
        .close     = snd_em28xx_pcm_close,
@@ -452,17 +639,17 @@ static int em28xx_audio_init(struct em28xx *dev)
        static int          devnr;
        int                 err;
 
-       if (dev->has_alsa_audio != 1) {
+       if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
                /* This device does not support the extension (in this case
                   the device is expecting the snd-usb-audio module or
                   doesn't have analog audio support at all) */
                return 0;
        }
 
-       printk(KERN_INFO "em28xx-audio.c: probing for em28x1 "
-                        "non standard usbaudio\n");
+       printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
        printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
                         "Rechberger\n");
+       printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
 
        err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
                              &card);
@@ -488,6 +675,22 @@ static int em28xx_audio_init(struct em28xx *dev)
 
        INIT_WORK(&dev->wq_trigger, audio_trigger);
 
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+               em28xx_cvol_new(card, dev, "Video", AC97_VIDEO_VOL);
+               em28xx_cvol_new(card, dev, "Line In", AC97_LINEIN_VOL);
+               em28xx_cvol_new(card, dev, "Phone", AC97_PHONE_VOL);
+               em28xx_cvol_new(card, dev, "Microphone", AC97_PHONE_VOL);
+               em28xx_cvol_new(card, dev, "CD", AC97_CD_VOL);
+               em28xx_cvol_new(card, dev, "AUX", AC97_AUX_VOL);
+               em28xx_cvol_new(card, dev, "PCM", AC97_PCM_OUT_VOL);
+
+               em28xx_cvol_new(card, dev, "Master", AC97_MASTER_VOL);
+               em28xx_cvol_new(card, dev, "Line", AC97_LINE_LEVEL_VOL);
+               em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO_VOL);
+               em28xx_cvol_new(card, dev, "LFE", AC97_LFE_MASTER_VOL);
+               em28xx_cvol_new(card, dev, "Surround", AC97_SURR_MASTER_VOL);
+       }
+
        err = snd_card_register(card);
        if (err < 0) {
                snd_card_free(card);
@@ -538,7 +741,7 @@ static void __exit em28xx_alsa_unregister(void)
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
 MODULE_DESCRIPTION("Em28xx Audio driver");
 
 module_init(em28xx_alsa_register);
index 4e37375decf54dbdea4e3c9617fcf52b9201912f..3e3959fee4195cad5bfc6070d42250f57e2c96a2 100644 (file)
@@ -289,7 +289,7 @@ static struct em28xx_reg_seq leadership_reset[] = {
        {       -1,             -1,     -1,     -1},
 };
 
-/* 2013:024f PCTV Systems nanoStick T2 290e
+/* 2013:024f PCTV nanoStick T2 290e
  * GPIO_6 - demod reset
  * GPIO_7 - LED
  */
@@ -300,6 +300,23 @@ static struct em28xx_reg_seq pctv_290e[] = {
        {-1,                    -1,     -1,             -1},
 };
 
+#if 0
+static struct em28xx_reg_seq terratec_h5_gpio[] = {
+       {EM28XX_R08_GPIO,       0xff,   0xff,   10},
+       {EM2874_R80_GPIO,       0xf6,   0xff,   100},
+       {EM2874_R80_GPIO,       0xf2,   0xff,   50},
+       {EM2874_R80_GPIO,       0xf6,   0xff,   50},
+       { -1,                   -1,     -1,     -1},
+};
+
+static struct em28xx_reg_seq terratec_h5_digital[] = {
+       {EM2874_R80_GPIO,       0xf6,   0xff,   10},
+       {EM2874_R80_GPIO,       0xe6,   0xff,   100},
+       {EM2874_R80_GPIO,       0xa6,   0xff,   10},
+       { -1,                   -1,     -1,     -1},
+};
+#endif
+
 /*
  *  Board definitions
  */
@@ -843,6 +860,19 @@ struct em28xx_board em28xx_boards[] = {
                        .gpio     = terratec_cinergy_USB_XS_FR_analog,
                } },
        },
+       [EM2884_BOARD_TERRATEC_H5] = {
+               .name         = "Terratec Cinergy H5",
+               .has_dvb      = 1,
+#if 0
+               .tuner_type   = TUNER_PHILIPS_TDA8290,
+               .tuner_addr   = 0x41,
+               .dvb_gpio     = terratec_h5_digital, /* FIXME: probably wrong */
+               .tuner_gpio   = terratec_h5_gpio,
+#endif
+               .i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
        [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
                .name         = "Hauppauge WinTV HVR 900",
                .tda9887_conf = TDA9887_PRESENT,
@@ -1259,7 +1289,7 @@ struct em28xx_board em28xx_boards[] = {
                } },
        },
 
-       [EM2874_LEADERSHIP_ISDBT] = {
+       [EM2874_BOARD_LEADERSHIP_ISDBT] = {
                .i2c_speed      = EM2874_I2C_SECONDARY_BUS_SELECT |
                                  EM28XX_I2C_CLK_WAIT_ENABLE |
                                  EM28XX_I2C_FREQ_100_KHZ,
@@ -1319,7 +1349,6 @@ struct em28xx_board em28xx_boards[] = {
        },
        [EM2880_BOARD_KWORLD_DVB_305U] = {
                .name         = "KWorld DVB-T 305U",
-               .valid        = EM28XX_BOARD_NOT_VALIDATED,
                .tuner_type   = TUNER_XC2028,
                .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
@@ -1770,16 +1799,16 @@ struct em28xx_board em28xx_boards[] = {
                .dvb_gpio   = kworld_a340_digital,
                .tuner_gpio = default_tuner_gpio,
        },
-       /* 2013:024f PCTV Systems nanoStick T2 290e.
+       /* 2013:024f PCTV nanoStick T2 290e.
         * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */
        [EM28174_BOARD_PCTV_290E] = {
+               .name          = "PCTV nanoStick T2 290e",
                .i2c_speed      = EM2874_I2C_SECONDARY_BUS_SELECT |
                        EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
-               .xclk          = EM28XX_XCLK_FREQUENCY_12MHZ,
-               .name          = "PCTV Systems nanoStick T2 290e",
                .tuner_type    = TUNER_ABSENT,
                .tuner_gpio    = pctv_290e,
                .has_dvb       = 1,
+               .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
        },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1855,8 +1884,10 @@ struct usb_device_id em28xx_id_table[] = {
        { USB_DEVICE(0x0ccd, 0x0042),
                        .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
        { USB_DEVICE(0x0ccd, 0x0043),
-                       .driver_info = EM2870_BOARD_TERRATEC_XS },
-       { USB_DEVICE(0x0ccd, 0x0047),
+                       .driver_info = EM2884_BOARD_TERRATEC_H5 },
+       { USB_DEVICE(0x0ccd, 0x10a2),   /* Rev. 1 */
+                       .driver_info = EM2884_BOARD_TERRATEC_H5 },
+       { USB_DEVICE(0x0ccd, 0x10ad),   /* Rev. 2 */
                        .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
        { USB_DEVICE(0x0ccd, 0x0084),
                        .driver_info = EM2860_BOARD_TERRATEC_AV350 },
@@ -1937,7 +1968,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
        {0x77800080, EM2860_BOARD_TVP5150_REFERENCE_DESIGN, TUNER_ABSENT},
        {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
        {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
-       {0x6b800080, EM2874_LEADERSHIP_ISDBT, TUNER_ABSENT},
+       {0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT},
 };
 
 /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
@@ -2660,10 +2691,9 @@ void em28xx_card_setup(struct em28xx *dev)
                        .addr = 0xba >> 1,
                        .platform_data = &pdata,
                };
-               struct v4l2_subdev *sd;
 
                pdata.xtal = dev->sensor_xtal;
-               sd = v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap,
+               v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap,
                                &mt9v011_info, NULL);
        }
 
@@ -2842,11 +2872,26 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
                        em28xx_info("chip ID is em2882/em2883\n");
                        dev->wait_after_write = 0;
                        break;
+               case CHIP_ID_EM2884:
+                       em28xx_info("chip ID is em2884\n");
+                       dev->reg_gpio_num = EM2874_R80_GPIO;
+                       dev->wait_after_write = 0;
+                       break;
                default:
                        em28xx_info("em28xx chip ID = %d\n", dev->chip_id);
                }
        }
 
+       if (dev->is_audio_only) {
+               errCode = em28xx_audio_setup(dev);
+               if (errCode)
+                       return -ENODEV;
+               em28xx_add_into_devlist(dev);
+               em28xx_init_extension(dev);
+
+               return 0;
+       }
+
        /* Prepopulate cached GPO register content */
        retval = em28xx_read_reg(dev, dev->reg_gpo_num);
        if (retval >= 0)
@@ -2947,6 +2992,9 @@ fail_reg_devices:
        return retval;
 }
 
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
 /*
  * em28xx_usb_probe()
  * checks for supported devices
@@ -2956,15 +3004,15 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 {
        const struct usb_endpoint_descriptor *endpoint;
        struct usb_device *udev;
-       struct usb_interface *uif;
        struct em28xx *dev = NULL;
        int retval;
-       int i, nr, ifnum, isoc_pipe;
+       bool is_audio_only = false, has_audio = false;
+       int i, nr, isoc_pipe;
+       const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
        char *speed;
        char descr[255] = "";
 
        udev = usb_get_dev(interface_to_usbdev(interface));
-       ifnum = interface->altsetting[0].desc.bInterfaceNumber;
 
        /* Check to see next free device and mark as used */
        nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
@@ -2984,6 +3032,19 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                goto err;
        }
 
+       /* Get endpoints */
+       for (i = 0; i < interface->num_altsetting; i++) {
+               int ep;
+
+               for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
+                       struct usb_host_endpoint        *e;
+                       e = &interface->altsetting[i].endpoint[ep];
+
+                       if (e->desc.bEndpointAddress == 0x83)
+                               has_audio = true;
+               }
+       }
+
        endpoint = &interface->cur_altsetting->endpoint[0].desc;
 
        /* check if the device has the iso in endpoint at the correct place */
@@ -3003,19 +3064,22 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                        check_interface = 0;
 
                if (!check_interface) {
-                       em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
-                               "interface %i, class %i found.\n",
-                               le16_to_cpu(udev->descriptor.idVendor),
-                               le16_to_cpu(udev->descriptor.idProduct),
-                               ifnum,
-                               interface->altsetting[0].desc.bInterfaceClass);
-
-                       em28xx_err(DRIVER_NAME " This is an anciliary "
-                               "interface not used by the driver\n");
-
-                       em28xx_devused &= ~(1<<nr);
-                       retval = -ENODEV;
-                       goto err;
+                       if (has_audio) {
+                               is_audio_only = true;
+                       } else {
+                               em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
+                                       "interface %i, class %i found.\n",
+                                       le16_to_cpu(udev->descriptor.idVendor),
+                                       le16_to_cpu(udev->descriptor.idProduct),
+                                       ifnum,
+                                       interface->altsetting[0].desc.bInterfaceClass);
+                               em28xx_err(DRIVER_NAME " This is an anciliary "
+                                       "interface not used by the driver\n");
+
+                               em28xx_devused &= ~(1<<nr);
+                               retval = -ENODEV;
+                               goto err;
+                       }
                }
        }
 
@@ -3045,8 +3109,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        if (*descr)
                strlcat(descr, " ", sizeof(descr));
 
-       printk(DRIVER_NAME ": New device %s@ %s Mbps "
-               "(%04x:%04x, interface %d, class %d)\n",
+       printk(KERN_INFO DRIVER_NAME
+               ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n",
                descr,
                speed,
                le16_to_cpu(udev->descriptor.idVendor),
@@ -3054,6 +3118,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                ifnum,
                interface->altsetting->desc.bInterfaceNumber);
 
+       if (has_audio)
+               printk(KERN_INFO DRIVER_NAME
+                      ": Audio Vendor Class interface %i found\n",
+                      ifnum);
+
        /*
         * Make sure we have 480 Mbps of bandwidth, otherwise things like
         * video stream wouldn't likely work, since 12 Mbps is generally
@@ -3089,10 +3158,13 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        dev->devno = nr;
        dev->model = id->driver_info;
        dev->alt   = -1;
+       dev->is_audio_only = is_audio_only;
+       dev->has_alsa_audio = has_audio;
+       dev->audio_ifnum = ifnum;
 
        /* Checks if audio is provided by some interface */
        for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
-               uif = udev->config->interface[i];
+               struct usb_interface *uif = udev->config->interface[i];
                if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
                        dev->has_audio_class = 1;
                        break;
@@ -3100,9 +3172,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        }
 
        /* compute alternate max packet sizes */
-       uif = udev->actconfig->interface[0];
-
-       dev->num_alt = uif->num_altsetting;
+       dev->num_alt = interface->num_altsetting;
        dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
 
        if (dev->alt_max_pkt_size == NULL) {
@@ -3114,14 +3184,21 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        }
 
        for (i = 0; i < dev->num_alt ; i++) {
-               u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
-               dev->alt_max_pkt_size[i] =
-                   (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+               u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
+               unsigned int size = tmp & 0x7ff;
+
+               if (udev->speed == USB_SPEED_HIGH)
+                       size = size * hb_mult(tmp);
+
+               dev->alt_max_pkt_size[i] = size;
        }
 
        if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
                dev->model = card[nr];
 
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+
        /* allocate device struct */
        mutex_init(&dev->lock);
        mutex_lock(&dev->lock);
@@ -3133,9 +3210,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                goto err;
        }
 
-       /* save our data pointer in this interface device */
-       usb_set_intfdata(interface, dev);
-
        request_modules(dev);
 
        /* Should be the last thing to do, to avoid newer udev's to
@@ -3164,6 +3238,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
        if (!dev)
                return;
 
+       if (dev->is_audio_only) {
+               mutex_lock(&dev->lock);
+               em28xx_close_extension(dev);
+               mutex_unlock(&dev->lock);
+               return;
+       }
+
        em28xx_info("disconnecting %s\n", dev->vdev->name);
 
        flush_request_modules(dev);
index e33f145d867ae923772768dcc02cb08a5de54eec..57b1b5c6d88585521b06dcf647424669e7a2de60 100644 (file)
@@ -211,6 +211,7 @@ int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val)
 {
        return em28xx_write_regs(dev, reg, &val, 1);
 }
+EXPORT_SYMBOL_GPL(em28xx_write_reg);
 
 /*
  * em28xx_write_reg_bits()
@@ -286,6 +287,7 @@ int em28xx_read_ac97(struct em28xx *dev, u8 reg)
                return ret;
        return le16_to_cpu(val);
 }
+EXPORT_SYMBOL_GPL(em28xx_read_ac97);
 
 /*
  * em28xx_write_ac97()
@@ -313,13 +315,14 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(em28xx_write_ac97);
 
-struct em28xx_vol_table {
+struct em28xx_vol_itable {
        enum em28xx_amux mux;
        u8               reg;
 };
 
-static struct em28xx_vol_table inputs[] = {
+static struct em28xx_vol_itable inputs[] = {
        { EM28XX_AMUX_VIDEO,    AC97_VIDEO_VOL   },
        { EM28XX_AMUX_LINE_IN,  AC97_LINEIN_VOL  },
        { EM28XX_AMUX_PHONE,    AC97_PHONE_VOL   },
@@ -403,7 +406,12 @@ static int em28xx_set_audio_source(struct em28xx *dev)
        return ret;
 }
 
-static const struct em28xx_vol_table outputs[] = {
+struct em28xx_vol_otable {
+       enum em28xx_aout mux;
+       u8               reg;
+};
+
+static const struct em28xx_vol_otable outputs[] = {
        { EM28XX_AOUT_MASTER, AC97_MASTER_VOL      },
        { EM28XX_AOUT_LINE,   AC97_LINE_LEVEL_VOL  },
        { EM28XX_AOUT_MONO,   AC97_MASTER_MONO_VOL },
@@ -492,17 +500,13 @@ int em28xx_audio_setup(struct em28xx *dev)
        if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
                || dev->chip_id == CHIP_ID_EM28174) {
                /* Digital only device - don't load any alsa module */
-               dev->audio_mode.has_audio = 0;
-               dev->has_audio_class = 0;
-               dev->has_alsa_audio = 0;
+               dev->audio_mode.has_audio = false;
+               dev->has_audio_class = false;
+               dev->has_alsa_audio = false;
                return 0;
        }
 
-       /* If device doesn't support Usb Audio Class, use vendor class */
-       if (!dev->has_audio_class)
-               dev->has_alsa_audio = 1;
-
-       dev->audio_mode.has_audio = 1;
+       dev->audio_mode.has_audio = true;
 
        /* See how this device is configured */
        cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
@@ -512,8 +516,8 @@ int em28xx_audio_setup(struct em28xx *dev)
                cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
        } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
                /* The device doesn't have vendor audio at all */
-               dev->has_alsa_audio = 0;
-               dev->audio_mode.has_audio = 0;
+               dev->has_alsa_audio = false;
+               dev->audio_mode.has_audio = false;
                return 0;
        } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
                   EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
@@ -542,8 +546,8 @@ int em28xx_audio_setup(struct em28xx *dev)
                 */
                em28xx_warn("AC97 chip type couldn't be determined\n");
                dev->audio_mode.ac97 = EM28XX_NO_AC97;
-               dev->has_alsa_audio = 0;
-               dev->audio_mode.has_audio = 0;
+               dev->has_alsa_audio = false;
+               dev->audio_mode.has_audio = false;
                goto init_audio;
        }
 
@@ -615,7 +619,9 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 {
        int rc;
 
-       if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) {
+       if (dev->chip_id == CHIP_ID_EM2874 ||
+           dev->chip_id == CHIP_ID_EM2884 ||
+           dev->chip_id == CHIP_ID_EM28174) {
                /* The Transport Stream Enable Register moved in em2874 */
                if (!start) {
                        rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
@@ -884,6 +890,7 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
        }
        return rc;
 }
+EXPORT_SYMBOL_GPL(em28xx_gpio_set);
 
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
 {
@@ -917,7 +924,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode);
 static void em28xx_irq_callback(struct urb *urb)
 {
        struct em28xx *dev = urb->context;
-       int rc, i;
+       int i;
 
        switch (urb->status) {
        case 0:             /* success */
@@ -934,7 +941,7 @@ static void em28xx_irq_callback(struct urb *urb)
 
        /* Copy data from URB */
        spin_lock(&dev->slock);
-       rc = dev->isoc_ctl.isoc_copy(dev, urb);
+       dev->isoc_ctl.isoc_copy(dev, urb);
        spin_unlock(&dev->slock);
 
        /* Reset urb buffers */
@@ -1106,17 +1113,19 @@ EXPORT_SYMBOL_GPL(em28xx_init_isoc);
 int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
 {
        unsigned int chip_cfg2;
-       unsigned int packet_size = 564;
-
-       if (dev->chip_id == CHIP_ID_EM2874) {
-               /* FIXME - for now assume 564 like it was before, but the
-                  em2874 code should be added to return the proper value... */
-               packet_size = 564;
-       } else if (dev->chip_id == CHIP_ID_EM28174) {
-               /* FIXME same as em2874. 564 was enough for 22 Mbit DVB-T
-                  but too much for 44 Mbit DVB-C. */
-               packet_size = 752;
-       } else {
+       unsigned int packet_size;
+
+       switch (dev->chip_id) {
+       case CHIP_ID_EM2710:
+       case CHIP_ID_EM2750:
+       case CHIP_ID_EM2800:
+       case CHIP_ID_EM2820:
+       case CHIP_ID_EM2840:
+       case CHIP_ID_EM2860:
+               /* No DVB support */
+               return -EINVAL;
+       case CHIP_ID_EM2870:
+       case CHIP_ID_EM2883:
                /* TS max packet size stored in bits 1-0 of R01 */
                chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2);
                switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) {
@@ -1133,9 +1142,24 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
                        packet_size = 752;
                        break;
                }
+               break;
+       case CHIP_ID_EM2874:
+               /*
+                * FIXME: for now assumes 564 like it was before, but the
+                * em2874 code should be added to return the proper value
+                */
+               packet_size = 564;
+               break;
+       case CHIP_ID_EM2884:
+       case CHIP_ID_EM28174:
+       default:
+               /*
+                * FIXME: same as em2874. 564 was enough for 22 Mbit DVB-T
+                * but not enough for 44 Mbit DVB-C.
+                */
+               packet_size = 752;
        }
 
-       em28xx_coredbg("dvb max packet size=%d\n", packet_size);
        return packet_size;
 }
 EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize);
index 7904ca4b69134d1fdb4af0d3d0a89b0acbeffdee..e5916dee40945b8fd250582615904f5c8b381e98 100644 (file)
@@ -1,7 +1,7 @@
 /*
  DVB device driver for em28xx
 
- (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org>
+ (c) 2008-2011 Mauro Carvalho Chehab <mchehab@infradead.org>
 
  (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
        - Fixes for the driver to properly work with HVR-950
@@ -40,6 +40,8 @@
 #include "s921.h"
 #include "drxd.h"
 #include "cxd2820r.h"
+#include "tda18271c2dd.h"
+#include "drxk.h"
 
 MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -73,6 +75,11 @@ struct em28xx_dvb {
        struct dmx_frontend        fe_hw;
        struct dmx_frontend        fe_mem;
        struct dvb_net             net;
+
+       /* Due to DRX-K - probably need changes */
+       int (*gate_ctrl)(struct dvb_frontend *, int);
+       struct semaphore      pll_mutex;
+       bool                    dont_attach_fe1;
 };
 
 
@@ -160,6 +167,11 @@ static int start_streaming(struct em28xx_dvb *dvb)
                return rc;
 
        max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
+       if (max_dvb_packet_size < 0)
+               return max_dvb_packet_size;
+       dprintk(1, "Using %d buffers each with %d bytes\n",
+               EM28XX_DVB_NUM_BUFS,
+               max_dvb_packet_size);
 
        return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
                                EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
@@ -295,6 +307,79 @@ static struct drxd_config em28xx_drxd = {
        .disable_i2c_gate_ctrl = 1,
 };
 
+struct drxk_config terratec_h5_drxk = {
+       .adr = 0x29,
+       .single_master = 1,
+       .no_i2c_bridge = 1,
+       .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
+};
+
+static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct em28xx_dvb *dvb = fe->sec_priv;
+       int status;
+
+       if (!dvb)
+               return -EINVAL;
+
+       if (enable) {
+               down(&dvb->pll_mutex);
+               status = dvb->gate_ctrl(fe, 1);
+       } else {
+               status = dvb->gate_ctrl(fe, 0);
+               up(&dvb->pll_mutex);
+       }
+       return status;
+}
+
+static void terratec_h5_init(struct em28xx *dev)
+{
+       int i;
+       struct em28xx_reg_seq terratec_h5_init[] = {
+               {EM28XX_R08_GPIO,       0xff,   0xff,   10},
+               {EM2874_R80_GPIO,       0xf6,   0xff,   100},
+               {EM2874_R80_GPIO,       0xf2,   0xff,   50},
+               {EM2874_R80_GPIO,       0xf6,   0xff,   100},
+               { -1,                   -1,     -1,     -1},
+       };
+       struct em28xx_reg_seq terratec_h5_end[] = {
+               {EM2874_R80_GPIO,       0xe6,   0xff,   100},
+               {EM2874_R80_GPIO,       0xa6,   0xff,   50},
+               {EM2874_R80_GPIO,       0xe6,   0xff,   100},
+               { -1,                   -1,     -1,     -1},
+       };
+       struct {
+               unsigned char r[4];
+               int len;
+       } regs[] = {
+               {{ 0x06, 0x02, 0x00, 0x31 }, 4},
+               {{ 0x01, 0x02 }, 2},
+               {{ 0x01, 0x02, 0x00, 0xc6 }, 4},
+               {{ 0x01, 0x00 }, 2},
+               {{ 0x01, 0x00, 0xff, 0xaf }, 4},
+               {{ 0x01, 0x00, 0x03, 0xa0 }, 4},
+               {{ 0x01, 0x00 }, 2},
+               {{ 0x01, 0x00, 0x73, 0xaf }, 4},
+               {{ 0x04, 0x00 }, 2},
+               {{ 0x00, 0x04 }, 2},
+               {{ 0x00, 0x04, 0x00, 0x0a }, 4},
+               {{ 0x04, 0x14 }, 2},
+               {{ 0x04, 0x14, 0x00, 0x00 }, 4},
+       };
+
+       em28xx_gpio_set(dev, terratec_h5_init);
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+       msleep(10);
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
+       msleep(10);
+
+       dev->i2c_client.addr = 0x82 >> 1;
+
+       for (i = 0; i < ARRAY_SIZE(regs); i++)
+               i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+       em28xx_gpio_set(dev, terratec_h5_end);
+};
+
 static int mt352_terratec_xs_init(struct dvb_frontend *fe)
 {
        /* Values extracted from a USB trace of the Terratec Windows driver */
@@ -516,7 +601,7 @@ static void unregister_dvb(struct em28xx_dvb *dvb)
        if (dvb->fe[1])
                dvb_unregister_frontend(dvb->fe[1]);
        dvb_unregister_frontend(dvb->fe[0]);
-       if (dvb->fe[1])
+       if (dvb->fe[1] && !dvb->dont_attach_fe1)
                dvb_frontend_detach(dvb->fe[1]);
        dvb_frontend_detach(dvb->fe[0]);
        dvb_unregister_adapter(&dvb->adapter);
@@ -546,7 +631,7 @@ static int dvb_init(struct em28xx *dev)
        em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
        /* init frontend */
        switch (dev->model) {
-       case EM2874_LEADERSHIP_ISDBT:
+       case EM2874_BOARD_LEADERSHIP_ISDBT:
                dvb->fe[0] = dvb_attach(s921_attach,
                                &sharp_isdbt, &dev->i2c_adap);
 
@@ -688,6 +773,41 @@ static int dvb_init(struct em28xx *dev)
                                /* leave FE 0 still active */
                        }
                }
+               break;
+       case EM2884_BOARD_TERRATEC_H5:
+               terratec_h5_init(dev);
+
+               dvb->dont_attach_fe1 = 1;
+
+               dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap, &dvb->fe[1]);
+               if (!dvb->fe[0]) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+
+               /* FIXME: do we need a pll semaphore? */
+               dvb->fe[0]->sec_priv = dvb;
+               sema_init(&dvb->pll_mutex, 1);
+               dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
+               dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+               dvb->fe[1]->id = 1;
+
+               /* Attach tda18271 to DVB-C frontend */
+               if (dvb->fe[0]->ops.i2c_gate_ctrl)
+                       dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
+               if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap, 0x60)) {
+                       result = -EINVAL;
+                       goto out_free;
+               }
+               if (dvb->fe[0]->ops.i2c_gate_ctrl)
+                       dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
+
+               /* Hack - needed by drxk/tda18271c2dd */
+               dvb->fe[1]->tuner_priv = dvb->fe[0]->tuner_priv;
+               memcpy(&dvb->fe[1]->ops.tuner_ops,
+                      &dvb->fe[0]->ops.tuner_ops,
+                      sizeof(dvb->fe[0]->ops.tuner_ops));
+
                break;
        default:
                em28xx_errdev("/2: The frontend of your DVB/ATSC card"
index 4739fc7e6eb360397f6e21c426b805206ef20d4a..36f5a9bc8b765b56129dd6368d88146d938edb72 100644 (file)
@@ -181,16 +181,25 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
 
 /*
  * em28xx_i2c_send_bytes()
- * untested for more than 4 bytes
  */
 static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf,
                                 short len, int stop)
 {
        int wrcount = 0;
        struct em28xx *dev = (struct em28xx *)data;
+       int write_timeout, ret;
 
        wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
 
+       /* Seems to be required after a write */
+       for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+            write_timeout -= 5) {
+               ret = dev->em28xx_read_reg(dev, 0x05);
+               if (!ret)
+                       break;
+               msleep(5);
+       }
+
        return wrcount;
 }
 
@@ -218,9 +227,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr,
  */
 static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr)
 {
-       char msg;
        int ret;
-       msg = addr;
 
        ret = dev->em28xx_read_reg_req(dev, 2, addr);
        if (ret < 0) {
@@ -332,7 +339,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
        struct em28xx_eeprom *em_eeprom = (void *)eedata;
        int i, err, size = len, block;
 
-       if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) {
+       if (dev->chip_id == CHIP_ID_EM2874 ||
+           dev->chip_id == CHIP_ID_EM28174 ||
+           dev->chip_id == CHIP_ID_EM2884) {
                /* Empia switched to a 16-bit addressable eeprom in newer
                   devices.  While we could certainly write a routine to read
                   the eeprom, there is nothing of use in there that cannot be
index ba1ba8648c8169c074fdcb497643d6ad05a5197b..5d12b14282e3dc19353f62831b3d5df1d7757f6f 100644 (file)
@@ -372,6 +372,7 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
                ir->get_key = default_polling_getkey;
                break;
        case CHIP_ID_EM2874:
+       case CHIP_ID_EM28174:
                ir->get_key = em2874_polling_getkey;
                em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
                break;
index e92a28ede434d803cc56e2ad7aaa91fcc454a512..66f792361b97dee12d7b91c9839c12f71600f8a2 100644 (file)
@@ -201,6 +201,7 @@ enum em28xx_chip_id {
        CHIP_ID_EM2870 = 35,
        CHIP_ID_EM2883 = 36,
        CHIP_ID_EM2874 = 65,
+       CHIP_ID_EM2884 = 68,
        CHIP_ID_EM28174 = 113,
 };
 
index 7b6461d2d1ff3f1a2ef9b25560772d7a34909b08..d176dc0394e2f9c276c4e333f695c7c91f39a563 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/bitmap.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
@@ -50,7 +49,8 @@
                      "Sascha Sommer <saschasommer@freenet.de>"
 
 #define DRIVER_DESC         "Empia em28xx based USB video device driver"
-#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 2)
+
+#define EM28XX_VERSION "0.1.3"
 
 #define em28xx_videodbg(fmt, arg...) do {\
        if (video_debug) \
@@ -72,6 +72,7 @@ do {\
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(EM28XX_VERSION);
 
 static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
@@ -1757,8 +1758,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
-       cap->version = EM28XX_VERSION_CODE;
-
        cap->capabilities =
                        V4L2_CAP_SLICED_VBI_CAPTURE |
                        V4L2_CAP_VIDEO_CAPTURE |
@@ -1976,7 +1975,6 @@ static int radio_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
 
-       cap->version = EM28XX_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
@@ -2450,10 +2448,8 @@ int em28xx_register_analog_devices(struct em28xx *dev)
       u8 val;
        int ret;
 
-       printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n",
-               dev->name,
-               (EM28XX_VERSION_CODE >> 16) & 0xff,
-               (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
+       printk(KERN_INFO "%s: v4l2 driver version %s\n",
+               dev->name, EM28XX_VERSION);
 
        /* set default norm */
        dev->norm = em28xx_video_template.current_norm;
index 3cca3312245086aed60a7ab0a2e65a525b8a2e56..d80658bf3da9f70df94b60c4cdd2ed042b470f7b 100644 (file)
 #define EM2800_BOARD_VC211A                      74
 #define EM2882_BOARD_DIKOM_DK300                 75
 #define EM2870_BOARD_KWORLD_A340                 76
-#define EM2874_LEADERSHIP_ISDBT                          77
+#define EM2874_BOARD_LEADERSHIP_ISDBT            77
 #define EM28174_BOARD_PCTV_290E                   78
-
+#define EM2884_BOARD_TERRATEC_H5                 79
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -487,6 +487,8 @@ struct em28xx {
        int devno;              /* marks the number of this device */
        enum em28xx_chip_id chip_id;
 
+       int audio_ifnum;
+
        struct v4l2_device v4l2_dev;
        struct em28xx_board board;
 
@@ -503,6 +505,7 @@ struct em28xx {
 
        unsigned int has_audio_class:1;
        unsigned int has_alsa_audio:1;
+       unsigned int is_audio_only:1;
 
        /* Controls audio streaming */
        struct work_struct wq_trigger;              /* Trigger to start/stop audio for alsa module */
@@ -697,6 +700,9 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_release_resources(struct em28xx *dev);
 
 /* Provided by em28xx-input.c */
+
+#ifdef CONFIG_VIDEO_EM28XX_RC
+
 int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
@@ -709,6 +715,20 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev);
 int em28xx_ir_init(struct em28xx *dev);
 int em28xx_ir_fini(struct em28xx *dev);
 
+#else
+
+#define em28xx_get_key_terratec                        NULL
+#define em28xx_get_key_em_haup                 NULL
+#define em28xx_get_key_pinnacle_usb_grey       NULL
+#define em28xx_get_key_winfast_usbii_deluxe    NULL
+
+static inline void em28xx_register_snapshot_button(struct em28xx *dev) {}
+static inline void em28xx_deregister_snapshot_button(struct em28xx *dev) {}
+static inline int em28xx_ir_init(struct em28xx *dev) { return 0; }
+static inline int em28xx_ir_fini(struct em28xx *dev) { return 0; }
+
+#endif
+
 /* Provided by em28xx-vbi.c */
 extern struct videobuf_queue_ops em28xx_vbi_qops;
 
index bf66189cb26de1fba4f58884e458b89adb08d2b7..14bb907d650e123b4fe2be6a2366c5618f596f82 100644 (file)
@@ -21,7 +21,6 @@
 #ifndef _ET61X251_H_
 #define _ET61X251_H_
 
-#include <linux/version.h>
 #include <linux/usb.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
index a982750dcef10ad0d73f36be93246c4e1051a80b..9a1e80a1e1459824b95da0abe23dc00f8e8393e7 100644 (file)
@@ -18,6 +18,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
  ***************************************************************************/
 
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -48,8 +49,7 @@
 #define ET61X251_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
 #define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.09"
-#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 9)
+#define ET61X251_MODULE_VERSION "1.1.10"
 
 /*****************************************************************************/
 
@@ -1579,7 +1579,7 @@ et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)
 {
        struct v4l2_capability cap = {
                .driver = "et61x251",
-               .version = ET61X251_MODULE_VERSION_CODE,
+               .version = LINUX_VERSION_CODE,
                .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
                                V4L2_CAP_STREAMING,
        };
@@ -2480,16 +2480,8 @@ static long et61x251_ioctl_v4l2(struct file *filp,
        case VIDIOC_S_PARM:
                return et61x251_vidioc_s_parm(cam, arg);
 
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-       case VIDIOC_ENUM_FRAMEINTERVALS:
-               return -EINVAL;
-
        default:
-               return -EINVAL;
+               return -ENOTTY;
 
        }
 }
index 908d7012c3f23652507adbc77cf8f2a5729428f8..27cb197d0bd6e911696750e988a85e5af0a5994f 100644 (file)
 #include <linux/io.h>
 #include <linux/of_platform.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/videobuf-dma-contig.h>
 
 #define DRV_NAME               "fsl_viu"
-#define VIU_MAJOR_VERSION      0
-#define VIU_MINOR_VERSION      5
-#define VIU_RELEASE            0
-#define VIU_VERSION            KERNEL_VERSION(VIU_MAJOR_VERSION, \
-                                              VIU_MINOR_VERSION, \
-                                              VIU_RELEASE)
+#define VIU_VERSION            "0.5.1"
 
 #define BUFFER_TIMEOUT         msecs_to_jiffies(500)  /* 0.5 seconds */
 
@@ -610,7 +604,6 @@ static int vidioc_querycap(struct file *file, void *priv,
 {
        strcpy(cap->driver, "viu");
        strcpy(cap->card, "viu");
-       cap->version = VIU_VERSION;
        cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
                                V4L2_CAP_STREAMING     |
                                V4L2_CAP_VIDEO_OVERLAY |
@@ -1684,3 +1677,4 @@ module_exit(viu_exit);
 MODULE_DESCRIPTION("Freescale Video-In(VIU)");
 MODULE_AUTHOR("Hongjun Chen");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(VIU_VERSION);
index 34ae2c299799c350f255e0988bc4325d4dedf124..43d9a20caebc3f6439693e0833530e247c4b94ee 100644 (file)
@@ -179,6 +179,16 @@ config USB_GSPCA_PAC7311
          To compile this driver as a module, choose M here: the
          module will be called gspca_pac7311.
 
+config USB_GSPCA_SE401
+       tristate "SE401 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+        Say Y here if you want support for cameras based on the
+        Endpoints (formerly known as AOX) se401 chip.
+
+        To compile this driver as a module, choose M here: the
+        module will be called gspca_se401.
+
 config USB_GSPCA_SN9C2028
        tristate "SONIX Dual-Mode USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
index 802fbe1bff4a009f2787f749771f4e57ce9ccda9..d6364a86333ab8382d5ab11f0f360087a927ad39 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_USB_GSPCA_OV534_9)  += gspca_ov534_9.o
 obj-$(CONFIG_USB_GSPCA_PAC207)   += gspca_pac207.o
 obj-$(CONFIG_USB_GSPCA_PAC7302)  += gspca_pac7302.o
 obj-$(CONFIG_USB_GSPCA_PAC7311)  += gspca_pac7311.o
+obj-$(CONFIG_USB_GSPCA_SE401)    += gspca_se401.o
 obj-$(CONFIG_USB_GSPCA_SN9C2028) += gspca_sn9c2028.o
 obj-$(CONFIG_USB_GSPCA_SN9C20X)  += gspca_sn9c20x.o
 obj-$(CONFIG_USB_GSPCA_SONIXB)   += gspca_sonixb.o
@@ -58,6 +59,7 @@ gspca_ov534_9-objs  := ov534_9.o
 gspca_pac207-objs   := pac207.o
 gspca_pac7302-objs  := pac7302.o
 gspca_pac7311-objs  := pac7311.o
+gspca_se401-objs    := se401.o
 gspca_sn9c2028-objs := sn9c2028.o
 gspca_sn9c20x-objs  := sn9c20x.o
 gspca_sonixb-objs   := sonixb.o
index 49ad4acbf602663c0963d09e420aaf8a1cabf149..0330a0293b9ca58aed0a9e6a9461f5451b7151a4 100644 (file)
@@ -18,7 +18,6 @@
  */
 #ifndef GL860_DEV_H
 #define GL860_DEV_H
-#include <linux/version.h>
 
 #include "gspca.h"
 
index 08ce9948d99b28f28e0800fc9ffdeaf18d2d8551..5da4879f47f2c3e01342479add75a04332e48fa8 100644 (file)
@@ -24,7 +24,6 @@
 #define MODULE_NAME "gspca"
 
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
 #error "DEF_NURBS too big"
 #endif
 
+#define DRIVER_VERSION_NUMBER  "2.13.0"
+
 MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
-
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 13, 0)
+MODULE_VERSION(DRIVER_VERSION_NUMBER);
 
 #ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
@@ -443,8 +443,11 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
        } else {
                switch (gspca_dev->last_packet_type) {
                case DISCARD_PACKET:
-                       if (packet_type == LAST_PACKET)
+                       if (packet_type == LAST_PACKET) {
                                gspca_dev->last_packet_type = packet_type;
+                               gspca_dev->image = NULL;
+                               gspca_dev->image_len = 0;
+                       }
                        return;
                case LAST_PACKET:
                        return;
@@ -1278,10 +1281,10 @@ static int vidioc_querycap(struct file *file, void  *priv,
                ret = -ENODEV;
                goto out;
        }
-       strncpy((char *) cap->driver, gspca_dev->sd_desc->name,
+       strlcpy((char *) cap->driver, gspca_dev->sd_desc->name,
                        sizeof cap->driver);
        if (gspca_dev->dev->product != NULL) {
-               strncpy((char *) cap->card, gspca_dev->dev->product,
+               strlcpy((char *) cap->card, gspca_dev->dev->product,
                        sizeof cap->card);
        } else {
                snprintf((char *) cap->card, sizeof cap->card,
@@ -1291,7 +1294,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        }
        usb_make_path(gspca_dev->dev, (char *) cap->bus_info,
                        sizeof(cap->bus_info));
-       cap->version = DRIVER_VERSION_NUMBER;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
                          | V4L2_CAP_STREAMING
                          | V4L2_CAP_READWRITE;
@@ -1460,7 +1462,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
                return -EINVAL;
        input->type = V4L2_INPUT_TYPE_CAMERA;
        input->status = gspca_dev->cam.input_flags;
-       strncpy(input->name, gspca_dev->sd_desc->name,
+       strlcpy(input->name, gspca_dev->sd_desc->name,
                sizeof input->name);
        return 0;
 }
@@ -2478,10 +2480,7 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure);
 /* -- module insert / remove -- */
 static int __init gspca_init(void)
 {
-       info("v%d.%d.%d registered",
-               (DRIVER_VERSION_NUMBER >> 16) & 0xff,
-               (DRIVER_VERSION_NUMBER >> 8) & 0xff,
-               DRIVER_VERSION_NUMBER & 0xff);
+       info("v" DRIVER_VERSION_NUMBER " registered");
        return 0;
 }
 static void __exit gspca_exit(void)
index 057e287b9152a78fea793bdefa8ec6d26b699085..0800433b209287c45c9f4672a41f20e99b43adfe 100644 (file)
@@ -134,6 +134,7 @@ enum sensors {
        SEN_OV7670,
        SEN_OV76BE,
        SEN_OV8610,
+       SEN_OV9600,
 };
 
 /* Note this is a bit of a hack, but the w9968cf driver needs the code for all
@@ -340,6 +341,10 @@ static const unsigned ctrl_dis[] = {
                        (1 << EXPOSURE) |
                        (1 << AUTOGAIN) |
                        (1 << FREQ),
+[SEN_OV9600] =         ((1 << NCTRL) - 1)      /* no control */
+                       ^ ((1 << EXPOSURE)      /* but exposure */
+                        | (1 << AUTOGAIN)),    /* and autogain */
+
 };
 
 static const struct v4l2_pix_format ov519_vga_mode[] = {
@@ -525,6 +530,17 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0},
 };
+static const struct v4l2_pix_format ovfx2_ov9600_mode[] = {
+       {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1},
+       {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+               .bytesperline = 1280,
+               .sizeimage = 1280 * 1024,
+               .colorspace = V4L2_COLORSPACE_SRGB},
+};
 
 /* Registers common to OV511 / OV518 */
 #define R51x_FIFO_PSIZE                        0x30    /* 2 bytes wide w/ OV518(+) */
@@ -1807,6 +1823,22 @@ static const struct ov_i2c_regvals norm_7660[] = {
                        | OV7670_COM8_AEC},
        {0xa1, 0xc8}
 };
+static const struct ov_i2c_regvals norm_9600[] = {
+       {0x12, 0x80},
+       {0x0c, 0x28},
+       {0x11, 0x80},
+       {0x13, 0xb5},
+       {0x14, 0x3e},
+       {0x1b, 0x04},
+       {0x24, 0xb0},
+       {0x25, 0x90},
+       {0x26, 0x94},
+       {0x35, 0x90},
+       {0x37, 0x07},
+       {0x38, 0x08},
+       {0x01, 0x8e},
+       {0x02, 0x85}
+};
 
 /* 7670. Defaults taken from OmniVision provided data,
 *  as provided by Jonathan Corbet of OLPC              */
@@ -2400,9 +2432,12 @@ static int ov518_i2c_r(struct sd *sd, u8 reg)
 
        /* Initiate 2-byte write cycle */
        reg_w(sd, R518_I2C_CTL, 0x03);
+       reg_r8(sd, R518_I2C_CTL);
 
        /* Initiate 2-byte read cycle */
        reg_w(sd, R518_I2C_CTL, 0x05);
+       reg_r8(sd, R518_I2C_CTL);
+
        value = reg_r(sd, R51x_I2C_DATA);
        PDEBUG(D_USBI, "ov518_i2c_r %02x %02x", reg, value);
        return value;
@@ -2686,7 +2721,7 @@ static void write_i2c_regvals(struct sd *sd,
  *
  ***************************************************************************/
 
-/* This initializes the OV2x10 / OV3610 / OV3620 */
+/* This initializes the OV2x10 / OV3610 / OV3620 / OV9600 */
 static void ov_hires_configure(struct sd *sd)
 {
        int high, low;
@@ -2702,19 +2737,32 @@ static void ov_hires_configure(struct sd *sd)
        high = i2c_r(sd, 0x0a);
        low = i2c_r(sd, 0x0b);
        /* info("%x, %x", high, low); */
-       if (high == 0x96 && low == 0x40) {
-               PDEBUG(D_PROBE, "Sensor is an OV2610");
-               sd->sensor = SEN_OV2610;
-       } else if (high == 0x96 && low == 0x41) {
-               PDEBUG(D_PROBE, "Sensor is an OV2610AE");
-               sd->sensor = SEN_OV2610AE;
-       } else if (high == 0x36 && (low & 0x0f) == 0x00) {
-               PDEBUG(D_PROBE, "Sensor is an OV3610");
-               sd->sensor = SEN_OV3610;
-       } else {
-               err("Error unknown sensor type: %02x%02x",
-                       high, low);
+       switch (high) {
+       case 0x96:
+               switch (low) {
+               case 0x40:
+                       PDEBUG(D_PROBE, "Sensor is a OV2610");
+                       sd->sensor = SEN_OV2610;
+                       return;
+               case 0x41:
+                       PDEBUG(D_PROBE, "Sensor is a OV2610AE");
+                       sd->sensor = SEN_OV2610AE;
+                       return;
+               case 0xb1:
+                       PDEBUG(D_PROBE, "Sensor is a OV9600");
+                       sd->sensor = SEN_OV9600;
+                       return;
+               }
+               break;
+       case 0x36:
+               if ((low & 0x0f) == 0x00) {
+                       PDEBUG(D_PROBE, "Sensor is a OV3610");
+                       sd->sensor = SEN_OV3610;
+                       return;
+               }
+               break;
        }
+       err("Error unknown sensor type: %02x%02x", high, low);
 }
 
 /* This initializes the OV8110, OV8610 sensor. The OV8110 uses
@@ -3400,6 +3448,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
                        cam->cam_mode = ovfx2_ov3610_mode;
                        cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode);
                        break;
+               case SEN_OV9600:
+                       cam->cam_mode = ovfx2_ov9600_mode;
+                       cam->nmodes = ARRAY_SIZE(ovfx2_ov9600_mode);
+                       break;
                default:
                        if (sd->sif) {
                                cam->cam_mode = ov519_sif_mode;
@@ -3497,6 +3549,12 @@ static int sd_init(struct gspca_dev *gspca_dev)
        case SEN_OV8610:
                write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610));
                break;
+       case SEN_OV9600:
+               write_i2c_regvals(sd, norm_9600, ARRAY_SIZE(norm_9600));
+
+               /* enable autoexpo */
+/*             i2c_w_mask(sd, 0x13, 0x05, 0x05); */
+               break;
        }
        return gspca_dev->usb_err;
 error:
@@ -4085,6 +4143,33 @@ static void mode_init_ov_sensor_regs(struct sd *sd)
                i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
                i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
                break;
+       case SEN_OV9600: {
+               const struct ov_i2c_regvals *vals;
+               static const struct ov_i2c_regvals sxga_15[] = {
+                       {0x11, 0x80}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75}
+               };
+               static const struct ov_i2c_regvals sxga_7_5[] = {
+                       {0x11, 0x81}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75}
+               };
+               static const struct ov_i2c_regvals vga_30[] = {
+                       {0x11, 0x81}, {0x14, 0x7e}, {0x24, 0x70}, {0x25, 0x60}
+               };
+               static const struct ov_i2c_regvals vga_15[] = {
+                       {0x11, 0x83}, {0x14, 0x3e}, {0x24, 0x80}, {0x25, 0x70}
+               };
+
+               /* frame rates:
+                *      15fps / 7.5 fps for 1280x1024
+                *      30fps / 15fps for 640x480
+                */
+               i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0x40);
+               if (qvga)
+                       vals = sd->frame_rate < 30 ? vga_15 : vga_30;
+               else
+                       vals = sd->frame_rate < 15 ? sxga_7_5 : sxga_15;
+               write_i2c_regvals(sd, vals, ARRAY_SIZE(sxga_15));
+               return;
+           }
        default:
                return;
        }
@@ -4120,6 +4205,7 @@ static void set_ov_sensor_window(struct sd *sd)
        case SEN_OV2610AE:
        case SEN_OV3610:
        case SEN_OV7670:
+       case SEN_OV9600:
                mode_init_ov_sensor_regs(sd);
                return;
        case SEN_OV7660:
@@ -4920,7 +5006,8 @@ static const struct sd_desc sd_desc = {
 static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF },
        {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
-       {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x405f),
+               .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
        {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
        {USB_DEVICE(0x041e, 0x4064),
diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/video/gspca/se401.c
new file mode 100644 (file)
index 0000000..4c283c2
--- /dev/null
@@ -0,0 +1,774 @@
+/*
+ * GSPCA Endpoints (formerly known as AOX) se401 USB Camera sub Driver
+ *
+ * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on the v4l1 se401 driver which is:
+ *
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define MODULE_NAME "se401"
+
+#define BULK_SIZE 4096
+#define PACKET_SIZE 1024
+#define READ_REQ_SIZE 64
+#define MAX_MODES ((READ_REQ_SIZE - 6) / 4)
+/* The se401 compression algorithm uses a fixed quant factor, which
+   can be configured by setting the high nibble of the SE401_OPERATINGMODE
+   feature. This needs to exactly match what is in libv4l! */
+#define SE401_QUANT_FACT 8
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include "gspca.h"
+#include "se401.h"
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Endpoints se401");
+MODULE_LICENSE("GPL");
+
+/* controls */
+enum e_ctrl {
+       BRIGHTNESS,
+       GAIN,
+       EXPOSURE,
+       FREQ,
+       NCTRL   /* number of controls */
+};
+
+/* exposure change state machine states */
+enum {
+       EXPO_CHANGED,
+       EXPO_DROP_FRAME,
+       EXPO_NO_CHANGE,
+};
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+       struct gspca_ctrl ctrls[NCTRL];
+       struct v4l2_pix_format fmts[MAX_MODES];
+       int pixels_read;
+       int packet_read;
+       u8 packet[PACKET_SIZE];
+       u8 restart_stream;
+       u8 button_state;
+       u8 resetlevel;
+       u8 resetlevel_frame_count;
+       int resetlevel_adjust_dir;
+       int expo_change_state;
+};
+
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRL] = {
+[BRIGHTNESS] = {
+               {
+                       .id      = V4L2_CID_BRIGHTNESS,
+                       .type    = V4L2_CTRL_TYPE_INTEGER,
+                       .name    = "Brightness",
+                       .minimum = 0,
+                       .maximum = 255,
+                       .step    = 1,
+                       .default_value = 15,
+               },
+               .set_control = setbrightness
+       },
+[GAIN] = {
+               {
+                       .id      = V4L2_CID_GAIN,
+                       .type    = V4L2_CTRL_TYPE_INTEGER,
+                       .name    = "Gain",
+                       .minimum = 0,
+                       .maximum = 50, /* Really 63 but > 50 is not pretty */
+                       .step    = 1,
+                       .default_value = 25,
+               },
+               .set_control = setgain
+       },
+[EXPOSURE] = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "Exposure",
+                       .minimum = 0,
+                       .maximum = 32767,
+                       .step = 1,
+                       .default_value = 15000,
+               },
+               .set_control = setexposure
+       },
+[FREQ] = {
+               {
+                       .id      = V4L2_CID_POWER_LINE_FREQUENCY,
+                       .type    = V4L2_CTRL_TYPE_MENU,
+                       .name    = "Light frequency filter",
+                       .minimum = 0,
+                       .maximum = 2,
+                       .step    = 1,
+                       .default_value = 0,
+               },
+               .set_control = setexposure
+       },
+};
+
+static void se401_write_req(struct gspca_dev *gspca_dev, u16 req, u16 value,
+                           int silent)
+{
+       int err;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+
+       err = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0), req,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             value, 0, NULL, 0, 1000);
+       if (err < 0) {
+               if (!silent)
+                       err("write req failed req %#04x val %#04x error %d",
+                           req, value, err);
+               gspca_dev->usb_err = err;
+       }
+}
+
+static void se401_read_req(struct gspca_dev *gspca_dev, u16 req, int silent)
+{
+       int err;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+
+       if (USB_BUF_SZ < READ_REQ_SIZE) {
+               err("USB_BUF_SZ too small!!");
+               gspca_dev->usb_err = -ENOBUFS;
+               return;
+       }
+
+       err = usb_control_msg(gspca_dev->dev,
+                             usb_rcvctrlpipe(gspca_dev->dev, 0), req,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0, 0, gspca_dev->usb_buf, READ_REQ_SIZE, 1000);
+       if (err < 0) {
+               if (!silent)
+                       err("read req failed req %#04x error %d", req, err);
+               gspca_dev->usb_err = err;
+       }
+}
+
+static void se401_set_feature(struct gspca_dev *gspca_dev,
+                             u16 selector, u16 param)
+{
+       int err;
+
+       if (gspca_dev->usb_err < 0)
+               return;
+
+       err = usb_control_msg(gspca_dev->dev,
+                             usb_sndctrlpipe(gspca_dev->dev, 0),
+                             SE401_REQ_SET_EXT_FEATURE,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             param, selector, NULL, 0, 1000);
+       if (err < 0) {
+               err("set feature failed sel %#04x param %#04x error %d",
+                   selector, param, err);
+               gspca_dev->usb_err = err;
+       }
+}
+
+static int se401_get_feature(struct gspca_dev *gspca_dev, u16 selector)
+{
+       int err;
+
+       if (gspca_dev->usb_err < 0)
+               return gspca_dev->usb_err;
+
+       if (USB_BUF_SZ < 2) {
+               err("USB_BUF_SZ too small!!");
+               gspca_dev->usb_err = -ENOBUFS;
+               return gspca_dev->usb_err;
+       }
+
+       err = usb_control_msg(gspca_dev->dev,
+                             usb_rcvctrlpipe(gspca_dev->dev, 0),
+                             SE401_REQ_GET_EXT_FEATURE,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0, selector, gspca_dev->usb_buf, 2, 1000);
+       if (err < 0) {
+               err("get feature failed sel %#04x error %d", selector, err);
+               gspca_dev->usb_err = err;
+               return err;
+       }
+       return gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8);
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS))
+               return;
+
+       /* HDG: this does not seem to do anything on my cam */
+       se401_write_req(gspca_dev, SE401_REQ_SET_BRT,
+                       sd->ctrls[BRIGHTNESS].val, 0);
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       u16 gain = 63 - sd->ctrls[GAIN].val;
+
+       /* red color gain */
+       se401_set_feature(gspca_dev, HV7131_REG_ARCG, gain);
+       /* green color gain */
+       se401_set_feature(gspca_dev, HV7131_REG_AGCG, gain);
+       /* blue color gain */
+       se401_set_feature(gspca_dev, HV7131_REG_ABCG, gain);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int integration = sd->ctrls[EXPOSURE].val << 6;
+       u8 expose_h, expose_m, expose_l;
+
+       /* Do this before the set_feature calls, for proper timing wrt
+          the interrupt driven pkt_scan. Note we may still race but that
+          is not a big issue, the expo change state machine is merely for
+          avoiding underexposed frames getting send out, if one sneaks
+          through so be it */
+       sd->expo_change_state = EXPO_CHANGED;
+
+       if (sd->ctrls[FREQ].val == V4L2_CID_POWER_LINE_FREQUENCY_50HZ)
+               integration = integration - integration % 106667;
+       if (sd->ctrls[FREQ].val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ)
+               integration = integration - integration % 88889;
+
+       expose_h = (integration >> 16);
+       expose_m = (integration >> 8);
+       expose_l = integration;
+
+       /* integration time low */
+       se401_set_feature(gspca_dev, HV7131_REG_TITL, expose_l);
+       /* integration time mid */
+       se401_set_feature(gspca_dev, HV7131_REG_TITM, expose_m);
+       /* integration time high */
+       se401_set_feature(gspca_dev, HV7131_REG_TITU, expose_h);
+}
+
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       struct cam *cam = &gspca_dev->cam;
+       u8 *cd = gspca_dev->usb_buf;
+       int i, j, n;
+       int widths[MAX_MODES], heights[MAX_MODES];
+
+       /* Read the camera descriptor */
+       se401_read_req(gspca_dev, SE401_REQ_GET_CAMERA_DESCRIPTOR, 1);
+       if (gspca_dev->usb_err) {
+               /* Sometimes after being idle for a while the se401 won't
+                  respond and needs a good kicking  */
+               usb_reset_device(gspca_dev->dev);
+               gspca_dev->usb_err = 0;
+               se401_read_req(gspca_dev, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0);
+       }
+
+       /* Some cameras start with their LED on */
+       se401_write_req(gspca_dev, SE401_REQ_LED_CONTROL, 0, 0);
+       if (gspca_dev->usb_err)
+               return gspca_dev->usb_err;
+
+       if (cd[1] != 0x41) {
+               err("Wrong descriptor type");
+               return -ENODEV;
+       }
+
+       if (!(cd[2] & SE401_FORMAT_BAYER)) {
+               err("Bayer format not supported!");
+               return -ENODEV;
+       }
+
+       if (cd[3])
+               info("ExtraFeatures: %d", cd[3]);
+
+       n = cd[4] | (cd[5] << 8);
+       if (n > MAX_MODES) {
+               err("Too many frame sizes");
+               return -ENODEV;
+       }
+
+       for (i = 0; i < n ; i++) {
+               widths[i] = cd[6 + i * 4 + 0] | (cd[6 + i * 4 + 1] << 8);
+               heights[i] = cd[6 + i * 4 + 2] | (cd[6 + i * 4 + 3] << 8);
+       }
+
+       for (i = 0; i < n ; i++) {
+               sd->fmts[i].width = widths[i];
+               sd->fmts[i].height = heights[i];
+               sd->fmts[i].field = V4L2_FIELD_NONE;
+               sd->fmts[i].colorspace = V4L2_COLORSPACE_SRGB;
+               sd->fmts[i].priv = 1;
+
+               /* janggu compression only works for 1/4th or 1/16th res */
+               for (j = 0; j < n; j++) {
+                       if (widths[j] / 2 == widths[i] &&
+                           heights[j] / 2 == heights[i]) {
+                               sd->fmts[i].priv = 2;
+                               break;
+                       }
+               }
+               /* 1/16th if available too is better then 1/4th, because
+                  we then use a larger area of the sensor */
+               for (j = 0; j < n; j++) {
+                       if (widths[j] / 4 == widths[i] &&
+                           heights[j] / 4 == heights[i]) {
+                               sd->fmts[i].priv = 4;
+                               break;
+                       }
+               }
+
+               if (sd->fmts[i].priv == 1) {
+                       /* Not a 1/4th or 1/16th res, use bayer */
+                       sd->fmts[i].pixelformat = V4L2_PIX_FMT_SBGGR8;
+                       sd->fmts[i].bytesperline = widths[i];
+                       sd->fmts[i].sizeimage = widths[i] * heights[i];
+                       info("Frame size: %dx%d bayer", widths[i], heights[i]);
+               } else {
+                       /* Found a match use janggu compression */
+                       sd->fmts[i].pixelformat = V4L2_PIX_FMT_SE401;
+                       sd->fmts[i].bytesperline = 0;
+                       sd->fmts[i].sizeimage = widths[i] * heights[i] * 3;
+                       info("Frame size: %dx%d 1/%dth janggu",
+                            widths[i], heights[i],
+                            sd->fmts[i].priv * sd->fmts[i].priv);
+               }
+       }
+
+       cam->cam_mode = sd->fmts;
+       cam->nmodes = n;
+       cam->bulk = 1;
+       cam->bulk_size = BULK_SIZE;
+       cam->bulk_nurbs = 4;
+       cam->ctrls = sd->ctrls;
+       gspca_dev->nbalt = 1;  /* Ignore the bogus isoc alt settings */
+       sd->resetlevel = 0x2d; /* Set initial resetlevel */
+
+       /* See if the camera supports brightness */
+       se401_read_req(gspca_dev, SE401_REQ_GET_BRT, 1);
+       if (gspca_dev->usb_err) {
+               gspca_dev->ctrl_dis = (1 << BRIGHTNESS);
+               gspca_dev->usb_err = 0;
+       }
+
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       int mult = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+       int mode = 0;
+
+       se401_write_req(gspca_dev, SE401_REQ_CAMERA_POWER, 1, 1);
+       if (gspca_dev->usb_err) {
+               /* Sometimes after being idle for a while the se401 won't
+                  respond and needs a good kicking  */
+               usb_reset_device(gspca_dev->dev);
+               gspca_dev->usb_err = 0;
+               se401_write_req(gspca_dev, SE401_REQ_CAMERA_POWER, 1, 0);
+       }
+       se401_write_req(gspca_dev, SE401_REQ_LED_CONTROL, 1, 0);
+
+       se401_set_feature(gspca_dev, HV7131_REG_MODE_B, 0x05);
+
+       /* set size + mode */
+       se401_write_req(gspca_dev, SE401_REQ_SET_WIDTH,
+                       gspca_dev->width * mult, 0);
+       se401_write_req(gspca_dev, SE401_REQ_SET_HEIGHT,
+                       gspca_dev->height * mult, 0);
+       /*
+        * HDG: disabled this as it does not seem to do anything
+        * se401_write_req(gspca_dev, SE401_REQ_SET_OUTPUT_MODE,
+        *                 SE401_FORMAT_BAYER, 0);
+        */
+
+       switch (mult) {
+       case 1: /* Raw bayer */
+               mode = 0x03; break;
+       case 2: /* 1/4th janggu */
+               mode = SE401_QUANT_FACT << 4; break;
+       case 4: /* 1/16th janggu */
+               mode = (SE401_QUANT_FACT << 4) | 0x02; break;
+       }
+       se401_set_feature(gspca_dev, SE401_OPERATINGMODE, mode);
+
+       setbrightness(gspca_dev);
+       setgain(gspca_dev);
+       setexposure(gspca_dev);
+       se401_set_feature(gspca_dev, HV7131_REG_ARLV, sd->resetlevel);
+
+       sd->packet_read = 0;
+       sd->pixels_read = 0;
+       sd->restart_stream = 0;
+       sd->resetlevel_frame_count = 0;
+       sd->resetlevel_adjust_dir = 0;
+       sd->expo_change_state = EXPO_NO_CHANGE;
+
+       se401_write_req(gspca_dev, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, 0);
+
+       return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       se401_write_req(gspca_dev, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, 0);
+       se401_write_req(gspca_dev, SE401_REQ_LED_CONTROL, 0, 0);
+       se401_write_req(gspca_dev, SE401_REQ_CAMERA_POWER, 0, 0);
+}
+
+static void sd_dq_callback(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       unsigned int ahrc, alrc;
+       int oldreset, adjust_dir;
+
+       /* Restart the stream if requested do so by pkt_scan */
+       if (sd->restart_stream) {
+               sd_stopN(gspca_dev);
+               sd_start(gspca_dev);
+               sd->restart_stream = 0;
+       }
+
+       /* Automatically adjust sensor reset level
+          Hyundai have some really nice docs about this and other sensor
+          related stuff on their homepage: www.hei.co.kr */
+       sd->resetlevel_frame_count++;
+       if (sd->resetlevel_frame_count < 20)
+               return;
+
+       /* For some reason this normally read-only register doesn't get reset
+          to zero after reading them just once... */
+       se401_get_feature(gspca_dev, HV7131_REG_HIREFNOH);
+       se401_get_feature(gspca_dev, HV7131_REG_HIREFNOL);
+       se401_get_feature(gspca_dev, HV7131_REG_LOREFNOH);
+       se401_get_feature(gspca_dev, HV7131_REG_LOREFNOL);
+       ahrc = 256*se401_get_feature(gspca_dev, HV7131_REG_HIREFNOH) +
+           se401_get_feature(gspca_dev, HV7131_REG_HIREFNOL);
+       alrc = 256*se401_get_feature(gspca_dev, HV7131_REG_LOREFNOH) +
+           se401_get_feature(gspca_dev, HV7131_REG_LOREFNOL);
+
+       /* Not an exact science, but it seems to work pretty well... */
+       oldreset = sd->resetlevel;
+       if (alrc > 10) {
+               while (alrc >= 10 && sd->resetlevel < 63) {
+                       sd->resetlevel++;
+                       alrc /= 2;
+               }
+       } else if (ahrc > 20) {
+               while (ahrc >= 20 && sd->resetlevel > 0) {
+                       sd->resetlevel--;
+                       ahrc /= 2;
+               }
+       }
+       /* Detect ping-pong-ing and halve adjustment to avoid overshoot */
+       if (sd->resetlevel > oldreset)
+               adjust_dir = 1;
+       else
+               adjust_dir = -1;
+       if (sd->resetlevel_adjust_dir &&
+           sd->resetlevel_adjust_dir != adjust_dir)
+               sd->resetlevel = oldreset + (sd->resetlevel - oldreset) / 2;
+
+       if (sd->resetlevel != oldreset) {
+               sd->resetlevel_adjust_dir = adjust_dir;
+               se401_set_feature(gspca_dev, HV7131_REG_ARLV, sd->resetlevel);
+       }
+
+       sd->resetlevel_frame_count = 0;
+}
+
+static void sd_complete_frame(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+
+       switch (sd->expo_change_state) {
+       case EXPO_CHANGED:
+               /* The exposure was changed while this frame
+                  was being send, so this frame is ok */
+               sd->expo_change_state = EXPO_DROP_FRAME;
+               break;
+       case EXPO_DROP_FRAME:
+               /* The exposure was changed while this frame
+                  was being captured, drop it! */
+               gspca_dev->last_packet_type = DISCARD_PACKET;
+               sd->expo_change_state = EXPO_NO_CHANGE;
+               break;
+       case EXPO_NO_CHANGE:
+               break;
+       }
+       gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
+}
+
+static void sd_pkt_scan_janggu(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       int imagesize = gspca_dev->width * gspca_dev->height;
+       int i, plen, bits, pixels, info, count;
+
+       if (sd->restart_stream)
+               return;
+
+       /* Sometimes a 1024 bytes garbage bulk packet is send between frames */
+       if (gspca_dev->last_packet_type == LAST_PACKET && len == 1024) {
+               gspca_dev->last_packet_type = DISCARD_PACKET;
+               return;
+       }
+
+       i = 0;
+       while (i < len) {
+               /* Read header if not already be present from prev bulk pkt */
+               if (sd->packet_read < 4) {
+                       count = 4 - sd->packet_read;
+                       if (count > len - i)
+                               count = len - i;
+                       memcpy(&sd->packet[sd->packet_read], &data[i], count);
+                       sd->packet_read += count;
+                       i += count;
+                       if (sd->packet_read < 4)
+                               break;
+               }
+               bits   = sd->packet[3] + (sd->packet[2] << 8);
+               pixels = sd->packet[1] + ((sd->packet[0] & 0x3f) << 8);
+               info   = (sd->packet[0] & 0xc0) >> 6;
+               plen   = ((bits + 47) >> 4) << 1;
+               /* Sanity checks */
+               if (plen > 1024) {
+                       err("invalid packet len %d restarting stream", plen);
+                       goto error;
+               }
+               if (info == 3) {
+                       err("unknown frame info value restarting stream");
+                       goto error;
+               }
+
+               /* Read (remainder of) packet contents */
+               count = plen - sd->packet_read;
+               if (count > len - i)
+                       count = len - i;
+               memcpy(&sd->packet[sd->packet_read], &data[i], count);
+               sd->packet_read += count;
+               i += count;
+               if (sd->packet_read < plen)
+                       break;
+
+               sd->pixels_read += pixels;
+               sd->packet_read = 0;
+
+               switch (info) {
+               case 0: /* Frame data */
+                       gspca_frame_add(gspca_dev, INTER_PACKET, sd->packet,
+                                       plen);
+                       break;
+               case 1: /* EOF */
+                       if (sd->pixels_read != imagesize) {
+                               err("frame size %d expected %d",
+                                   sd->pixels_read, imagesize);
+                               goto error;
+                       }
+                       sd_complete_frame(gspca_dev, sd->packet, plen);
+                       return; /* Discard the rest of the bulk packet !! */
+               case 2: /* SOF */
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, sd->packet,
+                                       plen);
+                       sd->pixels_read = pixels;
+                       break;
+               }
+       }
+       return;
+
+error:
+       sd->restart_stream = 1;
+       /* Give userspace a 0 bytes frame, so our dq callback gets
+          called and it can restart the stream */
+       gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+       gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+}
+
+static void sd_pkt_scan_bayer(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       struct cam *cam = &gspca_dev->cam;
+       int imagesize = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
+
+       if (gspca_dev->image_len == 0) {
+               gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
+               return;
+       }
+
+       if (gspca_dev->image_len + len >= imagesize) {
+               sd_complete_frame(gspca_dev, data, len);
+               return;
+       }
+
+       gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       int mult = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+
+       if (len == 0)
+               return;
+
+       if (mult == 1) /* mult == 1 means raw bayer */
+               sd_pkt_scan_bayer(gspca_dev, data, len);
+       else
+               sd_pkt_scan_janggu(gspca_dev, data, len);
+}
+
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+                       struct v4l2_querymenu *menu)
+{
+       switch (menu->id) {
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               switch (menu->index) {
+               case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
+                       strcpy((char *) menu->name, "NoFliker");
+                       return 0;
+               case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
+                       strcpy((char *) menu->name, "50 Hz");
+                       return 0;
+               case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
+                       strcpy((char *) menu->name, "60 Hz");
+                       return 0;
+               }
+               break;
+       }
+       return -EINVAL;
+}
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+       struct sd *sd = (struct sd *)gspca_dev;
+       u8 state;
+
+       if (len != 2)
+               return -EINVAL;
+
+       switch (data[0]) {
+       case 0:
+       case 1:
+               state = data[0];
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (sd->button_state != state) {
+               input_report_key(gspca_dev->input_dev, KEY_CAMERA, state);
+               input_sync(gspca_dev->input_dev);
+               sd->button_state = state;
+       }
+
+       return 0;
+}
+#endif
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .ctrls = sd_ctrls,
+       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .config = sd_config,
+       .init = sd_init,
+       .start = sd_start,
+       .stopN = sd_stopN,
+       .dq_callback = sd_dq_callback,
+       .pkt_scan = sd_pkt_scan,
+       .querymenu = sd_querymenu,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       .int_pkt_scan = sd_int_pkt_scan,
+#endif
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x03e8, 0x0004)}, /* Endpoints/Aox SE401 */
+       {USB_DEVICE(0x0471, 0x030b)}, /* Philips PCVC665K */
+       {USB_DEVICE(0x047d, 0x5001)}, /* Kensington 67014 */
+       {USB_DEVICE(0x047d, 0x5002)}, /* Kensington 6701(5/7) */
+       {USB_DEVICE(0x047d, 0x5003)}, /* Kensington 67016 */
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                               THIS_MODULE);
+}
+
+static int sd_pre_reset(struct usb_interface *intf)
+{
+       return 0;
+}
+
+static int sd_post_reset(struct usb_interface *intf)
+{
+       return 0;
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
+       .pre_reset = sd_pre_reset,
+       .post_reset = sd_post_reset,
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       return usb_register(&sd_driver);
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/se401.h b/drivers/media/video/gspca/se401.h
new file mode 100644 (file)
index 0000000..96d8ebf
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * GSPCA Endpoints (formerly known as AOX) se401 USB Camera sub Driver
+ *
+ * Copyright (C) 2011 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on the v4l1 se401 driver which is:
+ *
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define SE401_REQ_GET_CAMERA_DESCRIPTOR                0x06
+#define SE401_REQ_START_CONTINUOUS_CAPTURE     0x41
+#define SE401_REQ_STOP_CONTINUOUS_CAPTURE      0x42
+#define SE401_REQ_CAPTURE_FRAME                        0x43
+#define SE401_REQ_GET_BRT                      0x44
+#define SE401_REQ_SET_BRT                      0x45
+#define SE401_REQ_GET_WIDTH                    0x4c
+#define SE401_REQ_SET_WIDTH                    0x4d
+#define SE401_REQ_GET_HEIGHT                   0x4e
+#define SE401_REQ_SET_HEIGHT                   0x4f
+#define SE401_REQ_GET_OUTPUT_MODE              0x50
+#define SE401_REQ_SET_OUTPUT_MODE              0x51
+#define SE401_REQ_GET_EXT_FEATURE              0x52
+#define SE401_REQ_SET_EXT_FEATURE              0x53
+#define SE401_REQ_CAMERA_POWER                 0x56
+#define SE401_REQ_LED_CONTROL                  0x57
+#define SE401_REQ_BIOS                         0xff
+
+#define SE401_BIOS_READ                                0x07
+
+#define SE401_FORMAT_BAYER     0x40
+
+/* Hyundai hv7131b registers
+   7121 and 7141 should be the same (haven't really checked...) */
+/* Mode registers: */
+#define HV7131_REG_MODE_A              0x00
+#define HV7131_REG_MODE_B              0x01
+#define HV7131_REG_MODE_C              0x02
+/* Frame registers: */
+#define HV7131_REG_FRSU                0x10
+#define HV7131_REG_FRSL                0x11
+#define HV7131_REG_FCSU                0x12
+#define HV7131_REG_FCSL                0x13
+#define HV7131_REG_FWHU                0x14
+#define HV7131_REG_FWHL                0x15
+#define HV7131_REG_FWWU                0x16
+#define HV7131_REG_FWWL                0x17
+/* Timing registers: */
+#define HV7131_REG_THBU                0x20
+#define HV7131_REG_THBL                0x21
+#define HV7131_REG_TVBU                0x22
+#define HV7131_REG_TVBL                0x23
+#define HV7131_REG_TITU                0x25
+#define HV7131_REG_TITM                0x26
+#define HV7131_REG_TITL                0x27
+#define HV7131_REG_TMCD                0x28
+/* Adjust Registers: */
+#define HV7131_REG_ARLV                0x30
+#define HV7131_REG_ARCG                0x31
+#define HV7131_REG_AGCG                0x32
+#define HV7131_REG_ABCG                0x33
+#define HV7131_REG_APBV                0x34
+#define HV7131_REG_ASLP                0x54
+/* Offset Registers: */
+#define HV7131_REG_OFSR                0x50
+#define HV7131_REG_OFSG                0x51
+#define HV7131_REG_OFSB                0x52
+/* REset level statistics registers: */
+#define HV7131_REG_LOREFNOH    0x57
+#define HV7131_REG_LOREFNOL    0x58
+#define HV7131_REG_HIREFNOH    0x59
+#define HV7131_REG_HIREFNOL    0x5a
+
+/* se401 registers */
+#define SE401_OPERATINGMODE    0x2000
index b089c0d3ee9f96dc7b2de6f770105efe35db1503..6ec232902183ebb7b2dc4c7afe93010b9c1cd791 100644 (file)
@@ -247,7 +247,6 @@ static const struct cmd spca504A_clicksmart420_init_data[] = {
        {0x30, 0x0004, 0x000a},
        {0xb0, 0x0001, 0x0000},
 
-
        {0xa1, 0x0080, 0x0001},
        {0x30, 0x0049, 0x0000},
        {0x30, 0x0060, 0x0005},
@@ -256,8 +255,6 @@ static const struct cmd spca504A_clicksmart420_init_data[] = {
        {0x00, 0x0000, 0x2000},
        {0x00, 0x0013, 0x2301},
        {0x00, 0x0003, 0x2000},
-       {0x00, 0x0000, 0x2000},
-
 };
 
 /* clicksmart 420 open data ? */
index 7e762d55109915d52e0d7306e554f2210d2f6461..d1d733b9359b41e9f012a6d6b651d2f4b2597a3b 100644 (file)
@@ -1387,7 +1387,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
                return 0;
        case V4L2_CID_EFFECTS:
                if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
-                       strncpy((char *) menu->name,
+                       strlcpy((char *) menu->name,
                                effects_control[menu->index],
                                sizeof menu->name);
                        return 0;
index 5f1db46beb4e18031a0342f9f6e48cc241106303..441dacf642bb090fc270676403868f778d3b34e3 100644 (file)
@@ -474,5 +474,6 @@ module_init(hdpvr_init);
 module_exit(hdpvr_exit);
 
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2.1");
 MODULE_AUTHOR("Janne Grunau");
 MODULE_DESCRIPTION("Hauppauge HD PVR driver");
index 514aea76eaa5b68b30acf66b0ce4fd4446421fb5..087f7c08cb851ee50485dd2a50e80f30d9a82674 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/mutex.h>
-#include <linux/version.h>
 #include <linux/workqueue.h>
 
 #include <linux/videodev2.h>
@@ -574,7 +573,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strcpy(cap->driver, "hdpvr");
        strcpy(cap->card, "Hauppauge HD PVR");
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-       cap->version = HDPVR_VERSION;
        cap->capabilities =     V4L2_CAP_VIDEO_CAPTURE |
                                V4L2_CAP_AUDIO         |
                                V4L2_CAP_READWRITE;
index 072f23c570f343388e11582d504e07e7ae38ab74..d6439db1d18beb1d10b745a303149316016236e6 100644 (file)
 #include <media/v4l2-device.h>
 #include <media/ir-kbd-i2c.h>
 
-#define HDPVR_MAJOR_VERSION 0
-#define HDPVR_MINOR_VERSION 2
-#define HDPVR_RELEASE 0
-#define HDPVR_VERSION \
-       KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE)
-
 #define HDPVR_MAX 8
 #define HDPVR_I2C_MAX_SIZE 128
 
index 84bdf0f42a8eb81a3b4016869547e24cb2d46202..8f9cc17b518eaaf6320e092d0a667d8d4876e586 100644 (file)
@@ -36,7 +36,6 @@
  *                using information provided by Jiun-Kuei Jung @ AVerMedia.
  */
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
index a7f54b010a5c705e1fd0320b1f9aaaaf8ec8f7aa..38f052257f4620498d6b23e0bf3b7cfb88aa5ba9 100644 (file)
@@ -722,8 +722,8 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
 
        /* If there are subscribed events, then only use the new event
           API instead of the old video.h based API. */
-       if (!list_empty(&id->fh.events->subscribed)) {
-               poll_wait(filp, &id->fh.events->wait, wait);
+       if (!list_empty(&id->fh.subscribed)) {
+               poll_wait(filp, &id->fh.wait, wait);
                /* Turn off the old-style vsync events */
                clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
                if (v4l2_event_pending(&id->fh))
@@ -750,6 +750,7 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
        struct ivtv *itv = id->itv;
        struct ivtv_stream *s = &itv->streams[id->type];
        int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+       unsigned res = 0;
 
        /* Start a capture if there is none */
        if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
@@ -769,12 +770,16 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
        /* add stream's waitq to the poll list */
        IVTV_DEBUG_HI_FILE("Encoder poll\n");
        poll_wait(filp, &s->waitq, wait);
+       if (v4l2_event_pending(&id->fh))
+               res |= POLLPRI;
+       else
+               poll_wait(filp, &id->fh.wait, wait);
 
        if (s->q_full.length || s->q_io.length)
-               return POLLIN | POLLRDNORM;
+               return res | POLLIN | POLLRDNORM;
        if (eof)
-               return POLLHUP;
-       return 0;
+               return res | POLLHUP;
+       return res;
 }
 
 void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
@@ -961,10 +966,6 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
                return -ENOMEM;
        }
        v4l2_fh_init(&item->fh, s->vdev);
-       if (s->type == IVTV_DEC_STREAM_TYPE_YUV ||
-           s->type == IVTV_DEC_STREAM_TYPE_MPG) {
-               res = v4l2_event_alloc(&item->fh, 60);
-       }
        if (res < 0) {
                v4l2_fh_exit(&item->fh);
                kfree(item);
index 120c7d8e0895ea36619e97759b34b0184edd2bf6..3e5c090af112bf12fb229bda27166e08db935d3d 100644 (file)
@@ -757,7 +757,6 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
        strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
        strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
        snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
-       vcap->version = IVTV_DRIVER_VERSION;        /* version */
        vcap->capabilities = itv->v4l2_cap;         /* capabilities */
        return 0;
 }
@@ -1451,11 +1450,11 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscripti
        switch (sub->type) {
        case V4L2_EVENT_VSYNC:
        case V4L2_EVENT_EOS:
-               break;
+       case V4L2_EVENT_CTRL:
+               return v4l2_event_subscribe(fh, sub, 0);
        default:
                return -EINVAL;
        }
-       return v4l2_event_subscribe(fh, sub);
 }
 
 static int ivtv_log_status(struct file *file, void *fh)
index b67a4048f5aa422fe7c198ae467c58fdd6c3b964..a20f346fcad89b4ef245423b579e072da14965ec 100644 (file)
 #define IVTV_VERSION_H
 
 #define IVTV_DRIVER_NAME "ivtv"
-#define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 4
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 2
-
-#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
-#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
+#define IVTV_VERSION "1.4.3"
 
 #endif
index a45d8f098e02a200a52c05a4155866050bb15c6b..3248ac8057119dcabbe0c726206f9fa60e2ca612 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/version.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/videodev2.h>
index 43c68f51c5ce07822b58b44de9efe7749e1c3cf9..fb8e4a7a9dd29f27fdf96a5191a4e1581f5ddf56 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/version.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/videodev2.h>
diff --git a/drivers/media/video/marvell-ccic/Kconfig b/drivers/media/video/marvell-ccic/Kconfig
new file mode 100644 (file)
index 0000000..bf739e3
--- /dev/null
@@ -0,0 +1,23 @@
+config VIDEO_CAFE_CCIC
+       tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support"
+       depends on PCI && I2C && VIDEO_V4L2
+       select VIDEO_OV7670
+       select VIDEOBUF2_VMALLOC
+       select VIDEOBUF2_DMA_CONTIG
+       ---help---
+         This is a video4linux2 driver for the Marvell 88ALP01 integrated
+         CMOS camera controller.  This is the controller found on first-
+         generation OLPC systems.
+
+config VIDEO_MMP_CAMERA
+       tristate "Marvell Armada 610 integrated camera controller support"
+       depends on ARCH_MMP && I2C && VIDEO_V4L2
+       select VIDEO_OV7670
+       select I2C_GPIO
+       select VIDEOBUF2_DMA_SG
+       ---help---
+         This is a Video4Linux2 driver for the integrated camera
+         controller found on Marvell Armada 610 application
+         processors (and likely beyond).  This is the controller found
+         in OLPC XO 1.75 systems.
+
diff --git a/drivers/media/video/marvell-ccic/Makefile b/drivers/media/video/marvell-ccic/Makefile
new file mode 100644 (file)
index 0000000..05a792c
--- /dev/null
@@ -0,0 +1,6 @@
+obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+cafe_ccic-y := cafe-driver.o mcam-core.o
+
+obj-$(CONFIG_VIDEO_MMP_CAMERA) += mmp_camera.o
+mmp_camera-y := mmp-driver.o mcam-core.o
+
diff --git a/drivers/media/video/marvell-ccic/cafe-driver.c b/drivers/media/video/marvell-ccic/cafe-driver.c
new file mode 100644 (file)
index 0000000..d030f9b
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe"
+ * multifunction chip.  Currently works with the Omnivision OV7670
+ * sensor.
+ *
+ * The data sheet for this device can be found at:
+ *    http://www.marvell.com/products/pc_connectivity/88alp01/
+ *
+ * Copyright 2006-11 One Laptop Per Child Association, Inc.
+ * Copyright 2006-11 Jonathan Corbet <corbet@lwn.net>
+ *
+ * Written by Jonathan Corbet, corbet@lwn.net.
+ *
+ * v4l2_device/v4l2_subdev conversion by:
+ * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "mcam-core.h"
+
+#define CAFE_VERSION 0x000002
+
+
+/*
+ * Parameters.
+ */
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("Video");
+
+
+
+
+struct cafe_camera {
+       int registered;                 /* Fully initialized? */
+       struct mcam_camera mcam;
+       struct pci_dev *pdev;
+       wait_queue_head_t smbus_wait;   /* Waiting on i2c events */
+};
+
+/*
+ * Most of the camera controller registers are defined in mcam-core.h,
+ * but the Cafe platform has some additional registers of its own;
+ * they are described here.
+ */
+
+/*
+ * "General purpose register" has a couple of GPIOs used for sensor
+ * power and reset on OLPC XO 1.0 systems.
+ */
+#define REG_GPR                0xb4
+#define          GPR_C1EN        0x00000020    /* Pad 1 (power down) enable */
+#define          GPR_C0EN        0x00000010    /* Pad 0 (reset) enable */
+#define          GPR_C1          0x00000002    /* Control 1 value */
+/*
+ * Control 0 is wired to reset on OLPC machines.  For ov7x sensors,
+ * it is active low.
+ */
+#define          GPR_C0          0x00000001    /* Control 0 value */
+
+/*
+ * These registers control the SMBUS module for communicating
+ * with the sensor.
+ */
+#define REG_TWSIC0     0xb8    /* TWSI (smbus) control 0 */
+#define          TWSIC0_EN       0x00000001    /* TWSI enable */
+#define          TWSIC0_MODE     0x00000002    /* 1 = 16-bit, 0 = 8-bit */
+#define          TWSIC0_SID      0x000003fc    /* Slave ID */
+/*
+ * Subtle trickery: the slave ID field starts with bit 2.  But the
+ * Linux i2c stack wants to treat the bottommost bit as a separate
+ * read/write bit, which is why slave ID's are usually presented
+ * >>1.  For consistency with that behavior, we shift over three
+ * bits instead of two.
+ */
+#define          TWSIC0_SID_SHIFT 3
+#define          TWSIC0_CLKDIV   0x0007fc00    /* Clock divider */
+#define          TWSIC0_MASKACK  0x00400000    /* Mask ack from sensor */
+#define          TWSIC0_OVMAGIC  0x00800000    /* Make it work on OV sensors */
+
+#define REG_TWSIC1     0xbc    /* TWSI control 1 */
+#define          TWSIC1_DATA     0x0000ffff    /* Data to/from camchip */
+#define          TWSIC1_ADDR     0x00ff0000    /* Address (register) */
+#define          TWSIC1_ADDR_SHIFT 16
+#define          TWSIC1_READ     0x01000000    /* Set for read op */
+#define          TWSIC1_WSTAT    0x02000000    /* Write status */
+#define          TWSIC1_RVALID   0x04000000    /* Read data valid */
+#define          TWSIC1_ERROR    0x08000000    /* Something screwed up */
+
+/*
+ * Here's the weird global control registers
+ */
+#define REG_GL_CSR     0x3004  /* Control/status register */
+#define          GCSR_SRS       0x00000001     /* SW Reset set */
+#define          GCSR_SRC       0x00000002     /* SW Reset clear */
+#define          GCSR_MRS       0x00000004     /* Master reset set */
+#define          GCSR_MRC       0x00000008     /* HW Reset clear */
+#define          GCSR_CCIC_EN   0x00004000    /* CCIC Clock enable */
+#define REG_GL_IMASK   0x300c  /* Interrupt mask register */
+#define          GIMSK_CCIC_EN          0x00000004    /* CCIC Interrupt enable */
+
+#define REG_GL_FCR     0x3038  /* GPIO functional control register */
+#define          GFCR_GPIO_ON    0x08          /* Camera GPIO enabled */
+#define REG_GL_GPIOR   0x315c  /* GPIO register */
+#define          GGPIO_OUT             0x80000 /* GPIO output */
+#define          GGPIO_VAL             0x00008 /* Output pin value */
+
+#define REG_LEN                       (REG_GL_IMASK + 4)
+
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+       dev_err(&(cam)->pdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+       dev_warn(&(cam)->pdev->dev, fmt, ##arg);
+
+/* -------------------------------------------------------------------- */
+/*
+ * The I2C/SMBUS interface to the camera itself starts here.  The
+ * controller handles SMBUS itself, presenting a relatively simple register
+ * interface; all we have to do is to tell it where to route the data.
+ */
+#define CAFE_SMBUS_TIMEOUT (HZ)  /* generous */
+
+static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
+{
+       struct mcam_camera *m = container_of(dev, struct mcam_camera, v4l2_dev);
+       return container_of(m, struct cafe_camera, mcam);
+}
+
+
+static int cafe_smbus_write_done(struct mcam_camera *mcam)
+{
+       unsigned long flags;
+       int c1;
+
+       /*
+        * We must delay after the interrupt, or the controller gets confused
+        * and never does give us good status.  Fortunately, we don't do this
+        * often.
+        */
+       udelay(20);
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       c1 = mcam_reg_read(mcam, REG_TWSIC1);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+       return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT;
+}
+
+static int cafe_smbus_write_data(struct cafe_camera *cam,
+               u16 addr, u8 command, u8 value)
+{
+       unsigned int rval;
+       unsigned long flags;
+       struct mcam_camera *mcam = &cam->mcam;
+
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+       rval |= TWSIC0_OVMAGIC;  /* Make OV sensors work */
+       /*
+        * Marvell sez set clkdiv to all 1's for now.
+        */
+       rval |= TWSIC0_CLKDIV;
+       mcam_reg_write(mcam, REG_TWSIC0, rval);
+       (void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */
+       rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+       mcam_reg_write(mcam, REG_TWSIC1, rval);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+       /* Unfortunately, reading TWSIC1 too soon after sending a command
+        * causes the device to die.
+        * Use a busy-wait because we often send a large quantity of small
+        * commands at-once; using msleep() would cause a lot of context
+        * switches which take longer than 2ms, resulting in a noticeable
+        * boot-time and capture-start delays.
+        */
+       mdelay(2);
+
+       /*
+        * Another sad fact is that sometimes, commands silently complete but
+        * cafe_smbus_write_done() never becomes aware of this.
+        * This happens at random and appears to possible occur with any
+        * command.
+        * We don't understand why this is. We work around this issue
+        * with the timeout in the wait below, assuming that all commands
+        * complete within the timeout.
+        */
+       wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(mcam),
+                       CAFE_SMBUS_TIMEOUT);
+
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       rval = mcam_reg_read(mcam, REG_TWSIC1);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+       if (rval & TWSIC1_WSTAT) {
+               cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr,
+                               command, value);
+               return -EIO;
+       }
+       if (rval & TWSIC1_ERROR) {
+               cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr,
+                               command, value);
+               return -EIO;
+       }
+       return 0;
+}
+
+
+
+static int cafe_smbus_read_done(struct mcam_camera *mcam)
+{
+       unsigned long flags;
+       int c1;
+
+       /*
+        * We must delay after the interrupt, or the controller gets confused
+        * and never does give us good status.  Fortunately, we don't do this
+        * often.
+        */
+       udelay(20);
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       c1 = mcam_reg_read(mcam, REG_TWSIC1);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+       return c1 & (TWSIC1_RVALID|TWSIC1_ERROR);
+}
+
+
+
+static int cafe_smbus_read_data(struct cafe_camera *cam,
+               u16 addr, u8 command, u8 *value)
+{
+       unsigned int rval;
+       unsigned long flags;
+       struct mcam_camera *mcam = &cam->mcam;
+
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
+       rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */
+       /*
+        * Marvel sez set clkdiv to all 1's for now.
+        */
+       rval |= TWSIC0_CLKDIV;
+       mcam_reg_write(mcam, REG_TWSIC0, rval);
+       (void) mcam_reg_read(mcam, REG_TWSIC1); /* force write */
+       rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
+       mcam_reg_write(mcam, REG_TWSIC1, rval);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+       wait_event_timeout(cam->smbus_wait,
+                       cafe_smbus_read_done(mcam), CAFE_SMBUS_TIMEOUT);
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       rval = mcam_reg_read(mcam, REG_TWSIC1);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+
+       if (rval & TWSIC1_ERROR) {
+               cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command);
+               return -EIO;
+       }
+       if (!(rval & TWSIC1_RVALID)) {
+               cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr,
+                               command);
+               return -EIO;
+       }
+       *value = rval & 0xff;
+       return 0;
+}
+
+/*
+ * Perform a transfer over SMBUS.  This thing is called under
+ * the i2c bus lock, so we shouldn't race with ourselves...
+ */
+static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+               unsigned short flags, char rw, u8 command,
+               int size, union i2c_smbus_data *data)
+{
+       struct cafe_camera *cam = i2c_get_adapdata(adapter);
+       int ret = -EINVAL;
+
+       /*
+        * This interface would appear to only do byte data ops.  OK
+        * it can do word too, but the cam chip has no use for that.
+        */
+       if (size != I2C_SMBUS_BYTE_DATA) {
+               cam_err(cam, "funky xfer size %d\n", size);
+               return -EINVAL;
+       }
+
+       if (rw == I2C_SMBUS_WRITE)
+               ret = cafe_smbus_write_data(cam, addr, command, data->byte);
+       else if (rw == I2C_SMBUS_READ)
+               ret = cafe_smbus_read_data(cam, addr, command, &data->byte);
+       return ret;
+}
+
+
+static void cafe_smbus_enable_irq(struct cafe_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->mcam.dev_lock, flags);
+       mcam_reg_set_bit(&cam->mcam, REG_IRQMASK, TWSIIRQS);
+       spin_unlock_irqrestore(&cam->mcam.dev_lock, flags);
+}
+
+static u32 cafe_smbus_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_SMBUS_READ_BYTE_DATA  |
+              I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
+}
+
+static struct i2c_algorithm cafe_smbus_algo = {
+       .smbus_xfer = cafe_smbus_xfer,
+       .functionality = cafe_smbus_func
+};
+
+static int cafe_smbus_setup(struct cafe_camera *cam)
+{
+       struct i2c_adapter *adap;
+       int ret;
+
+       adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+       if (adap == NULL)
+               return -ENOMEM;
+       cam->mcam.i2c_adapter = adap;
+       cafe_smbus_enable_irq(cam);
+       adap->owner = THIS_MODULE;
+       adap->algo = &cafe_smbus_algo;
+       strcpy(adap->name, "cafe_ccic");
+       adap->dev.parent = &cam->pdev->dev;
+       i2c_set_adapdata(adap, cam);
+       ret = i2c_add_adapter(adap);
+       if (ret)
+               printk(KERN_ERR "Unable to register cafe i2c adapter\n");
+       return ret;
+}
+
+static void cafe_smbus_shutdown(struct cafe_camera *cam)
+{
+       i2c_del_adapter(cam->mcam.i2c_adapter);
+       kfree(cam->mcam.i2c_adapter);
+}
+
+
+/*
+ * Controller-level stuff
+ */
+
+static void cafe_ctlr_init(struct mcam_camera *mcam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+       /*
+        * Added magic to bring up the hardware on the B-Test board
+        */
+       mcam_reg_write(mcam, 0x3038, 0x8);
+       mcam_reg_write(mcam, 0x315c, 0x80008);
+       /*
+        * Go through the dance needed to wake the device up.
+        * Note that these registers are global and shared
+        * with the NAND and SD devices.  Interaction between the
+        * three still needs to be examined.
+        */
+       mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */
+       mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRC);
+       mcam_reg_write(mcam, REG_GL_CSR, GCSR_SRC|GCSR_MRS);
+       /*
+        * Here we must wait a bit for the controller to come around.
+        */
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+       msleep(5);
+       spin_lock_irqsave(&mcam->dev_lock, flags);
+
+       mcam_reg_write(mcam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
+       mcam_reg_set_bit(mcam, REG_GL_IMASK, GIMSK_CCIC_EN);
+       /*
+        * Mask all interrupts.
+        */
+       mcam_reg_write(mcam, REG_IRQMASK, 0);
+       spin_unlock_irqrestore(&mcam->dev_lock, flags);
+}
+
+
+static void cafe_ctlr_power_up(struct mcam_camera *mcam)
+{
+       /*
+        * Part one of the sensor dance: turn the global
+        * GPIO signal on.
+        */
+       mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON);
+       mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT|GGPIO_VAL);
+       /*
+        * Put the sensor into operational mode (assumes OLPC-style
+        * wiring).  Control 0 is reset - set to 1 to operate.
+        * Control 1 is power down, set to 0 to operate.
+        */
+       mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */
+       mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0);
+}
+
+static void cafe_ctlr_power_down(struct mcam_camera *mcam)
+{
+       mcam_reg_write(mcam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1);
+       mcam_reg_write(mcam, REG_GL_FCR, GFCR_GPIO_ON);
+       mcam_reg_write(mcam, REG_GL_GPIOR, GGPIO_OUT);
+}
+
+
+
+/*
+ * The platform interrupt handler.
+ */
+static irqreturn_t cafe_irq(int irq, void *data)
+{
+       struct cafe_camera *cam = data;
+       struct mcam_camera *mcam = &cam->mcam;
+       unsigned int irqs, handled;
+
+       spin_lock(&mcam->dev_lock);
+       irqs = mcam_reg_read(mcam, REG_IRQSTAT);
+       handled = cam->registered && mccic_irq(mcam, irqs);
+       if (irqs & TWSIIRQS) {
+               mcam_reg_write(mcam, REG_IRQSTAT, TWSIIRQS);
+               wake_up(&cam->smbus_wait);
+               handled = 1;
+       }
+       spin_unlock(&mcam->dev_lock);
+       return IRQ_RETVAL(handled);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/*
+ * PCI interface stuff.
+ */
+
+static int cafe_pci_probe(struct pci_dev *pdev,
+               const struct pci_device_id *id)
+{
+       int ret;
+       struct cafe_camera *cam;
+       struct mcam_camera *mcam;
+
+       /*
+        * Start putting together one of our big camera structures.
+        */
+       ret = -ENOMEM;
+       cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
+       if (cam == NULL)
+               goto out;
+       cam->pdev = pdev;
+       mcam = &cam->mcam;
+       mcam->chip_id = V4L2_IDENT_CAFE;
+       spin_lock_init(&mcam->dev_lock);
+       init_waitqueue_head(&cam->smbus_wait);
+       mcam->plat_power_up = cafe_ctlr_power_up;
+       mcam->plat_power_down = cafe_ctlr_power_down;
+       mcam->dev = &pdev->dev;
+       /*
+        * Set the clock speed for the XO 1; I don't believe this
+        * driver has ever run anywhere else.
+        */
+       mcam->clock_speed = 45;
+       mcam->use_smbus = 1;
+       /*
+        * Vmalloc mode for buffers is traditional with this driver.
+        * We *might* be able to run DMA_contig, especially on a system
+        * with CMA in it.
+        */
+       mcam->buffer_mode = B_vmalloc;
+       /*
+        * Get set up on the PCI bus.
+        */
+       ret = pci_enable_device(pdev);
+       if (ret)
+               goto out_free;
+       pci_set_master(pdev);
+
+       ret = -EIO;
+       mcam->regs = pci_iomap(pdev, 0, 0);
+       if (!mcam->regs) {
+               printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n");
+               goto out_disable;
+       }
+       ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam);
+       if (ret)
+               goto out_iounmap;
+
+       /*
+        * Initialize the controller and leave it powered up.  It will
+        * stay that way until the sensor driver shows up.
+        */
+       cafe_ctlr_init(mcam);
+       cafe_ctlr_power_up(mcam);
+       /*
+        * Set up I2C/SMBUS communications.  We have to drop the mutex here
+        * because the sensor could attach in this call chain, leading to
+        * unsightly deadlocks.
+        */
+       ret = cafe_smbus_setup(cam);
+       if (ret)
+               goto out_pdown;
+
+       ret = mccic_register(mcam);
+       if (ret == 0) {
+               cam->registered = 1;
+               return 0;
+       }
+
+       cafe_smbus_shutdown(cam);
+out_pdown:
+       cafe_ctlr_power_down(mcam);
+       free_irq(pdev->irq, cam);
+out_iounmap:
+       pci_iounmap(pdev, mcam->regs);
+out_disable:
+       pci_disable_device(pdev);
+out_free:
+       kfree(cam);
+out:
+       return ret;
+}
+
+
+/*
+ * Shut down an initialized device
+ */
+static void cafe_shutdown(struct cafe_camera *cam)
+{
+       mccic_shutdown(&cam->mcam);
+       cafe_smbus_shutdown(cam);
+       free_irq(cam->pdev->irq, cam);
+       pci_iounmap(cam->pdev, cam->mcam.regs);
+}
+
+
+static void cafe_pci_remove(struct pci_dev *pdev)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct cafe_camera *cam = to_cam(v4l2_dev);
+
+       if (cam == NULL) {
+               printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
+               return;
+       }
+       cafe_shutdown(cam);
+       kfree(cam);
+}
+
+
+#ifdef CONFIG_PM
+/*
+ * Basic power management.
+ */
+static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct cafe_camera *cam = to_cam(v4l2_dev);
+       int ret;
+
+       ret = pci_save_state(pdev);
+       if (ret)
+               return ret;
+       mccic_suspend(&cam->mcam);
+       pci_disable_device(pdev);
+       return 0;
+}
+
+
+static int cafe_pci_resume(struct pci_dev *pdev)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct cafe_camera *cam = to_cam(v4l2_dev);
+       int ret = 0;
+
+       pci_restore_state(pdev);
+       ret = pci_enable_device(pdev);
+
+       if (ret) {
+               cam_warn(cam, "Unable to re-enable device on resume!\n");
+               return ret;
+       }
+       cafe_ctlr_init(&cam->mcam);
+       return mccic_resume(&cam->mcam);
+}
+
+#endif  /* CONFIG_PM */
+
+static struct pci_device_id cafe_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL,
+                    PCI_DEVICE_ID_MARVELL_88ALP01_CCIC) },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, cafe_ids);
+
+static struct pci_driver cafe_pci_driver = {
+       .name = "cafe1000-ccic",
+       .id_table = cafe_ids,
+       .probe = cafe_pci_probe,
+       .remove = cafe_pci_remove,
+#ifdef CONFIG_PM
+       .suspend = cafe_pci_suspend,
+       .resume = cafe_pci_resume,
+#endif
+};
+
+
+
+
+static int __init cafe_init(void)
+{
+       int ret;
+
+       printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n",
+                       CAFE_VERSION);
+       ret = pci_register_driver(&cafe_pci_driver);
+       if (ret) {
+               printk(KERN_ERR "Unable to register cafe_ccic driver\n");
+               goto out;
+       }
+       ret = 0;
+
+out:
+       return ret;
+}
+
+
+static void __exit cafe_exit(void)
+{
+       pci_unregister_driver(&cafe_pci_driver);
+}
+
+module_init(cafe_init);
+module_exit(cafe_exit);
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c
new file mode 100644 (file)
index 0000000..83c1451
--- /dev/null
@@ -0,0 +1,1843 @@
+/*
+ * The Marvell camera core.  This device appears in a number of settings,
+ * so it needs platform-specific support outside of the core.
+ *
+ * Copyright 2011 Jonathan Corbet corbet@lwn.net
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/io.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/ov7670.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "mcam-core.h"
+
+/*
+ * Basic frame stats - to be deleted shortly
+ */
+static int frames;
+static int singles;
+static int delivered;
+
+#ifdef MCAM_MODE_VMALLOC
+/*
+ * Internal DMA buffer management.  Since the controller cannot do S/G I/O,
+ * we must have physically contiguous buffers to bring frames into.
+ * These parameters control how many buffers we use, whether we
+ * allocate them at load time (better chance of success, but nails down
+ * memory) or when somebody tries to use the camera (riskier), and,
+ * for load-time allocation, how big they should be.
+ *
+ * The controller can cycle through three buffers.  We could use
+ * more by flipping pointers around, but it probably makes little
+ * sense.
+ */
+
+static int alloc_bufs_at_read;
+module_param(alloc_bufs_at_read, bool, 0444);
+MODULE_PARM_DESC(alloc_bufs_at_read,
+               "Non-zero value causes DMA buffers to be allocated when the "
+               "video capture device is read, rather than at module load "
+               "time.  This saves memory, but decreases the chances of "
+               "successfully getting those buffers.  This parameter is "
+               "only used in the vmalloc buffer mode");
+
+static int n_dma_bufs = 3;
+module_param(n_dma_bufs, uint, 0644);
+MODULE_PARM_DESC(n_dma_bufs,
+               "The number of DMA buffers to allocate.  Can be either two "
+               "(saves memory, makes timing tighter) or three.");
+
+static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2;  /* Worst case */
+module_param(dma_buf_size, uint, 0444);
+MODULE_PARM_DESC(dma_buf_size,
+               "The size of the allocated DMA buffers.  If actual operating "
+               "parameters require larger buffers, an attempt to reallocate "
+               "will be made.");
+#else /* MCAM_MODE_VMALLOC */
+static const int alloc_bufs_at_read = 0;
+static const int n_dma_bufs = 3;  /* Used by S/G_PARM */
+#endif /* MCAM_MODE_VMALLOC */
+
+static int flip;
+module_param(flip, bool, 0444);
+MODULE_PARM_DESC(flip,
+               "If set, the sensor will be instructed to flip the image "
+               "vertically.");
+
+static int buffer_mode = -1;
+module_param(buffer_mode, int, 0444);
+MODULE_PARM_DESC(buffer_mode,
+               "Set the buffer mode to be used; default is to go with what "
+               "the platform driver asks for.  Set to 0 for vmalloc, 1 for "
+               "DMA contiguous.");
+
+/*
+ * Status flags.  Always manipulated with bit operations.
+ */
+#define CF_BUF0_VALID   0      /* Buffers valid - first three */
+#define CF_BUF1_VALID   1
+#define CF_BUF2_VALID   2
+#define CF_DMA_ACTIVE   3      /* A frame is incoming */
+#define CF_CONFIG_NEEDED 4     /* Must configure hardware */
+#define CF_SINGLE_BUFFER 5     /* Running with a single buffer */
+#define CF_SG_RESTART   6      /* SG restart needed */
+
+#define sensor_call(cam, o, f, args...) \
+       v4l2_subdev_call(cam->sensor, o, f, ##args)
+
+static struct mcam_format_struct {
+       __u8 *desc;
+       __u32 pixelformat;
+       int bpp;   /* Bytes per pixel */
+       enum v4l2_mbus_pixelcode mbus_code;
+} mcam_formats[] = {
+       {
+               .desc           = "YUYV 4:2:2",
+               .pixelformat    = V4L2_PIX_FMT_YUYV,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .bpp            = 2,
+       },
+       {
+               .desc           = "RGB 444",
+               .pixelformat    = V4L2_PIX_FMT_RGB444,
+               .mbus_code      = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+               .bpp            = 2,
+       },
+       {
+               .desc           = "RGB 565",
+               .pixelformat    = V4L2_PIX_FMT_RGB565,
+               .mbus_code      = V4L2_MBUS_FMT_RGB565_2X8_LE,
+               .bpp            = 2,
+       },
+       {
+               .desc           = "Raw RGB Bayer",
+               .pixelformat    = V4L2_PIX_FMT_SBGGR8,
+               .mbus_code      = V4L2_MBUS_FMT_SBGGR8_1X8,
+               .bpp            = 1
+       },
+};
+#define N_MCAM_FMTS ARRAY_SIZE(mcam_formats)
+
+static struct mcam_format_struct *mcam_find_format(u32 pixelformat)
+{
+       unsigned i;
+
+       for (i = 0; i < N_MCAM_FMTS; i++)
+               if (mcam_formats[i].pixelformat == pixelformat)
+                       return mcam_formats + i;
+       /* Not found? Then return the first format. */
+       return mcam_formats;
+}
+
+/*
+ * The default format we use until somebody says otherwise.
+ */
+static const struct v4l2_pix_format mcam_def_pix_format = {
+       .width          = VGA_WIDTH,
+       .height         = VGA_HEIGHT,
+       .pixelformat    = V4L2_PIX_FMT_YUYV,
+       .field          = V4L2_FIELD_NONE,
+       .bytesperline   = VGA_WIDTH*2,
+       .sizeimage      = VGA_WIDTH*VGA_HEIGHT*2,
+};
+
+static const enum v4l2_mbus_pixelcode mcam_def_mbus_code =
+                                       V4L2_MBUS_FMT_YUYV8_2X8;
+
+
+/*
+ * The two-word DMA descriptor format used by the Armada 610 and like.  There
+ * Is a three-word format as well (set C1_DESC_3WORD) where the third
+ * word is a pointer to the next descriptor, but we don't use it.  Two-word
+ * descriptors have to be contiguous in memory.
+ */
+struct mcam_dma_desc {
+       u32 dma_addr;
+       u32 segment_len;
+};
+
+/*
+ * Our buffer type for working with videobuf2.  Note that the vb2
+ * developers have decreed that struct vb2_buffer must be at the
+ * beginning of this structure.
+ */
+struct mcam_vb_buffer {
+       struct vb2_buffer vb_buf;
+       struct list_head queue;
+       struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */
+       dma_addr_t dma_desc_pa;         /* Descriptor physical address */
+       int dma_desc_nent;              /* Number of mapped descriptors */
+};
+
+static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb)
+{
+       return container_of(vb, struct mcam_vb_buffer, vb_buf);
+}
+
+/*
+ * Hand a completed buffer back to user space.
+ */
+static void mcam_buffer_done(struct mcam_camera *cam, int frame,
+               struct vb2_buffer *vbuf)
+{
+       vbuf->v4l2_buf.bytesused = cam->pix_format.sizeimage;
+       vbuf->v4l2_buf.sequence = cam->buf_seq[frame];
+       vb2_set_plane_payload(vbuf, 0, cam->pix_format.sizeimage);
+       vb2_buffer_done(vbuf, VB2_BUF_STATE_DONE);
+}
+
+
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+       dev_err((cam)->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+       dev_warn((cam)->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+       dev_dbg((cam)->dev, fmt, ##arg);
+
+
+/*
+ * Flag manipulation helpers
+ */
+static void mcam_reset_buffers(struct mcam_camera *cam)
+{
+       int i;
+
+       cam->next_buf = -1;
+       for (i = 0; i < cam->nbufs; i++)
+               clear_bit(i, &cam->flags);
+}
+
+static inline int mcam_needs_config(struct mcam_camera *cam)
+{
+       return test_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+static void mcam_set_config_needed(struct mcam_camera *cam, int needed)
+{
+       if (needed)
+               set_bit(CF_CONFIG_NEEDED, &cam->flags);
+       else
+               clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+}
+
+/* ------------------------------------------------------------------- */
+/*
+ * Make the controller start grabbing images.  Everything must
+ * be set up before doing this.
+ */
+static void mcam_ctlr_start(struct mcam_camera *cam)
+{
+       /* set_bit performs a read, so no other barrier should be
+          needed here */
+       mcam_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+static void mcam_ctlr_stop(struct mcam_camera *cam)
+{
+       mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+}
+
+/* ------------------------------------------------------------------- */
+
+#ifdef MCAM_MODE_VMALLOC
+/*
+ * Code specific to the vmalloc buffer mode.
+ */
+
+/*
+ * Allocate in-kernel DMA buffers for vmalloc mode.
+ */
+static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
+{
+       int i;
+
+       mcam_set_config_needed(cam, 1);
+       if (loadtime)
+               cam->dma_buf_size = dma_buf_size;
+       else
+               cam->dma_buf_size = cam->pix_format.sizeimage;
+       if (n_dma_bufs > 3)
+               n_dma_bufs = 3;
+
+       cam->nbufs = 0;
+       for (i = 0; i < n_dma_bufs; i++) {
+               cam->dma_bufs[i] = dma_alloc_coherent(cam->dev,
+                               cam->dma_buf_size, cam->dma_handles + i,
+                               GFP_KERNEL);
+               if (cam->dma_bufs[i] == NULL) {
+                       cam_warn(cam, "Failed to allocate DMA buffer\n");
+                       break;
+               }
+               (cam->nbufs)++;
+       }
+
+       switch (cam->nbufs) {
+       case 1:
+               dma_free_coherent(cam->dev, cam->dma_buf_size,
+                               cam->dma_bufs[0], cam->dma_handles[0]);
+               cam->nbufs = 0;
+       case 0:
+               cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
+               return -ENOMEM;
+
+       case 2:
+               if (n_dma_bufs > 2)
+                       cam_warn(cam, "Will limp along with only 2 buffers\n");
+               break;
+       }
+       return 0;
+}
+
+static void mcam_free_dma_bufs(struct mcam_camera *cam)
+{
+       int i;
+
+       for (i = 0; i < cam->nbufs; i++) {
+               dma_free_coherent(cam->dev, cam->dma_buf_size,
+                               cam->dma_bufs[i], cam->dma_handles[i]);
+               cam->dma_bufs[i] = NULL;
+       }
+       cam->nbufs = 0;
+}
+
+
+/*
+ * Set up DMA buffers when operating in vmalloc mode
+ */
+static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam)
+{
+       /*
+        * Store the first two Y buffers (we aren't supporting
+        * planar formats for now, so no UV bufs).  Then either
+        * set the third if it exists, or tell the controller
+        * to just use two.
+        */
+       mcam_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]);
+       mcam_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]);
+       if (cam->nbufs > 2) {
+               mcam_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]);
+               mcam_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS);
+       } else
+               mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
+       if (cam->chip_id == V4L2_IDENT_CAFE)
+               mcam_reg_write(cam, REG_UBAR, 0); /* 32 bits only */
+}
+
+/*
+ * Copy data out to user space in the vmalloc case
+ */
+static void mcam_frame_tasklet(unsigned long data)
+{
+       struct mcam_camera *cam = (struct mcam_camera *) data;
+       int i;
+       unsigned long flags;
+       struct mcam_vb_buffer *buf;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       for (i = 0; i < cam->nbufs; i++) {
+               int bufno = cam->next_buf;
+
+               if (cam->state != S_STREAMING || bufno < 0)
+                       break;  /* I/O got stopped */
+               if (++(cam->next_buf) >= cam->nbufs)
+                       cam->next_buf = 0;
+               if (!test_bit(bufno, &cam->flags))
+                       continue;
+               if (list_empty(&cam->buffers)) {
+                       singles++;
+                       break;  /* Leave it valid, hope for better later */
+               }
+               delivered++;
+               clear_bit(bufno, &cam->flags);
+               buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer,
+                               queue);
+               list_del_init(&buf->queue);
+               /*
+                * Drop the lock during the big copy.  This *should* be safe...
+                */
+               spin_unlock_irqrestore(&cam->dev_lock, flags);
+               memcpy(vb2_plane_vaddr(&buf->vb_buf, 0), cam->dma_bufs[bufno],
+                               cam->pix_format.sizeimage);
+               mcam_buffer_done(cam, bufno, &buf->vb_buf);
+               spin_lock_irqsave(&cam->dev_lock, flags);
+       }
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+/*
+ * Make sure our allocated buffers are up to the task.
+ */
+static int mcam_check_dma_buffers(struct mcam_camera *cam)
+{
+       if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)
+                       mcam_free_dma_bufs(cam);
+       if (cam->nbufs == 0)
+               return mcam_alloc_dma_bufs(cam, 0);
+       return 0;
+}
+
+static void mcam_vmalloc_done(struct mcam_camera *cam, int frame)
+{
+       tasklet_schedule(&cam->s_tasklet);
+}
+
+#else /* MCAM_MODE_VMALLOC */
+
+static inline int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
+{
+       return 0;
+}
+
+static inline void mcam_free_dma_bufs(struct mcam_camera *cam)
+{
+       return;
+}
+
+static inline int mcam_check_dma_buffers(struct mcam_camera *cam)
+{
+       return 0;
+}
+
+
+
+#endif /* MCAM_MODE_VMALLOC */
+
+
+#ifdef MCAM_MODE_DMA_CONTIG
+/* ---------------------------------------------------------------------- */
+/*
+ * DMA-contiguous code.
+ */
+/*
+ * Set up a contiguous buffer for the given frame.  Here also is where
+ * the underrun strategy is set: if there is no buffer available, reuse
+ * the buffer from the other BAR and set the CF_SINGLE_BUFFER flag to
+ * keep the interrupt handler from giving that buffer back to user
+ * space.  In this way, we always have a buffer to DMA to and don't
+ * have to try to play games stopping and restarting the controller.
+ */
+static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame)
+{
+       struct mcam_vb_buffer *buf;
+       /*
+        * If there are no available buffers, go into single mode
+        */
+       if (list_empty(&cam->buffers)) {
+               buf = cam->vb_bufs[frame ^ 0x1];
+               cam->vb_bufs[frame] = buf;
+               mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
+                               vb2_dma_contig_plane_paddr(&buf->vb_buf, 0));
+               set_bit(CF_SINGLE_BUFFER, &cam->flags);
+               singles++;
+               return;
+       }
+       /*
+        * OK, we have a buffer we can use.
+        */
+       buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
+       list_del_init(&buf->queue);
+       mcam_reg_write(cam, frame == 0 ? REG_Y0BAR : REG_Y1BAR,
+                       vb2_dma_contig_plane_paddr(&buf->vb_buf, 0));
+       cam->vb_bufs[frame] = buf;
+       clear_bit(CF_SINGLE_BUFFER, &cam->flags);
+}
+
+/*
+ * Initial B_DMA_contig setup.
+ */
+static void mcam_ctlr_dma_contig(struct mcam_camera *cam)
+{
+       mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
+       cam->nbufs = 2;
+       mcam_set_contig_buffer(cam, 0);
+       mcam_set_contig_buffer(cam, 1);
+}
+
+/*
+ * Frame completion handling.
+ */
+static void mcam_dma_contig_done(struct mcam_camera *cam, int frame)
+{
+       struct mcam_vb_buffer *buf = cam->vb_bufs[frame];
+
+       if (!test_bit(CF_SINGLE_BUFFER, &cam->flags)) {
+               delivered++;
+               mcam_buffer_done(cam, frame, &buf->vb_buf);
+       }
+       mcam_set_contig_buffer(cam, frame);
+}
+
+#endif /* MCAM_MODE_DMA_CONTIG */
+
+#ifdef MCAM_MODE_DMA_SG
+/* ---------------------------------------------------------------------- */
+/*
+ * Scatter/gather-specific code.
+ */
+
+/*
+ * Set up the next buffer for S/G I/O; caller should be sure that
+ * the controller is stopped and a buffer is available.
+ */
+static void mcam_sg_next_buffer(struct mcam_camera *cam)
+{
+       struct mcam_vb_buffer *buf;
+
+       buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
+       list_del_init(&buf->queue);
+       mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa);
+       mcam_reg_write(cam, REG_DESC_LEN_Y,
+                       buf->dma_desc_nent*sizeof(struct mcam_dma_desc));
+       mcam_reg_write(cam, REG_DESC_LEN_U, 0);
+       mcam_reg_write(cam, REG_DESC_LEN_V, 0);
+       cam->vb_bufs[0] = buf;
+}
+
+/*
+ * Initial B_DMA_sg setup
+ */
+static void mcam_ctlr_dma_sg(struct mcam_camera *cam)
+{
+       mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD);
+       mcam_sg_next_buffer(cam);
+       mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
+       cam->nbufs = 3;
+}
+
+
+/*
+ * Frame completion with S/G is trickier.  We can't muck with
+ * a descriptor chain on the fly, since the controller buffers it
+ * internally.  So we have to actually stop and restart; Marvell
+ * says this is the way to do it.
+ *
+ * Of course, stopping is easier said than done; experience shows
+ * that the controller can start a frame *after* C0_ENABLE has been
+ * cleared.  So when running in S/G mode, the controller is "stopped"
+ * on receipt of the start-of-frame interrupt.  That means we can
+ * safely change the DMA descriptor array here and restart things
+ * (assuming there's another buffer waiting to go).
+ */
+static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
+{
+       struct mcam_vb_buffer *buf = cam->vb_bufs[0];
+
+       /*
+        * Very Bad Not Good Things happen if you don't clear
+        * C1_DESC_ENA before making any descriptor changes.
+        */
+       mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
+       /*
+        * If we have another buffer available, put it in and
+        * restart the engine.
+        */
+       if (!list_empty(&cam->buffers)) {
+               mcam_sg_next_buffer(cam);
+               mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
+               mcam_ctlr_start(cam);
+       /*
+        * Otherwise set CF_SG_RESTART and the controller will
+        * be restarted once another buffer shows up.
+        */
+       } else {
+               set_bit(CF_SG_RESTART, &cam->flags);
+               singles++;
+       }
+       /*
+        * Now we can give the completed frame back to user space.
+        */
+       delivered++;
+       mcam_buffer_done(cam, frame, &buf->vb_buf);
+}
+
+
+/*
+ * Scatter/gather mode requires stopping the controller between
+ * frames so we can put in a new DMA descriptor array.  If no new
+ * buffer exists at frame completion, the controller is left stopped;
+ * this function is charged with gettig things going again.
+ */
+static void mcam_sg_restart(struct mcam_camera *cam)
+{
+       mcam_ctlr_dma_sg(cam);
+       mcam_ctlr_start(cam);
+       clear_bit(CF_SG_RESTART, &cam->flags);
+}
+
+#else /* MCAM_MODE_DMA_SG */
+
+static inline void mcam_sg_restart(struct mcam_camera *cam)
+{
+       return;
+}
+
+#endif /* MCAM_MODE_DMA_SG */
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Buffer-mode-independent controller code.
+ */
+
+/*
+ * Image format setup
+ */
+static void mcam_ctlr_image(struct mcam_camera *cam)
+{
+       int imgsz;
+       struct v4l2_pix_format *fmt = &cam->pix_format;
+
+       imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
+               (fmt->bytesperline & IMGSZ_H_MASK);
+       mcam_reg_write(cam, REG_IMGSIZE, imgsz);
+       mcam_reg_write(cam, REG_IMGOFFSET, 0);
+       /* YPITCH just drops the last two bits */
+       mcam_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline,
+                       IMGP_YP_MASK);
+       /*
+        * Tell the controller about the image format we are using.
+        */
+       switch (cam->pix_format.pixelformat) {
+       case V4L2_PIX_FMT_YUYV:
+           mcam_reg_write_mask(cam, REG_CTRL0,
+                           C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV,
+                           C0_DF_MASK);
+           break;
+
+       case V4L2_PIX_FMT_RGB444:
+           mcam_reg_write_mask(cam, REG_CTRL0,
+                           C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
+                           C0_DF_MASK);
+               /* Alpha value? */
+           break;
+
+       case V4L2_PIX_FMT_RGB565:
+           mcam_reg_write_mask(cam, REG_CTRL0,
+                           C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR,
+                           C0_DF_MASK);
+           break;
+
+       default:
+           cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat);
+           break;
+       }
+       /*
+        * Make sure it knows we want to use hsync/vsync.
+        */
+       mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC,
+                       C0_SIFM_MASK);
+}
+
+
+/*
+ * Configure the controller for operation; caller holds the
+ * device mutex.
+ */
+static int mcam_ctlr_configure(struct mcam_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cam->dma_setup(cam);
+       mcam_ctlr_image(cam);
+       mcam_set_config_needed(cam, 0);
+       clear_bit(CF_SG_RESTART, &cam->flags);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       return 0;
+}
+
+static void mcam_ctlr_irq_enable(struct mcam_camera *cam)
+{
+       /*
+        * Clear any pending interrupts, since we do not
+        * expect to have I/O active prior to enabling.
+        */
+       mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS);
+       mcam_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+static void mcam_ctlr_irq_disable(struct mcam_camera *cam)
+{
+       mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
+}
+
+
+
+static void mcam_ctlr_init(struct mcam_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       /*
+        * Make sure it's not powered down.
+        */
+       mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+       /*
+        * Turn off the enable bit.  It sure should be off anyway,
+        * but it's good to be sure.
+        */
+       mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
+       /*
+        * Clock the sensor appropriately.  Controller clock should
+        * be 48MHz, sensor "typical" value is half that.
+        */
+       mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+
+/*
+ * Stop the controller, and don't return until we're really sure that no
+ * further DMA is going on.
+ */
+static void mcam_ctlr_stop_dma(struct mcam_camera *cam)
+{
+       unsigned long flags;
+
+       /*
+        * Theory: stop the camera controller (whether it is operating
+        * or not).  Delay briefly just in case we race with the SOF
+        * interrupt, then wait until no DMA is active.
+        */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       clear_bit(CF_SG_RESTART, &cam->flags);
+       mcam_ctlr_stop(cam);
+       cam->state = S_IDLE;
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       msleep(40);
+       if (test_bit(CF_DMA_ACTIVE, &cam->flags))
+               cam_err(cam, "Timeout waiting for DMA to end\n");
+               /* This would be bad news - what now? */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       mcam_ctlr_irq_disable(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/*
+ * Power up and down.
+ */
+static void mcam_ctlr_power_up(struct mcam_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       cam->plat_power_up(cam);
+       mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       msleep(5); /* Just to be sure */
+}
+
+static void mcam_ctlr_power_down(struct mcam_camera *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       /*
+        * School of hard knocks department: be sure we do any register
+        * twiddling on the controller *before* calling the platform
+        * power down routine.
+        */
+       mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN);
+       cam->plat_power_down(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+}
+
+/* -------------------------------------------------------------------- */
+/*
+ * Communications with the sensor.
+ */
+
+static int __mcam_cam_reset(struct mcam_camera *cam)
+{
+       return sensor_call(cam, core, reset, 0);
+}
+
+/*
+ * We have found the sensor on the i2c.  Let's try to have a
+ * conversation.
+ */
+static int mcam_cam_init(struct mcam_camera *cam)
+{
+       struct v4l2_dbg_chip_ident chip;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       if (cam->state != S_NOTREADY)
+               cam_warn(cam, "Cam init with device in funky state %d",
+                               cam->state);
+       ret = __mcam_cam_reset(cam);
+       if (ret)
+               goto out;
+       chip.ident = V4L2_IDENT_NONE;
+       chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR;
+       chip.match.addr = cam->sensor_addr;
+       ret = sensor_call(cam, core, g_chip_ident, &chip);
+       if (ret)
+               goto out;
+       cam->sensor_type = chip.ident;
+       if (cam->sensor_type != V4L2_IDENT_OV7670) {
+               cam_err(cam, "Unsupported sensor type 0x%x", cam->sensor_type);
+               ret = -EINVAL;
+               goto out;
+       }
+/* Get/set parameters? */
+       ret = 0;
+       cam->state = S_IDLE;
+out:
+       mcam_ctlr_power_down(cam);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+/*
+ * Configure the sensor to match the parameters we have.  Caller should
+ * hold s_mutex
+ */
+static int mcam_cam_set_flip(struct mcam_camera *cam)
+{
+       struct v4l2_control ctrl;
+
+       memset(&ctrl, 0, sizeof(ctrl));
+       ctrl.id = V4L2_CID_VFLIP;
+       ctrl.value = flip;
+       return sensor_call(cam, core, s_ctrl, &ctrl);
+}
+
+
+static int mcam_cam_configure(struct mcam_camera *cam)
+{
+       struct v4l2_mbus_framefmt mbus_fmt;
+       int ret;
+
+       v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code);
+       ret = sensor_call(cam, core, init, 0);
+       if (ret == 0)
+               ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
+       /*
+        * OV7670 does weird things if flip is set *before* format...
+        */
+       ret += mcam_cam_set_flip(cam);
+       return ret;
+}
+
+/*
+ * Get everything ready, and start grabbing frames.
+ */
+static int mcam_read_setup(struct mcam_camera *cam)
+{
+       int ret;
+       unsigned long flags;
+
+       /*
+        * Configuration.  If we still don't have DMA buffers,
+        * make one last, desperate attempt.
+        */
+       if (cam->buffer_mode == B_vmalloc && cam->nbufs == 0 &&
+                       mcam_alloc_dma_bufs(cam, 0))
+               return -ENOMEM;
+
+       if (mcam_needs_config(cam)) {
+               mcam_cam_configure(cam);
+               ret = mcam_ctlr_configure(cam);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * Turn it loose.
+        */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       mcam_reset_buffers(cam);
+       mcam_ctlr_irq_enable(cam);
+       cam->state = S_STREAMING;
+       mcam_ctlr_start(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+/*
+ * Videobuf2 interface code.
+ */
+
+static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
+               unsigned int *num_planes, unsigned long sizes[],
+               void *alloc_ctxs[])
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vq);
+       int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2;
+
+       sizes[0] = cam->pix_format.sizeimage;
+       *num_planes = 1; /* Someday we have to support planar formats... */
+       if (*nbufs < minbufs)
+               *nbufs = minbufs;
+       if (cam->buffer_mode == B_DMA_contig)
+               alloc_ctxs[0] = cam->vb_alloc_ctx;
+       return 0;
+}
+
+
+static void mcam_vb_buf_queue(struct vb2_buffer *vb)
+{
+       struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+       struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+       unsigned long flags;
+       int start;
+
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers);
+       list_add(&mvb->queue, &cam->buffers);
+       if (test_bit(CF_SG_RESTART, &cam->flags))
+               mcam_sg_restart(cam);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       if (start)
+               mcam_read_setup(cam);
+}
+
+
+/*
+ * vb2 uses these to release the mutex when waiting in dqbuf.  I'm
+ * not actually sure we need to do this (I'm not sure that vb2_dqbuf() needs
+ * to be called with the mutex held), but better safe than sorry.
+ */
+static void mcam_vb_wait_prepare(struct vb2_queue *vq)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vq);
+
+       mutex_unlock(&cam->s_mutex);
+}
+
+static void mcam_vb_wait_finish(struct vb2_queue *vq)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vq);
+
+       mutex_lock(&cam->s_mutex);
+}
+
+/*
+ * These need to be called with the mutex held from vb2
+ */
+static int mcam_vb_start_streaming(struct vb2_queue *vq)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vq);
+
+       if (cam->state != S_IDLE)
+               return -EINVAL;
+       cam->sequence = 0;
+       /*
+        * Videobuf2 sneakily hoards all the buffers and won't
+        * give them to us until *after* streaming starts.  But
+        * we can't actually start streaming until we have a
+        * destination.  So go into a wait state and hope they
+        * give us buffers soon.
+        */
+       if (cam->buffer_mode != B_vmalloc && list_empty(&cam->buffers)) {
+               cam->state = S_BUFWAIT;
+               return 0;
+       }
+       return mcam_read_setup(cam);
+}
+
+static int mcam_vb_stop_streaming(struct vb2_queue *vq)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vq);
+       unsigned long flags;
+
+       if (cam->state == S_BUFWAIT) {
+               /* They never gave us buffers */
+               cam->state = S_IDLE;
+               return 0;
+       }
+       if (cam->state != S_STREAMING)
+               return -EINVAL;
+       mcam_ctlr_stop_dma(cam);
+       /*
+        * VB2 reclaims the buffers, so we need to forget
+        * about them.
+        */
+       spin_lock_irqsave(&cam->dev_lock, flags);
+       INIT_LIST_HEAD(&cam->buffers);
+       spin_unlock_irqrestore(&cam->dev_lock, flags);
+       return 0;
+}
+
+
+static const struct vb2_ops mcam_vb2_ops = {
+       .queue_setup            = mcam_vb_queue_setup,
+       .buf_queue              = mcam_vb_buf_queue,
+       .start_streaming        = mcam_vb_start_streaming,
+       .stop_streaming         = mcam_vb_stop_streaming,
+       .wait_prepare           = mcam_vb_wait_prepare,
+       .wait_finish            = mcam_vb_wait_finish,
+};
+
+
+#ifdef MCAM_MODE_DMA_SG
+/*
+ * Scatter/gather mode uses all of the above functions plus a
+ * few extras to deal with DMA mapping.
+ */
+static int mcam_vb_sg_buf_init(struct vb2_buffer *vb)
+{
+       struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+       struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+       int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1;
+
+       mvb->dma_desc = dma_alloc_coherent(cam->dev,
+                       ndesc * sizeof(struct mcam_dma_desc),
+                       &mvb->dma_desc_pa, GFP_KERNEL);
+       if (mvb->dma_desc == NULL) {
+               cam_err(cam, "Unable to get DMA descriptor array\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb)
+{
+       struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+       struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0);
+       struct mcam_dma_desc *desc = mvb->dma_desc;
+       struct scatterlist *sg;
+       int i;
+
+       mvb->dma_desc_nent = dma_map_sg(cam->dev, sgd->sglist, sgd->num_pages,
+                       DMA_FROM_DEVICE);
+       if (mvb->dma_desc_nent <= 0)
+               return -EIO;  /* Not sure what's right here */
+       for_each_sg(sgd->sglist, sg, mvb->dma_desc_nent, i) {
+               desc->dma_addr = sg_dma_address(sg);
+               desc->segment_len = sg_dma_len(sg);
+               desc++;
+       }
+       return 0;
+}
+
+static int mcam_vb_sg_buf_finish(struct vb2_buffer *vb)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+       struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0);
+
+       dma_unmap_sg(cam->dev, sgd->sglist, sgd->num_pages, DMA_FROM_DEVICE);
+       return 0;
+}
+
+static void mcam_vb_sg_buf_cleanup(struct vb2_buffer *vb)
+{
+       struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+       struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
+       int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1;
+
+       dma_free_coherent(cam->dev, ndesc * sizeof(struct mcam_dma_desc),
+                       mvb->dma_desc, mvb->dma_desc_pa);
+}
+
+
+static const struct vb2_ops mcam_vb2_sg_ops = {
+       .queue_setup            = mcam_vb_queue_setup,
+       .buf_init               = mcam_vb_sg_buf_init,
+       .buf_prepare            = mcam_vb_sg_buf_prepare,
+       .buf_queue              = mcam_vb_buf_queue,
+       .buf_finish             = mcam_vb_sg_buf_finish,
+       .buf_cleanup            = mcam_vb_sg_buf_cleanup,
+       .start_streaming        = mcam_vb_start_streaming,
+       .stop_streaming         = mcam_vb_stop_streaming,
+       .wait_prepare           = mcam_vb_wait_prepare,
+       .wait_finish            = mcam_vb_wait_finish,
+};
+
+#endif /* MCAM_MODE_DMA_SG */
+
+static int mcam_setup_vb2(struct mcam_camera *cam)
+{
+       struct vb2_queue *vq = &cam->vb_queue;
+
+       memset(vq, 0, sizeof(*vq));
+       vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       vq->drv_priv = cam;
+       INIT_LIST_HEAD(&cam->buffers);
+       switch (cam->buffer_mode) {
+       case B_DMA_contig:
+#ifdef MCAM_MODE_DMA_CONTIG
+               vq->ops = &mcam_vb2_ops;
+               vq->mem_ops = &vb2_dma_contig_memops;
+               cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev);
+               vq->io_modes = VB2_MMAP | VB2_USERPTR;
+               cam->dma_setup = mcam_ctlr_dma_contig;
+               cam->frame_complete = mcam_dma_contig_done;
+#endif
+               break;
+       case B_DMA_sg:
+#ifdef MCAM_MODE_DMA_SG
+               vq->ops = &mcam_vb2_sg_ops;
+               vq->mem_ops = &vb2_dma_sg_memops;
+               vq->io_modes = VB2_MMAP | VB2_USERPTR;
+               cam->dma_setup = mcam_ctlr_dma_sg;
+               cam->frame_complete = mcam_dma_sg_done;
+#endif
+               break;
+       case B_vmalloc:
+#ifdef MCAM_MODE_VMALLOC
+               tasklet_init(&cam->s_tasklet, mcam_frame_tasklet,
+                               (unsigned long) cam);
+               vq->ops = &mcam_vb2_ops;
+               vq->mem_ops = &vb2_vmalloc_memops;
+               vq->buf_struct_size = sizeof(struct mcam_vb_buffer);
+               vq->io_modes = VB2_MMAP;
+               cam->dma_setup = mcam_ctlr_dma_vmalloc;
+               cam->frame_complete = mcam_vmalloc_done;
+#endif
+               break;
+       }
+       return vb2_queue_init(vq);
+}
+
+static void mcam_cleanup_vb2(struct mcam_camera *cam)
+{
+       vb2_queue_release(&cam->vb_queue);
+#ifdef MCAM_MODE_DMA_CONTIG
+       if (cam->buffer_mode == B_DMA_contig)
+               vb2_dma_contig_cleanup_ctx(cam->vb_alloc_ctx);
+#endif
+}
+
+
+/* ---------------------------------------------------------------------- */
+/*
+ * The long list of V4L2 ioctl() operations.
+ */
+
+static int mcam_vidioc_streamon(struct file *filp, void *priv,
+               enum v4l2_buf_type type)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_streamon(&cam->vb_queue, type);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_streamoff(struct file *filp, void *priv,
+               enum v4l2_buf_type type)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_streamoff(&cam->vb_queue, type);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_reqbufs(struct file *filp, void *priv,
+               struct v4l2_requestbuffers *req)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_reqbufs(&cam->vb_queue, req);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_querybuf(struct file *filp, void *priv,
+               struct v4l2_buffer *buf)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_querybuf(&cam->vb_queue, buf);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+static int mcam_vidioc_qbuf(struct file *filp, void *priv,
+               struct v4l2_buffer *buf)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_qbuf(&cam->vb_queue, buf);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+static int mcam_vidioc_dqbuf(struct file *filp, void *priv,
+               struct v4l2_buffer *buf)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+
+static int mcam_vidioc_queryctrl(struct file *filp, void *priv,
+               struct v4l2_queryctrl *qc)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, core, queryctrl, qc);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_g_ctrl(struct file *filp, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, core, g_ctrl, ctrl);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_s_ctrl(struct file *filp, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, core, s_ctrl, ctrl);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_vidioc_querycap(struct file *file, void *priv,
+               struct v4l2_capability *cap)
+{
+       strcpy(cap->driver, "marvell_ccic");
+       strcpy(cap->card, "marvell_ccic");
+       cap->version = 1;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+
+static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp,
+               void *priv, struct v4l2_fmtdesc *fmt)
+{
+       if (fmt->index >= N_MCAM_FMTS)
+               return -EINVAL;
+       strlcpy(fmt->description, mcam_formats[fmt->index].desc,
+                       sizeof(fmt->description));
+       fmt->pixelformat = mcam_formats[fmt->index].pixelformat;
+       return 0;
+}
+
+static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
+               struct v4l2_format *fmt)
+{
+       struct mcam_camera *cam = priv;
+       struct mcam_format_struct *f;
+       struct v4l2_pix_format *pix = &fmt->fmt.pix;
+       struct v4l2_mbus_framefmt mbus_fmt;
+       int ret;
+
+       f = mcam_find_format(pix->pixelformat);
+       pix->pixelformat = f->pixelformat;
+       v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code);
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
+       mutex_unlock(&cam->s_mutex);
+       v4l2_fill_pix_format(pix, &mbus_fmt);
+       pix->bytesperline = pix->width * f->bpp;
+       pix->sizeimage = pix->height * pix->bytesperline;
+       return ret;
+}
+
+static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
+               struct v4l2_format *fmt)
+{
+       struct mcam_camera *cam = priv;
+       struct mcam_format_struct *f;
+       int ret;
+
+       /*
+        * Can't do anything if the device is not idle
+        * Also can't if there are streaming buffers in place.
+        */
+       if (cam->state != S_IDLE || cam->vb_queue.num_buffers > 0)
+               return -EBUSY;
+
+       f = mcam_find_format(fmt->fmt.pix.pixelformat);
+
+       /*
+        * See if the formatting works in principle.
+        */
+       ret = mcam_vidioc_try_fmt_vid_cap(filp, priv, fmt);
+       if (ret)
+               return ret;
+       /*
+        * Now we start to change things for real, so let's do it
+        * under lock.
+        */
+       mutex_lock(&cam->s_mutex);
+       cam->pix_format = fmt->fmt.pix;
+       cam->mbus_code = f->mbus_code;
+
+       /*
+        * Make sure we have appropriate DMA buffers.
+        */
+       if (cam->buffer_mode == B_vmalloc) {
+               ret = mcam_check_dma_buffers(cam);
+               if (ret)
+                       goto out;
+       }
+       mcam_set_config_needed(cam, 1);
+       ret = 0;
+out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+/*
+ * Return our stored notion of how the camera is/should be configured.
+ * The V4l2 spec wants us to be smarter, and actually get this from
+ * the camera (and not mess with it at open time).  Someday.
+ */
+static int mcam_vidioc_g_fmt_vid_cap(struct file *filp, void *priv,
+               struct v4l2_format *f)
+{
+       struct mcam_camera *cam = priv;
+
+       f->fmt.pix = cam->pix_format;
+       return 0;
+}
+
+/*
+ * We only have one input - the sensor - so minimize the nonsense here.
+ */
+static int mcam_vidioc_enum_input(struct file *filp, void *priv,
+               struct v4l2_input *input)
+{
+       if (input->index != 0)
+               return -EINVAL;
+
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+       input->std = V4L2_STD_ALL; /* Not sure what should go here */
+       strcpy(input->name, "Camera");
+       return 0;
+}
+
+static int mcam_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+       *i = 0;
+       return 0;
+}
+
+static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+       if (i != 0)
+               return -EINVAL;
+       return 0;
+}
+
+/* from vivi.c */
+static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
+{
+       return 0;
+}
+
+/*
+ * G/S_PARM.  Most of this is done by the sensor, but we are
+ * the level which controls the number of read buffers.
+ */
+static int mcam_vidioc_g_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parms)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, g_parm, parms);
+       mutex_unlock(&cam->s_mutex);
+       parms->parm.capture.readbuffers = n_dma_bufs;
+       return ret;
+}
+
+static int mcam_vidioc_s_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parms)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, s_parm, parms);
+       mutex_unlock(&cam->s_mutex);
+       parms->parm.capture.readbuffers = n_dma_bufs;
+       return ret;
+}
+
+static int mcam_vidioc_g_chip_ident(struct file *file, void *priv,
+               struct v4l2_dbg_chip_ident *chip)
+{
+       struct mcam_camera *cam = priv;
+
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+       if (v4l2_chip_match_host(&chip->match)) {
+               chip->ident = cam->chip_id;
+               return 0;
+       }
+       return sensor_call(cam, core, g_chip_ident, chip);
+}
+
+static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv,
+               struct v4l2_frmsizeenum *sizes)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, enum_framesizes, sizes);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv,
+               struct v4l2_frmivalenum *interval)
+{
+       struct mcam_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = sensor_call(cam, video, enum_frameintervals, interval);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mcam_vidioc_g_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg)
+{
+       struct mcam_camera *cam = priv;
+
+       if (v4l2_chip_match_host(&reg->match)) {
+               reg->val = mcam_reg_read(cam, reg->reg);
+               reg->size = 4;
+               return 0;
+       }
+       return sensor_call(cam, core, g_register, reg);
+}
+
+static int mcam_vidioc_s_register(struct file *file, void *priv,
+               struct v4l2_dbg_register *reg)
+{
+       struct mcam_camera *cam = priv;
+
+       if (v4l2_chip_match_host(&reg->match)) {
+               mcam_reg_write(cam, reg->reg, reg->val);
+               return 0;
+       }
+       return sensor_call(cam, core, s_register, reg);
+}
+#endif
+
+static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = {
+       .vidioc_querycap        = mcam_vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = mcam_vidioc_enum_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap = mcam_vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap   = mcam_vidioc_s_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap   = mcam_vidioc_g_fmt_vid_cap,
+       .vidioc_enum_input      = mcam_vidioc_enum_input,
+       .vidioc_g_input         = mcam_vidioc_g_input,
+       .vidioc_s_input         = mcam_vidioc_s_input,
+       .vidioc_s_std           = mcam_vidioc_s_std,
+       .vidioc_reqbufs         = mcam_vidioc_reqbufs,
+       .vidioc_querybuf        = mcam_vidioc_querybuf,
+       .vidioc_qbuf            = mcam_vidioc_qbuf,
+       .vidioc_dqbuf           = mcam_vidioc_dqbuf,
+       .vidioc_streamon        = mcam_vidioc_streamon,
+       .vidioc_streamoff       = mcam_vidioc_streamoff,
+       .vidioc_queryctrl       = mcam_vidioc_queryctrl,
+       .vidioc_g_ctrl          = mcam_vidioc_g_ctrl,
+       .vidioc_s_ctrl          = mcam_vidioc_s_ctrl,
+       .vidioc_g_parm          = mcam_vidioc_g_parm,
+       .vidioc_s_parm          = mcam_vidioc_s_parm,
+       .vidioc_enum_framesizes = mcam_vidioc_enum_framesizes,
+       .vidioc_enum_frameintervals = mcam_vidioc_enum_frameintervals,
+       .vidioc_g_chip_ident    = mcam_vidioc_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register      = mcam_vidioc_g_register,
+       .vidioc_s_register      = mcam_vidioc_s_register,
+#endif
+};
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Our various file operations.
+ */
+static int mcam_v4l_open(struct file *filp)
+{
+       struct mcam_camera *cam = video_drvdata(filp);
+       int ret = 0;
+
+       filp->private_data = cam;
+
+       frames = singles = delivered = 0;
+       mutex_lock(&cam->s_mutex);
+       if (cam->users == 0) {
+               ret = mcam_setup_vb2(cam);
+               if (ret)
+                       goto out;
+               mcam_ctlr_power_up(cam);
+               __mcam_cam_reset(cam);
+               mcam_set_config_needed(cam, 1);
+       }
+       (cam->users)++;
+out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_v4l_release(struct file *filp)
+{
+       struct mcam_camera *cam = filp->private_data;
+
+       cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
+                       singles, delivered);
+       mutex_lock(&cam->s_mutex);
+       (cam->users)--;
+       if (filp == cam->owner) {
+               mcam_ctlr_stop_dma(cam);
+               cam->owner = NULL;
+       }
+       if (cam->users == 0) {
+               mcam_cleanup_vb2(cam);
+               mcam_ctlr_power_down(cam);
+               if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
+                       mcam_free_dma_bufs(cam);
+       }
+       mutex_unlock(&cam->s_mutex);
+       return 0;
+}
+
+static ssize_t mcam_v4l_read(struct file *filp,
+               char __user *buffer, size_t len, loff_t *pos)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_read(&cam->vb_queue, buffer, len, pos,
+                       filp->f_flags & O_NONBLOCK);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+
+static unsigned int mcam_v4l_poll(struct file *filp,
+               struct poll_table_struct *pt)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_poll(&cam->vb_queue, filp, pt);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+static int mcam_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct mcam_camera *cam = filp->private_data;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = vb2_mmap(&cam->vb_queue, vma);
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+}
+
+
+
+static const struct v4l2_file_operations mcam_v4l_fops = {
+       .owner = THIS_MODULE,
+       .open = mcam_v4l_open,
+       .release = mcam_v4l_release,
+       .read = mcam_v4l_read,
+       .poll = mcam_v4l_poll,
+       .mmap = mcam_v4l_mmap,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+
+/*
+ * This template device holds all of those v4l2 methods; we
+ * clone it for specific real devices.
+ */
+static struct video_device mcam_v4l_template = {
+       .name = "mcam",
+       .tvnorms = V4L2_STD_NTSC_M,
+       .current_norm = V4L2_STD_NTSC_M,  /* make mplayer happy */
+
+       .fops = &mcam_v4l_fops,
+       .ioctl_ops = &mcam_v4l_ioctl_ops,
+       .release = video_device_release_empty,
+};
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Interrupt handler stuff
+ */
+static void mcam_frame_complete(struct mcam_camera *cam, int frame)
+{
+       /*
+        * Basic frame housekeeping.
+        */
+       set_bit(frame, &cam->flags);
+       clear_bit(CF_DMA_ACTIVE, &cam->flags);
+       cam->next_buf = frame;
+       cam->buf_seq[frame] = ++(cam->sequence);
+       frames++;
+       /*
+        * "This should never happen"
+        */
+       if (cam->state != S_STREAMING)
+               return;
+       /*
+        * Process the frame and set up the next one.
+        */
+       cam->frame_complete(cam, frame);
+}
+
+
+/*
+ * The interrupt handler; this needs to be called from the
+ * platform irq handler with the lock held.
+ */
+int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
+{
+       unsigned int frame, handled = 0;
+
+       mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */
+       /*
+        * Handle any frame completions.  There really should
+        * not be more than one of these, or we have fallen
+        * far behind.
+        *
+        * When running in S/G mode, the frame number lacks any
+        * real meaning - there's only one descriptor array - but
+        * the controller still picks a different one to signal
+        * each time.
+        */
+       for (frame = 0; frame < cam->nbufs; frame++)
+               if (irqs & (IRQ_EOF0 << frame)) {
+                       mcam_frame_complete(cam, frame);
+                       handled = 1;
+               }
+       /*
+        * If a frame starts, note that we have DMA active.  This
+        * code assumes that we won't get multiple frame interrupts
+        * at once; may want to rethink that.
+        */
+       if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) {
+               set_bit(CF_DMA_ACTIVE, &cam->flags);
+               handled = 1;
+               if (cam->buffer_mode == B_DMA_sg)
+                       mcam_ctlr_stop(cam);
+       }
+       return handled;
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Registration and such.
+ */
+static struct ov7670_config sensor_cfg = {
+       /*
+        * Exclude QCIF mode, because it only captures a tiny portion
+        * of the sensor FOV
+        */
+       .min_width = 320,
+       .min_height = 240,
+};
+
+
+int mccic_register(struct mcam_camera *cam)
+{
+       struct i2c_board_info ov7670_info = {
+               .type = "ov7670",
+               .addr = 0x42 >> 1,
+               .platform_data = &sensor_cfg,
+       };
+       int ret;
+
+       /*
+        * Validate the requested buffer mode.
+        */
+       if (buffer_mode >= 0)
+               cam->buffer_mode = buffer_mode;
+       if (cam->buffer_mode == B_DMA_sg &&
+                       cam->chip_id == V4L2_IDENT_CAFE) {
+               printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, "
+                       "attempting vmalloc mode instead\n");
+               cam->buffer_mode = B_vmalloc;
+       }
+       if (!mcam_buffer_mode_supported(cam->buffer_mode)) {
+               printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n",
+                               cam->buffer_mode);
+               return -EINVAL;
+       }
+       /*
+        * Register with V4L
+        */
+       ret = v4l2_device_register(cam->dev, &cam->v4l2_dev);
+       if (ret)
+               return ret;
+
+       mutex_init(&cam->s_mutex);
+       cam->state = S_NOTREADY;
+       mcam_set_config_needed(cam, 1);
+       cam->pix_format = mcam_def_pix_format;
+       cam->mbus_code = mcam_def_mbus_code;
+       INIT_LIST_HEAD(&cam->buffers);
+       mcam_ctlr_init(cam);
+
+       /*
+        * Try to find the sensor.
+        */
+       sensor_cfg.clock_speed = cam->clock_speed;
+       sensor_cfg.use_smbus = cam->use_smbus;
+       cam->sensor_addr = ov7670_info.addr;
+       cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev,
+                       cam->i2c_adapter, &ov7670_info, NULL);
+       if (cam->sensor == NULL) {
+               ret = -ENODEV;
+               goto out_unregister;
+       }
+
+       ret = mcam_cam_init(cam);
+       if (ret)
+               goto out_unregister;
+       /*
+        * Get the v4l2 setup done.
+        */
+       mutex_lock(&cam->s_mutex);
+       cam->vdev = mcam_v4l_template;
+       cam->vdev.debug = 0;
+       cam->vdev.v4l2_dev = &cam->v4l2_dev;
+       ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+       if (ret)
+               goto out;
+       video_set_drvdata(&cam->vdev, cam);
+
+       /*
+        * If so requested, try to get our DMA buffers now.
+        */
+       if (cam->buffer_mode == B_vmalloc && !alloc_bufs_at_read) {
+               if (mcam_alloc_dma_bufs(cam, 1))
+                       cam_warn(cam, "Unable to alloc DMA buffers at load"
+                                       " will try again later.");
+       }
+
+out:
+       mutex_unlock(&cam->s_mutex);
+       return ret;
+out_unregister:
+       v4l2_device_unregister(&cam->v4l2_dev);
+       return ret;
+}
+
+
+void mccic_shutdown(struct mcam_camera *cam)
+{
+       /*
+        * If we have no users (and we really, really should have no
+        * users) the device will already be powered down.  Trying to
+        * take it down again will wedge the machine, which is frowned
+        * upon.
+        */
+       if (cam->users > 0) {
+               cam_warn(cam, "Removing a device with users!\n");
+               mcam_ctlr_power_down(cam);
+       }
+       vb2_queue_release(&cam->vb_queue);
+       if (cam->buffer_mode == B_vmalloc)
+               mcam_free_dma_bufs(cam);
+       video_unregister_device(&cam->vdev);
+       v4l2_device_unregister(&cam->v4l2_dev);
+}
+
+/*
+ * Power management
+ */
+#ifdef CONFIG_PM
+
+void mccic_suspend(struct mcam_camera *cam)
+{
+       enum mcam_state cstate = cam->state;
+
+       mcam_ctlr_stop_dma(cam);
+       mcam_ctlr_power_down(cam);
+       cam->state = cstate;
+}
+
+int mccic_resume(struct mcam_camera *cam)
+{
+       int ret = 0;
+
+       mutex_lock(&cam->s_mutex);
+       if (cam->users > 0) {
+               mcam_ctlr_power_up(cam);
+               __mcam_cam_reset(cam);
+       } else {
+               mcam_ctlr_power_down(cam);
+       }
+       mutex_unlock(&cam->s_mutex);
+
+       set_bit(CF_CONFIG_NEEDED, &cam->flags);
+       if (cam->state == S_STREAMING)
+               ret = mcam_read_setup(cam);
+       return ret;
+}
+#endif /* CONFIG_PM */
diff --git a/drivers/media/video/marvell-ccic/mcam-core.h b/drivers/media/video/marvell-ccic/mcam-core.h
new file mode 100644 (file)
index 0000000..917200e
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Marvell camera core structures.
+ *
+ * Copyright 2011 Jonathan Corbet corbet@lwn.net
+ */
+#ifndef _MCAM_CORE_H
+#define _MCAM_CORE_H
+
+#include <linux/list.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf2-core.h>
+
+/*
+ * Create our own symbols for the supported buffer modes, but, for now,
+ * base them entirely on which videobuf2 options have been selected.
+ */
+#if defined(CONFIG_VIDEOBUF2_VMALLOC) || defined(CONFIG_VIDEOBUF2_VMALLOC_MODULE)
+#define MCAM_MODE_VMALLOC 1
+#endif
+
+#if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) || defined(CONFIG_VIDEOBUF2_DMA_CONTIG_MODULE)
+#define MCAM_MODE_DMA_CONTIG 1
+#endif
+
+#if defined(CONFIG_VIDEOBUF2_DMA_SG) || defined(CONFIG_VIDEOBUF2_DMA_SG_MODULE)
+#define MCAM_MODE_DMA_SG 1
+#endif
+
+#if !defined(MCAM_MODE_VMALLOC) && !defined(MCAM_MODE_DMA_CONTIG) && \
+       !defined(MCAM_MODE_DMA_SG)
+#error One of the videobuf buffer modes must be selected in the config
+#endif
+
+
+enum mcam_state {
+       S_NOTREADY,     /* Not yet initialized */
+       S_IDLE,         /* Just hanging around */
+       S_FLAKED,       /* Some sort of problem */
+       S_STREAMING,    /* Streaming data */
+       S_BUFWAIT       /* streaming requested but no buffers yet */
+};
+#define MAX_DMA_BUFS 3
+
+/*
+ * Different platforms work best with different buffer modes, so we
+ * let the platform pick.
+ */
+enum mcam_buffer_mode {
+       B_vmalloc = 0,
+       B_DMA_contig = 1,
+       B_DMA_sg = 2
+};
+
+/*
+ * Is a given buffer mode supported by the current kernel configuration?
+ */
+static inline int mcam_buffer_mode_supported(enum mcam_buffer_mode mode)
+{
+       switch (mode) {
+#ifdef MCAM_MODE_VMALLOC
+       case B_vmalloc:
+#endif
+#ifdef MCAM_MODE_DMA_CONTIG
+       case B_DMA_contig:
+#endif
+#ifdef MCAM_MODE_DMA_SG
+       case B_DMA_sg:
+#endif
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+
+/*
+ * A description of one of our devices.
+ * Locking: controlled by s_mutex.  Certain fields, however, require
+ *          the dev_lock spinlock; they are marked as such by comments.
+ *          dev_lock is also required for access to device registers.
+ */
+struct mcam_camera {
+       /*
+        * These fields should be set by the platform code prior to
+        * calling mcam_register().
+        */
+       struct i2c_adapter *i2c_adapter;
+       unsigned char __iomem *regs;
+       spinlock_t dev_lock;
+       struct device *dev; /* For messages, dma alloc */
+       unsigned int chip_id;
+       short int clock_speed;  /* Sensor clock speed, default 30 */
+       short int use_smbus;    /* SMBUS or straight I2c? */
+       enum mcam_buffer_mode buffer_mode;
+       /*
+        * Callbacks from the core to the platform code.
+        */
+       void (*plat_power_up) (struct mcam_camera *cam);
+       void (*plat_power_down) (struct mcam_camera *cam);
+
+       /*
+        * Everything below here is private to the mcam core and
+        * should not be touched by the platform code.
+        */
+       struct v4l2_device v4l2_dev;
+       enum mcam_state state;
+       unsigned long flags;            /* Buffer status, mainly (dev_lock) */
+       int users;                      /* How many open FDs */
+       struct file *owner;             /* Who has data access (v4l2) */
+
+       /*
+        * Subsystem structures.
+        */
+       struct video_device vdev;
+       struct v4l2_subdev *sensor;
+       unsigned short sensor_addr;
+
+       /* Videobuf2 stuff */
+       struct vb2_queue vb_queue;
+       struct list_head buffers;       /* Available frames */
+
+       unsigned int nbufs;             /* How many are alloc'd */
+       int next_buf;                   /* Next to consume (dev_lock) */
+
+       /* DMA buffers - vmalloc mode */
+#ifdef MCAM_MODE_VMALLOC
+       unsigned int dma_buf_size;      /* allocated size */
+       void *dma_bufs[MAX_DMA_BUFS];   /* Internal buffer addresses */
+       dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
+       struct tasklet_struct s_tasklet;
+#endif
+       unsigned int sequence;          /* Frame sequence number */
+       unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */
+
+       /* DMA buffers - DMA modes */
+       struct mcam_vb_buffer *vb_bufs[MAX_DMA_BUFS];
+       struct vb2_alloc_ctx *vb_alloc_ctx;
+
+       /* Mode-specific ops, set at open time */
+       void (*dma_setup)(struct mcam_camera *cam);
+       void (*frame_complete)(struct mcam_camera *cam, int frame);
+
+       /* Current operating parameters */
+       u32 sensor_type;                /* Currently ov7670 only */
+       struct v4l2_pix_format pix_format;
+       enum v4l2_mbus_pixelcode mbus_code;
+
+       /* Locks */
+       struct mutex s_mutex; /* Access to this structure */
+};
+
+
+/*
+ * Register I/O functions.  These are here because the platform code
+ * may legitimately need to mess with the register space.
+ */
+/*
+ * Device register I/O
+ */
+static inline void mcam_reg_write(struct mcam_camera *cam, unsigned int reg,
+               unsigned int val)
+{
+       iowrite32(val, cam->regs + reg);
+}
+
+static inline unsigned int mcam_reg_read(struct mcam_camera *cam,
+               unsigned int reg)
+{
+       return ioread32(cam->regs + reg);
+}
+
+
+static inline void mcam_reg_write_mask(struct mcam_camera *cam, unsigned int reg,
+               unsigned int val, unsigned int mask)
+{
+       unsigned int v = mcam_reg_read(cam, reg);
+
+       v = (v & ~mask) | (val & mask);
+       mcam_reg_write(cam, reg, v);
+}
+
+static inline void mcam_reg_clear_bit(struct mcam_camera *cam,
+               unsigned int reg, unsigned int val)
+{
+       mcam_reg_write_mask(cam, reg, 0, val);
+}
+
+static inline void mcam_reg_set_bit(struct mcam_camera *cam,
+               unsigned int reg, unsigned int val)
+{
+       mcam_reg_write_mask(cam, reg, val, val);
+}
+
+/*
+ * Functions for use by platform code.
+ */
+int mccic_register(struct mcam_camera *cam);
+int mccic_irq(struct mcam_camera *cam, unsigned int irqs);
+void mccic_shutdown(struct mcam_camera *cam);
+#ifdef CONFIG_PM
+void mccic_suspend(struct mcam_camera *cam);
+int mccic_resume(struct mcam_camera *cam);
+#endif
+
+/*
+ * Register definitions for the m88alp01 camera interface.  Offsets in bytes
+ * as given in the spec.
+ */
+#define REG_Y0BAR      0x00
+#define REG_Y1BAR      0x04
+#define REG_Y2BAR      0x08
+/* ... */
+
+#define REG_IMGPITCH   0x24    /* Image pitch register */
+#define   IMGP_YP_SHFT   2             /* Y pitch params */
+#define   IMGP_YP_MASK   0x00003ffc    /* Y pitch field */
+#define          IMGP_UVP_SHFT   18            /* UV pitch (planar) */
+#define   IMGP_UVP_MASK   0x3ffc0000
+#define REG_IRQSTATRAW 0x28    /* RAW IRQ Status */
+#define   IRQ_EOF0       0x00000001    /* End of frame 0 */
+#define   IRQ_EOF1       0x00000002    /* End of frame 1 */
+#define   IRQ_EOF2       0x00000004    /* End of frame 2 */
+#define   IRQ_SOF0       0x00000008    /* Start of frame 0 */
+#define   IRQ_SOF1       0x00000010    /* Start of frame 1 */
+#define   IRQ_SOF2       0x00000020    /* Start of frame 2 */
+#define   IRQ_OVERFLOW   0x00000040    /* FIFO overflow */
+#define   IRQ_TWSIW      0x00010000    /* TWSI (smbus) write */
+#define   IRQ_TWSIR      0x00020000    /* TWSI read */
+#define   IRQ_TWSIE      0x00040000    /* TWSI error */
+#define   TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE)
+#define   FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2)
+#define   ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW)
+#define REG_IRQMASK    0x2c    /* IRQ mask - same bits as IRQSTAT */
+#define REG_IRQSTAT    0x30    /* IRQ status / clear */
+
+#define REG_IMGSIZE    0x34    /* Image size */
+#define  IMGSZ_V_MASK    0x1fff0000
+#define  IMGSZ_V_SHIFT   16
+#define         IMGSZ_H_MASK     0x00003fff
+#define REG_IMGOFFSET  0x38    /* IMage offset */
+
+#define REG_CTRL0      0x3c    /* Control 0 */
+#define   C0_ENABLE      0x00000001    /* Makes the whole thing go */
+
+/* Mask for all the format bits */
+#define   C0_DF_MASK     0x00fffffc    /* Bits 2-23 */
+
+/* RGB ordering */
+#define          C0_RGB4_RGBX    0x00000000
+#define          C0_RGB4_XRGB    0x00000004
+#define          C0_RGB4_BGRX    0x00000008
+#define          C0_RGB4_XBGR    0x0000000c
+#define          C0_RGB5_RGGB    0x00000000
+#define          C0_RGB5_GRBG    0x00000004
+#define          C0_RGB5_GBRG    0x00000008
+#define          C0_RGB5_BGGR    0x0000000c
+
+/* Spec has two fields for DIN and DOUT, but they must match, so
+   combine them here. */
+#define          C0_DF_YUV       0x00000000    /* Data is YUV      */
+#define          C0_DF_RGB       0x000000a0    /* ... RGB                  */
+#define          C0_DF_BAYER     0x00000140    /* ... Bayer                */
+/* 8-8-8 must be missing from the below - ask */
+#define          C0_RGBF_565     0x00000000
+#define          C0_RGBF_444     0x00000800
+#define          C0_RGB_BGR      0x00001000    /* Blue comes first */
+#define          C0_YUV_PLANAR   0x00000000    /* YUV 422 planar format */
+#define          C0_YUV_PACKED   0x00008000    /* YUV 422 packed       */
+#define          C0_YUV_420PL    0x0000a000    /* YUV 420 planar       */
+/* Think that 420 packed must be 111 - ask */
+#define          C0_YUVE_YUYV    0x00000000    /* Y1CbY0Cr             */
+#define          C0_YUVE_YVYU    0x00010000    /* Y1CrY0Cb             */
+#define          C0_YUVE_VYUY    0x00020000    /* CrY1CbY0             */
+#define          C0_YUVE_UYVY    0x00030000    /* CbY1CrY0             */
+#define          C0_YUVE_XYUV    0x00000000    /* 420: .YUV            */
+#define          C0_YUVE_XYVU    0x00010000    /* 420: .YVU            */
+#define          C0_YUVE_XUVY    0x00020000    /* 420: .UVY            */
+#define          C0_YUVE_XVUY    0x00030000    /* 420: .VUY            */
+/* Bayer bits 18,19 if needed */
+#define          C0_HPOL_LOW     0x01000000    /* HSYNC polarity active low */
+#define          C0_VPOL_LOW     0x02000000    /* VSYNC polarity active low */
+#define          C0_VCLK_LOW     0x04000000    /* VCLK on falling edge */
+#define          C0_DOWNSCALE    0x08000000    /* Enable downscaler */
+#define          C0_SIFM_MASK    0xc0000000    /* SIF mode bits */
+#define          C0_SIF_HVSYNC   0x00000000    /* Use H/VSYNC */
+#define          CO_SOF_NOSYNC   0x40000000    /* Use inband active signaling */
+
+/* Bits below C1_444ALPHA are not present in Cafe */
+#define REG_CTRL1      0x40    /* Control 1 */
+#define          C1_CLKGATE      0x00000001    /* Sensor clock gate */
+#define   C1_DESC_ENA    0x00000100    /* DMA descriptor enable */
+#define   C1_DESC_3WORD   0x00000200   /* Three-word descriptors used */
+#define          C1_444ALPHA     0x00f00000    /* Alpha field in RGB444 */
+#define          C1_ALPHA_SHFT   20
+#define          C1_DMAB32       0x00000000    /* 32-byte DMA burst */
+#define          C1_DMAB16       0x02000000    /* 16-byte DMA burst */
+#define          C1_DMAB64       0x04000000    /* 64-byte DMA burst */
+#define          C1_DMAB_MASK    0x06000000
+#define          C1_TWOBUFS      0x08000000    /* Use only two DMA buffers */
+#define          C1_PWRDWN       0x10000000    /* Power down */
+
+#define REG_CLKCTRL    0x88    /* Clock control */
+#define          CLK_DIV_MASK    0x0000ffff    /* Upper bits RW "reserved" */
+
+/* This appears to be a Cafe-only register */
+#define REG_UBAR       0xc4    /* Upper base address register */
+
+/* Armada 610 DMA descriptor registers */
+#define        REG_DMA_DESC_Y  0x200
+#define        REG_DMA_DESC_U  0x204
+#define        REG_DMA_DESC_V  0x208
+#define REG_DESC_LEN_Y 0x20c   /* Lengths are in bytes */
+#define        REG_DESC_LEN_U  0x210
+#define REG_DESC_LEN_V 0x214
+
+/*
+ * Useful stuff that probably belongs somewhere global.
+ */
+#define VGA_WIDTH      640
+#define VGA_HEIGHT     480
+
+#endif /* _MCAM_CORE_H */
diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/video/marvell-ccic/mmp-driver.c
new file mode 100644 (file)
index 0000000..d6b7645
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Support for the camera device found on Marvell MMP processors; known
+ * to work with the Armada 610 as used in the OLPC 1.75 system.
+ *
+ * Copyright 2011 Jonathan Corbet <corbet@lwn.net>
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/mmp-camera.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+
+#include "mcam-core.h"
+
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_LICENSE("GPL");
+
+struct mmp_camera {
+       void *power_regs;
+       struct platform_device *pdev;
+       struct mcam_camera mcam;
+       struct list_head devlist;
+       int irq;
+};
+
+static inline struct mmp_camera *mcam_to_cam(struct mcam_camera *mcam)
+{
+       return container_of(mcam, struct mmp_camera, mcam);
+}
+
+/*
+ * A silly little infrastructure so we can keep track of our devices.
+ * Chances are that we will never have more than one of them, but
+ * the Armada 610 *does* have two controllers...
+ */
+
+static LIST_HEAD(mmpcam_devices);
+static struct mutex mmpcam_devices_lock;
+
+static void mmpcam_add_device(struct mmp_camera *cam)
+{
+       mutex_lock(&mmpcam_devices_lock);
+       list_add(&cam->devlist, &mmpcam_devices);
+       mutex_unlock(&mmpcam_devices_lock);
+}
+
+static void mmpcam_remove_device(struct mmp_camera *cam)
+{
+       mutex_lock(&mmpcam_devices_lock);
+       list_del(&cam->devlist);
+       mutex_unlock(&mmpcam_devices_lock);
+}
+
+/*
+ * Platform dev remove passes us a platform_device, and there's
+ * no handy unused drvdata to stash a backpointer in.  So just
+ * dig it out of our list.
+ */
+static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
+{
+       struct mmp_camera *cam;
+
+       mutex_lock(&mmpcam_devices_lock);
+       list_for_each_entry(cam, &mmpcam_devices, devlist) {
+               if (cam->pdev == pdev) {
+                       mutex_unlock(&mmpcam_devices_lock);
+                       return cam;
+               }
+       }
+       mutex_unlock(&mmpcam_devices_lock);
+       return NULL;
+}
+
+
+
+
+/*
+ * Power-related registers; this almost certainly belongs
+ * somewhere else.
+ *
+ * ARMADA 610 register manual, sec 7.2.1, p1842.
+ */
+#define CPU_SUBSYS_PMU_BASE    0xd4282800
+#define REG_CCIC_DCGCR         0x28    /* CCIC dyn clock gate ctrl reg */
+#define REG_CCIC_CRCR          0x50    /* CCIC clk reset ctrl reg      */
+
+/*
+ * Power control.
+ */
+static void mmpcam_power_up(struct mcam_camera *mcam)
+{
+       struct mmp_camera *cam = mcam_to_cam(mcam);
+       struct mmp_camera_platform_data *pdata;
+/*
+ * Turn on power and clocks to the controller.
+ */
+       iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
+       iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
+       mdelay(1);
+/*
+ * Provide power to the sensor.
+ */
+       mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002);
+       pdata = cam->pdev->dev.platform_data;
+       gpio_set_value(pdata->sensor_power_gpio, 1);
+       mdelay(5);
+       mcam_reg_clear_bit(mcam, REG_CTRL1, 0x10000000);
+       gpio_set_value(pdata->sensor_reset_gpio, 0); /* reset is active low */
+       mdelay(5);
+       gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */
+       mdelay(5);
+}
+
+static void mmpcam_power_down(struct mcam_camera *mcam)
+{
+       struct mmp_camera *cam = mcam_to_cam(mcam);
+       struct mmp_camera_platform_data *pdata;
+/*
+ * Turn off clocks and set reset lines
+ */
+       iowrite32(0, cam->power_regs + REG_CCIC_DCGCR);
+       iowrite32(0, cam->power_regs + REG_CCIC_CRCR);
+/*
+ * Shut down the sensor.
+ */
+       pdata = cam->pdev->dev.platform_data;
+       gpio_set_value(pdata->sensor_power_gpio, 0);
+       gpio_set_value(pdata->sensor_reset_gpio, 0);
+}
+
+
+static irqreturn_t mmpcam_irq(int irq, void *data)
+{
+       struct mcam_camera *mcam = data;
+       unsigned int irqs, handled;
+
+       spin_lock(&mcam->dev_lock);
+       irqs = mcam_reg_read(mcam, REG_IRQSTAT);
+       handled = mccic_irq(mcam, irqs);
+       spin_unlock(&mcam->dev_lock);
+       return IRQ_RETVAL(handled);
+}
+
+
+static int mmpcam_probe(struct platform_device *pdev)
+{
+       struct mmp_camera *cam;
+       struct mcam_camera *mcam;
+       struct resource *res;
+       struct mmp_camera_platform_data *pdata;
+       int ret;
+
+       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+       if (cam == NULL)
+               return -ENOMEM;
+       cam->pdev = pdev;
+       INIT_LIST_HEAD(&cam->devlist);
+
+       mcam = &cam->mcam;
+       mcam->platform = MHP_Armada610;
+       mcam->plat_power_up = mmpcam_power_up;
+       mcam->plat_power_down = mmpcam_power_down;
+       mcam->dev = &pdev->dev;
+       mcam->use_smbus = 0;
+       mcam->chip_id = V4L2_IDENT_ARMADA610;
+       mcam->buffer_mode = B_DMA_sg;
+       spin_lock_init(&mcam->dev_lock);
+       /*
+        * Get our I/O memory.
+        */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no iomem resource!\n");
+               ret = -ENODEV;
+               goto out_free;
+       }
+       mcam->regs = ioremap(res->start, resource_size(res));
+       if (mcam->regs == NULL) {
+               dev_err(&pdev->dev, "MMIO ioremap fail\n");
+               ret = -ENODEV;
+               goto out_free;
+       }
+       /*
+        * Power/clock memory is elsewhere; get it too.  Perhaps this
+        * should really be managed outside of this driver?
+        */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no power resource!\n");
+               ret = -ENODEV;
+               goto out_unmap1;
+       }
+       cam->power_regs = ioremap(res->start, resource_size(res));
+       if (cam->power_regs == NULL) {
+               dev_err(&pdev->dev, "power MMIO ioremap fail\n");
+               ret = -ENODEV;
+               goto out_unmap1;
+       }
+       /*
+        * Find the i2c adapter.  This assumes, of course, that the
+        * i2c bus is already up and functioning.
+        */
+       pdata = pdev->dev.platform_data;
+       mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device);
+       if (mcam->i2c_adapter == NULL) {
+               ret = -ENODEV;
+               dev_err(&pdev->dev, "No i2c adapter\n");
+               goto out_unmap2;
+       }
+       /*
+        * Sensor GPIO pins.
+        */
+       ret = gpio_request(pdata->sensor_power_gpio, "cam-power");
+       if (ret) {
+               dev_err(&pdev->dev, "Can't get sensor power gpio %d",
+                               pdata->sensor_power_gpio);
+               goto out_unmap2;
+       }
+       gpio_direction_output(pdata->sensor_power_gpio, 0);
+       ret = gpio_request(pdata->sensor_reset_gpio, "cam-reset");
+       if (ret) {
+               dev_err(&pdev->dev, "Can't get sensor reset gpio %d",
+                               pdata->sensor_reset_gpio);
+               goto out_gpio;
+       }
+       gpio_direction_output(pdata->sensor_reset_gpio, 0);
+       /*
+        * Power the device up and hand it off to the core.
+        */
+       mmpcam_power_up(mcam);
+       ret = mccic_register(mcam);
+       if (ret)
+               goto out_gpio2;
+       /*
+        * Finally, set up our IRQ now that the core is ready to
+        * deal with it.
+        */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               ret = -ENODEV;
+               goto out_unregister;
+       }
+       cam->irq = res->start;
+       ret = request_irq(cam->irq, mmpcam_irq, IRQF_SHARED,
+                       "mmp-camera", mcam);
+       if (ret == 0) {
+               mmpcam_add_device(cam);
+               return 0;
+       }
+
+out_unregister:
+       mccic_shutdown(mcam);
+out_gpio2:
+       mmpcam_power_down(mcam);
+       gpio_free(pdata->sensor_reset_gpio);
+out_gpio:
+       gpio_free(pdata->sensor_power_gpio);
+out_unmap2:
+       iounmap(cam->power_regs);
+out_unmap1:
+       iounmap(mcam->regs);
+out_free:
+       kfree(cam);
+       return ret;
+}
+
+
+static int mmpcam_remove(struct mmp_camera *cam)
+{
+       struct mcam_camera *mcam = &cam->mcam;
+       struct mmp_camera_platform_data *pdata;
+
+       mmpcam_remove_device(cam);
+       free_irq(cam->irq, mcam);
+       mccic_shutdown(mcam);
+       mmpcam_power_down(mcam);
+       pdata = cam->pdev->dev.platform_data;
+       gpio_free(pdata->sensor_reset_gpio);
+       gpio_free(pdata->sensor_power_gpio);
+       iounmap(cam->power_regs);
+       iounmap(mcam->regs);
+       kfree(cam);
+       return 0;
+}
+
+static int mmpcam_platform_remove(struct platform_device *pdev)
+{
+       struct mmp_camera *cam = mmpcam_find_device(pdev);
+
+       if (cam == NULL)
+               return -ENODEV;
+       return mmpcam_remove(cam);
+}
+
+
+static struct platform_driver mmpcam_driver = {
+       .probe          = mmpcam_probe,
+       .remove         = mmpcam_platform_remove,
+       .driver = {
+               .name   = "mmp-camera",
+               .owner  = THIS_MODULE
+       }
+};
+
+
+static int __init mmpcam_init_module(void)
+{
+       mutex_init(&mmpcam_devices_lock);
+       return platform_driver_register(&mmpcam_driver);
+}
+
+static void __exit mmpcam_exit_module(void)
+{
+       platform_driver_unregister(&mmpcam_driver);
+       /*
+        * platform_driver_unregister() should have emptied the list
+        */
+       if (!list_empty(&mmpcam_devices))
+               printk(KERN_ERR "mmp_camera leaving devices behind\n");
+}
+
+module_init(mmpcam_init_module);
+module_exit(mmpcam_exit_module);
index b03d74e09a3c1083f226942e7b82f708797a38fc..166bf9349c10c03dacce418f452e7bdc64df168a 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
-#include <linux/version.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -35,7 +34,7 @@
 MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
 MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
 MODULE_LICENSE("GPL");
-
+MODULE_VERSION("0.1.1");
 
 #define MIN_W 32
 #define MIN_H 32
@@ -380,7 +379,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
        strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
-       cap->version = KERNEL_VERSION(0, 1, 0);
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
                          | V4L2_CAP_STREAMING;
 
index e2bbd8c35c9860a9ad1bd16d0ded17df64fae1ca..4da9cca939c121999908d021d66d169a20df70b7 100644 (file)
@@ -603,13 +603,9 @@ static int mt9m001_video_probe(struct soc_camera_device *icd,
        unsigned long flags;
        int ret;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /* Enable the chip */
        data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
@@ -675,8 +671,8 @@ static void mt9m001_video_remove(struct soc_camera_device *icd)
 {
        struct soc_camera_link *icl = to_soc_camera_link(icd);
 
-       dev_dbg(&icd->dev, "Video removed: %p, %p\n",
-               icd->dev.parent, icd->vdev);
+       dev_dbg(icd->pdev, "Video removed: %p, %p\n",
+               icd->parent, icd->vdev);
        if (icl->free_bus)
                icl->free_bus(icl);
 }
index ebebed929627c8a8ffcae19a6730992a066c0372..a357aa889fc6c07357b91c86877f8094db7d8539 100644 (file)
 #define MT9M111_RESET_RESTART_FRAME    (1 << 1)
 #define MT9M111_RESET_RESET_MODE       (1 << 0)
 
+#define MT9M111_RM_FULL_POWER_RD       (0 << 10)
+#define MT9M111_RM_LOW_POWER_RD                (1 << 10)
+#define MT9M111_RM_COL_SKIP_4X         (1 << 5)
+#define MT9M111_RM_ROW_SKIP_4X         (1 << 4)
+#define MT9M111_RM_COL_SKIP_2X         (1 << 3)
+#define MT9M111_RM_ROW_SKIP_2X         (1 << 2)
 #define MT9M111_RMB_MIRROR_COLS                (1 << 1)
 #define MT9M111_RMB_MIRROR_ROWS                (1 << 0)
 #define MT9M111_CTXT_CTRL_RESTART      (1 << 15)
 
 #define MT9M111_OPMODE_AUTOEXPO_EN     (1 << 14)
 #define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1)
-
+#define MT9M111_OUTFMT_FLIP_BAYER_COL  (1 << 9)
+#define MT9M111_OUTFMT_FLIP_BAYER_ROW  (1 << 8)
 #define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14)
 #define MT9M111_OUTFMT_BYPASS_IFP      (1 << 10)
 #define MT9M111_OUTFMT_INV_PIX_CLOCK   (1 << 9)
 #define MT9M111_OUTFMT_TST_RAMP_FRAME  (3 << 4)
 #define MT9M111_OUTFMT_SHIFT_3_UP      (1 << 3)
 #define MT9M111_OUTFMT_AVG_CHROMA      (1 << 2)
-#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y  (1 << 1)
-#define MT9M111_OUTFMT_SWAP_RGB_EVEN   (1 << 1)
-#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr        (1 << 0)
+#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN (1 << 1)
+#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B        (1 << 0)
 
 /*
  * Camera control register addresses (0x200..0x2ff not implemented)
 #define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val))
 #define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val))
 #define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
+#define reg_mask(reg, val, mask) mt9m111_reg_mask(client, MT9M111_##reg, \
+               (val), (mask))
 
 #define MT9M111_MIN_DARK_ROWS  8
 #define MT9M111_MIN_DARK_COLS  26
@@ -153,7 +161,11 @@ static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
        {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
        {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
        {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+       {V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
        {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
+       {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
+       {V4L2_MBUS_FMT_BGR565_2X8_LE, V4L2_COLORSPACE_SRGB},
+       {V4L2_MBUS_FMT_BGR565_2X8_BE, V4L2_COLORSPACE_SRGB},
        {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
        {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
 };
@@ -169,6 +181,8 @@ struct mt9m111 {
                         * from v4l2-chip-ident.h */
        enum mt9m111_context context;
        struct v4l2_rect rect;
+       struct mutex power_lock; /* lock to protect power_count */
+       int power_count;
        const struct mt9m111_datafmt *fmt;
        unsigned int gain;
        unsigned char autoexposure;
@@ -176,10 +190,6 @@ struct mt9m111 {
        unsigned int powered:1;
        unsigned int hflip:1;
        unsigned int vflip:1;
-       unsigned int swap_rgb_even_odd:1;
-       unsigned int swap_rgb_red_blue:1;
-       unsigned int swap_yuv_y_chromas:1;
-       unsigned int swap_yuv_cb_cr:1;
        unsigned int autowhitebalance:1;
 };
 
@@ -248,12 +258,26 @@ static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
        int ret;
 
        ret = mt9m111_reg_read(client, reg);
-       return mt9m111_reg_write(client, reg, ret & ~data);
+       if (ret >= 0)
+               ret = mt9m111_reg_write(client, reg, ret & ~data);
+       return ret;
 }
 
-static int mt9m111_set_context(struct i2c_client *client,
+static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg,
+                           const u16 data, const u16 mask)
+{
+       int ret;
+
+       ret = mt9m111_reg_read(client, reg);
+       if (ret >= 0)
+               ret = mt9m111_reg_write(client, reg, (ret & ~mask) | data);
+       return ret;
+}
+
+static int mt9m111_set_context(struct mt9m111 *mt9m111,
                               enum mt9m111_context ctxt)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
                | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
                | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
@@ -267,10 +291,10 @@ static int mt9m111_set_context(struct i2c_client *client,
                return reg_write(CONTEXT_CONTROL, valA);
 }
 
-static int mt9m111_setup_rect(struct i2c_client *client,
+static int mt9m111_setup_rect(struct mt9m111 *mt9m111,
                              struct v4l2_rect *rect)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret, is_raw_format;
        int width = rect->width;
        int height = rect->height;
@@ -312,81 +336,9 @@ static int mt9m111_setup_rect(struct i2c_client *client,
        return ret;
 }
 
-static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt)
+static int mt9m111_enable(struct mt9m111 *mt9m111)
 {
-       int ret;
-       u16 mask = MT9M111_OUTFMT_PROCESSED_BAYER | MT9M111_OUTFMT_RGB |
-               MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_SWAP_RGB_EVEN |
-               MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
-               MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr |
-               MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
-
-       ret = reg_read(OUTPUT_FORMAT_CTRL2_A);
-       if (ret >= 0)
-               ret = reg_write(OUTPUT_FORMAT_CTRL2_A, (ret & ~mask) | outfmt);
-       if (!ret)
-               ret = reg_read(OUTPUT_FORMAT_CTRL2_B);
-       if (ret >= 0)
-               ret = reg_write(OUTPUT_FORMAT_CTRL2_B, (ret & ~mask) | outfmt);
-
-       return ret;
-}
-
-static int mt9m111_setfmt_bayer8(struct i2c_client *client)
-{
-       return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER |
-                                   MT9M111_OUTFMT_RGB);
-}
-
-static int mt9m111_setfmt_bayer10(struct i2c_client *client)
-{
-       return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_BYPASS_IFP);
-}
-
-static int mt9m111_setfmt_rgb565(struct i2c_client *client)
-{
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-       int val = 0;
-
-       if (mt9m111->swap_rgb_red_blue)
-               val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
-       if (mt9m111->swap_rgb_even_odd)
-               val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
-       val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
-
-       return mt9m111_setup_pixfmt(client, val);
-}
-
-static int mt9m111_setfmt_rgb555(struct i2c_client *client)
-{
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-       int val = 0;
-
-       if (mt9m111->swap_rgb_red_blue)
-               val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
-       if (mt9m111->swap_rgb_even_odd)
-               val |= MT9M111_OUTFMT_SWAP_RGB_EVEN;
-       val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
-
-       return mt9m111_setup_pixfmt(client, val);
-}
-
-static int mt9m111_setfmt_yuv(struct i2c_client *client)
-{
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-       int val = 0;
-
-       if (mt9m111->swap_yuv_cb_cr)
-               val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr;
-       if (mt9m111->swap_yuv_y_chromas)
-               val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
-
-       return mt9m111_setup_pixfmt(client, val);
-}
-
-static int mt9m111_enable(struct i2c_client *client)
-{
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE);
@@ -395,8 +347,9 @@ static int mt9m111_enable(struct i2c_client *client)
        return ret;
 }
 
-static int mt9m111_reset(struct i2c_client *client)
+static int mt9m111_reset(struct mt9m111 *mt9m111)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
@@ -424,11 +377,9 @@ static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
        return 0;
 }
 
-static int mt9m111_make_rect(struct i2c_client *client,
+static int mt9m111_make_rect(struct mt9m111 *mt9m111,
                             struct v4l2_rect *rect)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-
        if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
            mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
                /* Bayer format - even size lengths */
@@ -444,14 +395,14 @@ static int mt9m111_make_rect(struct i2c_client *client,
        soc_camera_limit_side(&rect->top, &rect->height,
                     MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT);
 
-       return mt9m111_setup_rect(client, rect);
+       return mt9m111_setup_rect(mt9m111, rect);
 }
 
 static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
        struct v4l2_rect rect = a->c;
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        int ret;
 
        dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
@@ -460,7 +411,7 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
        if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       ret = mt9m111_make_rect(client, &rect);
+       ret = mt9m111_make_rect(mt9m111, &rect);
        if (!ret)
                mt9m111->rect = rect;
        return ret;
@@ -468,8 +419,7 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 
 static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 
        a->c    = mt9m111->rect;
        a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -496,8 +446,7 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 static int mt9m111_g_fmt(struct v4l2_subdev *sd,
                         struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 
        mf->width       = mt9m111->rect.width;
        mf->height      = mt9m111->rect.height;
@@ -508,51 +457,73 @@ static int mt9m111_g_fmt(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int mt9m111_set_pixfmt(struct i2c_client *client,
+static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
                              enum v4l2_mbus_pixelcode code)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
+       u16 data_outfmt2, mask_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
+               MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB |
+               MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
+               MT9M111_OUTFMT_RGB444x | MT9M111_OUTFMT_RGBx444 |
+               MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+               MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
        int ret;
 
        switch (code) {
        case V4L2_MBUS_FMT_SBGGR8_1X8:
-               ret = mt9m111_setfmt_bayer8(client);
+               data_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
+                       MT9M111_OUTFMT_RGB;
                break;
        case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
-               ret = mt9m111_setfmt_bayer10(client);
+               data_outfmt2 = MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB;
                break;
        case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
-               ret = mt9m111_setfmt_rgb555(client);
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 |
+                       MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
+               break;
+       case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
                break;
        case V4L2_MBUS_FMT_RGB565_2X8_LE:
-               ret = mt9m111_setfmt_rgb565(client);
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+                       MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
+               break;
+       case V4L2_MBUS_FMT_RGB565_2X8_BE:
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
+               break;
+       case V4L2_MBUS_FMT_BGR565_2X8_BE:
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+                       MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
+               break;
+       case V4L2_MBUS_FMT_BGR565_2X8_LE:
+               data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
+                       MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+                       MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
                break;
        case V4L2_MBUS_FMT_UYVY8_2X8:
-               mt9m111->swap_yuv_y_chromas = 0;
-               mt9m111->swap_yuv_cb_cr = 0;
-               ret = mt9m111_setfmt_yuv(client);
+               data_outfmt2 = 0;
                break;
        case V4L2_MBUS_FMT_VYUY8_2X8:
-               mt9m111->swap_yuv_y_chromas = 0;
-               mt9m111->swap_yuv_cb_cr = 1;
-               ret = mt9m111_setfmt_yuv(client);
+               data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
                break;
        case V4L2_MBUS_FMT_YUYV8_2X8:
-               mt9m111->swap_yuv_y_chromas = 1;
-               mt9m111->swap_yuv_cb_cr = 0;
-               ret = mt9m111_setfmt_yuv(client);
+               data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
                break;
        case V4L2_MBUS_FMT_YVYU8_2X8:
-               mt9m111->swap_yuv_y_chromas = 1;
-               mt9m111->swap_yuv_cb_cr = 1;
-               ret = mt9m111_setfmt_yuv(client);
+               data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
+                       MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
                break;
        default:
-               dev_err(&client->dev, "Pixel format not handled : %x\n",
-                       code);
-               ret = -EINVAL;
+               dev_err(&client->dev, "Pixel format not handled: %x\n", code);
+               return -EINVAL;
        }
 
+       ret = reg_mask(OUTPUT_FORMAT_CTRL2_A, data_outfmt2,
+                      mask_outfmt2);
+       if (!ret)
+               ret = reg_mask(OUTPUT_FORMAT_CTRL2_B, data_outfmt2,
+                              mask_outfmt2);
+
        return ret;
 }
 
@@ -561,7 +532,7 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        const struct mt9m111_datafmt *fmt;
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        struct v4l2_rect rect = {
                .left   = mt9m111->rect.left,
                .top    = mt9m111->rect.top,
@@ -579,9 +550,9 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
                "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__,
                mf->code, rect.left, rect.top, rect.width, rect.height);
 
-       ret = mt9m111_make_rect(client, &rect);
+       ret = mt9m111_make_rect(mt9m111, &rect);
        if (!ret)
-               ret = mt9m111_set_pixfmt(client, mf->code);
+               ret = mt9m111_set_pixfmt(mt9m111, mf->code);
        if (!ret) {
                mt9m111->rect   = rect;
                mt9m111->fmt    = fmt;
@@ -594,8 +565,7 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
 static int mt9m111_try_fmt(struct v4l2_subdev *sd,
                           struct v4l2_mbus_framefmt *mf)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        const struct mt9m111_datafmt *fmt;
        bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
                mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
@@ -635,7 +605,7 @@ static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
                                struct v4l2_dbg_chip_ident *id)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
 
        if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
                return -EINVAL;
@@ -726,21 +696,16 @@ static const struct v4l2_queryctrl mt9m111_controls[] = {
        }
 };
 
-static int mt9m111_resume(struct soc_camera_device *icd);
-static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state);
-
 static struct soc_camera_ops mt9m111_ops = {
-       .suspend                = mt9m111_suspend,
-       .resume                 = mt9m111_resume,
        .query_bus_param        = mt9m111_query_bus_param,
        .set_bus_param          = mt9m111_set_bus_param,
        .controls               = mt9m111_controls,
        .num_controls           = ARRAY_SIZE(mt9m111_controls),
 };
 
-static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask)
+static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        if (mt9m111->context == HIGHPOWER) {
@@ -758,8 +723,9 @@ static int mt9m111_set_flip(struct i2c_client *client, int flip, int mask)
        return ret;
 }
 
-static int mt9m111_get_global_gain(struct i2c_client *client)
+static int mt9m111_get_global_gain(struct mt9m111 *mt9m111)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int data;
 
        data = reg_read(GLOBAL_GAIN);
@@ -769,9 +735,9 @@ static int mt9m111_get_global_gain(struct i2c_client *client)
        return data;
 }
 
-static int mt9m111_set_global_gain(struct i2c_client *client, int gain)
+static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        u16 val;
 
        if (gain > 63 * 2 * 2)
@@ -788,9 +754,9 @@ static int mt9m111_set_global_gain(struct i2c_client *client, int gain)
        return reg_write(GLOBAL_GAIN, val);
 }
 
-static int mt9m111_set_autoexposure(struct i2c_client *client, int on)
+static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        if (on)
@@ -804,9 +770,9 @@ static int mt9m111_set_autoexposure(struct i2c_client *client, int on)
        return ret;
 }
 
-static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on)
+static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        if (on)
@@ -823,7 +789,7 @@ static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on)
 static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        int data;
 
        switch (ctrl->id) {
@@ -848,7 +814,7 @@ static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
                ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS);
                break;
        case V4L2_CID_GAIN:
-               data = mt9m111_get_global_gain(client);
+               data = mt9m111_get_global_gain(mt9m111);
                if (data < 0)
                        return data;
                ctrl->value = data;
@@ -865,8 +831,7 @@ static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 
 static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
        const struct v4l2_queryctrl *qctrl;
        int ret;
 
@@ -877,22 +842,22 @@ static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
                mt9m111->vflip = ctrl->value;
-               ret = mt9m111_set_flip(client, ctrl->value,
+               ret = mt9m111_set_flip(mt9m111, ctrl->value,
                                        MT9M111_RMB_MIRROR_ROWS);
                break;
        case V4L2_CID_HFLIP:
                mt9m111->hflip = ctrl->value;
-               ret = mt9m111_set_flip(client, ctrl->value,
+               ret = mt9m111_set_flip(mt9m111, ctrl->value,
                                        MT9M111_RMB_MIRROR_COLS);
                break;
        case V4L2_CID_GAIN:
-               ret = mt9m111_set_global_gain(client, ctrl->value);
+               ret = mt9m111_set_global_gain(mt9m111, ctrl->value);
                break;
        case V4L2_CID_EXPOSURE_AUTO:
-               ret =  mt9m111_set_autoexposure(client, ctrl->value);
+               ret =  mt9m111_set_autoexposure(mt9m111, ctrl->value);
                break;
        case V4L2_CID_AUTO_WHITE_BALANCE:
-               ret =  mt9m111_set_autowhitebalance(client, ctrl->value);
+               ret =  mt9m111_set_autowhitebalance(mt9m111, ctrl->value);
                break;
        default:
                ret = -EINVAL;
@@ -901,60 +866,52 @@ static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        return ret;
 }
 
-static int mt9m111_suspend(struct soc_camera_device *icd, pm_message_t state)
+static int mt9m111_suspend(struct mt9m111 *mt9m111)
 {
-       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-
-       mt9m111->gain = mt9m111_get_global_gain(client);
+       mt9m111->gain = mt9m111_get_global_gain(mt9m111);
 
        return 0;
 }
 
-static int mt9m111_restore_state(struct i2c_client *client)
+static void mt9m111_restore_state(struct mt9m111 *mt9m111)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
-
-       mt9m111_set_context(client, mt9m111->context);
-       mt9m111_set_pixfmt(client, mt9m111->fmt->code);
-       mt9m111_setup_rect(client, &mt9m111->rect);
-       mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
-       mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
-       mt9m111_set_global_gain(client, mt9m111->gain);
-       mt9m111_set_autoexposure(client, mt9m111->autoexposure);
-       mt9m111_set_autowhitebalance(client, mt9m111->autowhitebalance);
-       return 0;
+       mt9m111_set_context(mt9m111, mt9m111->context);
+       mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
+       mt9m111_setup_rect(mt9m111, &mt9m111->rect);
+       mt9m111_set_flip(mt9m111, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS);
+       mt9m111_set_flip(mt9m111, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
+       mt9m111_set_global_gain(mt9m111, mt9m111->gain);
+       mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure);
+       mt9m111_set_autowhitebalance(mt9m111, mt9m111->autowhitebalance);
 }
 
-static int mt9m111_resume(struct soc_camera_device *icd)
+static int mt9m111_resume(struct mt9m111 *mt9m111)
 {
-       struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
        int ret = 0;
 
        if (mt9m111->powered) {
-               ret = mt9m111_enable(client);
+               ret = mt9m111_enable(mt9m111);
                if (!ret)
-                       ret = mt9m111_reset(client);
+                       ret = mt9m111_reset(mt9m111);
                if (!ret)
-                       ret = mt9m111_restore_state(client);
+                       mt9m111_restore_state(mt9m111);
        }
        return ret;
 }
 
-static int mt9m111_init(struct i2c_client *client)
+static int mt9m111_init(struct mt9m111 *mt9m111)
 {
-       struct mt9m111 *mt9m111 = to_mt9m111(client);
+       struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
        int ret;
 
        mt9m111->context = HIGHPOWER;
-       ret = mt9m111_enable(client);
+       ret = mt9m111_enable(mt9m111);
        if (!ret)
-               ret = mt9m111_reset(client);
+               ret = mt9m111_reset(mt9m111);
        if (!ret)
-               ret = mt9m111_set_context(client, mt9m111->context);
+               ret = mt9m111_set_context(mt9m111, mt9m111->context);
        if (!ret)
-               ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure);
+               ret = mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure);
        if (ret)
                dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
        return ret;
@@ -971,20 +928,13 @@ static int mt9m111_video_probe(struct soc_camera_device *icd,
        s32 data;
        int ret;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        mt9m111->autoexposure = 1;
        mt9m111->autowhitebalance = 1;
 
-       mt9m111->swap_rgb_even_odd = 1;
-       mt9m111->swap_rgb_red_blue = 1;
-
        data = reg_read(CHIP_VERSION);
 
        switch (data) {
@@ -1005,16 +955,51 @@ static int mt9m111_video_probe(struct soc_camera_device *icd,
                goto ei2c;
        }
 
-       ret = mt9m111_init(client);
+       ret = mt9m111_init(mt9m111);
 
 ei2c:
        return ret;
 }
 
+static int mt9m111_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       mutex_lock(&mt9m111->power_lock);
+
+       /*
+        * If the power count is modified from 0 to != 0 or from != 0 to 0,
+        * update the power state.
+        */
+       if (mt9m111->power_count == !on) {
+               if (on) {
+                       ret = mt9m111_resume(mt9m111);
+                       if (ret) {
+                               dev_err(&client->dev,
+                                       "Failed to resume the sensor: %d\n", ret);
+                               goto out;
+                       }
+               } else {
+                       mt9m111_suspend(mt9m111);
+               }
+       }
+
+       /* Update the power count. */
+       mt9m111->power_count += on ? 1 : -1;
+       WARN_ON(mt9m111->power_count < 0);
+
+out:
+       mutex_unlock(&mt9m111->power_lock);
+       return ret;
+}
+
 static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
        .g_ctrl         = mt9m111_g_ctrl,
        .s_ctrl         = mt9m111_s_ctrl,
        .g_chip_ident   = mt9m111_g_chip_ident,
+       .s_power        = mt9m111_s_power,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register     = mt9m111_g_register,
        .s_register     = mt9m111_s_register,
index 7ce279c3751dbd2dd5379c454046473d7b0b775e..30547cc3f89b374e286ddf9da1105bf9317db2df 100644 (file)
@@ -700,8 +700,7 @@ static int mt9t031_runtime_suspend(struct device *dev)
 static int mt9t031_runtime_resume(struct device *dev)
 {
        struct video_device *vdev = to_video_device(dev);
-       struct soc_camera_device *icd = container_of(vdev->parent,
-               struct soc_camera_device, dev);
+       struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct mt9t031 *mt9t031 = to_mt9t031(client);
index bffa9ee10968e315172b1cc4678d3c2e1c0397b5..d2e0a50063a269e54987f7d3e9e5221855786c2e 100644 (file)
@@ -1057,13 +1057,9 @@ static int mt9t112_camera_probe(struct soc_camera_device *icd,
        const char          *devname;
        int                  chipid;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * check and show chip ID
index 4904d25f689fdf61c60fc0d8db2d40f80fd473f8..893a8b8f514134a4aa68645e8029166e75e16c02 100644 (file)
@@ -54,10 +54,19 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = {
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Gain",
                .minimum = 0,
-               .maximum = (1 << 10) - 1,
+               .maximum = (1 << 12) - 1 - 0x0020,
                .step = 1,
                .default_value = 0x0020,
                .flags = 0,
+       }, {
+               .id = V4L2_CID_EXPOSURE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Exposure",
+               .minimum = 0,
+               .maximum = 2047,
+               .step = 1,
+               .default_value = 0x01fc,
+               .flags = 0,
        }, {
                .id = V4L2_CID_RED_BALANCE,
                .type = V4L2_CTRL_TYPE_INTEGER,
@@ -105,7 +114,8 @@ struct mt9v011 {
        unsigned hflip:1;
        unsigned vflip:1;
 
-       u16 global_gain, red_bal, blue_bal;
+       u16 global_gain, exposure;
+       s16 red_bal, blue_bal;
 };
 
 static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd)
@@ -180,24 +190,68 @@ static const struct i2c_reg_value mt9v011_init_default[] = {
                { R07_MT9V011_OUT_CTRL, 0x0002 },       /* chip enable */
 };
 
+
+static u16 calc_mt9v011_gain(s16 lineargain)
+{
+
+       u16 digitalgain = 0;
+       u16 analogmult = 0;
+       u16 analoginit = 0;
+
+       if (lineargain < 0)
+               lineargain = 0;
+
+       /* recommended minimum */
+       lineargain += 0x0020;
+
+       if (lineargain > 2047)
+               lineargain = 2047;
+
+       if (lineargain > 1023) {
+               digitalgain = 3;
+               analogmult = 3;
+               analoginit = lineargain / 16;
+       } else if (lineargain > 511) {
+               digitalgain = 1;
+               analogmult = 3;
+               analoginit = lineargain / 8;
+       } else if (lineargain > 255) {
+               analogmult = 3;
+               analoginit = lineargain / 4;
+       } else if (lineargain > 127) {
+               analogmult = 1;
+               analoginit = lineargain / 2;
+       } else
+               analoginit = lineargain;
+
+       return analoginit + (analogmult << 7) + (digitalgain << 9);
+
+}
+
 static void set_balance(struct v4l2_subdev *sd)
 {
        struct mt9v011 *core = to_mt9v011(sd);
-       u16 green1_gain, green2_gain, blue_gain, red_gain;
+       u16 green_gain, blue_gain, red_gain;
+       u16 exposure;
+       s16 bal;
 
-       green1_gain = core->global_gain;
-       green2_gain = core->global_gain;
+       exposure = core->exposure;
 
-       blue_gain = core->global_gain +
-                   core->global_gain * core->blue_bal / (1 << 9);
+       green_gain = calc_mt9v011_gain(core->global_gain);
 
-       red_gain = core->global_gain +
-                  core->global_gain * core->blue_bal / (1 << 9);
+       bal = core->global_gain;
+       bal += (core->blue_bal * core->global_gain / (1 << 7));
+       blue_gain = calc_mt9v011_gain(bal);
 
-       mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green1_gain);
-       mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN,  green1_gain);
+       bal = core->global_gain;
+       bal += (core->red_bal * core->global_gain / (1 << 7));
+       red_gain = calc_mt9v011_gain(bal);
+
+       mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green_gain);
+       mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green_gain);
        mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain);
        mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
+       mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure);
 }
 
 static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator)
@@ -286,7 +340,7 @@ static void set_res(struct v4l2_subdev *sd)
         * be missing.
         */
 
-       hstart = 14 + (640 - core->width) / 2;
+       hstart = 20 + (640 - core->width) / 2;
        mt9v011_write(sd, R02_MT9V011_COLSTART, hstart);
        mt9v011_write(sd, R04_MT9V011_WIDTH, core->width);
        mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width);
@@ -338,6 +392,9 @@ static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        case V4L2_CID_GAIN:
                ctrl->value = core->global_gain;
                return 0;
+       case V4L2_CID_EXPOSURE:
+               ctrl->value = core->exposure;
+               return 0;
        case V4L2_CID_RED_BALANCE:
                ctrl->value = core->red_bal;
                return 0;
@@ -392,6 +449,9 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
        case V4L2_CID_GAIN:
                core->global_gain = ctrl->value;
                break;
+       case V4L2_CID_EXPOSURE:
+               core->exposure = ctrl->value;
+               break;
        case V4L2_CID_RED_BALANCE:
                core->red_bal = ctrl->value;
                break;
@@ -598,6 +658,7 @@ static int mt9v011_probe(struct i2c_client *c,
        }
 
        core->global_gain = 0x0024;
+       core->exposure = 0x01fc;
        core->width  = 640;
        core->height = 480;
        core->xtal = 27000000;  /* Hz */
index fc76ed1c08e59a43baf0a3632d0417734b807d7a..51b0fccbfe70f922080f25bf15122816466ff26a 100644 (file)
@@ -728,9 +728,9 @@ static int mt9v022_video_probe(struct soc_camera_device *icd,
        int ret;
        unsigned long flags;
 
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /* Read out the chip version register */
        data = reg_read(client, MT9V022_CHIP_VERSION);
@@ -809,8 +809,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)
 {
        struct soc_camera_link *icl = to_soc_camera_link(icd);
 
-       dev_dbg(&icd->dev, "Video removed: %p, %p\n",
-               icd->dev.parent, icd->vdev);
+       dev_dbg(icd->pdev, "Video removed: %p, %p\n",
+               icd->parent, icd->vdev);
        if (icl->free_bus)
                icl->free_bus(icl);
 }
index 1319c2c48aff7ee3e0c56bc20aec69bc32a6a438..c64e1dc4cb4e52585f3518564cf334d2b2bf55ba 100644 (file)
 #define MT9V032_CHIP_VERSION                           0x00
 #define                MT9V032_CHIP_ID_REV1                    0x1311
 #define                MT9V032_CHIP_ID_REV3                    0x1313
-#define MT9V032_ROW_START                              0x01
-#define                MT9V032_ROW_START_MIN                   4
-#define                MT9V032_ROW_START_DEF                   10
-#define                MT9V032_ROW_START_MAX                   482
-#define MT9V032_COLUMN_START                           0x02
+#define MT9V032_COLUMN_START                           0x01
 #define                MT9V032_COLUMN_START_MIN                1
-#define                MT9V032_COLUMN_START_DEF                2
+#define                MT9V032_COLUMN_START_DEF                1
 #define                MT9V032_COLUMN_START_MAX                752
+#define MT9V032_ROW_START                              0x02
+#define                MT9V032_ROW_START_MIN                   4
+#define                MT9V032_ROW_START_DEF                   5
+#define                MT9V032_ROW_START_MAX                   482
 #define MT9V032_WINDOW_HEIGHT                          0x03
 #define                MT9V032_WINDOW_HEIGHT_MIN               1
 #define                MT9V032_WINDOW_HEIGHT_DEF               480
@@ -420,13 +420,13 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev,
        struct v4l2_rect *__crop;
        struct v4l2_rect rect;
 
-       /* Clamp the crop rectangle boundaries and align them to a multiple of 2
-        * pixels.
+       /* Clamp the crop rectangle boundaries and align them to a non multiple
+        * of 2 pixels to ensure a GRBG Bayer pattern.
         */
-       rect.left = clamp(ALIGN(crop->rect.left, 2),
+       rect.left = clamp(ALIGN(crop->rect.left + 1, 2) - 1,
                          MT9V032_COLUMN_START_MIN,
                          MT9V032_COLUMN_START_MAX);
-       rect.top = clamp(ALIGN(crop->rect.top, 2),
+       rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1,
                         MT9V032_ROW_START_MIN,
                         MT9V032_ROW_START_MAX);
        rect.width = clamp(ALIGN(crop->rect.width, 2),
index 63f8a0cc33d89ec167701c1bee1a0614eebed89f..087db12a3a678eed5ef67f2b273746828da10d91 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/time.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 
 #include <media/soc_camera.h>
@@ -73,7 +72,7 @@
 #define CSISR_SOF_INT          (1 << 16)
 #define CSISR_DRDY             (1 << 0)
 
-#define VERSION_CODE KERNEL_VERSION(0, 0, 1)
+#define DRIVER_VERSION "0.0.2"
 #define DRIVER_NAME "mx1-camera"
 
 #define CSI_IRQ_MASK   (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \
@@ -142,7 +141,7 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
                *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
 
-       dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
+       dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
 
        return 0;
 }
@@ -154,7 +153,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf)
 
        BUG_ON(in_interrupt());
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        /*
@@ -179,7 +178,7 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
        if (bytes_per_line < 0)
                return bytes_per_line;
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        /* Added list head initialization on alloc */
@@ -232,7 +231,7 @@ out:
 static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
 {
        struct videobuf_buffer *vbuf = &pcdev->active->vb;
-       struct device *dev = pcdev->icd->dev.parent;
+       struct device *dev = pcdev->icd->parent;
        int ret;
 
        if (unlikely(!pcdev->active)) {
@@ -256,11 +255,11 @@ static void mx1_videobuf_queue(struct videobuf_queue *vq,
                                                struct videobuf_buffer *vb)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
        struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        list_add_tail(&vb->queue, &pcdev->capture);
@@ -287,7 +286,7 @@ static void mx1_videobuf_release(struct videobuf_queue *vq,
        struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
 #ifdef DEBUG
        struct soc_camera_device *icd = vq->priv_data;
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
 
        dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
@@ -343,7 +342,7 @@ static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev,
 static void mx1_camera_dma_irq(int channel, void *data)
 {
        struct mx1_camera_dev *pcdev = data;
-       struct device *dev = pcdev->icd->dev.parent;
+       struct device *dev = pcdev->icd->parent;
        struct mx1_buffer *buf;
        struct videobuf_buffer *vb;
        unsigned long flags;
@@ -378,10 +377,10 @@ static struct videobuf_queue_ops mx1_videobuf_ops = {
 static void mx1_camera_init_videobuf(struct videobuf_queue *q,
                                     struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
 
-       videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->dev.parent,
+       videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->parent,
                                &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                V4L2_FIELD_NONE,
                                sizeof(struct mx1_buffer), icd, &icd->video_lock);
@@ -401,7 +400,7 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
         */
        div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
 
-       dev_dbg(pcdev->icd->dev.parent,
+       dev_dbg(pcdev->icd->parent,
                "System clock %lukHz, target freq %dkHz, divisor %lu\n",
                lcdclk / 1000, mclk / 1000, div);
 
@@ -412,7 +411,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 {
        unsigned int csicr1 = CSICR1_EN;
 
-       dev_dbg(pcdev->icd->dev.parent, "Activate device\n");
+       dev_dbg(pcdev->icd->parent, "Activate device\n");
 
        clk_enable(pcdev->clk);
 
@@ -428,7 +427,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 
 static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
 {
-       dev_dbg(pcdev->icd->dev.parent, "Deactivate device\n");
+       dev_dbg(pcdev->icd->parent, "Deactivate device\n");
 
        /* Disable all CSI interface */
        __raw_writel(0x00, pcdev->base + CSICR1);
@@ -442,13 +441,13 @@ static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
  */
 static int mx1_camera_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
 
        if (pcdev->icd)
                return -EBUSY;
 
-       dev_info(icd->dev.parent, "MX1 Camera driver attached to camera %d\n",
+       dev_info(icd->parent, "MX1 Camera driver attached to camera %d\n",
                 icd->devnum);
 
        mx1_camera_activate(pcdev);
@@ -460,7 +459,7 @@ static int mx1_camera_add_device(struct soc_camera_device *icd)
 
 static void mx1_camera_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
        unsigned int csicr1;
 
@@ -473,7 +472,7 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd)
        /* Stop DMA engine */
        imx_dma_disable(pcdev->dma_chan);
 
-       dev_info(icd->dev.parent, "MX1 Camera driver detached from camera %d\n",
+       dev_info(icd->parent, "MX1 Camera driver detached from camera %d\n",
                 icd->devnum);
 
        mx1_camera_deactivate(pcdev);
@@ -491,7 +490,7 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd,
 
 static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx1_camera_dev *pcdev = ici->priv;
        unsigned long camera_flags, common_flags;
        unsigned int csicr1;
@@ -562,14 +561,14 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n",
+               dev_warn(icd->parent, "Format %x not found\n",
                         pix->pixelformat);
                return -EINVAL;
        }
 
        buswidth = xlate->host_fmt->bits_per_sample;
        if (buswidth > 8) {
-               dev_warn(icd->dev.parent,
+               dev_warn(icd->parent,
                         "bits-per-sample %d for format %x unsupported\n",
                         buswidth, pix->pixelformat);
                return -EINVAL;
@@ -609,7 +608,7 @@ static int mx1_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n",
+               dev_warn(icd->parent, "Format %x not found\n",
                         pix->pixelformat);
                return -EINVAL;
        }
@@ -676,7 +675,6 @@ static int mx1_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the friendly caller:-> */
        strlcpy(cap->card, "i.MX1/i.MXL Camera", sizeof(cap->card));
-       cap->version = VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
@@ -883,4 +881,5 @@ module_exit(mx1_camera_exit);
 MODULE_DESCRIPTION("i.MX1/i.MXL SoC Camera Host driver");
 MODULE_AUTHOR("Paulius Zaleckas <paulius.zaleckas@teltonika.lt>");
 MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRIVER_VERSION);
 MODULE_ALIAS("platform:" DRIVER_NAME);
index 4eab1c620318ef49c22aed6e2a208646b27f513c..ec2410c0c8069cddda1d19986d2235072bccbfbd 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/time.h>
-#include <linux/version.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
@@ -47,7 +46,7 @@
 #include <asm/dma.h>
 
 #define MX2_CAM_DRV_NAME "mx2-camera"
-#define MX2_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
+#define MX2_CAM_VERSION "0.0.6"
 #define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera"
 
 /* reset values */
@@ -278,7 +277,7 @@ static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
  */
 static int mx2_camera_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        int ret;
        u32 csicr1;
@@ -303,7 +302,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
 
        pcdev->icd = icd;
 
-       dev_info(icd->dev.parent, "Camera driver attached to camera %d\n",
+       dev_info(icd->parent, "Camera driver attached to camera %d\n",
                 icd->devnum);
 
        return 0;
@@ -311,12 +310,12 @@ static int mx2_camera_add_device(struct soc_camera_device *icd)
 
 static void mx2_camera_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
 
        BUG_ON(icd != pcdev->icd);
 
-       dev_info(icd->dev.parent, "Camera driver detached from camera %d\n",
+       dev_info(icd->parent, "Camera driver detached from camera %d\n",
                 icd->devnum);
 
        mx2_camera_deactivate(pcdev);
@@ -437,7 +436,7 @@ static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                        icd->current_fmt->host_fmt);
 
-       dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+       dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
 
        if (bytes_per_line < 0)
                return bytes_per_line;
@@ -457,7 +456,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
        struct soc_camera_device *icd = vq->priv_data;
        struct videobuf_buffer *vb = &buf->vb;
 
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        /*
@@ -467,7 +466,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
        videobuf_waiton(vq, vb, 0, 0);
 
        videobuf_dma_contig_free(vq, vb);
-       dev_dbg(&icd->dev, "%s freed\n", __func__);
+       dev_dbg(icd->parent, "%s freed\n", __func__);
 
        vb->state = VIDEOBUF_NEEDS_INIT;
 }
@@ -481,7 +480,7 @@ static int mx2_videobuf_prepare(struct videobuf_queue *vq,
                        icd->current_fmt->host_fmt);
        int ret = 0;
 
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        if (bytes_per_line < 0)
@@ -533,12 +532,12 @@ static void mx2_videobuf_queue(struct videobuf_queue *vq,
 {
        struct soc_camera_device *icd = vq->priv_data;
        struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+               to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
        unsigned long flags;
 
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        spin_lock_irqsave(&pcdev->lock, flags);
@@ -611,27 +610,27 @@ static void mx2_videobuf_release(struct videobuf_queue *vq,
                                 struct videobuf_buffer *vb)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
        unsigned long flags;
 
 #ifdef DEBUG
-       dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        switch (vb->state) {
        case VIDEOBUF_ACTIVE:
-               dev_info(&icd->dev, "%s (active)\n", __func__);
+               dev_info(icd->parent, "%s (active)\n", __func__);
                break;
        case VIDEOBUF_QUEUED:
-               dev_info(&icd->dev, "%s (queued)\n", __func__);
+               dev_info(icd->parent, "%s (queued)\n", __func__);
                break;
        case VIDEOBUF_PREPARED:
-               dev_info(&icd->dev, "%s (prepared)\n", __func__);
+               dev_info(icd->parent, "%s (prepared)\n", __func__);
                break;
        default:
-               dev_info(&icd->dev, "%s (unknown) %d\n", __func__,
+               dev_info(icd->parent, "%s (unknown) %d\n", __func__,
                                vb->state);
                break;
        }
@@ -678,7 +677,7 @@ static struct videobuf_queue_ops mx2_videobuf_ops = {
 static void mx2_camera_init_videobuf(struct videobuf_queue *q,
                              struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
 
        videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev,
@@ -719,7 +718,7 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
                int bytesperline)
 {
        struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+               to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
 
        writel(pcdev->discard_buffer_dma,
@@ -772,7 +771,7 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd,
                __u32 pixfmt)
 {
        struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+               to_soc_camera_host(icd->parent);
        struct mx2_camera_dev *pcdev = ici->priv;
        unsigned long camera_flags, common_flags;
        int ret = 0;
@@ -891,7 +890,7 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd,
        if (ret < 0)
                return ret;
 
-       dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
+       dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
                mf.width, mf.height);
 
        icd->user_width         = mf.width;
@@ -911,7 +910,7 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n",
+               dev_warn(icd->parent, "Format %x not found\n",
                                pix->pixelformat);
                return -EINVAL;
        }
@@ -951,7 +950,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (pixfmt && !xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
+               dev_warn(icd->parent, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -974,11 +973,16 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
                if (pix->bytesperline < 0)
                        return pix->bytesperline;
                pix->sizeimage = pix->height * pix->bytesperline;
-               if (pix->sizeimage > (4 * 0x3ffff)) { /* CSIRXCNT limit */
-                       dev_warn(icd->dev.parent,
-                                       "Image size (%u) above limit\n",
-                                       pix->sizeimage);
-                       return -EINVAL;
+               /* Check against the CSIRXCNT limit */
+               if (pix->sizeimage > 4 * 0x3ffff) {
+                       /* Adjust geometry, preserve aspect ratio */
+                       unsigned int new_height = int_sqrt(4 * 0x3ffff *
+                                       pix->height / pix->bytesperline);
+                       pix->width = new_height * pix->width / pix->height;
+                       pix->height = new_height;
+                       pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+                                                       xlate->host_fmt);
+                       BUG_ON(pix->bytesperline < 0);
                }
        }
 
@@ -996,7 +1000,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
        if (mf.field == V4L2_FIELD_ANY)
                mf.field = V4L2_FIELD_NONE;
        if (mf.field != V4L2_FIELD_NONE) {
-               dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+               dev_err(icd->parent, "Field type %d unsupported.\n",
                                mf.field);
                return -EINVAL;
        }
@@ -1014,7 +1018,6 @@ static int mx2_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the friendly caller:-> */
        strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
-       cap->version = MX2_CAM_VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
@@ -1523,3 +1526,4 @@ module_exit(mx2_camera_exit);
 MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver");
 MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(MX2_CAM_VERSION);
index c7680eb83664ea6606d238cd6a53d55380194912..c045b47803adfdca07328815b08c34ab009ea9e3 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
@@ -195,7 +194,7 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
                        unsigned long sizes[], void *alloc_ctxs[])
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                                                icd->current_fmt->host_fmt);
@@ -224,7 +223,7 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
 static int mx3_videobuf_prepare(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
        struct scatterlist *sg;
@@ -242,7 +241,7 @@ static int mx3_videobuf_prepare(struct vb2_buffer *vb)
        new_size = bytes_per_line * icd->user_height;
 
        if (vb2_plane_size(vb, 0) < new_size) {
-               dev_err(icd->dev.parent, "Buffer too small (%lu < %zu)\n",
+               dev_err(icd->parent, "Buffer too small (%lu < %zu)\n",
                        vb2_plane_size(vb, 0), new_size);
                return -ENOBUFS;
        }
@@ -284,7 +283,7 @@ static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc)
 static void mx3_videobuf_queue(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct mx3_camera_buffer *buf = to_mx3_vb(vb);
        struct dma_async_tx_descriptor *txd = buf->txd;
@@ -337,7 +336,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
        spin_unlock_irq(&mx3_cam->lock);
 
        cookie = txd->tx_submit(txd);
-       dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n",
+       dev_dbg(icd->parent, "Submitted cookie %d DMA 0x%08x\n",
                cookie, sg_dma_address(&buf->sg));
 
        if (cookie >= 0)
@@ -358,13 +357,13 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
 static void mx3_videobuf_release(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct mx3_camera_buffer *buf = to_mx3_vb(vb);
        struct dma_async_tx_descriptor *txd = buf->txd;
        unsigned long flags;
 
-       dev_dbg(icd->dev.parent,
+       dev_dbg(icd->parent,
                "Release%s DMA 0x%08x, queue %sempty\n",
                mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
                list_empty(&buf->queue) ? "" : "not ");
@@ -403,7 +402,7 @@ static int mx3_videobuf_init(struct vb2_buffer *vb)
 static int mx3_stop_streaming(struct vb2_queue *q)
 {
        struct soc_camera_device *icd = soc_camera_from_vb2q(q);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
        struct dma_chan *chan;
@@ -499,7 +498,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
 
        clk_enable(mx3_cam->clk);
        rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
-       dev_dbg(icd->dev.parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
+       dev_dbg(icd->parent, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
        if (rate)
                clk_set_rate(mx3_cam->clk, rate);
 }
@@ -507,7 +506,7 @@ static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
 /* Called with .video_lock held */
 static int mx3_camera_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
 
        if (mx3_cam->icd)
@@ -517,7 +516,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd)
 
        mx3_cam->icd = icd;
 
-       dev_info(icd->dev.parent, "MX3 Camera driver attached to camera %d\n",
+       dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n",
                 icd->devnum);
 
        return 0;
@@ -526,7 +525,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd)
 /* Called with .video_lock held */
 static void mx3_camera_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
 
@@ -541,7 +540,7 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd)
 
        mx3_cam->icd = NULL;
 
-       dev_info(icd->dev.parent, "MX3 Camera driver detached from camera %d\n",
+       dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n",
                 icd->devnum);
 }
 
@@ -608,12 +607,12 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam,
 static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
                                    const unsigned int depth)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        unsigned long bus_flags, camera_flags;
        int ret = test_platform_param(mx3_cam, depth, &bus_flags);
 
-       dev_dbg(icd->dev.parent, "request bus width %d bit: %d\n", depth, ret);
+       dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret);
 
        if (ret < 0)
                return ret;
@@ -622,7 +621,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
 
        ret = soc_camera_bus_param_compatible(camera_flags, bus_flags);
        if (ret < 0)
-               dev_warn(icd->dev.parent,
+               dev_warn(icd->parent,
                         "Flags incompatible: camera %lx, host %lx\n",
                         camera_flags, bus_flags);
 
@@ -676,7 +675,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
                                  struct soc_camera_format_xlate *xlate)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        int formats = 0, ret;
        enum v4l2_mbus_pixelcode code;
        const struct soc_mbus_pixelfmt *fmt;
@@ -688,7 +687,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
 
        fmt = soc_mbus_get_fmtdesc(code);
        if (!fmt) {
-               dev_warn(icd->dev.parent,
+               dev_warn(icd->parent,
                         "Unsupported format code #%u: %d\n", idx, code);
                return 0;
        }
@@ -816,7 +815,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
                               struct v4l2_crop *a)
 {
        struct v4l2_rect *rect = &a->c;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct v4l2_mbus_framefmt mf;
@@ -849,7 +848,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
                configure_geometry(mx3_cam, mf.width, mf.height,
                                   icd->current_fmt->host_fmt);
 
-       dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
+       dev_dbg(icd->parent, "Sensor cropped %dx%d\n",
                mf.width, mf.height);
 
        icd->user_width         = mf.width;
@@ -861,7 +860,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
 static int mx3_camera_set_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate;
@@ -871,13 +870,13 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n",
+               dev_warn(icd->parent, "Format %x not found\n",
                         pix->pixelformat);
                return -EINVAL;
        }
 
        stride_align(&pix->width);
-       dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height);
+       dev_dbg(icd->parent, "Set format %dx%d\n", pix->width, pix->height);
 
        /*
         * Might have to perform a complete interface initialisation like in
@@ -913,13 +912,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
        pix->colorspace         = mf.colorspace;
        icd->current_fmt        = xlate;
 
-       pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
-                                                   xlate->host_fmt);
-       if (pix->bytesperline < 0)
-               return pix->bytesperline;
-       pix->sizeimage = pix->height * pix->bytesperline;
-
-       dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height);
+       dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height);
 
        return ret;
 }
@@ -936,7 +929,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (pixfmt && !xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
+               dev_warn(icd->parent, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -946,12 +939,6 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
        if (pix->width > 4096)
                pix->width = 4096;
 
-       pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
-                                                   xlate->host_fmt);
-       if (pix->bytesperline < 0)
-               return pix->bytesperline;
-       pix->sizeimage = pix->height * pix->bytesperline;
-
        /* limit to sensor capabilities */
        mf.width        = pix->width;
        mf.height       = pix->height;
@@ -974,7 +961,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
        case V4L2_FIELD_NONE:
                break;
        default:
-               dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+               dev_err(icd->parent, "Field type %d unsupported.\n",
                        mf.field);
                ret = -EINVAL;
        }
@@ -1000,7 +987,6 @@ static int mx3_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the firendly caller:-> */
        strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card));
-       cap->version = KERNEL_VERSION(0, 2, 2);
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
@@ -1008,7 +994,7 @@ static int mx3_camera_querycap(struct soc_camera_host *ici,
 
 static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
        unsigned long bus_flags, camera_flags, common_flags;
        u32 dw, sens_conf;
@@ -1016,7 +1002,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
        int buswidth;
        int ret;
        const struct soc_camera_format_xlate *xlate;
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
 
        fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code);
        if (!fmt)
@@ -1325,4 +1311,5 @@ module_exit(mx3_camera_exit);
 MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
 MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.2.3");
 MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME);
index e63233fd2aaab3a4a1cc99e7c0e546cd72a3592c..390ab094f9f2389a0d80deb893f6d357199221fd 100644 (file)
@@ -1,11 +1,14 @@
+config VIDEO_OMAP2_VOUT_VRFB
+       bool
+
 config VIDEO_OMAP2_VOUT
        tristate "OMAP2/OMAP3 V4L2-Display driver"
        depends on ARCH_OMAP2 || ARCH_OMAP3
        select VIDEOBUF_GEN
        select VIDEOBUF_DMA_CONTIG
        select OMAP2_DSS
-       select OMAP2_VRAM
-       select OMAP2_VRFB
+       select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
+       select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB
        default n
        ---help---
          V4L2 Display driver support for OMAP2/3 based boards.
index b28788070ae123ce6d59338055e1462040a22658..fc410b438f7d6545b2d35ce19e9fb0cdf43e2333 100644 (file)
@@ -4,4 +4,5 @@
 
 # OMAP2/3 Display driver
 omap-vout-y := omap_vout.o omap_voutlib.o
+omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o
 obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o
index a647894d3a717a9307be0a0b1ad243012f7d25bf..b5ef36222440bab59f14d8978b099b0cbe0ca8d5 100644 (file)
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
 #include <linux/irq.h>
 #include <linux/videodev2.h>
-#include <linux/slab.h>
+#include <linux/dma-mapping.h>
 
 #include <media/videobuf-dma-contig.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 
 #include <plat/dma.h>
-#include <plat/vram.h>
 #include <plat/vrfb.h>
 #include <video/omapdss.h>
 
 #include "omap_voutlib.h"
 #include "omap_voutdef.h"
+#include "omap_vout_vrfb.h"
 
 MODULE_AUTHOR("Texas Instruments");
 MODULE_DESCRIPTION("OMAP Video for Linux Video out driver");
 MODULE_LICENSE("GPL");
 
-
 /* Driver Configuration macros */
 #define VOUT_NAME              "omap_vout"
 
@@ -65,31 +63,6 @@ enum omap_vout_channels {
        OMAP_VIDEO2,
 };
 
-enum dma_channel_state {
-       DMA_CHAN_NOT_ALLOTED,
-       DMA_CHAN_ALLOTED,
-};
-
-#define QQVGA_WIDTH            160
-#define QQVGA_HEIGHT           120
-
-/* Max Resolution supported by the driver */
-#define VID_MAX_WIDTH          1280    /* Largest width */
-#define VID_MAX_HEIGHT         720     /* Largest height */
-
-/* Mimimum requirement is 2x2 for DSS */
-#define VID_MIN_WIDTH          2
-#define VID_MIN_HEIGHT         2
-
-/* 2048 x 2048 is max res supported by OMAP display controller */
-#define MAX_PIXELS_PER_LINE     2048
-
-#define VRFB_TX_TIMEOUT         1000
-#define VRFB_NUM_BUFS          4
-
-/* Max buffer size tobe allocated during init */
-#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)
-
 static struct videobuf_queue_ops video_vbq_ops;
 /* Variables configurable through module params*/
 static u32 video1_numbuffers = 3;
@@ -171,84 +144,6 @@ static const struct v4l2_fmtdesc omap_formats[] = {
 
 #define NUM_OUTPUT_FORMATS (ARRAY_SIZE(omap_formats))
 
-/*
- * Allocate buffers
- */
-static unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
-{
-       u32 order, size;
-       unsigned long virt_addr, addr;
-
-       size = PAGE_ALIGN(buf_size);
-       order = get_order(size);
-       virt_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, order);
-       addr = virt_addr;
-
-       if (virt_addr) {
-               while (size > 0) {
-                       SetPageReserved(virt_to_page(addr));
-                       addr += PAGE_SIZE;
-                       size -= PAGE_SIZE;
-               }
-       }
-       *phys_addr = (u32) virt_to_phys((void *) virt_addr);
-       return virt_addr;
-}
-
-/*
- * Free buffers
- */
-static void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
-{
-       u32 order, size;
-       unsigned long addr = virtaddr;
-
-       size = PAGE_ALIGN(buf_size);
-       order = get_order(size);
-
-       while (size > 0) {
-               ClearPageReserved(virt_to_page(addr));
-               addr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       free_pages((unsigned long) virtaddr, order);
-}
-
-/*
- * Function for allocating video buffers
- */
-static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
-               unsigned int *count, int startindex)
-{
-       int i, j;
-
-       for (i = 0; i < *count; i++) {
-               if (!vout->smsshado_virt_addr[i]) {
-                       vout->smsshado_virt_addr[i] =
-                               omap_vout_alloc_buffer(vout->smsshado_size,
-                                               &vout->smsshado_phy_addr[i]);
-               }
-               if (!vout->smsshado_virt_addr[i] && startindex != -1) {
-                       if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex)
-                               break;
-               }
-               if (!vout->smsshado_virt_addr[i]) {
-                       for (j = 0; j < i; j++) {
-                               omap_vout_free_buffer(
-                                               vout->smsshado_virt_addr[j],
-                                               vout->smsshado_size);
-                               vout->smsshado_virt_addr[j] = 0;
-                               vout->smsshado_phy_addr[j] = 0;
-                       }
-                       *count = 0;
-                       return -ENOMEM;
-               }
-               memset((void *) vout->smsshado_virt_addr[i], 0,
-                               vout->smsshado_size);
-       }
-       return 0;
-}
-
 /*
  * Try format
  */
@@ -341,74 +236,10 @@ static u32 omap_vout_uservirt_to_phys(u32 virtp)
        return physp;
 }
 
-/*
- * Wakes up the application once the DMA transfer to VRFB space is completed.
- */
-static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
-{
-       struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
-
-       t->tx_status = 1;
-       wake_up_interruptible(&t->wait);
-}
-
-/*
- * Release the VRFB context once the module exits
- */
-static void omap_vout_release_vrfb(struct omap_vout_device *vout)
-{
-       int i;
-
-       for (i = 0; i < VRFB_NUM_BUFS; i++)
-               omap_vrfb_release_ctx(&vout->vrfb_context[i]);
-
-       if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
-               vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
-               omap_free_dma(vout->vrfb_dma_tx.dma_ch);
-       }
-}
-
-/*
- * Return true if rotation is 90 or 270
- */
-static inline int rotate_90_or_270(const struct omap_vout_device *vout)
-{
-       return (vout->rotation == dss_rotation_90_degree ||
-                       vout->rotation == dss_rotation_270_degree);
-}
-
-/*
- * Return true if rotation is enabled
- */
-static inline int rotation_enabled(const struct omap_vout_device *vout)
-{
-       return vout->rotation || vout->mirror;
-}
-
-/*
- * Reverse the rotation degree if mirroring is enabled
- */
-static inline int calc_rotation(const struct omap_vout_device *vout)
-{
-       if (!vout->mirror)
-               return vout->rotation;
-
-       switch (vout->rotation) {
-       case dss_rotation_90_degree:
-               return dss_rotation_270_degree;
-       case dss_rotation_270_degree:
-               return dss_rotation_90_degree;
-       case dss_rotation_180_degree:
-               return dss_rotation_0_degree;
-       default:
-               return dss_rotation_180_degree;
-       }
-}
-
 /*
  * Free the V4L2 buffers
  */
-static void omap_vout_free_buffers(struct omap_vout_device *vout)
+void omap_vout_free_buffers(struct omap_vout_device *vout)
 {
        int i, numbuffers;
 
@@ -424,52 +255,6 @@ static void omap_vout_free_buffers(struct omap_vout_device *vout)
        }
 }
 
-/*
- * Free VRFB buffers
- */
-static void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
-{
-       int j;
-
-       for (j = 0; j < VRFB_NUM_BUFS; j++) {
-               omap_vout_free_buffer(vout->smsshado_virt_addr[j],
-                               vout->smsshado_size);
-               vout->smsshado_virt_addr[j] = 0;
-               vout->smsshado_phy_addr[j] = 0;
-       }
-}
-
-/*
- * Allocate the buffers for the VRFB space.  Data is copied from V4L2
- * buffers to the VRFB buffers using the DMA engine.
- */
-static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
-                         unsigned int *count, unsigned int startindex)
-{
-       int i;
-       bool yuv_mode;
-
-       /* Allocate the VRFB buffers only if the buffers are not
-        * allocated during init time.
-        */
-       if ((rotation_enabled(vout)) && !vout->vrfb_static_allocation)
-               if (omap_vout_allocate_vrfb_buffers(vout, count, startindex))
-                       return -ENOMEM;
-
-       if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 ||
-                       vout->dss_mode == OMAP_DSS_COLOR_UYVY)
-               yuv_mode = true;
-       else
-               yuv_mode = false;
-
-       for (i = 0; i < *count; i++)
-               omap_vrfb_setup(&vout->vrfb_context[i],
-                               vout->smsshado_phy_addr[i], vout->pix.width,
-                               vout->pix.height, vout->bpp, yuv_mode);
-
-       return 0;
-}
-
 /*
  * Convert V4L2 rotation to DSS rotation
  *     V4L2 understand 0, 90, 180, 270.
@@ -499,124 +284,38 @@ static int v4l2_rot_to_dss_rot(int v4l2_rotation,
        return ret;
 }
 
-/*
- * Calculate the buffer offsets from which the streaming should
- * start. This offset calculation is mainly required because of
- * the VRFB 32 pixels alignment with rotation.
- */
 static int omap_vout_calculate_offset(struct omap_vout_device *vout)
 {
-       struct omap_overlay *ovl;
-       enum dss_rotation rotation;
        struct omapvideo_info *ovid;
-       bool mirroring = vout->mirror;
-       struct omap_dss_device *cur_display;
        struct v4l2_rect *crop = &vout->crop;
        struct v4l2_pix_format *pix = &vout->pix;
        int *cropped_offset = &vout->cropped_offset;
-       int vr_ps = 1, ps = 2, temp_ps = 2;
-       int offset = 0, ctop = 0, cleft = 0, line_length = 0;
+       int ps = 2, line_length = 0;
 
        ovid = &vout->vid_info;
-       ovl = ovid->overlays[0];
-       /* get the display device attached to the overlay */
-       if (!ovl->manager || !ovl->manager->device)
-               return -1;
 
-       cur_display = ovl->manager->device;
-       rotation = calc_rotation(vout);
+       if (ovid->rotation_type == VOUT_ROT_VRFB) {
+               omap_vout_calculate_vrfb_offset(vout);
+       } else {
+               vout->line_length = line_length = pix->width;
 
-       if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
-                       V4L2_PIX_FMT_UYVY == pix->pixelformat) {
-               if (rotation_enabled(vout)) {
-                       /*
-                        * ps    - Actual pixel size for YUYV/UYVY for
-                        *         VRFB/Mirroring is 4 bytes
-                        * vr_ps - Virtually pixel size for YUYV/UYVY is
-                        *         2 bytes
-                        */
+               if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
+                       V4L2_PIX_FMT_UYVY == pix->pixelformat)
+                       ps = 2;
+               else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat)
                        ps = 4;
-                       vr_ps = 2;
-               } else {
-                       ps = 2; /* otherwise the pixel size is 2 byte */
-               }
-       } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
-               ps = 4;
-       } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
-               ps = 3;
-       }
-       vout->ps = ps;
-       vout->vr_ps = vr_ps;
-
-       if (rotation_enabled(vout)) {
-               line_length = MAX_PIXELS_PER_LINE;
-               ctop = (pix->height - crop->height) - crop->top;
-               cleft = (pix->width - crop->width) - crop->left;
-       } else {
-               line_length = pix->width;
-       }
-       vout->line_length = line_length;
-       switch (rotation) {
-       case dss_rotation_90_degree:
-               offset = vout->vrfb_context[0].yoffset *
-                       vout->vrfb_context[0].bytespp;
-               temp_ps = ps / vr_ps;
-               if (mirroring == 0) {
-                       *cropped_offset = offset + line_length *
-                               temp_ps * cleft + crop->top * temp_ps;
-               } else {
-                       *cropped_offset = offset + line_length * temp_ps *
-                               cleft + crop->top * temp_ps + (line_length *
-                               ((crop->width / (vr_ps)) - 1) * ps);
-               }
-               break;
-       case dss_rotation_180_degree:
-               offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
-                       vout->vrfb_context[0].bytespp) +
-                       (vout->vrfb_context[0].xoffset *
-                       vout->vrfb_context[0].bytespp));
-               if (mirroring == 0) {
-                       *cropped_offset = offset + (line_length * ps * ctop) +
-                               (cleft / vr_ps) * ps;
+               else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat)
+                       ps = 3;
 
-               } else {
-                       *cropped_offset = offset + (line_length * ps * ctop) +
-                               (cleft / vr_ps) * ps + (line_length *
-                               (crop->height - 1) * ps);
-               }
-               break;
-       case dss_rotation_270_degree:
-               offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
-                       vout->vrfb_context[0].bytespp;
-               temp_ps = ps / vr_ps;
-               if (mirroring == 0) {
-                       *cropped_offset = offset + line_length *
-                           temp_ps * crop->left + ctop * ps;
-               } else {
-                       *cropped_offset = offset + line_length *
-                               temp_ps * crop->left + ctop * ps +
-                               (line_length * ((crop->width / vr_ps) - 1) *
-                                ps);
-               }
-               break;
-       case dss_rotation_0_degree:
-               if (mirroring == 0) {
-                       *cropped_offset = (line_length * ps) *
-                               crop->top + (crop->left / vr_ps) * ps;
-               } else {
-                       *cropped_offset = (line_length * ps) *
-                               crop->top + (crop->left / vr_ps) * ps +
-                               (line_length * (crop->height - 1) * ps);
-               }
-               break;
-       default:
-               *cropped_offset = (line_length * ps * crop->top) /
-                       vr_ps + (crop->left * ps) / vr_ps +
-                       ((crop->width / vr_ps) - 1) * ps;
-               break;
+               vout->ps = ps;
+
+               *cropped_offset = (line_length * ps) *
+                       crop->top + crop->left * ps;
        }
+
        v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s Offset:%x\n",
-                       __func__, *cropped_offset);
+                       __func__, vout->cropped_offset);
+
        return 0;
 }
 
@@ -664,7 +363,7 @@ static int video_mode_to_dss_mode(struct omap_vout_device *vout)
 /*
  * Setup the overlay
  */
-int omapvid_setup_overlay(struct omap_vout_device *vout,
+static int omapvid_setup_overlay(struct omap_vout_device *vout,
                struct omap_overlay *ovl, int posx, int posy, int outw,
                int outh, u32 addr)
 {
@@ -687,7 +386,7 @@ int omapvid_setup_overlay(struct omap_vout_device *vout,
        /* Setup the input plane parameters according to
         * rotation value selected.
         */
-       if (rotate_90_or_270(vout)) {
+       if (is_rotation_90_or_270(vout)) {
                cropheight = vout->crop.width;
                cropwidth = vout->crop.height;
                pixheight = vout->pix.width;
@@ -711,7 +410,7 @@ int omapvid_setup_overlay(struct omap_vout_device *vout,
        info.out_width = outw;
        info.out_height = outh;
        info.global_alpha = vout->win.global_alpha;
-       if (!rotation_enabled(vout)) {
+       if (!is_rotation_enabled(vout)) {
                info.rotation = 0;
                info.rotation_type = OMAP_DSS_ROT_DMA;
                info.screen_width = pixwidth;
@@ -744,7 +443,7 @@ setup_ovl_err:
 /*
  * Initialize the overlay structure
  */
-int omapvid_init(struct omap_vout_device *vout, u32 addr)
+static int omapvid_init(struct omap_vout_device *vout, u32 addr)
 {
        int ret = 0, i;
        struct v4l2_window *win;
@@ -809,7 +508,7 @@ omapvid_init_err:
 /*
  * Apply the changes set the go bit of DSS
  */
-int omapvid_apply_changes(struct omap_vout_device *vout)
+static int omapvid_apply_changes(struct omap_vout_device *vout)
 {
        int i;
        struct omap_overlay *ovl;
@@ -825,7 +524,7 @@ int omapvid_apply_changes(struct omap_vout_device *vout)
        return 0;
 }
 
-void omap_vout_isr(void *arg, unsigned int irqstatus)
+static void omap_vout_isr(void *arg, unsigned int irqstatus)
 {
        int ret;
        u32 addr, fid;
@@ -848,10 +547,20 @@ void omap_vout_isr(void *arg, unsigned int irqstatus)
 
        spin_lock(&vout->vbq_lock);
        do_gettimeofday(&timevalue);
-       if (cur_display->type == OMAP_DISPLAY_TYPE_DPI) {
-               if (!(irqstatus & DISPC_IRQ_VSYNC))
-                       goto vout_isr_err;
 
+       if (cur_display->type != OMAP_DISPLAY_TYPE_VENC) {
+               switch (cur_display->type) {
+               case OMAP_DISPLAY_TYPE_DPI:
+                       if (!(irqstatus & (DISPC_IRQ_VSYNC | DISPC_IRQ_VSYNC2)))
+                               goto vout_isr_err;
+                       break;
+               case OMAP_DISPLAY_TYPE_HDMI:
+                       if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN))
+                               goto vout_isr_err;
+                       break;
+               default:
+                       goto vout_isr_err;
+               }
                if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
                        vout->cur_frm->ts = timevalue;
                        vout->cur_frm->state = VIDEOBUF_DONE;
@@ -875,7 +584,7 @@ void omap_vout_isr(void *arg, unsigned int irqstatus)
                ret = omapvid_init(vout, addr);
                if (ret)
                        printk(KERN_ERR VOUT_NAME
-                                       "failed to set overlay info\n");
+                               "failed to set overlay info\n");
                /* Enable the pipeline and set the Go bit */
                ret = omapvid_apply_changes(vout);
                if (ret)
@@ -954,6 +663,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
        int startindex = 0, i, j;
        u32 phy_addr = 0, virt_addr = 0;
        struct omap_vout_device *vout = q->priv_data;
+       struct omapvideo_info *ovid = &vout->vid_info;
 
        if (!vout)
                return -EINVAL;
@@ -966,13 +676,10 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
        if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex)
                *count = startindex;
 
-       if ((rotation_enabled(vout)) && *count > VRFB_NUM_BUFS)
-               *count = VRFB_NUM_BUFS;
-
-       /* If rotation is enabled, allocate memory for VRFB space also */
-       if (rotation_enabled(vout))
+       if (ovid->rotation_type == VOUT_ROT_VRFB) {
                if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
                        return -ENOMEM;
+       }
 
        if (V4L2_MEMORY_MMAP != vout->memory)
                return 0;
@@ -996,8 +703,11 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
                virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
                                &phy_addr);
                if (!virt_addr) {
-                       if (!rotation_enabled(vout))
+                       if (ovid->rotation_type == VOUT_ROT_NONE) {
                                break;
+                       } else {
+                               if (!is_rotation_enabled(vout))
+                                       break;
                        /* Free the VRFB buffers if no space for V4L2 buffers */
                        for (j = i; j < *count; j++) {
                                omap_vout_free_buffer(
@@ -1005,6 +715,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
                                                vout->smsshado_size);
                                vout->smsshado_virt_addr[j] = 0;
                                vout->smsshado_phy_addr[j] = 0;
+                               }
                        }
                }
                vout->buf_virt_addr[i] = virt_addr;
@@ -1017,9 +728,9 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
 
 /*
  * Free the V4L2 buffers additionally allocated than default
- * number of buffers and free all the VRFB buffers
+ * number of buffers
  */
-static void omap_vout_free_allbuffers(struct omap_vout_device *vout)
+static void omap_vout_free_extra_buffers(struct omap_vout_device *vout)
 {
        int num_buffers = 0, i;
 
@@ -1034,20 +745,6 @@ static void omap_vout_free_allbuffers(struct omap_vout_device *vout)
                vout->buf_virt_addr[i] = 0;
                vout->buf_phy_addr[i] = 0;
        }
-       /* Free the VRFB buffers only if they are allocated
-        * during reqbufs.  Don't free if init time allocated
-        */
-       if (!vout->vrfb_static_allocation) {
-               for (i = 0; i < VRFB_NUM_BUFS; i++) {
-                       if (vout->smsshado_virt_addr[i]) {
-                               omap_vout_free_buffer(
-                                               vout->smsshado_virt_addr[i],
-                                               vout->smsshado_size);
-                               vout->smsshado_virt_addr[i] = 0;
-                               vout->smsshado_phy_addr[i] = 0;
-                       }
-               }
-       }
        vout->buffer_allocated = num_buffers;
 }
 
@@ -1059,16 +756,11 @@ static void omap_vout_free_allbuffers(struct omap_vout_device *vout)
  * buffer into VRFB memory space before giving it to the DSS.
  */
 static int omap_vout_buffer_prepare(struct videobuf_queue *q,
-                           struct videobuf_buffer *vb,
-                           enum v4l2_field field)
+                       struct videobuf_buffer *vb,
+                       enum v4l2_field field)
 {
-       dma_addr_t dmabuf;
-       struct vid_vrfb_dma *tx;
-       enum dss_rotation rotation;
        struct omap_vout_device *vout = q->priv_data;
-       u32 dest_frame_index = 0, src_element_index = 0;
-       u32 dest_element_index = 0, src_frame_index = 0;
-       u32 elem_count = 0, frame_count = 0, pixsize = 2;
+       struct omapvideo_info *ovid = &vout->vid_info;
 
        if (VIDEOBUF_NEEDS_INIT == vb->state) {
                vb->width = vout->pix.width;
@@ -1087,66 +779,24 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q,
                vout->queued_buf_addr[vb->i] = (u8 *)
                        omap_vout_uservirt_to_phys(vb->baddr);
        } else {
-               vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i];
-       }
+               u32 addr, dma_addr;
+               unsigned long size;
 
-       if (!rotation_enabled(vout))
-               return 0;
+               addr = (unsigned long) vout->buf_virt_addr[vb->i];
+               size = (unsigned long) vb->size;
 
-       dmabuf = vout->buf_phy_addr[vb->i];
-       /* If rotation is enabled, copy input buffer into VRFB
-        * memory space using DMA. We are copying input buffer
-        * into VRFB memory space of desired angle and DSS will
-        * read image VRFB memory for 0 degree angle
-        */
-       pixsize = vout->bpp * vout->vrfb_bpp;
-       /*
-        * DMA transfer in double index mode
-        */
+               dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr,
+                               size, DMA_TO_DEVICE);
+               if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr))
+                       v4l2_err(&vout->vid_dev->v4l2_dev, "dma_map_single failed\n");
 
-       /* Frame index */
-       dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
-                       (vout->pix.width * vout->bpp)) + 1;
-
-       /* Source and destination parameters */
-       src_element_index = 0;
-       src_frame_index = 0;
-       dest_element_index = 1;
-       /* Number of elements per frame */
-       elem_count = vout->pix.width * vout->bpp;
-       frame_count = vout->pix.height;
-       tx = &vout->vrfb_dma_tx;
-       tx->tx_status = 0;
-       omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32,
-                       (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT,
-                       tx->dev_id, 0x0);
-       /* src_port required only for OMAP1 */
-       omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
-                       dmabuf, src_element_index, src_frame_index);
-       /*set dma source burst mode for VRFB */
-       omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
-       rotation = calc_rotation(vout);
-
-       /* dest_port required only for OMAP1 */
-       omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
-                       vout->vrfb_context[vb->i].paddr[0], dest_element_index,
-                       dest_frame_index);
-       /*set dma dest burst mode for VRFB */
-       omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
-       omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
-
-       omap_start_dma(tx->dma_ch);
-       interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT);
-
-       if (tx->tx_status == 0) {
-               omap_stop_dma(tx->dma_ch);
-               return -EINVAL;
+               vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i];
        }
-       /* Store buffers physical address into an array. Addresses
-        * from this array will be used to configure DSS */
-       vout->queued_buf_addr[vb->i] = (u8 *)
-               vout->vrfb_context[vb->i].paddr[rotation];
-       return 0;
+
+       if (ovid->rotation_type == VOUT_ROT_VRFB)
+               return omap_vout_prepare_vrfb(vout, vb);
+       else
+               return 0;
 }
 
 /*
@@ -1298,7 +948,15 @@ static int omap_vout_release(struct file *file)
                                "Unable to apply changes\n");
 
        /* Free all buffers */
-       omap_vout_free_allbuffers(vout);
+       omap_vout_free_extra_buffers(vout);
+
+       /* Free the VRFB buffers only if they are allocated
+        * during reqbufs.  Don't free if init time allocated
+        */
+       if (ovid->rotation_type == VOUT_ROT_VRFB) {
+               if (!vout->vrfb_static_allocation)
+                       omap_vout_free_vrfb_buffers(vout);
+       }
        videobuf_mmap_free(q);
 
        /* Even if apply changes fails we should continue
@@ -1307,7 +965,7 @@ static int omap_vout_release(struct file *file)
                u32 mask = 0;
 
                mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
-                       DISPC_IRQ_EVSYNC_ODD;
+                       DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2;
                omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
                vout->streaming = 0;
 
@@ -1383,10 +1041,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
                        struct v4l2_fmtdesc *fmt)
 {
        int index = fmt->index;
-       enum v4l2_buf_type type = fmt->type;
 
-       fmt->index = index;
-       fmt->type = type;
        if (index >= NUM_OUTPUT_FORMATS)
                return -EINVAL;
 
@@ -1457,7 +1112,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
 
        /* We dont support RGB24-packed mode if vrfb rotation
         * is enabled*/
-       if ((rotation_enabled(vout)) &&
+       if ((is_rotation_enabled(vout)) &&
                        f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
                ret = -EINVAL;
                goto s_fmt_vid_out_exit;
@@ -1465,7 +1120,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
 
        /* get the framebuffer parameters */
 
-       if (rotate_90_or_270(vout)) {
+       if (is_rotation_90_or_270(vout)) {
                vout->fbuf.fmt.height = timing->x_res;
                vout->fbuf.fmt.width = timing->y_res;
        } else {
@@ -1555,10 +1210,7 @@ static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh,
                        struct v4l2_fmtdesc *fmt)
 {
        int index = fmt->index;
-       enum v4l2_buf_type type = fmt->type;
 
-       fmt->index = index;
-       fmt->type = type;
        if (index >= NUM_OUTPUT_FORMATS)
                return -EINVAL;
 
@@ -1645,7 +1297,7 @@ static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
        /* get the display device attached to the overlay */
        timing = &ovl->manager->device->panel.timings;
 
-       if (rotate_90_or_270(vout)) {
+       if (is_rotation_90_or_270(vout)) {
                vout->fbuf.fmt.height = timing->x_res;
                vout->fbuf.fmt.width = timing->y_res;
        } else {
@@ -1725,9 +1377,17 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
        switch (a->id) {
        case V4L2_CID_ROTATE:
        {
+               struct omapvideo_info *ovid;
                int rotation = a->value;
 
+               ovid = &vout->vid_info;
+
                mutex_lock(&vout->lock);
+               if (rotation && ovid->rotation_type == VOUT_ROT_NONE) {
+                       mutex_unlock(&vout->lock);
+                       ret = -ERANGE;
+                       break;
+               }
 
                if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
                        mutex_unlock(&vout->lock);
@@ -1783,6 +1443,11 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
                ovl = ovid->overlays[0];
 
                mutex_lock(&vout->lock);
+               if (mirror && ovid->rotation_type == VOUT_ROT_NONE) {
+                       mutex_unlock(&vout->lock);
+                       ret = -ERANGE;
+                       break;
+               }
 
                if (mirror  && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
                        mutex_unlock(&vout->lock);
@@ -1893,7 +1558,7 @@ static int vidioc_qbuf(struct file *file, void *fh,
                }
        }
 
-       if ((rotation_enabled(vout)) &&
+       if ((is_rotation_enabled(vout)) &&
                        vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
                v4l2_warn(&vout->vid_dev->v4l2_dev,
                                "DMA Channel not allocated for Rotation\n");
@@ -1908,15 +1573,28 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
        struct omap_vout_device *vout = fh;
        struct videobuf_queue *q = &vout->vbq;
 
+       int ret;
+       u32 addr;
+       unsigned long size;
+       struct videobuf_buffer *vb;
+
+       vb = q->bufs[b->index];
+
        if (!vout->streaming)
                return -EINVAL;
 
        if (file->f_flags & O_NONBLOCK)
                /* Call videobuf_dqbuf for non blocking mode */
-               return videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
+               ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
        else
                /* Call videobuf_dqbuf for  blocking mode */
-               return videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+               ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+
+       addr = (unsigned long) vout->buf_phy_addr[vb->i];
+       size = (unsigned long) vb->size;
+       dma_unmap_single(vout->vid_dev->v4l2_dev.dev,  addr,
+                               size, DMA_TO_DEVICE);
+       return ret;
 }
 
 static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
@@ -1965,7 +1643,8 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
        addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
                + vout->cropped_offset;
 
-       mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD;
+       mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
+               | DISPC_IRQ_VSYNC2;
 
        omap_dispc_register_isr(omap_vout_isr, vout, mask);
 
@@ -2015,7 +1694,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
                return -EINVAL;
 
        vout->streaming = 0;
-       mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD;
+       mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
+               | DISPC_IRQ_VSYNC2;
 
        omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
 
@@ -2228,7 +1908,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
        vout->mirror = 0;
        vout->control[2].id = V4L2_CID_HFLIP;
        vout->control[2].value = 0;
-       vout->vrfb_bpp = 2;
+       if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
+               vout->vrfb_bpp = 2;
 
        control[1].id = V4L2_CID_BG_COLOR;
        control[1].value = 0;
@@ -2260,17 +1941,15 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
                int vid_num)
 {
        u32 numbuffers;
-       int ret = 0, i, j;
-       int image_width, image_height;
-       struct video_device *vfd;
+       int ret = 0, i;
+       struct omapvideo_info *ovid;
        struct omap_vout_device *vout;
-       int static_vrfb_allocation = 0, vrfb_num_bufs = VRFB_NUM_BUFS;
        struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
        struct omap2video_device *vid_dev =
                container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
 
        vout = vid_dev->vouts[vid_num];
-       vfd = vout->vfd;
+       ovid = &vout->vid_info;
 
        numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
        vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
@@ -2287,66 +1966,16 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
                }
        }
 
-       for (i = 0; i < VRFB_NUM_BUFS; i++) {
-               if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
-                       dev_info(&pdev->dev, ": VRFB allocation failed\n");
-                       for (j = 0; j < i; j++)
-                               omap_vrfb_release_ctx(&vout->vrfb_context[j]);
-                       ret = -ENOMEM;
-                       goto free_buffers;
-               }
-       }
        vout->cropped_offset = 0;
 
-       /* Calculate VRFB memory size */
-       /* allocate for worst case size */
-       image_width = VID_MAX_WIDTH / TILE_SIZE;
-       if (VID_MAX_WIDTH % TILE_SIZE)
-               image_width++;
-
-       image_width = image_width * TILE_SIZE;
-       image_height = VID_MAX_HEIGHT / TILE_SIZE;
-
-       if (VID_MAX_HEIGHT % TILE_SIZE)
-               image_height++;
-
-       image_height = image_height * TILE_SIZE;
-       vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
-
-       /*
-        * Request and Initialize DMA, for DMA based VRFB transfer
-        */
-       vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
-       vout->vrfb_dma_tx.dma_ch = -1;
-       vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
-       ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
-                       omap_vout_vrfb_dma_tx_callback,
-                       (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
-       if (ret < 0) {
-               vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
-               dev_info(&pdev->dev, ": failed to allocate DMA Channel for"
-                               " video%d\n", vfd->minor);
-       }
-       init_waitqueue_head(&vout->vrfb_dma_tx.wait);
-
-       /* Allocate VRFB buffers if selected through bootargs */
-       static_vrfb_allocation = (vid_num == 0) ?
-               vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
-
-       /* statically allocated the VRFB buffer is done through
-          commands line aruments */
-       if (static_vrfb_allocation) {
-               if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) {
-                       ret =  -ENOMEM;
-                       goto release_vrfb_ctx;
-               }
-               vout->vrfb_static_allocation = 1;
+       if (ovid->rotation_type == VOUT_ROT_VRFB) {
+               int static_vrfb_allocation = (vid_num == 0) ?
+                       vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
+               ret = omap_vout_setup_vrfb_bufs(pdev, vid_num,
+                               static_vrfb_allocation);
        }
-       return 0;
 
-release_vrfb_ctx:
-       for (j = 0; j < VRFB_NUM_BUFS; j++)
-               omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+       return ret;
 
 free_buffers:
        for (i = 0; i < numbuffers; i++) {
@@ -2389,6 +2018,10 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
                vout->vid_info.num_overlays = 1;
                vout->vid_info.id = k + 1;
 
+               /* Set VRFB as rotation_type for omap2 and omap3 */
+               if (cpu_is_omap24xx() || cpu_is_omap34xx())
+                       vout->vid_info.rotation_type = VOUT_ROT_VRFB;
+
                /* Setup the default configuration for the video devices
                 */
                if (omap_vout_setup_video_data(vout) != 0) {
@@ -2422,7 +2055,8 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
                        goto success;
 
 error2:
-               omap_vout_release_vrfb(vout);
+               if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
+                       omap_vout_release_vrfb(vout);
                omap_vout_free_buffers(vout);
 error1:
                video_device_release(vfd);
@@ -2443,11 +2077,13 @@ success:
 static void omap_vout_cleanup_device(struct omap_vout_device *vout)
 {
        struct video_device *vfd;
+       struct omapvideo_info *ovid;
 
        if (!vout)
                return;
 
        vfd = vout->vfd;
+       ovid = &vout->vid_info;
        if (vfd) {
                if (!video_is_registered(vfd)) {
                        /*
@@ -2463,14 +2099,15 @@ static void omap_vout_cleanup_device(struct omap_vout_device *vout)
                        video_unregister_device(vfd);
                }
        }
-
-       omap_vout_release_vrfb(vout);
+       if (ovid->rotation_type == VOUT_ROT_VRFB) {
+               omap_vout_release_vrfb(vout);
+               /* Free the VRFB buffer if allocated
+                * init time
+                */
+               if (vout->vrfb_static_allocation)
+                       omap_vout_free_vrfb_buffers(vout);
+       }
        omap_vout_free_buffers(vout);
-       /* Free the VRFB buffer if allocated
-        * init time
-        */
-       if (vout->vrfb_static_allocation)
-               omap_vout_free_vrfb_buffers(vout);
 
        kfree(vout);
 }
diff --git a/drivers/media/video/omap/omap_vout_vrfb.c b/drivers/media/video/omap/omap_vout_vrfb.c
new file mode 100644 (file)
index 0000000..ebebcac
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * omap_vout_vrfb.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * 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/sched.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+
+#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-device.h>
+
+#include <plat/dma.h>
+#include <plat/vrfb.h>
+
+#include "omap_voutdef.h"
+#include "omap_voutlib.h"
+
+/*
+ * Function for allocating video buffers
+ */
+static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
+               unsigned int *count, int startindex)
+{
+       int i, j;
+
+       for (i = 0; i < *count; i++) {
+               if (!vout->smsshado_virt_addr[i]) {
+                       vout->smsshado_virt_addr[i] =
+                               omap_vout_alloc_buffer(vout->smsshado_size,
+                                               &vout->smsshado_phy_addr[i]);
+               }
+               if (!vout->smsshado_virt_addr[i] && startindex != -1) {
+                       if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex)
+                               break;
+               }
+               if (!vout->smsshado_virt_addr[i]) {
+                       for (j = 0; j < i; j++) {
+                               omap_vout_free_buffer(
+                                               vout->smsshado_virt_addr[j],
+                                               vout->smsshado_size);
+                               vout->smsshado_virt_addr[j] = 0;
+                               vout->smsshado_phy_addr[j] = 0;
+                       }
+                       *count = 0;
+                       return -ENOMEM;
+               }
+               memset((void *) vout->smsshado_virt_addr[i], 0,
+                               vout->smsshado_size);
+       }
+       return 0;
+}
+
+/*
+ * Wakes up the application once the DMA transfer to VRFB space is completed.
+ */
+static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
+{
+       struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
+
+       t->tx_status = 1;
+       wake_up_interruptible(&t->wait);
+}
+
+/*
+ * Free VRFB buffers
+ */
+void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
+{
+       int j;
+
+       for (j = 0; j < VRFB_NUM_BUFS; j++) {
+               omap_vout_free_buffer(vout->smsshado_virt_addr[j],
+                               vout->smsshado_size);
+               vout->smsshado_virt_addr[j] = 0;
+               vout->smsshado_phy_addr[j] = 0;
+       }
+}
+
+int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+                       u32 static_vrfb_allocation)
+{
+       int ret = 0, i, j;
+       struct omap_vout_device *vout;
+       struct video_device *vfd;
+       int image_width, image_height;
+       int vrfb_num_bufs = VRFB_NUM_BUFS;
+       struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+       struct omap2video_device *vid_dev =
+               container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
+
+       vout = vid_dev->vouts[vid_num];
+       vfd = vout->vfd;
+
+       for (i = 0; i < VRFB_NUM_BUFS; i++) {
+               if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
+                       dev_info(&pdev->dev, ": VRFB allocation failed\n");
+                       for (j = 0; j < i; j++)
+                               omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+                       ret = -ENOMEM;
+                       goto free_buffers;
+               }
+       }
+
+       /* Calculate VRFB memory size */
+       /* allocate for worst case size */
+       image_width = VID_MAX_WIDTH / TILE_SIZE;
+       if (VID_MAX_WIDTH % TILE_SIZE)
+               image_width++;
+
+       image_width = image_width * TILE_SIZE;
+       image_height = VID_MAX_HEIGHT / TILE_SIZE;
+
+       if (VID_MAX_HEIGHT % TILE_SIZE)
+               image_height++;
+
+       image_height = image_height * TILE_SIZE;
+       vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
+
+       /*
+        * Request and Initialize DMA, for DMA based VRFB transfer
+        */
+       vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
+       vout->vrfb_dma_tx.dma_ch = -1;
+       vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
+       ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
+                       omap_vout_vrfb_dma_tx_callback,
+                       (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
+       if (ret < 0) {
+               vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+               dev_info(&pdev->dev, ": failed to allocate DMA Channel for"
+                               " video%d\n", vfd->minor);
+       }
+       init_waitqueue_head(&vout->vrfb_dma_tx.wait);
+
+       /* statically allocated the VRFB buffer is done through
+          commands line aruments */
+       if (static_vrfb_allocation) {
+               if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) {
+                       ret =  -ENOMEM;
+                       goto release_vrfb_ctx;
+               }
+               vout->vrfb_static_allocation = 1;
+       }
+       return 0;
+
+release_vrfb_ctx:
+       for (j = 0; j < VRFB_NUM_BUFS; j++)
+               omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+free_buffers:
+       omap_vout_free_buffers(vout);
+
+       return ret;
+}
+
+/*
+ * Release the VRFB context once the module exits
+ */
+void omap_vout_release_vrfb(struct omap_vout_device *vout)
+{
+       int i;
+
+       for (i = 0; i < VRFB_NUM_BUFS; i++)
+               omap_vrfb_release_ctx(&vout->vrfb_context[i]);
+
+       if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
+               vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+               omap_free_dma(vout->vrfb_dma_tx.dma_ch);
+       }
+}
+
+/*
+ * Allocate the buffers for the VRFB space.  Data is copied from V4L2
+ * buffers to the VRFB buffers using the DMA engine.
+ */
+int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+                         unsigned int *count, unsigned int startindex)
+{
+       int i;
+       bool yuv_mode;
+
+       if (!is_rotation_enabled(vout))
+               return 0;
+
+       /* If rotation is enabled, allocate memory for VRFB space also */
+       *count = *count > VRFB_NUM_BUFS ? VRFB_NUM_BUFS : *count;
+
+       /* Allocate the VRFB buffers only if the buffers are not
+        * allocated during init time.
+        */
+       if (!vout->vrfb_static_allocation)
+               if (omap_vout_allocate_vrfb_buffers(vout, count, startindex))
+                       return -ENOMEM;
+
+       if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 ||
+                       vout->dss_mode == OMAP_DSS_COLOR_UYVY)
+               yuv_mode = true;
+       else
+               yuv_mode = false;
+
+       for (i = 0; i < *count; i++)
+               omap_vrfb_setup(&vout->vrfb_context[i],
+                               vout->smsshado_phy_addr[i], vout->pix.width,
+                               vout->pix.height, vout->bpp, yuv_mode);
+
+       return 0;
+}
+
+int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+                               struct videobuf_buffer *vb)
+{
+       dma_addr_t dmabuf;
+       struct vid_vrfb_dma *tx;
+       enum dss_rotation rotation;
+       u32 dest_frame_index = 0, src_element_index = 0;
+       u32 dest_element_index = 0, src_frame_index = 0;
+       u32 elem_count = 0, frame_count = 0, pixsize = 2;
+
+       if (!is_rotation_enabled(vout))
+               return 0;
+
+       dmabuf = vout->buf_phy_addr[vb->i];
+       /* If rotation is enabled, copy input buffer into VRFB
+        * memory space using DMA. We are copying input buffer
+        * into VRFB memory space of desired angle and DSS will
+        * read image VRFB memory for 0 degree angle
+        */
+       pixsize = vout->bpp * vout->vrfb_bpp;
+       /*
+        * DMA transfer in double index mode
+        */
+
+       /* Frame index */
+       dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
+                       (vout->pix.width * vout->bpp)) + 1;
+
+       /* Source and destination parameters */
+       src_element_index = 0;
+       src_frame_index = 0;
+       dest_element_index = 1;
+       /* Number of elements per frame */
+       elem_count = vout->pix.width * vout->bpp;
+       frame_count = vout->pix.height;
+       tx = &vout->vrfb_dma_tx;
+       tx->tx_status = 0;
+       omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32,
+                       (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT,
+                       tx->dev_id, 0x0);
+       /* src_port required only for OMAP1 */
+       omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
+                       dmabuf, src_element_index, src_frame_index);
+       /*set dma source burst mode for VRFB */
+       omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
+       rotation = calc_rotation(vout);
+
+       /* dest_port required only for OMAP1 */
+       omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
+                       vout->vrfb_context[vb->i].paddr[0], dest_element_index,
+                       dest_frame_index);
+       /*set dma dest burst mode for VRFB */
+       omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
+       omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
+
+       omap_start_dma(tx->dma_ch);
+       interruptible_sleep_on_timeout(&tx->wait, VRFB_TX_TIMEOUT);
+
+       if (tx->tx_status == 0) {
+               omap_stop_dma(tx->dma_ch);
+               return -EINVAL;
+       }
+       /* Store buffers physical address into an array. Addresses
+        * from this array will be used to configure DSS */
+       vout->queued_buf_addr[vb->i] = (u8 *)
+               vout->vrfb_context[vb->i].paddr[rotation];
+       return 0;
+}
+
+/*
+ * Calculate the buffer offsets from which the streaming should
+ * start. This offset calculation is mainly required because of
+ * the VRFB 32 pixels alignment with rotation.
+ */
+void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout)
+{
+       enum dss_rotation rotation;
+       bool mirroring = vout->mirror;
+       struct v4l2_rect *crop = &vout->crop;
+       struct v4l2_pix_format *pix = &vout->pix;
+       int *cropped_offset = &vout->cropped_offset;
+       int vr_ps = 1, ps = 2, temp_ps = 2;
+       int offset = 0, ctop = 0, cleft = 0, line_length = 0;
+
+       rotation = calc_rotation(vout);
+
+       if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
+                       V4L2_PIX_FMT_UYVY == pix->pixelformat) {
+               if (is_rotation_enabled(vout)) {
+                       /*
+                        * ps    - Actual pixel size for YUYV/UYVY for
+                        *         VRFB/Mirroring is 4 bytes
+                        * vr_ps - Virtually pixel size for YUYV/UYVY is
+                        *         2 bytes
+                        */
+                       ps = 4;
+                       vr_ps = 2;
+               } else {
+                       ps = 2; /* otherwise the pixel size is 2 byte */
+               }
+       } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
+               ps = 4;
+       } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
+               ps = 3;
+       }
+       vout->ps = ps;
+       vout->vr_ps = vr_ps;
+
+       if (is_rotation_enabled(vout)) {
+               line_length = MAX_PIXELS_PER_LINE;
+               ctop = (pix->height - crop->height) - crop->top;
+               cleft = (pix->width - crop->width) - crop->left;
+       } else {
+               line_length = pix->width;
+       }
+       vout->line_length = line_length;
+       switch (rotation) {
+       case dss_rotation_90_degree:
+               offset = vout->vrfb_context[0].yoffset *
+                       vout->vrfb_context[0].bytespp;
+               temp_ps = ps / vr_ps;
+               if (mirroring == 0) {
+                       *cropped_offset = offset + line_length *
+                               temp_ps * cleft + crop->top * temp_ps;
+               } else {
+                       *cropped_offset = offset + line_length * temp_ps *
+                               cleft + crop->top * temp_ps + (line_length *
+                               ((crop->width / (vr_ps)) - 1) * ps);
+               }
+               break;
+       case dss_rotation_180_degree:
+               offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
+                       vout->vrfb_context[0].bytespp) +
+                       (vout->vrfb_context[0].xoffset *
+                       vout->vrfb_context[0].bytespp));
+               if (mirroring == 0) {
+                       *cropped_offset = offset + (line_length * ps * ctop) +
+                               (cleft / vr_ps) * ps;
+
+               } else {
+                       *cropped_offset = offset + (line_length * ps * ctop) +
+                               (cleft / vr_ps) * ps + (line_length *
+                               (crop->height - 1) * ps);
+               }
+               break;
+       case dss_rotation_270_degree:
+               offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset *
+                       vout->vrfb_context[0].bytespp;
+               temp_ps = ps / vr_ps;
+               if (mirroring == 0) {
+                       *cropped_offset = offset + line_length *
+                           temp_ps * crop->left + ctop * ps;
+               } else {
+                       *cropped_offset = offset + line_length *
+                               temp_ps * crop->left + ctop * ps +
+                               (line_length * ((crop->width / vr_ps) - 1) *
+                                ps);
+               }
+               break;
+       case dss_rotation_0_degree:
+               if (mirroring == 0) {
+                       *cropped_offset = (line_length * ps) *
+                               crop->top + (crop->left / vr_ps) * ps;
+               } else {
+                       *cropped_offset = (line_length * ps) *
+                               crop->top + (crop->left / vr_ps) * ps +
+                               (line_length * (crop->height - 1) * ps);
+               }
+               break;
+       default:
+               *cropped_offset = (line_length * ps * crop->top) /
+                       vr_ps + (crop->left * ps) / vr_ps +
+                       ((crop->width / vr_ps) - 1) * ps;
+               break;
+       }
+}
diff --git a/drivers/media/video/omap/omap_vout_vrfb.h b/drivers/media/video/omap/omap_vout_vrfb.h
new file mode 100644 (file)
index 0000000..ffde741
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * omap_vout_vrfb.h
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * 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 OMAP_VOUT_VRFB_H
+#define OMAP_VOUT_VRFB_H
+
+#ifdef CONFIG_VIDEO_OMAP2_VOUT_VRFB
+void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout);
+int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+                       u32 static_vrfb_allocation);
+void omap_vout_release_vrfb(struct omap_vout_device *vout);
+int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+                       unsigned int *count, unsigned int startindex);
+int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+                       struct videobuf_buffer *vb);
+void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout);
+#else
+void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }
+int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
+                       u32 static_vrfb_allocation)
+               { return 0; }
+void omap_vout_release_vrfb(struct omap_vout_device *vout) { }
+int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+                       unsigned int *count, unsigned int startindex)
+               { return 0; }
+int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
+                       struct videobuf_buffer *vb)
+               { return 0; }
+void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { }
+#endif
+
+#endif
index 659497b849965e9c017ec5a0846291bb513337ca..d793501cafcc516710f319cd5a9d64acced3da49 100644 (file)
@@ -12,6 +12,7 @@
 #define OMAP_VOUTDEF_H
 
 #include <video/omapdss.h>
+#include <plat/vrfb.h>
 
 #define YUYV_BPP        2
 #define RGB565_BPP      2
 #define MAX_DISPLAYS   3
 #define MAX_MANAGERS   3
 
+#define QQVGA_WIDTH            160
+#define QQVGA_HEIGHT           120
+
+/* Max Resolution supported by the driver */
+#define VID_MAX_WIDTH          1280    /* Largest width */
+#define VID_MAX_HEIGHT         720     /* Largest height */
+
+/* Mimimum requirement is 2x2 for DSS */
+#define VID_MIN_WIDTH          2
+#define VID_MIN_HEIGHT         2
+
+/* 2048 x 2048 is max res supported by OMAP display controller */
+#define MAX_PIXELS_PER_LINE     2048
+
+#define VRFB_TX_TIMEOUT         1000
+#define VRFB_NUM_BUFS          4
+
+/* Max buffer size tobe allocated during init */
+#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)
+
+enum dma_channel_state {
+       DMA_CHAN_NOT_ALLOTED,
+       DMA_CHAN_ALLOTED,
+};
+
 /* Enum for Rotation
  * DSS understands rotation in 0, 1, 2, 3 context
  * while V4L2 driver understands it as 0, 90, 180, 270
@@ -37,6 +63,18 @@ enum dss_rotation {
        dss_rotation_180_degree = 2,
        dss_rotation_270_degree = 3,
 };
+
+/* Enum for choosing rotation type for vout
+ * DSS2 doesn't understand no rotation as an
+ * option while V4L2 driver doesn't support
+ * rotation in the case where VRFB is not built in
+ * the kernel
+ */
+enum vout_rotaion_type {
+       VOUT_ROT_NONE   = 0,
+       VOUT_ROT_VRFB   = 1,
+};
+
 /*
  * This structure is used to store the DMA transfer parameters
  * for VRFB hidden buffer
@@ -53,6 +91,7 @@ struct omapvideo_info {
        int id;
        int num_overlays;
        struct omap_overlay *overlays[MAX_OVLS];
+       enum vout_rotaion_type rotation_type;
 };
 
 struct omap2video_device {
@@ -144,4 +183,43 @@ struct omap_vout_device {
        int io_allowed;
 
 };
+
+/*
+ * Return true if rotation is 90 or 270
+ */
+static inline int is_rotation_90_or_270(const struct omap_vout_device *vout)
+{
+       return (vout->rotation == dss_rotation_90_degree ||
+                       vout->rotation == dss_rotation_270_degree);
+}
+
+/*
+ * Return true if rotation is enabled
+ */
+static inline int is_rotation_enabled(const struct omap_vout_device *vout)
+{
+       return vout->rotation || vout->mirror;
+}
+
+/*
+ * Reverse the rotation degree if mirroring is enabled
+ */
+static inline int calc_rotation(const struct omap_vout_device *vout)
+{
+       if (!vout->mirror)
+               return vout->rotation;
+
+       switch (vout->rotation) {
+       case dss_rotation_90_degree:
+               return dss_rotation_270_degree;
+       case dss_rotation_270_degree:
+               return dss_rotation_90_degree;
+       case dss_rotation_180_degree:
+               return dss_rotation_0_degree;
+       default:
+               return dss_rotation_180_degree;
+       }
+}
+
+void omap_vout_free_buffers(struct omap_vout_device *vout);
 #endif /* ifndef OMAP_VOUTDEF_H */
index 8ae74817a1105251d07fff196d63c26b8c736de5..115408b9274f0c40370321fd86daa5b576e5e5e7 100644 (file)
 #include <linux/types.h>
 #include <linux/videodev2.h>
 
+#include <linux/dma-mapping.h>
+
 #include <plat/cpu.h>
 
+#include "omap_voutlib.h"
+
 MODULE_AUTHOR("Texas Instruments");
 MODULE_DESCRIPTION("OMAP Video library");
 MODULE_LICENSE("GPL");
@@ -291,3 +295,45 @@ void omap_vout_new_format(struct v4l2_pix_format *pix,
 }
 EXPORT_SYMBOL_GPL(omap_vout_new_format);
 
+/*
+ * Allocate buffers
+ */
+unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
+{
+       u32 order, size;
+       unsigned long virt_addr, addr;
+
+       size = PAGE_ALIGN(buf_size);
+       order = get_order(size);
+       virt_addr = __get_free_pages(GFP_KERNEL, order);
+       addr = virt_addr;
+
+       if (virt_addr) {
+               while (size > 0) {
+                       SetPageReserved(virt_to_page(addr));
+                       addr += PAGE_SIZE;
+                       size -= PAGE_SIZE;
+               }
+       }
+       *phys_addr = (u32) virt_to_phys((void *) virt_addr);
+       return virt_addr;
+}
+
+/*
+ * Free buffers
+ */
+void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
+{
+       u32 order, size;
+       unsigned long addr = virtaddr;
+
+       size = PAGE_ALIGN(buf_size);
+       order = get_order(size);
+
+       while (size > 0) {
+               ClearPageReserved(virt_to_page(addr));
+               addr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       free_pages((unsigned long) virtaddr, order);
+}
index a60b16e8bfc3c0e07e7b9a94d298b361ed2089c3..e51750a597e3a426aabb0917c0b8920666b59d51 100644 (file)
 #ifndef OMAP_VOUTLIB_H
 #define OMAP_VOUTLIB_H
 
-extern void omap_vout_default_crop(struct v4l2_pix_format *pix,
+void omap_vout_default_crop(struct v4l2_pix_format *pix,
                struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop);
 
-extern int omap_vout_new_crop(struct v4l2_pix_format *pix,
+int omap_vout_new_crop(struct v4l2_pix_format *pix,
                struct v4l2_rect *crop, struct v4l2_window *win,
                struct v4l2_framebuffer *fbuf,
                const struct v4l2_rect *new_crop);
 
-extern int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
+int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
                struct v4l2_window *new_win);
 
-extern int omap_vout_new_window(struct v4l2_rect *crop,
+int omap_vout_new_window(struct v4l2_rect *crop,
                struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
                struct v4l2_window *new_win);
 
-extern void omap_vout_new_format(struct v4l2_pix_format *pix,
+void omap_vout_new_format(struct v4l2_pix_format *pix,
                struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
                struct v4l2_window *win);
+unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr);
+void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size);
 #endif /* #ifndef OMAP_VOUTLIB_H */
 
index e7cfc85b0a1c37bc2b76a1ac12c7db6ccd0dba0a..8a947e603aca0008e5c97a3396552d4e5316b899 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 
 #include <media/omap1_camera.h>
 #include <media/soc_camera.h>
@@ -38,7 +37,7 @@
 
 
 #define DRIVER_NAME            "omap1-camera"
-#define VERSION_CODE           KERNEL_VERSION(0, 0, 1)
+#define DRIVER_VERSION         "0.0.2"
 
 
 /*
@@ -208,7 +207,7 @@ static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        struct soc_camera_device *icd = vq->priv_data;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                        icd->current_fmt->host_fmt);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
 
        if (bytes_per_line < 0)
@@ -222,7 +221,7 @@ static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
                *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
 
-       dev_dbg(icd->dev.parent,
+       dev_dbg(icd->parent,
                        "%s: count=%d, size=%d\n", __func__, *count, *size);
 
        return 0;
@@ -241,7 +240,7 @@ static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf,
                videobuf_dma_contig_free(vq, vb);
        } else {
                struct soc_camera_device *icd = vq->priv_data;
-               struct device *dev = icd->dev.parent;
+               struct device *dev = icd->parent;
                struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
 
                videobuf_dma_unmap(dev, dma);
@@ -258,7 +257,7 @@ static int omap1_videobuf_prepare(struct videobuf_queue *vq,
        struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb);
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                        icd->current_fmt->host_fmt);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        int ret;
 
@@ -490,7 +489,7 @@ static void omap1_videobuf_queue(struct videobuf_queue *vq,
                                                struct videobuf_buffer *vb)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        struct omap1_cam_buf *buf;
        u32 mode;
@@ -519,7 +518,7 @@ static void omap1_videobuf_queue(struct videobuf_queue *vq,
        pcdev->active = buf;
        pcdev->ready = NULL;
 
-       dev_dbg(icd->dev.parent,
+       dev_dbg(icd->parent,
                "%s: capture not active, setup FIFO, start DMA\n", __func__);
        mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK;
        mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT;
@@ -543,8 +542,8 @@ static void omap1_videobuf_release(struct videobuf_queue *vq,
        struct omap1_cam_buf *buf =
                        container_of(vb, struct omap1_cam_buf, vb);
        struct soc_camera_device *icd = vq->priv_data;
-       struct device *dev = icd->dev.parent;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct omap1_cam_dev *pcdev = ici->priv;
 
        switch (vb->state) {
@@ -573,7 +572,7 @@ static void videobuf_done(struct omap1_cam_dev *pcdev,
 {
        struct omap1_cam_buf *buf = pcdev->active;
        struct videobuf_buffer *vb;
-       struct device *dev = pcdev->icd->dev.parent;
+       struct device *dev = pcdev->icd->parent;
 
        if (WARN_ON(!buf)) {
                suspend_capture(pcdev);
@@ -799,7 +798,7 @@ out:
 static irqreturn_t cam_isr(int irq, void *data)
 {
        struct omap1_cam_dev *pcdev = data;
-       struct device *dev = pcdev->icd->dev.parent;
+       struct device *dev = pcdev->icd->parent;
        struct omap1_cam_buf *buf = pcdev->active;
        u32 it_status;
        unsigned long flags;
@@ -909,7 +908,7 @@ static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset)
  */
 static int omap1_cam_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        u32 ctrlclock;
 
@@ -952,14 +951,14 @@ static int omap1_cam_add_device(struct soc_camera_device *icd)
 
        pcdev->icd = icd;
 
-       dev_dbg(icd->dev.parent, "OMAP1 Camera driver attached to camera %d\n",
+       dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n",
                        icd->devnum);
        return 0;
 }
 
 static void omap1_cam_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        u32 ctrlclock;
 
@@ -985,7 +984,7 @@ static void omap1_cam_remove_device(struct soc_camera_device *icd)
 
        pcdev->icd = NULL;
 
-       dev_dbg(icd->dev.parent,
+       dev_dbg(icd->parent,
                "OMAP1 Camera driver detached from camera %d\n", icd->devnum);
 }
 
@@ -1070,7 +1069,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
                unsigned int idx, struct soc_camera_format_xlate *xlate)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        int formats = 0, ret;
        enum v4l2_mbus_pixelcode code;
        const struct soc_mbus_pixelfmt *fmt;
@@ -1222,9 +1221,9 @@ static int omap1_cam_set_crop(struct soc_camera_device *icd,
        struct v4l2_rect *rect = &crop->c;
        const struct soc_camera_format_xlate *xlate = icd->current_fmt;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct omap1_cam_dev *pcdev = ici->priv;
-       struct device *dev = icd->dev.parent;
        struct v4l2_mbus_framefmt mf;
        int ret;
 
@@ -1270,8 +1269,8 @@ static int omap1_cam_set_fmt(struct soc_camera_device *icd,
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate;
-       struct device *dev = icd->dev.parent;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct omap1_cam_dev *pcdev = ici->priv;
        struct v4l2_pix_format *pix = &f->fmt.pix;
        struct v4l2_mbus_framefmt mf;
@@ -1326,7 +1325,7 @@ static int omap1_cam_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %#x not found\n",
+               dev_warn(icd->parent, "Format %#x not found\n",
                         pix->pixelformat);
                return -EINVAL;
        }
@@ -1362,7 +1361,7 @@ static int omap1_cam_mmap_mapper(struct videobuf_queue *q,
                                  struct vm_area_struct *vma)
 {
        struct soc_camera_device *icd = q->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
        int ret;
 
@@ -1377,17 +1376,17 @@ static int omap1_cam_mmap_mapper(struct videobuf_queue *q,
 static void omap1_cam_init_videobuf(struct videobuf_queue *q,
                                     struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct omap1_cam_dev *pcdev = ici->priv;
 
        if (!sg_mode)
                videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops,
-                               icd->dev.parent, &pcdev->lock,
+                               icd->parent, &pcdev->lock,
                                V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
                                sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
        else
                videobuf_queue_sg_init(q, &omap1_videobuf_ops,
-                               icd->dev.parent, &pcdev->lock,
+                               icd->parent, &pcdev->lock,
                                V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
                                sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
 
@@ -1431,7 +1430,6 @@ static int omap1_cam_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the friendly caller:-> */
        strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card));
-       cap->version = VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
@@ -1440,9 +1438,9 @@ static int omap1_cam_querycap(struct soc_camera_host *ici,
 static int omap1_cam_set_bus_param(struct soc_camera_device *icd,
                __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct omap1_cam_dev *pcdev = ici->priv;
-       struct device *dev = icd->dev.parent;
        const struct soc_camera_format_xlate *xlate;
        const struct soc_mbus_pixelfmt *fmt;
        unsigned long camera_flags, common_flags;
@@ -1718,4 +1716,5 @@ MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg");
 MODULE_DESCRIPTION("OMAP1 Camera Interface driver");
 MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
 MODULE_LICENSE("GPL v2");
+MODULE_LICENSE(DRIVER_VERSION);
 MODULE_ALIAS("platform:" DRIVER_NAME);
index 69b60ba5dd7a90830ad175b9b4f4dfde60a2dd3d..eb97bff7116f644bbe66c5bd570d6a059f1a852b 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/interrupt.h>
 #include <linux/videodev2.h>
 #include <linux/pci.h>         /* needed for videobufs */
-#include <linux/version.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/io.h>
@@ -43,7 +42,7 @@
 
 #include "omap24xxcam.h"
 
-#define OMAP24XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+#define OMAP24XXCAM_VERSION "0.0.1"
 
 #define RESET_TIMEOUT_NS 10000
 
@@ -309,11 +308,11 @@ static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb)
                        order--;
 
                /* try to allocate as many contiguous pages as possible */
-               page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+               page = alloc_pages(GFP_KERNEL, order);
                /* if allocation fails, try to allocate smaller amount */
                while (page == NULL) {
                        order--;
-                       page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+                       page = alloc_pages(GFP_KERNEL, order);
                        if (page == NULL && !order) {
                                err = -ENOMEM;
                                goto out;
@@ -993,7 +992,6 @@ static int vidioc_querycap(struct file *file, void *fh,
 
        strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
        strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
-       cap->version = OMAP24XXCAM_VERSION;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
@@ -1888,6 +1886,7 @@ static void __exit omap24xxcam_cleanup(void)
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
 MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(OMAP24XXCAM_VERSION);
 module_param(video_nr, int, 0);
 MODULE_PARM_DESC(video_nr,
                 "Minor number for video device (-1 ==> auto assign)");
index 94b6ed89e195866e8eb1af83950faea772c7d0c6..5cea2bbd7014d463aa2e3959af2a0491b0e82136 100644 (file)
@@ -2234,3 +2234,4 @@ module_exit(isp_cleanup);
 MODULE_AUTHOR("Nokia Corporation");
 MODULE_DESCRIPTION("TI OMAP3 ISP driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(ISP_VIDEO_DRIVER_VERSION);
index 2620c405f5e42cf0f37d7d724535b7e3593f6a1c..529e582ef94875488a8b8ff239183a2f9054ca42 100644 (file)
@@ -139,6 +139,10 @@ struct isp_reg {
  *             3 - CAMEXT[13:6] -> CAM[7:0]
  * @clk_pol: Pixel clock polarity
  *             0 - Non Inverted, 1 - Inverted
+ * @hs_pol: Horizontal synchronization polarity
+ *             0 - Active high, 1 - Active low
+ * @vs_pol: Vertical synchronization polarity
+ *             0 - Active high, 1 - Active low
  * @bridge: CCDC Bridge input control
  *             ISPCTRL_PAR_BRIDGE_DISABLE - Disable
  *             ISPCTRL_PAR_BRIDGE_LENDIAN - Little endian
@@ -147,6 +151,8 @@ struct isp_reg {
 struct isp_parallel_platform_data {
        unsigned int data_lane_shift:2;
        unsigned int clk_pol:1;
+       unsigned int hs_pol:1;
+       unsigned int vs_pol:1;
        unsigned int bridge:4;
 };
 
index 39d501bda6362c485468dcc714b1a7fe3375dd8c..9d3459de04b2b5f48b6ede40d53468de8ab8a155 100644 (file)
@@ -1148,6 +1148,8 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        omap3isp_configure_bridge(isp, ccdc->input, pdata, shift);
 
        ccdc->syncif.datsz = depth_out;
+       ccdc->syncif.hdpol = pdata ? pdata->hs_pol : 0;
+       ccdc->syncif.vdpol = pdata ? pdata->vs_pol : 0;
        ccdc_config_sync_if(ccdc, &ccdc->syncif);
 
        /* CCDC_PAD_SINK */
@@ -1691,7 +1693,7 @@ static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
        if (sub->type != V4L2_EVENT_OMAP3ISP_HS_VS)
                return -EINVAL;
 
-       return v4l2_event_subscribe(fh, sub);
+       return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS);
 }
 
 static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
@@ -2162,7 +2164,6 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
        sd->grp_id = 1 << 16;   /* group ID for isp subdevs */
        v4l2_set_subdevdata(sd, ccdc);
        sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
-       sd->nevents = OMAP3ISP_CCDC_NEVENTS;
 
        pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
        pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
@@ -2257,8 +2258,6 @@ int omap3isp_ccdc_init(struct isp_device *isp)
        ccdc->syncif.fldout = 0;
        ccdc->syncif.fldpol = 0;
        ccdc->syncif.fldstat = 0;
-       ccdc->syncif.hdpol = 0;
-       ccdc->syncif.vdpol = 0;
 
        ccdc->clamp.oblen = 0;
        ccdc->clamp.dcsubval = 0;
index 0e16cab8e0890a64d8b175f4ece607db63951c13..ec9e395f3339dd0ae3f567620574a37149df4eff 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
 
 #include "isp.h"
 #include "ispreg.h"
@@ -163,6 +164,9 @@ static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
        struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
        int i;
 
+       if (enable && ccp2->vdds_csib)
+               regulator_enable(ccp2->vdds_csib);
+
        /* Enable/Disable all the LCx channels */
        for (i = 0; i < CCP2_LCx_CHANS_NUM; i++)
                isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i),
@@ -186,6 +190,9 @@ static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
                                    ISPCCP2_LC01_IRQENABLE,
                                    ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ);
        }
+
+       if (!enable && ccp2->vdds_csib)
+               regulator_disable(ccp2->vdds_csib);
 }
 
 /*
@@ -1137,6 +1144,9 @@ error:
  */
 void omap3isp_ccp2_cleanup(struct isp_device *isp)
 {
+       struct isp_ccp2_device *ccp2 = &isp->isp_ccp2;
+
+       regulator_put(ccp2->vdds_csib);
 }
 
 /*
@@ -1151,14 +1161,27 @@ int omap3isp_ccp2_init(struct isp_device *isp)
 
        init_waitqueue_head(&ccp2->wait);
 
-       /* On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with
+       /*
+        * On the OMAP34xx the CSI1 receiver is operated in the CSIb IO
+        * complex, which is powered by vdds_csib power rail. Hence the
+        * request for the regulator.
+        *
+        * On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with
         * the CSI2c or CSI2a receivers. The PHY then needs to be explicitly
         * configured.
         *
         * TODO: Don't hardcode the usage of PHY1 (shared with CSI2c).
         */
-       if (isp->revision == ISP_REVISION_15_0)
+       if (isp->revision == ISP_REVISION_2_0) {
+               ccp2->vdds_csib = regulator_get(isp->dev, "vdds_csib");
+               if (IS_ERR(ccp2->vdds_csib)) {
+                       dev_dbg(isp->dev,
+                               "Could not get regulator vdds_csib\n");
+                       ccp2->vdds_csib = NULL;
+               }
+       } else if (isp->revision == ISP_REVISION_15_0) {
                ccp2->phy = &isp->isp_csiphy1;
+       }
 
        ret = ccp2_init_entities(ccp2);
        if (ret < 0)
index 5505a86a9a748a04e3b880950ceafab8896e306d..6674e9de2cd7aace79aedb9fbceb958fbb27bf63 100644 (file)
@@ -81,6 +81,7 @@ struct isp_ccp2_device {
        struct isp_interface_mem_config mem_cfg;
        struct isp_video video_in;
        struct isp_csiphy *phy;
+       struct regulator *vdds_csib;
        unsigned int error;
        enum isp_pipeline_stream_state state;
        wait_queue_head_t wait;
index b44cb685236ad45f55fedf0f532a912b8add65c5..808065948ac15c56bd07d05389933937c98ed4d8 100644 (file)
@@ -1032,7 +1032,6 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name,
        snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name);
        subdev->grp_id = 1 << 16;       /* group ID for isp subdevs */
        subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
-       subdev->nevents = STAT_NEVENTS;
        v4l2_set_subdevdata(subdev, stat);
 
        stat->pad.flags = MEDIA_PAD_FL_SINK;
@@ -1050,7 +1049,7 @@ int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
        if (sub->type != stat->event_type)
                return -EINVAL;
 
-       return v4l2_event_subscribe(fh, sub);
+       return v4l2_event_subscribe(fh, sub, STAT_NEVENTS);
 }
 
 int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
index 9cd8f1aa567b9ce2f094b00a4d42f7c6132dd92c..fd965adfd5970316d4d763af4e4e311d5401d54d 100644 (file)
@@ -695,7 +695,6 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
        strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver));
        strlcpy(cap->card, video->video.name, sizeof(cap->card));
        strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
-       cap->version = ISP_VIDEO_DRIVER_VERSION;
 
        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
index 911bea64e78a318deded72ceac1701e1b55e8b6b..53160aa24e6ed0d39c9a2b6c6c52b997c1179864 100644 (file)
@@ -27,7 +27,6 @@
 #define OMAP3_ISP_VIDEO_H
 
 #include <linux/v4l2-mediabus.h>
-#include <linux/version.h>
 #include <media/media-entity.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-fh.h>
@@ -35,7 +34,7 @@
 #include "ispqueue.h"
 
 #define ISP_VIDEO_DRIVER_NAME          "ispvideo"
-#define ISP_VIDEO_DRIVER_VERSION       KERNEL_VERSION(0, 0, 1)
+#define ISP_VIDEO_DRIVER_VERSION       "0.0.2"
 
 struct isp_device;
 struct isp_video;
index 0cea0cf36679966c4c4883481ccb71333fc4bdf7..9ce2fa037b947847024b268af4b1c7387eb009f9 100644 (file)
@@ -1031,16 +1031,9 @@ static int ov2640_video_probe(struct soc_camera_device *icd,
        const char *devname;
        int ret;
 
-       /*
-        * we must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface) {
-               dev_err(&client->dev, "Parent missing or invalid!\n");
-               ret = -ENODEV;
-               goto err;
-       }
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * check and show product ID and manufacturer ID
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c
new file mode 100644 (file)
index 0000000..349a4ad
--- /dev/null
@@ -0,0 +1,1012 @@
+/*
+ * Driver for OV5642 CMOS Image Sensor from Omnivision
+ *
+ * Copyright (C) 2011, Bastian Hecht <hechtb@gmail.com>
+ *
+ * Based on Sony IMX074 Camera Driver
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Based on Omnivision OV7670 Camera Driver
+ * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
+ *
+ * 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+
+/* OV5642 registers */
+#define REG_CHIP_ID_HIGH               0x300a
+#define REG_CHIP_ID_LOW                        0x300b
+
+#define REG_WINDOW_START_X_HIGH                0x3800
+#define REG_WINDOW_START_X_LOW         0x3801
+#define REG_WINDOW_START_Y_HIGH                0x3802
+#define REG_WINDOW_START_Y_LOW         0x3803
+#define REG_WINDOW_WIDTH_HIGH          0x3804
+#define REG_WINDOW_WIDTH_LOW           0x3805
+#define REG_WINDOW_HEIGHT_HIGH                 0x3806
+#define REG_WINDOW_HEIGHT_LOW          0x3807
+#define REG_OUT_WIDTH_HIGH             0x3808
+#define REG_OUT_WIDTH_LOW              0x3809
+#define REG_OUT_HEIGHT_HIGH            0x380a
+#define REG_OUT_HEIGHT_LOW             0x380b
+#define REG_OUT_TOTAL_WIDTH_HIGH       0x380c
+#define REG_OUT_TOTAL_WIDTH_LOW                0x380d
+#define REG_OUT_TOTAL_HEIGHT_HIGH      0x380e
+#define REG_OUT_TOTAL_HEIGHT_LOW       0x380f
+
+/*
+ * define standard resolution.
+ * Works currently only for up to 720 lines
+ * eg. 320x240, 640x480, 800x600, 1280x720, 2048x720
+ */
+
+#define OV5642_WIDTH           1280
+#define OV5642_HEIGHT          720
+#define OV5642_TOTAL_WIDTH     3200
+#define OV5642_TOTAL_HEIGHT    2000
+#define OV5642_SENSOR_SIZE_X   2592
+#define OV5642_SENSOR_SIZE_Y   1944
+
+struct regval_list {
+       u16 reg_num;
+       u8 value;
+};
+
+static struct regval_list ov5642_default_regs_init[] = {
+       { 0x3103, 0x93 },
+       { 0x3008, 0x82 },
+       { 0x3017, 0x7f },
+       { 0x3018, 0xfc },
+       { 0x3810, 0xc2 },
+       { 0x3615, 0xf0 },
+       { 0x3000, 0x0  },
+       { 0x3001, 0x0  },
+       { 0x3002, 0x0  },
+       { 0x3003, 0x0  },
+       { 0x3004, 0xff },
+       { 0x3030, 0x2b },
+       { 0x3011, 0x8  },
+       { 0x3010, 0x10 },
+       { 0x3604, 0x60 },
+       { 0x3622, 0x60 },
+       { 0x3621, 0x9  },
+       { 0x3709, 0x0  },
+       { 0x4000, 0x21 },
+       { 0x401d, 0x22 },
+       { 0x3600, 0x54 },
+       { 0x3605, 0x4  },
+       { 0x3606, 0x3f },
+       { 0x3c01, 0x80 },
+       { 0x300d, 0x22 },
+       { 0x3623, 0x22 },
+       { 0x5000, 0x4f },
+       { 0x5020, 0x4  },
+       { 0x5181, 0x79 },
+       { 0x5182, 0x0  },
+       { 0x5185, 0x22 },
+       { 0x5197, 0x1  },
+       { 0x5500, 0xa  },
+       { 0x5504, 0x0  },
+       { 0x5505, 0x7f },
+       { 0x5080, 0x8  },
+       { 0x300e, 0x18 },
+       { 0x4610, 0x0  },
+       { 0x471d, 0x5  },
+       { 0x4708, 0x6  },
+       { 0x370c, 0xa0 },
+       { 0x5687, 0x94 },
+       { 0x501f, 0x0  },
+       { 0x5000, 0x4f },
+       { 0x5001, 0xcf },
+       { 0x4300, 0x30 },
+       { 0x4300, 0x30 },
+       { 0x460b, 0x35 },
+       { 0x471d, 0x0  },
+       { 0x3002, 0xc  },
+       { 0x3002, 0x0  },
+       { 0x4713, 0x3  },
+       { 0x471c, 0x50 },
+       { 0x4721, 0x2  },
+       { 0x4402, 0x90 },
+       { 0x460c, 0x22 },
+       { 0x3815, 0x44 },
+       { 0x3503, 0x7  },
+       { 0x3501, 0x73 },
+       { 0x3502, 0x80 },
+       { 0x350b, 0x0  },
+       { 0x3818, 0xc8 },
+       { 0x3824, 0x11 },
+       { 0x3a00, 0x78 },
+       { 0x3a1a, 0x4  },
+       { 0x3a13, 0x30 },
+       { 0x3a18, 0x0  },
+       { 0x3a19, 0x7c },
+       { 0x3a08, 0x12 },
+       { 0x3a09, 0xc0 },
+       { 0x3a0a, 0xf  },
+       { 0x3a0b, 0xa0 },
+       { 0x350c, 0x7  },
+       { 0x350d, 0xd0 },
+       { 0x3a0d, 0x8  },
+       { 0x3a0e, 0x6  },
+       { 0x3500, 0x0  },
+       { 0x3501, 0x0  },
+       { 0x3502, 0x0  },
+       { 0x350a, 0x0  },
+       { 0x350b, 0x0  },
+       { 0x3503, 0x0  },
+       { 0x3a0f, 0x3c },
+       { 0x3a10, 0x32 },
+       { 0x3a1b, 0x3c },
+       { 0x3a1e, 0x32 },
+       { 0x3a11, 0x80 },
+       { 0x3a1f, 0x20 },
+       { 0x3030, 0x2b },
+       { 0x3a02, 0x0  },
+       { 0x3a03, 0x7d },
+       { 0x3a04, 0x0  },
+       { 0x3a14, 0x0  },
+       { 0x3a15, 0x7d },
+       { 0x3a16, 0x0  },
+       { 0x3a00, 0x78 },
+       { 0x3a08, 0x9  },
+       { 0x3a09, 0x60 },
+       { 0x3a0a, 0x7  },
+       { 0x3a0b, 0xd0 },
+       { 0x3a0d, 0x10 },
+       { 0x3a0e, 0xd  },
+       { 0x4407, 0x4  },
+       { 0x5193, 0x70 },
+       { 0x589b, 0x0  },
+       { 0x589a, 0xc0 },
+       { 0x401e, 0x20 },
+       { 0x4001, 0x42 },
+       { 0x401c, 0x6  },
+       { 0x3825, 0xac },
+       { 0x3827, 0xc  },
+       { 0x528a, 0x1  },
+       { 0x528b, 0x4  },
+       { 0x528c, 0x8  },
+       { 0x528d, 0x10 },
+       { 0x528e, 0x20 },
+       { 0x528f, 0x28 },
+       { 0x5290, 0x30 },
+       { 0x5292, 0x0  },
+       { 0x5293, 0x1  },
+       { 0x5294, 0x0  },
+       { 0x5295, 0x4  },
+       { 0x5296, 0x0  },
+       { 0x5297, 0x8  },
+       { 0x5298, 0x0  },
+       { 0x5299, 0x10 },
+       { 0x529a, 0x0  },
+       { 0x529b, 0x20 },
+       { 0x529c, 0x0  },
+       { 0x529d, 0x28 },
+       { 0x529e, 0x0  },
+       { 0x529f, 0x30 },
+       { 0x5282, 0x0  },
+       { 0x5300, 0x0  },
+       { 0x5301, 0x20 },
+       { 0x5302, 0x0  },
+       { 0x5303, 0x7c },
+       { 0x530c, 0x0  },
+       { 0x530d, 0xc  },
+       { 0x530e, 0x20 },
+       { 0x530f, 0x80 },
+       { 0x5310, 0x20 },
+       { 0x5311, 0x80 },
+       { 0x5308, 0x20 },
+       { 0x5309, 0x40 },
+       { 0x5304, 0x0  },
+       { 0x5305, 0x30 },
+       { 0x5306, 0x0  },
+       { 0x5307, 0x80 },
+       { 0x5314, 0x8  },
+       { 0x5315, 0x20 },
+       { 0x5319, 0x30 },
+       { 0x5316, 0x10 },
+       { 0x5317, 0x0  },
+       { 0x5318, 0x2  },
+       { 0x5380, 0x1  },
+       { 0x5381, 0x0  },
+       { 0x5382, 0x0  },
+       { 0x5383, 0x4e },
+       { 0x5384, 0x0  },
+       { 0x5385, 0xf  },
+       { 0x5386, 0x0  },
+       { 0x5387, 0x0  },
+       { 0x5388, 0x1  },
+       { 0x5389, 0x15 },
+       { 0x538a, 0x0  },
+       { 0x538b, 0x31 },
+       { 0x538c, 0x0  },
+       { 0x538d, 0x0  },
+       { 0x538e, 0x0  },
+       { 0x538f, 0xf  },
+       { 0x5390, 0x0  },
+       { 0x5391, 0xab },
+       { 0x5392, 0x0  },
+       { 0x5393, 0xa2 },
+       { 0x5394, 0x8  },
+       { 0x5480, 0x14 },
+       { 0x5481, 0x21 },
+       { 0x5482, 0x36 },
+       { 0x5483, 0x57 },
+       { 0x5484, 0x65 },
+       { 0x5485, 0x71 },
+       { 0x5486, 0x7d },
+       { 0x5487, 0x87 },
+       { 0x5488, 0x91 },
+       { 0x5489, 0x9a },
+       { 0x548a, 0xaa },
+       { 0x548b, 0xb8 },
+       { 0x548c, 0xcd },
+       { 0x548d, 0xdd },
+       { 0x548e, 0xea },
+       { 0x548f, 0x1d },
+       { 0x5490, 0x5  },
+       { 0x5491, 0x0  },
+       { 0x5492, 0x4  },
+       { 0x5493, 0x20 },
+       { 0x5494, 0x3  },
+       { 0x5495, 0x60 },
+       { 0x5496, 0x2  },
+       { 0x5497, 0xb8 },
+       { 0x5498, 0x2  },
+       { 0x5499, 0x86 },
+       { 0x549a, 0x2  },
+       { 0x549b, 0x5b },
+       { 0x549c, 0x2  },
+       { 0x549d, 0x3b },
+       { 0x549e, 0x2  },
+       { 0x549f, 0x1c },
+       { 0x54a0, 0x2  },
+       { 0x54a1, 0x4  },
+       { 0x54a2, 0x1  },
+       { 0x54a3, 0xed },
+       { 0x54a4, 0x1  },
+       { 0x54a5, 0xc5 },
+       { 0x54a6, 0x1  },
+       { 0x54a7, 0xa5 },
+       { 0x54a8, 0x1  },
+       { 0x54a9, 0x6c },
+       { 0x54aa, 0x1  },
+       { 0x54ab, 0x41 },
+       { 0x54ac, 0x1  },
+       { 0x54ad, 0x20 },
+       { 0x54ae, 0x0  },
+       { 0x54af, 0x16 },
+       { 0x54b0, 0x1  },
+       { 0x54b1, 0x20 },
+       { 0x54b2, 0x0  },
+       { 0x54b3, 0x10 },
+       { 0x54b4, 0x0  },
+       { 0x54b5, 0xf0 },
+       { 0x54b6, 0x0  },
+       { 0x54b7, 0xdf },
+       { 0x5402, 0x3f },
+       { 0x5403, 0x0  },
+       { 0x3406, 0x0  },
+       { 0x5180, 0xff },
+       { 0x5181, 0x52 },
+       { 0x5182, 0x11 },
+       { 0x5183, 0x14 },
+       { 0x5184, 0x25 },
+       { 0x5185, 0x24 },
+       { 0x5186, 0x6  },
+       { 0x5187, 0x8  },
+       { 0x5188, 0x8  },
+       { 0x5189, 0x7c },
+       { 0x518a, 0x60 },
+       { 0x518b, 0xb2 },
+       { 0x518c, 0xb2 },
+       { 0x518d, 0x44 },
+       { 0x518e, 0x3d },
+       { 0x518f, 0x58 },
+       { 0x5190, 0x46 },
+       { 0x5191, 0xf8 },
+       { 0x5192, 0x4  },
+       { 0x5193, 0x70 },
+       { 0x5194, 0xf0 },
+       { 0x5195, 0xf0 },
+       { 0x5196, 0x3  },
+       { 0x5197, 0x1  },
+       { 0x5198, 0x4  },
+       { 0x5199, 0x12 },
+       { 0x519a, 0x4  },
+       { 0x519b, 0x0  },
+       { 0x519c, 0x6  },
+       { 0x519d, 0x82 },
+       { 0x519e, 0x0  },
+       { 0x5025, 0x80 },
+       { 0x3a0f, 0x38 },
+       { 0x3a10, 0x30 },
+       { 0x3a1b, 0x3a },
+       { 0x3a1e, 0x2e },
+       { 0x3a11, 0x60 },
+       { 0x3a1f, 0x10 },
+       { 0x5688, 0xa6 },
+       { 0x5689, 0x6a },
+       { 0x568a, 0xea },
+       { 0x568b, 0xae },
+       { 0x568c, 0xa6 },
+       { 0x568d, 0x6a },
+       { 0x568e, 0x62 },
+       { 0x568f, 0x26 },
+       { 0x5583, 0x40 },
+       { 0x5584, 0x40 },
+       { 0x5580, 0x2  },
+       { 0x5000, 0xcf },
+       { 0x5800, 0x27 },
+       { 0x5801, 0x19 },
+       { 0x5802, 0x12 },
+       { 0x5803, 0xf  },
+       { 0x5804, 0x10 },
+       { 0x5805, 0x15 },
+       { 0x5806, 0x1e },
+       { 0x5807, 0x2f },
+       { 0x5808, 0x15 },
+       { 0x5809, 0xd  },
+       { 0x580a, 0xa  },
+       { 0x580b, 0x9  },
+       { 0x580c, 0xa  },
+       { 0x580d, 0xc  },
+       { 0x580e, 0x12 },
+       { 0x580f, 0x19 },
+       { 0x5810, 0xb  },
+       { 0x5811, 0x7  },
+       { 0x5812, 0x4  },
+       { 0x5813, 0x3  },
+       { 0x5814, 0x3  },
+       { 0x5815, 0x6  },
+       { 0x5816, 0xa  },
+       { 0x5817, 0xf  },
+       { 0x5818, 0xa  },
+       { 0x5819, 0x5  },
+       { 0x581a, 0x1  },
+       { 0x581b, 0x0  },
+       { 0x581c, 0x0  },
+       { 0x581d, 0x3  },
+       { 0x581e, 0x8  },
+       { 0x581f, 0xc  },
+       { 0x5820, 0xa  },
+       { 0x5821, 0x5  },
+       { 0x5822, 0x1  },
+       { 0x5823, 0x0  },
+       { 0x5824, 0x0  },
+       { 0x5825, 0x3  },
+       { 0x5826, 0x8  },
+       { 0x5827, 0xc  },
+       { 0x5828, 0xe  },
+       { 0x5829, 0x8  },
+       { 0x582a, 0x6  },
+       { 0x582b, 0x4  },
+       { 0x582c, 0x5  },
+       { 0x582d, 0x7  },
+       { 0x582e, 0xb  },
+       { 0x582f, 0x12 },
+       { 0x5830, 0x18 },
+       { 0x5831, 0x10 },
+       { 0x5832, 0xc  },
+       { 0x5833, 0xa  },
+       { 0x5834, 0xb  },
+       { 0x5835, 0xe  },
+       { 0x5836, 0x15 },
+       { 0x5837, 0x19 },
+       { 0x5838, 0x32 },
+       { 0x5839, 0x1f },
+       { 0x583a, 0x18 },
+       { 0x583b, 0x16 },
+       { 0x583c, 0x17 },
+       { 0x583d, 0x1e },
+       { 0x583e, 0x26 },
+       { 0x583f, 0x53 },
+       { 0x5840, 0x10 },
+       { 0x5841, 0xf  },
+       { 0x5842, 0xd  },
+       { 0x5843, 0xc  },
+       { 0x5844, 0xe  },
+       { 0x5845, 0x9  },
+       { 0x5846, 0x11 },
+       { 0x5847, 0x10 },
+       { 0x5848, 0x10 },
+       { 0x5849, 0x10 },
+       { 0x584a, 0x10 },
+       { 0x584b, 0xe  },
+       { 0x584c, 0x10 },
+       { 0x584d, 0x10 },
+       { 0x584e, 0x11 },
+       { 0x584f, 0x10 },
+       { 0x5850, 0xf  },
+       { 0x5851, 0xc  },
+       { 0x5852, 0xf  },
+       { 0x5853, 0x10 },
+       { 0x5854, 0x10 },
+       { 0x5855, 0xf  },
+       { 0x5856, 0xe  },
+       { 0x5857, 0xb  },
+       { 0x5858, 0x10 },
+       { 0x5859, 0xd  },
+       { 0x585a, 0xd  },
+       { 0x585b, 0xc  },
+       { 0x585c, 0xc  },
+       { 0x585d, 0xc  },
+       { 0x585e, 0xb  },
+       { 0x585f, 0xc  },
+       { 0x5860, 0xc  },
+       { 0x5861, 0xc  },
+       { 0x5862, 0xd  },
+       { 0x5863, 0x8  },
+       { 0x5864, 0x11 },
+       { 0x5865, 0x18 },
+       { 0x5866, 0x18 },
+       { 0x5867, 0x19 },
+       { 0x5868, 0x17 },
+       { 0x5869, 0x19 },
+       { 0x586a, 0x16 },
+       { 0x586b, 0x13 },
+       { 0x586c, 0x13 },
+       { 0x586d, 0x12 },
+       { 0x586e, 0x13 },
+       { 0x586f, 0x16 },
+       { 0x5870, 0x14 },
+       { 0x5871, 0x12 },
+       { 0x5872, 0x10 },
+       { 0x5873, 0x11 },
+       { 0x5874, 0x11 },
+       { 0x5875, 0x16 },
+       { 0x5876, 0x14 },
+       { 0x5877, 0x11 },
+       { 0x5878, 0x10 },
+       { 0x5879, 0xf  },
+       { 0x587a, 0x10 },
+       { 0x587b, 0x14 },
+       { 0x587c, 0x13 },
+       { 0x587d, 0x12 },
+       { 0x587e, 0x11 },
+       { 0x587f, 0x11 },
+       { 0x5880, 0x12 },
+       { 0x5881, 0x15 },
+       { 0x5882, 0x14 },
+       { 0x5883, 0x15 },
+       { 0x5884, 0x15 },
+       { 0x5885, 0x15 },
+       { 0x5886, 0x13 },
+       { 0x5887, 0x17 },
+       { 0x3710, 0x10 },
+       { 0x3632, 0x51 },
+       { 0x3702, 0x10 },
+       { 0x3703, 0xb2 },
+       { 0x3704, 0x18 },
+       { 0x370b, 0x40 },
+       { 0x370d, 0x3  },
+       { 0x3631, 0x1  },
+       { 0x3632, 0x52 },
+       { 0x3606, 0x24 },
+       { 0x3620, 0x96 },
+       { 0x5785, 0x7  },
+       { 0x3a13, 0x30 },
+       { 0x3600, 0x52 },
+       { 0x3604, 0x48 },
+       { 0x3606, 0x1b },
+       { 0x370d, 0xb  },
+       { 0x370f, 0xc0 },
+       { 0x3709, 0x1  },
+       { 0x3823, 0x0  },
+       { 0x5007, 0x0  },
+       { 0x5009, 0x0  },
+       { 0x5011, 0x0  },
+       { 0x5013, 0x0  },
+       { 0x519e, 0x0  },
+       { 0x5086, 0x0  },
+       { 0x5087, 0x0  },
+       { 0x5088, 0x0  },
+       { 0x5089, 0x0  },
+       { 0x302b, 0x0  },
+       { 0x3503, 0x7  },
+       { 0x3011, 0x8  },
+       { 0x350c, 0x2  },
+       { 0x350d, 0xe4 },
+       { 0x3621, 0xc9 },
+       { 0x370a, 0x81 },
+       { 0xffff, 0xff },
+};
+
+static struct regval_list ov5642_default_regs_finalise[] = {
+       { 0x3810, 0xc2 },
+       { 0x3818, 0xc9 },
+       { 0x381c, 0x10 },
+       { 0x381d, 0xa0 },
+       { 0x381e, 0x5  },
+       { 0x381f, 0xb0 },
+       { 0x3820, 0x0  },
+       { 0x3821, 0x0  },
+       { 0x3824, 0x11 },
+       { 0x3a08, 0x1b },
+       { 0x3a09, 0xc0 },
+       { 0x3a0a, 0x17 },
+       { 0x3a0b, 0x20 },
+       { 0x3a0d, 0x2  },
+       { 0x3a0e, 0x1  },
+       { 0x401c, 0x4  },
+       { 0x5682, 0x5  },
+       { 0x5683, 0x0  },
+       { 0x5686, 0x2  },
+       { 0x5687, 0xcc },
+       { 0x5001, 0x4f },
+       { 0x589b, 0x6  },
+       { 0x589a, 0xc5 },
+       { 0x3503, 0x0  },
+       { 0x460c, 0x20 },
+       { 0x460b, 0x37 },
+       { 0x471c, 0xd0 },
+       { 0x471d, 0x5  },
+       { 0x3815, 0x1  },
+       { 0x3818, 0xc1 },
+       { 0x501f, 0x0  },
+       { 0x5002, 0xe0 },
+       { 0x4300, 0x32 }, /* UYVY */
+       { 0x3002, 0x1c },
+       { 0x4800, 0x14 },
+       { 0x4801, 0xf  },
+       { 0x3007, 0x3b },
+       { 0x300e, 0x4  },
+       { 0x4803, 0x50 },
+       { 0x3815, 0x1  },
+       { 0x4713, 0x2  },
+       { 0x4842, 0x1  },
+       { 0x300f, 0xe  },
+       { 0x3003, 0x3  },
+       { 0x3003, 0x1  },
+       { 0xffff, 0xff },
+};
+
+struct ov5642_datafmt {
+       enum v4l2_mbus_pixelcode        code;
+       enum v4l2_colorspace            colorspace;
+};
+
+struct ov5642 {
+       struct v4l2_subdev              subdev;
+       const struct ov5642_datafmt     *fmt;
+};
+
+static const struct ov5642_datafmt ov5642_colour_fmts[] = {
+       {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static struct ov5642 *to_ov5642(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct ov5642, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5642_datafmt
+                       *ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ov5642_colour_fmts); i++)
+               if (ov5642_colour_fmts[i].code == code)
+                       return ov5642_colour_fmts + i;
+
+       return NULL;
+}
+
+static int reg_read(struct i2c_client *client, u16 reg, u8 *val)
+{
+       int ret;
+       /* We have 16-bit i2c addresses - care for endianess */
+       unsigned char data[2] = { reg >> 8, reg & 0xff };
+
+       ret = i2c_master_send(client, data, 2);
+       if (ret < 2) {
+               dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
+                       __func__, reg);
+               return ret < 0 ? ret : -EIO;
+       }
+
+       ret = i2c_master_recv(client, val, 1);
+       if (ret < 1) {
+               dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
+                               __func__, reg);
+               return ret < 0 ? ret : -EIO;
+       }
+       return 0;
+}
+
+static int reg_write(struct i2c_client *client, u16 reg, u8 val)
+{
+       int ret;
+       unsigned char data[3] = { reg >> 8, reg & 0xff, val };
+
+       ret = i2c_master_send(client, data, 3);
+       if (ret < 3) {
+               dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
+                       __func__, reg);
+               return ret < 0 ? ret : -EIO;
+       }
+
+       return 0;
+}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u8 val;
+
+       if (reg->reg & ~0xffff)
+               return -EINVAL;
+
+       reg->size = 1;
+
+       ret = reg_read(client, reg->reg, &val);
+       if (!ret)
+               reg->val = (__u64)val;
+
+       return ret;
+}
+
+static int ov5642_set_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg & ~0xffff || reg->val & ~0xff)
+               return -EINVAL;
+
+       return reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov5642_write_array(struct i2c_client *client,
+                               struct regval_list *vals)
+{
+       while (vals->reg_num != 0xffff || vals->value != 0xff) {
+               int ret = reg_write(client, vals->reg_num, vals->value);
+               if (ret < 0)
+                       return ret;
+               vals++;
+       }
+       dev_dbg(&client->dev, "Register list loaded\n");
+       return 0;
+}
+
+static int ov5642_set_resolution(struct i2c_client *client)
+{
+       int ret;
+       u8 start_x_high = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) >> 8;
+       u8 start_x_low  = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) & 0xff;
+       u8 start_y_high = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) >> 8;
+       u8 start_y_low  = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) & 0xff;
+
+       u8 width_high   = OV5642_WIDTH  >> 8;
+       u8 width_low    = OV5642_WIDTH  & 0xff;
+       u8 height_high  = OV5642_HEIGHT >> 8;
+       u8 height_low   = OV5642_HEIGHT & 0xff;
+
+       u8 total_width_high  = OV5642_TOTAL_WIDTH  >> 8;
+       u8 total_width_low   = OV5642_TOTAL_WIDTH  & 0xff;
+       u8 total_height_high = OV5642_TOTAL_HEIGHT >> 8;
+       u8 total_height_low  = OV5642_TOTAL_HEIGHT & 0xff;
+
+       ret = reg_write(client, REG_WINDOW_START_X_HIGH, start_x_high);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_START_X_LOW, start_x_low);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_START_Y_HIGH, start_y_high);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_START_Y_LOW, start_y_low);
+
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_WIDTH_HIGH, width_high);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_WIDTH_LOW , width_low);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_HEIGHT_HIGH, height_high);
+       if (!ret)
+               ret = reg_write(client, REG_WINDOW_HEIGHT_LOW,  height_low);
+
+       if (!ret)
+               ret = reg_write(client, REG_OUT_WIDTH_HIGH, width_high);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_WIDTH_LOW , width_low);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_HEIGHT_HIGH, height_high);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_HEIGHT_LOW,  height_low);
+
+       if (!ret)
+               ret = reg_write(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width_high);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_TOTAL_WIDTH_LOW, total_width_low);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height_high);
+       if (!ret)
+               ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_LOW,  total_height_low);
+
+       return ret;
+}
+
+static int ov5642_try_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_mbus_framefmt *mf)
+{
+       const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code);
+
+       dev_dbg(sd->v4l2_dev->dev, "%s(%u) width: %u heigth: %u\n",
+                       __func__, mf->code, mf->width, mf->height);
+
+       if (!fmt) {
+               mf->code        = ov5642_colour_fmts[0].code;
+               mf->colorspace  = ov5642_colour_fmts[0].colorspace;
+       }
+
+       mf->width       = OV5642_WIDTH;
+       mf->height      = OV5642_HEIGHT;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int ov5642_s_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5642 *priv = to_ov5642(client);
+
+       dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+       /* MIPI CSI could have changed the format, double-check */
+       if (!ov5642_find_datafmt(mf->code))
+               return -EINVAL;
+
+       ov5642_try_fmt(sd, mf);
+
+       priv->fmt = ov5642_find_datafmt(mf->code);
+
+       ov5642_write_array(client, ov5642_default_regs_init);
+       ov5642_set_resolution(client);
+       ov5642_write_array(client, ov5642_default_regs_finalise);
+
+       return 0;
+}
+
+static int ov5642_g_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5642 *priv = to_ov5642(client);
+
+       const struct ov5642_datafmt *fmt = priv->fmt;
+
+       mf->code        = fmt->code;
+       mf->colorspace  = fmt->colorspace;
+       mf->width       = OV5642_WIDTH;
+       mf->height      = OV5642_HEIGHT;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int ov5642_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                          enum v4l2_mbus_pixelcode *code)
+{
+       if (index >= ARRAY_SIZE(ov5642_colour_fmts))
+               return -EINVAL;
+
+       *code = ov5642_colour_fmts[index].code;
+       return 0;
+}
+
+static int ov5642_g_chip_ident(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_chip_ident *id)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+               return -EINVAL;
+
+       if (id->match.addr != client->addr)
+               return -ENODEV;
+
+       id->ident       = V4L2_IDENT_OV5642;
+       id->revision    = 0;
+
+       return 0;
+}
+
+static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+       struct v4l2_rect *rect = &a->c;
+
+       a->type         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       rect->top       = 0;
+       rect->left      = 0;
+       rect->width     = OV5642_WIDTH;
+       rect->height    = OV5642_HEIGHT;
+
+       return 0;
+}
+
+static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+       a->bounds.left                  = 0;
+       a->bounds.top                   = 0;
+       a->bounds.width                 = OV5642_WIDTH;
+       a->bounds.height                = OV5642_HEIGHT;
+       a->defrect                      = a->bounds;
+       a->type                         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a->pixelaspect.numerator        = 1;
+       a->pixelaspect.denominator      = 1;
+
+       return 0;
+}
+
+static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = {
+       .s_mbus_fmt     = ov5642_s_fmt,
+       .g_mbus_fmt     = ov5642_g_fmt,
+       .try_mbus_fmt   = ov5642_try_fmt,
+       .enum_mbus_fmt  = ov5642_enum_fmt,
+       .g_crop         = ov5642_g_crop,
+       .cropcap        = ov5642_cropcap,
+};
+
+static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = {
+       .g_chip_ident   = ov5642_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register     = ov5642_get_register,
+       .s_register     = ov5642_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov5642_subdev_ops = {
+       .core   = &ov5642_subdev_core_ops,
+       .video  = &ov5642_subdev_video_ops,
+};
+
+/*
+ * We have to provide soc-camera operations, but we don't have anything to say
+ * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param
+ */
+static unsigned long soc_ov5642_query_bus_param(struct soc_camera_device *icd)
+{
+       return 0;
+}
+
+static int soc_ov5642_set_bus_param(struct soc_camera_device *icd,
+                                unsigned long flags)
+{
+       return -EINVAL;
+}
+
+static struct soc_camera_ops soc_ov5642_ops = {
+       .query_bus_param        = soc_ov5642_query_bus_param,
+       .set_bus_param          = soc_ov5642_set_bus_param,
+};
+
+static int ov5642_video_probe(struct soc_camera_device *icd,
+                             struct i2c_client *client)
+{
+       int ret;
+       u8 id_high, id_low;
+       u16 id;
+
+       /* Read sensor Model ID */
+       ret = reg_read(client, REG_CHIP_ID_HIGH, &id_high);
+       if (ret < 0)
+               return ret;
+
+       id = id_high << 8;
+
+       ret = reg_read(client, REG_CHIP_ID_LOW, &id_low);
+       if (ret < 0)
+               return ret;
+
+       id |= id_low;
+
+       dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
+
+       if (id != 0x5642)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int ov5642_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct ov5642 *priv;
+       struct soc_camera_device *icd = client->dev.platform_data;
+       struct soc_camera_link *icl;
+       int ret;
+
+       if (!icd) {
+               dev_err(&client->dev, "OV5642: missing soc-camera data!\n");
+               return -EINVAL;
+       }
+
+       icl = to_soc_camera_link(icd);
+       if (!icl) {
+               dev_err(&client->dev, "OV5642: missing platform data!\n");
+               return -EINVAL;
+       }
+
+       priv = kzalloc(sizeof(struct ov5642), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops);
+
+       icd->ops        = &soc_ov5642_ops;
+       priv->fmt       = &ov5642_colour_fmts[0];
+
+       ret = ov5642_video_probe(icd, client);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       icd->ops = NULL;
+       kfree(priv);
+       return ret;
+}
+
+static int ov5642_remove(struct i2c_client *client)
+{
+       struct ov5642 *priv = to_ov5642(client);
+       struct soc_camera_device *icd = client->dev.platform_data;
+       struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+       icd->ops = NULL;
+       if (icl->free_bus)
+               icl->free_bus(icl);
+       kfree(priv);
+
+       return 0;
+}
+
+static const struct i2c_device_id ov5642_id[] = {
+       { "ov5642", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ov5642_id);
+
+static struct i2c_driver ov5642_i2c_driver = {
+       .driver = {
+               .name = "ov5642",
+       },
+       .probe          = ov5642_probe,
+       .remove         = ov5642_remove,
+       .id_table       = ov5642_id,
+};
+
+static int __init ov5642_mod_init(void)
+{
+       return i2c_add_driver(&ov5642_i2c_driver);
+}
+
+static void __exit ov5642_mod_exit(void)
+{
+       i2c_del_driver(&ov5642_i2c_driver);
+}
+
+module_init(ov5642_mod_init);
+module_exit(ov5642_mod_exit);
+
+MODULE_DESCRIPTION("Omnivision OV5642 Camera driver");
+MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
+MODULE_LICENSE("GPL v2");
index d4e7c11553c3b427ee12e99631f2a65a224c9bfc..8aa05853128098732c6090421a1bba38e1c8315a 100644 (file)
@@ -19,8 +19,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-mediabus.h>
-
-#include "ov7670.h"
+#include <media/ov7670.h>
 
 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
 MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
diff --git a/drivers/media/video/ov7670.h b/drivers/media/video/ov7670.h
deleted file mode 100644 (file)
index b133bc1..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * A V4L2 driver for OmniVision OV7670 cameras.
- *
- * Copyright 2010 One Laptop Per Child
- *
- * This file may be distributed under the terms of the GNU General
- * Public License, version 2.
- */
-
-#ifndef __OV7670_H
-#define __OV7670_H
-
-struct ov7670_config {
-       int min_width;                  /* Filter out smaller sizes */
-       int min_height;                 /* Filter out smaller sizes */
-       int clock_speed;                /* External clock speed (MHz) */
-       bool use_smbus;                 /* Use smbus I/O instead of I2C */
-};
-
-#endif
index 48895ef863ff5da1ccddc3e5bc60f9af8f8f2e7c..397870f076c112d2f461cfeeb5222bf32a485b7a 100644 (file)
@@ -1032,13 +1032,9 @@ static int ov772x_video_probe(struct soc_camera_device *icd,
        u8                  pid, ver;
        const char         *devname;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * check and show product ID and manufacturer ID
index 5173ac449dd82c4b9c764c737cf20a328b53a01b..3681a6ff0815c4cddb5238a2e9230639ccfbdae4 100644 (file)
@@ -657,16 +657,9 @@ static int ov9640_video_probe(struct soc_camera_device *icd,
        const char      *devname;
        int             ret = 0;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface) {
-               dev_err(&client->dev, "Parent missing or invalid!\n");
-               ret = -ENODEV;
-               goto err;
-       }
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * check and show product ID and manufacturer ID
index 4d4ee4faca69737d5627f54abac0a432197bb5dd..edd1ffcca30b716e71df5ba2268ad9a4c44bb01a 100644 (file)
 #define OV9740_Y_ADDR_START_LO         0x0347
 #define OV9740_X_ADDR_END_HI           0x0348
 #define OV9740_X_ADDR_END_LO           0x0349
-#define OV9740_Y_ADDR_END_HI           0x034A
-#define OV9740_Y_ADDR_END_LO           0x034B
-#define OV9740_X_OUTPUT_SIZE_HI                0x034C
-#define OV9740_X_OUTPUT_SIZE_LO                0x034D
-#define OV9740_Y_OUTPUT_SIZE_HI                0x034E
-#define OV9740_Y_OUTPUT_SIZE_LO                0x034F
+#define OV9740_Y_ADDR_END_HI           0x034a
+#define OV9740_Y_ADDR_END_LO           0x034b
+#define OV9740_X_OUTPUT_SIZE_HI                0x034c
+#define OV9740_X_OUTPUT_SIZE_LO                0x034d
+#define OV9740_Y_OUTPUT_SIZE_HI                0x034e
+#define OV9740_Y_OUTPUT_SIZE_LO                0x034f
 
 /* IO Control Registers */
 #define OV9740_IO_CREL00               0x3002
@@ -68,6 +68,7 @@
 #define OV9740_ANALOG_CTRL04           0x3604
 #define OV9740_ANALOG_CTRL10           0x3610
 #define OV9740_ANALOG_CTRL12           0x3612
+#define OV9740_ANALOG_CTRL15           0x3615
 #define OV9740_ANALOG_CTRL20           0x3620
 #define OV9740_ANALOG_CTRL21           0x3621
 #define OV9740_ANALOG_CTRL22           0x3622
 #define OV9740_TIMING_CTRL35           0x3835
 
 /* Banding Filter */
-#define OV9740_AEC_MAXEXPO_60_H                0x3A02
-#define OV9740_AEC_MAXEXPO_60_L                0x3A03
-#define OV9740_AEC_B50_STEP_HI         0x3A08
-#define OV9740_AEC_B50_STEP_LO         0x3A09
-#define OV9740_AEC_B60_STEP_HI         0x3A0A
-#define OV9740_AEC_B60_STEP_LO         0x3A0B
-#define OV9740_AEC_CTRL0D              0x3A0D
-#define OV9740_AEC_CTRL0E              0x3A0E
-#define OV9740_AEC_MAXEXPO_50_H                0x3A14
-#define OV9740_AEC_MAXEXPO_50_L                0x3A15
+#define OV9740_AEC_MAXEXPO_60_H                0x3a02
+#define OV9740_AEC_MAXEXPO_60_L                0x3a03
+#define OV9740_AEC_B50_STEP_HI         0x3a08
+#define OV9740_AEC_B50_STEP_LO         0x3a09
+#define OV9740_AEC_B60_STEP_HI         0x3a0a
+#define OV9740_AEC_B60_STEP_LO         0x3a0b
+#define OV9740_AEC_CTRL0D              0x3a0d
+#define OV9740_AEC_CTRL0E              0x3a0e
+#define OV9740_AEC_MAXEXPO_50_H                0x3a14
+#define OV9740_AEC_MAXEXPO_50_L                0x3a15
 
 /* AEC/AGC Control */
 #define OV9740_AEC_ENABLE              0x3503
-#define OV9740_GAIN_CEILING_01         0x3A18
-#define OV9740_GAIN_CEILING_02         0x3A19
-#define OV9740_AEC_HI_THRESHOLD                0x3A11
-#define OV9740_AEC_3A1A                        0x3A1A
-#define OV9740_AEC_CTRL1B_WPT2         0x3A1B
-#define OV9740_AEC_CTRL0F_WPT          0x3A0F
-#define OV9740_AEC_CTRL10_BPT          0x3A10
-#define OV9740_AEC_CTRL1E_BPT2         0x3A1E
-#define OV9740_AEC_LO_THRESHOLD                0x3A1F
+#define OV9740_GAIN_CEILING_01         0x3a18
+#define OV9740_GAIN_CEILING_02         0x3a19
+#define OV9740_AEC_HI_THRESHOLD                0x3a11
+#define OV9740_AEC_3A1A                        0x3a1a
+#define OV9740_AEC_CTRL1B_WPT2         0x3a1b
+#define OV9740_AEC_CTRL0F_WPT          0x3a0f
+#define OV9740_AEC_CTRL10_BPT          0x3a10
+#define OV9740_AEC_CTRL1E_BPT2         0x3a1e
+#define OV9740_AEC_LO_THRESHOLD                0x3a1f
 
 /* BLC Control */
 #define OV9740_BLC_AUTO_ENABLE         0x4002
 #define OV9740_VT_SYS_CLK_DIV          0x0303
 #define OV9740_VT_PIX_CLK_DIV          0x0301
 #define OV9740_PLL_CTRL3010            0x3010
-#define OV9740_VFIFO_CTRL00            0x460E
+#define OV9740_VFIFO_CTRL00            0x460e
 
 /* ISP Control */
 #define OV9740_ISP_CTRL00              0x5000
 #define OV9740_ISP_CTRL05              0x5005
 #define OV9740_ISP_CTRL12              0x5012
 #define OV9740_ISP_CTRL19              0x5019
-#define OV9740_ISP_CTRL1A              0x501A
-#define OV9740_ISP_CTRL1E              0x501E
-#define OV9740_ISP_CTRL1F              0x501F
+#define OV9740_ISP_CTRL1A              0x501a
+#define OV9740_ISP_CTRL1E              0x501e
+#define OV9740_ISP_CTRL1F              0x501f
 #define OV9740_ISP_CTRL20              0x5020
 #define OV9740_ISP_CTRL21              0x5021
 
 #define OV9740_AWB_ADV_CTRL04          0x5187
 #define OV9740_AWB_ADV_CTRL05          0x5188
 #define OV9740_AWB_ADV_CTRL06          0x5189
-#define OV9740_AWB_ADV_CTRL07          0x518A
-#define OV9740_AWB_ADV_CTRL08          0x518B
-#define OV9740_AWB_ADV_CTRL09          0x518C
-#define OV9740_AWB_ADV_CTRL10          0x518D
-#define OV9740_AWB_ADV_CTRL11          0x518E
-#define OV9740_AWB_CTRL0F              0x518F
+#define OV9740_AWB_ADV_CTRL07          0x518a
+#define OV9740_AWB_ADV_CTRL08          0x518b
+#define OV9740_AWB_ADV_CTRL09          0x518c
+#define OV9740_AWB_ADV_CTRL10          0x518d
+#define OV9740_AWB_ADV_CTRL11          0x518e
+#define OV9740_AWB_CTRL0F              0x518f
 #define OV9740_AWB_CTRL10              0x5190
 #define OV9740_AWB_CTRL11              0x5191
 #define OV9740_AWB_CTRL12              0x5192
 #define OV9740_MIPI_CTRL_3012          0x3012
 #define OV9740_SC_CMMM_MIPI_CTR                0x3014
 
-/* supported resolutions */
-enum {
-       OV9740_VGA,
-       OV9740_720P,
-};
-
-struct ov9740_resolution {
-       unsigned int width;
-       unsigned int height;
-};
-
-static struct ov9740_resolution ov9740_resolutions[] = {
-       [OV9740_VGA] = {
-               .width  = 640,
-               .height = 480,
-       },
-       [OV9740_720P] = {
-               .width  = 1280,
-               .height = 720,
-       },
-};
+#define OV9740_MAX_WIDTH               1280
+#define OV9740_MAX_HEIGHT              720
 
 /* Misc. structures */
 struct ov9740_reg {
@@ -219,9 +201,16 @@ struct ov9740_priv {
 
        bool                            flag_vflip;
        bool                            flag_hflip;
+
+       /* For suspend/resume. */
+       struct v4l2_mbus_framefmt       current_mf;
+       bool                            current_enable;
 };
 
 static const struct ov9740_reg ov9740_defaults[] = {
+       /* Software Reset */
+       { OV9740_SOFTWARE_RESET,        0x01 },
+
        /* Banding Filter */
        { OV9740_AEC_B50_STEP_HI,       0x00 },
        { OV9740_AEC_B50_STEP_LO,       0xe8 },
@@ -241,36 +230,36 @@ static const struct ov9740_reg ov9740_defaults[] = {
        /* Un-documented OV9740 registers */
        { 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 },
        { 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c },
-       { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580A, 0x0e }, { 0x580B, 0x16 },
-       { 0x580C, 0x06 }, { 0x580D, 0x02 }, { 0x580E, 0x00 }, { 0x580F, 0x00 },
+       { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580a, 0x0e }, { 0x580b, 0x16 },
+       { 0x580c, 0x06 }, { 0x580d, 0x02 }, { 0x580e, 0x00 }, { 0x580f, 0x00 },
        { 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 },
        { 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 },
-       { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581A, 0x07 }, { 0x581B, 0x08 },
-       { 0x581C, 0x0b }, { 0x581D, 0x14 }, { 0x581E, 0x28 }, { 0x581F, 0x23 },
+       { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581a, 0x07 }, { 0x581b, 0x08 },
+       { 0x581c, 0x0b }, { 0x581d, 0x14 }, { 0x581e, 0x28 }, { 0x581f, 0x23 },
        { 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a },
        { 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f },
-       { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582A, 0x8f }, { 0x582B, 0x9e },
-       { 0x582C, 0x8f }, { 0x582D, 0x9f }, { 0x582E, 0x4f }, { 0x582F, 0x87 },
+       { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582a, 0x8f }, { 0x582b, 0x9e },
+       { 0x582c, 0x8f }, { 0x582d, 0x9f }, { 0x582e, 0x4f }, { 0x582f, 0x87 },
        { 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f },
        { 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf },
-       { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583A, 0x9f }, { 0x583B, 0x7f },
-       { 0x583C, 0x5f },
+       { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583a, 0x9f }, { 0x583b, 0x7f },
+       { 0x583c, 0x5f },
 
        /* Y Gamma */
        { 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e },
        { 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 },
-       { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548A, 0xa4 }, { 0x548B, 0xb1 },
-       { 0x548C, 0xc6 }, { 0x548D, 0xd8 }, { 0x548E, 0xe9 },
+       { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548a, 0xa4 }, { 0x548b, 0xb1 },
+       { 0x548c, 0xc6 }, { 0x548d, 0xd8 }, { 0x548e, 0xe9 },
 
        /* UV Gamma */
        { 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 },
        { 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 },
-       { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549A, 0x02 }, { 0x549B, 0xeb },
-       { 0x549C, 0x02 }, { 0x549D, 0xa0 }, { 0x549E, 0x02 }, { 0x549F, 0x67 },
-       { 0x54A0, 0x02 }, { 0x54A1, 0x3b }, { 0x54A2, 0x02 }, { 0x54A3, 0x18 },
-       { 0x54A4, 0x01 }, { 0x54A5, 0xe7 }, { 0x54A6, 0x01 }, { 0x54A7, 0xc3 },
-       { 0x54A8, 0x01 }, { 0x54A9, 0x94 }, { 0x54AA, 0x01 }, { 0x54AB, 0x72 },
-       { 0x54AC, 0x01 }, { 0x54AD, 0x57 },
+       { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549a, 0x02 }, { 0x549b, 0xeb },
+       { 0x549c, 0x02 }, { 0x549d, 0xa0 }, { 0x549e, 0x02 }, { 0x549f, 0x67 },
+       { 0x54a0, 0x02 }, { 0x54a1, 0x3b }, { 0x54a2, 0x02 }, { 0x54a3, 0x18 },
+       { 0x54a4, 0x01 }, { 0x54a5, 0xe7 }, { 0x54a6, 0x01 }, { 0x54a7, 0xc3 },
+       { 0x54a8, 0x01 }, { 0x54a9, 0x94 }, { 0x54aa, 0x01 }, { 0x54ab, 0x72 },
+       { 0x54ac, 0x01 }, { 0x54ad, 0x57 },
 
        /* AWB */
        { OV9740_AWB_CTRL00,            0xf0 },
@@ -296,18 +285,18 @@ static const struct ov9740_reg ov9740_defaults[] = {
        { OV9740_AWB_CTRL14,            0x00 },
 
        /* CIP */
-       { 0x530D, 0x12 },
+       { 0x530d, 0x12 },
 
        /* CMX */
        { 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 },
        { 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 },
-       { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538A, 0x00 }, { 0x538B, 0x20 },
-       { 0x538C, 0x00 }, { 0x538D, 0x00 }, { 0x538E, 0x00 }, { 0x538F, 0x16 },
+       { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538a, 0x00 }, { 0x538b, 0x20 },
+       { 0x538c, 0x00 }, { 0x538d, 0x00 }, { 0x538e, 0x00 }, { 0x538f, 0x16 },
        { 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 },
        { 0x5394, 0x18 },
 
        /* 50/60 Detection */
-       { 0x3C0A, 0x9c }, { 0x3C0B, 0x3f },
+       { 0x3c0a, 0x9c }, { 0x3c0b, 0x3f },
 
        /* Output Select */
        { OV9740_IO_OUTPUT_SEL01,       0x00 },
@@ -333,6 +322,7 @@ static const struct ov9740_reg ov9740_defaults[] = {
        { OV9740_ANALOG_CTRL10,         0xa1 },
        { OV9740_ANALOG_CTRL12,         0x24 },
        { OV9740_ANALOG_CTRL22,         0x9f },
+       { OV9740_ANALOG_CTRL15,         0xf0 },
 
        /* Sensor Control */
        { OV9740_SENSOR_CTRL03,         0x42 },
@@ -385,7 +375,7 @@ static const struct ov9740_reg ov9740_defaults[] = {
        { OV9740_LN_LENGTH_PCK_LO,      0x62 },
 
        /* MIPI Control */
-       { OV9740_MIPI_CTRL00,           0x44 },
+       { OV9740_MIPI_CTRL00,           0x44 }, /* 0x64 for discontinuous clk */
        { OV9740_MIPI_3837,             0x01 },
        { OV9740_MIPI_CTRL01,           0x0f },
        { OV9740_MIPI_CTRL03,           0x05 },
@@ -393,54 +383,9 @@ static const struct ov9740_reg ov9740_defaults[] = {
        { OV9740_VFIFO_RD_CTRL,         0x16 },
        { OV9740_MIPI_CTRL_3012,        0x70 },
        { OV9740_SC_CMMM_MIPI_CTR,      0x01 },
-};
-
-static const struct ov9740_reg ov9740_regs_vga[] = {
-       { OV9740_X_ADDR_START_HI,       0x00 },
-       { OV9740_X_ADDR_START_LO,       0xa0 },
-       { OV9740_Y_ADDR_START_HI,       0x00 },
-       { OV9740_Y_ADDR_START_LO,       0x00 },
-       { OV9740_X_ADDR_END_HI,         0x04 },
-       { OV9740_X_ADDR_END_LO,         0x63 },
-       { OV9740_Y_ADDR_END_HI,         0x02 },
-       { OV9740_Y_ADDR_END_LO,         0xd3 },
-       { OV9740_X_OUTPUT_SIZE_HI,      0x02 },
-       { OV9740_X_OUTPUT_SIZE_LO,      0x80 },
-       { OV9740_Y_OUTPUT_SIZE_HI,      0x01 },
-       { OV9740_Y_OUTPUT_SIZE_LO,      0xe0 },
-       { OV9740_ISP_CTRL1E,            0x03 },
-       { OV9740_ISP_CTRL1F,            0xc0 },
-       { OV9740_ISP_CTRL20,            0x02 },
-       { OV9740_ISP_CTRL21,            0xd0 },
-       { OV9740_VFIFO_READ_START_HI,   0x01 },
-       { OV9740_VFIFO_READ_START_LO,   0x40 },
-       { OV9740_ISP_CTRL00,            0xff },
-       { OV9740_ISP_CTRL01,            0xff },
-       { OV9740_ISP_CTRL03,            0xff },
-};
 
-static const struct ov9740_reg ov9740_regs_720p[] = {
-       { OV9740_X_ADDR_START_HI,       0x00 },
-       { OV9740_X_ADDR_START_LO,       0x00 },
-       { OV9740_Y_ADDR_START_HI,       0x00 },
-       { OV9740_Y_ADDR_START_LO,       0x00 },
-       { OV9740_X_ADDR_END_HI,         0x05 },
-       { OV9740_X_ADDR_END_LO,         0x03 },
-       { OV9740_Y_ADDR_END_HI,         0x02 },
-       { OV9740_Y_ADDR_END_LO,         0xd3 },
-       { OV9740_X_OUTPUT_SIZE_HI,      0x05 },
-       { OV9740_X_OUTPUT_SIZE_LO,      0x00 },
-       { OV9740_Y_OUTPUT_SIZE_HI,      0x02 },
-       { OV9740_Y_OUTPUT_SIZE_LO,      0xd0 },
-       { OV9740_ISP_CTRL1E,            0x05 },
-       { OV9740_ISP_CTRL1F,            0x00 },
-       { OV9740_ISP_CTRL20,            0x02 },
-       { OV9740_ISP_CTRL21,            0xd0 },
-       { OV9740_VFIFO_READ_START_HI,   0x02 },
-       { OV9740_VFIFO_READ_START_LO,   0x30 },
-       { OV9740_ISP_CTRL00,            0xff },
-       { OV9740_ISP_CTRL01,            0xef },
-       { OV9740_ISP_CTRL03,            0xff },
+       /* YUYV order */
+       { OV9740_ISP_CTRL19,            0x02 },
 };
 
 static enum v4l2_mbus_pixelcode ov9740_codes[] = {
@@ -537,7 +482,8 @@ static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
        ret = ov9740_reg_read(client, reg, &val);
        if (ret < 0) {
                dev_err(&client->dev,
-                       "[Read]-Modify-Write of register %02x failed!\n", reg);
+                       "[Read]-Modify-Write of register 0x%04x failed!\n",
+                       reg);
                return ret;
        }
 
@@ -547,7 +493,8 @@ static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
        ret = ov9740_reg_write(client, reg, val);
        if (ret < 0) {
                dev_err(&client->dev,
-                       "Read-Modify-[Write] of register %02x failed!\n", reg);
+                       "Read-Modify-[Write] of register 0x%04x failed!\n",
+                       reg);
                return ret;
        }
 
@@ -608,6 +555,8 @@ static int ov9740_s_stream(struct v4l2_subdev *sd, int enable)
                                               0x00);
        }
 
+       priv->current_enable = enable;
+
        return ret;
 }
 
@@ -630,126 +579,127 @@ static unsigned long ov9740_query_bus_param(struct soc_camera_device *icd)
        return soc_camera_apply_sensor_flags(icl, flags);
 }
 
-/* Get status of additional camera capabilities */
-static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct ov9740_priv *priv = to_ov9740(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               ctrl->value = priv->flag_vflip;
-               break;
-       case V4L2_CID_HFLIP:
-               ctrl->value = priv->flag_hflip;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* Set status of additional camera capabilities */
-static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-       struct ov9740_priv *priv = to_ov9740(sd);
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               priv->flag_vflip = ctrl->value;
-               break;
-       case V4L2_CID_HFLIP:
-               priv->flag_hflip = ctrl->value;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* Get chip identification */
-static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_chip_ident *id)
+/* select nearest higher resolution for capture */
+static void ov9740_res_roundup(u32 *width, u32 *height)
 {
-       struct ov9740_priv *priv = to_ov9740(sd);
+       /* Width must be a multiple of 4 pixels. */
+       *width = ALIGN(*width, 4);
 
-       id->ident = priv->ident;
-       id->revision = priv->revision;
+       /* Max resolution is 1280x720 (720p). */
+       if (*width > OV9740_MAX_WIDTH)
+               *width = OV9740_MAX_WIDTH;
 
-       return 0;
+       if (*height > OV9740_MAX_HEIGHT)
+               *height = OV9740_MAX_HEIGHT;
 }
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov9740_get_register(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_register *reg)
+/* Setup registers according to resolution and color encoding */
+static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u32 x_start;
+       u32 y_start;
+       u32 x_end;
+       u32 y_end;
+       bool scaling = 0;
+       u32 scale_input_x;
+       u32 scale_input_y;
        int ret;
-       u8 val;
-
-       if (reg->reg & ~0xffff)
-               return -EINVAL;
 
-       reg->size = 2;
-
-       ret = ov9740_reg_read(client, reg->reg, &val);
-       if (ret)
-               return ret;
-
-       reg->val = (__u64)val;
+       if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT))
+               scaling = 1;
 
-       return ret;
-}
-
-static int ov9740_set_register(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       /*
+        * Try to use as much of the sensor area as possible when supporting
+        * smaller resolutions.  Depending on the aspect ratio of the
+        * chosen resolution, we can either use the full width of the sensor,
+        * or the full height of the sensor (or both if the aspect ratio is
+        * the same as 1280x720.
+        */
+       if ((OV9740_MAX_WIDTH * height) > (OV9740_MAX_HEIGHT * width)) {
+               scale_input_x = (OV9740_MAX_HEIGHT * width) / height;
+               scale_input_y = OV9740_MAX_HEIGHT;
+       } else {
+               scale_input_x = OV9740_MAX_WIDTH;
+               scale_input_y = (OV9740_MAX_WIDTH * height) / width;
+       }
 
-       if (reg->reg & ~0xffff || reg->val & ~0xff)
-               return -EINVAL;
+       /* These describe the area of the sensor to use. */
+       x_start = (OV9740_MAX_WIDTH - scale_input_x) / 2;
+       y_start = (OV9740_MAX_HEIGHT - scale_input_y) / 2;
+       x_end = x_start + scale_input_x - 1;
+       y_end = y_start + scale_input_y - 1;
 
-       return ov9740_reg_write(client, reg->reg, reg->val);
-}
-#endif
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_START_HI, x_start >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_START_LO, x_start & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_HI, y_start >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_LO, y_start & 0xff);
+       if (ret)
+               goto done;
 
-/* select nearest higher resolution for capture */
-static void ov9740_res_roundup(u32 *width, u32 *height)
-{
-       int i;
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_END_HI, x_end >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_END_LO, x_end & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_HI, y_end >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_LO, y_end & 0xff);
+       if (ret)
+               goto done;
 
-       for (i = 0; i < ARRAY_SIZE(ov9740_resolutions); i++)
-               if ((ov9740_resolutions[i].width >= *width) &&
-                   (ov9740_resolutions[i].height >= *height)) {
-                       *width = ov9740_resolutions[i].width;
-                       *height = ov9740_resolutions[i].height;
-                       return;
-               }
+       ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_HI, width >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_LO, width & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_HI, height >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_LO, height & 0xff);
+       if (ret)
+               goto done;
 
-       *width = ov9740_resolutions[OV9740_720P].width;
-       *height = ov9740_resolutions[OV9740_720P].height;
-}
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL1E, scale_input_x >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL1F, scale_input_x & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL20, scale_input_y >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL21, scale_input_y & 0xff);
+       if (ret)
+               goto done;
 
-/* Setup registers according to resolution and color encoding */
-static int ov9740_set_res(struct i2c_client *client, u32 width)
-{
-       int ret;
+       ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_HI,
+                              (scale_input_x - width) >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_LO,
+                              (scale_input_x - width) & 0xff);
+       if (ret)
+               goto done;
 
-       /* select register configuration for given resolution */
-       if (width == ov9740_resolutions[OV9740_VGA].width) {
-               dev_dbg(&client->dev, "Setting image size to 640x480\n");
-               ret = ov9740_reg_write_array(client, ov9740_regs_vga,
-                                            ARRAY_SIZE(ov9740_regs_vga));
-       } else if (width == ov9740_resolutions[OV9740_720P].width) {
-               dev_dbg(&client->dev, "Setting image size to 1280x720\n");
-               ret = ov9740_reg_write_array(client, ov9740_regs_720p,
-                                            ARRAY_SIZE(ov9740_regs_720p));
-       } else {
-               dev_err(&client->dev, "Failed to select resolution!\n");
-               return -EINVAL;
-       }
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL00, 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL01, 0xef |
+                                                         (scaling << 4));
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL03, 0xff);
 
+done:
        return ret;
 }
 
@@ -758,6 +708,7 @@ static int ov9740_s_fmt(struct v4l2_subdev *sd,
                        struct v4l2_mbus_framefmt *mf)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov9740_priv *priv = to_ov9740(sd);
        enum v4l2_colorspace cspace;
        enum v4l2_mbus_pixelcode code = mf->code;
        int ret;
@@ -777,13 +728,15 @@ static int ov9740_s_fmt(struct v4l2_subdev *sd,
        if (ret < 0)
                return ret;
 
-       ret = ov9740_set_res(client, mf->width);
+       ret = ov9740_set_res(client, mf->width, mf->height);
        if (ret < 0)
                return ret;
 
        mf->code        = code;
        mf->colorspace  = cspace;
 
+       memcpy(&priv->current_mf, mf, sizeof(struct v4l2_mbus_framefmt));
+
        return ret;
 }
 
@@ -814,8 +767,8 @@ static int ov9740_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 {
        a->bounds.left          = 0;
        a->bounds.top           = 0;
-       a->bounds.width         = ov9740_resolutions[OV9740_720P].width;
-       a->bounds.height        = ov9740_resolutions[OV9740_720P].height;
+       a->bounds.width         = OV9740_MAX_WIDTH;
+       a->bounds.height        = OV9740_MAX_HEIGHT;
        a->defrect              = a->bounds;
        a->type                 = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        a->pixelaspect.numerator        = 1;
@@ -828,13 +781,115 @@ static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 {
        a->c.left               = 0;
        a->c.top                = 0;
-       a->c.width              = ov9740_resolutions[OV9740_720P].width;
-       a->c.height             = ov9740_resolutions[OV9740_720P].height;
+       a->c.width              = OV9740_MAX_WIDTH;
+       a->c.height             = OV9740_MAX_HEIGHT;
        a->type                 = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
        return 0;
 }
 
+/* Get status of additional camera capabilities */
+static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               ctrl->value = priv->flag_vflip;
+               break;
+       case V4L2_CID_HFLIP:
+               ctrl->value = priv->flag_hflip;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Set status of additional camera capabilities */
+static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               priv->flag_vflip = ctrl->value;
+               break;
+       case V4L2_CID_HFLIP:
+               priv->flag_hflip = ctrl->value;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Get chip identification */
+static int ov9740_g_chip_ident(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_chip_ident *id)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       id->ident = priv->ident;
+       id->revision = priv->revision;
+
+       return 0;
+}
+
+static int ov9740_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct ov9740_priv *priv = to_ov9740(sd);
+
+       if (!priv->current_enable)
+               return 0;
+
+       if (on) {
+               ov9740_s_fmt(sd, &priv->current_mf);
+               ov9740_s_stream(sd, priv->current_enable);
+       } else {
+               ov9740_s_stream(sd, 0);
+               priv->current_enable = true;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9740_get_register(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u8 val;
+
+       if (reg->reg & ~0xffff)
+               return -EINVAL;
+
+       reg->size = 2;
+
+       ret = ov9740_reg_read(client, reg->reg, &val);
+       if (ret)
+               return ret;
+
+       reg->val = (__u64)val;
+
+       return ret;
+}
+
+static int ov9740_set_register(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg & ~0xffff || reg->val & ~0xff)
+               return -EINVAL;
+
+       return ov9740_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
 static int ov9740_video_probe(struct soc_camera_device *icd,
                              struct i2c_client *client)
 {
@@ -843,16 +898,9 @@ static int ov9740_video_probe(struct soc_camera_device *icd,
        u8 modelhi, modello;
        int ret;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface) {
-               dev_err(&client->dev, "Parent missing or invalid!\n");
-               ret = -ENODEV;
-               goto err;
-       }
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * check and show product ID and manufacturer ID
@@ -901,24 +949,24 @@ static struct soc_camera_ops ov9740_ops = {
        .num_controls           = ARRAY_SIZE(ov9740_controls),
 };
 
+static struct v4l2_subdev_video_ops ov9740_video_ops = {
+       .s_stream               = ov9740_s_stream,
+       .s_mbus_fmt             = ov9740_s_fmt,
+       .try_mbus_fmt           = ov9740_try_fmt,
+       .enum_mbus_fmt          = ov9740_enum_fmt,
+       .cropcap                = ov9740_cropcap,
+       .g_crop                 = ov9740_g_crop,
+};
+
 static struct v4l2_subdev_core_ops ov9740_core_ops = {
        .g_ctrl                 = ov9740_g_ctrl,
        .s_ctrl                 = ov9740_s_ctrl,
        .g_chip_ident           = ov9740_g_chip_ident,
+       .s_power                = ov9740_s_power,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .g_register             = ov9740_get_register,
        .s_register             = ov9740_set_register,
 #endif
-
-};
-
-static struct v4l2_subdev_video_ops ov9740_video_ops = {
-       .s_stream               = ov9740_s_stream,
-       .s_mbus_fmt             = ov9740_s_fmt,
-       .try_mbus_fmt           = ov9740_try_fmt,
-       .enum_mbus_fmt          = ov9740_enum_fmt,
-       .cropcap                = ov9740_cropcap,
-       .g_crop                 = ov9740_g_crop,
 };
 
 static struct v4l2_subdev_ops ov9740_subdev_ops = {
index 7551907f8c280f4b9f896094ea9fe0cc079bfd19..e753b5e4d2ce449ba3730d3a3f17244491b9e04a 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
 #include <asm/io.h>
@@ -39,7 +38,7 @@
 #include <media/v4l2-device.h>
 
 MODULE_LICENSE("GPL");
-
+MODULE_VERSION("0.0.4");
 
 #define MOTOROLA       1
 #define PHILIPS2       2               /* SAA7191 */
@@ -678,7 +677,6 @@ static int pms_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card));
        strlcpy(vcap->bus_info, "ISA", sizeof(vcap->bus_info));
-       vcap->version = KERNEL_VERSION(0, 0, 3);
        vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
 }
index 2254194aad579c201475784f7c27a51e7be6791d..c1d9bb61cd7794765e2709d498c49dfc0de458af 100644 (file)
@@ -168,6 +168,7 @@ module_exit(pvr_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.9.1");
 
 
 /*
index 38761142a4d94235e595897e35ca1cd053acabbf..e27f8ab76966ccdebd9f1a11338b0006ea759a84 100644 (file)
@@ -91,7 +91,7 @@ static struct v4l2_capability pvr_capability ={
        .driver         = "pvrusb2",
        .card           = "Hauppauge WinTV pvr-usb2",
        .bus_info       = "usb",
-       .version        = KERNEL_VERSION(0, 9, 0),
+       .version        = LINUX_VERSION_CODE,
        .capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
                           V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
                           V4L2_CAP_READWRITE),
@@ -369,11 +369,6 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                break;
        }
 
-       case VIDIOC_S_AUDIO:
-       {
-               ret = -EINVAL;
-               break;
-       }
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
@@ -850,7 +845,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 #endif
 
        default :
-               ret = -EINVAL;
+               ret = -ENOTTY;
                break;
        }
 
index 8da42e4f1ba05dca90628d9028bcda7e80f5c23b..d63d0a85003599478f573e4a6bf7ad4e9a0762c7 100644 (file)
@@ -1,6 +1,7 @@
 config USB_PWC
        tristate "USB Philips Cameras"
        depends on VIDEO_V4L2
+       select VIDEOBUF2_VMALLOC
        ---help---
          Say Y or M here if you want to use one of these Philips & OEM
          webcams:
index 760b4de13adf6fa852b358ae88a9751f7cd1b597..3977addf3ba8553d586bfb0a3b8521e146435e7e 100644 (file)
@@ -3,6 +3,7 @@
    video modes.
    (C) 1999-2003 Nemosoft Unv.
    (C) 2004-2006 Luc Saillard (luc@saillard.org)
+   (C) 2011 Hans de Goede <hdegoede@redhat.com>
 
    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.
 #include <asm/errno.h>
 
 #include "pwc.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
-#define GET_LUM_CTL                    0x02
-#define SET_CHROM_CTL                  0x03
-#define GET_CHROM_CTL                  0x04
-#define SET_STATUS_CTL                 0x05
-#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
-
-/* Selectors for the Luminance controls [GS]ET_LUM_CTL */
-#define AGC_MODE_FORMATTER                     0x2000
-#define PRESET_AGC_FORMATTER                   0x2100
-#define SHUTTER_MODE_FORMATTER                 0x2200
-#define PRESET_SHUTTER_FORMATTER               0x2300
-#define PRESET_CONTOUR_FORMATTER               0x2400
-#define AUTO_CONTOUR_FORMATTER                 0x2500
-#define BACK_LIGHT_COMPENSATION_FORMATTER      0x2600
-#define CONTRAST_FORMATTER                     0x2700
-#define DYNAMIC_NOISE_CONTROL_FORMATTER                0x2800
-#define FLICKERLESS_MODE_FORMATTER             0x2900
-#define AE_CONTROL_SPEED                       0x2A00
-#define BRIGHTNESS_FORMATTER                   0x2B00
-#define GAMMA_FORMATTER                                0x2C00
-
-/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
-#define WB_MODE_FORMATTER                      0x1000
-#define AWB_CONTROL_SPEED_FORMATTER            0x1100
-#define AWB_CONTROL_DELAY_FORMATTER            0x1200
-#define PRESET_MANUAL_RED_GAIN_FORMATTER       0x1300
-#define PRESET_MANUAL_BLUE_GAIN_FORMATTER      0x1400
-#define COLOUR_MODE_FORMATTER                  0x1500
-#define SATURATION_MODE_FORMATTER1             0x1600
-#define SATURATION_MODE_FORMATTER2             0x1700
-
-/* Selectors for the Status controls [GS]ET_STATUS_CTL */
-#define SAVE_USER_DEFAULTS_FORMATTER           0x0200
-#define RESTORE_USER_DEFAULTS_FORMATTER                0x0300
-#define RESTORE_FACTORY_DEFAULTS_FORMATTER     0x0400
-#define READ_AGC_FORMATTER                     0x0500
-#define READ_SHUTTER_FORMATTER                 0x0600
-#define READ_RED_GAIN_FORMATTER                        0x0700
-#define READ_BLUE_GAIN_FORMATTER               0x0800
+/* Selectors for status controls used only in this file */
 #define GET_STATUS_B00                         0x0B00
 #define SENSOR_TYPE_FORMATTER1                 0x0C00
 #define GET_STATUS_3000                                0x3000
 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
 #define VIDEO_OUTPUT_CONTROL_FORMATTER         0x0100
 
-/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
-#define PT_RELATIVE_CONTROL_FORMATTER          0x01
-#define PT_RESET_CONTROL_FORMATTER             0x02
-#define PT_STATUS_FORMATTER                    0x03
-
 static const char *size2name[PSZ_MAX] =
 {
        "subQCIF",
@@ -160,7 +107,7 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev);
 /****************************************************************************/
 
 static int _send_control_msg(struct pwc_device *pdev,
-       u8 request, u16 value, int index, void *buf, int buflen, int timeout)
+       u8 request, u16 value, int index, void *buf, int buflen)
 {
        int rc;
        void *kbuf = NULL;
@@ -177,7 +124,7 @@ static int _send_control_msg(struct pwc_device *pdev,
                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                value,
                index,
-               kbuf, buflen, timeout);
+               kbuf, buflen, USB_CTRL_SET_TIMEOUT);
 
        kfree(kbuf);
        return rc;
@@ -197,9 +144,13 @@ static int recv_control_msg(struct pwc_device *pdev,
                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                value,
                pdev->vcinterface,
-               kbuf, buflen, 500);
+               kbuf, buflen, USB_CTRL_GET_TIMEOUT);
        memcpy(buf, kbuf, buflen);
        kfree(kbuf);
+
+       if (rc < 0)
+               PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
+                         rc, request, value);
        return rc;
 }
 
@@ -210,18 +161,16 @@ static inline int send_video_command(struct pwc_device *pdev,
                SET_EP_STREAM_CTL,
                VIDEO_OUTPUT_CONTROL_FORMATTER,
                index,
-               buf, buflen, 1000);
+               buf, buflen);
 }
 
-static inline int send_control_msg(struct pwc_device *pdev,
+int send_control_msg(struct pwc_device *pdev,
        u8 request, u16 value, void *buf, int buflen)
 {
        return _send_control_msg(pdev,
-               request, value, pdev->vcinterface, buf, buflen, 500);
+               request, value, pdev->vcinterface, buf, buflen);
 }
 
-
-
 static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
 {
        unsigned char buf[3];
@@ -261,8 +210,11 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
                PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
                return ret;
        }
-       if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
-               pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
+       if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
+               ret = pwc_dec1_init(pdev, pdev->type, pdev->release, buf);
+               if (ret < 0)
+                       return ret;
+       }
 
        pdev->cmd_len = 3;
        memcpy(pdev->cmd_buf, buf, 3);
@@ -321,8 +273,11 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, i
        if (ret < 0)
                return ret;
 
-       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
-               pwc_dec23_init(pdev, pdev->type, buf);
+       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
+               ret = pwc_dec23_init(pdev, pdev->type, buf);
+               if (ret < 0)
+                       return ret;
+       }
 
        pdev->cmd_len = 13;
        memcpy(pdev->cmd_buf, buf, 13);
@@ -394,8 +349,11 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i
        if (ret < 0)
                return ret;
 
-       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
-               pwc_dec23_init(pdev, pdev->type, buf);
+       if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
+               ret = pwc_dec23_init(pdev, pdev->type, buf);
+               if (ret < 0)
+                       return ret;
+       }
 
        pdev->cmd_len = 12;
        memcpy(pdev->cmd_buf, buf, 12);
@@ -452,6 +410,7 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame
        }
        pdev->view.x = width;
        pdev->view.y = height;
+       pdev->vcompression = compression;
        pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
        pwc_set_image_buffer_size(pdev);
        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);
@@ -511,13 +470,9 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i
        return ret;
 }
 
-#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;
+       int factor = 0;
 
        /* for V4L2_PIX_FMT_YUV420 */
        switch (pdev->pixfmt) {
@@ -541,442 +496,108 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev)
         */
        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 */
-
-int pwc_get_brightness(struct pwc_device *pdev)
+int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 {
-       char buf;
        int ret;
+       u8 buf;
 
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf));
+       ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf));
        if (ret < 0)
                return ret;
-       return buf;
-}
 
-int pwc_set_brightness(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 9) & 0x7f;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf));
+       *data = buf;
+       return 0;
 }
 
-/* CONTRAST */
-
-int pwc_get_contrast(struct pwc_device *pdev)
+int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
 {
-       char buf;
        int ret;
 
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf));
+       ret = send_control_msg(pdev, request, value, &data, sizeof(data));
        if (ret < 0)
                return ret;
-       return buf;
-}
 
-int pwc_set_contrast(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 10) & 0x3f;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf));
+       return 0;
 }
 
-/* GAMMA */
-
-int pwc_get_gamma(struct pwc_device *pdev)
+int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 {
-       char buf;
        int ret;
+       s8 buf;
 
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf));
+       ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf));
        if (ret < 0)
                return ret;
-       return buf;
-}
-
-int pwc_set_gamma(struct pwc_device *pdev, int value)
-{
-       char buf;
 
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 11) & 0x1f;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf));
-}
-
-
-/* SATURATION */
-
-/* return a value between [-100 , 100] */
-int pwc_get_saturation(struct pwc_device *pdev, int *value)
-{
-       char buf;
-       int ret, saturation_register;
-
-       if (pdev->type < 675)
-               return -EINVAL;
-       if (pdev->type < 730)
-               saturation_register = SATURATION_MODE_FORMATTER2;
-       else
-               saturation_register = SATURATION_MODE_FORMATTER1;
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, saturation_register, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *value = (signed)buf;
+       *data = buf;
        return 0;
 }
 
-/* @param value saturation color between [-100 , 100] */
-int pwc_set_saturation(struct pwc_device *pdev, int value)
+int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 {
-       char buf;
-       int saturation_register;
-
-       if (pdev->type < 675)
-               return -EINVAL;
-       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 send_control_msg(pdev,
-               SET_CHROM_CTL, saturation_register, &buf, sizeof(buf));
-}
-
-/* AGC */
-
-int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
-{
-       char buf;
        int ret;
+       u8 buf[2];
 
-       if (mode)
-               buf = 0x0; /* auto */
-       else
-               buf = 0xff; /* fixed */
-
-       ret = send_control_msg(pdev,
-               SET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf));
-
-       if (!mode && ret >= 0) {
-               if (value < 0)
-                       value = 0;
-               if (value > 0xffff)
-                       value = 0xffff;
-               buf = (value >> 10) & 0x3F;
-               ret = send_control_msg(pdev,
-                       SET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf));
-       }
+       ret = recv_control_msg(pdev, request, value, buf, sizeof(buf));
        if (ret < 0)
                return ret;
+
+       *data = (buf[1] << 8) | buf[0];
        return 0;
 }
 
-int pwc_get_agc(struct pwc_device *pdev, int *value)
+int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data)
 {
-       unsigned char buf;
        int ret;
+       u8 buf[2];
 
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf));
+       buf[0] = data & 0xff;
+       buf[1] = data >> 8;
+       ret = send_control_msg(pdev, request, value, buf, sizeof(buf));
        if (ret < 0)
                return ret;
 
-       if (buf != 0) { /* fixed */
-               ret = recv_control_msg(pdev,
-                       GET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf));
-               if (ret < 0)
-                       return ret;
-               if (buf > 0x3F)
-                       buf = 0x3F;
-               *value = (buf << 10);
-       }
-       else { /* auto */
-               ret = recv_control_msg(pdev,
-                       GET_STATUS_CTL, READ_AGC_FORMATTER, &buf, sizeof(buf));
-               if (ret < 0)
-                       return ret;
-               /* Gah... this value ranges from 0x00 ... 0x9F */
-               if (buf > 0x9F)
-                       buf = 0x9F;
-               *value = -(48 + buf * 409);
-       }
-
        return 0;
 }
 
-int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
-{
-       char buf[2];
-       int speed, ret;
-
-
-       if (mode)
-               buf[0] = 0x0;   /* auto */
-       else
-               buf[0] = 0xff; /* fixed */
-
-       ret = send_control_msg(pdev,
-               SET_LUM_CTL, SHUTTER_MODE_FORMATTER, &buf, 1);
-
-       if (!mode && ret >= 0) {
-               if (value < 0)
-                       value = 0;
-               if (value > 0xffff)
-                       value = 0xffff;
-
-               if (DEVICE_USE_CODEC2(pdev->type)) {
-                       /* speed ranges from 0x0 to 0x290 (656) */
-                       speed = (value / 100);
-                       buf[1] = speed >> 8;
-                       buf[0] = speed & 0xff;
-               } else if (DEVICE_USE_CODEC3(pdev->type)) {
-                       /* speed seems to range from 0x0 to 0xff */
-                       buf[1] = 0;
-                       buf[0] = value >> 8;
-               }
-
-               ret = send_control_msg(pdev,
-                       SET_LUM_CTL, PRESET_SHUTTER_FORMATTER,
-                       &buf, sizeof(buf));
-       }
-       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)
+int pwc_button_ctrl(struct pwc_device *pdev, u16 value)
 {
-       unsigned char buf[2];
        int ret;
 
-       ret = recv_control_msg(pdev,
-               GET_STATUS_CTL, READ_SHUTTER_FORMATTER, &buf, sizeof(buf));
+       ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0);
        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 */
-
-int pwc_camera_power(struct pwc_device *pdev, int power)
+void pwc_camera_power(struct pwc_device *pdev, int power)
 {
        char buf;
+       int r;
+
+       if (!pdev->power_save)
+               return;
 
        if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
-               return 0;       /* Not supported by Nala or Timon < release 6 */
+               return; /* Not supported by Nala or Timon < release 6 */
 
        if (power)
                buf = 0x00; /* active */
        else
                buf = 0xFF; /* power save */
-       return send_control_msg(pdev,
+       r = send_control_msg(pdev,
                SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER,
                &buf, sizeof(buf));
-}
-
-
-
-/* private calls */
-
-int pwc_restore_user(struct pwc_device *pdev)
-{
-       return send_control_msg(pdev,
-               SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, NULL, 0);
-}
-
-int pwc_save_user(struct pwc_device *pdev)
-{
-       return send_control_msg(pdev,
-               SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, NULL, 0);
-}
-
-int pwc_restore_factory(struct pwc_device *pdev)
-{
-       return send_control_msg(pdev,
-               SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, NULL, 0);
-}
-
- /* ************************************************* */
- /* Patch by Alvarado: (not in the original version   */
-
- /*
-  * the camera recognizes modes from 0 to 4:
-  *
-  * 00: indoor (incandescant lighting)
-  * 01: outdoor (sunlight)
-  * 02: fluorescent lighting
-  * 03: manual
-  * 04: auto
-  */
-int pwc_set_awb(struct pwc_device *pdev, int mode)
-{
-       char buf;
-       int ret;
-
-       if (mode < 0)
-           mode = 0;
-
-       if (mode > 4)
-           mode = 4;
-
-       buf = mode & 0x07; /* just the lowest three bits */
-
-       ret = send_control_msg(pdev,
-               SET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf));
-
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-int pwc_get_awb(struct pwc_device *pdev)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf));
-
-       if (ret < 0)
-               return ret;
-       return buf;
-}
-
-int pwc_set_red_gain(struct pwc_device *pdev, int value)
-{
-       unsigned char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* only the msb is considered */
-       buf = value >> 8;
-       return send_control_msg(pdev,
-               SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER,
-               &buf, sizeof(buf));
-}
-
-int pwc_get_red_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER,
-               &buf, sizeof(buf));
-       if (ret < 0)
-           return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-
-int pwc_set_blue_gain(struct pwc_device *pdev, int value)
-{
-       unsigned char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* only the msb is considered */
-       buf = value >> 8;
-       return send_control_msg(pdev,
-               SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER,
-               &buf, sizeof(buf));
-}
-
-int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER,
-               &buf, sizeof(buf));
-       if (ret < 0)
-           return ret;
-       *value = buf << 8;
-       return 0;
-}
-
 
-/* The following two functions are different, since they only read the
-   internal red/blue gains, which may be different from the manual
-   gains set or read above.
- */
-static int pwc_read_red_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *value = buf << 8;
-       return 0;
+       if (r < 0)
+               PWC_ERROR("Failed to power %s camera (%d)\n",
+                         power ? "on" : "off", r);
 }
 
-static int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-
 static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
 {
        unsigned char buf;
@@ -1028,6 +649,7 @@ static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
 int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
 {
        unsigned char buf[2];
+       int r;
 
        if (pdev->type < 730)
                return 0;
@@ -1045,8 +667,12 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
        buf[0] = on_value;
        buf[1] = off_value;
 
-       return send_control_msg(pdev,
+       r = send_control_msg(pdev,
                SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf));
+       if (r < 0)
+               PWC_ERROR("Failed to set LED on/off time (%d)\n", r);
+
+       return r;
 }
 
 static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
@@ -1069,164 +695,6 @@ static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
        return 0;
 }
 
-int pwc_set_contour(struct pwc_device *pdev, int contour)
-{
-       unsigned char buf;
-       int ret;
-
-       if (contour < 0)
-               buf = 0xff; /* auto contour on */
-       else
-               buf = 0x0; /* auto contour off */
-       ret = send_control_msg(pdev,
-               SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-
-       if (contour < 0)
-               return 0;
-       if (contour > 0xffff)
-               contour = 0xffff;
-
-       buf = (contour >> 10); /* contour preset is [0..3f] */
-       ret = send_control_msg(pdev,
-               SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-int pwc_get_contour(struct pwc_device *pdev, int *contour)
-{
-       unsigned char buf;
-       int ret;
-
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-
-       if (buf == 0) {
-               /* auto mode off, query current preset value */
-               ret = recv_control_msg(pdev,
-                       GET_LUM_CTL, PRESET_CONTOUR_FORMATTER,
-                       &buf, sizeof(buf));
-               if (ret < 0)
-                       return ret;
-               *contour = buf << 10;
-       }
-       else
-               *contour = -1;
-       return 0;
-}
-
-
-int pwc_set_backlight(struct pwc_device *pdev, int backlight)
-{
-       unsigned char buf;
-
-       if (backlight)
-               buf = 0xff;
-       else
-               buf = 0x0;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER,
-               &buf, sizeof(buf));
-}
-
-int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
-{
-       int ret;
-       unsigned char buf;
-
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER,
-               &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *backlight = !!buf;
-       return 0;
-}
-
-int pwc_set_colour_mode(struct pwc_device *pdev, int colour)
-{
-       unsigned char buf;
-
-       if (colour)
-               buf = 0xff;
-       else
-               buf = 0x0;
-       return send_control_msg(pdev,
-               SET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf));
-}
-
-int pwc_get_colour_mode(struct pwc_device *pdev, int *colour)
-{
-       int ret;
-       unsigned char buf;
-
-       ret = recv_control_msg(pdev,
-               GET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *colour = !!buf;
-       return 0;
-}
-
-
-int pwc_set_flicker(struct pwc_device *pdev, int flicker)
-{
-       unsigned char buf;
-
-       if (flicker)
-               buf = 0xff;
-       else
-               buf = 0x0;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf));
-}
-
-int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
-{
-       int ret;
-       unsigned char buf;
-
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *flicker = !!buf;
-       return 0;
-}
-
-int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
-{
-       unsigned char buf;
-
-       if (noise < 0)
-               noise = 0;
-       if (noise > 3)
-               noise = 3;
-       buf = noise;
-       return send_control_msg(pdev,
-               SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER,
-               &buf, sizeof(buf));
-}
-
-int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
-{
-       int ret;
-       unsigned char buf;
-
-       ret = recv_control_msg(pdev,
-               GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER,
-               &buf, sizeof(buf));
-       if (ret < 0)
-               return ret;
-       *noise = buf;
-       return 0;
-}
-
 static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
 {
        unsigned char buf;
@@ -1309,7 +777,7 @@ static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *st
        return 0;
 }
 
-
+#ifdef CONFIG_USB_PWC_DEBUG
 int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
 {
        unsigned char buf;
@@ -1332,7 +800,7 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
                *sensor = buf;
        return 0;
 }
-
+#endif
 
  /* End of Add-Ons                                    */
  /* ************************************************* */
@@ -1356,37 +824,41 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
 /* copy local variable to arg */
 #define ARG_OUT(ARG_name) /* nothing */
 
+/*
+ * Our ctrls use native values, but the old custom pwc ioctl interface expects
+ * values from 0 - 65535, define 2 helper functions to scale things. */
+static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl)
+{
+       return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum;
+}
+
+static int pwc_ioctl_s_ctrl(struct v4l2_ctrl *ctrl, int val)
+{
+       return v4l2_ctrl_s_ctrl(ctrl, val * ctrl->maximum / 65535);
+}
+
 long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 {
        long ret = 0;
 
        switch(cmd) {
        case VIDIOCPWCRUSER:
-       {
-               if (pwc_restore_user(pdev))
-                       ret = -EINVAL;
+               ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER);
                break;
-       }
 
        case VIDIOCPWCSUSER:
-       {
-               if (pwc_save_user(pdev))
-                       ret = -EINVAL;
+               ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER);
                break;
-       }
 
        case VIDIOCPWCFACTORY:
-       {
-               if (pwc_restore_factory(pdev))
-                       ret = -EINVAL;
+               ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER);
                break;
-       }
 
        case VIDIOCPWCSCQUAL:
        {
                ARG_DEF(int, qual)
 
-               if (pdev->iso_init) {
+               if (vb2_is_streaming(&pdev->vb_queue)) {
                        ret = -EBUSY;
                        break;
                }
@@ -1396,8 +868,6 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
                        ret = -EINVAL;
                else
                        ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
-               if (ret >= 0)
-                       pdev->vcompression = ARGR(qual);
                break;
        }
 
@@ -1432,71 +902,59 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        case VIDIOCPWCSAGC:
        {
                ARG_DEF(int, agc)
-
                ARG_IN(agc)
-               if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
-                       ret = -EINVAL;
+               ret = v4l2_ctrl_s_ctrl(pdev->autogain, ARGR(agc) < 0);
+               if (ret == 0 && ARGR(agc) >= 0)
+                       ret = pwc_ioctl_s_ctrl(pdev->gain, ARGR(agc));
                break;
        }
 
        case VIDIOCPWCGAGC:
        {
                ARG_DEF(int, agc)
-
-               if (pwc_get_agc(pdev, ARGA(agc)))
-                       ret = -EINVAL;
+               if (v4l2_ctrl_g_ctrl(pdev->autogain))
+                       ARGR(agc) = -1;
+               else
+                       ARGR(agc) = pwc_ioctl_g_ctrl(pdev->gain);
                ARG_OUT(agc)
                break;
        }
 
        case VIDIOCPWCSSHUTTER:
        {
-               ARG_DEF(int, shutter_speed)
-
-               ARG_IN(shutter_speed)
-               ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
+               ARG_DEF(int, shutter)
+               ARG_IN(shutter)
+               ret = v4l2_ctrl_s_ctrl(pdev->exposure_auto,
+                                      /* Menu idx 0 = auto, idx 1 = manual */
+                                      ARGR(shutter) >= 0);
+               if (ret == 0 && ARGR(shutter) >= 0)
+                       ret = pwc_ioctl_s_ctrl(pdev->exposure, ARGR(shutter));
                break;
        }
 
        case VIDIOCPWCSAWB:
        {
                ARG_DEF(struct pwc_whitebalance, wb)
-
                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);
-               }
+               ret = v4l2_ctrl_s_ctrl(pdev->auto_white_balance,
+                                      ARGR(wb).mode);
+               if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL)
+                       ret = pwc_ioctl_s_ctrl(pdev->red_balance,
+                                              ARGR(wb).manual_red);
+               if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL)
+                       ret = pwc_ioctl_s_ctrl(pdev->blue_balance,
+                                              ARGR(wb).manual_blue);
                break;
        }
 
        case VIDIOCPWCGAWB:
        {
                ARG_DEF(struct pwc_whitebalance, wb)
-
-               memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
-               ARGR(wb).mode = pwc_get_awb(pdev);
-               if (ARGR(wb).mode < 0)
-                       ret = -EINVAL;
-               else {
-                       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, &ARGR(wb).manual_blue);
-                               if (ret < 0)
-                                       break;
-                       }
-                       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, &ARGR(wb).read_blue);
-                               if (ret < 0)
-                                       break;
-                       }
-               }
+               ARGR(wb).mode = v4l2_ctrl_g_ctrl(pdev->auto_white_balance);
+               ARGR(wb).manual_red = ARGR(wb).read_red =
+                       pwc_ioctl_g_ctrl(pdev->red_balance);
+               ARGR(wb).manual_blue = ARGR(wb).read_blue =
+                       pwc_ioctl_g_ctrl(pdev->blue_balance);
                ARG_OUT(wb)
                break;
        }
@@ -1550,17 +1008,20 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        case VIDIOCPWCSCONTOUR:
        {
                ARG_DEF(int, contour)
-
                ARG_IN(contour)
-               ret = pwc_set_contour(pdev, ARGR(contour));
+               ret = v4l2_ctrl_s_ctrl(pdev->autocontour, ARGR(contour) < 0);
+               if (ret == 0 && ARGR(contour) >= 0)
+                       ret = pwc_ioctl_s_ctrl(pdev->contour, ARGR(contour));
                break;
        }
 
        case VIDIOCPWCGCONTOUR:
        {
                ARG_DEF(int, contour)
-
-               ret = pwc_get_contour(pdev, ARGA(contour));
+               if (v4l2_ctrl_g_ctrl(pdev->autocontour))
+                       ARGR(contour) = -1;
+               else
+                       ARGR(contour) = pwc_ioctl_g_ctrl(pdev->contour);
                ARG_OUT(contour)
                break;
        }
@@ -1568,17 +1029,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        case VIDIOCPWCSBACKLIGHT:
        {
                ARG_DEF(int, backlight)
-
                ARG_IN(backlight)
-               ret = pwc_set_backlight(pdev, ARGR(backlight));
+               ret = v4l2_ctrl_s_ctrl(pdev->backlight, ARGR(backlight));
                break;
        }
 
        case VIDIOCPWCGBACKLIGHT:
        {
                ARG_DEF(int, backlight)
-
-               ret = pwc_get_backlight(pdev, ARGA(backlight));
+               ARGR(backlight) = v4l2_ctrl_g_ctrl(pdev->backlight);
                ARG_OUT(backlight)
                break;
        }
@@ -1586,17 +1045,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        case VIDIOCPWCSFLICKER:
        {
                ARG_DEF(int, flicker)
-
                ARG_IN(flicker)
-               ret = pwc_set_flicker(pdev, ARGR(flicker));
+               ret = v4l2_ctrl_s_ctrl(pdev->flicker, ARGR(flicker));
                break;
        }
 
        case VIDIOCPWCGFLICKER:
        {
                ARG_DEF(int, flicker)
-
-               ret = pwc_get_flicker(pdev, ARGA(flicker));
+               ARGR(flicker) = v4l2_ctrl_g_ctrl(pdev->flicker);
                ARG_OUT(flicker)
                break;
        }
@@ -1604,17 +1061,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        case VIDIOCPWCSDYNNOISE:
        {
                ARG_DEF(int, dynnoise)
-
                ARG_IN(dynnoise)
-               ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
+               ret = v4l2_ctrl_s_ctrl(pdev->noise_reduction, ARGR(dynnoise));
                break;
        }
 
        case VIDIOCPWCGDYNNOISE:
        {
                ARG_DEF(int, dynnoise)
-
-               ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
+               ARGR(dynnoise) = v4l2_ctrl_g_ctrl(pdev->noise_reduction);
                ARG_OUT(dynnoise);
                break;
        }
index c29593f589eb457bf3db97e96ca4724b9de0c15c..be0e02cb487f1ff2cba5f32fbccd1826056eb93f 100644 (file)
    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)
+int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer)
 {
+       struct pwc_dec1_private *pdec;
 
-}
-
-void pwc_dec1_exit(void)
-{
+       if (pwc->decompress_data == NULL) {
+               pdec = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
+               if (pdec == NULL)
+                       return -ENOMEM;
+               pwc->decompress_data = pdec;
+       }
+       pdec = pwc->decompress_data;
 
-
-
-}
-
-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;
 }
-
index 8b62ddcc5c7e72ac8d8598da73fbe7ebe9b925d1..a57d8601080babf0ca5ed403aef63220f900f2af 100644 (file)
@@ -22,8 +22,6 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-
-
 #ifndef PWC_DEC1_H
 #define PWC_DEC1_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);
+int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer);
 
 #endif
-
index 0c801b8f3eca5a621f635a63eb8e48238254d851..06a4e877ba40dea4d6b69e1050a7c3a364652376 100644 (file)
@@ -916,27 +916,5 @@ void pwc_dec23_decompress(const struct pwc_device *pwc,
                        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: */
index 1c55298ad1537866969acf557a9558b312441750..a0ac4f3dff81b6960a64c2158244f08d220eb1f8 100644 (file)
@@ -49,19 +49,9 @@ struct pwc_dec23_private
 
 };
 
-
-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: */
-
index b0bde5a87c8a8b08575973f3158dde40ed546cc2..51ca3589b1b5987b7a19284613d8bc894376e982 100644 (file)
@@ -2,6 +2,7 @@
    USB and Video4Linux interface part.
    (C) 1999-2004 Nemosoft Unv.
    (C) 2004-2006 Luc Saillard (luc@saillard.org)
+   (C) 2011 Hans de Goede <hdegoede@redhat.com>
 
    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.
@@ -74,7 +75,6 @@
 #include "pwc-timon.h"
 #include "pwc-dec23.h"
 #include "pwc-dec1.h"
-#include "pwc-uncompress.h"
 
 /* Function prototypes and driver templates */
 
@@ -116,6 +116,7 @@ MODULE_DEVICE_TABLE(usb, pwc_device_table);
 
 static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
 static void usb_pwc_disconnect(struct usb_interface *intf);
+static void pwc_isoc_cleanup(struct pwc_device *pdev);
 
 static struct usb_driver pwc_driver = {
        .name =                 "Philips webcam",       /* name */
@@ -127,14 +128,11 @@ static struct usb_driver pwc_driver = {
 #define MAX_DEV_HINTS  20
 #define MAX_ISOC_ERRORS        20
 
-static int default_size = PSZ_QCIF;
 static int default_fps = 10;
-static int default_fbufs = 3;   /* Default number of frame buffers */
-       int pwc_mbufs = 2;      /* Default number of mmap() buffers */
 #ifdef CONFIG_USB_PWC_DEBUG
        int pwc_trace = PWC_DEBUG_LEVEL;
 #endif
-static int power_save;
+static int power_save = -1;
 static int led_on = 100, led_off; /* defaults to LED that is on while in use */
 static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
 static struct {
@@ -173,389 +171,20 @@ static struct video_device pwc_template = {
 /***************************************************************************/
 /* Private functions */
 
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the area.
- */
-
-
-
-static void *pwc_rvmalloc(unsigned long size)
-{
-       void * mem;
-       unsigned long adr;
-
-       mem=vmalloc_32(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 pwc_rvfree(void * mem, unsigned long size)
-{
-       unsigned long adr;
-
-       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);
-}
-
-
-
-
-static int pwc_allocate_buffers(struct pwc_device *pdev)
-{
-       int i, err;
-       void *kbuf;
-
-       PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
-
-       if (pdev == NULL)
-               return -ENXIO;
-
-       /* Allocate Isochronuous pipe buffers */
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               if (pdev->sbuf[i].data == NULL) {
-                       kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
-                       if (kbuf == NULL) {
-                               PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
-                               return -ENOMEM;
-                       }
-                       PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
-                       pdev->sbuf[i].data = kbuf;
-               }
-       }
-
-       /* Allocate frame buffer structure */
-       if (pdev->fbuf == NULL) {
-               kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
-               if (kbuf == NULL) {
-                       PWC_ERROR("Failed to allocate frame buffer structure.\n");
-                       return -ENOMEM;
-               }
-               PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
-               pdev->fbuf = kbuf;
-       }
-
-       /* create frame buffers, and make circular ring */
-       for (i = 0; i < default_fbufs; i++) {
-               if (pdev->fbuf[i].data == NULL) {
-                       kbuf = vzalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
-                       if (kbuf == NULL) {
-                               PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
-                               return -ENOMEM;
-                       }
-                       PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
-                       pdev->fbuf[i].data = kbuf;
-               }
-       }
-
-       /* Allocate decompressor table space */
-       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 = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
-       if (kbuf == NULL) {
-               PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
-                               pwc_mbufs * pdev->len_per_image);
-               return -ENOMEM;
-       }
-       PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
-       pdev->image_data = kbuf;
-       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;
-
-       PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
-       return 0;
-}
-
-static void pwc_free_buffers(struct pwc_device *pdev)
-{
-       int i;
-
-       PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
-
-       if (pdev == NULL)
-               return;
-       /* Release Iso-pipe buffers */
-       for (i = 0; i < MAX_ISO_BUFS; i++)
-               if (pdev->sbuf[i].data != NULL) {
-                       PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
-                       kfree(pdev->sbuf[i].data);
-                       pdev->sbuf[i].data = NULL;
-               }
-
-       /* The same for frame buffers */
-       if (pdev->fbuf != NULL) {
-               for (i = 0; i < default_fbufs; i++) {
-                       if (pdev->fbuf[i].data != NULL) {
-                               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;
-                       }
-               }
-               kfree(pdev->fbuf);
-               pdev->fbuf = NULL;
-       }
-
-       /* Intermediate decompression buffer & tables */
-       if (pdev->decompress_data != NULL) {
-               PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
-               kfree(pdev->decompress_data);
-               pdev->decompress_data = NULL;
-       }
-
-       /* Release image buffers */
-       if (pdev->image_data != NULL) {
-               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;
-
-       PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
-}
-
-/* The frame & image buffer mess.
-
-   Yes, this is a mess. Well, it used to be simple, but alas...  In this
-   module, 3 buffers schemes are used to get the data from the USB bus to
-   the user program. The first scheme involves the ISO buffers (called thus
-   since they transport ISO data from the USB controller), and not really
-   interesting. Suffices to say the data from this buffer is quickly
-   gathered in an interrupt handler (pwc_isoc_handler) and placed into the
-   frame buffer.
-
-   The frame buffer is the second scheme, and is the central element here.
-   It collects the data from a single frame from the camera (hence, the
-   name). Frames are delimited by the USB camera with a short USB packet,
-   so that's easy to detect. The frame buffers form a list that is filled
-   by the camera+USB controller and drained by the user process through
-   either read() or mmap().
-
-   The image buffer is the third scheme, in which frames are decompressed
-   and converted into planar format. For mmap() there is more than
-   one image buffer available.
-
-   The frame buffers provide the image buffering. In case the user process
-   is a bit slow, this introduces lag and some undesired side-effects.
-   The problem arises when the frame buffer is full. I used to drop the last
-   frame, which makes the data in the queue stale very quickly. But dropping
-   the frame at the head of the queue proved to be a litte bit more difficult.
-   I tried a circular linked scheme, but this introduced more problems than
-   it solved.
-
-   Because filling and draining are completely asynchronous processes, this
-   requires some fiddling with pointers and mutexes.
-
-   Eventually, I came up with a system with 2 lists: an 'empty' frame list
-   and a 'full' frame list:
-     * Initially, all frame buffers but one are on the 'empty' list; the one
-       remaining buffer is our initial fill frame.
-     * If a frame is needed for filling, we try to take it from the 'empty'
-       list, unless that list is empty, in which case we take the buffer at
-       the head of the 'full' list.
-     * When our fill buffer has been filled, it is appended to the 'full'
-       list.
-     * If a frame is needed by read() or mmap(), it is taken from the head of
-       the 'full' list, handled, and then appended to the 'empty' list. If no
-       buffer is present on the 'full' list, we wait.
-   The advantage is that the buffer that is currently being decompressed/
-   converted, is on neither list, and thus not in our way (any other scheme
-   I tried had the problem of old data lingering in the queue).
-
-   Whatever strategy you choose, it always remains a tradeoff: with more
-   frame buffers the chances of a missed frame are reduced. On the other
-   hand, on slower machines it introduces lag because the queue will
-   always be full.
- */
-
-/**
-  \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
- */
-static int pwc_next_fill_frame(struct pwc_device *pdev)
-{
-       int ret;
-       unsigned long flags;
-
-       ret = 0;
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       if (pdev->fill_frame != NULL) {
-               /* append to 'full' list */
-               if (pdev->full_frames == NULL) {
-                       pdev->full_frames = pdev->fill_frame;
-                       pdev->full_frames_tail = pdev->full_frames;
-               }
-               else {
-                       pdev->full_frames_tail->next = pdev->fill_frame;
-                       pdev->full_frames_tail = pdev->fill_frame;
-               }
-       }
-       if (pdev->empty_frames != NULL) {
-               /* We have empty frames available. That's easy */
-               pdev->fill_frame = pdev->empty_frames;
-               pdev->empty_frames = pdev->empty_frames->next;
-       }
-       else {
-               /* Hmm. Take it from the full list */
-               /* sanity check */
-               if (pdev->full_frames == NULL) {
-                       PWC_ERROR("Neither empty or full frames available!\n");
-                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-                       return -EINVAL;
-               }
-               pdev->fill_frame = pdev->full_frames;
-               pdev->full_frames = pdev->full_frames->next;
-               ret = 1;
-       }
-       pdev->fill_frame->next = NULL;
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-       return ret;
-}
-
-
-/**
-  \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
-
-  If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
- */
-static void pwc_reset_buffers(struct pwc_device *pdev)
-{
-       int i;
-       unsigned long flags;
-
-       PWC_DEBUG_MEMORY(">> %s __enter__\n", __func__);
-
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       pdev->full_frames = NULL;
-       pdev->full_frames_tail = NULL;
-       for (i = 0; i < default_fbufs; i++) {
-               pdev->fbuf[i].filled = 0;
-               if (i > 0)
-                       pdev->fbuf[i].next = &pdev->fbuf[i - 1];
-               else
-                       pdev->fbuf->next = NULL;
-       }
-       pdev->empty_frames = &pdev->fbuf[default_fbufs - 1];
-       pdev->empty_frames_tail = pdev->fbuf;
-       pdev->read_frame = NULL;
-       pdev->fill_frame = pdev->empty_frames;
-       pdev->empty_frames = pdev->empty_frames->next;
-
-       pdev->image_read_pos = 0;
-       pdev->fill_image = 0;
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-
-       PWC_DEBUG_MEMORY("<< %s __leaving__\n", __func__);
-}
-
-
-/**
-  \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
- */
-int pwc_handle_frame(struct pwc_device *pdev)
+struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev)
 {
-       int ret = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       /* First grab our read_frame; this is removed from all lists, so
-          we can release the lock after this without problems */
-       if (pdev->read_frame != NULL) {
-               /* This can't theoretically happen */
-               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 {
-               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 lengthy 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;
-       }
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-       return ret;
-}
-
-/**
-  \brief Advance pointers of image buffer (after each user request)
-*/
-void pwc_next_image(struct pwc_device *pdev)
-{
-       pdev->image_used[pdev->fill_image] = 0;
-       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);
+       unsigned long flags = 0;
+       struct pwc_frame_buf *buf = NULL;
+
+       spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
+       if (list_empty(&pdev->queued_bufs))
+               goto leave;
+
+       buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, list);
+       list_del(&buf->list);
+leave:
+       spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
+       return buf;
 }
 
 static void pwc_snapshot_button(struct pwc_device *pdev, int down)
@@ -575,9 +204,9 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down)
 #endif
 }
 
-static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
+static void pwc_frame_complete(struct pwc_device *pdev)
 {
-       int awake = 0;
+       struct pwc_frame_buf *fbuf = pdev->fill_buf;
 
        /* 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
@@ -589,7 +218,6 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
                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) {
                        pwc_snapshot_button(pdev, ptr[0] & 0x01);
@@ -612,8 +240,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
                   */
                if (fbuf->filled == 4)
                        pdev->drop_frames++;
-       }
-       else if (pdev->type == 740 || pdev->type == 720) {
+       } else if (pdev->type == 740 || pdev->type == 720) {
                unsigned char *ptr = (unsigned char *)fbuf->data;
                if ((ptr[0] ^ pdev->vmirror) & 0x01) {
                        pwc_snapshot_button(pdev, ptr[0] & 0x01);
@@ -621,33 +248,23 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
                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)
+       /* In case we were instructed to drop the frame, do so silently. */
+       if (pdev->drop_frames > 0) {
                pdev->drop_frames--;
-       else {
+       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);
-
+               } else {
+                       fbuf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
+                       fbuf->vb.v4l2_buf.sequence = pdev->vframe_count;
+                       vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
+                       pdev->fill_buf = NULL;
+                       pdev->vsync = 0;
                }
        } /* !drop_frames */
        pdev->vframe_count++;
-       return awake;
 }
 
 /* This gets called for the Isochronous pipe (video). This is done in
@@ -655,24 +272,20 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
  */
 static void pwc_isoc_handler(struct urb *urb)
 {
-       struct pwc_device *pdev;
+       struct pwc_device *pdev = (struct pwc_device *)urb->context;
        int i, fst, flen;
-       int awake;
-       struct pwc_frame_buf *fbuf;
-       unsigned char *fillptr = NULL, *iso_buf = NULL;
+       unsigned char *iso_buf = NULL;
 
-       awake = 0;
-       pdev = (struct pwc_device *)urb->context;
-       if (pdev == NULL) {
-               PWC_ERROR("isoc_handler() called with NULL device?!\n");
-               return;
-       }
-
-       if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+       if (urb->status == -ENOENT || urb->status == -ECONNRESET ||
+           urb->status == -ESHUTDOWN) {
                PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
                return;
        }
-       if (urb->status != -EINPROGRESS && urb->status != 0) {
+
+       if (pdev->fill_buf == NULL)
+               pdev->fill_buf = pwc_get_next_fill_buf(pdev);
+
+       if (urb->status != 0) {
                const char *errmsg;
 
                errmsg = "Unknown";
@@ -684,29 +297,21 @@ static void pwc_isoc_handler(struct urb *urb)
                        case -EILSEQ:           errmsg = "CRC/Timeout (could be anything)"; break;
                        case -ETIME:            errmsg = "Device does not respond"; break;
                }
-               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.
-                */
+               PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n",
+                         urb->status, errmsg);
+               /* Give up after a number of contiguous errors */
                if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
                {
-                       PWC_INFO("Too many ISOC errors, bailing out.\n");
-                       pdev->error_status = EIO;
-                       awake = 1;
-                       wake_up_interruptible(&pdev->frameq);
+                       PWC_ERROR("Too many ISOC errors, bailing out.\n");
+                       if (pdev->fill_buf) {
+                               vb2_buffer_done(&pdev->fill_buf->vb,
+                                               VB2_BUF_STATE_ERROR);
+                               pdev->fill_buf = NULL;
+                       }
                }
-               goto handler_end; // ugly, but practical
-       }
-
-       fbuf = pdev->fill_frame;
-       if (fbuf == NULL) {
-               PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
-               awake = 1;
+               pdev->vsync = 0; /* Drop the current frame */
                goto handler_end;
        }
-       else {
-               fillptr = fbuf->data + fbuf->filled;
-       }
 
        /* Reset ISOC error counter. We did get here, after all. */
        pdev->visoc_errors = 0;
@@ -720,89 +325,73 @@ static void pwc_isoc_handler(struct urb *urb)
                fst  = urb->iso_frame_desc[i].status;
                flen = urb->iso_frame_desc[i].actual_length;
                iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-               if (fst == 0) {
-                       if (flen > 0) { /* if valid data... */
-                               if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */
-                                       pdev->vsync = 2;
-
-                                       /* ...copy data to frame buffer, if possible */
-                                       if (flen + fbuf->filled > 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++;
-                                       }
-                                       else {
-                                               memmove(fillptr, iso_buf, flen);
-                                               fillptr += flen;
-                                       }
-                               }
+               if (fst != 0) {
+                       PWC_ERROR("Iso frame %d has error %d\n", i, fst);
+                       continue;
+               }
+               if (flen > 0 && pdev->vsync) {
+                       struct pwc_frame_buf *fbuf = pdev->fill_buf;
+
+                       if (pdev->vsync == 1) {
+                               do_gettimeofday(&fbuf->vb.v4l2_buf.timestamp);
+                               pdev->vsync = 2;
+                       }
+
+                       if (flen + fbuf->filled > pdev->frame_total_size) {
+                               PWC_ERROR("Frame overflow (%d > %d)\n",
+                                         flen + fbuf->filled,
+                                         pdev->frame_total_size);
+                               pdev->vsync = 0; /* Let's wait for an EOF */
+                       } else {
+                               memcpy(fbuf->data + fbuf->filled, iso_buf,
+                                      flen);
                                fbuf->filled += flen;
-                       } /* ..flen > 0 */
-
-                       if (flen < pdev->vlast_packet_size) {
-                               /* 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) {
-                                       if (pwc_rcv_short_packet(pdev, fbuf)) {
-                                               awake = 1;
-                                               fbuf = pdev->fill_frame;
-                                       }
-                               }
-                               fbuf->filled = 0;
-                               fillptr = fbuf->data;
+                       }
+               }
+               if (flen < pdev->vlast_packet_size) {
+                       /* Shorter packet... end of frame */
+                       if (pdev->vsync == 2)
+                               pwc_frame_complete(pdev);
+                       if (pdev->fill_buf == NULL)
+                               pdev->fill_buf = pwc_get_next_fill_buf(pdev);
+                       if (pdev->fill_buf) {
+                               pdev->fill_buf->filled = 0;
                                pdev->vsync = 1;
                        }
-
-                       pdev->vlast_packet_size = flen;
-               } /* ..status == 0 */
-               else {
-                       /* This is normally not interesting to the user, unless
-                        * you are really debugging something, default = 0 */
-                       static int iso_error;
-                       iso_error++;
-                       if (iso_error < 20)
-                               PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
                }
+               pdev->vlast_packet_size = flen;
        }
 
 handler_end:
-       if (awake)
-               wake_up_interruptible(&pdev->frameq);
-
-       urb->dev = pdev->udev;
        i = usb_submit_urb(urb, GFP_ATOMIC);
        if (i != 0)
                PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
 }
 
-
-int pwc_isoc_init(struct pwc_device *pdev)
+static int pwc_isoc_init(struct pwc_device *pdev)
 {
        struct usb_device *udev;
        struct urb *urb;
        int i, j, ret;
-
        struct usb_interface *intf;
        struct usb_host_interface *idesc = NULL;
 
-       if (pdev == NULL)
-               return -EFAULT;
        if (pdev->iso_init)
                return 0;
+
        pdev->vsync = 0;
+       pdev->vlast_packet_size = 0;
+       pdev->fill_buf = NULL;
+       pdev->vframe_count = 0;
+       pdev->visoc_errors = 0;
        udev = pdev->udev;
 
        /* 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);
-
        if (!idesc)
-               return -EFAULT;
+               return -EIO;
 
        /* Search video endpoint */
        pdev->vmax_packet_size = -1;
@@ -825,34 +414,32 @@ int pwc_isoc_init(struct pwc_device *pdev)
        if (ret < 0)
                return ret;
 
+       /* Allocate and init Isochronuous urbs */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
                if (urb == NULL) {
                        PWC_ERROR("Failed to allocate urb %d\n", i);
-                       ret = -ENOMEM;
-                       break;
+                       pdev->iso_init = 1;
+                       pwc_isoc_cleanup(pdev);
+                       return -ENOMEM;
                }
-               pdev->sbuf[i].urb = urb;
+               pdev->urbs[i] = urb;
                PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
-       }
-       if (ret) {
-               /* De-allocate in reverse order */
-               while (i--) {
-                       usb_free_urb(pdev->sbuf[i].urb);
-                       pdev->sbuf[i].urb = NULL;
-               }
-               return ret;
-       }
-
-       /* init URB structure */
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               urb = pdev->sbuf[i].urb;
 
                urb->interval = 1; // devik
                urb->dev = udev;
                urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = pdev->sbuf[i].data;
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_buffer = usb_alloc_coherent(udev,
+                                                         ISO_BUFFER_SIZE,
+                                                         GFP_KERNEL,
+                                                         &urb->transfer_dma);
+               if (urb->transfer_buffer == NULL) {
+                       PWC_ERROR("Failed to allocate urb buffer %d\n", i);
+                       pdev->iso_init = 1;
+                       pwc_isoc_cleanup(pdev);
+                       return -ENOMEM;
+               }
                urb->transfer_buffer_length = ISO_BUFFER_SIZE;
                urb->complete = pwc_isoc_handler;
                urb->context = pdev;
@@ -866,14 +453,14 @@ int pwc_isoc_init(struct pwc_device *pdev)
 
        /* link */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
-               ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
+               ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL);
                if (ret) {
                        PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
                        pdev->iso_init = 1;
                        pwc_isoc_cleanup(pdev);
                        return ret;
                }
-               PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+               PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->urbs[i]);
        }
 
        /* All is done... */
@@ -888,12 +475,9 @@ static void pwc_iso_stop(struct pwc_device *pdev)
 
        /* Unlinking ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
-               struct urb *urb;
-
-               urb = pdev->sbuf[i].urb;
-               if (urb) {
-                       PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
-                       usb_kill_urb(urb);
+               if (pdev->urbs[i]) {
+                       PWC_DEBUG_MEMORY("Unlinking URB %p\n", pdev->urbs[i]);
+                       usb_kill_urb(pdev->urbs[i]);
                }
        }
 }
@@ -904,40 +488,51 @@ static void pwc_iso_free(struct pwc_device *pdev)
 
        /* Freeing ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
-               struct urb *urb;
-
-               urb = pdev->sbuf[i].urb;
-               if (urb) {
+               if (pdev->urbs[i]) {
                        PWC_DEBUG_MEMORY("Freeing URB\n");
-                       usb_free_urb(urb);
-                       pdev->sbuf[i].urb = NULL;
+                       if (pdev->urbs[i]->transfer_buffer) {
+                               usb_free_coherent(pdev->udev,
+                                       pdev->urbs[i]->transfer_buffer_length,
+                                       pdev->urbs[i]->transfer_buffer,
+                                       pdev->urbs[i]->transfer_dma);
+                       }
+                       usb_free_urb(pdev->urbs[i]);
+                       pdev->urbs[i] = NULL;
                }
        }
 }
 
-void pwc_isoc_cleanup(struct pwc_device *pdev)
+static void pwc_isoc_cleanup(struct pwc_device *pdev)
 {
        PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
-       if (pdev == NULL)
-               return;
+
        if (pdev->iso_init == 0)
                return;
 
        pwc_iso_stop(pdev);
        pwc_iso_free(pdev);
-
-       /* Stop camera, but only if we are sure the camera is still there (unplug
-          is signalled by EPIPE)
-        */
-       if (pdev->error_status != EPIPE) {
-               PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
-               usb_set_interface(pdev->udev, 0, 0);
-       }
+       usb_set_interface(pdev->udev, 0, 0);
 
        pdev->iso_init = 0;
        PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
 }
 
+/*
+ * Release all queued buffers, no need to take queued_bufs_lock, since all
+ * iso urbs have been killed when we're called so pwc_isoc_handler won't run.
+ */
+static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
+{
+       while (!list_empty(&pdev->queued_bufs)) {
+               struct pwc_frame_buf *buf;
+
+               buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf,
+                                list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+}
+
 /*********
  * sysfs
  *********/
@@ -1051,98 +646,15 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
 
 static int pwc_video_open(struct file *file)
 {
-       int i, ret;
        struct video_device *vdev = video_devdata(file);
        struct pwc_device *pdev;
 
        PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
 
        pdev = video_get_drvdata(vdev);
-       BUG_ON(!pdev);
-       if (pdev->vopen) {
-               PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
-               return -EBUSY;
-       }
-
-       pwc_construct(pdev); /* set min/max sizes correct */
-       if (!pdev->usb_init) {
-               PWC_DEBUG_OPEN("Doing first time initialization.\n");
-               pdev->usb_init = 1;
-
-               /* Query sensor type */
-               ret = pwc_get_cmos_sensor(pdev, &i);
-               if (ret >= 0)
-               {
-                       PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
-                                       pdev->vdev.name,
-                                       pwc_sensor_type_to_string(i), i);
-               }
-       }
-
-       /* Turn on camera */
-       if (power_save) {
-               i = pwc_camera_power(pdev, 1);
-               if (i < 0)
-                       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)
-               PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
-
-
-       /* So far, so good. Allocate memory. */
-       i = pwc_allocate_buffers(pdev);
-       if (i < 0) {
-               PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
-               pwc_free_buffers(pdev);
-               return i;
-       }
-
-       /* Reset buffers & parameters */
-       pwc_reset_buffers(pdev);
-       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;
-       pwc_construct(pdev); /* set min/max sizes correct */
-
-       /* Set some defaults */
-       pdev->vsnapshot = 0;
-
-       /* Set video size, first try the last used video size
-          (or the default one); if that fails try QCIF/10 or QSIF/10;
-          it that fails too, give up.
-        */
-       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)  {
-               unsigned int default_resolution;
-               PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
-               if (pdev->type>= 730)
-                       default_resolution = PSZ_QSIF;
-               else
-                       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) {
-               PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
-               pwc_free_buffers(pdev);
-               return i;
-       }
-
-       /* Initialize the webcam to sane value */
-       pwc_set_brightness(pdev, 0x7fff);
-       pwc_set_agc(pdev, 1, 0);
+       if (!pdev->udev)
+               return -ENODEV;
 
-       pdev->vopen++;
        file->private_data = vdev;
        PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
        return 0;
@@ -1158,239 +670,211 @@ static void pwc_video_release(struct video_device *vfd)
                if (device_hint[hint].pdev == pdev)
                        device_hint[hint].pdev = NULL;
 
+       /* Free intermediate decompression buffer & tables */
+       if (pdev->decompress_data != NULL) {
+               PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n",
+                                pdev->decompress_data);
+               kfree(pdev->decompress_data);
+               pdev->decompress_data = NULL;
+       }
+
+       v4l2_ctrl_handler_free(&pdev->ctrl_handler);
+
        kfree(pdev);
 }
 
-/* Note that all cleanup is done in the reverse order as in _open */
 static int pwc_video_close(struct file *file)
 {
        struct video_device *vdev = file->private_data;
        struct pwc_device *pdev;
-       int i;
 
        PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
 
        pdev = video_get_drvdata(vdev);
-       if (pdev->vopen == 0)
-               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)
-               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);
-
-       if (DEVICE_USE_CODEC1(pdev->type))
-           pwc_dec1_exit();
-       else
-           pwc_dec23_exit();
-
-       pwc_isoc_cleanup(pdev);
-       pwc_free_buffers(pdev);
-
-       /* Turn off LEDS and power down camera, but only when not unplugged */
-       if (!pdev->unplugged) {
-               /* Turn LEDs off */
-               if (pwc_set_leds(pdev, 0, 0) < 0)
-                       PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
-               if (power_save) {
-                       i = pwc_camera_power(pdev, 0);
-                       if (i < 0)
-                               PWC_ERROR("Failed to power down camera (%d)\n", i);
-               }
-               pdev->vopen--;
-               PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
+       if (pdev->capt_file == file) {
+               vb2_queue_release(&pdev->vb_queue);
+               pdev->capt_file = NULL;
        }
 
+       PWC_DEBUG_OPEN("<< video_close()\n");
        return 0;
 }
 
-/*
- *     FIXME: what about two parallel reads ????
- *      ANSWER: Not supported. You can't open the device more than once,
-               despite what the V4L1 interface says. First, I don't see
-               the need, second there's no mechanism of alerting the
-               2nd/3rd/... process of events like changing image size.
-               And I don't see the point of blocking that for the
-               2nd/3rd/... process.
-               In multi-threaded environments reading parallel from any
-               device is tricky anyhow.
- */
-
 static ssize_t pwc_video_read(struct file *file, char __user *buf,
-                         size_t count, loff_t *ppos)
+                             size_t count, loff_t *ppos)
 {
        struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       int noblock = file->f_flags & O_NONBLOCK;
-       DECLARE_WAITQUEUE(wait, current);
-       int bytes_to_read, rv = 0;
-       void *image_buffer_addr;
-
-       PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
-                       vdev, buf, count);
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = video_get_drvdata(vdev);
-       if (pdev == NULL)
-               return -EFAULT;
+       struct pwc_device *pdev = video_get_drvdata(vdev);
 
-       if (pdev->error_status) {
-               rv = -pdev->error_status; /* Something happened, report what. */
-               goto err_out;
-       }
+       if (!pdev->udev)
+               return -ENODEV;
 
-       /* Start the stream (if not already started) */
-       rv = pwc_isoc_init(pdev);
-       if (rv)
-               goto err_out;
-
-       /* In case we're doing partial reads, we don't have to wait for a frame */
-       if (pdev->image_read_pos == 0) {
-               /* Do wait queueing according to the (doc)book */
-               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);
-                               rv = -pdev->error_status ;
-                               goto err_out;
-                       }
-                       if (noblock) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               rv = -EWOULDBLOCK;
-                               goto err_out;
-                       }
-                       if (signal_pending(current)) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               rv = -ERESTARTSYS;
-                               goto err_out;
-                       }
-                       mutex_unlock(&pdev->modlock);
-                       schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       mutex_lock(&pdev->modlock);
-               }
-               remove_wait_queue(&pdev->frameq, &wait);
-               set_current_state(TASK_RUNNING);
+       if (pdev->capt_file != NULL &&
+           pdev->capt_file != file)
+               return -EBUSY;
 
-               /* Decompress and release frame */
-               if (pwc_handle_frame(pdev)) {
-                       rv = -EFAULT;
-                       goto err_out;
-               }
-       }
+       pdev->capt_file = file;
 
-       PWC_DEBUG_READ("Copying data to user space.\n");
-       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
-               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;
-       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)) {
-               rv = -EFAULT;
-               goto err_out;
-       }
-       pdev->image_read_pos += count;
-       if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
-               pdev->image_read_pos = 0;
-               pwc_next_image(pdev);
-       }
-       return count;
-err_out:
-       return rv;
+       return vb2_read(&pdev->vb_queue, buf, count, ppos,
+                       file->f_flags & O_NONBLOCK);
 }
 
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
 {
        struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       int ret;
+       struct pwc_device *pdev = video_get_drvdata(vdev);
 
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = video_get_drvdata(vdev);
-       if (pdev == NULL)
-               return -EFAULT;
+       if (!pdev->udev)
+               return POLL_ERR;
 
-       /* Start the stream (if not already started) */
-       ret = pwc_isoc_init(pdev);
-       if (ret)
-               return ret;
+       return vb2_poll(&pdev->vb_queue, file, wait);
+}
+
+static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev = video_get_drvdata(vdev);
+
+       if (pdev->capt_file != file)
+               return -EBUSY;
+
+       return vb2_mmap(&pdev->vb_queue, vma);
+}
+
+/***************************************************************************/
+/* Videobuf2 operations */
+
+static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                               unsigned int *nplanes, unsigned long sizes[],
+                               void *alloc_ctxs[])
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vq);
+
+       if (*nbuffers < MIN_FRAMES)
+               *nbuffers = MIN_FRAMES;
+       else if (*nbuffers > MAX_FRAMES)
+               *nbuffers = MAX_FRAMES;
+
+       *nplanes = 1;
 
-       poll_wait(file, &pdev->frameq, wait);
-       if (pdev->error_status)
-               return POLLERR;
-       if (pdev->full_frames != NULL) /* we have frames waiting */
-               return (POLLIN | POLLRDNORM);
+       sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
 
        return 0;
 }
 
-static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
+static int buffer_init(struct vb2_buffer *vb)
 {
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       unsigned long start;
-       unsigned long size;
-       unsigned long page, pos = 0;
-       int index;
+       struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
 
-       PWC_DEBUG_MEMORY(">> %s\n", __func__);
-       pdev = video_get_drvdata(vdev);
-       size = vma->vm_end - vma->vm_start;
-       start = vma->vm_start;
+       /* need vmalloc since frame buffer > 128K */
+       buf->data = vzalloc(PWC_FRAME_SIZE);
+       if (buf->data == NULL)
+               return -ENOMEM;
 
-       /* 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;
+       return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
+
+       /* Don't allow queing new buffers after device disconnection */
+       if (!pdev->udev)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int buffer_finish(struct vb2_buffer *vb)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
+       struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
+
+       /*
+        * Application has called dqbuf and is getting back a buffer we've
+        * filled, take the pwc data we've stored in buf->data and decompress
+        * it into a usable format, storing the result in the vb2_buffer
+        */
+       return pwc_decompress(pdev, buf);
+}
+
+static void buffer_cleanup(struct vb2_buffer *vb)
+{
+       struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
+
+       vfree(buf->data);
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
+       struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
+       list_add_tail(&buf->list, &pdev->queued_bufs);
+       spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
+}
+
+static int start_streaming(struct vb2_queue *vq)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vq);
+
+       if (!pdev->udev)
+               return -ENODEV;
+
+       /* Turn on camera and set LEDS on */
+       pwc_camera_power(pdev, 1);
+       if (pdev->power_save) {
+               /* Restore video mode */
+               pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y,
+                                  pdev->vframes, pdev->vcompression,
+                                  pdev->vsnapshot);
        }
-       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;
-
-       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)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
+       pwc_set_leds(pdev, led_on, led_off);
+
+       return pwc_isoc_init(pdev);
+}
+
+static int stop_streaming(struct vb2_queue *vq)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vq);
+
+       if (pdev->udev) {
+               pwc_set_leds(pdev, 0, 0);
+               pwc_camera_power(pdev, 0);
+               pwc_isoc_cleanup(pdev);
        }
+       pwc_cleanup_queued_bufs(pdev);
+
        return 0;
 }
 
+static void pwc_lock(struct vb2_queue *vq)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vq);
+       mutex_lock(&pdev->modlock);
+}
+
+static void pwc_unlock(struct vb2_queue *vq)
+{
+       struct pwc_device *pdev = vb2_get_drv_priv(vq);
+       mutex_unlock(&pdev->modlock);
+}
+
+static struct vb2_ops pwc_vb_queue_ops = {
+       .queue_setup            = queue_setup,
+       .buf_init               = buffer_init,
+       .buf_prepare            = buffer_prepare,
+       .buf_finish             = buffer_finish,
+       .buf_cleanup            = buffer_cleanup,
+       .buf_queue              = buffer_queue,
+       .start_streaming        = start_streaming,
+       .stop_streaming         = stop_streaming,
+       .wait_prepare           = pwc_unlock,
+       .wait_finish            = pwc_lock,
+};
+
 /***************************************************************************/
 /* USB functions */
 
@@ -1406,6 +890,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        int hint, rc;
        int features = 0;
        int video_nr = -1; /* default: use next available device */
+       int my_power_save = power_save;
        char serial_number[30], *name;
 
        vendor_id = le16_to_cpu(udev->descriptor.idVendor);
@@ -1513,6 +998,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                        PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
                        name = "Logitech QuickCam Pro 4000";
                        type_id = 740; /* CCD sensor */
+                       if (my_power_save == -1)
+                               my_power_save = 1;
                        break;
                case 0x08b3:
                        PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
@@ -1523,12 +1010,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                        PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
                        name = "Logitech QuickCam Zoom";
                        type_id = 740; /* CCD sensor */
-                       power_save = 1;
+                       if (my_power_save == -1)
+                               my_power_save = 1;
                        break;
                case 0x08b5:
                        PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
                        name = "Logitech QuickCam Orbit";
                        type_id = 740; /* CCD sensor */
+                       if (my_power_save == -1)
+                               my_power_save = 1;
                        features |= FEATURE_MOTOR_PANTILT;
                        break;
                case 0x08b6:
@@ -1583,6 +1073,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                        PWC_INFO("Creative Labs Webcam 5 detected.\n");
                        name = "Creative Labs Webcam 5";
                        type_id = 730;
+                       if (my_power_save == -1)
+                               my_power_save = 1;
                        break;
                case 0x4011:
                        PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
@@ -1640,6 +1132,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        else
                return -ENODEV; /* Not any of the know types; but the list keeps growing. */
 
+       if (my_power_save == -1)
+               my_power_save = 0;
+
        memset(serial_number, 0, 30);
        usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
        PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
@@ -1654,7 +1149,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                return -ENOMEM;
        }
        pdev->type = type_id;
-       pdev->vsize = default_size;
        pdev->vframes = default_fps;
        strcpy(pdev->serial, serial_number);
        pdev->features = features;
@@ -1668,13 +1162,26 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                pdev->angle_range.tilt_min = -3000;
                pdev->angle_range.tilt_max =  2500;
        }
+       pwc_construct(pdev); /* set min/max sizes correct */
 
        mutex_init(&pdev->modlock);
-       spin_lock_init(&pdev->ptrlock);
+       mutex_init(&pdev->udevlock);
+       spin_lock_init(&pdev->queued_bufs_lock);
+       INIT_LIST_HEAD(&pdev->queued_bufs);
 
        pdev->udev = udev;
-       init_waitqueue_head(&pdev->frameq);
        pdev->vcompression = pwc_preferred_compression;
+       pdev->power_save = my_power_save;
+
+       /* Init videobuf2 queue structure */
+       memset(&pdev->vb_queue, 0, sizeof(pdev->vb_queue));
+       pdev->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       pdev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+       pdev->vb_queue.drv_priv = pdev;
+       pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf);
+       pdev->vb_queue.ops = &pwc_vb_queue_ops;
+       pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
+       vb2_queue_init(&pdev->vb_queue);
 
        /* Init video_device structure */
        memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
@@ -1707,14 +1214,40 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
        usb_set_intfdata(intf, pdev);
 
+#ifdef CONFIG_USB_PWC_DEBUG
+       /* Query sensor type */
+       if (pwc_get_cmos_sensor(pdev, &rc) >= 0) {
+               PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
+                               pdev->vdev.name,
+                               pwc_sensor_type_to_string(rc), rc);
+       }
+#endif
+
        /* Set the leds off */
        pwc_set_leds(pdev, 0, 0);
+
+       /* Setup intial videomode */
+       rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y,
+                               pdev->vframes, pdev->vcompression, 0);
+       if (rc)
+               goto err_free_mem;
+
+       /* Register controls (and read default values from camera */
+       rc = pwc_init_controls(pdev);
+       if (rc) {
+               PWC_ERROR("Failed to register v4l2 controls (%d).\n", rc);
+               goto err_free_mem;
+       }
+
+       pdev->vdev.ctrl_handler = &pdev->ctrl_handler;
+
+       /* And powerdown the camera until streaming starts */
        pwc_camera_power(pdev, 0);
 
        rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
        if (rc < 0) {
                PWC_ERROR("Failed to register as video device (%d).\n", rc);
-               goto err_free_mem;
+               goto err_free_controls;
        }
        rc = pwc_create_sysfs_files(pdev);
        if (rc)
@@ -1757,7 +1290,10 @@ err_video_unreg:
        if (hint < MAX_DEV_HINTS)
                device_hint[hint].pdev = NULL;
        video_unregister_device(&pdev->vdev);
+err_free_controls:
+       v4l2_ctrl_handler_free(&pdev->ctrl_handler);
 err_free_mem:
+       usb_set_intfdata(intf, NULL);
        kfree(pdev);
        return rc;
 }
@@ -1767,33 +1303,17 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
 {
        struct pwc_device *pdev  = usb_get_intfdata(intf);
 
+       mutex_lock(&pdev->udevlock);
        mutex_lock(&pdev->modlock);
-       usb_set_intfdata (intf, NULL);
-       if (pdev == NULL) {
-               PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
-               goto disconnect_out;
-       }
-       if (pdev->udev == NULL) {
-               PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
-               goto disconnect_out;
-       }
-       if (pdev->udev != interface_to_usbdev(intf)) {
-               PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
-               goto disconnect_out;
-       }
-
-       /* We got unplugged; this is signalled by an EPIPE error code */
-       pdev->error_status = EPIPE;
-       pdev->unplugged = 1;
-
-       /* Alert waiting processes */
-       wake_up_interruptible(&pdev->frameq);
 
+       usb_set_intfdata(intf, NULL);
        /* No need to keep the urbs around after disconnection */
        pwc_isoc_cleanup(pdev);
+       pwc_cleanup_queued_bufs(pdev);
+       pdev->udev = NULL;
 
-disconnect_out:
        mutex_unlock(&pdev->modlock);
+       mutex_unlock(&pdev->udevlock);
 
        pwc_remove_sysfs_files(pdev);
        video_unregister_device(&pdev->vdev);
@@ -1809,36 +1329,27 @@ disconnect_out:
  * Initialization code & module stuff
  */
 
-static char *size;
 static int fps;
-static int fbufs;
-static int mbufs;
 static int compression = -1;
 static int leds[2] = { -1, -1 };
 static unsigned int leds_nargs;
 static char *dev_hint[MAX_DEV_HINTS];
 static unsigned int dev_hint_nargs;
 
-module_param(size, charp, 0444);
 module_param(fps, int, 0444);
-module_param(fbufs, int, 0444);
-module_param(mbufs, int, 0444);
 #ifdef CONFIG_USB_PWC_DEBUG
 module_param_named(trace, pwc_trace, int, 0644);
 #endif
-module_param(power_save, int, 0444);
+module_param(power_save, int, 0644);
 module_param(compression, int, 0444);
 module_param_array(leds, int, &leds_nargs, 0444);
 module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
 
-MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
 MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
-MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
-MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
 #ifdef CONFIG_USB_PWC_DEBUG
 MODULE_PARM_DESC(trace, "For debugging purposes");
 #endif
-MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
+MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off");
 MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
 MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
 MODULE_PARM_DESC(dev_hint, "Device node hints");
@@ -1851,14 +1362,19 @@ MODULE_VERSION( PWC_VERSION );
 
 static int __init usb_pwc_init(void)
 {
-       int i, sz;
-       char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
+       int i;
 
+#ifdef CONFIG_USB_PWC_DEBUG
        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 (pwc_trace >= 0) {
+               PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
+       }
+#endif
+
        if (fps) {
                if (fps < 4 || fps > 30) {
                        PWC_ERROR("Framerate out of bounds (4-30).\n");
@@ -1868,41 +1384,6 @@ static int __init usb_pwc_init(void)
                PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
        }
 
-       if (size) {
-               /* string; try matching with array */
-               for (sz = 0; sz < PSZ_MAX; sz++) {
-                       if (!strcmp(sizenames[sz], size)) { /* Found! */
-                               default_size = sz;
-                               break;
-                       }
-               }
-               if (sz == PSZ_MAX) {
-                       PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
-                       return -EINVAL;
-               }
-               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) {
-                       PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
-                       return -EINVAL;
-               }
-               pwc_mbufs = mbufs;
-               PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
-       }
-       if (fbufs) {
-               if (fbufs < 2 || fbufs > MAX_FRAMES) {
-                       PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
-                       return -EINVAL;
-               }
-               default_fbufs = fbufs;
-               PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
-       }
-#ifdef CONFIG_USB_PWC_DEBUG
-       if (pwc_trace >= 0) {
-               PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
-       }
-#endif
        if (compression >= 0) {
                if (compression > 3) {
                        PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
@@ -1911,8 +1392,6 @@ static int __init usb_pwc_init(void)
                pwc_preferred_compression = compression;
                PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
        }
-       if (power_save)
-               PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
        if (leds[0] >= 0)
                led_on = leds[0];
        if (leds[1] >= 0)
diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h
deleted file mode 100644 (file)
index 8c0cae7..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-#ifndef PWC_IOCTL_H
-#define PWC_IOCTL_H
-
-/* (C) 2001-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
-*/
-
-/* This is pwc-ioctl.h belonging to PWC 10.0.10
-   It contains structures and defines to communicate from user space
-   directly to the driver.
- */
-
-/*
-   Changes
-   2001/08/03  Alvarado   Added ioctl constants to access methods for
-                         changing white balance and red/blue gains
-   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
-   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
-              PWCX easier
- */
-
-/* These are private ioctl() commands, specific for the Philips webcams.
-   They contain functions not found in other webcams, and settings not
-   specified in the Video4Linux API.
-
-   The #define names are built up like follows:
-   VIDIOC              VIDeo IOCtl prefix
-        PWC            Philps WebCam
-           G           optional: Get
-           S           optional: Set
-            ...        the function
- */
-
-#include <linux/types.h>
-#include <linux/version.h>
-
- /* Enumeration of image sizes */
-#define PSZ_SQCIF      0x00
-#define PSZ_QSIF       0x01
-#define PSZ_QCIF       0x02
-#define PSZ_SIF                0x03
-#define PSZ_CIF                0x04
-#define PSZ_VGA                0x05
-#define PSZ_MAX                6
-
-
-/* The frame rate is encoded in the video_window.flags parameter using
-   the upper 16 bits, since some flags are defined nowadays. The following
-   defines provide a mask and shift to filter out this value.
-   This value can also be passing using the private flag when using v4l2 and
-   VIDIOC_S_FMT ioctl.
-
-   In 'Snapshot' mode the camera freezes its automatic exposure and colour
-   balance controls.
- */
-#define PWC_FPS_SHIFT          16
-#define PWC_FPS_MASK           0x00FF0000
-#define PWC_FPS_FRMASK         0x003F0000
-#define PWC_FPS_SNAPSHOT       0x00400000
-#define PWC_QLT_MASK           0x03000000
-#define PWC_QLT_SHIFT          24
-
-
-/* structure for transferring x & y coordinates */
-struct pwc_coord
-{
-       int x, y;               /* guess what */
-       int size;               /* size, or offset */
-};
-
-
-/* Used with VIDIOCPWCPROBE */
-struct pwc_probe
-{
-       char name[32];
-       int type;
-};
-
-struct pwc_serial
-{
-       char serial[30];        /* String with serial number. Contains terminating 0 */
-};
-
-/* pwc_whitebalance.mode values */
-#define PWC_WB_INDOOR          0
-#define PWC_WB_OUTDOOR         1
-#define PWC_WB_FL              2
-#define PWC_WB_MANUAL          3
-#define PWC_WB_AUTO            4
-
-/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
-   Set mode to one of the PWC_WB_* values above.
-   *red and *blue are the respective gains of these colour components inside
-   the camera; range 0..65535
-   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read;
-   otherwise undefined.
-   'read_red' and 'read_blue' are read-only.
-*/
-struct pwc_whitebalance
-{
-       int mode;
-       int manual_red, manual_blue;    /* R/W */
-       int read_red, read_blue;        /* R/O */
-};
-
-/*
-   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
-   and tell the camera how fast it should react to changes in lighting, and
-   with how much delay. Valid values are 0..65535.
-*/
-struct pwc_wb_speed
-{
-       int control_speed;
-       int control_delay;
-
-};
-
-/* Used with VIDIOCPWC[SG]LED */
-struct pwc_leds
-{
-       int led_on;                     /* Led on-time; range = 0..25000 */
-       int led_off;                    /* Led off-time; range = 0..25000  */
-};
-
-/* Image size (used with GREALSIZE) */
-struct pwc_imagesize
-{
-       int width;
-       int height;
-};
-
-/* Defines and structures for Motorized Pan & Tilt */
-#define PWC_MPT_PAN            0x01
-#define PWC_MPT_TILT           0x02
-#define PWC_MPT_TIMEOUT                0x04 /* for status */
-
-/* Set angles; when absolute != 0, the angle is absolute and the
-   driver calculates the relative offset for you. This can only
-   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
-   absolute angles.
- */
-struct pwc_mpt_angles
-{
-       int absolute;           /* write-only */
-       int pan;                /* degrees * 100 */
-       int tilt;               /* degress * 100 */
-};
-
-/* Range of angles of the camera, both horizontally and vertically.
- */
-struct pwc_mpt_range
-{
-       int pan_min, pan_max;           /* degrees * 100 */
-       int tilt_min, tilt_max;
-};
-
-struct pwc_mpt_status
-{
-       int status;
-       int time_pan;
-       int time_tilt;
-};
-
-
-/* This is used for out-of-kernel decompression. With it, you can get
-   all the necessary information to initialize and use the decompressor
-   routines in standalone applications.
- */
-struct pwc_video_command
-{
-       int type;               /* camera type (645, 675, 730, etc.) */
-       int release;            /* release number */
-
-       int size;               /* one of PSZ_* */
-       int alternate;
-       int command_len;        /* length of USB video command */
-       unsigned char command_buf[13];  /* Actual USB video command */
-       int bandlength;         /* >0 = compressed */
-       int frame_size;         /* Size of one (un)compressed frame */
-};
-
-/* Flags for PWCX subroutines. Not all modules honour all flags. */
-#define PWCX_FLAG_PLANAR       0x0001
-#define PWCX_FLAG_BAYER                0x0008
-
-
-/* IOCTL definitions */
-
- /* Restore user settings */
-#define VIDIOCPWCRUSER         _IO('v', 192)
- /* Save user settings */
-#define VIDIOCPWCSUSER         _IO('v', 193)
- /* Restore factory settings */
-#define VIDIOCPWCFACTORY       _IO('v', 194)
-
- /* You can manipulate the compression factor. A compression preference of 0
-    means use uncompressed modes when available; 1 is low compression, 2 is
-    medium and 3 is high compression preferred. Of course, the higher the
-    compression, the lower the bandwidth used but more chance of artefacts
-    in the image. The driver automatically chooses a higher compression when
-    the preferred mode is not available.
-  */
- /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
-#define VIDIOCPWCSCQUAL                _IOW('v', 195, int)
- /* Get preferred compression quality */
-#define VIDIOCPWCGCQUAL                _IOR('v', 195, int)
-
-
-/* Retrieve serial number of camera */
-#define VIDIOCPWCGSERIAL       _IOR('v', 198, struct pwc_serial)
-
- /* This is a probe function; since so many devices are supported, it
-    becomes difficult to include all the names in programs that want to
-    check for the enhanced Philips stuff. So in stead, try this PROBE;
-    it returns a structure with the original name, and the corresponding
-    Philips type.
-    To use, fill the structure with zeroes, call PROBE and if that succeeds,
-    compare the name with that returned from VIDIOCGCAP; they should be the
-    same. If so, you can be assured it is a Philips (OEM) cam and the type
-    is valid.
- */
-#define VIDIOCPWCPROBE         _IOR('v', 199, struct pwc_probe)
-
- /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
-#define VIDIOCPWCSAGC          _IOW('v', 200, int)
- /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
-#define VIDIOCPWCGAGC          _IOR('v', 200, int)
- /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
-#define VIDIOCPWCSSHUTTER      _IOW('v', 201, int)
-
- /* Color compensation (Auto White Balance) */
-#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
-#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
-
- /* Auto WB speed */
-#define VIDIOCPWCSAWBSPEED     _IOW('v', 203, struct pwc_wb_speed)
-#define VIDIOCPWCGAWBSPEED     _IOR('v', 203, struct pwc_wb_speed)
-
- /* LEDs on/off/blink; int range 0..65535 */
-#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
-#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
-
-  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
-#define VIDIOCPWCSCONTOUR      _IOW('v', 206, int)
-#define VIDIOCPWCGCONTOUR      _IOR('v', 206, int)
-
-  /* Backlight compensation; 0 = off, otherwise on */
-#define VIDIOCPWCSBACKLIGHT    _IOW('v', 207, int)
-#define VIDIOCPWCGBACKLIGHT    _IOR('v', 207, int)
-
-  /* Flickerless mode; = 0 off, otherwise on */
-#define VIDIOCPWCSFLICKER      _IOW('v', 208, int)
-#define VIDIOCPWCGFLICKER      _IOR('v', 208, int)
-
-  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
-#define VIDIOCPWCSDYNNOISE     _IOW('v', 209, int)
-#define VIDIOCPWCGDYNNOISE     _IOR('v', 209, int)
-
- /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
-#define VIDIOCPWCGREALSIZE     _IOR('v', 210, struct pwc_imagesize)
-
- /* Motorized pan & tilt functions */
-#define VIDIOCPWCMPTRESET      _IOW('v', 211, int)
-#define VIDIOCPWCMPTGRANGE     _IOR('v', 211, struct pwc_mpt_range)
-#define VIDIOCPWCMPTSANGLE     _IOW('v', 212, struct pwc_mpt_angles)
-#define VIDIOCPWCMPTGANGLE     _IOR('v', 212, struct pwc_mpt_angles)
-#define VIDIOCPWCMPTSTATUS     _IOR('v', 213, struct pwc_mpt_status)
-
- /* Get the USB set-video command; needed for initializing libpwcx */
-#define VIDIOCPWCGVIDCMD       _IOR('v', 215, struct pwc_video_command)
-struct pwc_table_init_buffer {
-   int len;
-   char *buffer;
-
-};
-#define VIDIOCPWCGVIDTABLE     _IOR('v', 216, struct pwc_table_init_buffer)
-
-/*
- * This is private command used when communicating with v4l2.
- * In the future all private ioctl will be remove/replace to
- * use interface offer by v4l2.
- */
-
-#define V4L2_CID_PRIVATE_SAVE_USER       (V4L2_CID_PRIVATE_BASE + 0)
-#define V4L2_CID_PRIVATE_RESTORE_USER    (V4L2_CID_PRIVATE_BASE + 1)
-#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2)
-#define V4L2_CID_PRIVATE_COLOUR_MODE     (V4L2_CID_PRIVATE_BASE + 3)
-#define V4L2_CID_PRIVATE_AUTOCONTOUR     (V4L2_CID_PRIVATE_BASE + 4)
-#define V4L2_CID_PRIVATE_CONTOUR         (V4L2_CID_PRIVATE_BASE + 5)
-#define V4L2_CID_PRIVATE_BACKLIGHT       (V4L2_CID_PRIVATE_BASE + 6)
-#define V4L2_CID_PRIVATE_FLICKERLESS     (V4L2_CID_PRIVATE_BASE + 7)
-#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8)
-
-struct pwc_raw_frame {
-   __le16 type;                /* type of the webcam */
-   __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */
-   __u8   cmd[4];      /* the four byte of the command (in case of nala,
-                          only the first 3 bytes is filled) */
-   __u8   rawframe[0]; /* frame_size = H/4*vbandlength */
-} __attribute__ ((packed));
-
-
-#endif
index f4ae83c0cf2ba75ac26286c3906e84ba1a638035..e5f4fd81712591d1d0222f4f3c5b02d1674cf932 100644 (file)
@@ -40,7 +40,6 @@
 
 
 #include "pwc-kiara.h"
-#include "pwc-uncompress.h"
 
 const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA] = { 5, 10, 15, 20, 25, 30 };
 
index 6af5bb538358c95f2f5567e0a598cff05d75224a..0b031336eab84aa1272c0a299360c739eee5e950 100644 (file)
@@ -126,8 +126,4 @@ void pwc_construct(struct pwc_device *pdev)
        pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* 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 = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
 }
-
-
index 3b73f295f0329334bf1180f5844ddd2652fd2010..51265092bd312014308d9ed90e0369952963aedd 100644 (file)
 #include <asm/types.h>
 
 #include "pwc.h"
-#include "pwc-uncompress.h"
 #include "pwc-dec1.h"
 #include "pwc-dec23.h"
 
-int pwc_decompress(struct pwc_device *pdev)
+int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf)
 {
-       struct pwc_frame_buf *fbuf;
        int n, line, col, stride;
        void *yuv, *image;
        u16 *src;
        u16 *dsty, *dstu, *dstv;
 
-       if (pdev == NULL)
-               return -EFAULT;
-
-       fbuf = pdev->read_frame;
-       if (fbuf == NULL)
-               return -EFAULT;
-       image  = pdev->image_data;
-       image += pdev->images[pdev->fill_image].offset;
+       image = vb2_plane_vaddr(&fbuf->vb, 0);
 
        yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
 
@@ -64,9 +55,13 @@ int pwc_decompress(struct pwc_device *pdev)
                         * determine this using the type of the webcam */
                memcpy(raw_frame->cmd, pdev->cmd_buf, 4);
                memcpy(raw_frame+1, yuv, pdev->frame_size);
+               vb2_set_plane_payload(&fbuf->vb, 0,
+                       pdev->frame_size + sizeof(struct pwc_raw_frame));
                return 0;
        }
 
+       vb2_set_plane_payload(&fbuf->vb, 0, pdev->view.size);
+
        if (pdev->vbandlength == 0) {
                /* Uncompressed mode.
                 * We copy the data into the output buffer, using the viewport
diff --git a/drivers/media/video/pwc/pwc-uncompress.h b/drivers/media/video/pwc/pwc-uncompress.h
deleted file mode 100644 (file)
index 43028e7..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* (C) 1999-2003 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
-*/
-
-/* This file is the bridge between the kernel module and the plugin; it
-   describes the structures and datatypes used in both modules. Any
-   significant change should be reflected by increasing the
-   pwc_decompressor_version major number.
- */
-#ifndef PWC_UNCOMPRESS_H
-#define PWC_UNCOMPRESS_H
-
-
-#include <media/pwc-ioctl.h>
-
-/* from pwc-dec.h */
-#define PWCX_FLAG_PLANAR        0x0001
-/* */
-
-#endif
index f85c51249c7be48d78b45336baa35ffabd9e26c9..e9a0e94b9995003e26191583f4e91b8ba7690f56 100644 (file)
@@ -2,6 +2,7 @@
    USB and Video4Linux interface part.
    (C) 1999-2004 Nemosoft Unv.
    (C) 2004-2006 Luc Saillard (luc@saillard.org)
+   (C) 2011 Hans de Goede <hdegoede@redhat.com>
 
    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.
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/vmalloc.h>
+#include <linux/jiffies.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,
-       },
+#define PWC_CID_CUSTOM(ctrl) ((V4L2_CID_USER_BASE | 0xf000) + custom_ ## ctrl)
+
+static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
+static int pwc_s_ctrl(struct v4l2_ctrl *ctrl);
+
+static const struct v4l2_ctrl_ops pwc_ctrl_ops = {
+       .g_volatile_ctrl = pwc_g_volatile_ctrl,
+       .s_ctrl = pwc_s_ctrl,
+};
+
+enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto };
+enum { custom_autocontour, custom_contour, custom_noise_reduction,
+       custom_save_user, custom_restore_user, custom_restore_factory };
+
+const char * const pwc_auto_whitebal_qmenu[] = {
+       "Indoor (Incandescant Lighting) Mode",
+       "Outdoor (Sunlight) Mode",
+       "Indoor (Fluorescent Lighting) Mode",
+       "Manual Mode",
+       "Auto Mode",
+       NULL
+};
+
+static const struct v4l2_ctrl_config pwc_auto_white_balance_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = V4L2_CID_AUTO_WHITE_BALANCE,
+       .type   = V4L2_CTRL_TYPE_MENU,
+       .max    = awb_auto,
+       .qmenu  = pwc_auto_whitebal_qmenu,
+};
+
+static const struct v4l2_ctrl_config pwc_autocontour_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(autocontour),
+       .type   = V4L2_CTRL_TYPE_BOOLEAN,
+       .name   = "Auto contour",
+       .min    = 0,
+       .max    = 1,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_contour_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(contour),
+       .type   = V4L2_CTRL_TYPE_INTEGER,
+       .name   = "Contour",
+       .min    = 0,
+       .max    = 63,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_backlight_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = V4L2_CID_BACKLIGHT_COMPENSATION,
+       .type   = V4L2_CTRL_TYPE_BOOLEAN,
+       .min    = 0,
+       .max    = 1,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_flicker_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = V4L2_CID_BAND_STOP_FILTER,
+       .type   = V4L2_CTRL_TYPE_BOOLEAN,
+       .min    = 0,
+       .max    = 1,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_noise_reduction_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(noise_reduction),
+       .type   = V4L2_CTRL_TYPE_INTEGER,
+       .name   = "Dynamic Noise Reduction",
+       .min    = 0,
+       .max    = 3,
+       .step   = 1,
+};
+
+static const struct v4l2_ctrl_config pwc_save_user_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(save_user),
+       .type   = V4L2_CTRL_TYPE_BUTTON,
+       .name    = "Save User Settings",
 };
 
+static const struct v4l2_ctrl_config pwc_restore_user_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(restore_user),
+       .type   = V4L2_CTRL_TYPE_BUTTON,
+       .name    = "Restore User Settings",
+};
+
+static const struct v4l2_ctrl_config pwc_restore_factory_cfg = {
+       .ops    = &pwc_ctrl_ops,
+       .id     = PWC_CID_CUSTOM(restore_factory),
+       .type   = V4L2_CTRL_TYPE_BUTTON,
+       .name    = "Restore Factory Settings",
+};
+
+int pwc_init_controls(struct pwc_device *pdev)
+{
+       struct v4l2_ctrl_handler *hdl;
+       struct v4l2_ctrl_config cfg;
+       int r, def;
+
+       hdl = &pdev->ctrl_handler;
+       r = v4l2_ctrl_handler_init(hdl, 20);
+       if (r)
+               return r;
+
+       /* Brightness, contrast, saturation, gamma */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, BRIGHTNESS_FORMATTER, &def);
+       if (r || def > 127)
+               def = 63;
+       pdev->brightness = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_BRIGHTNESS, 0, 127, 1, def);
+
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, CONTRAST_FORMATTER, &def);
+       if (r || def > 63)
+               def = 31;
+       pdev->contrast = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_CONTRAST, 0, 63, 1, def);
+
+       if (pdev->type >= 675) {
+               if (pdev->type < 730)
+                       pdev->saturation_fmt = SATURATION_MODE_FORMATTER2;
+               else
+                       pdev->saturation_fmt = SATURATION_MODE_FORMATTER1;
+               r = pwc_get_s8_ctrl(pdev, GET_CHROM_CTL, pdev->saturation_fmt,
+                                   &def);
+               if (r || def < -100 || def > 100)
+                       def = 0;
+               pdev->saturation = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                                     V4L2_CID_SATURATION, -100, 100, 1, def);
+       }
+
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, GAMMA_FORMATTER, &def);
+       if (r || def > 31)
+               def = 15;
+       pdev->gamma = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_GAMMA, 0, 31, 1, def);
+
+       /* auto white balance, red gain, blue gain */
+       r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, WB_MODE_FORMATTER, &def);
+       if (r || def > awb_auto)
+               def = awb_auto;
+       cfg = pwc_auto_white_balance_cfg;
+       cfg.name = v4l2_ctrl_get_name(cfg.id);
+       cfg.def = def;
+       pdev->auto_white_balance = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+       /* check auto controls to avoid NULL deref in v4l2_ctrl_auto_cluster */
+       if (!pdev->auto_white_balance)
+               return hdl->error;
+
+       r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL,
+                           PRESET_MANUAL_RED_GAIN_FORMATTER, &def);
+       if (r)
+               def = 127;
+       pdev->red_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_RED_BALANCE, 0, 255, 1, def);
+
+       r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL,
+                           PRESET_MANUAL_BLUE_GAIN_FORMATTER, &def);
+       if (r)
+               def = 127;
+       pdev->blue_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_BLUE_BALANCE, 0, 255, 1, def);
+
+       v4l2_ctrl_auto_cluster(3, &pdev->auto_white_balance, awb_manual,
+                              pdev->auto_white_balance->cur.val == awb_auto);
+
+       /* autogain, gain */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AGC_MODE_FORMATTER, &def);
+       if (r || (def != 0 && def != 0xff))
+               def = 0;
+       /* Note a register value if 0 means auto gain is on */
+       pdev->autogain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_AUTOGAIN, 0, 1, 1, def == 0);
+       if (!pdev->autogain)
+               return hdl->error;
+
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_AGC_FORMATTER, &def);
+       if (r || def > 63)
+               def = 31;
+       pdev->gain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_GAIN, 0, 63, 1, def);
+
+       /* auto exposure, exposure */
+       if (DEVICE_USE_CODEC2(pdev->type)) {
+               r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, SHUTTER_MODE_FORMATTER,
+                                   &def);
+               if (r || (def != 0 && def != 0xff))
+                       def = 0;
+               /*
+                * def = 0 auto, def = ff manual
+                * menu idx 0 = auto, idx 1 = manual
+                */
+               pdev->exposure_auto = v4l2_ctrl_new_std_menu(hdl,
+                                       &pwc_ctrl_ops,
+                                       V4L2_CID_EXPOSURE_AUTO,
+                                       1, 0, def != 0);
+               if (!pdev->exposure_auto)
+                       return hdl->error;
+
+               /* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */
+               r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
+                                    READ_SHUTTER_FORMATTER, &def);
+               if (r || def > 655)
+                       def = 655;
+               pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                                       V4L2_CID_EXPOSURE, 0, 655, 1, def);
+               /* CODEC2: separate auto gain & auto exposure */
+               v4l2_ctrl_auto_cluster(2, &pdev->autogain, 0, true);
+               v4l2_ctrl_auto_cluster(2, &pdev->exposure_auto,
+                                      V4L2_EXPOSURE_MANUAL, true);
+       } else if (DEVICE_USE_CODEC3(pdev->type)) {
+               /* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */
+               r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
+                                    READ_SHUTTER_FORMATTER, &def);
+               if (r || def > 255)
+                       def = 255;
+               pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                                       V4L2_CID_EXPOSURE, 0, 255, 1, def);
+               /* CODEC3: both gain and exposure controlled by autogain */
+               pdev->autogain_expo_cluster[0] = pdev->autogain;
+               pdev->autogain_expo_cluster[1] = pdev->gain;
+               pdev->autogain_expo_cluster[2] = pdev->exposure;
+               v4l2_ctrl_auto_cluster(3, pdev->autogain_expo_cluster,
+                                      0, true);
+       }
+
+       /* color / bw setting */
+       r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, COLOUR_MODE_FORMATTER,
+                        &def);
+       if (r || (def != 0 && def != 0xff))
+               def = 0xff;
+       /* def = 0 bw, def = ff color, menu idx 0 = color, idx 1 = bw */
+       pdev->colorfx = v4l2_ctrl_new_std_menu(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_COLORFX, 1, 0, def == 0);
+
+       /* autocontour, contour */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &def);
+       if (r || (def != 0 && def != 0xff))
+               def = 0;
+       cfg = pwc_autocontour_cfg;
+       cfg.def = def == 0;
+       pdev->autocontour = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+       if (!pdev->autocontour)
+               return hdl->error;
+
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &def);
+       if (r || def > 63)
+               def = 31;
+       cfg = pwc_contour_cfg;
+       cfg.def = def;
+       pdev->contour = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
+       v4l2_ctrl_auto_cluster(2, &pdev->autocontour, 0, false);
+
+       /* backlight */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL,
+                           BACK_LIGHT_COMPENSATION_FORMATTER, &def);
+       if (r || (def != 0 && def != 0xff))
+               def = 0;
+       cfg = pwc_backlight_cfg;
+       cfg.name = v4l2_ctrl_get_name(cfg.id);
+       cfg.def = def == 0;
+       pdev->backlight = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
+       /* flikker rediction */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL,
+                           FLICKERLESS_MODE_FORMATTER, &def);
+       if (r || (def != 0 && def != 0xff))
+               def = 0;
+       cfg = pwc_flicker_cfg;
+       cfg.name = v4l2_ctrl_get_name(cfg.id);
+       cfg.def = def == 0;
+       pdev->flicker = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
+       /* Dynamic noise reduction */
+       r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL,
+                           DYNAMIC_NOISE_CONTROL_FORMATTER, &def);
+       if (r || def > 3)
+               def = 2;
+       cfg = pwc_noise_reduction_cfg;
+       cfg.def = def;
+       pdev->noise_reduction = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+
+       /* Save / Restore User / Factory Settings */
+       pdev->save_user = v4l2_ctrl_new_custom(hdl, &pwc_save_user_cfg, NULL);
+       pdev->restore_user = v4l2_ctrl_new_custom(hdl, &pwc_restore_user_cfg,
+                                                 NULL);
+       if (pdev->restore_user)
+               pdev->restore_user->flags = V4L2_CTRL_FLAG_UPDATE;
+       pdev->restore_factory = v4l2_ctrl_new_custom(hdl,
+                                                    &pwc_restore_factory_cfg,
+                                                    NULL);
+       if (pdev->restore_factory)
+               pdev->restore_factory->flags = V4L2_CTRL_FLAG_UPDATE;
+
+       if (!pdev->features & FEATURE_MOTOR_PANTILT)
+               return hdl->error;
+
+       /* Motor pan / tilt / reset */
+       pdev->motor_pan = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_PAN_RELATIVE, -4480, 4480, 64, 0);
+       if (!pdev->motor_pan)
+               return hdl->error;
+       pdev->motor_tilt = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_TILT_RELATIVE, -1920, 1920, 64, 0);
+       pdev->motor_pan_reset = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_PAN_RESET, 0, 0, 0, 0);
+       pdev->motor_tilt_reset = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
+                               V4L2_CID_TILT_RESET, 0, 0, 0, 0);
+       v4l2_ctrl_cluster(4, &pdev->motor_pan);
+
+       return hdl->error;
+}
 
 static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
 {
@@ -284,10 +431,21 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 }
 
 /* ioctl(VIDIOC_SET_FMT) */
-static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+
+static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
 {
+       struct pwc_device *pdev = video_drvdata(file);
        int ret, fps, snapshot, compression, pixelformat;
 
+       if (!pdev->udev)
+               return -ENODEV;
+
+       if (pdev->capt_file != NULL &&
+           pdev->capt_file != file)
+               return -EBUSY;
+
+       pdev->capt_file = file;
+
        ret = pwc_vidioc_try_fmt(pdev, f);
        if (ret<0)
                return ret;
@@ -309,7 +467,7 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
            pixelformat != V4L2_PIX_FMT_PWC2)
                return -EINVAL;
 
-       if (pdev->iso_init)
+       if (vb2_is_streaming(&pdev->vb_queue))
                return -EBUSY;
 
        PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
@@ -343,13 +501,14 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 
 static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
 {
-       struct video_device *vdev = video_devdata(file);
        struct pwc_device *pdev = video_drvdata(file);
 
+       if (!pdev->udev)
+               return -ENODEV;
+
        strcpy(cap->driver, PWC_NAME);
-       strlcpy(cap->card, vdev->name, sizeof(cap->card));
+       strlcpy(cap->card, pdev->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      |
@@ -377,255 +536,396 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i)
        return i ? -EINVAL : 0;
 }
 
-static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
+static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
-       int i, idx;
-       u32 id;
-
-       id = c->id;
-       if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
-               id &= V4L2_CTRL_ID_MASK;
-               id++;
-               idx = -1;
-               for (i = 0; i < ARRAY_SIZE(pwc_controls); i++) {
-                       if (pwc_controls[i].id < id)
-                               continue;
-                       if (idx >= 0
-                        && pwc_controls[i].id > pwc_controls[idx].id)
-                               continue;
-                       idx = i;
+       struct pwc_device *pdev =
+               container_of(ctrl->handler, struct pwc_device, ctrl_handler);
+       int ret = 0;
+
+       /*
+        * Sometimes it can take quite long for the pwc to complete usb control
+        * transfers, so release the modlock to give streaming by another
+        * process / thread the chance to continue with a dqbuf.
+        */
+       mutex_unlock(&pdev->modlock);
+
+       /*
+        * Take the udev-lock to protect against the disconnect handler
+        * completing and setting dev->udev to NULL underneath us. Other code
+        * does not need to do this since it is protected by the modlock.
+        */
+       mutex_lock(&pdev->udevlock);
+
+       if (!pdev->udev) {
+               ret = -ENODEV;
+               goto leave;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               if (pdev->color_bal_valid && time_before(jiffies,
+                               pdev->last_color_bal_update + HZ / 4)) {
+                       pdev->red_balance->val  = pdev->last_red_balance;
+                       pdev->blue_balance->val = pdev->last_blue_balance;
+                       break;
                }
-               if (idx < 0)
-                       return -EINVAL;
-               memcpy(c, &pwc_controls[idx], sizeof pwc_controls[0]);
-               return 0;
+               ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                     READ_RED_GAIN_FORMATTER,
+                                     &pdev->red_balance->val);
+               if (ret)
+                       break;
+               ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                     READ_BLUE_GAIN_FORMATTER,
+                                     &pdev->blue_balance->val);
+               if (ret)
+                       break;
+               pdev->last_red_balance  = pdev->red_balance->val;
+               pdev->last_blue_balance = pdev->blue_balance->val;
+               pdev->last_color_bal_update = jiffies;
+               pdev->color_bal_valid = true;
+               break;
+       case V4L2_CID_AUTOGAIN:
+               if (pdev->gain_valid && time_before(jiffies,
+                               pdev->last_gain_update + HZ / 4)) {
+                       pdev->gain->val = pdev->last_gain;
+                       break;
+               }
+               ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                     READ_AGC_FORMATTER, &pdev->gain->val);
+               if (ret)
+                       break;
+               pdev->last_gain = pdev->gain->val;
+               pdev->last_gain_update = jiffies;
+               pdev->gain_valid = true;
+               if (!DEVICE_USE_CODEC3(pdev->type))
+                       break;
+               /* Fall through for CODEC3 where autogain also controls expo */
+       case V4L2_CID_EXPOSURE_AUTO:
+               if (pdev->exposure_valid && time_before(jiffies,
+                               pdev->last_exposure_update + HZ / 4)) {
+                       pdev->exposure->val = pdev->last_exposure;
+                       break;
+               }
+               ret = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
+                                      READ_SHUTTER_FORMATTER,
+                                      &pdev->exposure->val);
+               if (ret)
+                       break;
+               pdev->last_exposure = pdev->exposure->val;
+               pdev->last_exposure_update = jiffies;
+               pdev->exposure_valid = true;
+               break;
+       default:
+               ret = -EINVAL;
        }
-       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;
+
+       if (ret)
+               PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret);
+
+leave:
+       mutex_unlock(&pdev->udevlock);
+       mutex_lock(&pdev->modlock);
+       return ret;
+}
+
+static int pwc_set_awb(struct pwc_device *pdev)
+{
+       int ret = 0;
+
+       if (pdev->auto_white_balance->is_new) {
+               ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+                                     WB_MODE_FORMATTER,
+                                     pdev->auto_white_balance->val);
+               if (ret)
+                       return ret;
+
+               /* Update val when coming from auto or going to a preset */
+               if (pdev->red_balance->is_volatile ||
+                   pdev->auto_white_balance->val == awb_indoor ||
+                   pdev->auto_white_balance->val == awb_outdoor ||
+                   pdev->auto_white_balance->val == awb_fl) {
+                       if (!pdev->red_balance->is_new)
+                               pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                       READ_RED_GAIN_FORMATTER,
+                                       &pdev->red_balance->val);
+                       if (!pdev->blue_balance->is_new)
+                               pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                       READ_BLUE_GAIN_FORMATTER,
+                                       &pdev->blue_balance->val);
+               }
+               if (pdev->auto_white_balance->val == awb_auto) {
+                       pdev->red_balance->is_volatile = true;
+                       pdev->blue_balance->is_volatile = true;
+                       pdev->color_bal_valid = false; /* Force cache update */
+               } else {
+                       pdev->red_balance->is_volatile = false;
+                       pdev->blue_balance->is_volatile = false;
                }
        }
-       return -EINVAL;
+
+       if (ret == 0 && pdev->red_balance->is_new) {
+               if (pdev->auto_white_balance->val != awb_manual)
+                       return -EBUSY;
+               ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+                                     PRESET_MANUAL_RED_GAIN_FORMATTER,
+                                     pdev->red_balance->val);
+       }
+
+       if (ret == 0 && pdev->blue_balance->is_new) {
+               if (pdev->auto_white_balance->val != awb_manual)
+                       return -EBUSY;
+               ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+                                     PRESET_MANUAL_BLUE_GAIN_FORMATTER,
+                                     pdev->blue_balance->val);
+       }
+       return ret;
 }
 
-static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+/* For CODEC2 models which have separate autogain and auto exposure */
+static int pwc_set_autogain(struct pwc_device *pdev)
 {
-       struct pwc_device *pdev = video_drvdata(file);
-       int ret;
+       int ret = 0;
+
+       if (pdev->autogain->is_new) {
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     AGC_MODE_FORMATTER,
+                                     pdev->autogain->val ? 0 : 0xff);
+               if (ret)
+                       return ret;
+               if (pdev->autogain->val)
+                       pdev->gain_valid = false; /* Force cache update */
+               else if (!pdev->gain->is_new)
+                       pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                       READ_AGC_FORMATTER,
+                                       &pdev->gain->val);
+       }
+       if (ret == 0 && pdev->gain->is_new) {
+               if (pdev->autogain->val)
+                       return -EBUSY;
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     PRESET_AGC_FORMATTER,
+                                     pdev->gain->val);
+       }
+       return 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;
+/* For CODEC2 models which have separate autogain and auto exposure */
+static int pwc_set_exposure_auto(struct pwc_device *pdev)
+{
+       int ret = 0;
+       int is_auto = pdev->exposure_auto->val == V4L2_EXPOSURE_AUTO;
+
+       if (pdev->exposure_auto->is_new) {
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     SHUTTER_MODE_FORMATTER,
+                                     is_auto ? 0 : 0xff);
+               if (ret)
+                       return ret;
+               if (is_auto)
+                       pdev->exposure_valid = false; /* Force cache update */
+               else if (!pdev->exposure->is_new)
+                       pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
+                                        READ_SHUTTER_FORMATTER,
+                                        &pdev->exposure->val);
+       }
+       if (ret == 0 && pdev->exposure->is_new) {
+               if (is_auto)
+                       return -EBUSY;
+               ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL,
+                                      PRESET_SHUTTER_FORMATTER,
+                                      pdev->exposure->val);
+       }
+       return ret;
+}
 
-       case V4L2_CID_PRIVATE_SAVE_USER:
-       case V4L2_CID_PRIVATE_RESTORE_USER:
-       case V4L2_CID_PRIVATE_RESTORE_FACTORY:
-               return -EINVAL;
+/* For CODEC3 models which have autogain controlling both gain and exposure */
+static int pwc_set_autogain_expo(struct pwc_device *pdev)
+{
+       int ret = 0;
+
+       if (pdev->autogain->is_new) {
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     AGC_MODE_FORMATTER,
+                                     pdev->autogain->val ? 0 : 0xff);
+               if (ret)
+                       return ret;
+               if (pdev->autogain->val) {
+                       pdev->gain_valid     = false; /* Force cache update */
+                       pdev->exposure_valid = false; /* Force cache update */
+               } else {
+                       if (!pdev->gain->is_new)
+                               pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
+                                               READ_AGC_FORMATTER,
+                                               &pdev->gain->val);
+                       if (!pdev->exposure->is_new)
+                               pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
+                                                READ_SHUTTER_FORMATTER,
+                                                &pdev->exposure->val);
+               }
        }
-       return -EINVAL;
+       if (ret == 0 && pdev->gain->is_new) {
+               if (pdev->autogain->val)
+                       return -EBUSY;
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     PRESET_AGC_FORMATTER,
+                                     pdev->gain->val);
+       }
+       if (ret == 0 && pdev->exposure->is_new) {
+               if (pdev->autogain->val)
+                       return -EBUSY;
+               ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL,
+                                      PRESET_SHUTTER_FORMATTER,
+                                      pdev->exposure->val);
+       }
+       return ret;
 }
 
-static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+static int pwc_set_motor(struct pwc_device *pdev)
 {
-       struct pwc_device *pdev = video_drvdata(file);
        int ret;
+       u8 buf[4];
+
+       buf[0] = 0;
+       if (pdev->motor_pan_reset->is_new)
+               buf[0] |= 0x01;
+       if (pdev->motor_tilt_reset->is_new)
+               buf[0] |= 0x02;
+       if (pdev->motor_pan_reset->is_new || pdev->motor_tilt_reset->is_new) {
+               ret = send_control_msg(pdev, SET_MPT_CTL,
+                                      PT_RESET_CONTROL_FORMATTER, buf, 1);
+               if (ret < 0)
+                       return ret;
+       }
 
-       switch (c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               c->value <<= 9;
-               ret = pwc_set_brightness(pdev, c->value);
+       memset(buf, 0, sizeof(buf));
+       if (pdev->motor_pan->is_new) {
+               buf[0] = pdev->motor_pan->val & 0xFF;
+               buf[1] = (pdev->motor_pan->val >> 8);
+       }
+       if (pdev->motor_tilt->is_new) {
+               buf[2] = pdev->motor_tilt->val & 0xFF;
+               buf[3] = (pdev->motor_tilt->val >> 8);
+       }
+       if (pdev->motor_pan->is_new || pdev->motor_tilt->is_new) {
+               ret = send_control_msg(pdev, SET_MPT_CTL,
+                                      PT_RELATIVE_CONTROL_FORMATTER,
+                                      buf, sizeof(buf));
                if (ret < 0)
-                       return -EINVAL;
-               return 0;
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct pwc_device *pdev =
+               container_of(ctrl->handler, struct pwc_device, ctrl_handler);
+       int ret = 0;
+
+       /* See the comments on locking in pwc_g_volatile_ctrl */
+       mutex_unlock(&pdev->modlock);
+       mutex_lock(&pdev->udevlock);
+
+       if (!pdev->udev) {
+               ret = -ENODEV;
+               goto leave;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     BRIGHTNESS_FORMATTER, ctrl->val);
+               break;
        case V4L2_CID_CONTRAST:
-               c->value <<= 10;
-               ret = pwc_set_contrast(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     CONTRAST_FORMATTER, ctrl->val);
+               break;
        case V4L2_CID_SATURATION:
-               ret = pwc_set_saturation(pdev, c->value);
-               if (ret < 0)
-                       return -EINVAL;
-               return 0;
+               ret = pwc_set_s8_ctrl(pdev, SET_CHROM_CTL,
+                                     pdev->saturation_fmt, ctrl->val);
+               break;
        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;
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     GAMMA_FORMATTER, ctrl->val);
+               break;
        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;
+               ret = pwc_set_awb(pdev);
+               break;
        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;
-
+               if (DEVICE_USE_CODEC2(pdev->type))
+                       ret = pwc_set_autogain(pdev);
+               else if (DEVICE_USE_CODEC3(pdev->type))
+                       ret = pwc_set_autogain_expo(pdev);
+               else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               if (DEVICE_USE_CODEC2(pdev->type))
+                       ret = pwc_set_exposure_auto(pdev);
+               else
+                       ret = -EINVAL;
+               break;
+       case V4L2_CID_COLORFX:
+               ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
+                                     COLOUR_MODE_FORMATTER,
+                                     ctrl->val ? 0 : 0xff);
+               break;
+       case PWC_CID_CUSTOM(autocontour):
+               if (pdev->autocontour->is_new) {
+                       ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                       AUTO_CONTOUR_FORMATTER,
+                                       pdev->autocontour->val ? 0 : 0xff);
+               }
+               if (ret == 0 && pdev->contour->is_new) {
+                       if (pdev->autocontour->val) {
+                               ret = -EBUSY;
+                               break;
+                       }
+                       ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                             PRESET_CONTOUR_FORMATTER,
+                                             pdev->contour->val);
+               }
+               break;
+       case V4L2_CID_BACKLIGHT_COMPENSATION:
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     BACK_LIGHT_COMPENSATION_FORMATTER,
+                                     ctrl->val ? 0 : 0xff);
+               break;
+       case V4L2_CID_BAND_STOP_FILTER:
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     FLICKERLESS_MODE_FORMATTER,
+                                     ctrl->val ? 0 : 0xff);
+               break;
+       case PWC_CID_CUSTOM(noise_reduction):
+               ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
+                                     DYNAMIC_NOISE_CONTROL_FORMATTER,
+                                     ctrl->val);
+               break;
+       case PWC_CID_CUSTOM(save_user):
+               ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER);
+               break;
+       case PWC_CID_CUSTOM(restore_user):
+               ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER);
+               break;
+       case PWC_CID_CUSTOM(restore_factory):
+               ret = pwc_button_ctrl(pdev,
+                                     RESTORE_FACTORY_DEFAULTS_FORMATTER);
+               break;
+       case V4L2_CID_PAN_RELATIVE:
+               ret = pwc_set_motor(pdev);
+               break;
+       default:
+               ret = -EINVAL;
        }
-       return -EINVAL;
+
+       if (ret)
+               PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret);
+
+leave:
+       mutex_unlock(&pdev->udevlock);
+       mutex_lock(&pdev->modlock);
+       return ret;
 }
 
 static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
@@ -667,157 +967,77 @@ static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *
        return pwc_vidioc_try_fmt(pdev, f);
 }
 
-static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
+static int pwc_reqbufs(struct file *file, void *fh,
+                      struct v4l2_requestbuffers *rb)
 {
        struct pwc_device *pdev = video_drvdata(file);
 
-       return pwc_vidioc_set_fmt(pdev, f);
-}
-
-static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
-{
-       int nbuffers;
+       if (pdev->capt_file != NULL &&
+           pdev->capt_file != file)
+               return -EBUSY;
 
-       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;
+       pdev->capt_file = file;
 
-       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;
+       return vb2_reqbufs(&pdev->vb_queue, rb);
 }
 
 static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
        struct pwc_device *pdev = video_drvdata(file);
-       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;
-       }
-       index = buf->index;
-       if (index < 0 || index >= pwc_mbufs) {
-               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
-               return -EINVAL;
-       }
-
-       buf->m.offset = index * pdev->len_per_image;
-       if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
-               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;
+       return vb2_querybuf(&pdev->vb_queue, buf);
 }
 
 static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
-       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 >= pwc_mbufs)
-               return -EINVAL;
+       struct pwc_device *pdev = video_drvdata(file);
 
-       buf->flags |= V4L2_BUF_FLAG_QUEUED;
-       buf->flags &= ~V4L2_BUF_FLAG_DONE;
+       if (!pdev->udev)
+               return -ENODEV;
 
-       return 0;
+       if (pdev->capt_file != file)
+               return -EBUSY;
+
+       return vb2_qbuf(&pdev->vb_queue, buf);
 }
 
 static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 {
-       DECLARE_WAITQUEUE(wait, current);
        struct pwc_device *pdev = video_drvdata(file);
-       int ret;
 
-       PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
+       if (!pdev->udev)
+               return -ENODEV;
 
-       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       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;
-               }
-               mutex_unlock(&pdev->modlock);
-               schedule();
-               set_current_state(TASK_INTERRUPTIBLE);
-               mutex_lock(&pdev->modlock);
-       }
-       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->pixfmt != V4L2_PIX_FMT_YUV420)
-               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 = pdev->len_per_image;
-       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;
+       if (pdev->capt_file != file)
+               return -EBUSY;
 
+       return vb2_dqbuf(&pdev->vb_queue, buf, file->f_flags & O_NONBLOCK);
 }
 
 static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
 {
        struct pwc_device *pdev = video_drvdata(file);
 
-       return pwc_isoc_init(pdev);
+       if (!pdev->udev)
+               return -ENODEV;
+
+       if (pdev->capt_file != file)
+               return -EBUSY;
+
+       return vb2_streamon(&pdev->vb_queue, i);
 }
 
 static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
 {
        struct pwc_device *pdev = video_drvdata(file);
 
-       pwc_isoc_cleanup(pdev);
-       return 0;
+       if (!pdev->udev)
+               return -ENODEV;
+
+       if (pdev->capt_file != file)
+               return -EBUSY;
+
+       return vb2_streamoff(&pdev->vb_queue, i);
 }
 
 static int pwc_enum_framesizes(struct file *file, void *fh,
@@ -896,9 +1116,6 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = {
        .vidioc_g_fmt_vid_cap               = pwc_g_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap               = pwc_s_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap             = pwc_try_fmt_vid_cap,
-       .vidioc_queryctrl                   = pwc_queryctrl,
-       .vidioc_g_ctrl                      = pwc_g_ctrl,
-       .vidioc_s_ctrl                      = pwc_s_ctrl,
        .vidioc_reqbufs                     = pwc_reqbufs,
        .vidioc_querybuf                    = pwc_querybuf,
        .vidioc_qbuf                        = pwc_qbuf,
index 083f8b15df7337323666f01af18dc9ab5aa183bc..0e4e2d7b78720a0c954bc0d5db9df787f7c813b4 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/usb.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
-#include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-vmalloc.h>
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
 #include <linux/input.h>
 #endif
 
-#include "pwc-uncompress.h"
 #include <media/pwc-ioctl.h>
 
 /* 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.14"
+#define PWC_VERSION    "10.0.15"
 #define PWC_NAME       "pwc"
 #define PFX            PWC_NAME ": "
 
@@ -81,9 +77,9 @@
 #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)
+       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 FEATURE_CODEC1                 0x0002
 #define FEATURE_CODEC2                 0x0004
 
-/* Turn certain features on/off */
-#define PWC_INT_PIPE 0
-
 /* Ignore errors in the first N frames, to allow for startup delays */
 #define FRAME_LOWMARK 5
 
 /* Size and number of buffers for the ISO pipe. */
-#define MAX_ISO_BUFS           2
+#define MAX_ISO_BUFS           3
 #define ISO_FRAMES_PER_DESC    10
 #define ISO_MAX_FRAME_SIZE     960
 #define ISO_BUFFER_SIZE        (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
 
-/* Frame buffers: contains compressed or uncompressed video data. */
-#define MAX_FRAMES             5
 /* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */
 #define PWC_FRAME_SIZE                 (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE)
 
-/* Absolute maximum number of buffers available for mmap() */
-#define MAX_IMAGES             10
+/* Absolute minimum and maximum number of buffers available for mmap() */
+#define MIN_FRAMES             2
+#define MAX_FRAMES             16
 
 /* Some macros to quickly find the type of a webcam */
 #define DEVICE_USE_CODEC1(x) ((x)<675)
 #define DEVICE_USE_CODEC3(x) ((x)>=700)
 #define DEVICE_USE_CODEC23(x) ((x)>=675)
 
-/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
-struct pwc_iso_buf
-{
-       void *data;
-       int  length;
-       int  read;
-       struct urb *urb;
-};
+/* from pwc-dec.h */
+#define PWCX_FLAG_PLANAR        0x0001
+
+/* Request types: video */
+#define SET_LUM_CTL                    0x01
+#define GET_LUM_CTL                    0x02
+#define SET_CHROM_CTL                  0x03
+#define GET_CHROM_CTL                  0x04
+#define SET_STATUS_CTL                 0x05
+#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
+
+/* Selectors for the Luminance controls [GS]ET_LUM_CTL */
+#define AGC_MODE_FORMATTER                     0x2000
+#define PRESET_AGC_FORMATTER                   0x2100
+#define SHUTTER_MODE_FORMATTER                 0x2200
+#define PRESET_SHUTTER_FORMATTER               0x2300
+#define PRESET_CONTOUR_FORMATTER               0x2400
+#define AUTO_CONTOUR_FORMATTER                 0x2500
+#define BACK_LIGHT_COMPENSATION_FORMATTER      0x2600
+#define CONTRAST_FORMATTER                     0x2700
+#define DYNAMIC_NOISE_CONTROL_FORMATTER                0x2800
+#define FLICKERLESS_MODE_FORMATTER             0x2900
+#define AE_CONTROL_SPEED                       0x2A00
+#define BRIGHTNESS_FORMATTER                   0x2B00
+#define GAMMA_FORMATTER                                0x2C00
+
+/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
+#define WB_MODE_FORMATTER                      0x1000
+#define AWB_CONTROL_SPEED_FORMATTER            0x1100
+#define AWB_CONTROL_DELAY_FORMATTER            0x1200
+#define PRESET_MANUAL_RED_GAIN_FORMATTER       0x1300
+#define PRESET_MANUAL_BLUE_GAIN_FORMATTER      0x1400
+#define COLOUR_MODE_FORMATTER                  0x1500
+#define SATURATION_MODE_FORMATTER1             0x1600
+#define SATURATION_MODE_FORMATTER2             0x1700
+
+/* Selectors for the Status controls [GS]ET_STATUS_CTL */
+#define SAVE_USER_DEFAULTS_FORMATTER           0x0200
+#define RESTORE_USER_DEFAULTS_FORMATTER                0x0300
+#define RESTORE_FACTORY_DEFAULTS_FORMATTER     0x0400
+#define READ_AGC_FORMATTER                     0x0500
+#define READ_SHUTTER_FORMATTER                 0x0600
+#define READ_RED_GAIN_FORMATTER                        0x0700
+#define READ_BLUE_GAIN_FORMATTER               0x0800
+
+/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
+#define PT_RELATIVE_CONTROL_FORMATTER          0x01
+#define PT_RESET_CONTROL_FORMATTER             0x02
+#define PT_STATUS_FORMATTER                    0x03
 
 /* intermediate buffers with raw data from the USB cam */
 struct pwc_frame_buf
 {
-   void *data;
-   volatile int filled;                /* number of bytes filled */
-   struct pwc_frame_buf *next; /* list */
-};
-
-/* 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 vb2_buffer vb;   /* common v4l buffer stuff -- must be first */
+       struct list_head list;
+       void *data;
+       int filled;             /* number of bytes filled */
 };
 
 struct pwc_device
 {
        struct video_device vdev;
-
-   /* Pointer to our usb_device, may be NULL after unplug */
-   struct usb_device *udev;
-
-   int type;                    /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
-   int release;                        /* release number */
-   int features;               /* feature bits */
-   char serial[30];            /* serial number (string) */
-   int error_status;           /* set when something goes wrong with the cam (unplugged, USB errors) */
-   int usb_init;               /* set when the cam has been initialized over USB */
-
-   /*** Video data ***/
-   int vopen;                  /* flag */
-   int vendpoint;              /* video isoc endpoint */
-   int vcinterface;            /* video control interface */
-   int valternate;             /* alternate interface needed */
-   int vframes, vsize;         /* frames-per-second & size (see PSZ_*) */
-   int pixfmt;                 /* pixelformat: V4L2_PIX_FMT_YUV420 or raw: _PWC1, _PWC2 */
-   int vframe_count;           /* received frames */
-   int vframes_dumped;                 /* counter for dumped frames */
-   int vframes_error;          /* frames received in error */
-   int vmax_packet_size;       /* USB maxpacket size */
-   int vlast_packet_size;      /* for frame synchronisation */
-   int visoc_errors;           /* number of contiguous ISOC errors */
-   int vcompression;           /* desired compression factor */
-   int vbandlength;            /* compressed band length; 0 is uncompressed */
-   char vsnapshot;             /* snapshot mode */
-   char vsync;                 /* used by isoc handler */
-   char vmirror;               /* for ToUCaM series */
-       char unplugged;
-
-   int cmd_len;
-   unsigned char cmd_buf[13];
-
-   /* The image acquisition requires 3 to 4 steps:
-      1. data is gathered in short packets from the USB controller
-      2. data is synchronized and packed into a frame buffer
-      3a. in case data is compressed, decompress it directly into image buffer
-      3b. in case data is uncompressed, copy into image buffer with viewport
-      4. data is transferred to the user process
-
-      Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES....
-      We have in effect a back-to-back-double-buffer system.
-    */
-   /* 1: isoc */
-   struct pwc_iso_buf sbuf[MAX_ISO_BUFS];
-   char iso_init;
-
-   /* 2: frame */
-   struct pwc_frame_buf *fbuf; /* all frames */
-   struct pwc_frame_buf *empty_frames, *empty_frames_tail;     /* all empty frames */
-   struct pwc_frame_buf *full_frames, *full_frames_tail;       /* all filled frames */
-   struct pwc_frame_buf *fill_frame;   /* frame currently being filled */
-   struct pwc_frame_buf *read_frame;   /* frame currently read by user process */
-   int frame_header_size, frame_trailer_size;
-   int frame_size;
-   int frame_total_size; /* including header & trailer */
-   int drop_frames;
-
-   /* 3: decompression */
-   void *decompress_data;              /* private data for decompression engine */
-
-   /* 4: image */
-   /* We have an 'image' and a 'view', where 'image' is the fixed-size image
-      as delivered by the camera, and 'view' is the size requested by the
-      program. The camera image is centered in this viewport, laced with
-      a gray or black border. view_min <= image <= view <= view_max;
-    */
-   int image_mask;                     /* bitmask of supported sizes */
-   struct pwc_coord view_min, view_max;        /* minimum and maximum viewable sizes */
-   struct pwc_coord abs_max;            /* maximum supported size with compression */
-   struct pwc_coord image, view;       /* image and viewport size */
-   struct pwc_coord offset;            /* offset within the viewport */
-
-   void *image_data;                   /* total buffer, which is subdivided into ... */
-   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 */
-   int image_used[MAX_IMAGES];         /* For MCAPTURE and SYNC */
-
-   struct mutex modlock;               /* to prevent races in video_open(), etc */
-   spinlock_t ptrlock;                 /* for manipulating the buffer pointers */
-
-   /*** motorized pan/tilt feature */
-   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 */
+       struct mutex modlock;
+
+       /* Pointer to our usb_device, may be NULL after unplug */
+       struct usb_device *udev;
+       /* Protects the setting of udev to NULL by our disconnect handler */
+       struct mutex udevlock;
+
+       /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
+       int type;
+       int release;            /* release number */
+       int features;           /* feature bits */
+       char serial[30];        /* serial number (string) */
+
+       /*** Video data ***/
+       struct file *capt_file; /* file doing video capture */
+       int vendpoint;          /* video isoc endpoint */
+       int vcinterface;        /* video control interface */
+       int valternate;         /* alternate interface needed */
+       int vframes, vsize;     /* frames-per-second & size (see PSZ_*) */
+       int pixfmt;             /* pixelformat: V4L2_PIX_FMT_YUV420 or _PWCX */
+       int vframe_count;       /* received frames */
+       int vmax_packet_size;   /* USB maxpacket size */
+       int vlast_packet_size;  /* for frame synchronisation */
+       int visoc_errors;       /* number of contiguous ISOC errors */
+       int vcompression;       /* desired compression factor */
+       int vbandlength;        /* compressed band length; 0 is uncompressed */
+       char vsnapshot;         /* snapshot mode */
+       char vsync;             /* used by isoc handler */
+       char vmirror;           /* for ToUCaM series */
+       char power_save;        /* Do powersaving for this cam */
+
+       int cmd_len;
+       unsigned char cmd_buf[13];
+
+       struct urb *urbs[MAX_ISO_BUFS];
+       char iso_init;
+
+       /* videobuf2 queue and queued buffers list */
+       struct vb2_queue vb_queue;
+       struct list_head queued_bufs;
+       spinlock_t queued_bufs_lock;
+
+       /*
+        * Frame currently being filled, this only gets touched by the
+        * isoc urb complete handler, and by stream start / stop since
+        * start / stop touch it before / after starting / killing the urbs
+        * no locking is needed around this
+        */
+       struct pwc_frame_buf *fill_buf;
+
+       int frame_header_size, frame_trailer_size;
+       int frame_size;
+       int frame_total_size;   /* including header & trailer */
+       int drop_frames;
+
+       void *decompress_data;  /* private data for decompression engine */
+
+       /*
+        * We have an 'image' and a 'view', where 'image' is the fixed-size img
+        * as delivered by the camera, and 'view' is the size requested by the
+        * program. The camera image is centered in this viewport, laced with
+        * a gray or black border. view_min <= image <= view <= view_max;
+        */
+       int image_mask;                         /* supported sizes */
+       struct pwc_coord view_min, view_max;    /* minimum and maximum view */
+       struct pwc_coord abs_max;               /* maximum supported size */
+       struct pwc_coord image, view;           /* image and viewport size */
+       struct pwc_coord offset;                /* offset of the viewport */
+
+       /*** motorized pan/tilt feature */
+       struct pwc_mpt_range angle_range;
+       int pan_angle;                  /* in degrees * 100 */
+       int tilt_angle;                 /* absolute angle; 0,0 is home */
+
+       /*
+        * Set to 1 when the user push the button, reset to 0
+        * when this value is read from sysfs.
+        */
+       int snapshot_button_status;
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
-   struct input_dev *button_dev;       /* webcam snapshot button input */
-   char button_phys[64];
+       struct input_dev *button_dev;   /* webcam snapshot button input */
+       char button_phys[64];
 #endif
 
-   /*** Misc. data ***/
-   wait_queue_head_t frameq;           /* When waiting for a frame to finish... */
-#if PWC_INT_PIPE
-   void *usb_int_handler;              /* for the interrupt endpoint */
-#endif
+       /* controls */
+       struct v4l2_ctrl_handler        ctrl_handler;
+       u16                             saturation_fmt;
+       struct v4l2_ctrl                *brightness;
+       struct v4l2_ctrl                *contrast;
+       struct v4l2_ctrl                *saturation;
+       struct v4l2_ctrl                *gamma;
+       struct {
+               /* awb / red-blue balance cluster */
+               struct v4l2_ctrl        *auto_white_balance;
+               struct v4l2_ctrl        *red_balance;
+               struct v4l2_ctrl        *blue_balance;
+               /* usb ctrl transfers are slow, so we cache things */
+               int                     color_bal_valid;
+               unsigned long           last_color_bal_update; /* In jiffies */
+               s32                     last_red_balance;
+               s32                     last_blue_balance;
+       };
+       struct {
+               /* autogain / gain cluster */
+               struct v4l2_ctrl        *autogain;
+               struct v4l2_ctrl        *gain;
+               int                     gain_valid;
+               unsigned long           last_gain_update; /* In jiffies */
+               s32                     last_gain;
+       };
+       struct {
+               /* exposure_auto / exposure cluster */
+               struct v4l2_ctrl        *exposure_auto;
+               struct v4l2_ctrl        *exposure;
+               int                     exposure_valid;
+               unsigned long           last_exposure_update; /* In jiffies */
+               s32                     last_exposure;
+       };
+       struct v4l2_ctrl                *colorfx;
+       struct {
+               /* autocontour/contour cluster */
+               struct v4l2_ctrl        *autocontour;
+               struct v4l2_ctrl        *contour;
+       };
+       struct v4l2_ctrl                *backlight;
+       struct v4l2_ctrl                *flicker;
+       struct v4l2_ctrl                *noise_reduction;
+       struct v4l2_ctrl                *save_user;
+       struct v4l2_ctrl                *restore_user;
+       struct v4l2_ctrl                *restore_factory;
+       struct {
+               /* motor control cluster */
+               struct v4l2_ctrl        *motor_pan;
+               struct v4l2_ctrl        *motor_tilt;
+               struct v4l2_ctrl        *motor_pan_reset;
+               struct v4l2_ctrl        *motor_tilt_reset;
+       };
+       /* CODEC3 models have both gain and exposure controlled by autogain */
+       struct v4l2_ctrl                *autogain_expo_cluster[3];
 };
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Global variables */
 #ifdef CONFIG_USB_PWC_DEBUG
 extern int pwc_trace;
 #endif
-extern int pwc_mbufs;
-
-/** functions in pwc-if.c */
-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 */
@@ -291,50 +355,25 @@ void pwc_construct(struct pwc_device *pdev);
 /* 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);
 extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size);
-/* 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);
-extern int pwc_set_brightness(struct pwc_device *pdev, int value);
-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, 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);
+extern int send_control_msg(struct pwc_device *pdev,
+                           u8 request, u16 value, void *buf, int buflen);
+
+/* Control get / set helpers */
+int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data);
+int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data);
+int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data);
+#define pwc_set_s8_ctrl pwc_set_u8_ctrl
+int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *dat);
+int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data);
+int pwc_button_ctrl(struct pwc_device *pdev, u16 value);
+int pwc_init_controls(struct pwc_device *pdev);
 
 /* Power down or up the camera; not supported by all models */
-extern int pwc_camera_power(struct pwc_device *pdev, int power);
+extern void pwc_camera_power(struct pwc_device *pdev, int power);
 
 /* Private ioctl()s; see pwc-ioctl.h */
 extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
@@ -343,12 +382,6 @@ extern const struct v4l2_ioctl_ops pwc_ioctl_ops;
 
 /** pwc-uncompress.c */
 /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
-extern int pwc_decompress(struct pwc_device *pdev);
-
-#ifdef __cplusplus
-}
-#endif
-
+int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf);
 
 #endif
-/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
index b42bfa5ccdf2f3b2fc8280ef36e5f9c70c86cf9b..d07df22a5ec6c6b0611bf43d757575bc05762ead 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/time.h>
-#include <linux/version.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
@@ -40,7 +39,7 @@
 #include <mach/dma.h>
 #include <mach/camera.h>
 
-#define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
+#define PXA_CAM_VERSION "0.0.6"
 #define PXA_CAM_DRV_NAME "pxa27x-camera"
 
 /* Camera Interface */
@@ -247,7 +246,7 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
        if (bytes_per_line < 0)
                return bytes_per_line;
 
-       dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size);
+       dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
 
        *size = bytes_per_line * icd->user_height;
 
@@ -262,13 +261,13 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
 static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
        int i;
 
        BUG_ON(in_interrupt());
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                &buf->vb, buf->vb.baddr, buf->vb.bsize);
 
        /*
@@ -429,7 +428,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                struct videobuf_buffer *vb, enum v4l2_field field)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct device *dev = pcdev->soc_host.v4l2_dev.dev;
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
@@ -636,11 +635,11 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
                               struct videobuf_buffer *vb)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n",
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d active=%p\n",
                __func__, vb, vb->baddr, vb->bsize, pcdev->active);
 
        list_add_tail(&vb->queue, &pcdev->capture);
@@ -658,7 +657,7 @@ static void pxa_videobuf_release(struct videobuf_queue *vq,
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
 #ifdef DEBUG
        struct soc_camera_device *icd = vq->priv_data;
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
 
        dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
@@ -843,7 +842,7 @@ static struct videobuf_queue_ops pxa_videobuf_ops = {
 static void pxa_camera_init_videobuf(struct videobuf_queue *q,
                              struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
 
        /*
@@ -972,7 +971,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
  */
 static int pxa_camera_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
 
        if (pcdev->icd)
@@ -982,7 +981,7 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
 
        pcdev->icd = icd;
 
-       dev_info(icd->dev.parent, "PXA Camera driver attached to camera %d\n",
+       dev_info(icd->parent, "PXA Camera driver attached to camera %d\n",
                 icd->devnum);
 
        return 0;
@@ -991,12 +990,12 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
 /* Called with .video_lock held */
 static void pxa_camera_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
 
        BUG_ON(icd != pcdev->icd);
 
-       dev_info(icd->dev.parent, "PXA Camera driver detached from camera %d\n",
+       dev_info(icd->parent, "PXA Camera driver detached from camera %d\n",
                 icd->devnum);
 
        /* disable capture, disable interrupts */
@@ -1057,7 +1056,7 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
 static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
                                  unsigned long flags, __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        unsigned long dw, bpp;
@@ -1152,7 +1151,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd,
 
 static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        unsigned long bus_flags, camera_flags, common_flags;
        int ret;
@@ -1210,7 +1209,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 static int pxa_camera_try_bus_param(struct soc_camera_device *icd,
                                    unsigned char buswidth)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        unsigned long bus_flags, camera_flags;
        int ret = test_platform_param(pcdev, buswidth, &bus_flags);
@@ -1247,7 +1246,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
                                  struct soc_camera_format_xlate *xlate)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        int formats = 0, ret;
        struct pxa_cam *cam;
        enum v4l2_mbus_pixelcode code;
@@ -1335,9 +1334,9 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
                               struct v4l2_crop *a)
 {
        struct v4l2_rect *rect = &a->c;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct pxa_camera_dev *pcdev = ici->priv;
-       struct device *dev = icd->dev.parent;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        struct soc_camera_sense sense = {
                .master_clock = pcdev->mclk,
@@ -1379,7 +1378,7 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
                        return ret;
 
                if (pxa_camera_check_frame(mf.width, mf.height)) {
-                       dev_warn(icd->dev.parent,
+                       dev_warn(icd->parent,
                                 "Inconsistent state. Use S_FMT to repair\n");
                        return -EINVAL;
                }
@@ -1406,9 +1405,9 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
 static int pxa_camera_set_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct pxa_camera_dev *pcdev = ici->priv;
-       struct device *dev = icd->dev.parent;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        const struct soc_camera_format_xlate *xlate = NULL;
        struct soc_camera_sense sense = {
@@ -1485,7 +1484,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
+               dev_warn(icd->parent, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -1499,16 +1498,11 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
                              &pix->height, 32, 2048, 0,
                              pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
 
-       pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
-                                                   xlate->host_fmt);
-       if (pix->bytesperline < 0)
-               return pix->bytesperline;
-       pix->sizeimage = pix->height * pix->bytesperline;
-
        /* limit to sensor capabilities */
        mf.width        = pix->width;
        mf.height       = pix->height;
-       mf.field        = pix->field;
+       /* Only progressive video supported so far */
+       mf.field        = V4L2_FIELD_NONE;
        mf.colorspace   = pix->colorspace;
        mf.code         = xlate->code;
 
@@ -1527,7 +1521,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
                break;
        default:
                /* TODO: support interlaced at least in pass-through mode */
-               dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+               dev_err(icd->parent, "Field type %d unsupported.\n",
                        mf.field);
                return -EINVAL;
        }
@@ -1578,15 +1572,14 @@ static int pxa_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the firendly caller:-> */
        strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card));
-       cap->version = PXA_CAM_VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
        return 0;
 }
 
-static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state)
+static int pxa_camera_suspend(struct device *dev)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct pxa_camera_dev *pcdev = ici->priv;
        int i = 0, ret = 0;
 
@@ -1596,15 +1589,19 @@ static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state)
        pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3);
        pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4);
 
-       if ((pcdev->icd) && (pcdev->icd->ops->suspend))
-               ret = pcdev->icd->ops->suspend(pcdev->icd, state);
+       if (pcdev->icd) {
+               struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd);
+               ret = v4l2_subdev_call(sd, core, s_power, 0);
+               if (ret == -ENOIOCTLCMD)
+                       ret = 0;
+       }
 
        return ret;
 }
 
-static int pxa_camera_resume(struct soc_camera_device *icd)
+static int pxa_camera_resume(struct device *dev)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct pxa_camera_dev *pcdev = ici->priv;
        int i = 0, ret = 0;
 
@@ -1618,8 +1615,12 @@ static int pxa_camera_resume(struct soc_camera_device *icd)
        __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3);
        __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4);
 
-       if ((pcdev->icd) && (pcdev->icd->ops->resume))
-               ret = pcdev->icd->ops->resume(pcdev->icd);
+       if (pcdev->icd) {
+               struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd);
+               ret = v4l2_subdev_call(sd, core, s_power, 1);
+               if (ret == -ENOIOCTLCMD)
+                       ret = 0;
+       }
 
        /* Restart frame capture if active buffer exists */
        if (!ret && pcdev->active)
@@ -1632,8 +1633,6 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .owner          = THIS_MODULE,
        .add            = pxa_camera_add_device,
        .remove         = pxa_camera_remove_device,
-       .suspend        = pxa_camera_suspend,
-       .resume         = pxa_camera_resume,
        .set_crop       = pxa_camera_set_crop,
        .get_formats    = pxa_camera_get_formats,
        .put_formats    = pxa_camera_put_formats,
@@ -1818,9 +1817,15 @@ static int __devexit pxa_camera_remove(struct platform_device *pdev)
        return 0;
 }
 
+static struct dev_pm_ops pxa_camera_pm = {
+       .suspend        = pxa_camera_suspend,
+       .resume         = pxa_camera_resume,
+};
+
 static struct platform_driver pxa_camera_driver = {
        .driver         = {
                .name   = PXA_CAM_DRV_NAME,
+               .pm     = &pxa_camera_pm,
        },
        .probe          = pxa_camera_probe,
        .remove         = __devexit_p(pxa_camera_remove),
@@ -1843,4 +1848,5 @@ module_exit(pxa_camera_exit);
 MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(PXA_CAM_VERSION);
 MODULE_ALIAS("platform:" PXA_CAM_DRV_NAME);
index 57e11b6f19fbda4a08b915c92434faf9d2ce75c5..847ccc067e87161384c4ef231fbfdb1d36d31e45 100644 (file)
@@ -1364,10 +1364,9 @@ static int rj54n1_video_probe(struct soc_camera_device *icd,
        int data1, data2;
        int ret;
 
-       /* This could be a BUG_ON() or a WARN_ON(), or remove it completely */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /* Read out the chip version register */
        data1 = reg_read(client, RJ54N1_DEV_CODE);
index 5b9dce85645c351220330db9a14b0f39cf628763..803c9c82e496cf518ca173afac1e458b81ae8efd 100644 (file)
  * Example maximum bandwidth utilization:
  *
  * -full size, color mode YUYV or YUV422P: 2 channels at once
- *
  * -full or half size Grey scale: all 4 channels at once
- *
  * -half size, color mode YUYV or YUV422P: all 4 channels at once
- *
  * -full size, color mode YUYV or YUV422P 1/2 frame rate: all 4 channels
  *  at once.
- *  (TODO: Incorporate videodev2 frame rate(FR) enumeration,
- *  which is currently experimental.)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -47,7 +42,6 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-common.h>
 #include <linux/vmalloc.h>
 #include <linux/usb.h>
 
-#define S2255_MAJOR_VERSION    1
-#define S2255_MINOR_VERSION    21
-#define S2255_RELEASE          0
-#define S2255_VERSION          KERNEL_VERSION(S2255_MAJOR_VERSION, \
-                                              S2255_MINOR_VERSION, \
-                                              S2255_RELEASE)
+#define S2255_VERSION          "1.22.1"
 #define FIRMWARE_FILE_NAME "f2255usb.bin"
 
 /* default JPEG quality */
 #define MASK_COLOR       0x000000ff
 #define MASK_JPG_QUALITY 0x0000ff00
 #define MASK_INPUT_TYPE  0x000f0000
-/* frame decimation. Not implemented by V4L yet(experimental in V4L) */
+/* frame decimation. */
 #define FDEC_1         1       /* capture every frame. default */
 #define FDEC_2         2       /* capture every 2nd frame */
 #define FDEC_3         3       /* capture every 3rd frame */
@@ -312,9 +301,9 @@ struct s2255_fh {
 };
 
 /* current cypress EEPROM firmware version */
-#define S2255_CUR_USB_FWVER    ((3 << 8) | 11)
+#define S2255_CUR_USB_FWVER    ((3 << 8) | 12)
 /* current DSP FW version */
-#define S2255_CUR_DSP_FWVER     10102
+#define S2255_CUR_DSP_FWVER     10104
 /* Need DSP version 5+ for video status feature */
 #define S2255_MIN_DSP_STATUS      5
 #define S2255_MIN_DSP_COLORFILTER 8
@@ -502,7 +491,7 @@ static void planar422p_to_yuv_packed(const unsigned char *in,
 
 static void s2255_reset_dsppower(struct s2255_dev *dev)
 {
-       s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b01, NULL, 0, 1);
+       s2255_vendor_req(dev, 0x40, 0x0000, 0x0001, NULL, 0, 1);
        msleep(10);
        s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
        msleep(600);
@@ -856,7 +845,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(cap->driver, "s2255", sizeof(cap->driver));
        strlcpy(cap->card, "s2255", sizeof(cap->card));
        usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-       cap->version = S2255_VERSION;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
        return 0;
 }
@@ -1984,9 +1972,8 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                          video_device_node_name(&channel->vdev));
 
        }
-       printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n",
-              S2255_MAJOR_VERSION,
-              S2255_MINOR_VERSION);
+       printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %s\n",
+              S2255_VERSION);
        /* if no channels registered, return error and probe will fail*/
        if (atomic_read(&dev->num_channels) == 0) {
                v4l2_device_unregister(&dev->v4l2_dev);
@@ -2302,15 +2289,12 @@ static int s2255_board_init(struct s2255_dev *dev)
        /* query the firmware */
        fw_ver = s2255_get_fx2fw(dev);
 
-       printk(KERN_INFO "2255 usb firmware version %d.%d\n",
+       printk(KERN_INFO "s2255: usb firmware version %d.%d\n",
               (fw_ver >> 8) & 0xff,
               fw_ver & 0xff);
 
        if (fw_ver < S2255_CUR_USB_FWVER)
-               dev_err(&dev->udev->dev,
-                       "usb firmware not up to date %d.%d\n",
-                       (fw_ver >> 8) & 0xff,
-                       fw_ver & 0xff);
+               printk(KERN_INFO "s2255: newer USB firmware available\n");
 
        for (j = 0; j < MAX_CHANNELS; j++) {
                struct s2255_channel *channel = &dev->channel[j];
@@ -2721,3 +2705,4 @@ module_exit(usb_s2255_exit);
 MODULE_DESCRIPTION("Sensoray 2255 Video for Linux driver");
 MODULE_AUTHOR("Dean Anderson (Sensoray Company Inc.)");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(S2255_VERSION);
index 81b4a826ee5e3338d25910d52e498c0cd0779a1f..0d730e55605d02423a5f34aea359f1e5202416d0 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/bug.h>
@@ -451,7 +450,6 @@ static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
        strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
        strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
-       cap->version = KERNEL_VERSION(1, 0, 0);
        cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
                            V4L2_CAP_VIDEO_CAPTURE_MPLANE;
 
index bdf19ada91725eb45a03d6b710691dd9778f6a97..aa550666cc0bca77fe372cb93067fd0312c6d327 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/bug.h>
@@ -774,7 +773,6 @@ static int fimc_m2m_querycap(struct file *file, void *priv,
        strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
        strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
        cap->bus_info[0] = 0;
-       cap->version = KERNEL_VERSION(1, 0, 0);
        cap->capabilities = V4L2_CAP_STREAMING |
                V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
                V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
@@ -1937,3 +1935,4 @@ module_exit(fimc_exit);
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
 MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.1");
diff --git a/drivers/media/video/s5p-mfc/Makefile b/drivers/media/video/s5p-mfc/Makefile
new file mode 100644 (file)
index 0000000..d066340
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o
+s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.o
+s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o
+s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o
+s5p-mfc-y += s5p_mfc_pm.o s5p_mfc_shm.o
diff --git a/drivers/media/video/s5p-mfc/regs-mfc.h b/drivers/media/video/s5p-mfc/regs-mfc.h
new file mode 100644 (file)
index 0000000..053a8a8
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Register definition file for Samsung MFC V5.1 Interface (FIMV) driver
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.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.
+*/
+
+#ifndef _REGS_FIMV_H
+#define _REGS_FIMV_H
+
+#define S5P_FIMV_REG_SIZE      (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR)
+#define S5P_FIMV_REG_COUNT     ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4)
+
+/* Number of bits that the buffer address should be shifted for particular
+ * MFC buffers.  */
+#define S5P_FIMV_START_ADDR            0x0000
+#define S5P_FIMV_END_ADDR              0xe008
+
+#define S5P_FIMV_SW_RESET              0x0000
+#define S5P_FIMV_RISC_HOST_INT         0x0008
+
+/* Command from HOST to RISC */
+#define S5P_FIMV_HOST2RISC_CMD         0x0030
+#define S5P_FIMV_HOST2RISC_ARG1                0x0034
+#define S5P_FIMV_HOST2RISC_ARG2                0x0038
+#define S5P_FIMV_HOST2RISC_ARG3                0x003c
+#define S5P_FIMV_HOST2RISC_ARG4                0x0040
+
+/* Command from RISC to HOST */
+#define S5P_FIMV_RISC2HOST_CMD         0x0044
+#define S5P_FIMV_RISC2HOST_CMD_MASK    0x1FFFF
+#define S5P_FIMV_RISC2HOST_ARG1                0x0048
+#define S5P_FIMV_RISC2HOST_ARG2                0x004c
+#define S5P_FIMV_RISC2HOST_ARG3                0x0050
+#define S5P_FIMV_RISC2HOST_ARG4                0x0054
+
+#define S5P_FIMV_FW_VERSION            0x0058
+#define S5P_FIMV_SYS_MEM_SZ            0x005c
+#define S5P_FIMV_FW_STATUS             0x0080
+
+/* Memory controller register */
+#define S5P_FIMV_MC_DRAMBASE_ADR_A     0x0508
+#define S5P_FIMV_MC_DRAMBASE_ADR_B     0x050c
+#define S5P_FIMV_MC_STATUS             0x0510
+
+/* Common register */
+#define S5P_FIMV_COMMON_BASE_A         0x0600
+#define S5P_FIMV_COMMON_BASE_B         0x0700
+
+/* Decoder */
+#define S5P_FIMV_DEC_CHROMA_ADR                (S5P_FIMV_COMMON_BASE_A)
+#define S5P_FIMV_DEC_LUMA_ADR          (S5P_FIMV_COMMON_BASE_B)
+
+/* H.264 decoding */
+#define S5P_FIMV_H264_VERT_NB_MV_ADR   (S5P_FIMV_COMMON_BASE_A + 0x8c)
+                                       /* vertical neighbor motion vector */
+#define S5P_FIMV_H264_NB_IP_ADR                (S5P_FIMV_COMMON_BASE_A + 0x90)
+                                       /* neighbor pixels for intra pred */
+#define S5P_FIMV_H264_MV_ADR           (S5P_FIMV_COMMON_BASE_B + 0x80)
+                                       /* H264 motion vector */
+
+/* MPEG4 decoding */
+#define S5P_FIMV_MPEG4_NB_DCAC_ADR     (S5P_FIMV_COMMON_BASE_A + 0x8c)
+                                       /* neighbor AC/DC coeff. */
+#define S5P_FIMV_MPEG4_UP_NB_MV_ADR    (S5P_FIMV_COMMON_BASE_A + 0x90)
+                                       /* upper neighbor motion vector */
+#define S5P_FIMV_MPEG4_SA_MV_ADR       (S5P_FIMV_COMMON_BASE_A + 0x94)
+                                       /* subseq. anchor motion vector */
+#define S5P_FIMV_MPEG4_OT_LINE_ADR     (S5P_FIMV_COMMON_BASE_A + 0x98)
+                                       /* overlap transform line */
+#define S5P_FIMV_MPEG4_SP_ADR          (S5P_FIMV_COMMON_BASE_A + 0xa8)
+                                       /* syntax parser */
+
+/* H.263 decoding */
+#define S5P_FIMV_H263_NB_DCAC_ADR      (S5P_FIMV_COMMON_BASE_A + 0x8c)
+#define S5P_FIMV_H263_UP_NB_MV_ADR     (S5P_FIMV_COMMON_BASE_A + 0x90)
+#define S5P_FIMV_H263_SA_MV_ADR                (S5P_FIMV_COMMON_BASE_A + 0x94)
+#define S5P_FIMV_H263_OT_LINE_ADR      (S5P_FIMV_COMMON_BASE_A + 0x98)
+
+/* VC-1 decoding */
+#define S5P_FIMV_VC1_NB_DCAC_ADR       (S5P_FIMV_COMMON_BASE_A + 0x8c)
+#define S5P_FIMV_VC1_UP_NB_MV_ADR      (S5P_FIMV_COMMON_BASE_A + 0x90)
+#define S5P_FIMV_VC1_SA_MV_ADR         (S5P_FIMV_COMMON_BASE_A + 0x94)
+#define S5P_FIMV_VC1_OT_LINE_ADR       (S5P_FIMV_COMMON_BASE_A + 0x98)
+#define S5P_FIMV_VC1_BITPLANE3_ADR     (S5P_FIMV_COMMON_BASE_A + 0x9c)
+                                       /* bitplane3 */
+#define S5P_FIMV_VC1_BITPLANE2_ADR     (S5P_FIMV_COMMON_BASE_A + 0xa0)
+                                       /* bitplane2 */
+#define S5P_FIMV_VC1_BITPLANE1_ADR     (S5P_FIMV_COMMON_BASE_A + 0xa4)
+                                       /* bitplane1 */
+
+/* Encoder */
+#define S5P_FIMV_ENC_REF0_LUMA_ADR     (S5P_FIMV_COMMON_BASE_A + 0x1c)
+#define S5P_FIMV_ENC_REF1_LUMA_ADR     (S5P_FIMV_COMMON_BASE_A + 0x20)
+                                       /* reconstructed luma */
+#define S5P_FIMV_ENC_REF0_CHROMA_ADR   (S5P_FIMV_COMMON_BASE_B)
+#define S5P_FIMV_ENC_REF1_CHROMA_ADR   (S5P_FIMV_COMMON_BASE_B + 0x04)
+                                       /* reconstructed chroma */
+#define S5P_FIMV_ENC_REF2_LUMA_ADR     (S5P_FIMV_COMMON_BASE_B + 0x10)
+#define S5P_FIMV_ENC_REF2_CHROMA_ADR   (S5P_FIMV_COMMON_BASE_B + 0x08)
+#define S5P_FIMV_ENC_REF3_LUMA_ADR     (S5P_FIMV_COMMON_BASE_B + 0x14)
+#define S5P_FIMV_ENC_REF3_CHROMA_ADR   (S5P_FIMV_COMMON_BASE_B + 0x0c)
+
+/* H.264 encoding */
+#define S5P_FIMV_H264_UP_MV_ADR                (S5P_FIMV_COMMON_BASE_A)
+                                       /* upper motion vector */
+#define S5P_FIMV_H264_NBOR_INFO_ADR    (S5P_FIMV_COMMON_BASE_A + 0x04)
+                                       /* entropy engine's neighbor info. */
+#define S5P_FIMV_H264_UP_INTRA_MD_ADR  (S5P_FIMV_COMMON_BASE_A + 0x08)
+                                       /* upper intra MD */
+#define S5P_FIMV_H264_COZERO_FLAG_ADR  (S5P_FIMV_COMMON_BASE_A + 0x10)
+                                       /* direct cozero flag */
+#define S5P_FIMV_H264_UP_INTRA_PRED_ADR        (S5P_FIMV_COMMON_BASE_B + 0x40)
+                                       /* upper intra PRED */
+
+/* H.263 encoding */
+#define S5P_FIMV_H263_UP_MV_ADR                (S5P_FIMV_COMMON_BASE_A)
+                                       /* upper motion vector */
+#define S5P_FIMV_H263_ACDC_COEF_ADR    (S5P_FIMV_COMMON_BASE_A + 0x04)
+                                       /* upper Q coeff. */
+
+/* MPEG4 encoding */
+#define S5P_FIMV_MPEG4_UP_MV_ADR       (S5P_FIMV_COMMON_BASE_A)
+                                       /* upper motion vector */
+#define S5P_FIMV_MPEG4_ACDC_COEF_ADR   (S5P_FIMV_COMMON_BASE_A + 0x04)
+                                       /* upper Q coeff. */
+#define S5P_FIMV_MPEG4_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10)
+                                       /* direct cozero flag */
+
+#define S5P_FIMV_ENC_REF_B_LUMA_ADR     0x062c /* ref B Luma addr */
+#define S5P_FIMV_ENC_REF_B_CHROMA_ADR   0x0630 /* ref B Chroma addr */
+
+#define S5P_FIMV_ENC_CUR_LUMA_ADR      0x0718 /* current Luma addr */
+#define S5P_FIMV_ENC_CUR_CHROMA_ADR    0x071C /* current Chroma addr */
+
+/* Codec common register */
+#define S5P_FIMV_ENC_HSIZE_PX          0x0818 /* frame width at encoder */
+#define S5P_FIMV_ENC_VSIZE_PX          0x081c /* frame height at encoder */
+#define S5P_FIMV_ENC_PROFILE           0x0830 /* profile register */
+#define S5P_FIMV_ENC_PROFILE_H264_MAIN                 0
+#define S5P_FIMV_ENC_PROFILE_H264_HIGH                 1
+#define S5P_FIMV_ENC_PROFILE_H264_BASELINE             2
+#define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE              0
+#define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE     1
+#define S5P_FIMV_ENC_PIC_STRUCT                0x083c /* picture field/frame flag */
+#define S5P_FIMV_ENC_LF_CTRL           0x0848 /* loop filter control */
+#define S5P_FIMV_ENC_ALPHA_OFF         0x084c /* loop filter alpha offset */
+#define S5P_FIMV_ENC_BETA_OFF          0x0850 /* loop filter beta offset */
+#define S5P_FIMV_MR_BUSIF_CTRL         0x0854 /* hidden, bus interface ctrl */
+#define S5P_FIMV_ENC_PXL_CACHE_CTRL    0x0a00 /* pixel cache control */
+
+/* Channel & stream interface register */
+#define S5P_FIMV_SI_RTN_CHID           0x2000 /* Return CH inst ID register */
+#define S5P_FIMV_SI_CH0_INST_ID                0x2040 /* codec instance ID */
+#define S5P_FIMV_SI_CH1_INST_ID                0x2080 /* codec instance ID */
+/* Decoder */
+#define S5P_FIMV_SI_VRESOL             0x2004 /* vertical res of decoder */
+#define S5P_FIMV_SI_HRESOL             0x2008 /* horizontal res of decoder */
+#define S5P_FIMV_SI_BUF_NUMBER         0x200c /* number of frames in the
+                                                               decoded pic */
+#define S5P_FIMV_SI_DISPLAY_Y_ADR      0x2010 /* luma addr of displayed pic */
+#define S5P_FIMV_SI_DISPLAY_C_ADR      0x2014 /* chroma addrof displayed pic */
+#define S5P_FIMV_SI_CONSUMED_BYTES     0x2018 /* Consumed number of bytes to
+                                                       decode a frame */
+#define S5P_FIMV_SI_DISPLAY_STATUS     0x201c /* status of decoded picture */
+
+#define S5P_FIMV_SI_CH0_SB_ST_ADR      0x2044 /* start addr of stream buf */
+#define S5P_FIMV_SI_CH0_SB_FRM_SIZE    0x2048 /* size of stream buf */
+#define S5P_FIMV_SI_CH0_DESC_ADR       0x204c /* addr of descriptor buf */
+#define S5P_FIMV_SI_CH0_CPB_SIZE       0x2058 /* max size of coded pic. buf */
+#define S5P_FIMV_SI_CH0_DESC_SIZE      0x205c /* max size of descriptor buf */
+
+#define S5P_FIMV_SI_CH1_SB_ST_ADR      0x2084 /* start addr of stream buf */
+#define S5P_FIMV_SI_CH1_SB_FRM_SIZE    0x2088 /* size of stream buf */
+#define S5P_FIMV_SI_CH1_DESC_ADR       0x208c /* addr of descriptor buf */
+#define S5P_FIMV_SI_CH1_CPB_SIZE       0x2098 /* max size of coded pic. buf */
+#define S5P_FIMV_SI_CH1_DESC_SIZE      0x209c /* max size of descriptor buf */
+
+#define S5P_FIMV_CRC_LUMA0             0x2030 /* luma crc data per frame
+                                                               (top field) */
+#define S5P_FIMV_CRC_CHROMA0           0x2034 /* chroma crc data per frame
+                                                               (top field) */
+#define S5P_FIMV_CRC_LUMA1             0x2038 /* luma crc data per bottom
+                                                               field */
+#define S5P_FIMV_CRC_CHROMA1           0x203c /* chroma crc data per bottom
+                                                               field */
+
+/* Display status */
+#define S5P_FIMV_DEC_STATUS_DECODING_ONLY              0
+#define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY           1
+#define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY               2
+#define S5P_FIMV_DEC_STATUS_DECODING_EMPTY             3
+#define S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK       7
+#define S5P_FIMV_DEC_STATUS_PROGRESSIVE                        (0<<3)
+#define S5P_FIMV_DEC_STATUS_INTERLACE                  (1<<3)
+#define S5P_FIMV_DEC_STATUS_INTERLACE_MASK             (1<<3)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_TWO             (0<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_FOUR            (1<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_MASK            (1<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_GENERATED              (1<<5)
+#define S5P_FIMV_DEC_STATUS_CRC_NOT_GENERATED          (0<<5)
+#define S5P_FIMV_DEC_STATUS_CRC_MASK                   (1<<5)
+
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK            (3<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_INC             (1<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC             (2<<4)
+
+/* Decode frame address */
+#define S5P_FIMV_DECODE_Y_ADR                  0x2024
+#define S5P_FIMV_DECODE_C_ADR                  0x2028
+
+/* Decoded frame tpe */
+#define S5P_FIMV_DECODE_FRAME_TYPE             0x2020
+#define S5P_FIMV_DECODE_FRAME_MASK             7
+
+#define S5P_FIMV_DECODE_FRAME_SKIPPED          0
+#define S5P_FIMV_DECODE_FRAME_I_FRAME          1
+#define S5P_FIMV_DECODE_FRAME_P_FRAME          2
+#define S5P_FIMV_DECODE_FRAME_B_FRAME          3
+#define S5P_FIMV_DECODE_FRAME_OTHER_FRAME      4
+
+/* Sizes of buffers required for decoding */
+#define S5P_FIMV_DEC_NB_IP_SIZE                        (32 * 1024)
+#define S5P_FIMV_DEC_VERT_NB_MV_SIZE           (16 * 1024)
+#define S5P_FIMV_DEC_NB_DCAC_SIZE              (16 * 1024)
+#define S5P_FIMV_DEC_UPNB_MV_SIZE              (68 * 1024)
+#define S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE                (136 * 1024)
+#define S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE     (32 * 1024)
+#define S5P_FIMV_DEC_VC1_BITPLANE_SIZE         (2 * 1024)
+#define S5P_FIMV_DEC_STX_PARSER_SIZE           (68 * 1024)
+
+#define S5P_FIMV_DEC_BUF_ALIGN                 (8 * 1024)
+#define S5P_FIMV_ENC_BUF_ALIGN                 (8 * 1024)
+#define S5P_FIMV_NV12M_HALIGN                  16
+#define S5P_FIMV_NV12M_LVALIGN                 16
+#define S5P_FIMV_NV12M_CVALIGN                 8
+#define S5P_FIMV_NV12MT_HALIGN                 128
+#define S5P_FIMV_NV12MT_VALIGN                 32
+#define S5P_FIMV_NV12M_SALIGN                  2048
+#define S5P_FIMV_NV12MT_SALIGN                 8192
+
+/* Sizes of buffers required for encoding */
+#define S5P_FIMV_ENC_UPMV_SIZE         0x10000
+#define S5P_FIMV_ENC_COLFLG_SIZE       0x10000
+#define S5P_FIMV_ENC_INTRAMD_SIZE      0x10000
+#define S5P_FIMV_ENC_INTRAPRED_SIZE    0x4000
+#define S5P_FIMV_ENC_NBORINFO_SIZE     0x10000
+#define S5P_FIMV_ENC_ACDCCOEF_SIZE     0x10000
+
+/* Encoder */
+#define S5P_FIMV_ENC_SI_STRM_SIZE      0x2004 /* stream size */
+#define S5P_FIMV_ENC_SI_PIC_CNT                0x2008 /* picture count */
+#define S5P_FIMV_ENC_SI_WRITE_PTR      0x200c /* write pointer */
+#define S5P_FIMV_ENC_SI_SLICE_TYPE     0x2010 /* slice type(I/P/B/IDR) */
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_NON_CODED   0
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_I           1
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_P           2
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_B           3
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_SKIPPED     4
+#define S5P_FIMV_ENC_SI_SLICE_TYPE_OTHERS      5
+#define S5P_FIMV_ENCODED_Y_ADDR         0x2014 /* the addr of the encoded
+                                                               luma pic */
+#define S5P_FIMV_ENCODED_C_ADDR         0x2018 /* the addr of the encoded
+                                                               chroma pic */
+
+#define S5P_FIMV_ENC_SI_CH0_SB_ADR     0x2044 /* addr of stream buf */
+#define S5P_FIMV_ENC_SI_CH0_SB_SIZE    0x204c /* size of stream buf */
+#define S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR  0x2050 /* current Luma addr */
+#define S5P_FIMV_ENC_SI_CH0_CUR_C_ADR  0x2054 /* current Chroma addr */
+#define S5P_FIMV_ENC_SI_CH0_FRAME_INS  0x2058 /* frame insertion */
+
+#define S5P_FIMV_ENC_SI_CH1_SB_ADR     0x2084 /* addr of stream buf */
+#define S5P_FIMV_ENC_SI_CH1_SB_SIZE    0x208c /* size of stream buf */
+#define S5P_FIMV_ENC_SI_CH1_CUR_Y_ADR  0x2090 /* current Luma addr */
+#define S5P_FIMV_ENC_SI_CH1_CUR_C_ADR  0x2094 /* current Chroma addr */
+#define S5P_FIMV_ENC_SI_CH1_FRAME_INS  0x2098 /* frame insertion */
+
+#define S5P_FIMV_ENC_PIC_TYPE_CTRL     0xc504 /* pic type level control */
+#define S5P_FIMV_ENC_B_RECON_WRITE_ON  0xc508 /* B frame recon write ctrl */
+#define S5P_FIMV_ENC_MSLICE_CTRL       0xc50c /* multi slice control */
+#define S5P_FIMV_ENC_MSLICE_MB         0xc510 /* MB number in the one slice */
+#define S5P_FIMV_ENC_MSLICE_BIT                0xc514 /* bit count for one slice */
+#define S5P_FIMV_ENC_CIR_CTRL          0xc518 /* number of intra refresh MB */
+#define S5P_FIMV_ENC_MAP_FOR_CUR       0xc51c /* linear or tiled mode */
+#define S5P_FIMV_ENC_PADDING_CTRL      0xc520 /* padding control */
+
+#define S5P_FIMV_ENC_RC_CONFIG         0xc5a0 /* RC config */
+#define S5P_FIMV_ENC_RC_BIT_RATE       0xc5a8 /* bit rate */
+#define S5P_FIMV_ENC_RC_QBOUND         0xc5ac /* max/min QP */
+#define S5P_FIMV_ENC_RC_RPARA          0xc5b0 /* rate control reaction coeff */
+#define S5P_FIMV_ENC_RC_MB_CTRL                0xc5b4 /* MB adaptive scaling */
+
+/* Encoder for H264 only */
+#define S5P_FIMV_ENC_H264_ENTROPY_MODE 0xd004 /* CAVLC or CABAC */
+#define S5P_FIMV_ENC_H264_ALPHA_OFF    0xd008 /* loop filter alpha offset */
+#define S5P_FIMV_ENC_H264_BETA_OFF     0xd00c /* loop filter beta offset */
+#define S5P_FIMV_ENC_H264_NUM_OF_REF   0xd010 /* number of reference for P/B */
+#define S5P_FIMV_ENC_H264_TRANS_FLAG   0xd034 /* 8x8 transform flag in PPS &
+                                                               high profile */
+
+#define S5P_FIMV_ENC_RC_FRAME_RATE     0xd0d0 /* frame rate */
+
+/* Encoder for MPEG4 only */
+#define S5P_FIMV_ENC_MPEG4_QUART_PXL   0xe008 /* qpel interpolation ctrl */
+
+/* Additional */
+#define S5P_FIMV_SI_CH0_DPB_CONF_CTRL   0x2068 /* DPB Config Control Register */
+#define S5P_FIMV_SLICE_INT_MASK                1
+#define S5P_FIMV_SLICE_INT_SHIFT       31
+#define S5P_FIMV_DDELAY_ENA_SHIFT      30
+#define S5P_FIMV_DDELAY_VAL_MASK       0xff
+#define S5P_FIMV_DDELAY_VAL_SHIFT      16
+#define S5P_FIMV_DPB_COUNT_MASK                0xffff
+#define S5P_FIMV_DPB_FLUSH_MASK                1
+#define S5P_FIMV_DPB_FLUSH_SHIFT       14
+
+
+#define S5P_FIMV_SI_CH0_RELEASE_BUF     0x2060 /* DPB release buffer register */
+#define S5P_FIMV_SI_CH0_HOST_WR_ADR    0x2064 /* address of shared memory */
+
+/* Codec numbers  */
+#define S5P_FIMV_CODEC_NONE            -1
+
+#define S5P_FIMV_CODEC_H264_DEC                0
+#define S5P_FIMV_CODEC_VC1_DEC         1
+#define S5P_FIMV_CODEC_MPEG4_DEC       2
+#define S5P_FIMV_CODEC_MPEG2_DEC       3
+#define S5P_FIMV_CODEC_H263_DEC                4
+#define S5P_FIMV_CODEC_VC1RCV_DEC      5
+
+#define S5P_FIMV_CODEC_H264_ENC                16
+#define S5P_FIMV_CODEC_MPEG4_ENC       17
+#define S5P_FIMV_CODEC_H263_ENC                18
+
+/* Channel Control Register */
+#define S5P_FIMV_CH_SEQ_HEADER         1
+#define S5P_FIMV_CH_FRAME_START                2
+#define S5P_FIMV_CH_LAST_FRAME         3
+#define S5P_FIMV_CH_INIT_BUFS          4
+#define S5P_FIMV_CH_FRAME_START_REALLOC        5
+#define S5P_FIMV_CH_MASK               7
+#define S5P_FIMV_CH_SHIFT              16
+
+
+/* Host to RISC command */
+#define S5P_FIMV_H2R_CMD_EMPTY         0
+#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE 1
+#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE        2
+#define S5P_FIMV_H2R_CMD_SYS_INIT      3
+#define S5P_FIMV_H2R_CMD_FLUSH         4
+#define S5P_FIMV_H2R_CMD_SLEEP         5
+#define S5P_FIMV_H2R_CMD_WAKEUP                6
+
+#define S5P_FIMV_R2H_CMD_EMPTY                 0
+#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET     1
+#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET    2
+#define S5P_FIMV_R2H_CMD_RSV_RET               3
+#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET          4
+#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET                5
+#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET                6
+#define S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET      7
+#define S5P_FIMV_R2H_CMD_SYS_INIT_RET          8
+#define S5P_FIMV_R2H_CMD_FW_STATUS_RET         9
+#define S5P_FIMV_R2H_CMD_SLEEP_RET             10
+#define S5P_FIMV_R2H_CMD_WAKEUP_RET            11
+#define S5P_FIMV_R2H_CMD_FLUSH_RET             12
+#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET      15
+#define S5P_FIMV_R2H_CMD_EDFU_INIT_RET         16
+#define S5P_FIMV_R2H_CMD_ERR_RET               32
+
+/* Error handling defines */
+#define S5P_FIMV_ERR_WARNINGS_START            145
+#define S5P_FIMV_ERR_DEC_MASK                  0xFFFF
+#define S5P_FIMV_ERR_DEC_SHIFT                 0
+#define S5P_FIMV_ERR_DSPL_MASK                 0xFFFF0000
+#define S5P_FIMV_ERR_DSPL_SHIFT                        16
+
+/* Shared memory registers' offsets */
+
+/* An offset of the start position in the stream when
+ * the start position is not aligned */
+#define S5P_FIMV_SHARED_CROP_INFO_H            0x0020
+#define S5P_FIMV_SHARED_CROP_LEFT_MASK         0xFFFF
+#define S5P_FIMV_SHARED_CROP_LEFT_SHIFT                0
+#define S5P_FIMV_SHARED_CROP_RIGHT_MASK                0xFFFF0000
+#define S5P_FIMV_SHARED_CROP_RIGHT_SHIFT       16
+#define S5P_FIMV_SHARED_CROP_INFO_V            0x0024
+#define S5P_FIMV_SHARED_CROP_TOP_MASK          0xFFFF
+#define S5P_FIMV_SHARED_CROP_TOP_SHIFT         0
+#define S5P_FIMV_SHARED_CROP_BOTTOM_MASK       0xFFFF0000
+#define S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT      16
+#define S5P_FIMV_SHARED_SET_FRAME_TAG          0x0004
+#define S5P_FIMV_SHARED_GET_FRAME_TAG_TOP      0x0008
+#define S5P_FIMV_SHARED_GET_FRAME_TAG_BOT      0x000C
+#define S5P_FIMV_SHARED_START_BYTE_NUM         0x0018
+#define S5P_FIMV_SHARED_RC_VOP_TIMING          0x0030
+#define S5P_FIMV_SHARED_LUMA_DPB_SIZE          0x0064
+#define S5P_FIMV_SHARED_CHROMA_DPB_SIZE                0x0068
+#define S5P_FIMV_SHARED_MV_SIZE                        0x006C
+#define S5P_FIMV_SHARED_PIC_TIME_TOP           0x0010
+#define S5P_FIMV_SHARED_PIC_TIME_BOTTOM                0x0014
+#define S5P_FIMV_SHARED_EXT_ENC_CONTROL                0x0028
+#define S5P_FIMV_SHARED_P_B_FRAME_QP           0x0070
+#define S5P_FIMV_SHARED_ASPECT_RATIO_IDC       0x0074
+#define S5P_FIMV_SHARED_EXTENDED_SAR           0x0078
+#define S5P_FIMV_SHARED_H264_I_PERIOD          0x009C
+#define S5P_FIMV_SHARED_RC_CONTROL_CONFIG      0x00A0
+
+#endif /* _REGS_FIMV_H */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc.c b/drivers/media/video/s5p-mfc/s5p_mfc.c
new file mode 100644 (file)
index 0000000..7dc7eab
--- /dev/null
@@ -0,0 +1,1274 @@
+/*
+ * Samsung S5P Multi Format Codec v 5.1
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_ctrl.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_enc.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+
+#define S5P_MFC_NAME           "s5p-mfc"
+#define S5P_MFC_DEC_NAME       "s5p-mfc-dec"
+#define S5P_MFC_ENC_NAME       "s5p-mfc-enc"
+
+int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages");
+
+/* Helper functions for interrupt processing */
+/* Remove from hw execution round robin */
+static void clear_work_bit(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       spin_lock(&dev->condlock);
+       clear_bit(ctx->num, &dev->ctx_work_bits);
+       spin_unlock(&dev->condlock);
+}
+
+/* Wake up context wait_queue */
+static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
+                       unsigned int err)
+{
+       ctx->int_cond = 1;
+       ctx->int_type = reason;
+       ctx->int_err = err;
+       wake_up(&ctx->queue);
+}
+
+/* Wake up device wait_queue */
+static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
+                       unsigned int err)
+{
+       dev->int_cond = 1;
+       dev->int_type = reason;
+       dev->int_err = err;
+       wake_up(&dev->queue);
+}
+
+void s5p_mfc_watchdog(unsigned long arg)
+{
+       struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
+
+       if (test_bit(0, &dev->hw_lock))
+               atomic_inc(&dev->watchdog_cnt);
+       if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) {
+               /* This means that hw is busy and no interrupts were
+                * generated by hw for the Nth time of running this
+                * watchdog timer. This usually means a serious hw
+                * error. Now it is time to kill all instances and
+                * reset the MFC. */
+               mfc_err("Time out during waiting for HW\n");
+               queue_work(dev->watchdog_workqueue, &dev->watchdog_work);
+       }
+       dev->watchdog_timer.expires = jiffies +
+                                       msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
+       add_timer(&dev->watchdog_timer);
+}
+
+static void s5p_mfc_watchdog_worker(struct work_struct *work)
+{
+       struct s5p_mfc_dev *dev;
+       struct s5p_mfc_ctx *ctx;
+       unsigned long flags;
+       int mutex_locked;
+       int i, ret;
+
+       dev = container_of(work, struct s5p_mfc_dev, watchdog_work);
+
+       mfc_err("Driver timeout error handling\n");
+       /* Lock the mutex that protects open and release.
+        * This is necessary as they may load and unload firmware. */
+       mutex_locked = mutex_trylock(&dev->mfc_mutex);
+       if (!mutex_locked)
+               mfc_err("Error: some instance may be closing/opening\n");
+       spin_lock_irqsave(&dev->irqlock, flags);
+
+       s5p_mfc_clock_off();
+
+       for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+               ctx = dev->ctx[i];
+               if (!ctx)
+                       continue;
+               ctx->state = MFCINST_ERROR;
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+               clear_work_bit(ctx);
+               wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0);
+       }
+       clear_bit(0, &dev->hw_lock);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       /* Double check if there is at least one instance running.
+        * If no instance is in memory than no firmware should be present */
+       if (dev->num_inst > 0) {
+               ret = s5p_mfc_reload_firmware(dev);
+               if (ret) {
+                       mfc_err("Failed to reload FW\n");
+                       goto unlock;
+               }
+               s5p_mfc_clock_on();
+               ret = s5p_mfc_init_hw(dev);
+               if (ret)
+                       mfc_err("Failed to reinit FW\n");
+       }
+unlock:
+       if (mutex_locked)
+               mutex_unlock(&dev->mfc_mutex);
+}
+
+static enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+
+       if (!vdev) {
+               mfc_err("failed to get video_device");
+               return MFCNODE_INVALID;
+       }
+       if (vdev->index == 0)
+               return MFCNODE_DECODER;
+       else if (vdev->index == 1)
+               return MFCNODE_ENCODER;
+       return MFCNODE_INVALID;
+}
+
+static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev)
+{
+       mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT);
+       mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
+       mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID);
+}
+
+static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_buf *dst_buf;
+
+       ctx->state = MFCINST_FINISHED;
+       ctx->sequence++;
+       while (!list_empty(&ctx->dst_queue)) {
+               dst_buf = list_entry(ctx->dst_queue.next,
+                                    struct s5p_mfc_buf, list);
+               mfc_debug(2, "Cleaning up buffer: %d\n",
+                                         dst_buf->b->v4l2_buf.index);
+               vb2_set_plane_payload(dst_buf->b, 0, 0);
+               vb2_set_plane_payload(dst_buf->b, 1, 0);
+               list_del(&dst_buf->list);
+               ctx->dst_queue_cnt--;
+               dst_buf->b->v4l2_buf.sequence = (ctx->sequence++);
+
+               if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) ==
+                       s5p_mfc_read_shm(ctx, PIC_TIME_BOT))
+                       dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
+               else
+                       dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED;
+
+               ctx->dec_dst_flag &= ~(1 << dst_buf->b->v4l2_buf.index);
+               vb2_buffer_done(dst_buf->b, VB2_BUF_STATE_DONE);
+       }
+}
+
+static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf  *dst_buf, *src_buf;
+       size_t dec_y_addr = s5p_mfc_get_dec_y_adr();
+       unsigned int frame_type = s5p_mfc_get_frame_type();
+
+       /* Copy timestamp / timecode from decoded src to dst and set
+          appropraite flags */
+       src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
+               if (vb2_dma_contig_plane_paddr(dst_buf->b, 0) == dec_y_addr) {
+                       memcpy(&dst_buf->b->v4l2_buf.timecode,
+                               &src_buf->b->v4l2_buf.timecode,
+                               sizeof(struct v4l2_timecode));
+                       memcpy(&dst_buf->b->v4l2_buf.timestamp,
+                               &src_buf->b->v4l2_buf.timestamp,
+                               sizeof(struct timeval));
+                       switch (frame_type) {
+                       case S5P_FIMV_DECODE_FRAME_I_FRAME:
+                               dst_buf->b->v4l2_buf.flags |=
+                                               V4L2_BUF_FLAG_KEYFRAME;
+                               break;
+                       case S5P_FIMV_DECODE_FRAME_P_FRAME:
+                               dst_buf->b->v4l2_buf.flags |=
+                                               V4L2_BUF_FLAG_PFRAME;
+                               break;
+                       case S5P_FIMV_DECODE_FRAME_B_FRAME:
+                               dst_buf->b->v4l2_buf.flags |=
+                                               V4L2_BUF_FLAG_BFRAME;
+                               break;
+                       }
+                       break;
+               }
+       }
+}
+
+static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf  *dst_buf;
+       size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr();
+       unsigned int frame_type = s5p_mfc_get_frame_type();
+       unsigned int index;
+
+       /* If frame is same as previous then skip and do not dequeue */
+       if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
+               if (!ctx->after_packed_pb)
+                       ctx->sequence++;
+               ctx->after_packed_pb = 0;
+               return;
+       }
+       ctx->sequence++;
+       /* The MFC returns address of the buffer, now we have to
+        * check which videobuf does it correspond to */
+       list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
+               /* Check if this is the buffer we're looking for */
+               if (vb2_dma_contig_plane_paddr(dst_buf->b, 0) == dspl_y_addr) {
+                       list_del(&dst_buf->list);
+                       ctx->dst_queue_cnt--;
+                       dst_buf->b->v4l2_buf.sequence = ctx->sequence;
+                       if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) ==
+                               s5p_mfc_read_shm(ctx, PIC_TIME_BOT))
+                               dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
+                       else
+                               dst_buf->b->v4l2_buf.field =
+                                                       V4L2_FIELD_INTERLACED;
+                       vb2_set_plane_payload(dst_buf->b, 0, ctx->luma_size);
+                       vb2_set_plane_payload(dst_buf->b, 1, ctx->chroma_size);
+                       clear_bit(dst_buf->b->v4l2_buf.index,
+                                                       &ctx->dec_dst_flag);
+
+                       vb2_buffer_done(dst_buf->b,
+                               err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+                       index = dst_buf->b->v4l2_buf.index;
+                       break;
+               }
+       }
+}
+
+/* Handle frame decoding interrupt */
+static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
+                                       unsigned int reason, unsigned int err)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned int dst_frame_status;
+       struct s5p_mfc_buf *src_buf;
+       unsigned long flags;
+       unsigned int res_change;
+
+       unsigned int index;
+
+       dst_frame_status = s5p_mfc_get_dspl_status()
+                               & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
+       res_change = s5p_mfc_get_dspl_status()
+                               & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK;
+       mfc_debug(2, "Frame Status: %x\n", dst_frame_status);
+       if (ctx->state == MFCINST_RES_CHANGE_INIT)
+               ctx->state = MFCINST_RES_CHANGE_FLUSH;
+       if (res_change) {
+               ctx->state = MFCINST_RES_CHANGE_INIT;
+               s5p_mfc_clear_int_flags(dev);
+               wake_up_ctx(ctx, reason, err);
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       BUG();
+               s5p_mfc_clock_off();
+               s5p_mfc_try_run(dev);
+               return;
+       }
+       if (ctx->dpb_flush_flag)
+               ctx->dpb_flush_flag = 0;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       /* All frames remaining in the buffer have been extracted  */
+       if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
+               if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
+                       s5p_mfc_handle_frame_all_extracted(ctx);
+                       ctx->state = MFCINST_RES_CHANGE_END;
+                       goto leave_handle_frame;
+               } else {
+                       s5p_mfc_handle_frame_all_extracted(ctx);
+               }
+       }
+
+       if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY ||
+               dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY)
+               s5p_mfc_handle_frame_copy_time(ctx);
+
+       /* A frame has been decoded and is in the buffer  */
+       if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY ||
+           dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) {
+               s5p_mfc_handle_frame_new(ctx, err);
+       } else {
+               mfc_debug(2, "No frame decode\n");
+       }
+       /* Mark source buffer as complete */
+       if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY
+               && !list_empty(&ctx->src_queue)) {
+               src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
+                                                               list);
+               ctx->consumed_stream += s5p_mfc_get_consumed_stream();
+               if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC &&
+                       s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME
+                                       && ctx->consumed_stream + STUFF_BYTE <
+                                       src_buf->b->v4l2_planes[0].bytesused) {
+                       /* Run MFC again on the same buffer */
+                       mfc_debug(2, "Running again the same buffer\n");
+                       ctx->after_packed_pb = 1;
+               } else {
+                       index = src_buf->b->v4l2_buf.index;
+                       mfc_debug(2, "MFC needs next buffer\n");
+                       ctx->consumed_stream = 0;
+                       list_del(&src_buf->list);
+                       ctx->src_queue_cnt--;
+                       if (s5p_mfc_err_dec(err) > 0)
+                               vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR);
+                       else
+                               vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE);
+               }
+       }
+leave_handle_frame:
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
+                                   || ctx->dst_queue_cnt < ctx->dpb_count)
+               clear_work_bit(ctx);
+       s5p_mfc_clear_int_flags(dev);
+       wake_up_ctx(ctx, reason, err);
+       if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+               BUG();
+       s5p_mfc_clock_off();
+       s5p_mfc_try_run(dev);
+}
+
+/* Error handling for interrupt */
+static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx,
+                                unsigned int reason, unsigned int err)
+{
+       struct s5p_mfc_dev *dev;
+       unsigned long flags;
+
+       /* If no context is available then all necessary
+        * processing has been done. */
+       if (ctx == 0)
+               return;
+
+       dev = ctx->dev;
+       mfc_err("Interrupt Error: %08x\n", err);
+       s5p_mfc_clear_int_flags(dev);
+       wake_up_dev(dev, reason, err);
+
+       /* Error recovery is dependent on the state of context */
+       switch (ctx->state) {
+       case MFCINST_INIT:
+               /* This error had to happen while acquireing instance */
+       case MFCINST_GOT_INST:
+               /* This error had to happen while parsing the header */
+       case MFCINST_HEAD_PARSED:
+               /* This error had to happen while setting dst buffers */
+       case MFCINST_RETURN_INST:
+               /* This error had to happen while releasing instance */
+               clear_work_bit(ctx);
+               wake_up_ctx(ctx, reason, err);
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       BUG();
+               s5p_mfc_clock_off();
+               ctx->state = MFCINST_ERROR;
+               break;
+       case MFCINST_FINISHING:
+       case MFCINST_FINISHED:
+       case MFCINST_RUNNING:
+               /* It is higly probable that an error occured
+                * while decoding a frame */
+               clear_work_bit(ctx);
+               ctx->state = MFCINST_ERROR;
+               /* Mark all dst buffers as having an error */
+               spin_lock_irqsave(&dev->irqlock, flags);
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+               /* Mark all src buffers as having an error */
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       BUG();
+               s5p_mfc_clock_off();
+               break;
+       default:
+               mfc_err("Encountered an error interrupt which had not been handled\n");
+               break;
+       }
+       return;
+}
+
+/* Header parsing interrupt handling */
+static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
+                                unsigned int reason, unsigned int err)
+{
+       struct s5p_mfc_dev *dev;
+       unsigned int guard_width, guard_height;
+
+       if (ctx == 0)
+               return;
+       dev = ctx->dev;
+       if (ctx->c_ops->post_seq_start) {
+               if (ctx->c_ops->post_seq_start(ctx))
+                       mfc_err("post_seq_start() failed\n");
+       } else {
+               ctx->img_width = s5p_mfc_get_img_width();
+               ctx->img_height = s5p_mfc_get_img_height();
+
+               ctx->buf_width = ALIGN(ctx->img_width,
+                                               S5P_FIMV_NV12MT_HALIGN);
+               ctx->buf_height = ALIGN(ctx->img_height,
+                                               S5P_FIMV_NV12MT_VALIGN);
+               mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, "
+                       "buffer dimensions: %dx%d\n", ctx->img_width,
+                               ctx->img_height, ctx->buf_width,
+                                               ctx->buf_height);
+               if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
+                       ctx->luma_size = ALIGN(ctx->buf_width *
+                               ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN);
+                       ctx->chroma_size = ALIGN(ctx->buf_width *
+                                        ALIGN((ctx->img_height >> 1),
+                                              S5P_FIMV_NV12MT_VALIGN),
+                                              S5P_FIMV_DEC_BUF_ALIGN);
+                       ctx->mv_size = ALIGN(ctx->buf_width *
+                                       ALIGN((ctx->buf_height >> 2),
+                                       S5P_FIMV_NV12MT_VALIGN),
+                                       S5P_FIMV_DEC_BUF_ALIGN);
+               } else {
+                       guard_width = ALIGN(ctx->img_width + 24,
+                                       S5P_FIMV_NV12MT_HALIGN);
+                       guard_height = ALIGN(ctx->img_height + 16,
+                                               S5P_FIMV_NV12MT_VALIGN);
+                       ctx->luma_size = ALIGN(guard_width *
+                               guard_height, S5P_FIMV_DEC_BUF_ALIGN);
+                       guard_width = ALIGN(ctx->img_width + 16,
+                                               S5P_FIMV_NV12MT_HALIGN);
+                       guard_height = ALIGN((ctx->img_height >> 1) + 4,
+                                               S5P_FIMV_NV12MT_VALIGN);
+                       ctx->chroma_size = ALIGN(guard_width *
+                               guard_height, S5P_FIMV_DEC_BUF_ALIGN);
+                       ctx->mv_size = 0;
+               }
+               ctx->dpb_count = s5p_mfc_get_dpb_count();
+               if (ctx->img_width == 0 || ctx->img_width == 0)
+                       ctx->state = MFCINST_ERROR;
+               else
+                       ctx->state = MFCINST_HEAD_PARSED;
+       }
+       s5p_mfc_clear_int_flags(dev);
+       clear_work_bit(ctx);
+       if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+               BUG();
+       s5p_mfc_clock_off();
+       s5p_mfc_try_run(dev);
+       wake_up_ctx(ctx, reason, err);
+}
+
+/* Header parsing interrupt handling */
+static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
+                                unsigned int reason, unsigned int err)
+{
+       struct s5p_mfc_buf *src_buf;
+       struct s5p_mfc_dev *dev;
+       unsigned long flags;
+
+       if (ctx == 0)
+               return;
+       dev = ctx->dev;
+       s5p_mfc_clear_int_flags(dev);
+       ctx->int_type = reason;
+       ctx->int_err = err;
+       ctx->int_cond = 1;
+       spin_lock(&dev->condlock);
+       clear_bit(ctx->num, &dev->ctx_work_bits);
+       spin_unlock(&dev->condlock);
+       if (err == 0) {
+               ctx->state = MFCINST_RUNNING;
+               if (!ctx->dpb_flush_flag) {
+                       spin_lock_irqsave(&dev->irqlock, flags);
+                       if (!list_empty(&ctx->src_queue)) {
+                               src_buf = list_entry(ctx->src_queue.next,
+                                            struct s5p_mfc_buf, list);
+                               list_del(&src_buf->list);
+                               ctx->src_queue_cnt--;
+                               vb2_buffer_done(src_buf->b,
+                                               VB2_BUF_STATE_DONE);
+                       }
+                       spin_unlock_irqrestore(&dev->irqlock, flags);
+               } else {
+                       ctx->dpb_flush_flag = 0;
+               }
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       BUG();
+
+               s5p_mfc_clock_off();
+
+               wake_up(&ctx->queue);
+               s5p_mfc_try_run(dev);
+       } else {
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       BUG();
+
+               s5p_mfc_clock_off();
+
+               wake_up(&ctx->queue);
+       }
+}
+
+/* Interrupt processing */
+static irqreturn_t s5p_mfc_irq(int irq, void *priv)
+{
+       struct s5p_mfc_dev *dev = priv;
+       struct s5p_mfc_ctx *ctx;
+       unsigned int reason;
+       unsigned int err;
+
+       mfc_debug_enter();
+       /* Reset the timeout watchdog */
+       atomic_set(&dev->watchdog_cnt, 0);
+       ctx = dev->ctx[dev->curr_ctx];
+       /* Get the reason of interrupt and the error code */
+       reason = s5p_mfc_get_int_reason();
+       err = s5p_mfc_get_int_err();
+       mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err);
+       switch (reason) {
+       case S5P_FIMV_R2H_CMD_ERR_RET:
+               /* An error has occured */
+               if (ctx->state == MFCINST_RUNNING &&
+                       s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START)
+                       s5p_mfc_handle_frame(ctx, reason, err);
+               else
+                       s5p_mfc_handle_error(ctx, reason, err);
+               clear_bit(0, &dev->enter_suspend);
+               break;
+
+       case S5P_FIMV_R2H_CMD_SLICE_DONE_RET:
+       case S5P_FIMV_R2H_CMD_FRAME_DONE_RET:
+               if (ctx->c_ops->post_frame_start) {
+                       if (ctx->c_ops->post_frame_start(ctx))
+                               mfc_err("post_frame_start() failed\n");
+                       s5p_mfc_clear_int_flags(dev);
+                       wake_up_ctx(ctx, reason, err);
+                       if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                               BUG();
+                       s5p_mfc_clock_off();
+                       s5p_mfc_try_run(dev);
+               } else {
+                       s5p_mfc_handle_frame(ctx, reason, err);
+               }
+               break;
+
+       case S5P_FIMV_R2H_CMD_SEQ_DONE_RET:
+               s5p_mfc_handle_seq_done(ctx, reason, err);
+               break;
+
+       case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET:
+               ctx->inst_no = s5p_mfc_get_inst_no();
+               ctx->state = MFCINST_GOT_INST;
+               clear_work_bit(ctx);
+               wake_up(&ctx->queue);
+               goto irq_cleanup_hw;
+
+       case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET:
+               clear_work_bit(ctx);
+               ctx->state = MFCINST_FREE;
+               wake_up(&ctx->queue);
+               goto irq_cleanup_hw;
+
+       case S5P_FIMV_R2H_CMD_SYS_INIT_RET:
+       case S5P_FIMV_R2H_CMD_FW_STATUS_RET:
+       case S5P_FIMV_R2H_CMD_SLEEP_RET:
+       case S5P_FIMV_R2H_CMD_WAKEUP_RET:
+               if (ctx)
+                       clear_work_bit(ctx);
+               s5p_mfc_clear_int_flags(dev);
+               wake_up_dev(dev, reason, err);
+               clear_bit(0, &dev->hw_lock);
+               clear_bit(0, &dev->enter_suspend);
+               break;
+
+       case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET:
+               s5p_mfc_handle_init_buffers(ctx, reason, err);
+               break;
+       default:
+               mfc_debug(2, "Unknown int reason\n");
+               s5p_mfc_clear_int_flags(dev);
+       }
+       mfc_debug_leave();
+       return IRQ_HANDLED;
+irq_cleanup_hw:
+       s5p_mfc_clear_int_flags(dev);
+       ctx->int_type = reason;
+       ctx->int_err = err;
+       ctx->int_cond = 1;
+       if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+               mfc_err("Failed to unlock hw\n");
+
+       s5p_mfc_clock_off();
+
+       s5p_mfc_try_run(dev);
+       mfc_debug(2, "Exit via irq_cleanup_hw\n");
+       return IRQ_HANDLED;
+}
+
+/* Open an MFC node */
+static int s5p_mfc_open(struct file *file)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+       struct s5p_mfc_ctx *ctx = NULL;
+       struct vb2_queue *q;
+       unsigned long flags;
+       int ret = 0;
+
+       mfc_debug_enter();
+       dev->num_inst++;        /* It is guarded by mfc_mutex in vfd */
+       /* Allocate memory for context */
+       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+       if (!ctx) {
+               mfc_err("Not enough memory\n");
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+       ctx->dev = dev;
+       INIT_LIST_HEAD(&ctx->src_queue);
+       INIT_LIST_HEAD(&ctx->dst_queue);
+       ctx->src_queue_cnt = 0;
+       ctx->dst_queue_cnt = 0;
+       /* Get context number */
+       ctx->num = 0;
+       while (dev->ctx[ctx->num]) {
+               ctx->num++;
+               if (ctx->num >= MFC_NUM_CONTEXTS) {
+                       mfc_err("Too many open contexts\n");
+                       ret = -EBUSY;
+                       goto err_no_ctx;
+               }
+       }
+       /* Mark context as idle */
+       spin_lock_irqsave(&dev->condlock, flags);
+       clear_bit(ctx->num, &dev->ctx_work_bits);
+       spin_unlock_irqrestore(&dev->condlock, flags);
+       dev->ctx[ctx->num] = ctx;
+       if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+               ctx->type = MFCINST_DECODER;
+               ctx->c_ops = get_dec_codec_ops();
+               /* Setup ctrl handler */
+               ret = s5p_mfc_dec_ctrls_setup(ctx);
+               if (ret) {
+                       mfc_err("Failed to setup mfc controls\n");
+                       goto err_ctrls_setup;
+               }
+       } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+               ctx->type = MFCINST_ENCODER;
+               ctx->c_ops = get_enc_codec_ops();
+               /* only for encoder */
+               INIT_LIST_HEAD(&ctx->ref_queue);
+               ctx->ref_queue_cnt = 0;
+               /* Setup ctrl handler */
+               ret = s5p_mfc_enc_ctrls_setup(ctx);
+               if (ret) {
+                       mfc_err("Failed to setup mfc controls\n");
+                       goto err_ctrls_setup;
+               }
+       } else {
+               ret = -ENOENT;
+               goto err_bad_node;
+       }
+       ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+       ctx->inst_no = -1;
+       /* Load firmware if this is the first instance */
+       if (dev->num_inst == 1) {
+               dev->watchdog_timer.expires = jiffies +
+                                       msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
+               add_timer(&dev->watchdog_timer);
+               ret = s5p_mfc_power_on();
+               if (ret < 0) {
+                       mfc_err("power on failed\n");
+                       goto err_pwr_enable;
+               }
+               s5p_mfc_clock_on();
+               ret = s5p_mfc_alloc_and_load_firmware(dev);
+               if (ret)
+                       goto err_alloc_fw;
+               /* Init the FW */
+               ret = s5p_mfc_init_hw(dev);
+               if (ret)
+                       goto err_init_hw;
+               s5p_mfc_clock_off();
+       }
+       /* Init videobuf2 queue for CAPTURE */
+       q = &ctx->vq_dst;
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+       q->drv_priv = &ctx->fh;
+       if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+               q->io_modes = VB2_MMAP;
+               q->ops = get_dec_queue_ops();
+       } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+               q->io_modes = VB2_MMAP | VB2_USERPTR;
+               q->ops = get_enc_queue_ops();
+       } else {
+               ret = -ENOENT;
+               goto err_queue_init;
+       }
+       q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+       ret = vb2_queue_init(q);
+       if (ret) {
+               mfc_err("Failed to initialize videobuf2 queue(capture)\n");
+               goto err_queue_init;
+       }
+       /* Init videobuf2 queue for OUTPUT */
+       q = &ctx->vq_src;
+       q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+       q->io_modes = VB2_MMAP;
+       q->drv_priv = &ctx->fh;
+       if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+               q->io_modes = VB2_MMAP;
+               q->ops = get_dec_queue_ops();
+       } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+               q->io_modes = VB2_MMAP | VB2_USERPTR;
+               q->ops = get_enc_queue_ops();
+       } else {
+               ret = -ENOENT;
+               goto err_queue_init;
+       }
+       q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+       ret = vb2_queue_init(q);
+       if (ret) {
+               mfc_err("Failed to initialize videobuf2 queue(output)\n");
+               goto err_queue_init;
+       }
+       init_waitqueue_head(&ctx->queue);
+       mfc_debug_leave();
+       return ret;
+       /* Deinit when failure occured */
+err_queue_init:
+err_init_hw:
+       s5p_mfc_release_firmware(dev);
+err_alloc_fw:
+       dev->ctx[ctx->num] = 0;
+       del_timer_sync(&dev->watchdog_timer);
+       s5p_mfc_clock_off();
+err_pwr_enable:
+       if (dev->num_inst == 1) {
+               if (s5p_mfc_power_off() < 0)
+                       mfc_err("power off failed\n");
+               s5p_mfc_release_firmware(dev);
+       }
+err_ctrls_setup:
+       s5p_mfc_dec_ctrls_delete(ctx);
+err_bad_node:
+err_no_ctx:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+err_alloc:
+       dev->num_inst--;
+       mfc_debug_leave();
+       return ret;
+}
+
+/* Release MFC context */
+static int s5p_mfc_release(struct file *file)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+
+       mfc_debug_enter();
+       s5p_mfc_clock_on();
+       vb2_queue_release(&ctx->vq_src);
+       vb2_queue_release(&ctx->vq_dst);
+       /* Mark context as idle */
+       spin_lock_irqsave(&dev->condlock, flags);
+       clear_bit(ctx->num, &dev->ctx_work_bits);
+       spin_unlock_irqrestore(&dev->condlock, flags);
+       /* If instance was initialised then
+        * return instance and free reosurces */
+       if (ctx->inst_no != MFC_NO_INSTANCE_SET) {
+               mfc_debug(2, "Has to free instance\n");
+               ctx->state = MFCINST_RETURN_INST;
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+               s5p_mfc_clean_ctx_int_flags(ctx);
+               s5p_mfc_try_run(dev);
+               /* Wait until instance is returned or timeout occured */
+               if (s5p_mfc_wait_for_done_ctx
+                   (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) {
+                       s5p_mfc_clock_off();
+                       mfc_err("Err returning instance\n");
+               }
+               mfc_debug(2, "After free instance\n");
+               /* Free resources */
+               s5p_mfc_release_codec_buffers(ctx);
+               s5p_mfc_release_instance_buffer(ctx);
+               if (ctx->type == MFCINST_DECODER)
+                       s5p_mfc_release_dec_desc_buffer(ctx);
+
+               ctx->inst_no = MFC_NO_INSTANCE_SET;
+       }
+       /* hardware locking scheme */
+       if (dev->curr_ctx == ctx->num)
+               clear_bit(0, &dev->hw_lock);
+       dev->num_inst--;
+       if (dev->num_inst == 0) {
+               mfc_debug(2, "Last instance - release firmware\n");
+               /* reset <-> F/W release */
+               s5p_mfc_reset(dev);
+               s5p_mfc_release_firmware(dev);
+               del_timer_sync(&dev->watchdog_timer);
+               if (s5p_mfc_power_off() < 0)
+                       mfc_err("Power off failed\n");
+       }
+       mfc_debug(2, "Shutting down clock\n");
+       s5p_mfc_clock_off();
+       dev->ctx[ctx->num] = 0;
+       s5p_mfc_dec_ctrls_delete(ctx);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+       mfc_debug_leave();
+       return 0;
+}
+
+/* Poll */
+static unsigned int s5p_mfc_poll(struct file *file,
+                                struct poll_table_struct *wait)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct vb2_queue *src_q, *dst_q;
+       struct vb2_buffer *src_vb = NULL, *dst_vb = NULL;
+       unsigned int rc = 0;
+       unsigned long flags;
+
+       src_q = &ctx->vq_src;
+       dst_q = &ctx->vq_dst;
+       /*
+        * There has to be at least one buffer queued on each queued_list, which
+        * means either in driver already or waiting for driver to claim it
+        * and start processing.
+        */
+       if ((!src_q->streaming || list_empty(&src_q->queued_list))
+               && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+               rc = POLLERR;
+               goto end;
+       }
+       mutex_unlock(&dev->mfc_mutex);
+       poll_wait(file, &src_q->done_wq, wait);
+       poll_wait(file, &dst_q->done_wq, wait);
+       mutex_lock(&dev->mfc_mutex);
+       spin_lock_irqsave(&src_q->done_lock, flags);
+       if (!list_empty(&src_q->done_list))
+               src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer,
+                                                               done_entry);
+       if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE
+                               || src_vb->state == VB2_BUF_STATE_ERROR))
+               rc |= POLLOUT | POLLWRNORM;
+       spin_unlock_irqrestore(&src_q->done_lock, flags);
+       spin_lock_irqsave(&dst_q->done_lock, flags);
+       if (!list_empty(&dst_q->done_list))
+               dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer,
+                                                               done_entry);
+       if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE
+                               || dst_vb->state == VB2_BUF_STATE_ERROR))
+               rc |= POLLIN | POLLRDNORM;
+       spin_unlock_irqrestore(&dst_q->done_lock, flags);
+end:
+       return rc;
+}
+
+/* Mmap */
+static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       int ret;
+       if (offset < DST_QUEUE_OFF_BASE) {
+               mfc_debug(2, "mmaping source\n");
+               ret = vb2_mmap(&ctx->vq_src, vma);
+       } else {                /* capture */
+               mfc_debug(2, "mmaping destination\n");
+               vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
+               ret = vb2_mmap(&ctx->vq_dst, vma);
+       }
+       return ret;
+}
+
+/* v4l2 ops */
+static const struct v4l2_file_operations s5p_mfc_fops = {
+       .owner = THIS_MODULE,
+       .open = s5p_mfc_open,
+       .release = s5p_mfc_release,
+       .poll = s5p_mfc_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap = s5p_mfc_mmap,
+};
+
+static int match_child(struct device *dev, void *data)
+{
+       if (!dev_name(dev))
+               return 0;
+       return !strcmp(dev_name(dev), (char *)data);
+}
+
+
+/* MFC probe function */
+static int __devinit s5p_mfc_probe(struct platform_device *pdev)
+{
+       struct s5p_mfc_dev *dev;
+       struct video_device *vfd;
+       struct resource *res;
+       int ret;
+
+       pr_debug("%s++\n", __func__);
+       dev = kzalloc(sizeof *dev, GFP_KERNEL);
+       if (!dev) {
+               dev_err(&pdev->dev, "Not enough memory for MFC device\n");
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&dev->irqlock);
+       spin_lock_init(&dev->condlock);
+       dev->plat_dev = pdev;
+       if (!dev->plat_dev) {
+               dev_err(&pdev->dev, "No platform data specified\n");
+               ret = -ENODEV;
+               goto err_dev;
+       }
+
+       ret = s5p_mfc_init_pm(dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to get mfc clock source\n");
+               goto err_clk;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get memory region resource\n");
+               ret = -ENOENT;
+               goto err_res;
+       }
+
+       dev->mfc_mem = request_mem_region(res->start, resource_size(res),
+                                         pdev->name);
+       if (dev->mfc_mem == NULL) {
+               dev_err(&pdev->dev, "failed to get memory region\n");
+               ret = -ENOENT;
+               goto err_mem_reg;
+       }
+       dev->regs_base = ioremap(dev->mfc_mem->start, resource_size(dev->mfc_mem));
+       if (dev->regs_base == NULL) {
+               dev_err(&pdev->dev, "failed to ioremap address region\n");
+               ret = -ENOENT;
+               goto err_ioremap;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get irq resource\n");
+               ret = -ENOENT;
+               goto err_get_res;
+       }
+       dev->irq = res->start;
+       ret = request_irq(dev->irq, s5p_mfc_irq, IRQF_DISABLED, pdev->name,
+                                                                       dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
+               goto err_req_irq;
+       }
+
+       dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, "s5p-mfc-l",
+                                          match_child);
+       if (!dev->mem_dev_l) {
+               mfc_err("Mem child (L) device get failed\n");
+               ret = -ENODEV;
+               goto err_find_child;
+       }
+       dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r",
+                                          match_child);
+       if (!dev->mem_dev_r) {
+               mfc_err("Mem child (R) device get failed\n");
+               ret = -ENODEV;
+               goto err_find_child;
+       }
+
+       dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l);
+       if (IS_ERR_OR_NULL(dev->alloc_ctx[0])) {
+               ret = PTR_ERR(dev->alloc_ctx[0]);
+               goto err_mem_init_ctx_0;
+       }
+       dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r);
+       if (IS_ERR_OR_NULL(dev->alloc_ctx[1])) {
+               ret = PTR_ERR(dev->alloc_ctx[1]);
+               goto err_mem_init_ctx_1;
+       }
+
+       mutex_init(&dev->mfc_mutex);
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret)
+               goto err_v4l2_dev_reg;
+       init_waitqueue_head(&dev->queue);
+
+       /* decoder */
+       vfd = video_device_alloc();
+       if (!vfd) {
+               v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+               ret = -ENOMEM;
+               goto err_dec_alloc;
+       }
+       vfd->fops       = &s5p_mfc_fops,
+       vfd->ioctl_ops  = get_dec_v4l2_ioctl_ops();
+       vfd->release    = video_device_release,
+       vfd->lock       = &dev->mfc_mutex;
+       vfd->v4l2_dev   = &dev->v4l2_dev;
+       snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
+       dev->vfd_dec    = vfd;
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+               video_device_release(vfd);
+               goto err_dec_reg;
+       }
+       v4l2_info(&dev->v4l2_dev,
+                 "decoder registered as /dev/video%d\n", vfd->num);
+       video_set_drvdata(vfd, dev);
+
+       /* encoder */
+       vfd = video_device_alloc();
+       if (!vfd) {
+               v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+               ret = -ENOMEM;
+               goto err_enc_alloc;
+       }
+       vfd->fops       = &s5p_mfc_fops,
+       vfd->ioctl_ops  = get_enc_v4l2_ioctl_ops();
+       vfd->release    = video_device_release,
+       vfd->lock       = &dev->mfc_mutex;
+       vfd->v4l2_dev   = &dev->v4l2_dev;
+       snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME);
+       dev->vfd_enc    = vfd;
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+               video_device_release(vfd);
+               goto err_enc_reg;
+       }
+       v4l2_info(&dev->v4l2_dev,
+                 "encoder registered as /dev/video%d\n", vfd->num);
+       video_set_drvdata(vfd, dev);
+       platform_set_drvdata(pdev, dev);
+
+       dev->hw_lock = 0;
+       dev->watchdog_workqueue = create_singlethread_workqueue(S5P_MFC_NAME);
+       INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker);
+       atomic_set(&dev->watchdog_cnt, 0);
+       init_timer(&dev->watchdog_timer);
+       dev->watchdog_timer.data = (unsigned long)dev;
+       dev->watchdog_timer.function = s5p_mfc_watchdog;
+
+       pr_debug("%s--\n", __func__);
+       return 0;
+
+/* Deinit MFC if probe had failed */
+err_enc_reg:
+       video_device_release(dev->vfd_enc);
+err_enc_alloc:
+       video_unregister_device(dev->vfd_dec);
+err_dec_reg:
+       video_device_release(dev->vfd_dec);
+err_dec_alloc:
+       v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2_dev_reg:
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
+err_mem_init_ctx_1:
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
+err_mem_init_ctx_0:
+err_find_child:
+       free_irq(dev->irq, dev);
+err_req_irq:
+err_get_res:
+       iounmap(dev->regs_base);
+       dev->regs_base = NULL;
+err_ioremap:
+       release_resource(dev->mfc_mem);
+       kfree(dev->mfc_mem);
+err_mem_reg:
+err_res:
+       s5p_mfc_final_pm(dev);
+err_clk:
+err_dev:
+       kfree(dev);
+       pr_debug("%s-- with error\n", __func__);
+       return ret;
+
+}
+
+/* Remove the driver */
+static int __devexit s5p_mfc_remove(struct platform_device *pdev)
+{
+       struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
+
+       v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name);
+
+       del_timer_sync(&dev->watchdog_timer);
+       flush_workqueue(dev->watchdog_workqueue);
+       destroy_workqueue(dev->watchdog_workqueue);
+
+       video_unregister_device(dev->vfd_enc);
+       video_unregister_device(dev->vfd_dec);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
+
+       free_irq(dev->irq, dev);
+       iounmap(dev->regs_base);
+       if (dev->mfc_mem) {
+               release_resource(dev->mfc_mem);
+               kfree(dev->mfc_mem);
+               dev->mfc_mem = NULL;
+       }
+       s5p_mfc_final_pm(dev);
+       kfree(dev);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int s5p_mfc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+       int ret;
+
+       if (m_dev->num_inst == 0)
+               return 0;
+       return s5p_mfc_sleep(m_dev);
+       if (test_and_set_bit(0, &m_dev->enter_suspend) != 0) {
+               mfc_err("Error: going to suspend for a second time\n");
+               return -EIO;
+       }
+
+       /* Check if we're processing then wait if it necessary. */
+       while (test_and_set_bit(0, &m_dev->hw_lock) != 0) {
+               /* Try and lock the HW */
+               /* Wait on the interrupt waitqueue */
+               ret = wait_event_interruptible_timeout(m_dev->queue,
+                       m_dev->int_cond || m_dev->ctx[m_dev->curr_ctx]->int_cond,
+                       msecs_to_jiffies(MFC_INT_TIMEOUT));
+
+               if (ret == 0) {
+                       mfc_err("Waiting for hardware to finish timed out\n");
+                       return -EIO;
+               }
+       }
+       return 0;
+}
+
+static int s5p_mfc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+
+       if (m_dev->num_inst == 0)
+               return 0;
+       return s5p_mfc_wakeup(m_dev);
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int s5p_mfc_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+
+       atomic_set(&m_dev->pm.power, 0);
+       return 0;
+}
+
+static int s5p_mfc_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev);
+       int pre_power;
+
+       if (!m_dev->alloc_ctx)
+               return 0;
+       pre_power = atomic_read(&m_dev->pm.power);
+       atomic_set(&m_dev->pm.power, 1);
+       return 0;
+}
+#endif
+
+/* Power management */
+static const struct dev_pm_ops s5p_mfc_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume)
+       SET_RUNTIME_PM_OPS(s5p_mfc_runtime_suspend, s5p_mfc_runtime_resume,
+                          NULL)
+};
+
+static struct platform_driver s5p_mfc_pdrv = {
+       .probe  = s5p_mfc_probe,
+       .remove = __devexit_p(s5p_mfc_remove),
+       .driver = {
+               .name   = S5P_MFC_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &s5p_mfc_pm_ops
+       },
+};
+
+static char banner[] __initdata =
+                       "S5P MFC V4L2 Driver, (C) 2011 Samsung Electronics\n";
+
+static int __init s5p_mfc_init(void)
+{
+       int ret;
+
+       pr_info("%s", banner);
+       ret = platform_driver_register(&s5p_mfc_pdrv);
+       if (ret)
+               pr_err("Platform device registration failed.\n");
+       return ret;
+}
+
+static void __devexit s5p_mfc_exit(void)
+{
+       platform_driver_unregister(&s5p_mfc_pdrv);
+}
+
+module_init(s5p_mfc_init);
+module_exit(s5p_mfc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_DESCRIPTION("Samsung S5P Multi Format Codec V4L2 driver");
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c
new file mode 100644 (file)
index 0000000..f0665ed
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#include "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+
+/* This function is used to send a command to the MFC */
+static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd,
+                                               struct s5p_mfc_cmd_args *args)
+{
+       int cur_cmd;
+       unsigned long timeout;
+
+       timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+       /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */
+       do {
+               if (time_after(jiffies, timeout)) {
+                       mfc_err("Timeout while waiting for hardware\n");
+                       return -EIO;
+               }
+               cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD);
+       } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY);
+       mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1);
+       mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2);
+       mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3);
+       mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4);
+       /* Issue the command */
+       mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD);
+       return 0;
+}
+
+/* Initialize the MFC */
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev)
+{
+       struct s5p_mfc_cmd_args h2r_args;
+
+       memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+       h2r_args.arg[0] = dev->fw_size;
+       return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args);
+}
+
+/* Suspend the MFC hardware */
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev)
+{
+       struct s5p_mfc_cmd_args h2r_args;
+
+       memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+       return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args);
+}
+
+/* Wake up the MFC hardware */
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev)
+{
+       struct s5p_mfc_cmd_args h2r_args;
+
+       memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+       return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args);
+}
+
+
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_cmd_args h2r_args;
+       int ret;
+
+       /* Preparing decoding - getting instance number */
+       mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode);
+       dev->curr_ctx = ctx->num;
+       memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+       h2r_args.arg[0] = ctx->codec_mode;
+       h2r_args.arg[1] = 0; /* no crc & no pixelcache */
+       h2r_args.arg[2] = ctx->ctx_ofs;
+       h2r_args.arg[3] = ctx->ctx_size;
+       ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE,
+                                                               &h2r_args);
+       if (ret) {
+               mfc_err("Failed to create a new instance\n");
+               ctx->state = MFCINST_ERROR;
+       }
+       return ret;
+}
+
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_cmd_args h2r_args;
+       int ret;
+
+       if (ctx->state == MFCINST_FREE) {
+               mfc_err("Instance already returned\n");
+               ctx->state = MFCINST_ERROR;
+               return -EINVAL;
+       }
+       /* Closing decoding instance  */
+       mfc_debug(2, "Returning instance number %d\n", ctx->inst_no);
+       dev->curr_ctx = ctx->num;
+       memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+       h2r_args.arg[0] = ctx->inst_no;
+       ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
+                                                               &h2r_args);
+       if (ret) {
+               mfc_err("Failed to return an instance\n");
+               ctx->state = MFCINST_ERROR;
+               return -EINVAL;
+       }
+       return 0;
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h
new file mode 100644 (file)
index 0000000..5ceebfe
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_CMD_H_
+#define S5P_MFC_CMD_H_
+
+#include "s5p_mfc_common.h"
+
+#define MAX_H2R_ARG    4
+
+struct s5p_mfc_cmd_args {
+       unsigned int    arg[MAX_H2R_ARG];
+};
+
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_CMD_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_common.h b/drivers/media/video/s5p-mfc/s5p_mfc_common.h
new file mode 100644 (file)
index 0000000..91146fa
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Samsung S5P Multi Format Codec v 5.0
+ *
+ * This file contains definitions of enums and structs used by the codec
+ * driver.
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.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
+ */
+
+#ifndef S5P_MFC_COMMON_H_
+#define S5P_MFC_COMMON_H_
+
+#include "regs-mfc.h"
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+
+/* Definitions related to MFC memory */
+
+/* Offset base used to differentiate between CAPTURE and OUTPUT
+*  while mmaping */
+#define DST_QUEUE_OFF_BASE      (TASK_SIZE / 2)
+
+/* Offset used by the hardware to store addresses */
+#define MFC_OFFSET_SHIFT       11
+
+#define FIRMWARE_ALIGN         0x20000         /* 128KB */
+#define MFC_H264_CTX_BUF_SIZE  0x96000         /* 600KB per H264 instance */
+#define MFC_CTX_BUF_SIZE       0x2800          /* 10KB per instance */
+#define DESC_BUF_SIZE          0x20000         /* 128KB for DESC buffer */
+#define SHARED_BUF_SIZE                0x2000          /* 8KB for shared buffer */
+
+#define DEF_CPB_SIZE           0x40000         /* 512KB */
+
+#define MFC_BANK1_ALLOC_CTX    0
+#define MFC_BANK2_ALLOC_CTX    1
+
+#define MFC_BANK1_ALIGN_ORDER  13
+#define MFC_BANK2_ALIGN_ORDER  13
+#define MFC_BASE_ALIGN_ORDER   17
+
+#include <media/videobuf2-dma-contig.h>
+
+static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b)
+{
+       /* Same functionality as the vb2_dma_contig_plane_paddr */
+       dma_addr_t *paddr = vb2_dma_contig_memops.cookie(b);
+
+       return *paddr;
+}
+
+/* MFC definitions */
+#define MFC_MAX_EXTRA_DPB       5
+#define MFC_MAX_BUFFERS                32
+#define MFC_NUM_CONTEXTS       4
+/* Interrupt timeout */
+#define MFC_INT_TIMEOUT                2000
+/* Busy wait timeout */
+#define MFC_BW_TIMEOUT         500
+/* Watchdog interval */
+#define MFC_WATCHDOG_INTERVAL   1000
+/* After how many executions watchdog should assume lock up */
+#define MFC_WATCHDOG_CNT        10
+#define MFC_NO_INSTANCE_SET    -1
+#define MFC_ENC_CAP_PLANE_COUNT        1
+#define MFC_ENC_OUT_PLANE_COUNT        2
+#define STUFF_BYTE             4
+#define MFC_MAX_CTRLS          64
+
+#define mfc_read(dev, offset)          readl(dev->regs_base + (offset))
+#define mfc_write(dev, data, offset)   writel((data), dev->regs_base + \
+                                                               (offset))
+
+/**
+ * enum s5p_mfc_fmt_type - type of the pixelformat
+ */
+enum s5p_mfc_fmt_type {
+       MFC_FMT_DEC,
+       MFC_FMT_ENC,
+       MFC_FMT_RAW,
+};
+
+/**
+ * enum s5p_mfc_node_type - The type of an MFC device node.
+ */
+enum s5p_mfc_node_type {
+       MFCNODE_INVALID = -1,
+       MFCNODE_DECODER = 0,
+       MFCNODE_ENCODER = 1,
+};
+
+/**
+ * enum s5p_mfc_inst_type - The type of an MFC instance.
+ */
+enum s5p_mfc_inst_type {
+       MFCINST_INVALID,
+       MFCINST_DECODER,
+       MFCINST_ENCODER,
+};
+
+/**
+ * enum s5p_mfc_inst_state - The state of an MFC instance.
+ */
+enum s5p_mfc_inst_state {
+       MFCINST_FREE = 0,
+       MFCINST_INIT = 100,
+       MFCINST_GOT_INST,
+       MFCINST_HEAD_PARSED,
+       MFCINST_BUFS_SET,
+       MFCINST_RUNNING,
+       MFCINST_FINISHING,
+       MFCINST_FINISHED,
+       MFCINST_RETURN_INST,
+       MFCINST_ERROR,
+       MFCINST_ABORT,
+       MFCINST_RES_CHANGE_INIT,
+       MFCINST_RES_CHANGE_FLUSH,
+       MFCINST_RES_CHANGE_END,
+};
+
+/**
+ * enum s5p_mfc_queue_state - The state of buffer queue.
+ */
+enum s5p_mfc_queue_state {
+       QUEUE_FREE,
+       QUEUE_BUFS_REQUESTED,
+       QUEUE_BUFS_QUERIED,
+       QUEUE_BUFS_MMAPED,
+};
+
+/**
+ * enum s5p_mfc_decode_arg - type of frame decoding
+ */
+enum s5p_mfc_decode_arg {
+       MFC_DEC_FRAME,
+       MFC_DEC_LAST_FRAME,
+       MFC_DEC_RES_CHANGE,
+};
+
+struct s5p_mfc_ctx;
+
+/**
+ * struct s5p_mfc_buf - MFC buffer
+ */
+struct s5p_mfc_buf {
+       struct list_head list;
+       struct vb2_buffer *b;
+       union {
+               struct {
+                       size_t luma;
+                       size_t chroma;
+               } raw;
+               size_t stream;
+       } cookie;
+       int used;
+};
+
+/**
+ * struct s5p_mfc_pm - power management data structure
+ */
+struct s5p_mfc_pm {
+       struct clk      *clock;
+       struct clk      *clock_gate;
+       atomic_t        power;
+       struct device   *device;
+};
+
+/**
+ * struct s5p_mfc_dev - The struct containing driver internal parameters.
+ *
+ * @v4l2_dev:          v4l2_device
+ * @vfd_dec:           video device for decoding
+ * @vfd_enc:           video device for encoding
+ * @plat_dev:          platform device
+ * @mem_dev_l:         child device of the left memory bank (0)
+ * @mem_dev_r:         child device of the right memory bank (1)
+ * @regs_base:         base address of the MFC hw registers
+ * @irq:               irq resource
+ * @mfc_mem:           MFC registers memory resource
+ * @dec_ctrl_handler:  control framework handler for decoding
+ * @enc_ctrl_handler:  control framework handler for encoding
+ * @pm:                        power management control
+ * @num_inst:          couter of active MFC instances
+ * @irqlock:           lock for operations on videobuf2 queues
+ * @condlock:          lock for changing/checking if a context is ready to be
+ *                     processed
+ * @mfc_mutex:         lock for video_device
+ * @int_cond:          variable used by the waitqueue
+ * @int_type:          type of last interrupt
+ * @int_err:           error number for last interrupt
+ * @queue:             waitqueue for waiting for completion of device commands
+ * @fw_size:           size of firmware
+ * @bank1:             address of the beggining of bank 1 memory
+ * @bank2:             address of the beggining of bank 2 memory
+ * @hw_lock:           used for hardware locking
+ * @ctx:               array of driver contexts
+ * @curr_ctx:          number of the currently running context
+ * @ctx_work_bits:     used to mark which contexts are waiting for hardware
+ * @watchdog_cnt:      counter for the watchdog
+ * @watchdog_workqueue:        workqueue for the watchdog
+ * @watchdog_work:     worker for the watchdog
+ * @alloc_ctx:         videobuf2 allocator contexts for two memory banks
+ * @enter_suspend:     flag set when entering suspend
+ *
+ */
+struct s5p_mfc_dev {
+       struct v4l2_device      v4l2_dev;
+       struct video_device     *vfd_dec;
+       struct video_device     *vfd_enc;
+       struct platform_device  *plat_dev;
+       struct device           *mem_dev_l;
+       struct device           *mem_dev_r;
+       void __iomem            *regs_base;
+       int                     irq;
+       struct resource         *mfc_mem;
+       struct v4l2_ctrl_handler dec_ctrl_handler;
+       struct v4l2_ctrl_handler enc_ctrl_handler;
+       struct s5p_mfc_pm       pm;
+       int num_inst;
+       spinlock_t irqlock;     /* lock when operating on videobuf2 queues */
+       spinlock_t condlock;    /* lock when changing/checking if a context is
+                                       ready to be processed */
+       struct mutex mfc_mutex; /* video_device lock */
+       int int_cond;
+       int int_type;
+       unsigned int int_err;
+       wait_queue_head_t queue;
+       size_t fw_size;
+       size_t bank1;
+       size_t bank2;
+       unsigned long hw_lock;
+       struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS];
+       int curr_ctx;
+       unsigned long ctx_work_bits;
+       atomic_t watchdog_cnt;
+       struct timer_list watchdog_timer;
+       struct workqueue_struct *watchdog_workqueue;
+       struct work_struct watchdog_work;
+       void *alloc_ctx[2];
+       unsigned long enter_suspend;
+};
+
+/**
+ * struct s5p_mfc_h264_enc_params - encoding parameters for h264
+ */
+struct s5p_mfc_h264_enc_params {
+       enum v4l2_mpeg_video_h264_profile profile;
+       enum v4l2_mpeg_video_h264_loop_filter_mode loop_filter_mode;
+       s8 loop_filter_alpha;
+       s8 loop_filter_beta;
+       enum v4l2_mpeg_video_h264_entropy_mode entropy_mode;
+       u8 max_ref_pic;
+       u8 num_ref_pic_4p;
+       int _8x8_transform;
+       int rc_mb;
+       int rc_mb_dark;
+       int rc_mb_smooth;
+       int rc_mb_static;
+       int rc_mb_activity;
+       int vui_sar;
+       u8 vui_sar_idc;
+       u16 vui_ext_sar_width;
+       u16 vui_ext_sar_height;
+       int open_gop;
+       u16 open_gop_size;
+       u8 rc_frame_qp;
+       u8 rc_min_qp;
+       u8 rc_max_qp;
+       u8 rc_p_frame_qp;
+       u8 rc_b_frame_qp;
+       enum v4l2_mpeg_video_h264_level level_v4l2;
+       int level;
+       u16 cpb_size;
+};
+
+/**
+ * struct s5p_mfc_mpeg4_enc_params - encoding parameters for h263 and mpeg4
+ */
+struct s5p_mfc_mpeg4_enc_params {
+       /* MPEG4 Only */
+       enum v4l2_mpeg_video_mpeg4_profile profile;
+       int quarter_pixel;
+       /* Common for MPEG4, H263 */
+       u16 vop_time_res;
+       u16 vop_frm_delta;
+       u8 rc_frame_qp;
+       u8 rc_min_qp;
+       u8 rc_max_qp;
+       u8 rc_p_frame_qp;
+       u8 rc_b_frame_qp;
+       enum v4l2_mpeg_video_mpeg4_level level_v4l2;
+       int level;
+};
+
+/**
+ * struct s5p_mfc_enc_params - general encoding parameters
+ */
+struct s5p_mfc_enc_params {
+       u16 width;
+       u16 height;
+
+       u16 gop_size;
+       enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+       u16 slice_mb;
+       u32 slice_bit;
+       u16 intra_refresh_mb;
+       int pad;
+       u8 pad_luma;
+       u8 pad_cb;
+       u8 pad_cr;
+       int rc_frame;
+       u32 rc_bitrate;
+       u16 rc_reaction_coeff;
+       u16 vbv_size;
+
+       enum v4l2_mpeg_video_header_mode seq_hdr_mode;
+       enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode;
+       int fixed_target_bit;
+
+       u8 num_b_frame;
+       u32 rc_framerate_num;
+       u32 rc_framerate_denom;
+       int interlace;
+
+       union {
+               struct s5p_mfc_h264_enc_params h264;
+               struct s5p_mfc_mpeg4_enc_params mpeg4;
+       } codec;
+
+};
+
+/**
+ * struct s5p_mfc_codec_ops - codec ops, used by encoding
+ */
+struct s5p_mfc_codec_ops {
+       /* initialization routines */
+       int (*pre_seq_start) (struct s5p_mfc_ctx *ctx);
+       int (*post_seq_start) (struct s5p_mfc_ctx *ctx);
+       /* execution routines */
+       int (*pre_frame_start) (struct s5p_mfc_ctx *ctx);
+       int (*post_frame_start) (struct s5p_mfc_ctx *ctx);
+};
+
+#define call_cop(c, op, args...)                               \
+       (((c)->c_ops->op) ?                                     \
+               ((c)->c_ops->op(args)) : 0)
+
+/**
+ * struct s5p_mfc_ctx - This struct contains the instance context
+ *
+ * @dev:               pointer to the s5p_mfc_dev of the device
+ * @fh:                        struct v4l2_fh
+ * @num:               number of the context that this structure describes
+ * @int_cond:          variable used by the waitqueue
+ * @int_type:          type of the last interrupt
+ * @int_err:           error number received from MFC hw in the interrupt
+ * @queue:             waitqueue that can be used to wait for this context to
+ *                     finish
+ * @src_fmt:           source pixelformat information
+ * @dst_fmt:           destination pixelformat information
+ * @vq_src:            vb2 queue for source buffers
+ * @vq_dst:            vb2 queue for destination buffers
+ * @src_queue:         driver internal queue for source buffers
+ * @dst_queue:         driver internal queue for destination buffers
+ * @src_queue_cnt:     number of buffers queued on the source internal queue
+ * @dst_queue_cnt:     number of buffers queued on the dest internal queue
+ * @type:              type of the instance - decoder or encoder
+ * @state:             state of the context
+ * @inst_no:           number of hw instance associated with the context
+ * @img_width:         width of the image that is decoded or encoded
+ * @img_height:                height of the image that is decoded or encoded
+ * @buf_width:         width of the buffer for processed image
+ * @buf_height:                height of the buffer for processed image
+ * @luma_size:         size of a luma plane
+ * @chroma_size:       size of a chroma plane
+ * @mv_size:           size of a motion vectors buffer
+ * @consumed_stream:   number of bytes that have been used so far from the
+ *                     decoding buffer
+ * @dpb_flush_flag:    flag used to indicate that a DPB buffers are being
+ *                     flushed
+ * @bank1_buf:         handle to memory allocated for temporary buffers from
+ *                     memory bank 1
+ * @bank1_phys:                address of the temporary buffers from memory bank 1
+ * @bank1_size:                size of the memory allocated for temporary buffers from
+ *                     memory bank 1
+ * @bank2_buf:         handle to memory allocated for temporary buffers from
+ *                     memory bank 2
+ * @bank2_phys:                address of the temporary buffers from memory bank 2
+ * @bank2_size:                size of the memory allocated for temporary buffers from
+ *                     memory bank 2
+ * @capture_state:     state of the capture buffers queue
+ * @output_state:      state of the output buffers queue
+ * @src_bufs:          information on allocated source buffers
+ * @dst_bufs:          information on allocated destination buffers
+ * @sequence:          counter for the sequence number for v4l2
+ * @dec_dst_flag:      flags for buffers queued in the hardware
+ * @dec_src_buf_size:  size of the buffer for source buffers in decoding
+ * @codec_mode:                number of codec mode used by MFC hw
+ * @slice_interface:   slice interface flag
+ * @loop_filter_mpeg4: loop filter for MPEG4 flag
+ * @display_delay:     value of the display delay for H264
+ * @display_delay_enable:      display delay for H264 enable flag
+ * @after_packed_pb:   flag used to track buffer when stream is in
+ *                     Packed PB format
+ * @dpb_count:         count of the DPB buffers required by MFC hw
+ * @total_dpb_count:   count of DPB buffers with additional buffers
+ *                     requested by the application
+ * @ctx_buf:           handle to the memory associated with this context
+ * @ctx_phys:          address of the memory associated with this context
+ * @ctx_size:          size of the memory associated with this context
+ * @desc_buf:          description buffer for decoding handle
+ * @desc_phys:         description buffer for decoding address
+ * @shm_alloc:         handle for the shared memory buffer
+ * @shm:               virtual address for the shared memory buffer
+ * @shm_ofs:           address offset for shared memory
+ * @enc_params:                encoding parameters for MFC
+ * @enc_dst_buf_size:  size of the buffers for encoder output
+ * @frame_type:                used to force the type of the next encoded frame
+ * @ref_queue:         list of the reference buffers for encoding
+ * @ref_queue_cnt:     number of the buffers in the reference list
+ * @c_ops:             ops for encoding
+ * @ctrls:             array of controls, used when adding controls to the
+ *                     v4l2 control framework
+ * @ctrl_handler:      handler for v4l2 framework
+ */
+struct s5p_mfc_ctx {
+       struct s5p_mfc_dev *dev;
+       struct v4l2_fh fh;
+
+       int num;
+
+       int int_cond;
+       int int_type;
+       unsigned int int_err;
+       wait_queue_head_t queue;
+
+       struct s5p_mfc_fmt *src_fmt;
+       struct s5p_mfc_fmt *dst_fmt;
+
+       struct vb2_queue vq_src;
+       struct vb2_queue vq_dst;
+
+       struct list_head src_queue;
+       struct list_head dst_queue;
+
+       unsigned int src_queue_cnt;
+       unsigned int dst_queue_cnt;
+
+       enum s5p_mfc_inst_type type;
+       enum s5p_mfc_inst_state state;
+       int inst_no;
+
+       /* Image parameters */
+       int img_width;
+       int img_height;
+       int buf_width;
+       int buf_height;
+
+       int luma_size;
+       int chroma_size;
+       int mv_size;
+
+       unsigned long consumed_stream;
+
+       unsigned int dpb_flush_flag;
+
+       /* Buffers */
+       void *bank1_buf;
+       size_t bank1_phys;
+       size_t bank1_size;
+
+       void *bank2_buf;
+       size_t bank2_phys;
+       size_t bank2_size;
+
+       enum s5p_mfc_queue_state capture_state;
+       enum s5p_mfc_queue_state output_state;
+
+       struct s5p_mfc_buf src_bufs[MFC_MAX_BUFFERS];
+       int src_bufs_cnt;
+       struct s5p_mfc_buf dst_bufs[MFC_MAX_BUFFERS];
+       int dst_bufs_cnt;
+
+       unsigned int sequence;
+       unsigned long dec_dst_flag;
+       size_t dec_src_buf_size;
+
+       /* Control values */
+       int codec_mode;
+       int slice_interface;
+       int loop_filter_mpeg4;
+       int display_delay;
+       int display_delay_enable;
+       int after_packed_pb;
+
+       int dpb_count;
+       int total_dpb_count;
+
+       /* Buffers */
+       void *ctx_buf;
+       size_t ctx_phys;
+       size_t ctx_ofs;
+       size_t ctx_size;
+
+       void *desc_buf;
+       size_t desc_phys;
+
+
+       void *shm_alloc;
+       void *shm;
+       size_t shm_ofs;
+
+       struct s5p_mfc_enc_params enc_params;
+
+       size_t enc_dst_buf_size;
+
+       enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
+
+       struct list_head ref_queue;
+       unsigned int ref_queue_cnt;
+
+       struct s5p_mfc_codec_ops *c_ops;
+
+       struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS];
+       struct v4l2_ctrl_handler ctrl_handler;
+};
+
+/*
+ * struct s5p_mfc_fmt -        structure used to store information about pixelformats
+ *                     used by the MFC
+ */
+struct s5p_mfc_fmt {
+       char *name;
+       u32 fourcc;
+       u32 codec_mode;
+       enum s5p_mfc_fmt_type type;
+       u32 num_planes;
+};
+
+/**
+ * struct mfc_control -        structure used to store information about MFC controls
+ *                     it is used to initialize the control framework.
+ */
+struct mfc_control {
+       __u32                   id;
+       enum v4l2_ctrl_type     type;
+       __u8                    name[32];  /* Whatever */
+       __s32                   minimum;   /* Note signedness */
+       __s32                   maximum;
+       __s32                   step;
+       __u32                   menu_skip_mask;
+       __s32                   default_value;
+       __u32                   flags;
+       __u32                   reserved[2];
+       __u8                    is_volatile;
+};
+
+
+#define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh)
+#define ctrl_to_ctx(__ctrl) \
+       container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler)
+
+#endif /* S5P_MFC_COMMON_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
new file mode 100644 (file)
index 0000000..5f4da80
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_pm.h"
+
+static void *s5p_mfc_bitproc_buf;
+static size_t s5p_mfc_bitproc_phys;
+static unsigned char *s5p_mfc_bitproc_virt;
+
+/* Allocate and load firmware */
+int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
+{
+       struct firmware *fw_blob;
+       size_t bank2_base_phys;
+       void *b_base;
+       int err;
+
+       /* Firmare has to be present as a separate file or compiled
+        * into kernel. */
+       mfc_debug_enter();
+       err = request_firmware((const struct firmware **)&fw_blob,
+                                    "s5pc110-mfc.fw", dev->v4l2_dev.dev);
+       if (err != 0) {
+               mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
+               return -EINVAL;
+       }
+       dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN);
+       if (s5p_mfc_bitproc_buf) {
+               mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
+               release_firmware(fw_blob);
+               return -ENOMEM;
+       }
+       s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size);
+       if (IS_ERR(s5p_mfc_bitproc_buf)) {
+               s5p_mfc_bitproc_buf = 0;
+               mfc_err("Allocating bitprocessor buffer failed\n");
+               release_firmware(fw_blob);
+               return -ENOMEM;
+       }
+       s5p_mfc_bitproc_phys = s5p_mfc_mem_cookie(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], s5p_mfc_bitproc_buf);
+       if (s5p_mfc_bitproc_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
+               mfc_err("The base memory for bank 1 is not aligned to 128KB\n");
+               vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+               s5p_mfc_bitproc_phys = 0;
+               s5p_mfc_bitproc_buf = 0;
+               release_firmware(fw_blob);
+               return -EIO;
+       }
+       s5p_mfc_bitproc_virt = vb2_dma_contig_memops.vaddr(s5p_mfc_bitproc_buf);
+       if (!s5p_mfc_bitproc_virt) {
+               mfc_err("Bitprocessor memory remap failed\n");
+               vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+               s5p_mfc_bitproc_phys = 0;
+               s5p_mfc_bitproc_buf = 0;
+               release_firmware(fw_blob);
+               return -EIO;
+       }
+       dev->bank1 = s5p_mfc_bitproc_phys;
+       b_base = vb2_dma_contig_memops.alloc(
+               dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BANK2_ALIGN_ORDER);
+       if (IS_ERR(b_base)) {
+               vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+               s5p_mfc_bitproc_phys = 0;
+               s5p_mfc_bitproc_buf = 0;
+               mfc_err("Allocating bank2 base failed\n");
+       release_firmware(fw_blob);
+               return -ENOMEM;
+       }
+       bank2_base_phys = s5p_mfc_mem_cookie(
+               dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base);
+       vb2_dma_contig_memops.put(b_base);
+       if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
+               mfc_err("The base memory for bank 2 is not aligned to 128KB\n");
+               vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+               s5p_mfc_bitproc_phys = 0;
+               s5p_mfc_bitproc_buf = 0;
+               release_firmware(fw_blob);
+               return -EIO;
+       }
+       dev->bank2 = bank2_base_phys;
+       memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+       wmb();
+       release_firmware(fw_blob);
+       mfc_debug_leave();
+       return 0;
+}
+
+/* Reload firmware to MFC */
+int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev)
+{
+       struct firmware *fw_blob;
+       int err;
+
+       /* Firmare has to be present as a separate file or compiled
+        * into kernel. */
+       mfc_debug_enter();
+       err = request_firmware((const struct firmware **)&fw_blob,
+                                    "s5pc110-mfc.fw", dev->v4l2_dev.dev);
+       if (err != 0) {
+               mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
+               return -EINVAL;
+       }
+       if (fw_blob->size > dev->fw_size) {
+               mfc_err("MFC firmware is too big to be loaded\n");
+               release_firmware(fw_blob);
+               return -ENOMEM;
+       }
+       if (s5p_mfc_bitproc_buf == 0 || s5p_mfc_bitproc_phys == 0) {
+               mfc_err("MFC firmware is not allocated or was not mapped correctly\n");
+               release_firmware(fw_blob);
+               return -EINVAL;
+       }
+       memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+       wmb();
+       release_firmware(fw_blob);
+       mfc_debug_leave();
+       return 0;
+}
+
+/* Release firmware memory */
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
+{
+       /* Before calling this function one has to make sure
+        * that MFC is no longer processing */
+       if (!s5p_mfc_bitproc_buf)
+               return -EINVAL;
+       vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
+       s5p_mfc_bitproc_virt =  0;
+       s5p_mfc_bitproc_phys = 0;
+       s5p_mfc_bitproc_buf = 0;
+       return 0;
+}
+
+/* Reset the device */
+int s5p_mfc_reset(struct s5p_mfc_dev *dev)
+{
+       unsigned int mc_status;
+       unsigned long timeout;
+
+       mfc_debug_enter();
+       /* Stop procedure */
+       /*  reset RISC */
+       mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET);
+       /*  All reset except for MC */
+       mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET);
+       mdelay(10);
+
+       timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+       /* Check MC status */
+       do {
+               if (time_after(jiffies, timeout)) {
+                       mfc_err("Timeout while resetting MFC\n");
+                       return -EIO;
+               }
+
+               mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS);
+
+       } while (mc_status & 0x3);
+
+       mfc_write(dev, 0x0, S5P_FIMV_SW_RESET);
+       mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET);
+       mfc_debug_leave();
+       return 0;
+}
+
+static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
+{
+       mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
+       mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
+       mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2);
+}
+
+static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
+{
+       mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID);
+       mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID);
+       mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
+       mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD);
+}
+
+/* Initialize hardware */
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
+{
+       unsigned int ver;
+       int ret;
+
+       mfc_debug_enter();
+       if (!s5p_mfc_bitproc_buf)
+               return -EINVAL;
+
+       /* 0. MFC reset */
+       mfc_debug(2, "MFC reset..\n");
+       s5p_mfc_clock_on();
+       ret = s5p_mfc_reset(dev);
+       if (ret) {
+               mfc_err("Failed to reset MFC - timeout\n");
+               return ret;
+       }
+       mfc_debug(2, "Done MFC reset..\n");
+       /* 1. Set DRAM base Addr */
+       s5p_mfc_init_memctrl(dev);
+       /* 2. Initialize registers of channel I/F */
+       s5p_mfc_clear_cmds(dev);
+       /* 3. Release reset signal to the RISC */
+       s5p_mfc_clean_dev_int_flags(dev);
+       mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
+       mfc_debug(2, "Will now wait for completion of firmware transfer\n");
+       if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) {
+               mfc_err("Failed to load firmware\n");
+               s5p_mfc_reset(dev);
+               s5p_mfc_clock_off();
+               return -EIO;
+       }
+       s5p_mfc_clean_dev_int_flags(dev);
+       /* 4. Initialize firmware */
+       ret = s5p_mfc_sys_init_cmd(dev);
+       if (ret) {
+               mfc_err("Failed to send command to MFC - timeout\n");
+               s5p_mfc_reset(dev);
+               s5p_mfc_clock_off();
+               return ret;
+       }
+       mfc_debug(2, "Ok, now will write a command to init the system\n");
+       if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) {
+               mfc_err("Failed to load firmware\n");
+               s5p_mfc_reset(dev);
+               s5p_mfc_clock_off();
+               return -EIO;
+       }
+       dev->int_cond = 0;
+       if (dev->int_err != 0 || dev->int_type !=
+                                       S5P_FIMV_R2H_CMD_SYS_INIT_RET) {
+               /* Failure. */
+               mfc_err("Failed to init firmware - error: %d int: %d\n",
+                                               dev->int_err, dev->int_type);
+               s5p_mfc_reset(dev);
+               s5p_mfc_clock_off();
+               return -EIO;
+       }
+       ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
+       mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n",
+               (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
+       s5p_mfc_clock_off();
+       mfc_debug_leave();
+       return 0;
+}
+
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
+{
+       int ret;
+
+       mfc_debug_enter();
+       s5p_mfc_clock_on();
+       s5p_mfc_clean_dev_int_flags(dev);
+       ret = s5p_mfc_sleep_cmd(dev);
+       if (ret) {
+               mfc_err("Failed to send command to MFC - timeout\n");
+               return ret;
+       }
+       if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) {
+               mfc_err("Failed to sleep\n");
+               return -EIO;
+       }
+       s5p_mfc_clock_off();
+       dev->int_cond = 0;
+       if (dev->int_err != 0 || dev->int_type !=
+                                               S5P_FIMV_R2H_CMD_SLEEP_RET) {
+               /* Failure. */
+               mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err,
+                                                               dev->int_type);
+               return -EIO;
+       }
+       mfc_debug_leave();
+       return ret;
+}
+
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
+{
+       int ret;
+
+       mfc_debug_enter();
+       /* 0. MFC reset */
+       mfc_debug(2, "MFC reset..\n");
+       s5p_mfc_clock_on();
+       ret = s5p_mfc_reset(dev);
+       if (ret) {
+               mfc_err("Failed to reset MFC - timeout\n");
+               return ret;
+       }
+       mfc_debug(2, "Done MFC reset..\n");
+       /* 1. Set DRAM base Addr */
+       s5p_mfc_init_memctrl(dev);
+       /* 2. Initialize registers of channel I/F */
+       s5p_mfc_clear_cmds(dev);
+       s5p_mfc_clean_dev_int_flags(dev);
+       /* 3. Initialize firmware */
+       ret = s5p_mfc_wakeup_cmd(dev);
+       if (ret) {
+               mfc_err("Failed to send command to MFC - timeout\n");
+               return ret;
+       }
+       /* 4. Release reset signal to the RISC */
+       mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
+       mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
+       if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) {
+               mfc_err("Failed to load firmware\n");
+               return -EIO;
+       }
+       s5p_mfc_clock_off();
+       dev->int_cond = 0;
+       if (dev->int_err != 0 || dev->int_type !=
+                                               S5P_FIMV_R2H_CMD_WAKEUP_RET) {
+               /* Failure. */
+               mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err,
+                                                               dev->int_type);
+               return -EIO;
+       }
+       mfc_debug_leave();
+       return 0;
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h
new file mode 100644 (file)
index 0000000..61dc23b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_CTRL_H
+#define S5P_MFC_CTRL_H
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_reset(struct s5p_mfc_dev *dev);
+
+#endif /* S5P_MFC_CTRL_H */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_debug.h b/drivers/media/video/s5p-mfc/s5p_mfc_debug.h
new file mode 100644 (file)
index 0000000..ecb8616
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * drivers/media/video/samsung/mfc5/s5p_mfc_debug.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains debug macros
+ *
+ * Kamil Debski, Copyright (c) 2011 Samsung Electronics
+ * http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_DEBUG_H_
+#define S5P_MFC_DEBUG_H_
+
+#define DEBUG
+
+#ifdef DEBUG
+extern int debug;
+
+#define mfc_debug(level, fmt, args...)                         \
+       do {                                                    \
+               if (debug >= level)                             \
+                       printk(KERN_DEBUG "%s:%d: " fmt,        \
+                               __func__, __LINE__, ##args);    \
+       } while (0)
+#else
+#define mfc_debug(level, fmt, args...)
+#endif
+
+#define mfc_debug_enter() mfc_debug(5, "enter")
+#define mfc_debug_leave() mfc_debug(5, "leave")
+
+#define mfc_err(fmt, args...)                          \
+       do {                                            \
+               printk(KERN_ERR "%s:%d: " fmt,          \
+                      __func__, __LINE__, ##args);     \
+       } while (0)
+
+#define mfc_info(fmt, args...)                         \
+       do {                                            \
+               printk(KERN_INFO "%s:%d: " fmt,         \
+                      __func__, __LINE__, ##args);     \
+       } while (0)
+
+#endif /* S5P_MFC_DEBUG_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
new file mode 100644 (file)
index 0000000..b2c5052
--- /dev/null
@@ -0,0 +1,1036 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_dec.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ * Kamil Debski, <k.debski@samsung.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+
+static struct s5p_mfc_fmt formats[] = {
+       {
+               .name           = "4:2:0 2 Planes 64x32 Tiles",
+               .fourcc         = V4L2_PIX_FMT_NV12MT,
+               .codec_mode     = S5P_FIMV_CODEC_NONE,
+               .type           = MFC_FMT_RAW,
+               .num_planes     = 2,
+        },
+       {
+               .name = "4:2:0 2 Planes",
+               .fourcc = V4L2_PIX_FMT_NV12M,
+               .codec_mode = S5P_FIMV_CODEC_NONE,
+               .type = MFC_FMT_RAW,
+               .num_planes = 2,
+       },
+       {
+               .name = "H264 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H264,
+               .codec_mode = S5P_FIMV_CODEC_H264_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "H263 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H263,
+               .codec_mode = S5P_FIMV_CODEC_H263_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "MPEG1 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG1,
+               .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "MPEG2 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG2,
+               .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "MPEG4 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG4,
+               .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "XviD Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_XVID,
+               .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "VC1 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+               .codec_mode = S5P_FIMV_CODEC_VC1_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+       {
+               .name = "VC1 RCV Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+               .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC,
+               .type = MFC_FMT_DEC,
+               .num_planes = 1,
+       },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Find selected format description */
+static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
+{
+       unsigned int i;
+
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+                   formats[i].type == t)
+                       return &formats[i];
+       }
+       return NULL;
+}
+
+static struct mfc_control controls[] = {
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H264 Display Delay",
+               .minimum = 0,
+               .maximum = 16383,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "H264 Display Delay Enable",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Mpeg4 Loop Filter Enable",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Slice Interface Enable",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Minimum number of cap bufs",
+               .minimum = 1,
+               .maximum = 32,
+               .step = 1,
+               .default_value = 1,
+               .is_volatile = 1,
+       },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+
+/* Check whether a context should be run on hardware */
+static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+       /* Context is to parse header */
+       if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST)
+               return 1;
+       /* Context is to decode a frame */
+       if (ctx->src_queue_cnt >= 1 &&
+           ctx->state == MFCINST_RUNNING &&
+           ctx->dst_queue_cnt >= ctx->dpb_count)
+               return 1;
+       /* Context is to return last frame */
+       if (ctx->state == MFCINST_FINISHING &&
+           ctx->dst_queue_cnt >= ctx->dpb_count)
+               return 1;
+       /* Context is to set buffers */
+       if (ctx->src_queue_cnt >= 1 &&
+           ctx->state == MFCINST_HEAD_PARSED &&
+           ctx->capture_state == QUEUE_BUFS_MMAPED)
+               return 1;
+       /* Resolution change */
+       if ((ctx->state == MFCINST_RES_CHANGE_INIT ||
+               ctx->state == MFCINST_RES_CHANGE_FLUSH) &&
+               ctx->dst_queue_cnt >= ctx->dpb_count)
+               return 1;
+       if (ctx->state == MFCINST_RES_CHANGE_END &&
+               ctx->src_queue_cnt >= 1)
+               return 1;
+       mfc_debug(2, "ctx is not ready\n");
+       return 0;
+}
+
+static struct s5p_mfc_codec_ops decoder_codec_ops = {
+       .pre_seq_start          = NULL,
+       .post_seq_start         = NULL,
+       .pre_frame_start        = NULL,
+       .post_frame_start       = NULL,
+};
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+
+       strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+       strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+       cap->bus_info[0] = 0;
+       cap->version = KERNEL_VERSION(1, 0, 0);
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+                                                   | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+/* Enumerate format */
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+{
+       struct s5p_mfc_fmt *fmt;
+       int i, j = 0;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (mplane && formats[i].num_planes == 1)
+                       continue;
+               else if (!mplane && formats[i].num_planes > 1)
+                       continue;
+               if (out && formats[i].type != MFC_FMT_DEC)
+                       continue;
+               else if (!out && formats[i].type != MFC_FMT_RAW)
+                       continue;
+
+               if (j == f->index)
+                       break;
+               ++j;
+       }
+       if (i == ARRAY_SIZE(formats))
+               return -EINVAL;
+       fmt = &formats[i];
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+                                                       struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, false, false);
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+                                                       struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, true, false);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+                                                       struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, false, true);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+                                                       struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, true, true);
+}
+
+/* Get format */
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_pix_format_mplane *pix_mp;
+
+       mfc_debug_enter();
+       pix_mp = &f->fmt.pix_mp;
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+           (ctx->state == MFCINST_GOT_INST || ctx->state ==
+                                               MFCINST_RES_CHANGE_END)) {
+               /* If the MFC is parsing the header,
+                * so wait until it is finished */
+               s5p_mfc_clean_ctx_int_flags(ctx);
+               s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET,
+                                                                       0);
+       }
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+           ctx->state >= MFCINST_HEAD_PARSED &&
+           ctx->state < MFCINST_ABORT) {
+               /* This is run on CAPTURE (decode output) */
+               /* Width and height are set to the dimensions
+                  of the movie, the buffer is bigger and
+                  further processing stages should crop to this
+                  rectangle. */
+               pix_mp->width = ctx->buf_width;
+               pix_mp->height = ctx->buf_height;
+               pix_mp->field = V4L2_FIELD_NONE;
+               pix_mp->num_planes = 2;
+               /* Set pixelformat to the format in which MFC
+                  outputs the decoded frame */
+               pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT;
+               pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+               pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+               pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+               pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* This is run on OUTPUT
+                  The buffer contains compressed image
+                  so width and height have no meaning */
+               pix_mp->width = 0;
+               pix_mp->height = 0;
+               pix_mp->field = V4L2_FIELD_NONE;
+               pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size;
+               pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size;
+               pix_mp->pixelformat = ctx->src_fmt->fourcc;
+               pix_mp->num_planes = ctx->src_fmt->num_planes;
+       } else {
+               mfc_err("Format could not be read\n");
+               mfc_debug(2, "%s-- with error\n", __func__);
+               return -EINVAL;
+       }
+       mfc_debug_leave();
+       return 0;
+}
+
+/* Try format */
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_fmt *fmt;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               mfc_err("This node supports decoding only\n");
+               return -EINVAL;
+       }
+       fmt = find_format(f, MFC_FMT_DEC);
+       if (!fmt) {
+               mfc_err("Unsupported format\n");
+               return -EINVAL;
+       }
+       if (fmt->type != MFC_FMT_DEC) {
+               mfc_err("\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* Set format */
+static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       int ret = 0;
+       struct s5p_mfc_fmt *fmt;
+       struct v4l2_pix_format_mplane *pix_mp;
+
+       mfc_debug_enter();
+       ret = vidioc_try_fmt(file, priv, f);
+       pix_mp = &f->fmt.pix_mp;
+       if (ret)
+               return ret;
+       if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
+               v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+               ret = -EBUSY;
+               goto out;
+       }
+       fmt = find_format(f, MFC_FMT_DEC);
+       if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
+               mfc_err("Unknown codec\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       if (fmt->type != MFC_FMT_DEC) {
+               mfc_err("Wrong format selected, you should choose "
+                                       "format for decoding\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       ctx->src_fmt = fmt;
+       ctx->codec_mode = fmt->codec_mode;
+       mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
+       pix_mp->height = 0;
+       pix_mp->width = 0;
+       if (pix_mp->plane_fmt[0].sizeimage)
+               ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
+       else
+               pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
+                                                               DEF_CPB_SIZE;
+       pix_mp->plane_fmt[0].bytesperline = 0;
+       ctx->state = MFCINST_INIT;
+out:
+       mfc_debug_leave();
+       return ret;
+}
+
+/* Reqeust buffers */
+static int vidioc_reqbufs(struct file *file, void *priv,
+                                         struct v4l2_requestbuffers *reqbufs)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       int ret = 0;
+       unsigned long flags;
+
+       if (reqbufs->memory != V4L2_MEMORY_MMAP) {
+               mfc_err("Only V4L2_MEMORY_MAP is supported\n");
+               return -EINVAL;
+       }
+       if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* Can only request buffers after an instance has been opened.*/
+               if (ctx->state == MFCINST_INIT) {
+                       ctx->src_bufs_cnt = 0;
+                       if (reqbufs->count == 0) {
+                               mfc_debug(2, "Freeing buffers\n");
+                               s5p_mfc_clock_on();
+                               ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+                               s5p_mfc_clock_off();
+                               return ret;
+                       }
+                       /* Decoding */
+                       if (ctx->output_state != QUEUE_FREE) {
+                               mfc_err("Bufs have already been requested\n");
+                               return -EINVAL;
+                       }
+                       s5p_mfc_clock_on();
+                       ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+                       s5p_mfc_clock_off();
+                       if (ret) {
+                               mfc_err("vb2_reqbufs on output failed\n");
+                               return ret;
+                       }
+                       mfc_debug(2, "vb2_reqbufs: %d\n", ret);
+                       ctx->output_state = QUEUE_BUFS_REQUESTED;
+               }
+       } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               ctx->dst_bufs_cnt = 0;
+               if (reqbufs->count == 0) {
+                       mfc_debug(2, "Freeing buffers\n");
+                       s5p_mfc_clock_on();
+                       ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+                       s5p_mfc_clock_off();
+                       return ret;
+               }
+               if (ctx->capture_state != QUEUE_FREE) {
+                       mfc_err("Bufs have already been requested\n");
+                       return -EINVAL;
+               }
+               ctx->capture_state = QUEUE_BUFS_REQUESTED;
+               s5p_mfc_clock_on();
+               ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+               s5p_mfc_clock_off();
+               if (ret) {
+                       mfc_err("vb2_reqbufs on capture failed\n");
+                       return ret;
+               }
+               if (reqbufs->count < ctx->dpb_count) {
+                       mfc_err("Not enough buffers allocated\n");
+                       reqbufs->count = 0;
+                       s5p_mfc_clock_on();
+                       ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+                       s5p_mfc_clock_off();
+                       return -ENOMEM;
+               }
+               ctx->total_dpb_count = reqbufs->count;
+               ret = s5p_mfc_alloc_codec_buffers(ctx);
+               if (ret) {
+                       mfc_err("Failed to allocate decoding buffers\n");
+                       reqbufs->count = 0;
+                       s5p_mfc_clock_on();
+                       ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+                       s5p_mfc_clock_off();
+                       return -ENOMEM;
+               }
+               if (ctx->dst_bufs_cnt == ctx->total_dpb_count) {
+                       ctx->capture_state = QUEUE_BUFS_MMAPED;
+               } else {
+                       mfc_err("Not all buffers passed to buf_init\n");
+                       reqbufs->count = 0;
+                       s5p_mfc_clock_on();
+                       ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+                       s5p_mfc_release_codec_buffers(ctx);
+                       s5p_mfc_clock_off();
+                       return -ENOMEM;
+               }
+               if (s5p_mfc_ctx_ready(ctx)) {
+                       spin_lock_irqsave(&dev->condlock, flags);
+                       set_bit(ctx->num, &dev->ctx_work_bits);
+                       spin_unlock_irqrestore(&dev->condlock, flags);
+               }
+               s5p_mfc_try_run(dev);
+               s5p_mfc_wait_for_done_ctx(ctx,
+                                        S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0);
+       }
+       return ret;
+}
+
+/* Query buffer */
+static int vidioc_querybuf(struct file *file, void *priv,
+                                                  struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+       int i;
+
+       if (buf->memory != V4L2_MEMORY_MMAP) {
+               mfc_err("Only mmaped buffers can be used\n");
+               return -EINVAL;
+       }
+       mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type);
+       if (ctx->state == MFCINST_INIT &&
+                       buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               ret = vb2_querybuf(&ctx->vq_src, buf);
+       } else if (ctx->state == MFCINST_RUNNING &&
+                       buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               ret = vb2_querybuf(&ctx->vq_dst, buf);
+               for (i = 0; i < buf->length; i++)
+                       buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE;
+       } else {
+               mfc_err("vidioc_querybuf called in an inappropriate state\n");
+               ret = -EINVAL;
+       }
+       mfc_debug_leave();
+       return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MFCINST_ERROR) {
+               mfc_err("Call on QBUF after unrecoverable error\n");
+               return -EIO;
+       }
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_qbuf(&ctx->vq_src, buf);
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_qbuf(&ctx->vq_dst, buf);
+       return -EINVAL;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MFCINST_ERROR) {
+               mfc_err("Call on DQBUF after unrecoverable error\n");
+               return -EIO;
+       }
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+       return -EINVAL;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type type)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       mfc_debug_enter();
+       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+
+               if (ctx->state == MFCINST_INIT) {
+                       ctx->dst_bufs_cnt = 0;
+                       ctx->src_bufs_cnt = 0;
+                       ctx->capture_state = QUEUE_FREE;
+                       ctx->output_state = QUEUE_FREE;
+                       s5p_mfc_alloc_instance_buffer(ctx);
+                       s5p_mfc_alloc_dec_temp_buffers(ctx);
+                       spin_lock_irqsave(&dev->condlock, flags);
+                       set_bit(ctx->num, &dev->ctx_work_bits);
+                       spin_unlock_irqrestore(&dev->condlock, flags);
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       s5p_mfc_try_run(dev);
+
+                       if (s5p_mfc_wait_for_done_ctx(ctx,
+                               S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
+                               /* Error or timeout */
+                               mfc_err("Error getting instance from hardware\n");
+                               s5p_mfc_release_instance_buffer(ctx);
+                               s5p_mfc_release_dec_desc_buffer(ctx);
+                               return -EIO;
+                       }
+                       mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+               }
+               ret = vb2_streamon(&ctx->vq_src, type);
+               }
+       else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               ret = vb2_streamon(&ctx->vq_dst, type);
+       mfc_debug_leave();
+       return ret;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type type)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_streamoff(&ctx->vq_src, type);
+       else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_streamoff(&ctx->vq_dst, type);
+       return -EINVAL;
+}
+
+/* Set controls - v4l2 control framework */
+static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
+               ctx->loop_filter_mpeg4 = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE:
+               ctx->display_delay_enable = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+               ctx->display_delay = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+               ctx->slice_interface = ctrl->val;
+               break;
+       default:
+               mfc_err("Invalid control 0x%08x\n", ctrl->id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+               if (ctx->state >= MFCINST_HEAD_PARSED &&
+                   ctx->state < MFCINST_ABORT) {
+                       ctrl->val = ctx->dpb_count;
+                       break;
+               } else if (ctx->state != MFCINST_INIT) {
+                       v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
+                       return -EINVAL;
+               }
+               /* Should wait for the header to be parsed */
+               s5p_mfc_clean_ctx_int_flags(ctx);
+               s5p_mfc_wait_for_done_ctx(ctx,
+                               S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0);
+               if (ctx->state >= MFCINST_HEAD_PARSED &&
+                   ctx->state < MFCINST_ABORT) {
+                       ctrl->val = ctx->dpb_count;
+               } else {
+                       v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
+                       return -EINVAL;
+               }
+               break;
+       }
+       return 0;
+}
+
+
+static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = {
+       .s_ctrl = s5p_mfc_dec_s_ctrl,
+       .g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl,
+};
+
+/* Get cropping information */
+static int vidioc_g_crop(struct file *file, void *priv,
+               struct v4l2_crop *cr)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       u32 left, right, top, bottom;
+
+       if (ctx->state != MFCINST_HEAD_PARSED &&
+       ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING
+                                       && ctx->state != MFCINST_FINISHED) {
+                       mfc_err("Cannont set crop\n");
+                       return -EINVAL;
+               }
+       if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) {
+               left = s5p_mfc_read_shm(ctx, CROP_INFO_H);
+               right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT;
+               left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK;
+               top = s5p_mfc_read_shm(ctx, CROP_INFO_V);
+               bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT;
+               top = top & S5P_FIMV_SHARED_CROP_TOP_MASK;
+               cr->c.left = left;
+               cr->c.top = top;
+               cr->c.width = ctx->img_width - left - right;
+               cr->c.height = ctx->img_height - top - bottom;
+               mfc_debug(2, "Cropping info [h264]: l=%d t=%d "
+                       "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top,
+                       cr->c.width, cr->c.height, right, bottom,
+                       ctx->buf_width, ctx->buf_height);
+       } else {
+               cr->c.left = 0;
+               cr->c.top = 0;
+               cr->c.width = ctx->img_width;
+               cr->c.height = ctx->img_height;
+               mfc_debug(2, "Cropping info: w=%d h=%d fw=%d "
+                       "fh=%d\n", cr->c.width, cr->c.height, ctx->buf_width,
+                                                       ctx->buf_height);
+       }
+       return 0;
+}
+
+/* v4l2_ioctl_ops */
+static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
+       .vidioc_querycap = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+       .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+       .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+       .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+       .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+       .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+       .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
+       .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
+       .vidioc_reqbufs = vidioc_reqbufs,
+       .vidioc_querybuf = vidioc_querybuf,
+       .vidioc_qbuf = vidioc_qbuf,
+       .vidioc_dqbuf = vidioc_dqbuf,
+       .vidioc_streamon = vidioc_streamon,
+       .vidioc_streamoff = vidioc_streamoff,
+       .vidioc_g_crop = vidioc_g_crop,
+};
+
+static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count,
+                              unsigned int *plane_count, unsigned long psize[],
+                              void *allocators[])
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+
+       /* Video output for decoding (source)
+        * this can be set after getting an instance */
+       if (ctx->state == MFCINST_INIT &&
+           vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* A single plane is required for input */
+               *plane_count = 1;
+               if (*buf_count < 1)
+                       *buf_count = 1;
+               if (*buf_count > MFC_MAX_BUFFERS)
+                       *buf_count = MFC_MAX_BUFFERS;
+       /* Video capture for decoding (destination)
+        * this can be set after the header was parsed */
+       } else if (ctx->state == MFCINST_HEAD_PARSED &&
+                  vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               /* Output plane count is 2 - one for Y and one for CbCr */
+               *plane_count = 2;
+               /* Setup buffer count */
+               if (*buf_count < ctx->dpb_count)
+                       *buf_count = ctx->dpb_count;
+               if (*buf_count > ctx->dpb_count + MFC_MAX_EXTRA_DPB)
+                       *buf_count = ctx->dpb_count + MFC_MAX_EXTRA_DPB;
+               if (*buf_count > MFC_MAX_BUFFERS)
+                       *buf_count = MFC_MAX_BUFFERS;
+       } else {
+               mfc_err("State seems invalid. State = %d, vq->type = %d\n",
+                                                       ctx->state, vq->type);
+               return -EINVAL;
+       }
+       mfc_debug(2, "Buffer count=%d, plane count=%d\n",
+                                               *buf_count, *plane_count);
+       if (ctx->state == MFCINST_HEAD_PARSED &&
+           vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               psize[0] = ctx->luma_size;
+               psize[1] = ctx->chroma_size;
+               allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+               allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+                  ctx->state == MFCINST_INIT) {
+               psize[0] = ctx->dec_src_buf_size;
+               allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+       } else {
+               mfc_err("This video node is dedicated to decoding. Decoding not initalised\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void s5p_mfc_unlock(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_lock(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_buf_init(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       unsigned int i;
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               if (ctx->capture_state == QUEUE_BUFS_MMAPED)
+                       return 0;
+               for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
+                       if (IS_ERR_OR_NULL(ERR_PTR(
+                                       vb2_dma_contig_plane_paddr(vb, i)))) {
+                               mfc_err("Plane mem not allocated\n");
+                               return -EINVAL;
+                       }
+               }
+               if (vb2_plane_size(vb, 0) < ctx->luma_size ||
+                       vb2_plane_size(vb, 1) < ctx->chroma_size) {
+                       mfc_err("Plane buffer (CAPTURE) is too small\n");
+                       return -EINVAL;
+               }
+               i = vb->v4l2_buf.index;
+               ctx->dst_bufs[i].b = vb;
+               ctx->dst_bufs[i].cookie.raw.luma =
+                                       vb2_dma_contig_plane_paddr(vb, 0);
+               ctx->dst_bufs[i].cookie.raw.chroma =
+                                       vb2_dma_contig_plane_paddr(vb, 1);
+               ctx->dst_bufs_cnt++;
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               if (IS_ERR_OR_NULL(ERR_PTR(
+                                       vb2_dma_contig_plane_paddr(vb, 0)))) {
+                       mfc_err("Plane memory not allocated\n");
+                       return -EINVAL;
+               }
+               if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) {
+                       mfc_err("Plane buffer (OUTPUT) is too small\n");
+                       return -EINVAL;
+               }
+
+               i = vb->v4l2_buf.index;
+               ctx->src_bufs[i].b = vb;
+               ctx->src_bufs[i].cookie.stream =
+                                       vb2_dma_contig_plane_paddr(vb, 0);
+               ctx->src_bufs_cnt++;
+       } else {
+               mfc_err("s5p_mfc_buf_init: unknown queue type\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s5p_mfc_start_streaming(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+
+       v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+       if (ctx->state == MFCINST_FINISHING ||
+               ctx->state == MFCINST_FINISHED)
+               ctx->state = MFCINST_RUNNING;
+       /* If context is ready then dev = work->data;schedule it to run */
+       if (s5p_mfc_ctx_ready(ctx)) {
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+       }
+       s5p_mfc_try_run(dev);
+       return 0;
+}
+
+static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+{
+       unsigned long flags;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       int aborted = 0;
+
+       if ((ctx->state == MFCINST_FINISHING ||
+               ctx->state ==  MFCINST_RUNNING) &&
+               dev->curr_ctx == ctx->num && dev->hw_lock) {
+               ctx->state = MFCINST_ABORT;
+               s5p_mfc_wait_for_done_ctx(ctx,
+                                       S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0);
+               aborted = 1;
+       }
+       spin_lock_irqsave(&dev->irqlock, flags);
+       if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+               INIT_LIST_HEAD(&ctx->dst_queue);
+               ctx->dst_queue_cnt = 0;
+               ctx->dpb_flush_flag = 1;
+               ctx->dec_dst_flag = 0;
+       }
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+               INIT_LIST_HEAD(&ctx->src_queue);
+               ctx->src_queue_cnt = 0;
+       }
+       if (aborted)
+               ctx->state = MFCINST_RUNNING;
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       return 0;
+}
+
+
+static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *mfc_buf;
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
+               mfc_buf->used = 0;
+               spin_lock_irqsave(&dev->irqlock, flags);
+               list_add_tail(&mfc_buf->list, &ctx->src_queue);
+               ctx->src_queue_cnt++;
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index];
+               mfc_buf->used = 0;
+               /* Mark destination as available for use by MFC */
+               spin_lock_irqsave(&dev->irqlock, flags);
+               set_bit(vb->v4l2_buf.index, &ctx->dec_dst_flag);
+               list_add_tail(&mfc_buf->list, &ctx->dst_queue);
+               ctx->dst_queue_cnt++;
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+       } else {
+               mfc_err("Unsupported buffer type (%d)\n", vq->type);
+       }
+       if (s5p_mfc_ctx_ready(ctx)) {
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+       }
+       s5p_mfc_try_run(dev);
+}
+
+static struct vb2_ops s5p_mfc_dec_qops = {
+       .queue_setup            = s5p_mfc_queue_setup,
+       .wait_prepare           = s5p_mfc_unlock,
+       .wait_finish            = s5p_mfc_lock,
+       .buf_init               = s5p_mfc_buf_init,
+       .start_streaming        = s5p_mfc_start_streaming,
+       .stop_streaming         = s5p_mfc_stop_streaming,
+       .buf_queue              = s5p_mfc_buf_queue,
+};
+
+struct s5p_mfc_codec_ops *get_dec_codec_ops(void)
+{
+       return &decoder_codec_ops;
+}
+
+struct vb2_ops *get_dec_queue_ops(void)
+{
+       return &s5p_mfc_dec_qops;
+}
+
+const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void)
+{
+       return &s5p_mfc_dec_ioctl_ops;
+}
+
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+                                               && V4L2_CTRL_DRIVER_PRIV(x))
+
+int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
+{
+       struct v4l2_ctrl_config cfg;
+       int i;
+
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
+       if (ctx->ctrl_handler.error) {
+               mfc_err("v4l2_ctrl_handler_init failed\n");
+               return ctx->ctrl_handler.error;
+       }
+
+       for (i = 0; i < NUM_CTRLS; i++) {
+               if (IS_MFC51_PRIV(controls[i].id)) {
+                       cfg.ops = &s5p_mfc_dec_ctrl_ops;
+                       cfg.id = controls[i].id;
+                       cfg.min = controls[i].minimum;
+                       cfg.max = controls[i].maximum;
+                       cfg.def = controls[i].default_value;
+                       cfg.name = controls[i].name;
+                       cfg.type = controls[i].type;
+
+                       cfg.step = controls[i].step;
+                       cfg.menu_skip_mask = 0;
+
+                       ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+                                       &cfg, NULL);
+               } else {
+                       ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+                                       &s5p_mfc_dec_ctrl_ops,
+                                       controls[i].id, controls[i].minimum,
+                                       controls[i].maximum, controls[i].step,
+                                       controls[i].default_value);
+               }
+               if (ctx->ctrl_handler.error) {
+                       mfc_err("Adding control (%d) failed\n", i);
+                       return ctx->ctrl_handler.error;
+               }
+               if (controls[i].is_volatile && ctx->ctrls[i])
+                       ctx->ctrls[i]->is_volatile = 1;
+       }
+       return 0;
+}
+
+void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx)
+{
+       int i;
+
+       v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+       for (i = 0; i < NUM_CTRLS; i++)
+               ctx->ctrls[i] = NULL;
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.h b/drivers/media/video/s5p-mfc/s5p_mfc_dec.h
new file mode 100644 (file)
index 0000000..fb8b215
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_dec.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_DEC_H_
+#define S5P_MFC_DEC_H_
+
+struct s5p_mfc_codec_ops *get_dec_codec_ops(void);
+struct vb2_ops *get_dec_queue_ops(void);
+const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void);
+struct s5p_mfc_fmt *get_dec_def_fmt(bool src);
+int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_DEC_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
new file mode 100644 (file)
index 0000000..fee094a
--- /dev/null
@@ -0,0 +1,1829 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Jeongtae Park       <jtp.park@samsung.com>
+ * Kamil Debski                <k.debski@samsung.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_enc.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+
+static struct s5p_mfc_fmt formats[] = {
+       {
+               .name = "4:2:0 2 Planes 64x32 Tiles",
+               .fourcc = V4L2_PIX_FMT_NV12MT,
+               .codec_mode = S5P_FIMV_CODEC_NONE,
+               .type = MFC_FMT_RAW,
+               .num_planes = 2,
+       },
+       {
+               .name = "4:2:0 2 Planes",
+               .fourcc = V4L2_PIX_FMT_NV12M,
+               .codec_mode = S5P_FIMV_CODEC_NONE,
+               .type = MFC_FMT_RAW,
+               .num_planes = 2,
+       },
+       {
+               .name = "H264 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H264,
+               .codec_mode = S5P_FIMV_CODEC_H264_ENC,
+               .type = MFC_FMT_ENC,
+               .num_planes = 1,
+       },
+       {
+               .name = "MPEG4 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG4,
+               .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC,
+               .type = MFC_FMT_ENC,
+               .num_planes = 1,
+       },
+       {
+               .name = "H264 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H263,
+               .codec_mode = S5P_FIMV_CODEC_H263_ENC,
+               .type = MFC_FMT_ENC,
+               .num_planes = 1,
+       },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
+{
+       unsigned int i;
+
+       for (i = 0; i < NUM_FORMATS; i++) {
+               if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+                   formats[i].type == t)
+                       return &formats[i];
+       }
+       return NULL;
+}
+
+static struct mfc_control controls[] = {
+       {
+               .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+               .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
+               .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 1,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 1900,
+               .maximum = (1 << 30) - 1,
+               .step = 1,
+               .default_value = 1900,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Padding Control Enable",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Padding Color YUV Value",
+               .minimum = 0,
+               .maximum = (1 << 25) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 1,
+               .maximum = (1 << 30) - 1,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Rate Control Reaction Coeff.",
+               .minimum = 1,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .name = "Force frame type",
+               .minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+               .maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED,
+               .default_value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+               .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+               .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .name = "Frame Skip Enable",
+               .minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+               .maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+               .menu_skip_mask = 0,
+               .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "Fixed Target Bit Enable",
+               .minimum = 0,
+               .maximum = 1,
+               .default_value = 0,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 2,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+               .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
+               .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+               .menu_skip_mask = ~(
+                               (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+                               (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+                               (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)
+                               ),
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+               .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
+               .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+               .menu_skip_mask = ~(
+                               (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
+                               (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2) |
+                               (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_0) |
+                               (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_1)
+                               ),
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+               .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
+               .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+               .maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
+               .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = -6,
+               .maximum = 6,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = -6,
+               .maximum = 6,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+               .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+               .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "The Number of Ref. Pic for P",
+               .minimum = 1,
+               .maximum = 2,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H263 I-Frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H263 Minimum QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H263 Maximum QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H263 P frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "H263 B frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "MPEG4 I-Frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "MPEG4 Minimum QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "MPEG4 Maximum QP value",
+               .minimum = 0,
+               .maximum = 51,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "MPEG4 P frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "MPEG4 B frame QP value",
+               .minimum = 1,
+               .maximum = 31,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "H264 Dark Reg Adaptive RC",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "H264 Smooth Reg Adaptive RC",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "H264 Static Reg Adaptive RC",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .name = "H264 Activity Reg Adaptive RC",
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
+               .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
+               .default_value = 0,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 1,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = (1 << 16) - 1,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+               .type = V4L2_CTRL_TYPE_MENU,
+               .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+               .maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
+               .default_value = 0,
+               .menu_skip_mask = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL,
+               .type = V4L2_CTRL_TYPE_BOOLEAN,
+               .minimum = 0,
+               .maximum = 1,
+               .step = 1,
+               .default_value = 0,
+       },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+static const char * const *mfc51_get_menu(u32 id)
+{
+       static const char * const mfc51_video_frame_skip[] = {
+               "Disabled",
+               "Level Limit",
+               "VBV/CPB Limit",
+               NULL,
+       };
+       static const char * const mfc51_video_force_frame[] = {
+               "Disabled",
+               "I Frame",
+               "Not Coded",
+               NULL,
+       };
+       switch (id) {
+       case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+               return mfc51_video_frame_skip;
+       case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+               return mfc51_video_force_frame;
+       }
+       return NULL;
+}
+
+static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+       mfc_debug(2, "src=%d, dst=%d, state=%d\n",
+                 ctx->src_queue_cnt, ctx->dst_queue_cnt, ctx->state);
+       /* context is ready to make header */
+       if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1)
+               return 1;
+       /* context is ready to encode a frame */
+       if (ctx->state == MFCINST_RUNNING &&
+               ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+               return 1;
+       /* context is ready to encode remain frames */
+       if (ctx->state == MFCINST_FINISHING &&
+               ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+               return 1;
+       mfc_debug(2, "ctx is not ready\n");
+       return 0;
+}
+
+static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_buf *mb_entry;
+       unsigned long mb_y_addr, mb_c_addr;
+
+       /* move buffers in ref queue to src queue */
+       while (!list_empty(&ctx->ref_queue)) {
+               mb_entry = list_entry((&ctx->ref_queue)->next,
+                                               struct s5p_mfc_buf, list);
+               mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0);
+               mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1);
+               list_del(&mb_entry->list);
+               ctx->ref_queue_cnt--;
+               list_add_tail(&mb_entry->list, &ctx->src_queue);
+               ctx->src_queue_cnt++;
+       }
+       mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
+                 ctx->src_queue_cnt, ctx->ref_queue_cnt);
+       INIT_LIST_HEAD(&ctx->ref_queue);
+       ctx->ref_queue_cnt = 0;
+}
+
+static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf *dst_mb;
+       unsigned long dst_addr;
+       unsigned int dst_size;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_size = vb2_plane_size(dst_mb->b, 0);
+       s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       return 0;
+}
+
+static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       struct s5p_mfc_buf *dst_mb;
+       unsigned long flags;
+
+       if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
+               spin_lock_irqsave(&dev->irqlock, flags);
+               dst_mb = list_entry(ctx->dst_queue.next,
+                               struct s5p_mfc_buf, list);
+               list_del(&dst_mb->list);
+               ctx->dst_queue_cnt--;
+               vb2_set_plane_payload(dst_mb->b, 0,
+                                               s5p_mfc_get_enc_strm_size());
+               vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE);
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+       }
+       ctx->state = MFCINST_RUNNING;
+       if (s5p_mfc_ctx_ready(ctx)) {
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+       }
+       s5p_mfc_try_run(dev);
+       return 0;
+}
+
+static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf *dst_mb;
+       struct s5p_mfc_buf *src_mb;
+       unsigned long flags;
+       unsigned long src_y_addr, src_c_addr, dst_addr;
+       unsigned int dst_size;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       src_y_addr = vb2_dma_contig_plane_paddr(src_mb->b, 0);
+       src_c_addr = vb2_dma_contig_plane_paddr(src_mb->b, 1);
+       s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_size = vb2_plane_size(dst_mb->b, 0);
+       s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+
+       return 0;
+}
+
+static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf *mb_entry;
+       unsigned long enc_y_addr, enc_c_addr;
+       unsigned long mb_y_addr, mb_c_addr;
+       int slice_type;
+       unsigned int strm_size;
+       unsigned long flags;
+
+       slice_type = s5p_mfc_get_enc_slice_type();
+       strm_size = s5p_mfc_get_enc_strm_size();
+       mfc_debug(2, "Encoded slice type: %d", slice_type);
+       mfc_debug(2, "Encoded stream size: %d", strm_size);
+       mfc_debug(2, "Display order: %d",
+                 mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
+       spin_lock_irqsave(&dev->irqlock, flags);
+       if (slice_type >= 0) {
+               s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr);
+               list_for_each_entry(mb_entry, &ctx->src_queue, list) {
+                       mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0);
+                       mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1);
+                       if ((enc_y_addr == mb_y_addr) &&
+                                               (enc_c_addr == mb_c_addr)) {
+                               list_del(&mb_entry->list);
+                               ctx->src_queue_cnt--;
+                               vb2_buffer_done(mb_entry->b,
+                                                       VB2_BUF_STATE_DONE);
+                               break;
+                       }
+               }
+               list_for_each_entry(mb_entry, &ctx->ref_queue, list) {
+                       mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0);
+                       mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1);
+                       if ((enc_y_addr == mb_y_addr) &&
+                                               (enc_c_addr == mb_c_addr)) {
+                               list_del(&mb_entry->list);
+                               ctx->ref_queue_cnt--;
+                               vb2_buffer_done(mb_entry->b,
+                                                       VB2_BUF_STATE_DONE);
+                               break;
+                       }
+               }
+       }
+       if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) {
+               mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
+                                                                       list);
+               if (mb_entry->used) {
+                       list_del(&mb_entry->list);
+                       ctx->src_queue_cnt--;
+                       list_add_tail(&mb_entry->list, &ctx->ref_queue);
+                       ctx->ref_queue_cnt++;
+               }
+               mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
+                         ctx->src_queue_cnt, ctx->ref_queue_cnt);
+       }
+       if (strm_size > 0) {
+               /* at least one more dest. buffers exist always  */
+               mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf,
+                                                                       list);
+               list_del(&mb_entry->list);
+               ctx->dst_queue_cnt--;
+               switch (slice_type) {
+               case S5P_FIMV_ENC_SI_SLICE_TYPE_I:
+                       mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+                       break;
+               case S5P_FIMV_ENC_SI_SLICE_TYPE_P:
+                       mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+                       break;
+               case S5P_FIMV_ENC_SI_SLICE_TYPE_B:
+                       mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME;
+                       break;
+               }
+               vb2_set_plane_payload(mb_entry->b, 0, strm_size);
+               vb2_buffer_done(mb_entry->b, VB2_BUF_STATE_DONE);
+       }
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0)) {
+               spin_lock(&dev->condlock);
+               clear_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock(&dev->condlock);
+       }
+       return 0;
+}
+
+static struct s5p_mfc_codec_ops encoder_codec_ops = {
+       .pre_seq_start          = enc_pre_seq_start,
+       .post_seq_start         = enc_post_seq_start,
+       .pre_frame_start        = enc_pre_frame_start,
+       .post_frame_start       = enc_post_frame_start,
+};
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+
+       strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+       strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+       cap->bus_info[0] = 0;
+       cap->version = KERNEL_VERSION(1, 0, 0);
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+                         | V4L2_CAP_VIDEO_OUTPUT
+                         | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+{
+       struct s5p_mfc_fmt *fmt;
+       int i, j = 0;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (mplane && formats[i].num_planes == 1)
+                       continue;
+               else if (!mplane && formats[i].num_planes > 1)
+                       continue;
+               if (out && formats[i].type != MFC_FMT_RAW)
+                       continue;
+               else if (!out && formats[i].type != MFC_FMT_ENC)
+                       continue;
+               if (j == f->index) {
+                       fmt = &formats[i];
+                       strlcpy(f->description, fmt->name,
+                               sizeof(f->description));
+                       f->pixelformat = fmt->fourcc;
+                       return 0;
+               }
+               ++j;
+       }
+       return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+                                  struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, false, false);
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+                                         struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, true, false);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+                                  struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, false, true);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+                                         struct v4l2_fmtdesc *f)
+{
+       return vidioc_enum_fmt(f, true, true);
+}
+
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+       mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state);
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               /* This is run on output (encoder dest) */
+               pix_fmt_mp->width = 0;
+               pix_fmt_mp->height = 0;
+               pix_fmt_mp->field = V4L2_FIELD_NONE;
+               pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
+               pix_fmt_mp->num_planes = ctx->dst_fmt->num_planes;
+
+               pix_fmt_mp->plane_fmt[0].bytesperline = ctx->enc_dst_buf_size;
+               pix_fmt_mp->plane_fmt[0].sizeimage = ctx->enc_dst_buf_size;
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* This is run on capture (encoder src) */
+               pix_fmt_mp->width = ctx->img_width;
+               pix_fmt_mp->height = ctx->img_height;
+
+               pix_fmt_mp->field = V4L2_FIELD_NONE;
+               pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
+               pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
+
+               pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+               pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+               pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+               pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+       } else {
+               mfc_err("invalid buf type\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_fmt *fmt;
+       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               fmt = find_format(f, MFC_FMT_ENC);
+               if (!fmt) {
+                       mfc_err("failed to try output format\n");
+                       return -EINVAL;
+               }
+
+               if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
+                       mfc_err("must be set encoding output size\n");
+                       return -EINVAL;
+               }
+
+               pix_fmt_mp->plane_fmt[0].bytesperline =
+                       pix_fmt_mp->plane_fmt[0].sizeimage;
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               fmt = find_format(f, MFC_FMT_RAW);
+               if (!fmt) {
+                       mfc_err("failed to try output format\n");
+                       return -EINVAL;
+               }
+
+               if (fmt->num_planes != pix_fmt_mp->num_planes) {
+                       mfc_err("failed to try output format\n");
+                       return -EINVAL;
+               }
+       } else {
+               mfc_err("invalid buf type\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct s5p_mfc_dev *dev = video_drvdata(file);
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       struct s5p_mfc_fmt *fmt;
+       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+       unsigned long flags;
+       int ret = 0;
+
+       ret = vidioc_try_fmt(file, priv, f);
+       if (ret)
+               return ret;
+       if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
+               v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+               ret = -EBUSY;
+               goto out;
+       }
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               fmt = find_format(f, MFC_FMT_ENC);
+               if (!fmt) {
+                       mfc_err("failed to set capture format\n");
+                       return -EINVAL;
+               }
+               ctx->state = MFCINST_INIT;
+               ctx->dst_fmt = fmt;
+               ctx->codec_mode = ctx->dst_fmt->codec_mode;
+               ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
+               pix_fmt_mp->plane_fmt[0].bytesperline = 0;
+               ctx->dst_bufs_cnt = 0;
+               ctx->capture_state = QUEUE_FREE;
+               s5p_mfc_alloc_instance_buffer(ctx);
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+               s5p_mfc_clean_ctx_int_flags(ctx);
+               s5p_mfc_try_run(dev);
+               if (s5p_mfc_wait_for_done_ctx(ctx, \
+                               S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 1)) {
+                               /* Error or timeout */
+                       mfc_err("Error getting instance from hardware\n");
+                       s5p_mfc_release_instance_buffer(ctx);
+                       ret = -EIO;
+                       goto out;
+               }
+               mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               fmt = find_format(f, MFC_FMT_RAW);
+               if (!fmt) {
+                       mfc_err("failed to set output format\n");
+                       return -EINVAL;
+               }
+               if (fmt->num_planes != pix_fmt_mp->num_planes) {
+                       mfc_err("failed to set output format\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+               ctx->src_fmt = fmt;
+               ctx->img_width = pix_fmt_mp->width;
+               ctx->img_height = pix_fmt_mp->height;
+               mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode);
+               mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n",
+                       pix_fmt_mp->width, pix_fmt_mp->height,
+                       ctx->img_width, ctx->img_height);
+               if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
+                       ctx->buf_width = ALIGN(ctx->img_width,
+                                                       S5P_FIMV_NV12M_HALIGN);
+                       ctx->luma_size = ALIGN(ctx->img_width,
+                               S5P_FIMV_NV12M_HALIGN) * ALIGN(ctx->img_height,
+                               S5P_FIMV_NV12M_LVALIGN);
+                       ctx->chroma_size = ALIGN(ctx->img_width,
+                               S5P_FIMV_NV12M_HALIGN) * ALIGN((ctx->img_height
+                               >> 1), S5P_FIMV_NV12M_CVALIGN);
+
+                       ctx->luma_size = ALIGN(ctx->luma_size,
+                                                       S5P_FIMV_NV12M_SALIGN);
+                       ctx->chroma_size = ALIGN(ctx->chroma_size,
+                                                       S5P_FIMV_NV12M_SALIGN);
+
+                       pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+                       pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+                       pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+                       pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+
+               } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
+                       ctx->buf_width = ALIGN(ctx->img_width,
+                                                       S5P_FIMV_NV12MT_HALIGN);
+                       ctx->luma_size = ALIGN(ctx->img_width,
+                               S5P_FIMV_NV12MT_HALIGN) * ALIGN(ctx->img_height,
+                               S5P_FIMV_NV12MT_VALIGN);
+                       ctx->chroma_size = ALIGN(ctx->img_width,
+                               S5P_FIMV_NV12MT_HALIGN) * ALIGN((ctx->img_height
+                               >> 1), S5P_FIMV_NV12MT_VALIGN);
+                       ctx->luma_size = ALIGN(ctx->luma_size,
+                                                       S5P_FIMV_NV12MT_SALIGN);
+                       ctx->chroma_size = ALIGN(ctx->chroma_size,
+                                                       S5P_FIMV_NV12MT_SALIGN);
+
+                       pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+                       pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+                       pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+                       pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+               }
+               ctx->src_bufs_cnt = 0;
+               ctx->output_state = QUEUE_FREE;
+       } else {
+               mfc_err("invalid buf type\n");
+               return -EINVAL;
+       }
+out:
+       mfc_debug_leave();
+       return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                                         struct v4l2_requestbuffers *reqbufs)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       int ret = 0;
+
+       /* if memory is not mmp or userptr return error */
+       if ((reqbufs->memory != V4L2_MEMORY_MMAP) &&
+               (reqbufs->memory != V4L2_MEMORY_USERPTR))
+               return -EINVAL;
+       if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               if (ctx->capture_state != QUEUE_FREE) {
+                       mfc_err("invalid capture state: %d\n",
+                                                       ctx->capture_state);
+                       return -EINVAL;
+               }
+               ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+               if (ret != 0) {
+                       mfc_err("error in vb2_reqbufs() for E(D)\n");
+                       return ret;
+               }
+               ctx->capture_state = QUEUE_BUFS_REQUESTED;
+               ret = s5p_mfc_alloc_codec_buffers(ctx);
+               if (ret) {
+                       mfc_err("Failed to allocate encoding buffers\n");
+                       reqbufs->count = 0;
+                       ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+                       return -ENOMEM;
+               }
+       } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               if (ctx->output_state != QUEUE_FREE) {
+                       mfc_err("invalid output state: %d\n",
+                                                       ctx->output_state);
+                       return -EINVAL;
+               }
+               ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+               if (ret != 0) {
+                       mfc_err("error in vb2_reqbufs() for E(S)\n");
+                       return ret;
+               }
+               ctx->output_state = QUEUE_BUFS_REQUESTED;
+       } else {
+               mfc_err("invalid buf type\n");
+               return -EINVAL;
+       }
+       return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                                                  struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+       int ret = 0;
+
+       /* if memory is not mmp or userptr return error */
+       if ((buf->memory != V4L2_MEMORY_MMAP) &&
+               (buf->memory != V4L2_MEMORY_USERPTR))
+               return -EINVAL;
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               if (ctx->state != MFCINST_GOT_INST) {
+                       mfc_err("invalid context state: %d\n", ctx->state);
+                       return -EINVAL;
+               }
+               ret = vb2_querybuf(&ctx->vq_dst, buf);
+               if (ret != 0) {
+                       mfc_err("error in vb2_querybuf() for E(D)\n");
+                       return ret;
+               }
+               buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE;
+       } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               ret = vb2_querybuf(&ctx->vq_src, buf);
+               if (ret != 0) {
+                       mfc_err("error in vb2_querybuf() for E(S)\n");
+                       return ret;
+               }
+       } else {
+               mfc_err("invalid buf type\n");
+               return -EINVAL;
+       }
+       return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MFCINST_ERROR) {
+               mfc_err("Call on QBUF after unrecoverable error\n");
+               return -EIO;
+       }
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_qbuf(&ctx->vq_src, buf);
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_qbuf(&ctx->vq_dst, buf);
+       return -EINVAL;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (ctx->state == MFCINST_ERROR) {
+               mfc_err("Call on DQBUF after unrecoverable error\n");
+               return -EIO;
+       }
+       if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+       else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+       return -EINVAL;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type type)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_streamon(&ctx->vq_src, type);
+       else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_streamon(&ctx->vq_dst, type);
+       return -EINVAL;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type type)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               return vb2_streamoff(&ctx->vq_src, type);
+       else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+               return vb2_streamoff(&ctx->vq_dst, type);
+       return -EINVAL;
+}
+
+static inline int h264_level(enum v4l2_mpeg_video_h264_level lvl)
+{
+       static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_4_0 + 1] = {
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_1_0   */ 10,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_1B    */ 9,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_1_1   */ 11,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_1_2   */ 12,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_1_3   */ 13,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_2_0   */ 20,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_2_1   */ 21,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_2_2   */ 22,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_3_0   */ 30,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_3_1   */ 31,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_3_2   */ 32,
+               /* V4L2_MPEG_VIDEO_H264_LEVEL_4_0   */ 40,
+       };
+       return t[lvl];
+}
+
+static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl)
+{
+       static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 + 1] = {
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0    */ 0,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B   */ 9,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1    */ 1,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2    */ 2,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3    */ 3,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B   */ 7,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4    */ 4,
+               /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5    */ 5,
+       };
+       return t[lvl];
+}
+
+static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
+{
+       static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = {
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED     */ 0,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1             */ 1,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11           */ 2,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11           */ 3,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11           */ 4,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33           */ 5,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11           */ 6,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11           */ 7,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11           */ 8,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33           */ 9,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11           */ 10,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11           */ 11,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33           */ 12,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99          */ 13,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3             */ 14,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2             */ 15,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1             */ 16,
+               /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED        */ 255,
+       };
+       return t[sar];
+}
+
+static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               p->gop_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+               p->slice_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+               p->slice_mb = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+               p->slice_bit = ctrl->val * 8;
+               break;
+       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+               p->intra_refresh_mb = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_PADDING:
+               p->pad = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV:
+               p->pad_luma = (ctrl->val >> 16) & 0xff;
+               p->pad_cb = (ctrl->val >> 8) & 0xff;
+               p->pad_cr = (ctrl->val >> 0) & 0xff;
+               break;
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+               p->rc_frame = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               p->rc_bitrate = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
+               p->rc_reaction_coeff = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+               ctx->force_frame_type = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
+               p->vbv_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
+               p->codec.h264.cpb_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+               p->seq_hdr_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+               p->frame_skip_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT:
+               p->fixed_target_bit = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+               p->num_b_frame = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+               switch (ctrl->val) {
+               case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+                       p->codec.h264.profile =
+                                       S5P_FIMV_ENC_PROFILE_H264_MAIN;
+                       break;
+               case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+                       p->codec.h264.profile =
+                                       S5P_FIMV_ENC_PROFILE_H264_HIGH;
+                       break;
+               case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+                       p->codec.h264.profile =
+                               S5P_FIMV_ENC_PROFILE_H264_BASELINE;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+               p->codec.h264.level_v4l2 = ctrl->val;
+               p->codec.h264.level = h264_level(ctrl->val);
+               if (p->codec.h264.level < 0) {
+                       mfc_err("Level number is wrong\n");
+                       ret = p->codec.h264.level;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+               p->codec.mpeg4.level_v4l2 = ctrl->val;
+               p->codec.mpeg4.level = mpeg4_level(ctrl->val);
+               if (p->codec.mpeg4.level < 0) {
+                       mfc_err("Level number is wrong\n");
+                       ret = p->codec.mpeg4.level;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+               p->codec.h264.loop_filter_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+               p->codec.h264.loop_filter_alpha = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+               p->codec.h264.loop_filter_beta = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+               p->codec.h264.entropy_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P:
+               p->codec.h264.num_ref_pic_4p = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+               p->codec.h264._8x8_transform = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+               p->codec.h264.rc_mb = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+               p->codec.h264.rc_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+               p->codec.h264.rc_min_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+               p->codec.h264.rc_max_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+               p->codec.h264.rc_p_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+               p->codec.h264.rc_b_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+       case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+               p->codec.mpeg4.rc_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+       case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+               p->codec.mpeg4.rc_min_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+       case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+               p->codec.mpeg4.rc_max_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+       case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+               p->codec.mpeg4.rc_p_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+       case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
+               p->codec.mpeg4.rc_b_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK:
+               p->codec.h264.rc_mb_dark = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH:
+               p->codec.h264.rc_mb_smooth = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC:
+               p->codec.h264.rc_mb_static = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY:
+               p->codec.h264.rc_mb_activity = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+               p->codec.h264.vui_sar = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+               p->codec.h264.vui_sar_idc = vui_sar_idc(ctrl->val);
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
+               p->codec.h264.vui_ext_sar_width = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
+               p->codec.h264.vui_ext_sar_height = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+               p->codec.h264.open_gop = !ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+               p->codec.h264.open_gop_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+               switch (ctrl->val) {
+               case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+                       p->codec.mpeg4.profile =
+                               S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE;
+                       break;
+               case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+                       p->codec.mpeg4.profile =
+                       S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+               p->codec.mpeg4.quarter_pixel = ctrl->val;
+               break;
+       default:
+               v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
+                                                       ctrl->id, ctrl->val);
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = {
+       .s_ctrl = s5p_mfc_enc_s_ctrl,
+};
+
+int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               ctx->enc_params.rc_framerate_num =
+                                       a->parm.output.timeperframe.denominator;
+               ctx->enc_params.rc_framerate_denom =
+                                       a->parm.output.timeperframe.numerator;
+       } else {
+               mfc_err("Setting FPS is only possible for the output queue\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+       if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               a->parm.output.timeperframe.denominator =
+                                       ctx->enc_params.rc_framerate_num;
+               a->parm.output.timeperframe.numerator =
+                                       ctx->enc_params.rc_framerate_denom;
+       } else {
+               mfc_err("Setting FPS is only possible for the output queue\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
+       .vidioc_querycap = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+       .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+       .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+       .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+       .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+       .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+       .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
+       .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
+       .vidioc_reqbufs = vidioc_reqbufs,
+       .vidioc_querybuf = vidioc_querybuf,
+       .vidioc_qbuf = vidioc_qbuf,
+       .vidioc_dqbuf = vidioc_dqbuf,
+       .vidioc_streamon = vidioc_streamon,
+       .vidioc_streamoff = vidioc_streamoff,
+       .vidioc_s_parm = vidioc_s_parm,
+       .vidioc_g_parm = vidioc_g_parm,
+};
+
+static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
+{
+       int i;
+
+       if (!fmt)
+               return -EINVAL;
+       if (fmt->num_planes != vb->num_planes) {
+               mfc_err("invalid plane number for the format\n");
+               return -EINVAL;
+       }
+       for (i = 0; i < fmt->num_planes; i++) {
+               if (!vb2_dma_contig_plane_paddr(vb, i)) {
+                       mfc_err("failed to get plane cookie\n");
+                       return -EINVAL;
+               }
+               mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx",
+                               vb->v4l2_buf.index, i,
+                               vb2_dma_contig_plane_paddr(vb, i));
+       }
+       return 0;
+}
+
+static int s5p_mfc_queue_setup(struct vb2_queue *vq,
+                      unsigned int *buf_count, unsigned int *plane_count,
+                      unsigned long psize[], void *allocators[])
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+
+       if (ctx->state != MFCINST_GOT_INST) {
+               mfc_err("inavlid state: %d\n", ctx->state);
+               return -EINVAL;
+       }
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               if (ctx->dst_fmt)
+                       *plane_count = ctx->dst_fmt->num_planes;
+               else
+                       *plane_count = MFC_ENC_CAP_PLANE_COUNT;
+               if (*buf_count < 1)
+                       *buf_count = 1;
+               if (*buf_count > MFC_MAX_BUFFERS)
+                       *buf_count = MFC_MAX_BUFFERS;
+               psize[0] = ctx->enc_dst_buf_size;
+               allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               if (ctx->src_fmt)
+                       *plane_count = ctx->src_fmt->num_planes;
+               else
+                       *plane_count = MFC_ENC_OUT_PLANE_COUNT;
+
+               if (*buf_count < 1)
+                       *buf_count = 1;
+               if (*buf_count > MFC_MAX_BUFFERS)
+                       *buf_count = MFC_MAX_BUFFERS;
+               psize[0] = ctx->luma_size;
+               psize[1] = ctx->chroma_size;
+               allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+               allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
+       } else {
+               mfc_err("inavlid queue type: %d\n", vq->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void s5p_mfc_unlock(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_lock(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_buf_init(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       unsigned int i;
+       int ret;
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               ret = check_vb_with_fmt(ctx->dst_fmt, vb);
+               if (ret < 0)
+                       return ret;
+               i = vb->v4l2_buf.index;
+               ctx->dst_bufs[i].b = vb;
+               ctx->dst_bufs[i].cookie.stream =
+                                       vb2_dma_contig_plane_paddr(vb, 0);
+               ctx->dst_bufs_cnt++;
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               ret = check_vb_with_fmt(ctx->src_fmt, vb);
+               if (ret < 0)
+                       return ret;
+               i = vb->v4l2_buf.index;
+               ctx->src_bufs[i].b = vb;
+               ctx->src_bufs[i].cookie.raw.luma =
+                                       vb2_dma_contig_plane_paddr(vb, 0);
+               ctx->src_bufs[i].cookie.raw.chroma =
+                                       vb2_dma_contig_plane_paddr(vb, 1);
+               ctx->src_bufs_cnt++;
+       } else {
+               mfc_err("inavlid queue type: %d\n", vq->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       int ret;
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               ret = check_vb_with_fmt(ctx->dst_fmt, vb);
+               if (ret < 0)
+                       return ret;
+               mfc_debug(2, "plane size: %ld, dst size: %d\n",
+                       vb2_plane_size(vb, 0), ctx->enc_dst_buf_size);
+               if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) {
+                       mfc_err("plane size is too small for capture\n");
+                       return -EINVAL;
+               }
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               ret = check_vb_with_fmt(ctx->src_fmt, vb);
+               if (ret < 0)
+                       return ret;
+               mfc_debug(2, "plane size: %ld, luma size: %d\n",
+                       vb2_plane_size(vb, 0), ctx->luma_size);
+               mfc_debug(2, "plane size: %ld, chroma size: %d\n",
+                       vb2_plane_size(vb, 1), ctx->chroma_size);
+               if (vb2_plane_size(vb, 0) < ctx->luma_size ||
+                   vb2_plane_size(vb, 1) < ctx->chroma_size) {
+                       mfc_err("plane size is too small for output\n");
+                       return -EINVAL;
+               }
+       } else {
+               mfc_err("inavlid queue type: %d\n", vq->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s5p_mfc_start_streaming(struct vb2_queue *q)
+{
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+
+       v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+       /* If context is ready then dev = work->data;schedule it to run */
+       if (s5p_mfc_ctx_ready(ctx)) {
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+       }
+       s5p_mfc_try_run(dev);
+       return 0;
+}
+
+static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+{
+       unsigned long flags;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       if ((ctx->state == MFCINST_FINISHING ||
+               ctx->state == MFCINST_RUNNING) &&
+               dev->curr_ctx == ctx->num && dev->hw_lock) {
+               ctx->state = MFCINST_ABORT;
+               s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET,
+                                         0);
+       }
+       ctx->state = MFCINST_FINISHED;
+       spin_lock_irqsave(&dev->irqlock, flags);
+       if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+               INIT_LIST_HEAD(&ctx->dst_queue);
+               ctx->dst_queue_cnt = 0;
+       }
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               cleanup_ref_queue(ctx);
+               s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+               INIT_LIST_HEAD(&ctx->src_queue);
+               ctx->src_queue_cnt = 0;
+       }
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       return 0;
+}
+
+static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *mfc_buf;
+
+       if (ctx->state == MFCINST_ERROR) {
+               vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+               cleanup_ref_queue(ctx);
+               return;
+       }
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+               mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index];
+               mfc_buf->used = 0;
+               /* Mark destination as available for use by MFC */
+               spin_lock_irqsave(&dev->irqlock, flags);
+               list_add_tail(&mfc_buf->list, &ctx->dst_queue);
+               ctx->dst_queue_cnt++;
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+       } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index];
+               mfc_buf->used = 0;
+               spin_lock_irqsave(&dev->irqlock, flags);
+               if (vb->v4l2_planes[0].bytesused == 0) {
+                       mfc_debug(1, "change state to FINISHING\n");
+                       ctx->state = MFCINST_FINISHING;
+                       vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+                       cleanup_ref_queue(ctx);
+               } else {
+                       list_add_tail(&mfc_buf->list, &ctx->src_queue);
+                       ctx->src_queue_cnt++;
+               }
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+       } else {
+               mfc_err("unsupported buffer type (%d)\n", vq->type);
+       }
+       if (s5p_mfc_ctx_ready(ctx)) {
+               spin_lock_irqsave(&dev->condlock, flags);
+               set_bit(ctx->num, &dev->ctx_work_bits);
+               spin_unlock_irqrestore(&dev->condlock, flags);
+       }
+       s5p_mfc_try_run(dev);
+}
+
+static struct vb2_ops s5p_mfc_enc_qops = {
+       .queue_setup            = s5p_mfc_queue_setup,
+       .wait_prepare           = s5p_mfc_unlock,
+       .wait_finish            = s5p_mfc_lock,
+       .buf_init               = s5p_mfc_buf_init,
+       .buf_prepare            = s5p_mfc_buf_prepare,
+       .start_streaming        = s5p_mfc_start_streaming,
+       .stop_streaming         = s5p_mfc_stop_streaming,
+       .buf_queue              = s5p_mfc_buf_queue,
+};
+
+struct s5p_mfc_codec_ops *get_enc_codec_ops(void)
+{
+       return &encoder_codec_ops;
+}
+
+struct vb2_ops *get_enc_queue_ops(void)
+{
+       return &s5p_mfc_enc_qops;
+}
+
+const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void)
+{
+       return &s5p_mfc_enc_ioctl_ops;
+}
+
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+                                               && V4L2_CTRL_DRIVER_PRIV(x))
+
+int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
+{
+       struct v4l2_ctrl_config cfg;
+       int i;
+
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
+       if (ctx->ctrl_handler.error) {
+               mfc_err("v4l2_ctrl_handler_init failed\n");
+               return ctx->ctrl_handler.error;
+       }
+       for (i = 0; i < NUM_CTRLS; i++) {
+               if (IS_MFC51_PRIV(controls[i].id)) {
+                       cfg.ops = &s5p_mfc_enc_ctrl_ops;
+                       cfg.id = controls[i].id;
+                       cfg.min = controls[i].minimum;
+                       cfg.max = controls[i].maximum;
+                       cfg.def = controls[i].default_value;
+                       cfg.name = controls[i].name;
+                       cfg.type = controls[i].type;
+                       cfg.flags = 0;
+
+                       if (cfg.type == V4L2_CTRL_TYPE_MENU) {
+                               cfg.step = 0;
+                               cfg.menu_skip_mask = cfg.menu_skip_mask;
+                               cfg.qmenu = mfc51_get_menu(cfg.id);
+                       } else {
+                               cfg.step = controls[i].step;
+                               cfg.menu_skip_mask = 0;
+                       }
+                       ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+                                       &cfg, NULL);
+               } else {
+                       if (controls[i].type == V4L2_CTRL_TYPE_MENU) {
+                               ctx->ctrls[i] = v4l2_ctrl_new_std_menu(
+                                       &ctx->ctrl_handler,
+                                       &s5p_mfc_enc_ctrl_ops, controls[i].id,
+                                       controls[i].maximum, 0,
+                                       controls[i].default_value);
+                       } else {
+                               ctx->ctrls[i] = v4l2_ctrl_new_std(
+                                       &ctx->ctrl_handler,
+                                       &s5p_mfc_enc_ctrl_ops, controls[i].id,
+                                       controls[i].minimum,
+                                       controls[i].maximum, controls[i].step,
+                                       controls[i].default_value);
+                       }
+               }
+               if (ctx->ctrl_handler.error) {
+                       mfc_err("Adding control (%d) failed\n", i);
+                       return ctx->ctrl_handler.error;
+               }
+               if (controls[i].is_volatile && ctx->ctrls[i])
+                       ctx->ctrls[i]->is_volatile = 1;
+       }
+       return 0;
+}
+
+void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx)
+{
+       int i;
+
+       v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+       for (i = 0; i < NUM_CTRLS; i++)
+               ctx->ctrls[i] = NULL;
+}
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.h b/drivers/media/video/s5p-mfc/s5p_mfc_enc.h
new file mode 100644 (file)
index 0000000..405bdd3
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_enc.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_ENC_H_
+#define S5P_MFC_ENC_H_
+
+struct s5p_mfc_codec_ops *get_enc_codec_ops(void);
+struct vb2_ops *get_enc_queue_ops(void);
+const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void);
+struct s5p_mfc_fmt *get_enc_def_fmt(bool src);
+int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx);
+
+#endif /* S5P_MFC_ENC_H_  */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_intr.c b/drivers/media/video/s5p-mfc/s5p_mfc_intr.c
new file mode 100644 (file)
index 0000000..8f2f8bf
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * drivers/media/video/samsung/mfc5/s5p_mfc_intr.c
+ *
+ * C file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains functions used to wait for command completion.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.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.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include "regs-mfc.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command)
+{
+       int ret;
+
+       ret = wait_event_interruptible_timeout(dev->queue,
+               (dev->int_cond && (dev->int_type == command
+               || dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+               msecs_to_jiffies(MFC_INT_TIMEOUT));
+       if (ret == 0) {
+               mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n",
+                                                       dev->int_type, command);
+               return 1;
+       } else if (ret == -ERESTARTSYS) {
+               mfc_err("Interrupted by a signal\n");
+               return 1;
+       }
+       mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n",
+                                                       dev->int_type, command);
+       if (dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)
+               return 1;
+       return 0;
+}
+
+void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev)
+{
+       dev->int_cond = 0;
+       dev->int_type = 0;
+       dev->int_err = 0;
+}
+
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
+                                   int command, int interrupt)
+{
+       int ret;
+
+       if (interrupt) {
+               ret = wait_event_interruptible_timeout(ctx->queue,
+                               (ctx->int_cond && (ctx->int_type == command
+                       || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+                                       msecs_to_jiffies(MFC_INT_TIMEOUT));
+       } else {
+               ret = wait_event_timeout(ctx->queue,
+                               (ctx->int_cond && (ctx->int_type == command
+                       || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+                                       msecs_to_jiffies(MFC_INT_TIMEOUT));
+       }
+       if (ret == 0) {
+               mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out\n",
+                                                       ctx->int_type, command);
+               return 1;
+       } else if (ret == -ERESTARTSYS) {
+               mfc_err("Interrupted by a signal\n");
+               return 1;
+       }
+       mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n",
+                                                       ctx->int_type, command);
+       if (ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)
+               return 1;
+       return 0;
+}
+
+void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx)
+{
+       ctx->int_cond = 0;
+       ctx->int_type = 0;
+       ctx->int_err = 0;
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_intr.h b/drivers/media/video/s5p-mfc/s5p_mfc_intr.h
new file mode 100644 (file)
index 0000000..122d773
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * drivers/media/video/samsung/mfc5/s5p_mfc_intr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * It contains waiting functions declarations.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics
+ * http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_INTR_H_
+#define S5P_MFC_INTR_H_
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx,
+                             int command, int interrupt);
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command);
+void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev);
+
+#endif /* S5P_MFC_INTR_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c
new file mode 100644 (file)
index 0000000..7b23916
--- /dev/null
@@ -0,0 +1,1397 @@
+/*
+ * drivers/media/video/samsung/mfc5/s5p_mfc_opr.c
+ *
+ * Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains hw related functions.
+ *
+ * Kamil Debski, Copyright (c) 2011 Samsung Electronics
+ * http://www.samsung.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.
+ */
+
+#include "regs-mfc.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_ctrl.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_opr.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_shm.h"
+#include <asm/cacheflush.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#define OFFSETA(x)             (((x) - dev->bank1) >> MFC_OFFSET_SHIFT)
+#define OFFSETB(x)             (((x) - dev->bank2) >> MFC_OFFSET_SHIFT)
+
+/* Allocate temporary buffers for decoding */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx)
+{
+       void *desc_virt;
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       ctx->desc_buf = vb2_dma_contig_memops.alloc(
+                       dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE);
+       if (IS_ERR_VALUE((int)ctx->desc_buf)) {
+               ctx->desc_buf = 0;
+               mfc_err("Allocating DESC buffer failed\n");
+               return -ENOMEM;
+       }
+       ctx->desc_phys = s5p_mfc_mem_cookie(
+                       dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf);
+       BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+       desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf);
+       if (desc_virt == NULL) {
+               vb2_dma_contig_memops.put(ctx->desc_buf);
+               ctx->desc_phys = 0;
+               ctx->desc_buf = 0;
+               mfc_err("Remapping DESC buffer failed\n");
+               return -ENOMEM;
+       }
+       memset(desc_virt, 0, DESC_BUF_SIZE);
+       wmb();
+       return 0;
+}
+
+/* Release temporary buffers for decoding */
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+       if (ctx->desc_phys) {
+               vb2_dma_contig_memops.put(ctx->desc_buf);
+               ctx->desc_phys = 0;
+               ctx->desc_buf = 0;
+       }
+}
+
+/* Allocate codec buffers */
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned int enc_ref_y_size = 0;
+       unsigned int enc_ref_c_size = 0;
+       unsigned int guard_width, guard_height;
+
+       if (ctx->type == MFCINST_DECODER) {
+               mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n",
+                         ctx->luma_size, ctx->chroma_size, ctx->mv_size);
+               mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count);
+       } else if (ctx->type == MFCINST_ENCODER) {
+               enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+                       * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+               enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
+
+               if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
+                       enc_ref_c_size = ALIGN(ctx->img_width,
+                                               S5P_FIMV_NV12MT_HALIGN)
+                                               * ALIGN(ctx->img_height >> 1,
+                                               S5P_FIMV_NV12MT_VALIGN);
+                       enc_ref_c_size = ALIGN(enc_ref_c_size,
+                                                       S5P_FIMV_NV12MT_SALIGN);
+               } else {
+                       guard_width = ALIGN(ctx->img_width + 16,
+                                                       S5P_FIMV_NV12MT_HALIGN);
+                       guard_height = ALIGN((ctx->img_height >> 1) + 4,
+                                                       S5P_FIMV_NV12MT_VALIGN);
+                       enc_ref_c_size = ALIGN(guard_width * guard_height,
+                                              S5P_FIMV_NV12MT_SALIGN);
+               }
+               mfc_debug(2, "recon luma size: %d chroma size: %d\n",
+                         enc_ref_y_size, enc_ref_c_size);
+       } else {
+               return -EINVAL;
+       }
+       /* Codecs have different memory requirements */
+       switch (ctx->codec_mode) {
+       case S5P_FIMV_CODEC_H264_DEC:
+               ctx->bank1_size =
+                   ALIGN(S5P_FIMV_DEC_NB_IP_SIZE +
+                                       S5P_FIMV_DEC_VERT_NB_MV_SIZE,
+                                       S5P_FIMV_DEC_BUF_ALIGN);
+               ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size;
+               break;
+       case S5P_FIMV_CODEC_MPEG4_DEC:
+               ctx->bank1_size =
+                   ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE +
+                                    S5P_FIMV_DEC_UPNB_MV_SIZE +
+                                    S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+                                    S5P_FIMV_DEC_STX_PARSER_SIZE +
+                                    S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE,
+                                    S5P_FIMV_DEC_BUF_ALIGN);
+               ctx->bank2_size = 0;
+               break;
+       case S5P_FIMV_CODEC_VC1RCV_DEC:
+       case S5P_FIMV_CODEC_VC1_DEC:
+               ctx->bank1_size =
+                   ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
+                            S5P_FIMV_DEC_UPNB_MV_SIZE +
+                            S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+                            S5P_FIMV_DEC_NB_DCAC_SIZE +
+                            3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE,
+                            S5P_FIMV_DEC_BUF_ALIGN);
+               ctx->bank2_size = 0;
+               break;
+       case S5P_FIMV_CODEC_MPEG2_DEC:
+               ctx->bank1_size = 0;
+               ctx->bank2_size = 0;
+               break;
+       case S5P_FIMV_CODEC_H263_DEC:
+               ctx->bank1_size =
+                   ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
+                            S5P_FIMV_DEC_UPNB_MV_SIZE +
+                            S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+                            S5P_FIMV_DEC_NB_DCAC_SIZE,
+                            S5P_FIMV_DEC_BUF_ALIGN);
+               ctx->bank2_size = 0;
+               break;
+       case S5P_FIMV_CODEC_H264_ENC:
+               ctx->bank1_size = (enc_ref_y_size * 2) +
+                                  S5P_FIMV_ENC_UPMV_SIZE +
+                                  S5P_FIMV_ENC_COLFLG_SIZE +
+                                  S5P_FIMV_ENC_INTRAMD_SIZE +
+                                  S5P_FIMV_ENC_NBORINFO_SIZE;
+               ctx->bank2_size = (enc_ref_y_size * 2) +
+                                  (enc_ref_c_size * 4) +
+                                  S5P_FIMV_ENC_INTRAPRED_SIZE;
+               break;
+       case S5P_FIMV_CODEC_MPEG4_ENC:
+               ctx->bank1_size = (enc_ref_y_size * 2) +
+                                  S5P_FIMV_ENC_UPMV_SIZE +
+                                  S5P_FIMV_ENC_COLFLG_SIZE +
+                                  S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               ctx->bank2_size = (enc_ref_y_size * 2) +
+                                  (enc_ref_c_size * 4);
+               break;
+       case S5P_FIMV_CODEC_H263_ENC:
+               ctx->bank1_size = (enc_ref_y_size * 2) +
+                                  S5P_FIMV_ENC_UPMV_SIZE +
+                                  S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               ctx->bank2_size = (enc_ref_y_size * 2) +
+                                  (enc_ref_c_size * 4);
+               break;
+       default:
+               break;
+       }
+       /* Allocate only if memory from bank 1 is necessary */
+       if (ctx->bank1_size > 0) {
+               ctx->bank1_buf = vb2_dma_contig_memops.alloc(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size);
+               if (IS_ERR(ctx->bank1_buf)) {
+                       ctx->bank1_buf = 0;
+                       printk(KERN_ERR
+                              "Buf alloc for decoding failed (port A)\n");
+                       return -ENOMEM;
+               }
+               ctx->bank1_phys = s5p_mfc_mem_cookie(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf);
+               BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+       }
+       /* Allocate only if memory from bank 2 is necessary */
+       if (ctx->bank2_size > 0) {
+               ctx->bank2_buf = vb2_dma_contig_memops.alloc(
+               dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size);
+               if (IS_ERR(ctx->bank2_buf)) {
+                       ctx->bank2_buf = 0;
+                       mfc_err("Buf alloc for decoding failed (port B)\n");
+                       return -ENOMEM;
+               }
+               ctx->bank2_phys = s5p_mfc_mem_cookie(
+               dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf);
+               BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1));
+       }
+       return 0;
+}
+
+/* Release buffers allocated for codec */
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+       if (ctx->bank1_buf) {
+               vb2_dma_contig_memops.put(ctx->bank1_buf);
+               ctx->bank1_buf = 0;
+               ctx->bank1_phys = 0;
+               ctx->bank1_size = 0;
+       }
+       if (ctx->bank2_buf) {
+               vb2_dma_contig_memops.put(ctx->bank2_buf);
+               ctx->bank2_buf = 0;
+               ctx->bank2_phys = 0;
+               ctx->bank2_size = 0;
+       }
+}
+
+/* Allocate memory for instance data buffer */
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+       void *context_virt;
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
+               ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+               ctx->ctx_size = MFC_H264_CTX_BUF_SIZE;
+       else
+               ctx->ctx_size = MFC_CTX_BUF_SIZE;
+       ctx->ctx_buf = vb2_dma_contig_memops.alloc(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size);
+       if (IS_ERR(ctx->ctx_buf)) {
+               mfc_err("Allocating context buffer failed\n");
+               ctx->ctx_phys = 0;
+               ctx->ctx_buf = 0;
+               return -ENOMEM;
+       }
+       ctx->ctx_phys = s5p_mfc_mem_cookie(
+               dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf);
+       BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+       ctx->ctx_ofs = OFFSETA(ctx->ctx_phys);
+       context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf);
+       if (context_virt == NULL) {
+               mfc_err("Remapping instance buffer failed\n");
+               vb2_dma_contig_memops.put(ctx->ctx_buf);
+               ctx->ctx_phys = 0;
+               ctx->ctx_buf = 0;
+               return -ENOMEM;
+       }
+       /* Zero content of the allocated memory */
+       memset(context_virt, 0, ctx->ctx_size);
+       wmb();
+       if (s5p_mfc_init_shm(ctx) < 0) {
+               vb2_dma_contig_memops.put(ctx->ctx_buf);
+               ctx->ctx_phys = 0;
+               ctx->ctx_buf = 0;
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+/* Release instance buffer */
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+       if (ctx->ctx_buf) {
+               vb2_dma_contig_memops.put(ctx->ctx_buf);
+               ctx->ctx_phys = 0;
+               ctx->ctx_buf = 0;
+       }
+       if (ctx->shm_alloc) {
+               vb2_dma_contig_memops.put(ctx->shm_alloc);
+               ctx->shm_alloc = 0;
+               ctx->shm = 0;
+       }
+}
+
+/* Set registers for decoding temporary buffers */
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR);
+       mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE);
+}
+
+/* Set registers for shared buffer */
+void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR);
+}
+
+/* Set registers for decoding stream buffer */
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr,
+                 unsigned int start_num_byte, unsigned int buf_size)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR);
+       mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE);
+       mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE);
+       s5p_mfc_write_shm(ctx, start_num_byte, START_BYTE_NUM);
+       return 0;
+}
+
+/* Set decoding frame buffer */
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx)
+{
+       unsigned int frame_size, i;
+       unsigned int frame_size_ch, frame_size_mv;
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned int dpb;
+       size_t buf_addr1, buf_addr2;
+       int buf_size1, buf_size2;
+
+       buf_addr1 = ctx->bank1_phys;
+       buf_size1 = ctx->bank1_size;
+       buf_addr2 = ctx->bank2_phys;
+       buf_size2 = ctx->bank2_size;
+       dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
+                                               ~S5P_FIMV_DPB_COUNT_MASK;
+       mfc_write(dev, ctx->total_dpb_count | dpb,
+                                               S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+       s5p_mfc_set_shared_buffer(ctx);
+       switch (ctx->codec_mode) {
+       case S5P_FIMV_CODEC_H264_DEC:
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                               S5P_FIMV_H264_VERT_NB_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR);
+               buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE;
+               break;
+       case S5P_FIMV_CODEC_MPEG4_DEC:
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR);
+               buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR);
+               buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR);
+               buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               break;
+       case S5P_FIMV_CODEC_H263_DEC:
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR);
+               buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR);
+               buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+               break;
+       case S5P_FIMV_CODEC_VC1_DEC:
+       case S5P_FIMV_CODEC_VC1RCV_DEC:
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR);
+               buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR);
+               buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR);
+               buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR);
+               buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR);
+               buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR);
+               buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+               break;
+       case S5P_FIMV_CODEC_MPEG2_DEC:
+               break;
+       default:
+               mfc_err("Unknown codec for decoding (%x)\n",
+                       ctx->codec_mode);
+               return -EINVAL;
+               break;
+       }
+       frame_size = ctx->luma_size;
+       frame_size_ch = ctx->chroma_size;
+       frame_size_mv = ctx->mv_size;
+       mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch,
+                                                               frame_size_mv);
+       for (i = 0; i < ctx->total_dpb_count; i++) {
+               /* Bank2 */
+               mfc_debug(2, "Luma %d: %x\n", i,
+                                       ctx->dst_bufs[i].cookie.raw.luma);
+               mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma),
+                                               S5P_FIMV_DEC_LUMA_ADR + i * 4);
+               mfc_debug(2, "\tChroma %d: %x\n", i,
+                                       ctx->dst_bufs[i].cookie.raw.chroma);
+               mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma),
+                                              S5P_FIMV_DEC_CHROMA_ADR + i * 4);
+               if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
+                       mfc_debug(2, "\tBuf2: %x, size: %d\n",
+                                                       buf_addr2, buf_size2);
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                                               S5P_FIMV_H264_MV_ADR + i * 4);
+                       buf_addr2 += frame_size_mv;
+                       buf_size2 -= frame_size_mv;
+               }
+       }
+       mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1);
+       mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n",
+                       buf_size1,  buf_size2, ctx->total_dpb_count);
+       if (buf_size1 < 0 || buf_size2 < 0) {
+               mfc_debug(2, "Not enough memory has been allocated\n");
+               return -ENOMEM;
+       }
+       s5p_mfc_write_shm(ctx, frame_size, ALLOC_LUMA_DPB_SIZE);
+       s5p_mfc_write_shm(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE);
+       if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC)
+               s5p_mfc_write_shm(ctx, frame_size_mv, ALLOC_MV_SIZE);
+       mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK)
+                                       << S5P_FIMV_CH_SHIFT) | (ctx->inst_no),
+                                               S5P_FIMV_SI_CH0_INST_ID);
+       return 0;
+}
+
+/* Set registers for encoding stream buffer */
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long addr, unsigned int size)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR);
+       mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE);
+       return 0;
+}
+
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long y_addr, unsigned long c_addr)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR);
+       mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR);
+}
+
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long *y_addr, unsigned long *c_addr)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR)
+                                                       << MFC_OFFSET_SHIFT);
+       *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR)
+                                                       << MFC_OFFSET_SHIFT);
+}
+
+/* Set encoding ref & codec buffer */
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       size_t buf_addr1, buf_addr2;
+       size_t buf_size1, buf_size2;
+       unsigned int enc_ref_y_size, enc_ref_c_size;
+       unsigned int guard_width, guard_height;
+       int i;
+
+       buf_addr1 = ctx->bank1_phys;
+       buf_size1 = ctx->bank1_size;
+       buf_addr2 = ctx->bank2_phys;
+       buf_size2 = ctx->bank2_size;
+       enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+               * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+       enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
+       if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
+               enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+                       * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN);
+               enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN);
+       } else {
+               guard_width = ALIGN(ctx->img_width + 16,
+                                               S5P_FIMV_NV12MT_HALIGN);
+               guard_height = ALIGN((ctx->img_height >> 1) + 4,
+                                               S5P_FIMV_NV12MT_VALIGN);
+               enc_ref_c_size = ALIGN(guard_width * guard_height,
+                                      S5P_FIMV_NV12MT_SALIGN);
+       }
+       mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2);
+       switch (ctx->codec_mode) {
+       case S5P_FIMV_CODEC_H264_ENC:
+               for (i = 0; i < 2; i++) {
+                       mfc_write(dev, OFFSETA(buf_addr1),
+                               S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+                       buf_addr1 += enc_ref_y_size;
+                       buf_size1 -= enc_ref_y_size;
+
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_y_size;
+                       buf_size2 -= enc_ref_y_size;
+               }
+               for (i = 0; i < 4; i++) {
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_c_size;
+                       buf_size2 -= enc_ref_c_size;
+               }
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR);
+               buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                       S5P_FIMV_H264_COZERO_FLAG_ADR);
+               buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                       S5P_FIMV_H264_UP_INTRA_MD_ADR);
+               buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE;
+               mfc_write(dev, OFFSETB(buf_addr2),
+                                       S5P_FIMV_H264_UP_INTRA_PRED_ADR);
+               buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE;
+               buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                       S5P_FIMV_H264_NBOR_INFO_ADR);
+               buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE;
+               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+                       buf_size1, buf_size2);
+               break;
+       case S5P_FIMV_CODEC_MPEG4_ENC:
+               for (i = 0; i < 2; i++) {
+                       mfc_write(dev, OFFSETA(buf_addr1),
+                               S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+                       buf_addr1 += enc_ref_y_size;
+                       buf_size1 -= enc_ref_y_size;
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_y_size;
+                       buf_size2 -= enc_ref_y_size;
+               }
+               for (i = 0; i < 4; i++) {
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_c_size;
+                       buf_size2 -= enc_ref_c_size;
+               }
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR);
+               buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                               S5P_FIMV_MPEG4_COZERO_FLAG_ADR);
+               buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1),
+                                               S5P_FIMV_MPEG4_ACDC_COEF_ADR);
+               buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+                       buf_size1, buf_size2);
+               break;
+       case S5P_FIMV_CODEC_H263_ENC:
+               for (i = 0; i < 2; i++) {
+                       mfc_write(dev, OFFSETA(buf_addr1),
+                               S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+                       buf_addr1 += enc_ref_y_size;
+                       buf_size1 -= enc_ref_y_size;
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_y_size;
+                       buf_size2 -= enc_ref_y_size;
+               }
+               for (i = 0; i < 4; i++) {
+                       mfc_write(dev, OFFSETB(buf_addr2),
+                               S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+                       buf_addr2 += enc_ref_c_size;
+                       buf_size2 -= enc_ref_c_size;
+               }
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR);
+               buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+               mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR);
+               buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
+               mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+                       buf_size1, buf_size2);
+               break;
+       default:
+               mfc_err("Unknown codec set for encoding: %d\n",
+                       ctx->codec_mode);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       unsigned int reg;
+       unsigned int shm;
+
+       /* width */
+       mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX);
+       /* height */
+       mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX);
+       /* pictype : enable, IDR period */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       reg |= (1 << 18);
+       reg &= ~(0xFFFF);
+       reg |= p->gop_size;
+       mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON);
+       /* multi-slice control */
+       /* multi-slice MB number or bit size */
+       mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL);
+       if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+               mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB);
+       } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
+               mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT);
+       } else {
+               mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB);
+               mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT);
+       }
+       /* cyclic intra refresh */
+       mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL);
+       /* memory structure cur. frame */
+       if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+               mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR);
+       else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+               mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR);
+       /* padding control & value */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL);
+       if (p->pad) {
+               /** enable */
+               reg |= (1 << 31);
+               /** cr value */
+               reg &= ~(0xFF << 16);
+               reg |= (p->pad_cr << 16);
+               /** cb value */
+               reg &= ~(0xFF << 8);
+               reg |= (p->pad_cb << 8);
+               /** y value */
+               reg &= ~(0xFF);
+               reg |= (p->pad_luma);
+       } else {
+               /** disable & all value clear */
+               reg = 0;
+       }
+       mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL);
+       /* rate control config. */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+       /** frame-level rate control */
+       reg &= ~(0x1 << 9);
+       reg |= (p->rc_frame << 9);
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+       /* bit rate */
+       if (p->rc_frame)
+               mfc_write(dev, p->rc_bitrate,
+                       S5P_FIMV_ENC_RC_BIT_RATE);
+       else
+               mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE);
+       /* reaction coefficient */
+       if (p->rc_frame)
+               mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA);
+       shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+       /* seq header ctrl */
+       shm &= ~(0x1 << 3);
+       shm |= (p->seq_hdr_mode << 3);
+       /* frame skip mode */
+       shm &= ~(0x3 << 1);
+       shm |= (p->frame_skip_mode << 1);
+       s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+       /* fixed target bit */
+       s5p_mfc_write_shm(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG);
+       return 0;
+}
+
+static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
+       unsigned int reg;
+       unsigned int shm;
+
+       s5p_mfc_set_enc_params(ctx);
+       /* pictype : number of B */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       /* num_b_frame - 0 ~ 2 */
+       reg &= ~(0x3 << 16);
+       reg |= (p->num_b_frame << 16);
+       mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       /* profile & level */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE);
+       /* level */
+       reg &= ~(0xFF << 8);
+       reg |= (p_264->level << 8);
+       /* profile - 0 ~ 2 */
+       reg &= ~(0x3F);
+       reg |= p_264->profile;
+       mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE);
+       /* interlace  */
+       mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT);
+       /* height */
+       if (p->interlace)
+               mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX);
+       /* loopfilter ctrl */
+       mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL);
+       /* loopfilter alpha offset */
+       if (p_264->loop_filter_alpha < 0) {
+               reg = 0x10;
+               reg |= (0xFF - p_264->loop_filter_alpha) + 1;
+       } else {
+               reg = 0x00;
+               reg |= (p_264->loop_filter_alpha & 0xF);
+       }
+       mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF);
+       /* loopfilter beta offset */
+       if (p_264->loop_filter_beta < 0) {
+               reg = 0x10;
+               reg |= (0xFF - p_264->loop_filter_beta) + 1;
+       } else {
+               reg = 0x00;
+               reg |= (p_264->loop_filter_beta & 0xF);
+       }
+       mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF);
+       /* entropy coding mode */
+       if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
+               mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE);
+       else
+               mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE);
+       /* number of ref. picture */
+       reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF);
+       /* num of ref. pictures of P */
+       reg &= ~(0x3 << 5);
+       reg |= (p_264->num_ref_pic_4p << 5);
+       /* max number of ref. pictures */
+       reg &= ~(0x1F);
+       reg |= p_264->max_ref_pic;
+       mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF);
+       /* 8x8 transform enable */
+       mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG);
+       /* rate control config. */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+       /* macroblock level rate control */
+       reg &= ~(0x1 << 8);
+       reg |= (p_264->rc_mb << 8);
+       /* frame QP */
+       reg &= ~(0x3F);
+       reg |= p_264->rc_frame_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+       /* frame rate */
+       if (p->rc_frame && p->rc_framerate_denom)
+               mfc_write(dev, p->rc_framerate_num * 1000
+                       / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+       else
+               mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+       /* max & min value of QP */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+       /* max QP */
+       reg &= ~(0x3F << 8);
+       reg |= (p_264->rc_max_qp << 8);
+       /* min QP */
+       reg &= ~(0x3F);
+       reg |= p_264->rc_min_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+       /* macroblock adaptive scaling features */
+       if (p_264->rc_mb) {
+               reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL);
+               /* dark region */
+               reg &= ~(0x1 << 3);
+               reg |= (p_264->rc_mb_dark << 3);
+               /* smooth region */
+               reg &= ~(0x1 << 2);
+               reg |= (p_264->rc_mb_smooth << 2);
+               /* static region */
+               reg &= ~(0x1 << 1);
+               reg |= (p_264->rc_mb_static << 1);
+               /* high activity region */
+               reg &= ~(0x1);
+               reg |= p_264->rc_mb_activity;
+               mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL);
+       }
+       if (!p->rc_frame &&
+           !p_264->rc_mb) {
+               shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+               shm &= ~(0xFFF);
+               shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6);
+               shm |= (p_264->rc_p_frame_qp & 0x3F);
+               s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+       }
+       /* extended encoder ctrl */
+       shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+       /* AR VUI control */
+       shm &= ~(0x1 << 15);
+       shm |= (p_264->vui_sar << 1);
+       s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+       if (p_264->vui_sar) {
+               /* aspect ration IDC */
+               shm = s5p_mfc_read_shm(ctx, SAMPLE_ASPECT_RATIO_IDC);
+               shm &= ~(0xFF);
+               shm |= p_264->vui_sar_idc;
+               s5p_mfc_write_shm(ctx, shm, SAMPLE_ASPECT_RATIO_IDC);
+               if (p_264->vui_sar_idc == 0xFF) {
+                       /* sample  AR info */
+                       shm = s5p_mfc_read_shm(ctx, EXTENDED_SAR);
+                       shm &= ~(0xFFFFFFFF);
+                       shm |= p_264->vui_ext_sar_width << 16;
+                       shm |= p_264->vui_ext_sar_height;
+                       s5p_mfc_write_shm(ctx, shm, EXTENDED_SAR);
+               }
+       }
+       /* intra picture period for H.264 */
+       shm = s5p_mfc_read_shm(ctx, H264_I_PERIOD);
+       /* control */
+       shm &= ~(0x1 << 16);
+       shm |= (p_264->open_gop << 16);
+       /* value */
+       if (p_264->open_gop) {
+               shm &= ~(0xFFFF);
+               shm |= p_264->open_gop_size;
+       }
+       s5p_mfc_write_shm(ctx, shm, H264_I_PERIOD);
+       /* extended encoder ctrl */
+       shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+       /* vbv buffer size */
+       if (p->frame_skip_mode ==
+                       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+               shm &= ~(0xFFFF << 16);
+               shm |= (p_264->cpb_size << 16);
+       }
+       s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+       return 0;
+}
+
+static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
+       unsigned int reg;
+       unsigned int shm;
+       unsigned int framerate;
+
+       s5p_mfc_set_enc_params(ctx);
+       /* pictype : number of B */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       /* num_b_frame - 0 ~ 2 */
+       reg &= ~(0x3 << 16);
+       reg |= (p->num_b_frame << 16);
+       mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+       /* profile & level */
+       reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE);
+       /* level */
+       reg &= ~(0xFF << 8);
+       reg |= (p_mpeg4->level << 8);
+       /* profile - 0 ~ 2 */
+       reg &= ~(0x3F);
+       reg |= p_mpeg4->profile;
+       mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE);
+       /* quarter_pixel */
+       mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL);
+       /* qp */
+       if (!p->rc_frame) {
+               shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+               shm &= ~(0xFFF);
+               shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6);
+               shm |= (p_mpeg4->rc_p_frame_qp & 0x3F);
+               s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+       }
+       /* frame rate */
+       if (p->rc_frame) {
+               if (p->rc_framerate_denom > 0) {
+                       framerate = p->rc_framerate_num * 1000 /
+                                               p->rc_framerate_denom;
+                       mfc_write(dev, framerate,
+                               S5P_FIMV_ENC_RC_FRAME_RATE);
+                       shm = s5p_mfc_read_shm(ctx, RC_VOP_TIMING);
+                       shm &= ~(0xFFFFFFFF);
+                       shm |= (1 << 31);
+                       shm |= ((p->rc_framerate_num & 0x7FFF) << 16);
+                       shm |= (p->rc_framerate_denom & 0xFFFF);
+                       s5p_mfc_write_shm(ctx, shm, RC_VOP_TIMING);
+               }
+       } else {
+               mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+       }
+       /* rate control config. */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+       /* frame QP */
+       reg &= ~(0x3F);
+       reg |= p_mpeg4->rc_frame_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+       /* max & min value of QP */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+       /* max QP */
+       reg &= ~(0x3F << 8);
+       reg |= (p_mpeg4->rc_max_qp << 8);
+       /* min QP */
+       reg &= ~(0x3F);
+       reg |= p_mpeg4->rc_min_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+       /* extended encoder ctrl */
+       shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+       /* vbv buffer size */
+       if (p->frame_skip_mode ==
+                       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+               shm &= ~(0xFFFF << 16);
+               shm |= (p->vbv_size << 16);
+       }
+       s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+       return 0;
+}
+
+static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_enc_params *p = &ctx->enc_params;
+       struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4;
+       unsigned int reg;
+       unsigned int shm;
+
+       s5p_mfc_set_enc_params(ctx);
+       /* qp */
+       if (!p->rc_frame) {
+               shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP);
+               shm &= ~(0xFFF);
+               shm |= (p_h263->rc_p_frame_qp & 0x3F);
+               s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP);
+       }
+       /* frame rate */
+       if (p->rc_frame && p->rc_framerate_denom)
+               mfc_write(dev, p->rc_framerate_num * 1000
+                       / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE);
+       else
+               mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE);
+       /* rate control config. */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG);
+       /* frame QP */
+       reg &= ~(0x3F);
+       reg |= p_h263->rc_frame_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG);
+       /* max & min value of QP */
+       reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND);
+       /* max QP */
+       reg &= ~(0x3F << 8);
+       reg |= (p_h263->rc_max_qp << 8);
+       /* min QP */
+       reg &= ~(0x3F);
+       reg |= p_h263->rc_min_qp;
+       mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND);
+       /* extended encoder ctrl */
+       shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL);
+       /* vbv buffer size */
+       if (p->frame_skip_mode ==
+                       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+               shm &= ~(0xFFFF << 16);
+               shm |= (p->vbv_size << 16);
+       }
+       s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL);
+       return 0;
+}
+
+/* Initialize decoding */
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       s5p_mfc_set_shared_buffer(ctx);
+       /* Setup loop filter, for decoding this is only valid for MPEG4 */
+       if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC)
+               mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL);
+       else
+               mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL);
+       mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) <<
+               S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable <<
+               S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay &
+               S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT),
+               S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+       mfc_write(dev,
+       ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT)
+                               | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+       return 0;
+}
+
+static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned int dpb;
+
+       if (flush)
+               dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (
+                       S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
+       else
+               dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) &
+                       ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT);
+       mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+}
+
+/* Decode a single frame */
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx,
+                                       enum s5p_mfc_decode_arg last_frame)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF);
+       s5p_mfc_set_shared_buffer(ctx);
+       s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag);
+       /* Issue different commands to instance basing on whether it
+        * is the last frame or not. */
+       switch (last_frame) {
+       case MFC_DEC_FRAME:
+               mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) <<
+               S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+               break;
+       case MFC_DEC_LAST_FRAME:
+               mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) <<
+               S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+               break;
+       case MFC_DEC_RES_CHANGE:
+               mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC &
+               S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no),
+               S5P_FIMV_SI_CH0_INST_ID);
+               break;
+       }
+       mfc_debug(2, "Decoding a usual frame\n");
+       return 0;
+}
+
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+               s5p_mfc_set_enc_params_h264(ctx);
+       else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC)
+               s5p_mfc_set_enc_params_mpeg4(ctx);
+       else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC)
+               s5p_mfc_set_enc_params_h263(ctx);
+       else {
+               mfc_err("Unknown codec for encoding (%x)\n",
+                       ctx->codec_mode);
+               return -EINVAL;
+       }
+       s5p_mfc_set_shared_buffer(ctx);
+       mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) |
+               (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+       return 0;
+}
+
+/* Encode a single frame */
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       /* memory structure cur. frame */
+       if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+               mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR);
+       else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+               mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR);
+       s5p_mfc_set_shared_buffer(ctx);
+       mfc_write(dev, (S5P_FIMV_CH_FRAME_START << 16 & 0x70000) |
+               (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+       return 0;
+}
+
+static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
+{
+       unsigned long flags;
+       int new_ctx;
+       int cnt;
+
+       spin_lock_irqsave(&dev->condlock, flags);
+       new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
+       cnt = 0;
+       while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
+               new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
+               if (++cnt > MFC_NUM_CONTEXTS) {
+                       /* No contexts to run */
+                       spin_unlock_irqrestore(&dev->condlock, flags);
+                       return -EAGAIN;
+               }
+       }
+       spin_unlock_irqrestore(&dev->condlock, flags);
+       return new_ctx;
+}
+
+static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+
+       s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0);
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE);
+}
+
+static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       struct s5p_mfc_buf *temp_vb;
+       unsigned long flags;
+       unsigned int index;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       /* Frames are being decoded */
+       if (list_empty(&ctx->src_queue)) {
+               mfc_debug(2, "No src buffers\n");
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               return -EAGAIN;
+       }
+       /* Get the next source buffer */
+       temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       temp_vb->used = 1;
+       s5p_mfc_set_dec_stream_buffer(ctx,
+               vb2_dma_contig_plane_paddr(temp_vb->b, 0), ctx->consumed_stream,
+                                       temp_vb->b->v4l2_planes[0].bytesused);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       index = temp_vb->b->v4l2_buf.index;
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
+               last_frame = MFC_DEC_LAST_FRAME;
+               mfc_debug(2, "Setting ctx->state to FINISHING\n");
+               ctx->state = MFCINST_FINISHING;
+       }
+       s5p_mfc_decode_one_frame(ctx, last_frame);
+       return 0;
+}
+
+static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *dst_mb;
+       struct s5p_mfc_buf *src_mb;
+       unsigned long src_y_addr, src_c_addr, dst_addr;
+       unsigned int dst_size;
+
+       spin_lock_irqsave(&dev->irqlock, flags);
+       if (list_empty(&ctx->src_queue)) {
+               mfc_debug(2, "no src buffers\n");
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               return -EAGAIN;
+       }
+       if (list_empty(&ctx->dst_queue)) {
+               mfc_debug(2, "no dst buffers\n");
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               return -EAGAIN;
+       }
+       src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       src_mb->used = 1;
+       src_y_addr = vb2_dma_contig_plane_paddr(src_mb->b, 0);
+       src_c_addr = vb2_dma_contig_plane_paddr(src_mb->b, 1);
+       s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+       dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+       dst_mb->used = 1;
+       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_size = vb2_plane_size(dst_mb->b, 0);
+       s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       s5p_mfc_encode_one_frame(ctx);
+       return 0;
+}
+
+static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *temp_vb;
+
+       /* Initializing decoding - parsing header */
+       spin_lock_irqsave(&dev->irqlock, flags);
+       mfc_debug(2, "Preparing to init decoding\n");
+       temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       s5p_mfc_set_dec_desc_buffer(ctx);
+       mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
+       s5p_mfc_set_dec_stream_buffer(ctx,
+                               vb2_dma_contig_plane_paddr(temp_vb->b, 0),
+                               0, temp_vb->b->v4l2_planes[0].bytesused);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       s5p_mfc_init_decode(ctx);
+}
+
+static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *dst_mb;
+       unsigned long dst_addr;
+       unsigned int dst_size;
+
+       s5p_mfc_set_enc_ref_buffer(ctx);
+       spin_lock_irqsave(&dev->irqlock, flags);
+       dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+       dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0);
+       dst_size = vb2_plane_size(dst_mb->b, 0);
+       s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       s5p_mfc_init_encode(ctx);
+}
+
+static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       unsigned long flags;
+       struct s5p_mfc_buf *temp_vb;
+       int ret;
+
+       /*
+        * Header was parsed now starting processing
+        * First set the output frame buffers
+        */
+       if (ctx->capture_state != QUEUE_BUFS_MMAPED) {
+               mfc_err("It seems that not all destionation buffers were "
+                       "mmaped\nMFC requires that all destination are mmaped "
+                       "before starting processing\n");
+               return -EAGAIN;
+       }
+       spin_lock_irqsave(&dev->irqlock, flags);
+       if (list_empty(&ctx->src_queue)) {
+               mfc_err("Header has been deallocated in the middle of"
+                       " initialization\n");
+               spin_unlock_irqrestore(&dev->irqlock, flags);
+               return -EIO;
+       }
+       temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+       mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused);
+       s5p_mfc_set_dec_stream_buffer(ctx,
+                               vb2_dma_contig_plane_paddr(temp_vb->b, 0),
+                               0, temp_vb->b->v4l2_planes[0].bytesused);
+       spin_unlock_irqrestore(&dev->irqlock, flags);
+       dev->curr_ctx = ctx->num;
+       s5p_mfc_clean_ctx_int_flags(ctx);
+       ret = s5p_mfc_set_dec_frame_buffer(ctx);
+       if (ret) {
+               mfc_err("Failed to alloc frame mem\n");
+               ctx->state = MFCINST_ERROR;
+       }
+       return ret;
+}
+
+/* Try running an operation on hardware */
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev)
+{
+       struct s5p_mfc_ctx *ctx;
+       int new_ctx;
+       unsigned int ret = 0;
+
+       if (test_bit(0, &dev->enter_suspend)) {
+               mfc_debug(1, "Entering suspend so do not schedule any jobs\n");
+               return;
+       }
+       /* Check whether hardware is not running */
+       if (test_and_set_bit(0, &dev->hw_lock) != 0) {
+               /* This is perfectly ok, the scheduled ctx should wait */
+               mfc_debug(1, "Couldn't lock HW\n");
+               return;
+       }
+       /* Choose the context to run */
+       new_ctx = s5p_mfc_get_new_ctx(dev);
+       if (new_ctx < 0) {
+               /* No contexts to run */
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0) {
+                       mfc_err("Failed to unlock hardware\n");
+                       return;
+               }
+               mfc_debug(1, "No ctx is scheduled to be run\n");
+               return;
+       }
+       ctx = dev->ctx[new_ctx];
+       /* Got context to run in ctx */
+       /*
+        * Last frame has already been sent to MFC.
+        * Now obtaining frames from MFC buffer
+        */
+       s5p_mfc_clock_on();
+       if (ctx->type == MFCINST_DECODER) {
+               s5p_mfc_set_dec_desc_buffer(ctx);
+               switch (ctx->state) {
+               case MFCINST_FINISHING:
+                       s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME);
+                       break;
+               case MFCINST_RUNNING:
+                       ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
+                       break;
+               case MFCINST_INIT:
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       ret = s5p_mfc_open_inst_cmd(ctx);
+                       break;
+               case MFCINST_RETURN_INST:
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       ret = s5p_mfc_close_inst_cmd(ctx);
+                       break;
+               case MFCINST_GOT_INST:
+                       s5p_mfc_run_init_dec(ctx);
+                       break;
+               case MFCINST_HEAD_PARSED:
+                       ret = s5p_mfc_run_init_dec_buffers(ctx);
+                       mfc_debug(1, "head parsed\n");
+                       break;
+               case MFCINST_RES_CHANGE_INIT:
+                       s5p_mfc_run_res_change(ctx);
+                       break;
+               case MFCINST_RES_CHANGE_FLUSH:
+                       s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
+                       break;
+               case MFCINST_RES_CHANGE_END:
+                       mfc_debug(2, "Finished remaining frames after resolution change\n");
+                       ctx->capture_state = QUEUE_FREE;
+                       mfc_debug(2, "Will re-init the codec\n");
+                       s5p_mfc_run_init_dec(ctx);
+                       break;
+               default:
+                       ret = -EAGAIN;
+               }
+       } else if (ctx->type == MFCINST_ENCODER) {
+               switch (ctx->state) {
+               case MFCINST_FINISHING:
+               case MFCINST_RUNNING:
+                       ret = s5p_mfc_run_enc_frame(ctx);
+                       break;
+               case MFCINST_INIT:
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       ret = s5p_mfc_open_inst_cmd(ctx);
+                       break;
+               case MFCINST_RETURN_INST:
+                       s5p_mfc_clean_ctx_int_flags(ctx);
+                       ret = s5p_mfc_close_inst_cmd(ctx);
+                       break;
+               case MFCINST_GOT_INST:
+                       s5p_mfc_run_init_enc(ctx);
+                       break;
+               default:
+                       ret = -EAGAIN;
+               }
+       } else {
+               mfc_err("Invalid context type: %d\n", ctx->type);
+               ret = -EAGAIN;
+       }
+
+       if (ret) {
+               /* Free hardware lock */
+               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+                       mfc_err("Failed to unlock hardware\n");
+
+               /* This is in deed imporant, as no operation has been
+                * scheduled, reduce the clock count as no one will
+                * ever do this, because no interrupt related to this try_run
+                * will ever come from hardware. */
+               s5p_mfc_clock_off();
+       }
+}
+
+
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq)
+{
+       struct s5p_mfc_buf *b;
+       int i;
+
+       while (!list_empty(lh)) {
+               b = list_entry(lh->next, struct s5p_mfc_buf, list);
+               for (i = 0; i < b->b->num_planes; i++)
+                       vb2_set_plane_payload(b->b, i, 0);
+               vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR);
+               list_del(&b->list);
+       }
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.h b/drivers/media/video/s5p-mfc/s5p_mfc_opr.h
new file mode 100644 (file)
index 0000000..db83836
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * drivers/media/video/samsung/mfc5/s5p_mfc_opr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * Contains declarations of hw related functions.
+ *
+ * Kamil Debski, Copyright (C) 2011 Samsung Electronics
+ * http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_OPR_H_
+#define S5P_MFC_OPR_H_
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx);
+
+/* Decoding functions */
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr,
+                                                 unsigned int start_num_byte,
+                                                 unsigned int buf_size);
+
+/* Encoding functions */
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long y_addr, unsigned long c_addr);
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long addr, unsigned int size);
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+               unsigned long *y_addr, unsigned long *c_addr);
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx);
+
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx,
+                                       enum s5p_mfc_decode_arg last_frame);
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx);
+
+/* Memory allocation */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx);
+
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev);
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
+
+#define s5p_mfc_get_dspl_y_adr()       (readl(dev->regs_base + \
+                                       S5P_FIMV_SI_DISPLAY_Y_ADR) << \
+                                       MFC_OFFSET_SHIFT)
+#define s5p_mfc_get_dec_y_adr()                (readl(dev->regs_base + \
+                                       S5P_FIMV_SI_DISPLAY_Y_ADR) << \
+                                       MFC_OFFSET_SHIFT)
+#define s5p_mfc_get_dspl_status()      readl(dev->regs_base + \
+                                               S5P_FIMV_SI_DISPLAY_STATUS)
+#define s5p_mfc_get_frame_type()       (readl(dev->regs_base + \
+                                               S5P_FIMV_DECODE_FRAME_TYPE) \
+                                       & S5P_FIMV_DECODE_FRAME_MASK)
+#define s5p_mfc_get_consumed_stream()  readl(dev->regs_base + \
+                                               S5P_FIMV_SI_CONSUMED_BYTES)
+#define s5p_mfc_get_int_reason()       (readl(dev->regs_base + \
+                                       S5P_FIMV_RISC2HOST_CMD) & \
+                                       S5P_FIMV_RISC2HOST_CMD_MASK)
+#define s5p_mfc_get_int_err()          readl(dev->regs_base + \
+                                               S5P_FIMV_RISC2HOST_ARG2)
+#define s5p_mfc_err_dec(x)             (((x) & S5P_FIMV_ERR_DEC_MASK) >> \
+                                                       S5P_FIMV_ERR_DEC_SHIFT)
+#define s5p_mfc_err_dspl(x)            (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \
+                                                       S5P_FIMV_ERR_DSPL_SHIFT)
+#define s5p_mfc_get_img_width()                readl(dev->regs_base + \
+                                               S5P_FIMV_SI_HRESOL)
+#define s5p_mfc_get_img_height()       readl(dev->regs_base + \
+                                               S5P_FIMV_SI_VRESOL)
+#define s5p_mfc_get_dpb_count()                readl(dev->regs_base + \
+                                               S5P_FIMV_SI_BUF_NUMBER)
+#define s5p_mfc_get_inst_no()          readl(dev->regs_base + \
+                                               S5P_FIMV_RISC2HOST_ARG1)
+#define s5p_mfc_get_enc_strm_size()    readl(dev->regs_base + \
+                                               S5P_FIMV_ENC_SI_STRM_SIZE)
+#define s5p_mfc_get_enc_slice_type()   readl(dev->regs_base + \
+                                               S5P_FIMV_ENC_SI_SLICE_TYPE)
+
+#endif /* S5P_MFC_OPR_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
new file mode 100644 (file)
index 0000000..f6a3035
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_pm.h"
+
+#define MFC_CLKNAME            "sclk_mfc"
+#define MFC_GATE_CLK_NAME      "mfc"
+
+#define CLK_DEBUG
+
+static struct s5p_mfc_pm *pm;
+static struct s5p_mfc_dev *p_dev;
+
+#ifdef CLK_DEBUG
+atomic_t clk_ref;
+#endif
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
+{
+       int ret = 0;
+
+       pm = &dev->pm;
+       p_dev = dev;
+       pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME);
+       if (IS_ERR(pm->clock_gate)) {
+               mfc_err("Failed to get clock-gating control\n");
+               ret = -ENOENT;
+               goto err_g_ip_clk;
+       }
+       pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME);
+       if (IS_ERR(pm->clock)) {
+               mfc_err("Failed to get MFC clock\n");
+               ret = -ENOENT;
+               goto err_g_ip_clk_2;
+       }
+       atomic_set(&pm->power, 0);
+#ifdef CONFIG_PM_RUNTIME
+       pm->device = &dev->plat_dev->dev;
+       pm_runtime_enable(pm->device);
+#endif
+#ifdef CLK_DEBUG
+       atomic_set(&clk_ref, 0);
+#endif
+       return 0;
+err_g_ip_clk_2:
+       clk_put(pm->clock_gate);
+err_g_ip_clk:
+       return ret;
+}
+
+void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
+{
+       clk_put(pm->clock_gate);
+       clk_put(pm->clock);
+#ifdef CONFIG_PM_RUNTIME
+       pm_runtime_disable(pm->device);
+#endif
+}
+
+int s5p_mfc_clock_on(void)
+{
+       int ret;
+#ifdef CLK_DEBUG
+       atomic_inc(&clk_ref);
+       mfc_debug(3, "+ %d", atomic_read(&clk_ref));
+#endif
+       ret = clk_enable(pm->clock_gate);
+       return ret;
+}
+
+void s5p_mfc_clock_off(void)
+{
+#ifdef CLK_DEBUG
+       atomic_dec(&clk_ref);
+       mfc_debug(3, "- %d", atomic_read(&clk_ref));
+#endif
+       clk_disable(pm->clock_gate);
+}
+
+int s5p_mfc_power_on(void)
+{
+#ifdef CONFIG_PM_RUNTIME
+       return pm_runtime_get_sync(pm->device);
+#else
+       atomic_set(&pm->power, 1);
+       return 0;
+#endif
+}
+
+int s5p_mfc_power_off(void)
+{
+#ifdef CONFIG_PM_RUNTIME
+       return pm_runtime_put_sync(pm->device);
+#else
+       atomic_set(&pm->power, 0);
+       return 0;
+#endif
+}
+
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.h b/drivers/media/video/s5p-mfc/s5p_mfc_pm.h
new file mode 100644 (file)
index 0000000..5107914
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_pm.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_PM_H_
+#define S5P_MFC_PM_H_
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev);
+void s5p_mfc_final_pm(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_clock_on(void);
+void s5p_mfc_clock_off(void);
+int s5p_mfc_power_on(void);
+int s5p_mfc_power_off(void);
+
+#endif /* S5P_MFC_PM_H_ */
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_shm.c b/drivers/media/video/s5p-mfc/s5p_mfc_shm.c
new file mode 100644 (file)
index 0000000..91fdbac
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_shm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifdef CONFIG_ARCH_EXYNOS4
+#include <linux/dma-mapping.h>
+#endif
+#include <linux/io.h>
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+
+int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx)
+{
+       struct s5p_mfc_dev *dev = ctx->dev;
+       void *shm_alloc_ctx = dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
+
+       ctx->shm_alloc = vb2_dma_contig_memops.alloc(shm_alloc_ctx,
+                                                       SHARED_BUF_SIZE);
+       if (IS_ERR(ctx->shm_alloc)) {
+               mfc_err("failed to allocate shared memory\n");
+               return PTR_ERR(ctx->shm_alloc);
+       }
+       /* shm_ofs only keeps the offset from base (port a) */
+       ctx->shm_ofs = s5p_mfc_mem_cookie(shm_alloc_ctx, ctx->shm_alloc)
+                                                               - dev->bank1;
+       BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1));
+       ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc);
+       if (!ctx->shm) {
+               vb2_dma_contig_memops.put(ctx->shm_alloc);
+               ctx->shm_ofs = 0;
+               ctx->shm_alloc = NULL;
+               mfc_err("failed to virt addr of shared memory\n");
+               return -ENOMEM;
+       }
+       memset((void *)ctx->shm, 0, SHARED_BUF_SIZE);
+       wmb();
+       return 0;
+}
+
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_shm.h b/drivers/media/video/s5p-mfc/s5p_mfc_shm.h
new file mode 100644 (file)
index 0000000..764eac6
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * linux/drivers/media/video/s5p-mfc/s5p_mfc_shm.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.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.
+ */
+
+#ifndef S5P_MFC_SHM_H_
+#define S5P_MFC_SHM_H_
+
+enum MFC_SHM_OFS
+{
+       EXTENEDED_DECODE_STATUS = 0x00, /* D */
+       SET_FRAME_TAG           = 0x04, /* D */
+       GET_FRAME_TAG_TOP       = 0x08, /* D */
+       GET_FRAME_TAG_BOT       = 0x0C, /* D */
+       PIC_TIME_TOP            = 0x10, /* D */
+       PIC_TIME_BOT            = 0x14, /* D */
+       START_BYTE_NUM          = 0x18, /* D */
+
+       CROP_INFO_H             = 0x20, /* D */
+       CROP_INFO_V             = 0x24, /* D */
+       EXT_ENC_CONTROL         = 0x28, /* E */
+       ENC_PARAM_CHANGE        = 0x2C, /* E */
+       RC_VOP_TIMING           = 0x30, /* E, MPEG4 */
+       HEC_PERIOD              = 0x34, /* E, MPEG4 */
+       METADATA_ENABLE         = 0x38, /* C */
+       METADATA_STATUS         = 0x3C, /* C */
+       METADATA_DISPLAY_INDEX  = 0x40, /* C */
+       EXT_METADATA_START_ADDR = 0x44, /* C */
+       PUT_EXTRADATA           = 0x48, /* C */
+       EXTRADATA_ADDR          = 0x4C, /* C */
+
+       ALLOC_LUMA_DPB_SIZE     = 0x64, /* D */
+       ALLOC_CHROMA_DPB_SIZE   = 0x68, /* D */
+       ALLOC_MV_SIZE           = 0x6C, /* D */
+       P_B_FRAME_QP            = 0x70, /* E */
+       SAMPLE_ASPECT_RATIO_IDC = 0x74, /* E, H.264, depend on
+                               ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
+       EXTENDED_SAR            = 0x78, /* E, H.264, depned on
+                               ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
+       DISP_PIC_PROFILE        = 0x7C, /* D */
+       FLUSH_CMD_TYPE          = 0x80, /* C */
+       FLUSH_CMD_INBUF1        = 0x84, /* C */
+       FLUSH_CMD_INBUF2        = 0x88, /* C */
+       FLUSH_CMD_OUTBUF        = 0x8C, /* E */
+       NEW_RC_BIT_RATE         = 0x90, /* E, format as RC_BIT_RATE(0xC5A8)
+                       depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */
+       NEW_RC_FRAME_RATE       = 0x94, /* E, format as RC_FRAME_RATE(0xD0D0)
+                       depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */
+       NEW_I_PERIOD            = 0x98, /* E, format as I_FRM_CTRL(0xC504)
+                       depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */
+       H264_I_PERIOD           = 0x9C, /* E, H.264, open GOP */
+       RC_CONTROL_CONFIG       = 0xA0, /* E */
+       BATCH_INPUT_ADDR        = 0xA4, /* E */
+       BATCH_OUTPUT_ADDR       = 0xA8, /* E */
+       BATCH_OUTPUT_SIZE       = 0xAC, /* E */
+       MIN_LUMA_DPB_SIZE       = 0xB0, /* D */
+       DEVICE_FORMAT_ID        = 0xB4, /* C */
+       H264_POC_TYPE           = 0xB8, /* D */
+       MIN_CHROMA_DPB_SIZE     = 0xBC, /* D */
+       DISP_PIC_FRAME_TYPE     = 0xC0, /* D */
+       FREE_LUMA_DPB           = 0xC4, /* D, VC1 MPEG4 */
+       ASPECT_RATIO_INFO       = 0xC8, /* D, MPEG4 */
+       EXTENDED_PAR            = 0xCC, /* D, MPEG4 */
+       DBG_HISTORY_INPUT0      = 0xD0, /* C */
+       DBG_HISTORY_INPUT1      = 0xD4, /* C */
+       DBG_HISTORY_OUTPUT      = 0xD8, /* C */
+       HIERARCHICAL_P_QP       = 0xE0, /* E, H.264 */
+};
+
+int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx);
+
+#define s5p_mfc_write_shm(ctx, x, ofs)         \
+       do {                                    \
+               writel(x, (ctx->shm + ofs));    \
+               wmb();                          \
+       } while (0)
+
+static inline u32 s5p_mfc_read_shm(struct s5p_mfc_ctx *ctx, unsigned int ofs)
+{
+       rmb();
+       return readl(ctx->shm + ofs);
+}
+
+#endif /* S5P_MFC_SHM_H_ */
diff --git a/drivers/media/video/s5p-tv/Kconfig b/drivers/media/video/s5p-tv/Kconfig
new file mode 100644 (file)
index 0000000..9c37dee
--- /dev/null
@@ -0,0 +1,76 @@
+# drivers/media/video/s5p-tv/Kconfig
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+#      http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+config VIDEO_SAMSUNG_S5P_TV
+       bool "Samsung TV driver for S5P platform (experimental)"
+       depends on PLAT_S5P
+       depends on EXPERIMENTAL
+       default n
+       ---help---
+         Say Y here to enable selecting the TV output devices for
+         Samsung S5P platform.
+
+if VIDEO_SAMSUNG_S5P_TV
+
+config VIDEO_SAMSUNG_S5P_HDMI
+       tristate "Samsung HDMI Driver"
+       depends on VIDEO_V4L2
+       depends on VIDEO_SAMSUNG_S5P_TV
+       select VIDEO_SAMSUNG_S5P_HDMIPHY
+       help
+         Say Y here if you want support for the HDMI output
+         interface in S5P Samsung SoC. The driver can be compiled
+         as module. It is an auxiliary driver, that exposes a V4L2
+         subdev for use by other drivers. This driver requires
+         hdmiphy driver to work correctly.
+
+config VIDEO_SAMSUNG_S5P_HDMI_DEBUG
+       bool "Enable debug for HDMI Driver"
+       depends on VIDEO_SAMSUNG_S5P_HDMI
+       default n
+       help
+         Enables debugging for HDMI driver.
+
+config VIDEO_SAMSUNG_S5P_HDMIPHY
+       tristate "Samsung HDMIPHY Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+       depends on VIDEO_SAMSUNG_S5P_TV
+       help
+         Say Y here if you want support for the physical HDMI
+         interface in S5P Samsung SoC. The driver can be compiled
+         as module. It is an I2C driver, that exposes a V4L2
+         subdev for use by other drivers.
+
+config VIDEO_SAMSUNG_S5P_SDO
+       tristate "Samsung Analog TV Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on VIDEO_SAMSUNG_S5P_TV
+       help
+         Say Y here if you want support for the analog TV output
+         interface in S5P Samsung SoC. The driver can be compiled
+         as module. It is an auxiliary driver, that exposes a V4L2
+         subdev for use by other drivers. This driver requires
+         hdmiphy driver to work correctly.
+
+config VIDEO_SAMSUNG_S5P_MIXER
+       tristate "Samsung Mixer and Video Processor Driver"
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on VIDEO_SAMSUNG_S5P_TV
+       select VIDEOBUF2_DMA_CONTIG
+       help
+         Say Y here if you want support for the Mixer in Samsung S5P SoCs.
+         This device produce image data to one of output interfaces.
+
+config VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+       bool "Enable debug for Mixer Driver"
+       depends on VIDEO_SAMSUNG_S5P_MIXER
+       default n
+       help
+         Enables debugging for Mixer driver.
+
+endif # VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/media/video/s5p-tv/Makefile b/drivers/media/video/s5p-tv/Makefile
new file mode 100644 (file)
index 0000000..37e4c17
--- /dev/null
@@ -0,0 +1,17 @@
+# drivers/media/video/samsung/tvout/Makefile
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+#      http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMIPHY) += s5p-hdmiphy.o
+s5p-hdmiphy-y += hdmiphy_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_HDMI) += s5p-hdmi.o
+s5p-hdmi-y += hdmi_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_SDO) += s5p-sdo.o
+s5p-sdo-y += sdo_drv.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MIXER) += s5p-mixer.o
+s5p-mixer-y += mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o mixer_vp_layer.o
+
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c
new file mode 100644 (file)
index 0000000..06d6663
--- /dev/null
@@ -0,0 +1,1042 @@
+/*
+ * Samsung HDMI interface driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_HDMI_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/bug.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+
+#include "regs-hdmi.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI");
+MODULE_LICENSE("GPL");
+
+/* default preset configured on probe */
+#define HDMI_DEFAULT_PRESET V4L2_DV_1080P60
+
+struct hdmi_resources {
+       struct clk *hdmi;
+       struct clk *sclk_hdmi;
+       struct clk *sclk_pixel;
+       struct clk *sclk_hdmiphy;
+       struct clk *hdmiphy;
+       struct regulator_bulk_data *regul_bulk;
+       int regul_count;
+};
+
+struct hdmi_device {
+       /** base address of HDMI registers */
+       void __iomem *regs;
+       /** HDMI interrupt */
+       unsigned int irq;
+       /** pointer to device parent */
+       struct device *dev;
+       /** subdev generated by HDMI device */
+       struct v4l2_subdev sd;
+       /** V4L2 device structure */
+       struct v4l2_device v4l2_dev;
+       /** subdev of HDMIPHY interface */
+       struct v4l2_subdev *phy_sd;
+       /** configuration of current graphic mode */
+       const struct hdmi_preset_conf *cur_conf;
+       /** current preset */
+       u32 cur_preset;
+       /** other resources */
+       struct hdmi_resources res;
+};
+
+struct hdmi_driver_data {
+       int hdmiphy_bus;
+};
+
+struct hdmi_tg_regs {
+       u8 cmd;
+       u8 h_fsz_l;
+       u8 h_fsz_h;
+       u8 hact_st_l;
+       u8 hact_st_h;
+       u8 hact_sz_l;
+       u8 hact_sz_h;
+       u8 v_fsz_l;
+       u8 v_fsz_h;
+       u8 vsync_l;
+       u8 vsync_h;
+       u8 vsync2_l;
+       u8 vsync2_h;
+       u8 vact_st_l;
+       u8 vact_st_h;
+       u8 vact_sz_l;
+       u8 vact_sz_h;
+       u8 field_chg_l;
+       u8 field_chg_h;
+       u8 vact_st2_l;
+       u8 vact_st2_h;
+       u8 vsync_top_hdmi_l;
+       u8 vsync_top_hdmi_h;
+       u8 vsync_bot_hdmi_l;
+       u8 vsync_bot_hdmi_h;
+       u8 field_top_hdmi_l;
+       u8 field_top_hdmi_h;
+       u8 field_bot_hdmi_l;
+       u8 field_bot_hdmi_h;
+};
+
+struct hdmi_core_regs {
+       u8 h_blank[2];
+       u8 v_blank[3];
+       u8 h_v_line[3];
+       u8 vsync_pol[1];
+       u8 int_pro_mode[1];
+       u8 v_blank_f[3];
+       u8 h_sync_gen[3];
+       u8 v_sync_gen1[3];
+       u8 v_sync_gen2[3];
+       u8 v_sync_gen3[3];
+};
+
+struct hdmi_preset_conf {
+       struct hdmi_core_regs core;
+       struct hdmi_tg_regs tg;
+       struct v4l2_mbus_framefmt mbus_fmt;
+};
+
+/* I2C module and id for HDMIPHY */
+static struct i2c_board_info hdmiphy_info = {
+       I2C_BOARD_INFO("hdmiphy", 0x38),
+};
+
+static struct hdmi_driver_data hdmi_driver_data[] = {
+       { .hdmiphy_bus = 3 },
+       { .hdmiphy_bus = 8 },
+};
+
+static struct platform_device_id hdmi_driver_types[] = {
+       {
+               .name           = "s5pv210-hdmi",
+               .driver_data    = (unsigned long)&hdmi_driver_data[0],
+       }, {
+               .name           = "exynos4-hdmi",
+               .driver_data    = (unsigned long)&hdmi_driver_data[1],
+       }, {
+               /* end node */
+       }
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops;
+
+static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct hdmi_device, sd);
+}
+
+static inline
+void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value)
+{
+       writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask)
+{
+       u32 old = readl(hdev->regs + reg_id);
+       value = (value & mask) | (old & ~mask);
+       writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
+{
+       writeb(value, hdev->regs + reg_id);
+}
+
+static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
+{
+       return readl(hdev->regs + reg_id);
+}
+
+static irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
+{
+       struct hdmi_device *hdev = dev_data;
+       u32 intc_flag;
+
+       (void)irq;
+       intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG);
+       /* clearing flags for HPD plug/unplug */
+       if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
+               printk(KERN_INFO "unplugged\n");
+               hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+                       HDMI_INTC_FLAG_HPD_UNPLUG);
+       }
+       if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
+               printk(KERN_INFO "plugged\n");
+               hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+                       HDMI_INTC_FLAG_HPD_PLUG);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void hdmi_reg_init(struct hdmi_device *hdev)
+{
+       /* enable HPD interrupts */
+       hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
+               HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+       /* choose HDMI mode */
+       hdmi_write_mask(hdev, HDMI_MODE_SEL,
+               HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
+       /* disable bluescreen */
+       hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+       /* choose bluescreen (fecal) color */
+       hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
+       hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
+       hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
+       /* enable AVI packet every vsync, fixes purple line problem */
+       hdmi_writeb(hdev, HDMI_AVI_CON, 0x02);
+       /* force YUV444, look to CEA-861-D, table 7 for more detail */
+       hdmi_writeb(hdev, HDMI_AVI_BYTE(0), 2 << 5);
+       hdmi_write_mask(hdev, HDMI_CON_1, 2, 3 << 5);
+}
+
+static void hdmi_timing_apply(struct hdmi_device *hdev,
+       const struct hdmi_preset_conf *conf)
+{
+       const struct hdmi_core_regs *core = &conf->core;
+       const struct hdmi_tg_regs *tg = &conf->tg;
+
+       /* setting core registers */
+       hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
+       hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]);
+       hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]);
+       hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]);
+       hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]);
+       hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
+       hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
+       hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
+       hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
+       hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+       /* Timing generator registers */
+       hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
+       hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
+       hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
+       hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
+       hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
+       hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
+       hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
+       hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
+       hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
+       hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+}
+
+static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
+{
+       struct device *dev = hdmi_dev->dev;
+       const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
+       struct v4l2_dv_preset preset;
+       int ret;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       /* reset hdmiphy */
+       hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+       mdelay(10);
+       hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT,  0, HDMI_PHY_SW_RSTOUT);
+       mdelay(10);
+
+       /* configure presets */
+       preset.preset = hdmi_dev->cur_preset;
+       ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+       if (ret) {
+               dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+               return ret;
+       }
+
+       /* resetting HDMI core */
+       hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT,  0, HDMI_CORE_SW_RSTOUT);
+       mdelay(10);
+       hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
+       mdelay(10);
+
+       hdmi_reg_init(hdmi_dev);
+
+       /* setting core registers */
+       hdmi_timing_apply(hdmi_dev, conf);
+
+       return 0;
+}
+
+static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
+{
+#define DUMPREG(reg_id) \
+       dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
+               readl(hdev->regs + reg_id))
+
+       dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_INTC_FLAG);
+       DUMPREG(HDMI_INTC_CON);
+       DUMPREG(HDMI_HPD_STATUS);
+       DUMPREG(HDMI_PHY_RSTOUT);
+       DUMPREG(HDMI_PHY_VPLL);
+       DUMPREG(HDMI_PHY_CMU);
+       DUMPREG(HDMI_CORE_RSTOUT);
+
+       dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_CON_0);
+       DUMPREG(HDMI_CON_1);
+       DUMPREG(HDMI_CON_2);
+       DUMPREG(HDMI_SYS_STATUS);
+       DUMPREG(HDMI_PHY_STATUS);
+       DUMPREG(HDMI_STATUS_EN);
+       DUMPREG(HDMI_HPD);
+       DUMPREG(HDMI_MODE_SEL);
+       DUMPREG(HDMI_HPD_GEN);
+       DUMPREG(HDMI_DC_CONTROL);
+       DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+
+       dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_H_BLANK_0);
+       DUMPREG(HDMI_H_BLANK_1);
+       DUMPREG(HDMI_V_BLANK_0);
+       DUMPREG(HDMI_V_BLANK_1);
+       DUMPREG(HDMI_V_BLANK_2);
+       DUMPREG(HDMI_H_V_LINE_0);
+       DUMPREG(HDMI_H_V_LINE_1);
+       DUMPREG(HDMI_H_V_LINE_2);
+       DUMPREG(HDMI_VSYNC_POL);
+       DUMPREG(HDMI_INT_PRO_MODE);
+       DUMPREG(HDMI_V_BLANK_F_0);
+       DUMPREG(HDMI_V_BLANK_F_1);
+       DUMPREG(HDMI_V_BLANK_F_2);
+       DUMPREG(HDMI_H_SYNC_GEN_0);
+       DUMPREG(HDMI_H_SYNC_GEN_1);
+       DUMPREG(HDMI_H_SYNC_GEN_2);
+       DUMPREG(HDMI_V_SYNC_GEN_1_0);
+       DUMPREG(HDMI_V_SYNC_GEN_1_1);
+       DUMPREG(HDMI_V_SYNC_GEN_1_2);
+       DUMPREG(HDMI_V_SYNC_GEN_2_0);
+       DUMPREG(HDMI_V_SYNC_GEN_2_1);
+       DUMPREG(HDMI_V_SYNC_GEN_2_2);
+       DUMPREG(HDMI_V_SYNC_GEN_3_0);
+       DUMPREG(HDMI_V_SYNC_GEN_3_1);
+       DUMPREG(HDMI_V_SYNC_GEN_3_2);
+
+       dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
+       DUMPREG(HDMI_TG_CMD);
+       DUMPREG(HDMI_TG_H_FSZ_L);
+       DUMPREG(HDMI_TG_H_FSZ_H);
+       DUMPREG(HDMI_TG_HACT_ST_L);
+       DUMPREG(HDMI_TG_HACT_ST_H);
+       DUMPREG(HDMI_TG_HACT_SZ_L);
+       DUMPREG(HDMI_TG_HACT_SZ_H);
+       DUMPREG(HDMI_TG_V_FSZ_L);
+       DUMPREG(HDMI_TG_V_FSZ_H);
+       DUMPREG(HDMI_TG_VSYNC_L);
+       DUMPREG(HDMI_TG_VSYNC_H);
+       DUMPREG(HDMI_TG_VSYNC2_L);
+       DUMPREG(HDMI_TG_VSYNC2_H);
+       DUMPREG(HDMI_TG_VACT_ST_L);
+       DUMPREG(HDMI_TG_VACT_ST_H);
+       DUMPREG(HDMI_TG_VACT_SZ_L);
+       DUMPREG(HDMI_TG_VACT_SZ_H);
+       DUMPREG(HDMI_TG_FIELD_CHG_L);
+       DUMPREG(HDMI_TG_FIELD_CHG_H);
+       DUMPREG(HDMI_TG_VACT_ST2_L);
+       DUMPREG(HDMI_TG_VACT_ST2_H);
+       DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+       DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+       DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+       DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+       DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+       DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+       DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+       DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+#undef DUMPREG
+}
+
+static const struct hdmi_preset_conf hdmi_conf_480p = {
+       .core = {
+               .h_blank = {0x8a, 0x00},
+               .v_blank = {0x0d, 0x6a, 0x01},
+               .h_v_line = {0x0d, 0xa2, 0x35},
+               .vsync_pol = {0x01},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00},
+               .h_sync_gen = {0x0e, 0x30, 0x11},
+               .v_sync_gen1 = {0x0f, 0x90, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x5a, 0x03, /* h_fsz */
+               0x8a, 0x00, 0xd0, 0x02, /* hact */
+               0x0d, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0xe0, 0x01, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 720,
+               .height = 480,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+       .core = {
+               .h_blank = {0x72, 0x01},
+               .v_blank = {0xee, 0xf2, 0x00},
+               .h_v_line = {0xee, 0x22, 0x67},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+               .h_sync_gen = {0x6c, 0x50, 0x02},
+               .v_sync_gen1 = {0x0a, 0x50, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x72, 0x06, /* h_fsz */
+               0x72, 0x01, 0x00, 0x05, /* hact */
+               0xee, 0x02, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x1e, 0x00, 0xd0, 0x02, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 1280,
+               .height = 720,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+       .core = {
+               .h_blank = {0xd0, 0x02},
+               .v_blank = {0x65, 0x6c, 0x01},
+               .h_v_line = {0x65, 0x04, 0xa5},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+               .h_sync_gen = {0x0e, 0xea, 0x08},
+               .v_sync_gen1 = {0x09, 0x40, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x49, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+       .core = {
+               .h_blank = {0x18, 0x01},
+               .v_blank = {0x65, 0x6c, 0x01},
+               .h_v_line = {0x65, 0x84, 0x89},
+               .vsync_pol = {0x00},
+               .int_pro_mode = {0x00},
+               .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+               .h_sync_gen = {0x56, 0x08, 0x02},
+               .v_sync_gen1 = {0x09, 0x40, 0x00},
+               /* other don't care */
+       },
+       .tg = {
+               0x00, /* cmd */
+               0x98, 0x08, /* h_fsz */
+               0x18, 0x01, 0x80, 0x07, /* hact */
+               0x65, 0x04, /* v_fsz */
+               0x01, 0x00, 0x33, 0x02, /* vsync */
+               0x2d, 0x00, 0x38, 0x04, /* vact */
+               0x33, 0x02, /* field_chg */
+               0x48, 0x02, /* vact_st2 */
+               0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+               0x01, 0x00, 0x33, 0x02, /* field top/bot */
+       },
+       .mbus_fmt = {
+               .width = 1920,
+               .height = 1080,
+               .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+               .field = V4L2_FIELD_NONE,
+       },
+};
+
+static const struct {
+       u32 preset;
+       const struct hdmi_preset_conf *conf;
+} hdmi_conf[] = {
+       { V4L2_DV_480P59_94, &hdmi_conf_480p },
+       { V4L2_DV_720P59_94, &hdmi_conf_720p60 },
+       { V4L2_DV_1080P50, &hdmi_conf_1080p50 },
+       { V4L2_DV_1080P30, &hdmi_conf_1080p60 },
+       { V4L2_DV_1080P60, &hdmi_conf_1080p60 },
+};
+
+static const struct hdmi_preset_conf *hdmi_preset2conf(u32 preset)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(hdmi_conf); ++i)
+               if (hdmi_conf[i].preset == preset)
+                       return  hdmi_conf[i].conf;
+       return NULL;
+}
+
+static int hdmi_streamon(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       struct hdmi_resources *res = &hdev->res;
+       int ret, tries;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
+       if (ret)
+               return ret;
+
+       /* waiting for HDMIPHY's PLL to get to steady state */
+       for (tries = 100; tries; --tries) {
+               u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
+               if (val & HDMI_PHY_STATUS_READY)
+                       break;
+               mdelay(1);
+       }
+       /* steady state not achieved */
+       if (tries == 0) {
+               dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
+               v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+               hdmi_dumpregs(hdev, "s_stream");
+               return -EIO;
+       }
+
+       /* hdmiphy clock is used for HDMI in streaming mode */
+       clk_disable(res->sclk_hdmi);
+       clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy);
+       clk_enable(res->sclk_hdmi);
+
+       /* enable HDMI and timing generator */
+       hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
+       hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_EN);
+       hdmi_dumpregs(hdev, "streamon");
+       return 0;
+}
+
+static int hdmi_streamoff(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       struct hdmi_resources *res = &hdev->res;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
+       hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_EN);
+
+       /* pixel(vpll) clock is used for HDMI in config mode */
+       clk_disable(res->sclk_hdmi);
+       clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+       clk_enable(res->sclk_hdmi);
+
+       v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+
+       hdmi_dumpregs(hdev, "streamoff");
+       return 0;
+}
+
+static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+
+       dev_dbg(dev, "%s(%d)\n", __func__, enable);
+       if (enable)
+               return hdmi_streamon(hdev);
+       return hdmi_streamoff(hdev);
+}
+
+static void hdmi_resource_poweron(struct hdmi_resources *res)
+{
+       /* turn HDMI power on */
+       regulator_bulk_enable(res->regul_count, res->regul_bulk);
+       /* power-on hdmi physical interface */
+       clk_enable(res->hdmiphy);
+       /* use VPP as parent clock; HDMIPHY is not working yet */
+       clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+       /* turn clocks on */
+       clk_enable(res->sclk_hdmi);
+}
+
+static void hdmi_resource_poweroff(struct hdmi_resources *res)
+{
+       /* turn clocks off */
+       clk_disable(res->sclk_hdmi);
+       /* power-off hdmiphy */
+       clk_disable(res->hdmiphy);
+       /* turn HDMI power off */
+       regulator_bulk_disable(res->regul_count, res->regul_bulk);
+}
+
+static int hdmi_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       int ret;
+
+       if (on)
+               ret = pm_runtime_get_sync(hdev->dev);
+       else
+               ret = pm_runtime_put_sync(hdev->dev);
+       /* only values < 0 indicate errors */
+       return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
+       struct v4l2_dv_preset *preset)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+       const struct hdmi_preset_conf *conf;
+
+       conf = hdmi_preset2conf(preset->preset);
+       if (conf == NULL) {
+               dev_err(dev, "preset (%u) not supported\n", preset->preset);
+               return -EINVAL;
+       }
+       hdev->cur_conf = conf;
+       hdev->cur_preset = preset->preset;
+       return 0;
+}
+
+static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
+       struct v4l2_dv_preset *preset)
+{
+       memset(preset, 0, sizeof(*preset));
+       preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
+       return 0;
+}
+
+static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
+         struct v4l2_mbus_framefmt *fmt)
+{
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       struct device *dev = hdev->dev;
+
+       dev_dbg(dev, "%s\n", __func__);
+       if (!hdev->cur_conf)
+               return -EINVAL;
+       *fmt = hdev->cur_conf->mbus_fmt;
+       return 0;
+}
+
+static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
+       struct v4l2_dv_enum_preset *preset)
+{
+       if (preset->index >= ARRAY_SIZE(hdmi_conf))
+               return -EINVAL;
+       return v4l_fill_dv_preset_info(hdmi_conf[preset->index].preset, preset);
+}
+
+static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
+       .s_power = hdmi_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
+       .s_dv_preset = hdmi_s_dv_preset,
+       .g_dv_preset = hdmi_g_dv_preset,
+       .enum_dv_presets = hdmi_enum_dv_presets,
+       .g_mbus_fmt = hdmi_g_mbus_fmt,
+       .s_stream = hdmi_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops = {
+       .core = &hdmi_sd_core_ops,
+       .video = &hdmi_sd_video_ops,
+};
+
+static int hdmi_runtime_suspend(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+
+       dev_dbg(dev, "%s\n", __func__);
+       hdmi_resource_poweroff(&hdev->res);
+       return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+       int ret = 0;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       hdmi_resource_poweron(&hdev->res);
+
+       ret = hdmi_conf_apply(hdev);
+       if (ret)
+               goto fail;
+
+       dev_dbg(dev, "poweron succeed\n");
+
+       return 0;
+
+fail:
+       hdmi_resource_poweroff(&hdev->res);
+       dev_err(dev, "poweron failed\n");
+
+       return ret;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+       .runtime_suspend = hdmi_runtime_suspend,
+       .runtime_resume  = hdmi_runtime_resume,
+};
+
+static void hdmi_resources_cleanup(struct hdmi_device *hdev)
+{
+       struct hdmi_resources *res = &hdev->res;
+
+       dev_dbg(hdev->dev, "HDMI resource cleanup\n");
+       /* put clocks, power */
+       if (res->regul_count)
+               regulator_bulk_free(res->regul_count, res->regul_bulk);
+       /* kfree is NULL-safe */
+       kfree(res->regul_bulk);
+       if (!IS_ERR_OR_NULL(res->hdmiphy))
+               clk_put(res->hdmiphy);
+       if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
+               clk_put(res->sclk_hdmiphy);
+       if (!IS_ERR_OR_NULL(res->sclk_pixel))
+               clk_put(res->sclk_pixel);
+       if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+               clk_put(res->sclk_hdmi);
+       if (!IS_ERR_OR_NULL(res->hdmi))
+               clk_put(res->hdmi);
+       memset(res, 0, sizeof *res);
+}
+
+static int hdmi_resources_init(struct hdmi_device *hdev)
+{
+       struct device *dev = hdev->dev;
+       struct hdmi_resources *res = &hdev->res;
+       static char *supply[] = {
+               "hdmi-en",
+               "vdd",
+               "vdd_osc",
+               "vdd_pll",
+       };
+       int i, ret;
+
+       dev_dbg(dev, "HDMI resource init\n");
+
+       memset(res, 0, sizeof *res);
+       /* get clocks, power */
+
+       res->hdmi = clk_get(dev, "hdmi");
+       if (IS_ERR_OR_NULL(res->hdmi)) {
+               dev_err(dev, "failed to get clock 'hdmi'\n");
+               goto fail;
+       }
+       res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+       if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+               dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
+               goto fail;
+       }
+       res->sclk_pixel = clk_get(dev, "sclk_pixel");
+       if (IS_ERR_OR_NULL(res->sclk_pixel)) {
+               dev_err(dev, "failed to get clock 'sclk_pixel'\n");
+               goto fail;
+       }
+       res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
+       if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
+               dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
+               goto fail;
+       }
+       res->hdmiphy = clk_get(dev, "hdmiphy");
+       if (IS_ERR_OR_NULL(res->hdmiphy)) {
+               dev_err(dev, "failed to get clock 'hdmiphy'\n");
+               goto fail;
+       }
+       res->regul_bulk = kzalloc(ARRAY_SIZE(supply) *
+               sizeof res->regul_bulk[0], GFP_KERNEL);
+       if (!res->regul_bulk) {
+               dev_err(dev, "failed to get memory for regulators\n");
+               goto fail;
+       }
+       for (i = 0; i < ARRAY_SIZE(supply); ++i) {
+               res->regul_bulk[i].supply = supply[i];
+               res->regul_bulk[i].consumer = NULL;
+       }
+
+       ret = regulator_bulk_get(dev, ARRAY_SIZE(supply), res->regul_bulk);
+       if (ret) {
+               dev_err(dev, "failed to get regulators\n");
+               goto fail;
+       }
+       res->regul_count = ARRAY_SIZE(supply);
+
+       return 0;
+fail:
+       dev_err(dev, "HDMI resource init - failed\n");
+       hdmi_resources_cleanup(hdev);
+       return -ENODEV;
+}
+
+static int __devinit hdmi_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct i2c_adapter *phy_adapter;
+       struct v4l2_subdev *sd;
+       struct hdmi_device *hdmi_dev = NULL;
+       struct hdmi_driver_data *drv_data;
+       int ret;
+
+       dev_dbg(dev, "probe start\n");
+
+       hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL);
+       if (!hdmi_dev) {
+               dev_err(dev, "out of memory\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       hdmi_dev->dev = dev;
+
+       ret = hdmi_resources_init(hdmi_dev);
+       if (ret)
+               goto fail_hdev;
+
+       /* mapping HDMI registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail_init;
+       }
+
+       hdmi_dev->regs = ioremap(res->start, resource_size(res));
+       if (hdmi_dev->regs == NULL) {
+               dev_err(dev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail_hdev;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(dev, "get interrupt resource failed.\n");
+               ret = -ENXIO;
+               goto fail_regs;
+       }
+
+       ret = request_irq(res->start, hdmi_irq_handler, 0, "hdmi", hdmi_dev);
+       if (ret) {
+               dev_err(dev, "request interrupt failed.\n");
+               goto fail_regs;
+       }
+       hdmi_dev->irq = res->start;
+
+       /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
+       strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev),
+               sizeof(hdmi_dev->v4l2_dev.name));
+       /* passing NULL owner prevents driver from erasing drvdata */
+       ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
+       if (ret) {
+               dev_err(dev, "could not register v4l2 device.\n");
+               goto fail_irq;
+       }
+
+       drv_data = (struct hdmi_driver_data *)
+               platform_get_device_id(pdev)->driver_data;
+       phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus);
+       if (phy_adapter == NULL) {
+               dev_err(dev, "adapter request failed\n");
+               ret = -ENXIO;
+               goto fail_vdev;
+       }
+
+       hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
+               phy_adapter, &hdmiphy_info, NULL);
+       /* on failure or not adapter is no longer useful */
+       i2c_put_adapter(phy_adapter);
+       if (hdmi_dev->phy_sd == NULL) {
+               dev_err(dev, "missing subdev for hdmiphy\n");
+               ret = -ENODEV;
+               goto fail_vdev;
+       }
+
+       clk_enable(hdmi_dev->res.hdmi);
+
+       pm_runtime_enable(dev);
+
+       sd = &hdmi_dev->sd;
+       v4l2_subdev_init(sd, &hdmi_sd_ops);
+       sd->owner = THIS_MODULE;
+
+       strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
+       hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
+       /* FIXME: missing fail preset is not supported */
+       hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset);
+
+       /* storing subdev for call that have only access to struct device */
+       dev_set_drvdata(dev, sd);
+
+       dev_info(dev, "probe sucessful\n");
+
+       return 0;
+
+fail_vdev:
+       v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+
+fail_irq:
+       free_irq(hdmi_dev->irq, hdmi_dev);
+
+fail_regs:
+       iounmap(hdmi_dev->regs);
+
+fail_init:
+       hdmi_resources_cleanup(hdmi_dev);
+
+fail_hdev:
+       kfree(hdmi_dev);
+
+fail:
+       dev_err(dev, "probe failed\n");
+       return ret;
+}
+
+static int __devexit hdmi_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd);
+
+       pm_runtime_disable(dev);
+       clk_disable(hdmi_dev->res.hdmi);
+       v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+       disable_irq(hdmi_dev->irq);
+       free_irq(hdmi_dev->irq, hdmi_dev);
+       iounmap(hdmi_dev->regs);
+       hdmi_resources_cleanup(hdmi_dev);
+       kfree(hdmi_dev);
+       dev_info(dev, "remove sucessful\n");
+
+       return 0;
+}
+
+static struct platform_driver hdmi_driver __refdata = {
+       .probe = hdmi_probe,
+       .remove = __devexit_p(hdmi_remove),
+       .id_table = hdmi_driver_types,
+       .driver = {
+               .name = "s5p-hdmi",
+               .owner = THIS_MODULE,
+               .pm = &hdmi_pm_ops,
+       }
+};
+
+/* D R I V E R   I N I T I A L I Z A T I O N */
+
+static int __init hdmi_init(void)
+{
+       int ret;
+       static const char banner[] __initdata = KERN_INFO \
+               "Samsung HDMI output driver, "
+               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+       printk(banner);
+
+       ret = platform_driver_register(&hdmi_driver);
+       if (ret)
+               printk(KERN_ERR "HDMI platform driver register failed\n");
+
+       return ret;
+}
+module_init(hdmi_init);
+
+static void __exit hdmi_exit(void)
+{
+       platform_driver_unregister(&hdmi_driver);
+}
+module_exit(hdmi_exit);
+
+
diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/video/s5p-tv/hdmiphy_drv.c
new file mode 100644 (file)
index 0000000..6693f4a
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Samsung HDMI Physical interface driver
+ *
+ * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
+ * Author: Tomasz Stanislawski <t.stanislaws@samsung.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.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+
+#include <media/v4l2-subdev.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI Physical interface driver");
+MODULE_LICENSE("GPL");
+
+struct hdmiphy_conf {
+       u32 preset;
+       const u8 *data;
+};
+
+static const u8 hdmiphy_conf27[32] = {
+       0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+       0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
+       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+       0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 hdmiphy_conf74_175[32] = {
+       0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
+       0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
+       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+       0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
+};
+
+static const u8 hdmiphy_conf74_25[32] = {
+       0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
+       0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
+       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xe0,
+       0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
+};
+
+static const u8 hdmiphy_conf148_5[32] = {
+       0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
+       0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
+       0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+       0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
+};
+
+static const struct hdmiphy_conf hdmiphy_conf[] = {
+       { V4L2_DV_480P59_94, hdmiphy_conf27 },
+       { V4L2_DV_1080P30, hdmiphy_conf74_175 },
+       { V4L2_DV_720P59_94, hdmiphy_conf74_175 },
+       { V4L2_DV_720P60, hdmiphy_conf74_25 },
+       { V4L2_DV_1080P50, hdmiphy_conf148_5 },
+       { V4L2_DV_1080P60, hdmiphy_conf148_5 },
+};
+
+const u8 *hdmiphy_preset2conf(u32 preset)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(hdmiphy_conf); ++i)
+               if (hdmiphy_conf[i].preset == preset)
+                       return hdmiphy_conf[i].data;
+       return NULL;
+}
+
+static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
+{
+       /* to be implemented */
+       return 0;
+}
+
+static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
+       struct v4l2_dv_preset *preset)
+{
+       const u8 *data;
+       u8 buffer[32];
+       int ret;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct device *dev = &client->dev;
+
+       dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset);
+       data = hdmiphy_preset2conf(preset->preset);
+       if (!data) {
+               dev_err(dev, "format not supported\n");
+               return -EINVAL;
+       }
+
+       /* storing configuration to the device */
+       memcpy(buffer, data, 32);
+       ret = i2c_master_send(client, buffer, 32);
+       if (ret != 32) {
+               dev_err(dev, "failed to configure HDMIPHY via I2C\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct device *dev = &client->dev;
+       u8 buffer[2];
+       int ret;
+
+       dev_info(dev, "s_stream(%d)\n", enable);
+       /* going to/from configuration from/to operation mode */
+       buffer[0] = 0x1f;
+       buffer[1] = enable ? 0x80 : 0x00;
+
+       ret = i2c_master_send(client, buffer, 2);
+       if (ret != 2) {
+               dev_err(dev, "stream (%d) failed\n", enable);
+               return -EIO;
+       }
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
+       .s_power =  hdmiphy_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
+       .s_dv_preset = hdmiphy_s_dv_preset,
+       .s_stream =  hdmiphy_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmiphy_ops = {
+       .core = &hdmiphy_core_ops,
+       .video = &hdmiphy_video_ops,
+};
+
+static int __devinit hdmiphy_probe(struct i2c_client *client,
+       const struct i2c_device_id *id)
+{
+       static struct v4l2_subdev sd;
+
+       v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops);
+       dev_info(&client->dev, "probe successful\n");
+       return 0;
+}
+
+static int __devexit hdmiphy_remove(struct i2c_client *client)
+{
+       dev_info(&client->dev, "remove successful\n");
+       return 0;
+}
+
+static const struct i2c_device_id hdmiphy_id[] = {
+       { "hdmiphy", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
+
+static struct i2c_driver hdmiphy_driver = {
+       .driver = {
+               .name   = "s5p-hdmiphy",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = hdmiphy_probe,
+       .remove         = __devexit_p(hdmiphy_remove),
+       .id_table = hdmiphy_id,
+};
+
+static int __init hdmiphy_init(void)
+{
+       return i2c_add_driver(&hdmiphy_driver);
+}
+module_init(hdmiphy_init);
+
+static void __exit hdmiphy_exit(void)
+{
+       i2c_del_driver(&hdmiphy_driver);
+}
+module_exit(hdmiphy_exit);
diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h
new file mode 100644 (file)
index 0000000..e224224
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifndef SAMSUNG_MIXER_H
+#define SAMSUNG_MIXER_H
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+       #define DEBUG
+#endif
+
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
+
+#include "regs-mixer.h"
+
+/** maximum number of output interfaces */
+#define MXR_MAX_OUTPUTS 2
+/** maximum number of input interfaces (layers) */
+#define MXR_MAX_LAYERS 3
+#define MXR_DRIVER_NAME "s5p-mixer"
+/** maximal number of planes for every layer */
+#define MXR_MAX_PLANES 2
+
+#define MXR_ENABLE 1
+#define MXR_DISABLE 0
+
+/** description of a macroblock for packed formats */
+struct mxr_block {
+       /** vertical number of pixels in macroblock */
+       unsigned int width;
+       /** horizontal number of pixels in macroblock */
+       unsigned int height;
+       /** size of block in bytes */
+       unsigned int size;
+};
+
+/** description of supported format */
+struct mxr_format {
+       /** format name/mnemonic */
+       const char *name;
+       /** fourcc identifier */
+       u32 fourcc;
+       /** colorspace identifier */
+       enum v4l2_colorspace colorspace;
+       /** number of planes in image data */
+       int num_planes;
+       /** description of block for each plane */
+       struct mxr_block plane[MXR_MAX_PLANES];
+       /** number of subframes in image data */
+       int num_subframes;
+       /** specifies to which subframe belong given plane */
+       int plane2subframe[MXR_MAX_PLANES];
+       /** internal code, driver dependant */
+       unsigned long cookie;
+};
+
+/** description of crop configuration for image */
+struct mxr_crop {
+       /** width of layer in pixels */
+       unsigned int full_width;
+       /** height of layer in pixels */
+       unsigned int full_height;
+       /** horizontal offset of first pixel to be displayed */
+       unsigned int x_offset;
+       /** vertical offset of first pixel to be displayed */
+       unsigned int y_offset;
+       /** width of displayed data in pixels */
+       unsigned int width;
+       /** height of displayed data in pixels */
+       unsigned int height;
+       /** indicate which fields are present in buffer */
+       unsigned int field;
+};
+
+/** description of transformation from source to destination image */
+struct mxr_geometry {
+       /** cropping for source image */
+       struct mxr_crop src;
+       /** cropping for destination image */
+       struct mxr_crop dst;
+       /** layer-dependant description of horizontal scaling */
+       unsigned int x_ratio;
+       /** layer-dependant description of vertical scaling */
+       unsigned int y_ratio;
+};
+
+/** instance of a buffer */
+struct mxr_buffer {
+       /** common v4l buffer stuff -- must be first */
+       struct vb2_buffer       vb;
+       /** node for layer's lists */
+       struct list_head        list;
+};
+
+
+/** internal states of layer */
+enum mxr_layer_state {
+       /** layers is not shown */
+       MXR_LAYER_IDLE = 0,
+       /** state between STREAMON and hardware start */
+       MXR_LAYER_STREAMING_START,
+       /** layer is shown */
+       MXR_LAYER_STREAMING,
+       /** state before STREAMOFF is finished */
+       MXR_LAYER_STREAMING_FINISH,
+};
+
+/** forward declarations */
+struct mxr_device;
+struct mxr_layer;
+
+/** callback for layers operation */
+struct mxr_layer_ops {
+       /* TODO: try to port it to subdev API */
+       /** handler for resource release function */
+       void (*release)(struct mxr_layer *);
+       /** setting buffer to HW */
+       void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *);
+       /** setting format and geometry in HW */
+       void (*format_set)(struct mxr_layer *);
+       /** streaming stop/start */
+       void (*stream_set)(struct mxr_layer *, int);
+       /** adjusting geometry */
+       void (*fix_geometry)(struct mxr_layer *);
+};
+
+/** layer instance, a single window and content displayed on output */
+struct mxr_layer {
+       /** parent mixer device */
+       struct mxr_device *mdev;
+       /** layer index (unique identifier) */
+       int idx;
+       /** callbacks for layer methods */
+       struct mxr_layer_ops ops;
+       /** format array */
+       const struct mxr_format **fmt_array;
+       /** size of format array */
+       unsigned long fmt_array_size;
+
+       /** lock for protection of list and state fields */
+       spinlock_t enq_slock;
+       /** list for enqueued buffers */
+       struct list_head enq_list;
+       /** buffer currently owned by hardware in temporary registers */
+       struct mxr_buffer *update_buf;
+       /** buffer currently owned by hardware in shadow registers */
+       struct mxr_buffer *shadow_buf;
+       /** state of layer IDLE/STREAMING */
+       enum mxr_layer_state state;
+
+       /** mutex for protection of fields below */
+       struct mutex mutex;
+       /** handler for video node */
+       struct video_device vfd;
+       /** queue for output buffers */
+       struct vb2_queue vb_queue;
+       /** current image format */
+       const struct mxr_format *fmt;
+       /** current geometry of image */
+       struct mxr_geometry geo;
+};
+
+/** description of mixers output interface */
+struct mxr_output {
+       /** name of output */
+       char name[32];
+       /** output subdev */
+       struct v4l2_subdev *sd;
+       /** cookie used for configuration of registers */
+       int cookie;
+};
+
+/** specify source of output subdevs */
+struct mxr_output_conf {
+       /** name of output (connector) */
+       char *output_name;
+       /** name of module that generates output subdev */
+       char *module_name;
+       /** cookie need for mixer HW */
+       int cookie;
+};
+
+struct clk;
+struct regulator;
+
+/** auxiliary resources used my mixer */
+struct mxr_resources {
+       /** interrupt index */
+       int irq;
+       /** pointer to Mixer registers */
+       void __iomem *mxr_regs;
+       /** pointer to Video Processor registers */
+       void __iomem *vp_regs;
+       /** other resources, should used under mxr_device.mutex */
+       struct clk *mixer;
+       struct clk *vp;
+       struct clk *sclk_mixer;
+       struct clk *sclk_hdmi;
+       struct clk *sclk_dac;
+};
+
+/* event flags used  */
+enum mxr_devide_flags {
+       MXR_EVENT_VSYNC = 0,
+};
+
+/** drivers instance */
+struct mxr_device {
+       /** master device */
+       struct device *dev;
+       /** state of each layer */
+       struct mxr_layer *layer[MXR_MAX_LAYERS];
+       /** state of each output */
+       struct mxr_output *output[MXR_MAX_OUTPUTS];
+       /** number of registered outputs */
+       int output_cnt;
+
+       /* video resources */
+
+       /** V4L2 device */
+       struct v4l2_device v4l2_dev;
+       /** context of allocator */
+       void *alloc_ctx;
+       /** event wait queue */
+       wait_queue_head_t event_queue;
+       /** state flags */
+       unsigned long event_flags;
+
+       /** spinlock for protection of registers */
+       spinlock_t reg_slock;
+
+       /** mutex for protection of fields below */
+       struct mutex mutex;
+       /** number of entities depndant on output configuration */
+       int n_output;
+       /** number of users that do streaming */
+       int n_streamer;
+       /** index of current output */
+       int current_output;
+       /** auxiliary resources used my mixer */
+       struct mxr_resources res;
+};
+
+/** transform device structure into mixer device */
+static inline struct mxr_device *to_mdev(struct device *dev)
+{
+       struct v4l2_device *vdev = dev_get_drvdata(dev);
+       return container_of(vdev, struct mxr_device, v4l2_dev);
+}
+
+/** get current output data, should be called under mdev's mutex */
+static inline struct mxr_output *to_output(struct mxr_device *mdev)
+{
+       return mdev->output[mdev->current_output];
+}
+
+/** get current output subdev, should be called under mdev's mutex */
+static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev)
+{
+       struct mxr_output *out = to_output(mdev);
+       return out ? out->sd : NULL;
+}
+
+/** forward declaration for mixer platform data */
+struct mxr_platform_data;
+
+/** acquiring common video resources */
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+       struct mxr_output_conf *output_cont, int output_count);
+
+/** releasing common video resources */
+void __devexit mxr_release_video(struct mxr_device *mdev);
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+       int idx, char *name, struct mxr_layer_ops *ops);
+
+void mxr_base_layer_release(struct mxr_layer *layer);
+void mxr_layer_release(struct mxr_layer *layer);
+
+int mxr_base_layer_register(struct mxr_layer *layer);
+void mxr_base_layer_unregister(struct mxr_layer *layer);
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+       unsigned int width, unsigned int height);
+
+/** adds new consumer for mixer's power */
+int __must_check mxr_power_get(struct mxr_device *mdev);
+/** removes consumer for mixer's power */
+void mxr_power_put(struct mxr_device *mdev);
+/** add new client for output configuration */
+void mxr_output_get(struct mxr_device *mdev);
+/** removes new client for output configuration */
+void mxr_output_put(struct mxr_device *mdev);
+/** add new client for streaming */
+void mxr_streamer_get(struct mxr_device *mdev);
+/** removes new client for streaming */
+void mxr_streamer_put(struct mxr_device *mdev);
+/** returns format of data delivared to current output */
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *mbus_fmt);
+
+/* Debug */
+
+#define mxr_err(mdev, fmt, ...)  dev_err(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__)
+
+#ifdef CONFIG_VIDEO_SAMSUNG_S5P_MIXER_DEBUG
+       #define mxr_dbg(mdev, fmt, ...)  dev_dbg(mdev->dev, fmt, ##__VA_ARGS__)
+#else
+       #define mxr_dbg(mdev, fmt, ...)  do { (void) mdev; } while (0)
+#endif
+
+/* accessing Mixer's and Video Processor's registers */
+
+void mxr_vsync_set_update(struct mxr_device *mdev, int en);
+void mxr_reg_reset(struct mxr_device *mdev);
+irqreturn_t mxr_irq_handler(int irq, void *dev_data);
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie);
+void mxr_reg_streamon(struct mxr_device *mdev);
+void mxr_reg_streamoff(struct mxr_device *mdev);
+int mxr_reg_wait4vsync(struct mxr_device *mdev);
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *fmt);
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en);
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr);
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo);
+
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en);
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+       dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]);
+void mxr_reg_vp_format(struct mxr_device *mdev,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo);
+void mxr_reg_dump(struct mxr_device *mdev);
+
+#endif /* SAMSUNG_MIXER_H */
+
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
new file mode 100644 (file)
index 0000000..0064309
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MIXER");
+MODULE_LICENSE("GPL");
+
+/* --------- DRIVER PARAMETERS ---------- */
+
+static struct mxr_output_conf mxr_output_conf[] = {
+       {
+               .output_name = "S5P HDMI connector",
+               .module_name = "s5p-hdmi",
+               .cookie = 1,
+       },
+       {
+               .output_name = "S5P SDO connector",
+               .module_name = "s5p-sdo",
+               .cookie = 0,
+       },
+};
+
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *mbus_fmt)
+{
+       struct v4l2_subdev *sd;
+       int ret;
+
+       mutex_lock(&mdev->mutex);
+       sd = to_outsd(mdev);
+       ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
+       WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+       mutex_unlock(&mdev->mutex);
+}
+
+void mxr_streamer_get(struct mxr_device *mdev)
+{
+       mutex_lock(&mdev->mutex);
+       ++mdev->n_streamer;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+       if (mdev->n_streamer == 1) {
+               struct v4l2_subdev *sd = to_outsd(mdev);
+               struct v4l2_mbus_framefmt mbus_fmt;
+               struct mxr_resources *res = &mdev->res;
+               int ret;
+
+               if (to_output(mdev)->cookie == 0)
+                       clk_set_parent(res->sclk_mixer, res->sclk_dac);
+               else
+                       clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
+               mxr_reg_s_output(mdev, to_output(mdev)->cookie);
+
+               ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
+               WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+               ret = v4l2_subdev_call(sd, video, s_stream, 1);
+               WARN(ret, "starting stream failed for output %s\n", sd->name);
+
+               mxr_reg_set_mbus_fmt(mdev, &mbus_fmt);
+               mxr_reg_streamon(mdev);
+               ret = mxr_reg_wait4vsync(mdev);
+               WARN(ret, "failed to get vsync (%d) from output\n", ret);
+       }
+       mutex_unlock(&mdev->mutex);
+       mxr_reg_dump(mdev);
+       /* FIXME: what to do when streaming fails? */
+}
+
+void mxr_streamer_put(struct mxr_device *mdev)
+{
+       mutex_lock(&mdev->mutex);
+       --mdev->n_streamer;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+       if (mdev->n_streamer == 0) {
+               int ret;
+               struct v4l2_subdev *sd = to_outsd(mdev);
+
+               mxr_reg_streamoff(mdev);
+               /* vsync applies Mixer setup */
+               ret = mxr_reg_wait4vsync(mdev);
+               WARN(ret, "failed to get vsync (%d) from output\n", ret);
+               ret = v4l2_subdev_call(sd, video, s_stream, 0);
+               WARN(ret, "stopping stream failed for output %s\n", sd->name);
+       }
+       WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
+               mdev->n_streamer);
+       mutex_unlock(&mdev->mutex);
+       mxr_reg_dump(mdev);
+}
+
+void mxr_output_get(struct mxr_device *mdev)
+{
+       mutex_lock(&mdev->mutex);
+       ++mdev->n_output;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+       /* turn on auxiliary driver */
+       if (mdev->n_output == 1)
+               v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
+       mutex_unlock(&mdev->mutex);
+}
+
+void mxr_output_put(struct mxr_device *mdev)
+{
+       mutex_lock(&mdev->mutex);
+       --mdev->n_output;
+       mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+       /* turn on auxiliary driver */
+       if (mdev->n_output == 0)
+               v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
+       WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
+               mdev->n_output);
+       mutex_unlock(&mdev->mutex);
+}
+
+int mxr_power_get(struct mxr_device *mdev)
+{
+       int ret = pm_runtime_get_sync(mdev->dev);
+
+       /* returning 1 means that power is already enabled,
+        * so zero success be returned */
+       if (IS_ERR_VALUE(ret))
+               return ret;
+       return 0;
+}
+
+void mxr_power_put(struct mxr_device *mdev)
+{
+       pm_runtime_put_sync(mdev->dev);
+}
+
+/* --------- RESOURCE MANAGEMENT -------------*/
+
+static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
+       struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
+       if (res == NULL) {
+               mxr_err(mdev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
+       if (mdev->res.mxr_regs == NULL) {
+               mxr_err(mdev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
+       if (res == NULL) {
+               mxr_err(mdev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail_mxr_regs;
+       }
+
+       mdev->res.vp_regs = ioremap(res->start, resource_size(res));
+       if (mdev->res.vp_regs == NULL) {
+               mxr_err(mdev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail_mxr_regs;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
+       if (res == NULL) {
+               mxr_err(mdev, "get interrupt resource failed.\n");
+               ret = -ENXIO;
+               goto fail_vp_regs;
+       }
+
+       ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
+       if (ret) {
+               mxr_err(mdev, "request interrupt failed.\n");
+               goto fail_vp_regs;
+       }
+       mdev->res.irq = res->start;
+
+       return 0;
+
+fail_vp_regs:
+       iounmap(mdev->res.vp_regs);
+
+fail_mxr_regs:
+       iounmap(mdev->res.mxr_regs);
+
+fail:
+       return ret;
+}
+
+static void mxr_release_plat_resources(struct mxr_device *mdev)
+{
+       free_irq(mdev->res.irq, mdev);
+       iounmap(mdev->res.vp_regs);
+       iounmap(mdev->res.mxr_regs);
+}
+
+static void mxr_release_clocks(struct mxr_device *mdev)
+{
+       struct mxr_resources *res = &mdev->res;
+
+       if (!IS_ERR_OR_NULL(res->sclk_dac))
+               clk_put(res->sclk_dac);
+       if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+               clk_put(res->sclk_hdmi);
+       if (!IS_ERR_OR_NULL(res->sclk_mixer))
+               clk_put(res->sclk_mixer);
+       if (!IS_ERR_OR_NULL(res->vp))
+               clk_put(res->vp);
+       if (!IS_ERR_OR_NULL(res->mixer))
+               clk_put(res->mixer);
+}
+
+static int mxr_acquire_clocks(struct mxr_device *mdev)
+{
+       struct mxr_resources *res = &mdev->res;
+       struct device *dev = mdev->dev;
+
+       res->mixer = clk_get(dev, "mixer");
+       if (IS_ERR_OR_NULL(res->mixer)) {
+               mxr_err(mdev, "failed to get clock 'mixer'\n");
+               goto fail;
+       }
+       res->vp = clk_get(dev, "vp");
+       if (IS_ERR_OR_NULL(res->vp)) {
+               mxr_err(mdev, "failed to get clock 'vp'\n");
+               goto fail;
+       }
+       res->sclk_mixer = clk_get(dev, "sclk_mixer");
+       if (IS_ERR_OR_NULL(res->sclk_mixer)) {
+               mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
+               goto fail;
+       }
+       res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+       if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+               mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
+               goto fail;
+       }
+       res->sclk_dac = clk_get(dev, "sclk_dac");
+       if (IS_ERR_OR_NULL(res->sclk_dac)) {
+               mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
+               goto fail;
+       }
+
+       return 0;
+fail:
+       mxr_release_clocks(mdev);
+       return -ENODEV;
+}
+
+static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
+       struct platform_device *pdev)
+{
+       int ret;
+       ret = mxr_acquire_plat_resources(mdev, pdev);
+
+       if (ret)
+               goto fail;
+
+       ret = mxr_acquire_clocks(mdev);
+       if (ret)
+               goto fail_plat;
+
+       mxr_info(mdev, "resources acquired\n");
+       return 0;
+
+fail_plat:
+       mxr_release_plat_resources(mdev);
+fail:
+       mxr_err(mdev, "resources acquire failed\n");
+       return ret;
+}
+
+static void mxr_release_resources(struct mxr_device *mdev)
+{
+       mxr_release_clocks(mdev);
+       mxr_release_plat_resources(mdev);
+       memset(&mdev->res, 0, sizeof mdev->res);
+}
+
+static void mxr_release_layers(struct mxr_device *mdev)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(mdev->layer); ++i)
+               if (mdev->layer[i])
+                       mxr_layer_release(mdev->layer[i]);
+}
+
+static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
+       struct mxr_platform_data *pdata)
+{
+       mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
+       mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
+       mdev->layer[2] = mxr_vp_layer_create(mdev, 0);
+
+       if (!mdev->layer[0] || !mdev->layer[1] || !mdev->layer[2]) {
+               mxr_err(mdev, "failed to acquire layers\n");
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       mxr_release_layers(mdev);
+       return -ENODEV;
+}
+
+/* ---------- POWER MANAGEMENT ----------- */
+
+static int mxr_runtime_resume(struct device *dev)
+{
+       struct mxr_device *mdev = to_mdev(dev);
+       struct mxr_resources *res = &mdev->res;
+
+       mxr_dbg(mdev, "resume - start\n");
+       mutex_lock(&mdev->mutex);
+       /* turn clocks on */
+       clk_enable(res->mixer);
+       clk_enable(res->vp);
+       clk_enable(res->sclk_mixer);
+       /* apply default configuration */
+       mxr_reg_reset(mdev);
+       mxr_dbg(mdev, "resume - finished\n");
+
+       mutex_unlock(&mdev->mutex);
+       return 0;
+}
+
+static int mxr_runtime_suspend(struct device *dev)
+{
+       struct mxr_device *mdev = to_mdev(dev);
+       struct mxr_resources *res = &mdev->res;
+       mxr_dbg(mdev, "suspend - start\n");
+       mutex_lock(&mdev->mutex);
+       /* turn clocks off */
+       clk_disable(res->sclk_mixer);
+       clk_disable(res->vp);
+       clk_disable(res->mixer);
+       mutex_unlock(&mdev->mutex);
+       mxr_dbg(mdev, "suspend - finished\n");
+       return 0;
+}
+
+static const struct dev_pm_ops mxr_pm_ops = {
+       .runtime_suspend = mxr_runtime_suspend,
+       .runtime_resume  = mxr_runtime_resume,
+};
+
+/* --------- DRIVER INITIALIZATION ---------- */
+
+static int __devinit mxr_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mxr_platform_data *pdata = dev->platform_data;
+       struct mxr_device *mdev;
+       int ret;
+
+       /* mdev does not exist yet so no mxr_dbg is used */
+       dev_info(dev, "probe start\n");
+
+       mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+       if (!mdev) {
+               mxr_err(mdev, "not enough memory.\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       /* setup pointer to master device */
+       mdev->dev = dev;
+
+       mutex_init(&mdev->mutex);
+       spin_lock_init(&mdev->reg_slock);
+       init_waitqueue_head(&mdev->event_queue);
+
+       /* acquire resources: regs, irqs, clocks, regulators */
+       ret = mxr_acquire_resources(mdev, pdev);
+       if (ret)
+               goto fail_mem;
+
+       /* configure resources for video output */
+       ret = mxr_acquire_video(mdev, mxr_output_conf,
+               ARRAY_SIZE(mxr_output_conf));
+       if (ret)
+               goto fail_resources;
+
+       /* configure layers */
+       ret = mxr_acquire_layers(mdev, pdata);
+       if (ret)
+               goto fail_video;
+
+       pm_runtime_enable(dev);
+
+       mxr_info(mdev, "probe successful\n");
+       return 0;
+
+fail_video:
+       mxr_release_video(mdev);
+
+fail_resources:
+       mxr_release_resources(mdev);
+
+fail_mem:
+       kfree(mdev);
+
+fail:
+       dev_info(dev, "probe failed\n");
+       return ret;
+}
+
+static int __devexit mxr_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mxr_device *mdev = to_mdev(dev);
+
+       pm_runtime_disable(dev);
+
+       mxr_release_layers(mdev);
+       mxr_release_video(mdev);
+       mxr_release_resources(mdev);
+
+       kfree(mdev);
+
+       dev_info(dev, "remove sucessful\n");
+       return 0;
+}
+
+static struct platform_driver mxr_driver __refdata = {
+       .probe = mxr_probe,
+       .remove = __devexit_p(mxr_remove),
+       .driver = {
+               .name = MXR_DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .pm = &mxr_pm_ops,
+       }
+};
+
+static int __init mxr_init(void)
+{
+       int i, ret;
+       static const char banner[] __initdata = KERN_INFO
+               "Samsung TV Mixer driver, "
+               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+       printk(banner);
+
+       /* Loading auxiliary modules */
+       for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
+               request_module(mxr_output_conf[i].module_name);
+
+       ret = platform_driver_register(&mxr_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "registration of MIXER driver failed\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+module_init(mxr_init);
+
+static void __exit mxr_exit(void)
+{
+       platform_driver_unregister(&mxr_driver);
+}
+module_exit(mxr_exit);
diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/video/s5p-tv/mixer_grp_layer.c
new file mode 100644 (file)
index 0000000..58f0ba4
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include <media/videobuf2-dma-contig.h>
+
+/* FORMAT DEFINITIONS */
+
+static const struct mxr_format mxr_fb_fmt_rgb565 = {
+       .name = "RGB565",
+       .fourcc = V4L2_PIX_FMT_RGB565,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .num_planes = 1,
+       .plane = {
+               { .width = 1, .height = 1, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = 4,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb1555 = {
+       .name = "ARGB1555",
+       .num_planes = 1,
+       .fourcc = V4L2_PIX_FMT_RGB555,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .plane = {
+               { .width = 1, .height = 1, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = 5,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb4444 = {
+       .name = "ARGB4444",
+       .num_planes = 1,
+       .fourcc = V4L2_PIX_FMT_RGB444,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .plane = {
+               { .width = 1, .height = 1, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = 6,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb8888 = {
+       .name = "ARGB8888",
+       .fourcc = V4L2_PIX_FMT_BGR32,
+       .colorspace = V4L2_COLORSPACE_SRGB,
+       .num_planes = 1,
+       .plane = {
+               { .width = 1, .height = 1, .size = 4 },
+       },
+       .num_subframes = 1,
+       .cookie = 7,
+};
+
+static const struct mxr_format *mxr_graph_format[] = {
+       &mxr_fb_fmt_rgb565,
+       &mxr_fb_fmt_argb1555,
+       &mxr_fb_fmt_argb4444,
+       &mxr_fb_fmt_argb8888,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_graph_layer_release(struct mxr_layer *layer)
+{
+       mxr_base_layer_unregister(layer);
+       mxr_base_layer_release(layer);
+}
+
+static void mxr_graph_buffer_set(struct mxr_layer *layer,
+       struct mxr_buffer *buf)
+{
+       dma_addr_t addr = 0;
+
+       if (buf)
+               addr = vb2_dma_contig_plane_paddr(&buf->vb, 0);
+       mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
+}
+
+static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
+{
+       mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
+}
+
+static void mxr_graph_format_set(struct mxr_layer *layer)
+{
+       mxr_reg_graph_format(layer->mdev, layer->idx,
+               layer->fmt, &layer->geo);
+}
+
+static void mxr_graph_fix_geometry(struct mxr_layer *layer)
+{
+       struct mxr_geometry *geo = &layer->geo;
+
+       /* limit to boundary size */
+       geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
+       geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047);
+       geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width);
+       geo->src.width = min(geo->src.width, 2047U);
+       /* not possible to crop of Y axis */
+       geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1);
+       geo->src.height = geo->src.full_height - geo->src.y_offset;
+       /* limitting offset */
+       geo->src.x_offset = min(geo->src.x_offset,
+               geo->src.full_width - geo->src.width);
+
+       /* setting position in output */
+       geo->dst.width = min(geo->dst.width, geo->dst.full_width);
+       geo->dst.height = min(geo->dst.height, geo->dst.full_height);
+
+       /* Mixer supports only 1x and 2x scaling */
+       if (geo->dst.width >= 2 * geo->src.width) {
+               geo->x_ratio = 1;
+               geo->dst.width = 2 * geo->src.width;
+       } else {
+               geo->x_ratio = 0;
+               geo->dst.width = geo->src.width;
+       }
+
+       if (geo->dst.height >= 2 * geo->src.height) {
+               geo->y_ratio = 1;
+               geo->dst.height = 2 * geo->src.height;
+       } else {
+               geo->y_ratio = 0;
+               geo->dst.height = geo->src.height;
+       }
+
+       geo->dst.x_offset = min(geo->dst.x_offset,
+               geo->dst.full_width - geo->dst.width);
+       geo->dst.y_offset = min(geo->dst.y_offset,
+               geo->dst.full_height - geo->dst.height);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
+{
+       struct mxr_layer *layer;
+       int ret;
+       struct mxr_layer_ops ops = {
+               .release = mxr_graph_layer_release,
+               .buffer_set = mxr_graph_buffer_set,
+               .stream_set = mxr_graph_stream_set,
+               .format_set = mxr_graph_format_set,
+               .fix_geometry = mxr_graph_fix_geometry,
+       };
+       char name[32];
+
+       sprintf(name, "graph%d", idx);
+
+       layer = mxr_base_layer_create(mdev, idx, name, &ops);
+       if (layer == NULL) {
+               mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+               goto fail;
+       }
+
+       layer->fmt_array = mxr_graph_format;
+       layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
+
+       ret = mxr_base_layer_register(layer);
+       if (ret)
+               goto fail_layer;
+
+       return layer;
+
+fail_layer:
+       mxr_base_layer_release(layer);
+
+fail:
+       return NULL;
+}
+
diff --git a/drivers/media/video/s5p-tv/mixer_reg.c b/drivers/media/video/s5p-tv/mixer_reg.c
new file mode 100644 (file)
index 0000000..38dac67
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+#include "regs-mixer.h"
+#include "regs-vp.h"
+
+#include <linux/delay.h>
+
+/* Register access subroutines */
+
+static inline u32 vp_read(struct mxr_device *mdev, u32 reg_id)
+{
+       return readl(mdev->res.vp_regs + reg_id);
+}
+
+static inline void vp_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+       writel(val, mdev->res.vp_regs + reg_id);
+}
+
+static inline void vp_write_mask(struct mxr_device *mdev, u32 reg_id,
+       u32 val, u32 mask)
+{
+       u32 old = vp_read(mdev, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, mdev->res.vp_regs + reg_id);
+}
+
+static inline u32 mxr_read(struct mxr_device *mdev, u32 reg_id)
+{
+       return readl(mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+       writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id,
+       u32 val, u32 mask)
+{
+       u32 old = mxr_read(mdev, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+void mxr_vsync_set_update(struct mxr_device *mdev, int en)
+{
+       /* block update on vsync */
+       mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0,
+               MXR_STATUS_SYNC_ENABLE);
+       vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0);
+}
+
+static void __mxr_reg_vp_reset(struct mxr_device *mdev)
+{
+       int tries = 100;
+
+       vp_write(mdev, VP_SRESET, VP_SRESET_PROCESSING);
+       for (tries = 100; tries; --tries) {
+               /* waiting until VP_SRESET_PROCESSING is 0 */
+               if (~vp_read(mdev, VP_SRESET) & VP_SRESET_PROCESSING)
+                       break;
+               mdelay(10);
+       }
+       WARN(tries == 0, "failed to reset Video Processor\n");
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev);
+
+void mxr_reg_reset(struct mxr_device *mdev)
+{
+       unsigned long flags;
+       u32 val; /* value stored to register */
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       /* set output in RGB888 mode */
+       mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_YUV444);
+
+       /* 16 beat burst in DMA */
+       mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST,
+               MXR_STATUS_BURST_MASK);
+
+       /* setting default layer priority: layer1 > video > layer0
+        * because typical usage scenario would be
+        * layer0 - framebuffer
+        * video - video overlay
+        * layer1 - OSD
+        */
+       val  = MXR_LAYER_CFG_GRP0_VAL(1);
+       val |= MXR_LAYER_CFG_VP_VAL(2);
+       val |= MXR_LAYER_CFG_GRP1_VAL(3);
+       mxr_write(mdev, MXR_LAYER_CFG, val);
+
+       /* use dark gray background color */
+       mxr_write(mdev, MXR_BG_COLOR0, 0x808080);
+       mxr_write(mdev, MXR_BG_COLOR1, 0x808080);
+       mxr_write(mdev, MXR_BG_COLOR2, 0x808080);
+
+       /* setting graphical layers */
+
+       val  = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
+       val |= MXR_GRP_CFG_BLEND_PRE_MUL; /* premul mode */
+       val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
+
+       /* the same configuration for both layers */
+       mxr_write(mdev, MXR_GRAPHIC_CFG(0), val);
+       mxr_write(mdev, MXR_GRAPHIC_CFG(1), val);
+
+       /* configuration of Video Processor Registers */
+       __mxr_reg_vp_reset(mdev);
+       mxr_reg_vp_default_filter(mdev);
+
+       /* enable all interrupts */
+       mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       /* setup format */
+       mxr_write_mask(mdev, MXR_GRAPHIC_CFG(idx),
+               MXR_GRP_CFG_FORMAT_VAL(fmt->cookie), MXR_GRP_CFG_FORMAT_MASK);
+
+       /* setup geometry */
+       mxr_write(mdev, MXR_GRAPHIC_SPAN(idx), geo->src.full_width);
+       val  = MXR_GRP_WH_WIDTH(geo->src.width);
+       val |= MXR_GRP_WH_HEIGHT(geo->src.height);
+       val |= MXR_GRP_WH_H_SCALE(geo->x_ratio);
+       val |= MXR_GRP_WH_V_SCALE(geo->y_ratio);
+       mxr_write(mdev, MXR_GRAPHIC_WH(idx), val);
+
+       /* setup offsets in source image */
+       val  = MXR_GRP_SXY_SX(geo->src.x_offset);
+       val |= MXR_GRP_SXY_SY(geo->src.y_offset);
+       mxr_write(mdev, MXR_GRAPHIC_SXY(idx), val);
+
+       /* setup offsets in display image */
+       val  = MXR_GRP_DXY_DX(geo->dst.x_offset);
+       val |= MXR_GRP_DXY_DY(geo->dst.y_offset);
+       mxr_write(mdev, MXR_GRAPHIC_DXY(idx), val);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_format(struct mxr_device *mdev,
+       const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       vp_write_mask(mdev, VP_MODE, fmt->cookie, VP_MODE_FMT_MASK);
+
+       /* setting size of input image */
+       vp_write(mdev, VP_IMG_SIZE_Y, VP_IMG_HSIZE(geo->src.full_width) |
+               VP_IMG_VSIZE(geo->src.full_height));
+       /* chroma height has to reduced by 2 to avoid chroma distorions */
+       vp_write(mdev, VP_IMG_SIZE_C, VP_IMG_HSIZE(geo->src.full_width) |
+               VP_IMG_VSIZE(geo->src.full_height / 2));
+
+       vp_write(mdev, VP_SRC_WIDTH, geo->src.width);
+       vp_write(mdev, VP_SRC_HEIGHT, geo->src.height);
+       vp_write(mdev, VP_SRC_H_POSITION,
+               VP_SRC_H_POSITION_VAL(geo->src.x_offset));
+       vp_write(mdev, VP_SRC_V_POSITION, geo->src.y_offset);
+
+       vp_write(mdev, VP_DST_WIDTH, geo->dst.width);
+       vp_write(mdev, VP_DST_H_POSITION, geo->dst.x_offset);
+       if (geo->dst.field == V4L2_FIELD_INTERLACED) {
+               vp_write(mdev, VP_DST_HEIGHT, geo->dst.height / 2);
+               vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset / 2);
+       } else {
+               vp_write(mdev, VP_DST_HEIGHT, geo->dst.height);
+               vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset);
+       }
+
+       vp_write(mdev, VP_H_RATIO, geo->x_ratio);
+       vp_write(mdev, VP_V_RATIO, geo->y_ratio);
+
+       vp_write(mdev, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+
+}
+
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr)
+{
+       u32 val = addr ? ~0 : 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       if (idx == 0)
+               mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
+       else
+               mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
+       mxr_write(mdev, MXR_GRAPHIC_BASE(idx), addr);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+       dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2])
+{
+       u32 val = luma_addr[0] ? ~0 : 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VP_ENABLE);
+       vp_write_mask(mdev, VP_ENABLE, val, VP_ENABLE_ON);
+       /* TODO: fix tiled mode */
+       vp_write(mdev, VP_TOP_Y_PTR, luma_addr[0]);
+       vp_write(mdev, VP_TOP_C_PTR, chroma_addr[0]);
+       vp_write(mdev, VP_BOT_Y_PTR, luma_addr[1]);
+       vp_write(mdev, VP_BOT_C_PTR, chroma_addr[1]);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+static void mxr_irq_layer_handle(struct mxr_layer *layer)
+{
+       struct list_head *head = &layer->enq_list;
+       struct mxr_buffer *done;
+
+       /* skip non-existing layer */
+       if (layer == NULL)
+               return;
+
+       spin_lock(&layer->enq_slock);
+       if (layer->state == MXR_LAYER_IDLE)
+               goto done;
+
+       done = layer->shadow_buf;
+       layer->shadow_buf = layer->update_buf;
+
+       if (list_empty(head)) {
+               if (layer->state != MXR_LAYER_STREAMING)
+                       layer->update_buf = NULL;
+       } else {
+               struct mxr_buffer *next;
+               next = list_first_entry(head, struct mxr_buffer, list);
+               list_del(&next->list);
+               layer->update_buf = next;
+       }
+
+       layer->ops.buffer_set(layer, layer->update_buf);
+
+       if (done && done != layer->shadow_buf)
+               vb2_buffer_done(&done->vb, VB2_BUF_STATE_DONE);
+
+done:
+       spin_unlock(&layer->enq_slock);
+}
+
+irqreturn_t mxr_irq_handler(int irq, void *dev_data)
+{
+       struct mxr_device *mdev = dev_data;
+       u32 i, val;
+
+       spin_lock(&mdev->reg_slock);
+       val = mxr_read(mdev, MXR_INT_STATUS);
+
+       /* wake up process waiting for VSYNC */
+       if (val & MXR_INT_STATUS_VSYNC) {
+               set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+               wake_up(&mdev->event_queue);
+       }
+
+       /* clear interrupts */
+       if (~val & MXR_INT_EN_VSYNC) {
+               /* vsync interrupt use different bit for read and clear */
+               val &= ~MXR_INT_EN_VSYNC;
+               val |= MXR_INT_CLEAR_VSYNC;
+       }
+       mxr_write(mdev, MXR_INT_STATUS, val);
+
+       spin_unlock(&mdev->reg_slock);
+       /* leave on non-vsync event */
+       if (~val & MXR_INT_CLEAR_VSYNC)
+               return IRQ_HANDLED;
+       for (i = 0; i < MXR_MAX_LAYERS; ++i)
+               mxr_irq_layer_handle(mdev->layer[i]);
+       return IRQ_HANDLED;
+}
+
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie)
+{
+       u32 val;
+
+       val = cookie == 0 ? MXR_CFG_DST_SDO : MXR_CFG_DST_HDMI;
+       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_DST_MASK);
+}
+
+void mxr_reg_streamon(struct mxr_device *mdev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       /* single write -> no need to block vsync update */
+
+       /* start MIXER */
+       mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
+
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_streamoff(struct mxr_device *mdev)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       /* single write -> no need to block vsync update */
+
+       /* stop MIXER */
+       mxr_write_mask(mdev, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
+
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+int mxr_reg_wait4vsync(struct mxr_device *mdev)
+{
+       int ret;
+
+       clear_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+       /* TODO: consider adding interruptible */
+       ret = wait_event_timeout(mdev->event_queue,
+               test_bit(MXR_EVENT_VSYNC, &mdev->event_flags),
+               msecs_to_jiffies(1000));
+       if (ret > 0)
+               return 0;
+       if (ret < 0)
+               return ret;
+       mxr_warn(mdev, "no vsync detected - timeout\n");
+       return -ETIME;
+}
+
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+       struct v4l2_mbus_framefmt *fmt)
+{
+       u32 val = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&mdev->reg_slock, flags);
+       mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+       /* choosing between interlace and progressive mode */
+       if (fmt->field == V4L2_FIELD_INTERLACED)
+               val |= MXR_CFG_SCAN_INTERLACE;
+       else
+               val |= MXR_CFG_SCAN_PROGRASSIVE;
+
+       /* choosing between porper HD and SD mode */
+       if (fmt->height == 480)
+               val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
+       else if (fmt->height == 576)
+               val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
+       else if (fmt->height == 720)
+               val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+       else if (fmt->height == 1080)
+               val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
+       else
+               WARN(1, "unrecognized mbus height %u!\n", fmt->height);
+
+       mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK);
+
+       val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0;
+       vp_write_mask(mdev, VP_MODE, val,
+               VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING);
+
+       mxr_vsync_set_update(mdev, MXR_ENABLE);
+       spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en)
+{
+       /* no extra actions need to be done */
+}
+
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en)
+{
+       /* no extra actions need to be done */
+}
+
+static const u8 filter_y_horiz_tap8[] = {
+       0,      -1,     -1,     -1,     -1,     -1,     -1,     -1,
+       -1,     -1,     -1,     -1,     -1,     0,      0,      0,
+       0,      2,      4,      5,      6,      6,      6,      6,
+       6,      5,      5,      4,      3,      2,      1,      1,
+       0,      -6,     -12,    -16,    -18,    -20,    -21,    -20,
+       -20,    -18,    -16,    -13,    -10,    -8,     -5,     -2,
+       127,    126,    125,    121,    114,    107,    99,     89,
+       79,     68,     57,     46,     35,     25,     16,     8,
+};
+
+static const u8 filter_y_vert_tap4[] = {
+       0,      -3,     -6,     -8,     -8,     -8,     -8,     -7,
+       -6,     -5,     -4,     -3,     -2,     -1,     -1,     0,
+       127,    126,    124,    118,    111,    102,    92,     81,
+       70,     59,     48,     37,     27,     19,     11,     5,
+       0,      5,      11,     19,     27,     37,     48,     59,
+       70,     81,     92,     102,    111,    118,    124,    126,
+       0,      0,      -1,     -1,     -2,     -3,     -4,     -5,
+       -6,     -7,     -8,     -8,     -8,     -8,     -6,     -3,
+};
+
+static const u8 filter_cr_horiz_tap4[] = {
+       0,      -3,     -6,     -8,     -8,     -8,     -8,     -7,
+       -6,     -5,     -4,     -3,     -2,     -1,     -1,     0,
+       127,    126,    124,    118,    111,    102,    92,     81,
+       70,     59,     48,     37,     27,     19,     11,     5,
+};
+
+static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev,
+       int reg_id, const u8 *data, unsigned int size)
+{
+       /* assure 4-byte align */
+       BUG_ON(size & 3);
+       for (; size; size -= 4, reg_id += 4, data += 4) {
+               u32 val = (data[0] << 24) |  (data[1] << 16) |
+                       (data[2] << 8) | data[3];
+               vp_write(mdev, reg_id, val);
+       }
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev)
+{
+       mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL,
+               filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
+       mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL,
+               filter_y_vert_tap4, sizeof filter_y_vert_tap4);
+       mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL,
+               filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
+}
+
+static void mxr_reg_mxr_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+       mxr_dbg(mdev, #reg_id " = %08x\n", \
+               (u32)readl(mdev->res.mxr_regs + reg_id)); \
+} while (0)
+
+       DUMPREG(MXR_STATUS);
+       DUMPREG(MXR_CFG);
+       DUMPREG(MXR_INT_EN);
+       DUMPREG(MXR_INT_STATUS);
+
+       DUMPREG(MXR_LAYER_CFG);
+       DUMPREG(MXR_VIDEO_CFG);
+
+       DUMPREG(MXR_GRAPHIC0_CFG);
+       DUMPREG(MXR_GRAPHIC0_BASE);
+       DUMPREG(MXR_GRAPHIC0_SPAN);
+       DUMPREG(MXR_GRAPHIC0_WH);
+       DUMPREG(MXR_GRAPHIC0_SXY);
+       DUMPREG(MXR_GRAPHIC0_DXY);
+
+       DUMPREG(MXR_GRAPHIC1_CFG);
+       DUMPREG(MXR_GRAPHIC1_BASE);
+       DUMPREG(MXR_GRAPHIC1_SPAN);
+       DUMPREG(MXR_GRAPHIC1_WH);
+       DUMPREG(MXR_GRAPHIC1_SXY);
+       DUMPREG(MXR_GRAPHIC1_DXY);
+#undef DUMPREG
+}
+
+static void mxr_reg_vp_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+       mxr_dbg(mdev, #reg_id " = %08x\n", \
+               (u32) readl(mdev->res.vp_regs + reg_id)); \
+} while (0)
+
+
+       DUMPREG(VP_ENABLE);
+       DUMPREG(VP_SRESET);
+       DUMPREG(VP_SHADOW_UPDATE);
+       DUMPREG(VP_FIELD_ID);
+       DUMPREG(VP_MODE);
+       DUMPREG(VP_IMG_SIZE_Y);
+       DUMPREG(VP_IMG_SIZE_C);
+       DUMPREG(VP_PER_RATE_CTRL);
+       DUMPREG(VP_TOP_Y_PTR);
+       DUMPREG(VP_BOT_Y_PTR);
+       DUMPREG(VP_TOP_C_PTR);
+       DUMPREG(VP_BOT_C_PTR);
+       DUMPREG(VP_ENDIAN_MODE);
+       DUMPREG(VP_SRC_H_POSITION);
+       DUMPREG(VP_SRC_V_POSITION);
+       DUMPREG(VP_SRC_WIDTH);
+       DUMPREG(VP_SRC_HEIGHT);
+       DUMPREG(VP_DST_H_POSITION);
+       DUMPREG(VP_DST_V_POSITION);
+       DUMPREG(VP_DST_WIDTH);
+       DUMPREG(VP_DST_HEIGHT);
+       DUMPREG(VP_H_RATIO);
+       DUMPREG(VP_V_RATIO);
+
+#undef DUMPREG
+}
+
+void mxr_reg_dump(struct mxr_device *mdev)
+{
+       mxr_reg_mxr_dump(mdev);
+       mxr_reg_vp_dump(mdev);
+}
+
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
new file mode 100644 (file)
index 0000000..43ac22f
--- /dev/null
@@ -0,0 +1,1006 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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
+ */
+
+#include "mixer.h"
+
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <linux/mm.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <media/videobuf2-dma-contig.h>
+
+static int find_reg_callback(struct device *dev, void *p)
+{
+       struct v4l2_subdev **sd = p;
+
+       *sd = dev_get_drvdata(dev);
+       /* non-zero value stops iteration */
+       return 1;
+}
+
+static struct v4l2_subdev *find_and_register_subdev(
+       struct mxr_device *mdev, char *module_name)
+{
+       struct device_driver *drv;
+       struct v4l2_subdev *sd = NULL;
+       int ret;
+
+       /* TODO: add waiting until probe is finished */
+       drv = driver_find(module_name, &platform_bus_type);
+       if (!drv) {
+               mxr_warn(mdev, "module %s is missing\n", module_name);
+               return NULL;
+       }
+       /* driver refcnt is increased, it is safe to iterate over devices */
+       ret = driver_for_each_device(drv, NULL, &sd, find_reg_callback);
+       /* ret == 0 means that find_reg_callback was never executed */
+       if (sd == NULL) {
+               mxr_warn(mdev, "module %s provides no subdev!\n", module_name);
+               goto done;
+       }
+       /* v4l2_device_register_subdev detects if sd is NULL */
+       ret = v4l2_device_register_subdev(&mdev->v4l2_dev, sd);
+       if (ret) {
+               mxr_warn(mdev, "failed to register subdev %s\n", sd->name);
+               sd = NULL;
+       }
+
+done:
+       put_driver(drv);
+       return sd;
+}
+
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+       struct mxr_output_conf *output_conf, int output_count)
+{
+       struct device *dev = mdev->dev;
+       struct v4l2_device *v4l2_dev = &mdev->v4l2_dev;
+       int i;
+       int ret = 0;
+       struct v4l2_subdev *sd;
+
+       strlcpy(v4l2_dev->name, dev_name(mdev->dev), sizeof(v4l2_dev->name));
+       /* prepare context for V4L2 device */
+       ret = v4l2_device_register(dev, v4l2_dev);
+       if (ret) {
+               mxr_err(mdev, "could not register v4l2 device.\n");
+               goto fail;
+       }
+
+       mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev);
+       if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
+               mxr_err(mdev, "could not acquire vb2 allocator\n");
+               goto fail_v4l2_dev;
+       }
+
+       /* registering outputs */
+       mdev->output_cnt = 0;
+       for (i = 0; i < output_count; ++i) {
+               struct mxr_output_conf *conf = &output_conf[i];
+               struct mxr_output *out;
+
+               sd = find_and_register_subdev(mdev, conf->module_name);
+               /* trying to register next output */
+               if (sd == NULL)
+                       continue;
+               out = kzalloc(sizeof *out, GFP_KERNEL);
+               if (out == NULL) {
+                       mxr_err(mdev, "no memory for '%s'\n",
+                               conf->output_name);
+                       ret = -ENOMEM;
+                       /* registered subdevs are removed in fail_v4l2_dev */
+                       goto fail_output;
+               }
+               strlcpy(out->name, conf->output_name, sizeof(out->name));
+               out->sd = sd;
+               out->cookie = conf->cookie;
+               mdev->output[mdev->output_cnt++] = out;
+               mxr_info(mdev, "added output '%s' from module '%s'\n",
+                       conf->output_name, conf->module_name);
+               /* checking if maximal number of outputs is reached */
+               if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
+                       break;
+       }
+
+       if (mdev->output_cnt == 0) {
+               mxr_err(mdev, "failed to register any output\n");
+               ret = -ENODEV;
+               /* skipping fail_output because there is nothing to free */
+               goto fail_vb2_allocator;
+       }
+
+       return 0;
+
+fail_output:
+       /* kfree is NULL-safe */
+       for (i = 0; i < mdev->output_cnt; ++i)
+               kfree(mdev->output[i]);
+       memset(mdev->output, 0, sizeof mdev->output);
+
+fail_vb2_allocator:
+       /* freeing allocator context */
+       vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+
+fail_v4l2_dev:
+       /* NOTE: automatically unregister all subdevs */
+       v4l2_device_unregister(v4l2_dev);
+
+fail:
+       return ret;
+}
+
+void __devexit mxr_release_video(struct mxr_device *mdev)
+{
+       int i;
+
+       /* kfree is NULL-safe */
+       for (i = 0; i < mdev->output_cnt; ++i)
+               kfree(mdev->output[i]);
+
+       vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx);
+       v4l2_device_unregister(&mdev->v4l2_dev);
+}
+
+static int mxr_querycap(struct file *file, void *priv,
+       struct v4l2_capability *cap)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
+       strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
+       sprintf(cap->bus_info, "%d", layer->idx);
+       cap->version = KERNEL_VERSION(0, 1, 0);
+       cap->capabilities = V4L2_CAP_STREAMING |
+               V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+       return 0;
+}
+
+/* Geometry handling */
+static void mxr_layer_geo_fix(struct mxr_layer *layer)
+{
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_mbus_framefmt mbus_fmt;
+
+       /* TODO: add some dirty flag to avoid unnecessary adjustments */
+       mxr_get_mbus_fmt(mdev, &mbus_fmt);
+       layer->geo.dst.full_width = mbus_fmt.width;
+       layer->geo.dst.full_height = mbus_fmt.height;
+       layer->geo.dst.field = mbus_fmt.field;
+       layer->ops.fix_geometry(layer);
+}
+
+static void mxr_layer_default_geo(struct mxr_layer *layer)
+{
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_mbus_framefmt mbus_fmt;
+
+       memset(&layer->geo, 0, sizeof layer->geo);
+
+       mxr_get_mbus_fmt(mdev, &mbus_fmt);
+
+       layer->geo.dst.full_width = mbus_fmt.width;
+       layer->geo.dst.full_height = mbus_fmt.height;
+       layer->geo.dst.width = layer->geo.dst.full_width;
+       layer->geo.dst.height = layer->geo.dst.full_height;
+       layer->geo.dst.field = mbus_fmt.field;
+
+       layer->geo.src.full_width = mbus_fmt.width;
+       layer->geo.src.full_height = mbus_fmt.height;
+       layer->geo.src.width = layer->geo.src.full_width;
+       layer->geo.src.height = layer->geo.src.full_height;
+
+       layer->ops.fix_geometry(layer);
+}
+
+static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
+{
+       mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
+               geo->src.full_width, geo->src.full_height);
+       mxr_dbg(mdev, "src.size = (%u, %u)\n",
+               geo->src.width, geo->src.height);
+       mxr_dbg(mdev, "src.offset = (%u, %u)\n",
+               geo->src.x_offset, geo->src.y_offset);
+       mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
+               geo->dst.full_width, geo->dst.full_height);
+       mxr_dbg(mdev, "dst.size = (%u, %u)\n",
+               geo->dst.width, geo->dst.height);
+       mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
+               geo->dst.x_offset, geo->dst.y_offset);
+       mxr_dbg(mdev, "ratio = (%u, %u)\n",
+               geo->x_ratio, geo->y_ratio);
+}
+
+
+static const struct mxr_format *find_format_by_fourcc(
+       struct mxr_layer *layer, unsigned long fourcc);
+static const struct mxr_format *find_format_by_index(
+       struct mxr_layer *layer, unsigned long index);
+
+static int mxr_enum_fmt(struct file *file, void  *priv,
+       struct v4l2_fmtdesc *f)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       const struct mxr_format *fmt;
+
+       mxr_dbg(mdev, "%s\n", __func__);
+       fmt = find_format_by_index(layer, f->index);
+       if (fmt == NULL)
+               return -EINVAL;
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+
+       return 0;
+}
+
+static int mxr_s_fmt(struct file *file, void *priv,
+       struct v4l2_format *f)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       const struct mxr_format *fmt;
+       struct v4l2_pix_format_mplane *pix;
+       struct mxr_device *mdev = layer->mdev;
+       struct mxr_geometry *geo = &layer->geo;
+
+       mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+
+       pix = &f->fmt.pix_mp;
+       fmt = find_format_by_fourcc(layer, pix->pixelformat);
+       if (fmt == NULL) {
+               mxr_warn(mdev, "not recognized fourcc: %08x\n",
+                       pix->pixelformat);
+               return -EINVAL;
+       }
+       layer->fmt = fmt;
+       geo->src.full_width = pix->width;
+       geo->src.width = pix->width;
+       geo->src.full_height = pix->height;
+       geo->src.height = pix->height;
+       /* assure consistency of geometry */
+       mxr_layer_geo_fix(layer);
+       mxr_dbg(mdev, "width=%u height=%u span=%u\n",
+               geo->src.width, geo->src.height, geo->src.full_width);
+
+       return 0;
+}
+
+static unsigned int divup(unsigned int divident, unsigned int divisor)
+{
+       return (divident + divisor - 1) / divisor;
+}
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+       unsigned int width, unsigned int height)
+{
+       unsigned int bl_width = divup(width, blk->width);
+       unsigned int bl_height = divup(height, blk->height);
+
+       return bl_width * bl_height * blk->size;
+}
+
+static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
+       const struct mxr_format *fmt, u32 width, u32 height)
+{
+       int i;
+
+       memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
+       for (i = 0; i < fmt->num_planes; ++i) {
+               struct v4l2_plane_pix_format *plane = planes
+                       + fmt->plane2subframe[i];
+               const struct mxr_block *blk = &fmt->plane[i];
+               u32 bl_width = divup(width, blk->width);
+               u32 bl_height = divup(height, blk->height);
+               u32 sizeimage = bl_width * bl_height * blk->size;
+               u16 bytesperline = bl_width * blk->size / blk->height;
+
+               plane->sizeimage += sizeimage;
+               plane->bytesperline = max(plane->bytesperline, bytesperline);
+       }
+}
+
+static int mxr_g_fmt(struct file *file, void *priv,
+                            struct v4l2_format *f)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       pix->width = layer->geo.src.full_width;
+       pix->height = layer->geo.src.full_height;
+       pix->field = V4L2_FIELD_NONE;
+       pix->pixelformat = layer->fmt->fourcc;
+       pix->colorspace = layer->fmt->colorspace;
+       mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);
+
+       return 0;
+}
+
+static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo,
+       enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               return &geo->dst;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               return &geo->src;
+       default:
+               return NULL;
+       }
+}
+
+static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_crop *crop;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       crop = choose_crop_by_type(&layer->geo, a->type);
+       if (crop == NULL)
+               return -EINVAL;
+       mxr_layer_geo_fix(layer);
+       a->c.left = crop->x_offset;
+       a->c.top = crop->y_offset;
+       a->c.width = crop->width;
+       a->c.height = crop->height;
+       return 0;
+}
+
+static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_crop *crop;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       crop = choose_crop_by_type(&layer->geo, a->type);
+       if (crop == NULL)
+               return -EINVAL;
+       crop->x_offset = a->c.left;
+       crop->y_offset = a->c.top;
+       crop->width = a->c.width;
+       crop->height = a->c.height;
+       mxr_layer_geo_fix(layer);
+       return 0;
+}
+
+static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_crop *crop;
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       crop = choose_crop_by_type(&layer->geo, a->type);
+       if (crop == NULL)
+               return -EINVAL;
+       mxr_layer_geo_fix(layer);
+       a->bounds.left = 0;
+       a->bounds.top = 0;
+       a->bounds.width = crop->full_width;
+       a->bounds.top = crop->full_height;
+       a->defrect = a->bounds;
+       /* setting pixel aspect to 1/1 */
+       a->pixelaspect.numerator = 1;
+       a->pixelaspect.denominator = 1;
+       return 0;
+}
+
+static int mxr_enum_dv_presets(struct file *file, void *fh,
+       struct v4l2_dv_enum_preset *preset)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+       ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_dv_preset(struct file *file, void *fh,
+       struct v4l2_dv_preset *preset)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+
+       /* preset change cannot be done while there is an entity
+        * dependant on output configuration
+        */
+       if (mdev->n_output > 0) {
+               mutex_unlock(&mdev->mutex);
+               return -EBUSY;
+       }
+
+       ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
+
+       mutex_unlock(&mdev->mutex);
+
+       /* any failure should return EINVAL according to V4L2 doc */
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_dv_preset(struct file *file, void *fh,
+       struct v4l2_dv_preset *preset)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+       ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+
+       /* standard change cannot be done while there is an entity
+        * dependant on output configuration
+        */
+       if (mdev->n_output > 0) {
+               mutex_unlock(&mdev->mutex);
+               return -EBUSY;
+       }
+
+       ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
+
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       /* lock protects from changing sd_out */
+       mutex_lock(&mdev->mutex);
+       ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm);
+       mutex_unlock(&mdev->mutex);
+
+       return ret ? -EINVAL : 0;
+}
+
+static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       struct mxr_output *out;
+       struct v4l2_subdev *sd;
+
+       if (a->index >= mdev->output_cnt)
+               return -EINVAL;
+       out = mdev->output[a->index];
+       BUG_ON(out == NULL);
+       sd = out->sd;
+       strlcpy(a->name, out->name, sizeof(a->name));
+
+       /* try to obtain supported tv norms */
+       v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
+       a->capabilities = 0;
+       if (sd->ops->video && sd->ops->video->s_dv_preset)
+               a->capabilities |= V4L2_OUT_CAP_PRESETS;
+       if (sd->ops->video && sd->ops->video->s_std_output)
+               a->capabilities |= V4L2_OUT_CAP_STD;
+       a->type = V4L2_OUTPUT_TYPE_ANALOG;
+
+       return 0;
+}
+
+static int mxr_s_output(struct file *file, void *fh, unsigned int i)
+{
+       struct video_device *vfd = video_devdata(file);
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret = 0;
+
+       if (i >= mdev->output_cnt || mdev->output[i] == NULL)
+               return -EINVAL;
+
+       mutex_lock(&mdev->mutex);
+       if (mdev->n_output > 0) {
+               ret = -EBUSY;
+               goto done;
+       }
+       mdev->current_output = i;
+       vfd->tvnorms = 0;
+       v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
+               &vfd->tvnorms);
+       mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
+
+done:
+       mutex_unlock(&mdev->mutex);
+       return ret;
+}
+
+static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+
+       mutex_lock(&mdev->mutex);
+       *p = mdev->current_output;
+       mutex_unlock(&mdev->mutex);
+
+       return 0;
+}
+
+static int mxr_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_reqbufs(&layer->vb_queue, p);
+}
+
+static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_querybuf(&layer->vb_queue, p);
+}
+
+static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d(%d)\n", __func__, __LINE__, p->index);
+       return vb2_qbuf(&layer->vb_queue, p);
+}
+
+static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
+}
+
+static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_streamon(&layer->vb_queue, i);
+}
+
+static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       return vb2_streamoff(&layer->vb_queue, i);
+}
+
+static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
+       .vidioc_querycap = mxr_querycap,
+       /* format handling */
+       .vidioc_enum_fmt_vid_out = mxr_enum_fmt,
+       .vidioc_s_fmt_vid_out_mplane = mxr_s_fmt,
+       .vidioc_g_fmt_vid_out_mplane = mxr_g_fmt,
+       /* buffer control */
+       .vidioc_reqbufs = mxr_reqbufs,
+       .vidioc_querybuf = mxr_querybuf,
+       .vidioc_qbuf = mxr_qbuf,
+       .vidioc_dqbuf = mxr_dqbuf,
+       /* Streaming control */
+       .vidioc_streamon = mxr_streamon,
+       .vidioc_streamoff = mxr_streamoff,
+       /* Preset functions */
+       .vidioc_enum_dv_presets = mxr_enum_dv_presets,
+       .vidioc_s_dv_preset = mxr_s_dv_preset,
+       .vidioc_g_dv_preset = mxr_g_dv_preset,
+       /* analog TV standard functions */
+       .vidioc_s_std = mxr_s_std,
+       .vidioc_g_std = mxr_g_std,
+       /* Output handling */
+       .vidioc_enum_output = mxr_enum_output,
+       .vidioc_s_output = mxr_s_output,
+       .vidioc_g_output = mxr_g_output,
+       /* Crop ioctls */
+       .vidioc_g_crop = mxr_g_crop,
+       .vidioc_s_crop = mxr_s_crop,
+       .vidioc_cropcap = mxr_cropcap,
+};
+
+static int mxr_video_open(struct file *file)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+       struct mxr_device *mdev = layer->mdev;
+       int ret = 0;
+
+       mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+       /* assure device probe is finished */
+       wait_for_device_probe();
+       /* creating context for file descriptor */
+       ret = v4l2_fh_open(file);
+       if (ret) {
+               mxr_err(mdev, "v4l2_fh_open failed\n");
+               return ret;
+       }
+
+       /* leaving if layer is already initialized */
+       if (!v4l2_fh_is_singular_file(file))
+               return 0;
+
+       /* FIXME: should power be enabled on open? */
+       ret = mxr_power_get(mdev);
+       if (ret) {
+               mxr_err(mdev, "power on failed\n");
+               goto fail_fh_open;
+       }
+
+       ret = vb2_queue_init(&layer->vb_queue);
+       if (ret != 0) {
+               mxr_err(mdev, "failed to initialize vb2 queue\n");
+               goto fail_power;
+       }
+       /* set default format, first on the list */
+       layer->fmt = layer->fmt_array[0];
+       /* setup default geometry */
+       mxr_layer_default_geo(layer);
+
+       return 0;
+
+fail_power:
+       mxr_power_put(mdev);
+
+fail_fh_open:
+       v4l2_fh_release(file);
+
+       return ret;
+}
+
+static unsigned int
+mxr_video_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       return vb2_poll(&layer->vb_queue, file, wait);
+}
+
+static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+       return vb2_mmap(&layer->vb_queue, vma);
+}
+
+static int mxr_video_release(struct file *file)
+{
+       struct mxr_layer *layer = video_drvdata(file);
+
+       mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       if (v4l2_fh_is_singular_file(file)) {
+               vb2_queue_release(&layer->vb_queue);
+               mxr_power_put(layer->mdev);
+       }
+       v4l2_fh_release(file);
+       return 0;
+}
+
+static const struct v4l2_file_operations mxr_fops = {
+       .owner = THIS_MODULE,
+       .open = mxr_video_open,
+       .poll = mxr_video_poll,
+       .mmap = mxr_video_mmap,
+       .release = mxr_video_release,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+       unsigned int *nplanes, unsigned long sizes[],
+       void *alloc_ctxs[])
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+       const struct mxr_format *fmt = layer->fmt;
+       int i;
+       struct mxr_device *mdev = layer->mdev;
+       struct v4l2_plane_pix_format planes[3];
+
+       mxr_dbg(mdev, "%s\n", __func__);
+       /* checking if format was configured */
+       if (fmt == NULL)
+               return -EINVAL;
+       mxr_dbg(mdev, "fmt = %s\n", fmt->name);
+       mxr_mplane_fill(planes, fmt, layer->geo.src.full_width,
+               layer->geo.src.full_height);
+
+       *nplanes = fmt->num_subframes;
+       for (i = 0; i < fmt->num_subframes; ++i) {
+               alloc_ctxs[i] = layer->mdev->alloc_ctx;
+               sizes[i] = PAGE_ALIGN(planes[i].sizeimage);
+               mxr_dbg(mdev, "size[%d] = %08lx\n", i, sizes[i]);
+       }
+
+       if (*nbuffers == 0)
+               *nbuffers = 1;
+
+       return 0;
+}
+
+static void buf_queue(struct vb2_buffer *vb)
+{
+       struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
+       struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
+       struct mxr_device *mdev = layer->mdev;
+       unsigned long flags;
+       int must_start = 0;
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+       if (layer->state == MXR_LAYER_STREAMING_START) {
+               layer->state = MXR_LAYER_STREAMING;
+               must_start = 1;
+       }
+       list_add_tail(&buffer->list, &layer->enq_list);
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+       if (must_start) {
+               layer->ops.stream_set(layer, MXR_ENABLE);
+               mxr_streamer_get(mdev);
+       }
+
+       mxr_dbg(mdev, "queuing buffer\n");
+}
+
+static void wait_lock(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+       mxr_dbg(layer->mdev, "%s\n", __func__);
+       mutex_lock(&layer->mutex);
+}
+
+static void wait_unlock(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+       mxr_dbg(layer->mdev, "%s\n", __func__);
+       mutex_unlock(&layer->mutex);
+}
+
+static int start_streaming(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+       struct mxr_device *mdev = layer->mdev;
+       unsigned long flags;
+
+       mxr_dbg(mdev, "%s\n", __func__);
+       /* block any changes in output configuration */
+       mxr_output_get(mdev);
+
+       /* update layers geometry */
+       mxr_layer_geo_fix(layer);
+       mxr_geometry_dump(mdev, &layer->geo);
+
+       layer->ops.format_set(layer);
+       /* enabling layer in hardware */
+       spin_lock_irqsave(&layer->enq_slock, flags);
+       layer->state = MXR_LAYER_STREAMING_START;
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       return 0;
+}
+
+static void mxr_watchdog(unsigned long arg)
+{
+       struct mxr_layer *layer = (struct mxr_layer *) arg;
+       struct mxr_device *mdev = layer->mdev;
+       unsigned long flags;
+
+       mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name);
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+
+       if (layer->update_buf == layer->shadow_buf)
+               layer->update_buf = NULL;
+       if (layer->update_buf) {
+               vb2_buffer_done(&layer->update_buf->vb, VB2_BUF_STATE_ERROR);
+               layer->update_buf = NULL;
+       }
+       if (layer->shadow_buf) {
+               vb2_buffer_done(&layer->shadow_buf->vb, VB2_BUF_STATE_ERROR);
+               layer->shadow_buf = NULL;
+       }
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+}
+
+static int stop_streaming(struct vb2_queue *vq)
+{
+       struct mxr_layer *layer = vb2_get_drv_priv(vq);
+       struct mxr_device *mdev = layer->mdev;
+       unsigned long flags;
+       struct timer_list watchdog;
+       struct mxr_buffer *buf, *buf_tmp;
+
+       mxr_dbg(mdev, "%s\n", __func__);
+
+       spin_lock_irqsave(&layer->enq_slock, flags);
+
+       /* reset list */
+       layer->state = MXR_LAYER_STREAMING_FINISH;
+
+       /* set all buffer to be done */
+       list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) {
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       /* give 1 seconds to complete to complete last buffers */
+       setup_timer_on_stack(&watchdog, mxr_watchdog,
+               (unsigned long)layer);
+       mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000));
+
+       /* wait until all buffers are goes to done state */
+       vb2_wait_for_all_buffers(vq);
+
+       /* stop timer if all synchronization is done */
+       del_timer_sync(&watchdog);
+       destroy_timer_on_stack(&watchdog);
+
+       /* stopping hardware */
+       spin_lock_irqsave(&layer->enq_slock, flags);
+       layer->state = MXR_LAYER_IDLE;
+       spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+       /* disabling layer in hardware */
+       layer->ops.stream_set(layer, MXR_DISABLE);
+       /* remove one streamer */
+       mxr_streamer_put(mdev);
+       /* allow changes in output configuration */
+       mxr_output_put(mdev);
+       return 0;
+}
+
+static struct vb2_ops mxr_video_qops = {
+       .queue_setup = queue_setup,
+       .buf_queue = buf_queue,
+       .wait_prepare = wait_unlock,
+       .wait_finish = wait_lock,
+       .start_streaming = start_streaming,
+       .stop_streaming = stop_streaming,
+};
+
+/* FIXME: try to put this functions to mxr_base_layer_create */
+int mxr_base_layer_register(struct mxr_layer *layer)
+{
+       struct mxr_device *mdev = layer->mdev;
+       int ret;
+
+       ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER, -1);
+       if (ret)
+               mxr_err(mdev, "failed to register video device\n");
+       else
+               mxr_info(mdev, "registered layer %s as /dev/video%d\n",
+                       layer->vfd.name, layer->vfd.num);
+       return ret;
+}
+
+void mxr_base_layer_unregister(struct mxr_layer *layer)
+{
+       video_unregister_device(&layer->vfd);
+}
+
+void mxr_layer_release(struct mxr_layer *layer)
+{
+       if (layer->ops.release)
+               layer->ops.release(layer);
+}
+
+void mxr_base_layer_release(struct mxr_layer *layer)
+{
+       kfree(layer);
+}
+
+static void mxr_vfd_release(struct video_device *vdev)
+{
+       printk(KERN_INFO "video device release\n");
+}
+
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+       int idx, char *name, struct mxr_layer_ops *ops)
+{
+       struct mxr_layer *layer;
+
+       layer = kzalloc(sizeof *layer, GFP_KERNEL);
+       if (layer == NULL) {
+               mxr_err(mdev, "not enough memory for layer.\n");
+               goto fail;
+       }
+
+       layer->mdev = mdev;
+       layer->idx = idx;
+       layer->ops = *ops;
+
+       spin_lock_init(&layer->enq_slock);
+       INIT_LIST_HEAD(&layer->enq_list);
+       mutex_init(&layer->mutex);
+
+       layer->vfd = (struct video_device) {
+               .minor = -1,
+               .release = mxr_vfd_release,
+               .fops = &mxr_fops,
+               .ioctl_ops = &mxr_ioctl_ops,
+       };
+       strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
+       /* let framework control PRIORITY */
+       set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
+
+       video_set_drvdata(&layer->vfd, layer);
+       layer->vfd.lock = &layer->mutex;
+       layer->vfd.v4l2_dev = &mdev->v4l2_dev;
+
+       layer->vb_queue = (struct vb2_queue) {
+               .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+               .io_modes = VB2_MMAP | VB2_USERPTR,
+               .drv_priv = layer,
+               .buf_struct_size = sizeof(struct mxr_buffer),
+               .ops = &mxr_video_qops,
+               .mem_ops = &vb2_dma_contig_memops,
+       };
+
+       return layer;
+
+fail:
+       return NULL;
+}
+
+static const struct mxr_format *find_format_by_fourcc(
+       struct mxr_layer *layer, unsigned long fourcc)
+{
+       int i;
+
+       for (i = 0; i < layer->fmt_array_size; ++i)
+               if (layer->fmt_array[i]->fourcc == fourcc)
+                       return layer->fmt_array[i];
+       return NULL;
+}
+
+static const struct mxr_format *find_format_by_index(
+       struct mxr_layer *layer, unsigned long index)
+{
+       if (index >= layer->fmt_array_size)
+               return NULL;
+       return layer->fmt_array[index];
+}
+
diff --git a/drivers/media/video/s5p-tv/mixer_vp_layer.c b/drivers/media/video/s5p-tv/mixer_vp_layer.c
new file mode 100644 (file)
index 0000000..6950ed8
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include "regs-vp.h"
+
+#include <media/videobuf2-dma-contig.h>
+
+/* FORMAT DEFINITIONS */
+static const struct mxr_format mxr_fmt_nv12 = {
+       .name = "NV12",
+       .fourcc = V4L2_PIX_FMT_NV12,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 1, .height = 1, .size = 1 },
+               { .width = 2, .height = 2, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv21 = {
+       .name = "NV21",
+       .fourcc = V4L2_PIX_FMT_NV21,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 1, .height = 1, .size = 1 },
+               { .width = 2, .height = 2, .size = 2 },
+       },
+       .num_subframes = 1,
+       .cookie = VP_MODE_NV21 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12m = {
+       .name = "NV12 (mplane)",
+       .fourcc = V4L2_PIX_FMT_NV12M,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 1, .height = 1, .size = 1 },
+               { .width = 2, .height = 2, .size = 2 },
+       },
+       .num_subframes = 2,
+       .plane2subframe = {0, 1},
+       .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12mt = {
+       .name = "NV12 tiled (mplane)",
+       .fourcc = V4L2_PIX_FMT_NV12MT,
+       .colorspace = V4L2_COLORSPACE_JPEG,
+       .num_planes = 2,
+       .plane = {
+               { .width = 128, .height = 32, .size = 4096 },
+               { .width = 128, .height = 32, .size = 2048 },
+       },
+       .num_subframes = 2,
+       .plane2subframe = {0, 1},
+       .cookie = VP_MODE_NV12 | VP_MODE_MEM_TILED,
+};
+
+static const struct mxr_format *mxr_video_format[] = {
+       &mxr_fmt_nv12,
+       &mxr_fmt_nv21,
+       &mxr_fmt_nv12m,
+       &mxr_fmt_nv12mt,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_vp_layer_release(struct mxr_layer *layer)
+{
+       mxr_base_layer_unregister(layer);
+       mxr_base_layer_release(layer);
+}
+
+static void mxr_vp_buffer_set(struct mxr_layer *layer,
+       struct mxr_buffer *buf)
+{
+       dma_addr_t luma_addr[2] = {0, 0};
+       dma_addr_t chroma_addr[2] = {0, 0};
+
+       if (buf == NULL) {
+               mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
+               return;
+       }
+       luma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 0);
+       if (layer->fmt->num_subframes == 2) {
+               chroma_addr[0] = vb2_dma_contig_plane_paddr(&buf->vb, 1);
+       } else {
+               /* FIXME: mxr_get_plane_size compute integer division,
+                * which is slow and should not be performed in interrupt */
+               chroma_addr[0] = luma_addr[0] + mxr_get_plane_size(
+                       &layer->fmt->plane[0], layer->geo.src.full_width,
+                       layer->geo.src.full_height);
+       }
+       if (layer->fmt->cookie & VP_MODE_MEM_TILED) {
+               luma_addr[1] = luma_addr[0] + 0x40;
+               chroma_addr[1] = chroma_addr[0] + 0x40;
+       } else {
+               luma_addr[1] = luma_addr[0] + layer->geo.src.full_width;
+               chroma_addr[1] = chroma_addr[0];
+       }
+       mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
+}
+
+static void mxr_vp_stream_set(struct mxr_layer *layer, int en)
+{
+       mxr_reg_vp_layer_stream(layer->mdev, en);
+}
+
+static void mxr_vp_format_set(struct mxr_layer *layer)
+{
+       mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
+}
+
+static void mxr_vp_fix_geometry(struct mxr_layer *layer)
+{
+       struct mxr_geometry *geo = &layer->geo;
+
+       /* align horizontal size to 8 pixels */
+       geo->src.full_width = ALIGN(geo->src.full_width, 8);
+       /* limit to boundary size */
+       geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
+       geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
+       geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
+       geo->src.width = min(geo->src.width, 2047U);
+       geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
+       geo->src.height = min(geo->src.height, 2047U);
+
+       /* setting size of output window */
+       geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
+       geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);
+
+       /* ensure that scaling is in range 1/4x to 16x */
+       if (geo->src.width >= 4 * geo->dst.width)
+               geo->src.width = 4 * geo->dst.width;
+       if (geo->dst.width >= 16 * geo->src.width)
+               geo->dst.width = 16 * geo->src.width;
+       if (geo->src.height >= 4 * geo->dst.height)
+               geo->src.height = 4 * geo->dst.height;
+       if (geo->dst.height >= 16 * geo->src.height)
+               geo->dst.height = 16 * geo->src.height;
+
+       /* setting scaling ratio */
+       geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
+       geo->y_ratio = (geo->src.height << 16) / geo->dst.height;
+
+       /* adjust offsets */
+       geo->src.x_offset = min(geo->src.x_offset,
+               geo->src.full_width - geo->src.width);
+       geo->src.y_offset = min(geo->src.y_offset,
+               geo->src.full_height - geo->src.height);
+       geo->dst.x_offset = min(geo->dst.x_offset,
+               geo->dst.full_width - geo->dst.width);
+       geo->dst.y_offset = min(geo->dst.y_offset,
+               geo->dst.full_height - geo->dst.height);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx)
+{
+       struct mxr_layer *layer;
+       int ret;
+       struct mxr_layer_ops ops = {
+               .release = mxr_vp_layer_release,
+               .buffer_set = mxr_vp_buffer_set,
+               .stream_set = mxr_vp_stream_set,
+               .format_set = mxr_vp_format_set,
+               .fix_geometry = mxr_vp_fix_geometry,
+       };
+       char name[32];
+
+       sprintf(name, "video%d", idx);
+
+       layer = mxr_base_layer_create(mdev, idx, name, &ops);
+       if (layer == NULL) {
+               mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+               goto fail;
+       }
+
+       layer->fmt_array = mxr_video_format;
+       layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
+
+       ret = mxr_base_layer_register(layer);
+       if (ret)
+               goto fail_layer;
+
+       return layer;
+
+fail_layer:
+       mxr_base_layer_release(layer);
+
+fail:
+       return NULL;
+}
+
diff --git a/drivers/media/video/s5p-tv/regs-hdmi.h b/drivers/media/video/s5p-tv/regs-hdmi.h
new file mode 100644 (file)
index 0000000..ac93ad6
--- /dev/null
@@ -0,0 +1,141 @@
+/* linux/arch/arm/mach-exynos4/include/mach/regs-hdmi.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * HDMI register header file for Samsung TVOUT driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef SAMSUNG_REGS_HDMI_H
+#define SAMSUNG_REGS_HDMI_H
+
+/*
+ * Register part
+*/
+
+#define HDMI_CTRL_BASE(x)              ((x) + 0x00000000)
+#define HDMI_CORE_BASE(x)              ((x) + 0x00010000)
+#define HDMI_TG_BASE(x)                        ((x) + 0x00050000)
+
+/* Control registers */
+#define HDMI_INTC_CON                  HDMI_CTRL_BASE(0x0000)
+#define HDMI_INTC_FLAG                 HDMI_CTRL_BASE(0x0004)
+#define HDMI_HPD_STATUS                        HDMI_CTRL_BASE(0x000C)
+#define HDMI_PHY_RSTOUT                        HDMI_CTRL_BASE(0x0014)
+#define HDMI_PHY_VPLL                  HDMI_CTRL_BASE(0x0018)
+#define HDMI_PHY_CMU                   HDMI_CTRL_BASE(0x001C)
+#define HDMI_CORE_RSTOUT               HDMI_CTRL_BASE(0x0020)
+
+/* Core registers */
+#define HDMI_CON_0                     HDMI_CORE_BASE(0x0000)
+#define HDMI_CON_1                     HDMI_CORE_BASE(0x0004)
+#define HDMI_CON_2                     HDMI_CORE_BASE(0x0008)
+#define HDMI_SYS_STATUS                        HDMI_CORE_BASE(0x0010)
+#define HDMI_PHY_STATUS                        HDMI_CORE_BASE(0x0014)
+#define HDMI_STATUS_EN                 HDMI_CORE_BASE(0x0020)
+#define HDMI_HPD                       HDMI_CORE_BASE(0x0030)
+#define HDMI_MODE_SEL                  HDMI_CORE_BASE(0x0040)
+#define HDMI_BLUE_SCREEN_0             HDMI_CORE_BASE(0x0050)
+#define HDMI_BLUE_SCREEN_1             HDMI_CORE_BASE(0x0054)
+#define HDMI_BLUE_SCREEN_2             HDMI_CORE_BASE(0x0058)
+#define HDMI_H_BLANK_0                 HDMI_CORE_BASE(0x00A0)
+#define HDMI_H_BLANK_1                 HDMI_CORE_BASE(0x00A4)
+#define HDMI_V_BLANK_0                 HDMI_CORE_BASE(0x00B0)
+#define HDMI_V_BLANK_1                 HDMI_CORE_BASE(0x00B4)
+#define HDMI_V_BLANK_2                 HDMI_CORE_BASE(0x00B8)
+#define HDMI_H_V_LINE_0                        HDMI_CORE_BASE(0x00C0)
+#define HDMI_H_V_LINE_1                        HDMI_CORE_BASE(0x00C4)
+#define HDMI_H_V_LINE_2                        HDMI_CORE_BASE(0x00C8)
+#define HDMI_VSYNC_POL                 HDMI_CORE_BASE(0x00E4)
+#define HDMI_INT_PRO_MODE              HDMI_CORE_BASE(0x00E8)
+#define HDMI_V_BLANK_F_0               HDMI_CORE_BASE(0x0110)
+#define HDMI_V_BLANK_F_1               HDMI_CORE_BASE(0x0114)
+#define HDMI_V_BLANK_F_2               HDMI_CORE_BASE(0x0118)
+#define HDMI_H_SYNC_GEN_0              HDMI_CORE_BASE(0x0120)
+#define HDMI_H_SYNC_GEN_1              HDMI_CORE_BASE(0x0124)
+#define HDMI_H_SYNC_GEN_2              HDMI_CORE_BASE(0x0128)
+#define HDMI_V_SYNC_GEN_1_0            HDMI_CORE_BASE(0x0130)
+#define HDMI_V_SYNC_GEN_1_1            HDMI_CORE_BASE(0x0134)
+#define HDMI_V_SYNC_GEN_1_2            HDMI_CORE_BASE(0x0138)
+#define HDMI_V_SYNC_GEN_2_0            HDMI_CORE_BASE(0x0140)
+#define HDMI_V_SYNC_GEN_2_1            HDMI_CORE_BASE(0x0144)
+#define HDMI_V_SYNC_GEN_2_2            HDMI_CORE_BASE(0x0148)
+#define HDMI_V_SYNC_GEN_3_0            HDMI_CORE_BASE(0x0150)
+#define HDMI_V_SYNC_GEN_3_1            HDMI_CORE_BASE(0x0154)
+#define HDMI_V_SYNC_GEN_3_2            HDMI_CORE_BASE(0x0158)
+#define HDMI_AVI_CON                   HDMI_CORE_BASE(0x0300)
+#define HDMI_AVI_BYTE(n)               HDMI_CORE_BASE(0x0320 + 4 * (n))
+#define        HDMI_DC_CONTROL                 HDMI_CORE_BASE(0x05C0)
+#define HDMI_VIDEO_PATTERN_GEN         HDMI_CORE_BASE(0x05C4)
+#define HDMI_HPD_GEN                   HDMI_CORE_BASE(0x05C8)
+
+/* Timing generator registers */
+#define HDMI_TG_CMD                    HDMI_TG_BASE(0x0000)
+#define HDMI_TG_H_FSZ_L                        HDMI_TG_BASE(0x0018)
+#define HDMI_TG_H_FSZ_H                        HDMI_TG_BASE(0x001C)
+#define HDMI_TG_HACT_ST_L              HDMI_TG_BASE(0x0020)
+#define HDMI_TG_HACT_ST_H              HDMI_TG_BASE(0x0024)
+#define HDMI_TG_HACT_SZ_L              HDMI_TG_BASE(0x0028)
+#define HDMI_TG_HACT_SZ_H              HDMI_TG_BASE(0x002C)
+#define HDMI_TG_V_FSZ_L                        HDMI_TG_BASE(0x0030)
+#define HDMI_TG_V_FSZ_H                        HDMI_TG_BASE(0x0034)
+#define HDMI_TG_VSYNC_L                        HDMI_TG_BASE(0x0038)
+#define HDMI_TG_VSYNC_H                        HDMI_TG_BASE(0x003C)
+#define HDMI_TG_VSYNC2_L               HDMI_TG_BASE(0x0040)
+#define HDMI_TG_VSYNC2_H               HDMI_TG_BASE(0x0044)
+#define HDMI_TG_VACT_ST_L              HDMI_TG_BASE(0x0048)
+#define HDMI_TG_VACT_ST_H              HDMI_TG_BASE(0x004C)
+#define HDMI_TG_VACT_SZ_L              HDMI_TG_BASE(0x0050)
+#define HDMI_TG_VACT_SZ_H              HDMI_TG_BASE(0x0054)
+#define HDMI_TG_FIELD_CHG_L            HDMI_TG_BASE(0x0058)
+#define HDMI_TG_FIELD_CHG_H            HDMI_TG_BASE(0x005C)
+#define HDMI_TG_VACT_ST2_L             HDMI_TG_BASE(0x0060)
+#define HDMI_TG_VACT_ST2_H             HDMI_TG_BASE(0x0064)
+#define HDMI_TG_VSYNC_TOP_HDMI_L       HDMI_TG_BASE(0x0078)
+#define HDMI_TG_VSYNC_TOP_HDMI_H       HDMI_TG_BASE(0x007C)
+#define HDMI_TG_VSYNC_BOT_HDMI_L       HDMI_TG_BASE(0x0080)
+#define HDMI_TG_VSYNC_BOT_HDMI_H       HDMI_TG_BASE(0x0084)
+#define HDMI_TG_FIELD_TOP_HDMI_L       HDMI_TG_BASE(0x0088)
+#define HDMI_TG_FIELD_TOP_HDMI_H       HDMI_TG_BASE(0x008C)
+#define HDMI_TG_FIELD_BOT_HDMI_L       HDMI_TG_BASE(0x0090)
+#define HDMI_TG_FIELD_BOT_HDMI_H       HDMI_TG_BASE(0x0094)
+
+/*
+ * Bit definition part
+ */
+
+/* HDMI_INTC_CON */
+#define HDMI_INTC_EN_GLOBAL            (1 << 6)
+#define HDMI_INTC_EN_HPD_PLUG          (1 << 3)
+#define HDMI_INTC_EN_HPD_UNPLUG                (1 << 2)
+
+/* HDMI_INTC_FLAG */
+#define HDMI_INTC_FLAG_HPD_PLUG                (1 << 3)
+#define HDMI_INTC_FLAG_HPD_UNPLUG      (1 << 2)
+
+/* HDMI_PHY_RSTOUT */
+#define HDMI_PHY_SW_RSTOUT             (1 << 0)
+
+/* HDMI_CORE_RSTOUT */
+#define HDMI_CORE_SW_RSTOUT            (1 << 0)
+
+/* HDMI_CON_0 */
+#define HDMI_BLUE_SCR_EN               (1 << 5)
+#define HDMI_EN                                (1 << 0)
+
+/* HDMI_PHY_STATUS */
+#define HDMI_PHY_STATUS_READY          (1 << 0)
+
+/* HDMI_MODE_SEL */
+#define HDMI_MODE_HDMI_EN              (1 << 1)
+#define HDMI_MODE_DVI_EN               (1 << 0)
+#define HDMI_MODE_MASK                 (3 << 0)
+
+/* HDMI_TG_CMD */
+#define HDMI_TG_EN                     (1 << 0)
+
+#endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/media/video/s5p-tv/regs-mixer.h b/drivers/media/video/s5p-tv/regs-mixer.h
new file mode 100644 (file)
index 0000000..3c84426
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Mixer register header file for Samsung Mixer driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+#ifndef SAMSUNG_REGS_MIXER_H
+#define SAMSUNG_REGS_MIXER_H
+
+/*
+ * Register part
+ */
+#define MXR_STATUS                     0x0000
+#define MXR_CFG                                0x0004
+#define MXR_INT_EN                     0x0008
+#define MXR_INT_STATUS                 0x000C
+#define MXR_LAYER_CFG                  0x0010
+#define MXR_VIDEO_CFG                  0x0014
+#define MXR_GRAPHIC0_CFG               0x0020
+#define MXR_GRAPHIC0_BASE              0x0024
+#define MXR_GRAPHIC0_SPAN              0x0028
+#define MXR_GRAPHIC0_SXY               0x002C
+#define MXR_GRAPHIC0_WH                        0x0030
+#define MXR_GRAPHIC0_DXY               0x0034
+#define MXR_GRAPHIC0_BLANK             0x0038
+#define MXR_GRAPHIC1_CFG               0x0040
+#define MXR_GRAPHIC1_BASE              0x0044
+#define MXR_GRAPHIC1_SPAN              0x0048
+#define MXR_GRAPHIC1_SXY               0x004C
+#define MXR_GRAPHIC1_WH                        0x0050
+#define MXR_GRAPHIC1_DXY               0x0054
+#define MXR_GRAPHIC1_BLANK             0x0058
+#define MXR_BG_CFG                     0x0060
+#define MXR_BG_COLOR0                  0x0064
+#define MXR_BG_COLOR1                  0x0068
+#define MXR_BG_COLOR2                  0x006C
+
+/* for parametrized access to layer registers */
+#define MXR_GRAPHIC_CFG(i)             (0x0020 + (i) * 0x20)
+#define MXR_GRAPHIC_BASE(i)            (0x0024 + (i) * 0x20)
+#define MXR_GRAPHIC_SPAN(i)            (0x0028 + (i) * 0x20)
+#define MXR_GRAPHIC_SXY(i)             (0x002C + (i) * 0x20)
+#define MXR_GRAPHIC_WH(i)              (0x0030 + (i) * 0x20)
+#define MXR_GRAPHIC_DXY(i)             (0x0034 + (i) * 0x20)
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+#define MXR_MASK(high_bit, low_bit) \
+       (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define MXR_MASK_VAL(val, high_bit, low_bit) \
+       (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
+
+/* bits for MXR_STATUS */
+#define MXR_STATUS_16_BURST            (1 << 7)
+#define MXR_STATUS_BURST_MASK          (1 << 7)
+#define MXR_STATUS_SYNC_ENABLE         (1 << 2)
+#define MXR_STATUS_REG_RUN             (1 << 0)
+
+/* bits for MXR_CFG */
+#define MXR_CFG_OUT_YUV444             (0 << 8)
+#define MXR_CFG_OUT_RGB888             (1 << 8)
+#define MXR_CFG_DST_SDO                        (0 << 7)
+#define MXR_CFG_DST_HDMI               (1 << 7)
+#define MXR_CFG_DST_MASK               (1 << 7)
+#define MXR_CFG_SCAN_HD_720            (0 << 6)
+#define MXR_CFG_SCAN_HD_1080           (1 << 6)
+#define MXR_CFG_GRP1_ENABLE            (1 << 5)
+#define MXR_CFG_GRP0_ENABLE            (1 << 4)
+#define MXR_CFG_VP_ENABLE              (1 << 3)
+#define MXR_CFG_SCAN_INTERLACE         (0 << 2)
+#define MXR_CFG_SCAN_PROGRASSIVE       (1 << 2)
+#define MXR_CFG_SCAN_NTSC              (0 << 1)
+#define MXR_CFG_SCAN_PAL               (1 << 1)
+#define MXR_CFG_SCAN_SD                        (0 << 0)
+#define MXR_CFG_SCAN_HD                        (1 << 0)
+#define MXR_CFG_SCAN_MASK              0x47
+
+/* bits for MXR_GRAPHICn_CFG */
+#define MXR_GRP_CFG_COLOR_KEY_DISABLE  (1 << 21)
+#define MXR_GRP_CFG_BLEND_PRE_MUL      (1 << 20)
+#define MXR_GRP_CFG_FORMAT_VAL(x)      MXR_MASK_VAL(x, 11, 8)
+#define MXR_GRP_CFG_FORMAT_MASK                MXR_GRP_CFG_FORMAT_VAL(~0)
+#define MXR_GRP_CFG_ALPHA_VAL(x)       MXR_MASK_VAL(x, 7, 0)
+
+/* bits for MXR_GRAPHICn_WH */
+#define MXR_GRP_WH_H_SCALE(x)          MXR_MASK_VAL(x, 28, 28)
+#define MXR_GRP_WH_V_SCALE(x)          MXR_MASK_VAL(x, 12, 12)
+#define MXR_GRP_WH_WIDTH(x)            MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_WH_HEIGHT(x)           MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_SXY */
+#define MXR_GRP_SXY_SX(x)              MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_SXY_SY(x)              MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_DXY */
+#define MXR_GRP_DXY_DX(x)              MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_DXY_DY(x)              MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_INT_EN */
+#define MXR_INT_EN_VSYNC               (1 << 11)
+#define MXR_INT_EN_ALL                 (0x0f << 8)
+
+/* bit for MXR_INT_STATUS */
+#define MXR_INT_CLEAR_VSYNC            (1 << 11)
+#define MXR_INT_STATUS_VSYNC           (1 << 0)
+
+/* bit for MXR_LAYER_CFG */
+#define MXR_LAYER_CFG_GRP1_VAL(x)      MXR_MASK_VAL(x, 11, 8)
+#define MXR_LAYER_CFG_GRP0_VAL(x)      MXR_MASK_VAL(x, 7, 4)
+#define MXR_LAYER_CFG_VP_VAL(x)                MXR_MASK_VAL(x, 3, 0)
+
+#endif /* SAMSUNG_REGS_MIXER_H */
+
diff --git a/drivers/media/video/s5p-tv/regs-sdo.h b/drivers/media/video/s5p-tv/regs-sdo.h
new file mode 100644 (file)
index 0000000..7f7c2b8
--- /dev/null
@@ -0,0 +1,63 @@
+/* drivers/media/video/s5p-tv/regs-sdo.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * SDO register description file
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SAMSUNG_REGS_SDO_H
+#define SAMSUNG_REGS_SDO_H
+
+/*
+ * Register part
+ */
+
+#define SDO_CLKCON                     0x0000
+#define SDO_CONFIG                     0x0008
+#define SDO_VBI                                0x0014
+#define SDO_DAC                                0x003C
+#define SDO_CCCON                      0x0180
+#define SDO_IRQ                                0x0280
+#define SDO_IRQMASK                    0x0284
+#define SDO_VERSION                    0x03D8
+
+/*
+ * Bit definition part
+ */
+
+/* SDO Clock Control Register (SDO_CLKCON) */
+#define SDO_TVOUT_SW_RESET             (1 << 4)
+#define SDO_TVOUT_CLOCK_READY          (1 << 1)
+#define SDO_TVOUT_CLOCK_ON             (1 << 0)
+
+/* SDO Video Standard Configuration Register (SDO_CONFIG) */
+#define SDO_PROGRESSIVE                        (1 << 4)
+#define SDO_NTSC_M                     0
+#define SDO_PAL_M                      1
+#define SDO_PAL_BGHID                  2
+#define SDO_PAL_N                      3
+#define SDO_PAL_NC                     4
+#define SDO_NTSC_443                   8
+#define SDO_PAL_60                     9
+#define SDO_STANDARD_MASK              0xf
+
+/* SDO VBI Configuration Register (SDO_VBI) */
+#define SDO_CVBS_WSS_INS               (1 << 14)
+#define SDO_CVBS_CLOSED_CAPTION_MASK   (3 << 12)
+
+/* SDO DAC Configuration Register (SDO_DAC) */
+#define SDO_POWER_ON_DAC               (1 << 0)
+
+/* SDO Color Compensation On/Off Control (SDO_CCCON) */
+#define SDO_COMPENSATION_BHS_ADJ_OFF   (1 << 4)
+#define SDO_COMPENSATION_CVBS_COMP_OFF (1 << 0)
+
+/* SDO Interrupt Request Register (SDO_IRQ) */
+#define SDO_VSYNC_IRQ_PEND             (1 << 0)
+
+#endif /* SAMSUNG_REGS_SDO_H */
diff --git a/drivers/media/video/s5p-tv/regs-vp.h b/drivers/media/video/s5p-tv/regs-vp.h
new file mode 100644 (file)
index 0000000..6c63984
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Video processor register header file for Samsung Mixer driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SAMSUNG_REGS_VP_H
+#define SAMSUNG_REGS_VP_H
+
+/*
+ * Register part
+ */
+
+#define VP_ENABLE                      0x0000
+#define VP_SRESET                      0x0004
+#define VP_SHADOW_UPDATE               0x0008
+#define VP_FIELD_ID                    0x000C
+#define VP_MODE                                0x0010
+#define VP_IMG_SIZE_Y                  0x0014
+#define VP_IMG_SIZE_C                  0x0018
+#define VP_PER_RATE_CTRL               0x001C
+#define VP_TOP_Y_PTR                   0x0028
+#define VP_BOT_Y_PTR                   0x002C
+#define VP_TOP_C_PTR                   0x0030
+#define VP_BOT_C_PTR                   0x0034
+#define VP_ENDIAN_MODE                 0x03CC
+#define VP_SRC_H_POSITION              0x0044
+#define VP_SRC_V_POSITION              0x0048
+#define VP_SRC_WIDTH                   0x004C
+#define VP_SRC_HEIGHT                  0x0050
+#define VP_DST_H_POSITION              0x0054
+#define VP_DST_V_POSITION              0x0058
+#define VP_DST_WIDTH                   0x005C
+#define VP_DST_HEIGHT                  0x0060
+#define VP_H_RATIO                     0x0064
+#define VP_V_RATIO                     0x0068
+#define VP_POLY8_Y0_LL                 0x006C
+#define VP_POLY4_Y0_LL                 0x00EC
+#define VP_POLY4_C0_LL                 0x012C
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+
+#define VP_MASK(high_bit, low_bit) \
+       (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define VP_MASK_VAL(val, high_bit, low_bit) \
+       (((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
+
+ /* VP_ENABLE */
+#define VP_ENABLE_ON                   (1 << 0)
+
+/* VP_SRESET */
+#define VP_SRESET_PROCESSING           (1 << 0)
+
+/* VP_SHADOW_UPDATE */
+#define VP_SHADOW_UPDATE_ENABLE                (1 << 0)
+
+/* VP_MODE */
+#define VP_MODE_NV12                   (0 << 6)
+#define VP_MODE_NV21                   (1 << 6)
+#define VP_MODE_LINE_SKIP              (1 << 5)
+#define VP_MODE_MEM_LINEAR             (0 << 4)
+#define VP_MODE_MEM_TILED              (1 << 4)
+#define VP_MODE_FMT_MASK               (5 << 4)
+#define VP_MODE_FIELD_ID_AUTO_TOGGLING (1 << 2)
+#define VP_MODE_2D_IPC                 (1 << 1)
+
+/* VP_IMG_SIZE_Y */
+/* VP_IMG_SIZE_C */
+#define VP_IMG_HSIZE(x)                        VP_MASK_VAL(x, 29, 16)
+#define VP_IMG_VSIZE(x)                        VP_MASK_VAL(x, 13, 0)
+
+/* VP_SRC_H_POSITION */
+#define VP_SRC_H_POSITION_VAL(x)       VP_MASK_VAL(x, 14, 4)
+
+/* VP_ENDIAN_MODE */
+#define VP_ENDIAN_MODE_LITTLE          (1 << 0)
+
+#endif /* SAMSUNG_REGS_VP_H */
diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c
new file mode 100644 (file)
index 0000000..4dddd6b
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Samsung Standard Definition Output (SDO) driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-subdev.h>
+
+#include "regs-sdo.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
+MODULE_LICENSE("GPL");
+
+#define SDO_DEFAULT_STD        V4L2_STD_PAL
+
+struct sdo_format {
+       v4l2_std_id id;
+       /* all modes are 720 pixels wide */
+       unsigned int height;
+       unsigned int cookie;
+};
+
+struct sdo_device {
+       /** pointer to device parent */
+       struct device *dev;
+       /** base address of SDO registers */
+       void __iomem *regs;
+       /** SDO interrupt */
+       unsigned int irq;
+       /** DAC source clock */
+       struct clk *sclk_dac;
+       /** DAC clock */
+       struct clk *dac;
+       /** DAC physical interface */
+       struct clk *dacphy;
+       /** clock for control of VPLL */
+       struct clk *fout_vpll;
+       /** regulator for SDO IP power */
+       struct regulator *vdac;
+       /** regulator for SDO plug detection */
+       struct regulator *vdet;
+       /** subdev used as device interface */
+       struct v4l2_subdev sd;
+       /** current format */
+       const struct sdo_format *fmt;
+};
+
+static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct sdo_device, sd);
+}
+
+static inline
+void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
+{
+       u32 old = readl(sdev->regs + reg_id);
+       value = (value & mask) | (old & ~mask);
+       writel(value, sdev->regs + reg_id);
+}
+
+static inline
+void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
+{
+       writel(value, sdev->regs + reg_id);
+}
+
+static inline
+u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
+{
+       return readl(sdev->regs + reg_id);
+}
+
+static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
+{
+       struct sdo_device *sdev = dev_data;
+
+       /* clear interrupt */
+       sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
+       return IRQ_HANDLED;
+}
+
+static void sdo_reg_debug(struct sdo_device *sdev)
+{
+#define DBGREG(reg_id) \
+       dev_info(sdev->dev, #reg_id " = %08x\n", \
+               sdo_read(sdev, reg_id))
+
+       DBGREG(SDO_CLKCON);
+       DBGREG(SDO_CONFIG);
+       DBGREG(SDO_VBI);
+       DBGREG(SDO_DAC);
+       DBGREG(SDO_IRQ);
+       DBGREG(SDO_IRQMASK);
+       DBGREG(SDO_VERSION);
+}
+
+static const struct sdo_format sdo_format[] = {
+       { V4L2_STD_PAL_N,       .height = 576, .cookie = SDO_PAL_N },
+       { V4L2_STD_PAL_Nc,      .height = 576, .cookie = SDO_PAL_NC },
+       { V4L2_STD_PAL_M,       .height = 480, .cookie = SDO_PAL_M },
+       { V4L2_STD_PAL_60,      .height = 480, .cookie = SDO_PAL_60 },
+       { V4L2_STD_NTSC_443,    .height = 480, .cookie = SDO_NTSC_443 },
+       { V4L2_STD_PAL,         .height = 576, .cookie = SDO_PAL_BGHID },
+       { V4L2_STD_NTSC_M,      .height = 480, .cookie = SDO_NTSC_M },
+};
+
+static const struct sdo_format *sdo_find_format(v4l2_std_id id)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
+               if (sdo_format[i].id & id)
+                       return &sdo_format[i];
+       return NULL;
+}
+
+static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       *std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
+               V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
+               V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
+       return 0;
+}
+
+static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+       const struct sdo_format *fmt;
+       fmt = sdo_find_format(std);
+       if (fmt == NULL)
+               return -EINVAL;
+       sdev->fmt = fmt;
+       return 0;
+}
+
+static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+       *std = sd_to_sdev(sd)->fmt->id;
+       return 0;
+}
+
+static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
+       struct v4l2_mbus_framefmt *fmt)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       if (!sdev->fmt)
+               return -ENXIO;
+       /* all modes are 720 pixels wide */
+       fmt->width = 720;
+       fmt->height = sdev->fmt->height;
+       fmt->code = V4L2_MBUS_FMT_FIXED;
+       fmt->field = V4L2_FIELD_INTERLACED;
+       return 0;
+}
+
+static int sdo_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+       struct device *dev = sdev->dev;
+       int ret;
+
+       dev_info(dev, "sdo_s_power(%d)\n", on);
+
+       if (on)
+               ret = pm_runtime_get_sync(dev);
+       else
+               ret = pm_runtime_put_sync(dev);
+
+       /* only values < 0 indicate errors */
+       return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sdo_streamon(struct sdo_device *sdev)
+{
+       /* set proper clock for Timing Generator */
+       clk_set_rate(sdev->fout_vpll, 54000000);
+       dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
+       clk_get_rate(sdev->fout_vpll));
+       /* enable clock in SDO */
+       sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
+       clk_enable(sdev->dacphy);
+       /* enable DAC */
+       sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
+       sdo_reg_debug(sdev);
+       return 0;
+}
+
+static int sdo_streamoff(struct sdo_device *sdev)
+{
+       int tries;
+
+       sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
+       clk_disable(sdev->dacphy);
+       sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
+       for (tries = 100; tries; --tries) {
+               if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
+                       break;
+               mdelay(1);
+       }
+       if (tries == 0)
+               dev_err(sdev->dev, "failed to stop streaming\n");
+       return tries ? 0 : -EIO;
+}
+
+static int sdo_s_stream(struct v4l2_subdev *sd, int on)
+{
+       struct sdo_device *sdev = sd_to_sdev(sd);
+       return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
+}
+
+static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
+       .s_power = sdo_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
+       .s_std_output = sdo_s_std_output,
+       .g_std_output = sdo_g_std_output,
+       .g_tvnorms_output = sdo_g_tvnorms_output,
+       .g_mbus_fmt = sdo_g_mbus_fmt,
+       .s_stream = sdo_s_stream,
+};
+
+static const struct v4l2_subdev_ops sdo_sd_ops = {
+       .core = &sdo_sd_core_ops,
+       .video = &sdo_sd_video_ops,
+};
+
+static int sdo_runtime_suspend(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       dev_info(dev, "suspend\n");
+       regulator_disable(sdev->vdet);
+       regulator_disable(sdev->vdac);
+       clk_disable(sdev->sclk_dac);
+       return 0;
+}
+
+static int sdo_runtime_resume(struct device *dev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(dev);
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       dev_info(dev, "resume\n");
+       clk_enable(sdev->sclk_dac);
+       regulator_enable(sdev->vdac);
+       regulator_enable(sdev->vdet);
+
+       /* software reset */
+       sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
+       mdelay(10);
+       sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
+
+       /* setting TV mode */
+       sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
+       /* XXX: forcing interlaced mode using undocumented bit */
+       sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
+       /* turn all VBI off */
+       sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
+               SDO_CVBS_CLOSED_CAPTION_MASK);
+       /* turn all post processing off */
+       sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
+               SDO_COMPENSATION_CVBS_COMP_OFF);
+       sdo_reg_debug(sdev);
+       return 0;
+}
+
+static const struct dev_pm_ops sdo_pm_ops = {
+       .runtime_suspend = sdo_runtime_suspend,
+       .runtime_resume  = sdo_runtime_resume,
+};
+
+static int __devinit sdo_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct sdo_device *sdev;
+       struct resource *res;
+       int ret = 0;
+       struct clk *sclk_vpll;
+
+       dev_info(dev, "probe start\n");
+       sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+       if (!sdev) {
+               dev_err(dev, "not enough memory.\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+       sdev->dev = dev;
+
+       /* mapping registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "get memory resource failed.\n");
+               ret = -ENXIO;
+               goto fail_sdev;
+       }
+
+       sdev->regs = ioremap(res->start, resource_size(res));
+       if (sdev->regs == NULL) {
+               dev_err(dev, "register mapping failed.\n");
+               ret = -ENXIO;
+               goto fail_sdev;
+       }
+
+       /* acquiring interrupt */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(dev, "get interrupt resource failed.\n");
+               ret = -ENXIO;
+               goto fail_regs;
+       }
+       ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev);
+       if (ret) {
+               dev_err(dev, "request interrupt failed.\n");
+               goto fail_regs;
+       }
+       sdev->irq = res->start;
+
+       /* acquire clocks */
+       sdev->sclk_dac = clk_get(dev, "sclk_dac");
+       if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
+               dev_err(dev, "failed to get clock 'sclk_dac'\n");
+               ret = -ENXIO;
+               goto fail_irq;
+       }
+       sdev->dac = clk_get(dev, "dac");
+       if (IS_ERR_OR_NULL(sdev->dac)) {
+               dev_err(dev, "failed to get clock 'dac'\n");
+               ret = -ENXIO;
+               goto fail_sclk_dac;
+       }
+       sdev->dacphy = clk_get(dev, "dacphy");
+       if (IS_ERR_OR_NULL(sdev->dacphy)) {
+               dev_err(dev, "failed to get clock 'dacphy'\n");
+               ret = -ENXIO;
+               goto fail_dac;
+       }
+       sclk_vpll = clk_get(dev, "sclk_vpll");
+       if (IS_ERR_OR_NULL(sclk_vpll)) {
+               dev_err(dev, "failed to get clock 'sclk_vpll'\n");
+               ret = -ENXIO;
+               goto fail_dacphy;
+       }
+       clk_set_parent(sdev->sclk_dac, sclk_vpll);
+       clk_put(sclk_vpll);
+       sdev->fout_vpll = clk_get(dev, "fout_vpll");
+       if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
+               dev_err(dev, "failed to get clock 'fout_vpll'\n");
+               goto fail_dacphy;
+       }
+       dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
+
+       /* acquire regulator */
+       sdev->vdac = regulator_get(dev, "vdd33a_dac");
+       if (IS_ERR_OR_NULL(sdev->vdac)) {
+               dev_err(dev, "failed to get regulator 'vdac'\n");
+               goto fail_fout_vpll;
+       }
+       sdev->vdet = regulator_get(dev, "vdet");
+       if (IS_ERR_OR_NULL(sdev->vdet)) {
+               dev_err(dev, "failed to get regulator 'vdet'\n");
+               goto fail_vdac;
+       }
+
+       /* enable gate for dac clock, because mixer uses it */
+       clk_enable(sdev->dac);
+
+       /* configure power management */
+       pm_runtime_enable(dev);
+
+       /* configuration of interface subdevice */
+       v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
+       sdev->sd.owner = THIS_MODULE;
+       strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
+
+       /* set default format */
+       sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
+       BUG_ON(sdev->fmt == NULL);
+
+       /* keeping subdev in device's private for use by other drivers */
+       dev_set_drvdata(dev, &sdev->sd);
+
+       dev_info(dev, "probe succeeded\n");
+       return 0;
+
+fail_vdac:
+       regulator_put(sdev->vdac);
+fail_fout_vpll:
+       clk_put(sdev->fout_vpll);
+fail_dacphy:
+       clk_put(sdev->dacphy);
+fail_dac:
+       clk_put(sdev->dac);
+fail_sclk_dac:
+       clk_put(sdev->sclk_dac);
+fail_irq:
+       free_irq(sdev->irq, sdev);
+fail_regs:
+       iounmap(sdev->regs);
+fail_sdev:
+       kfree(sdev);
+fail:
+       dev_info(dev, "probe failed\n");
+       return ret;
+}
+
+static int __devexit sdo_remove(struct platform_device *pdev)
+{
+       struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
+       struct sdo_device *sdev = sd_to_sdev(sd);
+
+       pm_runtime_disable(&pdev->dev);
+       clk_disable(sdev->dac);
+       regulator_put(sdev->vdet);
+       regulator_put(sdev->vdac);
+       clk_put(sdev->fout_vpll);
+       clk_put(sdev->dacphy);
+       clk_put(sdev->dac);
+       clk_put(sdev->sclk_dac);
+       free_irq(sdev->irq, sdev);
+       iounmap(sdev->regs);
+       kfree(sdev);
+
+       dev_info(&pdev->dev, "remove successful\n");
+       return 0;
+}
+
+static struct platform_driver sdo_driver __refdata = {
+       .probe = sdo_probe,
+       .remove = __devexit_p(sdo_remove),
+       .driver = {
+               .name = "s5p-sdo",
+               .owner = THIS_MODULE,
+               .pm = &sdo_pm_ops,
+       }
+};
+
+static int __init sdo_init(void)
+{
+       int ret;
+       static const char banner[] __initdata = KERN_INFO \
+               "Samsung Standard Definition Output (SDO) driver, "
+               "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+       printk(banner);
+
+       ret = platform_driver_register(&sdo_driver);
+       if (ret)
+               printk(KERN_ERR "SDO platform driver register failed\n");
+
+       return ret;
+}
+module_init(sdo_init);
+
+static void __exit sdo_exit(void)
+{
+       platform_driver_unregister(&sdo_driver);
+}
+module_exit(sdo_exit);
index 0db90922ee93fef406380f72ca15b48827562dde..f2ae405c74ac4186b84bda12a7e8f0b5c48b6ec2 100644 (file)
@@ -757,8 +757,8 @@ static int saa711x_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
        switch (ctrl->id) {
        case V4L2_CID_CHROMA_AGC:
                /* chroma gain cluster */
-               if (state->agc->cur.val)
-                       state->gain->cur.val =
+               if (state->agc->val)
+                       state->gain->val =
                                saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL) & 0x7f;
                break;
        }
index e2062b240e320578969d0afc72a44e2fcd21240b..0f9fb99adeb4e06224445f42d25546038b0bf878 100644 (file)
@@ -4951,8 +4951,9 @@ struct saa7134_board saa7134_boards[] = {
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_XC2028,
                .radio_type     = UNSET,
-               .tuner_addr     = ADDR_UNSET,
+               .tuner_addr     = 0x61,
                .radio_addr     = ADDR_UNSET,
+               .mpeg           = SAA7134_MPEG_DVB,
                .inputs = {{
                        .name   = name_tv,
                        .vmux   = 3,
@@ -6992,6 +6993,11 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev,
                        msleep(10);
                        saa7134_set_gpio(dev, 18, 1);
                break;
+               case SAA7134_BOARD_VIDEOMATE_T750:
+                       saa7134_set_gpio(dev, 20, 0);
+                       msleep(10);
+                       saa7134_set_gpio(dev, 20, 1);
+               break;
                }
        return 0;
        }
@@ -7451,6 +7457,11 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x0e050000, 0x0c050000);
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0e050000, 0x0c050000);
                break;
+       case SAA7134_BOARD_VIDEOMATE_T750:
+               /* enable the analog tuner */
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x00008000, 0x00008000);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+               break;
        }
        return 0;
 }
index f9be737ba6f4fceafa2d71faf133f3d0c8f47774..ca65cda3e101880d63b1c002412af0f80a6561a2 100644 (file)
@@ -39,6 +39,8 @@
 MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(SAA7134_VERSION);
+
 
 /* ------------------------------------------------------------------ */
 
@@ -1332,14 +1334,8 @@ static struct pci_driver saa7134_pci_driver = {
 static int __init saa7134_init(void)
 {
        INIT_LIST_HEAD(&saa7134_devlist);
-       printk(KERN_INFO "saa7130/34: v4l2 driver version %d.%d.%d loaded\n",
-              (SAA7134_VERSION_CODE >> 16) & 0xff,
-              (SAA7134_VERSION_CODE >>  8) & 0xff,
-              SAA7134_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
-#endif
+       printk(KERN_INFO "saa7130/34: v4l2 driver version %s loaded\n",
+              SAA7134_VERSION);
        return pci_register_driver(&saa7134_pci_driver);
 }
 
index 996a206c6d79749276e8a90cf54cd2ee190903c6..1e4ef16698879f5904fd7b378a4883f48b987640 100644 (file)
@@ -56,6 +56,7 @@
 #include "lgs8gxx.h"
 
 #include "zl10353.h"
+#include "qt1010.h"
 
 #include "zl10036.h"
 #include "zl10039.h"
@@ -939,6 +940,18 @@ static struct zl10353_config behold_x7_config = {
        .disable_i2c_gate_ctrl = 1,
 };
 
+static struct zl10353_config videomate_t750_zl10353_config = {
+       .demod_address         = 0x0f,
+       .no_tuner              = 1,
+       .parallel_ts           = 1,
+       .disable_i2c_gate_ctrl = 1,
+};
+
+static struct qt1010_config videomate_t750_qt1010_config = {
+       .i2c_address = 0x62
+};
+
+
 /* ==================================================================
  * tda10086 based DVB-S cards, helper functions
  */
@@ -1649,6 +1662,18 @@ static int dvb_init(struct saa7134_dev *dev)
                                wprintk("%s: No zl10039 found!\n",
                                        __func__);
 
+               break;
+       case SAA7134_BOARD_VIDEOMATE_T750:
+               fe0->dvb.frontend = dvb_attach(zl10353_attach,
+                                               &videomate_t750_zl10353_config,
+                                               &dev->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       if (dvb_attach(qt1010_attach,
+                                       fe0->dvb.frontend,
+                                       &dev->i2c_adap,
+                                       &videomate_t750_qt1010_config) == NULL)
+                               wprintk("error attaching QT1010\n");
+               }
                break;
        case SAA7134_BOARD_ZOLID_HYBRID_PCI:
                fe0->dvb.frontend = dvb_attach(tda10048_attach,
index 18294db38a01ace446d4ccb908d431dfcea99a2c..dde361a9194e003ce5cd42a22785dea9975c4458 100644 (file)
@@ -172,7 +172,6 @@ static int empress_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, saa7134_boards[dev->board].name,
                sizeof(cap->card));
        sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-       cap->version = SAA7134_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_READWRITE |
index 776ba2dd7f9f7a02de4099add180795c9d4482dd..9cf7914f6f90eb87c03205650a39396a50b84f38 100644 (file)
@@ -1810,7 +1810,6 @@ static int saa7134_querycap(struct file *file, void  *priv,
        strlcpy(cap->card, saa7134_boards[dev->board].name,
                sizeof(cap->card));
        sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-       cap->version = SAA7134_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_VBI_CAPTURE |
@@ -2307,7 +2306,6 @@ static int radio_querycap(struct file *file, void *priv,
        strcpy(cap->driver, "saa7134");
        strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card));
        sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-       cap->version = SAA7134_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
        return 0;
 }
index 28eb10398323b092079c1f8008fda39f2264fc3e..bc8d6bba8ee5e1a7e2e847b1fd293983c20a9430 100644 (file)
@@ -19,8 +19,7 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
-#define SAA7134_VERSION_CODE KERNEL_VERSION(0, 2, 16)
+#define SAA7134_VERSION "0, 2, 17"
 
 #include <linux/pci.h>
 #include <linux/i2c.h>
index 400364569c8df4accc8ca85044ab8e971f2fd610..2fd38a01887ff359b50314fb1d7f68ec86e98480 100644 (file)
@@ -1246,7 +1246,6 @@ static unsigned int fops_poll(struct file *file, poll_table *wait)
        struct saa7164_encoder_fh *fh =
                (struct saa7164_encoder_fh *)file->private_data;
        struct saa7164_port *port = fh->port;
-       struct saa7164_user_buffer *ubuf;
        unsigned int mask = 0;
 
        port->last_poll_msecs_diff = port->last_poll_msecs;
@@ -1278,10 +1277,7 @@ static unsigned int fops_poll(struct file *file, poll_table *wait)
        }
 
        /* Pull the first buffer from the used list */
-       ubuf = list_first_entry(&port->list_buf_used.list,
-               struct saa7164_user_buffer, list);
-
-       if (ubuf)
+       if (!list_empty(&port->list_buf_used.list))
                mask |= POLLIN | POLLRDNORM;
 
        return mask;
index bc1fcedba874b87ce7b384e9a9775928e1520753..e2e034158718d2d20934dfc0c19138474cff9e7d 100644 (file)
@@ -1192,7 +1192,6 @@ static unsigned int fops_poll(struct file *file, poll_table *wait)
 {
        struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data;
        struct saa7164_port *port = fh->port;
-       struct saa7164_user_buffer *ubuf;
        unsigned int mask = 0;
 
        port->last_poll_msecs_diff = port->last_poll_msecs;
@@ -1224,10 +1223,7 @@ static unsigned int fops_poll(struct file *file, poll_table *wait)
        }
 
        /* Pull the first buffer from the used list */
-       ubuf = list_first_entry(&port->list_buf_used.list,
-               struct saa7164_user_buffer, list);
-
-       if (ubuf)
+       if (!list_empty(&port->list_buf_used.list))
                mask |= POLLIN | POLLRDNORM;
 
        return mask;
index 16745d2fb349003deefb9d6cff205a68222fb3af..6678bf1e78168bc0401453de3599e4c5ebc2ad7d 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/kdev_t.h>
-#include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/crc32.h>
 #include <linux/kthread.h>
index 3ae5c9c58cba18b4cca6f3645279f2dc9ed88531..e54089802b6b906027b36369984f126d9d8e8830 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/time.h>
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
@@ -39,6 +38,7 @@
 #include <media/v4l2-dev.h>
 #include <media/soc_camera.h>
 #include <media/sh_mobile_ceu.h>
+#include <media/sh_mobile_csi2.h>
 #include <media/videobuf2-dma-contig.h>
 #include <media/v4l2-mediabus.h>
 #include <media/soc_mediabus.h>
@@ -96,6 +96,7 @@ struct sh_mobile_ceu_buffer {
 struct sh_mobile_ceu_dev {
        struct soc_camera_host ici;
        struct soc_camera_device *icd;
+       struct platform_device *csi2_pdev;
 
        unsigned int irq;
        void __iomem *base;
@@ -205,7 +206,7 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
 
 
        if (2 != success) {
-               dev_warn(&icd->dev, "soft reset time out\n");
+               dev_warn(icd->pdev, "soft reset time out\n");
                return -EIO;
        }
 
@@ -220,7 +221,7 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
                        unsigned long sizes[], void *alloc_ctxs[])
 {
        struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
                                                icd->current_fmt->host_fmt);
@@ -242,7 +243,7 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
                        *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]);
        }
 
-       dev_dbg(icd->dev.parent, "count=%d, size=%lu\n", *count, sizes[0]);
+       dev_dbg(icd->parent, "count=%d, size=%lu\n", *count, sizes[0]);
 
        return 0;
 }
@@ -351,7 +352,7 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
 
        buf = to_ceu_vb(vb);
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
                vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
        /* Added list head initialization on alloc */
@@ -371,7 +372,7 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
        size = icd->user_height * bytes_per_line;
 
        if (vb2_plane_size(vb, 0) < size) {
-               dev_err(icd->dev.parent, "Buffer too small (%lu < %lu)\n",
+               dev_err(icd->parent, "Buffer too small (%lu < %lu)\n",
                        vb2_plane_size(vb, 0), size);
                return -ENOBUFS;
        }
@@ -384,11 +385,11 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb)
 static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
 
-       dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+       dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
                vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
 
        spin_lock_irq(&pcdev->lock);
@@ -409,7 +410,7 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
 static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
 {
        struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
 
@@ -421,8 +422,12 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
                pcdev->active = NULL;
        }
 
-       /* Doesn't hurt also if the list is empty */
-       list_del_init(&buf->queue);
+       /*
+        * Doesn't hurt also if the list is empty, but it hurts, if queuing the
+        * buffer failed, and .buf_init() hasn't been called
+        */
+       if (buf->queue.next)
+               list_del_init(&buf->queue);
 
        spin_unlock_irq(&pcdev->lock);
 }
@@ -437,7 +442,7 @@ static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
 static int sh_mobile_ceu_stop_streaming(struct vb2_queue *q)
 {
        struct soc_camera_device *icd = container_of(q, struct soc_camera_device, vb2_vidq);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct list_head *buf_head, *tmp;
 
@@ -499,25 +504,48 @@ out:
        return IRQ_HANDLED;
 }
 
+static struct v4l2_subdev *find_csi2(struct sh_mobile_ceu_dev *pcdev)
+{
+       struct v4l2_subdev *sd;
+
+       if (!pcdev->csi2_pdev)
+               return NULL;
+
+       v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev)
+               if (&pcdev->csi2_pdev->dev == v4l2_get_subdevdata(sd))
+                       return sd;
+
+       return NULL;
+}
+
 /* Called with .video_lock held */
 static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       struct v4l2_subdev *csi2_sd;
        int ret;
 
        if (pcdev->icd)
                return -EBUSY;
 
-       dev_info(icd->dev.parent,
+       dev_info(icd->parent,
                 "SuperH Mobile CEU driver attached to camera %d\n",
                 icd->devnum);
 
        pm_runtime_get_sync(ici->v4l2_dev.dev);
 
        ret = sh_mobile_ceu_soft_reset(pcdev);
-       if (!ret)
+
+       csi2_sd = find_csi2(pcdev);
+
+       ret = v4l2_subdev_call(csi2_sd, core, s_power, 1);
+       if (ret != -ENODEV && ret != -ENOIOCTLCMD && ret < 0) {
+               pm_runtime_put_sync(ici->v4l2_dev.dev);
+       } else {
                pcdev->icd = icd;
+               ret = 0;
+       }
 
        return ret;
 }
@@ -525,11 +553,13 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
 /* Called with .video_lock held */
 static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       struct v4l2_subdev *csi2_sd = find_csi2(pcdev);
 
        BUG_ON(icd != pcdev->icd);
 
+       v4l2_subdev_call(csi2_sd, core, s_power, 0);
        /* disable capture, disable interrupts */
        ceu_write(pcdev, CEIER, 0);
        sh_mobile_ceu_soft_reset(pcdev);
@@ -545,7 +575,7 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 
        pm_runtime_put_sync(ici->v4l2_dev.dev);
 
-       dev_info(icd->dev.parent,
+       dev_info(icd->parent,
                 "SuperH Mobile CEU driver detached from camera %d\n",
                 icd->devnum);
 
@@ -585,14 +615,14 @@ static u16 calc_scale(unsigned int src, unsigned int *dst)
 /* rect is guaranteed to not exceed the scaled camera rectangle */
 static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        unsigned int height, width, cdwdr_width, in_width, in_height;
        unsigned int left_offset, top_offset;
        u32 camor;
 
-       dev_geo(icd->dev.parent, "Crop %ux%u@%u:%u\n",
+       dev_geo(icd->parent, "Crop %ux%u@%u:%u\n",
                icd->user_width, icd->user_height, cam->ceu_left, cam->ceu_top);
 
        left_offset     = cam->ceu_left;
@@ -641,7 +671,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
        }
 
        /* CSI2 special configuration */
-       if (pcdev->pdata->csi2_dev) {
+       if (pcdev->pdata->csi2) {
                in_width = ((in_width - 2) * 2);
                left_offset *= 2;
        }
@@ -649,7 +679,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
        /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
        camor = left_offset | (top_offset << 16);
 
-       dev_geo(icd->dev.parent,
+       dev_geo(icd->parent,
                "CAMOR 0x%x, CAPWR 0x%x, CFSZR 0x%x, CDWDR 0x%x\n", camor,
                (in_height << 16) | in_width, (height << 16) | width,
                cdwdr_width);
@@ -697,7 +727,7 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr)
 static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
                                       __u32 pixfmt)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        int ret;
        unsigned long camera_flags, common_flags, value;
@@ -783,7 +813,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        value |= pcdev->is_16bit ? 1 << 12 : 0;
 
        /* CSI2 mode */
-       if (pcdev->pdata->csi2_dev)
+       if (pcdev->pdata->csi2)
                value |= 3 << 12;
 
        ceu_write(pcdev, CAMCR, value);
@@ -806,7 +836,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        sh_mobile_ceu_set_rect(icd);
        mdelay(1);
 
-       dev_geo(icd->dev.parent, "CFLCR 0x%x\n", pcdev->cflcr);
+       dev_geo(icd->parent, "CFLCR 0x%x\n", pcdev->cflcr);
        ceu_write(pcdev, CFLCR, pcdev->cflcr);
 
        /*
@@ -829,7 +859,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        ceu_write(pcdev, CDOCR, value);
        ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
 
-       dev_dbg(icd->dev.parent, "S_FMT successful for %c%c%c%c %ux%u\n",
+       dev_dbg(icd->parent, "S_FMT successful for %c%c%c%c %ux%u\n",
                pixfmt & 0xff, (pixfmt >> 8) & 0xff,
                (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
                icd->user_width, icd->user_height);
@@ -843,7 +873,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
 static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
                                       unsigned char buswidth)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        unsigned long camera_flags, common_flags;
 
@@ -901,7 +931,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                                     struct soc_camera_format_xlate *xlate)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        int ret, k, n;
@@ -921,7 +951,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
                return 0;
        }
 
-       if (!pcdev->pdata->csi2_dev) {
+       if (!pcdev->pdata->csi2) {
                ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
                if (ret < 0)
                        return 0;
@@ -1244,7 +1274,7 @@ static int client_s_fmt(struct soc_camera_device *icd,
 {
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h;
        unsigned int max_width, max_height;
        struct v4l2_cropcap cap;
@@ -1313,7 +1343,7 @@ static int client_scale(struct soc_camera_device *icd,
                        bool ceu_can_scale)
 {
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        struct v4l2_mbus_framefmt mf_tmp = *mf;
        unsigned int scale_h, scale_v;
        int ret;
@@ -1363,13 +1393,13 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
                                  struct v4l2_crop *a)
 {
        struct v4l2_rect *rect = &a->c;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct v4l2_crop cam_crop;
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
        struct v4l2_rect *cam_rect = &cam_crop.c;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct device *dev = icd->dev.parent;
        struct v4l2_mbus_framefmt mf;
        unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v,
                out_width, out_height;
@@ -1511,7 +1541,7 @@ static void calculate_client_output(struct soc_camera_device *icd,
                struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf)
 {
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
-       struct device *dev = icd->dev.parent;
+       struct device *dev = icd->parent;
        struct v4l2_rect *cam_subrect = &cam->subrect;
        unsigned int scale_v, scale_h;
 
@@ -1555,12 +1585,12 @@ static void calculate_client_output(struct soc_camera_device *icd,
 static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
                                 struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct device *dev = icd->parent;
+       struct soc_camera_host *ici = to_soc_camera_host(dev);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        struct sh_mobile_ceu_cam *cam = icd->host_priv;
        struct v4l2_pix_format *pix = &f->fmt.pix;
        struct v4l2_mbus_framefmt mf;
-       struct device *dev = icd->dev.parent;
        __u32 pixfmt = pix->pixelformat;
        const struct soc_camera_format_xlate *xlate;
        /* Keep Compiler Happy */
@@ -1684,12 +1714,12 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        int width, height;
        int ret;
 
-       dev_geo(icd->dev.parent, "TRY_FMT(pix=0x%x, %ux%u)\n",
+       dev_geo(icd->parent, "TRY_FMT(pix=0x%x, %ux%u)\n",
                 pixfmt, pix->width, pix->height);
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
+               dev_warn(icd->parent, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -1701,11 +1731,6 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
        width = pix->width;
        height = pix->height;
 
-       pix->bytesperline = soc_mbus_bytes_per_line(width, xlate->host_fmt);
-       if ((int)pix->bytesperline < 0)
-               return pix->bytesperline;
-       pix->sizeimage = height * pix->bytesperline;
-
        /* limit to sensor capabilities */
        mf.width        = pix->width;
        mf.height       = pix->height;
@@ -1741,7 +1766,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
                                                         try_mbus_fmt, &mf);
                        if (ret < 0) {
                                /* Shouldn't actually happen... */
-                               dev_err(icd->dev.parent,
+                               dev_err(icd->parent,
                                        "FIXME: client try_fmt() = %d\n", ret);
                                return ret;
                        }
@@ -1753,7 +1778,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
                        pix->height = height;
        }
 
-       dev_geo(icd->dev.parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
+       dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
                __func__, ret, pix->pixelformat, pix->width, pix->height);
 
        return ret;
@@ -1763,7 +1788,7 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
                                      struct v4l2_crop *a)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        u32 out_width = icd->user_width, out_height = icd->user_height;
        int ret;
@@ -1775,13 +1800,13 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
        /* Stop the client */
        ret = v4l2_subdev_call(sd, video, s_stream, 0);
        if (ret < 0)
-               dev_warn(icd->dev.parent,
+               dev_warn(icd->parent,
                         "Client failed to stop the stream: %d\n", ret);
        else
                /* Do the crop, if it fails, there's nothing more we can do */
                sh_mobile_ceu_set_crop(icd, a);
 
-       dev_geo(icd->dev.parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height);
+       dev_geo(icd->parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height);
 
        if (icd->user_width != out_width || icd->user_height != out_height) {
                struct v4l2_format f = {
@@ -1827,7 +1852,6 @@ static int sh_mobile_ceu_querycap(struct soc_camera_host *ici,
                                  struct v4l2_capability *cap)
 {
        strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card));
-       cap->version = KERNEL_VERSION(0, 0, 5);
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
        return 0;
 }
@@ -1848,7 +1872,7 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q,
 static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
                                  struct v4l2_control *ctrl)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        u32 val;
 
@@ -1864,7 +1888,7 @@ static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
 static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd,
                                  struct v4l2_control *ctrl)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
 
        switch (ctrl->id) {
@@ -1950,7 +1974,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
                .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
                .notifier.notifier_call = bus_notify,
        };
-       struct device *csi2;
+       struct sh_mobile_ceu_companion *csi2;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
@@ -2023,26 +2047,61 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
        pcdev->ici.drv_name = dev_name(&pdev->dev);
        pcdev->ici.ops = &sh_mobile_ceu_host_ops;
 
+       pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(pcdev->alloc_ctx)) {
+               err = PTR_ERR(pcdev->alloc_ctx);
+               goto exit_free_clk;
+       }
+
+       err = soc_camera_host_register(&pcdev->ici);
+       if (err)
+               goto exit_free_ctx;
+
        /* CSI2 interfacing */
-       csi2 = pcdev->pdata->csi2_dev;
+       csi2 = pcdev->pdata->csi2;
        if (csi2) {
-               wait.dev = csi2;
+               struct platform_device *csi2_pdev =
+                       platform_device_alloc("sh-mobile-csi2", csi2->id);
+               struct sh_csi2_pdata *csi2_pdata = csi2->platform_data;
+
+               if (!csi2_pdev) {
+                       err = -ENOMEM;
+                       goto exit_host_unregister;
+               }
+
+               pcdev->csi2_pdev                = csi2_pdev;
+
+               err = platform_device_add_data(csi2_pdev, csi2_pdata, sizeof(*csi2_pdata));
+               if (err < 0)
+                       goto exit_pdev_put;
+
+               csi2_pdata                      = csi2_pdev->dev.platform_data;
+               csi2_pdata->v4l2_dev            = &pcdev->ici.v4l2_dev;
+
+               csi2_pdev->resource             = csi2->resource;
+               csi2_pdev->num_resources        = csi2->num_resources;
+
+               err = platform_device_add(csi2_pdev);
+               if (err < 0)
+                       goto exit_pdev_put;
+
+               wait.dev = &csi2_pdev->dev;
 
                err = bus_register_notifier(&platform_bus_type, &wait.notifier);
                if (err < 0)
-                       goto exit_free_clk;
+                       goto exit_pdev_unregister;
 
                /*
                 * From this point the driver module will not unload, until
                 * we complete the completion.
                 */
 
-               if (!csi2->driver) {
+               if (!csi2_pdev->dev.driver) {
                        complete(&wait.completion);
                        /* Either too late, or probing failed */
                        bus_unregister_notifier(&platform_bus_type, &wait.notifier);
                        err = -ENXIO;
-                       goto exit_free_clk;
+                       goto exit_pdev_unregister;
                }
 
                /*
@@ -2051,34 +2110,28 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
                 * the "owner" is safe!
                 */
 
-               err = try_module_get(csi2->driver->owner);
+               err = try_module_get(csi2_pdev->dev.driver->owner);
 
                /* Let notifier complete, if it has been locked */
                complete(&wait.completion);
                bus_unregister_notifier(&platform_bus_type, &wait.notifier);
                if (!err) {
                        err = -ENODEV;
-                       goto exit_free_clk;
+                       goto exit_pdev_unregister;
                }
        }
 
-       pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
-       if (IS_ERR(pcdev->alloc_ctx)) {
-               err = PTR_ERR(pcdev->alloc_ctx);
-               goto exit_module_put;
-       }
-
-       err = soc_camera_host_register(&pcdev->ici);
-       if (err)
-               goto exit_free_ctx;
-
        return 0;
 
+exit_pdev_unregister:
+       platform_device_del(pcdev->csi2_pdev);
+exit_pdev_put:
+       pcdev->csi2_pdev->resource = NULL;
+       platform_device_put(pcdev->csi2_pdev);
+exit_host_unregister:
+       soc_camera_host_unregister(&pcdev->ici);
 exit_free_ctx:
        vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
-exit_module_put:
-       if (csi2 && csi2->driver)
-               module_put(csi2->driver->owner);
 exit_free_clk:
        pm_runtime_disable(&pdev->dev);
        free_irq(pcdev->irq, pcdev);
@@ -2098,7 +2151,7 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
        struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
        struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
                                        struct sh_mobile_ceu_dev, ici);
-       struct device *csi2 = pcdev->pdata->csi2_dev;
+       struct platform_device *csi2_pdev = pcdev->csi2_pdev;
 
        soc_camera_host_unregister(soc_host);
        pm_runtime_disable(&pdev->dev);
@@ -2107,8 +2160,13 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
                dma_release_declared_memory(&pdev->dev);
        iounmap(pcdev->base);
        vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
-       if (csi2 && csi2->driver)
-               module_put(csi2->driver->owner);
+       if (csi2_pdev && csi2_pdev->dev.driver) {
+               struct module *csi2_drv = csi2_pdev->dev.driver->owner;
+               platform_device_del(csi2_pdev);
+               csi2_pdev->resource = NULL;
+               platform_device_put(csi2_pdev);
+               module_put(csi2_drv);
+       }
        kfree(pcdev);
 
        return 0;
@@ -2158,4 +2216,5 @@ module_exit(sh_mobile_ceu_exit);
 MODULE_DESCRIPTION("SuperH Mobile CEU driver");
 MODULE_AUTHOR("Magnus Damm");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.6");
 MODULE_ALIAS("platform:sh_mobile_ceu");
index 98b87481fa94ba232e586323ebd3bb912abf11d5..2893a0134c7e081ba68e5fbe53d9598465a4d287 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 
+#include <media/sh_mobile_ceu.h>
 #include <media/sh_mobile_csi2.h>
 #include <media/soc_camera.h>
 #include <media/v4l2-common.h>
@@ -33,7 +34,6 @@
 struct sh_csi2 {
        struct v4l2_subdev              subdev;
        struct list_head                list;
-       struct notifier_block           notifier;
        unsigned int                    irq;
        void __iomem                    *base;
        struct platform_device          *pdev;
@@ -132,13 +132,6 @@ static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = {
        .try_mbus_fmt   = sh_csi2_try_fmt,
 };
 
-static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops;
-
-static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
-       .core   = &sh_csi2_subdev_core_ops,
-       .video  = &sh_csi2_subdev_video_ops,
-};
-
 static void sh_csi2_hwinit(struct sh_csi2 *priv)
 {
        struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
@@ -186,65 +179,84 @@ static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd)
        return soc_camera_apply_sensor_flags(icl, flags);
 }
 
-static int sh_csi2_notify(struct notifier_block *nb,
-                         unsigned long action, void *data)
+static int sh_csi2_client_connect(struct sh_csi2 *priv)
 {
-       struct device *dev = data;
-       struct soc_camera_device *icd = to_soc_camera_dev(dev);
-       struct v4l2_device *v4l2_dev = dev_get_drvdata(dev->parent);
-       struct sh_csi2 *priv =
-               container_of(nb, struct sh_csi2, notifier);
        struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
-       int ret, i;
+       struct v4l2_subdev *sd, *csi2_sd = &priv->subdev;
+       struct soc_camera_device *icd = NULL;
+       struct device *dev = v4l2_get_subdevdata(&priv->subdev);
+       int i;
+
+       v4l2_device_for_each_subdev(sd, csi2_sd->v4l2_dev)
+               if (sd->grp_id) {
+                       icd = (struct soc_camera_device *)sd->grp_id;
+                       break;
+               }
+
+       if (!icd)
+               return -EINVAL;
 
        for (i = 0; i < pdata->num_clients; i++)
                if (&pdata->clients[i].pdev->dev == icd->pdev)
                        break;
 
-       dev_dbg(dev, "%s(%p): action = %lu, found #%d\n", __func__, dev, action, i);
+       dev_dbg(dev, "%s(%p): found #%d\n", __func__, dev, i);
 
        if (i == pdata->num_clients)
-               return NOTIFY_DONE;
+               return -ENODEV;
 
-       switch (action) {
-       case BUS_NOTIFY_BOUND_DRIVER:
-               snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s",
-                        dev_name(v4l2_dev->dev), ".mipi-csi");
-               priv->subdev.grp_id = (long)icd;
-               ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev);
-               dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
-               if (ret < 0)
-                       return NOTIFY_DONE;
+       priv->client = pdata->clients + i;
 
-               priv->client = pdata->clients + i;
+       priv->set_bus_param             = icd->ops->set_bus_param;
+       priv->query_bus_param           = icd->ops->query_bus_param;
+       icd->ops->set_bus_param         = sh_csi2_set_bus_param;
+       icd->ops->query_bus_param       = sh_csi2_query_bus_param;
 
-               priv->set_bus_param             = icd->ops->set_bus_param;
-               priv->query_bus_param           = icd->ops->query_bus_param;
-               icd->ops->set_bus_param         = sh_csi2_set_bus_param;
-               icd->ops->query_bus_param       = sh_csi2_query_bus_param;
+       csi2_sd->grp_id = (long)icd;
 
-               pm_runtime_get_sync(v4l2_get_subdevdata(&priv->subdev));
+       pm_runtime_get_sync(dev);
 
-               sh_csi2_hwinit(priv);
-               break;
-       case BUS_NOTIFY_UNBIND_DRIVER:
-               priv->client = NULL;
+       sh_csi2_hwinit(priv);
 
-               /* Driver is about to be unbound */
-               icd->ops->set_bus_param         = priv->set_bus_param;
-               icd->ops->query_bus_param       = priv->query_bus_param;
-               priv->set_bus_param             = NULL;
-               priv->query_bus_param           = NULL;
+       return 0;
+}
 
-               v4l2_device_unregister_subdev(&priv->subdev);
+static void sh_csi2_client_disconnect(struct sh_csi2 *priv)
+{
+       struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id;
 
-               pm_runtime_put(v4l2_get_subdevdata(&priv->subdev));
-               break;
-       }
+       priv->client = NULL;
+       priv->subdev.grp_id = 0;
 
-       return NOTIFY_OK;
+       /* Driver is about to be unbound */
+       icd->ops->set_bus_param         = priv->set_bus_param;
+       icd->ops->query_bus_param       = priv->query_bus_param;
+       priv->set_bus_param             = NULL;
+       priv->query_bus_param           = NULL;
+
+       pm_runtime_put(v4l2_get_subdevdata(&priv->subdev));
 }
 
+static int sh_csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+
+       if (on)
+               return sh_csi2_client_connect(priv);
+
+       sh_csi2_client_disconnect(priv);
+       return 0;
+}
+
+static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops = {
+       .s_power        = sh_csi2_s_power,
+};
+
+static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
+       .core   = &sh_csi2_subdev_core_ops,
+       .video  = &sh_csi2_subdev_video_ops,
+};
+
 static __devinit int sh_csi2_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -274,14 +286,6 @@ static __devinit int sh_csi2_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        priv->irq = irq;
-       priv->notifier.notifier_call = sh_csi2_notify;
-
-       /* We MUST attach after the MIPI sensor */
-       ret = bus_register_notifier(&soc_camera_bus_type, &priv->notifier);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "CSI2 cannot register notifier\n");
-               goto ernotify;
-       }
 
        if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
                dev_err(&pdev->dev, "CSI2 register region already claimed\n");
@@ -297,11 +301,17 @@ static __devinit int sh_csi2_probe(struct platform_device *pdev)
        }
 
        priv->pdev = pdev;
+       platform_set_drvdata(pdev, priv);
 
        v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops);
        v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
 
-       platform_set_drvdata(pdev, priv);
+       snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s.mipi-csi",
+                dev_name(pdata->v4l2_dev->dev));
+       ret = v4l2_device_register_subdev(pdata->v4l2_dev, &priv->subdev);
+       dev_dbg(&pdev->dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
+       if (ret < 0)
+               goto esdreg;
 
        pm_runtime_enable(&pdev->dev);
 
@@ -309,11 +319,11 @@ static __devinit int sh_csi2_probe(struct platform_device *pdev)
 
        return 0;
 
+esdreg:
+       iounmap(priv->base);
 eremap:
        release_mem_region(res->start, resource_size(res));
 ereqreg:
-       bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
-ernotify:
        kfree(priv);
 
        return ret;
@@ -324,7 +334,7 @@ static __devexit int sh_csi2_remove(struct platform_device *pdev)
        struct sh_csi2 *priv = platform_get_drvdata(pdev);
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
+       v4l2_device_unregister_subdev(&priv->subdev);
        pm_runtime_disable(&pdev->dev);
        iounmap(priv->base);
        release_mem_region(res->start, resource_size(res));
@@ -335,8 +345,9 @@ static __devexit int sh_csi2_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver __refdata sh_csi2_pdrv = {
-       .remove  = __devexit_p(sh_csi2_remove),
-       .driver  = {
+       .remove = __devexit_p(sh_csi2_remove),
+       .probe  = sh_csi2_probe,
+       .driver = {
                .name   = "sh-mobile-csi2",
                .owner  = THIS_MODULE,
        },
@@ -344,7 +355,7 @@ static struct platform_driver __refdata sh_csi2_pdrv = {
 
 static int __init sh_csi2_init(void)
 {
-       return platform_driver_probe(&sh_csi2_pdrv, sh_csi2_probe);
+       return platform_driver_register(&sh_csi2_pdrv);
 }
 
 static void __exit sh_csi2_exit(void)
index 07cf0c6c7c1f7a210c3a078fc580ee68845535c6..6a729879d89e66b684d675839aa0fdf1b2c923ce 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 
 #include <media/sh_vou.h>
@@ -393,7 +392,6 @@ static int sh_vou_querycap(struct file *file, void  *priv,
        dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
 
        strlcpy(cap->card, "SuperH VOU", sizeof(cap->card));
-       cap->version = KERNEL_VERSION(0, 1, 0);
        cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
        return 0;
 }
@@ -1490,4 +1488,5 @@ module_exit(sh_vou_exit);
 MODULE_DESCRIPTION("SuperH VOU driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
 MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1.0");
 MODULE_ALIAS("platform:sh-vou");
index cbfc44433b99fd56a2bbb8aff56712698f96a61e..22ea211ab54f144cfb656c2080a17896c93d9538 100644 (file)
@@ -21,7 +21,6 @@
 #ifndef _SN9C102_H_
 #define _SN9C102_H_
 
-#include <linux/version.h>
 #include <linux/usb.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
index 0e07c493e6f0ddf0d61d87351d9744c02c5d041e..16cb07c5c27b5cfc4be615b83812894ca04f8eb8 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/stat.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
+#include <linux/version.h>
 #include <linux/page-flags.h>
 #include <asm/byteorder.h>
 #include <asm/page.h>
@@ -47,8 +48,7 @@
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.47pre49"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 47)
+#define SN9C102_MODULE_VERSION  "1:1.48"
 
 /*****************************************************************************/
 
@@ -2158,7 +2158,7 @@ sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
 {
        struct v4l2_capability cap = {
                .driver = "sn9c102",
-               .version = SN9C102_MODULE_VERSION_CODE,
+               .version = LINUX_VERSION_CODE,
                .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
                                V4L2_CAP_STREAMING,
        };
@@ -3187,16 +3187,8 @@ static long sn9c102_ioctl_v4l2(struct file *filp,
        case VIDIOC_S_AUDIO:
                return sn9c102_vidioc_s_audio(cam, arg);
 
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-       case VIDIOC_ENUM_FRAMEINTERVALS:
-               return -EINVAL;
-
        default:
-               return -EINVAL;
+               return -ENOTTY;
 
        }
 }
index 4e4d4122d9a60339175486b999a8576b25565c09..5bdfe7e16bc13e26c3bced5a7289d2ad50819f4d 100644 (file)
@@ -60,14 +60,14 @@ static int soc_camera_power_set(struct soc_camera_device *icd,
                ret = regulator_bulk_enable(icl->num_regulators,
                                            icl->regulators);
                if (ret < 0) {
-                       dev_err(&icd->dev, "Cannot enable regulators\n");
+                       dev_err(icd->pdev, "Cannot enable regulators\n");
                        return ret;
                }
 
                if (icl->power)
                        ret = icl->power(icd->pdev, power_on);
                if (ret < 0) {
-                       dev_err(&icd->dev,
+                       dev_err(icd->pdev,
                                "Platform failed to power-on the camera.\n");
 
                        regulator_bulk_disable(icl->num_regulators,
@@ -79,7 +79,7 @@ static int soc_camera_power_set(struct soc_camera_device *icd,
                if (icl->power)
                        ret = icl->power(icd->pdev, 0);
                if (ret < 0) {
-                       dev_err(&icd->dev,
+                       dev_err(icd->pdev,
                                "Platform failed to power-off the camera.\n");
                        return ret;
                }
@@ -87,7 +87,7 @@ static int soc_camera_power_set(struct soc_camera_device *icd,
                ret = regulator_bulk_disable(icl->num_regulators,
                                             icl->regulators);
                if (ret < 0) {
-                       dev_err(&icd->dev, "Cannot disable regulators\n");
+                       dev_err(icd->pdev, "Cannot disable regulators\n");
                        return ret;
                }
        }
@@ -147,11 +147,11 @@ EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
 static int soc_camera_try_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_pix_format *pix = &f->fmt.pix;
        int ret;
 
-       dev_dbg(&icd->dev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
+       dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
                pixfmtstr(pix->pixelformat), pix->width, pix->height);
 
        pix->bytesperline = 0;
@@ -199,22 +199,15 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
 static int soc_camera_enum_input(struct file *file, void *priv,
                                 struct v4l2_input *inp)
 {
-       struct soc_camera_device *icd = file->private_data;
-       int ret = 0;
-
        if (inp->index != 0)
                return -EINVAL;
 
-       if (icd->ops->enum_input)
-               ret = icd->ops->enum_input(icd, inp);
-       else {
-               /* default is camera */
-               inp->type = V4L2_INPUT_TYPE_CAMERA;
-               inp->std  = V4L2_STD_UNKNOWN;
-               strcpy(inp->name, "Camera");
-       }
+       /* default is camera */
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       inp->std  = V4L2_STD_UNKNOWN;
+       strcpy(inp->name, "Camera");
 
-       return ret;
+       return 0;
 }
 
 static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
@@ -244,7 +237,7 @@ static int soc_camera_enum_fsizes(struct file *file, void *fh,
                                         struct v4l2_frmsizeenum *fsize)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        return ici->ops->enum_fsizes(icd, fsize);
 }
@@ -254,7 +247,7 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
 {
        int ret;
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -281,7 +274,7 @@ static int soc_camera_querybuf(struct file *file, void *priv,
                               struct v4l2_buffer *p)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -295,7 +288,7 @@ static int soc_camera_qbuf(struct file *file, void *priv,
                           struct v4l2_buffer *p)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -312,7 +305,7 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
                            struct v4l2_buffer *p)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -329,7 +322,7 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
 static int soc_camera_init_user_formats(struct soc_camera_device *icd)
 {
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        unsigned int i, fmts = 0, raw_fmts = 0;
        int ret;
        enum v4l2_mbus_pixelcode code;
@@ -363,7 +356,7 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
        if (!icd->user_formats)
                return -ENOMEM;
 
-       dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
+       dev_dbg(icd->pdev, "Found %d supported formats.\n", fmts);
 
        /* Second pass - actually fill data formats */
        fmts = 0;
@@ -395,7 +388,7 @@ egfmt:
 /* Always entered with .video_lock held */
 static void soc_camera_free_user_formats(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        if (ici->ops->put_formats)
                ici->ops->put_formats(icd);
@@ -409,11 +402,11 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
 static int soc_camera_set_fmt(struct soc_camera_device *icd,
                              struct v4l2_format *f)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_pix_format *pix = &f->fmt.pix;
        int ret;
 
-       dev_dbg(&icd->dev, "S_FMT(%c%c%c%c, %ux%u)\n",
+       dev_dbg(icd->pdev, "S_FMT(%c%c%c%c, %ux%u)\n",
                pixfmtstr(pix->pixelformat), pix->width, pix->height);
 
        /* We always call try_fmt() before set_fmt() or set_crop() */
@@ -426,7 +419,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
                return ret;
        } else if (!icd->current_fmt ||
                   icd->current_fmt->host_fmt->fourcc != pix->pixelformat) {
-               dev_err(&icd->dev,
+               dev_err(icd->pdev,
                        "Host driver hasn't set up current format correctly!\n");
                return -EINVAL;
        }
@@ -440,7 +433,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
        if (ici->ops->init_videobuf)
                icd->vb_vidq.field = pix->field;
 
-       dev_dbg(&icd->dev, "set width: %d height: %d\n",
+       dev_dbg(icd->pdev, "set width: %d height: %d\n",
                icd->user_width, icd->user_height);
 
        /* set physical bus parameters */
@@ -450,9 +443,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
 static int soc_camera_open(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
-       struct soc_camera_device *icd = container_of(vdev->parent,
-                                                    struct soc_camera_device,
-                                                    dev);
+       struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
        struct soc_camera_link *icl = to_soc_camera_link(icd);
        struct soc_camera_host *ici;
        int ret;
@@ -461,10 +452,10 @@ static int soc_camera_open(struct file *file)
                /* No device driver attached */
                return -ENODEV;
 
-       ici = to_soc_camera_host(icd->dev.parent);
+       ici = to_soc_camera_host(icd->parent);
 
        if (!try_module_get(ici->ops->owner)) {
-               dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
+               dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
                return -EINVAL;
        }
 
@@ -495,7 +486,7 @@ static int soc_camera_open(struct file *file)
 
                ret = ici->ops->add(icd);
                if (ret < 0) {
-                       dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
+                       dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret);
                        goto eiciadd;
                }
 
@@ -524,7 +515,7 @@ static int soc_camera_open(struct file *file)
        }
 
        file->private_data = icd;
-       dev_dbg(&icd->dev, "camera device open\n");
+       dev_dbg(icd->pdev, "camera device open\n");
 
        return 0;
 
@@ -549,7 +540,7 @@ epower:
 static int soc_camera_close(struct file *file)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        icd->use_count--;
        if (!icd->use_count) {
@@ -570,7 +561,7 @@ static int soc_camera_close(struct file *file)
 
        module_put(ici->ops->owner);
 
-       dev_dbg(&icd->dev, "camera device close\n");
+       dev_dbg(icd->pdev, "camera device close\n");
 
        return 0;
 }
@@ -581,7 +572,7 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf,
        struct soc_camera_device *icd = file->private_data;
        int err = -EINVAL;
 
-       dev_err(&icd->dev, "camera device read not implemented\n");
+       dev_err(icd->pdev, "camera device read not implemented\n");
 
        return err;
 }
@@ -589,10 +580,10 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf,
 static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        int err;
 
-       dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+       dev_dbg(icd->pdev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
        if (icd->streamer != file)
                return -EBUSY;
@@ -602,7 +593,7 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
        else
                err = vb2_mmap(&icd->vb2_vidq, vma);
 
-       dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
+       dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
                (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
                err);
@@ -613,13 +604,13 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
 static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        if (icd->streamer != file)
                return -EBUSY;
 
        if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream)) {
-               dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
+               dev_err(icd->pdev, "Trying to poll with no queued buffers!\n");
                return POLLERR;
        }
 
@@ -659,15 +650,15 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
        WARN_ON(priv != file->private_data);
 
        if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               dev_warn(&icd->dev, "Wrong buf-type %d\n", f->type);
+               dev_warn(icd->pdev, "Wrong buf-type %d\n", f->type);
                return -EINVAL;
        }
 
        if (icd->streamer && icd->streamer != file)
                return -EBUSY;
 
-       if (is_streaming(to_soc_camera_host(icd->dev.parent), icd)) {
-               dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
+       if (is_streaming(to_soc_camera_host(icd->parent), icd)) {
+               dev_err(icd->pdev, "S_FMT denied: queue initialised\n");
                return -EBUSY;
        }
 
@@ -716,7 +707,7 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
        pix->field              = icd->field;
        pix->pixelformat        = icd->current_fmt->host_fmt->fourcc;
        pix->colorspace         = icd->colorspace;
-       dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
+       dev_dbg(icd->pdev, "current_fmt->fourcc: 0x%08x\n",
                icd->current_fmt->host_fmt->fourcc);
        return 0;
 }
@@ -725,7 +716,7 @@ static int soc_camera_querycap(struct file *file, void  *priv,
                               struct v4l2_capability *cap)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -737,7 +728,7 @@ static int soc_camera_streamon(struct file *file, void *priv,
                               enum v4l2_buf_type i)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        int ret;
 
@@ -766,7 +757,7 @@ static int soc_camera_streamoff(struct file *file, void *priv,
 {
        struct soc_camera_device *icd = file->private_data;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -794,7 +785,7 @@ static int soc_camera_queryctrl(struct file *file, void *priv,
                                struct v4l2_queryctrl *qc)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        int i;
 
        WARN_ON(priv != file->private_data);
@@ -825,7 +816,7 @@ static int soc_camera_g_ctrl(struct file *file, void *priv,
                             struct v4l2_control *ctrl)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        int ret;
 
@@ -844,7 +835,7 @@ static int soc_camera_s_ctrl(struct file *file, void *priv,
                             struct v4l2_control *ctrl)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
        int ret;
 
@@ -863,7 +854,7 @@ static int soc_camera_cropcap(struct file *file, void *fh,
                              struct v4l2_cropcap *a)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        return ici->ops->cropcap(icd, a);
 }
@@ -872,7 +863,7 @@ static int soc_camera_g_crop(struct file *file, void *fh,
                             struct v4l2_crop *a)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        int ret;
 
        ret = ici->ops->get_crop(icd, a);
@@ -889,7 +880,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
                             struct v4l2_crop *a)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct v4l2_rect *rect = &a->c;
        struct v4l2_crop current_crop;
        int ret;
@@ -897,7 +888,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
        if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       dev_dbg(&icd->dev, "S_CROP(%ux%u@%u:%u)\n",
+       dev_dbg(icd->pdev, "S_CROP(%ux%u@%u:%u)\n",
                rect->width, rect->height, rect->left, rect->top);
 
        /* If get_crop fails, we'll let host and / or client drivers decide */
@@ -905,7 +896,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
 
        /* Prohibit window size change with initialised buffers */
        if (ret < 0) {
-               dev_err(&icd->dev,
+               dev_err(icd->pdev,
                        "S_CROP denied: getting current crop failed\n");
        } else if ((a->c.width == current_crop.c.width &&
                    a->c.height == current_crop.c.height) ||
@@ -915,7 +906,7 @@ static int soc_camera_s_crop(struct file *file, void *fh,
        } else if (ici->ops->set_livecrop) {
                ret = ici->ops->set_livecrop(icd, a);
        } else {
-               dev_err(&icd->dev,
+               dev_err(icd->pdev,
                        "S_CROP denied: queue initialised and sizes differ\n");
                ret = -EBUSY;
        }
@@ -927,7 +918,7 @@ static int soc_camera_g_parm(struct file *file, void *fh,
                             struct v4l2_streamparm *a)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        if (ici->ops->get_parm)
                return ici->ops->get_parm(icd, a);
@@ -939,7 +930,7 @@ static int soc_camera_s_parm(struct file *file, void *fh,
                             struct v4l2_streamparm *a)
 {
        struct soc_camera_device *icd = file->private_data;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
        if (ici->ops->set_parm)
                return ici->ops->set_parm(icd, a);
@@ -976,6 +967,8 @@ static int soc_camera_s_register(struct file *file, void *fh,
 }
 #endif
 
+static int soc_camera_probe(struct soc_camera_device *icd);
+
 /* So far this function cannot fail */
 static void scan_add_host(struct soc_camera_host *ici)
 {
@@ -986,15 +979,9 @@ static void scan_add_host(struct soc_camera_host *ici)
        list_for_each_entry(icd, &devices, list) {
                if (icd->iface == ici->nr) {
                        int ret;
-                       icd->dev.parent = ici->v4l2_dev.dev;
-                       dev_set_name(&icd->dev, "%u-%u", icd->iface,
-                                    icd->devnum);
-                       ret = device_register(&icd->dev);
-                       if (ret < 0) {
-                               icd->dev.parent = NULL;
-                               dev_err(&icd->dev,
-                                       "Cannot register device: %d\n", ret);
-                       }
+
+                       icd->parent = ici->v4l2_dev.dev;
+                       ret = soc_camera_probe(icd);
                }
        }
 
@@ -1006,12 +993,12 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
                               struct soc_camera_link *icl)
 {
        struct i2c_client *client;
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
        struct v4l2_subdev *subdev;
 
        if (!adap) {
-               dev_err(&icd->dev, "Cannot get I2C adapter #%d. No driver?\n",
+               dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n",
                        icl->i2c_adapter_id);
                goto ei2cga;
        }
@@ -1026,7 +1013,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
        client = v4l2_get_subdevdata(subdev);
 
        /* Use to_i2c_client(dev) to recover the i2c client */
-       dev_set_drvdata(&icd->dev, &client->dev);
+       icd->control = &client->dev;
 
        return 0;
 ei2cnd:
@@ -1040,7 +1027,8 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd)
        struct i2c_client *client =
                to_i2c_client(to_soc_camera_control(icd));
        struct i2c_adapter *adap = client->adapter;
-       dev_set_drvdata(&icd->dev, NULL);
+
+       icd->control = NULL;
        v4l2_device_unregister_subdev(i2c_get_clientdata(client));
        i2c_unregister_device(client);
        i2c_put_adapter(adap);
@@ -1053,17 +1041,16 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd)
 static int soc_camera_video_start(struct soc_camera_device *icd);
 static int video_dev_create(struct soc_camera_device *icd);
 /* Called during host-driver probe */
-static int soc_camera_probe(struct device *dev)
+static int soc_camera_probe(struct soc_camera_device *icd)
 {
-       struct soc_camera_device *icd = to_soc_camera_dev(dev);
-       struct soc_camera_host *ici = to_soc_camera_host(dev->parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct soc_camera_link *icl = to_soc_camera_link(icd);
        struct device *control = NULL;
        struct v4l2_subdev *sd;
        struct v4l2_mbus_framefmt mf;
        int ret;
 
-       dev_info(dev, "Probing %s\n", dev_name(dev));
+       dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev));
 
        ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
                                 icl->regulators);
@@ -1099,7 +1086,7 @@ static int soc_camera_probe(struct device *dev)
                if (icl->module_name)
                        ret = request_module(icl->module_name);
 
-               ret = icl->add_device(icl, &icd->dev);
+               ret = icl->add_device(icd);
                if (ret < 0)
                        goto eadddev;
 
@@ -1110,7 +1097,7 @@ static int soc_camera_probe(struct device *dev)
                control = to_soc_camera_control(icd);
                if (!control || !control->driver || !dev_get_drvdata(control) ||
                    !try_module_get(control->driver->owner)) {
-                       icl->del_device(icl);
+                       icl->del_device(icd);
                        goto enodrv;
                }
        }
@@ -1125,8 +1112,6 @@ static int soc_camera_probe(struct device *dev)
 
        icd->field = V4L2_FIELD_ANY;
 
-       icd->vdev->lock = &icd->video_lock;
-
        /*
         * ..._video_start() will create a device node, video_register_device()
         * itself is protected against concurrent open() calls, but we also have
@@ -1146,11 +1131,6 @@ static int soc_camera_probe(struct device *dev)
                icd->field              = mf.field;
        }
 
-       /* Do we have to sysfs_remove_link() before device_unregister()? */
-       if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj,
-                             "control"))
-               dev_warn(&icd->dev, "Failed creating the control symlink\n");
-
        ici->ops->remove(icd);
 
        soc_camera_power_set(icd, icl, 0);
@@ -1166,7 +1146,7 @@ eiufmt:
        if (icl->board_info) {
                soc_camera_free_i2c(icd);
        } else {
-               icl->del_device(icl);
+               icl->del_device(icd);
                module_put(control->driver->owner);
        }
 enodrv:
@@ -1186,13 +1166,12 @@ ereg:
  * This is called on device_unregister, which only means we have to disconnect
  * from the host, but not remove ourselves from the device list
  */
-static int soc_camera_remove(struct device *dev)
+static int soc_camera_remove(struct soc_camera_device *icd)
 {
-       struct soc_camera_device *icd = to_soc_camera_dev(dev);
        struct soc_camera_link *icl = to_soc_camera_link(icd);
        struct video_device *vdev = icd->vdev;
 
-       BUG_ON(!dev->parent);
+       BUG_ON(!icd->parent);
 
        if (vdev) {
                video_unregister_device(vdev);
@@ -1202,10 +1181,9 @@ static int soc_camera_remove(struct device *dev)
        if (icl->board_info) {
                soc_camera_free_i2c(icd);
        } else {
-               struct device_driver *drv = to_soc_camera_control(icd) ?
-                       to_soc_camera_control(icd)->driver : NULL;
+               struct device_driver *drv = to_soc_camera_control(icd)->driver;
                if (drv) {
-                       icl->del_device(icl);
+                       icl->del_device(icd);
                        module_put(drv->owner);
                }
        }
@@ -1216,49 +1194,6 @@ static int soc_camera_remove(struct device *dev)
        return 0;
 }
 
-static int soc_camera_suspend(struct device *dev, pm_message_t state)
-{
-       struct soc_camera_device *icd = to_soc_camera_dev(dev);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       int ret = 0;
-
-       if (ici->ops->suspend)
-               ret = ici->ops->suspend(icd, state);
-
-       return ret;
-}
-
-static int soc_camera_resume(struct device *dev)
-{
-       struct soc_camera_device *icd = to_soc_camera_dev(dev);
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       int ret = 0;
-
-       if (ici->ops->resume)
-               ret = ici->ops->resume(icd);
-
-       return ret;
-}
-
-struct bus_type soc_camera_bus_type = {
-       .name           = "soc-camera",
-       .probe          = soc_camera_probe,
-       .remove         = soc_camera_remove,
-       .suspend        = soc_camera_suspend,
-       .resume         = soc_camera_resume,
-};
-EXPORT_SYMBOL_GPL(soc_camera_bus_type);
-
-static struct device_driver ic_drv = {
-       .name   = "camera",
-       .bus    = &soc_camera_bus_type,
-       .owner  = THIS_MODULE,
-};
-
-static void dummy_release(struct device *dev)
-{
-}
-
 static int default_cropcap(struct soc_camera_device *icd,
                           struct v4l2_cropcap *a)
 {
@@ -1317,13 +1252,6 @@ static int default_enum_fsizes(struct soc_camera_device *icd,
        return 0;
 }
 
-static void soc_camera_device_init(struct device *dev, void *pdata)
-{
-       dev->platform_data      = pdata;
-       dev->bus                = &soc_camera_bus_type;
-       dev->release            = dummy_release;
-}
-
 int soc_camera_host_register(struct soc_camera_host *ici)
 {
        struct soc_camera_host *ix;
@@ -1389,24 +1317,9 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
        mutex_lock(&list_lock);
 
        list_del(&ici->list);
-
-       list_for_each_entry(icd, &devices, list) {
-               if (icd->iface == ici->nr) {
-                       void *pdata = icd->dev.platform_data;
-                       /* The bus->remove will be called */
-                       device_unregister(&icd->dev);
-                       /*
-                        * Not before device_unregister(), .remove
-                        * needs parent to call ici->ops->remove().
-                        * If the host module is loaded again, device_register()
-                        * would complain "already initialised," since 2.6.32
-                        * this is also needed to prevent use-after-free of the
-                        * device private data.
-                        */
-                       memset(&icd->dev, 0, sizeof(icd->dev));
-                       soc_camera_device_init(&icd->dev, pdata);
-               }
-       }
+       list_for_each_entry(icd, &devices, list)
+               if (icd->iface == ici->nr && to_soc_camera_control(icd))
+                       soc_camera_remove(icd);
 
        mutex_unlock(&list_lock);
 
@@ -1448,11 +1361,6 @@ static int soc_camera_device_register(struct soc_camera_device *icd)
        return 0;
 }
 
-static void soc_camera_device_unregister(struct soc_camera_device *icd)
-{
-       list_del(&icd->list);
-}
-
 static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
        .vidioc_querycap         = soc_camera_querycap,
        .vidioc_g_fmt_vid_cap    = soc_camera_g_fmt_vid_cap,
@@ -1487,7 +1395,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
 
 static int video_dev_create(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct video_device *vdev = video_device_alloc();
 
        if (!vdev)
@@ -1495,12 +1403,13 @@ static int video_dev_create(struct soc_camera_device *icd)
 
        strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
 
-       vdev->parent            = &icd->dev;
+       vdev->parent            = icd->pdev;
        vdev->current_norm      = V4L2_STD_UNKNOWN;
        vdev->fops              = &soc_camera_fops;
        vdev->ioctl_ops         = &soc_camera_ioctl_ops;
        vdev->release           = video_device_release;
        vdev->tvnorms           = V4L2_STD_UNKNOWN;
+       vdev->lock              = &icd->video_lock;
 
        icd->vdev = vdev;
 
@@ -1515,7 +1424,7 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
        const struct device_type *type = icd->vdev->dev.type;
        int ret;
 
-       if (!icd->dev.parent)
+       if (!icd->parent)
                return -ENODEV;
 
        if (!icd->ops ||
@@ -1525,7 +1434,7 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
 
        ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
        if (ret < 0) {
-               dev_err(&icd->dev, "video_register_device failed: %d\n", ret);
+               dev_err(icd->pdev, "video_register_device failed: %d\n", ret);
                return ret;
        }
 
@@ -1549,6 +1458,7 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        icd->iface = icl->bus_id;
+       icd->link = icl;
        icd->pdev = &pdev->dev;
        platform_set_drvdata(pdev, icd);
 
@@ -1556,8 +1466,6 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
        if (ret < 0)
                goto escdevreg;
 
-       soc_camera_device_init(&icd->dev, icl);
-
        icd->user_width         = DEFAULT_WIDTH;
        icd->user_height        = DEFAULT_HEIGHT;
 
@@ -1581,7 +1489,7 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
        if (!icd)
                return -EINVAL;
 
-       soc_camera_device_unregister(icd);
+       list_del(&icd->list);
 
        kfree(icd);
 
@@ -1598,31 +1506,12 @@ static struct platform_driver __refdata soc_camera_pdrv = {
 
 static int __init soc_camera_init(void)
 {
-       int ret = bus_register(&soc_camera_bus_type);
-       if (ret)
-               return ret;
-       ret = driver_register(&ic_drv);
-       if (ret)
-               goto edrvr;
-
-       ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);
-       if (ret)
-               goto epdr;
-
-       return 0;
-
-epdr:
-       driver_unregister(&ic_drv);
-edrvr:
-       bus_unregister(&soc_camera_bus_type);
-       return ret;
+       return platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);
 }
 
 static void __exit soc_camera_exit(void)
 {
        platform_driver_unregister(&soc_camera_pdrv);
-       driver_unregister(&ic_drv);
-       bus_unregister(&soc_camera_bus_type);
 }
 
 module_init(soc_camera_init);
index bf406e89c992b6515ed7c27f8f87ef6577202d6e..8069cd6bc5e865c0fab19b4c929c540137749f25 100644 (file)
@@ -146,7 +146,7 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
        if (!p)
                return -EINVAL;
 
-       if (!p->dev) {
+       if (!p->icd) {
                dev_err(&pdev->dev,
                        "Platform has not set soc_camera_device pointer!\n");
                return -EINVAL;
@@ -156,16 +156,16 @@ static int soc_camera_platform_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       icd = to_soc_camera_dev(p->dev);
+       icd = p->icd;
 
        /* soc-camera convention: control's drvdata points to the subdev */
        platform_set_drvdata(pdev, &priv->subdev);
        /* Set the control device reference */
-       dev_set_drvdata(&icd->dev, &pdev->dev);
+       icd->control = &pdev->dev;
 
        icd->ops = &soc_camera_platform_ops;
 
-       ici = to_soc_camera_host(icd->dev.parent);
+       ici = to_soc_camera_host(icd->parent);
 
        v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);
        v4l2_set_subdevdata(&priv->subdev, p);
@@ -188,7 +188,7 @@ static int soc_camera_platform_remove(struct platform_device *pdev)
 {
        struct soc_camera_platform_priv *priv = get_priv(pdev);
        struct soc_camera_platform_info *p = pdev->dev.platform_data;
-       struct soc_camera_device *icd = to_soc_camera_dev(p->dev);
+       struct soc_camera_device *icd = p->icd;
 
        v4l2_device_unregister_subdev(&priv->subdev);
        icd->ops = NULL;
index c901721a1db3e7380d25a71da9b3597a5837cf66..8afb0e8a2e0033dea97f466d929fea3a8d53a09c 100644 (file)
@@ -726,8 +726,10 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
        const struct sr030pc30_platform_data *pdata = info->pdata;
        int ret;
 
-       if (WARN(pdata == NULL, "No platform data!\n"))
-               return -ENOMEM;
+       if (pdata == NULL) {
+               WARN(1, "No platform data!\n");
+               return -EINVAL;
+       }
 
        /*
         * Put sensor into power sleep mode before switching off
@@ -746,6 +748,7 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
        if (on) {
                ret = sr030pc30_base_config(sd);
        } else {
+               ret = 0;
                info->curr_win = NULL;
                info->curr_fmt = NULL;
        }
index 3941f954daf4eeba5bba42ebf9a36712f3370ea8..bd218545da9c42a6a5067f726172f2a24352c875 100644 (file)
@@ -49,10 +49,11 @@ static int maxvol;
 static int loudness; /* disable loudness by default */
 static int debug;       /* insmod parameter */
 module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Set debugging level from 0 to 3. Default is off(0).");
 module_param(loudness, int, S_IRUGO);
-MODULE_PARM_DESC(maxvol,"Set maximium volume to +20db (0), default is 0db(1)");
+MODULE_PARM_DESC(loudness, "Turn loudness on(1) else off(0). Default is off(0).");
 module_param(maxvol, int, S_IRUGO | S_IWUSR);
-
+MODULE_PARM_DESC(maxvol, "Set maximium volume to +20dB(0) else +0dB(1). Default is +20dB(0).");
 
 
 /* Structure of address and subaddresses for the tda7432 */
index fc611ebeb82c3a550b3d2425c58927813dfb448d..84cd1b65b765afd19b628daede13dca6354469da 100644 (file)
@@ -20,7 +20,6 @@
  * Timberdale FPGA LogiWin Video In
  */
 
-#include <linux/version.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dmaengine.h>
index 46066bdc73f9a967eeb97508de0d67b1c62cae8c..56564e6aaac2b60c19238604607499011d68ba58 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef PD_COMMON_H
 #define PD_COMMON_H
 
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/wait.h>
 #include <linux/list.h>
index 99c81a9a4f46bb6dc1b95e7f98190798c5f79fbc..129f135d5a5fe1deffaa12fdc81611bd2ecd12d4 100644 (file)
@@ -531,3 +531,4 @@ module_exit(poseidon_exit);
 MODULE_AUTHOR("Telegent Systems");
 MODULE_DESCRIPTION("For tlg2300-based USB device ");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.2");
index fae84c2a0c39c6ee07029d5ee19902c3eec76b7d..4fad1dfb92cf00818bf3ee2c769d0dc59eb7b4dc 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/usb.h>
 #include <linux/i2c.h>
 #include <media/v4l2-dev.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <media/v4l2-ioctl.h>
@@ -149,7 +148,6 @@ static int vidioc_querycap(struct file *file, void *priv,
        strlcpy(v->driver, "tele-radio", sizeof(v->driver));
        strlcpy(v->card, "Telegent Poseidon", sizeof(v->card));
        usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info));
-       v->version = KERNEL_VERSION(0, 0, 1);
        v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
        return 0;
 }
index a03945ab9f08f14218501d28a5eee4ba4cd629f8..11cc980b0cd5e7113da25b6b39297de8e33038da 100644 (file)
@@ -39,6 +39,7 @@
 #include "tda9887.h"
 #include "xc5000.h"
 #include "tda18271.h"
+#include "xc4000.h"
 
 #define UNSET (-1U)
 
@@ -391,6 +392,23 @@ static void set_type(struct i2c_client *c, unsigned int type,
                tune_now = 0;
                break;
        }
+       case TUNER_XC4000:
+       {
+               struct xc4000_config xc4000_cfg = {
+                       .i2c_address      = t->i2c->addr,
+                       /* FIXME: the correct parameters will be set */
+                       /* only when the digital dvb_attach() occurs */
+                       .default_pm       = 0,
+                       .dvb_amplitude    = 0,
+                       .set_smoothedcvbs = 0,
+                       .if_khz           = 0
+               };
+               if (!dvb_attach(xc4000_attach,
+                               &t->fe, t->i2c->adapter, &xc4000_cfg))
+                       goto attach_failed;
+               tune_now = 0;
+               break;
+       }
        default:
                if (!dvb_attach(simple_tuner_attach, &t->fe,
                                t->i2c->adapter, t->i2c->addr, t->type))
index 0347bbe364593e7683ad16289a3c3a29362efa2e..742482e30011f9438edaa47e2ce2f3ebefcb0ced 100644 (file)
@@ -552,16 +552,6 @@ static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
        return ret;
 }
 
-static int tw9910_enum_input(struct soc_camera_device *icd,
-                            struct v4l2_input *inp)
-{
-       inp->type = V4L2_INPUT_TYPE_TUNER;
-       inp->std  = V4L2_STD_UNKNOWN;
-       strcpy(inp->name, "Video");
-
-       return 0;
-}
-
 static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
                               struct v4l2_dbg_chip_ident *id)
 {
@@ -846,13 +836,9 @@ static int tw9910_video_probe(struct soc_camera_device *icd,
        struct tw9910_priv *priv = to_tw9910(client);
        s32 id;
 
-       /*
-        * We must have a parent by now. And it cannot be a wrong one.
-        * So this entire test is completely redundant.
-        */
-       if (!icd->dev.parent ||
-           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
-               return -ENODEV;
+       /* We must have a parent by now. And it cannot be a wrong one. */
+       BUG_ON(!icd->parent ||
+              to_soc_camera_host(icd->parent)->nr != icd->iface);
 
        /*
         * tw9910 only use 8 or 16 bit bus width
@@ -891,7 +877,6 @@ static int tw9910_video_probe(struct soc_camera_device *icd,
 static struct soc_camera_ops tw9910_ops = {
        .set_bus_param          = tw9910_set_bus_param,
        .query_bus_param        = tw9910_query_bus_param,
-       .enum_input             = tw9910_enum_input,
 };
 
 static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
index ea8ea8a48dfe57f7c3b423bef45e3e0055b3267a..5a74f5e07d7dd6bf1caf42d310ca01294f5db9ee 100644 (file)
@@ -45,7 +45,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/timer.h>
 #define DRIVER_ALIAS "USBVision"
 #define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
 #define DRIVER_LICENSE "GPL"
-#define USBVISION_DRIVER_VERSION_MAJOR 0
-#define USBVISION_DRIVER_VERSION_MINOR 9
-#define USBVISION_DRIVER_VERSION_PATCHLEVEL 10
-#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\
-USBVISION_DRIVER_VERSION_MINOR,\
-USBVISION_DRIVER_VERSION_PATCHLEVEL)
-#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) \
-"." __stringify(USBVISION_DRIVER_VERSION_MINOR) \
-"." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING "0.9.11"
 
 #define        ENABLE_HEXDUMP  0       /* Enable if you need it */
 
@@ -516,7 +507,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
                usbvision_device_data[usbvision->dev_model].model_string,
                sizeof(vc->card));
        usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
-       vc->version = USBVISION_DRIVER_VERSION;
        vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_AUDIO |
                V4L2_CAP_READWRITE |
index 2c8954ec685950bc0552f403dea77ce046fec7b2..10c2364f3e8a56624babb71ac2f1d59f2c4c37f1 100644 (file)
@@ -1664,8 +1664,8 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
                return -EINVAL;
        }
 
-       /* Search for the matching (GUID/CS) control in the given device */
-       list_for_each_entry(entity, &dev->entities, list) {
+       /* Search for the matching (GUID/CS) control on the current chain */
+       list_for_each_entry(entity, &chain->entities, chain) {
                unsigned int i;
 
                if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT ||
index b6eae48d7fb802f53a950b90ef3f9107f96e9271..d29f9c2d085482ff667e001887f585280ce2f413 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/videodev2.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
+#include <linux/version.h>
 #include <asm/atomic.h>
 #include <asm/unaligned.h>
 
@@ -1857,7 +1858,7 @@ static int uvc_probe(struct usb_interface *intf,
                        sizeof(dev->mdev.serial));
        strcpy(dev->mdev.bus_info, udev->devpath);
        dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
-       dev->mdev.driver_version = DRIVER_VERSION_NUMBER;
+       dev->mdev.driver_version = LINUX_VERSION_CODE;
        if (media_device_register(&dev->mdev) < 0)
                goto error;
 
@@ -2130,6 +2131,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX
                                | UVC_QUIRK_BUILTIN_ISIGHT },
+       /* Foxlink ("HP Webcam" on HP Mini 5103) */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x05c8,
+         .idProduct            = 0x0403,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_FIX_BANDWIDTH },
        /* Genesys Logic USB 2.0 PC Camera */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
index dde6533e8e6dce16984c4db5eafb4c8ac25dba41..ea71d5f1f6db93d285eada76f87f68b2692cfd36 100644 (file)
@@ -83,7 +83,7 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
        default:
                uvc_trace(UVC_TRACE_CONTROL, "Unsupported V4L2 control type "
                          "%u.\n", xmap->v4l2_type);
-               ret = -EINVAL;
+               ret = -ENOTTY;
                goto done;
        }
 
@@ -571,7 +571,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                strlcpy(cap->card, vdev->name, sizeof cap->card);
                usb_make_path(stream->dev->udev,
                              cap->bus_info, sizeof(cap->bus_info));
-               cap->version = DRIVER_VERSION_NUMBER;
+               cap->version = LINUX_VERSION_CODE;
                if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
                                          | V4L2_CAP_STREAMING;
index 20107fd3574da44508f69835e5fc098b3eec86a6..df32a43ca86a71db60c31bc92751aa0a2308615e 100644 (file)
@@ -183,8 +183,7 @@ struct uvc_xu_control {
  * Driver specific constants.
  */
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(1, 1, 0)
-#define DRIVER_VERSION         "v1.1.0"
+#define DRIVER_VERSION         "1.1.1"
 
 /* Number of isochronous URBs. */
 #define UVC_URBS               5
index 06b9f9f82013c33b1c61e812038aa3bd660469ad..5c6100fb4072120072d0301ca366ddbb8bf5ed93 100644 (file)
@@ -105,6 +105,9 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
                    menu_items[ctrl->value][0] == '\0')
                        return -EINVAL;
        }
+       if (qctrl->type == V4L2_CTRL_TYPE_BITMASK &&
+                       (ctrl->value & ~qctrl->maximum))
+               return -ERANGE;
        return 0;
 }
 EXPORT_SYMBOL(v4l2_ctrl_check);
index 7c2694738b312db94557c0e342e97872124adc8d..61979b70f3883ab340eb2e8c01350d88a71defa3 100644 (file)
@@ -662,6 +662,32 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
        return 0;
 }
 
+struct v4l2_event32 {
+       __u32                           type;
+       union {
+               __u8                    data[64];
+       } u;
+       __u32                           pending;
+       __u32                           sequence;
+       struct compat_timespec          timestamp;
+       __u32                           id;
+       __u32                           reserved[8];
+};
+
+static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
+{
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
+               put_user(kp->type, &up->type) ||
+               copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
+               put_user(kp->pending, &up->pending) ||
+               put_user(kp->sequence, &up->sequence) ||
+               put_compat_timespec(&kp->timestamp, &up->timestamp) ||
+               put_user(kp->id, &up->id) ||
+               copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
+                       return -EFAULT;
+       return 0;
+}
+
 #define VIDIOC_G_FMT32         _IOWR('V',  4, struct v4l2_format32)
 #define VIDIOC_S_FMT32         _IOWR('V',  5, struct v4l2_format32)
 #define VIDIOC_QUERYBUF32      _IOWR('V',  9, struct v4l2_buffer32)
@@ -675,6 +701,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
 #define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
 #define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
 #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
+#define        VIDIOC_DQEVENT32        _IOR ('V', 89, struct v4l2_event32)
 
 #define VIDIOC_OVERLAY32       _IOW ('V', 14, s32)
 #define VIDIOC_STREAMON32      _IOW ('V', 18, s32)
@@ -693,6 +720,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
                struct v4l2_input v2i;
                struct v4l2_standard v2s;
                struct v4l2_ext_controls v2ecs;
+               struct v4l2_event v2ev;
                unsigned long vx;
                int vi;
        } karg;
@@ -715,6 +743,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
        case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
        case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
        case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
+       case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break;
        case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
        case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
        case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
@@ -778,6 +807,9 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
                err = get_v4l2_ext_controls32(&karg.v2ecs, up);
                compatible_arg = 0;
                break;
+       case VIDIOC_DQEVENT:
+               compatible_arg = 0;
+               break;
        }
        if (err)
                return err;
@@ -818,6 +850,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
                err = put_v4l2_framebuffer32(&karg.v2fb, up);
                break;
 
+       case VIDIOC_DQEVENT:
+               err = put_v4l2_event32(&karg.v2ev, up);
+               break;
+
        case VIDIOC_G_FMT:
        case VIDIOC_S_FMT:
        case VIDIOC_TRY_FMT:
@@ -920,6 +956,7 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
        case VIDIOC_S_DV_TIMINGS:
        case VIDIOC_G_DV_TIMINGS:
        case VIDIOC_DQEVENT:
+       case VIDIOC_DQEVENT32:
        case VIDIOC_SUBSCRIBE_EVENT:
        case VIDIOC_UNSUBSCRIBE_EVENT:
                ret = do_video_ioctl(file, cmd, arg);
index 2412f08527aa8e014a440971b7ade207ecd1b233..06b6014d4fb4cda5adb94c54a425c0b08b94019e 100644 (file)
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-dev.h>
 
+#define has_op(master, op) \
+       (master->ops && master->ops->op)
+#define call_op(master, op) \
+       (has_op(master, op) ? master->ops->op(master) : 0)
+
 /* Internal temporary helper struct, one for each v4l2_ext_control */
-struct ctrl_helper {
+struct v4l2_ctrl_helper {
+       /* Pointer to the control reference of the master control */
+       struct v4l2_ctrl_ref *mref;
        /* The control corresponding to the v4l2_ext_control ID field. */
        struct v4l2_ctrl *ctrl;
-       /* Used internally to mark whether this control was already
-          processed. */
-       bool handled;
+       /* v4l2_ext_control index of the next control belonging to the
+          same cluster, or 0 if there isn't any. */
+       u32 next;
 };
 
+/* Small helper function to determine if the autocluster is set to manual
+   mode. In that case the is_volatile flag should be ignored. */
+static bool is_cur_manual(const struct v4l2_ctrl *master)
+{
+       return master->is_auto && master->cur.val == master->manual_mode_value;
+}
+
+/* Same as above, but this checks the against the new value instead of the
+   current value. */
+static bool is_new_manual(const struct v4l2_ctrl *master)
+{
+       return master->is_auto && master->val == master->manual_mode_value;
+}
+
 /* 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
@@ -181,7 +203,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
        };
        static const char * const mpeg_stream_vbi_fmt[] = {
                "No VBI",
-               "Private packet, IVTV format",
+               "Private Packet, IVTV Format",
                NULL
        };
        static const char * const camera_power_line_frequency[] = {
@@ -204,18 +226,130 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                "Negative",
                "Emboss",
                "Sketch",
-               "Sky blue",
-               "Grass green",
-               "Skin whiten",
+               "Sky Blue",
+               "Grass Green",
+               "Skin Whiten",
                "Vivid",
                NULL
        };
        static const char * const tune_preemphasis[] = {
-               "No preemphasis",
+               "No Preemphasis",
                "50 useconds",
                "75 useconds",
                NULL,
        };
+       static const char * const header_mode[] = {
+               "Separate Buffer",
+               "Joined With 1st Frame",
+               NULL,
+       };
+       static const char * const multi_slice[] = {
+               "Single",
+               "Max Macroblocks",
+               "Max Bytes",
+               NULL,
+       };
+       static const char * const entropy_mode[] = {
+               "CAVLC",
+               "CABAC",
+               NULL,
+       };
+       static const char * const mpeg_h264_level[] = {
+               "1",
+               "1b",
+               "1.1",
+               "1.2",
+               "1.3",
+               "2",
+               "2.1",
+               "2.2",
+               "3",
+               "3.1",
+               "3.2",
+               "4",
+               "4.1",
+               "4.2",
+               "5",
+               "5.1",
+               NULL,
+       };
+       static const char * const h264_loop_filter[] = {
+               "Enabled",
+               "Disabled",
+               "Disabled at Slice Boundary",
+               NULL,
+       };
+       static const char * const h264_profile[] = {
+               "Baseline",
+               "Constrained Baseline",
+               "Main",
+               "Extended",
+               "High",
+               "High 10",
+               "High 422",
+               "High 444 Predictive",
+               "High 10 Intra",
+               "High 422 Intra",
+               "High 444 Intra",
+               "CAVLC 444 Intra",
+               "Scalable Baseline",
+               "Scalable High",
+               "Scalable High Intra",
+               "Multiview High",
+               NULL,
+       };
+       static const char * const vui_sar_idc[] = {
+               "Unspecified",
+               "1:1",
+               "12:11",
+               "10:11",
+               "16:11",
+               "40:33",
+               "24:11",
+               "20:11",
+               "32:11",
+               "80:33",
+               "18:11",
+               "15:11",
+               "64:33",
+               "160:99",
+               "4:3",
+               "3:2",
+               "2:1",
+               "Extended SAR",
+               NULL,
+       };
+       static const char * const mpeg_mpeg4_level[] = {
+               "0",
+               "0b",
+               "1",
+               "2",
+               "3",
+               "3b",
+               "4",
+               "5",
+               NULL,
+       };
+       static const char * const mpeg4_profile[] = {
+               "Simple",
+               "Adcanved Simple",
+               "Core",
+               "Simple Scalable",
+               "Advanced Coding Efficency",
+               NULL,
+       };
+
+       static const char * const flash_led_mode[] = {
+               "Off",
+               "Flash",
+               "Torch",
+               NULL,
+       };
+       static const char * const flash_strobe_source[] = {
+               "Software",
+               "External",
+               NULL,
+       };
 
        switch (id) {
        case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -256,6 +390,28 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
                return colorfx;
        case V4L2_CID_TUNE_PREEMPHASIS:
                return tune_preemphasis;
+       case V4L2_CID_FLASH_LED_MODE:
+               return flash_led_mode;
+       case V4L2_CID_FLASH_STROBE_SOURCE:
+               return flash_strobe_source;
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+               return header_mode;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+               return multi_slice;
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+               return entropy_mode;
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+               return mpeg_h264_level;
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+               return h264_loop_filter;
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+               return h264_profile;
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+               return vui_sar_idc;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+               return mpeg_mpeg4_level;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+               return mpeg4_profile;
        default:
                return NULL;
        }
@@ -307,6 +463,8 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_CHROMA_GAIN:              return "Chroma Gain";
        case V4L2_CID_ILLUMINATORS_1:           return "Illuminator 1";
        case V4L2_CID_ILLUMINATORS_2:           return "Illuminator 2";
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:  return "Minimum Number of Capture Buffers";
+       case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:   return "Minimum Number of Output Buffers";
 
        /* MPEG controls */
        /* Keep the order of the 'case's the same as in videodev2.h! */
@@ -343,6 +501,48 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
        case V4L2_CID_MPEG_VIDEO_MUTE:          return "Video Mute";
        case V4L2_CID_MPEG_VIDEO_MUTE_YUV:      return "Video Mute YUV";
+       case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:       return "Decoder Slice Interface";
+       case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:  return "MPEG4 Loop Filter Enable";
+       case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:       return "The Number of Intra Refresh MBs";
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:               return "Frame Level Rate Control Enable";
+       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:                  return "H264 MB Level Rate Control";
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:                   return "Sequence Header Mode";
+       case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC:                   return "The Max Number of Reference Picture";
+       case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:               return "H263 I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:               return "H263 P frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:               return "H263 B frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:                   return "H263 Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:                   return "H263 Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:               return "H264 I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:               return "H264 P frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:               return "H264 B frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:                   return "H264 Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:                   return "H264 Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:            return "H264 8x8 Transform Enable";
+       case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:                 return "H264 CPB Buffer Size";
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:             return "H264 Entorpy Mode";
+       case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:                 return "H264 I Period";
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:                    return "H264 Level";
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:        return "H264 Loop Filter Alpha Offset";
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:         return "H264 Loop Filter Beta Offset";
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:         return "H264 Loop Filter Mode";
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:                  return "H264 Profile";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:       return "Vertical Size of SAR";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:        return "Horizontal Size of SAR";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:           return "Aspect Ratio VUI Enable";
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:              return "VUI Aspect Ratio IDC";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:              return "MPEG4 I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:              return "MPEG4 P frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:              return "MPEG4 B frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:                  return "MPEG4 Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:                  return "MPEG4 Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:                   return "MPEG4 Level";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:                 return "MPEG4 Profile";
+       case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:                    return "Quarter Pixel Search Enable";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:         return "The Maximum Bytes Per Slice";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:            return "The Number of MB in a Slice";
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:              return "The Slice Partitioning Method";
+       case V4L2_CID_MPEG_VIDEO_VBV_SIZE:                      return "VBV Buffer Size";
 
        /* CAMERA controls */
        /* Keep the order of the 'case's the same as in videodev2.h! */
@@ -389,6 +589,21 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_TUNE_POWER_LEVEL:         return "Tune Power Level";
        case V4L2_CID_TUNE_ANTENNA_CAPACITOR:   return "Tune Antenna Capacitor";
 
+       /* Flash controls */
+       case V4L2_CID_FLASH_CLASS:              return "Flash controls";
+       case V4L2_CID_FLASH_LED_MODE:           return "LED mode";
+       case V4L2_CID_FLASH_STROBE_SOURCE:      return "Strobe source";
+       case V4L2_CID_FLASH_STROBE:             return "Strobe";
+       case V4L2_CID_FLASH_STROBE_STOP:        return "Stop strobe";
+       case V4L2_CID_FLASH_STROBE_STATUS:      return "Strobe status";
+       case V4L2_CID_FLASH_TIMEOUT:            return "Strobe timeout";
+       case V4L2_CID_FLASH_INTENSITY:          return "Intensity, flash mode";
+       case V4L2_CID_FLASH_TORCH_INTENSITY:    return "Intensity, torch mode";
+       case V4L2_CID_FLASH_INDICATOR_INTENSITY: return "Intensity, indicator";
+       case V4L2_CID_FLASH_FAULT:              return "Faults";
+       case V4L2_CID_FLASH_CHARGE:             return "Charge";
+       case V4L2_CID_FLASH_READY:              return "Ready to strobe";
+
        default:
                return NULL;
        }
@@ -423,12 +638,24 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_PILOT_TONE_ENABLED:
        case V4L2_CID_ILLUMINATORS_1:
        case V4L2_CID_ILLUMINATORS_2:
+       case V4L2_CID_FLASH_STROBE_STATUS:
+       case V4L2_CID_FLASH_CHARGE:
+       case V4L2_CID_FLASH_READY:
+       case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+       case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+       case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+       case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+       case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
                *type = V4L2_CTRL_TYPE_BOOLEAN;
                *min = 0;
                *max = *step = 1;
                break;
        case V4L2_CID_PAN_RESET:
        case V4L2_CID_TILT_RESET:
+       case V4L2_CID_FLASH_STROBE:
+       case V4L2_CID_FLASH_STROBE_STOP:
                *type = V4L2_CTRL_TYPE_BUTTON;
                *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
                *min = *max = *step = *def = 0;
@@ -452,6 +679,17 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_EXPOSURE_AUTO:
        case V4L2_CID_COLORFX:
        case V4L2_CID_TUNE_PREEMPHASIS:
+       case V4L2_CID_FLASH_LED_MODE:
+       case V4L2_CID_FLASH_STROBE_SOURCE:
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+       case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+       case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+       case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+       case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+       case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+       case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+       case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
                *type = V4L2_CTRL_TYPE_MENU;
                break;
        case V4L2_CID_RDS_TX_PS_NAME:
@@ -462,6 +700,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_CAMERA_CLASS:
        case V4L2_CID_MPEG_CLASS:
        case V4L2_CID_FM_TX_CLASS:
+       case V4L2_CID_FLASH_CLASS:
                *type = V4L2_CTRL_TYPE_CTRL_CLASS;
                /* You can neither read not write these */
                *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -474,6 +713,14 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
                /* Max is calculated as RGB888 that is 2^24 */
                *max = 0xFFFFFF;
                break;
+       case V4L2_CID_FLASH_FAULT:
+               *type = V4L2_CTRL_TYPE_BITMASK;
+               break;
+       case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+       case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
+               *type = V4L2_CTRL_TYPE_INTEGER;
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               break;
        default:
                *type = V4L2_CTRL_TYPE_INTEGER;
                break;
@@ -519,6 +766,10 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
        case V4L2_CID_ZOOM_RELATIVE:
                *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
                break;
+       case V4L2_CID_FLASH_STROBE_STATUS:
+       case V4L2_CID_FLASH_READY:
+               *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+               break;
        }
 }
 EXPORT_SYMBOL(v4l2_ctrl_fill);
@@ -537,6 +788,42 @@ static bool type_is_int(const struct v4l2_ctrl *ctrl)
        }
 }
 
+static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes)
+{
+       memset(ev->reserved, 0, sizeof(ev->reserved));
+       ev->type = V4L2_EVENT_CTRL;
+       ev->id = ctrl->id;
+       ev->u.ctrl.changes = changes;
+       ev->u.ctrl.type = ctrl->type;
+       ev->u.ctrl.flags = ctrl->flags;
+       if (ctrl->type == V4L2_CTRL_TYPE_STRING)
+               ev->u.ctrl.value64 = 0;
+       else
+               ev->u.ctrl.value64 = ctrl->cur.val64;
+       ev->u.ctrl.minimum = ctrl->minimum;
+       ev->u.ctrl.maximum = ctrl->maximum;
+       if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+               ev->u.ctrl.step = 1;
+       else
+               ev->u.ctrl.step = ctrl->step;
+       ev->u.ctrl.default_value = ctrl->default_value;
+}
+
+static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
+{
+       struct v4l2_event ev;
+       struct v4l2_subscribed_event *sev;
+
+       if (list_empty(&ctrl->ev_subs))
+               return;
+       fill_event(&ev, ctrl, changes);
+
+       list_for_each_entry(sev, &ctrl->ev_subs, node)
+               if (sev->fh && (sev->fh != fh ||
+                               (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK)))
+                       v4l2_event_queue_fh(sev->fh, &ev);
+}
+
 /* Helper function: copy the current control value back to the caller */
 static int cur_to_user(struct v4l2_ext_control *c,
                       struct v4l2_ctrl *ctrl)
@@ -624,22 +911,45 @@ static int new_to_user(struct v4l2_ext_control *c,
 }
 
 /* Copy the new value to the current value. */
-static void new_to_cur(struct v4l2_ctrl *ctrl)
+static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
+                                               bool update_inactive)
 {
+       bool changed = false;
+
        if (ctrl == NULL)
                return;
        switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_BUTTON:
+               changed = true;
+               break;
        case V4L2_CTRL_TYPE_STRING:
                /* strings are always 0-terminated */
+               changed = strcmp(ctrl->string, ctrl->cur.string);
                strcpy(ctrl->cur.string, ctrl->string);
                break;
        case V4L2_CTRL_TYPE_INTEGER64:
+               changed = ctrl->val64 != ctrl->cur.val64;
                ctrl->cur.val64 = ctrl->val64;
                break;
        default:
+               changed = ctrl->val != ctrl->cur.val;
                ctrl->cur.val = ctrl->val;
                break;
        }
+       if (update_inactive) {
+               ctrl->flags &= ~V4L2_CTRL_FLAG_INACTIVE;
+               if (!is_cur_manual(ctrl->cluster[0]))
+                       ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+       }
+       if (changed || update_inactive) {
+               /* If a control was changed that was not one of the controls
+                  modified by the application, then send the event to all. */
+               if (!ctrl->is_new)
+                       fh = NULL;
+               send_event(fh, ctrl,
+                       (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) |
+                       (update_inactive ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
+       }
 }
 
 /* Copy the current value to the new value */
@@ -692,13 +1002,11 @@ static int cluster_changed(struct v4l2_ctrl *master)
        return diff;
 }
 
-/* Validate a new control */
-static int validate_new(struct v4l2_ctrl *ctrl)
+/* Validate integer-type control */
+static int validate_new_int(const struct v4l2_ctrl *ctrl, s32 *pval)
 {
-       s32 val = ctrl->val;
-       char *s = ctrl->string;
+       s32 val = *pval;
        u32 offset;
-       size_t len;
 
        switch (ctrl->type) {
        case V4L2_CTRL_TYPE_INTEGER:
@@ -711,11 +1019,11 @@ static int validate_new(struct v4l2_ctrl *ctrl)
                offset = val - ctrl->minimum;
                offset = ctrl->step * (offset / ctrl->step);
                val = ctrl->minimum + offset;
-               ctrl->val = val;
+               *pval = val;
                return 0;
 
        case V4L2_CTRL_TYPE_BOOLEAN:
-               ctrl->val = !!ctrl->val;
+               *pval = !!val;
                return 0;
 
        case V4L2_CTRL_TYPE_MENU:
@@ -726,11 +1034,35 @@ static int validate_new(struct v4l2_ctrl *ctrl)
                        return -EINVAL;
                return 0;
 
+       case V4L2_CTRL_TYPE_BITMASK:
+               *pval &= ctrl->maximum;
+               return 0;
+
        case V4L2_CTRL_TYPE_BUTTON:
        case V4L2_CTRL_TYPE_CTRL_CLASS:
-               ctrl->val64 = 0;
+               *pval = 0;
                return 0;
 
+       default:
+               return -EINVAL;
+       }
+}
+
+/* Validate a new control */
+static int validate_new(const struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
+{
+       char *s = c->string;
+       size_t len;
+
+       switch (ctrl->type) {
+       case V4L2_CTRL_TYPE_INTEGER:
+       case V4L2_CTRL_TYPE_BOOLEAN:
+       case V4L2_CTRL_TYPE_MENU:
+       case V4L2_CTRL_TYPE_BITMASK:
+       case V4L2_CTRL_TYPE_BUTTON:
+       case V4L2_CTRL_TYPE_CTRL_CLASS:
+               return validate_new_int(ctrl, &c->value);
+
        case V4L2_CTRL_TYPE_INTEGER64:
                return 0;
 
@@ -780,6 +1112,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
 {
        struct v4l2_ctrl_ref *ref, *next_ref;
        struct v4l2_ctrl *ctrl, *next_ctrl;
+       struct v4l2_subscribed_event *sev, *next_sev;
 
        if (hdl == NULL || hdl->buckets == NULL)
                return;
@@ -793,6 +1126,8 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
        /* Free all controls owned by the handler */
        list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
                list_del(&ctrl->node);
+               list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
+                       list_del(&sev->node);
                kfree(ctrl);
        }
        kfree(hdl->buckets);
@@ -962,13 +1297,17 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 
        /* Sanity checks */
        if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
-           max < min ||
            (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
+           (type == V4L2_CTRL_TYPE_BITMASK && max == 0) ||
            (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
            (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
                handler_set_err(hdl, -ERANGE);
                return NULL;
        }
+       if (type != V4L2_CTRL_TYPE_BITMASK && max < min) {
+               handler_set_err(hdl, -ERANGE);
+               return NULL;
+       }
        if ((type == V4L2_CTRL_TYPE_INTEGER ||
             type == V4L2_CTRL_TYPE_MENU ||
             type == V4L2_CTRL_TYPE_BOOLEAN) &&
@@ -976,6 +1315,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
                handler_set_err(hdl, -ERANGE);
                return NULL;
        }
+       if (type == V4L2_CTRL_TYPE_BITMASK && ((def & ~max) || min || step)) {
+               handler_set_err(hdl, -ERANGE);
+               return NULL;
+       }
 
        if (type == V4L2_CTRL_TYPE_BUTTON)
                flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -991,6 +1334,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
        }
 
        INIT_LIST_HEAD(&ctrl->node);
+       INIT_LIST_HEAD(&ctrl->ev_subs);
        ctrl->handler = hdl;
        ctrl->ops = ops;
        ctrl->id = id;
@@ -1132,6 +1476,9 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
                /* Skip handler-private controls. */
                if (ctrl->is_private)
                        continue;
+               /* And control classes */
+               if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+                       continue;
                ret = handler_new_ref(hdl, ctrl);
                if (ret)
                        break;
@@ -1147,7 +1494,7 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
        int i;
 
        /* The first control is the master control and it must not be NULL */
-       BUG_ON(controls[0] == NULL);
+       BUG_ON(ncontrols == 0 || controls[0] == NULL);
 
        for (i = 0; i < ncontrols; i++) {
                if (controls[i]) {
@@ -1158,18 +1505,47 @@ void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
 }
 EXPORT_SYMBOL(v4l2_ctrl_cluster);
 
+void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
+                           u8 manual_val, bool set_volatile)
+{
+       struct v4l2_ctrl *master = controls[0];
+       u32 flag;
+       int i;
+
+       v4l2_ctrl_cluster(ncontrols, controls);
+       WARN_ON(ncontrols <= 1);
+       WARN_ON(manual_val < master->minimum || manual_val > master->maximum);
+       master->is_auto = true;
+       master->manual_mode_value = manual_val;
+       master->flags |= V4L2_CTRL_FLAG_UPDATE;
+       flag = is_cur_manual(master) ? 0 : V4L2_CTRL_FLAG_INACTIVE;
+
+       for (i = 1; i < ncontrols; i++)
+               if (controls[i]) {
+                       controls[i]->is_volatile = set_volatile;
+                       controls[i]->flags |= flag;
+               }
+}
+EXPORT_SYMBOL(v4l2_ctrl_auto_cluster);
+
 /* Activate/deactivate a control. */
 void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
 {
+       /* invert since the actual flag is called 'inactive' */
+       bool inactive = !active;
+       bool old;
+
        if (ctrl == NULL)
                return;
 
-       if (!active)
+       if (inactive)
                /* set V4L2_CTRL_FLAG_INACTIVE */
-               set_bit(4, &ctrl->flags);
+               old = test_and_set_bit(4, &ctrl->flags);
        else
                /* clear V4L2_CTRL_FLAG_INACTIVE */
-               clear_bit(4, &ctrl->flags);
+               old = test_and_clear_bit(4, &ctrl->flags);
+       if (old != inactive)
+               send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
 }
 EXPORT_SYMBOL(v4l2_ctrl_activate);
 
@@ -1181,15 +1557,21 @@ EXPORT_SYMBOL(v4l2_ctrl_activate);
    these controls. */
 void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
 {
+       bool old;
+
        if (ctrl == NULL)
                return;
 
+       v4l2_ctrl_lock(ctrl);
        if (grabbed)
                /* set V4L2_CTRL_FLAG_GRABBED */
-               set_bit(1, &ctrl->flags);
+               old = test_and_set_bit(1, &ctrl->flags);
        else
                /* clear V4L2_CTRL_FLAG_GRABBED */
-               clear_bit(1, &ctrl->flags);
+               old = test_and_clear_bit(1, &ctrl->flags);
+       if (old != grabbed)
+               send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
+       v4l2_ctrl_unlock(ctrl);
 }
 EXPORT_SYMBOL(v4l2_ctrl_grab);
 
@@ -1217,6 +1599,9 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
        case V4L2_CTRL_TYPE_MENU:
                printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]);
                break;
+       case V4L2_CTRL_TYPE_BITMASK:
+               printk(KERN_CONT "0x%08x", ctrl->cur.val);
+               break;
        case V4L2_CTRL_TYPE_INTEGER64:
                printk(KERN_CONT "%lld", ctrl->cur.val64);
                break;
@@ -1277,26 +1662,21 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
                int i;
 
                /* Skip if this control was already handled by a cluster. */
-               if (ctrl->done)
+               /* Skip button controls and read-only controls. */
+               if (ctrl->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+                   (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
                        continue;
 
                for (i = 0; i < master->ncontrols; i++) {
                        if (master->cluster[i]) {
                                cur_to_new(master->cluster[i]);
                                master->cluster[i]->is_new = 1;
+                               master->cluster[i]->done = true;
                        }
                }
-
-               /* Skip button controls and read-only controls. */
-               if (ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
-                   (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
-                       continue;
-               ret = master->ops->s_ctrl(master);
+               ret = call_op(master, s_ctrl);
                if (ret)
                        break;
-               for (i = 0; i < master->ncontrols; i++)
-                       if (master->cluster[i])
-                               master->cluster[i]->done = true;
        }
        mutex_unlock(&hdl->lock);
        return ret;
@@ -1447,18 +1827,19 @@ EXPORT_SYMBOL(v4l2_subdev_querymenu);
    Find the controls in the control array and do some basic checks. */
 static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
                             struct v4l2_ext_controls *cs,
-                            struct ctrl_helper *helpers,
-                            bool try)
+                            struct v4l2_ctrl_helper *helpers)
 {
+       struct v4l2_ctrl_helper *h;
+       bool have_clusters = false;
        u32 i;
 
-       for (i = 0; i < cs->count; i++) {
+       for (i = 0, h = helpers; i < cs->count; i++, h++) {
                struct v4l2_ext_control *c = &cs->controls[i];
+               struct v4l2_ctrl_ref *ref;
                struct v4l2_ctrl *ctrl;
                u32 id = c->id & V4L2_CTRL_ID_MASK;
 
-               if (try)
-                       cs->error_idx = i;
+               cs->error_idx = i;
 
                if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class)
                        return -EINVAL;
@@ -1467,53 +1848,59 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
                   extended controls */
                if (id >= V4L2_CID_PRIVATE_BASE)
                        return -EINVAL;
-               ctrl = v4l2_ctrl_find(hdl, id);
-               if (ctrl == NULL)
+               ref = find_ref_lock(hdl, id);
+               if (ref == NULL)
                        return -EINVAL;
+               ctrl = ref->ctrl;
                if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED)
                        return -EINVAL;
 
-               helpers[i].ctrl = ctrl;
-               helpers[i].handled = false;
+               if (ctrl->cluster[0]->ncontrols > 1)
+                       have_clusters = true;
+               if (ctrl->cluster[0] != ctrl)
+                       ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
+               /* Store the ref to the master control of the cluster */
+               h->mref = ref;
+               h->ctrl = ctrl;
+               /* Initially set next to 0, meaning that there is no other
+                  control in this helper array belonging to the same
+                  cluster */
+               h->next = 0;
        }
-       return 0;
-}
 
-typedef int (*cluster_func)(struct v4l2_ext_control *c,
-                           struct v4l2_ctrl *ctrl);
+       /* We are done if there were no controls that belong to a multi-
+          control cluster. */
+       if (!have_clusters)
+               return 0;
 
-/* Walk over all controls in v4l2_ext_controls belonging to the same cluster
-   and call the provided function. */
-static int cluster_walk(unsigned from,
-                       struct v4l2_ext_controls *cs,
-                       struct ctrl_helper *helpers,
-                       cluster_func f)
-{
-       struct v4l2_ctrl **cluster = helpers[from].ctrl->cluster;
-       int ret = 0;
-       int i;
+       /* The code below figures out in O(n) time which controls in the list
+          belong to the same cluster. */
 
-       /* Find any controls from the same cluster and call the function */
-       for (i = from; !ret && i < cs->count; i++) {
-               struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+       /* This has to be done with the handler lock taken. */
+       mutex_lock(&hdl->lock);
 
-               if (!helpers[i].handled && ctrl->cluster == cluster)
-                       ret = f(&cs->controls[i], ctrl);
+       /* First zero the helper field in the master control references */
+       for (i = 0; i < cs->count; i++)
+               helpers[i].mref->helper = 0;
+       for (i = 0, h = helpers; i < cs->count; i++, h++) {
+               struct v4l2_ctrl_ref *mref = h->mref;
+
+               /* If the mref->helper is set, then it points to an earlier
+                  helper that belongs to the same cluster. */
+               if (mref->helper) {
+                       /* Set the next field of mref->helper to the current
+                          index: this means that that earlier helper now
+                          points to the next helper in the same cluster. */
+                       mref->helper->next = i;
+                       /* mref should be set only for the first helper in the
+                          cluster, clear the others. */
+                       h->mref = NULL;
+               }
+               /* Point the mref helper to the current helper struct. */
+               mref->helper = h;
        }
-       return ret;
-}
-
-static void cluster_done(unsigned from,
-                        struct v4l2_ext_controls *cs,
-                        struct ctrl_helper *helpers)
-{
-       struct v4l2_ctrl **cluster = helpers[from].ctrl->cluster;
-       int i;
-
-       /* Find any controls from the same cluster and mark them as handled */
-       for (i = from; i < cs->count; i++)
-               if (helpers[i].ctrl->cluster == cluster)
-                       helpers[i].handled = true;
+       mutex_unlock(&hdl->lock);
+       return 0;
 }
 
 /* Handles the corner case where cs->count == 0. It checks whether the
@@ -1531,10 +1918,10 @@ static int class_check(struct v4l2_ctrl_handler *hdl, u32 ctrl_class)
 /* Get extended controls. Allocates the helpers array if needed. */
 int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
 {
-       struct ctrl_helper helper[4];
-       struct ctrl_helper *helpers = helper;
+       struct v4l2_ctrl_helper helper[4];
+       struct v4l2_ctrl_helper *helpers = helper;
        int ret;
-       int i;
+       int i, j;
 
        cs->error_idx = cs->count;
        cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
@@ -1551,30 +1938,46 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
                        return -ENOMEM;
        }
 
-       ret = prepare_ext_ctrls(hdl, cs, helpers, false);
+       ret = prepare_ext_ctrls(hdl, cs, helpers);
+       cs->error_idx = cs->count;
 
        for (i = 0; !ret && i < cs->count; i++)
                if (helpers[i].ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
                        ret = -EACCES;
 
        for (i = 0; !ret && i < cs->count; i++) {
-               struct v4l2_ctrl *ctrl = helpers[i].ctrl;
-               struct v4l2_ctrl *master = ctrl->cluster[0];
+               int (*ctrl_to_user)(struct v4l2_ext_control *c,
+                                   struct v4l2_ctrl *ctrl) = cur_to_user;
+               struct v4l2_ctrl *master;
 
-               if (helpers[i].handled)
+               if (helpers[i].mref == NULL)
                        continue;
 
+               master = helpers[i].mref->ctrl;
                cs->error_idx = i;
 
                v4l2_ctrl_lock(master);
-               /* g_volatile_ctrl will update the current control values */
-               if (ctrl->is_volatile && master->ops->g_volatile_ctrl)
-                       ret = master->ops->g_volatile_ctrl(master);
-               /* If OK, then copy the current control values to the caller */
-               if (!ret)
-                       ret = cluster_walk(i, cs, helpers, cur_to_user);
+
+               /* g_volatile_ctrl will update the new control values */
+               if (has_op(master, g_volatile_ctrl) && !is_cur_manual(master)) {
+                       for (j = 0; j < master->ncontrols; j++)
+                               cur_to_new(master->cluster[j]);
+                       ret = call_op(master, g_volatile_ctrl);
+                       ctrl_to_user = new_to_user;
+               }
+               /* If OK, then copy the current (for non-volatile controls)
+                  or the new (for volatile controls) control values to the
+                  caller */
+               if (!ret) {
+                       u32 idx = i;
+
+                       do {
+                               ret = ctrl_to_user(cs->controls + idx,
+                                                  helpers[idx].ctrl);
+                               idx = helpers[idx].next;
+                       } while (!ret && idx);
+               }
                v4l2_ctrl_unlock(master);
-               cluster_done(i, cs, helpers);
        }
 
        if (cs->count > ARRAY_SIZE(helper))
@@ -1594,15 +1997,21 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
 {
        struct v4l2_ctrl *master = ctrl->cluster[0];
        int ret = 0;
+       int i;
 
        if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
                return -EACCES;
 
        v4l2_ctrl_lock(master);
        /* g_volatile_ctrl will update the current control values */
-       if (ctrl->is_volatile && master->ops->g_volatile_ctrl)
-               ret = master->ops->g_volatile_ctrl(master);
-       *val = ctrl->cur.val;
+       if (ctrl->is_volatile && !is_cur_manual(master)) {
+               for (i = 0; i < master->ncontrols; i++)
+                       cur_to_new(master->cluster[i]);
+               ret = call_op(master, g_volatile_ctrl);
+               *val = ctrl->val;
+       } else {
+               *val = ctrl->cur.val;
+       }
        v4l2_ctrl_unlock(master);
        return ret;
 }
@@ -1638,72 +2047,61 @@ EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
 /* Core function that calls try/s_ctrl and ensures that the new value is
    copied to the current value on a set.
    Must be called with ctrl->handler->lock held. */
-static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set)
+static int try_or_set_cluster(struct v4l2_fh *fh,
+                             struct v4l2_ctrl *master, bool set)
 {
-       bool try = !set;
-       int ret = 0;
+       bool update_flag;
+       int ret;
        int i;
 
        /* Go through the cluster and either validate the new value or
           (if no new value was set), copy the current value to the new
           value, ensuring a consistent view for the control ops when
           called. */
-       for (i = 0; !ret && i < master->ncontrols; i++) {
+       for (i = 0; i < master->ncontrols; i++) {
                struct v4l2_ctrl *ctrl = master->cluster[i];
 
                if (ctrl == NULL)
                        continue;
 
-               if (ctrl->is_new) {
-                       /* Double check this: it may have changed since the
-                          last check in try_or_set_ext_ctrls(). */
-                       if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
-                               return -EBUSY;
-
-                       /* Validate if required */
-                       if (!set)
-                               ret = validate_new(ctrl);
+               if (!ctrl->is_new) {
+                       cur_to_new(ctrl);
                        continue;
                }
-               /* No new value was set, so copy the current and force
-                  a call to try_ctrl later, since the values for the cluster
-                  may now have changed and the end result might be invalid. */
-               try = true;
-               cur_to_new(ctrl);
+               /* Check again: it may have changed since the
+                  previous check in try_or_set_ext_ctrls(). */
+               if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
+                       return -EBUSY;
        }
 
-       /* For larger clusters you have to call try_ctrl again to
-          verify that the controls are still valid after the
-          'cur_to_new' above. */
-       if (!ret && master->ops->try_ctrl && try)
-               ret = master->ops->try_ctrl(master);
+       ret = call_op(master, try_ctrl);
 
        /* Don't set if there is no change */
-       if (!ret && set && cluster_changed(master)) {
-               ret = master->ops->s_ctrl(master);
-               /* If OK, then make the new values permanent. */
-               if (!ret)
-                       for (i = 0; i < master->ncontrols; i++)
-                               new_to_cur(master->cluster[i]);
-       }
-       return ret;
+       if (ret || !set || !cluster_changed(master))
+               return ret;
+       ret = call_op(master, s_ctrl);
+       if (ret)
+               return ret;
+
+       /* If OK, then make the new values permanent. */
+       update_flag = is_cur_manual(master) != is_new_manual(master);
+       for (i = 0; i < master->ncontrols; i++)
+               new_to_cur(fh, master->cluster[i], update_flag && i > 0);
+       return 0;
 }
 
-/* Try or set controls. */
-static int try_or_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
-                               struct v4l2_ext_controls *cs,
-                               struct ctrl_helper *helpers,
-                               bool set)
+/* Validate controls. */
+static int validate_ctrls(struct v4l2_ext_controls *cs,
+                         struct v4l2_ctrl_helper *helpers, bool set)
 {
-       unsigned i, j;
+       unsigned i;
        int ret = 0;
 
        cs->error_idx = cs->count;
        for (i = 0; i < cs->count; i++) {
                struct v4l2_ctrl *ctrl = helpers[i].ctrl;
 
-               if (!set)
-                       cs->error_idx = i;
+               cs->error_idx = i;
 
                if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
                        return -EACCES;
@@ -1715,50 +2113,22 @@ static int try_or_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
                   best-effort to avoid that. */
                if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
                        return -EBUSY;
+               ret = validate_new(ctrl, &cs->controls[i]);
+               if (ret)
+                       return ret;
        }
-
-       for (i = 0; !ret && i < cs->count; i++) {
-               struct v4l2_ctrl *ctrl = helpers[i].ctrl;
-               struct v4l2_ctrl *master = ctrl->cluster[0];
-
-               cs->error_idx = i;
-
-               if (helpers[i].handled)
-                       continue;
-
-               v4l2_ctrl_lock(ctrl);
-
-               /* Reset the 'is_new' flags of the cluster */
-               for (j = 0; j < master->ncontrols; j++)
-                       if (master->cluster[j])
-                               master->cluster[j]->is_new = 0;
-
-               /* Copy the new caller-supplied control values.
-                  user_to_new() sets 'is_new' to 1. */
-               ret = cluster_walk(i, cs, helpers, user_to_new);
-
-               if (!ret)
-                       ret = try_or_set_control_cluster(master, set);
-
-               /* Copy the new values back to userspace. */
-               if (!ret)
-                       ret = cluster_walk(i, cs, helpers, new_to_user);
-
-               v4l2_ctrl_unlock(ctrl);
-               cluster_done(i, cs, helpers);
-       }
-       return ret;
+       return 0;
 }
 
 /* Try or try-and-set controls */
-static int try_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
                             struct v4l2_ext_controls *cs,
                             bool set)
 {
-       struct ctrl_helper helper[4];
-       struct ctrl_helper *helpers = helper;
+       struct v4l2_ctrl_helper helper[4];
+       struct v4l2_ctrl_helper *helpers = helper;
+       unsigned i, j;
        int ret;
-       int i;
 
        cs->error_idx = cs->count;
        cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
@@ -1774,25 +2144,49 @@ static int try_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
                if (!helpers)
                        return -ENOMEM;
        }
-       ret = prepare_ext_ctrls(hdl, cs, helpers, !set);
-       if (ret)
-               goto free;
-
-       /* First 'try' all controls and abort on error */
-       ret = try_or_set_ext_ctrls(hdl, cs, helpers, false);
-       /* If this is a 'set' operation and the initial 'try' failed,
-          then set error_idx to count to tell the application that no
-          controls changed value yet. */
-       if (set)
+       ret = prepare_ext_ctrls(hdl, cs, helpers);
+       if (!ret)
+               ret = validate_ctrls(cs, helpers, set);
+       if (ret && set)
                cs->error_idx = cs->count;
-       if (!ret && set) {
-               /* Reset 'handled' state */
-               for (i = 0; i < cs->count; i++)
-                       helpers[i].handled = false;
-               ret = try_or_set_ext_ctrls(hdl, cs, helpers, true);
+       for (i = 0; !ret && i < cs->count; i++) {
+               struct v4l2_ctrl *master;
+               u32 idx = i;
+
+               if (helpers[i].mref == NULL)
+                       continue;
+
+               cs->error_idx = i;
+               master = helpers[i].mref->ctrl;
+               v4l2_ctrl_lock(master);
+
+               /* Reset the 'is_new' flags of the cluster */
+               for (j = 0; j < master->ncontrols; j++)
+                       if (master->cluster[j])
+                               master->cluster[j]->is_new = 0;
+
+               /* Copy the new caller-supplied control values.
+                  user_to_new() sets 'is_new' to 1. */
+               do {
+                       ret = user_to_new(cs->controls + idx, helpers[idx].ctrl);
+                       idx = helpers[idx].next;
+               } while (!ret && idx);
+
+               if (!ret)
+                       ret = try_or_set_cluster(fh, master, set);
+
+               /* Copy the new values back to userspace. */
+               if (!ret) {
+                       idx = i;
+                       do {
+                               ret = new_to_user(cs->controls + idx,
+                                               helpers[idx].ctrl);
+                               idx = helpers[idx].next;
+                       } while (!ret && idx);
+               }
+               v4l2_ctrl_unlock(master);
        }
 
-free:
        if (cs->count > ARRAY_SIZE(helper))
                kfree(helpers);
        return ret;
@@ -1800,37 +2194,39 @@ free:
 
 int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
 {
-       return try_set_ext_ctrls(hdl, cs, false);
+       return try_set_ext_ctrls(NULL, hdl, cs, false);
 }
 EXPORT_SYMBOL(v4l2_try_ext_ctrls);
 
-int v4l2_s_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+                                       struct v4l2_ext_controls *cs)
 {
-       return try_set_ext_ctrls(hdl, cs, true);
+       return try_set_ext_ctrls(fh, hdl, cs, true);
 }
 EXPORT_SYMBOL(v4l2_s_ext_ctrls);
 
 int v4l2_subdev_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs)
 {
-       return try_set_ext_ctrls(sd->ctrl_handler, cs, false);
+       return try_set_ext_ctrls(NULL, sd->ctrl_handler, cs, false);
 }
 EXPORT_SYMBOL(v4l2_subdev_try_ext_ctrls);
 
 int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs)
 {
-       return try_set_ext_ctrls(sd->ctrl_handler, cs, true);
+       return try_set_ext_ctrls(NULL, sd->ctrl_handler, cs, true);
 }
 EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
 
 /* Helper function for VIDIOC_S_CTRL compatibility */
-static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
+static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, s32 *val)
 {
        struct v4l2_ctrl *master = ctrl->cluster[0];
        int ret;
        int i;
 
-       if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
-               return -EACCES;
+       ret = validate_new_int(ctrl, val);
+       if (ret)
+               return ret;
 
        v4l2_ctrl_lock(ctrl);
 
@@ -1841,28 +2237,30 @@ static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
 
        ctrl->val = *val;
        ctrl->is_new = 1;
-       ret = try_or_set_control_cluster(master, false);
-       if (!ret)
-               ret = try_or_set_control_cluster(master, true);
+       ret = try_or_set_cluster(fh, master, true);
        *val = ctrl->cur.val;
        v4l2_ctrl_unlock(ctrl);
        return ret;
 }
 
-int v4l2_s_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
+int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+                                       struct v4l2_control *control)
 {
        struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
 
        if (ctrl == NULL || !type_is_int(ctrl))
                return -EINVAL;
 
-       return set_ctrl(ctrl, &control->value);
+       if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+               return -EACCES;
+
+       return set_ctrl(fh, ctrl, &control->value);
 }
 EXPORT_SYMBOL(v4l2_s_ctrl);
 
 int v4l2_subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *control)
 {
-       return v4l2_s_ctrl(sd->ctrl_handler, control);
+       return v4l2_s_ctrl(NULL, sd->ctrl_handler, control);
 }
 EXPORT_SYMBOL(v4l2_subdev_s_ctrl);
 
@@ -1870,6 +2268,34 @@ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
 {
        /* It's a driver bug if this happens. */
        WARN_ON(!type_is_int(ctrl));
-       return set_ctrl(ctrl, &val);
+       return set_ctrl(NULL, ctrl, &val);
 }
 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
+
+void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
+                               struct v4l2_subscribed_event *sev)
+{
+       v4l2_ctrl_lock(ctrl);
+       list_add_tail(&sev->node, &ctrl->ev_subs);
+       if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
+           (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL)) {
+               struct v4l2_event ev;
+               u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
+
+               if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY))
+                       changes |= V4L2_EVENT_CTRL_CH_VALUE;
+               fill_event(&ev, ctrl, changes);
+               v4l2_event_queue_fh(sev->fh, &ev);
+       }
+       v4l2_ctrl_unlock(ctrl);
+}
+EXPORT_SYMBOL(v4l2_ctrl_add_event);
+
+void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
+                               struct v4l2_subscribed_event *sev)
+{
+       v4l2_ctrl_lock(ctrl);
+       list_del(&sev->node);
+       v4l2_ctrl_unlock(ctrl);
+}
+EXPORT_SYMBOL(v4l2_ctrl_del_event);
index 4aae501f02d08f22148f5baf88d3620f3125f205..c72856c41434c570d395676a9669e4bd0f792184 100644 (file)
@@ -209,6 +209,7 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
                vdev->v4l2_dev = v4l2_dev;
                vdev->fops = &v4l2_subdev_fops;
                vdev->release = video_device_release_empty;
+               vdev->ctrl_handler = sd->ctrl_handler;
                err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
                                              sd->owner);
                if (err < 0)
index 69fd343d477441f66facfe6d2b01339354037214..53b190cf225e734e71a0ddaacfa1c66b69644b67 100644 (file)
 #include <media/v4l2-dev.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
 
 #include <linux/sched.h>
 #include <linux/slab.h>
 
-int v4l2_event_init(struct v4l2_fh *fh)
+static unsigned sev_pos(const struct v4l2_subscribed_event *sev, unsigned idx)
 {
-       fh->events = kzalloc(sizeof(*fh->events), GFP_KERNEL);
-       if (fh->events == NULL)
-               return -ENOMEM;
-
-       init_waitqueue_head(&fh->events->wait);
-
-       INIT_LIST_HEAD(&fh->events->free);
-       INIT_LIST_HEAD(&fh->events->available);
-       INIT_LIST_HEAD(&fh->events->subscribed);
-
-       fh->events->sequence = -1;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(v4l2_event_init);
-
-int v4l2_event_alloc(struct v4l2_fh *fh, unsigned int n)
-{
-       struct v4l2_events *events = fh->events;
-       unsigned long flags;
-
-       if (!events) {
-               WARN_ON(1);
-               return -ENOMEM;
-       }
-
-       while (events->nallocated < n) {
-               struct v4l2_kevent *kev;
-
-               kev = kzalloc(sizeof(*kev), GFP_KERNEL);
-               if (kev == NULL)
-                       return -ENOMEM;
-
-               spin_lock_irqsave(&fh->vdev->fh_lock, flags);
-               list_add_tail(&kev->list, &events->free);
-               events->nallocated++;
-               spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(v4l2_event_alloc);
-
-#define list_kfree(list, type, member)                         \
-       while (!list_empty(list)) {                             \
-               type *hi;                                       \
-               hi = list_first_entry(list, type, member);      \
-               list_del(&hi->member);                          \
-               kfree(hi);                                      \
-       }
-
-void v4l2_event_free(struct v4l2_fh *fh)
-{
-       struct v4l2_events *events = fh->events;
-
-       if (!events)
-               return;
-
-       list_kfree(&events->free, struct v4l2_kevent, list);
-       list_kfree(&events->available, struct v4l2_kevent, list);
-       list_kfree(&events->subscribed, struct v4l2_subscribed_event, list);
-
-       kfree(events);
-       fh->events = NULL;
+       idx += sev->first;
+       return idx >= sev->elems ? idx - sev->elems : idx;
 }
-EXPORT_SYMBOL_GPL(v4l2_event_free);
 
 static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
 {
-       struct v4l2_events *events = fh->events;
        struct v4l2_kevent *kev;
        unsigned long flags;
 
        spin_lock_irqsave(&fh->vdev->fh_lock, flags);
 
-       if (list_empty(&events->available)) {
+       if (list_empty(&fh->available)) {
                spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
                return -ENOENT;
        }
 
-       WARN_ON(events->navailable == 0);
+       WARN_ON(fh->navailable == 0);
 
-       kev = list_first_entry(&events->available, struct v4l2_kevent, list);
-       list_move(&kev->list, &events->free);
-       events->navailable--;
+       kev = list_first_entry(&fh->available, struct v4l2_kevent, list);
+       list_del(&kev->list);
+       fh->navailable--;
 
-       kev->event.pending = events->navailable;
+       kev->event.pending = fh->navailable;
        *event = kev->event;
+       kev->sev->first = sev_pos(kev->sev, 1);
+       kev->sev->in_use--;
 
        spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
 
@@ -128,7 +67,6 @@ static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
 int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
                       int nonblocking)
 {
-       struct v4l2_events *events = fh->events;
        int ret;
 
        if (nonblocking)
@@ -139,8 +77,8 @@ int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
                mutex_unlock(fh->vdev->lock);
 
        do {
-               ret = wait_event_interruptible(events->wait,
-                                              events->navailable != 0);
+               ret = wait_event_interruptible(fh->wait,
+                                              fh->navailable != 0);
                if (ret < 0)
                        break;
 
@@ -154,23 +92,72 @@ int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
 }
 EXPORT_SYMBOL_GPL(v4l2_event_dequeue);
 
-/* Caller must hold fh->event->lock! */
+/* Caller must hold fh->vdev->fh_lock! */
 static struct v4l2_subscribed_event *v4l2_event_subscribed(
-       struct v4l2_fh *fh, u32 type)
+               struct v4l2_fh *fh, u32 type, u32 id)
 {
-       struct v4l2_events *events = fh->events;
        struct v4l2_subscribed_event *sev;
 
        assert_spin_locked(&fh->vdev->fh_lock);
 
-       list_for_each_entry(sev, &events->subscribed, list) {
-               if (sev->type == type)
+       list_for_each_entry(sev, &fh->subscribed, list)
+               if (sev->type == type && sev->id == id)
                        return sev;
-       }
 
        return NULL;
 }
 
+static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev,
+               const struct timespec *ts)
+{
+       struct v4l2_subscribed_event *sev;
+       struct v4l2_kevent *kev;
+       bool copy_payload = true;
+
+       /* Are we subscribed? */
+       sev = v4l2_event_subscribed(fh, ev->type, ev->id);
+       if (sev == NULL)
+               return;
+
+       /* Increase event sequence number on fh. */
+       fh->sequence++;
+
+       /* Do we have any free events? */
+       if (sev->in_use == sev->elems) {
+               /* no, remove the oldest one */
+               kev = sev->events + sev_pos(sev, 0);
+               list_del(&kev->list);
+               sev->in_use--;
+               sev->first = sev_pos(sev, 1);
+               fh->navailable--;
+               if (sev->elems == 1) {
+                       if (sev->replace) {
+                               sev->replace(&kev->event, ev);
+                               copy_payload = false;
+                       }
+               } else if (sev->merge) {
+                       struct v4l2_kevent *second_oldest =
+                               sev->events + sev_pos(sev, 0);
+                       sev->merge(&kev->event, &second_oldest->event);
+               }
+       }
+
+       /* Take one and fill it. */
+       kev = sev->events + sev_pos(sev, sev->in_use);
+       kev->event.type = ev->type;
+       if (copy_payload)
+               kev->event.u = ev->u;
+       kev->event.id = ev->id;
+       kev->event.timestamp = *ts;
+       kev->event.sequence = fh->sequence;
+       sev->in_use++;
+       list_add_tail(&kev->list, &fh->available);
+
+       fh->navailable++;
+
+       wake_up_all(&fh->wait);
+}
+
 void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
 {
        struct v4l2_fh *fh;
@@ -181,81 +168,95 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
 
        spin_lock_irqsave(&vdev->fh_lock, flags);
 
-       list_for_each_entry(fh, &vdev->fh_list, list) {
-               struct v4l2_events *events = fh->events;
-               struct v4l2_kevent *kev;
+       list_for_each_entry(fh, &vdev->fh_list, list)
+               __v4l2_event_queue_fh(fh, ev, &timestamp);
 
-               /* Are we subscribed? */
-               if (!v4l2_event_subscribed(fh, ev->type))
-                       continue;
+       spin_unlock_irqrestore(&vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_event_queue);
 
-               /* Increase event sequence number on fh. */
-               events->sequence++;
+void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev)
+{
+       unsigned long flags;
+       struct timespec timestamp;
 
-               /* Do we have any free events? */
-               if (list_empty(&events->free))
-                       continue;
+       ktime_get_ts(&timestamp);
 
-               /* Take one and fill it. */
-               kev = list_first_entry(&events->free, struct v4l2_kevent, list);
-               kev->event.type = ev->type;
-               kev->event.u = ev->u;
-               kev->event.timestamp = timestamp;
-               kev->event.sequence = events->sequence;
-               list_move_tail(&kev->list, &events->available);
+       spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+       __v4l2_event_queue_fh(fh, ev, &timestamp);
+       spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_event_queue_fh);
 
-               events->navailable++;
+int v4l2_event_pending(struct v4l2_fh *fh)
+{
+       return fh->navailable;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_pending);
 
-               wake_up_all(&events->wait);
-       }
+static void ctrls_replace(struct v4l2_event *old, const struct v4l2_event *new)
+{
+       u32 old_changes = old->u.ctrl.changes;
 
-       spin_unlock_irqrestore(&vdev->fh_lock, flags);
+       old->u.ctrl = new->u.ctrl;
+       old->u.ctrl.changes |= old_changes;
 }
-EXPORT_SYMBOL_GPL(v4l2_event_queue);
 
-int v4l2_event_pending(struct v4l2_fh *fh)
+static void ctrls_merge(const struct v4l2_event *old, struct v4l2_event *new)
 {
-       return fh->events->navailable;
+       new->u.ctrl.changes |= old->u.ctrl.changes;
 }
-EXPORT_SYMBOL_GPL(v4l2_event_pending);
 
 int v4l2_event_subscribe(struct v4l2_fh *fh,
-                        struct v4l2_event_subscription *sub)
+                        struct v4l2_event_subscription *sub, unsigned elems)
 {
-       struct v4l2_events *events = fh->events;
-       struct v4l2_subscribed_event *sev;
+       struct v4l2_subscribed_event *sev, *found_ev;
+       struct v4l2_ctrl *ctrl = NULL;
        unsigned long flags;
-
-       if (fh->events == NULL) {
-               WARN_ON(1);
-               return -ENOMEM;
+       unsigned i;
+
+       if (elems < 1)
+               elems = 1;
+       if (sub->type == V4L2_EVENT_CTRL) {
+               ctrl = v4l2_ctrl_find(fh->ctrl_handler, sub->id);
+               if (ctrl == NULL)
+                       return -EINVAL;
        }
 
-       sev = kmalloc(sizeof(*sev), GFP_KERNEL);
+       sev = kzalloc(sizeof(*sev) + sizeof(struct v4l2_kevent) * elems, GFP_KERNEL);
        if (!sev)
                return -ENOMEM;
-
-       spin_lock_irqsave(&fh->vdev->fh_lock, flags);
-
-       if (v4l2_event_subscribed(fh, sub->type) == NULL) {
-               INIT_LIST_HEAD(&sev->list);
-               sev->type = sub->type;
-
-               list_add(&sev->list, &events->subscribed);
-               sev = NULL;
+       for (i = 0; i < elems; i++)
+               sev->events[i].sev = sev;
+       sev->type = sub->type;
+       sev->id = sub->id;
+       sev->flags = sub->flags;
+       sev->fh = fh;
+       sev->elems = elems;
+       if (ctrl) {
+               sev->replace = ctrls_replace;
+               sev->merge = ctrls_merge;
        }
 
+       spin_lock_irqsave(&fh->vdev->fh_lock, flags);
+       found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
+       if (!found_ev)
+               list_add(&sev->list, &fh->subscribed);
        spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
 
-       kfree(sev);
+       /* v4l2_ctrl_add_event uses a mutex, so do this outside the spin lock */
+       if (found_ev)
+               kfree(sev);
+       else if (ctrl)
+               v4l2_ctrl_add_event(ctrl, sev);
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
 
-static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
+void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
 {
-       struct v4l2_events *events = fh->events;
+       struct v4l2_event_subscription sub;
        struct v4l2_subscribed_event *sev;
        unsigned long flags;
 
@@ -263,15 +264,18 @@ static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
                sev = NULL;
 
                spin_lock_irqsave(&fh->vdev->fh_lock, flags);
-               if (!list_empty(&events->subscribed)) {
-                       sev = list_first_entry(&events->subscribed,
-                                      struct v4l2_subscribed_event, list);
-                       list_del(&sev->list);
+               if (!list_empty(&fh->subscribed)) {
+                       sev = list_first_entry(&fh->subscribed,
+                                       struct v4l2_subscribed_event, list);
+                       sub.type = sev->type;
+                       sub.id = sev->id;
                }
                spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
-               kfree(sev);
+               if (sev)
+                       v4l2_event_unsubscribe(fh, &sub);
        } while (sev);
 }
+EXPORT_SYMBOL_GPL(v4l2_event_unsubscribe_all);
 
 int v4l2_event_unsubscribe(struct v4l2_fh *fh,
                           struct v4l2_event_subscription *sub)
@@ -286,11 +290,19 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
 
        spin_lock_irqsave(&fh->vdev->fh_lock, flags);
 
-       sev = v4l2_event_subscribed(fh, sub->type);
-       if (sev != NULL)
+       sev = v4l2_event_subscribed(fh, sub->type, sub->id);
+       if (sev != NULL) {
                list_del(&sev->list);
+               sev->fh = NULL;
+       }
 
        spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
+       if (sev && sev->type == V4L2_EVENT_CTRL) {
+               struct v4l2_ctrl *ctrl = v4l2_ctrl_find(fh->ctrl_handler, sev->id);
+
+               if (ctrl)
+                       v4l2_ctrl_del_event(ctrl, sev);
+       }
 
        kfree(sev);
 
index 717f71e6370e564deb08371fb2b72bf326ee3bad..122822d2b8b2ccb1a1869833f44ea77ddec33999 100644 (file)
 #include <media/v4l2-event.h>
 #include <media/v4l2-ioctl.h>
 
-int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
+void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
 {
        fh->vdev = vdev;
+       /* Inherit from video_device. May be overridden by the driver. */
+       fh->ctrl_handler = vdev->ctrl_handler;
        INIT_LIST_HEAD(&fh->list);
        set_bit(V4L2_FL_USES_V4L2_FH, &fh->vdev->flags);
        fh->prio = V4L2_PRIORITY_UNSET;
-
-       /*
-        * fh->events only needs to be initialized if the driver
-        * supports the VIDIOC_SUBSCRIBE_EVENT ioctl.
-        */
-       if (vdev->ioctl_ops && vdev->ioctl_ops->vidioc_subscribe_event)
-               return v4l2_event_init(fh);
-
-       fh->events = NULL;
-
-       return 0;
+       init_waitqueue_head(&fh->wait);
+       INIT_LIST_HEAD(&fh->available);
+       INIT_LIST_HEAD(&fh->subscribed);
+       fh->sequence = -1;
 }
 EXPORT_SYMBOL_GPL(v4l2_fh_init);
 
@@ -91,10 +86,8 @@ void v4l2_fh_exit(struct v4l2_fh *fh)
 {
        if (fh->vdev == NULL)
                return;
-
+       v4l2_event_unsubscribe_all(fh);
        fh->vdev = NULL;
-
-       v4l2_event_free(fh);
 }
 EXPORT_SYMBOL_GPL(v4l2_fh_exit);
 
index 69e8c6ffcc49b8b64700c8049acaf0b172d25350..002ce1363443338a714fca863f254968a224f6ee 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/version.h>
 
 #include <linux/videodev2.h>
 
@@ -542,12 +543,12 @@ static long __video_do_ioctl(struct file *file,
        struct v4l2_fh *vfh = NULL;
        struct v4l2_format f_copy;
        int use_fh_prio = 0;
-       long ret = -EINVAL;
+       long ret = -ENOTTY;
 
        if (ops == NULL) {
                printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n",
                                vfd->name);
-               return -EINVAL;
+               return ret;
        }
 
        if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
@@ -605,6 +606,7 @@ static long __video_do_ioctl(struct file *file,
                if (!ops->vidioc_querycap)
                        break;
 
+               cap->version = LINUX_VERSION_CODE;
                ret = ops->vidioc_querycap(file, fh, cap);
                if (!ret)
                        dbgarg(cmd, "driver=%s, card=%s, bus=%s, "
@@ -1418,7 +1420,9 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_queryctrl *p = arg;
 
-               if (vfd->ctrl_handler)
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_queryctrl(vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
                        ret = v4l2_queryctrl(vfd->ctrl_handler, p);
                else if (ops->vidioc_queryctrl)
                        ret = ops->vidioc_queryctrl(file, fh, p);
@@ -1438,7 +1442,9 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_control *p = arg;
 
-               if (vfd->ctrl_handler)
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_g_ctrl(vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
                        ret = v4l2_g_ctrl(vfd->ctrl_handler, p);
                else if (ops->vidioc_g_ctrl)
                        ret = ops->vidioc_g_ctrl(file, fh, p);
@@ -1470,14 +1476,18 @@ static long __video_do_ioctl(struct file *file,
                struct v4l2_ext_controls ctrls;
                struct v4l2_ext_control ctrl;
 
-               if (!vfd->ctrl_handler &&
+               if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
                        !ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
                        break;
 
                dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
 
+               if (vfh && vfh->ctrl_handler) {
+                       ret = v4l2_s_ctrl(vfh, vfh->ctrl_handler, p);
+                       break;
+               }
                if (vfd->ctrl_handler) {
-                       ret = v4l2_s_ctrl(vfd->ctrl_handler, p);
+                       ret = v4l2_s_ctrl(NULL, vfd->ctrl_handler, p);
                        break;
                }
                if (ops->vidioc_s_ctrl) {
@@ -1501,7 +1511,9 @@ static long __video_do_ioctl(struct file *file,
                struct v4l2_ext_controls *p = arg;
 
                p->error_idx = p->count;
-               if (vfd->ctrl_handler)
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_g_ext_ctrls(vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
                        ret = v4l2_g_ext_ctrls(vfd->ctrl_handler, p);
                else if (ops->vidioc_g_ext_ctrls && check_ext_ctrls(p, 0))
                        ret = ops->vidioc_g_ext_ctrls(file, fh, p);
@@ -1515,11 +1527,14 @@ static long __video_do_ioctl(struct file *file,
                struct v4l2_ext_controls *p = arg;
 
                p->error_idx = p->count;
-               if (!vfd->ctrl_handler && !ops->vidioc_s_ext_ctrls)
+               if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
+                               !ops->vidioc_s_ext_ctrls)
                        break;
                v4l_print_ext_ctrls(cmd, vfd, p, 1);
-               if (vfd->ctrl_handler)
-                       ret = v4l2_s_ext_ctrls(vfd->ctrl_handler, p);
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
+                       ret = v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, p);
                else if (check_ext_ctrls(p, 0))
                        ret = ops->vidioc_s_ext_ctrls(file, fh, p);
                break;
@@ -1529,10 +1544,13 @@ static long __video_do_ioctl(struct file *file,
                struct v4l2_ext_controls *p = arg;
 
                p->error_idx = p->count;
-               if (!vfd->ctrl_handler && !ops->vidioc_try_ext_ctrls)
+               if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
+                               !ops->vidioc_try_ext_ctrls)
                        break;
                v4l_print_ext_ctrls(cmd, vfd, p, 1);
-               if (vfd->ctrl_handler)
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_try_ext_ctrls(vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
                        ret = v4l2_try_ext_ctrls(vfd->ctrl_handler, p);
                else if (check_ext_ctrls(p, 0))
                        ret = ops->vidioc_try_ext_ctrls(file, fh, p);
@@ -1542,7 +1560,9 @@ static long __video_do_ioctl(struct file *file,
        {
                struct v4l2_querymenu *p = arg;
 
-               if (vfd->ctrl_handler)
+               if (vfh && vfh->ctrl_handler)
+                       ret = v4l2_querymenu(vfh->ctrl_handler, p);
+               else if (vfd->ctrl_handler)
                        ret = v4l2_querymenu(vfd->ctrl_handler, p);
                else if (ops->vidioc_querymenu)
                        ret = ops->vidioc_querymenu(file, fh, p);
@@ -2276,7 +2296,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
                                break;
                        }
                        *user_ptr = (void __user *)buf->m.planes;
-                       *kernel_ptr = (void **)&buf->m.planes;
+                       *kernel_ptr = (void *)&buf->m.planes;
                        *array_size = sizeof(struct v4l2_plane) * buf->length;
                        ret = 1;
                }
@@ -2290,7 +2310,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
 
                if (ctrls->count != 0) {
                        *user_ptr = (void __user *)ctrls->controls;
-                       *kernel_ptr = (void **)&ctrls->controls;
+                       *kernel_ptr = (void *)&ctrls->controls;
                        *array_size = sizeof(struct v4l2_ext_control)
                                    * ctrls->count;
                        ret = 1;
index 812729ebf09e53a5461a9df2667ad1f1ff9a286a..b7967c9dc4ae917c16cec58da1ac16b947bedd50 100644 (file)
@@ -75,20 +75,7 @@ static int subdev_open(struct file *file)
                return ret;
        }
 
-       ret = v4l2_fh_init(&subdev_fh->vfh, vdev);
-       if (ret)
-               goto err;
-
-       if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
-               ret = v4l2_event_init(&subdev_fh->vfh);
-               if (ret)
-                       goto err;
-
-               ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents);
-               if (ret)
-                       goto err;
-       }
-
+       v4l2_fh_init(&subdev_fh->vfh, vdev);
        v4l2_fh_add(&subdev_fh->vfh);
        file->private_data = &subdev_fh->vfh;
 #if defined(CONFIG_MEDIA_CONTROLLER)
@@ -155,25 +142,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        switch (cmd) {
        case VIDIOC_QUERYCTRL:
-               return v4l2_queryctrl(sd->ctrl_handler, arg);
+               return v4l2_queryctrl(vfh->ctrl_handler, arg);
 
        case VIDIOC_QUERYMENU:
-               return v4l2_querymenu(sd->ctrl_handler, arg);
+               return v4l2_querymenu(vfh->ctrl_handler, arg);
 
        case VIDIOC_G_CTRL:
-               return v4l2_g_ctrl(sd->ctrl_handler, arg);
+               return v4l2_g_ctrl(vfh->ctrl_handler, arg);
 
        case VIDIOC_S_CTRL:
-               return v4l2_s_ctrl(sd->ctrl_handler, arg);
+               return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg);
 
        case VIDIOC_G_EXT_CTRLS:
-               return v4l2_g_ext_ctrls(sd->ctrl_handler, arg);
+               return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg);
 
        case VIDIOC_S_EXT_CTRLS:
-               return v4l2_s_ext_ctrls(sd->ctrl_handler, arg);
+               return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg);
 
        case VIDIOC_TRY_EXT_CTRLS:
-               return v4l2_try_ext_ctrls(sd->ctrl_handler, arg);
+               return v4l2_try_ext_ctrls(vfh->ctrl_handler, arg);
 
        case VIDIOC_DQEVENT:
                if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
@@ -297,7 +284,7 @@ static unsigned int subdev_poll(struct file *file, poll_table *wait)
        if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
                return POLLERR;
 
-       poll_wait(file, &fh->events->wait, wait);
+       poll_wait(file, &fh->wait, wait);
 
        if (v4l2_event_pending(fh))
                return POLLPRI;
index ddb8f4b46c03bacea044ec9395adefdcee69350d..f300deafd268e555e54f1d9cdefbc22c97cd75cc 100644 (file)
@@ -108,8 +108,9 @@ static struct scatterlist *videobuf_pages_to_sg(struct page **pages,
        if (PageHighMem(pages[0]))
                /* DMA to highmem pages might not work */
                goto highmem;
-       sg_set_page(&sglist[0], pages[0], PAGE_SIZE - offset, offset);
-       size -= PAGE_SIZE - offset;
+       sg_set_page(&sglist[0], pages[0],
+                       min_t(size_t, PAGE_SIZE - offset, size), offset);
+       size -= min_t(size_t, PAGE_SIZE - offset, size);
        for (i = 1; i < nr_pages; i++) {
                if (NULL == pages[i])
                        goto nopage;
index 10a20d9509d982434f456ee300b771c6389f872e..065f468faf8fd021d7b12b59407db380a3cd478e 100644 (file)
@@ -48,12 +48,10 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size)
        buf->sg_desc.size = size;
        buf->sg_desc.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
-       buf->sg_desc.sglist = vmalloc(buf->sg_desc.num_pages *
+       buf->sg_desc.sglist = vzalloc(buf->sg_desc.num_pages *
                                      sizeof(*buf->sg_desc.sglist));
        if (!buf->sg_desc.sglist)
                goto fail_sglist_alloc;
-       memset(buf->sg_desc.sglist, 0, buf->sg_desc.num_pages *
-              sizeof(*buf->sg_desc.sglist));
        sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages);
 
        buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *),
@@ -136,13 +134,11 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
        last  = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
        buf->sg_desc.num_pages = last - first + 1;
 
-       buf->sg_desc.sglist = vmalloc(
+       buf->sg_desc.sglist = vzalloc(
                buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist));
        if (!buf->sg_desc.sglist)
                goto userptr_fail_sglist_alloc;
 
-       memset(buf->sg_desc.sglist, 0,
-               buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist));
        sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages);
 
        buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *),
index b03c3aea5beaf08ac1c51296240dfa573b3b7481..569eeb3dfd506d4647ca9dae2e54db7213e816ec 100644 (file)
@@ -176,7 +176,7 @@ int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
 
        vma->vm_ops->open(vma);
 
-       printk(KERN_DEBUG "%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n",
+       pr_debug("%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n",
                        __func__, paddr, vma->vm_start, size);
 
        return 0;
@@ -194,7 +194,7 @@ static void vb2_common_vm_open(struct vm_area_struct *vma)
 {
        struct vb2_vmarea_handler *h = vma->vm_private_data;
 
-       printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n",
+       pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n",
               __func__, h, atomic_read(h->refcount), vma->vm_start,
               vma->vm_end);
 
@@ -212,7 +212,7 @@ static void vb2_common_vm_close(struct vm_area_struct *vma)
 {
        struct vb2_vmarea_handler *h = vma->vm_private_data;
 
-       printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n",
+       pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n",
               __func__, h, atomic_read(h->refcount), vma->vm_start,
               vma->vm_end);
 
index d63e9d97849339c069e3820298384b1c49be9cb8..52a0a3736c820d156025c8fc91df13d20cb31663 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/time.h>
-#include <linux/version.h>
 #include <linux/kmod.h>
 
 #include <linux/i2c.h>
@@ -61,8 +60,7 @@
 // #define VINO_DEBUG
 // #define VINO_DEBUG_INT
 
-#define VINO_MODULE_VERSION "0.0.6"
-#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 6)
+#define VINO_MODULE_VERSION "0.0.7"
 
 MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver");
 MODULE_VERSION(VINO_MODULE_VERSION);
@@ -2934,7 +2932,6 @@ static int vino_querycap(struct file *file, void *__fh,
        strcpy(cap->driver, vino_driver_name);
        strcpy(cap->card, vino_driver_description);
        strcpy(cap->bus_info, vino_bus_name);
-       cap->version = VINO_VERSION_CODE;
        cap->capabilities =
                V4L2_CAP_VIDEO_CAPTURE |
                V4L2_CAP_STREAMING;
index 2238a613d664b7b9edebdaef4b0a58195888955c..a848bd2af97f0b704fbdf49216da85109ee874c2 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/font.h>
-#include <linux/version.h>
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/kthread.h>
@@ -32,6 +31,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-common.h>
 
 #define VIVI_MODULE_NAME "vivi"
 #define MAX_WIDTH 1920
 #define MAX_HEIGHT 1200
 
-#define VIVI_MAJOR_VERSION 0
-#define VIVI_MINOR_VERSION 8
-#define VIVI_RELEASE 0
-#define VIVI_VERSION \
-       KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
+#define VIVI_VERSION "0.8.1"
 
 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_VERSION(VIVI_VERSION);
 
 static unsigned video_nr = -1;
 module_param(video_nr, uint, 0644);
@@ -167,6 +164,11 @@ struct vivi_dev {
        struct v4l2_ctrl           *contrast;
        struct v4l2_ctrl           *saturation;
        struct v4l2_ctrl           *hue;
+       struct {
+               /* autogain/gain cluster */
+               struct v4l2_ctrl           *autogain;
+               struct v4l2_ctrl           *gain;
+       };
        struct v4l2_ctrl           *volume;
        struct v4l2_ctrl           *button;
        struct v4l2_ctrl           *boolean;
@@ -174,6 +176,7 @@ struct vivi_dev {
        struct v4l2_ctrl           *int64;
        struct v4l2_ctrl           *menu;
        struct v4l2_ctrl           *string;
+       struct v4l2_ctrl           *bitmask;
 
        spinlock_t                 slock;
        struct mutex               mutex;
@@ -457,6 +460,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
        unsigned ms;
        char str[100];
        int h, line = 1;
+       s32 gain;
 
        if (!vbuf)
                return;
@@ -479,6 +483,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
                        dev->width, dev->height, dev->input);
        gen_text(dev, vbuf, line++ * 16, 16, str);
 
+       gain = v4l2_ctrl_g_ctrl(dev->gain);
        mutex_lock(&dev->ctrl_handler.lock);
        snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
                        dev->brightness->cur.val,
@@ -486,11 +491,13 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
                        dev->saturation->cur.val,
                        dev->hue->cur.val);
        gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " volume %3d ", dev->volume->cur.val);
+       snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d ",
+                       dev->autogain->cur.val, gain, dev->volume->cur.val);
        gen_text(dev, vbuf, line++ * 16, 16, str);
-       snprintf(str, sizeof(str), " int32 %d, int64 %lld ",
+       snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
                        dev->int32->cur.val,
-                       dev->int64->cur.val64);
+                       dev->int64->cur.val64,
+                       dev->bitmask->cur.val);
        gen_text(dev, vbuf, line++ * 16, 16, str);
        snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
                        dev->boolean->cur.val,
@@ -524,11 +531,13 @@ static void vivi_thread_tick(struct vivi_dev *dev)
        spin_lock_irqsave(&dev->slock, flags);
        if (list_empty(&dma_q->active)) {
                dprintk(dev, 1, "No active queue to serve\n");
-               goto unlock;
+               spin_unlock_irqrestore(&dev->slock, flags);
+               return;
        }
 
        buf = list_entry(dma_q->active.next, struct vivi_buffer, list);
        list_del(&buf->list);
+       spin_unlock_irqrestore(&dev->slock, flags);
 
        do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
 
@@ -538,8 +547,6 @@ static void vivi_thread_tick(struct vivi_dev *dev)
 
        vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
        dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
-unlock:
-       spin_unlock_irqrestore(&dev->slock, flags);
 }
 
 #define frames_to_ms(frames)                                   \
@@ -812,7 +819,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
        strcpy(cap->driver, "vivi");
        strcpy(cap->card, "vivi");
        strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
-       cap->version = VIVI_VERSION;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
                            V4L2_CAP_READWRITE;
        return 0;
@@ -975,14 +981,37 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
        if (i >= NUM_INPUTS)
                return -EINVAL;
 
+       if (i == dev->input)
+               return 0;
+
        dev->input = i;
        precalculate_bars(dev);
        precalculate_line(dev);
        return 0;
 }
 
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+                               struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_CTRL:
+               return v4l2_event_subscribe(fh, sub, 0);
+       default:
+               return -EINVAL;
+       }
+}
+
 /* --- controls ---------------------------------------------- */
 
+static int vivi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
+
+       if (ctrl == dev->autogain)
+               dev->gain->val = jiffies & 0xff;
+       return 0;
+}
+
 static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
@@ -1010,10 +1039,17 @@ static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct vivi_dev *dev = video_drvdata(file);
+       struct v4l2_fh *fh = file->private_data;
        struct vb2_queue *q = &dev->vb_vidq;
+       unsigned int res;
 
        dprintk(dev, 1, "%s\n", __func__);
-       return vb2_poll(q, file, wait);
+       res = vb2_poll(q, file, wait);
+       if (v4l2_event_pending(fh))
+               res |= POLLPRI;
+       else
+               poll_wait(file, &fh->wait, wait);
+       return res;
 }
 
 static int vivi_close(struct file *file)
@@ -1045,6 +1081,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 }
 
 static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
+       .g_volatile_ctrl = vivi_g_volatile_ctrl,
        .s_ctrl = vivi_s_ctrl,
 };
 
@@ -1117,9 +1154,20 @@ static const struct v4l2_ctrl_config vivi_ctrl_string = {
        .step = 1,
 };
 
+static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
+       .ops = &vivi_ctrl_ops,
+       .id = VIVI_CID_CUSTOM_BASE + 6,
+       .name = "Bitmask",
+       .type = V4L2_CTRL_TYPE_BITMASK,
+       .def = 0x80002000,
+       .min = 0,
+       .max = 0x80402010,
+       .step = 0,
+};
+
 static const struct v4l2_file_operations vivi_fops = {
        .owner          = THIS_MODULE,
-       .open           = v4l2_fh_open,
+       .open           = v4l2_fh_open,
        .release        = vivi_close,
        .read           = vivi_read,
        .poll           = vivi_poll,
@@ -1143,6 +1191,8 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
        .vidioc_s_input       = vidioc_s_input,
        .vidioc_streamon      = vidioc_streamon,
        .vidioc_streamoff     = vidioc_streamoff,
+       .vidioc_subscribe_event = vidioc_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 static struct video_device vivi_template = {
@@ -1213,16 +1263,22 @@ static int __init vivi_create_instance(int inst)
                        V4L2_CID_SATURATION, 0, 255, 1, 127);
        dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
                        V4L2_CID_HUE, -128, 127, 1, 0);
+       dev->autogain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+                       V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+       dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+                       V4L2_CID_GAIN, 0, 255, 1, 100);
        dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
        dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
        dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
        dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
        dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
        dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
+       dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
        if (hdl->error) {
                ret = hdl->error;
                goto unreg_dev;
        }
+       v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
        dev->v4l2_dev.ctrl_handler = hdl;
 
        /* initialize locks */
@@ -1325,9 +1381,8 @@ static int __init vivi_init(void)
        }
 
        printk(KERN_INFO "Video Technology Magazine Virtual Video "
-                       "Capture Board ver %u.%u.%u successfully loaded.\n",
-                       (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
-                       VIVI_VERSION & 0xFF);
+                       "Capture Board ver %s successfully loaded.\n",
+                       VIVI_VERSION);
 
        /* n_devs will reflect the actual number of allocated devices */
        n_devs = i;
index fa35639d0c150bd6851a6c80cd393b464ca92eb9..453dbbd1e6e8636f9d38e8b6d7543c880ed2ae41 100644 (file)
@@ -57,7 +57,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/version.h>
 #include <linux/videodev2.h>
 #include <linux/slab.h>
 #include <media/v4l2-common.h>
@@ -127,7 +126,7 @@ struct w9966 {
 MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
 MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
 MODULE_LICENSE("GPL");
-
+MODULE_VERSION("0.33.1");
 
 #ifdef MODULE
 static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
@@ -568,7 +567,6 @@ static int cam_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card));
        strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
-       vcap->version = KERNEL_VERSION(0, 33, 0);
        vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
        return 0;
 }
index f3f64001492866d49610091e70a996dae2838d1d..d7166afc255edf06ea7396b6efc12b91da92fca3 100644 (file)
@@ -41,10 +41,6 @@ struct zoran_sync {
 };
 
 
-#define MAJOR_VERSION 0                /* driver major version */
-#define MINOR_VERSION 10       /* driver minor version */
-#define RELEASE_VERSION 0      /* release version */
-
 #define ZORAN_NAME    "ZORAN"  /* name of the device */
 
 #define ZR_DEVNAME(zr) ((zr)->name)
index 79b04ac0f1adb97cc6d7c7c9912877bc2d8505b5..c3602d6cd48e839f9fa1cadbad9e8ab9e4e9bcc6 100644 (file)
@@ -123,9 +123,12 @@ int zr36067_debug = 1;
 module_param_named(debug, zr36067_debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-5)");
 
+#define ZORAN_VERSION "0.10.1"
+
 MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
 MODULE_AUTHOR("Serguei Miridonov");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(ZORAN_VERSION);
 
 #define ZR_DEVICE(subven, subdev, data)        { \
        .vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \
@@ -1459,8 +1462,8 @@ static int __init zoran_init(void)
 {
        int res;
 
-       printk(KERN_INFO "Zoran MJPEG board driver version %d.%d.%d\n",
-              MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION);
+       printk(KERN_INFO "Zoran MJPEG board driver version %s\n",
+              ZORAN_VERSION);
 
        /* check the parameters we have been given, adjust if necessary */
        if (v4l_nbufs < 2)
index 2771d818406e7d629de256a709302b0cbaf0d742..d4d05d2ace654ca3698491f7e57dde47530c04b4 100644 (file)
@@ -44,7 +44,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -1538,8 +1537,6 @@ static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability
        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 = KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
-                          RELEASE_VERSION);
        cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
                            V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY;
        return 0;
index 7dfb01e9930ed1a67720e5ce8e33c1f580d4ec3e..c492846c1c5a33770c6488cbfd8095f7c91757db 100644 (file)
@@ -29,7 +29,6 @@
 
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
@@ -42,8 +41,7 @@
 
 
 /* Version Information */
-#define DRIVER_VERSION "v0.73"
-#define ZR364XX_VERSION_CODE KERNEL_VERSION(0, 7, 3)
+#define DRIVER_VERSION "0.7.4"
 #define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
 #define DRIVER_DESC "Zoran 364xx"
 
@@ -744,7 +742,6 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv,
        strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
        strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
                sizeof(cap->bus_info));
-       cap->version = ZR364XX_VERSION_CODE;
        cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
                            V4L2_CAP_READWRITE |
                            V4L2_CAP_STREAMING;
@@ -1721,3 +1718,4 @@ module_exit(zr364xx_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
index a1d4ee6671be52a201a6385c63763ec7fb8b9bc8..ce61a5769765a4fda0fd4b5acfc2883a937480c6 100644 (file)
@@ -827,7 +827,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                                 * DID_SOFT_ERROR is set.
                                 */
                                if (ioc->bus_type == SPI) {
-                                       if (pScsiReq->CDB[0] == READ_6  ||
+                                       if ((pScsiReq->CDB[0] == READ_6  && ((pScsiReq->CDB[1] & 0x02) == 0)) ||
                                            pScsiReq->CDB[0] == READ_10 ||
                                            pScsiReq->CDB[0] == READ_12 ||
                                            pScsiReq->CDB[0] == READ_16 ||
index 37b83eb6d703fd782d9f24f9b4763b9a3be683c8..21574bdf485f3f422ca354e1bedc790a511de148 100644 (file)
@@ -171,6 +171,37 @@ config MFD_TPS6586X
          This driver can also be built as a module.  If so, the module
          will be called tps6586x.
 
+config MFD_TPS65910
+       bool "TPS65910 Power Management chip"
+       depends on I2C=y && GPIOLIB
+       select MFD_CORE
+       select GPIO_TPS65910
+       help
+         if you say yes here you get support for the TPS65910 series of
+         Power Management chips.
+
+config MFD_TPS65912
+       bool
+       depends on GPIOLIB
+
+config MFD_TPS65912_I2C
+       bool "TPS95612 Power Management chip with I2C"
+       select MFD_CORE
+       select MFD_TPS65912
+       depends on I2C=y && GPIOLIB
+       help
+         If you say yes here you get support for the TPS65912 series of
+         PM chips with I2C interface.
+
+config MFD_TPS65912_SPI
+       bool "TPS65912 Power Management chip with SPI"
+       select MFD_CORE
+       select MFD_TPS65912
+       depends on SPI_MASTER && GPIOLIB
+       help
+         If you say yes here you get support for the TPS65912 series of
+         PM chips with SPI interface.
+
 config MENELAUS
        bool "Texas Instruments TWL92330/Menelaus PM chip"
        depends on I2C=y && ARCH_OMAP2
@@ -662,8 +693,9 @@ config MFD_JANZ_CMODIO
          CAN and GPIO controllers.
 
 config MFD_JZ4740_ADC
-       tristate "Support for the JZ4740 SoC ADC core"
+       bool "Support for the JZ4740 SoC ADC core"
        select MFD_CORE
+       select GENERIC_IRQ_CHIP
        depends on MACH_JZ4740
        help
          Say yes here if you want support for the ADC unit in the JZ4740 SoC.
@@ -725,18 +757,19 @@ config MFD_PM8XXX_IRQ
          This is required to use certain other PM 8xxx features, such as GPIO
          and MPP.
 
-config MFD_TPS65910
-       bool "TPS65910 Power Management chip"
-       depends on I2C=y && GPIOLIB
-       select MFD_CORE
-       select GPIO_TPS65910
-       help
-         if you say yes here you get support for the TPS65910 series of
-         Power Management chips.
-
 config TPS65911_COMPARATOR
        tristate
 
+config MFD_AAT2870_CORE
+       bool "Support for the AnalogicTech AAT2870"
+       select MFD_CORE
+       depends on I2C=y && GPIOLIB
+       help
+         If you say yes here you get support for the AAT2870.
+         This driver provides common support for accessing the device,
+         additional drivers must be enabled in order to use the
+         functionality of the device.
+
 endif # MFD_SUPPORT
 
 menu "Multimedia Capabilities Port drivers"
index 22a280fcb7059436966400a4a71caaecfd390ece..c58020303d184922dce43b36845413e3d798ff8d 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_MFD_TC6393XB)    += tc6393xb.o tmio_core.o
 
 obj-$(CONFIG_MFD_WM8400)       += wm8400-core.o
 wm831x-objs                    := wm831x-core.o wm831x-irq.o wm831x-otp.o
+wm831x-objs                    += wm831x-auxadc.o
 obj-$(CONFIG_MFD_WM831X)       += wm831x.o
 obj-$(CONFIG_MFD_WM831X_I2C)   += wm831x-i2c.o
 obj-$(CONFIG_MFD_WM831X_SPI)   += wm831x-spi.o
@@ -35,6 +36,11 @@ obj-$(CONFIG_MFD_WM8994)     += wm8994-core.o wm8994-irq.o
 obj-$(CONFIG_TPS6105X)         += tps6105x.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_TPS6507X)         += tps6507x.o
+obj-$(CONFIG_MFD_TPS65910)     += tps65910.o tps65910-irq.o
+tps65912-objs                   := tps65912-core.o tps65912-irq.o
+obj-$(CONFIG_MFD_TPS65912)     += tps65912.o
+obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o
+obj-$(CONFIG_MFD_TPS65912_SPI)  += tps65912-spi.o
 obj-$(CONFIG_MENELAUS)         += menelaus.o
 
 obj-$(CONFIG_TWL4030_CORE)     += twl-core.o twl4030-irq.o twl6030-irq.o
@@ -94,5 +100,5 @@ obj-$(CONFIG_MFD_CS5535)     += cs5535-mfd.o
 obj-$(CONFIG_MFD_OMAP_USB_HOST)        += omap-usb-host.o
 obj-$(CONFIG_MFD_PM8921_CORE)  += pm8921-core.o
 obj-$(CONFIG_MFD_PM8XXX_IRQ)   += pm8xxx-irq.o
-obj-$(CONFIG_MFD_TPS65910)     += tps65910.o tps65910-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)      += tps65911-comparator.o
+obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c
new file mode 100644 (file)
index 0000000..345dc65
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * linux/drivers/mfd/aat2870-core.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ * Author: Jin Park <jinyoungp@nvidia.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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/aat2870.h>
+#include <linux/regulator/machine.h>
+
+static struct aat2870_register aat2870_regs[AAT2870_REG_NUM] = {
+       /* readable, writeable, value */
+       { 0, 1, 0x00 }, /* 0x00 AAT2870_BL_CH_EN */
+       { 0, 1, 0x16 }, /* 0x01 AAT2870_BLM */
+       { 0, 1, 0x16 }, /* 0x02 AAT2870_BLS */
+       { 0, 1, 0x56 }, /* 0x03 AAT2870_BL1 */
+       { 0, 1, 0x56 }, /* 0x04 AAT2870_BL2 */
+       { 0, 1, 0x56 }, /* 0x05 AAT2870_BL3 */
+       { 0, 1, 0x56 }, /* 0x06 AAT2870_BL4 */
+       { 0, 1, 0x56 }, /* 0x07 AAT2870_BL5 */
+       { 0, 1, 0x56 }, /* 0x08 AAT2870_BL6 */
+       { 0, 1, 0x56 }, /* 0x09 AAT2870_BL7 */
+       { 0, 1, 0x56 }, /* 0x0A AAT2870_BL8 */
+       { 0, 1, 0x00 }, /* 0x0B AAT2870_FLR */
+       { 0, 1, 0x03 }, /* 0x0C AAT2870_FM */
+       { 0, 1, 0x03 }, /* 0x0D AAT2870_FS */
+       { 0, 1, 0x10 }, /* 0x0E AAT2870_ALS_CFG0 */
+       { 0, 1, 0x06 }, /* 0x0F AAT2870_ALS_CFG1 */
+       { 0, 1, 0x00 }, /* 0x10 AAT2870_ALS_CFG2 */
+       { 1, 0, 0x00 }, /* 0x11 AAT2870_AMB */
+       { 0, 1, 0x00 }, /* 0x12 AAT2870_ALS0 */
+       { 0, 1, 0x00 }, /* 0x13 AAT2870_ALS1 */
+       { 0, 1, 0x00 }, /* 0x14 AAT2870_ALS2 */
+       { 0, 1, 0x00 }, /* 0x15 AAT2870_ALS3 */
+       { 0, 1, 0x00 }, /* 0x16 AAT2870_ALS4 */
+       { 0, 1, 0x00 }, /* 0x17 AAT2870_ALS5 */
+       { 0, 1, 0x00 }, /* 0x18 AAT2870_ALS6 */
+       { 0, 1, 0x00 }, /* 0x19 AAT2870_ALS7 */
+       { 0, 1, 0x00 }, /* 0x1A AAT2870_ALS8 */
+       { 0, 1, 0x00 }, /* 0x1B AAT2870_ALS9 */
+       { 0, 1, 0x00 }, /* 0x1C AAT2870_ALSA */
+       { 0, 1, 0x00 }, /* 0x1D AAT2870_ALSB */
+       { 0, 1, 0x00 }, /* 0x1E AAT2870_ALSC */
+       { 0, 1, 0x00 }, /* 0x1F AAT2870_ALSD */
+       { 0, 1, 0x00 }, /* 0x20 AAT2870_ALSE */
+       { 0, 1, 0x00 }, /* 0x21 AAT2870_ALSF */
+       { 0, 1, 0x00 }, /* 0x22 AAT2870_SUB_SET */
+       { 0, 1, 0x00 }, /* 0x23 AAT2870_SUB_CTRL */
+       { 0, 1, 0x00 }, /* 0x24 AAT2870_LDO_AB */
+       { 0, 1, 0x00 }, /* 0x25 AAT2870_LDO_CD */
+       { 0, 1, 0x00 }, /* 0x26 AAT2870_LDO_EN */
+};
+
+static struct mfd_cell aat2870_devs[] = {
+       {
+               .name = "aat2870-backlight",
+               .id = AAT2870_ID_BL,
+               .pdata_size = sizeof(struct aat2870_bl_platform_data),
+       },
+       {
+               .name = "aat2870-regulator",
+               .id = AAT2870_ID_LDOA,
+               .pdata_size = sizeof(struct regulator_init_data),
+       },
+       {
+               .name = "aat2870-regulator",
+               .id = AAT2870_ID_LDOB,
+               .pdata_size = sizeof(struct regulator_init_data),
+       },
+       {
+               .name = "aat2870-regulator",
+               .id = AAT2870_ID_LDOC,
+               .pdata_size = sizeof(struct regulator_init_data),
+       },
+       {
+               .name = "aat2870-regulator",
+               .id = AAT2870_ID_LDOD,
+               .pdata_size = sizeof(struct regulator_init_data),
+       },
+};
+
+static int __aat2870_read(struct aat2870_data *aat2870, u8 addr, u8 *val)
+{
+       int ret;
+
+       if (addr >= AAT2870_REG_NUM) {
+               dev_err(aat2870->dev, "Invalid address, 0x%02x\n", addr);
+               return -EINVAL;
+       }
+
+       if (!aat2870->reg_cache[addr].readable) {
+               *val = aat2870->reg_cache[addr].value;
+               goto out;
+       }
+
+       ret = i2c_master_send(aat2870->client, &addr, 1);
+       if (ret < 0)
+               return ret;
+       if (ret != 1)
+               return -EIO;
+
+       ret = i2c_master_recv(aat2870->client, val, 1);
+       if (ret < 0)
+               return ret;
+       if (ret != 1)
+               return -EIO;
+
+out:
+       dev_dbg(aat2870->dev, "read: addr=0x%02x, val=0x%02x\n", addr, *val);
+       return 0;
+}
+
+static int __aat2870_write(struct aat2870_data *aat2870, u8 addr, u8 val)
+{
+       u8 msg[2];
+       int ret;
+
+       if (addr >= AAT2870_REG_NUM) {
+               dev_err(aat2870->dev, "Invalid address, 0x%02x\n", addr);
+               return -EINVAL;
+       }
+
+       if (!aat2870->reg_cache[addr].writeable) {
+               dev_err(aat2870->dev, "Address 0x%02x is not writeable\n",
+                       addr);
+               return -EINVAL;
+       }
+
+       msg[0] = addr;
+       msg[1] = val;
+       ret = i2c_master_send(aat2870->client, msg, 2);
+       if (ret < 0)
+               return ret;
+       if (ret != 2)
+               return -EIO;
+
+       aat2870->reg_cache[addr].value = val;
+
+       dev_dbg(aat2870->dev, "write: addr=0x%02x, val=0x%02x\n", addr, val);
+       return 0;
+}
+
+static int aat2870_read(struct aat2870_data *aat2870, u8 addr, u8 *val)
+{
+       int ret;
+
+       mutex_lock(&aat2870->io_lock);
+       ret = __aat2870_read(aat2870, addr, val);
+       mutex_unlock(&aat2870->io_lock);
+
+       return ret;
+}
+
+static int aat2870_write(struct aat2870_data *aat2870, u8 addr, u8 val)
+{
+       int ret;
+
+       mutex_lock(&aat2870->io_lock);
+       ret = __aat2870_write(aat2870, addr, val);
+       mutex_unlock(&aat2870->io_lock);
+
+       return ret;
+}
+
+static int aat2870_update(struct aat2870_data *aat2870, u8 addr, u8 mask,
+                         u8 val)
+{
+       int change;
+       u8 old_val, new_val;
+       int ret;
+
+       mutex_lock(&aat2870->io_lock);
+
+       ret = __aat2870_read(aat2870, addr, &old_val);
+       if (ret)
+               goto out_unlock;
+
+       new_val = (old_val & ~mask) | (val & mask);
+       change = old_val != new_val;
+       if (change)
+               ret = __aat2870_write(aat2870, addr, new_val);
+
+out_unlock:
+       mutex_unlock(&aat2870->io_lock);
+
+       return ret;
+}
+
+static inline void aat2870_enable(struct aat2870_data *aat2870)
+{
+       if (aat2870->en_pin >= 0)
+               gpio_set_value(aat2870->en_pin, 1);
+
+       aat2870->is_enable = 1;
+}
+
+static inline void aat2870_disable(struct aat2870_data *aat2870)
+{
+       if (aat2870->en_pin >= 0)
+               gpio_set_value(aat2870->en_pin, 0);
+
+       aat2870->is_enable = 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t aat2870_dump_reg(struct aat2870_data *aat2870, char *buf)
+{
+       u8 addr, val;
+       ssize_t count = 0;
+       int ret;
+
+       count += sprintf(buf, "aat2870 registers\n");
+       for (addr = 0; addr < AAT2870_REG_NUM; addr++) {
+               count += sprintf(buf + count, "0x%02x: ", addr);
+               if (count >= PAGE_SIZE - 1)
+                       break;
+
+               ret = aat2870->read(aat2870, addr, &val);
+               if (ret == 0)
+                       count += snprintf(buf + count, PAGE_SIZE - count,
+                                         "0x%02x", val);
+               else
+                       count += snprintf(buf + count, PAGE_SIZE - count,
+                                         "<read fail: %d>", ret);
+
+               if (count >= PAGE_SIZE - 1)
+                       break;
+
+               count += snprintf(buf + count, PAGE_SIZE - count, "\n");
+               if (count >= PAGE_SIZE - 1)
+                       break;
+       }
+
+       /* Truncate count; min() would cause a warning */
+       if (count >= PAGE_SIZE)
+               count = PAGE_SIZE - 1;
+
+       return count;
+}
+
+static int aat2870_reg_open_file(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+
+       return 0;
+}
+
+static ssize_t aat2870_reg_read_file(struct file *file, char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct aat2870_data *aat2870 = file->private_data;
+       char *buf;
+       ssize_t ret;
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = aat2870_dump_reg(aat2870, buf);
+       if (ret >= 0)
+               ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+       kfree(buf);
+
+       return ret;
+}
+
+static ssize_t aat2870_reg_write_file(struct file *file,
+                                     const char __user *user_buf, size_t count,
+                                     loff_t *ppos)
+{
+       struct aat2870_data *aat2870 = file->private_data;
+       char buf[32];
+       int buf_size;
+       char *start = buf;
+       unsigned long addr, val;
+       int ret;
+
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size)) {
+               dev_err(aat2870->dev, "Failed to copy from user\n");
+               return -EFAULT;
+       }
+       buf[buf_size] = 0;
+
+       while (*start == ' ')
+               start++;
+
+       addr = simple_strtoul(start, &start, 16);
+       if (addr >= AAT2870_REG_NUM) {
+               dev_err(aat2870->dev, "Invalid address, 0x%lx\n", addr);
+               return -EINVAL;
+       }
+
+       while (*start == ' ')
+               start++;
+
+       if (strict_strtoul(start, 16, &val))
+               return -EINVAL;
+
+       ret = aat2870->write(aat2870, (u8)addr, (u8)val);
+       if (ret)
+               return ret;
+
+       return buf_size;
+}
+
+static const struct file_operations aat2870_reg_fops = {
+       .open = aat2870_reg_open_file,
+       .read = aat2870_reg_read_file,
+       .write = aat2870_reg_write_file,
+};
+
+static void aat2870_init_debugfs(struct aat2870_data *aat2870)
+{
+       aat2870->dentry_root = debugfs_create_dir("aat2870", NULL);
+       if (!aat2870->dentry_root) {
+               dev_warn(aat2870->dev,
+                        "Failed to create debugfs root directory\n");
+               return;
+       }
+
+       aat2870->dentry_reg = debugfs_create_file("regs", 0644,
+                                                 aat2870->dentry_root,
+                                                 aat2870, &aat2870_reg_fops);
+       if (!aat2870->dentry_reg)
+               dev_warn(aat2870->dev,
+                        "Failed to create debugfs register file\n");
+}
+
+static void aat2870_uninit_debugfs(struct aat2870_data *aat2870)
+{
+       debugfs_remove_recursive(aat2870->dentry_root);
+}
+#else
+static inline void aat2870_init_debugfs(struct aat2870_data *aat2870)
+{
+}
+
+static inline void aat2870_uninit_debugfs(struct aat2870_data *aat2870)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static int aat2870_i2c_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct aat2870_platform_data *pdata = client->dev.platform_data;
+       struct aat2870_data *aat2870;
+       int i, j;
+       int ret = 0;
+
+       aat2870 = kzalloc(sizeof(struct aat2870_data), GFP_KERNEL);
+       if (!aat2870) {
+               dev_err(&client->dev,
+                       "Failed to allocate memory for aat2870\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       aat2870->dev = &client->dev;
+       dev_set_drvdata(aat2870->dev, aat2870);
+
+       aat2870->client = client;
+       i2c_set_clientdata(client, aat2870);
+
+       aat2870->reg_cache = aat2870_regs;
+
+       if (pdata->en_pin < 0)
+               aat2870->en_pin = -1;
+       else
+               aat2870->en_pin = pdata->en_pin;
+
+       aat2870->init = pdata->init;
+       aat2870->uninit = pdata->uninit;
+       aat2870->read = aat2870_read;
+       aat2870->write = aat2870_write;
+       aat2870->update = aat2870_update;
+
+       mutex_init(&aat2870->io_lock);
+
+       if (aat2870->init)
+               aat2870->init(aat2870);
+
+       if (aat2870->en_pin >= 0) {
+               ret = gpio_request(aat2870->en_pin, "aat2870-en");
+               if (ret < 0) {
+                       dev_err(&client->dev,
+                               "Failed to request GPIO %d\n", aat2870->en_pin);
+                       goto out_kfree;
+               }
+               gpio_direction_output(aat2870->en_pin, 1);
+       }
+
+       aat2870_enable(aat2870);
+
+       for (i = 0; i < pdata->num_subdevs; i++) {
+               for (j = 0; j < ARRAY_SIZE(aat2870_devs); j++) {
+                       if ((pdata->subdevs[i].id == aat2870_devs[j].id) &&
+                                       !strcmp(pdata->subdevs[i].name,
+                                               aat2870_devs[j].name)) {
+                               aat2870_devs[j].platform_data =
+                                       pdata->subdevs[i].platform_data;
+                               break;
+                       }
+               }
+       }
+
+       ret = mfd_add_devices(aat2870->dev, 0, aat2870_devs,
+                             ARRAY_SIZE(aat2870_devs), NULL, 0);
+       if (ret != 0) {
+               dev_err(aat2870->dev, "Failed to add subdev: %d\n", ret);
+               goto out_disable;
+       }
+
+       aat2870_init_debugfs(aat2870);
+
+       return 0;
+
+out_disable:
+       aat2870_disable(aat2870);
+       if (aat2870->en_pin >= 0)
+               gpio_free(aat2870->en_pin);
+out_kfree:
+       kfree(aat2870);
+out:
+       return ret;
+}
+
+static int aat2870_i2c_remove(struct i2c_client *client)
+{
+       struct aat2870_data *aat2870 = i2c_get_clientdata(client);
+
+       aat2870_uninit_debugfs(aat2870);
+
+       mfd_remove_devices(aat2870->dev);
+       aat2870_disable(aat2870);
+       if (aat2870->en_pin >= 0)
+               gpio_free(aat2870->en_pin);
+       if (aat2870->uninit)
+               aat2870->uninit(aat2870);
+       kfree(aat2870);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state)
+{
+       struct aat2870_data *aat2870 = i2c_get_clientdata(client);
+
+       aat2870_disable(aat2870);
+
+       return 0;
+}
+
+static int aat2870_i2c_resume(struct i2c_client *client)
+{
+       struct aat2870_data *aat2870 = i2c_get_clientdata(client);
+       struct aat2870_register *reg = NULL;
+       int i;
+
+       aat2870_enable(aat2870);
+
+       /* restore registers */
+       for (i = 0; i < AAT2870_REG_NUM; i++) {
+               reg = &aat2870->reg_cache[i];
+               if (reg->writeable)
+                       aat2870->write(aat2870, i, reg->value);
+       }
+
+       return 0;
+}
+#else
+#define aat2870_i2c_suspend    NULL
+#define aat2870_i2c_resume     NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_device_id aat2870_i2c_id_table[] = {
+       { "aat2870", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, aat2870_i2c_id_table);
+
+static struct i2c_driver aat2870_i2c_driver = {
+       .driver = {
+               .name   = "aat2870",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = aat2870_i2c_probe,
+       .remove         = aat2870_i2c_remove,
+       .suspend        = aat2870_i2c_suspend,
+       .resume         = aat2870_i2c_resume,
+       .id_table       = aat2870_i2c_id_table,
+};
+
+static int __init aat2870_init(void)
+{
+       return i2c_add_driver(&aat2870_i2c_driver);
+}
+subsys_initcall(aat2870_init);
+
+static void __exit aat2870_exit(void)
+{
+       i2c_del_driver(&aat2870_i2c_driver);
+}
+module_exit(aat2870_exit);
+
+MODULE_DESCRIPTION("Core support for the AnalogicTech AAT2870");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
index 3d7dce671b936a1affb6429c2469d56a436e8cf2..56ba1943c91d71a0c3d0ff8cba69d9c9c56a85a1 100644 (file)
@@ -879,20 +879,13 @@ static ssize_t ab3550_bank_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct ab3550 *ab = ((struct seq_file *)(file->private_data))->private;
-       char buf[32];
-       int buf_size;
        unsigned long user_bank;
        int err;
 
        /* Get userspace string and assure termination */
-       buf_size = min(count, (sizeof(buf) - 1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = 0;
-
-       err = strict_strtoul(buf, 0, &user_bank);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_bank);
        if (err)
-               return -EINVAL;
+               return err;
 
        if (user_bank >= AB3550_NUM_BANKS) {
                dev_err(&ab->i2c_client[0]->dev,
@@ -902,7 +895,7 @@ static ssize_t ab3550_bank_write(struct file *file,
 
        ab->debug_bank = user_bank;
 
-       return buf_size;
+       return count;
 }
 
 static int ab3550_address_print(struct seq_file *s, void *p)
@@ -923,27 +916,21 @@ static ssize_t ab3550_address_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct ab3550 *ab = ((struct seq_file *)(file->private_data))->private;
-       char buf[32];
-       int buf_size;
        unsigned long user_address;
        int err;
 
        /* Get userspace string and assure termination */
-       buf_size = min(count, (sizeof(buf) - 1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = 0;
-
-       err = strict_strtoul(buf, 0, &user_address);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_address);
        if (err)
-               return -EINVAL;
+               return err;
+
        if (user_address > 0xff) {
                dev_err(&ab->i2c_client[0]->dev,
                        "debugfs error input > 0xff\n");
                return -EINVAL;
        }
        ab->debug_address = user_address;
-       return buf_size;
+       return count;
 }
 
 static int ab3550_val_print(struct seq_file *s, void *p)
@@ -971,21 +958,15 @@ static ssize_t ab3550_val_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct ab3550 *ab = ((struct seq_file *)(file->private_data))->private;
-       char buf[32];
-       int buf_size;
        unsigned long user_val;
        int err;
        u8 regvalue;
 
        /* Get userspace string and assure termination */
-       buf_size = min(count, (sizeof(buf)-1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = 0;
-
-       err = strict_strtoul(buf, 0, &user_val);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_val);
        if (err)
-               return -EINVAL;
+               return err;
+
        if (user_val > 0xff) {
                dev_err(&ab->i2c_client[0]->dev,
                        "debugfs error input > 0xff\n");
@@ -1002,7 +983,7 @@ static ssize_t ab3550_val_write(struct file *file,
        if (err)
                return -EINVAL;
 
-       return buf_size;
+       return count;
 }
 
 static const struct file_operations ab3550_bank_fops = {
index fc0c1af1566e08d01b7351de9e1a00466d2c0614..387705e494b963a3b6fa9ded763cf2cc6d8f90a7 100644 (file)
@@ -363,7 +363,7 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
        }
 }
 
-static struct resource ab8500_gpio_resources[] = {
+static struct resource __devinitdata ab8500_gpio_resources[] = {
        {
                .name   = "GPIO_INT6",
                .start  = AB8500_INT_GPIO6R,
@@ -372,7 +372,7 @@ static struct resource ab8500_gpio_resources[] = {
        }
 };
 
-static struct resource ab8500_gpadc_resources[] = {
+static struct resource __devinitdata ab8500_gpadc_resources[] = {
        {
                .name   = "HW_CONV_END",
                .start  = AB8500_INT_GP_HW_ADC_CONV_END,
@@ -387,7 +387,7 @@ static struct resource ab8500_gpadc_resources[] = {
        },
 };
 
-static struct resource ab8500_rtc_resources[] = {
+static struct resource __devinitdata ab8500_rtc_resources[] = {
        {
                .name   = "60S",
                .start  = AB8500_INT_RTC_60S,
@@ -402,7 +402,7 @@ static struct resource ab8500_rtc_resources[] = {
        },
 };
 
-static struct resource ab8500_poweronkey_db_resources[] = {
+static struct resource __devinitdata ab8500_poweronkey_db_resources[] = {
        {
                .name   = "ONKEY_DBF",
                .start  = AB8500_INT_PON_KEY1DB_F,
@@ -417,19 +417,46 @@ static struct resource ab8500_poweronkey_db_resources[] = {
        },
 };
 
-static struct resource ab8500_bm_resources[] = {
+static struct resource __devinitdata ab8500_av_acc_detect_resources[] = {
        {
-               .name = "MAIN_EXT_CH_NOT_OK",
-               .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
-               .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
-               .flags = IORESOURCE_IRQ,
+              .name = "ACC_DETECT_1DB_F",
+              .start = AB8500_INT_ACC_DETECT_1DB_F,
+              .end = AB8500_INT_ACC_DETECT_1DB_F,
+              .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "BATT_OVV",
-               .start = AB8500_INT_BATT_OVV,
-               .end = AB8500_INT_BATT_OVV,
-               .flags = IORESOURCE_IRQ,
+              .name = "ACC_DETECT_1DB_R",
+              .start = AB8500_INT_ACC_DETECT_1DB_R,
+              .end = AB8500_INT_ACC_DETECT_1DB_R,
+              .flags = IORESOURCE_IRQ,
+       },
+       {
+              .name = "ACC_DETECT_21DB_F",
+              .start = AB8500_INT_ACC_DETECT_21DB_F,
+              .end = AB8500_INT_ACC_DETECT_21DB_F,
+              .flags = IORESOURCE_IRQ,
+       },
+       {
+              .name = "ACC_DETECT_21DB_R",
+              .start = AB8500_INT_ACC_DETECT_21DB_R,
+              .end = AB8500_INT_ACC_DETECT_21DB_R,
+              .flags = IORESOURCE_IRQ,
+       },
+       {
+              .name = "ACC_DETECT_22DB_F",
+              .start = AB8500_INT_ACC_DETECT_22DB_F,
+              .end = AB8500_INT_ACC_DETECT_22DB_F,
+              .flags = IORESOURCE_IRQ,
        },
+       {
+              .name = "ACC_DETECT_22DB_R",
+              .start = AB8500_INT_ACC_DETECT_22DB_R,
+              .end = AB8500_INT_ACC_DETECT_22DB_R,
+              .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource __devinitdata ab8500_charger_resources[] = {
        {
                .name = "MAIN_CH_UNPLUG_DET",
                .start = AB8500_INT_MAIN_CH_UNPLUG_DET,
@@ -442,12 +469,6 @@ static struct resource ab8500_bm_resources[] = {
                .end = AB8500_INT_MAIN_CH_PLUG_DET,
                .flags = IORESOURCE_IRQ,
        },
-       {
-               .name = "VBUS_DET_F",
-               .start = AB8500_INT_VBUS_DET_F,
-               .end = AB8500_INT_VBUS_DET_F,
-               .flags = IORESOURCE_IRQ,
-       },
        {
                .name = "VBUS_DET_R",
                .start = AB8500_INT_VBUS_DET_R,
@@ -455,15 +476,21 @@ static struct resource ab8500_bm_resources[] = {
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "BAT_CTRL_INDB",
-               .start = AB8500_INT_BAT_CTRL_INDB,
-               .end = AB8500_INT_BAT_CTRL_INDB,
+               .name = "VBUS_DET_F",
+               .start = AB8500_INT_VBUS_DET_F,
+               .end = AB8500_INT_VBUS_DET_F,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "CH_WD_EXP",
-               .start = AB8500_INT_CH_WD_EXP,
-               .end = AB8500_INT_CH_WD_EXP,
+               .name = "USB_LINK_STATUS",
+               .start = AB8500_INT_USB_LINK_STATUS,
+               .end = AB8500_INT_USB_LINK_STATUS,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_CHARGE_DET_DONE",
+               .start = AB8500_INT_USB_CHG_DET_DONE,
+               .end = AB8500_INT_USB_CHG_DET_DONE,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -473,21 +500,60 @@ static struct resource ab8500_bm_resources[] = {
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "NCONV_ACCU",
-               .start = AB8500_INT_CCN_CONV_ACC,
-               .end = AB8500_INT_CCN_CONV_ACC,
+               .name = "USB_CH_TH_PROT_R",
+               .start = AB8500_INT_USB_CH_TH_PROT_R,
+               .end = AB8500_INT_USB_CH_TH_PROT_R,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "LOW_BAT_F",
-               .start = AB8500_INT_LOW_BAT_F,
-               .end = AB8500_INT_LOW_BAT_F,
+               .name = "USB_CH_TH_PROT_F",
+               .start = AB8500_INT_USB_CH_TH_PROT_F,
+               .end = AB8500_INT_USB_CH_TH_PROT_F,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "LOW_BAT_R",
-               .start = AB8500_INT_LOW_BAT_R,
-               .end = AB8500_INT_LOW_BAT_R,
+               .name = "MAIN_EXT_CH_NOT_OK",
+               .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+               .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "MAIN_CH_TH_PROT_R",
+               .start = AB8500_INT_MAIN_CH_TH_PROT_R,
+               .end = AB8500_INT_MAIN_CH_TH_PROT_R,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "MAIN_CH_TH_PROT_F",
+               .start = AB8500_INT_MAIN_CH_TH_PROT_F,
+               .end = AB8500_INT_MAIN_CH_TH_PROT_F,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_CHARGER_NOT_OKR",
+               .start = AB8500_INT_USB_CHARGER_NOT_OK,
+               .end = AB8500_INT_USB_CHARGER_NOT_OK,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_CHARGER_NOT_OKF",
+               .start = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "CH_WD_EXP",
+               .start = AB8500_INT_CH_WD_EXP,
+               .end = AB8500_INT_CH_WD_EXP,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource __devinitdata ab8500_btemp_resources[] = {
+       {
+               .name = "BAT_CTRL_INDB",
+               .start = AB8500_INT_BAT_CTRL_INDB,
+               .end = AB8500_INT_BAT_CTRL_INDB,
                .flags = IORESOURCE_IRQ,
        },
        {
@@ -503,38 +569,55 @@ static struct resource ab8500_bm_resources[] = {
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "USB_CHARGER_NOT_OKR",
-               .start = AB8500_INT_USB_CHARGER_NOT_OK,
-               .end = AB8500_INT_USB_CHARGER_NOT_OK,
+               .name = "BTEMP_LOW_MEDIUM",
+               .start = AB8500_INT_BTEMP_LOW_MEDIUM,
+               .end = AB8500_INT_BTEMP_LOW_MEDIUM,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "USB_CHARGE_DET_DONE",
-               .start = AB8500_INT_USB_CHG_DET_DONE,
-               .end = AB8500_INT_USB_CHG_DET_DONE,
+               .name = "BTEMP_MEDIUM_HIGH",
+               .start = AB8500_INT_BTEMP_MEDIUM_HIGH,
+               .end = AB8500_INT_BTEMP_MEDIUM_HIGH,
                .flags = IORESOURCE_IRQ,
        },
+};
+
+static struct resource __devinitdata ab8500_fg_resources[] = {
        {
-               .name = "USB_CH_TH_PROT_R",
-               .start = AB8500_INT_USB_CH_TH_PROT_R,
-               .end = AB8500_INT_USB_CH_TH_PROT_R,
+               .name = "NCONV_ACCU",
+               .start = AB8500_INT_CCN_CONV_ACC,
+               .end = AB8500_INT_CCN_CONV_ACC,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "MAIN_CH_TH_PROT_R",
-               .start = AB8500_INT_MAIN_CH_TH_PROT_R,
-               .end = AB8500_INT_MAIN_CH_TH_PROT_R,
+               .name = "BATT_OVV",
+               .start = AB8500_INT_BATT_OVV,
+               .end = AB8500_INT_BATT_OVV,
                .flags = IORESOURCE_IRQ,
        },
        {
-               .name = "USB_CHARGER_NOT_OKF",
-               .start = AB8500_INT_USB_CHARGER_NOT_OKF,
-               .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+               .name = "LOW_BAT_F",
+               .start = AB8500_INT_LOW_BAT_F,
+               .end = AB8500_INT_LOW_BAT_F,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "LOW_BAT_R",
+               .start = AB8500_INT_LOW_BAT_R,
+               .end = AB8500_INT_LOW_BAT_R,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "CC_INT_CALIB",
+               .start = AB8500_INT_CC_INT_CALIB,
+               .end = AB8500_INT_CC_INT_CALIB,
                .flags = IORESOURCE_IRQ,
        },
 };
 
-static struct resource ab8500_debug_resources[] = {
+static struct resource __devinitdata ab8500_chargalg_resources[] = {};
+
+static struct resource __devinitdata ab8500_debug_resources[] = {
        {
                .name   = "IRQ_FIRST",
                .start  = AB8500_INT_MAIN_EXT_CH_NOT_OK,
@@ -549,7 +632,7 @@ static struct resource ab8500_debug_resources[] = {
        },
 };
 
-static struct resource ab8500_usb_resources[] = {
+static struct resource __devinitdata ab8500_usb_resources[] = {
        {
                .name = "ID_WAKEUP_R",
                .start = AB8500_INT_ID_WAKEUP_R,
@@ -580,9 +663,21 @@ static struct resource ab8500_usb_resources[] = {
                .end = AB8500_INT_USB_LINK_STATUS,
                .flags = IORESOURCE_IRQ,
        },
+       {
+               .name = "USB_ADP_PROBE_PLUG",
+               .start = AB8500_INT_ADP_PROBE_PLUG,
+               .end = AB8500_INT_ADP_PROBE_PLUG,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "USB_ADP_PROBE_UNPLUG",
+               .start = AB8500_INT_ADP_PROBE_UNPLUG,
+               .end = AB8500_INT_ADP_PROBE_UNPLUG,
+               .flags = IORESOURCE_IRQ,
+       },
 };
 
-static struct resource ab8500_temp_resources[] = {
+static struct resource __devinitdata ab8500_temp_resources[] = {
        {
                .name  = "AB8500_TEMP_WARM",
                .start = AB8500_INT_TEMP_WARM,
@@ -591,7 +686,7 @@ static struct resource ab8500_temp_resources[] = {
        },
 };
 
-static struct mfd_cell ab8500_devs[] = {
+static struct mfd_cell __devinitdata ab8500_devs[] = {
 #ifdef CONFIG_DEBUG_FS
        {
                .name = "ab8500-debug",
@@ -621,11 +716,33 @@ static struct mfd_cell ab8500_devs[] = {
                .resources = ab8500_rtc_resources,
        },
        {
-               .name = "ab8500-bm",
-               .num_resources = ARRAY_SIZE(ab8500_bm_resources),
-               .resources = ab8500_bm_resources,
+               .name = "ab8500-charger",
+               .num_resources = ARRAY_SIZE(ab8500_charger_resources),
+               .resources = ab8500_charger_resources,
+       },
+       {
+               .name = "ab8500-btemp",
+               .num_resources = ARRAY_SIZE(ab8500_btemp_resources),
+               .resources = ab8500_btemp_resources,
+       },
+       {
+               .name = "ab8500-fg",
+               .num_resources = ARRAY_SIZE(ab8500_fg_resources),
+               .resources = ab8500_fg_resources,
+       },
+       {
+               .name = "ab8500-chargalg",
+               .num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
+               .resources = ab8500_chargalg_resources,
+       },
+       {
+               .name = "ab8500-acc-det",
+               .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
+               .resources = ab8500_av_acc_detect_resources,
+       },
+       {
+               .name = "ab8500-codec",
        },
-       { .name = "ab8500-codec", },
        {
                .name = "ab8500-usb",
                .num_resources = ARRAY_SIZE(ab8500_usb_resources),
index 64748e42ac039c101431782547194834cd4ca69b..64bdeeb1c11a4c18f236a764e2e863cd4c1920c4 100644 (file)
@@ -419,20 +419,13 @@ static ssize_t ab8500_bank_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct device *dev = ((struct seq_file *)(file->private_data))->private;
-       char buf[32];
-       int buf_size;
        unsigned long user_bank;
        int err;
 
        /* Get userspace string and assure termination */
-       buf_size = min(count, (sizeof(buf) - 1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = 0;
-
-       err = strict_strtoul(buf, 0, &user_bank);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_bank);
        if (err)
-               return -EINVAL;
+               return err;
 
        if (user_bank >= AB8500_NUM_BANKS) {
                dev_err(dev, "debugfs error input > number of banks\n");
@@ -441,7 +434,7 @@ static ssize_t ab8500_bank_write(struct file *file,
 
        debug_bank = user_bank;
 
-       return buf_size;
+       return count;
 }
 
 static int ab8500_address_print(struct seq_file *s, void *p)
@@ -459,26 +452,20 @@ static ssize_t ab8500_address_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct device *dev = ((struct seq_file *)(file->private_data))->private;
-       char buf[32];
-       int buf_size;
        unsigned long user_address;
        int err;
 
        /* Get userspace string and assure termination */
-       buf_size = min(count, (sizeof(buf) - 1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = 0;
-
-       err = strict_strtoul(buf, 0, &user_address);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_address);
        if (err)
-               return -EINVAL;
+               return err;
+
        if (user_address > 0xff) {
                dev_err(dev, "debugfs error input > 0xff\n");
                return -EINVAL;
        }
        debug_address = user_address;
-       return buf_size;
+       return count;
 }
 
 static int ab8500_val_print(struct seq_file *s, void *p)
@@ -509,20 +496,14 @@ static ssize_t ab8500_val_write(struct file *file,
        size_t count, loff_t *ppos)
 {
        struct device *dev = ((struct seq_file *)(file->private_data))->private;
-       char buf[32];
-       int buf_size;
        unsigned long user_val;
        int err;
 
        /* Get userspace string and assure termination */
-       buf_size = min(count, (sizeof(buf)-1));
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       buf[buf_size] = 0;
-
-       err = strict_strtoul(buf, 0, &user_val);
+       err = kstrtoul_from_user(user_buf, count, 0, &user_val);
        if (err)
-               return -EINVAL;
+               return err;
+
        if (user_val > 0xff) {
                dev_err(dev, "debugfs error input > 0xff\n");
                return -EINVAL;
@@ -534,7 +515,7 @@ static ssize_t ab8500_val_write(struct file *file,
                return -EINVAL;
        }
 
-       return buf_size;
+       return count;
 }
 
 static const struct file_operations ab8500_bank_fops = {
index a0bd0cf05af3912b1c0c7d490419a3e6eab9d102..21131c7b0f1e7395573d174efb7e73f889b66a45 100644 (file)
@@ -56,7 +56,7 @@ struct jz4740_adc {
        void __iomem *base;
 
        int irq;
-       int irq_base;
+       struct irq_chip_generic *gc;
 
        struct clk *clk;
        atomic_t clk_ref;
@@ -64,63 +64,17 @@ struct jz4740_adc {
        spinlock_t lock;
 };
 
-static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq,
-       bool masked)
-{
-       unsigned long flags;
-       uint8_t val;
-
-       irq -= adc->irq_base;
-
-       spin_lock_irqsave(&adc->lock, flags);
-
-       val = readb(adc->base + JZ_REG_ADC_CTRL);
-       if (masked)
-               val |= BIT(irq);
-       else
-               val &= ~BIT(irq);
-       writeb(val, adc->base + JZ_REG_ADC_CTRL);
-
-       spin_unlock_irqrestore(&adc->lock, flags);
-}
-
-static void jz4740_adc_irq_mask(struct irq_data *data)
-{
-       struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
-       jz4740_adc_irq_set_masked(adc, data->irq, true);
-}
-
-static void jz4740_adc_irq_unmask(struct irq_data *data)
-{
-       struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
-       jz4740_adc_irq_set_masked(adc, data->irq, false);
-}
-
-static void jz4740_adc_irq_ack(struct irq_data *data)
-{
-       struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
-       unsigned int irq = data->irq - adc->irq_base;
-       writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS);
-}
-
-static struct irq_chip jz4740_adc_irq_chip = {
-       .name = "jz4740-adc",
-       .irq_mask = jz4740_adc_irq_mask,
-       .irq_unmask = jz4740_adc_irq_unmask,
-       .irq_ack = jz4740_adc_irq_ack,
-};
-
 static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
-       struct jz4740_adc *adc = irq_desc_get_handler_data(desc);
+       struct irq_chip_generic *gc = irq_desc_get_handler_data(desc);
        uint8_t status;
        unsigned int i;
 
-       status = readb(adc->base + JZ_REG_ADC_STATUS);
+       status = readb(gc->reg_base + JZ_REG_ADC_STATUS);
 
        for (i = 0; i < 5; ++i) {
                if (status & BIT(i))
-                       generic_handle_irq(adc->irq_base + i);
+                       generic_handle_irq(gc->irq_base + i);
        }
 }
 
@@ -249,10 +203,12 @@ const struct mfd_cell jz4740_adc_cells[] = {
 
 static int __devinit jz4740_adc_probe(struct platform_device *pdev)
 {
-       int ret;
+       struct irq_chip_generic *gc;
+       struct irq_chip_type *ct;
        struct jz4740_adc *adc;
        struct resource *mem_base;
-       int irq;
+       int ret;
+       int irq_base;
 
        adc = kmalloc(sizeof(*adc), GFP_KERNEL);
        if (!adc) {
@@ -267,9 +223,9 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev)
                goto err_free;
        }
 
-       adc->irq_base = platform_get_irq(pdev, 1);
-       if (adc->irq_base < 0) {
-               ret = adc->irq_base;
+       irq_base = platform_get_irq(pdev, 1);
+       if (irq_base < 0) {
+               ret = irq_base;
                dev_err(&pdev->dev, "Failed to get irq base: %d\n", ret);
                goto err_free;
        }
@@ -309,20 +265,28 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, adc);
 
-       for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) {
-               irq_set_chip_data(irq, adc);
-               irq_set_chip_and_handler(irq, &jz4740_adc_irq_chip,
-                                        handle_level_irq);
-       }
+       gc = irq_alloc_generic_chip("INTC", 1, irq_base, adc->base,
+               handle_level_irq);
+
+       ct = gc->chip_types;
+       ct->regs.mask = JZ_REG_ADC_CTRL;
+       ct->regs.ack = JZ_REG_ADC_STATUS;
+       ct->chip.irq_mask = irq_gc_mask_set_bit;
+       ct->chip.irq_unmask = irq_gc_mask_clr_bit;
+       ct->chip.irq_ack = irq_gc_ack;
+
+       irq_setup_generic_chip(gc, IRQ_MSK(5), 0, 0, IRQ_NOPROBE | IRQ_LEVEL);
+
+       adc->gc = gc;
 
-       irq_set_handler_data(adc->irq, adc);
+       irq_set_handler_data(adc->irq, gc);
        irq_set_chained_handler(adc->irq, jz4740_adc_irq_demux);
 
        writeb(0x00, adc->base + JZ_REG_ADC_ENABLE);
        writeb(0xff, adc->base + JZ_REG_ADC_CTRL);
 
        ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells,
-               ARRAY_SIZE(jz4740_adc_cells), mem_base, adc->irq_base);
+               ARRAY_SIZE(jz4740_adc_cells), mem_base, irq_base);
        if (ret < 0)
                goto err_clk_put;
 
@@ -347,6 +311,8 @@ static int __devexit jz4740_adc_remove(struct platform_device *pdev)
 
        mfd_remove_devices(&pdev->dev);
 
+       irq_remove_generic_chip(adc->gc, IRQ_MSK(5), IRQ_NOPROBE | IRQ_LEVEL, 0);
+       kfree(adc->gc);
        irq_set_handler_data(adc->irq, NULL);
        irq_set_chained_handler(adc->irq, NULL);
 
index ea3f52c07ef7fd3436cee6a078f011961bdb92eb..ea1169b04779597cb4bf8964b26d7f861ba75afa 100644 (file)
@@ -37,6 +37,9 @@
 #define GPIOBASE       0x44
 #define GPIO_IO_SIZE   64
 
+#define WDTBASE                0x84
+#define WDT_IO_SIZE    64
+
 static struct resource smbus_sch_resource = {
                .flags = IORESOURCE_IO,
 };
@@ -59,6 +62,18 @@ static struct mfd_cell lpc_sch_cells[] = {
        },
 };
 
+static struct resource wdt_sch_resource = {
+               .flags = IORESOURCE_IO,
+};
+
+static struct mfd_cell tunnelcreek_cells[] = {
+       {
+               .name = "tunnelcreek_wdt",
+               .num_resources = 1,
+               .resources = &wdt_sch_resource,
+       },
+};
+
 static struct pci_device_id lpc_sch_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
@@ -72,6 +87,7 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
        unsigned int base_addr_cfg;
        unsigned short base_addr;
        int i;
+       int ret;
 
        pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
        if (!(base_addr_cfg & (1 << 31))) {
@@ -104,8 +120,39 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
        for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
                lpc_sch_cells[i].id = id->device;
 
-       return mfd_add_devices(&dev->dev, 0,
+       ret = mfd_add_devices(&dev->dev, 0,
                        lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0);
+       if (ret)
+               goto out_dev;
+
+       if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC) {
+               pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
+               if (!(base_addr_cfg & (1 << 31))) {
+                       dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n");
+                       ret = -ENODEV;
+                       goto out_dev;
+               }
+               base_addr = (unsigned short)base_addr_cfg;
+               if (base_addr == 0) {
+                       dev_err(&dev->dev, "I/O space for WDT uninitialized\n");
+                       ret = -ENODEV;
+                       goto out_dev;
+               }
+
+               wdt_sch_resource.start = base_addr;
+               wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1;
+
+               for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++)
+                       tunnelcreek_cells[i].id = id->device;
+
+               ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells,
+                       ARRAY_SIZE(tunnelcreek_cells), NULL, 0);
+       }
+
+       return ret;
+out_dev:
+       mfd_remove_devices(&dev->dev);
+       return ret;
 }
 
 static void __devexit lpc_sch_remove(struct pci_dev *dev)
index 638bf7e4d3b38b613a188d08e655d09389516626..09274cf7c33bd0bd7d21ca2ee4cd12f78330bcfb 100644 (file)
@@ -58,8 +58,6 @@ static struct i2c_client *get_i2c(struct max8997_dev *max8997,
        default:
                return ERR_PTR(-EINVAL);
        }
-
-       return ERR_PTR(-EINVAL);
 }
 
 struct max8997_irq_data {
index 9ec7570f5b8140b53bc620edbba36df37b9757b4..de4096aee24877fccbaf36ae981b06483d41da50 100644 (file)
@@ -39,6 +39,8 @@ static struct mfd_cell max8998_devs[] = {
                .name = "max8998-pmic",
        }, {
                .name = "max8998-rtc",
+       }, {
+               .name = "max8998-battery",
        },
 };
 
index 1717144fe7f4f220f6cd79ccea856f39f87ecac3..29601e7d606dc425591205597817cc19935066a4 100644 (file)
@@ -998,9 +998,9 @@ static void usbhs_disable(struct device *dev)
 
        if (is_omap_usbhs_rev2(omap)) {
                if (is_ehci_tll_mode(pdata->port_mode[0]))
-                       clk_enable(omap->usbtll_p1_fck);
+                       clk_disable(omap->usbtll_p1_fck);
                if (is_ehci_tll_mode(pdata->port_mode[1]))
-                       clk_enable(omap->usbtll_p2_fck);
+                       clk_disable(omap->usbtll_p2_fck);
                clk_disable(omap->utmi_p2_fck);
                clk_disable(omap->utmi_p1_fck);
        }
index 7ab7746631d4e58a9e2fd0611c13da211ce54463..2963689cf45c2c93dcd56e56fea26b0b4debdf92 100644 (file)
@@ -228,7 +228,7 @@ int stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
 EXPORT_SYMBOL_GPL(stmpe_block_write);
 
 /**
- * stmpe_set_altfunc: set the alternate function for STMPE pins
+ * stmpe_set_altfunc()- set the alternate function for STMPE pins
  * @stmpe:     Device to configure
  * @pins:      Bitmask of pins to affect
  * @block:     block to enable alternate functions for
index 0dbdc4e8cd77037ac0d8b2b6c17164af04495773..e4ee38956583069fbf912ac78e59279dbd6615e2 100644 (file)
@@ -42,6 +42,7 @@ struct stmpe_variant_block {
  * @id_mask:   bits valid in CHIPID register for comparison with id_val
  * @num_gpios: number of GPIOS
  * @af_bits:   number of bits used to specify the alternate function
+ * @regs: variant specific registers.
  * @blocks:    list of blocks present on this device
  * @num_blocks:        number of blocks present on this device
  * @num_irqs:  number of internal IRQs available on this device
index 69272e4e34596a60b059a4d30f6eadddd4a473c3..696879e2eef77b2429fd8b52e77375a5032e45fc 100644 (file)
@@ -287,12 +287,8 @@ static __devinitdata struct i2c_board_info timberdale_saa7706_i2c_board_info = {
 static __devinitdata struct timb_radio_platform_data
        timberdale_radio_platform_data = {
        .i2c_adapter = 0,
-       .tuner = {
-               .info = &timberdale_tef6868_i2c_board_info
-       },
-       .dsp = {
-               .info = &timberdale_saa7706_i2c_board_info
-       }
+       .tuner = &timberdale_tef6868_i2c_board_info,
+       .dsp = &timberdale_saa7706_i2c_board_info
 };
 
 static const __devinitconst struct resource timberdale_video_resources[] = {
index 2229e66d80db8e4d7b11afe823295d69162f1f00..6f5b8cf2f652b8edf6accf9db107d8f63ea72c23 100644 (file)
@@ -147,12 +147,11 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        if (init_data == NULL)
                return -ENOMEM;
 
-       init_data->irq = pmic_plat_data->irq;
-       init_data->irq_base = pmic_plat_data->irq;
-
        tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL);
-       if (tps65910 == NULL)
+       if (tps65910 == NULL) {
+               kfree(init_data);
                return -ENOMEM;
+       }
 
        i2c_set_clientdata(i2c, tps65910);
        tps65910->dev = &i2c->dev;
@@ -168,17 +167,22 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        if (ret < 0)
                goto err;
 
+       init_data->irq = pmic_plat_data->irq;
+       init_data->irq_base = pmic_plat_data->irq;
+
        tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
 
        ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
        if (ret < 0)
                goto err;
 
+       kfree(init_data);
        return ret;
 
 err:
        mfd_remove_devices(tps65910->dev);
        kfree(tps65910);
+       kfree(init_data);
        return ret;
 }
 
@@ -187,6 +191,7 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
        struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
 
        mfd_remove_devices(tps65910->dev);
+       tps65910_irq_exit(tps65910);
        kfree(tps65910);
 
        return 0;
index 283ac67597575831b778ad9653420b6750aab763..e7ff783aa31ec2a214d691cde38902105bebfa49 100644 (file)
@@ -157,6 +157,8 @@ static __devexit int tps65911_comparator_remove(struct platform_device *pdev)
        struct tps65910 *tps65910;
 
        tps65910 = dev_get_drvdata(pdev->dev.parent);
+       device_remove_file(&pdev->dev, &dev_attr_comp2_threshold);
+       device_remove_file(&pdev->dev, &dev_attr_comp1_threshold);
 
        return 0;
 }
diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c
new file mode 100644 (file)
index 0000000..955bc00
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * tps65912-core.c  --  TI TPS65912x
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya Cabrera <magi@slimlogic.co.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 of the License, or (at your
+ *  option) any later version.
+ *
+ *  This driver is based on wm8350 implementation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65912.h>
+
+static struct mfd_cell tps65912s[] = {
+       {
+               .name = "tps65912-pmic",
+       },
+};
+
+int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask)
+{
+       u8 data;
+       int err;
+
+       mutex_lock(&tps65912->io_mutex);
+
+       err = tps65912->read(tps65912, reg, 1, &data);
+       if (err) {
+               dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg);
+               goto out;
+       }
+
+       data |= mask;
+       err = tps65912->write(tps65912, reg, 1, &data);
+       if (err)
+               dev_err(tps65912->dev, "Write to reg 0x%x failed\n", reg);
+
+out:
+       mutex_unlock(&tps65912->io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(tps65912_set_bits);
+
+int tps65912_clear_bits(struct tps65912 *tps65912, u8 reg, u8 mask)
+{
+       u8 data;
+       int err;
+
+       mutex_lock(&tps65912->io_mutex);
+       err = tps65912->read(tps65912, reg, 1, &data);
+       if (err) {
+               dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg);
+               goto out;
+       }
+
+       data &= ~mask;
+       err = tps65912->write(tps65912, reg, 1, &data);
+       if (err)
+               dev_err(tps65912->dev, "Write to reg 0x%x failed\n", reg);
+
+out:
+       mutex_unlock(&tps65912->io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(tps65912_clear_bits);
+
+static inline int tps65912_read(struct tps65912 *tps65912, u8 reg)
+{
+       u8 val;
+       int err;
+
+       err = tps65912->read(tps65912, reg, 1, &val);
+       if (err < 0)
+               return err;
+
+       return val;
+}
+
+static inline int tps65912_write(struct tps65912 *tps65912, u8 reg, u8 val)
+{
+       return tps65912->write(tps65912, reg, 1, &val);
+}
+
+int tps65912_reg_read(struct tps65912 *tps65912, u8 reg)
+{
+       int data;
+
+       mutex_lock(&tps65912->io_mutex);
+
+       data = tps65912_read(tps65912, reg);
+       if (data < 0)
+               dev_err(tps65912->dev, "Read from reg 0x%x failed\n", reg);
+
+       mutex_unlock(&tps65912->io_mutex);
+       return data;
+}
+EXPORT_SYMBOL_GPL(tps65912_reg_read);
+
+int tps65912_reg_write(struct tps65912 *tps65912, u8 reg, u8 val)
+{
+       int err;
+
+       mutex_lock(&tps65912->io_mutex);
+
+       err = tps65912_write(tps65912, reg, val);
+       if (err < 0)
+               dev_err(tps65912->dev, "Write for reg 0x%x failed\n", reg);
+
+       mutex_unlock(&tps65912->io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(tps65912_reg_write);
+
+int tps65912_device_init(struct tps65912 *tps65912)
+{
+       struct tps65912_board *pmic_plat_data = tps65912->dev->platform_data;
+       struct tps65912_platform_data *init_data;
+       int ret, dcdc_avs, value;
+
+       init_data = kzalloc(sizeof(struct tps65912_platform_data), GFP_KERNEL);
+       if (init_data == NULL)
+               return -ENOMEM;
+
+       init_data->irq = pmic_plat_data->irq;
+       init_data->irq_base = pmic_plat_data->irq;
+
+       mutex_init(&tps65912->io_mutex);
+       dev_set_drvdata(tps65912->dev, tps65912);
+
+       dcdc_avs = (pmic_plat_data->is_dcdc1_avs << 0 |
+                       pmic_plat_data->is_dcdc2_avs  << 1 |
+                               pmic_plat_data->is_dcdc3_avs << 2 |
+                                       pmic_plat_data->is_dcdc4_avs << 3);
+       if (dcdc_avs) {
+               tps65912->read(tps65912, TPS65912_I2C_SPI_CFG, 1, &value);
+               dcdc_avs |= value;
+               tps65912->write(tps65912, TPS65912_I2C_SPI_CFG, 1, &dcdc_avs);
+       }
+
+       ret = mfd_add_devices(tps65912->dev, -1,
+                             tps65912s, ARRAY_SIZE(tps65912s),
+                             NULL, 0);
+       if (ret < 0)
+               goto err;
+
+       ret = tps65912_irq_init(tps65912, init_data->irq, init_data);
+       if (ret < 0)
+               goto err;
+
+       return ret;
+
+err:
+       kfree(init_data);
+       mfd_remove_devices(tps65912->dev);
+       kfree(tps65912);
+       return ret;
+}
+
+void tps65912_device_exit(struct tps65912 *tps65912)
+{
+       mfd_remove_devices(tps65912->dev);
+       kfree(tps65912);
+}
+
+MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS65912x chip family multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c
new file mode 100644 (file)
index 0000000..c041f2c
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * tps65912-i2c.c  --  I2C access for TI TPS65912x PMIC
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya Cabrera <magi@slimlogic.co.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 of the License, or (at your
+ *  option) any later version.
+ *
+ *  This driver is based on wm8350 implementation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65912.h>
+
+static int tps65912_i2c_read(struct tps65912 *tps65912, u8 reg,
+                                 int bytes, void *dest)
+{
+       struct i2c_client *i2c = tps65912->control_data;
+       struct i2c_msg xfer[2];
+       int ret;
+
+       /* Write register */
+       xfer[0].addr = i2c->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 1;
+       xfer[0].buf = &reg;
+
+       /* Read data */
+       xfer[1].addr = i2c->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = bytes;
+       xfer[1].buf = dest;
+
+       ret = i2c_transfer(i2c->adapter, xfer, 2);
+       if (ret == 2)
+               ret = 0;
+       else if (ret >= 0)
+               ret = -EIO;
+       return ret;
+}
+
+static int tps65912_i2c_write(struct tps65912 *tps65912, u8 reg,
+                                  int bytes, void *src)
+{
+       struct i2c_client *i2c = tps65912->control_data;
+       /* we add 1 byte for device register */
+       u8 msg[TPS6591X_MAX_REGISTER + 1];
+       int ret;
+
+       if (bytes > TPS6591X_MAX_REGISTER)
+               return -EINVAL;
+
+       msg[0] = reg;
+       memcpy(&msg[1], src, bytes);
+
+       ret = i2c_master_send(i2c, msg, bytes + 1);
+       if (ret < 0)
+               return ret;
+       if (ret != bytes + 1)
+               return -EIO;
+
+       return 0;
+}
+
+static int tps65912_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct tps65912 *tps65912;
+
+       tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
+       if (tps65912 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, tps65912);
+       tps65912->dev = &i2c->dev;
+       tps65912->control_data = i2c;
+       tps65912->read = tps65912_i2c_read;
+       tps65912->write = tps65912_i2c_write;
+
+       return tps65912_device_init(tps65912);
+}
+
+static int tps65912_i2c_remove(struct i2c_client *i2c)
+{
+       struct tps65912 *tps65912 = i2c_get_clientdata(i2c);
+
+       tps65912_device_exit(tps65912);
+
+       return 0;
+}
+
+static const struct i2c_device_id tps65912_i2c_id[] = {
+       {"tps65912", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tps65912_i2c_id);
+
+static struct i2c_driver tps65912_i2c_driver = {
+       .driver = {
+                  .name = "tps65912",
+                  .owner = THIS_MODULE,
+       },
+       .probe = tps65912_i2c_probe,
+       .remove = tps65912_i2c_remove,
+       .id_table = tps65912_i2c_id,
+};
+
+static int __init tps65912_i2c_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&tps65912_i2c_driver);
+       if (ret != 0)
+               pr_err("Failed to register TPS65912 I2C driver: %d\n", ret);
+
+       return ret;
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(tps65912_i2c_init);
+
+static void __exit tps65912_i2c_exit(void)
+{
+       i2c_del_driver(&tps65912_i2c_driver);
+}
+module_exit(tps65912_i2c_exit);
+
+MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS6591x chip family multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tps65912-irq.c b/drivers/mfd/tps65912-irq.c
new file mode 100644 (file)
index 0000000..d360a83
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * tps65912-irq.c  --  TI TPS6591x
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya <magi@slimlogic.co.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 of the License, or (at your
+ *  option) any later version.
+ *
+ * This driver is based on wm8350 implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65912.h>
+
+static inline int irq_to_tps65912_irq(struct tps65912 *tps65912,
+                                                       int irq)
+{
+       return irq - tps65912->irq_base;
+}
+
+/*
+ * This is a threaded IRQ handler so can access I2C/SPI.  Since the
+ * IRQ handler explicitly clears the IRQ it handles the IRQ line
+ * will be reasserted and the physical IRQ will be handled again if
+ * another interrupt is asserted while we run - in the normal course
+ * of events this is a rare occurrence so we save I2C/SPI reads. We're
+ * also assuming that it's rare to get lots of interrupts firing
+ * simultaneously so try to minimise I/O.
+ */
+static irqreturn_t tps65912_irq(int irq, void *irq_data)
+{
+       struct tps65912 *tps65912 = irq_data;
+       u32 irq_sts;
+       u32 irq_mask;
+       u8 reg;
+       int i;
+
+
+       tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg);
+       irq_sts = reg;
+       tps65912->read(tps65912, TPS65912_INT_STS2, 1, &reg);
+       irq_sts |= reg << 8;
+       tps65912->read(tps65912, TPS65912_INT_STS3, 1, &reg);
+       irq_sts |= reg << 16;
+       tps65912->read(tps65912, TPS65912_INT_STS4, 1, &reg);
+       irq_sts |= reg << 24;
+
+       tps65912->read(tps65912, TPS65912_INT_MSK, 1, &reg);
+       irq_mask = reg;
+       tps65912->read(tps65912, TPS65912_INT_MSK2, 1, &reg);
+       irq_mask |= reg << 8;
+       tps65912->read(tps65912, TPS65912_INT_MSK3, 1, &reg);
+       irq_mask |= reg << 16;
+       tps65912->read(tps65912, TPS65912_INT_MSK4, 1, &reg);
+       irq_mask |= reg << 24;
+
+       irq_sts &= ~irq_mask;
+       if (!irq_sts)
+               return IRQ_NONE;
+
+       for (i = 0; i < tps65912->irq_num; i++) {
+               if (!(irq_sts & (1 << i)))
+                       continue;
+
+               handle_nested_irq(tps65912->irq_base + i);
+       }
+
+       /* Write the STS register back to clear IRQs we handled */
+       reg = irq_sts & 0xFF;
+       irq_sts >>= 8;
+       if (reg)
+               tps65912->write(tps65912, TPS65912_INT_STS, 1, &reg);
+       reg = irq_sts & 0xFF;
+       irq_sts >>= 8;
+       if (reg)
+               tps65912->write(tps65912, TPS65912_INT_STS2, 1, &reg);
+       reg = irq_sts & 0xFF;
+       irq_sts >>= 8;
+       if (reg)
+               tps65912->write(tps65912, TPS65912_INT_STS3, 1, &reg);
+       reg = irq_sts & 0xFF;
+       if (reg)
+               tps65912->write(tps65912, TPS65912_INT_STS4, 1, &reg);
+
+       return IRQ_HANDLED;
+}
+
+static void tps65912_irq_lock(struct irq_data *data)
+{
+       struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&tps65912->irq_lock);
+}
+
+static void tps65912_irq_sync_unlock(struct irq_data *data)
+{
+       struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
+       u32 reg_mask;
+       u8 reg;
+
+       tps65912->read(tps65912, TPS65912_INT_MSK, 1, &reg);
+       reg_mask = reg;
+       tps65912->read(tps65912, TPS65912_INT_MSK2, 1, &reg);
+       reg_mask |= reg << 8;
+       tps65912->read(tps65912, TPS65912_INT_MSK3, 1, &reg);
+       reg_mask |= reg << 16;
+       tps65912->read(tps65912, TPS65912_INT_MSK4, 1, &reg);
+       reg_mask |= reg << 24;
+
+       if (tps65912->irq_mask != reg_mask) {
+               reg = tps65912->irq_mask & 0xFF;
+               tps65912->write(tps65912, TPS65912_INT_MSK, 1, &reg);
+               reg = tps65912->irq_mask >> 8 & 0xFF;
+               tps65912->write(tps65912, TPS65912_INT_MSK2, 1, &reg);
+               reg = tps65912->irq_mask >> 16 & 0xFF;
+               tps65912->write(tps65912, TPS65912_INT_MSK3, 1, &reg);
+               reg = tps65912->irq_mask >> 24 & 0xFF;
+               tps65912->write(tps65912, TPS65912_INT_MSK4, 1, &reg);
+       }
+
+       mutex_unlock(&tps65912->irq_lock);
+}
+
+static void tps65912_irq_enable(struct irq_data *data)
+{
+       struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
+
+       tps65912->irq_mask &= ~(1 << irq_to_tps65912_irq(tps65912, data->irq));
+}
+
+static void tps65912_irq_disable(struct irq_data *data)
+{
+       struct tps65912 *tps65912 = irq_data_get_irq_chip_data(data);
+
+       tps65912->irq_mask |= (1 << irq_to_tps65912_irq(tps65912, data->irq));
+}
+
+static struct irq_chip tps65912_irq_chip = {
+       .name = "tps65912",
+       .irq_bus_lock = tps65912_irq_lock,
+       .irq_bus_sync_unlock = tps65912_irq_sync_unlock,
+       .irq_disable = tps65912_irq_disable,
+       .irq_enable = tps65912_irq_enable,
+};
+
+int tps65912_irq_init(struct tps65912 *tps65912, int irq,
+                           struct tps65912_platform_data *pdata)
+{
+       int ret, cur_irq;
+       int flags = IRQF_ONESHOT;
+       u8 reg;
+
+       if (!irq) {
+               dev_warn(tps65912->dev, "No interrupt support, no core IRQ\n");
+               return 0;
+       }
+
+       if (!pdata || !pdata->irq_base) {
+               dev_warn(tps65912->dev, "No interrupt support, no IRQ base\n");
+               return 0;
+       }
+
+       /* Clear unattended interrupts */
+       tps65912->read(tps65912, TPS65912_INT_STS, 1, &reg);
+       tps65912->write(tps65912, TPS65912_INT_STS, 1, &reg);
+       tps65912->read(tps65912, TPS65912_INT_STS2, 1, &reg);
+       tps65912->write(tps65912, TPS65912_INT_STS2, 1, &reg);
+       tps65912->read(tps65912, TPS65912_INT_STS3, 1, &reg);
+       tps65912->write(tps65912, TPS65912_INT_STS3, 1, &reg);
+       tps65912->read(tps65912, TPS65912_INT_STS4, 1, &reg);
+       tps65912->write(tps65912, TPS65912_INT_STS4, 1, &reg);
+
+       /* Mask top level interrupts */
+       tps65912->irq_mask = 0xFFFFFFFF;
+
+       mutex_init(&tps65912->irq_lock);
+       tps65912->chip_irq = irq;
+       tps65912->irq_base = pdata->irq_base;
+
+       tps65912->irq_num = TPS65912_NUM_IRQ;
+
+       /* Register with genirq */
+       for (cur_irq = tps65912->irq_base;
+            cur_irq < tps65912->irq_num + tps65912->irq_base;
+            cur_irq++) {
+               irq_set_chip_data(cur_irq, tps65912);
+               irq_set_chip_and_handler(cur_irq, &tps65912_irq_chip,
+                                        handle_edge_irq);
+               irq_set_nested_thread(cur_irq, 1);
+               /* ARM needs us to explicitly flag the IRQ as valid
+                * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+               set_irq_flags(cur_irq, IRQF_VALID);
+#else
+               irq_set_noprobe(cur_irq);
+#endif
+       }
+
+       ret = request_threaded_irq(irq, NULL, tps65912_irq, flags,
+                                  "tps65912", tps65912);
+
+       irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
+       if (ret != 0)
+               dev_err(tps65912->dev, "Failed to request IRQ: %d\n", ret);
+
+       return ret;
+}
+
+int tps65912_irq_exit(struct tps65912 *tps65912)
+{
+       free_irq(tps65912->chip_irq, tps65912);
+       return 0;
+}
diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c
new file mode 100644 (file)
index 0000000..6d71e0d
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * tps65912-spi.c  --  SPI access for TI TPS65912x PMIC
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya Cabrera <magi@slimlogic.co.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 of the License, or (at your
+ *  option) any later version.
+ *
+ *  This driver is based on wm8350 implementation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65912.h>
+
+static int tps65912_spi_write(struct tps65912 *tps65912, u8 addr,
+                                                       int bytes, void *src)
+{
+       struct spi_device *spi = tps65912->control_data;
+       u8 *data = (u8 *) src;
+       int ret;
+       /* bit 23 is the read/write bit */
+       unsigned long spi_data = 1 << 23 | addr << 15 | *data;
+       struct spi_transfer xfer;
+       struct spi_message msg;
+       u32 tx_buf, rx_buf;
+
+       tx_buf = spi_data;
+       rx_buf = 0;
+
+       xfer.tx_buf     = &tx_buf;
+       xfer.rx_buf     = NULL;
+       xfer.len        = sizeof(unsigned long);
+       xfer.bits_per_word = 24;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       ret = spi_sync(spi, &msg);
+       return ret;
+}
+
+static int tps65912_spi_read(struct tps65912 *tps65912, u8 addr,
+                                                       int bytes, void *dest)
+{
+       struct spi_device *spi = tps65912->control_data;
+       /* bit 23 is the read/write bit */
+       unsigned long spi_data = 0 << 23 | addr << 15;
+       struct spi_transfer xfer;
+       struct spi_message msg;
+       int ret;
+       u8 *data = (u8 *) dest;
+       u32 tx_buf, rx_buf;
+
+       tx_buf = spi_data;
+       rx_buf = 0;
+
+       xfer.tx_buf     = &tx_buf;
+       xfer.rx_buf     = &rx_buf;
+       xfer.len        = sizeof(unsigned long);
+       xfer.bits_per_word = 24;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       if (spi == NULL)
+               return 0;
+
+       ret = spi_sync(spi, &msg);
+       if (ret == 0)
+               *data = (u8) (rx_buf & 0xFF);
+       return ret;
+}
+
+static int __devinit tps65912_spi_probe(struct spi_device *spi)
+{
+       struct tps65912 *tps65912;
+
+       tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
+       if (tps65912 == NULL)
+               return -ENOMEM;
+
+       tps65912->dev = &spi->dev;
+       tps65912->control_data = spi;
+       tps65912->read = tps65912_spi_read;
+       tps65912->write = tps65912_spi_write;
+
+       spi_set_drvdata(spi, tps65912);
+
+       return tps65912_device_init(tps65912);
+}
+
+static int __devexit tps65912_spi_remove(struct spi_device *spi)
+{
+       struct tps65912 *tps65912 = spi_get_drvdata(spi);
+
+       tps65912_device_exit(tps65912);
+
+       return 0;
+}
+
+static struct spi_driver tps65912_spi_driver = {
+       .driver = {
+               .name = "tps65912",
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
+       },
+       .probe  = tps65912_spi_probe,
+       .remove = __devexit_p(tps65912_spi_remove),
+};
+
+static int __init tps65912_spi_init(void)
+{
+       int ret;
+
+       ret = spi_register_driver(&tps65912_spi_driver);
+       if (ret != 0)
+               pr_err("Failed to register TPS65912 SPI driver: %d\n", ret);
+
+       return 0;
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(tps65912_spi_init);
+
+static void __exit tps65912_spi_exit(void)
+{
+       spi_unregister_driver(&tps65912_spi_driver);
+}
+module_exit(tps65912_spi_exit);
+
+MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("SPI support for TPS65912 chip family mfd");
+MODULE_LICENSE("GPL");
index a2eddc70995cdfc789651548ad58fde1659c4488..01ecfeee6524697d26a08634f705bc28131e41bc 100644 (file)
@@ -1283,6 +1283,8 @@ static const struct i2c_device_id twl_ids[] = {
        { "tps65950", 0 },              /* catalog version of twl5030 */
        { "tps65930", TPS_SUBSET },     /* fewer LDOs and DACs; no charger */
        { "tps65920", TPS_SUBSET },     /* fewer LDOs; no codec or charger */
+       { "tps65921", TPS_SUBSET },     /* fewer LDOs; no codec, no LED
+                                          and vibrator. Charger in USB module*/
        { "twl6030", TWL6030_CLASS },   /* "Phoenix power chip" */
        { "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
        { /* end of list */ },
index 3941ddcf15feff4bc45403569fa2296bd760ec36..b5d598c3aa71b356f40fb9a5f89738eed16c5350 100644 (file)
@@ -530,13 +530,13 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
        if (ret) {
                dev_err(twl4030_madc->dev,
                        "unable to write sel register 0x%X\n", method->sel + 1);
-               return ret;
+               goto out;
        }
        ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel);
        if (ret) {
                dev_err(twl4030_madc->dev,
                        "unable to write sel register 0x%X\n", method->sel + 1);
-               return ret;
+               goto out;
        }
        /* Select averaging for all channels if do_avg is set */
        if (req->do_avg) {
@@ -546,7 +546,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
                        dev_err(twl4030_madc->dev,
                                "unable to write avg register 0x%X\n",
                                method->avg + 1);
-                       return ret;
+                       goto out;
                }
                ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
                                       ch_lsb, method->avg);
@@ -554,7 +554,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
                        dev_err(twl4030_madc->dev,
                                "unable to write sel reg 0x%X\n",
                                method->sel + 1);
-                       return ret;
+                       goto out;
                }
        }
        if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
index 5d25bdc78424392d4168ff3065a6eb2f43407c69..e8fee147678d31e57e4d6c9d7272a998ba95029b 100644 (file)
@@ -161,3 +161,5 @@ void pwm_free(struct pwm_device *pwm)
        kfree(pwm);
 }
 EXPORT_SYMBOL(pwm_free);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm831x-auxadc.c b/drivers/mfd/wm831x-auxadc.c
new file mode 100644 (file)
index 0000000..8721095
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * wm831x-auxadc.c  --  AUXADC for Wolfson WM831x PMICs
+ *
+ * Copyright 2009-2011 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+#include <linux/mfd/wm831x/core.h>
+#include <linux/mfd/wm831x/pdata.h>
+#include <linux/mfd/wm831x/irq.h>
+#include <linux/mfd/wm831x/auxadc.h>
+#include <linux/mfd/wm831x/otp.h>
+#include <linux/mfd/wm831x/regulator.h>
+
+struct wm831x_auxadc_req {
+       struct list_head list;
+       enum wm831x_auxadc input;
+       int val;
+       struct completion done;
+};
+
+static int wm831x_auxadc_read_irq(struct wm831x *wm831x,
+                                 enum wm831x_auxadc input)
+{
+       struct wm831x_auxadc_req *req;
+       int ret;
+       bool ena = false;
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
+
+       init_completion(&req->done);
+       req->input = input;
+       req->val = -ETIMEDOUT;
+
+       mutex_lock(&wm831x->auxadc_lock);
+
+       /* Enqueue the request */
+       list_add(&req->list, &wm831x->auxadc_pending);
+
+       ena = !wm831x->auxadc_active;
+
+       if (ena) {
+               ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
+                                     WM831X_AUX_ENA, WM831X_AUX_ENA);
+               if (ret != 0) {
+                       dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n",
+                               ret);
+                       goto out;
+               }
+       }
+
+       /* Enable the conversion if not already running */
+       if (!(wm831x->auxadc_active & (1 << input))) {
+               ret = wm831x_set_bits(wm831x, WM831X_AUXADC_SOURCE,
+                                     1 << input, 1 << input);
+               if (ret != 0) {
+                       dev_err(wm831x->dev,
+                               "Failed to set AUXADC source: %d\n", ret);
+                       goto out;
+               }
+
+               wm831x->auxadc_active |= 1 << input;
+       }
+
+       /* We convert at the fastest rate possible */
+       if (ena) {
+               ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
+                                     WM831X_AUX_CVT_ENA |
+                                     WM831X_AUX_RATE_MASK,
+                                     WM831X_AUX_CVT_ENA |
+                                     WM831X_AUX_RATE_MASK);
+               if (ret != 0) {
+                       dev_err(wm831x->dev, "Failed to start AUXADC: %d\n",
+                               ret);
+                       goto out;
+               }
+       }
+
+       mutex_unlock(&wm831x->auxadc_lock);
+
+       /* Wait for an interrupt */
+       wait_for_completion_timeout(&req->done, msecs_to_jiffies(500));
+
+       mutex_lock(&wm831x->auxadc_lock);
+
+       list_del(&req->list);
+       ret = req->val;
+
+out:
+       mutex_unlock(&wm831x->auxadc_lock);
+
+       kfree(req);
+
+       return ret;
+}
+
+static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
+{
+       struct wm831x *wm831x = irq_data;
+       struct wm831x_auxadc_req *req;
+       int ret, input, val;
+
+       ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
+       if (ret < 0) {
+               dev_err(wm831x->dev,
+                       "Failed to read AUXADC data: %d\n", ret);
+               return IRQ_NONE;
+       }
+
+       input = ((ret & WM831X_AUX_DATA_SRC_MASK)
+                >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
+
+       if (input == 14)
+               input = WM831X_AUX_CAL;
+
+       val = ret & WM831X_AUX_DATA_MASK;
+
+       mutex_lock(&wm831x->auxadc_lock);
+
+       /* Disable this conversion, we're about to complete all users */
+       wm831x_set_bits(wm831x, WM831X_AUXADC_SOURCE,
+                       1 << input, 0);
+       wm831x->auxadc_active &= ~(1 << input);
+
+       /* Turn off the entire convertor if idle */
+       if (!wm831x->auxadc_active)
+               wm831x_reg_write(wm831x, WM831X_AUXADC_CONTROL, 0);
+
+       /* Wake up any threads waiting for this request */
+       list_for_each_entry(req, &wm831x->auxadc_pending, list) {
+               if (req->input == input) {
+                       req->val = val;
+                       complete(&req->done);
+               }
+       }
+
+       mutex_unlock(&wm831x->auxadc_lock);
+
+       return IRQ_HANDLED;
+}
+
+static int wm831x_auxadc_read_polled(struct wm831x *wm831x,
+                                    enum wm831x_auxadc input)
+{
+       int ret, src, timeout;
+
+       mutex_lock(&wm831x->auxadc_lock);
+
+       ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
+                             WM831X_AUX_ENA, WM831X_AUX_ENA);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret);
+               goto out;
+       }
+
+       /* We force a single source at present */
+       src = input;
+       ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE,
+                              1 << src);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret);
+               goto out;
+       }
+
+       ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
+                             WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret);
+               goto disable;
+       }
+
+       /* If we're not using interrupts then poll the
+        * interrupt status register */
+       timeout = 5;
+       while (timeout) {
+               msleep(1);
+
+               ret = wm831x_reg_read(wm831x,
+                                     WM831X_INTERRUPT_STATUS_1);
+               if (ret < 0) {
+                       dev_err(wm831x->dev,
+                               "ISR 1 read failed: %d\n", ret);
+                       goto disable;
+               }
+
+               /* Did it complete? */
+               if (ret & WM831X_AUXADC_DATA_EINT) {
+                       wm831x_reg_write(wm831x,
+                                        WM831X_INTERRUPT_STATUS_1,
+                                        WM831X_AUXADC_DATA_EINT);
+                       break;
+               } else {
+                       dev_err(wm831x->dev,
+                               "AUXADC conversion timeout\n");
+                       ret = -EBUSY;
+                       goto disable;
+               }
+       }
+
+       ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
+       if (ret < 0) {
+               dev_err(wm831x->dev,
+                       "Failed to read AUXADC data: %d\n", ret);
+               goto disable;
+       }
+
+       src = ((ret & WM831X_AUX_DATA_SRC_MASK)
+              >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
+
+       if (src == 14)
+               src = WM831X_AUX_CAL;
+
+       if (src != input) {
+               dev_err(wm831x->dev, "Data from source %d not %d\n",
+                       src, input);
+               ret = -EINVAL;
+       } else {
+               ret &= WM831X_AUX_DATA_MASK;
+       }
+
+disable:
+       wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0);
+out:
+       mutex_unlock(&wm831x->auxadc_lock);
+       return ret;
+}
+
+/**
+ * wm831x_auxadc_read: Read a value from the WM831x AUXADC
+ *
+ * @wm831x: Device to read from.
+ * @input: AUXADC input to read.
+ */
+int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
+{
+       return wm831x->auxadc_read(wm831x, input);
+}
+EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
+
+/**
+ * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
+ *
+ * @wm831x: Device to read from.
+ * @input: AUXADC input to read.
+ */
+int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input)
+{
+       int ret;
+
+       ret = wm831x_auxadc_read(wm831x, input);
+       if (ret < 0)
+               return ret;
+
+       ret *= 1465;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv);
+
+void wm831x_auxadc_init(struct wm831x *wm831x)
+{
+       int ret;
+
+       mutex_init(&wm831x->auxadc_lock);
+       INIT_LIST_HEAD(&wm831x->auxadc_pending);
+
+       if (wm831x->irq && wm831x->irq_base) {
+               wm831x->auxadc_read = wm831x_auxadc_read_irq;
+
+               ret = request_threaded_irq(wm831x->irq_base +
+                                          WM831X_IRQ_AUXADC_DATA,
+                                          NULL, wm831x_auxadc_irq, 0,
+                                          "auxadc", wm831x);
+               if (ret < 0) {
+                       dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n",
+                               ret);
+                       wm831x->auxadc_read = NULL;
+               }
+       }
+
+       if (!wm831x->auxadc_read)
+               wm831x->auxadc_read = wm831x_auxadc_read_polled;
+}
index 265f75fc6a25f404a60d0954f2228585bb149938..282e76ab678f15c4cb3d792f571f47e04f6fd872 100644 (file)
@@ -295,7 +295,7 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
                goto out;
 
        r &= ~mask;
-       r |= val;
+       r |= val & mask;
 
        ret = wm831x_write(wm831x, reg, 2, &r);
 
@@ -306,146 +306,6 @@ out:
 }
 EXPORT_SYMBOL_GPL(wm831x_set_bits);
 
-/**
- * wm831x_auxadc_read: Read a value from the WM831x AUXADC
- *
- * @wm831x: Device to read from.
- * @input: AUXADC input to read.
- */
-int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
-{
-       int ret, src, irq_masked, timeout;
-
-       /* Are we using the interrupt? */
-       irq_masked = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1_MASK);
-       irq_masked &= WM831X_AUXADC_DATA_EINT;
-
-       mutex_lock(&wm831x->auxadc_lock);
-
-       ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
-                             WM831X_AUX_ENA, WM831X_AUX_ENA);
-       if (ret < 0) {
-               dev_err(wm831x->dev, "Failed to enable AUXADC: %d\n", ret);
-               goto out;
-       }
-
-       /* We force a single source at present */
-       src = input;
-       ret = wm831x_reg_write(wm831x, WM831X_AUXADC_SOURCE,
-                              1 << src);
-       if (ret < 0) {
-               dev_err(wm831x->dev, "Failed to set AUXADC source: %d\n", ret);
-               goto out;
-       }
-
-       /* Clear any notification from a very late arriving interrupt */
-       try_wait_for_completion(&wm831x->auxadc_done);
-
-       ret = wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL,
-                             WM831X_AUX_CVT_ENA, WM831X_AUX_CVT_ENA);
-       if (ret < 0) {
-               dev_err(wm831x->dev, "Failed to start AUXADC: %d\n", ret);
-               goto disable;
-       }
-
-       if (irq_masked) {
-               /* If we're not using interrupts then poll the
-                * interrupt status register */
-               timeout = 5;
-               while (timeout) {
-                       msleep(1);
-
-                       ret = wm831x_reg_read(wm831x,
-                                             WM831X_INTERRUPT_STATUS_1);
-                       if (ret < 0) {
-                               dev_err(wm831x->dev,
-                                       "ISR 1 read failed: %d\n", ret);
-                               goto disable;
-                       }
-
-                       /* Did it complete? */
-                       if (ret & WM831X_AUXADC_DATA_EINT) {
-                               wm831x_reg_write(wm831x,
-                                                WM831X_INTERRUPT_STATUS_1,
-                                                WM831X_AUXADC_DATA_EINT);
-                               break;
-                       } else {
-                               dev_err(wm831x->dev,
-                                       "AUXADC conversion timeout\n");
-                               ret = -EBUSY;
-                               goto disable;
-                       }
-               }
-       } else {
-               /* If we are using interrupts then wait for the
-                * interrupt to complete.  Use an extremely long
-                * timeout to handle situations with heavy load where
-                * the notification of the interrupt may be delayed by
-                * threaded IRQ handling. */
-               if (!wait_for_completion_timeout(&wm831x->auxadc_done,
-                                                msecs_to_jiffies(500))) {
-                       dev_err(wm831x->dev, "Timed out waiting for AUXADC\n");
-                       ret = -EBUSY;
-                       goto disable;
-               }
-       }
-
-       ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA);
-       if (ret < 0) {
-               dev_err(wm831x->dev, "Failed to read AUXADC data: %d\n", ret);
-       } else {
-               src = ((ret & WM831X_AUX_DATA_SRC_MASK)
-                      >> WM831X_AUX_DATA_SRC_SHIFT) - 1;
-
-               if (src == 14)
-                       src = WM831X_AUX_CAL;
-
-               if (src != input) {
-                       dev_err(wm831x->dev, "Data from source %d not %d\n",
-                               src, input);
-                       ret = -EINVAL;
-               } else {
-                       ret &= WM831X_AUX_DATA_MASK;
-               }
-       }
-
-disable:
-       wm831x_set_bits(wm831x, WM831X_AUXADC_CONTROL, WM831X_AUX_ENA, 0);
-out:
-       mutex_unlock(&wm831x->auxadc_lock);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(wm831x_auxadc_read);
-
-static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data)
-{
-       struct wm831x *wm831x = irq_data;
-
-       complete(&wm831x->auxadc_done);
-
-       return IRQ_HANDLED;
-}
-
-/**
- * wm831x_auxadc_read_uv: Read a voltage from the WM831x AUXADC
- *
- * @wm831x: Device to read from.
- * @input: AUXADC input to read.
- */
-int wm831x_auxadc_read_uv(struct wm831x *wm831x, enum wm831x_auxadc input)
-{
-       int ret;
-
-       ret = wm831x_auxadc_read(wm831x, input);
-       if (ret < 0)
-               return ret;
-
-       ret *= 1465;
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(wm831x_auxadc_read_uv);
-
 static struct resource wm831x_dcdc1_resources[] = {
        {
                .start = WM831X_DC1_CONTROL_1,
@@ -871,6 +731,9 @@ static struct mfd_cell wm8310_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
                .resources = wm831x_dcdc4_resources,
        },
+       {
+               .name = "wm831x-clk",
+       },
        {
                .name = "wm831x-epe",
                .id = 1,
@@ -975,11 +838,6 @@ static struct mfd_cell wm8310_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_power_resources),
                .resources = wm831x_power_resources,
        },
-       {
-               .name = "wm831x-rtc",
-               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
-               .resources = wm831x_rtc_resources,
-       },
        {
                .name = "wm831x-status",
                .id = 1,
@@ -1027,6 +885,9 @@ static struct mfd_cell wm8311_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
                .resources = wm831x_dcdc4_resources,
        },
+       {
+               .name = "wm831x-clk",
+       },
        {
                .name = "wm831x-epe",
                .id = 1,
@@ -1107,11 +968,6 @@ static struct mfd_cell wm8311_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_power_resources),
                .resources = wm831x_power_resources,
        },
-       {
-               .name = "wm831x-rtc",
-               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
-               .resources = wm831x_rtc_resources,
-       },
        {
                .name = "wm831x-status",
                .id = 1,
@@ -1124,11 +980,6 @@ static struct mfd_cell wm8311_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_status2_resources),
                .resources = wm831x_status2_resources,
        },
-       {
-               .name = "wm831x-touch",
-               .num_resources = ARRAY_SIZE(wm831x_touch_resources),
-               .resources = wm831x_touch_resources,
-       },
        {
                .name = "wm831x-watchdog",
                .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
@@ -1164,6 +1015,9 @@ static struct mfd_cell wm8312_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_dcdc4_resources),
                .resources = wm831x_dcdc4_resources,
        },
+       {
+               .name = "wm831x-clk",
+       },
        {
                .name = "wm831x-epe",
                .id = 1,
@@ -1268,11 +1122,6 @@ static struct mfd_cell wm8312_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_power_resources),
                .resources = wm831x_power_resources,
        },
-       {
-               .name = "wm831x-rtc",
-               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
-               .resources = wm831x_rtc_resources,
-       },
        {
                .name = "wm831x-status",
                .id = 1,
@@ -1285,11 +1134,6 @@ static struct mfd_cell wm8312_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_status2_resources),
                .resources = wm831x_status2_resources,
        },
-       {
-               .name = "wm831x-touch",
-               .num_resources = ARRAY_SIZE(wm831x_touch_resources),
-               .resources = wm831x_touch_resources,
-       },
        {
                .name = "wm831x-watchdog",
                .num_resources = ARRAY_SIZE(wm831x_wdt_resources),
@@ -1325,6 +1169,9 @@ static struct mfd_cell wm8320_devs[] = {
                .num_resources = ARRAY_SIZE(wm8320_dcdc4_buck_resources),
                .resources = wm8320_dcdc4_buck_resources,
        },
+       {
+               .name = "wm831x-clk",
+       },
        {
                .name = "wm831x-gpio",
                .num_resources = ARRAY_SIZE(wm831x_gpio_resources),
@@ -1404,11 +1251,6 @@ static struct mfd_cell wm8320_devs[] = {
                .num_resources = ARRAY_SIZE(wm831x_on_resources),
                .resources = wm831x_on_resources,
        },
-       {
-               .name = "wm831x-rtc",
-               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
-               .resources = wm831x_rtc_resources,
-       },
        {
                .name = "wm831x-status",
                .id = 1,
@@ -1428,6 +1270,22 @@ static struct mfd_cell wm8320_devs[] = {
        },
 };
 
+static struct mfd_cell touch_devs[] = {
+       {
+               .name = "wm831x-touch",
+               .num_resources = ARRAY_SIZE(wm831x_touch_resources),
+               .resources = wm831x_touch_resources,
+       },
+};
+
+static struct mfd_cell rtc_devs[] = {
+       {
+               .name = "wm831x-rtc",
+               .num_resources = ARRAY_SIZE(wm831x_rtc_resources),
+               .resources = wm831x_rtc_resources,
+       },
+};
+
 static struct mfd_cell backlight_devs[] = {
        {
                .name = "wm831x-backlight",
@@ -1440,14 +1298,12 @@ static struct mfd_cell backlight_devs[] = {
 int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 {
        struct wm831x_pdata *pdata = wm831x->dev->platform_data;
-       int rev;
+       int rev, wm831x_num;
        enum wm831x_parent parent;
        int ret, i;
 
        mutex_init(&wm831x->io_lock);
        mutex_init(&wm831x->key_lock);
-       mutex_init(&wm831x->auxadc_lock);
-       init_completion(&wm831x->auxadc_done);
        dev_set_drvdata(wm831x->dev, wm831x);
 
        ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
@@ -1592,45 +1448,51 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
                }
        }
 
+       /* Multiply by 10 as we have many subdevices of the same type */
+       if (pdata && pdata->wm831x_num)
+               wm831x_num = pdata->wm831x_num * 10;
+       else
+               wm831x_num = -1;
+
        ret = wm831x_irq_init(wm831x, irq);
        if (ret != 0)
                goto err;
 
-       if (wm831x->irq_base) {
-               ret = request_threaded_irq(wm831x->irq_base +
-                                          WM831X_IRQ_AUXADC_DATA,
-                                          NULL, wm831x_auxadc_irq, 0,
-                                          "auxadc", wm831x);
-               if (ret < 0)
-                       dev_err(wm831x->dev, "AUXADC IRQ request failed: %d\n",
-                               ret);
-       }
+       wm831x_auxadc_init(wm831x);
 
        /* The core device is up, instantiate the subdevices. */
        switch (parent) {
        case WM8310:
-               ret = mfd_add_devices(wm831x->dev, -1,
+               ret = mfd_add_devices(wm831x->dev, wm831x_num,
                                      wm8310_devs, ARRAY_SIZE(wm8310_devs),
                                      NULL, wm831x->irq_base);
                break;
 
        case WM8311:
-               ret = mfd_add_devices(wm831x->dev, -1,
+               ret = mfd_add_devices(wm831x->dev, wm831x_num,
                                      wm8311_devs, ARRAY_SIZE(wm8311_devs),
                                      NULL, wm831x->irq_base);
+               if (!pdata || !pdata->disable_touch)
+                       mfd_add_devices(wm831x->dev, wm831x_num,
+                                       touch_devs, ARRAY_SIZE(touch_devs),
+                                       NULL, wm831x->irq_base);
                break;
 
        case WM8312:
-               ret = mfd_add_devices(wm831x->dev, -1,
+               ret = mfd_add_devices(wm831x->dev, wm831x_num,
                                      wm8312_devs, ARRAY_SIZE(wm8312_devs),
                                      NULL, wm831x->irq_base);
+               if (!pdata || !pdata->disable_touch)
+                       mfd_add_devices(wm831x->dev, wm831x_num,
+                                       touch_devs, ARRAY_SIZE(touch_devs),
+                                       NULL, wm831x->irq_base);
                break;
 
        case WM8320:
        case WM8321:
        case WM8325:
        case WM8326:
-               ret = mfd_add_devices(wm831x->dev, -1,
+               ret = mfd_add_devices(wm831x->dev, wm831x_num,
                                      wm8320_devs, ARRAY_SIZE(wm8320_devs),
                                      NULL, wm831x->irq_base);
                break;
@@ -1645,9 +1507,30 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
                goto err_irq;
        }
 
+       /* The RTC can only be used if the 32.768kHz crystal is
+        * enabled; this can't be controlled by software at runtime.
+        */
+       ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
+       if (ret < 0) {
+               dev_err(wm831x->dev, "Failed to read clock status: %d\n", ret);
+               goto err_irq;
+       }
+
+       if (ret & WM831X_XTAL_ENA) {
+               ret = mfd_add_devices(wm831x->dev, wm831x_num,
+                                     rtc_devs, ARRAY_SIZE(rtc_devs),
+                                     NULL, wm831x->irq_base);
+               if (ret != 0) {
+                       dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret);
+                       goto err_irq;
+               }
+       } else {
+               dev_info(wm831x->dev, "32.768kHz clock disabled, no RTC\n");
+       }
+
        if (pdata && pdata->backlight) {
                /* Treat errors as non-critical */
-               ret = mfd_add_devices(wm831x->dev, -1, backlight_devs,
+               ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs,
                                      ARRAY_SIZE(backlight_devs), NULL,
                                      wm831x->irq_base);
                if (ret < 0)
index 42b928ec891e6b4b2a60a6323ed5d6265659e978..ada1835a54557b31424dc1f93297ffdb45b71a9a 100644 (file)
@@ -348,6 +348,15 @@ static void wm831x_irq_sync_unlock(struct irq_data *data)
        struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
        int i;
 
+       for (i = 0; i < ARRAY_SIZE(wm831x->gpio_update); i++) {
+               if (wm831x->gpio_update[i]) {
+                       wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + i,
+                                       WM831X_GPN_INT_MODE | WM831X_GPN_POL,
+                                       wm831x->gpio_update[i]);
+                       wm831x->gpio_update[i] = 0;
+               }
+       }
+
        for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
                /* If there's been a change in the mask write it back
                 * to the hardware. */
@@ -387,7 +396,7 @@ static void wm831x_irq_disable(struct irq_data *data)
 static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
 {
        struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
-       int val, irq;
+       int irq;
 
        irq = data->irq - wm831x->irq_base;
 
@@ -399,22 +408,30 @@ static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
                        return -EINVAL;
        }
 
+       /* Rebase the IRQ into the GPIO range so we've got a sensible array
+        * index.
+        */
+       irq -= WM831X_IRQ_GPIO_1;
+
+       /* We set the high bit to flag that we need an update; don't
+        * do the update here as we can be called with the bus lock
+        * held.
+        */
        switch (type) {
        case IRQ_TYPE_EDGE_BOTH:
-               val = WM831X_GPN_INT_MODE;
+               wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_INT_MODE;
                break;
        case IRQ_TYPE_EDGE_RISING:
-               val = WM831X_GPN_POL;
+               wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_POL;
                break;
        case IRQ_TYPE_EDGE_FALLING:
-               val = 0;
+               wm831x->gpio_update[irq] = 0x10000;
                break;
        default:
                return -EINVAL;
        }
 
-       return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + irq,
-                              WM831X_GPN_INT_MODE | WM831X_GPN_POL, val);
+       return 0;
 }
 
 static struct irq_chip wm831x_irq_chip = {
@@ -432,7 +449,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
 {
        struct wm831x *wm831x = data;
        unsigned int i;
-       int primary;
+       int primary, status_addr;
        int status_regs[WM831X_NUM_IRQ_REGS] = { 0 };
        int read[WM831X_NUM_IRQ_REGS] = { 0 };
        int *status;
@@ -467,8 +484,9 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
                /* Hopefully there should only be one register to read
                 * each time otherwise we ought to do a block read. */
                if (!read[offset]) {
-                       *status = wm831x_reg_read(wm831x,
-                                    irq_data_to_status_reg(&wm831x_irqs[i]));
+                       status_addr = irq_data_to_status_reg(&wm831x_irqs[i]);
+
+                       *status = wm831x_reg_read(wm831x, status_addr);
                        if (*status < 0) {
                                dev_err(wm831x->dev,
                                        "Failed to read IRQ status: %d\n",
@@ -477,26 +495,21 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
                        }
 
                        read[offset] = 1;
+
+                       /* Ignore any bits that we don't think are masked */
+                       *status &= ~wm831x->irq_masks_cur[offset];
+
+                       /* Acknowledge now so we don't miss
+                        * notifications while we handle.
+                        */
+                       wm831x_reg_write(wm831x, status_addr, *status);
                }
 
-               /* Report it if it isn't masked, or forget the status. */
-               if ((*status & ~wm831x->irq_masks_cur[offset])
-                   & wm831x_irqs[i].mask)
+               if (*status & wm831x_irqs[i].mask)
                        handle_nested_irq(wm831x->irq_base + i);
-               else
-                       *status &= ~wm831x_irqs[i].mask;
        }
 
 out:
-       /* Touchscreen interrupts are handled specially in the driver */
-       status_regs[0] &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT);
-
-       for (i = 0; i < ARRAY_SIZE(status_regs); i++) {
-               if (status_regs[i])
-                       wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i,
-                                        status_regs[i]);
-       }
-
        return IRQ_HANDLED;
 }
 
@@ -515,13 +528,22 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
                                 0xffff);
        }
 
-       if (!pdata || !pdata->irq_base) {
-               dev_err(wm831x->dev,
-                       "No interrupt base specified, no interrupts\n");
+       /* Try to dynamically allocate IRQs if no base is specified */
+       if (!pdata || !pdata->irq_base)
+               wm831x->irq_base = -1;
+       else
+               wm831x->irq_base = pdata->irq_base;
+
+       wm831x->irq_base = irq_alloc_descs(wm831x->irq_base, 0,
+                                          WM831X_NUM_IRQS, 0);
+       if (wm831x->irq_base < 0) {
+               dev_warn(wm831x->dev, "Failed to allocate IRQs: %d\n",
+                        wm831x->irq_base);
+               wm831x->irq_base = 0;
                return 0;
        }
 
-       if (pdata->irq_cmos)
+       if (pdata && pdata->irq_cmos)
                i = 0;
        else
                i = WM831X_IRQ_OD;
@@ -541,7 +563,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
        }
 
        wm831x->irq = irq;
-       wm831x->irq_base = pdata->irq_base;
 
        /* Register them with genirq */
        for (cur_irq = wm831x->irq_base;
index ed4b22a167b30104d3628bed7d3ee34753dd867b..8a1fafd0bf7d129184e8910b73a0848954dcf42c 100644 (file)
@@ -473,17 +473,13 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq,
 {
        int ret, cur_irq, i;
        int flags = IRQF_ONESHOT;
+       int irq_base = -1;
 
        if (!irq) {
                dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n");
                return 0;
        }
 
-       if (!pdata || !pdata->irq_base) {
-               dev_warn(wm8350->dev, "No interrupt support, no IRQ base\n");
-               return 0;
-       }
-
        /* Mask top level interrupts */
        wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
 
@@ -502,7 +498,17 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq,
        wm8350->chip_irq = irq;
        wm8350->irq_base = pdata->irq_base;
 
-       if (pdata->irq_high) {
+       if (pdata && pdata->irq_base > 0)
+               irq_base = pdata->irq_base;
+
+       wm8350->irq_base = irq_alloc_descs(irq_base, 0, ARRAY_SIZE(wm8350_irqs), 0);
+       if (wm8350->irq_base < 0) {
+               dev_warn(wm8350->dev, "Allocating irqs failed with %d\n",
+                       wm8350->irq_base);
+               return 0;
+       }
+
+       if (pdata && pdata->irq_high) {
                flags |= IRQF_TRIGGER_HIGH;
 
                wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
index e198d40292e7f5cb9c1ed5e78c4d3f41e30f1bc5..96479c9b1728918e8672a6aa9d03847365594263 100644 (file)
@@ -316,7 +316,7 @@ static int wm8994_suspend(struct device *dev)
 static int wm8994_resume(struct device *dev)
 {
        struct wm8994 *wm8994 = dev_get_drvdata(dev);
-       int ret;
+       int ret, i;
 
        /* We may have lied to the PM core about suspending */
        if (!wm8994->suspended)
@@ -329,10 +329,16 @@ static int wm8994_resume(struct device *dev)
                return ret;
        }
 
-       ret = wm8994_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK,
-                          WM8994_NUM_IRQ_REGS * 2, &wm8994->irq_masks_cur);
-       if (ret < 0)
-               dev_err(dev, "Failed to restore interrupt masks: %d\n", ret);
+       /* Write register at a time as we use the cache on the CPU so store
+        * it in native endian.
+        */
+       for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
+               ret = wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK
+                                      + i, wm8994->irq_masks_cur[i]);
+               if (ret < 0)
+                       dev_err(dev, "Failed to restore interrupt masks: %d\n",
+                               ret);
+       }
 
        ret = wm8994_write(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
                           &wm8994->ldo_regs);
@@ -403,7 +409,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                break;
        default:
                BUG();
-               return -EINVAL;
+               goto err;
        }
 
        wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
@@ -425,7 +431,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                break;
        default:
                BUG();
-               return -EINVAL;
+               goto err;
        }
                
        ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
@@ -476,13 +482,18 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
                goto err_enable;
        }
 
-       switch (ret) {
-       case 0:
-       case 1:
-               if (wm8994->type == WM8994)
+       switch (wm8994->type) {
+       case WM8994:
+               switch (ret) {
+               case 0:
+               case 1:
                        dev_warn(wm8994->dev,
                                 "revision %c not fully supported\n",
                                 'A' + ret);
+                       break;
+               default:
+                       break;
+               }
                break;
        default:
                break;
index 71c6e8f9aedb47af0fb1ab5d72a48bca872ad6ef..d682f7bd112cecf45519ceb178404c958c0f4747 100644 (file)
@@ -231,12 +231,6 @@ static irqreturn_t wm8994_irq_thread(int irq, void *data)
                status[i] &= ~wm8994->irq_masks_cur[i];
        }
 
-       /* Report */
-       for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
-               if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask)
-                       handle_nested_irq(wm8994->irq_base + i);
-       }
-
        /* Ack any unmasked IRQs */
        for (i = 0; i < ARRAY_SIZE(status); i++) {
                if (status[i])
@@ -244,6 +238,12 @@ static irqreturn_t wm8994_irq_thread(int irq, void *data)
                                         status[i]);
        }
 
+       /* Report */
+       for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
+               if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask)
+                       handle_nested_irq(wm8994->irq_base + i);
+       }
+
        return IRQ_HANDLED;
 }
 
index 710b706f4fcfd95ffd216068d07109c92c02f4f4..9ebfb4b482f5983870169b1b4f0662b1fd4c7e24 100644 (file)
@@ -20,7 +20,9 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
-#include <mach/hardware.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <mach/esdhc.h>
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
@@ -29,7 +31,6 @@
 #define SDHCI_VENDOR_SPEC              0xC0
 #define  SDHCI_VENDOR_SPEC_SDIO_QUIRK  0x00000002
 
-#define ESDHC_FLAG_GPIO_FOR_CD         (1 << 0)
 /*
  * The CMDTYPE of the CMD register (offset 0xE) should be set to
  * "11" when the STOP CMD12 is issued on imx53 to abort one
  */
 #define ESDHC_FLAG_MULTIBLK_NO_INT     (1 << 1)
 
+enum imx_esdhc_type {
+       IMX25_ESDHC,
+       IMX35_ESDHC,
+       IMX51_ESDHC,
+       IMX53_ESDHC,
+};
+
 struct pltfm_imx_data {
        int flags;
        u32 scratchpad;
+       enum imx_esdhc_type devtype;
+       struct esdhc_platform_data boarddata;
+};
+
+static struct platform_device_id imx_esdhc_devtype[] = {
+       {
+               .name = "sdhci-esdhc-imx25",
+               .driver_data = IMX25_ESDHC,
+       }, {
+               .name = "sdhci-esdhc-imx35",
+               .driver_data = IMX35_ESDHC,
+       }, {
+               .name = "sdhci-esdhc-imx51",
+               .driver_data = IMX51_ESDHC,
+       }, {
+               .name = "sdhci-esdhc-imx53",
+               .driver_data = IMX53_ESDHC,
+       }, {
+               /* sentinel */
+       }
 };
+MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype);
+
+static const struct of_device_id imx_esdhc_dt_ids[] = {
+       { .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], },
+       { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], },
+       { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
+       { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
+
+static inline int is_imx25_esdhc(struct pltfm_imx_data *data)
+{
+       return data->devtype == IMX25_ESDHC;
+}
+
+static inline int is_imx35_esdhc(struct pltfm_imx_data *data)
+{
+       return data->devtype == IMX35_ESDHC;
+}
+
+static inline int is_imx51_esdhc(struct pltfm_imx_data *data)
+{
+       return data->devtype == IMX51_ESDHC;
+}
+
+static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
+{
+       return data->devtype == IMX53_ESDHC;
+}
 
 static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
 {
@@ -60,17 +118,14 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
 
-       /* fake CARD_PRESENT flag on mx25/35 */
+       /* fake CARD_PRESENT flag */
        u32 val = readl(host->ioaddr + reg);
 
        if (unlikely((reg == SDHCI_PRESENT_STATE)
-                       && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD))) {
-               struct esdhc_platform_data *boarddata =
-                               host->mmc->parent->platform_data;
-
-               if (boarddata && gpio_is_valid(boarddata->cd_gpio)
-                               && gpio_get_value(boarddata->cd_gpio))
+                       && gpio_is_valid(boarddata->cd_gpio))) {
+               if (gpio_get_value(boarddata->cd_gpio))
                        /* no card, if a valid gpio says so... */
                        val &= ~SDHCI_CARD_PRESENT;
                else
@@ -85,12 +140,12 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
 
        if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)
-                       && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD)))
+                       && (boarddata->cd_type == ESDHC_CD_GPIO)))
                /*
                 * these interrupts won't work with a custom card_detect gpio
-                * (only applied to mx25/35)
                 */
                val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
 
@@ -173,6 +228,17 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
                return;
        }
        esdhc_clrset_le(host, 0xff, val, reg);
+
+       /*
+        * The esdhc has a design violation to SDHC spec which tells
+        * that software reset should not affect card detection circuit.
+        * But esdhc clears its SYSCTL register bits [0..2] during the
+        * software reset.  This will stop those clocks that card detection
+        * circuit relies on.  To work around it, we turn the clocks on back
+        * to keep card detection circuit functional.
+        */
+       if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1))
+               esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL);
 }
 
 static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
@@ -189,6 +255,26 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
        return clk_get_rate(pltfm_host->clk) / 256 / 16;
 }
 
+static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct pltfm_imx_data *imx_data = pltfm_host->priv;
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
+
+       switch (boarddata->wp_type) {
+       case ESDHC_WP_GPIO:
+               if (gpio_is_valid(boarddata->wp_gpio))
+                       return gpio_get_value(boarddata->wp_gpio);
+       case ESDHC_WP_CONTROLLER:
+               return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
+                              SDHCI_WRITE_PROTECT);
+       case ESDHC_WP_NONE:
+               break;
+       }
+
+       return -ENOSYS;
+}
+
 static struct sdhci_ops sdhci_esdhc_ops = {
        .read_l = esdhc_readl_le,
        .read_w = esdhc_readw_le,
@@ -198,6 +284,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
        .set_clock = esdhc_set_clock,
        .get_max_clock = esdhc_pltfm_get_max_clock,
        .get_min_clock = esdhc_pltfm_get_min_clock,
+       .get_ro = esdhc_pltfm_get_ro,
 };
 
 static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@@ -207,17 +294,6 @@ static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
        .ops = &sdhci_esdhc_ops,
 };
 
-static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
-{
-       struct esdhc_platform_data *boarddata =
-                       host->mmc->parent->platform_data;
-
-       if (boarddata && gpio_is_valid(boarddata->wp_gpio))
-               return gpio_get_value(boarddata->wp_gpio);
-       else
-               return -ENOSYS;
-}
-
 static irqreturn_t cd_irq(int irq, void *data)
 {
        struct sdhci_host *sdhost = (struct sdhci_host *)data;
@@ -226,8 +302,48 @@ static irqreturn_t cd_irq(int irq, void *data)
        return IRQ_HANDLED;
 };
 
+#ifdef CONFIG_OF
+static int __devinit
+sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
+                        struct esdhc_platform_data *boarddata)
+{
+       struct device_node *np = pdev->dev.of_node;
+
+       if (!np)
+               return -ENODEV;
+
+       if (of_get_property(np, "fsl,card-wired", NULL))
+               boarddata->cd_type = ESDHC_CD_PERMANENT;
+
+       if (of_get_property(np, "fsl,cd-controller", NULL))
+               boarddata->cd_type = ESDHC_CD_CONTROLLER;
+
+       if (of_get_property(np, "fsl,wp-controller", NULL))
+               boarddata->wp_type = ESDHC_WP_CONTROLLER;
+
+       boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
+       if (gpio_is_valid(boarddata->cd_gpio))
+               boarddata->cd_type = ESDHC_CD_GPIO;
+
+       boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
+       if (gpio_is_valid(boarddata->wp_gpio))
+               boarddata->wp_type = ESDHC_WP_GPIO;
+
+       return 0;
+}
+#else
+static inline int
+sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
+                        struct esdhc_platform_data *boarddata)
+{
+       return -ENODEV;
+}
+#endif
+
 static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *of_id =
+                       of_match_device(imx_esdhc_dt_ids, &pdev->dev);
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_host *host;
        struct esdhc_platform_data *boarddata;
@@ -242,8 +358,14 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
        pltfm_host = sdhci_priv(host);
 
        imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
-       if (!imx_data)
-               return -ENOMEM;
+       if (!imx_data) {
+               err = -ENOMEM;
+               goto err_imx_data;
+       }
+
+       if (of_id)
+               pdev->id_entry = of_id->data;
+       imx_data->devtype = pdev->id_entry->driver_data;
        pltfm_host->priv = imx_data;
 
        clk = clk_get(mmc_dev(host->mmc), NULL);
@@ -255,50 +377,72 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
        clk_enable(clk);
        pltfm_host->clk = clk;
 
-       if (!cpu_is_mx25())
+       if (!is_imx25_esdhc(imx_data))
                host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 
-       if (cpu_is_mx25() || cpu_is_mx35()) {
+       if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
                /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
                host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
-               /* write_protect can't be routed to controller, use gpio */
-               sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro;
-       }
 
-       if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
+       if (is_imx53_esdhc(imx_data))
                imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
 
-       boarddata = host->mmc->parent->platform_data;
-       if (boarddata) {
+       boarddata = &imx_data->boarddata;
+       if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
+               if (!host->mmc->parent->platform_data) {
+                       dev_err(mmc_dev(host->mmc), "no board data!\n");
+                       err = -EINVAL;
+                       goto no_board_data;
+               }
+               imx_data->boarddata = *((struct esdhc_platform_data *)
+                                       host->mmc->parent->platform_data);
+       }
+
+       /* write_protect */
+       if (boarddata->wp_type == ESDHC_WP_GPIO) {
                err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
                if (err) {
                        dev_warn(mmc_dev(host->mmc),
-                               "no write-protect pin available!\n");
-                       boarddata->wp_gpio = err;
+                                "no write-protect pin available!\n");
+                       boarddata->wp_gpio = -EINVAL;
                }
+       } else {
+               boarddata->wp_gpio = -EINVAL;
+       }
+
+       /* card_detect */
+       if (boarddata->cd_type != ESDHC_CD_GPIO)
+               boarddata->cd_gpio = -EINVAL;
 
+       switch (boarddata->cd_type) {
+       case ESDHC_CD_GPIO:
                err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
                if (err) {
-                       dev_warn(mmc_dev(host->mmc),
+                       dev_err(mmc_dev(host->mmc),
                                "no card-detect pin available!\n");
                        goto no_card_detect_pin;
                }
 
-               /* i.MX5x has issues to be researched */
-               if (!cpu_is_mx25() && !cpu_is_mx35())
-                       goto not_supported;
-
                err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
                                 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
                                 mmc_hostname(host->mmc), host);
                if (err) {
-                       dev_warn(mmc_dev(host->mmc), "request irq error\n");
+                       dev_err(mmc_dev(host->mmc), "request irq error\n");
                        goto no_card_detect_irq;
                }
+               /* fall through */
 
-               imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD;
-               /* Now we have a working card_detect again */
+       case ESDHC_CD_CONTROLLER:
+               /* we have a working card_detect back */
                host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+               break;
+
+       case ESDHC_CD_PERMANENT:
+               host->mmc->caps = MMC_CAP_NONREMOVABLE;
+               break;
+
+       case ESDHC_CD_NONE:
+               break;
        }
 
        err = sdhci_add_host(host);
@@ -307,16 +451,21 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 
        return 0;
 
- no_card_detect_irq:
-       gpio_free(boarddata->cd_gpio);
- no_card_detect_pin:
-       boarddata->cd_gpio = err;
- not_supported:
-       kfree(imx_data);
- err_add_host:
+err_add_host:
+       if (gpio_is_valid(boarddata->cd_gpio))
+               free_irq(gpio_to_irq(boarddata->cd_gpio), host);
+no_card_detect_irq:
+       if (gpio_is_valid(boarddata->cd_gpio))
+               gpio_free(boarddata->cd_gpio);
+       if (gpio_is_valid(boarddata->wp_gpio))
+               gpio_free(boarddata->wp_gpio);
+no_card_detect_pin:
+no_board_data:
        clk_disable(pltfm_host->clk);
        clk_put(pltfm_host->clk);
- err_clk_get:
+err_clk_get:
+       kfree(imx_data);
+err_imx_data:
        sdhci_pltfm_free(pdev);
        return err;
 }
@@ -325,20 +474,18 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
        struct pltfm_imx_data *imx_data = pltfm_host->priv;
+       struct esdhc_platform_data *boarddata = &imx_data->boarddata;
        int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
 
        sdhci_remove_host(host, dead);
 
-       if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+       if (gpio_is_valid(boarddata->wp_gpio))
                gpio_free(boarddata->wp_gpio);
 
-       if (boarddata && gpio_is_valid(boarddata->cd_gpio)) {
+       if (gpio_is_valid(boarddata->cd_gpio)) {
+               free_irq(gpio_to_irq(boarddata->cd_gpio), host);
                gpio_free(boarddata->cd_gpio);
-
-               if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION))
-                       free_irq(gpio_to_irq(boarddata->cd_gpio), host);
        }
 
        clk_disable(pltfm_host->clk);
@@ -354,7 +501,9 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
        .driver         = {
                .name   = "sdhci-esdhc-imx",
                .owner  = THIS_MODULE,
+               .of_match_table = imx_esdhc_dt_ids,
        },
+       .id_table       = imx_esdhc_devtype,
        .probe          = sdhci_esdhc_imx_probe,
        .remove         = __devexit_p(sdhci_esdhc_imx_remove),
 #ifdef CONFIG_PM
index 71c0ce1f6db08be407aa291b4501b0d4a5b5433f..6414efeddca0bb4475cd2fafa4d201dd2af77747 100644 (file)
@@ -85,6 +85,7 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
 {
        struct sdhci_host *host;
        struct sdhci_pltfm_host *pltfm_host;
+       struct device_node *np = pdev->dev.of_node;
        struct resource *iomem;
        int ret;
 
@@ -98,7 +99,7 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
                dev_err(&pdev->dev, "Invalid iomem size!\n");
 
        /* Some PCI-based MFD need the parent here */
-       if (pdev->dev.parent != &platform_bus)
+       if (pdev->dev.parent != &platform_bus && !np)
                host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
        else
                host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));
index b7622c3745fa118f746f66b121b5b3472b5f675b..e1eca2ab505ea248648346e21269ae380c0b7634 100644 (file)
@@ -282,6 +282,7 @@ obj-$(CONFIG_USB_HSO)               += usb/
 obj-$(CONFIG_USB_USBNET)        += usb/
 obj-$(CONFIG_USB_ZD1201)        += usb/
 obj-$(CONFIG_USB_IPHETH)        += usb/
+obj-$(CONFIG_USB_CDC_PHONET)   += usb/
 
 obj-$(CONFIG_WLAN) += wireless/
 obj-$(CONFIG_NET_TULIP) += tulip/
index 536038b22710607048b2af412917ae309074c306..31798f5f5d0601ffdc7f6522edb33f6b8a7cda47 100644 (file)
@@ -1502,13 +1502,13 @@ static int __devinit ace_init(struct net_device *dev)
         * firmware to wipe the ring without re-initializing it.
         */
        if (!test_and_set_bit(0, &ap->std_refill_busy))
-               ace_load_std_rx_ring(ap, RX_RING_SIZE);
+               ace_load_std_rx_ring(dev, RX_RING_SIZE);
        else
                printk(KERN_ERR "%s: Someone is busy refilling the RX ring\n",
                       ap->name);
        if (ap->version >= 2) {
                if (!test_and_set_bit(0, &ap->mini_refill_busy))
-                       ace_load_mini_rx_ring(ap, RX_MINI_SIZE);
+                       ace_load_mini_rx_ring(dev, RX_MINI_SIZE);
                else
                        printk(KERN_ERR "%s: Someone is busy refilling "
                               "the RX mini ring\n", ap->name);
@@ -1584,9 +1584,10 @@ static void ace_watchdog(struct net_device *data)
 }
 
 
-static void ace_tasklet(unsigned long dev)
+static void ace_tasklet(unsigned long arg)
 {
-       struct ace_private *ap = netdev_priv((struct net_device *)dev);
+       struct net_device *dev = (struct net_device *) arg;
+       struct ace_private *ap = netdev_priv(dev);
        int cur_size;
 
        cur_size = atomic_read(&ap->cur_rx_bufs);
@@ -1595,7 +1596,7 @@ static void ace_tasklet(unsigned long dev)
 #ifdef DEBUG
                printk("refilling buffers (current %i)\n", cur_size);
 #endif
-               ace_load_std_rx_ring(ap, RX_RING_SIZE - cur_size);
+               ace_load_std_rx_ring(dev, RX_RING_SIZE - cur_size);
        }
 
        if (ap->version >= 2) {
@@ -1606,7 +1607,7 @@ static void ace_tasklet(unsigned long dev)
                        printk("refilling mini buffers (current %i)\n",
                               cur_size);
 #endif
-                       ace_load_mini_rx_ring(ap, RX_MINI_SIZE - cur_size);
+                       ace_load_mini_rx_ring(dev, RX_MINI_SIZE - cur_size);
                }
        }
 
@@ -1616,7 +1617,7 @@ static void ace_tasklet(unsigned long dev)
 #ifdef DEBUG
                printk("refilling jumbo buffers (current %i)\n", cur_size);
 #endif
-               ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE - cur_size);
+               ace_load_jumbo_rx_ring(dev, RX_JUMBO_SIZE - cur_size);
        }
        ap->tasklet_pending = 0;
 }
@@ -1642,8 +1643,9 @@ static void ace_dump_trace(struct ace_private *ap)
  * done only before the device is enabled, thus no interrupts are
  * generated and by the interrupt handler/tasklet handler.
  */
-static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs)
+static void ace_load_std_rx_ring(struct net_device *dev, int nr_bufs)
 {
+       struct ace_private *ap = netdev_priv(dev);
        struct ace_regs __iomem *regs = ap->regs;
        short i, idx;
 
@@ -1657,11 +1659,10 @@ static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs)
                struct rx_desc *rd;
                dma_addr_t mapping;
 
-               skb = dev_alloc_skb(ACE_STD_BUFSIZE + NET_IP_ALIGN);
+               skb = netdev_alloc_skb_ip_align(dev, ACE_STD_BUFSIZE);
                if (!skb)
                        break;
 
-               skb_reserve(skb, NET_IP_ALIGN);
                mapping = pci_map_page(ap->pdev, virt_to_page(skb->data),
                                       offset_in_page(skb->data),
                                       ACE_STD_BUFSIZE,
@@ -1705,8 +1706,9 @@ static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs)
 }
 
 
-static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs)
+static void ace_load_mini_rx_ring(struct net_device *dev, int nr_bufs)
 {
+       struct ace_private *ap = netdev_priv(dev);
        struct ace_regs __iomem *regs = ap->regs;
        short i, idx;
 
@@ -1718,11 +1720,10 @@ static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs)
                struct rx_desc *rd;
                dma_addr_t mapping;
 
-               skb = dev_alloc_skb(ACE_MINI_BUFSIZE + NET_IP_ALIGN);
+               skb = netdev_alloc_skb_ip_align(dev, ACE_MINI_BUFSIZE);
                if (!skb)
                        break;
 
-               skb_reserve(skb, NET_IP_ALIGN);
                mapping = pci_map_page(ap->pdev, virt_to_page(skb->data),
                                       offset_in_page(skb->data),
                                       ACE_MINI_BUFSIZE,
@@ -1762,8 +1763,9 @@ static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs)
  * Load the jumbo rx ring, this may happen at any time if the MTU
  * is changed to a value > 1500.
  */
-static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs)
+static void ace_load_jumbo_rx_ring(struct net_device *dev, int nr_bufs)
 {
+       struct ace_private *ap = netdev_priv(dev);
        struct ace_regs __iomem *regs = ap->regs;
        short i, idx;
 
@@ -1774,11 +1776,10 @@ static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs)
                struct rx_desc *rd;
                dma_addr_t mapping;
 
-               skb = dev_alloc_skb(ACE_JUMBO_BUFSIZE + NET_IP_ALIGN);
+               skb = netdev_alloc_skb_ip_align(dev, ACE_JUMBO_BUFSIZE);
                if (!skb)
                        break;
 
-               skb_reserve(skb, NET_IP_ALIGN);
                mapping = pci_map_page(ap->pdev, virt_to_page(skb->data),
                                       offset_in_page(skb->data),
                                       ACE_JUMBO_BUFSIZE,
@@ -2196,7 +2197,7 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
 #ifdef DEBUG
                                printk("low on std buffers %i\n", cur_size);
 #endif
-                               ace_load_std_rx_ring(ap,
+                               ace_load_std_rx_ring(dev,
                                                     RX_RING_SIZE - cur_size);
                        } else
                                run_tasklet = 1;
@@ -2212,7 +2213,8 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
                                        printk("low on mini buffers %i\n",
                                               cur_size);
 #endif
-                                       ace_load_mini_rx_ring(ap, RX_MINI_SIZE - cur_size);
+                                       ace_load_mini_rx_ring(dev,
+                                                             RX_MINI_SIZE - cur_size);
                                } else
                                        run_tasklet = 1;
                        }
@@ -2228,7 +2230,8 @@ static irqreturn_t ace_interrupt(int irq, void *dev_id)
                                        printk("low on jumbo buffers %i\n",
                                               cur_size);
 #endif
-                                       ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE - cur_size);
+                                       ace_load_jumbo_rx_ring(dev,
+                                                              RX_JUMBO_SIZE - cur_size);
                                } else
                                        run_tasklet = 1;
                        }
@@ -2267,7 +2270,7 @@ static int ace_open(struct net_device *dev)
 
        if (ap->jumbo &&
            !test_and_set_bit(0, &ap->jumbo_refill_busy))
-               ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE);
+               ace_load_jumbo_rx_ring(dev, RX_JUMBO_SIZE);
 
        if (dev->flags & IFF_PROMISC) {
                cmd.evt = C_SET_PROMISC_MODE;
@@ -2575,7 +2578,7 @@ static int ace_change_mtu(struct net_device *dev, int new_mtu)
                               "support\n", dev->name);
                        ap->jumbo = 1;
                        if (!test_and_set_bit(0, &ap->jumbo_refill_busy))
-                               ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE);
+                               ace_load_jumbo_rx_ring(dev, RX_JUMBO_SIZE);
                        ace_set_rxtx_parms(dev, 1);
                }
        } else {
index f67dc9b0eb80071c2a3a7a41cc6f18869520a29d..51c486cfbb8cdec978f7e40083819b0acff624f1 100644 (file)
@@ -766,9 +766,9 @@ static inline void ace_unmask_irq(struct net_device *dev)
  * Prototypes
  */
 static int ace_init(struct net_device *dev);
-static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs);
-static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs);
-static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs);
+static void ace_load_std_rx_ring(struct net_device *dev, int nr_bufs);
+static void ace_load_mini_rx_ring(struct net_device *dev, int nr_bufs);
+static void ace_load_jumbo_rx_ring(struct net_device *dev, int nr_bufs);
 static irqreturn_t ace_interrupt(int irq, void *dev_id);
 static int ace_load_firmware(struct net_device *dev);
 static int ace_open(struct net_device *dev);
index 02842d05c11f4fce72069db79de1ed155d3919cd..38a83acd502e6395f06257cff0fa39cde757fa40 100644 (file)
@@ -1557,8 +1557,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
                        if (slave_dev->type != ARPHRD_ETHER)
                                bond_setup_by_slave(bond_dev, slave_dev);
-                       else
+                       else {
                                ether_setup(bond_dev);
+                               bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+                       }
 
                        netdev_bonding_change(bond_dev,
                                              NETDEV_POST_TYPE_CHANGE);
@@ -4330,7 +4332,7 @@ static void bond_setup(struct net_device *bond_dev)
        bond_dev->tx_queue_len = 0;
        bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
        bond_dev->priv_flags |= IFF_BONDING;
-       bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+       bond_dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
 
        /* At first, we block adding VLANs. That's the only way to
         * prevent problems that occur when adding VLANs over an
@@ -4691,7 +4693,7 @@ static int bond_check_params(struct bond_params *params)
                /* miimon and arp_interval not set, we need one so things
                 * work as expected, see bonding.txt for details
                 */
-               pr_warning("Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details.\n");
+               pr_debug("Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details.\n");
        }
 
        if (primary && !USES_PRIMARY(bond_mode)) {
index b60835f58650e8da337453d1f5a94c56b7444c4f..2dfb4bf90087a1af3475fbba0f6168eb85af3485 100644 (file)
@@ -1025,6 +1025,7 @@ static ssize_t bonding_store_primary(struct device *d,
        int i;
        struct slave *slave;
        struct bonding *bond = to_bond(d);
+       char ifname[IFNAMSIZ];
 
        if (!rtnl_trylock())
                return restart_syscall();
@@ -1035,32 +1036,33 @@ static ssize_t bonding_store_primary(struct device *d,
        if (!USES_PRIMARY(bond->params.mode)) {
                pr_info("%s: Unable to set primary slave; %s is in mode %d\n",
                        bond->dev->name, bond->dev->name, bond->params.mode);
-       } else {
-               bond_for_each_slave(bond, slave, i) {
-                       if (strnicmp
-                           (slave->dev->name, buf,
-                            strlen(slave->dev->name)) == 0) {
-                               pr_info("%s: Setting %s as primary slave.\n",
-                                       bond->dev->name, slave->dev->name);
-                               bond->primary_slave = slave;
-                               strcpy(bond->params.primary, slave->dev->name);
-                               bond_select_active_slave(bond);
-                               goto out;
-                       }
-               }
+               goto out;
+       }
 
-               /* if we got here, then we didn't match the name of any slave */
+       sscanf(buf, "%16s", ifname); /* IFNAMSIZ */
 
-               if (strlen(buf) == 0 || buf[0] == '\n') {
-                       pr_info("%s: Setting primary slave to None.\n",
-                               bond->dev->name);
-                       bond->primary_slave = NULL;
-                               bond_select_active_slave(bond);
-               } else {
-                       pr_info("%s: Unable to set %.*s as primary slave as it is not a slave.\n",
-                               bond->dev->name, (int)strlen(buf) - 1, buf);
+       /* check to see if we are clearing primary */
+       if (!strlen(ifname) || buf[0] == '\n') {
+               pr_info("%s: Setting primary slave to None.\n",
+                       bond->dev->name);
+               bond->primary_slave = NULL;
+               bond_select_active_slave(bond);
+               goto out;
+       }
+
+       bond_for_each_slave(bond, slave, i) {
+               if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
+                       pr_info("%s: Setting %s as primary slave.\n",
+                               bond->dev->name, slave->dev->name);
+                       bond->primary_slave = slave;
+                       strcpy(bond->params.primary, slave->dev->name);
+                       bond_select_active_slave(bond);
+                       goto out;
                }
        }
+
+       pr_info("%s: Unable to set %.*s as primary slave.\n",
+               bond->dev->name, (int)strlen(buf) - 1, buf);
 out:
        write_unlock_bh(&bond->curr_slave_lock);
        read_unlock(&bond->lock);
@@ -1195,6 +1197,7 @@ static ssize_t bonding_store_active_slave(struct device *d,
        struct slave *old_active = NULL;
        struct slave *new_active = NULL;
        struct bonding *bond = to_bond(d);
+       char ifname[IFNAMSIZ];
 
        if (!rtnl_trylock())
                return restart_syscall();
@@ -1203,56 +1206,62 @@ static ssize_t bonding_store_active_slave(struct device *d,
        read_lock(&bond->lock);
        write_lock_bh(&bond->curr_slave_lock);
 
-       if (!USES_PRIMARY(bond->params.mode))
+       if (!USES_PRIMARY(bond->params.mode)) {
                pr_info("%s: Unable to change active slave; %s is in mode %d\n",
                        bond->dev->name, bond->dev->name, bond->params.mode);
-       else {
-               bond_for_each_slave(bond, slave, i) {
-                       if (strnicmp
-                           (slave->dev->name, buf,
-                            strlen(slave->dev->name)) == 0) {
-                               old_active = bond->curr_active_slave;
-                               new_active = slave;
-                               if (new_active == old_active) {
-                                       /* do nothing */
-                                       pr_info("%s: %s is already the current active slave.\n",
+               goto out;
+       }
+
+       sscanf(buf, "%16s", ifname); /* IFNAMSIZ */
+
+       /* check to see if we are clearing active */
+       if (!strlen(ifname) || buf[0] == '\n') {
+               pr_info("%s: Clearing current active slave.\n",
+                       bond->dev->name);
+               bond->curr_active_slave = NULL;
+               bond_select_active_slave(bond);
+               goto out;
+       }
+
+       bond_for_each_slave(bond, slave, i) {
+               if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
+                       old_active = bond->curr_active_slave;
+                       new_active = slave;
+                       if (new_active == old_active) {
+                               /* do nothing */
+                               pr_info("%s: %s is already the current"
+                                       " active slave.\n",
+                                       bond->dev->name,
+                                       slave->dev->name);
+                               goto out;
+                       }
+                       else {
+                               if ((new_active) &&
+                                   (old_active) &&
+                                   (new_active->link == BOND_LINK_UP) &&
+                                   IS_UP(new_active->dev)) {
+                                       pr_info("%s: Setting %s as active"
+                                               " slave.\n",
                                                bond->dev->name,
                                                slave->dev->name);
-                                       goto out;
+                                       bond_change_active_slave(bond,
+                                                                new_active);
                                }
                                else {
-                                       if ((new_active) &&
-                                           (old_active) &&
-                                           (new_active->link == BOND_LINK_UP) &&
-                                           IS_UP(new_active->dev)) {
-                                               pr_info("%s: Setting %s as active slave.\n",
-                                                       bond->dev->name,
-                                                       slave->dev->name);
-                                                       bond_change_active_slave(bond, new_active);
-                                       }
-                                       else {
-                                               pr_info("%s: Could not set %s as active slave; either %s is down or the link is down.\n",
-                                                       bond->dev->name,
-                                                       slave->dev->name,
-                                                       slave->dev->name);
-                                       }
-                                       goto out;
+                                       pr_info("%s: Could not set %s as"
+                                               " active slave; either %s is"
+                                               " down or the link is down.\n",
+                                               bond->dev->name,
+                                               slave->dev->name,
+                                               slave->dev->name);
                                }
+                               goto out;
                        }
                }
-
-               /* if we got here, then we didn't match the name of any slave */
-
-               if (strlen(buf) == 0 || buf[0] == '\n') {
-                       pr_info("%s: Setting active slave to None.\n",
-                               bond->dev->name);
-                       bond->primary_slave = NULL;
-                       bond_select_active_slave(bond);
-               } else {
-                       pr_info("%s: Unable to set %.*s as active slave as it is not a slave.\n",
-                               bond->dev->name, (int)strlen(buf) - 1, buf);
-               }
        }
+
+       pr_info("%s: Unable to set %.*s as active slave.\n",
+               bond->dev->name, (int)strlen(buf) - 1, buf);
  out:
        write_unlock_bh(&bond->curr_slave_lock);
        read_unlock(&bond->lock);
index 5b631fe74738367d50c6b59e6f0f93995ef4c87d..e8266ccf818a033b0539e8e3cb0b3c82c4056c7c 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/phy.h>
 #include <linux/fec.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_net.h>
 
 #include <asm/cacheflush.h>
 
 #define FEC_QUIRK_ENET_MAC             (1 << 0)
 /* Controller needs driver to swap frame */
 #define FEC_QUIRK_SWAP_FRAME           (1 << 1)
+/* Controller uses gasket */
+#define FEC_QUIRK_USE_GASKET           (1 << 2)
 
 static struct platform_device_id fec_devtype[] = {
        {
+               /* keep it for coldfire */
                .name = DRIVER_NAME,
                .driver_data = 0,
+       }, {
+               .name = "imx25-fec",
+               .driver_data = FEC_QUIRK_USE_GASKET,
+       }, {
+               .name = "imx27-fec",
+               .driver_data = 0,
        }, {
                .name = "imx28-fec",
                .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
-       },
-       { }
+       }, {
+               /* sentinel */
+       }
 };
+MODULE_DEVICE_TABLE(platform, fec_devtype);
+
+enum imx_fec_type {
+       IMX25_FEC = 1,  /* runs on i.mx25/50/53 */
+       IMX27_FEC,      /* runs on i.mx27/35/51 */
+       IMX28_FEC,
+};
+
+static const struct of_device_id fec_dt_ids[] = {
+       { .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], },
+       { .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
+       { .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fec_dt_ids);
 
 static unsigned char macaddr[ETH_ALEN];
 module_param_array(macaddr, byte, NULL, 0);
@@ -427,7 +456,7 @@ fec_restart(struct net_device *ndev, int duplex)
 
        } else {
 #ifdef FEC_MIIGSK_ENR
-               if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
+               if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) {
                        /* disable the gasket and wait */
                        writel(0, fep->hwp + FEC_MIIGSK_ENR);
                        while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
@@ -436,8 +465,11 @@ fec_restart(struct net_device *ndev, int duplex)
                        /*
                         * configure the gasket:
                         *   RMII, 50 MHz, no loopback, no echo
+                        *   MII, 25 MHz, no loopback, no echo
                         */
-                       writel(1, fep->hwp + FEC_MIIGSK_CFGR);
+                       writel((fep->phy_interface == PHY_INTERFACE_MODE_RMII) ?
+                                       1 : 0, fep->hwp + FEC_MIIGSK_CFGR);
+
 
                        /* re-enable the gasket */
                        writel(2, fep->hwp + FEC_MIIGSK_ENR);
@@ -734,8 +766,22 @@ static void __inline__ fec_get_mac(struct net_device *ndev)
         */
        iap = macaddr;
 
+#ifdef CONFIG_OF
        /*
-        * 2) from flash or fuse (via platform data)
+        * 2) from device tree data
+        */
+       if (!is_valid_ether_addr(iap)) {
+               struct device_node *np = fep->pdev->dev.of_node;
+               if (np) {
+                       const char *mac = of_get_mac_address(np);
+                       if (mac)
+                               iap = (unsigned char *) mac;
+               }
+       }
+#endif
+
+       /*
+        * 3) from flash or fuse (via platform data)
         */
        if (!is_valid_ether_addr(iap)) {
 #ifdef CONFIG_M5272
@@ -748,7 +794,7 @@ static void __inline__ fec_get_mac(struct net_device *ndev)
        }
 
        /*
-        * 3) FEC mac registers set by bootloader
+        * 4) FEC mac registers set by bootloader
         */
        if (!is_valid_ether_addr(iap)) {
                *((unsigned long *) &tmpaddr[0]) =
@@ -1354,6 +1400,52 @@ static int fec_enet_init(struct net_device *ndev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static int __devinit fec_get_phy_mode_dt(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+
+       if (np)
+               return of_get_phy_mode(np);
+
+       return -ENODEV;
+}
+
+static int __devinit fec_reset_phy(struct platform_device *pdev)
+{
+       int err, phy_reset;
+       struct device_node *np = pdev->dev.of_node;
+
+       if (!np)
+               return -ENODEV;
+
+       phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
+       err = gpio_request_one(phy_reset, GPIOF_OUT_INIT_LOW, "phy-reset");
+       if (err) {
+               pr_warn("FEC: failed to get gpio phy-reset: %d\n", err);
+               return err;
+       }
+       msleep(1);
+       gpio_set_value(phy_reset, 1);
+
+       return 0;
+}
+#else /* CONFIG_OF */
+static inline int fec_get_phy_mode_dt(struct platform_device *pdev)
+{
+       return -ENODEV;
+}
+
+static inline int fec_reset_phy(struct platform_device *pdev)
+{
+       /*
+        * In case of platform probe, the reset has been done
+        * by machine code.
+        */
+       return 0;
+}
+#endif /* CONFIG_OF */
+
 static int __devinit
 fec_probe(struct platform_device *pdev)
 {
@@ -1362,6 +1454,11 @@ fec_probe(struct platform_device *pdev)
        struct net_device *ndev;
        int i, irq, ret = 0;
        struct resource *r;
+       const struct of_device_id *of_id;
+
+       of_id = of_match_device(fec_dt_ids, &pdev->dev);
+       if (of_id)
+               pdev->id_entry = of_id->data;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r)
@@ -1393,9 +1490,18 @@ fec_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ndev);
 
-       pdata = pdev->dev.platform_data;
-       if (pdata)
-               fep->phy_interface = pdata->phy;
+       ret = fec_get_phy_mode_dt(pdev);
+       if (ret < 0) {
+               pdata = pdev->dev.platform_data;
+               if (pdata)
+                       fep->phy_interface = pdata->phy;
+               else
+                       fep->phy_interface = PHY_INTERFACE_MODE_MII;
+       } else {
+               fep->phy_interface = ret;
+       }
+
+       fec_reset_phy(pdev);
 
        /* This device has up to three irqs on some platforms */
        for (i = 0; i < 3; i++) {
@@ -1530,6 +1636,7 @@ static struct platform_driver fec_driver = {
 #ifdef CONFIG_PM
                .pm     = &fec_pm_ops,
 #endif
+               .of_match_table = fec_dt_ids,
        },
        .id_table = fec_devtype,
        .probe  = fec_probe,
index e64cd9ceac3f082e2f88844be5262c411860100a..e55df308a3af219a54beaadc7dfdcd42c9508de8 100644 (file)
@@ -2764,7 +2764,14 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
                        prefetch(skb->data);
 
                        vlanflags = le32_to_cpu(np->get_rx.ex->buflow);
-                       if (vlanflags & NV_RX3_VLAN_TAG_PRESENT) {
+
+                       /*
+                        * There's need to check for NETIF_F_HW_VLAN_RX here.
+                        * Even if vlan rx accel is disabled,
+                        * NV_RX3_VLAN_TAG_PRESENT is pseudo randomly set.
+                        */
+                       if (dev->features & NETIF_F_HW_VLAN_RX &&
+                           vlanflags & NV_RX3_VLAN_TAG_PRESENT) {
                                u16 vid = vlanflags & NV_RX3_VLAN_TAG_MASK;
 
                                __vlan_hwaccel_put_tag(skb, vid);
@@ -5331,15 +5338,16 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
                dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG |
                        NETIF_F_TSO | NETIF_F_RXCSUM;
-               dev->features |= dev->hw_features;
        }
 
        np->vlanctl_bits = 0;
        if (id->driver_data & DEV_HAS_VLAN) {
                np->vlanctl_bits = NVREG_VLANCONTROL_ENABLE;
-               dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
+               dev->hw_features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
        }
 
+       dev->features |= dev->hw_features;
+
        np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG;
        if ((id->driver_data & DEV_HAS_PAUSEFRAME_TX_V1) ||
            (id->driver_data & DEV_HAS_PAUSEFRAME_TX_V2) ||
@@ -5607,6 +5615,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                goto out_error;
        }
 
+       nv_vlan_mode(dev, dev->features);
+
        netif_carrier_off(dev);
 
        dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n",
index 835cd2588148527777f87c089e31bca2d2d06d81..2659daad783ddb857f5e9597bbb2a2ea95c05f04 100644 (file)
@@ -388,12 +388,8 @@ static void gfar_init_mac(struct net_device *ndev)
        if (priv->hwts_rx_en)
                rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE;
 
-       /* keep vlan related bits if it's enabled */
-       if (ndev->features & NETIF_F_HW_VLAN_TX)
-               rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
-
        if (ndev->features & NETIF_F_HW_VLAN_RX)
-               tctrl |= TCTRL_VLINS;
+               rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
 
        /* Init rctrl based on our settings */
        gfar_write(&regs->rctrl, rctrl);
index 725399ea06902f33e7e480b7f4f31826e019b7be..70cb7d8a3b53c6eeb10595455434a34836c9b44e 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/bitops.h>
 #include <linux/workqueue.h>
 #include <linux/of.h>
+#include <linux/of_net.h>
 #include <linux/slab.h>
 
 #include <asm/processor.h>
@@ -2506,18 +2507,6 @@ static int __devinit emac_init_config(struct emac_instance *dev)
 {
        struct device_node *np = dev->ofdev->dev.of_node;
        const void *p;
-       unsigned int plen;
-       const char *pm, *phy_modes[] = {
-               [PHY_MODE_NA] = "",
-               [PHY_MODE_MII] = "mii",
-               [PHY_MODE_RMII] = "rmii",
-               [PHY_MODE_SMII] = "smii",
-               [PHY_MODE_RGMII] = "rgmii",
-               [PHY_MODE_TBI] = "tbi",
-               [PHY_MODE_GMII] = "gmii",
-               [PHY_MODE_RTBI] = "rtbi",
-               [PHY_MODE_SGMII] = "sgmii",
-       };
 
        /* Read config from device-tree */
        if (emac_read_uint_prop(np, "mal-device", &dev->mal_ph, 1))
@@ -2566,23 +2555,9 @@ static int __devinit emac_init_config(struct emac_instance *dev)
                dev->mal_burst_size = 256;
 
        /* PHY mode needs some decoding */
-       dev->phy_mode = PHY_MODE_NA;
-       pm = of_get_property(np, "phy-mode", &plen);
-       if (pm != NULL) {
-               int i;
-               for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
-                       if (!strcasecmp(pm, phy_modes[i])) {
-                               dev->phy_mode = i;
-                               break;
-                       }
-       }
-
-       /* Backward compat with non-final DT */
-       if (dev->phy_mode == PHY_MODE_NA && pm != NULL && plen == 4) {
-               u32 nmode = *(const u32 *)pm;
-               if (nmode > PHY_MODE_NA && nmode <= PHY_MODE_SGMII)
-                       dev->phy_mode = nmode;
-       }
+       dev->phy_mode = of_get_phy_mode(np);
+       if (dev->phy_mode < 0)
+               dev->phy_mode = PHY_MODE_NA;
 
        /* Check EMAC version */
        if (of_device_is_compatible(np, "ibm,emac4sync")) {
index 8a61b597a169e78a3a6035e274cc919bfa13b301..1568278d759a893589196c505251c92ad5e3c587 100644 (file)
@@ -26,6 +26,7 @@
 #define __IBM_NEWEMAC_H
 
 #include <linux/types.h>
+#include <linux/phy.h>
 
 /* EMAC registers                      Write Access rules */
 struct emac_regs {
@@ -106,15 +107,15 @@ struct emac_regs {
 /*
  * PHY mode settings (EMAC <-> ZMII/RGMII bridge <-> PHY)
  */
-#define PHY_MODE_NA    0
-#define PHY_MODE_MII   1
-#define PHY_MODE_RMII  2
-#define PHY_MODE_SMII  3
-#define PHY_MODE_RGMII 4
-#define PHY_MODE_TBI   5
-#define PHY_MODE_GMII  6
-#define PHY_MODE_RTBI  7
-#define PHY_MODE_SGMII 8
+#define PHY_MODE_NA    PHY_INTERFACE_MODE_NA
+#define PHY_MODE_MII   PHY_INTERFACE_MODE_MII
+#define PHY_MODE_RMII  PHY_INTERFACE_MODE_RMII
+#define PHY_MODE_SMII  PHY_INTERFACE_MODE_SMII
+#define PHY_MODE_RGMII PHY_INTERFACE_MODE_RGMII
+#define PHY_MODE_TBI   PHY_INTERFACE_MODE_TBI
+#define PHY_MODE_GMII  PHY_INTERFACE_MODE_GMII
+#define PHY_MODE_RTBI  PHY_INTERFACE_MODE_RTBI
+#define PHY_MODE_SGMII PHY_INTERFACE_MODE_SGMII
 
 /* EMACx_MR0 */
 #define EMAC_MR0_RXI                   0x80000000
index ac9d964e59ec7c4a2f067f025559a9374b544938..ab4e5969fe65e3cc9ef3faf67b57c92f91aeb73c 100644 (file)
 #include "emac.h"
 #include "phy.h"
 
-static inline int phy_read(struct mii_phy *phy, int reg)
+#define phy_read _phy_read
+#define phy_write _phy_write
+
+static inline int _phy_read(struct mii_phy *phy, int reg)
 {
        return phy->mdio_read(phy->dev, phy->address, reg);
 }
 
-static inline void phy_write(struct mii_phy *phy, int reg, int val)
+static inline void _phy_write(struct mii_phy *phy, int reg, int val)
 {
        phy->mdio_write(phy->dev, phy->address, reg, val);
 }
index 6e82dd32e8063b019dcba2918c8fb108d6ab7eb5..46b5f5fd686bab98b98aff86fbf3e43b0702ddb8 100644 (file)
@@ -183,7 +183,7 @@ static void ifb_setup(struct net_device *dev)
 
        dev->flags |= IFF_NOARP;
        dev->flags &= ~IFF_MULTICAST;
-       dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+       dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
        random_ether_addr(dev->dev_addr);
 }
 
index ba631fcece34d795c4bfea754d0d192178cc622e..05172c39a0ceaab229c4c89411c7fabc7201ce0c 100644 (file)
@@ -572,7 +572,7 @@ void macvlan_common_setup(struct net_device *dev)
 {
        ether_setup(dev);
 
-       dev->priv_flags        &= ~IFF_XMIT_DST_RELEASE;
+       dev->priv_flags        &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
        dev->netdev_ops         = &macvlan_netdev_ops;
        dev->destructor         = free_netdev;
        dev->header_ops         = &macvlan_hard_header_ops,
index 1cd9394c33598eb500796e9e6921ad5128d14cd9..cffbc0373fa9bd1a3aae0e69bd26b7f7c2f070c2 100644 (file)
@@ -809,7 +809,7 @@ static int smc91c92_config(struct pcmcia_device *link)
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
     char *name;
-    int i, j, rev;
+    int i, rev, j = 0;
     unsigned int ioaddr;
     u_long mir;
 
index be745ae8f4e39f7e6fe867564a4b2e8f20acf7cd..ade35dde5b51593638327ab5a640f995fb0c08a3 100644 (file)
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
-#include <asm/prom.h>
 
 #ifdef CONFIG_SPARC
 #include <asm/idprom.h>
+#include <asm/prom.h>
 #endif
 
 #ifdef CONFIG_PPC_PMAC
 #include <asm/pci-bridge.h>
+#include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #endif
index 803576568154e9e622222e2d91ac6d2ef2e06b0f..dc3fbf61910b562bdaa2686e8bb3f861a4cc499b 100644 (file)
@@ -190,6 +190,7 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 
 /* minimum number of free TX descriptors required to wake up TX process */
 #define TG3_TX_WAKEUP_THRESH(tnapi)            ((tnapi)->tx_pending / 4)
+#define TG3_TX_BD_DMA_MAX              4096
 
 #define TG3_RAW_IP_ALIGN 2
 
@@ -4824,7 +4825,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
        txq = netdev_get_tx_queue(tp->dev, index);
 
        while (sw_idx != hw_idx) {
-               struct ring_info *ri = &tnapi->tx_buffers[sw_idx];
+               struct tg3_tx_ring_info *ri = &tnapi->tx_buffers[sw_idx];
                struct sk_buff *skb = ri->skb;
                int i, tx_bug = 0;
 
@@ -4840,6 +4841,12 @@ static void tg3_tx(struct tg3_napi *tnapi)
 
                ri->skb = NULL;
 
+               while (ri->fragmented) {
+                       ri->fragmented = false;
+                       sw_idx = NEXT_TX(sw_idx);
+                       ri = &tnapi->tx_buffers[sw_idx];
+               }
+
                sw_idx = NEXT_TX(sw_idx);
 
                for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
@@ -4851,6 +4858,13 @@ static void tg3_tx(struct tg3_napi *tnapi)
                                       dma_unmap_addr(ri, mapping),
                                       skb_shinfo(skb)->frags[i].size,
                                       PCI_DMA_TODEVICE);
+
+                       while (ri->fragmented) {
+                               ri->fragmented = false;
+                               sw_idx = NEXT_TX(sw_idx);
+                               ri = &tnapi->tx_buffers[sw_idx];
+                       }
+
                        sw_idx = NEXT_TX(sw_idx);
                }
 
@@ -5901,40 +5915,100 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping,
 #endif
 }
 
-static void tg3_set_txd(struct tg3_napi *tnapi, int entry,
-                       dma_addr_t mapping, int len, u32 flags,
-                       u32 mss_and_is_end)
+static inline void tg3_tx_set_bd(struct tg3_tx_buffer_desc *txbd,
+                                dma_addr_t mapping, u32 len, u32 flags,
+                                u32 mss, u32 vlan)
+{
+       txbd->addr_hi = ((u64) mapping >> 32);
+       txbd->addr_lo = ((u64) mapping & 0xffffffff);
+       txbd->len_flags = (len << TXD_LEN_SHIFT) | (flags & 0x0000ffff);
+       txbd->vlan_tag = (mss << TXD_MSS_SHIFT) | (vlan << TXD_VLAN_TAG_SHIFT);
+}
+
+static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget,
+                           dma_addr_t map, u32 len, u32 flags,
+                           u32 mss, u32 vlan)
 {
-       struct tg3_tx_buffer_desc *txd = &tnapi->tx_ring[entry];
-       int is_end = (mss_and_is_end & 0x1);
-       u32 mss = (mss_and_is_end >> 1);
-       u32 vlan_tag = 0;
+       struct tg3 *tp = tnapi->tp;
+       bool hwbug = false;
+
+       if (tg3_flag(tp, SHORT_DMA_BUG) && len <= 8)
+               hwbug = 1;
+
+       if (tg3_4g_overflow_test(map, len))
+               hwbug = 1;
+
+       if (tg3_40bit_overflow_test(tp, map, len))
+               hwbug = 1;
+
+       if (tg3_flag(tp, 4K_FIFO_LIMIT)) {
+               u32 tmp_flag = flags & ~TXD_FLAG_END;
+               while (len > TG3_TX_BD_DMA_MAX) {
+                       u32 frag_len = TG3_TX_BD_DMA_MAX;
+                       len -= TG3_TX_BD_DMA_MAX;
+
+                       if (len) {
+                               tnapi->tx_buffers[*entry].fragmented = true;
+                               /* Avoid the 8byte DMA problem */
+                               if (len <= 8) {
+                                       len += TG3_TX_BD_DMA_MAX / 2;
+                                       frag_len = TG3_TX_BD_DMA_MAX / 2;
+                               }
+                       } else
+                               tmp_flag = flags;
+
+                       if (*budget) {
+                               tg3_tx_set_bd(&tnapi->tx_ring[*entry], map,
+                                             frag_len, tmp_flag, mss, vlan);
+                               (*budget)--;
+                               *entry = NEXT_TX(*entry);
+                       } else {
+                               hwbug = 1;
+                               break;
+                       }
+
+                       map += frag_len;
+               }
 
-       if (is_end)
-               flags |= TXD_FLAG_END;
-       if (flags & TXD_FLAG_VLAN) {
-               vlan_tag = flags >> 16;
-               flags &= 0xffff;
+               if (len) {
+                       if (*budget) {
+                               tg3_tx_set_bd(&tnapi->tx_ring[*entry], map,
+                                             len, flags, mss, vlan);
+                               (*budget)--;
+                               *entry = NEXT_TX(*entry);
+                       } else {
+                               hwbug = 1;
+                       }
+               }
+       } else {
+               tg3_tx_set_bd(&tnapi->tx_ring[*entry], map,
+                             len, flags, mss, vlan);
+               *entry = NEXT_TX(*entry);
        }
-       vlan_tag |= (mss << TXD_MSS_SHIFT);
 
-       txd->addr_hi = ((u64) mapping >> 32);
-       txd->addr_lo = ((u64) mapping & 0xffffffff);
-       txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
-       txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
+       return hwbug;
 }
 
-static void tg3_skb_error_unmap(struct tg3_napi *tnapi,
-                               struct sk_buff *skb, int last)
+static void tg3_tx_skb_unmap(struct tg3_napi *tnapi, u32 entry, int last)
 {
        int i;
-       u32 entry = tnapi->tx_prod;
-       struct ring_info *txb = &tnapi->tx_buffers[entry];
+       struct sk_buff *skb;
+       struct tg3_tx_ring_info *txb = &tnapi->tx_buffers[entry];
+
+       skb = txb->skb;
+       txb->skb = NULL;
 
        pci_unmap_single(tnapi->tp->pdev,
                         dma_unmap_addr(txb, mapping),
                         skb_headlen(skb),
                         PCI_DMA_TODEVICE);
+
+       while (txb->fragmented) {
+               txb->fragmented = false;
+               entry = NEXT_TX(entry);
+               txb = &tnapi->tx_buffers[entry];
+       }
+
        for (i = 0; i < last; i++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
@@ -5944,18 +6018,24 @@ static void tg3_skb_error_unmap(struct tg3_napi *tnapi,
                pci_unmap_page(tnapi->tp->pdev,
                               dma_unmap_addr(txb, mapping),
                               frag->size, PCI_DMA_TODEVICE);
+
+               while (txb->fragmented) {
+                       txb->fragmented = false;
+                       entry = NEXT_TX(entry);
+                       txb = &tnapi->tx_buffers[entry];
+               }
        }
 }
 
 /* Workaround 4GB and 40-bit hardware DMA bugs. */
 static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
                                       struct sk_buff *skb,
-                                      u32 base_flags, u32 mss)
+                                      u32 *entry, u32 *budget,
+                                      u32 base_flags, u32 mss, u32 vlan)
 {
        struct tg3 *tp = tnapi->tp;
        struct sk_buff *new_skb;
        dma_addr_t new_addr = 0;
-       u32 entry = tnapi->tx_prod;
        int ret = 0;
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
@@ -5976,24 +6056,22 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
                                          PCI_DMA_TODEVICE);
                /* Make sure the mapping succeeded */
                if (pci_dma_mapping_error(tp->pdev, new_addr)) {
-                       ret = -1;
                        dev_kfree_skb(new_skb);
-
-               /* Make sure new skb does not cross any 4G boundaries.
-                * Drop the packet if it does.
-                */
-               } else if (tg3_4g_overflow_test(new_addr, new_skb->len)) {
-                       pci_unmap_single(tp->pdev, new_addr, new_skb->len,
-                                        PCI_DMA_TODEVICE);
                        ret = -1;
-                       dev_kfree_skb(new_skb);
                } else {
-                       tnapi->tx_buffers[entry].skb = new_skb;
-                       dma_unmap_addr_set(&tnapi->tx_buffers[entry],
+                       base_flags |= TXD_FLAG_END;
+
+                       tnapi->tx_buffers[*entry].skb = new_skb;
+                       dma_unmap_addr_set(&tnapi->tx_buffers[*entry],
                                           mapping, new_addr);
 
-                       tg3_set_txd(tnapi, entry, new_addr, new_skb->len,
-                                   base_flags, 1 | (mss << 1));
+                       if (tg3_tx_frag_set(tnapi, entry, budget, new_addr,
+                                           new_skb->len, base_flags,
+                                           mss, vlan)) {
+                               tg3_tx_skb_unmap(tnapi, *entry, 0);
+                               dev_kfree_skb(new_skb);
+                               ret = -1;
+                       }
                }
        }
 
@@ -6051,7 +6129,8 @@ tg3_tso_bug_end:
 static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
-       u32 len, entry, base_flags, mss;
+       u32 len, entry, base_flags, mss, vlan = 0;
+       u32 budget;
        int i = -1, would_hit_hwbug;
        dma_addr_t mapping;
        struct tg3_napi *tnapi;
@@ -6063,12 +6142,14 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (tg3_flag(tp, ENABLE_TSS))
                tnapi++;
 
+       budget = tg3_tx_avail(tnapi);
+
        /* We are running in BH disabled context with netif_tx_lock
         * and TX reclaim runs via tp->napi.poll inside of a software
         * interrupt.  Furthermore, IRQ processing runs lockless so we have
         * no IRQ context deadlocks to worry about either.  Rejoice!
         */
-       if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) {
+       if (unlikely(budget <= (skb_shinfo(skb)->nr_frags + 1))) {
                if (!netif_tx_queue_stopped(txq)) {
                        netif_tx_stop_queue(txq);
 
@@ -6153,9 +6234,12 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
-       if (vlan_tx_tag_present(skb))
-               base_flags |= (TXD_FLAG_VLAN |
-                              (vlan_tx_tag_get(skb) << 16));
+#ifdef BCM_KERNEL_SUPPORTS_8021Q
+       if (vlan_tx_tag_present(skb)) {
+               base_flags |= TXD_FLAG_VLAN;
+               vlan = vlan_tx_tag_get(skb);
+       }
+#endif
 
        if (tg3_flag(tp, USE_JUMBO_BDFLAG) &&
            !mss && skb->len > VLAN_ETH_FRAME_LEN)
@@ -6174,25 +6258,23 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        would_hit_hwbug = 0;
 
-       if (tg3_flag(tp, SHORT_DMA_BUG) && len <= 8)
-               would_hit_hwbug = 1;
-
-       if (tg3_4g_overflow_test(mapping, len))
-               would_hit_hwbug = 1;
-
-       if (tg3_40bit_overflow_test(tp, mapping, len))
-               would_hit_hwbug = 1;
-
        if (tg3_flag(tp, 5701_DMA_BUG))
                would_hit_hwbug = 1;
 
-       tg3_set_txd(tnapi, entry, mapping, len, base_flags,
-                   (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
-
-       entry = NEXT_TX(entry);
+       if (tg3_tx_frag_set(tnapi, &entry, &budget, mapping, len, base_flags |
+                         ((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0),
+                           mss, vlan))
+               would_hit_hwbug = 1;
 
        /* Now loop through additional data fragments, and queue them. */
        if (skb_shinfo(skb)->nr_frags > 0) {
+               u32 tmp_mss = mss;
+
+               if (!tg3_flag(tp, HW_TSO_1) &&
+                   !tg3_flag(tp, HW_TSO_2) &&
+                   !tg3_flag(tp, HW_TSO_3))
+                       tmp_mss = 0;
+
                last = skb_shinfo(skb)->nr_frags - 1;
                for (i = 0; i <= last; i++) {
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -6209,39 +6291,25 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        if (pci_dma_mapping_error(tp->pdev, mapping))
                                goto dma_error;
 
-                       if (tg3_flag(tp, SHORT_DMA_BUG) &&
-                           len <= 8)
+                       if (tg3_tx_frag_set(tnapi, &entry, &budget, mapping,
+                                           len, base_flags |
+                                           ((i == last) ? TXD_FLAG_END : 0),
+                                           tmp_mss, vlan))
                                would_hit_hwbug = 1;
-
-                       if (tg3_4g_overflow_test(mapping, len))
-                               would_hit_hwbug = 1;
-
-                       if (tg3_40bit_overflow_test(tp, mapping, len))
-                               would_hit_hwbug = 1;
-
-                       if (tg3_flag(tp, HW_TSO_1) ||
-                           tg3_flag(tp, HW_TSO_2) ||
-                           tg3_flag(tp, HW_TSO_3))
-                               tg3_set_txd(tnapi, entry, mapping, len,
-                                           base_flags, (i == last)|(mss << 1));
-                       else
-                               tg3_set_txd(tnapi, entry, mapping, len,
-                                           base_flags, (i == last));
-
-                       entry = NEXT_TX(entry);
                }
        }
 
        if (would_hit_hwbug) {
-               tg3_skb_error_unmap(tnapi, skb, i);
+               tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i);
 
                /* If the workaround fails due to memory/mapping
                 * failure, silently drop this packet.
                 */
-               if (tigon3_dma_hwbug_workaround(tnapi, skb, base_flags, mss))
+               entry = tnapi->tx_prod;
+               budget = tg3_tx_avail(tnapi);
+               if (tigon3_dma_hwbug_workaround(tnapi, skb, &entry, &budget,
+                                               base_flags, mss, vlan))
                        goto out_unlock;
-
-               entry = NEXT_TX(tnapi->tx_prod);
        }
 
        skb_tx_timestamp(skb);
@@ -6269,7 +6337,7 @@ out_unlock:
        return NETDEV_TX_OK;
 
 dma_error:
-       tg3_skb_error_unmap(tnapi, skb, i);
+       tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i);
        dev_kfree_skb(skb);
        tnapi->tx_buffers[tnapi->tx_prod].skb = NULL;
        return NETDEV_TX_OK;
@@ -6602,35 +6670,13 @@ static void tg3_free_rings(struct tg3 *tp)
                if (!tnapi->tx_buffers)
                        continue;
 
-               for (i = 0; i < TG3_TX_RING_SIZE; ) {
-                       struct ring_info *txp;
-                       struct sk_buff *skb;
-                       unsigned int k;
-
-                       txp = &tnapi->tx_buffers[i];
-                       skb = txp->skb;
+               for (i = 0; i < TG3_TX_RING_SIZE; i++) {
+                       struct sk_buff *skb = tnapi->tx_buffers[i].skb;
 
-                       if (skb == NULL) {
-                               i++;
+                       if (!skb)
                                continue;
-                       }
-
-                       pci_unmap_single(tp->pdev,
-                                        dma_unmap_addr(txp, mapping),
-                                        skb_headlen(skb),
-                                        PCI_DMA_TODEVICE);
-                       txp->skb = NULL;
 
-                       i++;
-
-                       for (k = 0; k < skb_shinfo(skb)->nr_frags; k++) {
-                               txp = &tnapi->tx_buffers[i & (TG3_TX_RING_SIZE - 1)];
-                               pci_unmap_page(tp->pdev,
-                                              dma_unmap_addr(txp, mapping),
-                                              skb_shinfo(skb)->frags[k].size,
-                                              PCI_DMA_TODEVICE);
-                               i++;
-                       }
+                       tg3_tx_skb_unmap(tnapi, i, skb_shinfo(skb)->nr_frags);
 
                        dev_kfree_skb_any(skb);
                }
@@ -6762,9 +6808,9 @@ static int tg3_alloc_consistent(struct tg3 *tp)
                 */
                if ((!i && !tg3_flag(tp, ENABLE_TSS)) ||
                    (i && tg3_flag(tp, ENABLE_TSS))) {
-                       tnapi->tx_buffers = kzalloc(sizeof(struct ring_info) *
-                                                   TG3_TX_RING_SIZE,
-                                                   GFP_KERNEL);
+                       tnapi->tx_buffers = kzalloc(
+                                              sizeof(struct tg3_tx_ring_info) *
+                                              TG3_TX_RING_SIZE, GFP_KERNEL);
                        if (!tnapi->tx_buffers)
                                goto err_out;
 
@@ -8360,7 +8406,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        /* Program the jumbo buffer descriptor ring control
         * blocks on those devices that have them.
         */
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+       if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 ||
            (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS))) {
 
                if (tg3_flag(tp, JUMBO_RING_ENABLE)) {
@@ -11204,6 +11250,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
 {
        u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key;
        u32 base_flags = 0, mss = 0, desc_idx, coal_now, data_off, val;
+       u32 budget;
        struct sk_buff *skb, *rx_skb;
        u8 *tx_data;
        dma_addr_t map;
@@ -11363,6 +11410,10 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
                return -EIO;
        }
 
+       val = tnapi->tx_prod;
+       tnapi->tx_buffers[val].skb = skb;
+       dma_unmap_addr_set(&tnapi->tx_buffers[val], mapping, map);
+
        tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
               rnapi->coal_now);
 
@@ -11370,8 +11421,13 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
 
        rx_start_idx = rnapi->hw_status->idx[0].rx_producer;
 
-       tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len,
-                   base_flags, (mss << 1) | 1);
+       budget = tg3_tx_avail(tnapi);
+       if (tg3_tx_frag_set(tnapi, &val, &budget, map, tx_len,
+                           base_flags | TXD_FLAG_END, mss, 0)) {
+               tnapi->tx_buffers[val].skb = NULL;
+               dev_kfree_skb(skb);
+               return -EIO;
+       }
 
        tnapi->tx_prod++;
 
@@ -11394,7 +11450,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
                        break;
        }
 
-       pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE);
+       tg3_tx_skb_unmap(tnapi, tnapi->tx_prod - 1, 0);
        dev_kfree_skb(skb);
 
        if (tx_idx != tnapi->tx_prod)
@@ -13817,7 +13873,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                tg3_flag_set(tp, 5705_PLUS);
 
        /* Determine TSO capabilities */
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+       if (tp->pci_chip_rev_id == CHIPREV_ID_5719_A0)
                ; /* Do nothing. HW bug. */
        else if (tg3_flag(tp, 57765_PLUS))
                tg3_flag_set(tp, HW_TSO_3);
@@ -13880,11 +13936,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        if (tg3_flag(tp, 5755_PLUS))
                tg3_flag_set(tp, SHORT_DMA_BUG);
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+               tg3_flag_set(tp, 4K_FIFO_LIMIT);
+
        if (tg3_flag(tp, 5717_PLUS))
                tg3_flag_set(tp, LRG_PROD_RING_CAP);
 
        if (tg3_flag(tp, 57765_PLUS) &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
+           tp->pci_chip_rev_id != CHIPREV_ID_5719_A0)
                tg3_flag_set(tp, USE_JUMBO_BDFLAG);
 
        if (!tg3_flag(tp, 5705_PLUS) ||
index 691539ba17b39fdeb94997e1c307c801d50a1d82..2ea456dd588082e4fc8a2fc845eb85e5d36b52d1 100644 (file)
@@ -2652,6 +2652,12 @@ struct ring_info {
        DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
+struct tg3_tx_ring_info {
+       struct sk_buff                  *skb;
+       DEFINE_DMA_UNMAP_ADDR(mapping);
+       bool                            fragmented;
+};
+
 struct tg3_link_config {
        /* Describes what we're trying to get. */
        u32                             advertising;
@@ -2816,7 +2822,7 @@ struct tg3_napi {
        u32                             last_tx_cons;
        u32                             prodmbox;
        struct tg3_tx_buffer_desc       *tx_ring;
-       struct ring_info                *tx_buffers;
+       struct tg3_tx_ring_info         *tx_buffers;
 
        dma_addr_t                      status_mapping;
        dma_addr_t                      rx_rcb_mapping;
@@ -2899,6 +2905,7 @@ enum TG3_FLAGS {
        TG3_FLAG_57765_PLUS,
        TG3_FLAG_APE_HAS_NCSI,
        TG3_FLAG_5717_PLUS,
+       TG3_FLAG_4K_FIFO_LIMIT,
 
        /* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */
        TG3_FLAG_NUMBER_OF_FLAGS,       /* Last entry in enum TG3_FLAGS */
index 9a6b3824da146bdc8943eaba02b0e48ec5dac74c..71f3d1a35b74ea4c0d1615bb5326e254a4475e63 100644 (file)
@@ -528,6 +528,7 @@ static void tun_net_init(struct net_device *dev)
                dev->netdev_ops = &tap_netdev_ops;
                /* Ethernet TAP Device */
                ether_setup(dev);
+               dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 
                random_ether_addr(dev->dev_addr);
 
index 52502883523ed99cab0d9ca9db455b344fe7728f..c5c4b4def7fbfdb1fe1de2a5f13c19968d55dd12 100644 (file)
@@ -314,12 +314,11 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        skb_pull(skb, 4);
 
        while (skb->len > 0) {
-               if ((short)(header & 0x0000ffff) !=
-                   ~((short)((header & 0xffff0000) >> 16))) {
+               if ((header & 0x07ff) != ((~header >> 16) & 0x07ff))
                        netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n");
-               }
+
                /* get the packet length */
-               size = (u16) (header & 0x0000ffff);
+               size = (u16) (header & 0x000007ff);
 
                if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
                        u8 alignment = (unsigned long)skb->data & 0x3;
index 7f78db7bd68db33e24a805bf4cfd3d995fe50011..5b23767ea817232a24b33a479f9b2014e895d1b6 100644 (file)
@@ -263,6 +263,8 @@ static void veth_setup(struct net_device *dev)
 {
        ether_setup(dev);
 
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+
        dev->netdev_ops = &veth_netdev_ops;
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
index b25c9229a6a94646d4c6fccd4a7a3faff694b13e..eb2028187fbe1a5e7de31f862bd908d45fcd82e8 100644 (file)
@@ -1074,9 +1074,10 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
 
        used = pvc_is_used(pvc);
 
-       if (type == ARPHRD_ETHER)
+       if (type == ARPHRD_ETHER) {
                dev = alloc_netdev(0, "pvceth%d", ether_setup);
-       else
+               dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+       } else
                dev = alloc_netdev(0, "pvc%d", pvc_setup);
 
        if (!dev) {
index 55cf71fbffe32125d9bdbbbe429b98ed0acea35e..e1b3e3c134fdfaeccbd2f575734fa9754b9660e6 100644 (file)
@@ -2823,6 +2823,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
        dev->wireless_data = &ai->wireless_data;
        dev->irq = irq;
        dev->base_addr = port;
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 
        SET_NETDEV_DEV(dev, dmdev);
 
index d2293dcc117ff93f652caf576b01ebf2e4291a90..3cab843afb0503f1062a41107290ca735d3e35b8 100644 (file)
@@ -28,7 +28,7 @@ config B43
 
 config B43_BCMA
        bool "Support for BCMA bus"
-       depends on B43 && BCMA && BROKEN
+       depends on B43 && BCMA
        default y
 
 config B43_SSB
index 64c3f65ff8c0849e4469bd364f36b26c72f0970f..05f6c7bff6ab683836c9614bbe4797e5fdd2d2ad 100644 (file)
@@ -244,10 +244,12 @@ void b43_bus_set_wldev(struct b43_bus_dev *dev, void *wldev)
 #ifdef CONFIG_B43_BCMA
        case B43_BUS_BCMA:
                bcma_set_drvdata(dev->bdev, wldev);
+               break;
 #endif
 #ifdef CONFIG_B43_SSB
        case B43_BUS_SSB:
                ssb_set_drvdata(dev->sdev, wldev);
+               break;
 #endif
        }
 }
index 032d46674f6bb278441e897ddd6581f33736e6e5..26f1ab840cc7b60c162c43d67b567de2d9b76f06 100644 (file)
@@ -5350,6 +5350,7 @@ static void b43_ssb_remove(struct ssb_device *sdev)
 {
        struct b43_wl *wl = ssb_get_devtypedata(sdev);
        struct b43_wldev *wldev = ssb_get_drvdata(sdev);
+       struct b43_bus_dev *dev = wldev->dev;
 
        /* We must cancel any work here before unregistering from ieee80211,
         * as the ieee80211 unreg will destroy the workqueue. */
@@ -5365,14 +5366,14 @@ static void b43_ssb_remove(struct ssb_device *sdev)
                ieee80211_unregister_hw(wl->hw);
        }
 
-       b43_one_core_detach(wldev->dev);
+       b43_one_core_detach(dev);
 
        if (list_empty(&wl->devlist)) {
                b43_leds_unregister(wl);
                /* Last core on the chip unregistered.
                 * We can destroy common struct b43_wl.
                 */
-               b43_wireless_exit(wldev->dev, wl);
+               b43_wireless_exit(dev, wl);
        }
 }
 
index c052a0d5cbdd909b68d0641aaed990065d1ea981..5441ad1951196ac9f791ae4c9e0ad57886c05e79 100644 (file)
@@ -648,6 +648,8 @@ static const struct pcmcia_device_id hostap_cs_ids[] = {
                                         0x74c5e40d),
        PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
                                         0x4b801a17),
+       PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.02",
+                                        0x4b74baa0),
        PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
                                    0x7a954bd9, 0x74be00c6),
        PCMCIA_DEVICE_PROD_ID123(
index d5084829c9e5426946ce6554e712d40796fa2695..89a116fba1de24f81d4fd3b25f7d5ad6e059c27a 100644 (file)
@@ -855,6 +855,7 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local,
 
        iface = netdev_priv(dev);
        ether_setup(dev);
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 
        /* kernel callbacks */
        if (iface) {
index 3f7fc4a0b43d4c961ce489ada47763721c6666fa..d7dbc00bcfbe81edb63608820ec12f75677a7bd8 100644 (file)
@@ -239,7 +239,6 @@ static int orinoco_cs_resume(struct pcmcia_device *link)
 
 static const struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
-       PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */
        PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
        PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */
        PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */
@@ -272,6 +271,7 @@ static const struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
        PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
        PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
+       PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.01", 0xd27deb1a), /* Lucent Orinoco */
 #ifdef CONFIG_HERMES_PRISM
        /* Only entries that certainly identify Prism chipset */
        PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */
@@ -321,6 +321,9 @@ static const struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
        PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
        PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
+
+       /* This may be Agere or Intersil Firmware */
+       PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
 #endif
        PCMCIA_DEVICE_NULL,
 };
index 03723154071925ef9f75127b62118b4949770023..c77e0543e5021be8d1b8696f5572d537bb654882 100644 (file)
@@ -1596,7 +1596,7 @@ static void pn533_disconnect(struct usb_interface *interface)
        usb_free_urb(dev->out_urb);
        kfree(dev);
 
-       nfc_dev_info(&dev->interface->dev, "NXP PN533 NFC device disconnected");
+       nfc_dev_info(&interface->dev, "NXP PN533 NFC device disconnected");
 }
 
 static struct usb_driver pn533_driver = {
index 3007662ac6146d971ec52aa8eb7b9e1f1f6a8ffa..ef0105fa52b14d1280e3fb746387d713cb0d7933 100644 (file)
@@ -127,8 +127,8 @@ EXPORT_SYMBOL(of_gpio_count);
  * gpio chips. This function performs only one sanity check: whether gpio
  * is less than ngpios (that is specified in the gpio_chip).
  */
-static int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
-                               const void *gpio_spec, u32 *flags)
+int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
+                        const void *gpio_spec, u32 *flags)
 {
        const __be32 *gpio = gpio_spec;
        const u32 n = be32_to_cpup(gpio);
@@ -152,6 +152,7 @@ static int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
 
        return n;
 }
+EXPORT_SYMBOL(of_gpio_simple_xlate);
 
 /**
  * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank)
index 86f334a2769c751e1fb0aa07c4a65de65d63ad29..bb184717588fe019e7bf039bfb73e651c5960ec6 100644 (file)
@@ -8,6 +8,51 @@
 #include <linux/etherdevice.h>
 #include <linux/kernel.h>
 #include <linux/of_net.h>
+#include <linux/phy.h>
+
+/**
+ * It maps 'enum phy_interface_t' found in include/linux/phy.h
+ * into the device tree binding of 'phy-mode', so that Ethernet
+ * device driver can get phy interface from device tree.
+ */
+static const char *phy_modes[] = {
+       [PHY_INTERFACE_MODE_NA]         = "",
+       [PHY_INTERFACE_MODE_MII]        = "mii",
+       [PHY_INTERFACE_MODE_GMII]       = "gmii",
+       [PHY_INTERFACE_MODE_SGMII]      = "sgmii",
+       [PHY_INTERFACE_MODE_TBI]        = "tbi",
+       [PHY_INTERFACE_MODE_RMII]       = "rmii",
+       [PHY_INTERFACE_MODE_RGMII]      = "rgmii",
+       [PHY_INTERFACE_MODE_RGMII_ID]   = "rgmii-id",
+       [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
+       [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
+       [PHY_INTERFACE_MODE_RTBI]       = "rtbi",
+       [PHY_INTERFACE_MODE_SMII]       = "smii",
+};
+
+/**
+ * of_get_phy_mode - Get phy mode for given device_node
+ * @np:        Pointer to the given device_node
+ *
+ * The function gets phy interface string from property 'phy-mode',
+ * and return its index in phy_modes table, or errno in error case.
+ */
+const int of_get_phy_mode(struct device_node *np)
+{
+       const char *pm;
+       int err, i;
+
+       err = of_property_read_string(np, "phy-mode", &pm);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
+               if (!strcasecmp(pm, phy_modes[i]))
+                       return i;
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_get_phy_mode);
 
 /**
  * Search the device tree for the best MAC address to use.  'mac-address' is
index 8f3faf343f754c83322bc4efecc803ef01ed2b03..095f29e13734ad8e830e2614a42b7dc6c5d4a2b8 100644 (file)
@@ -408,7 +408,7 @@ got_one:
 }
 EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware);
 
-static int is_ejectable(acpi_handle handle)
+static int pcihp_is_ejectable(acpi_handle handle)
 {
        acpi_status status;
        acpi_handle tmp;
@@ -442,7 +442,7 @@ int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle)
                return 0;
        if (bridge_handle != parent_handle)
                return 0;
-       return is_ejectable(handle);
+       return pcihp_is_ejectable(handle);
 }
 EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable);
 
@@ -450,7 +450,7 @@ static acpi_status
 check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        int *found = (int *)context;
-       if (is_ejectable(handle)) {
+       if (pcihp_is_ejectable(handle)) {
                *found = 1;
                return AE_CTRL_TERMINATE;
        }
index 4952c3b9379dcddcbb8f2c7b1f340009f0cba15c..f1ce99cceac60a2135cf8292da0013eebeadb2a1 100644 (file)
@@ -840,8 +840,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Need to read VID early b/c it's used to differentiate CPQ and INTC
         * discovery
         */
-       rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id);
-       if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) {
+       vendor_id = pdev->vendor;
+       if ((vendor_id != PCI_VENDOR_ID_COMPAQ) &&
+           (vendor_id != PCI_VENDOR_ID_INTEL)) {
                err(msg_HPC_non_compaq_or_intel);
                rc = -ENODEV;
                goto err_disable_device;
@@ -868,11 +869,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* TODO: This code can be made to support non-Compaq or Intel
         * subsystem IDs
         */
-       rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid);
-       if (rc) {
-               err("%s : pci_read_config_word failed\n", __func__);
-               goto err_disable_device;
-       }
+       subsystem_vid = pdev->subsystem_vendor;
        dbg("Subsystem Vendor ID: %x\n", subsystem_vid);
        if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) {
                err(msg_HPC_non_compaq_or_intel);
@@ -887,11 +884,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_disable_device;
        }
 
-       rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid);
-       if (rc) {
-               err("%s : pci_read_config_word failed\n", __func__);
-               goto err_free_ctrl;
-       }
+       subsystem_deviceid = pdev->subsystem_device;
 
        info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid);
 
index 085dbb5fc168be33de77d0ced5c411c807ffc2ef..1e9c9aacc3a6c82363b39602c5f6bab1b4bbd30d 100644 (file)
@@ -213,6 +213,9 @@ static int board_added(struct slot *p_slot)
                goto err_exit;
        }
 
+       /* Wait for 1 second after checking link training status */
+       msleep(1000);
+
        /* Check for a power fault */
        if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {
                ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
index 50a23da5d24dc5ea248e34c73c6f13855f538983..96dc4734e4affcc6c7f763a9853342678df8a7c6 100644 (file)
@@ -275,16 +275,9 @@ int pciehp_check_link_status(struct controller *ctrl)
          * hot-plug capable downstream port. But old controller might
          * not implement it. In this case, we wait for 1000 ms.
          */
-        if (ctrl->link_active_reporting){
-                /* Wait for Data Link Layer Link Active bit to be set */
+        if (ctrl->link_active_reporting)
                 pcie_wait_link_active(ctrl);
-                /*
-                 * We must wait for 100 ms after the Data Link Layer
-                 * Link Active bit reads 1b before initiating a
-                 * configuration access to the hot added device.
-                 */
-                msleep(100);
-        } else
+        else
                 msleep(1000);
 
        retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
index 692671b11667381516b9d95101e26415c10e35fc..08a95b369d850c54292c66e45f67dfd197c860ef 100644 (file)
@@ -1905,7 +1905,7 @@ void pci_enable_ari(struct pci_dev *dev)
 {
        int pos;
        u32 cap;
-       u16 ctrl;
+       u16 flags, ctrl;
        struct pci_dev *bridge;
 
        if (!pci_is_pcie(dev) || dev->devfn)
@@ -1923,6 +1923,11 @@ void pci_enable_ari(struct pci_dev *dev)
        if (!pos)
                return;
 
+       /* ARI is a PCIe v2 feature */
+       pci_read_config_word(bridge, pos + PCI_EXP_FLAGS, &flags);
+       if ((flags & PCI_EXP_FLAGS_VERS) < 2)
+               return;
+
        pci_read_config_dword(bridge, pos + PCI_EXP_DEVCAP2, &cap);
        if (!(cap & PCI_EXP_DEVCAP2_ARI))
                return;
@@ -3186,7 +3191,7 @@ EXPORT_SYMBOL(pcie_get_readrq);
  * @rq: maximum memory read count in bytes
  *    valid values are 128, 256, 512, 1024, 2048, 4096
  *
- * If possible sets maximum read byte count
+ * If possible sets maximum memory read request in bytes
  */
 int pcie_set_readrq(struct pci_dev *dev, int rq)
 {
@@ -3209,7 +3214,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
        if ((ctl & PCI_EXP_DEVCTL_READRQ) != v) {
                ctl &= ~PCI_EXP_DEVCTL_READRQ;
                ctl |= v;
-               err = pci_write_config_dword(dev, cap + PCI_EXP_DEVCTL, ctl);
+               err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl);
        }
 
 out:
index 43421fbe080a01c3c962844942c0018c50881158..9674e9f30d492671b94250e52dde1825eb1e3f5b 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/suspend.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/kfifo.h>
 #include "aerdrv.h"
 
 static int forceload;
@@ -445,8 +446,7 @@ static struct pcie_port_service_driver *find_aer_service(struct pci_dev *dev)
        return drv;
 }
 
-static pci_ers_result_t reset_link(struct pcie_device *aerdev,
-               struct pci_dev *dev)
+static pci_ers_result_t reset_link(struct pci_dev *dev)
 {
        struct pci_dev *udev;
        pci_ers_result_t status;
@@ -486,7 +486,6 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev,
 
 /**
  * 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
  *
@@ -494,8 +493,7 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev,
  * error detected message to all downstream drivers within a hierarchy in
  * question and return the returned code.
  */
-static void do_recovery(struct pcie_device *aerdev, struct pci_dev *dev,
-               int severity)
+static void do_recovery(struct pci_dev *dev, int severity)
 {
        pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;
        enum pci_channel_state state;
@@ -511,7 +509,7 @@ static void do_recovery(struct pcie_device *aerdev, struct pci_dev *dev,
                        report_error_detected);
 
        if (severity == AER_FATAL) {
-               result = reset_link(aerdev, dev);
+               result = reset_link(dev);
                if (result != PCI_ERS_RESULT_RECOVERED)
                        goto failed;
        }
@@ -576,9 +574,73 @@ static void handle_error_source(struct pcie_device *aerdev,
                        pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
                                        info->status);
        } else
-               do_recovery(aerdev, dev, info->severity);
+               do_recovery(dev, info->severity);
 }
 
+#ifdef CONFIG_ACPI_APEI_PCIEAER
+static void aer_recover_work_func(struct work_struct *work);
+
+#define AER_RECOVER_RING_ORDER         4
+#define AER_RECOVER_RING_SIZE          (1 << AER_RECOVER_RING_ORDER)
+
+struct aer_recover_entry
+{
+       u8      bus;
+       u8      devfn;
+       u16     domain;
+       int     severity;
+};
+
+static DEFINE_KFIFO(aer_recover_ring, struct aer_recover_entry,
+                   AER_RECOVER_RING_SIZE);
+/*
+ * Mutual exclusion for writers of aer_recover_ring, reader side don't
+ * need lock, because there is only one reader and lock is not needed
+ * between reader and writer.
+ */
+static DEFINE_SPINLOCK(aer_recover_ring_lock);
+static DECLARE_WORK(aer_recover_work, aer_recover_work_func);
+
+void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
+                      int severity)
+{
+       unsigned long flags;
+       struct aer_recover_entry entry = {
+               .bus            = bus,
+               .devfn          = devfn,
+               .domain         = domain,
+               .severity       = severity,
+       };
+
+       spin_lock_irqsave(&aer_recover_ring_lock, flags);
+       if (kfifo_put(&aer_recover_ring, &entry))
+               schedule_work(&aer_recover_work);
+       else
+               pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n",
+                      domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+       spin_unlock_irqrestore(&aer_recover_ring_lock, flags);
+}
+EXPORT_SYMBOL_GPL(aer_recover_queue);
+
+static void aer_recover_work_func(struct work_struct *work)
+{
+       struct aer_recover_entry entry;
+       struct pci_dev *pdev;
+
+       while (kfifo_get(&aer_recover_ring, &entry)) {
+               pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus,
+                                                  entry.devfn);
+               if (!pdev) {
+                       pr_err("AER recover: Can not find pci_dev for %04x:%02x:%02x:%x\n",
+                              entry.domain, entry.bus,
+                              PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn));
+                       continue;
+               }
+               do_recovery(pdev, entry.severity);
+       }
+}
+#endif
+
 /**
  * get_device_error_info - read error status from dev and store it to info
  * @dev: pointer to the device expected to have a error record
index b07a42e0b350f9c84207df510272ef6926430a70..3ea51736f18db45be7c40280626eb0d803c157b1 100644 (file)
@@ -204,7 +204,7 @@ void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
 }
 
 #ifdef CONFIG_ACPI_APEI_PCIEAER
-static int cper_severity_to_aer(int cper_severity)
+int cper_severity_to_aer(int cper_severity)
 {
        switch (cper_severity) {
        case CPER_SEV_RECOVERABLE:
@@ -215,6 +215,7 @@ static int cper_severity_to_aer(int cper_severity)
                return AER_CORRECTABLE;
        }
 }
+EXPORT_SYMBOL_GPL(cper_severity_to_aer);
 
 void cper_print_aer(const char *prefix, int cper_severity,
                    struct aer_capability_regs *aer)
index 9ab492f21f862ce73a1b994e1d1c259e73d6998f..795c9026d55fccfa512d9c2393973947af05dab9 100644 (file)
@@ -68,21 +68,6 @@ static int __init pcibus_class_init(void)
 }
 postcore_initcall(pcibus_class_init);
 
-/*
- * Translate the low bits of the PCI base
- * to the resource type
- */
-static inline unsigned int pci_calc_resource_flags(unsigned int flags)
-{
-       if (flags & PCI_BASE_ADDRESS_SPACE_IO)
-               return IORESOURCE_IO;
-
-       if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
-               return IORESOURCE_MEM | IORESOURCE_PREFETCH;
-
-       return IORESOURCE_MEM;
-}
-
 static u64 pci_size(u64 base, u64 maxbase, u64 mask)
 {
        u64 size = mask & maxbase;      /* Find the significant bits */
@@ -101,18 +86,39 @@ static u64 pci_size(u64 base, u64 maxbase, u64 mask)
        return size;
 }
 
-static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar)
+static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar)
 {
+       u32 mem_type;
+       unsigned long flags;
+
        if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
-               res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK;
-               return pci_bar_io;
+               flags = bar & ~PCI_BASE_ADDRESS_IO_MASK;
+               flags |= IORESOURCE_IO;
+               return flags;
        }
 
-       res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK;
+       flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK;
+       flags |= IORESOURCE_MEM;
+       if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
+               flags |= IORESOURCE_PREFETCH;
 
-       if (res->flags & PCI_BASE_ADDRESS_MEM_TYPE_64)
-               return pci_bar_mem64;
-       return pci_bar_mem32;
+       mem_type = bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+       switch (mem_type) {
+       case PCI_BASE_ADDRESS_MEM_TYPE_32:
+               break;
+       case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+               dev_info(&dev->dev, "1M mem BAR treated as 32-bit BAR\n");
+               break;
+       case PCI_BASE_ADDRESS_MEM_TYPE_64:
+               flags |= IORESOURCE_MEM_64;
+               break;
+       default:
+               dev_warn(&dev->dev,
+                        "mem unknown type %x treated as 32-bit BAR\n",
+                        mem_type);
+               break;
+       }
+       return flags;
 }
 
 /**
@@ -165,9 +171,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                l = 0;
 
        if (type == pci_bar_unknown) {
-               type = decode_bar(res, l);
-               res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
-               if (type == pci_bar_io) {
+               res->flags = decode_bar(dev, l);
+               res->flags |= IORESOURCE_SIZEALIGN;
+               if (res->flags & IORESOURCE_IO) {
                        l &= PCI_BASE_ADDRESS_IO_MASK;
                        mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT;
                } else {
@@ -180,7 +186,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                mask = (u32)PCI_ROM_ADDRESS_MASK;
        }
 
-       if (type == pci_bar_mem64) {
+       if (res->flags & IORESOURCE_MEM_64) {
                u64 l64 = l;
                u64 sz64 = sz;
                u64 mask64 = mask | (u64)~0 << 32;
@@ -204,7 +210,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
                        goto fail;
                }
 
-               res->flags |= IORESOURCE_MEM_64;
                if ((sizeof(resource_size_t) < 8) && l) {
                        /* Address above 32-bit boundary; disable the BAR */
                        pci_write_config_dword(dev, pos, 0);
@@ -230,7 +235,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
        }
 
  out:
-       return (type == pci_bar_mem64) ? 1 : 0;
+       return (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
  fail:
        res->flags = 0;
        goto out;
@@ -284,10 +289,6 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
                if (!res->end)
                        res->end = limit + 0xfff;
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
-       } else {
-               dev_printk(KERN_DEBUG, &dev->dev,
-                        "  bridge window [io  %#06lx-%#06lx] (disabled)\n",
-                                base, limit);
        }
 }
 
@@ -308,10 +309,6 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
                res->start = base;
                res->end = limit + 0xfffff;
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
-       } else {
-               dev_printk(KERN_DEBUG, &dev->dev,
-                       "  bridge window [mem %#010lx-%#010lx] (disabled)\n",
-                                        base, limit + 0xfffff);
        }
 }
 
@@ -359,10 +356,6 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
                res->start = base;
                res->end = limit + 0xfffff;
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
-       } else {
-               dev_printk(KERN_DEBUG, &dev->dev,
-                    "  bridge window [mem %#010lx-%#010lx pref] (disabled)\n",
-                                        base, limit + 0xfffff);
        }
 }
 
@@ -725,12 +718,14 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
                pci_write_config_word(dev, PCI_STATUS, 0xffff);
 
                /* Prevent assigning a bus number that already exists.
-                * This can happen when a bridge is hot-plugged */
-               if (pci_find_bus(pci_domain_nr(bus), max+1))
-                       goto out;
-               child = pci_add_new_bus(bus, dev, ++max);
-               if (!child)
-                       goto out;
+                * This can happen when a bridge is hot-plugged, so in
+                * this case we only re-scan this bus. */
+               child = pci_find_bus(pci_domain_nr(bus), max+1);
+               if (!child) {
+                       child = pci_add_new_bus(bus, dev, ++max);
+                       if (!child)
+                               goto out;
+               }
                buses = (buses & 0xff000000)
                      | ((unsigned int)(child->primary)     <<  0)
                      | ((unsigned int)(child->secondary)   <<  8)
index 9995842e45b5cb75fcc296bb668df3638ded8088..8a1d3c7863a89d5514f18357e8a5b6726452335e 100644 (file)
@@ -336,7 +336,6 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
                /* Clear upper 16 bits of I/O base/limit. */
                io_upper16 = 0;
                l = 0x00f0;
-               dev_info(&bridge->dev, "  bridge window [io  disabled]\n");
        }
        /* Temporarily disable the I/O range before updating PCI_IO_BASE. */
        pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
@@ -362,7 +361,6 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus)
                dev_info(&bridge->dev, "  bridge window %pR\n", res);
        } else {
                l = 0x0000fff0;
-               dev_info(&bridge->dev, "  bridge window [mem disabled]\n");
        }
        pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
 }
@@ -393,7 +391,6 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)
                dev_info(&bridge->dev, "  bridge window %pR\n", res);
        } else {
                l = 0x0000fff0;
-               dev_info(&bridge->dev, "  bridge window [mem pref disabled]\n");
        }
        pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
 
index eec9738f34927c7a3b87c6f9d647a5c3b1207877..eb219a1d16f760f4596dded6e9811b006946586d 100644 (file)
@@ -21,7 +21,7 @@
 static void __init
 pdev_fixup_irq(struct pci_dev *dev,
               u8 (*swizzle)(struct pci_dev *, u8 *),
-              int (*map_irq)(struct pci_dev *, u8, u8))
+              int (*map_irq)(const struct pci_dev *, u8, u8))
 {
        u8 pin, slot;
        int irq = 0;
@@ -56,7 +56,7 @@ pdev_fixup_irq(struct pci_dev *dev,
 
 void __init
 pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
-              int (*map_irq)(struct pci_dev *, u8, u8))
+              int (*map_irq)(const struct pci_dev *, u8, u8))
 {
        struct pci_dev *dev = NULL;
        for_each_pci_dev(dev)
index bc0e6eea0fff61be65de11e8827a44c4ee2cafc8..319f359906e8198628e3d8a7ce60447dd82c3c0f 100644 (file)
@@ -74,8 +74,7 @@ void pci_update_resource(struct pci_dev *dev, int resno)
                        resno, new, check);
        }
 
-       if ((new & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
-           (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+       if (res->flags & IORESOURCE_MEM_64) {
                new = region.start >> 16 >> 16;
                pci_write_config_dword(dev, reg + 4, new);
                pci_read_config_dword(dev, reg + 4, &check);
index 4c3e94c0ae85336a9fcee6511d570e1ab4b058e5..f56d7de7c7514e2fd7cc9d9b0d04cbaf31effab7 100644 (file)
@@ -103,22 +103,12 @@ static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void balloon3_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void balloon3_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level balloon3_pcmcia_ops = {
        .owner                  = THIS_MODULE,
        .hw_init                = balloon3_pcmcia_hw_init,
        .hw_shutdown            = balloon3_pcmcia_hw_shutdown,
        .socket_state           = balloon3_pcmcia_socket_state,
        .configure_socket       = balloon3_pcmcia_configure_socket,
-       .socket_init            = balloon3_pcmcia_socket_init,
-       .socket_suspend         = balloon3_pcmcia_socket_suspend,
        .first                  = 0,
        .nr                     = 1,
 };
index 05913d0bbdbef64b513ab89f1c7fe448c6002248..63f4d5211ed2b9bf31650840195010bb10dc3889 100644 (file)
@@ -102,23 +102,12 @@ static int cmx255_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void cmx255_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void cmx255_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
-
 static struct pcmcia_low_level cmx255_pcmcia_ops __initdata = {
        .owner                  = THIS_MODULE,
        .hw_init                = cmx255_pcmcia_hw_init,
        .hw_shutdown            = cmx255_pcmcia_shutdown,
        .socket_state           = cmx255_pcmcia_socket_state,
        .configure_socket       = cmx255_pcmcia_configure_socket,
-       .socket_init            = cmx255_pcmcia_socket_init,
-       .socket_suspend         = cmx255_pcmcia_socket_suspend,
        .nr                     = 1,
 };
 
index 5662646b84da9bdb8eda5666f7251b3a3de4faec..6ee42b4c3e68b902248b4a2416c6d0add4fcb7f3 100644 (file)
@@ -82,23 +82,12 @@ static int cmx270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void cmx270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void cmx270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
-
 static struct pcmcia_low_level cmx270_pcmcia_ops __initdata = {
        .owner                  = THIS_MODULE,
        .hw_init                = cmx270_pcmcia_hw_init,
        .hw_shutdown            = cmx270_pcmcia_shutdown,
        .socket_state           = cmx270_pcmcia_socket_state,
        .configure_socket       = cmx270_pcmcia_configure_socket,
-       .socket_init            = cmx270_pcmcia_socket_init,
-       .socket_suspend         = cmx270_pcmcia_socket_suspend,
        .nr                     = 1,
 };
 
index 443cb7fc872d7c1e03b60254caf623e372f05ce7..c6dec572a05da6593bac0bce1777042393f66e03 100644 (file)
@@ -116,14 +116,6 @@ colibri_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void colibri_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void colibri_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level colibri_pcmcia_ops = {
        .owner                  = THIS_MODULE,
 
@@ -135,9 +127,6 @@ static struct pcmcia_low_level colibri_pcmcia_ops = {
 
        .socket_state           = colibri_pcmcia_socket_state,
        .configure_socket       = colibri_pcmcia_configure_socket,
-
-       .socket_init            = colibri_pcmcia_socket_init,
-       .socket_suspend         = colibri_pcmcia_socket_suspend,
 };
 
 static struct platform_device *colibri_pcmcia_device;
index 92016fe932b46bfd720b6ecfc56fca26a6add563..aded706c0b9fa941a98a94ff84a3881f38a1da42 100644 (file)
@@ -128,22 +128,12 @@ static int mst_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return ret;
 }
 
-static void mst_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void mst_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level mst_pcmcia_ops __initdata = {
        .owner                  = THIS_MODULE,
        .hw_init                = mst_pcmcia_hw_init,
        .hw_shutdown            = mst_pcmcia_hw_shutdown,
        .socket_state           = mst_pcmcia_socket_state,
        .configure_socket       = mst_pcmcia_configure_socket,
-       .socket_init            = mst_pcmcia_socket_init,
-       .socket_suspend         = mst_pcmcia_socket_suspend,
        .nr                     = 2,
 };
 
index 69f73670949a2163b75eeaebe487947e65c01fac..d589ad1dcd4c7f9f15552c889eec5e187687d8d5 100644 (file)
@@ -65,14 +65,6 @@ static int palmld_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void palmld_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void palmld_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level palmld_pcmcia_ops = {
        .owner                  = THIS_MODULE,
 
@@ -84,9 +76,6 @@ static struct pcmcia_low_level palmld_pcmcia_ops = {
 
        .socket_state           = palmld_pcmcia_socket_state,
        .configure_socket       = palmld_pcmcia_configure_socket,
-
-       .socket_init            = palmld_pcmcia_socket_init,
-       .socket_suspend         = palmld_pcmcia_socket_suspend,
 };
 
 static struct platform_device *palmld_pcmcia_device;
index d0ad6a76bbde26812f764c4b8f8cd73cf7c9ba79..9c6a04b2f71b378549ef85b74b7d3bd7c89fd22b 100644 (file)
@@ -117,14 +117,6 @@ static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return ret;
 }
 
-static void palmtc_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void palmtc_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level palmtc_pcmcia_ops = {
        .owner                  = THIS_MODULE,
 
@@ -136,9 +128,6 @@ static struct pcmcia_low_level palmtc_pcmcia_ops = {
 
        .socket_state           = palmtc_pcmcia_socket_state,
        .configure_socket       = palmtc_pcmcia_configure_socket,
-
-       .socket_init            = palmtc_pcmcia_socket_init,
-       .socket_suspend         = palmtc_pcmcia_socket_suspend,
 };
 
 static struct platform_device *palmtc_pcmcia_device;
index 1a2580450402f49f6f4e338316f9589ef82edf40..80645a688ee3cf7b2fc3ddc1e55ddda02058e842 100644 (file)
@@ -67,14 +67,6 @@ palmtx_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void palmtx_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void palmtx_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level palmtx_pcmcia_ops = {
        .owner                  = THIS_MODULE,
 
@@ -86,9 +78,6 @@ static struct pcmcia_low_level palmtx_pcmcia_ops = {
 
        .socket_state           = palmtx_pcmcia_socket_state,
        .configure_socket       = palmtx_pcmcia_configure_socket,
-
-       .socket_init            = palmtx_pcmcia_socket_init,
-       .socket_suspend         = palmtx_pcmcia_socket_suspend,
 };
 
 static struct platform_device *palmtx_pcmcia_device;
index d08802fe35f9a993cdd50cec2410543d83aa29ad..939622251dfb5e7d17b03988110b33d093e06039 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "soc_common.h"
 
-#define SG2_S0_BUFF_CTL                120
 #define SG2_S0_POWER_CTL       108
 #define SG2_S0_GPIO_RESET      82
 #define SG2_S0_GPIO_DETECT     53
@@ -38,6 +37,11 @@ static struct pcmcia_irqs irqs[] = {
        { 0, IRQ_GPIO(SG2_S0_GPIO_DETECT), "PCMCIA0 CD" },
 };
 
+static struct gpio sg2_pcmcia_gpios[] = {
+       { SG2_S0_GPIO_RESET, GPIOF_OUT_INIT_HIGH, "PCMCIA Reset" },
+       { SG2_S0_POWER_CTL, GPIOF_OUT_INIT_HIGH, "PCMCIA Power Ctrl" },
+};
+
 static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 {
        skt->socket.pci_irq = IRQ_GPIO(SG2_S0_GPIO_READY);
@@ -122,37 +126,23 @@ static int __init sg2_pcmcia_init(void)
        if (!sg2_pcmcia_device)
                return -ENOMEM;
 
-       ret = gpio_request(SG2_S0_BUFF_CTL, "SG2 CF buff ctl");
+       ret = gpio_request_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
        if (ret)
                goto error_put_platform_device;
-       ret = gpio_request(SG2_S0_POWER_CTL, "SG2 CF power ctl");
-       if (ret)
-               goto error_free_gpio_buff_ctl;
-       ret = gpio_request(SG2_S0_GPIO_RESET, "SG2 CF reset");
-       if (ret)
-               goto error_free_gpio_power_ctl;
-       /* Set gpio directions */
-       gpio_direction_output(SG2_S0_BUFF_CTL, 0);
-       gpio_direction_output(SG2_S0_POWER_CTL, 1);
-       gpio_direction_output(SG2_S0_GPIO_RESET, 1);
 
        ret = platform_device_add_data(sg2_pcmcia_device,
                                       &sg2_pcmcia_ops,
                                       sizeof(sg2_pcmcia_ops));
        if (ret)
-               goto error_free_gpio_reset;
+               goto error_free_gpios;
 
        ret = platform_device_add(sg2_pcmcia_device);
        if (ret)
-               goto error_free_gpio_reset;
+               goto error_free_gpios;
 
        return 0;
-error_free_gpio_reset:
-       gpio_free(SG2_S0_GPIO_RESET);
-error_free_gpio_power_ctl:
-       gpio_free(SG2_S0_POWER_CTL);
-error_free_gpio_buff_ctl:
-       gpio_free(SG2_S0_BUFF_CTL);
+error_free_gpios:
+       gpio_free_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
 error_put_platform_device:
        platform_device_put(sg2_pcmcia_device);
 
@@ -162,9 +152,7 @@ error_put_platform_device:
 static void __exit sg2_pcmcia_exit(void)
 {
        platform_device_unregister(sg2_pcmcia_device);
-       gpio_free(SG2_S0_BUFF_CTL);
-       gpio_free(SG2_S0_POWER_CTL);
-       gpio_free(SG2_S0_GPIO_RESET);
+       gpio_free_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
 }
 
 fs_initcall(sg2_pcmcia_init);
index a51f2077644a5f80cdb4e9688947e046ce42a0e7..1064b1c2869d002634b92dfbd7ffa5709825b8bc 100644 (file)
@@ -136,22 +136,12 @@ static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
        return 0;
 }
 
-static void viper_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
-{
-}
-
-static void viper_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
-{
-}
-
 static struct pcmcia_low_level viper_pcmcia_ops = {
        .owner                  = THIS_MODULE,
        .hw_init                = viper_pcmcia_hw_init,
        .hw_shutdown            = viper_pcmcia_hw_shutdown,
        .socket_state           = viper_pcmcia_socket_state,
        .configure_socket       = viper_pcmcia_configure_socket,
-       .socket_init            = viper_pcmcia_socket_init,
-       .socket_suspend         = viper_pcmcia_socket_suspend,
        .nr                     = 1,
 };
 
index 768f9572a8c88cca0c91bf8a977060b638ceae6f..a0a9c2aa8d78a5a02aae23065b6e2a51ccec7621 100644 (file)
@@ -186,8 +186,8 @@ static int soc_common_pcmcia_sock_init(struct pcmcia_socket *sock)
        struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock);
 
        debug(skt, 2, "initializing socket\n");
-
-       skt->ops->socket_init(skt);
+       if (skt->ops->socket_init)
+               skt->ops->socket_init(skt);
        return 0;
 }
 
@@ -207,7 +207,8 @@ static int soc_common_pcmcia_suspend(struct pcmcia_socket *sock)
 
        debug(skt, 2, "suspending socket\n");
 
-       skt->ops->socket_suspend(skt);
+       if (skt->ops->socket_suspend)
+               skt->ops->socket_suspend(skt);
 
        return 0;
 }
index e57b50b385655d24eb5aeb94866a68cef42813e2..57de051a74b340bfb11da61e787fc1944321aad1 100644 (file)
@@ -235,4 +235,18 @@ config CHARGER_GPIO
          This driver can be build as a module. If so, the module will be
          called gpio-charger.
 
+config CHARGER_MAX8997
+       tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
+       depends on MFD_MAX8997 && REGULATOR_MAX8997
+       help
+         Say Y to enable support for the battery charger control sysfs and
+         platform data of MAX8997/LP3974 PMICs.
+
+config CHARGER_MAX8998
+       tristate "Maxim MAX8998/LP3974 PMIC battery charger driver"
+       depends on MFD_MAX8998 && REGULATOR_MAX8998
+       help
+         Say Y to enable support for the battery charger control sysfs and
+         platform data of MAX8998/LP3974 PMICs.
+
 endif # POWER_SUPPLY
index 009a90fa8ac9538e320ec1f0f9196b44e87054f1..b4af13dd8b66a1b45a3ed1307c1d0c4b1b10e169 100644 (file)
@@ -36,3 +36,5 @@ obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
 obj-$(CONFIG_CHARGER_MAX8903)  += max8903_charger.o
 obj-$(CONFIG_CHARGER_TWL4030)  += twl4030_charger.o
 obj-$(CONFIG_CHARGER_GPIO)     += gpio-charger.o
+obj-$(CONFIG_CHARGER_MAX8997)  += max8997_charger.o
+obj-$(CONFIG_CHARGER_MAX8998)  += max8998_charger.o
index dc628cb2e762803b6f3374d33a99feae5b08640c..8a612dec9139d27b4e0a814be38b6c71d6954fca 100644 (file)
 #include <linux/apm-emulation.h>
 
 
-#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
-                        POWER_SUPPLY_PROP_##prop, val)
+#define PSY_PROP(psy, prop, val) (psy->get_property(psy, \
+                        POWER_SUPPLY_PROP_##prop, val))
 
-#define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \
-                                                        prop, val)
+#define _MPSY_PROP(prop, val) (main_battery->get_property(main_battery, \
+                                                        prop, val))
 
 #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
 
index 506585e31a5bee12ff53e3d7b3604f11d9d70902..9c5e5beda3a8e34a50dcdc6f960f2e830ca099f7 100644 (file)
@@ -152,6 +152,10 @@ struct bq20z75_info {
        bool                            gpio_detect;
        bool                            enable_detection;
        int                             irq;
+       int                             last_state;
+       int                             poll_time;
+       struct delayed_work             work;
+       int                             ignore_changes;
 };
 
 static int bq20z75_read_word_data(struct i2c_client *client, u8 address)
@@ -279,6 +283,7 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
        int reg_offset, enum power_supply_property psp,
        union power_supply_propval *val)
 {
+       struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
        s32 ret;
 
        ret = bq20z75_read_word_data(client,
@@ -293,15 +298,24 @@ static int bq20z75_get_battery_property(struct i2c_client *client,
        if (ret >= bq20z75_data[reg_offset].min_value &&
            ret <= bq20z75_data[reg_offset].max_value) {
                val->intval = ret;
-               if (psp == POWER_SUPPLY_PROP_STATUS) {
-                       if (ret & BATTERY_FULL_CHARGED)
-                               val->intval = POWER_SUPPLY_STATUS_FULL;
-                       else if (ret & BATTERY_FULL_DISCHARGED)
-                               val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
-                       else if (ret & BATTERY_DISCHARGING)
-                               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
-                       else
-                               val->intval = POWER_SUPPLY_STATUS_CHARGING;
+               if (psp != POWER_SUPPLY_PROP_STATUS)
+                       return 0;
+
+               if (ret & BATTERY_FULL_CHARGED)
+                       val->intval = POWER_SUPPLY_STATUS_FULL;
+               else if (ret & BATTERY_FULL_DISCHARGED)
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               else if (ret & BATTERY_DISCHARGING)
+                       val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+
+               if (bq20z75_device->poll_time == 0)
+                       bq20z75_device->last_state = val->intval;
+               else if (bq20z75_device->last_state != val->intval) {
+                       cancel_delayed_work_sync(&bq20z75_device->work);
+                       power_supply_changed(&bq20z75_device->power_supply);
+                       bq20z75_device->poll_time = 0;
                }
        } else {
                if (psp == POWER_SUPPLY_PROP_STATUS)
@@ -545,6 +559,60 @@ static irqreturn_t bq20z75_irq(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
+static void bq20z75_external_power_changed(struct power_supply *psy)
+{
+       struct bq20z75_info *bq20z75_device;
+
+       bq20z75_device = container_of(psy, struct bq20z75_info, power_supply);
+
+       if (bq20z75_device->ignore_changes > 0) {
+               bq20z75_device->ignore_changes--;
+               return;
+       }
+
+       /* cancel outstanding work */
+       cancel_delayed_work_sync(&bq20z75_device->work);
+
+       schedule_delayed_work(&bq20z75_device->work, HZ);
+       bq20z75_device->poll_time = bq20z75_device->pdata->poll_retry_count;
+}
+
+static void bq20z75_delayed_work(struct work_struct *work)
+{
+       struct bq20z75_info *bq20z75_device;
+       s32 ret;
+
+       bq20z75_device = container_of(work, struct bq20z75_info, work.work);
+
+       ret = bq20z75_read_word_data(bq20z75_device->client,
+                                    bq20z75_data[REG_STATUS].addr);
+       /* if the read failed, give up on this work */
+       if (ret < 0) {
+               bq20z75_device->poll_time = 0;
+               return;
+       }
+
+       if (ret & BATTERY_FULL_CHARGED)
+               ret = POWER_SUPPLY_STATUS_FULL;
+       else if (ret & BATTERY_FULL_DISCHARGED)
+               ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
+       else if (ret & BATTERY_DISCHARGING)
+               ret = POWER_SUPPLY_STATUS_DISCHARGING;
+       else
+               ret = POWER_SUPPLY_STATUS_CHARGING;
+
+       if (bq20z75_device->last_state != ret) {
+               bq20z75_device->poll_time = 0;
+               power_supply_changed(&bq20z75_device->power_supply);
+               return;
+       }
+       if (bq20z75_device->poll_time > 0) {
+               schedule_delayed_work(&bq20z75_device->work, HZ);
+               bq20z75_device->poll_time--;
+               return;
+       }
+}
+
 static int __devinit bq20z75_probe(struct i2c_client *client,
        const struct i2c_device_id *id)
 {
@@ -566,6 +634,13 @@ static int __devinit bq20z75_probe(struct i2c_client *client,
        bq20z75_device->power_supply.num_properties =
                ARRAY_SIZE(bq20z75_properties);
        bq20z75_device->power_supply.get_property = bq20z75_get_property;
+       /* ignore first notification of external change, it is generated
+        * from the power_supply_register call back
+        */
+       bq20z75_device->ignore_changes = 1;
+       bq20z75_device->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
+       bq20z75_device->power_supply.external_power_changed =
+               bq20z75_external_power_changed;
 
        if (pdata) {
                bq20z75_device->gpio_detect =
@@ -625,6 +700,10 @@ skip_gpio:
        dev_info(&client->dev,
                "%s: battery gas gauge device registered\n", client->name);
 
+       INIT_DELAYED_WORK(&bq20z75_device->work, bq20z75_delayed_work);
+
+       bq20z75_device->enable_detection = true;
+
        return 0;
 
 exit_psupply:
@@ -648,6 +727,9 @@ static int __devexit bq20z75_remove(struct i2c_client *client)
                gpio_free(bq20z75_device->pdata->battery_detect);
 
        power_supply_unregister(&bq20z75_device->power_supply);
+
+       cancel_delayed_work_sync(&bq20z75_device->work);
+
        kfree(bq20z75_device);
        bq20z75_device = NULL;
 
@@ -661,6 +743,9 @@ static int bq20z75_suspend(struct i2c_client *client,
        struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client);
        s32 ret;
 
+       if (bq20z75_device->poll_time > 0)
+               cancel_delayed_work_sync(&bq20z75_device->work);
+
        /* write to manufacturer access with sleep command */
        ret = bq20z75_write_word_data(client,
                bq20z75_data[REG_MANUFACTURER_DATA].addr,
index 718f2c537827a5a38ae90617bc91efb3eba9c8e0..a64b8854cfd59dcb640202e56044e77ff9e13605 100644 (file)
@@ -127,7 +127,7 @@ static int __devinit gpio_charger_probe(struct platform_device *pdev)
                ret = request_any_context_irq(irq, gpio_charger_irq,
                                IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                                dev_name(&pdev->dev), charger);
-               if (ret)
+               if (ret < 0)
                        dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
                else
                        gpio_charger->irq = irq;
index c5c8805156cbebe4ebc734052c175af4eb45aa37..98bfab35b8e99ab4c020e9dad91b8f6475b79ac2 100644 (file)
 #include <linux/power_supply.h>
 #include <linux/power/max17042_battery.h>
 
-enum max17042_register {
-       MAX17042_STATUS         = 0x00,
-       MAX17042_VALRT_Th       = 0x01,
-       MAX17042_TALRT_Th       = 0x02,
-       MAX17042_SALRT_Th       = 0x03,
-       MAX17042_AtRate         = 0x04,
-       MAX17042_RepCap         = 0x05,
-       MAX17042_RepSOC         = 0x06,
-       MAX17042_Age            = 0x07,
-       MAX17042_TEMP           = 0x08,
-       MAX17042_VCELL          = 0x09,
-       MAX17042_Current        = 0x0A,
-       MAX17042_AvgCurrent     = 0x0B,
-       MAX17042_Qresidual      = 0x0C,
-       MAX17042_SOC            = 0x0D,
-       MAX17042_AvSOC          = 0x0E,
-       MAX17042_RemCap         = 0x0F,
-       MAX17402_FullCAP        = 0x10,
-       MAX17042_TTE            = 0x11,
-       MAX17042_V_empty        = 0x12,
-
-       MAX17042_RSLOW          = 0x14,
-
-       MAX17042_AvgTA          = 0x16,
-       MAX17042_Cycles         = 0x17,
-       MAX17042_DesignCap      = 0x18,
-       MAX17042_AvgVCELL       = 0x19,
-       MAX17042_MinMaxTemp     = 0x1A,
-       MAX17042_MinMaxVolt     = 0x1B,
-       MAX17042_MinMaxCurr     = 0x1C,
-       MAX17042_CONFIG         = 0x1D,
-       MAX17042_ICHGTerm       = 0x1E,
-       MAX17042_AvCap          = 0x1F,
-       MAX17042_ManName        = 0x20,
-       MAX17042_DevName        = 0x21,
-       MAX17042_DevChem        = 0x22,
-
-       MAX17042_TempNom        = 0x24,
-       MAX17042_TempCold       = 0x25,
-       MAX17042_TempHot        = 0x26,
-       MAX17042_AIN            = 0x27,
-       MAX17042_LearnCFG       = 0x28,
-       MAX17042_SHFTCFG        = 0x29,
-       MAX17042_RelaxCFG       = 0x2A,
-       MAX17042_MiscCFG        = 0x2B,
-       MAX17042_TGAIN          = 0x2C,
-       MAx17042_TOFF           = 0x2D,
-       MAX17042_CGAIN          = 0x2E,
-       MAX17042_COFF           = 0x2F,
-
-       MAX17042_Q_empty        = 0x33,
-       MAX17042_T_empty        = 0x34,
-
-       MAX17042_RCOMP0         = 0x38,
-       MAX17042_TempCo         = 0x39,
-       MAX17042_Rx             = 0x3A,
-       MAX17042_T_empty0       = 0x3B,
-       MAX17042_TaskPeriod     = 0x3C,
-       MAX17042_FSTAT          = 0x3D,
-
-       MAX17042_SHDNTIMER      = 0x3F,
-
-       MAX17042_VFRemCap       = 0x4A,
-
-       MAX17042_QH             = 0x4D,
-       MAX17042_QL             = 0x4E,
-};
-
 struct max17042_chip {
        struct i2c_client *client;
        struct power_supply battery;
@@ -123,10 +55,27 @@ static int max17042_read_reg(struct i2c_client *client, u8 reg)
        return ret;
 }
 
+static void max17042_set_reg(struct i2c_client *client,
+                            struct max17042_reg_data *data, int size)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               max17042_write_reg(client, data[i].addr, data[i].data);
+}
+
 static enum power_supply_property max17042_battery_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_CYCLE_COUNT,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
        POWER_SUPPLY_PROP_VOLTAGE_NOW,
        POWER_SUPPLY_PROP_VOLTAGE_AVG,
        POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CHARGE_FULL,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CURRENT_AVG,
 };
 
 static int max17042_get_property(struct power_supply *psy,
@@ -137,6 +86,30 @@ static int max17042_get_property(struct power_supply *psy,
                                struct max17042_chip, battery);
 
        switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_STATUS);
+               if (val->intval & MAX17042_STATUS_BattAbsent)
+                       val->intval = 0;
+               else
+                       val->intval = 1;
+               break;
+       case POWER_SUPPLY_PROP_CYCLE_COUNT:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_Cycles);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_MinMaxVolt);
+               val->intval >>= 8;
+               val->intval *= 20000; /* Units of LSB = 20mV */
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_V_empty);
+               val->intval >>= 7;
+               val->intval *= 10000; /* Units of LSB = 10mV */
+               break;
        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
                val->intval = max17042_read_reg(chip->client,
                                MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
@@ -149,6 +122,57 @@ static int max17042_get_property(struct power_supply *psy,
                val->intval = max17042_read_reg(chip->client,
                                MAX17042_SOC) / 256;
                break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_RepSOC);
+               if ((val->intval / 256) >= MAX17042_BATTERY_FULL)
+                       val->intval = 1;
+               else if (val->intval >= 0)
+                       val->intval = 0;
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+               val->intval = max17042_read_reg(chip->client,
+                               MAX17042_TEMP);
+               /* The value is signed. */
+               if (val->intval & 0x8000) {
+                       val->intval = (0x7fff & ~val->intval) + 1;
+                       val->intval *= -1;
+               }
+               /* The value is converted into deci-centigrade scale */
+               /* Units of LSB = 1 / 256 degree Celsius */
+               val->intval = val->intval * 10 / 256;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               if (chip->pdata->enable_current_sense) {
+                       val->intval = max17042_read_reg(chip->client,
+                                       MAX17042_Current);
+                       if (val->intval & 0x8000) {
+                               /* Negative */
+                               val->intval = ~val->intval & 0x7fff;
+                               val->intval++;
+                               val->intval *= -1;
+                       }
+                       val->intval >>= 4;
+                       val->intval *= 1000000 * 25 / chip->pdata->r_sns;
+               } else {
+                       return -EINVAL;
+               }
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_AVG:
+               if (chip->pdata->enable_current_sense) {
+                       val->intval = max17042_read_reg(chip->client,
+                                       MAX17042_AvgCurrent);
+                       if (val->intval & 0x8000) {
+                               /* Negative */
+                               val->intval = ~val->intval & 0x7fff;
+                               val->intval++;
+                               val->intval *= -1;
+                       }
+                       val->intval *= 1562500 / chip->pdata->r_sns;
+               } else {
+                       return -EINVAL;
+               }
+               break;
        default:
                return -EINVAL;
        }
@@ -180,18 +204,30 @@ static int __devinit max17042_probe(struct i2c_client *client,
        chip->battery.properties        = max17042_battery_props;
        chip->battery.num_properties    = ARRAY_SIZE(max17042_battery_props);
 
+       /* When current is not measured,
+        * CURRENT_NOW and CURRENT_AVG properties should be invisible. */
+       if (!chip->pdata->enable_current_sense)
+               chip->battery.num_properties -= 2;
+
        ret = power_supply_register(&client->dev, &chip->battery);
        if (ret) {
                dev_err(&client->dev, "failed: power supply register\n");
-               i2c_set_clientdata(client, NULL);
                kfree(chip);
                return ret;
        }
 
+       /* Initialize registers according to values from the platform data */
+       if (chip->pdata->init_data)
+               max17042_set_reg(client, chip->pdata->init_data,
+                                chip->pdata->num_init_data);
+
        if (!chip->pdata->enable_current_sense) {
                max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
                max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
                max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
+       } else {
+               if (chip->pdata->r_sns == 0)
+                       chip->pdata->r_sns = MAX17042_DEFAULT_SNS_RESISTOR;
        }
 
        return 0;
@@ -202,7 +238,6 @@ static int __devexit max17042_remove(struct i2c_client *client)
        struct max17042_chip *chip = i2c_get_clientdata(client);
 
        power_supply_unregister(&chip->battery);
-       i2c_set_clientdata(client, NULL);
        kfree(chip);
        return 0;
 }
index 33ff0e37809e43c29e848da0eac1e72ebf27d406..a9b0209a2f55042a572fc18b2d34b2cee979ad78 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/power/max8903_charger.h>
 
 struct max8903_data {
-       struct max8903_pdata *pdata;
+       struct max8903_pdata pdata;
        struct device *dev;
        struct power_supply psy;
        bool fault;
@@ -52,8 +52,8 @@ static int max8903_get_property(struct power_supply *psy,
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
                val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
-               if (data->pdata->chg) {
-                       if (gpio_get_value(data->pdata->chg) == 0)
+               if (data->pdata.chg) {
+                       if (gpio_get_value(data->pdata.chg) == 0)
                                val->intval = POWER_SUPPLY_STATUS_CHARGING;
                        else if (data->usb_in || data->ta_in)
                                val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
@@ -80,7 +80,7 @@ static int max8903_get_property(struct power_supply *psy,
 static irqreturn_t max8903_dcin(int irq, void *_data)
 {
        struct max8903_data *data = _data;
-       struct max8903_pdata *pdata = data->pdata;
+       struct max8903_pdata *pdata = &data->pdata;
        bool ta_in;
        enum power_supply_type old_type;
 
@@ -121,7 +121,7 @@ static irqreturn_t max8903_dcin(int irq, void *_data)
 static irqreturn_t max8903_usbin(int irq, void *_data)
 {
        struct max8903_data *data = _data;
-       struct max8903_pdata *pdata = data->pdata;
+       struct max8903_pdata *pdata = &data->pdata;
        bool usb_in;
        enum power_supply_type old_type;
 
@@ -160,7 +160,7 @@ static irqreturn_t max8903_usbin(int irq, void *_data)
 static irqreturn_t max8903_fault(int irq, void *_data)
 {
        struct max8903_data *data = _data;
-       struct max8903_pdata *pdata = data->pdata;
+       struct max8903_pdata *pdata = &data->pdata;
        bool fault;
 
        fault = gpio_get_value(pdata->flt) ? false : true;
@@ -193,7 +193,7 @@ static __devinit int max8903_probe(struct platform_device *pdev)
                dev_err(dev, "Cannot allocate memory.\n");
                return -ENOMEM;
        }
-       data->pdata = pdata;
+       memcpy(&data->pdata, pdata, sizeof(struct max8903_pdata));
        data->dev = dev;
        platform_set_drvdata(pdev, data);
 
@@ -349,7 +349,7 @@ static __devexit int max8903_remove(struct platform_device *pdev)
        struct max8903_data *data = platform_get_drvdata(pdev);
 
        if (data) {
-               struct max8903_pdata *pdata = data->pdata;
+               struct max8903_pdata *pdata = &data->pdata;
 
                if (pdata->flt)
                        free_irq(gpio_to_irq(pdata->flt), data);
diff --git a/drivers/power/max8997_charger.c b/drivers/power/max8997_charger.c
new file mode 100644 (file)
index 0000000..7106b49
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * max8997_charger.c - Power supply consumer driver for the Maxim 8997/8966
+ *
+ *  Copyright (C) 2011 Samsung Electronics
+ *  MyungJoo Ham <myungjoo.ham@samsung.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/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+
+struct charger_data {
+       struct device *dev;
+       struct max8997_dev *iodev;
+       struct power_supply battery;
+};
+
+static enum power_supply_property max8997_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS, /* "FULL" or "NOT FULL" only. */
+       POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
+       POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
+};
+
+/* Note that the charger control is done by a current regulator "CHARGER" */
+static int max8997_battery_get_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               union power_supply_propval *val)
+{
+       struct charger_data *charger = container_of(psy,
+                       struct charger_data, battery);
+       struct i2c_client *i2c = charger->iodev->i2c;
+       int ret;
+       u8 reg;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = 0;
+               ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
+               if (ret)
+                       return ret;
+               if ((reg & (1 << 0)) == 0x1)
+                       val->intval = POWER_SUPPLY_STATUS_FULL;
+
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = 0;
+               ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
+               if (ret)
+                       return ret;
+               if ((reg & (1 << 2)) == 0x0)
+                       val->intval = 1;
+
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = 0;
+               ret = max8997_read_reg(i2c, MAX8997_REG_STATUS4, &reg);
+               if (ret)
+                       return ret;
+               /* DCINOK */
+               if (reg & (1 << 1))
+                       val->intval = 1;
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static __devinit int max8997_battery_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct charger_data *charger;
+       struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+
+       if (!pdata)
+               return -EINVAL;
+
+       if (pdata->eoc_mA) {
+               u8 val = (pdata->eoc_mA - 50) / 10;
+               if (val < 0)
+                       val = 0;
+               if (val > 0xf)
+                       val = 0xf;
+
+               ret = max8997_update_reg(iodev->i2c,
+                               MAX8997_REG_MBCCTRL5, val, 0xf);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Cannot use i2c bus.\n");
+                       return ret;
+               }
+       }
+
+       switch (pdata->timeout) {
+       case 5:
+               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
+                               0x2 << 4, 0x7 << 4);
+               break;
+       case 6:
+               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
+                               0x3 << 4, 0x7 << 4);
+               break;
+       case 7:
+               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
+                               0x4 << 4, 0x7 << 4);
+               break;
+       case 0:
+               ret = max8997_update_reg(iodev->i2c, MAX8997_REG_MBCCTRL1,
+                               0x7 << 4, 0x7 << 4);
+               break;
+       default:
+               dev_err(&pdev->dev, "incorrect timeout value (%d)\n",
+                               pdata->timeout);
+               return -EINVAL;
+       }
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Cannot use i2c bus.\n");
+               return ret;
+       }
+
+       charger = kzalloc(sizeof(struct charger_data), GFP_KERNEL);
+       if (charger == NULL) {
+               dev_err(&pdev->dev, "Cannot allocate memory.\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, charger);
+
+       charger->battery.name = "max8997_pmic";
+       charger->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+       charger->battery.get_property = max8997_battery_get_property;
+       charger->battery.properties = max8997_battery_props;
+       charger->battery.num_properties = ARRAY_SIZE(max8997_battery_props);
+
+       charger->dev = &pdev->dev;
+       charger->iodev = iodev;
+
+       ret = power_supply_register(&pdev->dev, &charger->battery);
+       if (ret) {
+               dev_err(&pdev->dev, "failed: power supply register\n");
+               goto err;
+       }
+
+       return 0;
+err:
+       kfree(charger);
+       return ret;
+}
+
+static int __devexit max8997_battery_remove(struct platform_device *pdev)
+{
+       struct charger_data *charger = platform_get_drvdata(pdev);
+
+       power_supply_unregister(&charger->battery);
+       kfree(charger);
+       return 0;
+}
+
+static const struct platform_device_id max8997_battery_id[] = {
+       { "max8997-battery", 0 },
+};
+
+static struct platform_driver max8997_battery_driver = {
+       .driver = {
+               .name = "max8997-battery",
+               .owner = THIS_MODULE,
+       },
+       .probe = max8997_battery_probe,
+       .remove = __devexit_p(max8997_battery_remove),
+       .id_table = max8997_battery_id,
+};
+
+static int __init max8997_battery_init(void)
+{
+       return platform_driver_register(&max8997_battery_driver);
+}
+subsys_initcall(max8997_battery_init);
+
+static void __exit max8997_battery_cleanup(void)
+{
+       platform_driver_unregister(&max8997_battery_driver);
+}
+module_exit(max8997_battery_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 8997/8966 battery control driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c
new file mode 100644 (file)
index 0000000..cc21fa2
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * max8998_charger.c - Power supply consumer driver for the Maxim 8998/LP3974
+ *
+ *  Copyright (C) 2009-2010 Samsung Electronics
+ *  MyungJoo Ham <myungjoo.ham@samsung.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/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/max8998.h>
+#include <linux/mfd/max8998-private.h>
+
+struct max8998_battery_data {
+       struct device *dev;
+       struct max8998_dev *iodev;
+       struct power_supply battery;
+};
+
+static enum power_supply_property max8998_battery_props[] = {
+       POWER_SUPPLY_PROP_PRESENT, /* the presence of battery */
+       POWER_SUPPLY_PROP_ONLINE, /* charger is active or not */
+};
+
+/* Note that the charger control is done by a current regulator "CHARGER" */
+static int max8998_battery_get_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               union power_supply_propval *val)
+{
+       struct max8998_battery_data *max8998 = container_of(psy,
+                       struct max8998_battery_data, battery);
+       struct i2c_client *i2c = max8998->iodev->i2c;
+       int ret;
+       u8 reg;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_PRESENT:
+               ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, &reg);
+               if (ret)
+                       return ret;
+               if (reg & (1 << 4))
+                       val->intval = 0;
+               else
+                       val->intval = 1;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               ret = max8998_read_reg(i2c, MAX8998_REG_STATUS2, &reg);
+               if (ret)
+                       return ret;
+               if (reg & (1 << 3))
+                       val->intval = 0;
+               else
+                       val->intval = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static __devinit int max8998_battery_probe(struct platform_device *pdev)
+{
+       struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct max8998_battery_data *max8998;
+       struct i2c_client *i2c;
+       int ret = 0;
+
+       if (!pdata) {
+               dev_err(pdev->dev.parent, "No platform init data supplied\n");
+               return -ENODEV;
+       }
+
+       max8998 = kzalloc(sizeof(struct max8998_battery_data), GFP_KERNEL);
+       if (!max8998)
+               return -ENOMEM;
+
+       max8998->dev = &pdev->dev;
+       max8998->iodev = iodev;
+       platform_set_drvdata(pdev, max8998);
+       i2c = max8998->iodev->i2c;
+
+       /* Setup "End of Charge" */
+       /* If EOC value equals 0,
+        * remain value set from bootloader or default value */
+       if (pdata->eoc >= 10 && pdata->eoc <= 45) {
+               max8998_update_reg(i2c, MAX8998_REG_CHGR1,
+                               (pdata->eoc / 5 - 2) << 5, 0x7 << 5);
+       } else if (pdata->eoc == 0) {
+               dev_dbg(max8998->dev,
+                       "EOC value not set: leave it unchanged.\n");
+       } else {
+               dev_err(max8998->dev, "Invalid EOC value\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* Setup Charge Restart Level */
+       switch (pdata->restart) {
+       case 100:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x1 << 3, 0x3 << 3);
+               break;
+       case 150:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x0 << 3, 0x3 << 3);
+               break;
+       case 200:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x2 << 3, 0x3 << 3);
+               break;
+       case -1:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR1, 0x3 << 3, 0x3 << 3);
+               break;
+       case 0:
+               dev_dbg(max8998->dev,
+                       "Restart Level not set: leave it unchanged.\n");
+               break;
+       default:
+               dev_err(max8998->dev, "Invalid Restart Level\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* Setup Charge Full Timeout */
+       switch (pdata->timeout) {
+       case 5:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x0 << 4, 0x3 << 4);
+               break;
+       case 6:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x1 << 4, 0x3 << 4);
+               break;
+       case 7:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x2 << 4, 0x3 << 4);
+               break;
+       case -1:
+               max8998_update_reg(i2c, MAX8998_REG_CHGR2, 0x3 << 4, 0x3 << 4);
+               break;
+       case 0:
+               dev_dbg(max8998->dev,
+                       "Full Timeout not set: leave it unchanged.\n");
+       default:
+               dev_err(max8998->dev, "Invalid Full Timeout value\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       max8998->battery.name = "max8998_pmic";
+       max8998->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+       max8998->battery.get_property = max8998_battery_get_property;
+       max8998->battery.properties = max8998_battery_props;
+       max8998->battery.num_properties = ARRAY_SIZE(max8998_battery_props);
+
+       ret = power_supply_register(max8998->dev, &max8998->battery);
+       if (ret) {
+               dev_err(max8998->dev, "failed: power supply register\n");
+               goto err;
+       }
+
+       return 0;
+err:
+       kfree(max8998);
+       return ret;
+}
+
+static int __devexit max8998_battery_remove(struct platform_device *pdev)
+{
+       struct max8998_battery_data *max8998 = platform_get_drvdata(pdev);
+
+       power_supply_unregister(&max8998->battery);
+       kfree(max8998);
+
+       return 0;
+}
+
+static const struct platform_device_id max8998_battery_id[] = {
+       { "max8998-battery", TYPE_MAX8998 },
+};
+
+static struct platform_driver max8998_battery_driver = {
+       .driver = {
+               .name = "max8998-battery",
+               .owner = THIS_MODULE,
+       },
+       .probe = max8998_battery_probe,
+       .remove = __devexit_p(max8998_battery_remove),
+       .id_table = max8998_battery_id,
+};
+
+static int __init max8998_battery_init(void)
+{
+       return platform_driver_register(&max8998_battery_driver);
+}
+module_init(max8998_battery_init);
+
+static void __exit max8998_battery_cleanup(void)
+{
+       platform_driver_unregister(&max8998_battery_driver);
+}
+module_exit(max8998_battery_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 8998 battery control driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:max8998-battery");
index d36c289aaef52e1246029dd97f07f8f9d061f2f8..a675e31b4f132d507cd2c8c72ac09a5ada5cac0b 100644 (file)
@@ -266,7 +266,7 @@ static irqreturn_t s3c_adc_bat_charged(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __init s3c_adc_bat_probe(struct platform_device *pdev)
+static int __devinit s3c_adc_bat_probe(struct platform_device *pdev)
 {
        struct s3c_adc_client   *client;
        struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
index 92c16e1677bd7db5d796a34d64e5bd3b29428c7b..54b9198fa576a12b1d7f59a2ecc1463786cb0196 100644 (file)
@@ -62,7 +62,7 @@
 #define TWL4030_MSTATEC_COMPLETE4      0x0e
 
 static bool allow_usb;
-module_param(allow_usb, bool, 1);
+module_param(allow_usb, bool, 0644);
 MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current");
 
 struct twl4030_bci {
@@ -425,7 +425,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
 {
        struct twl4030_bci *bci;
        int ret;
-       int reg;
+       u32 reg;
 
        bci = kzalloc(sizeof(*bci), GFP_KERNEL);
        if (bci == NULL)
@@ -486,7 +486,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
        }
 
        /* Enable interrupts now. */
-       reg = ~(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
+       reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 |
                TWL4030_TBATOR1 | TWL4030_BATSTS);
        ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
                               TWL4030_INTERRUPTS_BCIIMR1A);
@@ -495,7 +495,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
                goto fail_unmask_interrupts;
        }
 
-       reg = ~(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
+       reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV);
        ret = twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, reg,
                               TWL4030_INTERRUPTS_BCIIMR2A);
        if (ret < 0)
@@ -572,7 +572,7 @@ static void __exit twl4030_bci_exit(void)
 }
 module_exit(twl4030_bci_exit);
 
-MODULE_AUTHOR("Gražydas Ignotas");
+MODULE_AUTHOR("Gražvydas Ignotas");
 MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:twl4030_bci");
index 0fd130d80f5d914826029c9f8bb370d44718472f..e648cbea1e6ac513349d31682114c5e56e4fcabd 100644 (file)
@@ -22,6 +22,7 @@
 struct wm831x_backup {
        struct wm831x *wm831x;
        struct power_supply backup;
+       char name[20];
 };
 
 static int wm831x_backup_read_voltage(struct wm831x *wm831x,
@@ -163,6 +164,7 @@ static enum power_supply_property wm831x_backup_props[] = {
 static __devinit int wm831x_backup_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+       struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
        struct wm831x_backup *devdata;
        struct power_supply *backup;
        int ret;
@@ -182,7 +184,14 @@ static __devinit int wm831x_backup_probe(struct platform_device *pdev)
         */
        wm831x_config_backup(wm831x);
 
-       backup->name = "wm831x-backup";
+       if (wm831x_pdata && wm831x_pdata->wm831x_num)
+               snprintf(devdata->name, sizeof(devdata->name),
+                        "wm831x-backup.%d", wm831x_pdata->wm831x_num);
+       else
+               snprintf(devdata->name, sizeof(devdata->name),
+                        "wm831x-backup");
+
+       backup->name = devdata->name;
        backup->type = POWER_SUPPLY_TYPE_BATTERY;
        backup->properties = wm831x_backup_props;
        backup->num_properties = ARRAY_SIZE(wm831x_backup_props);
@@ -203,6 +212,7 @@ static __devexit int wm831x_backup_remove(struct platform_device *pdev)
        struct wm831x_backup *devdata = platform_get_drvdata(pdev);
 
        power_supply_unregister(&devdata->backup);
+       kfree(devdata->backup.name);
        kfree(devdata);
 
        return 0;
index ddf8cf5f3204032f835892487ba085e058f49c82..6cc2ca6427f337460152ca9ab257d3575396e465 100644 (file)
@@ -24,6 +24,9 @@ struct wm831x_power {
        struct power_supply wall;
        struct power_supply usb;
        struct power_supply battery;
+       char wall_name[20];
+       char usb_name[20];
+       char battery_name[20];
 };
 
 static int wm831x_power_check_online(struct wm831x *wm831x, int supply,
@@ -486,6 +489,7 @@ static irqreturn_t wm831x_pwr_src_irq(int irq, void *data)
 static __devinit int wm831x_power_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
+       struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data;
        struct wm831x_power *power;
        struct power_supply *usb;
        struct power_supply *battery;
@@ -503,12 +507,28 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
        battery = &power->battery;
        wall = &power->wall;
 
+       if (wm831x_pdata && wm831x_pdata->wm831x_num) {
+               snprintf(power->wall_name, sizeof(power->wall_name),
+                        "wm831x-wall.%d", wm831x_pdata->wm831x_num);
+               snprintf(power->battery_name, sizeof(power->wall_name),
+                        "wm831x-battery.%d", wm831x_pdata->wm831x_num);
+               snprintf(power->usb_name, sizeof(power->wall_name),
+                        "wm831x-usb.%d", wm831x_pdata->wm831x_num);
+       } else {
+               snprintf(power->wall_name, sizeof(power->wall_name),
+                        "wm831x-wall");
+               snprintf(power->battery_name, sizeof(power->wall_name),
+                        "wm831x-battery");
+               snprintf(power->usb_name, sizeof(power->wall_name),
+                        "wm831x-usb");
+       }
+
        /* We ignore configuration failures since we can still read back
         * the status without enabling the charger.
         */
        wm831x_config_battery(wm831x);
 
-       wall->name = "wm831x-wall";
+       wall->name = power->wall_name;
        wall->type = POWER_SUPPLY_TYPE_MAINS;
        wall->properties = wm831x_wall_props;
        wall->num_properties = ARRAY_SIZE(wm831x_wall_props);
@@ -517,7 +537,7 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
        if (ret)
                goto err_kmalloc;
 
-       battery->name = "wm831x-battery";
+       battery->name = power->battery_name;
        battery->properties = wm831x_bat_props;
        battery->num_properties = ARRAY_SIZE(wm831x_bat_props);
        battery->get_property = wm831x_bat_get_prop;
@@ -526,7 +546,7 @@ static __devinit int wm831x_power_probe(struct platform_device *pdev)
        if (ret)
                goto err_wall;
 
-       usb->name = "wm831x-usb",
+       usb->name = power->usb_name,
        usb->type = POWER_SUPPLY_TYPE_USB;
        usb->properties = wm831x_usb_props;
        usb->num_properties = ARRAY_SIZE(wm831x_usb_props);
index 118eb213eb3a7ea8e5731fdf7004f2b50b672b82..c7fd2c0e3f2bd212ebe607224fb9dd4943fa8546 100644 (file)
@@ -249,6 +249,12 @@ config REGULATOR_TPS6507X
          three step-down converters and two general-purpose LDO voltage regulators.
          It supports TI's software based Class-2 SmartReflex implementation.
 
+config REGULATOR_TPS65912
+       tristate "TI TPS65912 Power regulator"
+       depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI)
+       help
+           This driver supports TPS65912 voltage regulator chip.
+
 config REGULATOR_88PM8607
        bool "Marvell 88PM8607 Power regulators"
        depends on MFD_88PM860X=y
@@ -304,5 +310,12 @@ config REGULATOR_TPS65910
        help
          This driver supports TPS65910 voltage regulator chips.
 
+config REGULATOR_AAT2870
+       tristate "AnalogicTech AAT2870 Regulators"
+       depends on MFD_AAT2870_CORE
+       help
+         If you have a AnalogicTech AAT2870 say Y to enable the
+         regulator driver.
+
 endif
 
index 3932d2ec38f36f08ea209dfd50f0a32ba1b75121..040d5aa63535bb33d2c0e946d7878bfc7418fad8 100644 (file)
@@ -38,10 +38,12 @@ obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
 obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
 obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
+obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c
new file mode 100644 (file)
index 0000000..cd41045
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * linux/drivers/regulator/aat2870-regulator.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ * Author: Jin Park <jinyoungp@nvidia.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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/aat2870.h>
+
+struct aat2870_regulator {
+       struct platform_device *pdev;
+       struct regulator_desc desc;
+
+       const int *voltages; /* uV */
+
+       int min_uV;
+       int max_uV;
+
+       u8 enable_addr;
+       u8 enable_shift;
+       u8 enable_mask;
+
+       u8 voltage_addr;
+       u8 voltage_shift;
+       u8 voltage_mask;
+};
+
+static int aat2870_ldo_list_voltage(struct regulator_dev *rdev,
+                                   unsigned selector)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+
+       return ri->voltages[selector];
+}
+
+static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev,
+                                      unsigned selector)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+       struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent);
+
+       return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask,
+                       (selector << ri->voltage_shift) & ri->voltage_mask);
+}
+
+static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+       struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent);
+       u8 val;
+       int ret;
+
+       ret = aat2870->read(aat2870, ri->voltage_addr, &val);
+       if (ret)
+               return ret;
+
+       return (val & ri->voltage_mask) >> ri->voltage_shift;
+}
+
+static int aat2870_ldo_enable(struct regulator_dev *rdev)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+       struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent);
+
+       return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask,
+                              ri->enable_mask);
+}
+
+static int aat2870_ldo_disable(struct regulator_dev *rdev)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+       struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent);
+
+       return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0);
+}
+
+static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
+{
+       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
+       struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent);
+       u8 val;
+       int ret;
+
+       ret = aat2870->read(aat2870, ri->enable_addr, &val);
+       if (ret)
+               return ret;
+
+       return val & ri->enable_mask ? 1 : 0;
+}
+
+static struct regulator_ops aat2870_ldo_ops = {
+       .list_voltage = aat2870_ldo_list_voltage,
+       .set_voltage_sel = aat2870_ldo_set_voltage_sel,
+       .get_voltage_sel = aat2870_ldo_get_voltage_sel,
+       .enable = aat2870_ldo_enable,
+       .disable = aat2870_ldo_disable,
+       .is_enabled = aat2870_ldo_is_enabled,
+};
+
+static const int aat2870_ldo_voltages[] = {
+       1200000, 1300000, 1500000, 1600000,
+       1800000, 2000000, 2200000, 2500000,
+       2600000, 2700000, 2800000, 2900000,
+       3000000, 3100000, 3200000, 3300000,
+};
+
+#define AAT2870_LDO(ids)                               \
+       {                                               \
+               .desc = {                               \
+                       .name = #ids,                   \
+                       .id = AAT2870_ID_##ids,         \
+                       .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \
+                       .ops = &aat2870_ldo_ops,        \
+                       .type = REGULATOR_VOLTAGE,      \
+                       .owner = THIS_MODULE,           \
+               },                                      \
+               .voltages = aat2870_ldo_voltages,       \
+               .min_uV = 1200000,                      \
+               .max_uV = 3300000,                      \
+       }
+
+static struct aat2870_regulator aat2870_regulators[] = {
+       AAT2870_LDO(LDOA),
+       AAT2870_LDO(LDOB),
+       AAT2870_LDO(LDOC),
+       AAT2870_LDO(LDOD),
+};
+
+static struct aat2870_regulator *aat2870_get_regulator(int id)
+{
+       struct aat2870_regulator *ri = NULL;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) {
+               ri = &aat2870_regulators[i];
+               if (ri->desc.id == id)
+                       break;
+       }
+
+       if (!ri)
+               return NULL;
+
+       ri->enable_addr = AAT2870_LDO_EN;
+       ri->enable_shift = id - AAT2870_ID_LDOA;
+       ri->enable_mask = 0x1 << ri->enable_shift;
+
+       ri->voltage_addr = (id - AAT2870_ID_LDOA) / 2 ?
+                          AAT2870_LDO_CD : AAT2870_LDO_AB;
+       ri->voltage_shift = (id - AAT2870_ID_LDOA) % 2 ? 0 : 4;
+       ri->voltage_mask = 0xF << ri->voltage_shift;
+
+       return ri;
+}
+
+static int aat2870_regulator_probe(struct platform_device *pdev)
+{
+       struct aat2870_regulator *ri;
+       struct regulator_dev *rdev;
+
+       ri = aat2870_get_regulator(pdev->id);
+       if (!ri) {
+               dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id);
+               return -EINVAL;
+       }
+       ri->pdev = pdev;
+
+       rdev = regulator_register(&ri->desc, &pdev->dev,
+                                 pdev->dev.platform_data, ri);
+       if (IS_ERR(rdev)) {
+               dev_err(&pdev->dev, "Failed to register regulator %s\n",
+                       ri->desc.name);
+               return PTR_ERR(rdev);
+       }
+       platform_set_drvdata(pdev, rdev);
+
+       return 0;
+}
+
+static int __devexit aat2870_regulator_remove(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+       regulator_unregister(rdev);
+       return 0;
+}
+
+static struct platform_driver aat2870_regulator_driver = {
+       .driver = {
+               .name   = "aat2870-regulator",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = aat2870_regulator_probe,
+       .remove = __devexit_p(aat2870_regulator_remove),
+};
+
+static int __init aat2870_regulator_init(void)
+{
+       return platform_driver_register(&aat2870_regulator_driver);
+}
+subsys_initcall(aat2870_regulator_init);
+
+static void __exit aat2870_regulator_exit(void)
+{
+       platform_driver_unregister(&aat2870_regulator_driver);
+}
+module_exit(aat2870_regulator_exit);
+
+MODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c
new file mode 100644 (file)
index 0000000..3a9313e
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * tps65912.c  --  TI tps65912
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya Cabrera <magi@slimlogic.co.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 of the License, or (at your
+ *  option) any later version.
+ *
+ * This driver is based on wm8350 implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65912.h>
+
+/* DCDC's */
+#define TPS65912_REG_DCDC1     0
+#define TPS65912_REG_DCDC2     1
+#define TPS65912_REG_DCDC3     2
+#define TPS65912_REG_DCDC4     3
+
+/* LDOs */
+#define TPS65912_REG_LDO1      4
+#define TPS65912_REG_LDO2      5
+#define TPS65912_REG_LDO3      6
+#define TPS65912_REG_LDO4      7
+#define TPS65912_REG_LDO5      8
+#define TPS65912_REG_LDO6      9
+#define TPS65912_REG_LDO7      10
+#define TPS65912_REG_LDO8      11
+#define TPS65912_REG_LDO9      12
+#define TPS65912_REG_LDO10     13
+
+#define TPS65912_MAX_REG_ID    TPS65912_REG_LDO_10
+
+/* Number of step-down converters available */
+#define TPS65912_NUM_DCDC      4
+
+/* Number of LDO voltage regulators  available */
+#define TPS65912_NUM_LDO       10
+
+/* Number of total regulators available */
+#define TPS65912_NUM_REGULATOR         (TPS65912_NUM_DCDC + TPS65912_NUM_LDO)
+
+#define TPS65912_REG_ENABLED   0x80
+#define OP_SELREG_MASK         0x40
+#define OP_SELREG_SHIFT                6
+
+struct tps_info {
+       const char *name;
+};
+
+static struct tps_info tps65912_regs[] = {
+       {
+               .name = "DCDC1",
+       },
+       {
+               .name = "DCDC2",
+       },
+       {
+               .name = "DCDC3",
+       },
+       {
+               .name = "DCDC4",
+       },
+       {
+               .name = "LDO1",
+       },
+       {
+               .name = "LDO2",
+       },
+       {
+               .name = "LDO3",
+       },
+       {
+               .name = "LDO4",
+       },
+       {
+               .name = "LDO5",
+       },
+       {
+               .name = "LDO6",
+       },
+       {
+               .name = "LDO7",
+       },
+       {
+               .name = "LDO8",
+       },
+       {
+               .name = "LDO9",
+       },
+       {
+               .name = "LDO10",
+       },
+};
+
+struct tps65912_reg {
+       struct regulator_desc desc[TPS65912_NUM_REGULATOR];
+       struct tps65912 *mfd;
+       struct regulator_dev *rdev[TPS65912_NUM_REGULATOR];
+       struct tps_info *info[TPS65912_NUM_REGULATOR];
+       /* for read/write access */
+       struct mutex io_lock;
+       int mode;
+       int (*get_ctrl_reg)(int);
+       int dcdc1_range;
+       int dcdc2_range;
+       int dcdc3_range;
+       int dcdc4_range;
+       int pwm_mode_reg;
+       int eco_reg;
+};
+
+static int tps65912_get_range(struct tps65912_reg *pmic, int id)
+{
+       struct tps65912 *mfd = pmic->mfd;
+
+       if (id > TPS65912_REG_DCDC4)
+               return 0;
+
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               pmic->dcdc1_range = tps65912_reg_read(mfd,
+                                                       TPS65912_DCDC1_LIMIT);
+               if (pmic->dcdc1_range < 0)
+                       return pmic->dcdc1_range;
+               pmic->dcdc1_range = (pmic->dcdc1_range &
+                       DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT;
+               return pmic->dcdc1_range;
+       case TPS65912_REG_DCDC2:
+               pmic->dcdc2_range = tps65912_reg_read(mfd,
+                                                       TPS65912_DCDC2_LIMIT);
+               if (pmic->dcdc2_range < 0)
+                       return pmic->dcdc2_range;
+               pmic->dcdc2_range = (pmic->dcdc2_range &
+                       DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT;
+               return pmic->dcdc2_range;
+       case TPS65912_REG_DCDC3:
+               pmic->dcdc3_range = tps65912_reg_read(mfd,
+                                                       TPS65912_DCDC3_LIMIT);
+               if (pmic->dcdc3_range < 0)
+                       return pmic->dcdc3_range;
+               pmic->dcdc3_range = (pmic->dcdc3_range &
+                       DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT;
+               return pmic->dcdc3_range;
+       case TPS65912_REG_DCDC4:
+               pmic->dcdc4_range = tps65912_reg_read(mfd,
+                                                       TPS65912_DCDC4_LIMIT);
+               if (pmic->dcdc4_range < 0)
+                       return pmic->dcdc4_range;
+               pmic->dcdc4_range = (pmic->dcdc4_range &
+                       DCDC_LIMIT_RANGE_MASK) >> DCDC_LIMIT_RANGE_SHIFT;
+               return pmic->dcdc4_range;
+       default:
+               return 0;
+       }
+}
+
+static unsigned long tps65912_vsel_to_uv_range0(u8 vsel)
+{
+       unsigned long uv;
+
+       uv = ((vsel * 12500) + 500000);
+       return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_range1(u8 vsel)
+{
+       unsigned long uv;
+
+        uv = ((vsel * 12500) + 700000);
+       return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_range2(u8 vsel)
+{
+       unsigned long uv;
+
+       uv = ((vsel * 25000) + 500000);
+       return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_range3(u8 vsel)
+{
+       unsigned long uv;
+
+       if (vsel == 0x3f)
+               uv = 3800000;
+       else
+               uv = ((vsel * 50000) + 500000);
+
+       return uv;
+}
+
+static unsigned long tps65912_vsel_to_uv_ldo(u8 vsel)
+{
+       unsigned long uv = 0;
+
+       if (vsel <= 32)
+               uv = ((vsel * 25000) + 800000);
+       else if (vsel > 32 && vsel <= 60)
+               uv = (((vsel - 32) * 50000) + 1600000);
+       else if (vsel > 60)
+               uv = (((vsel - 60) * 100000) + 3000000);
+
+       return uv;
+}
+
+static int tps65912_get_ctrl_register(int id)
+{
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               return TPS65912_DCDC1_AVS;
+       case TPS65912_REG_DCDC2:
+               return TPS65912_DCDC2_AVS;
+       case TPS65912_REG_DCDC3:
+               return TPS65912_DCDC3_AVS;
+       case TPS65912_REG_DCDC4:
+               return TPS65912_DCDC4_AVS;
+       case TPS65912_REG_LDO1:
+               return TPS65912_LDO1_AVS;
+       case TPS65912_REG_LDO2:
+               return TPS65912_LDO2_AVS;
+       case TPS65912_REG_LDO3:
+               return TPS65912_LDO3_AVS;
+       case TPS65912_REG_LDO4:
+               return TPS65912_LDO4_AVS;
+       case TPS65912_REG_LDO5:
+               return TPS65912_LDO5;
+       case TPS65912_REG_LDO6:
+               return TPS65912_LDO6;
+       case TPS65912_REG_LDO7:
+               return TPS65912_LDO7;
+       case TPS65912_REG_LDO8:
+               return TPS65912_LDO8;
+       case TPS65912_REG_LDO9:
+               return TPS65912_LDO9;
+       case TPS65912_REG_LDO10:
+               return TPS65912_LDO10;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int tps65912_get_dcdc_sel_register(struct tps65912_reg *pmic, int id)
+{
+       struct tps65912 *mfd = pmic->mfd;
+       int opvsel = 0, sr = 0;
+       u8 reg = 0;
+
+       if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_DCDC4)
+               return -EINVAL;
+
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC1_OP);
+               sr = ((opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT);
+               if (sr)
+                       reg = TPS65912_DCDC1_AVS;
+               else
+                       reg = TPS65912_DCDC1_OP;
+               break;
+       case TPS65912_REG_DCDC2:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC2_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_DCDC2_AVS;
+               else
+                       reg = TPS65912_DCDC2_OP;
+               break;
+       case TPS65912_REG_DCDC3:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC3_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_DCDC3_AVS;
+               else
+                       reg = TPS65912_DCDC3_OP;
+               break;
+       case TPS65912_REG_DCDC4:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC4_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_DCDC4_AVS;
+               else
+                       reg = TPS65912_DCDC4_OP;
+               break;
+       }
+       return reg;
+}
+
+static int tps65912_get_ldo_sel_register(struct tps65912_reg *pmic, int id)
+{
+       struct tps65912 *mfd = pmic->mfd;
+       int opvsel = 0, sr = 0;
+       u8 reg = 0;
+
+       if (id < TPS65912_REG_LDO1 || id > TPS65912_REG_LDO10)
+               return -EINVAL;
+
+       switch (id) {
+       case TPS65912_REG_LDO1:
+               opvsel = tps65912_reg_read(mfd, TPS65912_LDO1_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_LDO1_AVS;
+               else
+                       reg = TPS65912_LDO1_OP;
+               break;
+       case TPS65912_REG_LDO2:
+               opvsel = tps65912_reg_read(mfd, TPS65912_LDO2_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_LDO2_AVS;
+               else
+                       reg = TPS65912_LDO2_OP;
+               break;
+       case TPS65912_REG_LDO3:
+               opvsel = tps65912_reg_read(mfd, TPS65912_LDO3_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_LDO3_AVS;
+               else
+                       reg = TPS65912_LDO3_OP;
+               break;
+       case TPS65912_REG_LDO4:
+               opvsel = tps65912_reg_read(mfd, TPS65912_LDO4_OP);
+               sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+               if (sr)
+                       reg = TPS65912_LDO4_AVS;
+               else
+                       reg = TPS65912_LDO4_OP;
+               break;
+       case TPS65912_REG_LDO5:
+               reg = TPS65912_LDO5;
+               break;
+       case TPS65912_REG_LDO6:
+               reg = TPS65912_LDO6;
+               break;
+       case TPS65912_REG_LDO7:
+               reg = TPS65912_LDO7;
+               break;
+       case TPS65912_REG_LDO8:
+               reg = TPS65912_LDO8;
+               break;
+       case TPS65912_REG_LDO9:
+               reg = TPS65912_LDO9;
+               break;
+       case TPS65912_REG_LDO10:
+               reg = TPS65912_LDO10;
+               break;
+       }
+
+       return reg;
+}
+
+static int tps65912_get_mode_regiters(struct tps65912_reg *pmic, int id)
+{
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               pmic->pwm_mode_reg = TPS65912_DCDC1_CTRL;
+               pmic->eco_reg = TPS65912_DCDC1_AVS;
+               break;
+       case TPS65912_REG_DCDC2:
+               pmic->pwm_mode_reg = TPS65912_DCDC2_CTRL;
+               pmic->eco_reg = TPS65912_DCDC2_AVS;
+               break;
+       case TPS65912_REG_DCDC3:
+               pmic->pwm_mode_reg = TPS65912_DCDC3_CTRL;
+               pmic->eco_reg = TPS65912_DCDC3_AVS;
+               break;
+       case TPS65912_REG_DCDC4:
+               pmic->pwm_mode_reg = TPS65912_DCDC4_CTRL;
+               pmic->eco_reg = TPS65912_DCDC4_AVS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tps65912_reg_is_enabled(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int reg, value, id = rdev_get_id(dev);
+
+       if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_LDO10)
+               return -EINVAL;
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       value = tps65912_reg_read(mfd, reg);
+       if (value < 0)
+               return value;
+
+       return value & TPS65912_REG_ENABLED;
+}
+
+static int tps65912_reg_enable(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev);
+       int reg;
+
+       if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_LDO10)
+               return -EINVAL;
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       return tps65912_set_bits(mfd, reg, TPS65912_REG_ENABLED);
+}
+
+static int tps65912_reg_disable(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev), reg;
+
+       reg = pmic->get_ctrl_reg(id);
+       if (reg < 0)
+               return reg;
+
+       return tps65912_clear_bits(mfd, reg, TPS65912_REG_ENABLED);
+}
+
+static int tps65912_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int pwm_mode, eco, id = rdev_get_id(dev);
+
+       tps65912_get_mode_regiters(pmic, id);
+
+       pwm_mode = tps65912_reg_read(mfd, pmic->pwm_mode_reg);
+       eco = tps65912_reg_read(mfd, pmic->eco_reg);
+
+       pwm_mode &= DCDCCTRL_DCDC_MODE_MASK;
+       eco &= DCDC_AVS_ECO_MASK;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               /* Verify if mode alredy set */
+               if (pwm_mode && !eco)
+                       break;
+               tps65912_set_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK);
+               tps65912_clear_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+               break;
+       case REGULATOR_MODE_NORMAL:
+       case REGULATOR_MODE_IDLE:
+               if (!pwm_mode && !eco)
+                       break;
+               tps65912_clear_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK);
+               tps65912_clear_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+               break;
+       case REGULATOR_MODE_STANDBY:
+               if (!pwm_mode && eco)
+                       break;
+               tps65912_clear_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK);
+               tps65912_set_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static unsigned int tps65912_get_mode(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int pwm_mode, eco, mode = 0, id = rdev_get_id(dev);
+
+       tps65912_get_mode_regiters(pmic, id);
+
+       pwm_mode = tps65912_reg_read(mfd, pmic->pwm_mode_reg);
+       eco = tps65912_reg_read(mfd, pmic->eco_reg);
+
+       pwm_mode &= DCDCCTRL_DCDC_MODE_MASK;
+       eco &= DCDC_AVS_ECO_MASK;
+
+       if (pwm_mode && !eco)
+               mode = REGULATOR_MODE_FAST;
+       else if (!pwm_mode && !eco)
+               mode = REGULATOR_MODE_NORMAL;
+       else if (!pwm_mode && eco)
+               mode = REGULATOR_MODE_STANDBY;
+
+       return mode;
+}
+
+static int tps65912_get_voltage_dcdc(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev), voltage = 0, range;
+       int opvsel = 0, avsel = 0, sr, vsel;
+
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC1_OP);
+               avsel = tps65912_reg_read(mfd, TPS65912_DCDC1_AVS);
+               range = pmic->dcdc1_range;
+               break;
+       case TPS65912_REG_DCDC2:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC2_OP);
+               avsel = tps65912_reg_read(mfd, TPS65912_DCDC2_AVS);
+               range = pmic->dcdc2_range;
+               break;
+       case TPS65912_REG_DCDC3:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC3_OP);
+               avsel = tps65912_reg_read(mfd, TPS65912_DCDC3_AVS);
+               range = pmic->dcdc3_range;
+               break;
+       case TPS65912_REG_DCDC4:
+               opvsel = tps65912_reg_read(mfd, TPS65912_DCDC4_OP);
+               avsel = tps65912_reg_read(mfd, TPS65912_DCDC4_AVS);
+               range = pmic->dcdc4_range;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       sr = (opvsel & OP_SELREG_MASK) >> OP_SELREG_SHIFT;
+       if (sr)
+               vsel = avsel;
+       else
+               vsel = opvsel;
+       vsel &= 0x3F;
+
+       switch (range) {
+       case 0:
+               /* 0.5 - 1.2875V in 12.5mV steps */
+               voltage = tps65912_vsel_to_uv_range0(vsel);
+               break;
+       case 1:
+               /* 0.7 - 1.4875V in 12.5mV steps */
+               voltage = tps65912_vsel_to_uv_range1(vsel);
+               break;
+       case 2:
+               /* 0.5 - 2.075V in 25mV steps */
+               voltage = tps65912_vsel_to_uv_range2(vsel);
+               break;
+       case 3:
+               /* 0.5 - 3.8V in 50mV steps */
+               voltage = tps65912_vsel_to_uv_range3(vsel);
+               break;
+       }
+       return voltage;
+}
+
+static int tps65912_set_voltage_dcdc(struct regulator_dev *dev,
+                                               unsigned selector)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev);
+       int value;
+       u8 reg;
+
+       reg = tps65912_get_dcdc_sel_register(pmic, id);
+       value = tps65912_reg_read(mfd, reg);
+       value &= 0xC0;
+       return tps65912_reg_write(mfd, reg, selector | value);
+}
+
+static int tps65912_get_voltage_ldo(struct regulator_dev *dev)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev);
+       int vsel = 0;
+       u8 reg;
+
+       reg = tps65912_get_ldo_sel_register(pmic, id);
+       vsel = tps65912_reg_read(mfd, reg);
+       vsel &= 0x3F;
+
+       return tps65912_vsel_to_uv_ldo(vsel);
+}
+
+static int tps65912_set_voltage_ldo(struct regulator_dev *dev,
+                                               unsigned selector)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       struct tps65912 *mfd = pmic->mfd;
+       int id = rdev_get_id(dev), reg, value;
+
+       reg = tps65912_get_ldo_sel_register(pmic, id);
+       value = tps65912_reg_read(mfd, reg);
+       value &= 0xC0;
+       return tps65912_reg_write(mfd, reg, selector | value);
+}
+
+static int tps65912_list_voltage_dcdc(struct regulator_dev *dev,
+                                       unsigned selector)
+{
+       struct tps65912_reg *pmic = rdev_get_drvdata(dev);
+       int range, voltage = 0, id = rdev_get_id(dev);
+
+       switch (id) {
+       case TPS65912_REG_DCDC1:
+               range = pmic->dcdc1_range;
+               break;
+       case TPS65912_REG_DCDC2:
+               range = pmic->dcdc2_range;
+               break;
+       case TPS65912_REG_DCDC3:
+               range = pmic->dcdc3_range;
+               break;
+       case TPS65912_REG_DCDC4:
+               range = pmic->dcdc4_range;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (range) {
+       case 0:
+               /* 0.5 - 1.2875V in 12.5mV steps */
+               voltage = tps65912_vsel_to_uv_range0(selector);
+               break;
+       case 1:
+               /* 0.7 - 1.4875V in 12.5mV steps */
+               voltage = tps65912_vsel_to_uv_range1(selector);
+               break;
+       case 2:
+               /* 0.5 - 2.075V in 25mV steps */
+               voltage = tps65912_vsel_to_uv_range2(selector);
+               break;
+       case 3:
+               /* 0.5 - 3.8V in 50mV steps */
+               voltage = tps65912_vsel_to_uv_range3(selector);
+               break;
+       }
+       return voltage;
+}
+
+static int tps65912_list_voltage_ldo(struct regulator_dev *dev,
+                                       unsigned selector)
+{
+       int ldo = rdev_get_id(dev);
+
+       if (ldo < TPS65912_REG_LDO1 || ldo > TPS65912_REG_LDO10)
+               return -EINVAL;
+
+       return tps65912_vsel_to_uv_ldo(selector);
+}
+
+/* Operations permitted on DCDCx */
+static struct regulator_ops tps65912_ops_dcdc = {
+       .is_enabled = tps65912_reg_is_enabled,
+       .enable = tps65912_reg_enable,
+       .disable = tps65912_reg_disable,
+       .set_mode = tps65912_set_mode,
+       .get_mode = tps65912_get_mode,
+       .get_voltage = tps65912_get_voltage_dcdc,
+       .set_voltage_sel = tps65912_set_voltage_dcdc,
+       .list_voltage = tps65912_list_voltage_dcdc,
+};
+
+/* Operations permitted on LDOx */
+static struct regulator_ops tps65912_ops_ldo = {
+       .is_enabled = tps65912_reg_is_enabled,
+       .enable = tps65912_reg_enable,
+       .disable = tps65912_reg_disable,
+       .get_voltage = tps65912_get_voltage_ldo,
+       .set_voltage_sel = tps65912_set_voltage_ldo,
+       .list_voltage = tps65912_list_voltage_ldo,
+};
+
+static __devinit int tps65912_probe(struct platform_device *pdev)
+{
+       struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent);
+       struct tps_info *info;
+       struct regulator_init_data *reg_data;
+       struct regulator_dev *rdev;
+       struct tps65912_reg *pmic;
+       struct tps65912_board *pmic_plat_data;
+       int i, err;
+
+       pmic_plat_data = dev_get_platdata(tps65912->dev);
+       if (!pmic_plat_data)
+               return -EINVAL;
+
+       reg_data = pmic_plat_data->tps65912_pmic_init_data;
+
+       pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
+       if (!pmic)
+               return -ENOMEM;
+
+       mutex_init(&pmic->io_lock);
+       pmic->mfd = tps65912;
+       platform_set_drvdata(pdev, pmic);
+
+       pmic->get_ctrl_reg = &tps65912_get_ctrl_register;
+       info = tps65912_regs;
+
+       for (i = 0; i < TPS65912_NUM_REGULATOR; i++, info++, reg_data++) {
+               int range = 0;
+               /* Register the regulators */
+               pmic->info[i] = info;
+
+               pmic->desc[i].name = info->name;
+               pmic->desc[i].id = i;
+               pmic->desc[i].n_voltages = 64;
+               pmic->desc[i].ops = (i > TPS65912_REG_DCDC4 ?
+                       &tps65912_ops_ldo : &tps65912_ops_dcdc);
+               pmic->desc[i].type = REGULATOR_VOLTAGE;
+               pmic->desc[i].owner = THIS_MODULE;
+               range = tps65912_get_range(pmic, i);
+               rdev = regulator_register(&pmic->desc[i],
+                                       tps65912->dev, reg_data, pmic);
+               if (IS_ERR(rdev)) {
+                       dev_err(tps65912->dev,
+                               "failed to register %s regulator\n",
+                               pdev->name);
+                       err = PTR_ERR(rdev);
+                       goto err;
+               }
+
+               /* Save regulator for cleanup */
+               pmic->rdev[i] = rdev;
+       }
+       return 0;
+
+err:
+       while (--i >= 0)
+               regulator_unregister(pmic->rdev[i]);
+
+       kfree(pmic);
+       return err;
+}
+
+static int __devexit tps65912_remove(struct platform_device *pdev)
+{
+       struct tps65912_reg *tps65912_reg = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < TPS65912_NUM_REGULATOR; i++)
+               regulator_unregister(tps65912_reg->rdev[i]);
+
+       kfree(tps65912_reg);
+       return 0;
+}
+
+static struct platform_driver tps65912_driver = {
+       .driver = {
+               .name = "tps65912-pmic",
+               .owner = THIS_MODULE,
+       },
+       .probe = tps65912_probe,
+       .remove = __devexit_p(tps65912_remove),
+};
+
+/**
+ * tps65912_init
+ *
+ * Module init function
+ */
+static int __init tps65912_init(void)
+{
+       return platform_driver_register(&tps65912_driver);
+}
+subsys_initcall(tps65912_init);
+
+/**
+ * tps65912_cleanup
+ *
+ * Module exit function
+ */
+static void __exit tps65912_cleanup(void)
+{
+       platform_driver_unregister(&tps65912_driver);
+}
+module_exit(tps65912_cleanup);
+
+MODULE_AUTHOR("Margarita Olaya Cabrera <magi@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS65912 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65912-pmic");
index 081c171a1ed60965d3c47701a409fc263fd6ece3..5ce5170254caaabd2ce81d0438e5523c001ffaca 100644 (file)
@@ -397,7 +397,7 @@ struct amap_pdu_data_out {
 };
 
 struct be_cmd_bhs {
-       struct iscsi_cmd iscsi_hdr;
+       struct iscsi_scsi_req iscsi_hdr;
        unsigned char pad1[16];
        struct pdu_data_out iscsi_data_pdu;
        unsigned char pad2[BE_SENSE_INFO_SIZE -
@@ -428,7 +428,7 @@ struct be_nonio_bhs {
 };
 
 struct be_status_bhs {
-       struct iscsi_cmd iscsi_hdr;
+       struct iscsi_scsi_req iscsi_hdr;
        unsigned char pad1[16];
        /**
         * The plus 2 below is to hold the sense info length that gets
index 3b0af1102bf418255d6a44fb78c670fc63cd9a78..a796de9350541a4fcae375681bb911d1fc27ec00 100644 (file)
@@ -27,6 +27,7 @@
 struct bfa_s;
 
 typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m);
+typedef void (*bfa_cb_cbfn_status_t) (void *cbarg, bfa_status_t status);
 
 /*
  * Interrupt message handlers
@@ -121,6 +122,7 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
 #define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do {    \
                (__hcb_qe)->cbfn  = (__cbfn);      \
                (__hcb_qe)->cbarg = (__cbarg);      \
+               (__hcb_qe)->pre_rmv = BFA_FALSE;                \
                list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q);      \
        } while (0)
 
@@ -135,6 +137,11 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
                }                                                       \
        } while (0)
 
+#define bfa_cb_queue_status(__bfa, __hcb_qe, __status) do {            \
+               (__hcb_qe)->fw_status = (__status);                     \
+               list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q);       \
+} while (0)
+
 #define bfa_cb_queue_done(__hcb_qe) do {       \
                (__hcb_qe)->once = BFA_FALSE;   \
        } while (0)
@@ -177,7 +184,7 @@ struct bfa_msix_s {
 struct bfa_hwif_s {
        void (*hw_reginit)(struct bfa_s *bfa);
        void (*hw_reqq_ack)(struct bfa_s *bfa, int reqq);
-       void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq);
+       void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq, u32 ci);
        void (*hw_msix_init)(struct bfa_s *bfa, int nvecs);
        void (*hw_msix_ctrl_install)(struct bfa_s *bfa);
        void (*hw_msix_queue_install)(struct bfa_s *bfa);
@@ -268,10 +275,8 @@ struct bfa_iocfc_s {
        ((__bfa)->iocfc.hwif.hw_msix_queue_install(__bfa))
 #define bfa_msix_uninstall(__bfa)                                      \
        ((__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa))
-#define bfa_isr_rspq_ack(__bfa, __queue) do {                          \
-       if ((__bfa)->iocfc.hwif.hw_rspq_ack)                            \
-               (__bfa)->iocfc.hwif.hw_rspq_ack(__bfa, __queue);        \
-} while (0)
+#define bfa_isr_rspq_ack(__bfa, __queue, __ci)                         \
+       ((__bfa)->iocfc.hwif.hw_rspq_ack(__bfa, __queue, __ci))
 #define bfa_isr_reqq_ack(__bfa, __queue) do {                          \
        if ((__bfa)->iocfc.hwif.hw_reqq_ack)                            \
                (__bfa)->iocfc.hwif.hw_reqq_ack(__bfa, __queue);        \
@@ -311,7 +316,7 @@ void bfa_msix_rspq(struct bfa_s *bfa, int vec);
 void bfa_msix_lpu_err(struct bfa_s *bfa, int vec);
 
 void bfa_hwcb_reginit(struct bfa_s *bfa);
-void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq);
+void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci);
 void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs);
 void bfa_hwcb_msix_ctrl_install(struct bfa_s *bfa);
 void bfa_hwcb_msix_queue_install(struct bfa_s *bfa);
@@ -324,7 +329,8 @@ void bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start,
 void bfa_hwct_reginit(struct bfa_s *bfa);
 void bfa_hwct2_reginit(struct bfa_s *bfa);
 void bfa_hwct_reqq_ack(struct bfa_s *bfa, int rspq);
-void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq);
+void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci);
+void bfa_hwct2_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci);
 void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs);
 void bfa_hwct_msix_ctrl_install(struct bfa_s *bfa);
 void bfa_hwct_msix_queue_install(struct bfa_s *bfa);
@@ -376,6 +382,22 @@ int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa,
 #define bfa_get_fw_clock_res(__bfa)            \
        ((__bfa)->iocfc.cfgrsp->fwcfg.fw_tick_res)
 
+/*
+ * lun mask macros return NULL when min cfg is enabled and there is
+ * no memory allocated for lunmask.
+ */
+#define bfa_get_lun_mask(__bfa)                                        \
+       ((&(__bfa)->modules.dconf_mod)->min_cfg) ? NULL :       \
+        (&(BFA_DCONF_MOD(__bfa)->dconf->lun_mask))
+
+#define bfa_get_lun_mask_list(_bfa)                            \
+       ((&(_bfa)->modules.dconf_mod)->min_cfg) ? NULL :        \
+        (bfa_get_lun_mask(_bfa)->lun_list)
+
+#define bfa_get_lun_mask_status(_bfa)                          \
+       (((&(_bfa)->modules.dconf_mod)->min_cfg)                \
+        ? BFA_LUNMASK_MINCFG : ((bfa_get_lun_mask(_bfa))->status))
+
 void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids);
 void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg);
 void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg);
@@ -406,7 +428,22 @@ bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa,
 
 void bfa_iocfc_enable(struct bfa_s *bfa);
 void bfa_iocfc_disable(struct bfa_s *bfa);
+void bfa_iocfc_cb_dconf_modinit(struct bfa_s *bfa, bfa_status_t status);
 #define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout)                \
        bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout)
 
+struct bfa_cb_pending_q_s {
+       struct bfa_cb_qe_s      hcb_qe;
+       void                    *data;  /* Driver buffer */
+};
+
+/* Common macros to operate on pending stats/attr apis */
+#define bfa_pending_q_init(__qe, __cbfn, __cbarg, __data) do { \
+       bfa_q_qe_init(&((__qe)->hcb_qe.qe));                    \
+       (__qe)->hcb_qe.cbfn = (__cbfn);                         \
+       (__qe)->hcb_qe.cbarg = (__cbarg);                       \
+       (__qe)->hcb_qe.pre_rmv = BFA_TRUE;                      \
+       (__qe)->data = (__data);                                \
+} while (0)
+
 #endif /* __BFA_H__ */
index c38e589105a5551ece1d3e0a93b805bc6f1b015c..4bd546bcc240740fdadd04fd435828b4dc94f4f6 100644 (file)
@@ -33,6 +33,7 @@ static struct bfa_module_s *hal_mods[] = {
        &hal_mod_uf,
        &hal_mod_rport,
        &hal_mod_fcp,
+       &hal_mod_dconf,
        NULL
 };
 
@@ -237,8 +238,6 @@ bfa_isr_rspq(struct bfa_s *bfa, int qid)
        u32     pi, ci;
        struct list_head *waitq;
 
-       bfa_isr_rspq_ack(bfa, qid);
-
        ci = bfa_rspq_ci(bfa, qid);
        pi = bfa_rspq_pi(bfa, qid);
 
@@ -251,11 +250,9 @@ bfa_isr_rspq(struct bfa_s *bfa, int qid)
        }
 
        /*
-        * update CI
+        * acknowledge RME completions and update CI
         */
-       bfa_rspq_ci(bfa, qid) = pi;
-       writel(pi, bfa->iocfc.bfa_regs.rme_q_ci[qid]);
-       mmiowb();
+       bfa_isr_rspq_ack(bfa, qid, ci);
 
        /*
         * Resume any pending requests in the corresponding reqq.
@@ -325,23 +322,19 @@ bfa_intx(struct bfa_s *bfa)
        int queue;
 
        intr = readl(bfa->iocfc.bfa_regs.intr_status);
-       if (!intr)
-               return BFA_FALSE;
 
        qintr = intr & (__HFN_INT_RME_MASK | __HFN_INT_CPE_MASK);
        if (qintr)
                writel(qintr, bfa->iocfc.bfa_regs.intr_status);
 
        /*
-        * RME completion queue interrupt
+        * Unconditional RME completion queue interrupt
         */
-       qintr = intr & __HFN_INT_RME_MASK;
-       if (qintr && bfa->queue_process) {
+       if (bfa->queue_process) {
                for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++)
                        bfa_isr_rspq(bfa, queue);
        }
 
-       intr &= ~qintr;
        if (!intr)
                return BFA_TRUE;
 
@@ -432,7 +425,8 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec)
                                   __HFN_INT_MBOX_LPU1_CT2);
                intr    &= __HFN_INT_ERR_MASK_CT2;
        } else {
-               halt_isr = intr & __HFN_INT_LL_HALT;
+               halt_isr = bfa_asic_id_ct(bfa->ioc.pcidev.device_id) ?
+                                         (intr & __HFN_INT_LL_HALT) : 0;
                pss_isr  = intr & __HFN_INT_ERR_PSS;
                lpu_isr  = intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1);
                intr    &= __HFN_INT_ERR_MASK;
@@ -578,7 +572,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        } else {
                iocfc->hwif.hw_reginit = bfa_hwcb_reginit;
                iocfc->hwif.hw_reqq_ack = NULL;
-               iocfc->hwif.hw_rspq_ack = NULL;
+               iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack;
                iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init;
                iocfc->hwif.hw_msix_ctrl_install = bfa_hwcb_msix_ctrl_install;
                iocfc->hwif.hw_msix_queue_install = bfa_hwcb_msix_queue_install;
@@ -595,7 +589,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
        if (bfa_asic_id_ct2(bfa_ioc_devid(&bfa->ioc))) {
                iocfc->hwif.hw_reginit = bfa_hwct2_reginit;
                iocfc->hwif.hw_isr_mode_set = NULL;
-               iocfc->hwif.hw_rspq_ack = NULL;
+               iocfc->hwif.hw_rspq_ack = bfa_hwct2_rspq_ack;
        }
 
        iocfc->hwif.hw_reginit(bfa);
@@ -685,7 +679,7 @@ bfa_iocfc_start_submod(struct bfa_s *bfa)
 
        bfa->queue_process = BFA_TRUE;
        for (i = 0; i < BFI_IOC_MAX_CQS; i++)
-               bfa_isr_rspq_ack(bfa, i);
+               bfa_isr_rspq_ack(bfa, i, bfa_rspq_ci(bfa, i));
 
        for (i = 0; hal_mods[i]; i++)
                hal_mods[i]->start(bfa);
@@ -709,7 +703,7 @@ bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete)
        struct bfa_s    *bfa = bfa_arg;
 
        if (complete) {
-               if (bfa->iocfc.cfgdone)
+               if (bfa->iocfc.cfgdone && BFA_DCONF_MOD(bfa)->flashdone)
                        bfa_cb_init(bfa->bfad, BFA_STATUS_OK);
                else
                        bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED);
@@ -822,9 +816,11 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa)
         */
        bfa_fcport_init(bfa);
 
-       if (iocfc->action == BFA_IOCFC_ACT_INIT)
-               bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa);
-       else {
+       if (iocfc->action == BFA_IOCFC_ACT_INIT) {
+               if (BFA_DCONF_MOD(bfa)->flashdone == BFA_TRUE)
+                       bfa_cb_queue(bfa, &iocfc->init_hcb_qe,
+                               bfa_iocfc_init_cb, bfa);
+       } else {
                if (bfa->iocfc.action == BFA_IOCFC_ACT_ENABLE)
                        bfa_cb_queue(bfa, &bfa->iocfc.en_hcb_qe,
                                        bfa_iocfc_enable_cb, bfa);
@@ -1045,6 +1041,7 @@ bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status)
        }
 
        bfa_iocfc_send_cfg(bfa);
+       bfa_dconf_modinit(bfa);
 }
 
 /*
@@ -1207,7 +1204,9 @@ bfa_iocfc_stop(struct bfa_s *bfa)
        bfa->iocfc.action = BFA_IOCFC_ACT_STOP;
 
        bfa->queue_process = BFA_FALSE;
-       bfa_ioc_disable(&bfa->ioc);
+       bfa_dconf_modexit(bfa);
+       if (BFA_DCONF_MOD(bfa)->flashdone == BFA_TRUE)
+               bfa_ioc_disable(&bfa->ioc);
 }
 
 void
@@ -1540,10 +1539,17 @@ bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q)
        struct list_head                *qe;
        struct list_head                *qen;
        struct bfa_cb_qe_s      *hcb_qe;
+       bfa_cb_cbfn_status_t    cbfn;
 
        list_for_each_safe(qe, qen, comp_q) {
                hcb_qe = (struct bfa_cb_qe_s *) qe;
-               hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE);
+               if (hcb_qe->pre_rmv) {
+                       /* qe is invalid after return, dequeue before cbfn() */
+                       list_del(qe);
+                       cbfn = (bfa_cb_cbfn_status_t)(hcb_qe->cbfn);
+                       cbfn(hcb_qe->cbarg, hcb_qe->fw_status);
+               } else
+                       hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE);
        }
 }
 
@@ -1556,10 +1562,20 @@ bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q)
        while (!list_empty(comp_q)) {
                bfa_q_deq(comp_q, &qe);
                hcb_qe = (struct bfa_cb_qe_s *) qe;
+               WARN_ON(hcb_qe->pre_rmv);
                hcb_qe->cbfn(hcb_qe->cbarg, BFA_FALSE);
        }
 }
 
+void
+bfa_iocfc_cb_dconf_modinit(struct bfa_s *bfa, bfa_status_t status)
+{
+       if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) {
+               if (bfa->iocfc.cfgdone == BFA_TRUE)
+                       bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe,
+                               bfa_iocfc_init_cb, bfa);
+       }
+}
 
 /*
  * Return the list of PCI vendor/device id lists supported by this
index ed8d31b0188b12bf6933f209776a4d7c84346f0b..7b3d235d20b4638fb62d270b5a5a37980230055e 100644 (file)
@@ -144,6 +144,7 @@ enum bfa_status {
        BFA_STATUS_INVLD_DFSZ   = 24,   /*  Invalid Max data field size */
        BFA_STATUS_CMD_NOTSUPP  = 26,   /*  Command/API not supported */
        BFA_STATUS_FABRIC_RJT   = 29,   /*  Reject from attached fabric */
+       BFA_STATUS_UNKNOWN_VWWN = 30,   /*  VPORT PWWN not found */
        BFA_STATUS_PORT_OFFLINE = 34,   /*  Port is not online */
        BFA_STATUS_VPORT_WWN_BP = 46,   /*  WWN is same as base port's WWN */
        BFA_STATUS_PORT_NOT_DISABLED = 47, /* Port not disabled disable port */
@@ -164,6 +165,8 @@ enum bfa_status {
        BFA_STATUS_INVALID_MAC  = 134, /*  Invalid MAC address */
        BFA_STATUS_PBC          = 154, /*  Operation not allowed for pre-boot
                                        *  configuration */
+       BFA_STATUS_BAD_FWCFG = 156,     /* Bad firmware configuration */
+       BFA_STATUS_INVALID_VENDOR = 158, /* Invalid switch vendor */
        BFA_STATUS_SFP_NOT_READY = 159, /* SFP info is not ready. Retry */
        BFA_STATUS_TRUNK_ENABLED = 164, /* Trunk is already enabled on
                                         * this adapter */
@@ -172,11 +175,15 @@ enum bfa_status {
        BFA_STATUS_IOPROFILE_OFF = 175, /* IO profile OFF */
        BFA_STATUS_PHY_NOT_PRESENT = 183, /* PHY module not present */
        BFA_STATUS_FEATURE_NOT_SUPPORTED = 192, /* Feature not supported */
+       BFA_STATUS_ENTRY_EXISTS = 193,  /* Entry already exists */
+       BFA_STATUS_ENTRY_NOT_EXISTS = 194, /* Entry does not exist */
+       BFA_STATUS_NO_CHANGE = 195,     /* Feature already in that state */
        BFA_STATUS_FAA_ENABLED = 197,   /* FAA is already enabled */
        BFA_STATUS_FAA_DISABLED = 198,  /* FAA is already disabled */
        BFA_STATUS_FAA_ACQUIRED = 199,  /* FAA is already acquired */
        BFA_STATUS_FAA_ACQ_ADDR = 200,  /* Acquiring addr */
        BFA_STATUS_ERROR_TRUNK_ENABLED = 203,   /* Trunk enabled on adapter */
+       BFA_STATUS_MAX_ENTRY_REACHED = 212,     /* MAX entry reached */
        BFA_STATUS_MAX_VAL              /* Unknown error code */
 };
 #define bfa_status_t enum bfa_status
@@ -358,6 +365,139 @@ struct bfa_ioc_attr_s {
        u8                              rsvd[4];        /*  64bit align */
 };
 
+/*
+ *                     AEN related definitions
+ */
+enum bfa_aen_category {
+       BFA_AEN_CAT_ADAPTER     = 1,
+       BFA_AEN_CAT_PORT        = 2,
+       BFA_AEN_CAT_LPORT       = 3,
+       BFA_AEN_CAT_RPORT       = 4,
+       BFA_AEN_CAT_ITNIM       = 5,
+       BFA_AEN_CAT_AUDIT       = 8,
+       BFA_AEN_CAT_IOC         = 9,
+};
+
+/* BFA adapter level events */
+enum bfa_adapter_aen_event {
+       BFA_ADAPTER_AEN_ADD     = 1,    /* New Adapter found event */
+       BFA_ADAPTER_AEN_REMOVE  = 2,    /* Adapter removed event */
+};
+
+struct bfa_adapter_aen_data_s {
+       char    serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+       u32     nports; /* Number of NPorts */
+       wwn_t   pwwn;   /* WWN of one of its physical port */
+};
+
+/* BFA physical port Level events */
+enum bfa_port_aen_event {
+       BFA_PORT_AEN_ONLINE     = 1,    /* Physical Port online event */
+       BFA_PORT_AEN_OFFLINE    = 2,    /* Physical Port offline event */
+       BFA_PORT_AEN_RLIR       = 3,    /* RLIR event, not supported */
+       BFA_PORT_AEN_SFP_INSERT = 4,    /* SFP inserted event */
+       BFA_PORT_AEN_SFP_REMOVE = 5,    /* SFP removed event */
+       BFA_PORT_AEN_SFP_POM    = 6,    /* SFP POM event */
+       BFA_PORT_AEN_ENABLE     = 7,    /* Physical Port enable event */
+       BFA_PORT_AEN_DISABLE    = 8,    /* Physical Port disable event */
+       BFA_PORT_AEN_AUTH_ON    = 9,    /* Physical Port auth success event */
+       BFA_PORT_AEN_AUTH_OFF   = 10,   /* Physical Port auth fail event */
+       BFA_PORT_AEN_DISCONNECT = 11,   /* Physical Port disconnect event */
+       BFA_PORT_AEN_QOS_NEG    = 12,   /* Base Port QOS negotiation event */
+       BFA_PORT_AEN_FABRIC_NAME_CHANGE = 13, /* Fabric Name/WWN change */
+       BFA_PORT_AEN_SFP_ACCESS_ERROR   = 14, /* SFP read error event */
+       BFA_PORT_AEN_SFP_UNSUPPORT      = 15, /* Unsupported SFP event */
+};
+
+enum bfa_port_aen_sfp_pom {
+       BFA_PORT_AEN_SFP_POM_GREEN = 1, /* Normal */
+       BFA_PORT_AEN_SFP_POM_AMBER = 2, /* Warning */
+       BFA_PORT_AEN_SFP_POM_RED   = 3, /* Critical */
+       BFA_PORT_AEN_SFP_POM_MAX   = BFA_PORT_AEN_SFP_POM_RED
+};
+
+struct bfa_port_aen_data_s {
+       wwn_t           pwwn;           /* WWN of the physical port */
+       wwn_t           fwwn;           /* WWN of the fabric port */
+       u32             phy_port_num;   /* For SFP related events */
+       u16             ioc_type;
+       u16             level;          /* Only transitions will be informed */
+       mac_t           mac;            /* MAC address of the ethernet port */
+       u16             rsvd;
+};
+
+/* BFA AEN logical port events */
+enum bfa_lport_aen_event {
+       BFA_LPORT_AEN_NEW       = 1,            /* LPort created event */
+       BFA_LPORT_AEN_DELETE    = 2,            /* LPort deleted event */
+       BFA_LPORT_AEN_ONLINE    = 3,            /* LPort online event */
+       BFA_LPORT_AEN_OFFLINE   = 4,            /* LPort offline event */
+       BFA_LPORT_AEN_DISCONNECT = 5,           /* LPort disconnect event */
+       BFA_LPORT_AEN_NEW_PROP  = 6,            /* VPort created event */
+       BFA_LPORT_AEN_DELETE_PROP = 7,          /* VPort deleted event */
+       BFA_LPORT_AEN_NEW_STANDARD = 8,         /* VPort created event */
+       BFA_LPORT_AEN_DELETE_STANDARD = 9,      /* VPort deleted event */
+       BFA_LPORT_AEN_NPIV_DUP_WWN = 10,        /* VPort with duplicate WWN */
+       BFA_LPORT_AEN_NPIV_FABRIC_MAX = 11,     /* Max NPIV in fabric/fport */
+       BFA_LPORT_AEN_NPIV_UNKNOWN = 12,        /* Unknown NPIV Error code */
+};
+
+struct bfa_lport_aen_data_s {
+       u16     vf_id;  /* vf_id of this logical port */
+       u16     roles;  /* Logical port mode,IM/TM/IP etc */
+       u32     rsvd;
+       wwn_t   ppwwn;  /* WWN of its physical port */
+       wwn_t   lpwwn;  /* WWN of this logical port */
+};
+
+/* BFA ITNIM events */
+enum bfa_itnim_aen_event {
+       BFA_ITNIM_AEN_ONLINE     = 1,   /* Target online */
+       BFA_ITNIM_AEN_OFFLINE    = 2,   /* Target offline */
+       BFA_ITNIM_AEN_DISCONNECT = 3,   /* Target disconnected */
+};
+
+struct bfa_itnim_aen_data_s {
+       u16             vf_id;          /* vf_id of the IT nexus */
+       u16             rsvd[3];
+       wwn_t           ppwwn;          /* WWN of its physical port */
+       wwn_t           lpwwn;          /* WWN of logical port */
+       wwn_t           rpwwn;          /* WWN of remote(target) port */
+};
+
+/* BFA audit events */
+enum bfa_audit_aen_event {
+       BFA_AUDIT_AEN_AUTH_ENABLE       = 1,
+       BFA_AUDIT_AEN_AUTH_DISABLE      = 2,
+       BFA_AUDIT_AEN_FLASH_ERASE       = 3,
+       BFA_AUDIT_AEN_FLASH_UPDATE      = 4,
+};
+
+struct bfa_audit_aen_data_s {
+       wwn_t   pwwn;
+       int     partition_inst;
+       int     partition_type;
+};
+
+/* BFA IOC level events */
+enum bfa_ioc_aen_event {
+       BFA_IOC_AEN_HBGOOD  = 1,        /* Heart Beat restore event     */
+       BFA_IOC_AEN_HBFAIL  = 2,        /* Heart Beat failure event     */
+       BFA_IOC_AEN_ENABLE  = 3,        /* IOC enabled event            */
+       BFA_IOC_AEN_DISABLE = 4,        /* IOC disabled event           */
+       BFA_IOC_AEN_FWMISMATCH  = 5,    /* IOC firmware mismatch        */
+       BFA_IOC_AEN_FWCFG_ERROR = 6,    /* IOC firmware config error    */
+       BFA_IOC_AEN_INVALID_VENDOR = 7,
+       BFA_IOC_AEN_INVALID_NWWN = 8,   /* Zero NWWN                    */
+       BFA_IOC_AEN_INVALID_PWWN = 9    /* Zero PWWN                    */
+};
+
+struct bfa_ioc_aen_data_s {
+       wwn_t   pwwn;
+       u16     ioc_type;
+       mac_t   mac;
+};
+
 /*
  * ---------------------- mfg definitions ------------
  */
@@ -520,6 +660,20 @@ struct bfa_boot_bootlun_s {
 /*
  * BOOT boot configuraton
  */
+struct bfa_boot_cfg_s {
+       u8              version;
+       u8              rsvd1;
+       u16             chksum;
+       u8              enable;         /* enable/disable SAN boot */
+       u8              speed;          /* boot speed settings */
+       u8              topology;       /* boot topology setting */
+       u8              bootopt;        /* bfa_boot_bootopt_t */
+       u32             nbluns;         /* number of boot luns */
+       u32             rsvd2;
+       struct bfa_boot_bootlun_s blun[BFA_BOOT_BOOTLUN_MAX];
+       struct bfa_boot_bootlun_s blun_disc[BFA_BOOT_BOOTLUN_MAX];
+};
+
 struct bfa_boot_pbc_s {
        u8              enable;         /*  enable/disable SAN boot */
        u8              speed;          /*  boot speed settings */
@@ -529,6 +683,15 @@ struct bfa_boot_pbc_s {
        struct bfa_boot_bootlun_s pblun[BFA_PREBOOT_BOOTLUN_MAX];
 };
 
+struct bfa_ethboot_cfg_s {
+       u8              version;
+       u8              rsvd1;
+       u16             chksum;
+       u8              enable; /* enable/disable Eth/PXE boot */
+       u8              rsvd2;
+       u16             vlan;
+};
+
 /*
  * ASIC block configuration related structures
  */
@@ -587,6 +750,14 @@ struct bfa_ablk_cfg_s {
  */
 #define SFP_DIAGMON_SIZE       10 /* num bytes of diag monitor data */
 
+/* SFP state change notification event */
+#define BFA_SFP_SCN_REMOVED    0
+#define BFA_SFP_SCN_INSERTED   1
+#define BFA_SFP_SCN_POM                2
+#define BFA_SFP_SCN_FAILED     3
+#define BFA_SFP_SCN_UNSUPPORT  4
+#define BFA_SFP_SCN_VALID      5
+
 enum bfa_defs_sfp_media_e {
        BFA_SFP_MEDIA_UNKNOWN   = 0x00,
        BFA_SFP_MEDIA_CU        = 0x01,
index 0b97525803fb64db6516dc23582bde52c943990f..863c6ba7d5eb0c817bfa7f3975a9d3de981cc8be 100644 (file)
@@ -268,6 +268,7 @@ struct bfa_fw_port_snsm_stats_s {
     u32    error_resets;       /*  error resets initiated by upsm      */
     u32    sync_lost;          /*  Sync loss count                     */
     u32    sig_lost;           /*  Signal loss count                   */
+       u32     asn8g_attempts; /* SNSM HWSM at 8Gbps attempts */
 };
 
 struct bfa_fw_port_physm_stats_s {
@@ -468,6 +469,7 @@ struct bfa_fw_stats_s {
  * QoS states
  */
 enum bfa_qos_state {
+       BFA_QOS_DISABLED = 0,           /* QoS is disabled */
        BFA_QOS_ONLINE = 1,             /*  QoS is online */
        BFA_QOS_OFFLINE = 2,            /*  QoS is offline */
 };
@@ -670,6 +672,12 @@ struct bfa_itnim_iostats_s {
        u32     tm_iocdowns;            /*  TM cleaned-up due to IOC down   */
        u32     tm_cleanups;            /*  TM cleanup requests */
        u32     tm_cleanup_comps;       /*  TM cleanup completions      */
+       u32     lm_lun_across_sg;       /*  LM lun is across sg data buf */
+       u32     lm_lun_not_sup;         /*  LM lun not supported */
+       u32     lm_rpl_data_changed;    /*  LM report-lun data changed */
+       u32     lm_wire_residue_changed; /* LM report-lun rsp residue changed */
+       u32     lm_small_buf_addresidue; /* LM buf smaller than reported cnt */
+       u32     lm_lun_not_rdy;         /* LM lun not ready */
 };
 
 /* Modify char* port_stt[] in bfal_port.c if a new state was added */
@@ -785,7 +793,50 @@ enum bfa_port_linkstate_rsn {
        CEE_ISCSI_PRI_PFC_OFF                   = 42,
        CEE_ISCSI_PRI_OVERLAP_FCOE_PRI          = 43
 };
+
+#define MAX_LUN_MASK_CFG 16
+
+/*
+ * Initially flash content may be fff. On making LUN mask enable and disable
+ * state chnage.  when report lun command is being processed it goes from
+ * BFA_LUN_MASK_ACTIVE to BFA_LUN_MASK_FETCH and comes back to
+ * BFA_LUN_MASK_ACTIVE.
+ */
+enum bfa_ioim_lun_mask_state_s {
+       BFA_IOIM_LUN_MASK_INACTIVE = 0,
+       BFA_IOIM_LUN_MASK_ACTIVE = 1,
+       BFA_IOIM_LUN_MASK_FETCHED = 2,
+};
+
+enum bfa_lunmask_state_s {
+       BFA_LUNMASK_DISABLED = 0x00,
+       BFA_LUNMASK_ENABLED = 0x01,
+       BFA_LUNMASK_MINCFG = 0x02,
+       BFA_LUNMASK_UNINITIALIZED = 0xff,
+};
+
 #pragma pack(1)
+/*
+ * LUN mask configuration
+ */
+struct bfa_lun_mask_s {
+       wwn_t           lp_wwn;
+       wwn_t           rp_wwn;
+       struct scsi_lun lun;
+       u8              ua;
+       u8              rsvd[3];
+       u16             rp_tag;
+       u8              lp_tag;
+       u8              state;
+};
+
+#define MAX_LUN_MASK_CFG 16
+struct bfa_lunmask_cfg_s {
+       u32     status;
+       u32     rsvd;
+       struct bfa_lun_mask_s   lun_list[MAX_LUN_MASK_CFG];
+};
+
 /*
  *      Physical port configuration
  */
@@ -1228,4 +1279,52 @@ struct bfa_cee_stats_s {
 
 #pragma pack()
 
+/*
+ *                     AEN related definitions
+ */
+#define BFAD_NL_VENDOR_ID (((u64)0x01 << SCSI_NL_VID_TYPE_SHIFT) \
+                          | BFA_PCI_VENDOR_ID_BROCADE)
+
+/* BFA remote port events */
+enum bfa_rport_aen_event {
+       BFA_RPORT_AEN_ONLINE     = 1,   /* RPort online event */
+       BFA_RPORT_AEN_OFFLINE    = 2,   /* RPort offline event */
+       BFA_RPORT_AEN_DISCONNECT = 3,   /* RPort disconnect event */
+       BFA_RPORT_AEN_QOS_PRIO   = 4,   /* QOS priority change event */
+       BFA_RPORT_AEN_QOS_FLOWID = 5,   /* QOS flow Id change event */
+};
+
+struct bfa_rport_aen_data_s {
+       u16             vf_id;  /* vf_id of this logical port */
+       u16             rsvd[3];
+       wwn_t           ppwwn;  /* WWN of its physical port */
+       wwn_t           lpwwn;  /* WWN of this logical port */
+       wwn_t           rpwwn;  /* WWN of this remote port */
+       union {
+               struct bfa_rport_qos_attr_s qos;
+       } priv;
+};
+
+union bfa_aen_data_u {
+       struct bfa_adapter_aen_data_s   adapter;
+       struct bfa_port_aen_data_s      port;
+       struct bfa_lport_aen_data_s     lport;
+       struct bfa_rport_aen_data_s     rport;
+       struct bfa_itnim_aen_data_s     itnim;
+       struct bfa_audit_aen_data_s     audit;
+       struct bfa_ioc_aen_data_s       ioc;
+};
+
+#define BFA_AEN_MAX_ENTRY      512
+
+struct bfa_aen_entry_s {
+       struct list_head        qe;
+       enum bfa_aen_category   aen_category;
+       u32                     aen_type;
+       union bfa_aen_data_u    aen_data;
+       struct timeval          aen_tv;
+       u32                     seq_num;
+       u32                     bfad_num;
+};
+
 #endif /* __BFA_DEFS_SVC_H__ */
index 8d0b88f67a382e3582c40382d7dfe3892a19f3c8..50b6a1c86195ac6d6c394295fcdd8150dbd43852 100644 (file)
@@ -56,6 +56,161 @@ struct scsi_cdb_s {
 
 #define SCSI_MAX_ALLOC_LEN      0xFF    /* maximum allocarion length */
 
+#define SCSI_SENSE_CUR_ERR     0x70
+#define SCSI_SENSE_DEF_ERR     0x71
+
+/*
+ * SCSI additional sense codes
+ */
+#define SCSI_ASC_LUN_NOT_READY         0x04
+#define SCSI_ASC_LUN_NOT_SUPPORTED     0x25
+#define SCSI_ASC_TOCC                  0x3F
+
+/*
+ * SCSI additional sense code qualifiers
+ */
+#define SCSI_ASCQ_MAN_INTR_REQ         0x03    /* manual intervention req */
+#define SCSI_ASCQ_RL_DATA_CHANGED      0x0E    /* report luns data changed */
+
+/*
+ * Methods of reporting informational exceptions
+ */
+#define SCSI_MP_IEC_UNIT_ATTN          0x2     /* generate unit attention */
+
+struct scsi_report_luns_data_s {
+       u32             lun_list_length;        /* length of LUN list length */
+       u32             reserved;
+       struct scsi_lun lun[1];                 /* first LUN in lun list */
+};
+
+struct scsi_inquiry_vendor_s {
+       u8      vendor_id[8];
+};
+
+struct scsi_inquiry_prodid_s {
+       u8      product_id[16];
+};
+
+struct scsi_inquiry_prodrev_s {
+       u8      product_rev[4];
+};
+
+struct scsi_inquiry_data_s {
+#ifdef __BIG_ENDIAN
+       u8              peripheral_qual:3;      /* peripheral qualifier */
+       u8              device_type:5;          /* peripheral device type */
+       u8              rmb:1;                  /* removable medium bit */
+       u8              device_type_mod:7;      /* device type modifier */
+       u8              version;
+       u8              aenc:1;         /* async evt notification capability */
+       u8              trm_iop:1;      /* terminate I/O process */
+       u8              norm_aca:1;     /* normal ACA supported */
+       u8              hi_support:1;   /* SCSI-3: supports REPORT LUNS */
+       u8              rsp_data_format:4;
+       u8              additional_len;
+       u8              sccs:1;
+       u8              reserved1:7;
+       u8              reserved2:1;
+       u8              enc_serv:1;     /* enclosure service component */
+       u8              reserved3:1;
+       u8              multi_port:1;   /* multi-port device */
+       u8              m_chngr:1;      /* device in medium transport element */
+       u8              ack_req_q:1;    /* SIP specific bit */
+       u8              addr32:1;       /* SIP specific bit */
+       u8              addr16:1;       /* SIP specific bit */
+       u8              rel_adr:1;      /* relative address */
+       u8              w_bus32:1;
+       u8              w_bus16:1;
+       u8              synchronous:1;
+       u8              linked_commands:1;
+       u8              trans_dis:1;
+       u8              cmd_queue:1;    /* command queueing supported */
+       u8              soft_reset:1;   /* soft reset alternative (VS) */
+#else
+       u8              device_type:5;  /* peripheral device type */
+       u8              peripheral_qual:3; /* peripheral qualifier */
+       u8              device_type_mod:7; /* device type modifier */
+       u8              rmb:1;          /* removable medium bit */
+       u8              version;
+       u8              rsp_data_format:4;
+       u8              hi_support:1;   /* SCSI-3: supports REPORT LUNS */
+       u8              norm_aca:1;     /* normal ACA supported */
+       u8              terminate_iop:1;/* terminate I/O process */
+       u8              aenc:1;         /* async evt notification capability */
+       u8              additional_len;
+       u8              reserved1:7;
+       u8              sccs:1;
+       u8              addr16:1;       /* SIP specific bit */
+       u8              addr32:1;       /* SIP specific bit */
+       u8              ack_req_q:1;    /* SIP specific bit */
+       u8              m_chngr:1;      /* device in medium transport element */
+       u8              multi_port:1;   /* multi-port device */
+       u8              reserved3:1;    /* TBD - Vendor Specific */
+       u8              enc_serv:1;     /* enclosure service component */
+       u8              reserved2:1;
+       u8              soft_seset:1;   /* soft reset alternative (VS) */
+       u8              cmd_queue:1;    /* command queueing supported */
+       u8              trans_dis:1;
+       u8              linked_commands:1;
+       u8              synchronous:1;
+       u8              w_bus16:1;
+       u8              w_bus32:1;
+       u8              rel_adr:1;      /* relative address */
+#endif
+       struct scsi_inquiry_vendor_s    vendor_id;
+       struct scsi_inquiry_prodid_s    product_id;
+       struct scsi_inquiry_prodrev_s   product_rev;
+       u8              vendor_specific[20];
+       u8              reserved4[40];
+};
+
+/*
+ *     SCSI sense data format
+ */
+struct scsi_sense_s {
+#ifdef __BIG_ENDIAN
+       u8              valid:1;
+       u8              rsp_code:7;
+#else
+       u8              rsp_code:7;
+       u8              valid:1;
+#endif
+       u8              seg_num;
+#ifdef __BIG_ENDIAN
+       u8              file_mark:1;
+       u8              eom:1;          /* end of media */
+       u8              ili:1;          /* incorrect length indicator */
+       u8              reserved:1;
+       u8              sense_key:4;
+#else
+       u8              sense_key:4;
+       u8              reserved:1;
+       u8              ili:1;          /* incorrect length indicator */
+       u8              eom:1;          /* end of media */
+       u8              file_mark:1;
+#endif
+       u8              information[4]; /* device-type or cmd specific info */
+       u8              add_sense_length; /* additional sense length */
+       u8              command_info[4];/* command specific information */
+       u8              asc;            /* additional sense code */
+       u8              ascq;           /* additional sense code qualifier */
+       u8              fru_code;       /* field replaceable unit code */
+#ifdef __BIG_ENDIAN
+       u8              sksv:1;         /* sense key specific valid */
+       u8              c_d:1;          /* command/data bit */
+       u8              res1:2;
+       u8              bpv:1;          /* bit pointer valid */
+       u8              bpointer:3;     /* bit pointer */
+#else
+       u8              bpointer:3;     /* bit pointer */
+       u8              bpv:1;          /* bit pointer valid */
+       u8              res1:2;
+       u8              c_d:1;          /* command/data bit */
+       u8              sksv:1;         /* sense key specific valid */
+#endif
+       u8              fpointer[2];    /* field pointer */
+};
+
 /*
  * Fibre Channel Header Structure (FCHS) definition
  */
index a4e7951c6063c083d4127abb920f876aa774d14e..e07bd4745d8ba5b968ded24e81785096c1535b84 100644 (file)
@@ -24,6 +24,9 @@ BFA_TRC_FILE(HAL, FCPIM);
  *  BFA ITNIM Related definitions
  */
 static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
+static bfa_boolean_t bfa_ioim_lm_proc_rpl_data(struct bfa_ioim_s *ioim);
+static bfa_boolean_t bfa_ioim_lm_proc_inq_data(struct bfa_ioim_s *ioim);
+static void bfa_ioim_lm_init(struct bfa_s *bfa);
 
 #define BFA_ITNIM_FROM_TAG(_fcpim, _tag)                                \
        (((_fcpim)->itnim_arr + ((_tag) & ((_fcpim)->num_itnims - 1))))
@@ -57,6 +60,14 @@ static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
        }                                                               \
 } while (0)
 
+#define bfa_ioim_rp_wwn(__ioim)                                                \
+       (((struct bfa_fcs_rport_s *)                                    \
+        (__ioim)->itnim->rport->rport_drv)->pwwn)
+
+#define bfa_ioim_lp_wwn(__ioim)                                                \
+       ((BFA_LPS_FROM_TAG(BFA_LPS_MOD((__ioim)->bfa),                  \
+       (__ioim)->itnim->rport->rport_info.lp_tag))->pwwn)              \
+
 #define bfa_itnim_sler_cb(__itnim) do {                                        \
        if ((__itnim)->bfa->fcs)                                        \
                bfa_cb_itnim_sler((__itnim)->ditn);      \
@@ -66,6 +77,18 @@ static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim);
        }                                                               \
 } while (0)
 
+enum bfa_ioim_lm_status {
+       BFA_IOIM_LM_PRESENT = 1,
+       BFA_IOIM_LM_LUN_NOT_SUP = 2,
+       BFA_IOIM_LM_RPL_DATA_CHANGED = 3,
+       BFA_IOIM_LM_LUN_NOT_RDY = 4,
+};
+
+enum bfa_ioim_lm_ua_status {
+       BFA_IOIM_LM_UA_RESET = 0,
+       BFA_IOIM_LM_UA_SET = 1,
+};
+
 /*
  *  itnim state machine event
  */
@@ -122,6 +145,9 @@ enum bfa_ioim_event {
        BFA_IOIM_SM_TMDONE      = 16,   /*  IO cleanup from tskim */
        BFA_IOIM_SM_HWFAIL      = 17,   /*  IOC h/w failure event */
        BFA_IOIM_SM_IOTOV       = 18,   /*  ITN offline TOV */
+       BFA_IOIM_SM_LM_LUN_NOT_SUP = 19,/*  lunmask lun not supported */
+       BFA_IOIM_SM_LM_RPL_DC = 20,     /*  lunmask report-lun data changed */
+       BFA_IOIM_SM_LM_LUN_NOT_RDY = 21,/*  lunmask lun not ready */
 };
 
 
@@ -219,6 +245,9 @@ static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete);
 static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete);
 static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete);
 static bfa_boolean_t    bfa_ioim_is_abortable(struct bfa_ioim_s *ioim);
+static void __bfa_cb_ioim_lm_lun_not_sup(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_lm_rpl_dc(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_lm_lun_not_rdy(void *cbarg, bfa_boolean_t complete);
 
 /*
  * forward declaration of BFA IO state machine
@@ -416,6 +445,12 @@ bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats,
        bfa_fcpim_add_iostats(lstats, rstats, output_reqs);
        bfa_fcpim_add_iostats(lstats, rstats, rd_throughput);
        bfa_fcpim_add_iostats(lstats, rstats, wr_throughput);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_lun_across_sg);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_lun_not_sup);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_rpl_data_changed);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_wire_residue_changed);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_small_buf_addresidue);
+       bfa_fcpim_add_iostats(lstats, rstats, lm_lun_not_rdy);
 }
 
 bfa_status_t
@@ -437,6 +472,59 @@ bfa_fcpim_port_iostats(struct bfa_s *bfa,
        return BFA_STATUS_OK;
 }
 
+void
+bfa_ioim_profile_comp(struct bfa_ioim_s *ioim)
+{
+       struct bfa_itnim_latency_s *io_lat =
+                       &(ioim->itnim->ioprofile.io_latency);
+       u32 val, idx;
+
+       val = (u32)(jiffies - ioim->start_time);
+       idx = bfa_ioim_get_index(scsi_bufflen((struct scsi_cmnd *)ioim->dio));
+       bfa_itnim_ioprofile_update(ioim->itnim, idx);
+
+       io_lat->count[idx]++;
+       io_lat->min[idx] = (io_lat->min[idx] < val) ? io_lat->min[idx] : val;
+       io_lat->max[idx] = (io_lat->max[idx] > val) ? io_lat->max[idx] : val;
+       io_lat->avg[idx] += val;
+}
+
+void
+bfa_ioim_profile_start(struct bfa_ioim_s *ioim)
+{
+       ioim->start_time = jiffies;
+}
+
+bfa_status_t
+bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time)
+{
+       struct bfa_itnim_s *itnim;
+       struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa);
+       struct list_head *qe, *qen;
+
+       /* accumulate IO stats from itnim */
+       list_for_each_safe(qe, qen, &fcpim->itnim_q) {
+               itnim = (struct bfa_itnim_s *) qe;
+               bfa_itnim_clear_stats(itnim);
+       }
+       fcpim->io_profile = BFA_TRUE;
+       fcpim->io_profile_start_time = time;
+       fcpim->profile_comp = bfa_ioim_profile_comp;
+       fcpim->profile_start = bfa_ioim_profile_start;
+       return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_fcpim_profile_off(struct bfa_s *bfa)
+{
+       struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa);
+       fcpim->io_profile = BFA_FALSE;
+       fcpim->io_profile_start_time = 0;
+       fcpim->profile_comp = NULL;
+       fcpim->profile_start = NULL;
+       return BFA_STATUS_OK;
+}
+
 u16
 bfa_fcpim_qdepth_get(struct bfa_s *bfa)
 {
@@ -1401,6 +1489,26 @@ bfa_itnim_hold_io(struct bfa_itnim_s *itnim)
                 bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable));
 }
 
+#define bfa_io_lat_clock_res_div       HZ
+#define bfa_io_lat_clock_res_mul       1000
+bfa_status_t
+bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim,
+                       struct bfa_itnim_ioprofile_s *ioprofile)
+{
+       struct bfa_fcpim_s *fcpim = BFA_FCPIM(itnim->bfa);
+       if (!fcpim->io_profile)
+               return BFA_STATUS_IOPROFILE_OFF;
+
+       itnim->ioprofile.index = BFA_IOBUCKET_MAX;
+       itnim->ioprofile.io_profile_start_time =
+                               bfa_io_profile_start_time(itnim->bfa);
+       itnim->ioprofile.clock_res_mul = bfa_io_lat_clock_res_mul;
+       itnim->ioprofile.clock_res_div = bfa_io_lat_clock_res_div;
+       *ioprofile = itnim->ioprofile;
+
+       return BFA_STATUS_OK;
+}
+
 void
 bfa_itnim_clear_stats(struct bfa_itnim_s *itnim)
 {
@@ -1469,7 +1577,28 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
                bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
                WARN_ON(!bfa_q_is_on_q(&ioim->itnim->pending_q, ioim));
                bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
-                               __bfa_cb_ioim_abort, ioim);
+                       __bfa_cb_ioim_abort, ioim);
+               break;
+
+       case BFA_IOIM_SM_LM_LUN_NOT_SUP:
+               bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+               bfa_ioim_move_to_comp_q(ioim);
+               bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+                       __bfa_cb_ioim_lm_lun_not_sup, ioim);
+               break;
+
+       case BFA_IOIM_SM_LM_RPL_DC:
+               bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+               bfa_ioim_move_to_comp_q(ioim);
+               bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+                               __bfa_cb_ioim_lm_rpl_dc, ioim);
+               break;
+
+       case BFA_IOIM_SM_LM_LUN_NOT_RDY:
+               bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+               bfa_ioim_move_to_comp_q(ioim);
+               bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+                       __bfa_cb_ioim_lm_lun_not_rdy, ioim);
                break;
 
        default:
@@ -2009,6 +2138,264 @@ bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
        }
 }
 
+/*
+ * This is called from bfa_fcpim_start after the bfa_init() with flash read
+ * is complete by driver. now invalidate the stale content of lun mask
+ * like unit attention, rp tag and lp tag.
+ */
+static void
+bfa_ioim_lm_init(struct bfa_s *bfa)
+{
+       struct bfa_lun_mask_s *lunm_list;
+       int     i;
+
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return;
+
+       lunm_list = bfa_get_lun_mask_list(bfa);
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               lunm_list[i].ua = BFA_IOIM_LM_UA_RESET;
+               lunm_list[i].lp_tag = BFA_LP_TAG_INVALID;
+               lunm_list[i].rp_tag = BFA_RPORT_TAG_INVALID;
+       }
+}
+
+/*
+ * Validate LUN for LUN masking
+ */
+static enum bfa_ioim_lm_status
+bfa_ioim_lm_check(struct bfa_ioim_s *ioim, struct bfa_lps_s *lps,
+               struct bfa_rport_s *rp, struct scsi_lun lun)
+{
+       u8 i;
+       struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa);
+       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
+       struct scsi_cdb_s *cdb = (struct scsi_cdb_s *)cmnd->cmnd;
+
+       if ((cdb->scsi_cdb[0] == REPORT_LUNS) &&
+           (scsilun_to_int((struct scsi_lun *)&lun) == 0)) {
+               ioim->proc_rsp_data = bfa_ioim_lm_proc_rpl_data;
+               return BFA_IOIM_LM_PRESENT;
+       }
+
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+
+               if (lun_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE)
+                       continue;
+
+               if ((scsilun_to_int((struct scsi_lun *)&lun_list[i].lun) ==
+                   scsilun_to_int((struct scsi_lun *)&lun))
+                   && (rp->rport_tag == lun_list[i].rp_tag)
+                   && ((u8)ioim->itnim->rport->rport_info.lp_tag ==
+                                               lun_list[i].lp_tag)) {
+                       bfa_trc(ioim->bfa, lun_list[i].rp_tag);
+                       bfa_trc(ioim->bfa, lun_list[i].lp_tag);
+                       bfa_trc(ioim->bfa, scsilun_to_int(
+                               (struct scsi_lun *)&lun_list[i].lun));
+
+                       if ((lun_list[i].ua == BFA_IOIM_LM_UA_SET) &&
+                           ((cdb->scsi_cdb[0] != INQUIRY) ||
+                           (cdb->scsi_cdb[0] != REPORT_LUNS))) {
+                               lun_list[i].ua = BFA_IOIM_LM_UA_RESET;
+                               return BFA_IOIM_LM_RPL_DATA_CHANGED;
+                       }
+
+                       if (cdb->scsi_cdb[0] == REPORT_LUNS)
+                               ioim->proc_rsp_data = bfa_ioim_lm_proc_rpl_data;
+
+                       return BFA_IOIM_LM_PRESENT;
+               }
+       }
+
+       if ((cdb->scsi_cdb[0] == INQUIRY) &&
+           (scsilun_to_int((struct scsi_lun *)&lun) == 0)) {
+               ioim->proc_rsp_data = bfa_ioim_lm_proc_inq_data;
+               return BFA_IOIM_LM_PRESENT;
+       }
+
+       if (cdb->scsi_cdb[0] == TEST_UNIT_READY)
+               return BFA_IOIM_LM_LUN_NOT_RDY;
+
+       return BFA_IOIM_LM_LUN_NOT_SUP;
+}
+
+static bfa_boolean_t
+bfa_ioim_lm_proc_rsp_data_dummy(struct bfa_ioim_s *ioim)
+{
+       return BFA_TRUE;
+}
+
+static void
+bfa_ioim_lm_fetch_lun(struct bfa_ioim_s *ioim, u8 *rl_data, int offset,
+               int buf_lun_cnt)
+{
+       struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa);
+       struct scsi_lun *lun_data = (struct scsi_lun *)(rl_data + offset);
+       struct scsi_lun lun;
+       int i, j;
+
+       bfa_trc(ioim->bfa, buf_lun_cnt);
+       for (j = 0; j < buf_lun_cnt; j++) {
+               lun = *((struct scsi_lun *)(lun_data + j));
+               for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+                       if (lun_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE)
+                               continue;
+                       if ((lun_list[i].rp_wwn == bfa_ioim_rp_wwn(ioim)) &&
+                           (lun_list[i].lp_wwn == bfa_ioim_lp_wwn(ioim)) &&
+                           (scsilun_to_int((struct scsi_lun *)&lun_list[i].lun)
+                               == scsilun_to_int((struct scsi_lun *)&lun))) {
+                               lun_list[i].state = BFA_IOIM_LUN_MASK_FETCHED;
+                               break;
+                       }
+               } /* next lun in mask DB */
+       } /* next lun in buf */
+}
+
+static int
+bfa_ioim_lm_update_lun_sg(struct bfa_ioim_s *ioim, u32 *pgdlen,
+               struct scsi_report_luns_data_s *rl)
+{
+       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
+       struct scatterlist *sg = scsi_sglist(cmnd);
+       struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(ioim->bfa);
+       struct scsi_lun *prev_rl_data = NULL, *base_rl_data;
+       int i, j, sgeid, lun_fetched_cnt = 0, prev_sg_len = 0, base_count;
+       int lun_across_sg_bytes, bytes_from_next_buf;
+       u64     last_lun, temp_last_lun;
+
+       /* fetch luns from the first sg element */
+       bfa_ioim_lm_fetch_lun(ioim, (u8 *)(rl->lun), 0,
+                       (sg_dma_len(sg) / sizeof(struct scsi_lun)) - 1);
+
+       /* fetch luns from multiple sg elements */
+       scsi_for_each_sg(cmnd, sg, scsi_sg_count(cmnd), sgeid) {
+               if (sgeid == 0) {
+                       prev_sg_len = sg_dma_len(sg);
+                       prev_rl_data = (struct scsi_lun *)
+                                       phys_to_virt(sg_dma_address(sg));
+                       continue;
+               }
+
+               /* if the buf is having more data */
+               lun_across_sg_bytes = prev_sg_len % sizeof(struct scsi_lun);
+               if (lun_across_sg_bytes) {
+                       bfa_trc(ioim->bfa, lun_across_sg_bytes);
+                       bfa_stats(ioim->itnim, lm_lun_across_sg);
+                       bytes_from_next_buf = sizeof(struct scsi_lun) -
+                                             lun_across_sg_bytes;
+
+                       /* from next buf take higher bytes */
+                       temp_last_lun = *((u64 *)
+                                         phys_to_virt(sg_dma_address(sg)));
+                       last_lun |= temp_last_lun >>
+                                   (lun_across_sg_bytes * BITS_PER_BYTE);
+
+                       /* from prev buf take higher bytes */
+                       temp_last_lun = *((u64 *)(prev_rl_data +
+                                         (prev_sg_len - lun_across_sg_bytes)));
+                       temp_last_lun >>= bytes_from_next_buf * BITS_PER_BYTE;
+                       last_lun = last_lun | (temp_last_lun <<
+                                  (bytes_from_next_buf * BITS_PER_BYTE));
+
+                       bfa_ioim_lm_fetch_lun(ioim, (u8 *)&last_lun, 0, 1);
+               } else
+                       bytes_from_next_buf = 0;
+
+               *pgdlen += sg_dma_len(sg);
+               prev_sg_len = sg_dma_len(sg);
+               prev_rl_data = (struct scsi_lun *)
+                               phys_to_virt(sg_dma_address(sg));
+               bfa_ioim_lm_fetch_lun(ioim, (u8 *)prev_rl_data,
+                               bytes_from_next_buf,
+                               sg_dma_len(sg) / sizeof(struct scsi_lun));
+       }
+
+       /* update the report luns data - based on fetched luns */
+       sg = scsi_sglist(cmnd);
+       base_rl_data = (struct scsi_lun *)rl->lun;
+       base_count = (sg_dma_len(sg) / sizeof(struct scsi_lun)) - 1;
+       for (i = 0, j = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lun_list[i].state == BFA_IOIM_LUN_MASK_FETCHED) {
+                       base_rl_data[j] = lun_list[i].lun;
+                       lun_list[i].state = BFA_IOIM_LUN_MASK_ACTIVE;
+                       j++;
+                       lun_fetched_cnt++;
+               }
+
+               if (j > base_count) {
+                       j = 0;
+                       sg = sg_next(sg);
+                       base_rl_data = (struct scsi_lun *)
+                                       phys_to_virt(sg_dma_address(sg));
+                       base_count = sg_dma_len(sg) / sizeof(struct scsi_lun);
+               }
+       }
+
+       bfa_trc(ioim->bfa, lun_fetched_cnt);
+       return lun_fetched_cnt;
+}
+
+static bfa_boolean_t
+bfa_ioim_lm_proc_inq_data(struct bfa_ioim_s *ioim)
+{
+       struct scsi_inquiry_data_s *inq;
+       struct scatterlist *sg = scsi_sglist((struct scsi_cmnd *)ioim->dio);
+
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
+       inq = (struct scsi_inquiry_data_s *)phys_to_virt(sg_dma_address(sg));
+
+       bfa_trc(ioim->bfa, inq->device_type);
+       inq->peripheral_qual = SCSI_INQ_PQ_NOT_CON;
+       return 0;
+}
+
+static bfa_boolean_t
+bfa_ioim_lm_proc_rpl_data(struct bfa_ioim_s *ioim)
+{
+       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
+       struct scatterlist *sg = scsi_sglist(cmnd);
+       struct bfi_ioim_rsp_s *m;
+       struct scsi_report_luns_data_s *rl = NULL;
+       int lun_count = 0, lun_fetched_cnt = 0;
+       u32 residue, pgdlen = 0;
+
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
+       if (bfa_get_lun_mask_status(ioim->bfa) != BFA_LUNMASK_ENABLED)
+               return BFA_TRUE;
+
+       m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg;
+       if (m->scsi_status == SCSI_STATUS_CHECK_CONDITION)
+               return BFA_TRUE;
+
+       pgdlen = sg_dma_len(sg);
+       bfa_trc(ioim->bfa, pgdlen);
+       rl = (struct scsi_report_luns_data_s *)phys_to_virt(sg_dma_address(sg));
+       lun_count = cpu_to_be32(rl->lun_list_length) / sizeof(struct scsi_lun);
+       lun_fetched_cnt = bfa_ioim_lm_update_lun_sg(ioim, &pgdlen, rl);
+
+       if (lun_count == lun_fetched_cnt)
+               return BFA_TRUE;
+
+       bfa_trc(ioim->bfa, lun_count);
+       bfa_trc(ioim->bfa, lun_fetched_cnt);
+       bfa_trc(ioim->bfa, be32_to_cpu(rl->lun_list_length));
+
+       if (be32_to_cpu(rl->lun_list_length) <= pgdlen)
+               rl->lun_list_length = be32_to_cpu(lun_fetched_cnt) *
+                                     sizeof(struct scsi_lun);
+       else
+               bfa_stats(ioim->itnim, lm_small_buf_addresidue);
+
+       bfa_trc(ioim->bfa, be32_to_cpu(rl->lun_list_length));
+       bfa_trc(ioim->bfa, be32_to_cpu(m->residue));
+
+       residue = be32_to_cpu(m->residue);
+       residue += (lun_count - lun_fetched_cnt) * sizeof(struct scsi_lun);
+       bfa_stats(ioim->itnim, lm_wire_residue_changed);
+       m->residue = be32_to_cpu(residue);
+       bfa_trc(ioim->bfa, ioim->nsges);
+       return BFA_FALSE;
+}
 
 static void
 __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete)
@@ -2067,6 +2454,299 @@ __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete)
                          m->scsi_status, sns_len, snsinfo, residue);
 }
 
+static void
+__bfa_cb_ioim_lm_lun_not_sup(void *cbarg, bfa_boolean_t complete)
+{
+       struct bfa_ioim_s *ioim = cbarg;
+       int sns_len = 0xD;
+       u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio);
+       struct scsi_sense_s *snsinfo;
+
+       if (!complete) {
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+               return;
+       }
+
+       snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(
+                                       ioim->fcpim->fcp, ioim->iotag);
+       snsinfo->rsp_code = SCSI_SENSE_CUR_ERR;
+       snsinfo->add_sense_length = 0xa;
+       snsinfo->asc = SCSI_ASC_LUN_NOT_SUPPORTED;
+       snsinfo->sense_key = ILLEGAL_REQUEST;
+       bfa_trc(ioim->bfa, residue);
+       bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK,
+                       SCSI_STATUS_CHECK_CONDITION, sns_len,
+                       (u8 *)snsinfo, residue);
+}
+
+static void
+__bfa_cb_ioim_lm_rpl_dc(void *cbarg, bfa_boolean_t complete)
+{
+       struct bfa_ioim_s *ioim = cbarg;
+       int sns_len = 0xD;
+       u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio);
+       struct scsi_sense_s *snsinfo;
+
+       if (!complete) {
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+               return;
+       }
+
+       snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(ioim->fcpim->fcp,
+                                                      ioim->iotag);
+       snsinfo->rsp_code = SCSI_SENSE_CUR_ERR;
+       snsinfo->sense_key = SCSI_MP_IEC_UNIT_ATTN;
+       snsinfo->asc = SCSI_ASC_TOCC;
+       snsinfo->add_sense_length = 0x6;
+       snsinfo->ascq = SCSI_ASCQ_RL_DATA_CHANGED;
+       bfa_trc(ioim->bfa, residue);
+       bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK,
+                       SCSI_STATUS_CHECK_CONDITION, sns_len,
+                       (u8 *)snsinfo, residue);
+}
+
+static void
+__bfa_cb_ioim_lm_lun_not_rdy(void *cbarg, bfa_boolean_t complete)
+{
+       struct bfa_ioim_s *ioim = cbarg;
+       int sns_len = 0xD;
+       u32 residue = scsi_bufflen((struct scsi_cmnd *)ioim->dio);
+       struct scsi_sense_s *snsinfo;
+
+       if (!complete) {
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+               return;
+       }
+
+       snsinfo = (struct scsi_sense_s *)BFA_SNSINFO_FROM_TAG(
+                                       ioim->fcpim->fcp, ioim->iotag);
+       snsinfo->rsp_code = SCSI_SENSE_CUR_ERR;
+       snsinfo->add_sense_length = 0xa;
+       snsinfo->sense_key = NOT_READY;
+       snsinfo->asc = SCSI_ASC_LUN_NOT_READY;
+       snsinfo->ascq = SCSI_ASCQ_MAN_INTR_REQ;
+       bfa_trc(ioim->bfa, residue);
+       bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_OK,
+                       SCSI_STATUS_CHECK_CONDITION, sns_len,
+                       (u8 *)snsinfo, residue);
+}
+
+void
+bfa_fcpim_lunmask_rp_update(struct bfa_s *bfa, wwn_t lp_wwn, wwn_t rp_wwn,
+                       u16 rp_tag, u8 lp_tag)
+{
+       struct bfa_lun_mask_s *lun_list;
+       u8      i;
+
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return;
+
+       lun_list = bfa_get_lun_mask_list(bfa);
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lun_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE) {
+                       if ((lun_list[i].lp_wwn == lp_wwn) &&
+                           (lun_list[i].rp_wwn == rp_wwn)) {
+                               lun_list[i].rp_tag = rp_tag;
+                               lun_list[i].lp_tag = lp_tag;
+                       }
+               }
+       }
+}
+
+/*
+ * set UA for all active luns in LM DB
+ */
+static void
+bfa_ioim_lm_set_ua(struct bfa_s *bfa)
+{
+       struct bfa_lun_mask_s   *lunm_list;
+       int     i;
+
+       lunm_list = bfa_get_lun_mask_list(bfa);
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lunm_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE)
+                       continue;
+               lunm_list[i].ua = BFA_IOIM_LM_UA_SET;
+       }
+}
+
+bfa_status_t
+bfa_fcpim_lunmask_update(struct bfa_s *bfa, u32 update)
+{
+       struct bfa_lunmask_cfg_s        *lun_mask;
+
+       bfa_trc(bfa, bfa_get_lun_mask_status(bfa));
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return BFA_STATUS_FAILED;
+
+       if (bfa_get_lun_mask_status(bfa) == update)
+               return BFA_STATUS_NO_CHANGE;
+
+       lun_mask = bfa_get_lun_mask(bfa);
+       lun_mask->status = update;
+
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_ENABLED)
+               bfa_ioim_lm_set_ua(bfa);
+
+       return  bfa_dconf_update(bfa);
+}
+
+bfa_status_t
+bfa_fcpim_lunmask_clear(struct bfa_s *bfa)
+{
+       int i;
+       struct bfa_lun_mask_s   *lunm_list;
+
+       bfa_trc(bfa, bfa_get_lun_mask_status(bfa));
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return BFA_STATUS_FAILED;
+
+       lunm_list = bfa_get_lun_mask_list(bfa);
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lunm_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE) {
+                       if (lunm_list[i].rp_tag != BFA_RPORT_TAG_INVALID)
+                               bfa_rport_unset_lunmask(bfa,
+                                 BFA_RPORT_FROM_TAG(bfa, lunm_list[i].rp_tag));
+               }
+       }
+
+       memset(lunm_list, 0, sizeof(struct bfa_lun_mask_s) * MAX_LUN_MASK_CFG);
+       return bfa_dconf_update(bfa);
+}
+
+bfa_status_t
+bfa_fcpim_lunmask_query(struct bfa_s *bfa, void *buf)
+{
+       struct bfa_lunmask_cfg_s *lun_mask;
+
+       bfa_trc(bfa, bfa_get_lun_mask_status(bfa));
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return BFA_STATUS_FAILED;
+
+       lun_mask = bfa_get_lun_mask(bfa);
+       memcpy(buf, lun_mask, sizeof(struct bfa_lunmask_cfg_s));
+       return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_fcpim_lunmask_add(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn,
+                     wwn_t rpwwn, struct scsi_lun lun)
+{
+       struct bfa_lun_mask_s *lunm_list;
+       struct bfa_rport_s *rp = NULL;
+       int i, free_index = MAX_LUN_MASK_CFG + 1;
+       struct bfa_fcs_lport_s *port = NULL;
+       struct bfa_fcs_rport_s *rp_fcs;
+
+       bfa_trc(bfa, bfa_get_lun_mask_status(bfa));
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return BFA_STATUS_FAILED;
+
+       port = bfa_fcs_lookup_port(&((struct bfad_s *)bfa->bfad)->bfa_fcs,
+                                  vf_id, *pwwn);
+       if (port) {
+               *pwwn = port->port_cfg.pwwn;
+               rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn);
+               rp = rp_fcs->bfa_rport;
+       }
+
+       lunm_list = bfa_get_lun_mask_list(bfa);
+       /* if entry exists */
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if (lunm_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE)
+                       free_index = i;
+               if ((lunm_list[i].lp_wwn == *pwwn) &&
+                   (lunm_list[i].rp_wwn == rpwwn) &&
+                   (scsilun_to_int((struct scsi_lun *)&lunm_list[i].lun) ==
+                    scsilun_to_int((struct scsi_lun *)&lun)))
+                       return  BFA_STATUS_ENTRY_EXISTS;
+       }
+
+       if (free_index > MAX_LUN_MASK_CFG)
+               return BFA_STATUS_MAX_ENTRY_REACHED;
+
+       if (rp) {
+               lunm_list[free_index].lp_tag = bfa_lps_get_tag_from_pid(bfa,
+                                                  rp->rport_info.local_pid);
+               lunm_list[free_index].rp_tag = rp->rport_tag;
+       } else {
+               lunm_list[free_index].lp_tag = BFA_LP_TAG_INVALID;
+               lunm_list[free_index].rp_tag = BFA_RPORT_TAG_INVALID;
+       }
+
+       lunm_list[free_index].lp_wwn = *pwwn;
+       lunm_list[free_index].rp_wwn = rpwwn;
+       lunm_list[free_index].lun = lun;
+       lunm_list[free_index].state = BFA_IOIM_LUN_MASK_ACTIVE;
+
+       /* set for all luns in this rp */
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if ((lunm_list[i].lp_wwn == *pwwn) &&
+                   (lunm_list[i].rp_wwn == rpwwn))
+                       lunm_list[i].ua = BFA_IOIM_LM_UA_SET;
+       }
+
+       return bfa_dconf_update(bfa);
+}
+
+bfa_status_t
+bfa_fcpim_lunmask_delete(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn,
+                        wwn_t rpwwn, struct scsi_lun lun)
+{
+       struct bfa_lun_mask_s   *lunm_list;
+       struct bfa_rport_s      *rp = NULL;
+       struct bfa_fcs_lport_s *port = NULL;
+       struct bfa_fcs_rport_s *rp_fcs;
+       int     i;
+
+       /* in min cfg lunm_list could be NULL but  no commands should run. */
+       if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG)
+               return BFA_STATUS_FAILED;
+
+       bfa_trc(bfa, bfa_get_lun_mask_status(bfa));
+       bfa_trc(bfa, *pwwn);
+       bfa_trc(bfa, rpwwn);
+       bfa_trc(bfa, scsilun_to_int((struct scsi_lun *)&lun));
+
+       if (*pwwn == 0) {
+               port = bfa_fcs_lookup_port(
+                               &((struct bfad_s *)bfa->bfad)->bfa_fcs,
+                               vf_id, *pwwn);
+               if (port) {
+                       *pwwn = port->port_cfg.pwwn;
+                       rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn);
+                       rp = rp_fcs->bfa_rport;
+               }
+       }
+
+       lunm_list = bfa_get_lun_mask_list(bfa);
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if ((lunm_list[i].lp_wwn == *pwwn) &&
+                   (lunm_list[i].rp_wwn == rpwwn) &&
+                   (scsilun_to_int((struct scsi_lun *)&lunm_list[i].lun) ==
+                    scsilun_to_int((struct scsi_lun *)&lun))) {
+                       lunm_list[i].lp_wwn = 0;
+                       lunm_list[i].rp_wwn = 0;
+                       int_to_scsilun(0, &lunm_list[i].lun);
+                       lunm_list[i].state = BFA_IOIM_LUN_MASK_INACTIVE;
+                       if (lunm_list[i].rp_tag != BFA_RPORT_TAG_INVALID) {
+                               lunm_list[i].rp_tag = BFA_RPORT_TAG_INVALID;
+                               lunm_list[i].lp_tag = BFA_LP_TAG_INVALID;
+                       }
+                       return bfa_dconf_update(bfa);
+               }
+       }
+
+       /* set for all luns in this rp */
+       for (i = 0; i < MAX_LUN_MASK_CFG; i++) {
+               if ((lunm_list[i].lp_wwn == *pwwn) &&
+                   (lunm_list[i].rp_wwn == rpwwn))
+                       lunm_list[i].ua = BFA_IOIM_LM_UA_SET;
+       }
+
+       return BFA_STATUS_ENTRY_NOT_EXISTS;
+}
+
 static void
 __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete)
 {
@@ -2077,6 +2757,7 @@ __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete)
                return;
        }
 
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED,
                          0, 0, NULL, 0);
 }
@@ -2092,6 +2773,7 @@ __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete)
                return;
        }
 
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV,
                          0, 0, NULL, 0);
 }
@@ -2106,6 +2788,7 @@ __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete)
                return;
        }
 
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio);
 }
 
@@ -2449,6 +3132,7 @@ bfa_ioim_attach(struct bfa_fcpim_s *fcpim)
                ioim->bfa     = fcpim->bfa;
                ioim->fcpim   = fcpim;
                ioim->iosp    = iosp;
+               ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
                INIT_LIST_HEAD(&ioim->sgpg_q);
                bfa_reqq_winit(&ioim->iosp->reqq_wait,
                                   bfa_ioim_qresume, ioim);
@@ -2486,6 +3170,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                        evt = BFA_IOIM_SM_DONE;
                else
                        evt = BFA_IOIM_SM_COMP;
+               ioim->proc_rsp_data(ioim);
                break;
 
        case BFI_IOIM_STS_TIMEDOUT:
@@ -2521,6 +3206,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                if (rsp->abort_tag != ioim->abort_tag) {
                        bfa_trc(ioim->bfa, rsp->abort_tag);
                        bfa_trc(ioim->bfa, ioim->abort_tag);
+                       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
                        return;
                }
 
@@ -2539,6 +3225,7 @@ bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                WARN_ON(1);
        }
 
+       ioim->proc_rsp_data = bfa_ioim_lm_proc_rsp_data_dummy;
        bfa_sm_send_event(ioim, evt);
 }
 
@@ -2556,7 +3243,16 @@ bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        WARN_ON(BFA_IOIM_TAG_2_ID(ioim->iotag) != iotag);
 
        bfa_ioim_cb_profile_comp(fcpim, ioim);
-       bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
+
+       if (bfa_get_lun_mask_status(bfa) != BFA_LUNMASK_ENABLED)  {
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
+               return;
+       }
+
+       if (ioim->proc_rsp_data(ioim) == BFA_TRUE)
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
+       else
+               bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP);
 }
 
 /*
@@ -2668,6 +3364,35 @@ bfa_ioim_free(struct bfa_ioim_s *ioim)
 void
 bfa_ioim_start(struct bfa_ioim_s *ioim)
 {
+       struct scsi_cmnd *cmnd = (struct scsi_cmnd *)ioim->dio;
+       struct bfa_lps_s        *lps;
+       enum bfa_ioim_lm_status status;
+       struct scsi_lun scsilun;
+
+       if (bfa_get_lun_mask_status(ioim->bfa) == BFA_LUNMASK_ENABLED) {
+               lps = BFA_IOIM_TO_LPS(ioim);
+               int_to_scsilun(cmnd->device->lun, &scsilun);
+               status = bfa_ioim_lm_check(ioim, lps,
+                               ioim->itnim->rport, scsilun);
+               if (status == BFA_IOIM_LM_LUN_NOT_RDY) {
+                       bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_LUN_NOT_RDY);
+                       bfa_stats(ioim->itnim, lm_lun_not_rdy);
+                       return;
+               }
+
+               if (status == BFA_IOIM_LM_LUN_NOT_SUP) {
+                       bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_LUN_NOT_SUP);
+                       bfa_stats(ioim->itnim, lm_lun_not_sup);
+                       return;
+               }
+
+               if (status == BFA_IOIM_LM_RPL_DATA_CHANGED) {
+                       bfa_sm_send_event(ioim, BFA_IOIM_SM_LM_RPL_DC);
+                       bfa_stats(ioim->itnim, lm_rpl_data_changed);
+                       return;
+               }
+       }
+
        bfa_ioim_cb_profile_start(ioim->fcpim, ioim);
 
        /*
@@ -3411,6 +4136,13 @@ bfa_fcp_detach(struct bfa_s *bfa)
 static void
 bfa_fcp_start(struct bfa_s *bfa)
 {
+       struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa);
+
+       /*
+        * bfa_init() with flash read is complete. now invalidate the stale
+        * content of lun mask like unit attention, rp tag and lp tag.
+        */
+       bfa_ioim_lm_init(fcp->bfa);
 }
 
 static void
index 57b695ad4ee52389fde2297055e93be2d6147f75..1080bcb81cb73a2caf409d800da3b78deed8234f 100644 (file)
@@ -79,14 +79,22 @@ bfa_ioim_get_index(u32 n) {
        if (n >= (1UL)<<22)
                return BFA_IOBUCKET_MAX - 1;
        n >>= 8;
-       if (n >= (1UL)<<16)
-               n >>= 16; pos += 16;
-       if (n >= 1 << 8)
-               n >>= 8; pos += 8;
-       if (n >= 1 << 4)
-               n >>= 4; pos += 4;
-       if (n >= 1 << 2)
-               n >>= 2; pos += 2;
+       if (n >= (1UL)<<16) {
+               n >>= 16;
+               pos += 16;
+       }
+       if (n >= 1 << 8) {
+               n >>= 8;
+               pos += 8;
+       }
+       if (n >= 1 << 4) {
+               n >>= 4;
+               pos += 4;
+       }
+       if (n >= 1 << 2) {
+               n >>= 2;
+               pos += 2;
+       }
        if (n >= 1 << 1)
                pos += 1;
 
@@ -102,6 +110,7 @@ struct bfad_ioim_s;
 struct bfad_tskim_s;
 
 typedef void    (*bfa_fcpim_profile_t) (struct bfa_ioim_s *ioim);
+typedef bfa_boolean_t (*bfa_ioim_lm_proc_rsp_data_t) (struct bfa_ioim_s *ioim);
 
 struct bfa_fcpim_s {
        struct bfa_s            *bfa;
@@ -115,7 +124,7 @@ struct bfa_fcpim_s {
        u32                     path_tov;
        u16                     q_depth;
        u8                      reqq;           /*  Request queue to be used */
-       u8                      rsvd;
+       u8                      lun_masking_pending;
        struct list_head        itnim_q;        /*  queue of active itnim */
        struct list_head        ioim_resfree_q; /*  IOs waiting for f/w */
        struct list_head        ioim_comp_q;    /*  IO global comp Q    */
@@ -170,7 +179,9 @@ struct bfa_ioim_s {
        bfa_cb_cbfn_t           io_cbfn;        /*  IO completion handler */
        struct bfa_ioim_sp_s    *iosp;          /*  slow-path IO handling */
        u8                      reqq;           /*  Request queue for I/O */
+       u8                      mode;           /*  IO is passthrough or not */
        u64                     start_time;     /*  IO's Profile start val */
+       bfa_ioim_lm_proc_rsp_data_t proc_rsp_data; /* RSP data adjust */
 };
 
 struct bfa_ioim_sp_s {
@@ -250,6 +261,10 @@ struct bfa_itnim_s {
        (__ioim)->iotag |= k << BFA_IOIM_RETRY_TAG_OFFSET;              \
 } while (0)
 
+#define BFA_IOIM_TO_LPS(__ioim)                \
+       BFA_LPS_FROM_TAG(BFA_LPS_MOD(__ioim->bfa),      \
+               __ioim->itnim->rport->rport_info.lp_tag)
+
 static inline bfa_boolean_t
 bfa_ioim_maxretry_reached(struct bfa_ioim_s *ioim)
 {
@@ -297,6 +312,8 @@ bfa_status_t bfa_fcpim_port_iostats(struct bfa_s *bfa,
                        struct bfa_itnim_iostats_s *stats, u8 lp_tag);
 void bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *fcpim_stats,
                        struct bfa_itnim_iostats_s *itnim_stats);
+bfa_status_t bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time);
+bfa_status_t bfa_fcpim_profile_off(struct bfa_s *bfa);
 
 #define bfa_fcpim_ioredirect_enabled(__bfa)                            \
        (((struct bfa_fcpim_s *)(BFA_FCPIM(__bfa)))->ioredirect)
@@ -397,4 +414,14 @@ void bfa_tskim_start(struct bfa_tskim_s *tskim,
 void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
                        enum bfi_tskim_status tsk_status);
 
+void   bfa_fcpim_lunmask_rp_update(struct bfa_s *bfa, wwn_t lp_wwn,
+                       wwn_t rp_wwn, u16 rp_tag, u8 lp_tag);
+bfa_status_t   bfa_fcpim_lunmask_update(struct bfa_s *bfa, u32 on_off);
+bfa_status_t   bfa_fcpim_lunmask_query(struct bfa_s *bfa, void *buf);
+bfa_status_t   bfa_fcpim_lunmask_delete(struct bfa_s *bfa, u16 vf_id,
+                               wwn_t *pwwn, wwn_t rpwwn, struct scsi_lun lun);
+bfa_status_t   bfa_fcpim_lunmask_add(struct bfa_s *bfa, u16 vf_id,
+                               wwn_t *pwwn, wwn_t rpwwn, struct scsi_lun lun);
+bfa_status_t   bfa_fcpim_lunmask_clear(struct bfa_s *bfa);
+
 #endif /* __BFA_FCPIM_H__ */
index a9b22bc48bc307aab341cd42490744be85d34c0a..eaac57e1ddec4fd42a0ef08f47494c9310a3bc14 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "bfad_drv.h"
+#include "bfad_im.h"
 #include "bfa_fcs.h"
 #include "bfa_fcbuild.h"
 
@@ -1327,6 +1328,29 @@ bfa_fcs_fabric_flogiacc_comp(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
        bfa_trc(fabric->fcs, status);
 }
 
+
+/*
+ * Send AEN notification
+ */
+static void
+bfa_fcs_fabric_aen_post(struct bfa_fcs_lport_s *port,
+                       enum bfa_port_aen_event event)
+{
+       struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.port.pwwn = bfa_fcs_lport_get_pwwn(port);
+       aen_entry->aen_data.port.fwwn = bfa_fcs_lport_get_fabric_name(port);
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
+                                 BFA_AEN_CAT_PORT, event);
+}
+
 /*
  *
  * @param[in] fabric - fabric
@@ -1358,6 +1382,8 @@ bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
                BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
                        "Base port WWN = %s Fabric WWN = %s\n",
                        pwwn_ptr, fwwn_ptr);
+               bfa_fcs_fabric_aen_post(&fabric->bport,
+                               BFA_PORT_AEN_FABRIC_NAME_CHANGE);
        }
 }
 
index a5f1faf335a76ed222508b9a4077d6829524a2ed..e75e07d25915250b7ec16d6d1087b220c882c85d 100644 (file)
@@ -675,6 +675,7 @@ struct bfa_fcs_s {
        struct bfa_fcs_fabric_s fabric; /*  base fabric state machine */
        struct bfa_fcs_stats_s  stats;  /*  FCS statistics */
        struct bfa_wc_s         wc;     /*  waiting counter */
+       int                     fcs_aen_seq;
 };
 
 /*
index 29b4108be269f337dca6ea9e6def5d392b6db979..9272840a2409fe6075c26604d9d62bc135e0774c 100644 (file)
@@ -37,6 +37,8 @@ static void   bfa_fcs_itnim_prli_response(void *fcsarg,
                         struct bfa_fcxp_s *fcxp, void *cbarg,
                            bfa_status_t req_status, u32 rsp_len,
                            u32 resid_len, struct fchs_s *rsp_fchs);
+static void    bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
+                       enum bfa_itnim_aen_event event);
 
 /*
  *  fcs_itnim_sm FCS itnim state machine events
@@ -269,6 +271,7 @@ bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                "Target (WWN = %s) is online for initiator (WWN = %s)\n",
                rpwwn_buf, lpwwn_buf);
+               bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE);
                break;
 
        case BFA_FCS_ITNIM_SM_OFFLINE:
@@ -305,14 +308,17 @@ bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
                bfa_itnim_offline(itnim->bfa_itnim);
                wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port));
                wwn2str(rpwwn_buf, itnim->rport->pwwn);
-               if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE)
+               if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE) {
                        BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                        "Target (WWN = %s) connectivity lost for "
                        "initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf);
-               else
+                       bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
+               } else {
                        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Target (WWN = %s) offlined by initiator (WWN = %s)\n",
                        rpwwn_buf, lpwwn_buf);
+                       bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
+               }
                break;
 
        case BFA_FCS_ITNIM_SM_DELETE:
@@ -381,6 +387,33 @@ bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
        }
 }
 
+static void
+bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
+                       enum bfa_itnim_aen_event event)
+{
+       struct bfa_fcs_rport_s *rport = itnim->rport;
+       struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       /* Don't post events for well known addresses */
+       if (BFA_FCS_PID_IS_WKA(rport->pid))
+               return;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.itnim.vf_id = rport->port->fabric->vf_id;
+       aen_entry->aen_data.itnim.ppwwn = bfa_fcs_lport_get_pwwn(
+                                       bfa_fcs_get_base_port(itnim->fcs));
+       aen_entry->aen_data.itnim.lpwwn = bfa_fcs_lport_get_pwwn(rport->port);
+       aen_entry->aen_data.itnim.rpwwn = rport->pwwn;
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++rport->fcs->fcs_aen_seq,
+                                 BFA_AEN_CAT_ITNIM, event);
+}
+
 static void
 bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
 {
index f8251a91ba91b39f7d70375eaf67087e89f20cd7..d4f951fe753eecb1fbccade0e96e5adde904b986 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "bfad_drv.h"
+#include "bfad_im.h"
 #include "bfa_fcs.h"
 #include "bfa_fcbuild.h"
 #include "bfa_fc.h"
@@ -299,6 +300,31 @@ bfa_fcs_lport_sm_deleting(
  *  fcs_port_pvt
  */
 
+/*
+ * Send AEN notification
+ */
+static void
+bfa_fcs_lport_aen_post(struct bfa_fcs_lport_s *port,
+                       enum bfa_lport_aen_event event)
+{
+       struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.lport.vf_id = port->fabric->vf_id;
+       aen_entry->aen_data.lport.roles = port->port_cfg.roles;
+       aen_entry->aen_data.lport.ppwwn = bfa_fcs_lport_get_pwwn(
+                                       bfa_fcs_get_base_port(port->fcs));
+       aen_entry->aen_data.lport.lpwwn = bfa_fcs_lport_get_pwwn(port);
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
+                                 BFA_AEN_CAT_LPORT, event);
+}
+
 /*
  * Send a LS reject
  */
@@ -593,6 +619,7 @@ bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port)
        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                "Logical port online: WWN = %s Role = %s\n",
                lpwwn_buf, "Initiator");
+       bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_ONLINE);
 
        bfad->bfad_flags |= BFAD_PORT_ONLINE;
 }
@@ -611,14 +638,17 @@ bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port)
 
        wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
        if (bfa_sm_cmp_state(port->fabric,
-                       bfa_fcs_fabric_sm_online) == BFA_TRUE)
+                       bfa_fcs_fabric_sm_online) == BFA_TRUE) {
                BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                "Logical port lost fabric connectivity: WWN = %s Role = %s\n",
                lpwwn_buf, "Initiator");
-       else
+               bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
+       } else {
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                "Logical port taken offline: WWN = %s Role = %s\n",
                lpwwn_buf, "Initiator");
+               bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_OFFLINE);
+       }
 
        list_for_each_safe(qe, qen, &port->rport_q) {
                rport = (struct bfa_fcs_rport_s *) qe;
@@ -676,6 +706,7 @@ bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port)
        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                "Logical port deleted: WWN = %s Role = %s\n",
                lpwwn_buf, "Initiator");
+       bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DELETE);
 
        /* Base port will be deleted by the OS driver */
        if (port->vport) {
@@ -973,6 +1004,7 @@ bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport,
        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                "New logical port created: WWN = %s Role = %s\n",
                lpwwn_buf, "Initiator");
+       bfa_fcs_lport_aen_post(lport, BFA_LPORT_AEN_NEW);
 
        bfa_sm_set_state(lport, bfa_fcs_lport_sm_uninit);
        bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
@@ -5558,6 +5590,31 @@ bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
 /*
  *  fcs_vport_private FCS virtual port private functions
  */
+/*
+ * Send AEN notification
+ */
+static void
+bfa_fcs_vport_aen_post(struct bfa_fcs_lport_s *port,
+                      enum bfa_lport_aen_event event)
+{
+       struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.lport.vf_id = port->fabric->vf_id;
+       aen_entry->aen_data.lport.roles = port->port_cfg.roles;
+       aen_entry->aen_data.lport.ppwwn = bfa_fcs_lport_get_pwwn(
+                                       bfa_fcs_get_base_port(port->fcs));
+       aen_entry->aen_data.lport.lpwwn = bfa_fcs_lport_get_pwwn(port);
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq,
+                                 BFA_AEN_CAT_LPORT, event);
+}
+
 /*
  * This routine will be called to send a FDISC command.
  */
@@ -5585,8 +5642,11 @@ bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport)
        case FC_LS_RJT_EXP_INVALID_NPORT_ID: /* by Cisco */
                if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES)
                        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
-               else
+               else {
+                       bfa_fcs_vport_aen_post(&vport->lport,
+                                       BFA_LPORT_AEN_NPIV_DUP_WWN);
                        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_DUP_WWN);
+               }
                break;
 
        case FC_LS_RJT_EXP_INSUFF_RES:
@@ -5596,11 +5656,17 @@ bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport)
                 */
                if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES)
                        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
-               else
+               else {
+                       bfa_fcs_vport_aen_post(&vport->lport,
+                                       BFA_LPORT_AEN_NPIV_FABRIC_MAX);
                        bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_FAILED);
+               }
                break;
 
        default:
+               if (vport->fdisc_retries == 0)
+                       bfa_fcs_vport_aen_post(&vport->lport,
+                                       BFA_LPORT_AEN_NPIV_UNKNOWN);
                bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
        }
 }
index 2c514458a6b44d74ef36833c70fa2cb4faacc016..52628d5d3c9b0663486833db47eda3d449a60aa9 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "bfad_drv.h"
+#include "bfad_im.h"
 #include "bfa_fcs.h"
 #include "bfa_fcbuild.h"
 
@@ -2040,6 +2041,35 @@ bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport)
        kfree(rport->rp_drv);
 }
 
+static void
+bfa_fcs_rport_aen_post(struct bfa_fcs_rport_s *rport,
+                       enum bfa_rport_aen_event event,
+                       struct bfa_rport_aen_data_s *data)
+{
+       struct bfa_fcs_lport_s *port = rport->port;
+       struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       if (event == BFA_RPORT_AEN_QOS_PRIO)
+               aen_entry->aen_data.rport.priv.qos = data->priv.qos;
+       else if (event == BFA_RPORT_AEN_QOS_FLOWID)
+               aen_entry->aen_data.rport.priv.qos = data->priv.qos;
+
+       aen_entry->aen_data.rport.vf_id = rport->port->fabric->vf_id;
+       aen_entry->aen_data.rport.ppwwn = bfa_fcs_lport_get_pwwn(
+                                       bfa_fcs_get_base_port(rport->fcs));
+       aen_entry->aen_data.rport.lpwwn = bfa_fcs_lport_get_pwwn(rport->port);
+       aen_entry->aen_data.rport.rpwwn = rport->pwwn;
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++rport->fcs->fcs_aen_seq,
+                                 BFA_AEN_CAT_RPORT, event);
+}
+
 static void
 bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport)
 {
@@ -2063,10 +2093,12 @@ bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport)
 
        wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
        wwn2str(rpwwn_buf, rport->pwwn);
-       if (!BFA_FCS_PID_IS_WKA(rport->pid))
+       if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                "Remote port (WWN = %s) online for logical port (WWN = %s)\n",
                rpwwn_buf, lpwwn_buf);
+               bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_ONLINE, NULL);
+       }
 }
 
 static void
@@ -2083,16 +2115,21 @@ bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport)
        wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port));
        wwn2str(rpwwn_buf, rport->pwwn);
        if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
-               if (bfa_fcs_lport_is_online(rport->port) == BFA_TRUE)
+               if (bfa_fcs_lport_is_online(rport->port) == BFA_TRUE) {
                        BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                                "Remote port (WWN = %s) connectivity lost for "
                                "logical port (WWN = %s)\n",
                                rpwwn_buf, lpwwn_buf);
-               else
+                       bfa_fcs_rport_aen_post(rport,
+                               BFA_RPORT_AEN_DISCONNECT, NULL);
+               } else {
                        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                                "Remote port (WWN = %s) offlined by "
                                "logical port (WWN = %s)\n",
                                rpwwn_buf, lpwwn_buf);
+                       bfa_fcs_rport_aen_post(rport,
+                               BFA_RPORT_AEN_OFFLINE, NULL);
+               }
        }
 
        if (bfa_fcs_lport_is_initiator(port)) {
@@ -2366,8 +2403,11 @@ bfa_cb_rport_qos_scn_flowid(void *cbarg,
                struct bfa_rport_qos_attr_s new_qos_attr)
 {
        struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg;
+       struct bfa_rport_aen_data_s aen_data;
 
        bfa_trc(rport->fcs, rport->pwwn);
+       aen_data.priv.qos = new_qos_attr;
+       bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_FLOWID, &aen_data);
 }
 
 /*
@@ -2390,8 +2430,11 @@ bfa_cb_rport_qos_scn_prio(void *cbarg,
                struct bfa_rport_qos_attr_s new_qos_attr)
 {
        struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg;
+       struct bfa_rport_aen_data_s aen_data;
 
        bfa_trc(rport->fcs, rport->pwwn);
+       aen_data.priv.qos = new_qos_attr;
+       bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_PRIO, &aen_data);
 }
 
 /*
index e7ffd8205dc7e44e267b8c0809903e764284ef24..ea24d4c6e67afc025ce68e5363f8eda1771f335e 100644 (file)
@@ -42,11 +42,36 @@ bfa_hwcb_reqq_ack_msix(struct bfa_s *bfa, int reqq)
                        bfa->iocfc.bfa_regs.intr_status);
 }
 
+/*
+ * Actions to respond RME Interrupt for Crossbow ASIC:
+ * - Write 1 to Interrupt Status register
+ *              INTX - done in bfa_intx()
+ *              MSIX - done in bfa_hwcb_rspq_ack_msix()
+ * - Update CI (only if new CI)
+ */
 static void
-bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq)
+bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq, u32 ci)
 {
        writel(__HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq),
-                       bfa->iocfc.bfa_regs.intr_status);
+               bfa->iocfc.bfa_regs.intr_status);
+
+       if (bfa_rspq_ci(bfa, rspq) == ci)
+               return;
+
+       bfa_rspq_ci(bfa, rspq) = ci;
+       writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
+       mmiowb();
+}
+
+void
+bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci)
+{
+       if (bfa_rspq_ci(bfa, rspq) == ci)
+               return;
+
+       bfa_rspq_ci(bfa, rspq) = ci;
+       writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
+       mmiowb();
 }
 
 void
@@ -149,8 +174,13 @@ bfa_hwcb_msix_uninstall(struct bfa_s *bfa)
 void
 bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix)
 {
-       bfa->iocfc.hwif.hw_reqq_ack = bfa_hwcb_reqq_ack_msix;
-       bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix;
+       if (msix) {
+               bfa->iocfc.hwif.hw_reqq_ack = bfa_hwcb_reqq_ack_msix;
+               bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix;
+       } else {
+               bfa->iocfc.hwif.hw_reqq_ack = NULL;
+               bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack;
+       }
 }
 
 void
index 989bbce9b29699c721aa25a83e4cce24c65f112b..637527f48b400c741805dbdf9a2e5758cad64a7e 100644 (file)
@@ -64,13 +64,36 @@ bfa_hwct_reqq_ack(struct bfa_s *bfa, int reqq)
        writel(r32, bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]);
 }
 
+/*
+ * Actions to respond RME Interrupt for Catapult ASIC:
+ * - Write 1 to Interrupt Status register (INTx only - done in bfa_intx())
+ * - Acknowledge by writing to RME Queue Control register
+ * - Update CI
+ */
 void
-bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq)
+bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci)
 {
        u32     r32;
 
        r32 = readl(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
        writel(r32, bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
+
+       bfa_rspq_ci(bfa, rspq) = ci;
+       writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
+       mmiowb();
+}
+
+/*
+ * Actions to respond RME Interrupt for Catapult2 ASIC:
+ * - Write 1 to Interrupt Status register (INTx only - done in bfa_intx())
+ * - Update CI
+ */
+void
+bfa_hwct2_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci)
+{
+       bfa_rspq_ci(bfa, rspq) = ci;
+       writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
+       mmiowb();
 }
 
 void
index d6c2bf3865d26b7a6903d6f3de9db5634002b99b..1ac5aecf25a68a14c2c98011cf1af357b60ead26 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "bfad_drv.h"
+#include "bfad_im.h"
 #include "bfa_ioc.h"
 #include "bfi_reg.h"
 #include "bfa_defs.h"
@@ -458,6 +459,7 @@ bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc)
        ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
        bfa_ioc_event_notify(ioc, BFA_IOC_E_ENABLED);
        BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n");
+       bfa_ioc_aen_post(ioc, BFA_IOC_AEN_ENABLE);
 }
 
 static void
@@ -502,6 +504,7 @@ bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc)
        struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
        bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE);
        BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC disabled\n");
+       bfa_ioc_aen_post(ioc, BFA_IOC_AEN_DISABLE);
 }
 
 /*
@@ -1966,6 +1969,7 @@ bfa_ioc_fail_notify(struct bfa_ioc_s *ioc)
 
        BFA_LOG(KERN_CRIT, bfad, bfa_log_level,
                "Heart Beat of IOC has failed\n");
+       bfa_ioc_aen_post(ioc, BFA_IOC_AEN_HBFAIL);
 
 }
 
@@ -1980,6 +1984,7 @@ bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc)
        BFA_LOG(KERN_WARNING, bfad, bfa_log_level,
                "Running firmware version is incompatible "
                "with the driver version\n");
+       bfa_ioc_aen_post(ioc, BFA_IOC_AEN_FWMISMATCH);
 }
 
 bfa_status_t
@@ -2678,6 +2683,43 @@ bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc)
        return m;
 }
 
+/*
+ * Send AEN notification
+ */
+void
+bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
+{
+       struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+       enum bfa_ioc_type_e ioc_type;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       ioc_type = bfa_ioc_get_type(ioc);
+       switch (ioc_type) {
+       case BFA_IOC_TYPE_FC:
+               aen_entry->aen_data.ioc.pwwn = ioc->attr->pwwn;
+               break;
+       case BFA_IOC_TYPE_FCoE:
+               aen_entry->aen_data.ioc.pwwn = ioc->attr->pwwn;
+               aen_entry->aen_data.ioc.mac = bfa_ioc_get_mac(ioc);
+               break;
+       case BFA_IOC_TYPE_LL:
+               aen_entry->aen_data.ioc.mac = bfa_ioc_get_mac(ioc);
+               break;
+       default:
+               WARN_ON(ioc_type != BFA_IOC_TYPE_FC);
+               break;
+       }
+
+       /* Send the AEN notification */
+       aen_entry->aen_data.ioc.ioc_type = ioc_type;
+       bfad_im_post_vendor_event(aen_entry, bfad, ++ioc->ioc_aen_seq,
+                                 BFA_AEN_CAT_IOC, event);
+}
+
 /*
  * Retrieve saved firmware trace from a prior IOC failure.
  */
@@ -2879,6 +2921,10 @@ bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc)
 {
        if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_LL)
                return;
+       if (ioc->attr->nwwn == 0)
+               bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_NWWN);
+       if (ioc->attr->pwwn == 0)
+               bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_PWWN);
 }
 
 /*
@@ -3442,6 +3488,54 @@ bfa_sfp_notify(void *sfp_arg, enum bfa_ioc_event_e event)
        }
 }
 
+/*
+ * SFP's State Change Notification post to AEN
+ */
+static void
+bfa_sfp_scn_aen_post(struct bfa_sfp_s *sfp, struct bfi_sfp_scn_s *rsp)
+{
+       struct bfad_s *bfad = (struct bfad_s *)sfp->ioc->bfa->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+       enum bfa_port_aen_event aen_evt = 0;
+
+       bfa_trc(sfp, (((u64)rsp->pomlvl) << 16) | (((u64)rsp->sfpid) << 8) |
+                     ((u64)rsp->event));
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.port.ioc_type = bfa_ioc_get_type(sfp->ioc);
+       aen_entry->aen_data.port.pwwn = sfp->ioc->attr->pwwn;
+       aen_entry->aen_data.port.mac = bfa_ioc_get_mac(sfp->ioc);
+
+       switch (rsp->event) {
+       case BFA_SFP_SCN_INSERTED:
+               aen_evt = BFA_PORT_AEN_SFP_INSERT;
+               break;
+       case BFA_SFP_SCN_REMOVED:
+               aen_evt = BFA_PORT_AEN_SFP_REMOVE;
+               break;
+       case BFA_SFP_SCN_FAILED:
+               aen_evt = BFA_PORT_AEN_SFP_ACCESS_ERROR;
+               break;
+       case BFA_SFP_SCN_UNSUPPORT:
+               aen_evt = BFA_PORT_AEN_SFP_UNSUPPORT;
+               break;
+       case BFA_SFP_SCN_POM:
+               aen_evt = BFA_PORT_AEN_SFP_POM;
+               aen_entry->aen_data.port.level = rsp->pomlvl;
+               break;
+       default:
+               bfa_trc(sfp, rsp->event);
+               WARN_ON(1);
+       }
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++sfp->ioc->ioc_aen_seq,
+                                 BFA_AEN_CAT_PORT, aen_evt);
+}
+
 /*
  *     SFP get data send
  */
@@ -3481,6 +3575,50 @@ bfa_sfp_getdata(struct bfa_sfp_s *sfp, enum bfi_sfp_mem_e memtype)
        bfa_sfp_getdata_send(sfp);
 }
 
+/*
+ *     SFP scn handler
+ */
+static void
+bfa_sfp_scn(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg)
+{
+       struct bfi_sfp_scn_s *rsp = (struct bfi_sfp_scn_s *) msg;
+
+       switch (rsp->event) {
+       case BFA_SFP_SCN_INSERTED:
+               sfp->state = BFA_SFP_STATE_INSERTED;
+               sfp->data_valid = 0;
+               bfa_sfp_scn_aen_post(sfp, rsp);
+               break;
+       case BFA_SFP_SCN_REMOVED:
+               sfp->state = BFA_SFP_STATE_REMOVED;
+               sfp->data_valid = 0;
+               bfa_sfp_scn_aen_post(sfp, rsp);
+                break;
+       case BFA_SFP_SCN_FAILED:
+               sfp->state = BFA_SFP_STATE_FAILED;
+               sfp->data_valid = 0;
+               bfa_sfp_scn_aen_post(sfp, rsp);
+               break;
+       case BFA_SFP_SCN_UNSUPPORT:
+               sfp->state = BFA_SFP_STATE_UNSUPPORT;
+               bfa_sfp_scn_aen_post(sfp, rsp);
+               if (!sfp->lock)
+                       bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL);
+               break;
+       case BFA_SFP_SCN_POM:
+               bfa_sfp_scn_aen_post(sfp, rsp);
+               break;
+       case BFA_SFP_SCN_VALID:
+               sfp->state = BFA_SFP_STATE_VALID;
+               if (!sfp->lock)
+                       bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL);
+               break;
+       default:
+               bfa_trc(sfp, rsp->event);
+               WARN_ON(1);
+       }
+}
+
 /*
  * SFP show complete
  */
@@ -3645,7 +3783,7 @@ bfa_sfp_intr(void *sfparg, struct bfi_mbmsg_s *msg)
                break;
 
        case BFI_SFP_I2H_SCN:
-               bfa_trc(sfp, msg->mh.msg_id);
+               bfa_sfp_scn(sfp, msg);
                break;
 
        default:
@@ -3837,6 +3975,26 @@ bfa_sfp_speed(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed,
 #define BFA_FLASH_DMA_BUF_SZ   \
        BFA_ROUNDUP(0x010000 + sizeof(struct bfa_mfg_block_s), BFA_FLASH_SEG_SZ)
 
+static void
+bfa_flash_aen_audit_post(struct bfa_ioc_s *ioc, enum bfa_audit_aen_event event,
+                       int inst, int type)
+{
+       struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.audit.pwwn = ioc->attr->pwwn;
+       aen_entry->aen_data.audit.partition_inst = inst;
+       aen_entry->aen_data.audit.partition_type = type;
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++ioc->ioc_aen_seq,
+                                 BFA_AEN_CAT_AUDIT, event);
+}
+
 static void
 bfa_flash_cb(struct bfa_flash_s *flash)
 {
@@ -3978,6 +4136,7 @@ bfa_flash_intr(void *flasharg, struct bfi_mbmsg_s *msg)
                struct bfi_flash_erase_rsp_s *erase;
                struct bfi_flash_write_rsp_s *write;
                struct bfi_flash_read_rsp_s *read;
+               struct bfi_flash_event_s *event;
                struct bfi_mbmsg_s   *msg;
        } m;
 
@@ -4061,8 +4220,19 @@ bfa_flash_intr(void *flasharg, struct bfi_mbmsg_s *msg)
                }
                break;
        case BFI_FLASH_I2H_BOOT_VER_RSP:
+               break;
        case BFI_FLASH_I2H_EVENT:
-               bfa_trc(flash, msg->mh.msg_id);
+               status = be32_to_cpu(m.event->status);
+               bfa_trc(flash, status);
+               if (status == BFA_STATUS_BAD_FWCFG)
+                       bfa_ioc_aen_post(flash->ioc, BFA_IOC_AEN_FWCFG_ERROR);
+               else if (status == BFA_STATUS_INVALID_VENDOR) {
+                       u32 param;
+                       param = be32_to_cpu(m.event->param);
+                       bfa_trc(flash, param);
+                       bfa_ioc_aen_post(flash->ioc,
+                               BFA_IOC_AEN_INVALID_VENDOR);
+               }
                break;
 
        default:
@@ -4204,6 +4374,8 @@ bfa_flash_erase_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type,
        flash->instance = instance;
 
        bfa_flash_erase_send(flash);
+       bfa_flash_aen_audit_post(flash->ioc, BFA_AUDIT_AEN_FLASH_ERASE,
+                               instance, type);
        return BFA_STATUS_OK;
 }
 
@@ -5416,3 +5588,396 @@ bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg)
                WARN_ON(1);
        }
 }
+
+/*
+ *     DCONF module specific
+ */
+
+BFA_MODULE(dconf);
+
+/*
+ * DCONF state machine events
+ */
+enum bfa_dconf_event {
+       BFA_DCONF_SM_INIT               = 1,    /* dconf Init */
+       BFA_DCONF_SM_FLASH_COMP         = 2,    /* read/write to flash */
+       BFA_DCONF_SM_WR                 = 3,    /* binding change, map */
+       BFA_DCONF_SM_TIMEOUT            = 4,    /* Start timer */
+       BFA_DCONF_SM_EXIT               = 5,    /* exit dconf module */
+       BFA_DCONF_SM_IOCDISABLE         = 6,    /* IOC disable event */
+};
+
+/* forward declaration of DCONF state machine */
+static void bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+static void bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf,
+                               enum bfa_dconf_event event);
+
+static void bfa_dconf_cbfn(void *dconf, bfa_status_t status);
+static void bfa_dconf_timer(void *cbarg);
+static bfa_status_t bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf);
+static void bfa_dconf_init_cb(void *arg, bfa_status_t status);
+
+/*
+ * Begining state of dconf module. Waiting for an event to start.
+ */
+static void
+bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
+{
+       bfa_status_t bfa_status;
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_INIT:
+               if (dconf->min_cfg) {
+                       bfa_trc(dconf->bfa, dconf->min_cfg);
+                       return;
+               }
+               bfa_sm_set_state(dconf, bfa_dconf_sm_flash_read);
+               dconf->flashdone = BFA_FALSE;
+               bfa_trc(dconf->bfa, dconf->flashdone);
+               bfa_status = bfa_flash_read_part(BFA_FLASH(dconf->bfa),
+                                       BFA_FLASH_PART_DRV, dconf->instance,
+                                       dconf->dconf,
+                                       sizeof(struct bfa_dconf_s), 0,
+                                       bfa_dconf_init_cb, dconf->bfa);
+               if (bfa_status != BFA_STATUS_OK) {
+                       bfa_dconf_init_cb(dconf->bfa, BFA_STATUS_FAILED);
+                       bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+                       return;
+               }
+               break;
+       case BFA_DCONF_SM_EXIT:
+               dconf->flashdone = BFA_TRUE;
+       case BFA_DCONF_SM_IOCDISABLE:
+       case BFA_DCONF_SM_WR:
+       case BFA_DCONF_SM_FLASH_COMP:
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+/*
+ * Read flash for dconf entries and make a call back to the driver once done.
+ */
+static void
+bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf,
+                       enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_FLASH_COMP:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
+               break;
+       case BFA_DCONF_SM_TIMEOUT:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
+               break;
+       case BFA_DCONF_SM_EXIT:
+               dconf->flashdone = BFA_TRUE;
+               bfa_trc(dconf->bfa, dconf->flashdone);
+       case BFA_DCONF_SM_IOCDISABLE:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+/*
+ * DCONF Module is in ready state. Has completed the initialization.
+ */
+static void
+bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_WR:
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
+               break;
+       case BFA_DCONF_SM_EXIT:
+               dconf->flashdone = BFA_TRUE;
+               bfa_trc(dconf->bfa, dconf->flashdone);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+               break;
+       case BFA_DCONF_SM_INIT:
+       case BFA_DCONF_SM_IOCDISABLE:
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+/*
+ * entries are dirty, write back to the flash.
+ */
+
+static void
+bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_TIMEOUT:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_sync);
+               bfa_dconf_flash_write(dconf);
+               break;
+       case BFA_DCONF_SM_WR:
+               bfa_timer_stop(&dconf->timer);
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               break;
+       case BFA_DCONF_SM_EXIT:
+               bfa_timer_stop(&dconf->timer);
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync);
+               bfa_dconf_flash_write(dconf);
+               break;
+       case BFA_DCONF_SM_FLASH_COMP:
+               break;
+       case BFA_DCONF_SM_IOCDISABLE:
+               bfa_timer_stop(&dconf->timer);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty);
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+/*
+ * Sync the dconf entries to the flash.
+ */
+static void
+bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf,
+                       enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_IOCDISABLE:
+       case BFA_DCONF_SM_FLASH_COMP:
+               bfa_timer_stop(&dconf->timer);
+       case BFA_DCONF_SM_TIMEOUT:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+               dconf->flashdone = BFA_TRUE;
+               bfa_trc(dconf->bfa, dconf->flashdone);
+               bfa_ioc_disable(&dconf->bfa->ioc);
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+static void
+bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_FLASH_COMP:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_ready);
+               break;
+       case BFA_DCONF_SM_WR:
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
+               break;
+       case BFA_DCONF_SM_EXIT:
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync);
+               break;
+       case BFA_DCONF_SM_IOCDISABLE:
+               bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty);
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+static void
+bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf,
+                       enum bfa_dconf_event event)
+{
+       bfa_trc(dconf->bfa, event);
+
+       switch (event) {
+       case BFA_DCONF_SM_INIT:
+               bfa_timer_start(dconf->bfa, &dconf->timer,
+                       bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);
+               bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);
+               break;
+       case BFA_DCONF_SM_EXIT:
+               dconf->flashdone = BFA_TRUE;
+               bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+               break;
+       case BFA_DCONF_SM_IOCDISABLE:
+               break;
+       default:
+               bfa_sm_fault(dconf->bfa, event);
+       }
+}
+
+/*
+ * Compute and return memory needed by DRV_CFG module.
+ */
+static void
+bfa_dconf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
+                 struct bfa_s *bfa)
+{
+       struct bfa_mem_kva_s *dconf_kva = BFA_MEM_DCONF_KVA(bfa);
+
+       if (cfg->drvcfg.min_cfg)
+               bfa_mem_kva_setup(meminfo, dconf_kva,
+                               sizeof(struct bfa_dconf_hdr_s));
+       else
+               bfa_mem_kva_setup(meminfo, dconf_kva,
+                               sizeof(struct bfa_dconf_s));
+}
+
+static void
+bfa_dconf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+               struct bfa_pcidev_s *pcidev)
+{
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+
+       dconf->bfad = bfad;
+       dconf->bfa = bfa;
+       dconf->instance = bfa->ioc.port_id;
+       bfa_trc(bfa, dconf->instance);
+
+       dconf->dconf = (struct bfa_dconf_s *) bfa_mem_kva_curp(dconf);
+       if (cfg->drvcfg.min_cfg) {
+               bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_hdr_s);
+               dconf->min_cfg = BFA_TRUE;
+               /*
+                * Set the flashdone flag to TRUE explicitly as no flash
+                * write will happen in min_cfg mode.
+                */
+               dconf->flashdone = BFA_TRUE;
+       } else {
+               dconf->min_cfg = BFA_FALSE;
+               bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_s);
+       }
+
+       bfa_dconf_read_data_valid(bfa) = BFA_FALSE;
+       bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);
+}
+
+static void
+bfa_dconf_init_cb(void *arg, bfa_status_t status)
+{
+       struct bfa_s *bfa = arg;
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+
+       dconf->flashdone = BFA_TRUE;
+       bfa_trc(bfa, dconf->flashdone);
+       bfa_iocfc_cb_dconf_modinit(bfa, status);
+       if (status == BFA_STATUS_OK) {
+               bfa_dconf_read_data_valid(bfa) = BFA_TRUE;
+               if (dconf->dconf->hdr.signature != BFI_DCONF_SIGNATURE)
+                       dconf->dconf->hdr.signature = BFI_DCONF_SIGNATURE;
+               if (dconf->dconf->hdr.version != BFI_DCONF_VERSION)
+                       dconf->dconf->hdr.version = BFI_DCONF_VERSION;
+       }
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP);
+}
+
+void
+bfa_dconf_modinit(struct bfa_s *bfa)
+{
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_INIT);
+}
+static void
+bfa_dconf_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_dconf_stop(struct bfa_s *bfa)
+{
+}
+
+static void bfa_dconf_timer(void *cbarg)
+{
+       struct bfa_dconf_mod_s *dconf = cbarg;
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_TIMEOUT);
+}
+static void
+bfa_dconf_iocdisable(struct bfa_s *bfa)
+{
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_IOCDISABLE);
+}
+
+static void
+bfa_dconf_detach(struct bfa_s *bfa)
+{
+}
+
+static bfa_status_t
+bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf)
+{
+       bfa_status_t bfa_status;
+       bfa_trc(dconf->bfa, 0);
+
+       bfa_status = bfa_flash_update_part(BFA_FLASH(dconf->bfa),
+                               BFA_FLASH_PART_DRV, dconf->instance,
+                               dconf->dconf,  sizeof(struct bfa_dconf_s), 0,
+                               bfa_dconf_cbfn, dconf);
+       if (bfa_status != BFA_STATUS_OK)
+               WARN_ON(bfa_status);
+       bfa_trc(dconf->bfa, bfa_status);
+
+       return bfa_status;
+}
+
+bfa_status_t
+bfa_dconf_update(struct bfa_s *bfa)
+{
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+       bfa_trc(dconf->bfa, 0);
+       if (bfa_sm_cmp_state(dconf, bfa_dconf_sm_iocdown_dirty))
+               return BFA_STATUS_FAILED;
+
+       if (dconf->min_cfg) {
+               bfa_trc(dconf->bfa, dconf->min_cfg);
+               return BFA_STATUS_FAILED;
+       }
+
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_WR);
+       return BFA_STATUS_OK;
+}
+
+static void
+bfa_dconf_cbfn(void *arg, bfa_status_t status)
+{
+       struct bfa_dconf_mod_s *dconf = arg;
+       WARN_ON(status);
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP);
+}
+
+void
+bfa_dconf_modexit(struct bfa_s *bfa)
+{
+       struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);
+       BFA_DCONF_MOD(bfa)->flashdone = BFA_FALSE;
+       bfa_trc(bfa, BFA_DCONF_MOD(bfa)->flashdone);
+       bfa_sm_send_event(dconf, BFA_DCONF_SM_EXIT);
+}
index c5ecd2edc95da0b6bc3617e7978eb38582344071..546d46b371017102136b0d5b87d49347b424755c 100644 (file)
@@ -327,6 +327,7 @@ struct bfa_ioc_s {
        enum bfa_mode_s         port_mode;
        u8                      ad_cap_bm;      /* adapter cap bit mask */
        u8                      port_mode_cfg;  /* config port mode */
+       int                     ioc_aen_seq;
 };
 
 struct bfa_ioc_hwif_s {
@@ -366,6 +367,8 @@ struct bfa_cb_qe_s {
        struct list_head        qe;
        bfa_cb_cbfn_t   cbfn;
        bfa_boolean_t   once;
+       bfa_boolean_t   pre_rmv;        /* set for stack based qe(s) */
+       bfa_status_t    fw_status;      /* to access fw status in comp proc */
        void            *cbarg;
 };
 
@@ -658,7 +661,6 @@ struct bfa_phy_s {
        struct bfa_ioc_notify_s ioc_notify; /* ioc event notify */
        struct bfa_mem_dma_s    phy_dma;
 };
-
 #define BFA_PHY(__bfa) (&(__bfa)->modules.phy)
 #define BFA_MEM_PHY_DMA(__bfa) (&(BFA_PHY(__bfa)->phy_dma))
 
@@ -683,6 +685,49 @@ void bfa_phy_memclaim(struct bfa_phy_s *phy,
                u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg);
 void bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg);
 
+/*
+ * Driver Config( dconf) specific
+ */
+#define BFI_DCONF_SIGNATURE    0xabcdabcd
+#define BFI_DCONF_VERSION      1
+
+#pragma pack(1)
+struct bfa_dconf_hdr_s {
+       u32     signature;
+       u32     version;
+};
+
+struct bfa_dconf_s {
+       struct bfa_dconf_hdr_s          hdr;
+       struct bfa_lunmask_cfg_s        lun_mask;
+};
+#pragma pack()
+
+struct bfa_dconf_mod_s {
+       bfa_sm_t                sm;
+       u8                      instance;
+       bfa_boolean_t           flashdone;
+       bfa_boolean_t           read_data_valid;
+       bfa_boolean_t           min_cfg;
+       struct bfa_timer_s      timer;
+       struct bfa_s            *bfa;
+       void                    *bfad;
+       void                    *trcmod;
+       struct bfa_dconf_s      *dconf;
+       struct bfa_mem_kva_s    kva_seg;
+};
+
+#define BFA_DCONF_MOD(__bfa)   \
+       (&(__bfa)->modules.dconf_mod)
+#define BFA_MEM_DCONF_KVA(__bfa)       (&(BFA_DCONF_MOD(__bfa)->kva_seg))
+#define bfa_dconf_read_data_valid(__bfa)       \
+       (BFA_DCONF_MOD(__bfa)->read_data_valid)
+#define BFA_DCONF_UPDATE_TOV   5000    /* memtest timeout in msec */
+
+void   bfa_dconf_modinit(struct bfa_s *bfa);
+void   bfa_dconf_modexit(struct bfa_s *bfa);
+bfa_status_t   bfa_dconf_update(struct bfa_s *bfa);
+
 /*
  *     IOC specfic macros
  */
@@ -803,6 +848,7 @@ void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc,
                        struct bfi_ioc_image_hdr_s *fwhdr);
 bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc,
                        struct bfi_ioc_image_hdr_s *fwhdr);
+void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event);
 bfa_status_t bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats);
 bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc);
 
index 1c6efd40a673f0fadf9adc365108a57f780dd155..2d36e4823835d326bfc32c2c29f9a2d8e93d55c9 100644 (file)
@@ -44,6 +44,7 @@ struct bfa_modules_s {
        struct bfa_flash_s      flash;          /*  flash module */
        struct bfa_diag_s       diag_mod;       /*  diagnostics module  */
        struct bfa_phy_s        phy;            /*  phy module          */
+       struct bfa_dconf_mod_s  dconf_mod;      /*  DCONF common module */
 };
 
 /*
@@ -119,6 +120,7 @@ struct bfa_s {
        struct list_head        reqq_waitq[BFI_IOC_MAX_CQS];
        bfa_boolean_t           fcs;            /*  FCS is attached to BFA */
        struct bfa_msix_s       msix;
+       int                     bfa_aen_seq;
 };
 
 extern bfa_boolean_t bfa_auto_recover;
@@ -130,5 +132,6 @@ extern struct bfa_module_s hal_mod_lps;
 extern struct bfa_module_s hal_mod_uf;
 extern struct bfa_module_s hal_mod_rport;
 extern struct bfa_module_s hal_mod_fcp;
+extern struct bfa_module_s hal_mod_dconf;
 
 #endif /* __BFA_MODULES_H__ */
index 21caaefce99fc9f143af955622615efce1434867..aa8a0eaf91f9c6b7a2e846dc51048726dd10c5a2 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "bfad_drv.h"
+#include "bfad_im.h"
 #include "bfa_plog.h"
 #include "bfa_cs.h"
 #include "bfa_modules.h"
@@ -2007,6 +2008,24 @@ bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        }
 }
 
+static void
+bfa_fcport_aen_post(struct bfa_fcport_s *fcport, enum bfa_port_aen_event event)
+{
+       struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad;
+       struct bfa_aen_entry_s  *aen_entry;
+
+       bfad_get_aen_entry(bfad, aen_entry);
+       if (!aen_entry)
+               return;
+
+       aen_entry->aen_data.port.ioc_type = bfa_get_type(fcport->bfa);
+       aen_entry->aen_data.port.pwwn = fcport->pwwn;
+
+       /* Send the AEN notification */
+       bfad_im_post_vendor_event(aen_entry, bfad, ++fcport->bfa->bfa_aen_seq,
+                                 BFA_AEN_CAT_PORT, event);
+}
+
 /*
  * FC PORT state machine functions
  */
@@ -2095,6 +2114,7 @@ bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port disabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
        case BFA_FCPORT_SM_LINKUP:
@@ -2155,6 +2175,7 @@ bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port disabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
        case BFA_FCPORT_SM_STOP:
@@ -2208,6 +2229,12 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port online: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ONLINE);
+
+               /* If QoS is enabled and it is not online, send AEN */
+               if (fcport->cfg.qos_enabled &&
+                   fcport->qos_attr.state != BFA_QOS_ONLINE)
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_QOS_NEG);
                break;
 
        case BFA_FCPORT_SM_LINKDOWN:
@@ -2234,6 +2261,7 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port disabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
        case BFA_FCPORT_SM_STOP:
@@ -2279,8 +2307,10 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port offline: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port disabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE);
                break;
 
        case BFA_FCPORT_SM_LINKDOWN:
@@ -2290,26 +2320,32 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
                bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL,
                                BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown");
                wwn2str(pwwn_buf, fcport->pwwn);
-               if (BFA_PORT_IS_DISABLED(fcport->bfa))
+               if (BFA_PORT_IS_DISABLED(fcport->bfa)) {
                        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                                "Base port offline: WWN = %s\n", pwwn_buf);
-               else
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
+               } else {
                        BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                                "Base port (WWN = %s) "
                                "lost fabric connectivity\n", pwwn_buf);
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
+               }
                break;
 
        case BFA_FCPORT_SM_STOP:
                bfa_sm_set_state(fcport, bfa_fcport_sm_stopped);
                bfa_fcport_reset_linkinfo(fcport);
                wwn2str(pwwn_buf, fcport->pwwn);
-               if (BFA_PORT_IS_DISABLED(fcport->bfa))
+               if (BFA_PORT_IS_DISABLED(fcport->bfa)) {
                        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                                "Base port offline: WWN = %s\n", pwwn_buf);
-               else
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
+               } else {
                        BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                                "Base port (WWN = %s) "
                                "lost fabric connectivity\n", pwwn_buf);
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
+               }
                break;
 
        case BFA_FCPORT_SM_HWFAIL:
@@ -2317,13 +2353,16 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport,
                bfa_fcport_reset_linkinfo(fcport);
                bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE);
                wwn2str(pwwn_buf, fcport->pwwn);
-               if (BFA_PORT_IS_DISABLED(fcport->bfa))
+               if (BFA_PORT_IS_DISABLED(fcport->bfa)) {
                        BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                                "Base port offline: WWN = %s\n", pwwn_buf);
-               else
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE);
+               } else {
                        BFA_LOG(KERN_ERR, bfad, bfa_log_level,
                                "Base port (WWN = %s) "
                                "lost fabric connectivity\n", pwwn_buf);
+                       bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT);
+               }
                break;
 
        default:
@@ -2454,6 +2493,7 @@ bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port enabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE);
                break;
 
        case BFA_FCPORT_SM_STOP:
@@ -2508,6 +2548,7 @@ bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport,
                wwn2str(pwwn_buf, fcport->pwwn);
                BFA_LOG(KERN_INFO, bfad, bfa_log_level,
                        "Base port enabled: WWN = %s\n", pwwn_buf);
+               bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE);
                break;
 
        case BFA_FCPORT_SM_DISABLE:
@@ -2874,6 +2915,9 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
 
        port_cfg->trl_def_speed = BFA_PORT_SPEED_1GBPS;
 
+       INIT_LIST_HEAD(&fcport->stats_pending_q);
+       INIT_LIST_HEAD(&fcport->statsclr_pending_q);
+
        bfa_reqq_winit(&fcport->reqq_wait, bfa_fcport_qresume, fcport);
 }
 
@@ -3102,30 +3146,38 @@ bfa_fcport_fcoe_stats_swap(struct bfa_fcoe_stats_s *d,
 static void
 __bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete)
 {
-       struct bfa_fcport_s *fcport = cbarg;
+       struct bfa_fcport_s *fcport = (struct bfa_fcport_s *)cbarg;
+       struct bfa_cb_pending_q_s *cb;
+       struct list_head *qe, *qen;
+       union bfa_fcport_stats_u *ret;
 
        if (complete) {
-               if (fcport->stats_status == BFA_STATUS_OK) {
-                       struct timeval tv;
-
-                       /* Swap FC QoS or FCoE stats */
-                       if (bfa_ioc_get_fcmode(&fcport->bfa->ioc)) {
-                               bfa_fcport_qos_stats_swap(
-                                       &fcport->stats_ret->fcqos,
-                                       &fcport->stats->fcqos);
-                       } else {
-                               bfa_fcport_fcoe_stats_swap(
-                                       &fcport->stats_ret->fcoe,
-                                       &fcport->stats->fcoe);
-
-                               do_gettimeofday(&tv);
-                               fcport->stats_ret->fcoe.secs_reset =
+               struct timeval tv;
+               if (fcport->stats_status == BFA_STATUS_OK)
+                       do_gettimeofday(&tv);
+
+               list_for_each_safe(qe, qen, &fcport->stats_pending_q) {
+                       bfa_q_deq(&fcport->stats_pending_q, &qe);
+                       cb = (struct bfa_cb_pending_q_s *)qe;
+                       if (fcport->stats_status == BFA_STATUS_OK) {
+                               ret = (union bfa_fcport_stats_u *)cb->data;
+                               /* Swap FC QoS or FCoE stats */
+                               if (bfa_ioc_get_fcmode(&fcport->bfa->ioc))
+                                       bfa_fcport_qos_stats_swap(&ret->fcqos,
+                                                       &fcport->stats->fcqos);
+                               else {
+                                       bfa_fcport_fcoe_stats_swap(&ret->fcoe,
+                                                       &fcport->stats->fcoe);
+                                       ret->fcoe.secs_reset =
                                        tv.tv_sec - fcport->stats_reset_time;
+                               }
                        }
+                       bfa_cb_queue_status(fcport->bfa, &cb->hcb_qe,
+                                       fcport->stats_status);
                }
-               fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
+               fcport->stats_status = BFA_STATUS_OK;
        } else {
-               fcport->stats_busy = BFA_FALSE;
+               INIT_LIST_HEAD(&fcport->stats_pending_q);
                fcport->stats_status = BFA_STATUS_OK;
        }
 }
@@ -3143,8 +3195,7 @@ bfa_fcport_stats_get_timeout(void *cbarg)
        }
 
        fcport->stats_status = BFA_STATUS_ETIMER;
-       bfa_cb_queue(fcport->bfa, &fcport->hcb_qe, __bfa_cb_fcport_stats_get,
-               fcport);
+       __bfa_cb_fcport_stats_get(fcport, BFA_TRUE);
 }
 
 static void
@@ -3174,7 +3225,9 @@ bfa_fcport_send_stats_get(void *cbarg)
 static void
 __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete)
 {
-       struct bfa_fcport_s *fcport = cbarg;
+       struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg;
+       struct bfa_cb_pending_q_s *cb;
+       struct list_head *qe, *qen;
 
        if (complete) {
                struct timeval tv;
@@ -3184,10 +3237,15 @@ __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete)
                 */
                do_gettimeofday(&tv);
                fcport->stats_reset_time = tv.tv_sec;
-
-               fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status);
+               list_for_each_safe(qe, qen, &fcport->statsclr_pending_q) {
+                       bfa_q_deq(&fcport->statsclr_pending_q, &qe);
+                       cb = (struct bfa_cb_pending_q_s *)qe;
+                       bfa_cb_queue_status(fcport->bfa, &cb->hcb_qe,
+                                               fcport->stats_status);
+               }
+               fcport->stats_status = BFA_STATUS_OK;
        } else {
-               fcport->stats_busy = BFA_FALSE;
+               INIT_LIST_HEAD(&fcport->statsclr_pending_q);
                fcport->stats_status = BFA_STATUS_OK;
        }
 }
@@ -3205,8 +3263,7 @@ bfa_fcport_stats_clr_timeout(void *cbarg)
        }
 
        fcport->stats_status = BFA_STATUS_ETIMER;
-       bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
-                       __bfa_cb_fcport_stats_clr, fcport);
+       __bfa_cb_fcport_stats_clr(fcport, BFA_TRUE);
 }
 
 static void
@@ -3402,6 +3459,11 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
                                fcport->use_flash_cfg = BFA_FALSE;
                        }
 
+                       if (fcport->cfg.qos_enabled)
+                               fcport->qos_attr.state = BFA_QOS_OFFLINE;
+                       else
+                               fcport->qos_attr.state = BFA_QOS_DISABLED;
+
                        bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP);
                }
                break;
@@ -3426,28 +3488,26 @@ bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
                /*
                 * check for timer pop before processing the rsp
                 */
-               if (fcport->stats_busy == BFA_FALSE ||
-                   fcport->stats_status == BFA_STATUS_ETIMER)
+               if (list_empty(&fcport->stats_pending_q) ||
+                   (fcport->stats_status == BFA_STATUS_ETIMER))
                        break;
 
                bfa_timer_stop(&fcport->timer);
                fcport->stats_status = i2hmsg.pstatsget_rsp->status;
-               bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
-                               __bfa_cb_fcport_stats_get, fcport);
+               __bfa_cb_fcport_stats_get(fcport, BFA_TRUE);
                break;
 
        case BFI_FCPORT_I2H_STATS_CLEAR_RSP:
                /*
                 * check for timer pop before processing the rsp
                 */
-               if (fcport->stats_busy == BFA_FALSE ||
-                   fcport->stats_status == BFA_STATUS_ETIMER)
+               if (list_empty(&fcport->statsclr_pending_q) ||
+                   (fcport->stats_status == BFA_STATUS_ETIMER))
                        break;
 
                bfa_timer_stop(&fcport->timer);
                fcport->stats_status = BFA_STATUS_OK;
-               bfa_cb_queue(fcport->bfa, &fcport->hcb_qe,
-                               __bfa_cb_fcport_stats_clr, fcport);
+               __bfa_cb_fcport_stats_clr(fcport, BFA_TRUE);
                break;
 
        case BFI_FCPORT_I2H_ENABLE_AEN:
@@ -3779,25 +3839,25 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr)
  * Fetch port statistics (FCQoS or FCoE).
  */
 bfa_status_t
-bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
-       bfa_cb_port_t cbfn, void *cbarg)
+bfa_fcport_get_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb)
 {
        struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       if (fcport->stats_busy) {
-               bfa_trc(bfa, fcport->stats_busy);
-               return BFA_STATUS_DEVBUSY;
-       }
+       if (bfa_ioc_is_disabled(&bfa->ioc))
+               return BFA_STATUS_IOC_DISABLED;
 
-       fcport->stats_busy  = BFA_TRUE;
-       fcport->stats_ret   = stats;
-       fcport->stats_cbfn  = cbfn;
-       fcport->stats_cbarg = cbarg;
+       if (!list_empty(&fcport->statsclr_pending_q))
+               return BFA_STATUS_DEVBUSY;
 
-       bfa_fcport_send_stats_get(fcport);
+       if (list_empty(&fcport->stats_pending_q)) {
+               list_add_tail(&cb->hcb_qe.qe, &fcport->stats_pending_q);
+               bfa_fcport_send_stats_get(fcport);
+               bfa_timer_start(bfa, &fcport->timer,
+                               bfa_fcport_stats_get_timeout,
+                               fcport, BFA_FCPORT_STATS_TOV);
+       } else
+               list_add_tail(&cb->hcb_qe.qe, &fcport->stats_pending_q);
 
-       bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_get_timeout,
-                       fcport, BFA_FCPORT_STATS_TOV);
        return BFA_STATUS_OK;
 }
 
@@ -3805,27 +3865,25 @@ bfa_fcport_get_stats(struct bfa_s *bfa, union bfa_fcport_stats_u *stats,
  * Reset port statistics (FCQoS or FCoE).
  */
 bfa_status_t
-bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn, void *cbarg)
+bfa_fcport_clear_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb)
 {
        struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa);
 
-       if (fcport->stats_busy) {
-               bfa_trc(bfa, fcport->stats_busy);
+       if (!list_empty(&fcport->stats_pending_q))
                return BFA_STATUS_DEVBUSY;
-       }
-
-       fcport->stats_busy  = BFA_TRUE;
-       fcport->stats_cbfn  = cbfn;
-       fcport->stats_cbarg = cbarg;
 
-       bfa_fcport_send_stats_clear(fcport);
+       if (list_empty(&fcport->statsclr_pending_q)) {
+               list_add_tail(&cb->hcb_qe.qe, &fcport->statsclr_pending_q);
+               bfa_fcport_send_stats_clear(fcport);
+               bfa_timer_start(bfa, &fcport->timer,
+                               bfa_fcport_stats_clr_timeout,
+                               fcport, BFA_FCPORT_STATS_TOV);
+       } else
+               list_add_tail(&cb->hcb_qe.qe, &fcport->statsclr_pending_q);
 
-       bfa_timer_start(bfa, &fcport->timer, bfa_fcport_stats_clr_timeout,
-                       fcport, BFA_FCPORT_STATS_TOV);
        return BFA_STATUS_OK;
 }
 
-
 /*
  * Fetch port attributes.
  */
@@ -4619,6 +4677,7 @@ bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
                rp = BFA_RPORT_FROM_TAG(bfa, msg.create_rsp->bfa_handle);
                rp->fw_handle = msg.create_rsp->fw_handle;
                rp->qos_attr = msg.create_rsp->qos_attr;
+               bfa_rport_set_lunmask(bfa, rp);
                WARN_ON(msg.create_rsp->status != BFA_STATUS_OK);
                bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
                break;
@@ -4626,6 +4685,7 @@ bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
        case BFI_RPORT_I2H_DELETE_RSP:
                rp = BFA_RPORT_FROM_TAG(bfa, msg.delete_rsp->bfa_handle);
                WARN_ON(msg.delete_rsp->status != BFA_STATUS_OK);
+               bfa_rport_unset_lunmask(bfa, rp);
                bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
                break;
 
@@ -4706,6 +4766,37 @@ bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed)
        bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED);
 }
 
+/* Set Rport LUN Mask */
+void
+bfa_rport_set_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp)
+{
+       struct bfa_lps_mod_s    *lps_mod = BFA_LPS_MOD(bfa);
+       wwn_t   lp_wwn, rp_wwn;
+       u8 lp_tag = (u8)rp->rport_info.lp_tag;
+
+       rp_wwn = ((struct bfa_fcs_rport_s *)rp->rport_drv)->pwwn;
+       lp_wwn = (BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag))->pwwn;
+
+       BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag)->lun_mask =
+                                       rp->lun_mask = BFA_TRUE;
+       bfa_fcpim_lunmask_rp_update(bfa, lp_wwn, rp_wwn, rp->rport_tag, lp_tag);
+}
+
+/* Unset Rport LUN mask */
+void
+bfa_rport_unset_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp)
+{
+       struct bfa_lps_mod_s    *lps_mod = BFA_LPS_MOD(bfa);
+       wwn_t   lp_wwn, rp_wwn;
+
+       rp_wwn = ((struct bfa_fcs_rport_s *)rp->rport_drv)->pwwn;
+       lp_wwn = (BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag))->pwwn;
+
+       BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag)->lun_mask =
+                               rp->lun_mask = BFA_FALSE;
+       bfa_fcpim_lunmask_rp_update(bfa, lp_wwn, rp_wwn,
+                       BFA_RPORT_TAG_INVALID, BFA_LP_TAG_INVALID);
+}
 
 /*
  * SGPG related functions
@@ -5517,11 +5608,29 @@ bfa_fcdiag_loopback(struct bfa_s *bfa, enum bfa_port_opmode opmode,
                return BFA_STATUS_PORT_NOT_DISABLED;
        }
 
-       /* Check if the speed is supported */
-       bfa_fcport_get_attr(bfa, &attr);
-       bfa_trc(fcdiag, attr.speed_supported);
-       if (speed > attr.speed_supported)
-               return BFA_STATUS_UNSUPP_SPEED;
+       /*
+        * Check if input speed is supported by the port mode
+        */
+       if (bfa_ioc_get_type(&bfa->ioc) == BFA_IOC_TYPE_FC) {
+               if (!(speed == BFA_PORT_SPEED_1GBPS ||
+                     speed == BFA_PORT_SPEED_2GBPS ||
+                     speed == BFA_PORT_SPEED_4GBPS ||
+                     speed == BFA_PORT_SPEED_8GBPS ||
+                     speed == BFA_PORT_SPEED_16GBPS ||
+                     speed == BFA_PORT_SPEED_AUTO)) {
+                       bfa_trc(fcdiag, speed);
+                       return BFA_STATUS_UNSUPP_SPEED;
+               }
+               bfa_fcport_get_attr(bfa, &attr);
+               bfa_trc(fcdiag, attr.speed_supported);
+               if (speed > attr.speed_supported)
+                       return BFA_STATUS_UNSUPP_SPEED;
+       } else {
+               if (speed != BFA_PORT_SPEED_10GBPS) {
+                       bfa_trc(fcdiag, speed);
+                       return BFA_STATUS_UNSUPP_SPEED;
+               }
+       }
 
        /* For Mezz card, port speed entered needs to be checked */
        if (bfa_mfg_is_mezz(bfa->ioc.attr->card_type)) {
index fbe513a671b5b830acf3ecb3c09c9ab13af1958e..95adb86d3769d477bdbf0b652aa704621eca665b 100644 (file)
@@ -297,6 +297,7 @@ struct bfa_rport_s {
        void            *rport_drv;     /*  fcs/driver rport object         */
        u16     fw_handle;      /*  firmware rport handle           */
        u16     rport_tag;      /*  BFA rport tag                   */
+       u8      lun_mask;       /*  LUN mask flag                   */
        struct bfa_rport_info_s rport_info; /*  rport info from fcs/driver */
        struct bfa_reqq_wait_s reqq_wait; /*  to wait for room in reqq     */
        struct bfa_cb_qe_s hcb_qe;      /*  BFA callback qelem              */
@@ -404,6 +405,7 @@ struct bfa_lps_s {
        u8              bb_scn;         /*  local BB_SCN                */
        u8              lsrjt_rsn;      /*  LSRJT reason                */
        u8              lsrjt_expl;     /*  LSRJT explanation           */
+       u8              lun_mask;       /*  LUN mask flag               */
        wwn_t           pwwn;           /*  port wwn of lport           */
        wwn_t           nwwn;           /*  node wwn of lport           */
        wwn_t           pr_pwwn;        /*  port wwn of lport peer      */
@@ -441,7 +443,6 @@ void        bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
  */
 
 #define BFA_FCPORT(_bfa)       (&((_bfa)->modules.port))
-typedef void (*bfa_cb_port_t) (void *cbarg, enum bfa_status status);
 
 /*
  * Link notification data structure
@@ -495,13 +496,11 @@ struct bfa_fcport_s {
        u8                      *stats_kva;
        u64             stats_pa;
        union bfa_fcport_stats_u *stats;
-       union bfa_fcport_stats_u *stats_ret; /*  driver stats location */
        bfa_status_t            stats_status; /*  stats/statsclr status */
-       bfa_boolean_t           stats_busy; /*  outstanding stats/statsclr */
+       struct list_head        stats_pending_q;
+       struct list_head        statsclr_pending_q;
        bfa_boolean_t           stats_qfull;
        u32             stats_reset_time; /*  stats reset time stamp */
-       bfa_cb_port_t           stats_cbfn; /*  driver callback function */
-       void                    *stats_cbarg; /* *!< user callback arg */
        bfa_boolean_t           diag_busy; /*  diag busy status */
        bfa_boolean_t           beacon; /*  port beacon status */
        bfa_boolean_t           link_e2e_beacon; /*  link beacon status */
@@ -552,10 +551,9 @@ void bfa_fcport_beacon(void *dev, bfa_boolean_t beacon,
                        bfa_boolean_t link_e2e_beacon);
 bfa_boolean_t  bfa_fcport_is_linkup(struct bfa_s *bfa);
 bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa,
-                                 union bfa_fcport_stats_u *stats,
-                                 bfa_cb_port_t cbfn, void *cbarg);
-bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_port_t cbfn,
-                                   void *cbarg);
+                       struct bfa_cb_pending_q_s *cb);
+bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa,
+                       struct bfa_cb_pending_q_s *cb);
 bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa);
 bfa_boolean_t bfa_fcport_is_trunk_enabled(struct bfa_s *bfa);
 bfa_status_t bfa_fcport_is_pbcdisabled(struct bfa_s *bfa);
@@ -577,6 +575,19 @@ void bfa_cb_rport_qos_scn_prio(void *rport,
                               struct bfa_rport_qos_attr_s old_qos_attr,
                               struct bfa_rport_qos_attr_s new_qos_attr);
 
+/*
+ *     Rport LUN masking related
+ */
+#define BFA_RPORT_TAG_INVALID  0xffff
+#define BFA_LP_TAG_INVALID     0xff
+void   bfa_rport_set_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp);
+void   bfa_rport_unset_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp);
+bfa_boolean_t  bfa_rport_lunmask_active(struct bfa_rport_s *rp);
+wwn_t  bfa_rport_get_pwwn(struct bfa_s *bfa, struct bfa_rport_s *rp);
+struct bfa_rport_s *bfa_rport_get_by_wwn(struct bfa_s *bfa, u16 vf_id,
+                                        wwn_t *lpwwn, wwn_t rpwwn);
+void *bfa_cb_get_rp_by_wwn(void *arg, u16 vf_id, wwn_t *lpwwn, wwn_t rpwwn);
+
 /*
  * bfa fcxp API functions
  */
index beb30a748ea567d4024fc59525002f4fa2499673..66fb72531b34caab0323797761d68ac2ab0e6fbc 100644 (file)
@@ -1348,7 +1348,7 @@ int
 bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
        struct bfad_s   *bfad;
-       int             error = -ENODEV, retval;
+       int             error = -ENODEV, retval, i;
 
        /* For single port cards - only claim function 0 */
        if ((pdev->device == BFA_PCI_DEVICE_ID_FC_8G1P) &&
@@ -1372,6 +1372,12 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
        bfa_trc_init(bfad->trcmod);
        bfa_trc(bfad, bfad_inst);
 
+       /* AEN INIT */
+       INIT_LIST_HEAD(&bfad->free_aen_q);
+       INIT_LIST_HEAD(&bfad->active_aen_q);
+       for (i = 0; i < BFA_AEN_MAX_ENTRY; i++)
+               list_add_tail(&bfad->aen_list[i].qe, &bfad->free_aen_q);
+
        if (!(bfad_load_fwimg(pdev))) {
                kfree(bfad->trcmod);
                goto out_alloc_trace_failure;
index 89f863ed2334e9c14c8bbf341a75b22993adc6e0..06fc00caeb41f725750a1ddafd44b5731e7eaa4a 100644 (file)
@@ -56,7 +56,7 @@ bfad_iocmd_ioc_disable(struct bfad_s *bfad, void *cmd)
        spin_lock_irqsave(&bfad->bfad_lock, flags);
        if (bfad->disable_active) {
                spin_unlock_irqrestore(&bfad->bfad_lock, flags);
-               return EBUSY;
+               return -EBUSY;
        }
 
        bfad->disable_active = BFA_TRUE;
@@ -90,6 +90,7 @@ bfad_iocmd_ioc_get_info(struct bfad_s *bfad, void *cmd)
        bfa_get_adapter_serial_num(&bfad->bfa, iocmd->serialnum);
        iocmd->factorynwwn = pattr.factorynwwn;
        iocmd->factorypwwn = pattr.factorypwwn;
+       iocmd->bfad_num = bfad->inst_no;
        im_port = bfad->pport.im_port;
        iocmd->host = im_port->shost->host_no;
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
@@ -177,6 +178,38 @@ out:
        return 0;
 }
 
+int
+bfad_iocmd_ioc_reset_stats(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       unsigned long   flags;
+
+       if (v_cmd == IOCMD_IOC_RESET_STATS) {
+               bfa_ioc_clear_stats(&bfad->bfa);
+               iocmd->status = BFA_STATUS_OK;
+       } else if (v_cmd == IOCMD_IOC_RESET_FWSTATS) {
+               spin_lock_irqsave(&bfad->bfad_lock, flags);
+               iocmd->status = bfa_ioc_fw_stats_clear(&bfad->bfa.ioc);
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       }
+
+       return 0;
+}
+
+int
+bfad_iocmd_ioc_set_name(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_ioc_name_s *iocmd = (struct bfa_bsg_ioc_name_s *) cmd;
+
+       if (v_cmd == IOCMD_IOC_SET_ADAPTER_NAME)
+               strcpy(bfad->adapter_name, iocmd->name);
+       else if (v_cmd == IOCMD_IOC_SET_PORT_NAME)
+               strcpy(bfad->port_name, iocmd->name);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
 int
 bfad_iocmd_iocfc_get_attr(struct bfad_s *bfad, void *cmd)
 {
@@ -306,6 +339,81 @@ out:
        return 0;
 }
 
+int
+bfad_iocmd_port_reset_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_port_clear_stats(&bfad->bfa.modules.port,
+                                       bfad_hcb_comp, &fcomp);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK) {
+               bfa_trc(bfad, iocmd->status);
+               return 0;
+       }
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+       return 0;
+}
+
+int
+bfad_iocmd_set_port_cfg(struct bfad_s *bfad, void *iocmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_port_cfg_s *cmd = (struct bfa_bsg_port_cfg_s *)iocmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (v_cmd == IOCMD_PORT_CFG_TOPO)
+               cmd->status = bfa_fcport_cfg_topology(&bfad->bfa, cmd->param);
+       else if (v_cmd == IOCMD_PORT_CFG_SPEED)
+               cmd->status = bfa_fcport_cfg_speed(&bfad->bfa, cmd->param);
+       else if (v_cmd == IOCMD_PORT_CFG_ALPA)
+               cmd->status = bfa_fcport_cfg_hardalpa(&bfad->bfa, cmd->param);
+       else if (v_cmd == IOCMD_PORT_CLR_ALPA)
+               cmd->status = bfa_fcport_clr_hardalpa(&bfad->bfa);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+int
+bfad_iocmd_port_cfg_maxfrsize(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_port_cfg_maxfrsize_s *iocmd =
+                               (struct bfa_bsg_port_cfg_maxfrsize_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_fcport_cfg_maxfrsize(&bfad->bfa, iocmd->maxfrsize);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+int
+bfad_iocmd_port_cfg_bbsc(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (bfa_ioc_get_type(&bfad->bfa.ioc) == BFA_IOC_TYPE_FC) {
+               if (v_cmd == IOCMD_PORT_BBSC_ENABLE)
+                       fcport->cfg.bb_scn_state = BFA_TRUE;
+               else if (v_cmd == IOCMD_PORT_BBSC_DISABLE)
+                       fcport->cfg.bb_scn_state = BFA_FALSE;
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
 static int
 bfad_iocmd_lport_get_attr(struct bfad_s *bfad, void *cmd)
 {
@@ -353,6 +461,40 @@ out:
        return 0;
 }
 
+int
+bfad_iocmd_lport_reset_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_fcs_lport_s *fcs_port;
+       struct bfa_bsg_reset_stats_s *iocmd =
+                       (struct bfa_bsg_reset_stats_s *)cmd;
+       struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa);
+       struct list_head *qe, *qen;
+       struct bfa_itnim_s *itnim;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->vpwwn);
+       if (fcs_port == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_LWWN;
+               goto out;
+       }
+
+       bfa_fcs_lport_clear_stats(fcs_port);
+       /* clear IO stats from all active itnims */
+       list_for_each_safe(qe, qen, &fcpim->itnim_q) {
+               itnim = (struct bfa_itnim_s *) qe;
+               if (itnim->rport->rport_info.lp_tag != fcs_port->lp_tag)
+                       continue;
+               bfa_itnim_clear_stats(itnim);
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
 int
 bfad_iocmd_lport_get_iostats(struct bfad_s *bfad, void *cmd)
 {
@@ -389,7 +531,7 @@ bfad_iocmd_lport_get_rports(struct bfad_s *bfad, void *cmd,
        void    *iocmd_bufptr;
 
        if (iocmd->nrports == 0)
-               return EINVAL;
+               return -EINVAL;
 
        if (bfad_chk_iocmd_sz(payload_len,
                        sizeof(struct bfa_bsg_lport_get_rports_s),
@@ -539,6 +681,152 @@ out:
        return 0;
 }
 
+int
+bfad_iocmd_rport_clr_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_rport_reset_stats_s *iocmd =
+                               (struct bfa_bsg_rport_reset_stats_s *)cmd;
+       struct bfa_fcs_lport_s *fcs_port;
+       struct bfa_fcs_rport_s *fcs_rport;
+       struct bfa_rport_s *rport;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->pwwn);
+       if (fcs_port == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_LWWN;
+               goto out;
+       }
+
+       fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn);
+       if (fcs_rport == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_RWWN;
+               goto out;
+       }
+
+       memset((char *)&fcs_rport->stats, 0, sizeof(struct bfa_rport_stats_s));
+       rport = bfa_fcs_rport_get_halrport(fcs_rport);
+       memset(&rport->stats, 0, sizeof(rport->stats));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_rport_set_speed(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_rport_set_speed_s *iocmd =
+                               (struct bfa_bsg_rport_set_speed_s *)cmd;
+       struct bfa_fcs_lport_s *fcs_port;
+       struct bfa_fcs_rport_s *fcs_rport;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->pwwn);
+       if (fcs_port == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_LWWN;
+               goto out;
+       }
+
+       fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn);
+       if (fcs_rport == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_RWWN;
+               goto out;
+       }
+
+       fcs_rport->rpf.assigned_speed  = iocmd->speed;
+       /* Set this speed in f/w only if the RPSC speed is not available */
+       if (fcs_rport->rpf.rpsc_speed == BFA_PORT_SPEED_UNKNOWN)
+               bfa_rport_speed(fcs_rport->bfa_rport, iocmd->speed);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_vport_get_attr(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_fcs_vport_s *fcs_vport;
+       struct bfa_bsg_vport_attr_s *iocmd = (struct bfa_bsg_vport_attr_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->vpwwn);
+       if (fcs_vport == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_VWWN;
+               goto out;
+       }
+
+       bfa_fcs_vport_get_attr(fcs_vport, &iocmd->vport_attr);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_vport_get_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_fcs_vport_s *fcs_vport;
+       struct bfa_bsg_vport_stats_s *iocmd =
+                               (struct bfa_bsg_vport_stats_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->vpwwn);
+       if (fcs_vport == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_VWWN;
+               goto out;
+       }
+
+       memcpy((void *)&iocmd->vport_stats, (void *)&fcs_vport->vport_stats,
+               sizeof(struct bfa_vport_stats_s));
+       memcpy((void *)&iocmd->vport_stats.port_stats,
+              (void *)&fcs_vport->lport.stats,
+               sizeof(struct bfa_lport_stats_s));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_vport_clr_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_fcs_vport_s *fcs_vport;
+       struct bfa_bsg_reset_stats_s *iocmd =
+                               (struct bfa_bsg_reset_stats_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->vpwwn);
+       if (fcs_vport == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_VWWN;
+               goto out;
+       }
+
+       memset(&fcs_vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s));
+       memset(&fcs_vport->lport.stats, 0, sizeof(struct bfa_lport_stats_s));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
 static int
 bfad_iocmd_fabric_get_lports(struct bfad_s *bfad, void *cmd,
                        unsigned int payload_len)
@@ -581,6 +869,66 @@ out:
        return 0;
 }
 
+int
+bfad_iocmd_ratelim(struct bfad_s *bfad, unsigned int cmd, void *pcmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+       if (cmd == IOCMD_RATELIM_ENABLE)
+               fcport->cfg.ratelimit = BFA_TRUE;
+       else if (cmd == IOCMD_RATELIM_DISABLE)
+               fcport->cfg.ratelimit = BFA_FALSE;
+
+       if (fcport->cfg.trl_def_speed == BFA_PORT_SPEED_UNKNOWN)
+               fcport->cfg.trl_def_speed = BFA_PORT_SPEED_1GBPS;
+
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+
+       return 0;
+}
+
+int
+bfad_iocmd_ratelim_speed(struct bfad_s *bfad, unsigned int cmd, void *pcmd)
+{
+       struct bfa_bsg_trl_speed_s *iocmd = (struct bfa_bsg_trl_speed_s *)pcmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+       /* Auto and speeds greater than the supported speed, are invalid */
+       if ((iocmd->speed == BFA_PORT_SPEED_AUTO) ||
+           (iocmd->speed > fcport->speed_sup)) {
+               iocmd->status = BFA_STATUS_UNSUPP_SPEED;
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               return 0;
+       }
+
+       fcport->cfg.trl_def_speed = iocmd->speed;
+       iocmd->status = BFA_STATUS_OK;
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+int
+bfad_iocmd_cfg_fcpim(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_fcpim_s *iocmd = (struct bfa_bsg_fcpim_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       bfa_fcpim_path_tov_set(&bfad->bfa, iocmd->param);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
 int
 bfad_iocmd_fcpim_get_modstats(struct bfad_s *bfad, void *cmd)
 {
@@ -603,6 +951,28 @@ bfad_iocmd_fcpim_get_modstats(struct bfad_s *bfad, void *cmd)
        return 0;
 }
 
+int
+bfad_iocmd_fcpim_clr_modstats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_fcpim_modstatsclr_s *iocmd =
+                               (struct bfa_bsg_fcpim_modstatsclr_s *)cmd;
+       struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa);
+       struct list_head *qe, *qen;
+       struct bfa_itnim_s *itnim;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       list_for_each_safe(qe, qen, &fcpim->itnim_q) {
+               itnim = (struct bfa_itnim_s *) qe;
+               bfa_itnim_clear_stats(itnim);
+       }
+       memset(&fcpim->del_itn_stats, 0,
+               sizeof(struct bfa_fcpim_del_itn_stats_s));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
 int
 bfad_iocmd_fcpim_get_del_itn_stats(struct bfad_s *bfad, void *cmd)
 {
@@ -670,7 +1040,36 @@ bfad_iocmd_itnim_get_iostats(struct bfad_s *bfad, void *cmd)
 }
 
 static int
-bfad_iocmd_itnim_get_itnstats(struct bfad_s *bfad, void *cmd)
+bfad_iocmd_itnim_reset_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_rport_reset_stats_s *iocmd =
+                       (struct bfa_bsg_rport_reset_stats_s *)cmd;
+       struct bfa_fcs_lport_s  *fcs_port;
+       struct bfa_fcs_itnim_s  *itnim;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->pwwn);
+       if (!fcs_port)
+               iocmd->status = BFA_STATUS_UNKNOWN_LWWN;
+       else {
+               itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn);
+               if (itnim == NULL)
+                       iocmd->status = BFA_STATUS_UNKNOWN_RWWN;
+               else {
+                       iocmd->status = BFA_STATUS_OK;
+                       bfa_fcs_itnim_stats_clear(fcs_port, iocmd->rpwwn);
+                       bfa_itnim_clear_stats(bfa_fcs_itnim_get_halitn(itnim));
+               }
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+static int
+bfad_iocmd_itnim_get_itnstats(struct bfad_s *bfad, void *cmd)
 {
        struct bfa_bsg_itnim_itnstats_s *iocmd =
                        (struct bfa_bsg_itnim_itnstats_s *)cmd;
@@ -1511,11 +1910,545 @@ out:
        return 0;
 }
 
+#define BFA_DEBUG_FW_CORE_CHUNK_SZ     0x4000U /* 16K chunks for FW dump */
+int
+bfad_iocmd_debug_fw_core(struct bfad_s *bfad, void *cmd,
+                       unsigned int payload_len)
+{
+       struct bfa_bsg_debug_s *iocmd = (struct bfa_bsg_debug_s *)cmd;
+       void    *iocmd_bufptr;
+       unsigned long   flags;
+
+       if (bfad_chk_iocmd_sz(payload_len, sizeof(struct bfa_bsg_debug_s),
+                       BFA_DEBUG_FW_CORE_CHUNK_SZ) != BFA_STATUS_OK) {
+               iocmd->status = BFA_STATUS_VERSION_FAIL;
+               return 0;
+       }
+
+       if (iocmd->bufsz < BFA_DEBUG_FW_CORE_CHUNK_SZ ||
+                       !IS_ALIGNED(iocmd->bufsz, sizeof(u16)) ||
+                       !IS_ALIGNED(iocmd->offset, sizeof(u32))) {
+               bfa_trc(bfad, BFA_DEBUG_FW_CORE_CHUNK_SZ);
+               iocmd->status = BFA_STATUS_EINVAL;
+               goto out;
+       }
+
+       iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_debug_s);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_ioc_debug_fwcore(&bfad->bfa.ioc, iocmd_bufptr,
+                               (u32 *)&iocmd->offset, &iocmd->bufsz);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_debug_ctl(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       unsigned long   flags;
+
+       if (v_cmd == IOCMD_DEBUG_FW_STATE_CLR) {
+               spin_lock_irqsave(&bfad->bfad_lock, flags);
+               bfad->bfa.ioc.dbg_fwsave_once = BFA_TRUE;
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       } else if (v_cmd == IOCMD_DEBUG_PORTLOG_CLR)
+               bfad->plog_buf.head = bfad->plog_buf.tail = 0;
+       else if (v_cmd == IOCMD_DEBUG_START_DTRC)
+               bfa_trc_init(bfad->trcmod);
+       else if (v_cmd == IOCMD_DEBUG_STOP_DTRC)
+               bfa_trc_stop(bfad->trcmod);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_porglog_ctl(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_portlogctl_s *iocmd = (struct bfa_bsg_portlogctl_s *)cmd;
+
+       if (iocmd->ctl == BFA_TRUE)
+               bfad->plog_buf.plog_enabled = 1;
+       else
+               bfad->plog_buf.plog_enabled = 0;
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_fcpim_cfg_profile(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_fcpim_profile_s *iocmd =
+                               (struct bfa_bsg_fcpim_profile_s *)cmd;
+       struct timeval  tv;
+       unsigned long   flags;
+
+       do_gettimeofday(&tv);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (v_cmd == IOCMD_FCPIM_PROFILE_ON)
+               iocmd->status = bfa_fcpim_profile_on(&bfad->bfa, tv.tv_sec);
+       else if (v_cmd == IOCMD_FCPIM_PROFILE_OFF)
+               iocmd->status = bfa_fcpim_profile_off(&bfad->bfa);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+static int
+bfad_iocmd_itnim_get_ioprofile(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_itnim_ioprofile_s *iocmd =
+                               (struct bfa_bsg_itnim_ioprofile_s *)cmd;
+       struct bfa_fcs_lport_s *fcs_port;
+       struct bfa_fcs_itnim_s *itnim;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs,
+                               iocmd->vf_id, iocmd->lpwwn);
+       if (!fcs_port)
+               iocmd->status = BFA_STATUS_UNKNOWN_LWWN;
+       else {
+               itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn);
+               if (itnim == NULL)
+                       iocmd->status = BFA_STATUS_UNKNOWN_RWWN;
+               else
+                       iocmd->status = bfa_itnim_get_ioprofile(
+                                               bfa_fcs_itnim_get_halitn(itnim),
+                                               &iocmd->ioprofile);
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       return 0;
+}
+
+int
+bfad_iocmd_fcport_get_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_fcport_stats_s *iocmd =
+                               (struct bfa_bsg_fcport_stats_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+       struct bfa_cb_pending_q_s cb_qe;
+
+       init_completion(&fcomp.comp);
+       bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp,
+                          &fcomp, &iocmd->stats);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_fcport_get_stats(&bfad->bfa, &cb_qe);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK) {
+               bfa_trc(bfad, iocmd->status);
+               goto out;
+       }
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_fcport_reset_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+       struct bfa_cb_pending_q_s cb_qe;
+
+       init_completion(&fcomp.comp);
+       bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, &fcomp, NULL);
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_fcport_clear_stats(&bfad->bfa, &cb_qe);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK) {
+               bfa_trc(bfad, iocmd->status);
+               goto out;
+       }
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_boot_cfg(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_boot_s *iocmd = (struct bfa_bsg_boot_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_flash_update_part(BFA_FLASH(&bfad->bfa),
+                       BFA_FLASH_PART_BOOT, PCI_FUNC(bfad->pcidev->devfn),
+                       &iocmd->cfg, sizeof(struct bfa_boot_cfg_s), 0,
+                       bfad_hcb_comp, &fcomp);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK)
+               goto out;
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_boot_query(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_boot_s *iocmd = (struct bfa_bsg_boot_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_flash_read_part(BFA_FLASH(&bfad->bfa),
+                       BFA_FLASH_PART_BOOT, PCI_FUNC(bfad->pcidev->devfn),
+                       &iocmd->cfg, sizeof(struct bfa_boot_cfg_s), 0,
+                       bfad_hcb_comp, &fcomp);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK)
+               goto out;
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_preboot_query(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_preboot_s *iocmd = (struct bfa_bsg_preboot_s *)cmd;
+       struct bfi_iocfc_cfgrsp_s *cfgrsp = bfad->bfa.iocfc.cfgrsp;
+       struct bfa_boot_pbc_s *pbcfg = &iocmd->cfg;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       pbcfg->enable = cfgrsp->pbc_cfg.boot_enabled;
+       pbcfg->nbluns = cfgrsp->pbc_cfg.nbluns;
+       pbcfg->speed = cfgrsp->pbc_cfg.port_speed;
+       memcpy(pbcfg->pblun, cfgrsp->pbc_cfg.blun, sizeof(pbcfg->pblun));
+       iocmd->status = BFA_STATUS_OK;
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       return 0;
+}
+
+int
+bfad_iocmd_ethboot_cfg(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_ethboot_s *iocmd = (struct bfa_bsg_ethboot_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_flash_update_part(BFA_FLASH(&bfad->bfa),
+                               BFA_FLASH_PART_PXECFG,
+                               bfad->bfa.ioc.port_id, &iocmd->cfg,
+                               sizeof(struct bfa_ethboot_cfg_s), 0,
+                               bfad_hcb_comp, &fcomp);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK)
+               goto out;
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_ethboot_query(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_ethboot_s *iocmd = (struct bfa_bsg_ethboot_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_flash_read_part(BFA_FLASH(&bfad->bfa),
+                               BFA_FLASH_PART_PXECFG,
+                               bfad->bfa.ioc.port_id, &iocmd->cfg,
+                               sizeof(struct bfa_ethboot_cfg_s), 0,
+                               bfad_hcb_comp, &fcomp);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK)
+               goto out;
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_cfg_trunk(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+       if (v_cmd == IOCMD_TRUNK_ENABLE) {
+               trunk->attr.state = BFA_TRUNK_OFFLINE;
+               bfa_fcport_disable(&bfad->bfa);
+               fcport->cfg.trunked = BFA_TRUE;
+       } else if (v_cmd == IOCMD_TRUNK_DISABLE) {
+               trunk->attr.state = BFA_TRUNK_DISABLED;
+               bfa_fcport_disable(&bfad->bfa);
+               fcport->cfg.trunked = BFA_FALSE;
+       }
+
+       if (!bfa_fcport_is_disabled(&bfad->bfa))
+               bfa_fcport_enable(&bfad->bfa);
+
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_trunk_get_attr(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_trunk_attr_s *iocmd = (struct bfa_bsg_trunk_attr_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       struct bfa_fcport_trunk_s *trunk = &fcport->trunk;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       memcpy((void *)&iocmd->attr, (void *)&trunk->attr,
+               sizeof(struct bfa_trunk_attr_s));
+       iocmd->attr.port_id = bfa_lps_get_base_pid(&bfad->bfa);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_qos(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (bfa_ioc_get_type(&bfad->bfa.ioc) == BFA_IOC_TYPE_FC) {
+               if (v_cmd == IOCMD_QOS_ENABLE)
+                       fcport->cfg.qos_enabled = BFA_TRUE;
+               else if (v_cmd == IOCMD_QOS_DISABLE)
+                       fcport->cfg.qos_enabled = BFA_FALSE;
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_qos_get_attr(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_qos_attr_s *iocmd = (struct bfa_bsg_qos_attr_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->attr.state = fcport->qos_attr.state;
+       iocmd->attr.total_bb_cr = be32_to_cpu(fcport->qos_attr.total_bb_cr);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_qos_get_vc_attr(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_qos_vc_attr_s *iocmd =
+                               (struct bfa_bsg_qos_vc_attr_s *)cmd;
+       struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
+       struct bfa_qos_vc_attr_s *bfa_vc_attr = &fcport->qos_vc_attr;
+       unsigned long   flags;
+       u32     i = 0;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->attr.total_vc_count = be16_to_cpu(bfa_vc_attr->total_vc_count);
+       iocmd->attr.shared_credit  = be16_to_cpu(bfa_vc_attr->shared_credit);
+       iocmd->attr.elp_opmode_flags  =
+                               be32_to_cpu(bfa_vc_attr->elp_opmode_flags);
+
+       /* Individual VC info */
+       while (i < iocmd->attr.total_vc_count) {
+               iocmd->attr.vc_info[i].vc_credit =
+                               bfa_vc_attr->vc_info[i].vc_credit;
+               iocmd->attr.vc_info[i].borrow_credit =
+                               bfa_vc_attr->vc_info[i].borrow_credit;
+               iocmd->attr.vc_info[i].priority =
+                               bfa_vc_attr->vc_info[i].priority;
+               i++;
+       }
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+       iocmd->status = BFA_STATUS_OK;
+       return 0;
+}
+
+int
+bfad_iocmd_qos_get_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_fcport_stats_s *iocmd =
+                               (struct bfa_bsg_fcport_stats_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+       struct bfa_cb_pending_q_s cb_qe;
+
+       init_completion(&fcomp.comp);
+       bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp,
+                          &fcomp, &iocmd->stats);
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc));
+       iocmd->status = bfa_fcport_get_stats(&bfad->bfa, &cb_qe);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK) {
+               bfa_trc(bfad, iocmd->status);
+               goto out;
+       }
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_qos_reset_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd;
+       struct bfad_hal_comp fcomp;
+       unsigned long   flags;
+       struct bfa_cb_pending_q_s cb_qe;
+
+       init_completion(&fcomp.comp);
+       bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp,
+                          &fcomp, NULL);
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc));
+       iocmd->status = bfa_fcport_clear_stats(&bfad->bfa, &cb_qe);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       if (iocmd->status != BFA_STATUS_OK) {
+               bfa_trc(bfad, iocmd->status);
+               goto out;
+       }
+       wait_for_completion(&fcomp.comp);
+       iocmd->status = fcomp.status;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_vf_get_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_vf_stats_s *iocmd =
+                       (struct bfa_bsg_vf_stats_s *)cmd;
+       struct bfa_fcs_fabric_s *fcs_vf;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vf = bfa_fcs_vf_lookup(&bfad->bfa_fcs, iocmd->vf_id);
+       if (fcs_vf == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_VFID;
+               goto out;
+       }
+       memcpy((void *)&iocmd->stats, (void *)&fcs_vf->stats,
+               sizeof(struct bfa_vf_stats_s));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_vf_clr_stats(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_vf_reset_stats_s *iocmd =
+                       (struct bfa_bsg_vf_reset_stats_s *)cmd;
+       struct bfa_fcs_fabric_s *fcs_vf;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       fcs_vf = bfa_fcs_vf_lookup(&bfad->bfa_fcs, iocmd->vf_id);
+       if (fcs_vf == NULL) {
+               spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+               iocmd->status = BFA_STATUS_UNKNOWN_VFID;
+               goto out;
+       }
+       memset((void *)&fcs_vf->stats, 0, sizeof(struct bfa_vf_stats_s));
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       iocmd->status = BFA_STATUS_OK;
+out:
+       return 0;
+}
+
+int
+bfad_iocmd_lunmask(struct bfad_s *bfad, void *pcmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (v_cmd == IOCMD_FCPIM_LUNMASK_ENABLE)
+               iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_TRUE);
+       else if (v_cmd == IOCMD_FCPIM_LUNMASK_DISABLE)
+               iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_FALSE);
+       else if (v_cmd == IOCMD_FCPIM_LUNMASK_CLEAR)
+               iocmd->status = bfa_fcpim_lunmask_clear(&bfad->bfa);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       return 0;
+}
+
+int
+bfad_iocmd_fcpim_lunmask_query(struct bfad_s *bfad, void *cmd)
+{
+       struct bfa_bsg_fcpim_lunmask_query_s *iocmd =
+                       (struct bfa_bsg_fcpim_lunmask_query_s *)cmd;
+       struct bfa_lunmask_cfg_s *lun_mask = &iocmd->lun_mask;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       iocmd->status = bfa_fcpim_lunmask_query(&bfad->bfa, lun_mask);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       return 0;
+}
+
+int
+bfad_iocmd_fcpim_cfg_lunmask(struct bfad_s *bfad, void *cmd, unsigned int v_cmd)
+{
+       struct bfa_bsg_fcpim_lunmask_s *iocmd =
+                               (struct bfa_bsg_fcpim_lunmask_s *)cmd;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&bfad->bfad_lock, flags);
+       if (v_cmd == IOCMD_FCPIM_LUNMASK_ADD)
+               iocmd->status = bfa_fcpim_lunmask_add(&bfad->bfa, iocmd->vf_id,
+                                       &iocmd->pwwn, iocmd->rpwwn, iocmd->lun);
+       else if (v_cmd == IOCMD_FCPIM_LUNMASK_DELETE)
+               iocmd->status = bfa_fcpim_lunmask_delete(&bfad->bfa,
+                                       iocmd->vf_id, &iocmd->pwwn,
+                                       iocmd->rpwwn, iocmd->lun);
+       spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+       return 0;
+}
+
 static int
 bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
                unsigned int payload_len)
 {
-       int rc = EINVAL;
+       int rc = -EINVAL;
 
        switch (cmd) {
        case IOCMD_IOC_ENABLE:
@@ -1536,6 +2469,14 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
        case IOCMD_IOC_GET_FWSTATS:
                rc = bfad_iocmd_ioc_get_fwstats(bfad, iocmd, payload_len);
                break;
+       case IOCMD_IOC_RESET_STATS:
+       case IOCMD_IOC_RESET_FWSTATS:
+               rc = bfad_iocmd_ioc_reset_stats(bfad, iocmd, cmd);
+               break;
+       case IOCMD_IOC_SET_ADAPTER_NAME:
+       case IOCMD_IOC_SET_PORT_NAME:
+               rc = bfad_iocmd_ioc_set_name(bfad, iocmd, cmd);
+               break;
        case IOCMD_IOCFC_GET_ATTR:
                rc = bfad_iocmd_iocfc_get_attr(bfad, iocmd);
                break;
@@ -1554,12 +2495,31 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
        case IOCMD_PORT_GET_STATS:
                rc = bfad_iocmd_port_get_stats(bfad, iocmd, payload_len);
                break;
+       case IOCMD_PORT_RESET_STATS:
+               rc = bfad_iocmd_port_reset_stats(bfad, iocmd);
+               break;
+       case IOCMD_PORT_CFG_TOPO:
+       case IOCMD_PORT_CFG_SPEED:
+       case IOCMD_PORT_CFG_ALPA:
+       case IOCMD_PORT_CLR_ALPA:
+               rc = bfad_iocmd_set_port_cfg(bfad, iocmd, cmd);
+               break;
+       case IOCMD_PORT_CFG_MAXFRSZ:
+               rc = bfad_iocmd_port_cfg_maxfrsize(bfad, iocmd);
+               break;
+       case IOCMD_PORT_BBSC_ENABLE:
+       case IOCMD_PORT_BBSC_DISABLE:
+               rc = bfad_iocmd_port_cfg_bbsc(bfad, iocmd, cmd);
+               break;
        case IOCMD_LPORT_GET_ATTR:
                rc = bfad_iocmd_lport_get_attr(bfad, iocmd);
                break;
        case IOCMD_LPORT_GET_STATS:
                rc = bfad_iocmd_lport_get_stats(bfad, iocmd);
                break;
+       case IOCMD_LPORT_RESET_STATS:
+               rc = bfad_iocmd_lport_reset_stats(bfad, iocmd);
+               break;
        case IOCMD_LPORT_GET_IOSTATS:
                rc = bfad_iocmd_lport_get_iostats(bfad, iocmd);
                break;
@@ -1575,12 +2535,40 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
        case IOCMD_RPORT_GET_STATS:
                rc = bfad_iocmd_rport_get_stats(bfad, iocmd);
                break;
+       case IOCMD_RPORT_RESET_STATS:
+               rc = bfad_iocmd_rport_clr_stats(bfad, iocmd);
+               break;
+       case IOCMD_RPORT_SET_SPEED:
+               rc = bfad_iocmd_rport_set_speed(bfad, iocmd);
+               break;
+       case IOCMD_VPORT_GET_ATTR:
+               rc = bfad_iocmd_vport_get_attr(bfad, iocmd);
+               break;
+       case IOCMD_VPORT_GET_STATS:
+               rc = bfad_iocmd_vport_get_stats(bfad, iocmd);
+               break;
+       case IOCMD_VPORT_RESET_STATS:
+               rc = bfad_iocmd_vport_clr_stats(bfad, iocmd);
+               break;
        case IOCMD_FABRIC_GET_LPORTS:
                rc = bfad_iocmd_fabric_get_lports(bfad, iocmd, payload_len);
                break;
+       case IOCMD_RATELIM_ENABLE:
+       case IOCMD_RATELIM_DISABLE:
+               rc = bfad_iocmd_ratelim(bfad, cmd, iocmd);
+               break;
+       case IOCMD_RATELIM_DEF_SPEED:
+               rc = bfad_iocmd_ratelim_speed(bfad, cmd, iocmd);
+               break;
+       case IOCMD_FCPIM_FAILOVER:
+               rc = bfad_iocmd_cfg_fcpim(bfad, iocmd);
+               break;
        case IOCMD_FCPIM_MODSTATS:
                rc = bfad_iocmd_fcpim_get_modstats(bfad, iocmd);
                break;
+       case IOCMD_FCPIM_MODSTATSCLR:
+               rc = bfad_iocmd_fcpim_clr_modstats(bfad, iocmd);
+               break;
        case IOCMD_FCPIM_DEL_ITN_STATS:
                rc = bfad_iocmd_fcpim_get_del_itn_stats(bfad, iocmd);
                break;
@@ -1590,6 +2578,9 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
        case IOCMD_ITNIM_GET_IOSTATS:
                rc = bfad_iocmd_itnim_get_iostats(bfad, iocmd);
                break;
+       case IOCMD_ITNIM_RESET_STATS:
+               rc = bfad_iocmd_itnim_reset_stats(bfad, iocmd);
+               break;
        case IOCMD_ITNIM_GET_ITNSTATS:
                rc = bfad_iocmd_itnim_get_itnstats(bfad, iocmd);
                break;
@@ -1702,11 +2693,92 @@ bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd,
        case IOCMD_DEBUG_PORTLOG:
                rc = bfad_iocmd_porglog_get(bfad, iocmd);
                break;
+       case IOCMD_DEBUG_FW_CORE:
+               rc = bfad_iocmd_debug_fw_core(bfad, iocmd, payload_len);
+               break;
+       case IOCMD_DEBUG_FW_STATE_CLR:
+       case IOCMD_DEBUG_PORTLOG_CLR:
+       case IOCMD_DEBUG_START_DTRC:
+       case IOCMD_DEBUG_STOP_DTRC:
+               rc = bfad_iocmd_debug_ctl(bfad, iocmd, cmd);
+               break;
+       case IOCMD_DEBUG_PORTLOG_CTL:
+               rc = bfad_iocmd_porglog_ctl(bfad, iocmd);
+               break;
+       case IOCMD_FCPIM_PROFILE_ON:
+       case IOCMD_FCPIM_PROFILE_OFF:
+               rc = bfad_iocmd_fcpim_cfg_profile(bfad, iocmd, cmd);
+               break;
+       case IOCMD_ITNIM_GET_IOPROFILE:
+               rc = bfad_iocmd_itnim_get_ioprofile(bfad, iocmd);
+               break;
+       case IOCMD_FCPORT_GET_STATS:
+               rc = bfad_iocmd_fcport_get_stats(bfad, iocmd);
+               break;
+       case IOCMD_FCPORT_RESET_STATS:
+               rc = bfad_iocmd_fcport_reset_stats(bfad, iocmd);
+               break;
+       case IOCMD_BOOT_CFG:
+               rc = bfad_iocmd_boot_cfg(bfad, iocmd);
+               break;
+       case IOCMD_BOOT_QUERY:
+               rc = bfad_iocmd_boot_query(bfad, iocmd);
+               break;
+       case IOCMD_PREBOOT_QUERY:
+               rc = bfad_iocmd_preboot_query(bfad, iocmd);
+               break;
+       case IOCMD_ETHBOOT_CFG:
+               rc = bfad_iocmd_ethboot_cfg(bfad, iocmd);
+               break;
+       case IOCMD_ETHBOOT_QUERY:
+               rc = bfad_iocmd_ethboot_query(bfad, iocmd);
+               break;
+       case IOCMD_TRUNK_ENABLE:
+       case IOCMD_TRUNK_DISABLE:
+               rc = bfad_iocmd_cfg_trunk(bfad, iocmd, cmd);
+               break;
+       case IOCMD_TRUNK_GET_ATTR:
+               rc = bfad_iocmd_trunk_get_attr(bfad, iocmd);
+               break;
+       case IOCMD_QOS_ENABLE:
+       case IOCMD_QOS_DISABLE:
+               rc = bfad_iocmd_qos(bfad, iocmd, cmd);
+               break;
+       case IOCMD_QOS_GET_ATTR:
+               rc = bfad_iocmd_qos_get_attr(bfad, iocmd);
+               break;
+       case IOCMD_QOS_GET_VC_ATTR:
+               rc = bfad_iocmd_qos_get_vc_attr(bfad, iocmd);
+               break;
+       case IOCMD_QOS_GET_STATS:
+               rc = bfad_iocmd_qos_get_stats(bfad, iocmd);
+               break;
+       case IOCMD_QOS_RESET_STATS:
+               rc = bfad_iocmd_qos_reset_stats(bfad, iocmd);
+               break;
+       case IOCMD_VF_GET_STATS:
+               rc = bfad_iocmd_vf_get_stats(bfad, iocmd);
+               break;
+       case IOCMD_VF_RESET_STATS:
+               rc = bfad_iocmd_vf_clr_stats(bfad, iocmd);
+               break;
+       case IOCMD_FCPIM_LUNMASK_ENABLE:
+       case IOCMD_FCPIM_LUNMASK_DISABLE:
+       case IOCMD_FCPIM_LUNMASK_CLEAR:
+               rc = bfad_iocmd_lunmask(bfad, iocmd, cmd);
+               break;
+       case IOCMD_FCPIM_LUNMASK_QUERY:
+               rc = bfad_iocmd_fcpim_lunmask_query(bfad, iocmd);
+               break;
+       case IOCMD_FCPIM_LUNMASK_ADD:
+       case IOCMD_FCPIM_LUNMASK_DELETE:
+               rc = bfad_iocmd_fcpim_cfg_lunmask(bfad, iocmd, cmd);
+               break;
        default:
-               rc = EINVAL;
+               rc = -EINVAL;
                break;
        }
-       return -rc;
+       return rc;
 }
 
 static int
index 99b0e8a70c89dd7fb0c1de718a3fe1617defccfd..e859adb9aa9e807ae779e2ddb5444ec31bc7400b 100644 (file)
@@ -30,24 +30,48 @@ enum {
        IOCMD_IOC_GET_INFO,
        IOCMD_IOC_GET_STATS,
        IOCMD_IOC_GET_FWSTATS,
+       IOCMD_IOC_RESET_STATS,
+       IOCMD_IOC_RESET_FWSTATS,
+       IOCMD_IOC_SET_ADAPTER_NAME,
+       IOCMD_IOC_SET_PORT_NAME,
        IOCMD_IOCFC_GET_ATTR,
        IOCMD_IOCFC_SET_INTR,
        IOCMD_PORT_ENABLE,
        IOCMD_PORT_DISABLE,
        IOCMD_PORT_GET_ATTR,
        IOCMD_PORT_GET_STATS,
+       IOCMD_PORT_RESET_STATS,
+       IOCMD_PORT_CFG_TOPO,
+       IOCMD_PORT_CFG_SPEED,
+       IOCMD_PORT_CFG_ALPA,
+       IOCMD_PORT_CFG_MAXFRSZ,
+       IOCMD_PORT_CLR_ALPA,
+       IOCMD_PORT_BBSC_ENABLE,
+       IOCMD_PORT_BBSC_DISABLE,
        IOCMD_LPORT_GET_ATTR,
        IOCMD_LPORT_GET_RPORTS,
        IOCMD_LPORT_GET_STATS,
+       IOCMD_LPORT_RESET_STATS,
        IOCMD_LPORT_GET_IOSTATS,
        IOCMD_RPORT_GET_ATTR,
        IOCMD_RPORT_GET_ADDR,
        IOCMD_RPORT_GET_STATS,
+       IOCMD_RPORT_RESET_STATS,
+       IOCMD_RPORT_SET_SPEED,
+       IOCMD_VPORT_GET_ATTR,
+       IOCMD_VPORT_GET_STATS,
+       IOCMD_VPORT_RESET_STATS,
        IOCMD_FABRIC_GET_LPORTS,
+       IOCMD_RATELIM_ENABLE,
+       IOCMD_RATELIM_DISABLE,
+       IOCMD_RATELIM_DEF_SPEED,
+       IOCMD_FCPIM_FAILOVER,
        IOCMD_FCPIM_MODSTATS,
+       IOCMD_FCPIM_MODSTATSCLR,
        IOCMD_FCPIM_DEL_ITN_STATS,
        IOCMD_ITNIM_GET_ATTR,
        IOCMD_ITNIM_GET_IOSTATS,
+       IOCMD_ITNIM_RESET_STATS,
        IOCMD_ITNIM_GET_ITNSTATS,
        IOCMD_IOC_PCIFN_CFG,
        IOCMD_FCPORT_ENABLE,
@@ -86,6 +110,39 @@ enum {
        IOCMD_PHY_READ_FW,
        IOCMD_VHBA_QUERY,
        IOCMD_DEBUG_PORTLOG,
+       IOCMD_DEBUG_FW_CORE,
+       IOCMD_DEBUG_FW_STATE_CLR,
+       IOCMD_DEBUG_PORTLOG_CLR,
+       IOCMD_DEBUG_START_DTRC,
+       IOCMD_DEBUG_STOP_DTRC,
+       IOCMD_DEBUG_PORTLOG_CTL,
+       IOCMD_FCPIM_PROFILE_ON,
+       IOCMD_FCPIM_PROFILE_OFF,
+       IOCMD_ITNIM_GET_IOPROFILE,
+       IOCMD_FCPORT_GET_STATS,
+       IOCMD_FCPORT_RESET_STATS,
+       IOCMD_BOOT_CFG,
+       IOCMD_BOOT_QUERY,
+       IOCMD_PREBOOT_QUERY,
+       IOCMD_ETHBOOT_CFG,
+       IOCMD_ETHBOOT_QUERY,
+       IOCMD_TRUNK_ENABLE,
+       IOCMD_TRUNK_DISABLE,
+       IOCMD_TRUNK_GET_ATTR,
+       IOCMD_QOS_ENABLE,
+       IOCMD_QOS_DISABLE,
+       IOCMD_QOS_GET_ATTR,
+       IOCMD_QOS_GET_VC_ATTR,
+       IOCMD_QOS_GET_STATS,
+       IOCMD_QOS_RESET_STATS,
+       IOCMD_VF_GET_STATS,
+       IOCMD_VF_RESET_STATS,
+       IOCMD_FCPIM_LUNMASK_ENABLE,
+       IOCMD_FCPIM_LUNMASK_DISABLE,
+       IOCMD_FCPIM_LUNMASK_CLEAR,
+       IOCMD_FCPIM_LUNMASK_QUERY,
+       IOCMD_FCPIM_LUNMASK_ADD,
+       IOCMD_FCPIM_LUNMASK_DELETE,
 };
 
 struct bfa_bsg_gen_s {
@@ -94,6 +151,43 @@ struct bfa_bsg_gen_s {
        u16             rsvd;
 };
 
+struct bfa_bsg_portlogctl_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       bfa_boolean_t   ctl;
+       int             inst_no;
+};
+
+struct bfa_bsg_fcpim_profile_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+};
+
+struct bfa_bsg_itnim_ioprofile_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           lpwwn;
+       wwn_t           rpwwn;
+       struct bfa_itnim_ioprofile_s ioprofile;
+};
+
+struct bfa_bsg_fcport_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       union bfa_fcport_stats_u stats;
+};
+
+struct bfa_bsg_ioc_name_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       char            name[BFA_ADAPTER_SYM_NAME_LEN];
+};
+
 struct bfa_bsg_ioc_info_s {
        bfa_status_t    status;
        u16             bfad_num;
@@ -164,6 +258,20 @@ struct bfa_bsg_port_attr_s {
        struct bfa_port_attr_s  attr;
 };
 
+struct bfa_bsg_port_cfg_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       u32             param;
+       u32             rsvd1;
+};
+
+struct bfa_bsg_port_cfg_maxfrsize_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             maxfrsize;
+};
+
 struct bfa_bsg_port_stats_s {
        bfa_status_t    status;
        u16             bfad_num;
@@ -237,6 +345,47 @@ struct bfa_bsg_rport_scsi_addr_s {
        u32             lun;
 };
 
+struct bfa_bsg_rport_reset_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           pwwn;
+       wwn_t           rpwwn;
+};
+
+struct bfa_bsg_rport_set_speed_s {
+       bfa_status_t            status;
+       u16                     bfad_num;
+       u16                     vf_id;
+       enum bfa_port_speed     speed;
+       u32                     rsvd;
+       wwn_t                   pwwn;
+       wwn_t                   rpwwn;
+};
+
+struct bfa_bsg_vport_attr_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           vpwwn;
+       struct bfa_vport_attr_s vport_attr;
+};
+
+struct bfa_bsg_vport_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           vpwwn;
+       struct bfa_vport_stats_s vport_stats;
+};
+
+struct bfa_bsg_reset_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           vpwwn;
+};
+
 struct bfa_bsg_fabric_get_lports_s {
        bfa_status_t    status;
        u16             bfad_num;
@@ -246,6 +395,19 @@ struct bfa_bsg_fabric_get_lports_s {
        u32             rsvd;
 };
 
+struct bfa_bsg_trl_speed_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       enum bfa_port_speed speed;
+};
+
+struct bfa_bsg_fcpim_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             param;
+};
+
 struct bfa_bsg_fcpim_modstats_s {
        bfa_status_t    status;
        u16             bfad_num;
@@ -258,6 +420,11 @@ struct bfa_bsg_fcpim_del_itn_stats_s {
        struct bfa_fcpim_del_itn_stats_s modstats;
 };
 
+struct bfa_bsg_fcpim_modstatsclr_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+};
+
 struct bfa_bsg_itnim_attr_s {
        bfa_status_t    status;
        u16             bfad_num;
@@ -485,6 +652,76 @@ struct bfa_bsg_vhba_attr_s {
        struct bfa_vhba_attr_s  attr;
 };
 
+struct bfa_bsg_boot_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct bfa_boot_cfg_s   cfg;
+};
+
+struct bfa_bsg_preboot_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct bfa_boot_pbc_s   cfg;
+};
+
+struct bfa_bsg_ethboot_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct  bfa_ethboot_cfg_s  cfg;
+};
+
+struct bfa_bsg_trunk_attr_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct bfa_trunk_attr_s attr;
+};
+
+struct bfa_bsg_qos_attr_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct bfa_qos_attr_s   attr;
+};
+
+struct bfa_bsg_qos_vc_attr_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             rsvd;
+       struct bfa_qos_vc_attr_s attr;
+};
+
+struct bfa_bsg_vf_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       struct bfa_vf_stats_s   stats;
+};
+
+struct bfa_bsg_vf_reset_stats_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+};
+
+struct bfa_bsg_fcpim_lunmask_query_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       struct bfa_lunmask_cfg_s lun_mask;
+};
+
+struct bfa_bsg_fcpim_lunmask_s {
+       bfa_status_t    status;
+       u16             bfad_num;
+       u16             vf_id;
+       wwn_t           pwwn;
+       wwn_t           rpwwn;
+       struct scsi_lun lun;
+};
+
 struct bfa_bsg_fcpt_s {
        bfa_status_t    status;
        u16             vf_id;
index 48661a2726d7cb3ec8a15485d2f64af0d4dd1b69..bda999ad9f5232a61981b96a4c6bae9b80437c0e 100644 (file)
@@ -56,7 +56,7 @@
 #ifdef BFA_DRIVER_VERSION
 #define BFAD_DRIVER_VERSION    BFA_DRIVER_VERSION
 #else
-#define BFAD_DRIVER_VERSION    "3.0.2.1"
+#define BFAD_DRIVER_VERSION    "3.0.2.2"
 #endif
 
 #define BFAD_PROTO_NAME FCPI_NAME
@@ -224,6 +224,10 @@ struct bfad_s {
        char *regdata;
        u32 reglen;
        struct dentry *bfad_dentry_files[5];
+       struct list_head        free_aen_q;
+       struct list_head        active_aen_q;
+       struct bfa_aen_entry_s  aen_list[BFA_AEN_MAX_ENTRY];
+       spinlock_t              bfad_aen_spinlock;
 };
 
 /* BFAD state machine events */
index f2bf81265ae52cdfa212063749b08d5b4d0c4a1b..01312381639f74415d1ebd2ca10c1752308fb922 100644 (file)
@@ -656,6 +656,31 @@ bfad_im_port_clean(struct bfad_im_port_s *im_port)
        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 }
 
+static void bfad_aen_im_notify_handler(struct work_struct *work)
+{
+       struct bfad_im_s *im =
+               container_of(work, struct bfad_im_s, aen_im_notify_work);
+       struct bfa_aen_entry_s *aen_entry;
+       struct bfad_s *bfad = im->bfad;
+       struct Scsi_Host *shost = bfad->pport.im_port->shost;
+       void *event_data;
+       unsigned long flags;
+
+       while (!list_empty(&bfad->active_aen_q)) {
+               spin_lock_irqsave(&bfad->bfad_aen_spinlock, flags);
+               bfa_q_deq(&bfad->active_aen_q, &aen_entry);
+               spin_unlock_irqrestore(&bfad->bfad_aen_spinlock, flags);
+               event_data = (char *)aen_entry + sizeof(struct list_head);
+               fc_host_post_vendor_event(shost, fc_get_event_number(),
+                               sizeof(struct bfa_aen_entry_s) -
+                               sizeof(struct list_head),
+                               (char *)event_data, BFAD_NL_VENDOR_ID);
+               spin_lock_irqsave(&bfad->bfad_aen_spinlock, flags);
+               list_add_tail(&aen_entry->qe, &bfad->free_aen_q);
+               spin_unlock_irqrestore(&bfad->bfad_aen_spinlock, flags);
+       }
+}
+
 bfa_status_t
 bfad_im_probe(struct bfad_s *bfad)
 {
@@ -676,6 +701,7 @@ bfad_im_probe(struct bfad_s *bfad)
                rc = BFA_STATUS_FAILED;
        }
 
+       INIT_WORK(&im->aen_im_notify_work, bfad_aen_im_notify_handler);
 ext:
        return rc;
 }
index 4fe34d576b05681f6e29cfb4dbe0b338038b3a28..004b6cf848d943288934452237c1cfa2ef8b8cfd 100644 (file)
@@ -115,8 +115,30 @@ struct bfad_im_s {
        struct bfad_s         *bfad;
        struct workqueue_struct *drv_workq;
        char            drv_workq_name[KOBJ_NAME_LEN];
+       struct work_struct      aen_im_notify_work;
 };
 
+#define bfad_get_aen_entry(_drv, _entry) do {                          \
+       unsigned long   _flags;                                         \
+       spin_lock_irqsave(&(_drv)->bfad_aen_spinlock, _flags);          \
+       bfa_q_deq(&(_drv)->free_aen_q, &(_entry));                      \
+       if (_entry)                                                     \
+               list_add_tail(&(_entry)->qe, &(_drv)->active_aen_q);    \
+       spin_unlock_irqrestore(&(_drv)->bfad_aen_spinlock, _flags);     \
+} while (0)
+
+/* post fc_host vendor event */
+#define bfad_im_post_vendor_event(_entry, _drv, _cnt, _cat, _evt) do {       \
+       do_gettimeofday(&(_entry)->aen_tv);                                   \
+       (_entry)->bfad_num = (_drv)->inst_no;                                 \
+       (_entry)->seq_num = (_cnt);                                           \
+       (_entry)->aen_category = (_cat);                                      \
+       (_entry)->aen_type = (_evt);                                          \
+       if ((_drv)->bfad_flags & BFAD_FC4_PROBE_DONE)                         \
+               queue_work((_drv)->im->drv_workq,                             \
+                          &(_drv)->im->aen_im_notify_work);                  \
+} while (0)
+
 struct Scsi_Host *bfad_scsi_host_alloc(struct bfad_im_port_s *im_port,
                                struct bfad_s *);
 bfa_status_t bfad_thread_workq(struct bfad_s *bfad);
index 1e258d5f8aec5a5f5e8dc0cbb39e0295a50f1ff3..b2ba0b2e91b2cdfe03bed11ce417c95b880313e7 100644 (file)
@@ -783,6 +783,17 @@ enum bfi_sfp_i2h_e {
        BFI_SFP_I2H_SCN  = BFA_I2HM(BFI_SFP_H2I_SCN),
 };
 
+/*
+ *     SFP state change notification
+ */
+struct bfi_sfp_scn_s {
+       struct bfi_mhdr_s mhr;  /* host msg header        */
+       u8      event;
+       u8      sfpid;
+       u8      pomlvl; /* pom level: normal/warning/alarm */
+       u8      is_elb; /* e-loopback */
+};
+
 /*
  *     SFP state
  */
@@ -925,6 +936,15 @@ struct bfi_flash_erase_rsp_s {
        u32     status;
 };
 
+/*
+ * Flash event notification
+ */
+struct bfi_flash_event_s {
+       struct bfi_mhdr_s       mh;     /* Common msg header */
+       bfa_status_t            status;
+       u32                     param;
+};
+
 /*
  *----------------------------------------------------------------------
  *                             DIAG
index d924236e1b9174f6fda284442fabc469ae12bf20..42228ca5a9d223d42a6fbf897366620b47b96cc5 100644 (file)
@@ -2,7 +2,7 @@
 #define _BNX2FC_H_
 /* bnx2fc.h: Broadcom NetXtreme II Linux FCoE offload driver.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 Broadcom 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
@@ -62,7 +62,7 @@
 #include "bnx2fc_constants.h"
 
 #define BNX2FC_NAME            "bnx2fc"
-#define BNX2FC_VERSION         "1.0.3"
+#define BNX2FC_VERSION         "1.0.4"
 
 #define PFX                    "bnx2fc: "
 
 
 #define BNX2FC_RNID_HBA                        0x7
 
+#define SRR_RETRY_COUNT                        5
+#define REC_RETRY_COUNT                        1
+#define BNX2FC_NUM_ERR_BITS            63
+
 /* bnx2fc driver uses only one instance of fcoe_percpu_s */
 extern struct fcoe_percpu_s bnx2fc_global;
 
@@ -153,18 +157,13 @@ struct bnx2fc_percpu_s {
 };
 
 struct bnx2fc_hba {
-       struct list_head link;
+       struct list_head list;
        struct cnic_dev *cnic;
        struct pci_dev *pcidev;
-       struct net_device *netdev;
        struct net_device *phys_dev;
        unsigned long reg_with_cnic;
                #define BNX2FC_CNIC_REGISTERED           1
-       struct packet_type fcoe_packet_type;
-       struct packet_type fip_packet_type;
        struct bnx2fc_cmd_mgr *cmd_mgr;
-       struct workqueue_struct *timer_work_queue;
-       struct kref kref;
        spinlock_t hba_lock;
        struct mutex hba_mutex;
        unsigned long adapter_state;
@@ -172,15 +171,9 @@ struct bnx2fc_hba {
                #define ADAPTER_STATE_GOING_DOWN        1
                #define ADAPTER_STATE_LINK_DOWN         2
                #define ADAPTER_STATE_READY             3
-       u32 flags;
-       unsigned long init_done;
-               #define BNX2FC_FW_INIT_DONE             0
-               #define BNX2FC_CTLR_INIT_DONE           1
-               #define BNX2FC_CREATE_DONE              2
-       struct fcoe_ctlr ctlr;
-       struct list_head vports;
-       u8 vlan_enabled;
-       int vlan_id;
+       unsigned long flags;
+               #define BNX2FC_FLAG_FW_INIT_DONE        0
+               #define BNX2FC_FLAG_DESTROY_CMPL        1
        u32 next_conn_id;
        struct fcoe_task_ctx_entry **task_ctx;
        dma_addr_t *task_ctx_dma;
@@ -199,38 +192,41 @@ struct bnx2fc_hba {
        char *dummy_buffer;
        dma_addr_t dummy_buf_dma;
 
+       /* Active list of offloaded sessions */
+       struct bnx2fc_rport **tgt_ofld_list;
+
+       /* statistics */
        struct fcoe_statistics_params *stats_buffer;
        dma_addr_t stats_buf_dma;
-
-       /*
-        * PCI related info.
-        */
-       u16 pci_did;
-       u16 pci_vid;
-       u16 pci_sdid;
-       u16 pci_svid;
-       u16 pci_func;
-       u16 pci_devno;
-
-       struct task_struct *l2_thread;
-
-       /* linkdown handling */
-       wait_queue_head_t shutdown_wait;
-       int wait_for_link_down;
+       struct completion stat_req_done;
 
        /*destroy handling */
        struct timer_list destroy_timer;
        wait_queue_head_t destroy_wait;
 
-       /* Active list of offloaded sessions */
-       struct bnx2fc_rport *tgt_ofld_list[BNX2FC_NUM_MAX_SESS];
+       /* linkdown handling */
+       wait_queue_head_t shutdown_wait;
+       int wait_for_link_down;
        int num_ofld_sess;
+       struct list_head vports;
+};
 
-       /* statistics */
-       struct completion stat_req_done;
+struct bnx2fc_interface {
+       struct list_head list;
+       unsigned long if_flags;
+               #define BNX2FC_CTLR_INIT_DONE           0
+       struct bnx2fc_hba *hba;
+       struct net_device *netdev;
+       struct packet_type fcoe_packet_type;
+       struct packet_type fip_packet_type;
+       struct workqueue_struct *timer_work_queue;
+       struct kref kref;
+       struct fcoe_ctlr ctlr;
+       u8 vlan_enabled;
+       int vlan_id;
 };
 
-#define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_hba, ctlr)
+#define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_interface, ctlr)
 
 struct bnx2fc_lport {
        struct list_head list;
@@ -252,9 +248,11 @@ struct bnx2fc_rport {
        struct fc_rport_priv *rdata;
        void __iomem *ctx_base;
 #define DPM_TRIGER_TYPE                0x40
+       u32 io_timeout;
        u32 fcoe_conn_id;
        u32 context_id;
        u32 sid;
+       int dev_type;
 
        unsigned long flags;
 #define BNX2FC_FLAG_SESSION_READY      0x1
@@ -262,10 +260,9 @@ struct bnx2fc_rport {
 #define BNX2FC_FLAG_DISABLED           0x3
 #define BNX2FC_FLAG_DESTROYED          0x4
 #define BNX2FC_FLAG_OFLD_REQ_CMPL      0x5
-#define BNX2FC_FLAG_DESTROY_CMPL       0x6
-#define BNX2FC_FLAG_CTX_ALLOC_FAILURE  0x7
-#define BNX2FC_FLAG_UPLD_REQ_COMPL     0x8
-#define BNX2FC_FLAG_EXPL_LOGO          0x9
+#define BNX2FC_FLAG_CTX_ALLOC_FAILURE  0x6
+#define BNX2FC_FLAG_UPLD_REQ_COMPL     0x7
+#define BNX2FC_FLAG_EXPL_LOGO          0x8
 
        u8 src_addr[ETH_ALEN];
        u32 max_sqes;
@@ -327,12 +324,9 @@ struct bnx2fc_rport {
        spinlock_t cq_lock;
        atomic_t num_active_ios;
        u32 flush_in_prog;
-       unsigned long work_time_slice;
        unsigned long timestamp;
        struct list_head free_task_list;
        struct bnx2fc_cmd *pending_queue[BNX2FC_SQ_WQES_MAX+1];
-       atomic_t pi;
-       atomic_t ci;
        struct list_head active_cmd_queue;
        struct list_head els_queue;
        struct list_head io_retire_queue;
@@ -367,6 +361,8 @@ struct bnx2fc_els_cb_arg {
        struct bnx2fc_cmd *aborted_io_req;
        struct bnx2fc_cmd *io_req;
        u16 l2_oxid;
+       u32 offset;
+       enum fc_rctl r_ctl;
 };
 
 /* bnx2fc command structure */
@@ -380,6 +376,7 @@ struct bnx2fc_cmd {
 #define BNX2FC_ABTS                    3
 #define BNX2FC_ELS                     4
 #define BNX2FC_CLEANUP                 5
+#define BNX2FC_SEQ_CLEANUP             6
        u8 io_req_flags;
        struct kref refcount;
        struct fcoe_port *port;
@@ -393,6 +390,7 @@ struct bnx2fc_cmd {
        struct completion tm_done;
        int wait_for_comp;
        u16 xid;
+       struct fcoe_err_report_entry err_entry;
        struct fcoe_task_ctx_entry *task;
        struct io_bdt *bd_tbl;
        struct fcp_rsp *rsp;
@@ -409,6 +407,12 @@ struct bnx2fc_cmd {
 #define BNX2FC_FLAG_IO_COMPL           0x9
 #define BNX2FC_FLAG_ELS_DONE           0xa
 #define BNX2FC_FLAG_ELS_TIMEOUT                0xb
+#define BNX2FC_FLAG_CMD_LOST           0xc
+#define BNX2FC_FLAG_SRR_SENT           0xd
+       u8 rec_retry;
+       u8 srr_retry;
+       u32 srr_offset;
+       u8 srr_rctl;
        u32 fcp_resid;
        u32 fcp_rsp_len;
        u32 fcp_sns_len;
@@ -439,6 +443,7 @@ struct bnx2fc_unsol_els {
 
 
 
+struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt);
 struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type);
 void bnx2fc_cmd_release(struct kref *ref);
 int bnx2fc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd);
@@ -476,6 +481,10 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req);
 void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req,
                              struct fcoe_task_ctx_entry *task,
                              u16 orig_xid);
+void bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnup_req,
+                                 struct fcoe_task_ctx_entry *task,
+                                 struct bnx2fc_cmd *orig_io_req,
+                                 u32 offset);
 void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req,
                         struct fcoe_task_ctx_entry *task);
 void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
@@ -525,5 +534,13 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
                                   unsigned char *buf,
                                   u32 frame_len, u16 l2_oxid);
 int bnx2fc_send_stat_req(struct bnx2fc_hba *hba);
+int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, struct bnx2fc_cmd *io_req);
+int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req);
+int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl);
+void bnx2fc_process_seq_cleanup_compl(struct bnx2fc_cmd *seq_clnup_req,
+                                     struct fcoe_task_ctx_entry *task,
+                                     u8 rx_state);
+int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset,
+                               enum fc_rctl r_ctl);
 
 #endif
index 7f6aff68cc53641f9e99300d15bb038b65c6d6ff..3416d9a746c71320ca73310dc3a077ba2a144bd3 100644 (file)
@@ -21,21 +21,21 @@ extern unsigned int bnx2fc_debug_level;
 
 #define BNX2FC_ELS_DBG(fmt, arg...)                                    \
        BNX2FC_CHK_LOGGING(LOG_ELS,                                     \
-                          printk(KERN_ALERT PFX fmt, ##arg))
+                          printk(KERN_INFO PFX fmt, ##arg))
 
 #define BNX2FC_MISC_DBG(fmt, arg...)                                   \
        BNX2FC_CHK_LOGGING(LOG_MISC,                                    \
-                          printk(KERN_ALERT PFX fmt, ##arg))
+                          printk(KERN_INFO PFX fmt, ##arg))
 
 #define BNX2FC_IO_DBG(io_req, fmt, arg...)                             \
        do {                                                            \
                if (!io_req || !io_req->port || !io_req->port->lport || \
                    !io_req->port->lport->host)                         \
                        BNX2FC_CHK_LOGGING(LOG_IO,                      \
-                          printk(KERN_ALERT PFX "NULL " fmt, ##arg));  \
+                          printk(KERN_INFO PFX "NULL " fmt, ##arg));   \
                else                                                    \
                        BNX2FC_CHK_LOGGING(LOG_IO,                      \
-                          shost_printk(KERN_ALERT,                     \
+                          shost_printk(KERN_INFO,                      \
                                   (io_req)->port->lport->host,         \
                                   PFX "xid:0x%x " fmt,                 \
                                   (io_req)->xid, ##arg));              \
@@ -46,10 +46,10 @@ extern unsigned int bnx2fc_debug_level;
                if (!tgt || !tgt->port || !tgt->port->lport ||          \
                    !tgt->port->lport->host || !tgt->rport)             \
                        BNX2FC_CHK_LOGGING(LOG_TGT,                     \
-                          printk(KERN_ALERT PFX "NULL " fmt, ##arg));  \
+                          printk(KERN_INFO PFX "NULL " fmt, ##arg));   \
                else                                                    \
                        BNX2FC_CHK_LOGGING(LOG_TGT,                     \
-                          shost_printk(KERN_ALERT,                     \
+                          shost_printk(KERN_INFO,                      \
                                   (tgt)->port->lport->host,            \
                                   PFX "port:%x " fmt,                  \
                                   (tgt)->rport->port_id, ##arg));      \
@@ -60,10 +60,10 @@ extern unsigned int bnx2fc_debug_level;
        do {                                                            \
                if (!lport || !lport->host)                             \
                        BNX2FC_CHK_LOGGING(LOG_HBA,                     \
-                          printk(KERN_ALERT PFX "NULL " fmt, ##arg));  \
+                          printk(KERN_INFO PFX "NULL " fmt, ##arg));   \
                else                                                    \
                        BNX2FC_CHK_LOGGING(LOG_HBA,                     \
-                          shost_printk(KERN_ALERT, lport->host,        \
+                          shost_printk(KERN_INFO, lport->host, \
                                   PFX fmt, ##arg));                    \
        } while (0)
 
index 7e89143f15cf3af027592cbf55cbed47d727d7cc..d66dcbd0df106d1a9912f90b6e50bbbcb9621e46 100644 (file)
@@ -3,7 +3,7 @@
  * This file contains helper routines that handle ELS requests
  * and responses.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 Broadcom 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
@@ -253,13 +253,417 @@ int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp)
        return rc;
 }
 
+void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg)
+{
+       struct bnx2fc_mp_req *mp_req;
+       struct fc_frame_header *fc_hdr, *fh;
+       struct bnx2fc_cmd *srr_req;
+       struct bnx2fc_cmd *orig_io_req;
+       struct fc_frame *fp;
+       unsigned char *buf;
+       void *resp_buf;
+       u32 resp_len, hdr_len;
+       u8 opcode;
+       int rc = 0;
+
+       orig_io_req = cb_arg->aborted_io_req;
+       srr_req = cb_arg->io_req;
+       if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) {
+               BNX2FC_IO_DBG(srr_req, "srr_compl: xid - 0x%x completed",
+                       orig_io_req->xid);
+               goto srr_compl_done;
+       }
+       if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) {
+               BNX2FC_IO_DBG(srr_req, "rec abts in prog "
+                      "orig_io - 0x%x\n",
+                       orig_io_req->xid);
+               goto srr_compl_done;
+       }
+       if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &srr_req->req_flags)) {
+               /* SRR timedout */
+               BNX2FC_IO_DBG(srr_req, "srr timed out, abort "
+                      "orig_io - 0x%x\n",
+                       orig_io_req->xid);
+               rc = bnx2fc_initiate_abts(srr_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
+                               "failed. issue cleanup\n");
+                       bnx2fc_initiate_cleanup(srr_req);
+               }
+               orig_io_req->srr_retry++;
+               if (orig_io_req->srr_retry <= SRR_RETRY_COUNT) {
+                       struct bnx2fc_rport *tgt = orig_io_req->tgt;
+                       spin_unlock_bh(&tgt->tgt_lock);
+                       rc = bnx2fc_send_srr(orig_io_req,
+                                            orig_io_req->srr_offset,
+                                            orig_io_req->srr_rctl);
+                       spin_lock_bh(&tgt->tgt_lock);
+                       if (!rc)
+                               goto srr_compl_done;
+               }
+
+               rc = bnx2fc_initiate_abts(orig_io_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
+                               "failed xid = 0x%x. issue cleanup\n",
+                               orig_io_req->xid);
+                       bnx2fc_initiate_cleanup(orig_io_req);
+               }
+               goto srr_compl_done;
+       }
+       mp_req = &(srr_req->mp_req);
+       fc_hdr = &(mp_req->resp_fc_hdr);
+       resp_len = mp_req->resp_len;
+       resp_buf = mp_req->resp_buf;
+
+       hdr_len = sizeof(*fc_hdr);
+       buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
+       if (!buf) {
+               printk(KERN_ERR PFX "srr buf: mem alloc failure\n");
+               goto srr_compl_done;
+       }
+       memcpy(buf, fc_hdr, hdr_len);
+       memcpy(buf + hdr_len, resp_buf, resp_len);
+
+       fp = fc_frame_alloc(NULL, resp_len);
+       if (!fp) {
+               printk(KERN_ERR PFX "fc_frame_alloc failure\n");
+               goto free_buf;
+       }
+
+       fh = (struct fc_frame_header *) fc_frame_header_get(fp);
+       /* Copy FC Frame header and payload into the frame */
+       memcpy(fh, buf, hdr_len + resp_len);
+
+       opcode = fc_frame_payload_op(fp);
+       switch (opcode) {
+       case ELS_LS_ACC:
+               BNX2FC_IO_DBG(srr_req, "SRR success\n");
+               break;
+       case ELS_LS_RJT:
+               BNX2FC_IO_DBG(srr_req, "SRR rejected\n");
+               rc = bnx2fc_initiate_abts(orig_io_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts "
+                               "failed xid = 0x%x. issue cleanup\n",
+                               orig_io_req->xid);
+                       bnx2fc_initiate_cleanup(orig_io_req);
+               }
+               break;
+       default:
+               BNX2FC_IO_DBG(srr_req, "srr compl - invalid opcode = %d\n",
+                       opcode);
+               break;
+       }
+       fc_frame_free(fp);
+free_buf:
+       kfree(buf);
+srr_compl_done:
+       kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+}
+
+void bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg)
+{
+       struct bnx2fc_cmd *orig_io_req, *new_io_req;
+       struct bnx2fc_cmd *rec_req;
+       struct bnx2fc_mp_req *mp_req;
+       struct fc_frame_header *fc_hdr, *fh;
+       struct fc_els_ls_rjt *rjt;
+       struct fc_els_rec_acc *acc;
+       struct bnx2fc_rport *tgt;
+       struct fcoe_err_report_entry *err_entry;
+       struct scsi_cmnd *sc_cmd;
+       enum fc_rctl r_ctl;
+       unsigned char *buf;
+       void *resp_buf;
+       struct fc_frame *fp;
+       u8 opcode;
+       u32 offset;
+       u32 e_stat;
+       u32 resp_len, hdr_len;
+       int rc = 0;
+       bool send_seq_clnp = false;
+       bool abort_io = false;
+
+       BNX2FC_MISC_DBG("Entered rec_compl callback\n");
+       rec_req = cb_arg->io_req;
+       orig_io_req = cb_arg->aborted_io_req;
+       BNX2FC_IO_DBG(rec_req, "rec_compl: orig xid = 0x%x", orig_io_req->xid);
+       tgt = orig_io_req->tgt;
+
+       if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) {
+               BNX2FC_IO_DBG(rec_req, "completed"
+                      "orig_io - 0x%x\n",
+                       orig_io_req->xid);
+               goto rec_compl_done;
+       }
+       if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) {
+               BNX2FC_IO_DBG(rec_req, "abts in prog "
+                      "orig_io - 0x%x\n",
+                       orig_io_req->xid);
+               goto rec_compl_done;
+       }
+       /* Handle REC timeout case */
+       if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rec_req->req_flags)) {
+               BNX2FC_IO_DBG(rec_req, "timed out, abort "
+                      "orig_io - 0x%x\n",
+                       orig_io_req->xid);
+               /* els req is timed out. send abts for els */
+               rc = bnx2fc_initiate_abts(rec_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
+                               "failed. issue cleanup\n");
+                       bnx2fc_initiate_cleanup(rec_req);
+               }
+               orig_io_req->rec_retry++;
+               /* REC timedout. send ABTS to the orig IO req */
+               if (orig_io_req->rec_retry <= REC_RETRY_COUNT) {
+                       spin_unlock_bh(&tgt->tgt_lock);
+                       rc = bnx2fc_send_rec(orig_io_req);
+                       spin_lock_bh(&tgt->tgt_lock);
+                       if (!rc)
+                               goto rec_compl_done;
+               }
+               rc = bnx2fc_initiate_abts(orig_io_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
+                               "failed xid = 0x%x. issue cleanup\n",
+                               orig_io_req->xid);
+                       bnx2fc_initiate_cleanup(orig_io_req);
+               }
+               goto rec_compl_done;
+       }
+       mp_req = &(rec_req->mp_req);
+       fc_hdr = &(mp_req->resp_fc_hdr);
+       resp_len = mp_req->resp_len;
+       acc = resp_buf = mp_req->resp_buf;
+
+       hdr_len = sizeof(*fc_hdr);
+
+       buf = kzalloc(PAGE_SIZE, GFP_ATOMIC);
+       if (!buf) {
+               printk(KERN_ERR PFX "rec buf: mem alloc failure\n");
+               goto rec_compl_done;
+       }
+       memcpy(buf, fc_hdr, hdr_len);
+       memcpy(buf + hdr_len, resp_buf, resp_len);
+
+       fp = fc_frame_alloc(NULL, resp_len);
+       if (!fp) {
+               printk(KERN_ERR PFX "fc_frame_alloc failure\n");
+               goto free_buf;
+       }
+
+       fh = (struct fc_frame_header *) fc_frame_header_get(fp);
+       /* Copy FC Frame header and payload into the frame */
+       memcpy(fh, buf, hdr_len + resp_len);
+
+       opcode = fc_frame_payload_op(fp);
+       if (opcode == ELS_LS_RJT) {
+               BNX2FC_IO_DBG(rec_req, "opcode is RJT\n");
+               rjt = fc_frame_payload_get(fp, sizeof(*rjt));
+               if ((rjt->er_reason == ELS_RJT_LOGIC ||
+                   rjt->er_reason == ELS_RJT_UNAB) &&
+                   rjt->er_explan == ELS_EXPL_OXID_RXID) {
+                       BNX2FC_IO_DBG(rec_req, "handle CMD LOST case\n");
+                       new_io_req = bnx2fc_cmd_alloc(tgt);
+                       if (!new_io_req)
+                               goto abort_io;
+                       new_io_req->sc_cmd = orig_io_req->sc_cmd;
+                       /* cleanup orig_io_req that is with the FW */
+                       set_bit(BNX2FC_FLAG_CMD_LOST,
+                               &orig_io_req->req_flags);
+                       bnx2fc_initiate_cleanup(orig_io_req);
+                       /* Post a new IO req with the same sc_cmd */
+                       BNX2FC_IO_DBG(rec_req, "Post IO request again\n");
+                       spin_unlock_bh(&tgt->tgt_lock);
+                       rc = bnx2fc_post_io_req(tgt, new_io_req);
+                       spin_lock_bh(&tgt->tgt_lock);
+                       if (!rc)
+                               goto free_frame;
+                       BNX2FC_IO_DBG(rec_req, "REC: io post err\n");
+               }
+abort_io:
+               rc = bnx2fc_initiate_abts(orig_io_req);
+               if (rc != SUCCESS) {
+                       BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts "
+                               "failed. issue cleanup\n");
+                       bnx2fc_initiate_cleanup(orig_io_req);
+               }
+       } else if (opcode == ELS_LS_ACC) {
+               /* REVISIT: Check if the exchange is already aborted */
+               offset = ntohl(acc->reca_fc4value);
+               e_stat = ntohl(acc->reca_e_stat);
+               if (e_stat & ESB_ST_SEQ_INIT)  {
+                       BNX2FC_IO_DBG(rec_req, "target has the seq init\n");
+                       goto free_frame;
+               }
+               BNX2FC_IO_DBG(rec_req, "e_stat = 0x%x, offset = 0x%x\n",
+                       e_stat, offset);
+               /* Seq initiative is with us */
+               err_entry = (struct fcoe_err_report_entry *)
+                            &orig_io_req->err_entry;
+               sc_cmd = orig_io_req->sc_cmd;
+               if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) {
+                       /* SCSI WRITE command */
+                       if (offset == orig_io_req->data_xfer_len) {
+                               BNX2FC_IO_DBG(rec_req, "WRITE - resp lost\n");
+                               /* FCP_RSP lost */
+                               r_ctl = FC_RCTL_DD_CMD_STATUS;
+                               offset = 0;
+                       } else  {
+                               /* start transmitting from offset */
+                               BNX2FC_IO_DBG(rec_req, "XFER_RDY/DATA lost\n");
+                               send_seq_clnp = true;
+                               r_ctl = FC_RCTL_DD_DATA_DESC;
+                               if (bnx2fc_initiate_seq_cleanup(orig_io_req,
+                                                               offset, r_ctl))
+                                       abort_io = true;
+                               /* XFER_RDY */
+                       }
+               } else {
+                       /* SCSI READ command */
+                       if (err_entry->data.rx_buf_off ==
+                                       orig_io_req->data_xfer_len) {
+                               /* FCP_RSP lost */
+                               BNX2FC_IO_DBG(rec_req, "READ - resp lost\n");
+                               r_ctl = FC_RCTL_DD_CMD_STATUS;
+                               offset = 0;
+                       } else  {
+                               /* request retransmission from this offset */
+                               send_seq_clnp = true;
+                               offset = err_entry->data.rx_buf_off;
+                               BNX2FC_IO_DBG(rec_req, "RD DATA lost\n");
+                               /* FCP_DATA lost */
+                               r_ctl = FC_RCTL_DD_SOL_DATA;
+                               if (bnx2fc_initiate_seq_cleanup(orig_io_req,
+                                                               offset, r_ctl))
+                                       abort_io = true;
+                       }
+               }
+               if (abort_io) {
+                       rc = bnx2fc_initiate_abts(orig_io_req);
+                       if (rc != SUCCESS) {
+                               BNX2FC_IO_DBG(rec_req, "rec_compl:initiate_abts"
+                                             " failed. issue cleanup\n");
+                               bnx2fc_initiate_cleanup(orig_io_req);
+                       }
+               } else if (!send_seq_clnp) {
+                       BNX2FC_IO_DBG(rec_req, "Send SRR - FCP_RSP\n");
+                       spin_unlock_bh(&tgt->tgt_lock);
+                       rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl);
+                       spin_lock_bh(&tgt->tgt_lock);
+
+                       if (rc) {
+                               BNX2FC_IO_DBG(rec_req, "Unable to send SRR"
+                                       " IO will abort\n");
+                       }
+               }
+       }
+free_frame:
+       fc_frame_free(fp);
+free_buf:
+       kfree(buf);
+rec_compl_done:
+       kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+       kfree(cb_arg);
+}
+
+int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req)
+{
+       struct fc_els_rec rec;
+       struct bnx2fc_rport *tgt = orig_io_req->tgt;
+       struct fc_lport *lport = tgt->rdata->local_port;
+       struct bnx2fc_els_cb_arg *cb_arg = NULL;
+       u32 sid = tgt->sid;
+       u32 r_a_tov = lport->r_a_tov;
+       int rc;
+
+       BNX2FC_IO_DBG(orig_io_req, "Sending REC\n");
+       memset(&rec, 0, sizeof(rec));
+
+       cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
+       if (!cb_arg) {
+               printk(KERN_ERR PFX "Unable to allocate cb_arg for REC\n");
+               rc = -ENOMEM;
+               goto rec_err;
+       }
+       kref_get(&orig_io_req->refcount);
+
+       cb_arg->aborted_io_req = orig_io_req;
+
+       rec.rec_cmd = ELS_REC;
+       hton24(rec.rec_s_id, sid);
+       rec.rec_ox_id = htons(orig_io_req->xid);
+       rec.rec_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id);
+
+       rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec),
+                                bnx2fc_rec_compl, cb_arg,
+                                r_a_tov);
+rec_err:
+       if (rc) {
+               BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n");
+               spin_lock_bh(&tgt->tgt_lock);
+               kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+               spin_unlock_bh(&tgt->tgt_lock);
+               kfree(cb_arg);
+       }
+       return rc;
+}
+
+int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl)
+{
+       struct fcp_srr srr;
+       struct bnx2fc_rport *tgt = orig_io_req->tgt;
+       struct fc_lport *lport = tgt->rdata->local_port;
+       struct bnx2fc_els_cb_arg *cb_arg = NULL;
+       u32 r_a_tov = lport->r_a_tov;
+       int rc;
+
+       BNX2FC_IO_DBG(orig_io_req, "Sending SRR\n");
+       memset(&srr, 0, sizeof(srr));
+
+       cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
+       if (!cb_arg) {
+               printk(KERN_ERR PFX "Unable to allocate cb_arg for SRR\n");
+               rc = -ENOMEM;
+               goto srr_err;
+       }
+       kref_get(&orig_io_req->refcount);
+
+       cb_arg->aborted_io_req = orig_io_req;
+
+       srr.srr_op = ELS_SRR;
+       srr.srr_ox_id = htons(orig_io_req->xid);
+       srr.srr_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id);
+       srr.srr_rel_off = htonl(offset);
+       srr.srr_r_ctl = r_ctl;
+       orig_io_req->srr_offset = offset;
+       orig_io_req->srr_rctl = r_ctl;
+
+       rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr),
+                                bnx2fc_srr_compl, cb_arg,
+                                r_a_tov);
+srr_err:
+       if (rc) {
+               BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n");
+               spin_lock_bh(&tgt->tgt_lock);
+               kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+               spin_unlock_bh(&tgt->tgt_lock);
+               kfree(cb_arg);
+       } else
+               set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags);
+
+       return rc;
+}
+
 static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
                        void *data, u32 data_len,
                        void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg),
                        struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec)
 {
        struct fcoe_port *port = tgt->port;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
        struct fc_rport *rport = tgt->rport;
        struct fc_lport *lport = port->lport;
        struct bnx2fc_cmd *els_req;
@@ -274,12 +678,12 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
 
        rc = fc_remote_port_chkready(rport);
        if (rc) {
-               printk(KERN_ALERT PFX "els 0x%x: rport not ready\n", op);
+               printk(KERN_ERR PFX "els 0x%x: rport not ready\n", op);
                rc = -EINVAL;
                goto els_err;
        }
        if (lport->state != LPORT_ST_READY || !(lport->link_up)) {
-               printk(KERN_ALERT PFX "els 0x%x: link is not ready\n", op);
+               printk(KERN_ERR PFX "els 0x%x: link is not ready\n", op);
                rc = -EINVAL;
                goto els_err;
        }
@@ -305,7 +709,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
        mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req);
        rc = bnx2fc_init_mp_req(els_req);
        if (rc == FAILED) {
-               printk(KERN_ALERT PFX "ELS MP request init failed\n");
+               printk(KERN_ERR PFX "ELS MP request init failed\n");
                spin_lock_bh(&tgt->tgt_lock);
                kref_put(&els_req->refcount, bnx2fc_cmd_release);
                spin_unlock_bh(&tgt->tgt_lock);
@@ -324,7 +728,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
        if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) {
                memcpy(mp_req->req_buf, data, data_len);
        } else {
-               printk(KERN_ALERT PFX "Invalid ELS op 0x%x\n", op);
+               printk(KERN_ERR PFX "Invalid ELS op 0x%x\n", op);
                els_req->cb_func = NULL;
                els_req->cb_arg = NULL;
                spin_lock_bh(&tgt->tgt_lock);
@@ -342,9 +746,14 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
        did = tgt->rport->port_id;
        sid = tgt->sid;
 
-       __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS_REQ, did, sid,
-                          FC_TYPE_ELS, FC_FC_FIRST_SEQ | FC_FC_END_SEQ |
-                          FC_FC_SEQ_INIT, 0);
+       if (op == ELS_SRR)
+               __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS4_REQ, did, sid,
+                                  FC_TYPE_FCP, FC_FC_FIRST_SEQ |
+                                  FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+       else
+               __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS_REQ, did, sid,
+                                  FC_TYPE_ELS, FC_FC_FIRST_SEQ |
+                                  FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
        /* Obtain exchange id */
        xid = els_req->xid;
@@ -352,7 +761,8 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
        index = xid % BNX2FC_TASKS_PER_PAGE;
 
        /* Initialize task context for this IO request */
-       task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+       task_page = (struct fcoe_task_ctx_entry *)
+                       interface->hba->task_ctx[task_idx];
        task = &(task_page[index]);
        bnx2fc_init_mp_task(els_req, task);
 
@@ -496,8 +906,8 @@ struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did,
                                      void *arg, u32 timeout)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
-       struct fcoe_ctlr *fip = &hba->ctlr;
+       struct bnx2fc_interface *interface = port->priv;
+       struct fcoe_ctlr *fip = &interface->ctlr;
        struct fc_frame_header *fh = fc_frame_header_get(fp);
 
        switch (op) {
index a97aff3a06625f80bac54879bb20d8032f277cb7..7cb2cd48b17b253954c0c4801b22d7e980a5f644 100644 (file)
@@ -3,7 +3,7 @@
  * cnic modules to create FCoE instances, send/receive non-offloaded
  * FIP/FCoE packets, listen to link events etc.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 Broadcom 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
 #include "bnx2fc.h"
 
 static struct list_head adapter_list;
+static struct list_head if_list;
 static u32 adapter_count;
 static DEFINE_MUTEX(bnx2fc_dev_lock);
 DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
 
 #define DRV_MODULE_NAME                "bnx2fc"
 #define DRV_MODULE_VERSION     BNX2FC_VERSION
-#define DRV_MODULE_RELDATE     "Jun 10, 2011"
+#define DRV_MODULE_RELDATE     "Jun 23, 2011"
 
 
 static char version[] __devinitdata =
@@ -61,7 +62,7 @@ static int bnx2fc_disable(struct net_device *netdev);
 
 static void bnx2fc_recv_frame(struct sk_buff *skb);
 
-static void bnx2fc_start_disc(struct bnx2fc_hba *hba);
+static void bnx2fc_start_disc(struct bnx2fc_interface *interface);
 static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev);
 static int bnx2fc_net_config(struct fc_lport *lp);
 static int bnx2fc_lport_config(struct fc_lport *lport);
@@ -70,18 +71,20 @@ static int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba);
 static void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba);
 static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba);
 static void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba);
-static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
+static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
                                  struct device *parent, int npiv);
 static void bnx2fc_destroy_work(struct work_struct *work);
 
 static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev);
+static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device
+                                                       *phys_dev);
 static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic);
 
 static int bnx2fc_fw_init(struct bnx2fc_hba *hba);
 static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba);
 
 static void bnx2fc_port_shutdown(struct fc_lport *lport);
-static void bnx2fc_stop(struct bnx2fc_hba *hba);
+static void bnx2fc_stop(struct bnx2fc_interface *interface);
 static int __init bnx2fc_mod_init(void);
 static void __exit bnx2fc_mod_exit(void);
 
@@ -142,7 +145,8 @@ static void bnx2fc_abort_io(struct fc_lport *lport)
 static void bnx2fc_cleanup(struct fc_lport *lport)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct bnx2fc_rport *tgt;
        int i;
 
@@ -219,7 +223,8 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
        struct fcoe_crc_eof     *cp;
        struct sk_buff          *skb;
        struct fc_frame_header  *fh;
-       struct bnx2fc_hba       *hba;
+       struct bnx2fc_interface *interface;
+       struct bnx2fc_hba *hba;
        struct fcoe_port        *port;
        struct fcoe_hdr         *hp;
        struct bnx2fc_rport     *tgt;
@@ -230,7 +235,8 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
        int                     wlen, rc = 0;
 
        port = (struct fcoe_port *)lport_priv(lport);
-       hba = port->priv;
+       interface = port->priv;
+       hba = interface->hba;
 
        fh = fc_frame_header_get(fp);
 
@@ -242,12 +248,12 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
        }
 
        if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) {
-               if (!hba->ctlr.sel_fcf) {
+               if (!interface->ctlr.sel_fcf) {
                        BNX2FC_HBA_DBG(lport, "FCF not selected yet!\n");
                        kfree_skb(skb);
                        return -EINVAL;
                }
-               if (fcoe_ctlr_els_send(&hba->ctlr, lport, skb))
+               if (fcoe_ctlr_els_send(&interface->ctlr, lport, skb))
                        return 0;
        }
 
@@ -316,19 +322,19 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
        skb_reset_network_header(skb);
        skb->mac_len = elen;
        skb->protocol = htons(ETH_P_FCOE);
-       skb->dev = hba->netdev;
+       skb->dev = interface->netdev;
 
        /* fill up mac and fcoe headers */
        eh = eth_hdr(skb);
        eh->h_proto = htons(ETH_P_FCOE);
-       if (hba->ctlr.map_dest)
+       if (interface->ctlr.map_dest)
                fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id);
        else
                /* insert GW address */
-               memcpy(eh->h_dest, hba->ctlr.dest_addr, ETH_ALEN);
+               memcpy(eh->h_dest, interface->ctlr.dest_addr, ETH_ALEN);
 
-       if (unlikely(hba->ctlr.flogi_oxid != FC_XID_UNKNOWN))
-               memcpy(eh->h_source, hba->ctlr.ctl_src_addr, ETH_ALEN);
+       if (unlikely(interface->ctlr.flogi_oxid != FC_XID_UNKNOWN))
+               memcpy(eh->h_source, interface->ctlr.ctl_src_addr, ETH_ALEN);
        else
                memcpy(eh->h_source, port->data_src_addr, ETH_ALEN);
 
@@ -377,22 +383,23 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
                struct packet_type *ptype, struct net_device *olddev)
 {
        struct fc_lport *lport;
-       struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct fc_frame_header *fh;
        struct fcoe_rcv_info *fr;
        struct fcoe_percpu_s *bg;
        unsigned short oxid;
 
-       hba = container_of(ptype, struct bnx2fc_hba, fcoe_packet_type);
-       lport = hba->ctlr.lp;
+       interface = container_of(ptype, struct bnx2fc_interface,
+                                fcoe_packet_type);
+       lport = interface->ctlr.lp;
 
        if (unlikely(lport == NULL)) {
-               printk(KERN_ALERT PFX "bnx2fc_rcv: lport is NULL\n");
+               printk(KERN_ERR PFX "bnx2fc_rcv: lport is NULL\n");
                goto err;
        }
 
        if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
-               printk(KERN_ALERT PFX "bnx2fc_rcv: Wrong FC type frame\n");
+               printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n");
                goto err;
        }
 
@@ -411,7 +418,6 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev,
 
        fr = fcoe_dev_from_skb(skb);
        fr->fr_dev = lport;
-       fr->ptype = ptype;
 
        bg = &bnx2fc_global;
        spin_lock_bh(&bg->fcoe_rx_list.lock);
@@ -469,7 +475,7 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
        fr = fcoe_dev_from_skb(skb);
        lport = fr->fr_dev;
        if (unlikely(lport == NULL)) {
-               printk(KERN_ALERT PFX "Invalid lport struct\n");
+               printk(KERN_ERR PFX "Invalid lport struct\n");
                kfree_skb(skb);
                return;
        }
@@ -594,7 +600,8 @@ static struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost)
        struct fc_host_statistics *bnx2fc_stats;
        struct fc_lport *lport = shost_priv(shost);
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct fcoe_statistics_params *fw_stats;
        int rc = 0;
 
@@ -631,7 +638,7 @@ static struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost)
 static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
        struct Scsi_Host *shost = lport->host;
        int rc = 0;
 
@@ -654,7 +661,7 @@ static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev)
                fc_host_max_npiv_vports(lport->host) = USHRT_MAX;
        sprintf(fc_host_symbolic_name(lport->host), "%s v%s over %s",
                BNX2FC_NAME, BNX2FC_VERSION,
-               hba->netdev->name);
+               interface->netdev->name);
 
        return 0;
 }
@@ -662,8 +669,8 @@ static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev)
 static void bnx2fc_link_speed_update(struct fc_lport *lport)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
-       struct net_device *netdev = hba->netdev;
+       struct bnx2fc_interface *interface = port->priv;
+       struct net_device *netdev = interface->netdev;
        struct ethtool_cmd ecmd;
 
        if (!dev_ethtool_get_settings(netdev, &ecmd)) {
@@ -691,7 +698,8 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
 static int bnx2fc_link_ok(struct fc_lport *lport)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct net_device *dev = hba->phys_dev;
        int rc = 0;
 
@@ -713,7 +721,7 @@ static int bnx2fc_link_ok(struct fc_lport *lport)
  */
 void bnx2fc_get_link_state(struct bnx2fc_hba *hba)
 {
-       if (test_bit(__LINK_STATE_NOCARRIER, &hba->netdev->state))
+       if (test_bit(__LINK_STATE_NOCARRIER, &hba->phys_dev->state))
                set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
        else
                clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state);
@@ -722,11 +730,13 @@ void bnx2fc_get_link_state(struct bnx2fc_hba *hba)
 static int bnx2fc_net_config(struct fc_lport *lport)
 {
        struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct fcoe_port *port;
        u64 wwnn, wwpn;
 
        port = lport_priv(lport);
-       hba = port->priv;
+       interface = port->priv;
+       hba = interface->hba;
 
        /* require support for get_pauseparam ethtool op. */
        if (!hba->phys_dev->ethtool_ops ||
@@ -743,11 +753,11 @@ static int bnx2fc_net_config(struct fc_lport *lport)
        bnx2fc_link_speed_update(lport);
 
        if (!lport->vport) {
-               wwnn = fcoe_wwn_from_mac(hba->ctlr.ctl_src_addr, 1, 0);
+               wwnn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, 1, 0);
                BNX2FC_HBA_DBG(lport, "WWNN = 0x%llx\n", wwnn);
                fc_set_wwnn(lport, wwnn);
 
-               wwpn = fcoe_wwn_from_mac(hba->ctlr.ctl_src_addr, 2, 0);
+               wwpn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, 2, 0);
                BNX2FC_HBA_DBG(lport, "WWPN = 0x%llx\n", wwpn);
                fc_set_wwpn(lport, wwpn);
        }
@@ -759,9 +769,9 @@ static void bnx2fc_destroy_timer(unsigned long data)
 {
        struct bnx2fc_hba *hba = (struct bnx2fc_hba *)data;
 
-       BNX2FC_HBA_DBG(hba->ctlr.lp, "ERROR:bnx2fc_destroy_timer - "
+       BNX2FC_MISC_DBG("ERROR:bnx2fc_destroy_timer - "
                   "Destroy compl not received!!\n");
-       hba->flags |= BNX2FC_FLAG_DESTROY_CMPL;
+       set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags);
        wake_up_interruptible(&hba->destroy_wait);
 }
 
@@ -779,54 +789,35 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
                                     u16 vlan_id)
 {
        struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context;
-       struct fc_lport *lport = hba->ctlr.lp;
+       struct fc_lport *lport;
        struct fc_lport *vport;
+       struct bnx2fc_interface *interface;
+       int wait_for_upload = 0;
        u32 link_possible = 1;
 
        /* Ignore vlans for now */
        if (vlan_id != 0)
                return;
 
-       if (!test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
-               BNX2FC_MISC_DBG("driver not ready. event=%s %ld\n",
-                          hba->netdev->name, event);
-               return;
-       }
-
-       /*
-        * ASSUMPTION:
-        * indicate_netevent cannot be called from cnic unless bnx2fc
-        * does register_device
-        */
-       BUG_ON(!lport);
-
-       BNX2FC_HBA_DBG(lport, "enter netevent handler - event=%s %ld\n",
-                               hba->netdev->name, event);
-
        switch (event) {
        case NETDEV_UP:
-               BNX2FC_HBA_DBG(lport, "Port up, adapter_state = %ld\n",
-                       hba->adapter_state);
                if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
                        printk(KERN_ERR "indicate_netevent: "\
-                                       "adapter is not UP!!\n");
+                                       "hba is not UP!!\n");
                break;
 
        case NETDEV_DOWN:
-               BNX2FC_HBA_DBG(lport, "Port down\n");
                clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
                clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
                link_possible = 0;
                break;
 
        case NETDEV_GOING_DOWN:
-               BNX2FC_HBA_DBG(lport, "Port going down\n");
                set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
                link_possible = 0;
                break;
 
        case NETDEV_CHANGE:
-               BNX2FC_HBA_DBG(lport, "NETDEV_CHANGE\n");
                break;
 
        default:
@@ -834,15 +825,22 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
                return;
        }
 
-       bnx2fc_link_speed_update(lport);
+       mutex_lock(&bnx2fc_dev_lock);
+       list_for_each_entry(interface, &if_list, list) {
 
-       if (link_possible && !bnx2fc_link_ok(lport)) {
-               printk(KERN_ERR "indicate_netevent: call ctlr_link_up\n");
-               fcoe_ctlr_link_up(&hba->ctlr);
-       } else {
-               printk(KERN_ERR "indicate_netevent: call ctlr_link_down\n");
-               if (fcoe_ctlr_link_down(&hba->ctlr)) {
-                       clear_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+               if (interface->hba != hba)
+                       continue;
+
+               lport = interface->ctlr.lp;
+               BNX2FC_HBA_DBG(lport, "netevent handler - event=%s %ld\n",
+                               interface->netdev->name, event);
+
+               bnx2fc_link_speed_update(lport);
+
+               if (link_possible && !bnx2fc_link_ok(lport)) {
+                       printk(KERN_ERR "indicate_netevent: ctlr_link_up\n");
+                       fcoe_ctlr_link_up(&interface->ctlr);
+               } else if (fcoe_ctlr_link_down(&interface->ctlr)) {
                        mutex_lock(&lport->lp_mutex);
                        list_for_each_entry(vport, &lport->vports, list)
                                fc_host_port_type(vport->host) =
@@ -853,24 +851,26 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
                                    get_cpu())->LinkFailureCount++;
                        put_cpu();
                        fcoe_clean_pending_queue(lport);
+                       wait_for_upload = 1;
+               }
+       }
+       mutex_unlock(&bnx2fc_dev_lock);
 
-                       init_waitqueue_head(&hba->shutdown_wait);
-                       BNX2FC_HBA_DBG(lport, "indicate_netevent "
-                                            "num_ofld_sess = %d\n",
-                                  hba->num_ofld_sess);
-                       hba->wait_for_link_down = 1;
-                       BNX2FC_HBA_DBG(lport, "waiting for uploads to "
-                                            "compl proc = %s\n",
-                                  current->comm);
-                       wait_event_interruptible(hba->shutdown_wait,
-                                                (hba->num_ofld_sess == 0));
-                       BNX2FC_HBA_DBG(lport, "wakeup - num_ofld_sess = %d\n",
+       if (wait_for_upload) {
+               clear_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+               init_waitqueue_head(&hba->shutdown_wait);
+               BNX2FC_MISC_DBG("indicate_netevent "
+                               "num_ofld_sess = %d\n",
+                               hba->num_ofld_sess);
+               hba->wait_for_link_down = 1;
+               wait_event_interruptible(hba->shutdown_wait,
+                                        (hba->num_ofld_sess == 0));
+               BNX2FC_MISC_DBG("wakeup - num_ofld_sess = %d\n",
                                hba->num_ofld_sess);
-                       hba->wait_for_link_down = 0;
+               hba->wait_for_link_down = 0;
 
-                       if (signal_pending(current))
-                               flush_signals(current);
-               }
+               if (signal_pending(current))
+                       flush_signals(current);
        }
 }
 
@@ -889,23 +889,12 @@ static int bnx2fc_libfc_config(struct fc_lport *lport)
 
 static int bnx2fc_em_config(struct fc_lport *lport)
 {
-       struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
-
        if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_MIN_XID,
                                FCOE_MAX_XID, NULL)) {
                printk(KERN_ERR PFX "em_config:fc_exch_mgr_alloc failed\n");
                return -ENOMEM;
        }
 
-       hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba, BNX2FC_MIN_XID,
-                                           BNX2FC_MAX_XID);
-
-       if (!hba->cmd_mgr) {
-               printk(KERN_ERR PFX "em_config:bnx2fc_cmd_mgr_alloc failed\n");
-               fc_exch_mgr_free(lport);
-               return -ENOMEM;
-       }
        return 0;
 }
 
@@ -918,11 +907,8 @@ static int bnx2fc_lport_config(struct fc_lport *lport)
        lport->e_d_tov = 2 * 1000;
        lport->r_a_tov = 10 * 1000;
 
-       /* REVISIT: enable when supporting tape devices
        lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
                                FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
-       */
-       lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS);
        lport->does_npiv = 1;
 
        memset(&lport->rnid_gen, 0, sizeof(struct fc_els_rnid_gen));
@@ -952,9 +938,10 @@ static int bnx2fc_fip_recv(struct sk_buff *skb, struct net_device *dev,
                           struct packet_type *ptype,
                           struct net_device *orig_dev)
 {
-       struct bnx2fc_hba *hba;
-       hba = container_of(ptype, struct bnx2fc_hba, fip_packet_type);
-       fcoe_ctlr_recv(&hba->ctlr, skb);
+       struct bnx2fc_interface *interface;
+       interface = container_of(ptype, struct bnx2fc_interface,
+                                fip_packet_type);
+       fcoe_ctlr_recv(&interface->ctlr, skb);
        return 0;
 }
 
@@ -1005,17 +992,17 @@ static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled)
        struct Scsi_Host *shost = vport_to_shost(vport);
        struct fc_lport *n_port = shost_priv(shost);
        struct fcoe_port *port = lport_priv(n_port);
-       struct bnx2fc_hba *hba = port->priv;
-       struct net_device *netdev = hba->netdev;
+       struct bnx2fc_interface *interface = port->priv;
+       struct net_device *netdev = interface->netdev;
        struct fc_lport *vn_port;
 
-       if (!test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
+       if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) {
                printk(KERN_ERR PFX "vn ports cannot be created on"
-                       "this hba\n");
+                       "this interface\n");
                return -EIO;
        }
        mutex_lock(&bnx2fc_dev_lock);
-       vn_port = bnx2fc_if_create(hba, &vport->dev, 1);
+       vn_port = bnx2fc_if_create(interface, &vport->dev, 1);
        mutex_unlock(&bnx2fc_dev_lock);
 
        if (IS_ERR(vn_port)) {
@@ -1065,10 +1052,10 @@ static int bnx2fc_vport_disable(struct fc_vport *vport, bool disable)
 }
 
 
-static int bnx2fc_netdev_setup(struct bnx2fc_hba *hba)
+static int bnx2fc_netdev_setup(struct bnx2fc_interface *interface)
 {
-       struct net_device *netdev = hba->netdev;
-       struct net_device *physdev = hba->phys_dev;
+       struct net_device *netdev = interface->netdev;
+       struct net_device *physdev = interface->hba->phys_dev;
        struct netdev_hw_addr *ha;
        int sel_san_mac = 0;
 
@@ -1083,7 +1070,8 @@ static int bnx2fc_netdev_setup(struct bnx2fc_hba *hba)
 
                if ((ha->type == NETDEV_HW_ADDR_T_SAN) &&
                    (is_valid_ether_addr(ha->addr))) {
-                       memcpy(hba->ctlr.ctl_src_addr, ha->addr, ETH_ALEN);
+                       memcpy(interface->ctlr.ctl_src_addr, ha->addr,
+                              ETH_ALEN);
                        sel_san_mac = 1;
                        BNX2FC_MISC_DBG("Found SAN MAC\n");
                }
@@ -1093,15 +1081,15 @@ static int bnx2fc_netdev_setup(struct bnx2fc_hba *hba)
        if (!sel_san_mac)
                return -ENODEV;
 
-       hba->fip_packet_type.func = bnx2fc_fip_recv;
-       hba->fip_packet_type.type = htons(ETH_P_FIP);
-       hba->fip_packet_type.dev = netdev;
-       dev_add_pack(&hba->fip_packet_type);
+       interface->fip_packet_type.func = bnx2fc_fip_recv;
+       interface->fip_packet_type.type = htons(ETH_P_FIP);
+       interface->fip_packet_type.dev = netdev;
+       dev_add_pack(&interface->fip_packet_type);
 
-       hba->fcoe_packet_type.func = bnx2fc_rcv;
-       hba->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE);
-       hba->fcoe_packet_type.dev = netdev;
-       dev_add_pack(&hba->fcoe_packet_type);
+       interface->fcoe_packet_type.func = bnx2fc_rcv;
+       interface->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE);
+       interface->fcoe_packet_type.dev = netdev;
+       dev_add_pack(&interface->fcoe_packet_type);
 
        return 0;
 }
@@ -1137,53 +1125,54 @@ static void bnx2fc_release_transport(void)
 
 static void bnx2fc_interface_release(struct kref *kref)
 {
-       struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct net_device *netdev;
-       struct net_device *phys_dev;
 
-       hba = container_of(kref, struct bnx2fc_hba, kref);
+       interface = container_of(kref, struct bnx2fc_interface, kref);
        BNX2FC_MISC_DBG("Interface is being released\n");
 
-       netdev = hba->netdev;
-       phys_dev = hba->phys_dev;
+       netdev = interface->netdev;
 
        /* tear-down FIP controller */
-       if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done))
-               fcoe_ctlr_destroy(&hba->ctlr);
+       if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags))
+               fcoe_ctlr_destroy(&interface->ctlr);
+
+       kfree(interface);
 
-       /* Free the command manager */
-       if (hba->cmd_mgr) {
-               bnx2fc_cmd_mgr_free(hba->cmd_mgr);
-               hba->cmd_mgr = NULL;
-       }
        dev_put(netdev);
        module_put(THIS_MODULE);
 }
 
-static inline void bnx2fc_interface_get(struct bnx2fc_hba *hba)
+static inline void bnx2fc_interface_get(struct bnx2fc_interface *interface)
 {
-       kref_get(&hba->kref);
+       kref_get(&interface->kref);
 }
 
-static inline void bnx2fc_interface_put(struct bnx2fc_hba *hba)
+static inline void bnx2fc_interface_put(struct bnx2fc_interface *interface)
 {
-       kref_put(&hba->kref, bnx2fc_interface_release);
+       kref_put(&interface->kref, bnx2fc_interface_release);
 }
-static void bnx2fc_interface_destroy(struct bnx2fc_hba *hba)
+static void bnx2fc_hba_destroy(struct bnx2fc_hba *hba)
 {
+       /* Free the command manager */
+       if (hba->cmd_mgr) {
+               bnx2fc_cmd_mgr_free(hba->cmd_mgr);
+               hba->cmd_mgr = NULL;
+       }
+       kfree(hba->tgt_ofld_list);
        bnx2fc_unbind_pcidev(hba);
        kfree(hba);
 }
 
 /**
- * bnx2fc_interface_create - create a new fcoe instance
+ * bnx2fc_hba_create - create a new bnx2fc hba
  *
  * @cnic:      pointer to cnic device
  *
- * Creates a new FCoE instance on the given device which include allocating
- *     hba structure, scsi_host and lport structures.
+ * Creates a new FCoE hba on the given device.
+ *
  */
-static struct bnx2fc_hba *bnx2fc_interface_create(struct cnic_dev *cnic)
+static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic)
 {
        struct bnx2fc_hba *hba;
        int rc;
@@ -1198,65 +1187,83 @@ static struct bnx2fc_hba *bnx2fc_interface_create(struct cnic_dev *cnic)
 
        hba->cnic = cnic;
        rc = bnx2fc_bind_pcidev(hba);
-       if (rc)
+       if (rc) {
+               printk(KERN_ERR PFX "create_adapter:  bind error\n");
                goto bind_err;
+       }
        hba->phys_dev = cnic->netdev;
-       /* will get overwritten after we do vlan discovery */
-       hba->netdev = hba->phys_dev;
+       hba->next_conn_id = 0;
+
+       hba->tgt_ofld_list =
+               kzalloc(sizeof(struct bnx2fc_rport *) * BNX2FC_NUM_MAX_SESS,
+                       GFP_KERNEL);
+       if (!hba->tgt_ofld_list) {
+               printk(KERN_ERR PFX "Unable to allocate tgt offload list\n");
+               goto tgtofld_err;
+       }
+
+       hba->num_ofld_sess = 0;
+
+       hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba, BNX2FC_MIN_XID,
+                                               BNX2FC_MAX_XID);
+       if (!hba->cmd_mgr) {
+               printk(KERN_ERR PFX "em_config:bnx2fc_cmd_mgr_alloc failed\n");
+               goto cmgr_err;
+       }
 
        init_waitqueue_head(&hba->shutdown_wait);
        init_waitqueue_head(&hba->destroy_wait);
+       INIT_LIST_HEAD(&hba->vports);
 
        return hba;
+
+cmgr_err:
+       kfree(hba->tgt_ofld_list);
+tgtofld_err:
+       bnx2fc_unbind_pcidev(hba);
 bind_err:
-       printk(KERN_ERR PFX "create_interface: bind error\n");
        kfree(hba);
        return NULL;
 }
 
-static int bnx2fc_interface_setup(struct bnx2fc_hba *hba,
-                                 enum fip_state fip_mode)
+struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba,
+                                     struct net_device *netdev,
+                                     enum fip_state fip_mode)
 {
+       struct bnx2fc_interface *interface;
        int rc = 0;
-       struct net_device *netdev = hba->netdev;
-       struct fcoe_ctlr *fip = &hba->ctlr;
 
+       interface = kzalloc(sizeof(*interface), GFP_KERNEL);
+       if (!interface) {
+               printk(KERN_ERR PFX "Unable to allocate interface structure\n");
+               return NULL;
+       }
        dev_hold(netdev);
-       kref_init(&hba->kref);
-
-       hba->flags = 0;
+       kref_init(&interface->kref);
+       interface->hba = hba;
+       interface->netdev = netdev;
 
        /* Initialize FIP */
-       memset(fip, 0, sizeof(*fip));
-       fcoe_ctlr_init(fip, fip_mode);
-       hba->ctlr.send = bnx2fc_fip_send;
-       hba->ctlr.update_mac = bnx2fc_update_src_mac;
-       hba->ctlr.get_src_addr = bnx2fc_get_src_mac;
-       set_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done);
-
-       INIT_LIST_HEAD(&hba->vports);
-       rc = bnx2fc_netdev_setup(hba);
-       if (rc)
-               goto setup_err;
+       fcoe_ctlr_init(&interface->ctlr, fip_mode);
+       interface->ctlr.send = bnx2fc_fip_send;
+       interface->ctlr.update_mac = bnx2fc_update_src_mac;
+       interface->ctlr.get_src_addr = bnx2fc_get_src_mac;
+       set_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags);
 
-       hba->next_conn_id = 0;
+       rc = bnx2fc_netdev_setup(interface);
+       if (!rc)
+               return interface;
 
-       memset(hba->tgt_ofld_list, 0, sizeof(hba->tgt_ofld_list));
-       hba->num_ofld_sess = 0;
-
-       return 0;
-
-setup_err:
-       fcoe_ctlr_destroy(&hba->ctlr);
+       fcoe_ctlr_destroy(&interface->ctlr);
        dev_put(netdev);
-       bnx2fc_interface_put(hba);
-       return rc;
+       kfree(interface);
+       return NULL;
 }
 
 /**
  * bnx2fc_if_create - Create FCoE instance on a given interface
  *
- * @hba:       FCoE interface to create a local port on
+ * @interface: FCoE interface to create a local port on
  * @parent:    Device pointer to be the parent in sysfs for the SCSI host
  * @npiv:      Indicates if the port is vport or not
  *
@@ -1264,7 +1271,7 @@ setup_err:
  *
  * Returns:    Allocated fc_lport or an error pointer
  */
-static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
+static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
                                  struct device *parent, int npiv)
 {
        struct fc_lport         *lport, *n_port;
@@ -1272,11 +1279,12 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
        struct Scsi_Host        *shost;
        struct fc_vport         *vport = dev_to_vport(parent);
        struct bnx2fc_lport     *blport;
+       struct bnx2fc_hba       *hba;
        int                     rc = 0;
 
        blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL);
        if (!blport) {
-               BNX2FC_HBA_DBG(hba->ctlr.lp, "Unable to alloc bnx2fc_lport\n");
+               BNX2FC_HBA_DBG(interface->ctlr.lp, "Unable to alloc blport\n");
                return NULL;
        }
 
@@ -1293,7 +1301,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
        shost = lport->host;
        port = lport_priv(lport);
        port->lport = lport;
-       port->priv = hba;
+       port->priv = interface;
        INIT_WORK(&port->destroy_work, bnx2fc_destroy_work);
 
        /* Configure fcoe_port */
@@ -1317,7 +1325,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
        rc = bnx2fc_shost_config(lport, parent);
        if (rc) {
                printk(KERN_ERR PFX "Couldnt configure shost for %s\n",
-                       hba->netdev->name);
+                       interface->netdev->name);
                goto lp_config_err;
        }
 
@@ -1343,8 +1351,9 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
                goto shost_err;
        }
 
-       bnx2fc_interface_get(hba);
+       bnx2fc_interface_get(interface);
 
+       hba = interface->hba;
        spin_lock_bh(&hba->hba_lock);
        blport->lport = lport;
        list_add_tail(&blport->list, &hba->vports);
@@ -1361,21 +1370,19 @@ free_blport:
        return NULL;
 }
 
-static void bnx2fc_netdev_cleanup(struct bnx2fc_hba *hba)
+static void bnx2fc_netdev_cleanup(struct bnx2fc_interface *interface)
 {
        /* Dont listen for Ethernet packets anymore */
-       __dev_remove_pack(&hba->fcoe_packet_type);
-       __dev_remove_pack(&hba->fip_packet_type);
+       __dev_remove_pack(&interface->fcoe_packet_type);
+       __dev_remove_pack(&interface->fip_packet_type);
        synchronize_net();
 }
 
-static void bnx2fc_if_destroy(struct fc_lport *lport)
+static void bnx2fc_if_destroy(struct fc_lport *lport, struct bnx2fc_hba *hba)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
        struct bnx2fc_lport *blport, *tmp;
 
-       BNX2FC_HBA_DBG(hba->ctlr.lp, "ENTERED bnx2fc_if_destroy\n");
        /* Stop the transmit retry timer */
        del_timer_sync(&port->timer);
 
@@ -1409,8 +1416,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport)
 
        /* Release Scsi_Host */
        scsi_host_put(lport->host);
-
-       bnx2fc_interface_put(hba);
 }
 
 /**
@@ -1425,46 +1430,31 @@ static void bnx2fc_if_destroy(struct fc_lport *lport)
  */
 static int bnx2fc_destroy(struct net_device *netdev)
 {
-       struct bnx2fc_hba *hba = NULL;
-       struct net_device *phys_dev;
+       struct bnx2fc_interface *interface = NULL;
+       struct bnx2fc_hba *hba;
+       struct fc_lport *lport;
        int rc = 0;
 
        rtnl_lock();
-
        mutex_lock(&bnx2fc_dev_lock);
-       /* obtain physical netdev */
-       if (netdev->priv_flags & IFF_802_1Q_VLAN)
-               phys_dev = vlan_dev_real_dev(netdev);
-       else {
-               printk(KERN_ERR PFX "Not a vlan device\n");
-               rc = -ENODEV;
-               goto netdev_err;
-       }
 
-       hba = bnx2fc_hba_lookup(phys_dev);
-       if (!hba || !hba->ctlr.lp) {
+       interface = bnx2fc_interface_lookup(netdev);
+       if (!interface || !interface->ctlr.lp) {
                rc = -ENODEV;
-               printk(KERN_ERR PFX "bnx2fc_destroy: hba or lport not found\n");
-               goto netdev_err;
-       }
-
-       if (!test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
-               printk(KERN_ERR PFX "bnx2fc_destroy: Create not called\n");
+               printk(KERN_ERR PFX "bnx2fc_destroy: interface or lport not found\n");
                goto netdev_err;
        }
 
-       bnx2fc_netdev_cleanup(hba);
-
-       bnx2fc_stop(hba);
-
-       bnx2fc_if_destroy(hba->ctlr.lp);
+       hba = interface->hba;
 
-       destroy_workqueue(hba->timer_work_queue);
+       bnx2fc_netdev_cleanup(interface);
+       lport = interface->ctlr.lp;
+       bnx2fc_stop(interface);
+       list_del(&interface->list);
+       destroy_workqueue(interface->timer_work_queue);
+       bnx2fc_interface_put(interface);
+       bnx2fc_if_destroy(lport, hba);
 
-       if (test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done))
-               bnx2fc_fw_destroy(hba);
-
-       clear_bit(BNX2FC_CREATE_DONE, &hba->init_done);
 netdev_err:
        mutex_unlock(&bnx2fc_dev_lock);
        rtnl_unlock();
@@ -1475,16 +1465,20 @@ static void bnx2fc_destroy_work(struct work_struct *work)
 {
        struct fcoe_port *port;
        struct fc_lport *lport;
+       struct bnx2fc_interface *interface;
+       struct bnx2fc_hba *hba;
 
        port = container_of(work, struct fcoe_port, destroy_work);
        lport = port->lport;
+       interface = port->priv;
+       hba = interface->hba;
 
        BNX2FC_HBA_DBG(lport, "Entered bnx2fc_destroy_work\n");
 
        bnx2fc_port_shutdown(lport);
        rtnl_lock();
        mutex_lock(&bnx2fc_dev_lock);
-       bnx2fc_if_destroy(lport);
+       bnx2fc_if_destroy(lport, hba);
        mutex_unlock(&bnx2fc_dev_lock);
        rtnl_unlock();
 }
@@ -1556,28 +1550,27 @@ static void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba)
 static void bnx2fc_ulp_start(void *handle)
 {
        struct bnx2fc_hba *hba = handle;
-       struct fc_lport *lport = hba->ctlr.lp;
+       struct bnx2fc_interface *interface;
+       struct fc_lport *lport;
 
-       BNX2FC_MISC_DBG("Entered %s\n", __func__);
        mutex_lock(&bnx2fc_dev_lock);
 
-       if (test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done))
-               goto start_disc;
-
-       if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done))
+       if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags))
                bnx2fc_fw_init(hba);
 
-start_disc:
-       mutex_unlock(&bnx2fc_dev_lock);
-
        BNX2FC_MISC_DBG("bnx2fc started.\n");
 
-       /* Kick off Fabric discovery*/
-       if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
-               printk(KERN_ERR PFX "ulp_init: start discovery\n");
-               lport->tt.frame_send = bnx2fc_xmit;
-               bnx2fc_start_disc(hba);
+       list_for_each_entry(interface, &if_list, list) {
+               if (interface->hba == hba) {
+                       lport = interface->ctlr.lp;
+                       /* Kick off Fabric discovery*/
+                       printk(KERN_ERR PFX "ulp_init: start discovery\n");
+                       lport->tt.frame_send = bnx2fc_xmit;
+                       bnx2fc_start_disc(interface);
+               }
        }
+
+       mutex_unlock(&bnx2fc_dev_lock);
 }
 
 static void bnx2fc_port_shutdown(struct fc_lport *lport)
@@ -1587,37 +1580,25 @@ static void bnx2fc_port_shutdown(struct fc_lport *lport)
        fc_lport_destroy(lport);
 }
 
-static void bnx2fc_stop(struct bnx2fc_hba *hba)
+static void bnx2fc_stop(struct bnx2fc_interface *interface)
 {
        struct fc_lport *lport;
        struct fc_lport *vport;
 
-       BNX2FC_MISC_DBG("ENTERED %s - init_done = %ld\n", __func__,
-                  hba->init_done);
-       if (test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done) &&
-           test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
-               lport = hba->ctlr.lp;
-               bnx2fc_port_shutdown(lport);
-               BNX2FC_HBA_DBG(lport, "bnx2fc_stop: waiting for %d "
-                               "offloaded sessions\n",
-                               hba->num_ofld_sess);
-               wait_event_interruptible(hba->shutdown_wait,
-                                        (hba->num_ofld_sess == 0));
-               mutex_lock(&lport->lp_mutex);
-               list_for_each_entry(vport, &lport->vports, list)
-                       fc_host_port_type(vport->host) = FC_PORTTYPE_UNKNOWN;
-               mutex_unlock(&lport->lp_mutex);
-               fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
-               fcoe_ctlr_link_down(&hba->ctlr);
-               fcoe_clean_pending_queue(lport);
-
-               mutex_lock(&hba->hba_mutex);
-               clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
-               clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state);
+       if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags))
+               return;
 
-               clear_bit(ADAPTER_STATE_READY, &hba->adapter_state);
-               mutex_unlock(&hba->hba_mutex);
-       }
+       lport = interface->ctlr.lp;
+       bnx2fc_port_shutdown(lport);
+
+       mutex_lock(&lport->lp_mutex);
+       list_for_each_entry(vport, &lport->vports, list)
+               fc_host_port_type(vport->host) =
+                                       FC_PORTTYPE_UNKNOWN;
+       mutex_unlock(&lport->lp_mutex);
+       fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
+       fcoe_ctlr_link_down(&interface->ctlr);
+       fcoe_clean_pending_queue(lport);
 }
 
 static int bnx2fc_fw_init(struct bnx2fc_hba *hba)
@@ -1656,8 +1637,7 @@ static int bnx2fc_fw_init(struct bnx2fc_hba *hba)
        }
 
 
-       /* Mark HBA to indicate that the FW INIT is done */
-       set_bit(BNX2FC_FW_INIT_DONE, &hba->init_done);
+       set_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags);
        return 0;
 
 err_unbind:
@@ -1668,7 +1648,7 @@ err_out:
 
 static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba)
 {
-       if (test_and_clear_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
+       if (test_and_clear_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) {
                if (bnx2fc_send_fw_fcoe_destroy_msg(hba) == 0) {
                        init_timer(&hba->destroy_timer);
                        hba->destroy_timer.expires = BNX2FC_FW_TIMEOUT +
@@ -1677,8 +1657,8 @@ static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba)
                        hba->destroy_timer.data = (unsigned long)hba;
                        add_timer(&hba->destroy_timer);
                        wait_event_interruptible(hba->destroy_wait,
-                                                (hba->flags &
-                                                 BNX2FC_FLAG_DESTROY_CMPL));
+                                       test_bit(BNX2FC_FLAG_DESTROY_CMPL,
+                                                &hba->flags));
                        /* This should never happen */
                        if (signal_pending(current))
                                flush_signals(current);
@@ -1699,40 +1679,57 @@ static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba)
  */
 static void bnx2fc_ulp_stop(void *handle)
 {
-       struct bnx2fc_hba *hba = (struct bnx2fc_hba *)handle;
+       struct bnx2fc_hba *hba = handle;
+       struct bnx2fc_interface *interface;
 
        printk(KERN_ERR "ULP_STOP\n");
 
        mutex_lock(&bnx2fc_dev_lock);
-       bnx2fc_stop(hba);
+       if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags))
+               goto exit;
+       list_for_each_entry(interface, &if_list, list) {
+               if (interface->hba == hba)
+                       bnx2fc_stop(interface);
+       }
+       BUG_ON(hba->num_ofld_sess != 0);
+
+       mutex_lock(&hba->hba_mutex);
+       clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
+       clear_bit(ADAPTER_STATE_GOING_DOWN,
+                 &hba->adapter_state);
+
+       clear_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+       mutex_unlock(&hba->hba_mutex);
+
        bnx2fc_fw_destroy(hba);
+exit:
        mutex_unlock(&bnx2fc_dev_lock);
 }
 
-static void bnx2fc_start_disc(struct bnx2fc_hba *hba)
+static void bnx2fc_start_disc(struct bnx2fc_interface *interface)
 {
        struct fc_lport *lport;
        int wait_cnt = 0;
 
        BNX2FC_MISC_DBG("Entered %s\n", __func__);
        /* Kick off FIP/FLOGI */
-       if (!test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
+       if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) {
                printk(KERN_ERR PFX "Init not done yet\n");
                return;
        }
 
-       lport = hba->ctlr.lp;
+       lport = interface->ctlr.lp;
        BNX2FC_HBA_DBG(lport, "calling fc_fabric_login\n");
 
        if (!bnx2fc_link_ok(lport)) {
                BNX2FC_HBA_DBG(lport, "ctlr_link_up\n");
-               fcoe_ctlr_link_up(&hba->ctlr);
+               fcoe_ctlr_link_up(&interface->ctlr);
                fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT;
-               set_bit(ADAPTER_STATE_READY, &hba->adapter_state);
+               set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state);
        }
 
        /* wait for the FCF to be selected before issuing FLOGI */
-       while (!hba->ctlr.sel_fcf) {
+       while (!interface->ctlr.sel_fcf) {
                msleep(250);
                /* give up after 3 secs */
                if (++wait_cnt > 12)
@@ -1758,15 +1755,15 @@ static void bnx2fc_ulp_init(struct cnic_dev *dev)
 
        BNX2FC_MISC_DBG("Entered %s\n", __func__);
        /* bnx2fc works only when bnx2x is loaded */
-       if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
+       if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags) ||
+           (dev->max_fcoe_conn == 0)) {
                printk(KERN_ERR PFX "bnx2fc FCoE not supported on %s,"
-                                   " flags: %lx\n",
-                       dev->netdev->name, dev->flags);
+                                   " flags: %lx fcoe_conn: %d\n",
+                       dev->netdev->name, dev->flags, dev->max_fcoe_conn);
                return;
        }
 
-       /* Configure FCoE interface */
-       hba = bnx2fc_interface_create(dev);
+       hba = bnx2fc_hba_create(dev);
        if (!hba) {
                printk(KERN_ERR PFX "hba initialization failed\n");
                return;
@@ -1774,7 +1771,7 @@ static void bnx2fc_ulp_init(struct cnic_dev *dev)
 
        /* Add HBA to the adapter list */
        mutex_lock(&bnx2fc_dev_lock);
-       list_add_tail(&hba->link, &adapter_list);
+       list_add_tail(&hba->list, &adapter_list);
        adapter_count++;
        mutex_unlock(&bnx2fc_dev_lock);
 
@@ -1782,7 +1779,7 @@ static void bnx2fc_ulp_init(struct cnic_dev *dev)
        rc = dev->register_device(dev, CNIC_ULP_FCOE,
                                                (void *) hba);
        if (rc)
-               printk(KERN_ALERT PFX "register_device failed, rc = %d\n", rc);
+               printk(KERN_ERR PFX "register_device failed, rc = %d\n", rc);
        else
                set_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic);
 }
@@ -1790,52 +1787,21 @@ static void bnx2fc_ulp_init(struct cnic_dev *dev)
 
 static int bnx2fc_disable(struct net_device *netdev)
 {
-       struct bnx2fc_hba *hba;
-       struct net_device *phys_dev;
-       struct ethtool_drvinfo drvinfo;
+       struct bnx2fc_interface *interface;
        int rc = 0;
 
        rtnl_lock();
-
        mutex_lock(&bnx2fc_dev_lock);
 
-       /* obtain physical netdev */
-       if (netdev->priv_flags & IFF_802_1Q_VLAN)
-               phys_dev = vlan_dev_real_dev(netdev);
-       else {
-               printk(KERN_ERR PFX "Not a vlan device\n");
-               rc = -ENODEV;
-               goto nodev;
-       }
-
-       /* verify if the physical device is a netxtreme2 device */
-       if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) {
-               memset(&drvinfo, 0, sizeof(drvinfo));
-               phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo);
-               if (strcmp(drvinfo.driver, "bnx2x")) {
-                       printk(KERN_ERR PFX "Not a netxtreme2 device\n");
-                       rc = -ENODEV;
-                       goto nodev;
-               }
-       } else {
-               printk(KERN_ERR PFX "unable to obtain drv_info\n");
-               rc = -ENODEV;
-               goto nodev;
-       }
-
-       printk(KERN_ERR PFX "phys_dev is netxtreme2 device\n");
-
-       /* obtain hba and initialize rest of the structure */
-       hba = bnx2fc_hba_lookup(phys_dev);
-       if (!hba || !hba->ctlr.lp) {
+       interface = bnx2fc_interface_lookup(netdev);
+       if (!interface || !interface->ctlr.lp) {
                rc = -ENODEV;
-               printk(KERN_ERR PFX "bnx2fc_disable: hba or lport not found\n");
+               printk(KERN_ERR PFX "bnx2fc_disable: interface or lport not found\n");
        } else {
-               fcoe_ctlr_link_down(&hba->ctlr);
-               fcoe_clean_pending_queue(hba->ctlr.lp);
+               fcoe_ctlr_link_down(&interface->ctlr);
+               fcoe_clean_pending_queue(interface->ctlr.lp);
        }
 
-nodev:
        mutex_unlock(&bnx2fc_dev_lock);
        rtnl_unlock();
        return rc;
@@ -1844,48 +1810,19 @@ nodev:
 
 static int bnx2fc_enable(struct net_device *netdev)
 {
-       struct bnx2fc_hba *hba;
-       struct net_device *phys_dev;
-       struct ethtool_drvinfo drvinfo;
+       struct bnx2fc_interface *interface;
        int rc = 0;
 
        rtnl_lock();
-
-       BNX2FC_MISC_DBG("Entered %s\n", __func__);
        mutex_lock(&bnx2fc_dev_lock);
 
-       /* obtain physical netdev */
-       if (netdev->priv_flags & IFF_802_1Q_VLAN)
-               phys_dev = vlan_dev_real_dev(netdev);
-       else {
-               printk(KERN_ERR PFX "Not a vlan device\n");
-               rc = -ENODEV;
-               goto nodev;
-       }
-       /* verify if the physical device is a netxtreme2 device */
-       if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) {
-               memset(&drvinfo, 0, sizeof(drvinfo));
-               phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo);
-               if (strcmp(drvinfo.driver, "bnx2x")) {
-                       printk(KERN_ERR PFX "Not a netxtreme2 device\n");
-                       rc = -ENODEV;
-                       goto nodev;
-               }
-       } else {
-               printk(KERN_ERR PFX "unable to obtain drv_info\n");
+       interface = bnx2fc_interface_lookup(netdev);
+       if (!interface || !interface->ctlr.lp) {
                rc = -ENODEV;
-               goto nodev;
-       }
-
-       /* obtain hba and initialize rest of the structure */
-       hba = bnx2fc_hba_lookup(phys_dev);
-       if (!hba || !hba->ctlr.lp) {
-               rc = -ENODEV;
-               printk(KERN_ERR PFX "bnx2fc_enable: hba or lport not found\n");
-       } else if (!bnx2fc_link_ok(hba->ctlr.lp))
-               fcoe_ctlr_link_up(&hba->ctlr);
+               printk(KERN_ERR PFX "bnx2fc_enable: interface or lport not found\n");
+       } else if (!bnx2fc_link_ok(interface->ctlr.lp))
+               fcoe_ctlr_link_up(&interface->ctlr);
 
-nodev:
        mutex_unlock(&bnx2fc_dev_lock);
        rtnl_unlock();
        return rc;
@@ -1903,6 +1840,7 @@ nodev:
  */
 static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
 {
+       struct bnx2fc_interface *interface;
        struct bnx2fc_hba *hba;
        struct net_device *phys_dev;
        struct fc_lport *lport;
@@ -1938,7 +1876,7 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
        if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) {
                memset(&drvinfo, 0, sizeof(drvinfo));
                phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo);
-               if (strcmp(drvinfo.driver, "bnx2x")) {
+               if (strncmp(drvinfo.driver, "bnx2x", strlen("bnx2x"))) {
                        printk(KERN_ERR PFX "Not a netxtreme2 device\n");
                        rc = -EINVAL;
                        goto netdev_err;
@@ -1949,7 +1887,7 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
                goto netdev_err;
        }
 
-       /* obtain hba and initialize rest of the structure */
+       /* obtain interface and initialize rest of the structure */
        hba = bnx2fc_hba_lookup(phys_dev);
        if (!hba) {
                rc = -ENODEV;
@@ -1957,67 +1895,61 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
                goto netdev_err;
        }
 
-       if (!test_bit(BNX2FC_FW_INIT_DONE, &hba->init_done)) {
-               rc = bnx2fc_fw_init(hba);
-               if (rc)
-                       goto netdev_err;
-       }
-
-       if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
+       if (bnx2fc_interface_lookup(netdev)) {
                rc = -EEXIST;
                goto netdev_err;
        }
 
-       /* update netdev with vlan netdev */
-       hba->netdev = netdev;
-       hba->vlan_id = vlan_id;
-       hba->vlan_enabled = 1;
-
-       rc = bnx2fc_interface_setup(hba, fip_mode);
-       if (rc) {
-               printk(KERN_ERR PFX "bnx2fc_interface_setup failed\n");
+       interface = bnx2fc_interface_create(hba, netdev, fip_mode);
+       if (!interface) {
+               printk(KERN_ERR PFX "bnx2fc_interface_create failed\n");
                goto ifput_err;
        }
 
-       hba->timer_work_queue =
+       interface->vlan_id = vlan_id;
+       interface->vlan_enabled = 1;
+
+       interface->timer_work_queue =
                        create_singlethread_workqueue("bnx2fc_timer_wq");
-       if (!hba->timer_work_queue) {
+       if (!interface->timer_work_queue) {
                printk(KERN_ERR PFX "ulp_init could not create timer_wq\n");
                rc = -EINVAL;
                goto ifput_err;
        }
 
-       lport = bnx2fc_if_create(hba, &hba->pcidev->dev, 0);
+       lport = bnx2fc_if_create(interface, &interface->hba->pcidev->dev, 0);
        if (!lport) {
                printk(KERN_ERR PFX "Failed to create interface (%s)\n",
                        netdev->name);
-               bnx2fc_netdev_cleanup(hba);
+               bnx2fc_netdev_cleanup(interface);
                rc = -EINVAL;
                goto if_create_err;
        }
 
+       /* Add interface to if_list */
+       list_add_tail(&interface->list, &if_list);
+
        lport->boot_time = jiffies;
 
        /* Make this master N_port */
-       hba->ctlr.lp = lport;
+       interface->ctlr.lp = lport;
 
-       set_bit(BNX2FC_CREATE_DONE, &hba->init_done);
-       printk(KERN_ERR PFX "create: START DISC\n");
-       bnx2fc_start_disc(hba);
+       BNX2FC_HBA_DBG(lport, "create: START DISC\n");
+       bnx2fc_start_disc(interface);
        /*
         * Release from kref_init in bnx2fc_interface_setup, on success
         * lport should be holding a reference taken in bnx2fc_if_create
         */
-       bnx2fc_interface_put(hba);
+       bnx2fc_interface_put(interface);
        /* put netdev that was held while calling dev_get_by_name */
        mutex_unlock(&bnx2fc_dev_lock);
        rtnl_unlock();
        return 0;
 
 if_create_err:
-       destroy_workqueue(hba->timer_work_queue);
+       destroy_workqueue(interface->timer_work_queue);
 ifput_err:
-       bnx2fc_interface_put(hba);
+       bnx2fc_interface_put(interface);
 netdev_err:
        module_put(THIS_MODULE);
 mod_err:
@@ -2027,7 +1959,7 @@ mod_err:
 }
 
 /**
- * bnx2fc_find_hba_for_cnic - maps cnic instance to bnx2fc adapter instance
+ * bnx2fc_find_hba_for_cnic - maps cnic instance to bnx2fc hba instance
  *
  * @cnic:      Pointer to cnic device instance
  *
@@ -2047,19 +1979,30 @@ static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic)
        return NULL;
 }
 
-static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev)
+static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device
+                                                       *netdev)
+{
+       struct bnx2fc_interface *interface;
+
+       /* Called with bnx2fc_dev_lock held */
+       list_for_each_entry(interface, &if_list, list) {
+               if (interface->netdev == netdev)
+                       return interface;
+       }
+       return NULL;
+}
+
+static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device
+                                                     *phys_dev)
 {
-       struct list_head *list;
-       struct list_head *temp;
        struct bnx2fc_hba *hba;
 
        /* Called with bnx2fc_dev_lock held */
-       list_for_each_safe(list, temp, &adapter_list) {
-               hba = (struct bnx2fc_hba *)list;
+       list_for_each_entry(hba, &adapter_list, list) {
                if (hba->phys_dev == phys_dev)
                        return hba;
        }
-       printk(KERN_ERR PFX "hba_lookup: hba NULL\n");
+       printk(KERN_ERR PFX "adapter_lookup: hba NULL\n");
        return NULL;
 }
 
@@ -2071,6 +2014,8 @@ static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev)
 static void bnx2fc_ulp_exit(struct cnic_dev *dev)
 {
        struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface, *tmp;
+       struct fc_lport *lport;
 
        BNX2FC_MISC_DBG("Entered bnx2fc_ulp_exit\n");
 
@@ -2089,13 +2034,20 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev)
                return;
        }
 
-       list_del_init(&hba->link);
+       list_del_init(&hba->list);
        adapter_count--;
 
-       if (test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
+       list_for_each_entry_safe(interface, tmp, &if_list, list) {
                /* destroy not called yet, move to quiesced list */
-               bnx2fc_netdev_cleanup(hba);
-               bnx2fc_if_destroy(hba->ctlr.lp);
+               if (interface->hba == hba) {
+                       bnx2fc_netdev_cleanup(interface);
+                       bnx2fc_stop(interface);
+
+                       list_del(&interface->list);
+                       lport = interface->ctlr.lp;
+                       bnx2fc_interface_put(interface);
+                       bnx2fc_if_destroy(lport, hba);
+               }
        }
        mutex_unlock(&bnx2fc_dev_lock);
 
@@ -2103,7 +2055,7 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev)
        /* unregister cnic device */
        if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic))
                hba->cnic->unregister_device(hba->cnic, CNIC_ULP_FCOE);
-       bnx2fc_interface_destroy(hba);
+       bnx2fc_hba_destroy(hba);
 }
 
 /**
@@ -2259,6 +2211,7 @@ static int __init bnx2fc_mod_init(void)
        }
 
        INIT_LIST_HEAD(&adapter_list);
+       INIT_LIST_HEAD(&if_list);
        mutex_init(&bnx2fc_dev_lock);
        adapter_count = 0;
 
@@ -2336,16 +2289,17 @@ static void __exit bnx2fc_mod_exit(void)
        mutex_unlock(&bnx2fc_dev_lock);
 
        /* Unregister with cnic */
-       list_for_each_entry_safe(hba, next, &to_be_deleted, link) {
-               list_del_init(&hba->link);
-               printk(KERN_ERR PFX "MOD_EXIT:destroy hba = 0x%p, kref = %d\n",
-                       hba, atomic_read(&hba->kref.refcount));
+       list_for_each_entry_safe(hba, next, &to_be_deleted, list) {
+               list_del_init(&hba->list);
+               printk(KERN_ERR PFX "MOD_EXIT:destroy hba = 0x%p\n",
+                      hba);
                bnx2fc_ulp_stop(hba);
                /* unregister cnic device */
                if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED,
                                       &hba->reg_with_cnic))
-                       hba->cnic->unregister_device(hba->cnic, CNIC_ULP_FCOE);
-               bnx2fc_interface_destroy(hba);
+                       hba->cnic->unregister_device(hba->cnic,
+                                                        CNIC_ULP_FCOE);
+               bnx2fc_hba_destroy(hba);
        }
        cnic_unregister_driver(CNIC_ULP_FCOE);
 
index 09bdd9b88d1aae0d14a817d807a1902cce3cf961..72cfb14acd3aacf0ea6ca43f88f0846ddca08004 100644 (file)
@@ -2,7 +2,7 @@
  * This file contains the code that low level functions that interact
  * with 57712 FCoE firmware.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 Broadcom 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
@@ -23,7 +23,7 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
                                                struct fcoe_kcqe *ofld_kcqe);
 static void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code);
 static void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba,
-                                       struct fcoe_kcqe *conn_destroy);
+                                       struct fcoe_kcqe *destroy_kcqe);
 
 int bnx2fc_send_stat_req(struct bnx2fc_hba *hba)
 {
@@ -67,7 +67,7 @@ int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba)
        int rc = 0;
 
        if (!hba->cnic) {
-               printk(KERN_ALERT PFX "hba->cnic NULL during fcoe fw init\n");
+               printk(KERN_ERR PFX "hba->cnic NULL during fcoe fw init\n");
                return -ENODEV;
        }
 
@@ -103,6 +103,7 @@ int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba)
        fcoe_init2.hsi_major_version = FCOE_HSI_MAJOR_VERSION;
        fcoe_init2.hsi_minor_version = FCOE_HSI_MINOR_VERSION;
 
+
        fcoe_init2.hash_tbl_pbl_addr_lo = (u32) hba->hash_tbl_pbl_dma;
        fcoe_init2.hash_tbl_pbl_addr_hi = (u32)
                                           ((u64) hba->hash_tbl_pbl_dma >> 32);
@@ -165,7 +166,8 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
                                        struct bnx2fc_rport *tgt)
 {
        struct fc_lport *lport = port->lport;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct kwqe *kwqe_arr[4];
        struct fcoe_kwqe_conn_offload1 ofld_req1;
        struct fcoe_kwqe_conn_offload2 ofld_req2;
@@ -227,7 +229,7 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
        ofld_req3.hdr.flags =
                (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
 
-       ofld_req3.vlan_tag = hba->vlan_id <<
+       ofld_req3.vlan_tag = interface->vlan_id <<
                                FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT;
        ofld_req3.vlan_tag |= 3 << FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT;
 
@@ -277,8 +279,20 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
        ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_SEQC) ? 1 : 0) <<
                             FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT);
 
+       /*
+        * Info from PRLI response, this info is used for sequence level error
+        * recovery support
+        */
+       if (tgt->dev_type == TYPE_TAPE) {
+               ofld_req3.flags |= 1 <<
+                                   FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT;
+               ofld_req3.flags |= (((rdata->flags & FC_RP_FLAGS_REC_SUPPORTED)
+                                   ? 1 : 0) <<
+                                   FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT);
+       }
+
        /* vlan flag */
-       ofld_req3.flags |= (hba->vlan_enabled <<
+       ofld_req3.flags |= (interface->vlan_enabled <<
                            FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT);
 
        /* C2_VALID and ACK flags are not set as they are not suppported */
@@ -300,12 +314,13 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port,
        ofld_req4.src_mac_addr_mid[1] =  port->data_src_addr[2];
        ofld_req4.src_mac_addr_hi[0] =  port->data_src_addr[1];
        ofld_req4.src_mac_addr_hi[1] =  port->data_src_addr[0];
-       ofld_req4.dst_mac_addr_lo[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
-       ofld_req4.dst_mac_addr_lo[1] =  hba->ctlr.dest_addr[4];
-       ofld_req4.dst_mac_addr_mid[0] =  hba->ctlr.dest_addr[3];
-       ofld_req4.dst_mac_addr_mid[1] =  hba->ctlr.dest_addr[2];
-       ofld_req4.dst_mac_addr_hi[0] =  hba->ctlr.dest_addr[1];
-       ofld_req4.dst_mac_addr_hi[1] =  hba->ctlr.dest_addr[0];
+       ofld_req4.dst_mac_addr_lo[0] =  interface->ctlr.dest_addr[5];
+                                                       /* fcf mac */
+       ofld_req4.dst_mac_addr_lo[1] =  interface->ctlr.dest_addr[4];
+       ofld_req4.dst_mac_addr_mid[0] =  interface->ctlr.dest_addr[3];
+       ofld_req4.dst_mac_addr_mid[1] =  interface->ctlr.dest_addr[2];
+       ofld_req4.dst_mac_addr_hi[0] =  interface->ctlr.dest_addr[1];
+       ofld_req4.dst_mac_addr_hi[1] =  interface->ctlr.dest_addr[0];
 
        ofld_req4.lcq_addr_lo = (u32) tgt->lcq_dma;
        ofld_req4.lcq_addr_hi = (u32)((u64) tgt->lcq_dma >> 32);
@@ -335,7 +350,8 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port,
                                        struct bnx2fc_rport *tgt)
 {
        struct kwqe *kwqe_arr[2];
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct fcoe_kwqe_conn_enable_disable enbl_req;
        struct fc_lport *lport = port->lport;
        struct fc_rport *rport = tgt->rport;
@@ -358,12 +374,12 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port,
        enbl_req.src_mac_addr_hi[1] =  port->data_src_addr[0];
        memcpy(tgt->src_addr, port->data_src_addr, ETH_ALEN);
 
-       enbl_req.dst_mac_addr_lo[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
-       enbl_req.dst_mac_addr_lo[1] =  hba->ctlr.dest_addr[4];
-       enbl_req.dst_mac_addr_mid[0] =  hba->ctlr.dest_addr[3];
-       enbl_req.dst_mac_addr_mid[1] =  hba->ctlr.dest_addr[2];
-       enbl_req.dst_mac_addr_hi[0] =  hba->ctlr.dest_addr[1];
-       enbl_req.dst_mac_addr_hi[1] =  hba->ctlr.dest_addr[0];
+       enbl_req.dst_mac_addr_lo[0] =  interface->ctlr.dest_addr[5];
+       enbl_req.dst_mac_addr_lo[1] =  interface->ctlr.dest_addr[4];
+       enbl_req.dst_mac_addr_mid[0] =  interface->ctlr.dest_addr[3];
+       enbl_req.dst_mac_addr_mid[1] =  interface->ctlr.dest_addr[2];
+       enbl_req.dst_mac_addr_hi[0] =  interface->ctlr.dest_addr[1];
+       enbl_req.dst_mac_addr_hi[1] =  interface->ctlr.dest_addr[0];
 
        port_id = fc_host_port_id(lport->host);
        if (port_id != tgt->sid) {
@@ -379,10 +395,10 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port,
        enbl_req.d_id[0] = (port_id & 0x000000FF);
        enbl_req.d_id[1] = (port_id & 0x0000FF00) >> 8;
        enbl_req.d_id[2] = (port_id & 0x00FF0000) >> 16;
-       enbl_req.vlan_tag = hba->vlan_id <<
+       enbl_req.vlan_tag = interface->vlan_id <<
                                FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT;
        enbl_req.vlan_tag |= 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT;
-       enbl_req.vlan_flag = hba->vlan_enabled;
+       enbl_req.vlan_flag = interface->vlan_enabled;
        enbl_req.context_id = tgt->context_id;
        enbl_req.conn_id = tgt->fcoe_conn_id;
 
@@ -402,7 +418,8 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port,
 int bnx2fc_send_session_disable_req(struct fcoe_port *port,
                                    struct bnx2fc_rport *tgt)
 {
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct fcoe_kwqe_conn_enable_disable disable_req;
        struct kwqe *kwqe_arr[2];
        struct fc_rport *rport = tgt->rport;
@@ -423,12 +440,12 @@ int bnx2fc_send_session_disable_req(struct fcoe_port *port,
        disable_req.src_mac_addr_hi[0] =  tgt->src_addr[1];
        disable_req.src_mac_addr_hi[1] =  tgt->src_addr[0];
 
-       disable_req.dst_mac_addr_lo[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
-       disable_req.dst_mac_addr_lo[1] =  hba->ctlr.dest_addr[4];
-       disable_req.dst_mac_addr_mid[0] =  hba->ctlr.dest_addr[3];
-       disable_req.dst_mac_addr_mid[1] =  hba->ctlr.dest_addr[2];
-       disable_req.dst_mac_addr_hi[0] =  hba->ctlr.dest_addr[1];
-       disable_req.dst_mac_addr_hi[1] =  hba->ctlr.dest_addr[0];
+       disable_req.dst_mac_addr_lo[0] =  interface->ctlr.dest_addr[5];
+       disable_req.dst_mac_addr_lo[1] =  interface->ctlr.dest_addr[4];
+       disable_req.dst_mac_addr_mid[0] =  interface->ctlr.dest_addr[3];
+       disable_req.dst_mac_addr_mid[1] =  interface->ctlr.dest_addr[2];
+       disable_req.dst_mac_addr_hi[0] =  interface->ctlr.dest_addr[1];
+       disable_req.dst_mac_addr_hi[1] =  interface->ctlr.dest_addr[0];
 
        port_id = tgt->sid;
        disable_req.s_id[0] = (port_id & 0x000000FF);
@@ -442,11 +459,11 @@ int bnx2fc_send_session_disable_req(struct fcoe_port *port,
        disable_req.d_id[2] = (port_id & 0x00FF0000) >> 16;
        disable_req.context_id = tgt->context_id;
        disable_req.conn_id = tgt->fcoe_conn_id;
-       disable_req.vlan_tag = hba->vlan_id <<
+       disable_req.vlan_tag = interface->vlan_id <<
                                FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT;
        disable_req.vlan_tag |=
                        3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT;
-       disable_req.vlan_flag = hba->vlan_enabled;
+       disable_req.vlan_flag = interface->vlan_enabled;
 
        kwqe_arr[0] = (struct kwqe *) &disable_req;
 
@@ -525,7 +542,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
 {
        struct fcoe_port *port = tgt->port;
        struct fc_lport *lport = port->lport;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
        struct bnx2fc_unsol_els *unsol_els;
        struct fc_frame_header *fh;
        struct fc_frame *fp;
@@ -586,7 +603,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
                fr_eof(fp) = FC_EOF_T;
                fr_crc(fp) = cpu_to_le32(~crc);
                unsol_els->lport = lport;
-               unsol_els->hba = hba;
+               unsol_els->hba = interface->hba;
                unsol_els->fp = fp;
                INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work);
                queue_work(bnx2fc_wq, &unsol_els->unsol_els_work);
@@ -608,9 +625,12 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
        u32 frame_len, len;
        struct bnx2fc_cmd *io_req = NULL;
        struct fcoe_task_ctx_entry *task, *task_page;
-       struct bnx2fc_hba *hba = tgt->port->priv;
+       struct bnx2fc_interface *interface = tgt->port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        int task_idx, index;
        int rc = 0;
+       u64 err_warn_bit_map;
+       u8 err_warn = 0xff;
 
 
        BNX2FC_TGT_DBG(tgt, "Entered UNSOL COMPLETION wqe = 0x%x\n", wqe);
@@ -673,39 +693,43 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
                BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x\n",
                        err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
 
-               bnx2fc_return_rqe(tgt, 1);
 
                if (xid > BNX2FC_MAX_XID) {
                        BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n",
                                   xid);
-                       spin_unlock_bh(&tgt->tgt_lock);
-                       break;
+                       goto ret_err_rqe;
                }
 
                task_idx = xid / BNX2FC_TASKS_PER_PAGE;
                index = xid % BNX2FC_TASKS_PER_PAGE;
                task_page = (struct fcoe_task_ctx_entry *)
-                                               hba->task_ctx[task_idx];
+                                       hba->task_ctx[task_idx];
                task = &(task_page[index]);
 
                io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
-               if (!io_req) {
-                       spin_unlock_bh(&tgt->tgt_lock);
-                       break;
-               }
+               if (!io_req)
+                       goto ret_err_rqe;
 
                if (io_req->cmd_type != BNX2FC_SCSI_CMD) {
                        printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n");
-                       spin_unlock_bh(&tgt->tgt_lock);
-                       break;
+                       goto ret_err_rqe;
                }
 
                if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP,
                                       &io_req->req_flags)) {
                        BNX2FC_IO_DBG(io_req, "unsol_err: cleanup in "
                                            "progress.. ignore unsol err\n");
-                       spin_unlock_bh(&tgt->tgt_lock);
-                       break;
+                       goto ret_err_rqe;
+               }
+
+               err_warn_bit_map = (u64)
+                       ((u64)err_entry->data.err_warn_bitmap_hi << 32) |
+                       (u64)err_entry->data.err_warn_bitmap_lo;
+               for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) {
+                       if (err_warn_bit_map & (u64)((u64)1 << i)) {
+                               err_warn = i;
+                               break;
+                       }
                }
 
                /*
@@ -715,26 +739,61 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
                 * logging out the target, when the ABTS eventually
                 * times out.
                 */
-               if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS,
-                                     &io_req->req_flags)) {
-                       /*
-                        * Cancel the timeout_work, as we received IO
-                        * completion with FW error.
-                        */
-                       if (cancel_delayed_work(&io_req->timeout_work))
-                               kref_put(&io_req->refcount,
-                                        bnx2fc_cmd_release); /* timer hold */
-
-                       rc = bnx2fc_initiate_abts(io_req);
-                       if (rc != SUCCESS) {
-                               BNX2FC_IO_DBG(io_req, "err_warn: initiate_abts "
-                                       "failed. issue cleanup\n");
-                               rc = bnx2fc_initiate_cleanup(io_req);
-                               BUG_ON(rc);
-                       }
-               } else
+               if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) {
                        printk(KERN_ERR PFX "err_warn: io_req (0x%x) already "
                                            "in ABTS processing\n", xid);
+                       goto ret_err_rqe;
+               }
+               BNX2FC_TGT_DBG(tgt, "err = 0x%x\n", err_warn);
+               if (tgt->dev_type != TYPE_TAPE)
+                       goto skip_rec;
+               switch (err_warn) {
+               case FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION:
+               case FCOE_ERROR_CODE_DATA_OOO_RO:
+               case FCOE_ERROR_CODE_COMMON_INCORRECT_SEQ_CNT:
+               case FCOE_ERROR_CODE_DATA_SOFI3_SEQ_ACTIVE_SET:
+               case FCOE_ERROR_CODE_FCP_RSP_OPENED_SEQ:
+               case FCOE_ERROR_CODE_DATA_SOFN_SEQ_ACTIVE_RESET:
+                       BNX2FC_TGT_DBG(tgt, "REC TOV popped for xid - 0x%x\n",
+                                  xid);
+                       memset(&io_req->err_entry, 0,
+                              sizeof(struct fcoe_err_report_entry));
+                       memcpy(&io_req->err_entry, err_entry,
+                              sizeof(struct fcoe_err_report_entry));
+                       if (!test_bit(BNX2FC_FLAG_SRR_SENT,
+                                     &io_req->req_flags)) {
+                               spin_unlock_bh(&tgt->tgt_lock);
+                               rc = bnx2fc_send_rec(io_req);
+                               spin_lock_bh(&tgt->tgt_lock);
+
+                               if (rc)
+                                       goto skip_rec;
+                       } else
+                               printk(KERN_ERR PFX "SRR in progress\n");
+                       goto ret_err_rqe;
+                       break;
+               default:
+                       break;
+               }
+
+skip_rec:
+               set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags);
+               /*
+                * Cancel the timeout_work, as we received IO
+                * completion with FW error.
+                */
+               if (cancel_delayed_work(&io_req->timeout_work))
+                       kref_put(&io_req->refcount, bnx2fc_cmd_release);
+
+               rc = bnx2fc_initiate_abts(io_req);
+               if (rc != SUCCESS) {
+                       printk(KERN_ERR PFX "err_warn: initiate_abts "
+                               "failed xid = 0x%x. issue cleanup\n",
+                               io_req->xid);
+                       bnx2fc_initiate_cleanup(io_req);
+               }
+ret_err_rqe:
+               bnx2fc_return_rqe(tgt, 1);
                spin_unlock_bh(&tgt->tgt_lock);
                break;
 
@@ -755,6 +814,47 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
                BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x",
                        err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
 
+               if (xid > BNX2FC_MAX_XID) {
+                       BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", xid);
+                       goto ret_warn_rqe;
+               }
+
+               err_warn_bit_map = (u64)
+                       ((u64)err_entry->data.err_warn_bitmap_hi << 32) |
+                       (u64)err_entry->data.err_warn_bitmap_lo;
+               for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) {
+                       if (err_warn_bit_map & (u64) (1 << i)) {
+                               err_warn = i;
+                               break;
+                       }
+               }
+               BNX2FC_TGT_DBG(tgt, "warn = 0x%x\n", err_warn);
+
+               task_idx = xid / BNX2FC_TASKS_PER_PAGE;
+               index = xid % BNX2FC_TASKS_PER_PAGE;
+               task_page = (struct fcoe_task_ctx_entry *)
+                            interface->hba->task_ctx[task_idx];
+               task = &(task_page[index]);
+               io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
+               if (!io_req)
+                       goto ret_warn_rqe;
+
+               if (io_req->cmd_type != BNX2FC_SCSI_CMD) {
+                       printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n");
+                       goto ret_warn_rqe;
+               }
+
+               memset(&io_req->err_entry, 0,
+                      sizeof(struct fcoe_err_report_entry));
+               memcpy(&io_req->err_entry, err_entry,
+                      sizeof(struct fcoe_err_report_entry));
+
+               if (err_warn == FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION)
+                       /* REC_TOV is not a warning code */
+                       BUG_ON(1);
+               else
+                       BNX2FC_TGT_DBG(tgt, "Unsolicited warning\n");
+ret_warn_rqe:
                bnx2fc_return_rqe(tgt, 1);
                spin_unlock_bh(&tgt->tgt_lock);
                break;
@@ -770,7 +870,8 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
        struct fcoe_task_ctx_entry *task;
        struct fcoe_task_ctx_entry *task_page;
        struct fcoe_port *port = tgt->port;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct bnx2fc_cmd *io_req;
        int task_idx, index;
        u16 xid;
@@ -781,7 +882,7 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
        spin_lock_bh(&tgt->tgt_lock);
        xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
        if (xid >= BNX2FC_MAX_TASKS) {
-               printk(KERN_ALERT PFX "ERROR:xid out of range\n");
+               printk(KERN_ERR PFX "ERROR:xid out of range\n");
                spin_unlock_bh(&tgt->tgt_lock);
                return;
        }
@@ -861,6 +962,13 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
                kref_put(&io_req->refcount, bnx2fc_cmd_release);
                break;
 
+       case BNX2FC_SEQ_CLEANUP:
+               BNX2FC_IO_DBG(io_req, "cq_compl(0x%x) - seq cleanup resp\n",
+                             io_req->xid);
+               bnx2fc_process_seq_cleanup_compl(io_req, task, rx_state);
+               kref_put(&io_req->refcount, bnx2fc_cmd_release);
+               break;
+
        default:
                printk(KERN_ERR PFX "Invalid cmd_type %d\n", cmd_type);
                break;
@@ -962,8 +1070,10 @@ unlock:
                                1 - tgt->cq_curr_toggle_bit;
                }
        }
-       bnx2fc_arm_cq(tgt);
-       atomic_add(num_free_sqes, &tgt->free_sqes);
+       if (num_free_sqes) {
+               bnx2fc_arm_cq(tgt);
+               atomic_add(num_free_sqes, &tgt->free_sqes);
+       }
        spin_unlock_bh(&tgt->cq_lock);
        return 0;
 }
@@ -983,7 +1093,7 @@ static void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba,
        struct bnx2fc_rport *tgt = hba->tgt_ofld_list[conn_id];
 
        if (!tgt) {
-               printk(KERN_ALERT PFX "conn_id 0x%x not valid\n", conn_id);
+               printk(KERN_ERR PFX "conn_id 0x%x not valid\n", conn_id);
                return;
        }
 
@@ -1004,6 +1114,7 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba,
 {
        struct bnx2fc_rport             *tgt;
        struct fcoe_port                *port;
+       struct bnx2fc_interface         *interface;
        u32                             conn_id;
        u32                             context_id;
        int                             rc;
@@ -1018,8 +1129,9 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba,
        BNX2FC_TGT_DBG(tgt, "Entered ofld compl - context_id = 0x%x\n",
                ofld_kcqe->fcoe_conn_context_id);
        port = tgt->port;
-       if (hba != tgt->port->priv) {
-               printk(KERN_ALERT PFX "ERROR:ofld_cmpl: HBA mis-match\n");
+       interface = tgt->port->priv;
+       if (hba != interface->hba) {
+               printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mis-match\n");
                goto ofld_cmpl_err;
        }
        /*
@@ -1040,7 +1152,7 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba,
                /* now enable the session */
                rc = bnx2fc_send_session_enable_req(port, tgt);
                if (rc) {
-                       printk(KERN_ALERT PFX "enable session failed\n");
+                       printk(KERN_ERR PFX "enable session failed\n");
                        goto ofld_cmpl_err;
                }
        }
@@ -1063,6 +1175,7 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
                                                struct fcoe_kcqe *ofld_kcqe)
 {
        struct bnx2fc_rport             *tgt;
+       struct bnx2fc_interface         *interface;
        u32                             conn_id;
        u32                             context_id;
 
@@ -1070,7 +1183,7 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
        conn_id = ofld_kcqe->fcoe_conn_id;
        tgt = hba->tgt_ofld_list[conn_id];
        if (!tgt) {
-               printk(KERN_ALERT PFX "ERROR:enbl_cmpl: No pending ofld req\n");
+               printk(KERN_ERR PFX "ERROR:enbl_cmpl: No pending ofld req\n");
                return;
        }
 
@@ -1082,16 +1195,17 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
         * and enable
         */
        if (tgt->context_id != context_id) {
-               printk(KERN_ALERT PFX "context id mis-match\n");
+               printk(KERN_ERR PFX "context id mis-match\n");
                return;
        }
-       if (hba != tgt->port->priv) {
-               printk(KERN_ALERT PFX "bnx2fc-enbl_cmpl: HBA mis-match\n");
+       interface = tgt->port->priv;
+       if (hba != interface->hba) {
+               printk(KERN_ERR PFX "bnx2fc-enbl_cmpl: HBA mis-match\n");
                goto enbl_cmpl_err;
        }
-       if (ofld_kcqe->completion_status) {
+       if (ofld_kcqe->completion_status)
                goto enbl_cmpl_err;
-       else {
+       else {
                /* enable successful - rport ready for issuing IOs */
                set_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags);
                set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags);
@@ -1114,14 +1228,14 @@ static void bnx2fc_process_conn_disable_cmpl(struct bnx2fc_hba *hba,
        conn_id = disable_kcqe->fcoe_conn_id;
        tgt = hba->tgt_ofld_list[conn_id];
        if (!tgt) {
-               printk(KERN_ALERT PFX "ERROR: disable_cmpl: No disable req\n");
+               printk(KERN_ERR PFX "ERROR: disable_cmpl: No disable req\n");
                return;
        }
 
        BNX2FC_TGT_DBG(tgt, PFX "disable_cmpl: conn_id %d\n", conn_id);
 
        if (disable_kcqe->completion_status) {
-               printk(KERN_ALERT PFX "ERROR: Disable failed with cmpl status %d\n",
+               printk(KERN_ERR PFX "Disable failed with cmpl status %d\n",
                        disable_kcqe->completion_status);
                return;
        } else {
@@ -1143,14 +1257,14 @@ static void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba,
        conn_id = destroy_kcqe->fcoe_conn_id;
        tgt = hba->tgt_ofld_list[conn_id];
        if (!tgt) {
-               printk(KERN_ALERT PFX "destroy_cmpl: No destroy req\n");
+               printk(KERN_ERR PFX "destroy_cmpl: No destroy req\n");
                return;
        }
 
        BNX2FC_TGT_DBG(tgt, "destroy_cmpl: conn_id %d\n", conn_id);
 
        if (destroy_kcqe->completion_status) {
-               printk(KERN_ALERT PFX "Destroy conn failed, cmpl status %d\n",
+               printk(KERN_ERR PFX "Destroy conn failed, cmpl status %d\n",
                        destroy_kcqe->completion_status);
                return;
        } else {
@@ -1182,6 +1296,7 @@ static void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code)
                break;
        case FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION:
                printk(KERN_ERR PFX "init failure due to HSI mismatch\n");
+               break;
        default:
                printk(KERN_ERR PFX "Unknown Error code %d\n", err_code);
        }
@@ -1240,7 +1355,7 @@ void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[],
                        } else {
                                printk(KERN_ERR PFX "DESTROY success\n");
                        }
-                       hba->flags |= BNX2FC_FLAG_DESTROY_CMPL;
+                       set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags);
                        wake_up_interruptible(&hba->destroy_wait);
                        break;
 
@@ -1262,7 +1377,7 @@ void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[],
                case FCOE_KCQE_OPCODE_FCOE_ERROR:
                        /* fall thru */
                default:
-                       printk(KERN_ALERT PFX "unknown opcode 0x%x\n",
+                       printk(KERN_ERR PFX "unknown opcode 0x%x\n",
                                                                kcqe->op_code);
                }
        }
@@ -1305,7 +1420,8 @@ int bnx2fc_map_doorbell(struct bnx2fc_rport *tgt)
        struct fcoe_port *port = tgt->port;
        u32 reg_off;
        resource_size_t reg_base;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
 
        reg_base = pci_resource_start(hba->pcidev,
                                        BNX2X_DOORBELL_PCI_BAR);
@@ -1344,6 +1460,96 @@ void bnx2fc_return_rqe(struct bnx2fc_rport *tgt, u8 num_items)
        tgt->conn_db->rq_prod = tgt->rq_prod_idx;
 }
 
+void bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnp_req,
+                                 struct fcoe_task_ctx_entry *task,
+                                 struct bnx2fc_cmd *orig_io_req,
+                                 u32 offset)
+{
+       struct scsi_cmnd *sc_cmd = orig_io_req->sc_cmd;
+       struct bnx2fc_rport *tgt = seq_clnp_req->tgt;
+       struct bnx2fc_interface *interface = tgt->port->priv;
+       struct fcoe_bd_ctx *bd = orig_io_req->bd_tbl->bd_tbl;
+       struct fcoe_task_ctx_entry *orig_task;
+       struct fcoe_task_ctx_entry *task_page;
+       struct fcoe_ext_mul_sges_ctx *sgl;
+       u8 task_type = FCOE_TASK_TYPE_SEQUENCE_CLEANUP;
+       u8 orig_task_type;
+       u16 orig_xid = orig_io_req->xid;
+       u32 context_id = tgt->context_id;
+       u64 phys_addr = (u64)orig_io_req->bd_tbl->bd_tbl_dma;
+       u32 orig_offset = offset;
+       int bd_count;
+       int orig_task_idx, index;
+       int i;
+
+       memset(task, 0, sizeof(struct fcoe_task_ctx_entry));
+
+       if (sc_cmd->sc_data_direction == DMA_TO_DEVICE)
+               orig_task_type = FCOE_TASK_TYPE_WRITE;
+       else
+               orig_task_type = FCOE_TASK_TYPE_READ;
+
+       /* Tx flags */
+       task->txwr_rxrd.const_ctx.tx_flags =
+                               FCOE_TASK_TX_STATE_SEQUENCE_CLEANUP <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT;
+       /* init flags */
+       task->txwr_rxrd.const_ctx.init_flags = task_type <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
+       task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT;
+       task->rxwr_txrd.const_ctx.init_flags = context_id <<
+                               FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT;
+       task->rxwr_txrd.const_ctx.init_flags = context_id <<
+                               FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT;
+
+       task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid;
+
+       task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_seq_cnt = 0;
+       task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_data_offset = offset;
+
+       bd_count = orig_io_req->bd_tbl->bd_valid;
+
+       /* obtain the appropriate bd entry from relative offset */
+       for (i = 0; i < bd_count; i++) {
+               if (offset < bd[i].buf_len)
+                       break;
+               offset -= bd[i].buf_len;
+       }
+       phys_addr += (i * sizeof(struct fcoe_bd_ctx));
+
+       if (orig_task_type == FCOE_TASK_TYPE_WRITE) {
+               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo =
+                               (u32)phys_addr;
+               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi =
+                               (u32)((u64)phys_addr >> 32);
+               task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size =
+                               bd_count;
+               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_off =
+                               offset; /* adjusted offset */
+               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_idx = i;
+       } else {
+               orig_task_idx = orig_xid / BNX2FC_TASKS_PER_PAGE;
+               index = orig_xid % BNX2FC_TASKS_PER_PAGE;
+
+               task_page = (struct fcoe_task_ctx_entry *)
+                            interface->hba->task_ctx[orig_task_idx];
+               orig_task = &(task_page[index]);
+
+               /* Multiple SGEs were used for this IO */
+               sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl;
+               sgl->mul_sgl.cur_sge_addr.lo = (u32)phys_addr;
+               sgl->mul_sgl.cur_sge_addr.hi = (u32)((u64)phys_addr >> 32);
+               sgl->mul_sgl.sgl_size = bd_count;
+               sgl->mul_sgl.cur_sge_off = offset; /*adjusted offset */
+               sgl->mul_sgl.cur_sge_idx = i;
+
+               memset(&task->rxwr_only.rx_seq_ctx, 0,
+                      sizeof(struct fcoe_rx_seq_ctx));
+               task->rxwr_only.rx_seq_ctx.low_exp_ro = orig_offset;
+               task->rxwr_only.rx_seq_ctx.high_exp_ro = orig_offset;
+       }
+}
 void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req,
                              struct fcoe_task_ctx_entry *task,
                              u16 orig_xid)
@@ -1360,7 +1566,12 @@ void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req,
                                FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
        task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT;
-       task->txwr_rxrd.const_ctx.init_flags |=
+       if (tgt->dev_type == TYPE_TAPE)
+               task->txwr_rxrd.const_ctx.init_flags |=
+                               FCOE_TASK_DEV_TYPE_TAPE <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
+       else
+               task->txwr_rxrd.const_ctx.init_flags |=
                                FCOE_TASK_DEV_TYPE_DISK <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
        task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid;
@@ -1420,7 +1631,12 @@ void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req,
        /* init flags */
        task->txwr_rxrd.const_ctx.init_flags = task_type <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
-       task->txwr_rxrd.const_ctx.init_flags |=
+       if (tgt->dev_type == TYPE_TAPE)
+               task->txwr_rxrd.const_ctx.init_flags |=
+                               FCOE_TASK_DEV_TYPE_TAPE <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
+       else
+               task->txwr_rxrd.const_ctx.init_flags |=
                                FCOE_TASK_DEV_TYPE_DISK <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
        task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
@@ -1477,6 +1693,7 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
        struct bnx2fc_rport *tgt = io_req->tgt;
        struct fcoe_cached_sge_ctx *cached_sge;
        struct fcoe_ext_mul_sges_ctx *sgl;
+       int dev_type = tgt->dev_type;
        u64 *fcp_cmnd;
        u64 tmp_fcp_cmnd[4];
        u32 context_id;
@@ -1494,20 +1711,40 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
                task_type = FCOE_TASK_TYPE_READ;
 
        /* Tx only */
+       bd_count = bd_tbl->bd_valid;
        if (task_type == FCOE_TASK_TYPE_WRITE) {
-               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo =
-                               (u32)bd_tbl->bd_tbl_dma;
-               task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi =
-                               (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
-               task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size =
-                               bd_tbl->bd_valid;
+               if ((dev_type == TYPE_DISK) && (bd_count == 1)) {
+                       struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl;
+
+                       task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.lo =
+                                       fcoe_bd_tbl->buf_addr_lo;
+                       task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.hi =
+                                       fcoe_bd_tbl->buf_addr_hi;
+                       task->txwr_only.sgl_ctx.cached_sge.cur_buf_rem =
+                                       fcoe_bd_tbl->buf_len;
+
+                       task->txwr_rxrd.const_ctx.init_flags |= 1 <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT;
+               } else {
+                       task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo =
+                                       (u32)bd_tbl->bd_tbl_dma;
+                       task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi =
+                                       (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
+                       task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size =
+                                       bd_tbl->bd_valid;
+               }
        }
 
        /*Tx Write Rx Read */
        /* Init state to NORMAL */
-       task->txwr_rxrd.const_ctx.init_flags = task_type <<
+       task->txwr_rxrd.const_ctx.init_flags |= task_type <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
-       task->txwr_rxrd.const_ctx.init_flags |=
+       if (dev_type == TYPE_TAPE)
+               task->txwr_rxrd.const_ctx.init_flags |=
+                               FCOE_TASK_DEV_TYPE_TAPE <<
+                               FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
+       else
+               task->txwr_rxrd.const_ctx.init_flags |=
                                FCOE_TASK_DEV_TYPE_DISK <<
                                FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
        task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
@@ -1550,7 +1787,8 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
        cached_sge = &task->rxwr_only.union_ctx.read_info.sgl_ctx.cached_sge;
        sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl;
        bd_count = bd_tbl->bd_valid;
-       if (task_type == FCOE_TASK_TYPE_READ) {
+       if (task_type == FCOE_TASK_TYPE_READ &&
+           dev_type == TYPE_DISK) {
                if (bd_count == 1) {
 
                        struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl;
@@ -1582,6 +1820,11 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req,
                                        (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
                        sgl->mul_sgl.sgl_size = bd_count;
                }
+       } else {
+               sgl->mul_sgl.cur_sge_addr.lo = (u32)bd_tbl->bd_tbl_dma;
+               sgl->mul_sgl.cur_sge_addr.hi =
+                               (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
+               sgl->mul_sgl.sgl_size = bd_count;
        }
 }
 
index 45eba6d609c9a6f8d989941329636b79fd94b19a..6cc3789075bc16fc9a4104b5277b94c40f6faca9 100644 (file)
@@ -1,7 +1,7 @@
 /* bnx2fc_io.c: Broadcom NetXtreme II Linux FCoE offload driver.
  * IO manager and SCSI IO processing.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 Broadcom 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
@@ -18,8 +18,6 @@ static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len,
                           int bd_index);
 static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req);
 static void bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req);
-static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
-                              struct bnx2fc_cmd *io_req);
 static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req);
 static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req);
 static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
@@ -29,10 +27,11 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
 void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req,
                          unsigned int timer_msec)
 {
-       struct bnx2fc_hba *hba = io_req->port->priv;
+       struct bnx2fc_interface *interface = io_req->port->priv;
 
-       if (queue_delayed_work(hba->timer_work_queue, &io_req->timeout_work,
-                                 msecs_to_jiffies(timer_msec)))
+       if (queue_delayed_work(interface->timer_work_queue,
+                              &io_req->timeout_work,
+                              msecs_to_jiffies(timer_msec)))
                kref_get(&io_req->refcount);
 }
 
@@ -217,6 +216,11 @@ static void bnx2fc_scsi_done(struct bnx2fc_cmd *io_req, int err_code)
                return;
 
        BNX2FC_IO_DBG(io_req, "scsi_done. err_code = 0x%x\n", err_code);
+       if (test_bit(BNX2FC_FLAG_CMD_LOST, &io_req->req_flags)) {
+               /* Do not call scsi done for this IO */
+               return;
+       }
+
        bnx2fc_unmap_sg_list(io_req);
        io_req->sc_cmd = NULL;
        if (!sc_cmd) {
@@ -419,8 +423,8 @@ free_cmgr:
 struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type)
 {
        struct fcoe_port *port = tgt->port;
-       struct bnx2fc_hba *hba = port->priv;
-       struct bnx2fc_cmd_mgr *cmd_mgr = hba->cmd_mgr;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_cmd_mgr *cmd_mgr = interface->hba->cmd_mgr;
        struct bnx2fc_cmd *io_req;
        struct list_head *listp;
        struct io_bdt *bd_tbl;
@@ -485,11 +489,12 @@ struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type)
        kref_init(&io_req->refcount);
        return io_req;
 }
-static struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt)
+
+struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt)
 {
        struct fcoe_port *port = tgt->port;
-       struct bnx2fc_hba *hba = port->priv;
-       struct bnx2fc_cmd_mgr *cmd_mgr = hba->cmd_mgr;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_cmd_mgr *cmd_mgr = interface->hba->cmd_mgr;
        struct bnx2fc_cmd *io_req;
        struct list_head *listp;
        struct io_bdt *bd_tbl;
@@ -570,7 +575,8 @@ void bnx2fc_cmd_release(struct kref *ref)
 static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req)
 {
        struct bnx2fc_mp_req *mp_req = &(io_req->mp_req);
-       struct bnx2fc_hba *hba = io_req->port->priv;
+       struct bnx2fc_interface *interface = io_req->port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        size_t sz = sizeof(struct fcoe_bd_ctx);
 
        /* clear tm flags */
@@ -606,7 +612,8 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
        struct bnx2fc_mp_req *mp_req;
        struct fcoe_bd_ctx *mp_req_bd;
        struct fcoe_bd_ctx *mp_resp_bd;
-       struct bnx2fc_hba *hba = io_req->port->priv;
+       struct bnx2fc_interface *interface = io_req->port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        dma_addr_t addr;
        size_t sz;
 
@@ -682,7 +689,7 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags)
        struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
        struct fc_rport_libfc_priv *rp = rport->dd_data;
        struct fcoe_port *port;
-       struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct bnx2fc_rport *tgt;
        struct bnx2fc_cmd *io_req;
        struct bnx2fc_mp_req *tm_req;
@@ -699,10 +706,10 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags)
 
        lport = shost_priv(host);
        port = lport_priv(lport);
-       hba = port->priv;
+       interface = port->priv;
 
        if (rport == NULL) {
-               printk(KERN_ALERT PFX "device_reset: rport is NULL\n");
+               printk(KERN_ERR PFX "device_reset: rport is NULL\n");
                rc = FAILED;
                goto tmf_err;
        }
@@ -745,7 +752,9 @@ retry_tmf:
        rc = bnx2fc_init_mp_req(io_req);
        if (rc == FAILED) {
                printk(KERN_ERR PFX "Task mgmt MP request init failed\n");
+               spin_lock_bh(&tgt->tgt_lock);
                kref_put(&io_req->refcount, bnx2fc_cmd_release);
+               spin_unlock_bh(&tgt->tgt_lock);
                goto tmf_err;
        }
 
@@ -774,7 +783,8 @@ retry_tmf:
        index = xid % BNX2FC_TASKS_PER_PAGE;
 
        /* Initialize task context for this IO request */
-       task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+       task_page = (struct fcoe_task_ctx_entry *)
+                       interface->hba->task_ctx[task_idx];
        task = &(task_page[index]);
        bnx2fc_init_mp_task(io_req, task);
 
@@ -806,10 +816,10 @@ retry_tmf:
        spin_unlock_bh(&tgt->tgt_lock);
 
        if (!rc) {
-               printk(KERN_ERR PFX "task mgmt command failed...\n");
+               BNX2FC_TGT_DBG(tgt, "task mgmt command failed...\n");
                rc = FAILED;
        } else {
-               printk(KERN_ERR PFX "task mgmt command success...\n");
+               BNX2FC_TGT_DBG(tgt, "task mgmt command success...\n");
                rc = SUCCESS;
        }
 tmf_err:
@@ -822,7 +832,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req)
        struct bnx2fc_rport *tgt = io_req->tgt;
        struct fc_rport *rport = tgt->rport;
        struct fc_rport_priv *rdata = tgt->rdata;
-       struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct fcoe_port *port;
        struct bnx2fc_cmd *abts_io_req;
        struct fcoe_task_ctx_entry *task;
@@ -839,7 +849,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req)
        BNX2FC_IO_DBG(io_req, "Entered bnx2fc_initiate_abts\n");
 
        port = io_req->port;
-       hba = port->priv;
+       interface = port->priv;
        lport = port->lport;
 
        if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) {
@@ -849,7 +859,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req)
        }
 
        if (rport == NULL) {
-               printk(KERN_ALERT PFX "initiate_abts: rport is NULL\n");
+               printk(KERN_ERR PFX "initiate_abts: rport is NULL\n");
                rc = FAILED;
                goto abts_err;
        }
@@ -896,7 +906,8 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req)
        index = xid % BNX2FC_TASKS_PER_PAGE;
 
        /* Initialize task context for this IO request */
-       task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+       task_page = (struct fcoe_task_ctx_entry *)
+                       interface->hba->task_ctx[task_idx];
        task = &(task_page[index]);
        bnx2fc_init_mp_task(abts_io_req, task);
 
@@ -924,11 +935,81 @@ abts_err:
        return rc;
 }
 
+int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset,
+                               enum fc_rctl r_ctl)
+{
+       struct fc_lport *lport;
+       struct bnx2fc_rport *tgt = orig_io_req->tgt;
+       struct bnx2fc_interface *interface;
+       struct fcoe_port *port;
+       struct bnx2fc_cmd *seq_clnp_req;
+       struct fcoe_task_ctx_entry *task;
+       struct fcoe_task_ctx_entry *task_page;
+       struct bnx2fc_els_cb_arg *cb_arg = NULL;
+       int task_idx, index;
+       u16 xid;
+       int rc = 0;
+
+       BNX2FC_IO_DBG(orig_io_req, "bnx2fc_initiate_seq_cleanup xid = 0x%x\n",
+                  orig_io_req->xid);
+       kref_get(&orig_io_req->refcount);
+
+       port = orig_io_req->port;
+       interface = port->priv;
+       lport = port->lport;
+
+       cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC);
+       if (!cb_arg) {
+               printk(KERN_ERR PFX "Unable to alloc cb_arg for seq clnup\n");
+               rc = -ENOMEM;
+               goto cleanup_err;
+       }
+
+       seq_clnp_req = bnx2fc_elstm_alloc(tgt, BNX2FC_SEQ_CLEANUP);
+       if (!seq_clnp_req) {
+               printk(KERN_ERR PFX "cleanup: couldnt allocate cmd\n");
+               rc = -ENOMEM;
+               kfree(cb_arg);
+               goto cleanup_err;
+       }
+       /* Initialize rest of io_req fields */
+       seq_clnp_req->sc_cmd = NULL;
+       seq_clnp_req->port = port;
+       seq_clnp_req->tgt = tgt;
+       seq_clnp_req->data_xfer_len = 0; /* No data transfer for cleanup */
+
+       xid = seq_clnp_req->xid;
+
+       task_idx = xid/BNX2FC_TASKS_PER_PAGE;
+       index = xid % BNX2FC_TASKS_PER_PAGE;
+
+       /* Initialize task context for this IO request */
+       task_page = (struct fcoe_task_ctx_entry *)
+                    interface->hba->task_ctx[task_idx];
+       task = &(task_page[index]);
+       cb_arg->aborted_io_req = orig_io_req;
+       cb_arg->io_req = seq_clnp_req;
+       cb_arg->r_ctl = r_ctl;
+       cb_arg->offset = offset;
+       seq_clnp_req->cb_arg = cb_arg;
+
+       printk(KERN_ERR PFX "call init_seq_cleanup_task\n");
+       bnx2fc_init_seq_cleanup_task(seq_clnp_req, task, orig_io_req, offset);
+
+       /* Obtain free SQ entry */
+       bnx2fc_add_2_sq(tgt, xid);
+
+       /* Ring doorbell */
+       bnx2fc_ring_doorbell(tgt);
+cleanup_err:
+       return rc;
+}
+
 int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req)
 {
        struct fc_lport *lport;
        struct bnx2fc_rport *tgt = io_req->tgt;
-       struct bnx2fc_hba *hba;
+       struct bnx2fc_interface *interface;
        struct fcoe_port *port;
        struct bnx2fc_cmd *cleanup_io_req;
        struct fcoe_task_ctx_entry *task;
@@ -941,7 +1022,7 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req)
        BNX2FC_IO_DBG(io_req, "Entered bnx2fc_initiate_cleanup\n");
 
        port = io_req->port;
-       hba = port->priv;
+       interface = port->priv;
        lport = port->lport;
 
        cleanup_io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_CLEANUP);
@@ -963,7 +1044,8 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req)
        index = xid % BNX2FC_TASKS_PER_PAGE;
 
        /* Initialize task context for this IO request */
-       task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx];
+       task_page = (struct fcoe_task_ctx_entry *)
+                       interface->hba->task_ctx[task_idx];
        task = &(task_page[index]);
        orig_xid = io_req->xid;
 
@@ -1031,7 +1113,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
 
        lport = shost_priv(sc_cmd->device->host);
        if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) {
-               printk(KERN_ALERT PFX "eh_abort: link not ready\n");
+               printk(KERN_ERR PFX "eh_abort: link not ready\n");
                return rc;
        }
 
@@ -1062,7 +1144,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
         * io_req is no longer in the active_q.
         */
        if (tgt->flush_in_prog) {
-               printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) "
+               printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
                        "flush in progress\n", io_req->xid);
                kref_put(&io_req->refcount, bnx2fc_cmd_release);
                spin_unlock_bh(&tgt->tgt_lock);
@@ -1070,7 +1152,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
        }
 
        if (io_req->on_active_queue == 0) {
-               printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) "
+               printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
                                "not on active_q\n", io_req->xid);
                /*
                 * This condition can happen only due to the FW bug,
@@ -1108,7 +1190,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
                set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags);
                rc = bnx2fc_initiate_abts(io_req);
        } else {
-               printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) "
+               printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
                                "already in abts processing\n", io_req->xid);
                kref_put(&io_req->refcount, bnx2fc_cmd_release);
                spin_unlock_bh(&tgt->tgt_lock);
@@ -1149,6 +1231,42 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
        return rc;
 }
 
+void bnx2fc_process_seq_cleanup_compl(struct bnx2fc_cmd *seq_clnp_req,
+                                     struct fcoe_task_ctx_entry *task,
+                                     u8 rx_state)
+{
+       struct bnx2fc_els_cb_arg *cb_arg = seq_clnp_req->cb_arg;
+       struct bnx2fc_cmd *orig_io_req = cb_arg->aborted_io_req;
+       u32 offset = cb_arg->offset;
+       enum fc_rctl r_ctl = cb_arg->r_ctl;
+       int rc = 0;
+       struct bnx2fc_rport *tgt = orig_io_req->tgt;
+
+       BNX2FC_IO_DBG(orig_io_req, "Entered process_cleanup_compl xid = 0x%x"
+                             "cmd_type = %d\n",
+                  seq_clnp_req->xid, seq_clnp_req->cmd_type);
+
+       if (rx_state == FCOE_TASK_RX_STATE_IGNORED_SEQUENCE_CLEANUP) {
+               printk(KERN_ERR PFX "seq cleanup ignored - xid = 0x%x\n",
+                       seq_clnp_req->xid);
+               goto free_cb_arg;
+       }
+       kref_get(&orig_io_req->refcount);
+
+       spin_unlock_bh(&tgt->tgt_lock);
+       rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl);
+       spin_lock_bh(&tgt->tgt_lock);
+
+       if (rc)
+               printk(KERN_ERR PFX "clnup_compl: Unable to send SRR"
+                       " IO will abort\n");
+       seq_clnp_req->cb_arg = NULL;
+       kref_put(&orig_io_req->refcount, bnx2fc_cmd_release);
+free_cb_arg:
+       kfree(cb_arg);
+       return;
+}
+
 void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req,
                                  struct fcoe_task_ctx_entry *task,
                                  u8 num_rq)
@@ -1378,7 +1496,7 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
                        fc_hdr->fh_r_ctl);
        }
        if (!sc_cmd->SCp.ptr) {
-               printk(KERN_ALERT PFX "tm_compl: SCp.ptr is NULL\n");
+               printk(KERN_ERR PFX "tm_compl: SCp.ptr is NULL\n");
                return;
        }
        switch (io_req->fcp_status) {
@@ -1410,7 +1528,7 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req,
                io_req->on_tmf_queue = 0;
        } else {
 
-               printk(KERN_ALERT PFX "Command not on active_cmd_queue!\n");
+               printk(KERN_ERR PFX "Command not on active_cmd_queue!\n");
                return;
        }
 
@@ -1597,7 +1715,7 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
 
                if (rq_buff_len > num_rq * BNX2FC_RQ_BUF_SZ) {
                        /* Invalid sense sense length. */
-                       printk(KERN_ALERT PFX "invalid sns length %d\n",
+                       printk(KERN_ERR PFX "invalid sns length %d\n",
                                rq_buff_len);
                        /* reset rq_buff_len */
                        rq_buff_len =  num_rq * BNX2FC_RQ_BUF_SZ;
@@ -1780,7 +1898,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                        scsi_set_resid(sc_cmd, io_req->fcp_resid);
                break;
        default:
-               printk(KERN_ALERT PFX "scsi_cmd_compl: fcp_status = %d\n",
+               printk(KERN_ERR PFX "scsi_cmd_compl: fcp_status = %d\n",
                        io_req->fcp_status);
                break;
        }
@@ -1789,14 +1907,15 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
        kref_put(&io_req->refcount, bnx2fc_cmd_release);
 }
 
-static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
+int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
                               struct bnx2fc_cmd *io_req)
 {
        struct fcoe_task_ctx_entry *task;
        struct fcoe_task_ctx_entry *task_page;
        struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
        struct fcoe_port *port = tgt->port;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct fc_lport *lport = port->lport;
        struct fcoe_dev_stats *stats;
        int task_idx, index;
@@ -1854,7 +1973,8 @@ static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
        }
 
        /* Time IO req */
-       bnx2fc_cmd_timer_set(io_req, BNX2FC_IO_TIMEOUT);
+       if (tgt->io_timeout)
+               bnx2fc_cmd_timer_set(io_req, BNX2FC_IO_TIMEOUT);
        /* Obtain free SQ entry */
        bnx2fc_add_2_sq(tgt, xid);
 
index 3e892bd66fbe12e08f4370efdfebcadf449043bc..d5311b577ccadcf322cf271410552ba31cfb50e3 100644 (file)
@@ -2,7 +2,7 @@
  * Handles operations such as session offload/upload etc, and manages
  * session resources such as connection id and qp resources.
  *
- * Copyright (c) 2008 - 2010 Broadcom Corporation
+ * Copyright (c) 2008 - 2011 Broadcom 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
@@ -65,7 +65,8 @@ static void bnx2fc_offload_session(struct fcoe_port *port,
 {
        struct fc_lport *lport = rdata->local_port;
        struct fc_rport *rport = rdata->rport;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        int rval;
        int i = 0;
 
@@ -237,7 +238,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
 static void bnx2fc_upload_session(struct fcoe_port *port,
                                        struct bnx2fc_rport *tgt)
 {
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
 
        BNX2FC_TGT_DBG(tgt, "upload_session: active_ios = %d\n",
                tgt->num_active_ios.counter);
@@ -316,7 +318,8 @@ static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt,
 {
 
        struct fc_rport *rport = rdata->rport;
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct b577xx_doorbell_set_prod *sq_db = &tgt->sq_db;
        struct b577xx_fcoe_rx_doorbell *rx_db = &tgt->rx_db;
 
@@ -350,6 +353,14 @@ static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt,
        tgt->rq_cons_idx = 0;
        atomic_set(&tgt->num_active_ios, 0);
 
+       if (rdata->flags & FC_RP_FLAGS_RETRY) {
+               tgt->dev_type = TYPE_TAPE;
+               tgt->io_timeout = 0; /* use default ULP timeout */
+       } else {
+               tgt->dev_type = TYPE_DISK;
+               tgt->io_timeout = BNX2FC_IO_TIMEOUT;
+       }
+
        /* initialize sq doorbell */
        sq_db->header.header = B577XX_DOORBELL_HDR_DB_TYPE;
        sq_db->header.header |= B577XX_FCOE_CONNECTION_TYPE <<
@@ -392,7 +403,8 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
                                enum fc_rport_event event)
 {
        struct fcoe_port *port = lport_priv(lport);
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct fc_rport *rport = rdata->rport;
        struct fc_rport_libfc_priv *rp;
        struct bnx2fc_rport *tgt;
@@ -403,7 +415,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
        switch (event) {
        case RPORT_EV_READY:
                if (!rport) {
-                       printk(KERN_ALERT PFX "rport is NULL: ERROR!\n");
+                       printk(KERN_ERR PFX "rport is NULL: ERROR!\n");
                        break;
                }
 
@@ -415,7 +427,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
                         * We should not come here, as lport will
                         * take care of fabric login
                         */
-                       printk(KERN_ALERT PFX "%x - rport_event_handler ERROR\n",
+                       printk(KERN_ERR PFX "%x - rport_event_handler ERROR\n",
                                rdata->ids.port_id);
                        break;
                }
@@ -483,7 +495,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
                        break;
 
                if (!rport) {
-                       printk(KERN_ALERT PFX "%x - rport not created Yet!!\n",
+                       printk(KERN_INFO PFX "%x - rport not created Yet!!\n",
                                port_id);
                        break;
                }
@@ -537,7 +549,8 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
 struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
                                             u32 port_id)
 {
-       struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_interface *interface = port->priv;
+       struct bnx2fc_hba *hba = interface->hba;
        struct bnx2fc_rport *tgt;
        struct fc_rport_priv *rdata;
        int i;
@@ -552,7 +565,7 @@ struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
                                                "obtained\n");
                                        return tgt;
                                } else {
-                                       printk(KERN_ERR PFX "rport 0x%x "
+                                       BNX2FC_TGT_DBG(tgt, "rport 0x%x "
                                                "is in DELETED state\n",
                                                rdata->ids.port_id);
                                        return NULL;
@@ -633,7 +646,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
                                     &tgt->sq_dma, GFP_KERNEL);
        if (!tgt->sq) {
-               printk(KERN_ALERT PFX "unable to allocate SQ memory %d\n",
+               printk(KERN_ERR PFX "unable to allocate SQ memory %d\n",
                        tgt->sq_mem_size);
                goto mem_alloc_failure;
        }
@@ -646,7 +659,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
                                     &tgt->cq_dma, GFP_KERNEL);
        if (!tgt->cq) {
-               printk(KERN_ALERT PFX "unable to allocate CQ memory %d\n",
+               printk(KERN_ERR PFX "unable to allocate CQ memory %d\n",
                        tgt->cq_mem_size);
                goto mem_alloc_failure;
        }
@@ -659,7 +672,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
                                        &tgt->rq_dma, GFP_KERNEL);
        if (!tgt->rq) {
-               printk(KERN_ALERT PFX "unable to allocate RQ memory %d\n",
+               printk(KERN_ERR PFX "unable to allocate RQ memory %d\n",
                        tgt->rq_mem_size);
                goto mem_alloc_failure;
        }
@@ -671,7 +684,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
                                         &tgt->rq_pbl_dma, GFP_KERNEL);
        if (!tgt->rq_pbl) {
-               printk(KERN_ALERT PFX "unable to allocate RQ PBL %d\n",
+               printk(KERN_ERR PFX "unable to allocate RQ PBL %d\n",
                        tgt->rq_pbl_size);
                goto mem_alloc_failure;
        }
@@ -697,7 +710,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
                                        &tgt->xferq_dma, GFP_KERNEL);
        if (!tgt->xferq) {
-               printk(KERN_ALERT PFX "unable to allocate XFERQ %d\n",
+               printk(KERN_ERR PFX "unable to allocate XFERQ %d\n",
                        tgt->xferq_mem_size);
                goto mem_alloc_failure;
        }
@@ -711,7 +724,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
                                        &tgt->confq_dma, GFP_KERNEL);
        if (!tgt->confq) {
-               printk(KERN_ALERT PFX "unable to allocate CONFQ %d\n",
+               printk(KERN_ERR PFX "unable to allocate CONFQ %d\n",
                        tgt->confq_mem_size);
                goto mem_alloc_failure;
        }
@@ -726,7 +739,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
                                            tgt->confq_pbl_size,
                                            &tgt->confq_pbl_dma, GFP_KERNEL);
        if (!tgt->confq_pbl) {
-               printk(KERN_ALERT PFX "unable to allocate CONFQ PBL %d\n",
+               printk(KERN_ERR PFX "unable to allocate CONFQ PBL %d\n",
                        tgt->confq_pbl_size);
                goto mem_alloc_failure;
        }
@@ -751,7 +764,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
                                          tgt->conn_db_mem_size,
                                          &tgt->conn_db_dma, GFP_KERNEL);
        if (!tgt->conn_db) {
-               printk(KERN_ALERT PFX "unable to allocate conn_db %d\n",
+               printk(KERN_ERR PFX "unable to allocate conn_db %d\n",
                                                tgt->conn_db_mem_size);
                goto mem_alloc_failure;
        }
@@ -767,7 +780,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
                                      &tgt->lcq_dma, GFP_KERNEL);
 
        if (!tgt->lcq) {
-               printk(KERN_ALERT PFX "unable to allocate lcq %d\n",
+               printk(KERN_ERR PFX "unable to allocate lcq %d\n",
                       tgt->lcq_mem_size);
                goto mem_alloc_failure;
        }
index 030a96c646c314fc093ecf7b99a80a6a41cf32c3..9ae80cd5953bce99f24d9f7b85dd77d332b25a6f 100644 (file)
@@ -332,11 +332,11 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
 {
        struct bnx2i_cmd *bnx2i_cmd;
        struct bnx2i_login_request *login_wqe;
-       struct iscsi_login *login_hdr;
+       struct iscsi_login_req *login_hdr;
        u32 dword;
 
        bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data;
-       login_hdr = (struct iscsi_login *)task->hdr;
+       login_hdr = (struct iscsi_login_req *)task->hdr;
        login_wqe = (struct bnx2i_login_request *)
                                                bnx2i_conn->ep->qp.sq_prod_qe;
 
@@ -1349,7 +1349,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
        struct bnx2i_cmd_response *resp_cqe;
        struct bnx2i_cmd *bnx2i_cmd;
        struct iscsi_task *task;
-       struct iscsi_cmd_rsp *hdr;
+       struct iscsi_scsi_rsp *hdr;
        u32 datalen = 0;
 
        resp_cqe = (struct bnx2i_cmd_response *)cqe;
@@ -1376,7 +1376,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
        }
        bnx2i_iscsi_unmap_sg_list(bnx2i_cmd);
 
-       hdr = (struct iscsi_cmd_rsp *)task->hdr;
+       hdr = (struct iscsi_scsi_rsp *)task->hdr;
        resp_cqe = (struct bnx2i_cmd_response *)cqe;
        hdr->opcode = resp_cqe->op_code;
        hdr->max_cmdsn = cpu_to_be32(resp_cqe->max_cmd_sn);
index 5c55a75ae597a65b33e6d50b8eb6f4d81259ee4a..cffd4d75df568a0d994e9b4e2187f4ed4ac3c30e 100644 (file)
@@ -1213,7 +1213,7 @@ static int bnx2i_task_xmit(struct iscsi_task *task)
        struct bnx2i_conn *bnx2i_conn = conn->dd_data;
        struct scsi_cmnd *sc = task->sc;
        struct bnx2i_cmd *cmd = task->dd_data;
-       struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr;
+       struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr;
 
        if (atomic_read(&bnx2i_conn->ep->num_active_cmds) + 1  >
            hba->max_sqes)
index 2e7c136bb80528906ca2374eca7f235ac02a997a..27c9d65d54a902443ff5b32fd4772666951c15dd 100644 (file)
@@ -128,25 +128,7 @@ struct c4_inquiry {
        u8      reserved[2];
 };
 
-struct rdac_controller {
-       u8                      subsys_id[SUBSYS_ID_LEN];
-       u8                      slot_id[SLOT_ID_LEN];
-       int                     use_ms10;
-       struct kref             kref;
-       struct list_head        node; /* list of all controllers */
-       union                   {
-               struct rdac_pg_legacy legacy;
-               struct rdac_pg_expanded expanded;
-       } mode_select;
-       u8      index;
-       u8      array_name[ARRAY_LABEL_LEN];
-       spinlock_t              ms_lock;
-       int                     ms_queued;
-       struct work_struct      ms_work;
-       struct scsi_device      *ms_sdev;
-       struct list_head        ms_head;
-};
-
+#define UNIQUE_ID_LEN 16
 struct c8_inquiry {
        u8      peripheral_info;
        u8      page_code; /* 0xC8 */
@@ -159,12 +141,31 @@ struct c8_inquiry {
        u8      vol_user_label_len;
        u8      vol_user_label[60];
        u8      array_uniq_id_len;
-       u8      array_unique_id[16];
+       u8      array_unique_id[UNIQUE_ID_LEN];
        u8      array_user_label_len;
        u8      array_user_label[60];
        u8      lun[8];
 };
 
+struct rdac_controller {
+       u8                      array_id[UNIQUE_ID_LEN];
+       int                     use_ms10;
+       struct kref             kref;
+       struct list_head        node; /* list of all controllers */
+       union                   {
+               struct rdac_pg_legacy legacy;
+               struct rdac_pg_expanded expanded;
+       } mode_select;
+       u8      index;
+       u8      array_name[ARRAY_LABEL_LEN];
+       struct Scsi_Host        *host;
+       spinlock_t              ms_lock;
+       int                     ms_queued;
+       struct work_struct      ms_work;
+       struct scsi_device      *ms_sdev;
+       struct list_head        ms_head;
+};
+
 struct c2_inquiry {
        u8      peripheral_info;
        u8      page_code;      /* 0xC2 */
@@ -369,16 +370,17 @@ static void release_controller(struct kref *kref)
        kfree(ctlr);
 }
 
-static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id,
-                                               char *array_name)
+static struct rdac_controller *get_controller(int index, char *array_name,
+                       u8 *array_id, struct scsi_device *sdev)
 {
        struct rdac_controller *ctlr, *tmp;
 
        spin_lock(&list_lock);
 
        list_for_each_entry(tmp, &ctlr_list, node) {
-               if ((memcmp(tmp->subsys_id, subsys_id, SUBSYS_ID_LEN) == 0) &&
-                         (memcmp(tmp->slot_id, slot_id, SLOT_ID_LEN) == 0)) {
+               if ((memcmp(tmp->array_id, array_id, UNIQUE_ID_LEN) == 0) &&
+                         (tmp->index == index) &&
+                         (tmp->host == sdev->host)) {
                        kref_get(&tmp->kref);
                        spin_unlock(&list_lock);
                        return tmp;
@@ -389,16 +391,11 @@ static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id,
                goto done;
 
        /* initialize fields of controller */
-       memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN);
-       memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN);
+       memcpy(ctlr->array_id, array_id, UNIQUE_ID_LEN);
+       ctlr->index = index;
+       ctlr->host = sdev->host;
        memcpy(ctlr->array_name, array_name, ARRAY_LABEL_LEN);
 
-       /* update the controller index */
-       if (slot_id[1] == 0x31)
-               ctlr->index = 0;
-       else
-               ctlr->index = 1;
-
        kref_init(&ctlr->kref);
        ctlr->use_ms10 = -1;
        ctlr->ms_queued = 0;
@@ -444,7 +441,7 @@ done:
 }
 
 static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h,
-                       char *array_name)
+                       char *array_name, u8 *array_id)
 {
        int err, i;
        struct c8_inquiry *inqp;
@@ -463,6 +460,8 @@ static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h,
                        *(array_name+i) = inqp->array_user_label[(2*i)+1];
 
                *(array_name+ARRAY_LABEL_LEN-1) = '\0';
+               memset(array_id, 0, UNIQUE_ID_LEN);
+               memcpy(array_id, inqp->array_unique_id, inqp->array_uniq_id_len);
        }
        return err;
 }
@@ -504,16 +503,20 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
 }
 
 static int initialize_controller(struct scsi_device *sdev,
-                                struct rdac_dh_data *h, char *array_name)
+               struct rdac_dh_data *h, char *array_name, u8 *array_id)
 {
-       int err;
+       int err, index;
        struct c4_inquiry *inqp;
 
        err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h);
        if (err == SCSI_DH_OK) {
                inqp = &h->inq.c4;
-               h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id,
-                                       array_name);
+               /* get the controller index */
+               if (inqp->slot_id[1] == 0x31)
+                       index = 0;
+               else
+                       index = 1;
+               h->ctlr = get_controller(index, array_name, array_id, sdev);
                if (!h->ctlr)
                        err = SCSI_DH_RES_TEMP_UNAVAIL;
        }
@@ -835,6 +838,7 @@ static int rdac_bus_attach(struct scsi_device *sdev)
        unsigned long flags;
        int err;
        char array_name[ARRAY_LABEL_LEN];
+       char array_id[UNIQUE_ID_LEN];
 
        scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
                               + sizeof(*h) , GFP_KERNEL);
@@ -849,11 +853,11 @@ static int rdac_bus_attach(struct scsi_device *sdev)
        h->lun = UNINITIALIZED_LUN;
        h->state = RDAC_STATE_ACTIVE;
 
-       err = get_lun_info(sdev, h, array_name);
+       err = get_lun_info(sdev, h, array_name, array_id);
        if (err != SCSI_DH_OK)
                goto failed;
 
-       err = initialize_controller(sdev, h, array_name);
+       err = initialize_controller(sdev, h, array_name, array_id);
        if (err != SCSI_DH_OK)
                goto failed;
 
index 204fa8d4b4ab6833ade46d4494628f8bfdbf4aa6..ba710e350ac56931a234d1cf0d718f6ae12cea7d 100644 (file)
@@ -486,6 +486,19 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev,
        return 0;
 }
 
+/**
+ * fcoe_port_send() - Send an Ethernet-encapsulated FIP/FCoE frame
+ * @port: The FCoE port
+ * @skb: The FIP/FCoE packet to be sent
+ */
+static void fcoe_port_send(struct fcoe_port *port, struct sk_buff *skb)
+{
+       if (port->fcoe_pending_queue.qlen)
+               fcoe_check_wait_queue(port->lport, skb);
+       else if (fcoe_start_io(skb))
+               fcoe_check_wait_queue(port->lport, skb);
+}
+
 /**
  * fcoe_fip_send() - Send an Ethernet-encapsulated FIP frame
  * @fip: The FCoE controller
@@ -494,7 +507,7 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev,
 static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
 {
        skb->dev = fcoe_from_ctlr(fip)->netdev;
-       dev_queue_xmit(skb);
+       fcoe_port_send(lport_priv(fip->lp), skb);
 }
 
 /**
@@ -1257,30 +1270,20 @@ static int fcoe_cpu_callback(struct notifier_block *nfb,
 /**
  * fcoe_select_cpu() - Selects CPU to handle post-processing of incoming
  *                     command.
- * @curr_cpu:   CPU which received request
  *
- * This routine selects next CPU based on cpumask.
+ * This routine selects next CPU based on cpumask to distribute
+ * incoming requests in round robin.
  *
- * Returns: int (CPU number). Caller to verify if returned CPU is online or not.
+ * Returns: int CPU number
  */
-static unsigned int fcoe_select_cpu(unsigned int curr_cpu)
+static inline unsigned int fcoe_select_cpu(void)
 {
        static unsigned int selected_cpu;
 
-       if (num_online_cpus() == 1)
-               return curr_cpu;
-       /*
-        * Doing following check, to skip "curr_cpu (smp_processor_id)"
-        * from selection of CPU is intentional. This is to avoid same CPU
-        * doing post-processing of command. "curr_cpu" to just receive
-        * incoming request in case where rx_id is UNKNOWN and all other
-        * CPU to actually process the command(s)
-        */
-       do {
-               selected_cpu = cpumask_next(selected_cpu, cpu_online_mask);
-               if (selected_cpu >= nr_cpu_ids)
-                       selected_cpu = cpumask_first(cpu_online_mask);
-       } while (selected_cpu == curr_cpu);
+       selected_cpu = cpumask_next(selected_cpu, cpu_online_mask);
+       if (selected_cpu >= nr_cpu_ids)
+               selected_cpu = cpumask_first(cpu_online_mask);
+
        return selected_cpu;
 }
 
@@ -1350,30 +1353,26 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
 
        fr = fcoe_dev_from_skb(skb);
        fr->fr_dev = lport;
-       fr->ptype = ptype;
 
        /*
         * In case the incoming frame's exchange is originated from
         * the initiator, then received frame's exchange id is ANDed
         * with fc_cpu_mask bits to get the same cpu on which exchange
-        * was originated, otherwise just use the current cpu.
+        * was originated, otherwise select cpu using rx exchange id
+        * or fcoe_select_cpu().
         */
        if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX)
                cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask;
        else {
-               cpu = smp_processor_id();
-
-               if ((fh->fh_type == FC_TYPE_FCP) &&
-                   (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) {
-                       do {
-                               cpu = fcoe_select_cpu(cpu);
-                       } while (!cpu_online(cpu));
-               } else  if ((fh->fh_type == FC_TYPE_FCP) &&
-                           (ntohs(fh->fh_rx_id) != FC_XID_UNKNOWN)) {
+               if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)
+                       cpu = fcoe_select_cpu();
+               else
                        cpu = ntohs(fh->fh_rx_id) & fc_cpu_mask;
-               } else
-                       cpu = smp_processor_id();
        }
+
+       if (cpu >= nr_cpu_ids)
+               goto err;
+
        fps = &per_cpu(fcoe_percpu, cpu);
        spin_lock_bh(&fps->fcoe_rx_list.lock);
        if (unlikely(!fps->thread)) {
@@ -1572,11 +1571,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
 
        /* send down to lld */
        fr_dev(fp) = lport;
-       if (port->fcoe_pending_queue.qlen)
-               fcoe_check_wait_queue(lport, skb);
-       else if (fcoe_start_io(skb))
-               fcoe_check_wait_queue(lport, skb);
-
+       fcoe_port_send(port, skb);
        return 0;
 }
 
index c6f99b1d23835304b82aba002aca8f0db003418c..ec61bdb833ac4baeab42c6c0473801dc02ec6743 100644 (file)
@@ -1219,8 +1219,8 @@ static void complete_scsi_command(struct CommandList *cp)
                dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp);
                break;
        case CMD_UNSOLICITED_ABORT:
-               cmd->result = DID_RESET << 16;
-               dev_warn(&h->pdev->dev, "cp %p aborted do to an unsolicited "
+               cmd->result = DID_SOFT_ERROR << 16; /* retry the command */
+               dev_warn(&h->pdev->dev, "cp %p aborted due to an unsolicited "
                        "abort\n", cp);
                break;
        case CMD_TIMEOUT:
index 6d8dcd4dd06bf7a16a655d010af75e98c2456259..7f53ceaa7239144523c0bc1c9c2685327bfb6198 100644 (file)
@@ -214,7 +214,7 @@ static void SA5_submit_command(struct ctlr_info *h,
        dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr,
                c->Header.Tag.lower);
        writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
-       (void) readl(h->vaddr + SA5_REQUEST_PORT_OFFSET);
+       (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
        h->commands_outstanding++;
        if (h->commands_outstanding > h->max_outstanding)
                h->max_outstanding = h->commands_outstanding;
index 888086c4e709497e6d8c7ae9e02dcf06b5bbca18..8d636301e32c4ba289bffe22300739b396ccd566 100644 (file)
@@ -8778,14 +8778,14 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        if (rc != PCIBIOS_SUCCESSFUL) {
                dev_err(&pdev->dev, "Failed to save PCI config space\n");
                rc = -EIO;
-               goto cleanup_nomem;
+               goto out_msi_disable;
        }
 
        if ((rc = ipr_save_pcix_cmd_reg(ioa_cfg)))
-               goto cleanup_nomem;
+               goto out_msi_disable;
 
        if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg)))
-               goto cleanup_nomem;
+               goto out_msi_disable;
 
        if (ioa_cfg->sis64)
                ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr64)
@@ -8800,7 +8800,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
        if (rc < 0) {
                dev_err(&pdev->dev,
                        "Couldn't allocate enough memory for device driver!\n");
-               goto cleanup_nomem;
+               goto out_msi_disable;
        }
 
        /*
@@ -8845,10 +8845,10 @@ out:
 
 cleanup_nolog:
        ipr_free_mem(ioa_cfg);
-cleanup_nomem:
-       iounmap(ipr_regs);
 out_msi_disable:
        pci_disable_msi(pdev);
+cleanup_nomem:
+       iounmap(ipr_regs);
 out_release_regions:
        pci_release_regions(pdev);
 out_scsi_host_put:
index f5a0665b6773d1e0c2cec93dd4a251390817f8d6..01ff082dc34cfaac127eb62ebc4ad2cd02ef3ff5 100644 (file)
@@ -802,10 +802,8 @@ static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid)
                pool = per_cpu_ptr(mp->pool, xid & fc_cpu_mask);
                spin_lock_bh(&pool->lock);
                ep = fc_exch_ptr_get(pool, (xid - mp->min_xid) >> fc_cpu_order);
-               if (ep) {
+               if (ep && ep->xid == xid)
                        fc_exch_hold(ep);
-                       WARN_ON(ep->xid != xid);
-               }
                spin_unlock_bh(&pool->lock);
        }
        return ep;
@@ -2465,8 +2463,11 @@ int fc_setup_exch_mgr(void)
 
        fc_exch_workqueue = create_singlethread_workqueue("fc_exch_workqueue");
        if (!fc_exch_workqueue)
-               return -ENOMEM;
+               goto err;
        return 0;
+err:
+       kmem_cache_destroy(fc_em_cachep);
+       return -ENOMEM;
 }
 
 /**
index 9cd2149519ace23d9dbbff8fa7d28b1c5e2acdf5..afb63c843144b483c362794f72e41de8689d3358 100644 (file)
@@ -498,7 +498,7 @@ crc_err:
                        stats = per_cpu_ptr(lport->dev_stats, get_cpu());
                        stats->ErrorFrames++;
                        /* per cpu count, not total count, but OK for limit */
-                       if (stats->InvalidCRCCount++ < 5)
+                       if (stats->InvalidCRCCount++ < FC_MAX_ERROR_CNT)
                                printk(KERN_WARNING "libfc: CRC error on data "
                                       "frame for port (%6.6x)\n",
                                       lport->port_id);
@@ -690,7 +690,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
 }
 
 /**
- * fc_fcp_abts_resp() - Send an ABTS response
+ * fc_fcp_abts_resp() - Receive an ABTS response
  * @fsp: The FCP packet that is being aborted
  * @fp:         The response frame
  */
@@ -730,7 +730,7 @@ static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 }
 
 /**
- * fc_fcp_recv() - Reveive an FCP frame
+ * fc_fcp_recv() - Receive an FCP frame
  * @seq: The sequence the frame is on
  * @fp:         The received frame
  * @arg: The related FCP packet
@@ -1084,6 +1084,7 @@ static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp)
        rc = lport->tt.fcp_cmd_send(lport, fsp, fc_fcp_recv);
        if (unlikely(rc)) {
                spin_lock_irqsave(&si->scsi_queue_lock, flags);
+               fsp->cmd->SCp.ptr = NULL;
                list_del(&fsp->list);
                spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
        }
@@ -1645,12 +1646,10 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
        struct fc_seq *seq;
        struct fcp_srr *srr;
        struct fc_frame *fp;
-       u8 cdb_op;
        unsigned int rec_tov;
 
        rport = fsp->rport;
        rpriv = rport->dd_data;
-       cdb_op = fsp->cdb_cmd.fc_cdb[0];
 
        if (!(rpriv->flags & FC_RP_FLAGS_RETRY) ||
            rpriv->rp_state != RPORT_ST_READY)
index e008b1673507b7e6687597b6c5b97046e0acac52..e55ed9cf23fb15cfa8a386eff6921471b39b1e57 100644 (file)
@@ -1352,7 +1352,6 @@ static void fc_lport_timeout(struct work_struct *work)
                WARN_ON(1);
                break;
        case LPORT_ST_READY:
-               WARN_ON(1);
                break;
        case LPORT_ST_RESET:
                break;
index d7a4120034a279be7d42bbea03dd09c41d7b66c6..256a999d010bc6414f3f6702189decddd3813ac4 100644 (file)
@@ -84,22 +84,6 @@ MODULE_PARM_DESC(debug_libiscsi_eh,
                                             __func__, ##arg);          \
        } while (0);
 
-/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
-#define SNA32_CHECK 2147483648UL
-
-static int iscsi_sna_lt(u32 n1, u32 n2)
-{
-       return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
-                           (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
-}
-
-/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
-static int iscsi_sna_lte(u32 n1, u32 n2)
-{
-       return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
-                           (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
-}
-
 inline void iscsi_conn_queue_work(struct iscsi_conn *conn)
 {
        struct Scsi_Host *shost = conn->session->host;
@@ -360,7 +344,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
        struct iscsi_conn *conn = task->conn;
        struct iscsi_session *session = conn->session;
        struct scsi_cmnd *sc = task->sc;
-       struct iscsi_cmd *hdr;
+       struct iscsi_scsi_req *hdr;
        unsigned hdrlength, cmd_len;
        itt_t itt;
        int rc;
@@ -374,7 +358,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
                if (rc)
                        return rc;
        }
-       hdr = (struct iscsi_cmd *) task->hdr;
+       hdr = (struct iscsi_scsi_req *)task->hdr;
        itt = hdr->itt;
        memset(hdr, 0, sizeof(*hdr));
 
@@ -830,7 +814,7 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                               struct iscsi_task *task, char *data,
                               int datalen)
 {
-       struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr;
+       struct iscsi_scsi_rsp *rhdr = (struct iscsi_scsi_rsp *)hdr;
        struct iscsi_session *session = conn->session;
        struct scsi_cmnd *sc = task->sc;
 
index 874e29d9533f901ee761358a92fc5b824e2c985c..f84084bba2f0ea19f19b5f073120fc8ff34612d0 100644 (file)
@@ -849,6 +849,9 @@ static struct domain_device *sas_ex_discover_expander(
 
        res = sas_discover_expander(child);
        if (res) {
+               spin_lock_irq(&parent->port->dev_list_lock);
+               list_del(&child->dev_list_node);
+               spin_unlock_irq(&parent->port->dev_list_lock);
                kfree(child);
                return NULL;
        }
index 8ec2c86a49d42fa3661b71875bcbe1f20c9ed37f..c088a36d1f33c679730fa8ce0082a0fab4a45888 100644 (file)
  *******************************************************************/
 
 #include <scsi/scsi_host.h>
+
+#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_SCSI_LPFC_DEBUG_FS)
+#define CONFIG_SCSI_LPFC_DEBUG_FS
+#endif
+
 struct lpfc_sli2_slim;
 
 #define LPFC_PCI_DEV_LP                0x1
@@ -465,9 +470,10 @@ enum intr_type_t {
 struct unsol_rcv_ct_ctx {
        uint32_t ctxt_id;
        uint32_t SID;
-       uint32_t oxid;
        uint32_t flags;
 #define UNSOL_VALID    0x00000001
+       uint16_t oxid;
+       uint16_t rxid;
 };
 
 #define LPFC_USER_LINK_SPEED_AUTO      0       /* auto select (default)*/
@@ -674,6 +680,9 @@ struct lpfc_hba {
        uint32_t cfg_enable_rrq;
        uint32_t cfg_topology;
        uint32_t cfg_link_speed;
+#define LPFC_FCF_FOV 1         /* Fast fcf failover */
+#define LPFC_FCF_PRIORITY 2    /* Priority fcf failover */
+       uint32_t cfg_fcf_failover_policy;
        uint32_t cfg_cr_delay;
        uint32_t cfg_cr_count;
        uint32_t cfg_multi_ring_support;
@@ -845,9 +854,13 @@ struct lpfc_hba {
        /* iDiag debugfs sub-directory */
        struct dentry *idiag_root;
        struct dentry *idiag_pci_cfg;
+       struct dentry *idiag_bar_acc;
        struct dentry *idiag_que_info;
        struct dentry *idiag_que_acc;
        struct dentry *idiag_drb_acc;
+       struct dentry *idiag_ctl_acc;
+       struct dentry *idiag_mbx_acc;
+       struct dentry *idiag_ext_acc;
 #endif
 
        /* Used for deferred freeing of ELS data buffers */
index 135a53baa735177513f6dfcc7f7fd85afb9d8ea1..2542f1f8bf86583df36fba43ddbfb2c26e0d5120 100644 (file)
@@ -754,6 +754,47 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr,
                return status;
 }
 
+/**
+ * lpfc_sli4_pdev_status_reg_wait - Wait for pdev status register for readyness
+ * @phba: lpfc_hba pointer.
+ *
+ * Description:
+ * SLI4 interface type-2 device to wait on the sliport status register for
+ * the readyness after performing a firmware reset.
+ *
+ * Returns:
+ * zero for success
+ **/
+static int
+lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba)
+{
+       struct lpfc_register portstat_reg;
+       int i;
+
+
+       lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
+                  &portstat_reg.word0);
+
+       /* wait for the SLI port firmware ready after firmware reset */
+       for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) {
+               msleep(10);
+               lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
+                          &portstat_reg.word0);
+               if (!bf_get(lpfc_sliport_status_err, &portstat_reg))
+                       continue;
+               if (!bf_get(lpfc_sliport_status_rn, &portstat_reg))
+                       continue;
+               if (!bf_get(lpfc_sliport_status_rdy, &portstat_reg))
+                       continue;
+               break;
+       }
+
+       if (i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT)
+               return 0;
+       else
+               return -EIO;
+}
+
 /**
  * lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc
  * @phba: lpfc_hba pointer.
@@ -769,6 +810,7 @@ static ssize_t
 lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
 {
        struct completion online_compl;
+       struct pci_dev *pdev = phba->pcidev;
        uint32_t reg_val;
        int status = 0;
        int rc;
@@ -781,6 +823,14 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
             LPFC_SLI_INTF_IF_TYPE_2))
                return -EPERM;
 
+       if (!pdev->is_physfn)
+               return -EPERM;
+
+       /* Disable SR-IOV virtual functions if enabled */
+       if (phba->cfg_sriov_nr_virtfn) {
+               pci_disable_sriov(pdev);
+               phba->cfg_sriov_nr_virtfn = 0;
+       }
        status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 
        if (status != 0)
@@ -805,7 +855,10 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
        readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);
 
        /* delay driver action following IF_TYPE_2 reset */
-       msleep(100);
+       rc = lpfc_sli4_pdev_status_reg_wait(phba);
+
+       if (rc)
+               return -EIO;
 
        init_completion(&online_compl);
        rc = lpfc_workq_post_event(phba, &status, &online_compl,
@@ -895,6 +948,10 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr,
 
        if (!phba->cfg_enable_hba_reset)
                return -EACCES;
+
+       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+               "3050 lpfc_board_mode set to %s\n", buf);
+
        init_completion(&online_compl);
 
        if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
@@ -1290,6 +1347,10 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr,
        if (phba->sli_rev == LPFC_SLI_REV4)
                val = 0;
 
+       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+               "3051 lpfc_poll changed from %d to %d\n",
+               phba->cfg_poll, val);
+
        spin_lock_irq(&phba->hbalock);
 
        old_val = phba->cfg_poll;
@@ -1414,80 +1475,10 @@ lpfc_sriov_hw_max_virtfn_show(struct device *dev,
        struct Scsi_Host *shost = class_to_shost(dev);
        struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
        struct lpfc_hba *phba = vport->phba;
-       struct pci_dev *pdev = phba->pcidev;
-       union  lpfc_sli4_cfg_shdr *shdr;
-       uint32_t shdr_status, shdr_add_status;
-       LPFC_MBOXQ_t *mboxq;
-       struct lpfc_mbx_get_prof_cfg *get_prof_cfg;
-       struct lpfc_rsrc_desc_pcie *desc;
-       uint32_t max_nr_virtfn;
-       uint32_t desc_count;
-       int length, rc, i;
-
-       if ((phba->sli_rev < LPFC_SLI_REV4) ||
-           (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
-            LPFC_SLI_INTF_IF_TYPE_2))
-               return -EPERM;
-
-       if (!pdev->is_physfn)
-               return snprintf(buf, PAGE_SIZE, "%d\n", 0);
-
-       mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mboxq)
-               return -ENOMEM;
-
-       /* get the maximum number of virtfn support by physfn */
-       length = (sizeof(struct lpfc_mbx_get_prof_cfg) -
-                 sizeof(struct lpfc_sli4_cfg_mhdr));
-       lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON,
-                        LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG,
-                        length, LPFC_SLI4_MBX_EMBED);
-       shdr = (union lpfc_sli4_cfg_shdr *)
-               &mboxq->u.mqe.un.sli4_config.header.cfg_shdr;
-       bf_set(lpfc_mbox_hdr_pf_num, &shdr->request,
-              phba->sli4_hba.iov.pf_number + 1);
-
-       get_prof_cfg = &mboxq->u.mqe.un.get_prof_cfg;
-       bf_set(lpfc_mbx_get_prof_cfg_prof_tp, &get_prof_cfg->u.request,
-              LPFC_CFG_TYPE_CURRENT_ACTIVE);
-
-       rc = lpfc_sli_issue_mbox_wait(phba, mboxq,
-                               lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG));
-
-       if (rc != MBX_TIMEOUT) {
-               /* check return status */
-               shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
-               shdr_add_status = bf_get(lpfc_mbox_hdr_add_status,
-                                        &shdr->response);
-               if (shdr_status || shdr_add_status || rc)
-                       goto error_out;
-
-       } else
-               goto error_out;
-
-       desc_count = get_prof_cfg->u.response.prof_cfg.rsrc_desc_count;
-
-       for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) {
-               desc = (struct lpfc_rsrc_desc_pcie *)
-                       &get_prof_cfg->u.response.prof_cfg.desc[i];
-               if (LPFC_RSRC_DESC_TYPE_PCIE ==
-                   bf_get(lpfc_rsrc_desc_pcie_type, desc)) {
-                       max_nr_virtfn = bf_get(lpfc_rsrc_desc_pcie_nr_virtfn,
-                                              desc);
-                       break;
-               }
-       }
-
-       if (i < LPFC_RSRC_DESC_MAX_NUM) {
-               if (rc != MBX_TIMEOUT)
-                       mempool_free(mboxq, phba->mbox_mem_pool);
-               return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
-       }
+       uint16_t max_nr_virtfn;
 
-error_out:
-       if (rc != MBX_TIMEOUT)
-               mempool_free(mboxq, phba->mbox_mem_pool);
-       return -EIO;
+       max_nr_virtfn = lpfc_sli_sriov_nr_virtfn_get(phba);
+       return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);
 }
 
 /**
@@ -1605,6 +1596,9 @@ static int \
 lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \
 { \
        if (val >= minval && val <= maxval) {\
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \
+                       "3052 lpfc_" #attr " changed from %d to %d\n", \
+                       phba->cfg_##attr, val); \
                phba->cfg_##attr = val;\
                return 0;\
        }\
@@ -1762,6 +1756,9 @@ static int \
 lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \
 { \
        if (val >= minval && val <= maxval) {\
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \
+                       "3053 lpfc_" #attr " changed from %d to %d\n", \
+                       vport->cfg_##attr, val); \
                vport->cfg_##attr = val;\
                return 0;\
        }\
@@ -2196,6 +2193,9 @@ lpfc_param_show(enable_npiv);
 lpfc_param_init(enable_npiv, 1, 0, 1);
 static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
 
+LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2,
+       "FCF Fast failover=1 Priority failover=2");
+
 int lpfc_enable_rrq;
 module_param(lpfc_enable_rrq, int, S_IRUGO);
 MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality");
@@ -2678,6 +2678,9 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr,
                if (nolip)
                        return strlen(buf);
 
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                       "3054 lpfc_topology changed from %d to %d\n",
+                       prev_val, val);
                err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
                if (err) {
                        phba->cfg_topology = prev_val;
@@ -3101,6 +3104,10 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,
        if (sscanf(val_buf, "%i", &val) != 1)
                return -EINVAL;
 
+       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+               "3055 lpfc_link_speed changed from %d to %d %s\n",
+               phba->cfg_link_speed, val, nolip ? "(nolip)" : "(lip)");
+
        if (((val == LPFC_USER_LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
            ((val == LPFC_USER_LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
            ((val == LPFC_USER_LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
@@ -3678,7 +3685,9 @@ LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support");
 #      - Default will result in registering capabilities for all profiles.
 #
 */
-unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION;
+unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION |
+                             SHOST_DIX_TYPE0_PROTECTION |
+                             SHOST_DIX_TYPE1_PROTECTION;
 
 module_param(lpfc_prot_mask, uint, S_IRUGO);
 MODULE_PARM_DESC(lpfc_prot_mask, "host protection mask");
@@ -3769,6 +3778,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_lpfc_fdmi_on,
        &dev_attr_lpfc_max_luns,
        &dev_attr_lpfc_enable_npiv,
+       &dev_attr_lpfc_fcf_failover_policy,
        &dev_attr_lpfc_enable_rrq,
        &dev_attr_nport_evt_cnt,
        &dev_attr_board_mode,
@@ -4989,6 +4999,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_link_speed_init(phba, lpfc_link_speed);
        lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
        lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
+       lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
        lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
        lpfc_use_msi_init(phba, lpfc_use_msi);
        lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
index 7fb0ba4cbfa7048661bb616e5b8c5bdad5a09252..6760c69f525381f2d4c89be25ef7b4c5d5bc36ed 100644 (file)
@@ -42,6 +42,7 @@
 #include "lpfc.h"
 #include "lpfc_logmsg.h"
 #include "lpfc_crtn.h"
+#include "lpfc_debugfs.h"
 #include "lpfc_vport.h"
 #include "lpfc_version.h"
 
@@ -960,8 +961,10 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                                                    evt_dat->immed_dat].oxid,
                                                phba->ct_ctx[
                                                    evt_dat->immed_dat].SID);
+                       phba->ct_ctx[evt_dat->immed_dat].rxid =
+                               piocbq->iocb.ulpContext;
                        phba->ct_ctx[evt_dat->immed_dat].oxid =
-                                               piocbq->iocb.ulpContext;
+                               piocbq->iocb.unsli3.rcvsli3.ox_id;
                        phba->ct_ctx[evt_dat->immed_dat].SID =
                                piocbq->iocb.un.rcvels.remoteID;
                        phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID;
@@ -1312,7 +1315,8 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
                        rc = IOCB_ERROR;
                        goto issue_ct_rsp_exit;
                }
-               icmd->ulpContext = phba->ct_ctx[tag].oxid;
+               icmd->ulpContext = phba->ct_ctx[tag].rxid;
+               icmd->unsli3.rcvsli3.ox_id = phba->ct_ctx[tag].oxid;
                ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID);
                if (!ndlp) {
                        lpfc_printf_log(phba, KERN_WARNING, LOG_ELS,
@@ -1337,9 +1341,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
                        goto issue_ct_rsp_exit;
                }
 
-               icmd->un.ulpWord[3] = ndlp->nlp_rpi;
-               if (phba->sli_rev == LPFC_SLI_REV4)
-                       icmd->ulpContext =
+               icmd->un.ulpWord[3] =
                                phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
 
                /* The exchange is done, mark the entry as invalid */
@@ -1351,8 +1353,8 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
 
        /* Xmit CT response on exchange <xid> */
        lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-                       "2722 Xmit CT response on exchange x%x Data: x%x x%x\n",
-                       icmd->ulpContext, icmd->ulpIoTag, phba->link_state);
+               "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n",
+               icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state);
 
        ctiocb->iocb_cmpl = NULL;
        ctiocb->iocb_flag |= LPFC_IO_LIBDFC;
@@ -1471,13 +1473,12 @@ send_mgmt_rsp_exit:
 /**
  * lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode
  * @phba: Pointer to HBA context object.
- * @job: LPFC_BSG_VENDOR_DIAG_MODE
  *
  * This function is responsible for preparing driver for diag loopback
  * on device.
  */
 static int
-lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba, struct fc_bsg_job *job)
+lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba)
 {
        struct lpfc_vport **vports;
        struct Scsi_Host *shost;
@@ -1521,7 +1522,6 @@ lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba, struct fc_bsg_job *job)
 /**
  * lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode
  * @phba: Pointer to HBA context object.
- * @job: LPFC_BSG_VENDOR_DIAG_MODE
  *
  * This function is responsible for driver exit processing of setting up
  * diag loopback mode on device.
@@ -1567,7 +1567,7 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
        uint32_t link_flags;
        uint32_t timeout;
        LPFC_MBOXQ_t *pmboxq;
-       int mbxstatus;
+       int mbxstatus = MBX_SUCCESS;
        int i = 0;
        int rc = 0;
 
@@ -1586,7 +1586,7 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
                goto job_error;
        }
 
-       rc = lpfc_bsg_diag_mode_enter(phba, job);
+       rc = lpfc_bsg_diag_mode_enter(phba);
        if (rc)
                goto job_error;
 
@@ -1741,7 +1741,7 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
        uint32_t link_flags, timeout, req_len, alloc_len;
        struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback;
        LPFC_MBOXQ_t *pmboxq = NULL;
-       int mbxstatus, i, rc = 0;
+       int mbxstatus = MBX_SUCCESS, i, rc = 0;
 
        /* no data to return just the return code */
        job->reply->reply_payload_rcv_len = 0;
@@ -1758,7 +1758,7 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)
                goto job_error;
        }
 
-       rc = lpfc_bsg_diag_mode_enter(phba, job);
+       rc = lpfc_bsg_diag_mode_enter(phba);
        if (rc)
                goto job_error;
 
@@ -1982,7 +1982,7 @@ lpfc_sli4_bsg_link_diag_test(struct fc_bsg_job *job)
                goto job_error;
        }
 
-       rc = lpfc_bsg_diag_mode_enter(phba, job);
+       rc = lpfc_bsg_diag_mode_enter(phba);
        if (rc)
                goto job_error;
 
@@ -3178,6 +3178,11 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
                                "(x%x/x%x) complete bsg job done, bsize:%d\n",
                                phba->mbox_ext_buf_ctx.nembType,
                                phba->mbox_ext_buf_ctx.mboxType, size);
+               lpfc_idiag_mbxacc_dump_bsg_mbox(phba,
+                                       phba->mbox_ext_buf_ctx.nembType,
+                                       phba->mbox_ext_buf_ctx.mboxType,
+                                       dma_ebuf, sta_pos_addr,
+                                       phba->mbox_ext_buf_ctx.mbx_dmabuf, 0);
        } else
                spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
 
@@ -3430,6 +3435,10 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                                "ext_buf_cnt:%d\n", ext_buf_cnt);
        }
 
+       /* before dma descriptor setup */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox,
+                                       sta_pre_addr, dmabuf, ext_buf_cnt);
+
        /* reject non-embedded mailbox command with none external buffer */
        if (ext_buf_cnt == 0) {
                rc = -EPERM;
@@ -3477,6 +3486,10 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                }
        }
 
+       /* after dma descriptor setup */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox,
+                                       sta_pos_addr, dmabuf, ext_buf_cnt);
+
        /* construct base driver mbox command */
        pmb = &pmboxq->u.mb;
        pmbx = (uint8_t *)dmabuf->virt;
@@ -3511,7 +3524,7 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
                                "2947 Issued SLI_CONFIG ext-buffer "
                                "maibox command, rc:x%x\n", rc);
-               return 1;
+               return SLI_CONFIG_HANDLED;
        }
        lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
                        "2948 Failed to issue SLI_CONFIG ext-buffer "
@@ -3549,7 +3562,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
        LPFC_MBOXQ_t *pmboxq = NULL;
        MAILBOX_t *pmb;
        uint8_t *mbx;
-       int rc = 0, i;
+       int rc = SLI_CONFIG_NOT_HANDLED, i;
 
        mbox_req =
           (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;
@@ -3591,12 +3604,20 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                                "ext_buf_cnt:%d\n", ext_buf_cnt);
        }
 
+       /* before dma buffer descriptor setup */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox,
+                                       sta_pre_addr, dmabuf, ext_buf_cnt);
+
        if (ext_buf_cnt == 0)
                return -EPERM;
 
        /* for the first external buffer */
        lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf);
 
+       /* after dma descriptor setup */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox,
+                                       sta_pos_addr, dmabuf, ext_buf_cnt);
+
        /* log for looking forward */
        for (i = 1; i < ext_buf_cnt; i++) {
                if (nemb_tp == nemb_mse)
@@ -3660,7 +3681,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
                                        "2955 Issued SLI_CONFIG ext-buffer "
                                        "maibox command, rc:x%x\n", rc);
-                       return 1;
+                       return SLI_CONFIG_HANDLED;
                }
                lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
                                "2956 Failed to issue SLI_CONFIG ext-buffer "
@@ -3668,6 +3689,11 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                rc = -EPIPE;
        }
 
+       /* wait for additoinal external buffers */
+       job->reply->result = 0;
+       job->job_done(job);
+       return SLI_CONFIG_HANDLED;
+
 job_error:
        if (pmboxq)
                mempool_free(pmboxq, phba->mbox_mem_pool);
@@ -3840,6 +3866,12 @@ lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct fc_bsg_job *job)
        dmabuf = list_first_entry(&phba->mbox_ext_buf_ctx.ext_dmabuf_list,
                                  struct lpfc_dmabuf, list);
        list_del_init(&dmabuf->list);
+
+       /* after dma buffer descriptor setup */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType,
+                                       mbox_rd, dma_ebuf, sta_pos_addr,
+                                       dmabuf, index);
+
        pbuf = (uint8_t *)dmabuf->virt;
        job->reply->reply_payload_rcv_len =
                sg_copy_from_buffer(job->reply_payload.sg_list,
@@ -3922,6 +3954,11 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job,
                                        dmabuf);
        list_add_tail(&dmabuf->list, &phba->mbox_ext_buf_ctx.ext_dmabuf_list);
 
+       /* after write dma buffer */
+       lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType,
+                                       mbox_wr, dma_ebuf, sta_pos_addr,
+                                       dmabuf, index);
+
        if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) {
                lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
                                "2968 SLI_CONFIG ext-buffer wr all %d "
@@ -3959,7 +3996,7 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
                                        "2969 Issued SLI_CONFIG ext-buffer "
                                        "maibox command, rc:x%x\n", rc);
-                       return 1;
+                       return SLI_CONFIG_HANDLED;
                }
                lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
                                "2970 Failed to issue SLI_CONFIG ext-buffer "
@@ -4039,14 +4076,14 @@ lpfc_bsg_handle_sli_cfg_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
                            struct lpfc_dmabuf *dmabuf)
 {
        struct dfc_mbox_req *mbox_req;
-       int rc;
+       int rc = SLI_CONFIG_NOT_HANDLED;
 
        mbox_req =
           (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;
 
        /* mbox command with/without single external buffer */
        if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0)
-               return SLI_CONFIG_NOT_HANDLED;
+               return rc;
 
        /* mbox command and first external buffer */
        if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) {
@@ -4249,7 +4286,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                 * mailbox extension size
                 */
                if ((transmit_length > receive_length) ||
-                       (transmit_length > MAILBOX_EXT_SIZE)) {
+                       (transmit_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t))) {
                        rc = -ERANGE;
                        goto job_done;
                }
@@ -4272,7 +4309,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                /* receive length cannot be greater than mailbox
                 * extension size
                 */
-               if (receive_length > MAILBOX_EXT_SIZE) {
+               if (receive_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t)) {
                        rc = -ERANGE;
                        goto job_done;
                }
@@ -4306,7 +4343,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                        bde = (struct ulp_bde64 *)&pmb->un.varWords[4];
 
                        /* bde size cannot be greater than mailbox ext size */
-                       if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) {
+                       if (bde->tus.f.bdeSize >
+                           BSG_MBOX_SIZE - sizeof(MAILBOX_t)) {
                                rc = -ERANGE;
                                goto job_done;
                        }
@@ -4332,7 +4370,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
                                 * mailbox extension size
                                 */
                                if ((receive_length == 0) ||
-                                   (receive_length > MAILBOX_EXT_SIZE)) {
+                                   (receive_length >
+                                    BSG_MBOX_SIZE - sizeof(MAILBOX_t))) {
                                        rc = -ERANGE;
                                        goto job_done;
                                }
index fc20c247f36b7242b1643d0debef3785f1e95d3d..a6db6aef133193a22f810f6ddd0e0800bdbc7918 100644 (file)
@@ -235,9 +235,11 @@ int lpfc_sli4_redisc_fcf_table(struct lpfc_hba *);
 void lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *);
 void lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *);
 uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *);
+void lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *, uint16_t);
 int lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *, uint16_t);
 void lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *, uint16_t);
 int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t);
+void lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *);
 
 int lpfc_mem_alloc(struct lpfc_hba *, int align);
 void lpfc_mem_free(struct lpfc_hba *);
@@ -371,6 +373,10 @@ extern struct lpfc_hbq_init *lpfc_hbq_defs[];
 /* SLI4 if_type 2 externs. */
 int lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *);
 int lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *);
+int lpfc_sli4_get_allocated_extnts(struct lpfc_hba *, uint16_t,
+                                  uint16_t *, uint16_t *);
+int lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *, uint16_t,
+                                         uint16_t *, uint16_t *);
 
 /* externs BlockGuard */
 extern char *_dump_buf_data;
@@ -432,10 +438,16 @@ void lpfc_handle_rrq_active(struct lpfc_hba *);
 int lpfc_send_rrq(struct lpfc_hba *, struct lpfc_node_rrq *);
 int lpfc_set_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *,
        uint16_t, uint16_t, uint16_t);
+uint16_t lpfc_sli4_xri_inrange(struct lpfc_hba *, uint16_t);
 void lpfc_cleanup_wt_rrqs(struct lpfc_hba *);
 void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *);
 struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,
        uint32_t);
+void lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *, enum nemb_type,
+       enum mbox_type, enum dma_type, enum sta_type,
+       struct lpfc_dmabuf *, uint32_t);
+void lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *, MAILBOX_t *);
 int lpfc_wr_object(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t *);
 /* functions to support SR-IOV */
 int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int);
+uint16_t lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *);
index 30b25c5fdd7e2520c719b283af284016bf72b6e9..a0424dd90e4039863c272550e1263ce71c52c716 100644 (file)
@@ -48,6 +48,7 @@
 #include "lpfc_version.h"
 #include "lpfc_compat.h"
 #include "lpfc_debugfs.h"
+#include "lpfc_bsg.h"
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
 /*
@@ -135,7 +136,11 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
        int i, index, len, enable;
        uint32_t ms;
        struct lpfc_debugfs_trc *dtp;
-       char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE];
+       char *buffer;
+
+       buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL);
+       if (!buffer)
+               return 0;
 
        enable = lpfc_debugfs_enable;
        lpfc_debugfs_enable = 0;
@@ -167,6 +172,8 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
        }
 
        lpfc_debugfs_enable = enable;
+       kfree(buffer);
+
        return len;
 }
 
@@ -195,8 +202,11 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
        int i, index, len, enable;
        uint32_t ms;
        struct lpfc_debugfs_trc *dtp;
-       char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE];
+       char *buffer;
 
+       buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL);
+       if (!buffer)
+               return 0;
 
        enable = lpfc_debugfs_enable;
        lpfc_debugfs_enable = 0;
@@ -228,6 +238,8 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
        }
 
        lpfc_debugfs_enable = enable;
+       kfree(buffer);
+
        return len;
 }
 
@@ -378,7 +390,11 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
        int len = 0;
        int i, off;
        uint32_t *ptr;
-       char buffer[1024];
+       char *buffer;
+
+       buffer = kmalloc(1024, GFP_KERNEL);
+       if (!buffer)
+               return 0;
 
        off = 0;
        spin_lock_irq(&phba->hbalock);
@@ -407,6 +423,8 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
        }
 
        spin_unlock_irq(&phba->hbalock);
+       kfree(buffer);
+
        return len;
 }
 
@@ -1327,8 +1345,8 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes,
                return 0;
 
        if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) {
-               where = idiag.cmd.data[0];
-               count = idiag.cmd.data[1];
+               where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
+               count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
        } else
                return 0;
 
@@ -1373,6 +1391,11 @@ pcicfg_browse:
                len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
                                "%08x ", u32val);
                offset += sizeof(uint32_t);
+               if (offset >= LPFC_PCI_CFG_SIZE) {
+                       len += snprintf(pbuffer+len,
+                                       LPFC_PCI_CFG_SIZE-len, "\n");
+                       break;
+               }
                index -= sizeof(uint32_t);
                if (!index)
                        len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,
@@ -1385,8 +1408,11 @@ pcicfg_browse:
        }
 
        /* Set up the offset for next portion of pci cfg read */
-       idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE;
-       if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE)
+       if (index == 0) {
+               idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE;
+               if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE)
+                       idiag.offset.last_rd = 0;
+       } else
                idiag.offset.last_rd = 0;
 
        return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
@@ -1439,8 +1465,8 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf,
                if (rc != LPFC_PCI_CFG_RD_CMD_ARG)
                        goto error_out;
                /* Read command from PCI config space, set up command fields */
-               where = idiag.cmd.data[0];
-               count = idiag.cmd.data[1];
+               where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
+               count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
                if (count == LPFC_PCI_CFG_BROWSE) {
                        if (where % sizeof(uint32_t))
                                goto error_out;
@@ -1475,9 +1501,9 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf,
                if (rc != LPFC_PCI_CFG_WR_CMD_ARG)
                        goto error_out;
                /* Write command to PCI config space, read-modify-write */
-               where = idiag.cmd.data[0];
-               count = idiag.cmd.data[1];
-               value = idiag.cmd.data[2];
+               where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX];
+               count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];
+               value = idiag.cmd.data[IDIAG_PCICFG_VALUE_INDX];
                /* Sanity checks */
                if ((count != sizeof(uint8_t)) &&
                    (count != sizeof(uint16_t)) &&
@@ -1569,6 +1595,292 @@ error_out:
        return -EINVAL;
 }
 
+/**
+ * lpfc_idiag_baracc_read - idiag debugfs pci bar access read
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the data to.
+ * @nbytes: The number of bytes to read.
+ * @ppos: The position in the file to start reading from.
+ *
+ * Description:
+ * This routine reads data from the @phba pci bar memory mapped space
+ * according to the idiag command, and copies to user @buf.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static ssize_t
+lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes,
+                      loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       int offset_label, offset, offset_run, len = 0, index;
+       int bar_num, acc_range, bar_size;
+       char *pbuffer;
+       void __iomem *mem_mapped_bar;
+       uint32_t if_type;
+       struct pci_dev *pdev;
+       uint32_t u32val;
+
+       pdev = phba->pcidev;
+       if (!pdev)
+               return 0;
+
+       /* This is a user read operation */
+       debug->op = LPFC_IDIAG_OP_RD;
+
+       if (!debug->buffer)
+               debug->buffer = kmalloc(LPFC_PCI_BAR_RD_BUF_SIZE, GFP_KERNEL);
+       if (!debug->buffer)
+               return 0;
+       pbuffer = debug->buffer;
+
+       if (*ppos)
+               return 0;
+
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) {
+               bar_num   = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX];
+               offset    = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX];
+               acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX];
+               bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX];
+       } else
+               return 0;
+
+       if (acc_range == 0)
+               return 0;
+
+       if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+       if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
+               if (bar_num == IDIAG_BARACC_BAR_0)
+                       mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
+               else if (bar_num == IDIAG_BARACC_BAR_1)
+                       mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p;
+               else if (bar_num == IDIAG_BARACC_BAR_2)
+                       mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p;
+               else
+                       return 0;
+       } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+               if (bar_num == IDIAG_BARACC_BAR_0)
+                       mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
+               else
+                       return 0;
+       } else
+               return 0;
+
+       /* Read single PCI bar space register */
+       if (acc_range == SINGLE_WORD) {
+               offset_run = offset;
+               u32val = readl(mem_mapped_bar + offset_run);
+               len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
+                               "%05x: %08x\n", offset_run, u32val);
+       } else
+               goto baracc_browse;
+
+       return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+
+baracc_browse:
+
+       /* Browse all PCI bar space registers */
+       offset_label = idiag.offset.last_rd;
+       offset_run = offset_label;
+
+       /* Read PCI bar memory mapped space */
+       len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
+                       "%05x: ", offset_label);
+       index = LPFC_PCI_BAR_RD_SIZE;
+       while (index > 0) {
+               u32val = readl(mem_mapped_bar + offset_run);
+               len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len,
+                               "%08x ", u32val);
+               offset_run += sizeof(uint32_t);
+               if (acc_range == LPFC_PCI_BAR_BROWSE) {
+                       if (offset_run >= bar_size) {
+                               len += snprintf(pbuffer+len,
+                                       LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
+                               break;
+                       }
+               } else {
+                       if (offset_run >= offset +
+                           (acc_range * sizeof(uint32_t))) {
+                               len += snprintf(pbuffer+len,
+                                       LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
+                               break;
+                       }
+               }
+               index -= sizeof(uint32_t);
+               if (!index)
+                       len += snprintf(pbuffer+len,
+                                       LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n");
+               else if (!(index % (8 * sizeof(uint32_t)))) {
+                       offset_label += (8 * sizeof(uint32_t));
+                       len += snprintf(pbuffer+len,
+                                       LPFC_PCI_BAR_RD_BUF_SIZE-len,
+                                       "\n%05x: ", offset_label);
+               }
+       }
+
+       /* Set up the offset for next portion of pci bar read */
+       if (index == 0) {
+               idiag.offset.last_rd += LPFC_PCI_BAR_RD_SIZE;
+               if (acc_range == LPFC_PCI_BAR_BROWSE) {
+                       if (idiag.offset.last_rd >= bar_size)
+                               idiag.offset.last_rd = 0;
+               } else {
+                       if (offset_run >= offset +
+                           (acc_range * sizeof(uint32_t)))
+                               idiag.offset.last_rd = offset;
+               }
+       } else {
+               if (acc_range == LPFC_PCI_BAR_BROWSE)
+                       idiag.offset.last_rd = 0;
+               else
+                       idiag.offset.last_rd = offset;
+       }
+
+       return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+}
+
+/**
+ * lpfc_idiag_baracc_write - Syntax check and set up idiag bar access commands
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the user data from.
+ * @nbytes: The number of bytes to get.
+ * @ppos: The position in the file to start reading from.
+ *
+ * This routine get the debugfs idiag command struct from user space and
+ * then perform the syntax check for PCI bar memory mapped space read or
+ * write command accordingly. In the case of PCI bar memory mapped space
+ * read command, it sets up the command in the idiag command struct for
+ * the debugfs read operation. In the case of PCI bar memorpy mapped space
+ * write operation, it executes the write operation into the PCI bar memory
+ * mapped space accordingly.
+ *
+ * It returns the @nbytges passing in from debugfs user space when successful.
+ * In case of error conditions, it returns proper error code back to the user
+ * space.
+ */
+static ssize_t
+lpfc_idiag_baracc_write(struct file *file, const char __user *buf,
+                       size_t nbytes, loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       uint32_t bar_num, bar_size, offset, value, acc_range;
+       struct pci_dev *pdev;
+       void __iomem *mem_mapped_bar;
+       uint32_t if_type;
+       uint32_t u32val;
+       int rc;
+
+       pdev = phba->pcidev;
+       if (!pdev)
+               return -EFAULT;
+
+       /* This is a user write operation */
+       debug->op = LPFC_IDIAG_OP_WR;
+
+       rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
+       if (rc < 0)
+               return rc;
+
+       if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
+       bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX];
+
+       if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
+               if ((bar_num != IDIAG_BARACC_BAR_0) &&
+                   (bar_num != IDIAG_BARACC_BAR_1) &&
+                   (bar_num != IDIAG_BARACC_BAR_2))
+                       goto error_out;
+       } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+               if (bar_num != IDIAG_BARACC_BAR_0)
+                       goto error_out;
+       } else
+               goto error_out;
+
+       if (if_type == LPFC_SLI_INTF_IF_TYPE_0) {
+               if (bar_num == IDIAG_BARACC_BAR_0) {
+                       idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
+                               LPFC_PCI_IF0_BAR0_SIZE;
+                       mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
+               } else if (bar_num == IDIAG_BARACC_BAR_1) {
+                       idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
+                               LPFC_PCI_IF0_BAR1_SIZE;
+                       mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p;
+               } else if (bar_num == IDIAG_BARACC_BAR_2) {
+                       idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
+                               LPFC_PCI_IF0_BAR2_SIZE;
+                       mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p;
+               } else
+                       goto error_out;
+       } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
+               if (bar_num == IDIAG_BARACC_BAR_0) {
+                       idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] =
+                               LPFC_PCI_IF2_BAR0_SIZE;
+                       mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p;
+               } else
+                       goto error_out;
+       } else
+               goto error_out;
+
+       offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX];
+       if (offset % sizeof(uint32_t))
+               goto error_out;
+
+       bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX];
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) {
+               /* Sanity check on PCI config read command line arguments */
+               if (rc != LPFC_PCI_BAR_RD_CMD_ARG)
+                       goto error_out;
+               acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX];
+               if (acc_range == LPFC_PCI_BAR_BROWSE) {
+                       if (offset > bar_size - sizeof(uint32_t))
+                               goto error_out;
+                       /* Starting offset to browse */
+                       idiag.offset.last_rd = offset;
+               } else if (acc_range > SINGLE_WORD) {
+                       if (offset + acc_range * sizeof(uint32_t) > bar_size)
+                               goto error_out;
+                       /* Starting offset to browse */
+                       idiag.offset.last_rd = offset;
+               } else if (acc_range != SINGLE_WORD)
+                       goto error_out;
+       } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR ||
+                  idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST ||
+                  idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) {
+               /* Sanity check on PCI bar write command line arguments */
+               if (rc != LPFC_PCI_BAR_WR_CMD_ARG)
+                       goto error_out;
+               /* Write command to PCI bar space, read-modify-write */
+               acc_range = SINGLE_WORD;
+               value = idiag.cmd.data[IDIAG_BARACC_REG_VAL_INDX];
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR) {
+                       writel(value, mem_mapped_bar + offset);
+                       readl(mem_mapped_bar + offset);
+               }
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST) {
+                       u32val = readl(mem_mapped_bar + offset);
+                       u32val |= value;
+                       writel(u32val, mem_mapped_bar + offset);
+                       readl(mem_mapped_bar + offset);
+               }
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) {
+                       u32val = readl(mem_mapped_bar + offset);
+                       u32val &= ~value;
+                       writel(u32val, mem_mapped_bar + offset);
+                       readl(mem_mapped_bar + offset);
+               }
+       } else
+               /* All other opecodes are illegal for now */
+               goto error_out;
+
+       return nbytes;
+error_out:
+       memset(&idiag, 0, sizeof(idiag));
+       return -EINVAL;
+}
+
 /**
  * lpfc_idiag_queinfo_read - idiag debugfs read queue information
  * @file: The file pointer to read from.
@@ -1871,8 +2183,8 @@ lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes,
                return 0;
 
        if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) {
-               index = idiag.cmd.data[2];
-               count = idiag.cmd.data[3];
+               index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX];
+               count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];
                pque = (struct lpfc_queue *)idiag.ptr_private;
        } else
                return 0;
@@ -1944,12 +2256,12 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf,
                return rc;
 
        /* Get and sanity check on command feilds */
-       quetp  = idiag.cmd.data[0];
-       queid  = idiag.cmd.data[1];
-       index  = idiag.cmd.data[2];
-       count  = idiag.cmd.data[3];
-       offset = idiag.cmd.data[4];
-       value  = idiag.cmd.data[5];
+       quetp  = idiag.cmd.data[IDIAG_QUEACC_QUETP_INDX];
+       queid  = idiag.cmd.data[IDIAG_QUEACC_QUEID_INDX];
+       index  = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX];
+       count  = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];
+       offset = idiag.cmd.data[IDIAG_QUEACC_OFFST_INDX];
+       value  = idiag.cmd.data[IDIAG_QUEACC_VALUE_INDX];
 
        /* Sanity check on command line arguments */
        if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR ||
@@ -2218,7 +2530,7 @@ lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes,
                return 0;
 
        if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD)
-               drb_reg_id = idiag.cmd.data[0];
+               drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];
        else
                return 0;
 
@@ -2257,7 +2569,7 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,
 {
        struct lpfc_debug *debug = file->private_data;
        struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
-       uint32_t drb_reg_id, value, reg_val;
+       uint32_t drb_reg_id, value, reg_val = 0;
        void __iomem *drb_reg;
        int rc;
 
@@ -2269,8 +2581,8 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,
                return rc;
 
        /* Sanity check on command line arguments */
-       drb_reg_id = idiag.cmd.data[0];
-       value = idiag.cmd.data[1];
+       drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];
+       value = idiag.cmd.data[IDIAG_DRBACC_VALUE_INDX];
 
        if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR ||
            idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST ||
@@ -2330,63 +2642,736 @@ error_out:
        return -EINVAL;
 }
 
-#undef lpfc_debugfs_op_disc_trc
-static const struct file_operations lpfc_debugfs_op_disc_trc = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_disc_trc_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .release =      lpfc_debugfs_release,
-};
+/**
+ * lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers
+ * @phba: The pointer to hba structure.
+ * @pbuffer: The pointer to the buffer to copy the data to.
+ * @len: The lenght of bytes to copied.
+ * @drbregid: The id to doorbell registers.
+ *
+ * Description:
+ * This routine reads a control register and copies its content to the
+ * user buffer pointed to by @pbuffer.
+ *
+ * Returns:
+ * This function returns the amount of data that was copied into @pbuffer.
+ **/
+static int
+lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer,
+                          int len, uint32_t ctlregid)
+{
 
-#undef lpfc_debugfs_op_nodelist
-static const struct file_operations lpfc_debugfs_op_nodelist = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_nodelist_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .release =      lpfc_debugfs_release,
-};
+       if (!pbuffer)
+               return 0;
 
-#undef lpfc_debugfs_op_hbqinfo
-static const struct file_operations lpfc_debugfs_op_hbqinfo = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_hbqinfo_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .release =      lpfc_debugfs_release,
-};
+       switch (ctlregid) {
+       case LPFC_CTL_PORT_SEM:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "Port SemReg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PORT_SEM_OFFSET));
+               break;
+       case LPFC_CTL_PORT_STA:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "Port StaReg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PORT_STA_OFFSET));
+               break;
+       case LPFC_CTL_PORT_CTL:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "Port CtlReg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PORT_CTL_OFFSET));
+               break;
+       case LPFC_CTL_PORT_ER1:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "Port Er1Reg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PORT_ER1_OFFSET));
+               break;
+       case LPFC_CTL_PORT_ER2:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "Port Er2Reg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PORT_ER2_OFFSET));
+               break;
+       case LPFC_CTL_PDEV_CTL:
+               len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len,
+                               "PDev CtlReg:   0x%08x\n",
+                               readl(phba->sli4_hba.conf_regs_memmap_p +
+                                     LPFC_CTL_PDEV_CTL_OFFSET));
+               break;
+       default:
+               break;
+       }
+       return len;
+}
 
-#undef lpfc_debugfs_op_dumpHBASlim
-static const struct file_operations lpfc_debugfs_op_dumpHBASlim = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_dumpHBASlim_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .release =      lpfc_debugfs_release,
-};
+/**
+ * lpfc_idiag_ctlacc_read - idiag debugfs read port and device control register
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the data to.
+ * @nbytes: The number of bytes to read.
+ * @ppos: The position in the file to start reading from.
+ *
+ * Description:
+ * This routine reads data from the @phba port and device registers according
+ * to the idiag command, and copies to user @buf.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static ssize_t
+lpfc_idiag_ctlacc_read(struct file *file, char __user *buf, size_t nbytes,
+                      loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       uint32_t ctl_reg_id, i;
+       char *pbuffer;
+       int len = 0;
 
-#undef lpfc_debugfs_op_dumpHostSlim
-static const struct file_operations lpfc_debugfs_op_dumpHostSlim = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_dumpHostSlim_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .release =      lpfc_debugfs_release,
-};
+       /* This is a user read operation */
+       debug->op = LPFC_IDIAG_OP_RD;
 
-#undef lpfc_debugfs_op_dumpData
-static const struct file_operations lpfc_debugfs_op_dumpData = {
-       .owner =        THIS_MODULE,
-       .open =         lpfc_debugfs_dumpData_open,
-       .llseek =       lpfc_debugfs_lseek,
-       .read =         lpfc_debugfs_read,
-       .write =        lpfc_debugfs_dumpDataDif_write,
-       .release =      lpfc_debugfs_dumpDataDif_release,
-};
+       if (!debug->buffer)
+               debug->buffer = kmalloc(LPFC_CTL_ACC_BUF_SIZE, GFP_KERNEL);
+       if (!debug->buffer)
+               return 0;
+       pbuffer = debug->buffer;
 
-#undef lpfc_debugfs_op_dumpDif
-static const struct file_operations lpfc_debugfs_op_dumpDif = {
+       if (*ppos)
+               return 0;
+
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD)
+               ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX];
+       else
+               return 0;
+
+       if (ctl_reg_id == LPFC_CTL_ACC_ALL)
+               for (i = 1; i <= LPFC_CTL_MAX; i++)
+                       len = lpfc_idiag_ctlacc_read_reg(phba,
+                                                        pbuffer, len, i);
+       else
+               len = lpfc_idiag_ctlacc_read_reg(phba,
+                                                pbuffer, len, ctl_reg_id);
+
+       return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+}
+
+/**
+ * lpfc_idiag_ctlacc_write - Syntax check and set up idiag ctlacc commands
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the user data from.
+ * @nbytes: The number of bytes to get.
+ * @ppos: The position in the file to start reading from.
+ *
+ * This routine get the debugfs idiag command struct from user space and then
+ * perform the syntax check for port and device control register read (dump)
+ * or write (set) command accordingly.
+ *
+ * It returns the @nbytges passing in from debugfs user space when successful.
+ * In case of error conditions, it returns proper error code back to the user
+ * space.
+ **/
+static ssize_t
+lpfc_idiag_ctlacc_write(struct file *file, const char __user *buf,
+                       size_t nbytes, loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       uint32_t ctl_reg_id, value, reg_val = 0;
+       void __iomem *ctl_reg;
+       int rc;
+
+       /* This is a user write operation */
+       debug->op = LPFC_IDIAG_OP_WR;
+
+       rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
+       if (rc < 0)
+               return rc;
+
+       /* Sanity check on command line arguments */
+       ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX];
+       value = idiag.cmd.data[IDIAG_CTLACC_VALUE_INDX];
+
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR ||
+           idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST ||
+           idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
+               if (rc != LPFC_CTL_ACC_WR_CMD_ARG)
+                       goto error_out;
+               if (ctl_reg_id > LPFC_CTL_MAX)
+                       goto error_out;
+       } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) {
+               if (rc != LPFC_CTL_ACC_RD_CMD_ARG)
+                       goto error_out;
+               if ((ctl_reg_id > LPFC_CTL_MAX) &&
+                   (ctl_reg_id != LPFC_CTL_ACC_ALL))
+                       goto error_out;
+       } else
+               goto error_out;
+
+       /* Perform the write access operation */
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR ||
+           idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST ||
+           idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
+               switch (ctl_reg_id) {
+               case LPFC_CTL_PORT_SEM:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PORT_SEM_OFFSET;
+                       break;
+               case LPFC_CTL_PORT_STA:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PORT_STA_OFFSET;
+                       break;
+               case LPFC_CTL_PORT_CTL:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PORT_CTL_OFFSET;
+                       break;
+               case LPFC_CTL_PORT_ER1:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PORT_ER1_OFFSET;
+                       break;
+               case LPFC_CTL_PORT_ER2:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PORT_ER2_OFFSET;
+                       break;
+               case LPFC_CTL_PDEV_CTL:
+                       ctl_reg = phba->sli4_hba.conf_regs_memmap_p +
+                                       LPFC_CTL_PDEV_CTL_OFFSET;
+                       break;
+               default:
+                       goto error_out;
+               }
+
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR)
+                       reg_val = value;
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST) {
+                       reg_val = readl(ctl_reg);
+                       reg_val |= value;
+               }
+               if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) {
+                       reg_val = readl(ctl_reg);
+                       reg_val &= ~value;
+               }
+               writel(reg_val, ctl_reg);
+               readl(ctl_reg); /* flush */
+       }
+       return nbytes;
+
+error_out:
+       /* Clean out command structure on command error out */
+       memset(&idiag, 0, sizeof(idiag));
+       return -EINVAL;
+}
+
+/**
+ * lpfc_idiag_mbxacc_get_setup - idiag debugfs get mailbox access setup
+ * @phba: Pointer to HBA context object.
+ * @pbuffer: Pointer to data buffer.
+ *
+ * Description:
+ * This routine gets the driver mailbox access debugfs setup information.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static int
+lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer)
+{
+       uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd;
+       int len = 0;
+
+       mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
+       mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
+       mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
+       mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
+
+       len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+                       "mbx_dump_map: 0x%08x\n", mbx_dump_map);
+       len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+                       "mbx_dump_cnt: %04d\n", mbx_dump_cnt);
+       len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+                       "mbx_word_cnt: %04d\n", mbx_word_cnt);
+       len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len,
+                       "mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd);
+
+       return len;
+}
+
+/**
+ * lpfc_idiag_mbxacc_read - idiag debugfs read on mailbox access
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the data to.
+ * @nbytes: The number of bytes to read.
+ * @ppos: The position in the file to start reading from.
+ *
+ * Description:
+ * This routine reads data from the @phba driver mailbox access debugfs setup
+ * information.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static ssize_t
+lpfc_idiag_mbxacc_read(struct file *file, char __user *buf, size_t nbytes,
+                      loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       char *pbuffer;
+       int len = 0;
+
+       /* This is a user read operation */
+       debug->op = LPFC_IDIAG_OP_RD;
+
+       if (!debug->buffer)
+               debug->buffer = kmalloc(LPFC_MBX_ACC_BUF_SIZE, GFP_KERNEL);
+       if (!debug->buffer)
+               return 0;
+       pbuffer = debug->buffer;
+
+       if (*ppos)
+               return 0;
+
+       if ((idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) &&
+           (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP))
+               return 0;
+
+       len = lpfc_idiag_mbxacc_get_setup(phba, pbuffer);
+
+       return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+}
+
+/**
+ * lpfc_idiag_mbxacc_write - Syntax check and set up idiag mbxacc commands
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the user data from.
+ * @nbytes: The number of bytes to get.
+ * @ppos: The position in the file to start reading from.
+ *
+ * This routine get the debugfs idiag command struct from user space and then
+ * perform the syntax check for driver mailbox command (dump) and sets up the
+ * necessary states in the idiag command struct accordingly.
+ *
+ * It returns the @nbytges passing in from debugfs user space when successful.
+ * In case of error conditions, it returns proper error code back to the user
+ * space.
+ **/
+static ssize_t
+lpfc_idiag_mbxacc_write(struct file *file, const char __user *buf,
+                       size_t nbytes, loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd;
+       int rc;
+
+       /* This is a user write operation */
+       debug->op = LPFC_IDIAG_OP_WR;
+
+       rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
+       if (rc < 0)
+               return rc;
+
+       /* Sanity check on command line arguments */
+       mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
+       mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
+       mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
+       mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
+
+       if (idiag.cmd.opcode == LPFC_IDIAG_CMD_MBXACC_DP) {
+               if (!(mbx_dump_map & LPFC_MBX_DMP_MBX_ALL))
+                       goto error_out;
+               if ((mbx_dump_map & ~LPFC_MBX_DMP_MBX_ALL) &&
+                   (mbx_dump_map != LPFC_MBX_DMP_ALL))
+                       goto error_out;
+               if (mbx_word_cnt > sizeof(MAILBOX_t))
+                       goto error_out;
+       } else if (idiag.cmd.opcode == LPFC_IDIAG_BSG_MBXACC_DP) {
+               if (!(mbx_dump_map & LPFC_BSG_DMP_MBX_ALL))
+                       goto error_out;
+               if ((mbx_dump_map & ~LPFC_BSG_DMP_MBX_ALL) &&
+                   (mbx_dump_map != LPFC_MBX_DMP_ALL))
+                       goto error_out;
+               if (mbx_word_cnt > (BSG_MBOX_SIZE)/4)
+                       goto error_out;
+               if (mbx_mbox_cmd != 0x9b)
+                       goto error_out;
+       } else
+               goto error_out;
+
+       if (mbx_word_cnt == 0)
+               goto error_out;
+       if (rc != LPFC_MBX_DMP_ARG)
+               goto error_out;
+       if (mbx_mbox_cmd & ~0xff)
+               goto error_out;
+
+       /* condition for stop mailbox dump */
+       if (mbx_dump_cnt == 0)
+               goto reset_out;
+
+       return nbytes;
+
+reset_out:
+       /* Clean out command structure on command error out */
+       memset(&idiag, 0, sizeof(idiag));
+       return nbytes;
+
+error_out:
+       /* Clean out command structure on command error out */
+       memset(&idiag, 0, sizeof(idiag));
+       return -EINVAL;
+}
+
+/**
+ * lpfc_idiag_extacc_avail_get - get the available extents information
+ * @phba: pointer to lpfc hba data structure.
+ * @pbuffer: pointer to internal buffer.
+ * @len: length into the internal buffer data has been copied.
+ *
+ * Description:
+ * This routine is to get the available extent information.
+ *
+ * Returns:
+ * overall lenth of the data read into the internal buffer.
+ **/
+static int
+lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len)
+{
+       uint16_t ext_cnt, ext_size;
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\nAvailable Extents Information:\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tPort Available VPI extents: ");
+       lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI,
+                                      &ext_cnt, &ext_size);
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "Count %3d, Size %3d\n", ext_cnt, ext_size);
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tPort Available VFI extents: ");
+       lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI,
+                                      &ext_cnt, &ext_size);
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "Count %3d, Size %3d\n", ext_cnt, ext_size);
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tPort Available RPI extents: ");
+       lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI,
+                                      &ext_cnt, &ext_size);
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "Count %3d, Size %3d\n", ext_cnt, ext_size);
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tPort Available XRI extents: ");
+       lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI,
+                                      &ext_cnt, &ext_size);
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "Count %3d, Size %3d\n", ext_cnt, ext_size);
+
+       return len;
+}
+
+/**
+ * lpfc_idiag_extacc_alloc_get - get the allocated extents information
+ * @phba: pointer to lpfc hba data structure.
+ * @pbuffer: pointer to internal buffer.
+ * @len: length into the internal buffer data has been copied.
+ *
+ * Description:
+ * This routine is to get the allocated extent information.
+ *
+ * Returns:
+ * overall lenth of the data read into the internal buffer.
+ **/
+static int
+lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len)
+{
+       uint16_t ext_cnt, ext_size;
+       int rc;
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\nAllocated Extents Information:\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tHost Allocated VPI extents: ");
+       rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI,
+                                           &ext_cnt, &ext_size);
+       if (!rc)
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "Port %d Extent %3d, Size %3d\n",
+                               phba->brd_no, ext_cnt, ext_size);
+       else
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "N/A\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tHost Allocated VFI extents: ");
+       rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI,
+                                           &ext_cnt, &ext_size);
+       if (!rc)
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "Port %d Extent %3d, Size %3d\n",
+                               phba->brd_no, ext_cnt, ext_size);
+       else
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "N/A\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tHost Allocated RPI extents: ");
+       rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI,
+                                           &ext_cnt, &ext_size);
+       if (!rc)
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "Port %d Extent %3d, Size %3d\n",
+                               phba->brd_no, ext_cnt, ext_size);
+       else
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "N/A\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tHost Allocated XRI extents: ");
+       rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI,
+                                           &ext_cnt, &ext_size);
+       if (!rc)
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "Port %d Extent %3d, Size %3d\n",
+                               phba->brd_no, ext_cnt, ext_size);
+       else
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "N/A\n");
+
+       return len;
+}
+
+/**
+ * lpfc_idiag_extacc_drivr_get - get driver extent information
+ * @phba: pointer to lpfc hba data structure.
+ * @pbuffer: pointer to internal buffer.
+ * @len: length into the internal buffer data has been copied.
+ *
+ * Description:
+ * This routine is to get the driver extent information.
+ *
+ * Returns:
+ * overall lenth of the data read into the internal buffer.
+ **/
+static int
+lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len)
+{
+       struct lpfc_rsrc_blks *rsrc_blks;
+       int index;
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\nDriver Extents Information:\n");
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tVPI extents:\n");
+       index = 0;
+       list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) {
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "\t\tBlock %3d: Start %4d, Count %4d\n",
+                               index, rsrc_blks->rsrc_start,
+                               rsrc_blks->rsrc_size);
+               index++;
+       }
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tVFI extents:\n");
+       index = 0;
+       list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list,
+                           list) {
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "\t\tBlock %3d: Start %4d, Count %4d\n",
+                               index, rsrc_blks->rsrc_start,
+                               rsrc_blks->rsrc_size);
+               index++;
+       }
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tRPI extents:\n");
+       index = 0;
+       list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list,
+                           list) {
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "\t\tBlock %3d: Start %4d, Count %4d\n",
+                               index, rsrc_blks->rsrc_start,
+                               rsrc_blks->rsrc_size);
+               index++;
+       }
+
+       len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                       "\tXRI extents:\n");
+       index = 0;
+       list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list,
+                           list) {
+               len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len,
+                               "\t\tBlock %3d: Start %4d, Count %4d\n",
+                               index, rsrc_blks->rsrc_start,
+                               rsrc_blks->rsrc_size);
+               index++;
+       }
+
+       return len;
+}
+
+/**
+ * lpfc_idiag_extacc_write - Syntax check and set up idiag extacc commands
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the user data from.
+ * @nbytes: The number of bytes to get.
+ * @ppos: The position in the file to start reading from.
+ *
+ * This routine get the debugfs idiag command struct from user space and then
+ * perform the syntax check for extent information access commands and sets
+ * up the necessary states in the idiag command struct accordingly.
+ *
+ * It returns the @nbytges passing in from debugfs user space when successful.
+ * In case of error conditions, it returns proper error code back to the user
+ * space.
+ **/
+static ssize_t
+lpfc_idiag_extacc_write(struct file *file, const char __user *buf,
+                       size_t nbytes, loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       uint32_t ext_map;
+       int rc;
+
+       /* This is a user write operation */
+       debug->op = LPFC_IDIAG_OP_WR;
+
+       rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd);
+       if (rc < 0)
+               return rc;
+
+       ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX];
+
+       if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD)
+               goto error_out;
+       if (rc != LPFC_EXT_ACC_CMD_ARG)
+               goto error_out;
+       if (!(ext_map & LPFC_EXT_ACC_ALL))
+               goto error_out;
+
+       return nbytes;
+error_out:
+       /* Clean out command structure on command error out */
+       memset(&idiag, 0, sizeof(idiag));
+       return -EINVAL;
+}
+
+/**
+ * lpfc_idiag_extacc_read - idiag debugfs read access to extent information
+ * @file: The file pointer to read from.
+ * @buf: The buffer to copy the data to.
+ * @nbytes: The number of bytes to read.
+ * @ppos: The position in the file to start reading from.
+ *
+ * Description:
+ * This routine reads data from the proper extent information according to
+ * the idiag command, and copies to user @buf.
+ *
+ * Returns:
+ * This function returns the amount of data that was read (this could be less
+ * than @nbytes if the end of the file was reached) or a negative error value.
+ **/
+static ssize_t
+lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes,
+                      loff_t *ppos)
+{
+       struct lpfc_debug *debug = file->private_data;
+       struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private;
+       char *pbuffer;
+       uint32_t ext_map;
+       int len = 0;
+
+       /* This is a user read operation */
+       debug->op = LPFC_IDIAG_OP_RD;
+
+       if (!debug->buffer)
+               debug->buffer = kmalloc(LPFC_EXT_ACC_BUF_SIZE, GFP_KERNEL);
+       if (!debug->buffer)
+               return 0;
+       pbuffer = debug->buffer;
+       if (*ppos)
+               return 0;
+       if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD)
+               return 0;
+
+       ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX];
+       if (ext_map & LPFC_EXT_ACC_AVAIL)
+               len = lpfc_idiag_extacc_avail_get(phba, pbuffer, len);
+       if (ext_map & LPFC_EXT_ACC_ALLOC)
+               len = lpfc_idiag_extacc_alloc_get(phba, pbuffer, len);
+       if (ext_map & LPFC_EXT_ACC_DRIVR)
+               len = lpfc_idiag_extacc_drivr_get(phba, pbuffer, len);
+
+       return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len);
+}
+
+#undef lpfc_debugfs_op_disc_trc
+static const struct file_operations lpfc_debugfs_op_disc_trc = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_disc_trc_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_nodelist
+static const struct file_operations lpfc_debugfs_op_nodelist = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_nodelist_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_hbqinfo
+static const struct file_operations lpfc_debugfs_op_hbqinfo = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_hbqinfo_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpHBASlim
+static const struct file_operations lpfc_debugfs_op_dumpHBASlim = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_dumpHBASlim_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpHostSlim
+static const struct file_operations lpfc_debugfs_op_dumpHostSlim = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_dumpHostSlim_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpData
+static const struct file_operations lpfc_debugfs_op_dumpData = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_debugfs_dumpData_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_debugfs_read,
+       .write =        lpfc_debugfs_dumpDataDif_write,
+       .release =      lpfc_debugfs_dumpDataDif_release,
+};
+
+#undef lpfc_debugfs_op_dumpDif
+static const struct file_operations lpfc_debugfs_op_dumpDif = {
        .owner =        THIS_MODULE,
        .open =         lpfc_debugfs_dumpDif_open,
        .llseek =       lpfc_debugfs_lseek,
@@ -2420,6 +3405,16 @@ static const struct file_operations lpfc_idiag_op_pciCfg = {
        .release =      lpfc_idiag_cmd_release,
 };
 
+#undef lpfc_idiag_op_barAcc
+static const struct file_operations lpfc_idiag_op_barAcc = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_idiag_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_idiag_baracc_read,
+       .write =        lpfc_idiag_baracc_write,
+       .release =      lpfc_idiag_cmd_release,
+};
+
 #undef lpfc_idiag_op_queInfo
 static const struct file_operations lpfc_idiag_op_queInfo = {
        .owner =        THIS_MODULE,
@@ -2428,7 +3423,7 @@ static const struct file_operations lpfc_idiag_op_queInfo = {
        .release =      lpfc_idiag_release,
 };
 
-#undef lpfc_idiag_op_queacc
+#undef lpfc_idiag_op_queAcc
 static const struct file_operations lpfc_idiag_op_queAcc = {
        .owner =        THIS_MODULE,
        .open =         lpfc_idiag_open,
@@ -2438,7 +3433,7 @@ static const struct file_operations lpfc_idiag_op_queAcc = {
        .release =      lpfc_idiag_cmd_release,
 };
 
-#undef lpfc_idiag_op_drbacc
+#undef lpfc_idiag_op_drbAcc
 static const struct file_operations lpfc_idiag_op_drbAcc = {
        .owner =        THIS_MODULE,
        .open =         lpfc_idiag_open,
@@ -2448,8 +3443,234 @@ static const struct file_operations lpfc_idiag_op_drbAcc = {
        .release =      lpfc_idiag_cmd_release,
 };
 
+#undef lpfc_idiag_op_ctlAcc
+static const struct file_operations lpfc_idiag_op_ctlAcc = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_idiag_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_idiag_ctlacc_read,
+       .write =        lpfc_idiag_ctlacc_write,
+       .release =      lpfc_idiag_cmd_release,
+};
+
+#undef lpfc_idiag_op_mbxAcc
+static const struct file_operations lpfc_idiag_op_mbxAcc = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_idiag_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_idiag_mbxacc_read,
+       .write =        lpfc_idiag_mbxacc_write,
+       .release =      lpfc_idiag_cmd_release,
+};
+
+#undef lpfc_idiag_op_extAcc
+static const struct file_operations lpfc_idiag_op_extAcc = {
+       .owner =        THIS_MODULE,
+       .open =         lpfc_idiag_open,
+       .llseek =       lpfc_debugfs_lseek,
+       .read =         lpfc_idiag_extacc_read,
+       .write =        lpfc_idiag_extacc_write,
+       .release =      lpfc_idiag_cmd_release,
+};
+
 #endif
 
+/* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command
+ * @phba: Pointer to HBA context object.
+ * @dmabuf: Pointer to a DMA buffer descriptor.
+ *
+ * Description:
+ * This routine dump a bsg pass-through non-embedded mailbox command with
+ * external buffer.
+ **/
+void
+lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp,
+                               enum mbox_type mbox_tp, enum dma_type dma_tp,
+                               enum sta_type sta_tp,
+                               struct lpfc_dmabuf *dmabuf, uint32_t ext_buf)
+{
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       uint32_t *mbx_mbox_cmd, *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt;
+       char line_buf[LPFC_MBX_ACC_LBUF_SZ];
+       int len = 0;
+       uint32_t do_dump = 0;
+       uint32_t *pword;
+       uint32_t i;
+
+       if (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP)
+               return;
+
+       mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
+       mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
+       mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
+       mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
+
+       if (!(*mbx_dump_map & LPFC_MBX_DMP_ALL) ||
+           (*mbx_dump_cnt == 0) ||
+           (*mbx_word_cnt == 0))
+               return;
+
+       if (*mbx_mbox_cmd != 0x9B)
+               return;
+
+       if ((mbox_tp == mbox_rd) && (dma_tp == dma_mbox)) {
+               if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_MBX) {
+                       do_dump |= LPFC_BSG_DMP_MBX_RD_MBX;
+                       printk(KERN_ERR "\nRead mbox command (x%x), "
+                              "nemb:0x%x, extbuf_cnt:%d:\n",
+                              sta_tp, nemb_tp, ext_buf);
+               }
+       }
+       if ((mbox_tp == mbox_rd) && (dma_tp == dma_ebuf)) {
+               if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_BUF) {
+                       do_dump |= LPFC_BSG_DMP_MBX_RD_BUF;
+                       printk(KERN_ERR "\nRead mbox buffer (x%x), "
+                              "nemb:0x%x, extbuf_seq:%d:\n",
+                              sta_tp, nemb_tp, ext_buf);
+               }
+       }
+       if ((mbox_tp == mbox_wr) && (dma_tp == dma_mbox)) {
+               if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_MBX) {
+                       do_dump |= LPFC_BSG_DMP_MBX_WR_MBX;
+                       printk(KERN_ERR "\nWrite mbox command (x%x), "
+                              "nemb:0x%x, extbuf_cnt:%d:\n",
+                              sta_tp, nemb_tp, ext_buf);
+               }
+       }
+       if ((mbox_tp == mbox_wr) && (dma_tp == dma_ebuf)) {
+               if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_BUF) {
+                       do_dump |= LPFC_BSG_DMP_MBX_WR_BUF;
+                       printk(KERN_ERR "\nWrite mbox buffer (x%x), "
+                              "nemb:0x%x, extbuf_seq:%d:\n",
+                              sta_tp, nemb_tp, ext_buf);
+               }
+       }
+
+       /* dump buffer content */
+       if (do_dump) {
+               pword = (uint32_t *)dmabuf->virt;
+               for (i = 0; i < *mbx_word_cnt; i++) {
+                       if (!(i % 8)) {
+                               if (i != 0)
+                                       printk(KERN_ERR "%s\n", line_buf);
+                               len = 0;
+                               len += snprintf(line_buf+len,
+                                               LPFC_MBX_ACC_LBUF_SZ-len,
+                                               "%03d: ", i);
+                       }
+                       len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
+                                       "%08x ", (uint32_t)*pword);
+                       pword++;
+               }
+               if ((i - 1) % 8)
+                       printk(KERN_ERR "%s\n", line_buf);
+               (*mbx_dump_cnt)--;
+       }
+
+       /* Clean out command structure on reaching dump count */
+       if (*mbx_dump_cnt == 0)
+               memset(&idiag, 0, sizeof(idiag));
+       return;
+#endif
+}
+
+/* lpfc_idiag_mbxacc_dump_issue_mbox - idiag debugfs dump issue mailbox command
+ * @phba: Pointer to HBA context object.
+ * @dmabuf: Pointer to a DMA buffer descriptor.
+ *
+ * Description:
+ * This routine dump a pass-through non-embedded mailbox command from issue
+ * mailbox command.
+ **/
+void
+lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox)
+{
+#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
+       uint32_t *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt, *mbx_mbox_cmd;
+       char line_buf[LPFC_MBX_ACC_LBUF_SZ];
+       int len = 0;
+       uint32_t *pword;
+       uint8_t *pbyte;
+       uint32_t i, j;
+
+       if (idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP)
+               return;
+
+       mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX];
+       mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX];
+       mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX];
+       mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX];
+
+       if (!(*mbx_dump_map & LPFC_MBX_DMP_MBX_ALL) ||
+           (*mbx_dump_cnt == 0) ||
+           (*mbx_word_cnt == 0))
+               return;
+
+       if ((*mbx_mbox_cmd != LPFC_MBX_ALL_CMD) &&
+           (*mbx_mbox_cmd != pmbox->mbxCommand))
+               return;
+
+       /* dump buffer content */
+       if (*mbx_dump_map & LPFC_MBX_DMP_MBX_WORD) {
+               printk(KERN_ERR "Mailbox command:0x%x dump by word:\n",
+                      pmbox->mbxCommand);
+               pword = (uint32_t *)pmbox;
+               for (i = 0; i < *mbx_word_cnt; i++) {
+                       if (!(i % 8)) {
+                               if (i != 0)
+                                       printk(KERN_ERR "%s\n", line_buf);
+                               len = 0;
+                               memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
+                               len += snprintf(line_buf+len,
+                                               LPFC_MBX_ACC_LBUF_SZ-len,
+                                               "%03d: ", i);
+                       }
+                       len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len,
+                                       "%08x ",
+                                       ((uint32_t)*pword) & 0xffffffff);
+                       pword++;
+               }
+               if ((i - 1) % 8)
+                       printk(KERN_ERR "%s\n", line_buf);
+               printk(KERN_ERR "\n");
+       }
+       if (*mbx_dump_map & LPFC_MBX_DMP_MBX_BYTE) {
+               printk(KERN_ERR "Mailbox command:0x%x dump by byte:\n",
+                      pmbox->mbxCommand);
+               pbyte = (uint8_t *)pmbox;
+               for (i = 0; i < *mbx_word_cnt; i++) {
+                       if (!(i % 8)) {
+                               if (i != 0)
+                                       printk(KERN_ERR "%s\n", line_buf);
+                               len = 0;
+                               memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ);
+                               len += snprintf(line_buf+len,
+                                               LPFC_MBX_ACC_LBUF_SZ-len,
+                                               "%03d: ", i);
+                       }
+                       for (j = 0; j < 4; j++) {
+                               len += snprintf(line_buf+len,
+                                               LPFC_MBX_ACC_LBUF_SZ-len,
+                                               "%02x",
+                                               ((uint8_t)*pbyte) & 0xff);
+                               pbyte++;
+                       }
+                       len += snprintf(line_buf+len,
+                                       LPFC_MBX_ACC_LBUF_SZ-len, " ");
+               }
+               if ((i - 1) % 8)
+                       printk(KERN_ERR "%s\n", line_buf);
+               printk(KERN_ERR "\n");
+       }
+       (*mbx_dump_cnt)--;
+
+       /* Clean out command structure on reaching dump count */
+       if (*mbx_dump_cnt == 0)
+               memset(&idiag, 0, sizeof(idiag));
+       return;
+#endif
+}
+
 /**
  * lpfc_debugfs_initialize - Initialize debugfs for a vport
  * @vport: The vport pointer to initialize.
@@ -2673,7 +3894,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                                 vport, &lpfc_debugfs_op_nodelist);
        if (!vport->debug_nodelist) {
                lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
-                                "0409 Can't create debugfs nodelist\n");
+                                "2985 Can't create debugfs nodelist\n");
                goto debug_failed;
        }
 
@@ -2710,6 +3931,20 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                idiag.offset.last_rd = 0;
        }
 
+       /* iDiag PCI BAR access */
+       snprintf(name, sizeof(name), "barAcc");
+       if (!phba->idiag_bar_acc) {
+               phba->idiag_bar_acc =
+                       debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+                               phba->idiag_root, phba, &lpfc_idiag_op_barAcc);
+               if (!phba->idiag_bar_acc) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                       "3056 Can't create idiag debugfs\n");
+                       goto debug_failed;
+               }
+               idiag.offset.last_rd = 0;
+       }
+
        /* iDiag get PCI function queue information */
        snprintf(name, sizeof(name), "queInfo");
        if (!phba->idiag_que_info) {
@@ -2749,6 +3984,50 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
                }
        }
 
+       /* iDiag access PCI function control registers */
+       snprintf(name, sizeof(name), "ctlAcc");
+       if (!phba->idiag_ctl_acc) {
+               phba->idiag_ctl_acc =
+                       debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+                               phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc);
+               if (!phba->idiag_ctl_acc) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                        "2981 Can't create idiag debugfs\n");
+                       goto debug_failed;
+               }
+       }
+
+       /* iDiag access mbox commands */
+       snprintf(name, sizeof(name), "mbxAcc");
+       if (!phba->idiag_mbx_acc) {
+               phba->idiag_mbx_acc =
+                       debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+                               phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc);
+               if (!phba->idiag_mbx_acc) {
+                       lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                       "2980 Can't create idiag debugfs\n");
+                       goto debug_failed;
+               }
+       }
+
+       /* iDiag extents access commands */
+       if (phba->sli4_hba.extents_in_use) {
+               snprintf(name, sizeof(name), "extAcc");
+               if (!phba->idiag_ext_acc) {
+                       phba->idiag_ext_acc =
+                               debugfs_create_file(name,
+                                                   S_IFREG|S_IRUGO|S_IWUSR,
+                                                   phba->idiag_root, phba,
+                                                   &lpfc_idiag_op_extAcc);
+                       if (!phba->idiag_ext_acc) {
+                               lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+                                               "2986 Cant create "
+                                               "idiag debugfs\n");
+                               goto debug_failed;
+                       }
+               }
+       }
+
 debug_failed:
        return;
 #endif
@@ -2783,7 +4062,6 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
                debugfs_remove(vport->debug_nodelist); /* nodelist */
                vport->debug_nodelist = NULL;
        }
-
        if (vport->vport_debugfs_root) {
                debugfs_remove(vport->vport_debugfs_root); /* vportX */
                vport->vport_debugfs_root = NULL;
@@ -2827,6 +4105,21 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
                 * iDiag release
                 */
                if (phba->sli_rev == LPFC_SLI_REV4) {
+                       if (phba->idiag_ext_acc) {
+                               /* iDiag extAcc */
+                               debugfs_remove(phba->idiag_ext_acc);
+                               phba->idiag_ext_acc = NULL;
+                       }
+                       if (phba->idiag_mbx_acc) {
+                               /* iDiag mbxAcc */
+                               debugfs_remove(phba->idiag_mbx_acc);
+                               phba->idiag_mbx_acc = NULL;
+                       }
+                       if (phba->idiag_ctl_acc) {
+                               /* iDiag ctlAcc */
+                               debugfs_remove(phba->idiag_ctl_acc);
+                               phba->idiag_ctl_acc = NULL;
+                       }
                        if (phba->idiag_drb_acc) {
                                /* iDiag drbAcc */
                                debugfs_remove(phba->idiag_drb_acc);
@@ -2842,6 +4135,11 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
                                debugfs_remove(phba->idiag_que_info);
                                phba->idiag_que_info = NULL;
                        }
+                       if (phba->idiag_bar_acc) {
+                               /* iDiag barAcc */
+                               debugfs_remove(phba->idiag_bar_acc);
+                               phba->idiag_bar_acc = NULL;
+                       }
                        if (phba->idiag_pci_cfg) {
                                /* iDiag pciCfg */
                                debugfs_remove(phba->idiag_pci_cfg);
index 6525a5e62d27eac813514e23178e5e898d976f14..f83bd944edd86c29fbe82a45228e8149a63dad45 100644 (file)
 /* hbqinfo output buffer size */
 #define LPFC_HBQINFO_SIZE 8192
 
+/*
+ * For SLI4 iDiag debugfs diagnostics tool
+ */
+
 /* pciConf */
 #define LPFC_PCI_CFG_BROWSE 0xffff
 #define LPFC_PCI_CFG_RD_CMD_ARG 2
 #define LPFC_PCI_CFG_WR_CMD_ARG 3
 #define LPFC_PCI_CFG_SIZE 4096
-#define LPFC_PCI_CFG_RD_BUF_SIZE (LPFC_PCI_CFG_SIZE/2)
 #define LPFC_PCI_CFG_RD_SIZE (LPFC_PCI_CFG_SIZE/4)
 
+#define IDIAG_PCICFG_WHERE_INDX 0
+#define IDIAG_PCICFG_COUNT_INDX 1
+#define IDIAG_PCICFG_VALUE_INDX 2
+
+/* barAcc */
+#define LPFC_PCI_BAR_BROWSE 0xffff
+#define LPFC_PCI_BAR_RD_CMD_ARG 3
+#define LPFC_PCI_BAR_WR_CMD_ARG 3
+
+#define LPFC_PCI_IF0_BAR0_SIZE (1024 *  16)
+#define LPFC_PCI_IF0_BAR1_SIZE (1024 * 128)
+#define LPFC_PCI_IF0_BAR2_SIZE (1024 * 128)
+#define LPFC_PCI_IF2_BAR0_SIZE (1024 *  32)
+
+#define LPFC_PCI_BAR_RD_BUF_SIZE 4096
+#define LPFC_PCI_BAR_RD_SIZE (LPFC_PCI_BAR_RD_BUF_SIZE/4)
+
+#define LPFC_PCI_IF0_BAR0_RD_SIZE (LPFC_PCI_IF0_BAR0_SIZE/4)
+#define LPFC_PCI_IF0_BAR1_RD_SIZE (LPFC_PCI_IF0_BAR1_SIZE/4)
+#define LPFC_PCI_IF0_BAR2_RD_SIZE (LPFC_PCI_IF0_BAR2_SIZE/4)
+#define LPFC_PCI_IF2_BAR0_RD_SIZE (LPFC_PCI_IF2_BAR0_SIZE/4)
+
+#define IDIAG_BARACC_BAR_NUM_INDX 0
+#define IDIAG_BARACC_OFF_SET_INDX 1
+#define IDIAG_BARACC_ACC_MOD_INDX 2
+#define IDIAG_BARACC_REG_VAL_INDX 2
+#define IDIAG_BARACC_BAR_SZE_INDX 3
+
+#define IDIAG_BARACC_BAR_0 0
+#define IDIAG_BARACC_BAR_1 1
+#define IDIAG_BARACC_BAR_2 2
+
+#define SINGLE_WORD 1
+
 /* queue info */
 #define LPFC_QUE_INFO_GET_BUF_SIZE 4096
 
 #define LPFC_IDIAG_WQ 4
 #define LPFC_IDIAG_RQ 5
 
-/* doorbell acc */
+#define IDIAG_QUEACC_QUETP_INDX 0
+#define IDIAG_QUEACC_QUEID_INDX 1
+#define IDIAG_QUEACC_INDEX_INDX 2
+#define IDIAG_QUEACC_COUNT_INDX 3
+#define IDIAG_QUEACC_OFFST_INDX 4
+#define IDIAG_QUEACC_VALUE_INDX 5
+
+/* doorbell register acc */
 #define LPFC_DRB_ACC_ALL 0xffff
 #define LPFC_DRB_ACC_RD_CMD_ARG 1
 #define LPFC_DRB_ACC_WR_CMD_ARG 2
 
 #define LPFC_DRB_MAX  4
 
+#define IDIAG_DRBACC_REGID_INDX 0
+#define IDIAG_DRBACC_VALUE_INDX 1
+
+/* control register acc */
+#define LPFC_CTL_ACC_ALL 0xffff
+#define LPFC_CTL_ACC_RD_CMD_ARG 1
+#define LPFC_CTL_ACC_WR_CMD_ARG 2
+#define LPFC_CTL_ACC_BUF_SIZE 256
+
+#define LPFC_CTL_PORT_SEM  1
+#define LPFC_CTL_PORT_STA  2
+#define LPFC_CTL_PORT_CTL  3
+#define LPFC_CTL_PORT_ER1  4
+#define LPFC_CTL_PORT_ER2  5
+#define LPFC_CTL_PDEV_CTL  6
+
+#define LPFC_CTL_MAX  6
+
+#define IDIAG_CTLACC_REGID_INDX 0
+#define IDIAG_CTLACC_VALUE_INDX 1
+
+/* mailbox access */
+#define LPFC_MBX_DMP_ARG 4
+
+#define LPFC_MBX_ACC_BUF_SIZE 512
+#define LPFC_MBX_ACC_LBUF_SZ 128
+
+#define LPFC_MBX_DMP_MBX_WORD 0x00000001
+#define LPFC_MBX_DMP_MBX_BYTE 0x00000002
+#define LPFC_MBX_DMP_MBX_ALL (LPFC_MBX_DMP_MBX_WORD | LPFC_MBX_DMP_MBX_BYTE)
+
+#define LPFC_BSG_DMP_MBX_RD_MBX 0x00000001
+#define LPFC_BSG_DMP_MBX_RD_BUF 0x00000002
+#define LPFC_BSG_DMP_MBX_WR_MBX 0x00000004
+#define LPFC_BSG_DMP_MBX_WR_BUF 0x00000008
+#define LPFC_BSG_DMP_MBX_ALL (LPFC_BSG_DMP_MBX_RD_MBX | \
+                             LPFC_BSG_DMP_MBX_RD_BUF | \
+                             LPFC_BSG_DMP_MBX_WR_MBX | \
+                             LPFC_BSG_DMP_MBX_WR_BUF)
+
+#define LPFC_MBX_DMP_ALL 0xffff
+#define LPFC_MBX_ALL_CMD 0xff
+
+#define IDIAG_MBXACC_MBCMD_INDX 0
+#define IDIAG_MBXACC_DPMAP_INDX 1
+#define IDIAG_MBXACC_DPCNT_INDX 2
+#define IDIAG_MBXACC_WDCNT_INDX 3
+
+/* extents access */
+#define LPFC_EXT_ACC_CMD_ARG 1
+#define LPFC_EXT_ACC_BUF_SIZE 4096
+
+#define LPFC_EXT_ACC_AVAIL 0x1
+#define LPFC_EXT_ACC_ALLOC 0x2
+#define LPFC_EXT_ACC_DRIVR 0x4
+#define LPFC_EXT_ACC_ALL   (LPFC_EXT_ACC_DRIVR | \
+                           LPFC_EXT_ACC_AVAIL | \
+                           LPFC_EXT_ACC_ALLOC)
+
+#define IDIAG_EXTACC_EXMAP_INDX 0
+
 #define SIZE_U8  sizeof(uint8_t)
 #define SIZE_U16 sizeof(uint16_t)
 #define SIZE_U32 sizeof(uint32_t)
@@ -110,6 +215,11 @@ struct lpfc_idiag_cmd {
 #define LPFC_IDIAG_CMD_PCICFG_ST 0x00000003
 #define LPFC_IDIAG_CMD_PCICFG_CL 0x00000004
 
+#define LPFC_IDIAG_CMD_BARACC_RD 0x00000008
+#define LPFC_IDIAG_CMD_BARACC_WR 0x00000009
+#define LPFC_IDIAG_CMD_BARACC_ST 0x0000000a
+#define LPFC_IDIAG_CMD_BARACC_CL 0x0000000b
+
 #define LPFC_IDIAG_CMD_QUEACC_RD 0x00000011
 #define LPFC_IDIAG_CMD_QUEACC_WR 0x00000012
 #define LPFC_IDIAG_CMD_QUEACC_ST 0x00000013
@@ -119,6 +229,17 @@ struct lpfc_idiag_cmd {
 #define LPFC_IDIAG_CMD_DRBACC_WR 0x00000022
 #define LPFC_IDIAG_CMD_DRBACC_ST 0x00000023
 #define LPFC_IDIAG_CMD_DRBACC_CL 0x00000024
+
+#define LPFC_IDIAG_CMD_CTLACC_RD 0x00000031
+#define LPFC_IDIAG_CMD_CTLACC_WR 0x00000032
+#define LPFC_IDIAG_CMD_CTLACC_ST 0x00000033
+#define LPFC_IDIAG_CMD_CTLACC_CL 0x00000034
+
+#define LPFC_IDIAG_CMD_MBXACC_DP 0x00000041
+#define LPFC_IDIAG_BSG_MBXACC_DP 0x00000042
+
+#define LPFC_IDIAG_CMD_EXTACC_RD 0x00000051
+
        uint32_t data[LPFC_IDIAG_CMD_DATA_SIZE];
 };
 
index 32a084534f3e08898259d0360a9002acf121e8b1..023da0e00d38609fe407e0acf8f08a80eab5f419 100644 (file)
@@ -647,21 +647,15 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                }
                lpfc_cleanup_pending_mbox(vport);
 
-               if (phba->sli_rev == LPFC_SLI_REV4)
+               if (phba->sli_rev == LPFC_SLI_REV4) {
                        lpfc_sli4_unreg_all_rpis(vport);
-
-               if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
                        lpfc_mbx_unreg_vpi(vport);
                        spin_lock_irq(shost->host_lock);
                        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
-                       spin_unlock_irq(shost->host_lock);
-               }
-               /*
-                * If VPI is unreged, driver need to do INIT_VPI
-                * before re-registering
-                */
-               if (phba->sli_rev == LPFC_SLI_REV4) {
-                       spin_lock_irq(shost->host_lock);
+                       /*
+                       * If VPI is unreged, driver need to do INIT_VPI
+                       * before re-registering
+                       */
                        vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
                        spin_unlock_irq(shost->host_lock);
                }
@@ -880,6 +874,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                        phba->fcf.current_rec.fcf_indx,
                                        irsp->ulpStatus, irsp->un.ulpWord[4],
                                        irsp->ulpTimeout);
+                       lpfc_sli4_set_fcf_flogi_fail(phba,
+                                       phba->fcf.current_rec.fcf_indx);
                        fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
                        rc = lpfc_sli4_fcf_rr_next_proc(vport, fcf_index);
                        if (rc)
@@ -1096,11 +1092,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        /* Set the fcfi to the fcfi we registered with */
                        elsiocb->iocb.ulpContext = phba->fcf.fcfi;
                }
-       } else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
-               sp->cmn.request_multiple_Nport = 1;
-               /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
-               icmd->ulpCt_h = 1;
-               icmd->ulpCt_l = 0;
+       } else {
+               if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+                       sp->cmn.request_multiple_Nport = 1;
+                       /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
+                       icmd->ulpCt_h = 1;
+                       icmd->ulpCt_l = 0;
+               } else
+                       sp->cmn.request_multiple_Nport = 0;
        }
 
        if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) {
@@ -3656,7 +3655,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                }
 
                icmd = &elsiocb->iocb;
-               icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+               icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+               icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
                pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
                *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
                pcmd += sizeof(uint32_t);
@@ -3673,7 +3673,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                        return 1;
 
                icmd = &elsiocb->iocb;
-               icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+               icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+               icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
                pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
                if (mbox)
@@ -3695,7 +3696,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                        return 1;
 
                icmd = &elsiocb->iocb;
-               icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+               icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+               icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
                pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
                memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
@@ -3781,7 +3783,8 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+       icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
        *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
@@ -3853,7 +3856,8 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+       icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
 
        /* Xmit ADISC ACC response tag <ulpIoTag> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -3931,7 +3935,9 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+       icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
+
        /* Xmit PRLI ACC response tag <ulpIoTag> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
                         "0131 Xmit PRLI ACC response tag x%x xri x%x, "
@@ -4035,7 +4041,9 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+       icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
+
        /* Xmit RNID ACC response tag <ulpIoTag> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
                         "0132 Xmit RNID ACC response tag x%x xri x%x\n",
@@ -4163,7 +4171,9 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data,
        if (!elsiocb)
                return 1;
 
-       elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext;    /* Xri */
+       elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext;  /* Xri / rx_id */
+       elsiocb->iocb.unsli3.rcvsli3.ox_id = oldiocb->iocb.unsli3.rcvsli3.ox_id;
+
        /* Xmit ECHO ACC response tag <ulpIoTag> */
        lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
                         "2876 Xmit ECHO ACC response tag x%x xri x%x\n",
@@ -5054,13 +5064,15 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        uint8_t *pcmd;
        struct lpfc_iocbq *elsiocb;
        struct lpfc_nodelist *ndlp;
-       uint16_t xri;
+       uint16_t oxid;
+       uint16_t rxid;
        uint32_t cmdsize;
 
        mb = &pmb->u.mb;
 
        ndlp = (struct lpfc_nodelist *) pmb->context2;
-       xri = (uint16_t) ((unsigned long)(pmb->context1));
+       rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff);
+       oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff);
        pmb->context1 = NULL;
        pmb->context2 = NULL;
 
@@ -5082,7 +5094,8 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                return;
 
        icmd = &elsiocb->iocb;
-       icmd->ulpContext = xri;
+       icmd->ulpContext = rxid;
+       icmd->unsli3.rcvsli3.ox_id = oxid;
 
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -5137,13 +5150,16 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        uint8_t *pcmd;
        struct lpfc_iocbq *elsiocb;
        struct lpfc_nodelist *ndlp;
-       uint16_t xri, status;
+       uint16_t status;
+       uint16_t oxid;
+       uint16_t rxid;
        uint32_t cmdsize;
 
        mb = &pmb->u.mb;
 
        ndlp = (struct lpfc_nodelist *) pmb->context2;
-       xri = (uint16_t) ((unsigned long)(pmb->context1));
+       rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff);
+       oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff);
        pmb->context1 = NULL;
        pmb->context2 = NULL;
 
@@ -5165,7 +5181,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                return;
 
        icmd = &elsiocb->iocb;
-       icmd->ulpContext = xri;
+       icmd->ulpContext = rxid;
+       icmd->unsli3.rcvsli3.ox_id = oxid;
 
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -5238,8 +5255,9 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
        if (mbox) {
                lpfc_read_lnk_stat(phba, mbox);
-               mbox->context1 =
-                   (void *)((unsigned long) cmdiocb->iocb.ulpContext);
+               mbox->context1 = (void *)((unsigned long)
+                       ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) |
+                       cmdiocb->iocb.ulpContext)); /* rx_id */
                mbox->context2 = lpfc_nlp_get(ndlp);
                mbox->vport = vport;
                mbox->mbox_cmpl = lpfc_els_rsp_rls_acc;
@@ -5314,7 +5332,8 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        pcmd += sizeof(uint32_t); /* Skip past command */
 
        /* use the command's xri in the response */
-       elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext;
+       elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext;  /* Xri / rx_id */
+       elsiocb->iocb.unsli3.rcvsli3.ox_id = cmdiocb->iocb.unsli3.rcvsli3.ox_id;
 
        rtv_rsp = (struct RTV_RSP *)pcmd;
 
@@ -5399,8 +5418,9 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
                if (mbox) {
                        lpfc_read_lnk_stat(phba, mbox);
-                       mbox->context1 =
-                           (void *)((unsigned long) cmdiocb->iocb.ulpContext);
+                       mbox->context1 = (void *)((unsigned long)
+                               ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) |
+                               cmdiocb->iocb.ulpContext)); /* rx_id */
                        mbox->context2 = lpfc_nlp_get(ndlp);
                        mbox->vport = vport;
                        mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
@@ -5554,7 +5574,8 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
 
        icmd = &elsiocb->iocb;
        oldcmd = &oldiocb->iocb;
-       icmd->ulpContext = oldcmd->ulpContext;  /* Xri */
+       icmd->ulpContext = oldcmd->ulpContext;  /* Xri / rx_id */
+       icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
 
        pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
        *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -6586,7 +6607,7 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
 {
        struct lpfc_vport *vport;
        unsigned long flags;
-       int i;
+       int i = 0;
 
        /* The physical ports are always vpi 0 - translate is unnecessary. */
        if (vpi > 0) {
@@ -6609,7 +6630,7 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
 
        spin_lock_irqsave(&phba->hbalock, flags);
        list_for_each_entry(vport, &phba->port_list, listentry) {
-               if (vport->vpi == vpi) {
+               if (vport->vpi == i) {
                        spin_unlock_irqrestore(&phba->hbalock, flags);
                        return vport;
                }
@@ -7787,6 +7808,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
 {
        uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);
        uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri);
+       uint16_t lxri = 0;
 
        struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
        unsigned long iflag = 0;
@@ -7815,7 +7837,12 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
                }
        }
        spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
-       sglq_entry = __lpfc_get_active_sglq(phba, xri);
+       lxri = lpfc_sli4_xri_inrange(phba, xri);
+       if (lxri == NO_XRI) {
+               spin_unlock_irqrestore(&phba->hbalock, iflag);
+               return;
+       }
+       sglq_entry = __lpfc_get_active_sglq(phba, lxri);
        if (!sglq_entry || (sglq_entry->sli4_xritag != xri)) {
                spin_unlock_irqrestore(&phba->hbalock, iflag);
                return;
index 18d0dbfda2bcf8100b2dc5af25bc8dc5bc778370..0b47adf9fee8e18ae0e9becbb8232b9a98baba86 100644 (file)
@@ -1109,6 +1109,28 @@ out:
        return;
 }
 
+/**
+ * lpfc_sli4_clear_fcf_rr_bmask
+ * @phba pointer to the struct lpfc_hba for this port.
+ * This fucnction resets the round robin bit mask and clears the
+ * fcf priority list. The list deletions are done while holding the
+ * hbalock. The ON_LIST flag and the FLOGI_FAILED flags are cleared
+ * from the lpfc_fcf_pri record.
+ **/
+void
+lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *phba)
+{
+       struct lpfc_fcf_pri *fcf_pri;
+       struct lpfc_fcf_pri *next_fcf_pri;
+       memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask));
+       spin_lock_irq(&phba->hbalock);
+       list_for_each_entry_safe(fcf_pri, next_fcf_pri,
+                               &phba->fcf.fcf_pri_list, list) {
+               list_del_init(&fcf_pri->list);
+               fcf_pri->fcf_rec.flag = 0;
+       }
+       spin_unlock_irq(&phba->hbalock);
+}
 static void
 lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 {
@@ -1130,7 +1152,8 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        spin_unlock_irq(&phba->hbalock);
 
        /* If there is a pending FCoE event, restart FCF table scan. */
-       if (lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF))
+       if ((!(phba->hba_flag & FCF_RR_INPROG)) &&
+               lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF))
                goto fail_out;
 
        /* Mark successful completion of FCF table scan */
@@ -1249,6 +1272,30 @@ lpfc_vlan_id_match(uint16_t curr_vlan_id, uint16_t new_vlan_id)
        return (curr_vlan_id == new_vlan_id);
 }
 
+/**
+ * lpfc_update_fcf_record - Update driver fcf record
+ * __lpfc_update_fcf_record_pri - update the lpfc_fcf_pri record.
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index: Index for the lpfc_fcf_record.
+ * @new_fcf_record: pointer to hba fcf record.
+ *
+ * This routine updates the driver FCF priority record from the new HBA FCF
+ * record. This routine is called with the host lock held.
+ **/
+static void
+__lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index,
+                                struct fcf_record *new_fcf_record
+                                )
+{
+       struct lpfc_fcf_pri *fcf_pri;
+
+       fcf_pri = &phba->fcf.fcf_pri[fcf_index];
+       fcf_pri->fcf_rec.fcf_index = fcf_index;
+       /* FCF record priority */
+       fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority;
+
+}
+
 /**
  * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba.
  * @fcf: pointer to driver fcf record.
@@ -1332,6 +1379,9 @@ __lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec,
        fcf_rec->addr_mode = addr_mode;
        fcf_rec->vlan_id = vlan_id;
        fcf_rec->flag |= (flag | RECORD_VALID);
+       __lpfc_update_fcf_record_pri(phba,
+               bf_get(lpfc_fcf_record_fcf_index, new_fcf_record),
+                                new_fcf_record);
 }
 
 /**
@@ -1834,6 +1884,8 @@ lpfc_sli4_fcf_record_match(struct lpfc_hba *phba,
                return false;
        if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record))
                return false;
+       if (fcf_rec->priority != new_fcf_record->fip_priority)
+               return false;
        return true;
 }
 
@@ -1896,6 +1948,152 @@ stop_flogi_current_fcf:
        return 1;
 }
 
+/**
+ * lpfc_sli4_fcf_pri_list_del
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index the index of the fcf record to delete
+ * This routine checks the on list flag of the fcf_index to be deleted.
+ * If it is one the list then it is removed from the list, and the flag
+ * is cleared. This routine grab the hbalock before removing the fcf
+ * record from the list.
+ **/
+static void lpfc_sli4_fcf_pri_list_del(struct lpfc_hba *phba,
+                       uint16_t fcf_index)
+{
+       struct lpfc_fcf_pri *new_fcf_pri;
+
+       new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+               "3058 deleting idx x%x pri x%x flg x%x\n",
+               fcf_index, new_fcf_pri->fcf_rec.priority,
+                new_fcf_pri->fcf_rec.flag);
+       spin_lock_irq(&phba->hbalock);
+       if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST) {
+               if (phba->fcf.current_rec.priority ==
+                               new_fcf_pri->fcf_rec.priority)
+                       phba->fcf.eligible_fcf_cnt--;
+               list_del_init(&new_fcf_pri->list);
+               new_fcf_pri->fcf_rec.flag &= ~LPFC_FCF_ON_PRI_LIST;
+       }
+       spin_unlock_irq(&phba->hbalock);
+}
+
+/**
+ * lpfc_sli4_set_fcf_flogi_fail
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index the index of the fcf record to update
+ * This routine acquires the hbalock and then set the LPFC_FCF_FLOGI_FAILED
+ * flag so the the round robin slection for the particular priority level
+ * will try a different fcf record that does not have this bit set.
+ * If the fcf record is re-read for any reason this flag is cleared brfore
+ * adding it to the priority list.
+ **/
+void
+lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *phba, uint16_t fcf_index)
+{
+       struct lpfc_fcf_pri *new_fcf_pri;
+       new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
+       spin_lock_irq(&phba->hbalock);
+       new_fcf_pri->fcf_rec.flag |= LPFC_FCF_FLOGI_FAILED;
+       spin_unlock_irq(&phba->hbalock);
+}
+
+/**
+ * lpfc_sli4_fcf_pri_list_add
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_index the index of the fcf record to add
+ * This routine checks the priority of the fcf_index to be added.
+ * If it is a lower priority than the current head of the fcf_pri list
+ * then it is added to the list in the right order.
+ * If it is the same priority as the current head of the list then it
+ * is added to the head of the list and its bit in the rr_bmask is set.
+ * If the fcf_index to be added is of a higher priority than the current
+ * head of the list then the rr_bmask is cleared, its bit is set in the
+ * rr_bmask and it is added to the head of the list.
+ * returns:
+ * 0=success 1=failure
+ **/
+int lpfc_sli4_fcf_pri_list_add(struct lpfc_hba *phba, uint16_t fcf_index,
+       struct fcf_record *new_fcf_record)
+{
+       uint16_t current_fcf_pri;
+       uint16_t last_index;
+       struct lpfc_fcf_pri *fcf_pri;
+       struct lpfc_fcf_pri *next_fcf_pri;
+       struct lpfc_fcf_pri *new_fcf_pri;
+       int ret;
+
+       new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+               "3059 adding idx x%x pri x%x flg x%x\n",
+               fcf_index, new_fcf_record->fip_priority,
+                new_fcf_pri->fcf_rec.flag);
+       spin_lock_irq(&phba->hbalock);
+       if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST)
+               list_del_init(&new_fcf_pri->list);
+       new_fcf_pri->fcf_rec.fcf_index = fcf_index;
+       new_fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority;
+       if (list_empty(&phba->fcf.fcf_pri_list)) {
+               list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list);
+               ret = lpfc_sli4_fcf_rr_index_set(phba,
+                               new_fcf_pri->fcf_rec.fcf_index);
+               goto out;
+       }
+
+       last_index = find_first_bit(phba->fcf.fcf_rr_bmask,
+                               LPFC_SLI4_FCF_TBL_INDX_MAX);
+       if (last_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+               ret = 0; /* Empty rr list */
+               goto out;
+       }
+       current_fcf_pri = phba->fcf.fcf_pri[last_index].fcf_rec.priority;
+       if (new_fcf_pri->fcf_rec.priority <=  current_fcf_pri) {
+               list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list);
+               if (new_fcf_pri->fcf_rec.priority <  current_fcf_pri) {
+                       memset(phba->fcf.fcf_rr_bmask, 0,
+                               sizeof(*phba->fcf.fcf_rr_bmask));
+                       /* fcfs_at_this_priority_level = 1; */
+                       phba->fcf.eligible_fcf_cnt = 1;
+               } else
+                       /* fcfs_at_this_priority_level++; */
+                       phba->fcf.eligible_fcf_cnt++;
+               ret = lpfc_sli4_fcf_rr_index_set(phba,
+                               new_fcf_pri->fcf_rec.fcf_index);
+               goto out;
+       }
+
+       list_for_each_entry_safe(fcf_pri, next_fcf_pri,
+                               &phba->fcf.fcf_pri_list, list) {
+               if (new_fcf_pri->fcf_rec.priority <=
+                               fcf_pri->fcf_rec.priority) {
+                       if (fcf_pri->list.prev == &phba->fcf.fcf_pri_list)
+                               list_add(&new_fcf_pri->list,
+                                               &phba->fcf.fcf_pri_list);
+                       else
+                               list_add(&new_fcf_pri->list,
+                                        &((struct lpfc_fcf_pri *)
+                                       fcf_pri->list.prev)->list);
+                       ret = 0;
+                       goto out;
+               } else if (fcf_pri->list.next == &phba->fcf.fcf_pri_list
+                       || new_fcf_pri->fcf_rec.priority <
+                               next_fcf_pri->fcf_rec.priority) {
+                       list_add(&new_fcf_pri->list, &fcf_pri->list);
+                       ret = 0;
+                       goto out;
+               }
+               if (new_fcf_pri->fcf_rec.priority > fcf_pri->fcf_rec.priority)
+                       continue;
+
+       }
+       ret = 1;
+out:
+       /* we use = instead of |= to clear the FLOGI_FAILED flag. */
+       new_fcf_pri->fcf_rec.flag = LPFC_FCF_ON_PRI_LIST;
+       spin_unlock_irq(&phba->hbalock);
+       return ret;
+}
+
 /**
  * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
  * @phba: pointer to lpfc hba data structure.
@@ -1958,6 +2156,9 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
         * record for roundrobin FCF failover.
         */
        if (!rc) {
+               lpfc_sli4_fcf_pri_list_del(phba,
+                                       bf_get(lpfc_fcf_record_fcf_index,
+                                              new_fcf_record));
                lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
                                "2781 FCF (x%x) failed connection "
                                "list check: (x%x/x%x)\n",
@@ -2005,7 +2206,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                goto read_next_fcf;
        } else {
                fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
-               rc = lpfc_sli4_fcf_rr_index_set(phba, fcf_index);
+               rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index,
+                                                       new_fcf_record);
                if (rc)
                        goto read_next_fcf;
        }
@@ -2018,7 +2220,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
         */
        spin_lock_irq(&phba->hbalock);
        if (phba->fcf.fcf_flag & FCF_IN_USE) {
-               if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
+               if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV &&
+                       lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
                    new_fcf_record, vlan_id)) {
                        if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) ==
                            phba->fcf.current_rec.fcf_indx) {
@@ -2232,7 +2435,8 @@ read_next_fcf:
                            (phba->fcf.fcf_flag & FCF_REDISC_PEND))
                                return;
 
-                       if (phba->fcf.fcf_flag & FCF_IN_USE) {
+                       if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV &&
+                               phba->fcf.fcf_flag & FCF_IN_USE) {
                                /*
                                 * In case the current in-use FCF record no
                                 * longer existed during FCF discovery that
@@ -2247,7 +2451,6 @@ read_next_fcf:
                                spin_lock_irq(&phba->hbalock);
                                phba->fcf.fcf_flag |= FCF_REDISC_FOV;
                                spin_unlock_irq(&phba->hbalock);
-                               lpfc_sli4_mbox_cmd_free(phba, mboxq);
                                lpfc_sli4_fcf_scan_read_fcf_rec(phba,
                                                LPFC_FCOE_FCF_GET_FIRST);
                                return;
@@ -2424,7 +2627,8 @@ lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 
        /* Update the eligible FCF record index bmask */
        fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
-       rc = lpfc_sli4_fcf_rr_index_set(phba, fcf_index);
+
+       rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index, new_fcf_record);
 
 out:
        lpfc_sli4_mbox_cmd_free(phba, mboxq);
@@ -2645,6 +2849,7 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
        vport->vpi_state |= LPFC_VPI_REGISTERED;
        vport->fc_flag |= FC_VFI_REGISTERED;
        vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+       vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;
        spin_unlock_irq(shost->host_lock);
 
        if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
@@ -2893,8 +3098,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
                        goto out;
                }
                /* Reset FCF roundrobin bmask for new discovery */
-               memset(phba->fcf.fcf_rr_bmask, 0,
-                      sizeof(*phba->fcf.fcf_rr_bmask));
+               lpfc_sli4_clear_fcf_rr_bmask(phba);
        }
 
        return;
@@ -5592,7 +5796,7 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba)
        spin_unlock_irq(&phba->hbalock);
 
        /* Reset FCF roundrobin bmask for new discovery */
-       memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask));
+       lpfc_sli4_clear_fcf_rr_bmask(phba);
 
        rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
 
index ab4c4d651d0cf83226e9e00ba9d760c6dbbd7c09..046edc4ab35f7a858dc6c536b06c41c2cb3defe8 100644 (file)
@@ -3470,11 +3470,16 @@ typedef struct {
    or CMD_IOCB_RCV_SEQ64_CX (0xB5) */
 
 struct rcv_sli3 {
-       uint32_t word8Rsvd;
 #ifdef __BIG_ENDIAN_BITFIELD
+       uint16_t ox_id;
+       uint16_t seq_cnt;
+
        uint16_t vpi;
        uint16_t word9Rsvd;
 #else  /*  __LITTLE_ENDIAN */
+       uint16_t seq_cnt;
+       uint16_t ox_id;
+
        uint16_t word9Rsvd;
        uint16_t vpi;
 #endif
index 11e26a26b5d1cd6bb3dc34675c0243a01ffe8a95..7f8003b5181eb47504b86930550af227853ca2b1 100644 (file)
@@ -170,15 +170,8 @@ struct lpfc_sli_intf {
 #define LPFC_PCI_FUNC3         3
 #define LPFC_PCI_FUNC4         4
 
-/* SLI4 interface type-2 control register offsets */
-#define LPFC_CTL_PORT_SEM_OFFSET       0x400
-#define LPFC_CTL_PORT_STA_OFFSET       0x404
-#define LPFC_CTL_PORT_CTL_OFFSET       0x408
-#define LPFC_CTL_PORT_ER1_OFFSET       0x40C
-#define LPFC_CTL_PORT_ER2_OFFSET       0x410
+/* SLI4 interface type-2 PDEV_CTL register */
 #define LPFC_CTL_PDEV_CTL_OFFSET       0x414
-
-/* Some SLI4 interface type-2 PDEV_CTL register bits */
 #define LPFC_CTL_PDEV_CTL_DRST         0x00000001
 #define LPFC_CTL_PDEV_CTL_FRST         0x00000002
 #define LPFC_CTL_PDEV_CTL_DD           0x00000004
@@ -337,6 +330,7 @@ struct lpfc_cqe {
 #define CQE_CODE_RELEASE_WQE           0x2
 #define CQE_CODE_RECEIVE               0x4
 #define CQE_CODE_XRI_ABORTED           0x5
+#define CQE_CODE_RECEIVE_V1            0x9
 
 /* completion queue entry for wqe completions */
 struct lpfc_wcqe_complete {
@@ -440,7 +434,10 @@ struct lpfc_rcqe {
 #define FC_STATUS_RQ_BUF_LEN_EXCEEDED  0x11 /* payload truncated */
 #define FC_STATUS_INSUFF_BUF_NEED_BUF  0x12 /* Insufficient buffers */
 #define FC_STATUS_INSUFF_BUF_FRM_DISC  0x13 /* Frame Discard */
-       uint32_t reserved1;
+       uint32_t word1;
+#define lpfc_rcqe_fcf_id_v1_SHIFT      0
+#define lpfc_rcqe_fcf_id_v1_MASK       0x0000003F
+#define lpfc_rcqe_fcf_id_v1_WORD       word1
        uint32_t word2;
 #define lpfc_rcqe_length_SHIFT         16
 #define lpfc_rcqe_length_MASK          0x0000FFFF
@@ -451,6 +448,9 @@ struct lpfc_rcqe {
 #define lpfc_rcqe_fcf_id_SHIFT         0
 #define lpfc_rcqe_fcf_id_MASK          0x0000003F
 #define lpfc_rcqe_fcf_id_WORD          word2
+#define lpfc_rcqe_rq_id_v1_SHIFT       0
+#define lpfc_rcqe_rq_id_v1_MASK                0x0000FFFF
+#define lpfc_rcqe_rq_id_v1_WORD                word2
        uint32_t word3;
 #define lpfc_rcqe_valid_SHIFT          lpfc_cqe_valid_SHIFT
 #define lpfc_rcqe_valid_MASK           lpfc_cqe_valid_MASK
@@ -515,7 +515,7 @@ struct lpfc_register {
 /* The following BAR0 register sets are defined for if_type 0 and 2 UCNAs. */
 #define LPFC_SLI_INTF                  0x0058
 
-#define LPFC_SLIPORT_IF2_SMPHR         0x0400
+#define LPFC_CTL_PORT_SEM_OFFSET       0x400
 #define lpfc_port_smphr_perr_SHIFT     31
 #define lpfc_port_smphr_perr_MASK      0x1
 #define lpfc_port_smphr_perr_WORD      word0
@@ -575,7 +575,7 @@ struct lpfc_register {
 #define LPFC_POST_STAGE_PORT_READY                     0xC000
 #define LPFC_POST_STAGE_PORT_UE                        0xF000
 
-#define LPFC_SLIPORT_STATUS            0x0404
+#define LPFC_CTL_PORT_STA_OFFSET       0x404
 #define lpfc_sliport_status_err_SHIFT  31
 #define lpfc_sliport_status_err_MASK   0x1
 #define lpfc_sliport_status_err_WORD   word0
@@ -593,7 +593,7 @@ struct lpfc_register {
 #define lpfc_sliport_status_rdy_WORD   word0
 #define MAX_IF_TYPE_2_RESETS   1000
 
-#define LPFC_SLIPORT_CNTRL             0x0408
+#define LPFC_CTL_PORT_CTL_OFFSET       0x408
 #define lpfc_sliport_ctrl_end_SHIFT    30
 #define lpfc_sliport_ctrl_end_MASK     0x1
 #define lpfc_sliport_ctrl_end_WORD     word0
@@ -604,8 +604,8 @@ struct lpfc_register {
 #define lpfc_sliport_ctrl_ip_WORD      word0
 #define LPFC_SLIPORT_INIT_PORT 1
 
-#define LPFC_SLIPORT_ERR_1             0x040C
-#define LPFC_SLIPORT_ERR_2             0x0410
+#define LPFC_CTL_PORT_ER1_OFFSET       0x40C
+#define LPFC_CTL_PORT_ER2_OFFSET       0x410
 
 /* The following Registers apply to SLI4 if_type 0 UCNAs. They typically
  * reside in BAR 2.
@@ -3198,6 +3198,8 @@ struct lpfc_grp_hdr {
 #define lpfc_grp_hdr_id_MASK           0x000000FF
 #define lpfc_grp_hdr_id_WORD           word2
        uint8_t rev_name[128];
+       uint8_t date[12];
+       uint8_t revision[32];
 };
 
 #define FCP_COMMAND 0x0
index 148b98ddbb1d9ed17103c25f9cf5d5d50fd60342..a3c820083c368527c37ac2ea451a0634b281b1e4 100644 (file)
@@ -2927,6 +2927,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
                                 sizeof fc_host_symbolic_name(shost));
 
        fc_host_supported_speeds(shost) = 0;
+       if (phba->lmt & LMT_16Gb)
+               fc_host_supported_speeds(shost) |= FC_PORTSPEED_16GBIT;
        if (phba->lmt & LMT_10Gb)
                fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
        if (phba->lmt & LMT_8Gb)
@@ -3632,8 +3634,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
                        lpfc_sli4_fcf_dead_failthrough(phba);
                } else {
                        /* Reset FCF roundrobin bmask for new discovery */
-                       memset(phba->fcf.fcf_rr_bmask, 0,
-                              sizeof(*phba->fcf.fcf_rr_bmask));
+                       lpfc_sli4_clear_fcf_rr_bmask(phba);
                        /*
                         * Handling fast FCF failover to a DEAD FCF event is
                         * considered equalivant to receiving CVL to all vports.
@@ -3647,7 +3648,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
                        " tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag);
 
                vport = lpfc_find_vport_by_vpid(phba,
-                               acqe_fip->index - phba->vpi_base);
+                                               acqe_fip->index);
                ndlp = lpfc_sli4_perform_vport_cvl(vport);
                if (!ndlp)
                        break;
@@ -3719,8 +3720,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
                                 * Reset FCF roundrobin bmask for new
                                 * discovery.
                                 */
-                               memset(phba->fcf.fcf_rr_bmask, 0,
-                                      sizeof(*phba->fcf.fcf_rr_bmask));
+                               lpfc_sli4_clear_fcf_rr_bmask(phba);
                }
                break;
        default:
@@ -4034,6 +4034,34 @@ lpfc_reset_hba(struct lpfc_hba *phba)
        lpfc_unblock_mgmt_io(phba);
 }
 
+/**
+ * lpfc_sli_sriov_nr_virtfn_get - Get the number of sr-iov virtual functions
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This function enables the PCI SR-IOV virtual functions to a physical
+ * function. It invokes the PCI SR-IOV api with the @nr_vfn provided to
+ * enable the number of virtual functions to the physical function. As
+ * not all devices support SR-IOV, the return code from the pci_enable_sriov()
+ * API call does not considered as an error condition for most of the device.
+ **/
+uint16_t
+lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *phba)
+{
+       struct pci_dev *pdev = phba->pcidev;
+       uint16_t nr_virtfn;
+       int pos;
+
+       if (!pdev->is_physfn)
+               return 0;
+
+       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+       if (pos == 0)
+               return 0;
+
+       pci_read_config_word(pdev, pos + PCI_SRIOV_TOTAL_VF, &nr_virtfn);
+       return nr_virtfn;
+}
+
 /**
  * lpfc_sli_probe_sriov_nr_virtfn - Enable a number of sr-iov virtual functions
  * @phba: pointer to lpfc hba data structure.
@@ -4049,8 +4077,17 @@ int
 lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn)
 {
        struct pci_dev *pdev = phba->pcidev;
+       uint16_t max_nr_vfn;
        int rc;
 
+       max_nr_vfn = lpfc_sli_sriov_nr_virtfn_get(phba);
+       if (nr_vfn > max_nr_vfn) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                               "3057 Requested vfs (%d) greater than "
+                               "supported vfs (%d)", nr_vfn, max_nr_vfn);
+               return -EINVAL;
+       }
+
        rc = pci_enable_sriov(pdev, nr_vfn);
        if (rc) {
                lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -4516,7 +4553,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                }
        }
 
-       return rc;
+       return 0;
 
 out_free_fcp_eq_hdl:
        kfree(phba->sli4_hba.fcp_eq_hdl);
@@ -4966,17 +5003,14 @@ out_free_mem:
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to post rpi header templates to the
- * HBA consistent with the SLI-4 interface spec.  This routine
+ * port for those SLI4 ports that do not support extents.  This routine
  * posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers.
- * No locks are held here because this is an initialization routine
- * called only from probe or lpfc_online when interrupts are not
- * enabled and the driver is reinitializing the device.
+ * PAGE_SIZE modulo 64 rpi context headers.  This is an initialization routine
+ * and should be called only when interrupts are disabled.
  *
  * Return codes
  *     0 - successful
- *     -ENOMEM - No available memory
- *      -EIO - The mailbox failed to complete successfully.
+ *     -ERROR - otherwise.
  **/
 int
 lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba)
@@ -5687,17 +5721,22 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)
                break;
        case LPFC_SLI_INTF_IF_TYPE_2:
                phba->sli4_hba.u.if_type2.ERR1regaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_1;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_ER1_OFFSET;
                phba->sli4_hba.u.if_type2.ERR2regaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_2;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_ER2_OFFSET;
                phba->sli4_hba.u.if_type2.CTRLregaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_CNTRL;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_CTL_OFFSET;
                phba->sli4_hba.u.if_type2.STATUSregaddr =
-                       phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_STATUS;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_STA_OFFSET;
                phba->sli4_hba.SLIINTFregaddr =
                        phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF;
                phba->sli4_hba.PSMPHRregaddr =
-                    phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_IF2_SMPHR;
+                       phba->sli4_hba.conf_regs_memmap_p +
+                                               LPFC_CTL_PORT_SEM_OFFSET;
                phba->sli4_hba.RQDBregaddr =
                        phba->sli4_hba.conf_regs_memmap_p + LPFC_RQ_DOORBELL;
                phba->sli4_hba.WQDBregaddr =
@@ -8859,11 +8898,11 @@ lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)
                return -EINVAL;
        }
        lpfc_decode_firmware_rev(phba, fwrev, 1);
-       if (strncmp(fwrev, image->rev_name, strnlen(fwrev, 16))) {
+       if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "3023 Updating Firmware. Current Version:%s "
                                "New Version:%s\n",
-                               fwrev, image->rev_name);
+                               fwrev, image->revision);
                for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) {
                        dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),
                                         GFP_KERNEL);
@@ -8892,9 +8931,9 @@ lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)
                                               fw->size - offset);
                                        break;
                                }
-                               temp_offset += SLI4_PAGE_SIZE;
                                memcpy(dmabuf->virt, fw->data + temp_offset,
                                       SLI4_PAGE_SIZE);
+                               temp_offset += SLI4_PAGE_SIZE;
                        }
                        rc = lpfc_wr_object(phba, &dma_buffer_list,
                                    (fw->size - offset), &offset);
@@ -9005,6 +9044,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
        }
 
        INIT_LIST_HEAD(&phba->active_rrq_list);
+       INIT_LIST_HEAD(&phba->fcf.fcf_pri_list);
 
        /* Set up common device driver resources */
        error = lpfc_setup_driver_resource_phase2(phba);
@@ -9112,7 +9152,6 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
 
        /* Check if there are static vports to be created. */
        lpfc_create_static_vport(phba);
-
        return 0;
 
 out_disable_intr:
@@ -9483,6 +9522,13 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev)
        }
 
        pci_restore_state(pdev);
+
+       /*
+        * As the new kernel behavior of pci_restore_state() API call clears
+        * device saved_state flag, need to save the restored state again.
+        */
+       pci_save_state(pdev);
+
        if (pdev->is_busmaster)
                pci_set_master(pdev);
 
index 55676702835357710470ebf65010f69b08813696..83450cc5c4d3d0f722e214e4d09398501d491207 100644 (file)
@@ -2031,7 +2031,7 @@ lpfc_init_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport)
        bf_set(lpfc_init_vfi_vp, init_vfi, 1);
        bf_set(lpfc_init_vfi_vfi, init_vfi,
               vport->phba->sli4_hba.vfi_ids[vport->vfi]);
-       bf_set(lpfc_init_vpi_vpi, init_vfi,
+       bf_set(lpfc_init_vfi_vpi, init_vfi,
               vport->phba->vpi_ids[vport->vpi]);
        bf_set(lpfc_init_vfi_fcfi, init_vfi,
               vport->phba->fcf.fcfi);
index 3ccc97496ebfdb17c3aa63ce1fa0259dc497780c..eadd241eeff113cffc7a893412c43662ba695828 100644 (file)
@@ -1302,13 +1302,13 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                case SCSI_PROT_NORMAL:
                default:
                        lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-                               "9063 BLKGRD: Bad op/guard:%d/%d combination\n",
-                                       scsi_get_prot_op(sc), guard_type);
+                               "9063 BLKGRD: Bad op/guard:%d/IP combination\n",
+                                       scsi_get_prot_op(sc));
                        ret = 1;
                        break;
 
                }
-       } else if (guard_type == SHOST_DIX_GUARD_CRC) {
+       } else {
                switch (scsi_get_prot_op(sc)) {
                case SCSI_PROT_READ_STRIP:
                case SCSI_PROT_WRITE_INSERT:
@@ -1324,17 +1324,18 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
                case SCSI_PROT_READ_INSERT:
                case SCSI_PROT_WRITE_STRIP:
+                       *txop = BG_OP_IN_CRC_OUT_NODIF;
+                       *rxop = BG_OP_IN_NODIF_OUT_CRC;
+                       break;
+
                case SCSI_PROT_NORMAL:
                default:
                        lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-                               "9075 BLKGRD: Bad op/guard:%d/%d combination\n",
-                                       scsi_get_prot_op(sc), guard_type);
+                               "9075 BLKGRD: Bad op/guard:%d/CRC combination\n",
+                                       scsi_get_prot_op(sc));
                        ret = 1;
                        break;
                }
-       } else {
-               /* unsupported format */
-               BUG();
        }
 
        return ret;
@@ -1352,45 +1353,6 @@ lpfc_cmd_blksize(struct scsi_cmnd *sc)
        return sc->device->sector_size;
 }
 
-/**
- * lpfc_get_cmd_dif_parms - Extract DIF parameters from SCSI command
- * @sc:             in: SCSI command
- * @apptagmask:     out: app tag mask
- * @apptagval:      out: app tag value
- * @reftag:         out: ref tag (reference tag)
- *
- * Description:
- *   Extract DIF parameters from the command if possible.  Otherwise,
- *   use default parameters.
- *
- **/
-static inline void
-lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask,
-               uint16_t *apptagval, uint32_t *reftag)
-{
-       struct  scsi_dif_tuple *spt;
-       unsigned char op = scsi_get_prot_op(sc);
-       unsigned int protcnt = scsi_prot_sg_count(sc);
-       static int cnt;
-
-       if (protcnt && (op == SCSI_PROT_WRITE_STRIP ||
-                               op == SCSI_PROT_WRITE_PASS)) {
-
-               cnt++;
-               spt = page_address(sg_page(scsi_prot_sglist(sc))) +
-                       scsi_prot_sglist(sc)[0].offset;
-               *apptagmask = 0;
-               *apptagval = 0;
-               *reftag = cpu_to_be32(spt->ref_tag);
-
-       } else {
-               /* SBC defines ref tag to be lower 32bits of LBA */
-               *reftag = (uint32_t) (0xffffffff & scsi_get_lba(sc));
-               *apptagmask = 0;
-               *apptagval = 0;
-       }
-}
-
 /*
  * This function sets up buffer list for protection groups of
  * type LPFC_PG_TYPE_NO_DIF
@@ -1427,9 +1389,8 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
        dma_addr_t physaddr;
        int i = 0, num_bde = 0, status;
        int datadir = sc->sc_data_direction;
-       unsigned blksize;
        uint32_t reftag;
-       uint16_t apptagmask, apptagval;
+       unsigned blksize;
        uint8_t txop, rxop;
 
        status  = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
@@ -1438,17 +1399,16 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
        /* extract some info from the scsi command for pde*/
        blksize = lpfc_cmd_blksize(sc);
-       lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
+       reftag = scsi_get_lba(sc) & 0xffffffff;
 
        /* setup PDE5 with what we have */
        pde5 = (struct lpfc_pde5 *) bpl;
        memset(pde5, 0, sizeof(struct lpfc_pde5));
        bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
-       pde5->reftag = reftag;
 
        /* Endianness conversion if necessary for PDE5 */
        pde5->word0 = cpu_to_le32(pde5->word0);
-       pde5->reftag = cpu_to_le32(pde5->reftag);
+       pde5->reftag = cpu_to_le32(reftag);
 
        /* advance bpl and increment bde count */
        num_bde++;
@@ -1463,10 +1423,10 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
        if (datadir == DMA_FROM_DEVICE) {
                bf_set(pde6_ce, pde6, 1);
                bf_set(pde6_re, pde6, 1);
-               bf_set(pde6_ae, pde6, 1);
        }
        bf_set(pde6_ai, pde6, 1);
-       bf_set(pde6_apptagval, pde6, apptagval);
+       bf_set(pde6_ae, pde6, 0);
+       bf_set(pde6_apptagval, pde6, 0);
 
        /* Endianness conversion if necessary for PDE6 */
        pde6->word0 = cpu_to_le32(pde6->word0);
@@ -1551,7 +1511,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
        unsigned char pgdone = 0, alldone = 0;
        unsigned blksize;
        uint32_t reftag;
-       uint16_t apptagmask, apptagval;
        uint8_t txop, rxop;
        int num_bde = 0;
 
@@ -1571,7 +1530,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
        /* extract some info from the scsi command */
        blksize = lpfc_cmd_blksize(sc);
-       lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
+       reftag = scsi_get_lba(sc) & 0xffffffff;
 
        split_offset = 0;
        do {
@@ -1579,11 +1538,10 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                pde5 = (struct lpfc_pde5 *) bpl;
                memset(pde5, 0, sizeof(struct lpfc_pde5));
                bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
-               pde5->reftag = reftag;
 
                /* Endianness conversion if necessary for PDE5 */
                pde5->word0 = cpu_to_le32(pde5->word0);
-               pde5->reftag = cpu_to_le32(pde5->reftag);
+               pde5->reftag = cpu_to_le32(reftag);
 
                /* advance bpl and increment bde count */
                num_bde++;
@@ -1597,9 +1555,9 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                bf_set(pde6_oprx, pde6, rxop);
                bf_set(pde6_ce, pde6, 1);
                bf_set(pde6_re, pde6, 1);
-               bf_set(pde6_ae, pde6, 1);
                bf_set(pde6_ai, pde6, 1);
-               bf_set(pde6_apptagval, pde6, apptagval);
+               bf_set(pde6_ae, pde6, 0);
+               bf_set(pde6_apptagval, pde6, 0);
 
                /* Endianness conversion if necessary for PDE6 */
                pde6->word0 = cpu_to_le32(pde6->word0);
@@ -1621,8 +1579,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                memset(pde7, 0, sizeof(struct lpfc_pde7));
                bf_set(pde7_type, pde7, LPFC_PDE7_DESCRIPTOR);
 
-               pde7->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr));
-               pde7->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
+               pde7->addrHigh = le32_to_cpu(putPaddrHigh(protphysaddr));
+               pde7->addrLow = le32_to_cpu(putPaddrLow(protphysaddr));
 
                protgrp_blks = protgroup_len / 8;
                protgrp_bytes = protgrp_blks * blksize;
@@ -1632,7 +1590,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                        protgroup_remainder = 0x1000 - (pde7->addrLow & 0xfff);
                        protgroup_offset += protgroup_remainder;
                        protgrp_blks = protgroup_remainder / 8;
-                       protgrp_bytes = protgroup_remainder * blksize;
+                       protgrp_bytes = protgrp_blks * blksize;
                } else {
                        protgroup_offset = 0;
                        curr_prot++;
@@ -2006,16 +1964,21 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
        if (lpfc_bgs_get_hi_water_mark_present(bgstat)) {
                /*
                 * setup sense data descriptor 0 per SPC-4 as an information
-                * field, and put the failing LBA in it
+                * field, and put the failing LBA in it.
+                * This code assumes there was also a guard/app/ref tag error
+                * indication.
                 */
-               cmd->sense_buffer[8] = 0;     /* Information */
-               cmd->sense_buffer[9] = 0xa;   /* Add. length */
+               cmd->sense_buffer[7] = 0xc;   /* Additional sense length */
+               cmd->sense_buffer[8] = 0;     /* Information descriptor type */
+               cmd->sense_buffer[9] = 0xa;   /* Additional descriptor length */
+               cmd->sense_buffer[10] = 0x80; /* Validity bit */
                bghm /= cmd->device->sector_size;
 
                failing_sector = scsi_get_lba(cmd);
                failing_sector += bghm;
 
-               put_unaligned_be64(failing_sector, &cmd->sense_buffer[10]);
+               /* Descriptor Information */
+               put_unaligned_be64(failing_sector, &cmd->sense_buffer[12]);
        }
 
        if (!ret) {
index 98999bbd8cbfee0dedefa49f90a85917c3cf2e33..8b799f047a99fd2590a8bdbc1ddc9256887463f7 100644 (file)
@@ -560,7 +560,7 @@ __lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
        rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
        if (rrq) {
                rrq->send_rrq = send_rrq;
-               rrq->xritag = phba->sli4_hba.xri_ids[xritag];
+               rrq->xritag = xritag;
                rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
                rrq->ndlp = ndlp;
                rrq->nlp_DID = ndlp->nlp_DID;
@@ -2452,7 +2452,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
                /* search continue save q for same XRI */
                list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) {
-                       if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) {
+                       if (iocbq->iocb.unsli3.rcvsli3.ox_id ==
+                               saveq->iocb.unsli3.rcvsli3.ox_id) {
                                list_add_tail(&saveq->list, &iocbq->list);
                                found = 1;
                                break;
@@ -3355,6 +3356,7 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,
                                                           irspiocbq);
                        break;
                case CQE_CODE_RECEIVE:
+               case CQE_CODE_RECEIVE_V1:
                        dmabuf = container_of(cq_event, struct hbq_dmabuf,
                                              cq_event);
                        lpfc_sli4_handle_received_buffer(phba, dmabuf);
@@ -4712,10 +4714,15 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)
  * lpfc_sli4_get_avail_extnt_rsrc - Get available resource extent count.
  * @phba: Pointer to HBA context object.
  * @type: The resource extent type.
+ * @extnt_count: buffer to hold port available extent count.
+ * @extnt_size: buffer to hold element count per extent.
  *
- * This function allocates all SLI4 resource identifiers.
+ * This function calls the port and retrievs the number of available
+ * extents and their size for a particular extent type.
+ *
+ * Returns: 0 if successful.  Nonzero otherwise.
  **/
-static int
+int
 lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type,
                               uint16_t *extnt_count, uint16_t *extnt_size)
 {
@@ -4892,7 +4899,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,
                                     req_len, *emb);
        if (alloc_len < req_len) {
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-                       "9000 Allocated DMA memory size (x%x) is "
+                       "2982 Allocated DMA memory size (x%x) is "
                        "less than the requested DMA memory "
                        "size (x%x)\n", alloc_len, req_len);
                return -ENOMEM;
@@ -5505,6 +5512,154 @@ lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba)
        return 0;
 }
 
+/**
+ * lpfc_sli4_get_allocated_extnts - Get the port's allocated extents.
+ * @phba: Pointer to HBA context object.
+ * @type: The resource extent type.
+ * @extnt_count: buffer to hold port extent count response
+ * @extnt_size: buffer to hold port extent size response.
+ *
+ * This function calls the port to read the host allocated extents
+ * for a particular type.
+ **/
+int
+lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type,
+                              uint16_t *extnt_cnt, uint16_t *extnt_size)
+{
+       bool emb;
+       int rc = 0;
+       uint16_t curr_blks = 0;
+       uint32_t req_len, emb_len;
+       uint32_t alloc_len, mbox_tmo;
+       struct list_head *blk_list_head;
+       struct lpfc_rsrc_blks *rsrc_blk;
+       LPFC_MBOXQ_t *mbox;
+       void *virtaddr = NULL;
+       struct lpfc_mbx_nembed_rsrc_extent *n_rsrc;
+       struct lpfc_mbx_alloc_rsrc_extents *rsrc_ext;
+       union  lpfc_sli4_cfg_shdr *shdr;
+
+       switch (type) {
+       case LPFC_RSC_TYPE_FCOE_VPI:
+               blk_list_head = &phba->lpfc_vpi_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_XRI:
+               blk_list_head = &phba->sli4_hba.lpfc_xri_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_VFI:
+               blk_list_head = &phba->sli4_hba.lpfc_vfi_blk_list;
+               break;
+       case LPFC_RSC_TYPE_FCOE_RPI:
+               blk_list_head = &phba->sli4_hba.lpfc_rpi_blk_list;
+               break;
+       default:
+               return -EIO;
+       }
+
+       /* Count the number of extents currently allocatd for this type. */
+       list_for_each_entry(rsrc_blk, blk_list_head, list) {
+               if (curr_blks == 0) {
+                       /*
+                        * The GET_ALLOCATED mailbox does not return the size,
+                        * just the count.  The size should be just the size
+                        * stored in the current allocated block and all sizes
+                        * for an extent type are the same so set the return
+                        * value now.
+                        */
+                       *extnt_size = rsrc_blk->rsrc_size;
+               }
+               curr_blks++;
+       }
+
+       /* Calculate the total requested length of the dma memory. */
+       req_len = curr_blks * sizeof(uint16_t);
+
+       /*
+        * Calculate the size of an embedded mailbox.  The uint32_t
+        * accounts for extents-specific word.
+        */
+       emb_len = sizeof(MAILBOX_t) - sizeof(struct mbox_header) -
+               sizeof(uint32_t);
+
+       /*
+        * Presume the allocation and response will fit into an embedded
+        * mailbox.  If not true, reconfigure to a non-embedded mailbox.
+        */
+       emb = LPFC_SLI4_MBX_EMBED;
+       req_len = emb_len;
+       if (req_len > emb_len) {
+               req_len = curr_blks * sizeof(uint16_t) +
+                       sizeof(union lpfc_sli4_cfg_shdr) +
+                       sizeof(uint32_t);
+               emb = LPFC_SLI4_MBX_NEMBED;
+       }
+
+       mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox)
+               return -ENOMEM;
+       memset(mbox, 0, sizeof(LPFC_MBOXQ_t));
+
+       alloc_len = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+                                    LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT,
+                                    req_len, emb);
+       if (alloc_len < req_len) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                       "2983 Allocated DMA memory size (x%x) is "
+                       "less than the requested DMA memory "
+                       "size (x%x)\n", alloc_len, req_len);
+               rc = -ENOMEM;
+               goto err_exit;
+       }
+       rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, curr_blks, type, emb);
+       if (unlikely(rc)) {
+               rc = -EIO;
+               goto err_exit;
+       }
+
+       if (!phba->sli4_hba.intr_enable)
+               rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+       else {
+               mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG);
+               rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo);
+       }
+
+       if (unlikely(rc)) {
+               rc = -EIO;
+               goto err_exit;
+       }
+
+       /*
+        * Figure out where the response is located.  Then get local pointers
+        * to the response data.  The port does not guarantee to respond to
+        * all extents counts request so update the local variable with the
+        * allocated count from the port.
+        */
+       if (emb == LPFC_SLI4_MBX_EMBED) {
+               rsrc_ext = &mbox->u.mqe.un.alloc_rsrc_extents;
+               shdr = &rsrc_ext->header.cfg_shdr;
+               *extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, &rsrc_ext->u.rsp);
+       } else {
+               virtaddr = mbox->sge_array->addr[0];
+               n_rsrc = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr;
+               shdr = &n_rsrc->cfg_shdr;
+               *extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, n_rsrc);
+       }
+
+       if (bf_get(lpfc_mbox_hdr_status, &shdr->response)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
+                       "2984 Failed to read allocated resources "
+                       "for type %d - Status 0x%x Add'l Status 0x%x.\n",
+                       type,
+                       bf_get(lpfc_mbox_hdr_status, &shdr->response),
+                       bf_get(lpfc_mbox_hdr_add_status, &shdr->response));
+               rc = -EIO;
+               goto err_exit;
+       }
+ err_exit:
+       lpfc_sli4_mbox_cmd_free(phba, mbox);
+       return rc;
+}
+
 /**
  * lpfc_sli4_hba_setup - SLI4 device intialization PCI function
  * @phba: Pointer to HBA context object.
@@ -5837,6 +5992,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
                                        "Advanced Error Reporting (AER)\n");
                        phba->cfg_aer_support = 0;
                }
+               rc = 0;
        }
 
        if (!(phba->hba_flag & HBA_FCOE_MODE)) {
@@ -6634,6 +6790,9 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
        unsigned long iflags;
        int rc;
 
+       /* dump from issue mailbox command if setup */
+       lpfc_idiag_mbxacc_dump_issue_mbox(phba, &mboxq->u.mb);
+
        rc = lpfc_mbox_dev_check(phba);
        if (unlikely(rc)) {
                lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
@@ -7318,12 +7477,12 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1);
                bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE);
                bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0);
-       break;
+               break;
        case CMD_XMIT_SEQUENCE64_CX:
                bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com,
                       iocbq->iocb.un.ulpWord[3]);
                bf_set(wqe_rcvoxid, &wqe->xmit_sequence.wqe_com,
-                      iocbq->iocb.ulpContext);
+                      iocbq->iocb.unsli3.rcvsli3.ox_id);
                /* The entire sequence is transmitted for this IOCB */
                xmit_len = total_len;
                cmnd = CMD_XMIT_SEQUENCE64_CR;
@@ -7341,7 +7500,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_ebde_cnt, &wqe->xmit_sequence.wqe_com, 0);
                wqe->xmit_sequence.xmit_len = xmit_len;
                command_type = OTHER_COMMAND;
-       break;
+               break;
        case CMD_XMIT_BCAST64_CN:
                /* word3 iocb=iotag32 wqe=seq_payload_len */
                wqe->xmit_bcast64.seq_payload_len = xmit_len;
@@ -7355,7 +7514,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_lenloc, &wqe->xmit_bcast64.wqe_com,
                       LPFC_WQE_LENLOC_WORD3);
                bf_set(wqe_ebde_cnt, &wqe->xmit_bcast64.wqe_com, 0);
-       break;
+               break;
        case CMD_FCP_IWRITE64_CR:
                command_type = FCP_COMMAND_DATA_OUT;
                /* word3 iocb=iotag wqe=payload_offset_len */
@@ -7375,7 +7534,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                       LPFC_WQE_LENLOC_WORD4);
                bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);
                bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU);
-       break;
+               break;
        case CMD_FCP_IREAD64_CR:
                /* word3 iocb=iotag wqe=payload_offset_len */
                /* Add the FCP_CMD and FCP_RSP sizes to get the offset */
@@ -7394,7 +7553,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                       LPFC_WQE_LENLOC_WORD4);
                bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);
                bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU);
-       break;
+               break;
        case CMD_FCP_ICMND64_CR:
                /* word3 iocb=IO_TAG wqe=reserved */
                wqe->fcp_icmd.rsrvd3 = 0;
@@ -7407,7 +7566,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com,
                       LPFC_WQE_LENLOC_NONE);
                bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0);
-       break;
+               break;
        case CMD_GEN_REQUEST64_CR:
                /* For this command calculate the xmit length of the
                 * request bde.
@@ -7442,7 +7601,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE);
                bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0);
                command_type = OTHER_COMMAND;
-       break;
+               break;
        case CMD_XMIT_ELS_RSP64_CX:
                ndlp = (struct lpfc_nodelist *)iocbq->context1;
                /* words0-2 BDE memcpy */
@@ -7457,7 +7616,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                       ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));
                bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU);
                bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com,
-                      iocbq->iocb.ulpContext);
+                      iocbq->iocb.unsli3.rcvsli3.ox_id);
                if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l)
                        bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com,
                               phba->vpi_ids[iocbq->vport->vpi]);
@@ -7470,7 +7629,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp,
                       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
                command_type = OTHER_COMMAND;
-       break;
+               break;
        case CMD_CLOSE_XRI_CN:
        case CMD_ABORT_XRI_CN:
        case CMD_ABORT_XRI_CX:
@@ -7509,7 +7668,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                cmnd = CMD_ABORT_XRI_CX;
                command_type = OTHER_COMMAND;
                xritag = 0;
-       break;
+               break;
        case CMD_XMIT_BLS_RSP64_CX:
                /* As BLS ABTS RSP WQE is very different from other WQEs,
                 * we re-construct this WQE here based on information in
@@ -7553,7 +7712,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                               bf_get(lpfc_rsn_code, &iocbq->iocb.un.bls_rsp));
                }
 
-       break;
+               break;
        case CMD_XRI_ABORTED_CX:
        case CMD_CREATE_XRI_CR: /* Do we expect to use this? */
        case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */
@@ -7565,7 +7724,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
                                "2014 Invalid command 0x%x\n",
                                iocbq->iocb.ulpCommand);
                return IOCB_ERROR;
-       break;
+               break;
        }
 
        bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag);
@@ -10481,10 +10640,14 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)
        struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq;
        struct lpfc_queue *drq = phba->sli4_hba.dat_rq;
        struct hbq_dmabuf *dma_buf;
-       uint32_t status;
+       uint32_t status, rq_id;
        unsigned long iflags;
 
-       if (bf_get(lpfc_rcqe_rq_id, rcqe) != hrq->queue_id)
+       if (bf_get(lpfc_cqe_code, rcqe) == CQE_CODE_RECEIVE_V1)
+               rq_id = bf_get(lpfc_rcqe_rq_id_v1, rcqe);
+       else
+               rq_id = bf_get(lpfc_rcqe_rq_id, rcqe);
+       if (rq_id != hrq->queue_id)
                goto out;
 
        status = bf_get(lpfc_rcqe_status, rcqe);
@@ -10563,6 +10726,7 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
                                (struct sli4_wcqe_xri_aborted *)&cqevt);
                break;
        case CQE_CODE_RECEIVE:
+       case CQE_CODE_RECEIVE_V1:
                /* Process the RQ event */
                phba->last_completion_time = jiffies;
                workposted = lpfc_sli4_sp_handle_rcqe(phba,
@@ -12345,19 +12509,18 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba,
 }
 
 /**
- * lpfc_sli4_init_rpi_hdrs - Post the rpi header memory region to the port
+ * lpfc_sli4_alloc_xri - Get an available rpi in the device's range
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is invoked to post rpi header templates to the
- * port for those SLI4 ports that do not support extents.  This routine
- * posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers.  This is an initialization routine
- * and should be called only when interrupts are disabled.
+ * HBA consistent with the SLI-4 interface spec.  This routine
+ * posts a SLI4_PAGE_SIZE memory region to the port to hold up to
+ * SLI4_PAGE_SIZE modulo 64 rpi context headers.
  *
- * Return codes
- *     0 - successful
- *     -ERROR - otherwise.
- */
+ * Returns
+ *     A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful
+ *     LPFC_RPI_ALLOC_ERROR if no rpis are available.
+ **/
 uint16_t
 lpfc_sli4_alloc_xri(struct lpfc_hba *phba)
 {
@@ -13406,7 +13569,7 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba,
  * This function validates the xri maps to the known range of XRIs allocated an
  * used by the driver.
  **/
-static uint16_t
+uint16_t
 lpfc_sli4_xri_inrange(struct lpfc_hba *phba,
                      uint16_t xri)
 {
@@ -13643,10 +13806,12 @@ lpfc_seq_complete(struct hbq_dmabuf *dmabuf)
 static struct lpfc_iocbq *
 lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
 {
+       struct hbq_dmabuf *hbq_buf;
        struct lpfc_dmabuf *d_buf, *n_buf;
        struct lpfc_iocbq *first_iocbq, *iocbq;
        struct fc_frame_header *fc_hdr;
        uint32_t sid;
+       uint32_t len, tot_len;
        struct ulp_bde64 *pbde;
 
        fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt;
@@ -13655,6 +13820,7 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
        lpfc_update_rcv_time_stamp(vport);
        /* get the Remote Port's SID */
        sid = sli4_sid_from_fc_hdr(fc_hdr);
+       tot_len = 0;
        /* Get an iocbq struct to fill in. */
        first_iocbq = lpfc_sli_get_iocbq(vport->phba);
        if (first_iocbq) {
@@ -13662,9 +13828,12 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
                first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0;
                first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;
                first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
-               first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id);
-               /* iocbq is prepped for internal consumption.  Logical vpi. */
-               first_iocbq->iocb.unsli3.rcvsli3.vpi = vport->vpi;
+               first_iocbq->iocb.ulpContext = NO_XRI;
+               first_iocbq->iocb.unsli3.rcvsli3.ox_id =
+                       be16_to_cpu(fc_hdr->fh_ox_id);
+               /* iocbq is prepped for internal consumption.  Physical vpi. */
+               first_iocbq->iocb.unsli3.rcvsli3.vpi =
+                       vport->phba->vpi_ids[vport->vpi];
                /* put the first buffer into the first IOCBq */
                first_iocbq->context2 = &seq_dmabuf->dbuf;
                first_iocbq->context3 = NULL;
@@ -13672,9 +13841,9 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
                first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
                                                        LPFC_DATA_BUF_SIZE;
                first_iocbq->iocb.un.rcvels.remoteID = sid;
-               first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
-                               bf_get(lpfc_rcqe_length,
+               tot_len = bf_get(lpfc_rcqe_length,
                                       &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+               first_iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
        }
        iocbq = first_iocbq;
        /*
@@ -13692,9 +13861,13 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
                        pbde = (struct ulp_bde64 *)
                                        &iocbq->iocb.unsli3.sli3Words[4];
                        pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE;
-                       first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
-                               bf_get(lpfc_rcqe_length,
-                                      &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+
+                       /* We need to get the size out of the right CQE */
+                       hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+                       len = bf_get(lpfc_rcqe_length,
+                                      &hbq_buf->cq_event.cqe.rcqe_cmpl);
+                       iocbq->iocb.unsli3.rcvsli3.acc_len += len;
+                       tot_len += len;
                } else {
                        iocbq = lpfc_sli_get_iocbq(vport->phba);
                        if (!iocbq) {
@@ -13712,9 +13885,14 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
                        iocbq->iocb.ulpBdeCount = 1;
                        iocbq->iocb.un.cont64[0].tus.f.bdeSize =
                                                        LPFC_DATA_BUF_SIZE;
-                       first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
-                               bf_get(lpfc_rcqe_length,
-                                      &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+
+                       /* We need to get the size out of the right CQE */
+                       hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+                       len = bf_get(lpfc_rcqe_length,
+                                      &hbq_buf->cq_event.cqe.rcqe_cmpl);
+                       tot_len += len;
+                       iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
+
                        iocbq->iocb.un.rcvels.remoteID = sid;
                        list_add_tail(&iocbq->list, &first_iocbq->list);
                }
@@ -13787,7 +13965,13 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
                lpfc_in_buf_free(phba, &dmabuf->dbuf);
                return;
        }
-       fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl);
+       if ((bf_get(lpfc_cqe_code,
+                   &dmabuf->cq_event.cqe.rcqe_cmpl) == CQE_CODE_RECEIVE_V1))
+               fcfi = bf_get(lpfc_rcqe_fcf_id_v1,
+                             &dmabuf->cq_event.cqe.rcqe_cmpl);
+       else
+               fcfi = bf_get(lpfc_rcqe_fcf_id,
+                             &dmabuf->cq_event.cqe.rcqe_cmpl);
        vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi);
        if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) {
                /* throw out the frame */
@@ -14450,6 +14634,92 @@ fail_fcf_read:
        return error;
 }
 
+/**
+ * lpfc_check_next_fcf_pri
+ * phba pointer to the lpfc_hba struct for this port.
+ * This routine is called from the lpfc_sli4_fcf_rr_next_index_get
+ * routine when the rr_bmask is empty. The FCF indecies are put into the
+ * rr_bmask based on their priority level. Starting from the highest priority
+ * to the lowest. The most likely FCF candidate will be in the highest
+ * priority group. When this routine is called it searches the fcf_pri list for
+ * next lowest priority group and repopulates the rr_bmask with only those
+ * fcf_indexes.
+ * returns:
+ * 1=success 0=failure
+ **/
+int
+lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba)
+{
+       uint16_t next_fcf_pri;
+       uint16_t last_index;
+       struct lpfc_fcf_pri *fcf_pri;
+       int rc;
+       int ret = 0;
+
+       last_index = find_first_bit(phba->fcf.fcf_rr_bmask,
+                       LPFC_SLI4_FCF_TBL_INDX_MAX);
+       lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+                       "3060 Last IDX %d\n", last_index);
+       if (list_empty(&phba->fcf.fcf_pri_list)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+                       "3061 Last IDX %d\n", last_index);
+               return 0; /* Empty rr list */
+       }
+       next_fcf_pri = 0;
+       /*
+        * Clear the rr_bmask and set all of the bits that are at this
+        * priority.
+        */
+       memset(phba->fcf.fcf_rr_bmask, 0,
+                       sizeof(*phba->fcf.fcf_rr_bmask));
+       spin_lock_irq(&phba->hbalock);
+       list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
+               if (fcf_pri->fcf_rec.flag & LPFC_FCF_FLOGI_FAILED)
+                       continue;
+               /*
+                * the 1st priority that has not FLOGI failed
+                * will be the highest.
+                */
+               if (!next_fcf_pri)
+                       next_fcf_pri = fcf_pri->fcf_rec.priority;
+               spin_unlock_irq(&phba->hbalock);
+               if (fcf_pri->fcf_rec.priority == next_fcf_pri) {
+                       rc = lpfc_sli4_fcf_rr_index_set(phba,
+                                               fcf_pri->fcf_rec.fcf_index);
+                       if (rc)
+                               return 0;
+               }
+               spin_lock_irq(&phba->hbalock);
+       }
+       /*
+        * if next_fcf_pri was not set above and the list is not empty then
+        * we have failed flogis on all of them. So reset flogi failed
+        * and start at the begining.
+        */
+       if (!next_fcf_pri && !list_empty(&phba->fcf.fcf_pri_list)) {
+               list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
+                       fcf_pri->fcf_rec.flag &= ~LPFC_FCF_FLOGI_FAILED;
+                       /*
+                        * the 1st priority that has not FLOGI failed
+                        * will be the highest.
+                        */
+                       if (!next_fcf_pri)
+                               next_fcf_pri = fcf_pri->fcf_rec.priority;
+                       spin_unlock_irq(&phba->hbalock);
+                       if (fcf_pri->fcf_rec.priority == next_fcf_pri) {
+                               rc = lpfc_sli4_fcf_rr_index_set(phba,
+                                               fcf_pri->fcf_rec.fcf_index);
+                               if (rc)
+                                       return 0;
+                       }
+                       spin_lock_irq(&phba->hbalock);
+               }
+       } else
+               ret = 1;
+       spin_unlock_irq(&phba->hbalock);
+
+       return ret;
+}
 /**
  * lpfc_sli4_fcf_rr_next_index_get - Get next eligible fcf record index
  * @phba: pointer to lpfc hba data structure.
@@ -14466,6 +14736,7 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
        uint16_t next_fcf_index;
 
        /* Search start from next bit of currently registered FCF index */
+next_priority:
        next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) %
                                        LPFC_SLI4_FCF_TBL_INDX_MAX;
        next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
@@ -14473,17 +14744,46 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
                                       next_fcf_index);
 
        /* Wrap around condition on phba->fcf.fcf_rr_bmask */
-       if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
+       if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+               /*
+                * If we have wrapped then we need to clear the bits that
+                * have been tested so that we can detect when we should
+                * change the priority level.
+                */
                next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
                                               LPFC_SLI4_FCF_TBL_INDX_MAX, 0);
+       }
+
 
        /* Check roundrobin failover list empty condition */
-       if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
+       if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX ||
+               next_fcf_index == phba->fcf.current_rec.fcf_indx) {
+               /*
+                * If next fcf index is not found check if there are lower
+                * Priority level fcf's in the fcf_priority list.
+                * Set up the rr_bmask with all of the avaiable fcf bits
+                * at that level and continue the selection process.
+                */
+               if (lpfc_check_next_fcf_pri_level(phba))
+                       goto next_priority;
                lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
                                "2844 No roundrobin failover FCF available\n");
-               return LPFC_FCOE_FCF_NEXT_NONE;
+               if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)
+                       return LPFC_FCOE_FCF_NEXT_NONE;
+               else {
+                       lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+                               "3063 Only FCF available idx %d, flag %x\n",
+                               next_fcf_index,
+                       phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag);
+                       return next_fcf_index;
+               }
        }
 
+       if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX &&
+               phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag &
+               LPFC_FCF_FLOGI_FAILED)
+               goto next_priority;
+
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
                        "2845 Get next roundrobin failover FCF (x%x)\n",
                        next_fcf_index);
@@ -14535,6 +14835,7 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
 void
 lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
 {
+       struct lpfc_fcf_pri *fcf_pri;
        if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
                lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
                                "2762 FCF (x%x) reached driver's book "
@@ -14543,6 +14844,14 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
                return;
        }
        /* Clear the eligible FCF record index bmask */
+       spin_lock_irq(&phba->hbalock);
+       list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
+               if (fcf_pri->fcf_rec.fcf_index == fcf_index) {
+                       list_del_init(&fcf_pri->list);
+                       break;
+               }
+       }
+       spin_unlock_irq(&phba->hbalock);
        clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);
 
        lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
index 4b1703554a265f321cb4fb9c0eafd2b92632f299..19bb87ae85975a84bcf060642c7ba93402638766 100644 (file)
@@ -81,6 +81,8 @@
         (fc_hdr)->fh_f_ctl[1] <<  8 | \
         (fc_hdr)->fh_f_ctl[2])
 
+#define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000
+
 enum lpfc_sli4_queue_type {
        LPFC_EQ,
        LPFC_GCQ,
@@ -157,6 +159,25 @@ struct lpfc_fcf_rec {
 #define RECORD_VALID   0x02
 };
 
+struct lpfc_fcf_pri_rec {
+       uint16_t fcf_index;
+#define LPFC_FCF_ON_PRI_LIST 0x0001
+#define LPFC_FCF_FLOGI_FAILED 0x0002
+       uint16_t flag;
+       uint32_t priority;
+};
+
+struct lpfc_fcf_pri {
+       struct list_head list;
+       struct lpfc_fcf_pri_rec fcf_rec;
+};
+
+/*
+ * Maximum FCF table index, it is for driver internal book keeping, it
+ * just needs to be no less than the supported HBA's FCF table size.
+ */
+#define LPFC_SLI4_FCF_TBL_INDX_MAX     32
+
 struct lpfc_fcf {
        uint16_t fcfi;
        uint32_t fcf_flag;
@@ -176,15 +197,13 @@ struct lpfc_fcf {
        uint32_t eligible_fcf_cnt;
        struct lpfc_fcf_rec current_rec;
        struct lpfc_fcf_rec failover_rec;
+       struct list_head fcf_pri_list;
+       struct lpfc_fcf_pri fcf_pri[LPFC_SLI4_FCF_TBL_INDX_MAX];
+       uint32_t current_fcf_scan_pri;
        struct timer_list redisc_wait;
        unsigned long *fcf_rr_bmask; /* Eligible FCF indexes for RR failover */
 };
 
-/*
- * Maximum FCF table index, it is for driver internal book keeping, it
- * just needs to be no less than the supported HBA's FCF table size.
- */
-#define LPFC_SLI4_FCF_TBL_INDX_MAX     32
 
 #define LPFC_REGION23_SIGNATURE "RG23"
 #define LPFC_REGION23_VERSION  1
index c03921b1232cdf944d00bf195c1a3a04ceeaffb1..c1e0ae94d9f4e6cdc01c648e785a6bc6660a34fa 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.23"
+#define LPFC_DRIVER_VERSION "8.3.25"
 #define LPFC_DRIVER_NAME               "lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME    "lpfc:sp"
 #define LPFC_FP_DRIVER_HANDLER_NAME    "lpfc:fp"
index 7370c084b17855a58f25b5b88faa4ee8ed13d631..3948a00d81f44f536ce308e65ec8cc09dea92a6f 100644 (file)
@@ -33,9 +33,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "00.00.05.38-rc1"
-#define MEGASAS_RELDATE                                "May. 11, 2011"
-#define MEGASAS_EXT_VERSION                    "Wed. May. 11 17:00:00 PDT 2011"
+#define MEGASAS_VERSION                                "00.00.05.40-rc1"
+#define MEGASAS_RELDATE                                "Jul. 26, 2011"
+#define MEGASAS_EXT_VERSION                    "Tue. Jul. 26 17:00:00 PDT 2011"
 
 /*
  * Device IDs
index 2d8cdce7b2f5af14355233424e7092c218821da1..776d0198866044811e521d01911958f40d888768 100644 (file)
@@ -18,7 +18,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  *  FILE: megaraid_sas_base.c
- *  Version : v00.00.05.38-rc1
+ *  Version : v00.00.05.40-rc1
  *
  *  Authors: LSI Corporation
  *           Sreenivas Bagalkote
@@ -54,6 +54,7 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
 #include "megaraid_sas_fusion.h"
 #include "megaraid_sas.h"
 
@@ -2057,6 +2058,20 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
        }
 }
 
+static int megasas_change_queue_depth(struct scsi_device *sdev,
+                                     int queue_depth, int reason)
+{
+       if (reason != SCSI_QDEPTH_DEFAULT)
+               return -EOPNOTSUPP;
+
+       if (queue_depth > sdev->host->can_queue)
+               queue_depth = sdev->host->can_queue;
+       scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev),
+                               queue_depth);
+
+       return queue_depth;
+}
+
 /*
  * Scsi host template for megaraid_sas driver
  */
@@ -2074,6 +2089,7 @@ static struct scsi_host_template megasas_template = {
        .eh_timed_out = megasas_reset_timer,
        .bios_param = megasas_bios_param,
        .use_clustering = ENABLE_CLUSTERING,
+       .change_queue_depth = megasas_change_queue_depth,
 };
 
 /**
index 8fe3a45794fc454fa91fab83153528162dd9890e..5a5af1fe7581846fc2eeab99f73a002c7caa3e97 100644 (file)
@@ -288,7 +288,6 @@ u8 MR_GetPhyParams(u32 ld, u64 stripRow, u16 stripRef, u64 *pdBlock,
                                /* Get dev handle from Pd */
                                *pDevHandle = MR_PdDevHandleGet(pd, map);
                }
-               retval = FALSE;
        }
 
        *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
index 939f283d0c28c3e83fa6d5cfc3e2bab00505a0f3..6abd2fcc43e2dba024ff28c8e7f993b2c82c3d28 100644 (file)
@@ -4258,6 +4258,7 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
        u32 log_info;
        struct MPT2SAS_DEVICE *sas_device_priv_data;
        u32 response_code = 0;
+       unsigned long flags;
 
        mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
        scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
@@ -4282,6 +4283,9 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
         * the failed direct I/O should be redirected to volume
         */
        if (_scsih_scsi_direct_io_get(ioc, smid)) {
+               spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+               ioc->scsi_lookup[smid - 1].scmd = scmd;
+               spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
                _scsih_scsi_direct_io_set(ioc, smid, 0);
                memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
                mpi_request->DevHandle =
index c82b012aba37da7779d6dc03a17b339c8836d2da..78f7e20a0c1c5066b86793ea3dd615dd7fe25f1f 100644 (file)
@@ -3,7 +3,7 @@
 #
 # Copyright 2007 Red Hat, Inc.
 # Copyright 2008 Marvell. <kewei@marvell.com>
-# Copyright 2009-20011 Marvell. <yuxiangl@marvell.com>
+# Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
 #
 # This file is licensed under GPLv2.
 #
@@ -41,3 +41,10 @@ config SCSI_MVSAS_DEBUG
        help
                Compiles the 88SE64XX/88SE94XX driver in debug mode.  In debug mode,
                the driver prints some messages to the console.
+config SCSI_MVSAS_TASKLET
+       bool "Support for interrupt tasklet"
+       default n
+       depends on SCSI_MVSAS
+       help
+               Compiles the 88SE64xx/88SE94xx driver in interrupt tasklet mode.In this mode,
+               the interrupt will schedule a tasklet.
index 13c960481391e8590d0b7b2e3163f58022ca424f..8ba47229049f5d44bde2a6d55a145f9c1b277fff 100644 (file)
@@ -33,7 +33,6 @@ static void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i)
        u32 reg;
        struct mvs_phy *phy = &mvi->phy[i];
 
-       /* TODO check & save device type */
        reg = mr32(MVS_GBL_PORT_TYPE);
        phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
        if (reg & MODE_SAS_SATA & (1 << i))
@@ -48,7 +47,7 @@ static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
        u32 tmp;
 
        tmp = mr32(MVS_PCS);
-       if (mvi->chip->n_phy <= 4)
+       if (mvi->chip->n_phy <= MVS_SOC_PORTS)
                tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT);
        else
                tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2);
@@ -58,24 +57,16 @@ static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
 static void __devinit mvs_64xx_phy_hacks(struct mvs_info *mvi)
 {
        void __iomem *regs = mvi->regs;
+       int i;
 
        mvs_phy_hacks(mvi);
 
        if (!(mvi->flags & MVF_FLAG_SOC)) {
-               /* TEST - for phy decoding error, adjust voltage levels */
-               mw32(MVS_P0_VSR_ADDR + 0, 0x8);
-               mw32(MVS_P0_VSR_DATA + 0, 0x2F0);
-
-               mw32(MVS_P0_VSR_ADDR + 8, 0x8);
-               mw32(MVS_P0_VSR_DATA + 8, 0x2F0);
-
-               mw32(MVS_P0_VSR_ADDR + 16, 0x8);
-               mw32(MVS_P0_VSR_DATA + 16, 0x2F0);
-
-               mw32(MVS_P0_VSR_ADDR + 24, 0x8);
-               mw32(MVS_P0_VSR_DATA + 24, 0x2F0);
+               for (i = 0; i < MVS_SOC_PORTS; i++) {
+                       mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE8);
+                       mvs_write_port_vsr_data(mvi, i, 0x2F0);
+               }
        } else {
-               int i;
                /* disable auto port detection */
                mw32(MVS_GBL_PORT_TYPE, 0);
                for (i = 0; i < mvi->chip->n_phy; i++) {
@@ -95,7 +86,7 @@ static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id)
        u32 reg, tmp;
 
        if (!(mvi->flags & MVF_FLAG_SOC)) {
-               if (phy_id < 4)
+               if (phy_id < MVS_SOC_PORTS)
                        pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &reg);
                else
                        pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &reg);
@@ -104,13 +95,13 @@ static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id)
                reg = mr32(MVS_PHY_CTL);
 
        tmp = reg;
-       if (phy_id < 4)
+       if (phy_id < MVS_SOC_PORTS)
                tmp |= (1U << phy_id) << PCTL_LINK_OFFS;
        else
-               tmp |= (1U << (phy_id - 4)) << PCTL_LINK_OFFS;
+               tmp |= (1U << (phy_id - MVS_SOC_PORTS)) << PCTL_LINK_OFFS;
 
        if (!(mvi->flags & MVF_FLAG_SOC)) {
-               if (phy_id < 4) {
+               if (phy_id < MVS_SOC_PORTS) {
                        pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp);
                        mdelay(10);
                        pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg);
@@ -133,9 +124,9 @@ static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
        tmp &= ~PHYEV_RDY_CH;
        mvs_write_port_irq_stat(mvi, phy_id, tmp);
        tmp = mvs_read_phy_ctl(mvi, phy_id);
-       if (hard == 1)
+       if (hard == MVS_HARD_RESET)
                tmp |= PHY_RST_HARD;
-       else if (hard == 0)
+       else if (hard == MVS_SOFT_RESET)
                tmp |= PHY_RST;
        mvs_write_phy_ctl(mvi, phy_id, tmp);
        if (hard) {
@@ -321,6 +312,11 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi)
        /* init phys */
        mvs_64xx_phy_hacks(mvi);
 
+       tmp = mvs_cr32(mvi, CMD_PHY_MODE_21);
+       tmp &= 0x0000ffff;
+       tmp |= 0x00fa0000;
+       mvs_cw32(mvi, CMD_PHY_MODE_21, tmp);
+
        /* enable auto port detection */
        mw32(MVS_GBL_PORT_TYPE, MODE_AUTO_DET_EN);
 
@@ -346,7 +342,7 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi)
 
                mvs_64xx_enable_xmt(mvi, i);
 
-               mvs_64xx_phy_reset(mvi, i, 1);
+               mvs_64xx_phy_reset(mvi, i, MVS_HARD_RESET);
                msleep(500);
                mvs_64xx_detect_porttype(mvi, i);
        }
@@ -377,13 +373,7 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi)
                mvs_update_phyinfo(mvi, i, 1);
        }
 
-       /* FIXME: update wide port bitmaps */
-
        /* little endian for open address and command table, etc. */
-       /*
-        * it seems that ( from the spec ) turning on big-endian won't
-        * do us any good on big-endian machines, need further confirmation
-        */
        cctl = mr32(MVS_CTL);
        cctl |= CCTL_ENDIAN_CMD;
        cctl |= CCTL_ENDIAN_DATA;
@@ -394,15 +384,19 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi)
        /* reset CMD queue */
        tmp = mr32(MVS_PCS);
        tmp |= PCS_CMD_RST;
+       tmp &= ~PCS_SELF_CLEAR;
        mw32(MVS_PCS, tmp);
-       /* interrupt coalescing may cause missing HW interrput in some case,
-        * and the max count is 0x1ff, while our max slot is 0x200,
+       /*
+        * the max count is 0x1ff, while our max slot is 0x200,
         * it will make count 0.
         */
        tmp = 0;
-       mw32(MVS_INT_COAL, tmp);
+       if (MVS_CHIP_SLOT_SZ > 0x1ff)
+               mw32(MVS_INT_COAL, 0x1ff | COAL_EN);
+       else
+               mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ | COAL_EN);
 
-       tmp = 0x100;
+       tmp = 0x10000 | interrupt_coalescing;
        mw32(MVS_INT_COAL_TMOUT, tmp);
 
        /* ladies and gentlemen, start your engines */
@@ -477,13 +471,11 @@ static irqreturn_t mvs_64xx_isr(struct mvs_info *mvi, int irq, u32 stat)
 
        /* clear CMD_CMPLT ASAP */
        mw32_f(MVS_INT_STAT, CINT_DONE);
-#ifndef MVS_USE_TASKLET
+
        spin_lock(&mvi->lock);
-#endif
        mvs_int_full(mvi);
-#ifndef MVS_USE_TASKLET
        spin_unlock(&mvi->lock);
-#endif
+
        return IRQ_HANDLED;
 }
 
@@ -630,7 +622,6 @@ static void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i)
 {
        u32 tmp;
        struct mvs_phy *phy = &mvi->phy[i];
-       /* workaround for HW phy decoding error on 1.5g disk drive */
        mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
        tmp = mvs_read_port_vsr_data(mvi, i);
        if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
@@ -661,7 +652,7 @@ void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
                tmp |= lrmax;
        }
        mvs_write_phy_ctl(mvi, phy_id, tmp);
-       mvs_64xx_phy_reset(mvi, phy_id, 1);
+       mvs_64xx_phy_reset(mvi, phy_id, MVS_HARD_RESET);
 }
 
 static void mvs_64xx_clear_active_cmds(struct mvs_info *mvi)
@@ -744,11 +735,13 @@ int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
        return -1;
 }
 
-#ifndef DISABLE_HOTPLUG_DMA_FIX
-void mvs_64xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
+void mvs_64xx_fix_dma(struct mvs_info *mvi, u32 phy_mask,
+                               int buf_len, int from, void *prd)
 {
        int i;
        struct mvs_prd *buf_prd = prd;
+       dma_addr_t buf_dma = mvi->bulk_buffer_dma;
+
        buf_prd += from;
        for (i = 0; i < MAX_SG_ENTRY - from; i++) {
                buf_prd->addr = cpu_to_le64(buf_dma);
@@ -756,7 +749,28 @@ void mvs_64xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
                ++buf_prd;
        }
 }
-#endif
+
+static void mvs_64xx_tune_interrupt(struct mvs_info *mvi, u32 time)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp = 0;
+       /*
+        * the max count is 0x1ff, while our max slot is 0x200,
+        * it will make count 0.
+        */
+       if (time == 0) {
+               mw32(MVS_INT_COAL, 0);
+               mw32(MVS_INT_COAL_TMOUT, 0x10000);
+       } else {
+               if (MVS_CHIP_SLOT_SZ > 0x1ff)
+                       mw32(MVS_INT_COAL, 0x1ff|COAL_EN);
+               else
+                       mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN);
+
+               tmp = 0x10000 | time;
+               mw32(MVS_INT_COAL_TMOUT, tmp);
+       }
+}
 
 const struct mvs_dispatch mvs_64xx_dispatch = {
        "mv64xx",
@@ -780,7 +794,6 @@ const struct mvs_dispatch mvs_64xx_dispatch = {
        mvs_write_port_irq_stat,
        mvs_read_port_irq_mask,
        mvs_write_port_irq_mask,
-       mvs_get_sas_addr,
        mvs_64xx_command_active,
        mvs_64xx_clear_srs_irq,
        mvs_64xx_issue_stop,
@@ -808,8 +821,8 @@ const struct mvs_dispatch mvs_64xx_dispatch = {
        mvs_64xx_spi_buildcmd,
        mvs_64xx_spi_issuecmd,
        mvs_64xx_spi_waitdataready,
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        mvs_64xx_fix_dma,
-#endif
+       mvs_64xx_tune_interrupt,
+       NULL,
 };
 
index 78162c3c36e611ea2e5a2ecb2d1951f10a0ef284..3501291618fdad97c2be6bf1fc44292bce240348 100644 (file)
@@ -48,6 +48,216 @@ static void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i)
        }
 }
 
+void set_phy_tuning(struct mvs_info *mvi, int phy_id,
+                       struct phy_tuning phy_tuning)
+{
+       u32 tmp, setting_0 = 0, setting_1 = 0;
+       u8 i;
+
+       /* Remap information for B0 chip:
+       *
+       * R0Ch -> R118h[15:0] (Adapted DFE F3 - F5 coefficient)
+       * R0Dh -> R118h[31:16] (Generation 1 Setting 0)
+       * R0Eh -> R11Ch[15:0]  (Generation 1 Setting 1)
+       * R0Fh -> R11Ch[31:16] (Generation 2 Setting 0)
+       * R10h -> R120h[15:0]  (Generation 2 Setting 1)
+       * R11h -> R120h[31:16] (Generation 3 Setting 0)
+       * R12h -> R124h[15:0]  (Generation 3 Setting 1)
+       * R13h -> R124h[31:16] (Generation 4 Setting 0 (Reserved))
+       */
+
+       /* A0 has a different set of registers */
+       if (mvi->pdev->revision == VANIR_A0_REV)
+               return;
+
+       for (i = 0; i < 3; i++) {
+               /* loop 3 times, set Gen 1, Gen 2, Gen 3 */
+               switch (i) {
+               case 0:
+                       setting_0 = GENERATION_1_SETTING;
+                       setting_1 = GENERATION_1_2_SETTING;
+                       break;
+               case 1:
+                       setting_0 = GENERATION_1_2_SETTING;
+                       setting_1 = GENERATION_2_3_SETTING;
+                       break;
+               case 2:
+                       setting_0 = GENERATION_2_3_SETTING;
+                       setting_1 = GENERATION_3_4_SETTING;
+                       break;
+               }
+
+               /* Set:
+               *
+               * Transmitter Emphasis Enable
+               * Transmitter Emphasis Amplitude
+               * Transmitter Amplitude
+               */
+               mvs_write_port_vsr_addr(mvi, phy_id, setting_0);
+               tmp = mvs_read_port_vsr_data(mvi, phy_id);
+               tmp &= ~(0xFBE << 16);
+               tmp |= (((phy_tuning.trans_emp_en << 11) |
+                       (phy_tuning.trans_emp_amp << 7) |
+                       (phy_tuning.trans_amp << 1)) << 16);
+               mvs_write_port_vsr_data(mvi, phy_id, tmp);
+
+               /* Set Transmitter Amplitude Adjust */
+               mvs_write_port_vsr_addr(mvi, phy_id, setting_1);
+               tmp = mvs_read_port_vsr_data(mvi, phy_id);
+               tmp &= ~(0xC000);
+               tmp |= (phy_tuning.trans_amp_adj << 14);
+               mvs_write_port_vsr_data(mvi, phy_id, tmp);
+       }
+}
+
+void set_phy_ffe_tuning(struct mvs_info *mvi, int phy_id,
+                               struct ffe_control ffe)
+{
+       u32 tmp;
+
+       /* Don't run this if A0/B0 */
+       if ((mvi->pdev->revision == VANIR_A0_REV)
+               || (mvi->pdev->revision == VANIR_B0_REV))
+               return;
+
+       /* FFE Resistor and Capacitor */
+       /* R10Ch DFE Resolution Control/Squelch and FFE Setting
+        *
+        * FFE_FORCE            [7]
+        * FFE_RES_SEL          [6:4]
+        * FFE_CAP_SEL          [3:0]
+        */
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_FFE_CONTROL);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       tmp &= ~0xFF;
+
+       /* Read from HBA_Info_Page */
+       tmp |= ((0x1 << 7) |
+               (ffe.ffe_rss_sel << 4) |
+               (ffe.ffe_cap_sel << 0));
+
+       mvs_write_port_vsr_data(mvi, phy_id, tmp);
+
+       /* R064h PHY Mode Register 1
+        *
+        * DFE_DIS              18
+        */
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       tmp &= ~0x40001;
+       /* Hard coding */
+       /* No defines in HBA_Info_Page */
+       tmp |= (0 << 18);
+       mvs_write_port_vsr_data(mvi, phy_id, tmp);
+
+       /* R110h DFE F0-F1 Coefficient Control/DFE Update Control
+        *
+        * DFE_UPDATE_EN        [11:6]
+        * DFE_FX_FORCE         [5:0]
+        */
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_DFE_UPDATE_CRTL);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       tmp &= ~0xFFF;
+       /* Hard coding */
+       /* No defines in HBA_Info_Page */
+       tmp |= ((0x3F << 6) | (0x0 << 0));
+       mvs_write_port_vsr_data(mvi, phy_id, tmp);
+
+       /* R1A0h Interface and Digital Reference Clock Control/Reserved_50h
+        *
+        * FFE_TRAIN_EN         3
+        */
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       tmp &= ~0x8;
+       /* Hard coding */
+       /* No defines in HBA_Info_Page */
+       tmp |= (0 << 3);
+       mvs_write_port_vsr_data(mvi, phy_id, tmp);
+}
+
+/*Notice: this function must be called when phy is disabled*/
+void set_phy_rate(struct mvs_info *mvi, int phy_id, u8 rate)
+{
+       union reg_phy_cfg phy_cfg, phy_cfg_tmp;
+       mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2);
+       phy_cfg_tmp.v = mvs_read_port_vsr_data(mvi, phy_id);
+       phy_cfg.v = 0;
+       phy_cfg.u.disable_phy = phy_cfg_tmp.u.disable_phy;
+       phy_cfg.u.sas_support = 1;
+       phy_cfg.u.sata_support = 1;
+       phy_cfg.u.sata_host_mode = 1;
+
+       switch (rate) {
+       case 0x0:
+               /* support 1.5 Gbps */
+               phy_cfg.u.speed_support = 1;
+               phy_cfg.u.snw_3_support = 0;
+               phy_cfg.u.tx_lnk_parity = 1;
+               phy_cfg.u.tx_spt_phs_lnk_rate = 0x30;
+               break;
+       case 0x1:
+
+               /* support 1.5, 3.0 Gbps */
+               phy_cfg.u.speed_support = 3;
+               phy_cfg.u.tx_spt_phs_lnk_rate = 0x3c;
+               phy_cfg.u.tx_lgcl_lnk_rate = 0x08;
+               break;
+       case 0x2:
+       default:
+               /* support 1.5, 3.0, 6.0 Gbps */
+               phy_cfg.u.speed_support = 7;
+               phy_cfg.u.snw_3_support = 1;
+               phy_cfg.u.tx_lnk_parity = 1;
+               phy_cfg.u.tx_spt_phs_lnk_rate = 0x3f;
+               phy_cfg.u.tx_lgcl_lnk_rate = 0x09;
+               break;
+       }
+       mvs_write_port_vsr_data(mvi, phy_id, phy_cfg.v);
+}
+
+static void __devinit
+mvs_94xx_config_reg_from_hba(struct mvs_info *mvi, int phy_id)
+{
+       u32 temp;
+       temp = (u32)(*(u32 *)&mvi->hba_info_param.phy_tuning[phy_id]);
+       if (temp == 0xFFFFFFFFL) {
+               mvi->hba_info_param.phy_tuning[phy_id].trans_emp_amp = 0x6;
+               mvi->hba_info_param.phy_tuning[phy_id].trans_amp = 0x1A;
+               mvi->hba_info_param.phy_tuning[phy_id].trans_amp_adj = 0x3;
+       }
+
+       temp = (u8)(*(u8 *)&mvi->hba_info_param.ffe_ctl[phy_id]);
+       if (temp == 0xFFL) {
+               switch (mvi->pdev->revision) {
+               case VANIR_A0_REV:
+               case VANIR_B0_REV:
+                       mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7;
+                       mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0x7;
+                       break;
+               case VANIR_C0_REV:
+               case VANIR_C1_REV:
+               case VANIR_C2_REV:
+               default:
+                       mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7;
+                       mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0xC;
+                       break;
+               }
+       }
+
+       temp = (u8)(*(u8 *)&mvi->hba_info_param.phy_rate[phy_id]);
+       if (temp == 0xFFL)
+               /*set default phy_rate = 6Gbps*/
+               mvi->hba_info_param.phy_rate[phy_id] = 0x2;
+
+       set_phy_tuning(mvi, phy_id,
+               mvi->hba_info_param.phy_tuning[phy_id]);
+       set_phy_ffe_tuning(mvi, phy_id,
+               mvi->hba_info_param.ffe_ctl[phy_id]);
+       set_phy_rate(mvi, phy_id,
+               mvi->hba_info_param.phy_rate[phy_id]);
+}
+
 static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id)
 {
        void __iomem *regs = mvi->regs;
@@ -61,7 +271,14 @@ static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id)
 static void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
 {
        u32 tmp;
-
+       u32 delay = 5000;
+       if (hard == MVS_PHY_TUNE) {
+               mvs_write_port_cfg_addr(mvi, phy_id, PHYR_SATA_CTL);
+               tmp = mvs_read_port_cfg_data(mvi, phy_id);
+               mvs_write_port_cfg_data(mvi, phy_id, tmp|0x20000000);
+               mvs_write_port_cfg_data(mvi, phy_id, tmp|0x100000);
+               return;
+       }
        tmp = mvs_read_port_irq_stat(mvi, phy_id);
        tmp &= ~PHYEV_RDY_CH;
        mvs_write_port_irq_stat(mvi, phy_id, tmp);
@@ -71,12 +288,15 @@ static void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard)
                mvs_write_phy_ctl(mvi, phy_id, tmp);
                do {
                        tmp = mvs_read_phy_ctl(mvi, phy_id);
-               } while (tmp & PHY_RST_HARD);
+                       udelay(10);
+                       delay--;
+               } while ((tmp & PHY_RST_HARD) && delay);
+               if (!delay)
+                       mv_dprintk("phy hard reset failed.\n");
        } else {
-               mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_STAT);
-               tmp = mvs_read_port_vsr_data(mvi, phy_id);
+               tmp = mvs_read_phy_ctl(mvi, phy_id);
                tmp |= PHY_RST;
-               mvs_write_port_vsr_data(mvi, phy_id, tmp);
+               mvs_write_phy_ctl(mvi, phy_id, tmp);
        }
 }
 
@@ -90,12 +310,25 @@ static void mvs_94xx_phy_disable(struct mvs_info *mvi, u32 phy_id)
 
 static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
 {
-       mvs_write_port_vsr_addr(mvi, phy_id, 0x1B4);
-       mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1);
-       mvs_write_port_vsr_addr(mvi, phy_id, 0x104);
-       mvs_write_port_vsr_data(mvi, phy_id, 0x00018080);
+       u32 tmp;
+       u8 revision = 0;
+
+       revision = mvi->pdev->revision;
+       if (revision == VANIR_A0_REV) {
+               mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA);
+               mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1);
+       }
+       if (revision == VANIR_B0_REV) {
+               mvs_write_port_vsr_addr(mvi, phy_id, CMD_APP_MEM_CTL);
+               mvs_write_port_vsr_data(mvi, phy_id, 0x08001006);
+               mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA);
+               mvs_write_port_vsr_data(mvi, phy_id, 0x0000705f);
+       }
+
        mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2);
-       mvs_write_port_vsr_data(mvi, phy_id, 0x00207fff);
+       tmp = mvs_read_port_vsr_data(mvi, phy_id);
+       tmp |= bit(0);
+       mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff);
 }
 
 static int __devinit mvs_94xx_init(struct mvs_info *mvi)
@@ -103,7 +336,9 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
        void __iomem *regs = mvi->regs;
        int i;
        u32 tmp, cctl;
+       u8 revision;
 
+       revision = mvi->pdev->revision;
        mvs_show_pcie_usage(mvi);
        if (mvi->flags & MVF_FLAG_SOC) {
                tmp = mr32(MVS_PHY_CTL);
@@ -133,6 +368,28 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
                msleep(100);
        }
 
+       /* disable Multiplexing, enable phy implemented */
+       mw32(MVS_PORTS_IMP, 0xFF);
+
+       if (revision == VANIR_A0_REV) {
+               mw32(MVS_PA_VSR_ADDR, CMD_CMWK_OOB_DET);
+               mw32(MVS_PA_VSR_PORT, 0x00018080);
+       }
+       mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE2);
+       if (revision == VANIR_A0_REV || revision == VANIR_B0_REV)
+               /* set 6G/3G/1.5G, multiplexing, without SSC */
+               mw32(MVS_PA_VSR_PORT, 0x0084d4fe);
+       else
+               /* set 6G/3G/1.5G, multiplexing, with and without SSC */
+               mw32(MVS_PA_VSR_PORT, 0x0084fffe);
+
+       if (revision == VANIR_B0_REV) {
+               mw32(MVS_PA_VSR_ADDR, CMD_APP_MEM_CTL);
+               mw32(MVS_PA_VSR_PORT, 0x08001006);
+               mw32(MVS_PA_VSR_ADDR, CMD_HOST_RD_DATA);
+               mw32(MVS_PA_VSR_PORT, 0x0000705f);
+       }
+
        /* reset control */
        mw32(MVS_PCS, 0);               /* MVS_PCS */
        mw32(MVS_STP_REG_SET_0, 0);
@@ -141,17 +398,8 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
        /* init phys */
        mvs_phy_hacks(mvi);
 
-       /* disable Multiplexing, enable phy implemented */
-       mw32(MVS_PORTS_IMP, 0xFF);
-
-
-       mw32(MVS_PA_VSR_ADDR, 0x00000104);
-       mw32(MVS_PA_VSR_PORT, 0x00018080);
-       mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE8);
-       mw32(MVS_PA_VSR_PORT, 0x0084ffff);
-
        /* set LED blink when IO*/
-       mw32(MVS_PA_VSR_ADDR, 0x00000030);
+       mw32(MVS_PA_VSR_ADDR, VSR_PHY_ACT_LED);
        tmp = mr32(MVS_PA_VSR_PORT);
        tmp &= 0xFFFF00FF;
        tmp |= 0x00003300;
@@ -175,12 +423,13 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
                mvs_94xx_phy_disable(mvi, i);
                /* set phy local SAS address */
                mvs_set_sas_addr(mvi, i, CONFIG_ID_FRAME3, CONFIG_ID_FRAME4,
-                                               (mvi->phy[i].dev_sas_addr));
+                                               cpu_to_le64(mvi->phy[i].dev_sas_addr));
 
                mvs_94xx_enable_xmt(mvi, i);
+               mvs_94xx_config_reg_from_hba(mvi, i);
                mvs_94xx_phy_enable(mvi, i);
 
-               mvs_94xx_phy_reset(mvi, i, 1);
+               mvs_94xx_phy_reset(mvi, i, PHY_RST_HARD);
                msleep(500);
                mvs_94xx_detect_porttype(mvi, i);
        }
@@ -211,16 +460,9 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
                mvs_update_phyinfo(mvi, i, 1);
        }
 
-       /* FIXME: update wide port bitmaps */
-
        /* little endian for open address and command table, etc. */
-       /*
-        * it seems that ( from the spec ) turning on big-endian won't
-        * do us any good on big-endian machines, need further confirmation
-        */
        cctl = mr32(MVS_CTL);
        cctl |= CCTL_ENDIAN_CMD;
-       cctl |= CCTL_ENDIAN_DATA;
        cctl &= ~CCTL_ENDIAN_OPEN;
        cctl |= CCTL_ENDIAN_RSP;
        mw32_f(MVS_CTL, cctl);
@@ -228,15 +470,20 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
        /* reset CMD queue */
        tmp = mr32(MVS_PCS);
        tmp |= PCS_CMD_RST;
+       tmp &= ~PCS_SELF_CLEAR;
        mw32(MVS_PCS, tmp);
-       /* interrupt coalescing may cause missing HW interrput in some case,
-        * and the max count is 0x1ff, while our max slot is 0x200,
+       /*
+        * the max count is 0x1ff, while our max slot is 0x200,
         * it will make count 0.
         */
        tmp = 0;
-       mw32(MVS_INT_COAL, tmp);
+       if (MVS_CHIP_SLOT_SZ > 0x1ff)
+               mw32(MVS_INT_COAL, 0x1ff | COAL_EN);
+       else
+               mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ | COAL_EN);
 
-       tmp = 0x100;
+       /* default interrupt coalescing time is 128us */
+       tmp = 0x10000 | interrupt_coalescing;
        mw32(MVS_INT_COAL_TMOUT, tmp);
 
        /* ladies and gentlemen, start your engines */
@@ -249,7 +496,7 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi)
 
        /* enable completion queue interrupt */
        tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP |
-               CINT_DMA_PCIE);
+               CINT_DMA_PCIE | CINT_NON_SPEC_NCQ_ERROR);
        tmp |= CINT_PHY_MASK;
        mw32(MVS_INT_MASK, tmp);
 
@@ -332,13 +579,10 @@ static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat)
        if (((stat & IRQ_SAS_A) && mvi->id == 0) ||
                        ((stat & IRQ_SAS_B) && mvi->id == 1)) {
                mw32_f(MVS_INT_STAT, CINT_DONE);
-       #ifndef MVS_USE_TASKLET
+
                spin_lock(&mvi->lock);
-       #endif
                mvs_int_full(mvi);
-       #ifndef MVS_USE_TASKLET
                spin_unlock(&mvi->lock);
-       #endif
        }
        return IRQ_HANDLED;
 }
@@ -346,10 +590,48 @@ static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat)
 static void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx)
 {
        u32 tmp;
-       mvs_cw32(mvi, 0x300 + (slot_idx >> 3), 1 << (slot_idx % 32));
-       do {
-               tmp = mvs_cr32(mvi, 0x300 + (slot_idx >> 3));
-       } while (tmp & 1 << (slot_idx % 32));
+       tmp = mvs_cr32(mvi, MVS_COMMAND_ACTIVE+(slot_idx >> 3));
+       if (tmp && 1 << (slot_idx % 32)) {
+               mv_printk("command active %08X,  slot [%x].\n", tmp, slot_idx);
+               mvs_cw32(mvi, MVS_COMMAND_ACTIVE + (slot_idx >> 3),
+                       1 << (slot_idx % 32));
+               do {
+                       tmp = mvs_cr32(mvi,
+                               MVS_COMMAND_ACTIVE + (slot_idx >> 3));
+               } while (tmp & 1 << (slot_idx % 32));
+       }
+}
+
+void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all)
+{
+       void __iomem *regs = mvi->regs;
+       u32 tmp;
+
+       if (clear_all) {
+               tmp = mr32(MVS_INT_STAT_SRS_0);
+               if (tmp) {
+                       mv_dprintk("check SRS 0 %08X.\n", tmp);
+                       mw32(MVS_INT_STAT_SRS_0, tmp);
+               }
+               tmp = mr32(MVS_INT_STAT_SRS_1);
+               if (tmp) {
+                       mv_dprintk("check SRS 1 %08X.\n", tmp);
+                       mw32(MVS_INT_STAT_SRS_1, tmp);
+               }
+       } else {
+               if (reg_set > 31)
+                       tmp = mr32(MVS_INT_STAT_SRS_1);
+               else
+                       tmp = mr32(MVS_INT_STAT_SRS_0);
+
+               if (tmp & (1 << (reg_set % 32))) {
+                       mv_dprintk("register set 0x%x was stopped.\n", reg_set);
+                       if (reg_set > 31)
+                               mw32(MVS_INT_STAT_SRS_1, 1 << (reg_set % 32));
+                       else
+                               mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32));
+               }
+       }
 }
 
 static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
@@ -357,37 +639,56 @@ static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type,
 {
        void __iomem *regs = mvi->regs;
        u32 tmp;
+       mvs_94xx_clear_srs_irq(mvi, 0, 1);
 
-       if (type == PORT_TYPE_SATA) {
-               tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs);
-               mw32(MVS_INT_STAT_SRS_0, tmp);
-       }
-       mw32(MVS_INT_STAT, CINT_CI_STOP);
+       tmp = mr32(MVS_INT_STAT);
+       mw32(MVS_INT_STAT, tmp | CINT_CI_STOP);
        tmp = mr32(MVS_PCS) | 0xFF00;
        mw32(MVS_PCS, tmp);
 }
 
+static void mvs_94xx_non_spec_ncq_error(struct mvs_info *mvi)
+{
+       void __iomem *regs = mvi->regs;
+       u32 err_0, err_1;
+       u8 i;
+       struct mvs_device *device;
+
+       err_0 = mr32(MVS_NON_NCQ_ERR_0);
+       err_1 = mr32(MVS_NON_NCQ_ERR_1);
+
+       mv_dprintk("non specific ncq error err_0:%x,err_1:%x.\n",
+                       err_0, err_1);
+       for (i = 0; i < 32; i++) {
+               if (err_0 & bit(i)) {
+                       device = mvs_find_dev_by_reg_set(mvi, i);
+                       if (device)
+                               mvs_release_task(mvi, device->sas_device);
+               }
+               if (err_1 & bit(i)) {
+                       device = mvs_find_dev_by_reg_set(mvi, i+32);
+                       if (device)
+                               mvs_release_task(mvi, device->sas_device);
+               }
+       }
+
+       mw32(MVS_NON_NCQ_ERR_0, err_0);
+       mw32(MVS_NON_NCQ_ERR_1, err_1);
+}
+
 static void mvs_94xx_free_reg_set(struct mvs_info *mvi, u8 *tfs)
 {
        void __iomem *regs = mvi->regs;
-       u32 tmp;
        u8 reg_set = *tfs;
 
        if (*tfs == MVS_ID_NOT_MAPPED)
                return;
 
        mvi->sata_reg_set &= ~bit(reg_set);
-       if (reg_set < 32) {
+       if (reg_set < 32)
                w_reg_set_enable(reg_set, (u32)mvi->sata_reg_set);
-               tmp = mr32(MVS_INT_STAT_SRS_0) & (u32)mvi->sata_reg_set;
-               if (tmp)
-                       mw32(MVS_INT_STAT_SRS_0, tmp);
-       } else {
-               w_reg_set_enable(reg_set, mvi->sata_reg_set);
-               tmp = mr32(MVS_INT_STAT_SRS_1) & mvi->sata_reg_set;
-               if (tmp)
-                       mw32(MVS_INT_STAT_SRS_1, tmp);
-       }
+       else
+               w_reg_set_enable(reg_set, (u32)(mvi->sata_reg_set >> 32));
 
        *tfs = MVS_ID_NOT_MAPPED;
 
@@ -403,7 +704,7 @@ static u8 mvs_94xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs)
                return 0;
 
        i = mv_ffc64(mvi->sata_reg_set);
-       if (i > 32) {
+       if (i >= 32) {
                mvi->sata_reg_set |= bit(i);
                w_reg_set_enable(i, (u32)(mvi->sata_reg_set >> 32));
                *tfs = i;
@@ -422,9 +723,12 @@ static void mvs_94xx_make_prd(struct scatterlist *scatter, int nr, void *prd)
        int i;
        struct scatterlist *sg;
        struct mvs_prd *buf_prd = prd;
+       struct mvs_prd_imt im_len;
+       *(u32 *)&im_len = 0;
        for_each_sg(scatter, sg, nr, i) {
                buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
-               buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg));
+               im_len.len = sg_dma_len(sg);
+               buf_prd->im_len = cpu_to_le32(*(u32 *)&im_len);
                buf_prd++;
        }
 }
@@ -433,7 +737,7 @@ static int mvs_94xx_oob_done(struct mvs_info *mvi, int i)
 {
        u32 phy_st;
        phy_st = mvs_read_phy_ctl(mvi, i);
-       if (phy_st & PHY_READY_MASK)    /* phy ready */
+       if (phy_st & PHY_READY_MASK)
                return 1;
        return 0;
 }
@@ -447,7 +751,7 @@ static void mvs_94xx_get_dev_identify_frame(struct mvs_info *mvi, int port_id,
        for (i = 0; i < 7; i++) {
                mvs_write_port_cfg_addr(mvi, port_id,
                                        CONFIG_ID_FRAME0 + i * 4);
-               id_frame[i] = mvs_read_port_cfg_data(mvi, port_id);
+               id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id));
        }
        memcpy(id, id_frame, 28);
 }
@@ -458,15 +762,13 @@ static void mvs_94xx_get_att_identify_frame(struct mvs_info *mvi, int port_id,
        int i;
        u32 id_frame[7];
 
-       /* mvs_hexdump(28, (u8 *)id_frame, 0); */
        for (i = 0; i < 7; i++) {
                mvs_write_port_cfg_addr(mvi, port_id,
                                        CONFIG_ATT_ID_FRAME0 + i * 4);
-               id_frame[i] = mvs_read_port_cfg_data(mvi, port_id);
+               id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id));
                mv_dprintk("94xx phy %d atta frame %d %x.\n",
                        port_id + mvi->id * mvi->chip->n_phy, i, id_frame[i]);
        }
-       /* mvs_hexdump(28, (u8 *)id_frame, 0); */
        memcpy(id, id_frame, 28);
 }
 
@@ -526,7 +828,18 @@ static void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i,
 void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id,
                        struct sas_phy_linkrates *rates)
 {
-       /* TODO */
+       u32 lrmax = 0;
+       u32 tmp;
+
+       tmp = mvs_read_phy_ctl(mvi, phy_id);
+       lrmax = (rates->maximum_linkrate - SAS_LINK_RATE_1_5_GBPS) << 12;
+
+       if (lrmax) {
+               tmp &= ~(0x3 << 12);
+               tmp |= lrmax;
+       }
+       mvs_write_phy_ctl(mvi, phy_id, tmp);
+       mvs_94xx_phy_reset(mvi, phy_id, PHY_RST_HARD);
 }
 
 static void mvs_94xx_clear_active_cmds(struct mvs_info *mvi)
@@ -603,27 +916,59 @@ int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout)
        return -1;
 }
 
-#ifndef DISABLE_HOTPLUG_DMA_FIX
-void mvs_94xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd)
+void mvs_94xx_fix_dma(struct mvs_info *mvi, u32 phy_mask,
+                               int buf_len, int from, void *prd)
 {
        int i;
        struct mvs_prd *buf_prd = prd;
+       dma_addr_t buf_dma;
+       struct mvs_prd_imt im_len;
+
+       *(u32 *)&im_len = 0;
        buf_prd += from;
-       for (i = 0; i < MAX_SG_ENTRY - from; i++) {
-               buf_prd->addr = cpu_to_le64(buf_dma);
-               buf_prd->im_len.len = cpu_to_le32(buf_len);
-               ++buf_prd;
+
+#define PRD_CHAINED_ENTRY 0x01
+       if ((mvi->pdev->revision == VANIR_A0_REV) ||
+                       (mvi->pdev->revision == VANIR_B0_REV))
+               buf_dma = (phy_mask <= 0x08) ?
+                               mvi->bulk_buffer_dma : mvi->bulk_buffer_dma1;
+       else
+               return;
+
+       for (i = from; i < MAX_SG_ENTRY; i++, ++buf_prd) {
+               if (i == MAX_SG_ENTRY - 1) {
+                       buf_prd->addr = cpu_to_le64(virt_to_phys(buf_prd - 1));
+                       im_len.len = 2;
+                       im_len.misc_ctl = PRD_CHAINED_ENTRY;
+               } else {
+                       buf_prd->addr = cpu_to_le64(buf_dma);
+                       im_len.len = buf_len;
+               }
+               buf_prd->im_len = cpu_to_le32(*(u32 *)&im_len);
        }
 }
-#endif
 
-/*
- * FIXME JEJB: temporary nop clear_srs_irq to make 94xx still work
- * with 64xx fixes
- */
-static void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set,
-                                  u8 clear_all)
+static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time)
 {
+       void __iomem *regs = mvi->regs;
+       u32 tmp = 0;
+       /*
+        * the max count is 0x1ff, while our max slot is 0x200,
+        * it will make count 0.
+        */
+       if (time == 0) {
+               mw32(MVS_INT_COAL, 0);
+               mw32(MVS_INT_COAL_TMOUT, 0x10000);
+       } else {
+               if (MVS_CHIP_SLOT_SZ > 0x1ff)
+                       mw32(MVS_INT_COAL, 0x1ff|COAL_EN);
+               else
+                       mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN);
+
+               tmp = 0x10000 | time;
+               mw32(MVS_INT_COAL_TMOUT, tmp);
+       }
+
 }
 
 const struct mvs_dispatch mvs_94xx_dispatch = {
@@ -648,7 +993,6 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
        mvs_write_port_irq_stat,
        mvs_read_port_irq_mask,
        mvs_write_port_irq_mask,
-       mvs_get_sas_addr,
        mvs_94xx_command_active,
        mvs_94xx_clear_srs_irq,
        mvs_94xx_issue_stop,
@@ -676,8 +1020,8 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
        mvs_94xx_spi_buildcmd,
        mvs_94xx_spi_issuecmd,
        mvs_94xx_spi_waitdataready,
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        mvs_94xx_fix_dma,
-#endif
+       mvs_94xx_tune_interrupt,
+       mvs_94xx_non_spec_ncq_error,
 };
 
index 8835befe2c0e2ea33ea849eae9a81b16736a0a0c..8f7eb4f21140d5955416e4c752b0578cb29adcde 100644 (file)
 
 #define MAX_LINK_RATE          SAS_LINK_RATE_6_0_GBPS
 
+enum VANIR_REVISION_ID {
+       VANIR_A0_REV            = 0xA0,
+       VANIR_B0_REV            = 0x01,
+       VANIR_C0_REV            = 0x02,
+       VANIR_C1_REV            = 0x03,
+       VANIR_C2_REV            = 0xC2,
+};
+
 enum hw_registers {
        MVS_GBL_CTL             = 0x04,  /* global control */
        MVS_GBL_INT_STAT        = 0x00,  /* global irq status */
@@ -101,6 +109,7 @@ enum hw_registers {
        MVS_P4_VSR_DATA         = 0x254, /* phy4 VSR data */
        MVS_PA_VSR_ADDR         = 0x290, /* All port VSR addr */
        MVS_PA_VSR_PORT         = 0x294, /* All port VSR data */
+       MVS_COMMAND_ACTIVE      = 0x300,
 };
 
 enum pci_cfg_registers {
@@ -112,26 +121,29 @@ enum pci_cfg_registers {
 
 /*  SAS/SATA Vendor Specific Port Registers */
 enum sas_sata_vsp_regs {
-       VSR_PHY_STAT            = 0x00 * 4, /* Phy Status */
-       VSR_PHY_MODE1           = 0x01 * 4, /* phy tx */
-       VSR_PHY_MODE2           = 0x02 * 4, /* tx scc */
-       VSR_PHY_MODE3           = 0x03 * 4, /* pll */
-       VSR_PHY_MODE4           = 0x04 * 4, /* VCO */
-       VSR_PHY_MODE5           = 0x05 * 4, /* Rx */
-       VSR_PHY_MODE6           = 0x06 * 4, /* CDR */
-       VSR_PHY_MODE7           = 0x07 * 4, /* Impedance */
-       VSR_PHY_MODE8           = 0x08 * 4, /* Voltage */
-       VSR_PHY_MODE9           = 0x09 * 4, /* Test */
-       VSR_PHY_MODE10          = 0x0A * 4, /* Power */
-       VSR_PHY_MODE11          = 0x0B * 4, /* Phy Mode */
-       VSR_PHY_VS0             = 0x0C * 4, /* Vednor Specific 0 */
-       VSR_PHY_VS1             = 0x0D * 4, /* Vednor Specific 1 */
+       VSR_PHY_STAT            = 0x00 * 4, /* Phy Interrupt Status */
+       VSR_PHY_MODE1           = 0x01 * 4, /* phy Interrupt Enable */
+       VSR_PHY_MODE2           = 0x02 * 4, /* Phy Configuration */
+       VSR_PHY_MODE3           = 0x03 * 4, /* Phy Status */
+       VSR_PHY_MODE4           = 0x04 * 4, /* Phy Counter 0 */
+       VSR_PHY_MODE5           = 0x05 * 4, /* Phy Counter 1 */
+       VSR_PHY_MODE6           = 0x06 * 4, /* Event Counter Control */
+       VSR_PHY_MODE7           = 0x07 * 4, /* Event Counter Select */
+       VSR_PHY_MODE8           = 0x08 * 4, /* Event Counter 0 */
+       VSR_PHY_MODE9           = 0x09 * 4, /* Event Counter 1 */
+       VSR_PHY_MODE10          = 0x0A * 4, /* Event Counter 2 */
+       VSR_PHY_MODE11          = 0x0B * 4, /* Event Counter 3 */
+       VSR_PHY_ACT_LED         = 0x0C * 4, /* Activity LED control */
+
+       VSR_PHY_FFE_CONTROL     = 0x10C,
+       VSR_PHY_DFE_UPDATE_CRTL = 0x110,
+       VSR_REF_CLOCK_CRTL      = 0x1A0,
 };
 
 enum chip_register_bits {
        PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8),
-       PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8),
-       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (12),
+       PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0x7 << 12),
+       PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
        PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
                        (0x3 << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
 };
@@ -169,22 +181,75 @@ enum pci_interrupt_cause {
        IRQ_PCIE_ERR                   = (1 << 31),
 };
 
+union reg_phy_cfg {
+       u32 v;
+       struct {
+               u32 phy_reset:1;
+               u32 sas_support:1;
+               u32 sata_support:1;
+               u32 sata_host_mode:1;
+               /*
+                * bit 2: 6Gbps support
+                * bit 1: 3Gbps support
+                * bit 0: 1.5Gbps support
+                */
+               u32 speed_support:3;
+               u32 snw_3_support:1;
+               u32 tx_lnk_parity:1;
+               /*
+                * bit 5: G1 (1.5Gbps) Without SSC
+                * bit 4: G1 (1.5Gbps) with SSC
+                * bit 3: G2 (3.0Gbps) Without SSC
+                * bit 2: G2 (3.0Gbps) with SSC
+                * bit 1: G3 (6.0Gbps) without SSC
+                * bit 0: G3 (6.0Gbps) with SSC
+                */
+               u32 tx_spt_phs_lnk_rate:6;
+               /* 8h: 1.5Gbps 9h: 3Gbps Ah: 6Gbps */
+               u32 tx_lgcl_lnk_rate:4;
+               u32 tx_ssc_type:1;
+               u32 sata_spin_up_spt:1;
+               u32 sata_spin_up_en:1;
+               u32 bypass_oob:1;
+               u32 disable_phy:1;
+               u32 rsvd:8;
+       } u;
+};
+
 #define MAX_SG_ENTRY           255
 
 struct mvs_prd_imt {
+#ifndef __BIG_ENDIAN
        __le32                  len:22;
        u8                      _r_a:2;
        u8                      misc_ctl:4;
        u8                      inter_sel:4;
+#else
+       u32                     inter_sel:4;
+       u32                     misc_ctl:4;
+       u32                     _r_a:2;
+       u32                     len:22;
+#endif
 };
 
 struct mvs_prd {
        /* 64-bit buffer address */
        __le64                  addr;
        /* 22-bit length */
-       struct mvs_prd_imt      im_len;
+       __le32                  im_len;
 } __attribute__ ((packed));
 
+/*
+ * these registers are accessed through port vendor
+ * specific address/data registers
+ */
+enum sas_sata_phy_regs {
+       GENERATION_1_SETTING            = 0x118,
+       GENERATION_1_2_SETTING          = 0x11C,
+       GENERATION_2_3_SETTING          = 0x120,
+       GENERATION_3_4_SETTING          = 0x124,
+};
+
 #define SPI_CTRL_REG_94XX              0xc800
 #define SPI_ADDR_REG_94XX              0xc804
 #define SPI_WR_DATA_REG_94XX         0xc808
index 1753a6fc42d02851c74449bceffbe6944b59d211..bcc408042cee3b54c8e93ab890d9a0c2e69f2e9a 100644 (file)
@@ -164,7 +164,6 @@ static inline void __devinit mvs_phy_hacks(struct mvs_info *mvi)
 {
        u32 tmp;
 
-       /* workaround for SATA R-ERR, to ignore phy glitch */
        tmp = mvs_cr32(mvi, CMD_PHY_TIMER);
        tmp &= ~(1 << 9);
        tmp |= (1 << 10);
@@ -179,23 +178,10 @@ static inline void __devinit mvs_phy_hacks(struct mvs_info *mvi)
        tmp |= 0x3fff;
        mvs_cw32(mvi, CMD_SAS_CTL0, tmp);
 
-       /* workaround for WDTIMEOUT , set to 550 ms */
        mvs_cw32(mvi, CMD_WD_TIMER, 0x7a0000);
 
        /* not to halt for different port op during wideport link change */
        mvs_cw32(mvi, CMD_APP_ERR_CONFIG, 0xffefbf7d);
-
-       /* workaround for Seagate disk not-found OOB sequence, recv
-        * COMINIT before sending out COMWAKE */
-       tmp = mvs_cr32(mvi, CMD_PHY_MODE_21);
-       tmp &= 0x0000ffff;
-       tmp |= 0x00fa0000;
-       mvs_cw32(mvi, CMD_PHY_MODE_21, tmp);
-
-       tmp = mvs_cr32(mvi, CMD_PHY_TIMER);
-       tmp &= 0x1fffffff;
-       tmp |= (2U << 29);      /* 8 ms retry */
-       mvs_cw32(mvi, CMD_PHY_TIMER, tmp);
 }
 
 static inline void mvs_int_sata(struct mvs_info *mvi)
@@ -223,6 +209,9 @@ static inline void mvs_int_full(struct mvs_info *mvi)
                        mvs_int_port(mvi, i, tmp);
        }
 
+       if (stat & CINT_NON_SPEC_NCQ_ERROR)
+               MVS_CHIP_DISP->non_spec_ncq_error(mvi);
+
        if (stat & CINT_SRS)
                mvs_int_sata(mvi);
 
index bc00c940743c0394812aebcd91df07590e86beac..dec7cadb7485229d9c2612f33faeb9a2303f10c0 100644 (file)
@@ -43,7 +43,6 @@ enum chip_flavors {
 
 /* driver compile-time configuration */
 enum driver_configuration {
-       MVS_SLOTS               = 512,  /* command slots */
        MVS_TX_RING_SZ          = 1024, /* TX ring size (12-bit) */
        MVS_RX_RING_SZ          = 1024, /* RX ring size (12-bit) */
                                        /* software requires power-of-2
@@ -56,8 +55,7 @@ enum driver_configuration {
        MVS_SSP_CMD_SZ          = 64,   /* SSP command table buffer size */
        MVS_ATA_CMD_SZ          = 96,   /* SATA command table buffer size */
        MVS_OAF_SZ              = 64,   /* Open address frame buffer size */
-       MVS_QUEUE_SIZE  = 32,   /* Support Queue depth */
-       MVS_CAN_QUEUE           = MVS_SLOTS - 2,        /* SCSI Queue depth */
+       MVS_QUEUE_SIZE          = 64,   /* Support Queue depth */
        MVS_SOC_CAN_QUEUE       = MVS_SOC_SLOTS - 2,
 };
 
@@ -144,6 +142,7 @@ enum hw_register_bits {
        CINT_DMA_PCIE           = (1U << 27),   /* DMA to PCIE timeout */
        CINT_MEM                = (1U << 26),   /* int mem parity err */
        CINT_I2C_SLAVE          = (1U << 25),   /* slave I2C event */
+       CINT_NON_SPEC_NCQ_ERROR = (1U << 25),   /* Non specific NCQ error */
        CINT_SRS                = (1U << 3),    /* SRS event */
        CINT_CI_STOP            = (1U << 1),    /* cmd issue stopped */
        CINT_DONE               = (1U << 0),    /* cmd completion */
@@ -161,7 +160,7 @@ enum hw_register_bits {
        TXQ_CMD_SSP             = 1,            /* SSP protocol */
        TXQ_CMD_SMP             = 2,            /* SMP protocol */
        TXQ_CMD_STP             = 3,            /* STP/SATA protocol */
-       TXQ_CMD_SSP_FREE_LIST   = 4,            /* add to SSP targ free list */
+       TXQ_CMD_SSP_FREE_LIST   = 4,            /* add to SSP target free list */
        TXQ_CMD_SLOT_RESET      = 7,            /* reset command slot */
        TXQ_MODE_I              = (1U << 28),   /* mode: 0=target,1=initiator */
        TXQ_MODE_TARGET         = 0,
@@ -391,15 +390,15 @@ enum sas_cmd_port_registers {
 };
 
 enum mvs_info_flags {
-       MVF_MSI         = (1U << 0),    /* MSI is enabled */
        MVF_PHY_PWR_FIX = (1U << 1),    /* bug workaround */
        MVF_FLAG_SOC            = (1U << 2),    /* SoC integrated controllers */
 };
 
 enum mvs_event_flags {
-       PHY_PLUG_EVENT  = (3U),
+       PHY_PLUG_EVENT          = (3U),
        PHY_PLUG_IN             = (1U << 0),    /* phy plug in */
        PHY_PLUG_OUT            = (1U << 1),    /* phy plug out */
+       EXP_BRCT_CHG            = (1U << 2),    /* broadcast change */
 };
 
 enum mvs_port_type {
index 90b636611cde1c3a4f9ee4c2ce3aef9475847d57..4e9af66fd1d3ecf2ac6e996f0a9c31c1e55de379 100644 (file)
@@ -34,22 +34,25 @@ MODULE_PARM_DESC(collector, "\n"
        "\tThe mvsas SAS LLDD supports both modes.\n"
        "\tDefault: 1 (Direct Mode).\n");
 
+int interrupt_coalescing = 0x80;
+
 static struct scsi_transport_template *mvs_stt;
 struct kmem_cache *mvs_task_list_cache;
 static const struct mvs_chip_info mvs_chips[] = {
-       [chip_6320] =   { 1, 2, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
-       [chip_6440] =   { 1, 4, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
-       [chip_6485] =   { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, },
-       [chip_9180] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
-       [chip_9480] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
-       [chip_9445] =   { 1, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, },
-       [chip_9485] =   { 2, 4, 0x800, 17, 64, 11, &mvs_94xx_dispatch, },
-       [chip_1300] =   { 1, 4, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
-       [chip_1320] =   { 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
+       [chip_6320] =   { 1, 2, 0x400, 17, 16, 6,  9, &mvs_64xx_dispatch, },
+       [chip_6440] =   { 1, 4, 0x400, 17, 16, 6,  9, &mvs_64xx_dispatch, },
+       [chip_6485] =   { 1, 8, 0x800, 33, 32, 6, 10, &mvs_64xx_dispatch, },
+       [chip_9180] =   { 2, 4, 0x800, 17, 64, 8,  9, &mvs_94xx_dispatch, },
+       [chip_9480] =   { 2, 4, 0x800, 17, 64, 8,  9, &mvs_94xx_dispatch, },
+       [chip_9445] =   { 1, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, },
+       [chip_9485] =   { 2, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, },
+       [chip_1300] =   { 1, 4, 0x400, 17, 16, 6,  9, &mvs_64xx_dispatch, },
+       [chip_1320] =   { 2, 4, 0x800, 17, 64, 8,  9, &mvs_94xx_dispatch, },
 };
 
+struct device_attribute *mvst_host_attrs[];
+
 #define SOC_SAS_NUM 2
-#define SG_MX 64
 
 static struct scsi_host_template mvs_sht = {
        .module                 = THIS_MODULE,
@@ -66,7 +69,7 @@ static struct scsi_host_template mvs_sht = {
        .can_queue              = 1,
        .cmd_per_lun            = 1,
        .this_id                = -1,
-       .sg_tablesize           = SG_MX,
+       .sg_tablesize           = SG_ALL,
        .max_sectors            = SCSI_DEFAULT_MAX_SECTORS,
        .use_clustering         = ENABLE_CLUSTERING,
        .eh_device_reset_handler = sas_eh_device_reset_handler,
@@ -74,6 +77,7 @@ static struct scsi_host_template mvs_sht = {
        .slave_alloc            = mvs_slave_alloc,
        .target_destroy         = sas_target_destroy,
        .ioctl                  = sas_ioctl,
+       .shost_attrs            = mvst_host_attrs,
 };
 
 static struct sas_domain_function_template mvs_transport_ops = {
@@ -100,6 +104,7 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
        struct asd_sas_phy *sas_phy = &phy->sas_phy;
 
        phy->mvi = mvi;
+       phy->port = NULL;
        init_timer(&phy->timer);
        sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0;
        sas_phy->class = SAS;
@@ -128,7 +133,7 @@ static void mvs_free(struct mvs_info *mvi)
        if (mvi->flags & MVF_FLAG_SOC)
                slot_nr = MVS_SOC_SLOTS;
        else
-               slot_nr = MVS_SLOTS;
+               slot_nr = MVS_CHIP_SLOT_SZ;
 
        if (mvi->dma_pool)
                pci_pool_destroy(mvi->dma_pool);
@@ -148,25 +153,26 @@ static void mvs_free(struct mvs_info *mvi)
                dma_free_coherent(mvi->dev,
                                  sizeof(*mvi->slot) * slot_nr,
                                  mvi->slot, mvi->slot_dma);
-#ifndef DISABLE_HOTPLUG_DMA_FIX
+
        if (mvi->bulk_buffer)
                dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE,
                                  mvi->bulk_buffer, mvi->bulk_buffer_dma);
-#endif
+       if (mvi->bulk_buffer1)
+               dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE,
+                                 mvi->bulk_buffer1, mvi->bulk_buffer_dma1);
 
        MVS_CHIP_DISP->chip_iounmap(mvi);
        if (mvi->shost)
                scsi_host_put(mvi->shost);
        list_for_each_entry(mwq, &mvi->wq_list, entry)
                cancel_delayed_work(&mwq->work_q);
+       kfree(mvi->tags);
        kfree(mvi);
 }
 
-#ifdef MVS_USE_TASKLET
-struct tasklet_struct  mv_tasklet;
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
 static void mvs_tasklet(unsigned long opaque)
 {
-       unsigned long flags;
        u32 stat;
        u16 core_nr, i = 0;
 
@@ -179,35 +185,49 @@ static void mvs_tasklet(unsigned long opaque)
        if (unlikely(!mvi))
                BUG_ON(1);
 
+       stat = MVS_CHIP_DISP->isr_status(mvi, mvi->pdev->irq);
+       if (!stat)
+               goto out;
+
        for (i = 0; i < core_nr; i++) {
                mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
-               stat = MVS_CHIP_DISP->isr_status(mvi, mvi->irq);
-               if (stat)
-                       MVS_CHIP_DISP->isr(mvi, mvi->irq, stat);
+               MVS_CHIP_DISP->isr(mvi, mvi->pdev->irq, stat);
        }
+out:
+       MVS_CHIP_DISP->interrupt_enable(mvi);
 
 }
 #endif
 
 static irqreturn_t mvs_interrupt(int irq, void *opaque)
 {
-       u32 core_nr, i = 0;
+       u32 core_nr;
        u32 stat;
        struct mvs_info *mvi;
        struct sas_ha_struct *sha = opaque;
+#ifndef CONFIG_SCSI_MVSAS_TASKLET
+       u32 i;
+#endif
 
        core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
        mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
 
        if (unlikely(!mvi))
                return IRQ_NONE;
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
+       MVS_CHIP_DISP->interrupt_disable(mvi);
+#endif
 
        stat = MVS_CHIP_DISP->isr_status(mvi, irq);
-       if (!stat)
+       if (!stat) {
+       #ifdef CONFIG_SCSI_MVSAS_TASKLET
+               MVS_CHIP_DISP->interrupt_enable(mvi);
+       #endif
                return IRQ_NONE;
+       }
 
-#ifdef MVS_USE_TASKLET
-       tasklet_schedule(&mv_tasklet);
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
+       tasklet_schedule(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet);
 #else
        for (i = 0; i < core_nr; i++) {
                mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
@@ -225,7 +245,7 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
        if (mvi->flags & MVF_FLAG_SOC)
                slot_nr = MVS_SOC_SLOTS;
        else
-               slot_nr = MVS_SLOTS;
+               slot_nr = MVS_CHIP_SLOT_SZ;
 
        spin_lock_init(&mvi->lock);
        for (i = 0; i < mvi->chip->n_phy; i++) {
@@ -273,13 +293,18 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
                goto err_out;
        memset(mvi->slot, 0, sizeof(*mvi->slot) * slot_nr);
 
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        mvi->bulk_buffer = dma_alloc_coherent(mvi->dev,
                                       TRASH_BUCKET_SIZE,
                                       &mvi->bulk_buffer_dma, GFP_KERNEL);
        if (!mvi->bulk_buffer)
                goto err_out;
-#endif
+
+       mvi->bulk_buffer1 = dma_alloc_coherent(mvi->dev,
+                                      TRASH_BUCKET_SIZE,
+                                      &mvi->bulk_buffer_dma1, GFP_KERNEL);
+       if (!mvi->bulk_buffer1)
+               goto err_out;
+
        sprintf(pool_name, "%s%d", "mvs_dma_pool", mvi->id);
        mvi->dma_pool = pci_pool_create(pool_name, mvi->pdev, MVS_SLOT_BUF_SZ, 16, 0);
        if (!mvi->dma_pool) {
@@ -354,11 +379,12 @@ static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev,
                                const struct pci_device_id *ent,
                                struct Scsi_Host *shost, unsigned int id)
 {
-       struct mvs_info *mvi;
+       struct mvs_info *mvi = NULL;
        struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
 
-       mvi = kzalloc(sizeof(*mvi) + MVS_SLOTS * sizeof(struct mvs_slot_info),
-                       GFP_KERNEL);
+       mvi = kzalloc(sizeof(*mvi) +
+               (1L << mvs_chips[ent->driver_data].slot_width) *
+               sizeof(struct mvs_slot_info), GFP_KERNEL);
        if (!mvi)
                return NULL;
 
@@ -367,7 +393,6 @@ static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev,
        mvi->chip_id = ent->driver_data;
        mvi->chip = &mvs_chips[mvi->chip_id];
        INIT_LIST_HEAD(&mvi->wq_list);
-       mvi->irq = pdev->irq;
 
        ((struct mvs_prv_info *)sha->lldd_ha)->mvi[id] = mvi;
        ((struct mvs_prv_info *)sha->lldd_ha)->n_phy = mvi->chip->n_phy;
@@ -375,9 +400,10 @@ static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev,
        mvi->id = id;
        mvi->sas = sha;
        mvi->shost = shost;
-#ifdef MVS_USE_TASKLET
-       tasklet_init(&mv_tasklet, mvs_tasklet, (unsigned long)sha);
-#endif
+
+       mvi->tags = kzalloc(MVS_CHIP_SLOT_SZ>>3, GFP_KERNEL);
+       if (!mvi->tags)
+               goto err_out;
 
        if (MVS_CHIP_DISP->chip_ioremap(mvi))
                goto err_out;
@@ -388,7 +414,6 @@ err_out:
        return NULL;
 }
 
-/* move to PCI layer or libata core? */
 static int pci_go_64(struct pci_dev *pdev)
 {
        int rc;
@@ -450,7 +475,7 @@ static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost,
        ((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr;
 
        shost->transportt = mvs_stt;
-       shost->max_id = 128;
+       shost->max_id = MVS_MAX_DEVICES;
        shost->max_lun = ~0;
        shost->max_channel = 1;
        shost->max_cmd_len = 16;
@@ -493,11 +518,12 @@ static void  __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost,
        if (mvi->flags & MVF_FLAG_SOC)
                can_queue = MVS_SOC_CAN_QUEUE;
        else
-               can_queue = MVS_CAN_QUEUE;
+               can_queue = MVS_CHIP_SLOT_SZ;
 
        sha->lldd_queue_size = can_queue;
+       shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG);
        shost->can_queue = can_queue;
-       mvi->shost->cmd_per_lun = MVS_SLOTS/sha->num_phys;
+       mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE;
        sha->core.shost = mvi->shost;
 }
 
@@ -518,6 +544,7 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
 {
        unsigned int rc, nhost = 0;
        struct mvs_info *mvi;
+       struct mvs_prv_info *mpi;
        irq_handler_t irq_handler = mvs_interrupt;
        struct Scsi_Host *shost = NULL;
        const struct mvs_chip_info *chip;
@@ -569,6 +596,9 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
                        goto err_out_regions;
                }
 
+               memset(&mvi->hba_info_param, 0xFF,
+                       sizeof(struct hba_info_page));
+
                mvs_init_sas_add(mvi);
 
                mvi->instance = nhost;
@@ -579,8 +609,9 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
                }
                nhost++;
        } while (nhost < chip->n_host);
-#ifdef MVS_USE_TASKLET
-       tasklet_init(&mv_tasklet, mvs_tasklet,
+       mpi = (struct mvs_prv_info *)(SHOST_TO_SAS_HA(shost)->lldd_ha);
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
+       tasklet_init(&(mpi->mv_tasklet), mvs_tasklet,
                     (unsigned long)SHOST_TO_SAS_HA(shost));
 #endif
 
@@ -625,8 +656,8 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
        core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
        mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
 
-#ifdef MVS_USE_TASKLET
-       tasklet_kill(&mv_tasklet);
+#ifdef CONFIG_SCSI_MVSAS_TASKLET
+       tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet);
 #endif
 
        pci_set_drvdata(pdev, NULL);
@@ -635,7 +666,7 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
        scsi_remove_host(mvi->shost);
 
        MVS_CHIP_DISP->interrupt_disable(mvi);
-       free_irq(mvi->irq, sha);
+       free_irq(mvi->pdev->irq, sha);
        for (i = 0; i < core_nr; i++) {
                mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
                mvs_free(mvi);
@@ -703,6 +734,70 @@ static struct pci_driver mvs_pci_driver = {
        .remove         = __devexit_p(mvs_pci_remove),
 };
 
+static ssize_t
+mvs_show_driver_version(struct device *cdev,
+               struct device_attribute *attr,  char *buffer)
+{
+       return snprintf(buffer, PAGE_SIZE, "%s\n", DRV_VERSION);
+}
+
+static DEVICE_ATTR(driver_version,
+                        S_IRUGO,
+                        mvs_show_driver_version,
+                        NULL);
+
+static ssize_t
+mvs_store_interrupt_coalescing(struct device *cdev,
+                       struct device_attribute *attr,
+                       const char *buffer, size_t size)
+{
+       int val = 0;
+       struct mvs_info *mvi = NULL;
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       u8 i, core_nr;
+       if (buffer == NULL)
+               return size;
+
+       if (sscanf(buffer, "%d", &val) != 1)
+               return -EINVAL;
+
+       if (val >= 0x10000) {
+               mv_dprintk("interrupt coalescing timer %d us is"
+                       "too long\n", val);
+               return strlen(buffer);
+       }
+
+       interrupt_coalescing = val;
+
+       core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
+       mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0];
+
+       if (unlikely(!mvi))
+               return -EINVAL;
+
+       for (i = 0; i < core_nr; i++) {
+               mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
+               if (MVS_CHIP_DISP->tune_interrupt)
+                       MVS_CHIP_DISP->tune_interrupt(mvi,
+                               interrupt_coalescing);
+       }
+       mv_dprintk("set interrupt coalescing time to %d us\n",
+               interrupt_coalescing);
+       return strlen(buffer);
+}
+
+static ssize_t mvs_show_interrupt_coalescing(struct device *cdev,
+                       struct device_attribute *attr, char *buffer)
+{
+       return snprintf(buffer, PAGE_SIZE, "%d\n", interrupt_coalescing);
+}
+
+static DEVICE_ATTR(interrupt_coalescing,
+                        S_IRUGO|S_IWUSR,
+                        mvs_show_interrupt_coalescing,
+                        mvs_store_interrupt_coalescing);
+
 /* task handler */
 struct task_struct *mvs_th;
 static int __init mvs_init(void)
@@ -739,6 +834,12 @@ static void __exit mvs_exit(void)
        kmem_cache_destroy(mvs_task_list_cache);
 }
 
+struct device_attribute *mvst_host_attrs[] = {
+       &dev_attr_driver_version,
+       &dev_attr_interrupt_coalescing,
+       NULL,
+};
+
 module_init(mvs_init);
 module_exit(mvs_exit);
 
index 0ef27425c4471bdeeccdae6f62691c8e8a1887e9..4958fefff36559b79de06fa4a06fa67d1bc8d237 100644 (file)
@@ -38,7 +38,7 @@ static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag)
 
 void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
 {
-       void *bitmap = &mvi->tags;
+       void *bitmap = mvi->tags;
        clear_bit(tag, bitmap);
 }
 
@@ -49,14 +49,14 @@ void mvs_tag_free(struct mvs_info *mvi, u32 tag)
 
 void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
 {
-       void *bitmap = &mvi->tags;
+       void *bitmap = mvi->tags;
        set_bit(tag, bitmap);
 }
 
 inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
 {
        unsigned int index, tag;
-       void *bitmap = &mvi->tags;
+       void *bitmap = mvi->tags;
 
        index = find_first_zero_bit(bitmap, mvi->tags_num);
        tag = index;
@@ -74,126 +74,6 @@ void mvs_tag_init(struct mvs_info *mvi)
                mvs_tag_clear(mvi, i);
 }
 
-void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
-{
-       u32 i;
-       u32 run;
-       u32 offset;
-
-       offset = 0;
-       while (size) {
-               printk(KERN_DEBUG"%08X : ", baseaddr + offset);
-               if (size >= 16)
-                       run = 16;
-               else
-                       run = size;
-               size -= run;
-               for (i = 0; i < 16; i++) {
-                       if (i < run)
-                               printk(KERN_DEBUG"%02X ", (u32)data[i]);
-                       else
-                               printk(KERN_DEBUG"   ");
-               }
-               printk(KERN_DEBUG": ");
-               for (i = 0; i < run; i++)
-                       printk(KERN_DEBUG"%c",
-                               isalnum(data[i]) ? data[i] : '.');
-               printk(KERN_DEBUG"\n");
-               data = &data[16];
-               offset += run;
-       }
-       printk(KERN_DEBUG"\n");
-}
-
-#if (_MV_DUMP > 1)
-static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
-                                  enum sas_protocol proto)
-{
-       u32 offset;
-       struct mvs_slot_info *slot = &mvi->slot_info[tag];
-
-       offset = slot->cmd_size + MVS_OAF_SZ +
-           MVS_CHIP_DISP->prd_size() * slot->n_elem;
-       dev_printk(KERN_DEBUG, mvi->dev, "+---->Status buffer[%d] :\n",
-                       tag);
-       mvs_hexdump(32, (u8 *) slot->response,
-                   (u32) slot->buf_dma + offset);
-}
-#endif
-
-static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
-                               enum sas_protocol proto)
-{
-#if (_MV_DUMP > 1)
-       u32 sz, w_ptr;
-       u64 addr;
-       struct mvs_slot_info *slot = &mvi->slot_info[tag];
-
-       /*Delivery Queue */
-       sz = MVS_CHIP_SLOT_SZ;
-       w_ptr = slot->tx;
-       addr = mvi->tx_dma;
-       dev_printk(KERN_DEBUG, mvi->dev,
-               "Delivery Queue Size=%04d , WRT_PTR=%04X\n", sz, w_ptr);
-       dev_printk(KERN_DEBUG, mvi->dev,
-               "Delivery Queue Base Address=0x%llX (PA)"
-               "(tx_dma=0x%llX), Entry=%04d\n",
-               addr, (unsigned long long)mvi->tx_dma, w_ptr);
-       mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
-                       (u32) mvi->tx_dma + sizeof(u32) * w_ptr);
-       /*Command List */
-       addr = mvi->slot_dma;
-       dev_printk(KERN_DEBUG, mvi->dev,
-               "Command List Base Address=0x%llX (PA)"
-               "(slot_dma=0x%llX), Header=%03d\n",
-               addr, (unsigned long long)slot->buf_dma, tag);
-       dev_printk(KERN_DEBUG, mvi->dev, "Command Header[%03d]:\n", tag);
-       /*mvs_cmd_hdr */
-       mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
-               (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
-       /*1.command table area */
-       dev_printk(KERN_DEBUG, mvi->dev, "+---->Command Table :\n");
-       mvs_hexdump(slot->cmd_size, (u8 *) slot->buf, (u32) slot->buf_dma);
-       /*2.open address frame area */
-       dev_printk(KERN_DEBUG, mvi->dev, "+---->Open Address Frame :\n");
-       mvs_hexdump(MVS_OAF_SZ, (u8 *) slot->buf + slot->cmd_size,
-                               (u32) slot->buf_dma + slot->cmd_size);
-       /*3.status buffer */
-       mvs_hba_sb_dump(mvi, tag, proto);
-       /*4.PRD table */
-       dev_printk(KERN_DEBUG, mvi->dev, "+---->PRD table :\n");
-       mvs_hexdump(MVS_CHIP_DISP->prd_size() * slot->n_elem,
-               (u8 *) slot->buf + slot->cmd_size + MVS_OAF_SZ,
-               (u32) slot->buf_dma + slot->cmd_size + MVS_OAF_SZ);
-#endif
-}
-
-static void mvs_hba_cq_dump(struct mvs_info *mvi)
-{
-#if (_MV_DUMP > 2)
-       u64 addr;
-       void __iomem *regs = mvi->regs;
-       u32 entry = mvi->rx_cons + 1;
-       u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
-
-       /*Completion Queue */
-       addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
-       dev_printk(KERN_DEBUG, mvi->dev, "Completion Task = 0x%p\n",
-                  mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
-       dev_printk(KERN_DEBUG, mvi->dev,
-               "Completion List Base Address=0x%llX (PA), "
-               "CQ_Entry=%04d, CQ_WP=0x%08X\n",
-               addr, entry - 1, mvi->rx[0]);
-       mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
-                   mvi->rx_dma + sizeof(u32) * entry);
-#endif
-}
-
-void mvs_get_sas_addr(void *buf, u32 buflen)
-{
-       /*memcpy(buf, "\x50\x05\x04\x30\x11\xab\x64\x40", 8);*/
-}
-
 struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
 {
        unsigned long i = 0, j = 0, hi = 0;
@@ -222,7 +102,6 @@ struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
 
 }
 
-/* FIXME */
 int mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
 {
        unsigned long i = 0, j = 0, n = 0, num = 0;
@@ -253,6 +132,20 @@ int mvs_find_dev_phyno(struct domain_device *dev, int *phyno)
        return num;
 }
 
+struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi,
+                                               u8 reg_set)
+{
+       u32 dev_no;
+       for (dev_no = 0; dev_no < MVS_MAX_DEVICES; dev_no++) {
+               if (mvi->devices[dev_no].taskfileset == MVS_ID_NOT_MAPPED)
+                       continue;
+
+               if (mvi->devices[dev_no].taskfileset == reg_set)
+                       return &mvi->devices[dev_no];
+       }
+       return NULL;
+}
+
 static inline void mvs_free_reg_set(struct mvs_info *mvi,
                                struct mvs_device *dev)
 {
@@ -283,7 +176,6 @@ void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard)
        }
 }
 
-/* FIXME: locking? */
 int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
                        void *funcdata)
 {
@@ -309,12 +201,12 @@ int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
                tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id);
                if (tmp & PHY_RST_HARD)
                        break;
-               MVS_CHIP_DISP->phy_reset(mvi, phy_id, 1);
+               MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_HARD_RESET);
                break;
 
        case PHY_FUNC_LINK_RESET:
                MVS_CHIP_DISP->phy_enable(mvi, phy_id);
-               MVS_CHIP_DISP->phy_reset(mvi, phy_id, 0);
+               MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_SOFT_RESET);
                break;
 
        case PHY_FUNC_DISABLE:
@@ -406,14 +298,10 @@ int mvs_slave_configure(struct scsi_device *sdev)
 
        if (ret)
                return ret;
-       if (dev_is_sata(dev)) {
-               /* may set PIO mode */
-       #if MV_DISABLE_NCQ
-               struct ata_port *ap = dev->sata_dev.ap;
-               struct ata_device *adev = ap->link.device;
-               adev->flags |= ATA_DFLAG_NCQ_OFF;
-               scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1);
-       #endif
+       if (!dev_is_sata(dev)) {
+               sas_change_queue_depth(sdev,
+                       MVS_QUEUE_SIZE,
+                       SCSI_QDEPTH_DEFAULT);
        }
        return 0;
 }
@@ -424,6 +312,7 @@ void mvs_scan_start(struct Scsi_Host *shost)
        unsigned short core_nr;
        struct mvs_info *mvi;
        struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       struct mvs_prv_info *mvs_prv = sha->lldd_ha;
 
        core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host;
 
@@ -432,15 +321,17 @@ void mvs_scan_start(struct Scsi_Host *shost)
                for (i = 0; i < mvi->chip->n_phy; ++i)
                        mvs_bytes_dmaed(mvi, i);
        }
+       mvs_prv->scan_finished = 1;
 }
 
 int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
-       /* give the phy enabling interrupt event time to come in (1s
-        * is empirically about all it takes) */
-       if (time < HZ)
+       struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
+       struct mvs_prv_info *mvs_prv = sha->lldd_ha;
+
+       if (mvs_prv->scan_finished == 0)
                return 0;
-       /* Wait for discovery to finish */
+
        scsi_flush_work(shost);
        return 1;
 }
@@ -461,10 +352,7 @@ static int mvs_task_prep_smp(struct mvs_info *mvi,
        void *buf_prd;
        struct mvs_slot_info *slot = &mvi->slot_info[tag];
        u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-#if _MV_DUMP
-       u8 *buf_cmd;
-       void *from;
-#endif
+
        /*
         * DMA-map SMP request, response buffers
         */
@@ -496,15 +384,7 @@ static int mvs_task_prep_smp(struct mvs_info *mvi,
        buf_tmp = slot->buf;
        buf_tmp_dma = slot->buf_dma;
 
-#if _MV_DUMP
-       buf_cmd = buf_tmp;
-       hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
-       buf_tmp += req_len;
-       buf_tmp_dma += req_len;
-       slot->cmd_size = req_len;
-#else
        hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req));
-#endif
 
        /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
        buf_oaf = buf_tmp;
@@ -553,12 +433,6 @@ static int mvs_task_prep_smp(struct mvs_info *mvi,
        /* fill in PRD (scatter/gather) table, if any */
        MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
 
-#if _MV_DUMP
-       /* copy cmd table */
-       from = kmap_atomic(sg_page(sg_req), KM_IRQ0);
-       memcpy(buf_cmd, from + sg_req->offset, req_len);
-       kunmap_atomic(from, KM_IRQ0);
-#endif
        return 0;
 
 err_out_2:
@@ -616,14 +490,11 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
                (mvi_dev->taskfileset << TXQ_SRS_SHIFT);
        mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q);
 
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        if (task->data_dir == DMA_FROM_DEVICE)
                flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT);
        else
                flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-#else
-       flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
-#endif
+
        if (task->ata_task.use_ncq)
                flags |= MCH_FPDMA;
        if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
@@ -631,11 +502,8 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
                        flags |= MCH_ATAPI;
        }
 
-       /* FIXME: fill in port multiplier number */
-
        hdr->flags = cpu_to_le32(flags);
 
-       /* FIXME: the low order order 5 bits for the TAG if enable NCQ */
        if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag))
                task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
        else
@@ -657,9 +525,6 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
 
        buf_tmp += MVS_ATA_CMD_SZ;
        buf_tmp_dma += MVS_ATA_CMD_SZ;
-#if _MV_DUMP
-       slot->cmd_size = MVS_ATA_CMD_SZ;
-#endif
 
        /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
        /* used for STP.  unused for SATA? */
@@ -682,9 +547,6 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
        buf_tmp_dma += i;
 
        /* region 4: status buffer (larger the PRD, smaller this buf) ****** */
-       /* FIXME: probably unused, for SATA.  kept here just in case
-        * we get a STP/SATA error information record
-        */
        slot->response = buf_tmp;
        hdr->status_buf = cpu_to_le64(buf_tmp_dma);
        if (mvi->flags & MVF_FLAG_SOC)
@@ -715,11 +577,11 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
 
        /* fill in PRD (scatter/gather) table, if any */
        MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd);
-#ifndef DISABLE_HOTPLUG_DMA_FIX
+
        if (task->data_dir == DMA_FROM_DEVICE)
-               MVS_CHIP_DISP->dma_fix(mvi->bulk_buffer_dma,
+               MVS_CHIP_DISP->dma_fix(mvi, sas_port->phy_mask,
                                TRASH_BUCKET_SIZE, tei->n_elem, buf_prd);
-#endif
+
        return 0;
 }
 
@@ -761,6 +623,9 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
        }
        if (is_tmf)
                flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT);
+       else
+               flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT);
+
        hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT));
        hdr->tags = cpu_to_le32(tag);
        hdr->data_len = cpu_to_le32(task->total_xfer_len);
@@ -777,9 +642,6 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
 
        buf_tmp += MVS_SSP_CMD_SZ;
        buf_tmp_dma += MVS_SSP_CMD_SZ;
-#if _MV_DUMP
-       slot->cmd_size = MVS_SSP_CMD_SZ;
-#endif
 
        /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
        buf_oaf = buf_tmp;
@@ -986,7 +848,6 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf
        task->task_state_flags |= SAS_TASK_AT_INITIATOR;
        spin_unlock(&task->task_state_lock);
 
-       mvs_hba_memory_dump(mvi, tag, task->task_proto);
        mvi_dev->running_req++;
        ++(*pass);
        mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
@@ -1189,9 +1050,9 @@ static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
        mvs_slot_free(mvi, slot_idx);
 }
 
-static void mvs_update_wideport(struct mvs_info *mvi, int i)
+static void mvs_update_wideport(struct mvs_info *mvi, int phy_no)
 {
-       struct mvs_phy *phy = &mvi->phy[i];
+       struct mvs_phy *phy = &mvi->phy[phy_no];
        struct mvs_port *port = phy->port;
        int j, no;
 
@@ -1246,18 +1107,17 @@ static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
                return NULL;
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
-       s[3] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[3] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
-       s[2] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[2] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
-       s[1] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[1] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
        MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
-       s[0] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+       s[0] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i));
 
-       /* Workaround: take some ATAPI devices for ATA */
        if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01))
                s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10);
 
@@ -1269,6 +1129,13 @@ static u32 mvs_is_sig_fis_received(u32 irq_status)
        return irq_status & PHYEV_SIG_FIS;
 }
 
+static void mvs_sig_remove_timer(struct mvs_phy *phy)
+{
+       if (phy->timer.function)
+               del_timer(&phy->timer);
+       phy->timer.function = NULL;
+}
+
 void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
 {
        struct mvs_phy *phy = &mvi->phy[i];
@@ -1291,6 +1158,7 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
                if (phy->phy_type & PORT_TYPE_SATA) {
                        phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
                        if (mvs_is_sig_fis_received(phy->irq_status)) {
+                               mvs_sig_remove_timer(phy);
                                phy->phy_attached = 1;
                                phy->att_dev_sas_addr =
                                        i + mvi->id * mvi->chip->n_phy;
@@ -1308,7 +1176,6 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
                                                tmp | PHYEV_SIG_FIS);
                                phy->phy_attached = 0;
                                phy->phy_type &= ~PORT_TYPE_SATA;
-                               MVS_CHIP_DISP->phy_reset(mvi, i, 0);
                                goto out_done;
                        }
                }       else if (phy->phy_type & PORT_TYPE_SAS
@@ -1334,9 +1201,9 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st)
                if (MVS_CHIP_DISP->phy_work_around)
                        MVS_CHIP_DISP->phy_work_around(mvi, i);
        }
-       mv_dprintk("port %d attach dev info is %x\n",
+       mv_dprintk("phy %d attach dev info is %x\n",
                i + mvi->id * mvi->chip->n_phy, phy->att_dev_info);
-       mv_dprintk("port %d attach sas addr is %llx\n",
+       mv_dprintk("phy %d attach sas addr is %llx\n",
                i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr);
 out_done:
        if (get_st)
@@ -1361,10 +1228,10 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
        }
        hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy;
        mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi];
-       if (sas_port->id >= mvi->chip->n_phy)
-               port = &mvi->port[sas_port->id - mvi->chip->n_phy];
+       if (i >= mvi->chip->n_phy)
+               port = &mvi->port[i - mvi->chip->n_phy];
        else
-               port = &mvi->port[sas_port->id];
+               port = &mvi->port[i];
        if (lock)
                spin_lock_irqsave(&mvi->lock, flags);
        port->port_attached = 1;
@@ -1393,7 +1260,7 @@ static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock)
                        return;
        }
        list_for_each_entry(dev, &port->dev_list, dev_list_node)
-               mvs_do_release_task(phy->mvi, phy_no, NULL);
+               mvs_do_release_task(phy->mvi, phy_no, dev);
 
 }
 
@@ -1457,6 +1324,7 @@ int mvs_dev_found_notify(struct domain_device *dev, int lock)
        mvi_device->dev_status = MVS_DEV_NORMAL;
        mvi_device->dev_type = dev->dev_type;
        mvi_device->mvi_info = mvi;
+       mvi_device->sas_device = dev;
        if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
                int phy_id;
                u8 phy_num = parent_dev->ex_dev.num_phys;
@@ -1508,6 +1376,7 @@ void mvs_dev_gone_notify(struct domain_device *dev)
                mv_dprintk("found dev has gone.\n");
        }
        dev->lldd_dev = NULL;
+       mvi_dev->sas_device = NULL;
 
        spin_unlock_irqrestore(&mvi->lock, flags);
 }
@@ -1555,7 +1424,6 @@ static void mvs_tmf_timedout(unsigned long data)
        complete(&task->completion);
 }
 
-/* XXX */
 #define MVS_TASK_TIMEOUT 20
 static int mvs_exec_internal_tmf_task(struct domain_device *dev,
                        void *parameter, u32 para_len, struct mvs_tmf_task *tmf)
@@ -1588,7 +1456,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev,
                }
 
                wait_for_completion(&task->completion);
-               res = -TMF_RESP_FUNC_FAILED;
+               res = TMF_RESP_FUNC_FAILED;
                /* Even TMF timed out, return direct. */
                if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
                        if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
@@ -1638,11 +1506,10 @@ static int mvs_debug_issue_ssp_tmf(struct domain_device *dev,
                                u8 *lun, struct mvs_tmf_task *tmf)
 {
        struct sas_ssp_task ssp_task;
-       DECLARE_COMPLETION_ONSTACK(completion);
        if (!(dev->tproto & SAS_PROTOCOL_SSP))
                return TMF_RESP_FUNC_ESUPP;
 
-       strncpy((u8 *)&ssp_task.LUN, lun, 8);
+       memcpy(ssp_task.LUN, lun, 8);
 
        return mvs_exec_internal_tmf_task(dev, &ssp_task,
                                sizeof(ssp_task), tmf);
@@ -1666,7 +1533,7 @@ static int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
 int mvs_lu_reset(struct domain_device *dev, u8 *lun)
 {
        unsigned long flags;
-       int i, phyno[WIDE_PORT_MAX_PHY], num , rc = TMF_RESP_FUNC_FAILED;
+       int rc = TMF_RESP_FUNC_FAILED;
        struct mvs_tmf_task tmf_task;
        struct mvs_device * mvi_dev = dev->lldd_dev;
        struct mvs_info *mvi = mvi_dev->mvi_info;
@@ -1675,10 +1542,8 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun)
        mvi_dev->dev_status = MVS_DEV_EH;
        rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task);
        if (rc == TMF_RESP_FUNC_COMPLETE) {
-               num = mvs_find_dev_phyno(dev, phyno);
                spin_lock_irqsave(&mvi->lock, flags);
-               for (i = 0; i < num; i++)
-                       mvs_release_task(mvi, dev);
+               mvs_release_task(mvi, dev);
                spin_unlock_irqrestore(&mvi->lock, flags);
        }
        /* If failed, fall-through I_T_Nexus reset */
@@ -1696,11 +1561,12 @@ int mvs_I_T_nexus_reset(struct domain_device *dev)
 
        if (mvi_dev->dev_status != MVS_DEV_EH)
                return TMF_RESP_FUNC_COMPLETE;
+       else
+               mvi_dev->dev_status = MVS_DEV_NORMAL;
        rc = mvs_debug_I_T_nexus_reset(dev);
        mv_printk("%s for device[%x]:rc= %d\n",
                __func__, mvi_dev->device_id, rc);
 
-       /* housekeeper */
        spin_lock_irqsave(&mvi->lock, flags);
        mvs_release_task(mvi, dev);
        spin_unlock_irqrestore(&mvi->lock, flags);
@@ -1739,9 +1605,6 @@ int mvs_query_task(struct sas_task *task)
                case TMF_RESP_FUNC_FAILED:
                case TMF_RESP_FUNC_COMPLETE:
                        break;
-               default:
-                       rc = TMF_RESP_FUNC_COMPLETE;
-                       break;
                }
        }
        mv_printk("%s:rc= %d\n", __func__, rc);
@@ -1761,8 +1624,8 @@ int mvs_abort_task(struct sas_task *task)
        u32 tag;
 
        if (!mvi_dev) {
-               mv_printk("%s:%d TMF_RESP_FUNC_FAILED\n", __func__, __LINE__);
-               rc = TMF_RESP_FUNC_FAILED;
+               mv_printk("Device has removed\n");
+               return TMF_RESP_FUNC_FAILED;
        }
 
        mvi = mvi_dev->mvi_info;
@@ -1807,25 +1670,17 @@ int mvs_abort_task(struct sas_task *task)
 
        } else if (task->task_proto & SAS_PROTOCOL_SATA ||
                task->task_proto & SAS_PROTOCOL_STP) {
-               /* to do free register_set */
                if (SATA_DEV == dev->dev_type) {
                        struct mvs_slot_info *slot = task->lldd_task;
-                       struct task_status_struct *tstat;
                        u32 slot_idx = (u32)(slot - mvi->slot_info);
-                       tstat = &task->task_status;
-                       mv_dprintk(KERN_DEBUG "mv_abort_task() mvi=%p task=%p "
+                       mv_dprintk("mvs_abort_task() mvi=%p task=%p "
                                   "slot=%p slot_idx=x%x\n",
                                   mvi, task, slot, slot_idx);
-                       tstat->stat = SAS_ABORTED_TASK;
-                       if (mvi_dev && mvi_dev->running_req)
-                               mvi_dev->running_req--;
-                       if (sas_protocol_ata(task->task_proto))
-                               mvs_free_reg_set(mvi, mvi_dev);
+                       mvs_tmf_timedout((unsigned long)task);
                        mvs_slot_task_free(mvi, task, slot, slot_idx);
-                       return -1;
+                       rc = TMF_RESP_FUNC_COMPLETE;
+                       goto out;
                }
-       } else {
-               /* SMP */
 
        }
 out:
@@ -1891,12 +1746,63 @@ static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task,
        return stat;
 }
 
+void mvs_set_sense(u8 *buffer, int len, int d_sense,
+               int key, int asc, int ascq)
+{
+       memset(buffer, 0, len);
+
+       if (d_sense) {
+               /* Descriptor format */
+               if (len < 4) {
+                       mv_printk("Length %d of sense buffer too small to "
+                               "fit sense %x:%x:%x", len, key, asc, ascq);
+               }
+
+               buffer[0] = 0x72;               /* Response Code        */
+               if (len > 1)
+                       buffer[1] = key;        /* Sense Key */
+               if (len > 2)
+                       buffer[2] = asc;        /* ASC  */
+               if (len > 3)
+                       buffer[3] = ascq;       /* ASCQ */
+       } else {
+               if (len < 14) {
+                       mv_printk("Length %d of sense buffer too small to "
+                               "fit sense %x:%x:%x", len, key, asc, ascq);
+               }
+
+               buffer[0] = 0x70;               /* Response Code        */
+               if (len > 2)
+                       buffer[2] = key;        /* Sense Key */
+               if (len > 7)
+                       buffer[7] = 0x0a;       /* Additional Sense Length */
+               if (len > 12)
+                       buffer[12] = asc;       /* ASC */
+               if (len > 13)
+                       buffer[13] = ascq; /* ASCQ */
+       }
+
+       return;
+}
+
+void mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu,
+                               u8 key, u8 asc, u8 asc_q)
+{
+       iu->datapres = 2;
+       iu->response_data_len = 0;
+       iu->sense_data_len = 17;
+       iu->status = 02;
+       mvs_set_sense(iu->sense_data, 17, 0,
+                       key, asc, asc_q);
+}
+
 static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
                         u32 slot_idx)
 {
        struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
        int stat;
-       u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response));
+       u32 err_dw0 = le32_to_cpu(*(u32 *)slot->response);
+       u32 err_dw1 = le32_to_cpu(*((u32 *)slot->response + 1));
        u32 tfs = 0;
        enum mvs_port_type type = PORT_TYPE_SAS;
 
@@ -1908,8 +1814,19 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
        stat = SAM_STAT_CHECK_CONDITION;
        switch (task->task_proto) {
        case SAS_PROTOCOL_SSP:
+       {
                stat = SAS_ABORTED_TASK;
+               if ((err_dw0 & NO_DEST) || err_dw1 & bit(31)) {
+                       struct ssp_response_iu *iu = slot->response +
+                               sizeof(struct mvs_err_info);
+                       mvs_fill_ssp_resp_iu(iu, NOT_READY, 0x04, 01);
+                       sas_ssp_task_response(mvi->dev, task, iu);
+                       stat = SAM_STAT_CHECK_CONDITION;
+               }
+               if (err_dw1 & bit(31))
+                       mv_printk("reuse same slot, retry command.\n");
                break;
+       }
        case SAS_PROTOCOL_SMP:
                stat = SAM_STAT_CHECK_CONDITION;
                break;
@@ -1918,10 +1835,8 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
        case SAS_PROTOCOL_STP:
        case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
        {
-               if (err_dw0 == 0x80400002)
-                       mv_printk("find reserved error, why?\n");
-
                task->ata_task.use_ncq = 0;
+               stat = SAS_PROTO_RESPONSE;
                mvs_sata_done(mvi, task, slot_idx, err_dw0);
        }
                break;
@@ -1945,8 +1860,6 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
        void *to;
        enum exec_status sts;
 
-       if (mvi->exp_req)
-               mvi->exp_req--;
        if (unlikely(!task || !task->lldd_task || !task->dev))
                return -1;
 
@@ -1954,8 +1867,6 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
        dev = task->dev;
        mvi_dev = dev->lldd_dev;
 
-       mvs_hba_cq_dump(mvi);
-
        spin_lock(&task->task_state_lock);
        task->task_state_flags &=
                ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
@@ -1978,6 +1889,7 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
                return -1;
        }
 
+       /* when no device attaching, go ahead and complete by error handling*/
        if (unlikely(!mvi_dev || flags)) {
                if (!mvi_dev)
                        mv_dprintk("port has not device.\n");
@@ -1987,6 +1899,9 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags)
 
        /* error info record present */
        if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) {
+               mv_dprintk("port %d slot %d rx_desc %X has error info"
+                       "%016llX.\n", slot->port->sas_port.id, slot_idx,
+                        rx_desc, (u64)(*(u64 *)slot->response));
                tstat->stat = mvs_slot_err(mvi, task, slot_idx);
                tstat->resp = SAS_TASK_COMPLETE;
                goto out;
@@ -2048,8 +1963,7 @@ out:
        spin_unlock(&mvi->lock);
        if (task->task_done)
                task->task_done(task);
-       else
-               mv_dprintk("why has not task_done.\n");
+
        spin_lock(&mvi->lock);
 
        return sts;
@@ -2092,7 +2006,6 @@ void mvs_release_task(struct mvs_info *mvi,
                      struct domain_device *dev)
 {
        int i, phyno[WIDE_PORT_MAX_PHY], num;
-       /* housekeeper */
        num = mvs_find_dev_phyno(dev, phyno);
        for (i = 0; i < num; i++)
                mvs_do_release_task(mvi, phyno[i], dev);
@@ -2111,13 +2024,13 @@ static void mvs_work_queue(struct work_struct *work)
        struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q);
        struct mvs_info *mvi = mwq->mvi;
        unsigned long flags;
+       u32 phy_no = (unsigned long) mwq->data;
+       struct sas_ha_struct *sas_ha = mvi->sas;
+       struct mvs_phy *phy = &mvi->phy[phy_no];
+       struct asd_sas_phy *sas_phy = &phy->sas_phy;
 
        spin_lock_irqsave(&mvi->lock, flags);
        if (mwq->handler & PHY_PLUG_EVENT) {
-               u32 phy_no = (unsigned long) mwq->data;
-               struct sas_ha_struct *sas_ha = mvi->sas;
-               struct mvs_phy *phy = &mvi->phy[phy_no];
-               struct asd_sas_phy *sas_phy = &phy->sas_phy;
 
                if (phy->phy_event & PHY_PLUG_OUT) {
                        u32 tmp;
@@ -2139,6 +2052,11 @@ static void mvs_work_queue(struct work_struct *work)
                                mv_dprintk("phy%d Attached Device\n", phy_no);
                        }
                }
+       } else if (mwq->handler & EXP_BRCT_CHG) {
+               phy->phy_event &= ~EXP_BRCT_CHG;
+               sas_ha->notify_port_event(sas_phy,
+                               PORTE_BROADCAST_RCVD);
+               mv_dprintk("phy%d Got Broadcast Change\n", phy_no);
        }
        list_del(&mwq->entry);
        spin_unlock_irqrestore(&mvi->lock, flags);
@@ -2174,29 +2092,21 @@ static void mvs_sig_time_out(unsigned long tphy)
                if (&mvi->phy[phy_no] == phy) {
                        mv_dprintk("Get signature time out, reset phy %d\n",
                                phy_no+mvi->id*mvi->chip->n_phy);
-                       MVS_CHIP_DISP->phy_reset(mvi, phy_no, 1);
+                       MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_HARD_RESET);
                }
        }
 }
 
-static void mvs_sig_remove_timer(struct mvs_phy *phy)
-{
-       if (phy->timer.function)
-               del_timer(&phy->timer);
-       phy->timer.function = NULL;
-}
-
 void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
 {
        u32 tmp;
-       struct sas_ha_struct *sas_ha = mvi->sas;
        struct mvs_phy *phy = &mvi->phy[phy_no];
-       struct asd_sas_phy *sas_phy = &phy->sas_phy;
 
        phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no);
-       mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy,
+       MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
+       mv_dprintk("phy %d ctrl sts=0x%08X.\n", phy_no+mvi->id*mvi->chip->n_phy,
                MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no));
-       mv_dprintk("Port %d irq sts = 0x%X\n", phy_no+mvi->id*mvi->chip->n_phy,
+       mv_dprintk("phy %d irq sts = 0x%08X\n", phy_no+mvi->id*mvi->chip->n_phy,
                phy->irq_status);
 
        /*
@@ -2205,11 +2115,12 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
        */
 
        if (phy->irq_status & PHYEV_DCDR_ERR) {
-               mv_dprintk("port %d STP decoding error.\n",
+               mv_dprintk("phy %d STP decoding error.\n",
                phy_no + mvi->id*mvi->chip->n_phy);
        }
 
        if (phy->irq_status & PHYEV_POOF) {
+               mdelay(500);
                if (!(phy->phy_event & PHY_PLUG_OUT)) {
                        int dev_sata = phy->phy_type & PORT_TYPE_SATA;
                        int ready;
@@ -2220,17 +2131,13 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                                (void *)(unsigned long)phy_no,
                                PHY_PLUG_EVENT);
                        ready = mvs_is_phy_ready(mvi, phy_no);
-                       if (!ready)
-                               mv_dprintk("phy%d Unplug Notice\n",
-                                       phy_no +
-                                       mvi->id * mvi->chip->n_phy);
                        if (ready || dev_sata) {
                                if (MVS_CHIP_DISP->stp_reset)
                                        MVS_CHIP_DISP->stp_reset(mvi,
                                                        phy_no);
                                else
                                        MVS_CHIP_DISP->phy_reset(mvi,
-                                                       phy_no, 0);
+                                                       phy_no, MVS_SOFT_RESET);
                                return;
                        }
                }
@@ -2243,13 +2150,12 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                if (phy->timer.function == NULL) {
                        phy->timer.data = (unsigned long)phy;
                        phy->timer.function = mvs_sig_time_out;
-                       phy->timer.expires = jiffies + 10*HZ;
+                       phy->timer.expires = jiffies + 5*HZ;
                        add_timer(&phy->timer);
                }
        }
        if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) {
                phy->phy_status = mvs_is_phy_ready(mvi, phy_no);
-               mvs_sig_remove_timer(phy);
                mv_dprintk("notify plug in on phy[%d]\n", phy_no);
                if (phy->phy_status) {
                        mdelay(10);
@@ -2263,14 +2169,14 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                        }
                        mvs_update_phyinfo(mvi, phy_no, 0);
                        if (phy->phy_type & PORT_TYPE_SAS) {
-                               MVS_CHIP_DISP->phy_reset(mvi, phy_no, 2);
+                               MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_PHY_TUNE);
                                mdelay(10);
                        }
 
                        mvs_bytes_dmaed(mvi, phy_no);
                        /* whether driver is going to handle hot plug */
                        if (phy->phy_event & PHY_PLUG_OUT) {
-                               mvs_port_notify_formed(sas_phy, 0);
+                               mvs_port_notify_formed(&phy->sas_phy, 0);
                                phy->phy_event &= ~PHY_PLUG_OUT;
                        }
                } else {
@@ -2278,13 +2184,11 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
                                phy_no + mvi->id*mvi->chip->n_phy);
                }
        } else if (phy->irq_status & PHYEV_BROAD_CH) {
-               mv_dprintk("port %d broadcast change.\n",
+               mv_dprintk("phy %d broadcast change.\n",
                        phy_no + mvi->id*mvi->chip->n_phy);
-               /* exception for Samsung disk drive*/
-               mdelay(1000);
-               sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+               mvs_handle_event(mvi, (void *)(unsigned long)phy_no,
+                               EXP_BRCT_CHG);
        }
-       MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
 }
 
 int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
index 1367d8b9350de4580f32b64f9b4d8dc9520a2575..44d7885a4a1dd32dc3cef9460d80bcfcb65d2bfc 100644 (file)
 
 #define DRV_NAME               "mvsas"
 #define DRV_VERSION            "0.8.2"
-#define _MV_DUMP               0
 #define MVS_ID_NOT_MAPPED      0x7f
-/* #define DISABLE_HOTPLUG_DMA_FIX */
-// #define MAX_EXP_RUNNING_REQ 2
 #define WIDE_PORT_MAX_PHY              4
-#define        MV_DISABLE_NCQ  0
 #define mv_printk(fmt, arg ...)        \
        printk(KERN_DEBUG"%s %d:" fmt, __FILE__, __LINE__, ## arg)
 #ifdef MV_DEBUG
@@ -64,6 +60,7 @@
 #endif
 #define MV_MAX_U32                     0xffffffff
 
+extern int interrupt_coalescing;
 extern struct mvs_tgt_initiator mvs_tgt;
 extern struct mvs_info *tgt_mvi;
 extern const struct mvs_dispatch mvs_64xx_dispatch;
@@ -99,6 +96,11 @@ enum dev_status {
        MVS_DEV_EH      = 0x1,
 };
 
+enum dev_reset {
+       MVS_SOFT_RESET  = 0,
+       MVS_HARD_RESET  = 1,
+       MVS_PHY_TUNE    = 2,
+};
 
 struct mvs_info;
 
@@ -130,7 +132,6 @@ struct mvs_dispatch {
        u32 (*read_port_irq_mask)(struct mvs_info *mvi, u32 port);
        void (*write_port_irq_mask)(struct mvs_info *mvi, u32 port, u32 val);
 
-       void (*get_sas_addr)(void *buf, u32 buflen);
        void (*command_active)(struct mvs_info *mvi, u32 slot_idx);
        void (*clear_srs_irq)(struct mvs_info *mvi, u8 reg_set, u8 clear_all);
        void (*issue_stop)(struct mvs_info *mvi, enum mvs_port_type type,
@@ -167,9 +168,10 @@ struct mvs_dispatch {
                                                );
        int (*spi_issuecmd)(struct mvs_info *mvi, u32 cmd);
        int (*spi_waitdataready)(struct mvs_info *mvi, u32 timeout);
-#ifndef DISABLE_HOTPLUG_DMA_FIX
-       void (*dma_fix)(dma_addr_t buf_dma, int buf_len, int from, void *prd);
-#endif
+       void (*dma_fix)(struct mvs_info *mvi, u32 phy_mask,
+                               int buf_len, int from, void *prd);
+       void (*tune_interrupt)(struct mvs_info *mvi, u32 time);
+       void (*non_spec_ncq_error)(struct mvs_info *mvi);
 
 };
 
@@ -179,9 +181,11 @@ struct mvs_chip_info {
        u32             fis_offs;
        u32             fis_count;
        u32             srs_sz;
+       u32             sg_width;
        u32             slot_width;
        const struct mvs_dispatch *dispatch;
 };
+#define MVS_MAX_SG             (1U << mvi->chip->sg_width)
 #define MVS_CHIP_SLOT_SZ       (1U << mvi->chip->slot_width)
 #define MVS_RX_FISL_SZ         \
        (mvi->chip->fis_offs + (mvi->chip->fis_count * 0x100))
@@ -249,6 +253,73 @@ struct mvs_device {
        u16 reserved;
 };
 
+/* Generate  PHY tunning parameters */
+struct phy_tuning {
+       /* 1 bit,  transmitter emphasis enable  */
+       u8      trans_emp_en:1;
+       /* 4 bits, transmitter emphasis amplitude */
+       u8      trans_emp_amp:4;
+       /* 3 bits, reserved space */
+       u8      Reserved_2bit_1:3;
+       /* 5 bits, transmitter amplitude */
+       u8      trans_amp:5;
+       /* 2 bits, transmitter amplitude adjust */
+       u8      trans_amp_adj:2;
+       /* 1 bit, reserved space */
+       u8      resv_2bit_2:1;
+       /* 2 bytes, reserved space */
+       u8      reserved[2];
+};
+
+struct ffe_control {
+       /* 4 bits,  FFE Capacitor Select  (value range 0~F)  */
+       u8 ffe_cap_sel:4;
+       /* 3 bits,  FFE Resistor Select (value range 0~7) */
+       u8 ffe_rss_sel:3;
+       /* 1 bit reserve*/
+       u8 reserved:1;
+};
+
+/*
+ * HBA_Info_Page is saved in Flash/NVRAM, total 256 bytes.
+ * The data area is valid only Signature="MRVL".
+ * If any member fills with 0xFF, the member is invalid.
+ */
+struct hba_info_page {
+       /* Dword 0 */
+       /* 4 bytes, structure signature,should be "MRVL" at first initial */
+       u8 signature[4];
+
+       /* Dword 1-13 */
+       u32 reserved1[13];
+
+       /* Dword 14-29 */
+       /* 64 bytes, SAS address for each port */
+       u64 sas_addr[8];
+
+       /* Dword 30-31 */
+       /* 8 bytes for vanir 8 port PHY FFE seeting
+        * BIT 0~3 : FFE Capacitor select(value range 0~F)
+        * BIT 4~6 : FFE Resistor select(value range 0~7)
+        * BIT 7: reserve.
+        */
+
+       struct ffe_control  ffe_ctl[8];
+       /* Dword 32 -43 */
+       u32 reserved2[12];
+
+       /* Dword 44-45 */
+       /* 8 bytes,  0:  1.5G, 1: 3.0G, should be 0x01 at first initial */
+       u8 phy_rate[8];
+
+       /* Dword 46-53 */
+       /* 32 bytes, PHY tuning parameters for each PHY*/
+       struct phy_tuning   phy_tuning[8];
+
+       /* Dword 54-63 */
+       u32 reserved3[10];
+};     /* total 256 bytes */
+
 struct mvs_slot_info {
        struct list_head entry;
        union {
@@ -264,9 +335,6 @@ struct mvs_slot_info {
         */
        void *buf;
        dma_addr_t buf_dma;
-#if _MV_DUMP
-       u32 cmd_size;
-#endif
        void *response;
        struct mvs_port *port;
        struct mvs_device       *device;
@@ -320,12 +388,10 @@ struct mvs_info {
        const struct mvs_chip_info *chip;
 
        int tags_num;
-       DECLARE_BITMAP(tags, MVS_SLOTS);
+       unsigned long *tags;
        /* further per-slot information */
        struct mvs_phy phy[MVS_MAX_PHYS];
        struct mvs_port port[MVS_MAX_PHYS];
-       u32 irq;
-       u32 exp_req;
        u32 id;
        u64 sata_reg_set;
        struct list_head *hba_list;
@@ -337,12 +403,13 @@ struct mvs_info {
        u32 flashsectSize;
 
        void *addon;
+       struct hba_info_page hba_info_param;
        struct mvs_device       devices[MVS_MAX_DEVICES];
-#ifndef DISABLE_HOTPLUG_DMA_FIX
        void *bulk_buffer;
        dma_addr_t bulk_buffer_dma;
+       void *bulk_buffer1;
+       dma_addr_t bulk_buffer_dma1;
 #define TRASH_BUCKET_SIZE      0x20000
-#endif
        void *dma_pool;
        struct mvs_slot_info slot_info[0];
 };
@@ -350,8 +417,10 @@ struct mvs_info {
 struct mvs_prv_info{
        u8 n_host;
        u8 n_phy;
-       u16 reserve;
+       u8 scan_finished;
+       u8 reserve;
        struct mvs_info *mvi[2];
+       struct tasklet_struct mv_tasklet;
 };
 
 struct mvs_wq {
@@ -415,6 +484,6 @@ void mvs_do_release_task(struct mvs_info *mvi, int phy_no,
 void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
 void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
 int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
-void mvs_hexdump(u32 size, u8 *data, u32 baseaddr);
+struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set);
 #endif
 
index fca6a895307093a4630530b83e03e66b7fd447cd..d079f9a3c6b3a7fc2dedd4cc850d32fcc82b4930 100644 (file)
@@ -3871,6 +3871,9 @@ static long pmcraid_ioctl_passthrough(
                        pmcraid_err("couldn't build passthrough ioadls\n");
                        goto out_free_buffer;
                }
+       } else if (request_size < 0) {
+               rc = -EINVAL;
+               goto out_free_buffer;
        }
 
        /* If data is being written into the device, copy the data from user
index 532313e0725e3f731f9b936756fd64e0b6970fe8..7836eb01c7fcd16a583e2d55884da2eea035de47 100644 (file)
@@ -42,8 +42,8 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
        int reading;
 
        if (IS_QLA82XX(ha)) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                       "Firmware dump not supported for ISP82xx\n"));
+               ql_dbg(ql_dbg_user, vha, 0x705b,
+                   "Firmware dump not supported for ISP82xx\n");
                return count;
        }
 
@@ -56,7 +56,7 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
                if (!ha->fw_dump_reading)
                        break;
 
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0x705d,
                    "Firmware dump cleared on (%ld).\n", vha->host_no);
 
                ha->fw_dump_reading = 0;
@@ -66,7 +66,7 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
                if (ha->fw_dumped && !ha->fw_dump_reading) {
                        ha->fw_dump_reading = 1;
 
-                       qla_printk(KERN_INFO, ha,
+                       ql_log(ql_log_info, vha, 0x705e,
                            "Raw firmware dump ready for read on (%ld).\n",
                            vha->host_no);
                }
@@ -148,7 +148,7 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
        }
 
        if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x705f,
                    "HBA not online, failing NVRAM update.\n");
                return -EAGAIN;
        }
@@ -158,6 +158,8 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
        ha->isp_ops->read_nvram(vha, (uint8_t *)ha->nvram, ha->nvram_base,
            count);
 
+       ql_dbg(ql_dbg_user, vha, 0x7060,
+           "Setting ISP_ABORT_NEEDED\n");
        /* NVRAM settings take effect immediately. */
        set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
        qla2xxx_wake_dpc(vha);
@@ -255,9 +257,9 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
 
                ha->optrom_state = QLA_SWAITING;
 
-               DEBUG2(qla_printk(KERN_INFO, ha,
+               ql_dbg(ql_dbg_user, vha, 0x7061,
                    "Freeing flash region allocation -- 0x%x bytes.\n",
-                   ha->optrom_region_size));
+                   ha->optrom_region_size);
 
                vfree(ha->optrom_buffer);
                ha->optrom_buffer = NULL;
@@ -273,7 +275,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                ha->optrom_state = QLA_SREADING;
                ha->optrom_buffer = vmalloc(ha->optrom_region_size);
                if (ha->optrom_buffer == NULL) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x7062,
                            "Unable to allocate memory for optrom retrieval "
                            "(%x).\n", ha->optrom_region_size);
 
@@ -282,14 +284,14 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                }
 
                if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
-                       qla_printk(KERN_WARNING, ha,
-                               "HBA not online, failing NVRAM update.\n");
+                       ql_log(ql_log_warn, vha, 0x7063,
+                           "HBA not online, failing NVRAM update.\n");
                        return -EAGAIN;
                }
 
-               DEBUG2(qla_printk(KERN_INFO, ha,
+               ql_dbg(ql_dbg_user, vha, 0x7064,
                    "Reading flash region -- 0x%x/0x%x.\n",
-                   ha->optrom_region_start, ha->optrom_region_size));
+                   ha->optrom_region_start, ha->optrom_region_size);
 
                memset(ha->optrom_buffer, 0, ha->optrom_region_size);
                ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
@@ -328,7 +330,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                else if (IS_QLA25XX(ha) || IS_QLA8XXX_TYPE(ha))
                        valid = 1;
                if (!valid) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x7065,
                            "Invalid start region 0x%x/0x%x.\n", start, size);
                        return -EINVAL;
                }
@@ -340,17 +342,17 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                ha->optrom_state = QLA_SWRITING;
                ha->optrom_buffer = vmalloc(ha->optrom_region_size);
                if (ha->optrom_buffer == NULL) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x7066,
                            "Unable to allocate memory for optrom update "
-                           "(%x).\n", ha->optrom_region_size);
+                           "(%x)\n", ha->optrom_region_size);
 
                        ha->optrom_state = QLA_SWAITING;
                        return count;
                }
 
-               DEBUG2(qla_printk(KERN_INFO, ha,
+               ql_dbg(ql_dbg_user, vha, 0x7067,
                    "Staging flash region write -- 0x%x/0x%x.\n",
-                   ha->optrom_region_start, ha->optrom_region_size));
+                   ha->optrom_region_start, ha->optrom_region_size);
 
                memset(ha->optrom_buffer, 0, ha->optrom_region_size);
                break;
@@ -359,14 +361,14 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                        break;
 
                if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x7068,
                            "HBA not online, failing flash update.\n");
                        return -EAGAIN;
                }
 
-               DEBUG2(qla_printk(KERN_INFO, ha,
+               ql_dbg(ql_dbg_user, vha, 0x7069,
                    "Writing flash region -- 0x%x/0x%x.\n",
-                   ha->optrom_region_start, ha->optrom_region_size));
+                   ha->optrom_region_start, ha->optrom_region_size);
 
                ha->isp_ops->write_optrom(vha, ha->optrom_buffer,
                    ha->optrom_region_start, ha->optrom_region_size);
@@ -425,7 +427,7 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
                return 0;
 
        if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x706a,
                    "HBA not online, failing VPD update.\n");
                return -EAGAIN;
        }
@@ -440,7 +442,7 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
 
        tmp_data = vmalloc(256);
        if (!tmp_data) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x706b,
                    "Unable to allocate memory for VPD information update.\n");
                goto done;
        }
@@ -480,7 +482,7 @@ qla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj,
        ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
            &ha->sfp_data_dma);
        if (!ha->sfp_data) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x706c,
                    "Unable to allocate memory for SFP read-data.\n");
                return 0;
        }
@@ -499,9 +501,10 @@ do_read:
                rval = qla2x00_read_sfp(vha, ha->sfp_data_dma, ha->sfp_data,
                    addr, offset, SFP_BLOCK_SIZE, 0);
                if (rval != QLA_SUCCESS) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x706d,
                            "Unable to read SFP data (%x/%x/%x).\n", rval,
                            addr, offset);
+
                        count = 0;
                        break;
                }
@@ -538,8 +541,8 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
        type = simple_strtol(buf, NULL, 10);
        switch (type) {
        case 0x2025c:
-               qla_printk(KERN_INFO, ha,
-                   "Issuing ISP reset on (%ld).\n", vha->host_no);
+               ql_log(ql_log_info, vha, 0x706e,
+                   "Issuing ISP reset.\n");
 
                scsi_block_requests(vha->host);
                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -551,8 +554,8 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
                if (!IS_QLA81XX(ha))
                        break;
 
-               qla_printk(KERN_INFO, ha,
-                   "Issuing MPI reset on (%ld).\n", vha->host_no);
+               ql_log(ql_log_info, vha, 0x706f,
+                   "Issuing MPI reset.\n");
 
                /* Make sure FC side is not in reset */
                qla2x00_wait_for_hba_online(vha);
@@ -560,20 +563,19 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
                /* Issue MPI reset */
                scsi_block_requests(vha->host);
                if (qla81xx_restart_mpi_firmware(vha) != QLA_SUCCESS)
-                       qla_printk(KERN_WARNING, ha,
-                           "MPI reset failed on (%ld).\n", vha->host_no);
+                       ql_log(ql_log_warn, vha, 0x7070,
+                           "MPI reset failed.\n");
                scsi_unblock_requests(vha->host);
                break;
        case 0x2025e:
                if (!IS_QLA82XX(ha) || vha != base_vha) {
-                       qla_printk(KERN_INFO, ha,
-                           "FCoE ctx reset not supported for host%ld.\n",
-                           vha->host_no);
+                       ql_log(ql_log_info, vha, 0x7071,
+                           "FCoE ctx reset no supported.\n");
                        return count;
                }
 
-               qla_printk(KERN_INFO, ha,
-                   "Issuing FCoE CTX reset on host%ld.\n", vha->host_no);
+               ql_log(ql_log_info, vha, 0x7072,
+                   "Issuing FCoE ctx reset.\n");
                set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
                qla2xxx_wake_dpc(vha);
                qla2x00_wait_for_fcoe_ctx_reset(vha);
@@ -611,8 +613,8 @@ qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj,
                ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
                    &ha->edc_data_dma);
                if (!ha->edc_data) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "Unable to allocate memory for EDC write.\n"));
+                       ql_log(ql_log_warn, vha, 0x7073,
+                           "Unable to allocate memory for EDC write.\n");
                        return 0;
                }
        }
@@ -631,9 +633,9 @@ qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj,
        rval = qla2x00_write_sfp(vha, ha->edc_data_dma, ha->edc_data,
            dev, adr, len, opt);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "Unable to write EDC (%x) %02x:%02x:%04x:%02x:%02x.\n",
-                   rval, dev, adr, opt, len, buf[8]));
+               ql_log(ql_log_warn, vha, 0x7074,
+                   "Unable to write EDC (%x) %02x:%04x:%02x:%02x\n",
+                   rval, dev, adr, opt, len, buf[8]);
                return 0;
        }
 
@@ -669,8 +671,8 @@ qla2x00_sysfs_write_edc_status(struct file *filp, struct kobject *kobj,
                ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
                    &ha->edc_data_dma);
                if (!ha->edc_data) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "Unable to allocate memory for EDC status.\n"));
+                       ql_log(ql_log_warn, vha, 0x708c,
+                           "Unable to allocate memory for EDC status.\n");
                        return 0;
                }
        }
@@ -688,9 +690,9 @@ qla2x00_sysfs_write_edc_status(struct file *filp, struct kobject *kobj,
        rval = qla2x00_read_sfp(vha, ha->edc_data_dma, ha->edc_data,
                        dev, adr, len, opt);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "Unable to write EDC status (%x) %02x:%02x:%04x:%02x.\n",
-                   rval, dev, adr, opt, len));
+               ql_log(ql_log_info, vha, 0x7075,
+                   "Unable to write EDC status (%x) %02x:%04x:%02x.\n",
+                   rval, dev, adr, opt, len);
                return 0;
        }
 
@@ -749,7 +751,7 @@ qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
        ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE,
            &ha->xgmac_data_dma, GFP_KERNEL);
        if (!ha->xgmac_data) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7076,
                    "Unable to allocate memory for XGMAC read-data.\n");
                return 0;
        }
@@ -761,7 +763,7 @@ do_read:
        rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma,
            XGMAC_DATA_SIZE, &actual_size);
        if (rval != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7077,
                    "Unable to read XGMAC data (%x).\n", rval);
                count = 0;
        }
@@ -801,7 +803,7 @@ qla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj,
        ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
            &ha->dcbx_tlv_dma, GFP_KERNEL);
        if (!ha->dcbx_tlv) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7078,
                    "Unable to allocate memory for DCBX TLV read-data.\n");
                return 0;
        }
@@ -813,8 +815,8 @@ do_read:
        rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma,
            DCBX_TLV_DATA_SIZE);
        if (rval != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to read DCBX TLV data (%x).\n", rval);
+               ql_log(ql_log_warn, vha, 0x7079,
+                   "Unable to read DCBX TLV (%x).\n", rval);
                count = 0;
        }
 
@@ -869,9 +871,13 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
                ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
                    iter->attr);
                if (ret)
-                       qla_printk(KERN_INFO, vha->hw,
-                           "Unable to create sysfs %s binary attribute "
-                           "(%d).\n", iter->name, ret);
+                       ql_log(ql_log_warn, vha, 0x00f3,
+                           "Unable to create sysfs %s binary attribute (%d).\n",
+                           iter->name, ret);
+               else
+                       ql_dbg(ql_dbg_init, vha, 0x00f4,
+                           "Successfully created sysfs %s binary attribure.\n",
+                           iter->name);
        }
 }
 
@@ -1126,7 +1132,7 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr,
                return -EPERM;
 
        if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x707a,
                    "Abort ISP active -- ignoring beacon request.\n");
                return -EBUSY;
        }
@@ -1322,9 +1328,8 @@ qla2x00_thermal_temp_show(struct device *dev,
        temp = frac = 0;
        if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
            test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): isp reset in progress.\n",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x707b,
+                   "ISP reset active.\n");
        else if (!vha->hw->flags.eeh_busy)
                rval = qla2x00_get_thermal_temp(vha, &temp, &frac);
        if (rval != QLA_SUCCESS)
@@ -1343,8 +1348,8 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
 
        if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
                test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
-               DEBUG2_3_11(printk("%s(%ld): isp reset in progress.\n",
-                       __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x707c,
+                   "ISP reset active.\n");
        else if (!vha->hw->flags.eeh_busy)
                rval = qla2x00_get_firmware_state(vha, state);
        if (rval != QLA_SUCCESS)
@@ -1645,8 +1650,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
 
        stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
        if (stats == NULL) {
-               DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
-                   __func__, base_vha->host_no));
+               ql_log(ql_log_warn, vha, 0x707d,
+                   "Failed to allocate memory for stats.\n");
                goto done;
        }
        memset(stats, 0, DMA_POOL_SIZE);
@@ -1746,15 +1751,14 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
 
        ret = qla24xx_vport_create_req_sanity_check(fc_vport);
        if (ret) {
-               DEBUG15(printk("qla24xx_vport_create_req_sanity_check failed, "
-                   "status %x\n", ret));
+               ql_log(ql_log_warn, vha, 0x707e,
+                   "Vport sanity check failed, status %x\n", ret);
                return (ret);
        }
 
        vha = qla24xx_create_vhost(fc_vport);
        if (vha == NULL) {
-               DEBUG15(printk ("qla24xx_create_vhost failed, vha = %p\n",
-                   vha));
+               ql_log(ql_log_warn, vha, 0x707f, "Vport create host failed.\n");
                return FC_VPORT_FAILED;
        }
        if (disable) {
@@ -1764,8 +1768,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
                atomic_set(&vha->vp_state, VP_FAILED);
 
        /* ready to create vport */
-       qla_printk(KERN_INFO, vha->hw, "VP entry id %d assigned.\n",
-                                                       vha->vp_idx);
+       ql_log(ql_log_info, vha, 0x7080,
+           "VP entry id %d assigned.\n", vha->vp_idx);
 
        /* initialized vport states */
        atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -1775,8 +1779,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
        if (atomic_read(&base_vha->loop_state) == LOOP_DOWN ||
            atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
                /* Don't retry or attempt login of this virtual port */
-               DEBUG15(printk ("scsi(%ld): pport loop_state is not UP.\n",
-                   base_vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7081,
+                   "Vport loop state is not UP.\n");
                atomic_set(&vha->loop_state, LOOP_DEAD);
                if (!disable)
                        fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
@@ -1785,9 +1789,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
        if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
                if (ha->fw_attributes & BIT_4) {
                        vha->flags.difdix_supported = 1;
-                       DEBUG18(qla_printk(KERN_INFO, ha,
-                           "Registering for DIF/DIX type 1 and 3"
-                           " protection.\n"));
+                       ql_dbg(ql_dbg_user, vha, 0x7082,
+                           "Registered for DIF/DIX type 1 and 3 protection.\n");
                        scsi_host_set_prot(vha->host,
                            SHOST_DIF_TYPE1_PROTECTION
                            | SHOST_DIF_TYPE2_PROTECTION
@@ -1802,8 +1805,8 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
 
        if (scsi_add_host_with_dma(vha->host, &fc_vport->dev,
                                   &ha->pdev->dev)) {
-               DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n",
-                       vha->host_no, vha->vp_idx));
+               ql_dbg(ql_dbg_user, vha, 0x7083,
+                   "scsi_add_host failure for VP[%d].\n", vha->vp_idx);
                goto vport_create_failed_2;
        }
 
@@ -1820,6 +1823,10 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
 
        if (ha->flags.cpu_affinity_enabled) {
                req = ha->req_q_map[1];
+               ql_dbg(ql_dbg_multiq, vha, 0xc000,
+                   "Request queue %p attached with "
+                   "VP[%d], cpu affinity =%d\n",
+                   req, vha->vp_idx, ha->flags.cpu_affinity_enabled);
                goto vport_queue;
        } else if (ql2xmaxqueues == 1 || !ha->npiv_info)
                goto vport_queue;
@@ -1836,13 +1843,16 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
                ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, 0,
                        qos);
                if (!ret)
-                       qla_printk(KERN_WARNING, ha,
-                       "Can't create request queue for vp_idx:%d\n",
-                       vha->vp_idx);
+                       ql_log(ql_log_warn, vha, 0x7084,
+                           "Can't create request queue for VP[%d]\n",
+                           vha->vp_idx);
                else {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                       "Request Que:%d (QoS: %d) created for vp_idx:%d\n",
-                       ret, qos, vha->vp_idx));
+                       ql_dbg(ql_dbg_multiq, vha, 0xc001,
+                           "Request Que:%d Q0s: %d) created for VP[%d]\n",
+                           ret, qos, vha->vp_idx);
+                       ql_dbg(ql_dbg_user, vha, 0x7085,
+                           "Request Que:%d Q0s: %d) created for VP[%d]\n",
+                           ret, qos, vha->vp_idx);
                        req = ha->req_q_map[ret];
                }
        }
@@ -1882,12 +1892,13 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
 
        if (vha->timer_active) {
                qla2x00_vp_stop_timer(vha);
-               DEBUG15(printk(KERN_INFO "scsi(%ld): timer for the vport[%d]"
-               " = %p has stopped\n", vha->host_no, vha->vp_idx, vha));
+               ql_dbg(ql_dbg_user, vha, 0x7086,
+                   "Timer for the VP[%d] has stopped\n", vha->vp_idx);
        }
 
        /* No pending activities shall be there on the vha now */
-       DEBUG(msleep(random32()%10));  /* Just to see if something falls on
+       if (ql2xextended_error_logging & ql_dbg_user)
+               msleep(random32()%10);  /* Just to see if something falls on
                                        * the net we have placed below */
 
        BUG_ON(atomic_read(&vha->vref_count));
@@ -1901,12 +1912,12 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
 
        if (vha->req->id && !ha->flags.cpu_affinity_enabled) {
                if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS)
-                       qla_printk(KERN_WARNING, ha,
-                               "Queue delete failed.\n");
+                       ql_log(ql_log_warn, vha, 0x7087,
+                           "Queue delete failed.\n");
        }
 
        scsi_host_put(vha->host);
-       qla_printk(KERN_INFO, ha, "vport %d deleted\n", id);
+       ql_log(ql_log_info, vha, 0x7088, "VP[%d] deleted.\n", id);
        return 0;
 }
 
index 8c10e2c4928e3ccbbbab85e63534cde0c97aa528..07d1767cd26b077bce15cfbd6a675595b32b7c99 100644 (file)
@@ -36,7 +36,8 @@ done:
 }
 
 int
-qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
+qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *vha,
+       struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
 {
        int i, ret, num_valid;
        uint8_t *bcode;
@@ -51,18 +52,17 @@ qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
 
        if (bcode_val == 0xFFFFFFFF) {
                /* No FCP Priority config data in flash */
-               DEBUG2(printk(KERN_INFO
-                   "%s: No FCP priority config data.\n",
-                   __func__));
+               ql_dbg(ql_dbg_user, vha, 0x7051,
+                   "No FCP Priority config data.\n");
                return 0;
        }
 
        if (bcode[0] != 'H' || bcode[1] != 'Q' || bcode[2] != 'O' ||
                        bcode[3] != 'S') {
                /* Invalid FCP priority data header*/
-               DEBUG2(printk(KERN_ERR
-                   "%s: Invalid FCP Priority data header. bcode=0x%x\n",
-                   __func__, bcode_val));
+               ql_dbg(ql_dbg_user, vha, 0x7052,
+                   "Invalid FCP Priority data header. bcode=0x%x.\n",
+                   bcode_val);
                return 0;
        }
        if (flag != 1)
@@ -77,15 +77,14 @@ qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag)
 
        if (num_valid == 0) {
                /* No valid FCP priority data entries */
-               DEBUG2(printk(KERN_ERR
-                   "%s: No valid FCP Priority data entries.\n",
-                   __func__));
+               ql_dbg(ql_dbg_user, vha, 0x7053,
+                   "No valid FCP Priority data entries.\n");
                ret = 0;
        } else {
                /* FCP priority data is valid */
-               DEBUG2(printk(KERN_INFO
-                   "%s: Valid FCP priority data. num entries = %d\n",
-                   __func__, num_valid));
+               ql_dbg(ql_dbg_user, vha, 0x7054,
+                   "Valid FCP priority data. num entries = %d.\n",
+                   num_valid);
        }
 
        return ret;
@@ -182,10 +181,9 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
                if (!ha->fcp_prio_cfg) {
                        ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE);
                        if (!ha->fcp_prio_cfg) {
-                               qla_printk(KERN_WARNING, ha,
-                                       "Unable to allocate memory "
-                                       "for fcp prio config data (%x).\n",
-                                       FCP_PRIO_CFG_SIZE);
+                               ql_log(ql_log_warn, vha, 0x7050,
+                                   "Unable to allocate memory for fcp prio "
+                                   "config data (%x).\n", FCP_PRIO_CFG_SIZE);
                                bsg_job->reply->result = (DID_ERROR << 16);
                                ret = -ENOMEM;
                                goto exit_fcp_prio_cfg;
@@ -198,9 +196,9 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
                        FCP_PRIO_CFG_SIZE);
 
                /* validate fcp priority data */
-               if (!qla24xx_fcp_prio_cfg_valid(
-                       (struct qla_fcp_prio_cfg *)
-                       ha->fcp_prio_cfg, 1)) {
+
+               if (!qla24xx_fcp_prio_cfg_valid(vha,
+                   (struct qla_fcp_prio_cfg *) ha->fcp_prio_cfg, 1)) {
                        bsg_job->reply->result = (DID_ERROR << 16);
                        ret = -EINVAL;
                        /* If buffer was invalidatic int
@@ -256,9 +254,8 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
 
        /* pass through is supported only for ISP 4Gb or higher */
        if (!IS_FWI2_CAPABLE(ha)) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "scsi(%ld):ELS passthru not supported for ISP23xx based "
-                   "adapters\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7001,
+                   "ELS passthru not supported for ISP23xx based adapters.\n");
                rval = -EPERM;
                goto done;
        }
@@ -266,11 +263,11 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
        /*  Multiple SG's are not supported for ELS requests */
        if (bsg_job->request_payload.sg_cnt > 1 ||
                bsg_job->reply_payload.sg_cnt > 1) {
-               DEBUG2(printk(KERN_INFO
-                       "multiple SG's are not supported for ELS requests"
-                       " [request_sg_cnt: %x reply_sg_cnt: %x]\n",
-                       bsg_job->request_payload.sg_cnt,
-                       bsg_job->reply_payload.sg_cnt));
+               ql_dbg(ql_dbg_user, vha, 0x7002,
+                   "Multiple SG's are not suppored for ELS requests, "
+                   "request_sg_cnt=%x reply_sg_cnt=%x.\n",
+                   bsg_job->request_payload.sg_cnt,
+                   bsg_job->reply_payload.sg_cnt);
                rval = -EPERM;
                goto done;
        }
@@ -281,9 +278,9 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
                 * if not perform fabric login
                 */
                if (qla2x00_fabric_login(vha, fcport, &nextlid)) {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                       "failed to login port %06X for ELS passthru\n",
-                       fcport->d_id.b24));
+                       ql_dbg(ql_dbg_user, vha, 0x7003,
+                           "Failed to login port %06X for ELS passthru.\n",
+                           fcport->d_id.b24);
                        rval = -EIO;
                        goto done;
                }
@@ -314,8 +311,7 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
        }
 
        if (!vha->flags.online) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-               "host not online\n"));
+               ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n");
                rval = -EIO;
                goto done;
        }
@@ -337,12 +333,11 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
 
        if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
                (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
-               DEBUG2(printk(KERN_INFO
-                       "dma mapping resulted in different sg counts \
-                       [request_sg_cnt: %x dma_request_sg_cnt: %x\
-                       reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
-                       bsg_job->request_payload.sg_cnt, req_sg_cnt,
-                       bsg_job->reply_payload.sg_cnt, rsp_sg_cnt));
+               ql_log(ql_log_warn, vha, 0x7008,
+                   "dma mapping resulted in different sg counts, "
+                   "request_sg_cnt: %x dma_request_sg_cnt:%x reply_sg_cnt:%x "
+                   "dma_reply_sg_cnt:%x.\n", bsg_job->request_payload.sg_cnt,
+                   req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
                rval = -EAGAIN;
                goto done_unmap_sg;
        }
@@ -363,15 +358,16 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
                "bsg_els_rpt" : "bsg_els_hst");
        els->u.bsg_job = bsg_job;
 
-       DEBUG2(qla_printk(KERN_INFO, ha,
-               "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x "
-               "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type,
-               bsg_job->request->rqst_data.h_els.command_code,
-               fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
-               fcport->d_id.b.al_pa));
+       ql_dbg(ql_dbg_user, vha, 0x700a,
+           "bsg rqst type: %s els type: %x - loop-id=%x "
+           "portid=%-2x%02x%02x.\n", type,
+           bsg_job->request->rqst_data.h_els.command_code, fcport->loop_id,
+           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
 
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x700e,
+                   "qla2x00_start_sp failed = %d\n", rval);
                kfree(sp->ctx);
                mempool_free(sp, ha->srb_mempool);
                rval = -EIO;
@@ -411,6 +407,8 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
                dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
                        bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
        if (!req_sg_cnt) {
+               ql_log(ql_log_warn, vha, 0x700f,
+                   "dma_map_sg return %d for request\n", req_sg_cnt);
                rval = -ENOMEM;
                goto done;
        }
@@ -418,24 +416,25 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
        rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
                bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
        if (!rsp_sg_cnt) {
+               ql_log(ql_log_warn, vha, 0x7010,
+                   "dma_map_sg return %d for reply\n", rsp_sg_cnt);
                rval = -ENOMEM;
                goto done;
        }
 
        if ((req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
            (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "[request_sg_cnt: %x dma_request_sg_cnt: %x\
-                   reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
-                   bsg_job->request_payload.sg_cnt, req_sg_cnt,
-                   bsg_job->reply_payload.sg_cnt, rsp_sg_cnt));
+               ql_log(ql_log_warn, vha, 0x7011,
+                   "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x "
+                   "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt,
+                   req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
                rval = -EAGAIN;
                goto done_unmap_sg;
        }
 
        if (!vha->flags.online) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                       "host not online\n"));
+               ql_log(ql_log_warn, vha, 0x7012,
+                   "Host is not online.\n");
                rval = -EIO;
                goto done_unmap_sg;
        }
@@ -451,8 +450,8 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
                loop_id = vha->mgmt_svr_loop_id;
                break;
        default:
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "Unknown loop id: %x\n", loop_id));
+               ql_dbg(ql_dbg_user, vha, 0x7013,
+                   "Unknown loop id: %x.\n", loop_id);
                rval = -EINVAL;
                goto done_unmap_sg;
        }
@@ -464,6 +463,8 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
         */
        fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
        if (!fcport) {
+               ql_log(ql_log_warn, vha, 0x7014,
+                   "Failed to allocate fcport.\n");
                rval = -ENOMEM;
                goto done_unmap_sg;
        }
@@ -479,6 +480,8 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
        /* Alloc SRB structure */
        sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx));
        if (!sp) {
+               ql_log(ql_log_warn, vha, 0x7015,
+                   "qla2x00_get_ctx_bsg_sp failed.\n");
                rval = -ENOMEM;
                goto done_free_fcport;
        }
@@ -488,15 +491,17 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
        ct->name = "bsg_ct";
        ct->u.bsg_job = bsg_job;
 
-       DEBUG2(qla_printk(KERN_INFO, ha,
-               "scsi(%ld:%x): bsg rqst type: %s els type: %x - loop-id=%x "
-               "portid=%02x%02x%02x.\n", vha->host_no, sp->handle, type,
-               (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16),
-               fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
-               fcport->d_id.b.al_pa));
+       ql_dbg(ql_dbg_user, vha, 0x7016,
+           "bsg rqst type: %s else type: %x - "
+           "loop-id=%x portid=%02x%02x%02x.\n", type,
+           (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16),
+           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa);
 
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x7017,
+                   "qla2x00_start_sp failed=%d.\n", rval);
                kfree(sp->ctx);
                mempool_free(sp, ha->srb_mempool);
                rval = -EIO;
@@ -535,9 +540,8 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
        ha->notify_dcbx_comp = 1;
        ret = qla81xx_set_port_config(vha, new_config);
        if (ret != QLA_SUCCESS) {
-               DEBUG2(printk(KERN_ERR
-                   "%s(%lu): Set port config failed\n",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7021,
+                   "set port config failed.\n");
                ha->notify_dcbx_comp = 0;
                rval = -EINVAL;
                goto done_set_internal;
@@ -545,11 +549,11 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
 
        /* Wait for DCBX complete event */
        if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "State change notificaition not received.\n"));
+               ql_dbg(ql_dbg_user, vha, 0x7022,
+                   "State change notification not received.\n");
        } else
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "State change RECEIVED\n"));
+               ql_dbg(ql_dbg_user, vha, 0x7023,
+                   "State change received.\n");
 
        ha->notify_dcbx_comp = 0;
 
@@ -581,9 +585,8 @@ qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
                ha->notify_dcbx_comp = wait;
                ret = qla81xx_set_port_config(vha, new_config);
                if (ret != QLA_SUCCESS) {
-                       DEBUG2(printk(KERN_ERR
-                           "%s(%lu): Set port config failed\n",
-                            __func__, vha->host_no));
+                       ql_log(ql_log_warn, vha, 0x7025,
+                           "Set port config failed.\n");
                        ha->notify_dcbx_comp = 0;
                        rval = -EINVAL;
                        goto done_reset_internal;
@@ -592,14 +595,14 @@ qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
                /* Wait for DCBX complete event */
                if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
                        (20 * HZ))) {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "State change notificaition not received.\n"));
+                       ql_dbg(ql_dbg_user, vha, 0x7026,
+                           "State change notification not received.\n");
                        ha->notify_dcbx_comp = 0;
                        rval = -EINVAL;
                        goto done_reset_internal;
                } else
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "State change RECEIVED\n"));
+                       ql_dbg(ql_dbg_user, vha, 0x7027,
+                           "State change received.\n");
 
                ha->notify_dcbx_comp = 0;
        }
@@ -629,11 +632,13 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
 
        if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
                test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
-               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+               ql_log(ql_log_warn, vha, 0x7018, "Abort active or needed.\n");
                return -EBUSY;
+       }
 
        if (!vha->flags.online) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "host not online\n"));
+               ql_log(ql_log_warn, vha, 0x7019, "Host is not online.\n");
                return -EIO;
        }
 
@@ -641,26 +646,31 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt,
                DMA_TO_DEVICE);
 
-       if (!elreq.req_sg_cnt)
+       if (!elreq.req_sg_cnt) {
+               ql_log(ql_log_warn, vha, 0x701a,
+                   "dma_map_sg returned %d for request.\n", elreq.req_sg_cnt);
                return -ENOMEM;
+       }
 
        elreq.rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,
                bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt,
                DMA_FROM_DEVICE);
 
        if (!elreq.rsp_sg_cnt) {
+               ql_log(ql_log_warn, vha, 0x701b,
+                   "dma_map_sg returned %d for reply.\n", elreq.rsp_sg_cnt);
                rval = -ENOMEM;
                goto done_unmap_req_sg;
        }
 
        if ((elreq.req_sg_cnt !=  bsg_job->request_payload.sg_cnt) ||
                (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
-               DEBUG2(printk(KERN_INFO
-                       "dma mapping resulted in different sg counts "
-                       "[request_sg_cnt: %x dma_request_sg_cnt: %x "
-                       "reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
-                       bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt,
-                       bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt));
+               ql_log(ql_log_warn, vha, 0x701c,
+                   "dma mapping resulted in different sg counts, "
+                   "request_sg_cnt: %x dma_request_sg_cnt: %x "
+                   "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n",
+                   bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt,
+                   bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt);
                rval = -EAGAIN;
                goto done_unmap_sg;
        }
@@ -668,8 +678,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
        req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len,
                &req_data_dma, GFP_KERNEL);
        if (!req_data) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for req_data "
-                       "failed for host=%lu\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x701d,
+                   "dma alloc failed for req_data.\n");
                rval = -ENOMEM;
                goto done_unmap_sg;
        }
@@ -677,8 +687,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
        rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len,
                &rsp_data_dma, GFP_KERNEL);
        if (!rsp_data) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for rsp_data "
-                       "failed for host=%lu\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7004,
+                   "dma alloc failed for rsp_data.\n");
                rval = -ENOMEM;
                goto done_free_dma_req;
        }
@@ -699,8 +709,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
            && req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
                elreq.options == EXTERNAL_LOOPBACK) {
                type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                       "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
+               ql_dbg(ql_dbg_user, vha, 0x701e,
+                   "BSG request type: %s.\n", type);
                command_sent = INT_DEF_LB_ECHO_CMD;
                rval = qla2x00_echo_test(vha, &elreq, response);
        } else {
@@ -708,9 +718,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                        memset(config, 0, sizeof(config));
                        memset(new_config, 0, sizeof(new_config));
                        if (qla81xx_get_port_config(vha, config)) {
-                               DEBUG2(printk(KERN_ERR
-                                       "%s(%lu): Get port config failed\n",
-                                       __func__, vha->host_no));
+                               ql_log(ql_log_warn, vha, 0x701f,
+                                   "Get port config failed.\n");
                                bsg_job->reply->reply_payload_rcv_len = 0;
                                bsg_job->reply->result = (DID_ERROR << 16);
                                rval = -EPERM;
@@ -718,11 +727,13 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                        }
 
                        if (elreq.options != EXTERNAL_LOOPBACK) {
-                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                       "Internal: current port config = %x\n",
-                                       config[0]));
+                               ql_dbg(ql_dbg_user, vha, 0x7020,
+                                   "Internal: curent port config = %x\n",
+                                   config[0]);
                                if (qla81xx_set_internal_loopback(vha, config,
                                        new_config)) {
+                                       ql_log(ql_log_warn, vha, 0x7024,
+                                           "Internal loopback failed.\n");
                                        bsg_job->reply->reply_payload_rcv_len =
                                                0;
                                        bsg_job->reply->result =
@@ -746,9 +757,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                        }
 
                        type = "FC_BSG_HST_VENDOR_LOOPBACK";
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                               "scsi(%ld) bsg rqst type: %s\n",
-                               vha->host_no, type));
+                       ql_dbg(ql_dbg_user, vha, 0x7028,
+                           "BSG request type: %s.\n", type);
 
                        command_sent = INT_DEF_LB_LOOPBACK_CMD;
                        rval = qla2x00_loopback_test(vha, &elreq, response);
@@ -763,17 +773,16 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
 
                        if (response[0] == MBS_COMMAND_ERROR &&
                                        response[1] == MBS_LB_RESET) {
-                               DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
-                                       "ISP\n", __func__, vha->host_no));
+                               ql_log(ql_log_warn, vha, 0x7029,
+                                   "MBX command error, Aborting ISP.\n");
                                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                                qla2xxx_wake_dpc(vha);
                                qla2x00_wait_for_chip_reset(vha);
                                /* Also reset the MPI */
                                if (qla81xx_restart_mpi_firmware(vha) !=
                                    QLA_SUCCESS) {
-                                       qla_printk(KERN_INFO, ha,
-                                           "MPI reset failed for host%ld.\n",
-                                           vha->host_no);
+                                       ql_log(ql_log_warn, vha, 0x702a,
+                                           "MPI reset failed.\n");
                                }
 
                                bsg_job->reply->reply_payload_rcv_len = 0;
@@ -783,17 +792,16 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                        }
                } else {
                        type = "FC_BSG_HST_VENDOR_LOOPBACK";
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                               "scsi(%ld) bsg rqst type: %s\n",
-                               vha->host_no, type));
+                       ql_dbg(ql_dbg_user, vha, 0x702b,
+                           "BSG request type: %s.\n", type);
                        command_sent = INT_DEF_LB_LOOPBACK_CMD;
                        rval = qla2x00_loopback_test(vha, &elreq, response);
                }
        }
 
        if (rval) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                   "request %s failed\n", vha->host_no, type));
+               ql_log(ql_log_warn, vha, 0x702c,
+                   "Vendor request %s failed.\n", type);
 
                fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) +
                    sizeof(struct fc_bsg_reply);
@@ -805,8 +813,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                bsg_job->reply->reply_payload_rcv_len = 0;
                bsg_job->reply->result = (DID_ERROR << 16);
        } else {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                       "request %s completed\n", vha->host_no, type));
+               ql_dbg(ql_dbg_user, vha, 0x702d,
+                   "Vendor request %s completed.\n", type);
 
                bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
                        sizeof(response) + sizeof(uint8_t);
@@ -851,12 +859,13 @@ qla84xx_reset(struct fc_bsg_job *bsg_job)
 
        if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
            test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
-           test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+           test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+               ql_log(ql_log_warn, vha, 0x702e, "Abort active or needed.\n");
                return -EBUSY;
+       }
 
        if (!IS_QLA84XX(ha)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, "
-                  "exiting.\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x702f, "Not 84xx, exiting.\n");
                return -EINVAL;
        }
 
@@ -865,14 +874,14 @@ qla84xx_reset(struct fc_bsg_job *bsg_job)
        rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW);
 
        if (rval) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                   "request 84xx reset failed\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7030,
+                   "Vendor request 84xx reset failed.\n");
                rval = bsg_job->reply->reply_payload_rcv_len = 0;
                bsg_job->reply->result = (DID_ERROR << 16);
 
        } else {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                   "request 84xx reset completed\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7031,
+                   "Vendor request 84xx reset completed.\n");
                bsg_job->reply->result = DID_OK;
        }
 
@@ -902,21 +911,24 @@ qla84xx_updatefw(struct fc_bsg_job *bsg_job)
                return -EBUSY;
 
        if (!IS_QLA84XX(ha)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, "
-                       "exiting.\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7032,
+                   "Not 84xx, exiting.\n");
                return -EINVAL;
        }
 
        sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
                bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
-       if (!sg_cnt)
+       if (!sg_cnt) {
+               ql_log(ql_log_warn, vha, 0x7033,
+                   "dma_map_sg returned %d for request.\n", sg_cnt);
                return -ENOMEM;
+       }
 
        if (sg_cnt != bsg_job->request_payload.sg_cnt) {
-               DEBUG2(printk(KERN_INFO
-                       "dma mapping resulted in different sg counts "
-                       "request_sg_cnt: %x dma_request_sg_cnt: %x ",
-                       bsg_job->request_payload.sg_cnt, sg_cnt));
+               ql_log(ql_log_warn, vha, 0x7034,
+                   "DMA mapping resulted in different sg counts, "
+                   "request_sg_cnt: %x dma_request_sg_cnt: %x.\n",
+                   bsg_job->request_payload.sg_cnt, sg_cnt);
                rval = -EAGAIN;
                goto done_unmap_sg;
        }
@@ -925,8 +937,8 @@ qla84xx_updatefw(struct fc_bsg_job *bsg_job)
        fw_buf = dma_alloc_coherent(&ha->pdev->dev, data_len,
                &fw_dma, GFP_KERNEL);
        if (!fw_buf) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for fw_buf "
-                       "failed for host=%lu\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7035,
+                   "DMA alloc failed for fw_buf.\n");
                rval = -ENOMEM;
                goto done_unmap_sg;
        }
@@ -936,8 +948,8 @@ qla84xx_updatefw(struct fc_bsg_job *bsg_job)
 
        mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
        if (!mn) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer "
-                       "failed for host=%lu\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7036,
+                   "DMA alloc failed for fw buffer.\n");
                rval = -ENOMEM;
                goto done_free_fw_buf;
        }
@@ -965,15 +977,15 @@ qla84xx_updatefw(struct fc_bsg_job *bsg_job)
        rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120);
 
        if (rval) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                       "request 84xx updatefw failed\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7037,
+                   "Vendor request 84xx updatefw failed.\n");
 
                rval = bsg_job->reply->reply_payload_rcv_len = 0;
                bsg_job->reply->result = (DID_ERROR << 16);
 
        } else {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                       "request 84xx updatefw completed\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7038,
+                   "Vendor request 84xx updatefw completed.\n");
 
                bsg_job->reply_len = sizeof(struct fc_bsg_reply);
                bsg_job->reply->result = DID_OK;
@@ -1009,27 +1021,30 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
 
        if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
                test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
-               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+               ql_log(ql_log_warn, vha, 0x7039,
+                   "Abort active or needed.\n");
                return -EBUSY;
+       }
 
        if (!IS_QLA84XX(ha)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld): Not 84xx, "
-                       "exiting.\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x703a,
+                   "Not 84xx, exiting.\n");
                return -EINVAL;
        }
 
        ql84_mgmt = (struct qla_bsg_a84_mgmt *)((char *)bsg_job->request +
                sizeof(struct fc_bsg_request));
        if (!ql84_mgmt) {
-               DEBUG2(printk("%s(%ld): mgmt header not provided, exiting.\n",
-                       __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x703b,
+                   "MGMT header not provided, exiting.\n");
                return -EINVAL;
        }
 
        mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
        if (!mn) {
-               DEBUG2(printk(KERN_ERR "%s: dma alloc for fw buffer "
-                       "failed for host=%lu\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x703c,
+                   "DMA alloc failed for fw buffer.\n");
                return -ENOMEM;
        }
 
@@ -1044,6 +1059,8 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                        bsg_job->reply_payload.sg_list,
                        bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
                if (!sg_cnt) {
+                       ql_log(ql_log_warn, vha, 0x703d,
+                           "dma_map_sg returned %d for reply.\n", sg_cnt);
                        rval = -ENOMEM;
                        goto exit_mgmt;
                }
@@ -1051,10 +1068,10 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                dma_direction = DMA_FROM_DEVICE;
 
                if (sg_cnt != bsg_job->reply_payload.sg_cnt) {
-                       DEBUG2(printk(KERN_INFO
-                               "dma mapping resulted in different sg counts "
-                               "reply_sg_cnt: %x dma_reply_sg_cnt: %x\n",
-                               bsg_job->reply_payload.sg_cnt, sg_cnt));
+                       ql_log(ql_log_warn, vha, 0x703e,
+                           "DMA mapping resulted in different sg counts, "
+                           "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n",
+                           bsg_job->reply_payload.sg_cnt, sg_cnt);
                        rval = -EAGAIN;
                        goto done_unmap_sg;
                }
@@ -1064,9 +1081,8 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len,
                    &mgmt_dma, GFP_KERNEL);
                if (!mgmt_b) {
-                       DEBUG2(printk(KERN_ERR "%s: dma alloc for mgmt_b "
-                               "failed for host=%lu\n",
-                               __func__, vha->host_no));
+                       ql_log(ql_log_warn, vha, 0x703f,
+                           "DMA alloc failed for mgmt_b.\n");
                        rval = -ENOMEM;
                        goto done_unmap_sg;
                }
@@ -1094,6 +1110,8 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                        bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
 
                if (!sg_cnt) {
+                       ql_log(ql_log_warn, vha, 0x7040,
+                           "dma_map_sg returned %d.\n", sg_cnt);
                        rval = -ENOMEM;
                        goto exit_mgmt;
                }
@@ -1101,10 +1119,10 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                dma_direction = DMA_TO_DEVICE;
 
                if (sg_cnt != bsg_job->request_payload.sg_cnt) {
-                       DEBUG2(printk(KERN_INFO
-                               "dma mapping resulted in different sg counts "
-                               "request_sg_cnt: %x dma_request_sg_cnt: %x ",
-                               bsg_job->request_payload.sg_cnt, sg_cnt));
+                       ql_log(ql_log_warn, vha, 0x7041,
+                           "DMA mapping resulted in different sg counts, "
+                           "request_sg_cnt: %x dma_request_sg_cnt: %x.\n",
+                           bsg_job->request_payload.sg_cnt, sg_cnt);
                        rval = -EAGAIN;
                        goto done_unmap_sg;
                }
@@ -1113,9 +1131,8 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
                mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len,
                        &mgmt_dma, GFP_KERNEL);
                if (!mgmt_b) {
-                       DEBUG2(printk(KERN_ERR "%s: dma alloc for mgmt_b "
-                               "failed for host=%lu\n",
-                               __func__, vha->host_no));
+                       ql_log(ql_log_warn, vha, 0x7042,
+                           "DMA alloc failed for mgmt_b.\n");
                        rval = -ENOMEM;
                        goto done_unmap_sg;
                }
@@ -1156,15 +1173,15 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
        rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0);
 
        if (rval) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                       "request 84xx mgmt failed\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7043,
+                   "Vendor request 84xx mgmt failed.\n");
 
                rval = bsg_job->reply->reply_payload_rcv_len = 0;
                bsg_job->reply->result = (DID_ERROR << 16);
 
        } else {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "scsi(%ld) Vendor "
-                       "request 84xx mgmt completed\n", vha->host_no));
+               ql_dbg(ql_dbg_user, vha, 0x7044,
+                   "Vendor request 84xx mgmt completed.\n");
 
                bsg_job->reply_len = sizeof(struct fc_bsg_reply);
                bsg_job->reply->result = DID_OK;
@@ -1204,7 +1221,6 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
 {
        struct Scsi_Host *host = bsg_job->shost;
        scsi_qla_host_t *vha = shost_priv(host);
-       struct qla_hw_data *ha = vha->hw;
        int rval = 0;
        struct qla_port_param *port_param = NULL;
        fc_port_t *fcport = NULL;
@@ -1215,26 +1231,27 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
 
        if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
                test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
-               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags))
+               test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+               ql_log(ql_log_warn, vha, 0x7045, "abort active or needed.\n");
                return -EBUSY;
+       }
 
        if (!IS_IIDMA_CAPABLE(vha->hw)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha, "%s(%lu): iiDMA not "
-                       "supported\n",  __func__, vha->host_no));
+               ql_log(ql_log_info, vha, 0x7046, "iiDMA not supported.\n");
                return -EINVAL;
        }
 
        port_param = (struct qla_port_param *)((char *)bsg_job->request +
                sizeof(struct fc_bsg_request));
        if (!port_param) {
-               DEBUG2(printk("%s(%ld): port_param header not provided, "
-                       "exiting.\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7047,
+                   "port_param header not provided.\n");
                return -EINVAL;
        }
 
        if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) {
-               DEBUG2(printk(KERN_ERR "%s(%ld): Invalid destination type\n",
-                       __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7048,
+                   "Invalid destination type.\n");
                return -EINVAL;
        }
 
@@ -1249,21 +1266,20 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
        }
 
        if (!fcport) {
-               DEBUG2(printk(KERN_ERR "%s(%ld): Failed to find port\n",
-                       __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x7049,
+                   "Failed to find port.\n");
                return -EINVAL;
        }
 
        if (atomic_read(&fcport->state) != FCS_ONLINE) {
-               DEBUG2(printk(KERN_ERR "%s(%ld): Port not online\n",
-                       __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x704a,
+                   "Port is not online.\n");
                return -EINVAL;
        }
 
        if (fcport->flags & FCF_LOGIN_NEEDED) {
-               DEBUG2(printk(KERN_ERR "%s(%ld): Remote port not logged in, "
-                   "flags = 0x%x\n",
-                   __func__, vha->host_no, fcport->flags));
+               ql_log(ql_log_warn, vha, 0x704b,
+                   "Remote port not logged in flags = 0x%x.\n", fcport->flags);
                return -EINVAL;
        }
 
@@ -1275,15 +1291,13 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
                        &port_param->speed, mb);
 
        if (rval) {
-               DEBUG16(printk(KERN_ERR "scsi(%ld): iIDMA cmd failed for "
-                       "%02x%02x%02x%02x%02x%02x%02x%02x -- "
-                       "%04x %x %04x %04x.\n",
-                       vha->host_no, fcport->port_name[0],
-                       fcport->port_name[1],
-                       fcport->port_name[2], fcport->port_name[3],
-                       fcport->port_name[4], fcport->port_name[5],
-                       fcport->port_name[6], fcport->port_name[7], rval,
-                       fcport->fp_speed, mb[0], mb[1]));
+               ql_log(ql_log_warn, vha, 0x704c,
+                   "iIDMA cmd failed for %02x%02x%02x%02x%02x%02x%02x%02x -- "
+                   "%04x %x %04x %04x.\n", fcport->port_name[0],
+                   fcport->port_name[1], fcport->port_name[2],
+                   fcport->port_name[3], fcport->port_name[4],
+                   fcport->port_name[5], fcport->port_name[6],
+                   fcport->port_name[7], rval, fcport->fp_speed, mb[0], mb[1]);
                rval = 0;
                bsg_job->reply->result = (DID_ERROR << 16);
 
@@ -1307,11 +1321,12 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
 }
 
 static int
-qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
+qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, scsi_qla_host_t *vha,
        uint8_t is_update)
 {
        uint32_t start = 0;
        int valid = 0;
+       struct qla_hw_data *ha = vha->hw;
 
        bsg_job->reply->reply_payload_rcv_len = 0;
 
@@ -1319,14 +1334,20 @@ qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
                return -EINVAL;
 
        start = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
-       if (start > ha->optrom_size)
+       if (start > ha->optrom_size) {
+               ql_log(ql_log_warn, vha, 0x7055,
+                   "start %d > optrom_size %d.\n", start, ha->optrom_size);
                return -EINVAL;
+       }
 
-       if (ha->optrom_state != QLA_SWAITING)
+       if (ha->optrom_state != QLA_SWAITING) {
+               ql_log(ql_log_info, vha, 0x7056,
+                   "optrom_state %d.\n", ha->optrom_state);
                return -EBUSY;
+       }
 
        ha->optrom_region_start = start;
-
+       ql_dbg(ql_dbg_user, vha, 0x7057, "is_update=%d.\n", is_update);
        if (is_update) {
                if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
                        valid = 1;
@@ -1337,9 +1358,9 @@ qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
                    IS_QLA8XXX_TYPE(ha))
                        valid = 1;
                if (!valid) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Invalid start region 0x%x/0x%x.\n",
-                           start, bsg_job->request_payload.payload_len);
+                       ql_log(ql_log_warn, vha, 0x7058,
+                           "Invalid start region 0x%x/0x%x.\n", start,
+                           bsg_job->request_payload.payload_len);
                        return -EINVAL;
                }
 
@@ -1358,9 +1379,9 @@ qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
 
        ha->optrom_buffer = vmalloc(ha->optrom_region_size);
        if (!ha->optrom_buffer) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7059,
                    "Read: Unable to allocate memory for optrom retrieval "
-                   "(%x).\n", ha->optrom_region_size);
+                   "(%x)\n", ha->optrom_region_size);
 
                ha->optrom_state = QLA_SWAITING;
                return -ENOMEM;
@@ -1378,7 +1399,7 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
        struct qla_hw_data *ha = vha->hw;
        int rval = 0;
 
-       rval = qla2x00_optrom_setup(bsg_job, ha, 0);
+       rval = qla2x00_optrom_setup(bsg_job, vha, 0);
        if (rval)
                return rval;
 
@@ -1406,7 +1427,7 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
        struct qla_hw_data *ha = vha->hw;
        int rval = 0;
 
-       rval = qla2x00_optrom_setup(bsg_job, ha, 1);
+       rval = qla2x00_optrom_setup(bsg_job, vha, 1);
        if (rval)
                return rval;
 
@@ -1464,6 +1485,23 @@ int
 qla24xx_bsg_request(struct fc_bsg_job *bsg_job)
 {
        int ret = -EINVAL;
+       struct fc_rport *rport;
+       fc_port_t *fcport = NULL;
+       struct Scsi_Host *host;
+       scsi_qla_host_t *vha;
+
+       if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
+               rport = bsg_job->rport;
+               fcport = *(fc_port_t **) rport->dd_data;
+               host = rport_to_shost(rport);
+               vha = shost_priv(host);
+       } else {
+               host = bsg_job->shost;
+               vha = shost_priv(host);
+       }
+
+       ql_dbg(ql_dbg_user, vha, 0x7000,
+           "Entered %s msgcode=%d.\n", __func__, bsg_job->request->msgcode);
 
        switch (bsg_job->request->msgcode) {
        case FC_BSG_RPT_ELS:
@@ -1480,7 +1518,7 @@ qla24xx_bsg_request(struct fc_bsg_job *bsg_job)
        case FC_BSG_HST_DEL_RPORT:
        case FC_BSG_RPT_CT:
        default:
-               DEBUG2(printk("qla2xxx: unsupported BSG request\n"));
+               ql_log(ql_log_warn, vha, 0x705a, "Unsupported BSG request.\n");
                break;
        }
        return ret;
@@ -1514,17 +1552,15 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
                                        && (sp_bsg->u.bsg_job == bsg_job)) {
                                        spin_unlock_irqrestore(&ha->hardware_lock, flags);
                                        if (ha->isp_ops->abort_command(sp)) {
-                                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                                   "scsi(%ld): mbx "
-                                                   "abort_command failed\n",
-                                                   vha->host_no));
+                                               ql_log(ql_log_warn, vha, 0x7089,
+                                                   "mbx abort_command "
+                                                   "failed.\n");
                                                bsg_job->req->errors =
                                                bsg_job->reply->result = -EIO;
                                        } else {
-                                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                                   "scsi(%ld): mbx "
-                                                   "abort_command success\n",
-                                                   vha->host_no));
+                                               ql_dbg(ql_dbg_user, vha, 0x708a,
+                                                   "mbx abort_command "
+                                                   "success.\n");
                                                bsg_job->req->errors =
                                                bsg_job->reply->result = 0;
                                        }
@@ -1535,8 +1571,7 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
                }
        }
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       DEBUG2(qla_printk(KERN_INFO, ha,
-               "scsi(%ld) SRB not found to abort\n", vha->host_no));
+       ql_log(ql_log_info, vha, 0x708b, "SRB not found to abort.\n");
        bsg_job->req->errors = bsg_job->reply->result = -ENXIO;
        return 0;
 
index c53719a9a74740a37feeda2302a47375c8bb7614..2155071f3100a0489f39164bdb58b559deb74c1e 100644 (file)
@@ -4,10 +4,36 @@
  *
  * See LICENSE.qla2xxx for copyright and licensing details.
  */
+
+/*
+ * Table for showing the current message id in use for particular level
+ * Change this table for addition of log/debug messages.
+ * -----------------------------------------------------
+ * |             Level            |   Last Value Used  |
+ * -----------------------------------------------------
+ * | Module Init and Probe        |       0x0116       |
+ * | Mailbox commands             |       0x111e       |
+ * | Device Discovery             |       0x2083       |
+ * | Queue Command and IO tracing |       0x302e       |
+ * | DPC Thread                   |       0x401c       |
+ * | Async Events                 |       0x5059       |
+ * | Timer Routines               |       0x600d       |
+ * | User Space Interactions      |       0x709c       |
+ * | Task Management              |       0x8043       |
+ * | AER/EEH                      |       0x900f       |
+ * | Virtual Port                 |       0xa007       |
+ * | ISP82XX Specific             |       0xb027       |
+ * | MultiQ                       |       0xc00b       |
+ * | Misc                         |       0xd00b       |
+ * -----------------------------------------------------
+ */
+
 #include "qla_def.h"
 
 #include <linux/delay.h>
 
+static uint32_t ql_dbg_offset = 0x800;
+
 static inline void
 qla2xxx_prep_dump(struct qla_hw_data *ha, struct qla2xxx_fw_dump *fw_dump)
 {
@@ -383,11 +409,11 @@ qla2xxx_dump_post_process(scsi_qla_host_t *vha, int rval)
        struct qla_hw_data *ha = vha->hw;
 
        if (rval != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
-                   "Failed to dump firmware (%x)!!!\n", rval);
+               ql_log(ql_log_warn, vha, 0xd000,
+                   "Failed to dump firmware (%x).\n", rval);
                ha->fw_dumped = 0;
        } else {
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0xd001,
                    "Firmware dump saved to temp buffer (%ld/%p).\n",
                    vha->host_no, ha->fw_dump);
                ha->fw_dumped = 1;
@@ -419,15 +445,16 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&ha->hardware_lock, flags);
 
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "No buffer available for dump!!!\n");
+               ql_log(ql_log_warn, vha, 0xd002,
+                   "No buffer available for dump.\n");
                goto qla2300_fw_dump_failed;
        }
 
        if (ha->fw_dumped) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware has been previously dumped (%p) -- ignoring "
-                   "request...\n", ha->fw_dump);
+               ql_log(ql_log_warn, vha, 0xd003,
+                   "Firmware has been previously dumped (%p) "
+                   "-- ignoring request.\n",
+                   ha->fw_dump);
                goto qla2300_fw_dump_failed;
        }
        fw = &ha->fw_dump->isp.isp23;
@@ -582,15 +609,16 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&ha->hardware_lock, flags);
 
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "No buffer available for dump!!!\n");
+               ql_log(ql_log_warn, vha, 0xd004,
+                   "No buffer available for dump.\n");
                goto qla2100_fw_dump_failed;
        }
 
        if (ha->fw_dumped) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware has been previously dumped (%p) -- ignoring "
-                   "request...\n", ha->fw_dump);
+               ql_log(ql_log_warn, vha, 0xd005,
+                   "Firmware has been previously dumped (%p) "
+                   "-- ignoring request.\n",
+                   ha->fw_dump);
                goto qla2100_fw_dump_failed;
        }
        fw = &ha->fw_dump->isp.isp21;
@@ -779,15 +807,16 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&ha->hardware_lock, flags);
 
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "No buffer available for dump!!!\n");
+               ql_log(ql_log_warn, vha, 0xd006,
+                   "No buffer available for dump.\n");
                goto qla24xx_fw_dump_failed;
        }
 
        if (ha->fw_dumped) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware has been previously dumped (%p) -- ignoring "
-                   "request...\n", ha->fw_dump);
+               ql_log(ql_log_warn, vha, 0xd007,
+                   "Firmware has been previously dumped (%p) "
+                   "-- ignoring request.\n",
+                   ha->fw_dump);
                goto qla24xx_fw_dump_failed;
        }
        fw = &ha->fw_dump->isp.isp24;
@@ -1017,15 +1046,16 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&ha->hardware_lock, flags);
 
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "No buffer available for dump!!!\n");
+               ql_log(ql_log_warn, vha, 0xd008,
+                   "No buffer available for dump.\n");
                goto qla25xx_fw_dump_failed;
        }
 
        if (ha->fw_dumped) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware has been previously dumped (%p) -- ignoring "
-                   "request...\n", ha->fw_dump);
+               ql_log(ql_log_warn, vha, 0xd009,
+                   "Firmware has been previously dumped (%p) "
+                   "-- ignoring request.\n",
+                   ha->fw_dump);
                goto qla25xx_fw_dump_failed;
        }
        fw = &ha->fw_dump->isp.isp25;
@@ -1328,15 +1358,16 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
                spin_lock_irqsave(&ha->hardware_lock, flags);
 
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "No buffer available for dump!!!\n");
+               ql_log(ql_log_warn, vha, 0xd00a,
+                   "No buffer available for dump.\n");
                goto qla81xx_fw_dump_failed;
        }
 
        if (ha->fw_dumped) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware has been previously dumped (%p) -- ignoring "
-                   "request...\n", ha->fw_dump);
+               ql_log(ql_log_warn, vha, 0xd00b,
+                   "Firmware has been previously dumped (%p) "
+                   "-- ignoring request.\n",
+                   ha->fw_dump);
                goto qla81xx_fw_dump_failed;
        }
        fw = &ha->fw_dump->isp.isp81;
@@ -1619,106 +1650,255 @@ qla81xx_fw_dump_failed:
 /****************************************************************************/
 /*                         Driver Debug Functions.                          */
 /****************************************************************************/
-
+/*
+ * This function is for formatting and logging debug information.
+ * It is to be used when vha is available. It formats the message
+ * and logs it to the messages file.
+ * parameters:
+ * level: The level of the debug messages to be printed.
+ *        If ql2xextended_error_logging value is correctly set,
+ *        this message will appear in the messages file.
+ * vha:   Pointer to the scsi_qla_host_t.
+ * id:    This is a unique identifier for the level. It identifies the
+ *        part of the code from where the message originated.
+ * msg:   The message to be displayed.
+ */
 void
-qla2x00_dump_regs(scsi_qla_host_t *vha)
-{
-       int i;
-       struct qla_hw_data *ha = vha->hw;
-       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-       struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
-       uint16_t __iomem *mbx_reg;
+ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, char *msg, ...) {
+
+       char pbuf[QL_DBG_BUF_LEN];
+       va_list ap;
+       uint32_t len;
+       struct pci_dev *pdev = NULL;
+
+       memset(pbuf, 0, QL_DBG_BUF_LEN);
+
+       va_start(ap, msg);
+
+       if ((level & ql2xextended_error_logging) == level) {
+               if (vha != NULL) {
+                       pdev = vha->hw->pdev;
+                       /* <module-name> <pci-name> <msg-id>:<host> Message */
+                       sprintf(pbuf, "%s [%s]-%04x:%ld: ", QL_MSGHDR,
+                           dev_name(&(pdev->dev)), id + ql_dbg_offset,
+                           vha->host_no);
+               } else
+                       sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR,
+                           "0000:00:00.0", id + ql_dbg_offset);
+
+               len = strlen(pbuf);
+               vsprintf(pbuf+len, msg, ap);
+               pr_warning("%s", pbuf);
+       }
 
-       mbx_reg = IS_FWI2_CAPABLE(ha) ? &reg24->mailbox0:
-           MAILBOX_REG(ha, reg, 0);
+       va_end(ap);
 
-       printk("Mailbox registers:\n");
-       for (i = 0; i < 6; i++)
-               printk("scsi(%ld): mbox %d 0x%04x \n", vha->host_no, i,
-                   RD_REG_WORD(mbx_reg++));
 }
 
-
+/*
+ * This function is for formatting and logging debug information.
+ * It is to be used when vha is not available and pci is availble,
+ * i.e., before host allocation. It formats the message and logs it
+ * to the messages file.
+ * parameters:
+ * level: The level of the debug messages to be printed.
+ *        If ql2xextended_error_logging value is correctly set,
+ *        this message will appear in the messages file.
+ * pdev:  Pointer to the struct pci_dev.
+ * id:    This is a unique id for the level. It identifies the part
+ *        of the code from where the message originated.
+ * msg:   The message to be displayed.
+ */
 void
-qla2x00_dump_buffer(uint8_t * b, uint32_t size)
-{
-       uint32_t cnt;
-       uint8_t c;
+ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id, char *msg, ...) {
 
-       printk(" 0   1   2   3   4   5   6   7   8   9  "
-           "Ah  Bh  Ch  Dh  Eh  Fh\n");
-       printk("----------------------------------------"
-           "----------------------\n");
-
-       for (cnt = 0; cnt < size;) {
-               c = *b++;
-               printk("%02x",(uint32_t) c);
-               cnt++;
-               if (!(cnt % 16))
-                       printk("\n");
-               else
-                       printk("  ");
+       char pbuf[QL_DBG_BUF_LEN];
+       va_list ap;
+       uint32_t len;
+
+       if (pdev == NULL)
+               return;
+
+       memset(pbuf, 0, QL_DBG_BUF_LEN);
+
+       va_start(ap, msg);
+
+       if ((level & ql2xextended_error_logging) == level) {
+               /* <module-name> <dev-name>:<msg-id> Message */
+               sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR,
+                   dev_name(&(pdev->dev)), id + ql_dbg_offset);
+
+               len = strlen(pbuf);
+               vsprintf(pbuf+len, msg, ap);
+               pr_warning("%s", pbuf);
        }
-       if (cnt % 16)
-               printk("\n");
+
+       va_end(ap);
+
 }
 
+/*
+ * This function is for formatting and logging log messages.
+ * It is to be used when vha is available. It formats the message
+ * and logs it to the messages file. All the messages will be logged
+ * irrespective of value of ql2xextended_error_logging.
+ * parameters:
+ * level: The level of the log messages to be printed in the
+ *        messages file.
+ * vha:   Pointer to the scsi_qla_host_t
+ * id:    This is a unique id for the level. It identifies the
+ *        part of the code from where the message originated.
+ * msg:   The message to be displayed.
+ */
 void
-qla2x00_dump_buffer_zipped(uint8_t *b, uint32_t size)
-{
-       uint32_t cnt;
-       uint8_t c;
-       uint8_t  last16[16], cur16[16];
-       uint32_t lc = 0, num_same16 = 0, j;
+ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, char *msg, ...) {
 
-       printk(KERN_DEBUG " 0   1   2   3   4   5   6   7   8   9  "
-           "Ah  Bh  Ch  Dh  Eh  Fh\n");
-       printk(KERN_DEBUG "----------------------------------------"
-           "----------------------\n");
+       char pbuf[QL_DBG_BUF_LEN];
+       va_list ap;
+       uint32_t len;
+       struct pci_dev *pdev = NULL;
 
-       for (cnt = 0; cnt < size;) {
-               c = *b++;
+       memset(pbuf, 0, QL_DBG_BUF_LEN);
 
-               cur16[lc++] = c;
+       va_start(ap, msg);
 
-               cnt++;
-               if (cnt % 16)
-                       continue;
-
-               /* We have 16 now */
-               lc = 0;
-               if (num_same16 == 0) {
-                       memcpy(last16, cur16, 16);
-                       num_same16++;
-                       continue;
+       if (level <= ql_errlev) {
+               if (vha != NULL) {
+                       pdev = vha->hw->pdev;
+                       /* <module-name> <msg-id>:<host> Message */
+                       sprintf(pbuf, "%s [%s]-%04x:%ld: ", QL_MSGHDR,
+                           dev_name(&(pdev->dev)), id, vha->host_no);
+               } else
+                       sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR,
+                           "0000:00:00.0", id);
+
+               len = strlen(pbuf);
+                       vsprintf(pbuf+len, msg, ap);
+
+               switch (level) {
+               case 0: /* FATAL LOG */
+                       pr_crit("%s", pbuf);
+                       break;
+               case 1:
+                       pr_err("%s", pbuf);
+                       break;
+               case 2:
+                       pr_warn("%s", pbuf);
+                       break;
+               default:
+                       pr_info("%s", pbuf);
+                       break;
                }
-               if (memcmp(cur16, last16, 16) == 0) {
-                       num_same16++;
-                       continue;
+       }
+
+       va_end(ap);
+}
+
+/*
+ * This function is for formatting and logging log messages.
+ * It is to be used when vha is not available and pci is availble,
+ * i.e., before host allocation. It formats the message and logs
+ * it to the messages file. All the messages are logged irrespective
+ * of the value of ql2xextended_error_logging.
+ * parameters:
+ * level: The level of the log messages to be printed in the
+ *        messages file.
+ * pdev:  Pointer to the struct pci_dev.
+ * id:    This is a unique id for the level. It identifies the
+ *        part of the code from where the message originated.
+ * msg:   The message to be displayed.
+ */
+void
+ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id, char *msg, ...) {
+
+       char pbuf[QL_DBG_BUF_LEN];
+       va_list ap;
+       uint32_t len;
+
+       if (pdev == NULL)
+               return;
+
+       memset(pbuf, 0, QL_DBG_BUF_LEN);
+
+       va_start(ap, msg);
+
+       if (level <= ql_errlev) {
+               /* <module-name> <dev-name>:<msg-id> Message */
+               sprintf(pbuf, "%s [%s]-%04x: : ", QL_MSGHDR,
+                   dev_name(&(pdev->dev)), id);
+
+               len = strlen(pbuf);
+               vsprintf(pbuf+len, msg, ap);
+               switch (level) {
+               case 0: /* FATAL LOG */
+                       pr_crit("%s", pbuf);
+                       break;
+               case 1:
+                       pr_err("%s", pbuf);
+                       break;
+               case 2:
+                       pr_warn("%s", pbuf);
+                       break;
+               default:
+                       pr_info("%s", pbuf);
+                       break;
                }
-               for (j = 0; j < 16; j++)
-                       printk(KERN_DEBUG "%02x  ", (uint32_t)last16[j]);
-               printk(KERN_DEBUG "\n");
-
-               if (num_same16 > 1)
-                       printk(KERN_DEBUG "> prev pattern repeats (%u)"
-                           "more times\n", num_same16-1);
-               memcpy(last16, cur16, 16);
-               num_same16 = 1;
        }
 
-       if (num_same16) {
-               for (j = 0; j < 16; j++)
-                       printk(KERN_DEBUG "%02x  ", (uint32_t)last16[j]);
-               printk(KERN_DEBUG "\n");
+       va_end(ap);
+}
 
-               if (num_same16 > 1)
-                       printk(KERN_DEBUG "> prev pattern repeats (%u)"
-                           "more times\n", num_same16-1);
+void
+ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id)
+{
+       int i;
+       struct qla_hw_data *ha = vha->hw;
+       struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+       struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+       struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
+       uint16_t __iomem *mbx_reg;
+
+       if ((level & ql2xextended_error_logging) == level) {
+
+               if (IS_QLA82XX(ha))
+                       mbx_reg = &reg82->mailbox_in[0];
+               else if (IS_FWI2_CAPABLE(ha))
+                       mbx_reg = &reg24->mailbox0;
+               else
+                       mbx_reg = MAILBOX_REG(ha, reg, 0);
+
+               ql_dbg(level, vha, id, "Mailbox registers:\n");
+               for (i = 0; i < 6; i++)
+                       ql_dbg(level, vha, id,
+                           "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg++));
        }
-       if (lc) {
-               for (j = 0; j < lc; j++)
-                       printk(KERN_DEBUG "%02x  ", (uint32_t)cur16[j]);
-               printk(KERN_DEBUG "\n");
+}
+
+
+void
+ql_dump_buffer(uint32_t level, scsi_qla_host_t *vha, int32_t id,
+       uint8_t *b, uint32_t size)
+{
+       uint32_t cnt;
+       uint8_t c;
+       if ((level & ql2xextended_error_logging) == level) {
+
+               ql_dbg(level, vha, id, " 0   1   2   3   4   5   6   7   8   "
+                   "9  Ah  Bh  Ch  Dh  Eh  Fh\n");
+               ql_dbg(level, vha, id, "----------------------------------"
+                   "----------------------------\n");
+
+               ql_dbg(level, vha, id, "");
+               for (cnt = 0; cnt < size;) {
+                       c = *b++;
+                       printk("%02x", (uint32_t) c);
+                       cnt++;
+                       if (!(cnt % 16))
+                               printk("\n");
+                       else
+                               printk("  ");
+               }
+               if (cnt % 16)
+                       ql_dbg(level, vha, id, "\n");
        }
 }
index 930414541ec600daf9d8fe4a56a3b3323602c88d..98a377b990173503fcdc2c982f4ad68bb3efc222 100644 (file)
@@ -7,146 +7,6 @@
 
 #include "qla_def.h"
 
-/*
- * Driver debug definitions.
- */
-/* #define QL_DEBUG_LEVEL_1  */ /* Output register accesses to COM1 */
-/* #define QL_DEBUG_LEVEL_2  */ /* Output error msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_3  */ /* Output function trace msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_4  */ /* Output NVRAM trace msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_5  */ /* Output ring trace msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_6  */ /* Output WATCHDOG timer trace to COM1 */
-/* #define QL_DEBUG_LEVEL_7  */ /* Output RISC load trace msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_8  */ /* Output ring saturation msgs to COM1 */
-/* #define QL_DEBUG_LEVEL_9  */ /* Output IOCTL trace msgs */
-/* #define QL_DEBUG_LEVEL_10 */ /* Output IOCTL error msgs */
-/* #define QL_DEBUG_LEVEL_11 */ /* Output Mbx Cmd trace msgs */
-/* #define QL_DEBUG_LEVEL_12 */ /* Output IP trace msgs */
-/* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */
-/* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */
-/* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */
-/* #define QL_DEBUG_LEVEL_16 */ /* Output ISP84XX trace msgs */
-/* #define QL_DEBUG_LEVEL_17 */ /* Output EEH trace messages */
-/* #define QL_DEBUG_LEVEL_18 */ /* Output T10 CRC trace messages */
-
-/*
-* Macros use for debugging the driver.
-*/
-
-#define DEBUG(x)       do { if (ql2xextended_error_logging) { x; } } while (0)
-
-#if defined(QL_DEBUG_LEVEL_1)
-#define DEBUG1(x)      do {x;} while (0)
-#else
-#define DEBUG1(x)      do {} while (0)
-#endif
-
-#define DEBUG2(x)      do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_3(x)    do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_3_11(x) do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_9_10(x) do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_11(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_13(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_16(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
-#define DEBUG2_17(x)   do { if (ql2xextended_error_logging) { x; } } while (0)
-
-#if defined(QL_DEBUG_LEVEL_3)
-#define DEBUG3(x)      do {x;} while (0)
-#define DEBUG3_11(x)   do {x;} while (0)
-#else
-#define DEBUG3(x)      do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_4)
-#define DEBUG4(x)      do {x;} while (0)
-#else
-#define DEBUG4(x)      do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_5)
-#define DEBUG5(x)          do {x;} while (0)
-#else
-#define DEBUG5(x)      do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_7)
-#define DEBUG7(x)          do {x;} while (0)
-#else
-#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)
-#else
-#define DEBUG9(x)      do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_10)
-#define DEBUG10(x)      do {x;} while (0)
-#define DEBUG9_10(x)   do {x;} while (0)
-#else
-#define DEBUG10(x)     do {} while (0)
-  #if !defined(DEBUG9_10)
-  #define DEBUG9_10(x) do {} while (0)
-  #endif
-#endif
-
-#if defined(QL_DEBUG_LEVEL_11)
-#define DEBUG11(x)      do{x;} while(0)
-#if !defined(DEBUG3_11)
-#define DEBUG3_11(x)    do{x;} while(0)
-#endif
-#else
-#define DEBUG11(x)     do{} while(0)
-  #if !defined(QL_DEBUG_LEVEL_3)
-  #define DEBUG3_11(x) do{} while(0)
-  #endif
-#endif
-
-#if defined(QL_DEBUG_LEVEL_12)
-#define DEBUG12(x)      do {x;} while (0)
-#else
-#define DEBUG12(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_13)
-#define DEBUG13(x)      do {x;} while (0)
-#else
-#define DEBUG13(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_14)
-#define DEBUG14(x)      do {x;} while (0)
-#else
-#define DEBUG14(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_15)
-#define DEBUG15(x)      do {x;} while (0)
-#else
-#define DEBUG15(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_16)
-#define DEBUG16(x)     do {x;} while (0)
-#else
-#define DEBUG16(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_17)
-#define DEBUG17(x)     do {x;} while (0)
-#else
-#define DEBUG17(x)     do {} while (0)
-#endif
-
-#if defined(QL_DEBUG_LEVEL_18)
-#define DEBUG18(x)     do {if (ql2xextended_error_logging) x; } while (0)
-#else
-#define DEBUG18(x)     do {} while (0)
-#endif
-
-
 /*
  * Firmware Dump structure definition
  */
@@ -370,3 +230,50 @@ struct qla2xxx_fw_dump {
                struct qla81xx_fw_dump isp81;
        } isp;
 };
+
+#define QL_MSGHDR "qla2xxx"
+
+#define ql_log_fatal           0 /* display fatal errors */
+#define ql_log_warn            1 /* display critical errors */
+#define ql_log_info            2 /* display all recovered errors */
+#define ql_log_all             3 /* This value is only used by ql_errlev.
+                                  * No messages will use this value.
+                                  * This should be always highest value
+                                  * as compared to other log levels.
+                                  */
+
+extern int ql_errlev;
+
+void
+ql_dbg(uint32_t, scsi_qla_host_t *vha, int32_t, char *, ...);
+void
+ql_dbg_pci(uint32_t, struct pci_dev *pdev, int32_t, char *, ...);
+
+void
+ql_log(uint32_t, scsi_qla_host_t *vha, int32_t, char *, ...);
+void
+ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, char *, ...);
+
+/* Debug Levels */
+/* The 0x40000000 is the max value any debug level can have
+ * as ql2xextended_error_logging is of type signed int
+ */
+#define ql_dbg_init    0x40000000 /* Init Debug */
+#define ql_dbg_mbx     0x20000000 /* MBX Debug */
+#define ql_dbg_disc    0x10000000 /* Device Discovery Debug */
+#define ql_dbg_io      0x08000000 /* IO Tracing Debug */
+#define ql_dbg_dpc     0x04000000 /* DPC Thead Debug */
+#define ql_dbg_async   0x02000000 /* Async events Debug */
+#define ql_dbg_timer   0x01000000 /* Timer Debug */
+#define ql_dbg_user    0x00800000 /* User Space Interations Debug */
+#define ql_dbg_taskm   0x00400000 /* Task Management Debug */
+#define ql_dbg_aer     0x00200000 /* AER/EEH Debug */
+#define ql_dbg_multiq  0x00100000 /* MultiQ Debug */
+#define ql_dbg_p3p     0x00080000 /* P3P specific Debug */
+#define ql_dbg_vport   0x00040000 /* Virtual Port Debug */
+#define ql_dbg_buffer  0x00020000 /* For dumping the buffer/regs */
+#define ql_dbg_misc    0x00010000 /* For dumping everything that is not
+                                   * not covered by upper categories
+                                   */
+
+#define QL_DBG_BUF_LEN 512
index a5a4e1275bf2cd32532dd2949a7197c7f0a2f194..0b4c2b794c6f281629fb59540f8d013e76b55694 100644 (file)
@@ -64,7 +64,7 @@ qla2x00_dfs_fce_open(struct inode *inode, struct file *file)
        /* Pause tracing to flush FCE buffers. */
        rval = qla2x00_disable_fce_trace(vha, &ha->fce_wr, &ha->fce_rd);
        if (rval)
-               qla_printk(KERN_WARNING, ha,
+               ql_dbg(ql_dbg_user, vha, 0x705c,
                    "DebugFS: Unable to disable FCE (%d).\n", rval);
 
        ha->flags.fce_enabled = 0;
@@ -92,7 +92,7 @@ qla2x00_dfs_fce_release(struct inode *inode, struct file *file)
        rval = qla2x00_enable_fce_trace(vha, ha->fce_dma, ha->fce_bufs,
            ha->fce_mb, &ha->fce_bufs);
        if (rval) {
-               qla_printk(KERN_WARNING, ha,
+               ql_dbg(ql_dbg_user, vha, 0x700d,
                    "DebugFS: Unable to reinitialize FCE (%d).\n", rval);
                ha->flags.fce_enabled = 0;
        }
@@ -125,8 +125,8 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha)
        atomic_set(&qla2x00_dfs_root_count, 0);
        qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL);
        if (!qla2x00_dfs_root) {
-               qla_printk(KERN_NOTICE, ha,
-                   "DebugFS: Unable to create root directory.\n");
+               ql_log(ql_log_warn, vha, 0x00f7,
+                   "Unable to create debugfs root directory.\n");
                goto out;
        }
 
@@ -137,8 +137,8 @@ create_dir:
        mutex_init(&ha->fce_mutex);
        ha->dfs_dir = debugfs_create_dir(vha->host_str, qla2x00_dfs_root);
        if (!ha->dfs_dir) {
-               qla_printk(KERN_NOTICE, ha,
-                   "DebugFS: Unable to create ha directory.\n");
+               ql_log(ql_log_warn, vha, 0x00f8,
+                   "Unable to create debugfs ha directory.\n");
                goto out;
        }
 
@@ -148,8 +148,8 @@ create_nodes:
        ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
            &dfs_fce_ops);
        if (!ha->dfs_fce) {
-               qla_printk(KERN_NOTICE, ha,
-                   "DebugFS: Unable to fce node.\n");
+               ql_log(ql_log_warn, vha, 0x00f9,
+                   "Unable to create debugfs fce node.\n");
                goto out;
        }
 out:
index 0b381224ae4b86e0f575dbd53d6b60254b805f98..29b1a3e282318b80164241f61c2b5f8be1a33b60 100644 (file)
@@ -185,7 +185,7 @@ extern int qla24xx_start_scsi(srb_t *sp);
 int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
                                                uint16_t, uint16_t, uint8_t);
 extern int qla2x00_start_sp(srb_t *);
-extern uint16_t qla24xx_calc_iocbs(uint16_t);
+extern uint16_t qla24xx_calc_iocbs(scsi_qla_host_t *, uint16_t);
 extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t);
 extern int qla24xx_dif_start_scsi(srb_t *);
 
@@ -439,6 +439,9 @@ extern void qla81xx_fw_dump(scsi_qla_host_t *, int);
 extern void qla2x00_dump_regs(scsi_qla_host_t *);
 extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
 extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);
+extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t);
+extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t,
+       uint8_t *, uint32_t);
 
 /*
  * Global Function Prototypes in qla_gs.c source file.
@@ -478,7 +481,8 @@ extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16
 extern int qla2x00_echo_test(scsi_qla_host_t *,
        struct msg_echo_lb *, uint16_t *);
 extern int qla24xx_update_all_fcp_prio(scsi_qla_host_t *);
-extern int qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *, uint8_t);
+extern int qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *,
+       struct qla_fcp_prio_cfg *, uint8_t);
 
 /*
  * Global Function Prototypes in qla_dfs.c source file.
index 8cd9066ad90663e676a2a97d878cb644aeb0c47e..37937aa3c3b8dc46a150137547314c5eeaadff9c 100644 (file)
@@ -121,11 +121,10 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
 
        rval = QLA_FUNCTION_FAILED;
        if (ms_pkt->entry_status != 0) {
-               DEBUG2_3(printk(KERN_WARNING "scsi(%ld): %s failed, error status "
-                   "(%x) on port_id: %02x%02x%02x.\n",
-                   vha->host_no, routine, ms_pkt->entry_status,
-                   vha->d_id.b.domain, vha->d_id.b.area,
-                   vha->d_id.b.al_pa));
+               ql_dbg(ql_dbg_disc, vha, 0x2031,
+                   "%s failed, error status (%x) on port_id: %02x%02x%02x.\n",
+                   routine, ms_pkt->entry_status, vha->d_id.b.domain,
+                   vha->d_id.b.area, vha->d_id.b.al_pa);
        } else {
                if (IS_FWI2_CAPABLE(ha))
                        comp_status = le16_to_cpu(
@@ -138,24 +137,24 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
                case CS_DATA_OVERRUN:           /* Overrun? */
                        if (ct_rsp->header.response !=
                            __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
-                               DEBUG2_3(printk("scsi(%ld): %s failed, "
-                                   "rejected request on port_id: %02x%02x%02x\n",
-                                   vha->host_no, routine,
+                               ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2077,
+                                   "%s failed rejected request on port_id: "
+                                   "%02x%02x%02x.\n", routine,
                                    vha->d_id.b.domain, vha->d_id.b.area,
-                                   vha->d_id.b.al_pa));
-                               DEBUG2_3(qla2x00_dump_buffer(
-                                   (uint8_t *)&ct_rsp->header,
-                                   sizeof(struct ct_rsp_hdr)));
+                                   vha->d_id.b.al_pa);
+                               ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha,
+                                   0x2078, (uint8_t *)&ct_rsp->header,
+                                   sizeof(struct ct_rsp_hdr));
                                rval = QLA_INVALID_COMMAND;
                        } else
                                rval = QLA_SUCCESS;
                        break;
                default:
-                       DEBUG2_3(printk("scsi(%ld): %s failed, completion "
-                           "status (%x) on port_id: %02x%02x%02x.\n",
-                           vha->host_no, routine, comp_status,
+                       ql_dbg(ql_dbg_disc, vha, 0x2033,
+                           "%s failed, completion status (%x) on port_id: "
+                           "%02x%02x%02x.\n", routine, comp_status,
                            vha->d_id.b.domain, vha->d_id.b.area,
-                           vha->d_id.b.al_pa));
+                           vha->d_id.b.al_pa);
                        break;
                }
        }
@@ -202,8 +201,8 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): GA_NXT issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2062,
+                   "GA_NXT issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "GA_NXT") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
@@ -222,11 +221,10 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
                    ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE)
                        fcport->d_id.b.domain = 0xf0;
 
-               DEBUG2_3(printk("scsi(%ld): GA_NXT entry - "
-                   "nn %02x%02x%02x%02x%02x%02x%02x%02x "
+               ql_dbg(ql_dbg_disc, vha, 0x2063,
+                   "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
                    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
-                   "portid=%02x%02x%02x.\n",
-                   vha->host_no,
+                   "port_id=%02x%02x%02x.\n",
                    fcport->node_name[0], fcport->node_name[1],
                    fcport->node_name[2], fcport->node_name[3],
                    fcport->node_name[4], fcport->node_name[5],
@@ -236,7 +234,7 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
                    fcport->port_name[4], fcport->port_name[5],
                    fcport->port_name[6], fcport->port_name[7],
                    fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa));
+                   fcport->d_id.b.al_pa);
        }
 
        return (rval);
@@ -287,8 +285,8 @@ qla2x00_gid_pt(scsi_qla_host_t *vha, sw_info_t *list)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): GID_PT issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2055,
+                   "GID_PT issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "GID_PT") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
@@ -364,8 +362,8 @@ qla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    sizeof(ms_iocb_entry_t));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GPN_ID issue IOCB failed "
-                           "(%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x2056,
+                           "GPN_ID issue IOCB failed (%d).\n", rval);
                } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
                    "GPN_ID") != QLA_SUCCESS) {
                        rval = QLA_FUNCTION_FAILED;
@@ -424,8 +422,8 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    sizeof(ms_iocb_entry_t));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GNN_ID issue IOCB failed "
-                           "(%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x2057,
+                           "GNN_ID issue IOCB failed (%d).\n", rval);
                } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
                    "GNN_ID") != QLA_SUCCESS) {
                        rval = QLA_FUNCTION_FAILED;
@@ -434,11 +432,10 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                        memcpy(list[i].node_name,
                            ct_rsp->rsp.gnn_id.node_name, WWN_SIZE);
 
-                       DEBUG2_3(printk("scsi(%ld): GID_PT entry - "
-                           "nn %02x%02x%02x%02x%02x%02x%02x%02x "
-                           "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+                       ql_dbg(ql_dbg_disc, vha, 0x2058,
+                           "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02X%02x "
+                           "pn %02x%02x%02x%02x%02x%02x%02X%02x "
                            "portid=%02x%02x%02x.\n",
-                           vha->host_no,
                            list[i].node_name[0], list[i].node_name[1],
                            list[i].node_name[2], list[i].node_name[3],
                            list[i].node_name[4], list[i].node_name[5],
@@ -448,7 +445,7 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                            list[i].port_name[4], list[i].port_name[5],
                            list[i].port_name[6], list[i].port_name[7],
                            list[i].d_id.b.domain, list[i].d_id.b.area,
-                           list[i].d_id.b.al_pa));
+                           list[i].d_id.b.al_pa);
                }
 
                /* Last device exit. */
@@ -499,14 +496,14 @@ qla2x00_rft_id(scsi_qla_host_t *vha)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RFT_ID issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2043,
+                   "RFT_ID issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RFT_ID") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RFT_ID exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2044,
+                   "RFT_ID exiting normally.\n");
        }
 
        return (rval);
@@ -528,8 +525,8 @@ qla2x00_rff_id(scsi_qla_host_t *vha)
        struct ct_sns_rsp       *ct_rsp;
 
        if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
-               DEBUG2(printk("scsi(%ld): RFF_ID call unsupported on "
-                   "ISP2100/ISP2200.\n", vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2046,
+                   "RFF_ID call not supported on ISP2100/ISP2200.\n");
                return (QLA_SUCCESS);
        }
 
@@ -556,14 +553,14 @@ qla2x00_rff_id(scsi_qla_host_t *vha)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RFF_ID issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2047,
+                   "RFF_ID issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RFF_ID") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RFF_ID exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2048,
+                   "RFF_ID exiting normally.\n");
        }
 
        return (rval);
@@ -609,14 +606,14 @@ qla2x00_rnn_id(scsi_qla_host_t *vha)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RNN_ID issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x204d,
+                   "RNN_ID issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RNN_ID") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RNN_ID exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x204e,
+                   "RNN_ID exiting normally.\n");
        }
 
        return (rval);
@@ -647,8 +644,8 @@ qla2x00_rsnn_nn(scsi_qla_host_t *vha)
        struct ct_sns_rsp       *ct_rsp;
 
        if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
-               DEBUG2(printk("scsi(%ld): RSNN_ID call unsupported on "
-                   "ISP2100/ISP2200.\n", vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2050,
+                   "RSNN_ID call unsupported on ISP2100/ISP2200.\n");
                return (QLA_SUCCESS);
        }
 
@@ -682,14 +679,14 @@ qla2x00_rsnn_nn(scsi_qla_host_t *vha)
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RSNN_NN issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2051,
+                   "RSNN_NN issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RSNN_NN") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RSNN_NN exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2052,
+                   "RSNN_NN exiting normally.\n");
        }
 
        return (rval);
@@ -757,13 +754,14 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
            sizeof(struct sns_cmd_pkt));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): GA_NXT Send SNS failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x205f,
+                   "GA_NXT Send SNS failed (%d).\n", rval);
        } else if (sns_cmd->p.gan_data[8] != 0x80 ||
            sns_cmd->p.gan_data[9] != 0x02) {
-               DEBUG2_3(printk("scsi(%ld): GA_NXT failed, rejected request, "
-                   "ga_nxt_rsp:\n", vha->host_no));
-               DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gan_data, 16));
+               ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207d,
+                   "GA_NXT failed, rejected request ga_nxt_rsp:\n");
+               ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2074,
+                   sns_cmd->p.gan_data, 16);
                rval = QLA_FUNCTION_FAILED;
        } else {
                /* Populate fc_port_t entry. */
@@ -778,11 +776,10 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
                    sns_cmd->p.gan_data[16] != NS_NL_PORT_TYPE)
                        fcport->d_id.b.domain = 0xf0;
 
-               DEBUG2_3(printk("scsi(%ld): GA_NXT entry - "
-                   "nn %02x%02x%02x%02x%02x%02x%02x%02x "
+               ql_dbg(ql_dbg_disc, vha, 0x2061,
+                   "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
                    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
-                   "portid=%02x%02x%02x.\n",
-                   vha->host_no,
+                   "port_id=%02x%02x%02x.\n",
                    fcport->node_name[0], fcport->node_name[1],
                    fcport->node_name[2], fcport->node_name[3],
                    fcport->node_name[4], fcport->node_name[5],
@@ -792,7 +789,7 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
                    fcport->port_name[4], fcport->port_name[5],
                    fcport->port_name[6], fcport->port_name[7],
                    fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa));
+                   fcport->d_id.b.al_pa);
        }
 
        return (rval);
@@ -831,13 +828,14 @@ qla2x00_sns_gid_pt(scsi_qla_host_t *vha, sw_info_t *list)
            sizeof(struct sns_cmd_pkt));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): GID_PT Send SNS failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x206d,
+                   "GID_PT Send SNS failed (%d).\n", rval);
        } else if (sns_cmd->p.gid_data[8] != 0x80 ||
            sns_cmd->p.gid_data[9] != 0x02) {
-               DEBUG2_3(printk("scsi(%ld): GID_PT failed, rejected request, "
-                   "gid_rsp:\n", vha->host_no));
-               DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gid_data, 16));
+               ql_dbg(ql_dbg_disc, vha, 0x202f,
+                   "GID_PT failed, rejected request, gid_rsp:\n");
+               ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2081,
+                   sns_cmd->p.gid_data, 16);
                rval = QLA_FUNCTION_FAILED;
        } else {
                /* Set port IDs in switch info list. */
@@ -900,13 +898,14 @@ qla2x00_sns_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    GPN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GPN_ID Send SNS failed "
-                           "(%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x2032,
+                           "GPN_ID Send SNS failed (%d).\n", rval);
                } else if (sns_cmd->p.gpn_data[8] != 0x80 ||
                    sns_cmd->p.gpn_data[9] != 0x02) {
-                       DEBUG2_3(printk("scsi(%ld): GPN_ID failed, rejected "
-                           "request, gpn_rsp:\n", vha->host_no));
-                       DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gpn_data, 16));
+                       ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207e,
+                           "GPN_ID failed, rejected request, gpn_rsp:\n");
+                       ql_dump_buffer(ql_dbg_disc, vha, 0x207f,
+                           sns_cmd->p.gpn_data, 16);
                        rval = QLA_FUNCTION_FAILED;
                } else {
                        /* Save portname */
@@ -955,24 +954,24 @@ qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    GNN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GNN_ID Send SNS failed "
-                           "(%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x203f,
+                           "GNN_ID Send SNS failed (%d).\n", rval);
                } else if (sns_cmd->p.gnn_data[8] != 0x80 ||
                    sns_cmd->p.gnn_data[9] != 0x02) {
-                       DEBUG2_3(printk("scsi(%ld): GNN_ID failed, rejected "
-                           "request, gnn_rsp:\n", vha->host_no));
-                       DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gnn_data, 16));
+                       ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2082,
+                           "GNN_ID failed, rejected request, gnn_rsp:\n");
+                       ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207a,
+                           sns_cmd->p.gnn_data, 16);
                        rval = QLA_FUNCTION_FAILED;
                } else {
                        /* Save nodename */
                        memcpy(list[i].node_name, &sns_cmd->p.gnn_data[16],
                            WWN_SIZE);
 
-                       DEBUG2_3(printk("scsi(%ld): GID_PT entry - "
-                           "nn %02x%02x%02x%02x%02x%02x%02x%02x "
+                       ql_dbg(ql_dbg_disc, vha, 0x206e,
+                           "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
                            "pn %02x%02x%02x%02x%02x%02x%02x%02x "
-                           "portid=%02x%02x%02x.\n",
-                           vha->host_no,
+                           "port_id=%02x%02x%02x.\n",
                            list[i].node_name[0], list[i].node_name[1],
                            list[i].node_name[2], list[i].node_name[3],
                            list[i].node_name[4], list[i].node_name[5],
@@ -982,7 +981,7 @@ qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
                            list[i].port_name[4], list[i].port_name[5],
                            list[i].port_name[6], list[i].port_name[7],
                            list[i].d_id.b.domain, list[i].d_id.b.area,
-                           list[i].d_id.b.al_pa));
+                           list[i].d_id.b.al_pa);
                }
 
                /* Last device exit. */
@@ -1025,17 +1024,18 @@ qla2x00_sns_rft_id(scsi_qla_host_t *vha)
            sizeof(struct sns_cmd_pkt));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RFT_ID Send SNS failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2060,
+                   "RFT_ID Send SNS failed (%d).\n", rval);
        } else if (sns_cmd->p.rft_data[8] != 0x80 ||
            sns_cmd->p.rft_data[9] != 0x02) {
-               DEBUG2_3(printk("scsi(%ld): RFT_ID failed, rejected request, "
-                   "rft_rsp:\n", vha->host_no));
-               DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.rft_data, 16));
+               ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2083,
+                   "RFT_ID failed, rejected request rft_rsp:\n");
+               ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2080,
+                   sns_cmd->p.rft_data, 16);
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RFT_ID exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2073,
+                   "RFT_ID exiting normally.\n");
        }
 
        return (rval);
@@ -1081,17 +1081,18 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *vha)
            sizeof(struct sns_cmd_pkt));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RNN_ID Send SNS failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x204a,
+                   "RNN_ID Send SNS failed (%d).\n", rval);
        } else if (sns_cmd->p.rnn_data[8] != 0x80 ||
            sns_cmd->p.rnn_data[9] != 0x02) {
-               DEBUG2_3(printk("scsi(%ld): RNN_ID failed, rejected request, "
-                   "rnn_rsp:\n", vha->host_no));
-               DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.rnn_data, 16));
+               ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207b,
+                   "RNN_ID failed, rejected request, rnn_rsp:\n");
+               ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207c,
+                   sns_cmd->p.rnn_data, 16);
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RNN_ID exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x204c,
+                   "RNN_ID exiting normally.\n");
        }
 
        return (rval);
@@ -1116,10 +1117,10 @@ qla2x00_mgmt_svr_login(scsi_qla_host_t *vha)
        ha->isp_ops->fabric_login(vha, vha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
            mb, BIT_1|BIT_0);
        if (mb[0] != MBS_COMMAND_COMPLETE) {
-               DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: "
-                   "loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x\n",
-                   __func__, vha->host_no, vha->mgmt_svr_loop_id, mb[0], mb[1],
-                   mb[2], mb[6], mb[7]));
+               ql_dbg(ql_dbg_disc, vha, 0x2024,
+                   "Failed management_server login: loopid=%x mb[0]=%x "
+                   "mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x.\n",
+                   vha->mgmt_svr_loop_id, mb[0], mb[1], mb[2], mb[6], mb[7]);
                ret = QLA_FUNCTION_FAILED;
        } else
                vha->flags.management_server_logged_in = 1;
@@ -1292,11 +1293,12 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE);
        size += 4 + WWN_SIZE;
 
-       DEBUG13(printk("%s(%ld): NODENAME=%02x%02x%02x%02x%02x%02x%02x%02x.\n",
-           __func__, vha->host_no,
-           eiter->a.node_name[0], eiter->a.node_name[1], eiter->a.node_name[2],
-           eiter->a.node_name[3], eiter->a.node_name[4], eiter->a.node_name[5],
-           eiter->a.node_name[6], eiter->a.node_name[7]));
+       ql_dbg(ql_dbg_disc, vha, 0x2025,
+           "NodeName = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
+           eiter->a.node_name[0], eiter->a.node_name[1],
+           eiter->a.node_name[2], eiter->a.node_name[3],
+           eiter->a.node_name[4], eiter->a.node_name[5],
+           eiter->a.node_name[6], eiter->a.node_name[7]);
 
        /* Manufacturer. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1307,8 +1309,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): MANUFACTURER=%s.\n", __func__, vha->host_no,
-           eiter->a.manufacturer));
+       ql_dbg(ql_dbg_disc, vha, 0x2026,
+           "Manufacturer = %s.\n", eiter->a.manufacturer);
 
        /* Serial number. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1320,8 +1322,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): SERIALNO=%s.\n", __func__, vha->host_no,
-           eiter->a.serial_num));
+       ql_dbg(ql_dbg_disc, vha, 0x2027,
+           "Serial no. = %s.\n", eiter->a.serial_num);
 
        /* Model name. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1332,8 +1334,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): MODEL_NAME=%s.\n", __func__, vha->host_no,
-           eiter->a.model));
+       ql_dbg(ql_dbg_disc, vha, 0x2028,
+           "Model Name = %s.\n", eiter->a.model);
 
        /* Model description. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1345,8 +1347,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): MODEL_DESC=%s.\n", __func__, vha->host_no,
-           eiter->a.model_desc));
+       ql_dbg(ql_dbg_disc, vha, 0x2029,
+           "Model Desc = %s.\n", eiter->a.model_desc);
 
        /* Hardware version. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1357,8 +1359,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): HARDWAREVER=%s.\n", __func__, vha->host_no,
-           eiter->a.hw_version));
+       ql_dbg(ql_dbg_disc, vha, 0x202a,
+           "Hardware ver = %s.\n", eiter->a.hw_version);
 
        /* Driver version. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1369,8 +1371,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): DRIVERVER=%s.\n", __func__, vha->host_no,
-           eiter->a.driver_version));
+       ql_dbg(ql_dbg_disc, vha, 0x202b,
+           "Driver ver = %s.\n", eiter->a.driver_version);
 
        /* Option ROM version. */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1381,8 +1383,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): OPTROMVER=%s.\n", __func__, vha->host_no,
-           eiter->a.orom_version));
+       ql_dbg(ql_dbg_disc, vha , 0x202c,
+           "Optrom vers = %s.\n", eiter->a.orom_version);
 
        /* Firmware version */
        eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1393,44 +1395,46 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): FIRMWAREVER=%s.\n", __func__, vha->host_no,
-           eiter->a.fw_version));
+       ql_dbg(ql_dbg_disc, vha, 0x202d,
+           "Firmware vers = %s.\n", eiter->a.fw_version);
 
        /* Update MS request size. */
        qla2x00_update_ms_fdmi_iocb(vha, size + 16);
 
-       DEBUG13(printk("%s(%ld): RHBA identifier="
-           "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__,
-           vha->host_no, ct_req->req.rhba.hba_identifier[0],
+       ql_dbg(ql_dbg_disc, vha, 0x202e,
+           "RHBA identifier = "
+           "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n",
+           ct_req->req.rhba.hba_identifier[0],
            ct_req->req.rhba.hba_identifier[1],
            ct_req->req.rhba.hba_identifier[2],
            ct_req->req.rhba.hba_identifier[3],
            ct_req->req.rhba.hba_identifier[4],
            ct_req->req.rhba.hba_identifier[5],
            ct_req->req.rhba.hba_identifier[6],
-           ct_req->req.rhba.hba_identifier[7], size));
-       DEBUG13(qla2x00_dump_buffer(entries, size));
+           ct_req->req.rhba.hba_identifier[7], size);
+       ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2076,
+           entries, size);
 
        /* Execute MS IOCB */
        rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RHBA issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2030,
+                   "RHBA issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
                if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM &&
                    ct_rsp->header.explanation_code ==
                    CT_EXPL_ALREADY_REGISTERED) {
-                       DEBUG2_13(printk("%s(%ld): HBA already registered.\n",
-                           __func__, vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x2034,
+                           "HBA already registered.\n");
                        rval = QLA_ALREADY_REGISTERED;
                }
        } else {
-               DEBUG2(printk("scsi(%ld): RHBA exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2035,
+                   "RHBA exiting normally.\n");
        }
 
        return rval;
@@ -1464,26 +1468,26 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha)
        /* Prepare FDMI command arguments -- portname. */
        memcpy(ct_req->req.dhba.port_name, vha->port_name, WWN_SIZE);
 
-       DEBUG13(printk("%s(%ld): DHBA portname="
-           "%02x%02x%02x%02x%02x%02x%02x%02x.\n", __func__, vha->host_no,
+       ql_dbg(ql_dbg_disc, vha, 0x2036,
+           "DHBA portname = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
            ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1],
            ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3],
            ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5],
-           ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]));
+           ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]);
 
        /* Execute MS IOCB */
        rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): DHBA issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2037,
+                   "DHBA issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "DHBA") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): DHBA exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2038,
+                   "DHBA exiting normally.\n");
        }
 
        return rval;
@@ -1534,9 +1538,10 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
        eiter->a.fc4_types[2] = 0x01;
        size += 4 + 32;
 
-       DEBUG13(printk("%s(%ld): FC4_TYPES=%02x %02x.\n", __func__,
-               vha->host_no, eiter->a.fc4_types[2],
-               eiter->a.fc4_types[1]));
+       ql_dbg(ql_dbg_disc, vha, 0x2039,
+           "FC4_TYPES=%02x %02x.\n",
+           eiter->a.fc4_types[2],
+           eiter->a.fc4_types[1]);
 
        /* Supported speed. */
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
@@ -1561,8 +1566,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
                    FDMI_PORT_SPEED_1GB);
        size += 4 + 4;
 
-       DEBUG13(printk("%s(%ld): SUPPORTED_SPEED=%x.\n", __func__, vha->host_no,
-           eiter->a.sup_speed));
+       ql_dbg(ql_dbg_disc, vha, 0x203a,
+           "Supported_Speed=%x.\n", eiter->a.sup_speed);
 
        /* Current speed. */
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
@@ -1596,8 +1601,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
        }
        size += 4 + 4;
 
-       DEBUG13(printk("%s(%ld): CURRENT_SPEED=%x.\n", __func__, vha->host_no,
-           eiter->a.cur_speed));
+       ql_dbg(ql_dbg_disc, vha, 0x203b,
+           "Current_Speed=%x.\n", eiter->a.cur_speed);
 
        /* Max frame size. */
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
@@ -1609,8 +1614,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
        eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
        size += 4 + 4;
 
-       DEBUG13(printk("%s(%ld): MAX_FRAME_SIZE=%x.\n", __func__, vha->host_no,
-           eiter->a.max_frame_size));
+       ql_dbg(ql_dbg_disc, vha, 0x203c,
+           "Max_Frame_Size=%x.\n", eiter->a.max_frame_size);
 
        /* OS device name. */
        eiter = (struct ct_fdmi_port_attr *) (entries + size);
@@ -1621,8 +1626,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
        eiter->len = cpu_to_be16(4 + alen);
        size += 4 + alen;
 
-       DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, vha->host_no,
-           eiter->a.os_dev_name));
+       ql_dbg(ql_dbg_disc, vha, 0x204b,
+           "OS_Device_Name=%s.\n", eiter->a.os_dev_name);
 
        /* Hostname. */
        if (strlen(fc_host_system_hostname(vha->host))) {
@@ -1637,35 +1642,36 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
                eiter->len = cpu_to_be16(4 + alen);
                size += 4 + alen;
 
-               DEBUG13(printk("%s(%ld): HOSTNAME=%s.\n", __func__,
-                   vha->host_no, eiter->a.host_name));
+               ql_dbg(ql_dbg_disc, vha, 0x203d,
+                   "HostName=%s.\n", eiter->a.host_name);
        }
 
        /* Update MS request size. */
        qla2x00_update_ms_fdmi_iocb(vha, size + 16);
 
-       DEBUG13(printk("%s(%ld): RPA portname="
-           "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__,
-           vha->host_no, ct_req->req.rpa.port_name[0],
-           ct_req->req.rpa.port_name[1], ct_req->req.rpa.port_name[2],
-           ct_req->req.rpa.port_name[3], ct_req->req.rpa.port_name[4],
-           ct_req->req.rpa.port_name[5], ct_req->req.rpa.port_name[6],
-           ct_req->req.rpa.port_name[7], size));
-       DEBUG13(qla2x00_dump_buffer(entries, size));
+       ql_dbg(ql_dbg_disc, vha, 0x203e,
+           "RPA portname= %02x%02x%02x%02x%02X%02x%02x%02x size=%d.\n",
+           ct_req->req.rpa.port_name[0], ct_req->req.rpa.port_name[1],
+           ct_req->req.rpa.port_name[2], ct_req->req.rpa.port_name[3],
+           ct_req->req.rpa.port_name[4], ct_req->req.rpa.port_name[5],
+           ct_req->req.rpa.port_name[6], ct_req->req.rpa.port_name[7],
+           size);
+       ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2079,
+           entries, size);
 
        /* Execute MS IOCB */
        rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
            sizeof(ms_iocb_entry_t));
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3(printk("scsi(%ld): RPA issue IOCB failed (%d).\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2040,
+                   "RPA issue IOCB failed (%d).\n", rval);
        } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA") !=
            QLA_SUCCESS) {
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("scsi(%ld): RPA exiting normally.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2041,
+                   "RPA exiting nornally.\n");
        }
 
        return rval;
@@ -1749,8 +1755,8 @@ qla2x00_gfpn_id(scsi_qla_host_t *vha, sw_info_t *list)
                    sizeof(ms_iocb_entry_t));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GFPN_ID issue IOCB "
-                           "failed (%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x2023,
+                           "GFPN_ID issue IOCB failed (%d).\n", rval);
                } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
                    "GFPN_ID") != QLA_SUCCESS) {
                        rval = QLA_FUNCTION_FAILED;
@@ -1860,8 +1866,8 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
                    sizeof(ms_iocb_entry_t));
                if (rval != QLA_SUCCESS) {
                        /*EMPTY*/
-                       DEBUG2_3(printk("scsi(%ld): GPSC issue IOCB "
-                           "failed (%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x2059,
+                           "GPSC issue IOCB failed (%d).\n", rval);
                } else if ((rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
                    "GPSC")) != QLA_SUCCESS) {
                        /* FM command unsupported? */
@@ -1870,9 +1876,9 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
                                CT_REASON_INVALID_COMMAND_CODE ||
                             ct_rsp->header.reason_code ==
                                CT_REASON_COMMAND_UNSUPPORTED)) {
-                               DEBUG2(printk("scsi(%ld): GPSC command "
-                                   "unsupported, disabling query...\n",
-                                   vha->host_no));
+                               ql_dbg(ql_dbg_disc, vha, 0x205a,
+                                   "GPSC command unsupported, disabling "
+                                   "query.\n");
                                ha->flags.gpsc_supported = 0;
                                rval = QLA_FUNCTION_FAILED;
                                break;
@@ -1898,9 +1904,10 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
                                break;
                        }
 
-                       DEBUG2_3(printk("scsi(%ld): GPSC ext entry - "
-                           "fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
-                           "speed=%04x.\n", vha->host_no,
+                       ql_dbg(ql_dbg_disc, vha, 0x205b,
+                           "GPSC ext entry - fpn "
+                           "%02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
+                           "speed=%04x.\n",
                            list[i].fabric_port_name[0],
                            list[i].fabric_port_name[1],
                            list[i].fabric_port_name[2],
@@ -1910,7 +1917,7 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
                            list[i].fabric_port_name[6],
                            list[i].fabric_port_name[7],
                            be16_to_cpu(ct_rsp->rsp.gpsc.speeds),
-                           be16_to_cpu(ct_rsp->rsp.gpsc.speed)));
+                           be16_to_cpu(ct_rsp->rsp.gpsc.speed));
                }
 
                /* Last device exit. */
@@ -1968,14 +1975,12 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
                   sizeof(ms_iocb_entry_t));
 
                if (rval != QLA_SUCCESS) {
-                       DEBUG2_3(printk(KERN_INFO
-                           "scsi(%ld): GFF_ID issue IOCB failed "
-                           "(%d).\n", vha->host_no, rval));
+                       ql_dbg(ql_dbg_disc, vha, 0x205c,
+                           "GFF_ID issue IOCB failed (%d).\n", rval);
                } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
                               "GFF_ID") != QLA_SUCCESS) {
-                       DEBUG2_3(printk(KERN_INFO
-                           "scsi(%ld): GFF_ID IOCB status had a "
-                           "failure status code\n", vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x205d,
+                           "GFF_ID IOCB status had a failure status code.\n");
                } else {
                        fcp_scsi_features =
                           ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
index 920b76bfbb932e6329f735fa42ebb28013355fca..def694271bf79bf96cb6190878434b902381fb79 100644 (file)
@@ -153,11 +153,10 @@ qla2x00_async_iocb_timeout(srb_t *sp)
        fc_port_t *fcport = sp->fcport;
        struct srb_ctx *ctx = sp->ctx;
 
-       DEBUG2(printk(KERN_WARNING
-               "scsi(%ld:%x): Async-%s timeout - portid=%02x%02x%02x.\n",
-               fcport->vha->host_no, sp->handle,
-               ctx->name, fcport->d_id.b.domain,
-               fcport->d_id.b.area, fcport->d_id.b.al_pa));
+       ql_dbg(ql_dbg_disc, fcport->vha, 0x2071,
+           "Async-%s timeout - portid=%02x%02x%02x.\n",
+           ctx->name, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa);
 
        fcport->flags &= ~FCF_ASYNC_SENT;
        if (ctx->type == SRB_LOGIN_CMD) {
@@ -211,11 +210,10 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
 
-       DEBUG2(printk(KERN_DEBUG
-           "scsi(%ld:%x): Async-login - loop-id=%x portid=%02x%02x%02x "
-           "retries=%d.\n", fcport->vha->host_no, sp->handle, fcport->loop_id,
-           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
-           fcport->login_retry));
+       ql_dbg(ql_dbg_disc, vha, 0x2072,
+           "Async-login - loopid=%x portid=%02x%02x%02x retries=%d.\n",
+           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa, fcport->login_retry);
        return rval;
 
 done_free_sp:
@@ -259,10 +257,10 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
 
-       DEBUG2(printk(KERN_DEBUG
-           "scsi(%ld:%x): Async-logout - loop-id=%x portid=%02x%02x%02x.\n",
-           fcport->vha->host_no, sp->handle, fcport->loop_id,
-           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
+       ql_dbg(ql_dbg_disc, vha, 0x2070,
+           "Async-logout - loop-id=%x portid=%02x%02x%02x.\n",
+           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa);
        return rval;
 
 done_free_sp:
@@ -309,11 +307,10 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
 
-       DEBUG2(printk(KERN_DEBUG
-           "scsi(%ld:%x): Async-adisc - loop-id=%x portid=%02x%02x%02x.\n",
-           fcport->vha->host_no, sp->handle, fcport->loop_id,
-           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
-
+       ql_dbg(ql_dbg_disc, vha, 0x206f,
+           "Async-adisc - loopid=%x portid=%02x%02x%02x.\n",
+           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa);
        return rval;
 
 done_free_sp:
@@ -362,11 +359,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
 
-       DEBUG2(printk(KERN_DEBUG
-           "scsi(%ld:%x): Async-tmf - loop-id=%x portid=%02x%02x%02x.\n",
-           fcport->vha->host_no, sp->handle, fcport->loop_id,
-           fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
-
+       ql_dbg(ql_dbg_taskm, vha, 0x802f,
+           "Async-tmf loop-id=%x portid=%02x%02x%02x.\n",
+           fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+           fcport->d_id.b.al_pa);
        return rval;
 
 done_free_sp:
@@ -471,9 +467,8 @@ qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport,
                flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
 
        if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                       "%s(%ld): TM IOCB failed (%x).\n",
-                       __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_taskm, vha, 0x8030,
+                   "TM IOCB failed (%x).\n", rval);
        }
 
        return;
@@ -519,11 +514,12 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
        set_bit(0, ha->req_qid_map);
        set_bit(0, ha->rsp_qid_map);
 
-       qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
+       ql_log(ql_log_info, vha, 0x0040,
+           "Configuring PCI space...\n");
        rval = ha->isp_ops->pci_config(vha);
        if (rval) {
-               DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
-                   vha->host_no));
+               ql_log(ql_log_warn, vha, 0x0044,
+                   "Unable to configure PCI space.\n");
                return (rval);
        }
 
@@ -531,20 +527,21 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
 
        rval = qla2xxx_get_flash_info(vha);
        if (rval) {
-               DEBUG2(printk("scsi(%ld): Unable to validate FLASH data.\n",
-                   vha->host_no));
+               ql_log(ql_log_fatal, vha, 0x004f,
+                   "Unable to validate FLASH data.\n");
                return (rval);
        }
 
        ha->isp_ops->get_flash_version(vha, req->ring);
-
-       qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
+       ql_log(ql_log_info, vha, 0x0061,
+           "Configure NVRAM parameters...\n");
 
        ha->isp_ops->nvram_config(vha);
 
        if (ha->flags.disable_serdes) {
                /* Mask HBA via NVRAM settings? */
-               qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
+               ql_log(ql_log_info, vha, 0x0077,
+                   "Masking HBA WWPN "
                    "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
                    vha->port_name[0], vha->port_name[1],
                    vha->port_name[2], vha->port_name[3],
@@ -553,7 +550,8 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
                return QLA_FUNCTION_FAILED;
        }
 
-       qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
+       ql_log(ql_log_info, vha, 0x0078,
+           "Verifying loaded RISC code...\n");
 
        if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) {
                rval = ha->isp_ops->chip_diag(vha);
@@ -567,7 +565,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
        if (IS_QLA84XX(ha)) {
                ha->cs84xx = qla84xx_get_chip(vha);
                if (!ha->cs84xx) {
-                       qla_printk(KERN_ERR, ha,
+                       ql_log(ql_log_warn, vha, 0x00d0,
                            "Unable to configure ISP84XX.\n");
                        return QLA_FUNCTION_FAILED;
                }
@@ -579,8 +577,8 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
                /* Issue verify 84xx FW IOCB to complete 84xx initialization */
                rval = qla84xx_init_chip(vha);
                if (rval != QLA_SUCCESS) {
-                       qla_printk(KERN_ERR, ha,
-                               "Unable to initialize ISP84XX.\n");
+                       ql_log(ql_log_warn, vha, 0x00d4,
+                           "Unable to initialize ISP84XX.\n");
                qla84xx_put_chip(vha);
                }
        }
@@ -797,9 +795,7 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha)
        rval = QLA_FUNCTION_FAILED;
 
        if (ha->flags.disable_risc_code_load) {
-               DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n",
-                   vha->host_no));
-               qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n");
+               ql_log(ql_log_info, vha, 0x0079, "RISC CODE NOT loaded.\n");
 
                /* Verify checksum of loaded RISC code. */
                rval = qla2x00_verify_checksum(vha, ha->fw_srisc_address);
@@ -810,10 +806,9 @@ qla2x00_isp_firmware(scsi_qla_host_t *vha)
                }
        }
 
-       if (rval) {
-               DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n",
-                   vha->host_no));
-       }
+       if (rval)
+               ql_dbg(ql_dbg_init, vha, 0x007a,
+                   "**** Load RISC code ****.\n");
 
        return (rval);
 }
@@ -1105,8 +1100,8 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
        /* Assume a failed state */
        rval = QLA_FUNCTION_FAILED;
 
-       DEBUG3(printk("scsi(%ld): Testing device at %lx.\n",
-           vha->host_no, (u_long)&reg->flash_address));
+       ql_dbg(ql_dbg_init, vha, 0x007b,
+           "Testing device at %lx.\n", (u_long)&reg->flash_address);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
@@ -1128,8 +1123,8 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
        if (!cnt)
                goto chip_diag_failed;
 
-       DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_init, vha, 0x007c,
+           "Reset register cleared by chip reset.\n");
 
        /* Reset RISC processor. */
        WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
@@ -1150,7 +1145,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
                goto chip_diag_failed;
 
        /* Check product ID of chip */
-       DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", vha->host_no));
+       ql_dbg(ql_dbg_init, vha, 0x007d, "Checking product Id of chip.\n");
 
        mb[1] = RD_MAILBOX_REG(ha, reg, 1);
        mb[2] = RD_MAILBOX_REG(ha, reg, 2);
@@ -1158,8 +1153,9 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
        mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
        if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
            mb[3] != PROD_ID_3) {
-               qla_printk(KERN_WARNING, ha,
-                   "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]);
+               ql_log(ql_log_warn, vha, 0x0062,
+                   "Wrong product ID = 0x%x,0x%x,0x%x.\n",
+                   mb[1], mb[2], mb[3]);
 
                goto chip_diag_failed;
        }
@@ -1178,8 +1174,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
        if (IS_QLA2200(ha) &&
            RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
                /* Limit firmware transfer size with a 2200A */
-               DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_init, vha, 0x007e, "Found QLA2200A Chip.\n");
 
                ha->device_type |= DT_ISP2200A;
                ha->fw_transfer_size = 128;
@@ -1188,24 +1183,20 @@ qla2x00_chip_diag(scsi_qla_host_t *vha)
        /* Wrap Incoming Mailboxes Test. */
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", vha->host_no));
+       ql_dbg(ql_dbg_init, vha, 0x007f, "Checking mailboxes.\n");
        rval = qla2x00_mbx_reg_test(vha);
-       if (rval) {
-               DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
-                   vha->host_no));
-               qla_printk(KERN_WARNING, ha,
-                   "Failed mailbox send register test\n");
-       }
-       else {
+       if (rval)
+               ql_log(ql_log_warn, vha, 0x0080,
+                   "Failed mailbox send register test.\n");
+       else
                /* Flag a successful rval */
                rval = QLA_SUCCESS;
-       }
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
 chip_diag_failed:
        if (rval)
-               DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED "
-                   "****\n", vha->host_no));
+               ql_log(ql_log_info, vha, 0x0081,
+                   "Chip diagnostics **** FAILED ****.\n");
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
@@ -1232,10 +1223,8 @@ qla24xx_chip_diag(scsi_qla_host_t *vha)
 
        rval = qla2x00_mbx_reg_test(vha);
        if (rval) {
-               DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
-                   vha->host_no));
-               qla_printk(KERN_WARNING, ha,
-                   "Failed mailbox send register test\n");
+               ql_log(ql_log_warn, vha, 0x0082,
+                   "Failed mailbox send register test.\n");
        } else {
                /* Flag a successful rval */
                rval = QLA_SUCCESS;
@@ -1257,8 +1246,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
        struct rsp_que *rsp = ha->rsp_q_map[0];
 
        if (ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware dump previously allocated.\n");
+               ql_dbg(ql_dbg_init, vha, 0x00bd,
+                   "Firmware dump already allocated.\n");
                return;
        }
 
@@ -1288,8 +1277,9 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
                tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
                    GFP_KERNEL);
                if (!tc) {
-                       qla_printk(KERN_WARNING, ha, "Unable to allocate "
-                           "(%d KB) for FCE.\n", FCE_SIZE / 1024);
+                       ql_log(ql_log_warn, vha, 0x00be,
+                           "Unable to allocate (%d KB) for FCE.\n",
+                           FCE_SIZE / 1024);
                        goto try_eft;
                }
 
@@ -1297,16 +1287,15 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
                rval = qla2x00_enable_fce_trace(vha, tc_dma, FCE_NUM_BUFFERS,
                    ha->fce_mb, &ha->fce_bufs);
                if (rval) {
-                       qla_printk(KERN_WARNING, ha, "Unable to initialize "
-                           "FCE (%d).\n", rval);
+                       ql_log(ql_log_warn, vha, 0x00bf,
+                           "Unable to initialize FCE (%d).\n", rval);
                        dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
                            tc_dma);
                        ha->flags.fce_enabled = 0;
                        goto try_eft;
                }
-
-               qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
-                   FCE_SIZE / 1024);
+               ql_log(ql_log_info, vha, 0x00c0,
+                   "Allocate (%d KB) for FCE...\n", FCE_SIZE / 1024);
 
                fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
                ha->flags.fce_enabled = 1;
@@ -1317,23 +1306,23 @@ try_eft:
                tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
                    GFP_KERNEL);
                if (!tc) {
-                       qla_printk(KERN_WARNING, ha, "Unable to allocate "
-                           "(%d KB) for EFT.\n", EFT_SIZE / 1024);
+                       ql_log(ql_log_warn, vha, 0x00c1,
+                           "Unable to allocate (%d KB) for EFT.\n",
+                           EFT_SIZE / 1024);
                        goto cont_alloc;
                }
 
                memset(tc, 0, EFT_SIZE);
                rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS);
                if (rval) {
-                       qla_printk(KERN_WARNING, ha, "Unable to initialize "
-                           "EFT (%d).\n", rval);
+                       ql_log(ql_log_warn, vha, 0x00c2,
+                           "Unable to initialize EFT (%d).\n", rval);
                        dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
                            tc_dma);
                        goto cont_alloc;
                }
-
-               qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
-                   EFT_SIZE / 1024);
+               ql_log(ql_log_info, vha, 0x00c3,
+                   "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024);
 
                eft_size = EFT_SIZE;
                ha->eft_dma = tc_dma;
@@ -1350,8 +1339,9 @@ cont_alloc:
 
        ha->fw_dump = vmalloc(dump_size);
        if (!ha->fw_dump) {
-               qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
-                   "firmware dump!!!\n", dump_size / 1024);
+               ql_log(ql_log_warn, vha, 0x00c4,
+                   "Unable to allocate (%d KB) for firmware dump.\n",
+                   dump_size / 1024);
 
                if (ha->fce) {
                        dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
@@ -1368,8 +1358,8 @@ cont_alloc:
                }
                return;
        }
-       qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n",
-           dump_size / 1024);
+       ql_log(ql_log_info, vha, 0x00c5,
+           "Allocated (%d KB) for firmware dump.\n", dump_size / 1024);
 
        ha->fw_dump_len = dump_size;
        ha->fw_dump->signature[0] = 'Q';
@@ -1398,23 +1388,21 @@ qla81xx_mpi_sync(scsi_qla_host_t *vha)
        int rval;
        uint16_t dc;
        uint32_t dw;
-       struct qla_hw_data *ha = vha->hw;
 
        if (!IS_QLA81XX(vha->hw))
                return QLA_SUCCESS;
 
        rval = qla2x00_write_ram_word(vha, 0x7c00, 1);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "Sync-MPI: Unable to acquire semaphore.\n"));
+               ql_log(ql_log_warn, vha, 0x0105,
+                   "Unable to acquire semaphore.\n");
                goto done;
        }
 
        pci_read_config_word(vha->hw->pdev, 0x54, &dc);
        rval = qla2x00_read_ram_word(vha, 0x7a15, &dw);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "Sync-MPI: Unable to read sync.\n"));
+               ql_log(ql_log_warn, vha, 0x0067, "Unable to read sync.\n");
                goto done_release;
        }
 
@@ -1426,15 +1414,14 @@ qla81xx_mpi_sync(scsi_qla_host_t *vha)
        dw |= dc;
        rval = qla2x00_write_ram_word(vha, 0x7a15, dw);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "Sync-MPI: Unable to gain sync.\n"));
+               ql_log(ql_log_warn, vha, 0x0114, "Unable to gain sync.\n");
        }
 
 done_release:
        rval = qla2x00_write_ram_word(vha, 0x7c00, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "Sync-MPI: Unable to release semaphore.\n"));
+               ql_log(ql_log_warn, vha, 0x006d,
+                   "Unable to release semaphore.\n");
        }
 
 done:
@@ -1479,14 +1466,14 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
        /* Load firmware sequences */
        rval = ha->isp_ops->load_risc(vha, &srisc_address);
        if (rval == QLA_SUCCESS) {
-               DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
-                   "code.\n", vha->host_no));
+               ql_dbg(ql_dbg_init, vha, 0x00c9,
+                   "Verifying Checksum of loaded RISC code.\n");
 
                rval = qla2x00_verify_checksum(vha, srisc_address);
                if (rval == QLA_SUCCESS) {
                        /* Start firmware execution. */
-                       DEBUG(printk("scsi(%ld): Checksum OK, start "
-                           "firmware.\n", vha->host_no));
+                       ql_dbg(ql_dbg_init, vha, 0x00ca,
+                           "Starting firmware.\n");
 
                        rval = qla2x00_execute_fw(vha, srisc_address);
                        /* Retrieve firmware information. */
@@ -1522,9 +1509,9 @@ enable_82xx_npiv:
                                }
                        }
                } else {
-                       DEBUG2(printk(KERN_INFO
-                           "scsi(%ld): ISP Firmware failed checksum.\n",
-                           vha->host_no));
+                       ql_log(ql_log_fatal, vha, 0x00cd,
+                           "ISP Firmware failed checksum.\n");
+                       goto failed;
                }
        }
 
@@ -1549,7 +1536,7 @@ enable_82xx_npiv:
                        ha->flags.fac_supported = 1;
                        ha->fdt_block_size = size << 2;
                } else {
-                       qla_printk(KERN_ERR, ha,
+                       ql_log(ql_log_warn, vha, 0x00ce,
                            "Unsupported FAC firmware (%d.%02d.%02d).\n",
                            ha->fw_major_version, ha->fw_minor_version,
                            ha->fw_subminor_version);
@@ -1557,8 +1544,8 @@ enable_82xx_npiv:
        }
 failed:
        if (rval) {
-               DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
-                   vha->host_no));
+               ql_log(ql_log_fatal, vha, 0x00cf,
+                   "Setup chip ****FAILED****.\n");
        }
 
        return (rval);
@@ -1608,10 +1595,11 @@ qla2x00_update_fw_options(scsi_qla_host_t *vha)
                return;
 
        /* Serial Link options. */
-       DEBUG3(printk("scsi(%ld): Serial link options:\n",
-           vha->host_no));
-       DEBUG3(qla2x00_dump_buffer((uint8_t *)&ha->fw_seriallink_options,
-           sizeof(ha->fw_seriallink_options)));
+       ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0115,
+           "Serial link options.\n");
+       ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0109,
+           (uint8_t *)&ha->fw_seriallink_options,
+           sizeof(ha->fw_seriallink_options));
 
        ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
        if (ha->fw_seriallink_options[3] & BIT_2) {
@@ -1688,7 +1676,7 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
            le16_to_cpu(ha->fw_seriallink_options24[2]),
            le16_to_cpu(ha->fw_seriallink_options24[3]));
        if (rval != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x0104,
                    "Unable to update Serial Link options (%x).\n", rval);
        }
 }
@@ -1746,8 +1734,9 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
                icb->rid = __constant_cpu_to_le16(rid);
                if (ha->flags.msix_enabled) {
                        msix = &ha->msix_entries[1];
-                       DEBUG2_17(printk(KERN_INFO
-                       "Registering vector 0x%x for base que\n", msix->entry));
+                       ql_dbg(ql_dbg_init, vha, 0x00fd,
+                           "Registering vector 0x%x for base que.\n",
+                           msix->entry);
                        icb->msix = cpu_to_le16(msix->entry);
                }
                /* Use alternate PCI bus number */
@@ -1764,8 +1753,8 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
                        icb->firmware_options_2 &=
                                __constant_cpu_to_le32(~BIT_22);
                        ha->flags.disable_msix_handshake = 1;
-                       qla_printk(KERN_INFO, ha,
-                               "MSIX Handshake Disable Mode turned on\n");
+                       ql_dbg(ql_dbg_init, vha, 0x00fe,
+                           "MSIX Handshake Disable Mode turned on.\n");
                } else {
                        icb->firmware_options_2 |=
                                __constant_cpu_to_le32(BIT_22);
@@ -1850,7 +1839,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
        /* Update any ISP specific firmware options before initialization. */
        ha->isp_ops->update_fw_options(vha);
 
-       DEBUG(printk("scsi(%ld): Issue init firmware.\n", vha->host_no));
+       ql_dbg(ql_dbg_init, vha, 0x00d1, "Issue init firmware.\n");
 
        if (ha->flags.npiv_supported) {
                if (ha->operating_mode == LOOP)
@@ -1866,11 +1855,11 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
 
        rval = qla2x00_init_firmware(vha, ha->init_cb_size);
        if (rval) {
-               DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
-                   vha->host_no));
+               ql_log(ql_log_fatal, vha, 0x00d2,
+                   "Init Firmware **** FAILED ****.\n");
        } else {
-               DEBUG3(printk("scsi(%ld): Init firmware -- success.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_init, vha, 0x00d3,
+                   "Init Firmware -- success.\n");
        }
 
        return (rval);
@@ -1913,10 +1902,8 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
 
        /* Wait for ISP to finish LIP */
        if (!vha->flags.init_done)
-               qla_printk(KERN_INFO, ha, "Waiting for LIP to complete...\n");
-
-       DEBUG3(printk("scsi(%ld): Waiting for LIP to complete...\n",
-           vha->host_no));
+               ql_log(ql_log_info, vha, 0x801e,
+                   "Waiting for LIP to complete.\n");
 
        do {
                rval = qla2x00_get_firmware_state(vha, state);
@@ -1925,30 +1912,35 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
                                vha->device_flags &= ~DFLG_NO_CABLE;
                        }
                        if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) {
-                               DEBUG16(printk("scsi(%ld): fw_state=%x "
-                                   "84xx=%x.\n", vha->host_no, state[0],
-                                   state[2]));
+                               ql_dbg(ql_dbg_taskm, vha, 0x801f,
+                                   "fw_state=%x 84xx=%x.\n", state[0],
+                                   state[2]);
                                if ((state[2] & FSTATE_LOGGED_IN) &&
                                     (state[2] & FSTATE_WAITING_FOR_VERIFY)) {
-                                       DEBUG16(printk("scsi(%ld): Sending "
-                                           "verify iocb.\n", vha->host_no));
+                                       ql_dbg(ql_dbg_taskm, vha, 0x8028,
+                                           "Sending verify iocb.\n");
 
                                        cs84xx_time = jiffies;
                                        rval = qla84xx_init_chip(vha);
-                                       if (rval != QLA_SUCCESS)
+                                       if (rval != QLA_SUCCESS) {
+                                               ql_log(ql_log_warn,
+                                                   vha, 0x8043,
+                                                   "Init chip failed.\n");
                                                break;
+                                       }
 
                                        /* Add time taken to initialize. */
                                        cs84xx_time = jiffies - cs84xx_time;
                                        wtime += cs84xx_time;
                                        mtime += cs84xx_time;
-                                       DEBUG16(printk("scsi(%ld): Increasing "
-                                           "wait time by %ld. New time %ld\n",
-                                           vha->host_no, cs84xx_time, wtime));
+                                       ql_dbg(ql_dbg_taskm, vha, 0x8042,
+                                           "Increasing wait time by %ld. "
+                                           "New time %ld.\n", cs84xx_time,
+                                           wtime);
                                }
                        } else if (state[0] == FSTATE_READY) {
-                               DEBUG(printk("scsi(%ld): F/W Ready - OK \n",
-                                   vha->host_no));
+                               ql_dbg(ql_dbg_taskm, vha, 0x8037,
+                                   "F/W Ready - OK.\n");
 
                                qla2x00_get_retry_cnt(vha, &ha->retry_count,
                                    &ha->login_timeout, &ha->r_a_tov);
@@ -1965,7 +1957,7 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
                                 * other than Wait for Login.
                                 */
                                if (time_after_eq(jiffies, mtime)) {
-                                       qla_printk(KERN_INFO, ha,
+                                       ql_log(ql_log_info, vha, 0x8038,
                                            "Cable is unplugged...\n");
 
                                        vha->device_flags |= DFLG_NO_CABLE;
@@ -1985,17 +1977,17 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
                /* Delay for a while */
                msleep(500);
 
-               DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
-                   vha->host_no, state[0], jiffies));
+               ql_dbg(ql_dbg_taskm, vha, 0x8039,
+                   "fw_state=%x curr time=%lx.\n", state[0], jiffies);
        } while (1);
 
-       DEBUG(printk("scsi(%ld): fw_state=%x (%x, %x, %x, %x) curr time=%lx.\n",
-           vha->host_no, state[0], state[1], state[2], state[3], state[4],
-           jiffies));
+       ql_dbg(ql_dbg_taskm, vha, 0x803a,
+           "fw_state=%x (%x, %x, %x, %x) " "curr time=%lx.\n", state[0],
+           state[1], state[2], state[3], state[4], jiffies);
 
        if (rval) {
-               DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
-                   vha->host_no));
+               ql_log(ql_log_warn, vha, 0x803b,
+                   "Firmware ready **** FAILED ****.\n");
        }
 
        return (rval);
@@ -2034,19 +2026,19 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
                if (LOOP_TRANSITION(vha) || atomic_read(&ha->loop_down_timer) ||
                    IS_QLA8XXX_TYPE(ha) ||
                    (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
-                       DEBUG2(printk("%s(%ld) Loop is in a transition state\n",
-                           __func__, vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x2008,
+                           "Loop is in a transition state.\n");
                } else {
-                       qla_printk(KERN_WARNING, ha,
-                           "ERROR -- Unable to get host loop ID.\n");
+                       ql_log(ql_log_warn, vha, 0x2009,
+                           "Unable to get host loop ID.\n");
                        set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                }
                return (rval);
        }
 
        if (topo == 4) {
-               qla_printk(KERN_INFO, ha,
-                       "Cannot get topology - retrying.\n");
+               ql_log(ql_log_info, vha, 0x200a,
+                   "Cannot get topology - retrying.\n");
                return (QLA_FUNCTION_FAILED);
        }
 
@@ -2059,31 +2051,27 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
 
        switch (topo) {
        case 0:
-               DEBUG3(printk("scsi(%ld): HBA in NL topology.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x200b, "HBA in NL topology.\n");
                ha->current_topology = ISP_CFG_NL;
                strcpy(connect_type, "(Loop)");
                break;
 
        case 1:
-               DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x200c, "HBA in FL topology.\n");
                ha->switch_cap = sw_cap;
                ha->current_topology = ISP_CFG_FL;
                strcpy(connect_type, "(FL_Port)");
                break;
 
        case 2:
-               DEBUG3(printk("scsi(%ld): HBA in N P2P topology.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x200d, "HBA in N P2P topology.\n");
                ha->operating_mode = P2P;
                ha->current_topology = ISP_CFG_N;
                strcpy(connect_type, "(N_Port-to-N_Port)");
                break;
 
        case 3:
-               DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x200e, "HBA in F P2P topology.\n");
                ha->switch_cap = sw_cap;
                ha->operating_mode = P2P;
                ha->current_topology = ISP_CFG_F;
@@ -2091,9 +2079,8 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
                break;
 
        default:
-               DEBUG3(printk("scsi(%ld): HBA in unknown topology %x. "
-                   "Using NL.\n",
-                   vha->host_no, topo));
+               ql_dbg(ql_dbg_disc, vha, 0x200f,
+                   "HBA in unknown topology %x, using NL.\n", topo);
                ha->current_topology = ISP_CFG_NL;
                strcpy(connect_type, "(Loop)");
                break;
@@ -2106,14 +2093,16 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
        vha->d_id.b.al_pa = al_pa;
 
        if (!vha->flags.init_done)
-               qla_printk(KERN_INFO, ha,
-                   "Topology - %s, Host Loop address 0x%x\n",
+               ql_log(ql_log_info, vha, 0x2010,
+                   "Topology - %s, Host Loop address 0x%x.\n",
                    connect_type, vha->loop_id);
 
        if (rval) {
-               DEBUG2_3(printk("scsi(%ld): FAILED.\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x2011,
+                   "%s FAILED\n", __func__);
        } else {
-               DEBUG3(printk("scsi(%ld): exiting normally.\n", vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2012,
+                   "%s success\n", __func__);
        }
 
        return(rval);
@@ -2227,18 +2216,22 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
        for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
                chksum += *ptr++;
 
-       DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
-       DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
+       ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x010f,
+           "Contents of NVRAM.\n");
+       ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0110,
+           (uint8_t *)nv, ha->nvram_size);
 
        /* Bad NVRAM data, set defaults parameters. */
        if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
            nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
                /* Reset NVRAM data. */
-               qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
-                   "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
-                   nv->nvram_version);
-               qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
-                   "invalid -- WWPN) defaults.\n");
+               ql_log(ql_log_warn, vha, 0x0064,
+                   "Inconisistent NVRAM "
+                   "detected: checksum=0x%x id=%c version=0x%x.\n",
+                   chksum, nv->id[0], nv->nvram_version);
+               ql_log(ql_log_warn, vha, 0x0065,
+                   "Falling back to "
+                   "functioning (yet invalid -- WWPN) defaults.\n");
 
                /*
                 * Set default initialization control block.
@@ -2382,8 +2375,13 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
        /*
         * Set host adapter parameters.
         */
+
+       /*
+        * BIT_7 in the host-parameters section allows for modification to
+        * internal driver logging.
+        */
        if (nv->host_p[0] & BIT_7)
-               ql2xextended_error_logging = 1;
+               ql2xextended_error_logging = 0x7fffffff;
        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))
@@ -2488,10 +2486,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
                if (ha->zio_mode != QLA_ZIO_DISABLED) {
                        ha->zio_mode = QLA_ZIO_MODE_6;
 
-                       DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer "
-                           "delay (%d us).\n", vha->host_no, ha->zio_mode,
-                           ha->zio_timer * 100));
-                       qla_printk(KERN_INFO, ha,
+                       ql_log(ql_log_info, vha, 0x0068,
                            "ZIO mode %d enabled; timer delay (%d us).\n",
                            ha->zio_mode, ha->zio_timer * 100);
 
@@ -2502,8 +2497,8 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
        }
 
        if (rval) {
-               DEBUG2_3(printk(KERN_WARNING
-                   "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x0069,
+                   "NVRAM configuration failed.\n");
        }
        return (rval);
 }
@@ -2574,15 +2569,15 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
        if (test_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags)) {
                rval = qla2x00_configure_hba(vha);
                if (rval != QLA_SUCCESS) {
-                       DEBUG(printk("scsi(%ld): Unable to configure HBA.\n",
-                           vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x2013,
+                           "Unable to configure HBA.\n");
                        return (rval);
                }
        }
 
        save_flags = flags = vha->dpc_flags;
-       DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n",
-           vha->host_no, flags));
+       ql_dbg(ql_dbg_disc, vha, 0x2014,
+           "Configure loop -- dpc flags = 0x%lx.\n", flags);
 
        /*
         * If we have both an RSCN and PORT UPDATE pending then handle them
@@ -2619,15 +2614,21 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
        }
 
        if (test_bit(LOCAL_LOOP_UPDATE, &flags)) {
-               if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
+               if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
+                       ql_dbg(ql_dbg_disc, vha, 0x2015,
+                           "Loop resync needed, failing.\n");
                        rval = QLA_FUNCTION_FAILED;
+               }
                else
                        rval = qla2x00_configure_local_loop(vha);
        }
 
        if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
-               if (LOOP_TRANSITION(vha))
+               if (LOOP_TRANSITION(vha)) {
+                       ql_dbg(ql_dbg_disc, vha, 0x201e,
+                           "Needs RSCN update and loop transition.\n");
                        rval = QLA_FUNCTION_FAILED;
+               }
                else
                        rval = qla2x00_configure_fabric(vha);
        }
@@ -2638,16 +2639,17 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
                        rval = QLA_FUNCTION_FAILED;
                } else {
                        atomic_set(&vha->loop_state, LOOP_READY);
-
-                       DEBUG(printk("scsi(%ld): LOOP READY\n", vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x2069,
+                           "LOOP READY.\n");
                }
        }
 
        if (rval) {
-               DEBUG2_3(printk("%s(%ld): *** FAILED ***\n",
-                   __func__, vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x206a,
+                   "%s *** FAILED ***.\n", __func__);
        } else {
-               DEBUG3(printk("%s: exiting normally\n", __func__));
+               ql_dbg(ql_dbg_disc, vha, 0x206b,
+                   "%s: exiting normally.\n", __func__);
        }
 
        /* Restore state if a resync event occurred during processing */
@@ -2695,8 +2697,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
        new_fcport = NULL;
        entries = MAX_FIBRE_DEVICES;
 
-       DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", vha->host_no));
-       DEBUG3(qla2x00_get_fcal_position_map(vha, NULL));
+       ql_dbg(ql_dbg_disc, vha, 0x2016,
+           "Getting FCAL position map.\n");
+       if (ql2xextended_error_logging & ql_dbg_disc)
+               qla2x00_get_fcal_position_map(vha, NULL);
 
        /* Get list of logged in devices. */
        memset(ha->gid_list, 0, GID_LIST_SIZE);
@@ -2705,14 +2709,17 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
        if (rval != QLA_SUCCESS)
                goto cleanup_allocation;
 
-       DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
-           vha->host_no, entries));
-       DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
-           entries * sizeof(struct gid_list_info)));
+       ql_dbg(ql_dbg_disc, vha, 0x2017,
+           "Entries in ID list (%d).\n", entries);
+       ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2075,
+           (uint8_t *)ha->gid_list,
+           entries * sizeof(struct gid_list_info));
 
        /* Allocate temporary fcport for any new fcports discovered. */
        new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
        if (new_fcport == NULL) {
+               ql_log(ql_log_warn, vha, 0x2018,
+                   "Memory allocation failed for fcport.\n");
                rval = QLA_MEMORY_ALLOC_FAILED;
                goto cleanup_allocation;
        }
@@ -2726,9 +2733,9 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
                    fcport->port_type != FCT_BROADCAST &&
                    (fcport->flags & FCF_FABRIC_DEVICE) == 0) {
 
-                       DEBUG(printk("scsi(%ld): Marking port lost, "
-                           "loop_id=0x%04x\n",
-                           vha->host_no, fcport->loop_id));
+                       ql_dbg(ql_dbg_disc, vha, 0x2019,
+                           "Marking port lost loop_id=0x%04x.\n",
+                           fcport->loop_id);
 
                        qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
                }
@@ -2769,12 +2776,12 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
                new_fcport->vp_idx = vha->vp_idx;
                rval2 = qla2x00_get_port_database(vha, new_fcport, 0);
                if (rval2 != QLA_SUCCESS) {
-                       DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
-                           "information -- get_port_database=%x, "
-                           "loop_id=0x%04x\n",
-                           vha->host_no, rval2, new_fcport->loop_id));
-                       DEBUG2(printk("scsi(%ld): Scheduling resync...\n",
-                           vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x201a,
+                           "Failed to retrieve fcport information "
+                           "-- get_port_database=%x, loop_id=0x%04x.\n",
+                           rval2, new_fcport->loop_id);
+                       ql_dbg(ql_dbg_disc, vha, 0x201b,
+                           "Scheduling resync.\n");
                        set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
                        continue;
                }
@@ -2810,6 +2817,8 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
                        fcport = new_fcport;
                        new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
                        if (new_fcport == NULL) {
+                               ql_log(ql_log_warn, vha, 0x201c,
+                                   "Failed to allocate memory for fcport.\n");
                                rval = QLA_MEMORY_ALLOC_FAILED;
                                goto cleanup_allocation;
                        }
@@ -2828,8 +2837,8 @@ cleanup_allocation:
        kfree(new_fcport);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2(printk("scsi(%ld): Configure local loop error exit: "
-                   "rval=%x\n", vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x201d,
+                   "Configure local loop error exit: rval=%x.\n", rval);
        }
 
        return (rval);
@@ -2858,27 +2867,27 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
        rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed,
            mb);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
-                   "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
-                   vha->host_no, fcport->port_name[0], fcport->port_name[1],
+               ql_dbg(ql_dbg_disc, vha, 0x2004,
+                   "Unable to adjust iIDMA "
+                   "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x "
+                   "%04x.\n", fcport->port_name[0], fcport->port_name[1],
                    fcport->port_name[2], fcport->port_name[3],
                    fcport->port_name[4], fcport->port_name[5],
                    fcport->port_name[6], fcport->port_name[7], rval,
-                   fcport->fp_speed, mb[0], mb[1]));
+                   fcport->fp_speed, mb[0], mb[1]);
        } else {
                link_speed = link_speeds[LS_UNKNOWN];
                if (fcport->fp_speed < 5)
                        link_speed = link_speeds[fcport->fp_speed];
                else if (fcport->fp_speed == 0x13)
                        link_speed = link_speeds[5];
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "iIDMA adjusted to %s GB/s on "
-                   "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
-                   link_speed, fcport->port_name[0],
-                   fcport->port_name[1], fcport->port_name[2],
-                   fcport->port_name[3], fcport->port_name[4],
-                   fcport->port_name[5], fcport->port_name[6],
-                   fcport->port_name[7]));
+               ql_dbg(ql_dbg_disc, vha, 0x2005,
+                   "iIDMA adjusted to %s GB/s "
+                   "on %02x%02x%02x%02x%02x%02x%02x%02x.\n", link_speed,
+                   fcport->port_name[0], fcport->port_name[1],
+                   fcport->port_name[2], fcport->port_name[3],
+                   fcport->port_name[4], fcport->port_name[5],
+                   fcport->port_name[6], fcport->port_name[7]);
        }
 }
 
@@ -2887,7 +2896,6 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
 {
        struct fc_rport_identifiers rport_ids;
        struct fc_rport *rport;
-       struct qla_hw_data *ha = vha->hw;
        unsigned long flags;
 
        qla2x00_rport_del(fcport);
@@ -2899,8 +2907,8 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
        rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
        fcport->rport = rport = fc_remote_port_add(vha->host, 0, &rport_ids);
        if (!rport) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to allocate fc remote port!\n");
+               ql_log(ql_log_warn, vha, 0x2006,
+                   "Unable to allocate fc remote port.\n");
                return;
        }
        spin_lock_irqsave(fcport->vha->host->host_lock, flags);
@@ -2975,8 +2983,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                loop_id = SNS_FL_PORT;
        rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_node_name, 1);
        if (rval != QLA_SUCCESS) {
-               DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
-                   "Port\n", vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x201f,
+                   "MBX_GET_PORT_NAME failed, No FL Port.\n");
 
                vha->device_flags &= ~SWITCH_FOUND;
                return (QLA_SUCCESS);
@@ -3003,32 +3011,32 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff,
                    0xfc, mb, BIT_1 | BIT_0);
                if (mb[0] != MBS_COMMAND_COMPLETE) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
-                           "mb[2]=%x mb[6]=%x mb[7]=%x\n", loop_id,
-                           mb[0], mb[1], mb[2], mb[6], mb[7]));
+                       ql_dbg(ql_dbg_disc, vha, 0x2042,
+                           "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x "
+                           "mb[6]=%x mb[7]=%x.\n", loop_id, mb[0], mb[1],
+                           mb[2], mb[6], mb[7]);
                        return (QLA_SUCCESS);
                }
 
                if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) {
                        if (qla2x00_rft_id(vha)) {
                                /* EMPTY */
-                               DEBUG2(printk("scsi(%ld): Register FC-4 "
-                                   "TYPE failed.\n", vha->host_no));
+                               ql_dbg(ql_dbg_disc, vha, 0x2045,
+                                   "Register FC-4 TYPE failed.\n");
                        }
                        if (qla2x00_rff_id(vha)) {
                                /* EMPTY */
-                               DEBUG2(printk("scsi(%ld): Register FC-4 "
-                                   "Features failed.\n", vha->host_no));
+                               ql_dbg(ql_dbg_disc, vha, 0x2049,
+                                   "Register FC-4 Features failed.\n");
                        }
                        if (qla2x00_rnn_id(vha)) {
                                /* EMPTY */
-                               DEBUG2(printk("scsi(%ld): Register Node Name "
-                                   "failed.\n", vha->host_no));
+                               ql_dbg(ql_dbg_disc, vha, 0x204f,
+                                   "Register Node Name failed.\n");
                        } else if (qla2x00_rsnn_nn(vha)) {
                                /* EMPTY */
-                               DEBUG2(printk("scsi(%ld): Register Symbolic "
-                                   "Node Name failed.\n", vha->host_no));
+                               ql_dbg(ql_dbg_disc, vha, 0x2053,
+                                   "Register Symobilic Node Name failed.\n");
                        }
                }
 
@@ -3132,8 +3140,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
        }
 
        if (rval) {
-               DEBUG2(printk("scsi(%ld): Configure fabric error exit: "
-                   "rval=%d\n", vha->host_no, rval));
+               ql_dbg(ql_dbg_disc, vha, 0x2068,
+                   "Configure fabric error exit rval=%d.\n", rval);
        }
 
        return (rval);
@@ -3175,8 +3183,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
        swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_KERNEL);
        if (!swl) {
                /*EMPTY*/
-               DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
-                   "on GA_NXT\n", vha->host_no));
+               ql_dbg(ql_dbg_disc, vha, 0x2054,
+                   "GID_PT allocations failed, fallback on GA_NXT.\n");
        } else {
                if (qla2x00_gid_pt(vha, swl) != QLA_SUCCESS) {
                        kfree(swl);
@@ -3201,6 +3209,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
        /* Allocate temporary fcport for any new fcports discovered. */
        new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
        if (new_fcport == NULL) {
+               ql_log(ql_log_warn, vha, 0x205e,
+                   "Failed to allocate memory for fcport.\n");
                kfree(swl);
                return (QLA_MEMORY_ALLOC_FAILED);
        }
@@ -3247,9 +3257,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                        /* Send GA_NXT to the switch */
                        rval = qla2x00_ga_nxt(vha, new_fcport);
                        if (rval != QLA_SUCCESS) {
-                               qla_printk(KERN_WARNING, ha,
-                                   "SNS scan failed -- assuming zero-entry "
-                                   "result...\n");
+                               ql_log(ql_log_warn, vha, 0x2064,
+                                   "SNS scan failed -- assuming "
+                                   "zero-entry result.\n");
                                list_for_each_entry_safe(fcport, fcptemp,
                                    new_fcports, list) {
                                        list_del(&fcport->list);
@@ -3265,9 +3275,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                        wrap.b24 = new_fcport->d_id.b24;
                        first_dev = 0;
                } else if (new_fcport->d_id.b24 == wrap.b24) {
-                       DEBUG2(printk("scsi(%ld): device wrap (%02x%02x%02x)\n",
-                           vha->host_no, new_fcport->d_id.b.domain,
-                           new_fcport->d_id.b.area, new_fcport->d_id.b.al_pa));
+                       ql_dbg(ql_dbg_disc, vha, 0x2065,
+                           "Device wrap (%02x%02x%02x).\n",
+                           new_fcport->d_id.b.domain,
+                           new_fcport->d_id.b.area,
+                           new_fcport->d_id.b.al_pa);
                        break;
                }
 
@@ -3372,6 +3384,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
                nxt_d_id.b24 = new_fcport->d_id.b24;
                new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
                if (new_fcport == NULL) {
+                       ql_log(ql_log_warn, vha, 0x2066,
+                           "Memory allocation failed for fcport.\n");
                        kfree(swl);
                        return (QLA_MEMORY_ALLOC_FAILED);
                }
@@ -3501,10 +3515,10 @@ qla2x00_device_resync(scsi_qla_host_t *vha)
                d_id.b.area = MSB(LSW(rscn_entry));
                d_id.b.al_pa = LSB(LSW(rscn_entry));
 
-               DEBUG(printk("scsi(%ld): RSCN queue entry[%d] = "
-                   "[%02x/%02x%02x%02x].\n",
-                   vha->host_no, vha->rscn_out_ptr, format, d_id.b.domain,
-                   d_id.b.area, d_id.b.al_pa));
+               ql_dbg(ql_dbg_disc, vha, 0x2020,
+                   "RSCN queue entry[%d] = [%02x/%02x%02x%02x].\n",
+                   vha->rscn_out_ptr, format, d_id.b.domain, d_id.b.area,
+                   d_id.b.al_pa);
 
                vha->rscn_out_ptr++;
                if (vha->rscn_out_ptr == MAX_RSCN_COUNT)
@@ -3520,17 +3534,17 @@ qla2x00_device_resync(scsi_qla_host_t *vha)
                        if (rscn_entry != vha->rscn_queue[rscn_out_iter])
                                break;
 
-                       DEBUG(printk("scsi(%ld): Skipping duplicate RSCN queue "
-                           "entry found at [%d].\n", vha->host_no,
-                           rscn_out_iter));
+                       ql_dbg(ql_dbg_disc, vha, 0x2021,
+                           "Skipping duplicate RSCN queue entry found at "
+                           "[%d].\n", rscn_out_iter);
 
                        vha->rscn_out_ptr = rscn_out_iter;
                }
 
                /* Queue overflow, set switch default case. */
                if (vha->flags.rscn_queue_overflow) {
-                       DEBUG(printk("scsi(%ld): device_resync: rscn "
-                           "overflow.\n", vha->host_no));
+                       ql_dbg(ql_dbg_disc, vha, 0x2022,
+                           "device_resync: rscn overflow.\n");
 
                        format = 3;
                        vha->flags.rscn_queue_overflow = 0;
@@ -3659,10 +3673,11 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
        tmp_loopid = 0;
 
        for (;;) {
-               DEBUG(printk("scsi(%ld): Trying Fabric Login w/loop id 0x%04x "
-                   "for port %02x%02x%02x.\n",
-                   vha->host_no, fcport->loop_id, fcport->d_id.b.domain,
-                   fcport->d_id.b.area, fcport->d_id.b.al_pa));
+               ql_dbg(ql_dbg_disc, vha, 0x2000,
+                   "Trying Fabric Login w/loop id 0x%04x for port "
+                   "%02x%02x%02x.\n",
+                   fcport->loop_id, fcport->d_id.b.domain,
+                   fcport->d_id.b.area, fcport->d_id.b.al_pa);
 
                /* Login fcport on switch. */
                ha->isp_ops->fabric_login(vha, fcport->loop_id,
@@ -3680,10 +3695,11 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
                        tmp_loopid = fcport->loop_id;
                        fcport->loop_id = mb[1];
 
-                       DEBUG(printk("Fabric Login: port in use - next "
-                           "loop id=0x%04x, port Id=%02x%02x%02x.\n",
+                       ql_dbg(ql_dbg_disc, vha, 0x2001,
+                           "Fabric Login: port in use - next loop "
+                           "id=0x%04x, port id= %02x%02x%02x.\n",
                            fcport->loop_id, fcport->d_id.b.domain,
-                           fcport->d_id.b.area, fcport->d_id.b.al_pa));
+                           fcport->d_id.b.area, fcport->d_id.b.al_pa);
 
                } else if (mb[0] == MBS_COMMAND_COMPLETE) {
                        /*
@@ -3744,11 +3760,11 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
                        /*
                         * unrecoverable / not handled error
                         */
-                       DEBUG2(printk("%s(%ld): failed=%x port_id=%02x%02x%02x "
-                           "loop_id=%x jiffies=%lx.\n",
-                           __func__, vha->host_no, mb[0],
-                           fcport->d_id.b.domain, fcport->d_id.b.area,
-                           fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
+                       ql_dbg(ql_dbg_disc, vha, 0x2002,
+                           "Failed=%x port_id=%02x%02x%02x loop_id=%x "
+                           "jiffies=%lx.\n", mb[0], fcport->d_id.b.domain,
+                           fcport->d_id.b.area, fcport->d_id.b.al_pa,
+                           fcport->loop_id, jiffies);
 
                        *next_loopid = fcport->loop_id;
                        ha->isp_ops->fabric_logout(vha, fcport->loop_id,
@@ -3852,7 +3868,8 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
                return (QLA_FUNCTION_FAILED);
 
        if (rval)
-               DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+               ql_dbg(ql_dbg_disc, vha, 0x206c,
+                   "%s *** FAILED ***.\n", __func__);
 
        return (rval);
 }
@@ -3929,8 +3946,8 @@ qla82xx_quiescent_state_cleanup(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
        struct scsi_qla_host *vp;
 
-       qla_printk(KERN_INFO, ha,
-                       "Performing ISP error recovery - ha= %p.\n", ha);
+       ql_dbg(ql_dbg_p3p, vha, 0xb002,
+           "Performing ISP error recovery - ha=%p.\n", ha);
 
        atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
        if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
@@ -3964,8 +3981,8 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
        clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
        ha->qla_stats.total_isp_aborts++;
 
-       qla_printk(KERN_INFO, ha,
-           "Performing ISP error recovery - ha= %p.\n", ha);
+       ql_log(ql_log_info, vha, 0x00af,
+           "Performing ISP error recovery - ha=%p.\n", ha);
 
        /* For ISP82XX, reset_chip is just disabling interrupts.
         * Driver waits for the completion of the commands.
@@ -4016,6 +4033,8 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
                /* Make sure for ISP 82XX IO DMA is complete */
                if (IS_QLA82XX(ha)) {
                        qla82xx_chip_reset_cleanup(vha);
+                       ql_log(ql_log_info, vha, 0x00b4,
+                           "Done chip reset cleanup.\n");
 
                        /* Done waiting for pending commands.
                         * Reset the online flag.
@@ -4097,7 +4116,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                                    ha->fce_dma, ha->fce_bufs, ha->fce_mb,
                                    &ha->fce_bufs);
                                if (rval) {
-                                       qla_printk(KERN_WARNING, ha,
+                                       ql_log(ql_log_warn, vha, 0x8033,
                                            "Unable to reinitialize FCE "
                                            "(%d).\n", rval);
                                        ha->flags.fce_enabled = 0;
@@ -4109,7 +4128,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                                rval = qla2x00_enable_eft_trace(vha,
                                    ha->eft_dma, EFT_NUM_BUFFERS);
                                if (rval) {
-                                       qla_printk(KERN_WARNING, ha,
+                                       ql_log(ql_log_warn, vha, 0x8034,
                                            "Unable to reinitialize EFT "
                                            "(%d).\n", rval);
                                }
@@ -4118,9 +4137,9 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                        vha->flags.online = 1;
                        if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
                                if (ha->isp_abort_cnt == 0) {
-                                       qla_printk(KERN_WARNING, ha,
-                                           "ISP error recovery failed - "
-                                           "board disabled\n");
+                                       ql_log(ql_log_fatal, vha, 0x8035,
+                                           "ISP error recover failed - "
+                                           "board disabled.\n");
                                        /*
                                         * The next call disables the board
                                         * completely.
@@ -4132,16 +4151,16 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                                        status = 0;
                                } else { /* schedule another ISP abort */
                                        ha->isp_abort_cnt--;
-                                       DEBUG(printk("qla%ld: ISP abort - "
-                                           "retry remaining %d\n",
-                                           vha->host_no, ha->isp_abort_cnt));
+                                       ql_dbg(ql_dbg_taskm, vha, 0x8020,
+                                           "ISP abort - retry remaining %d.\n",
+                                           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",
-                                   vha->host_no, ha->isp_abort_cnt));
+                               ql_dbg(ql_dbg_taskm, vha, 0x8021,
+                                   "ISP error recovery - retrying (%d) "
+                                   "more times.\n", ha->isp_abort_cnt);
                                set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
                                status = 1;
                        }
@@ -4150,9 +4169,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
        }
 
        if (!status) {
-               DEBUG(printk(KERN_INFO
-                               "qla2x00_abort_isp(%ld): succeeded.\n",
-                               vha->host_no));
+               ql_dbg(ql_dbg_taskm, vha, 0x8022, "%s succeeded.\n", __func__);
 
                spin_lock_irqsave(&ha->vport_slock, flags);
                list_for_each_entry(vp, &ha->vp_list, list) {
@@ -4169,8 +4186,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
                spin_unlock_irqrestore(&ha->vport_slock, flags);
 
        } else {
-               qla_printk(KERN_INFO, ha,
-                       "qla2x00_abort_isp: **** FAILED ****\n");
+               ql_log(ql_log_warn, vha, 0x8023, "%s **** FAILED ****.\n");
        }
 
        return(status);
@@ -4211,8 +4227,8 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
 
                status = qla2x00_fw_ready(vha);
                if (!status) {
-                       DEBUG(printk("%s(): Start configure loop, "
-                           "status = %d\n", __func__, status));
+                       ql_dbg(ql_dbg_taskm, vha, 0x8031,
+                           "Start configure loop status = %d.\n", status);
 
                        /* Issue a marker after FW becomes ready. */
                        qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
@@ -4234,9 +4250,8 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
                if ((vha->device_flags & DFLG_NO_CABLE))
                        status = 0;
 
-               DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
-                               __func__,
-                               status));
+               ql_dbg(ql_dbg_taskm, vha, 0x8032,
+                   "Configure loop done, status = 0x%x.\n", status);
        }
        return (status);
 }
@@ -4256,13 +4271,13 @@ qla25xx_init_queues(struct qla_hw_data *ha)
                        rsp->options &= ~BIT_0;
                        ret = qla25xx_init_rsp_que(base_vha, rsp);
                        if (ret != QLA_SUCCESS)
-                               DEBUG2_17(printk(KERN_WARNING
-                                       "%s Rsp que:%d init failed\n", __func__,
-                                               rsp->id));
+                               ql_dbg(ql_dbg_init, base_vha, 0x00ff,
+                                   "%s Rsp que: %d init failed.\n",
+                                   __func__, rsp->id);
                        else
-                               DEBUG2_17(printk(KERN_INFO
-                                       "%s Rsp que:%d inited\n", __func__,
-                                               rsp->id));
+                               ql_dbg(ql_dbg_init, base_vha, 0x0100,
+                                   "%s Rsp que: %d inited.\n",
+                                   __func__, rsp->id);
                }
        }
        for (i = 1; i < ha->max_req_queues; i++) {
@@ -4272,13 +4287,13 @@ qla25xx_init_queues(struct qla_hw_data *ha)
                        req->options &= ~BIT_0;
                        ret = qla25xx_init_req_que(base_vha, req);
                        if (ret != QLA_SUCCESS)
-                               DEBUG2_17(printk(KERN_WARNING
-                                       "%s Req que:%d init failed\n", __func__,
-                                               req->id));
+                               ql_dbg(ql_dbg_init, base_vha, 0x0101,
+                                   "%s Req que: %d init failed.\n",
+                                   __func__, req->id);
                        else
-                               DEBUG2_17(printk(KERN_WARNING
-                                       "%s Req que:%d inited\n", __func__,
-                                               req->id));
+                               ql_dbg(ql_dbg_init, base_vha, 0x0102,
+                                   "%s Req que: %d inited.\n",
+                                   __func__, req->id);
                }
        }
        return ret;
@@ -4397,19 +4412,22 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
        for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
                chksum += le32_to_cpu(*dptr++);
 
-       DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
-       DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
+       ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x006a,
+           "Contents of NVRAM\n");
+       ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010d,
+           (uint8_t *)nv, ha->nvram_size);
 
        /* Bad NVRAM data, set defaults parameters. */
        if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
            || nv->id[3] != ' ' ||
            nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
                /* Reset NVRAM data. */
-               qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
-                   "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
-                   le16_to_cpu(nv->nvram_version));
-               qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
-                   "invalid -- WWPN) defaults.\n");
+               ql_log(ql_log_warn, vha, 0x006b,
+                   "Inconisistent NVRAM detected: checksum=0x%x id=%c "
+                   "version=0x%x.\n", chksum, nv->id[0], nv->nvram_version);
+               ql_log(ql_log_warn, vha, 0x006c,
+                   "Falling back to functioning (yet invalid -- WWPN) "
+                   "defaults.\n");
 
                /*
                 * Set default initialization control block.
@@ -4587,10 +4605,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
        if (ha->zio_mode != QLA_ZIO_DISABLED) {
                ha->zio_mode = QLA_ZIO_MODE_6;
 
-               DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
-                   "(%d us).\n", vha->host_no, ha->zio_mode,
-                   ha->zio_timer * 100));
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0x006f,
                    "ZIO mode %d enabled; timer delay (%d us).\n",
                    ha->zio_mode, ha->zio_timer * 100);
 
@@ -4601,8 +4616,8 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
        }
 
        if (rval) {
-               DEBUG2_3(printk(KERN_WARNING
-                   "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x0070,
+                   "NVRAM configuration failed.\n");
        }
        return (rval);
 }
@@ -4620,8 +4635,8 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = ha->req_q_map[0];
 
-       qla_printk(KERN_INFO, ha,
-           "FW: Loading from flash (%x)...\n", faddr);
+       ql_dbg(ql_dbg_init, vha, 0x008b,
+           "Loading firmware from flash (%x).\n", faddr);
 
        rval = QLA_SUCCESS;
 
@@ -4637,11 +4652,12 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
            dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
            (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
                dcode[3] == 0)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to verify integrity of flash firmware image!\n");
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
-                   dcode[1], dcode[2], dcode[3]);
+               ql_log(ql_log_fatal, vha, 0x008c,
+                   "Unable to verify the integrity of flash firmware "
+                   "image.\n");
+               ql_log(ql_log_fatal, vha, 0x008d,
+                   "Firmware data: %08x %08x %08x %08x.\n",
+                   dcode[0], dcode[1], dcode[2], dcode[3]);
 
                return QLA_FUNCTION_FAILED;
        }
@@ -4660,9 +4676,10 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
                        if (dlen > risc_size)
                                dlen = risc_size;
 
-                       DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
-                           "addr %x, number of dwords 0x%x, offset 0x%x.\n",
-                           vha->host_no, risc_addr, dlen, faddr));
+                       ql_dbg(ql_dbg_init, vha, 0x008e,
+                           "Loading risc segment@ risc addr %x "
+                           "number of dwords 0x%x offset 0x%x.\n",
+                           risc_addr, dlen, faddr);
 
                        qla24xx_read_flash_data(vha, dcode, faddr, dlen);
                        for (i = 0; i < dlen; i++)
@@ -4671,12 +4688,9 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
                        rval = qla2x00_load_ram(vha, req->dma, risc_addr,
                            dlen);
                        if (rval) {
-                               DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
-                                   "segment %d of firmware\n", vha->host_no,
-                                   fragment));
-                               qla_printk(KERN_WARNING, ha,
-                                   "[ERROR] Failed to load segment %d of "
-                                   "firmware\n", fragment);
+                               ql_log(ql_log_fatal, vha, 0x008f,
+                                   "Failed to load segment %d of firmware.\n",
+                                   fragment);
                                break;
                        }
 
@@ -4709,9 +4723,10 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
        /* Load firmware blob. */
        blob = qla2x00_request_firmware(vha);
        if (!blob) {
-               qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
-               qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
-                   "from: " QLA_FW_URL ".\n");
+               ql_log(ql_log_info, vha, 0x0083,
+                   "Fimware image unavailable.\n");
+               ql_log(ql_log_info, vha, 0x0084,
+                   "Firmware images can be retrieved from: "QLA_FW_URL ".\n");
                return QLA_FUNCTION_FAILED;
        }
 
@@ -4724,8 +4739,8 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 
        /* Validate firmware image by checking version. */
        if (blob->fw->size < 8 * sizeof(uint16_t)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to verify integrity of firmware image (%Zd)!\n",
+               ql_log(ql_log_fatal, vha, 0x0085,
+                   "Unable to verify integrity of firmware image (%Zd).\n",
                    blob->fw->size);
                goto fail_fw_integrity;
        }
@@ -4734,11 +4749,11 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
        if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff &&
            wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 &&
                wcode[2] == 0 && wcode[3] == 0)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to verify integrity of firmware image!\n");
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware data: %04x %04x %04x %04x!\n", wcode[0],
-                   wcode[1], wcode[2], wcode[3]);
+               ql_log(ql_log_fatal, vha, 0x0086,
+                   "Unable to verify integrity of firmware image.\n");
+               ql_log(ql_log_fatal, vha, 0x0087,
+                   "Firmware data: %04x %04x %04x %04x.\n",
+                   wcode[0], wcode[1], wcode[2], wcode[3]);
                goto fail_fw_integrity;
        }
 
@@ -4751,9 +4766,9 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                /* Validate firmware image size. */
                fwclen += risc_size * sizeof(uint16_t);
                if (blob->fw->size < fwclen) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_fatal, vha, 0x0088,
                            "Unable to verify integrity of firmware image "
-                           "(%Zd)!\n", blob->fw->size);
+                           "(%Zd).\n", blob->fw->size);
                        goto fail_fw_integrity;
                }
 
@@ -4762,10 +4777,9 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                        wlen = (uint16_t)(ha->fw_transfer_size >> 1);
                        if (wlen > risc_size)
                                wlen = risc_size;
-
-                       DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
-                           "addr %x, number of words 0x%x.\n", vha->host_no,
-                           risc_addr, wlen));
+                       ql_dbg(ql_dbg_init, vha, 0x0089,
+                           "Loading risc segment@ risc addr %x number of "
+                           "words 0x%x.\n", risc_addr, wlen);
 
                        for (i = 0; i < wlen; i++)
                                wcode[i] = swab16(fwcode[i]);
@@ -4773,12 +4787,9 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                        rval = qla2x00_load_ram(vha, req->dma, risc_addr,
                            wlen);
                        if (rval) {
-                               DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
-                                   "segment %d of firmware\n", vha->host_no,
-                                   fragment));
-                               qla_printk(KERN_WARNING, ha,
-                                   "[ERROR] Failed to load segment %d of "
-                                   "firmware\n", fragment);
+                               ql_log(ql_log_fatal, vha, 0x008a,
+                                   "Failed to load segment %d of firmware.\n",
+                                   fragment);
                                break;
                        }
 
@@ -4814,15 +4825,17 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
        /* Load firmware blob. */
        blob = qla2x00_request_firmware(vha);
        if (!blob) {
-               qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
-               qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
-                   "from: " QLA_FW_URL ".\n");
+               ql_log(ql_log_warn, vha, 0x0090,
+                   "Fimware image unavailable.\n");
+               ql_log(ql_log_warn, vha, 0x0091,
+                   "Firmware images can be retrieved from: "
+                   QLA_FW_URL ".\n");
 
                return QLA_FUNCTION_FAILED;
        }
 
-       qla_printk(KERN_INFO, ha,
-           "FW: Loading via request-firmware...\n");
+       ql_log(ql_log_info, vha, 0x0092,
+           "Loading via request-firmware.\n");
 
        rval = QLA_SUCCESS;
 
@@ -4834,8 +4847,8 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 
        /* Validate firmware image by checking version. */
        if (blob->fw->size < 8 * sizeof(uint32_t)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to verify integrity of firmware image (%Zd)!\n",
+               ql_log(ql_log_fatal, vha, 0x0093,
+                   "Unable to verify integrity of firmware image (%Zd).\n",
                    blob->fw->size);
                goto fail_fw_integrity;
        }
@@ -4845,11 +4858,12 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
            dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
            (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
                dcode[3] == 0)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to verify integrity of firmware image!\n");
-               qla_printk(KERN_WARNING, ha,
-                   "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
-                   dcode[1], dcode[2], dcode[3]);
+               ql_log(ql_log_fatal, vha, 0x0094,
+                   "Unable to verify integrity of firmware image (%Zd).\n",
+                   blob->fw->size);
+               ql_log(ql_log_fatal, vha, 0x0095,
+                   "Firmware data: %08x %08x %08x %08x.\n",
+                   dcode[0], dcode[1], dcode[2], dcode[3]);
                goto fail_fw_integrity;
        }
 
@@ -4861,9 +4875,9 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                /* Validate firmware image size. */
                fwclen += risc_size * sizeof(uint32_t);
                if (blob->fw->size < fwclen) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_fatal, vha, 0x0096,
                            "Unable to verify integrity of firmware image "
-                           "(%Zd)!\n", blob->fw->size);
+                           "(%Zd).\n", blob->fw->size);
 
                        goto fail_fw_integrity;
                }
@@ -4874,9 +4888,9 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                        if (dlen > risc_size)
                                dlen = risc_size;
 
-                       DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
-                           "addr %x, number of dwords 0x%x.\n", vha->host_no,
-                           risc_addr, dlen));
+                       ql_dbg(ql_dbg_init, vha, 0x0097,
+                           "Loading risc segment@ risc addr %x "
+                           "number of dwords 0x%x.\n", risc_addr, dlen);
 
                        for (i = 0; i < dlen; i++)
                                dcode[i] = swab32(fwcode[i]);
@@ -4884,12 +4898,9 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
                        rval = qla2x00_load_ram(vha, req->dma, risc_addr,
                            dlen);
                        if (rval) {
-                               DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
-                                   "segment %d of firmware\n", vha->host_no,
-                                   fragment));
-                               qla_printk(KERN_WARNING, ha,
-                                   "[ERROR] Failed to load segment %d of "
-                                   "firmware\n", fragment);
+                               ql_log(ql_log_fatal, vha, 0x0098,
+                                   "Failed to load segment %d of firmware.\n",
+                                   fragment);
                                break;
                        }
 
@@ -4953,14 +4964,13 @@ try_blob_fw:
        if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw)
                return rval;
 
-       qla_printk(KERN_ERR, ha,
-           "FW: Attempting to fallback to golden firmware...\n");
+       ql_log(ql_log_info, vha, 0x0099,
+           "Attempting to fallback to golden firmware.\n");
        rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw);
        if (rval != QLA_SUCCESS)
                return rval;
 
-       qla_printk(KERN_ERR, ha,
-           "FW: Please update operational firmware...\n");
+       ql_log(ql_log_info, vha, 0x009a, "Update operational firmware.\n");
        ha->flags.running_gold_fw = 1;
 
        return rval;
@@ -4987,8 +4997,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha)
                        continue;
                if (qla2x00_setup_chip(vha) != QLA_SUCCESS)
                        continue;
-               qla_printk(KERN_INFO, ha,
-                   "Attempting retry of stop-firmware command...\n");
+               ql_log(ql_log_info, vha, 0x8015,
+                   "Attempting retry of stop-firmware command.\n");
                ret = qla2x00_stop_firmware(vha);
        }
 }
@@ -5023,10 +5033,10 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha)
        /* Login to SNS first */
        ha->isp_ops->fabric_login(vha, NPH_SNS, 0xff, 0xff, 0xfc, mb, BIT_1);
        if (mb[0] != MBS_COMMAND_COMPLETE) {
-               DEBUG15(qla_printk(KERN_INFO, ha,
-                   "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
-                   "mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
-                   mb[0], mb[1], mb[2], mb[6], mb[7]));
+               ql_dbg(ql_dbg_init, vha, 0x0103,
+                   "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x "
+                   "mb[6]=%x mb[7]=%x.\n",
+                   NPH_SNS, mb[0], mb[1], mb[2], mb[6], mb[7]);
                return (QLA_FUNCTION_FAILED);
        }
 
@@ -5146,19 +5156,23 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
                chksum += le32_to_cpu(*dptr++);
 
-       DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
-       DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
+       ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111,
+           "Contents of NVRAM:\n");
+       ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0112,
+           (uint8_t *)nv, ha->nvram_size);
 
        /* Bad NVRAM data, set defaults parameters. */
        if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
            || nv->id[3] != ' ' ||
            nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
                /* Reset NVRAM data. */
-               qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
-                   "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
+               ql_log(ql_log_info, vha, 0x0073,
+                   "Inconisistent NVRAM detected: checksum=0x%x id=%c "
+                   "version=0x%x.\n", chksum, nv->id[0],
                    le16_to_cpu(nv->nvram_version));
-               qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
-                   "invalid -- WWPN) defaults.\n");
+               ql_log(ql_log_info, vha, 0x0074,
+                   "Falling back to functioning (yet invalid -- WWPN) "
+                   "defaults.\n");
 
                /*
                 * Set default initialization control block.
@@ -5350,12 +5364,10 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        if (ha->zio_mode != QLA_ZIO_DISABLED) {
                ha->zio_mode = QLA_ZIO_MODE_6;
 
-               DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
-                   "(%d us).\n", vha->host_no, ha->zio_mode,
-                   ha->zio_timer * 100));
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0x0075,
                    "ZIO mode %d enabled; timer delay (%d us).\n",
-                   ha->zio_mode, ha->zio_timer * 100);
+                   ha->zio_mode,
+                   ha->zio_timer * 100);
 
                icb->firmware_options_2 |= cpu_to_le32(
                    (uint32_t)ha->zio_mode);
@@ -5364,8 +5376,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        }
 
        if (rval) {
-               DEBUG2_3(printk(KERN_WARNING
-                   "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
+               ql_log(ql_log_warn, vha, 0x0076,
+                   "NVRAM configuration failed.\n");
        }
        return (rval);
 }
@@ -5388,9 +5400,8 @@ qla82xx_restart_isp(scsi_qla_host_t *vha)
 
                status = qla2x00_fw_ready(vha);
                if (!status) {
-                       qla_printk(KERN_INFO, ha,
-                       "%s(): Start configure loop, "
-                       "status = %d\n", __func__, status);
+                       ql_log(ql_log_info, vha, 0x803c,
+                           "Start configure loop, status =%d.\n", status);
 
                        /* Issue a marker after FW becomes ready. */
                        qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
@@ -5412,9 +5423,8 @@ qla82xx_restart_isp(scsi_qla_host_t *vha)
                if ((vha->device_flags & DFLG_NO_CABLE))
                        status = 0;
 
-               qla_printk(KERN_INFO, ha,
-                       "%s(): Configure loop done, status = 0x%x\n",
-                       __func__, status);
+               ql_log(ql_log_info, vha, 0x803d,
+                   "Configure loop done, status = 0x%x.\n", status);
        }
 
        if (!status) {
@@ -5450,9 +5460,9 @@ qla82xx_restart_isp(scsi_qla_host_t *vha)
                            ha->fce_dma, ha->fce_bufs, ha->fce_mb,
                            &ha->fce_bufs);
                        if (rval) {
-                               qla_printk(KERN_WARNING, ha,
-                                   "Unable to reinitialize FCE "
-                                   "(%d).\n", rval);
+                               ql_log(ql_log_warn, vha, 0x803e,
+                                   "Unable to reinitialize FCE (%d).\n",
+                                   rval);
                                ha->flags.fce_enabled = 0;
                        }
                }
@@ -5462,17 +5472,16 @@ qla82xx_restart_isp(scsi_qla_host_t *vha)
                        rval = qla2x00_enable_eft_trace(vha,
                            ha->eft_dma, EFT_NUM_BUFFERS);
                        if (rval) {
-                               qla_printk(KERN_WARNING, ha,
-                                   "Unable to reinitialize EFT "
-                                   "(%d).\n", rval);
+                               ql_log(ql_log_warn, vha, 0x803f,
+                                   "Unable to reinitialize EFT (%d).\n",
+                                   rval);
                        }
                }
        }
 
        if (!status) {
-               DEBUG(printk(KERN_INFO
-                       "qla82xx_restart_isp(%ld): succeeded.\n",
-                       vha->host_no));
+               ql_dbg(ql_dbg_taskm, vha, 0x8040,
+                   "qla82xx_restart_isp succeeded.\n");
 
                spin_lock_irqsave(&ha->vport_slock, flags);
                list_for_each_entry(vp, &ha->vp_list, list) {
@@ -5489,8 +5498,8 @@ qla82xx_restart_isp(scsi_qla_host_t *vha)
                spin_unlock_irqrestore(&ha->vport_slock, flags);
 
        } else {
-               qla_printk(KERN_INFO, ha,
-                       "qla82xx_restart_isp: **** FAILED ****\n");
+               ql_log(ql_log_warn, vha, 0x8041,
+                   "qla82xx_restart_isp **** FAILED ****.\n");
        }
 
        return status;
@@ -5640,9 +5649,8 @@ qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
        if (ret == QLA_SUCCESS)
                fcport->fcp_prio = priority;
        else
-               DEBUG2(printk(KERN_WARNING
-                       "scsi(%ld): Unable to activate fcp priority, "
-                       " ret=0x%x\n", vha->host_no, ret));
+               ql_dbg(ql_dbg_user, vha, 0x704f,
+                   "Unable to activate fcp priority, ret=0x%x.\n", ret);
 
        return  ret;
 }
index 4c8167e11f69e6ebf7d5658cac18675529237015..d2e904bc21c018606d3a40bf40f34ba3437d6159 100644 (file)
@@ -94,11 +94,11 @@ qla2x00_set_fcport_state(fc_port_t *fcport, int state)
 
        /* Don't print state transitions during initial allocation of fcport */
        if (old_state && old_state != state) {
-               DEBUG(qla_printk(KERN_WARNING, fcport->vha->hw,
-                   "scsi(%ld): FCPort state transitioned from %s to %s - "
-                   "portid=%02x%02x%02x.\n", fcport->vha->host_no,
+               ql_dbg(ql_dbg_disc, fcport->vha, 0x207d,
+                   "FCPort state transitioned from %s to %s - "
+                   "portid=%02x%02x%02x.\n",
                    port_state_str[old_state], port_state_str[state],
                    fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa));
+                   fcport->d_id.b.al_pa);
        }
 }
index 7bac3cd109d60740628c00a33aabc9345414e975..49d6906af886e06649494ba2eab37b8bddeac3aa 100644 (file)
@@ -150,7 +150,8 @@ qla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts)
 
        /* We only support T10 DIF right now */
        if (guard != SHOST_DIX_GUARD_CRC) {
-               DEBUG2(printk(KERN_ERR "Unsupported guard: %d\n", guard));
+               ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3007,
+                   "Unsupported guard: %d for cmd=%p.\n", guard, sp->cmd);
                return 0;
        }
 
@@ -343,9 +344,10 @@ qla2x00_start_scsi(srb_t *sp)
 
        /* Send marker if required */
        if (vha->marker_needed != 0) {
-               if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL)
-                                                       != QLA_SUCCESS)
+               if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) !=
+                   QLA_SUCCESS) {
                        return (QLA_FUNCTION_FAILED);
+               }
                vha->marker_needed = 0;
        }
 
@@ -490,8 +492,8 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
        mrk24 = NULL;
        mrk = (mrk_entry_t *)qla2x00_alloc_iocbs(vha, 0);
        if (mrk == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n",
-                   __func__, base_vha->host_no));
+               ql_log(ql_log_warn, base_vha, 0x3026,
+                   "Failed to allocate Marker IOCB.\n");
 
                return (QLA_FUNCTION_FAILED);
        }
@@ -547,9 +549,10 @@ qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req)
        device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
        struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
 
-       DEBUG5(printk("%s(): IOCB data:\n", __func__));
-       DEBUG5(qla2x00_dump_buffer(
-           (uint8_t *)req->ring_ptr, REQUEST_ENTRY_SIZE));
+       ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x302d,
+           "IOCB data:\n");
+       ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e,
+           (uint8_t *)req->ring_ptr, REQUEST_ENTRY_SIZE);
 
        /* Adjust ring index. */
        req->ring_index++;
@@ -604,7 +607,7 @@ qla2x00_isp_cmd(struct scsi_qla_host *vha, struct req_que *req)
  * Returns the number of IOCB entries needed to store @dsds.
  */
 inline uint16_t
-qla24xx_calc_iocbs(uint16_t dsds)
+qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds)
 {
        uint16_t iocbs;
 
@@ -614,8 +617,6 @@ qla24xx_calc_iocbs(uint16_t dsds)
                if ((dsds - 1) % 5)
                        iocbs++;
        }
-       DEBUG3(printk(KERN_DEBUG "%s(): Required PKT(s) = %d\n",
-           __func__, iocbs));
        return iocbs;
 }
 
@@ -712,6 +713,7 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
     unsigned int protcnt)
 {
        struct sd_dif_tuple *spt;
+       scsi_qla_host_t *vha = shost_priv(cmd->device->host);
        unsigned char op = scsi_get_prot_op(cmd);
 
        switch (scsi_get_prot_type(cmd)) {
@@ -768,9 +770,9 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
                    op == SCSI_PROT_WRITE_PASS)) {
                        spt = page_address(sg_page(scsi_prot_sglist(cmd))) +
                            scsi_prot_sglist(cmd)[0].offset;
-                       DEBUG18(printk(KERN_DEBUG
-                           "%s(): LBA from user %p, lba = 0x%x\n",
-                           __func__, spt, (int)spt->ref_tag));
+                       ql_dbg(ql_dbg_io, vha, 0x3008,
+                           "LBA from user %p, lba = 0x%x for cmd=%p.\n",
+                           spt, (int)spt->ref_tag, cmd);
                        pkt->ref_tag = swab32(spt->ref_tag);
                        pkt->app_tag_mask[0] = 0x0;
                        pkt->app_tag_mask[1] = 0x0;
@@ -789,11 +791,11 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt,
                break;
        }
 
-       DEBUG18(printk(KERN_DEBUG
-           "%s(): Setting protection Tags: (BIG) ref tag = 0x%x,"
-           " app tag = 0x%x, prot SG count %d , cmd lba 0x%x,"
-           " prot_type=%u\n", __func__, pkt->ref_tag, pkt->app_tag, protcnt,
-           (int)scsi_get_lba(cmd), scsi_get_prot_type(cmd)));
+       ql_dbg(ql_dbg_io, vha, 0x3009,
+           "Setting protection Tags: (BIG) ref tag = 0x%x, app tag = 0x%x, "
+           "prot SG count %d, cmd lba 0x%x, prot_type=%u cmd=%p.\n",
+           pkt->ref_tag, pkt->app_tag, protcnt, (int)scsi_get_lba(cmd),
+           scsi_get_prot_type(cmd), cmd);
 }
 
 
@@ -809,6 +811,7 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
        uint32_t *cur_dsd = dsd;
        int     i;
        uint16_t        used_dsds = tot_dsds;
+       scsi_qla_host_t *vha = shost_priv(sp->cmd->device->host);
 
        uint8_t         *cp;
 
@@ -853,9 +856,10 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
                        cur_dsd = (uint32_t *)next_dsd;
                }
                sle_dma = sg_dma_address(sg);
-               DEBUG18(printk("%s(): %p, sg entry %d - addr =0x%x 0x%x,"
-                   " len =%d\n", __func__ , cur_dsd, i, LSD(sle_dma),
-                   MSD(sle_dma), sg_dma_len(sg)));
+               ql_dbg(ql_dbg_io, vha, 0x300a,
+                   "sg entry %d - addr=0x%x 0x%x, " "len=%d for cmd=%p.\n",
+                   cur_dsd, i, LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg),
+                   sp->cmd);
                *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
                *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
                *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
@@ -863,8 +867,8 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd,
 
                if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
                        cp = page_address(sg_page(sg)) + sg->offset;
-                       DEBUG18(printk("%s(): User Data buffer= %p:\n",
-                           __func__ , cp));
+                       ql_dbg(ql_dbg_io, vha, 0x300b,
+                           "User data buffer=%p for cmd=%p.\n", cp, sp->cmd);
                }
        }
        /* Null termination */
@@ -888,7 +892,7 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
        struct scsi_cmnd *cmd;
        uint32_t *cur_dsd = dsd;
        uint16_t        used_dsds = tot_dsds;
-
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        uint8_t         *cp;
 
 
@@ -935,10 +939,11 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
                }
                sle_dma = sg_dma_address(sg);
                if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
-                       DEBUG18(printk(KERN_DEBUG
-                           "%s(): %p, sg entry %d - addr =0x%x"
-                           "0x%x, len =%d\n", __func__ , cur_dsd, i,
-                           LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg)));
+                       ql_dbg(ql_dbg_io, vha, 0x3027,
+                           "%s(): %p, sg_entry %d - "
+                           "addr=0x%x0x%x, len=%d.\n",
+                           __func__, cur_dsd, i,
+                           LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg));
                }
                *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
                *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
@@ -946,8 +951,9 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp,
 
                if (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_PASS) {
                        cp = page_address(sg_page(sg)) + sg->offset;
-                       DEBUG18(printk("%s(): Protection Data buffer = %p:\n",
-                           __func__ , cp));
+                       ql_dbg(ql_dbg_io, vha, 0x3028,
+                           "%s(): Protection Data buffer = %p.\n", __func__,
+                           cp);
                }
                avail_dsds--;
        }
@@ -996,22 +1002,16 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
        *((uint32_t *)(&cmd_pkt->entry_type)) =
            __constant_cpu_to_le32(COMMAND_TYPE_CRC_2);
 
+       vha = sp->fcport->vha;
+       ha = vha->hw;
+
        /* No data transfer */
        data_bytes = scsi_bufflen(cmd);
        if (!data_bytes || cmd->sc_data_direction == DMA_NONE) {
-               DEBUG18(printk(KERN_INFO "%s: Zero data bytes or DMA-NONE %d\n",
-                   __func__, data_bytes));
                cmd_pkt->byte_count = __constant_cpu_to_le32(0);
                return QLA_SUCCESS;
        }
 
-       vha = sp->fcport->vha;
-       ha = vha->hw;
-
-       DEBUG18(printk(KERN_DEBUG
-           "%s(%ld): Executing cmd sp %p, prot_op=%u.\n", __func__,
-           vha->host_no, sp, scsi_get_prot_op(sp->cmd)));
-
        cmd_pkt->vp_index = sp->fcport->vp_idx;
 
        /* Set transfer direction */
@@ -1056,8 +1056,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
 
        /* Determine SCSI command length -- align to 4 byte boundary */
        if (cmd->cmd_len > 16) {
-               DEBUG18(printk(KERN_INFO "%s(): **** SCSI CMD > 16\n",
-                   __func__));
                additional_fcpcdb_len = cmd->cmd_len - 16;
                if ((cmd->cmd_len % 4) != 0) {
                        /* SCSI cmd > 16 bytes must be multiple of 4 */
@@ -1108,11 +1106,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
 
        cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
 
-       DEBUG18(printk(KERN_INFO "%s(%ld): Total SG(s) Entries %d, Data"
-           "entries %d, data bytes %d, Protection entries %d\n",
-           __func__, vha->host_no, tot_dsds, (tot_dsds-tot_prot_dsds),
-           data_bytes, tot_prot_dsds));
-
        /* Compute dif len and adjust data len to incude protection */
        total_bytes = data_bytes;
        dif_bytes = 0;
@@ -1150,14 +1143,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
            additional_fcpcdb_len);
        *fcp_dl = htonl(total_bytes);
 
-       DEBUG18(printk(KERN_INFO "%s(%ld): dif bytes = 0x%x (%d), total bytes"
-           " = 0x%x (%d), dat block size =0x%x (%d)\n", __func__,
-           vha->host_no, dif_bytes, dif_bytes, total_bytes, total_bytes,
-           crc_ctx_pkt->blk_size, crc_ctx_pkt->blk_size));
-
        if (!data_bytes || cmd->sc_data_direction == DMA_NONE) {
-               DEBUG18(printk(KERN_INFO "%s: Zero data bytes or DMA-NONE %d\n",
-                   __func__, data_bytes));
                cmd_pkt->byte_count = __constant_cpu_to_le32(0);
                return QLA_SUCCESS;
        }
@@ -1182,8 +1168,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
        return QLA_SUCCESS;
 
 crc_queuing_error:
-       DEBUG18(qla_printk(KERN_INFO, ha,
-           "CMD sent FAILED crc_q error:sp = %p\n", sp));
        /* Cleanup will be performed by the caller */
 
        return QLA_FUNCTION_FAILED;
@@ -1225,8 +1209,8 @@ qla24xx_start_scsi(srb_t *sp)
 
        /* Send marker if required */
        if (vha->marker_needed != 0) {
-               if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL)
-                                                       != QLA_SUCCESS)
+               if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) !=
+                   QLA_SUCCESS)
                        return QLA_FUNCTION_FAILED;
                vha->marker_needed = 0;
        }
@@ -1243,8 +1227,9 @@ qla24xx_start_scsi(srb_t *sp)
                if (!req->outstanding_cmds[handle])
                        break;
        }
-       if (index == MAX_OUTSTANDING_COMMANDS)
+       if (index == MAX_OUTSTANDING_COMMANDS) {
                goto queuing_error;
+       }
 
        /* Map the sg table so we have an accurate count of sg entries needed */
        if (scsi_sg_count(cmd)) {
@@ -1256,8 +1241,7 @@ qla24xx_start_scsi(srb_t *sp)
                nseg = 0;
 
        tot_dsds = nseg;
-
-       req_cnt = qla24xx_calc_iocbs(tot_dsds);
+       req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
        if (req->cnt < (req_cnt + 2)) {
                cnt = RD_REG_DWORD_RELAXED(req->req_q_out);
 
@@ -1322,7 +1306,6 @@ qla24xx_start_scsi(srb_t *sp)
        /* Specify response queue number where completion should happen */
        cmd_pkt->entry_status = (uint8_t) rsp->id;
        wmb();
-
        /* Adjust ring index. */
        req->ring_index++;
        if (req->ring_index == req->length) {
@@ -1534,9 +1517,6 @@ queuing_error:
        /* Cleanup will be performed by the caller (queuecommand) */
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-       DEBUG18(qla_printk(KERN_INFO, ha,
-           "CMD sent FAILED SCSI prot_op:%02x\n", scsi_get_prot_op(cmd)));
        return QLA_FUNCTION_FAILED;
 }
 
@@ -1581,8 +1561,11 @@ qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp)
                if (!req->outstanding_cmds[handle])
                        break;
        }
-       if (index == MAX_OUTSTANDING_COMMANDS)
+       if (index == MAX_OUTSTANDING_COMMANDS) {
+               ql_log(ql_log_warn, vha, 0x700b,
+                   "No room on oustanding cmd array.\n");
                goto queuing_error;
+       }
 
        /* Prep command array. */
        req->current_outstanding_cmd = handle;
@@ -1999,8 +1982,11 @@ qla2x00_start_sp(srb_t *sp)
        rval = QLA_FUNCTION_FAILED;
        spin_lock_irqsave(&ha->hardware_lock, flags);
        pkt = qla2x00_alloc_iocbs(sp->fcport->vha, sp);
-       if (!pkt)
+       if (!pkt) {
+               ql_log(ql_log_warn, sp->fcport->vha, 0x700c,
+                   "qla2x00_alloc_iocbs failed.\n");
                goto done;
+       }
 
        rval = QLA_SUCCESS;
        switch (ctx->type) {
index ae8e298746bae1f02d25473ecbde6bcf3e8b52db..b16b7725dee001ee791b359a270d5a8792311957 100644 (file)
@@ -45,7 +45,7 @@ qla2100_intr_handler(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                   "%s(): NULL response queue pointer\n", __func__);
+                   "%s(): NULL response queue pointer.\n", __func__);
                return (IRQ_NONE);
        }
 
@@ -91,9 +91,9 @@ qla2100_intr_handler(int irq, void *dev_id)
                                qla2x00_async_event(vha, rsp, mb);
                        } else {
                                /*EMPTY*/
-                               DEBUG2(printk("scsi(%ld): Unrecognized "
-                                   "interrupt type (%d).\n",
-                                   vha->host_no, mb[0]));
+                               ql_dbg(ql_dbg_async, vha, 0x5025,
+                                   "Unrecognized interrupt type (%d).\n",
+                                   mb[0]);
                        }
                        /* Release mailbox registers. */
                        WRT_REG_WORD(&reg->semaphore, 0);
@@ -142,7 +142,7 @@ qla2300_intr_handler(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                   "%s(): NULL response queue pointer\n", __func__);
+                   "%s(): NULL response queue pointer.\n", __func__);
                return (IRQ_NONE);
        }
 
@@ -160,11 +160,13 @@ qla2300_intr_handler(int irq, void *dev_id)
 
                        hccr = RD_REG_WORD(&reg->hccr);
                        if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
-                               qla_printk(KERN_INFO, ha, "Parity error -- "
-                                   "HCCR=%x, Dumping firmware!\n", hccr);
+                               ql_log(ql_log_warn, vha, 0x5026,
+                                   "Parity error -- HCCR=%x, Dumping "
+                                   "firmware.\n", hccr);
                        else
-                               qla_printk(KERN_INFO, ha, "RISC paused -- "
-                                   "HCCR=%x, Dumping firmware!\n", hccr);
+                               ql_log(ql_log_warn, vha, 0x5027,
+                                   "RISC paused -- HCCR=%x, Dumping "
+                                   "firmware.\n", hccr);
 
                        /*
                         * Issue a "HARD" reset in order for the RISC
@@ -213,9 +215,8 @@ qla2300_intr_handler(int irq, void *dev_id)
                        qla2x00_async_event(vha, rsp, mb);
                        break;
                default:
-                       DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
-                           "(%d).\n",
-                           vha->host_no, stat & 0xff));
+                       ql_dbg(ql_dbg_async, vha, 0x5028,
+                           "Unrecognized interrupt type (%d).\n", stat & 0xff);
                        break;
                }
                WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
@@ -262,11 +263,11 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
        }
 
        if (ha->mcp) {
-               DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
-                   __func__, vha->host_no, ha->mcp->mb[0]));
+               ql_dbg(ql_dbg_async, vha, 0x5000,
+                   "Got mbx completion. cmd=%x.\n", ha->mcp->mb[0]);
        } else {
-               DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
-                   __func__, vha->host_no));
+               ql_dbg(ql_dbg_async, vha, 0x5001,
+                   "MBX pointer ERROR.\n");
        }
 }
 
@@ -285,22 +286,24 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
        for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
                mb[cnt] = RD_REG_WORD(wptr);
 
-       DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
-           "%04x %04x %04x %04x %04x %04x %04x.\n", vha->host_no,
-           event[aen & 0xff],
-           mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6]));
+       ql_dbg(ql_dbg_async, vha, 0x5021,
+           "Inter-Driver Commucation %s -- "
+           "%04x %04x %04x %04x %04x %04x %04x.\n",
+           event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
+           mb[4], mb[5], mb[6]);
 
        /* Acknowledgement needed? [Notify && non-zero timeout]. */
        timeout = (descr >> 8) & 0xf;
        if (aen != MBA_IDC_NOTIFY || !timeout)
                return;
 
-       DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
-           "ACK timeout=%d.\n", vha->host_no, event[aen & 0xff], timeout));
+       ql_dbg(ql_dbg_async, vha, 0x5022,
+           "Inter-Driver Commucation %s -- ACK timeout=%d.\n",
+           vha->host_no, event[aen & 0xff], timeout);
 
        rval = qla2x00_post_idc_ack_work(vha, mb);
        if (rval != QLA_SUCCESS)
-               qla_printk(KERN_WARNING, vha->hw,
+               ql_log(ql_log_warn, vha, 0x5023,
                    "IDC failed to post ACK.\n");
 }
 
@@ -393,15 +396,15 @@ skip_rio:
                break;
 
        case MBA_RESET:                 /* Reset */
-               DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n",
-                       vha->host_no));
+               ql_dbg(ql_dbg_async, vha, 0x5002,
+                   "Asynchronous RESET.\n");
 
                set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_SYSTEM_ERR:            /* System Error */
                mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox7) : 0;
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_warn, vha, 0x5003,
                    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
                    "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx);
 
@@ -409,7 +412,7 @@ skip_rio:
 
                if (IS_FWI2_CAPABLE(ha)) {
                        if (mb[1] == 0 && mb[2] == 0) {
-                               qla_printk(KERN_ERR, ha,
+                               ql_log(ql_log_fatal, vha, 0x5004,
                                    "Unrecoverable Hardware Error: adapter "
                                    "marked OFFLINE!\n");
                                vha->flags.online = 0;
@@ -422,7 +425,7 @@ skip_rio:
                                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        }
                } else if (mb[1] == 0) {
-                       qla_printk(KERN_INFO, ha,
+                       ql_log(ql_log_fatal, vha, 0x5005,
                            "Unrecoverable Hardware Error: adapter marked "
                            "OFFLINE!\n");
                        vha->flags.online = 0;
@@ -431,31 +434,27 @@ skip_rio:
                break;
 
        case MBA_REQ_TRANSFER_ERR:      /* Request Transfer Error */
-               DEBUG2(printk("scsi(%ld): ISP Request Transfer Error (%x).\n",
-                   vha->host_no, mb[1]));
-               qla_printk(KERN_WARNING, ha,
-                   "ISP Request Transfer Error (%x).\n", mb[1]);
+               ql_log(ql_log_warn, vha, 0x5006,
+                   "ISP Request Transfer Error (%x).\n",  mb[1]);
 
                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_RSP_TRANSFER_ERR:      /* Response Transfer Error */
-               DEBUG2(printk("scsi(%ld): ISP Response Transfer Error.\n",
-                   vha->host_no));
-               qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");
+               ql_log(ql_log_warn, vha, 0x5007,
+                   "ISP Response Transfer Error.\n");
 
                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                break;
 
        case MBA_WAKEUP_THRES:          /* Request Queue Wake-up */
-               DEBUG2(printk("scsi(%ld): Asynchronous WAKEUP_THRES.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_async, vha, 0x5008,
+                   "Asynchronous WAKEUP_THRES.\n");
                break;
 
        case MBA_LIP_OCCURRED:          /* Loop Initialization Procedure */
-               DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", vha->host_no,
-                   mb[1]));
-               qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]);
+               ql_log(ql_log_info, vha, 0x5009,
+                   "LIP occurred (%x).\n", mb[1]);
 
                if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
                        atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -488,10 +487,8 @@ skip_rio:
                        ha->link_data_rate = mb[1];
                }
 
-               DEBUG2(printk("scsi(%ld): Asynchronous LOOP UP (%s Gbps).\n",
-                   vha->host_no, link_speed));
-               qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n",
-                   link_speed);
+               ql_log(ql_log_info, vha, 0x500a,
+                   "LOOP UP detected (%s Gbps).\n", link_speed);
 
                vha->flags.management_server_logged_in = 0;
                qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
@@ -500,12 +497,9 @@ skip_rio:
        case MBA_LOOP_DOWN:             /* Loop Down Event */
                mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox4) : 0;
                mbx = IS_QLA82XX(ha) ? RD_REG_WORD(&reg82->mailbox_out[4]) : mbx;
-               DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
-                   "(%x %x %x %x).\n", vha->host_no, mb[1], mb[2], mb[3],
-                   mbx));
-               qla_printk(KERN_INFO, ha,
-                   "LOOP DOWN detected (%x %x %x %x).\n", mb[1], mb[2], mb[3],
-                   mbx);
+               ql_log(ql_log_info, vha, 0x500b,
+                   "LOOP DOWN detected (%x %x %x %x).\n",
+                   mb[1], mb[2], mb[3], mbx);
 
                if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
                        atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -525,9 +519,7 @@ skip_rio:
                break;
 
        case MBA_LIP_RESET:             /* LIP reset occurred */
-               DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
-                   vha->host_no, mb[1]));
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0x500c,
                    "LIP reset occurred (%x).\n", mb[1]);
 
                if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
@@ -554,14 +546,15 @@ skip_rio:
                        break;
 
                if (IS_QLA8XXX_TYPE(ha)) {
-                       DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
-                           "%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+                       ql_dbg(ql_dbg_async, vha, 0x500d,
+                           "DCBX Completed -- %04x %04x %04x.\n",
+                           mb[1], mb[2], mb[3]);
                        if (ha->notify_dcbx_comp)
                                complete(&ha->dcbx_comp);
 
                } else
-                       DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
-                           "received.\n", vha->host_no));
+                       ql_dbg(ql_dbg_async, vha, 0x500e,
+                           "Asynchronous P2P MODE received.\n");
 
                /*
                 * Until there's a transition from loop down to loop up, treat
@@ -594,10 +587,7 @@ skip_rio:
                if (IS_QLA2100(ha))
                        break;
 
-               DEBUG2(printk("scsi(%ld): Asynchronous Change In Connection "
-                   "received.\n",
-                   vha->host_no));
-               qla_printk(KERN_INFO, ha,
+               ql_log(ql_log_info, vha, 0x500f,
                    "Configuration change detected: value=%x.\n", mb[1]);
 
                if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
@@ -640,11 +630,9 @@ skip_rio:
 
                /* Global event -- port logout or port unavailable. */
                if (mb[1] == 0xffff && mb[2] == 0x7) {
-                       DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
-                           vha->host_no));
-                       DEBUG(printk(KERN_INFO
-                           "scsi(%ld): Port unavailable %04x %04x %04x.\n",
-                           vha->host_no, mb[1], mb[2], mb[3]));
+                       ql_dbg(ql_dbg_async, vha, 0x5010,
+                           "Port unavailable %04x %04x %04x.\n",
+                           mb[1], mb[2], mb[3]);
 
                        if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
                                atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -674,17 +662,15 @@ skip_rio:
                atomic_set(&vha->loop_down_timer, 0);
                if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
                    atomic_read(&vha->loop_state) != LOOP_DEAD) {
-                       DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE "
-                           "ignored %04x/%04x/%04x.\n", vha->host_no, mb[1],
-                           mb[2], mb[3]));
+                       ql_dbg(ql_dbg_async, vha, 0x5011,
+                           "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
+                           mb[1], mb[2], mb[3]);
                        break;
                }
 
-               DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
-                   vha->host_no));
-               DEBUG(printk(KERN_INFO
-                   "scsi(%ld): Port database changed %04x %04x %04x.\n",
-                   vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x5012,
+                   "Port database changed %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
 
                /*
                 * Mark all devices as missing so we will login again.
@@ -707,20 +693,17 @@ skip_rio:
                if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
                        break;
 
-               DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
-                   vha->host_no));
-               DEBUG(printk(KERN_INFO
-                   "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
-                   vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x5013,
+                   "RSCN database changed -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
 
                rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
                host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
                                | vha->d_id.b.al_pa;
                if (rscn_entry == host_pid) {
-                       DEBUG(printk(KERN_INFO
-                           "scsi(%ld): Ignoring RSCN update to local host "
-                           "port ID (%06x)\n",
-                           vha->host_no, host_pid));
+                       ql_dbg(ql_dbg_async, vha, 0x5014,
+                           "Ignoring RSCN update to local host "
+                           "port ID (%06x).\n", host_pid);
                        break;
                }
 
@@ -747,8 +730,8 @@ skip_rio:
 
        /* case MBA_RIO_RESPONSE: */
        case MBA_ZIO_RESPONSE:
-               DEBUG3(printk("scsi(%ld): [R|Z]IO update completion.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_async, vha, 0x5015,
+                   "[R|Z]IO update completion.\n");
 
                if (IS_FWI2_CAPABLE(ha))
                        qla24xx_process_response_queue(vha, rsp);
@@ -757,61 +740,68 @@ skip_rio:
                break;
 
        case MBA_DISCARD_RND_FRAME:
-               DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
-                   "%04x.\n", vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x5016,
+                   "Discard RND Frame -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
                break;
 
        case MBA_TRACE_NOTIFICATION:
-               DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
-               vha->host_no, mb[1], mb[2]));
+               ql_dbg(ql_dbg_async, vha, 0x5017,
+                   "Trace Notification -- %04x %04x.\n", mb[1], mb[2]);
                break;
 
        case MBA_ISP84XX_ALERT:
-               DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- "
-                   "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x5018,
+                   "ISP84XX Alert Notification -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
 
                spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
                switch (mb[1]) {
                case A84_PANIC_RECOVERY:
-                       qla_printk(KERN_INFO, ha, "Alert 84XX: panic recovery "
-                           "%04x %04x\n", mb[2], mb[3]);
+                       ql_log(ql_log_info, vha, 0x5019,
+                           "Alert 84XX: panic recovery %04x %04x.\n",
+                           mb[2], mb[3]);
                        break;
                case A84_OP_LOGIN_COMPLETE:
                        ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
-                           "firmware version %x\n", ha->cs84xx->op_fw_version));
+                       ql_log(ql_log_info, vha, 0x501a,
+                           "Alert 84XX: firmware version %x.\n",
+                           ha->cs84xx->op_fw_version);
                        break;
                case A84_DIAG_LOGIN_COMPLETE:
                        ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
-                           "diagnostic firmware version %x\n",
-                           ha->cs84xx->diag_fw_version));
+                       ql_log(ql_log_info, vha, 0x501b,
+                           "Alert 84XX: diagnostic firmware version %x.\n",
+                           ha->cs84xx->diag_fw_version);
                        break;
                case A84_GOLD_LOGIN_COMPLETE:
                        ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
                        ha->cs84xx->fw_update = 1;
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX: gold "
-                           "firmware version %x\n",
-                           ha->cs84xx->gold_fw_version));
+                       ql_log(ql_log_info, vha, 0x501c,
+                           "Alert 84XX: gold firmware version %x.\n",
+                           ha->cs84xx->gold_fw_version);
                        break;
                default:
-                       qla_printk(KERN_ERR, ha,
-                           "Alert 84xx: Invalid Alert %04x %04x %04x\n",
+                       ql_log(ql_log_warn, vha, 0x501d,
+                           "Alert 84xx: Invalid Alert %04x %04x %04x.\n",
                            mb[1], mb[2], mb[3]);
                }
                spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
                break;
        case MBA_DCBX_START:
-               DEBUG2(printk("scsi(%ld): DCBX Started -- %04x %04x %04x\n",
-                   vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x501e,
+                   "DCBX Started -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
                break;
        case MBA_DCBX_PARAM_UPDATE:
-               DEBUG2(printk("scsi(%ld): DCBX Parameters Updated -- "
-                   "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x501f,
+                   "DCBX Parameters Updated -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
                break;
        case MBA_FCF_CONF_ERR:
-               DEBUG2(printk("scsi(%ld): FCF Configuration Error -- "
-                   "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+               ql_dbg(ql_dbg_async, vha, 0x5020,
+                   "FCF Configuration Error -- %04x %04x %04x.\n",
+                   mb[1], mb[2], mb[3]);
                break;
        case MBA_IDC_COMPLETE:
        case MBA_IDC_NOTIFY:
@@ -838,10 +828,8 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
 
        /* Validate handle. */
        if (index >= MAX_OUTSTANDING_COMMANDS) {
-               DEBUG2(printk("scsi(%ld): Invalid SCSI completion handle %d.\n",
-                   vha->host_no, index));
-               qla_printk(KERN_WARNING, ha,
-                   "Invalid SCSI completion handle %d.\n", index);
+               ql_log(ql_log_warn, vha, 0x3014,
+                   "Invalid SCSI command index (%x).\n", index);
 
                if (IS_QLA82XX(ha))
                        set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -859,10 +847,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
                sp->cmd->result = DID_OK << 16;
                qla2x00_sp_compl(ha, sp);
        } else {
-               DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion"
-                       " handle(0x%x)\n", vha->host_no, req->id, index));
-               qla_printk(KERN_WARNING, ha,
-                   "Invalid ISP SCSI completion handle\n");
+               ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
 
                if (IS_QLA82XX(ha))
                        set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -882,8 +867,8 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
 
        index = LSW(pkt->handle);
        if (index >= MAX_OUTSTANDING_COMMANDS) {
-               qla_printk(KERN_WARNING, ha,
-                   "%s: Invalid completion handle (%x).\n", func, index);
+               ql_log(ql_log_warn, vha, 0x5031,
+                   "Invalid command index (%x).\n", index);
                if (IS_QLA82XX(ha))
                        set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
                else
@@ -892,15 +877,13 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
        }
        sp = req->outstanding_cmds[index];
        if (!sp) {
-               qla_printk(KERN_WARNING, ha,
-                   "%s: Invalid completion handle (%x) -- timed-out.\n", func,
-                   index);
+               ql_log(ql_log_warn, vha, 0x5032,
+                   "Invalid completion handle (%x) -- timed-out.\n", index);
                return sp;
        }
        if (sp->handle != index) {
-               qla_printk(KERN_WARNING, ha,
-                   "%s: SRB handle (%x) mismatch %x.\n", func, sp->handle,
-                   index);
+               ql_log(ql_log_warn, vha, 0x5033,
+                   "SRB handle (%x) mismatch %x.\n", sp->handle, index);
                return NULL;
        }
 
@@ -937,17 +920,17 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
        data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
            QLA_LOGIO_LOGIN_RETRIED : 0;
        if (mbx->entry_status) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error entry - portid=%02x%02x%02x "
+               ql_dbg(ql_dbg_async, vha, 0x5043,
+                   "Async-%s error entry - portid=%02x%02x%02x "
                    "entry-status=%x status=%x state-flag=%x "
                    "status-flags=%x.\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   fcport->d_id.b.domain, fcport->d_id.b.area,
+                   type, fcport->d_id.b.domain, fcport->d_id.b.area,
                    fcport->d_id.b.al_pa, mbx->entry_status,
                    le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
-                   le16_to_cpu(mbx->status_flags)));
+                   le16_to_cpu(mbx->status_flags));
 
-               DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));
+               ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5057,
+                   (uint8_t *)mbx, sizeof(*mbx));
 
                goto logio_done;
        }
@@ -957,12 +940,10 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
            le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
                status = 0;
        if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
-               DEBUG2(printk(KERN_DEBUG
-                   "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
-                   "mbx1=%x.\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa, le16_to_cpu(mbx->mb1)));
+               ql_dbg(ql_dbg_async, vha, 0x5045,
+                   "Async-%s complete - portid=%02x%02x%02x mbx1=%x.\n",
+                   type, fcport->d_id.b.domain, fcport->d_id.b.area,
+                   fcport->d_id.b.al_pa, le16_to_cpu(mbx->mb1));
 
                data[0] = MBS_COMMAND_COMPLETE;
                if (ctx->type == SRB_LOGIN_CMD) {
@@ -987,14 +968,14 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
                break;
        }
 
-       DEBUG2(printk(KERN_WARNING
-           "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x status=%x "
+       ql_log(ql_log_warn, vha, 0x5046,
+           "Async-%s failed - portid=%02x%02x%02x status=%x "
            "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
-           fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
+           type, fcport->d_id.b.domain,
            fcport->d_id.b.area, fcport->d_id.b.al_pa, status,
            le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
            le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
-           le16_to_cpu(mbx->mb7)));
+           le16_to_cpu(mbx->mb7));
 
 logio_done:
        lio->done(sp);
@@ -1025,9 +1006,8 @@ qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                type = "ct pass-through";
                break;
        default:
-               qla_printk(KERN_WARNING, ha,
-                   "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
-                   sp_bsg->type);
+               ql_log(ql_log_warn, vha, 0x5047,
+                   "Unrecognized SRB: (%p) type=%d.\n", sp, sp_bsg->type);
                return;
        }
 
@@ -1045,20 +1025,20 @@ qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                        bsg_job->reply->reply_payload_rcv_len =
                            le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len);
 
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "scsi(%ld): CT pass-through-%s error "
+                       ql_log(ql_log_warn, vha, 0x5048,
+                           "CT pass-through-%s error "
                            "comp_status-status=0x%x total_byte = 0x%x.\n",
-                           vha->host_no, type, comp_status,
-                           bsg_job->reply->reply_payload_rcv_len));
+                           type, comp_status,
+                           bsg_job->reply->reply_payload_rcv_len);
                } else {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "scsi(%ld): CT pass-through-%s error "
-                           "comp_status-status=0x%x.\n",
-                           vha->host_no, type, comp_status));
+                       ql_log(ql_log_warn, vha, 0x5049,
+                           "CT pass-through-%s error "
+                           "comp_status-status=0x%x.\n", type, comp_status);
                        bsg_job->reply->result = DID_ERROR << 16;
                        bsg_job->reply->reply_payload_rcv_len = 0;
                }
-               DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt)));
+               ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5058,
+                   (uint8_t *)pkt, sizeof(*pkt));
        } else {
                bsg_job->reply->result =  DID_OK << 16;
                bsg_job->reply->reply_payload_rcv_len =
@@ -1110,9 +1090,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                type = "ct pass-through";
                break;
        default:
-               qla_printk(KERN_WARNING, ha,
-                   "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
-                   sp_bsg->type);
+               ql_log(ql_log_warn, vha, 0x503e,
+                   "Unrecognized SRB: (%p) type=%d.\n", sp, sp_bsg->type);
                return;
        }
 
@@ -1132,27 +1111,31 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                        bsg_job->reply->reply_payload_rcv_len =
                                le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count);
 
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
+                       ql_log(ql_log_info, vha, 0x503f,
+                           "ELS-CT pass-through-%s error comp_status-status=0x%x "
                            "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
-                               vha->host_no, sp->handle, type, comp_status, fw_status[1], fw_status[2],
-                               le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count)));
+                           type, comp_status, fw_status[1], fw_status[2],
+                           le16_to_cpu(((struct els_sts_entry_24xx *)
+                               pkt)->total_byte_count));
                        fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
                        memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
                }
                else {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                           "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
+                       ql_log(ql_log_info, vha, 0x5040,
+                           "ELS-CT pass-through-%s error comp_status-status=0x%x "
                            "error subcode 1=0x%x error subcode 2=0x%x.\n",
-                               vha->host_no, sp->handle, type, comp_status,
-                               le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1),
-                               le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2)));
+                           type, comp_status,
+                           le16_to_cpu(((struct els_sts_entry_24xx *)
+                               pkt)->error_subcode_1),
+                           le16_to_cpu(((struct els_sts_entry_24xx *)
+                                   pkt)->error_subcode_2));
                        bsg_job->reply->result = DID_ERROR << 16;
                        bsg_job->reply->reply_payload_rcv_len = 0;
                        fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
                        memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
                }
-               DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt)));
+               ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5056,
+                               (uint8_t *)pkt, sizeof(*pkt));
        }
        else {
                bsg_job->reply->result =  DID_OK << 16;
@@ -1201,25 +1184,24 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
        data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
                QLA_LOGIO_LOGIN_RETRIED : 0;
        if (logio->entry_status) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error entry - "
+               ql_log(ql_log_warn, vha, 0x5034,
+                   "Async-%s error entry - "
                    "portid=%02x%02x%02x entry-status=%x.\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa, logio->entry_status));
-               DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio)));
+                   type, fcport->d_id.b.domain, fcport->d_id.b.area,
+                   fcport->d_id.b.al_pa, logio->entry_status);
+               ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5059,
+                   (uint8_t *)logio, sizeof(*logio));
 
                goto logio_done;
        }
 
        if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
-               DEBUG2(printk(KERN_DEBUG
-                   "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
+               ql_dbg(ql_dbg_async, vha, 0x5036,
+                   "Async-%s complete - portid=%02x%02x%02x "
                    "iop0=%x.\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   fcport->d_id.b.domain, fcport->d_id.b.area,
+                   type, fcport->d_id.b.domain, fcport->d_id.b.area,
                    fcport->d_id.b.al_pa,
-                   le32_to_cpu(logio->io_parameter[0])));
+                   le32_to_cpu(logio->io_parameter[0]));
 
                data[0] = MBS_COMMAND_COMPLETE;
                if (ctx->type != SRB_LOGIN_CMD)
@@ -1256,14 +1238,14 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
                break;
        }
 
-       DEBUG2(printk(KERN_WARNING
-           "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x comp=%x "
+       ql_dbg(ql_dbg_async, vha, 0x5037,
+           "Async-%s failed - portid=%02x%02x%02x comp=%x "
            "iop0=%x iop1=%x.\n",
-           fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
+           type, fcport->d_id.b.domain,
            fcport->d_id.b.area, fcport->d_id.b.al_pa,
            le16_to_cpu(logio->comp_status),
            le32_to_cpu(logio->io_parameter[0]),
-           le32_to_cpu(logio->io_parameter[1])));
+           le32_to_cpu(logio->io_parameter[1]));
 
 logio_done:
        lio->done(sp);
@@ -1292,38 +1274,34 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
        fcport = sp->fcport;
 
        if (sts->entry_status) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error - entry-status(%x).\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   sts->entry_status));
+               ql_log(ql_log_warn, vha, 0x5038,
+                   "Async-%s error - entry-status(%x).\n",
+                   type, sts->entry_status);
        } else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error - completion status(%x).\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   sts->comp_status));
+               ql_log(ql_log_warn, vha, 0x5039,
+                   "Async-%s error - completion status(%x).\n",
+                   type, sts->comp_status);
        } else if (!(le16_to_cpu(sts->scsi_status) &
            SS_RESPONSE_INFO_LEN_VALID)) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error - no response info(%x).\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   sts->scsi_status));
+               ql_log(ql_log_warn, vha, 0x503a,
+                   "Async-%s error - no response info(%x).\n",
+                   type, sts->scsi_status);
        } else if (le32_to_cpu(sts->rsp_data_len) < 4) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error - not enough response(%d).\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   sts->rsp_data_len));
+               ql_log(ql_log_warn, vha, 0x503b,
+                   "Async-%s error - not enough response(%d).\n",
+                   type, sts->rsp_data_len);
        } else if (sts->data[3]) {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld:%x): Async-%s error - response(%x).\n",
-                   fcport->vha->host_no, sp->handle, type,
-                   sts->data[3]));
+               ql_log(ql_log_warn, vha, 0x503c,
+                   "Async-%s error - response(%x).\n",
+                   type, sts->data[3]);
        } else {
                error = 0;
        }
 
        if (error) {
                iocb->u.tmf.data = error;
-               DEBUG2(qla2x00_dump_buffer((uint8_t *)sts, sizeof(*sts)));
+               ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055,
+                   (uint8_t *)sts, sizeof(*sts));
        }
 
        iocb->done(sp);
@@ -1360,8 +1338,8 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
                }
 
                if (pkt->entry_status != 0) {
-                       DEBUG3(printk(KERN_INFO
-                           "scsi(%ld): Process error entry.\n", vha->host_no));
+                       ql_log(ql_log_warn, vha, 0x5035,
+                           "Process error entry.\n");
 
                        qla2x00_error_entry(vha, rsp, pkt);
                        ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -1399,10 +1377,10 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
                        break;
                default:
                        /* Type Not Supported. */
-                       DEBUG4(printk(KERN_WARNING
-                           "scsi(%ld): Received unknown response pkt type %x "
+                       ql_log(ql_log_warn, vha, 0x504a,
+                           "Received unknown response pkt type %x "
                            "entry status=%x.\n",
-                           vha->host_no, pkt->entry_type, pkt->entry_status));
+                           pkt->entry_type, pkt->entry_status);
                        break;
                }
                ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -1418,6 +1396,7 @@ static inline void
 qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
     uint32_t sense_len, struct rsp_que *rsp)
 {
+       struct scsi_qla_host *vha = sp->fcport->vha;
        struct scsi_cmnd *cp = sp->cmd;
 
        if (sense_len >= SCSI_SENSE_BUFFERSIZE)
@@ -1435,11 +1414,13 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
        if (sp->request_sense_length != 0)
                rsp->status_srb = sp;
 
-       DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
-           "cmd=%p\n", __func__, sp->fcport->vha->host_no,
-           cp->device->channel, cp->device->id, cp->device->lun, cp));
+       ql_dbg(ql_dbg_io, vha, 0x301c,
+           "Check condition Sense data, scsi(%ld:%d:%d:%d) cmd=%p.\n",
+           sp->fcport->vha->host_no, cp->device->channel, cp->device->id,
+           cp->device->lun, cp);
        if (sense_len)
-               DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len));
+               ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b,
+                   cp->sense_buffer, sense_len);
 }
 
 struct scsi_dif_tuple {
@@ -1457,6 +1438,7 @@ struct scsi_dif_tuple {
 static inline void
 qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
 {
+       struct scsi_qla_host *vha = sp->fcport->vha;
        struct scsi_cmnd *cmd = sp->cmd;
        struct scsi_dif_tuple   *ep =
                        (struct scsi_dif_tuple *)&sts24->data[20];
@@ -1473,15 +1455,15 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
        e_guard = be16_to_cpu(ep->guard);
        a_guard = be16_to_cpu(ap->guard);
 
-       DEBUG18(printk(KERN_DEBUG
-           "%s(): iocb(s) %p Returned STATUS\n", __func__, sts24));
+       ql_dbg(ql_dbg_io, vha, 0x3023,
+           "iocb(s) %p Returned STATUS.\n", sts24);
 
-       DEBUG18(printk(KERN_ERR "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
+       ql_dbg(ql_dbg_io, vha, 0x3024,
+           "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
            " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app"
-           " tag=0x%x, act guard=0x%x, exp guard=0x%x\n",
+           " tag=0x%x, act guard=0x%x, exp guard=0x%x.\n",
            cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
-           a_app_tag, e_app_tag, a_guard, e_guard));
-
+           a_app_tag, e_app_tag, a_guard, e_guard);
 
        /* check guard */
        if (e_guard != a_guard) {
@@ -1569,9 +1551,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                sp = NULL;
 
        if (sp == NULL) {
-               qla_printk(KERN_WARNING, ha,
-                   "scsi(%ld): Invalid status handle (0x%x).\n", vha->host_no,
-                   sts->handle);
+               ql_log(ql_log_warn, vha, 0x3017,
+                   "Invalid status handle (0x%x).\n", sts->handle);
 
                if (IS_QLA82XX(ha))
                        set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -1582,9 +1563,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
        }
        cp = sp->cmd;
        if (cp == NULL) {
-               qla_printk(KERN_WARNING, ha,
-                   "scsi(%ld): Command already returned (0x%x/%p).\n",
-                   vha->host_no, sts->handle, sp);
+               ql_log(ql_log_warn, vha, 0x3018,
+                   "Command already returned (0x%x/%p).\n",
+                   sts->handle, sp);
 
                return;
        }
@@ -1629,10 +1610,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                        par_sense_len -= rsp_info_len;
                }
                if (rsp_info_len > 3 && rsp_info[3]) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "scsi(%ld:%d:%d): FCP I/O protocol failure "
-                           "(0x%x/0x%x).\n", vha->host_no, cp->device->id,
-                           cp->device->lun, rsp_info_len, rsp_info[3]));
+                       ql_log(ql_log_warn, vha, 0x3019,
+                           "FCP I/O protocol failure (0x%x/0x%x).\n",
+                           rsp_info_len, rsp_info[3]);
 
                        cp->result = DID_BUS_BUSY << 16;
                        goto out;
@@ -1661,11 +1641,10 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                        if (!lscsi_status &&
                            ((unsigned)(scsi_bufflen(cp) - resid) <
                             cp->underflow)) {
-                               qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld:%d:%d): Mid-layer underflow "
+                               ql_log(ql_log_warn, vha, 0x301a,
+                                   "Mid-layer underflow "
                                    "detected (0x%x of 0x%x bytes).\n",
-                                   vha->host_no, cp->device->id,
-                                   cp->device->lun, resid, scsi_bufflen(cp));
+                                   resid, scsi_bufflen(cp));
 
                                cp->result = DID_ERROR << 16;
                                break;
@@ -1674,9 +1653,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                cp->result = DID_OK << 16 | lscsi_status;
 
                if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "scsi(%ld:%d:%d) QUEUE FULL detected.\n",
-                           vha->host_no, cp->device->id, cp->device->lun));
+                       ql_log(ql_log_warn, vha, 0x301b,
+                           "QUEUE FULL detected.\n");
                        break;
                }
                logit = 0;
@@ -1697,11 +1675,10 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                scsi_set_resid(cp, resid);
                if (scsi_status & SS_RESIDUAL_UNDER) {
                        if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
-                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld:%d:%d) Dropped frame(s) detected "
-                                   "(0x%x of 0x%x bytes).\n", vha->host_no,
-                                   cp->device->id, cp->device->lun, resid,
-                                   scsi_bufflen(cp)));
+                               ql_log(ql_log_warn, vha, 0x301d,
+                                   "Dropped frame(s) detected "
+                                   "(0x%x of 0x%x bytes).\n",
+                                   resid, scsi_bufflen(cp));
 
                                cp->result = DID_ERROR << 16 | lscsi_status;
                                break;
@@ -1710,20 +1687,18 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
                        if (!lscsi_status &&
                            ((unsigned)(scsi_bufflen(cp) - resid) <
                            cp->underflow)) {
-                               qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld:%d:%d): Mid-layer underflow "
+                               ql_log(ql_log_warn, vha, 0x301e,
+                                   "Mid-layer underflow "
                                    "detected (0x%x of 0x%x bytes).\n",
-                                   vha->host_no, cp->device->id,
-                                   cp->device->lun, resid, scsi_bufflen(cp));
+                                   resid, scsi_bufflen(cp));
 
                                cp->result = DID_ERROR << 16;
                                break;
                        }
                } else {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "scsi(%ld:%d:%d) Dropped frame(s) detected (0x%x "
-                           "of 0x%x bytes).\n", vha->host_no, cp->device->id,
-                           cp->device->lun, resid, scsi_bufflen(cp)));
+                       ql_log(ql_log_warn, vha, 0x301f,
+                           "Dropped frame(s) detected (0x%x "
+                           "of 0x%x bytes).\n", resid, scsi_bufflen(cp));
 
                        cp->result = DID_ERROR << 16 | lscsi_status;
                        goto check_scsi_status;
@@ -1739,10 +1714,8 @@ check_scsi_status:
                 */
                if (lscsi_status != 0) {
                        if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
-                               DEBUG2(qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld:%d:%d) QUEUE FULL detected.\n",
-                                   vha->host_no, cp->device->id,
-                                   cp->device->lun));
+                               ql_log(ql_log_warn, vha, 0x3020,
+                                   "QUEUE FULL detected.\n");
                                logit = 1;
                                break;
                        }
@@ -1781,10 +1754,9 @@ check_scsi_status:
                                break;
                }
 
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                       "scsi(%ld:%d:%d) Port down status: port-state=0x%x\n",
-                       vha->host_no, cp->device->id, cp->device->lun,
-                       atomic_read(&fcport->state)));
+               ql_dbg(ql_dbg_io, vha, 0x3021,
+                   "Port down status: port-state=0x%x.\n",
+                   atomic_read(&fcport->state));
 
                if (atomic_read(&fcport->state) == FCS_ONLINE)
                        qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
@@ -1804,15 +1776,13 @@ check_scsi_status:
 
 out:
        if (logit)
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "scsi(%ld:%d:%d) FCP command status: 0x%x-0x%x (0x%x) "
-                   "portid=%02x%02x%02x oxid=0x%x cdb=%02x%02x%02x len=0x%x "
-                   "rsp_info=0x%x resid=0x%x fw_resid=0x%x\n", vha->host_no,
-                   cp->device->id, cp->device->lun, comp_status, scsi_status,
-                   cp->result, fcport->d_id.b.domain, fcport->d_id.b.area,
-                   fcport->d_id.b.al_pa, ox_id, cp->cmnd[0], cp->cmnd[1],
-                   cp->cmnd[2], scsi_bufflen(cp), rsp_info_len, resid_len,
-                   fw_resid_len));
+               ql_dbg(ql_dbg_io, vha, 0x3022,
+                   "FCP command status: 0x%x-0x%x (0x%x) "
+                   "oxid=0x%x cdb=%02x%02x%02x len=0x%x "
+                   "rsp_info=0x%x resid=0x%x fw_resid=0x%x.\n",
+                   comp_status, scsi_status, cp->result, ox_id, cp->cmnd[0],
+                   cp->cmnd[1], cp->cmnd[2], scsi_bufflen(cp), rsp_info_len,
+                   resid_len, fw_resid_len);
 
        if (rsp->status_srb == NULL)
                qla2x00_sp_compl(ha, sp);
@@ -1830,16 +1800,15 @@ qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
 {
        uint8_t         sense_sz = 0;
        struct qla_hw_data *ha = rsp->hw;
+       struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
        srb_t           *sp = rsp->status_srb;
        struct scsi_cmnd *cp;
 
        if (sp != NULL && sp->request_sense_length != 0) {
                cp = sp->cmd;
                if (cp == NULL) {
-                       DEBUG2(printk("%s(): Cmd already returned back to OS "
-                           "sp=%p.\n", __func__, sp));
-                       qla_printk(KERN_INFO, ha,
-                           "cmd is NULL: already returned to OS (sp=%p)\n",
+                       ql_log(ql_log_warn, vha, 0x3025,
+                           "cmd is NULL: already returned to OS (sp=%p).\n",
                            sp);
 
                        rsp->status_srb = NULL;
@@ -1856,7 +1825,8 @@ qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
                if (IS_FWI2_CAPABLE(ha))
                        host_to_fcp_swap(pkt->data, sizeof(pkt->data));
                memcpy(sp->request_sense_ptr, pkt->data, sense_sz);
-               DEBUG5(qla2x00_dump_buffer(sp->request_sense_ptr, sense_sz));
+               ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c,
+                       sp->request_sense_ptr, sense_sz);
 
                sp->request_sense_ptr += sense_sz;
                sp->request_sense_length -= sense_sz;
@@ -1882,21 +1852,25 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
        uint32_t handle = LSW(pkt->handle);
        uint16_t que = MSW(pkt->handle);
        struct req_que *req = ha->req_q_map[que];
-#if defined(QL_DEBUG_LEVEL_2)
+
        if (pkt->entry_status & RF_INV_E_ORDER)
-               qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__);
+               ql_dbg(ql_dbg_async, vha, 0x502a,
+                   "Invalid Entry Order.\n");
        else if (pkt->entry_status & RF_INV_E_COUNT)
-               qla_printk(KERN_ERR, ha, "%s: Invalid Entry Count\n", __func__);
+               ql_dbg(ql_dbg_async, vha, 0x502b,
+                   "Invalid Entry Count.\n");
        else if (pkt->entry_status & RF_INV_E_PARAM)
-               qla_printk(KERN_ERR, ha,
-                   "%s: Invalid Entry Parameter\n", __func__);
+               ql_dbg(ql_dbg_async, vha, 0x502c,
+                   "Invalid Entry Parameter.\n");
        else if (pkt->entry_status & RF_INV_E_TYPE)
-               qla_printk(KERN_ERR, ha, "%s: Invalid Entry Type\n", __func__);
+               ql_dbg(ql_dbg_async, vha, 0x502d,
+                   "Invalid Entry Type.\n");
        else if (pkt->entry_status & RF_BUSY)
-               qla_printk(KERN_ERR, ha, "%s: Busy\n", __func__);
+               ql_dbg(ql_dbg_async, vha, 0x502e,
+                   "Busy.\n");
        else
-               qla_printk(KERN_ERR, ha, "%s: UNKNOWN flag error\n", __func__);
-#endif
+               ql_dbg(ql_dbg_async, vha, 0x502f,
+                   "UNKNOWN flag error.\n");
 
        /* Validate handle. */
        if (handle < MAX_OUTSTANDING_COMMANDS)
@@ -1923,10 +1897,8 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
        } else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type ==
                COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7
                || pkt->entry_type == COMMAND_TYPE_6) {
-               DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n",
-                       vha->host_no));
-               qla_printk(KERN_WARNING, ha,
-                       "Error entry - invalid handle\n");
+               ql_log(ql_log_warn, vha, 0x5030,
+                   "Error entry - invalid handle.\n");
 
                if (IS_QLA82XX(ha))
                        set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -1960,11 +1932,11 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
        }
 
        if (ha->mcp) {
-               DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
-                   __func__, vha->host_no, ha->mcp->mb[0]));
+               ql_dbg(ql_dbg_async, vha, 0x504d,
+                   "Got mailbox completion. cmd=%x.\n", ha->mcp->mb[0]);
        } else {
-               DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
-                   __func__, vha->host_no));
+               ql_dbg(ql_dbg_async, vha, 0x504e,
+                   "MBX pointer ERROR.\n");
        }
 }
 
@@ -1993,8 +1965,8 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
                }
 
                if (pkt->entry_status != 0) {
-                       DEBUG3(printk(KERN_INFO
-                           "scsi(%ld): Process error entry.\n", vha->host_no));
+                       ql_dbg(ql_dbg_async, vha, 0x5029,
+                           "Process error entry.\n");
 
                        qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
                        ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -2030,10 +2002,10 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
                        break;
                default:
                        /* Type Not Supported. */
-                       DEBUG4(printk(KERN_WARNING
-                           "scsi(%ld): Received unknown response pkt type %x "
+                       ql_dbg(ql_dbg_async, vha, 0x5042,
+                           "Received unknown response pkt type %x "
                            "entry status=%x.\n",
-                           vha->host_no, pkt->entry_type, pkt->entry_status));
+                           pkt->entry_type, pkt->entry_status);
                        break;
                }
                ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
@@ -2088,7 +2060,8 @@ qla2xxx_check_risc_status(scsi_qla_host_t *vha)
 
 next_test:
        if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)
-               qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n");
+               ql_log(ql_log_info, vha, 0x504c,
+                   "Additional code -- 0x55AA.\n");
 
 done:
        WRT_REG_DWORD(&reg->iobase_window, 0x0000);
@@ -2121,7 +2094,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                   "%s(): NULL response queue pointer\n", __func__);
+                   "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
 
@@ -2142,8 +2115,9 @@ qla24xx_intr_handler(int irq, void *dev_id)
 
                        hccr = RD_REG_DWORD(&reg->hccr);
 
-                       qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
-                           "Dumping firmware!\n", hccr);
+                       ql_log(ql_log_warn, vha, 0x504b,
+                           "RISC paused -- HCCR=%x, Dumping firmware.\n",
+                           hccr);
 
                        qla2xxx_check_risc_status(vha);
 
@@ -2174,9 +2148,8 @@ qla24xx_intr_handler(int irq, void *dev_id)
                        qla24xx_process_response_queue(vha, rsp);
                        break;
                default:
-                       DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
-                           "(%d).\n",
-                           vha->host_no, stat & 0xff));
+                       ql_dbg(ql_dbg_async, vha, 0x504f,
+                           "Unrecognized interrupt type (%d).\n", stat * 0xff);
                        break;
                }
                WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
@@ -2205,7 +2178,7 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-               "%s(): NULL response queue pointer\n", __func__);
+               "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
        ha = rsp->hw;
@@ -2235,7 +2208,7 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                       "%s(): NULL response queue pointer\n", __func__);
+                       "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
        ha = rsp->hw;
@@ -2268,8 +2241,8 @@ qla24xx_msix_default(int irq, void *dev_id)
 
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
-               DEBUG(printk(
-               "%s(): NULL response queue pointer\n", __func__));
+               printk(KERN_INFO
+                       "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
        ha = rsp->hw;
@@ -2286,8 +2259,9 @@ qla24xx_msix_default(int irq, void *dev_id)
 
                        hccr = RD_REG_DWORD(&reg->hccr);
 
-                       qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
-                           "Dumping firmware!\n", hccr);
+                       ql_log(ql_log_info, vha, 0x5050,
+                           "RISC paused -- HCCR=%x, Dumping firmware.\n",
+                           hccr);
 
                        qla2xxx_check_risc_status(vha);
 
@@ -2318,9 +2292,8 @@ qla24xx_msix_default(int irq, void *dev_id)
                        qla24xx_process_response_queue(vha, rsp);
                        break;
                default:
-                       DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
-                           "(%d).\n",
-                           vha->host_no, stat & 0xff));
+                       ql_dbg(ql_dbg_async, vha, 0x5051,
+                           "Unrecognized interrupt type (%d).\n", stat & 0xff);
                        break;
                }
                WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
@@ -2358,6 +2331,7 @@ qla24xx_disable_msix(struct qla_hw_data *ha)
 {
        int i;
        struct qla_msix_entry *qentry;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        for (i = 0; i < ha->msix_count; i++) {
                qentry = &ha->msix_entries[i];
@@ -2368,6 +2342,8 @@ qla24xx_disable_msix(struct qla_hw_data *ha)
        kfree(ha->msix_entries);
        ha->msix_entries = NULL;
        ha->flags.msix_enabled = 0;
+       ql_dbg(ql_dbg_init, vha, 0x0042,
+           "Disabled the MSI.\n");
 }
 
 static int
@@ -2377,11 +2353,15 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
        int i, ret;
        struct msix_entry *entries;
        struct qla_msix_entry *qentry;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count,
                        GFP_KERNEL);
-       if (!entries)
+       if (!entries) {
+               ql_log(ql_log_warn, vha, 0x00bc,
+                   "Failed to allocate memory for msix_entry.\n");
                return -ENOMEM;
+       }
 
        for (i = 0; i < ha->msix_count; i++)
                entries[i].entry = i;
@@ -2391,16 +2371,18 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
                if (ret < MIN_MSIX_COUNT)
                        goto msix_failed;
 
-               qla_printk(KERN_WARNING, ha,
-                       "MSI-X: Failed to enable support -- %d/%d\n"
-                       " Retry with %d vectors\n", ha->msix_count, ret, ret);
+               ql_log(ql_log_warn, vha, 0x00c6,
+                   "MSI-X: Failed to enable support "
+                   "-- %d/%d\n Retry with %d vectors.\n",
+                   ha->msix_count, ret, ret);
                ha->msix_count = ret;
                ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
                if (ret) {
 msix_failed:
-                       qla_printk(KERN_WARNING, ha, "MSI-X: Failed to enable"
-                               " support, giving up -- %d/%d\n",
-                               ha->msix_count, ret);
+                       ql_log(ql_log_fatal, vha, 0x00c7,
+                           "MSI-X: Failed to enable support, "
+                           "giving   up -- %d/%d.\n",
+                           ha->msix_count, ret);
                        goto msix_out;
                }
                ha->max_rsp_queues = ha->msix_count - 1;
@@ -2408,6 +2390,8 @@ msix_failed:
        ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
                                ha->msix_count, GFP_KERNEL);
        if (!ha->msix_entries) {
+               ql_log(ql_log_fatal, vha, 0x00c8,
+                   "Failed to allocate memory for ha->msix_entries.\n");
                ret = -ENOMEM;
                goto msix_out;
        }
@@ -2434,9 +2418,9 @@ msix_failed:
                                0, msix_entries[i].name, rsp);
                }
                if (ret) {
-                       qla_printk(KERN_WARNING, ha,
-                       "MSI-X: Unable to register handler -- %x/%d.\n",
-                       qentry->vector, ret);
+                       ql_log(ql_log_fatal, vha, 0x00cb,
+                           "MSI-X: unable to register handler -- %x/%d.\n",
+                           qentry->vector, ret);
                        qla24xx_disable_msix(ha);
                        ha->mqenable = 0;
                        goto msix_out;
@@ -2449,6 +2433,12 @@ msix_failed:
        /* Enable MSI-X vector for response queue update for queue 0 */
        if (ha->mqiobase &&  (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
                ha->mqenable = 1;
+       ql_dbg(ql_dbg_multiq, vha, 0xc005,
+           "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
+           ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
+       ql_dbg(ql_dbg_init, vha, 0x0055,
+           "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
+           ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
 
 msix_out:
        kfree(entries);
@@ -2460,6 +2450,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
 {
        int ret;
        device_reg_t __iomem *reg = ha->iobase;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        /* If possible, enable MSI-X. */
        if (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
@@ -2470,30 +2461,30 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
                (ha->pdev->subsystem_device == 0x7040 ||
                ha->pdev->subsystem_device == 0x7041 ||
                ha->pdev->subsystem_device == 0x1705)) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                       "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X,0x%X).\n",
+               ql_log(ql_log_warn, vha, 0x0034,
+                   "MSI-X: Unsupported ISP 2432 SSVID/SSDID (0x%X,0x%X).\n",
                        ha->pdev->subsystem_vendor,
-                       ha->pdev->subsystem_device));
+                       ha->pdev->subsystem_device);
                goto skip_msi;
        }
 
        if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
                !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-               "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
-                       ha->pdev->revision, ha->fw_attributes));
+               ql_log(ql_log_warn, vha, 0x0035,
+                   "MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n",
+                   ha->pdev->revision, ha->fw_attributes);
                goto skip_msix;
        }
 
        ret = qla24xx_enable_msix(ha, rsp);
        if (!ret) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,
-                   ha->fw_attributes));
+               ql_dbg(ql_dbg_init, vha, 0x0036,
+                   "MSI-X: Enabled (0x%X, 0x%X).\n",
+                   ha->chip_revision, ha->fw_attributes);
                goto clear_risc_ints;
        }
-       qla_printk(KERN_WARNING, ha,
-           "MSI-X: Falling back-to MSI mode -- %d.\n", ret);
+       ql_log(ql_log_info, vha, 0x0037,
+           "MSI-X Falling back-to MSI mode -%d.\n", ret);
 skip_msix:
 
        if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
@@ -2502,18 +2493,19 @@ skip_msix:
 
        ret = pci_enable_msi(ha->pdev);
        if (!ret) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
+               ql_dbg(ql_dbg_init, vha, 0x0038,
+                   "MSI: Enabled.\n");
                ha->flags.msi_enabled = 1;
        } else
-               qla_printk(KERN_WARNING, ha,
-                   "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
+               ql_log(ql_log_warn, vha, 0x0039,
+                   "MSI-X; Falling back-to INTa mode -- %d.\n", ret);
 skip_msi:
 
        ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
            ha->flags.msi_enabled ? 0 : IRQF_SHARED,
            QLA2XXX_DRIVER_NAME, rsp);
        if (ret) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x003a,
                    "Failed to reserve interrupt %d already in use.\n",
                    ha->pdev->irq);
                goto fail;
@@ -2563,13 +2555,14 @@ int qla25xx_request_irq(struct rsp_que *rsp)
        struct qla_hw_data *ha = rsp->hw;
        struct qla_init_msix_entry *intr = &msix_entries[2];
        struct qla_msix_entry *msix = rsp->msix;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        int ret;
 
        ret = request_irq(msix->vector, intr->handler, 0, intr->name, rsp);
        if (ret) {
-               qla_printk(KERN_WARNING, ha,
-                       "MSI-X: Unable to register handler -- %x/%d.\n",
-                       msix->vector, ret);
+               ql_log(ql_log_fatal, vha, 0x00e6,
+                   "MSI-X: Unable to register handler -- %x/%d.\n",
+                   msix->vector, ret);
                return ret;
        }
        msix->have_irq = 1;
index c26f0acdfeccd94a58edaa015772c0a81d6848b6..f7604ea1af836b58e10d587be15d15283301e3da 100644 (file)
@@ -46,14 +46,18 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        struct qla_hw_data *ha = vha->hw;
        scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
-       if (ha->pdev->error_state > pci_channel_io_frozen)
+       ql_dbg(ql_dbg_mbx, base_vha, 0x1000, "Entered %s.\n", __func__);
+
+       if (ha->pdev->error_state > pci_channel_io_frozen) {
+               ql_log(ql_log_warn, base_vha, 0x1001,
+                   "error_state is greater than pci_channel_io_frozen, "
+                   "exiting.\n");
                return QLA_FUNCTION_TIMEOUT;
+       }
 
        if (vha->device_flags & DFLG_DEV_FAILED) {
-               DEBUG2_3_11(qla_printk(KERN_WARNING, ha,
-                       "%s(%ld): Device in failed state, "
-                       "timeout MBX Exiting.\n",
-                       __func__, base_vha->host_no));
+               ql_log(ql_log_warn, base_vha, 0x1002,
+                   "Device in failed state, exiting.\n");
                return QLA_FUNCTION_TIMEOUT;
        }
 
@@ -63,17 +67,18 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        rval = QLA_SUCCESS;
        abort_active = test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, base_vha->host_no));
 
        if (ha->flags.pci_channel_io_perm_failure) {
-               DEBUG(printk("%s(%ld): Perm failure on EEH, timeout MBX "
-                            "Exiting.\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, base_vha, 0x1003,
+                   "Perm failure on EEH timeout MBX, exiting.\n");
                return QLA_FUNCTION_TIMEOUT;
        }
 
        if (ha->flags.isp82xx_fw_hung) {
                /* Setting Link-Down error */
                mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+               ql_log(ql_log_warn, base_vha, 0x1004,
+                   "FW hung = %d.\n", ha->flags.isp82xx_fw_hung);
                rval = QLA_FUNCTION_FAILED;
                goto premature_exit;
        }
@@ -85,8 +90,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
         */
        if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, mcp->tov * HZ)) {
                /* Timeout occurred. Return error. */
-               DEBUG2_3_11(printk("%s(%ld): cmd access timeout. "
-                   "Exiting.\n", __func__, base_vha->host_no));
+               ql_log(ql_log_warn, base_vha, 0x1005,
+                   "Cmd access timeout, Exiting.\n");
                return QLA_FUNCTION_TIMEOUT;
        }
 
@@ -94,8 +99,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        /* Save mailbox command for debug */
        ha->mcp = mcp;
 
-       DEBUG11(printk("scsi(%ld): prepare to issue mbox cmd=0x%x.\n",
-           base_vha->host_no, mcp->mb[0]));
+       ql_dbg(ql_dbg_mbx, base_vha, 0x1006,
+           "Prepare to issue mbox cmd=0x%x.\n", mcp->mb[0]);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
@@ -123,27 +128,30 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                iptr++;
        }
 
-#if defined(QL_DEBUG_LEVEL_1)
-       printk("%s(%ld): Loaded MBX registers (displayed in bytes) = \n",
-           __func__, base_vha->host_no);
-       qla2x00_dump_buffer((uint8_t *)mcp->mb, 16);
-       printk("\n");
-       qla2x00_dump_buffer(((uint8_t *)mcp->mb + 0x10), 16);
-       printk("\n");
-       qla2x00_dump_buffer(((uint8_t *)mcp->mb + 0x20), 8);
-       printk("\n");
-       printk("%s(%ld): I/O address = %p.\n", __func__, base_vha->host_no,
-               optr);
-       qla2x00_dump_regs(base_vha);
-#endif
+       ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1111,
+           "Loaded MBX registers (displayed in bytes) =.\n");
+       ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1112,
+           (uint8_t *)mcp->mb, 16);
+       ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1113,
+           ".\n");
+       ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1114,
+           ((uint8_t *)mcp->mb + 0x10), 16);
+       ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1115,
+           ".\n");
+       ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1116,
+           ((uint8_t *)mcp->mb + 0x20), 8);
+       ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1117,
+           "I/O Address = %p.\n", optr);
+       ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x100e);
 
        /* Issue set host interrupt command to send cmd out. */
        ha->flags.mbox_int = 0;
        clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
 
        /* Unlock mbx registers and wait for interrupt */
-       DEBUG11(printk("%s(%ld): going to unlock irq & waiting for interrupt. "
-           "jiffies=%lx.\n", __func__, base_vha->host_no, jiffies));
+       ql_dbg(ql_dbg_mbx, base_vha, 0x100f,
+           "Going to unlock irq & waiting for interrupts. "
+           "jiffies=%lx.\n", jiffies);
 
        /* Wait for mbx cmd completion until timeout */
 
@@ -155,9 +163,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                                HINT_MBX_INT_PENDING) {
                                spin_unlock_irqrestore(&ha->hardware_lock,
                                        flags);
-                               DEBUG2_3_11(printk(KERN_INFO
-                                   "%s(%ld): Pending Mailbox timeout. "
-                                   "Exiting.\n", __func__, base_vha->host_no));
+                               ql_dbg(ql_dbg_mbx, base_vha, 0x1010,
+                                   "Pending mailbox timeout, exiting.\n");
                                rval = QLA_FUNCTION_TIMEOUT;
                                goto premature_exit;
                        }
@@ -173,17 +180,16 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
 
        } else {
-               DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
-                   base_vha->host_no, command));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x1011,
+                   "Cmd=%x Polling Mode.\n", command);
 
                if (IS_QLA82XX(ha)) {
                        if (RD_REG_DWORD(&reg->isp82.hint) &
                                HINT_MBX_INT_PENDING) {
                                spin_unlock_irqrestore(&ha->hardware_lock,
                                        flags);
-                               DEBUG2_3_11(printk(KERN_INFO
-                                   "%s(%ld): Pending Mailbox timeout. "
-                                   "Exiting.\n", __func__, base_vha->host_no));
+                               ql_dbg(ql_dbg_mbx, base_vha, 0x1012,
+                                   "Pending mailbox timeout, exiting.\n");
                                rval = QLA_FUNCTION_TIMEOUT;
                                goto premature_exit;
                        }
@@ -207,17 +213,17 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                            command == MBC_LOAD_RISC_RAM_EXTENDED))
                                msleep(10);
                } /* while */
-               DEBUG17(qla_printk(KERN_WARNING, ha,
-                       "Waited %d sec\n",
-                       (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ)));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x1013,
+                   "Waited %d sec.\n",
+                   (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ));
        }
 
        /* Check whether we timed out */
        if (ha->flags.mbox_int) {
                uint16_t *iptr2;
 
-               DEBUG3_11(printk("%s(%ld): cmd %x completed.\n", __func__,
-                   base_vha->host_no, command));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x1014,
+                   "Cmd=%x completed.\n", command);
 
                /* Got interrupt. Clear the flag. */
                ha->flags.mbox_int = 0;
@@ -229,6 +235,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                        mcp->mb[0] = MBS_LINK_DOWN_ERROR;
                        ha->mcp = NULL;
                        rval = QLA_FUNCTION_FAILED;
+                       ql_log(ql_log_warn, base_vha, 0x1015,
+                           "FW hung = %d.\n", ha->flags.isp82xx_fw_hung);
                        goto premature_exit;
                }
 
@@ -249,8 +257,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                }
        } else {
 
-#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) || \
-               defined(QL_DEBUG_LEVEL_11)
                uint16_t mb0;
                uint32_t ictrl;
 
@@ -261,14 +267,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                        mb0 = RD_MAILBOX_REG(ha, &reg->isp, 0);
                        ictrl = RD_REG_WORD(&reg->isp.ictrl);
                }
-               printk("%s(%ld): **** MB Command Timeout for cmd %x ****\n",
-                   __func__, base_vha->host_no, command);
-               printk("%s(%ld): icontrol=%x jiffies=%lx\n", __func__,
-                   base_vha->host_no, ictrl, jiffies);
-               printk("%s(%ld): *** mailbox[0] = 0x%x ***\n", __func__,
-                   base_vha->host_no, mb0);
-               qla2x00_dump_regs(base_vha);
-#endif
+               ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1119,
+                   "MBX Command timeout for cmd %x.\n", command);
+               ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x111a,
+                   "iocontrol=%x jiffies=%lx.\n", ictrl, jiffies);
+               ql_dbg(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x111b,
+                   "mb[0] = 0x%x.\n", mb0);
+               ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, base_vha, 0x1019);
 
                rval = QLA_FUNCTION_TIMEOUT;
        }
@@ -279,8 +284,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
        ha->mcp = NULL;
 
        if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) {
-               DEBUG11(printk("%s(%ld): checking for additional resp "
-                   "interrupt.\n", __func__, base_vha->host_no));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x101a,
+                   "Checking for additional resp interrupt.\n");
 
                /* polling mode for non isp_abort commands. */
                qla2x00_poll(ha->rsp_q_map[0]);
@@ -291,38 +296,32 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                if (!io_lock_on || (mcp->flags & IOCTL_CMD) ||
                    ha->flags.eeh_busy) {
                        /* not in dpc. schedule it for dpc to take over. */
-                       DEBUG(printk("%s(%ld): timeout schedule "
-                       "isp_abort_needed.\n", __func__,
-                       base_vha->host_no));
-                       DEBUG2_3_11(printk("%s(%ld): timeout schedule "
-                       "isp_abort_needed.\n", __func__,
-                       base_vha->host_no));
+                       ql_dbg(ql_dbg_mbx, base_vha, 0x101b,
+                           "Timeout, schedule isp_abort_needed.\n");
 
                        if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
                            !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
                            !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
 
-                               qla_printk(KERN_WARNING, ha,
-                                   "Mailbox command timeout occurred. "
-                                   "Scheduling ISP " "abort. eeh_busy: 0x%x\n",
-                                   ha->flags.eeh_busy);
+                               ql_log(ql_log_info, base_vha, 0x101c,
+                                   "Mailbox cmd timeout occured. "
+                                   "Scheduling ISP abort eeh_busy=0x%x.\n",
+                                       ha->flags.eeh_busy);
                                set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                                qla2xxx_wake_dpc(vha);
                        }
                } else if (!abort_active) {
                        /* call abort directly since we are in the DPC thread */
-                       DEBUG(printk("%s(%ld): timeout calling abort_isp\n",
-                           __func__, base_vha->host_no));
-                       DEBUG2_3_11(printk("%s(%ld): timeout calling "
-                           "abort_isp\n", __func__, base_vha->host_no));
+                       ql_dbg(ql_dbg_mbx, base_vha, 0x101d,
+                           "Timeout, calling abort_isp.\n");
 
                        if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
                            !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
                            !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
 
-                               qla_printk(KERN_WARNING, ha,
-                                   "Mailbox command timeout occurred. "
-                                   "Issuing ISP abort.\n");
+                               ql_log(ql_log_info, base_vha, 0x101e,
+                                   "Mailbox cmd timeout occured. "
+                                   "Scheduling ISP abort.\n");
 
                                set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
                                clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -332,11 +331,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
                                            &vha->dpc_flags);
                                }
                                clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
-                               DEBUG(printk("%s(%ld): finished abort_isp\n",
-                                   __func__, vha->host_no));
-                               DEBUG2_3_11(printk(
-                                   "%s(%ld): finished abort_isp\n",
-                                   __func__, vha->host_no));
+                               ql_dbg(ql_dbg_mbx, base_vha, 0x101f,
+                                   "Finished abort_isp.\n");
                        }
                }
        }
@@ -346,12 +342,11 @@ premature_exit:
        complete(&ha->mbx_cmd_comp);
 
        if (rval) {
-               DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, "
-                   "mbx2=%x, cmd=%x ****\n", __func__, base_vha->host_no,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[2], command));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x1020,
+                   "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, cmd=%x ****.\n",
+                   mcp->mb[0], mcp->mb[1], mcp->mb[2], command);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__,
-               base_vha->host_no));
+               ql_dbg(ql_dbg_mbx, base_vha, 0x1021, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -366,7 +361,7 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1022, "Entered %s.\n", __func__);
 
        if (MSW(risc_addr) || IS_FWI2_CAPABLE(ha)) {
                mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
@@ -397,10 +392,10 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1023,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1024, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -430,7 +425,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1025, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_EXECUTE_FIRMWARE;
        mcp->out_mb = MBX_0;
@@ -461,15 +456,14 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1026,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
                if (IS_FWI2_CAPABLE(ha)) {
-                       DEBUG11(printk("%s(%ld): done exchanges=%x.\n",
-                           __func__, vha->host_no, mcp->mb[1]));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1027,
+                           "Done exchanges=%x.\n", mcp->mb[1]);
                } else {
-                       DEBUG11(printk("%s(%ld): done.\n", __func__,
-                           vha->host_no));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1028, "Done %s.\n", __func__);
                }
        }
 
@@ -501,7 +495,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
        mbx_cmd_t       mc;
        mbx_cmd_t       *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1029, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_FIRMWARE_VERSION;
        mcp->out_mb = MBX_0;
@@ -535,11 +529,10 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
 failed:
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x102a, "Failed=%x.\n", rval);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x102b, "Done %s.\n", __func__);
        }
        return rval;
 }
@@ -565,7 +558,7 @@ qla2x00_get_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x102c, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_FIRMWARE_OPTION;
        mcp->out_mb = MBX_0;
@@ -576,15 +569,14 @@ qla2x00_get_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x102d, "Failed=%x.\n", rval);
        } else {
                fwopts[0] = mcp->mb[0];
                fwopts[1] = mcp->mb[1];
                fwopts[2] = mcp->mb[2];
                fwopts[3] = mcp->mb[3];
 
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x102e, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -612,7 +604,7 @@ qla2x00_set_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x102f, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_SET_FIRMWARE_OPTION;
        mcp->mb[1] = fwopts[1];
@@ -636,11 +628,11 @@ qla2x00_set_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x/%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1030,
+                   "Failed=%x (%x/%x).\n", rval, mcp->mb[0], mcp->mb[1]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1031, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -668,7 +660,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1032, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST;
        mcp->mb[1] = 0xAAAA;
@@ -695,12 +687,10 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *vha)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_mbx_reg_test(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1033, "Failed=%x.\n", rval);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_mbx_reg_test(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1034, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -728,7 +718,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *vha, uint32_t risc_addr)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1035, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_VERIFY_CHECKSUM;
        mcp->out_mb = MBX_0;
@@ -749,11 +739,11 @@ qla2x00_verify_checksum(scsi_qla_host_t *vha, uint32_t risc_addr)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x chk sum=%x.\n", __func__,
-                   vha->host_no, rval, IS_FWI2_CAPABLE(vha->hw) ?
-                   (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1036,
+                   "Failed=%x chm sum=%x.\n", rval, IS_FWI2_CAPABLE(vha->hw) ?
+                   (mcp->mb[2] << 16) | mcp->mb[1] : mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1037, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -785,6 +775,8 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer,
        mbx_cmd_t       mc;
        mbx_cmd_t       *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x1038, "Entered %s.\n", __func__);
+
        mcp->mb[0] = MBC_IOCB_COMMAND_A64;
        mcp->mb[1] = 0;
        mcp->mb[2] = MSW(phys_addr);
@@ -799,14 +791,14 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1039, "Failed=%x.\n", rval);
        } else {
                sts_entry_t *sts_entry = (sts_entry_t *) buffer;
 
                /* Mask reserved bits. */
                sts_entry->entry_status &=
                    IS_FWI2_CAPABLE(vha->hw) ? RF_MASK_24XX : RF_MASK;
+               ql_dbg(ql_dbg_mbx, vha, 0x103a, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -847,7 +839,7 @@ qla2x00_abort_command(srb_t *sp)
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = vha->req;
 
-       DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x103b, "Entered %s.\n", __func__);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
@@ -876,11 +868,9 @@ qla2x00_abort_command(srb_t *sp)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x103c, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("qla2x00_abort_command(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x103d, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -896,10 +886,11 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag)
        struct req_que *req;
        struct rsp_que *rsp;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
-
        l = l;
        vha = fcport->vha;
+
+       ql_dbg(ql_dbg_mbx, vha, 0x103e, "Entered %s.\n", __func__);
+
        req = vha->hw->req_q_map[0];
        rsp = req->rsp;
        mcp->mb[0] = MBC_ABORT_TARGET;
@@ -919,18 +910,17 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x103f, "Failed=%x.\n", rval);
        }
 
        /* Issue marker IOCB. */
        rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, 0,
                                                        MK_SYNC_ID);
        if (rval2 != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB "
-                   "(%x).\n", __func__, vha->host_no, rval2));
+               ql_dbg(ql_dbg_mbx, vha, 0x1040,
+                   "Failed to issue marker IOCB (%x).\n", rval2);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1041, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -946,9 +936,10 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
        struct req_que *req;
        struct rsp_que *rsp;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
-
        vha = fcport->vha;
+
+       ql_dbg(ql_dbg_mbx, vha, 0x1042, "Entered %s.\n", __func__);
+
        req = vha->hw->req_q_map[0];
        rsp = req->rsp;
        mcp->mb[0] = MBC_LUN_RESET;
@@ -966,18 +957,17 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1043, "Failed=%x.\n", rval);
        }
 
        /* Issue marker IOCB. */
        rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, l,
                                                                MK_SYNC_ID_LUN);
        if (rval2 != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB "
-                   "(%x).\n", __func__, vha->host_no, rval2));
+               ql_dbg(ql_dbg_mbx, vha, 0x1044,
+                   "Failed to issue marker IOCB (%x).\n", rval2);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1045, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1011,8 +1001,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_get_adapter_id(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1046, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
        mcp->mb[9] = vha->vp_idx;
@@ -1038,11 +1027,9 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1047, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1048, "Done %s.\n", __func__);
 
                if (IS_QLA8XXX_TYPE(vha->hw)) {
                        vha->fcoe_vlan_id = mcp->mb[9] & 0xfff;
@@ -1083,8 +1070,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *vha, uint8_t *retry_cnt, uint8_t *tov,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_get_retry_cnt(%ld): entered.\n",
-                       vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1049, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_RETRY_COUNT;
        mcp->out_mb = MBX_0;
@@ -1095,8 +1081,8 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *vha, uint8_t *retry_cnt, uint8_t *tov,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_get_retry_cnt(%ld): failed = %x.\n",
-                   vha->host_no, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x104a,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
                /* Convert returned data and check our values. */
                *r_a_tov = mcp->mb[3] / 2;
@@ -1107,8 +1093,8 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *vha, uint8_t *retry_cnt, uint8_t *tov,
                        *tov = ratov;
                }
 
-               DEBUG11(printk("qla2x00_get_retry_cnt(%ld): done. mb3=%d "
-                   "ratov=%d.\n", vha->host_no, mcp->mb[3], ratov));
+               ql_dbg(ql_dbg_mbx, vha, 0x104b,
+                   "Done %s mb3=%d ratov=%d.\n", __func__, mcp->mb[3], ratov);
        }
 
        return rval;
@@ -1139,8 +1125,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x104c, "Entered %s.\n", __func__);
 
        if (IS_QLA82XX(ha) && ql2xdbwr)
                qla82xx_wr_32(ha, ha->nxdb_wr_ptr,
@@ -1174,13 +1159,11 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_init_firmware(%ld): failed=%x "
-                   "mb0=%x.\n",
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x104d,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_init_firmware(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x104e, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1213,13 +1196,13 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
        dma_addr_t pd_dma;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x104f, "Entered %s.\n", __func__);
 
        pd24 = NULL;
        pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma);
        if (pd  == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Port Database "
-                   "structure.\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x1050,
+                   "Failed to allocate port database structure.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(pd, 0, max(PORT_DATABASE_SIZE, PORT_DATABASE_24XX_SIZE));
@@ -1261,12 +1244,10 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
                /* Check for logged in state. */
                if (pd24->current_login_state != PDS_PRLI_COMPLETE &&
                    pd24->last_login_state != PDS_PRLI_COMPLETE) {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                          "scsi(%ld): Unable to verify login-state (%x/%x) "
-                          " - portid=%02x%02x%02x.\n", vha->host_no,
-                          pd24->current_login_state, pd24->last_login_state,
-                          fcport->d_id.b.domain, fcport->d_id.b.area,
-                          fcport->d_id.b.al_pa));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1051,
+                           "Unable to verify login-state (%x/%x) for "
+                           "loop_id %x.\n", pd24->current_login_state,
+                           pd24->last_login_state, fcport->loop_id);
                        rval = QLA_FUNCTION_FAILED;
                        goto gpd_error_out;
                }
@@ -1290,12 +1271,11 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
                /* Check for logged in state. */
                if (pd->master_state != PD_STATE_PORT_LOGGED_IN &&
                    pd->slave_state != PD_STATE_PORT_LOGGED_IN) {
-                       DEBUG2(qla_printk(KERN_WARNING, ha,
-                          "scsi(%ld): Unable to verify login-state (%x/%x) "
-                          " - portid=%02x%02x%02x.\n", vha->host_no,
-                          pd->master_state, pd->slave_state,
-                          fcport->d_id.b.domain, fcport->d_id.b.area,
-                          fcport->d_id.b.al_pa));
+                       ql_dbg(ql_dbg_mbx, vha, 0x100a,
+                           "Unable to verify login-state (%x/%x) - "
+                           "portid=%02x%02x%02x.\n", pd->master_state,
+                           pd->slave_state, fcport->d_id.b.domain,
+                           fcport->d_id.b.area, fcport->d_id.b.al_pa);
                        rval = QLA_FUNCTION_FAILED;
                        goto gpd_error_out;
                }
@@ -1325,10 +1305,11 @@ gpd_error_out:
        dma_pool_free(ha->s_dma_pool, pd, pd_dma);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1052,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n", rval,
+                   mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1053, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1357,8 +1338,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_get_firmware_state(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1054, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
        mcp->out_mb = MBX_0;
@@ -1381,12 +1361,10 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_get_firmware_state(%ld): "
-                   "failed=%x.\n", vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1055, "Failed=%x.\n", rval);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_get_firmware_state(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1056, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1418,8 +1396,7 @@ qla2x00_get_port_name(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t *name,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_get_port_name(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1057, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_PORT_NAME;
        mcp->mb[9] = vha->vp_idx;
@@ -1439,8 +1416,7 @@ qla2x00_get_port_name(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t *name,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_get_port_name(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1058, "Failed=%x.\n", rval);
        } else {
                if (name != NULL) {
                        /* This function returns name in big endian. */
@@ -1454,8 +1430,7 @@ qla2x00_get_port_name(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t *name,
                        name[7] = LSB(mcp->mb[7]);
                }
 
-               DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1059, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1483,7 +1458,7 @@ qla2x00_lip_reset(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x105a, "Entered %s.\n", __func__);
 
        if (IS_QLA8XXX_TYPE(vha->hw)) {
                /* Logout across all FCFs. */
@@ -1517,11 +1492,10 @@ qla2x00_lip_reset(scsi_qla_host_t *vha)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n",
-                   __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x105b, "Failed=%x.\n", rval);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x105c, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1553,12 +1527,11 @@ qla2x00_send_sns(scsi_qla_host_t *vha, dma_addr_t sns_phys_address,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_send_sns(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x105d, "Entered %s.\n", __func__);
 
-       DEBUG11(printk("qla2x00_send_sns: retry cnt=%d ratov=%d total "
-               "tov=%d.\n", vha->hw->retry_count, vha->hw->login_timeout,
-               mcp->tov));
+       ql_dbg(ql_dbg_mbx, vha, 0x105e,
+           "Retry cnt=%d ratov=%d total tov=%d.\n",
+           vha->hw->retry_count, vha->hw->login_timeout, mcp->tov);
 
        mcp->mb[0] = MBC_SEND_SNS_COMMAND;
        mcp->mb[1] = cmd_size;
@@ -1575,13 +1548,12 @@ qla2x00_send_sns(scsi_qla_host_t *vha, 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", vha->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", vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x105f,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1060, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1600,7 +1572,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        struct req_que *req;
        struct rsp_que *rsp;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1061, "Entered %s.\n", __func__);
 
        if (ha->flags.cpu_affinity_enabled)
                req = ha->req_q_map[0];
@@ -1610,8 +1582,8 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 
        lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
        if (lg == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Login IOCB.\n",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x1062,
+                   "Failed to allocate login IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(lg, 0, sizeof(struct logio_entry_24xx));
@@ -1631,21 +1603,21 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        lg->vp_index = vha->vp_idx;
        rval = qla2x00_issue_iocb(vha, lg, lg_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB "
-                   "(%x).\n", __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1063,
+                   "Failed to issue login IOCB (%x).\n", rval);
        } else if (lg->entry_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, vha->host_no,
-                   lg->entry_status));
+               ql_dbg(ql_dbg_mbx, vha, 0x1064,
+                   "Failed to complete IOCB -- error status (%x).\n",
+                   lg->entry_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (lg->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
                iop[0] = le32_to_cpu(lg->io_parameter[0]);
                iop[1] = le32_to_cpu(lg->io_parameter[1]);
 
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x)  ioparam=%x/%x.\n", __func__,
-                   vha->host_no, le16_to_cpu(lg->comp_status), iop[0],
-                   iop[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1065,
+                   "Failed to complete IOCB -- completion  status (%x) "
+                   "ioparam=%x/%x.\n", le16_to_cpu(lg->comp_status),
+                   iop[0], iop[1]);
 
                switch (iop[0]) {
                case LSC_SCODE_PORTID_USED:
@@ -1673,7 +1645,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
                        break;
                }
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1066, "Done %s.\n", __func__);
 
                iop[0] = le32_to_cpu(lg->io_parameter[0]);
 
@@ -1728,7 +1700,7 @@ qla2x00_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1067, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_LOGIN_FABRIC_PORT;
        mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -1771,13 +1743,12 @@ qla2x00_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
                        rval = QLA_SUCCESS;
 
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_login_fabric(%ld): failed=%x "
-                   "mb[0]=%x mb[1]=%x mb[2]=%x.\n", vha->host_no, rval,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1068,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_login_fabric(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1069, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1808,13 +1779,13 @@ qla2x00_login_local_device(scsi_qla_host_t *vha, fc_port_t *fcport,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x106a, "Entered %s.\n", __func__);
+
        if (IS_FWI2_CAPABLE(ha))
                return qla24xx_login_fabric(vha, fcport->loop_id,
                    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__, vha->host_no));
-
        mcp->mb[0] = MBC_LOGIN_LOOP_PORT;
        if (HAS_EXTENDED_IDS(ha))
                mcp->mb[1] = fcport->loop_id;
@@ -1845,15 +1816,12 @@ qla2x00_login_local_device(scsi_qla_host_t *vha, fc_port_t *fcport,
                if (mcp->mb[0] == 0x4005 || mcp->mb[0] == 0x4006)
                        rval = QLA_SUCCESS;
 
-               DEBUG(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
-                   "mb[6]=%x mb[7]=%x.\n", __func__, vha->host_no, rval,
-                   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__, vha->host_no, rval,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]));
+               ql_dbg(ql_dbg_mbx, vha, 0x106b,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[6]=%x mb[7]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);
        } else {
                /*EMPTY*/
-               DEBUG3(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x106c, "Done %s.\n", __func__);
        }
 
        return (rval);
@@ -1870,12 +1838,12 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        struct req_que *req;
        struct rsp_que *rsp;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x106d, "Entered %s.\n", __func__);
 
        lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
        if (lg == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Logout IOCB.\n",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x106e,
+                   "Failed to allocate logout IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(lg, 0, sizeof(struct logio_entry_24xx));
@@ -1899,22 +1867,22 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
 
        rval = qla2x00_issue_iocb(vha, lg, lg_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB "
-                   "(%x).\n", __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x106f,
+                   "Failed to issue logout IOCB (%x).\n", rval);
        } else if (lg->entry_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, vha->host_no,
-                   lg->entry_status));
+               ql_dbg(ql_dbg_mbx, vha, 0x1070,
+                   "Failed to complete IOCB -- error status (%x).\n",
+                   lg->entry_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (lg->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
-               DEBUG2_3_11(printk("%s(%ld %d): failed to complete IOCB "
-                   "-- completion status (%x)  ioparam=%x/%x.\n", __func__,
-                   vha->host_no, vha->vp_idx, le16_to_cpu(lg->comp_status),
+               ql_dbg(ql_dbg_mbx, vha, 0x1071,
+                   "Failed to complete IOCB -- completion status (%x) "
+                   "ioparam=%x/%x.\n", 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__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1072, "Done %s.\n", __func__);
        }
 
        dma_pool_free(ha->s_dma_pool, lg, lg_dma);
@@ -1946,8 +1914,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_fabric_logout(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1073, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT;
        mcp->out_mb = MBX_1|MBX_0;
@@ -1966,12 +1933,11 @@ qla2x00_fabric_logout(scsi_qla_host_t *vha, 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", vha->host_no, rval, mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1074,
+                   "Failed=%x mb[1]=%x.\n", rval, mcp->mb[1]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_fabric_logout(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1075, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -1999,8 +1965,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1076, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_LIP_FULL_LOGIN;
        mcp->mb[1] = IS_FWI2_CAPABLE(vha->hw) ? BIT_3 : 0;
@@ -2014,12 +1979,10 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha)
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("qla2x00_full_login_lip(%ld): failed=%x.\n",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1077, "Failed=%x.\n", rval);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("qla2x00_full_login_lip(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1078, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2045,8 +2008,7 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("qla2x00_get_id_list(%ld): entered.\n",
-           vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1079, "Entered %s.\n", __func__);
 
        if (id_list == NULL)
                return QLA_FUNCTION_FAILED;
@@ -2075,12 +2037,10 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, 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",
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x107a, "Failed=%x.\n", rval);
        } else {
                *entries = mcp->mb[1];
-               DEBUG11(printk("qla2x00_get_id_list(%ld): done.\n",
-                   vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x107b, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2108,7 +2068,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x107c, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
        mcp->out_mb = MBX_0;
@@ -2121,14 +2081,14 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed = %x.\n", __func__,
-                   vha->host_no, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x107d,
+                   "Failed mb[0]=%x.\n", mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x "
-                   "mb7=%x mb10=%x mb11=%x mb12=%x.\n", __func__,
-                   vha->host_no, mcp->mb[1], mcp->mb[2], mcp->mb[3],
-                   mcp->mb[6], mcp->mb[7], mcp->mb[10], mcp->mb[11],
-                   mcp->mb[12]));
+               ql_dbg(ql_dbg_mbx, vha, 0x107e,
+                   "Done %s mb1=%x mb2=%x mb3=%x mb6=%x mb7=%x mb10=%x "
+                   "mb11=%x mb12=%x.\n", __func__, mcp->mb[1], mcp->mb[2],
+                   mcp->mb[3], mcp->mb[6], mcp->mb[7], mcp->mb[10],
+                   mcp->mb[11], mcp->mb[12]);
 
                if (cur_xchg_cnt)
                        *cur_xchg_cnt = mcp->mb[3];
@@ -2147,7 +2107,6 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
        return (rval);
 }
 
-#if defined(QL_DEBUG_LEVEL_3)
 /*
  * qla2x00_get_fcal_position_map
  *     Get FCAL (LILP) position map using mailbox command
@@ -2172,10 +2131,12 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *vha, char *pos_map)
        dma_addr_t pmap_dma;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x107f, "Entered %s.\n", __func__);
+
        pmap = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pmap_dma);
        if (pmap  == NULL) {
-               DEBUG2_3_11(printk("%s(%ld): **** Mem Alloc Failed ****",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x1080,
+                   "Memory alloc failed.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(pmap, 0, FCAL_MAP_SIZE);
@@ -2193,10 +2154,11 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *vha, char *pos_map)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval == QLA_SUCCESS) {
-               DEBUG11(printk("%s(%ld): (mb0=%x/mb1=%x) FC/AL Position Map "
-                   "size (%x)\n", __func__, vha->host_no, mcp->mb[0],
-                   mcp->mb[1], (unsigned)pmap[0]));
-               DEBUG11(qla2x00_dump_buffer(pmap, pmap[0] + 1));
+               ql_dbg(ql_dbg_mbx, vha, 0x1081,
+                   "mb0/mb1=%x/%X FC/AL position map size (%x).\n",
+                   mcp->mb[0], mcp->mb[1], (unsigned)pmap[0]);
+               ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111d,
+                   pmap, pmap[0] + 1);
 
                if (pos_map)
                        memcpy(pos_map, pmap, FCAL_MAP_SIZE);
@@ -2204,15 +2166,13 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *vha, char *pos_map)
        dma_pool_free(ha->s_dma_pool, pmap, pmap_dma);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1082, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1083, "Done %s.\n", __func__);
        }
 
        return rval;
 }
-#endif
 
 /*
  * qla2x00_get_link_status
@@ -2237,7 +2197,7 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
        uint32_t *siter, *diter, dwords;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1084, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_LINK_STATUS;
        mcp->mb[2] = MSW(stats_dma);
@@ -2266,11 +2226,12 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, 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__, vha->host_no, mcp->mb[0]));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1085,
+                           "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
                        rval = QLA_FUNCTION_FAILED;
                } else {
                        /* Copy over data -- firmware data is LE. */
+                       ql_dbg(ql_dbg_mbx, vha, 0x1086, "Done %s.\n", __func__);
                        dwords = offsetof(struct link_statistics, unused1) / 4;
                        siter = diter = &stats->link_fail_cnt;
                        while (dwords--)
@@ -2278,8 +2239,7 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id,
                }
        } else {
                /* Failed. */
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1087, "Failed=%x.\n", rval);
        }
 
        return rval;
@@ -2294,7 +2254,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
        mbx_cmd_t *mcp = &mc;
        uint32_t *siter, *diter, dwords;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1088, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GET_LINK_PRIV_STATS;
        mcp->mb[2] = MSW(stats_dma);
@@ -2312,10 +2272,11 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
 
        if (rval == QLA_SUCCESS) {
                if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
-                       DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
-                           __func__, vha->host_no, mcp->mb[0]));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1089,
+                           "Failed mb[0]=%x.\n", mcp->mb[0]);
                        rval = QLA_FUNCTION_FAILED;
                } else {
+                       ql_dbg(ql_dbg_mbx, vha, 0x108a, "Done %s.\n", __func__);
                        /* Copy over data -- firmware data is LE. */
                        dwords = sizeof(struct link_statistics) / 4;
                        siter = diter = &stats->link_fail_cnt;
@@ -2324,8 +2285,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats,
                }
        } else {
                /* Failed. */
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x108b, "Failed=%x.\n", rval);
        }
 
        return rval;
@@ -2345,7 +2305,7 @@ qla24xx_abort_command(srb_t *sp)
        struct qla_hw_data *ha = vha->hw;
        struct req_que *req = vha->req;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x108c, "Entered %s.\n", __func__);
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
@@ -2360,8 +2320,8 @@ qla24xx_abort_command(srb_t *sp)
 
        abt = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &abt_dma);
        if (abt == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Abort IOCB.\n",
-                   __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x108d,
+                   "Failed to allocate abort IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(abt, 0, sizeof(struct abort_entry_24xx));
@@ -2380,20 +2340,20 @@ qla24xx_abort_command(srb_t *sp)
 
        rval = qla2x00_issue_iocb(vha, abt, abt_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n",
-                   __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x108e,
+                   "Failed to issue IOCB (%x).\n", rval);
        } else if (abt->entry_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, vha->host_no,
-                   abt->entry_status));
+               ql_dbg(ql_dbg_mbx, vha, 0x108f,
+                   "Failed to complete IOCB -- error status (%x).\n",
+                   abt->entry_status);
                rval = QLA_FUNCTION_FAILED;
        } 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__, vha->host_no,
-                   le16_to_cpu(abt->nport_handle)));
+               ql_dbg(ql_dbg_mbx, vha, 0x1090,
+                   "Failed to complete IOCB -- completion status (%x).\n",
+                   le16_to_cpu(abt->nport_handle));
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1091, "Done %s.\n", __func__);
        }
 
        dma_pool_free(ha->s_dma_pool, abt, abt_dma);
@@ -2421,19 +2381,20 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
        struct req_que *req;
        struct rsp_que *rsp;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
-
        vha = fcport->vha;
        ha = vha->hw;
        req = vha->req;
+
+       ql_dbg(ql_dbg_mbx, vha, 0x1092, "Entered %s.\n", __func__);
+
        if (ha->flags.cpu_affinity_enabled)
                rsp = ha->rsp_q_map[tag + 1];
        else
                rsp = req->rsp;
        tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma);
        if (tsk == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Task Management "
-                   "IOCB.\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x1093,
+                   "Failed to allocate task management IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(tsk, 0, sizeof(struct tsk_mgmt_cmd));
@@ -2457,30 +2418,30 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
        sts = &tsk->p.sts;
        rval = qla2x00_issue_iocb(vha, tsk, tsk_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue %s Reset IOCB "
-                   "(%x).\n", __func__, vha->host_no, name, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1094,
+                   "Failed to issue %s reset IOCB (%x).\n", name, rval);
        } else if (sts->entry_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, vha->host_no,
-                   sts->entry_status));
+               ql_dbg(ql_dbg_mbx, vha, 0x1095,
+                   "Failed to complete IOCB -- error status (%x).\n",
+                   sts->entry_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (sts->comp_status !=
            __constant_cpu_to_le16(CS_COMPLETE)) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x).\n", __func__,
-                   vha->host_no, le16_to_cpu(sts->comp_status)));
+               ql_dbg(ql_dbg_mbx, vha, 0x1096,
+                   "Failed to complete IOCB -- completion status (%x).\n",
+                   le16_to_cpu(sts->comp_status));
                rval = QLA_FUNCTION_FAILED;
        } else if (le16_to_cpu(sts->scsi_status) &
            SS_RESPONSE_INFO_LEN_VALID) {
                if (le32_to_cpu(sts->rsp_data_len) < 4) {
-                       DEBUG2_3_11(printk("%s(%ld): ignoring inconsistent "
-                           "data length -- not enough response info (%d).\n",
-                           __func__, vha->host_no,
-                           le32_to_cpu(sts->rsp_data_len)));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1097,
+                           "Ignoring inconsistent data length -- not enough "
+                           "response info (%d).\n",
+                           le32_to_cpu(sts->rsp_data_len));
                } else if (sts->data[3]) {
-                       DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                           "-- response (%x).\n", __func__,
-                           vha->host_no, sts->data[3]));
+                       ql_dbg(ql_dbg_mbx, vha, 0x1098,
+                           "Failed to complete IOCB -- response (%x).\n",
+                           sts->data[3]);
                        rval = QLA_FUNCTION_FAILED;
                }
        }
@@ -2489,10 +2450,10 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
        rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, l,
            type == TCF_LUN_RESET ? MK_SYNC_ID_LUN: MK_SYNC_ID);
        if (rval2 != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB "
-                   "(%x).\n", __func__, vha->host_no, rval2));
+               ql_dbg(ql_dbg_mbx, vha, 0x1099,
+                   "Failed to issue marker IOCB (%x).\n", rval2);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x109a, "Done %s.\n", __func__);
        }
 
        dma_pool_free(ha->s_dma_pool, tsk, tsk_dma);
@@ -2533,7 +2494,7 @@ qla2x00_system_error(scsi_qla_host_t *vha)
        if (!IS_QLA23XX(ha) && !IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x109b, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_GEN_SYSTEM_ERROR;
        mcp->out_mb = MBX_0;
@@ -2543,10 +2504,9 @@ qla2x00_system_error(scsi_qla_host_t *vha)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x109c, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x109d, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2566,7 +2526,7 @@ qla2x00_set_serdes_params(scsi_qla_host_t *vha, uint16_t sw_em_1g,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x109e, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_SERDES_PARAMS;
        mcp->mb[1] = BIT_0;
@@ -2581,11 +2541,11 @@ qla2x00_set_serdes_params(scsi_qla_host_t *vha, uint16_t sw_em_1g,
 
        if (rval != QLA_SUCCESS) {
                /*EMPTY*/
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x109f,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
                /*EMPTY*/
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a0, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2601,7 +2561,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *vha)
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10a1, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_STOP_FIRMWARE;
        mcp->out_mb = MBX_0;
@@ -2611,12 +2571,11 @@ qla2x00_stop_firmware(scsi_qla_host_t *vha)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a2, "Failed=%x.\n", rval);
                if (mcp->mb[0] == MBS_INVALID_COMMAND)
                        rval = QLA_INVALID_COMMAND;
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a3, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2630,14 +2589,14 @@ qla2x00_enable_eft_trace(scsi_qla_host_t *vha, dma_addr_t eft_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10a4, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
        if (unlikely(pci_channel_offline(vha->hw->pdev)))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_TRACE_CONTROL;
        mcp->mb[1] = TC_EFT_ENABLE;
        mcp->mb[2] = LSW(eft_dma);
@@ -2652,10 +2611,11 @@ qla2x00_enable_eft_trace(scsi_qla_host_t *vha, dma_addr_t eft_dma,
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a5,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a6, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2668,14 +2628,14 @@ qla2x00_disable_eft_trace(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10a7, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
        if (unlikely(pci_channel_offline(vha->hw->pdev)))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_TRACE_CONTROL;
        mcp->mb[1] = TC_EFT_DISABLE;
        mcp->out_mb = MBX_1|MBX_0;
@@ -2684,10 +2644,11 @@ qla2x00_disable_eft_trace(scsi_qla_host_t *vha)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a8,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10a9, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2701,14 +2662,14 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10aa, "Entered %s.\n", __func__);
+
        if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw))
                return QLA_FUNCTION_FAILED;
 
        if (unlikely(pci_channel_offline(vha->hw->pdev)))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_TRACE_CONTROL;
        mcp->mb[1] = TC_FCE_ENABLE;
        mcp->mb[2] = LSW(fce_dma);
@@ -2727,10 +2688,11 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma,
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ab,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ac, "Done %s.\n", __func__);
 
                if (mb)
                        memcpy(mb, mcp->mb, 8 * sizeof(*mb));
@@ -2748,14 +2710,14 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *vha, uint64_t *wr, uint64_t *rd)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10ad, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
        if (unlikely(pci_channel_offline(vha->hw->pdev)))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_TRACE_CONTROL;
        mcp->mb[1] = TC_FCE_DISABLE;
        mcp->mb[2] = TC_FCE_DISABLE_TRACE;
@@ -2766,10 +2728,11 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *vha, uint64_t *wr, uint64_t *rd)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ae,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10af, "Done %s.\n", __func__);
 
                if (wr)
                        *wr = (uint64_t) mcp->mb[5] << 48 |
@@ -2794,11 +2757,11 @@ qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10b0, "Entered %s.\n", __func__);
+
        if (!IS_IIDMA_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_PORT_PARAMS;
        mcp->mb[1] = loop_id;
        mcp->mb[2] = mcp->mb[3] = 0;
@@ -2817,10 +2780,9 @@ qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
        }
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b1, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b2, "Done %s.\n", __func__);
                if (port_speed)
                        *port_speed = mcp->mb[3];
        }
@@ -2836,11 +2798,11 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10b3, "Entered %s.\n", __func__);
+
        if (!IS_IIDMA_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_PORT_PARAMS;
        mcp->mb[1] = loop_id;
        mcp->mb[2] = BIT_0;
@@ -2863,10 +2825,9 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
        }
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b4, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b5, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -2882,33 +2843,36 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
        scsi_qla_host_t *vp;
        unsigned long   flags;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10b6, "Entered %s.\n", __func__);
+
        if (rptid_entry->entry_status != 0)
                return;
 
        if (rptid_entry->format == 0) {
-               DEBUG15(printk("%s:format 0 : scsi(%ld) number of VPs setup %d,"
-                       " number of VPs acquired %d\n", __func__, vha->host_no,
-                       MSB(le16_to_cpu(rptid_entry->vp_count)),
-                       LSB(le16_to_cpu(rptid_entry->vp_count))));
-               DEBUG15(printk("%s primary port id %02x%02x%02x\n", __func__,
-                       rptid_entry->port_id[2], rptid_entry->port_id[1],
-                       rptid_entry->port_id[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b7,
+                   "Format 0 : Number of VPs setup %d, number of "
+                   "VPs acquired %d.\n",
+                   MSB(le16_to_cpu(rptid_entry->vp_count)),
+                   LSB(le16_to_cpu(rptid_entry->vp_count)));
+               ql_dbg(ql_dbg_mbx, vha, 0x10b8,
+                   "Primary port id %02x%02x%02x.\n",
+                   rptid_entry->port_id[2], rptid_entry->port_id[1],
+                   rptid_entry->port_id[0]);
        } else if (rptid_entry->format == 1) {
                vp_idx = LSB(stat);
-               DEBUG15(printk("%s:format 1: scsi(%ld): VP[%d] enabled "
-                   "- status %d - "
-                   "with port id %02x%02x%02x\n", __func__, vha->host_no,
-                   vp_idx, MSB(stat),
+               ql_dbg(ql_dbg_mbx, vha, 0x10b9,
+                   "Format 1: VP[%d] enabled - status %d - with "
+                   "port id %02x%02x%02x.\n", vp_idx, MSB(stat),
                    rptid_entry->port_id[2], rptid_entry->port_id[1],
-                   rptid_entry->port_id[0]));
+                   rptid_entry->port_id[0]);
 
                vp = vha;
                if (vp_idx == 0 && (MSB(stat) != 1))
                        goto reg_needed;
 
                if (MSB(stat) == 1) {
-                       DEBUG2(printk("scsi(%ld): Could not acquire ID for "
-                           "VP[%d].\n", vha->host_no, vp_idx));
+                       ql_dbg(ql_dbg_mbx, vha, 0x10ba,
+                           "Could not acquire ID for VP[%d].\n", vp_idx);
                        return;
                }
 
@@ -2963,10 +2927,12 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
 
        /* This can be called by the parent */
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10bb, "Entered %s.\n", __func__);
+
        vpmod = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vpmod_dma);
        if (!vpmod) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Modify VP "
-                   "IOCB.\n", __func__, vha->host_no));
+               ql_log(ql_log_warn, vha, 0x10bc,
+                   "Failed to allocate modify VP IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
 
@@ -2983,22 +2949,21 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
 
        rval = qla2x00_issue_iocb(base_vha, vpmod, vpmod_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue VP config IOCB"
-                       "(%x).\n", __func__, base_vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10bd,
+                   "Failed to issue VP config IOCB (%x).\n", rval);
        } else if (vpmod->comp_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                       "-- error status (%x).\n", __func__, base_vha->host_no,
-                       vpmod->comp_status));
+               ql_dbg(ql_dbg_mbx, vha, 0x10be,
+                   "Failed to complete IOCB -- error status (%x).\n",
+                   vpmod->comp_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (vpmod->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x).\n", __func__, base_vha->host_no,
-                   le16_to_cpu(vpmod->comp_status)));
+               ql_dbg(ql_dbg_mbx, vha, 0x10bf,
+                   "Failed to complete IOCB -- completion status (%x).\n",
+                   le16_to_cpu(vpmod->comp_status));
                rval = QLA_FUNCTION_FAILED;
        } else {
                /* EMPTY */
-               DEBUG11(printk("%s(%ld): done.\n", __func__,
-                                                       base_vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10c0, "Done %s.\n", __func__);
                fc_vport_set_state(vha->fc_vport, FC_VPORT_INITIALIZING);
        }
        dma_pool_free(ha->s_dma_pool, vpmod, vpmod_dma);
@@ -3032,17 +2997,16 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
        int     vp_index = vha->vp_idx;
        struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
 
-       DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__,
-           vha->host_no, vp_index));
+       ql_dbg(ql_dbg_mbx, vha, 0x10c1,
+           "Entered %s enabling index %d.\n", __func__, vp_index);
 
        if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
                return QLA_PARAMETER_ERROR;
 
        vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma);
        if (!vce) {
-               DEBUG2_3(printk("%s(%ld): "
-                   "failed to allocate VP Control IOCB.\n", __func__,
-                   base_vha->host_no));
+               ql_log(ql_log_warn, vha, 0x10c2,
+                   "Failed to allocate VP control IOCB.\n");
                return QLA_MEMORY_ALLOC_FAILED;
        }
        memset(vce, 0, sizeof(struct vp_ctrl_entry_24xx));
@@ -3063,28 +3027,20 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
 
        rval = qla2x00_issue_iocb(base_vha, vce, vce_dma, 0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed to issue VP control IOCB"
-                   "(%x).\n", __func__, base_vha->host_no, rval));
-               printk("%s(%ld): failed to issue VP control IOCB"
-                   "(%x).\n", __func__, base_vha->host_no, rval);
+               ql_dbg(ql_dbg_mbx, vha, 0x10c3,
+                   "Failed to issue VP control IOCB (%x).\n", rval);
        } else if (vce->entry_status != 0) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, base_vha->host_no,
-                   vce->entry_status));
-               printk("%s(%ld): failed to complete IOCB "
-                   "-- error status (%x).\n", __func__, base_vha->host_no,
+               ql_dbg(ql_dbg_mbx, vha, 0x10c4,
+                   "Failed to complete IOCB -- error status (%x).\n",
                    vce->entry_status);
                rval = QLA_FUNCTION_FAILED;
        } else if (vce->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
-               DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x).\n", __func__, base_vha->host_no,
-                   le16_to_cpu(vce->comp_status)));
-               printk("%s(%ld): failed to complete IOCB "
-                   "-- completion status (%x).\n", __func__, base_vha->host_no,
+               ql_dbg(ql_dbg_mbx, vha, 0x10c5,
+                   "Failed to complet IOCB -- completion status (%x).\n",
                    le16_to_cpu(vce->comp_status));
                rval = QLA_FUNCTION_FAILED;
        } else {
-               DEBUG2(printk("%s(%ld): done.\n", __func__, base_vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10c6, "Done %s.\n", __func__);
        }
 
        dma_pool_free(ha->s_dma_pool, vce, vce_dma);
@@ -3121,6 +3077,8 @@ qla2x00_send_change_request(scsi_qla_host_t *vha, uint16_t format,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10c7, "Entered %s.\n", __func__);
+
        /*
         * This command is implicitly executed by firmware during login for the
         * physical hosts
@@ -3155,7 +3113,7 @@ qla2x00_dump_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1009, "Entered %s.\n", __func__);
 
        if (MSW(addr) || IS_FWI2_CAPABLE(vha->hw)) {
                mcp->mb[0] = MBC_DUMP_RISC_RAM_EXTENDED;
@@ -3186,10 +3144,10 @@ qla2x00_dump_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1008,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1007, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3214,12 +3172,10 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status)
        unsigned long flags;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG16(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10c8, "Entered %s.\n", __func__);
 
        mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma);
        if (mn == NULL) {
-               DEBUG2_3(printk("%s(%ld): failed to allocate Verify ISP84XX "
-                   "IOCB.\n", __func__, vha->host_no));
                return QLA_MEMORY_ALLOC_FAILED;
        }
 
@@ -3237,43 +3193,43 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status)
                mn->p.req.entry_count = 1;
                mn->p.req.options = cpu_to_le16(options);
 
-               DEBUG16(printk("%s(%ld): Dump of Verify Request.\n", __func__,
-                   vha->host_no));
-               DEBUG16(qla2x00_dump_buffer((uint8_t *)mn,
-                   sizeof(*mn)));
+               ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111c,
+                   "Dump of Verify Request.\n");
+               ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111e,
+                   (uint8_t *)mn, sizeof(*mn));
 
                rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120);
                if (rval != QLA_SUCCESS) {
-                       DEBUG2_16(printk("%s(%ld): failed to issue Verify "
-                           "IOCB (%x).\n", __func__, vha->host_no, rval));
+                       ql_dbg(ql_dbg_mbx, vha, 0x10cb,
+                           "Failed to issue verify IOCB (%x).\n", rval);
                        goto verify_done;
                }
 
-               DEBUG16(printk("%s(%ld): Dump of Verify Response.\n", __func__,
-                   vha->host_no));
-               DEBUG16(qla2x00_dump_buffer((uint8_t *)mn,
-                   sizeof(*mn)));
+               ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1110,
+                   "Dump of Verify Response.\n");
+               ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1118,
+                   (uint8_t *)mn, sizeof(*mn));
 
                status[0] = le16_to_cpu(mn->p.rsp.comp_status);
                status[1] = status[0] == CS_VCS_CHIP_FAILURE ?
                    le16_to_cpu(mn->p.rsp.failure_code) : 0;
-               DEBUG2_16(printk("%s(%ld): cs=%x fc=%x\n", __func__,
-                   vha->host_no, status[0], status[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ce,
+                   "cs=%x fc=%x.\n", status[0], status[1]);
 
                if (status[0] != CS_COMPLETE) {
                        rval = QLA_FUNCTION_FAILED;
                        if (!(options & VCO_DONT_UPDATE_FW)) {
-                               DEBUG2_16(printk("%s(%ld): Firmware update "
-                                   "failed. Retrying without update "
-                                   "firmware.\n", __func__, vha->host_no));
+                               ql_dbg(ql_dbg_mbx, vha, 0x10cf,
+                                   "Firmware update failed. Retrying "
+                                   "without update firmware.\n");
                                options |= VCO_DONT_UPDATE_FW;
                                options &= ~VCO_FORCE_UPDATE;
                                retry = 1;
                        }
                } else {
-                       DEBUG2_16(printk("%s(%ld): firmware updated to %x.\n",
-                           __func__, vha->host_no,
-                           le32_to_cpu(mn->p.rsp.fw_ver)));
+                       ql_dbg(ql_dbg_mbx, vha, 0x10d0,
+                           "Firmware updated to %x.\n",
+                           le32_to_cpu(mn->p.rsp.fw_ver));
 
                        /* NOTE: we only update OP firmware. */
                        spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
@@ -3288,10 +3244,9 @@ verify_done:
        dma_pool_free(ha->s_dma_pool, mn, mn_dma);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_16(printk("%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10d1, "Failed=%x.\n", rval);
        } else {
-               DEBUG16(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10d2, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3307,6 +3262,8 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
        struct device_reg_25xxmq __iomem *reg;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10d3, "Entered %s.\n", __func__);
+
        mcp->mb[0] = MBC_INITIALIZE_MULTIQ;
        mcp->mb[1] = req->options;
        mcp->mb[2] = MSW(LSD(req->dma));
@@ -3344,9 +3301,13 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        rval = qla2x00_mailbox_command(vha, mcp);
-       if (rval != QLA_SUCCESS)
-               DEBUG2_3_11(printk(KERN_WARNING "%s(%ld): failed=%x mb0=%x.\n",
-                       __func__, vha->host_no, rval, mcp->mb[0]));
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_mbx, vha, 0x10d4,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+       } else {
+               ql_dbg(ql_dbg_mbx, vha, 0x10d5, "Done %s.\n", __func__);
+       }
+
        return rval;
 }
 
@@ -3360,6 +3321,8 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
        struct device_reg_25xxmq __iomem *reg;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10d6, "Entered %s.\n", __func__);
+
        mcp->mb[0] = MBC_INITIALIZE_MULTIQ;
        mcp->mb[1] = rsp->options;
        mcp->mb[2] = MSW(LSD(rsp->dma));
@@ -3393,10 +3356,13 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        rval = qla2x00_mailbox_command(vha, mcp);
-       if (rval != QLA_SUCCESS)
-               DEBUG2_3_11(printk(KERN_WARNING "%s(%ld): failed=%x "
-                       "mb0=%x.\n", __func__,
-                       vha->host_no, rval, mcp->mb[0]));
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_mbx, vha, 0x10d7,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+       } else {
+               ql_dbg(ql_dbg_mbx, vha, 0x10d8, "Done %s.\n", __func__);
+       }
+
        return rval;
 }
 
@@ -3407,7 +3373,7 @@ qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10d9, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_IDC_ACK;
        memcpy(&mcp->mb[1], mb, QLA_IDC_ACK_REGS * sizeof(uint16_t));
@@ -3418,10 +3384,10 @@ qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10da,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10db, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3434,11 +3400,11 @@ qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10dc, "Entered %s.\n", __func__);
+
        if (!IS_QLA81XX(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
        mcp->mb[1] = FAC_OPT_CMD_GET_SECTOR_SIZE;
        mcp->out_mb = MBX_1|MBX_0;
@@ -3448,10 +3414,11 @@ qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10dd,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10de, "Done %s.\n", __func__);
                *sector_size = mcp->mb[1];
        }
 
@@ -3468,7 +3435,7 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable)
        if (!IS_QLA81XX(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10df, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
        mcp->mb[1] = enable ? FAC_OPT_CMD_WRITE_ENABLE :
@@ -3480,10 +3447,11 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e0,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e1, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3499,7 +3467,7 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
        if (!IS_QLA81XX(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10e2, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_FLASH_ACCESS_CTRL;
        mcp->mb[1] = FAC_OPT_CMD_ERASE_SECTOR;
@@ -3514,11 +3482,11 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
-                   "mb[2]=%x.\n", __func__, vha->host_no, rval, mcp->mb[0],
-                   mcp->mb[1], mcp->mb[2]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e3,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e4, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3531,7 +3499,7 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10e5, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_RESTART_MPI_FW;
        mcp->out_mb = MBX_0;
@@ -3541,10 +3509,11 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x mb[1]=0x%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e6,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e7, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3559,11 +3528,11 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10e8, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        if (len == 1)
                opt |= BIT_0;
 
@@ -3586,10 +3555,10 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp,
                *sfp = mcp->mb[1];
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10e9,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ea, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3604,11 +3573,11 @@ qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10eb, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        if (len == 1)
                opt |= BIT_0;
 
@@ -3631,10 +3600,10 @@ qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ec,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ed, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3648,11 +3617,11 @@ qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10ee, "Entered %s.\n", __func__);
+
        if (!IS_QLA8XXX_TYPE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_GET_XGMAC_STATS;
        mcp->mb[2] = MSW(stats_dma);
        mcp->mb[3] = LSW(stats_dma);
@@ -3666,11 +3635,12 @@ qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x "
-                   "mb[1]=0x%x mb[2]=0x%x.\n", __func__, vha->host_no, rval,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ef,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f0, "Done %s.\n", __func__);
+
 
                *actual_size = mcp->mb[2] << 2;
        }
@@ -3686,11 +3656,11 @@ qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma,
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10f1, "Entered %s.\n", __func__);
+
        if (!IS_QLA8XXX_TYPE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_GET_DCBX_PARAMS;
        mcp->mb[1] = 0;
        mcp->mb[2] = MSW(tlv_dma);
@@ -3705,11 +3675,11 @@ qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=0x%x "
-                   "mb[1]=0x%x mb[2]=0x%x.\n", __func__, vha->host_no, rval,
-                   mcp->mb[0], mcp->mb[1], mcp->mb[2]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f2,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f3, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3722,11 +3692,11 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x10f4, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_READ_RAM_EXTENDED;
        mcp->mb[1] = LSW(risc_addr);
        mcp->mb[8] = MSW(risc_addr);
@@ -3736,10 +3706,10 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f5,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f6, "Done %s.\n", __func__);
                *data = mcp->mb[3] << 16 | mcp->mb[2];
        }
 
@@ -3755,7 +3725,7 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
        mbx_cmd_t *mcp = &mc;
        uint32_t iter_cnt = 0x1;
 
-       DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10f7, "Entered %s.\n", __func__);
 
        memset(mcp->mb, 0 , sizeof(mcp->mb));
        mcp->mb[0] = MBC_DIAGNOSTIC_LOOP_BACK;
@@ -3794,15 +3764,12 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2(printk(KERN_WARNING
-                       "(%ld): failed=%x mb[0]=0x%x "
-                       "mb[1]=0x%x mb[2]=0x%x mb[3]=0x%x mb[18]=0x%x "
-                       "mb[19]=0x%x.\n",
-                       vha->host_no, rval, mcp->mb[0], mcp->mb[1], mcp->mb[2],
-                       mcp->mb[3], mcp->mb[18], mcp->mb[19]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f8,
+                   "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[3]=%x mb[18]=%x "
+                   "mb[19]=%x.\n", rval, mcp->mb[0], mcp->mb[1], mcp->mb[2],
+                   mcp->mb[3], mcp->mb[18], mcp->mb[19]);
        } else {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld): done.\n", vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10f9, "Done %s.\n", __func__);
        }
 
        /* Copy mailbox information */
@@ -3819,7 +3786,7 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk("scsi(%ld): entered.\n", vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10fa, "Entered %s.\n", __func__);
 
        memset(mcp->mb, 0 , sizeof(mcp->mb));
        mcp->mb[0] = MBC_DIAGNOSTIC_ECHO;
@@ -3858,12 +3825,11 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2(printk(KERN_WARNING
-                   "(%ld): failed=%x mb[0]=0x%x mb[1]=0x%x.\n",
-                   vha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+               ql_dbg(ql_dbg_mbx, vha, 0x10fb,
+                   "Failed=%x mb[0]=%x mb[1]=%x.\n",
+                   rval, mcp->mb[0], mcp->mb[1]);
        } else {
-               DEBUG2(printk(KERN_WARNING
-                   "scsi(%ld): done.\n", vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10fc, "Done %s.\n", __func__);
        }
 
        /* Copy mailbox information */
@@ -3872,14 +3838,14 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
 }
 
 int
-qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic)
+qla84xx_reset_chip(scsi_qla_host_t *vha, uint16_t enable_diagnostic)
 {
        int rval;
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG16(printk("%s(%ld): enable_diag=%d entered.\n", __func__,
-               ha->host_no, enable_diagnostic));
+       ql_dbg(ql_dbg_mbx, vha, 0x10fd,
+           "Entered %s enable_diag=%d.\n", __func__, enable_diagnostic);
 
        mcp->mb[0] = MBC_ISP84XX_RESET;
        mcp->mb[1] = enable_diagnostic;
@@ -3887,13 +3853,12 @@ qla84xx_reset_chip(scsi_qla_host_t *ha, uint16_t enable_diagnostic)
        mcp->in_mb = MBX_1|MBX_0;
        mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
-       rval = qla2x00_mailbox_command(ha, mcp);
+       rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS)
-               DEBUG16(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no,
-                       rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10fe, "Failed=%x.\n", rval);
        else
-               DEBUG16(printk("%s(%ld): done.\n", __func__, ha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10ff, "Done %s.\n", __func__);
 
        return rval;
 }
@@ -3905,11 +3870,11 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x1100, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(vha->hw))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_WRITE_RAM_WORD_EXTENDED;
        mcp->mb[1] = LSW(risc_addr);
        mcp->mb[2] = LSW(data);
@@ -3921,10 +3886,10 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1101,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1102, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3941,8 +3906,7 @@ qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb)
 
        rval = QLA_SUCCESS;
 
-       DEBUG11(qla_printk(KERN_INFO, ha,
-           "%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1103, "Entered %s.\n", __func__);
 
        clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
 
@@ -3982,11 +3946,10 @@ qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb)
                rval = QLA_FUNCTION_FAILED;
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_INFO "%s(%ld): failed=%x mb[0]=%x.\n",
-                   __func__, vha->host_no, rval, mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1104,
+                   "Failed=%x mb[0]=%x.\n", rval, mb[0]);
        } else {
-               DEBUG11(printk(KERN_INFO
-                   "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1105, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -3999,12 +3962,11 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x1106, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(qla_printk(KERN_INFO, ha,
-               "%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_DATA_RATE;
        mcp->mb[1] = 0;
        mcp->out_mb = MBX_1|MBX_0;
@@ -4013,11 +3975,10 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_INFO "%s(%ld): failed=%x mb[0]=%x.\n",
-                   __func__, vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1107,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(printk(KERN_INFO
-                   "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x1108, "Done %s.\n", __func__);
                if (mcp->mb[1] != 0x7)
                        ha->link_data_rate = mcp->mb[1];
        }
@@ -4033,8 +3994,7 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk(KERN_INFO
-           "%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1109, "Entered %s.\n", __func__);
 
        if (!IS_QLA81XX(ha))
                return QLA_FUNCTION_FAILED;
@@ -4047,15 +4007,13 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x110a,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
                /* Copy all bits to preserve original value */
                memcpy(mb, &mcp->mb[1], sizeof(uint16_t) * 4);
 
-               DEBUG11(printk(KERN_INFO
-                   "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x110b, "Done %s.\n", __func__);
        }
        return rval;
 }
@@ -4067,8 +4025,7 @@ qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
-       DEBUG11(printk(KERN_INFO
-           "%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x110c, "Entered %s.\n", __func__);
 
        mcp->mb[0] = MBC_SET_PORT_CONFIG;
        /* Copy all bits to preserve original setting */
@@ -4080,12 +4037,10 @@ qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb)
        rval = qla2x00_mailbox_command(vha, mcp);
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): failed=%x (%x).\n", __func__,
-                   vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x110d,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else
-               DEBUG11(printk(KERN_INFO
-                   "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x110e, "Done %s.\n", __func__);
 
        return rval;
 }
@@ -4100,12 +4055,11 @@ qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
        mbx_cmd_t *mcp = &mc;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x110f, "Entered %s.\n", __func__);
+
        if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(printk(KERN_INFO
-           "%s(%ld): entered.\n", __func__, vha->host_no));
-
        mcp->mb[0] = MBC_PORT_PARAMS;
        mcp->mb[1] = loop_id;
        if (ha->flags.fcp_prio_enabled)
@@ -4127,12 +4081,9 @@ qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
        }
 
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): failed=%x.\n", __func__,
-                   vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10cd, "Failed=%x.\n", rval);
        } else {
-               DEBUG11(printk(KERN_INFO
-                   "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x10cc, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -4145,13 +4096,12 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp, uint16_t *frac)
        uint8_t byte;
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG11(printk(KERN_INFO "%s(%ld): entered.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x10ca, "Entered %s.\n", __func__);
 
        /* Integer part */
        rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x01, 1, BIT_13|BIT_0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): failed=%x.\n", __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x10c9, "Failed=%x.\n", rval);
                ha->flags.thermal_supported = 0;
                goto fail;
        }
@@ -4160,14 +4110,13 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp, uint16_t *frac)
        /* Fraction part */
        rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x10, 1, BIT_13|BIT_0);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(printk(KERN_WARNING
-                   "%s(%ld): failed=%x.\n", __func__, vha->host_no, rval));
+               ql_dbg(ql_dbg_mbx, vha, 0x1019, "Failed=%x.\n", rval);
                ha->flags.thermal_supported = 0;
                goto fail;
        }
        *frac = (byte >> 6) * 25;
 
-       DEBUG11(printk(KERN_INFO "%s(%ld): done.\n", __func__, vha->host_no));
+       ql_dbg(ql_dbg_mbx, vha, 0x1018, "Done %s.\n", __func__);
 fail:
        return rval;
 }
@@ -4180,12 +4129,11 @@ qla82xx_mbx_intr_enable(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x1017, "Entered %s.\n", __func__);
+
        if (!IS_FWI2_CAPABLE(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(qla_printk(KERN_INFO, ha,
-               "%s(%ld): entered.\n", __func__, vha->host_no));
-
        memset(mcp, 0, sizeof(mbx_cmd_t));
        mcp->mb[0] = MBC_TOGGLE_INTERRUPT;
        mcp->mb[1] = 1;
@@ -4197,12 +4145,10 @@ qla82xx_mbx_intr_enable(scsi_qla_host_t *vha)
 
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(qla_printk(KERN_WARNING, ha,
-                       "%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                       vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x1016,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(qla_printk(KERN_INFO, ha,
-                       "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x100e, "Done %s.\n", __func__);
        }
 
        return rval;
@@ -4216,12 +4162,11 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha)
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
 
+       ql_dbg(ql_dbg_mbx, vha, 0x100d, "Entered %s.\n", __func__);
+
        if (!IS_QLA82XX(ha))
                return QLA_FUNCTION_FAILED;
 
-       DEBUG11(qla_printk(KERN_INFO, ha,
-               "%s(%ld): entered.\n", __func__, vha->host_no));
-
        memset(mcp, 0, sizeof(mbx_cmd_t));
        mcp->mb[0] = MBC_TOGGLE_INTERRUPT;
        mcp->mb[1] = 0;
@@ -4233,12 +4178,10 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha)
 
        rval = qla2x00_mailbox_command(vha, mcp);
        if (rval != QLA_SUCCESS) {
-               DEBUG2_3_11(qla_printk(KERN_WARNING, ha,
-                       "%s(%ld): failed=%x mb[0]=%x.\n", __func__,
-                       vha->host_no, rval, mcp->mb[0]));
+               ql_dbg(ql_dbg_mbx, vha, 0x100c,
+                   "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
        } else {
-               DEBUG11(qla_printk(KERN_INFO, ha,
-                       "%s(%ld): done.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_mbx, vha, 0x100b, "Done %s.\n", __func__);
        }
 
        return rval;
index 5e343919acad791ccc8879b4b98cce37e92021d8..c706ed370000390f8450256aa2427817800e8430 100644 (file)
@@ -36,8 +36,9 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
        mutex_lock(&ha->vport_lock);
        vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1);
        if (vp_id > ha->max_npiv_vports) {
-               DEBUG15(printk ("vp_id %d is bigger than max-supported %d.\n",
-                   vp_id, ha->max_npiv_vports));
+               ql_dbg(ql_dbg_vport, vha, 0xa000,
+                   "vp_id %d is bigger than max-supported %d.\n",
+                   vp_id, ha->max_npiv_vports);
                mutex_unlock(&ha->vport_lock);
                return vp_id;
        }
@@ -131,9 +132,9 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
        fc_port_t *fcport;
 
        list_for_each_entry(fcport, &vha->vp_fcports, list) {
-               DEBUG15(printk("scsi(%ld): Marking port dead, "
-                   "loop_id=0x%04x :%x\n",
-                   vha->host_no, fcport->loop_id, fcport->vp_idx));
+               ql_dbg(ql_dbg_vport, vha, 0xa001,
+                   "Marking port dead, loop_id=0x%04x : %x.\n",
+                   fcport->loop_id, fcport->vp_idx);
 
                qla2x00_mark_device_lost(vha, fcport, 0, 0);
                qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED);
@@ -187,13 +188,13 @@ qla24xx_enable_vp(scsi_qla_host_t *vha)
                goto enable_failed;
        }
 
-       DEBUG15(qla_printk(KERN_INFO, ha,
-           "Virtual port with id: %d - Enabled\n", vha->vp_idx));
+       ql_dbg(ql_dbg_taskm, vha, 0x801a,
+           "Virtual port with id: %d - Enabled.\n", vha->vp_idx);
        return 0;
 
 enable_failed:
-       DEBUG15(qla_printk(KERN_INFO, ha,
-           "Virtual port with id: %d - Disabled\n", vha->vp_idx));
+       ql_dbg(ql_dbg_taskm, vha, 0x801b,
+           "Virtual port with id: %d - Disabled.\n", vha->vp_idx);
        return 1;
 }
 
@@ -205,12 +206,12 @@ qla24xx_configure_vp(scsi_qla_host_t *vha)
 
        fc_vport = vha->fc_vport;
 
-       DEBUG15(printk("scsi(%ld): %s: change request #3 for this host.\n",
-           vha->host_no, __func__));
+       ql_dbg(ql_dbg_vport, vha, 0xa002,
+           "%s: change request #3.\n", __func__);
        ret = qla2x00_send_change_request(vha, 0x3, vha->vp_idx);
        if (ret != QLA_SUCCESS) {
-               DEBUG15(qla_printk(KERN_ERR, vha->hw, "Failed to enable "
-                   "receiving of RSCN requests: 0x%x\n", ret));
+               ql_dbg(ql_dbg_vport, vha, 0xa003, "Failed to enable "
+                   "receiving of RSCN requests: 0x%x.\n", ret);
                return;
        } else {
                /* Corresponds to SCR enabled */
@@ -248,9 +249,9 @@ qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb)
                        case MBA_CHG_IN_CONNECTION:
                        case MBA_PORT_UPDATE:
                        case MBA_RSCN_UPDATE:
-                               DEBUG15(printk("scsi(%ld)%s: Async_event for"
-                               " VP[%d], mb = 0x%x, vha=%p\n",
-                               vha->host_no, __func__, i, *mb, vha));
+                               ql_dbg(ql_dbg_async, vha, 0x5024,
+                                   "Async_event for VP[%d], mb=0x%x vha=%p.\n",
+                                   i, *mb, vha);
                                qla2x00_async_event(vha, rsp, mb);
                                break;
                        }
@@ -286,37 +287,49 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
        if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
                qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
 
-       DEBUG15(printk("scsi(%ld): Scheduling enable of Vport %d...\n",
-           vha->host_no, vha->vp_idx));
+       ql_dbg(ql_dbg_taskm, vha, 0x801d,
+           "Scheduling enable of Vport %d.\n", vha->vp_idx);
        return qla24xx_enable_vp(vha);
 }
 
 static int
 qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
 {
+       ql_dbg(ql_dbg_dpc, vha, 0x4012,
+           "Entering %s.\n", __func__);
+       ql_dbg(ql_dbg_dpc, vha, 0x4013,
+           "vp_flags: 0x%lx.\n", vha->vp_flags);
+
        qla2x00_do_work(vha);
 
        if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
                /* VP acquired. complete port configuration */
+               ql_dbg(ql_dbg_dpc, vha, 0x4014,
+                   "Configure VP scheduled.\n");
                qla24xx_configure_vp(vha);
+               ql_dbg(ql_dbg_dpc, vha, 0x4015,
+                   "Configure VP end.\n");
                return 0;
        }
 
        if (test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) {
+               ql_dbg(ql_dbg_dpc, vha, 0x4016,
+                   "FCPort update scheduled.\n");
                qla2x00_update_fcports(vha);
                clear_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags);
+               ql_dbg(ql_dbg_dpc, vha, 0x4017,
+                   "FCPort update end.\n");
        }
 
        if ((test_and_clear_bit(RELOGIN_NEEDED, &vha->dpc_flags)) &&
                !test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) &&
                atomic_read(&vha->loop_state) != LOOP_DOWN) {
 
-               DEBUG(printk("scsi(%ld): qla2x00_port_login()\n",
-                                               vha->host_no));
+               ql_dbg(ql_dbg_dpc, vha, 0x4018,
+                   "Relogin needed scheduled.\n");
                qla2x00_relogin(vha);
-
-               DEBUG(printk("scsi(%ld): qla2x00_port_login - end\n",
-                                                       vha->host_no));
+               ql_dbg(ql_dbg_dpc, vha, 0x4019,
+                   "Relogin needed end.\n");
        }
 
        if (test_and_clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) &&
@@ -326,11 +339,17 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
 
        if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
                if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
+                       ql_dbg(ql_dbg_dpc, vha, 0x401a,
+                           "Loop resync scheduled.\n");
                        qla2x00_loop_resync(vha);
                        clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
+                       ql_dbg(ql_dbg_dpc, vha, 0x401b,
+                           "Loop resync end.\n");
                }
        }
 
+       ql_dbg(ql_dbg_dpc, vha, 0x401c,
+           "Exiting %s.\n", __func__);
        return 0;
 }
 
@@ -396,9 +415,10 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
 
        /* Check up max-npiv-supports */
        if (ha->num_vhosts > ha->max_npiv_vports) {
-               DEBUG15(printk("scsi(%ld): num_vhosts %ud is bigger than "
-                   "max_npv_vports %ud.\n", base_vha->host_no,
-                   ha->num_vhosts, ha->max_npiv_vports));
+               ql_dbg(ql_dbg_vport, vha, 0xa004,
+                   "num_vhosts %ud is bigger "
+                   "than max_npiv_vports %ud.\n",
+                   ha->num_vhosts, ha->max_npiv_vports);
                return VPCERR_UNSUPPORTED;
        }
        return 0;
@@ -415,7 +435,8 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 
        vha = qla2x00_create_host(sht, ha);
        if (!vha) {
-               DEBUG(printk("qla2xxx: scsi_host_alloc() failed for vport\n"));
+               ql_log(ql_log_warn, vha, 0xa005,
+                   "scsi_host_alloc() failed for vport.\n");
                return(NULL);
        }
 
@@ -429,8 +450,8 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
        vha->device_flags = 0;
        vha->vp_idx = qla24xx_allocate_vp_id(vha);
        if (vha->vp_idx > ha->max_npiv_vports) {
-               DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
-                       vha->host_no));
+               ql_dbg(ql_dbg_vport, vha, 0xa006,
+                   "Couldn't allocate vp_id.\n");
                goto create_vhost_failed;
        }
        vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
@@ -461,8 +482,9 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
        host->max_id = MAX_TARGETS_2200;
        host->transportt = qla2xxx_transport_vport_template;
 
-       DEBUG15(printk("DEBUG: detect vport hba %ld at address = %p\n",
-           vha->host_no, vha));
+       ql_dbg(ql_dbg_vport, vha, 0xa007,
+           "Detect vport hba %ld at address = %p.\n",
+           vha->host_no, vha);
 
        vha->flags.init_done = 1;
 
@@ -567,9 +589,9 @@ qla25xx_delete_queues(struct scsi_qla_host *vha)
                if (req) {
                        ret = qla25xx_delete_req_que(vha, req);
                        if (ret != QLA_SUCCESS) {
-                               qla_printk(KERN_WARNING, ha,
-                               "Couldn't delete req que %d\n",
-                               req->id);
+                               ql_log(ql_log_warn, vha, 0x00ea,
+                                   "Couldn't delete req que %d.\n",
+                                   req->id);
                                return ret;
                        }
                }
@@ -581,9 +603,9 @@ qla25xx_delete_queues(struct scsi_qla_host *vha)
                if (rsp) {
                        ret = qla25xx_delete_rsp_que(vha, rsp);
                        if (ret != QLA_SUCCESS) {
-                               qla_printk(KERN_WARNING, ha,
-                               "Couldn't delete rsp que %d\n",
-                               rsp->id);
+                               ql_log(ql_log_warn, vha, 0x00eb,
+                                   "Couldn't delete rsp que %d.\n",
+                                   rsp->id);
                                return ret;
                        }
                }
@@ -604,8 +626,8 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
 
        req = kzalloc(sizeof(struct req_que), GFP_KERNEL);
        if (req == NULL) {
-               qla_printk(KERN_WARNING, ha, "could not allocate memory"
-                       "for request que\n");
+               ql_log(ql_log_fatal, base_vha, 0x00d9,
+                   "Failed to allocate memory for request queue.\n");
                goto failed;
        }
 
@@ -614,8 +636,8 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
                        (req->length + 1) * sizeof(request_t),
                        &req->dma, GFP_KERNEL);
        if (req->ring == NULL) {
-               qla_printk(KERN_WARNING, ha,
-               "Memory Allocation failed - request_ring\n");
+               ql_log(ql_log_fatal, base_vha, 0x00da,
+                   "Failed to allocte memory for request_ring.\n");
                goto que_failed;
        }
 
@@ -623,8 +645,8 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
        que_id = find_first_zero_bit(ha->req_qid_map, ha->max_req_queues);
        if (que_id >= ha->max_req_queues) {
                mutex_unlock(&ha->vport_lock);
-               qla_printk(KERN_INFO, ha, "No resources to create "
-                        "additional request queue\n");
+               ql_log(ql_log_warn, base_vha, 0x00db,
+                   "No resources to create additional request queue.\n");
                goto que_failed;
        }
        set_bit(que_id, ha->req_qid_map);
@@ -633,6 +655,12 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
        req->vp_idx = vp_idx;
        req->qos = qos;
 
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc002,
+           "queue_id=%d rid=%d vp_idx=%d qos=%d.\n",
+           que_id, req->rid, req->vp_idx, req->qos);
+       ql_dbg(ql_dbg_init, base_vha, 0x00dc,
+           "queue_id=%d rid=%d vp_idx=%d qos=%d.\n",
+           que_id, req->rid, req->vp_idx, req->qos);
        if (rsp_que < 0)
                req->rsp = NULL;
        else
@@ -645,6 +673,10 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
                options |= BIT_5;
        req->options = options;
 
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc003,
+           "options=0x%x.\n", req->options);
+       ql_dbg(ql_dbg_init, base_vha, 0x00dd,
+           "options=0x%x.\n", req->options);
        for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
                req->outstanding_cmds[cnt] = NULL;
        req->current_outstanding_cmd = 1;
@@ -656,10 +688,21 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
        reg = ISP_QUE_REG(ha, que_id);
        req->max_q_depth = ha->req_q_map[0]->max_q_depth;
        mutex_unlock(&ha->vport_lock);
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc004,
+           "ring_ptr=%p ring_index=%d, "
+           "cnt=%d id=%d max_q_depth=%d.\n",
+           req->ring_ptr, req->ring_index,
+           req->cnt, req->id, req->max_q_depth);
+       ql_dbg(ql_dbg_init, base_vha, 0x00de,
+           "ring_ptr=%p ring_index=%d, "
+           "cnt=%d id=%d max_q_depth=%d.\n",
+           req->ring_ptr, req->ring_index, req->cnt,
+           req->id, req->max_q_depth);
 
        ret = qla25xx_init_req_que(base_vha, req);
        if (ret != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha, "%s failed\n", __func__);
+               ql_log(ql_log_fatal, base_vha, 0x00df,
+                   "%s failed.\n", __func__);
                mutex_lock(&ha->vport_lock);
                clear_bit(que_id, ha->req_qid_map);
                mutex_unlock(&ha->vport_lock);
@@ -700,8 +743,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 
        rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL);
        if (rsp == NULL) {
-               qla_printk(KERN_WARNING, ha, "could not allocate memory for"
-                               " response que\n");
+               ql_log(ql_log_warn, base_vha, 0x0066,
+                   "Failed to allocate memory for response queue.\n");
                goto failed;
        }
 
@@ -710,8 +753,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
                        (rsp->length + 1) * sizeof(response_t),
                        &rsp->dma, GFP_KERNEL);
        if (rsp->ring == NULL) {
-               qla_printk(KERN_WARNING, ha,
-               "Memory Allocation failed - response_ring\n");
+               ql_log(ql_log_warn, base_vha, 0x00e1,
+                   "Failed to allocate memory for response ring.\n");
                goto que_failed;
        }
 
@@ -719,8 +762,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
        que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_rsp_queues);
        if (que_id >= ha->max_rsp_queues) {
                mutex_unlock(&ha->vport_lock);
-               qla_printk(KERN_INFO, ha, "No resources to create "
-                        "additional response queue\n");
+               ql_log(ql_log_warn, base_vha, 0x00e2,
+                   "No resources to create additional request queue.\n");
                goto que_failed;
        }
        set_bit(que_id, ha->rsp_qid_map);
@@ -728,12 +771,16 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
        if (ha->flags.msix_enabled)
                rsp->msix = &ha->msix_entries[que_id + 1];
        else
-               qla_printk(KERN_WARNING, ha, "msix not enabled\n");
+               ql_log(ql_log_warn, base_vha, 0x00e3,
+                   "MSIX not enalbled.\n");
 
        ha->rsp_q_map[que_id] = rsp;
        rsp->rid = rid;
        rsp->vp_idx = vp_idx;
        rsp->hw = ha;
+       ql_dbg(ql_dbg_init, base_vha, 0x00e4,
+           "queue_id=%d rid=%d vp_idx=%d hw=%p.\n",
+           que_id, rsp->rid, rsp->vp_idx, rsp->hw);
        /* Use alternate PCI bus number */
        if (MSB(rsp->rid))
                options |= BIT_4;
@@ -750,6 +797,14 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
        rsp->rsp_q_in = &reg->isp25mq.rsp_q_in;
        rsp->rsp_q_out = &reg->isp25mq.rsp_q_out;
        mutex_unlock(&ha->vport_lock);
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc00b,
+           "options=%x id=%d rsp_q_in=%p rsp_q_out=%p",
+           rsp->options, rsp->id, rsp->rsp_q_in,
+           rsp->rsp_q_out);
+       ql_dbg(ql_dbg_init, base_vha, 0x00e5,
+           "options=%x id=%d rsp_q_in=%p rsp_q_out=%p",
+           rsp->options, rsp->id, rsp->rsp_q_in,
+           rsp->rsp_q_out);
 
        ret = qla25xx_request_irq(rsp);
        if (ret)
@@ -757,7 +812,8 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
 
        ret = qla25xx_init_rsp_que(base_vha, rsp);
        if (ret != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha, "%s failed\n", __func__);
+               ql_log(ql_log_fatal, base_vha, 0x00e7,
+                   "%s failed.\n", __func__);
                mutex_lock(&ha->vport_lock);
                clear_bit(que_id, ha->rsp_qid_map);
                mutex_unlock(&ha->vport_lock);
index e1138bcc834c1e56b0bab79efbd94402d9116147..5cbf33a50b14415eed6b5101cba7f2d17080fccc 100644 (file)
@@ -348,6 +348,7 @@ static void
 qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off)
 {
        u32 win_read;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        ha->crb_win = CRB_HI(*off);
        writel(ha->crb_win,
@@ -358,9 +359,10 @@ qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off)
         */
        win_read = RD_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase));
        if (win_read != ha->crb_win) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "%s: Written crbwin (0x%x) != Read crbwin (0x%x), "
-                   "off=0x%lx\n", __func__, ha->crb_win, win_read, *off));
+               ql_dbg(ql_dbg_p3p, vha, 0xb000,
+                   "%s: Written crbwin (0x%x) "
+                   "!= Read crbwin (0x%x), off=0x%lx.\n",
+                   ha->crb_win, win_read, *off);
        }
        *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase;
 }
@@ -368,6 +370,7 @@ qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off)
 static inline unsigned long
 qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        /* See if we are currently pointing to the region we want to use next */
        if ((off >= QLA82XX_CRB_PCIX_HOST) && (off < QLA82XX_CRB_DDR_NET)) {
                /* No need to change window. PCIX and PCIEregs are in both
@@ -398,9 +401,10 @@ qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off)
                        return off;
        }
        /* strange address given */
-       qla_printk(KERN_WARNING, ha,
-               "%s: Warning: unm_nic_pci_set_crbwindow called with"
-               " an unknown address(%llx)\n", QLA2XXX_DRIVER_NAME, off);
+       ql_dbg(ql_dbg_p3p, vha, 0xb001,
+           "%x: Warning: unm_nic_pci_set_crbwindow "
+           "called with an unknown address(%llx).\n",
+           QLA2XXX_DRIVER_NAME, off);
        return off;
 }
 
@@ -563,6 +567,7 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
 {
        int window;
        u32 win_read;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET,
                QLA82XX_ADDR_DDR_NET_MAX)) {
@@ -574,8 +579,8 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
                win_read = qla82xx_rd_32(ha,
                        ha->mn_win_crb | QLA82XX_PCI_CRBSPACE);
                if ((win_read << 17) != window) {
-                       qla_printk(KERN_WARNING, ha,
-                           "%s: Written MNwin (0x%x) != Read MNwin (0x%x)\n",
+                       ql_dbg(ql_dbg_p3p, vha, 0xb003,
+                           "%s: Written MNwin (0x%x) != Read MNwin (0x%x).\n",
                            __func__, window, win_read);
                }
                addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET;
@@ -583,7 +588,7 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
                QLA82XX_ADDR_OCM0_MAX)) {
                unsigned int temp1;
                if ((addr & 0x00ff800) == 0xff800) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0xb004,
                            "%s: QM access not handled.\n", __func__);
                        addr = -1UL;
                }
@@ -596,8 +601,8 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
                temp1 = ((window & 0x1FF) << 7) |
                    ((window & 0x0FFFE0000) >> 17);
                if (win_read != temp1) {
-                       qla_printk(KERN_WARNING, ha,
-                           "%s: Written OCMwin (0x%x) != Read OCMwin (0x%x)\n",
+                       ql_log(ql_log_warn, vha, 0xb005,
+                           "%s: Written OCMwin (0x%x) != Read OCMwin (0x%x).\n",
                            __func__, temp1, win_read);
                }
                addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M;
@@ -612,8 +617,8 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
                win_read = qla82xx_rd_32(ha,
                        ha->ms_win_crb | QLA82XX_PCI_CRBSPACE);
                if (win_read != window) {
-                       qla_printk(KERN_WARNING, ha,
-                           "%s: Written MSwin (0x%x) != Read MSwin (0x%x)\n",
+                       ql_log(ql_log_warn, vha, 0xb006,
+                           "%s: Written MSwin (0x%x) != Read MSwin (0x%x).\n",
                            __func__, window, win_read);
                }
                addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET;
@@ -624,9 +629,9 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
                 */
                if ((qla82xx_pci_set_window_warning_count++ < 8) ||
                    (qla82xx_pci_set_window_warning_count%64 == 0)) {
-                       qla_printk(KERN_WARNING, ha,
-                           "%s: Warning:%s Unknown address range!\n", __func__,
-                           QLA2XXX_DRIVER_NAME);
+                       ql_log(ql_log_warn, vha, 0xb007,
+                           "%s: Warning:%s Unknown address range!.\n",
+                           __func__, QLA2XXX_DRIVER_NAME);
                }
                addr = -1UL;
        }
@@ -671,6 +676,7 @@ static int qla82xx_pci_mem_read_direct(struct qla_hw_data *ha,
        uint8_t         *mem_ptr = NULL;
        unsigned long   mem_base;
        unsigned long   mem_page;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        write_lock_irqsave(&ha->hw_lock, flags);
 
@@ -682,9 +688,10 @@ static int qla82xx_pci_mem_read_direct(struct qla_hw_data *ha,
        if ((start == -1UL) ||
                (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
                write_unlock_irqrestore(&ha->hw_lock, flags);
-               qla_printk(KERN_ERR, ha,
-                       "%s out of bound pci memory access. "
-                       "offset is 0x%llx\n", QLA2XXX_DRIVER_NAME, off);
+               ql_log(ql_log_fatal, vha, 0xb008,
+                   "%s out of bound pci memory "
+                   "access, offset is 0x%llx.\n",
+                   QLA2XXX_DRIVER_NAME, off);
                return -1;
        }
 
@@ -741,6 +748,7 @@ qla82xx_pci_mem_write_direct(struct qla_hw_data *ha,
        uint8_t         *mem_ptr = NULL;
        unsigned long   mem_base;
        unsigned long   mem_page;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        write_lock_irqsave(&ha->hw_lock, flags);
 
@@ -752,9 +760,10 @@ qla82xx_pci_mem_write_direct(struct qla_hw_data *ha,
        if ((start == -1UL) ||
                (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
                write_unlock_irqrestore(&ha->hw_lock, flags);
-               qla_printk(KERN_ERR, ha,
-                       "%s out of bound pci memory access. "
-                       "offset is 0x%llx\n", QLA2XXX_DRIVER_NAME, off);
+               ql_log(ql_log_fatal, vha, 0xb009,
+                   "%s out of bount memory "
+                   "access, offset is 0x%llx.\n",
+                   QLA2XXX_DRIVER_NAME, off);
                return -1;
        }
 
@@ -855,15 +864,16 @@ qla82xx_wait_rom_busy(struct qla_hw_data *ha)
 {
        long timeout = 0;
        long done = 0 ;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        while (done == 0) {
                done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
                done &= 4;
                timeout++;
                if (timeout >= rom_max_timeout) {
-                       DEBUG(qla_printk(KERN_INFO, ha,
-                               "%s: Timeout reached waiting for rom busy",
-                               QLA2XXX_DRIVER_NAME));
+                       ql_dbg(ql_dbg_p3p, vha, 0xb00a,
+                           "%s: Timeout reached waiting for rom busy.\n",
+                           QLA2XXX_DRIVER_NAME);
                        return -1;
                }
        }
@@ -875,15 +885,16 @@ qla82xx_wait_rom_done(struct qla_hw_data *ha)
 {
        long timeout = 0;
        long done = 0 ;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        while (done == 0) {
                done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
                done &= 2;
                timeout++;
                if (timeout >= rom_max_timeout) {
-                       DEBUG(qla_printk(KERN_INFO, ha,
-                               "%s: Timeout reached  waiting for rom done",
-                               QLA2XXX_DRIVER_NAME));
+                       ql_dbg(ql_dbg_p3p, vha, 0xb00b,
+                           "%s: Timeout reached waiting for rom done.\n",
+                           QLA2XXX_DRIVER_NAME);
                        return -1;
                }
        }
@@ -893,15 +904,16 @@ qla82xx_wait_rom_done(struct qla_hw_data *ha)
 static int
 qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0xb);
        qla82xx_wait_rom_busy(ha);
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                       "%s: Error waiting for rom done\n",
-                       QLA2XXX_DRIVER_NAME);
+               ql_log(ql_log_fatal, vha, 0x00ba,
+                   "Error waiting for rom done.\n");
                return -1;
        }
        /* Reset abyte_cnt and dummy_byte_cnt */
@@ -917,6 +929,7 @@ static int
 qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
 {
        int ret, loops = 0;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) {
                udelay(100);
@@ -924,9 +937,8 @@ qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
                loops++;
        }
        if (loops >= 50000) {
-               qla_printk(KERN_INFO, ha,
-                       "%s: qla82xx_rom_lock failed\n",
-                       QLA2XXX_DRIVER_NAME);
+               ql_log(ql_log_fatal, vha, 0x00b9,
+                   "Failed to aquire SEM2 lock.\n");
                return -1;
        }
        ret = qla82xx_do_rom_fast_read(ha, addr, valp);
@@ -937,11 +949,12 @@ qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
 static int
 qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR);
        qla82xx_wait_rom_busy(ha);
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Error waiting for rom done\n");
+               ql_log(ql_log_warn, vha, 0xb00c,
+                   "Error waiting for rom done.\n");
                return -1;
        }
        *val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA);
@@ -955,6 +968,7 @@ qla82xx_flash_wait_write_finish(struct qla_hw_data *ha)
        uint32_t done = 1 ;
        uint32_t val;
        int ret = 0;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
        while ((done != 0) && (ret == 0)) {
@@ -964,8 +978,8 @@ qla82xx_flash_wait_write_finish(struct qla_hw_data *ha)
                udelay(10);
                cond_resched();
                if (timeout >= 50000) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Timeout reached  waiting for write finish");
+                       ql_log(ql_log_warn, vha, 0xb00d,
+                           "Timeout reached waiting for write finish.\n");
                        return -1;
                }
        }
@@ -992,13 +1006,14 @@ qla82xx_flash_set_write_enable(struct qla_hw_data *ha)
 static int
 qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        if (qla82xx_flash_set_write_enable(ha))
                return -1;
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, val);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0x1);
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Error waiting for rom done\n");
+               ql_log(ql_log_warn, vha, 0xb00e,
+                   "Error waiting for rom done.\n");
                return -1;
        }
        return qla82xx_flash_wait_write_finish(ha);
@@ -1007,10 +1022,11 @@ qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val)
 static int
 qla82xx_write_disable_flash(struct qla_hw_data *ha)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI);
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Error waiting for rom done\n");
+               ql_log(ql_log_warn, vha, 0xb00f,
+                   "Error waiting for rom done.\n");
                return -1;
        }
        return 0;
@@ -1020,13 +1036,16 @@ static int
 ql82xx_rom_lock_d(struct qla_hw_data *ha)
 {
        int loops = 0;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
        while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) {
                udelay(100);
                cond_resched();
                loops++;
        }
        if (loops >= 50000) {
-               qla_printk(KERN_WARNING, ha, "ROM lock failed\n");
+               ql_log(ql_log_warn, vha, 0xb010,
+                   "ROM lock failed.\n");
                return -1;
        }
        return 0;;
@@ -1037,10 +1056,12 @@ qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr,
        uint32_t data)
 {
        int ret = 0;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        ret = ql82xx_rom_lock_d(ha);
        if (ret < 0) {
-               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               ql_log(ql_log_warn, vha, 0xb011,
+                   "ROM lock failed.\n");
                return ret;
        }
 
@@ -1053,8 +1074,8 @@ qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr,
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_PP);
        qla82xx_wait_rom_busy(ha);
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                       "Error waiting for rom done\n");
+               ql_log(ql_log_warn, vha, 0xb012,
+                   "Error waiting for rom done.\n");
                ret = -1;
                goto done_write;
        }
@@ -1159,8 +1180,8 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
         */
        if (qla82xx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL ||
            qla82xx_rom_fast_read(ha, 4, &n) != 0) {
-               qla_printk(KERN_WARNING, ha,
-                   "[ERROR] Reading crb_init area: n: %08x\n", n);
+               ql_log(ql_log_fatal, vha, 0x006e,
+                   "Error Reading crb_init area: n: %08x.\n", n);
                return -1;
        }
 
@@ -1172,20 +1193,18 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
 
        /* number of addr/value pair should not exceed 1024 enteries */
        if (n  >= 1024) {
-               qla_printk(KERN_WARNING, ha,
-                   "%s: %s:n=0x%x [ERROR] Card flash not initialized.\n",
-                   QLA2XXX_DRIVER_NAME, __func__, n);
+               ql_log(ql_log_fatal, vha, 0x0071,
+                   "Card flash not initialized:n=0x%x.\n", n);
                return -1;
        }
 
-       qla_printk(KERN_INFO, ha,
-           "%s: %d CRB init values found in ROM.\n", QLA2XXX_DRIVER_NAME, n);
+       ql_log(ql_log_info, vha, 0x0072,
+           "%d CRB init values found in ROM.\n", n);
 
        buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL);
        if (buf == NULL) {
-               qla_printk(KERN_WARNING, ha,
-                   "%s: [ERROR] Unable to malloc memory.\n",
-                   QLA2XXX_DRIVER_NAME);
+               ql_log(ql_log_fatal, vha, 0x010c,
+                   "Unable to allocate memory.\n");
                return -1;
        }
 
@@ -1236,9 +1255,8 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha)
                        continue;
 
                if (off == ADDR_ERROR) {
-                       qla_printk(KERN_WARNING, ha,
-                           "%s: [ERROR] Unknown addr: 0x%08lx\n",
-                           QLA2XXX_DRIVER_NAME, buf[i].addr);
+                       ql_log(ql_log_fatal, vha, 0x0116,
+                           "Unknow addr: 0x%08lx.\n", buf[i].addr);
                        continue;
                }
 
@@ -1370,7 +1388,7 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
                if (j >= MAX_CTL_CHECK) {
                        if (printk_ratelimit())
                                dev_err(&ha->pdev->dev,
-                                   "failed to write through agent\n");
+                                   "failed to write through agent.\n");
                        ret = -1;
                        break;
                }
@@ -1460,7 +1478,7 @@ qla82xx_pci_mem_read_2M(struct qla_hw_data *ha,
                if (j >= MAX_CTL_CHECK) {
                        if (printk_ratelimit())
                                dev_err(&ha->pdev->dev,
-                                   "failed to read through agent\n");
+                                   "failed to read through agent.\n");
                        break;
                }
 
@@ -1633,17 +1651,15 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
        uint32_t len = 0;
 
        if (pci_request_regions(ha->pdev, QLA2XXX_DRIVER_NAME)) {
-               qla_printk(KERN_WARNING, ha,
-                       "Failed to reserve selected regions (%s)\n",
-                       pci_name(ha->pdev));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x000c,
+                   "Failed to reserver selected regions.\n");
                goto iospace_error_exit;
        }
 
        /* Use MMIO operations for all accesses. */
        if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) {
-               qla_printk(KERN_ERR, ha,
-                       "region #0 not an MMIO resource (%s), aborting\n",
-                       pci_name(ha->pdev));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x000d,
+                   "Region #0 not an MMIO resource, aborting.\n");
                goto iospace_error_exit;
        }
 
@@ -1651,9 +1667,8 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
        ha->nx_pcibase =
            (unsigned long)ioremap(pci_resource_start(ha->pdev, 0), len);
        if (!ha->nx_pcibase) {
-               qla_printk(KERN_ERR, ha,
-                   "cannot remap pcibase MMIO (%s), aborting\n",
-                   pci_name(ha->pdev));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x000e,
+                   "Cannot remap pcibase MMIO, aborting.\n");
                pci_release_regions(ha->pdev);
                goto iospace_error_exit;
        }
@@ -1667,9 +1682,8 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
                    (unsigned long)ioremap((pci_resource_start(ha->pdev, 4) +
                    (ha->pdev->devfn << 12)), 4);
                if (!ha->nxdb_wr_ptr) {
-                       qla_printk(KERN_ERR, ha,
-                           "cannot remap MMIO (%s), aborting\n",
-                           pci_name(ha->pdev));
+                       ql_log_pci(ql_log_fatal, ha->pdev, 0x000f,
+                           "Cannot remap MMIO, aborting.\n");
                        pci_release_regions(ha->pdev);
                        goto iospace_error_exit;
                }
@@ -1687,6 +1701,16 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
 
        ha->max_req_queues = ha->max_rsp_queues = 1;
        ha->msix_count = ha->max_rsp_queues + 1;
+       ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc006,
+           "nx_pci_base=%p iobase=%p "
+           "max_req_queues=%d msix_count=%d.\n",
+           ha->nx_pcibase, ha->iobase,
+           ha->max_req_queues, ha->msix_count);
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0010,
+           "nx_pci_base=%p iobase=%p "
+           "max_req_queues=%d msix_count=%d.\n",
+           ha->nx_pcibase, ha->iobase,
+           ha->max_req_queues, ha->msix_count);
        return 0;
 
 iospace_error_exit:
@@ -1712,6 +1736,9 @@ qla82xx_pci_config(scsi_qla_host_t *vha)
        pci_set_master(ha->pdev);
        ret = pci_set_mwi(ha->pdev);
        ha->chip_revision = ha->pdev->revision;
+       ql_dbg(ql_dbg_init, vha, 0x0043,
+           "Chip revision:%ld.\n",
+           ha->chip_revision);
        return 0;
 }
 
@@ -1877,6 +1904,7 @@ qla82xx_check_cmdpeg_state(struct qla_hw_data *ha)
 {
        u32 val = 0;
        int retries = 60;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        do {
                read_lock(&ha->hw_lock);
@@ -1892,15 +1920,15 @@ qla82xx_check_cmdpeg_state(struct qla_hw_data *ha)
                default:
                        break;
                }
-               qla_printk(KERN_WARNING, ha,
-                       "CRB_CMDPEG_STATE: 0x%x and retries: 0x%x\n",
-                       val, retries);
+               ql_log(ql_log_info, vha, 0x00a8,
+                   "CRB_CMDPEG_STATE: 0x%x and retries:0x%x.\n",
+                   val, retries);
 
                msleep(500);
 
        } while (--retries);
 
-       qla_printk(KERN_INFO, ha,
+       ql_log(ql_log_fatal, vha, 0x00a9,
            "Cmd Peg initialization failed: 0x%x.\n", val);
 
        val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
@@ -1915,6 +1943,7 @@ qla82xx_check_rcvpeg_state(struct qla_hw_data *ha)
 {
        u32 val = 0;
        int retries = 60;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        do {
                read_lock(&ha->hw_lock);
@@ -1930,17 +1959,16 @@ qla82xx_check_rcvpeg_state(struct qla_hw_data *ha)
                default:
                        break;
                }
-
-               qla_printk(KERN_WARNING, ha,
-                       "CRB_RCVPEG_STATE: 0x%x and retries: 0x%x\n",
-                       val, retries);
+               ql_log(ql_log_info, vha, 0x00ab,
+                   "CRB_RCVPEG_STATE: 0x%x and retries: 0x%x.\n",
+                   val, retries);
 
                msleep(500);
 
        } while (--retries);
 
-       qla_printk(KERN_INFO, ha,
-               "Rcv Peg initialization failed: 0x%x.\n", val);
+       ql_log(ql_log_fatal, vha, 0x00ac,
+           "Rcv Peg initializatin failed: 0x%x.\n", val);
        read_lock(&ha->hw_lock);
        qla82xx_wr_32(ha, CRB_RCVPEG_STATE, PHAN_INITIALIZE_FAILED);
        read_unlock(&ha->hw_lock);
@@ -1989,13 +2017,11 @@ qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
        }
 
        if (ha->mcp) {
-               DEBUG3_11(printk(KERN_INFO "%s(%ld): "
-                       "Got mailbox completion. cmd=%x.\n",
-                       __func__, vha->host_no, ha->mcp->mb[0]));
+               ql_dbg(ql_dbg_async, vha, 0x5052,
+                   "Got mailbox completion. cmd=%x.\n", ha->mcp->mb[0]);
        } else {
-               qla_printk(KERN_INFO, ha,
-                       "%s(%ld): MBX pointer ERROR!\n",
-                       __func__, vha->host_no);
+               ql_dbg(ql_dbg_async, vha, 0x5053,
+                   "MBX pointer ERROR.\n");
        }
 }
 
@@ -2019,13 +2045,13 @@ qla82xx_intr_handler(int irq, void *dev_id)
        int status = 0, status1 = 0;
        unsigned long   flags;
        unsigned long   iter;
-       uint32_t        stat;
+       uint32_t        stat = 0;
        uint16_t        mb[4];
 
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                       "%s(): NULL response queue pointer\n", __func__);
+                       "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
        ha = rsp->hw;
@@ -2075,9 +2101,9 @@ qla82xx_intr_handler(int irq, void *dev_id)
                                qla24xx_process_response_queue(vha, rsp);
                                break;
                        default:
-                               DEBUG2(printk("scsi(%ld): "
-                                       " Unrecognized interrupt type (%d).\n",
-                                       vha->host_no, stat & 0xff));
+                               ql_dbg(ql_dbg_async, vha, 0x5054,
+                                   "Unrecognized interrupt type (%d).\n",
+                                   stat & 0xff);
                                break;
                        }
                }
@@ -2089,8 +2115,8 @@ qla82xx_intr_handler(int irq, void *dev_id)
 
 #ifdef QL_DEBUG_LEVEL_17
        if (!irq && ha->flags.eeh_busy)
-               qla_printk(KERN_WARNING, ha,
-                   "isr: status %x, cmd_flags %lx, mbox_int %x, stat %x\n",
+               ql_log(ql_log_warn, vha, 0x503d,
+                   "isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n",
                    status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
 #endif
 
@@ -2111,13 +2137,13 @@ qla82xx_msix_default(int irq, void *dev_id)
        struct device_reg_82xx __iomem *reg;
        int status = 0;
        unsigned long flags;
-       uint32_t stat;
+       uint32_t stat = 0;
        uint16_t mb[4];
 
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                       "%s(): NULL response queue pointer\n", __func__);
+                       "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
        ha = rsp->hw;
@@ -2149,9 +2175,9 @@ qla82xx_msix_default(int irq, void *dev_id)
                                qla24xx_process_response_queue(vha, rsp);
                                break;
                        default:
-                               DEBUG2(printk("scsi(%ld): "
-                                       " Unrecognized interrupt type (%d).\n",
-                                       vha->host_no, stat & 0xff));
+                               ql_dbg(ql_dbg_async, vha, 0x5041,
+                                   "Unrecognized interrupt type (%d).\n",
+                                   stat & 0xff);
                                break;
                        }
                }
@@ -2162,9 +2188,9 @@ qla82xx_msix_default(int irq, void *dev_id)
 
 #ifdef QL_DEBUG_LEVEL_17
        if (!irq && ha->flags.eeh_busy)
-               qla_printk(KERN_WARNING, ha,
-                       "isr: status %x, cmd_flags %lx, mbox_int %x, stat %x\n",
-                       status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
+               ql_log(ql_log_warn, vha, 0x5044,
+                   "isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n",
+                   status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
 #endif
 
        if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
@@ -2186,7 +2212,7 @@ qla82xx_msix_rsp_q(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                       "%s(): NULL response queue pointer\n", __func__);
+                       "%s(): NULL response queue pointer.\n", __func__);
                return IRQ_NONE;
        }
 
@@ -2215,7 +2241,7 @@ qla82xx_poll(int irq, void *dev_id)
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
                printk(KERN_INFO
-                       "%s(): NULL response queue pointer\n", __func__);
+                       "%s(): NULL response queue pointer.\n", __func__);
                return;
        }
        ha = rsp->hw;
@@ -2245,9 +2271,9 @@ qla82xx_poll(int irq, void *dev_id)
                        qla24xx_process_response_queue(vha, rsp);
                        break;
                default:
-                       DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
-                               "(%d).\n",
-                               vha->host_no, stat & 0xff));
+                       ql_dbg(ql_dbg_p3p, vha, 0xb013,
+                           "Unrecognized interrupt type (%d).\n",
+                           stat * 0xff);
                        break;
                }
        }
@@ -2347,9 +2373,8 @@ qla82xx_set_rst_ready(struct qla_hw_data *ha)
                drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
        }
        drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
-       qla_printk(KERN_INFO, ha,
-               "%s(%ld):drv_state = 0x%x\n",
-               __func__, vha->host_no, drv_state);
+       ql_log(ql_log_info, vha, 0x00bb,
+           "drv_state = 0x%x.\n", drv_state);
        qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
 }
 
@@ -2392,8 +2417,8 @@ qla82xx_load_fw(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
 
        if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) {
-               qla_printk(KERN_ERR, ha,
-                       "%s: Error during CRB Initialization\n", __func__);
+               ql_log(ql_log_fatal, vha, 0x009f,
+                   "Error during CRB initialization.\n");
                return QLA_FUNCTION_FAILED;
        }
        udelay(500);
@@ -2411,27 +2436,27 @@ qla82xx_load_fw(scsi_qla_host_t *vha)
        if (ql2xfwloadbin == 2)
                goto try_blob_fw;
 
-       qla_printk(KERN_INFO, ha,
-               "Attempting to load firmware from flash\n");
+       ql_log(ql_log_info, vha, 0x00a0,
+           "Attempting to load firmware from flash.\n");
 
        if (qla82xx_fw_load_from_flash(ha) == QLA_SUCCESS) {
-               qla_printk(KERN_ERR, ha,
-                   "Firmware loaded successfully from flash\n");
+               ql_log(ql_log_info, vha, 0x00a1,
+                   "Firmware loaded successully from flash.\n");
                return QLA_SUCCESS;
        } else {
-               qla_printk(KERN_ERR, ha,
-                   "Firmware load from flash failed\n");
+               ql_log(ql_log_warn, vha, 0x0108,
+                   "Firmware load from flash failed.\n");
        }
 
 try_blob_fw:
-       qla_printk(KERN_INFO, ha,
-           "Attempting to load firmware from blob\n");
+       ql_log(ql_log_info, vha, 0x00a2,
+           "Attempting to load firmware from blob.\n");
 
        /* Load firmware blob. */
        blob = ha->hablob = qla2x00_request_firmware(vha);
        if (!blob) {
-               qla_printk(KERN_ERR, ha,
-                       "Firmware image not present.\n");
+               ql_log(ql_log_fatal, vha, 0x00a3,
+                   "Firmware image not preset.\n");
                goto fw_load_failed;
        }
 
@@ -2441,20 +2466,19 @@ try_blob_fw:
                /* Fallback to URI format */
                if (qla82xx_validate_firmware_blob(vha,
                        QLA82XX_UNIFIED_ROMIMAGE)) {
-                       qla_printk(KERN_ERR, ha,
-                               "No valid firmware image found!!!");
+                       ql_log(ql_log_fatal, vha, 0x00a4,
+                           "No valid firmware image found.\n");
                        return QLA_FUNCTION_FAILED;
                }
        }
 
        if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) {
-               qla_printk(KERN_ERR, ha,
-                       "%s: Firmware loaded successfully "
-                       " from binary blob\n", __func__);
+               ql_log(ql_log_info, vha, 0x00a5,
+                   "Firmware loaded successfully from binary blob.\n");
                return QLA_SUCCESS;
        } else {
-               qla_printk(KERN_ERR, ha,
-                   "Firmware load failed from binary blob\n");
+               ql_log(ql_log_fatal, vha, 0x00a6,
+                   "Firmware load failed for binary blob.\n");
                blob->fw = NULL;
                blob = NULL;
                goto fw_load_failed;
@@ -2486,15 +2510,15 @@ qla82xx_start_firmware(scsi_qla_host_t *vha)
        qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0);
 
        if (qla82xx_load_fw(vha) != QLA_SUCCESS) {
-               qla_printk(KERN_INFO, ha,
-                       "%s: Error trying to start fw!\n", __func__);
+               ql_log(ql_log_fatal, vha, 0x00a7,
+                   "Error trying to start fw.\n");
                return QLA_FUNCTION_FAILED;
        }
 
        /* Handshake with the card before we register the devices. */
        if (qla82xx_check_cmdpeg_state(ha) != QLA_SUCCESS) {
-               qla_printk(KERN_INFO, ha,
-                       "%s: Error during card handshake!\n", __func__);
+               ql_log(ql_log_fatal, vha, 0x00aa,
+                   "Error during card handshake.\n");
                return QLA_FUNCTION_FAILED;
        }
 
@@ -2663,8 +2687,11 @@ qla82xx_start_scsi(srb_t *sp)
        /* Send marker if required */
        if (vha->marker_needed != 0) {
                if (qla2x00_marker(vha, req,
-                       rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS)
+                       rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) {
+                       ql_log(ql_log_warn, vha, 0x300c,
+                           "qla2x00_marker failed for cmd=%p.\n", cmd);
                        return QLA_FUNCTION_FAILED;
+               }
                vha->marker_needed = 0;
        }
 
@@ -2701,8 +2728,13 @@ qla82xx_start_scsi(srb_t *sp)
                uint16_t i;
 
                more_dsd_lists = qla82xx_calc_dsd_lists(tot_dsds);
-               if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN)
+               if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN) {
+                       ql_dbg(ql_dbg_io, vha, 0x300d,
+                           "Num of DSD list %d is than %d for cmd=%p.\n",
+                           more_dsd_lists + ha->gbl_dsd_inuse, NUM_DSD_CHAIN,
+                           cmd);
                        goto queuing_error;
+               }
 
                if (more_dsd_lists <= ha->gbl_dsd_avail)
                        goto sufficient_dsds;
@@ -2711,13 +2743,20 @@ qla82xx_start_scsi(srb_t *sp)
 
                for (i = 0; i < more_dsd_lists; i++) {
                        dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC);
-                       if (!dsd_ptr)
+                       if (!dsd_ptr) {
+                               ql_log(ql_log_fatal, vha, 0x300e,
+                                   "Failed to allocate memory for dsd_dma "
+                                   "for cmd=%p.\n", cmd);
                                goto queuing_error;
+                       }
 
                        dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool,
                                GFP_ATOMIC, &dsd_ptr->dsd_list_dma);
                        if (!dsd_ptr->dsd_addr) {
                                kfree(dsd_ptr);
+                               ql_log(ql_log_fatal, vha, 0x300f,
+                                   "Failed to allocate memory for dsd_addr "
+                                   "for cmd=%p.\n", cmd);
                                goto queuing_error;
                        }
                        list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list);
@@ -2742,17 +2781,16 @@ sufficient_dsds:
 
                ctx = sp->ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC);
                if (!sp->ctx) {
-                       DEBUG(printk(KERN_INFO
-                               "%s(%ld): failed to allocate"
-                               " ctx.\n", __func__, vha->host_no));
+                       ql_log(ql_log_fatal, vha, 0x3010,
+                           "Failed to allocate ctx for cmd=%p.\n", cmd);
                        goto queuing_error;
                }
                memset(ctx, 0, sizeof(struct ct6_dsd));
                ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool,
                        GFP_ATOMIC, &ctx->fcp_cmnd_dma);
                if (!ctx->fcp_cmnd) {
-                       DEBUG2_3(printk("%s(%ld): failed to allocate"
-                               " fcp_cmnd.\n", __func__, vha->host_no));
+                       ql_log(ql_log_fatal, vha, 0x3011,
+                           "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd);
                        goto queuing_error_fcp_cmnd;
                }
 
@@ -2766,6 +2804,9 @@ sufficient_dsds:
                                /* SCSI command bigger than 16 bytes must be
                                 * multiple of 4
                                 */
+                               ql_log(ql_log_warn, vha, 0x3012,
+                                   "scsi cmd len %d not multiple of 4 "
+                                   "for cmd=%p.\n", cmd->cmd_len, cmd);
                                goto queuing_error_fcp_cmnd;
                        }
                        ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4;
@@ -2845,7 +2886,7 @@ sufficient_dsds:
                cmd_pkt->entry_status = (uint8_t) rsp->id;
        } else {
                struct cmd_type_7 *cmd_pkt;
-               req_cnt = qla24xx_calc_iocbs(tot_dsds);
+               req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
                if (req->cnt < (req_cnt + 2)) {
                        cnt = (uint16_t)RD_REG_DWORD_RELAXED(
                            &reg->req_q_out[0]);
@@ -2979,8 +3020,8 @@ qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
        /* Dword reads to flash. */
        for (i = 0; i < length/4; i++, faddr += 4) {
                if (qla82xx_rom_fast_read(ha, faddr, &val)) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Do ROM fast read failed\n");
+                       ql_log(ql_log_warn, vha, 0x0106,
+                           "Do ROM fast read failed.\n");
                        goto done_read;
                }
                dwptr[i] = __constant_cpu_to_le32(val);
@@ -2994,10 +3035,12 @@ qla82xx_unprotect_flash(struct qla_hw_data *ha)
 {
        int ret;
        uint32_t val;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        ret = ql82xx_rom_lock_d(ha);
        if (ret < 0) {
-               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               ql_log(ql_log_warn, vha, 0xb014,
+                   "ROM Lock failed.\n");
                return ret;
        }
 
@@ -3013,7 +3056,8 @@ qla82xx_unprotect_flash(struct qla_hw_data *ha)
        }
 
        if (qla82xx_write_disable_flash(ha) != 0)
-               qla_printk(KERN_WARNING, ha, "Write disable failed\n");
+               ql_log(ql_log_warn, vha, 0xb015,
+                   "Write disable failed.\n");
 
 done_unprotect:
        qla82xx_rom_unlock(ha);
@@ -3025,10 +3069,12 @@ qla82xx_protect_flash(struct qla_hw_data *ha)
 {
        int ret;
        uint32_t val;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        ret = ql82xx_rom_lock_d(ha);
        if (ret < 0) {
-               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               ql_log(ql_log_warn, vha, 0xb016,
+                   "ROM Lock failed.\n");
                return ret;
        }
 
@@ -3040,10 +3086,12 @@ qla82xx_protect_flash(struct qla_hw_data *ha)
        /* LOCK all sectors */
        ret = qla82xx_write_status_reg(ha, val);
        if (ret < 0)
-               qla_printk(KERN_WARNING, ha, "Write status register failed\n");
+               ql_log(ql_log_warn, vha, 0xb017,
+                   "Write status register failed.\n");
 
        if (qla82xx_write_disable_flash(ha) != 0)
-               qla_printk(KERN_WARNING, ha, "Write disable failed\n");
+               ql_log(ql_log_warn, vha, 0xb018,
+                   "Write disable failed.\n");
 done_protect:
        qla82xx_rom_unlock(ha);
        return ret;
@@ -3053,10 +3101,12 @@ static int
 qla82xx_erase_sector(struct qla_hw_data *ha, int addr)
 {
        int ret = 0;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        ret = ql82xx_rom_lock_d(ha);
        if (ret < 0) {
-               qla_printk(KERN_WARNING, ha, "ROM Lock failed\n");
+               ql_log(ql_log_warn, vha, 0xb019,
+                   "ROM Lock failed.\n");
                return ret;
        }
 
@@ -3066,8 +3116,8 @@ qla82xx_erase_sector(struct qla_hw_data *ha, int addr)
        qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_SE);
 
        if (qla82xx_wait_rom_done(ha)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Error waiting for rom done\n");
+               ql_log(ql_log_warn, vha, 0xb01a,
+                   "Error waiting for rom done.\n");
                ret = -1;
                goto done;
        }
@@ -3110,10 +3160,10 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
                optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
                    &optrom_dma, GFP_KERNEL);
                if (!optrom) {
-                       qla_printk(KERN_DEBUG, ha,
-                               "Unable to allocate memory for optrom "
-                               "burst write (%x KB).\n",
-                               OPTROM_BURST_SIZE / 1024);
+                       ql_log(ql_log_warn, vha, 0xb01b,
+                           "Unable to allocate memory "
+                           "for optron burst write (%x KB).\n",
+                           OPTROM_BURST_SIZE / 1024);
                }
        }
 
@@ -3122,8 +3172,8 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
 
        ret = qla82xx_unprotect_flash(ha);
        if (ret) {
-               qla_printk(KERN_WARNING, ha,
-                       "Unable to unprotect flash for update.\n");
+               ql_log(ql_log_warn, vha, 0xb01c,
+                   "Unable to unprotect flash for update.\n");
                goto write_done;
        }
 
@@ -3133,9 +3183,9 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
 
                        ret = qla82xx_erase_sector(ha, faddr);
                        if (ret) {
-                               DEBUG9(qla_printk(KERN_ERR, ha,
-                                   "Unable to erase sector: "
-                                   "address=%x.\n", faddr));
+                               ql_log(ql_log_warn, vha, 0xb01d,
+                                   "Unable to erase sector: address=%x.\n",
+                                   faddr);
                                break;
                        }
                }
@@ -3149,12 +3199,12 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
                            (ha->flash_data_off | faddr),
                            OPTROM_BURST_DWORDS);
                        if (ret != QLA_SUCCESS) {
-                               qla_printk(KERN_WARNING, ha,
+                               ql_log(ql_log_warn, vha, 0xb01e,
                                    "Unable to burst-write optrom segment "
                                    "(%x/%x/%llx).\n", ret,
                                    (ha->flash_data_off | faddr),
                                    (unsigned long long)optrom_dma);
-                               qla_printk(KERN_WARNING, ha,
+                               ql_log(ql_log_warn, vha, 0xb01f,
                                    "Reverting to slow-write.\n");
 
                                dma_free_coherent(&ha->pdev->dev,
@@ -3171,16 +3221,16 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr,
                ret = qla82xx_write_flash_dword(ha, faddr,
                    cpu_to_le32(*dwptr));
                if (ret) {
-                       DEBUG9(printk(KERN_DEBUG "%s(%ld) Unable to program"
-                           "flash address=%x data=%x.\n", __func__,
-                           ha->host_no, faddr, *dwptr));
+                       ql_dbg(ql_dbg_p3p, vha, 0xb020,
+                           "Unable to program flash address=%x data=%x.\n",
+                           faddr, *dwptr);
                        break;
                }
        }
 
        ret = qla82xx_protect_flash(ha);
        if (ret)
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0xb021,
                    "Unable to protect flash after update.\n");
 write_done:
        if (optrom)
@@ -3244,9 +3294,12 @@ qla82xx_start_iocbs(srb_t *sp)
 
 void qla82xx_rom_lock_recovery(struct qla_hw_data *ha)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
        if (qla82xx_rom_lock(ha))
                /* Someone else is holding the lock. */
-               qla_printk(KERN_INFO, ha, "Resetting rom_lock\n");
+               ql_log(ql_log_info, vha, 0xb022,
+                   "Resetting rom_lock.\n");
 
        /*
         * Either we got the lock, or someone
@@ -3313,7 +3366,8 @@ qla82xx_device_bootstrap(scsi_qla_host_t *vha)
 
 dev_initialize:
        /* set to DEV_INITIALIZING */
-       qla_printk(KERN_INFO, ha, "HW State: INITIALIZING\n");
+       ql_log(ql_log_info, vha, 0x009e,
+           "HW State: INITIALIZING.\n");
        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING);
 
        /* Driver that sets device state to initializating sets IDC version */
@@ -3324,14 +3378,16 @@ dev_initialize:
        qla82xx_idc_lock(ha);
 
        if (rval != QLA_SUCCESS) {
-               qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+               ql_log(ql_log_fatal, vha, 0x00ad,
+                   "HW State: FAILED.\n");
                qla82xx_clear_drv_active(ha);
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED);
                return rval;
        }
 
 dev_ready:
-       qla_printk(KERN_INFO, ha, "HW State: READY\n");
+       ql_log(ql_log_info, vha, 0x00ae,
+           "HW State: READY.\n");
        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY);
 
        return QLA_SUCCESS;
@@ -3376,15 +3432,15 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
                        /* quiescence timeout, other functions didn't ack
                         * changing the state to DEV_READY
                         */
-                       qla_printk(KERN_INFO, ha,
-                           "%s: QUIESCENT TIMEOUT\n", QLA2XXX_DRIVER_NAME);
-                       qla_printk(KERN_INFO, ha,
-                           "DRV_ACTIVE:%d DRV_STATE:%d\n", drv_active,
-                           drv_state);
+                       ql_log(ql_log_info, vha, 0xb023,
+                           "%s : QUIESCENT TIMEOUT.\n", QLA2XXX_DRIVER_NAME);
+                       ql_log(ql_log_info, vha, 0xb024,
+                           "DRV_ACTIVE:%d DRV_STATE:%d.\n",
+                           drv_active, drv_state);
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-                                               QLA82XX_DEV_READY);
-                       qla_printk(KERN_INFO, ha,
-                           "HW State: DEV_READY\n");
+                           QLA82XX_DEV_READY);
+                       ql_log(ql_log_info, vha, 0xb025,
+                           "HW State: DEV_READY.\n");
                        qla82xx_idc_unlock(ha);
                        qla2x00_perform_loop_resync(vha);
                        qla82xx_idc_lock(ha);
@@ -3404,7 +3460,8 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
        dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
        /* everyone acked so set the state to DEV_QUIESCENCE */
        if (dev_state == QLA82XX_DEV_NEED_QUIESCENT) {
-               qla_printk(KERN_INFO, ha, "HW State: DEV_QUIESCENT\n");
+               ql_log(ql_log_info, vha, 0xb026,
+                   "HW State: DEV_QUIESCENT.\n");
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_QUIESCENT);
        }
 }
@@ -3441,7 +3498,8 @@ qla82xx_dev_failed_handler(scsi_qla_host_t *vha)
        struct qla_hw_data *ha = vha->hw;
 
        /* Disable the board */
-       qla_printk(KERN_INFO, ha, "Disabling the board\n");
+       ql_log(ql_log_fatal, vha, 0x00b8,
+           "Disabling the board.\n");
 
        qla82xx_idc_lock(ha);
        qla82xx_clear_drv_active(ha);
@@ -3492,8 +3550,8 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
 
        while (drv_state != drv_active) {
                if (time_after_eq(jiffies, reset_timeout)) {
-                       qla_printk(KERN_INFO, ha,
-                               "%s: RESET TIMEOUT!\n", QLA2XXX_DRIVER_NAME);
+                       ql_log(ql_log_warn, vha, 0x00b5,
+                           "Reset timeout.\n");
                        break;
                }
                qla82xx_idc_unlock(ha);
@@ -3504,12 +3562,15 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
        }
 
        dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
-       qla_printk(KERN_INFO, ha, "3:Device state is 0x%x = %s\n", dev_state,
-               dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+       ql_log(ql_log_info, vha, 0x00b6,
+           "Device state is 0x%x = %s.\n",
+           dev_state,
+           dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
 
        /* Force to DEV_COLD unless someone else is starting a reset */
        if (dev_state != QLA82XX_DEV_INITIALIZING) {
-               qla_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n");
+               ql_log(ql_log_info, vha, 0x00b7,
+                   "HW State: COLD/RE-INIT.\n");
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD);
        }
 }
@@ -3523,8 +3584,12 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha)
        fw_heartbeat_counter = qla82xx_rd_32(vha->hw,
                QLA82XX_PEG_ALIVE_COUNTER);
        /* all 0xff, assume AER/EEH in progress, ignore */
-       if (fw_heartbeat_counter == 0xffffffff)
+       if (fw_heartbeat_counter == 0xffffffff) {
+               ql_dbg(ql_dbg_timer, vha, 0x6003,
+                   "FW heartbeat counter is 0xffffffff, "
+                   "returning status=%d.\n", status);
                return status;
+       }
        if (vha->fw_heartbeat_counter == fw_heartbeat_counter) {
                vha->seconds_since_last_heartbeat++;
                /* FW not alive after 2 seconds */
@@ -3535,6 +3600,9 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha)
        } else
                vha->seconds_since_last_heartbeat = 0;
        vha->fw_heartbeat_counter = fw_heartbeat_counter;
+       if (status)
+               ql_dbg(ql_dbg_timer, vha, 0x6004,
+                   "Returning status=%d.\n", status);
        return status;
 }
 
@@ -3565,8 +3633,10 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
 
        dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
        old_dev_state = dev_state;
-       qla_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state,
-               dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
+       ql_log(ql_log_info, vha, 0x009b,
+           "Device state is 0x%x = %s.\n",
+           dev_state,
+           dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
 
        /* wait for 30 seconds for device to go ready */
        dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
@@ -3574,9 +3644,8 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
        while (1) {
 
                if (time_after_eq(jiffies, dev_init_timeout)) {
-                       DEBUG(qla_printk(KERN_INFO, ha,
-                               "%s: device init failed!\n",
-                               QLA2XXX_DRIVER_NAME));
+                       ql_log(ql_log_fatal, vha, 0x009c,
+                           "Device init failed.\n");
                        rval = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -3586,10 +3655,11 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
                        old_dev_state = dev_state;
                }
                if (loopcount < 5) {
-                       qla_printk(KERN_INFO, ha,
-                           "2:Device state is 0x%x = %s\n", dev_state,
-                           dev_state < MAX_STATES ?
-                           qdev_state[dev_state] : "Unknown");
+                       ql_log(ql_log_info, vha, 0x009d,
+                           "Device state is 0x%x = %s.\n",
+                           dev_state,
+                           dev_state < MAX_STATES ? qdev_state[dev_state] :
+                           "Unknown");
                }
 
                switch (dev_state) {
@@ -3656,29 +3726,26 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
                dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
                if (dev_state == QLA82XX_DEV_NEED_RESET &&
                    !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) {
-                       qla_printk(KERN_WARNING, ha,
-                           "scsi(%ld) %s: Adapter reset needed!\n",
-                               vha->host_no, __func__);
+                       ql_log(ql_log_warn, vha, 0x6001,
+                           "Adapter reset needed.\n");
                        set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                        qla2xxx_wake_dpc(vha);
                } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
                        !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
-                       DEBUG(qla_printk(KERN_INFO, ha,
-                               "scsi(%ld) %s - detected quiescence needed\n",
-                               vha->host_no, __func__));
+                       ql_log(ql_log_warn, vha, 0x6002,
+                           "Quiescent needed.\n");
                        set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
                        qla2xxx_wake_dpc(vha);
                } else {
                        if (qla82xx_check_fw_alive(vha)) {
                                halt_status = qla82xx_rd_32(ha,
                                    QLA82XX_PEG_HALT_STATUS1);
-                               qla_printk(KERN_INFO, ha,
-                                   "scsi(%ld): %s, Dumping hw/fw registers:\n "
-                                   " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n "
-                                   " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n "
-                                   " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n "
-                                   " PEG_NET_4_PC: 0x%x\n",
-                                   vha->host_no, __func__, halt_status,
+                               ql_dbg(ql_dbg_timer, vha, 0x6005,
+                                   "dumping hw/fw registers:.\n "
+                                   " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,.\n "
+                                   " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,.\n "
+                                   " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,.\n "
+                                   " PEG_NET_4_PC: 0x%x.\n", halt_status,
                                    qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS2),
                                    qla82xx_rd_32(ha,
                                            QLA82XX_CRB_PEG_NET_0 + 0x3c),
@@ -3694,9 +3761,8 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
                                        set_bit(ISP_UNRECOVERABLE,
                                            &vha->dpc_flags);
                                } else {
-                                       qla_printk(KERN_INFO, ha,
-                                           "scsi(%ld): %s - detect abort needed\n",
-                                           vha->host_no, __func__);
+                                       ql_log(ql_log_info, vha, 0x6006,
+                                           "Detect abort  needed.\n");
                                        set_bit(ISP_ABORT_NEEDED,
                                            &vha->dpc_flags);
                                }
@@ -3704,10 +3770,10 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
                                ha->flags.isp82xx_fw_hung = 1;
                                if (ha->flags.mbox_busy) {
                                        ha->flags.mbox_int = 1;
-                                       DEBUG2(qla_printk(KERN_ERR, ha,
-                                           "scsi(%ld) Due to fw hung, doing "
+                                       ql_log(ql_log_warn, vha, 0x6007,
+                                           "Due to FW hung, doing "
                                            "premature completion of mbx "
-                                           "command\n", vha->host_no));
+                                           "command.\n");
                                        if (test_bit(MBX_INTR_WAIT,
                                            &ha->mbx_cmd_flags))
                                                complete(&ha->mbx_intr_comp);
@@ -3742,9 +3808,8 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
        uint32_t dev_state;
 
        if (vha->device_flags & DFLG_DEV_FAILED) {
-               qla_printk(KERN_WARNING, ha,
-                       "%s(%ld): Device in failed state, "
-                       "Exiting.\n", __func__, vha->host_no);
+               ql_log(ql_log_warn, vha, 0x8024,
+                   "Device in failed state, exiting.\n");
                return QLA_SUCCESS;
        }
        ha->flags.isp82xx_reset_hdlr_active = 1;
@@ -3752,13 +3817,14 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
        qla82xx_idc_lock(ha);
        dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
        if (dev_state == QLA82XX_DEV_READY) {
-               qla_printk(KERN_INFO, ha, "HW State: NEED RESET\n");
+               ql_log(ql_log_info, vha, 0x8025,
+                   "HW State: NEED RESET.\n");
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                        QLA82XX_DEV_NEED_RESET);
        } else
-               qla_printk(KERN_INFO, ha, "HW State: %s\n",
-                       dev_state < MAX_STATES ?
-                       qdev_state[dev_state] : "Unknown");
+               ql_log(ql_log_info, vha, 0x8026,
+                   "Hw State: %s.\n", dev_state < MAX_STATES ?
+                   qdev_state[dev_state] : "Unknown");
        qla82xx_idc_unlock(ha);
 
        rval = qla82xx_device_state_handler(vha);
@@ -3777,9 +3843,9 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
                vha->flags.online = 1;
                if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
                        if (ha->isp_abort_cnt == 0) {
-                               qla_printk(KERN_WARNING, ha,
-                                   "ISP error recovery failed - "
-                                   "board disabled\n");
+                               ql_log(ql_log_warn, vha, 0x8027,
+                                   "ISP error recover failed - board "
+                                   "disabled.\n");
                                /*
                                 * The next call disables the board
                                 * completely.
@@ -3791,16 +3857,16 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
                                rval = QLA_SUCCESS;
                        } else { /* schedule another ISP abort */
                                ha->isp_abort_cnt--;
-                               DEBUG(qla_printk(KERN_INFO, ha,
-                                   "qla%ld: ISP abort - retry remaining %d\n",
-                                   vha->host_no, ha->isp_abort_cnt));
+                               ql_log(ql_log_warn, vha, 0x8036,
+                                   "ISP abort - retry remaining %d.\n",
+                                   ha->isp_abort_cnt);
                                rval = QLA_FUNCTION_FAILED;
                        }
                } else {
                        ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
-                       DEBUG(qla_printk(KERN_INFO, ha,
-                           "(%ld): ISP error recovery - retrying (%d) "
-                           "more times\n", vha->host_no, ha->isp_abort_cnt));
+                       ql_dbg(ql_dbg_taskm, vha, 0x8029,
+                           "ISP error recovery - retrying (%d) more times.\n",
+                           ha->isp_abort_cnt);
                        set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
                        rval = QLA_FUNCTION_FAILED;
                }
@@ -3872,8 +3938,8 @@ int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha)
                        break;
                }
        }
-       DEBUG2(printk(KERN_INFO
-           "%s status=%d\n", __func__, status));
+       ql_dbg(ql_dbg_p3p, vha, 0xb027,
+           "%s status=%d.\n", status);
 
        return status;
 }
@@ -3902,6 +3968,9 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
                        }
                }
        }
+       ql_dbg(ql_dbg_init, vha, 0x00b0,
+           "Entered %s fw_hung=%d.\n",
+           __func__, ha->flags.isp82xx_fw_hung);
 
        /* Abort all commands gracefully if fw NOT hung */
        if (!ha->flags.isp82xx_fw_hung) {
@@ -3922,13 +3991,13 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
                                                spin_unlock_irqrestore(
                                                    &ha->hardware_lock, flags);
                                                if (ha->isp_ops->abort_command(sp)) {
-                                                       qla_printk(KERN_INFO, ha,
-                                                           "scsi(%ld): mbx abort command failed in %s\n",
-                                                           vha->host_no, __func__);
+                                                       ql_log(ql_log_info, vha,
+                                                           0x00b1,
+                                                           "mbx abort failed.\n");
                                                } else {
-                                                       qla_printk(KERN_INFO, ha,
-                                                           "scsi(%ld): mbx abort command success in %s\n",
-                                                           vha->host_no, __func__);
+                                                       ql_log(ql_log_info, vha,
+                                                           0x00b2,
+                                                           "mbx abort success.\n");
                                                }
                                                spin_lock_irqsave(&ha->hardware_lock, flags);
                                        }
@@ -3940,8 +4009,9 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
                /* Wait for pending cmds (physical and virtual) to complete */
                if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
                    WAIT_HOST) == QLA_SUCCESS) {
-                       DEBUG2(qla_printk(KERN_INFO, ha,
-                           "Done wait for pending commands\n"));
+                       ql_dbg(ql_dbg_init, vha, 0x00b3,
+                           "Done wait for "
+                           "pending commands.\n");
                }
        }
 }
index f461925a9dfc29d7656df3477eecdb29eaead55d..e02df276804ed25e119ca06d3ce7bf6f159d0876 100644 (file)
@@ -35,6 +35,10 @@ static struct kmem_cache *srb_cachep;
  * CT6 CTX allocation cache
  */
 static struct kmem_cache *ctx_cachep;
+/*
+ * error level for logging
+ */
+int ql_errlev = ql_log_all;
 
 int ql2xlogintimeout = 20;
 module_param(ql2xlogintimeout, int, S_IRUGO);
@@ -69,8 +73,17 @@ MODULE_PARM_DESC(ql2xallocfwdump,
 int ql2xextended_error_logging;
 module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ql2xextended_error_logging,
-               "Option to enable extended error logging, "
-               "Default is 0 - no logging. 1 - log errors.");
+               "Option to enable extended error logging,\n"
+               "\t\tDefault is 0 - no logging.  0x40000000 - Module Init & Probe.\n"
+               "\t\t0x20000000 - Mailbox Cmnds. 0x10000000 - Device Discovery.\n"
+               "\t\t0x08000000 - IO tracing.    0x04000000 - DPC Thread.\n"
+               "\t\t0x02000000 - Async events.  0x01000000 - Timer routines.\n"
+               "\t\t0x00800000 - User space.    0x00400000 - Task Management.\n"
+               "\t\t0x00200000 - AER/EEH.       0x00100000 - Multi Q.\n"
+               "\t\t0x00080000 - P3P Specific.  0x00040000 - Virtual Port.\n"
+               "\t\t0x00020000 - Buffer Dump.   0x00010000 - Misc.\n"
+               "\t\t0x7fffffff - For enabling all logs, can be too many logs.\n"
+               "\t\tDo LOGICAL OR of the value to enable more than one level");
 
 int ql2xshiftctondsd = 6;
 module_param(ql2xshiftctondsd, int, S_IRUGO);
@@ -128,8 +141,8 @@ MODULE_PARM_DESC(ql2xmultique_tag,
 int ql2xfwloadbin;
 module_param(ql2xfwloadbin, int, S_IRUGO);
 MODULE_PARM_DESC(ql2xfwloadbin,
-               "Option to specify location from which to load ISP firmware:\n"
-               " 2 -- load firmware via the request_firmware() (hotplug)\n"
+               "Option to specify location from which to load ISP firmware:.\n"
+               " 2 -- load firmware via the request_firmware() (hotplug).\n"
                "      interface.\n"
                " 1 -- load firmware from flash.\n"
                " 0 -- use default semantics.\n");
@@ -143,7 +156,7 @@ MODULE_PARM_DESC(ql2xetsenable,
 int ql2xdbwr = 1;
 module_param(ql2xdbwr, int, S_IRUGO);
 MODULE_PARM_DESC(ql2xdbwr,
-       "Option to specify scheme for request queue posting\n"
+       "Option to specify scheme for request queue posting.\n"
        " 0 -- Regular doorbell.\n"
        " 1 -- CAMRAM doorbell (faster).\n");
 
@@ -168,7 +181,7 @@ MODULE_PARM_DESC(ql2xasynctmfenable,
 int ql2xdontresethba;
 module_param(ql2xdontresethba, int, S_IRUGO);
 MODULE_PARM_DESC(ql2xdontresethba,
-       "Option to specify reset behaviour\n"
+       "Option to specify reset behaviour.\n"
        " 0 (Default) -- Reset on failure.\n"
        " 1 -- Do not reset on failure.\n");
 
@@ -247,8 +260,11 @@ static inline void
 qla2x00_restart_timer(scsi_qla_host_t *vha, unsigned long interval)
 {
        /* Currently used for 82XX only. */
-       if (vha->device_flags & DFLG_DEV_FAILED)
+       if (vha->device_flags & DFLG_DEV_FAILED) {
+               ql_dbg(ql_dbg_timer, vha, 0x600d,
+                   "Device in a failed state, returning.\n");
                return;
+       }
 
        mod_timer(&vha->timer, jiffies + interval * HZ);
 }
@@ -273,19 +289,20 @@ static void qla2x00_sp_free_dma(srb_t *);
 /* -------------------------------------------------------------------------- */
 static int qla2x00_alloc_queues(struct qla_hw_data *ha)
 {
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues,
                                GFP_KERNEL);
        if (!ha->req_q_map) {
-               qla_printk(KERN_WARNING, ha,
-                       "Unable to allocate memory for request queue ptrs\n");
+               ql_log(ql_log_fatal, vha, 0x003b,
+                   "Unable to allocate memory for request queue ptrs.\n");
                goto fail_req_map;
        }
 
        ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_rsp_queues,
                                GFP_KERNEL);
        if (!ha->rsp_q_map) {
-               qla_printk(KERN_WARNING, ha,
-                       "Unable to allocate memory for response queue ptrs\n");
+               ql_log(ql_log_fatal, vha, 0x003c,
+                   "Unable to allocate memory for response queue ptrs.\n");
                goto fail_rsp_map;
        }
        set_bit(0, ha->rsp_qid_map);
@@ -349,8 +366,8 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
        struct qla_hw_data *ha = vha->hw;
 
        if (!(ha->fw_attributes & BIT_6)) {
-               qla_printk(KERN_INFO, ha,
-                       "Firmware is not multi-queue capable\n");
+               ql_log(ql_log_warn, vha, 0x00d8,
+                   "Firmware is not multi-queue capable.\n");
                goto fail;
        }
        if (ql2xmultique_tag) {
@@ -359,8 +376,8 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
                req = qla25xx_create_req_que(ha, options, 0, 0, -1,
                        QLA_DEFAULT_QUE_QOS);
                if (!req) {
-                       qla_printk(KERN_WARNING, ha,
-                               "Can't create request queue\n");
+                       ql_log(ql_log_warn, vha, 0x00e0,
+                           "Failed to create request queue.\n");
                        goto fail;
                }
                ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1);
@@ -369,17 +386,20 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
                for (ques = 1; ques < ha->max_rsp_queues; ques++) {
                        ret = qla25xx_create_rsp_que(ha, options, 0, 0, req);
                        if (!ret) {
-                               qla_printk(KERN_WARNING, ha,
-                                       "Response Queue create failed\n");
+                               ql_log(ql_log_warn, vha, 0x00e8,
+                                   "Failed to create response queue.\n");
                                goto fail2;
                        }
                }
                ha->flags.cpu_affinity_enabled = 1;
-
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                       "CPU affinity mode enabled, no. of response"
-                       " queues:%d, no. of request queues:%d\n",
-                       ha->max_rsp_queues, ha->max_req_queues));
+               ql_dbg(ql_dbg_multiq, vha, 0xc007,
+                   "CPU affinity mode enalbed, "
+                   "no. of response queues:%d no. of request queues:%d.\n",
+                   ha->max_rsp_queues, ha->max_req_queues);
+               ql_dbg(ql_dbg_init, vha, 0x00e9,
+                   "CPU affinity mode enalbed, "
+                   "no. of response queues:%d no. of request queues:%d.\n",
+                   ha->max_rsp_queues, ha->max_req_queues);
        }
        return 0;
 fail2:
@@ -526,8 +546,11 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
        struct qla_hw_data *ha = vha->hw;
 
        sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
-       if (!sp)
+       if (!sp) {
+               ql_log(ql_log_warn, vha, 0x3006,
+                   "Memory allocation failed for sp.\n");
                return sp;
+       }
 
        atomic_set(&sp->ref_count, 1);
        sp->fcport = fcport;
@@ -551,30 +574,43 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        int rval;
 
        if (ha->flags.eeh_busy) {
-               if (ha->flags.pci_channel_io_perm_failure)
+               if (ha->flags.pci_channel_io_perm_failure) {
+                       ql_dbg(ql_dbg_io, vha, 0x3001,
+                           "PCI Channel IO permanent failure, exiting "
+                           "cmd=%p.\n", cmd);
                        cmd->result = DID_NO_CONNECT << 16;
-               else
+               } else {
+                       ql_dbg(ql_dbg_io, vha, 0x3002,
+                           "EEH_Busy, Requeuing the cmd=%p.\n", cmd);
                        cmd->result = DID_REQUEUE << 16;
+               }
                goto qc24_fail_command;
        }
 
        rval = fc_remote_port_chkready(rport);
        if (rval) {
                cmd->result = rval;
+               ql_dbg(ql_dbg_io, vha, 0x3003,
+                   "fc_remote_port_chkready failed for cmd=%p, rval=0x%x.\n",
+                   cmd, rval);
                goto qc24_fail_command;
        }
 
        if (!vha->flags.difdix_supported &&
                scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) {
-                       DEBUG2(qla_printk(KERN_ERR, ha,
-                           "DIF Cap Not Reg, fail DIF capable cmd's:%x\n",
-                           cmd->cmnd[0]));
+                       ql_dbg(ql_dbg_io, vha, 0x3004,
+                           "DIF Cap not reg, fail DIF capable cmd's:%p.\n",
+                           cmd);
                        cmd->result = DID_NO_CONNECT << 16;
                        goto qc24_fail_command;
        }
        if (atomic_read(&fcport->state) != FCS_ONLINE) {
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
                        atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
+                       ql_dbg(ql_dbg_io, vha, 0x3005,
+                           "Returning DNC, fcport_state=%d loop_state=%d.\n",
+                           atomic_read(&fcport->state),
+                           atomic_read(&base_vha->loop_state));
                        cmd->result = DID_NO_CONNECT << 16;
                        goto qc24_fail_command;
                }
@@ -586,8 +622,11 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
                goto qc24_host_busy;
 
        rval = ha->isp_ops->start_scsi(sp);
-       if (rval != QLA_SUCCESS)
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_io, vha, 0x3013,
+                   "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd);
                goto qc24_host_busy_free_sp;
+       }
 
        return 0;
 
@@ -630,7 +669,8 @@ qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd)
        int ret = QLA_SUCCESS;
 
        if (unlikely(pci_channel_offline(ha->pdev)) || ha->flags.eeh_busy) {
-               DEBUG17(qla_printk(KERN_WARNING, ha, "return:eh_wait\n"));
+               ql_dbg(ql_dbg_taskm, vha, 0x8005,
+                   "Return:eh_wait.\n");
                return ret;
        }
 
@@ -723,7 +763,8 @@ qla2x00_wait_for_reset_ready(scsi_qla_host_t *vha)
        else
                return_status = QLA_FUNCTION_FAILED;
 
-       DEBUG2(printk("%s return_status=%d\n", __func__, return_status));
+       ql_dbg(ql_dbg_taskm, vha, 0x8019,
+           "%s return status=%d.\n", __func__, return_status);
 
        return return_status;
 }
@@ -831,10 +872,14 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        int wait = 0;
        struct qla_hw_data *ha = vha->hw;
 
+       ql_dbg(ql_dbg_taskm, vha, 0x8000,
+           "Entered %s for cmd=%p.\n", __func__, cmd);
        if (!CMD_SP(cmd))
                return SUCCESS;
 
        ret = fc_block_scsi_eh(cmd);
+       ql_dbg(ql_dbg_taskm, vha, 0x8001,
+           "Return value of fc_block_scsi_eh=%d.\n", ret);
        if (ret != 0)
                return ret;
        ret = SUCCESS;
@@ -849,20 +894,19 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
                return SUCCESS;
        }
 
-       DEBUG2(printk("%s(%ld): aborting sp %p from RISC.",
-           __func__, vha->host_no, sp));
+       ql_dbg(ql_dbg_taskm, vha, 0x8002,
+           "Aborting sp=%p cmd=%p from RISC ", sp, cmd);
 
        /* Get a reference to the sp and drop the lock.*/
        sp_get(sp);
 
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
        if (ha->isp_ops->abort_command(sp)) {
-               DEBUG2(printk("%s(%ld): abort_command "
-               "mbx failed.\n", __func__, vha->host_no));
-               ret = FAILED;
+               ql_dbg(ql_dbg_taskm, vha, 0x8003,
+                   "Abort command mbx failed for cmd=%p.\n", cmd);
        } else {
-               DEBUG3(printk("%s(%ld): abort_command "
-               "mbx success.\n", __func__, vha->host_no));
+               ql_dbg(ql_dbg_taskm, vha, 0x8004,
+                   "Abort command mbx success.\n");
                wait = 1;
        }
        qla2x00_sp_compl(ha, sp);
@@ -870,16 +914,14 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
        /* Wait for the command to be returned. */
        if (wait) {
                if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) {
-                       qla_printk(KERN_ERR, ha,
-                           "scsi(%ld:%d:%d): Abort handler timed out -- %x.\n",
-                           vha->host_no, id, lun, ret);
+                       ql_log(ql_log_warn, vha, 0x8006,
+                           "Abort handler timed out for cmd=%p.\n", cmd);
                        ret = FAILED;
                }
        }
 
-       qla_printk(KERN_INFO, ha,
-           "scsi(%ld:%d:%d): Abort command issued -- %d %x.\n",
-           vha->host_no, id, lun, wait, ret);
+       ql_log(ql_log_info, vha, 0x801c,
+           "Abort command issued --  %d %x.\n", wait, ret);
 
        return ret;
 }
@@ -947,40 +989,59 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
        fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
        int err;
 
-       if (!fcport)
+       if (!fcport) {
+               ql_log(ql_log_warn, vha, 0x8007,
+                   "fcport is NULL.\n");
                return FAILED;
+       }
 
        err = fc_block_scsi_eh(cmd);
+       ql_dbg(ql_dbg_taskm, vha, 0x8008,
+           "fc_block_scsi_eh ret=%d.\n", err);
        if (err != 0)
                return err;
 
-       qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET ISSUED.\n",
-           vha->host_no, cmd->device->id, cmd->device->lun, name);
+       ql_log(ql_log_info, vha, 0x8009,
+           "%s RESET ISSUED for id %d lun %d cmd=%p.\n", name,
+           cmd->device->id, cmd->device->lun, cmd);
 
        err = 0;
-       if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS)
+       if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x800a,
+                   "Wait for hba online failed for cmd=%p.\n", cmd);
                goto eh_reset_failed;
+       }
        err = 1;
-       if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS)
+       if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x800b,
+                   "Wait for loop ready failed for cmd=%p.\n", cmd);
                goto eh_reset_failed;
+       }
        err = 2;
        if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1)
-               != QLA_SUCCESS)
+               != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x800c,
+                   "do_reset failed for cmd=%p.\n", cmd);
                goto eh_reset_failed;
+       }
        err = 3;
        if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id,
-           cmd->device->lun, type) != QLA_SUCCESS)
+           cmd->device->lun, type) != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x800d,
+                   "wait for peding cmds failed for cmd=%p.\n", cmd);
                goto eh_reset_failed;
+       }
 
-       qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n",
-           vha->host_no, cmd->device->id, cmd->device->lun, name);
+       ql_log(ql_log_info, vha, 0x800e,
+           "%s RESET SUCCEEDED for id %d lun %d cmd=%p.\n", name,
+           cmd->device->id, cmd->device->lun, cmd);
 
        return SUCCESS;
 
 eh_reset_failed:
-       qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n"
-           , vha->host_no, cmd->device->id, cmd->device->lun, name,
-           reset_errors[err]);
+       ql_log(ql_log_info, vha, 0x800f,
+           "%s RESET FAILED: %s for id %d lun %d cmd=%p.\n", name,
+           reset_errors[err], cmd->device->id, cmd->device->lun);
        return FAILED;
 }
 
@@ -1030,19 +1091,25 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
        id = cmd->device->id;
        lun = cmd->device->lun;
 
-       if (!fcport)
+       if (!fcport) {
+               ql_log(ql_log_warn, vha, 0x8010,
+                   "fcport is NULL.\n");
                return ret;
+       }
 
        ret = fc_block_scsi_eh(cmd);
+       ql_dbg(ql_dbg_taskm, vha, 0x8011,
+           "fc_block_scsi_eh ret=%d.\n", ret);
        if (ret != 0)
                return ret;
        ret = FAILED;
 
-       qla_printk(KERN_INFO, vha->hw,
-           "scsi(%ld:%d:%d): BUS RESET ISSUED.\n", vha->host_no, id, lun);
+       ql_log(ql_log_info, vha, 0x8012,
+           "BUS RESET ISSUED for id %d lun %d.\n", id, lun);
 
        if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
-               DEBUG2(printk("%s failed:board disabled\n",__func__));
+               ql_log(ql_log_fatal, vha, 0x8013,
+                   "Wait for hba online failed board disabled.\n");
                goto eh_bus_reset_done;
        }
 
@@ -1055,12 +1122,15 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
 
        /* Flush outstanding commands. */
        if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) !=
-           QLA_SUCCESS)
+           QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x8014,
+                   "Wait for pending commands failed.\n");
                ret = FAILED;
+       }
 
 eh_bus_reset_done:
-       qla_printk(KERN_INFO, vha->hw, "%s: reset %s\n", __func__,
-           (ret == FAILED) ? "failed" : "succeeded");
+       ql_log(ql_log_warn, vha, 0x802b,
+           "BUS RESET %s.\n", (ret == FAILED) ? "FAILED" : "SUCCEDED");
 
        return ret;
 }
@@ -1093,16 +1163,21 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
        id = cmd->device->id;
        lun = cmd->device->lun;
 
-       if (!fcport)
+       if (!fcport) {
+               ql_log(ql_log_warn, vha, 0x8016,
+                   "fcport is NULL.\n");
                return ret;
+       }
 
        ret = fc_block_scsi_eh(cmd);
+       ql_dbg(ql_dbg_taskm, vha, 0x8017,
+           "fc_block_scsi_eh ret=%d.\n", ret);
        if (ret != 0)
                return ret;
        ret = FAILED;
 
-       qla_printk(KERN_INFO, ha,
-           "scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", vha->host_no, id, lun);
+       ql_log(ql_log_info, vha, 0x8018,
+           "ADAPTER RESET ISSUED for id %d lun %d.\n", id, lun);
 
        if (qla2x00_wait_for_reset_ready(vha) != QLA_SUCCESS)
                goto eh_host_reset_lock;
@@ -1137,8 +1212,11 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
                        /* failed. schedule dpc to try */
                        set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
 
-                       if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS)
+                       if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
+                               ql_log(ql_log_warn, vha, 0x802a,
+                                   "wait for hba online failed.\n");
                                goto eh_host_reset_lock;
+                       }
                }
                clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
        }
@@ -1149,7 +1227,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
                ret = SUCCESS;
 
 eh_host_reset_lock:
-       qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
+       qla_printk(KERN_INFO, ha, "%s: reset %s.\n", __func__,
            (ret == FAILED) ? "failed" : "succeeded");
 
        return ret;
@@ -1179,9 +1257,9 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
 
                        ret = ha->isp_ops->target_reset(fcport, 0, 0);
                        if (ret != QLA_SUCCESS) {
-                               DEBUG2_3(printk("%s(%ld): bus_reset failed: "
-                                   "target_reset=%d d_id=%x.\n", __func__,
-                                   vha->host_no, ret, fcport->d_id.b24));
+                               ql_dbg(ql_dbg_taskm, vha, 0x802c,
+                                   "Bus Reset failed: Target Reset=%d "
+                                   "d_id=%x.\n", ret, fcport->d_id.b24);
                        }
                }
        }
@@ -1189,9 +1267,8 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
        if (ha->flags.enable_lip_full_login && !IS_QLA8XXX_TYPE(ha)) {
                ret = qla2x00_full_login_lip(vha);
                if (ret != QLA_SUCCESS) {
-                       DEBUG2_3(printk("%s(%ld): failed: "
-                           "full_login_lip=%d.\n", __func__, vha->host_no,
-                           ret));
+                       ql_dbg(ql_dbg_taskm, vha, 0x802d,
+                           "full_login_lip=%d.\n", ret);
                }
                atomic_set(&vha->loop_state, LOOP_DOWN);
                atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
@@ -1202,8 +1279,8 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
        if (ha->flags.enable_lip_reset) {
                ret = qla2x00_lip_reset(vha);
                if (ret != QLA_SUCCESS) {
-                       DEBUG2_3(printk("%s(%ld): failed: "
-                           "lip_reset=%d.\n", __func__, vha->host_no, ret));
+                       ql_dbg(ql_dbg_taskm, vha, 0x802e,
+                           "lip_reset failed (%d).\n", ret);
                } else
                        qla2x00_wait_for_loop_ready(vha);
        }
@@ -1302,17 +1379,17 @@ static void qla2x00_handle_queue_full(struct scsi_device *sdev, int qdepth)
        if (!scsi_track_queue_full(sdev, qdepth))
                return;
 
-       DEBUG2(qla_printk(KERN_INFO, fcport->vha->hw,
-               "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
-               fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
-               sdev->queue_depth));
+       ql_dbg(ql_dbg_io, fcport->vha, 0x3029,
+           "Queue depth adjusted-down "
+           "to %d for scsi(%ld:%d:%d:%d).\n",
+           sdev->queue_depth, fcport->vha->host_no,
+           sdev->channel, sdev->id, sdev->lun);
 }
 
 static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth)
 {
        fc_port_t *fcport = sdev->hostdata;
        struct scsi_qla_host *vha = fcport->vha;
-       struct qla_hw_data *ha = vha->hw;
        struct req_que *req = NULL;
 
        req = vha->req;
@@ -1327,10 +1404,11 @@ static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth)
        else
                scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, qdepth);
 
-       DEBUG2(qla_printk(KERN_INFO, ha,
-              "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
-              fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
-              sdev->queue_depth));
+       ql_dbg(ql_dbg_io, vha, 0x302a,
+           "Queue depth adjusted-up to %d for "
+           "scsi(%ld:%d:%d:%d).\n",
+           sdev->queue_depth, fcport->vha->host_no,
+           sdev->channel, sdev->id, sdev->lun);
 }
 
 static int
@@ -1776,6 +1854,9 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
                ha->flags.port0 = 1;
        else
                ha->flags.port0 = 0;
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x000b,
+           "device_type=0x%x port=%d fw_srisc_address=%p.\n",
+           ha->device_type, ha->flags.port0, ha->fw_srisc_address);
 }
 
 static int
@@ -1790,10 +1871,9 @@ qla2x00_iospace_config(struct qla_hw_data *ha)
 
        if (pci_request_selected_regions(ha->pdev, ha->bars,
            QLA2XXX_DRIVER_NAME)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Failed to reserve PIO/MMIO regions (%s)\n",
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0011,
+                   "Failed to reserve PIO/MMIO regions (%s), aborting.\n",
                    pci_name(ha->pdev));
-
                goto iospace_error_exit;
        }
        if (!(ha->bars & 1))
@@ -1803,39 +1883,42 @@ qla2x00_iospace_config(struct qla_hw_data *ha)
        pio = pci_resource_start(ha->pdev, 0);
        if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) {
                if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Invalid PCI I/O region size (%s)...\n",
-                               pci_name(ha->pdev));
+                       ql_log_pci(ql_log_warn, ha->pdev, 0x0012,
+                           "Invalid pci I/O region size (%s).\n",
+                           pci_name(ha->pdev));
                        pio = 0;
                }
        } else {
-               qla_printk(KERN_WARNING, ha,
-                   "region #0 not a PIO resource (%s)...\n",
+               ql_log_pci(ql_log_warn, ha->pdev, 0x0013,
+                   "Region #0 no a PIO resource (%s).\n",
                    pci_name(ha->pdev));
                pio = 0;
        }
        ha->pio_address = pio;
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0014,
+           "PIO address=%p.\n",
+           ha->pio_address);
 
 skip_pio:
        /* Use MMIO operations for all accesses. */
        if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) {
-               qla_printk(KERN_ERR, ha,
-                   "region #1 not an MMIO resource (%s), aborting\n",
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0015,
+                   "Region #1 not an MMIO resource (%s), aborting.\n",
                    pci_name(ha->pdev));
                goto iospace_error_exit;
        }
        if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) {
-               qla_printk(KERN_ERR, ha,
-                   "Invalid PCI mem region size (%s), aborting\n",
-                       pci_name(ha->pdev));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0016,
+                   "Invalid PCI mem region size (%s), aborting.\n",
+                   pci_name(ha->pdev));
                goto iospace_error_exit;
        }
 
        ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN);
        if (!ha->iobase) {
-               qla_printk(KERN_ERR, ha,
-                   "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
-
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0017,
+                   "Cannot remap MMIO (%s), aborting.\n",
+                   pci_name(ha->pdev));
                goto iospace_error_exit;
        }
 
@@ -1849,6 +1932,8 @@ skip_pio:
        ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3),
                        pci_resource_len(ha->pdev, 3));
        if (ha->mqiobase) {
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0018,
+                   "MQIO Base=%p.\n", ha->mqiobase);
                /* Read MSIX vector size of the board */
                pci_read_config_word(ha->pdev, QLA_PCI_MSIX_CONTROL, &msix);
                ha->msix_count = msix;
@@ -1861,17 +1946,24 @@ skip_pio:
                        ha->max_req_queues = 2;
                } else if (ql2xmaxqueues > 1) {
                        ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ?
-                                               QLA_MQ_SIZE : ql2xmaxqueues;
-                       DEBUG2(qla_printk(KERN_INFO, ha, "QoS mode set, max no"
-                       " of request queues:%d\n", ha->max_req_queues));
+                           QLA_MQ_SIZE : ql2xmaxqueues;
+                       ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc008,
+                           "QoS mode set, max no of request queues:%d.\n",
+                           ha->max_req_queues);
+                       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0019,
+                           "QoS mode set, max no of request queues:%d.\n",
+                           ha->max_req_queues);
                }
-               qla_printk(KERN_INFO, ha,
-                       "MSI-X vector count: %d\n", msix);
+               ql_log_pci(ql_log_info, ha->pdev, 0x001a,
+                   "MSI-X vector count: %d.\n", msix);
        } else
-               qla_printk(KERN_INFO, ha, "BAR 3 not enabled\n");
+               ql_log_pci(ql_log_info, ha->pdev, 0x001b,
+                   "BAR 3 not enabled.\n");
 
 mqiobase_exit:
        ha->msix_count = ha->max_rsp_queues + 1;
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x001c,
+           "MSIX Count:%d.\n", ha->msix_count);
        return (0);
 
 iospace_error_exit:
@@ -1935,7 +2027,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
            pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021) {
                bars = pci_select_bars(pdev, IORESOURCE_MEM);
                mem_only = 1;
+               ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
+                   "Mem only adapter.\n");
        }
+       ql_dbg_pci(ql_dbg_init, pdev, 0x0008,
+           "Bars=%d.\n", bars);
 
        if (mem_only) {
                if (pci_enable_device_mem(pdev))
@@ -1950,9 +2046,12 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL);
        if (!ha) {
-               DEBUG(printk("Unable to allocate memory for ha\n"));
+               ql_log_pci(ql_log_fatal, pdev, 0x0009,
+                   "Unable to allocate memory for ha.\n");
                goto probe_out;
        }
+       ql_dbg_pci(ql_dbg_init, pdev, 0x000a,
+           "Memory allocated for ha=%p.\n", ha);
        ha->pdev = pdev;
 
        /* Clear our data area */
@@ -1974,10 +2073,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        if (ret)
                goto probe_hw_failed;
 
-       qla_printk(KERN_INFO, ha,
-           "Found an ISP%04X, irq %d, iobase 0x%p\n", pdev->device, pdev->irq,
-           ha->iobase);
-
+       ql_log_pci(ql_log_info, pdev, 0x001d,
+           "Found an ISP%04X irq %d iobase 0x%p.\n",
+           pdev->device, pdev->irq, ha->iobase);
        ha->prev_topology = 0;
        ha->init_cb_size = sizeof(init_cb_t);
        ha->link_data_rate = PORT_SPEED_UNKNOWN;
@@ -2078,7 +2176,18 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
                ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
        }
-
+       ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
+           "mbx_count=%d, req_length=%d, "
+           "rsp_length=%d, max_loop_id=%d, init_cb_size=%d, "
+           "gid_list_info_size=%d, optrom_size=%d, nvram_npiv_size=%d, .\n",
+           ha->mbx_count, req_length, rsp_length, ha->max_loop_id,
+           ha->init_cb_size, ha->gid_list_info_size, ha->optrom_size,
+           ha->nvram_npiv_size);
+       ql_dbg_pci(ql_dbg_init, pdev, 0x001f,
+           "isp_ops=%p, flash_conf_off=%d, "
+           "flash_data_off=%d, nvram_conf_off=%d, nvram_data_off=%d.\n",
+           ha->isp_ops, ha->flash_conf_off, ha->flash_data_off,
+           ha->nvram_conf_off, ha->nvram_data_off);
        mutex_init(&ha->vport_lock);
        init_completion(&ha->mbx_cmd_comp);
        complete(&ha->mbx_cmd_comp);
@@ -2088,10 +2197,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        set_bit(0, (unsigned long *) ha->vp_idx_map);
 
        qla2x00_config_dma_addressing(ha);
+       ql_dbg_pci(ql_dbg_init, pdev, 0x0020,
+           "64 Bit addressing is %s.\n",
+           ha->flags.enable_64bit_addressing ? "enable" :
+           "disable");
        ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp);
        if (!ret) {
-               qla_printk(KERN_WARNING, ha,
-                   "[ERROR] Failed to allocate memory for adapter\n");
+               ql_log_pci(ql_log_fatal, pdev, 0x0031,
+                   "Failed to allocate memory for adapter, aborting.\n");
 
                goto probe_hw_failed;
        }
@@ -2103,9 +2216,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        base_vha = qla2x00_create_host(sht, ha);
        if (!base_vha) {
-               qla_printk(KERN_WARNING, ha,
-                   "[ERROR] Failed to allocate memory for scsi_host\n");
-
                ret = -ENOMEM;
                qla2x00_mem_free(ha);
                qla2x00_free_req_que(ha, req);
@@ -2132,7 +2242,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                if (!IS_QLA82XX(ha))
                        host->sg_tablesize = QLA_SG_ALL;
        }
-
+       ql_dbg(ql_dbg_init, base_vha, 0x0032,
+           "can_queue=%d, req=%p, "
+           "mgmt_svr_loop_id=%d, sg_tablesize=%d.\n",
+           host->can_queue, base_vha->req,
+           base_vha->mgmt_svr_loop_id, host->sg_tablesize);
        host->max_id = max_id;
        host->this_id = 255;
        host->cmd_per_lun = 3;
@@ -2146,6 +2260,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        host->transportt = qla2xxx_transport_template;
        sht->vendor_id = (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC);
 
+       ql_dbg(ql_dbg_init, base_vha, 0x0033,
+           "max_id=%d this_id=%d "
+           "cmd_per_len=%d unique_id=%d max_cmd_len=%d max_channel=%d "
+           "max_lun=%d transportt=%p, vendor_id=%d.\n", host->max_id,
+           host->this_id, host->cmd_per_lun, host->unique_id,
+           host->max_cmd_len, host->max_channel, host->max_lun,
+           host->transportt, sht->vendor_id);
+
        /* Set up the irqs */
        ret = qla2x00_request_irqs(ha, rsp);
        if (ret)
@@ -2156,9 +2278,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        /* Alloc arrays of request and response ring ptrs */
 que_init:
        if (!qla2x00_alloc_queues(ha)) {
-               qla_printk(KERN_WARNING, ha,
-               "[ERROR] Failed to allocate memory for queue"
-               " pointers\n");
+               ql_log(ql_log_fatal, base_vha, 0x003d,
+                   "Failed to allocate memory for queue pointers.. aborting.\n");
                goto probe_init_failed;
        }
 
@@ -2186,20 +2307,33 @@ que_init:
                rsp->rsp_q_out = &ha->iobase->isp82.rsp_q_out[0];
        }
 
-       if (qla2x00_initialize_adapter(base_vha)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Failed to initialize adapter\n");
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc009,
+           "rsp_q_map=%p req_q_map=%p rsp->req=%p req->rsp=%p.\n",
+           ha->rsp_q_map, ha->req_q_map, rsp->req, req->rsp);
+       ql_dbg(ql_dbg_multiq, base_vha, 0xc00a,
+           "req->req_q_in=%p req->req_q_out=%p "
+           "rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n",
+           req->req_q_in, req->req_q_out,
+           rsp->rsp_q_in, rsp->rsp_q_out);
+       ql_dbg(ql_dbg_init, base_vha, 0x003e,
+           "rsp_q_map=%p req_q_map=%p rsp->req=%p req->rsp=%p.\n",
+           ha->rsp_q_map, ha->req_q_map, rsp->req, req->rsp);
+       ql_dbg(ql_dbg_init, base_vha, 0x003f,
+           "req->req_q_in=%p req->req_q_out=%p rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n",
+           req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out);
 
-               DEBUG2(printk("scsi(%ld): Failed to initialize adapter - "
-                   "Adapter flags %x.\n",
-                   base_vha->host_no, base_vha->device_flags));
+       if (qla2x00_initialize_adapter(base_vha)) {
+               ql_log(ql_log_fatal, base_vha, 0x00d6,
+                   "Failed to initialize adapter - Adapter flags %x.\n",
+                   base_vha->device_flags);
 
                if (IS_QLA82XX(ha)) {
                        qla82xx_idc_lock(ha);
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                                QLA82XX_DEV_FAILED);
                        qla82xx_idc_unlock(ha);
-                       qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+                       ql_log(ql_log_fatal, base_vha, 0x00d7,
+                           "HW State: FAILED.\n");
                }
 
                ret = -ENODEV;
@@ -2208,9 +2342,8 @@ que_init:
 
        if (ha->mqenable) {
                if (qla25xx_setup_mode(base_vha)) {
-                       qla_printk(KERN_WARNING, ha,
-                               "Can't create queues, falling back to single"
-                               " queue mode\n");
+                       ql_log(ql_log_warn, base_vha, 0x00ec,
+                           "Failed to create queues, falling back to single queue mode.\n");
                        goto que_init;
                }
        }
@@ -2222,13 +2355,15 @@ que_init:
         * Startup the kernel thread for this host adapter
         */
        ha->dpc_thread = kthread_create(qla2x00_do_dpc, ha,
-                       "%s_dpc", base_vha->host_str);
+           "%s_dpc", base_vha->host_str);
        if (IS_ERR(ha->dpc_thread)) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to start DPC thread!\n");
+               ql_log(ql_log_fatal, base_vha, 0x00ed,
+                   "Failed to start DPC thread.\n");
                ret = PTR_ERR(ha->dpc_thread);
                goto probe_failed;
        }
+       ql_dbg(ql_dbg_init, base_vha, 0x00ee,
+           "DPC thread started successfully.\n");
 
 skip_dpc:
        list_add_tail(&base_vha->list, &ha->vp_list);
@@ -2236,16 +2371,18 @@ skip_dpc:
 
        /* Initialized the timer */
        qla2x00_start_timer(base_vha, qla2x00_timer, WATCH_INTERVAL);
-
-       DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
-           base_vha->host_no, ha));
+       ql_dbg(ql_dbg_init, base_vha, 0x00ef,
+           "Started qla2x00_timer with "
+           "interval=%d.\n", WATCH_INTERVAL);
+       ql_dbg(ql_dbg_init, base_vha, 0x00f0,
+           "Detected hba at address=%p.\n",
+           ha);
 
        if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
                if (ha->fw_attributes & BIT_4) {
                        base_vha->flags.difdix_supported = 1;
-                       DEBUG18(qla_printk(KERN_INFO, ha,
-                           "Registering for DIF/DIX type 1 and 3"
-                           " protection.\n"));
+                       ql_dbg(ql_dbg_init, base_vha, 0x00f1,
+                           "Registering for DIF/DIX type 1 and 3 protection.\n");
                        scsi_host_set_prot(host,
                            SHOST_DIF_TYPE1_PROTECTION
                            | SHOST_DIF_TYPE2_PROTECTION
@@ -2267,6 +2404,9 @@ skip_dpc:
        base_vha->flags.init_done = 1;
        base_vha->flags.online = 1;
 
+       ql_dbg(ql_dbg_init, base_vha, 0x00f2,
+           "Init done and hba is online.\n");
+
        scsi_scan_host(host);
 
        qla2x00_alloc_sysfs_attr(base_vha);
@@ -2275,14 +2415,17 @@ skip_dpc:
 
        qla2x00_dfs_setup(base_vha);
 
-       qla_printk(KERN_INFO, ha, "\n"
-           " QLogic Fibre Channel HBA Driver: %s\n"
-           "  QLogic %s - %s\n"
-           "  ISP%04X: %s @ %s hdma%c, host#=%ld, fw=%s\n",
-           qla2x00_version_str, ha->model_number,
-           ha->model_desc ? ha->model_desc : "", pdev->device,
-           ha->isp_ops->pci_info_str(base_vha, pci_info), pci_name(pdev),
-           ha->flags.enable_64bit_addressing ? '+' : '-', base_vha->host_no,
+       ql_log(ql_log_info, base_vha, 0x00fa,
+           "QLogic Fibre Channed HBA Driver: %s.\n",
+           qla2x00_version_str);
+       ql_log(ql_log_info, base_vha, 0x00fb,
+           "QLogic %s - %s.\n",
+           ha->model_number, ha->model_desc ? ha->model_desc : "");
+       ql_log(ql_log_info, base_vha, 0x00fc,
+           "ISP%04X: %s @ %s hdma%c host#=%ld fw=%s.\n",
+           pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info),
+           pci_name(pdev), ha->flags.enable_64bit_addressing ? '+' : '-',
+           base_vha->host_no,
            ha->isp_ops->fw_version_str(base_vha, fw_str));
 
        return 0;
@@ -2580,20 +2723,15 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport,
                fcport->login_retry = vha->hw->login_retry_count;
                set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
 
-               DEBUG(printk("scsi(%ld): Port login retry: "
+               ql_dbg(ql_dbg_disc, vha, 0x2067,
+                   "Port login retry "
                    "%02x%02x%02x%02x%02x%02x%02x%02x, "
-                   "id = 0x%04x retry cnt=%d\n",
-                   vha->host_no,
-                   fcport->port_name[0],
-                   fcport->port_name[1],
-                   fcport->port_name[2],
-                   fcport->port_name[3],
-                   fcport->port_name[4],
-                   fcport->port_name[5],
-                   fcport->port_name[6],
-                   fcport->port_name[7],
-                   fcport->loop_id,
-                   fcport->login_retry));
+                   "id = 0x%04x retry cnt=%d.\n",
+                   fcport->port_name[0], fcport->port_name[1],
+                   fcport->port_name[2], fcport->port_name[3],
+                   fcport->port_name[4], fcport->port_name[5],
+                   fcport->port_name[6], fcport->port_name[7],
+                   fcport->loop_id, fcport->login_retry);
        }
 }
 
@@ -2676,6 +2814,9 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                        ctx_cachep);
                if (!ha->ctx_mempool)
                        goto fail_free_srb_mempool;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0021,
+                   "ctx_cachep=%p ctx_mempool=%p.\n",
+                   ctx_cachep, ha->ctx_mempool);
        }
 
        /* Get memory for cached NVRAM */
@@ -2690,22 +2831,29 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
        if (!ha->s_dma_pool)
                goto fail_free_nvram;
 
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0022,
+           "init_cb=%p gid_list=%p, srb_mempool=%p s_dma_pool=%p.\n",
+           ha->init_cb, ha->gid_list, ha->srb_mempool, ha->s_dma_pool);
+
        if (IS_QLA82XX(ha) || ql2xenabledif) {
                ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev,
                        DSD_LIST_DMA_POOL_SIZE, 8, 0);
                if (!ha->dl_dma_pool) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Memory Allocation failed - dl_dma_pool\n");
+                       ql_log_pci(ql_log_fatal, ha->pdev, 0x0023,
+                           "Failed to allocate memory for dl_dma_pool.\n");
                        goto fail_s_dma_pool;
                }
 
                ha->fcp_cmnd_dma_pool = dma_pool_create(name, &ha->pdev->dev,
                        FCP_CMND_DMA_POOL_SIZE, 8, 0);
                if (!ha->fcp_cmnd_dma_pool) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Memory Allocation failed - fcp_cmnd_dma_pool\n");
+                       ql_log_pci(ql_log_fatal, ha->pdev, 0x0024,
+                           "Failed to allocate memory for fcp_cmnd_dma_pool.\n");
                        goto fail_dl_dma_pool;
                }
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0025,
+                   "dl_dma_pool=%p fcp_cmnd_dma_pool=%p.\n",
+                   ha->dl_dma_pool, ha->fcp_cmnd_dma_pool);
        }
 
        /* Allocate memory for SNS commands */
@@ -2715,6 +2863,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL);
                if (!ha->sns_cmd)
                        goto fail_dma_pool;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0026,
+                   "sns_cmd.\n", ha->sns_cmd);
        } else {
        /* Get consistent memory allocated for MS IOCB */
                ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
@@ -2726,12 +2876,16 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                        sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL);
                if (!ha->ct_sns)
                        goto fail_free_ms_iocb;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0027,
+                   "ms_iocb=%p ct_sns=%p.\n",
+                   ha->ms_iocb, ha->ct_sns);
        }
 
        /* Allocate memory for request ring */
        *req = kzalloc(sizeof(struct req_que), GFP_KERNEL);
        if (!*req) {
-               DEBUG(printk("Unable to allocate memory for req\n"));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0028,
+                   "Failed to allocate memory for req.\n");
                goto fail_req;
        }
        (*req)->length = req_len;
@@ -2739,14 +2893,15 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                ((*req)->length + 1) * sizeof(request_t),
                &(*req)->dma, GFP_KERNEL);
        if (!(*req)->ring) {
-               DEBUG(printk("Unable to allocate memory for req_ring\n"));
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0029,
+                   "Failed to allocate memory for req_ring.\n");
                goto fail_req_ring;
        }
        /* Allocate memory for response ring */
        *rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL);
        if (!*rsp) {
-               qla_printk(KERN_WARNING, ha,
-                       "Unable to allocate memory for rsp\n");
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x002a,
+                   "Failed to allocate memory for rsp.\n");
                goto fail_rsp;
        }
        (*rsp)->hw = ha;
@@ -2755,19 +2910,24 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                ((*rsp)->length + 1) * sizeof(response_t),
                &(*rsp)->dma, GFP_KERNEL);
        if (!(*rsp)->ring) {
-               qla_printk(KERN_WARNING, ha,
-                       "Unable to allocate memory for rsp_ring\n");
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x002b,
+                   "Failed to allocate memory for rsp_ring.\n");
                goto fail_rsp_ring;
        }
        (*req)->rsp = *rsp;
        (*rsp)->req = *req;
+       ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002c,
+           "req=%p req->length=%d req->ring=%p rsp=%p "
+           "rsp->length=%d rsp->ring=%p.\n",
+           *req, (*req)->length, (*req)->ring, *rsp, (*rsp)->length,
+           (*rsp)->ring);
        /* Allocate memory for NVRAM data for vports */
        if (ha->nvram_npiv_size) {
                ha->npiv_info = kzalloc(sizeof(struct qla_npiv_entry) *
-                                       ha->nvram_npiv_size, GFP_KERNEL);
+                   ha->nvram_npiv_size, GFP_KERNEL);
                if (!ha->npiv_info) {
-                       qla_printk(KERN_WARNING, ha,
-                               "Unable to allocate memory for npiv info\n");
+                       ql_log_pci(ql_log_fatal, ha->pdev, 0x002d,
+                           "Failed to allocate memory for npiv_info.\n");
                        goto fail_npiv_info;
                }
        } else
@@ -2779,6 +2939,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                    &ha->ex_init_cb_dma);
                if (!ha->ex_init_cb)
                        goto fail_ex_init_cb;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002e,
+                   "ex_init_cb=%p.\n", ha->ex_init_cb);
        }
 
        INIT_LIST_HEAD(&ha->gbl_dsd_list);
@@ -2789,6 +2951,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                        &ha->async_pd_dma);
                if (!ha->async_pd)
                        goto fail_async_pd;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002f,
+                   "async_pd=%p.\n", ha->async_pd);
        }
 
        INIT_LIST_HEAD(&ha->vp_list);
@@ -2854,7 +3018,8 @@ fail_free_init_cb:
        ha->init_cb = NULL;
        ha->init_cb_dma = 0;
 fail:
-       DEBUG(printk("%s: Memory allocation failure\n", __func__));
+       ql_log(ql_log_fatal, NULL, 0x0030,
+           "Memory allocation failure.\n");
        return -ENOMEM;
 }
 
@@ -3003,8 +3168,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
 
        host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
        if (host == NULL) {
-               printk(KERN_WARNING
-               "qla2xxx: Couldn't allocate host from scsi layer!\n");
+               ql_log_pci(ql_log_fatal, ha->pdev, 0x0107,
+                   "Failed to allocate host from the scsi layer, aborting.\n");
                goto fail;
        }
 
@@ -3023,6 +3188,11 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
        spin_lock_init(&vha->work_lock);
 
        sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no);
+       ql_dbg(ql_dbg_init, vha, 0x0041,
+           "Allocated the host=%p hw=%p vha=%p dev_name=%s",
+           vha->host, vha->hw, vha,
+           dev_name(&(ha->pdev->dev)));
+
        return vha;
 
 fail:
@@ -3264,18 +3434,18 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
                        if (status == QLA_SUCCESS) {
                                fcport->old_loop_id = fcport->loop_id;
 
-                               DEBUG(printk("scsi(%ld): port login OK: logged "
-                               "in ID 0x%x\n", vha->host_no, fcport->loop_id));
+                               ql_dbg(ql_dbg_disc, vha, 0x2003,
+                                   "Port login OK: logged in ID 0x%x.\n",
+                                   fcport->loop_id);
 
                                qla2x00_update_fcport(vha, fcport);
 
                        } else if (status == 1) {
                                set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
                                /* retry the login again */
-                               DEBUG(printk("scsi(%ld): Retrying"
-                               " %d login again loop_id 0x%x\n",
-                               vha->host_no, fcport->login_retry,
-                                               fcport->loop_id));
+                               ql_dbg(ql_dbg_disc, vha, 0x2007,
+                                   "Retrying %d login again loop_id 0x%x.\n",
+                                   fcport->login_retry, fcport->loop_id);
                        } else {
                                fcport->login_retry = 0;
                        }
@@ -3315,26 +3485,27 @@ qla2x00_do_dpc(void *data)
 
        set_current_state(TASK_INTERRUPTIBLE);
        while (!kthread_should_stop()) {
-               DEBUG3(printk("qla2x00: DPC handler sleeping\n"));
+               ql_dbg(ql_dbg_dpc, base_vha, 0x4000,
+                   "DPC handler sleeping.\n");
 
                schedule();
                __set_current_state(TASK_RUNNING);
 
-               DEBUG3(printk("qla2x00: DPC handler waking up\n"));
+               ql_dbg(ql_dbg_dpc, base_vha, 0x4001,
+                   "DPC handler waking up.\n");
+               ql_dbg(ql_dbg_dpc, base_vha, 0x4002,
+                   "dpc_flags=0x%lx.\n", base_vha->dpc_flags);
 
                /* Initialization not yet finished. Don't do anything yet. */
                if (!base_vha->flags.init_done)
                        continue;
 
                if (ha->flags.eeh_busy) {
-                       DEBUG17(qla_printk(KERN_WARNING, ha,
-                           "qla2x00_do_dpc: dpc_flags: %lx\n",
-                           base_vha->dpc_flags));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x4003,
+                           "eeh_busy=%d.\n", ha->flags.eeh_busy);
                        continue;
                }
 
-               DEBUG3(printk("scsi(%ld): DPC handler\n", base_vha->host_no));
-
                ha->dpc_active = 1;
 
                if (ha->flags.mbox_busy) {
@@ -3351,8 +3522,8 @@ qla2x00_do_dpc(void *data)
                                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                                        QLA82XX_DEV_FAILED);
                                qla82xx_idc_unlock(ha);
-                               qla_printk(KERN_INFO, ha,
-                                       "HW State: FAILED\n");
+                               ql_log(ql_log_info, base_vha, 0x4004,
+                                   "HW State: FAILED.\n");
                                qla82xx_device_state_handler(base_vha);
                                continue;
                        }
@@ -3360,10 +3531,8 @@ qla2x00_do_dpc(void *data)
                        if (test_and_clear_bit(FCOE_CTX_RESET_NEEDED,
                                &base_vha->dpc_flags)) {
 
-                               DEBUG(printk(KERN_INFO
-                                       "scsi(%ld): dpc: sched "
-                                       "qla82xx_fcoe_ctx_reset ha = %p\n",
-                                       base_vha->host_no, ha));
+                               ql_dbg(ql_dbg_dpc, base_vha, 0x4005,
+                                   "FCoE context reset scheduled.\n");
                                if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
                                        &base_vha->dpc_flags))) {
                                        if (qla82xx_fcoe_ctx_reset(base_vha)) {
@@ -3377,18 +3546,16 @@ qla2x00_do_dpc(void *data)
                                                &base_vha->dpc_flags);
                                }
 
-                               DEBUG(printk("scsi(%ld): dpc:"
-                                       " qla82xx_fcoe_ctx_reset end\n",
-                                       base_vha->host_no));
+                               ql_dbg(ql_dbg_dpc, base_vha, 0x4006,
+                                   "FCoE context reset end.\n");
                        }
                }
 
                if (test_and_clear_bit(ISP_ABORT_NEEDED,
                                                &base_vha->dpc_flags)) {
 
-                       DEBUG(printk("scsi(%ld): dpc: sched "
-                           "qla2x00_abort_isp ha = %p\n",
-                           base_vha->host_no, ha));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x4007,
+                           "ISP abort scheduled.\n");
                        if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
                            &base_vha->dpc_flags))) {
 
@@ -3401,8 +3568,8 @@ qla2x00_do_dpc(void *data)
                                                &base_vha->dpc_flags);
                        }
 
-                       DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n",
-                           base_vha->host_no));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x4008,
+                           "ISP abort end.\n");
                }
 
                if (test_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags)) {
@@ -3411,9 +3578,8 @@ qla2x00_do_dpc(void *data)
                }
 
                if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
-                       DEBUG(printk(KERN_INFO "scsi(%ld): dpc: sched "
-                           "qla2x00_quiesce_needed ha = %p\n",
-                           base_vha->host_no, ha));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
+                           "Quiescence mode scheduled.\n");
                        qla82xx_device_state_handler(base_vha);
                        clear_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags);
                        if (!ha->flags.quiesce_owner) {
@@ -3423,17 +3589,20 @@ qla2x00_do_dpc(void *data)
                                qla82xx_clear_qsnt_ready(base_vha);
                                qla82xx_idc_unlock(ha);
                        }
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400a,
+                           "Quiescence mode end.\n");
                }
 
                if (test_and_clear_bit(RESET_MARKER_NEEDED,
                                                        &base_vha->dpc_flags) &&
                    (!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) {
 
-                       DEBUG(printk("scsi(%ld): qla2x00_reset_marker()\n",
-                           base_vha->host_no));
-
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400b,
+                           "Reset marker scheduled.\n");
                        qla2x00_rst_aen(base_vha);
                        clear_bit(RESET_ACTIVE, &base_vha->dpc_flags);
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400c,
+                           "Reset marker end.\n");
                }
 
                /* Retry each device up to login retry count */
@@ -3442,19 +3611,18 @@ qla2x00_do_dpc(void *data)
                    !test_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags) &&
                    atomic_read(&base_vha->loop_state) != LOOP_DOWN) {
 
-                       DEBUG(printk("scsi(%ld): qla2x00_port_login()\n",
-                                       base_vha->host_no));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400d,
+                           "Relogin scheduled.\n");
                        qla2x00_relogin(base_vha);
-
-                       DEBUG(printk("scsi(%ld): qla2x00_port_login - end\n",
-                           base_vha->host_no));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400e,
+                           "Relogin end.\n");
                }
 
                if (test_and_clear_bit(LOOP_RESYNC_NEEDED,
                                                        &base_vha->dpc_flags)) {
 
-                       DEBUG(printk("scsi(%ld): qla2x00_loop_resync()\n",
-                               base_vha->host_no));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x400f,
+                           "Loop resync scheduled.\n");
 
                        if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
                            &base_vha->dpc_flags))) {
@@ -3465,8 +3633,8 @@ qla2x00_do_dpc(void *data)
                                                &base_vha->dpc_flags);
                        }
 
-                       DEBUG(printk("scsi(%ld): qla2x00_loop_resync - end\n",
-                           base_vha->host_no));
+                       ql_dbg(ql_dbg_dpc, base_vha, 0x4010,
+                           "Loop resync end.\n");
                }
 
                if (test_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags) &&
@@ -3489,7 +3657,8 @@ qla2x00_do_dpc(void *data)
        } /* End of while(1) */
        __set_current_state(TASK_RUNNING);
 
-       DEBUG(printk("scsi(%ld): DPC handler exiting\n", base_vha->host_no));
+       ql_dbg(ql_dbg_dpc, base_vha, 0x4011,
+           "DPC handler exiting.\n");
 
        /*
         * Make sure that nobody tries to wake us up again.
@@ -3596,9 +3765,11 @@ void
 qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
 {
        if (atomic_read(&sp->ref_count) == 0) {
-               DEBUG2(qla_printk(KERN_WARNING, ha,
-                   "SP reference-count to ZERO -- sp=%p\n", sp));
-               DEBUG2(BUG());
+               ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3015,
+                   "SP reference-count to ZERO -- sp=%p cmd=%p.\n",
+                   sp, sp->cmd);
+               if (ql2xextended_error_logging & ql_dbg_io)
+                       BUG();
                return;
        }
        if (!atomic_dec_and_test(&sp->ref_count))
@@ -3626,6 +3797,9 @@ qla2x00_timer(scsi_qla_host_t *vha)
        struct req_que *req;
 
        if (ha->flags.eeh_busy) {
+               ql_dbg(ql_dbg_timer, vha, 0x6000,
+                   "EEH = %d, restarting timer.\n",
+                   ha->flags.eeh_busy);
                qla2x00_restart_timer(vha, WATCH_INTERVAL);
                return;
        }
@@ -3650,9 +3824,8 @@ qla2x00_timer(scsi_qla_host_t *vha)
                if (atomic_read(&vha->loop_down_timer) ==
                    vha->loop_down_abort_time) {
 
-                       DEBUG(printk("scsi(%ld): Loop Down - aborting the "
-                           "queues before time expire\n",
-                           vha->host_no));
+                       ql_log(ql_log_info, vha, 0x6008,
+                           "Loop down - aborting the queues before time expires.\n");
 
                        if (!IS_QLA2100(ha) && vha->link_down_timeout)
                                atomic_set(&vha->loop_state, LOOP_DEAD);
@@ -3697,10 +3870,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
                /* if the loop has been down for 4 minutes, reinit adapter */
                if (atomic_dec_and_test(&vha->loop_down_timer) != 0) {
                        if (!(vha->device_flags & DFLG_NO_CABLE)) {
-                               DEBUG(printk("scsi(%ld): Loop down - "
-                                   "aborting ISP.\n",
-                                   vha->host_no));
-                               qla_printk(KERN_WARNING, ha,
+                               ql_log(ql_log_warn, vha, 0x6009,
                                    "Loop down - aborting ISP.\n");
 
                                if (IS_QLA82XX(ha))
@@ -3711,9 +3881,9 @@ qla2x00_timer(scsi_qla_host_t *vha)
                                                &vha->dpc_flags);
                        }
                }
-               DEBUG3(printk("scsi(%ld): Loop Down - seconds remaining %d\n",
-                   vha->host_no,
-                   atomic_read(&vha->loop_down_timer)));
+               ql_dbg(ql_dbg_timer, vha, 0x600a,
+                   "Loop down - seconds remaining %d.\n",
+                   atomic_read(&vha->loop_down_timer));
        }
 
        /* Check if beacon LED needs to be blinked for physical host only */
@@ -3736,8 +3906,27 @@ qla2x00_timer(scsi_qla_host_t *vha)
            test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) ||
            test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) ||
            test_bit(VP_DPC_NEEDED, &vha->dpc_flags) ||
-           test_bit(RELOGIN_NEEDED, &vha->dpc_flags)))
+           test_bit(RELOGIN_NEEDED, &vha->dpc_flags))) {
+               ql_dbg(ql_dbg_timer, vha, 0x600b,
+                   "isp_abort_needed=%d loop_resync_needed=%d "
+                   "fcport_update_needed=%d start_dpc=%d "
+                   "reset_marker_needed=%d",
+                   test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags),
+                   test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags),
+                   test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags),
+                   start_dpc,
+                   test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags));
+               ql_dbg(ql_dbg_timer, vha, 0x600c,
+                   "beacon_blink_needed=%d isp_unrecoverable=%d "
+                   "fcoe_ctx_reset_needed=%d vp_dpc_needed=%d "
+                   "relogin_needed=%d.\n",
+                   test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags),
+                   test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags),
+                   test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags),
+                   test_bit(VP_DPC_NEEDED, &vha->dpc_flags),
+                   test_bit(RELOGIN_NEEDED, &vha->dpc_flags));
                qla2xxx_wake_dpc(vha);
+       }
 
        qla2x00_restart_timer(vha, WATCH_INTERVAL);
 }
@@ -3806,8 +3995,8 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)
                goto out;
 
        if (request_firmware(&blob->fw, blob->name, &ha->pdev->dev)) {
-               DEBUG2(printk("scsi(%ld): Failed to load firmware image "
-                   "(%s).\n", vha->host_no, blob->name));
+               ql_log(ql_log_warn, vha, 0x0063,
+                   "Failed to load firmware image (%s).\n", blob->name);
                blob->fw = NULL;
                blob = NULL;
                goto out;
@@ -3836,8 +4025,8 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
        scsi_qla_host_t *vha = pci_get_drvdata(pdev);
        struct qla_hw_data *ha = vha->hw;
 
-       DEBUG2(qla_printk(KERN_WARNING, ha, "error_detected:state %x\n",
-           state));
+       ql_dbg(ql_dbg_aer, vha, 0x9000,
+           "PCI error detected, state %x.\n", state);
 
        switch (state) {
        case pci_channel_io_normal:
@@ -3850,9 +4039,9 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
                        ha->flags.isp82xx_fw_hung = 1;
                        if (ha->flags.mbox_busy) {
                                ha->flags.mbox_int = 1;
-                               DEBUG2(qla_printk(KERN_ERR, ha,
-                                       "Due to pci channel io frozen, doing premature "
-                                       "completion of mbx command\n"));
+                               ql_dbg(ql_dbg_aer, vha, 0x9001,
+                                   "Due to pci channel io frozen, doing premature "
+                                   "completion of mbx command.\n");
                                complete(&ha->mbx_intr_comp);
                        }
                }
@@ -3900,8 +4089,8 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        if (risc_paused) {
-               qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, "
-                   "Dumping firmware!\n");
+               ql_log(ql_log_info, base_vha, 0x9003,
+                   "RISC paused -- mmio_enabled, Dumping firmware.\n");
                ha->isp_ops->fw_dump(base_vha, 0);
 
                return PCI_ERS_RESULT_NEED_RESET;
@@ -3917,8 +4106,8 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
        int fn;
        struct pci_dev *other_pdev = NULL;
 
-       DEBUG17(qla_printk(KERN_INFO, ha,
-           "scsi(%ld): In qla82xx_error_recovery\n", base_vha->host_no));
+       ql_dbg(ql_dbg_aer, base_vha, 0x9006,
+           "Entered %s.\n", __func__);
 
        set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
 
@@ -3932,8 +4121,8 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
        fn = PCI_FUNC(ha->pdev->devfn);
        while (fn > 0) {
                fn--;
-               DEBUG17(qla_printk(KERN_INFO, ha,
-                   "Finding pci device at function = 0x%x\n", fn));
+               ql_dbg(ql_dbg_aer, base_vha, 0x9007,
+                   "Finding pci device at function = 0x%x.\n", fn);
                other_pdev =
                    pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus),
                    ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn),
@@ -3942,9 +4131,9 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                if (!other_pdev)
                        continue;
                if (atomic_read(&other_pdev->enable_cnt)) {
-                       DEBUG17(qla_printk(KERN_INFO, ha,
-                           "Found PCI func available and enabled at 0x%x\n",
-                           fn));
+                       ql_dbg(ql_dbg_aer, base_vha, 0x9008,
+                           "Found PCI func available and enable at 0x%x.\n",
+                           fn);
                        pci_dev_put(other_pdev);
                        break;
                }
@@ -3953,8 +4142,9 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
 
        if (!fn) {
                /* Reset owner */
-               DEBUG17(qla_printk(KERN_INFO, ha,
-                   "This devfn is reset owner = 0x%x\n", ha->pdev->devfn));
+               ql_dbg(ql_dbg_aer, base_vha, 0x9009,
+                   "This devfn is reset owner = 0x%x.\n",
+                   ha->pdev->devfn);
                qla82xx_idc_lock(ha);
 
                qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
@@ -3964,8 +4154,8 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                    QLA82XX_IDC_VERSION);
 
                drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
-               DEBUG17(qla_printk(KERN_INFO, ha,
-                   "drv_active = 0x%x\n", drv_active));
+               ql_dbg(ql_dbg_aer, base_vha, 0x900a,
+                   "drv_active = 0x%x.\n", drv_active);
 
                qla82xx_idc_unlock(ha);
                /* Reset if device is not already reset
@@ -3978,12 +4168,14 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                qla82xx_idc_lock(ha);
 
                if (rval != QLA_SUCCESS) {
-                       qla_printk(KERN_INFO, ha, "HW State: FAILED\n");
+                       ql_log(ql_log_info, base_vha, 0x900b,
+                           "HW State: FAILED.\n");
                        qla82xx_clear_drv_active(ha);
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                            QLA82XX_DEV_FAILED);
                } else {
-                       qla_printk(KERN_INFO, ha, "HW State: READY\n");
+                       ql_log(ql_log_info, base_vha, 0x900c,
+                           "HW State: READY.\n");
                        qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
                            QLA82XX_DEV_READY);
                        qla82xx_idc_unlock(ha);
@@ -3996,8 +4188,9 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
                }
                qla82xx_idc_unlock(ha);
        } else {
-               DEBUG17(qla_printk(KERN_INFO, ha,
-                   "This devfn is not reset owner = 0x%x\n", ha->pdev->devfn));
+               ql_dbg(ql_dbg_aer, base_vha, 0x900d,
+                   "This devfn is not reset owner = 0x%x.\n",
+                   ha->pdev->devfn);
                if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) ==
                    QLA82XX_DEV_READY)) {
                        ha->flags.isp82xx_fw_hung = 0;
@@ -4021,7 +4214,8 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
        struct rsp_que *rsp;
        int rc, retries = 10;
 
-       DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset\n"));
+       ql_dbg(ql_dbg_aer, base_vha, 0x9004,
+           "Slot Reset.\n");
 
        /* Workaround: qla2xxx driver which access hardware earlier
         * needs error state to be pci_channel_io_online.
@@ -4042,7 +4236,7 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
                rc = pci_enable_device(pdev);
 
        if (rc) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, base_vha, 0x9005,
                    "Can't re-enable PCI device after reset.\n");
                goto exit_slot_reset;
        }
@@ -4072,8 +4266,8 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
 
 
 exit_slot_reset:
-       DEBUG17(qla_printk(KERN_WARNING, ha,
-           "slot_reset-return:ret=%x\n", ret));
+       ql_dbg(ql_dbg_aer, base_vha, 0x900e,
+           "slot_reset return %x.\n", ret);
 
        return ret;
 }
@@ -4085,13 +4279,13 @@ qla2xxx_pci_resume(struct pci_dev *pdev)
        struct qla_hw_data *ha = base_vha->hw;
        int ret;
 
-       DEBUG17(qla_printk(KERN_WARNING, ha, "pci_resume\n"));
+       ql_dbg(ql_dbg_aer, base_vha, 0x900f,
+           "pci_resume.\n");
 
        ret = qla2x00_wait_for_hba_online(base_vha);
        if (ret != QLA_SUCCESS) {
-               qla_printk(KERN_ERR, ha,
-                   "the device failed to resume I/O "
-                   "from slot/link_reset");
+               ql_log(ql_log_fatal, base_vha, 0x9002,
+                   "The device failed to resume I/O from slot/link_reset.\n");
        }
 
        pci_cleanup_aer_uncorrect_error_status(pdev);
@@ -4155,8 +4349,8 @@ qla2x00_module_init(void)
        srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0,
            SLAB_HWCACHE_ALIGN, NULL);
        if (srb_cachep == NULL) {
-               printk(KERN_ERR
-                   "qla2xxx: Unable to allocate SRB cache...Failing load!\n");
+               ql_log(ql_log_fatal, NULL, 0x0001,
+                   "Unable to allocate SRB cache...Failing load!.\n");
                return -ENOMEM;
        }
 
@@ -4169,13 +4363,15 @@ qla2x00_module_init(void)
            fc_attach_transport(&qla2xxx_transport_functions);
        if (!qla2xxx_transport_template) {
                kmem_cache_destroy(srb_cachep);
+               ql_log(ql_log_fatal, NULL, 0x0002,
+                   "fc_attach_transport failed...Failing load!.\n");
                return -ENODEV;
        }
 
        apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops);
        if (apidev_major < 0) {
-               printk(KERN_WARNING "qla2xxx: Unable to register char device "
-                   "%s\n", QLA2XXX_APIDEV);
+               ql_log(ql_log_fatal, NULL, 0x0003,
+                   "Unable to register char device %s.\n", QLA2XXX_APIDEV);
        }
 
        qla2xxx_transport_vport_template =
@@ -4183,16 +4379,21 @@ qla2x00_module_init(void)
        if (!qla2xxx_transport_vport_template) {
                kmem_cache_destroy(srb_cachep);
                fc_release_transport(qla2xxx_transport_template);
+               ql_log(ql_log_fatal, NULL, 0x0004,
+                   "fc_attach_transport vport failed...Failing load!.\n");
                return -ENODEV;
        }
-
-       printk(KERN_INFO "QLogic Fibre Channel HBA Driver: %s\n",
+       ql_log(ql_log_info, NULL, 0x0005,
+           "QLogic Fibre Channel HBA Driver: %s.\n",
            qla2x00_version_str);
        ret = pci_register_driver(&qla2xxx_pci_driver);
        if (ret) {
                kmem_cache_destroy(srb_cachep);
                fc_release_transport(qla2xxx_transport_template);
                fc_release_transport(qla2xxx_transport_vport_template);
+               ql_log(ql_log_fatal, NULL, 0x0006,
+                   "pci_register_driver failed...ret=%d Failing load!.\n",
+                   ret);
        }
        return ret;
 }
index 693647661ed1e535faa2dffca9abf6adfed0c472..eff13563c82dba6061b51b5d6b7786b718ac181d 100644 (file)
@@ -189,6 +189,7 @@ qla2x00_write_nvram_word(struct qla_hw_data *ha, uint32_t addr, uint16_t data)
        uint16_t word;
        uint32_t nv_cmd, wait_cnt;
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        qla2x00_nv_write(ha, NVR_DATA_OUT);
        qla2x00_nv_write(ha, 0);
@@ -220,8 +221,8 @@ qla2x00_write_nvram_word(struct qla_hw_data *ha, uint32_t addr, uint16_t data)
        wait_cnt = NVR_WAIT_CNT;
        do {
                if (!--wait_cnt) {
-                       DEBUG9_10(qla_printk(KERN_WARNING, ha,
-                           "NVRAM didn't go ready...\n"));
+                       ql_dbg(ql_dbg_user, vha, 0x708d,
+                           "NVRAM didn't go ready...\n");
                        break;
                }
                NVRAM_DELAY();
@@ -308,6 +309,7 @@ qla2x00_clear_nvram_protection(struct qla_hw_data *ha)
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
        uint32_t word, wait_cnt;
        uint16_t wprot, wprot_old;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        /* Clear NVRAM write protection. */
        ret = QLA_FUNCTION_FAILED;
@@ -350,8 +352,8 @@ qla2x00_clear_nvram_protection(struct qla_hw_data *ha)
                wait_cnt = NVR_WAIT_CNT;
                do {
                        if (!--wait_cnt) {
-                               DEBUG9_10(qla_printk(KERN_WARNING, ha,
-                                   "NVRAM didn't go ready...\n"));
+                               ql_dbg(ql_dbg_user, vha, 0x708e,
+                                   "NVRAM didn't go ready...\n");
                                break;
                        }
                        NVRAM_DELAY();
@@ -371,6 +373,7 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat)
 {
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
        uint32_t word, wait_cnt;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
        if (stat != QLA_SUCCESS)
                return;
@@ -409,8 +412,8 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat)
        wait_cnt = NVR_WAIT_CNT;
        do {
                if (!--wait_cnt) {
-                       DEBUG9_10(qla_printk(KERN_WARNING, ha,
-                           "NVRAM didn't go ready...\n"));
+                       ql_dbg(ql_dbg_user, vha, 0x708f,
+                           "NVRAM didn't go ready...\n");
                        break;
                }
                NVRAM_DELAY();
@@ -607,9 +610,10 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
        for (chksum = 0; cnt; cnt--)
                chksum += le16_to_cpu(*wptr++);
        if (chksum) {
-               qla_printk(KERN_ERR, ha,
+               ql_log(ql_log_fatal, vha, 0x0045,
                    "Inconsistent FLTL detected: checksum=0x%x.\n", chksum);
-               qla2x00_dump_buffer(buf, sizeof(struct qla_flt_location));
+               ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010e,
+                   buf, sizeof(struct qla_flt_location));
                return QLA_FUNCTION_FAILED;
        }
 
@@ -618,7 +622,9 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
        *start = (le16_to_cpu(fltl->start_hi) << 16 |
            le16_to_cpu(fltl->start_lo)) >> 2;
 end:
-       DEBUG2(qla_printk(KERN_DEBUG, ha, "FLTL[%s] = 0x%x.\n", loc, *start));
+       ql_dbg(ql_dbg_init, vha, 0x0046,
+           "FLTL[%s] = 0x%x.\n",
+           loc, *start);
        return QLA_SUCCESS;
 }
 
@@ -685,10 +691,10 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
        if (*wptr == __constant_cpu_to_le16(0xffff))
                goto no_flash_data;
        if (flt->version != __constant_cpu_to_le16(1)) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported FLT detected: "
-                   "version=0x%x length=0x%x checksum=0x%x.\n",
+               ql_log(ql_log_warn, vha, 0x0047,
+                   "Unsupported FLT detected: version=0x%x length=0x%x checksum=0x%x.\n",
                    le16_to_cpu(flt->version), le16_to_cpu(flt->length),
-                   le16_to_cpu(flt->checksum)));
+                   le16_to_cpu(flt->checksum));
                goto no_flash_data;
        }
 
@@ -696,10 +702,10 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
        for (chksum = 0; cnt; cnt--)
                chksum += le16_to_cpu(*wptr++);
        if (chksum) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FLT detected: "
-                   "version=0x%x length=0x%x checksum=0x%x.\n",
+               ql_log(ql_log_fatal, vha, 0x0048,
+                   "Inconsistent FLT detected: version=0x%x length=0x%x checksum=0x%x.\n",
                    le16_to_cpu(flt->version), le16_to_cpu(flt->length),
-                   chksum));
+                   le16_to_cpu(flt->checksum));
                goto no_flash_data;
        }
 
@@ -708,10 +714,11 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
        for ( ; cnt; cnt--, region++) {
                /* Store addresses as DWORD offsets. */
                start = le32_to_cpu(region->start) >> 2;
-
-               DEBUG3(qla_printk(KERN_DEBUG, ha, "FLT[%02x]: start=0x%x "
-                   "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start,
-                   le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size)));
+               ql_dbg(ql_dbg_init, vha, 0x0049,
+                   "FLT[%02x]: start=0x%x "
+                   "end=0x%x size=0x%x.\n", le32_to_cpu(region->code),
+                   start, le32_to_cpu(region->end) >> 2,
+                   le32_to_cpu(region->size));
 
                switch (le32_to_cpu(region->code) & 0xff) {
                case FLT_REG_FW:
@@ -796,12 +803,16 @@ no_flash_data:
        ha->flt_region_npiv_conf = ha->flags.port0 ?
            def_npiv_conf0[def] : def_npiv_conf1[def];
 done:
-       DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "
-           "vpd_nvram=0x%x vpd=0x%x nvram=0x%x fdt=0x%x flt=0x%x "
-           "npiv=0x%x. fcp_prio_cfg=0x%x\n", loc, ha->flt_region_boot,
-           ha->flt_region_fw, ha->flt_region_vpd_nvram, ha->flt_region_vpd,
-           ha->flt_region_nvram, ha->flt_region_fdt, ha->flt_region_flt,
-           ha->flt_region_npiv_conf, ha->flt_region_fcp_prio));
+       ql_dbg(ql_dbg_init, vha, 0x004a,
+           "FLT[%s]: boot=0x%x fw=0x%x vpd_nvram=0x%x vpd=0x%x.\n",
+           loc, ha->flt_region_boot,
+           ha->flt_region_fw, ha->flt_region_vpd_nvram,
+           ha->flt_region_vpd);
+       ql_dbg(ql_dbg_init, vha, 0x004b,
+           "nvram=0x%x fdt=0x%x flt=0x%x npiv=0x%x fcp_prif_cfg=0x%x.\n",
+           ha->flt_region_nvram,
+           ha->flt_region_fdt, ha->flt_region_flt,
+           ha->flt_region_npiv_conf, ha->flt_region_fcp_prio);
 }
 
 static void
@@ -833,10 +844,12 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
            cnt++)
                chksum += le16_to_cpu(*wptr++);
        if (chksum) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FDT detected: "
-                   "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0],
-                   le16_to_cpu(fdt->version)));
-               DEBUG9(qla2x00_dump_buffer((uint8_t *)fdt, sizeof(*fdt)));
+               ql_dbg(ql_dbg_init, vha, 0x004c,
+                   "Inconsistent FDT detected:"
+                   " checksum=0x%x id=%c version0x%x.\n", chksum,
+                   fdt->sig[0], le16_to_cpu(fdt->version));
+               ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0113,
+                   (uint8_t *)fdt, sizeof(*fdt));
                goto no_flash_data;
        }
 
@@ -890,11 +903,12 @@ no_flash_data:
                break;
        }
 done:
-       DEBUG2(qla_printk(KERN_DEBUG, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x "
-           "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
+       ql_dbg(ql_dbg_init, vha, 0x004d,
+           "FDT[%x]: (0x%x/0x%x) erase=0x%x "
+           "pr=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
            ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd,
-           ha->fdt_unprotect_sec_cmd, ha->fdt_wrt_disable,
-           ha->fdt_block_size));
+           ha->fdt_wrt_disable, ha->fdt_block_size);
+
 }
 
 static void
@@ -919,6 +933,10 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha)
                ha->nx_dev_init_timeout = le32_to_cpu(*wptr++);
                ha->nx_reset_timeout = le32_to_cpu(*wptr);
        }
+       ql_dbg(ql_dbg_init, vha, 0x004e,
+           "nx_dev_init_timeout=%d "
+           "nx_reset_timeout=%d.\n", ha->nx_dev_init_timeout,
+           ha->nx_reset_timeout);
        return;
 }
 
@@ -963,17 +981,18 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
        if (hdr.version == __constant_cpu_to_le16(0xffff))
                return;
        if (hdr.version != __constant_cpu_to_le16(1)) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Unsupported NPIV-Config "
+               ql_dbg(ql_dbg_user, vha, 0x7090,
+                   "Unsupported NPIV-Config "
                    "detected: version=0x%x entries=0x%x checksum=0x%x.\n",
                    le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries),
-                   le16_to_cpu(hdr.checksum)));
+                   le16_to_cpu(hdr.checksum));
                return;
        }
 
        data = kmalloc(NPIV_CONFIG_SIZE, GFP_KERNEL);
        if (!data) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "NPIV-Config: Unable to "
-                   "allocate memory.\n"));
+               ql_log(ql_log_warn, vha, 0x7091,
+                   "Unable to allocate memory for data.\n");
                return;
        }
 
@@ -985,10 +1004,11 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
        for (wptr = data, chksum = 0; cnt; cnt--)
                chksum += le16_to_cpu(*wptr++);
        if (chksum) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent NPIV-Config "
+               ql_dbg(ql_dbg_user, vha, 0x7092,
+                   "Inconsistent NPIV-Config "
                    "detected: version=0x%x entries=0x%x checksum=0x%x.\n",
                    le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries),
-                   chksum));
+                   le16_to_cpu(hdr.checksum));
                goto done;
        }
 
@@ -1014,21 +1034,22 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
                vid.port_name = wwn_to_u64(entry->port_name);
                vid.node_name = wwn_to_u64(entry->node_name);
 
-               DEBUG2(qla_printk(KERN_INFO, ha, "NPIV[%02x]: wwpn=%llx "
-                       "wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt,
-                       (unsigned long long)vid.port_name,
-                       (unsigned long long)vid.node_name,
-                       le16_to_cpu(entry->vf_id),
-                       entry->q_qos, entry->f_qos));
+               ql_dbg(ql_dbg_user, vha, 0x7093,
+                   "NPIV[%02x]: wwpn=%llx "
+                   "wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt,
+                   (unsigned long long)vid.port_name,
+                   (unsigned long long)vid.node_name,
+                   le16_to_cpu(entry->vf_id),
+                   entry->q_qos, entry->f_qos);
 
                if (i < QLA_PRECONFIG_VPORTS) {
                        vport = fc_vport_create(vha->host, 0, &vid);
                        if (!vport)
-                               qla_printk(KERN_INFO, ha,
-                               "NPIV-Config: Failed to create vport [%02x]: "
-                               "wwpn=%llx wwnn=%llx.\n", cnt,
-                               (unsigned long long)vid.port_name,
-                               (unsigned long long)vid.node_name);
+                               ql_log(ql_log_warn, vha, 0x7094,
+                                   "NPIV-Config Failed to create vport [%02x]: "
+                                   "wwpn=%llx wwnn=%llx.\n", cnt,
+                                   (unsigned long long)vid.port_name,
+                                   (unsigned long long)vid.node_name);
                }
        }
 done:
@@ -1127,9 +1148,10 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
                optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
                    &optrom_dma, GFP_KERNEL);
                if (!optrom) {
-                       qla_printk(KERN_DEBUG, ha,
-                           "Unable to allocate memory for optrom burst write "
-                           "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
+                       ql_log(ql_log_warn, vha, 0x7095,
+                           "Unable to allocate "
+                           "memory for optrom burst write (%x KB).\n",
+                           OPTROM_BURST_SIZE / 1024);
                }
        }
 
@@ -1138,7 +1160,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
 
        ret = qla24xx_unprotect_flash(vha);
        if (ret != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7096,
                    "Unable to unprotect flash for update.\n");
                goto done;
        }
@@ -1156,9 +1178,9 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
                                    0xff0000) | ((fdata >> 16) & 0xff));
                        ret = qla24xx_erase_sector(vha, fdata);
                        if (ret != QLA_SUCCESS) {
-                               DEBUG9(qla_printk(KERN_WARNING, ha,
-                                   "Unable to erase sector: address=%x.\n",
-                                   faddr));
+                               ql_dbg(ql_dbg_user, vha, 0x7007,
+                                   "Unable to erase erase sector: address=%x.\n",
+                                   faddr);
                                break;
                        }
                }
@@ -1172,12 +1194,12 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
                            flash_data_addr(ha, faddr),
                            OPTROM_BURST_DWORDS);
                        if (ret != QLA_SUCCESS) {
-                               qla_printk(KERN_WARNING, ha,
+                               ql_log(ql_log_warn, vha, 0x7097,
                                    "Unable to burst-write optrom segment "
                                    "(%x/%x/%llx).\n", ret,
                                    flash_data_addr(ha, faddr),
                                    (unsigned long long)optrom_dma);
-                               qla_printk(KERN_WARNING, ha,
+                               ql_log(ql_log_warn, vha, 0x7098,
                                    "Reverting to slow-write.\n");
 
                                dma_free_coherent(&ha->pdev->dev,
@@ -1194,9 +1216,9 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
                ret = qla24xx_write_flash_dword(ha,
                    flash_data_addr(ha, faddr), cpu_to_le32(*dwptr));
                if (ret != QLA_SUCCESS) {
-                       DEBUG9(printk("%s(%ld) Unable to program flash "
-                           "address=%x data=%x.\n", __func__,
-                           vha->host_no, faddr, *dwptr));
+                       ql_dbg(ql_dbg_user, vha, 0x7006,
+                           "Unable to program flash address=%x data=%x.\n",
+                           faddr, *dwptr);
                        break;
                }
 
@@ -1211,7 +1233,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
 
        ret = qla24xx_protect_flash(vha);
        if (ret != QLA_SUCCESS)
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x7099,
                    "Unable to protect flash after update.\n");
 done:
        if (optrom)
@@ -1324,9 +1346,9 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
                ret = qla24xx_write_flash_dword(ha,
                    nvram_data_addr(ha, naddr), cpu_to_le32(*dwptr));
                if (ret != QLA_SUCCESS) {
-                       DEBUG9(qla_printk(KERN_WARNING, ha,
+                       ql_dbg(ql_dbg_user, vha, 0x709a,
                            "Unable to program nvram address=%x data=%x.\n",
-                           naddr, *dwptr));
+                           naddr, *dwptr);
                        break;
                }
        }
@@ -1476,7 +1498,7 @@ qla2x00_beacon_on(struct scsi_qla_host *vha)
        ha->fw_options[1] |= FO1_DISABLE_GPIO6_7;
 
        if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x709b,
                    "Unable to update fw options (beacon on).\n");
                return QLA_FUNCTION_FAILED;
        }
@@ -1541,7 +1563,7 @@ qla2x00_beacon_off(struct scsi_qla_host *vha)
 
        rval = qla2x00_set_fw_options(vha, ha->fw_options);
        if (rval != QLA_SUCCESS)
-               qla_printk(KERN_WARNING, ha,
+               ql_log(ql_log_warn, vha, 0x709c,
                    "Unable to update fw options (beacon off).\n");
        return rval;
 }
@@ -1616,7 +1638,7 @@ qla24xx_beacon_on(struct scsi_qla_host *vha)
 
                if (qla2x00_get_fw_options(vha, ha->fw_options) !=
                    QLA_SUCCESS) {
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x7009,
                            "Unable to update fw options (beacon on).\n");
                        return QLA_FUNCTION_FAILED;
                }
@@ -1670,14 +1692,14 @@ qla24xx_beacon_off(struct scsi_qla_host *vha)
        ha->fw_options[1] &= ~ADD_FO1_DISABLE_GPIO_LED_CTRL;
 
        if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to update fw options (beacon off).\n");
+               ql_log(ql_log_warn, vha, 0x704d,
+                   "Unable to update fw options (beacon on).\n");
                return QLA_FUNCTION_FAILED;
        }
 
        if (qla2x00_get_fw_options(vha, ha->fw_options) != QLA_SUCCESS) {
-               qla_printk(KERN_WARNING, ha,
-                   "Unable to get fw options (beacon off).\n");
+               ql_log(ql_log_warn, vha, 0x704e,
+                   "Unable to update fw options (beacon on).\n");
                return QLA_FUNCTION_FAILED;
        }
 
@@ -2389,10 +2411,9 @@ try_fast:
        optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
            &optrom_dma, GFP_KERNEL);
        if (!optrom) {
-               qla_printk(KERN_DEBUG, ha,
-                   "Unable to allocate memory for optrom burst read "
-                   "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
-
+               ql_log(ql_log_warn, vha, 0x00cc,
+                   "Unable to allocate memory for optrom burst read (%x KB).\n",
+                   OPTROM_BURST_SIZE / 1024);
                goto slow_read;
        }
 
@@ -2407,12 +2428,11 @@ try_fast:
                rval = qla2x00_dump_ram(vha, optrom_dma,
                    flash_data_addr(ha, faddr), burst);
                if (rval) {
-                       qla_printk(KERN_WARNING, ha,
-                           "Unable to burst-read optrom segment "
-                           "(%x/%x/%llx).\n", rval,
-                           flash_data_addr(ha, faddr),
+                       ql_log(ql_log_warn, vha, 0x00f5,
+                           "Unable to burst-read optrom segment (%x/%x/%llx).\n",
+                           rval, flash_data_addr(ha, faddr),
                            (unsigned long long)optrom_dma);
-                       qla_printk(KERN_WARNING, ha,
+                       ql_log(ql_log_warn, vha, 0x00f6,
                            "Reverting to slow-read.\n");
 
                        dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
@@ -2556,8 +2576,8 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                if (qla2x00_read_flash_byte(ha, pcihdr) != 0x55 ||
                    qla2x00_read_flash_byte(ha, pcihdr + 0x01) != 0xaa) {
                        /* No signature */
-                       DEBUG2(qla_printk(KERN_DEBUG, ha, "No matching ROM "
-                           "signature.\n"));
+                       ql_log(ql_log_fatal, vha, 0x0050,
+                           "No matching ROM signature.\n");
                        ret = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -2573,8 +2593,8 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                    qla2x00_read_flash_byte(ha, pcids + 0x2) != 'I' ||
                    qla2x00_read_flash_byte(ha, pcids + 0x3) != 'R') {
                        /* Incorrect header. */
-                       DEBUG2(qla_printk(KERN_INFO, ha, "PCI data struct not "
-                           "found pcir_adr=%x.\n", pcids));
+                       ql_log(ql_log_fatal, vha, 0x0051,
+                           "PCI data struct not found pcir_adr=%x.\n", pcids);
                        ret = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -2588,8 +2608,9 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                            qla2x00_read_flash_byte(ha, pcids + 0x12);
                        ha->bios_revision[1] =
                            qla2x00_read_flash_byte(ha, pcids + 0x13);
-                       DEBUG3(qla_printk(KERN_DEBUG, ha, "read BIOS %d.%d.\n",
-                           ha->bios_revision[1], ha->bios_revision[0]));
+                       ql_dbg(ql_dbg_init, vha, 0x0052,
+                           "Read BIOS %d.%d.\n",
+                           ha->bios_revision[1], ha->bios_revision[0]);
                        break;
                case ROM_CODE_TYPE_FCODE:
                        /* Open Firmware standard for PCI (FCode). */
@@ -2602,12 +2623,14 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                            qla2x00_read_flash_byte(ha, pcids + 0x12);
                        ha->efi_revision[1] =
                            qla2x00_read_flash_byte(ha, pcids + 0x13);
-                       DEBUG3(qla_printk(KERN_DEBUG, ha, "read EFI %d.%d.\n",
-                           ha->efi_revision[1], ha->efi_revision[0]));
+                       ql_dbg(ql_dbg_init, vha, 0x0053,
+                           "Read EFI %d.%d.\n",
+                           ha->efi_revision[1], ha->efi_revision[0]);
                        break;
                default:
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Unrecognized code "
-                           "type %x at pcids %x.\n", code_type, pcids));
+                       ql_log(ql_log_warn, vha, 0x0054,
+                           "Unrecognized code type %x at pcids %x.\n",
+                           code_type, pcids);
                        break;
                }
 
@@ -2627,21 +2650,28 @@ qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
 
                qla2x00_read_flash_data(ha, dbyte, ha->flt_region_fw * 4 + 10,
                    8);
-               DEBUG3(qla_printk(KERN_DEBUG, ha, "dumping fw ver from "
-                   "flash:\n"));
-               DEBUG3(qla2x00_dump_buffer((uint8_t *)dbyte, 8));
+               ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x010a,
+                   "Dumping fw "
+                   "ver from flash:.\n");
+               ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010b,
+                   (uint8_t *)dbyte, 8);
 
                if ((dcode[0] == 0xffff && dcode[1] == 0xffff &&
                    dcode[2] == 0xffff && dcode[3] == 0xffff) ||
                    (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
                    dcode[3] == 0)) {
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Unrecognized fw "
-                           "revision at %x.\n", ha->flt_region_fw * 4));
+                       ql_log(ql_log_warn, vha, 0x0057,
+                           "Unrecognized fw revision at %x.\n",
+                           ha->flt_region_fw * 4);
                } else {
                        /* values are in big endian */
                        ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1];
                        ha->fw_revision[1] = dbyte[2] << 16 | dbyte[3];
                        ha->fw_revision[2] = dbyte[4] << 16 | dbyte[5];
+                       ql_dbg(ql_dbg_init, vha, 0x0058,
+                           "FW Version: "
+                           "%d.%d.%d.\n", ha->fw_revision[0],
+                           ha->fw_revision[1], ha->fw_revision[2]);
                }
        }
 
@@ -2683,8 +2713,8 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                bcode = mbuf + (pcihdr % 4);
                if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) {
                        /* No signature */
-                       DEBUG2(qla_printk(KERN_DEBUG, ha, "No matching ROM "
-                           "signature.\n"));
+                       ql_log(ql_log_fatal, vha, 0x0059,
+                           "No matching ROM signature.\n");
                        ret = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -2699,8 +2729,8 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
                    bcode[0x2] != 'I' || bcode[0x3] != 'R') {
                        /* Incorrect header. */
-                       DEBUG2(qla_printk(KERN_INFO, ha, "PCI data struct not "
-                           "found pcir_adr=%x.\n", pcids));
+                       ql_log(ql_log_fatal, vha, 0x005a,
+                           "PCI data struct not found pcir_adr=%x.\n", pcids);
                        ret = QLA_FUNCTION_FAILED;
                        break;
                }
@@ -2712,26 +2742,30 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
                        /* Intel x86, PC-AT compatible. */
                        ha->bios_revision[0] = bcode[0x12];
                        ha->bios_revision[1] = bcode[0x13];
-                       DEBUG3(qla_printk(KERN_DEBUG, ha, "read BIOS %d.%d.\n",
-                           ha->bios_revision[1], ha->bios_revision[0]));
+                       ql_dbg(ql_dbg_init, vha, 0x005b,
+                           "Read BIOS %d.%d.\n",
+                           ha->bios_revision[1], ha->bios_revision[0]);
                        break;
                case ROM_CODE_TYPE_FCODE:
                        /* Open Firmware standard for PCI (FCode). */
                        ha->fcode_revision[0] = bcode[0x12];
                        ha->fcode_revision[1] = bcode[0x13];
-                       DEBUG3(qla_printk(KERN_DEBUG, ha, "read FCODE %d.%d.\n",
-                           ha->fcode_revision[1], ha->fcode_revision[0]));
+                       ql_dbg(ql_dbg_init, vha, 0x005c,
+                           "Read FCODE %d.%d.\n",
+                           ha->fcode_revision[1], ha->fcode_revision[0]);
                        break;
                case ROM_CODE_TYPE_EFI:
                        /* Extensible Firmware Interface (EFI). */
                        ha->efi_revision[0] = bcode[0x12];
                        ha->efi_revision[1] = bcode[0x13];
-                       DEBUG3(qla_printk(KERN_DEBUG, ha, "read EFI %d.%d.\n",
-                           ha->efi_revision[1], ha->efi_revision[0]));
+                       ql_dbg(ql_dbg_init, vha, 0x005d,
+                           "Read EFI %d.%d.\n",
+                           ha->efi_revision[1], ha->efi_revision[0]);
                        break;
                default:
-                       DEBUG2(qla_printk(KERN_INFO, ha, "Unrecognized code "
-                           "type %x at pcids %x.\n", code_type, pcids));
+                       ql_log(ql_log_warn, vha, 0x005e,
+                           "Unrecognized code type %x at pcids %x.\n",
+                           code_type, pcids);
                        break;
                }
 
@@ -2753,13 +2787,18 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
            dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
            (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
            dcode[3] == 0)) {
-               DEBUG2(qla_printk(KERN_INFO, ha, "Unrecognized fw "
-                   "revision at %x.\n", ha->flt_region_fw * 4));
+               ql_log(ql_log_warn, vha, 0x005f,
+                   "Unrecognized fw revision at %x.\n",
+                   ha->flt_region_fw * 4);
        } else {
                ha->fw_revision[0] = dcode[0];
                ha->fw_revision[1] = dcode[1];
                ha->fw_revision[2] = dcode[2];
                ha->fw_revision[3] = dcode[3];
+               ql_dbg(ql_dbg_init, vha, 0x0060,
+                   "Firmware revision %d.%d.%d.%d.\n",
+                   ha->fw_revision[0], ha->fw_revision[1],
+                   ha->fw_revision[2], ha->fw_revision[3]);
        }
 
        /* Check for golden firmware and get version if available */
@@ -2775,9 +2814,9 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
 
        if (dcode[4] == 0xFFFFFFFF && dcode[5] == 0xFFFFFFFF &&
            dcode[6] == 0xFFFFFFFF && dcode[7] == 0xFFFFFFFF) {
-               DEBUG2(qla_printk(KERN_INFO, ha,
-                   "%s(%ld): Unrecognized golden fw at 0x%x.\n",
-                   __func__, vha->host_no, ha->flt_region_gold_fw * 4));
+               ql_log(ql_log_warn, vha, 0x0056,
+                   "Unrecognized golden fw at 0x%x.\n",
+                   ha->flt_region_gold_fw * 4);
                return ret;
        }
 
@@ -2843,9 +2882,9 @@ qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha)
        if (!ha->fcp_prio_cfg) {
                ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE);
                if (!ha->fcp_prio_cfg) {
-                       qla_printk(KERN_WARNING, ha,
-                       "Unable to allocate memory for fcp priority data "
-                                       "(%x).\n", FCP_PRIO_CFG_SIZE);
+                       ql_log(ql_log_warn, vha, 0x00d5,
+                           "Unable to allocate memory for fcp priorty data (%x).\n",
+                           FCP_PRIO_CFG_SIZE);
                        return QLA_FUNCTION_FAILED;
                }
        }
@@ -2857,7 +2896,7 @@ qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha)
        ha->isp_ops->read_optrom(vha, (uint8_t *)ha->fcp_prio_cfg,
                        fcp_prio_addr << 2, FCP_PRIO_CFG_HDR_SIZE);
 
-       if (!qla24xx_fcp_prio_cfg_valid(ha->fcp_prio_cfg, 0))
+       if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 0))
                goto fail;
 
        /* read remaining FCP CMD config data from flash */
@@ -2869,7 +2908,7 @@ qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha)
                        fcp_prio_addr << 2, (len < max_len ? len : max_len));
 
        /* revalidate the entire FCP priority config data, including entries */
-       if (!qla24xx_fcp_prio_cfg_valid(ha->fcp_prio_cfg, 1))
+       if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 1))
                goto fail;
 
        ha->flags.fcp_prio_enabled = 1;
index 28d9c9d6b4b401f926eb62709efe9027e0d4cfaf..fc3f168decb4606cf479e5b6878236f9cfb5ca24 100644 (file)
@@ -137,6 +137,7 @@ static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy)
                host->host_blocked = host->max_host_blocked;
                break;
        case SCSI_MLQUEUE_DEVICE_BUSY:
+       case SCSI_MLQUEUE_EH_RETRY:
                device->device_blocked = device->max_device_blocked;
                break;
        case SCSI_MLQUEUE_TARGET_BUSY:
index 8a172d4f4564670c57450d06f484af6be0052827..5fbeadd9681977206f74f9315bd0a04815877a45 100644 (file)
@@ -597,6 +597,28 @@ static DEVICE_ATTR(signalling, S_IRUGO,
                   show_spi_host_signalling,
                   store_spi_host_signalling);
 
+static ssize_t show_spi_host_width(struct device *cdev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct Scsi_Host *shost = transport_class_to_shost(cdev);
+
+       return sprintf(buf, "%s\n", shost->max_id == 16 ? "wide" : "narrow");
+}
+static DEVICE_ATTR(host_width, S_IRUGO,
+                  show_spi_host_width, NULL);
+
+static ssize_t show_spi_host_hba_id(struct device *cdev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct Scsi_Host *shost = transport_class_to_shost(cdev);
+
+       return sprintf(buf, "%d\n", shost->this_id);
+}
+static DEVICE_ATTR(hba_id, S_IRUGO,
+                  show_spi_host_hba_id, NULL);
+
 #define DV_SET(x, y)                   \
        if(i->f->set_##x)               \
                i->f->set_##x(sdev->sdev_target, y)
@@ -1380,6 +1402,8 @@ static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class,
 
 static struct attribute *host_attributes[] = {
        &dev_attr_signalling.attr,
+       &dev_attr_host_width.attr,
+       &dev_attr_hba_id.attr,
        NULL
 };
 
index d6702e57d4285d150b2a94b6b94a6caf60652bc1..dc8d022c07a1505b2cc0bd86ccfb2e097c6f1f16 100644 (file)
@@ -34,6 +34,9 @@ static LIST_HEAD(clock_list);
 static DEFINE_SPINLOCK(clock_lock);
 static DEFINE_MUTEX(clock_list_sem);
 
+/* clock disable operations are not passed on to hardware during boot */
+static int allow_disable;
+
 void clk_rate_table_build(struct clk *clk,
                          struct cpufreq_frequency_table *freq_table,
                          int nr_freqs,
@@ -228,7 +231,7 @@ static void __clk_disable(struct clk *clk)
                return;
 
        if (!(--clk->usecount)) {
-               if (likely(clk->ops && clk->ops->disable))
+               if (likely(allow_disable && clk->ops && clk->ops->disable))
                        clk->ops->disable(clk);
                if (likely(clk->parent))
                        __clk_disable(clk->parent);
@@ -393,7 +396,7 @@ int clk_register(struct clk *clk)
 {
        int ret;
 
-       if (clk == NULL || IS_ERR(clk))
+       if (IS_ERR_OR_NULL(clk))
                return -EINVAL;
 
        /*
@@ -744,3 +747,25 @@ err_out:
        return err;
 }
 late_initcall(clk_debugfs_init);
+
+static int __init clk_late_init(void)
+{
+       unsigned long flags;
+       struct clk *clk;
+
+       /* disable all clocks with zero use count */
+       mutex_lock(&clock_list_sem);
+       spin_lock_irqsave(&clock_lock, flags);
+
+       list_for_each_entry(clk, &clock_list, node)
+               if (!clk->usecount && clk->ops && clk->ops->disable)
+                       clk->ops->disable(clk);
+
+       /* from now on allow clock disable operations */
+       allow_disable = 1;
+
+       spin_unlock_irqrestore(&clock_lock, flags);
+       mutex_unlock(&clock_list_sem);
+       return 0;
+}
+late_initcall(clk_late_init);
index 499b7a90e941a4e432537a9b325bd330cea93860..32ee39ad00df75b878af1d451acb296f6534a6dc 100644 (file)
@@ -6205,6 +6205,7 @@ int ar6000_create_ap_interface(struct ar6_softc *ar, char *ap_ifname)
     
     ether_setup(dev);
     init_netdev(dev, ap_ifname);
+    dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 
     if (register_netdev(dev)) {
         AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_create_ap_interface: register_netdev failed\n"));
index 5711e7c16b5043693a6177b12fec1a200b93191b..40e3d375ea993bb87d7cfea73ce1cb4cf1b987e1 100644 (file)
@@ -24,8 +24,6 @@
 #define BRCMS_SET_SHORTSLOT_OVERRIDE           146
 
 
-#include <linux/interrupt.h>
-
 /* BMAC Note: High-only driver is no longer working in softirq context as it needs to block and
  * sleep so perimeter lock has to be a semaphore instead of spinlock. This requires timers to be
  * submitted to workqueue instead of being on kernel timer
index 9d638c30735d299662168368959e832da76a559b..b48aefddc84c3a7e65dbac0ff53b6ff921160694 100644 (file)
@@ -1,9 +1,10 @@
 config DVB_CXD2099
-        tristate "CXD2099AR Common Interface driver"
-        depends on DVB_CORE && PCI && I2C && DVB_NGENE
-        ---help---
-          Support for the CI module found on cineS2 DVB-S2, supported by
-         the Micronas PCIe device driver (ngene).
+       tristate "CXD2099AR Common Interface driver"
+       depends on DVB_CORE && PCI && I2C
+       ---help---
+         Support for the CI module found on cards based on
+         - Micronas ngene PCIe bridge: cineS2 etc.
+         - Digital Devices PCIe bridge: Octopus series
 
          For now, data is passed through '/dev/dvb/adapterX/sec0':
            - Encrypted data must be written to 'sec0'.
index 55b1c4a59035ac9943db9079713100f3fbbf47fc..1c04185bcfd72d95bfe08a2b426fb9e1c1aaef6e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cxd2099.c: Driver for the CXD2099AR Common Interface Controller
  *
- * Copyright (C) 2010 DigitalDevices UG
+ * Copyright (C) 2010-2011 Digital Devices GmbH
  *
  *
  * This program is free software; you can redistribute it and/or
@@ -41,13 +41,13 @@ struct cxd {
        struct dvb_ca_en50221 en;
 
        struct i2c_adapter *i2c;
-       u8     adr;
+       struct cxd2099_cfg cfg;
+
        u8     regs[0x23];
        u8     lastaddress;
        u8     clk_reg_f;
        u8     clk_reg_b;
        int    mode;
-       u32    bitrate;
        int    ready;
        int    dr;
        int    slot_stat;
@@ -89,9 +89,9 @@ static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
                        u8 reg, u8 *val)
 {
        struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
-                                  .buf = &reg, .len = 1 },
+                                  .buf = &reg, .len = 1},
                                  {.addr = adr, .flags = I2C_M_RD,
-                                  .buf = val, .len = 1 } };
+                                  .buf = val, .len = 1} };
 
        if (i2c_transfer(adapter, msgs, 2) != 2) {
                printk(KERN_ERR "error in i2c_read_reg\n");
@@ -104,9 +104,9 @@ static int i2c_read(struct i2c_adapter *adapter, u8 adr,
                    u8 reg, u8 *data, u8 n)
 {
        struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
-                                  .buf = &reg, .len = 1 },
-                                 {.addr = adr, .flags = I2C_M_RD,
-                                  .buf = data, .len = n } };
+                                .buf = &reg, .len = 1},
+                               {.addr = adr, .flags = I2C_M_RD,
+                                .buf = data, .len = n} };
 
        if (i2c_transfer(adapter, msgs, 2) != 2) {
                printk(KERN_ERR "error in i2c_read\n");
@@ -119,10 +119,10 @@ static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n)
 {
        int status;
 
-       status = i2c_write_reg(ci->i2c, ci->adr, 0, adr);
+       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
        if (!status) {
                ci->lastaddress = adr;
-               status = i2c_read(ci->i2c, ci->adr, 1, data, n);
+               status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, n);
        }
        return status;
 }
@@ -136,24 +136,24 @@ static int read_reg(struct cxd *ci, u8 reg, u8 *val)
 static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
 {
        int status;
-       u8 addr[3] = { 2, address&0xff, address>>8 };
+       u8 addr[3] = {2, address & 0xff, address >> 8};
 
-       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
        if (!status)
-               status = i2c_read(ci->i2c, ci->adr, 3, data, n);
+               status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n);
        return status;
 }
 
 static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
 {
        int status;
-       u8 addr[3] = { 2, address&0xff, address>>8 };
+       u8 addr[3] = {2, address & 0xff, address >> 8};
 
-       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
        if (!status) {
                u8 buf[256] = {3};
                memcpy(buf+1, data, n);
-               status = i2c_write(ci->i2c, ci->adr, buf, n+1);
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n+1);
        }
        return status;
 }
@@ -161,39 +161,64 @@ static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n)
 static int read_io(struct cxd *ci, u16 address, u8 *val)
 {
        int status;
-       u8 addr[3] = { 2, address&0xff, address>>8 };
+       u8 addr[3] = {2, address & 0xff, address >> 8};
 
-       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
        if (!status)
-               status = i2c_read(ci->i2c, ci->adr, 3, val, 1);
+               status = i2c_read(ci->i2c, ci->cfg.adr, 3, val, 1);
        return status;
 }
 
 static int write_io(struct cxd *ci, u16 address, u8 val)
 {
        int status;
-       u8 addr[3] = { 2, address&0xff, address>>8 };
-       u8 buf[2] = { 3, val };
+       u8 addr[3] = {2, address & 0xff, address >> 8};
+       u8 buf[2] = {3, val};
 
-       status = i2c_write(ci->i2c, ci->adr, addr, 3);
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
        if (!status)
-               status = i2c_write(ci->i2c, ci->adr, buf, 2);
-
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, 2);
        return status;
 }
 
+#if 0
+static int read_io_data(struct cxd *ci, u8 *data, u8 n)
+{
+       int status;
+       u8 addr[3] = { 2, 0, 0 };
+
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+       if (!status)
+               status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n);
+       return 0;
+}
+
+static int write_io_data(struct cxd *ci, u8 *data, u8 n)
+{
+       int status;
+       u8 addr[3] = {2, 0, 0};
+
+       status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3);
+       if (!status) {
+               u8 buf[256] = {3};
+               memcpy(buf+1, data, n);
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
+       }
+       return 0;
+}
+#endif
 
 static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
 {
        int status;
 
-       status = i2c_write_reg(ci->i2c, ci->adr, 0, reg);
+       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
        if (!status && reg >= 6 && reg <= 8 && mask != 0xff)
-               status = i2c_read_reg(ci->i2c, ci->adr, 1, &ci->regs[reg]);
-       ci->regs[reg] = (ci->regs[reg]&(~mask))|val;
+               status = i2c_read_reg(ci->i2c, ci->cfg.adr, 1, &ci->regs[reg]);
+       ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;
        if (!status) {
                ci->lastaddress = reg;
-               status = i2c_write_reg(ci->i2c, ci->adr, 1, ci->regs[reg]);
+               status = i2c_write_reg(ci->i2c, ci->cfg.adr, 1, ci->regs[reg]);
        }
        if (reg == 0x20)
                ci->regs[reg] &= 0x7f;
@@ -211,11 +236,11 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, int n)
        int status;
        u8 buf[256] = {1};
 
-       status = i2c_write_reg(ci->i2c, ci->adr, 0, adr);
+       status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
        if (!status) {
                ci->lastaddress = adr;
-               memcpy(buf+1, data, n);
-               status = i2c_write(ci->i2c, ci->adr, buf, n+1);
+               memcpy(buf + 1, data, n);
+               status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
        }
        return status;
 }
@@ -249,12 +274,16 @@ static void cam_mode(struct cxd *ci, int mode)
                write_regm(ci, 0x20, 0x80, 0x80);
                break;
        case 0x01:
+#ifdef BUFFER_MODE
+               if (!ci->en.read_data)
+                       return;
                printk(KERN_INFO "enable cam buffer mode\n");
                /* write_reg(ci, 0x0d, 0x00); */
                /* write_reg(ci, 0x0e, 0x01); */
                write_regm(ci, 0x08, 0x40, 0x40);
                /* read_reg(ci, 0x12, &dummy); */
                write_regm(ci, 0x08, 0x80, 0x80);
+#endif
                break;
        default:
                break;
@@ -264,8 +293,6 @@ static void cam_mode(struct cxd *ci, int mode)
 
 
 
-#define CHK_ERROR(s) if ((status = s)) break
-
 static int init(struct cxd *ci)
 {
        int status;
@@ -273,63 +300,160 @@ static int init(struct cxd *ci)
        mutex_lock(&ci->lock);
        ci->mode = -1;
        do {
-               CHK_ERROR(write_reg(ci, 0x00, 0x00));
-               CHK_ERROR(write_reg(ci, 0x01, 0x00));
-               CHK_ERROR(write_reg(ci, 0x02, 0x10));
-               CHK_ERROR(write_reg(ci, 0x03, 0x00));
-               CHK_ERROR(write_reg(ci, 0x05, 0xFF));
-               CHK_ERROR(write_reg(ci, 0x06, 0x1F));
-               CHK_ERROR(write_reg(ci, 0x07, 0x1F));
-               CHK_ERROR(write_reg(ci, 0x08, 0x28));
-               CHK_ERROR(write_reg(ci, 0x14, 0x20));
-
-               CHK_ERROR(write_reg(ci, 0x09, 0x4D)); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */
-               CHK_ERROR(write_reg(ci, 0x0A, 0xA7)); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */
-
-               /* Sync detector */
-               CHK_ERROR(write_reg(ci, 0x0B, 0x33));
-               CHK_ERROR(write_reg(ci, 0x0C, 0x33));
-
-               CHK_ERROR(write_regm(ci, 0x14, 0x00, 0x0F));
-               CHK_ERROR(write_reg(ci, 0x15, ci->clk_reg_b));
-               CHK_ERROR(write_regm(ci, 0x16, 0x00, 0x0F));
-               CHK_ERROR(write_reg(ci, 0x17, ci->clk_reg_f));
-
-               CHK_ERROR(write_reg(ci, 0x20, 0x28)); /* Integer Divider, Falling Edge, Internal Sync, */
-               CHK_ERROR(write_reg(ci, 0x21, 0x00)); /* MCLKI = TICLK/8 */
-               CHK_ERROR(write_reg(ci, 0x22, 0x07)); /* MCLKI = TICLK/8 */
-
-
-               CHK_ERROR(write_regm(ci, 0x20, 0x80, 0x80)); /* Reset CAM state machine */
-
-               CHK_ERROR(write_regm(ci, 0x03, 0x02, 02));  /* Enable IREQA Interrupt */
-               CHK_ERROR(write_reg(ci, 0x01, 0x04));  /* Enable CD Interrupt */
-               CHK_ERROR(write_reg(ci, 0x00, 0x31));  /* Enable TS1,Hot Swap,Slot A */
-               CHK_ERROR(write_regm(ci, 0x09, 0x08, 0x08));  /* Put TS in bypass */
+               status = write_reg(ci, 0x00, 0x00);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x01, 0x00);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x02, 0x10);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x03, 0x00);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x05, 0xFF);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x06, 0x1F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x07, 0x1F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x08, 0x28);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x14, 0x20);
+               if (status < 0)
+                       break;
+
+#if 0
+               status = write_reg(ci, 0x09, 0x4D); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */
+               if (status < 0)
+                       break;
+#endif
+               status = write_reg(ci, 0x0A, 0xA7); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */
+               if (status < 0)
+                       break;
+
+               status = write_reg(ci, 0x0B, 0x33);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x0C, 0x33);
+               if (status < 0)
+                       break;
+
+               status = write_regm(ci, 0x14, 0x00, 0x0F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x15, ci->clk_reg_b);
+               if (status < 0)
+                       break;
+               status = write_regm(ci, 0x16, 0x00, 0x0F);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x17, ci->clk_reg_f);
+               if (status < 0)
+                       break;
+
+               if (ci->cfg.clock_mode) {
+                       if (ci->cfg.polarity) {
+                               status = write_reg(ci, 0x09, 0x6f);
+                               if (status < 0)
+                                       break;
+                       } else {
+                               status = write_reg(ci, 0x09, 0x6d);
+                               if (status < 0)
+                                       break;
+                       }
+                       status = write_reg(ci, 0x20, 0x68);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x21, 0x00);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x22, 0x02);
+                       if (status < 0)
+                               break;
+               } else {
+                       if (ci->cfg.polarity) {
+                               status = write_reg(ci, 0x09, 0x4f);
+                               if (status < 0)
+                                       break;
+                       } else {
+                               status = write_reg(ci, 0x09, 0x4d);
+                               if (status < 0)
+                                       break;
+                       }
+
+                       status = write_reg(ci, 0x20, 0x28);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x21, 0x00);
+                       if (status < 0)
+                               break;
+                       status = write_reg(ci, 0x22, 0x07);
+                       if (status < 0)
+                               break;
+               }
+
+               status = write_regm(ci, 0x20, 0x80, 0x80);
+               if (status < 0)
+                       break;
+               status = write_regm(ci, 0x03, 0x02, 0x02);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x01, 0x04);
+               if (status < 0)
+                       break;
+               status = write_reg(ci, 0x00, 0x31);
+               if (status < 0)
+                       break;
+
+               /* Put TS in bypass */
+               status = write_regm(ci, 0x09, 0x08, 0x08);
+               if (status < 0)
+                       break;
                ci->cammode = -1;
-#ifdef BUFFER_MODE
                cam_mode(ci, 0);
-#endif
        } while (0);
        mutex_unlock(&ci->lock);
 
        return 0;
 }
 
-
 static int read_attribute_mem(struct dvb_ca_en50221 *ca,
                              int slot, int address)
 {
        struct cxd *ci = ca->data;
+#if 0
+       if (ci->amem_read) {
+               if (address <= 0 || address > 1024)
+                       return -EIO;
+               return ci->amem[address];
+       }
+
+       mutex_lock(&ci->lock);
+       write_regm(ci, 0x06, 0x00, 0x05);
+       read_pccard(ci, 0, &ci->amem[0], 128);
+       read_pccard(ci, 128, &ci->amem[0], 128);
+       read_pccard(ci, 256, &ci->amem[0], 128);
+       read_pccard(ci, 384, &ci->amem[0], 128);
+       write_regm(ci, 0x06, 0x05, 0x05);
+       mutex_unlock(&ci->lock);
+       return ci->amem[address];
+#else
        u8 val;
        mutex_lock(&ci->lock);
        set_mode(ci, 1);
        read_pccard(ci, address, &val, 1);
        mutex_unlock(&ci->lock);
+       /* printk(KERN_INFO "%02x:%02x\n", address,val); */
        return val;
+#endif
 }
 
-
 static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
                               int address, u8 value)
 {
@@ -372,6 +496,15 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
        struct cxd *ci = ca->data;
 
        mutex_lock(&ci->lock);
+#if 0
+       write_reg(ci, 0x00, 0x21);
+       write_reg(ci, 0x06, 0x1F);
+       write_reg(ci, 0x00, 0x31);
+#else
+#if 0
+       write_reg(ci, 0x06, 0x1F);
+       write_reg(ci, 0x06, 0x2F);
+#else
        cam_mode(ci, 0);
        write_reg(ci, 0x00, 0x21);
        write_reg(ci, 0x06, 0x1F);
@@ -379,13 +512,25 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
        write_regm(ci, 0x20, 0x80, 0x80);
        write_reg(ci, 0x03, 0x02);
        ci->ready = 0;
+#endif
+#endif
        ci->mode = -1;
        {
                int i;
+#if 0
+               u8 val;
+#endif
                for (i = 0; i < 100; i++) {
                        msleep(10);
+#if 0
+                       read_reg(ci, 0x06, &val);
+                       printk(KERN_INFO "%d:%02x\n", i, val);
+                       if (!(val&0x10))
+                               break;
+#else
                        if (ci->ready)
                                break;
+#endif
                }
        }
        mutex_unlock(&ci->lock);
@@ -399,12 +544,12 @@ static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
 
        printk(KERN_INFO "slot_shutdown\n");
        mutex_lock(&ci->lock);
-       /* write_regm(ci, 0x09, 0x08, 0x08); */
-       write_regm(ci, 0x20, 0x80, 0x80);
-       write_regm(ci, 0x06, 0x07, 0x07);
+       write_regm(ci, 0x09, 0x08, 0x08);
+       write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */
+       write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */
        ci->mode = -1;
        mutex_unlock(&ci->lock);
-       return 0; /* shutdown(ci); */
+       return 0;
 }
 
 static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
@@ -459,7 +604,6 @@ static int campoll(struct cxd *ci)
                if (istat&8 && ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
                        ci->ready = 1;
                        ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
-                       printk(KERN_INFO "READY\n");
                }
        }
        return 0;
@@ -510,7 +654,7 @@ static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
        struct cxd *ci = ca->data;
 
        mutex_lock(&ci->lock);
-       printk(KERN_INFO "write_data %d\n", ecount);
+       printk(kern_INFO "write_data %d\n", ecount);
        write_reg(ci, 0x0d, ecount>>8);
        write_reg(ci, 0x0e, ecount&0xff);
        write_block(ci, 0x11, ebuf, ecount);
@@ -535,15 +679,15 @@ static struct dvb_ca_en50221 en_templ = {
 
 };
 
-struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv,
+struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
+                                     void *priv,
                                      struct i2c_adapter *i2c)
 {
        struct cxd *ci = 0;
-       u32 bitrate = 62000000;
        u8 val;
 
-       if (i2c_read_reg(i2c, adr, 0, &val) < 0) {
-               printk(KERN_ERR "No CXD2099 detected at %02x\n", adr);
+       if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
+               printk(KERN_INFO "No CXD2099 detected at %02x\n", cfg->adr);
                return 0;
        }
 
@@ -553,21 +697,20 @@ struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv,
        memset(ci, 0, sizeof(*ci));
 
        mutex_init(&ci->lock);
+       memcpy(&ci->cfg, cfg, sizeof(struct cxd2099_cfg));
        ci->i2c = i2c;
-       ci->adr = adr;
        ci->lastaddress = 0xff;
        ci->clk_reg_b = 0x4a;
        ci->clk_reg_f = 0x1b;
-       ci->bitrate = bitrate;
 
        memcpy(&ci->en, &en_templ, sizeof(en_templ));
        ci->en.data = ci;
        init(ci);
-       printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->adr);
+       printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->cfg.adr);
        return &ci->en;
 }
 EXPORT_SYMBOL(cxd2099_attach);
 
 MODULE_DESCRIPTION("cxd2099");
-MODULE_AUTHOR("Ralph Metzler <rjkm@metzlerbros.de>");
+MODULE_AUTHOR("Ralph Metzler");
 MODULE_LICENSE("GPL");
index bed54ff3e30be713211ef89b6bc9316f515f870e..19c588a595883be93f0cef4102e647fdbaa21e71 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cxd2099.h: Driver for the CXD2099AR Common Interface Controller
  *
- * Copyright (C) 2010 DigitalDevices UG
+ * Copyright (C) 2010-2011 Digital Devices GmbH
  *
  *
  * This program is free software; you can redistribute it and/or
 
 #include <dvb_ca_en50221.h>
 
+struct cxd2099_cfg {
+       u32 bitrate;
+       u8  adr;
+       u8  polarity:1;
+       u8  clock_mode:1;
+};
+
 #if defined(CONFIG_DVB_CXD2099) || \
-        (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE))
-struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c);
+       (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE))
+struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
+                                     void *priv, struct i2c_adapter *i2c);
 #else
-static inline struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c)
+
+static inline struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
+                                       void *priv, struct i2c_adapter *i2c)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return NULL;
index ddfd7c33361ba31ba64fb1a4ef3a4a79b5b1c260..bd5fa89af07c32814ea55f28c0075dad7747cdad 100644 (file)
@@ -84,7 +84,6 @@ static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
 
        tm6000_set_audio_bitrate(core, 48000);
 
-
        return 0;
 }
 
@@ -123,6 +122,7 @@ static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
        if (substream->runtime->dma_area) {
                if (substream->runtime->dma_bytes > size)
                        return 0;
+
                dsp_buffer_free(substream);
        }
 
@@ -152,9 +152,9 @@ static struct snd_pcm_hardware snd_tm6000_digital_hw = {
                SNDRV_PCM_INFO_MMAP_VALID,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 
-       .rates =                SNDRV_PCM_RATE_CONTINUOUS,
-       .rate_min =             48000,
-       .rate_max =             48000,
+       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+       .rate_min = 48000,
+       .rate_max = 48000,
        .channels_min = 2,
        .channels_max = 2,
        .period_bytes_min = 64,
@@ -254,9 +254,7 @@ static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
                memcpy(runtime->dma_area + buf_pos * stride, buf,
                        length * stride);
 
-#ifndef NO_PCM_LOCK
        snd_pcm_stream_lock(substream);
-#endif
 
        chip->buf_pos += length;
        if (chip->buf_pos >= runtime->buffer_size)
@@ -268,9 +266,7 @@ static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
                period_elapsed = 1;
        }
 
-#ifndef NO_PCM_LOCK
        snd_pcm_stream_unlock(substream);
-#endif
 
        if (period_elapsed)
                snd_pcm_period_elapsed(substream);
index 5cb0f0ef6af0e5cb00249185d3c58aca04d0fffc..b28794b7212531a88e7002e5a6584c291dfd9543 100644 (file)
@@ -31,5 +31,6 @@ config TCM_PSCSI
 
 source "drivers/target/loopback/Kconfig"
 source "drivers/target/tcm_fc/Kconfig"
+source "drivers/target/iscsi/Kconfig"
 
 endif
index 21df808a992c1d45e95ddfd5135b54d86785a798..1060c7b7f803d5b2d99cb8396b9e2167af3360db 100644 (file)
@@ -24,5 +24,5 @@ obj-$(CONFIG_TCM_PSCSI)               += target_core_pscsi.o
 
 # Fabric modules
 obj-$(CONFIG_LOOPBACK_TARGET)  += loopback/
-
 obj-$(CONFIG_TCM_FC)           += tcm_fc/
+obj-$(CONFIG_ISCSI_TARGET)     += iscsi/
diff --git a/drivers/target/iscsi/Kconfig b/drivers/target/iscsi/Kconfig
new file mode 100644 (file)
index 0000000..564ff4e
--- /dev/null
@@ -0,0 +1,8 @@
+config ISCSI_TARGET
+       tristate "Linux-iSCSI.org iSCSI Target Mode Stack"
+       select CRYPTO
+       select CRYPTO_CRC32C
+       select CRYPTO_CRC32C_INTEL if X86
+       help
+       Say M here to enable the ConfigFS enabled Linux-iSCSI.org iSCSI
+       Target Mode Stack.
diff --git a/drivers/target/iscsi/Makefile b/drivers/target/iscsi/Makefile
new file mode 100644 (file)
index 0000000..5b9a2cf
--- /dev/null
@@ -0,0 +1,20 @@
+iscsi_target_mod-y +=          iscsi_target_parameters.o \
+                               iscsi_target_seq_pdu_list.o \
+                               iscsi_target_tq.o \
+                               iscsi_target_auth.o \
+                               iscsi_target_datain_values.o \
+                               iscsi_target_device.o \
+                               iscsi_target_erl0.o \
+                               iscsi_target_erl1.o \
+                               iscsi_target_erl2.o \
+                               iscsi_target_login.o \
+                               iscsi_target_nego.o \
+                               iscsi_target_nodeattrib.o \
+                               iscsi_target_tmr.o \
+                               iscsi_target_tpg.o \
+                               iscsi_target_util.o \
+                               iscsi_target.o \
+                               iscsi_target_configfs.o \
+                               iscsi_target_stat.o
+
+obj-$(CONFIG_ISCSI_TARGET)     += iscsi_target_mod.o
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
new file mode 100644 (file)
index 0000000..14c81c4
--- /dev/null
@@ -0,0 +1,4559 @@
+/*******************************************************************************
+ * This file contains main functions related to the iSCSI Target Core Driver.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <linux/string.h>
+#include <linux/kthread.h>
+#include <linux/crypto.h>
+#include <linux/completion.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi_device.h>
+#include <scsi/iscsi_proto.h>
+#include <target/target_core_base.h>
+#include <target/target_core_tmr.h>
+#include <target/target_core_transport.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_parameters.h"
+#include "iscsi_target_seq_pdu_list.h"
+#include "iscsi_target_tq.h"
+#include "iscsi_target_configfs.h"
+#include "iscsi_target_datain_values.h"
+#include "iscsi_target_erl0.h"
+#include "iscsi_target_erl1.h"
+#include "iscsi_target_erl2.h"
+#include "iscsi_target_login.h"
+#include "iscsi_target_tmr.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target.h"
+#include "iscsi_target_device.h"
+#include "iscsi_target_stat.h"
+
+static LIST_HEAD(g_tiqn_list);
+static LIST_HEAD(g_np_list);
+static DEFINE_SPINLOCK(tiqn_lock);
+static DEFINE_SPINLOCK(np_lock);
+
+static struct idr tiqn_idr;
+struct idr sess_idr;
+struct mutex auth_id_lock;
+spinlock_t sess_idr_lock;
+
+struct iscsit_global *iscsit_global;
+
+struct kmem_cache *lio_cmd_cache;
+struct kmem_cache *lio_qr_cache;
+struct kmem_cache *lio_dr_cache;
+struct kmem_cache *lio_ooo_cache;
+struct kmem_cache *lio_r2t_cache;
+
+static int iscsit_handle_immediate_data(struct iscsi_cmd *,
+                       unsigned char *buf, u32);
+static int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
+
+struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *buf)
+{
+       struct iscsi_tiqn *tiqn = NULL;
+
+       spin_lock(&tiqn_lock);
+       list_for_each_entry(tiqn, &g_tiqn_list, tiqn_list) {
+               if (!strcmp(tiqn->tiqn, buf)) {
+
+                       spin_lock(&tiqn->tiqn_state_lock);
+                       if (tiqn->tiqn_state == TIQN_STATE_ACTIVE) {
+                               tiqn->tiqn_access_count++;
+                               spin_unlock(&tiqn->tiqn_state_lock);
+                               spin_unlock(&tiqn_lock);
+                               return tiqn;
+                       }
+                       spin_unlock(&tiqn->tiqn_state_lock);
+               }
+       }
+       spin_unlock(&tiqn_lock);
+
+       return NULL;
+}
+
+static int iscsit_set_tiqn_shutdown(struct iscsi_tiqn *tiqn)
+{
+       spin_lock(&tiqn->tiqn_state_lock);
+       if (tiqn->tiqn_state == TIQN_STATE_ACTIVE) {
+               tiqn->tiqn_state = TIQN_STATE_SHUTDOWN;
+               spin_unlock(&tiqn->tiqn_state_lock);
+               return 0;
+       }
+       spin_unlock(&tiqn->tiqn_state_lock);
+
+       return -1;
+}
+
+void iscsit_put_tiqn_for_login(struct iscsi_tiqn *tiqn)
+{
+       spin_lock(&tiqn->tiqn_state_lock);
+       tiqn->tiqn_access_count--;
+       spin_unlock(&tiqn->tiqn_state_lock);
+}
+
+/*
+ * Note that IQN formatting is expected to be done in userspace, and
+ * no explict IQN format checks are done here.
+ */
+struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf)
+{
+       struct iscsi_tiqn *tiqn = NULL;
+       int ret;
+
+       if (strlen(buf) > ISCSI_IQN_LEN) {
+               pr_err("Target IQN exceeds %d bytes\n",
+                               ISCSI_IQN_LEN);
+               return ERR_PTR(-EINVAL);
+       }
+
+       tiqn = kzalloc(sizeof(struct iscsi_tiqn), GFP_KERNEL);
+       if (!tiqn) {
+               pr_err("Unable to allocate struct iscsi_tiqn\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       sprintf(tiqn->tiqn, "%s", buf);
+       INIT_LIST_HEAD(&tiqn->tiqn_list);
+       INIT_LIST_HEAD(&tiqn->tiqn_tpg_list);
+       spin_lock_init(&tiqn->tiqn_state_lock);
+       spin_lock_init(&tiqn->tiqn_tpg_lock);
+       spin_lock_init(&tiqn->sess_err_stats.lock);
+       spin_lock_init(&tiqn->login_stats.lock);
+       spin_lock_init(&tiqn->logout_stats.lock);
+
+       if (!idr_pre_get(&tiqn_idr, GFP_KERNEL)) {
+               pr_err("idr_pre_get() for tiqn_idr failed\n");
+               kfree(tiqn);
+               return ERR_PTR(-ENOMEM);
+       }
+       tiqn->tiqn_state = TIQN_STATE_ACTIVE;
+
+       spin_lock(&tiqn_lock);
+       ret = idr_get_new(&tiqn_idr, NULL, &tiqn->tiqn_index);
+       if (ret < 0) {
+               pr_err("idr_get_new() failed for tiqn->tiqn_index\n");
+               spin_unlock(&tiqn_lock);
+               kfree(tiqn);
+               return ERR_PTR(ret);
+       }
+       list_add_tail(&tiqn->tiqn_list, &g_tiqn_list);
+       spin_unlock(&tiqn_lock);
+
+       pr_debug("CORE[0] - Added iSCSI Target IQN: %s\n", tiqn->tiqn);
+
+       return tiqn;
+
+}
+
+static void iscsit_wait_for_tiqn(struct iscsi_tiqn *tiqn)
+{
+       /*
+        * Wait for accesses to said struct iscsi_tiqn to end.
+        */
+       spin_lock(&tiqn->tiqn_state_lock);
+       while (tiqn->tiqn_access_count != 0) {
+               spin_unlock(&tiqn->tiqn_state_lock);
+               msleep(10);
+               spin_lock(&tiqn->tiqn_state_lock);
+       }
+       spin_unlock(&tiqn->tiqn_state_lock);
+}
+
+void iscsit_del_tiqn(struct iscsi_tiqn *tiqn)
+{
+       /*
+        * iscsit_set_tiqn_shutdown sets tiqn->tiqn_state = TIQN_STATE_SHUTDOWN
+        * while holding tiqn->tiqn_state_lock.  This means that all subsequent
+        * attempts to access this struct iscsi_tiqn will fail from both transport
+        * fabric and control code paths.
+        */
+       if (iscsit_set_tiqn_shutdown(tiqn) < 0) {
+               pr_err("iscsit_set_tiqn_shutdown() failed\n");
+               return;
+       }
+
+       iscsit_wait_for_tiqn(tiqn);
+
+       spin_lock(&tiqn_lock);
+       list_del(&tiqn->tiqn_list);
+       idr_remove(&tiqn_idr, tiqn->tiqn_index);
+       spin_unlock(&tiqn_lock);
+
+       pr_debug("CORE[0] - Deleted iSCSI Target IQN: %s\n",
+                       tiqn->tiqn);
+       kfree(tiqn);
+}
+
+int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
+{
+       int ret;
+       /*
+        * Determine if the network portal is accepting storage traffic.
+        */
+       spin_lock_bh(&np->np_thread_lock);
+       if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
+               spin_unlock_bh(&np->np_thread_lock);
+               return -1;
+       }
+       if (np->np_login_tpg) {
+               pr_err("np->np_login_tpg() is not NULL!\n");
+               spin_unlock_bh(&np->np_thread_lock);
+               return -1;
+       }
+       spin_unlock_bh(&np->np_thread_lock);
+       /*
+        * Determine if the portal group is accepting storage traffic.
+        */
+       spin_lock_bh(&tpg->tpg_state_lock);
+       if (tpg->tpg_state != TPG_STATE_ACTIVE) {
+               spin_unlock_bh(&tpg->tpg_state_lock);
+               return -1;
+       }
+       spin_unlock_bh(&tpg->tpg_state_lock);
+
+       /*
+        * Here we serialize access across the TIQN+TPG Tuple.
+        */
+       ret = mutex_lock_interruptible(&tpg->np_login_lock);
+       if ((ret != 0) || signal_pending(current))
+               return -1;
+
+       spin_lock_bh(&np->np_thread_lock);
+       np->np_login_tpg = tpg;
+       spin_unlock_bh(&np->np_thread_lock);
+
+       return 0;
+}
+
+int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
+{
+       struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
+
+       spin_lock_bh(&np->np_thread_lock);
+       np->np_login_tpg = NULL;
+       spin_unlock_bh(&np->np_thread_lock);
+
+       mutex_unlock(&tpg->np_login_lock);
+
+       if (tiqn)
+               iscsit_put_tiqn_for_login(tiqn);
+
+       return 0;
+}
+
+static struct iscsi_np *iscsit_get_np(
+       struct __kernel_sockaddr_storage *sockaddr,
+       int network_transport)
+{
+       struct sockaddr_in *sock_in, *sock_in_e;
+       struct sockaddr_in6 *sock_in6, *sock_in6_e;
+       struct iscsi_np *np;
+       int ip_match = 0;
+       u16 port;
+
+       spin_lock_bh(&np_lock);
+       list_for_each_entry(np, &g_np_list, np_list) {
+               spin_lock(&np->np_thread_lock);
+               if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
+                       spin_unlock(&np->np_thread_lock);
+                       continue;
+               }
+
+               if (sockaddr->ss_family == AF_INET6) {
+                       sock_in6 = (struct sockaddr_in6 *)sockaddr;
+                       sock_in6_e = (struct sockaddr_in6 *)&np->np_sockaddr;
+
+                       if (!memcmp((void *)&sock_in6->sin6_addr.in6_u,
+                                   (void *)&sock_in6_e->sin6_addr.in6_u,
+                                   sizeof(struct in6_addr)))
+                               ip_match = 1;
+
+                       port = ntohs(sock_in6->sin6_port);
+               } else {
+                       sock_in = (struct sockaddr_in *)sockaddr;
+                       sock_in_e = (struct sockaddr_in *)&np->np_sockaddr;
+
+                       if (sock_in->sin_addr.s_addr ==
+                           sock_in_e->sin_addr.s_addr)
+                               ip_match = 1;
+
+                       port = ntohs(sock_in->sin_port);
+               }
+
+               if ((ip_match == 1) && (np->np_port == port) &&
+                   (np->np_network_transport == network_transport)) {
+                       /*
+                        * Increment the np_exports reference count now to
+                        * prevent iscsit_del_np() below from being called
+                        * while iscsi_tpg_add_network_portal() is called.
+                        */
+                       np->np_exports++;
+                       spin_unlock(&np->np_thread_lock);
+                       spin_unlock_bh(&np_lock);
+                       return np;
+               }
+               spin_unlock(&np->np_thread_lock);
+       }
+       spin_unlock_bh(&np_lock);
+
+       return NULL;
+}
+
+struct iscsi_np *iscsit_add_np(
+       struct __kernel_sockaddr_storage *sockaddr,
+       char *ip_str,
+       int network_transport)
+{
+       struct sockaddr_in *sock_in;
+       struct sockaddr_in6 *sock_in6;
+       struct iscsi_np *np;
+       int ret;
+       /*
+        * Locate the existing struct iscsi_np if already active..
+        */
+       np = iscsit_get_np(sockaddr, network_transport);
+       if (np)
+               return np;
+
+       np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL);
+       if (!np) {
+               pr_err("Unable to allocate memory for struct iscsi_np\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       np->np_flags |= NPF_IP_NETWORK;
+       if (sockaddr->ss_family == AF_INET6) {
+               sock_in6 = (struct sockaddr_in6 *)sockaddr;
+               snprintf(np->np_ip, IPV6_ADDRESS_SPACE, "%s", ip_str);
+               np->np_port = ntohs(sock_in6->sin6_port);
+       } else {
+               sock_in = (struct sockaddr_in *)sockaddr;
+               sprintf(np->np_ip, "%s", ip_str);
+               np->np_port = ntohs(sock_in->sin_port);
+       }
+
+       np->np_network_transport = network_transport;
+       spin_lock_init(&np->np_thread_lock);
+       init_completion(&np->np_restart_comp);
+       INIT_LIST_HEAD(&np->np_list);
+
+       ret = iscsi_target_setup_login_socket(np, sockaddr);
+       if (ret != 0) {
+               kfree(np);
+               return ERR_PTR(ret);
+       }
+
+       np->np_thread = kthread_run(iscsi_target_login_thread, np, "iscsi_np");
+       if (IS_ERR(np->np_thread)) {
+               pr_err("Unable to create kthread: iscsi_np\n");
+               ret = PTR_ERR(np->np_thread);
+               kfree(np);
+               return ERR_PTR(ret);
+       }
+       /*
+        * Increment the np_exports reference count now to prevent
+        * iscsit_del_np() below from being run while a new call to
+        * iscsi_tpg_add_network_portal() for a matching iscsi_np is
+        * active.  We don't need to hold np->np_thread_lock at this
+        * point because iscsi_np has not been added to g_np_list yet.
+        */
+       np->np_exports = 1;
+
+       spin_lock_bh(&np_lock);
+       list_add_tail(&np->np_list, &g_np_list);
+       spin_unlock_bh(&np_lock);
+
+       pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
+               np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
+               "TCP" : "SCTP");
+
+       return np;
+}
+
+int iscsit_reset_np_thread(
+       struct iscsi_np *np,
+       struct iscsi_tpg_np *tpg_np,
+       struct iscsi_portal_group *tpg)
+{
+       spin_lock_bh(&np->np_thread_lock);
+       if (tpg && tpg_np) {
+               /*
+                * The reset operation need only be performed when the
+                * passed struct iscsi_portal_group has a login in progress
+                * to one of the network portals.
+                */
+               if (tpg_np->tpg_np->np_login_tpg != tpg) {
+                       spin_unlock_bh(&np->np_thread_lock);
+                       return 0;
+               }
+       }
+       if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) {
+               spin_unlock_bh(&np->np_thread_lock);
+               return 0;
+       }
+       np->np_thread_state = ISCSI_NP_THREAD_RESET;
+
+       if (np->np_thread) {
+               spin_unlock_bh(&np->np_thread_lock);
+               send_sig(SIGINT, np->np_thread, 1);
+               wait_for_completion(&np->np_restart_comp);
+               spin_lock_bh(&np->np_thread_lock);
+       }
+       spin_unlock_bh(&np->np_thread_lock);
+
+       return 0;
+}
+
+int iscsit_del_np_comm(struct iscsi_np *np)
+{
+       if (!np->np_socket)
+               return 0;
+
+       /*
+        * Some network transports allocate their own struct sock->file,
+        * see  if we need to free any additional allocated resources.
+        */
+       if (np->np_flags & NPF_SCTP_STRUCT_FILE) {
+               kfree(np->np_socket->file);
+               np->np_socket->file = NULL;
+       }
+
+       sock_release(np->np_socket);
+       return 0;
+}
+
+int iscsit_del_np(struct iscsi_np *np)
+{
+       spin_lock_bh(&np->np_thread_lock);
+       np->np_exports--;
+       if (np->np_exports) {
+               spin_unlock_bh(&np->np_thread_lock);
+               return 0;
+       }
+       np->np_thread_state = ISCSI_NP_THREAD_SHUTDOWN;
+       spin_unlock_bh(&np->np_thread_lock);
+
+       if (np->np_thread) {
+               /*
+                * We need to send the signal to wakeup Linux/Net
+                * which may be sleeping in sock_accept()..
+                */
+               send_sig(SIGINT, np->np_thread, 1);
+               kthread_stop(np->np_thread);
+       }
+       iscsit_del_np_comm(np);
+
+       spin_lock_bh(&np_lock);
+       list_del(&np->np_list);
+       spin_unlock_bh(&np_lock);
+
+       pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
+               np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
+               "TCP" : "SCTP");
+
+       kfree(np);
+       return 0;
+}
+
+static int __init iscsi_target_init_module(void)
+{
+       int ret = 0;
+
+       pr_debug("iSCSI-Target "ISCSIT_VERSION"\n");
+
+       iscsit_global = kzalloc(sizeof(struct iscsit_global), GFP_KERNEL);
+       if (!iscsit_global) {
+               pr_err("Unable to allocate memory for iscsit_global\n");
+               return -1;
+       }
+       mutex_init(&auth_id_lock);
+       spin_lock_init(&sess_idr_lock);
+       idr_init(&tiqn_idr);
+       idr_init(&sess_idr);
+
+       ret = iscsi_target_register_configfs();
+       if (ret < 0)
+               goto out;
+
+       ret = iscsi_thread_set_init();
+       if (ret < 0)
+               goto configfs_out;
+
+       if (iscsi_allocate_thread_sets(TARGET_THREAD_SET_COUNT) !=
+                       TARGET_THREAD_SET_COUNT) {
+               pr_err("iscsi_allocate_thread_sets() returned"
+                       " unexpected value!\n");
+               goto ts_out1;
+       }
+
+       lio_cmd_cache = kmem_cache_create("lio_cmd_cache",
+                       sizeof(struct iscsi_cmd), __alignof__(struct iscsi_cmd),
+                       0, NULL);
+       if (!lio_cmd_cache) {
+               pr_err("Unable to kmem_cache_create() for"
+                               " lio_cmd_cache\n");
+               goto ts_out2;
+       }
+
+       lio_qr_cache = kmem_cache_create("lio_qr_cache",
+                       sizeof(struct iscsi_queue_req),
+                       __alignof__(struct iscsi_queue_req), 0, NULL);
+       if (!lio_qr_cache) {
+               pr_err("nable to kmem_cache_create() for"
+                               " lio_qr_cache\n");
+               goto cmd_out;
+       }
+
+       lio_dr_cache = kmem_cache_create("lio_dr_cache",
+                       sizeof(struct iscsi_datain_req),
+                       __alignof__(struct iscsi_datain_req), 0, NULL);
+       if (!lio_dr_cache) {
+               pr_err("Unable to kmem_cache_create() for"
+                               " lio_dr_cache\n");
+               goto qr_out;
+       }
+
+       lio_ooo_cache = kmem_cache_create("lio_ooo_cache",
+                       sizeof(struct iscsi_ooo_cmdsn),
+                       __alignof__(struct iscsi_ooo_cmdsn), 0, NULL);
+       if (!lio_ooo_cache) {
+               pr_err("Unable to kmem_cache_create() for"
+                               " lio_ooo_cache\n");
+               goto dr_out;
+       }
+
+       lio_r2t_cache = kmem_cache_create("lio_r2t_cache",
+                       sizeof(struct iscsi_r2t), __alignof__(struct iscsi_r2t),
+                       0, NULL);
+       if (!lio_r2t_cache) {
+               pr_err("Unable to kmem_cache_create() for"
+                               " lio_r2t_cache\n");
+               goto ooo_out;
+       }
+
+       if (iscsit_load_discovery_tpg() < 0)
+               goto r2t_out;
+
+       return ret;
+r2t_out:
+       kmem_cache_destroy(lio_r2t_cache);
+ooo_out:
+       kmem_cache_destroy(lio_ooo_cache);
+dr_out:
+       kmem_cache_destroy(lio_dr_cache);
+qr_out:
+       kmem_cache_destroy(lio_qr_cache);
+cmd_out:
+       kmem_cache_destroy(lio_cmd_cache);
+ts_out2:
+       iscsi_deallocate_thread_sets();
+ts_out1:
+       iscsi_thread_set_free();
+configfs_out:
+       iscsi_target_deregister_configfs();
+out:
+       kfree(iscsit_global);
+       return -ENOMEM;
+}
+
+static void __exit iscsi_target_cleanup_module(void)
+{
+       iscsi_deallocate_thread_sets();
+       iscsi_thread_set_free();
+       iscsit_release_discovery_tpg();
+       kmem_cache_destroy(lio_cmd_cache);
+       kmem_cache_destroy(lio_qr_cache);
+       kmem_cache_destroy(lio_dr_cache);
+       kmem_cache_destroy(lio_ooo_cache);
+       kmem_cache_destroy(lio_r2t_cache);
+
+       iscsi_target_deregister_configfs();
+
+       kfree(iscsit_global);
+}
+
+int iscsit_add_reject(
+       u8 reason,
+       int fail_conn,
+       unsigned char *buf,
+       struct iscsi_conn *conn)
+{
+       struct iscsi_cmd *cmd;
+       struct iscsi_reject *hdr;
+       int ret;
+
+       cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+       if (!cmd)
+               return -1;
+
+       cmd->iscsi_opcode = ISCSI_OP_REJECT;
+       if (fail_conn)
+               cmd->cmd_flags |= ICF_REJECT_FAIL_CONN;
+
+       hdr     = (struct iscsi_reject *) cmd->pdu;
+       hdr->reason = reason;
+
+       cmd->buf_ptr = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
+       if (!cmd->buf_ptr) {
+               pr_err("Unable to allocate memory for cmd->buf_ptr\n");
+               iscsit_release_cmd(cmd);
+               return -1;
+       }
+       memcpy(cmd->buf_ptr, buf, ISCSI_HDR_LEN);
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+       spin_unlock_bh(&conn->cmd_lock);
+
+       cmd->i_state = ISTATE_SEND_REJECT;
+       iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+
+       ret = wait_for_completion_interruptible(&cmd->reject_comp);
+       if (ret != 0)
+               return -1;
+
+       return (!fail_conn) ? 0 : -1;
+}
+
+int iscsit_add_reject_from_cmd(
+       u8 reason,
+       int fail_conn,
+       int add_to_conn,
+       unsigned char *buf,
+       struct iscsi_cmd *cmd)
+{
+       struct iscsi_conn *conn;
+       struct iscsi_reject *hdr;
+       int ret;
+
+       if (!cmd->conn) {
+               pr_err("cmd->conn is NULL for ITT: 0x%08x\n",
+                               cmd->init_task_tag);
+               return -1;
+       }
+       conn = cmd->conn;
+
+       cmd->iscsi_opcode = ISCSI_OP_REJECT;
+       if (fail_conn)
+               cmd->cmd_flags |= ICF_REJECT_FAIL_CONN;
+
+       hdr     = (struct iscsi_reject *) cmd->pdu;
+       hdr->reason = reason;
+
+       cmd->buf_ptr = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
+       if (!cmd->buf_ptr) {
+               pr_err("Unable to allocate memory for cmd->buf_ptr\n");
+               iscsit_release_cmd(cmd);
+               return -1;
+       }
+       memcpy(cmd->buf_ptr, buf, ISCSI_HDR_LEN);
+
+       if (add_to_conn) {
+               spin_lock_bh(&conn->cmd_lock);
+               list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+               spin_unlock_bh(&conn->cmd_lock);
+       }
+
+       cmd->i_state = ISTATE_SEND_REJECT;
+       iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+
+       ret = wait_for_completion_interruptible(&cmd->reject_comp);
+       if (ret != 0)
+               return -1;
+
+       return (!fail_conn) ? 0 : -1;
+}
+
+/*
+ * Map some portion of the allocated scatterlist to an iovec, suitable for
+ * kernel sockets to copy data in/out. This handles both pages and slab-allocated
+ * buffers, since we have been tricky and mapped t_mem_sg to the buffer in
+ * either case (see iscsit_alloc_buffs)
+ */
+static int iscsit_map_iovec(
+       struct iscsi_cmd *cmd,
+       struct kvec *iov,
+       u32 data_offset,
+       u32 data_length)
+{
+       u32 i = 0;
+       struct scatterlist *sg;
+       unsigned int page_off;
+
+       /*
+        * We have a private mapping of the allocated pages in t_mem_sg.
+        * At this point, we also know each contains a page.
+        */
+       sg = &cmd->t_mem_sg[data_offset / PAGE_SIZE];
+       page_off = (data_offset % PAGE_SIZE);
+
+       cmd->first_data_sg = sg;
+       cmd->first_data_sg_off = page_off;
+
+       while (data_length) {
+               u32 cur_len = min_t(u32, data_length, sg->length - page_off);
+
+               iov[i].iov_base = kmap(sg_page(sg)) + sg->offset + page_off;
+               iov[i].iov_len = cur_len;
+
+               data_length -= cur_len;
+               page_off = 0;
+               sg = sg_next(sg);
+               i++;
+       }
+
+       cmd->kmapped_nents = i;
+
+       return i;
+}
+
+static void iscsit_unmap_iovec(struct iscsi_cmd *cmd)
+{
+       u32 i;
+       struct scatterlist *sg;
+
+       sg = cmd->first_data_sg;
+
+       for (i = 0; i < cmd->kmapped_nents; i++)
+               kunmap(sg_page(&sg[i]));
+}
+
+static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
+{
+       struct iscsi_cmd *cmd;
+
+       conn->exp_statsn = exp_statsn;
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+               spin_lock(&cmd->istate_lock);
+               if ((cmd->i_state == ISTATE_SENT_STATUS) &&
+                   (cmd->stat_sn < exp_statsn)) {
+                       cmd->i_state = ISTATE_REMOVE;
+                       spin_unlock(&cmd->istate_lock);
+                       iscsit_add_cmd_to_immediate_queue(cmd, conn,
+                                               cmd->i_state);
+                       continue;
+               }
+               spin_unlock(&cmd->istate_lock);
+       }
+       spin_unlock_bh(&conn->cmd_lock);
+}
+
+static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
+{
+       u32 iov_count = (cmd->se_cmd.t_data_nents == 0) ? 1 :
+                               cmd->se_cmd.t_data_nents;
+
+       iov_count += TRANSPORT_IOV_DATA_BUFFER;
+
+       cmd->iov_data = kzalloc(iov_count * sizeof(struct kvec), GFP_KERNEL);
+       if (!cmd->iov_data) {
+               pr_err("Unable to allocate cmd->iov_data\n");
+               return -ENOMEM;
+       }
+
+       cmd->orig_iov_data_count = iov_count;
+       return 0;
+}
+
+static int iscsit_alloc_buffs(struct iscsi_cmd *cmd)
+{
+       struct scatterlist *sgl;
+       u32 length = cmd->se_cmd.data_length;
+       int nents = DIV_ROUND_UP(length, PAGE_SIZE);
+       int i = 0, ret;
+       /*
+        * If no SCSI payload is present, allocate the default iovecs used for
+        * iSCSI PDU Header
+        */
+       if (!length)
+               return iscsit_allocate_iovecs(cmd);
+
+       sgl = kzalloc(sizeof(*sgl) * nents, GFP_KERNEL);
+       if (!sgl)
+               return -ENOMEM;
+
+       sg_init_table(sgl, nents);
+
+       while (length) {
+               int buf_size = min_t(int, length, PAGE_SIZE);
+               struct page *page;
+
+               page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+               if (!page)
+                       goto page_alloc_failed;
+
+               sg_set_page(&sgl[i], page, buf_size, 0);
+
+               length -= buf_size;
+               i++;
+       }
+
+       cmd->t_mem_sg = sgl;
+       cmd->t_mem_sg_nents = nents;
+
+       /* BIDI ops not supported */
+
+       /* Tell the core about our preallocated memory */
+       transport_generic_map_mem_to_cmd(&cmd->se_cmd, sgl, nents, NULL, 0);
+       /*
+        * Allocate iovecs for SCSI payload after transport_generic_map_mem_to_cmd
+        * so that cmd->se_cmd.t_tasks_se_num has been set.
+        */
+        ret = iscsit_allocate_iovecs(cmd);
+        if (ret < 0)
+               goto page_alloc_failed;
+
+       return 0;
+
+page_alloc_failed:
+       while (i >= 0) {
+               __free_page(sg_page(&sgl[i]));
+               i--;
+       }
+       kfree(cmd->t_mem_sg);
+       cmd->t_mem_sg = NULL;
+       return -ENOMEM;
+}
+
+static int iscsit_handle_scsi_cmd(
+       struct iscsi_conn *conn,
+       unsigned char *buf)
+{
+       int     data_direction, cmdsn_ret = 0, immed_ret, ret, transport_ret;
+       int     dump_immediate_data = 0, send_check_condition = 0, payload_length;
+       struct iscsi_cmd        *cmd = NULL;
+       struct iscsi_scsi_req *hdr;
+
+       spin_lock_bh(&conn->sess->session_stats_lock);
+       conn->sess->cmd_pdus++;
+       if (conn->sess->se_sess->se_node_acl) {
+               spin_lock(&conn->sess->se_sess->se_node_acl->stats_lock);
+               conn->sess->se_sess->se_node_acl->num_cmds++;
+               spin_unlock(&conn->sess->se_sess->se_node_acl->stats_lock);
+       }
+       spin_unlock_bh(&conn->sess->session_stats_lock);
+
+       hdr                     = (struct iscsi_scsi_req *) buf;
+       payload_length          = ntoh24(hdr->dlength);
+       hdr->itt                = be32_to_cpu(hdr->itt);
+       hdr->data_length        = be32_to_cpu(hdr->data_length);
+       hdr->cmdsn              = be32_to_cpu(hdr->cmdsn);
+       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
+
+       /* FIXME; Add checks for AdditionalHeaderSegment */
+
+       if (!(hdr->flags & ISCSI_FLAG_CMD_WRITE) &&
+           !(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {
+               pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL"
+                               " not set. Bad iSCSI Initiator.\n");
+               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
+                               buf, conn);
+       }
+
+       if (((hdr->flags & ISCSI_FLAG_CMD_READ) ||
+            (hdr->flags & ISCSI_FLAG_CMD_WRITE)) && !hdr->data_length) {
+               /*
+                * Vmware ESX v3.0 uses a modified Cisco Initiator (v3.4.2)
+                * that adds support for RESERVE/RELEASE.  There is a bug
+                * add with this new functionality that sets R/W bits when
+                * neither CDB carries any READ or WRITE datapayloads.
+                */
+               if ((hdr->cdb[0] == 0x16) || (hdr->cdb[0] == 0x17)) {
+                       hdr->flags &= ~ISCSI_FLAG_CMD_READ;
+                       hdr->flags &= ~ISCSI_FLAG_CMD_WRITE;
+                       goto done;
+               }
+
+               pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE"
+                       " set when Expected Data Transfer Length is 0 for"
+                       " CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]);
+               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
+                               buf, conn);
+       }
+done:
+
+       if (!(hdr->flags & ISCSI_FLAG_CMD_READ) &&
+           !(hdr->flags & ISCSI_FLAG_CMD_WRITE) && (hdr->data_length != 0)) {
+               pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE"
+                       " MUST be set if Expected Data Transfer Length is not 0."
+                       " Bad iSCSI Initiator\n");
+               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
+                               buf, conn);
+       }
+
+       if ((hdr->flags & ISCSI_FLAG_CMD_READ) &&
+           (hdr->flags & ISCSI_FLAG_CMD_WRITE)) {
+               pr_err("Bidirectional operations not supported!\n");
+               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
+                               buf, conn);
+       }
+
+       if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
+               pr_err("Illegally set Immediate Bit in iSCSI Initiator"
+                               " Scsi Command PDU.\n");
+               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
+                               buf, conn);
+       }
+
+       if (payload_length && !conn->sess->sess_ops->ImmediateData) {
+               pr_err("ImmediateData=No but DataSegmentLength=%u,"
+                       " protocol error.\n", payload_length);
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                               buf, conn);
+       }
+
+       if ((hdr->data_length == payload_length) &&
+           (!(hdr->flags & ISCSI_FLAG_CMD_FINAL))) {
+               pr_err("Expected Data Transfer Length and Length of"
+                       " Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL"
+                       " bit is not set protocol error\n");
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                               buf, conn);
+       }
+
+       if (payload_length > hdr->data_length) {
+               pr_err("DataSegmentLength: %u is greater than"
+                       " EDTL: %u, protocol error.\n", payload_length,
+                               hdr->data_length);
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                               buf, conn);
+       }
+
+       if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+               pr_err("DataSegmentLength: %u is greater than"
+                       " MaxRecvDataSegmentLength: %u, protocol error.\n",
+                       payload_length, conn->conn_ops->MaxRecvDataSegmentLength);
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                               buf, conn);
+       }
+
+       if (payload_length > conn->sess->sess_ops->FirstBurstLength) {
+               pr_err("DataSegmentLength: %u is greater than"
+                       " FirstBurstLength: %u, protocol error.\n",
+                       payload_length, conn->sess->sess_ops->FirstBurstLength);
+               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
+                                       buf, conn);
+       }
+
+       data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE :
+                        (hdr->flags & ISCSI_FLAG_CMD_READ) ? DMA_FROM_DEVICE :
+                         DMA_NONE;
+
+       cmd = iscsit_allocate_se_cmd(conn, hdr->data_length, data_direction,
+                               (hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK));
+       if (!cmd)
+               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1,
+                                       buf, conn);
+
+       pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x,"
+               " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt,
+               hdr->cmdsn, hdr->data_length, payload_length, conn->cid);
+
+       cmd->iscsi_opcode       = ISCSI_OP_SCSI_CMD;
+       cmd->i_state            = ISTATE_NEW_CMD;
+       cmd->immediate_cmd      = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
+       cmd->immediate_data     = (payload_length) ? 1 : 0;
+       cmd->unsolicited_data   = ((!(hdr->flags & ISCSI_FLAG_CMD_FINAL) &&
+                                    (hdr->flags & ISCSI_FLAG_CMD_WRITE)) ? 1 : 0);
+       if (cmd->unsolicited_data)
+               cmd->cmd_flags |= ICF_NON_IMMEDIATE_UNSOLICITED_DATA;
+
+       conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
+       if (hdr->flags & ISCSI_FLAG_CMD_READ) {
+               spin_lock_bh(&conn->sess->ttt_lock);
+               cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++;
+               if (cmd->targ_xfer_tag == 0xFFFFFFFF)
+                       cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++;
+               spin_unlock_bh(&conn->sess->ttt_lock);
+       } else if (hdr->flags & ISCSI_FLAG_CMD_WRITE)
+               cmd->targ_xfer_tag = 0xFFFFFFFF;
+       cmd->cmd_sn             = hdr->cmdsn;
+       cmd->exp_stat_sn        = hdr->exp_statsn;
+       cmd->first_burst_len    = payload_length;
+
+       if (cmd->data_direction == DMA_FROM_DEVICE) {
+               struct iscsi_datain_req *dr;
+
+               dr = iscsit_allocate_datain_req();
+               if (!dr)
+                       return iscsit_add_reject_from_cmd(
+                                       ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                                       1, 1, buf, cmd);
+
+               iscsit_attach_datain_req(cmd, dr);
+       }
+
+       /*
+        * The CDB is going to an se_device_t.
+        */
+       ret = iscsit_get_lun_for_cmd(cmd, hdr->cdb,
+                               get_unaligned_le64(&hdr->lun));
+       if (ret < 0) {
+               if (cmd->se_cmd.scsi_sense_reason == TCM_NON_EXISTENT_LUN) {
+                       pr_debug("Responding to non-acl'ed,"
+                               " non-existent or non-exported iSCSI LUN:"
+                               " 0x%016Lx\n", get_unaligned_le64(&hdr->lun));
+               }
+               if (ret == PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES)
+                       return iscsit_add_reject_from_cmd(
+                                       ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                                       1, 1, buf, cmd);
+
+               send_check_condition = 1;
+               goto attach_cmd;
+       }
+       /*
+        * The Initiator Node has access to the LUN (the addressing method
+        * is handled inside of iscsit_get_lun_for_cmd()).  Now it's time to
+        * allocate 1->N transport tasks (depending on sector count and
+        * maximum request size the physical HBA(s) can handle.
+        */
+       transport_ret = transport_generic_allocate_tasks(&cmd->se_cmd, hdr->cdb);
+       if (transport_ret == -ENOMEM) {
+               return iscsit_add_reject_from_cmd(
+                               ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                               1, 1, buf, cmd);
+       } else if (transport_ret == -EINVAL) {
+               /*
+                * Unsupported SAM Opcode.  CHECK_CONDITION will be sent
+                * in iscsit_execute_cmd() during the CmdSN OOO Execution
+                * Mechinism.
+                */
+               send_check_condition = 1;
+       } else {
+               if (iscsit_decide_list_to_build(cmd, payload_length) < 0)
+                       return iscsit_add_reject_from_cmd(
+                               ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                               1, 1, buf, cmd);
+       }
+
+attach_cmd:
+       spin_lock_bh(&conn->cmd_lock);
+       list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+       spin_unlock_bh(&conn->cmd_lock);
+       /*
+        * Check if we need to delay processing because of ALUA
+        * Active/NonOptimized primary access state..
+        */
+       core_alua_check_nonop_delay(&cmd->se_cmd);
+       /*
+        * Allocate and setup SGL used with transport_generic_map_mem_to_cmd().
+        * also call iscsit_allocate_iovecs()
+        */
+       ret = iscsit_alloc_buffs(cmd);
+       if (ret < 0)
+               return iscsit_add_reject_from_cmd(
+                               ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                               1, 1, buf, cmd);
+       /*
+        * Check the CmdSN against ExpCmdSN/MaxCmdSN here if
+        * the Immediate Bit is not set, and no Immediate
+        * Data is attached.
+        *
+        * A PDU/CmdSN carrying Immediate Data can only
+        * be processed after the DataCRC has passed.
+        * If the DataCRC fails, the CmdSN MUST NOT
+        * be acknowledged. (See below)
+        */
+       if (!cmd->immediate_data) {
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+                       return iscsit_add_reject_from_cmd(
+                               ISCSI_REASON_PROTOCOL_ERROR,
+                               1, 0, buf, cmd);
+       }
+
+       iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+
+       /*
+        * If no Immediate Data is attached, it's OK to return now.
+        */
+       if (!cmd->immediate_data) {
+               if (send_check_condition)
+                       return 0;
+
+               if (cmd->unsolicited_data) {
+                       iscsit_set_dataout_sequence_values(cmd);
+
+                       spin_lock_bh(&cmd->dataout_timeout_lock);
+                       iscsit_start_dataout_timer(cmd, cmd->conn);
+                       spin_unlock_bh(&cmd->dataout_timeout_lock);
+               }
+
+               return 0;
+       }
+
+       /*
+        * Early CHECK_CONDITIONs never make it to the transport processing
+        * thread.  They are processed in CmdSN order by
+        * iscsit_check_received_cmdsn() below.
+        */
+       if (send_check_condition) {
+               immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
+               dump_immediate_data = 1;
+               goto after_immediate_data;
+       }
+       /*
+        * Call directly into transport_generic_new_cmd() to perform
+        * the backend memory allocation.
+        */
+       ret = transport_generic_new_cmd(&cmd->se_cmd);
+       if ((ret < 0) || (cmd->se_cmd.se_cmd_flags & SCF_SE_CMD_FAILED)) {
+               immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
+               dump_immediate_data = 1;
+               goto after_immediate_data;
+       }
+
+       immed_ret = iscsit_handle_immediate_data(cmd, buf, payload_length);
+after_immediate_data:
+       if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) {
+               /*
+                * A PDU/CmdSN carrying Immediate Data passed
+                * DataCRC, check against ExpCmdSN/MaxCmdSN if
+                * Immediate Bit is not set.
+                */
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               /*
+                * Special case for Unsupported SAM WRITE Opcodes
+                * and ImmediateData=Yes.
+                */
+               if (dump_immediate_data) {
+                       if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
+                               return -1;
+               } else if (cmd->unsolicited_data) {
+                       iscsit_set_dataout_sequence_values(cmd);
+
+                       spin_lock_bh(&cmd->dataout_timeout_lock);
+                       iscsit_start_dataout_timer(cmd, cmd->conn);
+                       spin_unlock_bh(&cmd->dataout_timeout_lock);
+               }
+
+               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+                       return iscsit_add_reject_from_cmd(
+                               ISCSI_REASON_PROTOCOL_ERROR,
+                               1, 0, buf, cmd);
+
+       } else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
+               /*
+                * Immediate Data failed DataCRC and ERL>=1,
+                * silently drop this PDU and let the initiator
+                * plug the CmdSN gap.
+                *
+                * FIXME: Send Unsolicited NOPIN with reserved
+                * TTT here to help the initiator figure out
+                * the missing CmdSN, although they should be
+                * intelligent enough to determine the missing
+                * CmdSN and issue a retry to plug the sequence.
+                */
+               cmd->i_state = ISTATE_REMOVE;
+               iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
+       } else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */
+               return -1;
+
+       return 0;
+}
+
+static u32 iscsit_do_crypto_hash_sg(
+       struct hash_desc *hash,
+       struct iscsi_cmd *cmd,
+       u32 data_offset,
+       u32 data_length,
+       u32 padding,
+       u8 *pad_bytes)
+{
+       u32 data_crc;
+       u32 i;
+       struct scatterlist *sg;
+       unsigned int page_off;
+
+       crypto_hash_init(hash);
+
+       sg = cmd->first_data_sg;
+       page_off = cmd->first_data_sg_off;
+
+       i = 0;
+       while (data_length) {
+               u32 cur_len = min_t(u32, data_length, (sg[i].length - page_off));
+
+               crypto_hash_update(hash, &sg[i], cur_len);
+
+               data_length -= cur_len;
+               page_off = 0;
+               i++;
+       }
+
+       if (padding) {
+               struct scatterlist pad_sg;
+
+               sg_init_one(&pad_sg, pad_bytes, padding);
+               crypto_hash_update(hash, &pad_sg, padding);
+       }
+       crypto_hash_final(hash, (u8 *) &data_crc);
+
+       return data_crc;
+}
+
+static void iscsit_do_crypto_hash_buf(
+       struct hash_desc *hash,
+       unsigned char *buf,
+       u32 payload_length,
+       u32 padding,
+       u8 *pad_bytes,
+       u8 *data_crc)
+{
+       struct scatterlist sg;
+
+       crypto_hash_init(hash);
+
+       sg_init_one(&sg, (u8 *)buf, payload_length);
+       crypto_hash_update(hash, &sg, payload_length);
+
+       if (padding) {
+               sg_init_one(&sg, pad_bytes, padding);
+               crypto_hash_update(hash, &sg, padding);
+       }
+       crypto_hash_final(hash, data_crc);
+}
+
+static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
+{
+       int iov_ret, ooo_cmdsn = 0, ret;
+       u8 data_crc_failed = 0;
+       u32 checksum, iov_count = 0, padding = 0, rx_got = 0;
+       u32 rx_size = 0, payload_length;
+       struct iscsi_cmd *cmd = NULL;
+       struct se_cmd *se_cmd;
+       struct iscsi_data *hdr;
+       struct kvec *iov;
+       unsigned long flags;
+
+       hdr                     = (struct iscsi_data *) buf;
+       payload_length          = ntoh24(hdr->dlength);
+       hdr->itt                = be32_to_cpu(hdr->itt);
+       hdr->ttt                = be32_to_cpu(hdr->ttt);
+       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
+       hdr->datasn             = be32_to_cpu(hdr->datasn);
+       hdr->offset             = be32_to_cpu(hdr->offset);
+
+       if (!payload_length) {
+               pr_err("DataOUT payload is ZERO, protocol error.\n");
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                                       buf, conn);
+       }
+
+       /* iSCSI write */
+       spin_lock_bh(&conn->sess->session_stats_lock);
+       conn->sess->rx_data_octets += payload_length;
+       if (conn->sess->se_sess->se_node_acl) {
+               spin_lock(&conn->sess->se_sess->se_node_acl->stats_lock);
+               conn->sess->se_sess->se_node_acl->write_bytes += payload_length;
+               spin_unlock(&conn->sess->se_sess->se_node_acl->stats_lock);
+       }
+       spin_unlock_bh(&conn->sess->session_stats_lock);
+
+       if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+               pr_err("DataSegmentLength: %u is greater than"
+                       " MaxRecvDataSegmentLength: %u\n", payload_length,
+                       conn->conn_ops->MaxRecvDataSegmentLength);
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                                       buf, conn);
+       }
+
+       cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt,
+                       payload_length);
+       if (!cmd)
+               return 0;
+
+       pr_debug("Got DataOut ITT: 0x%08x, TTT: 0x%08x,"
+               " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n",
+               hdr->itt, hdr->ttt, hdr->datasn, hdr->offset,
+               payload_length, conn->cid);
+
+       if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
+               pr_err("Command ITT: 0x%08x received DataOUT after"
+                       " last DataOUT received, dumping payload\n",
+                       cmd->init_task_tag);
+               return iscsit_dump_data_payload(conn, payload_length, 1);
+       }
+
+       if (cmd->data_direction != DMA_TO_DEVICE) {
+               pr_err("Command ITT: 0x%08x received DataOUT for a"
+                       " NON-WRITE command.\n", cmd->init_task_tag);
+               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+                               1, 0, buf, cmd);
+       }
+       se_cmd = &cmd->se_cmd;
+       iscsit_mod_dataout_timer(cmd);
+
+       if ((hdr->offset + payload_length) > cmd->data_length) {
+               pr_err("DataOut Offset: %u, Length %u greater than"
+                       " iSCSI Command EDTL %u, protocol error.\n",
+                       hdr->offset, payload_length, cmd->data_length);
+               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+                               1, 0, buf, cmd);
+       }
+
+       if (cmd->unsolicited_data) {
+               int dump_unsolicited_data = 0;
+
+               if (conn->sess->sess_ops->InitialR2T) {
+                       pr_err("Received unexpected unsolicited data"
+                               " while InitialR2T=Yes, protocol error.\n");
+                       transport_send_check_condition_and_sense(&cmd->se_cmd,
+                                       TCM_UNEXPECTED_UNSOLICITED_DATA, 0);
+                       return -1;
+               }
+               /*
+                * Special case for dealing with Unsolicited DataOUT
+                * and Unsupported SAM WRITE Opcodes and SE resource allocation
+                * failures;
+                */
+
+               /* Something's amiss if we're not in WRITE_PENDING state... */
+               spin_lock_irqsave(&se_cmd->t_state_lock, flags);
+               WARN_ON(se_cmd->t_state != TRANSPORT_WRITE_PENDING);
+               spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
+
+               spin_lock_irqsave(&se_cmd->t_state_lock, flags);
+               if (!(se_cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) ||
+                    (se_cmd->se_cmd_flags & SCF_SE_CMD_FAILED))
+                       dump_unsolicited_data = 1;
+               spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
+
+               if (dump_unsolicited_data) {
+                       /*
+                        * Check if a delayed TASK_ABORTED status needs to
+                        * be sent now if the ISCSI_FLAG_CMD_FINAL has been
+                        * received with the unsolicitied data out.
+                        */
+                       if (hdr->flags & ISCSI_FLAG_CMD_FINAL)
+                               iscsit_stop_dataout_timer(cmd);
+
+                       transport_check_aborted_status(se_cmd,
+                                       (hdr->flags & ISCSI_FLAG_CMD_FINAL));
+                       return iscsit_dump_data_payload(conn, payload_length, 1);
+               }
+       } else {
+               /*
+                * For the normal solicited data path:
+                *
+                * Check for a delayed TASK_ABORTED status and dump any
+                * incoming data out payload if one exists.  Also, when the
+                * ISCSI_FLAG_CMD_FINAL is set to denote the end of the current
+                * data out sequence, we decrement outstanding_r2ts.  Once
+                * outstanding_r2ts reaches zero, go ahead and send the delayed
+                * TASK_ABORTED status.
+                */
+               if (atomic_read(&se_cmd->t_transport_aborted) != 0) {
+                       if (hdr->flags & ISCSI_FLAG_CMD_FINAL)
+                               if (--cmd->outstanding_r2ts < 1) {
+                                       iscsit_stop_dataout_timer(cmd);
+                                       transport_check_aborted_status(
+                                                       se_cmd, 1);
+                               }
+
+                       return iscsit_dump_data_payload(conn, payload_length, 1);
+               }
+       }
+       /*
+        * Preform DataSN, DataSequenceInOrder, DataPDUInOrder, and
+        * within-command recovery checks before receiving the payload.
+        */
+       ret = iscsit_check_pre_dataout(cmd, buf);
+       if (ret == DATAOUT_WITHIN_COMMAND_RECOVERY)
+               return 0;
+       else if (ret == DATAOUT_CANNOT_RECOVER)
+               return -1;
+
+       rx_size += payload_length;
+       iov = &cmd->iov_data[0];
+
+       iov_ret = iscsit_map_iovec(cmd, iov, hdr->offset, payload_length);
+       if (iov_ret < 0)
+               return -1;
+
+       iov_count += iov_ret;
+
+       padding = ((-payload_length) & 3);
+       if (padding != 0) {
+               iov[iov_count].iov_base = cmd->pad_bytes;
+               iov[iov_count++].iov_len = padding;
+               rx_size += padding;
+               pr_debug("Receiving %u padding bytes.\n", padding);
+       }
+
+       if (conn->conn_ops->DataDigest) {
+               iov[iov_count].iov_base = &checksum;
+               iov[iov_count++].iov_len = ISCSI_CRC_LEN;
+               rx_size += ISCSI_CRC_LEN;
+       }
+
+       rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size);
+
+       iscsit_unmap_iovec(cmd);
+
+       if (rx_got != rx_size)
+               return -1;
+
+       if (conn->conn_ops->DataDigest) {
+               u32 data_crc;
+
+               data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd,
+                                                   hdr->offset, payload_length, padding,
+                                                   cmd->pad_bytes);
+
+               if (checksum != data_crc) {
+                       pr_err("ITT: 0x%08x, Offset: %u, Length: %u,"
+                               " DataSN: 0x%08x, CRC32C DataDigest 0x%08x"
+                               " does not match computed 0x%08x\n",
+                               hdr->itt, hdr->offset, payload_length,
+                               hdr->datasn, checksum, data_crc);
+                       data_crc_failed = 1;
+               } else {
+                       pr_debug("Got CRC32C DataDigest 0x%08x for"
+                               " %u bytes of Data Out\n", checksum,
+                               payload_length);
+               }
+       }
+       /*
+        * Increment post receive data and CRC values or perform
+        * within-command recovery.
+        */
+       ret = iscsit_check_post_dataout(cmd, buf, data_crc_failed);
+       if ((ret == DATAOUT_NORMAL) || (ret == DATAOUT_WITHIN_COMMAND_RECOVERY))
+               return 0;
+       else if (ret == DATAOUT_SEND_R2T) {
+               iscsit_set_dataout_sequence_values(cmd);
+               iscsit_build_r2ts_for_cmd(cmd, conn, 0);
+       } else if (ret == DATAOUT_SEND_TO_TRANSPORT) {
+               /*
+                * Handle extra special case for out of order
+                * Unsolicited Data Out.
+                */
+               spin_lock_bh(&cmd->istate_lock);
+               ooo_cmdsn = (cmd->cmd_flags & ICF_OOO_CMDSN);
+               cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
+               cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
+               spin_unlock_bh(&cmd->istate_lock);
+
+               iscsit_stop_dataout_timer(cmd);
+               return (!ooo_cmdsn) ? transport_generic_handle_data(
+                                       &cmd->se_cmd) : 0;
+       } else /* DATAOUT_CANNOT_RECOVER */
+               return -1;
+
+       return 0;
+}
+
+static int iscsit_handle_nop_out(
+       struct iscsi_conn *conn,
+       unsigned char *buf)
+{
+       unsigned char *ping_data = NULL;
+       int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size;
+       u32 checksum, data_crc, padding = 0, payload_length;
+       u64 lun;
+       struct iscsi_cmd *cmd = NULL;
+       struct kvec *iov = NULL;
+       struct iscsi_nopout *hdr;
+
+       hdr                     = (struct iscsi_nopout *) buf;
+       payload_length          = ntoh24(hdr->dlength);
+       lun                     = get_unaligned_le64(&hdr->lun);
+       hdr->itt                = be32_to_cpu(hdr->itt);
+       hdr->ttt                = be32_to_cpu(hdr->ttt);
+       hdr->cmdsn              = be32_to_cpu(hdr->cmdsn);
+       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
+
+       if ((hdr->itt == 0xFFFFFFFF) && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+               pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
+                       " not set, protocol error.\n");
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                                       buf, conn);
+       }
+
+       if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+               pr_err("NOPOUT Ping Data DataSegmentLength: %u is"
+                       " greater than MaxRecvDataSegmentLength: %u, protocol"
+                       " error.\n", payload_length,
+                       conn->conn_ops->MaxRecvDataSegmentLength);
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                                       buf, conn);
+       }
+
+       pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%09x,"
+               " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
+               (hdr->itt == 0xFFFFFFFF) ? "Response" : "Request",
+               hdr->itt, hdr->ttt, hdr->cmdsn, hdr->exp_statsn,
+               payload_length);
+       /*
+        * This is not a response to a Unsolicited NopIN, which means
+        * it can either be a NOPOUT ping request (with a valid ITT),
+        * or a NOPOUT not requesting a NOPIN (with a reserved ITT).
+        * Either way, make sure we allocate an struct iscsi_cmd, as both
+        * can contain ping data.
+        */
+       if (hdr->ttt == 0xFFFFFFFF) {
+               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               if (!cmd)
+                       return iscsit_add_reject(
+                                       ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                                       1, buf, conn);
+
+               cmd->iscsi_opcode       = ISCSI_OP_NOOP_OUT;
+               cmd->i_state            = ISTATE_SEND_NOPIN;
+               cmd->immediate_cmd      = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ?
+                                               1 : 0);
+               conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
+               cmd->targ_xfer_tag      = 0xFFFFFFFF;
+               cmd->cmd_sn             = hdr->cmdsn;
+               cmd->exp_stat_sn        = hdr->exp_statsn;
+               cmd->data_direction     = DMA_NONE;
+       }
+
+       if (payload_length && (hdr->ttt == 0xFFFFFFFF)) {
+               rx_size = payload_length;
+               ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
+               if (!ping_data) {
+                       pr_err("Unable to allocate memory for"
+                               " NOPOUT ping data.\n");
+                       ret = -1;
+                       goto out;
+               }
+
+               iov = &cmd->iov_misc[0];
+               iov[niov].iov_base      = ping_data;
+               iov[niov++].iov_len     = payload_length;
+
+               padding = ((-payload_length) & 3);
+               if (padding != 0) {
+                       pr_debug("Receiving %u additional bytes"
+                               " for padding.\n", padding);
+                       iov[niov].iov_base      = &cmd->pad_bytes;
+                       iov[niov++].iov_len     = padding;
+                       rx_size += padding;
+               }
+               if (conn->conn_ops->DataDigest) {
+                       iov[niov].iov_base      = &checksum;
+                       iov[niov++].iov_len     = ISCSI_CRC_LEN;
+                       rx_size += ISCSI_CRC_LEN;
+               }
+
+               rx_got = rx_data(conn, &cmd->iov_misc[0], niov, rx_size);
+               if (rx_got != rx_size) {
+                       ret = -1;
+                       goto out;
+               }
+
+               if (conn->conn_ops->DataDigest) {
+                       iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
+                                       ping_data, payload_length,
+                                       padding, cmd->pad_bytes,
+                                       (u8 *)&data_crc);
+
+                       if (checksum != data_crc) {
+                               pr_err("Ping data CRC32C DataDigest"
+                               " 0x%08x does not match computed 0x%08x\n",
+                                       checksum, data_crc);
+                               if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+                                       pr_err("Unable to recover from"
+                                       " NOPOUT Ping DataCRC failure while in"
+                                               " ERL=0.\n");
+                                       ret = -1;
+                                       goto out;
+                               } else {
+                                       /*
+                                        * Silently drop this PDU and let the
+                                        * initiator plug the CmdSN gap.
+                                        */
+                                       pr_debug("Dropping NOPOUT"
+                                       " Command CmdSN: 0x%08x due to"
+                                       " DataCRC error.\n", hdr->cmdsn);
+                                       ret = 0;
+                                       goto out;
+                               }
+                       } else {
+                               pr_debug("Got CRC32C DataDigest"
+                               " 0x%08x for %u bytes of ping data.\n",
+                                       checksum, payload_length);
+                       }
+               }
+
+               ping_data[payload_length] = '\0';
+               /*
+                * Attach ping data to struct iscsi_cmd->buf_ptr.
+                */
+               cmd->buf_ptr = (void *)ping_data;
+               cmd->buf_ptr_size = payload_length;
+
+               pr_debug("Got %u bytes of NOPOUT ping"
+                       " data.\n", payload_length);
+               pr_debug("Ping Data: \"%s\"\n", ping_data);
+       }
+
+       if (hdr->itt != 0xFFFFFFFF) {
+               if (!cmd) {
+                       pr_err("Checking CmdSN for NOPOUT,"
+                               " but cmd is NULL!\n");
+                       return -1;
+               }
+               /*
+                * Initiator is expecting a NopIN ping reply,
+                */
+               spin_lock_bh(&conn->cmd_lock);
+               list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+               spin_unlock_bh(&conn->cmd_lock);
+
+               iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+
+               if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
+                       iscsit_add_cmd_to_response_queue(cmd, conn,
+                                       cmd->i_state);
+                       return 0;
+               }
+
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+                       ret = 0;
+                       goto ping_out;
+               }
+               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+                       return iscsit_add_reject_from_cmd(
+                                       ISCSI_REASON_PROTOCOL_ERROR,
+                                       1, 0, buf, cmd);
+
+               return 0;
+       }
+
+       if (hdr->ttt != 0xFFFFFFFF) {
+               /*
+                * This was a response to a unsolicited NOPIN ping.
+                */
+               cmd = iscsit_find_cmd_from_ttt(conn, hdr->ttt);
+               if (!cmd)
+                       return -1;
+
+               iscsit_stop_nopin_response_timer(conn);
+
+               cmd->i_state = ISTATE_REMOVE;
+               iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
+               iscsit_start_nopin_timer(conn);
+       } else {
+               /*
+                * Initiator is not expecting a NOPIN is response.
+                * Just ignore for now.
+                *
+                * iSCSI v19-91 10.18
+                * "A NOP-OUT may also be used to confirm a changed
+                *  ExpStatSN if another PDU will not be available
+                *  for a long time."
+                */
+               ret = 0;
+               goto out;
+       }
+
+       return 0;
+out:
+       if (cmd)
+               iscsit_release_cmd(cmd);
+ping_out:
+       kfree(ping_data);
+       return ret;
+}
+
+static int iscsit_handle_task_mgt_cmd(
+       struct iscsi_conn *conn,
+       unsigned char *buf)
+{
+       struct iscsi_cmd *cmd;
+       struct se_tmr_req *se_tmr;
+       struct iscsi_tmr_req *tmr_req;
+       struct iscsi_tm *hdr;
+       u32 payload_length;
+       int out_of_order_cmdsn = 0;
+       int ret;
+       u8 function;
+
+       hdr                     = (struct iscsi_tm *) buf;
+       payload_length          = ntoh24(hdr->dlength);
+       hdr->itt                = be32_to_cpu(hdr->itt);
+       hdr->rtt                = be32_to_cpu(hdr->rtt);
+       hdr->cmdsn              = be32_to_cpu(hdr->cmdsn);
+       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
+       hdr->refcmdsn           = be32_to_cpu(hdr->refcmdsn);
+       hdr->exp_datasn         = be32_to_cpu(hdr->exp_datasn);
+       hdr->flags &= ~ISCSI_FLAG_CMD_FINAL;
+       function = hdr->flags;
+
+       pr_debug("Got Task Management Request ITT: 0x%08x, CmdSN:"
+               " 0x%08x, Function: 0x%02x, RefTaskTag: 0x%08x, RefCmdSN:"
+               " 0x%08x, CID: %hu\n", hdr->itt, hdr->cmdsn, function,
+               hdr->rtt, hdr->refcmdsn, conn->cid);
+
+       if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
+           ((function != ISCSI_TM_FUNC_TASK_REASSIGN) &&
+            (hdr->rtt != ISCSI_RESERVED_TAG))) {
+               pr_err("RefTaskTag should be set to 0xFFFFFFFF.\n");
+               hdr->rtt = ISCSI_RESERVED_TAG;
+       }
+
+       if ((function == ISCSI_TM_FUNC_TASK_REASSIGN) &&
+                       !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+               pr_err("Task Management Request TASK_REASSIGN not"
+                       " issued as immediate command, bad iSCSI Initiator"
+                               "implementation\n");
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                                       buf, conn);
+       }
+       if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
+           (hdr->refcmdsn != ISCSI_RESERVED_TAG))
+               hdr->refcmdsn = ISCSI_RESERVED_TAG;
+
+       cmd = iscsit_allocate_se_cmd_for_tmr(conn, function);
+       if (!cmd)
+               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                                       1, buf, conn);
+
+       cmd->iscsi_opcode       = ISCSI_OP_SCSI_TMFUNC;
+       cmd->i_state            = ISTATE_SEND_TASKMGTRSP;
+       cmd->immediate_cmd      = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
+       cmd->init_task_tag      = hdr->itt;
+       cmd->targ_xfer_tag      = 0xFFFFFFFF;
+       cmd->cmd_sn             = hdr->cmdsn;
+       cmd->exp_stat_sn        = hdr->exp_statsn;
+       se_tmr                  = cmd->se_cmd.se_tmr_req;
+       tmr_req                 = cmd->tmr_req;
+       /*
+        * Locate the struct se_lun for all TMRs not related to ERL=2 TASK_REASSIGN
+        */
+       if (function != ISCSI_TM_FUNC_TASK_REASSIGN) {
+               ret = iscsit_get_lun_for_tmr(cmd,
+                               get_unaligned_le64(&hdr->lun));
+               if (ret < 0) {
+                       cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+                       se_tmr->response = ISCSI_TMF_RSP_NO_LUN;
+                       goto attach;
+               }
+       }
+
+       switch (function) {
+       case ISCSI_TM_FUNC_ABORT_TASK:
+               se_tmr->response = iscsit_tmr_abort_task(cmd, buf);
+               if (se_tmr->response != ISCSI_TMF_RSP_COMPLETE) {
+                       cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+                       goto attach;
+               }
+               break;
+       case ISCSI_TM_FUNC_ABORT_TASK_SET:
+       case ISCSI_TM_FUNC_CLEAR_ACA:
+       case ISCSI_TM_FUNC_CLEAR_TASK_SET:
+       case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
+               break;
+       case ISCSI_TM_FUNC_TARGET_WARM_RESET:
+               if (iscsit_tmr_task_warm_reset(conn, tmr_req, buf) < 0) {
+                       cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+                       se_tmr->response = ISCSI_TMF_RSP_AUTH_FAILED;
+                       goto attach;
+               }
+               break;
+       case ISCSI_TM_FUNC_TARGET_COLD_RESET:
+               if (iscsit_tmr_task_cold_reset(conn, tmr_req, buf) < 0) {
+                       cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+                       se_tmr->response = ISCSI_TMF_RSP_AUTH_FAILED;
+                       goto attach;
+               }
+               break;
+       case ISCSI_TM_FUNC_TASK_REASSIGN:
+               se_tmr->response = iscsit_tmr_task_reassign(cmd, buf);
+               /*
+                * Perform sanity checks on the ExpDataSN only if the
+                * TASK_REASSIGN was successful.
+                */
+               if (se_tmr->response != ISCSI_TMF_RSP_COMPLETE)
+                       break;
+
+               if (iscsit_check_task_reassign_expdatasn(tmr_req, conn) < 0)
+                       return iscsit_add_reject_from_cmd(
+                                       ISCSI_REASON_BOOKMARK_INVALID, 1, 1,
+                                       buf, cmd);
+               break;
+       default:
+               pr_err("Unknown TMR function: 0x%02x, protocol"
+                       " error.\n", function);
+               cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+               se_tmr->response = ISCSI_TMF_RSP_NOT_SUPPORTED;
+               goto attach;
+       }
+
+       if ((function != ISCSI_TM_FUNC_TASK_REASSIGN) &&
+           (se_tmr->response == ISCSI_TMF_RSP_COMPLETE))
+               se_tmr->call_transport = 1;
+attach:
+       spin_lock_bh(&conn->cmd_lock);
+       list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+       spin_unlock_bh(&conn->cmd_lock);
+
+       if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+               int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)
+                       out_of_order_cmdsn = 1;
+               else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+                       return 0;
+               } else { /* (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) */
+                       return iscsit_add_reject_from_cmd(
+                                       ISCSI_REASON_PROTOCOL_ERROR,
+                                       1, 0, buf, cmd);
+               }
+       }
+       iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+
+       if (out_of_order_cmdsn)
+               return 0;
+       /*
+        * Found the referenced task, send to transport for processing.
+        */
+       if (se_tmr->call_transport)
+               return transport_generic_handle_tmr(&cmd->se_cmd);
+
+       /*
+        * Could not find the referenced LUN, task, or Task Management
+        * command not authorized or supported.  Change state and
+        * let the tx_thread send the response.
+        *
+        * For connection recovery, this is also the default action for
+        * TMR TASK_REASSIGN.
+        */
+       iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+       return 0;
+}
+
+/* #warning FIXME: Support Text Command parameters besides SendTargets */
+static int iscsit_handle_text_cmd(
+       struct iscsi_conn *conn,
+       unsigned char *buf)
+{
+       char *text_ptr, *text_in;
+       int cmdsn_ret, niov = 0, rx_got, rx_size;
+       u32 checksum = 0, data_crc = 0, payload_length;
+       u32 padding = 0, text_length = 0;
+       struct iscsi_cmd *cmd;
+       struct kvec iov[3];
+       struct iscsi_text *hdr;
+
+       hdr                     = (struct iscsi_text *) buf;
+       payload_length          = ntoh24(hdr->dlength);
+       hdr->itt                = be32_to_cpu(hdr->itt);
+       hdr->ttt                = be32_to_cpu(hdr->ttt);
+       hdr->cmdsn              = be32_to_cpu(hdr->cmdsn);
+       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
+
+       if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) {
+               pr_err("Unable to accept text parameter length: %u"
+                       "greater than MaxRecvDataSegmentLength %u.\n",
+                      payload_length, conn->conn_ops->MaxRecvDataSegmentLength);
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                                       buf, conn);
+       }
+
+       pr_debug("Got Text Request: ITT: 0x%08x, CmdSN: 0x%08x,"
+               " ExpStatSN: 0x%08x, Length: %u\n", hdr->itt, hdr->cmdsn,
+               hdr->exp_statsn, payload_length);
+
+       rx_size = text_length = payload_length;
+       if (text_length) {
+               text_in = kzalloc(text_length, GFP_KERNEL);
+               if (!text_in) {
+                       pr_err("Unable to allocate memory for"
+                               " incoming text parameters\n");
+                       return -1;
+               }
+
+               memset(iov, 0, 3 * sizeof(struct kvec));
+               iov[niov].iov_base      = text_in;
+               iov[niov++].iov_len     = text_length;
+
+               padding = ((-payload_length) & 3);
+               if (padding != 0) {
+                       iov[niov].iov_base = cmd->pad_bytes;
+                       iov[niov++].iov_len  = padding;
+                       rx_size += padding;
+                       pr_debug("Receiving %u additional bytes"
+                                       " for padding.\n", padding);
+               }
+               if (conn->conn_ops->DataDigest) {
+                       iov[niov].iov_base      = &checksum;
+                       iov[niov++].iov_len     = ISCSI_CRC_LEN;
+                       rx_size += ISCSI_CRC_LEN;
+               }
+
+               rx_got = rx_data(conn, &iov[0], niov, rx_size);
+               if (rx_got != rx_size) {
+                       kfree(text_in);
+                       return -1;
+               }
+
+               if (conn->conn_ops->DataDigest) {
+                       iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
+                                       text_in, text_length,
+                                       padding, cmd->pad_bytes,
+                                       (u8 *)&data_crc);
+
+                       if (checksum != data_crc) {
+                               pr_err("Text data CRC32C DataDigest"
+                                       " 0x%08x does not match computed"
+                                       " 0x%08x\n", checksum, data_crc);
+                               if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+                                       pr_err("Unable to recover from"
+                                       " Text Data digest failure while in"
+                                               " ERL=0.\n");
+                                       kfree(text_in);
+                                       return -1;
+                               } else {
+                                       /*
+                                        * Silently drop this PDU and let the
+                                        * initiator plug the CmdSN gap.
+                                        */
+                                       pr_debug("Dropping Text"
+                                       " Command CmdSN: 0x%08x due to"
+                                       " DataCRC error.\n", hdr->cmdsn);
+                                       kfree(text_in);
+                                       return 0;
+                               }
+                       } else {
+                               pr_debug("Got CRC32C DataDigest"
+                                       " 0x%08x for %u bytes of text data.\n",
+                                               checksum, text_length);
+                       }
+               }
+               text_in[text_length - 1] = '\0';
+               pr_debug("Successfully read %d bytes of text"
+                               " data.\n", text_length);
+
+               if (strncmp("SendTargets", text_in, 11) != 0) {
+                       pr_err("Received Text Data that is not"
+                               " SendTargets, cannot continue.\n");
+                       kfree(text_in);
+                       return -1;
+               }
+               text_ptr = strchr(text_in, '=');
+               if (!text_ptr) {
+                       pr_err("No \"=\" separator found in Text Data,"
+                               "  cannot continue.\n");
+                       kfree(text_in);
+                       return -1;
+               }
+               if (strncmp("=All", text_ptr, 4) != 0) {
+                       pr_err("Unable to locate All value for"
+                               " SendTargets key,  cannot continue.\n");
+                       kfree(text_in);
+                       return -1;
+               }
+/*#warning Support SendTargets=(iSCSI Target Name/Nothing) values. */
+               kfree(text_in);
+       }
+
+       cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+       if (!cmd)
+               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                                       1, buf, conn);
+
+       cmd->iscsi_opcode       = ISCSI_OP_TEXT;
+       cmd->i_state            = ISTATE_SEND_TEXTRSP;
+       cmd->immediate_cmd      = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
+       conn->sess->init_task_tag = cmd->init_task_tag  = hdr->itt;
+       cmd->targ_xfer_tag      = 0xFFFFFFFF;
+       cmd->cmd_sn             = hdr->cmdsn;
+       cmd->exp_stat_sn        = hdr->exp_statsn;
+       cmd->data_direction     = DMA_NONE;
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+       spin_unlock_bh(&conn->cmd_lock);
+
+       iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+
+       if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+                       return iscsit_add_reject_from_cmd(
+                                       ISCSI_REASON_PROTOCOL_ERROR,
+                                       1, 0, buf, cmd);
+
+               return 0;
+       }
+
+       return iscsit_execute_cmd(cmd, 0);
+}
+
+int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+       struct iscsi_conn *conn_p;
+       struct iscsi_session *sess = conn->sess;
+
+       pr_debug("Received logout request CLOSESESSION on CID: %hu"
+               " for SID: %u.\n", conn->cid, conn->sess->sid);
+
+       atomic_set(&sess->session_logout, 1);
+       atomic_set(&conn->conn_logout_remove, 1);
+       conn->conn_logout_reason = ISCSI_LOGOUT_REASON_CLOSE_SESSION;
+
+       iscsit_inc_conn_usage_count(conn);
+       iscsit_inc_session_usage_count(sess);
+
+       spin_lock_bh(&sess->conn_lock);
+       list_for_each_entry(conn_p, &sess->sess_conn_list, conn_list) {
+               if (conn_p->conn_state != TARG_CONN_STATE_LOGGED_IN)
+                       continue;
+
+               pr_debug("Moving to TARG_CONN_STATE_IN_LOGOUT.\n");
+               conn_p->conn_state = TARG_CONN_STATE_IN_LOGOUT;
+       }
+       spin_unlock_bh(&sess->conn_lock);
+
+       iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+
+       return 0;
+}
+
+int iscsit_logout_closeconnection(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+       struct iscsi_conn *l_conn;
+       struct iscsi_session *sess = conn->sess;
+
+       pr_debug("Received logout request CLOSECONNECTION for CID:"
+               " %hu on CID: %hu.\n", cmd->logout_cid, conn->cid);
+
+       /*
+        * A Logout Request with a CLOSECONNECTION reason code for a CID
+        * can arrive on a connection with a differing CID.
+        */
+       if (conn->cid == cmd->logout_cid) {
+               spin_lock_bh(&conn->state_lock);
+               pr_debug("Moving to TARG_CONN_STATE_IN_LOGOUT.\n");
+               conn->conn_state = TARG_CONN_STATE_IN_LOGOUT;
+
+               atomic_set(&conn->conn_logout_remove, 1);
+               conn->conn_logout_reason = ISCSI_LOGOUT_REASON_CLOSE_CONNECTION;
+               iscsit_inc_conn_usage_count(conn);
+
+               spin_unlock_bh(&conn->state_lock);
+       } else {
+               /*
+                * Handle all different cid CLOSECONNECTION requests in
+                * iscsit_logout_post_handler_diffcid() as to give enough
+                * time for any non immediate command's CmdSN to be
+                * acknowledged on the connection in question.
+                *
+                * Here we simply make sure the CID is still around.
+                */
+               l_conn = iscsit_get_conn_from_cid(sess,
+                               cmd->logout_cid);
+               if (!l_conn) {
+                       cmd->logout_response = ISCSI_LOGOUT_CID_NOT_FOUND;
+                       iscsit_add_cmd_to_response_queue(cmd, conn,
+                                       cmd->i_state);
+                       return 0;
+               }
+
+               iscsit_dec_conn_usage_count(l_conn);
+       }
+
+       iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+
+       return 0;
+}
+
+int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+       struct iscsi_session *sess = conn->sess;
+
+       pr_debug("Received explicit REMOVECONNFORRECOVERY logout for"
+               " CID: %hu on CID: %hu.\n", cmd->logout_cid, conn->cid);
+
+       if (sess->sess_ops->ErrorRecoveryLevel != 2) {
+               pr_err("Received Logout Request REMOVECONNFORRECOVERY"
+                       " while ERL!=2.\n");
+               cmd->logout_response = ISCSI_LOGOUT_RECOVERY_UNSUPPORTED;
+               iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+               return 0;
+       }
+
+       if (conn->cid == cmd->logout_cid) {
+               pr_err("Received Logout Request REMOVECONNFORRECOVERY"
+                       " with CID: %hu on CID: %hu, implementation error.\n",
+                               cmd->logout_cid, conn->cid);
+               cmd->logout_response = ISCSI_LOGOUT_CLEANUP_FAILED;
+               iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+               return 0;
+       }
+
+       iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+
+       return 0;
+}
+
+static int iscsit_handle_logout_cmd(
+       struct iscsi_conn *conn,
+       unsigned char *buf)
+{
+       int cmdsn_ret, logout_remove = 0;
+       u8 reason_code = 0;
+       struct iscsi_cmd *cmd;
+       struct iscsi_logout *hdr;
+       struct iscsi_tiqn *tiqn = iscsit_snmp_get_tiqn(conn);
+
+       hdr                     = (struct iscsi_logout *) buf;
+       reason_code             = (hdr->flags & 0x7f);
+       hdr->itt                = be32_to_cpu(hdr->itt);
+       hdr->cid                = be16_to_cpu(hdr->cid);
+       hdr->cmdsn              = be32_to_cpu(hdr->cmdsn);
+       hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn);
+
+       if (tiqn) {
+               spin_lock(&tiqn->logout_stats.lock);
+               if (reason_code == ISCSI_LOGOUT_REASON_CLOSE_SESSION)
+                       tiqn->logout_stats.normal_logouts++;
+               else
+                       tiqn->logout_stats.abnormal_logouts++;
+               spin_unlock(&tiqn->logout_stats.lock);
+       }
+
+       pr_debug("Got Logout Request ITT: 0x%08x CmdSN: 0x%08x"
+               " ExpStatSN: 0x%08x Reason: 0x%02x CID: %hu on CID: %hu\n",
+               hdr->itt, hdr->cmdsn, hdr->exp_statsn, reason_code,
+               hdr->cid, conn->cid);
+
+       if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) {
+               pr_err("Received logout request on connection that"
+                       " is not in logged in state, ignoring request.\n");
+               return 0;
+       }
+
+       cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+       if (!cmd)
+               return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1,
+                                       buf, conn);
+
+       cmd->iscsi_opcode       = ISCSI_OP_LOGOUT;
+       cmd->i_state            = ISTATE_SEND_LOGOUTRSP;
+       cmd->immediate_cmd      = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
+       conn->sess->init_task_tag = cmd->init_task_tag  = hdr->itt;
+       cmd->targ_xfer_tag      = 0xFFFFFFFF;
+       cmd->cmd_sn             = hdr->cmdsn;
+       cmd->exp_stat_sn        = hdr->exp_statsn;
+       cmd->logout_cid         = hdr->cid;
+       cmd->logout_reason      = reason_code;
+       cmd->data_direction     = DMA_NONE;
+
+       /*
+        * We need to sleep in these cases (by returning 1) until the Logout
+        * Response gets sent in the tx thread.
+        */
+       if ((reason_code == ISCSI_LOGOUT_REASON_CLOSE_SESSION) ||
+          ((reason_code == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION) &&
+           (hdr->cid == conn->cid)))
+               logout_remove = 1;
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+       spin_unlock_bh(&conn->cmd_lock);
+
+       if (reason_code != ISCSI_LOGOUT_REASON_RECOVERY)
+               iscsit_ack_from_expstatsn(conn, hdr->exp_statsn);
+
+       /*
+        * Immediate commands are executed, well, immediately.
+        * Non-Immediate Logout Commands are executed in CmdSN order.
+        */
+       if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
+               int ret = iscsit_execute_cmd(cmd, 0);
+
+               if (ret < 0)
+                       return ret;
+       } else {
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+                       logout_remove = 0;
+               } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
+                       return iscsit_add_reject_from_cmd(
+                               ISCSI_REASON_PROTOCOL_ERROR,
+                               1, 0, buf, cmd);
+               }
+       }
+
+       return logout_remove;
+}
+
+static int iscsit_handle_snack(
+       struct iscsi_conn *conn,
+       unsigned char *buf)
+{
+       u32 unpacked_lun;
+       u64 lun;
+       struct iscsi_snack *hdr;
+
+       hdr                     = (struct iscsi_snack *) buf;
+       hdr->flags              &= ~ISCSI_FLAG_CMD_FINAL;
+       lun                     = get_unaligned_le64(&hdr->lun);
+       unpacked_lun            = scsilun_to_int((struct scsi_lun *)&lun);
+       hdr->itt                = be32_to_cpu(hdr->itt);
+       hdr->ttt                = be32_to_cpu(hdr->ttt);
+       hdr->exp_statsn         = be32_to_cpu(hdr->exp_statsn);
+       hdr->begrun             = be32_to_cpu(hdr->begrun);
+       hdr->runlength          = be32_to_cpu(hdr->runlength);
+
+       pr_debug("Got ISCSI_INIT_SNACK, ITT: 0x%08x, ExpStatSN:"
+               " 0x%08x, Type: 0x%02x, BegRun: 0x%08x, RunLength: 0x%08x,"
+               " CID: %hu\n", hdr->itt, hdr->exp_statsn, hdr->flags,
+                       hdr->begrun, hdr->runlength, conn->cid);
+
+       if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+               pr_err("Initiator sent SNACK request while in"
+                       " ErrorRecoveryLevel=0.\n");
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                                       buf, conn);
+       }
+       /*
+        * SNACK_DATA and SNACK_R2T are both 0,  so check which function to
+        * call from inside iscsi_send_recovery_datain_or_r2t().
+        */
+       switch (hdr->flags & ISCSI_FLAG_SNACK_TYPE_MASK) {
+       case 0:
+               return iscsit_handle_recovery_datain_or_r2t(conn, buf,
+                       hdr->itt, hdr->ttt, hdr->begrun, hdr->runlength);
+               return 0;
+       case ISCSI_FLAG_SNACK_TYPE_STATUS:
+               return iscsit_handle_status_snack(conn, hdr->itt, hdr->ttt,
+                       hdr->begrun, hdr->runlength);
+       case ISCSI_FLAG_SNACK_TYPE_DATA_ACK:
+               return iscsit_handle_data_ack(conn, hdr->ttt, hdr->begrun,
+                       hdr->runlength);
+       case ISCSI_FLAG_SNACK_TYPE_RDATA:
+               /* FIXME: Support R-Data SNACK */
+               pr_err("R-Data SNACK Not Supported.\n");
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                                       buf, conn);
+       default:
+               pr_err("Unknown SNACK type 0x%02x, protocol"
+                       " error.\n", hdr->flags & 0x0f);
+               return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                                       buf, conn);
+       }
+
+       return 0;
+}
+
+static void iscsit_rx_thread_wait_for_tcp(struct iscsi_conn *conn)
+{
+       if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) ||
+           (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) {
+               wait_for_completion_interruptible_timeout(
+                                       &conn->rx_half_close_comp,
+                                       ISCSI_RX_THREAD_TCP_TIMEOUT * HZ);
+       }
+}
+
+static int iscsit_handle_immediate_data(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf,
+       u32 length)
+{
+       int iov_ret, rx_got = 0, rx_size = 0;
+       u32 checksum, iov_count = 0, padding = 0;
+       struct iscsi_conn *conn = cmd->conn;
+       struct kvec *iov;
+
+       iov_ret = iscsit_map_iovec(cmd, cmd->iov_data, cmd->write_data_done, length);
+       if (iov_ret < 0)
+               return IMMEDIATE_DATA_CANNOT_RECOVER;
+
+       rx_size = length;
+       iov_count = iov_ret;
+       iov = &cmd->iov_data[0];
+
+       padding = ((-length) & 3);
+       if (padding != 0) {
+               iov[iov_count].iov_base = cmd->pad_bytes;
+               iov[iov_count++].iov_len = padding;
+               rx_size += padding;
+       }
+
+       if (conn->conn_ops->DataDigest) {
+               iov[iov_count].iov_base         = &checksum;
+               iov[iov_count++].iov_len        = ISCSI_CRC_LEN;
+               rx_size += ISCSI_CRC_LEN;
+       }
+
+       rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size);
+
+       iscsit_unmap_iovec(cmd);
+
+       if (rx_got != rx_size) {
+               iscsit_rx_thread_wait_for_tcp(conn);
+               return IMMEDIATE_DATA_CANNOT_RECOVER;
+       }
+
+       if (conn->conn_ops->DataDigest) {
+               u32 data_crc;
+
+               data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd,
+                                                   cmd->write_data_done, length, padding,
+                                                   cmd->pad_bytes);
+
+               if (checksum != data_crc) {
+                       pr_err("ImmediateData CRC32C DataDigest 0x%08x"
+                               " does not match computed 0x%08x\n", checksum,
+                               data_crc);
+
+                       if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+                               pr_err("Unable to recover from"
+                                       " Immediate Data digest failure while"
+                                       " in ERL=0.\n");
+                               iscsit_add_reject_from_cmd(
+                                               ISCSI_REASON_DATA_DIGEST_ERROR,
+                                               1, 0, buf, cmd);
+                               return IMMEDIATE_DATA_CANNOT_RECOVER;
+                       } else {
+                               iscsit_add_reject_from_cmd(
+                                               ISCSI_REASON_DATA_DIGEST_ERROR,
+                                               0, 0, buf, cmd);
+                               return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
+                       }
+               } else {
+                       pr_debug("Got CRC32C DataDigest 0x%08x for"
+                               " %u bytes of Immediate Data\n", checksum,
+                               length);
+               }
+       }
+
+       cmd->write_data_done += length;
+
+       if (cmd->write_data_done == cmd->data_length) {
+               spin_lock_bh(&cmd->istate_lock);
+               cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
+               cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
+               spin_unlock_bh(&cmd->istate_lock);
+       }
+
+       return IMMEDIATE_DATA_NORMAL_OPERATION;
+}
+
+/*
+ *     Called with sess->conn_lock held.
+ */
+/* #warning iscsi_build_conn_drop_async_message() only sends out on connections
+       with active network interface */
+static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)
+{
+       struct iscsi_cmd *cmd;
+       struct iscsi_conn *conn_p;
+
+       /*
+        * Only send a Asynchronous Message on connections whos network
+        * interface is still functional.
+        */
+       list_for_each_entry(conn_p, &conn->sess->sess_conn_list, conn_list) {
+               if (conn_p->conn_state == TARG_CONN_STATE_LOGGED_IN) {
+                       iscsit_inc_conn_usage_count(conn_p);
+                       break;
+               }
+       }
+
+       if (!conn_p)
+               return;
+
+       cmd = iscsit_allocate_cmd(conn_p, GFP_KERNEL);
+       if (!cmd) {
+               iscsit_dec_conn_usage_count(conn_p);
+               return;
+       }
+
+       cmd->logout_cid = conn->cid;
+       cmd->iscsi_opcode = ISCSI_OP_ASYNC_EVENT;
+       cmd->i_state = ISTATE_SEND_ASYNCMSG;
+
+       spin_lock_bh(&conn_p->cmd_lock);
+       list_add_tail(&cmd->i_list, &conn_p->conn_cmd_list);
+       spin_unlock_bh(&conn_p->cmd_lock);
+
+       iscsit_add_cmd_to_response_queue(cmd, conn_p, cmd->i_state);
+       iscsit_dec_conn_usage_count(conn_p);
+}
+
+static int iscsit_send_conn_drop_async_message(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       struct iscsi_async *hdr;
+
+       cmd->tx_size = ISCSI_HDR_LEN;
+       cmd->iscsi_opcode = ISCSI_OP_ASYNC_EVENT;
+
+       hdr                     = (struct iscsi_async *) cmd->pdu;
+       hdr->opcode             = ISCSI_OP_ASYNC_EVENT;
+       hdr->flags              = ISCSI_FLAG_CMD_FINAL;
+       cmd->init_task_tag      = 0xFFFFFFFF;
+       cmd->targ_xfer_tag      = 0xFFFFFFFF;
+       put_unaligned_be64(0xFFFFFFFFFFFFFFFFULL, &hdr->rsvd4[0]);
+       cmd->stat_sn            = conn->stat_sn++;
+       hdr->statsn             = cpu_to_be32(cmd->stat_sn);
+       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->async_event        = ISCSI_ASYNC_MSG_DROPPING_CONNECTION;
+       hdr->param1             = cpu_to_be16(cmd->logout_cid);
+       hdr->param2             = cpu_to_be16(conn->sess->sess_ops->DefaultTime2Wait);
+       hdr->param3             = cpu_to_be16(conn->sess->sess_ops->DefaultTime2Retain);
+
+       if (conn->conn_ops->HeaderDigest) {
+               u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
+
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)hdr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)header_digest);
+
+               cmd->tx_size += ISCSI_CRC_LEN;
+               pr_debug("Attaching CRC32C HeaderDigest to"
+                       " Async Message 0x%08x\n", *header_digest);
+       }
+
+       cmd->iov_misc[0].iov_base       = cmd->pdu;
+       cmd->iov_misc[0].iov_len        = cmd->tx_size;
+       cmd->iov_misc_count             = 1;
+
+       pr_debug("Sending Connection Dropped Async Message StatSN:"
+               " 0x%08x, for CID: %hu on CID: %hu\n", cmd->stat_sn,
+                       cmd->logout_cid, conn->cid);
+       return 0;
+}
+
+static int iscsit_send_data_in(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn,
+       int *eodr)
+{
+       int iov_ret = 0, set_statsn = 0;
+       u32 iov_count = 0, tx_size = 0;
+       struct iscsi_datain datain;
+       struct iscsi_datain_req *dr;
+       struct iscsi_data_rsp *hdr;
+       struct kvec *iov;
+
+       memset(&datain, 0, sizeof(struct iscsi_datain));
+       dr = iscsit_get_datain_values(cmd, &datain);
+       if (!dr) {
+               pr_err("iscsit_get_datain_values failed for ITT: 0x%08x\n",
+                               cmd->init_task_tag);
+               return -1;
+       }
+
+       /*
+        * Be paranoid and double check the logic for now.
+        */
+       if ((datain.offset + datain.length) > cmd->data_length) {
+               pr_err("Command ITT: 0x%08x, datain.offset: %u and"
+                       " datain.length: %u exceeds cmd->data_length: %u\n",
+                       cmd->init_task_tag, datain.offset, datain.length,
+                               cmd->data_length);
+               return -1;
+       }
+
+       spin_lock_bh(&conn->sess->session_stats_lock);
+       conn->sess->tx_data_octets += datain.length;
+       if (conn->sess->se_sess->se_node_acl) {
+               spin_lock(&conn->sess->se_sess->se_node_acl->stats_lock);
+               conn->sess->se_sess->se_node_acl->read_bytes += datain.length;
+               spin_unlock(&conn->sess->se_sess->se_node_acl->stats_lock);
+       }
+       spin_unlock_bh(&conn->sess->session_stats_lock);
+       /*
+        * Special case for successfully execution w/ both DATAIN
+        * and Sense Data.
+        */
+       if ((datain.flags & ISCSI_FLAG_DATA_STATUS) &&
+           (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE))
+               datain.flags &= ~ISCSI_FLAG_DATA_STATUS;
+       else {
+               if ((dr->dr_complete == DATAIN_COMPLETE_NORMAL) ||
+                   (dr->dr_complete == DATAIN_COMPLETE_CONNECTION_RECOVERY)) {
+                       iscsit_increment_maxcmdsn(cmd, conn->sess);
+                       cmd->stat_sn = conn->stat_sn++;
+                       set_statsn = 1;
+               } else if (dr->dr_complete ==
+                               DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY)
+                       set_statsn = 1;
+       }
+
+       hdr     = (struct iscsi_data_rsp *) cmd->pdu;
+       memset(hdr, 0, ISCSI_HDR_LEN);
+       hdr->opcode             = ISCSI_OP_SCSI_DATA_IN;
+       hdr->flags              = datain.flags;
+       if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+               if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) {
+                       hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW;
+                       hdr->residual_count = cpu_to_be32(cmd->residual_count);
+               } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) {
+                       hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW;
+                       hdr->residual_count = cpu_to_be32(cmd->residual_count);
+               }
+       }
+       hton24(hdr->dlength, datain.length);
+       if (hdr->flags & ISCSI_FLAG_DATA_ACK)
+               int_to_scsilun(cmd->se_cmd.orig_fe_lun,
+                               (struct scsi_lun *)&hdr->lun);
+       else
+               put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
+
+       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->ttt                = (hdr->flags & ISCSI_FLAG_DATA_ACK) ?
+                                  cpu_to_be32(cmd->targ_xfer_tag) :
+                                  0xFFFFFFFF;
+       hdr->statsn             = (set_statsn) ? cpu_to_be32(cmd->stat_sn) :
+                                               0xFFFFFFFF;
+       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->datasn             = cpu_to_be32(datain.data_sn);
+       hdr->offset             = cpu_to_be32(datain.offset);
+
+       iov = &cmd->iov_data[0];
+       iov[iov_count].iov_base = cmd->pdu;
+       iov[iov_count++].iov_len        = ISCSI_HDR_LEN;
+       tx_size += ISCSI_HDR_LEN;
+
+       if (conn->conn_ops->HeaderDigest) {
+               u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
+
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)hdr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)header_digest);
+
+               iov[0].iov_len += ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+
+               pr_debug("Attaching CRC32 HeaderDigest"
+                       " for DataIN PDU 0x%08x\n", *header_digest);
+       }
+
+       iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[1], datain.offset, datain.length);
+       if (iov_ret < 0)
+               return -1;
+
+       iov_count += iov_ret;
+       tx_size += datain.length;
+
+       cmd->padding = ((-datain.length) & 3);
+       if (cmd->padding) {
+               iov[iov_count].iov_base         = cmd->pad_bytes;
+               iov[iov_count++].iov_len        = cmd->padding;
+               tx_size += cmd->padding;
+
+               pr_debug("Attaching %u padding bytes\n",
+                               cmd->padding);
+       }
+       if (conn->conn_ops->DataDigest) {
+               cmd->data_crc = iscsit_do_crypto_hash_sg(&conn->conn_tx_hash, cmd,
+                        datain.offset, datain.length, cmd->padding, cmd->pad_bytes);
+
+               iov[iov_count].iov_base = &cmd->data_crc;
+               iov[iov_count++].iov_len = ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+
+               pr_debug("Attached CRC32C DataDigest %d bytes, crc"
+                       " 0x%08x\n", datain.length+cmd->padding, cmd->data_crc);
+       }
+
+       cmd->iov_data_count = iov_count;
+       cmd->tx_size = tx_size;
+
+       pr_debug("Built DataIN ITT: 0x%08x, StatSN: 0x%08x,"
+               " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n",
+               cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn),
+               ntohl(hdr->offset), datain.length, conn->cid);
+
+       if (dr->dr_complete) {
+               *eodr = (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ?
+                               2 : 1;
+               iscsit_free_datain_req(cmd, dr);
+       }
+
+       return 0;
+}
+
+static int iscsit_send_logout_response(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       int niov = 0, tx_size;
+       struct iscsi_conn *logout_conn = NULL;
+       struct iscsi_conn_recovery *cr = NULL;
+       struct iscsi_session *sess = conn->sess;
+       struct kvec *iov;
+       struct iscsi_logout_rsp *hdr;
+       /*
+        * The actual shutting down of Sessions and/or Connections
+        * for CLOSESESSION and CLOSECONNECTION Logout Requests
+        * is done in scsi_logout_post_handler().
+        */
+       switch (cmd->logout_reason) {
+       case ISCSI_LOGOUT_REASON_CLOSE_SESSION:
+               pr_debug("iSCSI session logout successful, setting"
+                       " logout response to ISCSI_LOGOUT_SUCCESS.\n");
+               cmd->logout_response = ISCSI_LOGOUT_SUCCESS;
+               break;
+       case ISCSI_LOGOUT_REASON_CLOSE_CONNECTION:
+               if (cmd->logout_response == ISCSI_LOGOUT_CID_NOT_FOUND)
+                       break;
+               /*
+                * For CLOSECONNECTION logout requests carrying
+                * a matching logout CID -> local CID, the reference
+                * for the local CID will have been incremented in
+                * iscsi_logout_closeconnection().
+                *
+                * For CLOSECONNECTION logout requests carrying
+                * a different CID than the connection it arrived
+                * on, the connection responding to cmd->logout_cid
+                * is stopped in iscsit_logout_post_handler_diffcid().
+                */
+
+               pr_debug("iSCSI CID: %hu logout on CID: %hu"
+                       " successful.\n", cmd->logout_cid, conn->cid);
+               cmd->logout_response = ISCSI_LOGOUT_SUCCESS;
+               break;
+       case ISCSI_LOGOUT_REASON_RECOVERY:
+               if ((cmd->logout_response == ISCSI_LOGOUT_RECOVERY_UNSUPPORTED) ||
+                   (cmd->logout_response == ISCSI_LOGOUT_CLEANUP_FAILED))
+                       break;
+               /*
+                * If the connection is still active from our point of view
+                * force connection recovery to occur.
+                */
+               logout_conn = iscsit_get_conn_from_cid_rcfr(sess,
+                               cmd->logout_cid);
+               if ((logout_conn)) {
+                       iscsit_connection_reinstatement_rcfr(logout_conn);
+                       iscsit_dec_conn_usage_count(logout_conn);
+               }
+
+               cr = iscsit_get_inactive_connection_recovery_entry(
+                               conn->sess, cmd->logout_cid);
+               if (!cr) {
+                       pr_err("Unable to locate CID: %hu for"
+                       " REMOVECONNFORRECOVERY Logout Request.\n",
+                               cmd->logout_cid);
+                       cmd->logout_response = ISCSI_LOGOUT_CID_NOT_FOUND;
+                       break;
+               }
+
+               iscsit_discard_cr_cmds_by_expstatsn(cr, cmd->exp_stat_sn);
+
+               pr_debug("iSCSI REMOVECONNFORRECOVERY logout"
+                       " for recovery for CID: %hu on CID: %hu successful.\n",
+                               cmd->logout_cid, conn->cid);
+               cmd->logout_response = ISCSI_LOGOUT_SUCCESS;
+               break;
+       default:
+               pr_err("Unknown cmd->logout_reason: 0x%02x\n",
+                               cmd->logout_reason);
+               return -1;
+       }
+
+       tx_size = ISCSI_HDR_LEN;
+       hdr                     = (struct iscsi_logout_rsp *)cmd->pdu;
+       memset(hdr, 0, ISCSI_HDR_LEN);
+       hdr->opcode             = ISCSI_OP_LOGOUT_RSP;
+       hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
+       hdr->response           = cmd->logout_response;
+       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       cmd->stat_sn            = conn->stat_sn++;
+       hdr->statsn             = cpu_to_be32(cmd->stat_sn);
+
+       iscsit_increment_maxcmdsn(cmd, conn->sess);
+       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+
+       iov = &cmd->iov_misc[0];
+       iov[niov].iov_base      = cmd->pdu;
+       iov[niov++].iov_len     = ISCSI_HDR_LEN;
+
+       if (conn->conn_ops->HeaderDigest) {
+               u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
+
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)hdr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)header_digest);
+
+               iov[0].iov_len += ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+               pr_debug("Attaching CRC32C HeaderDigest to"
+                       " Logout Response 0x%08x\n", *header_digest);
+       }
+       cmd->iov_misc_count = niov;
+       cmd->tx_size = tx_size;
+
+       pr_debug("Sending Logout Response ITT: 0x%08x StatSN:"
+               " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n",
+               cmd->init_task_tag, cmd->stat_sn, hdr->response,
+               cmd->logout_cid, conn->cid);
+
+       return 0;
+}
+
+/*
+ *     Unsolicited NOPIN, either requesting a response or not.
+ */
+static int iscsit_send_unsolicited_nopin(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn,
+       int want_response)
+{
+       int tx_size = ISCSI_HDR_LEN;
+       struct iscsi_nopin *hdr;
+
+       hdr                     = (struct iscsi_nopin *) cmd->pdu;
+       memset(hdr, 0, ISCSI_HDR_LEN);
+       hdr->opcode             = ISCSI_OP_NOOP_IN;
+       hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
+       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->ttt                = cpu_to_be32(cmd->targ_xfer_tag);
+       cmd->stat_sn            = conn->stat_sn;
+       hdr->statsn             = cpu_to_be32(cmd->stat_sn);
+       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+
+       if (conn->conn_ops->HeaderDigest) {
+               u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
+
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)hdr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)header_digest);
+
+               tx_size += ISCSI_CRC_LEN;
+               pr_debug("Attaching CRC32C HeaderDigest to"
+                       " NopIN 0x%08x\n", *header_digest);
+       }
+
+       cmd->iov_misc[0].iov_base       = cmd->pdu;
+       cmd->iov_misc[0].iov_len        = tx_size;
+       cmd->iov_misc_count     = 1;
+       cmd->tx_size            = tx_size;
+
+       pr_debug("Sending Unsolicited NOPIN TTT: 0x%08x StatSN:"
+               " 0x%08x CID: %hu\n", hdr->ttt, cmd->stat_sn, conn->cid);
+
+       return 0;
+}
+
+static int iscsit_send_nopin_response(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       int niov = 0, tx_size;
+       u32 padding = 0;
+       struct kvec *iov;
+       struct iscsi_nopin *hdr;
+
+       tx_size = ISCSI_HDR_LEN;
+       hdr                     = (struct iscsi_nopin *) cmd->pdu;
+       memset(hdr, 0, ISCSI_HDR_LEN);
+       hdr->opcode             = ISCSI_OP_NOOP_IN;
+       hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
+       hton24(hdr->dlength, cmd->buf_ptr_size);
+       put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
+       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->ttt                = cpu_to_be32(cmd->targ_xfer_tag);
+       cmd->stat_sn            = conn->stat_sn++;
+       hdr->statsn             = cpu_to_be32(cmd->stat_sn);
+
+       iscsit_increment_maxcmdsn(cmd, conn->sess);
+       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+
+       iov = &cmd->iov_misc[0];
+       iov[niov].iov_base      = cmd->pdu;
+       iov[niov++].iov_len     = ISCSI_HDR_LEN;
+
+       if (conn->conn_ops->HeaderDigest) {
+               u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
+
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)hdr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)header_digest);
+
+               iov[0].iov_len += ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+               pr_debug("Attaching CRC32C HeaderDigest"
+                       " to NopIn 0x%08x\n", *header_digest);
+       }
+
+       /*
+        * NOPOUT Ping Data is attached to struct iscsi_cmd->buf_ptr.
+        * NOPOUT DataSegmentLength is at struct iscsi_cmd->buf_ptr_size.
+        */
+       if (cmd->buf_ptr_size) {
+               iov[niov].iov_base      = cmd->buf_ptr;
+               iov[niov++].iov_len     = cmd->buf_ptr_size;
+               tx_size += cmd->buf_ptr_size;
+
+               pr_debug("Echoing back %u bytes of ping"
+                       " data.\n", cmd->buf_ptr_size);
+
+               padding = ((-cmd->buf_ptr_size) & 3);
+               if (padding != 0) {
+                       iov[niov].iov_base = &cmd->pad_bytes;
+                       iov[niov++].iov_len = padding;
+                       tx_size += padding;
+                       pr_debug("Attaching %u additional"
+                               " padding bytes.\n", padding);
+               }
+               if (conn->conn_ops->DataDigest) {
+                       iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               cmd->buf_ptr, cmd->buf_ptr_size,
+                               padding, (u8 *)&cmd->pad_bytes,
+                               (u8 *)&cmd->data_crc);
+
+                       iov[niov].iov_base = &cmd->data_crc;
+                       iov[niov++].iov_len = ISCSI_CRC_LEN;
+                       tx_size += ISCSI_CRC_LEN;
+                       pr_debug("Attached DataDigest for %u"
+                               " bytes of ping data, CRC 0x%08x\n",
+                               cmd->buf_ptr_size, cmd->data_crc);
+               }
+       }
+
+       cmd->iov_misc_count = niov;
+       cmd->tx_size = tx_size;
+
+       pr_debug("Sending NOPIN Response ITT: 0x%08x, TTT:"
+               " 0x%08x, StatSN: 0x%08x, Length %u\n", cmd->init_task_tag,
+               cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size);
+
+       return 0;
+}
+
+int iscsit_send_r2t(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       int tx_size = 0;
+       struct iscsi_r2t *r2t;
+       struct iscsi_r2t_rsp *hdr;
+
+       r2t = iscsit_get_r2t_from_list(cmd);
+       if (!r2t)
+               return -1;
+
+       hdr                     = (struct iscsi_r2t_rsp *) cmd->pdu;
+       memset(hdr, 0, ISCSI_HDR_LEN);
+       hdr->opcode             = ISCSI_OP_R2T;
+       hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
+       int_to_scsilun(cmd->se_cmd.orig_fe_lun,
+                       (struct scsi_lun *)&hdr->lun);
+       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       spin_lock_bh(&conn->sess->ttt_lock);
+       r2t->targ_xfer_tag      = conn->sess->targ_xfer_tag++;
+       if (r2t->targ_xfer_tag == 0xFFFFFFFF)
+               r2t->targ_xfer_tag = conn->sess->targ_xfer_tag++;
+       spin_unlock_bh(&conn->sess->ttt_lock);
+       hdr->ttt                = cpu_to_be32(r2t->targ_xfer_tag);
+       hdr->statsn             = cpu_to_be32(conn->stat_sn);
+       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+       hdr->r2tsn              = cpu_to_be32(r2t->r2t_sn);
+       hdr->data_offset        = cpu_to_be32(r2t->offset);
+       hdr->data_length        = cpu_to_be32(r2t->xfer_len);
+
+       cmd->iov_misc[0].iov_base       = cmd->pdu;
+       cmd->iov_misc[0].iov_len        = ISCSI_HDR_LEN;
+       tx_size += ISCSI_HDR_LEN;
+
+       if (conn->conn_ops->HeaderDigest) {
+               u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
+
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)hdr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)header_digest);
+
+               cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+               pr_debug("Attaching CRC32 HeaderDigest for R2T"
+                       " PDU 0x%08x\n", *header_digest);
+       }
+
+       pr_debug("Built %sR2T, ITT: 0x%08x, TTT: 0x%08x, StatSN:"
+               " 0x%08x, R2TSN: 0x%08x, Offset: %u, DDTL: %u, CID: %hu\n",
+               (!r2t->recovery_r2t) ? "" : "Recovery ", cmd->init_task_tag,
+               r2t->targ_xfer_tag, ntohl(hdr->statsn), r2t->r2t_sn,
+                       r2t->offset, r2t->xfer_len, conn->cid);
+
+       cmd->iov_misc_count = 1;
+       cmd->tx_size = tx_size;
+
+       spin_lock_bh(&cmd->r2t_lock);
+       r2t->sent_r2t = 1;
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       return 0;
+}
+
+/*
+ *     type 0: Normal Operation.
+ *     type 1: Called from Storage Transport.
+ *     type 2: Called from iscsi_task_reassign_complete_write() for
+ *             connection recovery.
+ */
+int iscsit_build_r2ts_for_cmd(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn,
+       int type)
+{
+       int first_r2t = 1;
+       u32 offset = 0, xfer_len = 0;
+
+       spin_lock_bh(&cmd->r2t_lock);
+       if (cmd->cmd_flags & ICF_SENT_LAST_R2T) {
+               spin_unlock_bh(&cmd->r2t_lock);
+               return 0;
+       }
+
+       if (conn->sess->sess_ops->DataSequenceInOrder && (type != 2))
+               if (cmd->r2t_offset < cmd->write_data_done)
+                       cmd->r2t_offset = cmd->write_data_done;
+
+       while (cmd->outstanding_r2ts < conn->sess->sess_ops->MaxOutstandingR2T) {
+               if (conn->sess->sess_ops->DataSequenceInOrder) {
+                       offset = cmd->r2t_offset;
+
+                       if (first_r2t && (type == 2)) {
+                               xfer_len = ((offset +
+                                            (conn->sess->sess_ops->MaxBurstLength -
+                                            cmd->next_burst_len) >
+                                            cmd->data_length) ?
+                                           (cmd->data_length - offset) :
+                                           (conn->sess->sess_ops->MaxBurstLength -
+                                            cmd->next_burst_len));
+                       } else {
+                               xfer_len = ((offset +
+                                            conn->sess->sess_ops->MaxBurstLength) >
+                                            cmd->data_length) ?
+                                            (cmd->data_length - offset) :
+                                            conn->sess->sess_ops->MaxBurstLength;
+                       }
+                       cmd->r2t_offset += xfer_len;
+
+                       if (cmd->r2t_offset == cmd->data_length)
+                               cmd->cmd_flags |= ICF_SENT_LAST_R2T;
+               } else {
+                       struct iscsi_seq *seq;
+
+                       seq = iscsit_get_seq_holder_for_r2t(cmd);
+                       if (!seq) {
+                               spin_unlock_bh(&cmd->r2t_lock);
+                               return -1;
+                       }
+
+                       offset = seq->offset;
+                       xfer_len = seq->xfer_len;
+
+                       if (cmd->seq_send_order == cmd->seq_count)
+                               cmd->cmd_flags |= ICF_SENT_LAST_R2T;
+               }
+               cmd->outstanding_r2ts++;
+               first_r2t = 0;
+
+               if (iscsit_add_r2t_to_list(cmd, offset, xfer_len, 0, 0) < 0) {
+                       spin_unlock_bh(&cmd->r2t_lock);
+                       return -1;
+               }
+
+               if (cmd->cmd_flags & ICF_SENT_LAST_R2T)
+                       break;
+       }
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       return 0;
+}
+
+static int iscsit_send_status(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       u8 iov_count = 0, recovery;
+       u32 padding = 0, tx_size = 0;
+       struct iscsi_scsi_rsp *hdr;
+       struct kvec *iov;
+
+       recovery = (cmd->i_state != ISTATE_SEND_STATUS);
+       if (!recovery)
+               cmd->stat_sn = conn->stat_sn++;
+
+       spin_lock_bh(&conn->sess->session_stats_lock);
+       conn->sess->rsp_pdus++;
+       spin_unlock_bh(&conn->sess->session_stats_lock);
+
+       hdr                     = (struct iscsi_scsi_rsp *) cmd->pdu;
+       memset(hdr, 0, ISCSI_HDR_LEN);
+       hdr->opcode             = ISCSI_OP_SCSI_CMD_RSP;
+       hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
+       if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) {
+               hdr->flags |= ISCSI_FLAG_CMD_OVERFLOW;
+               hdr->residual_count = cpu_to_be32(cmd->residual_count);
+       } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) {
+               hdr->flags |= ISCSI_FLAG_CMD_UNDERFLOW;
+               hdr->residual_count = cpu_to_be32(cmd->residual_count);
+       }
+       hdr->response           = cmd->iscsi_response;
+       hdr->cmd_status         = cmd->se_cmd.scsi_status;
+       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->statsn             = cpu_to_be32(cmd->stat_sn);
+
+       iscsit_increment_maxcmdsn(cmd, conn->sess);
+       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+
+       iov = &cmd->iov_misc[0];
+       iov[iov_count].iov_base = cmd->pdu;
+       iov[iov_count++].iov_len = ISCSI_HDR_LEN;
+       tx_size += ISCSI_HDR_LEN;
+
+       /*
+        * Attach SENSE DATA payload to iSCSI Response PDU
+        */
+       if (cmd->se_cmd.sense_buffer &&
+          ((cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
+           (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
+               padding         = -(cmd->se_cmd.scsi_sense_length) & 3;
+               hton24(hdr->dlength, cmd->se_cmd.scsi_sense_length);
+               iov[iov_count].iov_base = cmd->se_cmd.sense_buffer;
+               iov[iov_count++].iov_len =
+                               (cmd->se_cmd.scsi_sense_length + padding);
+               tx_size += cmd->se_cmd.scsi_sense_length;
+
+               if (padding) {
+                       memset(cmd->se_cmd.sense_buffer +
+                               cmd->se_cmd.scsi_sense_length, 0, padding);
+                       tx_size += padding;
+                       pr_debug("Adding %u bytes of padding to"
+                               " SENSE.\n", padding);
+               }
+
+               if (conn->conn_ops->DataDigest) {
+                       iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               cmd->se_cmd.sense_buffer,
+                               (cmd->se_cmd.scsi_sense_length + padding),
+                               0, NULL, (u8 *)&cmd->data_crc);
+
+                       iov[iov_count].iov_base    = &cmd->data_crc;
+                       iov[iov_count++].iov_len     = ISCSI_CRC_LEN;
+                       tx_size += ISCSI_CRC_LEN;
+
+                       pr_debug("Attaching CRC32 DataDigest for"
+                               " SENSE, %u bytes CRC 0x%08x\n",
+                               (cmd->se_cmd.scsi_sense_length + padding),
+                               cmd->data_crc);
+               }
+
+               pr_debug("Attaching SENSE DATA: %u bytes to iSCSI"
+                               " Response PDU\n",
+                               cmd->se_cmd.scsi_sense_length);
+       }
+
+       if (conn->conn_ops->HeaderDigest) {
+               u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
+
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)hdr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)header_digest);
+
+               iov[0].iov_len += ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+               pr_debug("Attaching CRC32 HeaderDigest for Response"
+                               " PDU 0x%08x\n", *header_digest);
+       }
+
+       cmd->iov_misc_count = iov_count;
+       cmd->tx_size = tx_size;
+
+       pr_debug("Built %sSCSI Response, ITT: 0x%08x, StatSN: 0x%08x,"
+               " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n",
+               (!recovery) ? "" : "Recovery ", cmd->init_task_tag,
+               cmd->stat_sn, 0x00, cmd->se_cmd.scsi_status, conn->cid);
+
+       return 0;
+}
+
+static u8 iscsit_convert_tcm_tmr_rsp(struct se_tmr_req *se_tmr)
+{
+       switch (se_tmr->response) {
+       case TMR_FUNCTION_COMPLETE:
+               return ISCSI_TMF_RSP_COMPLETE;
+       case TMR_TASK_DOES_NOT_EXIST:
+               return ISCSI_TMF_RSP_NO_TASK;
+       case TMR_LUN_DOES_NOT_EXIST:
+               return ISCSI_TMF_RSP_NO_LUN;
+       case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
+               return ISCSI_TMF_RSP_NOT_SUPPORTED;
+       case TMR_FUNCTION_AUTHORIZATION_FAILED:
+               return ISCSI_TMF_RSP_AUTH_FAILED;
+       case TMR_FUNCTION_REJECTED:
+       default:
+               return ISCSI_TMF_RSP_REJECTED;
+       }
+}
+
+static int iscsit_send_task_mgt_rsp(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
+       struct iscsi_tm_rsp *hdr;
+       u32 tx_size = 0;
+
+       hdr                     = (struct iscsi_tm_rsp *) cmd->pdu;
+       memset(hdr, 0, ISCSI_HDR_LEN);
+       hdr->opcode             = ISCSI_OP_SCSI_TMFUNC_RSP;
+       hdr->response           = iscsit_convert_tcm_tmr_rsp(se_tmr);
+       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       cmd->stat_sn            = conn->stat_sn++;
+       hdr->statsn             = cpu_to_be32(cmd->stat_sn);
+
+       iscsit_increment_maxcmdsn(cmd, conn->sess);
+       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+
+       cmd->iov_misc[0].iov_base       = cmd->pdu;
+       cmd->iov_misc[0].iov_len        = ISCSI_HDR_LEN;
+       tx_size += ISCSI_HDR_LEN;
+
+       if (conn->conn_ops->HeaderDigest) {
+               u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
+
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)hdr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)header_digest);
+
+               cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+               pr_debug("Attaching CRC32 HeaderDigest for Task"
+                       " Mgmt Response PDU 0x%08x\n", *header_digest);
+       }
+
+       cmd->iov_misc_count = 1;
+       cmd->tx_size = tx_size;
+
+       pr_debug("Built Task Management Response ITT: 0x%08x,"
+               " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n",
+               cmd->init_task_tag, cmd->stat_sn, hdr->response, conn->cid);
+
+       return 0;
+}
+
+static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
+{
+       char *payload = NULL;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_portal_group *tpg;
+       struct iscsi_tiqn *tiqn;
+       struct iscsi_tpg_np *tpg_np;
+       int buffer_len, end_of_buf = 0, len = 0, payload_len = 0;
+       unsigned char buf[256];
+
+       buffer_len = (conn->conn_ops->MaxRecvDataSegmentLength > 32768) ?
+                       32768 : conn->conn_ops->MaxRecvDataSegmentLength;
+
+       memset(buf, 0, 256);
+
+       payload = kzalloc(buffer_len, GFP_KERNEL);
+       if (!payload) {
+               pr_err("Unable to allocate memory for sendtargets"
+                               " response.\n");
+               return -ENOMEM;
+       }
+
+       spin_lock(&tiqn_lock);
+       list_for_each_entry(tiqn, &g_tiqn_list, tiqn_list) {
+               len = sprintf(buf, "TargetName=%s", tiqn->tiqn);
+               len += 1;
+
+               if ((len + payload_len) > buffer_len) {
+                       spin_unlock(&tiqn->tiqn_tpg_lock);
+                       end_of_buf = 1;
+                       goto eob;
+               }
+               memcpy((void *)payload + payload_len, buf, len);
+               payload_len += len;
+
+               spin_lock(&tiqn->tiqn_tpg_lock);
+               list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) {
+
+                       spin_lock(&tpg->tpg_state_lock);
+                       if ((tpg->tpg_state == TPG_STATE_FREE) ||
+                           (tpg->tpg_state == TPG_STATE_INACTIVE)) {
+                               spin_unlock(&tpg->tpg_state_lock);
+                               continue;
+                       }
+                       spin_unlock(&tpg->tpg_state_lock);
+
+                       spin_lock(&tpg->tpg_np_lock);
+                       list_for_each_entry(tpg_np, &tpg->tpg_gnp_list,
+                                               tpg_np_list) {
+                               len = sprintf(buf, "TargetAddress="
+                                       "%s%s%s:%hu,%hu",
+                                       (tpg_np->tpg_np->np_sockaddr.ss_family == AF_INET6) ?
+                                       "[" : "", tpg_np->tpg_np->np_ip,
+                                       (tpg_np->tpg_np->np_sockaddr.ss_family == AF_INET6) ?
+                                       "]" : "", tpg_np->tpg_np->np_port,
+                                       tpg->tpgt);
+                               len += 1;
+
+                               if ((len + payload_len) > buffer_len) {
+                                       spin_unlock(&tpg->tpg_np_lock);
+                                       spin_unlock(&tiqn->tiqn_tpg_lock);
+                                       end_of_buf = 1;
+                                       goto eob;
+                               }
+                               memcpy((void *)payload + payload_len, buf, len);
+                               payload_len += len;
+                       }
+                       spin_unlock(&tpg->tpg_np_lock);
+               }
+               spin_unlock(&tiqn->tiqn_tpg_lock);
+eob:
+               if (end_of_buf)
+                       break;
+       }
+       spin_unlock(&tiqn_lock);
+
+       cmd->buf_ptr = payload;
+
+       return payload_len;
+}
+
+/*
+ *     FIXME: Add support for F_BIT and C_BIT when the length is longer than
+ *     MaxRecvDataSegmentLength.
+ */
+static int iscsit_send_text_rsp(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       struct iscsi_text_rsp *hdr;
+       struct kvec *iov;
+       u32 padding = 0, tx_size = 0;
+       int text_length, iov_count = 0;
+
+       text_length = iscsit_build_sendtargets_response(cmd);
+       if (text_length < 0)
+               return text_length;
+
+       padding = ((-text_length) & 3);
+       if (padding != 0) {
+               memset(cmd->buf_ptr + text_length, 0, padding);
+               pr_debug("Attaching %u additional bytes for"
+                       " padding.\n", padding);
+       }
+
+       hdr                     = (struct iscsi_text_rsp *) cmd->pdu;
+       memset(hdr, 0, ISCSI_HDR_LEN);
+       hdr->opcode             = ISCSI_OP_TEXT_RSP;
+       hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
+       hton24(hdr->dlength, text_length);
+       hdr->itt                = cpu_to_be32(cmd->init_task_tag);
+       hdr->ttt                = cpu_to_be32(cmd->targ_xfer_tag);
+       cmd->stat_sn            = conn->stat_sn++;
+       hdr->statsn             = cpu_to_be32(cmd->stat_sn);
+
+       iscsit_increment_maxcmdsn(cmd, conn->sess);
+       hdr->exp_cmdsn          = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn          = cpu_to_be32(conn->sess->max_cmd_sn);
+
+       iov = &cmd->iov_misc[0];
+
+       iov[iov_count].iov_base = cmd->pdu;
+       iov[iov_count++].iov_len = ISCSI_HDR_LEN;
+       iov[iov_count].iov_base = cmd->buf_ptr;
+       iov[iov_count++].iov_len = text_length + padding;
+
+       tx_size += (ISCSI_HDR_LEN + text_length + padding);
+
+       if (conn->conn_ops->HeaderDigest) {
+               u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
+
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)hdr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)header_digest);
+
+               iov[0].iov_len += ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+               pr_debug("Attaching CRC32 HeaderDigest for"
+                       " Text Response PDU 0x%08x\n", *header_digest);
+       }
+
+       if (conn->conn_ops->DataDigest) {
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               cmd->buf_ptr, (text_length + padding),
+                               0, NULL, (u8 *)&cmd->data_crc);
+
+               iov[iov_count].iov_base = &cmd->data_crc;
+               iov[iov_count++].iov_len = ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+
+               pr_debug("Attaching DataDigest for %u bytes of text"
+                       " data, CRC 0x%08x\n", (text_length + padding),
+                       cmd->data_crc);
+       }
+
+       cmd->iov_misc_count = iov_count;
+       cmd->tx_size = tx_size;
+
+       pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x,"
+               " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn,
+                       text_length, conn->cid);
+       return 0;
+}
+
+static int iscsit_send_reject(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       u32 iov_count = 0, tx_size = 0;
+       struct iscsi_reject *hdr;
+       struct kvec *iov;
+
+       hdr                     = (struct iscsi_reject *) cmd->pdu;
+       hdr->opcode             = ISCSI_OP_REJECT;
+       hdr->flags              |= ISCSI_FLAG_CMD_FINAL;
+       hton24(hdr->dlength, ISCSI_HDR_LEN);
+       cmd->stat_sn            = conn->stat_sn++;
+       hdr->statsn             = cpu_to_be32(cmd->stat_sn);
+       hdr->exp_cmdsn  = cpu_to_be32(conn->sess->exp_cmd_sn);
+       hdr->max_cmdsn  = cpu_to_be32(conn->sess->max_cmd_sn);
+
+       iov = &cmd->iov_misc[0];
+
+       iov[iov_count].iov_base = cmd->pdu;
+       iov[iov_count++].iov_len = ISCSI_HDR_LEN;
+       iov[iov_count].iov_base = cmd->buf_ptr;
+       iov[iov_count++].iov_len = ISCSI_HDR_LEN;
+
+       tx_size = (ISCSI_HDR_LEN + ISCSI_HDR_LEN);
+
+       if (conn->conn_ops->HeaderDigest) {
+               u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
+
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)hdr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)header_digest);
+
+               iov[0].iov_len += ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+               pr_debug("Attaching CRC32 HeaderDigest for"
+                       " REJECT PDU 0x%08x\n", *header_digest);
+       }
+
+       if (conn->conn_ops->DataDigest) {
+               iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
+                               (unsigned char *)cmd->buf_ptr, ISCSI_HDR_LEN,
+                               0, NULL, (u8 *)&cmd->data_crc);
+
+               iov[iov_count].iov_base = &cmd->data_crc;
+               iov[iov_count++].iov_len  = ISCSI_CRC_LEN;
+               tx_size += ISCSI_CRC_LEN;
+               pr_debug("Attaching CRC32 DataDigest for REJECT"
+                               " PDU 0x%08x\n", cmd->data_crc);
+       }
+
+       cmd->iov_misc_count = iov_count;
+       cmd->tx_size = tx_size;
+
+       pr_debug("Built Reject PDU StatSN: 0x%08x, Reason: 0x%02x,"
+               " CID: %hu\n", ntohl(hdr->statsn), hdr->reason, conn->cid);
+
+       return 0;
+}
+
+static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn)
+{
+       if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) ||
+           (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) {
+               wait_for_completion_interruptible_timeout(
+                                       &conn->tx_half_close_comp,
+                                       ISCSI_TX_THREAD_TCP_TIMEOUT * HZ);
+       }
+}
+
+#ifdef CONFIG_SMP
+
+void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
+{
+       struct iscsi_thread_set *ts = conn->thread_set;
+       int ord, cpu;
+       /*
+        * thread_id is assigned from iscsit_global->ts_bitmap from
+        * within iscsi_thread_set.c:iscsi_allocate_thread_sets()
+        *
+        * Here we use thread_id to determine which CPU that this
+        * iSCSI connection's iscsi_thread_set will be scheduled to
+        * execute upon.
+        */
+       ord = ts->thread_id % cpumask_weight(cpu_online_mask);
+#if 0
+       pr_debug(">>>>>>>>>>>>>>>>>>>> Generated ord: %d from"
+                       " thread_id: %d\n", ord, ts->thread_id);
+#endif
+       for_each_online_cpu(cpu) {
+               if (ord-- == 0) {
+                       cpumask_set_cpu(cpu, conn->conn_cpumask);
+                       return;
+               }
+       }
+       /*
+        * This should never be reached..
+        */
+       dump_stack();
+       cpumask_setall(conn->conn_cpumask);
+}
+
+static inline void iscsit_thread_check_cpumask(
+       struct iscsi_conn *conn,
+       struct task_struct *p,
+       int mode)
+{
+       char buf[128];
+       /*
+        * mode == 1 signals iscsi_target_tx_thread() usage.
+        * mode == 0 signals iscsi_target_rx_thread() usage.
+        */
+       if (mode == 1) {
+               if (!conn->conn_tx_reset_cpumask)
+                       return;
+               conn->conn_tx_reset_cpumask = 0;
+       } else {
+               if (!conn->conn_rx_reset_cpumask)
+                       return;
+               conn->conn_rx_reset_cpumask = 0;
+       }
+       /*
+        * Update the CPU mask for this single kthread so that
+        * both TX and RX kthreads are scheduled to run on the
+        * same CPU.
+        */
+       memset(buf, 0, 128);
+       cpumask_scnprintf(buf, 128, conn->conn_cpumask);
+#if 0
+       pr_debug(">>>>>>>>>>>>>> Calling set_cpus_allowed_ptr():"
+                       " %s for %s\n", buf, p->comm);
+#endif
+       set_cpus_allowed_ptr(p, conn->conn_cpumask);
+}
+
+#else
+#define iscsit_thread_get_cpumask(X) ({})
+#define iscsit_thread_check_cpumask(X, Y, Z) ({})
+#endif /* CONFIG_SMP */
+
+int iscsi_target_tx_thread(void *arg)
+{
+       u8 state;
+       int eodr = 0;
+       int ret = 0;
+       int sent_status = 0;
+       int use_misc = 0;
+       int map_sg = 0;
+       struct iscsi_cmd *cmd = NULL;
+       struct iscsi_conn *conn;
+       struct iscsi_queue_req *qr = NULL;
+       struct se_cmd *se_cmd;
+       struct iscsi_thread_set *ts = (struct iscsi_thread_set *)arg;
+       /*
+        * Allow ourselves to be interrupted by SIGINT so that a
+        * connection recovery / failure event can be triggered externally.
+        */
+       allow_signal(SIGINT);
+
+restart:
+       conn = iscsi_tx_thread_pre_handler(ts);
+       if (!conn)
+               goto out;
+
+       eodr = map_sg = ret = sent_status = use_misc = 0;
+
+       while (!kthread_should_stop()) {
+               /*
+                * Ensure that both TX and RX per connection kthreads
+                * are scheduled to run on the same CPU.
+                */
+               iscsit_thread_check_cpumask(conn, current, 1);
+
+               schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
+
+               if ((ts->status == ISCSI_THREAD_SET_RESET) ||
+                    signal_pending(current))
+                       goto transport_err;
+
+get_immediate:
+               qr = iscsit_get_cmd_from_immediate_queue(conn);
+               if (qr) {
+                       atomic_set(&conn->check_immediate_queue, 0);
+                       cmd = qr->cmd;
+                       state = qr->state;
+                       kmem_cache_free(lio_qr_cache, qr);
+
+                       spin_lock_bh(&cmd->istate_lock);
+                       switch (state) {
+                       case ISTATE_SEND_R2T:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               ret = iscsit_send_r2t(cmd, conn);
+                               break;
+                       case ISTATE_REMOVE:
+                               spin_unlock_bh(&cmd->istate_lock);
+
+                               if (cmd->data_direction == DMA_TO_DEVICE)
+                                       iscsit_stop_dataout_timer(cmd);
+
+                               spin_lock_bh(&conn->cmd_lock);
+                               list_del(&cmd->i_list);
+                               spin_unlock_bh(&conn->cmd_lock);
+                               /*
+                                * Determine if a struct se_cmd is assoicated with
+                                * this struct iscsi_cmd.
+                                */
+                               if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) &&
+                                   !(cmd->tmr_req))
+                                       iscsit_release_cmd(cmd);
+                               else
+                                       transport_generic_free_cmd(&cmd->se_cmd,
+                                                               1, 0);
+                               goto get_immediate;
+                       case ISTATE_SEND_NOPIN_WANT_RESPONSE:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               iscsit_mod_nopin_response_timer(conn);
+                               ret = iscsit_send_unsolicited_nopin(cmd,
+                                               conn, 1);
+                               break;
+                       case ISTATE_SEND_NOPIN_NO_RESPONSE:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               ret = iscsit_send_unsolicited_nopin(cmd,
+                                               conn, 0);
+                               break;
+                       default:
+                               pr_err("Unknown Opcode: 0x%02x ITT:"
+                               " 0x%08x, i_state: %d on CID: %hu\n",
+                               cmd->iscsi_opcode, cmd->init_task_tag, state,
+                               conn->cid);
+                               spin_unlock_bh(&cmd->istate_lock);
+                               goto transport_err;
+                       }
+                       if (ret < 0) {
+                               conn->tx_immediate_queue = 0;
+                               goto transport_err;
+                       }
+
+                       if (iscsit_send_tx_data(cmd, conn, 1) < 0) {
+                               conn->tx_immediate_queue = 0;
+                               iscsit_tx_thread_wait_for_tcp(conn);
+                               goto transport_err;
+                       }
+
+                       spin_lock_bh(&cmd->istate_lock);
+                       switch (state) {
+                       case ISTATE_SEND_R2T:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               spin_lock_bh(&cmd->dataout_timeout_lock);
+                               iscsit_start_dataout_timer(cmd, conn);
+                               spin_unlock_bh(&cmd->dataout_timeout_lock);
+                               break;
+                       case ISTATE_SEND_NOPIN_WANT_RESPONSE:
+                               cmd->i_state = ISTATE_SENT_NOPIN_WANT_RESPONSE;
+                               spin_unlock_bh(&cmd->istate_lock);
+                               break;
+                       case ISTATE_SEND_NOPIN_NO_RESPONSE:
+                               cmd->i_state = ISTATE_SENT_STATUS;
+                               spin_unlock_bh(&cmd->istate_lock);
+                               break;
+                       default:
+                               pr_err("Unknown Opcode: 0x%02x ITT:"
+                                       " 0x%08x, i_state: %d on CID: %hu\n",
+                                       cmd->iscsi_opcode, cmd->init_task_tag,
+                                       state, conn->cid);
+                               spin_unlock_bh(&cmd->istate_lock);
+                               goto transport_err;
+                       }
+                       goto get_immediate;
+               } else
+                       conn->tx_immediate_queue = 0;
+
+get_response:
+               qr = iscsit_get_cmd_from_response_queue(conn);
+               if (qr) {
+                       cmd = qr->cmd;
+                       state = qr->state;
+                       kmem_cache_free(lio_qr_cache, qr);
+
+                       spin_lock_bh(&cmd->istate_lock);
+check_rsp_state:
+                       switch (state) {
+                       case ISTATE_SEND_DATAIN:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               ret = iscsit_send_data_in(cmd, conn,
+                                                         &eodr);
+                               map_sg = 1;
+                               break;
+                       case ISTATE_SEND_STATUS:
+                       case ISTATE_SEND_STATUS_RECOVERY:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               use_misc = 1;
+                               ret = iscsit_send_status(cmd, conn);
+                               break;
+                       case ISTATE_SEND_LOGOUTRSP:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               use_misc = 1;
+                               ret = iscsit_send_logout_response(cmd, conn);
+                               break;
+                       case ISTATE_SEND_ASYNCMSG:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               use_misc = 1;
+                               ret = iscsit_send_conn_drop_async_message(
+                                               cmd, conn);
+                               break;
+                       case ISTATE_SEND_NOPIN:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               use_misc = 1;
+                               ret = iscsit_send_nopin_response(cmd, conn);
+                               break;
+                       case ISTATE_SEND_REJECT:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               use_misc = 1;
+                               ret = iscsit_send_reject(cmd, conn);
+                               break;
+                       case ISTATE_SEND_TASKMGTRSP:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               use_misc = 1;
+                               ret = iscsit_send_task_mgt_rsp(cmd, conn);
+                               if (ret != 0)
+                                       break;
+                               ret = iscsit_tmr_post_handler(cmd, conn);
+                               if (ret != 0)
+                                       iscsit_fall_back_to_erl0(conn->sess);
+                               break;
+                       case ISTATE_SEND_TEXTRSP:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               use_misc = 1;
+                               ret = iscsit_send_text_rsp(cmd, conn);
+                               break;
+                       default:
+                               pr_err("Unknown Opcode: 0x%02x ITT:"
+                                       " 0x%08x, i_state: %d on CID: %hu\n",
+                                       cmd->iscsi_opcode, cmd->init_task_tag,
+                                       state, conn->cid);
+                               spin_unlock_bh(&cmd->istate_lock);
+                               goto transport_err;
+                       }
+                       if (ret < 0) {
+                               conn->tx_response_queue = 0;
+                               goto transport_err;
+                       }
+
+                       se_cmd = &cmd->se_cmd;
+
+                       if (map_sg && !conn->conn_ops->IFMarker) {
+                               if (iscsit_fe_sendpage_sg(cmd, conn) < 0) {
+                                       conn->tx_response_queue = 0;
+                                       iscsit_tx_thread_wait_for_tcp(conn);
+                                       iscsit_unmap_iovec(cmd);
+                                       goto transport_err;
+                               }
+                       } else {
+                               if (iscsit_send_tx_data(cmd, conn, use_misc) < 0) {
+                                       conn->tx_response_queue = 0;
+                                       iscsit_tx_thread_wait_for_tcp(conn);
+                                       iscsit_unmap_iovec(cmd);
+                                       goto transport_err;
+                               }
+                       }
+                       map_sg = 0;
+                       iscsit_unmap_iovec(cmd);
+
+                       spin_lock_bh(&cmd->istate_lock);
+                       switch (state) {
+                       case ISTATE_SEND_DATAIN:
+                               if (!eodr)
+                                       goto check_rsp_state;
+
+                               if (eodr == 1) {
+                                       cmd->i_state = ISTATE_SENT_LAST_DATAIN;
+                                       sent_status = 1;
+                                       eodr = use_misc = 0;
+                               } else if (eodr == 2) {
+                                       cmd->i_state = state =
+                                                       ISTATE_SEND_STATUS;
+                                       sent_status = 0;
+                                       eodr = use_misc = 0;
+                                       goto check_rsp_state;
+                               }
+                               break;
+                       case ISTATE_SEND_STATUS:
+                               use_misc = 0;
+                               sent_status = 1;
+                               break;
+                       case ISTATE_SEND_ASYNCMSG:
+                       case ISTATE_SEND_NOPIN:
+                       case ISTATE_SEND_STATUS_RECOVERY:
+                       case ISTATE_SEND_TEXTRSP:
+                               use_misc = 0;
+                               sent_status = 1;
+                               break;
+                       case ISTATE_SEND_REJECT:
+                               use_misc = 0;
+                               if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
+                                       cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
+                                       spin_unlock_bh(&cmd->istate_lock);
+                                       complete(&cmd->reject_comp);
+                                       goto transport_err;
+                               }
+                               complete(&cmd->reject_comp);
+                               break;
+                       case ISTATE_SEND_TASKMGTRSP:
+                               use_misc = 0;
+                               sent_status = 1;
+                               break;
+                       case ISTATE_SEND_LOGOUTRSP:
+                               spin_unlock_bh(&cmd->istate_lock);
+                               if (!iscsit_logout_post_handler(cmd, conn))
+                                       goto restart;
+                               spin_lock_bh(&cmd->istate_lock);
+                               use_misc = 0;
+                               sent_status = 1;
+                               break;
+                       default:
+                               pr_err("Unknown Opcode: 0x%02x ITT:"
+                                       " 0x%08x, i_state: %d on CID: %hu\n",
+                                       cmd->iscsi_opcode, cmd->init_task_tag,
+                                       cmd->i_state, conn->cid);
+                               spin_unlock_bh(&cmd->istate_lock);
+                               goto transport_err;
+                       }
+
+                       if (sent_status) {
+                               cmd->i_state = ISTATE_SENT_STATUS;
+                               sent_status = 0;
+                       }
+                       spin_unlock_bh(&cmd->istate_lock);
+
+                       if (atomic_read(&conn->check_immediate_queue))
+                               goto get_immediate;
+
+                       goto get_response;
+               } else
+                       conn->tx_response_queue = 0;
+       }
+
+transport_err:
+       iscsit_take_action_for_connection_exit(conn);
+       goto restart;
+out:
+       return 0;
+}
+
+int iscsi_target_rx_thread(void *arg)
+{
+       int ret;
+       u8 buffer[ISCSI_HDR_LEN], opcode;
+       u32 checksum = 0, digest = 0;
+       struct iscsi_conn *conn = NULL;
+       struct iscsi_thread_set *ts = (struct iscsi_thread_set *)arg;
+       struct kvec iov;
+       /*
+        * Allow ourselves to be interrupted by SIGINT so that a
+        * connection recovery / failure event can be triggered externally.
+        */
+       allow_signal(SIGINT);
+
+restart:
+       conn = iscsi_rx_thread_pre_handler(ts);
+       if (!conn)
+               goto out;
+
+       while (!kthread_should_stop()) {
+               /*
+                * Ensure that both TX and RX per connection kthreads
+                * are scheduled to run on the same CPU.
+                */
+               iscsit_thread_check_cpumask(conn, current, 0);
+
+               memset(buffer, 0, ISCSI_HDR_LEN);
+               memset(&iov, 0, sizeof(struct kvec));
+
+               iov.iov_base    = buffer;
+               iov.iov_len     = ISCSI_HDR_LEN;
+
+               ret = rx_data(conn, &iov, 1, ISCSI_HDR_LEN);
+               if (ret != ISCSI_HDR_LEN) {
+                       iscsit_rx_thread_wait_for_tcp(conn);
+                       goto transport_err;
+               }
+
+               /*
+                * Set conn->bad_hdr for use with REJECT PDUs.
+                */
+               memcpy(&conn->bad_hdr, &buffer, ISCSI_HDR_LEN);
+
+               if (conn->conn_ops->HeaderDigest) {
+                       iov.iov_base    = &digest;
+                       iov.iov_len     = ISCSI_CRC_LEN;
+
+                       ret = rx_data(conn, &iov, 1, ISCSI_CRC_LEN);
+                       if (ret != ISCSI_CRC_LEN) {
+                               iscsit_rx_thread_wait_for_tcp(conn);
+                               goto transport_err;
+                       }
+
+                       iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
+                                       buffer, ISCSI_HDR_LEN,
+                                       0, NULL, (u8 *)&checksum);
+
+                       if (digest != checksum) {
+                               pr_err("HeaderDigest CRC32C failed,"
+                                       " received 0x%08x, computed 0x%08x\n",
+                                       digest, checksum);
+                               /*
+                                * Set the PDU to 0xff so it will intentionally
+                                * hit default in the switch below.
+                                */
+                               memset(buffer, 0xff, ISCSI_HDR_LEN);
+                               spin_lock_bh(&conn->sess->session_stats_lock);
+                               conn->sess->conn_digest_errors++;
+                               spin_unlock_bh(&conn->sess->session_stats_lock);
+                       } else {
+                               pr_debug("Got HeaderDigest CRC32C"
+                                               " 0x%08x\n", checksum);
+                       }
+               }
+
+               if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)
+                       goto transport_err;
+
+               opcode = buffer[0] & ISCSI_OPCODE_MASK;
+
+               if (conn->sess->sess_ops->SessionType &&
+                  ((!(opcode & ISCSI_OP_TEXT)) ||
+                   (!(opcode & ISCSI_OP_LOGOUT)))) {
+                       pr_err("Received illegal iSCSI Opcode: 0x%02x"
+                       " while in Discovery Session, rejecting.\n", opcode);
+                       iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
+                                       buffer, conn);
+                       goto transport_err;
+               }
+
+               switch (opcode) {
+               case ISCSI_OP_SCSI_CMD:
+                       if (iscsit_handle_scsi_cmd(conn, buffer) < 0)
+                               goto transport_err;
+                       break;
+               case ISCSI_OP_SCSI_DATA_OUT:
+                       if (iscsit_handle_data_out(conn, buffer) < 0)
+                               goto transport_err;
+                       break;
+               case ISCSI_OP_NOOP_OUT:
+                       if (iscsit_handle_nop_out(conn, buffer) < 0)
+                               goto transport_err;
+                       break;
+               case ISCSI_OP_SCSI_TMFUNC:
+                       if (iscsit_handle_task_mgt_cmd(conn, buffer) < 0)
+                               goto transport_err;
+                       break;
+               case ISCSI_OP_TEXT:
+                       if (iscsit_handle_text_cmd(conn, buffer) < 0)
+                               goto transport_err;
+                       break;
+               case ISCSI_OP_LOGOUT:
+                       ret = iscsit_handle_logout_cmd(conn, buffer);
+                       if (ret > 0) {
+                               wait_for_completion_timeout(&conn->conn_logout_comp,
+                                               SECONDS_FOR_LOGOUT_COMP * HZ);
+                               goto transport_err;
+                       } else if (ret < 0)
+                               goto transport_err;
+                       break;
+               case ISCSI_OP_SNACK:
+                       if (iscsit_handle_snack(conn, buffer) < 0)
+                               goto transport_err;
+                       break;
+               default:
+                       pr_err("Got unknown iSCSI OpCode: 0x%02x\n",
+                                       opcode);
+                       if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+                               pr_err("Cannot recover from unknown"
+                               " opcode while ERL=0, closing iSCSI connection"
+                               ".\n");
+                               goto transport_err;
+                       }
+                       if (!conn->conn_ops->OFMarker) {
+                               pr_err("Unable to recover from unknown"
+                               " opcode while OFMarker=No, closing iSCSI"
+                                       " connection.\n");
+                               goto transport_err;
+                       }
+                       if (iscsit_recover_from_unknown_opcode(conn) < 0) {
+                               pr_err("Unable to recover from unknown"
+                                       " opcode, closing iSCSI connection.\n");
+                               goto transport_err;
+                       }
+                       break;
+               }
+       }
+
+transport_err:
+       if (!signal_pending(current))
+               atomic_set(&conn->transport_failed, 1);
+       iscsit_take_action_for_connection_exit(conn);
+       goto restart;
+out:
+       return 0;
+}
+
+static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
+{
+       struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
+       struct iscsi_session *sess = conn->sess;
+       struct se_cmd *se_cmd;
+       /*
+        * We expect this function to only ever be called from either RX or TX
+        * thread context via iscsit_close_connection() once the other context
+        * has been reset -> returned sleeping pre-handler state.
+        */
+       spin_lock_bh(&conn->cmd_lock);
+       list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) {
+               if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD)) {
+
+                       list_del(&cmd->i_list);
+                       spin_unlock_bh(&conn->cmd_lock);
+                       iscsit_increment_maxcmdsn(cmd, sess);
+                       se_cmd = &cmd->se_cmd;
+                       /*
+                        * Special cases for active iSCSI TMR, and
+                        * transport_lookup_cmd_lun() failing from
+                        * iscsit_get_lun_for_cmd() in iscsit_handle_scsi_cmd().
+                        */
+                       if (cmd->tmr_req && se_cmd->transport_wait_for_tasks)
+                               se_cmd->transport_wait_for_tasks(se_cmd, 1, 1);
+                       else if (cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD)
+                               transport_release_cmd(se_cmd);
+                       else
+                               iscsit_release_cmd(cmd);
+
+                       spin_lock_bh(&conn->cmd_lock);
+                       continue;
+               }
+               list_del(&cmd->i_list);
+               spin_unlock_bh(&conn->cmd_lock);
+
+               iscsit_increment_maxcmdsn(cmd, sess);
+               se_cmd = &cmd->se_cmd;
+
+               if (se_cmd->transport_wait_for_tasks)
+                       se_cmd->transport_wait_for_tasks(se_cmd, 1, 1);
+
+               spin_lock_bh(&conn->cmd_lock);
+       }
+       spin_unlock_bh(&conn->cmd_lock);
+}
+
+static void iscsit_stop_timers_for_cmds(
+       struct iscsi_conn *conn)
+{
+       struct iscsi_cmd *cmd;
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+               if (cmd->data_direction == DMA_TO_DEVICE)
+                       iscsit_stop_dataout_timer(cmd);
+       }
+       spin_unlock_bh(&conn->cmd_lock);
+}
+
+int iscsit_close_connection(
+       struct iscsi_conn *conn)
+{
+       int conn_logout = (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT);
+       struct iscsi_session    *sess = conn->sess;
+
+       pr_debug("Closing iSCSI connection CID %hu on SID:"
+               " %u\n", conn->cid, sess->sid);
+       /*
+        * Always up conn_logout_comp just in case the RX Thread is sleeping
+        * and the logout response never got sent because the connection
+        * failed.
+        */
+       complete(&conn->conn_logout_comp);
+
+       iscsi_release_thread_set(conn);
+
+       iscsit_stop_timers_for_cmds(conn);
+       iscsit_stop_nopin_response_timer(conn);
+       iscsit_stop_nopin_timer(conn);
+       iscsit_free_queue_reqs_for_conn(conn);
+
+       /*
+        * During Connection recovery drop unacknowledged out of order
+        * commands for this connection, and prepare the other commands
+        * for realligence.
+        *
+        * During normal operation clear the out of order commands (but
+        * do not free the struct iscsi_ooo_cmdsn's) and release all
+        * struct iscsi_cmds.
+        */
+       if (atomic_read(&conn->connection_recovery)) {
+               iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(conn);
+               iscsit_prepare_cmds_for_realligance(conn);
+       } else {
+               iscsit_clear_ooo_cmdsns_for_conn(conn);
+               iscsit_release_commands_from_conn(conn);
+       }
+
+       /*
+        * Handle decrementing session or connection usage count if
+        * a logout response was not able to be sent because the
+        * connection failed.  Fall back to Session Recovery here.
+        */
+       if (atomic_read(&conn->conn_logout_remove)) {
+               if (conn->conn_logout_reason == ISCSI_LOGOUT_REASON_CLOSE_SESSION) {
+                       iscsit_dec_conn_usage_count(conn);
+                       iscsit_dec_session_usage_count(sess);
+               }
+               if (conn->conn_logout_reason == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION)
+                       iscsit_dec_conn_usage_count(conn);
+
+               atomic_set(&conn->conn_logout_remove, 0);
+               atomic_set(&sess->session_reinstatement, 0);
+               atomic_set(&sess->session_fall_back_to_erl0, 1);
+       }
+
+       spin_lock_bh(&sess->conn_lock);
+       list_del(&conn->conn_list);
+
+       /*
+        * Attempt to let the Initiator know this connection failed by
+        * sending an Connection Dropped Async Message on another
+        * active connection.
+        */
+       if (atomic_read(&conn->connection_recovery))
+               iscsit_build_conn_drop_async_message(conn);
+
+       spin_unlock_bh(&sess->conn_lock);
+
+       /*
+        * If connection reinstatement is being performed on this connection,
+        * up the connection reinstatement semaphore that is being blocked on
+        * in iscsit_cause_connection_reinstatement().
+        */
+       spin_lock_bh(&conn->state_lock);
+       if (atomic_read(&conn->sleep_on_conn_wait_comp)) {
+               spin_unlock_bh(&conn->state_lock);
+               complete(&conn->conn_wait_comp);
+               wait_for_completion(&conn->conn_post_wait_comp);
+               spin_lock_bh(&conn->state_lock);
+       }
+
+       /*
+        * If connection reinstatement is being performed on this connection
+        * by receiving a REMOVECONNFORRECOVERY logout request, up the
+        * connection wait rcfr semaphore that is being blocked on
+        * an iscsit_connection_reinstatement_rcfr().
+        */
+       if (atomic_read(&conn->connection_wait_rcfr)) {
+               spin_unlock_bh(&conn->state_lock);
+               complete(&conn->conn_wait_rcfr_comp);
+               wait_for_completion(&conn->conn_post_wait_comp);
+               spin_lock_bh(&conn->state_lock);
+       }
+       atomic_set(&conn->connection_reinstatement, 1);
+       spin_unlock_bh(&conn->state_lock);
+
+       /*
+        * If any other processes are accessing this connection pointer we
+        * must wait until they have completed.
+        */
+       iscsit_check_conn_usage_count(conn);
+
+       if (conn->conn_rx_hash.tfm)
+               crypto_free_hash(conn->conn_rx_hash.tfm);
+       if (conn->conn_tx_hash.tfm)
+               crypto_free_hash(conn->conn_tx_hash.tfm);
+
+       if (conn->conn_cpumask)
+               free_cpumask_var(conn->conn_cpumask);
+
+       kfree(conn->conn_ops);
+       conn->conn_ops = NULL;
+
+       if (conn->sock) {
+               if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) {
+                       kfree(conn->sock->file);
+                       conn->sock->file = NULL;
+               }
+               sock_release(conn->sock);
+       }
+       conn->thread_set = NULL;
+
+       pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
+       conn->conn_state = TARG_CONN_STATE_FREE;
+       kfree(conn);
+
+       spin_lock_bh(&sess->conn_lock);
+       atomic_dec(&sess->nconn);
+       pr_debug("Decremented iSCSI connection count to %hu from node:"
+               " %s\n", atomic_read(&sess->nconn),
+               sess->sess_ops->InitiatorName);
+       /*
+        * Make sure that if one connection fails in an non ERL=2 iSCSI
+        * Session that they all fail.
+        */
+       if ((sess->sess_ops->ErrorRecoveryLevel != 2) && !conn_logout &&
+            !atomic_read(&sess->session_logout))
+               atomic_set(&sess->session_fall_back_to_erl0, 1);
+
+       /*
+        * If this was not the last connection in the session, and we are
+        * performing session reinstatement or falling back to ERL=0, call
+        * iscsit_stop_session() without sleeping to shutdown the other
+        * active connections.
+        */
+       if (atomic_read(&sess->nconn)) {
+               if (!atomic_read(&sess->session_reinstatement) &&
+                   !atomic_read(&sess->session_fall_back_to_erl0)) {
+                       spin_unlock_bh(&sess->conn_lock);
+                       return 0;
+               }
+               if (!atomic_read(&sess->session_stop_active)) {
+                       atomic_set(&sess->session_stop_active, 1);
+                       spin_unlock_bh(&sess->conn_lock);
+                       iscsit_stop_session(sess, 0, 0);
+                       return 0;
+               }
+               spin_unlock_bh(&sess->conn_lock);
+               return 0;
+       }
+
+       /*
+        * If this was the last connection in the session and one of the
+        * following is occurring:
+        *
+        * Session Reinstatement is not being performed, and are falling back
+        * to ERL=0 call iscsit_close_session().
+        *
+        * Session Logout was requested.  iscsit_close_session() will be called
+        * elsewhere.
+        *
+        * Session Continuation is not being performed, start the Time2Retain
+        * handler and check if sleep_on_sess_wait_sem is active.
+        */
+       if (!atomic_read(&sess->session_reinstatement) &&
+            atomic_read(&sess->session_fall_back_to_erl0)) {
+               spin_unlock_bh(&sess->conn_lock);
+               iscsit_close_session(sess);
+
+               return 0;
+       } else if (atomic_read(&sess->session_logout)) {
+               pr_debug("Moving to TARG_SESS_STATE_FREE.\n");
+               sess->session_state = TARG_SESS_STATE_FREE;
+               spin_unlock_bh(&sess->conn_lock);
+
+               if (atomic_read(&sess->sleep_on_sess_wait_comp))
+                       complete(&sess->session_wait_comp);
+
+               return 0;
+       } else {
+               pr_debug("Moving to TARG_SESS_STATE_FAILED.\n");
+               sess->session_state = TARG_SESS_STATE_FAILED;
+
+               if (!atomic_read(&sess->session_continuation)) {
+                       spin_unlock_bh(&sess->conn_lock);
+                       iscsit_start_time2retain_handler(sess);
+               } else
+                       spin_unlock_bh(&sess->conn_lock);
+
+               if (atomic_read(&sess->sleep_on_sess_wait_comp))
+                       complete(&sess->session_wait_comp);
+
+               return 0;
+       }
+       spin_unlock_bh(&sess->conn_lock);
+
+       return 0;
+}
+
+int iscsit_close_session(struct iscsi_session *sess)
+{
+       struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess);
+       struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
+
+       if (atomic_read(&sess->nconn)) {
+               pr_err("%d connection(s) still exist for iSCSI session"
+                       " to %s\n", atomic_read(&sess->nconn),
+                       sess->sess_ops->InitiatorName);
+               BUG();
+       }
+
+       spin_lock_bh(&se_tpg->session_lock);
+       atomic_set(&sess->session_logout, 1);
+       atomic_set(&sess->session_reinstatement, 1);
+       iscsit_stop_time2retain_timer(sess);
+       spin_unlock_bh(&se_tpg->session_lock);
+
+       /*
+        * transport_deregister_session_configfs() will clear the
+        * struct se_node_acl->nacl_sess pointer now as a iscsi_np process context
+        * can be setting it again with __transport_register_session() in
+        * iscsi_post_login_handler() again after the iscsit_stop_session()
+        * completes in iscsi_np context.
+        */
+       transport_deregister_session_configfs(sess->se_sess);
+
+       /*
+        * If any other processes are accessing this session pointer we must
+        * wait until they have completed.  If we are in an interrupt (the
+        * time2retain handler) and contain and active session usage count we
+        * restart the timer and exit.
+        */
+       if (!in_interrupt()) {
+               if (iscsit_check_session_usage_count(sess) == 1)
+                       iscsit_stop_session(sess, 1, 1);
+       } else {
+               if (iscsit_check_session_usage_count(sess) == 2) {
+                       atomic_set(&sess->session_logout, 0);
+                       iscsit_start_time2retain_handler(sess);
+                       return 0;
+               }
+       }
+
+       transport_deregister_session(sess->se_sess);
+
+       if (sess->sess_ops->ErrorRecoveryLevel == 2)
+               iscsit_free_connection_recovery_entires(sess);
+
+       iscsit_free_all_ooo_cmdsns(sess);
+
+       spin_lock_bh(&se_tpg->session_lock);
+       pr_debug("Moving to TARG_SESS_STATE_FREE.\n");
+       sess->session_state = TARG_SESS_STATE_FREE;
+       pr_debug("Released iSCSI session from node: %s\n",
+                       sess->sess_ops->InitiatorName);
+       tpg->nsessions--;
+       if (tpg->tpg_tiqn)
+               tpg->tpg_tiqn->tiqn_nsessions--;
+
+       pr_debug("Decremented number of active iSCSI Sessions on"
+               " iSCSI TPG: %hu to %u\n", tpg->tpgt, tpg->nsessions);
+
+       spin_lock(&sess_idr_lock);
+       idr_remove(&sess_idr, sess->session_index);
+       spin_unlock(&sess_idr_lock);
+
+       kfree(sess->sess_ops);
+       sess->sess_ops = NULL;
+       spin_unlock_bh(&se_tpg->session_lock);
+
+       kfree(sess);
+       return 0;
+}
+
+static void iscsit_logout_post_handler_closesession(
+       struct iscsi_conn *conn)
+{
+       struct iscsi_session *sess = conn->sess;
+
+       iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD);
+       iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD);
+
+       atomic_set(&conn->conn_logout_remove, 0);
+       complete(&conn->conn_logout_comp);
+
+       iscsit_dec_conn_usage_count(conn);
+       iscsit_stop_session(sess, 1, 1);
+       iscsit_dec_session_usage_count(sess);
+       iscsit_close_session(sess);
+}
+
+static void iscsit_logout_post_handler_samecid(
+       struct iscsi_conn *conn)
+{
+       iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD);
+       iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD);
+
+       atomic_set(&conn->conn_logout_remove, 0);
+       complete(&conn->conn_logout_comp);
+
+       iscsit_cause_connection_reinstatement(conn, 1);
+       iscsit_dec_conn_usage_count(conn);
+}
+
+static void iscsit_logout_post_handler_diffcid(
+       struct iscsi_conn *conn,
+       u16 cid)
+{
+       struct iscsi_conn *l_conn;
+       struct iscsi_session *sess = conn->sess;
+
+       if (!sess)
+               return;
+
+       spin_lock_bh(&sess->conn_lock);
+       list_for_each_entry(l_conn, &sess->sess_conn_list, conn_list) {
+               if (l_conn->cid == cid) {
+                       iscsit_inc_conn_usage_count(l_conn);
+                       break;
+               }
+       }
+       spin_unlock_bh(&sess->conn_lock);
+
+       if (!l_conn)
+               return;
+
+       if (l_conn->sock)
+               l_conn->sock->ops->shutdown(l_conn->sock, RCV_SHUTDOWN);
+
+       spin_lock_bh(&l_conn->state_lock);
+       pr_debug("Moving to TARG_CONN_STATE_IN_LOGOUT.\n");
+       l_conn->conn_state = TARG_CONN_STATE_IN_LOGOUT;
+       spin_unlock_bh(&l_conn->state_lock);
+
+       iscsit_cause_connection_reinstatement(l_conn, 1);
+       iscsit_dec_conn_usage_count(l_conn);
+}
+
+/*
+ *     Return of 0 causes the TX thread to restart.
+ */
+static int iscsit_logout_post_handler(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       int ret = 0;
+
+       switch (cmd->logout_reason) {
+       case ISCSI_LOGOUT_REASON_CLOSE_SESSION:
+               switch (cmd->logout_response) {
+               case ISCSI_LOGOUT_SUCCESS:
+               case ISCSI_LOGOUT_CLEANUP_FAILED:
+               default:
+                       iscsit_logout_post_handler_closesession(conn);
+                       break;
+               }
+               ret = 0;
+               break;
+       case ISCSI_LOGOUT_REASON_CLOSE_CONNECTION:
+               if (conn->cid == cmd->logout_cid) {
+                       switch (cmd->logout_response) {
+                       case ISCSI_LOGOUT_SUCCESS:
+                       case ISCSI_LOGOUT_CLEANUP_FAILED:
+                       default:
+                               iscsit_logout_post_handler_samecid(conn);
+                               break;
+                       }
+                       ret = 0;
+               } else {
+                       switch (cmd->logout_response) {
+                       case ISCSI_LOGOUT_SUCCESS:
+                               iscsit_logout_post_handler_diffcid(conn,
+                                       cmd->logout_cid);
+                               break;
+                       case ISCSI_LOGOUT_CID_NOT_FOUND:
+                       case ISCSI_LOGOUT_CLEANUP_FAILED:
+                       default:
+                               break;
+                       }
+                       ret = 1;
+               }
+               break;
+       case ISCSI_LOGOUT_REASON_RECOVERY:
+               switch (cmd->logout_response) {
+               case ISCSI_LOGOUT_SUCCESS:
+               case ISCSI_LOGOUT_CID_NOT_FOUND:
+               case ISCSI_LOGOUT_RECOVERY_UNSUPPORTED:
+               case ISCSI_LOGOUT_CLEANUP_FAILED:
+               default:
+                       break;
+               }
+               ret = 1;
+               break;
+       default:
+               break;
+
+       }
+       return ret;
+}
+
+void iscsit_fail_session(struct iscsi_session *sess)
+{
+       struct iscsi_conn *conn;
+
+       spin_lock_bh(&sess->conn_lock);
+       list_for_each_entry(conn, &sess->sess_conn_list, conn_list) {
+               pr_debug("Moving to TARG_CONN_STATE_CLEANUP_WAIT.\n");
+               conn->conn_state = TARG_CONN_STATE_CLEANUP_WAIT;
+       }
+       spin_unlock_bh(&sess->conn_lock);
+
+       pr_debug("Moving to TARG_SESS_STATE_FAILED.\n");
+       sess->session_state = TARG_SESS_STATE_FAILED;
+}
+
+int iscsit_free_session(struct iscsi_session *sess)
+{
+       u16 conn_count = atomic_read(&sess->nconn);
+       struct iscsi_conn *conn, *conn_tmp = NULL;
+       int is_last;
+
+       spin_lock_bh(&sess->conn_lock);
+       atomic_set(&sess->sleep_on_sess_wait_comp, 1);
+
+       list_for_each_entry_safe(conn, conn_tmp, &sess->sess_conn_list,
+                       conn_list) {
+               if (conn_count == 0)
+                       break;
+
+               if (list_is_last(&conn->conn_list, &sess->sess_conn_list)) {
+                       is_last = 1;
+               } else {
+                       iscsit_inc_conn_usage_count(conn_tmp);
+                       is_last = 0;
+               }
+               iscsit_inc_conn_usage_count(conn);
+
+               spin_unlock_bh(&sess->conn_lock);
+               iscsit_cause_connection_reinstatement(conn, 1);
+               spin_lock_bh(&sess->conn_lock);
+
+               iscsit_dec_conn_usage_count(conn);
+               if (is_last == 0)
+                       iscsit_dec_conn_usage_count(conn_tmp);
+
+               conn_count--;
+       }
+
+       if (atomic_read(&sess->nconn)) {
+               spin_unlock_bh(&sess->conn_lock);
+               wait_for_completion(&sess->session_wait_comp);
+       } else
+               spin_unlock_bh(&sess->conn_lock);
+
+       iscsit_close_session(sess);
+       return 0;
+}
+
+void iscsit_stop_session(
+       struct iscsi_session *sess,
+       int session_sleep,
+       int connection_sleep)
+{
+       u16 conn_count = atomic_read(&sess->nconn);
+       struct iscsi_conn *conn, *conn_tmp = NULL;
+       int is_last;
+
+       spin_lock_bh(&sess->conn_lock);
+       if (session_sleep)
+               atomic_set(&sess->sleep_on_sess_wait_comp, 1);
+
+       if (connection_sleep) {
+               list_for_each_entry_safe(conn, conn_tmp, &sess->sess_conn_list,
+                               conn_list) {
+                       if (conn_count == 0)
+                               break;
+
+                       if (list_is_last(&conn->conn_list, &sess->sess_conn_list)) {
+                               is_last = 1;
+                       } else {
+                               iscsit_inc_conn_usage_count(conn_tmp);
+                               is_last = 0;
+                       }
+                       iscsit_inc_conn_usage_count(conn);
+
+                       spin_unlock_bh(&sess->conn_lock);
+                       iscsit_cause_connection_reinstatement(conn, 1);
+                       spin_lock_bh(&sess->conn_lock);
+
+                       iscsit_dec_conn_usage_count(conn);
+                       if (is_last == 0)
+                               iscsit_dec_conn_usage_count(conn_tmp);
+                       conn_count--;
+               }
+       } else {
+               list_for_each_entry(conn, &sess->sess_conn_list, conn_list)
+                       iscsit_cause_connection_reinstatement(conn, 0);
+       }
+
+       if (session_sleep && atomic_read(&sess->nconn)) {
+               spin_unlock_bh(&sess->conn_lock);
+               wait_for_completion(&sess->session_wait_comp);
+       } else
+               spin_unlock_bh(&sess->conn_lock);
+}
+
+int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
+{
+       struct iscsi_session *sess;
+       struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
+       struct se_session *se_sess, *se_sess_tmp;
+       int session_count = 0;
+
+       spin_lock_bh(&se_tpg->session_lock);
+       if (tpg->nsessions && !force) {
+               spin_unlock_bh(&se_tpg->session_lock);
+               return -1;
+       }
+
+       list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
+                       sess_list) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+
+               spin_lock(&sess->conn_lock);
+               if (atomic_read(&sess->session_fall_back_to_erl0) ||
+                   atomic_read(&sess->session_logout) ||
+                   (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
+                       spin_unlock(&sess->conn_lock);
+                       continue;
+               }
+               atomic_set(&sess->session_reinstatement, 1);
+               spin_unlock(&sess->conn_lock);
+               spin_unlock_bh(&se_tpg->session_lock);
+
+               iscsit_free_session(sess);
+               spin_lock_bh(&se_tpg->session_lock);
+
+               session_count++;
+       }
+       spin_unlock_bh(&se_tpg->session_lock);
+
+       pr_debug("Released %d iSCSI Session(s) from Target Portal"
+                       " Group: %hu\n", session_count, tpg->tpgt);
+       return 0;
+}
+
+MODULE_DESCRIPTION("iSCSI-Target Driver for mainline target infrastructure");
+MODULE_VERSION("4.1.x");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(iscsi_target_init_module);
+module_exit(iscsi_target_cleanup_module);
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h
new file mode 100644 (file)
index 0000000..5db2dde
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef ISCSI_TARGET_H
+#define ISCSI_TARGET_H
+
+extern struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *);
+extern struct iscsi_tiqn *iscsit_get_tiqn(unsigned char *, int);
+extern void iscsit_put_tiqn_for_login(struct iscsi_tiqn *);
+extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *);
+extern void iscsit_del_tiqn(struct iscsi_tiqn *);
+extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *);
+extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *);
+extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *,
+                               char *, int);
+extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
+                               struct iscsi_portal_group *);
+extern int iscsit_del_np(struct iscsi_np *);
+extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *);
+extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *);
+extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *);
+extern int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *, struct iscsi_conn *);
+extern int iscsit_send_async_msg(struct iscsi_conn *, u16, u8, u8);
+extern int iscsit_send_r2t(struct iscsi_cmd *, struct iscsi_conn *);
+extern int iscsit_build_r2ts_for_cmd(struct iscsi_cmd *, struct iscsi_conn *, int);
+extern void iscsit_thread_get_cpumask(struct iscsi_conn *);
+extern int iscsi_target_tx_thread(void *);
+extern int iscsi_target_rx_thread(void *);
+extern int iscsit_close_connection(struct iscsi_conn *);
+extern int iscsit_close_session(struct iscsi_session *);
+extern void iscsit_fail_session(struct iscsi_session *);
+extern int iscsit_free_session(struct iscsi_session *);
+extern void iscsit_stop_session(struct iscsi_session *, int, int);
+extern int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *, int);
+
+extern struct iscsit_global *iscsit_global;
+extern struct target_fabric_configfs *lio_target_fabric_configfs;
+
+extern struct kmem_cache *lio_dr_cache;
+extern struct kmem_cache *lio_ooo_cache;
+extern struct kmem_cache *lio_cmd_cache;
+extern struct kmem_cache *lio_qr_cache;
+extern struct kmem_cache *lio_r2t_cache;
+
+#endif   /*** ISCSI_TARGET_H ***/
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
new file mode 100644 (file)
index 0000000..11fd743
--- /dev/null
@@ -0,0 +1,490 @@
+/*******************************************************************************
+ * This file houses the main functions for the iSCSI CHAP support
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/scatterlist.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_nego.h"
+#include "iscsi_target_auth.h"
+
+static unsigned char chap_asciihex_to_binaryhex(unsigned char val[2])
+{
+       unsigned char result = 0;
+       /*
+        * MSB
+        */
+       if ((val[0] >= 'a') && (val[0] <= 'f'))
+               result = ((val[0] - 'a' + 10) & 0xf) << 4;
+       else
+               if ((val[0] >= 'A') && (val[0] <= 'F'))
+                       result = ((val[0] - 'A' + 10) & 0xf) << 4;
+               else /* digit */
+                       result = ((val[0] - '0') & 0xf) << 4;
+       /*
+        * LSB
+        */
+       if ((val[1] >= 'a') && (val[1] <= 'f'))
+               result |= ((val[1] - 'a' + 10) & 0xf);
+       else
+               if ((val[1] >= 'A') && (val[1] <= 'F'))
+                       result |= ((val[1] - 'A' + 10) & 0xf);
+               else /* digit */
+                       result |= ((val[1] - '0') & 0xf);
+
+       return result;
+}
+
+static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len)
+{
+       int i, j = 0;
+
+       for (i = 0; i < len; i += 2) {
+               dst[j++] = (unsigned char) chap_asciihex_to_binaryhex(&src[i]);
+       }
+
+       dst[j] = '\0';
+       return j;
+}
+
+static void chap_binaryhex_to_asciihex(char *dst, char *src, int src_len)
+{
+       int i;
+
+       for (i = 0; i < src_len; i++) {
+               sprintf(&dst[i*2], "%02x", (int) src[i] & 0xff);
+       }
+}
+
+static void chap_set_random(char *data, int length)
+{
+       long r;
+       unsigned n;
+
+       while (length > 0) {
+               get_random_bytes(&r, sizeof(long));
+               r = r ^ (r >> 8);
+               r = r ^ (r >> 4);
+               n = r & 0x7;
+
+               get_random_bytes(&r, sizeof(long));
+               r = r ^ (r >> 8);
+               r = r ^ (r >> 5);
+               n = (n << 3) | (r & 0x7);
+
+               get_random_bytes(&r, sizeof(long));
+               r = r ^ (r >> 8);
+               r = r ^ (r >> 5);
+               n = (n << 2) | (r & 0x3);
+
+               *data++ = n;
+               length--;
+       }
+}
+
+static void chap_gen_challenge(
+       struct iscsi_conn *conn,
+       int caller,
+       char *c_str,
+       unsigned int *c_len)
+{
+       unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1];
+       struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
+
+       memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1);
+
+       chap_set_random(chap->challenge, CHAP_CHALLENGE_LENGTH);
+       chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge,
+                               CHAP_CHALLENGE_LENGTH);
+       /*
+        * Set CHAP_C, and copy the generated challenge into c_str.
+        */
+       *c_len += sprintf(c_str + *c_len, "CHAP_C=0x%s", challenge_asciihex);
+       *c_len += 1;
+
+       pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client",
+                       challenge_asciihex);
+}
+
+
+static struct iscsi_chap *chap_server_open(
+       struct iscsi_conn *conn,
+       struct iscsi_node_auth *auth,
+       const char *a_str,
+       char *aic_str,
+       unsigned int *aic_len)
+{
+       struct iscsi_chap *chap;
+
+       if (!(auth->naf_flags & NAF_USERID_SET) ||
+           !(auth->naf_flags & NAF_PASSWORD_SET)) {
+               pr_err("CHAP user or password not set for"
+                               " Initiator ACL\n");
+               return NULL;
+       }
+
+       conn->auth_protocol = kzalloc(sizeof(struct iscsi_chap), GFP_KERNEL);
+       if (!conn->auth_protocol)
+               return NULL;
+
+       chap = (struct iscsi_chap *) conn->auth_protocol;
+       /*
+        * We only support MD5 MDA presently.
+        */
+       if (strncmp(a_str, "CHAP_A=5", 8)) {
+               pr_err("CHAP_A is not MD5.\n");
+               return NULL;
+       }
+       pr_debug("[server] Got CHAP_A=5\n");
+       /*
+        * Send back CHAP_A set to MD5.
+        */
+       *aic_len = sprintf(aic_str, "CHAP_A=5");
+       *aic_len += 1;
+       chap->digest_type = CHAP_DIGEST_MD5;
+       pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type);
+       /*
+        * Set Identifier.
+        */
+       chap->id = ISCSI_TPG_C(conn)->tpg_chap_id++;
+       *aic_len += sprintf(aic_str + *aic_len, "CHAP_I=%d", chap->id);
+       *aic_len += 1;
+       pr_debug("[server] Sending CHAP_I=%d\n", chap->id);
+       /*
+        * Generate Challenge.
+        */
+       chap_gen_challenge(conn, 1, aic_str, aic_len);
+
+       return chap;
+}
+
+static void chap_close(struct iscsi_conn *conn)
+{
+       kfree(conn->auth_protocol);
+       conn->auth_protocol = NULL;
+}
+
+static int chap_server_compute_md5(
+       struct iscsi_conn *conn,
+       struct iscsi_node_auth *auth,
+       char *nr_in_ptr,
+       char *nr_out_ptr,
+       unsigned int *nr_out_len)
+{
+       char *endptr;
+       unsigned char id, digest[MD5_SIGNATURE_SIZE];
+       unsigned char type, response[MD5_SIGNATURE_SIZE * 2 + 2];
+       unsigned char identifier[10], *challenge = NULL;
+       unsigned char *challenge_binhex = NULL;
+       unsigned char client_digest[MD5_SIGNATURE_SIZE];
+       unsigned char server_digest[MD5_SIGNATURE_SIZE];
+       unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH];
+       struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
+       struct crypto_hash *tfm;
+       struct hash_desc desc;
+       struct scatterlist sg;
+       int auth_ret = -1, ret, challenge_len;
+
+       memset(identifier, 0, 10);
+       memset(chap_n, 0, MAX_CHAP_N_SIZE);
+       memset(chap_r, 0, MAX_RESPONSE_LENGTH);
+       memset(digest, 0, MD5_SIGNATURE_SIZE);
+       memset(response, 0, MD5_SIGNATURE_SIZE * 2 + 2);
+       memset(client_digest, 0, MD5_SIGNATURE_SIZE);
+       memset(server_digest, 0, MD5_SIGNATURE_SIZE);
+
+       challenge = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
+       if (!challenge) {
+               pr_err("Unable to allocate challenge buffer\n");
+               goto out;
+       }
+
+       challenge_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL);
+       if (!challenge_binhex) {
+               pr_err("Unable to allocate challenge_binhex buffer\n");
+               goto out;
+       }
+       /*
+        * Extract CHAP_N.
+        */
+       if (extract_param(nr_in_ptr, "CHAP_N", MAX_CHAP_N_SIZE, chap_n,
+                               &type) < 0) {
+               pr_err("Could not find CHAP_N.\n");
+               goto out;
+       }
+       if (type == HEX) {
+               pr_err("Could not find CHAP_N.\n");
+               goto out;
+       }
+
+       if (memcmp(chap_n, auth->userid, strlen(auth->userid)) != 0) {
+               pr_err("CHAP_N values do not match!\n");
+               goto out;
+       }
+       pr_debug("[server] Got CHAP_N=%s\n", chap_n);
+       /*
+        * Extract CHAP_R.
+        */
+       if (extract_param(nr_in_ptr, "CHAP_R", MAX_RESPONSE_LENGTH, chap_r,
+                               &type) < 0) {
+               pr_err("Could not find CHAP_R.\n");
+               goto out;
+       }
+       if (type != HEX) {
+               pr_err("Could not find CHAP_R.\n");
+               goto out;
+       }
+
+       pr_debug("[server] Got CHAP_R=%s\n", chap_r);
+       chap_string_to_hex(client_digest, chap_r, strlen(chap_r));
+
+       tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm)) {
+               pr_err("Unable to allocate struct crypto_hash\n");
+               goto out;
+       }
+       desc.tfm = tfm;
+       desc.flags = 0;
+
+       ret = crypto_hash_init(&desc);
+       if (ret < 0) {
+               pr_err("crypto_hash_init() failed\n");
+               crypto_free_hash(tfm);
+               goto out;
+       }
+
+       sg_init_one(&sg, (void *)&chap->id, 1);
+       ret = crypto_hash_update(&desc, &sg, 1);
+       if (ret < 0) {
+               pr_err("crypto_hash_update() failed for id\n");
+               crypto_free_hash(tfm);
+               goto out;
+       }
+
+       sg_init_one(&sg, (void *)&auth->password, strlen(auth->password));
+       ret = crypto_hash_update(&desc, &sg, strlen(auth->password));
+       if (ret < 0) {
+               pr_err("crypto_hash_update() failed for password\n");
+               crypto_free_hash(tfm);
+               goto out;
+       }
+
+       sg_init_one(&sg, (void *)chap->challenge, CHAP_CHALLENGE_LENGTH);
+       ret = crypto_hash_update(&desc, &sg, CHAP_CHALLENGE_LENGTH);
+       if (ret < 0) {
+               pr_err("crypto_hash_update() failed for challenge\n");
+               crypto_free_hash(tfm);
+               goto out;
+       }
+
+       ret = crypto_hash_final(&desc, server_digest);
+       if (ret < 0) {
+               pr_err("crypto_hash_final() failed for server digest\n");
+               crypto_free_hash(tfm);
+               goto out;
+       }
+       crypto_free_hash(tfm);
+
+       chap_binaryhex_to_asciihex(response, server_digest, MD5_SIGNATURE_SIZE);
+       pr_debug("[server] MD5 Server Digest: %s\n", response);
+
+       if (memcmp(server_digest, client_digest, MD5_SIGNATURE_SIZE) != 0) {
+               pr_debug("[server] MD5 Digests do not match!\n\n");
+               goto out;
+       } else
+               pr_debug("[server] MD5 Digests match, CHAP connetication"
+                               " successful.\n\n");
+       /*
+        * One way authentication has succeeded, return now if mutual
+        * authentication is not enabled.
+        */
+       if (!auth->authenticate_target) {
+               kfree(challenge);
+               kfree(challenge_binhex);
+               return 0;
+       }
+       /*
+        * Get CHAP_I.
+        */
+       if (extract_param(nr_in_ptr, "CHAP_I", 10, identifier, &type) < 0) {
+               pr_err("Could not find CHAP_I.\n");
+               goto out;
+       }
+
+       if (type == HEX)
+               id = (unsigned char)simple_strtoul((char *)&identifier[2],
+                                       &endptr, 0);
+       else
+               id = (unsigned char)simple_strtoul(identifier, &endptr, 0);
+       /*
+        * RFC 1994 says Identifier is no more than octet (8 bits).
+        */
+       pr_debug("[server] Got CHAP_I=%d\n", id);
+       /*
+        * Get CHAP_C.
+        */
+       if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN,
+                       challenge, &type) < 0) {
+               pr_err("Could not find CHAP_C.\n");
+               goto out;
+       }
+
+       if (type != HEX) {
+               pr_err("Could not find CHAP_C.\n");
+               goto out;
+       }
+       pr_debug("[server] Got CHAP_C=%s\n", challenge);
+       challenge_len = chap_string_to_hex(challenge_binhex, challenge,
+                               strlen(challenge));
+       if (!challenge_len) {
+               pr_err("Unable to convert incoming challenge\n");
+               goto out;
+       }
+       /*
+        * Generate CHAP_N and CHAP_R for mutual authentication.
+        */
+       tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm)) {
+               pr_err("Unable to allocate struct crypto_hash\n");
+               goto out;
+       }
+       desc.tfm = tfm;
+       desc.flags = 0;
+
+       ret = crypto_hash_init(&desc);
+       if (ret < 0) {
+               pr_err("crypto_hash_init() failed\n");
+               crypto_free_hash(tfm);
+               goto out;
+       }
+
+       sg_init_one(&sg, (void *)&id, 1);
+       ret = crypto_hash_update(&desc, &sg, 1);
+       if (ret < 0) {
+               pr_err("crypto_hash_update() failed for id\n");
+               crypto_free_hash(tfm);
+               goto out;
+       }
+
+       sg_init_one(&sg, (void *)auth->password_mutual,
+                               strlen(auth->password_mutual));
+       ret = crypto_hash_update(&desc, &sg, strlen(auth->password_mutual));
+       if (ret < 0) {
+               pr_err("crypto_hash_update() failed for"
+                               " password_mutual\n");
+               crypto_free_hash(tfm);
+               goto out;
+       }
+       /*
+        * Convert received challenge to binary hex.
+        */
+       sg_init_one(&sg, (void *)challenge_binhex, challenge_len);
+       ret = crypto_hash_update(&desc, &sg, challenge_len);
+       if (ret < 0) {
+               pr_err("crypto_hash_update() failed for ma challenge\n");
+               crypto_free_hash(tfm);
+               goto out;
+       }
+
+       ret = crypto_hash_final(&desc, digest);
+       if (ret < 0) {
+               pr_err("crypto_hash_final() failed for ma digest\n");
+               crypto_free_hash(tfm);
+               goto out;
+       }
+       crypto_free_hash(tfm);
+       /*
+        * Generate CHAP_N and CHAP_R.
+        */
+       *nr_out_len = sprintf(nr_out_ptr, "CHAP_N=%s", auth->userid_mutual);
+       *nr_out_len += 1;
+       pr_debug("[server] Sending CHAP_N=%s\n", auth->userid_mutual);
+       /*
+        * Convert response from binary hex to ascii hext.
+        */
+       chap_binaryhex_to_asciihex(response, digest, MD5_SIGNATURE_SIZE);
+       *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s",
+                       response);
+       *nr_out_len += 1;
+       pr_debug("[server] Sending CHAP_R=0x%s\n", response);
+       auth_ret = 0;
+out:
+       kfree(challenge);
+       kfree(challenge_binhex);
+       return auth_ret;
+}
+
+static int chap_got_response(
+       struct iscsi_conn *conn,
+       struct iscsi_node_auth *auth,
+       char *nr_in_ptr,
+       char *nr_out_ptr,
+       unsigned int *nr_out_len)
+{
+       struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
+
+       switch (chap->digest_type) {
+       case CHAP_DIGEST_MD5:
+               if (chap_server_compute_md5(conn, auth, nr_in_ptr,
+                               nr_out_ptr, nr_out_len) < 0)
+                       return -1;
+               return 0;
+       default:
+               pr_err("Unknown CHAP digest type %d!\n",
+                               chap->digest_type);
+               return -1;
+       }
+}
+
+u32 chap_main_loop(
+       struct iscsi_conn *conn,
+       struct iscsi_node_auth *auth,
+       char *in_text,
+       char *out_text,
+       int *in_len,
+       int *out_len)
+{
+       struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol;
+
+       if (!chap) {
+               chap = chap_server_open(conn, auth, in_text, out_text, out_len);
+               if (!chap)
+                       return 2;
+               chap->chap_state = CHAP_STAGE_SERVER_AIC;
+               return 0;
+       } else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) {
+               convert_null_to_semi(in_text, *in_len);
+               if (chap_got_response(conn, auth, in_text, out_text,
+                               out_len) < 0) {
+                       chap_close(conn);
+                       return 2;
+               }
+               if (auth->authenticate_target)
+                       chap->chap_state = CHAP_STAGE_SERVER_NR;
+               else
+                       *out_len = 0;
+               chap_close(conn);
+               return 1;
+       }
+
+       return 2;
+}
diff --git a/drivers/target/iscsi/iscsi_target_auth.h b/drivers/target/iscsi/iscsi_target_auth.h
new file mode 100644 (file)
index 0000000..2f463c0
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _ISCSI_CHAP_H_
+#define _ISCSI_CHAP_H_
+
+#define CHAP_DIGEST_MD5                5
+#define CHAP_DIGEST_SHA                6
+
+#define CHAP_CHALLENGE_LENGTH  16
+#define CHAP_CHALLENGE_STR_LEN 4096
+#define MAX_RESPONSE_LENGTH    64      /* sufficient for MD5 */
+#define        MAX_CHAP_N_SIZE         512
+
+#define MD5_SIGNATURE_SIZE     16      /* 16 bytes in a MD5 message digest */
+
+#define CHAP_STAGE_CLIENT_A    1
+#define CHAP_STAGE_SERVER_AIC  2
+#define CHAP_STAGE_CLIENT_NR   3
+#define CHAP_STAGE_CLIENT_NRIC 4
+#define CHAP_STAGE_SERVER_NR   5
+
+extern u32 chap_main_loop(struct iscsi_conn *, struct iscsi_node_auth *, char *, char *,
+                               int *, int *);
+
+struct iscsi_chap {
+       unsigned char   digest_type;
+       unsigned char   id;
+       unsigned char   challenge[CHAP_CHALLENGE_LENGTH];
+       unsigned int    authenticate_target;
+       unsigned int    chap_state;
+} ____cacheline_aligned;
+
+#endif   /*** _ISCSI_CHAP_H_ ***/
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
new file mode 100644 (file)
index 0000000..32bb92c
--- /dev/null
@@ -0,0 +1,1882 @@
+/*******************************************************************************
+ * This file contains the configfs implementation for iSCSI Target mode
+ * from the LIO-Target Project.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ****************************************************************************/
+
+#include <linux/configfs.h>
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_fabric_lib.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_parameters.h"
+#include "iscsi_target_device.h"
+#include "iscsi_target_erl0.h"
+#include "iscsi_target_nodeattrib.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target.h"
+#include "iscsi_target_stat.h"
+#include "iscsi_target_configfs.h"
+
+struct target_fabric_configfs *lio_target_fabric_configfs;
+
+struct lio_target_configfs_attribute {
+       struct configfs_attribute attr;
+       ssize_t (*show)(void *, char *);
+       ssize_t (*store)(void *, const char *, size_t);
+};
+
+struct iscsi_portal_group *lio_get_tpg_from_tpg_item(
+       struct config_item *item,
+       struct iscsi_tiqn **tiqn_out)
+{
+       struct se_portal_group *se_tpg = container_of(to_config_group(item),
+                                       struct se_portal_group, tpg_group);
+       struct iscsi_portal_group *tpg =
+                       (struct iscsi_portal_group *)se_tpg->se_tpg_fabric_ptr;
+       int ret;
+
+       if (!tpg) {
+               pr_err("Unable to locate struct iscsi_portal_group "
+                       "pointer\n");
+               return NULL;
+       }
+       ret = iscsit_get_tpg(tpg);
+       if (ret < 0)
+               return NULL;
+
+       *tiqn_out = tpg->tpg_tiqn;
+       return tpg;
+}
+
+/* Start items for lio_target_portal_cit */
+
+static ssize_t lio_target_np_show_sctp(
+       struct se_tpg_np *se_tpg_np,
+       char *page)
+{
+       struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
+                               struct iscsi_tpg_np, se_tpg_np);
+       struct iscsi_tpg_np *tpg_np_sctp;
+       ssize_t rb;
+
+       tpg_np_sctp = iscsit_tpg_locate_child_np(tpg_np, ISCSI_SCTP_TCP);
+       if (tpg_np_sctp)
+               rb = sprintf(page, "1\n");
+       else
+               rb = sprintf(page, "0\n");
+
+       return rb;
+}
+
+static ssize_t lio_target_np_store_sctp(
+       struct se_tpg_np *se_tpg_np,
+       const char *page,
+       size_t count)
+{
+       struct iscsi_np *np;
+       struct iscsi_portal_group *tpg;
+       struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
+                               struct iscsi_tpg_np, se_tpg_np);
+       struct iscsi_tpg_np *tpg_np_sctp = NULL;
+       char *endptr;
+       u32 op;
+       int ret;
+
+       op = simple_strtoul(page, &endptr, 0);
+       if ((op != 1) && (op != 0)) {
+               pr_err("Illegal value for tpg_enable: %u\n", op);
+               return -EINVAL;
+       }
+       np = tpg_np->tpg_np;
+       if (!np) {
+               pr_err("Unable to locate struct iscsi_np from"
+                               " struct iscsi_tpg_np\n");
+               return -EINVAL;
+       }
+
+       tpg = tpg_np->tpg;
+       if (iscsit_get_tpg(tpg) < 0)
+               return -EINVAL;
+
+       if (op) {
+               /*
+                * Use existing np->np_sockaddr for SCTP network portal reference
+                */
+               tpg_np_sctp = iscsit_tpg_add_network_portal(tpg, &np->np_sockaddr,
+                                       np->np_ip, tpg_np, ISCSI_SCTP_TCP);
+               if (!tpg_np_sctp || IS_ERR(tpg_np_sctp))
+                       goto out;
+       } else {
+               tpg_np_sctp = iscsit_tpg_locate_child_np(tpg_np, ISCSI_SCTP_TCP);
+               if (!tpg_np_sctp)
+                       goto out;
+
+               ret = iscsit_tpg_del_network_portal(tpg, tpg_np_sctp);
+               if (ret < 0)
+                       goto out;
+       }
+
+       iscsit_put_tpg(tpg);
+       return count;
+out:
+       iscsit_put_tpg(tpg);
+       return -EINVAL;
+}
+
+TF_NP_BASE_ATTR(lio_target, sctp, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *lio_target_portal_attrs[] = {
+       &lio_target_np_sctp.attr,
+       NULL,
+};
+
+/* Stop items for lio_target_portal_cit */
+
+/* Start items for lio_target_np_cit */
+
+#define MAX_PORTAL_LEN         256
+
+struct se_tpg_np *lio_target_call_addnptotpg(
+       struct se_portal_group *se_tpg,
+       struct config_group *group,
+       const char *name)
+{
+       struct iscsi_portal_group *tpg;
+       struct iscsi_tpg_np *tpg_np;
+       char *str, *str2, *ip_str, *port_str;
+       struct __kernel_sockaddr_storage sockaddr;
+       struct sockaddr_in *sock_in;
+       struct sockaddr_in6 *sock_in6;
+       unsigned long port;
+       int ret;
+       char buf[MAX_PORTAL_LEN + 1];
+
+       if (strlen(name) > MAX_PORTAL_LEN) {
+               pr_err("strlen(name): %d exceeds MAX_PORTAL_LEN: %d\n",
+                       (int)strlen(name), MAX_PORTAL_LEN);
+               return ERR_PTR(-EOVERFLOW);
+       }
+       memset(buf, 0, MAX_PORTAL_LEN + 1);
+       snprintf(buf, MAX_PORTAL_LEN, "%s", name);
+
+       memset(&sockaddr, 0, sizeof(struct __kernel_sockaddr_storage));
+
+       str = strstr(buf, "[");
+       if (str) {
+               const char *end;
+
+               str2 = strstr(str, "]");
+               if (!str2) {
+                       pr_err("Unable to locate trailing \"]\""
+                               " in IPv6 iSCSI network portal address\n");
+                       return ERR_PTR(-EINVAL);
+               }
+               str++; /* Skip over leading "[" */
+               *str2 = '\0'; /* Terminate the IPv6 address */
+               str2++; /* Skip over the "]" */
+               port_str = strstr(str2, ":");
+               if (!port_str) {
+                       pr_err("Unable to locate \":port\""
+                               " in IPv6 iSCSI network portal address\n");
+                       return ERR_PTR(-EINVAL);
+               }
+               *port_str = '\0'; /* Terminate string for IP */
+               port_str++; /* Skip over ":" */
+
+               ret = strict_strtoul(port_str, 0, &port);
+               if (ret < 0) {
+                       pr_err("strict_strtoul() failed for port_str: %d\n", ret);
+                       return ERR_PTR(ret);
+               }
+               sock_in6 = (struct sockaddr_in6 *)&sockaddr;
+               sock_in6->sin6_family = AF_INET6;
+               sock_in6->sin6_port = htons((unsigned short)port);
+               ret = in6_pton(str, IPV6_ADDRESS_SPACE,
+                               (void *)&sock_in6->sin6_addr.in6_u, -1, &end);
+               if (ret <= 0) {
+                       pr_err("in6_pton returned: %d\n", ret);
+                       return ERR_PTR(-EINVAL);
+               }
+       } else {
+               str = ip_str = &buf[0];
+               port_str = strstr(ip_str, ":");
+               if (!port_str) {
+                       pr_err("Unable to locate \":port\""
+                               " in IPv4 iSCSI network portal address\n");
+                       return ERR_PTR(-EINVAL);
+               }
+               *port_str = '\0'; /* Terminate string for IP */
+               port_str++; /* Skip over ":" */
+
+               ret = strict_strtoul(port_str, 0, &port);
+               if (ret < 0) {
+                       pr_err("strict_strtoul() failed for port_str: %d\n", ret);
+                       return ERR_PTR(ret);
+               }
+               sock_in = (struct sockaddr_in *)&sockaddr;
+               sock_in->sin_family = AF_INET;
+               sock_in->sin_port = htons((unsigned short)port);
+               sock_in->sin_addr.s_addr = in_aton(ip_str);
+       }
+       tpg = container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg);
+       ret = iscsit_get_tpg(tpg);
+       if (ret < 0)
+               return ERR_PTR(-EINVAL);
+
+       pr_debug("LIO_Target_ConfigFS: REGISTER -> %s TPGT: %hu"
+               " PORTAL: %s\n",
+               config_item_name(&se_tpg->se_tpg_wwn->wwn_group.cg_item),
+               tpg->tpgt, name);
+       /*
+        * Assume ISCSI_TCP by default.  Other network portals for other
+        * iSCSI fabrics:
+        *
+        * Traditional iSCSI over SCTP (initial support)
+        * iSER/TCP (TODO, hardware available)
+        * iSER/SCTP (TODO, software emulation with osc-iwarp)
+        * iSER/IB (TODO, hardware available)
+        *
+        * can be enabled with atributes under
+        * sys/kernel/config/iscsi/$IQN/$TPG/np/$IP:$PORT/
+        *
+        */
+       tpg_np = iscsit_tpg_add_network_portal(tpg, &sockaddr, str, NULL,
+                               ISCSI_TCP);
+       if (IS_ERR(tpg_np)) {
+               iscsit_put_tpg(tpg);
+               return ERR_PTR(PTR_ERR(tpg_np));
+       }
+       pr_debug("LIO_Target_ConfigFS: addnptotpg done!\n");
+
+       iscsit_put_tpg(tpg);
+       return &tpg_np->se_tpg_np;
+}
+
+static void lio_target_call_delnpfromtpg(
+       struct se_tpg_np *se_tpg_np)
+{
+       struct iscsi_portal_group *tpg;
+       struct iscsi_tpg_np *tpg_np;
+       struct se_portal_group *se_tpg;
+       int ret;
+
+       tpg_np = container_of(se_tpg_np, struct iscsi_tpg_np, se_tpg_np);
+       tpg = tpg_np->tpg;
+       ret = iscsit_get_tpg(tpg);
+       if (ret < 0)
+               return;
+
+       se_tpg = &tpg->tpg_se_tpg;
+       pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s TPGT: %hu"
+               " PORTAL: %s:%hu\n", config_item_name(&se_tpg->se_tpg_wwn->wwn_group.cg_item),
+               tpg->tpgt, tpg_np->tpg_np->np_ip, tpg_np->tpg_np->np_port);
+
+       ret = iscsit_tpg_del_network_portal(tpg, tpg_np);
+       if (ret < 0)
+               goto out;
+
+       pr_debug("LIO_Target_ConfigFS: delnpfromtpg done!\n");
+out:
+       iscsit_put_tpg(tpg);
+}
+
+/* End items for lio_target_np_cit */
+
+/* Start items for lio_target_nacl_attrib_cit */
+
+#define DEF_NACL_ATTRIB(name)                                          \
+static ssize_t iscsi_nacl_attrib_show_##name(                          \
+       struct se_node_acl *se_nacl,                                    \
+       char *page)                                                     \
+{                                                                      \
+       struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \
+                                       se_node_acl);                   \
+                                                                       \
+       return sprintf(page, "%u\n", ISCSI_NODE_ATTRIB(nacl)->name);    \
+}                                                                      \
+                                                                       \
+static ssize_t iscsi_nacl_attrib_store_##name(                         \
+       struct se_node_acl *se_nacl,                                    \
+       const char *page,                                               \
+       size_t count)                                                   \
+{                                                                      \
+       struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \
+                                       se_node_acl);                   \
+       char *endptr;                                                   \
+       u32 val;                                                        \
+       int ret;                                                        \
+                                                                       \
+       val = simple_strtoul(page, &endptr, 0);                         \
+       ret = iscsit_na_##name(nacl, val);                              \
+       if (ret < 0)                                                    \
+               return ret;                                             \
+                                                                       \
+       return count;                                                   \
+}
+
+#define NACL_ATTR(_name, _mode) TF_NACL_ATTRIB_ATTR(iscsi, _name, _mode);
+/*
+ * Define iscsi_node_attrib_s_dataout_timeout
+ */
+DEF_NACL_ATTRIB(dataout_timeout);
+NACL_ATTR(dataout_timeout, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_node_attrib_s_dataout_timeout_retries
+ */
+DEF_NACL_ATTRIB(dataout_timeout_retries);
+NACL_ATTR(dataout_timeout_retries, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_node_attrib_s_default_erl
+ */
+DEF_NACL_ATTRIB(default_erl);
+NACL_ATTR(default_erl, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_node_attrib_s_nopin_timeout
+ */
+DEF_NACL_ATTRIB(nopin_timeout);
+NACL_ATTR(nopin_timeout, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_node_attrib_s_nopin_response_timeout
+ */
+DEF_NACL_ATTRIB(nopin_response_timeout);
+NACL_ATTR(nopin_response_timeout, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_node_attrib_s_random_datain_pdu_offsets
+ */
+DEF_NACL_ATTRIB(random_datain_pdu_offsets);
+NACL_ATTR(random_datain_pdu_offsets, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_node_attrib_s_random_datain_seq_offsets
+ */
+DEF_NACL_ATTRIB(random_datain_seq_offsets);
+NACL_ATTR(random_datain_seq_offsets, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_node_attrib_s_random_r2t_offsets
+ */
+DEF_NACL_ATTRIB(random_r2t_offsets);
+NACL_ATTR(random_r2t_offsets, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *lio_target_nacl_attrib_attrs[] = {
+       &iscsi_nacl_attrib_dataout_timeout.attr,
+       &iscsi_nacl_attrib_dataout_timeout_retries.attr,
+       &iscsi_nacl_attrib_default_erl.attr,
+       &iscsi_nacl_attrib_nopin_timeout.attr,
+       &iscsi_nacl_attrib_nopin_response_timeout.attr,
+       &iscsi_nacl_attrib_random_datain_pdu_offsets.attr,
+       &iscsi_nacl_attrib_random_datain_seq_offsets.attr,
+       &iscsi_nacl_attrib_random_r2t_offsets.attr,
+       NULL,
+};
+
+/* End items for lio_target_nacl_attrib_cit */
+
+/* Start items for lio_target_nacl_auth_cit */
+
+#define __DEF_NACL_AUTH_STR(prefix, name, flags)                       \
+static ssize_t __iscsi_##prefix##_show_##name(                         \
+       struct iscsi_node_acl *nacl,                                    \
+       char *page)                                                     \
+{                                                                      \
+       struct iscsi_node_auth *auth = &nacl->node_auth;                \
+                                                                       \
+       if (!capable(CAP_SYS_ADMIN))                                    \
+               return -EPERM;                                          \
+       return snprintf(page, PAGE_SIZE, "%s\n", auth->name);           \
+}                                                                      \
+                                                                       \
+static ssize_t __iscsi_##prefix##_store_##name(                                \
+       struct iscsi_node_acl *nacl,                                    \
+       const char *page,                                               \
+       size_t count)                                                   \
+{                                                                      \
+       struct iscsi_node_auth *auth = &nacl->node_auth;                \
+                                                                       \
+       if (!capable(CAP_SYS_ADMIN))                                    \
+               return -EPERM;                                          \
+                                                                       \
+       snprintf(auth->name, PAGE_SIZE, "%s", page);                    \
+       if (!strncmp("NULL", auth->name, 4))                            \
+               auth->naf_flags &= ~flags;                              \
+       else                                                            \
+               auth->naf_flags |= flags;                               \
+                                                                       \
+       if ((auth->naf_flags & NAF_USERID_IN_SET) &&                    \
+           (auth->naf_flags & NAF_PASSWORD_IN_SET))                    \
+               auth->authenticate_target = 1;                          \
+       else                                                            \
+               auth->authenticate_target = 0;                          \
+                                                                       \
+       return count;                                                   \
+}
+
+#define __DEF_NACL_AUTH_INT(prefix, name)                              \
+static ssize_t __iscsi_##prefix##_show_##name(                         \
+       struct iscsi_node_acl *nacl,                                    \
+       char *page)                                                     \
+{                                                                      \
+       struct iscsi_node_auth *auth = &nacl->node_auth;                \
+                                                                       \
+       if (!capable(CAP_SYS_ADMIN))                                    \
+               return -EPERM;                                          \
+                                                                       \
+       return snprintf(page, PAGE_SIZE, "%d\n", auth->name);           \
+}
+
+#define DEF_NACL_AUTH_STR(name, flags)                                 \
+       __DEF_NACL_AUTH_STR(nacl_auth, name, flags)                     \
+static ssize_t iscsi_nacl_auth_show_##name(                            \
+       struct se_node_acl *nacl,                                       \
+       char *page)                                                     \
+{                                                                      \
+       return __iscsi_nacl_auth_show_##name(container_of(nacl,         \
+                       struct iscsi_node_acl, se_node_acl), page);             \
+}                                                                      \
+static ssize_t iscsi_nacl_auth_store_##name(                           \
+       struct se_node_acl *nacl,                                       \
+       const char *page,                                               \
+       size_t count)                                                   \
+{                                                                      \
+       return __iscsi_nacl_auth_store_##name(container_of(nacl,        \
+                       struct iscsi_node_acl, se_node_acl), page, count);      \
+}
+
+#define DEF_NACL_AUTH_INT(name)                                                \
+       __DEF_NACL_AUTH_INT(nacl_auth, name)                            \
+static ssize_t iscsi_nacl_auth_show_##name(                            \
+       struct se_node_acl *nacl,                                       \
+       char *page)                                                     \
+{                                                                      \
+       return __iscsi_nacl_auth_show_##name(container_of(nacl,         \
+                       struct iscsi_node_acl, se_node_acl), page);             \
+}
+
+#define AUTH_ATTR(_name, _mode)        TF_NACL_AUTH_ATTR(iscsi, _name, _mode);
+#define AUTH_ATTR_RO(_name) TF_NACL_AUTH_ATTR_RO(iscsi, _name);
+
+/*
+ * One-way authentication userid
+ */
+DEF_NACL_AUTH_STR(userid, NAF_USERID_SET);
+AUTH_ATTR(userid, S_IRUGO | S_IWUSR);
+/*
+ * One-way authentication password
+ */
+DEF_NACL_AUTH_STR(password, NAF_PASSWORD_SET);
+AUTH_ATTR(password, S_IRUGO | S_IWUSR);
+/*
+ * Enforce mutual authentication
+ */
+DEF_NACL_AUTH_INT(authenticate_target);
+AUTH_ATTR_RO(authenticate_target);
+/*
+ * Mutual authentication userid
+ */
+DEF_NACL_AUTH_STR(userid_mutual, NAF_USERID_IN_SET);
+AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR);
+/*
+ * Mutual authentication password
+ */
+DEF_NACL_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET);
+AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *lio_target_nacl_auth_attrs[] = {
+       &iscsi_nacl_auth_userid.attr,
+       &iscsi_nacl_auth_password.attr,
+       &iscsi_nacl_auth_authenticate_target.attr,
+       &iscsi_nacl_auth_userid_mutual.attr,
+       &iscsi_nacl_auth_password_mutual.attr,
+       NULL,
+};
+
+/* End items for lio_target_nacl_auth_cit */
+
+/* Start items for lio_target_nacl_param_cit */
+
+#define DEF_NACL_PARAM(name)                                           \
+static ssize_t iscsi_nacl_param_show_##name(                           \
+       struct se_node_acl *se_nacl,                                    \
+       char *page)                                                     \
+{                                                                      \
+       struct iscsi_session *sess;                                     \
+       struct se_session *se_sess;                                     \
+       ssize_t rb;                                                     \
+                                                                       \
+       spin_lock_bh(&se_nacl->nacl_sess_lock);                         \
+       se_sess = se_nacl->nacl_sess;                                   \
+       if (!se_sess) {                                                 \
+               rb = snprintf(page, PAGE_SIZE,                          \
+                       "No Active iSCSI Session\n");                   \
+       } else {                                                        \
+               sess = se_sess->fabric_sess_ptr;                        \
+               rb = snprintf(page, PAGE_SIZE, "%u\n",                  \
+                       (u32)sess->sess_ops->name);                     \
+       }                                                               \
+       spin_unlock_bh(&se_nacl->nacl_sess_lock);                       \
+                                                                       \
+       return rb;                                                      \
+}
+
+#define NACL_PARAM_ATTR(_name) TF_NACL_PARAM_ATTR_RO(iscsi, _name);
+
+DEF_NACL_PARAM(MaxConnections);
+NACL_PARAM_ATTR(MaxConnections);
+
+DEF_NACL_PARAM(InitialR2T);
+NACL_PARAM_ATTR(InitialR2T);
+
+DEF_NACL_PARAM(ImmediateData);
+NACL_PARAM_ATTR(ImmediateData);
+
+DEF_NACL_PARAM(MaxBurstLength);
+NACL_PARAM_ATTR(MaxBurstLength);
+
+DEF_NACL_PARAM(FirstBurstLength);
+NACL_PARAM_ATTR(FirstBurstLength);
+
+DEF_NACL_PARAM(DefaultTime2Wait);
+NACL_PARAM_ATTR(DefaultTime2Wait);
+
+DEF_NACL_PARAM(DefaultTime2Retain);
+NACL_PARAM_ATTR(DefaultTime2Retain);
+
+DEF_NACL_PARAM(MaxOutstandingR2T);
+NACL_PARAM_ATTR(MaxOutstandingR2T);
+
+DEF_NACL_PARAM(DataPDUInOrder);
+NACL_PARAM_ATTR(DataPDUInOrder);
+
+DEF_NACL_PARAM(DataSequenceInOrder);
+NACL_PARAM_ATTR(DataSequenceInOrder);
+
+DEF_NACL_PARAM(ErrorRecoveryLevel);
+NACL_PARAM_ATTR(ErrorRecoveryLevel);
+
+static struct configfs_attribute *lio_target_nacl_param_attrs[] = {
+       &iscsi_nacl_param_MaxConnections.attr,
+       &iscsi_nacl_param_InitialR2T.attr,
+       &iscsi_nacl_param_ImmediateData.attr,
+       &iscsi_nacl_param_MaxBurstLength.attr,
+       &iscsi_nacl_param_FirstBurstLength.attr,
+       &iscsi_nacl_param_DefaultTime2Wait.attr,
+       &iscsi_nacl_param_DefaultTime2Retain.attr,
+       &iscsi_nacl_param_MaxOutstandingR2T.attr,
+       &iscsi_nacl_param_DataPDUInOrder.attr,
+       &iscsi_nacl_param_DataSequenceInOrder.attr,
+       &iscsi_nacl_param_ErrorRecoveryLevel.attr,
+       NULL,
+};
+
+/* End items for lio_target_nacl_param_cit */
+
+/* Start items for lio_target_acl_cit */
+
+static ssize_t lio_target_nacl_show_info(
+       struct se_node_acl *se_nacl,
+       char *page)
+{
+       struct iscsi_session *sess;
+       struct iscsi_conn *conn;
+       struct se_session *se_sess;
+       ssize_t rb = 0;
+
+       spin_lock_bh(&se_nacl->nacl_sess_lock);
+       se_sess = se_nacl->nacl_sess;
+       if (!se_sess) {
+               rb += sprintf(page+rb, "No active iSCSI Session for Initiator"
+                       " Endpoint: %s\n", se_nacl->initiatorname);
+       } else {
+               sess = se_sess->fabric_sess_ptr;
+
+               if (sess->sess_ops->InitiatorName)
+                       rb += sprintf(page+rb, "InitiatorName: %s\n",
+                               sess->sess_ops->InitiatorName);
+               if (sess->sess_ops->InitiatorAlias)
+                       rb += sprintf(page+rb, "InitiatorAlias: %s\n",
+                               sess->sess_ops->InitiatorAlias);
+
+               rb += sprintf(page+rb, "LIO Session ID: %u   "
+                       "ISID: 0x%02x %02x %02x %02x %02x %02x  "
+                       "TSIH: %hu  ", sess->sid,
+                       sess->isid[0], sess->isid[1], sess->isid[2],
+                       sess->isid[3], sess->isid[4], sess->isid[5],
+                       sess->tsih);
+               rb += sprintf(page+rb, "SessionType: %s\n",
+                               (sess->sess_ops->SessionType) ?
+                               "Discovery" : "Normal");
+               rb += sprintf(page+rb, "Session State: ");
+               switch (sess->session_state) {
+               case TARG_SESS_STATE_FREE:
+                       rb += sprintf(page+rb, "TARG_SESS_FREE\n");
+                       break;
+               case TARG_SESS_STATE_ACTIVE:
+                       rb += sprintf(page+rb, "TARG_SESS_STATE_ACTIVE\n");
+                       break;
+               case TARG_SESS_STATE_LOGGED_IN:
+                       rb += sprintf(page+rb, "TARG_SESS_STATE_LOGGED_IN\n");
+                       break;
+               case TARG_SESS_STATE_FAILED:
+                       rb += sprintf(page+rb, "TARG_SESS_STATE_FAILED\n");
+                       break;
+               case TARG_SESS_STATE_IN_CONTINUE:
+                       rb += sprintf(page+rb, "TARG_SESS_STATE_IN_CONTINUE\n");
+                       break;
+               default:
+                       rb += sprintf(page+rb, "ERROR: Unknown Session"
+                                       " State!\n");
+                       break;
+               }
+
+               rb += sprintf(page+rb, "---------------------[iSCSI Session"
+                               " Values]-----------------------\n");
+               rb += sprintf(page+rb, "  CmdSN/WR  :  CmdSN/WC  :  ExpCmdSN"
+                               "  :  MaxCmdSN  :     ITT    :     TTT\n");
+               rb += sprintf(page+rb, " 0x%08x   0x%08x   0x%08x   0x%08x"
+                               "   0x%08x   0x%08x\n",
+                       sess->cmdsn_window,
+                       (sess->max_cmd_sn - sess->exp_cmd_sn) + 1,
+                       sess->exp_cmd_sn, sess->max_cmd_sn,
+                       sess->init_task_tag, sess->targ_xfer_tag);
+               rb += sprintf(page+rb, "----------------------[iSCSI"
+                               " Connections]-------------------------\n");
+
+               spin_lock(&sess->conn_lock);
+               list_for_each_entry(conn, &sess->sess_conn_list, conn_list) {
+                       rb += sprintf(page+rb, "CID: %hu  Connection"
+                                       " State: ", conn->cid);
+                       switch (conn->conn_state) {
+                       case TARG_CONN_STATE_FREE:
+                               rb += sprintf(page+rb,
+                                       "TARG_CONN_STATE_FREE\n");
+                               break;
+                       case TARG_CONN_STATE_XPT_UP:
+                               rb += sprintf(page+rb,
+                                       "TARG_CONN_STATE_XPT_UP\n");
+                               break;
+                       case TARG_CONN_STATE_IN_LOGIN:
+                               rb += sprintf(page+rb,
+                                       "TARG_CONN_STATE_IN_LOGIN\n");
+                               break;
+                       case TARG_CONN_STATE_LOGGED_IN:
+                               rb += sprintf(page+rb,
+                                       "TARG_CONN_STATE_LOGGED_IN\n");
+                               break;
+                       case TARG_CONN_STATE_IN_LOGOUT:
+                               rb += sprintf(page+rb,
+                                       "TARG_CONN_STATE_IN_LOGOUT\n");
+                               break;
+                       case TARG_CONN_STATE_LOGOUT_REQUESTED:
+                               rb += sprintf(page+rb,
+                                       "TARG_CONN_STATE_LOGOUT_REQUESTED\n");
+                               break;
+                       case TARG_CONN_STATE_CLEANUP_WAIT:
+                               rb += sprintf(page+rb,
+                                       "TARG_CONN_STATE_CLEANUP_WAIT\n");
+                               break;
+                       default:
+                               rb += sprintf(page+rb,
+                                       "ERROR: Unknown Connection State!\n");
+                               break;
+                       }
+
+                       rb += sprintf(page+rb, "   Address %s %s", conn->login_ip,
+                               (conn->network_transport == ISCSI_TCP) ?
+                               "TCP" : "SCTP");
+                       rb += sprintf(page+rb, "  StatSN: 0x%08x\n",
+                               conn->stat_sn);
+               }
+               spin_unlock(&sess->conn_lock);
+       }
+       spin_unlock_bh(&se_nacl->nacl_sess_lock);
+
+       return rb;
+}
+
+TF_NACL_BASE_ATTR_RO(lio_target, info);
+
+static ssize_t lio_target_nacl_show_cmdsn_depth(
+       struct se_node_acl *se_nacl,
+       char *page)
+{
+       return sprintf(page, "%u\n", se_nacl->queue_depth);
+}
+
+static ssize_t lio_target_nacl_store_cmdsn_depth(
+       struct se_node_acl *se_nacl,
+       const char *page,
+       size_t count)
+{
+       struct se_portal_group *se_tpg = se_nacl->se_tpg;
+       struct iscsi_portal_group *tpg = container_of(se_tpg,
+                       struct iscsi_portal_group, tpg_se_tpg);
+       struct config_item *acl_ci, *tpg_ci, *wwn_ci;
+       char *endptr;
+       u32 cmdsn_depth = 0;
+       int ret;
+
+       cmdsn_depth = simple_strtoul(page, &endptr, 0);
+       if (cmdsn_depth > TA_DEFAULT_CMDSN_DEPTH_MAX) {
+               pr_err("Passed cmdsn_depth: %u exceeds"
+                       " TA_DEFAULT_CMDSN_DEPTH_MAX: %u\n", cmdsn_depth,
+                       TA_DEFAULT_CMDSN_DEPTH_MAX);
+               return -EINVAL;
+       }
+       acl_ci = &se_nacl->acl_group.cg_item;
+       if (!acl_ci) {
+               pr_err("Unable to locatel acl_ci\n");
+               return -EINVAL;
+       }
+       tpg_ci = &acl_ci->ci_parent->ci_group->cg_item;
+       if (!tpg_ci) {
+               pr_err("Unable to locate tpg_ci\n");
+               return -EINVAL;
+       }
+       wwn_ci = &tpg_ci->ci_group->cg_item;
+       if (!wwn_ci) {
+               pr_err("Unable to locate config_item wwn_ci\n");
+               return -EINVAL;
+       }
+
+       if (iscsit_get_tpg(tpg) < 0)
+               return -EINVAL;
+       /*
+        * iscsit_tpg_set_initiator_node_queue_depth() assumes force=1
+        */
+       ret = iscsit_tpg_set_initiator_node_queue_depth(tpg,
+                               config_item_name(acl_ci), cmdsn_depth, 1);
+
+       pr_debug("LIO_Target_ConfigFS: %s/%s Set CmdSN Window: %u for"
+               "InitiatorName: %s\n", config_item_name(wwn_ci),
+               config_item_name(tpg_ci), cmdsn_depth,
+               config_item_name(acl_ci));
+
+       iscsit_put_tpg(tpg);
+       return (!ret) ? count : (ssize_t)ret;
+}
+
+TF_NACL_BASE_ATTR(lio_target, cmdsn_depth, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *lio_target_initiator_attrs[] = {
+       &lio_target_nacl_info.attr,
+       &lio_target_nacl_cmdsn_depth.attr,
+       NULL,
+};
+
+static struct se_node_acl *lio_tpg_alloc_fabric_acl(
+       struct se_portal_group *se_tpg)
+{
+       struct iscsi_node_acl *acl;
+
+       acl = kzalloc(sizeof(struct iscsi_node_acl), GFP_KERNEL);
+       if (!acl) {
+               pr_err("Unable to allocate memory for struct iscsi_node_acl\n");
+               return NULL;
+       }
+
+       return &acl->se_node_acl;
+}
+
+static struct se_node_acl *lio_target_make_nodeacl(
+       struct se_portal_group *se_tpg,
+       struct config_group *group,
+       const char *name)
+{
+       struct config_group *stats_cg;
+       struct iscsi_node_acl *acl;
+       struct se_node_acl *se_nacl_new, *se_nacl;
+       struct iscsi_portal_group *tpg = container_of(se_tpg,
+                       struct iscsi_portal_group, tpg_se_tpg);
+       u32 cmdsn_depth;
+
+       se_nacl_new = lio_tpg_alloc_fabric_acl(se_tpg);
+       if (!se_nacl_new)
+               return ERR_PTR(-ENOMEM);
+
+       acl = container_of(se_nacl_new, struct iscsi_node_acl,
+                               se_node_acl);
+
+       cmdsn_depth = ISCSI_TPG_ATTRIB(tpg)->default_cmdsn_depth;
+       /*
+        * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+        * when converting a NdoeACL from demo mode -> explict
+        */
+       se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+                               name, cmdsn_depth);
+       if (IS_ERR(se_nacl))
+               return se_nacl;
+
+       stats_cg = &acl->se_node_acl.acl_fabric_stat_group;
+
+       stats_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+                               GFP_KERNEL);
+       if (!stats_cg->default_groups) {
+               pr_err("Unable to allocate memory for"
+                               " stats_cg->default_groups\n");
+               core_tpg_del_initiator_node_acl(se_tpg, se_nacl, 1);
+               kfree(acl);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       stats_cg->default_groups[0] = &NODE_STAT_GRPS(acl)->iscsi_sess_stats_group;
+       stats_cg->default_groups[1] = NULL;
+       config_group_init_type_name(&NODE_STAT_GRPS(acl)->iscsi_sess_stats_group,
+                       "iscsi_sess_stats", &iscsi_stat_sess_cit);
+
+       return se_nacl;
+}
+
+static void lio_target_drop_nodeacl(
+       struct se_node_acl *se_nacl)
+{
+       struct se_portal_group *se_tpg = se_nacl->se_tpg;
+       struct iscsi_node_acl *acl = container_of(se_nacl,
+                       struct iscsi_node_acl, se_node_acl);
+       struct config_item *df_item;
+       struct config_group *stats_cg;
+       int i;
+
+       stats_cg = &acl->se_node_acl.acl_fabric_stat_group;
+       for (i = 0; stats_cg->default_groups[i]; i++) {
+               df_item = &stats_cg->default_groups[i]->cg_item;
+               stats_cg->default_groups[i] = NULL;
+               config_item_put(df_item);
+       }
+       kfree(stats_cg->default_groups);
+
+       core_tpg_del_initiator_node_acl(se_tpg, se_nacl, 1);
+       kfree(acl);
+}
+
+/* End items for lio_target_acl_cit */
+
+/* Start items for lio_target_tpg_attrib_cit */
+
+#define DEF_TPG_ATTRIB(name)                                           \
+                                                                       \
+static ssize_t iscsi_tpg_attrib_show_##name(                           \
+       struct se_portal_group *se_tpg,                         \
+       char *page)                                                     \
+{                                                                      \
+       struct iscsi_portal_group *tpg = container_of(se_tpg,           \
+                       struct iscsi_portal_group, tpg_se_tpg); \
+       ssize_t rb;                                                     \
+                                                                       \
+       if (iscsit_get_tpg(tpg) < 0)                                    \
+               return -EINVAL;                                         \
+                                                                       \
+       rb = sprintf(page, "%u\n", ISCSI_TPG_ATTRIB(tpg)->name);        \
+       iscsit_put_tpg(tpg);                                            \
+       return rb;                                                      \
+}                                                                      \
+                                                                       \
+static ssize_t iscsi_tpg_attrib_store_##name(                          \
+       struct se_portal_group *se_tpg,                         \
+       const char *page,                                               \
+       size_t count)                                                   \
+{                                                                      \
+       struct iscsi_portal_group *tpg = container_of(se_tpg,           \
+                       struct iscsi_portal_group, tpg_se_tpg); \
+       char *endptr;                                                   \
+       u32 val;                                                        \
+       int ret;                                                        \
+                                                                       \
+       if (iscsit_get_tpg(tpg) < 0)                                    \
+               return -EINVAL;                                         \
+                                                                       \
+       val = simple_strtoul(page, &endptr, 0);                         \
+       ret = iscsit_ta_##name(tpg, val);                               \
+       if (ret < 0)                                                    \
+               goto out;                                               \
+                                                                       \
+       iscsit_put_tpg(tpg);                                            \
+       return count;                                                   \
+out:                                                                   \
+       iscsit_put_tpg(tpg);                                            \
+       return ret;                                                     \
+}
+
+#define TPG_ATTR(_name, _mode) TF_TPG_ATTRIB_ATTR(iscsi, _name, _mode);
+
+/*
+ * Define iscsi_tpg_attrib_s_authentication
+ */
+DEF_TPG_ATTRIB(authentication);
+TPG_ATTR(authentication, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_tpg_attrib_s_login_timeout
+ */
+DEF_TPG_ATTRIB(login_timeout);
+TPG_ATTR(login_timeout, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_tpg_attrib_s_netif_timeout
+ */
+DEF_TPG_ATTRIB(netif_timeout);
+TPG_ATTR(netif_timeout, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_tpg_attrib_s_generate_node_acls
+ */
+DEF_TPG_ATTRIB(generate_node_acls);
+TPG_ATTR(generate_node_acls, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_tpg_attrib_s_default_cmdsn_depth
+ */
+DEF_TPG_ATTRIB(default_cmdsn_depth);
+TPG_ATTR(default_cmdsn_depth, S_IRUGO | S_IWUSR);
+/*
+ Define iscsi_tpg_attrib_s_cache_dynamic_acls
+ */
+DEF_TPG_ATTRIB(cache_dynamic_acls);
+TPG_ATTR(cache_dynamic_acls, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_tpg_attrib_s_demo_mode_write_protect
+ */
+DEF_TPG_ATTRIB(demo_mode_write_protect);
+TPG_ATTR(demo_mode_write_protect, S_IRUGO | S_IWUSR);
+/*
+ * Define iscsi_tpg_attrib_s_prod_mode_write_protect
+ */
+DEF_TPG_ATTRIB(prod_mode_write_protect);
+TPG_ATTR(prod_mode_write_protect, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
+       &iscsi_tpg_attrib_authentication.attr,
+       &iscsi_tpg_attrib_login_timeout.attr,
+       &iscsi_tpg_attrib_netif_timeout.attr,
+       &iscsi_tpg_attrib_generate_node_acls.attr,
+       &iscsi_tpg_attrib_default_cmdsn_depth.attr,
+       &iscsi_tpg_attrib_cache_dynamic_acls.attr,
+       &iscsi_tpg_attrib_demo_mode_write_protect.attr,
+       &iscsi_tpg_attrib_prod_mode_write_protect.attr,
+       NULL,
+};
+
+/* End items for lio_target_tpg_attrib_cit */
+
+/* Start items for lio_target_tpg_param_cit */
+
+#define DEF_TPG_PARAM(name)                                            \
+static ssize_t iscsi_tpg_param_show_##name(                            \
+       struct se_portal_group *se_tpg,                                 \
+       char *page)                                                     \
+{                                                                      \
+       struct iscsi_portal_group *tpg = container_of(se_tpg,           \
+                       struct iscsi_portal_group, tpg_se_tpg);         \
+       struct iscsi_param *param;                                      \
+       ssize_t rb;                                                     \
+                                                                       \
+       if (iscsit_get_tpg(tpg) < 0)                                    \
+               return -EINVAL;                                         \
+                                                                       \
+       param = iscsi_find_param_from_key(__stringify(name),            \
+                               tpg->param_list);                       \
+       if (!param) {                                                   \
+               iscsit_put_tpg(tpg);                                    \
+               return -EINVAL;                                         \
+       }                                                               \
+       rb = snprintf(page, PAGE_SIZE, "%s\n", param->value);           \
+                                                                       \
+       iscsit_put_tpg(tpg);                                            \
+       return rb;                                                      \
+}                                                                      \
+static ssize_t iscsi_tpg_param_store_##name(                           \
+       struct se_portal_group *se_tpg,                         \
+       const char *page,                                               \
+       size_t count)                                                   \
+{                                                                      \
+       struct iscsi_portal_group *tpg = container_of(se_tpg,           \
+                       struct iscsi_portal_group, tpg_se_tpg);         \
+       char *buf;                                                      \
+       int ret;                                                        \
+                                                                       \
+       buf = kzalloc(PAGE_SIZE, GFP_KERNEL);                           \
+       if (!buf)                                                       \
+               return -ENOMEM;                                         \
+       snprintf(buf, PAGE_SIZE, "%s=%s", __stringify(name), page);     \
+       buf[strlen(buf)-1] = '\0'; /* Kill newline */                   \
+                                                                       \
+       if (iscsit_get_tpg(tpg) < 0) {                                  \
+               kfree(buf);                                             \
+               return -EINVAL;                                         \
+       }                                                               \
+                                                                       \
+       ret = iscsi_change_param_value(buf, tpg->param_list, 1);        \
+       if (ret < 0)                                                    \
+               goto out;                                               \
+                                                                       \
+       kfree(buf);                                                     \
+       iscsit_put_tpg(tpg);                                            \
+       return count;                                                   \
+out:                                                                   \
+       kfree(buf);                                                     \
+       iscsit_put_tpg(tpg);                                            \
+       return -EINVAL;                                         \
+}
+
+#define TPG_PARAM_ATTR(_name, _mode) TF_TPG_PARAM_ATTR(iscsi, _name, _mode);
+
+DEF_TPG_PARAM(AuthMethod);
+TPG_PARAM_ATTR(AuthMethod, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(HeaderDigest);
+TPG_PARAM_ATTR(HeaderDigest, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(DataDigest);
+TPG_PARAM_ATTR(DataDigest, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(MaxConnections);
+TPG_PARAM_ATTR(MaxConnections, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(TargetAlias);
+TPG_PARAM_ATTR(TargetAlias, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(InitialR2T);
+TPG_PARAM_ATTR(InitialR2T, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(ImmediateData);
+TPG_PARAM_ATTR(ImmediateData, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(MaxRecvDataSegmentLength);
+TPG_PARAM_ATTR(MaxRecvDataSegmentLength, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(MaxBurstLength);
+TPG_PARAM_ATTR(MaxBurstLength, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(FirstBurstLength);
+TPG_PARAM_ATTR(FirstBurstLength, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(DefaultTime2Wait);
+TPG_PARAM_ATTR(DefaultTime2Wait, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(DefaultTime2Retain);
+TPG_PARAM_ATTR(DefaultTime2Retain, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(MaxOutstandingR2T);
+TPG_PARAM_ATTR(MaxOutstandingR2T, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(DataPDUInOrder);
+TPG_PARAM_ATTR(DataPDUInOrder, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(DataSequenceInOrder);
+TPG_PARAM_ATTR(DataSequenceInOrder, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(ErrorRecoveryLevel);
+TPG_PARAM_ATTR(ErrorRecoveryLevel, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(IFMarker);
+TPG_PARAM_ATTR(IFMarker, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(OFMarker);
+TPG_PARAM_ATTR(OFMarker, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(IFMarkInt);
+TPG_PARAM_ATTR(IFMarkInt, S_IRUGO | S_IWUSR);
+
+DEF_TPG_PARAM(OFMarkInt);
+TPG_PARAM_ATTR(OFMarkInt, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *lio_target_tpg_param_attrs[] = {
+       &iscsi_tpg_param_AuthMethod.attr,
+       &iscsi_tpg_param_HeaderDigest.attr,
+       &iscsi_tpg_param_DataDigest.attr,
+       &iscsi_tpg_param_MaxConnections.attr,
+       &iscsi_tpg_param_TargetAlias.attr,
+       &iscsi_tpg_param_InitialR2T.attr,
+       &iscsi_tpg_param_ImmediateData.attr,
+       &iscsi_tpg_param_MaxRecvDataSegmentLength.attr,
+       &iscsi_tpg_param_MaxBurstLength.attr,
+       &iscsi_tpg_param_FirstBurstLength.attr,
+       &iscsi_tpg_param_DefaultTime2Wait.attr,
+       &iscsi_tpg_param_DefaultTime2Retain.attr,
+       &iscsi_tpg_param_MaxOutstandingR2T.attr,
+       &iscsi_tpg_param_DataPDUInOrder.attr,
+       &iscsi_tpg_param_DataSequenceInOrder.attr,
+       &iscsi_tpg_param_ErrorRecoveryLevel.attr,
+       &iscsi_tpg_param_IFMarker.attr,
+       &iscsi_tpg_param_OFMarker.attr,
+       &iscsi_tpg_param_IFMarkInt.attr,
+       &iscsi_tpg_param_OFMarkInt.attr,
+       NULL,
+};
+
+/* End items for lio_target_tpg_param_cit */
+
+/* Start items for lio_target_tpg_cit */
+
+static ssize_t lio_target_tpg_show_enable(
+       struct se_portal_group *se_tpg,
+       char *page)
+{
+       struct iscsi_portal_group *tpg = container_of(se_tpg,
+                       struct iscsi_portal_group, tpg_se_tpg);
+       ssize_t len;
+
+       spin_lock(&tpg->tpg_state_lock);
+       len = sprintf(page, "%d\n",
+                       (tpg->tpg_state == TPG_STATE_ACTIVE) ? 1 : 0);
+       spin_unlock(&tpg->tpg_state_lock);
+
+       return len;
+}
+
+static ssize_t lio_target_tpg_store_enable(
+       struct se_portal_group *se_tpg,
+       const char *page,
+       size_t count)
+{
+       struct iscsi_portal_group *tpg = container_of(se_tpg,
+                       struct iscsi_portal_group, tpg_se_tpg);
+       char *endptr;
+       u32 op;
+       int ret = 0;
+
+       op = simple_strtoul(page, &endptr, 0);
+       if ((op != 1) && (op != 0)) {
+               pr_err("Illegal value for tpg_enable: %u\n", op);
+               return -EINVAL;
+       }
+
+       ret = iscsit_get_tpg(tpg);
+       if (ret < 0)
+               return -EINVAL;
+
+       if (op) {
+               ret = iscsit_tpg_enable_portal_group(tpg);
+               if (ret < 0)
+                       goto out;
+       } else {
+               /*
+                * iscsit_tpg_disable_portal_group() assumes force=1
+                */
+               ret = iscsit_tpg_disable_portal_group(tpg, 1);
+               if (ret < 0)
+                       goto out;
+       }
+
+       iscsit_put_tpg(tpg);
+       return count;
+out:
+       iscsit_put_tpg(tpg);
+       return -EINVAL;
+}
+
+TF_TPG_BASE_ATTR(lio_target, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *lio_target_tpg_attrs[] = {
+       &lio_target_tpg_enable.attr,
+       NULL,
+};
+
+/* End items for lio_target_tpg_cit */
+
+/* Start items for lio_target_tiqn_cit */
+
+struct se_portal_group *lio_target_tiqn_addtpg(
+       struct se_wwn *wwn,
+       struct config_group *group,
+       const char *name)
+{
+       struct iscsi_portal_group *tpg;
+       struct iscsi_tiqn *tiqn;
+       char *tpgt_str, *end_ptr;
+       int ret = 0;
+       unsigned short int tpgt;
+
+       tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);
+       /*
+        * Only tpgt_# directory groups can be created below
+        * target/iscsi/iqn.superturodiskarry/
+       */
+       tpgt_str = strstr(name, "tpgt_");
+       if (!tpgt_str) {
+               pr_err("Unable to locate \"tpgt_#\" directory"
+                               " group\n");
+               return NULL;
+       }
+       tpgt_str += 5; /* Skip ahead of "tpgt_" */
+       tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0);
+
+       tpg = iscsit_alloc_portal_group(tiqn, tpgt);
+       if (!tpg)
+               return NULL;
+
+       ret = core_tpg_register(
+                       &lio_target_fabric_configfs->tf_ops,
+                       wwn, &tpg->tpg_se_tpg, (void *)tpg,
+                       TRANSPORT_TPG_TYPE_NORMAL);
+       if (ret < 0)
+               return NULL;
+
+       ret = iscsit_tpg_add_portal_group(tiqn, tpg);
+       if (ret != 0)
+               goto out;
+
+       pr_debug("LIO_Target_ConfigFS: REGISTER -> %s\n", tiqn->tiqn);
+       pr_debug("LIO_Target_ConfigFS: REGISTER -> Allocated TPG: %s\n",
+                       name);
+       return &tpg->tpg_se_tpg;
+out:
+       core_tpg_deregister(&tpg->tpg_se_tpg);
+       kfree(tpg);
+       return NULL;
+}
+
+void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg)
+{
+       struct iscsi_portal_group *tpg;
+       struct iscsi_tiqn *tiqn;
+
+       tpg = container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg);
+       tiqn = tpg->tpg_tiqn;
+       /*
+        * iscsit_tpg_del_portal_group() assumes force=1
+        */
+       pr_debug("LIO_Target_ConfigFS: DEREGISTER -> Releasing TPG\n");
+       iscsit_tpg_del_portal_group(tiqn, tpg, 1);
+}
+
+/* End items for lio_target_tiqn_cit */
+
+/* Start LIO-Target TIQN struct contig_item lio_target_cit */
+
+static ssize_t lio_target_wwn_show_attr_lio_version(
+       struct target_fabric_configfs *tf,
+       char *page)
+{
+       return sprintf(page, "RisingTide Systems Linux-iSCSI Target "ISCSIT_VERSION"\n");
+}
+
+TF_WWN_ATTR_RO(lio_target, lio_version);
+
+static struct configfs_attribute *lio_target_wwn_attrs[] = {
+       &lio_target_wwn_lio_version.attr,
+       NULL,
+};
+
+struct se_wwn *lio_target_call_coreaddtiqn(
+       struct target_fabric_configfs *tf,
+       struct config_group *group,
+       const char *name)
+{
+       struct config_group *stats_cg;
+       struct iscsi_tiqn *tiqn;
+
+       tiqn = iscsit_add_tiqn((unsigned char *)name);
+       if (IS_ERR(tiqn))
+               return ERR_PTR(PTR_ERR(tiqn));
+       /*
+        * Setup struct iscsi_wwn_stat_grps for se_wwn->fabric_stat_group.
+        */
+       stats_cg = &tiqn->tiqn_wwn.fabric_stat_group;
+
+       stats_cg->default_groups = kzalloc(sizeof(struct config_group) * 6,
+                               GFP_KERNEL);
+       if (!stats_cg->default_groups) {
+               pr_err("Unable to allocate memory for"
+                               " stats_cg->default_groups\n");
+               iscsit_del_tiqn(tiqn);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       stats_cg->default_groups[0] = &WWN_STAT_GRPS(tiqn)->iscsi_instance_group;
+       stats_cg->default_groups[1] = &WWN_STAT_GRPS(tiqn)->iscsi_sess_err_group;
+       stats_cg->default_groups[2] = &WWN_STAT_GRPS(tiqn)->iscsi_tgt_attr_group;
+       stats_cg->default_groups[3] = &WWN_STAT_GRPS(tiqn)->iscsi_login_stats_group;
+       stats_cg->default_groups[4] = &WWN_STAT_GRPS(tiqn)->iscsi_logout_stats_group;
+       stats_cg->default_groups[5] = NULL;
+       config_group_init_type_name(&WWN_STAT_GRPS(tiqn)->iscsi_instance_group,
+                       "iscsi_instance", &iscsi_stat_instance_cit);
+       config_group_init_type_name(&WWN_STAT_GRPS(tiqn)->iscsi_sess_err_group,
+                       "iscsi_sess_err", &iscsi_stat_sess_err_cit);
+       config_group_init_type_name(&WWN_STAT_GRPS(tiqn)->iscsi_tgt_attr_group,
+                       "iscsi_tgt_attr", &iscsi_stat_tgt_attr_cit);
+       config_group_init_type_name(&WWN_STAT_GRPS(tiqn)->iscsi_login_stats_group,
+                       "iscsi_login_stats", &iscsi_stat_login_cit);
+       config_group_init_type_name(&WWN_STAT_GRPS(tiqn)->iscsi_logout_stats_group,
+                       "iscsi_logout_stats", &iscsi_stat_logout_cit);
+
+       pr_debug("LIO_Target_ConfigFS: REGISTER -> %s\n", tiqn->tiqn);
+       pr_debug("LIO_Target_ConfigFS: REGISTER -> Allocated Node:"
+                       " %s\n", name);
+       return &tiqn->tiqn_wwn;
+}
+
+void lio_target_call_coredeltiqn(
+       struct se_wwn *wwn)
+{
+       struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);
+       struct config_item *df_item;
+       struct config_group *stats_cg;
+       int i;
+
+       stats_cg = &tiqn->tiqn_wwn.fabric_stat_group;
+       for (i = 0; stats_cg->default_groups[i]; i++) {
+               df_item = &stats_cg->default_groups[i]->cg_item;
+               stats_cg->default_groups[i] = NULL;
+               config_item_put(df_item);
+       }
+       kfree(stats_cg->default_groups);
+
+       pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s\n",
+                       tiqn->tiqn);
+       iscsit_del_tiqn(tiqn);
+}
+
+/* End LIO-Target TIQN struct contig_lio_target_cit */
+
+/* Start lio_target_discovery_auth_cit */
+
+#define DEF_DISC_AUTH_STR(name, flags)                                 \
+       __DEF_NACL_AUTH_STR(disc, name, flags)                          \
+static ssize_t iscsi_disc_show_##name(                                 \
+       struct target_fabric_configfs *tf,                              \
+       char *page)                                                     \
+{                                                                      \
+       return __iscsi_disc_show_##name(&iscsit_global->discovery_acl,  \
+               page);                                                  \
+}                                                                      \
+static ssize_t iscsi_disc_store_##name(                                        \
+       struct target_fabric_configfs *tf,                              \
+       const char *page,                                               \
+       size_t count)                                                   \
+{                                                                      \
+       return __iscsi_disc_store_##name(&iscsit_global->discovery_acl, \
+               page, count);                                           \
+}
+
+#define DEF_DISC_AUTH_INT(name)                                                \
+       __DEF_NACL_AUTH_INT(disc, name)                                 \
+static ssize_t iscsi_disc_show_##name(                                 \
+       struct target_fabric_configfs *tf,                              \
+       char *page)                                                     \
+{                                                                      \
+       return __iscsi_disc_show_##name(&iscsit_global->discovery_acl,  \
+                       page);                                          \
+}
+
+#define DISC_AUTH_ATTR(_name, _mode) TF_DISC_ATTR(iscsi, _name, _mode)
+#define DISC_AUTH_ATTR_RO(_name) TF_DISC_ATTR_RO(iscsi, _name)
+
+/*
+ * One-way authentication userid
+ */
+DEF_DISC_AUTH_STR(userid, NAF_USERID_SET);
+DISC_AUTH_ATTR(userid, S_IRUGO | S_IWUSR);
+/*
+ * One-way authentication password
+ */
+DEF_DISC_AUTH_STR(password, NAF_PASSWORD_SET);
+DISC_AUTH_ATTR(password, S_IRUGO | S_IWUSR);
+/*
+ * Enforce mutual authentication
+ */
+DEF_DISC_AUTH_INT(authenticate_target);
+DISC_AUTH_ATTR_RO(authenticate_target);
+/*
+ * Mutual authentication userid
+ */
+DEF_DISC_AUTH_STR(userid_mutual, NAF_USERID_IN_SET);
+DISC_AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR);
+/*
+ * Mutual authentication password
+ */
+DEF_DISC_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET);
+DISC_AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR);
+
+/*
+ * enforce_discovery_auth
+ */
+static ssize_t iscsi_disc_show_enforce_discovery_auth(
+       struct target_fabric_configfs *tf,
+       char *page)
+{
+       struct iscsi_node_auth *discovery_auth = &iscsit_global->discovery_acl.node_auth;
+
+       return sprintf(page, "%d\n", discovery_auth->enforce_discovery_auth);
+}
+
+static ssize_t iscsi_disc_store_enforce_discovery_auth(
+       struct target_fabric_configfs *tf,
+       const char *page,
+       size_t count)
+{
+       struct iscsi_param *param;
+       struct iscsi_portal_group *discovery_tpg = iscsit_global->discovery_tpg;
+       char *endptr;
+       u32 op;
+
+       op = simple_strtoul(page, &endptr, 0);
+       if ((op != 1) && (op != 0)) {
+               pr_err("Illegal value for enforce_discovery_auth:"
+                               " %u\n", op);
+               return -EINVAL;
+       }
+
+       if (!discovery_tpg) {
+               pr_err("iscsit_global->discovery_tpg is NULL\n");
+               return -EINVAL;
+       }
+
+       param = iscsi_find_param_from_key(AUTHMETHOD,
+                               discovery_tpg->param_list);
+       if (!param)
+               return -EINVAL;
+
+       if (op) {
+               /*
+                * Reset the AuthMethod key to CHAP.
+                */
+               if (iscsi_update_param_value(param, CHAP) < 0)
+                       return -EINVAL;
+
+               discovery_tpg->tpg_attrib.authentication = 1;
+               iscsit_global->discovery_acl.node_auth.enforce_discovery_auth = 1;
+               pr_debug("LIO-CORE[0] Successfully enabled"
+                       " authentication enforcement for iSCSI"
+                       " Discovery TPG\n");
+       } else {
+               /*
+                * Reset the AuthMethod key to CHAP,None
+                */
+               if (iscsi_update_param_value(param, "CHAP,None") < 0)
+                       return -EINVAL;
+
+               discovery_tpg->tpg_attrib.authentication = 0;
+               iscsit_global->discovery_acl.node_auth.enforce_discovery_auth = 0;
+               pr_debug("LIO-CORE[0] Successfully disabled"
+                       " authentication enforcement for iSCSI"
+                       " Discovery TPG\n");
+       }
+
+       return count;
+}
+
+DISC_AUTH_ATTR(enforce_discovery_auth, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *lio_target_discovery_auth_attrs[] = {
+       &iscsi_disc_userid.attr,
+       &iscsi_disc_password.attr,
+       &iscsi_disc_authenticate_target.attr,
+       &iscsi_disc_userid_mutual.attr,
+       &iscsi_disc_password_mutual.attr,
+       &iscsi_disc_enforce_discovery_auth.attr,
+       NULL,
+};
+
+/* End lio_target_discovery_auth_cit */
+
+/* Start functions for target_core_fabric_ops */
+
+static char *iscsi_get_fabric_name(void)
+{
+       return "iSCSI";
+}
+
+static u32 iscsi_get_task_tag(struct se_cmd *se_cmd)
+{
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+       return cmd->init_task_tag;
+}
+
+static int iscsi_get_cmd_state(struct se_cmd *se_cmd)
+{
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+       return cmd->i_state;
+}
+
+static int iscsi_is_state_remove(struct se_cmd *se_cmd)
+{
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+       return (cmd->i_state == ISTATE_REMOVE);
+}
+
+static int lio_sess_logged_in(struct se_session *se_sess)
+{
+       struct iscsi_session *sess = se_sess->fabric_sess_ptr;
+       int ret;
+       /*
+        * Called with spin_lock_bh(&tpg_lock); and
+        * spin_lock(&se_tpg->session_lock); held.
+        */
+       spin_lock(&sess->conn_lock);
+       ret = (sess->session_state != TARG_SESS_STATE_LOGGED_IN);
+       spin_unlock(&sess->conn_lock);
+
+       return ret;
+}
+
+static u32 lio_sess_get_index(struct se_session *se_sess)
+{
+       struct iscsi_session *sess = se_sess->fabric_sess_ptr;
+
+       return sess->session_index;
+}
+
+static u32 lio_sess_get_initiator_sid(
+       struct se_session *se_sess,
+       unsigned char *buf,
+       u32 size)
+{
+       struct iscsi_session *sess = se_sess->fabric_sess_ptr;
+       /*
+        * iSCSI Initiator Session Identifier from RFC-3720.
+        */
+       return snprintf(buf, size, "%02x%02x%02x%02x%02x%02x",
+               sess->isid[0], sess->isid[1], sess->isid[2],
+               sess->isid[3], sess->isid[4], sess->isid[5]);
+}
+
+static int lio_queue_data_in(struct se_cmd *se_cmd)
+{
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+       cmd->i_state = ISTATE_SEND_DATAIN;
+       iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
+       return 0;
+}
+
+static int lio_write_pending(struct se_cmd *se_cmd)
+{
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+       if (!cmd->immediate_data && !cmd->unsolicited_data)
+               return iscsit_build_r2ts_for_cmd(cmd, cmd->conn, 1);
+
+       return 0;
+}
+
+static int lio_write_pending_status(struct se_cmd *se_cmd)
+{
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+       int ret;
+
+       spin_lock_bh(&cmd->istate_lock);
+       ret = !(cmd->cmd_flags & ICF_GOT_LAST_DATAOUT);
+       spin_unlock_bh(&cmd->istate_lock);
+
+       return ret;
+}
+
+static int lio_queue_status(struct se_cmd *se_cmd)
+{
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+       cmd->i_state = ISTATE_SEND_STATUS;
+       iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
+       return 0;
+}
+
+static u16 lio_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+       unsigned char *buffer = se_cmd->sense_buffer;
+       /*
+        * From RFC-3720 10.4.7.  Data Segment - Sense and Response Data Segment
+        * 16-bit SenseLength.
+        */
+       buffer[0] = ((sense_length >> 8) & 0xff);
+       buffer[1] = (sense_length & 0xff);
+       /*
+        * Return two byte offset into allocated sense_buffer.
+        */
+       return 2;
+}
+
+static u16 lio_get_fabric_sense_len(void)
+{
+       /*
+        * Return two byte offset into allocated sense_buffer.
+        */
+       return 2;
+}
+
+static int lio_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+       cmd->i_state = ISTATE_SEND_TASKMGTRSP;
+       iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
+       return 0;
+}
+
+static char *lio_tpg_get_endpoint_wwn(struct se_portal_group *se_tpg)
+{
+       struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
+
+       return &tpg->tpg_tiqn->tiqn[0];
+}
+
+static u16 lio_tpg_get_tag(struct se_portal_group *se_tpg)
+{
+       struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
+
+       return tpg->tpgt;
+}
+
+static u32 lio_tpg_get_default_depth(struct se_portal_group *se_tpg)
+{
+       struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
+
+       return ISCSI_TPG_ATTRIB(tpg)->default_cmdsn_depth;
+}
+
+static int lio_tpg_check_demo_mode(struct se_portal_group *se_tpg)
+{
+       struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
+
+       return ISCSI_TPG_ATTRIB(tpg)->generate_node_acls;
+}
+
+static int lio_tpg_check_demo_mode_cache(struct se_portal_group *se_tpg)
+{
+       struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
+
+       return ISCSI_TPG_ATTRIB(tpg)->cache_dynamic_acls;
+}
+
+static int lio_tpg_check_demo_mode_write_protect(
+       struct se_portal_group *se_tpg)
+{
+       struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
+
+       return ISCSI_TPG_ATTRIB(tpg)->demo_mode_write_protect;
+}
+
+static int lio_tpg_check_prod_mode_write_protect(
+       struct se_portal_group *se_tpg)
+{
+       struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
+
+       return ISCSI_TPG_ATTRIB(tpg)->prod_mode_write_protect;
+}
+
+static void lio_tpg_release_fabric_acl(
+       struct se_portal_group *se_tpg,
+       struct se_node_acl *se_acl)
+{
+       struct iscsi_node_acl *acl = container_of(se_acl,
+                               struct iscsi_node_acl, se_node_acl);
+       kfree(acl);
+}
+
+/*
+ * Called with spin_lock_bh(struct se_portal_group->session_lock) held..
+ *
+ * Also, this function calls iscsit_inc_session_usage_count() on the
+ * struct iscsi_session in question.
+ */
+static int lio_tpg_shutdown_session(struct se_session *se_sess)
+{
+       struct iscsi_session *sess = se_sess->fabric_sess_ptr;
+
+       spin_lock(&sess->conn_lock);
+       if (atomic_read(&sess->session_fall_back_to_erl0) ||
+           atomic_read(&sess->session_logout) ||
+           (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
+               spin_unlock(&sess->conn_lock);
+               return 0;
+       }
+       atomic_set(&sess->session_reinstatement, 1);
+       spin_unlock(&sess->conn_lock);
+
+       iscsit_inc_session_usage_count(sess);
+       iscsit_stop_time2retain_timer(sess);
+
+       return 1;
+}
+
+/*
+ * Calls iscsit_dec_session_usage_count() as inverse of
+ * lio_tpg_shutdown_session()
+ */
+static void lio_tpg_close_session(struct se_session *se_sess)
+{
+       struct iscsi_session *sess = se_sess->fabric_sess_ptr;
+       /*
+        * If the iSCSI Session for the iSCSI Initiator Node exists,
+        * forcefully shutdown the iSCSI NEXUS.
+        */
+       iscsit_stop_session(sess, 1, 1);
+       iscsit_dec_session_usage_count(sess);
+       iscsit_close_session(sess);
+}
+
+static void lio_tpg_stop_session(
+       struct se_session *se_sess,
+       int sess_sleep,
+       int conn_sleep)
+{
+       struct iscsi_session *sess = se_sess->fabric_sess_ptr;
+
+       iscsit_stop_session(sess, sess_sleep, conn_sleep);
+}
+
+static void lio_tpg_fall_back_to_erl0(struct se_session *se_sess)
+{
+       struct iscsi_session *sess = se_sess->fabric_sess_ptr;
+
+       iscsit_fall_back_to_erl0(sess);
+}
+
+static u32 lio_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+       struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
+
+       return tpg->tpg_tiqn->tiqn_index;
+}
+
+static void lio_set_default_node_attributes(struct se_node_acl *se_acl)
+{
+       struct iscsi_node_acl *acl = container_of(se_acl, struct iscsi_node_acl,
+                               se_node_acl);
+
+       ISCSI_NODE_ATTRIB(acl)->nacl = acl;
+       iscsit_set_default_node_attribues(acl);
+}
+
+static void lio_release_cmd(struct se_cmd *se_cmd)
+{
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+       iscsit_release_cmd(cmd);
+}
+
+/* End functions for target_core_fabric_ops */
+
+int iscsi_target_register_configfs(void)
+{
+       struct target_fabric_configfs *fabric;
+       int ret;
+
+       lio_target_fabric_configfs = NULL;
+       fabric = target_fabric_configfs_init(THIS_MODULE, "iscsi");
+       if (IS_ERR(fabric)) {
+               pr_err("target_fabric_configfs_init() for"
+                               " LIO-Target failed!\n");
+               return PTR_ERR(fabric);
+       }
+       /*
+        * Setup the fabric API of function pointers used by target_core_mod..
+        */
+       fabric->tf_ops.get_fabric_name = &iscsi_get_fabric_name;
+       fabric->tf_ops.get_fabric_proto_ident = &iscsi_get_fabric_proto_ident;
+       fabric->tf_ops.tpg_get_wwn = &lio_tpg_get_endpoint_wwn;
+       fabric->tf_ops.tpg_get_tag = &lio_tpg_get_tag;
+       fabric->tf_ops.tpg_get_default_depth = &lio_tpg_get_default_depth;
+       fabric->tf_ops.tpg_get_pr_transport_id = &iscsi_get_pr_transport_id;
+       fabric->tf_ops.tpg_get_pr_transport_id_len =
+                               &iscsi_get_pr_transport_id_len;
+       fabric->tf_ops.tpg_parse_pr_out_transport_id =
+                               &iscsi_parse_pr_out_transport_id;
+       fabric->tf_ops.tpg_check_demo_mode = &lio_tpg_check_demo_mode;
+       fabric->tf_ops.tpg_check_demo_mode_cache =
+                               &lio_tpg_check_demo_mode_cache;
+       fabric->tf_ops.tpg_check_demo_mode_write_protect =
+                               &lio_tpg_check_demo_mode_write_protect;
+       fabric->tf_ops.tpg_check_prod_mode_write_protect =
+                               &lio_tpg_check_prod_mode_write_protect;
+       fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl;
+       fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl;
+       fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index;
+       fabric->tf_ops.release_cmd = &lio_release_cmd;
+       fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session;
+       fabric->tf_ops.close_session = &lio_tpg_close_session;
+       fabric->tf_ops.stop_session = &lio_tpg_stop_session;
+       fabric->tf_ops.fall_back_to_erl0 = &lio_tpg_fall_back_to_erl0;
+       fabric->tf_ops.sess_logged_in = &lio_sess_logged_in;
+       fabric->tf_ops.sess_get_index = &lio_sess_get_index;
+       fabric->tf_ops.sess_get_initiator_sid = &lio_sess_get_initiator_sid;
+       fabric->tf_ops.write_pending = &lio_write_pending;
+       fabric->tf_ops.write_pending_status = &lio_write_pending_status;
+       fabric->tf_ops.set_default_node_attributes =
+                               &lio_set_default_node_attributes;
+       fabric->tf_ops.get_task_tag = &iscsi_get_task_tag;
+       fabric->tf_ops.get_cmd_state = &iscsi_get_cmd_state;
+       fabric->tf_ops.queue_data_in = &lio_queue_data_in;
+       fabric->tf_ops.queue_status = &lio_queue_status;
+       fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp;
+       fabric->tf_ops.set_fabric_sense_len = &lio_set_fabric_sense_len;
+       fabric->tf_ops.get_fabric_sense_len = &lio_get_fabric_sense_len;
+       fabric->tf_ops.is_state_remove = &iscsi_is_state_remove;
+       /*
+        * Setup function pointers for generic logic in target_core_fabric_configfs.c
+        */
+       fabric->tf_ops.fabric_make_wwn = &lio_target_call_coreaddtiqn;
+       fabric->tf_ops.fabric_drop_wwn = &lio_target_call_coredeltiqn;
+       fabric->tf_ops.fabric_make_tpg = &lio_target_tiqn_addtpg;
+       fabric->tf_ops.fabric_drop_tpg = &lio_target_tiqn_deltpg;
+       fabric->tf_ops.fabric_post_link = NULL;
+       fabric->tf_ops.fabric_pre_unlink = NULL;
+       fabric->tf_ops.fabric_make_np = &lio_target_call_addnptotpg;
+       fabric->tf_ops.fabric_drop_np = &lio_target_call_delnpfromtpg;
+       fabric->tf_ops.fabric_make_nodeacl = &lio_target_make_nodeacl;
+       fabric->tf_ops.fabric_drop_nodeacl = &lio_target_drop_nodeacl;
+       /*
+        * Setup default attribute lists for various fabric->tf_cit_tmpl
+        * sturct config_item_type's
+        */
+       TF_CIT_TMPL(fabric)->tfc_discovery_cit.ct_attrs = lio_target_discovery_auth_attrs;
+       TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = lio_target_wwn_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = lio_target_tpg_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = lio_target_tpg_attrib_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = lio_target_tpg_param_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = lio_target_portal_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = lio_target_initiator_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = lio_target_nacl_attrib_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = lio_target_nacl_auth_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = lio_target_nacl_param_attrs;
+
+       ret = target_fabric_configfs_register(fabric);
+       if (ret < 0) {
+               pr_err("target_fabric_configfs_register() for"
+                               " LIO-Target failed!\n");
+               target_fabric_configfs_free(fabric);
+               return ret;
+       }
+
+       lio_target_fabric_configfs = fabric;
+       pr_debug("LIO_TARGET[0] - Set fabric ->"
+                       " lio_target_fabric_configfs\n");
+       return 0;
+}
+
+
+void iscsi_target_deregister_configfs(void)
+{
+       if (!lio_target_fabric_configfs)
+               return;
+       /*
+        * Shutdown discovery sessions and disable discovery TPG
+        */
+       if (iscsit_global->discovery_tpg)
+               iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
+
+       target_fabric_configfs_deregister(lio_target_fabric_configfs);
+       lio_target_fabric_configfs = NULL;
+       pr_debug("LIO_TARGET[0] - Cleared"
+                               " lio_target_fabric_configfs\n");
+}
diff --git a/drivers/target/iscsi/iscsi_target_configfs.h b/drivers/target/iscsi/iscsi_target_configfs.h
new file mode 100644 (file)
index 0000000..8cd5a63
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef ISCSI_TARGET_CONFIGFS_H
+#define ISCSI_TARGET_CONFIGFS_H
+
+extern int iscsi_target_register_configfs(void);
+extern void iscsi_target_deregister_configfs(void);
+
+#endif /* ISCSI_TARGET_CONFIGFS_H */
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
new file mode 100644 (file)
index 0000000..470ed55
--- /dev/null
@@ -0,0 +1,859 @@
+#ifndef ISCSI_TARGET_CORE_H
+#define ISCSI_TARGET_CORE_H
+
+#include <linux/in.h>
+#include <linux/configfs.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/iscsi_proto.h>
+#include <target/target_core_base.h>
+
+#define ISCSIT_VERSION                 "v4.1.0-rc1"
+#define ISCSI_MAX_DATASN_MISSING_COUNT 16
+#define ISCSI_TX_THREAD_TCP_TIMEOUT    2
+#define ISCSI_RX_THREAD_TCP_TIMEOUT    2
+#define SECONDS_FOR_ASYNC_LOGOUT       10
+#define SECONDS_FOR_ASYNC_TEXT         10
+#define SECONDS_FOR_LOGOUT_COMP                15
+#define WHITE_SPACE                    " \t\v\f\n\r"
+
+/* struct iscsi_node_attrib sanity values */
+#define NA_DATAOUT_TIMEOUT             3
+#define NA_DATAOUT_TIMEOUT_MAX         60
+#define NA_DATAOUT_TIMEOUT_MIX         2
+#define NA_DATAOUT_TIMEOUT_RETRIES     5
+#define NA_DATAOUT_TIMEOUT_RETRIES_MAX 15
+#define NA_DATAOUT_TIMEOUT_RETRIES_MIN 1
+#define NA_NOPIN_TIMEOUT               5
+#define NA_NOPIN_TIMEOUT_MAX           60
+#define NA_NOPIN_TIMEOUT_MIN           3
+#define NA_NOPIN_RESPONSE_TIMEOUT      5
+#define NA_NOPIN_RESPONSE_TIMEOUT_MAX  60
+#define NA_NOPIN_RESPONSE_TIMEOUT_MIN  3
+#define NA_RANDOM_DATAIN_PDU_OFFSETS   0
+#define NA_RANDOM_DATAIN_SEQ_OFFSETS   0
+#define NA_RANDOM_R2T_OFFSETS          0
+#define NA_DEFAULT_ERL                 0
+#define NA_DEFAULT_ERL_MAX             2
+#define NA_DEFAULT_ERL_MIN             0
+
+/* struct iscsi_tpg_attrib sanity values */
+#define TA_AUTHENTICATION              1
+#define TA_LOGIN_TIMEOUT               15
+#define TA_LOGIN_TIMEOUT_MAX           30
+#define TA_LOGIN_TIMEOUT_MIN           5
+#define TA_NETIF_TIMEOUT               2
+#define TA_NETIF_TIMEOUT_MAX           15
+#define TA_NETIF_TIMEOUT_MIN           2
+#define TA_GENERATE_NODE_ACLS          0
+#define TA_DEFAULT_CMDSN_DEPTH         16
+#define TA_DEFAULT_CMDSN_DEPTH_MAX     512
+#define TA_DEFAULT_CMDSN_DEPTH_MIN     1
+#define TA_CACHE_DYNAMIC_ACLS          0
+/* Enabled by default in demo mode (generic_node_acls=1) */
+#define TA_DEMO_MODE_WRITE_PROTECT     1
+/* Disabled by default in production mode w/ explict ACLs */
+#define TA_PROD_MODE_WRITE_PROTECT     0
+#define TA_CACHE_CORE_NPS              0
+
+enum tpg_np_network_transport_table {
+       ISCSI_TCP                               = 0,
+       ISCSI_SCTP_TCP                          = 1,
+       ISCSI_SCTP_UDP                          = 2,
+       ISCSI_IWARP_TCP                         = 3,
+       ISCSI_IWARP_SCTP                        = 4,
+       ISCSI_INFINIBAND                        = 5,
+};
+
+/* RFC-3720 7.1.4  Standard Connection State Diagram for a Target */
+enum target_conn_state_table {
+       TARG_CONN_STATE_FREE                    = 0x1,
+       TARG_CONN_STATE_XPT_UP                  = 0x3,
+       TARG_CONN_STATE_IN_LOGIN                = 0x4,
+       TARG_CONN_STATE_LOGGED_IN               = 0x5,
+       TARG_CONN_STATE_IN_LOGOUT               = 0x6,
+       TARG_CONN_STATE_LOGOUT_REQUESTED        = 0x7,
+       TARG_CONN_STATE_CLEANUP_WAIT            = 0x8,
+};
+
+/* RFC-3720 7.3.2  Session State Diagram for a Target */
+enum target_sess_state_table {
+       TARG_SESS_STATE_FREE                    = 0x1,
+       TARG_SESS_STATE_ACTIVE                  = 0x2,
+       TARG_SESS_STATE_LOGGED_IN               = 0x3,
+       TARG_SESS_STATE_FAILED                  = 0x4,
+       TARG_SESS_STATE_IN_CONTINUE             = 0x5,
+};
+
+/* struct iscsi_data_count->type */
+enum data_count_type {
+       ISCSI_RX_DATA   = 1,
+       ISCSI_TX_DATA   = 2,
+};
+
+/* struct iscsi_datain_req->dr_complete */
+enum datain_req_comp_table {
+       DATAIN_COMPLETE_NORMAL                  = 1,
+       DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY = 2,
+       DATAIN_COMPLETE_CONNECTION_RECOVERY     = 3,
+};
+
+/* struct iscsi_datain_req->recovery */
+enum datain_req_rec_table {
+       DATAIN_WITHIN_COMMAND_RECOVERY          = 1,
+       DATAIN_CONNECTION_RECOVERY              = 2,
+};
+
+/* struct iscsi_portal_group->state */
+enum tpg_state_table {
+       TPG_STATE_FREE                          = 0,
+       TPG_STATE_ACTIVE                        = 1,
+       TPG_STATE_INACTIVE                      = 2,
+       TPG_STATE_COLD_RESET                    = 3,
+};
+
+/* struct iscsi_tiqn->tiqn_state */
+enum tiqn_state_table {
+       TIQN_STATE_ACTIVE                       = 1,
+       TIQN_STATE_SHUTDOWN                     = 2,
+};
+
+/* struct iscsi_cmd->cmd_flags */
+enum cmd_flags_table {
+       ICF_GOT_LAST_DATAOUT                    = 0x00000001,
+       ICF_GOT_DATACK_SNACK                    = 0x00000002,
+       ICF_NON_IMMEDIATE_UNSOLICITED_DATA      = 0x00000004,
+       ICF_SENT_LAST_R2T                       = 0x00000008,
+       ICF_WITHIN_COMMAND_RECOVERY             = 0x00000010,
+       ICF_CONTIG_MEMORY                       = 0x00000020,
+       ICF_ATTACHED_TO_RQUEUE                  = 0x00000040,
+       ICF_OOO_CMDSN                           = 0x00000080,
+       ICF_REJECT_FAIL_CONN                    = 0x00000100,
+};
+
+/* struct iscsi_cmd->i_state */
+enum cmd_i_state_table {
+       ISTATE_NO_STATE                 = 0,
+       ISTATE_NEW_CMD                  = 1,
+       ISTATE_DEFERRED_CMD             = 2,
+       ISTATE_UNSOLICITED_DATA         = 3,
+       ISTATE_RECEIVE_DATAOUT          = 4,
+       ISTATE_RECEIVE_DATAOUT_RECOVERY = 5,
+       ISTATE_RECEIVED_LAST_DATAOUT    = 6,
+       ISTATE_WITHIN_DATAOUT_RECOVERY  = 7,
+       ISTATE_IN_CONNECTION_RECOVERY   = 8,
+       ISTATE_RECEIVED_TASKMGT         = 9,
+       ISTATE_SEND_ASYNCMSG            = 10,
+       ISTATE_SENT_ASYNCMSG            = 11,
+       ISTATE_SEND_DATAIN              = 12,
+       ISTATE_SEND_LAST_DATAIN         = 13,
+       ISTATE_SENT_LAST_DATAIN         = 14,
+       ISTATE_SEND_LOGOUTRSP           = 15,
+       ISTATE_SENT_LOGOUTRSP           = 16,
+       ISTATE_SEND_NOPIN               = 17,
+       ISTATE_SENT_NOPIN               = 18,
+       ISTATE_SEND_REJECT              = 19,
+       ISTATE_SENT_REJECT              = 20,
+       ISTATE_SEND_R2T                 = 21,
+       ISTATE_SENT_R2T                 = 22,
+       ISTATE_SEND_R2T_RECOVERY        = 23,
+       ISTATE_SENT_R2T_RECOVERY        = 24,
+       ISTATE_SEND_LAST_R2T            = 25,
+       ISTATE_SENT_LAST_R2T            = 26,
+       ISTATE_SEND_LAST_R2T_RECOVERY   = 27,
+       ISTATE_SENT_LAST_R2T_RECOVERY   = 28,
+       ISTATE_SEND_STATUS              = 29,
+       ISTATE_SEND_STATUS_BROKEN_PC    = 30,
+       ISTATE_SENT_STATUS              = 31,
+       ISTATE_SEND_STATUS_RECOVERY     = 32,
+       ISTATE_SENT_STATUS_RECOVERY     = 33,
+       ISTATE_SEND_TASKMGTRSP          = 34,
+       ISTATE_SENT_TASKMGTRSP          = 35,
+       ISTATE_SEND_TEXTRSP             = 36,
+       ISTATE_SENT_TEXTRSP             = 37,
+       ISTATE_SEND_NOPIN_WANT_RESPONSE = 38,
+       ISTATE_SENT_NOPIN_WANT_RESPONSE = 39,
+       ISTATE_SEND_NOPIN_NO_RESPONSE   = 40,
+       ISTATE_REMOVE                   = 41,
+       ISTATE_FREE                     = 42,
+};
+
+/* Used for iscsi_recover_cmdsn() return values */
+enum recover_cmdsn_ret_table {
+       CMDSN_ERROR_CANNOT_RECOVER      = -1,
+       CMDSN_NORMAL_OPERATION          = 0,
+       CMDSN_LOWER_THAN_EXP            = 1,
+       CMDSN_HIGHER_THAN_EXP           = 2,
+};
+
+/* Used for iscsi_handle_immediate_data() return values */
+enum immedate_data_ret_table {
+       IMMEDIATE_DATA_CANNOT_RECOVER   = -1,
+       IMMEDIATE_DATA_NORMAL_OPERATION = 0,
+       IMMEDIATE_DATA_ERL1_CRC_FAILURE = 1,
+};
+
+/* Used for iscsi_decide_dataout_action() return values */
+enum dataout_action_ret_table {
+       DATAOUT_CANNOT_RECOVER          = -1,
+       DATAOUT_NORMAL                  = 0,
+       DATAOUT_SEND_R2T                = 1,
+       DATAOUT_SEND_TO_TRANSPORT       = 2,
+       DATAOUT_WITHIN_COMMAND_RECOVERY = 3,
+};
+
+/* Used for struct iscsi_node_auth->naf_flags */
+enum naf_flags_table {
+       NAF_USERID_SET                  = 0x01,
+       NAF_PASSWORD_SET                = 0x02,
+       NAF_USERID_IN_SET               = 0x04,
+       NAF_PASSWORD_IN_SET             = 0x08,
+};
+
+/* Used by various struct timer_list to manage iSCSI specific state */
+enum iscsi_timer_flags_table {
+       ISCSI_TF_RUNNING                = 0x01,
+       ISCSI_TF_STOP                   = 0x02,
+       ISCSI_TF_EXPIRED                = 0x04,
+};
+
+/* Used for struct iscsi_np->np_flags */
+enum np_flags_table {
+       NPF_IP_NETWORK          = 0x00,
+       NPF_SCTP_STRUCT_FILE    = 0x01 /* Bugfix */
+};
+
+/* Used for struct iscsi_np->np_thread_state */
+enum np_thread_state_table {
+       ISCSI_NP_THREAD_ACTIVE          = 1,
+       ISCSI_NP_THREAD_INACTIVE        = 2,
+       ISCSI_NP_THREAD_RESET           = 3,
+       ISCSI_NP_THREAD_SHUTDOWN        = 4,
+       ISCSI_NP_THREAD_EXIT            = 5,
+};
+
+struct iscsi_conn_ops {
+       u8      HeaderDigest;                   /* [0,1] == [None,CRC32C] */
+       u8      DataDigest;                     /* [0,1] == [None,CRC32C] */
+       u32     MaxRecvDataSegmentLength;       /* [512..2**24-1] */
+       u8      OFMarker;                       /* [0,1] == [No,Yes] */
+       u8      IFMarker;                       /* [0,1] == [No,Yes] */
+       u32     OFMarkInt;                      /* [1..65535] */
+       u32     IFMarkInt;                      /* [1..65535] */
+};
+
+struct iscsi_sess_ops {
+       char    InitiatorName[224];
+       char    InitiatorAlias[256];
+       char    TargetName[224];
+       char    TargetAlias[256];
+       char    TargetAddress[256];
+       u16     TargetPortalGroupTag;           /* [0..65535] */
+       u16     MaxConnections;                 /* [1..65535] */
+       u8      InitialR2T;                     /* [0,1] == [No,Yes] */
+       u8      ImmediateData;                  /* [0,1] == [No,Yes] */
+       u32     MaxBurstLength;                 /* [512..2**24-1] */
+       u32     FirstBurstLength;               /* [512..2**24-1] */
+       u16     DefaultTime2Wait;               /* [0..3600] */
+       u16     DefaultTime2Retain;             /* [0..3600] */
+       u16     MaxOutstandingR2T;              /* [1..65535] */
+       u8      DataPDUInOrder;                 /* [0,1] == [No,Yes] */
+       u8      DataSequenceInOrder;            /* [0,1] == [No,Yes] */
+       u8      ErrorRecoveryLevel;             /* [0..2] */
+       u8      SessionType;                    /* [0,1] == [Normal,Discovery]*/
+};
+
+struct iscsi_queue_req {
+       int                     state;
+       struct iscsi_cmd        *cmd;
+       struct list_head        qr_list;
+};
+
+struct iscsi_data_count {
+       int                     data_length;
+       int                     sync_and_steering;
+       enum data_count_type    type;
+       u32                     iov_count;
+       u32                     ss_iov_count;
+       u32                     ss_marker_count;
+       struct kvec             *iov;
+};
+
+struct iscsi_param_list {
+       struct list_head        param_list;
+       struct list_head        extra_response_list;
+};
+
+struct iscsi_datain_req {
+       enum datain_req_comp_table dr_complete;
+       int                     generate_recovery_values;
+       enum datain_req_rec_table recovery;
+       u32                     begrun;
+       u32                     runlength;
+       u32                     data_length;
+       u32                     data_offset;
+       u32                     data_offset_end;
+       u32                     data_sn;
+       u32                     next_burst_len;
+       u32                     read_data_done;
+       u32                     seq_send_order;
+       struct list_head        dr_list;
+} ____cacheline_aligned;
+
+struct iscsi_ooo_cmdsn {
+       u16                     cid;
+       u32                     batch_count;
+       u32                     cmdsn;
+       u32                     exp_cmdsn;
+       struct iscsi_cmd        *cmd;
+       struct list_head        ooo_list;
+} ____cacheline_aligned;
+
+struct iscsi_datain {
+       u8                      flags;
+       u32                     data_sn;
+       u32                     length;
+       u32                     offset;
+} ____cacheline_aligned;
+
+struct iscsi_r2t {
+       int                     seq_complete;
+       int                     recovery_r2t;
+       int                     sent_r2t;
+       u32                     r2t_sn;
+       u32                     offset;
+       u32                     targ_xfer_tag;
+       u32                     xfer_len;
+       struct list_head        r2t_list;
+} ____cacheline_aligned;
+
+struct iscsi_cmd {
+       enum iscsi_timer_flags_table dataout_timer_flags;
+       /* DataOUT timeout retries */
+       u8                      dataout_timeout_retries;
+       /* Within command recovery count */
+       u8                      error_recovery_count;
+       /* iSCSI dependent state for out or order CmdSNs */
+       enum cmd_i_state_table  deferred_i_state;
+       /* iSCSI dependent state */
+       enum cmd_i_state_table  i_state;
+       /* Command is an immediate command (ISCSI_OP_IMMEDIATE set) */
+       u8                      immediate_cmd;
+       /* Immediate data present */
+       u8                      immediate_data;
+       /* iSCSI Opcode */
+       u8                      iscsi_opcode;
+       /* iSCSI Response Code */
+       u8                      iscsi_response;
+       /* Logout reason when iscsi_opcode == ISCSI_INIT_LOGOUT_CMND */
+       u8                      logout_reason;
+       /* Logout response code when iscsi_opcode == ISCSI_INIT_LOGOUT_CMND */
+       u8                      logout_response;
+       /* MaxCmdSN has been incremented */
+       u8                      maxcmdsn_inc;
+       /* Immediate Unsolicited Dataout */
+       u8                      unsolicited_data;
+       /* CID contained in logout PDU when opcode == ISCSI_INIT_LOGOUT_CMND */
+       u16                     logout_cid;
+       /* Command flags */
+       enum cmd_flags_table    cmd_flags;
+       /* Initiator Task Tag assigned from Initiator */
+       u32                     init_task_tag;
+       /* Target Transfer Tag assigned from Target */
+       u32                     targ_xfer_tag;
+       /* CmdSN assigned from Initiator */
+       u32                     cmd_sn;
+       /* ExpStatSN assigned from Initiator */
+       u32                     exp_stat_sn;
+       /* StatSN assigned to this ITT */
+       u32                     stat_sn;
+       /* DataSN Counter */
+       u32                     data_sn;
+       /* R2TSN Counter */
+       u32                     r2t_sn;
+       /* Last DataSN acknowledged via DataAck SNACK */
+       u32                     acked_data_sn;
+       /* Used for echoing NOPOUT ping data */
+       u32                     buf_ptr_size;
+       /* Used to store DataDigest */
+       u32                     data_crc;
+       /* Total size in bytes associated with command */
+       u32                     data_length;
+       /* Counter for MaxOutstandingR2T */
+       u32                     outstanding_r2ts;
+       /* Next R2T Offset when DataSequenceInOrder=Yes */
+       u32                     r2t_offset;
+       /* Iovec current and orig count for iscsi_cmd->iov_data */
+       u32                     iov_data_count;
+       u32                     orig_iov_data_count;
+       /* Number of miscellaneous iovecs used for IP stack calls */
+       u32                     iov_misc_count;
+       /* Number of struct iscsi_pdu in struct iscsi_cmd->pdu_list */
+       u32                     pdu_count;
+       /* Next struct iscsi_pdu to send in struct iscsi_cmd->pdu_list */
+       u32                     pdu_send_order;
+       /* Current struct iscsi_pdu in struct iscsi_cmd->pdu_list */
+       u32                     pdu_start;
+       u32                     residual_count;
+       /* Next struct iscsi_seq to send in struct iscsi_cmd->seq_list */
+       u32                     seq_send_order;
+       /* Number of struct iscsi_seq in struct iscsi_cmd->seq_list */
+       u32                     seq_count;
+       /* Current struct iscsi_seq in struct iscsi_cmd->seq_list */
+       u32                     seq_no;
+       /* Lowest offset in current DataOUT sequence */
+       u32                     seq_start_offset;
+       /* Highest offset in current DataOUT sequence */
+       u32                     seq_end_offset;
+       /* Total size in bytes received so far of READ data */
+       u32                     read_data_done;
+       /* Total size in bytes received so far of WRITE data */
+       u32                     write_data_done;
+       /* Counter for FirstBurstLength key */
+       u32                     first_burst_len;
+       /* Counter for MaxBurstLength key */
+       u32                     next_burst_len;
+       /* Transfer size used for IP stack calls */
+       u32                     tx_size;
+       /* Buffer used for various purposes */
+       void                    *buf_ptr;
+       /* See include/linux/dma-mapping.h */
+       enum dma_data_direction data_direction;
+       /* iSCSI PDU Header + CRC */
+       unsigned char           pdu[ISCSI_HDR_LEN + ISCSI_CRC_LEN];
+       /* Number of times struct iscsi_cmd is present in immediate queue */
+       atomic_t                immed_queue_count;
+       atomic_t                response_queue_count;
+       atomic_t                transport_sent;
+       spinlock_t              datain_lock;
+       spinlock_t              dataout_timeout_lock;
+       /* spinlock for protecting struct iscsi_cmd->i_state */
+       spinlock_t              istate_lock;
+       /* spinlock for adding within command recovery entries */
+       spinlock_t              error_lock;
+       /* spinlock for adding R2Ts */
+       spinlock_t              r2t_lock;
+       /* DataIN List */
+       struct list_head        datain_list;
+       /* R2T List */
+       struct list_head        cmd_r2t_list;
+       struct completion       reject_comp;
+       /* Timer for DataOUT */
+       struct timer_list       dataout_timer;
+       /* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */
+       struct kvec             *iov_data;
+       /* Iovecs for miscellaneous purposes */
+#define ISCSI_MISC_IOVECS                      5
+       struct kvec             iov_misc[ISCSI_MISC_IOVECS];
+       /* Array of struct iscsi_pdu used for DataPDUInOrder=No */
+       struct iscsi_pdu        *pdu_list;
+       /* Current struct iscsi_pdu used for DataPDUInOrder=No */
+       struct iscsi_pdu        *pdu_ptr;
+       /* Array of struct iscsi_seq used for DataSequenceInOrder=No */
+       struct iscsi_seq        *seq_list;
+       /* Current struct iscsi_seq used for DataSequenceInOrder=No */
+       struct iscsi_seq        *seq_ptr;
+       /* TMR Request when iscsi_opcode == ISCSI_OP_SCSI_TMFUNC */
+       struct iscsi_tmr_req    *tmr_req;
+       /* Connection this command is alligient to */
+       struct iscsi_conn       *conn;
+       /* Pointer to connection recovery entry */
+       struct iscsi_conn_recovery *cr;
+       /* Session the command is part of,  used for connection recovery */
+       struct iscsi_session    *sess;
+       /* list_head for connection list */
+       struct list_head        i_list;
+       /* The TCM I/O descriptor that is accessed via container_of() */
+       struct se_cmd           se_cmd;
+       /* Sense buffer that will be mapped into outgoing status */
+#define ISCSI_SENSE_BUFFER_LEN          (TRANSPORT_SENSE_BUFFER + 2)
+       unsigned char           sense_buffer[ISCSI_SENSE_BUFFER_LEN];
+
+       struct scatterlist      *t_mem_sg;
+       u32                     t_mem_sg_nents;
+
+       u32                     padding;
+       u8                      pad_bytes[4];
+
+       struct scatterlist      *first_data_sg;
+       u32                     first_data_sg_off;
+       u32                     kmapped_nents;
+
+}  ____cacheline_aligned;
+
+struct iscsi_tmr_req {
+       bool                    task_reassign:1;
+       u32                     ref_cmd_sn;
+       u32                     exp_data_sn;
+       struct iscsi_conn_recovery *conn_recovery;
+       struct se_tmr_req       *se_tmr_req;
+};
+
+struct iscsi_conn {
+       /* Authentication Successful for this connection */
+       u8                      auth_complete;
+       /* State connection is currently in */
+       u8                      conn_state;
+       u8                      conn_logout_reason;
+       u8                      network_transport;
+       enum iscsi_timer_flags_table nopin_timer_flags;
+       enum iscsi_timer_flags_table nopin_response_timer_flags;
+       u8                      tx_immediate_queue;
+       u8                      tx_response_queue;
+       /* Used to know what thread encountered a transport failure */
+       u8                      which_thread;
+       /* connection id assigned by the Initiator */
+       u16                     cid;
+       /* Remote TCP Port */
+       u16                     login_port;
+       int                     net_size;
+       u32                     auth_id;
+#define CONNFLAG_SCTP_STRUCT_FILE                      0x01
+       u32                     conn_flags;
+       /* Used for iscsi_tx_login_rsp() */
+       u32                     login_itt;
+       u32                     exp_statsn;
+       /* Per connection status sequence number */
+       u32                     stat_sn;
+       /* IFMarkInt's Current Value */
+       u32                     if_marker;
+       /* OFMarkInt's Current Value */
+       u32                     of_marker;
+       /* Used for calculating OFMarker offset to next PDU */
+       u32                     of_marker_offset;
+       /* Complete Bad PDU for sending reject */
+       unsigned char           bad_hdr[ISCSI_HDR_LEN];
+#define IPV6_ADDRESS_SPACE                             48
+       unsigned char           login_ip[IPV6_ADDRESS_SPACE];
+       int                     conn_usage_count;
+       int                     conn_waiting_on_uc;
+       atomic_t                check_immediate_queue;
+       atomic_t                conn_logout_remove;
+       atomic_t                connection_exit;
+       atomic_t                connection_recovery;
+       atomic_t                connection_reinstatement;
+       atomic_t                connection_wait;
+       atomic_t                connection_wait_rcfr;
+       atomic_t                sleep_on_conn_wait_comp;
+       atomic_t                transport_failed;
+       struct completion       conn_post_wait_comp;
+       struct completion       conn_wait_comp;
+       struct completion       conn_wait_rcfr_comp;
+       struct completion       conn_waiting_on_uc_comp;
+       struct completion       conn_logout_comp;
+       struct completion       tx_half_close_comp;
+       struct completion       rx_half_close_comp;
+       /* socket used by this connection */
+       struct socket           *sock;
+       struct timer_list       nopin_timer;
+       struct timer_list       nopin_response_timer;
+       struct timer_list       transport_timer;
+       /* Spinlock used for add/deleting cmd's from conn_cmd_list */
+       spinlock_t              cmd_lock;
+       spinlock_t              conn_usage_lock;
+       spinlock_t              immed_queue_lock;
+       spinlock_t              nopin_timer_lock;
+       spinlock_t              response_queue_lock;
+       spinlock_t              state_lock;
+       /* libcrypto RX and TX contexts for crc32c */
+       struct hash_desc        conn_rx_hash;
+       struct hash_desc        conn_tx_hash;
+       /* Used for scheduling TX and RX connection kthreads */
+       cpumask_var_t           conn_cpumask;
+       int                     conn_rx_reset_cpumask:1;
+       int                     conn_tx_reset_cpumask:1;
+       /* list_head of struct iscsi_cmd for this connection */
+       struct list_head        conn_cmd_list;
+       struct list_head        immed_queue_list;
+       struct list_head        response_queue_list;
+       struct iscsi_conn_ops   *conn_ops;
+       struct iscsi_param_list *param_list;
+       /* Used for per connection auth state machine */
+       void                    *auth_protocol;
+       struct iscsi_login_thread_s *login_thread;
+       struct iscsi_portal_group *tpg;
+       /* Pointer to parent session */
+       struct iscsi_session    *sess;
+       /* Pointer to thread_set in use for this conn's threads */
+       struct iscsi_thread_set *thread_set;
+       /* list_head for session connection list */
+       struct list_head        conn_list;
+} ____cacheline_aligned;
+
+struct iscsi_conn_recovery {
+       u16                     cid;
+       u32                     cmd_count;
+       u32                     maxrecvdatasegmentlength;
+       int                     ready_for_reallegiance;
+       struct list_head        conn_recovery_cmd_list;
+       spinlock_t              conn_recovery_cmd_lock;
+       struct timer_list       time2retain_timer;
+       struct iscsi_session    *sess;
+       struct list_head        cr_list;
+}  ____cacheline_aligned;
+
+struct iscsi_session {
+       u8                      initiator_vendor;
+       u8                      isid[6];
+       enum iscsi_timer_flags_table time2retain_timer_flags;
+       u8                      version_active;
+       u16                     cid_called;
+       u16                     conn_recovery_count;
+       u16                     tsih;
+       /* state session is currently in */
+       u32                     session_state;
+       /* session wide counter: initiator assigned task tag */
+       u32                     init_task_tag;
+       /* session wide counter: target assigned task tag */
+       u32                     targ_xfer_tag;
+       u32                     cmdsn_window;
+
+       /* protects cmdsn values */
+       struct mutex            cmdsn_mutex;
+       /* session wide counter: expected command sequence number */
+       u32                     exp_cmd_sn;
+       /* session wide counter: maximum allowed command sequence number */
+       u32                     max_cmd_sn;
+       struct list_head        sess_ooo_cmdsn_list;
+
+       /* LIO specific session ID */
+       u32                     sid;
+       char                    auth_type[8];
+       /* unique within the target */
+       int                     session_index;
+       /* Used for session reference counting */
+       int                     session_usage_count;
+       int                     session_waiting_on_uc;
+       u32                     cmd_pdus;
+       u32                     rsp_pdus;
+       u64                     tx_data_octets;
+       u64                     rx_data_octets;
+       u32                     conn_digest_errors;
+       u32                     conn_timeout_errors;
+       u64                     creation_time;
+       spinlock_t              session_stats_lock;
+       /* Number of active connections */
+       atomic_t                nconn;
+       atomic_t                session_continuation;
+       atomic_t                session_fall_back_to_erl0;
+       atomic_t                session_logout;
+       atomic_t                session_reinstatement;
+       atomic_t                session_stop_active;
+       atomic_t                sleep_on_sess_wait_comp;
+       atomic_t                transport_wait_cmds;
+       /* connection list */
+       struct list_head        sess_conn_list;
+       struct list_head        cr_active_list;
+       struct list_head        cr_inactive_list;
+       spinlock_t              conn_lock;
+       spinlock_t              cr_a_lock;
+       spinlock_t              cr_i_lock;
+       spinlock_t              session_usage_lock;
+       spinlock_t              ttt_lock;
+       struct completion       async_msg_comp;
+       struct completion       reinstatement_comp;
+       struct completion       session_wait_comp;
+       struct completion       session_waiting_on_uc_comp;
+       struct timer_list       time2retain_timer;
+       struct iscsi_sess_ops   *sess_ops;
+       struct se_session       *se_sess;
+       struct iscsi_portal_group *tpg;
+} ____cacheline_aligned;
+
+struct iscsi_login {
+       u8 auth_complete;
+       u8 checked_for_existing;
+       u8 current_stage;
+       u8 leading_connection;
+       u8 first_request;
+       u8 version_min;
+       u8 version_max;
+       char isid[6];
+       u32 cmd_sn;
+       u32 init_task_tag;
+       u32 initial_exp_statsn;
+       u32 rsp_length;
+       u16 cid;
+       u16 tsih;
+       char *req;
+       char *rsp;
+       char *req_buf;
+       char *rsp_buf;
+} ____cacheline_aligned;
+
+struct iscsi_node_attrib {
+       u32                     dataout_timeout;
+       u32                     dataout_timeout_retries;
+       u32                     default_erl;
+       u32                     nopin_timeout;
+       u32                     nopin_response_timeout;
+       u32                     random_datain_pdu_offsets;
+       u32                     random_datain_seq_offsets;
+       u32                     random_r2t_offsets;
+       u32                     tmr_cold_reset;
+       u32                     tmr_warm_reset;
+       struct iscsi_node_acl *nacl;
+};
+
+struct se_dev_entry_s;
+
+struct iscsi_node_auth {
+       enum naf_flags_table    naf_flags;
+       int                     authenticate_target;
+       /* Used for iscsit_global->discovery_auth,
+        * set to zero (auth disabled) by default */
+       int                     enforce_discovery_auth;
+#define MAX_USER_LEN                           256
+#define MAX_PASS_LEN                           256
+       char                    userid[MAX_USER_LEN];
+       char                    password[MAX_PASS_LEN];
+       char                    userid_mutual[MAX_USER_LEN];
+       char                    password_mutual[MAX_PASS_LEN];
+};
+
+#include "iscsi_target_stat.h"
+
+struct iscsi_node_stat_grps {
+       struct config_group     iscsi_sess_stats_group;
+       struct config_group     iscsi_conn_stats_group;
+};
+
+struct iscsi_node_acl {
+       struct iscsi_node_attrib node_attrib;
+       struct iscsi_node_auth  node_auth;
+       struct iscsi_node_stat_grps node_stat_grps;
+       struct se_node_acl      se_node_acl;
+};
+
+#define NODE_STAT_GRPS(nacl)   (&(nacl)->node_stat_grps)
+
+#define ISCSI_NODE_ATTRIB(t)   (&(t)->node_attrib)
+#define ISCSI_NODE_AUTH(t)     (&(t)->node_auth)
+
+struct iscsi_tpg_attrib {
+       u32                     authentication;
+       u32                     login_timeout;
+       u32                     netif_timeout;
+       u32                     generate_node_acls;
+       u32                     cache_dynamic_acls;
+       u32                     default_cmdsn_depth;
+       u32                     demo_mode_write_protect;
+       u32                     prod_mode_write_protect;
+       struct iscsi_portal_group *tpg;
+};
+
+struct iscsi_np {
+       int                     np_network_transport;
+       int                     np_ip_proto;
+       int                     np_sock_type;
+       enum np_thread_state_table np_thread_state;
+       enum iscsi_timer_flags_table np_login_timer_flags;
+       u32                     np_exports;
+       enum np_flags_table     np_flags;
+       unsigned char           np_ip[IPV6_ADDRESS_SPACE];
+       u16                     np_port;
+       spinlock_t              np_thread_lock;
+       struct completion       np_restart_comp;
+       struct socket           *np_socket;
+       struct __kernel_sockaddr_storage np_sockaddr;
+       struct task_struct      *np_thread;
+       struct timer_list       np_login_timer;
+       struct iscsi_portal_group *np_login_tpg;
+       struct list_head        np_list;
+} ____cacheline_aligned;
+
+struct iscsi_tpg_np {
+       struct iscsi_np         *tpg_np;
+       struct iscsi_portal_group *tpg;
+       struct iscsi_tpg_np     *tpg_np_parent;
+       struct list_head        tpg_np_list;
+       struct list_head        tpg_np_child_list;
+       struct list_head        tpg_np_parent_list;
+       struct se_tpg_np        se_tpg_np;
+       spinlock_t              tpg_np_parent_lock;
+};
+
+struct iscsi_portal_group {
+       unsigned char           tpg_chap_id;
+       /* TPG State */
+       enum tpg_state_table    tpg_state;
+       /* Target Portal Group Tag */
+       u16                     tpgt;
+       /* Id assigned to target sessions */
+       u16                     ntsih;
+       /* Number of active sessions */
+       u32                     nsessions;
+       /* Number of Network Portals available for this TPG */
+       u32                     num_tpg_nps;
+       /* Per TPG LIO specific session ID. */
+       u32                     sid;
+       /* Spinlock for adding/removing Network Portals */
+       spinlock_t              tpg_np_lock;
+       spinlock_t              tpg_state_lock;
+       struct se_portal_group tpg_se_tpg;
+       struct mutex            tpg_access_lock;
+       struct mutex            np_login_lock;
+       struct iscsi_tpg_attrib tpg_attrib;
+       /* Pointer to default list of iSCSI parameters for TPG */
+       struct iscsi_param_list *param_list;
+       struct iscsi_tiqn       *tpg_tiqn;
+       struct list_head        tpg_gnp_list;
+       struct list_head        tpg_list;
+} ____cacheline_aligned;
+
+#define ISCSI_TPG_C(c)         ((struct iscsi_portal_group *)(c)->tpg)
+#define ISCSI_TPG_LUN(c, l)  ((iscsi_tpg_list_t *)(c)->tpg->tpg_lun_list_t[l])
+#define ISCSI_TPG_S(s)         ((struct iscsi_portal_group *)(s)->tpg)
+#define ISCSI_TPG_ATTRIB(t)    (&(t)->tpg_attrib)
+#define SE_TPG(tpg)            (&(tpg)->tpg_se_tpg)
+
+struct iscsi_wwn_stat_grps {
+       struct config_group     iscsi_stat_group;
+       struct config_group     iscsi_instance_group;
+       struct config_group     iscsi_sess_err_group;
+       struct config_group     iscsi_tgt_attr_group;
+       struct config_group     iscsi_login_stats_group;
+       struct config_group     iscsi_logout_stats_group;
+};
+
+struct iscsi_tiqn {
+#define ISCSI_IQN_LEN                          224
+       unsigned char           tiqn[ISCSI_IQN_LEN];
+       enum tiqn_state_table   tiqn_state;
+       int                     tiqn_access_count;
+       u32                     tiqn_active_tpgs;
+       u32                     tiqn_ntpgs;
+       u32                     tiqn_num_tpg_nps;
+       u32                     tiqn_nsessions;
+       struct list_head        tiqn_list;
+       struct list_head        tiqn_tpg_list;
+       spinlock_t              tiqn_state_lock;
+       spinlock_t              tiqn_tpg_lock;
+       struct se_wwn           tiqn_wwn;
+       struct iscsi_wwn_stat_grps tiqn_stat_grps;
+       int                     tiqn_index;
+       struct iscsi_sess_err_stats  sess_err_stats;
+       struct iscsi_login_stats     login_stats;
+       struct iscsi_logout_stats    logout_stats;
+} ____cacheline_aligned;
+
+#define WWN_STAT_GRPS(tiqn)    (&(tiqn)->tiqn_stat_grps)
+
+struct iscsit_global {
+       /* In core shutdown */
+       u32                     in_shutdown;
+       u32                     active_ts;
+       /* Unique identifier used for the authentication daemon */
+       u32                     auth_id;
+       u32                     inactive_ts;
+       /* Thread Set bitmap count */
+       int                     ts_bitmap_count;
+       /* Thread Set bitmap pointer */
+       unsigned long           *ts_bitmap;
+       /* Used for iSCSI discovery session authentication */
+       struct iscsi_node_acl   discovery_acl;
+       struct iscsi_portal_group       *discovery_tpg;
+};
+
+#endif /* ISCSI_TARGET_CORE_H */
diff --git a/drivers/target/iscsi/iscsi_target_datain_values.c b/drivers/target/iscsi/iscsi_target_datain_values.c
new file mode 100644 (file)
index 0000000..8c04951
--- /dev/null
@@ -0,0 +1,531 @@
+/*******************************************************************************
+ * This file contains the iSCSI Target DataIN value generation functions.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <scsi/iscsi_proto.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_seq_pdu_list.h"
+#include "iscsi_target_erl1.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target.h"
+#include "iscsi_target_datain_values.h"
+
+struct iscsi_datain_req *iscsit_allocate_datain_req(void)
+{
+       struct iscsi_datain_req *dr;
+
+       dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC);
+       if (!dr) {
+               pr_err("Unable to allocate memory for"
+                               " struct iscsi_datain_req\n");
+               return NULL;
+       }
+       INIT_LIST_HEAD(&dr->dr_list);
+
+       return dr;
+}
+
+void iscsit_attach_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
+{
+       spin_lock(&cmd->datain_lock);
+       list_add_tail(&dr->dr_list, &cmd->datain_list);
+       spin_unlock(&cmd->datain_lock);
+}
+
+void iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr)
+{
+       spin_lock(&cmd->datain_lock);
+       list_del(&dr->dr_list);
+       spin_unlock(&cmd->datain_lock);
+
+       kmem_cache_free(lio_dr_cache, dr);
+}
+
+void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd)
+{
+       struct iscsi_datain_req *dr, *dr_tmp;
+
+       spin_lock(&cmd->datain_lock);
+       list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, dr_list) {
+               list_del(&dr->dr_list);
+               kmem_cache_free(lio_dr_cache, dr);
+       }
+       spin_unlock(&cmd->datain_lock);
+}
+
+struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd)
+{
+       struct iscsi_datain_req *dr;
+
+       if (list_empty(&cmd->datain_list)) {
+               pr_err("cmd->datain_list is empty for ITT:"
+                       " 0x%08x\n", cmd->init_task_tag);
+               return NULL;
+       }
+       list_for_each_entry(dr, &cmd->datain_list, dr_list)
+               break;
+
+       return dr;
+}
+
+/*
+ *     For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes.
+ */
+static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes(
+       struct iscsi_cmd *cmd,
+       struct iscsi_datain *datain)
+{
+       u32 next_burst_len, read_data_done, read_data_left;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_datain_req *dr;
+
+       dr = iscsit_get_datain_req(cmd);
+       if (!dr)
+               return NULL;
+
+       if (dr->recovery && dr->generate_recovery_values) {
+               if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
+                                       cmd, dr) < 0)
+                       return NULL;
+
+               dr->generate_recovery_values = 0;
+       }
+
+       next_burst_len = (!dr->recovery) ?
+                       cmd->next_burst_len : dr->next_burst_len;
+       read_data_done = (!dr->recovery) ?
+                       cmd->read_data_done : dr->read_data_done;
+
+       read_data_left = (cmd->data_length - read_data_done);
+       if (!read_data_left) {
+               pr_err("ITT: 0x%08x read_data_left is zero!\n",
+                               cmd->init_task_tag);
+               return NULL;
+       }
+
+       if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) &&
+           (read_data_left <= (conn->sess->sess_ops->MaxBurstLength -
+            next_burst_len))) {
+               datain->length = read_data_left;
+
+               datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
+               if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
+                       datain->flags |= ISCSI_FLAG_DATA_ACK;
+       } else {
+               if ((next_burst_len +
+                    conn->conn_ops->MaxRecvDataSegmentLength) <
+                    conn->sess->sess_ops->MaxBurstLength) {
+                       datain->length =
+                               conn->conn_ops->MaxRecvDataSegmentLength;
+                       next_burst_len += datain->length;
+               } else {
+                       datain->length = (conn->sess->sess_ops->MaxBurstLength -
+                                         next_burst_len);
+                       next_burst_len = 0;
+
+                       datain->flags |= ISCSI_FLAG_CMD_FINAL;
+                       if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
+                               datain->flags |= ISCSI_FLAG_DATA_ACK;
+               }
+       }
+
+       datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
+       datain->offset = read_data_done;
+
+       if (!dr->recovery) {
+               cmd->next_burst_len = next_burst_len;
+               cmd->read_data_done += datain->length;
+       } else {
+               dr->next_burst_len = next_burst_len;
+               dr->read_data_done += datain->length;
+       }
+
+       if (!dr->recovery) {
+               if (datain->flags & ISCSI_FLAG_DATA_STATUS)
+                       dr->dr_complete = DATAIN_COMPLETE_NORMAL;
+
+               return dr;
+       }
+
+       if (!dr->runlength) {
+               if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
+                       dr->dr_complete =
+                           (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
+                               DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
+                               DATAIN_COMPLETE_CONNECTION_RECOVERY;
+               }
+       } else {
+               if ((dr->begrun + dr->runlength) == dr->data_sn) {
+                       dr->dr_complete =
+                           (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
+                               DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
+                               DATAIN_COMPLETE_CONNECTION_RECOVERY;
+               }
+       }
+
+       return dr;
+}
+
+/*
+ *     For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes.
+ */
+static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes(
+       struct iscsi_cmd *cmd,
+       struct iscsi_datain *datain)
+{
+       u32 offset, read_data_done, read_data_left, seq_send_order;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_datain_req *dr;
+       struct iscsi_seq *seq;
+
+       dr = iscsit_get_datain_req(cmd);
+       if (!dr)
+               return NULL;
+
+       if (dr->recovery && dr->generate_recovery_values) {
+               if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
+                                       cmd, dr) < 0)
+                       return NULL;
+
+               dr->generate_recovery_values = 0;
+       }
+
+       read_data_done = (!dr->recovery) ?
+                       cmd->read_data_done : dr->read_data_done;
+       seq_send_order = (!dr->recovery) ?
+                       cmd->seq_send_order : dr->seq_send_order;
+
+       read_data_left = (cmd->data_length - read_data_done);
+       if (!read_data_left) {
+               pr_err("ITT: 0x%08x read_data_left is zero!\n",
+                               cmd->init_task_tag);
+               return NULL;
+       }
+
+       seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
+       if (!seq)
+               return NULL;
+
+       seq->sent = 1;
+
+       if (!dr->recovery && !seq->next_burst_len)
+               seq->first_datasn = cmd->data_sn;
+
+       offset = (seq->offset + seq->next_burst_len);
+
+       if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
+            cmd->data_length) {
+               datain->length = (cmd->data_length - offset);
+               datain->offset = offset;
+
+               datain->flags |= ISCSI_FLAG_CMD_FINAL;
+               if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
+                       datain->flags |= ISCSI_FLAG_DATA_ACK;
+
+               seq->next_burst_len = 0;
+               seq_send_order++;
+       } else {
+               if ((seq->next_burst_len +
+                    conn->conn_ops->MaxRecvDataSegmentLength) <
+                    conn->sess->sess_ops->MaxBurstLength) {
+                       datain->length =
+                               conn->conn_ops->MaxRecvDataSegmentLength;
+                       datain->offset = (seq->offset + seq->next_burst_len);
+
+                       seq->next_burst_len += datain->length;
+               } else {
+                       datain->length = (conn->sess->sess_ops->MaxBurstLength -
+                                         seq->next_burst_len);
+                       datain->offset = (seq->offset + seq->next_burst_len);
+
+                       datain->flags |= ISCSI_FLAG_CMD_FINAL;
+                       if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
+                               datain->flags |= ISCSI_FLAG_DATA_ACK;
+
+                       seq->next_burst_len = 0;
+                       seq_send_order++;
+               }
+       }
+
+       if ((read_data_done + datain->length) == cmd->data_length)
+               datain->flags |= ISCSI_FLAG_DATA_STATUS;
+
+       datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
+       if (!dr->recovery) {
+               cmd->seq_send_order = seq_send_order;
+               cmd->read_data_done += datain->length;
+       } else {
+               dr->seq_send_order = seq_send_order;
+               dr->read_data_done += datain->length;
+       }
+
+       if (!dr->recovery) {
+               if (datain->flags & ISCSI_FLAG_CMD_FINAL)
+                       seq->last_datasn = datain->data_sn;
+               if (datain->flags & ISCSI_FLAG_DATA_STATUS)
+                       dr->dr_complete = DATAIN_COMPLETE_NORMAL;
+
+               return dr;
+       }
+
+       if (!dr->runlength) {
+               if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
+                       dr->dr_complete =
+                           (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
+                               DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
+                               DATAIN_COMPLETE_CONNECTION_RECOVERY;
+               }
+       } else {
+               if ((dr->begrun + dr->runlength) == dr->data_sn) {
+                       dr->dr_complete =
+                           (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
+                               DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
+                               DATAIN_COMPLETE_CONNECTION_RECOVERY;
+               }
+       }
+
+       return dr;
+}
+
+/*
+ *     For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No.
+ */
+static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no(
+       struct iscsi_cmd *cmd,
+       struct iscsi_datain *datain)
+{
+       u32 next_burst_len, read_data_done, read_data_left;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_datain_req *dr;
+       struct iscsi_pdu *pdu;
+
+       dr = iscsit_get_datain_req(cmd);
+       if (!dr)
+               return NULL;
+
+       if (dr->recovery && dr->generate_recovery_values) {
+               if (iscsit_create_recovery_datain_values_datasequenceinorder_yes(
+                                       cmd, dr) < 0)
+                       return NULL;
+
+               dr->generate_recovery_values = 0;
+       }
+
+       next_burst_len = (!dr->recovery) ?
+                       cmd->next_burst_len : dr->next_burst_len;
+       read_data_done = (!dr->recovery) ?
+                       cmd->read_data_done : dr->read_data_done;
+
+       read_data_left = (cmd->data_length - read_data_done);
+       if (!read_data_left) {
+               pr_err("ITT: 0x%08x read_data_left is zero!\n",
+                               cmd->init_task_tag);
+               return dr;
+       }
+
+       pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL);
+       if (!pdu)
+               return dr;
+
+       if ((read_data_done + pdu->length) == cmd->data_length) {
+               pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS);
+               if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
+                       pdu->flags |= ISCSI_FLAG_DATA_ACK;
+
+               next_burst_len = 0;
+       } else {
+               if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) <
+                    conn->sess->sess_ops->MaxBurstLength)
+                       next_burst_len += pdu->length;
+               else {
+                       pdu->flags |= ISCSI_FLAG_CMD_FINAL;
+                       if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
+                               pdu->flags |= ISCSI_FLAG_DATA_ACK;
+
+                       next_burst_len = 0;
+               }
+       }
+
+       pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
+       if (!dr->recovery) {
+               cmd->next_burst_len = next_burst_len;
+               cmd->read_data_done += pdu->length;
+       } else {
+               dr->next_burst_len = next_burst_len;
+               dr->read_data_done += pdu->length;
+       }
+
+       datain->flags = pdu->flags;
+       datain->length = pdu->length;
+       datain->offset = pdu->offset;
+       datain->data_sn = pdu->data_sn;
+
+       if (!dr->recovery) {
+               if (datain->flags & ISCSI_FLAG_DATA_STATUS)
+                       dr->dr_complete = DATAIN_COMPLETE_NORMAL;
+
+               return dr;
+       }
+
+       if (!dr->runlength) {
+               if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
+                       dr->dr_complete =
+                           (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
+                               DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
+                               DATAIN_COMPLETE_CONNECTION_RECOVERY;
+               }
+       } else {
+               if ((dr->begrun + dr->runlength) == dr->data_sn) {
+                       dr->dr_complete =
+                           (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
+                               DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
+                               DATAIN_COMPLETE_CONNECTION_RECOVERY;
+               }
+       }
+
+       return dr;
+}
+
+/*
+ *     For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No.
+ */
+static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no(
+       struct iscsi_cmd *cmd,
+       struct iscsi_datain *datain)
+{
+       u32 read_data_done, read_data_left, seq_send_order;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_datain_req *dr;
+       struct iscsi_pdu *pdu;
+       struct iscsi_seq *seq = NULL;
+
+       dr = iscsit_get_datain_req(cmd);
+       if (!dr)
+               return NULL;
+
+       if (dr->recovery && dr->generate_recovery_values) {
+               if (iscsit_create_recovery_datain_values_datasequenceinorder_no(
+                                       cmd, dr) < 0)
+                       return NULL;
+
+               dr->generate_recovery_values = 0;
+       }
+
+       read_data_done = (!dr->recovery) ?
+                       cmd->read_data_done : dr->read_data_done;
+       seq_send_order = (!dr->recovery) ?
+                       cmd->seq_send_order : dr->seq_send_order;
+
+       read_data_left = (cmd->data_length - read_data_done);
+       if (!read_data_left) {
+               pr_err("ITT: 0x%08x read_data_left is zero!\n",
+                               cmd->init_task_tag);
+               return NULL;
+       }
+
+       seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order);
+       if (!seq)
+               return NULL;
+
+       seq->sent = 1;
+
+       if (!dr->recovery && !seq->next_burst_len)
+               seq->first_datasn = cmd->data_sn;
+
+       pdu = iscsit_get_pdu_holder_for_seq(cmd, seq);
+       if (!pdu)
+               return NULL;
+
+       if (seq->pdu_send_order == seq->pdu_count) {
+               pdu->flags |= ISCSI_FLAG_CMD_FINAL;
+               if (conn->sess->sess_ops->ErrorRecoveryLevel > 0)
+                       pdu->flags |= ISCSI_FLAG_DATA_ACK;
+
+               seq->next_burst_len = 0;
+               seq_send_order++;
+       } else
+               seq->next_burst_len += pdu->length;
+
+       if ((read_data_done + pdu->length) == cmd->data_length)
+               pdu->flags |= ISCSI_FLAG_DATA_STATUS;
+
+       pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++;
+       if (!dr->recovery) {
+               cmd->seq_send_order = seq_send_order;
+               cmd->read_data_done += pdu->length;
+       } else {
+               dr->seq_send_order = seq_send_order;
+               dr->read_data_done += pdu->length;
+       }
+
+       datain->flags = pdu->flags;
+       datain->length = pdu->length;
+       datain->offset = pdu->offset;
+       datain->data_sn = pdu->data_sn;
+
+       if (!dr->recovery) {
+               if (datain->flags & ISCSI_FLAG_CMD_FINAL)
+                       seq->last_datasn = datain->data_sn;
+               if (datain->flags & ISCSI_FLAG_DATA_STATUS)
+                       dr->dr_complete = DATAIN_COMPLETE_NORMAL;
+
+               return dr;
+       }
+
+       if (!dr->runlength) {
+               if (datain->flags & ISCSI_FLAG_DATA_STATUS) {
+                       dr->dr_complete =
+                           (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
+                               DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
+                               DATAIN_COMPLETE_CONNECTION_RECOVERY;
+               }
+       } else {
+               if ((dr->begrun + dr->runlength) == dr->data_sn) {
+                       dr->dr_complete =
+                           (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ?
+                               DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY :
+                               DATAIN_COMPLETE_CONNECTION_RECOVERY;
+               }
+       }
+
+       return dr;
+}
+
+struct iscsi_datain_req *iscsit_get_datain_values(
+       struct iscsi_cmd *cmd,
+       struct iscsi_datain *datain)
+{
+       struct iscsi_conn *conn = cmd->conn;
+
+       if (conn->sess->sess_ops->DataSequenceInOrder &&
+           conn->sess->sess_ops->DataPDUInOrder)
+               return iscsit_set_datain_values_yes_and_yes(cmd, datain);
+       else if (!conn->sess->sess_ops->DataSequenceInOrder &&
+                 conn->sess->sess_ops->DataPDUInOrder)
+               return iscsit_set_datain_values_no_and_yes(cmd, datain);
+       else if (conn->sess->sess_ops->DataSequenceInOrder &&
+                !conn->sess->sess_ops->DataPDUInOrder)
+               return iscsit_set_datain_values_yes_and_no(cmd, datain);
+       else if (!conn->sess->sess_ops->DataSequenceInOrder &&
+                  !conn->sess->sess_ops->DataPDUInOrder)
+               return iscsit_set_datain_values_no_and_no(cmd, datain);
+
+       return NULL;
+}
diff --git a/drivers/target/iscsi/iscsi_target_datain_values.h b/drivers/target/iscsi/iscsi_target_datain_values.h
new file mode 100644 (file)
index 0000000..646429a
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef ISCSI_TARGET_DATAIN_VALUES_H
+#define ISCSI_TARGET_DATAIN_VALUES_H
+
+extern struct iscsi_datain_req *iscsit_allocate_datain_req(void);
+extern void iscsit_attach_datain_req(struct iscsi_cmd *, struct iscsi_datain_req *);
+extern void iscsit_free_datain_req(struct iscsi_cmd *, struct iscsi_datain_req *);
+extern void iscsit_free_all_datain_reqs(struct iscsi_cmd *);
+extern struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *);
+extern struct iscsi_datain_req *iscsit_get_datain_values(struct iscsi_cmd *,
+                       struct iscsi_datain *);
+
+#endif   /*** ISCSI_TARGET_DATAIN_VALUES_H ***/
diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c
new file mode 100644 (file)
index 0000000..a19fa5e
--- /dev/null
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * This file contains the iSCSI Virtual Device and Disk Transport
+ * agnostic related functions.
+ *
+ \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <scsi/scsi_device.h>
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_device.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_util.h"
+
+int iscsit_get_lun_for_tmr(
+       struct iscsi_cmd *cmd,
+       u64 lun)
+{
+       u32 unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
+
+       return transport_lookup_tmr_lun(&cmd->se_cmd, unpacked_lun);
+}
+
+int iscsit_get_lun_for_cmd(
+       struct iscsi_cmd *cmd,
+       unsigned char *cdb,
+       u64 lun)
+{
+       u32 unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
+
+       return transport_lookup_cmd_lun(&cmd->se_cmd, unpacked_lun);
+}
+
+void iscsit_determine_maxcmdsn(struct iscsi_session *sess)
+{
+       struct se_node_acl *se_nacl;
+
+       /*
+        * This is a discovery session, the single queue slot was already
+        * assigned in iscsi_login_zero_tsih().  Since only Logout and
+        * Text Opcodes are allowed during discovery we do not have to worry
+        * about the HBA's queue depth here.
+        */
+       if (sess->sess_ops->SessionType)
+               return;
+
+       se_nacl = sess->se_sess->se_node_acl;
+
+       /*
+        * This is a normal session, set the Session's CmdSN window to the
+        * struct se_node_acl->queue_depth.  The value in struct se_node_acl->queue_depth
+        * has already been validated as a legal value in
+        * core_set_queue_depth_for_node().
+        */
+       sess->cmdsn_window = se_nacl->queue_depth;
+       sess->max_cmd_sn = (sess->max_cmd_sn + se_nacl->queue_depth) - 1;
+}
+
+void iscsit_increment_maxcmdsn(struct iscsi_cmd *cmd, struct iscsi_session *sess)
+{
+       if (cmd->immediate_cmd || cmd->maxcmdsn_inc)
+               return;
+
+       cmd->maxcmdsn_inc = 1;
+
+       mutex_lock(&sess->cmdsn_mutex);
+       sess->max_cmd_sn += 1;
+       pr_debug("Updated MaxCmdSN to 0x%08x\n", sess->max_cmd_sn);
+       mutex_unlock(&sess->cmdsn_mutex);
+}
diff --git a/drivers/target/iscsi/iscsi_target_device.h b/drivers/target/iscsi/iscsi_target_device.h
new file mode 100644 (file)
index 0000000..bef1cad
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef ISCSI_TARGET_DEVICE_H
+#define ISCSI_TARGET_DEVICE_H
+
+extern int iscsit_get_lun_for_tmr(struct iscsi_cmd *, u64);
+extern int iscsit_get_lun_for_cmd(struct iscsi_cmd *, unsigned char *, u64);
+extern void iscsit_determine_maxcmdsn(struct iscsi_session *);
+extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *);
+
+#endif /* ISCSI_TARGET_DEVICE_H */
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c
new file mode 100644 (file)
index 0000000..b7ffc3c
--- /dev/null
@@ -0,0 +1,1004 @@
+/******************************************************************************
+ * This file contains error recovery level zero functions used by
+ * the iSCSI Target driver.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <scsi/iscsi_proto.h>
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_seq_pdu_list.h"
+#include "iscsi_target_tq.h"
+#include "iscsi_target_erl0.h"
+#include "iscsi_target_erl1.h"
+#include "iscsi_target_erl2.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target.h"
+
+/*
+ *     Used to set values in struct iscsi_cmd that iscsit_dataout_check_sequence()
+ *     checks against to determine a PDU's Offset+Length is within the current
+ *     DataOUT Sequence.  Used for DataSequenceInOrder=Yes only.
+ */
+void iscsit_set_dataout_sequence_values(
+       struct iscsi_cmd *cmd)
+{
+       struct iscsi_conn *conn = cmd->conn;
+       /*
+        * Still set seq_start_offset and seq_end_offset for Unsolicited
+        * DataOUT, even if DataSequenceInOrder=No.
+        */
+       if (cmd->unsolicited_data) {
+               cmd->seq_start_offset = cmd->write_data_done;
+               cmd->seq_end_offset = (cmd->write_data_done +
+                       (cmd->data_length >
+                        conn->sess->sess_ops->FirstBurstLength) ?
+                       conn->sess->sess_ops->FirstBurstLength : cmd->data_length);
+               return;
+       }
+
+       if (!conn->sess->sess_ops->DataSequenceInOrder)
+               return;
+
+       if (!cmd->seq_start_offset && !cmd->seq_end_offset) {
+               cmd->seq_start_offset = cmd->write_data_done;
+               cmd->seq_end_offset = (cmd->data_length >
+                       conn->sess->sess_ops->MaxBurstLength) ?
+                       (cmd->write_data_done +
+                       conn->sess->sess_ops->MaxBurstLength) : cmd->data_length;
+       } else {
+               cmd->seq_start_offset = cmd->seq_end_offset;
+               cmd->seq_end_offset = ((cmd->seq_end_offset +
+                       conn->sess->sess_ops->MaxBurstLength) >=
+                       cmd->data_length) ? cmd->data_length :
+                       (cmd->seq_end_offset +
+                        conn->sess->sess_ops->MaxBurstLength);
+       }
+}
+
+static int iscsit_dataout_within_command_recovery_check(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_data *hdr = (struct iscsi_data *) buf;
+       u32 payload_length = ntoh24(hdr->dlength);
+
+       /*
+        * We do the within-command recovery checks here as it is
+        * the first function called in iscsi_check_pre_dataout().
+        * Basically, if we are in within-command recovery and
+        * the PDU does not contain the offset the sequence needs,
+        * dump the payload.
+        *
+        * This only applies to DataPDUInOrder=Yes, for
+        * DataPDUInOrder=No we only re-request the failed PDU
+        * and check that all PDUs in a sequence are received
+        * upon end of sequence.
+        */
+       if (conn->sess->sess_ops->DataSequenceInOrder) {
+               if ((cmd->cmd_flags & ICF_WITHIN_COMMAND_RECOVERY) &&
+                   (cmd->write_data_done != hdr->offset))
+                       goto dump;
+
+               cmd->cmd_flags &= ~ICF_WITHIN_COMMAND_RECOVERY;
+       } else {
+               struct iscsi_seq *seq;
+
+               seq = iscsit_get_seq_holder(cmd, hdr->offset, payload_length);
+               if (!seq)
+                       return DATAOUT_CANNOT_RECOVER;
+               /*
+                * Set the struct iscsi_seq pointer to reuse later.
+                */
+               cmd->seq_ptr = seq;
+
+               if (conn->sess->sess_ops->DataPDUInOrder) {
+                       if ((seq->status ==
+                            DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY) &&
+                          ((seq->offset != hdr->offset) ||
+                           (seq->data_sn != hdr->datasn)))
+                               goto dump;
+               } else {
+                       if ((seq->status ==
+                            DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY) &&
+                           (seq->data_sn != hdr->datasn))
+                               goto dump;
+               }
+
+               if (seq->status == DATAOUT_SEQUENCE_COMPLETE)
+                       goto dump;
+
+               if (seq->status != DATAOUT_SEQUENCE_COMPLETE)
+                       seq->status = 0;
+       }
+
+       return DATAOUT_NORMAL;
+
+dump:
+       pr_err("Dumping DataOUT PDU Offset: %u Length: %d DataSN:"
+               " 0x%08x\n", hdr->offset, payload_length, hdr->datasn);
+       return iscsit_dump_data_payload(conn, payload_length, 1);
+}
+
+static int iscsit_dataout_check_unsolicited_sequence(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       u32 first_burst_len;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_data *hdr = (struct iscsi_data *) buf;
+       u32 payload_length = ntoh24(hdr->dlength);
+
+
+       if ((hdr->offset < cmd->seq_start_offset) ||
+          ((hdr->offset + payload_length) > cmd->seq_end_offset)) {
+               pr_err("Command ITT: 0x%08x with Offset: %u,"
+               " Length: %u outside of Unsolicited Sequence %u:%u while"
+               " DataSequenceInOrder=Yes.\n", cmd->init_task_tag,
+               hdr->offset, payload_length, cmd->seq_start_offset,
+                       cmd->seq_end_offset);
+               return DATAOUT_CANNOT_RECOVER;
+       }
+
+       first_burst_len = (cmd->first_burst_len + payload_length);
+
+       if (first_burst_len > conn->sess->sess_ops->FirstBurstLength) {
+               pr_err("Total %u bytes exceeds FirstBurstLength: %u"
+                       " for this Unsolicited DataOut Burst.\n",
+                       first_burst_len, conn->sess->sess_ops->FirstBurstLength);
+               transport_send_check_condition_and_sense(&cmd->se_cmd,
+                               TCM_INCORRECT_AMOUNT_OF_DATA, 0);
+               return DATAOUT_CANNOT_RECOVER;
+       }
+
+       /*
+        * Perform various MaxBurstLength and ISCSI_FLAG_CMD_FINAL sanity
+        * checks for the current Unsolicited DataOUT Sequence.
+        */
+       if (hdr->flags & ISCSI_FLAG_CMD_FINAL) {
+               /*
+                * Ignore ISCSI_FLAG_CMD_FINAL checks while DataPDUInOrder=No, end of
+                * sequence checks are handled in
+                * iscsit_dataout_datapduinorder_no_fbit().
+                */
+               if (!conn->sess->sess_ops->DataPDUInOrder)
+                       goto out;
+
+               if ((first_burst_len != cmd->data_length) &&
+                   (first_burst_len != conn->sess->sess_ops->FirstBurstLength)) {
+                       pr_err("Unsolicited non-immediate data"
+                       " received %u does not equal FirstBurstLength: %u, and"
+                       " does not equal ExpXferLen %u.\n", first_burst_len,
+                               conn->sess->sess_ops->FirstBurstLength,
+                               cmd->data_length);
+                       transport_send_check_condition_and_sense(&cmd->se_cmd,
+                                       TCM_INCORRECT_AMOUNT_OF_DATA, 0);
+                       return DATAOUT_CANNOT_RECOVER;
+               }
+       } else {
+               if (first_burst_len == conn->sess->sess_ops->FirstBurstLength) {
+                       pr_err("Command ITT: 0x%08x reached"
+                       " FirstBurstLength: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol"
+                               " error.\n", cmd->init_task_tag,
+                               conn->sess->sess_ops->FirstBurstLength);
+                       return DATAOUT_CANNOT_RECOVER;
+               }
+               if (first_burst_len == cmd->data_length) {
+                       pr_err("Command ITT: 0x%08x reached"
+                       " ExpXferLen: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol"
+                       " error.\n", cmd->init_task_tag, cmd->data_length);
+                       return DATAOUT_CANNOT_RECOVER;
+               }
+       }
+
+out:
+       return DATAOUT_NORMAL;
+}
+
+static int iscsit_dataout_check_sequence(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       u32 next_burst_len;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_seq *seq = NULL;
+       struct iscsi_data *hdr = (struct iscsi_data *) buf;
+       u32 payload_length = ntoh24(hdr->dlength);
+
+       /*
+        * For DataSequenceInOrder=Yes: Check that the offset and offset+length
+        * is within range as defined by iscsi_set_dataout_sequence_values().
+        *
+        * For DataSequenceInOrder=No: Check that an struct iscsi_seq exists for
+        * offset+length tuple.
+        */
+       if (conn->sess->sess_ops->DataSequenceInOrder) {
+               /*
+                * Due to possibility of recovery DataOUT sent by the initiator
+                * fullfilling an Recovery R2T, it's best to just dump the
+                * payload here, instead of erroring out.
+                */
+               if ((hdr->offset < cmd->seq_start_offset) ||
+                  ((hdr->offset + payload_length) > cmd->seq_end_offset)) {
+                       pr_err("Command ITT: 0x%08x with Offset: %u,"
+                       " Length: %u outside of Sequence %u:%u while"
+                       " DataSequenceInOrder=Yes.\n", cmd->init_task_tag,
+                       hdr->offset, payload_length, cmd->seq_start_offset,
+                               cmd->seq_end_offset);
+
+                       if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
+                               return DATAOUT_CANNOT_RECOVER;
+                       return DATAOUT_WITHIN_COMMAND_RECOVERY;
+               }
+
+               next_burst_len = (cmd->next_burst_len + payload_length);
+       } else {
+               seq = iscsit_get_seq_holder(cmd, hdr->offset, payload_length);
+               if (!seq)
+                       return DATAOUT_CANNOT_RECOVER;
+               /*
+                * Set the struct iscsi_seq pointer to reuse later.
+                */
+               cmd->seq_ptr = seq;
+
+               if (seq->status == DATAOUT_SEQUENCE_COMPLETE) {
+                       if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
+                               return DATAOUT_CANNOT_RECOVER;
+                       return DATAOUT_WITHIN_COMMAND_RECOVERY;
+               }
+
+               next_burst_len = (seq->next_burst_len + payload_length);
+       }
+
+       if (next_burst_len > conn->sess->sess_ops->MaxBurstLength) {
+               pr_err("Command ITT: 0x%08x, NextBurstLength: %u and"
+                       " Length: %u exceeds MaxBurstLength: %u. protocol"
+                       " error.\n", cmd->init_task_tag,
+                       (next_burst_len - payload_length),
+                       payload_length, conn->sess->sess_ops->MaxBurstLength);
+               return DATAOUT_CANNOT_RECOVER;
+       }
+
+       /*
+        * Perform various MaxBurstLength and ISCSI_FLAG_CMD_FINAL sanity
+        * checks for the current DataOUT Sequence.
+        */
+       if (hdr->flags & ISCSI_FLAG_CMD_FINAL) {
+               /*
+                * Ignore ISCSI_FLAG_CMD_FINAL checks while DataPDUInOrder=No, end of
+                * sequence checks are handled in
+                * iscsit_dataout_datapduinorder_no_fbit().
+                */
+               if (!conn->sess->sess_ops->DataPDUInOrder)
+                       goto out;
+
+               if (conn->sess->sess_ops->DataSequenceInOrder) {
+                       if ((next_burst_len <
+                            conn->sess->sess_ops->MaxBurstLength) &&
+                          ((cmd->write_data_done + payload_length) <
+                            cmd->data_length)) {
+                               pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL"
+                               " before end of DataOUT sequence, protocol"
+                               " error.\n", cmd->init_task_tag);
+                               return DATAOUT_CANNOT_RECOVER;
+                       }
+               } else {
+                       if (next_burst_len < seq->xfer_len) {
+                               pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL"
+                               " before end of DataOUT sequence, protocol"
+                               " error.\n", cmd->init_task_tag);
+                               return DATAOUT_CANNOT_RECOVER;
+                       }
+               }
+       } else {
+               if (conn->sess->sess_ops->DataSequenceInOrder) {
+                       if (next_burst_len ==
+                                       conn->sess->sess_ops->MaxBurstLength) {
+                               pr_err("Command ITT: 0x%08x reached"
+                               " MaxBurstLength: %u, but ISCSI_FLAG_CMD_FINAL is"
+                               " not set, protocol error.", cmd->init_task_tag,
+                                       conn->sess->sess_ops->MaxBurstLength);
+                               return DATAOUT_CANNOT_RECOVER;
+                       }
+                       if ((cmd->write_data_done + payload_length) ==
+                                       cmd->data_length) {
+                               pr_err("Command ITT: 0x%08x reached"
+                               " last DataOUT PDU in sequence but ISCSI_FLAG_"
+                               "CMD_FINAL is not set, protocol error.\n",
+                                       cmd->init_task_tag);
+                               return DATAOUT_CANNOT_RECOVER;
+                       }
+               } else {
+                       if (next_burst_len == seq->xfer_len) {
+                               pr_err("Command ITT: 0x%08x reached"
+                               " last DataOUT PDU in sequence but ISCSI_FLAG_"
+                               "CMD_FINAL is not set, protocol error.\n",
+                                       cmd->init_task_tag);
+                               return DATAOUT_CANNOT_RECOVER;
+                       }
+               }
+       }
+
+out:
+       return DATAOUT_NORMAL;
+}
+
+static int iscsit_dataout_check_datasn(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       int dump = 0, recovery = 0;
+       u32 data_sn = 0;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_data *hdr = (struct iscsi_data *) buf;
+       u32 payload_length = ntoh24(hdr->dlength);
+
+       /*
+        * Considering the target has no method of re-requesting DataOUT
+        * by DataSN, if we receieve a greater DataSN than expected we
+        * assume the functions for DataPDUInOrder=[Yes,No] below will
+        * handle it.
+        *
+        * If the DataSN is less than expected, dump the payload.
+        */
+       if (conn->sess->sess_ops->DataSequenceInOrder)
+               data_sn = cmd->data_sn;
+       else {
+               struct iscsi_seq *seq = cmd->seq_ptr;
+               data_sn = seq->data_sn;
+       }
+
+       if (hdr->datasn > data_sn) {
+               pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"
+                       " higher than expected 0x%08x.\n", cmd->init_task_tag,
+                               hdr->datasn, data_sn);
+               recovery = 1;
+               goto recover;
+       } else if (hdr->datasn < data_sn) {
+               pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x"
+                       " lower than expected 0x%08x, discarding payload.\n",
+                       cmd->init_task_tag, hdr->datasn, data_sn);
+               dump = 1;
+               goto dump;
+       }
+
+       return DATAOUT_NORMAL;
+
+recover:
+       if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+               pr_err("Unable to perform within-command recovery"
+                               " while ERL=0.\n");
+               return DATAOUT_CANNOT_RECOVER;
+       }
+dump:
+       if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
+               return DATAOUT_CANNOT_RECOVER;
+
+       return (recovery || dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY :
+                               DATAOUT_NORMAL;
+}
+
+static int iscsit_dataout_pre_datapduinorder_yes(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       int dump = 0, recovery = 0;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_data *hdr = (struct iscsi_data *) buf;
+       u32 payload_length = ntoh24(hdr->dlength);
+
+       /*
+        * For DataSequenceInOrder=Yes: If the offset is greater than the global
+        * DataPDUInOrder=Yes offset counter in struct iscsi_cmd a protcol error has
+        * occured and fail the connection.
+        *
+        * For DataSequenceInOrder=No: If the offset is greater than the per
+        * sequence DataPDUInOrder=Yes offset counter in struct iscsi_seq a protocol
+        * error has occured and fail the connection.
+        */
+       if (conn->sess->sess_ops->DataSequenceInOrder) {
+               if (hdr->offset != cmd->write_data_done) {
+                       pr_err("Command ITT: 0x%08x, received offset"
+                       " %u different than expected %u.\n", cmd->init_task_tag,
+                               hdr->offset, cmd->write_data_done);
+                       recovery = 1;
+                       goto recover;
+               }
+       } else {
+               struct iscsi_seq *seq = cmd->seq_ptr;
+
+               if (hdr->offset > seq->offset) {
+                       pr_err("Command ITT: 0x%08x, received offset"
+                       " %u greater than expected %u.\n", cmd->init_task_tag,
+                               hdr->offset, seq->offset);
+                       recovery = 1;
+                       goto recover;
+               } else if (hdr->offset < seq->offset) {
+                       pr_err("Command ITT: 0x%08x, received offset"
+                       " %u less than expected %u, discarding payload.\n",
+                               cmd->init_task_tag, hdr->offset, seq->offset);
+                       dump = 1;
+                       goto dump;
+               }
+       }
+
+       return DATAOUT_NORMAL;
+
+recover:
+       if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+               pr_err("Unable to perform within-command recovery"
+                               " while ERL=0.\n");
+               return DATAOUT_CANNOT_RECOVER;
+       }
+dump:
+       if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
+               return DATAOUT_CANNOT_RECOVER;
+
+       return (recovery) ? iscsit_recover_dataout_sequence(cmd,
+               hdr->offset, payload_length) :
+              (dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY : DATAOUT_NORMAL;
+}
+
+static int iscsit_dataout_pre_datapduinorder_no(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       struct iscsi_pdu *pdu;
+       struct iscsi_data *hdr = (struct iscsi_data *) buf;
+       u32 payload_length = ntoh24(hdr->dlength);
+
+       pdu = iscsit_get_pdu_holder(cmd, hdr->offset, payload_length);
+       if (!pdu)
+               return DATAOUT_CANNOT_RECOVER;
+
+       cmd->pdu_ptr = pdu;
+
+       switch (pdu->status) {
+       case ISCSI_PDU_NOT_RECEIVED:
+       case ISCSI_PDU_CRC_FAILED:
+       case ISCSI_PDU_TIMED_OUT:
+               break;
+       case ISCSI_PDU_RECEIVED_OK:
+               pr_err("Command ITT: 0x%08x received already gotten"
+                       " Offset: %u, Length: %u\n", cmd->init_task_tag,
+                               hdr->offset, payload_length);
+               return iscsit_dump_data_payload(cmd->conn, payload_length, 1);
+       default:
+               return DATAOUT_CANNOT_RECOVER;
+       }
+
+       return DATAOUT_NORMAL;
+}
+
+static int iscsit_dataout_update_r2t(struct iscsi_cmd *cmd, u32 offset, u32 length)
+{
+       struct iscsi_r2t *r2t;
+
+       if (cmd->unsolicited_data)
+               return 0;
+
+       r2t = iscsit_get_r2t_for_eos(cmd, offset, length);
+       if (!r2t)
+               return -1;
+
+       spin_lock_bh(&cmd->r2t_lock);
+       r2t->seq_complete = 1;
+       cmd->outstanding_r2ts--;
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       return 0;
+}
+
+static int iscsit_dataout_update_datapduinorder_no(
+       struct iscsi_cmd *cmd,
+       u32 data_sn,
+       int f_bit)
+{
+       int ret = 0;
+       struct iscsi_pdu *pdu = cmd->pdu_ptr;
+
+       pdu->data_sn = data_sn;
+
+       switch (pdu->status) {
+       case ISCSI_PDU_NOT_RECEIVED:
+               pdu->status = ISCSI_PDU_RECEIVED_OK;
+               break;
+       case ISCSI_PDU_CRC_FAILED:
+               pdu->status = ISCSI_PDU_RECEIVED_OK;
+               break;
+       case ISCSI_PDU_TIMED_OUT:
+               pdu->status = ISCSI_PDU_RECEIVED_OK;
+               break;
+       default:
+               return DATAOUT_CANNOT_RECOVER;
+       }
+
+       if (f_bit) {
+               ret = iscsit_dataout_datapduinorder_no_fbit(cmd, pdu);
+               if (ret == DATAOUT_CANNOT_RECOVER)
+                       return ret;
+       }
+
+       return DATAOUT_NORMAL;
+}
+
+static int iscsit_dataout_post_crc_passed(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       int ret, send_r2t = 0;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_seq *seq = NULL;
+       struct iscsi_data *hdr = (struct iscsi_data *) buf;
+       u32 payload_length = ntoh24(hdr->dlength);
+
+       if (cmd->unsolicited_data) {
+               if ((cmd->first_burst_len + payload_length) ==
+                    conn->sess->sess_ops->FirstBurstLength) {
+                       if (iscsit_dataout_update_r2t(cmd, hdr->offset,
+                                       payload_length) < 0)
+                               return DATAOUT_CANNOT_RECOVER;
+                       send_r2t = 1;
+               }
+
+               if (!conn->sess->sess_ops->DataPDUInOrder) {
+                       ret = iscsit_dataout_update_datapduinorder_no(cmd,
+                               hdr->datasn, (hdr->flags & ISCSI_FLAG_CMD_FINAL));
+                       if (ret == DATAOUT_CANNOT_RECOVER)
+                               return ret;
+               }
+
+               cmd->first_burst_len += payload_length;
+
+               if (conn->sess->sess_ops->DataSequenceInOrder)
+                       cmd->data_sn++;
+               else {
+                       seq = cmd->seq_ptr;
+                       seq->data_sn++;
+                       seq->offset += payload_length;
+               }
+
+               if (send_r2t) {
+                       if (seq)
+                               seq->status = DATAOUT_SEQUENCE_COMPLETE;
+                       cmd->first_burst_len = 0;
+                       cmd->unsolicited_data = 0;
+               }
+       } else {
+               if (conn->sess->sess_ops->DataSequenceInOrder) {
+                       if ((cmd->next_burst_len + payload_length) ==
+                            conn->sess->sess_ops->MaxBurstLength) {
+                               if (iscsit_dataout_update_r2t(cmd, hdr->offset,
+                                               payload_length) < 0)
+                                       return DATAOUT_CANNOT_RECOVER;
+                               send_r2t = 1;
+                       }
+
+                       if (!conn->sess->sess_ops->DataPDUInOrder) {
+                               ret = iscsit_dataout_update_datapduinorder_no(
+                                               cmd, hdr->datasn,
+                                               (hdr->flags & ISCSI_FLAG_CMD_FINAL));
+                               if (ret == DATAOUT_CANNOT_RECOVER)
+                                       return ret;
+                       }
+
+                       cmd->next_burst_len += payload_length;
+                       cmd->data_sn++;
+
+                       if (send_r2t)
+                               cmd->next_burst_len = 0;
+               } else {
+                       seq = cmd->seq_ptr;
+
+                       if ((seq->next_burst_len + payload_length) ==
+                            seq->xfer_len) {
+                               if (iscsit_dataout_update_r2t(cmd, hdr->offset,
+                                               payload_length) < 0)
+                                       return DATAOUT_CANNOT_RECOVER;
+                               send_r2t = 1;
+                       }
+
+                       if (!conn->sess->sess_ops->DataPDUInOrder) {
+                               ret = iscsit_dataout_update_datapduinorder_no(
+                                               cmd, hdr->datasn,
+                                               (hdr->flags & ISCSI_FLAG_CMD_FINAL));
+                               if (ret == DATAOUT_CANNOT_RECOVER)
+                                       return ret;
+                       }
+
+                       seq->data_sn++;
+                       seq->offset += payload_length;
+                       seq->next_burst_len += payload_length;
+
+                       if (send_r2t) {
+                               seq->next_burst_len = 0;
+                               seq->status = DATAOUT_SEQUENCE_COMPLETE;
+                       }
+               }
+       }
+
+       if (send_r2t && conn->sess->sess_ops->DataSequenceInOrder)
+               cmd->data_sn = 0;
+
+       cmd->write_data_done += payload_length;
+
+       return (cmd->write_data_done == cmd->data_length) ?
+               DATAOUT_SEND_TO_TRANSPORT : (send_r2t) ?
+               DATAOUT_SEND_R2T : DATAOUT_NORMAL;
+}
+
+static int iscsit_dataout_post_crc_failed(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_pdu *pdu;
+       struct iscsi_data *hdr = (struct iscsi_data *) buf;
+       u32 payload_length = ntoh24(hdr->dlength);
+
+       if (conn->sess->sess_ops->DataPDUInOrder)
+               goto recover;
+       /*
+        * The rest of this function is only called when DataPDUInOrder=No.
+        */
+       pdu = cmd->pdu_ptr;
+
+       switch (pdu->status) {
+       case ISCSI_PDU_NOT_RECEIVED:
+               pdu->status = ISCSI_PDU_CRC_FAILED;
+               break;
+       case ISCSI_PDU_CRC_FAILED:
+               break;
+       case ISCSI_PDU_TIMED_OUT:
+               pdu->status = ISCSI_PDU_CRC_FAILED;
+               break;
+       default:
+               return DATAOUT_CANNOT_RECOVER;
+       }
+
+recover:
+       return iscsit_recover_dataout_sequence(cmd, hdr->offset, payload_length);
+}
+
+/*
+ *     Called from iscsit_handle_data_out() before DataOUT Payload is received
+ *     and CRC computed.
+ */
+extern int iscsit_check_pre_dataout(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       int ret;
+       struct iscsi_conn *conn = cmd->conn;
+
+       ret = iscsit_dataout_within_command_recovery_check(cmd, buf);
+       if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||
+           (ret == DATAOUT_CANNOT_RECOVER))
+               return ret;
+
+       ret = iscsit_dataout_check_datasn(cmd, buf);
+       if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||
+           (ret == DATAOUT_CANNOT_RECOVER))
+               return ret;
+
+       if (cmd->unsolicited_data) {
+               ret = iscsit_dataout_check_unsolicited_sequence(cmd, buf);
+               if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||
+                   (ret == DATAOUT_CANNOT_RECOVER))
+                       return ret;
+       } else {
+               ret = iscsit_dataout_check_sequence(cmd, buf);
+               if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) ||
+                   (ret == DATAOUT_CANNOT_RECOVER))
+                       return ret;
+       }
+
+       return (conn->sess->sess_ops->DataPDUInOrder) ?
+               iscsit_dataout_pre_datapduinorder_yes(cmd, buf) :
+               iscsit_dataout_pre_datapduinorder_no(cmd, buf);
+}
+
+/*
+ *     Called from iscsit_handle_data_out() after DataOUT Payload is received
+ *     and CRC computed.
+ */
+int iscsit_check_post_dataout(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf,
+       u8 data_crc_failed)
+{
+       struct iscsi_conn *conn = cmd->conn;
+
+       cmd->dataout_timeout_retries = 0;
+
+       if (!data_crc_failed)
+               return iscsit_dataout_post_crc_passed(cmd, buf);
+       else {
+               if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+                       pr_err("Unable to recover from DataOUT CRC"
+                               " failure while ERL=0, closing session.\n");
+                       iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
+                                       1, 0, buf, cmd);
+                       return DATAOUT_CANNOT_RECOVER;
+               }
+
+               iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
+                               0, 0, buf, cmd);
+               return iscsit_dataout_post_crc_failed(cmd, buf);
+       }
+}
+
+static void iscsit_handle_time2retain_timeout(unsigned long data)
+{
+       struct iscsi_session *sess = (struct iscsi_session *) data;
+       struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess);
+       struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
+
+       spin_lock_bh(&se_tpg->session_lock);
+       if (sess->time2retain_timer_flags & ISCSI_TF_STOP) {
+               spin_unlock_bh(&se_tpg->session_lock);
+               return;
+       }
+       if (atomic_read(&sess->session_reinstatement)) {
+               pr_err("Exiting Time2Retain handler because"
+                               " session_reinstatement=1\n");
+               spin_unlock_bh(&se_tpg->session_lock);
+               return;
+       }
+       sess->time2retain_timer_flags |= ISCSI_TF_EXPIRED;
+
+       pr_err("Time2Retain timer expired for SID: %u, cleaning up"
+                       " iSCSI session.\n", sess->sid);
+       {
+       struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
+
+       if (tiqn) {
+               spin_lock(&tiqn->sess_err_stats.lock);
+               strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name,
+                       (void *)sess->sess_ops->InitiatorName);
+               tiqn->sess_err_stats.last_sess_failure_type =
+                               ISCSI_SESS_ERR_CXN_TIMEOUT;
+               tiqn->sess_err_stats.cxn_timeout_errors++;
+               sess->conn_timeout_errors++;
+               spin_unlock(&tiqn->sess_err_stats.lock);
+       }
+       }
+
+       spin_unlock_bh(&se_tpg->session_lock);
+       iscsit_close_session(sess);
+}
+
+extern void iscsit_start_time2retain_handler(struct iscsi_session *sess)
+{
+       int tpg_active;
+       /*
+        * Only start Time2Retain timer when the assoicated TPG is still in
+        * an ACTIVE (eg: not disabled or shutdown) state.
+        */
+       spin_lock(&ISCSI_TPG_S(sess)->tpg_state_lock);
+       tpg_active = (ISCSI_TPG_S(sess)->tpg_state == TPG_STATE_ACTIVE);
+       spin_unlock(&ISCSI_TPG_S(sess)->tpg_state_lock);
+
+       if (!tpg_active)
+               return;
+
+       if (sess->time2retain_timer_flags & ISCSI_TF_RUNNING)
+               return;
+
+       pr_debug("Starting Time2Retain timer for %u seconds on"
+               " SID: %u\n", sess->sess_ops->DefaultTime2Retain, sess->sid);
+
+       init_timer(&sess->time2retain_timer);
+       sess->time2retain_timer.expires =
+               (get_jiffies_64() + sess->sess_ops->DefaultTime2Retain * HZ);
+       sess->time2retain_timer.data = (unsigned long)sess;
+       sess->time2retain_timer.function = iscsit_handle_time2retain_timeout;
+       sess->time2retain_timer_flags &= ~ISCSI_TF_STOP;
+       sess->time2retain_timer_flags |= ISCSI_TF_RUNNING;
+       add_timer(&sess->time2retain_timer);
+}
+
+/*
+ *     Called with spin_lock_bh(&struct se_portal_group->session_lock) held
+ */
+extern int iscsit_stop_time2retain_timer(struct iscsi_session *sess)
+{
+       struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess);
+       struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
+
+       if (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)
+               return -1;
+
+       if (!(sess->time2retain_timer_flags & ISCSI_TF_RUNNING))
+               return 0;
+
+       sess->time2retain_timer_flags |= ISCSI_TF_STOP;
+       spin_unlock_bh(&se_tpg->session_lock);
+
+       del_timer_sync(&sess->time2retain_timer);
+
+       spin_lock_bh(&se_tpg->session_lock);
+       sess->time2retain_timer_flags &= ~ISCSI_TF_RUNNING;
+       pr_debug("Stopped Time2Retain Timer for SID: %u\n",
+                       sess->sid);
+       return 0;
+}
+
+void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *conn)
+{
+       spin_lock_bh(&conn->state_lock);
+       if (atomic_read(&conn->connection_exit)) {
+               spin_unlock_bh(&conn->state_lock);
+               goto sleep;
+       }
+
+       if (atomic_read(&conn->transport_failed)) {
+               spin_unlock_bh(&conn->state_lock);
+               goto sleep;
+       }
+       spin_unlock_bh(&conn->state_lock);
+
+       iscsi_thread_set_force_reinstatement(conn);
+
+sleep:
+       wait_for_completion(&conn->conn_wait_rcfr_comp);
+       complete(&conn->conn_post_wait_comp);
+}
+
+void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep)
+{
+       spin_lock_bh(&conn->state_lock);
+       if (atomic_read(&conn->connection_exit)) {
+               spin_unlock_bh(&conn->state_lock);
+               return;
+       }
+
+       if (atomic_read(&conn->transport_failed)) {
+               spin_unlock_bh(&conn->state_lock);
+               return;
+       }
+
+       if (atomic_read(&conn->connection_reinstatement)) {
+               spin_unlock_bh(&conn->state_lock);
+               return;
+       }
+
+       if (iscsi_thread_set_force_reinstatement(conn) < 0) {
+               spin_unlock_bh(&conn->state_lock);
+               return;
+       }
+
+       atomic_set(&conn->connection_reinstatement, 1);
+       if (!sleep) {
+               spin_unlock_bh(&conn->state_lock);
+               return;
+       }
+
+       atomic_set(&conn->sleep_on_conn_wait_comp, 1);
+       spin_unlock_bh(&conn->state_lock);
+
+       wait_for_completion(&conn->conn_wait_comp);
+       complete(&conn->conn_post_wait_comp);
+}
+
+void iscsit_fall_back_to_erl0(struct iscsi_session *sess)
+{
+       pr_debug("Falling back to ErrorRecoveryLevel=0 for SID:"
+                       " %u\n", sess->sid);
+
+       atomic_set(&sess->session_fall_back_to_erl0, 1);
+}
+
+static void iscsit_handle_connection_cleanup(struct iscsi_conn *conn)
+{
+       struct iscsi_session *sess = conn->sess;
+
+       if ((sess->sess_ops->ErrorRecoveryLevel == 2) &&
+           !atomic_read(&sess->session_reinstatement) &&
+           !atomic_read(&sess->session_fall_back_to_erl0))
+               iscsit_connection_recovery_transport_reset(conn);
+       else {
+               pr_debug("Performing cleanup for failed iSCSI"
+                       " Connection ID: %hu from %s\n", conn->cid,
+                       sess->sess_ops->InitiatorName);
+               iscsit_close_connection(conn);
+       }
+}
+
+extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
+{
+       spin_lock_bh(&conn->state_lock);
+       if (atomic_read(&conn->connection_exit)) {
+               spin_unlock_bh(&conn->state_lock);
+               return;
+       }
+       atomic_set(&conn->connection_exit, 1);
+
+       if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
+               spin_unlock_bh(&conn->state_lock);
+               iscsit_close_connection(conn);
+               return;
+       }
+
+       if (conn->conn_state == TARG_CONN_STATE_CLEANUP_WAIT) {
+               spin_unlock_bh(&conn->state_lock);
+               return;
+       }
+
+       pr_debug("Moving to TARG_CONN_STATE_CLEANUP_WAIT.\n");
+       conn->conn_state = TARG_CONN_STATE_CLEANUP_WAIT;
+       spin_unlock_bh(&conn->state_lock);
+
+       iscsit_handle_connection_cleanup(conn);
+}
+
+/*
+ *     This is the simple function that makes the magic of
+ *     sync and steering happen in the follow paradoxical order:
+ *
+ *     0) Receive conn->of_marker (bytes left until next OFMarker)
+ *        bytes into an offload buffer.  When we pass the exact number
+ *        of bytes in conn->of_marker, iscsit_dump_data_payload() and hence
+ *        rx_data() will automatically receive the identical u32 marker
+ *        values and store it in conn->of_marker_offset;
+ *     1) Now conn->of_marker_offset will contain the offset to the start
+ *        of the next iSCSI PDU.  Dump these remaining bytes into another
+ *        offload buffer.
+ *     2) We are done!
+ *        Next byte in the TCP stream will contain the next iSCSI PDU!
+ *        Cool Huh?!
+ */
+int iscsit_recover_from_unknown_opcode(struct iscsi_conn *conn)
+{
+       /*
+        * Make sure the remaining bytes to next maker is a sane value.
+        */
+       if (conn->of_marker > (conn->conn_ops->OFMarkInt * 4)) {
+               pr_err("Remaining bytes to OFMarker: %u exceeds"
+                       " OFMarkInt bytes: %u.\n", conn->of_marker,
+                               conn->conn_ops->OFMarkInt * 4);
+               return -1;
+       }
+
+       pr_debug("Advancing %u bytes in TCP stream to get to the"
+                       " next OFMarker.\n", conn->of_marker);
+
+       if (iscsit_dump_data_payload(conn, conn->of_marker, 0) < 0)
+               return -1;
+
+       /*
+        * Make sure the offset marker we retrived is a valid value.
+        */
+       if (conn->of_marker_offset > (ISCSI_HDR_LEN + (ISCSI_CRC_LEN * 2) +
+           conn->conn_ops->MaxRecvDataSegmentLength)) {
+               pr_err("OfMarker offset value: %u exceeds limit.\n",
+                       conn->of_marker_offset);
+               return -1;
+       }
+
+       pr_debug("Discarding %u bytes of TCP stream to get to the"
+                       " next iSCSI Opcode.\n", conn->of_marker_offset);
+
+       if (iscsit_dump_data_payload(conn, conn->of_marker_offset, 0) < 0)
+               return -1;
+
+       return 0;
+}
diff --git a/drivers/target/iscsi/iscsi_target_erl0.h b/drivers/target/iscsi/iscsi_target_erl0.h
new file mode 100644 (file)
index 0000000..21acc9a
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef ISCSI_TARGET_ERL0_H
+#define ISCSI_TARGET_ERL0_H
+
+extern void iscsit_set_dataout_sequence_values(struct iscsi_cmd *);
+extern int iscsit_check_pre_dataout(struct iscsi_cmd *, unsigned char *);
+extern int iscsit_check_post_dataout(struct iscsi_cmd *, unsigned char *, u8);
+extern void iscsit_start_time2retain_handler(struct iscsi_session *);
+extern int iscsit_stop_time2retain_timer(struct iscsi_session *);
+extern void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *);
+extern void iscsit_cause_connection_reinstatement(struct iscsi_conn *, int);
+extern void iscsit_fall_back_to_erl0(struct iscsi_session *);
+extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *);
+extern int iscsit_recover_from_unknown_opcode(struct iscsi_conn *);
+
+#endif   /*** ISCSI_TARGET_ERL0_H ***/
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
new file mode 100644 (file)
index 0000000..9806507
--- /dev/null
@@ -0,0 +1,1299 @@
+/*******************************************************************************
+ * This file contains error recovery level one used by the iSCSI Target driver.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <linux/list.h>
+#include <scsi/iscsi_proto.h>
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_seq_pdu_list.h"
+#include "iscsi_target_datain_values.h"
+#include "iscsi_target_device.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target_erl0.h"
+#include "iscsi_target_erl1.h"
+#include "iscsi_target_erl2.h"
+#include "iscsi_target.h"
+
+#define OFFLOAD_BUF_SIZE       32768
+
+/*
+ *     Used to dump excess datain payload for certain error recovery
+ *     situations.  Receive in OFFLOAD_BUF_SIZE max of datain per rx_data().
+ *
+ *     dump_padding_digest denotes if padding and data digests need
+ *     to be dumped.
+ */
+int iscsit_dump_data_payload(
+       struct iscsi_conn *conn,
+       u32 buf_len,
+       int dump_padding_digest)
+{
+       char *buf, pad_bytes[4];
+       int ret = DATAOUT_WITHIN_COMMAND_RECOVERY, rx_got;
+       u32 length, padding, offset = 0, size;
+       struct kvec iov;
+
+       length = (buf_len > OFFLOAD_BUF_SIZE) ? OFFLOAD_BUF_SIZE : buf_len;
+
+       buf = kzalloc(length, GFP_ATOMIC);
+       if (!buf) {
+               pr_err("Unable to allocate %u bytes for offload"
+                               " buffer.\n", length);
+               return -1;
+       }
+       memset(&iov, 0, sizeof(struct kvec));
+
+       while (offset < buf_len) {
+               size = ((offset + length) > buf_len) ?
+                       (buf_len - offset) : length;
+
+               iov.iov_len = size;
+               iov.iov_base = buf;
+
+               rx_got = rx_data(conn, &iov, 1, size);
+               if (rx_got != size) {
+                       ret = DATAOUT_CANNOT_RECOVER;
+                       goto out;
+               }
+
+               offset += size;
+       }
+
+       if (!dump_padding_digest)
+               goto out;
+
+       padding = ((-buf_len) & 3);
+       if (padding != 0) {
+               iov.iov_len = padding;
+               iov.iov_base = pad_bytes;
+
+               rx_got = rx_data(conn, &iov, 1, padding);
+               if (rx_got != padding) {
+                       ret = DATAOUT_CANNOT_RECOVER;
+                       goto out;
+               }
+       }
+
+       if (conn->conn_ops->DataDigest) {
+               u32 data_crc;
+
+               iov.iov_len = ISCSI_CRC_LEN;
+               iov.iov_base = &data_crc;
+
+               rx_got = rx_data(conn, &iov, 1, ISCSI_CRC_LEN);
+               if (rx_got != ISCSI_CRC_LEN) {
+                       ret = DATAOUT_CANNOT_RECOVER;
+                       goto out;
+               }
+       }
+
+out:
+       kfree(buf);
+       return ret;
+}
+
+/*
+ *     Used for retransmitting R2Ts from a R2T SNACK request.
+ */
+static int iscsit_send_recovery_r2t_for_snack(
+       struct iscsi_cmd *cmd,
+       struct iscsi_r2t *r2t)
+{
+       /*
+        * If the struct iscsi_r2t has not been sent yet, we can safely
+        * ignore retransmission
+        * of the R2TSN in question.
+        */
+       spin_lock_bh(&cmd->r2t_lock);
+       if (!r2t->sent_r2t) {
+               spin_unlock_bh(&cmd->r2t_lock);
+               return 0;
+       }
+       r2t->sent_r2t = 0;
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, ISTATE_SEND_R2T);
+
+       return 0;
+}
+
+static int iscsit_handle_r2t_snack(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf,
+       u32 begrun,
+       u32 runlength)
+{
+       u32 last_r2tsn;
+       struct iscsi_r2t *r2t;
+
+       /*
+        * Make sure the initiator is not requesting retransmission
+        * of R2TSNs already acknowledged by a TMR TASK_REASSIGN.
+        */
+       if ((cmd->cmd_flags & ICF_GOT_DATACK_SNACK) &&
+           (begrun <= cmd->acked_data_sn)) {
+               pr_err("ITT: 0x%08x, R2T SNACK requesting"
+                       " retransmission of R2TSN: 0x%08x to 0x%08x but already"
+                       " acked to  R2TSN: 0x%08x by TMR TASK_REASSIGN,"
+                       " protocol error.\n", cmd->init_task_tag, begrun,
+                       (begrun + runlength), cmd->acked_data_sn);
+
+                       return iscsit_add_reject_from_cmd(
+                                       ISCSI_REASON_PROTOCOL_ERROR,
+                                       1, 0, buf, cmd);
+       }
+
+       if (runlength) {
+               if ((begrun + runlength) > cmd->r2t_sn) {
+                       pr_err("Command ITT: 0x%08x received R2T SNACK"
+                       " with BegRun: 0x%08x, RunLength: 0x%08x, exceeds"
+                       " current R2TSN: 0x%08x, protocol error.\n",
+                       cmd->init_task_tag, begrun, runlength, cmd->r2t_sn);
+                       return iscsit_add_reject_from_cmd(
+                               ISCSI_REASON_BOOKMARK_INVALID, 1, 0, buf, cmd);
+               }
+               last_r2tsn = (begrun + runlength);
+       } else
+               last_r2tsn = cmd->r2t_sn;
+
+       while (begrun < last_r2tsn) {
+               r2t = iscsit_get_holder_for_r2tsn(cmd, begrun);
+               if (!r2t)
+                       return -1;
+               if (iscsit_send_recovery_r2t_for_snack(cmd, r2t) < 0)
+                       return -1;
+
+               begrun++;
+       }
+
+       return 0;
+}
+
+/*
+ *     Generates Offsets and NextBurstLength based on Begrun and Runlength
+ *     carried in a Data SNACK or ExpDataSN in TMR TASK_REASSIGN.
+ *
+ *     For DataSequenceInOrder=Yes and DataPDUInOrder=[Yes,No] only.
+ *
+ *     FIXME: How is this handled for a RData SNACK?
+ */
+int iscsit_create_recovery_datain_values_datasequenceinorder_yes(
+       struct iscsi_cmd *cmd,
+       struct iscsi_datain_req *dr)
+{
+       u32 data_sn = 0, data_sn_count = 0;
+       u32 pdu_start = 0, seq_no = 0;
+       u32 begrun = dr->begrun;
+       struct iscsi_conn *conn = cmd->conn;
+
+       while (begrun > data_sn++) {
+               data_sn_count++;
+               if ((dr->next_burst_len +
+                    conn->conn_ops->MaxRecvDataSegmentLength) <
+                    conn->sess->sess_ops->MaxBurstLength) {
+                       dr->read_data_done +=
+                               conn->conn_ops->MaxRecvDataSegmentLength;
+                       dr->next_burst_len +=
+                               conn->conn_ops->MaxRecvDataSegmentLength;
+               } else {
+                       dr->read_data_done +=
+                               (conn->sess->sess_ops->MaxBurstLength -
+                                dr->next_burst_len);
+                       dr->next_burst_len = 0;
+                       pdu_start += data_sn_count;
+                       data_sn_count = 0;
+                       seq_no++;
+               }
+       }
+
+       if (!conn->sess->sess_ops->DataPDUInOrder) {
+               cmd->seq_no = seq_no;
+               cmd->pdu_start = pdu_start;
+               cmd->pdu_send_order = data_sn_count;
+       }
+
+       return 0;
+}
+
+/*
+ *     Generates Offsets and NextBurstLength based on Begrun and Runlength
+ *     carried in a Data SNACK or ExpDataSN in TMR TASK_REASSIGN.
+ *
+ *     For DataSequenceInOrder=No and DataPDUInOrder=[Yes,No] only.
+ *
+ *     FIXME: How is this handled for a RData SNACK?
+ */
+int iscsit_create_recovery_datain_values_datasequenceinorder_no(
+       struct iscsi_cmd *cmd,
+       struct iscsi_datain_req *dr)
+{
+       int found_seq = 0, i;
+       u32 data_sn, read_data_done = 0, seq_send_order = 0;
+       u32 begrun = dr->begrun;
+       u32 runlength = dr->runlength;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_seq *first_seq = NULL, *seq = NULL;
+
+       if (!cmd->seq_list) {
+               pr_err("struct iscsi_cmd->seq_list is NULL!\n");
+               return -1;
+       }
+
+       /*
+        * Calculate read_data_done for all sequences containing a
+        * first_datasn and last_datasn less than the BegRun.
+        *
+        * Locate the struct iscsi_seq the BegRun lies within and calculate
+        * NextBurstLenghth up to the DataSN based on MaxRecvDataSegmentLength.
+        *
+        * Also use struct iscsi_seq->seq_send_order to determine where to start.
+        */
+       for (i = 0; i < cmd->seq_count; i++) {
+               seq = &cmd->seq_list[i];
+
+               if (!seq->seq_send_order)
+                       first_seq = seq;
+
+               /*
+                * No data has been transferred for this DataIN sequence, so the
+                * seq->first_datasn and seq->last_datasn have not been set.
+                */
+               if (!seq->sent) {
+#if 0
+                       pr_err("Ignoring non-sent sequence 0x%08x ->"
+                               " 0x%08x\n\n", seq->first_datasn,
+                               seq->last_datasn);
+#endif
+                       continue;
+               }
+
+               /*
+                * This DataIN sequence is precedes the received BegRun, add the
+                * total xfer_len of the sequence to read_data_done and reset
+                * seq->pdu_send_order.
+                */
+               if ((seq->first_datasn < begrun) &&
+                               (seq->last_datasn < begrun)) {
+#if 0
+                       pr_err("Pre BegRun sequence 0x%08x ->"
+                               " 0x%08x\n", seq->first_datasn,
+                               seq->last_datasn);
+#endif
+                       read_data_done += cmd->seq_list[i].xfer_len;
+                       seq->next_burst_len = seq->pdu_send_order = 0;
+                       continue;
+               }
+
+               /*
+                * The BegRun lies within this DataIN sequence.
+                */
+               if ((seq->first_datasn <= begrun) &&
+                               (seq->last_datasn >= begrun)) {
+#if 0
+                       pr_err("Found sequence begrun: 0x%08x in"
+                               " 0x%08x -> 0x%08x\n", begrun,
+                               seq->first_datasn, seq->last_datasn);
+#endif
+                       seq_send_order = seq->seq_send_order;
+                       data_sn = seq->first_datasn;
+                       seq->next_burst_len = seq->pdu_send_order = 0;
+                       found_seq = 1;
+
+                       /*
+                        * For DataPDUInOrder=Yes, while the first DataSN of
+                        * the sequence is less than the received BegRun, add
+                        * the MaxRecvDataSegmentLength to read_data_done and
+                        * to the sequence's next_burst_len;
+                        *
+                        * For DataPDUInOrder=No, while the first DataSN of the
+                        * sequence is less than the received BegRun, find the
+                        * struct iscsi_pdu of the DataSN in question and add the
+                        * MaxRecvDataSegmentLength to read_data_done and to the
+                        * sequence's next_burst_len;
+                        */
+                       if (conn->sess->sess_ops->DataPDUInOrder) {
+                               while (data_sn < begrun) {
+                                       seq->pdu_send_order++;
+                                       read_data_done +=
+                                               conn->conn_ops->MaxRecvDataSegmentLength;
+                                       seq->next_burst_len +=
+                                               conn->conn_ops->MaxRecvDataSegmentLength;
+                                       data_sn++;
+                               }
+                       } else {
+                               int j;
+                               struct iscsi_pdu *pdu;
+
+                               while (data_sn < begrun) {
+                                       seq->pdu_send_order++;
+
+                                       for (j = 0; j < seq->pdu_count; j++) {
+                                               pdu = &cmd->pdu_list[
+                                                       seq->pdu_start + j];
+                                               if (pdu->data_sn == data_sn) {
+                                                       read_data_done +=
+                                                               pdu->length;
+                                                       seq->next_burst_len +=
+                                                               pdu->length;
+                                               }
+                                       }
+                                       data_sn++;
+                               }
+                       }
+                       continue;
+               }
+
+               /*
+                * This DataIN sequence is larger than the received BegRun,
+                * reset seq->pdu_send_order and continue.
+                */
+               if ((seq->first_datasn > begrun) ||
+                               (seq->last_datasn > begrun)) {
+#if 0
+                       pr_err("Post BegRun sequence 0x%08x -> 0x%08x\n",
+                                       seq->first_datasn, seq->last_datasn);
+#endif
+                       seq->next_burst_len = seq->pdu_send_order = 0;
+                       continue;
+               }
+       }
+
+       if (!found_seq) {
+               if (!begrun) {
+                       if (!first_seq) {
+                               pr_err("ITT: 0x%08x, Begrun: 0x%08x"
+                                       " but first_seq is NULL\n",
+                                       cmd->init_task_tag, begrun);
+                               return -1;
+                       }
+                       seq_send_order = first_seq->seq_send_order;
+                       seq->next_burst_len = seq->pdu_send_order = 0;
+                       goto done;
+               }
+
+               pr_err("Unable to locate struct iscsi_seq for ITT: 0x%08x,"
+                       " BegRun: 0x%08x, RunLength: 0x%08x while"
+                       " DataSequenceInOrder=No and DataPDUInOrder=%s.\n",
+                               cmd->init_task_tag, begrun, runlength,
+                       (conn->sess->sess_ops->DataPDUInOrder) ? "Yes" : "No");
+               return -1;
+       }
+
+done:
+       dr->read_data_done = read_data_done;
+       dr->seq_send_order = seq_send_order;
+
+       return 0;
+}
+
+static int iscsit_handle_recovery_datain(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf,
+       u32 begrun,
+       u32 runlength)
+{
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_datain_req *dr;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+
+       if (!atomic_read(&se_cmd->t_transport_complete)) {
+               pr_err("Ignoring ITT: 0x%08x Data SNACK\n",
+                               cmd->init_task_tag);
+               return 0;
+       }
+
+       /*
+        * Make sure the initiator is not requesting retransmission
+        * of DataSNs already acknowledged by a Data ACK SNACK.
+        */
+       if ((cmd->cmd_flags & ICF_GOT_DATACK_SNACK) &&
+           (begrun <= cmd->acked_data_sn)) {
+               pr_err("ITT: 0x%08x, Data SNACK requesting"
+                       " retransmission of DataSN: 0x%08x to 0x%08x but"
+                       " already acked to DataSN: 0x%08x by Data ACK SNACK,"
+                       " protocol error.\n", cmd->init_task_tag, begrun,
+                       (begrun + runlength), cmd->acked_data_sn);
+
+               return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+                               1, 0, buf, cmd);
+       }
+
+       /*
+        * Make sure BegRun and RunLength in the Data SNACK are sane.
+        * Note: (cmd->data_sn - 1) will carry the maximum DataSN sent.
+        */
+       if ((begrun + runlength) > (cmd->data_sn - 1)) {
+               pr_err("Initiator requesting BegRun: 0x%08x, RunLength"
+                       ": 0x%08x greater than maximum DataSN: 0x%08x.\n",
+                               begrun, runlength, (cmd->data_sn - 1));
+               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+                               1, 0, buf, cmd);
+       }
+
+       dr = iscsit_allocate_datain_req();
+       if (!dr)
+               return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+                               1, 0, buf, cmd);
+
+       dr->data_sn = dr->begrun = begrun;
+       dr->runlength = runlength;
+       dr->generate_recovery_values = 1;
+       dr->recovery = DATAIN_WITHIN_COMMAND_RECOVERY;
+
+       iscsit_attach_datain_req(cmd, dr);
+
+       cmd->i_state = ISTATE_SEND_DATAIN;
+       iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+
+       return 0;
+}
+
+int iscsit_handle_recovery_datain_or_r2t(
+       struct iscsi_conn *conn,
+       unsigned char *buf,
+       u32 init_task_tag,
+       u32 targ_xfer_tag,
+       u32 begrun,
+       u32 runlength)
+{
+       struct iscsi_cmd *cmd;
+
+       cmd = iscsit_find_cmd_from_itt(conn, init_task_tag);
+       if (!cmd)
+               return 0;
+
+       /*
+        * FIXME: This will not work for bidi commands.
+        */
+       switch (cmd->data_direction) {
+       case DMA_TO_DEVICE:
+               return iscsit_handle_r2t_snack(cmd, buf, begrun, runlength);
+       case DMA_FROM_DEVICE:
+               return iscsit_handle_recovery_datain(cmd, buf, begrun,
+                               runlength);
+       default:
+               pr_err("Unknown cmd->data_direction: 0x%02x\n",
+                               cmd->data_direction);
+               return -1;
+       }
+
+       return 0;
+}
+
+/* #warning FIXME: Status SNACK needs to be dependent on OPCODE!!! */
+int iscsit_handle_status_snack(
+       struct iscsi_conn *conn,
+       u32 init_task_tag,
+       u32 targ_xfer_tag,
+       u32 begrun,
+       u32 runlength)
+{
+       struct iscsi_cmd *cmd = NULL;
+       u32 last_statsn;
+       int found_cmd;
+
+       if (conn->exp_statsn > begrun) {
+               pr_err("Got Status SNACK Begrun: 0x%08x, RunLength:"
+                       " 0x%08x but already got ExpStatSN: 0x%08x on CID:"
+                       " %hu.\n", begrun, runlength, conn->exp_statsn,
+                       conn->cid);
+               return 0;
+       }
+
+       last_statsn = (!runlength) ? conn->stat_sn : (begrun + runlength);
+
+       while (begrun < last_statsn) {
+               found_cmd = 0;
+
+               spin_lock_bh(&conn->cmd_lock);
+               list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+                       if (cmd->stat_sn == begrun) {
+                               found_cmd = 1;
+                               break;
+                       }
+               }
+               spin_unlock_bh(&conn->cmd_lock);
+
+               if (!found_cmd) {
+                       pr_err("Unable to find StatSN: 0x%08x for"
+                               " a Status SNACK, assuming this was a"
+                               " protactic SNACK for an untransmitted"
+                               " StatSN, ignoring.\n", begrun);
+                       begrun++;
+                       continue;
+               }
+
+               spin_lock_bh(&cmd->istate_lock);
+               if (cmd->i_state == ISTATE_SEND_DATAIN) {
+                       spin_unlock_bh(&cmd->istate_lock);
+                       pr_err("Ignoring Status SNACK for BegRun:"
+                               " 0x%08x, RunLength: 0x%08x, assuming this was"
+                               " a protactic SNACK for an untransmitted"
+                               " StatSN\n", begrun, runlength);
+                       begrun++;
+                       continue;
+               }
+               spin_unlock_bh(&cmd->istate_lock);
+
+               cmd->i_state = ISTATE_SEND_STATUS_RECOVERY;
+               iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+               begrun++;
+       }
+
+       return 0;
+}
+
+int iscsit_handle_data_ack(
+       struct iscsi_conn *conn,
+       u32 targ_xfer_tag,
+       u32 begrun,
+       u32 runlength)
+{
+       struct iscsi_cmd *cmd = NULL;
+
+       cmd = iscsit_find_cmd_from_ttt(conn, targ_xfer_tag);
+       if (!cmd) {
+               pr_err("Data ACK SNACK for TTT: 0x%08x is"
+                       " invalid.\n", targ_xfer_tag);
+               return -1;
+       }
+
+       if (begrun <= cmd->acked_data_sn) {
+               pr_err("ITT: 0x%08x Data ACK SNACK BegRUN: 0x%08x is"
+                       " less than the already acked DataSN: 0x%08x.\n",
+                       cmd->init_task_tag, begrun, cmd->acked_data_sn);
+               return -1;
+       }
+
+       /*
+        * For Data ACK SNACK, BegRun is the next expected DataSN.
+        * (see iSCSI v19: 10.16.6)
+        */
+       cmd->cmd_flags |= ICF_GOT_DATACK_SNACK;
+       cmd->acked_data_sn = (begrun - 1);
+
+       pr_debug("Received Data ACK SNACK for ITT: 0x%08x,"
+               " updated acked DataSN to 0x%08x.\n",
+                       cmd->init_task_tag, cmd->acked_data_sn);
+
+       return 0;
+}
+
+static int iscsit_send_recovery_r2t(
+       struct iscsi_cmd *cmd,
+       u32 offset,
+       u32 xfer_len)
+{
+       int ret;
+
+       spin_lock_bh(&cmd->r2t_lock);
+       ret = iscsit_add_r2t_to_list(cmd, offset, xfer_len, 1, 0);
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       return ret;
+}
+
+int iscsit_dataout_datapduinorder_no_fbit(
+       struct iscsi_cmd *cmd,
+       struct iscsi_pdu *pdu)
+{
+       int i, send_recovery_r2t = 0, recovery = 0;
+       u32 length = 0, offset = 0, pdu_count = 0, xfer_len = 0;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_pdu *first_pdu = NULL;
+
+       /*
+        * Get an struct iscsi_pdu pointer to the first PDU, and total PDU count
+        * of the DataOUT sequence.
+        */
+       if (conn->sess->sess_ops->DataSequenceInOrder) {
+               for (i = 0; i < cmd->pdu_count; i++) {
+                       if (cmd->pdu_list[i].seq_no == pdu->seq_no) {
+                               if (!first_pdu)
+                                       first_pdu = &cmd->pdu_list[i];
+                                xfer_len += cmd->pdu_list[i].length;
+                                pdu_count++;
+                       } else if (pdu_count)
+                               break;
+               }
+       } else {
+               struct iscsi_seq *seq = cmd->seq_ptr;
+
+               first_pdu = &cmd->pdu_list[seq->pdu_start];
+               pdu_count = seq->pdu_count;
+       }
+
+       if (!first_pdu || !pdu_count)
+               return DATAOUT_CANNOT_RECOVER;
+
+       /*
+        * Loop through the ending DataOUT Sequence checking each struct iscsi_pdu.
+        * The following ugly logic does batching of not received PDUs.
+        */
+       for (i = 0; i < pdu_count; i++) {
+               if (first_pdu[i].status == ISCSI_PDU_RECEIVED_OK) {
+                       if (!send_recovery_r2t)
+                               continue;
+
+                       if (iscsit_send_recovery_r2t(cmd, offset, length) < 0)
+                               return DATAOUT_CANNOT_RECOVER;
+
+                       send_recovery_r2t = length = offset = 0;
+                       continue;
+               }
+               /*
+                * Set recovery = 1 for any missing, CRC failed, or timed
+                * out PDUs to let the DataOUT logic know that this sequence
+                * has not been completed yet.
+                *
+                * Also, only send a Recovery R2T for ISCSI_PDU_NOT_RECEIVED.
+                * We assume if the PDU either failed CRC or timed out
+                * that a Recovery R2T has already been sent.
+                */
+               recovery = 1;
+
+               if (first_pdu[i].status != ISCSI_PDU_NOT_RECEIVED)
+                       continue;
+
+               if (!offset)
+                       offset = first_pdu[i].offset;
+               length += first_pdu[i].length;
+
+               send_recovery_r2t = 1;
+       }
+
+       if (send_recovery_r2t)
+               if (iscsit_send_recovery_r2t(cmd, offset, length) < 0)
+                       return DATAOUT_CANNOT_RECOVER;
+
+       return (!recovery) ? DATAOUT_NORMAL : DATAOUT_WITHIN_COMMAND_RECOVERY;
+}
+
+static int iscsit_recalculate_dataout_values(
+       struct iscsi_cmd *cmd,
+       u32 pdu_offset,
+       u32 pdu_length,
+       u32 *r2t_offset,
+       u32 *r2t_length)
+{
+       int i;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_pdu *pdu = NULL;
+
+       if (conn->sess->sess_ops->DataSequenceInOrder) {
+               cmd->data_sn = 0;
+
+               if (conn->sess->sess_ops->DataPDUInOrder) {
+                       *r2t_offset = cmd->write_data_done;
+                       *r2t_length = (cmd->seq_end_offset -
+                                       cmd->write_data_done);
+                       return 0;
+               }
+
+               *r2t_offset = cmd->seq_start_offset;
+               *r2t_length = (cmd->seq_end_offset - cmd->seq_start_offset);
+
+               for (i = 0; i < cmd->pdu_count; i++) {
+                       pdu = &cmd->pdu_list[i];
+
+                       if (pdu->status != ISCSI_PDU_RECEIVED_OK)
+                               continue;
+
+                       if ((pdu->offset >= cmd->seq_start_offset) &&
+                          ((pdu->offset + pdu->length) <=
+                            cmd->seq_end_offset)) {
+                               if (!cmd->unsolicited_data)
+                                       cmd->next_burst_len -= pdu->length;
+                               else
+                                       cmd->first_burst_len -= pdu->length;
+
+                               cmd->write_data_done -= pdu->length;
+                               pdu->status = ISCSI_PDU_NOT_RECEIVED;
+                       }
+               }
+       } else {
+               struct iscsi_seq *seq = NULL;
+
+               seq = iscsit_get_seq_holder(cmd, pdu_offset, pdu_length);
+               if (!seq)
+                       return -1;
+
+               *r2t_offset = seq->orig_offset;
+               *r2t_length = seq->xfer_len;
+
+               cmd->write_data_done -= (seq->offset - seq->orig_offset);
+               if (cmd->immediate_data)
+                       cmd->first_burst_len = cmd->write_data_done;
+
+               seq->data_sn = 0;
+               seq->offset = seq->orig_offset;
+               seq->next_burst_len = 0;
+               seq->status = DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY;
+
+               if (conn->sess->sess_ops->DataPDUInOrder)
+                       return 0;
+
+               for (i = 0; i < seq->pdu_count; i++) {
+                       pdu = &cmd->pdu_list[i+seq->pdu_start];
+
+                       if (pdu->status != ISCSI_PDU_RECEIVED_OK)
+                               continue;
+
+                       pdu->status = ISCSI_PDU_NOT_RECEIVED;
+               }
+       }
+
+       return 0;
+}
+
+int iscsit_recover_dataout_sequence(
+       struct iscsi_cmd *cmd,
+       u32 pdu_offset,
+       u32 pdu_length)
+{
+       u32 r2t_length = 0, r2t_offset = 0;
+
+       spin_lock_bh(&cmd->istate_lock);
+       cmd->cmd_flags |= ICF_WITHIN_COMMAND_RECOVERY;
+       spin_unlock_bh(&cmd->istate_lock);
+
+       if (iscsit_recalculate_dataout_values(cmd, pdu_offset, pdu_length,
+                       &r2t_offset, &r2t_length) < 0)
+               return DATAOUT_CANNOT_RECOVER;
+
+       iscsit_send_recovery_r2t(cmd, r2t_offset, r2t_length);
+
+       return DATAOUT_WITHIN_COMMAND_RECOVERY;
+}
+
+static struct iscsi_ooo_cmdsn *iscsit_allocate_ooo_cmdsn(void)
+{
+       struct iscsi_ooo_cmdsn *ooo_cmdsn = NULL;
+
+       ooo_cmdsn = kmem_cache_zalloc(lio_ooo_cache, GFP_ATOMIC);
+       if (!ooo_cmdsn) {
+               pr_err("Unable to allocate memory for"
+                       " struct iscsi_ooo_cmdsn.\n");
+               return NULL;
+       }
+       INIT_LIST_HEAD(&ooo_cmdsn->ooo_list);
+
+       return ooo_cmdsn;
+}
+
+/*
+ *     Called with sess->cmdsn_mutex held.
+ */
+static int iscsit_attach_ooo_cmdsn(
+       struct iscsi_session *sess,
+       struct iscsi_ooo_cmdsn *ooo_cmdsn)
+{
+       struct iscsi_ooo_cmdsn *ooo_tail, *ooo_tmp;
+       /*
+        * We attach the struct iscsi_ooo_cmdsn entry to the out of order
+        * list in increasing CmdSN order.
+        * This allows iscsi_execute_ooo_cmdsns() to detect any
+        * additional CmdSN holes while performing delayed execution.
+        */
+       if (list_empty(&sess->sess_ooo_cmdsn_list))
+               list_add_tail(&ooo_cmdsn->ooo_list,
+                               &sess->sess_ooo_cmdsn_list);
+       else {
+               ooo_tail = list_entry(sess->sess_ooo_cmdsn_list.prev,
+                               typeof(*ooo_tail), ooo_list);
+               /*
+                * CmdSN is greater than the tail of the list.
+                */
+               if (ooo_tail->cmdsn < ooo_cmdsn->cmdsn)
+                       list_add_tail(&ooo_cmdsn->ooo_list,
+                                       &sess->sess_ooo_cmdsn_list);
+               else {
+                       /*
+                        * CmdSN is either lower than the head,  or somewhere
+                        * in the middle.
+                        */
+                       list_for_each_entry(ooo_tmp, &sess->sess_ooo_cmdsn_list,
+                                               ooo_list) {
+                               while (ooo_tmp->cmdsn < ooo_cmdsn->cmdsn)
+                                       continue;
+
+                               list_add(&ooo_cmdsn->ooo_list,
+                                       &ooo_tmp->ooo_list);
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/*
+ *     Removes an struct iscsi_ooo_cmdsn from a session's list,
+ *     called with struct iscsi_session->cmdsn_mutex held.
+ */
+void iscsit_remove_ooo_cmdsn(
+       struct iscsi_session *sess,
+       struct iscsi_ooo_cmdsn *ooo_cmdsn)
+{
+       list_del(&ooo_cmdsn->ooo_list);
+       kmem_cache_free(lio_ooo_cache, ooo_cmdsn);
+}
+
+void iscsit_clear_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
+{
+       struct iscsi_ooo_cmdsn *ooo_cmdsn;
+       struct iscsi_session *sess = conn->sess;
+
+       mutex_lock(&sess->cmdsn_mutex);
+       list_for_each_entry(ooo_cmdsn, &sess->sess_ooo_cmdsn_list, ooo_list) {
+               if (ooo_cmdsn->cid != conn->cid)
+                       continue;
+
+               ooo_cmdsn->cmd = NULL;
+       }
+       mutex_unlock(&sess->cmdsn_mutex);
+}
+
+/*
+ *     Called with sess->cmdsn_mutex held.
+ */
+int iscsit_execute_ooo_cmdsns(struct iscsi_session *sess)
+{
+       int ooo_count = 0;
+       struct iscsi_cmd *cmd = NULL;
+       struct iscsi_ooo_cmdsn *ooo_cmdsn, *ooo_cmdsn_tmp;
+
+       list_for_each_entry_safe(ooo_cmdsn, ooo_cmdsn_tmp,
+                               &sess->sess_ooo_cmdsn_list, ooo_list) {
+               if (ooo_cmdsn->cmdsn != sess->exp_cmd_sn)
+                       continue;
+
+               if (!ooo_cmdsn->cmd) {
+                       sess->exp_cmd_sn++;
+                       iscsit_remove_ooo_cmdsn(sess, ooo_cmdsn);
+                       continue;
+               }
+
+               cmd = ooo_cmdsn->cmd;
+               cmd->i_state = cmd->deferred_i_state;
+               ooo_count++;
+               sess->exp_cmd_sn++;
+               pr_debug("Executing out of order CmdSN: 0x%08x,"
+                       " incremented ExpCmdSN to 0x%08x.\n",
+                       cmd->cmd_sn, sess->exp_cmd_sn);
+
+               iscsit_remove_ooo_cmdsn(sess, ooo_cmdsn);
+
+               if (iscsit_execute_cmd(cmd, 1) < 0)
+                       return -1;
+
+               continue;
+       }
+
+       return ooo_count;
+}
+
+/*
+ *     Called either:
+ *
+ *     1. With sess->cmdsn_mutex held from iscsi_execute_ooo_cmdsns()
+ *     or iscsi_check_received_cmdsn().
+ *     2. With no locks held directly from iscsi_handle_XXX_pdu() functions
+ *     for immediate commands.
+ */
+int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)
+{
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       int lr = 0;
+
+       spin_lock_bh(&cmd->istate_lock);
+       if (ooo)
+               cmd->cmd_flags &= ~ICF_OOO_CMDSN;
+
+       switch (cmd->iscsi_opcode) {
+       case ISCSI_OP_SCSI_CMD:
+               /*
+                * Go ahead and send the CHECK_CONDITION status for
+                * any SCSI CDB exceptions that may have occurred, also
+                * handle the SCF_SCSI_RESERVATION_CONFLICT case here as well.
+                */
+               if (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION) {
+                       if (se_cmd->se_cmd_flags &
+                                       SCF_SCSI_RESERVATION_CONFLICT) {
+                               cmd->i_state = ISTATE_SEND_STATUS;
+                               spin_unlock_bh(&cmd->istate_lock);
+                               iscsit_add_cmd_to_response_queue(cmd, cmd->conn,
+                                               cmd->i_state);
+                               return 0;
+                       }
+                       spin_unlock_bh(&cmd->istate_lock);
+                       /*
+                        * Determine if delayed TASK_ABORTED status for WRITEs
+                        * should be sent now if no unsolicited data out
+                        * payloads are expected, or if the delayed status
+                        * should be sent after unsolicited data out with
+                        * ISCSI_FLAG_CMD_FINAL set in iscsi_handle_data_out()
+                        */
+                       if (transport_check_aborted_status(se_cmd,
+                                       (cmd->unsolicited_data == 0)) != 0)
+                               return 0;
+                       /*
+                        * Otherwise send CHECK_CONDITION and sense for
+                        * exception
+                        */
+                       return transport_send_check_condition_and_sense(se_cmd,
+                                       se_cmd->scsi_sense_reason, 0);
+               }
+               /*
+                * Special case for delayed CmdSN with Immediate
+                * Data and/or Unsolicited Data Out attached.
+                */
+               if (cmd->immediate_data) {
+                       if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
+                               spin_unlock_bh(&cmd->istate_lock);
+                               return transport_generic_handle_data(
+                                               &cmd->se_cmd);
+                       }
+                       spin_unlock_bh(&cmd->istate_lock);
+
+                       if (!(cmd->cmd_flags &
+                                       ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) {
+                               /*
+                                * Send the delayed TASK_ABORTED status for
+                                * WRITEs if no more unsolicitied data is
+                                * expected.
+                                */
+                               if (transport_check_aborted_status(se_cmd, 1)
+                                               != 0)
+                                       return 0;
+
+                               iscsit_set_dataout_sequence_values(cmd);
+                               iscsit_build_r2ts_for_cmd(cmd, cmd->conn, 0);
+                       }
+                       return 0;
+               }
+               /*
+                * The default handler.
+                */
+               spin_unlock_bh(&cmd->istate_lock);
+
+               if ((cmd->data_direction == DMA_TO_DEVICE) &&
+                   !(cmd->cmd_flags & ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) {
+                       /*
+                        * Send the delayed TASK_ABORTED status for WRITEs if
+                        * no more nsolicitied data is expected.
+                        */
+                       if (transport_check_aborted_status(se_cmd, 1) != 0)
+                               return 0;
+
+                       iscsit_set_dataout_sequence_values(cmd);
+                       spin_lock_bh(&cmd->dataout_timeout_lock);
+                       iscsit_start_dataout_timer(cmd, cmd->conn);
+                       spin_unlock_bh(&cmd->dataout_timeout_lock);
+               }
+               return transport_handle_cdb_direct(&cmd->se_cmd);
+
+       case ISCSI_OP_NOOP_OUT:
+       case ISCSI_OP_TEXT:
+               spin_unlock_bh(&cmd->istate_lock);
+               iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
+               break;
+       case ISCSI_OP_SCSI_TMFUNC:
+               if (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION) {
+                       spin_unlock_bh(&cmd->istate_lock);
+                       iscsit_add_cmd_to_response_queue(cmd, cmd->conn,
+                                       cmd->i_state);
+                       return 0;
+               }
+               spin_unlock_bh(&cmd->istate_lock);
+
+               return transport_generic_handle_tmr(&cmd->se_cmd);
+       case ISCSI_OP_LOGOUT:
+               spin_unlock_bh(&cmd->istate_lock);
+               switch (cmd->logout_reason) {
+               case ISCSI_LOGOUT_REASON_CLOSE_SESSION:
+                       lr = iscsit_logout_closesession(cmd, cmd->conn);
+                       break;
+               case ISCSI_LOGOUT_REASON_CLOSE_CONNECTION:
+                       lr = iscsit_logout_closeconnection(cmd, cmd->conn);
+                       break;
+               case ISCSI_LOGOUT_REASON_RECOVERY:
+                       lr = iscsit_logout_removeconnforrecovery(cmd, cmd->conn);
+                       break;
+               default:
+                       pr_err("Unknown iSCSI Logout Request Code:"
+                               " 0x%02x\n", cmd->logout_reason);
+                       return -1;
+               }
+
+               return lr;
+       default:
+               spin_unlock_bh(&cmd->istate_lock);
+               pr_err("Cannot perform out of order execution for"
+               " unknown iSCSI Opcode: 0x%02x\n", cmd->iscsi_opcode);
+               return -1;
+       }
+
+       return 0;
+}
+
+void iscsit_free_all_ooo_cmdsns(struct iscsi_session *sess)
+{
+       struct iscsi_ooo_cmdsn *ooo_cmdsn, *ooo_cmdsn_tmp;
+
+       mutex_lock(&sess->cmdsn_mutex);
+       list_for_each_entry_safe(ooo_cmdsn, ooo_cmdsn_tmp,
+                       &sess->sess_ooo_cmdsn_list, ooo_list) {
+
+               list_del(&ooo_cmdsn->ooo_list);
+               kmem_cache_free(lio_ooo_cache, ooo_cmdsn);
+       }
+       mutex_unlock(&sess->cmdsn_mutex);
+}
+
+int iscsit_handle_ooo_cmdsn(
+       struct iscsi_session *sess,
+       struct iscsi_cmd *cmd,
+       u32 cmdsn)
+{
+       int batch = 0;
+       struct iscsi_ooo_cmdsn *ooo_cmdsn = NULL, *ooo_tail = NULL;
+
+       cmd->deferred_i_state           = cmd->i_state;
+       cmd->i_state                    = ISTATE_DEFERRED_CMD;
+       cmd->cmd_flags                  |= ICF_OOO_CMDSN;
+
+       if (list_empty(&sess->sess_ooo_cmdsn_list))
+               batch = 1;
+       else {
+               ooo_tail = list_entry(sess->sess_ooo_cmdsn_list.prev,
+                               typeof(*ooo_tail), ooo_list);
+               if (ooo_tail->cmdsn != (cmdsn - 1))
+                       batch = 1;
+       }
+
+       ooo_cmdsn = iscsit_allocate_ooo_cmdsn();
+       if (!ooo_cmdsn)
+               return CMDSN_ERROR_CANNOT_RECOVER;
+
+       ooo_cmdsn->cmd                  = cmd;
+       ooo_cmdsn->batch_count          = (batch) ?
+                                         (cmdsn - sess->exp_cmd_sn) : 1;
+       ooo_cmdsn->cid                  = cmd->conn->cid;
+       ooo_cmdsn->exp_cmdsn            = sess->exp_cmd_sn;
+       ooo_cmdsn->cmdsn                = cmdsn;
+
+       if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) {
+               kmem_cache_free(lio_ooo_cache, ooo_cmdsn);
+               return CMDSN_ERROR_CANNOT_RECOVER;
+       }
+
+       return CMDSN_HIGHER_THAN_EXP;
+}
+
+static int iscsit_set_dataout_timeout_values(
+       struct iscsi_cmd *cmd,
+       u32 *offset,
+       u32 *length)
+{
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_r2t *r2t;
+
+       if (cmd->unsolicited_data) {
+               *offset = 0;
+               *length = (conn->sess->sess_ops->FirstBurstLength >
+                          cmd->data_length) ?
+                          cmd->data_length :
+                          conn->sess->sess_ops->FirstBurstLength;
+               return 0;
+       }
+
+       spin_lock_bh(&cmd->r2t_lock);
+       if (list_empty(&cmd->cmd_r2t_list)) {
+               pr_err("cmd->cmd_r2t_list is empty!\n");
+               spin_unlock_bh(&cmd->r2t_lock);
+               return -1;
+       }
+
+       list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) {
+               if (r2t->sent_r2t && !r2t->recovery_r2t && !r2t->seq_complete) {
+                       *offset = r2t->offset;
+                       *length = r2t->xfer_len;
+                       spin_unlock_bh(&cmd->r2t_lock);
+                       return 0;
+               }
+       }
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       pr_err("Unable to locate any incomplete DataOUT"
+               " sequences for ITT: 0x%08x.\n", cmd->init_task_tag);
+
+       return -1;
+}
+
+/*
+ *     NOTE: Called from interrupt (timer) context.
+ */
+static void iscsit_handle_dataout_timeout(unsigned long data)
+{
+       u32 pdu_length = 0, pdu_offset = 0;
+       u32 r2t_length = 0, r2t_offset = 0;
+       struct iscsi_cmd *cmd = (struct iscsi_cmd *) data;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_session *sess = NULL;
+       struct iscsi_node_attrib *na;
+
+       iscsit_inc_conn_usage_count(conn);
+
+       spin_lock_bh(&cmd->dataout_timeout_lock);
+       if (cmd->dataout_timer_flags & ISCSI_TF_STOP) {
+               spin_unlock_bh(&cmd->dataout_timeout_lock);
+               iscsit_dec_conn_usage_count(conn);
+               return;
+       }
+       cmd->dataout_timer_flags &= ~ISCSI_TF_RUNNING;
+       sess = conn->sess;
+       na = iscsit_tpg_get_node_attrib(sess);
+
+       if (!sess->sess_ops->ErrorRecoveryLevel) {
+               pr_debug("Unable to recover from DataOut timeout while"
+                       " in ERL=0.\n");
+               goto failure;
+       }
+
+       if (++cmd->dataout_timeout_retries == na->dataout_timeout_retries) {
+               pr_debug("Command ITT: 0x%08x exceeded max retries"
+                       " for DataOUT timeout %u, closing iSCSI connection.\n",
+                       cmd->init_task_tag, na->dataout_timeout_retries);
+               goto failure;
+       }
+
+       cmd->cmd_flags |= ICF_WITHIN_COMMAND_RECOVERY;
+
+       if (conn->sess->sess_ops->DataSequenceInOrder) {
+               if (conn->sess->sess_ops->DataPDUInOrder) {
+                       pdu_offset = cmd->write_data_done;
+                       if ((pdu_offset + (conn->sess->sess_ops->MaxBurstLength -
+                            cmd->next_burst_len)) > cmd->data_length)
+                               pdu_length = (cmd->data_length -
+                                       cmd->write_data_done);
+                       else
+                               pdu_length = (conn->sess->sess_ops->MaxBurstLength -
+                                               cmd->next_burst_len);
+               } else {
+                       pdu_offset = cmd->seq_start_offset;
+                       pdu_length = (cmd->seq_end_offset -
+                               cmd->seq_start_offset);
+               }
+       } else {
+               if (iscsit_set_dataout_timeout_values(cmd, &pdu_offset,
+                               &pdu_length) < 0)
+                       goto failure;
+       }
+
+       if (iscsit_recalculate_dataout_values(cmd, pdu_offset, pdu_length,
+                       &r2t_offset, &r2t_length) < 0)
+               goto failure;
+
+       pr_debug("Command ITT: 0x%08x timed out waiting for"
+               " completion of %sDataOUT Sequence Offset: %u, Length: %u\n",
+               cmd->init_task_tag, (cmd->unsolicited_data) ? "Unsolicited " :
+               "", r2t_offset, r2t_length);
+
+       if (iscsit_send_recovery_r2t(cmd, r2t_offset, r2t_length) < 0)
+               goto failure;
+
+       iscsit_start_dataout_timer(cmd, conn);
+       spin_unlock_bh(&cmd->dataout_timeout_lock);
+       iscsit_dec_conn_usage_count(conn);
+
+       return;
+
+failure:
+       spin_unlock_bh(&cmd->dataout_timeout_lock);
+       iscsit_cause_connection_reinstatement(conn, 0);
+       iscsit_dec_conn_usage_count(conn);
+}
+
+void iscsit_mod_dataout_timer(struct iscsi_cmd *cmd)
+{
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_node_attrib *na = na = iscsit_tpg_get_node_attrib(sess);
+
+       spin_lock_bh(&cmd->dataout_timeout_lock);
+       if (!(cmd->dataout_timer_flags & ISCSI_TF_RUNNING)) {
+               spin_unlock_bh(&cmd->dataout_timeout_lock);
+               return;
+       }
+
+       mod_timer(&cmd->dataout_timer,
+               (get_jiffies_64() + na->dataout_timeout * HZ));
+       pr_debug("Updated DataOUT timer for ITT: 0x%08x",
+                       cmd->init_task_tag);
+       spin_unlock_bh(&cmd->dataout_timeout_lock);
+}
+
+/*
+ *     Called with cmd->dataout_timeout_lock held.
+ */
+void iscsit_start_dataout_timer(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_node_attrib *na = na = iscsit_tpg_get_node_attrib(sess);
+
+       if (cmd->dataout_timer_flags & ISCSI_TF_RUNNING)
+               return;
+
+       pr_debug("Starting DataOUT timer for ITT: 0x%08x on"
+               " CID: %hu.\n", cmd->init_task_tag, conn->cid);
+
+       init_timer(&cmd->dataout_timer);
+       cmd->dataout_timer.expires = (get_jiffies_64() + na->dataout_timeout * HZ);
+       cmd->dataout_timer.data = (unsigned long)cmd;
+       cmd->dataout_timer.function = iscsit_handle_dataout_timeout;
+       cmd->dataout_timer_flags &= ~ISCSI_TF_STOP;
+       cmd->dataout_timer_flags |= ISCSI_TF_RUNNING;
+       add_timer(&cmd->dataout_timer);
+}
+
+void iscsit_stop_dataout_timer(struct iscsi_cmd *cmd)
+{
+       spin_lock_bh(&cmd->dataout_timeout_lock);
+       if (!(cmd->dataout_timer_flags & ISCSI_TF_RUNNING)) {
+               spin_unlock_bh(&cmd->dataout_timeout_lock);
+               return;
+       }
+       cmd->dataout_timer_flags |= ISCSI_TF_STOP;
+       spin_unlock_bh(&cmd->dataout_timeout_lock);
+
+       del_timer_sync(&cmd->dataout_timer);
+
+       spin_lock_bh(&cmd->dataout_timeout_lock);
+       cmd->dataout_timer_flags &= ~ISCSI_TF_RUNNING;
+       pr_debug("Stopped DataOUT Timer for ITT: 0x%08x\n",
+                       cmd->init_task_tag);
+       spin_unlock_bh(&cmd->dataout_timeout_lock);
+}
diff --git a/drivers/target/iscsi/iscsi_target_erl1.h b/drivers/target/iscsi/iscsi_target_erl1.h
new file mode 100644 (file)
index 0000000..85e67e2
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef ISCSI_TARGET_ERL1_H
+#define ISCSI_TARGET_ERL1_H
+
+extern int iscsit_dump_data_payload(struct iscsi_conn *, u32, int);
+extern int iscsit_create_recovery_datain_values_datasequenceinorder_yes(
+                       struct iscsi_cmd *, struct iscsi_datain_req *);
+extern int iscsit_create_recovery_datain_values_datasequenceinorder_no(
+                       struct iscsi_cmd *, struct iscsi_datain_req *);
+extern int iscsit_handle_recovery_datain_or_r2t(struct iscsi_conn *, unsigned char *,
+                       u32, u32, u32, u32);
+extern int iscsit_handle_status_snack(struct iscsi_conn *, u32, u32,
+                       u32, u32);
+extern int iscsit_handle_data_ack(struct iscsi_conn *, u32, u32, u32);
+extern int iscsit_dataout_datapduinorder_no_fbit(struct iscsi_cmd *, struct iscsi_pdu *);
+extern int iscsit_recover_dataout_sequence(struct iscsi_cmd *, u32, u32);
+extern void iscsit_clear_ooo_cmdsns_for_conn(struct iscsi_conn *);
+extern void iscsit_free_all_ooo_cmdsns(struct iscsi_session *);
+extern int iscsit_execute_ooo_cmdsns(struct iscsi_session *);
+extern int iscsit_execute_cmd(struct iscsi_cmd *, int);
+extern int iscsit_handle_ooo_cmdsn(struct iscsi_session *, struct iscsi_cmd *, u32);
+extern void iscsit_remove_ooo_cmdsn(struct iscsi_session *, struct iscsi_ooo_cmdsn *);
+extern void iscsit_mod_dataout_timer(struct iscsi_cmd *);
+extern void iscsit_start_dataout_timer(struct iscsi_cmd *, struct iscsi_conn *);
+extern void iscsit_stop_dataout_timer(struct iscsi_cmd *);
+
+#endif /* ISCSI_TARGET_ERL1_H */
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
new file mode 100644 (file)
index 0000000..91a4d17
--- /dev/null
@@ -0,0 +1,474 @@
+/*******************************************************************************
+ * This file contains error recovery level two functions used by
+ * the iSCSI Target driver.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <scsi/iscsi_proto.h>
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_datain_values.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target_erl0.h"
+#include "iscsi_target_erl1.h"
+#include "iscsi_target_erl2.h"
+#include "iscsi_target.h"
+
+/*
+ *     FIXME: Does RData SNACK apply here as well?
+ */
+void iscsit_create_conn_recovery_datain_values(
+       struct iscsi_cmd *cmd,
+       u32 exp_data_sn)
+{
+       u32 data_sn = 0;
+       struct iscsi_conn *conn = cmd->conn;
+
+       cmd->next_burst_len = 0;
+       cmd->read_data_done = 0;
+
+       while (exp_data_sn > data_sn) {
+               if ((cmd->next_burst_len +
+                    conn->conn_ops->MaxRecvDataSegmentLength) <
+                    conn->sess->sess_ops->MaxBurstLength) {
+                       cmd->read_data_done +=
+                              conn->conn_ops->MaxRecvDataSegmentLength;
+                       cmd->next_burst_len +=
+                              conn->conn_ops->MaxRecvDataSegmentLength;
+               } else {
+                       cmd->read_data_done +=
+                               (conn->sess->sess_ops->MaxBurstLength -
+                               cmd->next_burst_len);
+                       cmd->next_burst_len = 0;
+               }
+               data_sn++;
+       }
+}
+
+void iscsit_create_conn_recovery_dataout_values(
+       struct iscsi_cmd *cmd)
+{
+       u32 write_data_done = 0;
+       struct iscsi_conn *conn = cmd->conn;
+
+       cmd->data_sn = 0;
+       cmd->next_burst_len = 0;
+
+       while (cmd->write_data_done > write_data_done) {
+               if ((write_data_done + conn->sess->sess_ops->MaxBurstLength) <=
+                    cmd->write_data_done)
+                       write_data_done += conn->sess->sess_ops->MaxBurstLength;
+               else
+                       break;
+       }
+
+       cmd->write_data_done = write_data_done;
+}
+
+static int iscsit_attach_active_connection_recovery_entry(
+       struct iscsi_session *sess,
+       struct iscsi_conn_recovery *cr)
+{
+       spin_lock(&sess->cr_a_lock);
+       list_add_tail(&cr->cr_list, &sess->cr_active_list);
+       spin_unlock(&sess->cr_a_lock);
+
+       return 0;
+}
+
+static int iscsit_attach_inactive_connection_recovery_entry(
+       struct iscsi_session *sess,
+       struct iscsi_conn_recovery *cr)
+{
+       spin_lock(&sess->cr_i_lock);
+       list_add_tail(&cr->cr_list, &sess->cr_inactive_list);
+
+       sess->conn_recovery_count++;
+       pr_debug("Incremented connection recovery count to %u for"
+               " SID: %u\n", sess->conn_recovery_count, sess->sid);
+       spin_unlock(&sess->cr_i_lock);
+
+       return 0;
+}
+
+struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry(
+       struct iscsi_session *sess,
+       u16 cid)
+{
+       struct iscsi_conn_recovery *cr;
+
+       spin_lock(&sess->cr_i_lock);
+       list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) {
+               if (cr->cid == cid) {
+                       spin_unlock(&sess->cr_i_lock);
+                       return cr;
+               }
+       }
+       spin_unlock(&sess->cr_i_lock);
+
+       return NULL;
+}
+
+void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
+{
+       struct iscsi_cmd *cmd, *cmd_tmp;
+       struct iscsi_conn_recovery *cr, *cr_tmp;
+
+       spin_lock(&sess->cr_a_lock);
+       list_for_each_entry_safe(cr, cr_tmp, &sess->cr_active_list, cr_list) {
+               list_del(&cr->cr_list);
+               spin_unlock(&sess->cr_a_lock);
+
+               spin_lock(&cr->conn_recovery_cmd_lock);
+               list_for_each_entry_safe(cmd, cmd_tmp,
+                               &cr->conn_recovery_cmd_list, i_list) {
+
+                       list_del(&cmd->i_list);
+                       cmd->conn = NULL;
+                       spin_unlock(&cr->conn_recovery_cmd_lock);
+                       if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
+                           !(cmd->se_cmd.transport_wait_for_tasks))
+                               iscsit_release_cmd(cmd);
+                       else
+                               cmd->se_cmd.transport_wait_for_tasks(
+                                               &cmd->se_cmd, 1, 1);
+                       spin_lock(&cr->conn_recovery_cmd_lock);
+               }
+               spin_unlock(&cr->conn_recovery_cmd_lock);
+               spin_lock(&sess->cr_a_lock);
+
+               kfree(cr);
+       }
+       spin_unlock(&sess->cr_a_lock);
+
+       spin_lock(&sess->cr_i_lock);
+       list_for_each_entry_safe(cr, cr_tmp, &sess->cr_inactive_list, cr_list) {
+               list_del(&cr->cr_list);
+               spin_unlock(&sess->cr_i_lock);
+
+               spin_lock(&cr->conn_recovery_cmd_lock);
+               list_for_each_entry_safe(cmd, cmd_tmp,
+                               &cr->conn_recovery_cmd_list, i_list) {
+
+                       list_del(&cmd->i_list);
+                       cmd->conn = NULL;
+                       spin_unlock(&cr->conn_recovery_cmd_lock);
+                       if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
+                           !(cmd->se_cmd.transport_wait_for_tasks))
+                               iscsit_release_cmd(cmd);
+                       else
+                               cmd->se_cmd.transport_wait_for_tasks(
+                                               &cmd->se_cmd, 1, 1);
+                       spin_lock(&cr->conn_recovery_cmd_lock);
+               }
+               spin_unlock(&cr->conn_recovery_cmd_lock);
+               spin_lock(&sess->cr_i_lock);
+
+               kfree(cr);
+       }
+       spin_unlock(&sess->cr_i_lock);
+}
+
+int iscsit_remove_active_connection_recovery_entry(
+       struct iscsi_conn_recovery *cr,
+       struct iscsi_session *sess)
+{
+       spin_lock(&sess->cr_a_lock);
+       list_del(&cr->cr_list);
+
+       sess->conn_recovery_count--;
+       pr_debug("Decremented connection recovery count to %u for"
+               " SID: %u\n", sess->conn_recovery_count, sess->sid);
+       spin_unlock(&sess->cr_a_lock);
+
+       kfree(cr);
+
+       return 0;
+}
+
+int iscsit_remove_inactive_connection_recovery_entry(
+       struct iscsi_conn_recovery *cr,
+       struct iscsi_session *sess)
+{
+       spin_lock(&sess->cr_i_lock);
+       list_del(&cr->cr_list);
+       spin_unlock(&sess->cr_i_lock);
+
+       return 0;
+}
+
+/*
+ *     Called with cr->conn_recovery_cmd_lock help.
+ */
+int iscsit_remove_cmd_from_connection_recovery(
+       struct iscsi_cmd *cmd,
+       struct iscsi_session *sess)
+{
+       struct iscsi_conn_recovery *cr;
+
+       if (!cmd->cr) {
+               pr_err("struct iscsi_conn_recovery pointer for ITT: 0x%08x"
+                       " is NULL!\n", cmd->init_task_tag);
+               BUG();
+       }
+       cr = cmd->cr;
+
+       list_del(&cmd->i_list);
+       return --cr->cmd_count;
+}
+
+void iscsit_discard_cr_cmds_by_expstatsn(
+       struct iscsi_conn_recovery *cr,
+       u32 exp_statsn)
+{
+       u32 dropped_count = 0;
+       struct iscsi_cmd *cmd, *cmd_tmp;
+       struct iscsi_session *sess = cr->sess;
+
+       spin_lock(&cr->conn_recovery_cmd_lock);
+       list_for_each_entry_safe(cmd, cmd_tmp,
+                       &cr->conn_recovery_cmd_list, i_list) {
+
+               if (((cmd->deferred_i_state != ISTATE_SENT_STATUS) &&
+                    (cmd->deferred_i_state != ISTATE_REMOVE)) ||
+                    (cmd->stat_sn >= exp_statsn)) {
+                       continue;
+               }
+
+               dropped_count++;
+               pr_debug("Dropping Acknowledged ITT: 0x%08x, StatSN:"
+                       " 0x%08x, CID: %hu.\n", cmd->init_task_tag,
+                               cmd->stat_sn, cr->cid);
+
+               iscsit_remove_cmd_from_connection_recovery(cmd, sess);
+
+               spin_unlock(&cr->conn_recovery_cmd_lock);
+               if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
+                   !(cmd->se_cmd.transport_wait_for_tasks))
+                       iscsit_release_cmd(cmd);
+               else
+                       cmd->se_cmd.transport_wait_for_tasks(
+                                       &cmd->se_cmd, 1, 0);
+               spin_lock(&cr->conn_recovery_cmd_lock);
+       }
+       spin_unlock(&cr->conn_recovery_cmd_lock);
+
+       pr_debug("Dropped %u total acknowledged commands on"
+               " CID: %hu less than old ExpStatSN: 0x%08x\n",
+                       dropped_count, cr->cid, exp_statsn);
+
+       if (!cr->cmd_count) {
+               pr_debug("No commands to be reassigned for failed"
+                       " connection CID: %hu on SID: %u\n",
+                       cr->cid, sess->sid);
+               iscsit_remove_inactive_connection_recovery_entry(cr, sess);
+               iscsit_attach_active_connection_recovery_entry(sess, cr);
+               pr_debug("iSCSI connection recovery successful for CID:"
+                       " %hu on SID: %u\n", cr->cid, sess->sid);
+               iscsit_remove_active_connection_recovery_entry(cr, sess);
+       } else {
+               iscsit_remove_inactive_connection_recovery_entry(cr, sess);
+               iscsit_attach_active_connection_recovery_entry(sess, cr);
+       }
+}
+
+int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
+{
+       u32 dropped_count = 0;
+       struct iscsi_cmd *cmd, *cmd_tmp;
+       struct iscsi_ooo_cmdsn *ooo_cmdsn, *ooo_cmdsn_tmp;
+       struct iscsi_session *sess = conn->sess;
+
+       mutex_lock(&sess->cmdsn_mutex);
+       list_for_each_entry_safe(ooo_cmdsn, ooo_cmdsn_tmp,
+                       &sess->sess_ooo_cmdsn_list, ooo_list) {
+
+               if (ooo_cmdsn->cid != conn->cid)
+                       continue;
+
+               dropped_count++;
+               pr_debug("Dropping unacknowledged CmdSN:"
+               " 0x%08x during connection recovery on CID: %hu\n",
+                       ooo_cmdsn->cmdsn, conn->cid);
+               iscsit_remove_ooo_cmdsn(sess, ooo_cmdsn);
+       }
+       mutex_unlock(&sess->cmdsn_mutex);
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) {
+               if (!(cmd->cmd_flags & ICF_OOO_CMDSN))
+                       continue;
+
+               list_del(&cmd->i_list);
+
+               spin_unlock_bh(&conn->cmd_lock);
+               if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
+                   !(cmd->se_cmd.transport_wait_for_tasks))
+                       iscsit_release_cmd(cmd);
+               else
+                       cmd->se_cmd.transport_wait_for_tasks(
+                                       &cmd->se_cmd, 1, 1);
+               spin_lock_bh(&conn->cmd_lock);
+       }
+       spin_unlock_bh(&conn->cmd_lock);
+
+       pr_debug("Dropped %u total unacknowledged commands on CID:"
+               " %hu for ExpCmdSN: 0x%08x.\n", dropped_count, conn->cid,
+                               sess->exp_cmd_sn);
+       return 0;
+}
+
+int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
+{
+       u32 cmd_count = 0;
+       struct iscsi_cmd *cmd, *cmd_tmp;
+       struct iscsi_conn_recovery *cr;
+
+       /*
+        * Allocate an struct iscsi_conn_recovery for this connection.
+        * Each struct iscsi_cmd contains an struct iscsi_conn_recovery pointer
+        * (struct iscsi_cmd->cr) so we need to allocate this before preparing the
+        * connection's command list for connection recovery.
+        */
+       cr = kzalloc(sizeof(struct iscsi_conn_recovery), GFP_KERNEL);
+       if (!cr) {
+               pr_err("Unable to allocate memory for"
+                       " struct iscsi_conn_recovery.\n");
+               return -1;
+       }
+       INIT_LIST_HEAD(&cr->cr_list);
+       INIT_LIST_HEAD(&cr->conn_recovery_cmd_list);
+       spin_lock_init(&cr->conn_recovery_cmd_lock);
+       /*
+        * Only perform connection recovery on ISCSI_OP_SCSI_CMD or
+        * ISCSI_OP_NOOP_OUT opcodes.  For all other opcodes call
+        * list_del(&cmd->i_list); to release the command to the
+        * session pool and remove it from the connection's list.
+        *
+        * Also stop the DataOUT timer, which will be restarted after
+        * sending the TMR response.
+        */
+       spin_lock_bh(&conn->cmd_lock);
+       list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) {
+
+               if ((cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD) &&
+                   (cmd->iscsi_opcode != ISCSI_OP_NOOP_OUT)) {
+                       pr_debug("Not performing realligence on"
+                               " Opcode: 0x%02x, ITT: 0x%08x, CmdSN: 0x%08x,"
+                               " CID: %hu\n", cmd->iscsi_opcode,
+                               cmd->init_task_tag, cmd->cmd_sn, conn->cid);
+
+                       list_del(&cmd->i_list);
+                       spin_unlock_bh(&conn->cmd_lock);
+
+                       if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
+                           !(cmd->se_cmd.transport_wait_for_tasks))
+                               iscsit_release_cmd(cmd);
+                       else
+                               cmd->se_cmd.transport_wait_for_tasks(
+                                               &cmd->se_cmd, 1, 0);
+                       spin_lock_bh(&conn->cmd_lock);
+                       continue;
+               }
+
+               /*
+                * Special case where commands greater than or equal to
+                * the session's ExpCmdSN are attached to the connection
+                * list but not to the out of order CmdSN list.  The one
+                * obvious case is when a command with immediate data
+                * attached must only check the CmdSN against ExpCmdSN
+                * after the data is received.  The special case below
+                * is when the connection fails before data is received,
+                * but also may apply to other PDUs, so it has been
+                * made generic here.
+                */
+               if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd &&
+                    (cmd->cmd_sn >= conn->sess->exp_cmd_sn)) {
+                       list_del(&cmd->i_list);
+                       spin_unlock_bh(&conn->cmd_lock);
+
+                       if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) ||
+                           !(cmd->se_cmd.transport_wait_for_tasks))
+                               iscsit_release_cmd(cmd);
+                       else
+                               cmd->se_cmd.transport_wait_for_tasks(
+                                               &cmd->se_cmd, 1, 1);
+                       spin_lock_bh(&conn->cmd_lock);
+                       continue;
+               }
+
+               cmd_count++;
+               pr_debug("Preparing Opcode: 0x%02x, ITT: 0x%08x,"
+                       " CmdSN: 0x%08x, StatSN: 0x%08x, CID: %hu for"
+                       " realligence.\n", cmd->iscsi_opcode,
+                       cmd->init_task_tag, cmd->cmd_sn, cmd->stat_sn,
+                       conn->cid);
+
+               cmd->deferred_i_state = cmd->i_state;
+               cmd->i_state = ISTATE_IN_CONNECTION_RECOVERY;
+
+               if (cmd->data_direction == DMA_TO_DEVICE)
+                       iscsit_stop_dataout_timer(cmd);
+
+               cmd->sess = conn->sess;
+
+               list_del(&cmd->i_list);
+               spin_unlock_bh(&conn->cmd_lock);
+
+               iscsit_free_all_datain_reqs(cmd);
+
+               if ((cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) &&
+                    cmd->se_cmd.transport_wait_for_tasks)
+                       cmd->se_cmd.transport_wait_for_tasks(&cmd->se_cmd,
+                                       0, 0);
+               /*
+                * Add the struct iscsi_cmd to the connection recovery cmd list
+                */
+               spin_lock(&cr->conn_recovery_cmd_lock);
+               list_add_tail(&cmd->i_list, &cr->conn_recovery_cmd_list);
+               spin_unlock(&cr->conn_recovery_cmd_lock);
+
+               spin_lock_bh(&conn->cmd_lock);
+               cmd->cr = cr;
+               cmd->conn = NULL;
+       }
+       spin_unlock_bh(&conn->cmd_lock);
+       /*
+        * Fill in the various values in the preallocated struct iscsi_conn_recovery.
+        */
+       cr->cid = conn->cid;
+       cr->cmd_count = cmd_count;
+       cr->maxrecvdatasegmentlength = conn->conn_ops->MaxRecvDataSegmentLength;
+       cr->sess = conn->sess;
+
+       iscsit_attach_inactive_connection_recovery_entry(conn->sess, cr);
+
+       return 0;
+}
+
+int iscsit_connection_recovery_transport_reset(struct iscsi_conn *conn)
+{
+       atomic_set(&conn->connection_recovery, 1);
+
+       if (iscsit_close_connection(conn) < 0)
+               return -1;
+
+       return 0;
+}
diff --git a/drivers/target/iscsi/iscsi_target_erl2.h b/drivers/target/iscsi/iscsi_target_erl2.h
new file mode 100644 (file)
index 0000000..22f8d24
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef ISCSI_TARGET_ERL2_H
+#define ISCSI_TARGET_ERL2_H
+
+extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, u32);
+extern void iscsit_create_conn_recovery_dataout_values(struct iscsi_cmd *);
+extern struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry(
+                       struct iscsi_session *, u16);
+extern void iscsit_free_connection_recovery_entires(struct iscsi_session *);
+extern int iscsit_remove_active_connection_recovery_entry(
+                       struct iscsi_conn_recovery *, struct iscsi_session *);
+extern int iscsit_remove_cmd_from_connection_recovery(struct iscsi_cmd *,
+                       struct iscsi_session *);
+extern void iscsit_discard_cr_cmds_by_expstatsn(struct iscsi_conn_recovery *, u32);
+extern int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *);
+extern int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *);
+extern int iscsit_connection_recovery_transport_reset(struct iscsi_conn *);
+
+#endif /*** ISCSI_TARGET_ERL2_H ***/
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
new file mode 100644 (file)
index 0000000..bcaf82f
--- /dev/null
@@ -0,0 +1,1232 @@
+/*******************************************************************************
+ * This file contains the login functions used by the iSCSI Target driver.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <linux/string.h>
+#include <linux/kthread.h>
+#include <linux/crypto.h>
+#include <scsi/iscsi_proto.h>
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_tq.h"
+#include "iscsi_target_device.h"
+#include "iscsi_target_nego.h"
+#include "iscsi_target_erl0.h"
+#include "iscsi_target_erl2.h"
+#include "iscsi_target_login.h"
+#include "iscsi_target_stat.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target.h"
+#include "iscsi_target_parameters.h"
+
+extern struct idr sess_idr;
+extern struct mutex auth_id_lock;
+extern spinlock_t sess_idr_lock;
+
+static int iscsi_login_init_conn(struct iscsi_conn *conn)
+{
+       INIT_LIST_HEAD(&conn->conn_list);
+       INIT_LIST_HEAD(&conn->conn_cmd_list);
+       INIT_LIST_HEAD(&conn->immed_queue_list);
+       INIT_LIST_HEAD(&conn->response_queue_list);
+       init_completion(&conn->conn_post_wait_comp);
+       init_completion(&conn->conn_wait_comp);
+       init_completion(&conn->conn_wait_rcfr_comp);
+       init_completion(&conn->conn_waiting_on_uc_comp);
+       init_completion(&conn->conn_logout_comp);
+       init_completion(&conn->rx_half_close_comp);
+       init_completion(&conn->tx_half_close_comp);
+       spin_lock_init(&conn->cmd_lock);
+       spin_lock_init(&conn->conn_usage_lock);
+       spin_lock_init(&conn->immed_queue_lock);
+       spin_lock_init(&conn->nopin_timer_lock);
+       spin_lock_init(&conn->response_queue_lock);
+       spin_lock_init(&conn->state_lock);
+
+       if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) {
+               pr_err("Unable to allocate conn->conn_cpumask\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/*
+ * Used by iscsi_target_nego.c:iscsi_target_locate_portal() to setup
+ * per struct iscsi_conn libcrypto contexts for crc32c and crc32-intel
+ */
+int iscsi_login_setup_crypto(struct iscsi_conn *conn)
+{
+       /*
+        * Setup slicing by CRC32C algorithm for RX and TX libcrypto contexts
+        * which will default to crc32c_intel.ko for cpu_has_xmm4_2, or fallback
+        * to software 1x8 byte slicing from crc32c.ko
+        */
+       conn->conn_rx_hash.flags = 0;
+       conn->conn_rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+                                               CRYPTO_ALG_ASYNC);
+       if (IS_ERR(conn->conn_rx_hash.tfm)) {
+               pr_err("crypto_alloc_hash() failed for conn_rx_tfm\n");
+               return -ENOMEM;
+       }
+
+       conn->conn_tx_hash.flags = 0;
+       conn->conn_tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+                                               CRYPTO_ALG_ASYNC);
+       if (IS_ERR(conn->conn_tx_hash.tfm)) {
+               pr_err("crypto_alloc_hash() failed for conn_tx_tfm\n");
+               crypto_free_hash(conn->conn_rx_hash.tfm);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int iscsi_login_check_initiator_version(
+       struct iscsi_conn *conn,
+       u8 version_max,
+       u8 version_min)
+{
+       if ((version_max != 0x00) || (version_min != 0x00)) {
+               pr_err("Unsupported iSCSI IETF Pre-RFC Revision,"
+                       " version Min/Max 0x%02x/0x%02x, rejecting login.\n",
+                       version_min, version_max);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_NO_VERSION);
+               return -1;
+       }
+
+       return 0;
+}
+
+int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
+{
+       int sessiontype;
+       struct iscsi_param *initiatorname_param = NULL, *sessiontype_param = NULL;
+       struct iscsi_portal_group *tpg = conn->tpg;
+       struct iscsi_session *sess = NULL, *sess_p = NULL;
+       struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
+       struct se_session *se_sess, *se_sess_tmp;
+
+       initiatorname_param = iscsi_find_param_from_key(
+                       INITIATORNAME, conn->param_list);
+       if (!initiatorname_param)
+               return -1;
+
+       sessiontype_param = iscsi_find_param_from_key(
+                       SESSIONTYPE, conn->param_list);
+       if (!sessiontype_param)
+               return -1;
+
+       sessiontype = (strncmp(sessiontype_param->value, NORMAL, 6)) ? 1 : 0;
+
+       spin_lock_bh(&se_tpg->session_lock);
+       list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
+                       sess_list) {
+
+               sess_p = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               spin_lock(&sess_p->conn_lock);
+               if (atomic_read(&sess_p->session_fall_back_to_erl0) ||
+                   atomic_read(&sess_p->session_logout) ||
+                   (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
+                       spin_unlock(&sess_p->conn_lock);
+                       continue;
+               }
+               if (!memcmp((void *)sess_p->isid, (void *)conn->sess->isid, 6) &&
+                  (!strcmp((void *)sess_p->sess_ops->InitiatorName,
+                           (void *)initiatorname_param->value) &&
+                  (sess_p->sess_ops->SessionType == sessiontype))) {
+                       atomic_set(&sess_p->session_reinstatement, 1);
+                       spin_unlock(&sess_p->conn_lock);
+                       iscsit_inc_session_usage_count(sess_p);
+                       iscsit_stop_time2retain_timer(sess_p);
+                       sess = sess_p;
+                       break;
+               }
+               spin_unlock(&sess_p->conn_lock);
+       }
+       spin_unlock_bh(&se_tpg->session_lock);
+       /*
+        * If the Time2Retain handler has expired, the session is already gone.
+        */
+       if (!sess)
+               return 0;
+
+       pr_debug("%s iSCSI Session SID %u is still active for %s,"
+               " preforming session reinstatement.\n", (sessiontype) ?
+               "Discovery" : "Normal", sess->sid,
+               sess->sess_ops->InitiatorName);
+
+       spin_lock_bh(&sess->conn_lock);
+       if (sess->session_state == TARG_SESS_STATE_FAILED) {
+               spin_unlock_bh(&sess->conn_lock);
+               iscsit_dec_session_usage_count(sess);
+               return iscsit_close_session(sess);
+       }
+       spin_unlock_bh(&sess->conn_lock);
+
+       iscsit_stop_session(sess, 1, 1);
+       iscsit_dec_session_usage_count(sess);
+
+       return iscsit_close_session(sess);
+}
+
+static void iscsi_login_set_conn_values(
+       struct iscsi_session *sess,
+       struct iscsi_conn *conn,
+       u16 cid)
+{
+       conn->sess              = sess;
+       conn->cid               = cid;
+       /*
+        * Generate a random Status sequence number (statsn) for the new
+        * iSCSI connection.
+        */
+       get_random_bytes(&conn->stat_sn, sizeof(u32));
+
+       mutex_lock(&auth_id_lock);
+       conn->auth_id           = iscsit_global->auth_id++;
+       mutex_unlock(&auth_id_lock);
+}
+
+/*
+ *     This is the leading connection of a new session,
+ *     or session reinstatement.
+ */
+static int iscsi_login_zero_tsih_s1(
+       struct iscsi_conn *conn,
+       unsigned char *buf)
+{
+       struct iscsi_session *sess = NULL;
+       struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
+
+       sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL);
+       if (!sess) {
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               pr_err("Could not allocate memory for session\n");
+               return -1;
+       }
+
+       iscsi_login_set_conn_values(sess, conn, pdu->cid);
+       sess->init_task_tag     = pdu->itt;
+       memcpy((void *)&sess->isid, (void *)pdu->isid, 6);
+       sess->exp_cmd_sn        = pdu->cmdsn;
+       INIT_LIST_HEAD(&sess->sess_conn_list);
+       INIT_LIST_HEAD(&sess->sess_ooo_cmdsn_list);
+       INIT_LIST_HEAD(&sess->cr_active_list);
+       INIT_LIST_HEAD(&sess->cr_inactive_list);
+       init_completion(&sess->async_msg_comp);
+       init_completion(&sess->reinstatement_comp);
+       init_completion(&sess->session_wait_comp);
+       init_completion(&sess->session_waiting_on_uc_comp);
+       mutex_init(&sess->cmdsn_mutex);
+       spin_lock_init(&sess->conn_lock);
+       spin_lock_init(&sess->cr_a_lock);
+       spin_lock_init(&sess->cr_i_lock);
+       spin_lock_init(&sess->session_usage_lock);
+       spin_lock_init(&sess->ttt_lock);
+
+       if (!idr_pre_get(&sess_idr, GFP_KERNEL)) {
+               pr_err("idr_pre_get() for sess_idr failed\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+       spin_lock(&sess_idr_lock);
+       idr_get_new(&sess_idr, NULL, &sess->session_index);
+       spin_unlock(&sess_idr_lock);
+
+       sess->creation_time = get_jiffies_64();
+       spin_lock_init(&sess->session_stats_lock);
+       /*
+        * The FFP CmdSN window values will be allocated from the TPG's
+        * Initiator Node's ACL once the login has been successfully completed.
+        */
+       sess->max_cmd_sn        = pdu->cmdsn;
+
+       sess->sess_ops = kzalloc(sizeof(struct iscsi_sess_ops), GFP_KERNEL);
+       if (!sess->sess_ops) {
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               pr_err("Unable to allocate memory for"
+                               " struct iscsi_sess_ops.\n");
+               return -1;
+       }
+
+       sess->se_sess = transport_init_session();
+       if (!sess->se_sess) {
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int iscsi_login_zero_tsih_s2(
+       struct iscsi_conn *conn)
+{
+       struct iscsi_node_attrib *na;
+       struct iscsi_session *sess = conn->sess;
+       unsigned char buf[32];
+
+       sess->tpg = conn->tpg;
+
+       /*
+        * Assign a new TPG Session Handle.  Note this is protected with
+        * struct iscsi_portal_group->np_login_sem from iscsit_access_np().
+        */
+       sess->tsih = ++ISCSI_TPG_S(sess)->ntsih;
+       if (!sess->tsih)
+               sess->tsih = ++ISCSI_TPG_S(sess)->ntsih;
+
+       /*
+        * Create the default params from user defined values..
+        */
+       if (iscsi_copy_param_list(&conn->param_list,
+                               ISCSI_TPG_C(conn)->param_list, 1) < 0) {
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+
+       iscsi_set_keys_to_negotiate(0, conn->param_list);
+
+       if (sess->sess_ops->SessionType)
+               return iscsi_set_keys_irrelevant_for_discovery(
+                               conn->param_list);
+
+       na = iscsit_tpg_get_node_attrib(sess);
+
+       /*
+        * Need to send TargetPortalGroupTag back in first login response
+        * on any iSCSI connection where the Initiator provides TargetName.
+        * See 5.3.1.  Login Phase Start
+        *
+        * In our case, we have already located the struct iscsi_tiqn at this point.
+        */
+       memset(buf, 0, 32);
+       sprintf(buf, "TargetPortalGroupTag=%hu", ISCSI_TPG_S(sess)->tpgt);
+       if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+
+       /*
+        * Workaround for Initiators that have broken connection recovery logic.
+        *
+        * "We would really like to get rid of this." Linux-iSCSI.org team
+        */
+       memset(buf, 0, 32);
+       sprintf(buf, "ErrorRecoveryLevel=%d", na->default_erl);
+       if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+
+       if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0)
+               return -1;
+
+       return 0;
+}
+
+/*
+ * Remove PSTATE_NEGOTIATE for the four FIM related keys.
+ * The Initiator node will be able to enable FIM by proposing them itself.
+ */
+int iscsi_login_disable_FIM_keys(
+       struct iscsi_param_list *param_list,
+       struct iscsi_conn *conn)
+{
+       struct iscsi_param *param;
+
+       param = iscsi_find_param_from_key("OFMarker", param_list);
+       if (!param) {
+               pr_err("iscsi_find_param_from_key() for"
+                               " OFMarker failed\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+       param->state &= ~PSTATE_NEGOTIATE;
+
+       param = iscsi_find_param_from_key("OFMarkInt", param_list);
+       if (!param) {
+               pr_err("iscsi_find_param_from_key() for"
+                               " IFMarker failed\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+       param->state &= ~PSTATE_NEGOTIATE;
+
+       param = iscsi_find_param_from_key("IFMarker", param_list);
+       if (!param) {
+               pr_err("iscsi_find_param_from_key() for"
+                               " IFMarker failed\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+       param->state &= ~PSTATE_NEGOTIATE;
+
+       param = iscsi_find_param_from_key("IFMarkInt", param_list);
+       if (!param) {
+               pr_err("iscsi_find_param_from_key() for"
+                               " IFMarker failed\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+       param->state &= ~PSTATE_NEGOTIATE;
+
+       return 0;
+}
+
+static int iscsi_login_non_zero_tsih_s1(
+       struct iscsi_conn *conn,
+       unsigned char *buf)
+{
+       struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
+
+       iscsi_login_set_conn_values(NULL, conn, pdu->cid);
+       return 0;
+}
+
+/*
+ *     Add a new connection to an existing session.
+ */
+static int iscsi_login_non_zero_tsih_s2(
+       struct iscsi_conn *conn,
+       unsigned char *buf)
+{
+       struct iscsi_portal_group *tpg = conn->tpg;
+       struct iscsi_session *sess = NULL, *sess_p = NULL;
+       struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
+       struct se_session *se_sess, *se_sess_tmp;
+       struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
+
+       spin_lock_bh(&se_tpg->session_lock);
+       list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
+                       sess_list) {
+
+               sess_p = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               if (atomic_read(&sess_p->session_fall_back_to_erl0) ||
+                   atomic_read(&sess_p->session_logout) ||
+                  (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED))
+                       continue;
+               if (!memcmp((const void *)sess_p->isid,
+                    (const void *)pdu->isid, 6) &&
+                    (sess_p->tsih == pdu->tsih)) {
+                       iscsit_inc_session_usage_count(sess_p);
+                       iscsit_stop_time2retain_timer(sess_p);
+                       sess = sess_p;
+                       break;
+               }
+       }
+       spin_unlock_bh(&se_tpg->session_lock);
+
+       /*
+        * If the Time2Retain handler has expired, the session is already gone.
+        */
+       if (!sess) {
+               pr_err("Initiator attempting to add a connection to"
+                       " a non-existent session, rejecting iSCSI Login.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_NO_SESSION);
+               return -1;
+       }
+
+       /*
+        * Stop the Time2Retain timer if this is a failed session, we restart
+        * the timer if the login is not successful.
+        */
+       spin_lock_bh(&sess->conn_lock);
+       if (sess->session_state == TARG_SESS_STATE_FAILED)
+               atomic_set(&sess->session_continuation, 1);
+       spin_unlock_bh(&sess->conn_lock);
+
+       iscsi_login_set_conn_values(sess, conn, pdu->cid);
+
+       if (iscsi_copy_param_list(&conn->param_list,
+                       ISCSI_TPG_C(conn)->param_list, 0) < 0) {
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+
+       iscsi_set_keys_to_negotiate(0, conn->param_list);
+       /*
+        * Need to send TargetPortalGroupTag back in first login response
+        * on any iSCSI connection where the Initiator provides TargetName.
+        * See 5.3.1.  Login Phase Start
+        *
+        * In our case, we have already located the struct iscsi_tiqn at this point.
+        */
+       memset(buf, 0, 32);
+       sprintf(buf, "TargetPortalGroupTag=%hu", ISCSI_TPG_S(sess)->tpgt);
+       if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               return -1;
+       }
+
+       return iscsi_login_disable_FIM_keys(conn->param_list, conn);
+}
+
+int iscsi_login_post_auth_non_zero_tsih(
+       struct iscsi_conn *conn,
+       u16 cid,
+       u32 exp_statsn)
+{
+       struct iscsi_conn *conn_ptr = NULL;
+       struct iscsi_conn_recovery *cr = NULL;
+       struct iscsi_session *sess = conn->sess;
+
+       /*
+        * By following item 5 in the login table,  if we have found
+        * an existing ISID and a valid/existing TSIH and an existing
+        * CID we do connection reinstatement.  Currently we dont not
+        * support it so we send back an non-zero status class to the
+        * initiator and release the new connection.
+        */
+       conn_ptr = iscsit_get_conn_from_cid_rcfr(sess, cid);
+       if ((conn_ptr)) {
+               pr_err("Connection exists with CID %hu for %s,"
+                       " performing connection reinstatement.\n",
+                       conn_ptr->cid, sess->sess_ops->InitiatorName);
+
+               iscsit_connection_reinstatement_rcfr(conn_ptr);
+               iscsit_dec_conn_usage_count(conn_ptr);
+       }
+
+       /*
+        * Check for any connection recovery entires containing CID.
+        * We use the original ExpStatSN sent in the first login request
+        * to acknowledge commands for the failed connection.
+        *
+        * Also note that an explict logout may have already been sent,
+        * but the response may not be sent due to additional connection
+        * loss.
+        */
+       if (sess->sess_ops->ErrorRecoveryLevel == 2) {
+               cr = iscsit_get_inactive_connection_recovery_entry(
+                               sess, cid);
+               if ((cr)) {
+                       pr_debug("Performing implicit logout"
+                               " for connection recovery on CID: %hu\n",
+                                       conn->cid);
+                       iscsit_discard_cr_cmds_by_expstatsn(cr, exp_statsn);
+               }
+       }
+
+       /*
+        * Else we follow item 4 from the login table in that we have
+        * found an existing ISID and a valid/existing TSIH and a new
+        * CID we go ahead and continue to add a new connection to the
+        * session.
+        */
+       pr_debug("Adding CID %hu to existing session for %s.\n",
+                       cid, sess->sess_ops->InitiatorName);
+
+       if ((atomic_read(&sess->nconn) + 1) > sess->sess_ops->MaxConnections) {
+               pr_err("Adding additional connection to this session"
+                       " would exceed MaxConnections %d, login failed.\n",
+                               sess->sess_ops->MaxConnections);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_ISID_ERROR);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
+{
+       struct iscsi_session *sess = conn->sess;
+
+       if (!sess->sess_ops->SessionType)
+               iscsit_start_nopin_timer(conn);
+}
+
+static int iscsi_post_login_handler(
+       struct iscsi_np *np,
+       struct iscsi_conn *conn,
+       u8 zero_tsih)
+{
+       int stop_timer = 0;
+       struct iscsi_session *sess = conn->sess;
+       struct se_session *se_sess = sess->se_sess;
+       struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess);
+       struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
+       struct iscsi_thread_set *ts;
+
+       iscsit_inc_conn_usage_count(conn);
+
+       iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_SUCCESS,
+                       ISCSI_LOGIN_STATUS_ACCEPT);
+
+       pr_debug("Moving to TARG_CONN_STATE_LOGGED_IN.\n");
+       conn->conn_state = TARG_CONN_STATE_LOGGED_IN;
+
+       iscsi_set_connection_parameters(conn->conn_ops, conn->param_list);
+       iscsit_set_sync_and_steering_values(conn);
+       /*
+        * SCSI Initiator -> SCSI Target Port Mapping
+        */
+       ts = iscsi_get_thread_set();
+       if (!zero_tsih) {
+               iscsi_set_session_parameters(sess->sess_ops,
+                               conn->param_list, 0);
+               iscsi_release_param_list(conn->param_list);
+               conn->param_list = NULL;
+
+               spin_lock_bh(&sess->conn_lock);
+               atomic_set(&sess->session_continuation, 0);
+               if (sess->session_state == TARG_SESS_STATE_FAILED) {
+                       pr_debug("Moving to"
+                                       " TARG_SESS_STATE_LOGGED_IN.\n");
+                       sess->session_state = TARG_SESS_STATE_LOGGED_IN;
+                       stop_timer = 1;
+               }
+
+               pr_debug("iSCSI Login successful on CID: %hu from %s to"
+                       " %s:%hu,%hu\n", conn->cid, conn->login_ip, np->np_ip,
+                               np->np_port, tpg->tpgt);
+
+               list_add_tail(&conn->conn_list, &sess->sess_conn_list);
+               atomic_inc(&sess->nconn);
+               pr_debug("Incremented iSCSI Connection count to %hu"
+                       " from node: %s\n", atomic_read(&sess->nconn),
+                       sess->sess_ops->InitiatorName);
+               spin_unlock_bh(&sess->conn_lock);
+
+               iscsi_post_login_start_timers(conn);
+               iscsi_activate_thread_set(conn, ts);
+               /*
+                * Determine CPU mask to ensure connection's RX and TX kthreads
+                * are scheduled on the same CPU.
+                */
+               iscsit_thread_get_cpumask(conn);
+               conn->conn_rx_reset_cpumask = 1;
+               conn->conn_tx_reset_cpumask = 1;
+
+               iscsit_dec_conn_usage_count(conn);
+               if (stop_timer) {
+                       spin_lock_bh(&se_tpg->session_lock);
+                       iscsit_stop_time2retain_timer(sess);
+                       spin_unlock_bh(&se_tpg->session_lock);
+               }
+               iscsit_dec_session_usage_count(sess);
+               return 0;
+       }
+
+       iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1);
+       iscsi_release_param_list(conn->param_list);
+       conn->param_list = NULL;
+
+       iscsit_determine_maxcmdsn(sess);
+
+       spin_lock_bh(&se_tpg->session_lock);
+       __transport_register_session(&sess->tpg->tpg_se_tpg,
+                       se_sess->se_node_acl, se_sess, (void *)sess);
+       pr_debug("Moving to TARG_SESS_STATE_LOGGED_IN.\n");
+       sess->session_state = TARG_SESS_STATE_LOGGED_IN;
+
+       pr_debug("iSCSI Login successful on CID: %hu from %s to %s:%hu,%hu\n",
+               conn->cid, conn->login_ip, np->np_ip, np->np_port, tpg->tpgt);
+
+       spin_lock_bh(&sess->conn_lock);
+       list_add_tail(&conn->conn_list, &sess->sess_conn_list);
+       atomic_inc(&sess->nconn);
+       pr_debug("Incremented iSCSI Connection count to %hu from node:"
+               " %s\n", atomic_read(&sess->nconn),
+               sess->sess_ops->InitiatorName);
+       spin_unlock_bh(&sess->conn_lock);
+
+       sess->sid = tpg->sid++;
+       if (!sess->sid)
+               sess->sid = tpg->sid++;
+       pr_debug("Established iSCSI session from node: %s\n",
+                       sess->sess_ops->InitiatorName);
+
+       tpg->nsessions++;
+       if (tpg->tpg_tiqn)
+               tpg->tpg_tiqn->tiqn_nsessions++;
+
+       pr_debug("Incremented number of active iSCSI sessions to %u on"
+               " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt);
+       spin_unlock_bh(&se_tpg->session_lock);
+
+       iscsi_post_login_start_timers(conn);
+       iscsi_activate_thread_set(conn, ts);
+       /*
+        * Determine CPU mask to ensure connection's RX and TX kthreads
+        * are scheduled on the same CPU.
+        */
+       iscsit_thread_get_cpumask(conn);
+       conn->conn_rx_reset_cpumask = 1;
+       conn->conn_tx_reset_cpumask = 1;
+
+       iscsit_dec_conn_usage_count(conn);
+
+       return 0;
+}
+
+static void iscsi_handle_login_thread_timeout(unsigned long data)
+{
+       struct iscsi_np *np = (struct iscsi_np *) data;
+
+       spin_lock_bh(&np->np_thread_lock);
+       pr_err("iSCSI Login timeout on Network Portal %s:%hu\n",
+                       np->np_ip, np->np_port);
+
+       if (np->np_login_timer_flags & ISCSI_TF_STOP) {
+               spin_unlock_bh(&np->np_thread_lock);
+               return;
+       }
+
+       if (np->np_thread)
+               send_sig(SIGINT, np->np_thread, 1);
+
+       np->np_login_timer_flags &= ~ISCSI_TF_RUNNING;
+       spin_unlock_bh(&np->np_thread_lock);
+}
+
+static void iscsi_start_login_thread_timer(struct iscsi_np *np)
+{
+       /*
+        * This used the TA_LOGIN_TIMEOUT constant because at this
+        * point we do not have access to ISCSI_TPG_ATTRIB(tpg)->login_timeout
+        */
+       spin_lock_bh(&np->np_thread_lock);
+       init_timer(&np->np_login_timer);
+       np->np_login_timer.expires = (get_jiffies_64() + TA_LOGIN_TIMEOUT * HZ);
+       np->np_login_timer.data = (unsigned long)np;
+       np->np_login_timer.function = iscsi_handle_login_thread_timeout;
+       np->np_login_timer_flags &= ~ISCSI_TF_STOP;
+       np->np_login_timer_flags |= ISCSI_TF_RUNNING;
+       add_timer(&np->np_login_timer);
+
+       pr_debug("Added timeout timer to iSCSI login request for"
+                       " %u seconds.\n", TA_LOGIN_TIMEOUT);
+       spin_unlock_bh(&np->np_thread_lock);
+}
+
+static void iscsi_stop_login_thread_timer(struct iscsi_np *np)
+{
+       spin_lock_bh(&np->np_thread_lock);
+       if (!(np->np_login_timer_flags & ISCSI_TF_RUNNING)) {
+               spin_unlock_bh(&np->np_thread_lock);
+               return;
+       }
+       np->np_login_timer_flags |= ISCSI_TF_STOP;
+       spin_unlock_bh(&np->np_thread_lock);
+
+       del_timer_sync(&np->np_login_timer);
+
+       spin_lock_bh(&np->np_thread_lock);
+       np->np_login_timer_flags &= ~ISCSI_TF_RUNNING;
+       spin_unlock_bh(&np->np_thread_lock);
+}
+
+int iscsi_target_setup_login_socket(
+       struct iscsi_np *np,
+       struct __kernel_sockaddr_storage *sockaddr)
+{
+       struct socket *sock;
+       int backlog = 5, ret, opt = 0, len;
+
+       switch (np->np_network_transport) {
+       case ISCSI_TCP:
+               np->np_ip_proto = IPPROTO_TCP;
+               np->np_sock_type = SOCK_STREAM;
+               break;
+       case ISCSI_SCTP_TCP:
+               np->np_ip_proto = IPPROTO_SCTP;
+               np->np_sock_type = SOCK_STREAM;
+               break;
+       case ISCSI_SCTP_UDP:
+               np->np_ip_proto = IPPROTO_SCTP;
+               np->np_sock_type = SOCK_SEQPACKET;
+               break;
+       case ISCSI_IWARP_TCP:
+       case ISCSI_IWARP_SCTP:
+       case ISCSI_INFINIBAND:
+       default:
+               pr_err("Unsupported network_transport: %d\n",
+                               np->np_network_transport);
+               return -EINVAL;
+       }
+
+       ret = sock_create(sockaddr->ss_family, np->np_sock_type,
+                       np->np_ip_proto, &sock);
+       if (ret < 0) {
+               pr_err("sock_create() failed.\n");
+               return ret;
+       }
+       np->np_socket = sock;
+       /*
+        * The SCTP stack needs struct socket->file.
+        */
+       if ((np->np_network_transport == ISCSI_SCTP_TCP) ||
+           (np->np_network_transport == ISCSI_SCTP_UDP)) {
+               if (!sock->file) {
+                       sock->file = kzalloc(sizeof(struct file), GFP_KERNEL);
+                       if (!sock->file) {
+                               pr_err("Unable to allocate struct"
+                                               " file for SCTP\n");
+                               ret = -ENOMEM;
+                               goto fail;
+                       }
+                       np->np_flags |= NPF_SCTP_STRUCT_FILE;
+               }
+       }
+       /*
+        * Setup the np->np_sockaddr from the passed sockaddr setup
+        * in iscsi_target_configfs.c code..
+        */
+       memcpy((void *)&np->np_sockaddr, (void *)sockaddr,
+                       sizeof(struct __kernel_sockaddr_storage));
+
+       if (sockaddr->ss_family == AF_INET6)
+               len = sizeof(struct sockaddr_in6);
+       else
+               len = sizeof(struct sockaddr_in);
+       /*
+        * Set SO_REUSEADDR, and disable Nagel Algorithm with TCP_NODELAY.
+        */
+       opt = 1;
+       if (np->np_network_transport == ISCSI_TCP) {
+               ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
+                               (char *)&opt, sizeof(opt));
+               if (ret < 0) {
+                       pr_err("kernel_setsockopt() for TCP_NODELAY"
+                               " failed: %d\n", ret);
+                       goto fail;
+               }
+       }
+
+       ret = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+                       (char *)&opt, sizeof(opt));
+       if (ret < 0) {
+               pr_err("kernel_setsockopt() for SO_REUSEADDR"
+                       " failed\n");
+               goto fail;
+       }
+
+       ret = kernel_bind(sock, (struct sockaddr *)&np->np_sockaddr, len);
+       if (ret < 0) {
+               pr_err("kernel_bind() failed: %d\n", ret);
+               goto fail;
+       }
+
+       ret = kernel_listen(sock, backlog);
+       if (ret != 0) {
+               pr_err("kernel_listen() failed: %d\n", ret);
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       np->np_socket = NULL;
+       if (sock) {
+               if (np->np_flags & NPF_SCTP_STRUCT_FILE) {
+                       kfree(sock->file);
+                       sock->file = NULL;
+               }
+
+               sock_release(sock);
+       }
+       return ret;
+}
+
+static int __iscsi_target_login_thread(struct iscsi_np *np)
+{
+       u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0;
+       int err, ret = 0, ip_proto, sock_type, set_sctp_conn_flag, stop;
+       struct iscsi_conn *conn = NULL;
+       struct iscsi_login *login;
+       struct iscsi_portal_group *tpg = NULL;
+       struct socket *new_sock, *sock;
+       struct kvec iov;
+       struct iscsi_login_req *pdu;
+       struct sockaddr_in sock_in;
+       struct sockaddr_in6 sock_in6;
+
+       flush_signals(current);
+       set_sctp_conn_flag = 0;
+       sock = np->np_socket;
+       ip_proto = np->np_ip_proto;
+       sock_type = np->np_sock_type;
+
+       spin_lock_bh(&np->np_thread_lock);
+       if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+               np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
+               complete(&np->np_restart_comp);
+       } else {
+               np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
+       }
+       spin_unlock_bh(&np->np_thread_lock);
+
+       if (kernel_accept(sock, &new_sock, 0) < 0) {
+               spin_lock_bh(&np->np_thread_lock);
+               if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+                       spin_unlock_bh(&np->np_thread_lock);
+                       complete(&np->np_restart_comp);
+                       /* Get another socket */
+                       return 1;
+               }
+               spin_unlock_bh(&np->np_thread_lock);
+               goto out;
+       }
+       /*
+        * The SCTP stack needs struct socket->file.
+        */
+       if ((np->np_network_transport == ISCSI_SCTP_TCP) ||
+           (np->np_network_transport == ISCSI_SCTP_UDP)) {
+               if (!new_sock->file) {
+                       new_sock->file = kzalloc(
+                                       sizeof(struct file), GFP_KERNEL);
+                       if (!new_sock->file) {
+                               pr_err("Unable to allocate struct"
+                                               " file for SCTP\n");
+                               sock_release(new_sock);
+                               /* Get another socket */
+                               return 1;
+                       }
+                       set_sctp_conn_flag = 1;
+               }
+       }
+
+       iscsi_start_login_thread_timer(np);
+
+       conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
+       if (!conn) {
+               pr_err("Could not allocate memory for"
+                       " new connection\n");
+               if (set_sctp_conn_flag) {
+                       kfree(new_sock->file);
+                       new_sock->file = NULL;
+               }
+               sock_release(new_sock);
+               /* Get another socket */
+               return 1;
+       }
+
+       pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
+       conn->conn_state = TARG_CONN_STATE_FREE;
+       conn->sock = new_sock;
+
+       if (set_sctp_conn_flag)
+               conn->conn_flags |= CONNFLAG_SCTP_STRUCT_FILE;
+
+       pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
+       conn->conn_state = TARG_CONN_STATE_XPT_UP;
+
+       /*
+        * Allocate conn->conn_ops early as a failure calling
+        * iscsit_tx_login_rsp() below will call tx_data().
+        */
+       conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
+       if (!conn->conn_ops) {
+               pr_err("Unable to allocate memory for"
+                       " struct iscsi_conn_ops.\n");
+               goto new_sess_out;
+       }
+       /*
+        * Perform the remaining iSCSI connection initialization items..
+        */
+       if (iscsi_login_init_conn(conn) < 0)
+               goto new_sess_out;
+
+       memset(buffer, 0, ISCSI_HDR_LEN);
+       memset(&iov, 0, sizeof(struct kvec));
+       iov.iov_base    = buffer;
+       iov.iov_len     = ISCSI_HDR_LEN;
+
+       if (rx_data(conn, &iov, 1, ISCSI_HDR_LEN) <= 0) {
+               pr_err("rx_data() returned an error.\n");
+               goto new_sess_out;
+       }
+
+       iscsi_opcode = (buffer[0] & ISCSI_OPCODE_MASK);
+       if (!(iscsi_opcode & ISCSI_OP_LOGIN)) {
+               pr_err("First opcode is not login request,"
+                       " failing login request.\n");
+               goto new_sess_out;
+       }
+
+       pdu                     = (struct iscsi_login_req *) buffer;
+       pdu->cid                = be16_to_cpu(pdu->cid);
+       pdu->tsih               = be16_to_cpu(pdu->tsih);
+       pdu->itt                = be32_to_cpu(pdu->itt);
+       pdu->cmdsn              = be32_to_cpu(pdu->cmdsn);
+       pdu->exp_statsn         = be32_to_cpu(pdu->exp_statsn);
+       /*
+        * Used by iscsit_tx_login_rsp() for Login Resonses PDUs
+        * when Status-Class != 0.
+       */
+       conn->login_itt         = pdu->itt;
+
+       spin_lock_bh(&np->np_thread_lock);
+       if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
+               spin_unlock_bh(&np->np_thread_lock);
+               pr_err("iSCSI Network Portal on %s:%hu currently not"
+                       " active.\n", np->np_ip, np->np_port);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
+               goto new_sess_out;
+       }
+       spin_unlock_bh(&np->np_thread_lock);
+
+       if (np->np_sockaddr.ss_family == AF_INET6) {
+               memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
+
+               if (conn->sock->ops->getname(conn->sock,
+                               (struct sockaddr *)&sock_in6, &err, 1) < 0) {
+                       pr_err("sock_ops->getname() failed.\n");
+                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                                       ISCSI_LOGIN_STATUS_TARGET_ERROR);
+                       goto new_sess_out;
+               }
+#if 0
+               if (!iscsi_ntop6((const unsigned char *)
+                               &sock_in6.sin6_addr.in6_u,
+                               (char *)&conn->ipv6_login_ip[0],
+                               IPV6_ADDRESS_SPACE)) {
+                       pr_err("iscsi_ntop6() failed\n");
+                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                                       ISCSI_LOGIN_STATUS_TARGET_ERROR);
+                       goto new_sess_out;
+               }
+#else
+               pr_debug("Skipping iscsi_ntop6()\n");
+#endif
+       } else {
+               memset(&sock_in, 0, sizeof(struct sockaddr_in));
+
+               if (conn->sock->ops->getname(conn->sock,
+                               (struct sockaddr *)&sock_in, &err, 1) < 0) {
+                       pr_err("sock_ops->getname() failed.\n");
+                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                                       ISCSI_LOGIN_STATUS_TARGET_ERROR);
+                       goto new_sess_out;
+               }
+               sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr);
+               conn->login_port = ntohs(sock_in.sin_port);
+       }
+
+       conn->network_transport = np->np_network_transport;
+
+       pr_debug("Received iSCSI login request from %s on %s Network"
+                       " Portal %s:%hu\n", conn->login_ip,
+               (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP",
+                       np->np_ip, np->np_port);
+
+       pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
+       conn->conn_state        = TARG_CONN_STATE_IN_LOGIN;
+
+       if (iscsi_login_check_initiator_version(conn, pdu->max_version,
+                       pdu->min_version) < 0)
+               goto new_sess_out;
+
+       zero_tsih = (pdu->tsih == 0x0000);
+       if ((zero_tsih)) {
+               /*
+                * This is the leading connection of a new session.
+                * We wait until after authentication to check for
+                * session reinstatement.
+                */
+               if (iscsi_login_zero_tsih_s1(conn, buffer) < 0)
+                       goto new_sess_out;
+       } else {
+               /*
+                * Add a new connection to an existing session.
+                * We check for a non-existant session in
+                * iscsi_login_non_zero_tsih_s2() below based
+                * on ISID/TSIH, but wait until after authentication
+                * to check for connection reinstatement, etc.
+                */
+               if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0)
+                       goto new_sess_out;
+       }
+
+       /*
+        * This will process the first login request, and call
+        * iscsi_target_locate_portal(), and return a valid struct iscsi_login.
+        */
+       login = iscsi_target_init_negotiation(np, conn, buffer);
+       if (!login) {
+               tpg = conn->tpg;
+               goto new_sess_out;
+       }
+
+       tpg = conn->tpg;
+       if (!tpg) {
+               pr_err("Unable to locate struct iscsi_conn->tpg\n");
+               goto new_sess_out;
+       }
+
+       if (zero_tsih) {
+               if (iscsi_login_zero_tsih_s2(conn) < 0) {
+                       iscsi_target_nego_release(login, conn);
+                       goto new_sess_out;
+               }
+       } else {
+               if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0) {
+                       iscsi_target_nego_release(login, conn);
+                       goto old_sess_out;
+               }
+       }
+
+       if (iscsi_target_start_negotiation(login, conn) < 0)
+               goto new_sess_out;
+
+       if (!conn->sess) {
+               pr_err("struct iscsi_conn session pointer is NULL!\n");
+               goto new_sess_out;
+       }
+
+       iscsi_stop_login_thread_timer(np);
+
+       if (signal_pending(current))
+               goto new_sess_out;
+
+       ret = iscsi_post_login_handler(np, conn, zero_tsih);
+
+       if (ret < 0)
+               goto new_sess_out;
+
+       iscsit_deaccess_np(np, tpg);
+       tpg = NULL;
+       /* Get another socket */
+       return 1;
+
+new_sess_out:
+       pr_err("iSCSI Login negotiation failed.\n");
+       iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                                 ISCSI_LOGIN_STATUS_INIT_ERR);
+       if (!zero_tsih || !conn->sess)
+               goto old_sess_out;
+       if (conn->sess->se_sess)
+               transport_free_session(conn->sess->se_sess);
+       if (conn->sess->session_index != 0) {
+               spin_lock_bh(&sess_idr_lock);
+               idr_remove(&sess_idr, conn->sess->session_index);
+               spin_unlock_bh(&sess_idr_lock);
+       }
+       if (conn->sess->sess_ops)
+               kfree(conn->sess->sess_ops);
+       if (conn->sess)
+               kfree(conn->sess);
+old_sess_out:
+       iscsi_stop_login_thread_timer(np);
+       /*
+        * If login negotiation fails check if the Time2Retain timer
+        * needs to be restarted.
+        */
+       if (!zero_tsih && conn->sess) {
+               spin_lock_bh(&conn->sess->conn_lock);
+               if (conn->sess->session_state == TARG_SESS_STATE_FAILED) {
+                       struct se_portal_group *se_tpg =
+                                       &ISCSI_TPG_C(conn)->tpg_se_tpg;
+
+                       atomic_set(&conn->sess->session_continuation, 0);
+                       spin_unlock_bh(&conn->sess->conn_lock);
+                       spin_lock_bh(&se_tpg->session_lock);
+                       iscsit_start_time2retain_handler(conn->sess);
+                       spin_unlock_bh(&se_tpg->session_lock);
+               } else
+                       spin_unlock_bh(&conn->sess->conn_lock);
+               iscsit_dec_session_usage_count(conn->sess);
+       }
+
+       if (!IS_ERR(conn->conn_rx_hash.tfm))
+               crypto_free_hash(conn->conn_rx_hash.tfm);
+       if (!IS_ERR(conn->conn_tx_hash.tfm))
+               crypto_free_hash(conn->conn_tx_hash.tfm);
+
+       if (conn->conn_cpumask)
+               free_cpumask_var(conn->conn_cpumask);
+
+       kfree(conn->conn_ops);
+
+       if (conn->param_list) {
+               iscsi_release_param_list(conn->param_list);
+               conn->param_list = NULL;
+       }
+       if (conn->sock) {
+               if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) {
+                       kfree(conn->sock->file);
+                       conn->sock->file = NULL;
+               }
+               sock_release(conn->sock);
+       }
+       kfree(conn);
+
+       if (tpg) {
+               iscsit_deaccess_np(np, tpg);
+               tpg = NULL;
+       }
+
+out:
+       stop = kthread_should_stop();
+       if (!stop && signal_pending(current)) {
+               spin_lock_bh(&np->np_thread_lock);
+               stop = (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN);
+               spin_unlock_bh(&np->np_thread_lock);
+       }
+       /* Wait for another socket.. */
+       if (!stop)
+               return 1;
+
+       iscsi_stop_login_thread_timer(np);
+       spin_lock_bh(&np->np_thread_lock);
+       np->np_thread_state = ISCSI_NP_THREAD_EXIT;
+       spin_unlock_bh(&np->np_thread_lock);
+       return 0;
+}
+
+int iscsi_target_login_thread(void *arg)
+{
+       struct iscsi_np *np = (struct iscsi_np *)arg;
+       int ret;
+
+       allow_signal(SIGINT);
+
+       while (!kthread_should_stop()) {
+               ret = __iscsi_target_login_thread(np);
+               /*
+                * We break and exit here unless another sock_accept() call
+                * is expected.
+                */
+               if (ret != 1)
+                       break;
+       }
+
+       return 0;
+}
diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h
new file mode 100644 (file)
index 0000000..091dcae
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef ISCSI_TARGET_LOGIN_H
+#define ISCSI_TARGET_LOGIN_H
+
+extern int iscsi_login_setup_crypto(struct iscsi_conn *);
+extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *);
+extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32);
+extern int iscsi_target_setup_login_socket(struct iscsi_np *,
+                               struct __kernel_sockaddr_storage *);
+extern int iscsi_target_login_thread(void *);
+extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *);
+
+#endif   /*** ISCSI_TARGET_LOGIN_H ***/
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
new file mode 100644 (file)
index 0000000..713a4d2
--- /dev/null
@@ -0,0 +1,1067 @@
+/*******************************************************************************
+ * This file contains main functions related to iSCSI Parameter negotiation.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <linux/ctype.h>
+#include <scsi/iscsi_proto.h>
+#include <target/target_core_base.h>
+#include <target/target_core_tpg.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_parameters.h"
+#include "iscsi_target_login.h"
+#include "iscsi_target_nego.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target.h"
+#include "iscsi_target_auth.h"
+
+#define MAX_LOGIN_PDUS  7
+#define TEXT_LEN       4096
+
+void convert_null_to_semi(char *buf, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (buf[i] == '\0')
+                       buf[i] = ';';
+}
+
+int strlen_semi(char *buf)
+{
+       int i = 0;
+
+       while (buf[i] != '\0') {
+               if (buf[i] == ';')
+                       return i;
+               i++;
+       }
+
+       return -1;
+}
+
+int extract_param(
+       const char *in_buf,
+       const char *pattern,
+       unsigned int max_length,
+       char *out_buf,
+       unsigned char *type)
+{
+       char *ptr;
+       int len;
+
+       if (!in_buf || !pattern || !out_buf || !type)
+               return -1;
+
+       ptr = strstr(in_buf, pattern);
+       if (!ptr)
+               return -1;
+
+       ptr = strstr(ptr, "=");
+       if (!ptr)
+               return -1;
+
+       ptr += 1;
+       if (*ptr == '0' && (*(ptr+1) == 'x' || *(ptr+1) == 'X')) {
+               ptr += 2; /* skip 0x */
+               *type = HEX;
+       } else
+               *type = DECIMAL;
+
+       len = strlen_semi(ptr);
+       if (len < 0)
+               return -1;
+
+       if (len > max_length) {
+               pr_err("Length of input: %d exeeds max_length:"
+                       " %d\n", len, max_length);
+               return -1;
+       }
+       memcpy(out_buf, ptr, len);
+       out_buf[len] = '\0';
+
+       return 0;
+}
+
+static u32 iscsi_handle_authentication(
+       struct iscsi_conn *conn,
+       char *in_buf,
+       char *out_buf,
+       int in_length,
+       int *out_length,
+       unsigned char *authtype)
+{
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_node_auth *auth;
+       struct iscsi_node_acl *iscsi_nacl;
+       struct se_node_acl *se_nacl;
+
+       if (!sess->sess_ops->SessionType) {
+               /*
+                * For SessionType=Normal
+                */
+               se_nacl = conn->sess->se_sess->se_node_acl;
+               if (!se_nacl) {
+                       pr_err("Unable to locate struct se_node_acl for"
+                                       " CHAP auth\n");
+                       return -1;
+               }
+               iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl,
+                               se_node_acl);
+               if (!iscsi_nacl) {
+                       pr_err("Unable to locate struct iscsi_node_acl for"
+                                       " CHAP auth\n");
+                       return -1;
+               }
+
+               auth = ISCSI_NODE_AUTH(iscsi_nacl);
+       } else {
+               /*
+                * For SessionType=Discovery
+                */
+               auth = &iscsit_global->discovery_acl.node_auth;
+       }
+
+       if (strstr("CHAP", authtype))
+               strcpy(conn->sess->auth_type, "CHAP");
+       else
+               strcpy(conn->sess->auth_type, NONE);
+
+       if (strstr("None", authtype))
+               return 1;
+#ifdef CANSRP
+       else if (strstr("SRP", authtype))
+               return srp_main_loop(conn, auth, in_buf, out_buf,
+                               &in_length, out_length);
+#endif
+       else if (strstr("CHAP", authtype))
+               return chap_main_loop(conn, auth, in_buf, out_buf,
+                               &in_length, out_length);
+       else if (strstr("SPKM1", authtype))
+               return 2;
+       else if (strstr("SPKM2", authtype))
+               return 2;
+       else if (strstr("KRB5", authtype))
+               return 2;
+       else
+               return 2;
+}
+
+static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn)
+{
+       kfree(conn->auth_protocol);
+}
+
+static int iscsi_target_check_login_request(
+       struct iscsi_conn *conn,
+       struct iscsi_login *login)
+{
+       int req_csg, req_nsg, rsp_csg, rsp_nsg;
+       u32 payload_length;
+       struct iscsi_login_req *login_req;
+       struct iscsi_login_rsp *login_rsp;
+
+       login_req = (struct iscsi_login_req *) login->req;
+       login_rsp = (struct iscsi_login_rsp *) login->rsp;
+       payload_length = ntoh24(login_req->dlength);
+
+       switch (login_req->opcode & ISCSI_OPCODE_MASK) {
+       case ISCSI_OP_LOGIN:
+               break;
+       default:
+               pr_err("Received unknown opcode 0x%02x.\n",
+                               login_req->opcode & ISCSI_OPCODE_MASK);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_INIT_ERR);
+               return -1;
+       }
+
+       if ((login_req->flags & ISCSI_FLAG_LOGIN_CONTINUE) &&
+           (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) {
+               pr_err("Login request has both ISCSI_FLAG_LOGIN_CONTINUE"
+                       " and ISCSI_FLAG_LOGIN_TRANSIT set, protocol error.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_INIT_ERR);
+               return -1;
+       }
+
+       req_csg = (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
+       rsp_csg = (login_rsp->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
+       req_nsg = (login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK);
+       rsp_nsg = (login_rsp->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK);
+
+       if (req_csg != login->current_stage) {
+               pr_err("Initiator unexpectedly changed login stage"
+                       " from %d to %d, login failed.\n", login->current_stage,
+                       req_csg);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_INIT_ERR);
+               return -1;
+       }
+
+       if ((req_nsg == 2) || (req_csg >= 2) ||
+          ((login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT) &&
+           (req_nsg <= req_csg))) {
+               pr_err("Illegal login_req->flags Combination, CSG: %d,"
+                       " NSG: %d, ISCSI_FLAG_LOGIN_TRANSIT: %d.\n", req_csg,
+                       req_nsg, (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT));
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_INIT_ERR);
+               return -1;
+       }
+
+       if ((login_req->max_version != login->version_max) ||
+           (login_req->min_version != login->version_min)) {
+               pr_err("Login request changed Version Max/Nin"
+                       " unexpectedly to 0x%02x/0x%02x, protocol error\n",
+                       login_req->max_version, login_req->min_version);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_INIT_ERR);
+               return -1;
+       }
+
+       if (memcmp(login_req->isid, login->isid, 6) != 0) {
+               pr_err("Login request changed ISID unexpectedly,"
+                               " protocol error.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_INIT_ERR);
+               return -1;
+       }
+
+       if (login_req->itt != login->init_task_tag) {
+               pr_err("Login request changed ITT unexpectedly to"
+                       " 0x%08x, protocol error.\n", login_req->itt);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_INIT_ERR);
+               return -1;
+       }
+
+       if (payload_length > MAX_KEY_VALUE_PAIRS) {
+               pr_err("Login request payload exceeds default"
+                       " MaxRecvDataSegmentLength: %u, protocol error.\n",
+                               MAX_KEY_VALUE_PAIRS);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int iscsi_target_check_first_request(
+       struct iscsi_conn *conn,
+       struct iscsi_login *login)
+{
+       struct iscsi_param *param = NULL;
+       struct se_node_acl *se_nacl;
+
+       login->first_request = 0;
+
+       list_for_each_entry(param, &conn->param_list->param_list, p_list) {
+               if (!strncmp(param->name, SESSIONTYPE, 11)) {
+                       if (!IS_PSTATE_ACCEPTOR(param)) {
+                               pr_err("SessionType key not received"
+                                       " in first login request.\n");
+                               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                                       ISCSI_LOGIN_STATUS_MISSING_FIELDS);
+                               return -1;
+                       }
+                       if (!strncmp(param->value, DISCOVERY, 9))
+                               return 0;
+               }
+
+               if (!strncmp(param->name, INITIATORNAME, 13)) {
+                       if (!IS_PSTATE_ACCEPTOR(param)) {
+                               if (!login->leading_connection)
+                                       continue;
+
+                               pr_err("InitiatorName key not received"
+                                       " in first login request.\n");
+                               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                                       ISCSI_LOGIN_STATUS_MISSING_FIELDS);
+                               return -1;
+                       }
+
+                       /*
+                        * For non-leading connections, double check that the
+                        * received InitiatorName matches the existing session's
+                        * struct iscsi_node_acl.
+                        */
+                       if (!login->leading_connection) {
+                               se_nacl = conn->sess->se_sess->se_node_acl;
+                               if (!se_nacl) {
+                                       pr_err("Unable to locate"
+                                               " struct se_node_acl\n");
+                                       iscsit_tx_login_rsp(conn,
+                                                       ISCSI_STATUS_CLS_INITIATOR_ERR,
+                                                       ISCSI_LOGIN_STATUS_TGT_NOT_FOUND);
+                                       return -1;
+                               }
+
+                               if (strcmp(param->value,
+                                               se_nacl->initiatorname)) {
+                                       pr_err("Incorrect"
+                                               " InitiatorName: %s for this"
+                                               " iSCSI Initiator Node.\n",
+                                               param->value);
+                                       iscsit_tx_login_rsp(conn,
+                                                       ISCSI_STATUS_CLS_INITIATOR_ERR,
+                                                       ISCSI_LOGIN_STATUS_TGT_NOT_FOUND);
+                                       return -1;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+       u32 padding = 0;
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_login_rsp *login_rsp;
+
+       login_rsp = (struct iscsi_login_rsp *) login->rsp;
+
+       login_rsp->opcode               = ISCSI_OP_LOGIN_RSP;
+       hton24(login_rsp->dlength, login->rsp_length);
+       memcpy(login_rsp->isid, login->isid, 6);
+       login_rsp->tsih                 = cpu_to_be16(login->tsih);
+       login_rsp->itt                  = cpu_to_be32(login->init_task_tag);
+       login_rsp->statsn               = cpu_to_be32(conn->stat_sn++);
+       login_rsp->exp_cmdsn            = cpu_to_be32(conn->sess->exp_cmd_sn);
+       login_rsp->max_cmdsn            = cpu_to_be32(conn->sess->max_cmd_sn);
+
+       pr_debug("Sending Login Response, Flags: 0x%02x, ITT: 0x%08x,"
+               " ExpCmdSN; 0x%08x, MaxCmdSN: 0x%08x, StatSN: 0x%08x, Length:"
+               " %u\n", login_rsp->flags, ntohl(login_rsp->itt),
+               ntohl(login_rsp->exp_cmdsn), ntohl(login_rsp->max_cmdsn),
+               ntohl(login_rsp->statsn), login->rsp_length);
+
+       padding = ((-login->rsp_length) & 3);
+
+       if (iscsi_login_tx_data(
+                       conn,
+                       login->rsp,
+                       login->rsp_buf,
+                       login->rsp_length + padding) < 0)
+               return -1;
+
+       login->rsp_length               = 0;
+       login_rsp->tsih                 = be16_to_cpu(login_rsp->tsih);
+       login_rsp->itt                  = be32_to_cpu(login_rsp->itt);
+       login_rsp->statsn               = be32_to_cpu(login_rsp->statsn);
+       mutex_lock(&sess->cmdsn_mutex);
+       login_rsp->exp_cmdsn            = be32_to_cpu(sess->exp_cmd_sn);
+       login_rsp->max_cmdsn            = be32_to_cpu(sess->max_cmd_sn);
+       mutex_unlock(&sess->cmdsn_mutex);
+
+       return 0;
+}
+
+static int iscsi_target_do_rx_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+       u32 padding = 0, payload_length;
+       struct iscsi_login_req *login_req;
+
+       if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
+               return -1;
+
+       login_req = (struct iscsi_login_req *) login->req;
+       payload_length                  = ntoh24(login_req->dlength);
+       login_req->tsih                 = be16_to_cpu(login_req->tsih);
+       login_req->itt                  = be32_to_cpu(login_req->itt);
+       login_req->cid                  = be16_to_cpu(login_req->cid);
+       login_req->cmdsn                = be32_to_cpu(login_req->cmdsn);
+       login_req->exp_statsn           = be32_to_cpu(login_req->exp_statsn);
+
+       pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
+               " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
+                login_req->flags, login_req->itt, login_req->cmdsn,
+                login_req->exp_statsn, login_req->cid, payload_length);
+
+       if (iscsi_target_check_login_request(conn, login) < 0)
+               return -1;
+
+       padding = ((-payload_length) & 3);
+       memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
+
+       if (iscsi_login_rx_data(
+                       conn,
+                       login->req_buf,
+                       payload_length + padding) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+       if (iscsi_target_do_tx_login_io(conn, login) < 0)
+               return -1;
+
+       if (iscsi_target_do_rx_login_io(conn, login) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int iscsi_target_get_initial_payload(
+       struct iscsi_conn *conn,
+       struct iscsi_login *login)
+{
+       u32 padding = 0, payload_length;
+       struct iscsi_login_req *login_req;
+
+       login_req = (struct iscsi_login_req *) login->req;
+       payload_length = ntoh24(login_req->dlength);
+
+       pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
+               " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
+               login_req->flags, login_req->itt, login_req->cmdsn,
+               login_req->exp_statsn, payload_length);
+
+       if (iscsi_target_check_login_request(conn, login) < 0)
+               return -1;
+
+       padding = ((-payload_length) & 3);
+
+       if (iscsi_login_rx_data(
+                       conn,
+                       login->req_buf,
+                       payload_length + padding) < 0)
+               return -1;
+
+       return 0;
+}
+
+/*
+ *     NOTE: We check for existing sessions or connections AFTER the initiator
+ *     has been successfully authenticated in order to protect against faked
+ *     ISID/TSIH combinations.
+ */
+static int iscsi_target_check_for_existing_instances(
+       struct iscsi_conn *conn,
+       struct iscsi_login *login)
+{
+       if (login->checked_for_existing)
+               return 0;
+
+       login->checked_for_existing = 1;
+
+       if (!login->tsih)
+               return iscsi_check_for_session_reinstatement(conn);
+       else
+               return iscsi_login_post_auth_non_zero_tsih(conn, login->cid,
+                               login->initial_exp_statsn);
+}
+
+static int iscsi_target_do_authentication(
+       struct iscsi_conn *conn,
+       struct iscsi_login *login)
+{
+       int authret;
+       u32 payload_length;
+       struct iscsi_param *param;
+       struct iscsi_login_req *login_req;
+       struct iscsi_login_rsp *login_rsp;
+
+       login_req = (struct iscsi_login_req *) login->req;
+       login_rsp = (struct iscsi_login_rsp *) login->rsp;
+       payload_length = ntoh24(login_req->dlength);
+
+       param = iscsi_find_param_from_key(AUTHMETHOD, conn->param_list);
+       if (!param)
+               return -1;
+
+       authret = iscsi_handle_authentication(
+                       conn,
+                       login->req_buf,
+                       login->rsp_buf,
+                       payload_length,
+                       &login->rsp_length,
+                       param->value);
+       switch (authret) {
+       case 0:
+               pr_debug("Received OK response"
+               " from LIO Authentication, continuing.\n");
+               break;
+       case 1:
+               pr_debug("iSCSI security negotiation"
+                       " completed sucessfully.\n");
+               login->auth_complete = 1;
+               if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) &&
+                   (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) {
+                       login_rsp->flags |= (ISCSI_FLAG_LOGIN_NEXT_STAGE1 |
+                                            ISCSI_FLAG_LOGIN_TRANSIT);
+                       login->current_stage = 1;
+               }
+               return iscsi_target_check_for_existing_instances(
+                               conn, login);
+       case 2:
+               pr_err("Security negotiation"
+                       " failed.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_AUTH_FAILED);
+               return -1;
+       default:
+               pr_err("Received unknown error %d from LIO"
+                               " Authentication\n", authret);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_TARGET_ERROR);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int iscsi_target_handle_csg_zero(
+       struct iscsi_conn *conn,
+       struct iscsi_login *login)
+{
+       int ret;
+       u32 payload_length;
+       struct iscsi_param *param;
+       struct iscsi_login_req *login_req;
+       struct iscsi_login_rsp *login_rsp;
+
+       login_req = (struct iscsi_login_req *) login->req;
+       login_rsp = (struct iscsi_login_rsp *) login->rsp;
+       payload_length = ntoh24(login_req->dlength);
+
+       param = iscsi_find_param_from_key(AUTHMETHOD, conn->param_list);
+       if (!param)
+               return -1;
+
+       ret = iscsi_decode_text_input(
+                       PHASE_SECURITY|PHASE_DECLARATIVE,
+                       SENDER_INITIATOR|SENDER_RECEIVER,
+                       login->req_buf,
+                       payload_length,
+                       conn->param_list);
+       if (ret < 0)
+               return -1;
+
+       if (ret > 0) {
+               if (login->auth_complete) {
+                       pr_err("Initiator has already been"
+                               " successfully authenticated, but is still"
+                               " sending %s keys.\n", param->value);
+                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                                       ISCSI_LOGIN_STATUS_INIT_ERR);
+                       return -1;
+               }
+
+               goto do_auth;
+       }
+
+       if (login->first_request)
+               if (iscsi_target_check_first_request(conn, login) < 0)
+                       return -1;
+
+       ret = iscsi_encode_text_output(
+                       PHASE_SECURITY|PHASE_DECLARATIVE,
+                       SENDER_TARGET,
+                       login->rsp_buf,
+                       &login->rsp_length,
+                       conn->param_list);
+       if (ret < 0)
+               return -1;
+
+       if (!iscsi_check_negotiated_keys(conn->param_list)) {
+               if (ISCSI_TPG_ATTRIB(ISCSI_TPG_C(conn))->authentication &&
+                   !strncmp(param->value, NONE, 4)) {
+                       pr_err("Initiator sent AuthMethod=None but"
+                               " Target is enforcing iSCSI Authentication,"
+                                       " login failed.\n");
+                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                                       ISCSI_LOGIN_STATUS_AUTH_FAILED);
+                       return -1;
+               }
+
+               if (ISCSI_TPG_ATTRIB(ISCSI_TPG_C(conn))->authentication &&
+                   !login->auth_complete)
+                       return 0;
+
+               if (strncmp(param->value, NONE, 4) && !login->auth_complete)
+                       return 0;
+
+               if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) &&
+                   (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) {
+                       login_rsp->flags |= ISCSI_FLAG_LOGIN_NEXT_STAGE1 |
+                                           ISCSI_FLAG_LOGIN_TRANSIT;
+                       login->current_stage = 1;
+               }
+       }
+
+       return 0;
+do_auth:
+       return iscsi_target_do_authentication(conn, login);
+}
+
+static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+       int ret;
+       u32 payload_length;
+       struct iscsi_login_req *login_req;
+       struct iscsi_login_rsp *login_rsp;
+
+       login_req = (struct iscsi_login_req *) login->req;
+       login_rsp = (struct iscsi_login_rsp *) login->rsp;
+       payload_length = ntoh24(login_req->dlength);
+
+       ret = iscsi_decode_text_input(
+                       PHASE_OPERATIONAL|PHASE_DECLARATIVE,
+                       SENDER_INITIATOR|SENDER_RECEIVER,
+                       login->req_buf,
+                       payload_length,
+                       conn->param_list);
+       if (ret < 0)
+               return -1;
+
+       if (login->first_request)
+               if (iscsi_target_check_first_request(conn, login) < 0)
+                       return -1;
+
+       if (iscsi_target_check_for_existing_instances(conn, login) < 0)
+               return -1;
+
+       ret = iscsi_encode_text_output(
+                       PHASE_OPERATIONAL|PHASE_DECLARATIVE,
+                       SENDER_TARGET,
+                       login->rsp_buf,
+                       &login->rsp_length,
+                       conn->param_list);
+       if (ret < 0)
+               return -1;
+
+       if (!login->auth_complete &&
+            ISCSI_TPG_ATTRIB(ISCSI_TPG_C(conn))->authentication) {
+               pr_err("Initiator is requesting CSG: 1, has not been"
+                        " successfully authenticated, and the Target is"
+                       " enforcing iSCSI Authentication, login failed.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_AUTH_FAILED);
+               return -1;
+       }
+
+       if (!iscsi_check_negotiated_keys(conn->param_list))
+               if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE3) &&
+                   (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT))
+                       login_rsp->flags |= ISCSI_FLAG_LOGIN_NEXT_STAGE3 |
+                                           ISCSI_FLAG_LOGIN_TRANSIT;
+
+       return 0;
+}
+
+static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+       int pdu_count = 0;
+       struct iscsi_login_req *login_req;
+       struct iscsi_login_rsp *login_rsp;
+
+       login_req = (struct iscsi_login_req *) login->req;
+       login_rsp = (struct iscsi_login_rsp *) login->rsp;
+
+       while (1) {
+               if (++pdu_count > MAX_LOGIN_PDUS) {
+                       pr_err("MAX_LOGIN_PDUS count reached.\n");
+                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                                       ISCSI_LOGIN_STATUS_TARGET_ERROR);
+                       return -1;
+               }
+
+               switch ((login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2) {
+               case 0:
+                       login_rsp->flags |= (0 & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK);
+                       if (iscsi_target_handle_csg_zero(conn, login) < 0)
+                               return -1;
+                       break;
+               case 1:
+                       login_rsp->flags |= ISCSI_FLAG_LOGIN_CURRENT_STAGE1;
+                       if (iscsi_target_handle_csg_one(conn, login) < 0)
+                               return -1;
+                       if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
+                               login->tsih = conn->sess->tsih;
+                               if (iscsi_target_do_tx_login_io(conn,
+                                               login) < 0)
+                                       return -1;
+                               return 0;
+                       }
+                       break;
+               default:
+                       pr_err("Illegal CSG: %d received from"
+                               " Initiator, protocol error.\n",
+                               (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK)
+                               >> 2);
+                       break;
+               }
+
+               if (iscsi_target_do_login_io(conn, login) < 0)
+                       return -1;
+
+               if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
+                       login_rsp->flags &= ~ISCSI_FLAG_LOGIN_TRANSIT;
+                       login_rsp->flags &= ~ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
+               }
+       }
+
+       return 0;
+}
+
+static void iscsi_initiatorname_tolower(
+       char *param_buf)
+{
+       char *c;
+       u32 iqn_size = strlen(param_buf), i;
+
+       for (i = 0; i < iqn_size; i++) {
+               c = (char *)&param_buf[i];
+               if (!isupper(*c))
+                       continue;
+
+               *c = tolower(*c);
+       }
+}
+
+/*
+ * Processes the first Login Request..
+ */
+static int iscsi_target_locate_portal(
+       struct iscsi_np *np,
+       struct iscsi_conn *conn,
+       struct iscsi_login *login)
+{
+       char *i_buf = NULL, *s_buf = NULL, *t_buf = NULL;
+       char *tmpbuf, *start = NULL, *end = NULL, *key, *value;
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_tiqn *tiqn;
+       struct iscsi_login_req *login_req;
+       struct iscsi_targ_login_rsp *login_rsp;
+       u32 payload_length;
+       int sessiontype = 0, ret = 0;
+
+       login_req = (struct iscsi_login_req *) login->req;
+       login_rsp = (struct iscsi_targ_login_rsp *) login->rsp;
+       payload_length = ntoh24(login_req->dlength);
+
+       login->first_request    = 1;
+       login->leading_connection = (!login_req->tsih) ? 1 : 0;
+       login->current_stage    =
+               (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
+       login->version_min      = login_req->min_version;
+       login->version_max      = login_req->max_version;
+       memcpy(login->isid, login_req->isid, 6);
+       login->cmd_sn           = login_req->cmdsn;
+       login->init_task_tag    = login_req->itt;
+       login->initial_exp_statsn = login_req->exp_statsn;
+       login->cid              = login_req->cid;
+       login->tsih             = login_req->tsih;
+
+       if (iscsi_target_get_initial_payload(conn, login) < 0)
+               return -1;
+
+       tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL);
+       if (!tmpbuf) {
+               pr_err("Unable to allocate memory for tmpbuf.\n");
+               return -1;
+       }
+
+       memcpy(tmpbuf, login->req_buf, payload_length);
+       tmpbuf[payload_length] = '\0';
+       start = tmpbuf;
+       end = (start + payload_length);
+
+       /*
+        * Locate the initial keys expected from the Initiator node in
+        * the first login request in order to progress with the login phase.
+        */
+       while (start < end) {
+               if (iscsi_extract_key_value(start, &key, &value) < 0) {
+                       ret = -1;
+                       goto out;
+               }
+
+               if (!strncmp(key, "InitiatorName", 13))
+                       i_buf = value;
+               else if (!strncmp(key, "SessionType", 11))
+                       s_buf = value;
+               else if (!strncmp(key, "TargetName", 10))
+                       t_buf = value;
+
+               start += strlen(key) + strlen(value) + 2;
+       }
+
+       /*
+        * See 5.3.  Login Phase.
+        */
+       if (!i_buf) {
+               pr_err("InitiatorName key not received"
+                       " in first login request.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                       ISCSI_LOGIN_STATUS_MISSING_FIELDS);
+               ret = -1;
+               goto out;
+       }
+       /*
+        * Convert the incoming InitiatorName to lowercase following
+        * RFC-3720 3.2.6.1. section c) that says that iSCSI IQNs
+        * are NOT case sensitive.
+        */
+       iscsi_initiatorname_tolower(i_buf);
+
+       if (!s_buf) {
+               if (!login->leading_connection)
+                       goto get_target;
+
+               pr_err("SessionType key not received"
+                       " in first login request.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                       ISCSI_LOGIN_STATUS_MISSING_FIELDS);
+               ret = -1;
+               goto out;
+       }
+
+       /*
+        * Use default portal group for discovery sessions.
+        */
+       sessiontype = strncmp(s_buf, DISCOVERY, 9);
+       if (!sessiontype) {
+               conn->tpg = iscsit_global->discovery_tpg;
+               if (!login->leading_connection)
+                       goto get_target;
+
+               sess->sess_ops->SessionType = 1;
+               /*
+                * Setup crc32c modules from libcrypto
+                */
+               if (iscsi_login_setup_crypto(conn) < 0) {
+                       pr_err("iscsi_login_setup_crypto() failed\n");
+                       ret = -1;
+                       goto out;
+               }
+               /*
+                * Serialize access across the discovery struct iscsi_portal_group to
+                * process login attempt.
+                */
+               if (iscsit_access_np(np, conn->tpg) < 0) {
+                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
+                       ret = -1;
+                       goto out;
+               }
+               ret = 0;
+               goto out;
+       }
+
+get_target:
+       if (!t_buf) {
+               pr_err("TargetName key not received"
+                       " in first login request while"
+                       " SessionType=Normal.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                       ISCSI_LOGIN_STATUS_MISSING_FIELDS);
+               ret = -1;
+               goto out;
+       }
+
+       /*
+        * Locate Target IQN from Storage Node.
+        */
+       tiqn = iscsit_get_tiqn_for_login(t_buf);
+       if (!tiqn) {
+               pr_err("Unable to locate Target IQN: %s in"
+                       " Storage Node\n", t_buf);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
+               ret = -1;
+               goto out;
+       }
+       pr_debug("Located Storage Object: %s\n", tiqn->tiqn);
+
+       /*
+        * Locate Target Portal Group from Storage Node.
+        */
+       conn->tpg = iscsit_get_tpg_from_np(tiqn, np);
+       if (!conn->tpg) {
+               pr_err("Unable to locate Target Portal Group"
+                               " on %s\n", tiqn->tiqn);
+               iscsit_put_tiqn_for_login(tiqn);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
+               ret = -1;
+               goto out;
+       }
+       pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt);
+       /*
+        * Setup crc32c modules from libcrypto
+        */
+       if (iscsi_login_setup_crypto(conn) < 0) {
+               pr_err("iscsi_login_setup_crypto() failed\n");
+               ret = -1;
+               goto out;
+       }
+       /*
+        * Serialize access across the struct iscsi_portal_group to
+        * process login attempt.
+        */
+       if (iscsit_access_np(np, conn->tpg) < 0) {
+               iscsit_put_tiqn_for_login(tiqn);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
+               ret = -1;
+               conn->tpg = NULL;
+               goto out;
+       }
+
+       /*
+        * conn->sess->node_acl will be set when the referenced
+        * struct iscsi_session is located from received ISID+TSIH in
+        * iscsi_login_non_zero_tsih_s2().
+        */
+       if (!login->leading_connection) {
+               ret = 0;
+               goto out;
+       }
+
+       /*
+        * This value is required in iscsi_login_zero_tsih_s2()
+        */
+       sess->sess_ops->SessionType = 0;
+
+       /*
+        * Locate incoming Initiator IQN reference from Storage Node.
+        */
+       sess->se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+                       &conn->tpg->tpg_se_tpg, i_buf);
+       if (!sess->se_sess->se_node_acl) {
+               pr_err("iSCSI Initiator Node: %s is not authorized to"
+                       " access iSCSI target portal group: %hu.\n",
+                               i_buf, conn->tpg->tpgt);
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                               ISCSI_LOGIN_STATUS_TGT_FORBIDDEN);
+               ret = -1;
+               goto out;
+       }
+
+       ret = 0;
+out:
+       kfree(tmpbuf);
+       return ret;
+}
+
+struct iscsi_login *iscsi_target_init_negotiation(
+       struct iscsi_np *np,
+       struct iscsi_conn *conn,
+       char *login_pdu)
+{
+       struct iscsi_login *login;
+
+       login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
+       if (!login) {
+               pr_err("Unable to allocate memory for struct iscsi_login.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               goto out;
+       }
+
+       login->req = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
+       if (!login->req) {
+               pr_err("Unable to allocate memory for Login Request.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               goto out;
+       }
+       memcpy(login->req, login_pdu, ISCSI_HDR_LEN);
+
+       login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+       if (!login->req_buf) {
+               pr_err("Unable to allocate memory for response buffer.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               goto out;
+       }
+       /*
+        * SessionType: Discovery
+        *
+        *      Locates Default Portal
+        *
+        * SessionType: Normal
+        *
+        *      Locates Target Portal from NP -> Target IQN
+        */
+       if (iscsi_target_locate_portal(np, conn, login) < 0) {
+               pr_err("iSCSI Login negotiation failed.\n");
+               goto out;
+       }
+
+       return login;
+out:
+       kfree(login->req);
+       kfree(login->req_buf);
+       kfree(login);
+
+       return NULL;
+}
+
+int iscsi_target_start_negotiation(
+       struct iscsi_login *login,
+       struct iscsi_conn *conn)
+{
+       int ret = -1;
+
+       login->rsp = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
+       if (!login->rsp) {
+               pr_err("Unable to allocate memory for"
+                               " Login Response.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               ret = -1;
+               goto out;
+       }
+
+       login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+       if (!login->rsp_buf) {
+               pr_err("Unable to allocate memory for"
+                       " request buffer.\n");
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               ret = -1;
+               goto out;
+       }
+
+       ret = iscsi_target_do_login(conn, login);
+out:
+       if (ret != 0)
+               iscsi_remove_failed_auth_entry(conn);
+
+       iscsi_target_nego_release(login, conn);
+       return ret;
+}
+
+void iscsi_target_nego_release(
+       struct iscsi_login *login,
+       struct iscsi_conn *conn)
+{
+       kfree(login->req);
+       kfree(login->rsp);
+       kfree(login->req_buf);
+       kfree(login->rsp_buf);
+       kfree(login);
+}
diff --git a/drivers/target/iscsi/iscsi_target_nego.h b/drivers/target/iscsi/iscsi_target_nego.h
new file mode 100644 (file)
index 0000000..92e133a
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef ISCSI_TARGET_NEGO_H
+#define ISCSI_TARGET_NEGO_H
+
+#define DECIMAL         0
+#define HEX             1
+
+extern void convert_null_to_semi(char *, int);
+extern int extract_param(const char *, const char *, unsigned int, char *,
+               unsigned char *);
+extern struct iscsi_login *iscsi_target_init_negotiation(
+               struct iscsi_np *, struct iscsi_conn *, char *);
+extern int iscsi_target_start_negotiation(
+               struct iscsi_login *, struct iscsi_conn *);
+extern void iscsi_target_nego_release(
+               struct iscsi_login *, struct iscsi_conn *);
+
+#endif /* ISCSI_TARGET_NEGO_H */
diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.c b/drivers/target/iscsi/iscsi_target_nodeattrib.c
new file mode 100644 (file)
index 0000000..aeafbe0
--- /dev/null
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * This file contains the main functions related to Initiator Node Attributes.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_device.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target_nodeattrib.h"
+
+static inline char *iscsit_na_get_initiatorname(
+       struct iscsi_node_acl *nacl)
+{
+       struct se_node_acl *se_nacl = &nacl->se_node_acl;
+
+       return &se_nacl->initiatorname[0];
+}
+
+void iscsit_set_default_node_attribues(
+       struct iscsi_node_acl *acl)
+{
+       struct iscsi_node_attrib *a = &acl->node_attrib;
+
+       a->dataout_timeout = NA_DATAOUT_TIMEOUT;
+       a->dataout_timeout_retries = NA_DATAOUT_TIMEOUT_RETRIES;
+       a->nopin_timeout = NA_NOPIN_TIMEOUT;
+       a->nopin_response_timeout = NA_NOPIN_RESPONSE_TIMEOUT;
+       a->random_datain_pdu_offsets = NA_RANDOM_DATAIN_PDU_OFFSETS;
+       a->random_datain_seq_offsets = NA_RANDOM_DATAIN_SEQ_OFFSETS;
+       a->random_r2t_offsets = NA_RANDOM_R2T_OFFSETS;
+       a->default_erl = NA_DEFAULT_ERL;
+}
+
+extern int iscsit_na_dataout_timeout(
+       struct iscsi_node_acl *acl,
+       u32 dataout_timeout)
+{
+       struct iscsi_node_attrib *a = &acl->node_attrib;
+
+       if (dataout_timeout > NA_DATAOUT_TIMEOUT_MAX) {
+               pr_err("Requested DataOut Timeout %u larger than"
+                       " maximum %u\n", dataout_timeout,
+                       NA_DATAOUT_TIMEOUT_MAX);
+               return -EINVAL;
+       } else if (dataout_timeout < NA_DATAOUT_TIMEOUT_MIX) {
+               pr_err("Requested DataOut Timeout %u smaller than"
+                       " minimum %u\n", dataout_timeout,
+                       NA_DATAOUT_TIMEOUT_MIX);
+               return -EINVAL;
+       }
+
+       a->dataout_timeout = dataout_timeout;
+       pr_debug("Set DataOut Timeout to %u for Initiator Node"
+               " %s\n", a->dataout_timeout, iscsit_na_get_initiatorname(acl));
+
+       return 0;
+}
+
+extern int iscsit_na_dataout_timeout_retries(
+       struct iscsi_node_acl *acl,
+       u32 dataout_timeout_retries)
+{
+       struct iscsi_node_attrib *a = &acl->node_attrib;
+
+       if (dataout_timeout_retries > NA_DATAOUT_TIMEOUT_RETRIES_MAX) {
+               pr_err("Requested DataOut Timeout Retries %u larger"
+                       " than maximum %u", dataout_timeout_retries,
+                               NA_DATAOUT_TIMEOUT_RETRIES_MAX);
+               return -EINVAL;
+       } else if (dataout_timeout_retries < NA_DATAOUT_TIMEOUT_RETRIES_MIN) {
+               pr_err("Requested DataOut Timeout Retries %u smaller"
+                       " than minimum %u", dataout_timeout_retries,
+                               NA_DATAOUT_TIMEOUT_RETRIES_MIN);
+               return -EINVAL;
+       }
+
+       a->dataout_timeout_retries = dataout_timeout_retries;
+       pr_debug("Set DataOut Timeout Retries to %u for"
+               " Initiator Node %s\n", a->dataout_timeout_retries,
+               iscsit_na_get_initiatorname(acl));
+
+       return 0;
+}
+
+extern int iscsit_na_nopin_timeout(
+       struct iscsi_node_acl *acl,
+       u32 nopin_timeout)
+{
+       struct iscsi_node_attrib *a = &acl->node_attrib;
+       struct iscsi_session *sess;
+       struct iscsi_conn *conn;
+       struct se_node_acl *se_nacl = &a->nacl->se_node_acl;
+       struct se_session *se_sess;
+       u32 orig_nopin_timeout = a->nopin_timeout;
+
+       if (nopin_timeout > NA_NOPIN_TIMEOUT_MAX) {
+               pr_err("Requested NopIn Timeout %u larger than maximum"
+                       " %u\n", nopin_timeout, NA_NOPIN_TIMEOUT_MAX);
+               return -EINVAL;
+       } else if ((nopin_timeout < NA_NOPIN_TIMEOUT_MIN) &&
+                  (nopin_timeout != 0)) {
+               pr_err("Requested NopIn Timeout %u smaller than"
+                       " minimum %u and not 0\n", nopin_timeout,
+                       NA_NOPIN_TIMEOUT_MIN);
+               return -EINVAL;
+       }
+
+       a->nopin_timeout = nopin_timeout;
+       pr_debug("Set NopIn Timeout to %u for Initiator"
+               " Node %s\n", a->nopin_timeout,
+               iscsit_na_get_initiatorname(acl));
+       /*
+        * Reenable disabled nopin_timeout timer for all iSCSI connections.
+        */
+       if (!orig_nopin_timeout) {
+               spin_lock_bh(&se_nacl->nacl_sess_lock);
+               se_sess = se_nacl->nacl_sess;
+               if (se_sess) {
+                       sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+
+                       spin_lock(&sess->conn_lock);
+                       list_for_each_entry(conn, &sess->sess_conn_list,
+                                       conn_list) {
+                               if (conn->conn_state !=
+                                               TARG_CONN_STATE_LOGGED_IN)
+                                       continue;
+
+                               spin_lock(&conn->nopin_timer_lock);
+                               __iscsit_start_nopin_timer(conn);
+                               spin_unlock(&conn->nopin_timer_lock);
+                       }
+                       spin_unlock(&sess->conn_lock);
+               }
+               spin_unlock_bh(&se_nacl->nacl_sess_lock);
+       }
+
+       return 0;
+}
+
+extern int iscsit_na_nopin_response_timeout(
+       struct iscsi_node_acl *acl,
+       u32 nopin_response_timeout)
+{
+       struct iscsi_node_attrib *a = &acl->node_attrib;
+
+       if (nopin_response_timeout > NA_NOPIN_RESPONSE_TIMEOUT_MAX) {
+               pr_err("Requested NopIn Response Timeout %u larger"
+                       " than maximum %u\n", nopin_response_timeout,
+                               NA_NOPIN_RESPONSE_TIMEOUT_MAX);
+               return -EINVAL;
+       } else if (nopin_response_timeout < NA_NOPIN_RESPONSE_TIMEOUT_MIN) {
+               pr_err("Requested NopIn Response Timeout %u smaller"
+                       " than minimum %u\n", nopin_response_timeout,
+                               NA_NOPIN_RESPONSE_TIMEOUT_MIN);
+               return -EINVAL;
+       }
+
+       a->nopin_response_timeout = nopin_response_timeout;
+       pr_debug("Set NopIn Response Timeout to %u for"
+               " Initiator Node %s\n", a->nopin_timeout,
+               iscsit_na_get_initiatorname(acl));
+
+       return 0;
+}
+
+extern int iscsit_na_random_datain_pdu_offsets(
+       struct iscsi_node_acl *acl,
+       u32 random_datain_pdu_offsets)
+{
+       struct iscsi_node_attrib *a = &acl->node_attrib;
+
+       if (random_datain_pdu_offsets != 0 && random_datain_pdu_offsets != 1) {
+               pr_err("Requested Random DataIN PDU Offsets: %u not"
+                       " 0 or 1\n", random_datain_pdu_offsets);
+               return -EINVAL;
+       }
+
+       a->random_datain_pdu_offsets = random_datain_pdu_offsets;
+       pr_debug("Set Random DataIN PDU Offsets to %u for"
+               " Initiator Node %s\n", a->random_datain_pdu_offsets,
+               iscsit_na_get_initiatorname(acl));
+
+       return 0;
+}
+
+extern int iscsit_na_random_datain_seq_offsets(
+       struct iscsi_node_acl *acl,
+       u32 random_datain_seq_offsets)
+{
+       struct iscsi_node_attrib *a = &acl->node_attrib;
+
+       if (random_datain_seq_offsets != 0 && random_datain_seq_offsets != 1) {
+               pr_err("Requested Random DataIN Sequence Offsets: %u"
+                       " not 0 or 1\n", random_datain_seq_offsets);
+               return -EINVAL;
+       }
+
+       a->random_datain_seq_offsets = random_datain_seq_offsets;
+       pr_debug("Set Random DataIN Sequence Offsets to %u for"
+               " Initiator Node %s\n", a->random_datain_seq_offsets,
+               iscsit_na_get_initiatorname(acl));
+
+       return 0;
+}
+
+extern int iscsit_na_random_r2t_offsets(
+       struct iscsi_node_acl *acl,
+       u32 random_r2t_offsets)
+{
+       struct iscsi_node_attrib *a = &acl->node_attrib;
+
+       if (random_r2t_offsets != 0 && random_r2t_offsets != 1) {
+               pr_err("Requested Random R2T Offsets: %u not"
+                       " 0 or 1\n", random_r2t_offsets);
+               return -EINVAL;
+       }
+
+       a->random_r2t_offsets = random_r2t_offsets;
+       pr_debug("Set Random R2T Offsets to %u for"
+               " Initiator Node %s\n", a->random_r2t_offsets,
+               iscsit_na_get_initiatorname(acl));
+
+       return 0;
+}
+
+extern int iscsit_na_default_erl(
+       struct iscsi_node_acl *acl,
+       u32 default_erl)
+{
+       struct iscsi_node_attrib *a = &acl->node_attrib;
+
+       if (default_erl != 0 && default_erl != 1 && default_erl != 2) {
+               pr_err("Requested default ERL: %u not 0, 1, or 2\n",
+                               default_erl);
+               return -EINVAL;
+       }
+
+       a->default_erl = default_erl;
+       pr_debug("Set use ERL0 flag to %u for Initiator"
+               " Node %s\n", a->default_erl,
+               iscsit_na_get_initiatorname(acl));
+
+       return 0;
+}
diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.h b/drivers/target/iscsi/iscsi_target_nodeattrib.h
new file mode 100644 (file)
index 0000000..c970b32
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef ISCSI_TARGET_NODEATTRIB_H
+#define ISCSI_TARGET_NODEATTRIB_H
+
+extern void iscsit_set_default_node_attribues(struct iscsi_node_acl *);
+extern int iscsit_na_dataout_timeout(struct iscsi_node_acl *, u32);
+extern int iscsit_na_dataout_timeout_retries(struct iscsi_node_acl *, u32);
+extern int iscsit_na_nopin_timeout(struct iscsi_node_acl *, u32);
+extern int iscsit_na_nopin_response_timeout(struct iscsi_node_acl *, u32);
+extern int iscsit_na_random_datain_pdu_offsets(struct iscsi_node_acl *, u32);
+extern int iscsit_na_random_datain_seq_offsets(struct iscsi_node_acl *, u32);
+extern int iscsit_na_random_r2t_offsets(struct iscsi_node_acl *, u32);
+extern int iscsit_na_default_erl(struct iscsi_node_acl *, u32);
+
+#endif /* ISCSI_TARGET_NODEATTRIB_H */
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
new file mode 100644 (file)
index 0000000..252e246
--- /dev/null
@@ -0,0 +1,1905 @@
+/*******************************************************************************
+ * This file contains main functions related to iSCSI Parameter negotiation.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <linux/slab.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target_parameters.h"
+
+int iscsi_login_rx_data(
+       struct iscsi_conn *conn,
+       char *buf,
+       int length)
+{
+       int rx_got;
+       struct kvec iov;
+
+       memset(&iov, 0, sizeof(struct kvec));
+       iov.iov_len     = length;
+       iov.iov_base    = buf;
+
+       /*
+        * Initial Marker-less Interval.
+        * Add the values regardless of IFMarker/OFMarker, considering
+        * it may not be negoitated yet.
+        */
+       conn->of_marker += length;
+
+       rx_got = rx_data(conn, &iov, 1, length);
+       if (rx_got != length) {
+               pr_err("rx_data returned %d, expecting %d.\n",
+                               rx_got, length);
+               return -1;
+       }
+
+       return 0 ;
+}
+
+int iscsi_login_tx_data(
+       struct iscsi_conn *conn,
+       char *pdu_buf,
+       char *text_buf,
+       int text_length)
+{
+       int length, tx_sent;
+       struct kvec iov[2];
+
+       length = (ISCSI_HDR_LEN + text_length);
+
+       memset(&iov[0], 0, 2 * sizeof(struct kvec));
+       iov[0].iov_len          = ISCSI_HDR_LEN;
+       iov[0].iov_base         = pdu_buf;
+       iov[1].iov_len          = text_length;
+       iov[1].iov_base         = text_buf;
+
+       /*
+        * Initial Marker-less Interval.
+        * Add the values regardless of IFMarker/OFMarker, considering
+        * it may not be negoitated yet.
+        */
+       conn->if_marker += length;
+
+       tx_sent = tx_data(conn, &iov[0], 2, length);
+       if (tx_sent != length) {
+               pr_err("tx_data returned %d, expecting %d.\n",
+                               tx_sent, length);
+               return -1;
+       }
+
+       return 0;
+}
+
+void iscsi_dump_conn_ops(struct iscsi_conn_ops *conn_ops)
+{
+       pr_debug("HeaderDigest: %s\n", (conn_ops->HeaderDigest) ?
+                               "CRC32C" : "None");
+       pr_debug("DataDigest: %s\n", (conn_ops->DataDigest) ?
+                               "CRC32C" : "None");
+       pr_debug("MaxRecvDataSegmentLength: %u\n",
+                               conn_ops->MaxRecvDataSegmentLength);
+       pr_debug("OFMarker: %s\n", (conn_ops->OFMarker) ? "Yes" : "No");
+       pr_debug("IFMarker: %s\n", (conn_ops->IFMarker) ? "Yes" : "No");
+       if (conn_ops->OFMarker)
+               pr_debug("OFMarkInt: %u\n", conn_ops->OFMarkInt);
+       if (conn_ops->IFMarker)
+               pr_debug("IFMarkInt: %u\n", conn_ops->IFMarkInt);
+}
+
+void iscsi_dump_sess_ops(struct iscsi_sess_ops *sess_ops)
+{
+       pr_debug("InitiatorName: %s\n", sess_ops->InitiatorName);
+       pr_debug("InitiatorAlias: %s\n", sess_ops->InitiatorAlias);
+       pr_debug("TargetName: %s\n", sess_ops->TargetName);
+       pr_debug("TargetAlias: %s\n", sess_ops->TargetAlias);
+       pr_debug("TargetPortalGroupTag: %hu\n",
+                       sess_ops->TargetPortalGroupTag);
+       pr_debug("MaxConnections: %hu\n", sess_ops->MaxConnections);
+       pr_debug("InitialR2T: %s\n",
+                       (sess_ops->InitialR2T) ? "Yes" : "No");
+       pr_debug("ImmediateData: %s\n", (sess_ops->ImmediateData) ?
+                       "Yes" : "No");
+       pr_debug("MaxBurstLength: %u\n", sess_ops->MaxBurstLength);
+       pr_debug("FirstBurstLength: %u\n", sess_ops->FirstBurstLength);
+       pr_debug("DefaultTime2Wait: %hu\n", sess_ops->DefaultTime2Wait);
+       pr_debug("DefaultTime2Retain: %hu\n",
+                       sess_ops->DefaultTime2Retain);
+       pr_debug("MaxOutstandingR2T: %hu\n",
+                       sess_ops->MaxOutstandingR2T);
+       pr_debug("DataPDUInOrder: %s\n",
+                       (sess_ops->DataPDUInOrder) ? "Yes" : "No");
+       pr_debug("DataSequenceInOrder: %s\n",
+                       (sess_ops->DataSequenceInOrder) ? "Yes" : "No");
+       pr_debug("ErrorRecoveryLevel: %hu\n",
+                       sess_ops->ErrorRecoveryLevel);
+       pr_debug("SessionType: %s\n", (sess_ops->SessionType) ?
+                       "Discovery" : "Normal");
+}
+
+void iscsi_print_params(struct iscsi_param_list *param_list)
+{
+       struct iscsi_param *param;
+
+       list_for_each_entry(param, &param_list->param_list, p_list)
+               pr_debug("%s: %s\n", param->name, param->value);
+}
+
+static struct iscsi_param *iscsi_set_default_param(struct iscsi_param_list *param_list,
+               char *name, char *value, u8 phase, u8 scope, u8 sender,
+               u16 type_range, u8 use)
+{
+       struct iscsi_param *param = NULL;
+
+       param = kzalloc(sizeof(struct iscsi_param), GFP_KERNEL);
+       if (!param) {
+               pr_err("Unable to allocate memory for parameter.\n");
+               goto out;
+       }
+       INIT_LIST_HEAD(&param->p_list);
+
+       param->name = kzalloc(strlen(name) + 1, GFP_KERNEL);
+       if (!param->name) {
+               pr_err("Unable to allocate memory for parameter name.\n");
+               goto out;
+       }
+
+       param->value = kzalloc(strlen(value) + 1, GFP_KERNEL);
+       if (!param->value) {
+               pr_err("Unable to allocate memory for parameter value.\n");
+               goto out;
+       }
+
+       memcpy(param->name, name, strlen(name));
+       param->name[strlen(name)] = '\0';
+       memcpy(param->value, value, strlen(value));
+       param->value[strlen(value)] = '\0';
+       param->phase            = phase;
+       param->scope            = scope;
+       param->sender           = sender;
+       param->use              = use;
+       param->type_range       = type_range;
+
+       switch (param->type_range) {
+       case TYPERANGE_BOOL_AND:
+               param->type = TYPE_BOOL_AND;
+               break;
+       case TYPERANGE_BOOL_OR:
+               param->type = TYPE_BOOL_OR;
+               break;
+       case TYPERANGE_0_TO_2:
+       case TYPERANGE_0_TO_3600:
+       case TYPERANGE_0_TO_32767:
+       case TYPERANGE_0_TO_65535:
+       case TYPERANGE_1_TO_65535:
+       case TYPERANGE_2_TO_3600:
+       case TYPERANGE_512_TO_16777215:
+               param->type = TYPE_NUMBER;
+               break;
+       case TYPERANGE_AUTH:
+       case TYPERANGE_DIGEST:
+               param->type = TYPE_VALUE_LIST | TYPE_STRING;
+               break;
+       case TYPERANGE_MARKINT:
+               param->type = TYPE_NUMBER_RANGE;
+               param->type_range |= TYPERANGE_1_TO_65535;
+               break;
+       case TYPERANGE_ISCSINAME:
+       case TYPERANGE_SESSIONTYPE:
+       case TYPERANGE_TARGETADDRESS:
+       case TYPERANGE_UTF8:
+               param->type = TYPE_STRING;
+               break;
+       default:
+               pr_err("Unknown type_range 0x%02x\n",
+                               param->type_range);
+               goto out;
+       }
+       list_add_tail(&param->p_list, &param_list->param_list);
+
+       return param;
+out:
+       if (param) {
+               kfree(param->value);
+               kfree(param->name);
+               kfree(param);
+       }
+
+       return NULL;
+}
+
+/* #warning Add extension keys */
+int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
+{
+       struct iscsi_param *param = NULL;
+       struct iscsi_param_list *pl;
+
+       pl = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL);
+       if (!pl) {
+               pr_err("Unable to allocate memory for"
+                               " struct iscsi_param_list.\n");
+               return -1 ;
+       }
+       INIT_LIST_HEAD(&pl->param_list);
+       INIT_LIST_HEAD(&pl->extra_response_list);
+
+       /*
+        * The format for setting the initial parameter definitions are:
+        *
+        * Parameter name:
+        * Initial value:
+        * Allowable phase:
+        * Scope:
+        * Allowable senders:
+        * Typerange:
+        * Use:
+        */
+       param = iscsi_set_default_param(pl, AUTHMETHOD, INITIAL_AUTHMETHOD,
+                       PHASE_SECURITY, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+                       TYPERANGE_AUTH, USE_INITIAL_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, HEADERDIGEST, INITIAL_HEADERDIGEST,
+                       PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+                       TYPERANGE_DIGEST, USE_INITIAL_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, DATADIGEST, INITIAL_DATADIGEST,
+                       PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+                       TYPERANGE_DIGEST, USE_INITIAL_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, MAXCONNECTIONS,
+                       INITIAL_MAXCONNECTIONS, PHASE_OPERATIONAL,
+                       SCOPE_SESSION_WIDE, SENDER_BOTH,
+                       TYPERANGE_1_TO_65535, USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, SENDTARGETS, INITIAL_SENDTARGETS,
+                       PHASE_FFP0, SCOPE_SESSION_WIDE, SENDER_INITIATOR,
+                       TYPERANGE_UTF8, 0);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, TARGETNAME, INITIAL_TARGETNAME,
+                       PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_BOTH,
+                       TYPERANGE_ISCSINAME, USE_ALL);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, INITIATORNAME,
+                       INITIAL_INITIATORNAME, PHASE_DECLARATIVE,
+                       SCOPE_SESSION_WIDE, SENDER_INITIATOR,
+                       TYPERANGE_ISCSINAME, USE_INITIAL_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, TARGETALIAS, INITIAL_TARGETALIAS,
+                       PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_TARGET,
+                       TYPERANGE_UTF8, USE_ALL);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, INITIATORALIAS,
+                       INITIAL_INITIATORALIAS, PHASE_DECLARATIVE,
+                       SCOPE_SESSION_WIDE, SENDER_INITIATOR, TYPERANGE_UTF8,
+                       USE_ALL);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, TARGETADDRESS,
+                       INITIAL_TARGETADDRESS, PHASE_DECLARATIVE,
+                       SCOPE_SESSION_WIDE, SENDER_TARGET,
+                       TYPERANGE_TARGETADDRESS, USE_ALL);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, TARGETPORTALGROUPTAG,
+                       INITIAL_TARGETPORTALGROUPTAG,
+                       PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_TARGET,
+                       TYPERANGE_0_TO_65535, USE_INITIAL_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, INITIALR2T, INITIAL_INITIALR2T,
+                       PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
+                       TYPERANGE_BOOL_OR, USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, IMMEDIATEDATA,
+                       INITIAL_IMMEDIATEDATA, PHASE_OPERATIONAL,
+                       SCOPE_SESSION_WIDE, SENDER_BOTH, TYPERANGE_BOOL_AND,
+                       USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, MAXRECVDATASEGMENTLENGTH,
+                       INITIAL_MAXRECVDATASEGMENTLENGTH,
+                       PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+                       TYPERANGE_512_TO_16777215, USE_ALL);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, MAXBURSTLENGTH,
+                       INITIAL_MAXBURSTLENGTH, PHASE_OPERATIONAL,
+                       SCOPE_SESSION_WIDE, SENDER_BOTH,
+                       TYPERANGE_512_TO_16777215, USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, FIRSTBURSTLENGTH,
+                       INITIAL_FIRSTBURSTLENGTH,
+                       PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
+                       TYPERANGE_512_TO_16777215, USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, DEFAULTTIME2WAIT,
+                       INITIAL_DEFAULTTIME2WAIT,
+                       PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
+                       TYPERANGE_0_TO_3600, USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, DEFAULTTIME2RETAIN,
+                       INITIAL_DEFAULTTIME2RETAIN,
+                       PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
+                       TYPERANGE_0_TO_3600, USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, MAXOUTSTANDINGR2T,
+                       INITIAL_MAXOUTSTANDINGR2T,
+                       PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
+                       TYPERANGE_1_TO_65535, USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, DATAPDUINORDER,
+                       INITIAL_DATAPDUINORDER, PHASE_OPERATIONAL,
+                       SCOPE_SESSION_WIDE, SENDER_BOTH, TYPERANGE_BOOL_OR,
+                       USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, DATASEQUENCEINORDER,
+                       INITIAL_DATASEQUENCEINORDER,
+                       PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
+                       TYPERANGE_BOOL_OR, USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, ERRORRECOVERYLEVEL,
+                       INITIAL_ERRORRECOVERYLEVEL,
+                       PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
+                       TYPERANGE_0_TO_2, USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, SESSIONTYPE, INITIAL_SESSIONTYPE,
+                       PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_INITIATOR,
+                       TYPERANGE_SESSIONTYPE, USE_LEADING_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, IFMARKER, INITIAL_IFMARKER,
+                       PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+                       TYPERANGE_BOOL_AND, USE_INITIAL_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, OFMARKER, INITIAL_OFMARKER,
+                       PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+                       TYPERANGE_BOOL_AND, USE_INITIAL_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, IFMARKINT, INITIAL_IFMARKINT,
+                       PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+                       TYPERANGE_MARKINT, USE_INITIAL_ONLY);
+       if (!param)
+               goto out;
+
+       param = iscsi_set_default_param(pl, OFMARKINT, INITIAL_OFMARKINT,
+                       PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+                       TYPERANGE_MARKINT, USE_INITIAL_ONLY);
+       if (!param)
+               goto out;
+
+       *param_list_ptr = pl;
+       return 0;
+out:
+       iscsi_release_param_list(pl);
+       return -1;
+}
+
+int iscsi_set_keys_to_negotiate(
+       int sessiontype,
+       struct iscsi_param_list *param_list)
+{
+       struct iscsi_param *param;
+
+       list_for_each_entry(param, &param_list->param_list, p_list) {
+               param->state = 0;
+               if (!strcmp(param->name, AUTHMETHOD)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, HEADERDIGEST)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, DATADIGEST)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, MAXCONNECTIONS)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, TARGETNAME)) {
+                       continue;
+               } else if (!strcmp(param->name, INITIATORNAME)) {
+                       continue;
+               } else if (!strcmp(param->name, TARGETALIAS)) {
+                       if (param->value)
+                               SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, INITIATORALIAS)) {
+                       continue;
+               } else if (!strcmp(param->name, TARGETPORTALGROUPTAG)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, INITIALR2T)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, IMMEDIATEDATA)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, MAXBURSTLENGTH)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, FIRSTBURSTLENGTH)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, DEFAULTTIME2WAIT)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, DEFAULTTIME2RETAIN)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, MAXOUTSTANDINGR2T)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, DATAPDUINORDER)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, DATASEQUENCEINORDER)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, ERRORRECOVERYLEVEL)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, SESSIONTYPE)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, IFMARKER)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, OFMARKER)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, IFMARKINT)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               } else if (!strcmp(param->name, OFMARKINT)) {
+                       SET_PSTATE_NEGOTIATE(param);
+               }
+       }
+
+       return 0;
+}
+
+int iscsi_set_keys_irrelevant_for_discovery(
+       struct iscsi_param_list *param_list)
+{
+       struct iscsi_param *param;
+
+       list_for_each_entry(param, &param_list->param_list, p_list) {
+               if (!strcmp(param->name, MAXCONNECTIONS))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, INITIALR2T))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, IMMEDIATEDATA))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, MAXBURSTLENGTH))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, FIRSTBURSTLENGTH))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, MAXOUTSTANDINGR2T))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, DATAPDUINORDER))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, DATASEQUENCEINORDER))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, ERRORRECOVERYLEVEL))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, DEFAULTTIME2WAIT))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, DEFAULTTIME2RETAIN))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, IFMARKER))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, OFMARKER))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, IFMARKINT))
+                       param->state &= ~PSTATE_NEGOTIATE;
+               else if (!strcmp(param->name, OFMARKINT))
+                       param->state &= ~PSTATE_NEGOTIATE;
+       }
+
+       return 0;
+}
+
+int iscsi_copy_param_list(
+       struct iscsi_param_list **dst_param_list,
+       struct iscsi_param_list *src_param_list,
+       int leading)
+{
+       struct iscsi_param *new_param = NULL, *param = NULL;
+       struct iscsi_param_list *param_list = NULL;
+
+       param_list = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL);
+       if (!param_list) {
+               pr_err("Unable to allocate memory for"
+                               " struct iscsi_param_list.\n");
+               goto err_out;
+       }
+       INIT_LIST_HEAD(&param_list->param_list);
+       INIT_LIST_HEAD(&param_list->extra_response_list);
+
+       list_for_each_entry(param, &src_param_list->param_list, p_list) {
+               if (!leading && (param->scope & SCOPE_SESSION_WIDE)) {
+                       if ((strcmp(param->name, "TargetName") != 0) &&
+                           (strcmp(param->name, "InitiatorName") != 0) &&
+                           (strcmp(param->name, "TargetPortalGroupTag") != 0))
+                               continue;
+               }
+
+               new_param = kzalloc(sizeof(struct iscsi_param), GFP_KERNEL);
+               if (!new_param) {
+                       pr_err("Unable to allocate memory for"
+                               " struct iscsi_param.\n");
+                       goto err_out;
+               }
+
+               new_param->set_param = param->set_param;
+               new_param->phase = param->phase;
+               new_param->scope = param->scope;
+               new_param->sender = param->sender;
+               new_param->type = param->type;
+               new_param->use = param->use;
+               new_param->type_range = param->type_range;
+
+               new_param->name = kzalloc(strlen(param->name) + 1, GFP_KERNEL);
+               if (!new_param->name) {
+                       pr_err("Unable to allocate memory for"
+                               " parameter name.\n");
+                       goto err_out;
+               }
+
+               new_param->value = kzalloc(strlen(param->value) + 1,
+                               GFP_KERNEL);
+               if (!new_param->value) {
+                       pr_err("Unable to allocate memory for"
+                               " parameter value.\n");
+                       goto err_out;
+               }
+
+               memcpy(new_param->name, param->name, strlen(param->name));
+               new_param->name[strlen(param->name)] = '\0';
+               memcpy(new_param->value, param->value, strlen(param->value));
+               new_param->value[strlen(param->value)] = '\0';
+
+               list_add_tail(&new_param->p_list, &param_list->param_list);
+       }
+
+       if (!list_empty(&param_list->param_list))
+               *dst_param_list = param_list;
+       else {
+               pr_err("No parameters allocated.\n");
+               goto err_out;
+       }
+
+       return 0;
+
+err_out:
+       iscsi_release_param_list(param_list);
+       return -1;
+}
+
+static void iscsi_release_extra_responses(struct iscsi_param_list *param_list)
+{
+       struct iscsi_extra_response *er, *er_tmp;
+
+       list_for_each_entry_safe(er, er_tmp, &param_list->extra_response_list,
+                       er_list) {
+               list_del(&er->er_list);
+               kfree(er);
+       }
+}
+
+void iscsi_release_param_list(struct iscsi_param_list *param_list)
+{
+       struct iscsi_param *param, *param_tmp;
+
+       list_for_each_entry_safe(param, param_tmp, &param_list->param_list,
+                       p_list) {
+               list_del(&param->p_list);
+
+               kfree(param->name);
+               param->name = NULL;
+               kfree(param->value);
+               param->value = NULL;
+               kfree(param);
+               param = NULL;
+       }
+
+       iscsi_release_extra_responses(param_list);
+
+       kfree(param_list);
+}
+
+struct iscsi_param *iscsi_find_param_from_key(
+       char *key,
+       struct iscsi_param_list *param_list)
+{
+       struct iscsi_param *param;
+
+       if (!key || !param_list) {
+               pr_err("Key or parameter list pointer is NULL.\n");
+               return NULL;
+       }
+
+       list_for_each_entry(param, &param_list->param_list, p_list) {
+               if (!strcmp(key, param->name))
+                       return param;
+       }
+
+       pr_err("Unable to locate key \"%s\".\n", key);
+       return NULL;
+}
+
+int iscsi_extract_key_value(char *textbuf, char **key, char **value)
+{
+       *value = strchr(textbuf, '=');
+       if (!*value) {
+               pr_err("Unable to locate \"=\" seperator for key,"
+                               " ignoring request.\n");
+               return -1;
+       }
+
+       *key = textbuf;
+       **value = '\0';
+       *value = *value + 1;
+
+       return 0;
+}
+
+int iscsi_update_param_value(struct iscsi_param *param, char *value)
+{
+       kfree(param->value);
+
+       param->value = kzalloc(strlen(value) + 1, GFP_KERNEL);
+       if (!param->value) {
+               pr_err("Unable to allocate memory for value.\n");
+               return -1;
+       }
+
+       memcpy(param->value, value, strlen(value));
+       param->value[strlen(value)] = '\0';
+
+       pr_debug("iSCSI Parameter updated to %s=%s\n",
+                       param->name, param->value);
+       return 0;
+}
+
+static int iscsi_add_notunderstood_response(
+       char *key,
+       char *value,
+       struct iscsi_param_list *param_list)
+{
+       struct iscsi_extra_response *extra_response;
+
+       if (strlen(value) > VALUE_MAXLEN) {
+               pr_err("Value for notunderstood key \"%s\" exceeds %d,"
+                       " protocol error.\n", key, VALUE_MAXLEN);
+               return -1;
+       }
+
+       extra_response = kzalloc(sizeof(struct iscsi_extra_response), GFP_KERNEL);
+       if (!extra_response) {
+               pr_err("Unable to allocate memory for"
+                       " struct iscsi_extra_response.\n");
+               return -1;
+       }
+       INIT_LIST_HEAD(&extra_response->er_list);
+
+       strncpy(extra_response->key, key, strlen(key) + 1);
+       strncpy(extra_response->value, NOTUNDERSTOOD,
+                       strlen(NOTUNDERSTOOD) + 1);
+
+       list_add_tail(&extra_response->er_list,
+                       &param_list->extra_response_list);
+       return 0;
+}
+
+static int iscsi_check_for_auth_key(char *key)
+{
+       /*
+        * RFC 1994
+        */
+       if (!strcmp(key, "CHAP_A") || !strcmp(key, "CHAP_I") ||
+           !strcmp(key, "CHAP_C") || !strcmp(key, "CHAP_N") ||
+           !strcmp(key, "CHAP_R"))
+               return 1;
+
+       /*
+        * RFC 2945
+        */
+       if (!strcmp(key, "SRP_U") || !strcmp(key, "SRP_N") ||
+           !strcmp(key, "SRP_g") || !strcmp(key, "SRP_s") ||
+           !strcmp(key, "SRP_A") || !strcmp(key, "SRP_B") ||
+           !strcmp(key, "SRP_M") || !strcmp(key, "SRP_HM"))
+               return 1;
+
+       return 0;
+}
+
+static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param)
+{
+       if (IS_TYPE_BOOL_AND(param)) {
+               if (!strcmp(param->value, NO))
+                       SET_PSTATE_REPLY_OPTIONAL(param);
+       } else if (IS_TYPE_BOOL_OR(param)) {
+               if (!strcmp(param->value, YES))
+                       SET_PSTATE_REPLY_OPTIONAL(param);
+                /*
+                 * Required for gPXE iSCSI boot client
+                 */
+               if (!strcmp(param->name, IMMEDIATEDATA))
+                       SET_PSTATE_REPLY_OPTIONAL(param);
+       } else if (IS_TYPE_NUMBER(param)) {
+               if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
+                       SET_PSTATE_REPLY_OPTIONAL(param);
+               /*
+                * The GlobalSAN iSCSI Initiator for MacOSX does
+                * not respond to MaxBurstLength, FirstBurstLength,
+                * DefaultTime2Wait or DefaultTime2Retain parameter keys.
+                * So, we set them to 'reply optional' here, and assume the
+                * the defaults from iscsi_parameters.h if the initiator
+                * is not RFC compliant and the keys are not negotiated.
+                */
+               if (!strcmp(param->name, MAXBURSTLENGTH))
+                       SET_PSTATE_REPLY_OPTIONAL(param);
+               if (!strcmp(param->name, FIRSTBURSTLENGTH))
+                       SET_PSTATE_REPLY_OPTIONAL(param);
+               if (!strcmp(param->name, DEFAULTTIME2WAIT))
+                       SET_PSTATE_REPLY_OPTIONAL(param);
+               if (!strcmp(param->name, DEFAULTTIME2RETAIN))
+                       SET_PSTATE_REPLY_OPTIONAL(param);
+               /*
+                * Required for gPXE iSCSI boot client
+                */
+               if (!strcmp(param->name, MAXCONNECTIONS))
+                       SET_PSTATE_REPLY_OPTIONAL(param);
+       } else if (IS_PHASE_DECLARATIVE(param))
+               SET_PSTATE_REPLY_OPTIONAL(param);
+}
+
+static int iscsi_check_boolean_value(struct iscsi_param *param, char *value)
+{
+       if (strcmp(value, YES) && strcmp(value, NO)) {
+               pr_err("Illegal value for \"%s\", must be either"
+                       " \"%s\" or \"%s\".\n", param->name, YES, NO);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int iscsi_check_numerical_value(struct iscsi_param *param, char *value_ptr)
+{
+       char *tmpptr;
+       int value = 0;
+
+       value = simple_strtoul(value_ptr, &tmpptr, 0);
+
+/* #warning FIXME: Fix this */
+#if 0
+       if (strspn(endptr, WHITE_SPACE) != strlen(endptr)) {
+               pr_err("Illegal value \"%s\" for \"%s\".\n",
+                       value, param->name);
+               return -1;
+       }
+#endif
+       if (IS_TYPERANGE_0_TO_2(param)) {
+               if ((value < 0) || (value > 2)) {
+                       pr_err("Illegal value for \"%s\", must be"
+                               " between 0 and 2.\n", param->name);
+                       return -1;
+               }
+               return 0;
+       }
+       if (IS_TYPERANGE_0_TO_3600(param)) {
+               if ((value < 0) || (value > 3600)) {
+                       pr_err("Illegal value for \"%s\", must be"
+                               " between 0 and 3600.\n", param->name);
+                       return -1;
+               }
+               return 0;
+       }
+       if (IS_TYPERANGE_0_TO_32767(param)) {
+               if ((value < 0) || (value > 32767)) {
+                       pr_err("Illegal value for \"%s\", must be"
+                               " between 0 and 32767.\n", param->name);
+                       return -1;
+               }
+               return 0;
+       }
+       if (IS_TYPERANGE_0_TO_65535(param)) {
+               if ((value < 0) || (value > 65535)) {
+                       pr_err("Illegal value for \"%s\", must be"
+                               " between 0 and 65535.\n", param->name);
+                       return -1;
+               }
+               return 0;
+       }
+       if (IS_TYPERANGE_1_TO_65535(param)) {
+               if ((value < 1) || (value > 65535)) {
+                       pr_err("Illegal value for \"%s\", must be"
+                               " between 1 and 65535.\n", param->name);
+                       return -1;
+               }
+               return 0;
+       }
+       if (IS_TYPERANGE_2_TO_3600(param)) {
+               if ((value < 2) || (value > 3600)) {
+                       pr_err("Illegal value for \"%s\", must be"
+                               " between 2 and 3600.\n", param->name);
+                       return -1;
+               }
+               return 0;
+       }
+       if (IS_TYPERANGE_512_TO_16777215(param)) {
+               if ((value < 512) || (value > 16777215)) {
+                       pr_err("Illegal value for \"%s\", must be"
+                               " between 512 and 16777215.\n", param->name);
+                       return -1;
+               }
+               return 0;
+       }
+
+       return 0;
+}
+
+static int iscsi_check_numerical_range_value(struct iscsi_param *param, char *value)
+{
+       char *left_val_ptr = NULL, *right_val_ptr = NULL;
+       char *tilde_ptr = NULL, *tmp_ptr = NULL;
+       u32 left_val, right_val, local_left_val, local_right_val;
+
+       if (strcmp(param->name, IFMARKINT) &&
+           strcmp(param->name, OFMARKINT)) {
+               pr_err("Only parameters \"%s\" or \"%s\" may contain a"
+                      " numerical range value.\n", IFMARKINT, OFMARKINT);
+               return -1;
+       }
+
+       if (IS_PSTATE_PROPOSER(param))
+               return 0;
+
+       tilde_ptr = strchr(value, '~');
+       if (!tilde_ptr) {
+               pr_err("Unable to locate numerical range indicator"
+                       " \"~\" for \"%s\".\n", param->name);
+               return -1;
+       }
+       *tilde_ptr = '\0';
+
+       left_val_ptr = value;
+       right_val_ptr = value + strlen(left_val_ptr) + 1;
+
+       if (iscsi_check_numerical_value(param, left_val_ptr) < 0)
+               return -1;
+       if (iscsi_check_numerical_value(param, right_val_ptr) < 0)
+               return -1;
+
+       left_val = simple_strtoul(left_val_ptr, &tmp_ptr, 0);
+       right_val = simple_strtoul(right_val_ptr, &tmp_ptr, 0);
+       *tilde_ptr = '~';
+
+       if (right_val < left_val) {
+               pr_err("Numerical range for parameter \"%s\" contains"
+                       " a right value which is less than the left.\n",
+                               param->name);
+               return -1;
+       }
+
+       /*
+        * For now,  enforce reasonable defaults for [I,O]FMarkInt.
+        */
+       tilde_ptr = strchr(param->value, '~');
+       if (!tilde_ptr) {
+               pr_err("Unable to locate numerical range indicator"
+                       " \"~\" for \"%s\".\n", param->name);
+               return -1;
+       }
+       *tilde_ptr = '\0';
+
+       left_val_ptr = param->value;
+       right_val_ptr = param->value + strlen(left_val_ptr) + 1;
+
+       local_left_val = simple_strtoul(left_val_ptr, &tmp_ptr, 0);
+       local_right_val = simple_strtoul(right_val_ptr, &tmp_ptr, 0);
+       *tilde_ptr = '~';
+
+       if (param->set_param) {
+               if ((left_val < local_left_val) ||
+                   (right_val < local_left_val)) {
+                       pr_err("Passed value range \"%u~%u\" is below"
+                               " minimum left value \"%u\" for key \"%s\","
+                               " rejecting.\n", left_val, right_val,
+                               local_left_val, param->name);
+                       return -1;
+               }
+       } else {
+               if ((left_val < local_left_val) &&
+                   (right_val < local_left_val)) {
+                       pr_err("Received value range \"%u~%u\" is"
+                               " below minimum left value \"%u\" for key"
+                               " \"%s\", rejecting.\n", left_val, right_val,
+                               local_left_val, param->name);
+                       SET_PSTATE_REJECT(param);
+                       if (iscsi_update_param_value(param, REJECT) < 0)
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int iscsi_check_string_or_list_value(struct iscsi_param *param, char *value)
+{
+       if (IS_PSTATE_PROPOSER(param))
+               return 0;
+
+       if (IS_TYPERANGE_AUTH_PARAM(param)) {
+               if (strcmp(value, KRB5) && strcmp(value, SPKM1) &&
+                   strcmp(value, SPKM2) && strcmp(value, SRP) &&
+                   strcmp(value, CHAP) && strcmp(value, NONE)) {
+                       pr_err("Illegal value for \"%s\", must be"
+                               " \"%s\", \"%s\", \"%s\", \"%s\", \"%s\""
+                               " or \"%s\".\n", param->name, KRB5,
+                                       SPKM1, SPKM2, SRP, CHAP, NONE);
+                       return -1;
+               }
+       }
+       if (IS_TYPERANGE_DIGEST_PARAM(param)) {
+               if (strcmp(value, CRC32C) && strcmp(value, NONE)) {
+                       pr_err("Illegal value for \"%s\", must be"
+                               " \"%s\" or \"%s\".\n", param->name,
+                                       CRC32C, NONE);
+                       return -1;
+               }
+       }
+       if (IS_TYPERANGE_SESSIONTYPE(param)) {
+               if (strcmp(value, DISCOVERY) && strcmp(value, NORMAL)) {
+                       pr_err("Illegal value for \"%s\", must be"
+                               " \"%s\" or \"%s\".\n", param->name,
+                                       DISCOVERY, NORMAL);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ *     This function is used to pick a value range number,  currently just
+ *     returns the lesser of both right values.
+ */
+static char *iscsi_get_value_from_number_range(
+       struct iscsi_param *param,
+       char *value)
+{
+       char *end_ptr, *tilde_ptr1 = NULL, *tilde_ptr2 = NULL;
+       u32 acceptor_right_value, proposer_right_value;
+
+       tilde_ptr1 = strchr(value, '~');
+       if (!tilde_ptr1)
+               return NULL;
+       *tilde_ptr1++ = '\0';
+       proposer_right_value = simple_strtoul(tilde_ptr1, &end_ptr, 0);
+
+       tilde_ptr2 = strchr(param->value, '~');
+       if (!tilde_ptr2)
+               return NULL;
+       *tilde_ptr2++ = '\0';
+       acceptor_right_value = simple_strtoul(tilde_ptr2, &end_ptr, 0);
+
+       return (acceptor_right_value >= proposer_right_value) ?
+               tilde_ptr1 : tilde_ptr2;
+}
+
+static char *iscsi_check_valuelist_for_support(
+       struct iscsi_param *param,
+       char *value)
+{
+       char *tmp1 = NULL, *tmp2 = NULL;
+       char *acceptor_values = NULL, *proposer_values = NULL;
+
+       acceptor_values = param->value;
+       proposer_values = value;
+
+       do {
+               if (!proposer_values)
+                       return NULL;
+               tmp1 = strchr(proposer_values, ',');
+               if (tmp1)
+                       *tmp1 = '\0';
+               acceptor_values = param->value;
+               do {
+                       if (!acceptor_values) {
+                               if (tmp1)
+                                       *tmp1 = ',';
+                               return NULL;
+                       }
+                       tmp2 = strchr(acceptor_values, ',');
+                       if (tmp2)
+                               *tmp2 = '\0';
+                       if (!acceptor_values || !proposer_values) {
+                               if (tmp1)
+                                       *tmp1 = ',';
+                               if (tmp2)
+                                       *tmp2 = ',';
+                               return NULL;
+                       }
+                       if (!strcmp(acceptor_values, proposer_values)) {
+                               if (tmp2)
+                                       *tmp2 = ',';
+                               goto out;
+                       }
+                       if (tmp2)
+                               *tmp2++ = ',';
+
+                       acceptor_values = tmp2;
+                       if (!acceptor_values)
+                               break;
+               } while (acceptor_values);
+               if (tmp1)
+                       *tmp1++ = ',';
+               proposer_values = tmp1;
+       } while (proposer_values);
+
+out:
+       return proposer_values;
+}
+
+static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value)
+{
+       u8 acceptor_boolean_value = 0, proposer_boolean_value = 0;
+       char *negoitated_value = NULL;
+
+       if (IS_PSTATE_ACCEPTOR(param)) {
+               pr_err("Received key \"%s\" twice, protocol error.\n",
+                               param->name);
+               return -1;
+       }
+
+       if (IS_PSTATE_REJECT(param))
+               return 0;
+
+       if (IS_TYPE_BOOL_AND(param)) {
+               if (!strcmp(value, YES))
+                       proposer_boolean_value = 1;
+               if (!strcmp(param->value, YES))
+                       acceptor_boolean_value = 1;
+               if (acceptor_boolean_value && proposer_boolean_value)
+                       do {} while (0);
+               else {
+                       if (iscsi_update_param_value(param, NO) < 0)
+                               return -1;
+                       if (!proposer_boolean_value)
+                               SET_PSTATE_REPLY_OPTIONAL(param);
+               }
+       } else if (IS_TYPE_BOOL_OR(param)) {
+               if (!strcmp(value, YES))
+                       proposer_boolean_value = 1;
+               if (!strcmp(param->value, YES))
+                       acceptor_boolean_value = 1;
+               if (acceptor_boolean_value || proposer_boolean_value) {
+                       if (iscsi_update_param_value(param, YES) < 0)
+                               return -1;
+                       if (proposer_boolean_value)
+                               SET_PSTATE_REPLY_OPTIONAL(param);
+               }
+       } else if (IS_TYPE_NUMBER(param)) {
+               char *tmpptr, buf[10];
+               u32 acceptor_value = simple_strtoul(param->value, &tmpptr, 0);
+               u32 proposer_value = simple_strtoul(value, &tmpptr, 0);
+
+               memset(buf, 0, 10);
+
+               if (!strcmp(param->name, MAXCONNECTIONS) ||
+                   !strcmp(param->name, MAXBURSTLENGTH) ||
+                   !strcmp(param->name, FIRSTBURSTLENGTH) ||
+                   !strcmp(param->name, MAXOUTSTANDINGR2T) ||
+                   !strcmp(param->name, DEFAULTTIME2RETAIN) ||
+                   !strcmp(param->name, ERRORRECOVERYLEVEL)) {
+                       if (proposer_value > acceptor_value) {
+                               sprintf(buf, "%u", acceptor_value);
+                               if (iscsi_update_param_value(param,
+                                               &buf[0]) < 0)
+                                       return -1;
+                       } else {
+                               if (iscsi_update_param_value(param, value) < 0)
+                                       return -1;
+                       }
+               } else if (!strcmp(param->name, DEFAULTTIME2WAIT)) {
+                       if (acceptor_value > proposer_value) {
+                               sprintf(buf, "%u", acceptor_value);
+                               if (iscsi_update_param_value(param,
+                                               &buf[0]) < 0)
+                                       return -1;
+                       } else {
+                               if (iscsi_update_param_value(param, value) < 0)
+                                       return -1;
+                       }
+               } else {
+                       if (iscsi_update_param_value(param, value) < 0)
+                               return -1;
+               }
+
+               if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
+                       SET_PSTATE_REPLY_OPTIONAL(param);
+       } else if (IS_TYPE_NUMBER_RANGE(param)) {
+               negoitated_value = iscsi_get_value_from_number_range(
+                                       param, value);
+               if (!negoitated_value)
+                       return -1;
+               if (iscsi_update_param_value(param, negoitated_value) < 0)
+                       return -1;
+       } else if (IS_TYPE_VALUE_LIST(param)) {
+               negoitated_value = iscsi_check_valuelist_for_support(
+                                       param, value);
+               if (!negoitated_value) {
+                       pr_err("Proposer's value list \"%s\" contains"
+                               " no valid values from Acceptor's value list"
+                               " \"%s\".\n", value, param->value);
+                       return -1;
+               }
+               if (iscsi_update_param_value(param, negoitated_value) < 0)
+                       return -1;
+       } else if (IS_PHASE_DECLARATIVE(param)) {
+               if (iscsi_update_param_value(param, value) < 0)
+                       return -1;
+               SET_PSTATE_REPLY_OPTIONAL(param);
+       }
+
+       return 0;
+}
+
+static int iscsi_check_proposer_state(struct iscsi_param *param, char *value)
+{
+       if (IS_PSTATE_RESPONSE_GOT(param)) {
+               pr_err("Received key \"%s\" twice, protocol error.\n",
+                               param->name);
+               return -1;
+       }
+
+       if (IS_TYPE_NUMBER_RANGE(param)) {
+               u32 left_val = 0, right_val = 0, recieved_value = 0;
+               char *left_val_ptr = NULL, *right_val_ptr = NULL;
+               char *tilde_ptr = NULL, *tmp_ptr = NULL;
+
+               if (!strcmp(value, IRRELEVANT) || !strcmp(value, REJECT)) {
+                       if (iscsi_update_param_value(param, value) < 0)
+                               return -1;
+                       return 0;
+               }
+
+               tilde_ptr = strchr(value, '~');
+               if (tilde_ptr) {
+                       pr_err("Illegal \"~\" in response for \"%s\".\n",
+                                       param->name);
+                       return -1;
+               }
+               tilde_ptr = strchr(param->value, '~');
+               if (!tilde_ptr) {
+                       pr_err("Unable to locate numerical range"
+                               " indicator \"~\" for \"%s\".\n", param->name);
+                       return -1;
+               }
+               *tilde_ptr = '\0';
+
+               left_val_ptr = param->value;
+               right_val_ptr = param->value + strlen(left_val_ptr) + 1;
+               left_val = simple_strtoul(left_val_ptr, &tmp_ptr, 0);
+               right_val = simple_strtoul(right_val_ptr, &tmp_ptr, 0);
+               recieved_value = simple_strtoul(value, &tmp_ptr, 0);
+
+               *tilde_ptr = '~';
+
+               if ((recieved_value < left_val) ||
+                   (recieved_value > right_val)) {
+                       pr_err("Illegal response \"%s=%u\", value must"
+                               " be between %u and %u.\n", param->name,
+                               recieved_value, left_val, right_val);
+                       return -1;
+               }
+       } else if (IS_TYPE_VALUE_LIST(param)) {
+               char *comma_ptr = NULL, *tmp_ptr = NULL;
+
+               comma_ptr = strchr(value, ',');
+               if (comma_ptr) {
+                       pr_err("Illegal \",\" in response for \"%s\".\n",
+                                       param->name);
+                       return -1;
+               }
+
+               tmp_ptr = iscsi_check_valuelist_for_support(param, value);
+               if (!tmp_ptr)
+                       return -1;
+       }
+
+       if (iscsi_update_param_value(param, value) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int iscsi_check_value(struct iscsi_param *param, char *value)
+{
+       char *comma_ptr = NULL;
+
+       if (!strcmp(value, REJECT)) {
+               if (!strcmp(param->name, IFMARKINT) ||
+                   !strcmp(param->name, OFMARKINT)) {
+                       /*
+                        * Reject is not fatal for [I,O]FMarkInt,  and causes
+                        * [I,O]FMarker to be reset to No. (See iSCSI v20 A.3.2)
+                        */
+                       SET_PSTATE_REJECT(param);
+                       return 0;
+               }
+               pr_err("Received %s=%s\n", param->name, value);
+               return -1;
+       }
+       if (!strcmp(value, IRRELEVANT)) {
+               pr_debug("Received %s=%s\n", param->name, value);
+               SET_PSTATE_IRRELEVANT(param);
+               return 0;
+       }
+       if (!strcmp(value, NOTUNDERSTOOD)) {
+               if (!IS_PSTATE_PROPOSER(param)) {
+                       pr_err("Received illegal offer %s=%s\n",
+                               param->name, value);
+                       return -1;
+               }
+
+/* #warning FIXME: Add check for X-ExtensionKey here */
+               pr_err("Standard iSCSI key \"%s\" cannot be answered"
+                       " with \"%s\", protocol error.\n", param->name, value);
+               return -1;
+       }
+
+       do {
+               comma_ptr = NULL;
+               comma_ptr = strchr(value, ',');
+
+               if (comma_ptr && !IS_TYPE_VALUE_LIST(param)) {
+                       pr_err("Detected value seperator \",\", but"
+                               " key \"%s\" does not allow a value list,"
+                               " protocol error.\n", param->name);
+                       return -1;
+               }
+               if (comma_ptr)
+                       *comma_ptr = '\0';
+
+               if (strlen(value) > VALUE_MAXLEN) {
+                       pr_err("Value for key \"%s\" exceeds %d,"
+                               " protocol error.\n", param->name,
+                               VALUE_MAXLEN);
+                       return -1;
+               }
+
+               if (IS_TYPE_BOOL_AND(param) || IS_TYPE_BOOL_OR(param)) {
+                       if (iscsi_check_boolean_value(param, value) < 0)
+                               return -1;
+               } else if (IS_TYPE_NUMBER(param)) {
+                       if (iscsi_check_numerical_value(param, value) < 0)
+                               return -1;
+               } else if (IS_TYPE_NUMBER_RANGE(param)) {
+                       if (iscsi_check_numerical_range_value(param, value) < 0)
+                               return -1;
+               } else if (IS_TYPE_STRING(param) || IS_TYPE_VALUE_LIST(param)) {
+                       if (iscsi_check_string_or_list_value(param, value) < 0)
+                               return -1;
+               } else {
+                       pr_err("Huh? 0x%02x\n", param->type);
+                       return -1;
+               }
+
+               if (comma_ptr)
+                       *comma_ptr++ = ',';
+
+               value = comma_ptr;
+       } while (value);
+
+       return 0;
+}
+
+static struct iscsi_param *__iscsi_check_key(
+       char *key,
+       int sender,
+       struct iscsi_param_list *param_list)
+{
+       struct iscsi_param *param;
+
+       if (strlen(key) > KEY_MAXLEN) {
+               pr_err("Length of key name \"%s\" exceeds %d.\n",
+                       key, KEY_MAXLEN);
+               return NULL;
+       }
+
+       param = iscsi_find_param_from_key(key, param_list);
+       if (!param)
+               return NULL;
+
+       if ((sender & SENDER_INITIATOR) && !IS_SENDER_INITIATOR(param)) {
+               pr_err("Key \"%s\" may not be sent to %s,"
+                       " protocol error.\n", param->name,
+                       (sender & SENDER_RECEIVER) ? "target" : "initiator");
+               return NULL;
+       }
+
+       if ((sender & SENDER_TARGET) && !IS_SENDER_TARGET(param)) {
+               pr_err("Key \"%s\" may not be sent to %s,"
+                       " protocol error.\n", param->name,
+                       (sender & SENDER_RECEIVER) ? "initiator" : "target");
+               return NULL;
+       }
+
+       return param;
+}
+
+static struct iscsi_param *iscsi_check_key(
+       char *key,
+       int phase,
+       int sender,
+       struct iscsi_param_list *param_list)
+{
+       struct iscsi_param *param;
+       /*
+        * Key name length must not exceed 63 bytes. (See iSCSI v20 5.1)
+        */
+       if (strlen(key) > KEY_MAXLEN) {
+               pr_err("Length of key name \"%s\" exceeds %d.\n",
+                       key, KEY_MAXLEN);
+               return NULL;
+       }
+
+       param = iscsi_find_param_from_key(key, param_list);
+       if (!param)
+               return NULL;
+
+       if ((sender & SENDER_INITIATOR) && !IS_SENDER_INITIATOR(param)) {
+               pr_err("Key \"%s\" may not be sent to %s,"
+                       " protocol error.\n", param->name,
+                       (sender & SENDER_RECEIVER) ? "target" : "initiator");
+               return NULL;
+       }
+       if ((sender & SENDER_TARGET) && !IS_SENDER_TARGET(param)) {
+               pr_err("Key \"%s\" may not be sent to %s,"
+                               " protocol error.\n", param->name,
+                       (sender & SENDER_RECEIVER) ? "initiator" : "target");
+               return NULL;
+       }
+
+       if (IS_PSTATE_ACCEPTOR(param)) {
+               pr_err("Key \"%s\" received twice, protocol error.\n",
+                               key);
+               return NULL;
+       }
+
+       if (!phase)
+               return param;
+
+       if (!(param->phase & phase)) {
+               pr_err("Key \"%s\" may not be negotiated during ",
+                               param->name);
+               switch (phase) {
+               case PHASE_SECURITY:
+                       pr_debug("Security phase.\n");
+                       break;
+               case PHASE_OPERATIONAL:
+                       pr_debug("Operational phase.\n");
+               default:
+                       pr_debug("Unknown phase.\n");
+               }
+               return NULL;
+       }
+
+       return param;
+}
+
+static int iscsi_enforce_integrity_rules(
+       u8 phase,
+       struct iscsi_param_list *param_list)
+{
+       char *tmpptr;
+       u8 DataSequenceInOrder = 0;
+       u8 ErrorRecoveryLevel = 0, SessionType = 0;
+       u8 IFMarker = 0, OFMarker = 0;
+       u8 IFMarkInt_Reject = 0, OFMarkInt_Reject = 0;
+       u32 FirstBurstLength = 0, MaxBurstLength = 0;
+       struct iscsi_param *param = NULL;
+
+       list_for_each_entry(param, &param_list->param_list, p_list) {
+               if (!(param->phase & phase))
+                       continue;
+               if (!strcmp(param->name, SESSIONTYPE))
+                       if (!strcmp(param->value, NORMAL))
+                               SessionType = 1;
+               if (!strcmp(param->name, ERRORRECOVERYLEVEL))
+                       ErrorRecoveryLevel = simple_strtoul(param->value,
+                                       &tmpptr, 0);
+               if (!strcmp(param->name, DATASEQUENCEINORDER))
+                       if (!strcmp(param->value, YES))
+                               DataSequenceInOrder = 1;
+               if (!strcmp(param->name, MAXBURSTLENGTH))
+                       MaxBurstLength = simple_strtoul(param->value,
+                                       &tmpptr, 0);
+               if (!strcmp(param->name, IFMARKER))
+                       if (!strcmp(param->value, YES))
+                               IFMarker = 1;
+               if (!strcmp(param->name, OFMARKER))
+                       if (!strcmp(param->value, YES))
+                               OFMarker = 1;
+               if (!strcmp(param->name, IFMARKINT))
+                       if (!strcmp(param->value, REJECT))
+                               IFMarkInt_Reject = 1;
+               if (!strcmp(param->name, OFMARKINT))
+                       if (!strcmp(param->value, REJECT))
+                               OFMarkInt_Reject = 1;
+       }
+
+       list_for_each_entry(param, &param_list->param_list, p_list) {
+               if (!(param->phase & phase))
+                       continue;
+               if (!SessionType && (!IS_PSTATE_ACCEPTOR(param) &&
+                    (strcmp(param->name, IFMARKER) &&
+                     strcmp(param->name, OFMARKER) &&
+                     strcmp(param->name, IFMARKINT) &&
+                     strcmp(param->name, OFMARKINT))))
+                       continue;
+               if (!strcmp(param->name, MAXOUTSTANDINGR2T) &&
+                   DataSequenceInOrder && (ErrorRecoveryLevel > 0)) {
+                       if (strcmp(param->value, "1")) {
+                               if (iscsi_update_param_value(param, "1") < 0)
+                                       return -1;
+                               pr_debug("Reset \"%s\" to \"%s\".\n",
+                                       param->name, param->value);
+                       }
+               }
+               if (!strcmp(param->name, MAXCONNECTIONS) && !SessionType) {
+                       if (strcmp(param->value, "1")) {
+                               if (iscsi_update_param_value(param, "1") < 0)
+                                       return -1;
+                               pr_debug("Reset \"%s\" to \"%s\".\n",
+                                       param->name, param->value);
+                       }
+               }
+               if (!strcmp(param->name, FIRSTBURSTLENGTH)) {
+                       FirstBurstLength = simple_strtoul(param->value,
+                                       &tmpptr, 0);
+                       if (FirstBurstLength > MaxBurstLength) {
+                               char tmpbuf[10];
+                               memset(tmpbuf, 0, 10);
+                               sprintf(tmpbuf, "%u", MaxBurstLength);
+                               if (iscsi_update_param_value(param, tmpbuf))
+                                       return -1;
+                               pr_debug("Reset \"%s\" to \"%s\".\n",
+                                       param->name, param->value);
+                       }
+               }
+               if (!strcmp(param->name, IFMARKER) && IFMarkInt_Reject) {
+                       if (iscsi_update_param_value(param, NO) < 0)
+                               return -1;
+                       IFMarker = 0;
+                       pr_debug("Reset \"%s\" to \"%s\".\n",
+                                       param->name, param->value);
+               }
+               if (!strcmp(param->name, OFMARKER) && OFMarkInt_Reject) {
+                       if (iscsi_update_param_value(param, NO) < 0)
+                               return -1;
+                       OFMarker = 0;
+                       pr_debug("Reset \"%s\" to \"%s\".\n",
+                                        param->name, param->value);
+               }
+               if (!strcmp(param->name, IFMARKINT) && !IFMarker) {
+                       if (!strcmp(param->value, REJECT))
+                               continue;
+                       param->state &= ~PSTATE_NEGOTIATE;
+                       if (iscsi_update_param_value(param, IRRELEVANT) < 0)
+                               return -1;
+                       pr_debug("Reset \"%s\" to \"%s\".\n",
+                                       param->name, param->value);
+               }
+               if (!strcmp(param->name, OFMARKINT) && !OFMarker) {
+                       if (!strcmp(param->value, REJECT))
+                               continue;
+                       param->state &= ~PSTATE_NEGOTIATE;
+                       if (iscsi_update_param_value(param, IRRELEVANT) < 0)
+                               return -1;
+                       pr_debug("Reset \"%s\" to \"%s\".\n",
+                                       param->name, param->value);
+               }
+       }
+
+       return 0;
+}
+
+int iscsi_decode_text_input(
+       u8 phase,
+       u8 sender,
+       char *textbuf,
+       u32 length,
+       struct iscsi_param_list *param_list)
+{
+       char *tmpbuf, *start = NULL, *end = NULL;
+
+       tmpbuf = kzalloc(length + 1, GFP_KERNEL);
+       if (!tmpbuf) {
+               pr_err("Unable to allocate memory for tmpbuf.\n");
+               return -1;
+       }
+
+       memcpy(tmpbuf, textbuf, length);
+       tmpbuf[length] = '\0';
+       start = tmpbuf;
+       end = (start + length);
+
+       while (start < end) {
+               char *key, *value;
+               struct iscsi_param *param;
+
+               if (iscsi_extract_key_value(start, &key, &value) < 0) {
+                       kfree(tmpbuf);
+                       return -1;
+               }
+
+               pr_debug("Got key: %s=%s\n", key, value);
+
+               if (phase & PHASE_SECURITY) {
+                       if (iscsi_check_for_auth_key(key) > 0) {
+                               char *tmpptr = key + strlen(key);
+                               *tmpptr = '=';
+                               kfree(tmpbuf);
+                               return 1;
+                       }
+               }
+
+               param = iscsi_check_key(key, phase, sender, param_list);
+               if (!param) {
+                       if (iscsi_add_notunderstood_response(key,
+                                       value, param_list) < 0) {
+                               kfree(tmpbuf);
+                               return -1;
+                       }
+                       start += strlen(key) + strlen(value) + 2;
+                       continue;
+               }
+               if (iscsi_check_value(param, value) < 0) {
+                       kfree(tmpbuf);
+                       return -1;
+               }
+
+               start += strlen(key) + strlen(value) + 2;
+
+               if (IS_PSTATE_PROPOSER(param)) {
+                       if (iscsi_check_proposer_state(param, value) < 0) {
+                               kfree(tmpbuf);
+                               return -1;
+                       }
+                       SET_PSTATE_RESPONSE_GOT(param);
+               } else {
+                       if (iscsi_check_acceptor_state(param, value) < 0) {
+                               kfree(tmpbuf);
+                               return -1;
+                       }
+                       SET_PSTATE_ACCEPTOR(param);
+               }
+       }
+
+       kfree(tmpbuf);
+       return 0;
+}
+
+int iscsi_encode_text_output(
+       u8 phase,
+       u8 sender,
+       char *textbuf,
+       u32 *length,
+       struct iscsi_param_list *param_list)
+{
+       char *output_buf = NULL;
+       struct iscsi_extra_response *er;
+       struct iscsi_param *param;
+
+       output_buf = textbuf + *length;
+
+       if (iscsi_enforce_integrity_rules(phase, param_list) < 0)
+               return -1;
+
+       list_for_each_entry(param, &param_list->param_list, p_list) {
+               if (!(param->sender & sender))
+                       continue;
+               if (IS_PSTATE_ACCEPTOR(param) &&
+                   !IS_PSTATE_RESPONSE_SENT(param) &&
+                   !IS_PSTATE_REPLY_OPTIONAL(param) &&
+                   (param->phase & phase)) {
+                       *length += sprintf(output_buf, "%s=%s",
+                               param->name, param->value);
+                       *length += 1;
+                       output_buf = textbuf + *length;
+                       SET_PSTATE_RESPONSE_SENT(param);
+                       pr_debug("Sending key: %s=%s\n",
+                               param->name, param->value);
+                       continue;
+               }
+               if (IS_PSTATE_NEGOTIATE(param) &&
+                   !IS_PSTATE_ACCEPTOR(param) &&
+                   !IS_PSTATE_PROPOSER(param) &&
+                   (param->phase & phase)) {
+                       *length += sprintf(output_buf, "%s=%s",
+                               param->name, param->value);
+                       *length += 1;
+                       output_buf = textbuf + *length;
+                       SET_PSTATE_PROPOSER(param);
+                       iscsi_check_proposer_for_optional_reply(param);
+                       pr_debug("Sending key: %s=%s\n",
+                               param->name, param->value);
+               }
+       }
+
+       list_for_each_entry(er, &param_list->extra_response_list, er_list) {
+               *length += sprintf(output_buf, "%s=%s", er->key, er->value);
+               *length += 1;
+               output_buf = textbuf + *length;
+               pr_debug("Sending key: %s=%s\n", er->key, er->value);
+       }
+       iscsi_release_extra_responses(param_list);
+
+       return 0;
+}
+
+int iscsi_check_negotiated_keys(struct iscsi_param_list *param_list)
+{
+       int ret = 0;
+       struct iscsi_param *param;
+
+       list_for_each_entry(param, &param_list->param_list, p_list) {
+               if (IS_PSTATE_NEGOTIATE(param) &&
+                   IS_PSTATE_PROPOSER(param) &&
+                   !IS_PSTATE_RESPONSE_GOT(param) &&
+                   !IS_PSTATE_REPLY_OPTIONAL(param) &&
+                   !IS_PHASE_DECLARATIVE(param)) {
+                       pr_err("No response for proposed key \"%s\".\n",
+                                       param->name);
+                       ret = -1;
+               }
+       }
+
+       return ret;
+}
+
+int iscsi_change_param_value(
+       char *keyvalue,
+       struct iscsi_param_list *param_list,
+       int check_key)
+{
+       char *key = NULL, *value = NULL;
+       struct iscsi_param *param;
+       int sender = 0;
+
+       if (iscsi_extract_key_value(keyvalue, &key, &value) < 0)
+               return -1;
+
+       if (!check_key) {
+               param = __iscsi_check_key(keyvalue, sender, param_list);
+               if (!param)
+                       return -1;
+       } else {
+               param = iscsi_check_key(keyvalue, 0, sender, param_list);
+               if (!param)
+                       return -1;
+
+               param->set_param = 1;
+               if (iscsi_check_value(param, value) < 0) {
+                       param->set_param = 0;
+                       return -1;
+               }
+               param->set_param = 0;
+       }
+
+       if (iscsi_update_param_value(param, value) < 0)
+               return -1;
+
+       return 0;
+}
+
+void iscsi_set_connection_parameters(
+       struct iscsi_conn_ops *ops,
+       struct iscsi_param_list *param_list)
+{
+       char *tmpptr;
+       struct iscsi_param *param;
+
+       pr_debug("---------------------------------------------------"
+                       "---------------\n");
+       list_for_each_entry(param, &param_list->param_list, p_list) {
+               if (!IS_PSTATE_ACCEPTOR(param) && !IS_PSTATE_PROPOSER(param))
+                       continue;
+               if (!strcmp(param->name, AUTHMETHOD)) {
+                       pr_debug("AuthMethod:                   %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, HEADERDIGEST)) {
+                       ops->HeaderDigest = !strcmp(param->value, CRC32C);
+                       pr_debug("HeaderDigest:                 %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, DATADIGEST)) {
+                       ops->DataDigest = !strcmp(param->value, CRC32C);
+                       pr_debug("DataDigest:                   %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
+                       ops->MaxRecvDataSegmentLength =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("MaxRecvDataSegmentLength:     %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, OFMARKER)) {
+                       ops->OFMarker = !strcmp(param->value, YES);
+                       pr_debug("OFMarker:                     %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, IFMARKER)) {
+                       ops->IFMarker = !strcmp(param->value, YES);
+                       pr_debug("IFMarker:                     %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, OFMARKINT)) {
+                       ops->OFMarkInt =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("OFMarkInt:                    %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, IFMARKINT)) {
+                       ops->IFMarkInt =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("IFMarkInt:                    %s\n",
+                               param->value);
+               }
+       }
+       pr_debug("----------------------------------------------------"
+                       "--------------\n");
+}
+
+void iscsi_set_session_parameters(
+       struct iscsi_sess_ops *ops,
+       struct iscsi_param_list *param_list,
+       int leading)
+{
+       char *tmpptr;
+       struct iscsi_param *param;
+
+       pr_debug("----------------------------------------------------"
+                       "--------------\n");
+       list_for_each_entry(param, &param_list->param_list, p_list) {
+               if (!IS_PSTATE_ACCEPTOR(param) && !IS_PSTATE_PROPOSER(param))
+                       continue;
+               if (!strcmp(param->name, INITIATORNAME)) {
+                       if (!param->value)
+                               continue;
+                       if (leading)
+                               snprintf(ops->InitiatorName,
+                                               sizeof(ops->InitiatorName),
+                                               "%s", param->value);
+                       pr_debug("InitiatorName:                %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, INITIATORALIAS)) {
+                       if (!param->value)
+                               continue;
+                       snprintf(ops->InitiatorAlias,
+                                               sizeof(ops->InitiatorAlias),
+                                               "%s", param->value);
+                       pr_debug("InitiatorAlias:               %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, TARGETNAME)) {
+                       if (!param->value)
+                               continue;
+                       if (leading)
+                               snprintf(ops->TargetName,
+                                               sizeof(ops->TargetName),
+                                               "%s", param->value);
+                       pr_debug("TargetName:                   %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, TARGETALIAS)) {
+                       if (!param->value)
+                               continue;
+                       snprintf(ops->TargetAlias, sizeof(ops->TargetAlias),
+                                       "%s", param->value);
+                       pr_debug("TargetAlias:                  %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, TARGETPORTALGROUPTAG)) {
+                       ops->TargetPortalGroupTag =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("TargetPortalGroupTag:         %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, MAXCONNECTIONS)) {
+                       ops->MaxConnections =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("MaxConnections:               %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, INITIALR2T)) {
+                       ops->InitialR2T = !strcmp(param->value, YES);
+                        pr_debug("InitialR2T:                   %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, IMMEDIATEDATA)) {
+                       ops->ImmediateData = !strcmp(param->value, YES);
+                       pr_debug("ImmediateData:                %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, MAXBURSTLENGTH)) {
+                       ops->MaxBurstLength =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("MaxBurstLength:               %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, FIRSTBURSTLENGTH)) {
+                       ops->FirstBurstLength =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("FirstBurstLength:             %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, DEFAULTTIME2WAIT)) {
+                       ops->DefaultTime2Wait =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("DefaultTime2Wait:             %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, DEFAULTTIME2RETAIN)) {
+                       ops->DefaultTime2Retain =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("DefaultTime2Retain:           %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, MAXOUTSTANDINGR2T)) {
+                       ops->MaxOutstandingR2T =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("MaxOutstandingR2T:            %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, DATAPDUINORDER)) {
+                       ops->DataPDUInOrder = !strcmp(param->value, YES);
+                       pr_debug("DataPDUInOrder:               %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, DATASEQUENCEINORDER)) {
+                       ops->DataSequenceInOrder = !strcmp(param->value, YES);
+                       pr_debug("DataSequenceInOrder:          %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, ERRORRECOVERYLEVEL)) {
+                       ops->ErrorRecoveryLevel =
+                               simple_strtoul(param->value, &tmpptr, 0);
+                       pr_debug("ErrorRecoveryLevel:           %s\n",
+                               param->value);
+               } else if (!strcmp(param->name, SESSIONTYPE)) {
+                       ops->SessionType = !strcmp(param->value, DISCOVERY);
+                       pr_debug("SessionType:                  %s\n",
+                               param->value);
+               }
+       }
+       pr_debug("----------------------------------------------------"
+                       "--------------\n");
+
+}
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
new file mode 100644 (file)
index 0000000..6a37fd6
--- /dev/null
@@ -0,0 +1,269 @@
+#ifndef ISCSI_PARAMETERS_H
+#define ISCSI_PARAMETERS_H
+
+struct iscsi_extra_response {
+       char key[64];
+       char value[32];
+       struct list_head er_list;
+} ____cacheline_aligned;
+
+struct iscsi_param {
+       char *name;
+       char *value;
+       u8 set_param;
+       u8 phase;
+       u8 scope;
+       u8 sender;
+       u8 type;
+       u8 use;
+       u16 type_range;
+       u32 state;
+       struct list_head p_list;
+} ____cacheline_aligned;
+
+extern int iscsi_login_rx_data(struct iscsi_conn *, char *, int);
+extern int iscsi_login_tx_data(struct iscsi_conn *, char *, char *, int);
+extern void iscsi_dump_conn_ops(struct iscsi_conn_ops *);
+extern void iscsi_dump_sess_ops(struct iscsi_sess_ops *);
+extern void iscsi_print_params(struct iscsi_param_list *);
+extern int iscsi_create_default_params(struct iscsi_param_list **);
+extern int iscsi_set_keys_to_negotiate(int, struct iscsi_param_list *);
+extern int iscsi_set_keys_irrelevant_for_discovery(struct iscsi_param_list *);
+extern int iscsi_copy_param_list(struct iscsi_param_list **,
+                       struct iscsi_param_list *, int);
+extern int iscsi_change_param_value(char *, struct iscsi_param_list *, int);
+extern void iscsi_release_param_list(struct iscsi_param_list *);
+extern struct iscsi_param *iscsi_find_param_from_key(char *, struct iscsi_param_list *);
+extern int iscsi_extract_key_value(char *, char **, char **);
+extern int iscsi_update_param_value(struct iscsi_param *, char *);
+extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_param_list *);
+extern int iscsi_encode_text_output(u8, u8, char *, u32 *,
+                       struct iscsi_param_list *);
+extern int iscsi_check_negotiated_keys(struct iscsi_param_list *);
+extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *,
+                       struct iscsi_param_list *);
+extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
+                       struct iscsi_param_list *, int);
+
+#define YES                            "Yes"
+#define NO                             "No"
+#define ALL                            "All"
+#define IRRELEVANT                     "Irrelevant"
+#define NONE                           "None"
+#define NOTUNDERSTOOD                  "NotUnderstood"
+#define REJECT                         "Reject"
+
+/*
+ * The Parameter Names.
+ */
+#define AUTHMETHOD                     "AuthMethod"
+#define HEADERDIGEST                   "HeaderDigest"
+#define DATADIGEST                     "DataDigest"
+#define MAXCONNECTIONS                 "MaxConnections"
+#define SENDTARGETS                    "SendTargets"
+#define TARGETNAME                     "TargetName"
+#define INITIATORNAME                  "InitiatorName"
+#define TARGETALIAS                    "TargetAlias"
+#define INITIATORALIAS                 "InitiatorAlias"
+#define TARGETADDRESS                  "TargetAddress"
+#define TARGETPORTALGROUPTAG           "TargetPortalGroupTag"
+#define INITIALR2T                     "InitialR2T"
+#define IMMEDIATEDATA                  "ImmediateData"
+#define MAXRECVDATASEGMENTLENGTH       "MaxRecvDataSegmentLength"
+#define MAXBURSTLENGTH                 "MaxBurstLength"
+#define FIRSTBURSTLENGTH               "FirstBurstLength"
+#define DEFAULTTIME2WAIT               "DefaultTime2Wait"
+#define DEFAULTTIME2RETAIN             "DefaultTime2Retain"
+#define MAXOUTSTANDINGR2T              "MaxOutstandingR2T"
+#define DATAPDUINORDER                 "DataPDUInOrder"
+#define DATASEQUENCEINORDER            "DataSequenceInOrder"
+#define ERRORRECOVERYLEVEL             "ErrorRecoveryLevel"
+#define SESSIONTYPE                    "SessionType"
+#define IFMARKER                       "IFMarker"
+#define OFMARKER                       "OFMarker"
+#define IFMARKINT                      "IFMarkInt"
+#define OFMARKINT                      "OFMarkInt"
+#define X_EXTENSIONKEY                 "X-com.sbei.version"
+#define X_EXTENSIONKEY_CISCO_NEW       "X-com.cisco.protocol"
+#define X_EXTENSIONKEY_CISCO_OLD       "X-com.cisco.iscsi.draft"
+
+/*
+ * For AuthMethod.
+ */
+#define KRB5                           "KRB5"
+#define SPKM1                          "SPKM1"
+#define SPKM2                          "SPKM2"
+#define SRP                            "SRP"
+#define CHAP                           "CHAP"
+
+/*
+ * Initial values for Parameter Negotiation.
+ */
+#define INITIAL_AUTHMETHOD                     CHAP
+#define INITIAL_HEADERDIGEST                   "CRC32C,None"
+#define INITIAL_DATADIGEST                     "CRC32C,None"
+#define INITIAL_MAXCONNECTIONS                 "1"
+#define INITIAL_SENDTARGETS                    ALL
+#define INITIAL_TARGETNAME                     "LIO.Target"
+#define INITIAL_INITIATORNAME                  "LIO.Initiator"
+#define INITIAL_TARGETALIAS                    "LIO Target"
+#define INITIAL_INITIATORALIAS                 "LIO Initiator"
+#define INITIAL_TARGETADDRESS                  "0.0.0.0:0000,0"
+#define INITIAL_TARGETPORTALGROUPTAG           "1"
+#define INITIAL_INITIALR2T                     YES
+#define INITIAL_IMMEDIATEDATA                  YES
+#define INITIAL_MAXRECVDATASEGMENTLENGTH       "8192"
+#define INITIAL_MAXBURSTLENGTH                 "262144"
+#define INITIAL_FIRSTBURSTLENGTH               "65536"
+#define INITIAL_DEFAULTTIME2WAIT               "2"
+#define INITIAL_DEFAULTTIME2RETAIN             "20"
+#define INITIAL_MAXOUTSTANDINGR2T              "1"
+#define INITIAL_DATAPDUINORDER                 YES
+#define INITIAL_DATASEQUENCEINORDER            YES
+#define INITIAL_ERRORRECOVERYLEVEL             "0"
+#define INITIAL_SESSIONTYPE                    NORMAL
+#define INITIAL_IFMARKER                       NO
+#define INITIAL_OFMARKER                       NO
+#define INITIAL_IFMARKINT                      "2048~65535"
+#define INITIAL_OFMARKINT                      "2048~65535"
+
+/*
+ * For [Header,Data]Digests.
+ */
+#define CRC32C                         "CRC32C"
+
+/*
+ * For SessionType.
+ */
+#define DISCOVERY                      "Discovery"
+#define NORMAL                         "Normal"
+
+/*
+ * struct iscsi_param->use
+ */
+#define USE_LEADING_ONLY               0x01
+#define USE_INITIAL_ONLY               0x02
+#define USE_ALL                                0x04
+
+#define IS_USE_LEADING_ONLY(p)         ((p)->use & USE_LEADING_ONLY)
+#define IS_USE_INITIAL_ONLY(p)         ((p)->use & USE_INITIAL_ONLY)
+#define IS_USE_ALL(p)                  ((p)->use & USE_ALL)
+
+#define SET_USE_INITIAL_ONLY(p)                ((p)->use |= USE_INITIAL_ONLY)
+
+/*
+ * struct iscsi_param->sender
+ */
+#define        SENDER_INITIATOR                0x01
+#define SENDER_TARGET                  0x02
+#define SENDER_BOTH                    0x03
+/* Used in iscsi_check_key() */
+#define SENDER_RECEIVER                        0x04
+
+#define IS_SENDER_INITIATOR(p)         ((p)->sender & SENDER_INITIATOR)
+#define IS_SENDER_TARGET(p)            ((p)->sender & SENDER_TARGET)
+#define IS_SENDER_BOTH(p)              ((p)->sender & SENDER_BOTH)
+
+/*
+ * struct iscsi_param->scope
+ */
+#define SCOPE_CONNECTION_ONLY          0x01
+#define SCOPE_SESSION_WIDE             0x02
+
+#define IS_SCOPE_CONNECTION_ONLY(p)    ((p)->scope & SCOPE_CONNECTION_ONLY)
+#define IS_SCOPE_SESSION_WIDE(p)       ((p)->scope & SCOPE_SESSION_WIDE)
+
+/*
+ * struct iscsi_param->phase
+ */
+#define PHASE_SECURITY                 0x01
+#define PHASE_OPERATIONAL              0x02
+#define PHASE_DECLARATIVE              0x04
+#define PHASE_FFP0                     0x08
+
+#define IS_PHASE_SECURITY(p)           ((p)->phase & PHASE_SECURITY)
+#define IS_PHASE_OPERATIONAL(p)                ((p)->phase & PHASE_OPERATIONAL)
+#define IS_PHASE_DECLARATIVE(p)                ((p)->phase & PHASE_DECLARATIVE)
+#define IS_PHASE_FFP0(p)               ((p)->phase & PHASE_FFP0)
+
+/*
+ * struct iscsi_param->type
+ */
+#define TYPE_BOOL_AND                  0x01
+#define TYPE_BOOL_OR                   0x02
+#define TYPE_NUMBER                    0x04
+#define TYPE_NUMBER_RANGE              0x08
+#define TYPE_STRING                    0x10
+#define TYPE_VALUE_LIST                        0x20
+
+#define IS_TYPE_BOOL_AND(p)            ((p)->type & TYPE_BOOL_AND)
+#define IS_TYPE_BOOL_OR(p)             ((p)->type & TYPE_BOOL_OR)
+#define IS_TYPE_NUMBER(p)              ((p)->type & TYPE_NUMBER)
+#define IS_TYPE_NUMBER_RANGE(p)                ((p)->type & TYPE_NUMBER_RANGE)
+#define IS_TYPE_STRING(p)              ((p)->type & TYPE_STRING)
+#define IS_TYPE_VALUE_LIST(p)          ((p)->type & TYPE_VALUE_LIST)
+
+/*
+ * struct iscsi_param->type_range
+ */
+#define TYPERANGE_BOOL_AND             0x0001
+#define TYPERANGE_BOOL_OR              0x0002
+#define TYPERANGE_0_TO_2               0x0004
+#define TYPERANGE_0_TO_3600            0x0008
+#define TYPERANGE_0_TO_32767           0x0010
+#define TYPERANGE_0_TO_65535           0x0020
+#define TYPERANGE_1_TO_65535           0x0040
+#define TYPERANGE_2_TO_3600            0x0080
+#define TYPERANGE_512_TO_16777215      0x0100
+#define TYPERANGE_AUTH                 0x0200
+#define TYPERANGE_DIGEST               0x0400
+#define TYPERANGE_ISCSINAME            0x0800
+#define TYPERANGE_MARKINT              0x1000
+#define TYPERANGE_SESSIONTYPE          0x2000
+#define TYPERANGE_TARGETADDRESS                0x4000
+#define TYPERANGE_UTF8                 0x8000
+
+#define IS_TYPERANGE_0_TO_2(p)         ((p)->type_range & TYPERANGE_0_TO_2)
+#define IS_TYPERANGE_0_TO_3600(p)      ((p)->type_range & TYPERANGE_0_TO_3600)
+#define IS_TYPERANGE_0_TO_32767(p)     ((p)->type_range & TYPERANGE_0_TO_32767)
+#define IS_TYPERANGE_0_TO_65535(p)     ((p)->type_range & TYPERANGE_0_TO_65535)
+#define IS_TYPERANGE_1_TO_65535(p)     ((p)->type_range & TYPERANGE_1_TO_65535)
+#define IS_TYPERANGE_2_TO_3600(p)      ((p)->type_range & TYPERANGE_2_TO_3600)
+#define IS_TYPERANGE_512_TO_16777215(p)        ((p)->type_range & \
+                                               TYPERANGE_512_TO_16777215)
+#define IS_TYPERANGE_AUTH_PARAM(p)     ((p)->type_range & TYPERANGE_AUTH)
+#define IS_TYPERANGE_DIGEST_PARAM(p)   ((p)->type_range & TYPERANGE_DIGEST)
+#define IS_TYPERANGE_SESSIONTYPE(p)    ((p)->type_range & \
+                                               TYPERANGE_SESSIONTYPE)
+
+/*
+ * struct iscsi_param->state
+ */
+#define PSTATE_ACCEPTOR                        0x01
+#define PSTATE_NEGOTIATE               0x02
+#define PSTATE_PROPOSER                        0x04
+#define PSTATE_IRRELEVANT              0x08
+#define PSTATE_REJECT                  0x10
+#define PSTATE_REPLY_OPTIONAL          0x20
+#define PSTATE_RESPONSE_GOT            0x40
+#define PSTATE_RESPONSE_SENT           0x80
+
+#define IS_PSTATE_ACCEPTOR(p)          ((p)->state & PSTATE_ACCEPTOR)
+#define IS_PSTATE_NEGOTIATE(p)         ((p)->state & PSTATE_NEGOTIATE)
+#define IS_PSTATE_PROPOSER(p)          ((p)->state & PSTATE_PROPOSER)
+#define IS_PSTATE_IRRELEVANT(p)                ((p)->state & PSTATE_IRRELEVANT)
+#define IS_PSTATE_REJECT(p)            ((p)->state & PSTATE_REJECT)
+#define IS_PSTATE_REPLY_OPTIONAL(p)    ((p)->state & PSTATE_REPLY_OPTIONAL)
+#define IS_PSTATE_RESPONSE_GOT(p)      ((p)->state & PSTATE_RESPONSE_GOT)
+#define IS_PSTATE_RESPONSE_SENT(p)     ((p)->state & PSTATE_RESPONSE_SENT)
+
+#define SET_PSTATE_ACCEPTOR(p)         ((p)->state |= PSTATE_ACCEPTOR)
+#define SET_PSTATE_NEGOTIATE(p)                ((p)->state |= PSTATE_NEGOTIATE)
+#define SET_PSTATE_PROPOSER(p)         ((p)->state |= PSTATE_PROPOSER)
+#define SET_PSTATE_IRRELEVANT(p)       ((p)->state |= PSTATE_IRRELEVANT)
+#define SET_PSTATE_REJECT(p)           ((p)->state |= PSTATE_REJECT)
+#define SET_PSTATE_REPLY_OPTIONAL(p)   ((p)->state |= PSTATE_REPLY_OPTIONAL)
+#define SET_PSTATE_RESPONSE_GOT(p)     ((p)->state |= PSTATE_RESPONSE_GOT)
+#define SET_PSTATE_RESPONSE_SENT(p)    ((p)->state |= PSTATE_RESPONSE_SENT)
+
+#endif /* ISCSI_PARAMETERS_H */
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
new file mode 100644 (file)
index 0000000..fc69408
--- /dev/null
@@ -0,0 +1,664 @@
+/*******************************************************************************
+ * This file contains main functions related to iSCSI DataSequenceInOrder=No
+ * and DataPDUInOrder=No.
+ *
+ \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <linux/slab.h>
+#include <linux/random.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target_seq_pdu_list.h"
+
+#define OFFLOAD_BUF_SIZE       32768
+
+void iscsit_dump_seq_list(struct iscsi_cmd *cmd)
+{
+       int i;
+       struct iscsi_seq *seq;
+
+       pr_debug("Dumping Sequence List for ITT: 0x%08x:\n",
+                       cmd->init_task_tag);
+
+       for (i = 0; i < cmd->seq_count; i++) {
+               seq = &cmd->seq_list[i];
+               pr_debug("i: %d, pdu_start: %d, pdu_count: %d,"
+                       " offset: %d, xfer_len: %d, seq_send_order: %d,"
+                       " seq_no: %d\n", i, seq->pdu_start, seq->pdu_count,
+                       seq->offset, seq->xfer_len, seq->seq_send_order,
+                       seq->seq_no);
+       }
+}
+
+void iscsit_dump_pdu_list(struct iscsi_cmd *cmd)
+{
+       int i;
+       struct iscsi_pdu *pdu;
+
+       pr_debug("Dumping PDU List for ITT: 0x%08x:\n",
+                       cmd->init_task_tag);
+
+       for (i = 0; i < cmd->pdu_count; i++) {
+               pdu = &cmd->pdu_list[i];
+               pr_debug("i: %d, offset: %d, length: %d,"
+                       " pdu_send_order: %d, seq_no: %d\n", i, pdu->offset,
+                       pdu->length, pdu->pdu_send_order, pdu->seq_no);
+       }
+}
+
+static void iscsit_ordered_seq_lists(
+       struct iscsi_cmd *cmd,
+       u8 type)
+{
+       u32 i, seq_count = 0;
+
+       for (i = 0; i < cmd->seq_count; i++) {
+               if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
+                       continue;
+               cmd->seq_list[i].seq_send_order = seq_count++;
+       }
+}
+
+static void iscsit_ordered_pdu_lists(
+       struct iscsi_cmd *cmd,
+       u8 type)
+{
+       u32 i, pdu_send_order = 0, seq_no = 0;
+
+       for (i = 0; i < cmd->pdu_count; i++) {
+redo:
+               if (cmd->pdu_list[i].seq_no == seq_no) {
+                       cmd->pdu_list[i].pdu_send_order = pdu_send_order++;
+                       continue;
+               }
+               seq_no++;
+               pdu_send_order = 0;
+               goto redo;
+       }
+}
+
+/*
+ *     Generate count random values into array.
+ *     Use 0x80000000 to mark generates valued in array[].
+ */
+static void iscsit_create_random_array(u32 *array, u32 count)
+{
+       int i, j, k;
+
+       if (count == 1) {
+               array[0] = 0;
+               return;
+       }
+
+       for (i = 0; i < count; i++) {
+redo:
+               get_random_bytes(&j, sizeof(u32));
+               j = (1 + (int) (9999 + 1) - j) % count;
+               for (k = 0; k < i + 1; k++) {
+                       j |= 0x80000000;
+                       if ((array[k] & 0x80000000) && (array[k] == j))
+                               goto redo;
+               }
+               array[i] = j;
+       }
+
+       for (i = 0; i < count; i++)
+               array[i] &= ~0x80000000;
+}
+
+static int iscsit_randomize_pdu_lists(
+       struct iscsi_cmd *cmd,
+       u8 type)
+{
+       int i = 0;
+       u32 *array, pdu_count, seq_count = 0, seq_no = 0, seq_offset = 0;
+
+       for (pdu_count = 0; pdu_count < cmd->pdu_count; pdu_count++) {
+redo:
+               if (cmd->pdu_list[pdu_count].seq_no == seq_no) {
+                       seq_count++;
+                       continue;
+               }
+               array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
+               if (!array) {
+                       pr_err("Unable to allocate memory"
+                               " for random array.\n");
+                       return -1;
+               }
+               iscsit_create_random_array(array, seq_count);
+
+               for (i = 0; i < seq_count; i++)
+                       cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
+
+               kfree(array);
+
+               seq_offset += seq_count;
+               seq_count = 0;
+               seq_no++;
+               goto redo;
+       }
+
+       if (seq_count) {
+               array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
+               if (!array) {
+                       pr_err("Unable to allocate memory for"
+                               " random array.\n");
+                       return -1;
+               }
+               iscsit_create_random_array(array, seq_count);
+
+               for (i = 0; i < seq_count; i++)
+                       cmd->pdu_list[seq_offset+i].pdu_send_order = array[i];
+
+               kfree(array);
+       }
+
+       return 0;
+}
+
+static int iscsit_randomize_seq_lists(
+       struct iscsi_cmd *cmd,
+       u8 type)
+{
+       int i, j = 0;
+       u32 *array, seq_count = cmd->seq_count;
+
+       if ((type == PDULIST_IMMEDIATE) || (type == PDULIST_UNSOLICITED))
+               seq_count--;
+       else if (type == PDULIST_IMMEDIATE_AND_UNSOLICITED)
+               seq_count -= 2;
+
+       if (!seq_count)
+               return 0;
+
+       array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL);
+       if (!array) {
+               pr_err("Unable to allocate memory for random array.\n");
+               return -1;
+       }
+       iscsit_create_random_array(array, seq_count);
+
+       for (i = 0; i < cmd->seq_count; i++) {
+               if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
+                       continue;
+               cmd->seq_list[i].seq_send_order = array[j++];
+       }
+
+       kfree(array);
+       return 0;
+}
+
+static void iscsit_determine_counts_for_list(
+       struct iscsi_cmd *cmd,
+       struct iscsi_build_list *bl,
+       u32 *seq_count,
+       u32 *pdu_count)
+{
+       int check_immediate = 0;
+       u32 burstlength = 0, offset = 0;
+       u32 unsolicited_data_length = 0;
+       struct iscsi_conn *conn = cmd->conn;
+
+       if ((bl->type == PDULIST_IMMEDIATE) ||
+           (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
+               check_immediate = 1;
+
+       if ((bl->type == PDULIST_UNSOLICITED) ||
+           (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
+               unsolicited_data_length = (cmd->data_length >
+                       conn->sess->sess_ops->FirstBurstLength) ?
+                       conn->sess->sess_ops->FirstBurstLength : cmd->data_length;
+
+       while (offset < cmd->data_length) {
+               *pdu_count += 1;
+
+               if (check_immediate) {
+                       check_immediate = 0;
+                       offset += bl->immediate_data_length;
+                       *seq_count += 1;
+                       if (unsolicited_data_length)
+                               unsolicited_data_length -=
+                                       bl->immediate_data_length;
+                       continue;
+               }
+               if (unsolicited_data_length > 0) {
+                       if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
+                                       >= cmd->data_length) {
+                               unsolicited_data_length -=
+                                       (cmd->data_length - offset);
+                               offset += (cmd->data_length - offset);
+                               continue;
+                       }
+                       if ((offset + conn->conn_ops->MaxRecvDataSegmentLength)
+                                       >= conn->sess->sess_ops->FirstBurstLength) {
+                               unsolicited_data_length -=
+                                       (conn->sess->sess_ops->FirstBurstLength -
+                                       offset);
+                               offset += (conn->sess->sess_ops->FirstBurstLength -
+                                       offset);
+                               burstlength = 0;
+                               *seq_count += 1;
+                               continue;
+                       }
+
+                       offset += conn->conn_ops->MaxRecvDataSegmentLength;
+                       unsolicited_data_length -=
+                               conn->conn_ops->MaxRecvDataSegmentLength;
+                       continue;
+               }
+               if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
+                    cmd->data_length) {
+                       offset += (cmd->data_length - offset);
+                       continue;
+               }
+               if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
+                    conn->sess->sess_ops->MaxBurstLength) {
+                       offset += (conn->sess->sess_ops->MaxBurstLength -
+                                       burstlength);
+                       burstlength = 0;
+                       *seq_count += 1;
+                       continue;
+               }
+
+               burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
+               offset += conn->conn_ops->MaxRecvDataSegmentLength;
+       }
+}
+
+
+/*
+ *     Builds PDU and/or Sequence list,  called while DataSequenceInOrder=No
+ *     and DataPDUInOrder=No.
+ */
+static int iscsit_build_pdu_and_seq_list(
+       struct iscsi_cmd *cmd,
+       struct iscsi_build_list *bl)
+{
+       int check_immediate = 0, datapduinorder, datasequenceinorder;
+       u32 burstlength = 0, offset = 0, i = 0;
+       u32 pdu_count = 0, seq_no = 0, unsolicited_data_length = 0;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_pdu *pdu = cmd->pdu_list;
+       struct iscsi_seq *seq = cmd->seq_list;
+
+       datapduinorder = conn->sess->sess_ops->DataPDUInOrder;
+       datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder;
+
+       if ((bl->type == PDULIST_IMMEDIATE) ||
+           (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
+               check_immediate = 1;
+
+       if ((bl->type == PDULIST_UNSOLICITED) ||
+           (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED))
+               unsolicited_data_length = (cmd->data_length >
+                       conn->sess->sess_ops->FirstBurstLength) ?
+                       conn->sess->sess_ops->FirstBurstLength : cmd->data_length;
+
+       while (offset < cmd->data_length) {
+               pdu_count++;
+               if (!datapduinorder) {
+                       pdu[i].offset = offset;
+                       pdu[i].seq_no = seq_no;
+               }
+               if (!datasequenceinorder && (pdu_count == 1)) {
+                       seq[seq_no].pdu_start = i;
+                       seq[seq_no].seq_no = seq_no;
+                       seq[seq_no].offset = offset;
+                       seq[seq_no].orig_offset = offset;
+               }
+
+               if (check_immediate) {
+                       check_immediate = 0;
+                       if (!datapduinorder) {
+                               pdu[i].type = PDUTYPE_IMMEDIATE;
+                               pdu[i++].length = bl->immediate_data_length;
+                       }
+                       if (!datasequenceinorder) {
+                               seq[seq_no].type = SEQTYPE_IMMEDIATE;
+                               seq[seq_no].pdu_count = 1;
+                               seq[seq_no].xfer_len =
+                                       bl->immediate_data_length;
+                       }
+                       offset += bl->immediate_data_length;
+                       pdu_count = 0;
+                       seq_no++;
+                       if (unsolicited_data_length)
+                               unsolicited_data_length -=
+                                       bl->immediate_data_length;
+                       continue;
+               }
+               if (unsolicited_data_length > 0) {
+                       if ((offset +
+                            conn->conn_ops->MaxRecvDataSegmentLength) >=
+                            cmd->data_length) {
+                               if (!datapduinorder) {
+                                       pdu[i].type = PDUTYPE_UNSOLICITED;
+                                       pdu[i].length =
+                                               (cmd->data_length - offset);
+                               }
+                               if (!datasequenceinorder) {
+                                       seq[seq_no].type = SEQTYPE_UNSOLICITED;
+                                       seq[seq_no].pdu_count = pdu_count;
+                                       seq[seq_no].xfer_len = (burstlength +
+                                               (cmd->data_length - offset));
+                               }
+                               unsolicited_data_length -=
+                                               (cmd->data_length - offset);
+                               offset += (cmd->data_length - offset);
+                               continue;
+                       }
+                       if ((offset +
+                            conn->conn_ops->MaxRecvDataSegmentLength) >=
+                                       conn->sess->sess_ops->FirstBurstLength) {
+                               if (!datapduinorder) {
+                                       pdu[i].type = PDUTYPE_UNSOLICITED;
+                                       pdu[i++].length =
+                                          (conn->sess->sess_ops->FirstBurstLength -
+                                               offset);
+                               }
+                               if (!datasequenceinorder) {
+                                       seq[seq_no].type = SEQTYPE_UNSOLICITED;
+                                       seq[seq_no].pdu_count = pdu_count;
+                                       seq[seq_no].xfer_len = (burstlength +
+                                          (conn->sess->sess_ops->FirstBurstLength -
+                                               offset));
+                               }
+                               unsolicited_data_length -=
+                                       (conn->sess->sess_ops->FirstBurstLength -
+                                               offset);
+                               offset += (conn->sess->sess_ops->FirstBurstLength -
+                                               offset);
+                               burstlength = 0;
+                               pdu_count = 0;
+                               seq_no++;
+                               continue;
+                       }
+
+                       if (!datapduinorder) {
+                               pdu[i].type = PDUTYPE_UNSOLICITED;
+                               pdu[i++].length =
+                                    conn->conn_ops->MaxRecvDataSegmentLength;
+                       }
+                       burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
+                       offset += conn->conn_ops->MaxRecvDataSegmentLength;
+                       unsolicited_data_length -=
+                               conn->conn_ops->MaxRecvDataSegmentLength;
+                       continue;
+               }
+               if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >=
+                    cmd->data_length) {
+                       if (!datapduinorder) {
+                               pdu[i].type = PDUTYPE_NORMAL;
+                               pdu[i].length = (cmd->data_length - offset);
+                       }
+                       if (!datasequenceinorder) {
+                               seq[seq_no].type = SEQTYPE_NORMAL;
+                               seq[seq_no].pdu_count = pdu_count;
+                               seq[seq_no].xfer_len = (burstlength +
+                                       (cmd->data_length - offset));
+                       }
+                       offset += (cmd->data_length - offset);
+                       continue;
+               }
+               if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >=
+                    conn->sess->sess_ops->MaxBurstLength) {
+                       if (!datapduinorder) {
+                               pdu[i].type = PDUTYPE_NORMAL;
+                               pdu[i++].length =
+                                       (conn->sess->sess_ops->MaxBurstLength -
+                                               burstlength);
+                       }
+                       if (!datasequenceinorder) {
+                               seq[seq_no].type = SEQTYPE_NORMAL;
+                               seq[seq_no].pdu_count = pdu_count;
+                               seq[seq_no].xfer_len = (burstlength +
+                                       (conn->sess->sess_ops->MaxBurstLength -
+                                       burstlength));
+                       }
+                       offset += (conn->sess->sess_ops->MaxBurstLength -
+                                       burstlength);
+                       burstlength = 0;
+                       pdu_count = 0;
+                       seq_no++;
+                       continue;
+               }
+
+               if (!datapduinorder) {
+                       pdu[i].type = PDUTYPE_NORMAL;
+                       pdu[i++].length =
+                               conn->conn_ops->MaxRecvDataSegmentLength;
+               }
+               burstlength += conn->conn_ops->MaxRecvDataSegmentLength;
+               offset += conn->conn_ops->MaxRecvDataSegmentLength;
+       }
+
+       if (!datasequenceinorder) {
+               if (bl->data_direction & ISCSI_PDU_WRITE) {
+                       if (bl->randomize & RANDOM_R2T_OFFSETS) {
+                               if (iscsit_randomize_seq_lists(cmd, bl->type)
+                                               < 0)
+                                       return -1;
+                       } else
+                               iscsit_ordered_seq_lists(cmd, bl->type);
+               } else if (bl->data_direction & ISCSI_PDU_READ) {
+                       if (bl->randomize & RANDOM_DATAIN_SEQ_OFFSETS) {
+                               if (iscsit_randomize_seq_lists(cmd, bl->type)
+                                               < 0)
+                                       return -1;
+                       } else
+                               iscsit_ordered_seq_lists(cmd, bl->type);
+               }
+#if 0
+               iscsit_dump_seq_list(cmd);
+#endif
+       }
+       if (!datapduinorder) {
+               if (bl->data_direction & ISCSI_PDU_WRITE) {
+                       if (bl->randomize & RANDOM_DATAOUT_PDU_OFFSETS) {
+                               if (iscsit_randomize_pdu_lists(cmd, bl->type)
+                                               < 0)
+                                       return -1;
+                       } else
+                               iscsit_ordered_pdu_lists(cmd, bl->type);
+               } else if (bl->data_direction & ISCSI_PDU_READ) {
+                       if (bl->randomize & RANDOM_DATAIN_PDU_OFFSETS) {
+                               if (iscsit_randomize_pdu_lists(cmd, bl->type)
+                                               < 0)
+                                       return -1;
+                       } else
+                               iscsit_ordered_pdu_lists(cmd, bl->type);
+               }
+#if 0
+               iscsit_dump_pdu_list(cmd);
+#endif
+       }
+
+       return 0;
+}
+
+/*
+ *     Only called while DataSequenceInOrder=No or DataPDUInOrder=No.
+ */
+int iscsit_do_build_list(
+       struct iscsi_cmd *cmd,
+       struct iscsi_build_list *bl)
+{
+       u32 pdu_count = 0, seq_count = 1;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_pdu *pdu = NULL;
+       struct iscsi_seq *seq = NULL;
+
+       iscsit_determine_counts_for_list(cmd, bl, &seq_count, &pdu_count);
+
+       if (!conn->sess->sess_ops->DataSequenceInOrder) {
+               seq = kzalloc(seq_count * sizeof(struct iscsi_seq), GFP_ATOMIC);
+               if (!seq) {
+                       pr_err("Unable to allocate struct iscsi_seq list\n");
+                       return -1;
+               }
+               cmd->seq_list = seq;
+               cmd->seq_count = seq_count;
+       }
+
+       if (!conn->sess->sess_ops->DataPDUInOrder) {
+               pdu = kzalloc(pdu_count * sizeof(struct iscsi_pdu), GFP_ATOMIC);
+               if (!pdu) {
+                       pr_err("Unable to allocate struct iscsi_pdu list.\n");
+                       kfree(seq);
+                       return -1;
+               }
+               cmd->pdu_list = pdu;
+               cmd->pdu_count = pdu_count;
+       }
+
+       return iscsit_build_pdu_and_seq_list(cmd, bl);
+}
+
+struct iscsi_pdu *iscsit_get_pdu_holder(
+       struct iscsi_cmd *cmd,
+       u32 offset,
+       u32 length)
+{
+       u32 i;
+       struct iscsi_pdu *pdu = NULL;
+
+       if (!cmd->pdu_list) {
+               pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
+               return NULL;
+       }
+
+       pdu = &cmd->pdu_list[0];
+
+       for (i = 0; i < cmd->pdu_count; i++)
+               if ((pdu[i].offset == offset) && (pdu[i].length == length))
+                       return &pdu[i];
+
+       pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:"
+               " %u, Length: %u\n", cmd->init_task_tag, offset, length);
+       return NULL;
+}
+
+struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(
+       struct iscsi_cmd *cmd,
+       struct iscsi_seq *seq)
+{
+       u32 i;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_pdu *pdu = NULL;
+
+       if (!cmd->pdu_list) {
+               pr_err("struct iscsi_cmd->pdu_list is NULL!\n");
+               return NULL;
+       }
+
+       if (conn->sess->sess_ops->DataSequenceInOrder) {
+redo:
+               pdu = &cmd->pdu_list[cmd->pdu_start];
+
+               for (i = 0; pdu[i].seq_no != cmd->seq_no; i++) {
+#if 0
+                       pr_debug("pdu[i].seq_no: %d, pdu[i].pdu"
+                               "_send_order: %d, pdu[i].offset: %d,"
+                               " pdu[i].length: %d\n", pdu[i].seq_no,
+                               pdu[i].pdu_send_order, pdu[i].offset,
+                               pdu[i].length);
+#endif
+                       if (pdu[i].pdu_send_order == cmd->pdu_send_order) {
+                               cmd->pdu_send_order++;
+                               return &pdu[i];
+                       }
+               }
+
+               cmd->pdu_start += cmd->pdu_send_order;
+               cmd->pdu_send_order = 0;
+               cmd->seq_no++;
+
+               if (cmd->pdu_start < cmd->pdu_count)
+                       goto redo;
+
+               pr_err("Command ITT: 0x%08x unable to locate"
+                       " struct iscsi_pdu for cmd->pdu_send_order: %u.\n",
+                       cmd->init_task_tag, cmd->pdu_send_order);
+               return NULL;
+       } else {
+               if (!seq) {
+                       pr_err("struct iscsi_seq is NULL!\n");
+                       return NULL;
+               }
+#if 0
+               pr_debug("seq->pdu_start: %d, seq->pdu_count: %d,"
+                       " seq->seq_no: %d\n", seq->pdu_start, seq->pdu_count,
+                       seq->seq_no);
+#endif
+               pdu = &cmd->pdu_list[seq->pdu_start];
+
+               if (seq->pdu_send_order == seq->pdu_count) {
+                       pr_err("Command ITT: 0x%08x seq->pdu_send"
+                               "_order: %u equals seq->pdu_count: %u\n",
+                               cmd->init_task_tag, seq->pdu_send_order,
+                               seq->pdu_count);
+                       return NULL;
+               }
+
+               for (i = 0; i < seq->pdu_count; i++) {
+                       if (pdu[i].pdu_send_order == seq->pdu_send_order) {
+                               seq->pdu_send_order++;
+                               return &pdu[i];
+                       }
+               }
+
+               pr_err("Command ITT: 0x%08x unable to locate iscsi"
+                       "_pdu_t for seq->pdu_send_order: %u.\n",
+                       cmd->init_task_tag, seq->pdu_send_order);
+               return NULL;
+       }
+
+       return NULL;
+}
+
+struct iscsi_seq *iscsit_get_seq_holder(
+       struct iscsi_cmd *cmd,
+       u32 offset,
+       u32 length)
+{
+       u32 i;
+
+       if (!cmd->seq_list) {
+               pr_err("struct iscsi_cmd->seq_list is NULL!\n");
+               return NULL;
+       }
+
+       for (i = 0; i < cmd->seq_count; i++) {
+#if 0
+               pr_debug("seq_list[i].orig_offset: %d, seq_list[i]."
+                       "xfer_len: %d, seq_list[i].seq_no %u\n",
+                       cmd->seq_list[i].orig_offset, cmd->seq_list[i].xfer_len,
+                       cmd->seq_list[i].seq_no);
+#endif
+               if ((cmd->seq_list[i].orig_offset +
+                               cmd->seq_list[i].xfer_len) >=
+                               (offset + length))
+                       return &cmd->seq_list[i];
+       }
+
+       pr_err("Unable to locate Sequence holder for ITT: 0x%08x,"
+               " Offset: %u, Length: %u\n", cmd->init_task_tag, offset,
+               length);
+       return NULL;
+}
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.h b/drivers/target/iscsi/iscsi_target_seq_pdu_list.h
new file mode 100644 (file)
index 0000000..0d52a10
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef ISCSI_SEQ_AND_PDU_LIST_H
+#define ISCSI_SEQ_AND_PDU_LIST_H
+
+/* struct iscsi_pdu->status */
+#define DATAOUT_PDU_SENT                       1
+
+/* struct iscsi_seq->type */
+#define SEQTYPE_IMMEDIATE                      1
+#define SEQTYPE_UNSOLICITED                    2
+#define SEQTYPE_NORMAL                         3
+
+/* struct iscsi_seq->status */
+#define DATAOUT_SEQUENCE_GOT_R2T               1
+#define DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY 2
+#define DATAOUT_SEQUENCE_COMPLETE              3
+
+/* iscsi_determine_counts_for_list() type */
+#define PDULIST_NORMAL                         1
+#define PDULIST_IMMEDIATE                      2
+#define PDULIST_UNSOLICITED                    3
+#define PDULIST_IMMEDIATE_AND_UNSOLICITED      4
+
+/* struct iscsi_pdu->type */
+#define PDUTYPE_IMMEDIATE                      1
+#define PDUTYPE_UNSOLICITED                    2
+#define PDUTYPE_NORMAL                         3
+
+/* struct iscsi_pdu->status */
+#define ISCSI_PDU_NOT_RECEIVED                 0
+#define ISCSI_PDU_RECEIVED_OK                  1
+#define ISCSI_PDU_CRC_FAILED                   2
+#define ISCSI_PDU_TIMED_OUT                    3
+
+/* struct iscsi_build_list->randomize */
+#define RANDOM_DATAIN_PDU_OFFSETS              0x01
+#define RANDOM_DATAIN_SEQ_OFFSETS              0x02
+#define RANDOM_DATAOUT_PDU_OFFSETS             0x04
+#define RANDOM_R2T_OFFSETS                     0x08
+
+/* struct iscsi_build_list->data_direction */
+#define ISCSI_PDU_READ                         0x01
+#define ISCSI_PDU_WRITE                                0x02
+
+struct iscsi_build_list {
+       int             data_direction;
+       int             randomize;
+       int             type;
+       int             immediate_data_length;
+};
+
+struct iscsi_pdu {
+       int             status;
+       int             type;
+       u8              flags;
+       u32             data_sn;
+       u32             length;
+       u32             offset;
+       u32             pdu_send_order;
+       u32             seq_no;
+} ____cacheline_aligned;
+
+struct iscsi_seq {
+       int             sent;
+       int             status;
+       int             type;
+       u32             data_sn;
+       u32             first_datasn;
+       u32             last_datasn;
+       u32             next_burst_len;
+       u32             pdu_start;
+       u32             pdu_count;
+       u32             offset;
+       u32             orig_offset;
+       u32             pdu_send_order;
+       u32             r2t_sn;
+       u32             seq_send_order;
+       u32             seq_no;
+       u32             xfer_len;
+} ____cacheline_aligned;
+
+extern int iscsit_do_build_list(struct iscsi_cmd *, struct iscsi_build_list *);
+extern struct iscsi_pdu *iscsit_get_pdu_holder(struct iscsi_cmd *, u32, u32);
+extern struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(struct iscsi_cmd *, struct iscsi_seq *);
+extern struct iscsi_seq *iscsit_get_seq_holder(struct iscsi_cmd *, u32, u32);
+
+#endif /* ISCSI_SEQ_AND_PDU_LIST_H */
diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c
new file mode 100644 (file)
index 0000000..bbdbe93
--- /dev/null
@@ -0,0 +1,950 @@
+/*******************************************************************************
+ * Modern ConfigFS group context specific iSCSI statistics based on original
+ * iscsi_target_mib.c code
+ *
+ * Copyright (c) 2011 Rising Tide Systems
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <linux/configfs.h>
+#include <scsi/iscsi_proto.h>
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+#include <target/configfs_macros.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_parameters.h"
+#include "iscsi_target_device.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target_stat.h"
+
+#ifndef INITIAL_JIFFIES
+#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
+#endif
+
+/* Instance Attributes Table */
+#define ISCSI_INST_NUM_NODES           1
+#define ISCSI_INST_DESCR               "Storage Engine Target"
+#define ISCSI_INST_LAST_FAILURE_TYPE   0
+#define ISCSI_DISCONTINUITY_TIME       0
+
+#define ISCSI_NODE_INDEX               1
+
+#define ISPRINT(a)   ((a >= ' ') && (a <= '~'))
+
+/****************************************************************************
+ * iSCSI MIB Tables
+ ****************************************************************************/
+/*
+ * Instance Attributes Table
+ */
+CONFIGFS_EATTR_STRUCT(iscsi_stat_instance, iscsi_wwn_stat_grps);
+#define ISCSI_STAT_INSTANCE_ATTR(_name, _mode)                 \
+static struct iscsi_stat_instance_attribute                    \
+                       iscsi_stat_instance_##_name =           \
+       __CONFIGFS_EATTR(_name, _mode,                          \
+       iscsi_stat_instance_show_attr_##_name,                  \
+       iscsi_stat_instance_store_attr_##_name);
+
+#define ISCSI_STAT_INSTANCE_ATTR_RO(_name)                     \
+static struct iscsi_stat_instance_attribute                    \
+                       iscsi_stat_instance_##_name =           \
+       __CONFIGFS_EATTR_RO(_name,                              \
+       iscsi_stat_instance_show_attr_##_name);
+
+static ssize_t iscsi_stat_instance_show_attr_inst(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(inst);
+
+static ssize_t iscsi_stat_instance_show_attr_min_ver(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DRAFT20_VERSION);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(min_ver);
+
+static ssize_t iscsi_stat_instance_show_attr_max_ver(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DRAFT20_VERSION);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(max_ver);
+
+static ssize_t iscsi_stat_instance_show_attr_portals(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_num_tpg_nps);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(portals);
+
+static ssize_t iscsi_stat_instance_show_attr_nodes(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_INST_NUM_NODES);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(nodes);
+
+static ssize_t iscsi_stat_instance_show_attr_sessions(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_nsessions);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(sessions);
+
+static ssize_t iscsi_stat_instance_show_attr_fail_sess(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
+       u32 sess_err_count;
+
+       spin_lock_bh(&sess_err->lock);
+       sess_err_count = (sess_err->digest_errors +
+                         sess_err->cxn_timeout_errors +
+                         sess_err->pdu_format_errors);
+       spin_unlock_bh(&sess_err->lock);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", sess_err_count);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(fail_sess);
+
+static ssize_t iscsi_stat_instance_show_attr_fail_type(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
+
+       return snprintf(page, PAGE_SIZE, "%u\n",
+                       sess_err->last_sess_failure_type);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(fail_type);
+
+static ssize_t iscsi_stat_instance_show_attr_fail_rem_name(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
+
+       return snprintf(page, PAGE_SIZE, "%s\n",
+                       sess_err->last_sess_fail_rem_name[0] ?
+                       sess_err->last_sess_fail_rem_name : NONE);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(fail_rem_name);
+
+static ssize_t iscsi_stat_instance_show_attr_disc_time(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DISCONTINUITY_TIME);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(disc_time);
+
+static ssize_t iscsi_stat_instance_show_attr_description(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%s\n", ISCSI_INST_DESCR);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(description);
+
+static ssize_t iscsi_stat_instance_show_attr_vendor(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "RisingTide Systems iSCSI-Target\n");
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(vendor);
+
+static ssize_t iscsi_stat_instance_show_attr_version(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%s\n", ISCSIT_VERSION);
+}
+ISCSI_STAT_INSTANCE_ATTR_RO(version);
+
+CONFIGFS_EATTR_OPS(iscsi_stat_instance, iscsi_wwn_stat_grps,
+               iscsi_instance_group);
+
+static struct configfs_attribute *iscsi_stat_instance_attrs[] = {
+       &iscsi_stat_instance_inst.attr,
+       &iscsi_stat_instance_min_ver.attr,
+       &iscsi_stat_instance_max_ver.attr,
+       &iscsi_stat_instance_portals.attr,
+       &iscsi_stat_instance_nodes.attr,
+       &iscsi_stat_instance_sessions.attr,
+       &iscsi_stat_instance_fail_sess.attr,
+       &iscsi_stat_instance_fail_type.attr,
+       &iscsi_stat_instance_fail_rem_name.attr,
+       &iscsi_stat_instance_disc_time.attr,
+       &iscsi_stat_instance_description.attr,
+       &iscsi_stat_instance_vendor.attr,
+       &iscsi_stat_instance_version.attr,
+       NULL,
+};
+
+static struct configfs_item_operations iscsi_stat_instance_item_ops = {
+       .show_attribute         = iscsi_stat_instance_attr_show,
+       .store_attribute        = iscsi_stat_instance_attr_store,
+};
+
+struct config_item_type iscsi_stat_instance_cit = {
+       .ct_item_ops            = &iscsi_stat_instance_item_ops,
+       .ct_attrs               = iscsi_stat_instance_attrs,
+       .ct_owner               = THIS_MODULE,
+};
+
+/*
+ * Instance Session Failure Stats Table
+ */
+CONFIGFS_EATTR_STRUCT(iscsi_stat_sess_err, iscsi_wwn_stat_grps);
+#define ISCSI_STAT_SESS_ERR_ATTR(_name, _mode)                 \
+static struct iscsi_stat_sess_err_attribute                    \
+                       iscsi_stat_sess_err_##_name =           \
+       __CONFIGFS_EATTR(_name, _mode,                          \
+       iscsi_stat_sess_err_show_attr_##_name,                  \
+       iscsi_stat_sess_err_store_attr_##_name);
+
+#define ISCSI_STAT_SESS_ERR_ATTR_RO(_name)                     \
+static struct iscsi_stat_sess_err_attribute                    \
+                       iscsi_stat_sess_err_##_name =           \
+       __CONFIGFS_EATTR_RO(_name,                              \
+       iscsi_stat_sess_err_show_attr_##_name);
+
+static ssize_t iscsi_stat_sess_err_show_attr_inst(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+}
+ISCSI_STAT_SESS_ERR_ATTR_RO(inst);
+
+static ssize_t iscsi_stat_sess_err_show_attr_digest_errors(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
+
+       return snprintf(page, PAGE_SIZE, "%u\n", sess_err->digest_errors);
+}
+ISCSI_STAT_SESS_ERR_ATTR_RO(digest_errors);
+
+static ssize_t iscsi_stat_sess_err_show_attr_cxn_errors(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
+
+       return snprintf(page, PAGE_SIZE, "%u\n", sess_err->cxn_timeout_errors);
+}
+ISCSI_STAT_SESS_ERR_ATTR_RO(cxn_errors);
+
+static ssize_t iscsi_stat_sess_err_show_attr_format_errors(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
+
+       return snprintf(page, PAGE_SIZE, "%u\n", sess_err->pdu_format_errors);
+}
+ISCSI_STAT_SESS_ERR_ATTR_RO(format_errors);
+
+CONFIGFS_EATTR_OPS(iscsi_stat_sess_err, iscsi_wwn_stat_grps,
+               iscsi_sess_err_group);
+
+static struct configfs_attribute *iscsi_stat_sess_err_attrs[] = {
+       &iscsi_stat_sess_err_inst.attr,
+       &iscsi_stat_sess_err_digest_errors.attr,
+       &iscsi_stat_sess_err_cxn_errors.attr,
+       &iscsi_stat_sess_err_format_errors.attr,
+       NULL,
+};
+
+static struct configfs_item_operations iscsi_stat_sess_err_item_ops = {
+       .show_attribute         = iscsi_stat_sess_err_attr_show,
+       .store_attribute        = iscsi_stat_sess_err_attr_store,
+};
+
+struct config_item_type iscsi_stat_sess_err_cit = {
+       .ct_item_ops            = &iscsi_stat_sess_err_item_ops,
+       .ct_attrs               = iscsi_stat_sess_err_attrs,
+       .ct_owner               = THIS_MODULE,
+};
+
+/*
+ * Target Attributes Table
+ */
+CONFIGFS_EATTR_STRUCT(iscsi_stat_tgt_attr, iscsi_wwn_stat_grps);
+#define ISCSI_STAT_TGT_ATTR(_name, _mode)                      \
+static struct iscsi_stat_tgt_attr_attribute                    \
+                       iscsi_stat_tgt_attr_##_name =           \
+       __CONFIGFS_EATTR(_name, _mode,                          \
+       iscsi_stat_tgt-attr_show_attr_##_name,                  \
+       iscsi_stat_tgt_attr_store_attr_##_name);
+
+#define ISCSI_STAT_TGT_ATTR_RO(_name)                          \
+static struct iscsi_stat_tgt_attr_attribute                    \
+                       iscsi_stat_tgt_attr_##_name =           \
+       __CONFIGFS_EATTR_RO(_name,                              \
+       iscsi_stat_tgt_attr_show_attr_##_name);
+
+static ssize_t iscsi_stat_tgt_attr_show_attr_inst(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+}
+ISCSI_STAT_TGT_ATTR_RO(inst);
+
+static ssize_t iscsi_stat_tgt_attr_show_attr_indx(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX);
+}
+ISCSI_STAT_TGT_ATTR_RO(indx);
+
+static ssize_t iscsi_stat_tgt_attr_show_attr_login_fails(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       u32 fail_count;
+
+       spin_lock(&lstat->lock);
+       fail_count = (lstat->redirects + lstat->authorize_fails +
+                       lstat->authenticate_fails + lstat->negotiate_fails +
+                       lstat->other_fails);
+       spin_unlock(&lstat->lock);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", fail_count);
+}
+ISCSI_STAT_TGT_ATTR_RO(login_fails);
+
+static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_time(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       u32 last_fail_time;
+
+       spin_lock(&lstat->lock);
+       last_fail_time = lstat->last_fail_time ?
+                       (u32)(((u32)lstat->last_fail_time -
+                               INITIAL_JIFFIES) * 100 / HZ) : 0;
+       spin_unlock(&lstat->lock);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", last_fail_time);
+}
+ISCSI_STAT_TGT_ATTR_RO(last_fail_time);
+
+static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_type(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       u32 last_fail_type;
+
+       spin_lock(&lstat->lock);
+       last_fail_type = lstat->last_fail_type;
+       spin_unlock(&lstat->lock);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", last_fail_type);
+}
+ISCSI_STAT_TGT_ATTR_RO(last_fail_type);
+
+static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_name(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       unsigned char buf[224];
+
+       spin_lock(&lstat->lock);
+       snprintf(buf, 224, "%s", lstat->last_intr_fail_name[0] ?
+                               lstat->last_intr_fail_name : NONE);
+       spin_unlock(&lstat->lock);
+
+       return snprintf(page, PAGE_SIZE, "%s\n", buf);
+}
+ISCSI_STAT_TGT_ATTR_RO(fail_intr_name);
+
+static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr_type(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                       struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       unsigned char buf[8];
+
+       spin_lock(&lstat->lock);
+       snprintf(buf, 8, "%s", (lstat->last_intr_fail_ip_addr != NULL) ?
+                               "ipv6" : "ipv4");
+       spin_unlock(&lstat->lock);
+
+       return snprintf(page, PAGE_SIZE, "%s\n", buf);
+}
+ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr_type);
+
+static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                       struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       unsigned char buf[32];
+
+       spin_lock(&lstat->lock);
+       if (lstat->last_intr_fail_ip_family == AF_INET6)
+               snprintf(buf, 32, "[%s]", lstat->last_intr_fail_ip_addr);
+       else
+               snprintf(buf, 32, "%s", lstat->last_intr_fail_ip_addr);
+       spin_unlock(&lstat->lock);
+
+       return snprintf(page, PAGE_SIZE, "%s\n", buf);
+}
+ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr);
+
+CONFIGFS_EATTR_OPS(iscsi_stat_tgt_attr, iscsi_wwn_stat_grps,
+               iscsi_tgt_attr_group);
+
+static struct configfs_attribute *iscsi_stat_tgt_attr_attrs[] = {
+       &iscsi_stat_tgt_attr_inst.attr,
+       &iscsi_stat_tgt_attr_indx.attr,
+       &iscsi_stat_tgt_attr_login_fails.attr,
+       &iscsi_stat_tgt_attr_last_fail_time.attr,
+       &iscsi_stat_tgt_attr_last_fail_type.attr,
+       &iscsi_stat_tgt_attr_fail_intr_name.attr,
+       &iscsi_stat_tgt_attr_fail_intr_addr_type.attr,
+       &iscsi_stat_tgt_attr_fail_intr_addr.attr,
+       NULL,
+};
+
+static struct configfs_item_operations iscsi_stat_tgt_attr_item_ops = {
+       .show_attribute         = iscsi_stat_tgt_attr_attr_show,
+       .store_attribute        = iscsi_stat_tgt_attr_attr_store,
+};
+
+struct config_item_type iscsi_stat_tgt_attr_cit = {
+       .ct_item_ops            = &iscsi_stat_tgt_attr_item_ops,
+       .ct_attrs               = iscsi_stat_tgt_attr_attrs,
+       .ct_owner               = THIS_MODULE,
+};
+
+/*
+ * Target Login Stats Table
+ */
+CONFIGFS_EATTR_STRUCT(iscsi_stat_login, iscsi_wwn_stat_grps);
+#define ISCSI_STAT_LOGIN(_name, _mode)                         \
+static struct iscsi_stat_login_attribute                       \
+                       iscsi_stat_login_##_name =              \
+       __CONFIGFS_EATTR(_name, _mode,                          \
+       iscsi_stat_login_show_attr_##_name,                     \
+       iscsi_stat_login_store_attr_##_name);
+
+#define ISCSI_STAT_LOGIN_RO(_name)                             \
+static struct iscsi_stat_login_attribute                       \
+                       iscsi_stat_login_##_name =              \
+       __CONFIGFS_EATTR_RO(_name,                              \
+       iscsi_stat_login_show_attr_##_name);
+
+static ssize_t iscsi_stat_login_show_attr_inst(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+}
+ISCSI_STAT_LOGIN_RO(inst);
+
+static ssize_t iscsi_stat_login_show_attr_indx(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX);
+}
+ISCSI_STAT_LOGIN_RO(indx);
+
+static ssize_t iscsi_stat_login_show_attr_accepts(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       ssize_t ret;
+
+       spin_lock(&lstat->lock);
+       ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->accepts);
+       spin_unlock(&lstat->lock);
+
+       return ret;
+}
+ISCSI_STAT_LOGIN_RO(accepts);
+
+static ssize_t iscsi_stat_login_show_attr_other_fails(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       ssize_t ret;
+
+       spin_lock(&lstat->lock);
+       ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->other_fails);
+       spin_unlock(&lstat->lock);
+
+       return ret;
+}
+ISCSI_STAT_LOGIN_RO(other_fails);
+
+static ssize_t iscsi_stat_login_show_attr_redirects(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       ssize_t ret;
+
+       spin_lock(&lstat->lock);
+       ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->redirects);
+       spin_unlock(&lstat->lock);
+
+       return ret;
+}
+ISCSI_STAT_LOGIN_RO(redirects);
+
+static ssize_t iscsi_stat_login_show_attr_authorize_fails(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       ssize_t ret;
+
+       spin_lock(&lstat->lock);
+       ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->authorize_fails);
+       spin_unlock(&lstat->lock);
+
+       return ret;
+}
+ISCSI_STAT_LOGIN_RO(authorize_fails);
+
+static ssize_t iscsi_stat_login_show_attr_authenticate_fails(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       ssize_t ret;
+
+       spin_lock(&lstat->lock);
+       ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->authenticate_fails);
+       spin_unlock(&lstat->lock);
+
+       return ret;
+}
+ISCSI_STAT_LOGIN_RO(authenticate_fails);
+
+static ssize_t iscsi_stat_login_show_attr_negotiate_fails(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                               struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_login_stats *lstat = &tiqn->login_stats;
+       ssize_t ret;
+
+       spin_lock(&lstat->lock);
+       ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->negotiate_fails);
+       spin_unlock(&lstat->lock);
+
+       return ret;
+}
+ISCSI_STAT_LOGIN_RO(negotiate_fails);
+
+CONFIGFS_EATTR_OPS(iscsi_stat_login, iscsi_wwn_stat_grps,
+               iscsi_login_stats_group);
+
+static struct configfs_attribute *iscsi_stat_login_stats_attrs[] = {
+       &iscsi_stat_login_inst.attr,
+       &iscsi_stat_login_indx.attr,
+       &iscsi_stat_login_accepts.attr,
+       &iscsi_stat_login_other_fails.attr,
+       &iscsi_stat_login_redirects.attr,
+       &iscsi_stat_login_authorize_fails.attr,
+       &iscsi_stat_login_authenticate_fails.attr,
+       &iscsi_stat_login_negotiate_fails.attr,
+       NULL,
+};
+
+static struct configfs_item_operations iscsi_stat_login_stats_item_ops = {
+       .show_attribute         = iscsi_stat_login_attr_show,
+       .store_attribute        = iscsi_stat_login_attr_store,
+};
+
+struct config_item_type iscsi_stat_login_cit = {
+       .ct_item_ops            = &iscsi_stat_login_stats_item_ops,
+       .ct_attrs               = iscsi_stat_login_stats_attrs,
+       .ct_owner               = THIS_MODULE,
+};
+
+/*
+ * Target Logout Stats Table
+ */
+
+CONFIGFS_EATTR_STRUCT(iscsi_stat_logout, iscsi_wwn_stat_grps);
+#define ISCSI_STAT_LOGOUT(_name, _mode)                                \
+static struct iscsi_stat_logout_attribute                      \
+                       iscsi_stat_logout_##_name =             \
+       __CONFIGFS_EATTR(_name, _mode,                          \
+       iscsi_stat_logout_show_attr_##_name,                    \
+       iscsi_stat_logout_store_attr_##_name);
+
+#define ISCSI_STAT_LOGOUT_RO(_name)                            \
+static struct iscsi_stat_logout_attribute                      \
+                       iscsi_stat_logout_##_name =             \
+       __CONFIGFS_EATTR_RO(_name,                              \
+       iscsi_stat_logout_show_attr_##_name);
+
+static ssize_t iscsi_stat_logout_show_attr_inst(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                       struct iscsi_tiqn, tiqn_stat_grps);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+}
+ISCSI_STAT_LOGOUT_RO(inst);
+
+static ssize_t iscsi_stat_logout_show_attr_indx(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX);
+}
+ISCSI_STAT_LOGOUT_RO(indx);
+
+static ssize_t iscsi_stat_logout_show_attr_normal_logouts(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                       struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_logout_stats *lstats = &tiqn->logout_stats;
+
+       return snprintf(page, PAGE_SIZE, "%u\n", lstats->normal_logouts);
+}
+ISCSI_STAT_LOGOUT_RO(normal_logouts);
+
+static ssize_t iscsi_stat_logout_show_attr_abnormal_logouts(
+       struct iscsi_wwn_stat_grps *igrps, char *page)
+{
+       struct iscsi_tiqn *tiqn = container_of(igrps,
+                       struct iscsi_tiqn, tiqn_stat_grps);
+       struct iscsi_logout_stats *lstats = &tiqn->logout_stats;
+
+       return snprintf(page, PAGE_SIZE, "%u\n", lstats->abnormal_logouts);
+}
+ISCSI_STAT_LOGOUT_RO(abnormal_logouts);
+
+CONFIGFS_EATTR_OPS(iscsi_stat_logout, iscsi_wwn_stat_grps,
+               iscsi_logout_stats_group);
+
+static struct configfs_attribute *iscsi_stat_logout_stats_attrs[] = {
+       &iscsi_stat_logout_inst.attr,
+       &iscsi_stat_logout_indx.attr,
+       &iscsi_stat_logout_normal_logouts.attr,
+       &iscsi_stat_logout_abnormal_logouts.attr,
+       NULL,
+};
+
+static struct configfs_item_operations iscsi_stat_logout_stats_item_ops = {
+       .show_attribute         = iscsi_stat_logout_attr_show,
+       .store_attribute        = iscsi_stat_logout_attr_store,
+};
+
+struct config_item_type iscsi_stat_logout_cit = {
+       .ct_item_ops            = &iscsi_stat_logout_stats_item_ops,
+       .ct_attrs               = iscsi_stat_logout_stats_attrs,
+       .ct_owner               = THIS_MODULE,
+};
+
+/*
+ * Session Stats Table
+ */
+
+CONFIGFS_EATTR_STRUCT(iscsi_stat_sess, iscsi_node_stat_grps);
+#define ISCSI_STAT_SESS(_name, _mode)                          \
+static struct iscsi_stat_sess_attribute                                \
+                       iscsi_stat_sess_##_name =               \
+       __CONFIGFS_EATTR(_name, _mode,                          \
+       iscsi_stat_sess_show_attr_##_name,                      \
+       iscsi_stat_sess_store_attr_##_name);
+
+#define ISCSI_STAT_SESS_RO(_name)                              \
+static struct iscsi_stat_sess_attribute                                \
+                       iscsi_stat_sess_##_name =               \
+       __CONFIGFS_EATTR_RO(_name,                              \
+       iscsi_stat_sess_show_attr_##_name);
+
+static ssize_t iscsi_stat_sess_show_attr_inst(
+       struct iscsi_node_stat_grps *igrps, char *page)
+{
+       struct iscsi_node_acl *acl = container_of(igrps,
+                       struct iscsi_node_acl, node_stat_grps);
+       struct se_wwn *wwn = acl->se_node_acl.se_tpg->se_tpg_wwn;
+       struct iscsi_tiqn *tiqn = container_of(wwn,
+                       struct iscsi_tiqn, tiqn_wwn);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+}
+ISCSI_STAT_SESS_RO(inst);
+
+static ssize_t iscsi_stat_sess_show_attr_node(
+       struct iscsi_node_stat_grps *igrps, char *page)
+{
+       struct iscsi_node_acl *acl = container_of(igrps,
+                       struct iscsi_node_acl, node_stat_grps);
+       struct se_node_acl *se_nacl = &acl->se_node_acl;
+       struct iscsi_session *sess;
+       struct se_session *se_sess;
+       ssize_t ret = 0;
+
+       spin_lock_bh(&se_nacl->nacl_sess_lock);
+       se_sess = se_nacl->nacl_sess;
+       if (se_sess) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               if (sess)
+                       ret = snprintf(page, PAGE_SIZE, "%u\n",
+                               sess->sess_ops->SessionType ? 0 : ISCSI_NODE_INDEX);
+       }
+       spin_unlock_bh(&se_nacl->nacl_sess_lock);
+
+       return ret;
+}
+ISCSI_STAT_SESS_RO(node);
+
+static ssize_t iscsi_stat_sess_show_attr_indx(
+       struct iscsi_node_stat_grps *igrps, char *page)
+{
+       struct iscsi_node_acl *acl = container_of(igrps,
+                       struct iscsi_node_acl, node_stat_grps);
+       struct se_node_acl *se_nacl = &acl->se_node_acl;
+       struct iscsi_session *sess;
+       struct se_session *se_sess;
+       ssize_t ret = 0;
+
+       spin_lock_bh(&se_nacl->nacl_sess_lock);
+       se_sess = se_nacl->nacl_sess;
+       if (se_sess) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               if (sess)
+                       ret = snprintf(page, PAGE_SIZE, "%u\n",
+                                       sess->session_index);
+       }
+       spin_unlock_bh(&se_nacl->nacl_sess_lock);
+
+       return ret;
+}
+ISCSI_STAT_SESS_RO(indx);
+
+static ssize_t iscsi_stat_sess_show_attr_cmd_pdus(
+       struct iscsi_node_stat_grps *igrps, char *page)
+{
+       struct iscsi_node_acl *acl = container_of(igrps,
+                       struct iscsi_node_acl, node_stat_grps);
+       struct se_node_acl *se_nacl = &acl->se_node_acl;
+       struct iscsi_session *sess;
+       struct se_session *se_sess;
+       ssize_t ret = 0;
+
+       spin_lock_bh(&se_nacl->nacl_sess_lock);
+       se_sess = se_nacl->nacl_sess;
+       if (se_sess) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               if (sess)
+                       ret = snprintf(page, PAGE_SIZE, "%u\n", sess->cmd_pdus);
+       }
+       spin_unlock_bh(&se_nacl->nacl_sess_lock);
+
+       return ret;
+}
+ISCSI_STAT_SESS_RO(cmd_pdus);
+
+static ssize_t iscsi_stat_sess_show_attr_rsp_pdus(
+       struct iscsi_node_stat_grps *igrps, char *page)
+{
+       struct iscsi_node_acl *acl = container_of(igrps,
+                       struct iscsi_node_acl, node_stat_grps);
+       struct se_node_acl *se_nacl = &acl->se_node_acl;
+       struct iscsi_session *sess;
+       struct se_session *se_sess;
+       ssize_t ret = 0;
+
+       spin_lock_bh(&se_nacl->nacl_sess_lock);
+       se_sess = se_nacl->nacl_sess;
+       if (se_sess) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               if (sess)
+                       ret = snprintf(page, PAGE_SIZE, "%u\n", sess->rsp_pdus);
+       }
+       spin_unlock_bh(&se_nacl->nacl_sess_lock);
+
+       return ret;
+}
+ISCSI_STAT_SESS_RO(rsp_pdus);
+
+static ssize_t iscsi_stat_sess_show_attr_txdata_octs(
+       struct iscsi_node_stat_grps *igrps, char *page)
+{
+       struct iscsi_node_acl *acl = container_of(igrps,
+                       struct iscsi_node_acl, node_stat_grps);
+       struct se_node_acl *se_nacl = &acl->se_node_acl;
+       struct iscsi_session *sess;
+       struct se_session *se_sess;
+       ssize_t ret = 0;
+
+       spin_lock_bh(&se_nacl->nacl_sess_lock);
+       se_sess = se_nacl->nacl_sess;
+       if (se_sess) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               if (sess)
+                       ret = snprintf(page, PAGE_SIZE, "%llu\n",
+                               (unsigned long long)sess->tx_data_octets);
+       }
+       spin_unlock_bh(&se_nacl->nacl_sess_lock);
+
+       return ret;
+}
+ISCSI_STAT_SESS_RO(txdata_octs);
+
+static ssize_t iscsi_stat_sess_show_attr_rxdata_octs(
+       struct iscsi_node_stat_grps *igrps, char *page)
+{
+       struct iscsi_node_acl *acl = container_of(igrps,
+                       struct iscsi_node_acl, node_stat_grps);
+       struct se_node_acl *se_nacl = &acl->se_node_acl;
+       struct iscsi_session *sess;
+       struct se_session *se_sess;
+       ssize_t ret = 0;
+
+       spin_lock_bh(&se_nacl->nacl_sess_lock);
+       se_sess = se_nacl->nacl_sess;
+       if (se_sess) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               if (sess)
+                       ret = snprintf(page, PAGE_SIZE, "%llu\n",
+                               (unsigned long long)sess->rx_data_octets);
+       }
+       spin_unlock_bh(&se_nacl->nacl_sess_lock);
+
+       return ret;
+}
+ISCSI_STAT_SESS_RO(rxdata_octs);
+
+static ssize_t iscsi_stat_sess_show_attr_conn_digest_errors(
+       struct iscsi_node_stat_grps *igrps, char *page)
+{
+       struct iscsi_node_acl *acl = container_of(igrps,
+                       struct iscsi_node_acl, node_stat_grps);
+       struct se_node_acl *se_nacl = &acl->se_node_acl;
+       struct iscsi_session *sess;
+       struct se_session *se_sess;
+       ssize_t ret = 0;
+
+       spin_lock_bh(&se_nacl->nacl_sess_lock);
+       se_sess = se_nacl->nacl_sess;
+       if (se_sess) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               if (sess)
+                       ret = snprintf(page, PAGE_SIZE, "%u\n",
+                                       sess->conn_digest_errors);
+       }
+       spin_unlock_bh(&se_nacl->nacl_sess_lock);
+
+       return ret;
+}
+ISCSI_STAT_SESS_RO(conn_digest_errors);
+
+static ssize_t iscsi_stat_sess_show_attr_conn_timeout_errors(
+       struct iscsi_node_stat_grps *igrps, char *page)
+{
+       struct iscsi_node_acl *acl = container_of(igrps,
+                       struct iscsi_node_acl, node_stat_grps);
+       struct se_node_acl *se_nacl = &acl->se_node_acl;
+       struct iscsi_session *sess;
+       struct se_session *se_sess;
+       ssize_t ret = 0;
+
+       spin_lock_bh(&se_nacl->nacl_sess_lock);
+       se_sess = se_nacl->nacl_sess;
+       if (se_sess) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+               if (sess)
+                       ret = snprintf(page, PAGE_SIZE, "%u\n",
+                                       sess->conn_timeout_errors);
+       }
+       spin_unlock_bh(&se_nacl->nacl_sess_lock);
+
+       return ret;
+}
+ISCSI_STAT_SESS_RO(conn_timeout_errors);
+
+CONFIGFS_EATTR_OPS(iscsi_stat_sess, iscsi_node_stat_grps,
+               iscsi_sess_stats_group);
+
+static struct configfs_attribute *iscsi_stat_sess_stats_attrs[] = {
+       &iscsi_stat_sess_inst.attr,
+       &iscsi_stat_sess_node.attr,
+       &iscsi_stat_sess_indx.attr,
+       &iscsi_stat_sess_cmd_pdus.attr,
+       &iscsi_stat_sess_rsp_pdus.attr,
+       &iscsi_stat_sess_txdata_octs.attr,
+       &iscsi_stat_sess_rxdata_octs.attr,
+       &iscsi_stat_sess_conn_digest_errors.attr,
+       &iscsi_stat_sess_conn_timeout_errors.attr,
+       NULL,
+};
+
+static struct configfs_item_operations iscsi_stat_sess_stats_item_ops = {
+       .show_attribute         = iscsi_stat_sess_attr_show,
+       .store_attribute        = iscsi_stat_sess_attr_store,
+};
+
+struct config_item_type iscsi_stat_sess_cit = {
+       .ct_item_ops            = &iscsi_stat_sess_stats_item_ops,
+       .ct_attrs               = iscsi_stat_sess_stats_attrs,
+       .ct_owner               = THIS_MODULE,
+};
diff --git a/drivers/target/iscsi/iscsi_target_stat.h b/drivers/target/iscsi/iscsi_target_stat.h
new file mode 100644 (file)
index 0000000..3ff76b4
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef ISCSI_TARGET_STAT_H
+#define ISCSI_TARGET_STAT_H
+
+/*
+ * For struct iscsi_tiqn->tiqn_wwn default groups
+ */
+extern struct config_item_type iscsi_stat_instance_cit;
+extern struct config_item_type iscsi_stat_sess_err_cit;
+extern struct config_item_type iscsi_stat_tgt_attr_cit;
+extern struct config_item_type iscsi_stat_login_cit;
+extern struct config_item_type iscsi_stat_logout_cit;
+
+/*
+ * For struct iscsi_session->se_sess default groups
+ */
+extern struct config_item_type iscsi_stat_sess_cit;
+
+/* iSCSI session error types */
+#define ISCSI_SESS_ERR_UNKNOWN         0
+#define ISCSI_SESS_ERR_DIGEST          1
+#define ISCSI_SESS_ERR_CXN_TIMEOUT     2
+#define ISCSI_SESS_ERR_PDU_FORMAT      3
+
+/* iSCSI session error stats */
+struct iscsi_sess_err_stats {
+       spinlock_t      lock;
+       u32             digest_errors;
+       u32             cxn_timeout_errors;
+       u32             pdu_format_errors;
+       u32             last_sess_failure_type;
+       char            last_sess_fail_rem_name[224];
+} ____cacheline_aligned;
+
+/* iSCSI login failure types (sub oids) */
+#define ISCSI_LOGIN_FAIL_OTHER         2
+#define ISCSI_LOGIN_FAIL_REDIRECT      3
+#define ISCSI_LOGIN_FAIL_AUTHORIZE     4
+#define ISCSI_LOGIN_FAIL_AUTHENTICATE  5
+#define ISCSI_LOGIN_FAIL_NEGOTIATE     6
+
+/* iSCSI login stats */
+struct iscsi_login_stats {
+       spinlock_t      lock;
+       u32             accepts;
+       u32             other_fails;
+       u32             redirects;
+       u32             authorize_fails;
+       u32             authenticate_fails;
+       u32             negotiate_fails;        /* used for notifications */
+       u64             last_fail_time;         /* time stamp (jiffies) */
+       u32             last_fail_type;
+       int             last_intr_fail_ip_family;
+       unsigned char   last_intr_fail_ip_addr[IPV6_ADDRESS_SPACE];
+       char            last_intr_fail_name[224];
+} ____cacheline_aligned;
+
+/* iSCSI logout stats */
+struct iscsi_logout_stats {
+       spinlock_t      lock;
+       u32             normal_logouts;
+       u32             abnormal_logouts;
+} ____cacheline_aligned;
+
+#endif   /*** ISCSI_TARGET_STAT_H ***/
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
new file mode 100644 (file)
index 0000000..db1fe1e
--- /dev/null
@@ -0,0 +1,849 @@
+/*******************************************************************************
+ * This file contains the iSCSI Target specific Task Management functions.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <asm/unaligned.h>
+#include <scsi/iscsi_proto.h>
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_seq_pdu_list.h"
+#include "iscsi_target_datain_values.h"
+#include "iscsi_target_device.h"
+#include "iscsi_target_erl0.h"
+#include "iscsi_target_erl1.h"
+#include "iscsi_target_erl2.h"
+#include "iscsi_target_tmr.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target.h"
+
+u8 iscsit_tmr_abort_task(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       struct iscsi_cmd *ref_cmd;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_tmr_req *tmr_req = cmd->tmr_req;
+       struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
+       struct iscsi_tm *hdr = (struct iscsi_tm *) buf;
+
+       ref_cmd = iscsit_find_cmd_from_itt(conn, hdr->rtt);
+       if (!ref_cmd) {
+               pr_err("Unable to locate RefTaskTag: 0x%08x on CID:"
+                       " %hu.\n", hdr->rtt, conn->cid);
+               return ((hdr->refcmdsn >= conn->sess->exp_cmd_sn) &&
+                       (hdr->refcmdsn <= conn->sess->max_cmd_sn)) ?
+                       ISCSI_TMF_RSP_COMPLETE : ISCSI_TMF_RSP_NO_TASK;
+       }
+       if (ref_cmd->cmd_sn != hdr->refcmdsn) {
+               pr_err("RefCmdSN 0x%08x does not equal"
+                       " task's CmdSN 0x%08x. Rejecting ABORT_TASK.\n",
+                       hdr->refcmdsn, ref_cmd->cmd_sn);
+               return ISCSI_TMF_RSP_REJECTED;
+       }
+
+       se_tmr->ref_task_tag            = hdr->rtt;
+       se_tmr->ref_cmd                 = &ref_cmd->se_cmd;
+       tmr_req->ref_cmd_sn             = hdr->refcmdsn;
+       tmr_req->exp_data_sn            = hdr->exp_datasn;
+
+       return ISCSI_TMF_RSP_COMPLETE;
+}
+
+/*
+ *     Called from iscsit_handle_task_mgt_cmd().
+ */
+int iscsit_tmr_task_warm_reset(
+       struct iscsi_conn *conn,
+       struct iscsi_tmr_req *tmr_req,
+       unsigned char *buf)
+{
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
+#if 0
+       struct iscsi_init_task_mgt_cmnd *hdr =
+               (struct iscsi_init_task_mgt_cmnd *) buf;
+#endif
+       if (!na->tmr_warm_reset) {
+               pr_err("TMR Opcode TARGET_WARM_RESET authorization"
+                       " failed for Initiator Node: %s\n",
+                       sess->se_sess->se_node_acl->initiatorname);
+                return -1;
+       }
+       /*
+        * Do the real work in transport_generic_do_tmr().
+        */
+       return 0;
+}
+
+int iscsit_tmr_task_cold_reset(
+       struct iscsi_conn *conn,
+       struct iscsi_tmr_req *tmr_req,
+       unsigned char *buf)
+{
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
+
+       if (!na->tmr_cold_reset) {
+               pr_err("TMR Opcode TARGET_COLD_RESET authorization"
+                       " failed for Initiator Node: %s\n",
+                       sess->se_sess->se_node_acl->initiatorname);
+               return -1;
+       }
+       /*
+        * Do the real work in transport_generic_do_tmr().
+        */
+       return 0;
+}
+
+u8 iscsit_tmr_task_reassign(
+       struct iscsi_cmd *cmd,
+       unsigned char *buf)
+{
+       struct iscsi_cmd *ref_cmd = NULL;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_conn_recovery *cr = NULL;
+       struct iscsi_tmr_req *tmr_req = cmd->tmr_req;
+       struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
+       struct iscsi_tm *hdr = (struct iscsi_tm *) buf;
+       int ret;
+
+       pr_debug("Got TASK_REASSIGN TMR ITT: 0x%08x,"
+               " RefTaskTag: 0x%08x, ExpDataSN: 0x%08x, CID: %hu\n",
+               hdr->itt, hdr->rtt, hdr->exp_datasn, conn->cid);
+
+       if (conn->sess->sess_ops->ErrorRecoveryLevel != 2) {
+               pr_err("TMR TASK_REASSIGN not supported in ERL<2,"
+                               " ignoring request.\n");
+               return ISCSI_TMF_RSP_NOT_SUPPORTED;
+       }
+
+       ret = iscsit_find_cmd_for_recovery(conn->sess, &ref_cmd, &cr, hdr->rtt);
+       if (ret == -2) {
+               pr_err("Command ITT: 0x%08x is still alligent to CID:"
+                       " %hu\n", ref_cmd->init_task_tag, cr->cid);
+               return ISCSI_TMF_RSP_TASK_ALLEGIANT;
+       } else if (ret == -1) {
+               pr_err("Unable to locate RefTaskTag: 0x%08x in"
+                       " connection recovery command list.\n", hdr->rtt);
+               return ISCSI_TMF_RSP_NO_TASK;
+       }
+       /*
+        * Temporary check to prevent connection recovery for
+        * connections with a differing MaxRecvDataSegmentLength.
+        */
+       if (cr->maxrecvdatasegmentlength !=
+           conn->conn_ops->MaxRecvDataSegmentLength) {
+               pr_err("Unable to perform connection recovery for"
+                       " differing MaxRecvDataSegmentLength, rejecting"
+                       " TMR TASK_REASSIGN.\n");
+               return ISCSI_TMF_RSP_REJECTED;
+       }
+
+       se_tmr->ref_task_tag            = hdr->rtt;
+       se_tmr->ref_cmd                 = &ref_cmd->se_cmd;
+       se_tmr->ref_task_lun            = get_unaligned_le64(&hdr->lun);
+       tmr_req->ref_cmd_sn             = hdr->refcmdsn;
+       tmr_req->exp_data_sn            = hdr->exp_datasn;
+       tmr_req->conn_recovery          = cr;
+       tmr_req->task_reassign          = 1;
+       /*
+        * Command can now be reassigned to a new connection.
+        * The task management response must be sent before the
+        * reassignment actually happens.  See iscsi_tmr_post_handler().
+        */
+       return ISCSI_TMF_RSP_COMPLETE;
+}
+
+static void iscsit_task_reassign_remove_cmd(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn_recovery *cr,
+       struct iscsi_session *sess)
+{
+       int ret;
+
+       spin_lock(&cr->conn_recovery_cmd_lock);
+       ret = iscsit_remove_cmd_from_connection_recovery(cmd, sess);
+       spin_unlock(&cr->conn_recovery_cmd_lock);
+       if (!ret) {
+               pr_debug("iSCSI connection recovery successful for CID:"
+                       " %hu on SID: %u\n", cr->cid, sess->sid);
+               iscsit_remove_active_connection_recovery_entry(cr, sess);
+       }
+}
+
+static int iscsit_task_reassign_complete_nop_out(
+       struct iscsi_tmr_req *tmr_req,
+       struct iscsi_conn *conn)
+{
+       struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
+       struct se_cmd *se_cmd = se_tmr->ref_cmd;
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+       struct iscsi_conn_recovery *cr;
+
+       if (!cmd->cr) {
+               pr_err("struct iscsi_conn_recovery pointer for ITT: 0x%08x"
+                       " is NULL!\n", cmd->init_task_tag);
+               return -1;
+       }
+       cr = cmd->cr;
+
+       /*
+        * Reset the StatSN so a new one for this commands new connection
+        * will be assigned.
+        * Reset the ExpStatSN as well so we may receive Status SNACKs.
+        */
+       cmd->stat_sn = cmd->exp_stat_sn = 0;
+
+       iscsit_task_reassign_remove_cmd(cmd, cr, conn->sess);
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+       spin_unlock_bh(&conn->cmd_lock);
+
+       cmd->i_state = ISTATE_SEND_NOPIN;
+       iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+       return 0;
+}
+
+static int iscsit_task_reassign_complete_write(
+       struct iscsi_cmd *cmd,
+       struct iscsi_tmr_req *tmr_req)
+{
+       int no_build_r2ts = 0;
+       u32 length = 0, offset = 0;
+       struct iscsi_conn *conn = cmd->conn;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       /*
+        * The Initiator must not send a R2T SNACK with a Begrun less than
+        * the TMR TASK_REASSIGN's ExpDataSN.
+        */
+       if (!tmr_req->exp_data_sn) {
+               cmd->cmd_flags &= ~ICF_GOT_DATACK_SNACK;
+               cmd->acked_data_sn = 0;
+       } else {
+               cmd->cmd_flags |= ICF_GOT_DATACK_SNACK;
+               cmd->acked_data_sn = (tmr_req->exp_data_sn - 1);
+       }
+
+       /*
+        * The TMR TASK_REASSIGN's ExpDataSN contains the next R2TSN the
+        * Initiator is expecting.  The Target controls all WRITE operations
+        * so if we have received all DataOUT we can safety ignore Initiator.
+        */
+       if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
+               if (!atomic_read(&cmd->transport_sent)) {
+                       pr_debug("WRITE ITT: 0x%08x: t_state: %d"
+                               " never sent to transport\n",
+                               cmd->init_task_tag, cmd->se_cmd.t_state);
+                       return transport_generic_handle_data(se_cmd);
+               }
+
+               cmd->i_state = ISTATE_SEND_STATUS;
+               iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+               return 0;
+       }
+
+       /*
+        * Special case to deal with DataSequenceInOrder=No and Non-Immeidate
+        * Unsolicited DataOut.
+        */
+       if (cmd->unsolicited_data) {
+               cmd->unsolicited_data = 0;
+
+               offset = cmd->next_burst_len = cmd->write_data_done;
+
+               if ((conn->sess->sess_ops->FirstBurstLength - offset) >=
+                    cmd->data_length) {
+                       no_build_r2ts = 1;
+                       length = (cmd->data_length - offset);
+               } else
+                       length = (conn->sess->sess_ops->FirstBurstLength - offset);
+
+               spin_lock_bh(&cmd->r2t_lock);
+               if (iscsit_add_r2t_to_list(cmd, offset, length, 0, 0) < 0) {
+                       spin_unlock_bh(&cmd->r2t_lock);
+                       return -1;
+               }
+               cmd->outstanding_r2ts++;
+               spin_unlock_bh(&cmd->r2t_lock);
+
+               if (no_build_r2ts)
+                       return 0;
+       }
+       /*
+        * iscsit_build_r2ts_for_cmd() can handle the rest from here.
+        */
+       return iscsit_build_r2ts_for_cmd(cmd, conn, 2);
+}
+
+static int iscsit_task_reassign_complete_read(
+       struct iscsi_cmd *cmd,
+       struct iscsi_tmr_req *tmr_req)
+{
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_datain_req *dr;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       /*
+        * The Initiator must not send a Data SNACK with a BegRun less than
+        * the TMR TASK_REASSIGN's ExpDataSN.
+        */
+       if (!tmr_req->exp_data_sn) {
+               cmd->cmd_flags &= ~ICF_GOT_DATACK_SNACK;
+               cmd->acked_data_sn = 0;
+       } else {
+               cmd->cmd_flags |= ICF_GOT_DATACK_SNACK;
+               cmd->acked_data_sn = (tmr_req->exp_data_sn - 1);
+       }
+
+       if (!atomic_read(&cmd->transport_sent)) {
+               pr_debug("READ ITT: 0x%08x: t_state: %d never sent to"
+                       " transport\n", cmd->init_task_tag,
+                       cmd->se_cmd.t_state);
+               transport_generic_handle_cdb(se_cmd);
+               return 0;
+       }
+
+       if (!atomic_read(&se_cmd->t_transport_complete)) {
+               pr_err("READ ITT: 0x%08x: t_state: %d, never returned"
+                       " from transport\n", cmd->init_task_tag,
+                       cmd->se_cmd.t_state);
+               return -1;
+       }
+
+       dr = iscsit_allocate_datain_req();
+       if (!dr)
+               return -1;
+       /*
+        * The TMR TASK_REASSIGN's ExpDataSN contains the next DataSN the
+        * Initiator is expecting.
+        */
+       dr->data_sn = dr->begrun = tmr_req->exp_data_sn;
+       dr->runlength = 0;
+       dr->generate_recovery_values = 1;
+       dr->recovery = DATAIN_CONNECTION_RECOVERY;
+
+       iscsit_attach_datain_req(cmd, dr);
+
+       cmd->i_state = ISTATE_SEND_DATAIN;
+       iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+       return 0;
+}
+
+static int iscsit_task_reassign_complete_none(
+       struct iscsi_cmd *cmd,
+       struct iscsi_tmr_req *tmr_req)
+{
+       struct iscsi_conn *conn = cmd->conn;
+
+       cmd->i_state = ISTATE_SEND_STATUS;
+       iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+       return 0;
+}
+
+static int iscsit_task_reassign_complete_scsi_cmnd(
+       struct iscsi_tmr_req *tmr_req,
+       struct iscsi_conn *conn)
+{
+       struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
+       struct se_cmd *se_cmd = se_tmr->ref_cmd;
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+       struct iscsi_conn_recovery *cr;
+
+       if (!cmd->cr) {
+               pr_err("struct iscsi_conn_recovery pointer for ITT: 0x%08x"
+                       " is NULL!\n", cmd->init_task_tag);
+               return -1;
+       }
+       cr = cmd->cr;
+
+       /*
+        * Reset the StatSN so a new one for this commands new connection
+        * will be assigned.
+        * Reset the ExpStatSN as well so we may receive Status SNACKs.
+        */
+       cmd->stat_sn = cmd->exp_stat_sn = 0;
+
+       iscsit_task_reassign_remove_cmd(cmd, cr, conn->sess);
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+       spin_unlock_bh(&conn->cmd_lock);
+
+       if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+               cmd->i_state = ISTATE_SEND_STATUS;
+               iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
+               return 0;
+       }
+
+       switch (cmd->data_direction) {
+       case DMA_TO_DEVICE:
+               return iscsit_task_reassign_complete_write(cmd, tmr_req);
+       case DMA_FROM_DEVICE:
+               return iscsit_task_reassign_complete_read(cmd, tmr_req);
+       case DMA_NONE:
+               return iscsit_task_reassign_complete_none(cmd, tmr_req);
+       default:
+               pr_err("Unknown cmd->data_direction: 0x%02x\n",
+                               cmd->data_direction);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int iscsit_task_reassign_complete(
+       struct iscsi_tmr_req *tmr_req,
+       struct iscsi_conn *conn)
+{
+       struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
+       struct se_cmd *se_cmd;
+       struct iscsi_cmd *cmd;
+       int ret = 0;
+
+       if (!se_tmr->ref_cmd) {
+               pr_err("TMR Request is missing a RefCmd struct iscsi_cmd.\n");
+               return -1;
+       }
+       se_cmd = se_tmr->ref_cmd;
+       cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+       cmd->conn = conn;
+
+       switch (cmd->iscsi_opcode) {
+       case ISCSI_OP_NOOP_OUT:
+               ret = iscsit_task_reassign_complete_nop_out(tmr_req, conn);
+               break;
+       case ISCSI_OP_SCSI_CMD:
+               ret = iscsit_task_reassign_complete_scsi_cmnd(tmr_req, conn);
+               break;
+       default:
+                pr_err("Illegal iSCSI Opcode 0x%02x during"
+                       " command realligence\n", cmd->iscsi_opcode);
+               return -1;
+       }
+
+       if (ret != 0)
+               return ret;
+
+       pr_debug("Completed connection realligence for Opcode: 0x%02x,"
+               " ITT: 0x%08x to CID: %hu.\n", cmd->iscsi_opcode,
+                       cmd->init_task_tag, conn->cid);
+
+       return 0;
+}
+
+/*
+ *     Handles special after-the-fact actions related to TMRs.
+ *     Right now the only one that its really needed for is
+ *     connection recovery releated TASK_REASSIGN.
+ */
+extern int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+       struct iscsi_tmr_req *tmr_req = cmd->tmr_req;
+       struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
+
+       if (tmr_req->task_reassign &&
+          (se_tmr->response == ISCSI_TMF_RSP_COMPLETE))
+               return iscsit_task_reassign_complete(tmr_req, conn);
+
+       return 0;
+}
+
+/*
+ *     Nothing to do here, but leave it for good measure. :-)
+ */
+int iscsit_task_reassign_prepare_read(
+       struct iscsi_tmr_req *tmr_req,
+       struct iscsi_conn *conn)
+{
+       return 0;
+}
+
+static void iscsit_task_reassign_prepare_unsolicited_dataout(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       int i, j;
+       struct iscsi_pdu *pdu = NULL;
+       struct iscsi_seq *seq = NULL;
+
+       if (conn->sess->sess_ops->DataSequenceInOrder) {
+               cmd->data_sn = 0;
+
+               if (cmd->immediate_data)
+                       cmd->r2t_offset += (cmd->first_burst_len -
+                               cmd->seq_start_offset);
+
+               if (conn->sess->sess_ops->DataPDUInOrder) {
+                       cmd->write_data_done -= (cmd->immediate_data) ?
+                                               (cmd->first_burst_len -
+                                                cmd->seq_start_offset) :
+                                                cmd->first_burst_len;
+                       cmd->first_burst_len = 0;
+                       return;
+               }
+
+               for (i = 0; i < cmd->pdu_count; i++) {
+                       pdu = &cmd->pdu_list[i];
+
+                       if (pdu->status != ISCSI_PDU_RECEIVED_OK)
+                               continue;
+
+                       if ((pdu->offset >= cmd->seq_start_offset) &&
+                          ((pdu->offset + pdu->length) <=
+                            cmd->seq_end_offset)) {
+                               cmd->first_burst_len -= pdu->length;
+                               cmd->write_data_done -= pdu->length;
+                               pdu->status = ISCSI_PDU_NOT_RECEIVED;
+                       }
+               }
+       } else {
+               for (i = 0; i < cmd->seq_count; i++) {
+                       seq = &cmd->seq_list[i];
+
+                       if (seq->type != SEQTYPE_UNSOLICITED)
+                               continue;
+
+                       cmd->write_data_done -=
+                                       (seq->offset - seq->orig_offset);
+                       cmd->first_burst_len = 0;
+                       seq->data_sn = 0;
+                       seq->offset = seq->orig_offset;
+                       seq->next_burst_len = 0;
+                       seq->status = DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY;
+
+                       if (conn->sess->sess_ops->DataPDUInOrder)
+                               continue;
+
+                       for (j = 0; j < seq->pdu_count; j++) {
+                               pdu = &cmd->pdu_list[j+seq->pdu_start];
+
+                               if (pdu->status != ISCSI_PDU_RECEIVED_OK)
+                                       continue;
+
+                               pdu->status = ISCSI_PDU_NOT_RECEIVED;
+                       }
+               }
+       }
+}
+
+int iscsit_task_reassign_prepare_write(
+       struct iscsi_tmr_req *tmr_req,
+       struct iscsi_conn *conn)
+{
+       struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
+       struct se_cmd *se_cmd = se_tmr->ref_cmd;
+       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+       struct iscsi_pdu *pdu = NULL;
+       struct iscsi_r2t *r2t = NULL, *r2t_tmp;
+       int first_incomplete_r2t = 1, i = 0;
+
+       /*
+        * The command was in the process of receiving Unsolicited DataOUT when
+        * the connection failed.
+        */
+       if (cmd->unsolicited_data)
+               iscsit_task_reassign_prepare_unsolicited_dataout(cmd, conn);
+
+       /*
+        * The Initiator is requesting R2Ts starting from zero,  skip
+        * checking acknowledged R2Ts and start checking struct iscsi_r2ts
+        * greater than zero.
+        */
+       if (!tmr_req->exp_data_sn)
+               goto drop_unacknowledged_r2ts;
+
+       /*
+        * We now check that the PDUs in DataOUT sequences below
+        * the TMR TASK_REASSIGN ExpDataSN (R2TSN the Initiator is
+        * expecting next) have all the DataOUT they require to complete
+        * the DataOUT sequence.  First scan from R2TSN 0 to TMR
+        * TASK_REASSIGN ExpDataSN-1.
+        *
+        * If we have not received all DataOUT in question,  we must
+        * make sure to make the appropriate changes to values in
+        * struct iscsi_cmd (and elsewhere depending on session parameters)
+        * so iscsit_build_r2ts_for_cmd() in iscsit_task_reassign_complete_write()
+        * will resend a new R2T for the DataOUT sequences in question.
+        */
+       spin_lock_bh(&cmd->r2t_lock);
+       if (list_empty(&cmd->cmd_r2t_list)) {
+               spin_unlock_bh(&cmd->r2t_lock);
+               return -1;
+       }
+
+       list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) {
+
+               if (r2t->r2t_sn >= tmr_req->exp_data_sn)
+                       continue;
+               /*
+                * Safely ignore Recovery R2Ts and R2Ts that have completed
+                * DataOUT sequences.
+                */
+               if (r2t->seq_complete)
+                       continue;
+
+               if (r2t->recovery_r2t)
+                       continue;
+
+               /*
+                *                 DataSequenceInOrder=Yes:
+                *
+                * Taking into account the iSCSI implementation requirement of
+                * MaxOutstandingR2T=1 while ErrorRecoveryLevel>0 and
+                * DataSequenceInOrder=Yes, we must take into consideration
+                * the following:
+                *
+                *                  DataSequenceInOrder=No:
+                *
+                * Taking into account that the Initiator controls the (possibly
+                * random) PDU Order in (possibly random) Sequence Order of
+                * DataOUT the target requests with R2Ts,  we must take into
+                * consideration the following:
+                *
+                *      DataPDUInOrder=Yes for DataSequenceInOrder=[Yes,No]:
+                *
+                * While processing non-complete R2T DataOUT sequence requests
+                * the Target will re-request only the total sequence length
+                * minus current received offset.  This is because we must
+                * assume the initiator will continue sending DataOUT from the
+                * last PDU before the connection failed.
+                *
+                *      DataPDUInOrder=No for DataSequenceInOrder=[Yes,No]:
+                *
+                * While processing non-complete R2T DataOUT sequence requests
+                * the Target will re-request the entire DataOUT sequence if
+                * any single PDU is missing from the sequence.  This is because
+                * we have no logical method to determine the next PDU offset,
+                * and we must assume the Initiator will be sending any random
+                * PDU offset in the current sequence after TASK_REASSIGN
+                * has completed.
+                */
+               if (conn->sess->sess_ops->DataSequenceInOrder) {
+                       if (!first_incomplete_r2t) {
+                               cmd->r2t_offset -= r2t->xfer_len;
+                               goto next;
+                       }
+
+                       if (conn->sess->sess_ops->DataPDUInOrder) {
+                               cmd->data_sn = 0;
+                               cmd->r2t_offset -= (r2t->xfer_len -
+                                       cmd->next_burst_len);
+                               first_incomplete_r2t = 0;
+                               goto next;
+                       }
+
+                       cmd->data_sn = 0;
+                       cmd->r2t_offset -= r2t->xfer_len;
+
+                       for (i = 0; i < cmd->pdu_count; i++) {
+                               pdu = &cmd->pdu_list[i];
+
+                               if (pdu->status != ISCSI_PDU_RECEIVED_OK)
+                                       continue;
+
+                               if ((pdu->offset >= r2t->offset) &&
+                                   (pdu->offset < (r2t->offset +
+                                               r2t->xfer_len))) {
+                                       cmd->next_burst_len -= pdu->length;
+                                       cmd->write_data_done -= pdu->length;
+                                       pdu->status = ISCSI_PDU_NOT_RECEIVED;
+                               }
+                       }
+
+                       first_incomplete_r2t = 0;
+               } else {
+                       struct iscsi_seq *seq;
+
+                       seq = iscsit_get_seq_holder(cmd, r2t->offset,
+                                       r2t->xfer_len);
+                       if (!seq) {
+                               spin_unlock_bh(&cmd->r2t_lock);
+                               return -1;
+                       }
+
+                       cmd->write_data_done -=
+                                       (seq->offset - seq->orig_offset);
+                       seq->data_sn = 0;
+                       seq->offset = seq->orig_offset;
+                       seq->next_burst_len = 0;
+                       seq->status = DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY;
+
+                       cmd->seq_send_order--;
+
+                       if (conn->sess->sess_ops->DataPDUInOrder)
+                               goto next;
+
+                       for (i = 0; i < seq->pdu_count; i++) {
+                               pdu = &cmd->pdu_list[i+seq->pdu_start];
+
+                               if (pdu->status != ISCSI_PDU_RECEIVED_OK)
+                                       continue;
+
+                               pdu->status = ISCSI_PDU_NOT_RECEIVED;
+                       }
+               }
+
+next:
+               cmd->outstanding_r2ts--;
+       }
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       /*
+        * We now drop all unacknowledged R2Ts, ie: ExpDataSN from TMR
+        * TASK_REASSIGN to the last R2T in the list..  We are also careful
+        * to check that the Initiator is not requesting R2Ts for DataOUT
+        * sequences it has already completed.
+        *
+        * Free each R2T in question and adjust values in struct iscsi_cmd
+        * accordingly so iscsit_build_r2ts_for_cmd() do the rest of
+        * the work after the TMR TASK_REASSIGN Response is sent.
+        */
+drop_unacknowledged_r2ts:
+
+       cmd->cmd_flags &= ~ICF_SENT_LAST_R2T;
+       cmd->r2t_sn = tmr_req->exp_data_sn;
+
+       spin_lock_bh(&cmd->r2t_lock);
+       list_for_each_entry_safe(r2t, r2t_tmp, &cmd->cmd_r2t_list, r2t_list) {
+               /*
+                * Skip up to the R2T Sequence number provided by the
+                * iSCSI TASK_REASSIGN TMR
+                */
+               if (r2t->r2t_sn < tmr_req->exp_data_sn)
+                       continue;
+
+               if (r2t->seq_complete) {
+                       pr_err("Initiator is requesting R2Ts from"
+                               " R2TSN: 0x%08x, but R2TSN: 0x%08x, Offset: %u,"
+                               " Length: %u is already complete."
+                               "   BAD INITIATOR ERL=2 IMPLEMENTATION!\n",
+                               tmr_req->exp_data_sn, r2t->r2t_sn,
+                               r2t->offset, r2t->xfer_len);
+                       spin_unlock_bh(&cmd->r2t_lock);
+                       return -1;
+               }
+
+               if (r2t->recovery_r2t) {
+                       iscsit_free_r2t(r2t, cmd);
+                       continue;
+               }
+
+               /*                 DataSequenceInOrder=Yes:
+                *
+                * Taking into account the iSCSI implementation requirement of
+                * MaxOutstandingR2T=1 while ErrorRecoveryLevel>0 and
+                * DataSequenceInOrder=Yes, it's safe to subtract the R2Ts
+                * entire transfer length from the commands R2T offset marker.
+                *
+                *                 DataSequenceInOrder=No:
+                *
+                * We subtract the difference from struct iscsi_seq between the
+                * current offset and original offset from cmd->write_data_done
+                * for account for DataOUT PDUs already received.  Then reset
+                * the current offset to the original and zero out the current
+                * burst length,  to make sure we re-request the entire DataOUT
+                * sequence.
+                */
+               if (conn->sess->sess_ops->DataSequenceInOrder)
+                       cmd->r2t_offset -= r2t->xfer_len;
+               else
+                       cmd->seq_send_order--;
+
+               cmd->outstanding_r2ts--;
+               iscsit_free_r2t(r2t, cmd);
+       }
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       return 0;
+}
+
+/*
+ *     Performs sanity checks TMR TASK_REASSIGN's ExpDataSN for
+ *     a given struct iscsi_cmd.
+ */
+int iscsit_check_task_reassign_expdatasn(
+       struct iscsi_tmr_req *tmr_req,
+       struct iscsi_conn *conn)
+{
+       struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
+       struct se_cmd *se_cmd = se_tmr->ref_cmd;
+       struct iscsi_cmd *ref_cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+
+       if (ref_cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD)
+               return 0;
+
+       if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION)
+               return 0;
+
+       if (ref_cmd->data_direction == DMA_NONE)
+               return 0;
+
+       /*
+        * For READs the TMR TASK_REASSIGNs ExpDataSN contains the next DataSN
+        * of DataIN the Initiator is expecting.
+        *
+        * Also check that the Initiator is not re-requesting DataIN that has
+        * already been acknowledged with a DataAck SNACK.
+        */
+       if (ref_cmd->data_direction == DMA_FROM_DEVICE) {
+               if (tmr_req->exp_data_sn > ref_cmd->data_sn) {
+                       pr_err("Received ExpDataSN: 0x%08x for READ"
+                               " in TMR TASK_REASSIGN greater than command's"
+                               " DataSN: 0x%08x.\n", tmr_req->exp_data_sn,
+                               ref_cmd->data_sn);
+                       return -1;
+               }
+               if ((ref_cmd->cmd_flags & ICF_GOT_DATACK_SNACK) &&
+                   (tmr_req->exp_data_sn <= ref_cmd->acked_data_sn)) {
+                       pr_err("Received ExpDataSN: 0x%08x for READ"
+                               " in TMR TASK_REASSIGN for previously"
+                               " acknowledged DataIN: 0x%08x,"
+                               " protocol error\n", tmr_req->exp_data_sn,
+                               ref_cmd->acked_data_sn);
+                       return -1;
+               }
+               return iscsit_task_reassign_prepare_read(tmr_req, conn);
+       }
+
+       /*
+        * For WRITEs the TMR TASK_REASSIGNs ExpDataSN contains the next R2TSN
+        * for R2Ts the Initiator is expecting.
+        *
+        * Do the magic in iscsit_task_reassign_prepare_write().
+        */
+       if (ref_cmd->data_direction == DMA_TO_DEVICE) {
+               if (tmr_req->exp_data_sn > ref_cmd->r2t_sn) {
+                       pr_err("Received ExpDataSN: 0x%08x for WRITE"
+                               " in TMR TASK_REASSIGN greater than command's"
+                               " R2TSN: 0x%08x.\n", tmr_req->exp_data_sn,
+                                       ref_cmd->r2t_sn);
+                       return -1;
+               }
+               return iscsit_task_reassign_prepare_write(tmr_req, conn);
+       }
+
+       pr_err("Unknown iSCSI data_direction: 0x%02x\n",
+                       ref_cmd->data_direction);
+
+       return -1;
+}
diff --git a/drivers/target/iscsi/iscsi_target_tmr.h b/drivers/target/iscsi/iscsi_target_tmr.h
new file mode 100644 (file)
index 0000000..142e992
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef ISCSI_TARGET_TMR_H
+#define ISCSI_TARGET_TMR_H
+
+extern u8 iscsit_tmr_abort_task(struct iscsi_cmd *, unsigned char *);
+extern int iscsit_tmr_task_warm_reset(struct iscsi_conn *, struct iscsi_tmr_req *,
+                       unsigned char *);
+extern int iscsit_tmr_task_cold_reset(struct iscsi_conn *, struct iscsi_tmr_req *,
+                       unsigned char *);
+extern u8 iscsit_tmr_task_reassign(struct iscsi_cmd *, unsigned char *);
+extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
+extern int iscsit_check_task_reassign_expdatasn(struct iscsi_tmr_req *,
+                       struct iscsi_conn *);
+
+#endif /* ISCSI_TARGET_TMR_H */
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
new file mode 100644 (file)
index 0000000..d4cf2cd
--- /dev/null
@@ -0,0 +1,759 @@
+/*******************************************************************************
+ * This file contains iSCSI Target Portal Group related functions.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+#include <target/target_core_tpg.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_erl0.h"
+#include "iscsi_target_login.h"
+#include "iscsi_target_nodeattrib.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target.h"
+#include "iscsi_target_parameters.h"
+
+struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u16 tpgt)
+{
+       struct iscsi_portal_group *tpg;
+
+       tpg = kzalloc(sizeof(struct iscsi_portal_group), GFP_KERNEL);
+       if (!tpg) {
+               pr_err("Unable to allocate struct iscsi_portal_group\n");
+               return NULL;
+       }
+
+       tpg->tpgt = tpgt;
+       tpg->tpg_state = TPG_STATE_FREE;
+       tpg->tpg_tiqn = tiqn;
+       INIT_LIST_HEAD(&tpg->tpg_gnp_list);
+       INIT_LIST_HEAD(&tpg->tpg_list);
+       mutex_init(&tpg->tpg_access_lock);
+       mutex_init(&tpg->np_login_lock);
+       spin_lock_init(&tpg->tpg_state_lock);
+       spin_lock_init(&tpg->tpg_np_lock);
+
+       return tpg;
+}
+
+static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *);
+
+int iscsit_load_discovery_tpg(void)
+{
+       struct iscsi_param *param;
+       struct iscsi_portal_group *tpg;
+       int ret;
+
+       tpg = iscsit_alloc_portal_group(NULL, 1);
+       if (!tpg) {
+               pr_err("Unable to allocate struct iscsi_portal_group\n");
+               return -1;
+       }
+
+       ret = core_tpg_register(
+                       &lio_target_fabric_configfs->tf_ops,
+                       NULL, &tpg->tpg_se_tpg, (void *)tpg,
+                       TRANSPORT_TPG_TYPE_DISCOVERY);
+       if (ret < 0) {
+               kfree(tpg);
+               return -1;
+       }
+
+       tpg->sid = 1; /* First Assigned LIO Session ID */
+       iscsit_set_default_tpg_attribs(tpg);
+
+       if (iscsi_create_default_params(&tpg->param_list) < 0)
+               goto out;
+       /*
+        * By default we disable authentication for discovery sessions,
+        * this can be changed with:
+        *
+        * /sys/kernel/config/target/iscsi/discovery_auth/enforce_discovery_auth
+        */
+       param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list);
+       if (!param)
+               goto out;
+
+       if (iscsi_update_param_value(param, "CHAP,None") < 0)
+               goto out;
+
+       tpg->tpg_attrib.authentication = 0;
+
+       spin_lock(&tpg->tpg_state_lock);
+       tpg->tpg_state  = TPG_STATE_ACTIVE;
+       spin_unlock(&tpg->tpg_state_lock);
+
+       iscsit_global->discovery_tpg = tpg;
+       pr_debug("CORE[0] - Allocated Discovery TPG\n");
+
+       return 0;
+out:
+       if (tpg->sid == 1)
+               core_tpg_deregister(&tpg->tpg_se_tpg);
+       kfree(tpg);
+       return -1;
+}
+
+void iscsit_release_discovery_tpg(void)
+{
+       struct iscsi_portal_group *tpg = iscsit_global->discovery_tpg;
+
+       if (!tpg)
+               return;
+
+       core_tpg_deregister(&tpg->tpg_se_tpg);
+
+       kfree(tpg);
+       iscsit_global->discovery_tpg = NULL;
+}
+
+struct iscsi_portal_group *iscsit_get_tpg_from_np(
+       struct iscsi_tiqn *tiqn,
+       struct iscsi_np *np)
+{
+       struct iscsi_portal_group *tpg = NULL;
+       struct iscsi_tpg_np *tpg_np;
+
+       spin_lock(&tiqn->tiqn_tpg_lock);
+       list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) {
+
+               spin_lock(&tpg->tpg_state_lock);
+               if (tpg->tpg_state == TPG_STATE_FREE) {
+                       spin_unlock(&tpg->tpg_state_lock);
+                       continue;
+               }
+               spin_unlock(&tpg->tpg_state_lock);
+
+               spin_lock(&tpg->tpg_np_lock);
+               list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) {
+                       if (tpg_np->tpg_np == np) {
+                               spin_unlock(&tpg->tpg_np_lock);
+                               spin_unlock(&tiqn->tiqn_tpg_lock);
+                               return tpg;
+                       }
+               }
+               spin_unlock(&tpg->tpg_np_lock);
+       }
+       spin_unlock(&tiqn->tiqn_tpg_lock);
+
+       return NULL;
+}
+
+int iscsit_get_tpg(
+       struct iscsi_portal_group *tpg)
+{
+       int ret;
+
+       ret = mutex_lock_interruptible(&tpg->tpg_access_lock);
+       return ((ret != 0) || signal_pending(current)) ? -1 : 0;
+}
+
+void iscsit_put_tpg(struct iscsi_portal_group *tpg)
+{
+       mutex_unlock(&tpg->tpg_access_lock);
+}
+
+static void iscsit_clear_tpg_np_login_thread(
+       struct iscsi_tpg_np *tpg_np,
+       struct iscsi_portal_group *tpg)
+{
+       if (!tpg_np->tpg_np) {
+               pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n");
+               return;
+       }
+
+       iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg);
+}
+
+void iscsit_clear_tpg_np_login_threads(
+       struct iscsi_portal_group *tpg)
+{
+       struct iscsi_tpg_np *tpg_np;
+
+       spin_lock(&tpg->tpg_np_lock);
+       list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) {
+               if (!tpg_np->tpg_np) {
+                       pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n");
+                       continue;
+               }
+               spin_unlock(&tpg->tpg_np_lock);
+               iscsit_clear_tpg_np_login_thread(tpg_np, tpg);
+               spin_lock(&tpg->tpg_np_lock);
+       }
+       spin_unlock(&tpg->tpg_np_lock);
+}
+
+void iscsit_tpg_dump_params(struct iscsi_portal_group *tpg)
+{
+       iscsi_print_params(tpg->param_list);
+}
+
+static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg)
+{
+       struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+       a->authentication = TA_AUTHENTICATION;
+       a->login_timeout = TA_LOGIN_TIMEOUT;
+       a->netif_timeout = TA_NETIF_TIMEOUT;
+       a->default_cmdsn_depth = TA_DEFAULT_CMDSN_DEPTH;
+       a->generate_node_acls = TA_GENERATE_NODE_ACLS;
+       a->cache_dynamic_acls = TA_CACHE_DYNAMIC_ACLS;
+       a->demo_mode_write_protect = TA_DEMO_MODE_WRITE_PROTECT;
+       a->prod_mode_write_protect = TA_PROD_MODE_WRITE_PROTECT;
+}
+
+int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg)
+{
+       if (tpg->tpg_state != TPG_STATE_FREE) {
+               pr_err("Unable to add iSCSI Target Portal Group: %d"
+                       " while not in TPG_STATE_FREE state.\n", tpg->tpgt);
+               return -EEXIST;
+       }
+       iscsit_set_default_tpg_attribs(tpg);
+
+       if (iscsi_create_default_params(&tpg->param_list) < 0)
+               goto err_out;
+
+       ISCSI_TPG_ATTRIB(tpg)->tpg = tpg;
+
+       spin_lock(&tpg->tpg_state_lock);
+       tpg->tpg_state  = TPG_STATE_INACTIVE;
+       spin_unlock(&tpg->tpg_state_lock);
+
+       spin_lock(&tiqn->tiqn_tpg_lock);
+       list_add_tail(&tpg->tpg_list, &tiqn->tiqn_tpg_list);
+       tiqn->tiqn_ntpgs++;
+       pr_debug("CORE[%s]_TPG[%hu] - Added iSCSI Target Portal Group\n",
+                       tiqn->tiqn, tpg->tpgt);
+       spin_unlock(&tiqn->tiqn_tpg_lock);
+
+       return 0;
+err_out:
+       if (tpg->param_list) {
+               iscsi_release_param_list(tpg->param_list);
+               tpg->param_list = NULL;
+       }
+       kfree(tpg);
+       return -ENOMEM;
+}
+
+int iscsit_tpg_del_portal_group(
+       struct iscsi_tiqn *tiqn,
+       struct iscsi_portal_group *tpg,
+       int force)
+{
+       u8 old_state = tpg->tpg_state;
+
+       spin_lock(&tpg->tpg_state_lock);
+       tpg->tpg_state = TPG_STATE_INACTIVE;
+       spin_unlock(&tpg->tpg_state_lock);
+
+       if (iscsit_release_sessions_for_tpg(tpg, force) < 0) {
+               pr_err("Unable to delete iSCSI Target Portal Group:"
+                       " %hu while active sessions exist, and force=0\n",
+                       tpg->tpgt);
+               tpg->tpg_state = old_state;
+               return -EPERM;
+       }
+
+       core_tpg_clear_object_luns(&tpg->tpg_se_tpg);
+
+       if (tpg->param_list) {
+               iscsi_release_param_list(tpg->param_list);
+               tpg->param_list = NULL;
+       }
+
+       core_tpg_deregister(&tpg->tpg_se_tpg);
+
+       spin_lock(&tpg->tpg_state_lock);
+       tpg->tpg_state = TPG_STATE_FREE;
+       spin_unlock(&tpg->tpg_state_lock);
+
+       spin_lock(&tiqn->tiqn_tpg_lock);
+       tiqn->tiqn_ntpgs--;
+       list_del(&tpg->tpg_list);
+       spin_unlock(&tiqn->tiqn_tpg_lock);
+
+       pr_debug("CORE[%s]_TPG[%hu] - Deleted iSCSI Target Portal Group\n",
+                       tiqn->tiqn, tpg->tpgt);
+
+       kfree(tpg);
+       return 0;
+}
+
+int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
+{
+       struct iscsi_param *param;
+       struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
+
+       spin_lock(&tpg->tpg_state_lock);
+       if (tpg->tpg_state == TPG_STATE_ACTIVE) {
+               pr_err("iSCSI target portal group: %hu is already"
+                       " active, ignoring request.\n", tpg->tpgt);
+               spin_unlock(&tpg->tpg_state_lock);
+               return -EINVAL;
+       }
+       /*
+        * Make sure that AuthMethod does not contain None as an option
+        * unless explictly disabled.  Set the default to CHAP if authentication
+        * is enforced (as per default), and remove the NONE option.
+        */
+       param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list);
+       if (!param) {
+               spin_unlock(&tpg->tpg_state_lock);
+               return -ENOMEM;
+       }
+
+       if (ISCSI_TPG_ATTRIB(tpg)->authentication) {
+               if (!strcmp(param->value, NONE))
+                       if (iscsi_update_param_value(param, CHAP) < 0) {
+                               spin_unlock(&tpg->tpg_state_lock);
+                               return -ENOMEM;
+                       }
+               if (iscsit_ta_authentication(tpg, 1) < 0) {
+                       spin_unlock(&tpg->tpg_state_lock);
+                       return -ENOMEM;
+               }
+       }
+
+       tpg->tpg_state = TPG_STATE_ACTIVE;
+       spin_unlock(&tpg->tpg_state_lock);
+
+       spin_lock(&tiqn->tiqn_tpg_lock);
+       tiqn->tiqn_active_tpgs++;
+       pr_debug("iSCSI_TPG[%hu] - Enabled iSCSI Target Portal Group\n",
+                       tpg->tpgt);
+       spin_unlock(&tiqn->tiqn_tpg_lock);
+
+       return 0;
+}
+
+int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force)
+{
+       struct iscsi_tiqn *tiqn;
+       u8 old_state = tpg->tpg_state;
+
+       spin_lock(&tpg->tpg_state_lock);
+       if (tpg->tpg_state == TPG_STATE_INACTIVE) {
+               pr_err("iSCSI Target Portal Group: %hu is already"
+                       " inactive, ignoring request.\n", tpg->tpgt);
+               spin_unlock(&tpg->tpg_state_lock);
+               return -EINVAL;
+       }
+       tpg->tpg_state = TPG_STATE_INACTIVE;
+       spin_unlock(&tpg->tpg_state_lock);
+
+       iscsit_clear_tpg_np_login_threads(tpg);
+
+       if (iscsit_release_sessions_for_tpg(tpg, force) < 0) {
+               spin_lock(&tpg->tpg_state_lock);
+               tpg->tpg_state = old_state;
+               spin_unlock(&tpg->tpg_state_lock);
+               pr_err("Unable to disable iSCSI Target Portal Group:"
+                       " %hu while active sessions exist, and force=0\n",
+                       tpg->tpgt);
+               return -EPERM;
+       }
+
+       tiqn = tpg->tpg_tiqn;
+       if (!tiqn || (tpg == iscsit_global->discovery_tpg))
+               return 0;
+
+       spin_lock(&tiqn->tiqn_tpg_lock);
+       tiqn->tiqn_active_tpgs--;
+       pr_debug("iSCSI_TPG[%hu] - Disabled iSCSI Target Portal Group\n",
+                       tpg->tpgt);
+       spin_unlock(&tiqn->tiqn_tpg_lock);
+
+       return 0;
+}
+
+struct iscsi_node_attrib *iscsit_tpg_get_node_attrib(
+       struct iscsi_session *sess)
+{
+       struct se_session *se_sess = sess->se_sess;
+       struct se_node_acl *se_nacl = se_sess->se_node_acl;
+       struct iscsi_node_acl *acl = container_of(se_nacl, struct iscsi_node_acl,
+                                       se_node_acl);
+
+       return &acl->node_attrib;
+}
+
+struct iscsi_tpg_np *iscsit_tpg_locate_child_np(
+       struct iscsi_tpg_np *tpg_np,
+       int network_transport)
+{
+       struct iscsi_tpg_np *tpg_np_child, *tpg_np_child_tmp;
+
+       spin_lock(&tpg_np->tpg_np_parent_lock);
+       list_for_each_entry_safe(tpg_np_child, tpg_np_child_tmp,
+                       &tpg_np->tpg_np_parent_list, tpg_np_child_list) {
+               if (tpg_np_child->tpg_np->np_network_transport ==
+                               network_transport) {
+                       spin_unlock(&tpg_np->tpg_np_parent_lock);
+                       return tpg_np_child;
+               }
+       }
+       spin_unlock(&tpg_np->tpg_np_parent_lock);
+
+       return NULL;
+}
+
+struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
+       struct iscsi_portal_group *tpg,
+       struct __kernel_sockaddr_storage *sockaddr,
+       char *ip_str,
+       struct iscsi_tpg_np *tpg_np_parent,
+       int network_transport)
+{
+       struct iscsi_np *np;
+       struct iscsi_tpg_np *tpg_np;
+
+       tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL);
+       if (!tpg_np) {
+               pr_err("Unable to allocate memory for"
+                               " struct iscsi_tpg_np.\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       np = iscsit_add_np(sockaddr, ip_str, network_transport);
+       if (IS_ERR(np)) {
+               kfree(tpg_np);
+               return ERR_CAST(np);
+       }
+
+       INIT_LIST_HEAD(&tpg_np->tpg_np_list);
+       INIT_LIST_HEAD(&tpg_np->tpg_np_child_list);
+       INIT_LIST_HEAD(&tpg_np->tpg_np_parent_list);
+       spin_lock_init(&tpg_np->tpg_np_parent_lock);
+       tpg_np->tpg_np          = np;
+       tpg_np->tpg             = tpg;
+
+       spin_lock(&tpg->tpg_np_lock);
+       list_add_tail(&tpg_np->tpg_np_list, &tpg->tpg_gnp_list);
+       tpg->num_tpg_nps++;
+       if (tpg->tpg_tiqn)
+               tpg->tpg_tiqn->tiqn_num_tpg_nps++;
+       spin_unlock(&tpg->tpg_np_lock);
+
+       if (tpg_np_parent) {
+               tpg_np->tpg_np_parent = tpg_np_parent;
+               spin_lock(&tpg_np_parent->tpg_np_parent_lock);
+               list_add_tail(&tpg_np->tpg_np_child_list,
+                       &tpg_np_parent->tpg_np_parent_list);
+               spin_unlock(&tpg_np_parent->tpg_np_parent_lock);
+       }
+
+       pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n",
+               tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
+               (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP");
+
+       return tpg_np;
+}
+
+static int iscsit_tpg_release_np(
+       struct iscsi_tpg_np *tpg_np,
+       struct iscsi_portal_group *tpg,
+       struct iscsi_np *np)
+{
+       iscsit_clear_tpg_np_login_thread(tpg_np, tpg);
+
+       pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n",
+               tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
+               (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP");
+
+       tpg_np->tpg_np = NULL;
+       tpg_np->tpg = NULL;
+       kfree(tpg_np);
+       /*
+        * iscsit_del_np() will shutdown struct iscsi_np when last TPG reference is released.
+        */
+       return iscsit_del_np(np);
+}
+
+int iscsit_tpg_del_network_portal(
+       struct iscsi_portal_group *tpg,
+       struct iscsi_tpg_np *tpg_np)
+{
+       struct iscsi_np *np;
+       struct iscsi_tpg_np *tpg_np_child, *tpg_np_child_tmp;
+       int ret = 0;
+
+       np = tpg_np->tpg_np;
+       if (!np) {
+               pr_err("Unable to locate struct iscsi_np from"
+                               " struct iscsi_tpg_np\n");
+               return -EINVAL;
+       }
+
+       if (!tpg_np->tpg_np_parent) {
+               /*
+                * We are the parent tpg network portal.  Release all of the
+                * child tpg_np's (eg: the non ISCSI_TCP ones) on our parent
+                * list first.
+                */
+               list_for_each_entry_safe(tpg_np_child, tpg_np_child_tmp,
+                               &tpg_np->tpg_np_parent_list,
+                               tpg_np_child_list) {
+                       ret = iscsit_tpg_del_network_portal(tpg, tpg_np_child);
+                       if (ret < 0)
+                               pr_err("iscsit_tpg_del_network_portal()"
+                                       " failed: %d\n", ret);
+               }
+       } else {
+               /*
+                * We are not the parent ISCSI_TCP tpg network portal.  Release
+                * our own network portals from the child list.
+                */
+               spin_lock(&tpg_np->tpg_np_parent->tpg_np_parent_lock);
+               list_del(&tpg_np->tpg_np_child_list);
+               spin_unlock(&tpg_np->tpg_np_parent->tpg_np_parent_lock);
+       }
+
+       spin_lock(&tpg->tpg_np_lock);
+       list_del(&tpg_np->tpg_np_list);
+       tpg->num_tpg_nps--;
+       if (tpg->tpg_tiqn)
+               tpg->tpg_tiqn->tiqn_num_tpg_nps--;
+       spin_unlock(&tpg->tpg_np_lock);
+
+       return iscsit_tpg_release_np(tpg_np, tpg, np);
+}
+
+int iscsit_tpg_set_initiator_node_queue_depth(
+       struct iscsi_portal_group *tpg,
+       unsigned char *initiatorname,
+       u32 queue_depth,
+       int force)
+{
+       return core_tpg_set_initiator_node_queue_depth(&tpg->tpg_se_tpg,
+               initiatorname, queue_depth, force);
+}
+
+int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication)
+{
+       unsigned char buf1[256], buf2[256], *none = NULL;
+       int len;
+       struct iscsi_param *param;
+       struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+       if ((authentication != 1) && (authentication != 0)) {
+               pr_err("Illegal value for authentication parameter:"
+                       " %u, ignoring request.\n", authentication);
+               return -1;
+       }
+
+       memset(buf1, 0, sizeof(buf1));
+       memset(buf2, 0, sizeof(buf2));
+
+       param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list);
+       if (!param)
+               return -EINVAL;
+
+       if (authentication) {
+               snprintf(buf1, sizeof(buf1), "%s", param->value);
+               none = strstr(buf1, NONE);
+               if (!none)
+                       goto out;
+               if (!strncmp(none + 4, ",", 1)) {
+                       if (!strcmp(buf1, none))
+                               sprintf(buf2, "%s", none+5);
+                       else {
+                               none--;
+                               *none = '\0';
+                               len = sprintf(buf2, "%s", buf1);
+                               none += 5;
+                               sprintf(buf2 + len, "%s", none);
+                       }
+               } else {
+                       none--;
+                       *none = '\0';
+                       sprintf(buf2, "%s", buf1);
+               }
+               if (iscsi_update_param_value(param, buf2) < 0)
+                       return -EINVAL;
+       } else {
+               snprintf(buf1, sizeof(buf1), "%s", param->value);
+               none = strstr(buf1, NONE);
+               if ((none))
+                       goto out;
+               strncat(buf1, ",", strlen(","));
+               strncat(buf1, NONE, strlen(NONE));
+               if (iscsi_update_param_value(param, buf1) < 0)
+                       return -EINVAL;
+       }
+
+out:
+       a->authentication = authentication;
+       pr_debug("%s iSCSI Authentication Methods for TPG: %hu.\n",
+               a->authentication ? "Enforcing" : "Disabling", tpg->tpgt);
+
+       return 0;
+}
+
+int iscsit_ta_login_timeout(
+       struct iscsi_portal_group *tpg,
+       u32 login_timeout)
+{
+       struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+       if (login_timeout > TA_LOGIN_TIMEOUT_MAX) {
+               pr_err("Requested Login Timeout %u larger than maximum"
+                       " %u\n", login_timeout, TA_LOGIN_TIMEOUT_MAX);
+               return -EINVAL;
+       } else if (login_timeout < TA_LOGIN_TIMEOUT_MIN) {
+               pr_err("Requested Logout Timeout %u smaller than"
+                       " minimum %u\n", login_timeout, TA_LOGIN_TIMEOUT_MIN);
+               return -EINVAL;
+       }
+
+       a->login_timeout = login_timeout;
+       pr_debug("Set Logout Timeout to %u for Target Portal Group"
+               " %hu\n", a->login_timeout, tpg->tpgt);
+
+       return 0;
+}
+
+int iscsit_ta_netif_timeout(
+       struct iscsi_portal_group *tpg,
+       u32 netif_timeout)
+{
+       struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+       if (netif_timeout > TA_NETIF_TIMEOUT_MAX) {
+               pr_err("Requested Network Interface Timeout %u larger"
+                       " than maximum %u\n", netif_timeout,
+                               TA_NETIF_TIMEOUT_MAX);
+               return -EINVAL;
+       } else if (netif_timeout < TA_NETIF_TIMEOUT_MIN) {
+               pr_err("Requested Network Interface Timeout %u smaller"
+                       " than minimum %u\n", netif_timeout,
+                               TA_NETIF_TIMEOUT_MIN);
+               return -EINVAL;
+       }
+
+       a->netif_timeout = netif_timeout;
+       pr_debug("Set Network Interface Timeout to %u for"
+               " Target Portal Group %hu\n", a->netif_timeout, tpg->tpgt);
+
+       return 0;
+}
+
+int iscsit_ta_generate_node_acls(
+       struct iscsi_portal_group *tpg,
+       u32 flag)
+{
+       struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+       if ((flag != 0) && (flag != 1)) {
+               pr_err("Illegal value %d\n", flag);
+               return -EINVAL;
+       }
+
+       a->generate_node_acls = flag;
+       pr_debug("iSCSI_TPG[%hu] - Generate Initiator Portal Group ACLs: %s\n",
+               tpg->tpgt, (a->generate_node_acls) ? "Enabled" : "Disabled");
+
+       return 0;
+}
+
+int iscsit_ta_default_cmdsn_depth(
+       struct iscsi_portal_group *tpg,
+       u32 tcq_depth)
+{
+       struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+       if (tcq_depth > TA_DEFAULT_CMDSN_DEPTH_MAX) {
+               pr_err("Requested Default Queue Depth: %u larger"
+                       " than maximum %u\n", tcq_depth,
+                               TA_DEFAULT_CMDSN_DEPTH_MAX);
+               return -EINVAL;
+       } else if (tcq_depth < TA_DEFAULT_CMDSN_DEPTH_MIN) {
+               pr_err("Requested Default Queue Depth: %u smaller"
+                       " than minimum %u\n", tcq_depth,
+                               TA_DEFAULT_CMDSN_DEPTH_MIN);
+               return -EINVAL;
+       }
+
+       a->default_cmdsn_depth = tcq_depth;
+       pr_debug("iSCSI_TPG[%hu] - Set Default CmdSN TCQ Depth to %u\n",
+               tpg->tpgt, a->default_cmdsn_depth);
+
+       return 0;
+}
+
+int iscsit_ta_cache_dynamic_acls(
+       struct iscsi_portal_group *tpg,
+       u32 flag)
+{
+       struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+       if ((flag != 0) && (flag != 1)) {
+               pr_err("Illegal value %d\n", flag);
+               return -EINVAL;
+       }
+
+       a->cache_dynamic_acls = flag;
+       pr_debug("iSCSI_TPG[%hu] - Cache Dynamic Initiator Portal Group"
+               " ACLs %s\n", tpg->tpgt, (a->cache_dynamic_acls) ?
+               "Enabled" : "Disabled");
+
+       return 0;
+}
+
+int iscsit_ta_demo_mode_write_protect(
+       struct iscsi_portal_group *tpg,
+       u32 flag)
+{
+       struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+       if ((flag != 0) && (flag != 1)) {
+               pr_err("Illegal value %d\n", flag);
+               return -EINVAL;
+       }
+
+       a->demo_mode_write_protect = flag;
+       pr_debug("iSCSI_TPG[%hu] - Demo Mode Write Protect bit: %s\n",
+               tpg->tpgt, (a->demo_mode_write_protect) ? "ON" : "OFF");
+
+       return 0;
+}
+
+int iscsit_ta_prod_mode_write_protect(
+       struct iscsi_portal_group *tpg,
+       u32 flag)
+{
+       struct iscsi_tpg_attrib *a = &tpg->tpg_attrib;
+
+       if ((flag != 0) && (flag != 1)) {
+               pr_err("Illegal value %d\n", flag);
+               return -EINVAL;
+       }
+
+       a->prod_mode_write_protect = flag;
+       pr_debug("iSCSI_TPG[%hu] - Production Mode Write Protect bit:"
+               " %s\n", tpg->tpgt, (a->prod_mode_write_protect) ?
+               "ON" : "OFF");
+
+       return 0;
+}
diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h
new file mode 100644 (file)
index 0000000..dda48c1
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef ISCSI_TARGET_TPG_H
+#define ISCSI_TARGET_TPG_H
+
+extern struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *, u16);
+extern int iscsit_load_discovery_tpg(void);
+extern void iscsit_release_discovery_tpg(void);
+extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *,
+                       struct iscsi_np *);
+extern int iscsit_get_tpg(struct iscsi_portal_group *);
+extern void iscsit_put_tpg(struct iscsi_portal_group *);
+extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *);
+extern void iscsit_tpg_dump_params(struct iscsi_portal_group *);
+extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *);
+extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *,
+                       int);
+extern int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *);
+extern int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *, int);
+extern struct iscsi_node_acl *iscsit_tpg_add_initiator_node_acl(
+                       struct iscsi_portal_group *, const char *, u32);
+extern void iscsit_tpg_del_initiator_node_acl(struct iscsi_portal_group *,
+                       struct se_node_acl *);
+extern struct iscsi_node_attrib *iscsit_tpg_get_node_attrib(struct iscsi_session *);
+extern void iscsit_tpg_del_external_nps(struct iscsi_tpg_np *);
+extern struct iscsi_tpg_np *iscsit_tpg_locate_child_np(struct iscsi_tpg_np *, int);
+extern struct iscsi_tpg_np *iscsit_tpg_add_network_portal(struct iscsi_portal_group *,
+                       struct __kernel_sockaddr_storage *, char *, struct iscsi_tpg_np *,
+                       int);
+extern int iscsit_tpg_del_network_portal(struct iscsi_portal_group *,
+                       struct iscsi_tpg_np *);
+extern int iscsit_tpg_set_initiator_node_queue_depth(struct iscsi_portal_group *,
+                       unsigned char *, u32, int);
+extern int iscsit_ta_authentication(struct iscsi_portal_group *, u32);
+extern int iscsit_ta_login_timeout(struct iscsi_portal_group *, u32);
+extern int iscsit_ta_netif_timeout(struct iscsi_portal_group *, u32);
+extern int iscsit_ta_generate_node_acls(struct iscsi_portal_group *, u32);
+extern int iscsit_ta_default_cmdsn_depth(struct iscsi_portal_group *, u32);
+extern int iscsit_ta_cache_dynamic_acls(struct iscsi_portal_group *, u32);
+extern int iscsit_ta_demo_mode_write_protect(struct iscsi_portal_group *, u32);
+extern int iscsit_ta_prod_mode_write_protect(struct iscsi_portal_group *, u32);
+
+#endif /* ISCSI_TARGET_TPG_H */
diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c
new file mode 100644 (file)
index 0000000..0baac5b
--- /dev/null
@@ -0,0 +1,551 @@
+/*******************************************************************************
+ * This file contains the iSCSI Login Thread and Thread Queue functions.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/bitmap.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_tq.h"
+#include "iscsi_target.h"
+
+static LIST_HEAD(active_ts_list);
+static LIST_HEAD(inactive_ts_list);
+static DEFINE_SPINLOCK(active_ts_lock);
+static DEFINE_SPINLOCK(inactive_ts_lock);
+static DEFINE_SPINLOCK(ts_bitmap_lock);
+
+static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts)
+{
+       spin_lock(&active_ts_lock);
+       list_add_tail(&ts->ts_list, &active_ts_list);
+       iscsit_global->active_ts++;
+       spin_unlock(&active_ts_lock);
+}
+
+extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts)
+{
+       spin_lock(&inactive_ts_lock);
+       list_add_tail(&ts->ts_list, &inactive_ts_list);
+       iscsit_global->inactive_ts++;
+       spin_unlock(&inactive_ts_lock);
+}
+
+static void iscsi_del_ts_from_active_list(struct iscsi_thread_set *ts)
+{
+       spin_lock(&active_ts_lock);
+       list_del(&ts->ts_list);
+       iscsit_global->active_ts--;
+       spin_unlock(&active_ts_lock);
+}
+
+static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void)
+{
+       struct iscsi_thread_set *ts;
+
+       spin_lock(&inactive_ts_lock);
+       if (list_empty(&inactive_ts_list)) {
+               spin_unlock(&inactive_ts_lock);
+               return NULL;
+       }
+
+       list_for_each_entry(ts, &inactive_ts_list, ts_list)
+               break;
+
+       list_del(&ts->ts_list);
+       iscsit_global->inactive_ts--;
+       spin_unlock(&inactive_ts_lock);
+
+       return ts;
+}
+
+extern int iscsi_allocate_thread_sets(u32 thread_pair_count)
+{
+       int allocated_thread_pair_count = 0, i, thread_id;
+       struct iscsi_thread_set *ts = NULL;
+
+       for (i = 0; i < thread_pair_count; i++) {
+               ts = kzalloc(sizeof(struct iscsi_thread_set), GFP_KERNEL);
+               if (!ts) {
+                       pr_err("Unable to allocate memory for"
+                                       " thread set.\n");
+                       return allocated_thread_pair_count;
+               }
+               /*
+                * Locate the next available regision in the thread_set_bitmap
+                */
+               spin_lock(&ts_bitmap_lock);
+               thread_id = bitmap_find_free_region(iscsit_global->ts_bitmap,
+                               iscsit_global->ts_bitmap_count, get_order(1));
+               spin_unlock(&ts_bitmap_lock);
+               if (thread_id < 0) {
+                       pr_err("bitmap_find_free_region() failed for"
+                               " thread_set_bitmap\n");
+                       kfree(ts);
+                       return allocated_thread_pair_count;
+               }
+
+               ts->thread_id = thread_id;
+               ts->status = ISCSI_THREAD_SET_FREE;
+               INIT_LIST_HEAD(&ts->ts_list);
+               spin_lock_init(&ts->ts_state_lock);
+               init_completion(&ts->rx_post_start_comp);
+               init_completion(&ts->tx_post_start_comp);
+               init_completion(&ts->rx_restart_comp);
+               init_completion(&ts->tx_restart_comp);
+               init_completion(&ts->rx_start_comp);
+               init_completion(&ts->tx_start_comp);
+
+               ts->create_threads = 1;
+               ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s",
+                                       ISCSI_TX_THREAD_NAME);
+               if (IS_ERR(ts->tx_thread)) {
+                       dump_stack();
+                       pr_err("Unable to start iscsi_target_tx_thread\n");
+                       break;
+               }
+
+               ts->rx_thread = kthread_run(iscsi_target_rx_thread, ts, "%s",
+                                       ISCSI_RX_THREAD_NAME);
+               if (IS_ERR(ts->rx_thread)) {
+                       kthread_stop(ts->tx_thread);
+                       pr_err("Unable to start iscsi_target_rx_thread\n");
+                       break;
+               }
+               ts->create_threads = 0;
+
+               iscsi_add_ts_to_inactive_list(ts);
+               allocated_thread_pair_count++;
+       }
+
+       pr_debug("Spawned %d thread set(s) (%d total threads).\n",
+               allocated_thread_pair_count, allocated_thread_pair_count * 2);
+       return allocated_thread_pair_count;
+}
+
+extern void iscsi_deallocate_thread_sets(void)
+{
+       u32 released_count = 0;
+       struct iscsi_thread_set *ts = NULL;
+
+       while ((ts = iscsi_get_ts_from_inactive_list())) {
+
+               spin_lock_bh(&ts->ts_state_lock);
+               ts->status = ISCSI_THREAD_SET_DIE;
+               spin_unlock_bh(&ts->ts_state_lock);
+
+               if (ts->rx_thread) {
+                       send_sig(SIGINT, ts->rx_thread, 1);
+                       kthread_stop(ts->rx_thread);
+               }
+               if (ts->tx_thread) {
+                       send_sig(SIGINT, ts->tx_thread, 1);
+                       kthread_stop(ts->tx_thread);
+               }
+               /*
+                * Release this thread_id in the thread_set_bitmap
+                */
+               spin_lock(&ts_bitmap_lock);
+               bitmap_release_region(iscsit_global->ts_bitmap,
+                               ts->thread_id, get_order(1));
+               spin_unlock(&ts_bitmap_lock);
+
+               released_count++;
+               kfree(ts);
+       }
+
+       if (released_count)
+               pr_debug("Stopped %d thread set(s) (%d total threads)."
+                       "\n", released_count, released_count * 2);
+}
+
+static void iscsi_deallocate_extra_thread_sets(void)
+{
+       u32 orig_count, released_count = 0;
+       struct iscsi_thread_set *ts = NULL;
+
+       orig_count = TARGET_THREAD_SET_COUNT;
+
+       while ((iscsit_global->inactive_ts + 1) > orig_count) {
+               ts = iscsi_get_ts_from_inactive_list();
+               if (!ts)
+                       break;
+
+               spin_lock_bh(&ts->ts_state_lock);
+               ts->status = ISCSI_THREAD_SET_DIE;
+               spin_unlock_bh(&ts->ts_state_lock);
+
+               if (ts->rx_thread) {
+                       send_sig(SIGINT, ts->rx_thread, 1);
+                       kthread_stop(ts->rx_thread);
+               }
+               if (ts->tx_thread) {
+                       send_sig(SIGINT, ts->tx_thread, 1);
+                       kthread_stop(ts->tx_thread);
+               }
+               /*
+                * Release this thread_id in the thread_set_bitmap
+                */
+               spin_lock(&ts_bitmap_lock);
+               bitmap_release_region(iscsit_global->ts_bitmap,
+                               ts->thread_id, get_order(1));
+               spin_unlock(&ts_bitmap_lock);
+
+               released_count++;
+               kfree(ts);
+       }
+
+       if (released_count) {
+               pr_debug("Stopped %d thread set(s) (%d total threads)."
+                       "\n", released_count, released_count * 2);
+       }
+}
+
+void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts)
+{
+       iscsi_add_ts_to_active_list(ts);
+
+       spin_lock_bh(&ts->ts_state_lock);
+       conn->thread_set = ts;
+       ts->conn = conn;
+       spin_unlock_bh(&ts->ts_state_lock);
+       /*
+        * Start up the RX thread and wait on rx_post_start_comp.  The RX
+        * Thread will then do the same for the TX Thread in
+        * iscsi_rx_thread_pre_handler().
+        */
+       complete(&ts->rx_start_comp);
+       wait_for_completion(&ts->rx_post_start_comp);
+}
+
+struct iscsi_thread_set *iscsi_get_thread_set(void)
+{
+       int allocate_ts = 0;
+       struct completion comp;
+       struct iscsi_thread_set *ts = NULL;
+       /*
+        * If no inactive thread set is available on the first call to
+        * iscsi_get_ts_from_inactive_list(), sleep for a second and
+        * try again.  If still none are available after two attempts,
+        * allocate a set ourselves.
+        */
+get_set:
+       ts = iscsi_get_ts_from_inactive_list();
+       if (!ts) {
+               if (allocate_ts == 2)
+                       iscsi_allocate_thread_sets(1);
+
+               init_completion(&comp);
+               wait_for_completion_timeout(&comp, 1 * HZ);
+
+               allocate_ts++;
+               goto get_set;
+       }
+
+       ts->delay_inactive = 1;
+       ts->signal_sent = 0;
+       ts->thread_count = 2;
+       init_completion(&ts->rx_restart_comp);
+       init_completion(&ts->tx_restart_comp);
+
+       return ts;
+}
+
+void iscsi_set_thread_clear(struct iscsi_conn *conn, u8 thread_clear)
+{
+       struct iscsi_thread_set *ts = NULL;
+
+       if (!conn->thread_set) {
+               pr_err("struct iscsi_conn->thread_set is NULL\n");
+               return;
+       }
+       ts = conn->thread_set;
+
+       spin_lock_bh(&ts->ts_state_lock);
+       ts->thread_clear &= ~thread_clear;
+
+       if ((thread_clear & ISCSI_CLEAR_RX_THREAD) &&
+           (ts->blocked_threads & ISCSI_BLOCK_RX_THREAD))
+               complete(&ts->rx_restart_comp);
+       else if ((thread_clear & ISCSI_CLEAR_TX_THREAD) &&
+                (ts->blocked_threads & ISCSI_BLOCK_TX_THREAD))
+               complete(&ts->tx_restart_comp);
+       spin_unlock_bh(&ts->ts_state_lock);
+}
+
+void iscsi_set_thread_set_signal(struct iscsi_conn *conn, u8 signal_sent)
+{
+       struct iscsi_thread_set *ts = NULL;
+
+       if (!conn->thread_set) {
+               pr_err("struct iscsi_conn->thread_set is NULL\n");
+               return;
+       }
+       ts = conn->thread_set;
+
+       spin_lock_bh(&ts->ts_state_lock);
+       ts->signal_sent |= signal_sent;
+       spin_unlock_bh(&ts->ts_state_lock);
+}
+
+int iscsi_release_thread_set(struct iscsi_conn *conn)
+{
+       int thread_called = 0;
+       struct iscsi_thread_set *ts = NULL;
+
+       if (!conn || !conn->thread_set) {
+               pr_err("connection or thread set pointer is NULL\n");
+               BUG();
+       }
+       ts = conn->thread_set;
+
+       spin_lock_bh(&ts->ts_state_lock);
+       ts->status = ISCSI_THREAD_SET_RESET;
+
+       if (!strncmp(current->comm, ISCSI_RX_THREAD_NAME,
+                       strlen(ISCSI_RX_THREAD_NAME)))
+               thread_called = ISCSI_RX_THREAD;
+       else if (!strncmp(current->comm, ISCSI_TX_THREAD_NAME,
+                       strlen(ISCSI_TX_THREAD_NAME)))
+               thread_called = ISCSI_TX_THREAD;
+
+       if (ts->rx_thread && (thread_called == ISCSI_TX_THREAD) &&
+          (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) {
+
+               if (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD)) {
+                       send_sig(SIGINT, ts->rx_thread, 1);
+                       ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD;
+               }
+               ts->blocked_threads |= ISCSI_BLOCK_RX_THREAD;
+               spin_unlock_bh(&ts->ts_state_lock);
+               wait_for_completion(&ts->rx_restart_comp);
+               spin_lock_bh(&ts->ts_state_lock);
+               ts->blocked_threads &= ~ISCSI_BLOCK_RX_THREAD;
+       }
+       if (ts->tx_thread && (thread_called == ISCSI_RX_THREAD) &&
+          (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) {
+
+               if (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD)) {
+                       send_sig(SIGINT, ts->tx_thread, 1);
+                       ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD;
+               }
+               ts->blocked_threads |= ISCSI_BLOCK_TX_THREAD;
+               spin_unlock_bh(&ts->ts_state_lock);
+               wait_for_completion(&ts->tx_restart_comp);
+               spin_lock_bh(&ts->ts_state_lock);
+               ts->blocked_threads &= ~ISCSI_BLOCK_TX_THREAD;
+       }
+
+       ts->conn = NULL;
+       ts->status = ISCSI_THREAD_SET_FREE;
+       spin_unlock_bh(&ts->ts_state_lock);
+
+       return 0;
+}
+
+int iscsi_thread_set_force_reinstatement(struct iscsi_conn *conn)
+{
+       struct iscsi_thread_set *ts;
+
+       if (!conn->thread_set)
+               return -1;
+       ts = conn->thread_set;
+
+       spin_lock_bh(&ts->ts_state_lock);
+       if (ts->status != ISCSI_THREAD_SET_ACTIVE) {
+               spin_unlock_bh(&ts->ts_state_lock);
+               return -1;
+       }
+
+       if (ts->tx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD))) {
+               send_sig(SIGINT, ts->tx_thread, 1);
+               ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD;
+       }
+       if (ts->rx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD))) {
+               send_sig(SIGINT, ts->rx_thread, 1);
+               ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD;
+       }
+       spin_unlock_bh(&ts->ts_state_lock);
+
+       return 0;
+}
+
+static void iscsi_check_to_add_additional_sets(void)
+{
+       int thread_sets_add;
+
+       spin_lock(&inactive_ts_lock);
+       thread_sets_add = iscsit_global->inactive_ts;
+       spin_unlock(&inactive_ts_lock);
+       if (thread_sets_add == 1)
+               iscsi_allocate_thread_sets(1);
+}
+
+static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts)
+{
+       spin_lock_bh(&ts->ts_state_lock);
+       if ((ts->status == ISCSI_THREAD_SET_DIE) || signal_pending(current)) {
+               spin_unlock_bh(&ts->ts_state_lock);
+               return -1;
+       }
+       spin_unlock_bh(&ts->ts_state_lock);
+
+       return 0;
+}
+
+struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts)
+{
+       int ret;
+
+       spin_lock_bh(&ts->ts_state_lock);
+       if (ts->create_threads) {
+               spin_unlock_bh(&ts->ts_state_lock);
+               goto sleep;
+       }
+
+       flush_signals(current);
+
+       if (ts->delay_inactive && (--ts->thread_count == 0)) {
+               spin_unlock_bh(&ts->ts_state_lock);
+               iscsi_del_ts_from_active_list(ts);
+
+               if (!iscsit_global->in_shutdown)
+                       iscsi_deallocate_extra_thread_sets();
+
+               iscsi_add_ts_to_inactive_list(ts);
+               spin_lock_bh(&ts->ts_state_lock);
+       }
+
+       if ((ts->status == ISCSI_THREAD_SET_RESET) &&
+           (ts->thread_clear & ISCSI_CLEAR_RX_THREAD))
+               complete(&ts->rx_restart_comp);
+
+       ts->thread_clear &= ~ISCSI_CLEAR_RX_THREAD;
+       spin_unlock_bh(&ts->ts_state_lock);
+sleep:
+       ret = wait_for_completion_interruptible(&ts->rx_start_comp);
+       if (ret != 0)
+               return NULL;
+
+       if (iscsi_signal_thread_pre_handler(ts) < 0)
+               return NULL;
+
+       if (!ts->conn) {
+               pr_err("struct iscsi_thread_set->conn is NULL for"
+                       " thread_id: %d, going back to sleep\n", ts->thread_id);
+               goto sleep;
+       }
+       iscsi_check_to_add_additional_sets();
+       /*
+        * The RX Thread starts up the TX Thread and sleeps.
+        */
+       ts->thread_clear |= ISCSI_CLEAR_RX_THREAD;
+       complete(&ts->tx_start_comp);
+       wait_for_completion(&ts->tx_post_start_comp);
+
+       return ts->conn;
+}
+
+struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts)
+{
+       int ret;
+
+       spin_lock_bh(&ts->ts_state_lock);
+       if (ts->create_threads) {
+               spin_unlock_bh(&ts->ts_state_lock);
+               goto sleep;
+       }
+
+       flush_signals(current);
+
+       if (ts->delay_inactive && (--ts->thread_count == 0)) {
+               spin_unlock_bh(&ts->ts_state_lock);
+               iscsi_del_ts_from_active_list(ts);
+
+               if (!iscsit_global->in_shutdown)
+                       iscsi_deallocate_extra_thread_sets();
+
+               iscsi_add_ts_to_inactive_list(ts);
+               spin_lock_bh(&ts->ts_state_lock);
+       }
+       if ((ts->status == ISCSI_THREAD_SET_RESET) &&
+           (ts->thread_clear & ISCSI_CLEAR_TX_THREAD))
+               complete(&ts->tx_restart_comp);
+
+       ts->thread_clear &= ~ISCSI_CLEAR_TX_THREAD;
+       spin_unlock_bh(&ts->ts_state_lock);
+sleep:
+       ret = wait_for_completion_interruptible(&ts->tx_start_comp);
+       if (ret != 0)
+               return NULL;
+
+       if (iscsi_signal_thread_pre_handler(ts) < 0)
+               return NULL;
+
+       if (!ts->conn) {
+               pr_err("struct iscsi_thread_set->conn is NULL for "
+                       " thread_id: %d, going back to sleep\n",
+                       ts->thread_id);
+               goto sleep;
+       }
+
+       iscsi_check_to_add_additional_sets();
+       /*
+        * From the TX thread, up the tx_post_start_comp that the RX Thread is
+        * sleeping on in iscsi_rx_thread_pre_handler(), then up the
+        * rx_post_start_comp that iscsi_activate_thread_set() is sleeping on.
+        */
+       ts->thread_clear |= ISCSI_CLEAR_TX_THREAD;
+       complete(&ts->tx_post_start_comp);
+       complete(&ts->rx_post_start_comp);
+
+       spin_lock_bh(&ts->ts_state_lock);
+       ts->status = ISCSI_THREAD_SET_ACTIVE;
+       spin_unlock_bh(&ts->ts_state_lock);
+
+       return ts->conn;
+}
+
+int iscsi_thread_set_init(void)
+{
+       int size;
+
+       iscsit_global->ts_bitmap_count = ISCSI_TS_BITMAP_BITS;
+
+       size = BITS_TO_LONGS(iscsit_global->ts_bitmap_count) * sizeof(long);
+       iscsit_global->ts_bitmap = kzalloc(size, GFP_KERNEL);
+       if (!iscsit_global->ts_bitmap) {
+               pr_err("Unable to allocate iscsit_global->ts_bitmap\n");
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&active_ts_lock);
+       spin_lock_init(&inactive_ts_lock);
+       spin_lock_init(&ts_bitmap_lock);
+       INIT_LIST_HEAD(&active_ts_list);
+       INIT_LIST_HEAD(&inactive_ts_list);
+
+       return 0;
+}
+
+void iscsi_thread_set_free(void)
+{
+       kfree(iscsit_global->ts_bitmap);
+}
diff --git a/drivers/target/iscsi/iscsi_target_tq.h b/drivers/target/iscsi/iscsi_target_tq.h
new file mode 100644 (file)
index 0000000..26e6a95
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef ISCSI_THREAD_QUEUE_H
+#define ISCSI_THREAD_QUEUE_H
+
+/*
+ * Defines for thread sets.
+ */
+extern int iscsi_thread_set_force_reinstatement(struct iscsi_conn *);
+extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *);
+extern int iscsi_allocate_thread_sets(u32);
+extern void iscsi_deallocate_thread_sets(void);
+extern void iscsi_activate_thread_set(struct iscsi_conn *, struct iscsi_thread_set *);
+extern struct iscsi_thread_set *iscsi_get_thread_set(void);
+extern void iscsi_set_thread_clear(struct iscsi_conn *, u8);
+extern void iscsi_set_thread_set_signal(struct iscsi_conn *, u8);
+extern int iscsi_release_thread_set(struct iscsi_conn *);
+extern struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *);
+extern struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *);
+extern int iscsi_thread_set_init(void);
+extern void iscsi_thread_set_free(void);
+
+extern int iscsi_target_tx_thread(void *);
+extern int iscsi_target_rx_thread(void *);
+
+#define TARGET_THREAD_SET_COUNT                        4
+
+#define ISCSI_RX_THREAD                         1
+#define ISCSI_TX_THREAD                         2
+#define ISCSI_RX_THREAD_NAME                   "iscsi_trx"
+#define ISCSI_TX_THREAD_NAME                   "iscsi_ttx"
+#define ISCSI_BLOCK_RX_THREAD                  0x1
+#define ISCSI_BLOCK_TX_THREAD                  0x2
+#define ISCSI_CLEAR_RX_THREAD                  0x1
+#define ISCSI_CLEAR_TX_THREAD                  0x2
+#define ISCSI_SIGNAL_RX_THREAD                 0x1
+#define ISCSI_SIGNAL_TX_THREAD                 0x2
+
+/* struct iscsi_thread_set->status */
+#define ISCSI_THREAD_SET_FREE                  1
+#define ISCSI_THREAD_SET_ACTIVE                        2
+#define ISCSI_THREAD_SET_DIE                   3
+#define ISCSI_THREAD_SET_RESET                 4
+#define ISCSI_THREAD_SET_DEALLOCATE_THREADS    5
+
+/* By default allow a maximum of 32K iSCSI connections */
+#define ISCSI_TS_BITMAP_BITS                   32768
+
+struct iscsi_thread_set {
+       /* flags used for blocking and restarting sets */
+       int     blocked_threads;
+       /* flag for creating threads */
+       int     create_threads;
+       /* flag for delaying readding to inactive list */
+       int     delay_inactive;
+       /* status for thread set */
+       int     status;
+       /* which threads have had signals sent */
+       int     signal_sent;
+       /* flag for which threads exited first */
+       int     thread_clear;
+       /* Active threads in the thread set */
+       int     thread_count;
+       /* Unique thread ID */
+       u32     thread_id;
+       /* pointer to connection if set is active */
+       struct iscsi_conn       *conn;
+       /* used for controlling ts state accesses */
+       spinlock_t      ts_state_lock;
+       /* Used for rx side post startup */
+       struct completion       rx_post_start_comp;
+       /* Used for tx side post startup */
+       struct completion       tx_post_start_comp;
+       /* used for restarting thread queue */
+       struct completion       rx_restart_comp;
+       /* used for restarting thread queue */
+       struct completion       tx_restart_comp;
+       /* used for normal unused blocking */
+       struct completion       rx_start_comp;
+       /* used for normal unused blocking */
+       struct completion       tx_start_comp;
+       /* OS descriptor for rx thread */
+       struct task_struct      *rx_thread;
+       /* OS descriptor for tx thread */
+       struct task_struct      *tx_thread;
+       /* struct iscsi_thread_set in list list head*/
+       struct list_head        ts_list;
+};
+
+#endif   /*** ISCSI_THREAD_QUEUE_H ***/
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
new file mode 100644 (file)
index 0000000..a1acb01
--- /dev/null
@@ -0,0 +1,1819 @@
+/*******************************************************************************
+ * This file contains the iSCSI Target specific utility functions.
+ *
+ * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Author: Nicholas A. Bellinger <nab@linux-iscsi.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.
+ ******************************************************************************/
+
+#include <linux/list.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/iscsi_proto.h>
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_tmr.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "iscsi_target_core.h"
+#include "iscsi_target_parameters.h"
+#include "iscsi_target_seq_pdu_list.h"
+#include "iscsi_target_datain_values.h"
+#include "iscsi_target_erl0.h"
+#include "iscsi_target_erl1.h"
+#include "iscsi_target_erl2.h"
+#include "iscsi_target_tpg.h"
+#include "iscsi_target_tq.h"
+#include "iscsi_target_util.h"
+#include "iscsi_target.h"
+
+#define PRINT_BUFF(buff, len)                                  \
+{                                                              \
+       int zzz;                                                \
+                                                               \
+       pr_debug("%d:\n", __LINE__);                            \
+       for (zzz = 0; zzz < len; zzz++) {                       \
+               if (zzz % 16 == 0) {                            \
+                       if (zzz)                                \
+                               pr_debug("\n");                 \
+                       pr_debug("%4i: ", zzz);                 \
+               }                                               \
+               pr_debug("%02x ", (unsigned char) (buff)[zzz]); \
+       }                                                       \
+       if ((len + 1) % 16)                                     \
+               pr_debug("\n");                                 \
+}
+
+extern struct list_head g_tiqn_list;
+extern spinlock_t tiqn_lock;
+
+/*
+ *     Called with cmd->r2t_lock held.
+ */
+int iscsit_add_r2t_to_list(
+       struct iscsi_cmd *cmd,
+       u32 offset,
+       u32 xfer_len,
+       int recovery,
+       u32 r2t_sn)
+{
+       struct iscsi_r2t *r2t;
+
+       r2t = kmem_cache_zalloc(lio_r2t_cache, GFP_ATOMIC);
+       if (!r2t) {
+               pr_err("Unable to allocate memory for struct iscsi_r2t.\n");
+               return -1;
+       }
+       INIT_LIST_HEAD(&r2t->r2t_list);
+
+       r2t->recovery_r2t = recovery;
+       r2t->r2t_sn = (!r2t_sn) ? cmd->r2t_sn++ : r2t_sn;
+       r2t->offset = offset;
+       r2t->xfer_len = xfer_len;
+       list_add_tail(&r2t->r2t_list, &cmd->cmd_r2t_list);
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, ISTATE_SEND_R2T);
+
+       spin_lock_bh(&cmd->r2t_lock);
+       return 0;
+}
+
+struct iscsi_r2t *iscsit_get_r2t_for_eos(
+       struct iscsi_cmd *cmd,
+       u32 offset,
+       u32 length)
+{
+       struct iscsi_r2t *r2t;
+
+       spin_lock_bh(&cmd->r2t_lock);
+       list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) {
+               if ((r2t->offset <= offset) &&
+                   (r2t->offset + r2t->xfer_len) >= (offset + length)) {
+                       spin_unlock_bh(&cmd->r2t_lock);
+                       return r2t;
+               }
+       }
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       pr_err("Unable to locate R2T for Offset: %u, Length:"
+                       " %u\n", offset, length);
+       return NULL;
+}
+
+struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *cmd)
+{
+       struct iscsi_r2t *r2t;
+
+       spin_lock_bh(&cmd->r2t_lock);
+       list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) {
+               if (!r2t->sent_r2t) {
+                       spin_unlock_bh(&cmd->r2t_lock);
+                       return r2t;
+               }
+       }
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       pr_err("Unable to locate next R2T to send for ITT:"
+                       " 0x%08x.\n", cmd->init_task_tag);
+       return NULL;
+}
+
+/*
+ *     Called with cmd->r2t_lock held.
+ */
+void iscsit_free_r2t(struct iscsi_r2t *r2t, struct iscsi_cmd *cmd)
+{
+       list_del(&r2t->r2t_list);
+       kmem_cache_free(lio_r2t_cache, r2t);
+}
+
+void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
+{
+       struct iscsi_r2t *r2t, *r2t_tmp;
+
+       spin_lock_bh(&cmd->r2t_lock);
+       list_for_each_entry_safe(r2t, r2t_tmp, &cmd->cmd_r2t_list, r2t_list)
+               iscsit_free_r2t(r2t, cmd);
+       spin_unlock_bh(&cmd->r2t_lock);
+}
+
+/*
+ * May be called from software interrupt (timer) context for allocating
+ * iSCSI NopINs.
+ */
+struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
+{
+       struct iscsi_cmd *cmd;
+
+       cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
+       if (!cmd) {
+               pr_err("Unable to allocate memory for struct iscsi_cmd.\n");
+               return NULL;
+       }
+
+       cmd->conn       = conn;
+       INIT_LIST_HEAD(&cmd->i_list);
+       INIT_LIST_HEAD(&cmd->datain_list);
+       INIT_LIST_HEAD(&cmd->cmd_r2t_list);
+       init_completion(&cmd->reject_comp);
+       spin_lock_init(&cmd->datain_lock);
+       spin_lock_init(&cmd->dataout_timeout_lock);
+       spin_lock_init(&cmd->istate_lock);
+       spin_lock_init(&cmd->error_lock);
+       spin_lock_init(&cmd->r2t_lock);
+
+       return cmd;
+}
+
+/*
+ * Called from iscsi_handle_scsi_cmd()
+ */
+struct iscsi_cmd *iscsit_allocate_se_cmd(
+       struct iscsi_conn *conn,
+       u32 data_length,
+       int data_direction,
+       int iscsi_task_attr)
+{
+       struct iscsi_cmd *cmd;
+       struct se_cmd *se_cmd;
+       int sam_task_attr;
+
+       cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+       if (!cmd)
+               return NULL;
+
+       cmd->data_direction = data_direction;
+       cmd->data_length = data_length;
+       /*
+        * Figure out the SAM Task Attribute for the incoming SCSI CDB
+        */
+       if ((iscsi_task_attr == ISCSI_ATTR_UNTAGGED) ||
+           (iscsi_task_attr == ISCSI_ATTR_SIMPLE))
+               sam_task_attr = MSG_SIMPLE_TAG;
+       else if (iscsi_task_attr == ISCSI_ATTR_ORDERED)
+               sam_task_attr = MSG_ORDERED_TAG;
+       else if (iscsi_task_attr == ISCSI_ATTR_HEAD_OF_QUEUE)
+               sam_task_attr = MSG_HEAD_TAG;
+       else if (iscsi_task_attr == ISCSI_ATTR_ACA)
+               sam_task_attr = MSG_ACA_TAG;
+       else {
+               pr_debug("Unknown iSCSI Task Attribute: 0x%02x, using"
+                       " MSG_SIMPLE_TAG\n", iscsi_task_attr);
+               sam_task_attr = MSG_SIMPLE_TAG;
+       }
+
+       se_cmd = &cmd->se_cmd;
+       /*
+        * Initialize struct se_cmd descriptor from target_core_mod infrastructure
+        */
+       transport_init_se_cmd(se_cmd, &lio_target_fabric_configfs->tf_ops,
+                       conn->sess->se_sess, data_length, data_direction,
+                       sam_task_attr, &cmd->sense_buffer[0]);
+       return cmd;
+}
+
+struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(
+       struct iscsi_conn *conn,
+       u8 function)
+{
+       struct iscsi_cmd *cmd;
+       struct se_cmd *se_cmd;
+       u8 tcm_function;
+
+       cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+       if (!cmd)
+               return NULL;
+
+       cmd->data_direction = DMA_NONE;
+
+       cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL);
+       if (!cmd->tmr_req) {
+               pr_err("Unable to allocate memory for"
+                       " Task Management command!\n");
+               return NULL;
+       }
+       /*
+        * TASK_REASSIGN for ERL=2 / connection stays inside of
+        * LIO-Target $FABRIC_MOD
+        */
+       if (function == ISCSI_TM_FUNC_TASK_REASSIGN)
+               return cmd;
+
+       se_cmd = &cmd->se_cmd;
+       /*
+        * Initialize struct se_cmd descriptor from target_core_mod infrastructure
+        */
+       transport_init_se_cmd(se_cmd, &lio_target_fabric_configfs->tf_ops,
+                               conn->sess->se_sess, 0, DMA_NONE,
+                               MSG_SIMPLE_TAG, &cmd->sense_buffer[0]);
+
+       switch (function) {
+       case ISCSI_TM_FUNC_ABORT_TASK:
+               tcm_function = TMR_ABORT_TASK;
+               break;
+       case ISCSI_TM_FUNC_ABORT_TASK_SET:
+               tcm_function = TMR_ABORT_TASK_SET;
+               break;
+       case ISCSI_TM_FUNC_CLEAR_ACA:
+               tcm_function = TMR_CLEAR_ACA;
+               break;
+       case ISCSI_TM_FUNC_CLEAR_TASK_SET:
+               tcm_function = TMR_CLEAR_TASK_SET;
+               break;
+       case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
+               tcm_function = TMR_LUN_RESET;
+               break;
+       case ISCSI_TM_FUNC_TARGET_WARM_RESET:
+               tcm_function = TMR_TARGET_WARM_RESET;
+               break;
+       case ISCSI_TM_FUNC_TARGET_COLD_RESET:
+               tcm_function = TMR_TARGET_COLD_RESET;
+               break;
+       default:
+               pr_err("Unknown iSCSI TMR Function:"
+                       " 0x%02x\n", function);
+               goto out;
+       }
+
+       se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd,
+                               (void *)cmd->tmr_req, tcm_function);
+       if (!se_cmd->se_tmr_req)
+               goto out;
+
+       cmd->tmr_req->se_tmr_req = se_cmd->se_tmr_req;
+
+       return cmd;
+out:
+       iscsit_release_cmd(cmd);
+       if (se_cmd)
+               transport_free_se_cmd(se_cmd);
+       return NULL;
+}
+
+int iscsit_decide_list_to_build(
+       struct iscsi_cmd *cmd,
+       u32 immediate_data_length)
+{
+       struct iscsi_build_list bl;
+       struct iscsi_conn *conn = cmd->conn;
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_node_attrib *na;
+
+       if (sess->sess_ops->DataSequenceInOrder &&
+           sess->sess_ops->DataPDUInOrder)
+               return 0;
+
+       if (cmd->data_direction == DMA_NONE)
+               return 0;
+
+       na = iscsit_tpg_get_node_attrib(sess);
+       memset(&bl, 0, sizeof(struct iscsi_build_list));
+
+       if (cmd->data_direction == DMA_FROM_DEVICE) {
+               bl.data_direction = ISCSI_PDU_READ;
+               bl.type = PDULIST_NORMAL;
+               if (na->random_datain_pdu_offsets)
+                       bl.randomize |= RANDOM_DATAIN_PDU_OFFSETS;
+               if (na->random_datain_seq_offsets)
+                       bl.randomize |= RANDOM_DATAIN_SEQ_OFFSETS;
+       } else {
+               bl.data_direction = ISCSI_PDU_WRITE;
+               bl.immediate_data_length = immediate_data_length;
+               if (na->random_r2t_offsets)
+                       bl.randomize |= RANDOM_R2T_OFFSETS;
+
+               if (!cmd->immediate_data && !cmd->unsolicited_data)
+                       bl.type = PDULIST_NORMAL;
+               else if (cmd->immediate_data && !cmd->unsolicited_data)
+                       bl.type = PDULIST_IMMEDIATE;
+               else if (!cmd->immediate_data && cmd->unsolicited_data)
+                       bl.type = PDULIST_UNSOLICITED;
+               else if (cmd->immediate_data && cmd->unsolicited_data)
+                       bl.type = PDULIST_IMMEDIATE_AND_UNSOLICITED;
+       }
+
+       return iscsit_do_build_list(cmd, &bl);
+}
+
+struct iscsi_seq *iscsit_get_seq_holder_for_datain(
+       struct iscsi_cmd *cmd,
+       u32 seq_send_order)
+{
+       u32 i;
+
+       for (i = 0; i < cmd->seq_count; i++)
+               if (cmd->seq_list[i].seq_send_order == seq_send_order)
+                       return &cmd->seq_list[i];
+
+       return NULL;
+}
+
+struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *cmd)
+{
+       u32 i;
+
+       if (!cmd->seq_list) {
+               pr_err("struct iscsi_cmd->seq_list is NULL!\n");
+               return NULL;
+       }
+
+       for (i = 0; i < cmd->seq_count; i++) {
+               if (cmd->seq_list[i].type != SEQTYPE_NORMAL)
+                       continue;
+               if (cmd->seq_list[i].seq_send_order == cmd->seq_send_order) {
+                       cmd->seq_send_order++;
+                       return &cmd->seq_list[i];
+               }
+       }
+
+       return NULL;
+}
+
+struct iscsi_r2t *iscsit_get_holder_for_r2tsn(
+       struct iscsi_cmd *cmd,
+       u32 r2t_sn)
+{
+       struct iscsi_r2t *r2t;
+
+       spin_lock_bh(&cmd->r2t_lock);
+       list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) {
+               if (r2t->r2t_sn == r2t_sn) {
+                       spin_unlock_bh(&cmd->r2t_lock);
+                       return r2t;
+               }
+       }
+       spin_unlock_bh(&cmd->r2t_lock);
+
+       return NULL;
+}
+
+static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cmdsn)
+{
+       int ret;
+
+       /*
+        * This is the proper method of checking received CmdSN against
+        * ExpCmdSN and MaxCmdSN values, as well as accounting for out
+        * or order CmdSNs due to multiple connection sessions and/or
+        * CRC failures.
+        */
+       if (iscsi_sna_gt(cmdsn, sess->max_cmd_sn)) {
+               pr_err("Received CmdSN: 0x%08x is greater than"
+                      " MaxCmdSN: 0x%08x, protocol error.\n", cmdsn,
+                      sess->max_cmd_sn);
+               ret = CMDSN_ERROR_CANNOT_RECOVER;
+
+       } else if (cmdsn == sess->exp_cmd_sn) {
+               sess->exp_cmd_sn++;
+               pr_debug("Received CmdSN matches ExpCmdSN,"
+                     " incremented ExpCmdSN to: 0x%08x\n",
+                     sess->exp_cmd_sn);
+               ret = CMDSN_NORMAL_OPERATION;
+
+       } else if (iscsi_sna_gt(cmdsn, sess->exp_cmd_sn)) {
+               pr_debug("Received CmdSN: 0x%08x is greater"
+                     " than ExpCmdSN: 0x%08x, not acknowledging.\n",
+                     cmdsn, sess->exp_cmd_sn);
+               ret = CMDSN_HIGHER_THAN_EXP;
+
+       } else {
+               pr_err("Received CmdSN: 0x%08x is less than"
+                      " ExpCmdSN: 0x%08x, ignoring.\n", cmdsn,
+                      sess->exp_cmd_sn);
+               ret = CMDSN_LOWER_THAN_EXP;
+       }
+
+       return ret;
+}
+
+/*
+ * Commands may be received out of order if MC/S is in use.
+ * Ensure they are executed in CmdSN order.
+ */
+int iscsit_sequence_cmd(
+       struct iscsi_conn *conn,
+       struct iscsi_cmd *cmd,
+       u32 cmdsn)
+{
+       int ret;
+       int cmdsn_ret;
+
+       mutex_lock(&conn->sess->cmdsn_mutex);
+
+       cmdsn_ret = iscsit_check_received_cmdsn(conn->sess, cmdsn);
+       switch (cmdsn_ret) {
+       case CMDSN_NORMAL_OPERATION:
+               ret = iscsit_execute_cmd(cmd, 0);
+               if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list))
+                       iscsit_execute_ooo_cmdsns(conn->sess);
+               break;
+       case CMDSN_HIGHER_THAN_EXP:
+               ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, cmdsn);
+               break;
+       case CMDSN_LOWER_THAN_EXP:
+               cmd->i_state = ISTATE_REMOVE;
+               iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
+               ret = cmdsn_ret;
+               break;
+       default:
+               ret = cmdsn_ret;
+               break;
+       }
+       mutex_unlock(&conn->sess->cmdsn_mutex);
+
+       return ret;
+}
+
+int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf)
+{
+       struct iscsi_conn *conn = cmd->conn;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct iscsi_data *hdr = (struct iscsi_data *) buf;
+       u32 payload_length = ntoh24(hdr->dlength);
+
+       if (conn->sess->sess_ops->InitialR2T) {
+               pr_err("Received unexpected unsolicited data"
+                       " while InitialR2T=Yes, protocol error.\n");
+               transport_send_check_condition_and_sense(se_cmd,
+                               TCM_UNEXPECTED_UNSOLICITED_DATA, 0);
+               return -1;
+       }
+
+       if ((cmd->first_burst_len + payload_length) >
+            conn->sess->sess_ops->FirstBurstLength) {
+               pr_err("Total %u bytes exceeds FirstBurstLength: %u"
+                       " for this Unsolicited DataOut Burst.\n",
+                       (cmd->first_burst_len + payload_length),
+                               conn->sess->sess_ops->FirstBurstLength);
+               transport_send_check_condition_and_sense(se_cmd,
+                               TCM_INCORRECT_AMOUNT_OF_DATA, 0);
+               return -1;
+       }
+
+       if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL))
+               return 0;
+
+       if (((cmd->first_burst_len + payload_length) != cmd->data_length) &&
+           ((cmd->first_burst_len + payload_length) !=
+             conn->sess->sess_ops->FirstBurstLength)) {
+               pr_err("Unsolicited non-immediate data received %u"
+                       " does not equal FirstBurstLength: %u, and does"
+                       " not equal ExpXferLen %u.\n",
+                       (cmd->first_burst_len + payload_length),
+                       conn->sess->sess_ops->FirstBurstLength, cmd->data_length);
+               transport_send_check_condition_and_sense(se_cmd,
+                               TCM_INCORRECT_AMOUNT_OF_DATA, 0);
+               return -1;
+       }
+       return 0;
+}
+
+struct iscsi_cmd *iscsit_find_cmd_from_itt(
+       struct iscsi_conn *conn,
+       u32 init_task_tag)
+{
+       struct iscsi_cmd *cmd;
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+               if (cmd->init_task_tag == init_task_tag) {
+                       spin_unlock_bh(&conn->cmd_lock);
+                       return cmd;
+               }
+       }
+       spin_unlock_bh(&conn->cmd_lock);
+
+       pr_err("Unable to locate ITT: 0x%08x on CID: %hu",
+                       init_task_tag, conn->cid);
+       return NULL;
+}
+
+struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(
+       struct iscsi_conn *conn,
+       u32 init_task_tag,
+       u32 length)
+{
+       struct iscsi_cmd *cmd;
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+               if (cmd->init_task_tag == init_task_tag) {
+                       spin_unlock_bh(&conn->cmd_lock);
+                       return cmd;
+               }
+       }
+       spin_unlock_bh(&conn->cmd_lock);
+
+       pr_err("Unable to locate ITT: 0x%08x on CID: %hu,"
+                       " dumping payload\n", init_task_tag, conn->cid);
+       if (length)
+               iscsit_dump_data_payload(conn, length, 1);
+
+       return NULL;
+}
+
+struct iscsi_cmd *iscsit_find_cmd_from_ttt(
+       struct iscsi_conn *conn,
+       u32 targ_xfer_tag)
+{
+       struct iscsi_cmd *cmd = NULL;
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) {
+               if (cmd->targ_xfer_tag == targ_xfer_tag) {
+                       spin_unlock_bh(&conn->cmd_lock);
+                       return cmd;
+               }
+       }
+       spin_unlock_bh(&conn->cmd_lock);
+
+       pr_err("Unable to locate TTT: 0x%08x on CID: %hu\n",
+                       targ_xfer_tag, conn->cid);
+       return NULL;
+}
+
+int iscsit_find_cmd_for_recovery(
+       struct iscsi_session *sess,
+       struct iscsi_cmd **cmd_ptr,
+       struct iscsi_conn_recovery **cr_ptr,
+       u32 init_task_tag)
+{
+       struct iscsi_cmd *cmd = NULL;
+       struct iscsi_conn_recovery *cr;
+       /*
+        * Scan through the inactive connection recovery list's command list.
+        * If init_task_tag matches the command is still alligent.
+        */
+       spin_lock(&sess->cr_i_lock);
+       list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) {
+               spin_lock(&cr->conn_recovery_cmd_lock);
+               list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_list) {
+                       if (cmd->init_task_tag == init_task_tag) {
+                               spin_unlock(&cr->conn_recovery_cmd_lock);
+                               spin_unlock(&sess->cr_i_lock);
+
+                               *cr_ptr = cr;
+                               *cmd_ptr = cmd;
+                               return -2;
+                       }
+               }
+               spin_unlock(&cr->conn_recovery_cmd_lock);
+       }
+       spin_unlock(&sess->cr_i_lock);
+       /*
+        * Scan through the active connection recovery list's command list.
+        * If init_task_tag matches the command is ready to be reassigned.
+        */
+       spin_lock(&sess->cr_a_lock);
+       list_for_each_entry(cr, &sess->cr_active_list, cr_list) {
+               spin_lock(&cr->conn_recovery_cmd_lock);
+               list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_list) {
+                       if (cmd->init_task_tag == init_task_tag) {
+                               spin_unlock(&cr->conn_recovery_cmd_lock);
+                               spin_unlock(&sess->cr_a_lock);
+
+                               *cr_ptr = cr;
+                               *cmd_ptr = cmd;
+                               return 0;
+                       }
+               }
+               spin_unlock(&cr->conn_recovery_cmd_lock);
+       }
+       spin_unlock(&sess->cr_a_lock);
+
+       return -1;
+}
+
+void iscsit_add_cmd_to_immediate_queue(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn,
+       u8 state)
+{
+       struct iscsi_queue_req *qr;
+
+       qr = kmem_cache_zalloc(lio_qr_cache, GFP_ATOMIC);
+       if (!qr) {
+               pr_err("Unable to allocate memory for"
+                               " struct iscsi_queue_req\n");
+               return;
+       }
+       INIT_LIST_HEAD(&qr->qr_list);
+       qr->cmd = cmd;
+       qr->state = state;
+
+       spin_lock_bh(&conn->immed_queue_lock);
+       list_add_tail(&qr->qr_list, &conn->immed_queue_list);
+       atomic_inc(&cmd->immed_queue_count);
+       atomic_set(&conn->check_immediate_queue, 1);
+       spin_unlock_bh(&conn->immed_queue_lock);
+
+       wake_up_process(conn->thread_set->tx_thread);
+}
+
+struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn)
+{
+       struct iscsi_queue_req *qr;
+
+       spin_lock_bh(&conn->immed_queue_lock);
+       if (list_empty(&conn->immed_queue_list)) {
+               spin_unlock_bh(&conn->immed_queue_lock);
+               return NULL;
+       }
+       list_for_each_entry(qr, &conn->immed_queue_list, qr_list)
+               break;
+
+       list_del(&qr->qr_list);
+       if (qr->cmd)
+               atomic_dec(&qr->cmd->immed_queue_count);
+       spin_unlock_bh(&conn->immed_queue_lock);
+
+       return qr;
+}
+
+static void iscsit_remove_cmd_from_immediate_queue(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       struct iscsi_queue_req *qr, *qr_tmp;
+
+       spin_lock_bh(&conn->immed_queue_lock);
+       if (!atomic_read(&cmd->immed_queue_count)) {
+               spin_unlock_bh(&conn->immed_queue_lock);
+               return;
+       }
+
+       list_for_each_entry_safe(qr, qr_tmp, &conn->immed_queue_list, qr_list) {
+               if (qr->cmd != cmd)
+                       continue;
+
+               atomic_dec(&qr->cmd->immed_queue_count);
+               list_del(&qr->qr_list);
+               kmem_cache_free(lio_qr_cache, qr);
+       }
+       spin_unlock_bh(&conn->immed_queue_lock);
+
+       if (atomic_read(&cmd->immed_queue_count)) {
+               pr_err("ITT: 0x%08x immed_queue_count: %d\n",
+                       cmd->init_task_tag,
+                       atomic_read(&cmd->immed_queue_count));
+       }
+}
+
+void iscsit_add_cmd_to_response_queue(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn,
+       u8 state)
+{
+       struct iscsi_queue_req *qr;
+
+       qr = kmem_cache_zalloc(lio_qr_cache, GFP_ATOMIC);
+       if (!qr) {
+               pr_err("Unable to allocate memory for"
+                       " struct iscsi_queue_req\n");
+               return;
+       }
+       INIT_LIST_HEAD(&qr->qr_list);
+       qr->cmd = cmd;
+       qr->state = state;
+
+       spin_lock_bh(&conn->response_queue_lock);
+       list_add_tail(&qr->qr_list, &conn->response_queue_list);
+       atomic_inc(&cmd->response_queue_count);
+       spin_unlock_bh(&conn->response_queue_lock);
+
+       wake_up_process(conn->thread_set->tx_thread);
+}
+
+struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn)
+{
+       struct iscsi_queue_req *qr;
+
+       spin_lock_bh(&conn->response_queue_lock);
+       if (list_empty(&conn->response_queue_list)) {
+               spin_unlock_bh(&conn->response_queue_lock);
+               return NULL;
+       }
+
+       list_for_each_entry(qr, &conn->response_queue_list, qr_list)
+               break;
+
+       list_del(&qr->qr_list);
+       if (qr->cmd)
+               atomic_dec(&qr->cmd->response_queue_count);
+       spin_unlock_bh(&conn->response_queue_lock);
+
+       return qr;
+}
+
+static void iscsit_remove_cmd_from_response_queue(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       struct iscsi_queue_req *qr, *qr_tmp;
+
+       spin_lock_bh(&conn->response_queue_lock);
+       if (!atomic_read(&cmd->response_queue_count)) {
+               spin_unlock_bh(&conn->response_queue_lock);
+               return;
+       }
+
+       list_for_each_entry_safe(qr, qr_tmp, &conn->response_queue_list,
+                               qr_list) {
+               if (qr->cmd != cmd)
+                       continue;
+
+               atomic_dec(&qr->cmd->response_queue_count);
+               list_del(&qr->qr_list);
+               kmem_cache_free(lio_qr_cache, qr);
+       }
+       spin_unlock_bh(&conn->response_queue_lock);
+
+       if (atomic_read(&cmd->response_queue_count)) {
+               pr_err("ITT: 0x%08x response_queue_count: %d\n",
+                       cmd->init_task_tag,
+                       atomic_read(&cmd->response_queue_count));
+       }
+}
+
+void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
+{
+       struct iscsi_queue_req *qr, *qr_tmp;
+
+       spin_lock_bh(&conn->immed_queue_lock);
+       list_for_each_entry_safe(qr, qr_tmp, &conn->immed_queue_list, qr_list) {
+               list_del(&qr->qr_list);
+               if (qr->cmd)
+                       atomic_dec(&qr->cmd->immed_queue_count);
+
+               kmem_cache_free(lio_qr_cache, qr);
+       }
+       spin_unlock_bh(&conn->immed_queue_lock);
+
+       spin_lock_bh(&conn->response_queue_lock);
+       list_for_each_entry_safe(qr, qr_tmp, &conn->response_queue_list,
+                       qr_list) {
+               list_del(&qr->qr_list);
+               if (qr->cmd)
+                       atomic_dec(&qr->cmd->response_queue_count);
+
+               kmem_cache_free(lio_qr_cache, qr);
+       }
+       spin_unlock_bh(&conn->response_queue_lock);
+}
+
+void iscsit_release_cmd(struct iscsi_cmd *cmd)
+{
+       struct iscsi_conn *conn = cmd->conn;
+       int i;
+
+       iscsit_free_r2ts_from_list(cmd);
+       iscsit_free_all_datain_reqs(cmd);
+
+       kfree(cmd->buf_ptr);
+       kfree(cmd->pdu_list);
+       kfree(cmd->seq_list);
+       kfree(cmd->tmr_req);
+       kfree(cmd->iov_data);
+
+       for (i = 0; i < cmd->t_mem_sg_nents; i++)
+               __free_page(sg_page(&cmd->t_mem_sg[i]));
+
+       kfree(cmd->t_mem_sg);
+
+       if (conn) {
+               iscsit_remove_cmd_from_immediate_queue(cmd, conn);
+               iscsit_remove_cmd_from_response_queue(cmd, conn);
+       }
+
+       kmem_cache_free(lio_cmd_cache, cmd);
+}
+
+int iscsit_check_session_usage_count(struct iscsi_session *sess)
+{
+       spin_lock_bh(&sess->session_usage_lock);
+       if (sess->session_usage_count != 0) {
+               sess->session_waiting_on_uc = 1;
+               spin_unlock_bh(&sess->session_usage_lock);
+               if (in_interrupt())
+                       return 2;
+
+               wait_for_completion(&sess->session_waiting_on_uc_comp);
+               return 1;
+       }
+       spin_unlock_bh(&sess->session_usage_lock);
+
+       return 0;
+}
+
+void iscsit_dec_session_usage_count(struct iscsi_session *sess)
+{
+       spin_lock_bh(&sess->session_usage_lock);
+       sess->session_usage_count--;
+
+       if (!sess->session_usage_count && sess->session_waiting_on_uc)
+               complete(&sess->session_waiting_on_uc_comp);
+
+       spin_unlock_bh(&sess->session_usage_lock);
+}
+
+void iscsit_inc_session_usage_count(struct iscsi_session *sess)
+{
+       spin_lock_bh(&sess->session_usage_lock);
+       sess->session_usage_count++;
+       spin_unlock_bh(&sess->session_usage_lock);
+}
+
+/*
+ *     Used before iscsi_do[rx,tx]_data() to determine iov and [rx,tx]_marker
+ *     array counts needed for sync and steering.
+ */
+static int iscsit_determine_sync_and_steering_counts(
+       struct iscsi_conn *conn,
+       struct iscsi_data_count *count)
+{
+       u32 length = count->data_length;
+       u32 marker, markint;
+
+       count->sync_and_steering = 1;
+
+       marker = (count->type == ISCSI_RX_DATA) ?
+                       conn->of_marker : conn->if_marker;
+       markint = (count->type == ISCSI_RX_DATA) ?
+                       (conn->conn_ops->OFMarkInt * 4) :
+                       (conn->conn_ops->IFMarkInt * 4);
+       count->ss_iov_count = count->iov_count;
+
+       while (length > 0) {
+               if (length >= marker) {
+                       count->ss_iov_count += 3;
+                       count->ss_marker_count += 2;
+
+                       length -= marker;
+                       marker = markint;
+               } else
+                       length = 0;
+       }
+
+       return 0;
+}
+
+/*
+ *     Setup conn->if_marker and conn->of_marker values based upon
+ *     the initial marker-less interval. (see iSCSI v19 A.2)
+ */
+int iscsit_set_sync_and_steering_values(struct iscsi_conn *conn)
+{
+       int login_ifmarker_count = 0, login_ofmarker_count = 0, next_marker = 0;
+       /*
+        * IFMarkInt and OFMarkInt are negotiated as 32-bit words.
+        */
+       u32 IFMarkInt = (conn->conn_ops->IFMarkInt * 4);
+       u32 OFMarkInt = (conn->conn_ops->OFMarkInt * 4);
+
+       if (conn->conn_ops->OFMarker) {
+               /*
+                * Account for the first Login Command received not
+                * via iscsi_recv_msg().
+                */
+               conn->of_marker += ISCSI_HDR_LEN;
+               if (conn->of_marker <= OFMarkInt) {
+                       conn->of_marker = (OFMarkInt - conn->of_marker);
+               } else {
+                       login_ofmarker_count = (conn->of_marker / OFMarkInt);
+                       next_marker = (OFMarkInt * (login_ofmarker_count + 1)) +
+                                       (login_ofmarker_count * MARKER_SIZE);
+                       conn->of_marker = (next_marker - conn->of_marker);
+               }
+               conn->of_marker_offset = 0;
+               pr_debug("Setting OFMarker value to %u based on Initial"
+                       " Markerless Interval.\n", conn->of_marker);
+       }
+
+       if (conn->conn_ops->IFMarker) {
+               if (conn->if_marker <= IFMarkInt) {
+                       conn->if_marker = (IFMarkInt - conn->if_marker);
+               } else {
+                       login_ifmarker_count = (conn->if_marker / IFMarkInt);
+                       next_marker = (IFMarkInt * (login_ifmarker_count + 1)) +
+                                       (login_ifmarker_count * MARKER_SIZE);
+                       conn->if_marker = (next_marker - conn->if_marker);
+               }
+               pr_debug("Setting IFMarker value to %u based on Initial"
+                       " Markerless Interval.\n", conn->if_marker);
+       }
+
+       return 0;
+}
+
+struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *sess, u16 cid)
+{
+       struct iscsi_conn *conn;
+
+       spin_lock_bh(&sess->conn_lock);
+       list_for_each_entry(conn, &sess->sess_conn_list, conn_list) {
+               if ((conn->cid == cid) &&
+                   (conn->conn_state == TARG_CONN_STATE_LOGGED_IN)) {
+                       iscsit_inc_conn_usage_count(conn);
+                       spin_unlock_bh(&sess->conn_lock);
+                       return conn;
+               }
+       }
+       spin_unlock_bh(&sess->conn_lock);
+
+       return NULL;
+}
+
+struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *sess, u16 cid)
+{
+       struct iscsi_conn *conn;
+
+       spin_lock_bh(&sess->conn_lock);
+       list_for_each_entry(conn, &sess->sess_conn_list, conn_list) {
+               if (conn->cid == cid) {
+                       iscsit_inc_conn_usage_count(conn);
+                       spin_lock(&conn->state_lock);
+                       atomic_set(&conn->connection_wait_rcfr, 1);
+                       spin_unlock(&conn->state_lock);
+                       spin_unlock_bh(&sess->conn_lock);
+                       return conn;
+               }
+       }
+       spin_unlock_bh(&sess->conn_lock);
+
+       return NULL;
+}
+
+void iscsit_check_conn_usage_count(struct iscsi_conn *conn)
+{
+       spin_lock_bh(&conn->conn_usage_lock);
+       if (conn->conn_usage_count != 0) {
+               conn->conn_waiting_on_uc = 1;
+               spin_unlock_bh(&conn->conn_usage_lock);
+
+               wait_for_completion(&conn->conn_waiting_on_uc_comp);
+               return;
+       }
+       spin_unlock_bh(&conn->conn_usage_lock);
+}
+
+void iscsit_dec_conn_usage_count(struct iscsi_conn *conn)
+{
+       spin_lock_bh(&conn->conn_usage_lock);
+       conn->conn_usage_count--;
+
+       if (!conn->conn_usage_count && conn->conn_waiting_on_uc)
+               complete(&conn->conn_waiting_on_uc_comp);
+
+       spin_unlock_bh(&conn->conn_usage_lock);
+}
+
+void iscsit_inc_conn_usage_count(struct iscsi_conn *conn)
+{
+       spin_lock_bh(&conn->conn_usage_lock);
+       conn->conn_usage_count++;
+       spin_unlock_bh(&conn->conn_usage_lock);
+}
+
+static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
+{
+       u8 state;
+       struct iscsi_cmd *cmd;
+
+       cmd = iscsit_allocate_cmd(conn, GFP_ATOMIC);
+       if (!cmd)
+               return -1;
+
+       cmd->iscsi_opcode = ISCSI_OP_NOOP_IN;
+       state = (want_response) ? ISTATE_SEND_NOPIN_WANT_RESPONSE :
+                               ISTATE_SEND_NOPIN_NO_RESPONSE;
+       cmd->init_task_tag = 0xFFFFFFFF;
+       spin_lock_bh(&conn->sess->ttt_lock);
+       cmd->targ_xfer_tag = (want_response) ? conn->sess->targ_xfer_tag++ :
+                       0xFFFFFFFF;
+       if (want_response && (cmd->targ_xfer_tag == 0xFFFFFFFF))
+               cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++;
+       spin_unlock_bh(&conn->sess->ttt_lock);
+
+       spin_lock_bh(&conn->cmd_lock);
+       list_add_tail(&cmd->i_list, &conn->conn_cmd_list);
+       spin_unlock_bh(&conn->cmd_lock);
+
+       if (want_response)
+               iscsit_start_nopin_response_timer(conn);
+       iscsit_add_cmd_to_immediate_queue(cmd, conn, state);
+
+       return 0;
+}
+
+static void iscsit_handle_nopin_response_timeout(unsigned long data)
+{
+       struct iscsi_conn *conn = (struct iscsi_conn *) data;
+
+       iscsit_inc_conn_usage_count(conn);
+
+       spin_lock_bh(&conn->nopin_timer_lock);
+       if (conn->nopin_response_timer_flags & ISCSI_TF_STOP) {
+               spin_unlock_bh(&conn->nopin_timer_lock);
+               iscsit_dec_conn_usage_count(conn);
+               return;
+       }
+
+       pr_debug("Did not receive response to NOPIN on CID: %hu on"
+               " SID: %u, failing connection.\n", conn->cid,
+                       conn->sess->sid);
+       conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING;
+       spin_unlock_bh(&conn->nopin_timer_lock);
+
+       {
+       struct iscsi_portal_group *tpg = conn->sess->tpg;
+       struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
+
+       if (tiqn) {
+               spin_lock_bh(&tiqn->sess_err_stats.lock);
+               strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name,
+                               (void *)conn->sess->sess_ops->InitiatorName);
+               tiqn->sess_err_stats.last_sess_failure_type =
+                               ISCSI_SESS_ERR_CXN_TIMEOUT;
+               tiqn->sess_err_stats.cxn_timeout_errors++;
+               conn->sess->conn_timeout_errors++;
+               spin_unlock_bh(&tiqn->sess_err_stats.lock);
+       }
+       }
+
+       iscsit_cause_connection_reinstatement(conn, 0);
+       iscsit_dec_conn_usage_count(conn);
+}
+
+void iscsit_mod_nopin_response_timer(struct iscsi_conn *conn)
+{
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
+
+       spin_lock_bh(&conn->nopin_timer_lock);
+       if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) {
+               spin_unlock_bh(&conn->nopin_timer_lock);
+               return;
+       }
+
+       mod_timer(&conn->nopin_response_timer,
+               (get_jiffies_64() + na->nopin_response_timeout * HZ));
+       spin_unlock_bh(&conn->nopin_timer_lock);
+}
+
+/*
+ *     Called with conn->nopin_timer_lock held.
+ */
+void iscsit_start_nopin_response_timer(struct iscsi_conn *conn)
+{
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
+
+       spin_lock_bh(&conn->nopin_timer_lock);
+       if (conn->nopin_response_timer_flags & ISCSI_TF_RUNNING) {
+               spin_unlock_bh(&conn->nopin_timer_lock);
+               return;
+       }
+
+       init_timer(&conn->nopin_response_timer);
+       conn->nopin_response_timer.expires =
+               (get_jiffies_64() + na->nopin_response_timeout * HZ);
+       conn->nopin_response_timer.data = (unsigned long)conn;
+       conn->nopin_response_timer.function = iscsit_handle_nopin_response_timeout;
+       conn->nopin_response_timer_flags &= ~ISCSI_TF_STOP;
+       conn->nopin_response_timer_flags |= ISCSI_TF_RUNNING;
+       add_timer(&conn->nopin_response_timer);
+
+       pr_debug("Started NOPIN Response Timer on CID: %d to %u"
+               " seconds\n", conn->cid, na->nopin_response_timeout);
+       spin_unlock_bh(&conn->nopin_timer_lock);
+}
+
+void iscsit_stop_nopin_response_timer(struct iscsi_conn *conn)
+{
+       spin_lock_bh(&conn->nopin_timer_lock);
+       if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) {
+               spin_unlock_bh(&conn->nopin_timer_lock);
+               return;
+       }
+       conn->nopin_response_timer_flags |= ISCSI_TF_STOP;
+       spin_unlock_bh(&conn->nopin_timer_lock);
+
+       del_timer_sync(&conn->nopin_response_timer);
+
+       spin_lock_bh(&conn->nopin_timer_lock);
+       conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING;
+       spin_unlock_bh(&conn->nopin_timer_lock);
+}
+
+static void iscsit_handle_nopin_timeout(unsigned long data)
+{
+       struct iscsi_conn *conn = (struct iscsi_conn *) data;
+
+       iscsit_inc_conn_usage_count(conn);
+
+       spin_lock_bh(&conn->nopin_timer_lock);
+       if (conn->nopin_timer_flags & ISCSI_TF_STOP) {
+               spin_unlock_bh(&conn->nopin_timer_lock);
+               iscsit_dec_conn_usage_count(conn);
+               return;
+       }
+       conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING;
+       spin_unlock_bh(&conn->nopin_timer_lock);
+
+       iscsit_add_nopin(conn, 1);
+       iscsit_dec_conn_usage_count(conn);
+}
+
+/*
+ * Called with conn->nopin_timer_lock held.
+ */
+void __iscsit_start_nopin_timer(struct iscsi_conn *conn)
+{
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
+       /*
+       * NOPIN timeout is disabled.
+        */
+       if (!na->nopin_timeout)
+               return;
+
+       if (conn->nopin_timer_flags & ISCSI_TF_RUNNING)
+               return;
+
+       init_timer(&conn->nopin_timer);
+       conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ);
+       conn->nopin_timer.data = (unsigned long)conn;
+       conn->nopin_timer.function = iscsit_handle_nopin_timeout;
+       conn->nopin_timer_flags &= ~ISCSI_TF_STOP;
+       conn->nopin_timer_flags |= ISCSI_TF_RUNNING;
+       add_timer(&conn->nopin_timer);
+
+       pr_debug("Started NOPIN Timer on CID: %d at %u second"
+               " interval\n", conn->cid, na->nopin_timeout);
+}
+
+void iscsit_start_nopin_timer(struct iscsi_conn *conn)
+{
+       struct iscsi_session *sess = conn->sess;
+       struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess);
+       /*
+        * NOPIN timeout is disabled..
+        */
+       if (!na->nopin_timeout)
+               return;
+
+       spin_lock_bh(&conn->nopin_timer_lock);
+       if (conn->nopin_timer_flags & ISCSI_TF_RUNNING) {
+               spin_unlock_bh(&conn->nopin_timer_lock);
+               return;
+       }
+
+       init_timer(&conn->nopin_timer);
+       conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ);
+       conn->nopin_timer.data = (unsigned long)conn;
+       conn->nopin_timer.function = iscsit_handle_nopin_timeout;
+       conn->nopin_timer_flags &= ~ISCSI_TF_STOP;
+       conn->nopin_timer_flags |= ISCSI_TF_RUNNING;
+       add_timer(&conn->nopin_timer);
+
+       pr_debug("Started NOPIN Timer on CID: %d at %u second"
+                       " interval\n", conn->cid, na->nopin_timeout);
+       spin_unlock_bh(&conn->nopin_timer_lock);
+}
+
+void iscsit_stop_nopin_timer(struct iscsi_conn *conn)
+{
+       spin_lock_bh(&conn->nopin_timer_lock);
+       if (!(conn->nopin_timer_flags & ISCSI_TF_RUNNING)) {
+               spin_unlock_bh(&conn->nopin_timer_lock);
+               return;
+       }
+       conn->nopin_timer_flags |= ISCSI_TF_STOP;
+       spin_unlock_bh(&conn->nopin_timer_lock);
+
+       del_timer_sync(&conn->nopin_timer);
+
+       spin_lock_bh(&conn->nopin_timer_lock);
+       conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING;
+       spin_unlock_bh(&conn->nopin_timer_lock);
+}
+
+int iscsit_send_tx_data(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn,
+       int use_misc)
+{
+       int tx_sent, tx_size;
+       u32 iov_count;
+       struct kvec *iov;
+
+send_data:
+       tx_size = cmd->tx_size;
+
+       if (!use_misc) {
+               iov = &cmd->iov_data[0];
+               iov_count = cmd->iov_data_count;
+       } else {
+               iov = &cmd->iov_misc[0];
+               iov_count = cmd->iov_misc_count;
+       }
+
+       tx_sent = tx_data(conn, &iov[0], iov_count, tx_size);
+       if (tx_size != tx_sent) {
+               if (tx_sent == -EAGAIN) {
+                       pr_err("tx_data() returned -EAGAIN\n");
+                       goto send_data;
+               } else
+                       return -1;
+       }
+       cmd->tx_size = 0;
+
+       return 0;
+}
+
+int iscsit_fe_sendpage_sg(
+       struct iscsi_cmd *cmd,
+       struct iscsi_conn *conn)
+{
+       struct scatterlist *sg = cmd->first_data_sg;
+       struct kvec iov;
+       u32 tx_hdr_size, data_len;
+       u32 offset = cmd->first_data_sg_off;
+       int tx_sent;
+
+send_hdr:
+       tx_hdr_size = ISCSI_HDR_LEN;
+       if (conn->conn_ops->HeaderDigest)
+               tx_hdr_size += ISCSI_CRC_LEN;
+
+       iov.iov_base = cmd->pdu;
+       iov.iov_len = tx_hdr_size;
+
+       tx_sent = tx_data(conn, &iov, 1, tx_hdr_size);
+       if (tx_hdr_size != tx_sent) {
+               if (tx_sent == -EAGAIN) {
+                       pr_err("tx_data() returned -EAGAIN\n");
+                       goto send_hdr;
+               }
+               return -1;
+       }
+
+       data_len = cmd->tx_size - tx_hdr_size - cmd->padding;
+       if (conn->conn_ops->DataDigest)
+               data_len -= ISCSI_CRC_LEN;
+
+       /*
+        * Perform sendpage() for each page in the scatterlist
+        */
+       while (data_len) {
+               u32 space = (sg->length - offset);
+               u32 sub_len = min_t(u32, data_len, space);
+send_pg:
+               tx_sent = conn->sock->ops->sendpage(conn->sock,
+                                       sg_page(sg), sg->offset + offset, sub_len, 0);
+               if (tx_sent != sub_len) {
+                       if (tx_sent == -EAGAIN) {
+                               pr_err("tcp_sendpage() returned"
+                                               " -EAGAIN\n");
+                               goto send_pg;
+                       }
+
+                       pr_err("tcp_sendpage() failure: %d\n",
+                                       tx_sent);
+                       return -1;
+               }
+
+               data_len -= sub_len;
+               offset = 0;
+               sg = sg_next(sg);
+       }
+
+send_padding:
+       if (cmd->padding) {
+               struct kvec *iov_p =
+                       &cmd->iov_data[cmd->iov_data_count-1];
+
+               tx_sent = tx_data(conn, iov_p, 1, cmd->padding);
+               if (cmd->padding != tx_sent) {
+                       if (tx_sent == -EAGAIN) {
+                               pr_err("tx_data() returned -EAGAIN\n");
+                               goto send_padding;
+                       }
+                       return -1;
+               }
+       }
+
+send_datacrc:
+       if (conn->conn_ops->DataDigest) {
+               struct kvec *iov_d =
+                       &cmd->iov_data[cmd->iov_data_count];
+
+               tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN);
+               if (ISCSI_CRC_LEN != tx_sent) {
+                       if (tx_sent == -EAGAIN) {
+                               pr_err("tx_data() returned -EAGAIN\n");
+                               goto send_datacrc;
+                       }
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ *      This function is used for mainly sending a ISCSI_TARG_LOGIN_RSP PDU
+ *      back to the Initiator when an expection condition occurs with the
+ *      errors set in status_class and status_detail.
+ *
+ *      Parameters:     iSCSI Connection, Status Class, Status Detail.
+ *      Returns:        0 on success, -1 on error.
+ */
+int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail)
+{
+       u8 iscsi_hdr[ISCSI_HDR_LEN];
+       int err;
+       struct kvec iov;
+       struct iscsi_login_rsp *hdr;
+
+       iscsit_collect_login_stats(conn, status_class, status_detail);
+
+       memset(&iov, 0, sizeof(struct kvec));
+       memset(&iscsi_hdr, 0x0, ISCSI_HDR_LEN);
+
+       hdr     = (struct iscsi_login_rsp *)&iscsi_hdr;
+       hdr->opcode             = ISCSI_OP_LOGIN_RSP;
+       hdr->status_class       = status_class;
+       hdr->status_detail      = status_detail;
+       hdr->itt                = cpu_to_be32(conn->login_itt);
+
+       iov.iov_base            = &iscsi_hdr;
+       iov.iov_len             = ISCSI_HDR_LEN;
+
+       PRINT_BUFF(iscsi_hdr, ISCSI_HDR_LEN);
+
+       err = tx_data(conn, &iov, 1, ISCSI_HDR_LEN);
+       if (err != ISCSI_HDR_LEN) {
+               pr_err("tx_data returned less than expected\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+void iscsit_print_session_params(struct iscsi_session *sess)
+{
+       struct iscsi_conn *conn;
+
+       pr_debug("-----------------------------[Session Params for"
+               " SID: %u]-----------------------------\n", sess->sid);
+       spin_lock_bh(&sess->conn_lock);
+       list_for_each_entry(conn, &sess->sess_conn_list, conn_list)
+               iscsi_dump_conn_ops(conn->conn_ops);
+       spin_unlock_bh(&sess->conn_lock);
+
+       iscsi_dump_sess_ops(sess->sess_ops);
+}
+
+static int iscsit_do_rx_data(
+       struct iscsi_conn *conn,
+       struct iscsi_data_count *count)
+{
+       int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len;
+       u32 rx_marker_val[count->ss_marker_count], rx_marker_iov = 0;
+       struct kvec iov[count->ss_iov_count], *iov_p;
+       struct msghdr msg;
+
+       if (!conn || !conn->sock || !conn->conn_ops)
+               return -1;
+
+       memset(&msg, 0, sizeof(struct msghdr));
+
+       if (count->sync_and_steering) {
+               int size = 0;
+               u32 i, orig_iov_count = 0;
+               u32 orig_iov_len = 0, orig_iov_loc = 0;
+               u32 iov_count = 0, per_iov_bytes = 0;
+               u32 *rx_marker, old_rx_marker = 0;
+               struct kvec *iov_record;
+
+               memset(&rx_marker_val, 0,
+                               count->ss_marker_count * sizeof(u32));
+               memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec));
+
+               iov_record = count->iov;
+               orig_iov_count = count->iov_count;
+               rx_marker = &conn->of_marker;
+
+               i = 0;
+               size = data;
+               orig_iov_len = iov_record[orig_iov_loc].iov_len;
+               while (size > 0) {
+                       pr_debug("rx_data: #1 orig_iov_len %u,"
+                       " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc);
+                       pr_debug("rx_data: #2 rx_marker %u, size"
+                               " %u\n", *rx_marker, size);
+
+                       if (orig_iov_len >= *rx_marker) {
+                               iov[iov_count].iov_len = *rx_marker;
+                               iov[iov_count++].iov_base =
+                                       (iov_record[orig_iov_loc].iov_base +
+                                               per_iov_bytes);
+
+                               iov[iov_count].iov_len = (MARKER_SIZE / 2);
+                               iov[iov_count++].iov_base =
+                                       &rx_marker_val[rx_marker_iov++];
+                               iov[iov_count].iov_len = (MARKER_SIZE / 2);
+                               iov[iov_count++].iov_base =
+                                       &rx_marker_val[rx_marker_iov++];
+                               old_rx_marker = *rx_marker;
+
+                               /*
+                                * OFMarkInt is in 32-bit words.
+                                */
+                               *rx_marker = (conn->conn_ops->OFMarkInt * 4);
+                               size -= old_rx_marker;
+                               orig_iov_len -= old_rx_marker;
+                               per_iov_bytes += old_rx_marker;
+
+                               pr_debug("rx_data: #3 new_rx_marker"
+                                       " %u, size %u\n", *rx_marker, size);
+                       } else {
+                               iov[iov_count].iov_len = orig_iov_len;
+                               iov[iov_count++].iov_base =
+                                       (iov_record[orig_iov_loc].iov_base +
+                                               per_iov_bytes);
+
+                               per_iov_bytes = 0;
+                               *rx_marker -= orig_iov_len;
+                               size -= orig_iov_len;
+
+                               if (size)
+                                       orig_iov_len =
+                                       iov_record[++orig_iov_loc].iov_len;
+
+                               pr_debug("rx_data: #4 new_rx_marker"
+                                       " %u, size %u\n", *rx_marker, size);
+                       }
+               }
+               data += (rx_marker_iov * (MARKER_SIZE / 2));
+
+               iov_p   = &iov[0];
+               iov_len = iov_count;
+
+               if (iov_count > count->ss_iov_count) {
+                       pr_err("iov_count: %d, count->ss_iov_count:"
+                               " %d\n", iov_count, count->ss_iov_count);
+                       return -1;
+               }
+               if (rx_marker_iov > count->ss_marker_count) {
+                       pr_err("rx_marker_iov: %d, count->ss_marker"
+                               "_count: %d\n", rx_marker_iov,
+                               count->ss_marker_count);
+                       return -1;
+               }
+       } else {
+               iov_p = count->iov;
+               iov_len = count->iov_count;
+       }
+
+       while (total_rx < data) {
+               rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len,
+                                       (data - total_rx), MSG_WAITALL);
+               if (rx_loop <= 0) {
+                       pr_debug("rx_loop: %d total_rx: %d\n",
+                               rx_loop, total_rx);
+                       return rx_loop;
+               }
+               total_rx += rx_loop;
+               pr_debug("rx_loop: %d, total_rx: %d, data: %d\n",
+                               rx_loop, total_rx, data);
+       }
+
+       if (count->sync_and_steering) {
+               int j;
+               for (j = 0; j < rx_marker_iov; j++) {
+                       pr_debug("rx_data: #5 j: %d, offset: %d\n",
+                               j, rx_marker_val[j]);
+                       conn->of_marker_offset = rx_marker_val[j];
+               }
+               total_rx -= (rx_marker_iov * (MARKER_SIZE / 2));
+       }
+
+       return total_rx;
+}
+
+static int iscsit_do_tx_data(
+       struct iscsi_conn *conn,
+       struct iscsi_data_count *count)
+{
+       int data = count->data_length, total_tx = 0, tx_loop = 0, iov_len;
+       u32 tx_marker_val[count->ss_marker_count], tx_marker_iov = 0;
+       struct kvec iov[count->ss_iov_count], *iov_p;
+       struct msghdr msg;
+
+       if (!conn || !conn->sock || !conn->conn_ops)
+               return -1;
+
+       if (data <= 0) {
+               pr_err("Data length is: %d\n", data);
+               return -1;
+       }
+
+       memset(&msg, 0, sizeof(struct msghdr));
+
+       if (count->sync_and_steering) {
+               int size = 0;
+               u32 i, orig_iov_count = 0;
+               u32 orig_iov_len = 0, orig_iov_loc = 0;
+               u32 iov_count = 0, per_iov_bytes = 0;
+               u32 *tx_marker, old_tx_marker = 0;
+               struct kvec *iov_record;
+
+               memset(&tx_marker_val, 0,
+                       count->ss_marker_count * sizeof(u32));
+               memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec));
+
+               iov_record = count->iov;
+               orig_iov_count = count->iov_count;
+               tx_marker = &conn->if_marker;
+
+               i = 0;
+               size = data;
+               orig_iov_len = iov_record[orig_iov_loc].iov_len;
+               while (size > 0) {
+                       pr_debug("tx_data: #1 orig_iov_len %u,"
+                       " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc);
+                       pr_debug("tx_data: #2 tx_marker %u, size"
+                               " %u\n", *tx_marker, size);
+
+                       if (orig_iov_len >= *tx_marker) {
+                               iov[iov_count].iov_len = *tx_marker;
+                               iov[iov_count++].iov_base =
+                                       (iov_record[orig_iov_loc].iov_base +
+                                               per_iov_bytes);
+
+                               tx_marker_val[tx_marker_iov] =
+                                               (size - *tx_marker);
+                               iov[iov_count].iov_len = (MARKER_SIZE / 2);
+                               iov[iov_count++].iov_base =
+                                       &tx_marker_val[tx_marker_iov++];
+                               iov[iov_count].iov_len = (MARKER_SIZE / 2);
+                               iov[iov_count++].iov_base =
+                                       &tx_marker_val[tx_marker_iov++];
+                               old_tx_marker = *tx_marker;
+
+                               /*
+                                * IFMarkInt is in 32-bit words.
+                                */
+                               *tx_marker = (conn->conn_ops->IFMarkInt * 4);
+                               size -= old_tx_marker;
+                               orig_iov_len -= old_tx_marker;
+                               per_iov_bytes += old_tx_marker;
+
+                               pr_debug("tx_data: #3 new_tx_marker"
+                                       " %u, size %u\n", *tx_marker, size);
+                               pr_debug("tx_data: #4 offset %u\n",
+                                       tx_marker_val[tx_marker_iov-1]);
+                       } else {
+                               iov[iov_count].iov_len = orig_iov_len;
+                               iov[iov_count++].iov_base
+                                       = (iov_record[orig_iov_loc].iov_base +
+                                               per_iov_bytes);
+
+                               per_iov_bytes = 0;
+                               *tx_marker -= orig_iov_len;
+                               size -= orig_iov_len;
+
+                               if (size)
+                                       orig_iov_len =
+                                       iov_record[++orig_iov_loc].iov_len;
+
+                               pr_debug("tx_data: #5 new_tx_marker"
+                                       " %u, size %u\n", *tx_marker, size);
+                       }
+               }
+
+               data += (tx_marker_iov * (MARKER_SIZE / 2));
+
+               iov_p = &iov[0];
+               iov_len = iov_count;
+
+               if (iov_count > count->ss_iov_count) {
+                       pr_err("iov_count: %d, count->ss_iov_count:"
+                               " %d\n", iov_count, count->ss_iov_count);
+                       return -1;
+               }
+               if (tx_marker_iov > count->ss_marker_count) {
+                       pr_err("tx_marker_iov: %d, count->ss_marker"
+                               "_count: %d\n", tx_marker_iov,
+                               count->ss_marker_count);
+                       return -1;
+               }
+       } else {
+               iov_p = count->iov;
+               iov_len = count->iov_count;
+       }
+
+       while (total_tx < data) {
+               tx_loop = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len,
+                                       (data - total_tx));
+               if (tx_loop <= 0) {
+                       pr_debug("tx_loop: %d total_tx %d\n",
+                               tx_loop, total_tx);
+                       return tx_loop;
+               }
+               total_tx += tx_loop;
+               pr_debug("tx_loop: %d, total_tx: %d, data: %d\n",
+                                       tx_loop, total_tx, data);
+       }
+
+       if (count->sync_and_steering)
+               total_tx -= (tx_marker_iov * (MARKER_SIZE / 2));
+
+       return total_tx;
+}
+
+int rx_data(
+       struct iscsi_conn *conn,
+       struct kvec *iov,
+       int iov_count,
+       int data)
+{
+       struct iscsi_data_count c;
+
+       if (!conn || !conn->sock || !conn->conn_ops)
+               return -1;
+
+       memset(&c, 0, sizeof(struct iscsi_data_count));
+       c.iov = iov;
+       c.iov_count = iov_count;
+       c.data_length = data;
+       c.type = ISCSI_RX_DATA;
+
+       if (conn->conn_ops->OFMarker &&
+          (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) {
+               if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0)
+                       return -1;
+       }
+
+       return iscsit_do_rx_data(conn, &c);
+}
+
+int tx_data(
+       struct iscsi_conn *conn,
+       struct kvec *iov,
+       int iov_count,
+       int data)
+{
+       struct iscsi_data_count c;
+
+       if (!conn || !conn->sock || !conn->conn_ops)
+               return -1;
+
+       memset(&c, 0, sizeof(struct iscsi_data_count));
+       c.iov = iov;
+       c.iov_count = iov_count;
+       c.data_length = data;
+       c.type = ISCSI_TX_DATA;
+
+       if (conn->conn_ops->IFMarker &&
+          (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) {
+               if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0)
+                       return -1;
+       }
+
+       return iscsit_do_tx_data(conn, &c);
+}
+
+void iscsit_collect_login_stats(
+       struct iscsi_conn *conn,
+       u8 status_class,
+       u8 status_detail)
+{
+       struct iscsi_param *intrname = NULL;
+       struct iscsi_tiqn *tiqn;
+       struct iscsi_login_stats *ls;
+
+       tiqn = iscsit_snmp_get_tiqn(conn);
+       if (!tiqn)
+               return;
+
+       ls = &tiqn->login_stats;
+
+       spin_lock(&ls->lock);
+       if (!strcmp(conn->login_ip, ls->last_intr_fail_ip_addr) &&
+           ((get_jiffies_64() - ls->last_fail_time) < 10)) {
+               /* We already have the failure info for this login */
+               spin_unlock(&ls->lock);
+               return;
+       }
+
+       if (status_class == ISCSI_STATUS_CLS_SUCCESS)
+               ls->accepts++;
+       else if (status_class == ISCSI_STATUS_CLS_REDIRECT) {
+               ls->redirects++;
+               ls->last_fail_type = ISCSI_LOGIN_FAIL_REDIRECT;
+       } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR)  &&
+                (status_detail == ISCSI_LOGIN_STATUS_AUTH_FAILED)) {
+               ls->authenticate_fails++;
+               ls->last_fail_type =  ISCSI_LOGIN_FAIL_AUTHENTICATE;
+       } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR)  &&
+                (status_detail == ISCSI_LOGIN_STATUS_TGT_FORBIDDEN)) {
+               ls->authorize_fails++;
+               ls->last_fail_type = ISCSI_LOGIN_FAIL_AUTHORIZE;
+       } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) &&
+                (status_detail == ISCSI_LOGIN_STATUS_INIT_ERR)) {
+               ls->negotiate_fails++;
+               ls->last_fail_type = ISCSI_LOGIN_FAIL_NEGOTIATE;
+       } else {
+               ls->other_fails++;
+               ls->last_fail_type = ISCSI_LOGIN_FAIL_OTHER;
+       }
+
+       /* Save initiator name, ip address and time, if it is a failed login */
+       if (status_class != ISCSI_STATUS_CLS_SUCCESS) {
+               if (conn->param_list)
+                       intrname = iscsi_find_param_from_key(INITIATORNAME,
+                                                            conn->param_list);
+               strcpy(ls->last_intr_fail_name,
+                      (intrname ? intrname->value : "Unknown"));
+
+               ls->last_intr_fail_ip_family = conn->sock->sk->sk_family;
+               snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE,
+                               "%s", conn->login_ip);
+               ls->last_fail_time = get_jiffies_64();
+       }
+
+       spin_unlock(&ls->lock);
+}
+
+struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *conn)
+{
+       struct iscsi_portal_group *tpg;
+
+       if (!conn || !conn->sess)
+               return NULL;
+
+       tpg = conn->sess->tpg;
+       if (!tpg)
+               return NULL;
+
+       if (!tpg->tpg_tiqn)
+               return NULL;
+
+       return tpg->tpg_tiqn;
+}
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
new file mode 100644 (file)
index 0000000..2cd49d6
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef ISCSI_TARGET_UTIL_H
+#define ISCSI_TARGET_UTIL_H
+
+#define MARKER_SIZE    8
+
+extern int iscsit_add_r2t_to_list(struct iscsi_cmd *, u32, u32, int, u32);
+extern struct iscsi_r2t *iscsit_get_r2t_for_eos(struct iscsi_cmd *, u32, u32);
+extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *);
+extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *);
+extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *);
+extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
+extern struct iscsi_cmd *iscsit_allocate_se_cmd(struct iscsi_conn *, u32, int, int);
+extern struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(struct iscsi_conn *, u8);
+extern int iscsit_decide_list_to_build(struct iscsi_cmd *, u32);
+extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
+extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
+extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
+int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, u32 cmdsn);
+extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *);
+extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, u32);
+extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
+                       u32, u32);
+extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32);
+extern int iscsit_find_cmd_for_recovery(struct iscsi_session *, struct iscsi_cmd **,
+                       struct iscsi_conn_recovery **, u32);
+extern void iscsit_add_cmd_to_immediate_queue(struct iscsi_cmd *, struct iscsi_conn *, u8);
+extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *);
+extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8);
+extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *);
+extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *);
+extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
+extern void iscsit_release_cmd(struct iscsi_cmd *);
+extern int iscsit_check_session_usage_count(struct iscsi_session *);
+extern void iscsit_dec_session_usage_count(struct iscsi_session *);
+extern void iscsit_inc_session_usage_count(struct iscsi_session *);
+extern int iscsit_set_sync_and_steering_values(struct iscsi_conn *);
+extern struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *, u16);
+extern struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *, u16);
+extern void iscsit_check_conn_usage_count(struct iscsi_conn *);
+extern void iscsit_dec_conn_usage_count(struct iscsi_conn *);
+extern void iscsit_inc_conn_usage_count(struct iscsi_conn *);
+extern void iscsit_mod_nopin_response_timer(struct iscsi_conn *);
+extern void iscsit_start_nopin_response_timer(struct iscsi_conn *);
+extern void iscsit_stop_nopin_response_timer(struct iscsi_conn *);
+extern void __iscsit_start_nopin_timer(struct iscsi_conn *);
+extern void iscsit_start_nopin_timer(struct iscsi_conn *);
+extern void iscsit_stop_nopin_timer(struct iscsi_conn *);
+extern int iscsit_send_tx_data(struct iscsi_cmd *, struct iscsi_conn *, int);
+extern int iscsit_fe_sendpage_sg(struct iscsi_cmd *, struct iscsi_conn *);
+extern int iscsit_tx_login_rsp(struct iscsi_conn *, u8, u8);
+extern void iscsit_print_session_params(struct iscsi_session *);
+extern int iscsit_print_dev_to_proc(char *, char **, off_t, int);
+extern int iscsit_print_sessions_to_proc(char *, char **, off_t, int);
+extern int iscsit_print_tpg_to_proc(char *, char **, off_t, int);
+extern int rx_data(struct iscsi_conn *, struct kvec *, int, int);
+extern int tx_data(struct iscsi_conn *, struct kvec *, int, int);
+extern void iscsit_collect_login_stats(struct iscsi_conn *, u8, u8);
+extern struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *);
+
+#endif /*** ISCSI_TARGET_UTIL_H ***/
index 46352d658e35b5d2698dc95d75ce9d6eb1c1cd58..c75a01a1c4757976b776634f0fe14d00aa35b313 100644 (file)
@@ -4052,17 +4052,16 @@ static int transport_allocate_data_tasks(
        struct se_task *task;
        struct se_device *dev = cmd->se_dev;
        unsigned long flags;
-       sector_t sectors;
        int task_count, i, ret;
-       sector_t dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors;
+       sector_t sectors, dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors;
        u32 sector_size = dev->se_sub_dev->se_dev_attrib.block_size;
        struct scatterlist *sg;
        struct scatterlist *cmd_sg;
 
        WARN_ON(cmd->data_length % sector_size);
        sectors = DIV_ROUND_UP(cmd->data_length, sector_size);
-       task_count = DIV_ROUND_UP(sectors, dev_max_sectors);
-
+       task_count = DIV_ROUND_UP_SECTOR_T(sectors, dev_max_sectors);
+       
        cmd_sg = sgl;
        for (i = 0; i < task_count; i++) {
                unsigned int task_size;
index cb40b82daf368081b434b14a1cc12f56c0d58c80..4dcb37bbdf9245a569d1afd0ca81324eff234708 100644 (file)
@@ -959,7 +959,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
 
 config SERIAL_SH_SCI
        tristate "SuperH SCI(F) serial port support"
-       depends on HAVE_CLK && (SUPERH || H8300 || ARCH_SHMOBILE)
+       depends on HAVE_CLK && (SUPERH || ARCH_SHMOBILE)
        select SERIAL_CORE
 
 config SERIAL_SH_SCI_NR_UARTS
index 22fe801cce31725cc8c2be37a45b01469d4394a1..827db7654594e43c0b078ef7cb65894585f56261 100644 (file)
 #include <linux/delay.h>
 #include <linux/rational.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <mach/hardware.h>
 #include <mach/imx-uart.h>
 
 /* Register definitions */
@@ -66,8 +67,9 @@
 #define UBIR  0xa4 /* BRM Incremental Register */
 #define UBMR  0xa8 /* BRM Modulator Register */
 #define UBRC  0xac /* Baud Rate Count Register */
-#define MX2_ONEMS 0xb0 /* One Millisecond register */
-#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */
+#define IMX21_ONEMS 0xb0 /* One Millisecond register */
+#define IMX1_UTS 0xd0 /* UART Test Register on i.mx1 */
+#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
 
 /* UART Control Register Bit Fields.*/
 #define  URXD_CHARRDY    (1<<15)
@@ -87,7 +89,7 @@
 #define  UCR1_RTSDEN     (1<<5)         /* RTS delta interrupt enable */
 #define  UCR1_SNDBRK     (1<<4)         /* Send break */
 #define  UCR1_TDMAEN     (1<<3)         /* Transmitter ready DMA enable */
-#define  MX1_UCR1_UARTCLKEN  (1<<2)     /* UART clock enabled, mx1 only */
+#define  IMX1_UCR1_UARTCLKEN  (1<<2)  /* UART clock enabled, i.mx1 only */
 #define  UCR1_DOZE       (1<<1)         /* Doze */
 #define  UCR1_UARTEN     (1<<0)         /* UART enabled */
 #define  UCR2_ESCI              (1<<15) /* Escape seq interrupt enable */
 #define  UCR3_RXDSEN    (1<<6)  /* Receive status interrupt enable */
 #define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
 #define  UCR3_AWAKEN    (1<<4)  /* Async wake interrupt enable */
-#define  MX1_UCR3_REF25         (1<<3)  /* Ref freq 25 MHz, only on mx1 */
-#define  MX1_UCR3_REF30         (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
-#define  MX2_UCR3_RXDMUXSEL     (1<<2)  /* RXD Muxed Input Select, on mx2/mx3 */
+#define  IMX21_UCR3_RXDMUXSEL   (1<<2)  /* RXD Muxed Input Select */
 #define  UCR3_INVT      (1<<1)  /* Inverted Infrared transmission */
 #define  UCR3_BPEN      (1<<0)  /* Preset registers enable */
 #define  UCR4_CTSTL_SHF  10      /* CTS trigger level shift */
 
 #define UART_NR 8
 
+/* i.mx21 type uart runs on all i.mx except i.mx1 */
+enum imx_uart_type {
+       IMX1_UART,
+       IMX21_UART,
+};
+
+/* device type dependent stuff */
+struct imx_uart_data {
+       unsigned uts_reg;
+       enum imx_uart_type devtype;
+};
+
 struct imx_port {
        struct uart_port        port;
        struct timer_list       timer;
@@ -192,6 +204,7 @@ struct imx_port {
        unsigned int            irda_inv_tx:1;
        unsigned short          trcv_delay; /* transceiver delay */
        struct clk              *clk;
+       struct imx_uart_data    *devdata;
 };
 
 #ifdef CONFIG_IRDA
@@ -200,6 +213,52 @@ struct imx_port {
 #define USE_IRDA(sport)        (0)
 #endif
 
+static struct imx_uart_data imx_uart_devdata[] = {
+       [IMX1_UART] = {
+               .uts_reg = IMX1_UTS,
+               .devtype = IMX1_UART,
+       },
+       [IMX21_UART] = {
+               .uts_reg = IMX21_UTS,
+               .devtype = IMX21_UART,
+       },
+};
+
+static struct platform_device_id imx_uart_devtype[] = {
+       {
+               .name = "imx1-uart",
+               .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART],
+       }, {
+               .name = "imx21-uart",
+               .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART],
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
+
+static struct of_device_id imx_uart_dt_ids[] = {
+       { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },
+       { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
+
+static inline unsigned uts_reg(struct imx_port *sport)
+{
+       return sport->devdata->uts_reg;
+}
+
+static inline int is_imx1_uart(struct imx_port *sport)
+{
+       return sport->devdata->devtype == IMX1_UART;
+}
+
+static inline int is_imx21_uart(struct imx_port *sport)
+{
+       return sport->devdata->devtype == IMX21_UART;
+}
+
 /*
  * Handle any change of modem status signal since we were last called.
  */
@@ -326,7 +385,8 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
        struct circ_buf *xmit = &sport->port.state->xmit;
 
        while (!uart_circ_empty(xmit) &&
-                       !(readl(sport->port.membase + UTS) & UTS_TXFULL)) {
+                       !(readl(sport->port.membase + uts_reg(sport))
+                               & UTS_TXFULL)) {
                /* send xmit->buf[xmit->tail]
                 * out the port here */
                writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
@@ -373,7 +433,7 @@ static void imx_start_tx(struct uart_port *port)
                writel(temp, sport->port.membase + UCR4);
        }
 
-       if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
+       if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
                imx_transmit_buffer(sport);
 }
 
@@ -689,9 +749,9 @@ static int imx_startup(struct uart_port *port)
                }
        }
 
-       if (!cpu_is_mx1()) {
+       if (is_imx21_uart(sport)) {
                temp = readl(sport->port.membase + UCR3);
-               temp |= MX2_UCR3_RXDMUXSEL;
+               temp |= IMX21_UCR3_RXDMUXSEL;
                writel(temp, sport->port.membase + UCR3);
        }
 
@@ -923,9 +983,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        writel(num, sport->port.membase + UBIR);
        writel(denom, sport->port.membase + UBMR);
 
-       if (!cpu_is_mx1())
+       if (is_imx21_uart(sport))
                writel(sport->port.uartclk / div / 1000,
-                               sport->port.membase + MX2_ONEMS);
+                               sport->port.membase + IMX21_ONEMS);
 
        writel(old_ucr1, sport->port.membase + UCR1);
 
@@ -1041,7 +1101,7 @@ static void imx_console_putchar(struct uart_port *port, int ch)
 {
        struct imx_port *sport = (struct imx_port *)port;
 
-       while (readl(sport->port.membase + UTS) & UTS_TXFULL)
+       while (readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)
                barrier();
 
        writel(ch, sport->port.membase + URTX0);
@@ -1062,8 +1122,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
        ucr1 = old_ucr1 = readl(sport->port.membase + UCR1);
        old_ucr2 = readl(sport->port.membase + UCR2);
 
-       if (cpu_is_mx1())
-               ucr1 |= MX1_UCR1_UARTCLKEN;
+       if (is_imx1_uart(sport))
+               ucr1 |= IMX1_UCR1_UARTCLKEN;
        ucr1 |= UCR1_UARTEN;
        ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
 
@@ -1222,6 +1282,63 @@ static int serial_imx_resume(struct platform_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static int serial_imx_probe_dt(struct imx_port *sport,
+               struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *of_id =
+                       of_match_device(imx_uart_dt_ids, &pdev->dev);
+       int ret;
+
+       if (!np)
+               return -ENODEV;
+
+       ret = of_alias_get_id(np, "serial");
+       if (ret < 0) {
+               pr_err("%s: failed to get alias id, errno %d\n",
+                       __func__, ret);
+               return -ENODEV;
+       } else {
+               sport->port.line = ret;
+       }
+
+       if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
+               sport->have_rtscts = 1;
+
+       if (of_get_property(np, "fsl,irda-mode", NULL))
+               sport->use_irda = 1;
+
+       sport->devdata = of_id->data;
+
+       return 0;
+}
+#else
+static inline int serial_imx_probe_dt(struct imx_port *sport,
+               struct platform_device *pdev)
+{
+       return -ENODEV;
+}
+#endif
+
+static void serial_imx_probe_pdata(struct imx_port *sport,
+               struct platform_device *pdev)
+{
+       struct imxuart_platform_data *pdata = pdev->dev.platform_data;
+
+       sport->port.line = pdev->id;
+       sport->devdata = (struct imx_uart_data  *) pdev->id_entry->driver_data;
+
+       if (!pdata)
+               return;
+
+       if (pdata->flags & IMXUART_HAVE_RTSCTS)
+               sport->have_rtscts = 1;
+
+       if (pdata->flags & IMXUART_IRDA)
+               sport->use_irda = 1;
+}
+
 static int serial_imx_probe(struct platform_device *pdev)
 {
        struct imx_port *sport;
@@ -1234,6 +1351,10 @@ static int serial_imx_probe(struct platform_device *pdev)
        if (!sport)
                return -ENOMEM;
 
+       ret = serial_imx_probe_dt(sport, pdev);
+       if (ret == -ENODEV)
+               serial_imx_probe_pdata(sport, pdev);
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                ret = -ENODEV;
@@ -1258,7 +1379,6 @@ static int serial_imx_probe(struct platform_device *pdev)
        sport->port.fifosize = 32;
        sport->port.ops = &imx_pops;
        sport->port.flags = UPF_BOOT_AUTOCONF;
-       sport->port.line = pdev->id;
        init_timer(&sport->timer);
        sport->timer.function = imx_timeout;
        sport->timer.data     = (unsigned long)sport;
@@ -1272,17 +1392,9 @@ static int serial_imx_probe(struct platform_device *pdev)
 
        sport->port.uartclk = clk_get_rate(sport->clk);
 
-       imx_ports[pdev->id] = sport;
+       imx_ports[sport->port.line] = sport;
 
        pdata = pdev->dev.platform_data;
-       if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
-               sport->have_rtscts = 1;
-
-#ifdef CONFIG_IRDA
-       if (pdata && (pdata->flags & IMXUART_IRDA))
-               sport->use_irda = 1;
-#endif
-
        if (pdata && pdata->init) {
                ret = pdata->init(pdev);
                if (ret)
@@ -1340,9 +1452,11 @@ static struct platform_driver serial_imx_driver = {
 
        .suspend        = serial_imx_suspend,
        .resume         = serial_imx_resume,
+       .id_table       = imx_uart_devtype,
        .driver         = {
                .name   = "imx-uart",
                .owner  = THIS_MODULE,
+               .of_match_table = imx_uart_dt_ids,
        },
 };
 
index ebd8629c108ddc06f6b731831dbe962442a1868f..d0a56235c50eedc5e9ed4dd9097e0b86b504ebda 100644 (file)
 #include <asm/sh_bios.h>
 #endif
 
-#ifdef CONFIG_H8300
-#include <asm/gpio.h>
-#endif
-
 #include "sh-sci.h"
 
 struct sci_port {
@@ -66,12 +62,6 @@ struct sci_port {
        /* Platform configuration */
        struct plat_sci_port    *cfg;
 
-       /* 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;
@@ -81,6 +71,8 @@ struct sci_port {
        /* Function clock */
        struct clk              *fclk;
 
+       char                    *irqstr[SCIx_NR_IRQS];
+
        struct dma_chan                 *chan_tx;
        struct dma_chan                 *chan_rx;
 
@@ -121,6 +113,278 @@ to_sci_port(struct uart_port *uart)
        return container_of(uart, struct sci_port, port);
 }
 
+struct plat_sci_reg {
+       u8 offset, size;
+};
+
+/* Helper for invalidating specific entries of an inherited map. */
+#define sci_reg_invalid        { .offset = 0, .size = 0 }
+
+static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
+       [SCIx_PROBE_REGTYPE] = {
+               [0 ... SCIx_NR_REGS - 1] = sci_reg_invalid,
+       },
+
+       /*
+        * Common SCI definitions, dependent on the port's regshift
+        * value.
+        */
+       [SCIx_SCI_REGTYPE] = {
+               [SCSMR]         = { 0x00,  8 },
+               [SCBRR]         = { 0x01,  8 },
+               [SCSCR]         = { 0x02,  8 },
+               [SCxTDR]        = { 0x03,  8 },
+               [SCxSR]         = { 0x04,  8 },
+               [SCxRDR]        = { 0x05,  8 },
+               [SCFCR]         = sci_reg_invalid,
+               [SCFDR]         = sci_reg_invalid,
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common definitions for legacy IrDA ports, dependent on
+        * regshift value.
+        */
+       [SCIx_IRDA_REGTYPE] = {
+               [SCSMR]         = { 0x00,  8 },
+               [SCBRR]         = { 0x01,  8 },
+               [SCSCR]         = { 0x02,  8 },
+               [SCxTDR]        = { 0x03,  8 },
+               [SCxSR]         = { 0x04,  8 },
+               [SCxRDR]        = { 0x05,  8 },
+               [SCFCR]         = { 0x06,  8 },
+               [SCFDR]         = { 0x07, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common SCIFA definitions.
+        */
+       [SCIx_SCIFA_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x20,  8 },
+               [SCxSR]         = { 0x14, 16 },
+               [SCxRDR]        = { 0x24,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common SCIFB definitions.
+        */
+       [SCIx_SCIFB_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x40,  8 },
+               [SCxSR]         = { 0x14, 16 },
+               [SCxRDR]        = { 0x60,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common SH-3 SCIF definitions.
+        */
+       [SCIx_SH3_SCIF_REGTYPE] = {
+               [SCSMR]         = { 0x00,  8 },
+               [SCBRR]         = { 0x02,  8 },
+               [SCSCR]         = { 0x04,  8 },
+               [SCxTDR]        = { 0x06,  8 },
+               [SCxSR]         = { 0x08, 16 },
+               [SCxRDR]        = { 0x0a,  8 },
+               [SCFCR]         = { 0x0c,  8 },
+               [SCFDR]         = { 0x0e, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+
+       /*
+        * Common SH-4(A) SCIF(B) definitions.
+        */
+       [SCIx_SH4_SCIF_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x0c,  8 },
+               [SCxSR]         = { 0x10, 16 },
+               [SCxRDR]        = { 0x14,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = { 0x20, 16 },
+               [SCLSR]         = { 0x24, 16 },
+       },
+
+       /*
+        * Common SH-4(A) SCIF(B) definitions for ports without an SCSPTR
+        * register.
+        */
+       [SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x0c,  8 },
+               [SCxSR]         = { 0x10, 16 },
+               [SCxRDR]        = { 0x14,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = { 0x24, 16 },
+       },
+
+       /*
+        * Common SH-4(A) SCIF(B) definitions for ports with FIFO data
+        * count registers.
+        */
+       [SCIx_SH4_SCIF_FIFODATA_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x0c,  8 },
+               [SCxSR]         = { 0x10, 16 },
+               [SCxRDR]        = { 0x14,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = { 0x1c, 16 }, /* aliased to SCFDR */
+               [SCRFDR]        = { 0x20, 16 },
+               [SCSPTR]        = { 0x24, 16 },
+               [SCLSR]         = { 0x28, 16 },
+       },
+
+       /*
+        * SH7705-style SCIF(B) ports, lacking both SCSPTR and SCLSR
+        * registers.
+        */
+       [SCIx_SH7705_SCIF_REGTYPE] = {
+               [SCSMR]         = { 0x00, 16 },
+               [SCBRR]         = { 0x04,  8 },
+               [SCSCR]         = { 0x08, 16 },
+               [SCxTDR]        = { 0x20,  8 },
+               [SCxSR]         = { 0x14, 16 },
+               [SCxRDR]        = { 0x24,  8 },
+               [SCFCR]         = { 0x18, 16 },
+               [SCFDR]         = { 0x1c, 16 },
+               [SCTFDR]        = sci_reg_invalid,
+               [SCRFDR]        = sci_reg_invalid,
+               [SCSPTR]        = sci_reg_invalid,
+               [SCLSR]         = sci_reg_invalid,
+       },
+};
+
+#define sci_getreg(up, offset)         (sci_regmap[to_sci_port(up)->cfg->regtype] + offset)
+
+/*
+ * The "offset" here is rather misleading, in that it refers to an enum
+ * value relative to the port mapping rather than the fixed offset
+ * itself, which needs to be manually retrieved from the platform's
+ * register map for the given port.
+ */
+static unsigned int sci_serial_in(struct uart_port *p, int offset)
+{
+       struct plat_sci_reg *reg = sci_getreg(p, offset);
+
+       if (reg->size == 8)
+               return ioread8(p->membase + (reg->offset << p->regshift));
+       else if (reg->size == 16)
+               return ioread16(p->membase + (reg->offset << p->regshift));
+       else
+               WARN(1, "Invalid register access\n");
+
+       return 0;
+}
+
+static void sci_serial_out(struct uart_port *p, int offset, int value)
+{
+       struct plat_sci_reg *reg = sci_getreg(p, offset);
+
+       if (reg->size == 8)
+               iowrite8(value, p->membase + (reg->offset << p->regshift));
+       else if (reg->size == 16)
+               iowrite16(value, p->membase + (reg->offset << p->regshift));
+       else
+               WARN(1, "Invalid register access\n");
+}
+
+#define sci_in(up, offset)             (up->serial_in(up, offset))
+#define sci_out(up, offset, value)     (up->serial_out(up, offset, value))
+
+static int sci_probe_regmap(struct plat_sci_port *cfg)
+{
+       switch (cfg->type) {
+       case PORT_SCI:
+               cfg->regtype = SCIx_SCI_REGTYPE;
+               break;
+       case PORT_IRDA:
+               cfg->regtype = SCIx_IRDA_REGTYPE;
+               break;
+       case PORT_SCIFA:
+               cfg->regtype = SCIx_SCIFA_REGTYPE;
+               break;
+       case PORT_SCIFB:
+               cfg->regtype = SCIx_SCIFB_REGTYPE;
+               break;
+       case PORT_SCIF:
+               /*
+                * The SH-4 is a bit of a misnomer here, although that's
+                * where this particular port layout originated. This
+                * configuration (or some slight variation thereof)
+                * remains the dominant model for all SCIFs.
+                */
+               cfg->regtype = SCIx_SH4_SCIF_REGTYPE;
+               break;
+       default:
+               printk(KERN_ERR "Can't probe register map for given port\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void sci_port_enable(struct sci_port *sci_port)
+{
+       if (!sci_port->port.dev)
+               return;
+
+       pm_runtime_get_sync(sci_port->port.dev);
+
+       clk_enable(sci_port->iclk);
+       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
+       clk_enable(sci_port->fclk);
+}
+
+static void sci_port_disable(struct sci_port *sci_port)
+{
+       if (!sci_port->port.dev)
+               return;
+
+       clk_disable(sci_port->fclk);
+       clk_disable(sci_port->iclk);
+
+       pm_runtime_put_sync(sci_port->port.dev);
+}
+
 #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
 
 #ifdef CONFIG_CONSOLE_POLL
@@ -164,223 +428,76 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
 }
 #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
 
-#if defined(__H8300H__) || defined(__H8300S__)
 static void sci_init_pins(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);
-
-       /* tx mark output*/
-       H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       if (port->mapbase == 0xA4400000) {
-               __raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
-               __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
-       } else if (port->mapbase == 0xA4410000)
-               __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
-
-       if (cflag & CRTSCTS) {
-               /* enable RTS/CTS */
-               if (port->mapbase == 0xa4430000) { /* SCIF0 */
-                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
-                       data = __raw_readw(PORT_PTCR);
-                       __raw_writew((data & 0xfc03), PORT_PTCR);
-               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
-                       /* Clear PVCR bit 9-2 */
-                       data = __raw_readw(PORT_PVCR);
-                       __raw_writew((data & 0xfc03), PORT_PVCR);
-               }
-       } else {
-               if (port->mapbase == 0xa4430000) { /* SCIF0 */
-                       /* Clear PTCR bit 5-2; enable only tx and rx  */
-                       data = __raw_readw(PORT_PTCR);
-                       __raw_writew((data & 0xffc3), PORT_PTCR);
-               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
-                       /* Clear PVCR bit 5-2 */
-                       data = __raw_readw(PORT_PVCR);
-                       __raw_writew((data & 0xffc3), PORT_PVCR);
-               }
-       }
-}
-#elif defined(CONFIG_CPU_SH3)
-/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
-
-       /* We need to set SCPCR to enable RTS/CTS */
-       data = __raw_readw(SCPCR);
-       /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
-       __raw_writew(data & 0x0fcf, SCPCR);
-
-       if (!(cflag & CRTSCTS)) {
-               /* We need to set SCPCR to enable RTS/CTS */
-               data = __raw_readw(SCPCR);
-               /* Clear out SCP7MD1,0, SCP4MD1,0,
-                  Set SCP6MD1,0 = {01} (output)  */
-               __raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
+       struct sci_port *s = to_sci_port(port);
+       struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
 
-               data = __raw_readb(SCPDR);
-               /* Set /RTS2 (bit6) = 0 */
-               __raw_writeb(data & 0xbf, SCPDR);
+       /*
+        * Use port-specific handler if provided.
+        */
+       if (s->cfg->ops && s->cfg->ops->init_pins) {
+               s->cfg->ops->init_pins(port, cflag);
+               return;
        }
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       unsigned short data;
 
-       if (port->mapbase == 0xffe00000) {
-               data = __raw_readw(PSCR);
-               data &= ~0x03cf;
-               if (!(cflag & CRTSCTS))
-                       data |= 0x0340;
+       /*
+        * For the generic path SCSPTR is necessary. Bail out if that's
+        * unavailable, too.
+        */
+       if (!reg->size)
+               return;
 
-               __raw_writew(data, PSCR);
-       }
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7763) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7786) || \
-      defined(CONFIG_CPU_SUBTYPE_SHX3)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       if (!(cflag & CRTSCTS))
-               __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */
-}
-#elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A)
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
        if (!(cflag & CRTSCTS))
-               __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */
+               sci_out(port, SCSPTR, 0x0080); /* Set RTS = 1 */
 }
-#else
-static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
-{
-       /* Nothing to do */
-}
-#endif
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7786)
-static int scif_txfill(struct uart_port *port)
+static int sci_txfill(struct uart_port *port)
 {
-       return sci_in(port, SCTFDR) & 0xff;
-}
+       struct plat_sci_reg *reg;
 
-static int scif_txroom(struct uart_port *port)
-{
-       return SCIF_TXROOM_MAX - scif_txfill(port);
-}
-
-static int scif_rxfill(struct uart_port *port)
-{
-       return sci_in(port, SCRFDR) & 0xff;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-static int scif_txfill(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000 ||
-           port->mapbase == 0xffe08000)
-               /* SCIF0/1*/
+       reg = sci_getreg(port, SCTFDR);
+       if (reg->size)
                return sci_in(port, SCTFDR) & 0xff;
-       else
-               /* SCIF2 */
+
+       reg = sci_getreg(port, SCFDR);
+       if (reg->size)
                return sci_in(port, SCFDR) >> 8;
-}
 
-static int scif_txroom(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000 ||
-           port->mapbase == 0xffe08000)
-               /* SCIF0/1*/
-               return SCIF_TXROOM_MAX - scif_txfill(port);
-       else
-               /* SCIF2 */
-               return SCIF2_TXROOM_MAX - scif_txfill(port);
+       return !(sci_in(port, SCxSR) & SCI_TDRE);
 }
 
-static int scif_rxfill(struct uart_port *port)
-{
-       if ((port->mapbase == 0xffe00000) ||
-           (port->mapbase == 0xffe08000)) {
-               /* SCIF0/1*/
-               return sci_in(port, SCRFDR) & 0xff;
-       } else {
-               /* SCIF2 */
-               return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
-       }
-}
-#elif defined(CONFIG_ARCH_SH7372)
-static int scif_txfill(struct uart_port *port)
+static int sci_txroom(struct uart_port *port)
 {
-       if (port->type == PORT_SCIFA)
-               return sci_in(port, SCFDR) >> 8;
-       else
-               return sci_in(port, SCTFDR);
+       return port->fifosize - sci_txfill(port);
 }
 
-static int scif_txroom(struct uart_port *port)
+static int sci_rxfill(struct uart_port *port)
 {
-       return port->fifosize - scif_txfill(port);
-}
+       struct plat_sci_reg *reg;
 
-static int scif_rxfill(struct uart_port *port)
-{
-       if (port->type == PORT_SCIFA)
-               return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
-       else
-               return sci_in(port, SCRFDR);
-}
-#else
-static int scif_txfill(struct uart_port *port)
-{
-       return sci_in(port, SCFDR) >> 8;
-}
+       reg = sci_getreg(port, SCRFDR);
+       if (reg->size)
+               return sci_in(port, SCRFDR) & 0xff;
 
-static int scif_txroom(struct uart_port *port)
-{
-       return SCIF_TXROOM_MAX - scif_txfill(port);
-}
+       reg = sci_getreg(port, SCFDR);
+       if (reg->size)
+               return sci_in(port, SCFDR) & ((port->fifosize << 1) - 1);
 
-static int scif_rxfill(struct uart_port *port)
-{
-       return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+       return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
 }
-#endif
 
-static int sci_txfill(struct uart_port *port)
+/*
+ * SCI helper for checking the state of the muxed port/RXD pins.
+ */
+static inline int sci_rxd_in(struct uart_port *port)
 {
-       return !(sci_in(port, SCxSR) & SCI_TDRE);
-}
+       struct sci_port *s = to_sci_port(port);
 
-static int sci_txroom(struct uart_port *port)
-{
-       return !sci_txfill(port);
-}
+       if (s->cfg->port_reg <= 0)
+               return 1;
 
-static int sci_rxfill(struct uart_port *port)
-{
-       return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
+       return !!__raw_readb(s->cfg->port_reg);
 }
 
 /* ********************************************************************** *
@@ -406,10 +523,7 @@ static void sci_transmit_chars(struct uart_port *port)
                return;
        }
 
-       if (port->type == PORT_SCI)
-               count = sci_txroom(port);
-       else
-               count = scif_txroom(port);
+       count = sci_txroom(port);
 
        do {
                unsigned char c;
@@ -464,13 +578,8 @@ static void sci_receive_chars(struct uart_port *port)
                return;
 
        while (1) {
-               if (port->type == PORT_SCI)
-                       count = sci_rxfill(port);
-               else
-                       count = scif_rxfill(port);
-
                /* Don't copy more bytes than there is room for in the buffer */
-               count = tty_buffer_request_room(tty, count);
+               count = tty_buffer_request_room(tty, sci_rxfill(port));
 
                /* If for any reason we can't copy more data, we're done! */
                if (count == 0)
@@ -561,8 +670,7 @@ static void sci_break_timer(unsigned long data)
 {
        struct sci_port *port = (struct sci_port *)data;
 
-       if (port->enable)
-               port->enable(&port->port);
+       sci_port_enable(port);
 
        if (sci_rxd_in(&port->port) == 0) {
                port->break_flag = 1;
@@ -574,8 +682,7 @@ static void sci_break_timer(unsigned long data)
        } else
                port->break_flag = 0;
 
-       if (port->disable)
-               port->disable(&port->port);
+       sci_port_disable(port);
 }
 
 static int sci_handle_errors(struct uart_port *port)
@@ -583,13 +690,19 @@ static int sci_handle_errors(struct uart_port *port)
        int copied = 0;
        unsigned short status = sci_in(port, SCxSR);
        struct tty_struct *tty = port->state->port.tty;
+       struct sci_port *s = to_sci_port(port);
 
-       if (status & SCxSR_ORER(port)) {
-               /* overrun error */
-               if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
-                       copied++;
+       /*
+        * Handle overruns, if supported.
+        */
+       if (s->cfg->overrun_bit != SCIx_NOT_SUPPORTED) {
+               if (status & (1 << s->cfg->overrun_bit)) {
+                       /* overrun error */
+                       if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
+                               copied++;
 
-               dev_notice(port->dev, "overrun error");
+                       dev_notice(port->dev, "overrun error");
+               }
        }
 
        if (status & SCxSR_FER(port)) {
@@ -637,12 +750,15 @@ static int sci_handle_errors(struct uart_port *port)
 static int sci_handle_fifo_overrun(struct uart_port *port)
 {
        struct tty_struct *tty = port->state->port.tty;
+       struct sci_port *s = to_sci_port(port);
+       struct plat_sci_reg *reg;
        int copied = 0;
 
-       if (port->type != PORT_SCIF)
+       reg = sci_getreg(port, SCLSR);
+       if (!reg->size)
                return 0;
 
-       if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) {
+       if ((sci_in(port, SCLSR) & (1 << s->cfg->overrun_bit))) {
                sci_out(port, SCLSR, 0);
 
                tty_insert_flip_char(tty, 0, TTY_OVERRUN);
@@ -840,74 +956,102 @@ static int sci_notifier(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static void sci_clk_enable(struct uart_port *port)
-{
-       struct sci_port *sci_port = to_sci_port(port);
-
-       pm_runtime_get_sync(port->dev);
+static struct sci_irq_desc {
+       const char      *desc;
+       irq_handler_t   handler;
+} sci_irq_desc[] = {
+       /*
+        * Split out handlers, the default case.
+        */
+       [SCIx_ERI_IRQ] = {
+               .desc = "rx err",
+               .handler = sci_er_interrupt,
+       },
 
-       clk_enable(sci_port->iclk);
-       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
-       clk_enable(sci_port->fclk);
-}
+       [SCIx_RXI_IRQ] = {
+               .desc = "rx full",
+               .handler = sci_rx_interrupt,
+       },
 
-static void sci_clk_disable(struct uart_port *port)
-{
-       struct sci_port *sci_port = to_sci_port(port);
+       [SCIx_TXI_IRQ] = {
+               .desc = "tx empty",
+               .handler = sci_tx_interrupt,
+       },
 
-       clk_disable(sci_port->fclk);
-       clk_disable(sci_port->iclk);
+       [SCIx_BRI_IRQ] = {
+               .desc = "break",
+               .handler = sci_br_interrupt,
+       },
 
-       pm_runtime_put_sync(port->dev);
-}
+       /*
+        * Special muxed handler.
+        */
+       [SCIx_MUX_IRQ] = {
+               .desc = "mux",
+               .handler = sci_mpxed_interrupt,
+       },
+};
 
 static int sci_request_irq(struct sci_port *port)
 {
-       int i;
-       irqreturn_t (*handlers[4])(int irq, void *ptr) = {
-               sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
-               sci_br_interrupt,
-       };
-       const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full",
-                              "SCI Transmit Data Empty", "SCI Break" };
-
-       if (port->cfg->irqs[0] == port->cfg->irqs[1]) {
-               if (unlikely(!port->cfg->irqs[0]))
-                       return -ENODEV;
-
-               if (request_irq(port->cfg->irqs[0], sci_mpxed_interrupt,
-                               IRQF_DISABLED, "sci", port)) {
-                       dev_err(port->port.dev, "Can't allocate IRQ\n");
-                       return -ENODEV;
+       struct uart_port *up = &port->port;
+       int i, j, ret = 0;
+
+       for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) {
+               struct sci_irq_desc *desc;
+               unsigned int irq;
+
+               if (SCIx_IRQ_IS_MUXED(port)) {
+                       i = SCIx_MUX_IRQ;
+                       irq = up->irq;
+               } else
+                       irq = port->cfg->irqs[i];
+
+               desc = sci_irq_desc + i;
+               port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
+                                           dev_name(up->dev), desc->desc);
+               if (!port->irqstr[j]) {
+                       dev_err(up->dev, "Failed to allocate %s IRQ string\n",
+                               desc->desc);
+                       goto out_nomem;
                }
-       } else {
-               for (i = 0; i < ARRAY_SIZE(handlers); i++) {
-                       if (unlikely(!port->cfg->irqs[i]))
-                               continue;
-
-                       if (request_irq(port->cfg->irqs[i], handlers[i],
-                                       IRQF_DISABLED, desc[i], port)) {
-                               dev_err(port->port.dev, "Can't allocate IRQ\n");
-                               return -ENODEV;
-                       }
+
+               ret = request_irq(irq, desc->handler, up->irqflags,
+                                 port->irqstr[j], port);
+               if (unlikely(ret)) {
+                       dev_err(up->dev, "Can't allocate %s IRQ\n", desc->desc);
+                       goto out_noirq;
                }
        }
 
        return 0;
+
+out_noirq:
+       while (--i >= 0)
+               free_irq(port->cfg->irqs[i], port);
+
+out_nomem:
+       while (--j >= 0)
+               kfree(port->irqstr[j]);
+
+       return ret;
 }
 
 static void sci_free_irq(struct sci_port *port)
 {
        int i;
 
-       if (port->cfg->irqs[0] == port->cfg->irqs[1])
-               free_irq(port->cfg->irqs[0], port);
-       else {
-               for (i = 0; i < ARRAY_SIZE(port->cfg->irqs); i++) {
-                       if (!port->cfg->irqs[i])
-                               continue;
+       /*
+        * Intentionally in reverse order so we iterate over the muxed
+        * IRQ first.
+        */
+       for (i = 0; i < SCIx_NR_IRQS; i++) {
+               free_irq(port->cfg->irqs[i], port);
+               kfree(port->irqstr[i]);
 
-                       free_irq(port->cfg->irqs[i], port);
+               if (SCIx_IRQ_IS_MUXED(port)) {
+                       /* If there's only one IRQ, we're done. */
+                       return;
                }
        }
 }
@@ -915,7 +1059,7 @@ static void sci_free_irq(struct sci_port *port)
 static unsigned int sci_tx_empty(struct uart_port *port)
 {
        unsigned short status = sci_in(port, SCxSR);
-       unsigned short in_tx_fifo = scif_txfill(port);
+       unsigned short in_tx_fifo = sci_txfill(port);
 
        return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
 }
@@ -1438,8 +1582,7 @@ static int sci_startup(struct uart_port *port)
 
        dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
 
-       if (s->enable)
-               s->enable(port);
+       sci_port_enable(s);
 
        ret = sci_request_irq(s);
        if (unlikely(ret < 0))
@@ -1465,8 +1608,7 @@ static void sci_shutdown(struct uart_port *port)
        sci_free_dma(port);
        sci_free_irq(s);
 
-       if (s->disable)
-               s->disable(port);
+       sci_port_disable(s);
 }
 
 static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
@@ -1513,8 +1655,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
        if (likely(baud && port->uartclk))
                t = sci_scbrr_calc(s->cfg->scbrr_algo_id, baud, port->uartclk);
 
-       if (s->enable)
-               s->enable(port);
+       sci_port_enable(s);
 
        do {
                status = sci_in(port, SCxSR);
@@ -1584,8 +1725,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
        if ((termios->c_cflag & CREAD) != 0)
                sci_start_rx(port);
 
-       if (s->disable)
-               s->disable(port);
+       sci_port_disable(s);
 }
 
 static const char *sci_type(struct uart_port *port)
@@ -1726,6 +1866,7 @@ static int __devinit sci_init_single(struct platform_device *dev,
                                     struct plat_sci_port *p)
 {
        struct uart_port *port = &sci_port->port;
+       int ret;
 
        port->ops       = &sci_uart_ops;
        port->iotype    = UPIO_MEM;
@@ -1746,6 +1887,12 @@ static int __devinit sci_init_single(struct platform_device *dev,
                break;
        }
 
+       if (p->regtype == SCIx_PROBE_REGTYPE) {
+               ret = sci_probe_regmap(p);
+               if (unlikely(!ret))
+                       return ret;
+       }
+
        if (dev) {
                sci_port->iclk = clk_get(&dev->dev, "sci_ick");
                if (IS_ERR(sci_port->iclk)) {
@@ -1764,8 +1911,6 @@ static int __devinit sci_init_single(struct platform_device *dev,
                if (IS_ERR(sci_port->fclk))
                        sci_port->fclk = NULL;
 
-               sci_port->enable = sci_clk_enable;
-               sci_port->disable = sci_clk_disable;
                port->dev = &dev->dev;
 
                pm_runtime_enable(&dev->dev);
@@ -1775,20 +1920,51 @@ static int __devinit sci_init_single(struct platform_device *dev,
        sci_port->break_timer.function = sci_break_timer;
        init_timer(&sci_port->break_timer);
 
+       /*
+        * Establish some sensible defaults for the error detection.
+        */
+       if (!p->error_mask)
+               p->error_mask = (p->type == PORT_SCI) ?
+                       SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK;
+
+       /*
+        * Establish sensible defaults for the overrun detection, unless
+        * the part has explicitly disabled support for it.
+        */
+       if (p->overrun_bit != SCIx_NOT_SUPPORTED) {
+               if (p->type == PORT_SCI)
+                       p->overrun_bit = 5;
+               else if (p->scbrr_algo_id == SCBRR_ALGO_4)
+                       p->overrun_bit = 9;
+               else
+                       p->overrun_bit = 0;
+
+               /*
+                * Make the error mask inclusive of overrun detection, if
+                * supported.
+                */
+               p->error_mask |= (1 << p->overrun_bit);
+       }
+
        sci_port->cfg           = p;
 
        port->mapbase           = p->mapbase;
        port->type              = p->type;
        port->flags             = p->flags;
+       port->regshift          = p->regshift;
 
        /*
-        * The UART port needs an IRQ value, so we peg this to the TX IRQ
+        * The UART port needs an IRQ value, so we peg this to the RX IRQ
         * for the multi-IRQ ports, which is where we are primarily
         * concerned with the shutdown path synchronization.
         *
         * For the muxed case there's nothing more to do.
         */
        port->irq               = p->irqs[SCIx_RXI_IRQ];
+       port->irqflags          = IRQF_DISABLED;
+
+       port->serial_in         = sci_serial_in;
+       port->serial_out        = sci_serial_out;
 
        if (p->dma_dev)
                dev_dbg(port->dev, "DMA device %p, tx %d, rx %d\n",
@@ -1814,8 +1990,7 @@ static void serial_console_write(struct console *co, const char *s,
        struct uart_port *port = &sci_port->port;
        unsigned short bits;
 
-       if (sci_port->enable)
-               sci_port->enable(port);
+       sci_port_enable(sci_port);
 
        uart_console_write(port, s, count, serial_console_putchar);
 
@@ -1824,8 +1999,7 @@ static void serial_console_write(struct console *co, const char *s,
        while ((sci_in(port, SCxSR) & bits) != bits)
                cpu_relax();
 
-       if (sci_port->disable)
-               sci_port->disable(port);
+       sci_port_disable(sci_port);
 }
 
 static int __devinit serial_console_setup(struct console *co, char *options)
@@ -1857,20 +2031,13 @@ static int __devinit serial_console_setup(struct console *co, char *options)
        if (unlikely(ret != 0))
                return ret;
 
-       if (sci_port->enable)
-               sci_port->enable(port);
+       sci_port_enable(sci_port);
 
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
 
-       ret = uart_set_options(port, co, baud, parity, bits, flow);
-#if defined(__H8300H__) || defined(__H8300S__)
-       /* disable rx interrupt */
-       if (ret == 0)
-               sci_stop_rx(port);
-#endif
        /* TODO: disable clock */
-       return ret;
+       return uart_set_options(port, co, baud, parity, bits, flow);
 }
 
 static struct console serial_console = {
@@ -2081,3 +2248,5 @@ module_exit(sci_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:sh-sci");
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("SuperH SCI(F) serial driver");
index b04d937c9110009ad9bd7507d39332789b5e475e..e9bed038aa1fc11e3c3b2f0ef3c01e967118b846 100644 (file)
 #include <linux/io.h>
 #include <linux/gpio.h>
 
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-#include <asm/regs306x.h>
-#endif
-#if defined(CONFIG_H8S2678)
-#include <asm/regs267x.h>
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7709)
-# define SCPCR  0xA4000116 /* 16 bit SCI and SCIF */
-# define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
-# define SCIF0         0xA4400000
-# define SCIF2         0xA4410000
-# define SCPCR 0xA4000116
-# define SCPDR 0xA4000136
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-      defined(CONFIG_ARCH_SH73A0) || \
-      defined(CONFIG_ARCH_SH7367) || \
-      defined(CONFIG_ARCH_SH7377) || \
-      defined(CONFIG_ARCH_SH7372)
-# define PORT_PTCR        0xA405011EUL
-# define PORT_PVCR        0xA4050122UL
-# define SCIF_ORER        0x0200   /* overrun error bit */
-#elif defined(CONFIG_SH_RTS7751R2D)
-# define SCSPTR1 0xFFE0001C /* 8 bit SCIF */
-# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7091)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751R)
-# define SCSPTR1 0xffe0001c /* 8  bit SCI */
-# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
-# define SCSPTR0 0xfe600024 /* 16 bit SCIF */
-# define SCSPTR1 0xfe610024 /* 16 bit SCIF */
-# define SCSPTR2 0xfe620024 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-# define SCSPTR0 0xA4400000      /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-# define PACR 0xa4050100
-# define PBCR 0xa4050102
-#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
-# define SCSPTR0 0xffe00010    /* 16 bit SCIF */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-# define PADR                  0xA4050120
-# define PSDR                  0xA405013e
-# define PWDR                  0xA4050166
-# define PSCR                  0xA405011E
-# define SCIF_ORER             0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7366)
-# define SCPDR0                        0xA405013E      /* 16 bit SCIF0 PSDR */
-# define SCSPTR0               SCPDR0
-# define SCIF_ORER             0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-# define SCSPTR0                0xa4050160
-# define SCIF_ORER              0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-# define SCIF_ORER              0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
-# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001   /* overrun error bit */
-#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
-# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
-#elif defined(CONFIG_H8S2678)
-# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
-# define SCSPTR0 0xfe4b0020
-# define SCIF_ORER 0x0001
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
-# define SCSPTR0 0xff923020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-# define SCSPTR0       0xffe00024      /* 16 bit SCIF */
-# define SCIF_ORER     0x0001          /* Overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7786)
-# define SCSPTR0       0xffea0024      /* 16 bit SCIF */
-# define SCIF_ORER     0x0001          /* Overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7203) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7263)
-# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
-# define SCSPTR0 0xf8400020 /* 16 bit SCIF */
-# define SCIF_ORER 0x0001  /* overrun error bit */
-#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
-# define SCSPTR0 0xffc30020            /* 16 bit SCIF */
-# define SCIF_ORER 0x0001              /* Overrun error bit */
-#else
-# error CPU subtype not defined
-#endif
-
-/* SCxSR SCI */
-#define SCI_TDRE  0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_RDRF  0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_ORER  0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_FER   0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_PER   0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-#define SCI_TEND  0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/*      SCI_MPB   0x02  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-/*      SCI_MPBT  0x01  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
-
-#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
-
-/* SCxSR SCIF */
-#define SCIF_ER    0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_TEND  0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_TDFE  0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_BRK   0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_FER   0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_PER   0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_RDF   0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
-# define SCIF_ORER    0x0200
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
-# define SCIF_RFDC_MASK 0x007f
-# define SCIF_TXROOM_MAX 64
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK )
-# define SCIF_RFDC_MASK 0x007f
-# define SCIF_TXROOM_MAX 64
-/* SH7763 SCIF2 support */
-# define SCIF2_RFDC_MASK 0x001f
-# define SCIF2_TXROOM_MAX 16
-#else
-# define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
-# define SCIF_RFDC_MASK 0x001f
-# define SCIF_TXROOM_MAX 16
-#endif
-
-#ifndef SCIF_ORER
-#define SCIF_ORER      0x0000
-#endif
-
 #define SCxSR_TEND(port)       (((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
-#define SCxSR_ERRORS(port)     (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
 #define SCxSR_RDxF(port)       (((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
 #define SCxSR_TDxE(port)       (((port)->type == PORT_SCI) ? SCI_TDRE   : SCIF_TDFE)
 #define SCxSR_FER(port)                (((port)->type == PORT_SCI) ? SCI_FER    : SCIF_FER)
 #define SCxSR_PER(port)                (((port)->type == PORT_SCI) ? SCI_PER    : SCIF_PER)
 #define SCxSR_BRK(port)                (((port)->type == PORT_SCI) ? 0x00       : SCIF_BRK)
-#define SCxSR_ORER(port)       (((port)->type == PORT_SCI) ? SCI_ORER   : SCIF_ORER)
+
+#define SCxSR_ERRORS(port)     (to_sci_port(port)->cfg->error_mask)
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
     defined(CONFIG_CPU_SUBTYPE_SH7720) || \
 
 #define SCI_MAJOR              204
 #define SCI_MINOR_START                8
-
-#define SCI_IN(size, offset)                                   \
-  if ((size) == 8) {                                           \
-    return ioread8(port->membase + (offset));                  \
-  } else {                                                     \
-    return ioread16(port->membase + (offset));                 \
-  }
-#define SCI_OUT(size, offset, value)                           \
-  if ((size) == 8) {                                           \
-    iowrite8(value, port->membase + (offset));                 \
-  } else if ((size) == 16) {                                   \
-    iowrite16(value, port->membase + (offset));                        \
-  }
-
-#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
-      SCI_IN(scif_size, scif_offset)                                   \
-    } else {   /* PORT_SCI or PORT_SCIFA */                            \
-      SCI_IN(sci_size, sci_offset);                                    \
-    }                                                                  \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-    if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {         \
-      SCI_OUT(scif_size, scif_offset, value)                           \
-    } else {   /* PORT_SCI or PORT_SCIFA */                            \
-      SCI_OUT(sci_size, sci_offset, value);                            \
-    }                                                                  \
-  }
-
-#ifdef CONFIG_H8300
-/* h8300 don't have SCIF */
-#define CPU_SCIF_FNS(name)                                             \
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    return 0;                                                          \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-  }
-#else
-#define CPU_SCIF_FNS(name, scif_offset, scif_size)                     \
-  static inline unsigned int sci_##name##_in(struct uart_port *port)   \
-  {                                                                    \
-    SCI_IN(scif_size, scif_offset);                                    \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
-  {                                                                    \
-    SCI_OUT(scif_size, scif_offset, value);                            \
-  }
-#endif
-
-#define CPU_SCI_FNS(name, sci_offset, sci_size)                                \
-  static inline unsigned int sci_##name##_in(struct uart_port* port)   \
-  {                                                                    \
-    SCI_IN(sci_size, sci_offset);                                      \
-  }                                                                    \
-  static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \
-  {                                                                    \
-    SCI_OUT(sci_size, sci_offset, value);                              \
-  }
-
-#if defined(CONFIG_CPU_SH3) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_SH7367) || \
-    defined(CONFIG_ARCH_SH7377) || \
-    defined(CONFIG_ARCH_SH7372)
-#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                               sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                                h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-         CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-      defined(CONFIG_ARCH_SH7367)
-#define SCIF_FNS(name, scif_offset, scif_size) \
-  CPU_SCIF_FNS(name, scif_offset, scif_size)
-#elif defined(CONFIG_ARCH_SH7377) || \
-      defined(CONFIG_ARCH_SH7372) || \
-      defined(CONFIG_ARCH_SH73A0)
-#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \
-  CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size)
-#define SCIF_FNS(name, scif_offset, scif_size) \
-  CPU_SCIF_FNS(name, scif_offset, scif_size)
-#else
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                 h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
-#endif
-#elif defined(__H8300H__) || defined(__H8300S__)
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                 h8_sci_offset, h8_sci_size) \
-  CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
-      defined(CONFIG_CPU_SUBTYPE_SH7724)
-        #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \
-                CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size)
-        #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \
-                CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#else
-#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
-                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
-                h8_sci_offset, h8_sci_size) \
-  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
-#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
-  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH7367)
-
-SCIF_FNS(SCSMR,  0x00, 16)
-SCIF_FNS(SCBRR,  0x04,  8)
-SCIF_FNS(SCSCR,  0x08, 16)
-SCIF_FNS(SCxSR,  0x14, 16)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCxTDR, 0x20,  8)
-SCIF_FNS(SCxRDR, 0x24,  8)
-SCIF_FNS(SCLSR,  0x00,  0)
-#elif defined(CONFIG_ARCH_SH7377) || \
-      defined(CONFIG_ARCH_SH7372) || \
-      defined(CONFIG_ARCH_SH73A0)
-SCIF_FNS(SCSMR,  0x00, 16)
-SCIF_FNS(SCBRR,  0x04,  8)
-SCIF_FNS(SCSCR,  0x08, 16)
-SCIF_FNS(SCTDSR, 0x0c, 16)
-SCIF_FNS(SCFER,  0x10, 16)
-SCIF_FNS(SCxSR,  0x14, 16)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCTFDR, 0x38, 16)
-SCIF_FNS(SCRFDR, 0x3c, 16)
-SCIx_FNS(SCxTDR, 0x20,  8, 0x40,  8)
-SCIx_FNS(SCxRDR, 0x24,  8, 0x60,  8)
-SCIF_FNS(SCLSR,  0x00,  0)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
-      defined(CONFIG_CPU_SUBTYPE_SH7724)
-SCIx_FNS(SCSMR,  0x00, 16, 0x00, 16)
-SCIx_FNS(SCBRR,  0x04,  8, 0x04,  8)
-SCIx_FNS(SCSCR,  0x08, 16, 0x08, 16)
-SCIx_FNS(SCxTDR, 0x20,  8, 0x0c,  8)
-SCIx_FNS(SCxSR,  0x14, 16, 0x10, 16)
-SCIx_FNS(SCxRDR, 0x24,  8, 0x14,  8)
-SCIx_FNS(SCSPTR, 0,     0,    0,  0)
-SCIF_FNS(SCFCR,  0x18, 16)
-SCIF_FNS(SCFDR,  0x1c, 16)
-SCIF_FNS(SCLSR,  0x24, 16)
-#else
-/*      reg      SCI/SH3   SCI/SH4  SCIF/SH3   SCIF/SH4  SCI/H8*/
-/*      name     off  sz   off  sz   off  sz   off  sz   off  sz*/
-SCIx_FNS(SCSMR,  0x00,  8, 0x00,  8, 0x00,  8, 0x00, 16, 0x00,  8)
-SCIx_FNS(SCBRR,  0x02,  8, 0x04,  8, 0x02,  8, 0x04,  8, 0x01,  8)
-SCIx_FNS(SCSCR,  0x04,  8, 0x08,  8, 0x04,  8, 0x08, 16, 0x02,  8)
-SCIx_FNS(SCxTDR, 0x06,  8, 0x0c,  8, 0x06,  8, 0x0C,  8, 0x03,  8)
-SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
-SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
-SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7785) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7786)
-SCIF_FNS(SCFDR,                             0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
-SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
-SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
-SCIF_FNS(SCFDR,                                0,  0, 0x1C, 16)
-SCIF_FNS(SCTFDR,                    0x0e, 16, 0x1C, 16)
-SCIF_FNS(SCRFDR,                    0x0e, 16, 0x20, 16)
-SCIF_FNS(SCSPTR,                       0,  0, 0x24, 16)
-SCIF_FNS(SCLSR,                                0,  0, 0x28, 16)
-#else
-SCIF_FNS(SCFDR,                      0x0e, 16, 0x1C, 16)
-#if defined(CONFIG_CPU_SUBTYPE_SH7722)
-SCIF_FNS(SCSPTR,                        0,  0, 0, 0)
-#else
-SCIF_FNS(SCSPTR,                        0,  0, 0x20, 16)
-#endif
-SCIF_FNS(SCLSR,                         0,  0, 0x24, 16)
-#endif
-#endif
-#define sci_in(port, reg) sci_##reg##_in(port)
-#define sci_out(port, reg, value) sci_##reg##_out(port, value)
-
-/* H8/300 series SCI pins assignment */
-#if defined(__H8300H__) || defined(__H8300S__)
-static const struct __attribute__((packed)) {
-       int port;             /* GPIO port no */
-       unsigned short rx,tx; /* GPIO bit no */
-} h8300_sci_pins[] = {
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-       {    /* SCI0 */
-               .port = H8300_GPIO_P9,
-               .rx   = H8300_GPIO_B2,
-               .tx   = H8300_GPIO_B0,
-       },
-       {    /* SCI1 */
-               .port = H8300_GPIO_P9,
-               .rx   = H8300_GPIO_B3,
-               .tx   = H8300_GPIO_B1,
-       },
-       {    /* SCI2 */
-               .port = H8300_GPIO_PB,
-               .rx   = H8300_GPIO_B7,
-               .tx   = H8300_GPIO_B6,
-       }
-#elif defined(CONFIG_H8S2678)
-       {    /* SCI0 */
-               .port = H8300_GPIO_P3,
-               .rx   = H8300_GPIO_B2,
-               .tx   = H8300_GPIO_B0,
-       },
-       {    /* SCI1 */
-               .port = H8300_GPIO_P3,
-               .rx   = H8300_GPIO_B3,
-               .tx   = H8300_GPIO_B1,
-       },
-       {    /* SCI2 */
-               .port = H8300_GPIO_P5,
-               .rx   = H8300_GPIO_B1,
-               .tx   = H8300_GPIO_B0,
-       }
-#endif
-};
-#endif
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7709)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       if (port->mapbase == 0xfffffe80)
-               return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */
-       return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
-      defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7091)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       if (port->mapbase == 0xffe00000)
-               return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
-       return 1;
-}
-#elif defined(__H8300H__) || defined(__H8300S__)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       int ch = (port->mapbase - SMR0) >> 3;
-       return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
-}
-#else /* default case for non-SCI processors */
-static inline int sci_rxd_in(struct uart_port *port)
-{
-       return 1;
-}
-#endif
index 5e807f083bc820e1251fbb7a08e8c023ed462edd..52f8f9e513af3032bbd4692af2f5453868bb01ac 100644 (file)
@@ -124,24 +124,12 @@ uvc_v4l2_open(struct file *file)
        struct video_device *vdev = video_devdata(file);
        struct uvc_device *uvc = video_get_drvdata(vdev);
        struct uvc_file_handle *handle;
-       int ret;
 
        handle = kzalloc(sizeof(*handle), GFP_KERNEL);
        if (handle == NULL)
                return -ENOMEM;
 
-       ret = v4l2_fh_init(&handle->vfh, vdev);
-       if (ret < 0)
-               goto error;
-
-       ret = v4l2_event_init(&handle->vfh);
-       if (ret < 0)
-               goto error;
-
-       ret = v4l2_event_alloc(&handle->vfh, 8);
-       if (ret < 0)
-               goto error;
-
+       v4l2_fh_init(&handle->vfh, vdev);
        v4l2_fh_add(&handle->vfh);
 
        handle->device = &uvc->video;
@@ -149,10 +137,6 @@ uvc_v4l2_open(struct file *file)
 
        uvc_function_connect(uvc);
        return 0;
-
-error:
-       v4l2_fh_exit(&handle->vfh);
-       return ret;
 }
 
 static int
@@ -314,7 +298,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
                        return -EINVAL;
 
-               return v4l2_event_subscribe(&handle->vfh, arg);
+               return v4l2_event_subscribe(&handle->vfh, arg, 2);
        }
 
        case VIDIOC_UNSUBSCRIBE_EVENT:
@@ -354,7 +338,7 @@ uvc_v4l2_poll(struct file *file, poll_table *wait)
        struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
        unsigned int mask = 0;
 
-       poll_wait(file, &handle->vfh.events->wait, wait);
+       poll_wait(file, &handle->vfh.wait, wait);
        if (v4l2_event_pending(&handle->vfh))
                mask |= POLLPRI;
 
index 1e54b8b7f698e464d909de332bc5c7efe594ae4f..69407e72aac1a9291d2ceb3dec812da2063cf94b 100644 (file)
@@ -335,6 +335,13 @@ config BACKLIGHT_PCF50633
          If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
          enable its driver.
 
+config BACKLIGHT_AAT2870
+       bool "AnalogicTech AAT2870 Backlight"
+       depends on BACKLIGHT_CLASS_DEVICE && MFD_AAT2870_CORE
+       help
+         If you have a AnalogicTech AAT2870 say Y to enable the
+         backlight driver.
+
 endif # BACKLIGHT_CLASS_DEVICE
 
 endif # BACKLIGHT_LCD_SUPPORT
index bf1dd92b75272e16dea09fc65a67bfd7a346d53d..fdd1fc4b277062333846f4f9cd3ba75855d394a7 100644 (file)
@@ -38,4 +38,5 @@ obj-$(CONFIG_BACKLIGHT_ADP8860)       += adp8860_bl.o
 obj-$(CONFIG_BACKLIGHT_ADP8870)        += adp8870_bl.o
 obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)       += pcf50633-backlight.o
+obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o
 
diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c
new file mode 100644 (file)
index 0000000..4952a61
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * linux/drivers/video/backlight/aat2870_bl.c
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ * Author: Jin Park <jinyoungp@nvidia.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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/mfd/aat2870.h>
+
+struct aat2870_bl_driver_data {
+       struct platform_device *pdev;
+       struct backlight_device *bd;
+
+       int channels;
+       int max_current;
+       int brightness; /* current brightness */
+};
+
+static inline int aat2870_brightness(struct aat2870_bl_driver_data *aat2870_bl,
+                                    int brightness)
+{
+       struct backlight_device *bd = aat2870_bl->bd;
+       int val;
+
+       val = brightness * aat2870_bl->max_current;
+       val /= bd->props.max_brightness;
+
+       return val;
+}
+
+static inline int aat2870_bl_enable(struct aat2870_bl_driver_data *aat2870_bl)
+{
+       struct aat2870_data *aat2870
+                       = dev_get_drvdata(aat2870_bl->pdev->dev.parent);
+
+       return aat2870->write(aat2870, AAT2870_BL_CH_EN,
+                             (u8)aat2870_bl->channels);
+}
+
+static inline int aat2870_bl_disable(struct aat2870_bl_driver_data *aat2870_bl)
+{
+       struct aat2870_data *aat2870
+                       = dev_get_drvdata(aat2870_bl->pdev->dev.parent);
+
+       return aat2870->write(aat2870, AAT2870_BL_CH_EN, 0x0);
+}
+
+static int aat2870_bl_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int aat2870_bl_update_status(struct backlight_device *bd)
+{
+       struct aat2870_bl_driver_data *aat2870_bl = dev_get_drvdata(&bd->dev);
+       struct aat2870_data *aat2870 =
+                       dev_get_drvdata(aat2870_bl->pdev->dev.parent);
+       int brightness = bd->props.brightness;
+       int ret;
+
+       if ((brightness < 0) || (bd->props.max_brightness < brightness)) {
+               dev_err(&bd->dev, "invalid brightness, %d\n", brightness);
+               return -EINVAL;
+       }
+
+       dev_dbg(&bd->dev, "brightness=%d, power=%d, state=%d\n",
+                bd->props.brightness, bd->props.power, bd->props.state);
+
+       if ((bd->props.power != FB_BLANK_UNBLANK) ||
+                       (bd->props.state & BL_CORE_FBBLANK) ||
+                       (bd->props.state & BL_CORE_SUSPENDED))
+               brightness = 0;
+
+       ret = aat2870->write(aat2870, AAT2870_BLM,
+                            (u8)aat2870_brightness(aat2870_bl, brightness));
+       if (ret < 0)
+               return ret;
+
+       if (brightness == 0) {
+               ret = aat2870_bl_disable(aat2870_bl);
+               if (ret < 0)
+                       return ret;
+       } else if (aat2870_bl->brightness == 0) {
+               ret = aat2870_bl_enable(aat2870_bl);
+               if (ret < 0)
+                       return ret;
+       }
+
+       aat2870_bl->brightness = brightness;
+
+       return 0;
+}
+
+static int aat2870_bl_check_fb(struct backlight_device *bd, struct fb_info *fi)
+{
+       return 1;
+}
+
+static const struct backlight_ops aat2870_bl_ops = {
+       .options = BL_CORE_SUSPENDRESUME,
+       .get_brightness = aat2870_bl_get_brightness,
+       .update_status = aat2870_bl_update_status,
+       .check_fb = aat2870_bl_check_fb,
+};
+
+static int aat2870_bl_probe(struct platform_device *pdev)
+{
+       struct aat2870_bl_platform_data *pdata = pdev->dev.platform_data;
+       struct aat2870_bl_driver_data *aat2870_bl;
+       struct backlight_device *bd;
+       struct backlight_properties props;
+       int ret = 0;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform data\n");
+               ret = -ENXIO;
+               goto out;
+       }
+
+       if (pdev->id != AAT2870_ID_BL) {
+               dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       aat2870_bl = kzalloc(sizeof(struct aat2870_bl_driver_data), GFP_KERNEL);
+       if (!aat2870_bl) {
+               dev_err(&pdev->dev,
+                       "Failed to allocate memory for aat2870 backlight\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+
+       props.type = BACKLIGHT_RAW;
+       bd = backlight_device_register("aat2870-backlight", &pdev->dev,
+                                      aat2870_bl, &aat2870_bl_ops, &props);
+       if (!bd) {
+               dev_err(&pdev->dev,
+                       "Failed allocate memory for backlight device\n");
+               ret = -ENOMEM;
+               goto out_kfree;
+       }
+
+       aat2870_bl->pdev = pdev;
+       platform_set_drvdata(pdev, aat2870_bl);
+
+       aat2870_bl->bd = bd;
+
+       if (pdata->channels > 0)
+               aat2870_bl->channels = pdata->channels;
+       else
+               aat2870_bl->channels = AAT2870_BL_CH_ALL;
+
+       if (pdata->max_brightness > 0)
+               aat2870_bl->max_current = pdata->max_current;
+       else
+               aat2870_bl->max_current = AAT2870_CURRENT_27_9;
+
+       if (pdata->max_brightness > 0)
+               bd->props.max_brightness = pdata->max_brightness;
+       else
+               bd->props.max_brightness = 255;
+
+       aat2870_bl->brightness = 0;
+       bd->props.power = FB_BLANK_UNBLANK;
+       bd->props.brightness = bd->props.max_brightness;
+
+       ret = aat2870_bl_update_status(bd);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to initialize\n");
+               goto out_bl_dev_unregister;
+       }
+
+       return 0;
+
+out_bl_dev_unregister:
+       backlight_device_unregister(bd);
+out_kfree:
+       kfree(aat2870_bl);
+out:
+       return ret;
+}
+
+static int aat2870_bl_remove(struct platform_device *pdev)
+{
+       struct aat2870_bl_driver_data *aat2870_bl = platform_get_drvdata(pdev);
+       struct backlight_device *bd = aat2870_bl->bd;
+
+       bd->props.power = FB_BLANK_POWERDOWN;
+       bd->props.brightness = 0;
+       backlight_update_status(bd);
+
+       backlight_device_unregister(bd);
+       kfree(aat2870_bl);
+
+       return 0;
+}
+
+static struct platform_driver aat2870_bl_driver = {
+       .driver = {
+               .name   = "aat2870-backlight",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = aat2870_bl_probe,
+       .remove         = aat2870_bl_remove,
+};
+
+static int __init aat2870_bl_init(void)
+{
+       return platform_driver_register(&aat2870_bl_driver);
+}
+subsys_initcall(aat2870_bl_init);
+
+static void __exit aat2870_bl_exit(void)
+{
+       platform_driver_unregister(&aat2870_bl_driver);
+}
+module_exit(aat2870_bl_exit);
+
+MODULE_DESCRIPTION("AnalogicTech AAT2870 Backlight");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
index fdd5d4ae437df9e3901f3891e07f188e14596e67..4e888ac09b3f4a79de6b263d275684affca45ba0 100644 (file)
@@ -504,14 +504,18 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
                return 0;
 
        r = omapdss_dsi_display_enable(dssdev);
-       if (r)
-               goto err;
+       if (r) {
+               dev_err(&dssdev->dev, "failed to enable DSI\n");
+               goto err1;
+       }
 
        omapdss_dsi_vc_enable_hs(dssdev, td->channel, true);
 
        r = _taal_enable_te(dssdev, true);
-       if (r)
-               goto err;
+       if (r) {
+               dev_err(&dssdev->dev, "failed to re-enable TE");
+               goto err2;
+       }
 
        enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
 
@@ -521,13 +525,15 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev)
 
        return 0;
 
-err:
-       dev_err(&dssdev->dev, "exit ULPS failed");
-       r = taal_panel_reset(dssdev);
-
-       enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
-       td->ulps_enabled = false;
+err2:
+       dev_err(&dssdev->dev, "failed to exit ULPS");
 
+       r = taal_panel_reset(dssdev);
+       if (!r) {
+               enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+               td->ulps_enabled = false;
+       }
+err1:
        taal_queue_ulps_work(dssdev);
 
        return r;
@@ -1241,11 +1247,8 @@ static void taal_power_off(struct omap_dss_device *dssdev)
        int r;
 
        r = taal_dcs_write_0(td, DCS_DISPLAY_OFF);
-       if (!r) {
+       if (!r)
                r = taal_sleep_in(td);
-               /* HACK: wait a bit so that the message goes through */
-               msleep(10);
-       }
 
        if (r) {
                dev_err(&dssdev->dev,
@@ -1317,8 +1320,11 @@ static void taal_disable(struct omap_dss_device *dssdev)
        dsi_bus_lock(dssdev);
 
        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
-               taal_wake_up(dssdev);
-               taal_power_off(dssdev);
+               int r;
+
+               r = taal_wake_up(dssdev);
+               if (!r)
+                       taal_power_off(dssdev);
        }
 
        dsi_bus_unlock(dssdev);
@@ -1897,20 +1903,6 @@ err:
        mutex_unlock(&td->lock);
 }
 
-static int taal_set_update_mode(struct omap_dss_device *dssdev,
-               enum omap_dss_update_mode mode)
-{
-       if (mode != OMAP_DSS_UPDATE_MANUAL)
-               return -EINVAL;
-       return 0;
-}
-
-static enum omap_dss_update_mode taal_get_update_mode(
-               struct omap_dss_device *dssdev)
-{
-       return OMAP_DSS_UPDATE_MANUAL;
-}
-
 static struct omap_dss_driver taal_driver = {
        .probe          = taal_probe,
        .remove         = __exit_p(taal_remove),
@@ -1920,9 +1912,6 @@ static struct omap_dss_driver taal_driver = {
        .suspend        = taal_suspend,
        .resume         = taal_resume,
 
-       .set_update_mode = taal_set_update_mode,
-       .get_update_mode = taal_get_update_mode,
-
        .update         = taal_update,
        .sync           = taal_sync,
 
index 6b3e2da11419497687b0a4a9449a793aa338a09a..0d12524db14bd7c8b45f1d5813143335bd19cd0a 100644 (file)
@@ -117,18 +117,6 @@ config OMAP2_DSS_MIN_FCK_PER_PCK
          Max FCK is 173MHz, so this doesn't work if your PCK
          is very high.
 
-config OMAP2_DSS_SLEEP_BEFORE_RESET
-       bool "Sleep 50ms before DSS reset"
-       default y
-       help
-         For some unknown reason we may get SYNC_LOST errors from the display
-         subsystem at initialization time if we don't sleep before resetting
-         the DSS. See the source (dss.c) for more comments.
-
-         However, 50ms is quite long time to sleep, and with some
-         configurations the SYNC_LOST may never happen, so the sleep can
-         be disabled here.
-
 config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
        bool "Sleep 20ms after VENC reset"
        default y
index 3da426719dd6e50f9451a60d1a592a6ef79ef83d..76821fefce9a9729a6134aa06e36906bfb3eb213 100644 (file)
@@ -183,8 +183,11 @@ static int omap_dss_probe(struct platform_device *pdev)
                goto err_dss;
        }
 
-       /* keep clocks enabled to prevent context saves/restores during init */
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       r = dispc_init_platform_driver();
+       if (r) {
+               DSSERR("Failed to initialize dispc platform driver\n");
+               goto err_dispc;
+       }
 
        r = rfbi_init_platform_driver();
        if (r) {
@@ -192,12 +195,6 @@ static int omap_dss_probe(struct platform_device *pdev)
                goto err_rfbi;
        }
 
-       r = dispc_init_platform_driver();
-       if (r) {
-               DSSERR("Failed to initialize dispc platform driver\n");
-               goto err_dispc;
-       }
-
        r = venc_init_platform_driver();
        if (r) {
                DSSERR("Failed to initialize venc platform driver\n");
@@ -238,8 +235,6 @@ static int omap_dss_probe(struct platform_device *pdev)
                        pdata->default_device = dssdev;
        }
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
-
        return 0;
 
 err_register:
@@ -268,11 +263,11 @@ static int omap_dss_remove(struct platform_device *pdev)
 
        dss_uninitialize_debugfs();
 
+       hdmi_uninit_platform_driver();
+       dsi_uninit_platform_driver();
        venc_uninit_platform_driver();
-       dispc_uninit_platform_driver();
        rfbi_uninit_platform_driver();
-       dsi_uninit_platform_driver();
-       hdmi_uninit_platform_driver();
+       dispc_uninit_platform_driver();
        dss_uninit_platform_driver();
 
        dss_uninit_overlays(pdev);
index 7a9a2e7d968530f9bac3000d086e4a2eac531d7f..0f3961a1ce26b47887adfacad6a417f975ec4044 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/workqueue.h>
 #include <linux/hardirq.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/sram.h>
 #include <plat/clock.h>
@@ -77,6 +79,12 @@ struct dispc_v_coef {
        s8 vc00;
 };
 
+enum omap_burst_size {
+       BURST_SIZE_X2 = 0,
+       BURST_SIZE_X4 = 1,
+       BURST_SIZE_X8 = 2,
+};
+
 #define REG_GET(idx, start, end) \
        FLD_GET(dispc_read_reg(idx), start, end)
 
@@ -92,7 +100,11 @@ struct dispc_irq_stats {
 static struct {
        struct platform_device *pdev;
        void __iomem    *base;
+
+       int             ctx_loss_cnt;
+
        int irq;
+       struct clk *dss_clk;
 
        u32     fifo_size[3];
 
@@ -102,6 +114,7 @@ static struct {
        u32 error_irqs;
        struct work_struct error_work;
 
+       bool            ctx_valid;
        u32             ctx[DISPC_SZ_REGS / sizeof(u32)];
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
@@ -134,18 +147,34 @@ static inline u32 dispc_read_reg(const u16 idx)
        return __raw_readl(dispc.base + idx);
 }
 
+static int dispc_get_ctx_loss_count(void)
+{
+       struct device *dev = &dispc.pdev->dev;
+       struct omap_display_platform_data *pdata = dev->platform_data;
+       struct omap_dss_board_info *board_data = pdata->board_data;
+       int cnt;
+
+       if (!board_data->get_context_loss_count)
+               return -ENOENT;
+
+       cnt = board_data->get_context_loss_count(dev);
+
+       WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt);
+
+       return cnt;
+}
+
 #define SR(reg) \
        dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
 #define RR(reg) \
        dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
 
-void dispc_save_context(void)
+static void dispc_save_context(void)
 {
        int i;
-       if (cpu_is_omap24xx())
-               return;
 
-       SR(SYSCONFIG);
+       DSSDBG("dispc_save_context\n");
+
        SR(IRQENABLE);
        SR(CONTROL);
        SR(CONFIG);
@@ -158,7 +187,8 @@ void dispc_save_context(void)
        SR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
        SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
        SR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
-       SR(GLOBAL_ALPHA);
+       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+               SR(GLOBAL_ALPHA);
        SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
        SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
@@ -188,20 +218,25 @@ void dispc_save_context(void)
        SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
        SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
 
-       SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
-       SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
-       SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       if (dss_has_feature(FEAT_CPR)) {
+               SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+               SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+               SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       }
        if (dss_has_feature(FEAT_MGR_LCD2)) {
-               SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
-               SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
-               SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+               if (dss_has_feature(FEAT_CPR)) {
+                       SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+                       SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+                       SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+               }
 
                SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
                SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
                SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
        }
 
-       SR(OVL_PRELOAD(OMAP_DSS_GFX));
+       if (dss_has_feature(FEAT_PRELOAD))
+               SR(OVL_PRELOAD(OMAP_DSS_GFX));
 
        /* VID1 */
        SR(OVL_BA0(OMAP_DSS_VIDEO1));
@@ -226,8 +261,10 @@ void dispc_save_context(void)
        for (i = 0; i < 5; i++)
                SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
 
-       for (i = 0; i < 8; i++)
-               SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                SR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
@@ -248,7 +285,8 @@ void dispc_save_context(void)
        if (dss_has_feature(FEAT_ATTR2))
                SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
 
-       SR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
+       if (dss_has_feature(FEAT_PRELOAD))
+               SR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
 
        /* VID2 */
        SR(OVL_BA0(OMAP_DSS_VIDEO2));
@@ -273,8 +311,10 @@ void dispc_save_context(void)
        for (i = 0; i < 5; i++)
                SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
 
-       for (i = 0; i < 8; i++)
-               SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                SR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
@@ -295,16 +335,35 @@ void dispc_save_context(void)
        if (dss_has_feature(FEAT_ATTR2))
                SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
 
-       SR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
+       if (dss_has_feature(FEAT_PRELOAD))
+               SR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                SR(DIVISOR);
+
+       dispc.ctx_loss_cnt = dispc_get_ctx_loss_count();
+       dispc.ctx_valid = true;
+
+       DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt);
 }
 
-void dispc_restore_context(void)
+static void dispc_restore_context(void)
 {
-       int i;
-       RR(SYSCONFIG);
+       int i, ctx;
+
+       DSSDBG("dispc_restore_context\n");
+
+       if (!dispc.ctx_valid)
+               return;
+
+       ctx = dispc_get_ctx_loss_count();
+
+       if (ctx >= 0 && ctx == dispc.ctx_loss_cnt)
+               return;
+
+       DSSDBG("ctx_loss_count: saved %d, current %d\n",
+                       dispc.ctx_loss_cnt, ctx);
+
        /*RR(IRQENABLE);*/
        /*RR(CONTROL);*/
        RR(CONFIG);
@@ -317,7 +376,8 @@ void dispc_restore_context(void)
        RR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
        RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
        RR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
-       RR(GLOBAL_ALPHA);
+       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+               RR(GLOBAL_ALPHA);
        RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
        RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
@@ -347,20 +407,25 @@ void dispc_restore_context(void)
        RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
        RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
 
-       RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
-       RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
-       RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       if (dss_has_feature(FEAT_CPR)) {
+               RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+               RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+               RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       }
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
                RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
                RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
 
-               RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
-               RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
-               RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+               if (dss_has_feature(FEAT_CPR)) {
+                       RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+                       RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+                       RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+               }
        }
 
-       RR(OVL_PRELOAD(OMAP_DSS_GFX));
+       if (dss_has_feature(FEAT_PRELOAD))
+               RR(OVL_PRELOAD(OMAP_DSS_GFX));
 
        /* VID1 */
        RR(OVL_BA0(OMAP_DSS_VIDEO1));
@@ -385,8 +450,10 @@ void dispc_restore_context(void)
        for (i = 0; i < 5; i++)
                RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
 
-       for (i = 0; i < 8; i++)
-               RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                RR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
@@ -407,7 +474,8 @@ void dispc_restore_context(void)
        if (dss_has_feature(FEAT_ATTR2))
                RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
 
-       RR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
+       if (dss_has_feature(FEAT_PRELOAD))
+               RR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
 
        /* VID2 */
        RR(OVL_BA0(OMAP_DSS_VIDEO2));
@@ -432,8 +500,10 @@ void dispc_restore_context(void)
        for (i = 0; i < 5; i++)
                RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
 
-       for (i = 0; i < 8; i++)
-               RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                RR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
@@ -454,7 +524,8 @@ void dispc_restore_context(void)
        if (dss_has_feature(FEAT_ATTR2))
                RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
 
-       RR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
+       if (dss_has_feature(FEAT_PRELOAD))
+               RR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                RR(DIVISOR);
@@ -471,19 +542,35 @@ void dispc_restore_context(void)
         * the context is fully restored
         */
        RR(IRQENABLE);
+
+       DSSDBG("context restored\n");
 }
 
 #undef SR
 #undef RR
 
-static inline void enable_clocks(bool enable)
+int dispc_runtime_get(void)
 {
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       int r;
+
+       DSSDBG("dispc_runtime_get\n");
+
+       r = pm_runtime_get_sync(&dispc.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
 }
 
+void dispc_runtime_put(void)
+{
+       int r;
+
+       DSSDBG("dispc_runtime_put\n");
+
+       r = pm_runtime_put(&dispc.pdev->dev);
+       WARN_ON(r < 0);
+}
+
+
 bool dispc_go_busy(enum omap_channel channel)
 {
        int bit;
@@ -505,8 +592,6 @@ void dispc_go(enum omap_channel channel)
        int bit;
        bool enable_bit, go_bit;
 
-       enable_clocks(1);
-
        if (channel == OMAP_DSS_CHANNEL_LCD ||
                        channel == OMAP_DSS_CHANNEL_LCD2)
                bit = 0; /* LCDENABLE */
@@ -520,7 +605,7 @@ void dispc_go(enum omap_channel channel)
                enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
 
        if (!enable_bit)
-               goto end;
+               return;
 
        if (channel == OMAP_DSS_CHANNEL_LCD ||
                        channel == OMAP_DSS_CHANNEL_LCD2)
@@ -535,7 +620,7 @@ void dispc_go(enum omap_channel channel)
 
        if (go_bit) {
                DSSERR("GO bit not down for channel %d\n", channel);
-               goto end;
+               return;
        }
 
        DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" :
@@ -545,8 +630,6 @@ void dispc_go(enum omap_channel channel)
                REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit);
        else
                REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
-end:
-       enable_clocks(0);
 }
 
 static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
@@ -920,7 +1003,7 @@ static void _dispc_set_color_mode(enum omap_plane plane,
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
 }
 
-static void _dispc_set_channel_out(enum omap_plane plane,
+void dispc_set_channel_out(enum omap_plane plane,
                enum omap_channel channel)
 {
        int shift;
@@ -967,13 +1050,10 @@ static void _dispc_set_channel_out(enum omap_plane plane,
        dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 }
 
-void dispc_set_burst_size(enum omap_plane plane,
+static void dispc_set_burst_size(enum omap_plane plane,
                enum omap_burst_size burst_size)
 {
        int shift;
-       u32 val;
-
-       enable_clocks(1);
 
        switch (plane) {
        case OMAP_DSS_GFX:
@@ -988,11 +1068,24 @@ void dispc_set_burst_size(enum omap_plane plane,
                return;
        }
 
-       val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
-       val = FLD_MOD(val, burst_size, shift+1, shift);
-       dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
+}
 
-       enable_clocks(0);
+static void dispc_configure_burst_sizes(void)
+{
+       int i;
+       const int burst_size = BURST_SIZE_X8;
+
+       /* Configure burst size always to maximum size */
+       for (i = 0; i < omap_dss_get_num_overlays(); ++i)
+               dispc_set_burst_size(i, burst_size);
+}
+
+u32 dispc_get_burst_size(enum omap_plane plane)
+{
+       unsigned unit = dss_feat_get_burst_size_unit();
+       /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
+       return unit * 8;
 }
 
 void dispc_enable_gamma_table(bool enable)
@@ -1009,6 +1102,40 @@ void dispc_enable_gamma_table(bool enable)
        REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
 }
 
+void dispc_enable_cpr(enum omap_channel channel, bool enable)
+{
+       u16 reg;
+
+       if (channel == OMAP_DSS_CHANNEL_LCD)
+               reg = DISPC_CONFIG;
+       else if (channel == OMAP_DSS_CHANNEL_LCD2)
+               reg = DISPC_CONFIG2;
+       else
+               return;
+
+       REG_FLD_MOD(reg, enable, 15, 15);
+}
+
+void dispc_set_cpr_coef(enum omap_channel channel,
+               struct omap_dss_cpr_coefs *coefs)
+{
+       u32 coef_r, coef_g, coef_b;
+
+       if (channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2)
+               return;
+
+       coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
+               FLD_VAL(coefs->rb, 9, 0);
+       coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
+               FLD_VAL(coefs->gb, 9, 0);
+       coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
+               FLD_VAL(coefs->bb, 9, 0);
+
+       dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
+       dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
+       dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
+}
+
 static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
 {
        u32 val;
@@ -1029,9 +1156,7 @@ void dispc_enable_replication(enum omap_plane plane, bool enable)
        else
                bit = 10;
 
-       enable_clocks(1);
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
-       enable_clocks(0);
 }
 
 void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
@@ -1039,9 +1164,7 @@ void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
        u32 val;
        BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
-       enable_clocks(1);
        dispc_write_reg(DISPC_SIZE_MGR(channel), val);
-       enable_clocks(0);
 }
 
 void dispc_set_digit_size(u16 width, u16 height)
@@ -1049,9 +1172,7 @@ void dispc_set_digit_size(u16 width, u16 height)
        u32 val;
        BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
-       enable_clocks(1);
        dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val);
-       enable_clocks(0);
 }
 
 static void dispc_read_plane_fifo_sizes(void)
@@ -1059,18 +1180,17 @@ static void dispc_read_plane_fifo_sizes(void)
        u32 size;
        int plane;
        u8 start, end;
+       u32 unit;
 
-       enable_clocks(1);
+       unit = dss_feat_get_buffer_size_unit();
 
        dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
 
        for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
-               size = FLD_GET(dispc_read_reg(DISPC_OVL_FIFO_SIZE_STATUS(plane)),
-                       start, end);
+               size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end);
+               size *= unit;
                dispc.fifo_size[plane] = size;
        }
-
-       enable_clocks(0);
 }
 
 u32 dispc_get_plane_fifo_size(enum omap_plane plane)
@@ -1078,15 +1198,22 @@ u32 dispc_get_plane_fifo_size(enum omap_plane plane)
        return dispc.fifo_size[plane];
 }
 
-void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
+void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
 {
        u8 hi_start, hi_end, lo_start, lo_end;
+       u32 unit;
+
+       unit = dss_feat_get_buffer_size_unit();
+
+       WARN_ON(low % unit != 0);
+       WARN_ON(high % unit != 0);
+
+       low /= unit;
+       high /= unit;
 
        dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
        dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
 
-       enable_clocks(1);
-
        DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
                        plane,
                        REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
@@ -1098,18 +1225,12 @@ void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
        dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
                        FLD_VAL(high, hi_start, hi_end) |
                        FLD_VAL(low, lo_start, lo_end));
-
-       enable_clocks(0);
 }
 
 void dispc_enable_fifomerge(bool enable)
 {
-       enable_clocks(1);
-
        DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
        REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
-
-       enable_clocks(0);
 }
 
 static void _dispc_set_fir(enum omap_plane plane,
@@ -1729,14 +1850,7 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width,
        return dispc_pclk_rate(channel) * vf * hf;
 }
 
-void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
-{
-       enable_clocks(1);
-       _dispc_set_channel_out(plane, channel_out);
-       enable_clocks(0);
-}
-
-static int _dispc_setup_plane(enum omap_plane plane,
+int dispc_setup_plane(enum omap_plane plane,
                u32 paddr, u16 screen_width,
                u16 pos_x, u16 pos_y,
                u16 width, u16 height,
@@ -1744,7 +1858,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
                enum omap_color_mode color_mode,
                bool ilace,
                enum omap_dss_rotation_type rotation_type,
-               u8 rotation, int mirror,
+               u8 rotation, bool mirror,
                u8 global_alpha, u8 pre_mult_alpha,
                enum omap_channel channel, u32 puv_addr)
 {
@@ -1758,6 +1872,14 @@ static int _dispc_setup_plane(enum omap_plane plane,
        u16 frame_height = height;
        unsigned int field_offset = 0;
 
+       DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
+              "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
+              plane, paddr, screen_width, pos_x, pos_y,
+              width, height,
+              out_width, out_height,
+              ilace, color_mode,
+              rotation, mirror, channel);
+
        if (paddr == 0)
                return -EINVAL;
 
@@ -1903,9 +2025,13 @@ static int _dispc_setup_plane(enum omap_plane plane,
        return 0;
 }
 
-static void _dispc_enable_plane(enum omap_plane plane, bool enable)
+int dispc_enable_plane(enum omap_plane plane, bool enable)
 {
+       DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
+
        REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
+
+       return 0;
 }
 
 static void dispc_disable_isr(void *data, u32 mask)
@@ -1929,8 +2055,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
        int r;
        u32 irq;
 
-       enable_clocks(1);
-
        /* When we disable LCD output, we need to wait until frame is done.
         * Otherwise the DSS is still working, and turning off the clocks
         * prevents DSS from going to OFF mode */
@@ -1964,8 +2088,6 @@ static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
                if (r)
                        DSSERR("failed to unregister FRAMEDONE isr\n");
        }
-
-       enable_clocks(0);
 }
 
 static void _enable_digit_out(bool enable)
@@ -1978,12 +2100,8 @@ static void dispc_enable_digit_out(bool enable)
        struct completion frame_done_completion;
        int r;
 
-       enable_clocks(1);
-
-       if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
-               enable_clocks(0);
+       if (REG_GET(DISPC_CONTROL, 1, 1) == enable)
                return;
-       }
 
        if (enable) {
                unsigned long flags;
@@ -2035,8 +2153,6 @@ static void dispc_enable_digit_out(bool enable)
                _omap_dispc_set_irqs();
                spin_unlock_irqrestore(&dispc.irq_lock, flags);
        }
-
-       enable_clocks(0);
 }
 
 bool dispc_is_channel_enabled(enum omap_channel channel)
@@ -2067,9 +2183,7 @@ void dispc_lcd_enable_signal_polarity(bool act_high)
        if (!dss_has_feature(FEAT_LCDENABLEPOL))
                return;
 
-       enable_clocks(1);
        REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
-       enable_clocks(0);
 }
 
 void dispc_lcd_enable_signal(bool enable)
@@ -2077,9 +2191,7 @@ void dispc_lcd_enable_signal(bool enable)
        if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
                return;
 
-       enable_clocks(1);
        REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
-       enable_clocks(0);
 }
 
 void dispc_pck_free_enable(bool enable)
@@ -2087,19 +2199,15 @@ void dispc_pck_free_enable(bool enable)
        if (!dss_has_feature(FEAT_PCKFREEENABLE))
                return;
 
-       enable_clocks(1);
        REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
-       enable_clocks(0);
 }
 
 void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable)
 {
-       enable_clocks(1);
        if (channel == OMAP_DSS_CHANNEL_LCD2)
                REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16);
        else
                REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
-       enable_clocks(0);
 }
 
 
@@ -2122,27 +2230,21 @@ void dispc_set_lcd_display_type(enum omap_channel channel,
                return;
        }
 
-       enable_clocks(1);
        if (channel == OMAP_DSS_CHANNEL_LCD2)
                REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3);
        else
                REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
-       enable_clocks(0);
 }
 
 void dispc_set_loadmode(enum omap_dss_load_mode mode)
 {
-       enable_clocks(1);
        REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
-       enable_clocks(0);
 }
 
 
 void dispc_set_default_color(enum omap_channel channel, u32 color)
 {
-       enable_clocks(1);
        dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
-       enable_clocks(0);
 }
 
 u32 dispc_get_default_color(enum omap_channel channel)
@@ -2153,9 +2255,7 @@ u32 dispc_get_default_color(enum omap_channel channel)
                channel != OMAP_DSS_CHANNEL_LCD &&
                channel != OMAP_DSS_CHANNEL_LCD2);
 
-       enable_clocks(1);
        l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel));
-       enable_clocks(0);
 
        return l;
 }
@@ -2164,7 +2264,6 @@ void dispc_set_trans_key(enum omap_channel ch,
                enum omap_dss_trans_key_type type,
                u32 trans_key)
 {
-       enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
@@ -2173,14 +2272,12 @@ void dispc_set_trans_key(enum omap_channel ch,
                REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11);
 
        dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
-       enable_clocks(0);
 }
 
 void dispc_get_trans_key(enum omap_channel ch,
                enum omap_dss_trans_key_type *type,
                u32 *trans_key)
 {
-       enable_clocks(1);
        if (type) {
                if (ch == OMAP_DSS_CHANNEL_LCD)
                        *type = REG_GET(DISPC_CONFIG, 11, 11);
@@ -2194,33 +2291,28 @@ void dispc_get_trans_key(enum omap_channel ch,
 
        if (trans_key)
                *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch));
-       enable_clocks(0);
 }
 
 void dispc_enable_trans_key(enum omap_channel ch, bool enable)
 {
-       enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
        else /* OMAP_DSS_CHANNEL_LCD2 */
                REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
-       enable_clocks(0);
 }
 void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
 {
        if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
                return;
 
-       enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
                REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
        else /* OMAP_DSS_CHANNEL_LCD2 */
                REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18);
-       enable_clocks(0);
 }
 bool dispc_alpha_blending_enabled(enum omap_channel ch)
 {
@@ -2229,7 +2321,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
        if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
                return false;
 
-       enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                enabled = REG_GET(DISPC_CONFIG, 18, 18);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
@@ -2238,7 +2329,6 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch)
                enabled = REG_GET(DISPC_CONFIG2, 18, 18);
        else
                BUG();
-       enable_clocks(0);
 
        return enabled;
 }
@@ -2248,7 +2338,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
 {
        bool enabled;
 
-       enable_clocks(1);
        if (ch == OMAP_DSS_CHANNEL_LCD)
                enabled = REG_GET(DISPC_CONFIG, 10, 10);
        else if (ch == OMAP_DSS_CHANNEL_DIGIT)
@@ -2257,7 +2346,6 @@ bool dispc_trans_key_enabled(enum omap_channel ch)
                enabled = REG_GET(DISPC_CONFIG2, 10, 10);
        else
                BUG();
-       enable_clocks(0);
 
        return enabled;
 }
@@ -2285,12 +2373,10 @@ void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
                return;
        }
 
-       enable_clocks(1);
        if (channel == OMAP_DSS_CHANNEL_LCD2)
                REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8);
        else
                REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
-       enable_clocks(0);
 }
 
 void dispc_set_parallel_interface_mode(enum omap_channel channel,
@@ -2322,8 +2408,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel,
                return;
        }
 
-       enable_clocks(1);
-
        if (channel == OMAP_DSS_CHANNEL_LCD2) {
                l = dispc_read_reg(DISPC_CONTROL2);
                l = FLD_MOD(l, stallmode, 11, 11);
@@ -2335,8 +2419,6 @@ void dispc_set_parallel_interface_mode(enum omap_channel channel,
                l = FLD_MOD(l, gpout1, 16, 16);
                dispc_write_reg(DISPC_CONTROL, l);
        }
-
-       enable_clocks(0);
 }
 
 static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
@@ -2389,10 +2471,8 @@ static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw,
                        FLD_VAL(vbp, 31, 20);
        }
 
-       enable_clocks(1);
        dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
        dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
-       enable_clocks(0);
 }
 
 /* change name to mode? */
@@ -2435,10 +2515,8 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
        BUG_ON(lck_div < 1);
        BUG_ON(pck_div < 2);
 
-       enable_clocks(1);
        dispc_write_reg(DISPC_DIVISORo(channel),
                        FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
-       enable_clocks(0);
 }
 
 static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
@@ -2457,7 +2535,7 @@ unsigned long dispc_fclk_rate(void)
 
        switch (dss_get_dispc_clk_source()) {
        case OMAP_DSS_CLK_SRC_FCK:
-               r = dss_clk_get_rate(DSS_CLK_FCK);
+               r = clk_get_rate(dispc.dss_clk);
                break;
        case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
                dsidev = dsi_get_dsidev_from_id(0);
@@ -2487,7 +2565,7 @@ unsigned long dispc_lclk_rate(enum omap_channel channel)
 
        switch (dss_get_lcd_clk_source(channel)) {
        case OMAP_DSS_CLK_SRC_FCK:
-               r = dss_clk_get_rate(DSS_CLK_FCK);
+               r = clk_get_rate(dispc.dss_clk);
                break;
        case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
                dsidev = dsi_get_dsidev_from_id(0);
@@ -2526,7 +2604,8 @@ void dispc_dump_clocks(struct seq_file *s)
        enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
        enum omap_dss_clk_source lcd_clk_src;
 
-       enable_clocks(1);
+       if (dispc_runtime_get())
+               return;
 
        seq_printf(s, "- DISPC -\n");
 
@@ -2574,7 +2653,8 @@ void dispc_dump_clocks(struct seq_file *s)
                seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
                                dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd);
        }
-       enable_clocks(0);
+
+       dispc_runtime_put();
 }
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
@@ -2629,7 +2709,8 @@ void dispc_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (dispc_runtime_get())
+               return;
 
        DUMPREG(DISPC_REVISION);
        DUMPREG(DISPC_SYSCONFIG);
@@ -2649,7 +2730,8 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD));
        DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD));
        DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_GLOBAL_ALPHA);
+       if (dss_has_feature(FEAT_GLOBAL_ALPHA))
+               DUMPREG(DISPC_GLOBAL_ALPHA);
        DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
        DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
@@ -2680,20 +2762,25 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
        DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
 
-       DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
-       DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       if (dss_has_feature(FEAT_CPR)) {
+               DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+               DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+               DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
+       }
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
                DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
                DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
 
-               DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
-               DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+               if (dss_has_feature(FEAT_CPR)) {
+                       DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+                       DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+                       DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+               }
        }
 
-       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX));
+       if (dss_has_feature(FEAT_PRELOAD))
+               DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX));
 
        DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1));
        DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1));
@@ -2744,14 +2831,16 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2));
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3));
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7));
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1));
@@ -2812,14 +2901,17 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2));
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3));
        DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6));
-       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7));
+
+       if (dss_has_feature(FEAT_FIR_COEF_V)) {
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7));
+       }
 
        if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
                DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2));
@@ -2858,10 +2950,12 @@ void dispc_dump_regs(struct seq_file *s)
        if (dss_has_feature(FEAT_ATTR2))
                DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
 
-       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1));
-       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2));
+       if (dss_has_feature(FEAT_PRELOAD)) {
+               DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1));
+               DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2));
+       }
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dispc_runtime_put();
 #undef DUMPREG
 }
 
@@ -2882,9 +2976,7 @@ static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf,
        l |= FLD_VAL(acbi, 11, 8);
        l |= FLD_VAL(acb, 7, 0);
 
-       enable_clocks(1);
        dispc_write_reg(DISPC_POL_FREQ(channel), l);
-       enable_clocks(0);
 }
 
 void dispc_set_pol_freq(enum omap_channel channel,
@@ -3005,15 +3097,11 @@ static void _omap_dispc_set_irqs(void)
                mask |= isr_data->mask;
        }
 
-       enable_clocks(1);
-
        old_mask = dispc_read_reg(DISPC_IRQENABLE);
        /* clear the irqstatus for newly enabled irqs */
        dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
 
        dispc_write_reg(DISPC_IRQENABLE, mask);
-
-       enable_clocks(0);
 }
 
 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
@@ -3522,13 +3610,6 @@ static void _omap_dispc_initial_config(void)
 {
        u32 l;
 
-       l = dispc_read_reg(DISPC_SYSCONFIG);
-       l = FLD_MOD(l, 2, 13, 12);      /* MIDLEMODE: smart standby */
-       l = FLD_MOD(l, 2, 4, 3);        /* SIDLEMODE: smart idle */
-       l = FLD_MOD(l, 1, 2, 2);        /* ENWAKEUP */
-       l = FLD_MOD(l, 1, 0, 0);        /* AUTOIDLE */
-       dispc_write_reg(DISPC_SYSCONFIG, l);
-
        /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
        if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
                l = dispc_read_reg(DISPC_DIVISOR);
@@ -3552,58 +3633,8 @@ static void _omap_dispc_initial_config(void)
        dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
 
        dispc_read_plane_fifo_sizes();
-}
 
-int dispc_enable_plane(enum omap_plane plane, bool enable)
-{
-       DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
-
-       enable_clocks(1);
-       _dispc_enable_plane(plane, enable);
-       enable_clocks(0);
-
-       return 0;
-}
-
-int dispc_setup_plane(enum omap_plane plane,
-                      u32 paddr, u16 screen_width,
-                      u16 pos_x, u16 pos_y,
-                      u16 width, u16 height,
-                      u16 out_width, u16 out_height,
-                      enum omap_color_mode color_mode,
-                      bool ilace,
-                      enum omap_dss_rotation_type rotation_type,
-                      u8 rotation, bool mirror, u8 global_alpha,
-                      u8 pre_mult_alpha, enum omap_channel channel,
-                      u32 puv_addr)
-{
-       int r = 0;
-
-       DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d, %d, %dx%d -> "
-              "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
-              plane, paddr, screen_width, pos_x, pos_y,
-              width, height,
-              out_width, out_height,
-              ilace, color_mode,
-              rotation, mirror, channel);
-
-       enable_clocks(1);
-
-       r = _dispc_setup_plane(plane,
-                          paddr, screen_width,
-                          pos_x, pos_y,
-                          width, height,
-                          out_width, out_height,
-                          color_mode, ilace,
-                          rotation_type,
-                          rotation, mirror,
-                          global_alpha,
-                          pre_mult_alpha,
-                          channel, puv_addr);
-
-       enable_clocks(0);
-
-       return r;
+       dispc_configure_burst_sizes();
 }
 
 /* DISPC HW IP initialisation */
@@ -3612,9 +3643,19 @@ static int omap_dispchw_probe(struct platform_device *pdev)
        u32 rev;
        int r = 0;
        struct resource *dispc_mem;
+       struct clk *clk;
 
        dispc.pdev = pdev;
 
+       clk = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get fck\n");
+               r = PTR_ERR(clk);
+               goto err_get_clk;
+       }
+
+       dispc.dss_clk = clk;
+
        spin_lock_init(&dispc.irq_lock);
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
@@ -3628,62 +3669,103 @@ static int omap_dispchw_probe(struct platform_device *pdev)
        if (!dispc_mem) {
                DSSERR("can't get IORESOURCE_MEM DISPC\n");
                r = -EINVAL;
-               goto fail0;
+               goto err_ioremap;
        }
        dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem));
        if (!dispc.base) {
                DSSERR("can't ioremap DISPC\n");
                r = -ENOMEM;
-               goto fail0;
+               goto err_ioremap;
        }
        dispc.irq = platform_get_irq(dispc.pdev, 0);
        if (dispc.irq < 0) {
                DSSERR("platform_get_irq failed\n");
                r = -ENODEV;
-               goto fail1;
+               goto err_irq;
        }
 
        r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED,
                "OMAP DISPC", dispc.pdev);
        if (r < 0) {
                DSSERR("request_irq failed\n");
-               goto fail1;
+               goto err_irq;
        }
 
-       enable_clocks(1);
+       pm_runtime_enable(&pdev->dev);
+
+       r = dispc_runtime_get();
+       if (r)
+               goto err_runtime_get;
 
        _omap_dispc_initial_config();
 
        _omap_dispc_initialize_irq();
 
-       dispc_save_context();
-
        rev = dispc_read_reg(DISPC_REVISION);
        dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
               FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
-       enable_clocks(0);
+       dispc_runtime_put();
 
        return 0;
-fail1:
+
+err_runtime_get:
+       pm_runtime_disable(&pdev->dev);
+       free_irq(dispc.irq, dispc.pdev);
+err_irq:
        iounmap(dispc.base);
-fail0:
+err_ioremap:
+       clk_put(dispc.dss_clk);
+err_get_clk:
        return r;
 }
 
 static int omap_dispchw_remove(struct platform_device *pdev)
 {
+       pm_runtime_disable(&pdev->dev);
+
+       clk_put(dispc.dss_clk);
+
        free_irq(dispc.irq, dispc.pdev);
        iounmap(dispc.base);
        return 0;
 }
 
+static int dispc_runtime_suspend(struct device *dev)
+{
+       dispc_save_context();
+       clk_disable(dispc.dss_clk);
+       dss_runtime_put();
+
+       return 0;
+}
+
+static int dispc_runtime_resume(struct device *dev)
+{
+       int r;
+
+       r = dss_runtime_get();
+       if (r < 0)
+               return r;
+
+       clk_enable(dispc.dss_clk);
+       dispc_restore_context();
+
+       return 0;
+}
+
+static const struct dev_pm_ops dispc_pm_ops = {
+       .runtime_suspend = dispc_runtime_suspend,
+       .runtime_resume = dispc_runtime_resume,
+};
+
 static struct platform_driver omap_dispchw_driver = {
        .probe          = omap_dispchw_probe,
        .remove         = omap_dispchw_remove,
        .driver         = {
                .name   = "omapdss_dispc",
                .owner  = THIS_MODULE,
+               .pm     = &dispc_pm_ops,
        },
 };
 
index c2dfc8c50057baad8be69900ba27f9a11434108b..94495e45ec5aca08e69fdb02489bab7776a68983 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <video/omapdss.h>
 #include "dss.h"
+#include "dss_features.h"
 
 static ssize_t display_enabled_show(struct device *dev,
                struct device_attribute *attr, char *buf)
@@ -65,48 +66,6 @@ static ssize_t display_enabled_store(struct device *dev,
        return size;
 }
 
-static ssize_t display_upd_mode_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct omap_dss_device *dssdev = to_dss_device(dev);
-       enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO;
-       if (dssdev->driver->get_update_mode)
-               mode = dssdev->driver->get_update_mode(dssdev);
-       return snprintf(buf, PAGE_SIZE, "%d\n", mode);
-}
-
-static ssize_t display_upd_mode_store(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf, size_t size)
-{
-       struct omap_dss_device *dssdev = to_dss_device(dev);
-       int val, r;
-       enum omap_dss_update_mode mode;
-
-       if (!dssdev->driver->set_update_mode)
-               return -EINVAL;
-
-       r = kstrtoint(buf, 0, &val);
-       if (r)
-               return r;
-
-       switch (val) {
-       case OMAP_DSS_UPDATE_DISABLED:
-       case OMAP_DSS_UPDATE_AUTO:
-       case OMAP_DSS_UPDATE_MANUAL:
-               mode = (enum omap_dss_update_mode)val;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       r = dssdev->driver->set_update_mode(dssdev, mode);
-       if (r)
-               return r;
-
-       return size;
-}
-
 static ssize_t display_tear_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
@@ -294,8 +253,6 @@ static ssize_t display_wss_store(struct device *dev,
 
 static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
                display_enabled_show, display_enabled_store);
-static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
-               display_upd_mode_show, display_upd_mode_store);
 static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
                display_tear_show, display_tear_store);
 static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
@@ -309,7 +266,6 @@ static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
 
 static struct device_attribute *display_sysfs_attrs[] = {
        &dev_attr_enabled,
-       &dev_attr_update_mode,
        &dev_attr_tear_elim,
        &dev_attr_timings,
        &dev_attr_rotate,
@@ -327,16 +283,13 @@ void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
 EXPORT_SYMBOL(omapdss_default_get_resolution);
 
 void default_get_overlay_fifo_thresholds(enum omap_plane plane,
-               u32 fifo_size, enum omap_burst_size *burst_size,
+               u32 fifo_size, u32 burst_size,
                u32 *fifo_low, u32 *fifo_high)
 {
-       unsigned burst_size_bytes;
-
-       *burst_size = OMAP_DSS_BURST_16x32;
-       burst_size_bytes = 16 * 32 / 8;
+       unsigned buf_unit = dss_feat_get_buffer_size_unit();
 
-       *fifo_high = fifo_size - 1;
-       *fifo_low = fifo_size - burst_size_bytes;
+       *fifo_high = fifo_size - buf_unit;
+       *fifo_low = fifo_size - burst_size;
 }
 
 int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
index ff6bd30132df04da253f639ea9c8fe5fe221c87a..f053b180ecd7d14e00808c32afe4166e8e21d6d8 100644 (file)
@@ -23,7 +23,6 @@
 #define DSS_SUBSYS_NAME "DPI"
 
 #include <linux/kernel.h>
-#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/errno.h>
@@ -130,8 +129,6 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
        bool is_tft;
        int r = 0;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-
        dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config,
                        dssdev->panel.acbi, dssdev->panel.acb);
 
@@ -144,7 +141,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
                r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000,
                                &fck, &lck_div, &pck_div);
        if (r)
-               goto err0;
+               return r;
 
        pck = fck / lck_div / pck_div / 1000;
 
@@ -158,12 +155,10 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
 
        dispc_set_lcd_timings(dssdev->manager->id, t);
 
-err0:
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
-       return r;
+       return 0;
 }
 
-static int dpi_basic_init(struct omap_dss_device *dssdev)
+static void dpi_basic_init(struct omap_dss_device *dssdev)
 {
        bool is_tft;
 
@@ -175,8 +170,6 @@ static int dpi_basic_init(struct omap_dss_device *dssdev)
                        OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN);
        dispc_set_tft_data_lines(dssdev->manager->id,
                        dssdev->phy.dpi.data_lines);
-
-       return 0;
 }
 
 int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
@@ -186,31 +179,38 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
-               goto err0;
+               goto err_start_dev;
        }
 
        if (cpu_is_omap34xx()) {
                r = regulator_enable(dpi.vdds_dsi_reg);
                if (r)
-                       goto err1;
+                       goto err_reg_enable;
        }
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       r = dss_runtime_get();
+       if (r)
+               goto err_get_dss;
 
-       r = dpi_basic_init(dssdev);
+       r = dispc_runtime_get();
        if (r)
-               goto err2;
+               goto err_get_dispc;
+
+       dpi_basic_init(dssdev);
 
        if (dpi_use_dsi_pll(dssdev)) {
-               dss_clk_enable(DSS_CLK_SYSCK);
+               r = dsi_runtime_get(dpi.dsidev);
+               if (r)
+                       goto err_get_dsi;
+
                r = dsi_pll_init(dpi.dsidev, 0, 1);
                if (r)
-                       goto err3;
+                       goto err_dsi_pll_init;
        }
 
        r = dpi_set_mode(dssdev);
        if (r)
-               goto err4;
+               goto err_set_mode;
 
        mdelay(2);
 
@@ -218,19 +218,22 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
 
        return 0;
 
-err4:
+err_set_mode:
        if (dpi_use_dsi_pll(dssdev))
                dsi_pll_uninit(dpi.dsidev, true);
-err3:
+err_dsi_pll_init:
        if (dpi_use_dsi_pll(dssdev))
-               dss_clk_disable(DSS_CLK_SYSCK);
-err2:
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+               dsi_runtime_put(dpi.dsidev);
+err_get_dsi:
+       dispc_runtime_put();
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
        if (cpu_is_omap34xx())
                regulator_disable(dpi.vdds_dsi_reg);
-err1:
+err_reg_enable:
        omap_dss_stop_device(dssdev);
-err0:
+err_start_dev:
        return r;
 }
 EXPORT_SYMBOL(omapdss_dpi_display_enable);
@@ -242,10 +245,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
        if (dpi_use_dsi_pll(dssdev)) {
                dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
                dsi_pll_uninit(dpi.dsidev, true);
-               dss_clk_disable(DSS_CLK_SYSCK);
+               dsi_runtime_put(dpi.dsidev);
        }
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dispc_runtime_put();
+       dss_runtime_put();
 
        if (cpu_is_omap34xx())
                regulator_disable(dpi.vdds_dsi_reg);
@@ -257,11 +261,26 @@ EXPORT_SYMBOL(omapdss_dpi_display_disable);
 void dpi_set_timings(struct omap_dss_device *dssdev,
                        struct omap_video_timings *timings)
 {
+       int r;
+
        DSSDBG("dpi_set_timings\n");
        dssdev->panel.timings = *timings;
        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+               r = dss_runtime_get();
+               if (r)
+                       return;
+
+               r = dispc_runtime_get();
+               if (r) {
+                       dss_runtime_put();
+                       return;
+               }
+
                dpi_set_mode(dssdev);
                dispc_go(dssdev->manager->id);
+
+               dispc_runtime_put();
+               dss_runtime_put();
        }
 }
 EXPORT_SYMBOL(dpi_set_timings);
index 345757cfcbee187cf90f7685b3bc1830ef2b783f..7adbbeb84334f3a9ec857c8f7d00b394b2082f6c 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
 #include <plat/clock.h>
@@ -267,8 +268,12 @@ struct dsi_isr_tables {
 struct dsi_data {
        struct platform_device *pdev;
        void __iomem    *base;
+
        int irq;
 
+       struct clk *dss_clk;
+       struct clk *sys_clk;
+
        void (*dsi_mux_pads)(bool enable);
 
        struct dsi_clock_info current_cinfo;
@@ -389,15 +394,6 @@ static inline u32 dsi_read_reg(struct platform_device *dsidev,
        return __raw_readl(dsi->base + idx.idx);
 }
 
-
-void dsi_save_context(void)
-{
-}
-
-void dsi_restore_context(void)
-{
-}
-
 void dsi_bus_lock(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -493,9 +489,18 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name)
                        total_bytes * 1000 / total_us);
 }
 #else
-#define dsi_perf_mark_setup(x)
-#define dsi_perf_mark_start(x)
-#define dsi_perf_show(x, y)
+static inline void dsi_perf_mark_setup(struct platform_device *dsidev)
+{
+}
+
+static inline void dsi_perf_mark_start(struct platform_device *dsidev)
+{
+}
+
+static inline void dsi_perf_show(struct platform_device *dsidev,
+               const char *name)
+{
+}
 #endif
 
 static void print_irq_status(u32 status)
@@ -1039,13 +1044,27 @@ static u32 dsi_get_errors(struct platform_device *dsidev)
        return e;
 }
 
-/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */
-static inline void enable_clocks(bool enable)
+int dsi_runtime_get(struct platform_device *dsidev)
 {
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       int r;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       DSSDBG("dsi_runtime_get\n");
+
+       r = pm_runtime_get_sync(&dsi->pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+void dsi_runtime_put(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int r;
+
+       DSSDBG("dsi_runtime_put\n");
+
+       r = pm_runtime_put(&dsi->pdev->dev);
+       WARN_ON(r < 0);
 }
 
 /* source clock for DSI PLL. this could also be PCLKFREE */
@@ -1055,9 +1074,9 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        if (enable)
-               dss_clk_enable(DSS_CLK_SYSCK);
+               clk_enable(dsi->sys_clk);
        else
-               dss_clk_disable(DSS_CLK_SYSCK);
+               clk_disable(dsi->sys_clk);
 
        if (enable && dsi->pll_locked) {
                if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
@@ -1150,10 +1169,11 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
 {
        unsigned long r;
        int dsi_module = dsi_get_dsidev_id(dsidev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) {
                /* DSI FCLK source is DSS_CLK_FCK */
-               r = dss_clk_get_rate(DSS_CLK_FCK);
+               r = clk_get_rate(dsi->dss_clk);
        } else {
                /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
                r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
@@ -1262,7 +1282,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
                return -EINVAL;
 
        if (cinfo->use_sys_clk) {
-               cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK);
+               cinfo->clkin = clk_get_rate(dsi->sys_clk);
                /* XXX it is unclear if highfreq should be used
                 * with DSS_SYS_CLK source also */
                cinfo->highfreq = 0;
@@ -1311,7 +1331,7 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
        int match = 0;
        unsigned long dss_sys_clk, max_dss_fck;
 
-       dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK);
+       dss_sys_clk = clk_get_rate(dsi->sys_clk);
 
        max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 
@@ -1601,7 +1621,6 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
                dsi->vdds_dsi_reg = vdds_dsi;
        }
 
-       enable_clocks(1);
        dsi_enable_pll_clock(dsidev, 1);
        /*
         * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
@@ -1653,7 +1672,6 @@ err1:
        }
 err0:
        dsi_disable_scp_clk(dsidev);
-       enable_clocks(0);
        dsi_enable_pll_clock(dsidev, 0);
        return r;
 }
@@ -1671,7 +1689,6 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
        }
 
        dsi_disable_scp_clk(dsidev);
-       enable_clocks(0);
        dsi_enable_pll_clock(dsidev, 0);
 
        DSSDBG("PLL uninit done\n");
@@ -1688,7 +1705,8 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
        dispc_clk_src = dss_get_dispc_clk_source();
        dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
 
-       enable_clocks(1);
+       if (dsi_runtime_get(dsidev))
+               return;
 
        seq_printf(s,   "- DSI%d PLL -\n", dsi_module + 1);
 
@@ -1731,7 +1749,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
 
        seq_printf(s,   "LP_CLK\t\t%lu\n", cinfo->lp_clk);
 
-       enable_clocks(0);
+       dsi_runtime_put(dsidev);
 }
 
 void dsi_dump_clocks(struct seq_file *s)
@@ -1873,7 +1891,8 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (dsi_runtime_get(dsidev))
+               return;
        dsi_enable_scp_clk(dsidev);
 
        DUMPREG(DSI_REVISION);
@@ -1947,7 +1966,7 @@ static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
        DUMPREG(DSI_PLL_CONFIGURATION2);
 
        dsi_disable_scp_clk(dsidev);
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dsi_runtime_put(dsidev);
 #undef DUMPREG
 }
 
@@ -2463,28 +2482,6 @@ static void dsi_cio_uninit(struct platform_device *dsidev)
                dsi->dsi_mux_pads(false);
 }
 
-static int _dsi_wait_reset(struct platform_device *dsidev)
-{
-       int t = 0;
-
-       while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) {
-               if (++t > 5) {
-                       DSSERR("soft reset failed\n");
-                       return -ENODEV;
-               }
-               udelay(1);
-       }
-
-       return 0;
-}
-
-static int _dsi_reset(struct platform_device *dsidev)
-{
-       /* Soft reset */
-       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1);
-       return _dsi_wait_reset(dsidev);
-}
-
 static void dsi_config_tx_fifo(struct platform_device *dsidev,
                enum fifo_size size1, enum fifo_size size2,
                enum fifo_size size3, enum fifo_size size4)
@@ -3386,6 +3383,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev)
        dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
                        DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
 
+       /* Reset LANEx_ULPS_SIG2 */
+       REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2),
+               7, 5);
+
        dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
 
        dsi_if_enable(dsidev, false);
@@ -4198,22 +4199,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
        dsi_pll_uninit(dsidev, disconnect_lanes);
 }
 
-static int dsi_core_init(struct platform_device *dsidev)
-{
-       /* Autoidle */
-       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0);
-
-       /* ENWAKEUP */
-       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2);
-
-       /* SIDLEMODE smart-idle */
-       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3);
-
-       _dsi_initialize_irq(dsidev);
-
-       return 0;
-}
-
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 {
        struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -4229,37 +4214,37 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
-               goto err0;
+               goto err_start_dev;
        }
 
-       enable_clocks(1);
-       dsi_enable_pll_clock(dsidev, 1);
-
-       r = _dsi_reset(dsidev);
+       r = dsi_runtime_get(dsidev);
        if (r)
-               goto err1;
+               goto err_get_dsi;
 
-       dsi_core_init(dsidev);
+       dsi_enable_pll_clock(dsidev, 1);
+
+       _dsi_initialize_irq(dsidev);
 
        r = dsi_display_init_dispc(dssdev);
        if (r)
-               goto err1;
+               goto err_init_dispc;
 
        r = dsi_display_init_dsi(dssdev);
        if (r)
-               goto err2;
+               goto err_init_dsi;
 
        mutex_unlock(&dsi->lock);
 
        return 0;
 
-err2:
+err_init_dsi:
        dsi_display_uninit_dispc(dssdev);
-err1:
-       enable_clocks(0);
+err_init_dispc:
        dsi_enable_pll_clock(dsidev, 0);
+       dsi_runtime_put(dsidev);
+err_get_dsi:
        omap_dss_stop_device(dssdev);
-err0:
+err_start_dev:
        mutex_unlock(&dsi->lock);
        DSSDBG("dsi_display_enable FAILED\n");
        return r;
@@ -4278,11 +4263,16 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
 
        mutex_lock(&dsi->lock);
 
+       dsi_sync_vc(dsidev, 0);
+       dsi_sync_vc(dsidev, 1);
+       dsi_sync_vc(dsidev, 2);
+       dsi_sync_vc(dsidev, 3);
+
        dsi_display_uninit_dispc(dssdev);
 
        dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
 
-       enable_clocks(0);
+       dsi_runtime_put(dsidev);
        dsi_enable_pll_clock(dsidev, 0);
 
        omap_dss_stop_device(dssdev);
@@ -4302,16 +4292,11 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
 EXPORT_SYMBOL(omapdss_dsi_enable_te);
 
 void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
-               u32 fifo_size, enum omap_burst_size *burst_size,
+               u32 fifo_size, u32 burst_size,
                u32 *fifo_low, u32 *fifo_high)
 {
-       unsigned burst_size_bytes;
-
-       *burst_size = OMAP_DSS_BURST_16x32;
-       burst_size_bytes = 16 * 32 / 8;
-
-       *fifo_high = fifo_size - burst_size_bytes;
-       *fifo_low = fifo_size - burst_size_bytes * 2;
+       *fifo_high = fifo_size - burst_size;
+       *fifo_low = fifo_size - burst_size * 2;
 }
 
 int dsi_init_display(struct omap_dss_device *dssdev)
@@ -4437,7 +4422,47 @@ static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
        dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
 }
 
-static int dsi_init(struct platform_device *dsidev)
+static int dsi_get_clocks(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct clk *clk;
+
+       clk = clk_get(&dsidev->dev, "fck");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get fck\n");
+               return PTR_ERR(clk);
+       }
+
+       dsi->dss_clk = clk;
+
+       if (cpu_is_omap34xx() || cpu_is_omap3630())
+               clk = clk_get(&dsidev->dev, "dss2_alwon_fck");
+       else
+               clk = clk_get(&dsidev->dev, "sys_clk");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get sys_clk\n");
+               clk_put(dsi->dss_clk);
+               dsi->dss_clk = NULL;
+               return PTR_ERR(clk);
+       }
+
+       dsi->sys_clk = clk;
+
+       return 0;
+}
+
+static void dsi_put_clocks(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->dss_clk)
+               clk_put(dsi->dss_clk);
+       if (dsi->sys_clk)
+               clk_put(dsi->sys_clk);
+}
+
+/* DSI1 HW IP initialisation */
+static int omap_dsi1hw_probe(struct platform_device *dsidev)
 {
        struct omap_display_platform_data *dss_plat_data;
        struct omap_dss_board_info *board_info;
@@ -4449,7 +4474,7 @@ static int dsi_init(struct platform_device *dsidev)
        dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
        if (!dsi) {
                r = -ENOMEM;
-               goto err0;
+               goto err_alloc;
        }
 
        dsi->pdev = dsidev;
@@ -4472,6 +4497,12 @@ static int dsi_init(struct platform_device *dsidev)
        mutex_init(&dsi->lock);
        sema_init(&dsi->bus_lock, 1);
 
+       r = dsi_get_clocks(dsidev);
+       if (r)
+               goto err_get_clk;
+
+       pm_runtime_enable(&dsidev->dev);
+
        INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work,
                        dsi_framedone_timeout_work_callback);
 
@@ -4484,26 +4515,26 @@ static int dsi_init(struct platform_device *dsidev)
        if (!dsi_mem) {
                DSSERR("can't get IORESOURCE_MEM DSI\n");
                r = -EINVAL;
-               goto err1;
+               goto err_ioremap;
        }
        dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem));
        if (!dsi->base) {
                DSSERR("can't ioremap DSI\n");
                r = -ENOMEM;
-               goto err1;
+               goto err_ioremap;
        }
        dsi->irq = platform_get_irq(dsi->pdev, 0);
        if (dsi->irq < 0) {
                DSSERR("platform_get_irq failed\n");
                r = -ENODEV;
-               goto err2;
+               goto err_get_irq;
        }
 
        r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED,
                dev_name(&dsidev->dev), dsi->pdev);
        if (r < 0) {
                DSSERR("request_irq failed\n");
-               goto err2;
+               goto err_get_irq;
        }
 
        /* DSI VCs initialization */
@@ -4515,7 +4546,9 @@ static int dsi_init(struct platform_device *dsidev)
 
        dsi_calc_clock_param_ranges(dsidev);
 
-       enable_clocks(1);
+       r = dsi_runtime_get(dsidev);
+       if (r)
+               goto err_get_dsi;
 
        rev = dsi_read_reg(dsidev, DSI_REVISION);
        dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
@@ -4523,21 +4556,32 @@ static int dsi_init(struct platform_device *dsidev)
 
        dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev);
 
-       enable_clocks(0);
+       dsi_runtime_put(dsidev);
 
        return 0;
-err2:
+
+err_get_dsi:
+       free_irq(dsi->irq, dsi->pdev);
+err_get_irq:
        iounmap(dsi->base);
-err1:
+err_ioremap:
+       pm_runtime_disable(&dsidev->dev);
+err_get_clk:
        kfree(dsi);
-err0:
+err_alloc:
        return r;
 }
 
-static void dsi_exit(struct platform_device *dsidev)
+static int omap_dsi1hw_remove(struct platform_device *dsidev)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
+       WARN_ON(dsi->scp_clk_refcount > 0);
+
+       pm_runtime_disable(&dsidev->dev);
+
+       dsi_put_clocks(dsidev);
+
        if (dsi->vdds_dsi_reg != NULL) {
                if (dsi->vdds_dsi_enabled) {
                        regulator_disable(dsi->vdds_dsi_reg);
@@ -4553,38 +4597,56 @@ static void dsi_exit(struct platform_device *dsidev)
 
        kfree(dsi);
 
-       DSSDBG("omap_dsi_exit\n");
+       return 0;
 }
 
-/* DSI1 HW IP initialisation */
-static int omap_dsi1hw_probe(struct platform_device *dsidev)
+static int dsi_runtime_suspend(struct device *dev)
 {
-       int r;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev));
 
-       r = dsi_init(dsidev);
-       if (r) {
-               DSSERR("Failed to initialize DSI\n");
-               goto err_dsi;
-       }
-err_dsi:
-       return r;
+       clk_disable(dsi->dss_clk);
+
+       dispc_runtime_put();
+       dss_runtime_put();
+
+       return 0;
 }
 
-static int omap_dsi1hw_remove(struct platform_device *dsidev)
+static int dsi_runtime_resume(struct device *dev)
 {
-       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev));
+       int r;
+
+       r = dss_runtime_get();
+       if (r)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r)
+               goto err_get_dispc;
+
+       clk_enable(dsi->dss_clk);
 
-       dsi_exit(dsidev);
-       WARN_ON(dsi->scp_clk_refcount > 0);
        return 0;
+
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
+       return r;
 }
 
+static const struct dev_pm_ops dsi_pm_ops = {
+       .runtime_suspend = dsi_runtime_suspend,
+       .runtime_resume = dsi_runtime_resume,
+};
+
 static struct platform_driver omap_dsi1hw_driver = {
        .probe          = omap_dsi1hw_probe,
        .remove         = omap_dsi1hw_remove,
        .driver         = {
                .name   = "omapdss_dsi1",
                .owner  = THIS_MODULE,
+               .pm     = &dsi_pm_ops,
        },
 };
 
index d9489d5c4f08d96c942676ee00dddc93d62f3208..0f9c3a6457a5cba009157f9255baf88681a5d30a 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/delay.h>
 #include <linux/seq_file.h>
 #include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
 #include <plat/clock.h>
@@ -59,15 +61,9 @@ struct dss_reg {
 static struct {
        struct platform_device *pdev;
        void __iomem    *base;
-       int             ctx_id;
 
        struct clk      *dpll4_m4_ck;
-       struct clk      *dss_ick;
-       struct clk      *dss_fck;
-       struct clk      *dss_sys_clk;
-       struct clk      *dss_tv_fck;
-       struct clk      *dss_video_fck;
-       unsigned        num_clks_enabled;
+       struct clk      *dss_clk;
 
        unsigned long   cache_req_pck;
        unsigned long   cache_prate;
@@ -78,6 +74,7 @@ static struct {
        enum omap_dss_clk_source dispc_clk_source;
        enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
 
+       bool            ctx_valid;
        u32             ctx[DSS_SZ_REGS / sizeof(u32)];
 } dss;
 
@@ -87,13 +84,6 @@ static const char * const dss_generic_clk_source_names[] = {
        [OMAP_DSS_CLK_SRC_FCK]                  = "DSS_FCK",
 };
 
-static void dss_clk_enable_all_no_ctx(void);
-static void dss_clk_disable_all_no_ctx(void);
-static void dss_clk_enable_no_ctx(enum dss_clock clks);
-static void dss_clk_disable_no_ctx(enum dss_clock clks);
-
-static int _omap_dss_wait_reset(void);
-
 static inline void dss_write_reg(const struct dss_reg idx, u32 val)
 {
        __raw_writel(val, dss.base + idx.idx);
@@ -109,12 +99,10 @@ static inline u32 dss_read_reg(const struct dss_reg idx)
 #define RR(reg) \
        dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
 
-void dss_save_context(void)
+static void dss_save_context(void)
 {
-       if (cpu_is_omap24xx())
-               return;
+       DSSDBG("dss_save_context\n");
 
-       SR(SYSCONFIG);
        SR(CONTROL);
 
        if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
@@ -122,14 +110,19 @@ void dss_save_context(void)
                SR(SDI_CONTROL);
                SR(PLL_CONTROL);
        }
+
+       dss.ctx_valid = true;
+
+       DSSDBG("context saved\n");
 }
 
-void dss_restore_context(void)
+static void dss_restore_context(void)
 {
-       if (_omap_dss_wait_reset())
-               DSSERR("DSS not coming out of reset after sleep\n");
+       DSSDBG("dss_restore_context\n");
+
+       if (!dss.ctx_valid)
+               return;
 
-       RR(SYSCONFIG);
        RR(CONTROL);
 
        if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
@@ -137,6 +130,8 @@ void dss_restore_context(void)
                RR(SDI_CONTROL);
                RR(PLL_CONTROL);
        }
+
+       DSSDBG("context restored\n");
 }
 
 #undef SR
@@ -234,6 +229,7 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
        return dss_generic_clk_source_names[clk_src];
 }
 
+
 void dss_dump_clocks(struct seq_file *s)
 {
        unsigned long dpll4_ck_rate;
@@ -241,13 +237,14 @@ void dss_dump_clocks(struct seq_file *s)
        const char *fclk_name, *fclk_real_name;
        unsigned long fclk_rate;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (dss_runtime_get())
+               return;
 
        seq_printf(s, "- DSS -\n");
 
        fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
        fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
-       fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
+       fclk_rate = clk_get_rate(dss.dss_clk);
 
        if (dss.dpll4_m4_ck) {
                dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
@@ -273,14 +270,15 @@ void dss_dump_clocks(struct seq_file *s)
                                fclk_rate);
        }
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dss_runtime_put();
 }
 
 void dss_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (dss_runtime_get())
+               return;
 
        DUMPREG(DSS_REVISION);
        DUMPREG(DSS_SYSCONFIG);
@@ -294,7 +292,7 @@ void dss_dump_regs(struct seq_file *s)
                DUMPREG(DSS_SDI_STATUS);
        }
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dss_runtime_put();
 #undef DUMPREG
 }
 
@@ -437,7 +435,7 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
        } else {
                if (cinfo->fck_div != 0)
                        return -EINVAL;
-               cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
+               cinfo->fck = clk_get_rate(dss.dss_clk);
        }
 
        return 0;
@@ -467,7 +465,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
 
 int dss_get_clock_div(struct dss_clock_info *cinfo)
 {
-       cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK);
+       cinfo->fck = clk_get_rate(dss.dss_clk);
 
        if (dss.dpll4_m4_ck) {
                unsigned long prate;
@@ -512,7 +510,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
 
        max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 
-       fck = dss_clk_get_rate(DSS_CLK_FCK);
+       fck = clk_get_rate(dss.dss_clk);
        if (req_pck == dss.cache_req_pck &&
                        ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
                         dss.cache_dss_cinfo.fck == fck)) {
@@ -539,7 +537,7 @@ retry:
        if (dss.dpll4_m4_ck == NULL) {
                struct dispc_clock_info cur_dispc;
                /* XXX can we change the clock on omap2? */
-               fck = dss_clk_get_rate(DSS_CLK_FCK);
+               fck = clk_get_rate(dss.dss_clk);
                fck_div = 1;
 
                dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
@@ -616,28 +614,6 @@ found:
        return 0;
 }
 
-static int _omap_dss_wait_reset(void)
-{
-       int t = 0;
-
-       while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
-               if (++t > 1000) {
-                       DSSERR("soft reset failed\n");
-                       return -ENODEV;
-               }
-               udelay(1);
-       }
-
-       return 0;
-}
-
-static int _omap_dss_reset(void)
-{
-       /* Soft reset */
-       REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
-       return _omap_dss_wait_reset();
-}
-
 void dss_set_venc_output(enum omap_dss_venc_type type)
 {
        int l = 0;
@@ -663,424 +639,88 @@ void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi)
        REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */
 }
 
-static int dss_init(void)
+static int dss_get_clocks(void)
 {
+       struct clk *clk;
        int r;
-       u32 rev;
-       struct resource *dss_mem;
-       struct clk *dpll4_m4_ck;
 
-       dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
-       if (!dss_mem) {
-               DSSERR("can't get IORESOURCE_MEM DSS\n");
-               r = -EINVAL;
-               goto fail0;
-       }
-       dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
-       if (!dss.base) {
-               DSSERR("can't ioremap DSS\n");
-               r = -ENOMEM;
-               goto fail0;
+       clk = clk_get(&dss.pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get clock fck\n");
+               r = PTR_ERR(clk);
+               goto err;
        }
 
-       /* disable LCD and DIGIT output. This seems to fix the synclost
-        * problem that we get, if the bootloader starts the DSS and
-        * the kernel resets it */
-       omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
-
-#ifdef CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET
-       /* We need to wait here a bit, otherwise we sometimes start to
-        * get synclost errors, and after that only power cycle will
-        * restore DSS functionality. I have no idea why this happens.
-        * And we have to wait _before_ resetting the DSS, but after
-        * enabling clocks.
-        *
-        * This bug was at least present on OMAP3430. It's unknown
-        * if it happens on OMAP2 or OMAP3630.
-        */
-       msleep(50);
-#endif
-
-       _omap_dss_reset();
+       dss.dss_clk = clk;
 
-       /* autoidle */
-       REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
-
-       /* Select DPLL */
-       REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
-
-#ifdef CONFIG_OMAP2_DSS_VENC
-       REG_FLD_MOD(DSS_CONTROL, 1, 4, 4);      /* venc dac demen */
-       REG_FLD_MOD(DSS_CONTROL, 1, 3, 3);      /* venc clock 4x enable */
-       REG_FLD_MOD(DSS_CONTROL, 0, 2, 2);      /* venc clock mode = normal */
-#endif
        if (cpu_is_omap34xx()) {
-               dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
-               if (IS_ERR(dpll4_m4_ck)) {
+               clk = clk_get(NULL, "dpll4_m4_ck");
+               if (IS_ERR(clk)) {
                        DSSERR("Failed to get dpll4_m4_ck\n");
-                       r = PTR_ERR(dpll4_m4_ck);
-                       goto fail1;
+                       r = PTR_ERR(clk);
+                       goto err;
                }
        } else if (cpu_is_omap44xx()) {
-               dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck");
-               if (IS_ERR(dpll4_m4_ck)) {
-                       DSSERR("Failed to get dpll4_m4_ck\n");
-                       r = PTR_ERR(dpll4_m4_ck);
-                       goto fail1;
+               clk = clk_get(NULL, "dpll_per_m5x2_ck");
+               if (IS_ERR(clk)) {
+                       DSSERR("Failed to get dpll_per_m5x2_ck\n");
+                       r = PTR_ERR(clk);
+                       goto err;
                }
        } else { /* omap24xx */
-               dpll4_m4_ck = NULL;
+               clk = NULL;
        }
 
-       dss.dpll4_m4_ck = dpll4_m4_ck;
-
-       dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
-       dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
-       dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
-       dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
-       dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
-
-       dss_save_context();
-
-       rev = dss_read_reg(DSS_REVISION);
-       printk(KERN_INFO "OMAP DSS rev %d.%d\n",
-                       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+       dss.dpll4_m4_ck = clk;
 
        return 0;
 
-fail1:
-       iounmap(dss.base);
-fail0:
-       return r;
-}
-
-static void dss_exit(void)
-{
+err:
+       if (dss.dss_clk)
+               clk_put(dss.dss_clk);
        if (dss.dpll4_m4_ck)
                clk_put(dss.dpll4_m4_ck);
 
-       iounmap(dss.base);
-}
-
-/* CONTEXT */
-static int dss_get_ctx_id(void)
-{
-       struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
-       int r;
-
-       if (!pdata->board_data->get_last_off_on_transaction_id)
-               return 0;
-       r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev);
-       if (r < 0) {
-               dev_err(&dss.pdev->dev, "getting transaction ID failed, "
-                               "will force context restore\n");
-               r = -1;
-       }
-       return r;
-}
-
-int dss_need_ctx_restore(void)
-{
-       int id = dss_get_ctx_id();
-
-       if (id < 0 || id != dss.ctx_id) {
-               DSSDBG("ctx id %d -> id %d\n",
-                               dss.ctx_id, id);
-               dss.ctx_id = id;
-               return 1;
-       } else {
-               return 0;
-       }
-}
-
-static void save_all_ctx(void)
-{
-       DSSDBG("save context\n");
-
-       dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
-
-       dss_save_context();
-       dispc_save_context();
-#ifdef CONFIG_OMAP2_DSS_DSI
-       dsi_save_context();
-#endif
-
-       dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK);
-}
-
-static void restore_all_ctx(void)
-{
-       DSSDBG("restore context\n");
-
-       dss_clk_enable_all_no_ctx();
-
-       dss_restore_context();
-       dispc_restore_context();
-#ifdef CONFIG_OMAP2_DSS_DSI
-       dsi_restore_context();
-#endif
-
-       dss_clk_disable_all_no_ctx();
-}
-
-static int dss_get_clock(struct clk **clock, const char *clk_name)
-{
-       struct clk *clk;
-
-       clk = clk_get(&dss.pdev->dev, clk_name);
-
-       if (IS_ERR(clk)) {
-               DSSERR("can't get clock %s", clk_name);
-               return PTR_ERR(clk);
-       }
-
-       *clock = clk;
-
-       DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
-
-       return 0;
-}
-
-static int dss_get_clocks(void)
-{
-       int r;
-       struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data;
-
-       dss.dss_ick = NULL;
-       dss.dss_fck = NULL;
-       dss.dss_sys_clk = NULL;
-       dss.dss_tv_fck = NULL;
-       dss.dss_video_fck = NULL;
-
-       r = dss_get_clock(&dss.dss_ick, "ick");
-       if (r)
-               goto err;
-
-       r = dss_get_clock(&dss.dss_fck, "fck");
-       if (r)
-               goto err;
-
-       if (!pdata->opt_clock_available) {
-               r = -ENODEV;
-               goto err;
-       }
-
-       if (pdata->opt_clock_available("sys_clk")) {
-               r = dss_get_clock(&dss.dss_sys_clk, "sys_clk");
-               if (r)
-                       goto err;
-       }
-
-       if (pdata->opt_clock_available("tv_clk")) {
-               r = dss_get_clock(&dss.dss_tv_fck, "tv_clk");
-               if (r)
-                       goto err;
-       }
-
-       if (pdata->opt_clock_available("video_clk")) {
-               r = dss_get_clock(&dss.dss_video_fck, "video_clk");
-               if (r)
-                       goto err;
-       }
-
-       return 0;
-
-err:
-       if (dss.dss_ick)
-               clk_put(dss.dss_ick);
-       if (dss.dss_fck)
-               clk_put(dss.dss_fck);
-       if (dss.dss_sys_clk)
-               clk_put(dss.dss_sys_clk);
-       if (dss.dss_tv_fck)
-               clk_put(dss.dss_tv_fck);
-       if (dss.dss_video_fck)
-               clk_put(dss.dss_video_fck);
-
        return r;
 }
 
 static void dss_put_clocks(void)
 {
-       if (dss.dss_video_fck)
-               clk_put(dss.dss_video_fck);
-       if (dss.dss_tv_fck)
-               clk_put(dss.dss_tv_fck);
-       if (dss.dss_sys_clk)
-               clk_put(dss.dss_sys_clk);
-       clk_put(dss.dss_fck);
-       clk_put(dss.dss_ick);
-}
-
-unsigned long dss_clk_get_rate(enum dss_clock clk)
-{
-       switch (clk) {
-       case DSS_CLK_ICK:
-               return clk_get_rate(dss.dss_ick);
-       case DSS_CLK_FCK:
-               return clk_get_rate(dss.dss_fck);
-       case DSS_CLK_SYSCK:
-               return clk_get_rate(dss.dss_sys_clk);
-       case DSS_CLK_TVFCK:
-               return clk_get_rate(dss.dss_tv_fck);
-       case DSS_CLK_VIDFCK:
-               return clk_get_rate(dss.dss_video_fck);
-       }
-
-       BUG();
-       return 0;
-}
-
-static unsigned count_clk_bits(enum dss_clock clks)
-{
-       unsigned num_clks = 0;
-
-       if (clks & DSS_CLK_ICK)
-               ++num_clks;
-       if (clks & DSS_CLK_FCK)
-               ++num_clks;
-       if (clks & DSS_CLK_SYSCK)
-               ++num_clks;
-       if (clks & DSS_CLK_TVFCK)
-               ++num_clks;
-       if (clks & DSS_CLK_VIDFCK)
-               ++num_clks;
-
-       return num_clks;
-}
-
-static void dss_clk_enable_no_ctx(enum dss_clock clks)
-{
-       unsigned num_clks = count_clk_bits(clks);
-
-       if (clks & DSS_CLK_ICK)
-               clk_enable(dss.dss_ick);
-       if (clks & DSS_CLK_FCK)
-               clk_enable(dss.dss_fck);
-       if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
-               clk_enable(dss.dss_sys_clk);
-       if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
-               clk_enable(dss.dss_tv_fck);
-       if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
-               clk_enable(dss.dss_video_fck);
-
-       dss.num_clks_enabled += num_clks;
-}
-
-void dss_clk_enable(enum dss_clock clks)
-{
-       bool check_ctx = dss.num_clks_enabled == 0;
-
-       dss_clk_enable_no_ctx(clks);
-
-       /*
-        * HACK: On omap4 the registers may not be accessible right after
-        * enabling the clocks. At some point this will be handled by
-        * pm_runtime, but for the time begin this should make things work.
-        */
-       if (cpu_is_omap44xx() && check_ctx)
-               udelay(10);
-
-       if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
-               restore_all_ctx();
+       if (dss.dpll4_m4_ck)
+               clk_put(dss.dpll4_m4_ck);
+       clk_put(dss.dss_clk);
 }
 
-static void dss_clk_disable_no_ctx(enum dss_clock clks)
+struct clk *dss_get_ick(void)
 {
-       unsigned num_clks = count_clk_bits(clks);
-
-       if (clks & DSS_CLK_ICK)
-               clk_disable(dss.dss_ick);
-       if (clks & DSS_CLK_FCK)
-               clk_disable(dss.dss_fck);
-       if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk)
-               clk_disable(dss.dss_sys_clk);
-       if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck)
-               clk_disable(dss.dss_tv_fck);
-       if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck)
-               clk_disable(dss.dss_video_fck);
-
-       dss.num_clks_enabled -= num_clks;
+       return clk_get(&dss.pdev->dev, "ick");
 }
 
-void dss_clk_disable(enum dss_clock clks)
+int dss_runtime_get(void)
 {
-       if (cpu_is_omap34xx()) {
-               unsigned num_clks = count_clk_bits(clks);
-
-               BUG_ON(dss.num_clks_enabled < num_clks);
+       int r;
 
-               if (dss.num_clks_enabled == num_clks)
-                       save_all_ctx();
-       }
+       DSSDBG("dss_runtime_get\n");
 
-       dss_clk_disable_no_ctx(clks);
+       r = pm_runtime_get_sync(&dss.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
 }
 
-static void dss_clk_enable_all_no_ctx(void)
+void dss_runtime_put(void)
 {
-       enum dss_clock clks;
-
-       clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
-       if (cpu_is_omap34xx())
-               clks |= DSS_CLK_VIDFCK;
-       dss_clk_enable_no_ctx(clks);
-}
-
-static void dss_clk_disable_all_no_ctx(void)
-{
-       enum dss_clock clks;
+       int r;
 
-       clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK;
-       if (cpu_is_omap34xx())
-               clks |= DSS_CLK_VIDFCK;
-       dss_clk_disable_no_ctx(clks);
-}
+       DSSDBG("dss_runtime_put\n");
 
-#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
-/* CLOCKS */
-static void core_dump_clocks(struct seq_file *s)
-{
-       int i;
-       struct clk *clocks[5] = {
-               dss.dss_ick,
-               dss.dss_fck,
-               dss.dss_sys_clk,
-               dss.dss_tv_fck,
-               dss.dss_video_fck
-       };
-
-       const char *names[5] = {
-               "ick",
-               "fck",
-               "sys_clk",
-               "tv_fck",
-               "video_fck"
-       };
-
-       seq_printf(s, "- CORE -\n");
-
-       seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled);
-
-       for (i = 0; i < 5; i++) {
-               if (!clocks[i])
-                       continue;
-               seq_printf(s, "%s (%s)%*s\t%lu\t%d\n",
-                               names[i],
-                               clocks[i]->name,
-                               24 - strlen(names[i]) - strlen(clocks[i]->name),
-                               "",
-                               clk_get_rate(clocks[i]),
-                               clocks[i]->usecount);
-       }
+       r = pm_runtime_put(&dss.pdev->dev);
+       WARN_ON(r < 0);
 }
-#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
 
 /* DEBUGFS */
 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
 void dss_debug_dump_clocks(struct seq_file *s)
 {
-       core_dump_clocks(s);
        dss_dump_clocks(s);
        dispc_dump_clocks(s);
 #ifdef CONFIG_OMAP2_DSS_DSI
@@ -1089,28 +729,51 @@ void dss_debug_dump_clocks(struct seq_file *s)
 }
 #endif
 
-
 /* DSS HW IP initialisation */
 static int omap_dsshw_probe(struct platform_device *pdev)
 {
+       struct resource *dss_mem;
+       u32 rev;
        int r;
 
        dss.pdev = pdev;
 
+       dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
+       if (!dss_mem) {
+               DSSERR("can't get IORESOURCE_MEM DSS\n");
+               r = -EINVAL;
+               goto err_ioremap;
+       }
+       dss.base = ioremap(dss_mem->start, resource_size(dss_mem));
+       if (!dss.base) {
+               DSSERR("can't ioremap DSS\n");
+               r = -ENOMEM;
+               goto err_ioremap;
+       }
+
        r = dss_get_clocks();
        if (r)
                goto err_clocks;
 
-       dss_clk_enable_all_no_ctx();
+       pm_runtime_enable(&pdev->dev);
 
-       dss.ctx_id = dss_get_ctx_id();
-       DSSDBG("initial ctx id %u\n", dss.ctx_id);
+       r = dss_runtime_get();
+       if (r)
+               goto err_runtime_get;
 
-       r = dss_init();
-       if (r) {
-               DSSERR("Failed to initialize DSS\n");
-               goto err_dss;
-       }
+       /* Select DPLL */
+       REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
+
+#ifdef CONFIG_OMAP2_DSS_VENC
+       REG_FLD_MOD(DSS_CONTROL, 1, 4, 4);      /* venc dac demen */
+       REG_FLD_MOD(DSS_CONTROL, 1, 3, 3);      /* venc clock 4x enable */
+       REG_FLD_MOD(DSS_CONTROL, 0, 2, 2);      /* venc clock mode = normal */
+#endif
+       dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+       dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
+       dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
+       dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+       dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
 
        r = dpi_init();
        if (r) {
@@ -1124,42 +787,66 @@ static int omap_dsshw_probe(struct platform_device *pdev)
                goto err_sdi;
        }
 
-       dss_clk_disable_all_no_ctx();
+       rev = dss_read_reg(DSS_REVISION);
+       printk(KERN_INFO "OMAP DSS rev %d.%d\n",
+                       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
+
+       dss_runtime_put();
+
        return 0;
 err_sdi:
        dpi_exit();
 err_dpi:
-       dss_exit();
-err_dss:
-       dss_clk_disable_all_no_ctx();
+       dss_runtime_put();
+err_runtime_get:
+       pm_runtime_disable(&pdev->dev);
        dss_put_clocks();
 err_clocks:
+       iounmap(dss.base);
+err_ioremap:
        return r;
 }
 
 static int omap_dsshw_remove(struct platform_device *pdev)
 {
+       dpi_exit();
+       sdi_exit();
 
-       dss_exit();
+       iounmap(dss.base);
 
-       /*
-        * As part of hwmod changes, DSS is not the only controller of dss
-        * clocks; hwmod framework itself will also enable clocks during hwmod
-        * init for dss, and autoidle is set in h/w for DSS. Hence, there's no
-        * need to disable clocks if their usecounts > 1.
-        */
-       WARN_ON(dss.num_clks_enabled > 0);
+       pm_runtime_disable(&pdev->dev);
 
        dss_put_clocks();
+
+       return 0;
+}
+
+static int dss_runtime_suspend(struct device *dev)
+{
+       dss_save_context();
+       clk_disable(dss.dss_clk);
        return 0;
 }
 
+static int dss_runtime_resume(struct device *dev)
+{
+       clk_enable(dss.dss_clk);
+       dss_restore_context();
+       return 0;
+}
+
+static const struct dev_pm_ops dss_pm_ops = {
+       .runtime_suspend = dss_runtime_suspend,
+       .runtime_resume = dss_runtime_resume,
+};
+
 static struct platform_driver omap_dsshw_driver = {
        .probe          = omap_dsshw_probe,
        .remove         = omap_dsshw_remove,
        .driver         = {
                .name   = "omapdss_dss",
                .owner  = THIS_MODULE,
+               .pm     = &dss_pm_ops,
        },
 };
 
index 8ab6d43329bb31af71feec89b876208e8ff4f054..9c94b1152c208575474968d18aa90d3099276736 100644 (file)
@@ -97,26 +97,12 @@ extern unsigned int dss_debug;
 #define FLD_MOD(orig, val, start, end) \
        (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
 
-enum omap_burst_size {
-       OMAP_DSS_BURST_4x32 = 0,
-       OMAP_DSS_BURST_8x32 = 1,
-       OMAP_DSS_BURST_16x32 = 2,
-};
-
 enum omap_parallel_interface_mode {
        OMAP_DSS_PARALLELMODE_BYPASS,           /* MIPI DPI */
        OMAP_DSS_PARALLELMODE_RFBI,             /* MIPI DBI */
        OMAP_DSS_PARALLELMODE_DSI,
 };
 
-enum dss_clock {
-       DSS_CLK_ICK     = 1 << 0,       /* DSS_L3_ICLK and DSS_L4_ICLK */
-       DSS_CLK_FCK     = 1 << 1,       /* DSS1_ALWON_FCLK */
-       DSS_CLK_SYSCK   = 1 << 2,       /* DSS2_ALWON_FCLK */
-       DSS_CLK_TVFCK   = 1 << 3,       /* DSS_TV_FCLK */
-       DSS_CLK_VIDFCK  = 1 << 4,       /* DSS_96M_FCLK*/
-};
-
 enum dss_hdmi_venc_clk_source_select {
        DSS_VENC_TV_CLK = 0,
        DSS_HDMI_M_PCLK = 1,
@@ -194,7 +180,7 @@ void dss_uninit_device(struct platform_device *pdev,
 bool dss_use_replication(struct omap_dss_device *dssdev,
                enum omap_color_mode mode);
 void default_get_overlay_fifo_thresholds(enum omap_plane plane,
-               u32 fifo_size, enum omap_burst_size *burst_size,
+               u32 fifo_size, u32 burst_size,
                u32 *fifo_low, u32 *fifo_high);
 
 /* manager */
@@ -220,13 +206,12 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
 int dss_init_platform_driver(void);
 void dss_uninit_platform_driver(void);
 
+int dss_runtime_get(void);
+void dss_runtime_put(void);
+
+struct clk *dss_get_ick(void);
+
 void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
-void dss_save_context(void);
-void dss_restore_context(void);
-void dss_clk_enable(enum dss_clock clks);
-void dss_clk_disable(enum dss_clock clks);
-unsigned long dss_clk_get_rate(enum dss_clock clk);
-int dss_need_ctx_restore(void);
 const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
 void dss_dump_clocks(struct seq_file *s);
 
@@ -283,15 +268,15 @@ struct file_operations;
 int dsi_init_platform_driver(void);
 void dsi_uninit_platform_driver(void);
 
+int dsi_runtime_get(struct platform_device *dsidev);
+void dsi_runtime_put(struct platform_device *dsidev);
+
 void dsi_dump_clocks(struct seq_file *s);
 void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
                const struct file_operations *debug_fops);
 void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
                const struct file_operations *debug_fops);
 
-void dsi_save_context(void);
-void dsi_restore_context(void);
-
 int dsi_init_display(struct omap_dss_device *display);
 void dsi_irq_handler(void);
 unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
@@ -304,7 +289,7 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
                bool enable_hsdiv);
 void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
 void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
-               u32 fifo_size, enum omap_burst_size *burst_size,
+               u32 fifo_size, u32 burst_size,
                u32 *fifo_low, u32 *fifo_high);
 void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
 void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
@@ -317,6 +302,13 @@ static inline int dsi_init_platform_driver(void)
 static inline void dsi_uninit_platform_driver(void)
 {
 }
+static inline int dsi_runtime_get(struct platform_device *dsidev)
+{
+       return 0;
+}
+static inline void dsi_runtime_put(struct platform_device *dsidev)
+{
+}
 static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
 {
        WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
@@ -384,8 +376,8 @@ void dispc_dump_regs(struct seq_file *s);
 void dispc_irq_handler(void);
 void dispc_fake_vsync_irq(void);
 
-void dispc_save_context(void);
-void dispc_restore_context(void);
+int dispc_runtime_get(void);
+void dispc_runtime_put(void);
 
 void dispc_enable_sidle(void);
 void dispc_disable_sidle(void);
@@ -398,10 +390,12 @@ void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable);
 void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height);
 void dispc_set_digit_size(u16 width, u16 height);
 u32 dispc_get_plane_fifo_size(enum omap_plane plane);
-void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
+void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
 void dispc_enable_fifomerge(bool enable);
-void dispc_set_burst_size(enum omap_plane plane,
-               enum omap_burst_size burst_size);
+u32 dispc_get_burst_size(enum omap_plane plane);
+void dispc_enable_cpr(enum omap_channel channel, bool enable);
+void dispc_set_cpr_coef(enum omap_channel channel,
+               struct omap_dss_cpr_coefs *coefs);
 
 void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
 void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
index 1c18888e5df39a06548d5dbf210ddcaa4e6f2600..b415c4ee621dca2160350244f3f7c881cdf5346a 100644 (file)
@@ -49,6 +49,9 @@ struct omap_dss_features {
        const enum omap_color_mode *supported_color_modes;
        const char * const *clksrc_names;
        const struct dss_param_range *dss_params;
+
+       const u32 buffer_size_unit;
+       const u32 burst_size_unit;
 };
 
 /* This struct is assigned to one of the below during initialization */
@@ -274,6 +277,8 @@ static const struct omap_dss_features omap2_dss_features = {
        .supported_color_modes = omap2_dss_supported_color_modes,
        .clksrc_names = omap2_dss_clk_source_names,
        .dss_params = omap2_dss_param_range,
+       .buffer_size_unit = 1,
+       .burst_size_unit = 8,
 };
 
 /* OMAP3 DSS Features */
@@ -286,7 +291,9 @@ static const struct omap_dss_features omap3430_dss_features = {
                FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
                FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
                FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF |
-               FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC,
+               FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC |
+               FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD |
+               FEAT_FIR_COEF_V,
 
        .num_mgrs = 2,
        .num_ovls = 3,
@@ -294,6 +301,8 @@ static const struct omap_dss_features omap3430_dss_features = {
        .supported_color_modes = omap3_dss_supported_color_modes,
        .clksrc_names = omap3_dss_clk_source_names,
        .dss_params = omap3_dss_param_range,
+       .buffer_size_unit = 1,
+       .burst_size_unit = 8,
 };
 
 static const struct omap_dss_features omap3630_dss_features = {
@@ -306,7 +315,8 @@ static const struct omap_dss_features omap3630_dss_features = {
                FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
                FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
                FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG |
-               FEAT_DSI_PLL_FREQSEL,
+               FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD |
+               FEAT_FIR_COEF_V,
 
        .num_mgrs = 2,
        .num_ovls = 3,
@@ -314,6 +324,8 @@ static const struct omap_dss_features omap3630_dss_features = {
        .supported_color_modes = omap3_dss_supported_color_modes,
        .clksrc_names = omap3_dss_clk_source_names,
        .dss_params = omap3_dss_param_range,
+       .buffer_size_unit = 1,
+       .burst_size_unit = 8,
 };
 
 /* OMAP4 DSS Features */
@@ -327,7 +339,8 @@ static const struct omap_dss_features omap4430_es1_0_dss_features  = {
                FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
                FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
                FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
-               FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
+               FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 |
+               FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V,
 
        .num_mgrs = 3,
        .num_ovls = 3,
@@ -335,6 +348,8 @@ static const struct omap_dss_features omap4430_es1_0_dss_features  = {
        .supported_color_modes = omap4_dss_supported_color_modes,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
+       .buffer_size_unit = 16,
+       .burst_size_unit = 16,
 };
 
 /* For all the other OMAP4 versions */
@@ -348,7 +363,8 @@ static const struct omap_dss_features omap4_dss_features = {
                FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
                FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
                FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE |
-               FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
+               FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR |
+               FEAT_PRELOAD | FEAT_FIR_COEF_V,
 
        .num_mgrs = 3,
        .num_ovls = 3,
@@ -356,6 +372,8 @@ static const struct omap_dss_features omap4_dss_features = {
        .supported_color_modes = omap4_dss_supported_color_modes,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
+       .buffer_size_unit = 16,
+       .burst_size_unit = 16,
 };
 
 /* Functions returning values related to a DSS feature */
@@ -401,6 +419,16 @@ const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id)
        return omap_current_dss_features->clksrc_names[id];
 }
 
+u32 dss_feat_get_buffer_size_unit(void)
+{
+       return omap_current_dss_features->buffer_size_unit;
+}
+
+u32 dss_feat_get_burst_size_unit(void)
+{
+       return omap_current_dss_features->burst_size_unit;
+}
+
 /* DSS has_feature check */
 bool dss_has_feature(enum dss_feat_id id)
 {
index 07b346f7d916569d5c84d0d901b3f4d911dcf299..b7398cbcda5f203be1681f198cd6bc2a69326f97 100644 (file)
@@ -51,6 +51,10 @@ enum dss_feat_id {
        FEAT_HDMI_CTS_SWMODE            = 1 << 19,
        FEAT_HANDLE_UV_SEPARATE         = 1 << 20,
        FEAT_ATTR2                      = 1 << 21,
+       FEAT_VENC_REQUIRES_TV_DAC_CLK   = 1 << 22,
+       FEAT_CPR                        = 1 << 23,
+       FEAT_PRELOAD                    = 1 << 24,
+       FEAT_FIR_COEF_V                 = 1 << 25,
 };
 
 /* DSS register field id */
@@ -90,6 +94,9 @@ bool dss_feat_color_mode_supported(enum omap_plane plane,
                enum omap_color_mode color_mode);
 const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
 
+u32 dss_feat_get_buffer_size_unit(void);       /* in bytes */
+u32 dss_feat_get_burst_size_unit(void);                /* in bytes */
+
 bool dss_has_feature(enum dss_feat_id id);
 void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
 void dss_features_init(void);
index b0555f4f0a78b534c52cd427d871603d3424969f..256f27a9064ac75ee5c3397a21db07b5948d482c 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
 #include <video/omapdss.h>
 #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
        defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
@@ -51,6 +54,9 @@ static struct {
        u8 edid_set;
        bool custom_set;
        struct hdmi_config cfg;
+
+       struct clk *sys_clk;
+       struct clk *hdmi_clk;
 } hdmi;
 
 /*
@@ -162,6 +168,27 @@ static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx,
        return val;
 }
 
+static int hdmi_runtime_get(void)
+{
+       int r;
+
+       DSSDBG("hdmi_runtime_get\n");
+
+       r = pm_runtime_get_sync(&hdmi.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+static void hdmi_runtime_put(void)
+{
+       int r;
+
+       DSSDBG("hdmi_runtime_put\n");
+
+       r = pm_runtime_put(&hdmi.pdev->dev);
+       WARN_ON(r < 0);
+}
+
 int hdmi_init_display(struct omap_dss_device *dssdev)
 {
        DSSDBG("init_display\n");
@@ -311,30 +338,11 @@ static int hdmi_phy_init(void)
        return 0;
 }
 
-static int hdmi_wait_softreset(void)
-{
-       /* reset W1 */
-       REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0);
-
-       /* wait till SOFTRESET == 0 */
-       if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) {
-               DSSERR("sysconfig reset failed\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
 static int hdmi_pll_program(struct hdmi_pll_info *fmt)
 {
        u16 r = 0;
        enum hdmi_clk_refsel refsel;
 
-       /* wait for wrapper reset */
-       r = hdmi_wait_softreset();
-       if (r)
-               return r;
-
        r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
        if (r)
                return r;
@@ -1064,7 +1072,7 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
        unsigned long clkin, refclk;
        u32 mf;
 
-       clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000;
+       clkin = clk_get_rate(hdmi.sys_clk) / 10000;
        /*
         * Input clock is predivided by N + 1
         * out put of which is reference clk
@@ -1098,16 +1106,6 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
        DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
 }
 
-static void hdmi_enable_clocks(int enable)
-{
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK |
-                               DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK |
-                               DSS_CLK_SYSCK | DSS_CLK_VIDFCK);
-}
-
 static int hdmi_power_on(struct omap_dss_device *dssdev)
 {
        int r, code = 0;
@@ -1115,7 +1113,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        struct omap_video_timings *p;
        unsigned long phy;
 
-       hdmi_enable_clocks(1);
+       r = hdmi_runtime_get();
+       if (r)
+               return r;
 
        dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0);
 
@@ -1180,7 +1180,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
 
        return 0;
 err:
-       hdmi_enable_clocks(0);
+       hdmi_runtime_put();
        return -EIO;
 }
 
@@ -1191,7 +1191,7 @@ static void hdmi_power_off(struct omap_dss_device *dssdev)
        hdmi_wp_video_start(0);
        hdmi_phy_off();
        hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF);
-       hdmi_enable_clocks(0);
+       hdmi_runtime_put();
 
        hdmi.edid_set = 0;
 }
@@ -1686,14 +1686,43 @@ static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
 };
 #endif
 
+static int hdmi_get_clocks(struct platform_device *pdev)
+{
+       struct clk *clk;
+
+       clk = clk_get(&pdev->dev, "sys_clk");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get sys_clk\n");
+               return PTR_ERR(clk);
+       }
+
+       hdmi.sys_clk = clk;
+
+       clk = clk_get(&pdev->dev, "dss_48mhz_clk");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get hdmi_clk\n");
+               clk_put(hdmi.sys_clk);
+               return PTR_ERR(clk);
+       }
+
+       hdmi.hdmi_clk = clk;
+
+       return 0;
+}
+
+static void hdmi_put_clocks(void)
+{
+       if (hdmi.sys_clk)
+               clk_put(hdmi.sys_clk);
+       if (hdmi.hdmi_clk)
+               clk_put(hdmi.hdmi_clk);
+}
+
 /* HDMI HW IP initialisation */
 static int omapdss_hdmihw_probe(struct platform_device *pdev)
 {
        struct resource *hdmi_mem;
-#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
-       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
-       int ret;
-#endif
+       int r;
 
        hdmi.pdata = pdev->dev.platform_data;
        hdmi.pdev = pdev;
@@ -1713,17 +1742,25 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       r = hdmi_get_clocks(pdev);
+       if (r) {
+               iounmap(hdmi.base_wp);
+               return r;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+
        hdmi_panel_init();
 
 #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
        defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
 
        /* Register ASoC codec DAI */
-       ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
+       r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
                                        &hdmi_codec_dai_drv, 1);
-       if (ret) {
+       if (r) {
                DSSERR("can't register ASoC HDMI audio codec\n");
-               return ret;
+               return r;
        }
 #endif
        return 0;
@@ -1738,17 +1775,62 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
        snd_soc_unregister_codec(&pdev->dev);
 #endif
 
+       pm_runtime_disable(&pdev->dev);
+
+       hdmi_put_clocks();
+
        iounmap(hdmi.base_wp);
 
        return 0;
 }
 
+static int hdmi_runtime_suspend(struct device *dev)
+{
+       clk_disable(hdmi.hdmi_clk);
+       clk_disable(hdmi.sys_clk);
+
+       dispc_runtime_put();
+       dss_runtime_put();
+
+       return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+       int r;
+
+       r = dss_runtime_get();
+       if (r < 0)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r < 0)
+               goto err_get_dispc;
+
+
+       clk_enable(hdmi.sys_clk);
+       clk_enable(hdmi.hdmi_clk);
+
+       return 0;
+
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
+       return r;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+       .runtime_suspend = hdmi_runtime_suspend,
+       .runtime_resume = hdmi_runtime_resume,
+};
+
 static struct platform_driver omapdss_hdmihw_driver = {
        .probe          = omapdss_hdmihw_probe,
        .remove         = omapdss_hdmihw_remove,
        .driver         = {
                .name   = "omapdss_hdmi",
                .owner  = THIS_MODULE,
+               .pm     = &hdmi_pm_ops,
        },
 };
 
index 9aeea50e33ffd49f5fc6376746c76c950caffc92..13d72d5c714b10f5aa41e074b0640769989b93b5 100644 (file)
@@ -275,6 +275,108 @@ static ssize_t manager_alpha_blending_enabled_store(
        return size;
 }
 
+static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
+               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.cpr_enable);
+}
+
+static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
+               const char *buf, size_t size)
+{
+       struct omap_overlay_manager_info info;
+       int v;
+       int r;
+       bool enable;
+
+       if (!dss_has_feature(FEAT_CPR))
+               return -ENODEV;
+
+       r = kstrtoint(buf, 0, &v);
+       if (r)
+               return r;
+
+       enable = !!v;
+
+       mgr->get_manager_info(mgr, &info);
+
+       if (info.cpr_enable == enable)
+               return size;
+
+       info.cpr_enable = enable;
+
+       r = mgr->set_manager_info(mgr, &info);
+       if (r)
+               return r;
+
+       r = mgr->apply(mgr);
+       if (r)
+               return r;
+
+       return size;
+}
+
+static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
+               char *buf)
+{
+       struct omap_overlay_manager_info info;
+
+       mgr->get_manager_info(mgr, &info);
+
+       return snprintf(buf, PAGE_SIZE,
+                       "%d %d %d %d %d %d %d %d %d\n",
+                       info.cpr_coefs.rr,
+                       info.cpr_coefs.rg,
+                       info.cpr_coefs.rb,
+                       info.cpr_coefs.gr,
+                       info.cpr_coefs.gg,
+                       info.cpr_coefs.gb,
+                       info.cpr_coefs.br,
+                       info.cpr_coefs.bg,
+                       info.cpr_coefs.bb);
+}
+
+static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
+               const char *buf, size_t size)
+{
+       struct omap_overlay_manager_info info;
+       struct omap_dss_cpr_coefs coefs;
+       int r, i;
+       s16 *arr;
+
+       if (!dss_has_feature(FEAT_CPR))
+               return -ENODEV;
+
+       if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
+                               &coefs.rr, &coefs.rg, &coefs.rb,
+                               &coefs.gr, &coefs.gg, &coefs.gb,
+                               &coefs.br, &coefs.bg, &coefs.bb) != 9)
+               return -EINVAL;
+
+       arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
+               coefs.gr, coefs.gg, coefs.gb,
+               coefs.br, coefs.bg, coefs.bb };
+
+       for (i = 0; i < 9; ++i) {
+               if (arr[i] < -512 || arr[i] > 511)
+                       return -EINVAL;
+       }
+
+       mgr->get_manager_info(mgr, &info);
+
+       info.cpr_coefs = coefs;
+
+       r = mgr->set_manager_info(mgr, &info);
+       if (r)
+               return r;
+
+       r = mgr->apply(mgr);
+       if (r)
+               return r;
+
+       return size;
+}
+
 struct manager_attribute {
        struct attribute attr;
        ssize_t (*show)(struct omap_overlay_manager *, char *);
@@ -300,6 +402,12 @@ static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
 static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
                manager_alpha_blending_enabled_show,
                manager_alpha_blending_enabled_store);
+static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
+               manager_cpr_enable_show,
+               manager_cpr_enable_store);
+static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
+               manager_cpr_coef_show,
+               manager_cpr_coef_store);
 
 
 static struct attribute *manager_sysfs_attrs[] = {
@@ -310,6 +418,8 @@ static struct attribute *manager_sysfs_attrs[] = {
        &manager_attr_trans_key_value.attr,
        &manager_attr_trans_key_enabled.attr,
        &manager_attr_alpha_blending_enabled.attr,
+       &manager_attr_cpr_enable.attr,
+       &manager_attr_cpr_coef.attr,
        NULL
 };
 
@@ -391,33 +501,14 @@ struct overlay_cache_data {
 
        bool enabled;
 
-       u32 paddr;
-       void __iomem *vaddr;
-       u32 p_uv_addr; /* relevant for NV12 format only */
-       u16 screen_width;
-       u16 width;
-       u16 height;
-       enum omap_color_mode color_mode;
-       u8 rotation;
-       enum omap_dss_rotation_type rotation_type;
-       bool mirror;
-
-       u16 pos_x;
-       u16 pos_y;
-       u16 out_width;  /* if 0, out_width == width */
-       u16 out_height; /* if 0, out_height == height */
-       u8 global_alpha;
-       u8 pre_mult_alpha;
+       struct omap_overlay_info info;
 
        enum omap_channel channel;
        bool replication;
        bool ilace;
 
-       enum omap_burst_size burst_size;
        u32 fifo_low;
        u32 fifo_high;
-
-       bool manual_update;
 };
 
 struct manager_cache_data {
@@ -429,15 +520,8 @@ struct manager_cache_data {
         * VSYNC/EVSYNC */
        bool shadow_dirty;
 
-       u32 default_color;
-
-       enum omap_dss_trans_key_type trans_key_type;
-       u32 trans_key;
-       bool trans_enabled;
-
-       bool alpha_enabled;
+       struct omap_overlay_manager_info info;
 
-       bool manual_upd_display;
        bool manual_update;
        bool do_manual_update;
 
@@ -539,24 +623,15 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
        if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
                return 0;
 
+       if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
+               return 0;
+
        if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
                        || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
                irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
        } else {
-               if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-                       enum omap_dss_update_mode mode;
-                       mode = dssdev->driver->get_update_mode(dssdev);
-                       if (mode != OMAP_DSS_UPDATE_AUTO)
-                               return 0;
-
-                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
-                               DISPC_IRQ_FRAMEDONE
-                               : DISPC_IRQ_FRAMEDONE2;
-               } else {
-                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
-                               DISPC_IRQ_VSYNC
-                               : DISPC_IRQ_VSYNC2;
-               }
+               irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+                       DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
        }
 
        mc = &dss_cache.manager_cache[mgr->id];
@@ -617,24 +692,15 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
        if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
                return 0;
 
+       if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
+               return 0;
+
        if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
                        || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
                irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
        } else {
-               if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-                       enum omap_dss_update_mode mode;
-                       mode = dssdev->driver->get_update_mode(dssdev);
-                       if (mode != OMAP_DSS_UPDATE_AUTO)
-                               return 0;
-
-                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
-                               DISPC_IRQ_FRAMEDONE
-                               : DISPC_IRQ_FRAMEDONE2;
-               } else {
-                       irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
-                               DISPC_IRQ_VSYNC
-                               : DISPC_IRQ_VSYNC2;
-               }
+               irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
+                       DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
        }
 
        oc = &dss_cache.overlay_cache[ovl->id];
@@ -720,10 +786,12 @@ static bool rectangle_intersects(int x1, int y1, int w1, int h1,
 
 static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
 {
-       if (oc->out_width != 0 && oc->width != oc->out_width)
+       struct omap_overlay_info *oi = &oc->info;
+
+       if (oi->out_width != 0 && oi->width != oi->out_width)
                return true;
 
-       if (oc->out_height != 0 && oc->height != oc->out_height)
+       if (oi->out_height != 0 && oi->height != oi->out_height)
                return true;
 
        return false;
@@ -733,6 +801,8 @@ static int configure_overlay(enum omap_plane plane)
 {
        struct overlay_cache_data *c;
        struct manager_cache_data *mc;
+       struct omap_overlay_info *oi;
+       struct omap_overlay_manager_info *mi;
        u16 outw, outh;
        u16 x, y, w, h;
        u32 paddr;
@@ -742,6 +812,7 @@ static int configure_overlay(enum omap_plane plane)
        DSSDBGF("%d", plane);
 
        c = &dss_cache.overlay_cache[plane];
+       oi = &c->info;
 
        if (!c->enabled) {
                dispc_enable_plane(plane, 0);
@@ -749,21 +820,22 @@ static int configure_overlay(enum omap_plane plane)
        }
 
        mc = &dss_cache.manager_cache[c->channel];
+       mi = &mc->info;
 
-       x = c->pos_x;
-       y = c->pos_y;
-       w = c->width;
-       h = c->height;
-       outw = c->out_width == 0 ? c->width : c->out_width;
-       outh = c->out_height == 0 ? c->height : c->out_height;
-       paddr = c->paddr;
+       x = oi->pos_x;
+       y = oi->pos_y;
+       w = oi->width;
+       h = oi->height;
+       outw = oi->out_width == 0 ? oi->width : oi->out_width;
+       outh = oi->out_height == 0 ? oi->height : oi->out_height;
+       paddr = oi->paddr;
 
        orig_w = w;
        orig_h = h;
        orig_outw = outw;
        orig_outh = outh;
 
-       if (c->manual_update && mc->do_manual_update) {
+       if (mc->manual_update && mc->do_manual_update) {
                unsigned bpp;
                unsigned scale_x_m = w, scale_x_d = outw;
                unsigned scale_y_m = h, scale_y_d = outh;
@@ -775,7 +847,7 @@ static int configure_overlay(enum omap_plane plane)
                        return 0;
                }
 
-               switch (c->color_mode) {
+               switch (oi->color_mode) {
                case OMAP_DSS_COLOR_NV12:
                        bpp = 8;
                        break;
@@ -805,23 +877,23 @@ static int configure_overlay(enum omap_plane plane)
                        BUG();
                }
 
-               if (mc->x > c->pos_x) {
+               if (mc->x > oi->pos_x) {
                        x = 0;
-                       outw -= (mc->x - c->pos_x);
-                       paddr += (mc->x - c->pos_x) *
+                       outw -= (mc->x - oi->pos_x);
+                       paddr += (mc->x - oi->pos_x) *
                                scale_x_m / scale_x_d * bpp / 8;
                } else {
-                       x = c->pos_x - mc->x;
+                       x = oi->pos_x - mc->x;
                }
 
-               if (mc->y > c->pos_y) {
+               if (mc->y > oi->pos_y) {
                        y = 0;
-                       outh -= (mc->y - c->pos_y);
-                       paddr += (mc->y - c->pos_y) *
+                       outh -= (mc->y - oi->pos_y);
+                       paddr += (mc->y - oi->pos_y) *
                                scale_y_m / scale_y_d *
-                               c->screen_width * bpp / 8;
+                               oi->screen_width * bpp / 8;
                } else {
-                       y = c->pos_y - mc->y;
+                       y = oi->pos_y - mc->y;
                }
 
                if (mc->w < (x + outw))
@@ -840,8 +912,8 @@ static int configure_overlay(enum omap_plane plane)
                 * the width if the original width was bigger.
                 */
                if ((w & 1) &&
-                               (c->color_mode == OMAP_DSS_COLOR_YUV2 ||
-                                c->color_mode == OMAP_DSS_COLOR_UYVY)) {
+                               (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
+                                oi->color_mode == OMAP_DSS_COLOR_UYVY)) {
                        if (orig_w > w)
                                w += 1;
                        else
@@ -851,19 +923,19 @@ static int configure_overlay(enum omap_plane plane)
 
        r = dispc_setup_plane(plane,
                        paddr,
-                       c->screen_width,
+                       oi->screen_width,
                        x, y,
                        w, h,
                        outw, outh,
-                       c->color_mode,
+                       oi->color_mode,
                        c->ilace,
-                       c->rotation_type,
-                       c->rotation,
-                       c->mirror,
-                       c->global_alpha,
-                       c->pre_mult_alpha,
+                       oi->rotation_type,
+                       oi->rotation,
+                       oi->mirror,
+                       oi->global_alpha,
+                       oi->pre_mult_alpha,
                        c->channel,
-                       c->p_uv_addr);
+                       oi->p_uv_addr);
 
        if (r) {
                /* this shouldn't happen */
@@ -874,8 +946,7 @@ static int configure_overlay(enum omap_plane plane)
 
        dispc_enable_replication(plane, c->replication);
 
-       dispc_set_burst_size(plane, c->burst_size);
-       dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
+       dispc_set_fifo_threshold(plane, c->fifo_low, c->fifo_high);
 
        dispc_enable_plane(plane, 1);
 
@@ -884,16 +955,21 @@ static int configure_overlay(enum omap_plane plane)
 
 static void configure_manager(enum omap_channel channel)
 {
-       struct manager_cache_data *c;
+       struct omap_overlay_manager_info *mi;
 
        DSSDBGF("%d", channel);
 
-       c = &dss_cache.manager_cache[channel];
+       /* picking info from the cache */
+       mi = &dss_cache.manager_cache[channel].info;
 
-       dispc_set_default_color(channel, c->default_color);
-       dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
-       dispc_enable_trans_key(channel, c->trans_enabled);
-       dispc_enable_alpha_blending(channel, c->alpha_enabled);
+       dispc_set_default_color(channel, mi->default_color);
+       dispc_set_trans_key(channel, mi->trans_key_type, mi->trans_key);
+       dispc_enable_trans_key(channel, mi->trans_enabled);
+       dispc_enable_alpha_blending(channel, mi->alpha_enabled);
+       if (dss_has_feature(FEAT_CPR)) {
+               dispc_enable_cpr(channel, mi->cpr_enable);
+               dispc_set_cpr_coef(channel, &mi->cpr_coefs);
+       }
 }
 
 /* configure_dispc() tries to write values from cache to shadow registers.
@@ -928,7 +1004,7 @@ static int configure_dispc(void)
                if (!oc->dirty)
                        continue;
 
-               if (oc->manual_update && !mc->do_manual_update)
+               if (mc->manual_update && !mc->do_manual_update)
                        continue;
 
                if (mgr_busy[oc->channel]) {
@@ -976,7 +1052,7 @@ static int configure_dispc(void)
                /* We don't need GO with manual update display. LCD iface will
                 * always be turned off after frame, and new settings will be
                 * taken in to use at next update */
-               if (!mc->manual_upd_display)
+               if (!mc->manual_update)
                        dispc_go(i);
        }
 
@@ -1011,6 +1087,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
 {
        struct overlay_cache_data *oc;
        struct manager_cache_data *mc;
+       struct omap_overlay_info *oi;
        const int num_ovls = dss_feat_get_num_ovls();
        struct omap_overlay_manager *mgr;
        int i;
@@ -1053,6 +1130,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
                        unsigned outw, outh;
 
                        oc = &dss_cache.overlay_cache[i];
+                       oi = &oc->info;
 
                        if (oc->channel != mgr->id)
                                continue;
@@ -1068,39 +1146,39 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
                        if (!dispc_is_overlay_scaled(oc))
                                continue;
 
-                       outw = oc->out_width == 0 ?
-                               oc->width : oc->out_width;
-                       outh = oc->out_height == 0 ?
-                               oc->height : oc->out_height;
+                       outw = oi->out_width == 0 ?
+                               oi->width : oi->out_width;
+                       outh = oi->out_height == 0 ?
+                               oi->height : oi->out_height;
 
                        /* is the overlay outside the update region? */
                        if (!rectangle_intersects(x, y, w, h,
-                                               oc->pos_x, oc->pos_y,
+                                               oi->pos_x, oi->pos_y,
                                                outw, outh))
                                continue;
 
                        /* if the overlay totally inside the update region? */
-                       if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
+                       if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh,
                                                x, y, w, h))
                                continue;
 
-                       if (x > oc->pos_x)
-                               x1 = oc->pos_x;
+                       if (x > oi->pos_x)
+                               x1 = oi->pos_x;
                        else
                                x1 = x;
 
-                       if (y > oc->pos_y)
-                               y1 = oc->pos_y;
+                       if (y > oi->pos_y)
+                               y1 = oi->pos_y;
                        else
                                y1 = y;
 
-                       if ((x + w) < (oc->pos_x + outw))
-                               x2 = oc->pos_x + outw;
+                       if ((x + w) < (oi->pos_x + outw))
+                               x2 = oi->pos_x + outw;
                        else
                                x2 = x + w;
 
-                       if ((y + h) < (oc->pos_y + outh))
-                               y2 = oc->pos_y + outh;
+                       if ((y + h) < (oi->pos_y + outh))
+                               y2 = oi->pos_y + outh;
                        else
                                y2 = y + h;
 
@@ -1236,6 +1314,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
        DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
 
+       r = dispc_runtime_get();
+       if (r)
+               return r;
+
        spin_lock_irqsave(&dss_cache.lock, flags);
 
        /* Configure overlays */
@@ -1275,23 +1357,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                ovl->info_dirty = false;
                oc->dirty = true;
-
-               oc->paddr = ovl->info.paddr;
-               oc->vaddr = ovl->info.vaddr;
-               oc->p_uv_addr = ovl->info.p_uv_addr;
-               oc->screen_width = ovl->info.screen_width;
-               oc->width = ovl->info.width;
-               oc->height = ovl->info.height;
-               oc->color_mode = ovl->info.color_mode;
-               oc->rotation = ovl->info.rotation;
-               oc->rotation_type = ovl->info.rotation_type;
-               oc->mirror = ovl->info.mirror;
-               oc->pos_x = ovl->info.pos_x;
-               oc->pos_y = ovl->info.pos_y;
-               oc->out_width = ovl->info.out_width;
-               oc->out_height = ovl->info.out_height;
-               oc->global_alpha = ovl->info.global_alpha;
-               oc->pre_mult_alpha = ovl->info.pre_mult_alpha;
+               oc->info = ovl->info;
 
                oc->replication =
                        dss_use_replication(dssdev, ovl->info.color_mode);
@@ -1302,11 +1368,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                oc->enabled = true;
 
-               oc->manual_update =
-                       dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
-                       dssdev->driver->get_update_mode(dssdev) !=
-                               OMAP_DSS_UPDATE_AUTO;
-
                ++num_planes_enabled;
        }
 
@@ -1334,20 +1395,10 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                mgr->info_dirty = false;
                mc->dirty = true;
-
-               mc->default_color = mgr->info.default_color;
-               mc->trans_key_type = mgr->info.trans_key_type;
-               mc->trans_key = mgr->info.trans_key;
-               mc->trans_enabled = mgr->info.trans_enabled;
-               mc->alpha_enabled = mgr->info.alpha_enabled;
-
-               mc->manual_upd_display =
-                       dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
+               mc->info = mgr->info;
 
                mc->manual_update =
-                       dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
-                       dssdev->driver->get_update_mode(dssdev) !=
-                               OMAP_DSS_UPDATE_AUTO;
+                       dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
        }
 
        /* XXX TODO: Try to get fifomerge working. The problem is that it
@@ -1368,7 +1419,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
        /* Configure overlay fifos */
        for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
                struct omap_dss_device *dssdev;
-               u32 size;
+               u32 size, burst_size;
 
                ovl = omap_dss_get_overlay(i);
 
@@ -1386,6 +1437,8 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
                if (use_fifomerge)
                        size *= 3;
 
+               burst_size = dispc_get_burst_size(ovl->id);
+
                switch (dssdev->type) {
                case OMAP_DISPLAY_TYPE_DPI:
                case OMAP_DISPLAY_TYPE_DBI:
@@ -1393,13 +1446,13 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
                case OMAP_DISPLAY_TYPE_VENC:
                case OMAP_DISPLAY_TYPE_HDMI:
                        default_get_overlay_fifo_thresholds(ovl->id, size,
-                                       &oc->burst_size, &oc->fifo_low,
+                                       burst_size, &oc->fifo_low,
                                        &oc->fifo_high);
                        break;
 #ifdef CONFIG_OMAP2_DSS_DSI
                case OMAP_DISPLAY_TYPE_DSI:
                        dsi_get_overlay_fifo_thresholds(ovl->id, size,
-                                       &oc->burst_size, &oc->fifo_low,
+                                       burst_size, &oc->fifo_low,
                                        &oc->fifo_high);
                        break;
 #endif
@@ -1409,7 +1462,6 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
        }
 
        r = 0;
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
        if (!dss_cache.irq_enabled) {
                u32 mask;
 
@@ -1422,10 +1474,11 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
                dss_cache.irq_enabled = true;
        }
        configure_dispc();
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        spin_unlock_irqrestore(&dss_cache.lock, flags);
 
+       dispc_runtime_put();
+
        return r;
 }
 
index 0f08025b1f0e95b9e65fb597d0fd63a16609f970..c84380c53c390633d0ec3f7f28ba32f48eb685f4 100644 (file)
@@ -84,32 +84,42 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
 
        old_mgr = ovl->manager;
 
+       r = dispc_runtime_get();
+       if (r)
+               return r;
+
        /* detach old manager */
        if (old_mgr) {
                r = ovl->unset_manager(ovl);
                if (r) {
                        DSSERR("detach failed\n");
-                       return r;
+                       goto err;
                }
 
                r = old_mgr->apply(old_mgr);
                if (r)
-                       return r;
+                       goto err;
        }
 
        if (mgr) {
                r = ovl->set_manager(ovl, mgr);
                if (r) {
                        DSSERR("Failed to attach overlay\n");
-                       return r;
+                       goto err;
                }
 
                r = mgr->apply(mgr);
                if (r)
-                       return r;
+                       goto err;
        }
 
+       dispc_runtime_put();
+
        return size;
+
+err:
+       dispc_runtime_put();
+       return r;
 }
 
 static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
@@ -238,6 +248,9 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
        u8 alpha;
        struct omap_overlay_info info;
 
+       if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
+               return -ENODEV;
+
        r = kstrtou8(buf, 0, &alpha);
        if (r)
                return r;
@@ -504,7 +517,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
 
        ovl->manager = mgr;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
        /* XXX: When there is an overlay on a DSI manual update display, and
         * the overlay is first disabled, then moved to tv, and enabled, we
         * seem to get SYNC_LOST_DIGIT error.
@@ -518,7 +530,6 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
         * the overlay, but before moving the overlay to TV.
         */
        dispc_set_channel_out(ovl->id, mgr->id);
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
        return 0;
 }
@@ -719,6 +730,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
        }
 
        if (mgr) {
+               dispc_runtime_get();
+
                for (i = 0; i < dss_feat_get_num_ovls(); i++) {
                        struct omap_overlay *ovl;
                        ovl = omap_dss_get_overlay(i);
@@ -728,6 +741,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
                                omap_dss_set_manager(ovl, mgr);
                        }
                }
+
+               dispc_runtime_put();
        }
 }
 
index c06fbe0bc6789bee3c32a796b1b9efdb4efc763d..39f4c597026accec26621bfc5cdedd75ad1e9c4b 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/hrtimer.h>
 #include <linux/seq_file.h>
 #include <linux/semaphore.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
 #include "dss.h"
@@ -120,12 +122,25 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
        return __raw_readl(rfbi.base + idx.idx);
 }
 
-static void rfbi_enable_clocks(bool enable)
+static int rfbi_runtime_get(void)
 {
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       int r;
+
+       DSSDBG("rfbi_runtime_get\n");
+
+       r = pm_runtime_get_sync(&rfbi.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+static void rfbi_runtime_put(void)
+{
+       int r;
+
+       DSSDBG("rfbi_runtime_put\n");
+
+       r = pm_runtime_put(&rfbi.pdev->dev);
+       WARN_ON(r < 0);
 }
 
 void rfbi_bus_lock(void)
@@ -805,7 +820,8 @@ void rfbi_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       if (rfbi_runtime_get())
+               return;
 
        DUMPREG(RFBI_REVISION);
        DUMPREG(RFBI_SYSCONFIG);
@@ -836,7 +852,7 @@ void rfbi_dump_regs(struct seq_file *s)
        DUMPREG(RFBI_VSYNC_WIDTH);
        DUMPREG(RFBI_HSYNC_WIDTH);
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       rfbi_runtime_put();
 #undef DUMPREG
 }
 
@@ -844,7 +860,9 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 {
        int r;
 
-       rfbi_enable_clocks(1);
+       r = rfbi_runtime_get();
+       if (r)
+               return r;
 
        r = omap_dss_start_device(dssdev);
        if (r) {
@@ -879,6 +897,7 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 err1:
        omap_dss_stop_device(dssdev);
 err0:
+       rfbi_runtime_put();
        return r;
 }
 EXPORT_SYMBOL(omapdss_rfbi_display_enable);
@@ -889,7 +908,7 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
                        DISPC_IRQ_FRAMEDONE);
        omap_dss_stop_device(dssdev);
 
-       rfbi_enable_clocks(0);
+       rfbi_runtime_put();
 }
 EXPORT_SYMBOL(omapdss_rfbi_display_disable);
 
@@ -904,8 +923,9 @@ int rfbi_init_display(struct omap_dss_device *dssdev)
 static int omap_rfbihw_probe(struct platform_device *pdev)
 {
        u32 rev;
-       u32 l;
        struct resource *rfbi_mem;
+       struct clk *clk;
+       int r;
 
        rfbi.pdev = pdev;
 
@@ -914,46 +934,102 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
        rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
        if (!rfbi_mem) {
                DSSERR("can't get IORESOURCE_MEM RFBI\n");
-               return -EINVAL;
+               r = -EINVAL;
+               goto err_ioremap;
        }
        rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem));
        if (!rfbi.base) {
                DSSERR("can't ioremap RFBI\n");
-               return -ENOMEM;
+               r = -ENOMEM;
+               goto err_ioremap;
        }
 
-       rfbi_enable_clocks(1);
+       pm_runtime_enable(&pdev->dev);
+
+       r = rfbi_runtime_get();
+       if (r)
+               goto err_get_rfbi;
 
        msleep(10);
 
-       rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
+       if (cpu_is_omap24xx() || cpu_is_omap34xx() || cpu_is_omap3630())
+               clk = dss_get_ick();
+       else
+               clk = clk_get(&pdev->dev, "ick");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get ick\n");
+               r = PTR_ERR(clk);
+               goto err_get_ick;
+       }
+
+       rfbi.l4_khz = clk_get_rate(clk) / 1000;
 
-       /* Enable autoidle and smart-idle */
-       l = rfbi_read_reg(RFBI_SYSCONFIG);
-       l |= (1 << 0) | (2 << 3);
-       rfbi_write_reg(RFBI_SYSCONFIG, l);
+       clk_put(clk);
 
        rev = rfbi_read_reg(RFBI_REVISION);
        dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
               FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
-       rfbi_enable_clocks(0);
+       rfbi_runtime_put();
 
        return 0;
+
+err_get_ick:
+       rfbi_runtime_put();
+err_get_rfbi:
+       pm_runtime_disable(&pdev->dev);
+       iounmap(rfbi.base);
+err_ioremap:
+       return r;
 }
 
 static int omap_rfbihw_remove(struct platform_device *pdev)
 {
+       pm_runtime_disable(&pdev->dev);
        iounmap(rfbi.base);
        return 0;
 }
 
+static int rfbi_runtime_suspend(struct device *dev)
+{
+       dispc_runtime_put();
+       dss_runtime_put();
+
+       return 0;
+}
+
+static int rfbi_runtime_resume(struct device *dev)
+{
+       int r;
+
+       r = dss_runtime_get();
+       if (r < 0)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r < 0)
+               goto err_get_dispc;
+
+       return 0;
+
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
+       return r;
+}
+
+static const struct dev_pm_ops rfbi_pm_ops = {
+       .runtime_suspend = rfbi_runtime_suspend,
+       .runtime_resume = rfbi_runtime_resume,
+};
+
 static struct platform_driver omap_rfbihw_driver = {
        .probe          = omap_rfbihw_probe,
        .remove         = omap_rfbihw_remove,
        .driver         = {
                .name   = "omapdss_rfbi",
                .owner  = THIS_MODULE,
+               .pm     = &rfbi_pm_ops,
        },
 };
 
index 0bd4b0350f809cde6daede29823fc6dd7f0acf0c..3a688c871a45579d8a695af71e88f91160a5e67c 100644 (file)
 #define DSS_SUBSYS_NAME "SDI"
 
 #include <linux/kernel.h>
-#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/regulator/consumer.h>
 
 #include <video/omapdss.h>
-#include <plat/cpu.h>
 #include "dss.h"
 
 static struct {
@@ -60,14 +58,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
-               goto err0;
+               goto err_start_dev;
        }
 
        r = regulator_enable(sdi.vdds_sdi_reg);
        if (r)
-               goto err1;
+               goto err_reg_enable;
 
-       dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       r = dss_runtime_get();
+       if (r)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r)
+               goto err_get_dispc;
 
        sdi_basic_init(dssdev);
 
@@ -80,7 +84,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
        r = dss_calc_clock_div(1, t->pixel_clock * 1000,
                        &dss_cinfo, &dispc_cinfo);
        if (r)
-               goto err2;
+               goto err_calc_clock_div;
 
        fck = dss_cinfo.fck;
        lck_div = dispc_cinfo.lck_div;
@@ -101,27 +105,34 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
 
        r = dss_set_clock_div(&dss_cinfo);
        if (r)
-               goto err2;
+               goto err_set_dss_clock_div;
 
        r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r)
-               goto err2;
+               goto err_set_dispc_clock_div;
 
        dss_sdi_init(dssdev->phy.sdi.datapairs);
        r = dss_sdi_enable();
        if (r)
-               goto err1;
+               goto err_sdi_enable;
        mdelay(2);
 
        dssdev->manager->enable(dssdev->manager);
 
        return 0;
-err2:
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+
+err_sdi_enable:
+err_set_dispc_clock_div:
+err_set_dss_clock_div:
+err_calc_clock_div:
+       dispc_runtime_put();
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
        regulator_disable(sdi.vdds_sdi_reg);
-err1:
+err_reg_enable:
        omap_dss_stop_device(dssdev);
-err0:
+err_start_dev:
        return r;
 }
 EXPORT_SYMBOL(omapdss_sdi_display_enable);
@@ -132,7 +143,8 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
 
        dss_sdi_disable();
 
-       dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dispc_runtime_put();
+       dss_runtime_put();
 
        regulator_disable(sdi.vdds_sdi_reg);
 
index 980f919ed987609b1b646af56ba47dee10b81767..173c66430daded57cbf59013a1e17d08c1423b04 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 #include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
+#include "dss_features.h"
 
 /* Venc registers */
 #define VENC_REV_ID                            0x00
@@ -292,6 +294,9 @@ static struct {
        struct mutex venc_lock;
        u32 wss_data;
        struct regulator *vdda_dac_reg;
+
+       struct clk      *tv_clk;
+       struct clk      *tv_dac_clk;
 } venc;
 
 static inline void venc_write_reg(int idx, u32 val)
@@ -380,14 +385,25 @@ static void venc_reset(void)
 #endif
 }
 
-static void venc_enable_clocks(int enable)
+static int venc_runtime_get(void)
+{
+       int r;
+
+       DSSDBG("venc_runtime_get\n");
+
+       r = pm_runtime_get_sync(&venc.pdev->dev);
+       WARN_ON(r < 0);
+       return r < 0 ? r : 0;
+}
+
+static void venc_runtime_put(void)
 {
-       if (enable)
-               dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
-                               DSS_CLK_VIDFCK);
-       else
-               dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK |
-                               DSS_CLK_VIDFCK);
+       int r;
+
+       DSSDBG("venc_runtime_put\n");
+
+       r = pm_runtime_put(&venc.pdev->dev);
+       WARN_ON(r < 0);
 }
 
 static const struct venc_config *venc_timings_to_config(
@@ -406,8 +422,6 @@ static void venc_power_on(struct omap_dss_device *dssdev)
 {
        u32 l;
 
-       venc_enable_clocks(1);
-
        venc_reset();
        venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
 
@@ -448,8 +462,6 @@ static void venc_power_off(struct omap_dss_device *dssdev)
                dssdev->platform_disable(dssdev);
 
        regulator_disable(venc.vdda_dac_reg);
-
-       venc_enable_clocks(0);
 }
 
 
@@ -487,6 +499,10 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
                goto err1;
        }
 
+       r = venc_runtime_get();
+       if (r)
+               goto err1;
+
        venc_power_on(dssdev);
 
        venc.wss_data = 0;
@@ -520,6 +536,8 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
 
        venc_power_off(dssdev);
 
+       venc_runtime_put();
+
        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 
        omap_dss_stop_device(dssdev);
@@ -538,20 +556,6 @@ static int venc_panel_resume(struct omap_dss_device *dssdev)
        return venc_panel_enable(dssdev);
 }
 
-static enum omap_dss_update_mode venc_get_update_mode(
-               struct omap_dss_device *dssdev)
-{
-       return OMAP_DSS_UPDATE_AUTO;
-}
-
-static int venc_set_update_mode(struct omap_dss_device *dssdev,
-               enum omap_dss_update_mode mode)
-{
-       if (mode != OMAP_DSS_UPDATE_AUTO)
-               return -EINVAL;
-       return 0;
-}
-
 static void venc_get_timings(struct omap_dss_device *dssdev,
                        struct omap_video_timings *timings)
 {
@@ -598,6 +602,7 @@ static u32 venc_get_wss(struct omap_dss_device *dssdev)
 static int venc_set_wss(struct omap_dss_device *dssdev,        u32 wss)
 {
        const struct venc_config *config;
+       int r;
 
        DSSDBG("venc_set_wss\n");
 
@@ -608,16 +613,19 @@ static int venc_set_wss(struct omap_dss_device *dssdev,   u32 wss)
        /* Invert due to VENC_L21_WC_CTL:INV=1 */
        venc.wss_data = (wss ^ 0xfffff) << 8;
 
-       venc_enable_clocks(1);
+       r = venc_runtime_get();
+       if (r)
+               goto err;
 
        venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
                        venc.wss_data);
 
-       venc_enable_clocks(0);
+       venc_runtime_put();
 
+err:
        mutex_unlock(&venc.venc_lock);
 
-       return 0;
+       return r;
 }
 
 static struct omap_dss_driver venc_driver = {
@@ -632,9 +640,6 @@ static struct omap_dss_driver venc_driver = {
        .get_resolution = omapdss_default_get_resolution,
        .get_recommended_bpp = omapdss_default_get_recommended_bpp,
 
-       .set_update_mode = venc_set_update_mode,
-       .get_update_mode = venc_get_update_mode,
-
        .get_timings    = venc_get_timings,
        .set_timings    = venc_set_timings,
        .check_timings  = venc_check_timings,
@@ -673,7 +678,8 @@ void venc_dump_regs(struct seq_file *s)
 {
 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
 
-       venc_enable_clocks(1);
+       if (venc_runtime_get())
+               return;
 
        DUMPREG(VENC_F_CONTROL);
        DUMPREG(VENC_VIDOUT_CTRL);
@@ -717,16 +723,56 @@ void venc_dump_regs(struct seq_file *s)
        DUMPREG(VENC_OUTPUT_CONTROL);
        DUMPREG(VENC_OUTPUT_TEST);
 
-       venc_enable_clocks(0);
+       venc_runtime_put();
 
 #undef DUMPREG
 }
 
+static int venc_get_clocks(struct platform_device *pdev)
+{
+       struct clk *clk;
+
+       clk = clk_get(&pdev->dev, "fck");
+       if (IS_ERR(clk)) {
+               DSSERR("can't get fck\n");
+               return PTR_ERR(clk);
+       }
+
+       venc.tv_clk = clk;
+
+       if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
+               if (cpu_is_omap34xx() || cpu_is_omap3630())
+                       clk = clk_get(&pdev->dev, "dss_96m_fck");
+               else
+                       clk = clk_get(&pdev->dev, "tv_dac_clk");
+               if (IS_ERR(clk)) {
+                       DSSERR("can't get tv_dac_clk\n");
+                       clk_put(venc.tv_clk);
+                       return PTR_ERR(clk);
+               }
+       } else {
+               clk = NULL;
+       }
+
+       venc.tv_dac_clk = clk;
+
+       return 0;
+}
+
+static void venc_put_clocks(void)
+{
+       if (venc.tv_clk)
+               clk_put(venc.tv_clk);
+       if (venc.tv_dac_clk)
+               clk_put(venc.tv_dac_clk);
+}
+
 /* VENC HW IP initialisation */
 static int omap_venchw_probe(struct platform_device *pdev)
 {
        u8 rev_id;
        struct resource *venc_mem;
+       int r;
 
        venc.pdev = pdev;
 
@@ -737,22 +783,40 @@ static int omap_venchw_probe(struct platform_device *pdev)
        venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
        if (!venc_mem) {
                DSSERR("can't get IORESOURCE_MEM VENC\n");
-               return -EINVAL;
+               r = -EINVAL;
+               goto err_ioremap;
        }
        venc.base = ioremap(venc_mem->start, resource_size(venc_mem));
        if (!venc.base) {
                DSSERR("can't ioremap VENC\n");
-               return -ENOMEM;
+               r = -ENOMEM;
+               goto err_ioremap;
        }
 
-       venc_enable_clocks(1);
+       r = venc_get_clocks(pdev);
+       if (r)
+               goto err_get_clk;
+
+       pm_runtime_enable(&pdev->dev);
+
+       r = venc_runtime_get();
+       if (r)
+               goto err_get_venc;
 
        rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
        dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
 
-       venc_enable_clocks(0);
+       venc_runtime_put();
 
        return omap_dss_register_driver(&venc_driver);
+
+err_get_venc:
+       pm_runtime_disable(&pdev->dev);
+       venc_put_clocks();
+err_get_clk:
+       iounmap(venc.base);
+err_ioremap:
+       return r;
 }
 
 static int omap_venchw_remove(struct platform_device *pdev)
@@ -763,16 +827,61 @@ static int omap_venchw_remove(struct platform_device *pdev)
        }
        omap_dss_unregister_driver(&venc_driver);
 
+       pm_runtime_disable(&pdev->dev);
+       venc_put_clocks();
+
        iounmap(venc.base);
        return 0;
 }
 
+static int venc_runtime_suspend(struct device *dev)
+{
+       if (venc.tv_dac_clk)
+               clk_disable(venc.tv_dac_clk);
+       clk_disable(venc.tv_clk);
+
+       dispc_runtime_put();
+       dss_runtime_put();
+
+       return 0;
+}
+
+static int venc_runtime_resume(struct device *dev)
+{
+       int r;
+
+       r = dss_runtime_get();
+       if (r < 0)
+               goto err_get_dss;
+
+       r = dispc_runtime_get();
+       if (r < 0)
+               goto err_get_dispc;
+
+       clk_enable(venc.tv_clk);
+       if (venc.tv_dac_clk)
+               clk_enable(venc.tv_dac_clk);
+
+       return 0;
+
+err_get_dispc:
+       dss_runtime_put();
+err_get_dss:
+       return r;
+}
+
+static const struct dev_pm_ops venc_pm_ops = {
+       .runtime_suspend = venc_runtime_suspend,
+       .runtime_resume = venc_runtime_resume,
+};
+
 static struct platform_driver omap_venchw_driver = {
        .probe          = omap_venchw_probe,
        .remove         = omap_venchw_remove,
        .driver         = {
                .name   = "omapdss_venc",
                .owner  = THIS_MODULE,
+               .pm     = &venc_pm_ops,
        },
 };
 
index cff450392b797053ac7aff3acd5d5bc7a51d0030..6b1ac23dbbd36910f5185bf78cc0f4357bb60c08 100644 (file)
@@ -316,67 +316,67 @@ int omapfb_update_window(struct fb_info *fbi,
 }
 EXPORT_SYMBOL(omapfb_update_window);
 
-static int omapfb_set_update_mode(struct fb_info *fbi,
+int omapfb_set_update_mode(struct fb_info *fbi,
                                   enum omapfb_update_mode mode)
 {
        struct omap_dss_device *display = fb2display(fbi);
-       enum omap_dss_update_mode um;
+       struct omapfb_info *ofbi = FB2OFB(fbi);
+       struct omapfb2_device *fbdev = ofbi->fbdev;
+       struct omapfb_display_data *d;
        int r;
 
-       if (!display || !display->driver->set_update_mode)
+       if (!display)
                return -EINVAL;
 
-       switch (mode) {
-       case OMAPFB_UPDATE_DISABLED:
-               um = OMAP_DSS_UPDATE_DISABLED;
-               break;
+       if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
+               return -EINVAL;
 
-       case OMAPFB_AUTO_UPDATE:
-               um = OMAP_DSS_UPDATE_AUTO;
-               break;
+       omapfb_lock(fbdev);
 
-       case OMAPFB_MANUAL_UPDATE:
-               um = OMAP_DSS_UPDATE_MANUAL;
-               break;
+       d = get_display_data(fbdev, display);
 
-       default:
-               return -EINVAL;
+       if (d->update_mode == mode) {
+               omapfb_unlock(fbdev);
+               return 0;
        }
 
-       r = display->driver->set_update_mode(display, um);
+       r = 0;
+
+       if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+               if (mode == OMAPFB_AUTO_UPDATE)
+                       omapfb_start_auto_update(fbdev, display);
+               else /* MANUAL_UPDATE */
+                       omapfb_stop_auto_update(fbdev, display);
+
+               d->update_mode = mode;
+       } else { /* AUTO_UPDATE */
+               if (mode == OMAPFB_MANUAL_UPDATE)
+                       r = -EINVAL;
+       }
+
+       omapfb_unlock(fbdev);
 
        return r;
 }
 
-static int omapfb_get_update_mode(struct fb_info *fbi,
+int omapfb_get_update_mode(struct fb_info *fbi,
                enum omapfb_update_mode *mode)
 {
        struct omap_dss_device *display = fb2display(fbi);
-       enum omap_dss_update_mode m;
+       struct omapfb_info *ofbi = FB2OFB(fbi);
+       struct omapfb2_device *fbdev = ofbi->fbdev;
+       struct omapfb_display_data *d;
 
        if (!display)
                return -EINVAL;
 
-       if (!display->driver->get_update_mode) {
-               *mode = OMAPFB_AUTO_UPDATE;
-               return 0;
-       }
+       omapfb_lock(fbdev);
 
-       m = display->driver->get_update_mode(display);
+       d = get_display_data(fbdev, display);
 
-       switch (m) {
-       case OMAP_DSS_UPDATE_DISABLED:
-               *mode = OMAPFB_UPDATE_DISABLED;
-               break;
-       case OMAP_DSS_UPDATE_AUTO:
-               *mode = OMAPFB_AUTO_UPDATE;
-               break;
-       case OMAP_DSS_UPDATE_MANUAL:
-               *mode = OMAPFB_MANUAL_UPDATE;
-               break;
-       default:
-               BUG();
-       }
+       *mode = d->update_mode;
+
+       omapfb_unlock(fbdev);
 
        return 0;
 }
index 505bc12a3031a877ad5617a0259dce21f519f970..602b71a92d3c3092db31f7b0fd349ce2e938b796 100644 (file)
@@ -46,6 +46,10 @@ static char *def_vram;
 static int def_vrfb;
 static int def_rotate;
 static int def_mirror;
+static bool auto_update;
+static unsigned int auto_update_freq;
+module_param(auto_update, bool, 0);
+module_param(auto_update_freq, uint, 0644);
 
 #ifdef DEBUG
 unsigned int omapfb_debug;
@@ -1242,6 +1246,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
        struct omapfb_info *ofbi = FB2OFB(fbi);
        struct omapfb2_device *fbdev = ofbi->fbdev;
        struct omap_dss_device *display = fb2display(fbi);
+       struct omapfb_display_data *d;
        int r = 0;
 
        if (!display)
@@ -1249,6 +1254,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
 
        omapfb_lock(fbdev);
 
+       d = get_display_data(fbdev, display);
+
        switch (blank) {
        case FB_BLANK_UNBLANK:
                if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
@@ -1257,6 +1264,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
                if (display->driver->resume)
                        r = display->driver->resume(display);
 
+               if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) &&
+                               d->update_mode == OMAPFB_AUTO_UPDATE &&
+                               !d->auto_update_work_enabled)
+                       omapfb_start_auto_update(fbdev, display);
+
                break;
 
        case FB_BLANK_NORMAL:
@@ -1268,6 +1280,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
                if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
                        goto exit;
 
+               if (d->auto_update_work_enabled)
+                       omapfb_stop_auto_update(fbdev, display);
+
                if (display->driver->suspend)
                        r = display->driver->suspend(display);
 
@@ -1724,6 +1739,78 @@ err:
        return r;
 }
 
+static void omapfb_auto_update_work(struct work_struct *work)
+{
+       struct omap_dss_device *dssdev;
+       struct omap_dss_driver *dssdrv;
+       struct omapfb_display_data *d;
+       u16 w, h;
+       unsigned int freq;
+       struct omapfb2_device *fbdev;
+
+       d = container_of(work, struct omapfb_display_data,
+                       auto_update_work.work);
+
+       dssdev = d->dssdev;
+       dssdrv = dssdev->driver;
+       fbdev = d->fbdev;
+
+       if (!dssdrv || !dssdrv->update)
+               return;
+
+       if (dssdrv->sync)
+               dssdrv->sync(dssdev);
+
+       dssdrv->get_resolution(dssdev, &w, &h);
+       dssdrv->update(dssdev, 0, 0, w, h);
+
+       freq = auto_update_freq;
+       if (freq == 0)
+               freq = 20;
+       queue_delayed_work(fbdev->auto_update_wq,
+                       &d->auto_update_work, HZ / freq);
+}
+
+void omapfb_start_auto_update(struct omapfb2_device *fbdev,
+               struct omap_dss_device *display)
+{
+       struct omapfb_display_data *d;
+
+       if (fbdev->auto_update_wq == NULL) {
+               struct workqueue_struct *wq;
+
+               wq = create_singlethread_workqueue("omapfb_auto_update");
+
+               if (wq == NULL) {
+                       dev_err(fbdev->dev, "Failed to create workqueue for "
+                                       "auto-update\n");
+                       return;
+               }
+
+               fbdev->auto_update_wq = wq;
+       }
+
+       d = get_display_data(fbdev, display);
+
+       INIT_DELAYED_WORK(&d->auto_update_work, omapfb_auto_update_work);
+
+       d->auto_update_work_enabled = true;
+
+       omapfb_auto_update_work(&d->auto_update_work.work);
+}
+
+void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
+               struct omap_dss_device *display)
+{
+       struct omapfb_display_data *d;
+
+       d = get_display_data(fbdev, display);
+
+       cancel_delayed_work_sync(&d->auto_update_work);
+
+       d->auto_update_work_enabled = false;
+}
+
 /* initialize fb_info, var, fix to something sane based on the display */
 static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
 {
@@ -1858,10 +1945,21 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev)
        }
 
        for (i = 0; i < fbdev->num_displays; i++) {
-               if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
-                       fbdev->displays[i]->driver->disable(fbdev->displays[i]);
+               struct omap_dss_device *dssdev = fbdev->displays[i].dssdev;
+
+               if (fbdev->displays[i].auto_update_work_enabled)
+                       omapfb_stop_auto_update(fbdev, dssdev);
+
+               if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
+                       dssdev->driver->disable(dssdev);
+
+               omap_dss_put_device(dssdev);
+       }
 
-               omap_dss_put_device(fbdev->displays[i]);
+       if (fbdev->auto_update_wq != NULL) {
+               flush_workqueue(fbdev->auto_update_wq);
+               destroy_workqueue(fbdev->auto_update_wq);
+               fbdev->auto_update_wq = NULL;
        }
 
        dev_set_drvdata(fbdev->dev, NULL);
@@ -2084,14 +2182,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
        int r;
        u8 bpp;
        struct omap_video_timings timings, temp_timings;
+       struct omapfb_display_data *d;
 
        r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
        if (r)
                return r;
 
-       fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display;
-       fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp;
-       ++fbdev->num_bpp_overrides;
+       d = get_display_data(fbdev, display);
+       d->bpp_override = bpp;
 
        if (display->driver->check_timings) {
                r = display->driver->check_timings(display, &timings);
@@ -2117,14 +2215,14 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
 static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
                struct omap_dss_device *dssdev)
 {
-       int i;
+       struct omapfb_display_data *d;
 
        BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
 
-       for (i = 0; i < fbdev->num_bpp_overrides; ++i) {
-               if (dssdev == fbdev->bpp_overrides[i].dssdev)
-                       return fbdev->bpp_overrides[i].bpp;
-       }
+       d = get_display_data(fbdev, dssdev);
+
+       if (d->bpp_override != 0)
+               return d->bpp_override;
 
        return dssdev->driver->get_recommended_bpp(dssdev);
 }
@@ -2156,9 +2254,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
 
                display = NULL;
                for (i = 0; i < fbdev->num_displays; ++i) {
-                       if (strcmp(fbdev->displays[i]->name,
+                       if (strcmp(fbdev->displays[i].dssdev->name,
                                                display_str) == 0) {
-                               display = fbdev->displays[i];
+                               display = fbdev->displays[i].dssdev;
                                break;
                        }
                }
@@ -2182,6 +2280,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
                struct omap_dss_device *dssdev)
 {
        struct omap_dss_driver *dssdrv = dssdev->driver;
+       struct omapfb_display_data *d;
        int r;
 
        r = dssdrv->enable(dssdev);
@@ -2191,8 +2290,20 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
                return r;
        }
 
+       d = get_display_data(fbdev, dssdev);
+
+       d->fbdev = fbdev;
+
        if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
                u16 w, h;
+
+               if (auto_update) {
+                       omapfb_start_auto_update(fbdev, dssdev);
+                       d->update_mode = OMAPFB_AUTO_UPDATE;
+               } else {
+                       d->update_mode = OMAPFB_MANUAL_UPDATE;
+               }
+
                if (dssdrv->enable_te) {
                        r = dssdrv->enable_te(dssdev, 1);
                        if (r) {
@@ -2201,16 +2312,6 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
                        }
                }
 
-               if (dssdrv->set_update_mode) {
-                       r = dssdrv->set_update_mode(dssdev,
-                                       OMAP_DSS_UPDATE_MANUAL);
-                       if (r) {
-                               dev_err(fbdev->dev,
-                                               "Failed to set update mode\n");
-                               return r;
-                       }
-               }
-
                dssdrv->get_resolution(dssdev, &w, &h);
                r = dssdrv->update(dssdev, 0, 0, w, h);
                if (r) {
@@ -2219,15 +2320,7 @@ static int omapfb_init_display(struct omapfb2_device *fbdev,
                        return r;
                }
        } else {
-               if (dssdrv->set_update_mode) {
-                       r = dssdrv->set_update_mode(dssdev,
-                                       OMAP_DSS_UPDATE_AUTO);
-                       if (r) {
-                               dev_err(fbdev->dev,
-                                               "Failed to set update mode\n");
-                               return r;
-                       }
-               }
+               d->update_mode = OMAPFB_AUTO_UPDATE;
        }
 
        return 0;
@@ -2275,6 +2368,8 @@ static int omapfb_probe(struct platform_device *pdev)
        fbdev->num_displays = 0;
        dssdev = NULL;
        for_each_dss_dev(dssdev) {
+               struct omapfb_display_data *d;
+
                omap_dss_get_device(dssdev);
 
                if (!dssdev->driver) {
@@ -2282,7 +2377,12 @@ static int omapfb_probe(struct platform_device *pdev)
                        r = -ENODEV;
                }
 
-               fbdev->displays[fbdev->num_displays++] = dssdev;
+               d = &fbdev->displays[fbdev->num_displays++];
+               d->dssdev = dssdev;
+               if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
+                       d->update_mode = OMAPFB_MANUAL_UPDATE;
+               else
+                       d->update_mode = OMAPFB_AUTO_UPDATE;
        }
 
        if (r)
index 2f5e817b2a9a65904e4f41631036fb350c478784..153bf1aceebcc3248051e5c29c80fc4548e6bf50 100644 (file)
@@ -518,6 +518,39 @@ static ssize_t show_virt(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
 }
 
+static ssize_t show_upd_mode(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct fb_info *fbi = dev_get_drvdata(dev);
+       enum omapfb_update_mode mode;
+       int r;
+
+       r = omapfb_get_update_mode(fbi, &mode);
+
+       if (r)
+               return r;
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
+}
+
+static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct fb_info *fbi = dev_get_drvdata(dev);
+       unsigned mode;
+       int r;
+
+       r = kstrtouint(buf, 0, &mode);
+       if (r)
+               return r;
+
+       r = omapfb_set_update_mode(fbi, mode);
+       if (r)
+               return r;
+
+       return count;
+}
+
 static struct device_attribute omapfb_attrs[] = {
        __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
                        store_rotate_type),
@@ -528,6 +561,7 @@ static struct device_attribute omapfb_attrs[] = {
                        store_overlays_rotate),
        __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
        __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
+       __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
 };
 
 int omapfb_create_sysfs(struct omapfb2_device *fbdev)
index aa1b1d9742760e86507102da28635a2f84a65ca7..fdf0edeccf4e9f5972aa0679952efd22a297bb92 100644 (file)
@@ -73,6 +73,15 @@ struct omapfb_info {
        bool mirror;
 };
 
+struct omapfb_display_data {
+       struct omapfb2_device *fbdev;
+       struct omap_dss_device *dssdev;
+       u8 bpp_override;
+       enum omapfb_update_mode update_mode;
+       bool auto_update_work_enabled;
+       struct delayed_work auto_update_work;
+};
+
 struct omapfb2_device {
        struct device *dev;
        struct mutex  mtx;
@@ -86,17 +95,13 @@ struct omapfb2_device {
        struct omapfb2_mem_region regions[10];
 
        unsigned num_displays;
-       struct omap_dss_device *displays[10];
+       struct omapfb_display_data displays[10];
        unsigned num_overlays;
        struct omap_overlay *overlays[10];
        unsigned num_managers;
        struct omap_overlay_manager *managers[10];
 
-       unsigned num_bpp_overrides;
-       struct {
-               struct omap_dss_device *dssdev;
-               u8 bpp;
-       } bpp_overrides[10];
+       struct workqueue_struct *auto_update_wq;
 };
 
 struct omapfb_colormode {
@@ -128,6 +133,13 @@ int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
 int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
                u16 posx, u16 posy, u16 outw, u16 outh);
 
+void omapfb_start_auto_update(struct omapfb2_device *fbdev,
+               struct omap_dss_device *display);
+void omapfb_stop_auto_update(struct omapfb2_device *fbdev,
+               struct omap_dss_device *display);
+int omapfb_get_update_mode(struct fb_info *fbi, enum omapfb_update_mode *mode);
+int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode);
+
 /* find the display connected to this fb, if any */
 static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
 {
@@ -143,6 +155,19 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
        return NULL;
 }
 
+static inline struct omapfb_display_data *get_display_data(
+               struct omapfb2_device *fbdev, struct omap_dss_device *dssdev)
+{
+       int i;
+
+       for (i = 0; i < fbdev->num_displays; ++i)
+               if (fbdev->displays[i].dssdev == dssdev)
+                       return &fbdev->displays[i];
+
+       /* This should never happen */
+       BUG();
+}
+
 static inline void omapfb_lock(struct omapfb2_device *fbdev)
 {
        mutex_lock(&fbdev->mtx);
index 21d816e9dfa51d7166d61c9b2272192040b56ad3..f441726ddf2bbf2a988981e32066806720fde5c3 100644 (file)
@@ -28,6 +28,17 @@ menuconfig WATCHDOG
 
 if WATCHDOG
 
+config WATCHDOG_CORE
+       bool "WatchDog Timer Driver Core"
+       ---help---
+         Say Y here if you want to use the new watchdog timer driver core.
+         This driver provides a framework for all watchdog timer drivers
+         and gives them the /dev/watchdog interface (and later also the
+         sysfs interface).
+
+         To compile this driver as a module, choose M here: the module will
+         be called watchdog.
+
 config WATCHDOG_NOWAYOUT
        bool "Disable watchdog shutdown on close"
        help
@@ -186,6 +197,15 @@ config SA1100_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called sa1100_wdt.
 
+config DW_WATCHDOG
+       tristate "Synopsys DesignWare watchdog"
+       depends on ARM && HAVE_CLK
+       help
+         Say Y here if to include support for the Synopsys DesignWare
+         watchdog timer found in many ARM chips.
+         To compile this driver as a module, choose M here: the
+         module will be called dw_wdt.
+
 config MPCORE_WATCHDOG
        tristate "MPcore watchdog"
        depends on HAVE_ARM_TWD
@@ -321,7 +341,7 @@ config MAX63XX_WATCHDOG
 
 config IMX2_WDT
        tristate "IMX2+ Watchdog"
-       depends on ARCH_MX2 || ARCH_MX25 || ARCH_MX3 || ARCH_MX5
+       depends on IMX_HAVE_PLATFORM_IMX2_WDT
        help
          This is the driver for the hardware watchdog
          on the Freescale IMX2 and later processors.
@@ -879,6 +899,20 @@ config M54xx_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called m54xx_wdt.
 
+# MicroBlaze Architecture
+
+config XILINX_WATCHDOG
+       tristate "Xilinx Watchdog timer"
+       depends on MICROBLAZE
+       ---help---
+         Watchdog driver for the xps_timebase_wdt ip core.
+
+         IMPORTANT: The xps_timebase_wdt parent must have the property
+         "clock-frequency" at device tree.
+
+         To compile this driver as a module, choose M here: the
+         module will be called of_xilinx_wdt.
+
 # MIPS Architecture
 
 config ATH79_WDT
index ed26f7094e470ac8cd06317136305ea1a01ea2a8..55bd5740e91000f1616da7ad0a4adf5eb4c33ac7 100644 (file)
@@ -2,6 +2,10 @@
 # Makefile for the WatchDog device drivers.
 #
 
+# The WatchDog Timer Driver Core.
+watchdog-objs  += watchdog_core.o watchdog_dev.o
+obj-$(CONFIG_WATCHDOG_CORE)    += watchdog.o
+
 # Only one watchdog can succeed. We probe the ISA/PCI/USB based
 # watchdog-cards first, then the architecture specific watchdog
 # drivers and then the architecture independent "softdog" driver.
@@ -37,6 +41,7 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
 obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
+obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o
 obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
 obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
@@ -109,6 +114,9 @@ obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
 # M68K Architecture
 obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o
 
+# MicroBlaze Architecture
+obj-$(CONFIG_XILINX_WATCHDOG) += of_xilinx_wdt.o
+
 # MIPS Architecture
 obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o
 obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
index eac26021e8da2e2681c6c0f82eb9a40d2292c0af..87445b2d72a7375f36290ab7c74a404e0dbeaa21 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/bitops.h>
 #include <linux/uaccess.h>
 
-#include <mach/at91_wdt.h>
+#include "at91sam9_wdt.h"
 
 #define DRV_NAME "AT91SAM9 Watchdog"
 
@@ -284,27 +284,8 @@ static int __exit at91wdt_remove(struct platform_device *pdev)
        return res;
 }
 
-#ifdef CONFIG_PM
-
-static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
-{
-       return 0;
-}
-
-static int at91wdt_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-
-#else
-#define at91wdt_suspend        NULL
-#define at91wdt_resume NULL
-#endif
-
 static struct platform_driver at91wdt_driver = {
        .remove         = __exit_p(at91wdt_remove),
-       .suspend        = at91wdt_suspend,
-       .resume         = at91wdt_resume,
        .driver         = {
                .name   = "at91_wdt",
                .owner  = THIS_MODULE,
diff --git a/drivers/watchdog/at91sam9_wdt.h b/drivers/watchdog/at91sam9_wdt.h
new file mode 100644 (file)
index 0000000..757f9ca
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * drivers/watchdog/at91sam9_wdt.h
+ *
+ * Copyright (C) 2007 Andrew Victor
+ * Copyright (C) 2007 Atmel Corporation.
+ *
+ * Watchdog Timer (WDT) - System peripherals regsters.
+ * Based on AT91SAM9261 datasheet revision D.
+ *
+ * This 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 AT91_WDT_H
+#define AT91_WDT_H
+
+#define AT91_WDT_CR            (AT91_WDT + 0x00)       /* Watchdog Control Register */
+#define                AT91_WDT_WDRSTT         (1    << 0)             /* Restart */
+#define                AT91_WDT_KEY            (0xa5 << 24)            /* KEY Password */
+
+#define AT91_WDT_MR            (AT91_WDT + 0x04)       /* Watchdog Mode Register */
+#define                AT91_WDT_WDV            (0xfff << 0)            /* Counter Value */
+#define                AT91_WDT_WDFIEN         (1     << 12)           /* Fault Interrupt Enable */
+#define                AT91_WDT_WDRSTEN        (1     << 13)           /* Reset Processor */
+#define                AT91_WDT_WDRPROC        (1     << 14)           /* Timer Restart */
+#define                AT91_WDT_WDDIS          (1     << 15)           /* Watchdog Disable */
+#define                AT91_WDT_WDD            (0xfff << 16)           /* Delta Value */
+#define                AT91_WDT_WDDBGHLT       (1     << 28)           /* Debug Halt */
+#define                AT91_WDT_WDIDLEHLT      (1     << 29)           /* Idle Halt */
+
+#define AT91_WDT_SR            (AT91_WDT + 0x08)       /* Watchdog Status Register */
+#define                AT91_WDT_WDUNF          (1 << 0)                /* Watchdog Underflow */
+#define                AT91_WDT_WDERR          (1 << 1)                /* Watchdog Error */
+
+#endif
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
new file mode 100644 (file)
index 0000000..f10f8c0
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2010-2011 Picochip Ltd., Jamie Iles
+ * http://www.picochip.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 file implements a driver for the Synopsys DesignWare watchdog device
+ * in the many ARM subsystems. The watchdog has 16 different timeout periods
+ * and these are a function of the input clock frequency.
+ *
+ * The DesignWare watchdog cannot be stopped once it has been started so we
+ * use a software timer to implement a ping that will keep the watchdog alive.
+ * If we receive an expected close for the watchdog then we keep the timer
+ * running, otherwise the timer is stopped and the watchdog will expire.
+ */
+#define pr_fmt(fmt) "dw_wdt: " fmt
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/uaccess.h>
+#include <linux/watchdog.h>
+
+#define WDOG_CONTROL_REG_OFFSET                    0x00
+#define WDOG_CONTROL_REG_WDT_EN_MASK       0x01
+#define WDOG_TIMEOUT_RANGE_REG_OFFSET      0x04
+#define WDOG_CURRENT_COUNT_REG_OFFSET      0x08
+#define WDOG_COUNTER_RESTART_REG_OFFSET     0x0c
+#define WDOG_COUNTER_RESTART_KICK_VALUE            0x76
+
+/* The maximum TOP (timeout period) value that can be set in the watchdog. */
+#define DW_WDT_MAX_TOP         15
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+                "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+#define WDT_TIMEOUT            (HZ / 2)
+
+static struct {
+       spinlock_t              lock;
+       void __iomem            *regs;
+       struct clk              *clk;
+       unsigned long           in_use;
+       unsigned long           next_heartbeat;
+       struct timer_list       timer;
+       int                     expect_close;
+} dw_wdt;
+
+static inline int dw_wdt_is_enabled(void)
+{
+       return readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET) &
+               WDOG_CONTROL_REG_WDT_EN_MASK;
+}
+
+static inline int dw_wdt_top_in_seconds(unsigned top)
+{
+       /*
+        * There are 16 possible timeout values in 0..15 where the number of
+        * cycles is 2 ^ (16 + i) and the watchdog counts down.
+        */
+       return (1 << (16 + top)) / clk_get_rate(dw_wdt.clk);
+}
+
+static int dw_wdt_get_top(void)
+{
+       int top = readl(dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET) & 0xF;
+
+       return dw_wdt_top_in_seconds(top);
+}
+
+static inline void dw_wdt_set_next_heartbeat(void)
+{
+       dw_wdt.next_heartbeat = jiffies + dw_wdt_get_top() * HZ;
+}
+
+static int dw_wdt_set_top(unsigned top_s)
+{
+       int i, top_val = DW_WDT_MAX_TOP;
+
+       /*
+        * Iterate over the timeout values until we find the closest match. We
+        * always look for >=.
+        */
+       for (i = 0; i <= DW_WDT_MAX_TOP; ++i)
+               if (dw_wdt_top_in_seconds(i) >= top_s) {
+                       top_val = i;
+                       break;
+               }
+
+       /* Set the new value in the watchdog. */
+       writel(top_val, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
+
+       dw_wdt_set_next_heartbeat();
+
+       return dw_wdt_top_in_seconds(top_val);
+}
+
+static void dw_wdt_keepalive(void)
+{
+       writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
+              WDOG_COUNTER_RESTART_REG_OFFSET);
+}
+
+static void dw_wdt_ping(unsigned long data)
+{
+       if (time_before(jiffies, dw_wdt.next_heartbeat) ||
+           (!nowayout && !dw_wdt.in_use)) {
+               dw_wdt_keepalive();
+               mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
+       } else
+               pr_crit("keepalive missed, machine will reset\n");
+}
+
+static int dw_wdt_open(struct inode *inode, struct file *filp)
+{
+       if (test_and_set_bit(0, &dw_wdt.in_use))
+               return -EBUSY;
+
+       /* Make sure we don't get unloaded. */
+       __module_get(THIS_MODULE);
+
+       spin_lock(&dw_wdt.lock);
+       if (!dw_wdt_is_enabled()) {
+               /*
+                * The watchdog is not currently enabled. Set the timeout to
+                * the maximum and then start it.
+                */
+               dw_wdt_set_top(DW_WDT_MAX_TOP);
+               writel(WDOG_CONTROL_REG_WDT_EN_MASK,
+                      dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
+       }
+
+       dw_wdt_set_next_heartbeat();
+
+       spin_unlock(&dw_wdt.lock);
+
+       return nonseekable_open(inode, filp);
+}
+
+ssize_t dw_wdt_write(struct file *filp, const char __user *buf, size_t len,
+                    loff_t *offset)
+{
+       if (!len)
+               return 0;
+
+       if (!nowayout) {
+               size_t i;
+
+               dw_wdt.expect_close = 0;
+
+               for (i = 0; i < len; ++i) {
+                       char c;
+
+                       if (get_user(c, buf + i))
+                               return -EFAULT;
+
+                       if (c == 'V') {
+                               dw_wdt.expect_close = 1;
+                               break;
+                       }
+               }
+       }
+
+       dw_wdt_set_next_heartbeat();
+       mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
+
+       return len;
+}
+
+static u32 dw_wdt_time_left(void)
+{
+       return readl(dw_wdt.regs + WDOG_CURRENT_COUNT_REG_OFFSET) /
+               clk_get_rate(dw_wdt.clk);
+}
+
+static const struct watchdog_info dw_wdt_ident = {
+       .options        = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
+                         WDIOF_MAGICCLOSE,
+       .identity       = "Synopsys DesignWare Watchdog",
+};
+
+static long dw_wdt_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       unsigned long val;
+       int timeout;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user((struct watchdog_info *)arg, &dw_wdt_ident,
+                                   sizeof(dw_wdt_ident)) ? -EFAULT : 0;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, (int *)arg);
+
+       case WDIOC_KEEPALIVE:
+               dw_wdt_set_next_heartbeat();
+               return 0;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(val, (int __user *)arg))
+                       return -EFAULT;
+               timeout = dw_wdt_set_top(val);
+               return put_user(timeout , (int __user *)arg);
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(dw_wdt_get_top(), (int __user *)arg);
+
+       case WDIOC_GETTIMELEFT:
+               /* Get the time left until expiry. */
+               if (get_user(val, (int __user *)arg))
+                       return -EFAULT;
+               return put_user(dw_wdt_time_left(), (int __user *)arg);
+
+       default:
+               return -ENOTTY;
+       }
+}
+
+static int dw_wdt_release(struct inode *inode, struct file *filp)
+{
+       clear_bit(0, &dw_wdt.in_use);
+
+       if (!dw_wdt.expect_close) {
+               del_timer(&dw_wdt.timer);
+
+               if (!nowayout)
+                       pr_crit("unexpected close, system will reboot soon\n");
+               else
+                       pr_crit("watchdog cannot be disabled, system will reboot soon\n");
+       }
+
+       dw_wdt.expect_close = 0;
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int dw_wdt_suspend(struct device *dev)
+{
+       clk_disable(dw_wdt.clk);
+
+       return 0;
+}
+
+static int dw_wdt_resume(struct device *dev)
+{
+       int err = clk_enable(dw_wdt.clk);
+
+       if (err)
+               return err;
+
+       dw_wdt_keepalive();
+
+       return 0;
+}
+
+static const struct dev_pm_ops dw_wdt_pm_ops = {
+       .suspend        = dw_wdt_suspend,
+       .resume         = dw_wdt_resume,
+};
+#endif /* CONFIG_PM */
+
+static const struct file_operations wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .open           = dw_wdt_open,
+       .write          = dw_wdt_write,
+       .unlocked_ioctl = dw_wdt_ioctl,
+       .release        = dw_wdt_release
+};
+
+static struct miscdevice dw_wdt_miscdev = {
+       .fops           = &wdt_fops,
+       .name           = "watchdog",
+       .minor          = WATCHDOG_MINOR,
+};
+
+static int __devinit dw_wdt_drv_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (!mem)
+               return -EINVAL;
+
+       if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
+                                    "dw_wdt"))
+               return -ENOMEM;
+
+       dw_wdt.regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+       if (!dw_wdt.regs)
+               return -ENOMEM;
+
+       dw_wdt.clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(dw_wdt.clk))
+               return PTR_ERR(dw_wdt.clk);
+
+       ret = clk_enable(dw_wdt.clk);
+       if (ret)
+               goto out_put_clk;
+
+       spin_lock_init(&dw_wdt.lock);
+
+       ret = misc_register(&dw_wdt_miscdev);
+       if (ret)
+               goto out_disable_clk;
+
+       dw_wdt_set_next_heartbeat();
+       setup_timer(&dw_wdt.timer, dw_wdt_ping, 0);
+       mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
+
+       return 0;
+
+out_disable_clk:
+       clk_disable(dw_wdt.clk);
+out_put_clk:
+       clk_put(dw_wdt.clk);
+
+       return ret;
+}
+
+static int __devexit dw_wdt_drv_remove(struct platform_device *pdev)
+{
+       misc_deregister(&dw_wdt_miscdev);
+
+       clk_disable(dw_wdt.clk);
+       clk_put(dw_wdt.clk);
+
+       return 0;
+}
+
+static struct platform_driver dw_wdt_driver = {
+       .probe          = dw_wdt_drv_probe,
+       .remove         = __devexit_p(dw_wdt_drv_remove),
+       .driver         = {
+               .name   = "dw_wdt",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &dw_wdt_pm_ops,
+#endif /* CONFIG_PM */
+       },
+};
+
+static int __init dw_wdt_watchdog_init(void)
+{
+       return platform_driver_register(&dw_wdt_driver);
+}
+module_init(dw_wdt_watchdog_init);
+
+static void __exit dw_wdt_watchdog_exit(void)
+{
+       platform_driver_unregister(&dw_wdt_driver);
+}
+module_exit(dw_wdt_watchdog_exit);
+
+MODULE_AUTHOR("Jamie Iles");
+MODULE_DESCRIPTION("Synopsys DesignWare Watchdog Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 8cb26855bfede30eeb6782f693a29add442cdaa1..410fba45378d404f5ce4045faaf6f3c9782a957b 100644 (file)
@@ -36,7 +36,7 @@
 #include <asm/cacheflush.h>
 #endif /* CONFIG_HPWDT_NMI_DECODING */
 
-#define HPWDT_VERSION                  "1.2.0"
+#define HPWDT_VERSION                  "1.3.0"
 #define SECS_TO_TICKS(secs)            ((secs) * 1000 / 128)
 #define TICKS_TO_SECS(ticks)           ((ticks) * 128 / 1000)
 #define HPWDT_MAX_TIMER                        TICKS_TO_SECS(65535)
@@ -87,6 +87,19 @@ struct smbios_cru64_info {
 };
 #define SMBIOS_CRU64_INFORMATION       212
 
+/* type 219 */
+struct smbios_proliant_info {
+       u8 type;
+       u8 byte_length;
+       u16 handle;
+       u32 power_features;
+       u32 omega_features;
+       u32 reserved;
+       u32 misc_features;
+};
+#define SMBIOS_ICRU_INFORMATION                219
+
+
 struct cmn_registers {
        union {
                struct {
@@ -132,6 +145,7 @@ struct cmn_registers {
 static unsigned int hpwdt_nmi_decoding;
 static unsigned int allow_kdump;
 static unsigned int priority;          /* hpwdt at end of die_notify list */
+static unsigned int is_icru;
 static DEFINE_SPINLOCK(rom_lock);
 static void *cru_rom_addr;
 static struct cmn_registers cmn_regs;
@@ -476,19 +490,22 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
                goto out;
 
        spin_lock_irqsave(&rom_lock, rom_pl);
-       if (!die_nmi_called)
+       if (!die_nmi_called && !is_icru)
                asminline_call(&cmn_regs, cru_rom_addr);
        die_nmi_called = 1;
        spin_unlock_irqrestore(&rom_lock, rom_pl);
-       if (cmn_regs.u1.ral == 0) {
-               printk(KERN_WARNING "hpwdt: An NMI occurred, "
-                       "but unable to determine source.\n");
-       } else {
-               if (allow_kdump)
-                       hpwdt_stop();
-               panic("An NMI occurred, please see the Integrated "
-                       "Management Log for details.\n");
+       if (!is_icru) {
+               if (cmn_regs.u1.ral == 0) {
+                       printk(KERN_WARNING "hpwdt: An NMI occurred, "
+                               "but unable to determine source.\n");
+               }
        }
+
+       if (allow_kdump)
+               hpwdt_stop();
+       panic("An NMI occurred, please see the Integrated "
+               "Management Log for details.\n");
+
 out:
        return NOTIFY_OK;
 }
@@ -659,30 +676,63 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev)
 }
 #endif /* CONFIG_X86_LOCAL_APIC */
 
+/*
+ *     dmi_find_icru
+ *
+ *     Routine Description:
+ *     This function checks whether or not we are on an iCRU-based server.
+ *     This check is independent of architecture and needs to be made for
+ *     any ProLiant system.
+ */
+static void __devinit dmi_find_icru(const struct dmi_header *dm, void *dummy)
+{
+       struct smbios_proliant_info *smbios_proliant_ptr;
+
+       if (dm->type == SMBIOS_ICRU_INFORMATION) {
+               smbios_proliant_ptr = (struct smbios_proliant_info *) dm;
+               if (smbios_proliant_ptr->misc_features & 0x01)
+                       is_icru = 1;
+       }
+}
+
 static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev)
 {
        int retval;
 
        /*
-        * We need to map the ROM to get the CRU service.
-        * For 32 bit Operating Systems we need to go through the 32 Bit
-        * BIOS Service Directory
-        * For 64 bit Operating Systems we get that service through SMBIOS.
+        * On typical CRU-based systems we need to map that service in
+        * the BIOS. For 32 bit Operating Systems we need to go through
+        * the 32 Bit BIOS Service Directory. For 64 bit Operating
+        * Systems we get that service through SMBIOS.
+        *
+        * On systems that support the new iCRU service all we need to
+        * do is call dmi_walk to get the supported flag value and skip
+        * the old cru detect code.
         */
-       retval = detect_cru_service();
-       if (retval < 0) {
-               dev_warn(&dev->dev,
-                       "Unable to detect the %d Bit CRU Service.\n",
-                       HPWDT_ARCH);
-               return retval;
-       }
+       dmi_walk(dmi_find_icru, NULL);
+       if (!is_icru) {
+
+               /*
+               * We need to map the ROM to get the CRU service.
+               * For 32 bit Operating Systems we need to go through the 32 Bit
+               * BIOS Service Directory
+               * For 64 bit Operating Systems we get that service through SMBIOS.
+               */
+               retval = detect_cru_service();
+               if (retval < 0) {
+                       dev_warn(&dev->dev,
+                               "Unable to detect the %d Bit CRU Service.\n",
+                               HPWDT_ARCH);
+                       return retval;
+               }
 
-       /*
-        * We know this is the only CRU call we need to make so lets keep as
-        * few instructions as possible once the NMI comes in.
-        */
-       cmn_regs.u1.rah = 0x0D;
-       cmn_regs.u1.ral = 0x02;
+               /*
+               * We know this is the only CRU call we need to make so lets keep as
+               * few instructions as possible once the NMI comes in.
+               */
+               cmn_regs.u1.rah = 0x0D;
+               cmn_regs.u1.ral = 0x02;
+       }
 
        /*
         * If the priority is set to 1, then we will be put first on the
index 5fd020da7c5534f32f7823d966ee49610ac9d31a..751a591684da73fc9a969fbe9717e51e43474cf2 100644 (file)
@@ -120,72 +120,12 @@ enum iTCO_chipsets {
        TCO_3420,       /* 3420 */
        TCO_3450,       /* 3450 */
        TCO_EP80579,    /* EP80579 */
-       TCO_CPT1,       /* Cougar Point */
-       TCO_CPT2,       /* Cougar Point Desktop */
-       TCO_CPT3,       /* Cougar Point Mobile */
-       TCO_CPT4,       /* Cougar Point */
-       TCO_CPT5,       /* Cougar Point */
-       TCO_CPT6,       /* Cougar Point */
-       TCO_CPT7,       /* Cougar Point */
-       TCO_CPT8,       /* Cougar Point */
-       TCO_CPT9,       /* Cougar Point */
-       TCO_CPT10,      /* Cougar Point */
-       TCO_CPT11,      /* Cougar Point */
-       TCO_CPT12,      /* Cougar Point */
-       TCO_CPT13,      /* Cougar Point */
-       TCO_CPT14,      /* Cougar Point */
-       TCO_CPT15,      /* Cougar Point */
-       TCO_CPT16,      /* Cougar Point */
-       TCO_CPT17,      /* Cougar Point */
-       TCO_CPT18,      /* Cougar Point */
-       TCO_CPT19,      /* Cougar Point */
-       TCO_CPT20,      /* Cougar Point */
-       TCO_CPT21,      /* Cougar Point */
-       TCO_CPT22,      /* Cougar Point */
-       TCO_CPT23,      /* Cougar Point */
-       TCO_CPT24,      /* Cougar Point */
-       TCO_CPT25,      /* Cougar Point */
-       TCO_CPT26,      /* Cougar Point */
-       TCO_CPT27,      /* Cougar Point */
-       TCO_CPT28,      /* Cougar Point */
-       TCO_CPT29,      /* Cougar Point */
-       TCO_CPT30,      /* Cougar Point */
-       TCO_CPT31,      /* Cougar Point */
-       TCO_PBG1,       /* Patsburg */
-       TCO_PBG2,       /* Patsburg */
+       TCO_CPT,        /* Cougar Point */
+       TCO_CPTD,       /* Cougar Point Desktop */
+       TCO_CPTM,       /* Cougar Point Mobile */
+       TCO_PBG,        /* Patsburg */
        TCO_DH89XXCC,   /* DH89xxCC */
-       TCO_PPT0,       /* Panther Point */
-       TCO_PPT1,       /* Panther Point */
-       TCO_PPT2,       /* Panther Point */
-       TCO_PPT3,       /* Panther Point */
-       TCO_PPT4,       /* Panther Point */
-       TCO_PPT5,       /* Panther Point */
-       TCO_PPT6,       /* Panther Point */
-       TCO_PPT7,       /* Panther Point */
-       TCO_PPT8,       /* Panther Point */
-       TCO_PPT9,       /* Panther Point */
-       TCO_PPT10,      /* Panther Point */
-       TCO_PPT11,      /* Panther Point */
-       TCO_PPT12,      /* Panther Point */
-       TCO_PPT13,      /* Panther Point */
-       TCO_PPT14,      /* Panther Point */
-       TCO_PPT15,      /* Panther Point */
-       TCO_PPT16,      /* Panther Point */
-       TCO_PPT17,      /* Panther Point */
-       TCO_PPT18,      /* Panther Point */
-       TCO_PPT19,      /* Panther Point */
-       TCO_PPT20,      /* Panther Point */
-       TCO_PPT21,      /* Panther Point */
-       TCO_PPT22,      /* Panther Point */
-       TCO_PPT23,      /* Panther Point */
-       TCO_PPT24,      /* Panther Point */
-       TCO_PPT25,      /* Panther Point */
-       TCO_PPT26,      /* Panther Point */
-       TCO_PPT27,      /* Panther Point */
-       TCO_PPT28,      /* Panther Point */
-       TCO_PPT29,      /* Panther Point */
-       TCO_PPT30,      /* Panther Point */
-       TCO_PPT31,      /* Panther Point */
+       TCO_PPT,        /* Panther Point */
 };
 
 static struct {
@@ -244,83 +184,14 @@ static struct {
        {"3450", 2},
        {"EP80579", 2},
        {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Cougar Point", 2},
-       {"Patsburg", 2},
+       {"Cougar Point Desktop", 2},
+       {"Cougar Point Mobile", 2},
        {"Patsburg", 2},
        {"DH89xxCC", 2},
        {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
-       {"Panther Point", 2},
        {NULL, 0}
 };
 
-#define ITCO_PCI_DEVICE(dev, data) \
-       .vendor = PCI_VENDOR_ID_INTEL,  \
-       .device = dev,                  \
-       .subvendor = PCI_ANY_ID,        \
-       .subdevice = PCI_ANY_ID,        \
-       .class = 0,                     \
-       .class_mask = 0,                \
-       .driver_data = data
-
 /*
  * This data only exists for exporting the supported PCI ids
  * via MODULE_DEVICE_TABLE.  We do not actually register a
@@ -328,138 +199,138 @@ static struct {
  * functions that probably will be registered by other drivers.
  */
 static DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = {
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0,        TCO_ICH)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0,        TCO_ICH0)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0,        TCO_ICH2)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10,       TCO_ICH2M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0,        TCO_ICH3)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12,       TCO_ICH3M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0,        TCO_ICH4)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12,       TCO_ICH4M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0,         TCO_CICH)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0,        TCO_ICH5)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1,            TCO_6300ESB)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0,           TCO_ICH6)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1,           TCO_ICH6M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2,           TCO_ICH6W)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0,           TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2671,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2672,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2673,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2674,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2675,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2676,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2677,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2678,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x2679,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267a,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267b,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267c,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267d,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267e,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(0x267f,                               TCO_631XESB)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0,           TCO_ICH7)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30,          TCO_ICH7DH)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1,           TCO_ICH7M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31,          TCO_ICH7MDH)},
-       { ITCO_PCI_DEVICE(0x27bc,                               TCO_NM10)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0,           TCO_ICH8)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2,           TCO_ICH8DH)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3,           TCO_ICH8DO)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4,           TCO_ICH8M)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1,           TCO_ICH8ME)},
-       { ITCO_PCI_DEVICE(0x2918,                               TCO_ICH9)},
-       { ITCO_PCI_DEVICE(0x2916,                               TCO_ICH9R)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2,           TCO_ICH9DH)},
-       { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4,           TCO_ICH9DO)},
-       { ITCO_PCI_DEVICE(0x2919,                               TCO_ICH9M)},
-       { ITCO_PCI_DEVICE(0x2917,                               TCO_ICH9ME)},
-       { ITCO_PCI_DEVICE(0x3a18,                               TCO_ICH10)},
-       { ITCO_PCI_DEVICE(0x3a16,                               TCO_ICH10R)},
-       { ITCO_PCI_DEVICE(0x3a1a,                               TCO_ICH10D)},
-       { ITCO_PCI_DEVICE(0x3a14,                               TCO_ICH10DO)},
-       { ITCO_PCI_DEVICE(0x3b00,                               TCO_PCH)},
-       { ITCO_PCI_DEVICE(0x3b01,                               TCO_PCHM)},
-       { ITCO_PCI_DEVICE(0x3b02,                               TCO_P55)},
-       { ITCO_PCI_DEVICE(0x3b03,                               TCO_PM55)},
-       { ITCO_PCI_DEVICE(0x3b06,                               TCO_H55)},
-       { ITCO_PCI_DEVICE(0x3b07,                               TCO_QM57)},
-       { ITCO_PCI_DEVICE(0x3b08,                               TCO_H57)},
-       { ITCO_PCI_DEVICE(0x3b09,                               TCO_HM55)},
-       { ITCO_PCI_DEVICE(0x3b0a,                               TCO_Q57)},
-       { ITCO_PCI_DEVICE(0x3b0b,                               TCO_HM57)},
-       { ITCO_PCI_DEVICE(0x3b0d,                               TCO_PCHMSFF)},
-       { ITCO_PCI_DEVICE(0x3b0f,                               TCO_QS57)},
-       { ITCO_PCI_DEVICE(0x3b12,                               TCO_3400)},
-       { ITCO_PCI_DEVICE(0x3b14,                               TCO_3420)},
-       { ITCO_PCI_DEVICE(0x3b16,                               TCO_3450)},
-       { ITCO_PCI_DEVICE(0x5031,                               TCO_EP80579)},
-       { ITCO_PCI_DEVICE(0x1c41,                               TCO_CPT1)},
-       { ITCO_PCI_DEVICE(0x1c42,                               TCO_CPT2)},
-       { ITCO_PCI_DEVICE(0x1c43,                               TCO_CPT3)},
-       { ITCO_PCI_DEVICE(0x1c44,                               TCO_CPT4)},
-       { ITCO_PCI_DEVICE(0x1c45,                               TCO_CPT5)},
-       { ITCO_PCI_DEVICE(0x1c46,                               TCO_CPT6)},
-       { ITCO_PCI_DEVICE(0x1c47,                               TCO_CPT7)},
-       { ITCO_PCI_DEVICE(0x1c48,                               TCO_CPT8)},
-       { ITCO_PCI_DEVICE(0x1c49,                               TCO_CPT9)},
-       { ITCO_PCI_DEVICE(0x1c4a,                               TCO_CPT10)},
-       { ITCO_PCI_DEVICE(0x1c4b,                               TCO_CPT11)},
-       { ITCO_PCI_DEVICE(0x1c4c,                               TCO_CPT12)},
-       { ITCO_PCI_DEVICE(0x1c4d,                               TCO_CPT13)},
-       { ITCO_PCI_DEVICE(0x1c4e,                               TCO_CPT14)},
-       { ITCO_PCI_DEVICE(0x1c4f,                               TCO_CPT15)},
-       { ITCO_PCI_DEVICE(0x1c50,                               TCO_CPT16)},
-       { ITCO_PCI_DEVICE(0x1c51,                               TCO_CPT17)},
-       { ITCO_PCI_DEVICE(0x1c52,                               TCO_CPT18)},
-       { ITCO_PCI_DEVICE(0x1c53,                               TCO_CPT19)},
-       { ITCO_PCI_DEVICE(0x1c54,                               TCO_CPT20)},
-       { ITCO_PCI_DEVICE(0x1c55,                               TCO_CPT21)},
-       { ITCO_PCI_DEVICE(0x1c56,                               TCO_CPT22)},
-       { ITCO_PCI_DEVICE(0x1c57,                               TCO_CPT23)},
-       { ITCO_PCI_DEVICE(0x1c58,                               TCO_CPT24)},
-       { ITCO_PCI_DEVICE(0x1c59,                               TCO_CPT25)},
-       { ITCO_PCI_DEVICE(0x1c5a,                               TCO_CPT26)},
-       { ITCO_PCI_DEVICE(0x1c5b,                               TCO_CPT27)},
-       { ITCO_PCI_DEVICE(0x1c5c,                               TCO_CPT28)},
-       { ITCO_PCI_DEVICE(0x1c5d,                               TCO_CPT29)},
-       { ITCO_PCI_DEVICE(0x1c5e,                               TCO_CPT30)},
-       { ITCO_PCI_DEVICE(0x1c5f,                               TCO_CPT31)},
-       { ITCO_PCI_DEVICE(0x1d40,                               TCO_PBG1)},
-       { ITCO_PCI_DEVICE(0x1d41,                               TCO_PBG2)},
-       { ITCO_PCI_DEVICE(0x2310,                               TCO_DH89XXCC)},
-       { ITCO_PCI_DEVICE(0x1e40,                               TCO_PPT0)},
-       { ITCO_PCI_DEVICE(0x1e41,                               TCO_PPT1)},
-       { ITCO_PCI_DEVICE(0x1e42,                               TCO_PPT2)},
-       { ITCO_PCI_DEVICE(0x1e43,                               TCO_PPT3)},
-       { ITCO_PCI_DEVICE(0x1e44,                               TCO_PPT4)},
-       { ITCO_PCI_DEVICE(0x1e45,                               TCO_PPT5)},
-       { ITCO_PCI_DEVICE(0x1e46,                               TCO_PPT6)},
-       { ITCO_PCI_DEVICE(0x1e47,                               TCO_PPT7)},
-       { ITCO_PCI_DEVICE(0x1e48,                               TCO_PPT8)},
-       { ITCO_PCI_DEVICE(0x1e49,                               TCO_PPT9)},
-       { ITCO_PCI_DEVICE(0x1e4a,                               TCO_PPT10)},
-       { ITCO_PCI_DEVICE(0x1e4b,                               TCO_PPT11)},
-       { ITCO_PCI_DEVICE(0x1e4c,                               TCO_PPT12)},
-       { ITCO_PCI_DEVICE(0x1e4d,                               TCO_PPT13)},
-       { ITCO_PCI_DEVICE(0x1e4e,                               TCO_PPT14)},
-       { ITCO_PCI_DEVICE(0x1e4f,                               TCO_PPT15)},
-       { ITCO_PCI_DEVICE(0x1e50,                               TCO_PPT16)},
-       { ITCO_PCI_DEVICE(0x1e51,                               TCO_PPT17)},
-       { ITCO_PCI_DEVICE(0x1e52,                               TCO_PPT18)},
-       { ITCO_PCI_DEVICE(0x1e53,                               TCO_PPT19)},
-       { ITCO_PCI_DEVICE(0x1e54,                               TCO_PPT20)},
-       { ITCO_PCI_DEVICE(0x1e55,                               TCO_PPT21)},
-       { ITCO_PCI_DEVICE(0x1e56,                               TCO_PPT22)},
-       { ITCO_PCI_DEVICE(0x1e57,                               TCO_PPT23)},
-       { ITCO_PCI_DEVICE(0x1e58,                               TCO_PPT24)},
-       { ITCO_PCI_DEVICE(0x1e59,                               TCO_PPT25)},
-       { ITCO_PCI_DEVICE(0x1e5a,                               TCO_PPT26)},
-       { ITCO_PCI_DEVICE(0x1e5b,                               TCO_PPT27)},
-       { ITCO_PCI_DEVICE(0x1e5c,                               TCO_PPT28)},
-       { ITCO_PCI_DEVICE(0x1e5d,                               TCO_PPT29)},
-       { ITCO_PCI_DEVICE(0x1e5e,                               TCO_PPT30)},
-       { ITCO_PCI_DEVICE(0x1e5f,                               TCO_PPT31)},
+       { PCI_VDEVICE(INTEL, 0x2410), TCO_ICH},
+       { PCI_VDEVICE(INTEL, 0x2420), TCO_ICH0},
+       { PCI_VDEVICE(INTEL, 0x2440), TCO_ICH2},
+       { PCI_VDEVICE(INTEL, 0x244c), TCO_ICH2M},
+       { PCI_VDEVICE(INTEL, 0x2480), TCO_ICH3},
+       { PCI_VDEVICE(INTEL, 0x248c), TCO_ICH3M},
+       { PCI_VDEVICE(INTEL, 0x24c0), TCO_ICH4},
+       { PCI_VDEVICE(INTEL, 0x24cc), TCO_ICH4M},
+       { PCI_VDEVICE(INTEL, 0x2450), TCO_CICH},
+       { PCI_VDEVICE(INTEL, 0x24d0), TCO_ICH5},
+       { PCI_VDEVICE(INTEL, 0x25a1), TCO_6300ESB},
+       { PCI_VDEVICE(INTEL, 0x2640), TCO_ICH6},
+       { PCI_VDEVICE(INTEL, 0x2641), TCO_ICH6M},
+       { PCI_VDEVICE(INTEL, 0x2642), TCO_ICH6W},
+       { PCI_VDEVICE(INTEL, 0x2670), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2671), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2672), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2673), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2674), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2675), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2676), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2677), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2678), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x2679), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267a), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267b), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267c), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267d), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267e), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x267f), TCO_631XESB},
+       { PCI_VDEVICE(INTEL, 0x27b8), TCO_ICH7},
+       { PCI_VDEVICE(INTEL, 0x27b0), TCO_ICH7DH},
+       { PCI_VDEVICE(INTEL, 0x27b9), TCO_ICH7M},
+       { PCI_VDEVICE(INTEL, 0x27bd), TCO_ICH7MDH},
+       { PCI_VDEVICE(INTEL, 0x27bc), TCO_NM10},
+       { PCI_VDEVICE(INTEL, 0x2810), TCO_ICH8},
+       { PCI_VDEVICE(INTEL, 0x2812), TCO_ICH8DH},
+       { PCI_VDEVICE(INTEL, 0x2814), TCO_ICH8DO},
+       { PCI_VDEVICE(INTEL, 0x2815), TCO_ICH8M},
+       { PCI_VDEVICE(INTEL, 0x2811), TCO_ICH8ME},
+       { PCI_VDEVICE(INTEL, 0x2918), TCO_ICH9},
+       { PCI_VDEVICE(INTEL, 0x2916), TCO_ICH9R},
+       { PCI_VDEVICE(INTEL, 0x2912), TCO_ICH9DH},
+       { PCI_VDEVICE(INTEL, 0x2914), TCO_ICH9DO},
+       { PCI_VDEVICE(INTEL, 0x2919), TCO_ICH9M},
+       { PCI_VDEVICE(INTEL, 0x2917), TCO_ICH9ME},
+       { PCI_VDEVICE(INTEL, 0x3a18), TCO_ICH10},
+       { PCI_VDEVICE(INTEL, 0x3a16), TCO_ICH10R},
+       { PCI_VDEVICE(INTEL, 0x3a1a), TCO_ICH10D},
+       { PCI_VDEVICE(INTEL, 0x3a14), TCO_ICH10DO},
+       { PCI_VDEVICE(INTEL, 0x3b00), TCO_PCH},
+       { PCI_VDEVICE(INTEL, 0x3b01), TCO_PCHM},
+       { PCI_VDEVICE(INTEL, 0x3b02), TCO_P55},
+       { PCI_VDEVICE(INTEL, 0x3b03), TCO_PM55},
+       { PCI_VDEVICE(INTEL, 0x3b06), TCO_H55},
+       { PCI_VDEVICE(INTEL, 0x3b07), TCO_QM57},
+       { PCI_VDEVICE(INTEL, 0x3b08), TCO_H57},
+       { PCI_VDEVICE(INTEL, 0x3b09), TCO_HM55},
+       { PCI_VDEVICE(INTEL, 0x3b0a), TCO_Q57},
+       { PCI_VDEVICE(INTEL, 0x3b0b), TCO_HM57},
+       { PCI_VDEVICE(INTEL, 0x3b0d), TCO_PCHMSFF},
+       { PCI_VDEVICE(INTEL, 0x3b0f), TCO_QS57},
+       { PCI_VDEVICE(INTEL, 0x3b12), TCO_3400},
+       { PCI_VDEVICE(INTEL, 0x3b14), TCO_3420},
+       { PCI_VDEVICE(INTEL, 0x3b16), TCO_3450},
+       { PCI_VDEVICE(INTEL, 0x5031), TCO_EP80579},
+       { PCI_VDEVICE(INTEL, 0x1c41), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c42), TCO_CPTD},
+       { PCI_VDEVICE(INTEL, 0x1c43), TCO_CPTM},
+       { PCI_VDEVICE(INTEL, 0x1c44), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c45), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c46), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c47), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c48), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c49), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4a), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4b), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4c), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4d), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4e), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c4f), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c50), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c51), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c52), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c53), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c54), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c55), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c56), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c57), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c58), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c59), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5a), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5b), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5c), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5d), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5e), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1c5f), TCO_CPT},
+       { PCI_VDEVICE(INTEL, 0x1d40), TCO_PBG},
+       { PCI_VDEVICE(INTEL, 0x1d41), TCO_PBG},
+       { PCI_VDEVICE(INTEL, 0x2310), TCO_DH89XXCC},
+       { PCI_VDEVICE(INTEL, 0x1e40), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e41), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e42), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e43), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e44), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e45), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e46), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e47), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e48), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e49), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4a), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4b), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4c), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4d), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4e), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e4f), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e50), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e51), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e52), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e53), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e54), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e55), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e56), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e57), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e58), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e59), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5a), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5b), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5c), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5d), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5e), TCO_PPT},
+       { PCI_VDEVICE(INTEL, 0x1e5f), TCO_PPT},
        { 0, },                 /* End of list */
 };
 MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
@@ -1052,15 +923,10 @@ static void iTCO_wdt_shutdown(struct platform_device *dev)
        iTCO_wdt_stop();
 }
 
-#define iTCO_wdt_suspend NULL
-#define iTCO_wdt_resume  NULL
-
 static struct platform_driver iTCO_wdt_driver = {
        .probe          = iTCO_wdt_probe,
        .remove         = __devexit_p(iTCO_wdt_remove),
        .shutdown       = iTCO_wdt_shutdown,
-       .suspend        = iTCO_wdt_suspend,
-       .resume         = iTCO_wdt_resume,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = DRV_NAME,
index 86f7cac1026c9c0de69ef0180398e71ecfcbe660..b8ef2c6dca7ca900fdf6ae752b59ca1e49c1ad6a 100644 (file)
@@ -329,12 +329,18 @@ static void imx2_wdt_shutdown(struct platform_device *pdev)
        }
 }
 
+static const struct of_device_id imx2_wdt_dt_ids[] = {
+       { .compatible = "fsl,imx21-wdt", },
+       { /* sentinel */ }
+};
+
 static struct platform_driver imx2_wdt_driver = {
        .remove         = __exit_p(imx2_wdt_remove),
        .shutdown       = imx2_wdt_shutdown,
        .driver         = {
                .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = imx2_wdt_dt_ids,
        },
 };
 
index 6143f52ba6b8d4f019794cb04896e8dc20de4e18..8d2d8502d3e8106c9d4c819b46cfe61715011b5b 100644 (file)
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/fs.h>
-#include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/ioport.h>
 
 #define NAME "it8712f_wdt"
 
@@ -51,7 +51,6 @@ MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
 static unsigned long wdt_open;
 static unsigned expect_close;
-static spinlock_t io_lock;
 static unsigned char revision;
 
 /* Dog Food address - We use the game port address */
@@ -121,20 +120,26 @@ static inline void superio_select(int ldn)
        outb(ldn, VAL);
 }
 
-static inline void superio_enter(void)
+static inline int superio_enter(void)
 {
-       spin_lock(&io_lock);
+       /*
+        * Try to reserve REG and REG + 1 for exclusive access.
+        */
+       if (!request_muxed_region(REG, 2, NAME))
+               return -EBUSY;
+
        outb(0x87, REG);
        outb(0x01, REG);
        outb(0x55, REG);
        outb(0x55, REG);
+       return 0;
 }
 
 static inline void superio_exit(void)
 {
        outb(0x02, REG);
        outb(0x02, VAL);
-       spin_unlock(&io_lock);
+       release_region(REG, 2);
 }
 
 static inline void it8712f_wdt_ping(void)
@@ -173,10 +178,13 @@ static int it8712f_wdt_get_status(void)
                return 0;
 }
 
-static void it8712f_wdt_enable(void)
+static int it8712f_wdt_enable(void)
 {
+       int ret = superio_enter();
+       if (ret)
+               return ret;
+
        printk(KERN_DEBUG NAME ": enabling watchdog timer\n");
-       superio_enter();
        superio_select(LDN_GPIO);
 
        superio_outb(wdt_control_reg, WDT_CONTROL);
@@ -186,13 +194,17 @@ static void it8712f_wdt_enable(void)
        superio_exit();
 
        it8712f_wdt_ping();
+
+       return 0;
 }
 
-static void it8712f_wdt_disable(void)
+static int it8712f_wdt_disable(void)
 {
-       printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+       int ret = superio_enter();
+       if (ret)
+               return ret;
 
-       superio_enter();
+       printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
        superio_select(LDN_GPIO);
 
        superio_outb(0, WDT_CONFIG);
@@ -202,6 +214,7 @@ static void it8712f_wdt_disable(void)
        superio_outb(0, WDT_TIMEOUT);
 
        superio_exit();
+       return 0;
 }
 
 static int it8712f_wdt_notify(struct notifier_block *this,
@@ -252,6 +265,7 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
                                                WDIOF_MAGICCLOSE,
        };
        int value;
+       int ret;
 
        switch (cmd) {
        case WDIOC_GETSUPPORT:
@@ -259,7 +273,9 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
                        return -EFAULT;
                return 0;
        case WDIOC_GETSTATUS:
-               superio_enter();
+               ret = superio_enter();
+               if (ret)
+                       return ret;
                superio_select(LDN_GPIO);
 
                value = it8712f_wdt_get_status();
@@ -280,7 +296,9 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
                if (value > (max_units * 60))
                        return -EINVAL;
                margin = value;
-               superio_enter();
+               ret = superio_enter();
+               if (ret)
+                       return ret;
                superio_select(LDN_GPIO);
 
                it8712f_wdt_update_margin();
@@ -299,10 +317,14 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
 
 static int it8712f_wdt_open(struct inode *inode, struct file *file)
 {
+       int ret;
        /* only allow one at a time */
        if (test_and_set_bit(0, &wdt_open))
                return -EBUSY;
-       it8712f_wdt_enable();
+
+       ret = it8712f_wdt_enable();
+       if (ret)
+               return ret;
        return nonseekable_open(inode, file);
 }
 
@@ -313,7 +335,8 @@ static int it8712f_wdt_release(struct inode *inode, struct file *file)
                        ": watchdog device closed unexpectedly, will not"
                        " disable the watchdog timer\n");
        } else if (!nowayout) {
-               it8712f_wdt_disable();
+               if (it8712f_wdt_disable())
+                       printk(KERN_WARNING NAME "Watchdog disable failed\n");
        }
        expect_close = 0;
        clear_bit(0, &wdt_open);
@@ -340,8 +363,10 @@ static int __init it8712f_wdt_find(unsigned short *address)
 {
        int err = -ENODEV;
        int chip_type;
+       int ret = superio_enter();
+       if (ret)
+               return ret;
 
-       superio_enter();
        chip_type = superio_inw(DEVID);
        if (chip_type != IT8712F_DEVID)
                goto exit;
@@ -382,8 +407,6 @@ static int __init it8712f_wdt_init(void)
 {
        int err = 0;
 
-       spin_lock_init(&io_lock);
-
        if (it8712f_wdt_find(&address))
                return -ENODEV;
 
@@ -392,7 +415,11 @@ static int __init it8712f_wdt_init(void)
                return -EBUSY;
        }
 
-       it8712f_wdt_disable();
+       err = it8712f_wdt_disable();
+       if (err) {
+               printk(KERN_ERR NAME ": unable to disable watchdog timer.\n");
+               goto out;
+       }
 
        err = register_reboot_notifier(&it8712f_wdt_notifier);
        if (err) {
index b1bc72f9a20940f1be3d341f29b5fc9567fcede6..a2d9a1266a23b30e645e4e682bfbabb0b86e2d50 100644 (file)
 
 static unsigned int base, gpact, ciract, max_units, chip_type;
 static unsigned long wdt_status;
-static DEFINE_SPINLOCK(spinlock);
 
 static int nogameport = DEFAULT_NOGAMEPORT;
 static int exclusive  = DEFAULT_EXCLUSIVE;
@@ -163,18 +162,26 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
 
 /* Superio Chip */
 
-static inline void superio_enter(void)
+static inline int superio_enter(void)
 {
+       /*
+        * Try to reserve REG and REG + 1 for exclusive access.
+        */
+       if (!request_muxed_region(REG, 2, WATCHDOG_NAME))
+               return -EBUSY;
+
        outb(0x87, REG);
        outb(0x01, REG);
        outb(0x55, REG);
        outb(0x55, REG);
+       return 0;
 }
 
 static inline void superio_exit(void)
 {
        outb(0x02, REG);
        outb(0x02, VAL);
+       release_region(REG, 2);
 }
 
 static inline void superio_select(int ldn)
@@ -255,12 +262,11 @@ static void wdt_keepalive(void)
        set_bit(WDTS_KEEPALIVE, &wdt_status);
 }
 
-static void wdt_start(void)
+static int wdt_start(void)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&spinlock, flags);
-       superio_enter();
+       int ret = superio_enter();
+       if (ret)
+               return ret;
 
        superio_select(GPIO);
        if (test_bit(WDTS_USE_GP, &wdt_status))
@@ -270,15 +276,15 @@ static void wdt_start(void)
        wdt_update_timeout();
 
        superio_exit();
-       spin_unlock_irqrestore(&spinlock, flags);
+
+       return 0;
 }
 
-static void wdt_stop(void)
+static int wdt_stop(void)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&spinlock, flags);
-       superio_enter();
+       int ret = superio_enter();
+       if (ret)
+               return ret;
 
        superio_select(GPIO);
        superio_outb(0x00, WDTCTRL);
@@ -288,7 +294,7 @@ static void wdt_stop(void)
                superio_outb(0x00, WDTVALMSB);
 
        superio_exit();
-       spin_unlock_irqrestore(&spinlock, flags);
+       return 0;
 }
 
 /**
@@ -303,8 +309,6 @@ static void wdt_stop(void)
 
 static int wdt_set_timeout(int t)
 {
-       unsigned long flags;
-
        if (t < 1 || t > max_units * 60)
                return -EINVAL;
 
@@ -313,14 +317,15 @@ static int wdt_set_timeout(int t)
        else
                timeout = t;
 
-       spin_lock_irqsave(&spinlock, flags);
        if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
-               superio_enter();
+               int ret = superio_enter();
+               if (ret)
+                       return ret;
+
                superio_select(GPIO);
                wdt_update_timeout();
                superio_exit();
        }
-       spin_unlock_irqrestore(&spinlock, flags);
        return 0;
 }
 
@@ -339,12 +344,12 @@ static int wdt_set_timeout(int t)
 
 static int wdt_get_status(int *status)
 {
-       unsigned long flags;
-
        *status = 0;
        if (testmode) {
-               spin_lock_irqsave(&spinlock, flags);
-               superio_enter();
+               int ret = superio_enter();
+               if (ret)
+                       return ret;
+
                superio_select(GPIO);
                if (superio_inb(WDTCTRL) & WDT_ZERO) {
                        superio_outb(0x00, WDTCTRL);
@@ -353,7 +358,6 @@ static int wdt_get_status(int *status)
                }
 
                superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
        }
        if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status))
                *status |= WDIOF_KEEPALIVEPING;
@@ -379,9 +383,17 @@ static int wdt_open(struct inode *inode, struct file *file)
        if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status))
                return -EBUSY;
        if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
+               int ret;
                if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status))
                        __module_get(THIS_MODULE);
-               wdt_start();
+
+               ret = wdt_start();
+               if (ret) {
+                       clear_bit(WDTS_LOCKED, &wdt_status);
+                       clear_bit(WDTS_TIMER_RUN, &wdt_status);
+                       clear_bit(WDTS_DEV_OPEN, &wdt_status);
+                       return ret;
+               }
        }
        return nonseekable_open(inode, file);
 }
@@ -403,7 +415,16 @@ static int wdt_release(struct inode *inode, struct file *file)
 {
        if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
                if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) {
-                       wdt_stop();
+                       int ret = wdt_stop();
+                       if (ret) {
+                               /*
+                                * Stop failed. Just keep the watchdog alive
+                                * and hope nothing bad happens.
+                                */
+                               set_bit(WDTS_EXPECTED, &wdt_status);
+                               wdt_keepalive();
+                               return ret;
+                       }
                        clear_bit(WDTS_TIMER_RUN, &wdt_status);
                } else {
                        wdt_keepalive();
@@ -484,7 +505,9 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                    &ident, sizeof(ident)) ? -EFAULT : 0;
 
        case WDIOC_GETSTATUS:
-               wdt_get_status(&status);
+               rc = wdt_get_status(&status);
+               if (rc)
+                       return rc;
                return put_user(status, uarg.i);
 
        case WDIOC_GETBOOTSTATUS:
@@ -500,14 +523,22 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
                switch (new_options) {
                case WDIOS_DISABLECARD:
-                       if (test_bit(WDTS_TIMER_RUN, &wdt_status))
-                               wdt_stop();
+                       if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+                               rc = wdt_stop();
+                               if (rc)
+                                       return rc;
+                       }
                        clear_bit(WDTS_TIMER_RUN, &wdt_status);
                        return 0;
 
                case WDIOS_ENABLECARD:
-                       if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status))
-                               wdt_start();
+                       if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
+                               rc = wdt_start();
+                               if (rc) {
+                                       clear_bit(WDTS_TIMER_RUN, &wdt_status);
+                                       return rc;
+                               }
+                       }
                        return 0;
 
                default:
@@ -560,16 +591,17 @@ static int __init it87_wdt_init(void)
        int rc = 0;
        int try_gameport = !nogameport;
        u8  chip_rev;
-       unsigned long flags;
+       int gp_rreq_fail = 0;
 
        wdt_status = 0;
 
-       spin_lock_irqsave(&spinlock, flags);
-       superio_enter();
+       rc = superio_enter();
+       if (rc)
+               return rc;
+
        chip_type = superio_inw(CHIPID);
        chip_rev  = superio_inb(CHIPREV) & 0x0f;
        superio_exit();
-       spin_unlock_irqrestore(&spinlock, flags);
 
        switch (chip_type) {
        case IT8702_ID:
@@ -603,8 +635,9 @@ static int __init it87_wdt_init(void)
                return -ENODEV;
        }
 
-       spin_lock_irqsave(&spinlock, flags);
-       superio_enter();
+       rc = superio_enter();
+       if (rc)
+               return rc;
 
        superio_select(GPIO);
        superio_outb(WDT_TOV1, WDTCFG);
@@ -620,21 +653,16 @@ static int __init it87_wdt_init(void)
                }
                gpact = superio_inb(ACTREG);
                superio_outb(0x01, ACTREG);
-               superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
                if (request_region(base, 1, WATCHDOG_NAME))
                        set_bit(WDTS_USE_GP, &wdt_status);
                else
-                       rc = -EIO;
-       } else {
-               superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
+                       gp_rreq_fail = 1;
        }
 
        /* If we haven't Gameport support, try to get CIR support */
        if (!test_bit(WDTS_USE_GP, &wdt_status)) {
                if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
-                       if (rc == -EIO)
+                       if (gp_rreq_fail)
                                printk(KERN_ERR PFX
                                        "I/O Address 0x%04x and 0x%04x"
                                        " already in use\n", base, CIR_BASE);
@@ -646,21 +674,16 @@ static int __init it87_wdt_init(void)
                        goto err_out;
                }
                base = CIR_BASE;
-               spin_lock_irqsave(&spinlock, flags);
-               superio_enter();
 
                superio_select(CIR);
                superio_outw(base, BASEREG);
                superio_outb(0x00, CIR_ILS);
                ciract = superio_inb(ACTREG);
                superio_outb(0x01, ACTREG);
-               if (rc == -EIO) {
+               if (gp_rreq_fail) {
                        superio_select(GAMEPORT);
                        superio_outb(gpact, ACTREG);
                }
-
-               superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
        }
 
        if (timeout < 1 || timeout > max_units * 60) {
@@ -704,6 +727,7 @@ static int __init it87_wdt_init(void)
                "nogameport=%d)\n", chip_type, chip_rev, timeout,
                nowayout, testmode, exclusive, nogameport);
 
+       superio_exit();
        return 0;
 
 err_out_reboot:
@@ -711,49 +735,37 @@ err_out_reboot:
 err_out_region:
        release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
        if (!test_bit(WDTS_USE_GP, &wdt_status)) {
-               spin_lock_irqsave(&spinlock, flags);
-               superio_enter();
                superio_select(CIR);
                superio_outb(ciract, ACTREG);
-               superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
        }
 err_out:
        if (try_gameport) {
-               spin_lock_irqsave(&spinlock, flags);
-               superio_enter();
                superio_select(GAMEPORT);
                superio_outb(gpact, ACTREG);
-               superio_exit();
-               spin_unlock_irqrestore(&spinlock, flags);
        }
 
+       superio_exit();
        return rc;
 }
 
 static void __exit it87_wdt_exit(void)
 {
-       unsigned long flags;
-       int nolock;
-
-       nolock = !spin_trylock_irqsave(&spinlock, flags);
-       superio_enter();
-       superio_select(GPIO);
-       superio_outb(0x00, WDTCTRL);
-       superio_outb(0x00, WDTCFG);
-       superio_outb(0x00, WDTVALLSB);
-       if (max_units > 255)
-               superio_outb(0x00, WDTVALMSB);
-       if (test_bit(WDTS_USE_GP, &wdt_status)) {
-               superio_select(GAMEPORT);
-               superio_outb(gpact, ACTREG);
-       } else {
-               superio_select(CIR);
-               superio_outb(ciract, ACTREG);
+       if (superio_enter() == 0) {
+               superio_select(GPIO);
+               superio_outb(0x00, WDTCTRL);
+               superio_outb(0x00, WDTCFG);
+               superio_outb(0x00, WDTVALLSB);
+               if (max_units > 255)
+                       superio_outb(0x00, WDTVALMSB);
+               if (test_bit(WDTS_USE_GP, &wdt_status)) {
+                       superio_select(GAMEPORT);
+                       superio_outb(gpact, ACTREG);
+               } else {
+                       superio_select(CIR);
+                       superio_outb(ciract, ACTREG);
+               }
+               superio_exit();
        }
-       superio_exit();
-       if (!nolock)
-               spin_unlock_irqrestore(&spinlock, flags);
 
        misc_deregister(&wdt_miscdev);
        unregister_reboot_notifier(&wdt_notifier);
index 2b4af222b5f260647de91b8bba56cd68b4ba8659..4dc31024d26c409e4b1593ee30ba78f2f50812a6 100644 (file)
@@ -407,12 +407,35 @@ static int __devexit mpcore_wdt_remove(struct platform_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int mpcore_wdt_suspend(struct platform_device *dev, pm_message_t msg)
+{
+       struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+       mpcore_wdt_stop(wdt);           /* Turn the WDT off */
+       return 0;
+}
+
+static int mpcore_wdt_resume(struct platform_device *dev)
+{
+       struct mpcore_wdt *wdt = platform_get_drvdata(dev);
+       /* re-activate timer */
+       if (test_bit(0, &wdt->timer_alive))
+               mpcore_wdt_start(wdt);
+       return 0;
+}
+#else
+#define mpcore_wdt_suspend     NULL
+#define mpcore_wdt_resume      NULL
+#endif
+
 /* work with hotplug and coldplug */
 MODULE_ALIAS("platform:mpcore_wdt");
 
 static struct platform_driver mpcore_wdt_driver = {
        .probe          = mpcore_wdt_probe,
        .remove         = __devexit_p(mpcore_wdt_remove),
+       .suspend        = mpcore_wdt_suspend,
+       .resume         = mpcore_wdt_resume,
        .shutdown       = mpcore_wdt_shutdown,
        .driver         = {
                .owner  = THIS_MODULE,
index 0430e093b1a0e39d8b97d62eebfbb8fa62ac8fb5..ac37bb82392cce7462918d3e36b7ab7e74aeec13 100644 (file)
@@ -225,11 +225,11 @@ static int __devinit mtx1_wdt_probe(struct platform_device *pdev)
 
        ret = misc_register(&mtx1_wdt_misc);
        if (ret < 0) {
-               printk(KERN_ERR " mtx-1_wdt : failed to register\n");
+               dev_err(&pdev->dev, "failed to register\n");
                return ret;
        }
        mtx1_wdt_start();
-       printk(KERN_INFO "MTX-1 Watchdog driver\n");
+       dev_info(&pdev->dev, "MTX-1 Watchdog driver\n");
        return 0;
 }
 
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
new file mode 100644 (file)
index 0000000..4ec741a
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+*   of_xilinx_wdt.c  1.01  A Watchdog Device Driver for Xilinx xps_timebase_wdt
+*
+*   (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
+*
+*       -----------------------
+*
+*   This program is free software; you can redistribute it and/or
+*   modify it under the terms of the GNU General Public License
+*   as published by the Free Software Foundation; either version
+*   2 of the License, or (at your option) any later version.
+*
+*       -----------------------
+*      30-May-2011 Alejandro Cabrera <aldaya@gmail.com>
+*              - If "xlnx,wdt-enable-once" wasn't found on device tree the
+*                module will use CONFIG_WATCHDOG_NOWAYOUT
+*              - If the device tree parameters ("clock-frequency" and
+*                "xlnx,wdt-interval") wasn't found the driver won't
+*                know the wdt reset interval
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+/* Register offsets for the Wdt device */
+#define XWT_TWCSR0_OFFSET   0x0 /* Control/Status Register0 */
+#define XWT_TWCSR1_OFFSET   0x4 /* Control/Status Register1 */
+#define XWT_TBR_OFFSET      0x8 /* Timebase Register Offset */
+
+/* Control/Status Register Masks  */
+#define XWT_CSR0_WRS_MASK   0x00000008 /* Reset status */
+#define XWT_CSR0_WDS_MASK   0x00000004 /* Timer state  */
+#define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */
+
+/* Control/Status Register 0/1 bits  */
+#define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */
+
+/* SelfTest constants */
+#define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000
+#define XWT_TIMER_FAILED            0xFFFFFFFF
+
+#define WATCHDOG_NAME     "Xilinx Watchdog"
+#define PFX WATCHDOG_NAME ": "
+
+struct xwdt_device {
+       struct resource  res;
+       void __iomem *base;
+       u32 nowayout;
+       u32 wdt_interval;
+       u32 boot_status;
+};
+
+static struct xwdt_device xdev;
+
+static  u32 timeout;
+static  u32 control_status_reg;
+static  u8  expect_close;
+static  u8  no_timeout;
+static unsigned long driver_open;
+
+static  DEFINE_SPINLOCK(spinlock);
+
+static void xwdt_start(void)
+{
+       spin_lock(&spinlock);
+
+       /* Clean previous status and enable the watchdog timer */
+       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+       control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
+
+       iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK),
+                               xdev.base + XWT_TWCSR0_OFFSET);
+
+       iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET);
+
+       spin_unlock(&spinlock);
+}
+
+static void xwdt_stop(void)
+{
+       spin_lock(&spinlock);
+
+       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+
+       iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK),
+                               xdev.base + XWT_TWCSR0_OFFSET);
+
+       iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
+
+       spin_unlock(&spinlock);
+       printk(KERN_INFO PFX "Stopped!\n");
+}
+
+static void xwdt_keepalive(void)
+{
+       spin_lock(&spinlock);
+
+       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+       control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
+       iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET);
+
+       spin_unlock(&spinlock);
+}
+
+static void xwdt_get_status(int *status)
+{
+       int new_status;
+
+       spin_lock(&spinlock);
+
+       control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
+       new_status = ((control_status_reg &
+                       (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK)) != 0);
+       spin_unlock(&spinlock);
+
+       *status = 0;
+       if (new_status & 1)
+               *status |= WDIOF_CARDRESET;
+}
+
+static u32 xwdt_selftest(void)
+{
+       int i;
+       u32 timer_value1;
+       u32 timer_value2;
+
+       spin_lock(&spinlock);
+
+       timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET);
+       timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
+
+       for (i = 0;
+               ((i <= XWT_MAX_SELFTEST_LOOP_COUNT) &&
+                       (timer_value2 == timer_value1)); i++) {
+               timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
+       }
+
+       spin_unlock(&spinlock);
+
+       if (timer_value2 != timer_value1)
+               return ~XWT_TIMER_FAILED;
+       else
+               return XWT_TIMER_FAILED;
+}
+
+static int xwdt_open(struct inode *inode, struct file *file)
+{
+       /* Only one process can handle the wdt at a time */
+       if (test_and_set_bit(0, &driver_open))
+               return -EBUSY;
+
+       /* Make sure that the module are always loaded...*/
+       if (xdev.nowayout)
+               __module_get(THIS_MODULE);
+
+       xwdt_start();
+       printk(KERN_INFO PFX "Started...\n");
+
+       return nonseekable_open(inode, file);
+}
+
+static int xwdt_release(struct inode *inode, struct file *file)
+{
+       if (expect_close == 42) {
+               xwdt_stop();
+       } else {
+               printk(KERN_CRIT PFX
+                       "Unexpected close, not stopping watchdog!\n");
+               xwdt_keepalive();
+       }
+
+       clear_bit(0, &driver_open);
+       expect_close = 0;
+       return 0;
+}
+
+/*
+ *      xwdt_write:
+ *      @file: file handle to the watchdog
+ *      @buf: buffer to write (unused as data does not matter here
+ *      @count: count of bytes
+ *      @ppos: pointer to the position to write. No seeks allowed
+ *
+ *      A write to a watchdog device is defined as a keepalive signal. Any
+ *      write of data will do, as we don't define content meaning.
+ */
+static ssize_t xwdt_write(struct file *file, const char __user *buf,
+                                               size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!xdev.nowayout) {
+                       size_t i;
+
+                       /* In case it was set long ago */
+                       expect_close = 0;
+
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, buf + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       expect_close = 42;
+                       }
+               }
+               xwdt_keepalive();
+       }
+       return len;
+}
+
+static const struct watchdog_info ident = {
+       .options =  WDIOF_MAGICCLOSE |
+                   WDIOF_KEEPALIVEPING,
+       .firmware_version =     1,
+       .identity =     WATCHDOG_NAME,
+};
+
+/*
+ *      xwdt_ioctl:
+ *      @file: file handle to the device
+ *      @cmd: watchdog command
+ *      @arg: argument pointer
+ *
+ *      The watchdog API defines a common set of functions for all watchdogs
+ *      according to their available features.
+ */
+static long xwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int status;
+
+       union {
+               struct watchdog_info __user *ident;
+               int __user *i;
+       } uarg;
+
+       uarg.i = (int __user *)arg;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(uarg.ident, &ident,
+                                       sizeof(ident)) ? -EFAULT : 0;
+
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(xdev.boot_status, uarg.i);
+
+       case WDIOC_GETSTATUS:
+               xwdt_get_status(&status);
+               return put_user(status, uarg.i);
+
+       case WDIOC_KEEPALIVE:
+               xwdt_keepalive();
+               return 0;
+
+       case WDIOC_GETTIMEOUT:
+               if (no_timeout)
+                       return -ENOTTY;
+               else
+                       return put_user(timeout, uarg.i);
+
+       default:
+               return -ENOTTY;
+       }
+}
+
+static const struct file_operations xwdt_fops = {
+       .owner      = THIS_MODULE,
+       .llseek     = no_llseek,
+       .write      = xwdt_write,
+       .open       = xwdt_open,
+       .release    = xwdt_release,
+       .unlocked_ioctl = xwdt_ioctl,
+};
+
+static struct miscdevice xwdt_miscdev = {
+       .minor      = WATCHDOG_MINOR,
+       .name       = "watchdog",
+       .fops       = &xwdt_fops,
+};
+
+static int __devinit xwdt_probe(struct platform_device *pdev)
+{
+       int rc;
+       u32 *tmptr;
+       u32 *pfreq;
+
+       no_timeout = 0;
+
+       pfreq = (u32 *)of_get_property(pdev->dev.of_node->parent,
+                                       "clock-frequency", NULL);
+
+       if (pfreq == NULL) {
+               printk(KERN_WARNING PFX
+                       "The watchdog clock frequency cannot be obtained!\n");
+               no_timeout = 1;
+       }
+
+       rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res);
+       if (rc) {
+               printk(KERN_WARNING PFX "invalid address!\n");
+               return rc;
+       }
+
+       tmptr = (u32 *)of_get_property(pdev->dev.of_node,
+                                       "xlnx,wdt-interval", NULL);
+       if (tmptr == NULL) {
+               printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-interval\""
+                                       " not found in device tree!\n");
+               no_timeout = 1;
+       } else {
+               xdev.wdt_interval = *tmptr;
+       }
+
+       tmptr = (u32 *)of_get_property(pdev->dev.of_node,
+                                       "xlnx,wdt-enable-once", NULL);
+       if (tmptr == NULL) {
+               printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-enable-once\""
+                                       " not found in device tree!\n");
+               xdev.nowayout = WATCHDOG_NOWAYOUT;
+       }
+
+/*
+ *  Twice of the 2^wdt_interval / freq  because the first wdt overflow is
+ *  ignored (interrupt), reset is only generated at second wdt overflow
+ */
+       if (!no_timeout)
+               timeout = 2 * ((1<<xdev.wdt_interval) / *pfreq);
+
+       if (!request_mem_region(xdev.res.start,
+                       xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) {
+               rc = -ENXIO;
+               printk(KERN_ERR PFX "memory request failure!\n");
+               goto err_out;
+       }
+
+       xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1);
+       if (xdev.base == NULL) {
+               rc = -ENOMEM;
+               printk(KERN_ERR PFX "ioremap failure!\n");
+               goto release_mem;
+       }
+
+       rc = xwdt_selftest();
+       if (rc == XWT_TIMER_FAILED) {
+               printk(KERN_ERR PFX "SelfTest routine error!\n");
+               goto unmap_io;
+       }
+
+       xwdt_get_status(&xdev.boot_status);
+
+       rc = misc_register(&xwdt_miscdev);
+       if (rc) {
+               printk(KERN_ERR PFX
+                       "cannot register miscdev on minor=%d (err=%d)\n",
+                                               xwdt_miscdev.minor, rc);
+               goto unmap_io;
+       }
+
+       if (no_timeout)
+               printk(KERN_INFO PFX
+                       "driver loaded (timeout=? sec, nowayout=%d)\n",
+                                                   xdev.nowayout);
+       else
+               printk(KERN_INFO PFX
+                       "driver loaded (timeout=%d sec, nowayout=%d)\n",
+                                       timeout, xdev.nowayout);
+
+       expect_close = 0;
+       clear_bit(0, &driver_open);
+
+       return 0;
+
+unmap_io:
+       iounmap(xdev.base);
+release_mem:
+       release_mem_region(xdev.res.start, resource_size(&xdev.res));
+err_out:
+       return rc;
+}
+
+static int __devexit xwdt_remove(struct platform_device *dev)
+{
+       misc_deregister(&xwdt_miscdev);
+       iounmap(xdev.base);
+       release_mem_region(xdev.res.start, resource_size(&xdev.res));
+
+       return 0;
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinitdata xwdt_of_match[] = {
+       { .compatible = "xlnx,xps-timebase-wdt-1.01.a", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xwdt_of_match);
+
+static struct platform_driver xwdt_driver = {
+       .probe       = xwdt_probe,
+       .remove      = __devexit_p(xwdt_remove),
+       .driver = {
+               .owner = THIS_MODULE,
+               .name  = WATCHDOG_NAME,
+               .of_match_table = xwdt_of_match,
+       },
+};
+
+static int __init xwdt_init(void)
+{
+       return platform_driver_register(&xwdt_driver);
+}
+
+static void __exit xwdt_exit(void)
+{
+       platform_driver_unregister(&xwdt_driver);
+}
+
+module_init(xwdt_init);
+module_exit(xwdt_exit);
+
+MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>");
+MODULE_DESCRIPTION("Xilinx Watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index b7c139051575d45e722ecdd2cff8d89090f10475..e78d8998676885fdf088186063e65883623fcc3f 100644 (file)
@@ -56,6 +56,7 @@
 #define IO_DEFAULT     0x2E            /* Address used on Portwell Boards */
 
 static int io = IO_DEFAULT;
+static int swc_base_addr = -1;
 
 static int timeout = DEFAULT_TIMEOUT;  /* timeout value */
 static unsigned long timer_enabled;    /* is the timer enabled? */
@@ -116,9 +117,8 @@ static inline void pc87413_enable_swc(void)
 
 /* Read SWC I/O base address */
 
-static inline unsigned int pc87413_get_swc_base(void)
+static void pc87413_get_swc_base_addr(void)
 {
-       unsigned int  swc_base_addr = 0;
        unsigned char addr_l, addr_h = 0;
 
        /* Step 3: Read SWC I/O Base Address */
@@ -136,12 +136,11 @@ static inline unsigned int pc87413_get_swc_base(void)
                "Read SWC I/O Base Address: low %d, high %d, res %d\n",
                                                addr_l, addr_h, swc_base_addr);
 #endif
-       return swc_base_addr;
 }
 
 /* Select Bank 3 of SWC */
 
-static inline void pc87413_swc_bank3(unsigned int swc_base_addr)
+static inline void pc87413_swc_bank3(void)
 {
        /* Step 4: Select Bank3 of SWC */
        outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);
@@ -152,8 +151,7 @@ static inline void pc87413_swc_bank3(unsigned int swc_base_addr)
 
 /* Set watchdog timeout to x minutes */
 
-static inline void pc87413_programm_wdto(unsigned int swc_base_addr,
-                                        char pc87413_time)
+static inline void pc87413_programm_wdto(char pc87413_time)
 {
        /* Step 5: Programm WDTO, Twd. */
        outb_p(pc87413_time, swc_base_addr + WDTO);
@@ -164,7 +162,7 @@ static inline void pc87413_programm_wdto(unsigned int swc_base_addr,
 
 /* Enable WDEN */
 
-static inline void pc87413_enable_wden(unsigned int swc_base_addr)
+static inline void pc87413_enable_wden(void)
 {
        /* Step 6: Enable WDEN */
        outb_p(inb(swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);
@@ -174,7 +172,7 @@ static inline void pc87413_enable_wden(unsigned int swc_base_addr)
 }
 
 /* Enable SW_WD_TREN */
-static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr)
+static inline void pc87413_enable_sw_wd_tren(void)
 {
        /* Enable SW_WD_TREN */
        outb_p(inb(swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);
@@ -185,7 +183,7 @@ static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr)
 
 /* Disable SW_WD_TREN */
 
-static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr)
+static inline void pc87413_disable_sw_wd_tren(void)
 {
        /* Disable SW_WD_TREN */
        outb_p(inb(swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);
@@ -196,7 +194,7 @@ static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr)
 
 /* Enable SW_WD_TRG */
 
-static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr)
+static inline void pc87413_enable_sw_wd_trg(void)
 {
        /* Enable SW_WD_TRG */
        outb_p(inb(swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);
@@ -207,7 +205,7 @@ static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr)
 
 /* Disable SW_WD_TRG */
 
-static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr)
+static inline void pc87413_disable_sw_wd_trg(void)
 {
        /* Disable SW_WD_TRG */
        outb_p(inb(swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);
@@ -222,18 +220,13 @@ static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr)
 
 static void pc87413_enable(void)
 {
-       unsigned int swc_base_addr;
-
        spin_lock(&io_lock);
 
-       pc87413_select_wdt_out();
-       pc87413_enable_swc();
-       swc_base_addr = pc87413_get_swc_base();
-       pc87413_swc_bank3(swc_base_addr);
-       pc87413_programm_wdto(swc_base_addr, timeout);
-       pc87413_enable_wden(swc_base_addr);
-       pc87413_enable_sw_wd_tren(swc_base_addr);
-       pc87413_enable_sw_wd_trg(swc_base_addr);
+       pc87413_swc_bank3();
+       pc87413_programm_wdto(timeout);
+       pc87413_enable_wden();
+       pc87413_enable_sw_wd_tren();
+       pc87413_enable_sw_wd_trg();
 
        spin_unlock(&io_lock);
 }
@@ -242,17 +235,12 @@ static void pc87413_enable(void)
 
 static void pc87413_disable(void)
 {
-       unsigned int swc_base_addr;
-
        spin_lock(&io_lock);
 
-       pc87413_select_wdt_out();
-       pc87413_enable_swc();
-       swc_base_addr = pc87413_get_swc_base();
-       pc87413_swc_bank3(swc_base_addr);
-       pc87413_disable_sw_wd_tren(swc_base_addr);
-       pc87413_disable_sw_wd_trg(swc_base_addr);
-       pc87413_programm_wdto(swc_base_addr, 0);
+       pc87413_swc_bank3();
+       pc87413_disable_sw_wd_tren();
+       pc87413_disable_sw_wd_trg();
+       pc87413_programm_wdto(0);
 
        spin_unlock(&io_lock);
 }
@@ -261,20 +249,15 @@ static void pc87413_disable(void)
 
 static void pc87413_refresh(void)
 {
-       unsigned int swc_base_addr;
-
        spin_lock(&io_lock);
 
-       pc87413_select_wdt_out();
-       pc87413_enable_swc();
-       swc_base_addr = pc87413_get_swc_base();
-       pc87413_swc_bank3(swc_base_addr);
-       pc87413_disable_sw_wd_tren(swc_base_addr);
-       pc87413_disable_sw_wd_trg(swc_base_addr);
-       pc87413_programm_wdto(swc_base_addr, timeout);
-       pc87413_enable_wden(swc_base_addr);
-       pc87413_enable_sw_wd_tren(swc_base_addr);
-       pc87413_enable_sw_wd_trg(swc_base_addr);
+       pc87413_swc_bank3();
+       pc87413_disable_sw_wd_tren();
+       pc87413_disable_sw_wd_trg();
+       pc87413_programm_wdto(timeout);
+       pc87413_enable_wden();
+       pc87413_enable_sw_wd_tren();
+       pc87413_enable_sw_wd_trg();
 
        spin_unlock(&io_lock);
 }
@@ -528,7 +511,8 @@ static int __init pc87413_init(void)
        printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n",
                                                        WDT_INDEX_IO_PORT);
 
-       /* request_region(io, 2, "pc87413"); */
+       if (!request_muxed_region(io, 2, MODNAME))
+               return -EBUSY;
 
        ret = register_reboot_notifier(&pc87413_notifier);
        if (ret != 0) {
@@ -541,12 +525,32 @@ static int __init pc87413_init(void)
                printk(KERN_ERR PFX
                        "cannot register miscdev on minor=%d (err=%d)\n",
                        WATCHDOG_MINOR, ret);
-               unregister_reboot_notifier(&pc87413_notifier);
-               return ret;
+               goto reboot_unreg;
        }
        printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
+
+       pc87413_select_wdt_out();
+       pc87413_enable_swc();
+       pc87413_get_swc_base_addr();
+
+       if (!request_region(swc_base_addr, 0x20, MODNAME)) {
+               printk(KERN_ERR PFX
+                       "cannot request SWC region at 0x%x\n", swc_base_addr);
+               ret = -EBUSY;
+               goto misc_unreg;
+       }
+
        pc87413_enable();
+
+       release_region(io, 2);
        return 0;
+
+misc_unreg:
+       misc_deregister(&pc87413_miscdev);
+reboot_unreg:
+       unregister_reboot_notifier(&pc87413_notifier);
+       release_region(io, 2);
+       return ret;
 }
 
 /**
@@ -569,7 +573,7 @@ static void __exit pc87413_exit(void)
 
        misc_deregister(&pc87413_miscdev);
        unregister_reboot_notifier(&pc87413_notifier);
-       /* release_region(io, 2); */
+       release_region(swc_base_addr, 0x20);
 
        printk(KERN_INFO MODNAME " watchdog component driver removed.\n");
 }
index f7f5aa00df609e2a39ad328418ef1840ec3c7157..30da88f47cd350885c58e9704a3c37735ff3323c 100644 (file)
@@ -589,6 +589,15 @@ static int s3c2410wdt_resume(struct platform_device *dev)
 #define s3c2410wdt_resume  NULL
 #endif /* CONFIG_PM */
 
+#ifdef CONFIG_OF
+static const struct of_device_id s3c2410_wdt_match[] = {
+       { .compatible = "samsung,s3c2410-wdt" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
+#else
+#define s3c2410_wdt_match NULL
+#endif
 
 static struct platform_driver s3c2410wdt_driver = {
        .probe          = s3c2410wdt_probe,
@@ -599,6 +608,7 @@ static struct platform_driver s3c2410wdt_driver = {
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "s3c2410-wdt",
+               .of_match_table = s3c2410_wdt_match,
        },
 };
 
index c7cf4b01f58dc8eec3c16ad6e7cb91b2770e2392..029467e34636f6b057e3c93ac5bdf7b524de945c 100644 (file)
@@ -472,15 +472,10 @@ static void sch311x_wdt_shutdown(struct platform_device *dev)
        sch311x_wdt_stop();
 }
 
-#define sch311x_wdt_suspend NULL
-#define sch311x_wdt_resume  NULL
-
 static struct platform_driver sch311x_wdt_driver = {
        .probe          = sch311x_wdt_probe,
        .remove         = __devexit_p(sch311x_wdt_remove),
        .shutdown       = sch311x_wdt_shutdown,
-       .suspend        = sch311x_wdt_suspend,
-       .resume         = sch311x_wdt_resume,
        .driver         = {
                .owner = THIS_MODULE,
                .name = DRV_NAME,
index 0d80e08b6439331e726fa8fe1c9f3c13e2deb0a5..cc2cfbe33b30d441a2ef6449d2babe0b1eb43a3d 100644 (file)
@@ -134,6 +134,8 @@ static void wdt_enable(void)
        writel(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
        writel(LOCK, wdt->base + WDTLOCK);
 
+       /* Flush posted writes. */
+       readl(wdt->base + WDTLOCK);
        spin_unlock(&wdt->lock);
 }
 
@@ -144,9 +146,10 @@ static void wdt_disable(void)
 
        writel(UNLOCK, wdt->base + WDTLOCK);
        writel(0, wdt->base + WDTCONTROL);
-       writel(0, wdt->base + WDTLOAD);
        writel(LOCK, wdt->base + WDTLOCK);
 
+       /* Flush posted writes. */
+       readl(wdt->base + WDTLOCK);
        spin_unlock(&wdt->lock);
 }
 
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
new file mode 100644 (file)
index 0000000..cfa1a15
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *     watchdog_core.c
+ *
+ *     (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>,
+ *                                             All Rights Reserved.
+ *
+ *     (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ *     This source code is part of the generic code that can be used
+ *     by all the watchdog timer drivers.
+ *
+ *     Based on source code of the following authors:
+ *       Matt Domsch <Matt_Domsch@dell.com>,
+ *       Rob Radez <rob@osinvestor.com>,
+ *       Rusty Lynch <rusty@linux.co.intel.com>
+ *       Satyam Sharma <satyam@infradead.org>
+ *       Randy Dunlap <randy.dunlap@oracle.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.
+ *
+ *     Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
+ *     admit liability nor provide warranty for any of this software.
+ *     This material is provided "AS-IS" and at no charge.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>      /* For EXPORT_SYMBOL/module stuff/... */
+#include <linux/types.h>       /* For standard types */
+#include <linux/errno.h>       /* For the -ENODEV/... values */
+#include <linux/kernel.h>      /* For printk/panic/... */
+#include <linux/watchdog.h>    /* For watchdog specific items */
+#include <linux/init.h>                /* For __init/__exit/... */
+
+#include "watchdog_dev.h"      /* For watchdog_dev_register/... */
+
+/**
+ * watchdog_register_device() - register a watchdog device
+ * @wdd: watchdog device
+ *
+ * Register a watchdog device with the kernel so that the
+ * watchdog timer can be accessed from userspace.
+ *
+ * A zero is returned on success and a negative errno code for
+ * failure.
+ */
+int watchdog_register_device(struct watchdog_device *wdd)
+{
+       int ret;
+
+       if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL)
+               return -EINVAL;
+
+       /* Mandatory operations need to be supported */
+       if (wdd->ops->start == NULL || wdd->ops->stop == NULL)
+               return -EINVAL;
+
+       /*
+        * Check that we have valid min and max timeout values, if
+        * not reset them both to 0 (=not used or unknown)
+        */
+       if (wdd->min_timeout > wdd->max_timeout) {
+               pr_info("Invalid min and max timeout values, resetting to 0!\n");
+               wdd->min_timeout = 0;
+               wdd->max_timeout = 0;
+       }
+
+       /*
+        * Note: now that all watchdog_device data has been verified, we
+        * will not check this anymore in other functions. If data gets
+        * corrupted in a later stage then we expect a kernel panic!
+        */
+
+       /* We only support 1 watchdog device via the /dev/watchdog interface */
+       ret = watchdog_dev_register(wdd);
+       if (ret) {
+               pr_err("error registering /dev/watchdog (err=%d).\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(watchdog_register_device);
+
+/**
+ * watchdog_unregister_device() - unregister a watchdog device
+ * @wdd: watchdog device to unregister
+ *
+ * Unregister a watchdog device that was previously successfully
+ * registered with watchdog_register_device().
+ */
+void watchdog_unregister_device(struct watchdog_device *wdd)
+{
+       int ret;
+
+       if (wdd == NULL)
+               return;
+
+       ret = watchdog_dev_unregister(wdd);
+       if (ret)
+               pr_err("error unregistering /dev/watchdog (err=%d).\n", ret);
+}
+EXPORT_SYMBOL_GPL(watchdog_unregister_device);
+
+MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
+MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
+MODULE_DESCRIPTION("WatchDog Timer Driver Core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
new file mode 100644 (file)
index 0000000..d33520d
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ *     watchdog_dev.c
+ *
+ *     (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>,
+ *                                             All Rights Reserved.
+ *
+ *     (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ *
+ *     This source code is part of the generic code that can be used
+ *     by all the watchdog timer drivers.
+ *
+ *     This part of the generic code takes care of the following
+ *     misc device: /dev/watchdog.
+ *
+ *     Based on source code of the following authors:
+ *       Matt Domsch <Matt_Domsch@dell.com>,
+ *       Rob Radez <rob@osinvestor.com>,
+ *       Rusty Lynch <rusty@linux.co.intel.com>
+ *       Satyam Sharma <satyam@infradead.org>
+ *       Randy Dunlap <randy.dunlap@oracle.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.
+ *
+ *     Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
+ *     admit liability nor provide warranty for any of this software.
+ *     This material is provided "AS-IS" and at no charge.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>      /* For module stuff/... */
+#include <linux/types.h>       /* For standard types (like size_t) */
+#include <linux/errno.h>       /* For the -ENODEV/... values */
+#include <linux/kernel.h>      /* For printk/panic/... */
+#include <linux/fs.h>          /* For file operations */
+#include <linux/watchdog.h>    /* For watchdog specific items */
+#include <linux/miscdevice.h>  /* For handling misc devices */
+#include <linux/init.h>                /* For __init/__exit/... */
+#include <linux/uaccess.h>     /* For copy_to_user/put_user/... */
+
+/* make sure we only register one /dev/watchdog device */
+static unsigned long watchdog_dev_busy;
+/* the watchdog device behind /dev/watchdog */
+static struct watchdog_device *wdd;
+
+/*
+ *     watchdog_ping: ping the watchdog.
+ *     @wddev: the watchdog device to ping
+ *
+ *     If the watchdog has no own ping operation then it needs to be
+ *     restarted via the start operation. This wrapper function does
+ *     exactly that.
+ *     We only ping when the watchdog device is running.
+ */
+
+static int watchdog_ping(struct watchdog_device *wddev)
+{
+       if (test_bit(WDOG_ACTIVE, &wdd->status)) {
+               if (wddev->ops->ping)
+                       return wddev->ops->ping(wddev);  /* ping the watchdog */
+               else
+                       return wddev->ops->start(wddev); /* restart watchdog */
+       }
+       return 0;
+}
+
+/*
+ *     watchdog_start: wrapper to start the watchdog.
+ *     @wddev: the watchdog device to start
+ *
+ *     Start the watchdog if it is not active and mark it active.
+ *     This function returns zero on success or a negative errno code for
+ *     failure.
+ */
+
+static int watchdog_start(struct watchdog_device *wddev)
+{
+       int err;
+
+       if (!test_bit(WDOG_ACTIVE, &wdd->status)) {
+               err = wddev->ops->start(wddev);
+               if (err < 0)
+                       return err;
+
+               set_bit(WDOG_ACTIVE, &wdd->status);
+       }
+       return 0;
+}
+
+/*
+ *     watchdog_stop: wrapper to stop the watchdog.
+ *     @wddev: the watchdog device to stop
+ *
+ *     Stop the watchdog if it is still active and unmark it active.
+ *     This function returns zero on success or a negative errno code for
+ *     failure.
+ *     If the 'nowayout' feature was set, the watchdog cannot be stopped.
+ */
+
+static int watchdog_stop(struct watchdog_device *wddev)
+{
+       int err = -EBUSY;
+
+       if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
+               pr_info("%s: nowayout prevents watchdog to be stopped!\n",
+                                                       wdd->info->identity);
+               return err;
+       }
+
+       if (test_bit(WDOG_ACTIVE, &wdd->status)) {
+               err = wddev->ops->stop(wddev);
+               if (err < 0)
+                       return err;
+
+               clear_bit(WDOG_ACTIVE, &wdd->status);
+       }
+       return 0;
+}
+
+/*
+ *     watchdog_write: writes to the watchdog.
+ *     @file: file from VFS
+ *     @data: user address of data
+ *     @len: length of data
+ *     @ppos: pointer to the file offset
+ *
+ *     A write to a watchdog device is defined as a keepalive ping.
+ *     Writing the magic 'V' sequence allows the next close to turn
+ *     off the watchdog (if 'nowayout' is not set).
+ */
+
+static ssize_t watchdog_write(struct file *file, const char __user *data,
+                                               size_t len, loff_t *ppos)
+{
+       size_t i;
+       char c;
+
+       if (len == 0)
+               return 0;
+
+       /*
+        * Note: just in case someone wrote the magic character
+        * five months ago...
+        */
+       clear_bit(WDOG_ALLOW_RELEASE, &wdd->status);
+
+       /* scan to see whether or not we got the magic character */
+       for (i = 0; i != len; i++) {
+               if (get_user(c, data + i))
+                       return -EFAULT;
+               if (c == 'V')
+                       set_bit(WDOG_ALLOW_RELEASE, &wdd->status);
+       }
+
+       /* someone wrote to us, so we send the watchdog a keepalive ping */
+       watchdog_ping(wdd);
+
+       return len;
+}
+
+/*
+ *     watchdog_ioctl: handle the different ioctl's for the watchdog device.
+ *     @file: file handle to the device
+ *     @cmd: watchdog command
+ *     @arg: argument pointer
+ *
+ *     The watchdog API defines a common set of functions for all watchdogs
+ *     according to their available features.
+ */
+
+static long watchdog_ioctl(struct file *file, unsigned int cmd,
+                                                       unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       unsigned int val;
+       int err;
+
+       if (wdd->ops->ioctl) {
+               err = wdd->ops->ioctl(wdd, cmd, arg);
+               if (err != -ENOIOCTLCMD)
+                       return err;
+       }
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(argp, wdd->info,
+                       sizeof(struct watchdog_info)) ? -EFAULT : 0;
+       case WDIOC_GETSTATUS:
+               val = wdd->ops->status ? wdd->ops->status(wdd) : 0;
+               return put_user(val, p);
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(wdd->bootstatus, p);
+       case WDIOC_SETOPTIONS:
+               if (get_user(val, p))
+                       return -EFAULT;
+               if (val & WDIOS_DISABLECARD) {
+                       err = watchdog_stop(wdd);
+                       if (err < 0)
+                               return err;
+               }
+               if (val & WDIOS_ENABLECARD) {
+                       err = watchdog_start(wdd);
+                       if (err < 0)
+                               return err;
+               }
+               return 0;
+       case WDIOC_KEEPALIVE:
+               if (!(wdd->info->options & WDIOF_KEEPALIVEPING))
+                       return -EOPNOTSUPP;
+               watchdog_ping(wdd);
+               return 0;
+       case WDIOC_SETTIMEOUT:
+               if ((wdd->ops->set_timeout == NULL) ||
+                   !(wdd->info->options & WDIOF_SETTIMEOUT))
+                       return -EOPNOTSUPP;
+               if (get_user(val, p))
+                       return -EFAULT;
+               if ((wdd->max_timeout != 0) &&
+                   (val < wdd->min_timeout || val > wdd->max_timeout))
+                               return -EINVAL;
+               err = wdd->ops->set_timeout(wdd, val);
+               if (err < 0)
+                       return err;
+               wdd->timeout = val;
+               /* If the watchdog is active then we send a keepalive ping
+                * to make sure that the watchdog keep's running (and if
+                * possible that it takes the new timeout) */
+               watchdog_ping(wdd);
+               /* Fall */
+       case WDIOC_GETTIMEOUT:
+               /* timeout == 0 means that we don't know the timeout */
+               if (wdd->timeout == 0)
+                       return -EOPNOTSUPP;
+               return put_user(wdd->timeout, p);
+       default:
+               return -ENOTTY;
+       }
+}
+
+/*
+ *     watchdog_open: open the /dev/watchdog device.
+ *     @inode: inode of device
+ *     @file: file handle to device
+ *
+ *     When the /dev/watchdog device gets opened, we start the watchdog.
+ *     Watch out: the /dev/watchdog device is single open, so we make sure
+ *     it can only be opened once.
+ */
+
+static int watchdog_open(struct inode *inode, struct file *file)
+{
+       int err = -EBUSY;
+
+       /* the watchdog is single open! */
+       if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status))
+               return -EBUSY;
+
+       /*
+        * If the /dev/watchdog device is open, we don't want the module
+        * to be unloaded.
+        */
+       if (!try_module_get(wdd->ops->owner))
+               goto out;
+
+       err = watchdog_start(wdd);
+       if (err < 0)
+               goto out_mod;
+
+       /* dev/watchdog is a virtual (and thus non-seekable) filesystem */
+       return nonseekable_open(inode, file);
+
+out_mod:
+       module_put(wdd->ops->owner);
+out:
+       clear_bit(WDOG_DEV_OPEN, &wdd->status);
+       return err;
+}
+
+/*
+ *      watchdog_release: release the /dev/watchdog device.
+ *      @inode: inode of device
+ *      @file: file handle to device
+ *
+ *     This is the code for when /dev/watchdog gets closed. We will only
+ *     stop the watchdog when we have received the magic char (and nowayout
+ *     was not set), else the watchdog will keep running.
+ */
+
+static int watchdog_release(struct inode *inode, struct file *file)
+{
+       int err = -EBUSY;
+
+       /*
+        * We only stop the watchdog if we received the magic character
+        * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
+        * watchdog_stop will fail.
+        */
+       if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
+           !(wdd->info->options & WDIOF_MAGICCLOSE))
+               err = watchdog_stop(wdd);
+
+       /* If the watchdog was not stopped, send a keepalive ping */
+       if (err < 0) {
+               pr_crit("%s: watchdog did not stop!\n", wdd->info->identity);
+               watchdog_ping(wdd);
+       }
+
+       /* Allow the owner module to be unloaded again */
+       module_put(wdd->ops->owner);
+
+       /* make sure that /dev/watchdog can be re-opened */
+       clear_bit(WDOG_DEV_OPEN, &wdd->status);
+
+       return 0;
+}
+
+static const struct file_operations watchdog_fops = {
+       .owner          = THIS_MODULE,
+       .write          = watchdog_write,
+       .unlocked_ioctl = watchdog_ioctl,
+       .open           = watchdog_open,
+       .release        = watchdog_release,
+};
+
+static struct miscdevice watchdog_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &watchdog_fops,
+};
+
+/*
+ *     watchdog_dev_register:
+ *     @watchdog: watchdog device
+ *
+ *     Register a watchdog device as /dev/watchdog. /dev/watchdog
+ *     is actually a miscdevice and thus we set it up like that.
+ */
+
+int watchdog_dev_register(struct watchdog_device *watchdog)
+{
+       int err;
+
+       /* Only one device can register for /dev/watchdog */
+       if (test_and_set_bit(0, &watchdog_dev_busy)) {
+               pr_err("only one watchdog can use /dev/watchdog.\n");
+               return -EBUSY;
+       }
+
+       wdd = watchdog;
+
+       err = misc_register(&watchdog_miscdev);
+       if (err != 0) {
+               pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
+                       watchdog->info->identity, WATCHDOG_MINOR, err);
+               goto out;
+       }
+
+       return 0;
+
+out:
+       wdd = NULL;
+       clear_bit(0, &watchdog_dev_busy);
+       return err;
+}
+
+/*
+ *     watchdog_dev_unregister:
+ *     @watchdog: watchdog device
+ *
+ *     Deregister the /dev/watchdog device.
+ */
+
+int watchdog_dev_unregister(struct watchdog_device *watchdog)
+{
+       /* Check that a watchdog device was registered in the past */
+       if (!test_bit(0, &watchdog_dev_busy) || !wdd)
+               return -ENODEV;
+
+       /* We can only unregister the watchdog device that was registered */
+       if (watchdog != wdd) {
+               pr_err("%s: watchdog was not registered as /dev/watchdog.\n",
+                       watchdog->info->identity);
+               return -ENODEV;
+       }
+
+       misc_deregister(&watchdog_miscdev);
+       wdd = NULL;
+       clear_bit(0, &watchdog_dev_busy);
+       return 0;
+}
diff --git a/drivers/watchdog/watchdog_dev.h b/drivers/watchdog/watchdog_dev.h
new file mode 100644 (file)
index 0000000..bc7612b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *     watchdog_core.h
+ *
+ *     (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>,
+ *                                             All Rights Reserved.
+ *
+ *     (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ *     This source code is part of the generic code that can be used
+ *     by all the watchdog timer drivers.
+ *
+ *     Based on source code of the following authors:
+ *       Matt Domsch <Matt_Domsch@dell.com>,
+ *       Rob Radez <rob@osinvestor.com>,
+ *       Rusty Lynch <rusty@linux.co.intel.com>
+ *       Satyam Sharma <satyam@infradead.org>
+ *       Randy Dunlap <randy.dunlap@oracle.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.
+ *
+ *     Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
+ *     admit liability nor provide warranty for any of this software.
+ *     This material is provided "AS-IS" and at no charge.
+ */
+
+/*
+ *     Functions/procedures to be called by the core
+ */
+int watchdog_dev_register(struct watchdog_device *);
+int watchdog_dev_unregister(struct watchdog_device *);
index fd725cde6ad174bc7048c2e6dd9aa268b061ae6d..4f44b347b24ab2e43a783f20a4c8232561ec120d 100644 (file)
@@ -82,7 +82,7 @@ static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
 static int get_free_entries(unsigned count)
 {
        unsigned long flags;
-       int ref, rc;
+       int ref, rc = 0;
        grant_ref_t head;
 
        spin_lock_irqsave(&gnttab_list_lock, flags);
index 206c4ce030bc98c9b2e5f66caca50ed27c459848..978d2c6f5dca5107172bee65cedbbc8751d1b12f 100644 (file)
@@ -11,7 +11,6 @@
 #include <xen/xenbus.h>
 #include <xen/events.h>
 #include <asm/xen/pci.h>
-#include <linux/workqueue.h>
 #include "pciback.h"
 
 #define        DRV_NAME        "xen-pciback"
index 010937b5a7c91d6df27f2766744981a0571d2585..1b4afd81f872306bb4f5ffd9b860fb5f3c0adc6f 100644 (file)
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
-
+#include <linux/workqueue.h>
 #include <xen/balloon.h>
-
 #include <xen/tmem.h>
+#include <xen/xen.h>
 
 /* Enable/disable with sysfs. */
 static int xen_selfballooning_enabled __read_mostly;
index 52d7eca8c7bfe9d599e60cd0918b36c7f5fefe42..502b9e98867949736b03d5bbf55b14b7d67205e7 100644 (file)
@@ -34,6 +34,9 @@ struct btrfs_inode {
         */
        struct btrfs_key location;
 
+       /* Lock for counters */
+       spinlock_t lock;
+
        /* the extent_tree has caches of all the extent mappings to disk */
        struct extent_map_tree extent_tree;
 
@@ -134,8 +137,8 @@ struct btrfs_inode {
         * items we think we'll end up using, and reserved_extents is the number
         * of extent items we've reserved metadata for.
         */
-       atomic_t outstanding_extents;
-       atomic_t reserved_extents;
+       unsigned outstanding_extents;
+       unsigned reserved_extents;
 
        /*
         * ordered_data_close is set by truncate when a file that used
@@ -184,4 +187,13 @@ static inline void btrfs_i_size_write(struct inode *inode, u64 size)
        BTRFS_I(inode)->disk_i_size = size;
 }
 
+static inline bool btrfs_is_free_space_inode(struct btrfs_root *root,
+                                      struct inode *inode)
+{
+       if (root == root->fs_info->tree_root ||
+           BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID)
+               return true;
+       return false;
+}
+
 #endif
index 2e667868e0d2b8b75649572d10602ac56679a0d0..011cab3aca8d9ffeba2690f642badec7e36471c9 100644 (file)
@@ -54,8 +54,13 @@ noinline void btrfs_set_path_blocking(struct btrfs_path *p)
 {
        int i;
        for (i = 0; i < BTRFS_MAX_LEVEL; i++) {
-               if (p->nodes[i] && p->locks[i])
-                       btrfs_set_lock_blocking(p->nodes[i]);
+               if (!p->nodes[i] || !p->locks[i])
+                       continue;
+               btrfs_set_lock_blocking_rw(p->nodes[i], p->locks[i]);
+               if (p->locks[i] == BTRFS_READ_LOCK)
+                       p->locks[i] = BTRFS_READ_LOCK_BLOCKING;
+               else if (p->locks[i] == BTRFS_WRITE_LOCK)
+                       p->locks[i] = BTRFS_WRITE_LOCK_BLOCKING;
        }
 }
 
@@ -68,7 +73,7 @@ noinline void btrfs_set_path_blocking(struct btrfs_path *p)
  * for held
  */
 noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
-                                       struct extent_buffer *held)
+                                       struct extent_buffer *held, int held_rw)
 {
        int i;
 
@@ -79,19 +84,29 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
         * really sure by forcing the path to blocking before we clear
         * the path blocking.
         */
-       if (held)
-               btrfs_set_lock_blocking(held);
+       if (held) {
+               btrfs_set_lock_blocking_rw(held, held_rw);
+               if (held_rw == BTRFS_WRITE_LOCK)
+                       held_rw = BTRFS_WRITE_LOCK_BLOCKING;
+               else if (held_rw == BTRFS_READ_LOCK)
+                       held_rw = BTRFS_READ_LOCK_BLOCKING;
+       }
        btrfs_set_path_blocking(p);
 #endif
 
        for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) {
-               if (p->nodes[i] && p->locks[i])
-                       btrfs_clear_lock_blocking(p->nodes[i]);
+               if (p->nodes[i] && p->locks[i]) {
+                       btrfs_clear_lock_blocking_rw(p->nodes[i], p->locks[i]);
+                       if (p->locks[i] == BTRFS_WRITE_LOCK_BLOCKING)
+                               p->locks[i] = BTRFS_WRITE_LOCK;
+                       else if (p->locks[i] == BTRFS_READ_LOCK_BLOCKING)
+                               p->locks[i] = BTRFS_READ_LOCK;
+               }
        }
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
        if (held)
-               btrfs_clear_lock_blocking(held);
+               btrfs_clear_lock_blocking_rw(held, held_rw);
 #endif
 }
 
@@ -119,7 +134,7 @@ noinline void btrfs_release_path(struct btrfs_path *p)
                if (!p->nodes[i])
                        continue;
                if (p->locks[i]) {
-                       btrfs_tree_unlock(p->nodes[i]);
+                       btrfs_tree_unlock_rw(p->nodes[i], p->locks[i]);
                        p->locks[i] = 0;
                }
                free_extent_buffer(p->nodes[i]);
@@ -167,6 +182,25 @@ struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root)
        return eb;
 }
 
+/* loop around taking references on and locking the root node of the
+ * tree until you end up with a lock on the root.  A locked buffer
+ * is returned, with a reference held.
+ */
+struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root)
+{
+       struct extent_buffer *eb;
+
+       while (1) {
+               eb = btrfs_root_node(root);
+               btrfs_tree_read_lock(eb);
+               if (eb == root->node)
+                       break;
+               btrfs_tree_read_unlock(eb);
+               free_extent_buffer(eb);
+       }
+       return eb;
+}
+
 /* cowonly root (everything not a reference counted cow subvolume), just get
  * put onto a simple dirty list.  transaction.c walks this to make sure they
  * get properly updated on disk.
@@ -626,14 +660,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
        for (i = start_slot; i < end_slot; i++) {
                int close = 1;
 
-               if (!parent->map_token) {
-                       map_extent_buffer(parent,
-                                       btrfs_node_key_ptr_offset(i),
-                                       sizeof(struct btrfs_key_ptr),
-                                       &parent->map_token, &parent->kaddr,
-                                       &parent->map_start, &parent->map_len,
-                                       KM_USER1);
-               }
                btrfs_node_key(parent, &disk_key, i);
                if (!progress_passed && comp_keys(&disk_key, progress) < 0)
                        continue;
@@ -656,11 +682,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                        last_block = blocknr;
                        continue;
                }
-               if (parent->map_token) {
-                       unmap_extent_buffer(parent, parent->map_token,
-                                           KM_USER1);
-                       parent->map_token = NULL;
-               }
 
                cur = btrfs_find_tree_block(root, blocknr, blocksize);
                if (cur)
@@ -701,11 +722,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
                btrfs_tree_unlock(cur);
                free_extent_buffer(cur);
        }
-       if (parent->map_token) {
-               unmap_extent_buffer(parent, parent->map_token,
-                                   KM_USER1);
-               parent->map_token = NULL;
-       }
        return err;
 }
 
@@ -746,7 +762,6 @@ static noinline int generic_bin_search(struct extent_buffer *eb,
        struct btrfs_disk_key *tmp = NULL;
        struct btrfs_disk_key unaligned;
        unsigned long offset;
-       char *map_token = NULL;
        char *kaddr = NULL;
        unsigned long map_start = 0;
        unsigned long map_len = 0;
@@ -756,18 +771,13 @@ static noinline int generic_bin_search(struct extent_buffer *eb,
                mid = (low + high) / 2;
                offset = p + mid * item_size;
 
-               if (!map_token || offset < map_start ||
+               if (!kaddr || offset < map_start ||
                    (offset + sizeof(struct btrfs_disk_key)) >
                    map_start + map_len) {
-                       if (map_token) {
-                               unmap_extent_buffer(eb, map_token, KM_USER0);
-                               map_token = NULL;
-                       }
 
                        err = map_private_extent_buffer(eb, offset,
                                                sizeof(struct btrfs_disk_key),
-                                               &map_token, &kaddr,
-                                               &map_start, &map_len, KM_USER0);
+                                               &kaddr, &map_start, &map_len);
 
                        if (!err) {
                                tmp = (struct btrfs_disk_key *)(kaddr + offset -
@@ -790,14 +800,10 @@ static noinline int generic_bin_search(struct extent_buffer *eb,
                        high = mid;
                else {
                        *slot = mid;
-                       if (map_token)
-                               unmap_extent_buffer(eb, map_token, KM_USER0);
                        return 0;
                }
        }
        *slot = low;
-       if (map_token)
-               unmap_extent_buffer(eb, map_token, KM_USER0);
        return 1;
 }
 
@@ -890,7 +896,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 
        mid = path->nodes[level];
 
-       WARN_ON(!path->locks[level]);
+       WARN_ON(path->locks[level] != BTRFS_WRITE_LOCK &&
+               path->locks[level] != BTRFS_WRITE_LOCK_BLOCKING);
        WARN_ON(btrfs_header_generation(mid) != trans->transid);
 
        orig_ptr = btrfs_node_blockptr(mid, orig_slot);
@@ -1228,7 +1235,6 @@ static void reada_for_search(struct btrfs_root *root,
        u32 nr;
        u32 blocksize;
        u32 nscan = 0;
-       bool map = true;
 
        if (level != 1)
                return;
@@ -1250,19 +1256,8 @@ static void reada_for_search(struct btrfs_root *root,
 
        nritems = btrfs_header_nritems(node);
        nr = slot;
-       if (node->map_token || path->skip_locking)
-               map = false;
 
        while (1) {
-               if (map && !node->map_token) {
-                       unsigned long offset = btrfs_node_key_ptr_offset(nr);
-                       map_private_extent_buffer(node, offset,
-                                                 sizeof(struct btrfs_key_ptr),
-                                                 &node->map_token,
-                                                 &node->kaddr,
-                                                 &node->map_start,
-                                                 &node->map_len, KM_USER1);
-               }
                if (direction < 0) {
                        if (nr == 0)
                                break;
@@ -1281,11 +1276,6 @@ static void reada_for_search(struct btrfs_root *root,
                if ((search <= target && target - search <= 65536) ||
                    (search > target && search - target <= 65536)) {
                        gen = btrfs_node_ptr_generation(node, nr);
-                       if (map && node->map_token) {
-                               unmap_extent_buffer(node, node->map_token,
-                                                   KM_USER1);
-                               node->map_token = NULL;
-                       }
                        readahead_tree_block(root, search, blocksize, gen);
                        nread += blocksize;
                }
@@ -1293,10 +1283,6 @@ static void reada_for_search(struct btrfs_root *root,
                if ((nread > 65536 || nscan > 32))
                        break;
        }
-       if (map && node->map_token) {
-               unmap_extent_buffer(node, node->map_token, KM_USER1);
-               node->map_token = NULL;
-       }
 }
 
 /*
@@ -1409,7 +1395,7 @@ static noinline void unlock_up(struct btrfs_path *path, int level,
 
                t = path->nodes[i];
                if (i >= lowest_unlock && i > skip_level && path->locks[i]) {
-                       btrfs_tree_unlock(t);
+                       btrfs_tree_unlock_rw(t, path->locks[i]);
                        path->locks[i] = 0;
                }
        }
@@ -1436,7 +1422,7 @@ noinline void btrfs_unlock_up_safe(struct btrfs_path *path, int level)
                        continue;
                if (!path->locks[i])
                        continue;
-               btrfs_tree_unlock(path->nodes[i]);
+               btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);
                path->locks[i] = 0;
        }
 }
@@ -1485,6 +1471,8 @@ read_block_for_search(struct btrfs_trans_handle *trans,
                         * we can trust our generation number
                         */
                        free_extent_buffer(tmp);
+                       btrfs_set_path_blocking(p);
+
                        tmp = read_tree_block(root, blocknr, blocksize, gen);
                        if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
                                *eb_ret = tmp;
@@ -1540,20 +1528,27 @@ read_block_for_search(struct btrfs_trans_handle *trans,
 static int
 setup_nodes_for_search(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root, struct btrfs_path *p,
-                      struct extent_buffer *b, int level, int ins_len)
+                      struct extent_buffer *b, int level, int ins_len,
+                      int *write_lock_level)
 {
        int ret;
        if ((p->search_for_split || ins_len > 0) && btrfs_header_nritems(b) >=
            BTRFS_NODEPTRS_PER_BLOCK(root) - 3) {
                int sret;
 
+               if (*write_lock_level < level + 1) {
+                       *write_lock_level = level + 1;
+                       btrfs_release_path(p);
+                       goto again;
+               }
+
                sret = reada_for_balance(root, p, level);
                if (sret)
                        goto again;
 
                btrfs_set_path_blocking(p);
                sret = split_node(trans, root, p, level);
-               btrfs_clear_path_blocking(p, NULL);
+               btrfs_clear_path_blocking(p, NULL, 0);
 
                BUG_ON(sret > 0);
                if (sret) {
@@ -1565,13 +1560,19 @@ setup_nodes_for_search(struct btrfs_trans_handle *trans,
                   BTRFS_NODEPTRS_PER_BLOCK(root) / 2) {
                int sret;
 
+               if (*write_lock_level < level + 1) {
+                       *write_lock_level = level + 1;
+                       btrfs_release_path(p);
+                       goto again;
+               }
+
                sret = reada_for_balance(root, p, level);
                if (sret)
                        goto again;
 
                btrfs_set_path_blocking(p);
                sret = balance_level(trans, root, p, level);
-               btrfs_clear_path_blocking(p, NULL);
+               btrfs_clear_path_blocking(p, NULL, 0);
 
                if (sret) {
                        ret = sret;
@@ -1615,27 +1616,78 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
        int err;
        int level;
        int lowest_unlock = 1;
+       int root_lock;
+       /* everything at write_lock_level or lower must be write locked */
+       int write_lock_level = 0;
        u8 lowest_level = 0;
 
        lowest_level = p->lowest_level;
        WARN_ON(lowest_level && ins_len > 0);
        WARN_ON(p->nodes[0] != NULL);
 
-       if (ins_len < 0)
+       if (ins_len < 0) {
                lowest_unlock = 2;
 
+               /* when we are removing items, we might have to go up to level
+                * two as we update tree pointers  Make sure we keep write
+                * for those levels as well
+                */
+               write_lock_level = 2;
+       } else if (ins_len > 0) {
+               /*
+                * for inserting items, make sure we have a write lock on
+                * level 1 so we can update keys
+                */
+               write_lock_level = 1;
+       }
+
+       if (!cow)
+               write_lock_level = -1;
+
+       if (cow && (p->keep_locks || p->lowest_level))
+               write_lock_level = BTRFS_MAX_LEVEL;
+
 again:
+       /*
+        * we try very hard to do read locks on the root
+        */
+       root_lock = BTRFS_READ_LOCK;
+       level = 0;
        if (p->search_commit_root) {
+               /*
+                * the commit roots are read only
+                * so we always do read locks
+                */
                b = root->commit_root;
                extent_buffer_get(b);
+               level = btrfs_header_level(b);
                if (!p->skip_locking)
-                       btrfs_tree_lock(b);
+                       btrfs_tree_read_lock(b);
        } else {
-               if (p->skip_locking)
+               if (p->skip_locking) {
                        b = btrfs_root_node(root);
-               else
-                       b = btrfs_lock_root_node(root);
+                       level = btrfs_header_level(b);
+               } else {
+                       /* we don't know the level of the root node
+                        * until we actually have it read locked
+                        */
+                       b = btrfs_read_lock_root_node(root);
+                       level = btrfs_header_level(b);
+                       if (level <= write_lock_level) {
+                               /* whoops, must trade for write lock */
+                               btrfs_tree_read_unlock(b);
+                               free_extent_buffer(b);
+                               b = btrfs_lock_root_node(root);
+                               root_lock = BTRFS_WRITE_LOCK;
+
+                               /* the level might have changed, check again */
+                               level = btrfs_header_level(b);
+                       }
+               }
        }
+       p->nodes[level] = b;
+       if (!p->skip_locking)
+               p->locks[level] = root_lock;
 
        while (b) {
                level = btrfs_header_level(b);
@@ -1644,10 +1696,6 @@ again:
                 * setup the path here so we can release it under lock
                 * contention with the cow code
                 */
-               p->nodes[level] = b;
-               if (!p->skip_locking)
-                       p->locks[level] = 1;
-
                if (cow) {
                        /*
                         * if we don't really need to cow this block
@@ -1659,6 +1707,16 @@ again:
 
                        btrfs_set_path_blocking(p);
 
+                       /*
+                        * must have write locks on this node and the
+                        * parent
+                        */
+                       if (level + 1 > write_lock_level) {
+                               write_lock_level = level + 1;
+                               btrfs_release_path(p);
+                               goto again;
+                       }
+
                        err = btrfs_cow_block(trans, root, b,
                                              p->nodes[level + 1],
                                              p->slots[level + 1], &b);
@@ -1671,10 +1729,7 @@ cow_done:
                BUG_ON(!cow && ins_len);
 
                p->nodes[level] = b;
-               if (!p->skip_locking)
-                       p->locks[level] = 1;
-
-               btrfs_clear_path_blocking(p, NULL);
+               btrfs_clear_path_blocking(p, NULL, 0);
 
                /*
                 * we have a lock on b and as long as we aren't changing
@@ -1700,7 +1755,7 @@ cow_done:
                        }
                        p->slots[level] = slot;
                        err = setup_nodes_for_search(trans, root, p, b, level,
-                                                    ins_len);
+                                            ins_len, &write_lock_level);
                        if (err == -EAGAIN)
                                goto again;
                        if (err) {
@@ -1710,6 +1765,19 @@ cow_done:
                        b = p->nodes[level];
                        slot = p->slots[level];
 
+                       /*
+                        * slot 0 is special, if we change the key
+                        * we have to update the parent pointer
+                        * which means we must have a write lock
+                        * on the parent
+                        */
+                       if (slot == 0 && cow &&
+                           write_lock_level < level + 1) {
+                               write_lock_level = level + 1;
+                               btrfs_release_path(p);
+                               goto again;
+                       }
+
                        unlock_up(p, level, lowest_unlock);
 
                        if (level == lowest_level) {
@@ -1728,23 +1796,42 @@ cow_done:
                        }
 
                        if (!p->skip_locking) {
-                               btrfs_clear_path_blocking(p, NULL);
-                               err = btrfs_try_spin_lock(b);
-
-                               if (!err) {
-                                       btrfs_set_path_blocking(p);
-                                       btrfs_tree_lock(b);
-                                       btrfs_clear_path_blocking(p, b);
+                               level = btrfs_header_level(b);
+                               if (level <= write_lock_level) {
+                                       err = btrfs_try_tree_write_lock(b);
+                                       if (!err) {
+                                               btrfs_set_path_blocking(p);
+                                               btrfs_tree_lock(b);
+                                               btrfs_clear_path_blocking(p, b,
+                                                                 BTRFS_WRITE_LOCK);
+                                       }
+                                       p->locks[level] = BTRFS_WRITE_LOCK;
+                               } else {
+                                       err = btrfs_try_tree_read_lock(b);
+                                       if (!err) {
+                                               btrfs_set_path_blocking(p);
+                                               btrfs_tree_read_lock(b);
+                                               btrfs_clear_path_blocking(p, b,
+                                                                 BTRFS_READ_LOCK);
+                                       }
+                                       p->locks[level] = BTRFS_READ_LOCK;
                                }
+                               p->nodes[level] = b;
                        }
                } else {
                        p->slots[level] = slot;
                        if (ins_len > 0 &&
                            btrfs_leaf_free_space(root, b) < ins_len) {
+                               if (write_lock_level < 1) {
+                                       write_lock_level = 1;
+                                       btrfs_release_path(p);
+                                       goto again;
+                               }
+
                                btrfs_set_path_blocking(p);
                                err = split_leaf(trans, root, key,
                                                 p, ins_len, ret == 0);
-                               btrfs_clear_path_blocking(p, NULL);
+                               btrfs_clear_path_blocking(p, NULL, 0);
 
                                BUG_ON(err > 0);
                                if (err) {
@@ -2025,7 +2112,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
        add_root_to_dirty_list(root);
        extent_buffer_get(c);
        path->nodes[level] = c;
-       path->locks[level] = 1;
+       path->locks[level] = BTRFS_WRITE_LOCK;
        path->slots[level] = 0;
        return 0;
 }
@@ -2253,14 +2340,6 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
                if (path->slots[0] == i)
                        push_space += data_size;
 
-               if (!left->map_token) {
-                       map_extent_buffer(left, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &left->map_token, &left->kaddr,
-                                       &left->map_start, &left->map_len,
-                                       KM_USER1);
-               }
-
                this_item_size = btrfs_item_size(left, item);
                if (this_item_size + sizeof(*item) + push_space > free_space)
                        break;
@@ -2271,10 +2350,6 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
                        break;
                i--;
        }
-       if (left->map_token) {
-               unmap_extent_buffer(left, left->map_token, KM_USER1);
-               left->map_token = NULL;
-       }
 
        if (push_items == 0)
                goto out_unlock;
@@ -2316,21 +2391,10 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
        push_space = BTRFS_LEAF_DATA_SIZE(root);
        for (i = 0; i < right_nritems; i++) {
                item = btrfs_item_nr(right, i);
-               if (!right->map_token) {
-                       map_extent_buffer(right, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &right->map_token, &right->kaddr,
-                                       &right->map_start, &right->map_len,
-                                       KM_USER1);
-               }
                push_space -= btrfs_item_size(right, item);
                btrfs_set_item_offset(right, item, push_space);
        }
 
-       if (right->map_token) {
-               unmap_extent_buffer(right, right->map_token, KM_USER1);
-               right->map_token = NULL;
-       }
        left_nritems -= push_items;
        btrfs_set_header_nritems(left, left_nritems);
 
@@ -2467,13 +2531,6 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
 
        for (i = 0; i < nr; i++) {
                item = btrfs_item_nr(right, i);
-               if (!right->map_token) {
-                       map_extent_buffer(right, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &right->map_token, &right->kaddr,
-                                       &right->map_start, &right->map_len,
-                                       KM_USER1);
-               }
 
                if (!empty && push_items > 0) {
                        if (path->slots[0] < i)
@@ -2496,11 +2553,6 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
                push_space += this_item_size + sizeof(*item);
        }
 
-       if (right->map_token) {
-               unmap_extent_buffer(right, right->map_token, KM_USER1);
-               right->map_token = NULL;
-       }
-
        if (push_items == 0) {
                ret = 1;
                goto out;
@@ -2530,23 +2582,12 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
                u32 ioff;
 
                item = btrfs_item_nr(left, i);
-               if (!left->map_token) {
-                       map_extent_buffer(left, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &left->map_token, &left->kaddr,
-                                       &left->map_start, &left->map_len,
-                                       KM_USER1);
-               }
 
                ioff = btrfs_item_offset(left, item);
                btrfs_set_item_offset(left, item,
                      ioff - (BTRFS_LEAF_DATA_SIZE(root) - old_left_item_size));
        }
        btrfs_set_header_nritems(left, old_left_nritems + push_items);
-       if (left->map_token) {
-               unmap_extent_buffer(left, left->map_token, KM_USER1);
-               left->map_token = NULL;
-       }
 
        /* fixup right node */
        if (push_items > right_nritems) {
@@ -2574,21 +2615,9 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
        for (i = 0; i < right_nritems; i++) {
                item = btrfs_item_nr(right, i);
 
-               if (!right->map_token) {
-                       map_extent_buffer(right, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &right->map_token, &right->kaddr,
-                                       &right->map_start, &right->map_len,
-                                       KM_USER1);
-               }
-
                push_space = push_space - btrfs_item_size(right, item);
                btrfs_set_item_offset(right, item, push_space);
        }
-       if (right->map_token) {
-               unmap_extent_buffer(right, right->map_token, KM_USER1);
-               right->map_token = NULL;
-       }
 
        btrfs_mark_buffer_dirty(left);
        if (right_nritems)
@@ -2729,23 +2758,10 @@ static noinline int copy_for_split(struct btrfs_trans_handle *trans,
                struct btrfs_item *item = btrfs_item_nr(right, i);
                u32 ioff;
 
-               if (!right->map_token) {
-                       map_extent_buffer(right, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &right->map_token, &right->kaddr,
-                                       &right->map_start, &right->map_len,
-                                       KM_USER1);
-               }
-
                ioff = btrfs_item_offset(right, item);
                btrfs_set_item_offset(right, item, ioff + rt_data_off);
        }
 
-       if (right->map_token) {
-               unmap_extent_buffer(right, right->map_token, KM_USER1);
-               right->map_token = NULL;
-       }
-
        btrfs_set_header_nritems(l, mid);
        ret = 0;
        btrfs_item_key(right, &disk_key, 0);
@@ -3264,23 +3280,10 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
                u32 ioff;
                item = btrfs_item_nr(leaf, i);
 
-               if (!leaf->map_token) {
-                       map_extent_buffer(leaf, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &leaf->map_token, &leaf->kaddr,
-                                       &leaf->map_start, &leaf->map_len,
-                                       KM_USER1);
-               }
-
                ioff = btrfs_item_offset(leaf, item);
                btrfs_set_item_offset(leaf, item, ioff + size_diff);
        }
 
-       if (leaf->map_token) {
-               unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
-               leaf->map_token = NULL;
-       }
-
        /* shift the data */
        if (from_end) {
                memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
@@ -3377,22 +3380,10 @@ int btrfs_extend_item(struct btrfs_trans_handle *trans,
                u32 ioff;
                item = btrfs_item_nr(leaf, i);
 
-               if (!leaf->map_token) {
-                       map_extent_buffer(leaf, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &leaf->map_token, &leaf->kaddr,
-                                       &leaf->map_start, &leaf->map_len,
-                                       KM_USER1);
-               }
                ioff = btrfs_item_offset(leaf, item);
                btrfs_set_item_offset(leaf, item, ioff - data_size);
        }
 
-       if (leaf->map_token) {
-               unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
-               leaf->map_token = NULL;
-       }
-
        /* shift the data */
        memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) +
                      data_end - data_size, btrfs_leaf_data(leaf) +
@@ -3494,27 +3485,13 @@ int btrfs_insert_some_items(struct btrfs_trans_handle *trans,
                 * item0..itemN ... dataN.offset..dataN.size .. data0.size
                 */
                /* first correct the data pointers */
-               WARN_ON(leaf->map_token);
                for (i = slot; i < nritems; i++) {
                        u32 ioff;
 
                        item = btrfs_item_nr(leaf, i);
-                       if (!leaf->map_token) {
-                               map_extent_buffer(leaf, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &leaf->map_token, &leaf->kaddr,
-                                       &leaf->map_start, &leaf->map_len,
-                                       KM_USER1);
-                       }
-
                        ioff = btrfs_item_offset(leaf, item);
                        btrfs_set_item_offset(leaf, item, ioff - total_data);
                }
-               if (leaf->map_token) {
-                       unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
-                       leaf->map_token = NULL;
-               }
-
                /* shift the items */
                memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr),
                              btrfs_item_nr_offset(slot),
@@ -3608,27 +3585,13 @@ int setup_items_for_insert(struct btrfs_trans_handle *trans,
                 * item0..itemN ... dataN.offset..dataN.size .. data0.size
                 */
                /* first correct the data pointers */
-               WARN_ON(leaf->map_token);
                for (i = slot; i < nritems; i++) {
                        u32 ioff;
 
                        item = btrfs_item_nr(leaf, i);
-                       if (!leaf->map_token) {
-                               map_extent_buffer(leaf, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &leaf->map_token, &leaf->kaddr,
-                                       &leaf->map_start, &leaf->map_len,
-                                       KM_USER1);
-                       }
-
                        ioff = btrfs_item_offset(leaf, item);
                        btrfs_set_item_offset(leaf, item, ioff - total_data);
                }
-               if (leaf->map_token) {
-                       unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
-                       leaf->map_token = NULL;
-               }
-
                /* shift the items */
                memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr),
                              btrfs_item_nr_offset(slot),
@@ -3840,22 +3803,10 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                        u32 ioff;
 
                        item = btrfs_item_nr(leaf, i);
-                       if (!leaf->map_token) {
-                               map_extent_buffer(leaf, (unsigned long)item,
-                                       sizeof(struct btrfs_item),
-                                       &leaf->map_token, &leaf->kaddr,
-                                       &leaf->map_start, &leaf->map_len,
-                                       KM_USER1);
-                       }
                        ioff = btrfs_item_offset(leaf, item);
                        btrfs_set_item_offset(leaf, item, ioff + dsize);
                }
 
-               if (leaf->map_token) {
-                       unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
-                       leaf->map_token = NULL;
-               }
-
                memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot),
                              btrfs_item_nr_offset(slot + nr),
                              sizeof(struct btrfs_item) *
@@ -4004,11 +3955,11 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
 
        WARN_ON(!path->keep_locks);
 again:
-       cur = btrfs_lock_root_node(root);
+       cur = btrfs_read_lock_root_node(root);
        level = btrfs_header_level(cur);
        WARN_ON(path->nodes[level]);
        path->nodes[level] = cur;
-       path->locks[level] = 1;
+       path->locks[level] = BTRFS_READ_LOCK;
 
        if (btrfs_header_generation(cur) < min_trans) {
                ret = 1;
@@ -4098,12 +4049,12 @@ find_next_key:
                cur = read_node_slot(root, cur, slot);
                BUG_ON(!cur);
 
-               btrfs_tree_lock(cur);
+               btrfs_tree_read_lock(cur);
 
-               path->locks[level - 1] = 1;
+               path->locks[level - 1] = BTRFS_READ_LOCK;
                path->nodes[level - 1] = cur;
                unlock_up(path, level, 1);
-               btrfs_clear_path_blocking(path, NULL);
+               btrfs_clear_path_blocking(path, NULL, 0);
        }
 out:
        if (ret == 0)
@@ -4218,30 +4169,21 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
        u32 nritems;
        int ret;
        int old_spinning = path->leave_spinning;
-       int force_blocking = 0;
+       int next_rw_lock = 0;
 
        nritems = btrfs_header_nritems(path->nodes[0]);
        if (nritems == 0)
                return 1;
 
-       /*
-        * we take the blocks in an order that upsets lockdep.  Using
-        * blocking mode is the only way around it.
-        */
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-       force_blocking = 1;
-#endif
-
        btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
 again:
        level = 1;
        next = NULL;
+       next_rw_lock = 0;
        btrfs_release_path(path);
 
        path->keep_locks = 1;
-
-       if (!force_blocking)
-               path->leave_spinning = 1;
+       path->leave_spinning = 1;
 
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        path->keep_locks = 0;
@@ -4281,11 +4223,12 @@ again:
                }
 
                if (next) {
-                       btrfs_tree_unlock(next);
+                       btrfs_tree_unlock_rw(next, next_rw_lock);
                        free_extent_buffer(next);
                }
 
                next = c;
+               next_rw_lock = path->locks[level];
                ret = read_block_for_search(NULL, root, path, &next, level,
                                            slot, &key);
                if (ret == -EAGAIN)
@@ -4297,15 +4240,14 @@ again:
                }
 
                if (!path->skip_locking) {
-                       ret = btrfs_try_spin_lock(next);
+                       ret = btrfs_try_tree_read_lock(next);
                        if (!ret) {
                                btrfs_set_path_blocking(path);
-                               btrfs_tree_lock(next);
-                               if (!force_blocking)
-                                       btrfs_clear_path_blocking(path, next);
+                               btrfs_tree_read_lock(next);
+                               btrfs_clear_path_blocking(path, next,
+                                                         BTRFS_READ_LOCK);
                        }
-                       if (force_blocking)
-                               btrfs_set_lock_blocking(next);
+                       next_rw_lock = BTRFS_READ_LOCK;
                }
                break;
        }
@@ -4314,14 +4256,13 @@ again:
                level--;
                c = path->nodes[level];
                if (path->locks[level])
-                       btrfs_tree_unlock(c);
+                       btrfs_tree_unlock_rw(c, path->locks[level]);
 
                free_extent_buffer(c);
                path->nodes[level] = next;
                path->slots[level] = 0;
                if (!path->skip_locking)
-                       path->locks[level] = 1;
-
+                       path->locks[level] = next_rw_lock;
                if (!level)
                        break;
 
@@ -4336,16 +4277,14 @@ again:
                }
 
                if (!path->skip_locking) {
-                       btrfs_assert_tree_locked(path->nodes[level]);
-                       ret = btrfs_try_spin_lock(next);
+                       ret = btrfs_try_tree_read_lock(next);
                        if (!ret) {
                                btrfs_set_path_blocking(path);
-                               btrfs_tree_lock(next);
-                               if (!force_blocking)
-                                       btrfs_clear_path_blocking(path, next);
+                               btrfs_tree_read_lock(next);
+                               btrfs_clear_path_blocking(path, next,
+                                                         BTRFS_READ_LOCK);
                        }
-                       if (force_blocking)
-                               btrfs_set_lock_blocking(next);
+                       next_rw_lock = BTRFS_READ_LOCK;
                }
        }
        ret = 0;
index fe9287b064969d503e0e2c44f8c7446a8767ce9b..365c4e1dde04968379b86568dbb129bd6f3f0dbc 100644 (file)
@@ -755,6 +755,8 @@ struct btrfs_space_info {
                                   chunks for this space */
        unsigned int chunk_alloc:1;     /* set if we are allocating a chunk */
 
+       unsigned int flush:1;           /* set if we are trying to make space */
+
        unsigned int force_alloc;       /* set if we need to force a chunk
                                           alloc for this space */
 
@@ -764,7 +766,7 @@ struct btrfs_space_info {
        struct list_head block_groups[BTRFS_NR_RAID_TYPES];
        spinlock_t lock;
        struct rw_semaphore groups_sem;
-       atomic_t caching_threads;
+       wait_queue_head_t wait;
 };
 
 struct btrfs_block_rsv {
@@ -824,6 +826,7 @@ struct btrfs_caching_control {
        struct list_head list;
        struct mutex mutex;
        wait_queue_head_t wait;
+       struct btrfs_work work;
        struct btrfs_block_group_cache *block_group;
        u64 progress;
        atomic_t count;
@@ -1032,6 +1035,8 @@ struct btrfs_fs_info {
        struct btrfs_workers endio_write_workers;
        struct btrfs_workers endio_freespace_worker;
        struct btrfs_workers submit_workers;
+       struct btrfs_workers caching_workers;
+
        /*
         * fixup workers take dirty pages that didn't properly go through
         * the cow mechanism and make them safe to write.  It happens
@@ -2128,7 +2133,7 @@ static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info)
 
 /* extent-tree.c */
 static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
-                                                int num_items)
+                                                unsigned num_items)
 {
        return (root->leafsize + root->nodesize * (BTRFS_MAX_LEVEL - 1)) *
                3 * num_items;
@@ -2222,9 +2227,6 @@ void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde);
 void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
 int btrfs_check_data_free_space(struct inode *inode, u64 bytes);
 void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes);
-int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
-                               struct btrfs_root *root,
-                               int num_items);
 void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root);
 int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
@@ -2330,7 +2332,7 @@ struct btrfs_path *btrfs_alloc_path(void);
 void btrfs_free_path(struct btrfs_path *p);
 void btrfs_set_path_blocking(struct btrfs_path *p);
 void btrfs_clear_path_blocking(struct btrfs_path *p,
-                              struct extent_buffer *held);
+                              struct extent_buffer *held, int held_rw);
 void btrfs_unlock_up_safe(struct btrfs_path *p, int level);
 
 int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
index 98c68e658a9b2eb08a8ba99d0b5691f16fc8a67d..b52c672f4c180beae28f60302071731bd343dcba 100644 (file)
@@ -735,7 +735,7 @@ static int btrfs_batch_insert_items(struct btrfs_trans_handle *trans,
        }
 
        /* reset all the locked nodes in the patch to spinning locks. */
-       btrfs_clear_path_blocking(path, NULL);
+       btrfs_clear_path_blocking(path, NULL, 0);
 
        /* insert the keys of the items */
        ret = setup_items_for_insert(trans, root, path, keys, data_size,
index 685f2593c4f049559a087cec8b88daa04a0d357d..c360a848d97fb6115c58a41bb45aeef611c4c86f 100644 (file)
@@ -89,13 +89,8 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
        data_size = sizeof(*dir_item) + name_len + data_len;
        dir_item = insert_with_overflow(trans, root, path, &key, data_size,
                                        name, name_len);
-       /*
-        * FIXME: at some point we should handle xattr's that are larger than
-        * what we can fit in our leaf.  We set location to NULL b/c we arent
-        * pointing at anything else, that will change if we store the xattr
-        * data in a separate inode.
-        */
-       BUG_ON(IS_ERR(dir_item));
+       if (IS_ERR(dir_item))
+               return PTR_ERR(dir_item);
        memset(&location, 0, sizeof(location));
 
        leaf = path->nodes[0];
index b231ae13b2697ebcd5b88d848a81ddc83e01c990..07b3ac662e193e6b3a19180c3c3c9bfccbeb8028 100644 (file)
@@ -100,38 +100,83 @@ struct async_submit_bio {
        struct btrfs_work work;
 };
 
-/* These are used to set the lockdep class on the extent buffer locks.
- * The class is set by the readpage_end_io_hook after the buffer has
- * passed csum validation but before the pages are unlocked.
+/*
+ * Lockdep class keys for extent_buffer->lock's in this root.  For a given
+ * eb, the lockdep key is determined by the btrfs_root it belongs to and
+ * the level the eb occupies in the tree.
+ *
+ * Different roots are used for different purposes and may nest inside each
+ * other and they require separate keysets.  As lockdep keys should be
+ * static, assign keysets according to the purpose of the root as indicated
+ * by btrfs_root->objectid.  This ensures that all special purpose roots
+ * have separate keysets.
  *
- * The lockdep class is also set by btrfs_init_new_buffer on freshly
- * allocated blocks.
+ * Lock-nesting across peer nodes is always done with the immediate parent
+ * node locked thus preventing deadlock.  As lockdep doesn't know this, use
+ * subclass to avoid triggering lockdep warning in such cases.
  *
- * The class is based on the level in the tree block, which allows lockdep
- * to know that lower nodes nest inside the locks of higher nodes.
+ * The key is set by the readpage_end_io_hook after the buffer has passed
+ * csum validation but before the pages are unlocked.  It is also set by
+ * btrfs_init_new_buffer on freshly allocated blocks.
  *
- * We also add a check to make sure the highest level of the tree is
- * the same as our lockdep setup here.  If BTRFS_MAX_LEVEL changes, this
- * code needs update as well.
+ * We also add a check to make sure the highest level of the tree is the
+ * same as our lockdep setup here.  If BTRFS_MAX_LEVEL changes, this code
+ * needs update as well.
  */
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # if BTRFS_MAX_LEVEL != 8
 #  error
 # endif
-static struct lock_class_key btrfs_eb_class[BTRFS_MAX_LEVEL + 1];
-static const char *btrfs_eb_name[BTRFS_MAX_LEVEL + 1] = {
-       /* leaf */
-       "btrfs-extent-00",
-       "btrfs-extent-01",
-       "btrfs-extent-02",
-       "btrfs-extent-03",
-       "btrfs-extent-04",
-       "btrfs-extent-05",
-       "btrfs-extent-06",
-       "btrfs-extent-07",
-       /* highest possible level */
-       "btrfs-extent-08",
+
+static struct btrfs_lockdep_keyset {
+       u64                     id;             /* root objectid */
+       const char              *name_stem;     /* lock name stem */
+       char                    names[BTRFS_MAX_LEVEL + 1][20];
+       struct lock_class_key   keys[BTRFS_MAX_LEVEL + 1];
+} btrfs_lockdep_keysets[] = {
+       { .id = BTRFS_ROOT_TREE_OBJECTID,       .name_stem = "root"     },
+       { .id = BTRFS_EXTENT_TREE_OBJECTID,     .name_stem = "extent"   },
+       { .id = BTRFS_CHUNK_TREE_OBJECTID,      .name_stem = "chunk"    },
+       { .id = BTRFS_DEV_TREE_OBJECTID,        .name_stem = "dev"      },
+       { .id = BTRFS_FS_TREE_OBJECTID,         .name_stem = "fs"       },
+       { .id = BTRFS_CSUM_TREE_OBJECTID,       .name_stem = "csum"     },
+       { .id = BTRFS_ORPHAN_OBJECTID,          .name_stem = "orphan"   },
+       { .id = BTRFS_TREE_LOG_OBJECTID,        .name_stem = "log"      },
+       { .id = BTRFS_TREE_RELOC_OBJECTID,      .name_stem = "treloc"   },
+       { .id = BTRFS_DATA_RELOC_TREE_OBJECTID, .name_stem = "dreloc"   },
+       { .id = 0,                              .name_stem = "tree"     },
 };
+
+void __init btrfs_init_lockdep(void)
+{
+       int i, j;
+
+       /* initialize lockdep class names */
+       for (i = 0; i < ARRAY_SIZE(btrfs_lockdep_keysets); i++) {
+               struct btrfs_lockdep_keyset *ks = &btrfs_lockdep_keysets[i];
+
+               for (j = 0; j < ARRAY_SIZE(ks->names); j++)
+                       snprintf(ks->names[j], sizeof(ks->names[j]),
+                                "btrfs-%s-%02d", ks->name_stem, j);
+       }
+}
+
+void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb,
+                                   int level)
+{
+       struct btrfs_lockdep_keyset *ks;
+
+       BUG_ON(level >= ARRAY_SIZE(ks->keys));
+
+       /* find the matching keyset, id 0 is the default entry */
+       for (ks = btrfs_lockdep_keysets; ks->id; ks++)
+               if (ks->id == objectid)
+                       break;
+
+       lockdep_set_class_and_name(&eb->lock,
+                                  &ks->keys[level], ks->names[level]);
+}
+
 #endif
 
 /*
@@ -217,7 +262,6 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
        unsigned long len;
        unsigned long cur_len;
        unsigned long offset = BTRFS_CSUM_SIZE;
-       char *map_token = NULL;
        char *kaddr;
        unsigned long map_start;
        unsigned long map_len;
@@ -228,8 +272,7 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
        len = buf->len - offset;
        while (len > 0) {
                err = map_private_extent_buffer(buf, offset, 32,
-                                       &map_token, &kaddr,
-                                       &map_start, &map_len, KM_USER0);
+                                       &kaddr, &map_start, &map_len);
                if (err)
                        return 1;
                cur_len = min(len, map_len - (offset - map_start));
@@ -237,7 +280,6 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
                                      crc, cur_len);
                len -= cur_len;
                offset += cur_len;
-               unmap_extent_buffer(buf, map_token, KM_USER0);
        }
        if (csum_size > sizeof(inline_result)) {
                result = kzalloc(csum_size * sizeof(char), GFP_NOFS);
@@ -494,15 +536,6 @@ static noinline int check_leaf(struct btrfs_root *root,
        return 0;
 }
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level)
-{
-       lockdep_set_class_and_name(&eb->lock,
-                          &btrfs_eb_class[level],
-                          btrfs_eb_name[level]);
-}
-#endif
-
 static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
                               struct extent_state *state)
 {
@@ -553,7 +586,8 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
        }
        found_level = btrfs_header_level(eb);
 
-       btrfs_set_buffer_lockdep_class(eb, found_level);
+       btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb),
+                                      eb, found_level);
 
        ret = csum_tree_block(root, eb, 1);
        if (ret) {
@@ -1598,7 +1632,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
                goto fail_bdi;
        }
 
-       fs_info->btree_inode->i_mapping->flags &= ~__GFP_FS;
+       mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
 
        INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
        INIT_LIST_HEAD(&fs_info->trans_list);
@@ -1802,6 +1836,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
                           fs_info->thread_pool_size),
                           &fs_info->generic_worker);
 
+       btrfs_init_workers(&fs_info->caching_workers, "cache",
+                          2, &fs_info->generic_worker);
+
        /* a higher idle thresh on the submit workers makes it much more
         * likely that bios will be send down in a sane order to the
         * devices
@@ -1855,6 +1892,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        btrfs_start_workers(&fs_info->endio_write_workers, 1);
        btrfs_start_workers(&fs_info->endio_freespace_worker, 1);
        btrfs_start_workers(&fs_info->delayed_workers, 1);
+       btrfs_start_workers(&fs_info->caching_workers, 1);
 
        fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
        fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
@@ -2112,6 +2150,7 @@ fail_sb_buffer:
        btrfs_stop_workers(&fs_info->endio_freespace_worker);
        btrfs_stop_workers(&fs_info->submit_workers);
        btrfs_stop_workers(&fs_info->delayed_workers);
+       btrfs_stop_workers(&fs_info->caching_workers);
 fail_alloc:
        kfree(fs_info->delayed_root);
 fail_iput:
@@ -2577,6 +2616,7 @@ int close_ctree(struct btrfs_root *root)
        btrfs_stop_workers(&fs_info->endio_freespace_worker);
        btrfs_stop_workers(&fs_info->submit_workers);
        btrfs_stop_workers(&fs_info->delayed_workers);
+       btrfs_stop_workers(&fs_info->caching_workers);
 
        btrfs_close_devices(fs_info->fs_devices);
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
index a0b610a67aaeadf1f564d03e218305997c021a85..bec3ea4bd67fd465a8a5e008fcae1e7353f573ad 100644 (file)
@@ -87,10 +87,14 @@ int btree_lock_page_hook(struct page *page);
 
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
-void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level);
+void btrfs_init_lockdep(void);
+void btrfs_set_buffer_lockdep_class(u64 objectid,
+                                   struct extent_buffer *eb, int level);
 #else
-static inline void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb,
-                                                int level)
+static inline void btrfs_init_lockdep(void)
+{ }
+static inline void btrfs_set_buffer_lockdep_class(u64 objectid,
+                                       struct extent_buffer *eb, int level)
 {
 }
 #endif
index 71cd456fdb60360d44edd113ab7c593bdacfa658..4d08ed79405d2c5729fd78d45c75a02f4e556687 100644 (file)
@@ -320,12 +320,12 @@ static u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
        return total_added;
 }
 
-static int caching_kthread(void *data)
+static noinline void caching_thread(struct btrfs_work *work)
 {
-       struct btrfs_block_group_cache *block_group = data;
-       struct btrfs_fs_info *fs_info = block_group->fs_info;
-       struct btrfs_caching_control *caching_ctl = block_group->caching_ctl;
-       struct btrfs_root *extent_root = fs_info->extent_root;
+       struct btrfs_block_group_cache *block_group;
+       struct btrfs_fs_info *fs_info;
+       struct btrfs_caching_control *caching_ctl;
+       struct btrfs_root *extent_root;
        struct btrfs_path *path;
        struct extent_buffer *leaf;
        struct btrfs_key key;
@@ -334,9 +334,14 @@ static int caching_kthread(void *data)
        u32 nritems;
        int ret = 0;
 
+       caching_ctl = container_of(work, struct btrfs_caching_control, work);
+       block_group = caching_ctl->block_group;
+       fs_info = block_group->fs_info;
+       extent_root = fs_info->extent_root;
+
        path = btrfs_alloc_path();
        if (!path)
-               return -ENOMEM;
+               goto out;
 
        last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET);
 
@@ -433,13 +438,11 @@ err:
        free_excluded_extents(extent_root, block_group);
 
        mutex_unlock(&caching_ctl->mutex);
+out:
        wake_up(&caching_ctl->wait);
 
        put_caching_control(caching_ctl);
-       atomic_dec(&block_group->space_info->caching_threads);
        btrfs_put_block_group(block_group);
-
-       return 0;
 }
 
 static int cache_block_group(struct btrfs_block_group_cache *cache,
@@ -449,7 +452,6 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
 {
        struct btrfs_fs_info *fs_info = cache->fs_info;
        struct btrfs_caching_control *caching_ctl;
-       struct task_struct *tsk;
        int ret = 0;
 
        smp_mb();
@@ -501,6 +503,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
        caching_ctl->progress = cache->key.objectid;
        /* one for caching kthread, one for caching block group list */
        atomic_set(&caching_ctl->count, 2);
+       caching_ctl->work.func = caching_thread;
 
        spin_lock(&cache->lock);
        if (cache->cached != BTRFS_CACHE_NO) {
@@ -516,16 +519,9 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
        list_add_tail(&caching_ctl->list, &fs_info->caching_block_groups);
        up_write(&fs_info->extent_commit_sem);
 
-       atomic_inc(&cache->space_info->caching_threads);
        btrfs_get_block_group(cache);
 
-       tsk = kthread_run(caching_kthread, cache, "btrfs-cache-%llu\n",
-                         cache->key.objectid);
-       if (IS_ERR(tsk)) {
-               ret = PTR_ERR(tsk);
-               printk(KERN_ERR "error running thread %d\n", ret);
-               BUG();
-       }
+       btrfs_queue_worker(&fs_info->caching_workers, &caching_ctl->work);
 
        return ret;
 }
@@ -2932,9 +2928,10 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
        found->full = 0;
        found->force_alloc = CHUNK_ALLOC_NO_FORCE;
        found->chunk_alloc = 0;
+       found->flush = 0;
+       init_waitqueue_head(&found->wait);
        *space_info = found;
        list_add_rcu(&found->list, &info->space_info);
-       atomic_set(&found->caching_threads, 0);
        return 0;
 }
 
@@ -3314,6 +3311,14 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
        if (reserved == 0)
                return 0;
 
+       smp_mb();
+       if (root->fs_info->delalloc_bytes == 0) {
+               if (trans)
+                       return 0;
+               btrfs_wait_ordered_extents(root, 0, 0);
+               return 0;
+       }
+
        max_reclaim = min(reserved, to_reclaim);
 
        while (loops < 1024) {
@@ -3356,6 +3361,8 @@ static int shrink_delalloc(struct btrfs_trans_handle *trans,
                }
 
        }
+       if (reclaimed >= to_reclaim && !trans)
+               btrfs_wait_ordered_extents(root, 0, 0);
        return reclaimed >= to_reclaim;
 }
 
@@ -3380,15 +3387,36 @@ static int reserve_metadata_bytes(struct btrfs_trans_handle *trans,
        u64 num_bytes = orig_bytes;
        int retries = 0;
        int ret = 0;
-       bool reserved = false;
        bool committed = false;
+       bool flushing = false;
 
 again:
-       ret = -ENOSPC;
-       if (reserved)
-               num_bytes = 0;
-
+       ret = 0;
        spin_lock(&space_info->lock);
+       /*
+        * We only want to wait if somebody other than us is flushing and we are
+        * actually alloed to flush.
+        */
+       while (flush && !flushing && space_info->flush) {
+               spin_unlock(&space_info->lock);
+               /*
+                * If we have a trans handle we can't wait because the flusher
+                * may have to commit the transaction, which would mean we would
+                * deadlock since we are waiting for the flusher to finish, but
+                * hold the current transaction open.
+                */
+               if (trans)
+                       return -EAGAIN;
+               ret = wait_event_interruptible(space_info->wait,
+                                              !space_info->flush);
+               /* Must have been interrupted, return */
+               if (ret)
+                       return -EINTR;
+
+               spin_lock(&space_info->lock);
+       }
+
+       ret = -ENOSPC;
        unused = space_info->bytes_used + space_info->bytes_reserved +
                 space_info->bytes_pinned + space_info->bytes_readonly +
                 space_info->bytes_may_use;
@@ -3403,8 +3431,7 @@ again:
        if (unused <= space_info->total_bytes) {
                unused = space_info->total_bytes - unused;
                if (unused >= num_bytes) {
-                       if (!reserved)
-                               space_info->bytes_reserved += orig_bytes;
+                       space_info->bytes_reserved += orig_bytes;
                        ret = 0;
                } else {
                        /*
@@ -3429,17 +3456,14 @@ again:
         * to reclaim space we can actually use it instead of somebody else
         * stealing it from us.
         */
-       if (ret && !reserved) {
-               space_info->bytes_reserved += orig_bytes;
-               reserved = true;
+       if (ret && flush) {
+               flushing = true;
+               space_info->flush = 1;
        }
 
        spin_unlock(&space_info->lock);
 
-       if (!ret)
-               return 0;
-
-       if (!flush)
+       if (!ret || !flush)
                goto out;
 
        /*
@@ -3447,11 +3471,11 @@ again:
         * metadata until after the IO is completed.
         */
        ret = shrink_delalloc(trans, root, num_bytes, 1);
-       if (ret > 0)
-               return 0;
-       else if (ret < 0)
+       if (ret < 0)
                goto out;
 
+       ret = 0;
+
        /*
         * So if we were overcommitted it's possible that somebody else flushed
         * out enough space and we simply didn't have enough space to reclaim,
@@ -3462,11 +3486,11 @@ again:
                goto again;
        }
 
-       spin_lock(&space_info->lock);
        /*
         * Not enough space to be reclaimed, don't bother committing the
         * transaction.
         */
+       spin_lock(&space_info->lock);
        if (space_info->bytes_pinned < orig_bytes)
                ret = -ENOSPC;
        spin_unlock(&space_info->lock);
@@ -3474,10 +3498,13 @@ again:
                goto out;
 
        ret = -EAGAIN;
-       if (trans || committed)
+       if (trans)
                goto out;
 
        ret = -ENOSPC;
+       if (committed)
+               goto out;
+
        trans = btrfs_join_transaction(root);
        if (IS_ERR(trans))
                goto out;
@@ -3489,12 +3516,12 @@ again:
        }
 
 out:
-       if (reserved) {
+       if (flushing) {
                spin_lock(&space_info->lock);
-               space_info->bytes_reserved -= orig_bytes;
+               space_info->flush = 0;
+               wake_up_all(&space_info->wait);
                spin_unlock(&space_info->lock);
        }
-
        return ret;
 }
 
@@ -3704,7 +3731,6 @@ int btrfs_block_rsv_check(struct btrfs_trans_handle *trans,
        if (commit_trans) {
                if (trans)
                        return -EAGAIN;
-
                trans = btrfs_join_transaction(root);
                BUG_ON(IS_ERR(trans));
                ret = btrfs_commit_transaction(trans, root);
@@ -3874,26 +3900,6 @@ int btrfs_truncate_reserve_metadata(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *root,
-                                int num_items)
-{
-       u64 num_bytes;
-       int ret;
-
-       if (num_items == 0 || root->fs_info->chunk_root == root)
-               return 0;
-
-       num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
-       ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv,
-                                 num_bytes);
-       if (!ret) {
-               trans->bytes_reserved += num_bytes;
-               trans->block_rsv = &root->fs_info->trans_block_rsv;
-       }
-       return ret;
-}
-
 void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
                                  struct btrfs_root *root)
 {
@@ -3944,6 +3950,30 @@ int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
        return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
 }
 
+static unsigned drop_outstanding_extent(struct inode *inode)
+{
+       unsigned dropped_extents = 0;
+
+       spin_lock(&BTRFS_I(inode)->lock);
+       BUG_ON(!BTRFS_I(inode)->outstanding_extents);
+       BTRFS_I(inode)->outstanding_extents--;
+
+       /*
+        * If we have more or the same amount of outsanding extents than we have
+        * reserved then we need to leave the reserved extents count alone.
+        */
+       if (BTRFS_I(inode)->outstanding_extents >=
+           BTRFS_I(inode)->reserved_extents)
+               goto out;
+
+       dropped_extents = BTRFS_I(inode)->reserved_extents -
+               BTRFS_I(inode)->outstanding_extents;
+       BTRFS_I(inode)->reserved_extents -= dropped_extents;
+out:
+       spin_unlock(&BTRFS_I(inode)->lock);
+       return dropped_extents;
+}
+
 static u64 calc_csum_metadata_size(struct inode *inode, u64 num_bytes)
 {
        return num_bytes >>= 3;
@@ -3953,9 +3983,8 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv;
-       u64 to_reserve;
-       int nr_extents;
-       int reserved_extents;
+       u64 to_reserve = 0;
+       unsigned nr_extents = 0;
        int ret;
 
        if (btrfs_transaction_in_commit(root->fs_info))
@@ -3963,66 +3992,49 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
 
        num_bytes = ALIGN(num_bytes, root->sectorsize);
 
-       nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents) + 1;
-       reserved_extents = atomic_read(&BTRFS_I(inode)->reserved_extents);
+       spin_lock(&BTRFS_I(inode)->lock);
+       BTRFS_I(inode)->outstanding_extents++;
+
+       if (BTRFS_I(inode)->outstanding_extents >
+           BTRFS_I(inode)->reserved_extents) {
+               nr_extents = BTRFS_I(inode)->outstanding_extents -
+                       BTRFS_I(inode)->reserved_extents;
+               BTRFS_I(inode)->reserved_extents += nr_extents;
 
-       if (nr_extents > reserved_extents) {
-               nr_extents -= reserved_extents;
                to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
-       } else {
-               nr_extents = 0;
-               to_reserve = 0;
        }
+       spin_unlock(&BTRFS_I(inode)->lock);
 
        to_reserve += calc_csum_metadata_size(inode, num_bytes);
        ret = reserve_metadata_bytes(NULL, root, block_rsv, to_reserve, 1);
-       if (ret)
+       if (ret) {
+               unsigned dropped;
+               /*
+                * We don't need the return value since our reservation failed,
+                * we just need to clean up our counter.
+                */
+               dropped = drop_outstanding_extent(inode);
+               WARN_ON(dropped > 1);
                return ret;
-
-       atomic_add(nr_extents, &BTRFS_I(inode)->reserved_extents);
-       atomic_inc(&BTRFS_I(inode)->outstanding_extents);
+       }
 
        block_rsv_add_bytes(block_rsv, to_reserve, 1);
 
-       if (block_rsv->size > 512 * 1024 * 1024)
-               shrink_delalloc(NULL, root, to_reserve, 0);
-
        return 0;
 }
 
 void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       u64 to_free;
-       int nr_extents;
-       int reserved_extents;
+       u64 to_free = 0;
+       unsigned dropped;
 
        num_bytes = ALIGN(num_bytes, root->sectorsize);
-       atomic_dec(&BTRFS_I(inode)->outstanding_extents);
-       WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents) < 0);
-
-       reserved_extents = atomic_read(&BTRFS_I(inode)->reserved_extents);
-       do {
-               int old, new;
-
-               nr_extents = atomic_read(&BTRFS_I(inode)->outstanding_extents);
-               if (nr_extents >= reserved_extents) {
-                       nr_extents = 0;
-                       break;
-               }
-               old = reserved_extents;
-               nr_extents = reserved_extents - nr_extents;
-               new = reserved_extents - nr_extents;
-               old = atomic_cmpxchg(&BTRFS_I(inode)->reserved_extents,
-                                    reserved_extents, new);
-               if (likely(old == reserved_extents))
-                       break;
-               reserved_extents = old;
-       } while (1);
+       dropped = drop_outstanding_extent(inode);
 
        to_free = calc_csum_metadata_size(inode, num_bytes);
-       if (nr_extents > 0)
-               to_free += btrfs_calc_trans_metadata_size(root, nr_extents);
+       if (dropped > 0)
+               to_free += btrfs_calc_trans_metadata_size(root, dropped);
 
        btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv,
                                to_free);
@@ -4990,14 +5002,10 @@ have_block_group:
                        }
 
                        /*
-                        * We only want to start kthread caching if we are at
-                        * the point where we will wait for caching to make
-                        * progress, or if our ideal search is over and we've
-                        * found somebody to start caching.
+                        * The caching workers are limited to 2 threads, so we
+                        * can queue as much work as we care to.
                         */
-                       if (loop > LOOP_CACHING_NOWAIT ||
-                           (loop > LOOP_FIND_IDEAL &&
-                            atomic_read(&space_info->caching_threads) < 2)) {
+                       if (loop > LOOP_FIND_IDEAL) {
                                ret = cache_block_group(block_group, trans,
                                                        orig_root, 0);
                                BUG_ON(ret);
@@ -5219,8 +5227,7 @@ loop:
                if (loop == LOOP_FIND_IDEAL && found_uncached_bg) {
                        found_uncached_bg = false;
                        loop++;
-                       if (!ideal_cache_percent &&
-                           atomic_read(&space_info->caching_threads))
+                       if (!ideal_cache_percent)
                                goto search;
 
                        /*
@@ -5623,7 +5630,7 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
        if (!buf)
                return ERR_PTR(-ENOMEM);
        btrfs_set_header_generation(buf, trans->transid);
-       btrfs_set_buffer_lockdep_class(buf, level);
+       btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level);
        btrfs_tree_lock(buf);
        clean_tree_block(trans, root, buf);
 
@@ -5910,7 +5917,7 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
                        return 1;
 
                if (path->locks[level] && !wc->keep_locks) {
-                       btrfs_tree_unlock(eb);
+                       btrfs_tree_unlock_rw(eb, path->locks[level]);
                        path->locks[level] = 0;
                }
                return 0;
@@ -5934,7 +5941,7 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
         * keep the tree lock
         */
        if (path->locks[level] && level > 0) {
-               btrfs_tree_unlock(eb);
+               btrfs_tree_unlock_rw(eb, path->locks[level]);
                path->locks[level] = 0;
        }
        return 0;
@@ -6047,7 +6054,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
        BUG_ON(level != btrfs_header_level(next));
        path->nodes[level] = next;
        path->slots[level] = 0;
-       path->locks[level] = 1;
+       path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING;
        wc->level = level;
        if (wc->level == 1)
                wc->reada_slot = 0;
@@ -6118,7 +6125,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                        BUG_ON(level == 0);
                        btrfs_tree_lock(eb);
                        btrfs_set_lock_blocking(eb);
-                       path->locks[level] = 1;
+                       path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING;
 
                        ret = btrfs_lookup_extent_info(trans, root,
                                                       eb->start, eb->len,
@@ -6127,8 +6134,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                        BUG_ON(ret);
                        BUG_ON(wc->refs[level] == 0);
                        if (wc->refs[level] == 1) {
-                               btrfs_tree_unlock(eb);
-                               path->locks[level] = 0;
+                               btrfs_tree_unlock_rw(eb, path->locks[level]);
                                return 1;
                        }
                }
@@ -6150,7 +6156,7 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                    btrfs_header_generation(eb) == trans->transid) {
                        btrfs_tree_lock(eb);
                        btrfs_set_lock_blocking(eb);
-                       path->locks[level] = 1;
+                       path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING;
                }
                clean_tree_block(trans, root, eb);
        }
@@ -6229,7 +6235,8 @@ static noinline int walk_up_tree(struct btrfs_trans_handle *trans,
                                return 0;
 
                        if (path->locks[level]) {
-                               btrfs_tree_unlock(path->nodes[level]);
+                               btrfs_tree_unlock_rw(path->nodes[level],
+                                                    path->locks[level]);
                                path->locks[level] = 0;
                        }
                        free_extent_buffer(path->nodes[level]);
@@ -6281,7 +6288,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                path->nodes[level] = btrfs_lock_root_node(root);
                btrfs_set_lock_blocking(path->nodes[level]);
                path->slots[level] = 0;
-               path->locks[level] = 1;
+               path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING;
                memset(&wc->update_progress, 0,
                       sizeof(wc->update_progress));
        } else {
@@ -6449,7 +6456,7 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
        level = btrfs_header_level(node);
        path->nodes[level] = node;
        path->slots[level] = 0;
-       path->locks[level] = 1;
+       path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING;
 
        wc->refs[parent_level] = 1;
        wc->flags[parent_level] = BTRFS_BLOCK_FLAG_FULL_BACKREF;
@@ -6524,15 +6531,28 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
        return flags;
 }
 
-static int set_block_group_ro(struct btrfs_block_group_cache *cache)
+static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force)
 {
        struct btrfs_space_info *sinfo = cache->space_info;
        u64 num_bytes;
+       u64 min_allocable_bytes;
        int ret = -ENOSPC;
 
        if (cache->ro)
                return 0;
 
+       /*
+        * We need some metadata space and system metadata space for
+        * allocating chunks in some corner cases until we force to set
+        * it to be readonly.
+        */
+       if ((sinfo->flags &
+            (BTRFS_BLOCK_GROUP_SYSTEM | BTRFS_BLOCK_GROUP_METADATA)) &&
+           !force)
+               min_allocable_bytes = 1 * 1024 * 1024;
+       else
+               min_allocable_bytes = 0;
+
        spin_lock(&sinfo->lock);
        spin_lock(&cache->lock);
        num_bytes = cache->key.offset - cache->reserved - cache->pinned -
@@ -6540,7 +6560,8 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache)
 
        if (sinfo->bytes_used + sinfo->bytes_reserved + sinfo->bytes_pinned +
            sinfo->bytes_may_use + sinfo->bytes_readonly +
-           cache->reserved_pinned + num_bytes <= sinfo->total_bytes) {
+           cache->reserved_pinned + num_bytes + min_allocable_bytes <=
+           sinfo->total_bytes) {
                sinfo->bytes_readonly += num_bytes;
                sinfo->bytes_reserved += cache->reserved_pinned;
                cache->reserved_pinned = 0;
@@ -6571,7 +6592,7 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
                do_chunk_alloc(trans, root, 2 * 1024 * 1024, alloc_flags,
                               CHUNK_ALLOC_FORCE);
 
-       ret = set_block_group_ro(cache);
+       ret = set_block_group_ro(cache, 0);
        if (!ret)
                goto out;
        alloc_flags = get_alloc_profile(root, cache->space_info->flags);
@@ -6579,7 +6600,7 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
                             CHUNK_ALLOC_FORCE);
        if (ret < 0)
                goto out;
-       ret = set_block_group_ro(cache);
+       ret = set_block_group_ro(cache, 0);
 out:
        btrfs_end_transaction(trans, root);
        return ret;
@@ -7016,7 +7037,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
 
                set_avail_alloc_bits(root->fs_info, cache->flags);
                if (btrfs_chunk_readonly(root, cache->key.objectid))
-                       set_block_group_ro(cache);
+                       set_block_group_ro(cache, 1);
        }
 
        list_for_each_entry_rcu(space_info, &root->fs_info->space_info, list) {
@@ -7030,9 +7051,9 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                 * mirrored block groups.
                 */
                list_for_each_entry(cache, &space_info->block_groups[3], list)
-                       set_block_group_ro(cache);
+                       set_block_group_ro(cache, 1);
                list_for_each_entry(cache, &space_info->block_groups[4], list)
-                       set_block_group_ro(cache);
+                       set_block_group_ro(cache, 1);
        }
 
        init_global_block_rsv(info);
index 561262d35689f463875e6bf4214f12ff5725b775..067b1747421bfd655b2d0ddbd228f195cca65553 100644 (file)
@@ -281,11 +281,10 @@ static int merge_state(struct extent_io_tree *tree,
                if (other->start == state->end + 1 &&
                    other->state == state->state) {
                        merge_cb(tree, state, other);
-                       other->start = state->start;
-                       state->tree = NULL;
-                       rb_erase(&state->rb_node, &tree->state);
-                       free_extent_state(state);
-                       state = NULL;
+                       state->end = other->end;
+                       other->tree = NULL;
+                       rb_erase(&other->rb_node, &tree->state);
+                       free_extent_state(other);
                }
        }
 
@@ -351,7 +350,6 @@ static int insert_state(struct extent_io_tree *tree,
                       "%llu %llu\n", (unsigned long long)found->start,
                       (unsigned long long)found->end,
                       (unsigned long long)start, (unsigned long long)end);
-               free_extent_state(state);
                return -EEXIST;
        }
        state->tree = tree;
@@ -500,7 +498,8 @@ again:
                        cached_state = NULL;
                }
 
-               if (cached && cached->tree && cached->start == start) {
+               if (cached && cached->tree && cached->start <= start &&
+                   cached->end > start) {
                        if (clear)
                                atomic_dec(&cached->refs);
                        state = cached;
@@ -742,7 +741,8 @@ again:
        spin_lock(&tree->lock);
        if (cached_state && *cached_state) {
                state = *cached_state;
-               if (state->start == start && state->tree) {
+               if (state->start <= start && state->end > start &&
+                   state->tree) {
                        node = &state->rb_node;
                        goto hit_next;
                }
@@ -783,13 +783,13 @@ hit_next:
                if (err)
                        goto out;
 
-               next_node = rb_next(node);
                cache_state(state, cached_state);
                merge_state(tree, state);
                if (last_end == (u64)-1)
                        goto out;
 
                start = last_end + 1;
+               next_node = rb_next(&state->rb_node);
                if (next_node && start < end && prealloc && !need_resched()) {
                        state = rb_entry(next_node, struct extent_state,
                                         rb_node);
@@ -862,7 +862,6 @@ hit_next:
                 * Avoid to free 'prealloc' if it can be merged with
                 * the later extent.
                 */
-               atomic_inc(&prealloc->refs);
                err = insert_state(tree, prealloc, start, this_end,
                                   &bits);
                BUG_ON(err == -EEXIST);
@@ -872,7 +871,6 @@ hit_next:
                        goto out;
                }
                cache_state(prealloc, cached_state);
-               free_extent_state(prealloc);
                prealloc = NULL;
                start = this_end + 1;
                goto search_again;
@@ -1564,7 +1562,8 @@ int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
        int bitset = 0;
 
        spin_lock(&tree->lock);
-       if (cached && cached->tree && cached->start == start)
+       if (cached && cached->tree && cached->start <= start &&
+           cached->end > start)
                node = &cached->rb_node;
        else
                node = tree_search(tree, start);
@@ -2432,6 +2431,7 @@ static int extent_write_cache_pages(struct extent_io_tree *tree,
        pgoff_t index;
        pgoff_t end;            /* Inclusive */
        int scanned = 0;
+       int tag;
 
        pagevec_init(&pvec, 0);
        if (wbc->range_cyclic) {
@@ -2442,11 +2442,16 @@ static int extent_write_cache_pages(struct extent_io_tree *tree,
                end = wbc->range_end >> PAGE_CACHE_SHIFT;
                scanned = 1;
        }
+       if (wbc->sync_mode == WB_SYNC_ALL)
+               tag = PAGECACHE_TAG_TOWRITE;
+       else
+               tag = PAGECACHE_TAG_DIRTY;
 retry:
+       if (wbc->sync_mode == WB_SYNC_ALL)
+               tag_pages_for_writeback(mapping, index, end);
        while (!done && !nr_to_write_done && (index <= end) &&
-              (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
-                             PAGECACHE_TAG_DIRTY, min(end - index,
-                                 (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
+              (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
+                       min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
                unsigned i;
 
                scanned = 1;
@@ -3020,8 +3025,15 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
                return NULL;
        eb->start = start;
        eb->len = len;
-       spin_lock_init(&eb->lock);
-       init_waitqueue_head(&eb->lock_wq);
+       rwlock_init(&eb->lock);
+       atomic_set(&eb->write_locks, 0);
+       atomic_set(&eb->read_locks, 0);
+       atomic_set(&eb->blocking_readers, 0);
+       atomic_set(&eb->blocking_writers, 0);
+       atomic_set(&eb->spinning_readers, 0);
+       atomic_set(&eb->spinning_writers, 0);
+       init_waitqueue_head(&eb->write_lock_wq);
+       init_waitqueue_head(&eb->read_lock_wq);
 
 #if LEAK_DEBUG
        spin_lock_irqsave(&leak_lock, flags);
@@ -3117,7 +3129,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
                i = 0;
        }
        for (; i < num_pages; i++, index++) {
-               p = find_or_create_page(mapping, index, GFP_NOFS | __GFP_HIGHMEM);
+               p = find_or_create_page(mapping, index, GFP_NOFS);
                if (!p) {
                        WARN_ON(1);
                        goto free_eb;
@@ -3264,6 +3276,22 @@ int set_extent_buffer_dirty(struct extent_io_tree *tree,
        return was_dirty;
 }
 
+static int __eb_straddles_pages(u64 start, u64 len)
+{
+       if (len < PAGE_CACHE_SIZE)
+               return 1;
+       if (start & (PAGE_CACHE_SIZE - 1))
+               return 1;
+       if ((start + len) & (PAGE_CACHE_SIZE - 1))
+               return 1;
+       return 0;
+}
+
+static int eb_straddles_pages(struct extent_buffer *eb)
+{
+       return __eb_straddles_pages(eb->start, eb->len);
+}
+
 int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
                                struct extent_buffer *eb,
                                struct extent_state **cached_state)
@@ -3275,8 +3303,10 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
        num_pages = num_extent_pages(eb->start, eb->len);
        clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
 
-       clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
-                             cached_state, GFP_NOFS);
+       if (eb_straddles_pages(eb)) {
+               clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
+                                     cached_state, GFP_NOFS);
+       }
        for (i = 0; i < num_pages; i++) {
                page = extent_buffer_page(eb, i);
                if (page)
@@ -3294,8 +3324,10 @@ int set_extent_buffer_uptodate(struct extent_io_tree *tree,
 
        num_pages = num_extent_pages(eb->start, eb->len);
 
-       set_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
-                           NULL, GFP_NOFS);
+       if (eb_straddles_pages(eb)) {
+               set_extent_uptodate(tree, eb->start, eb->start + eb->len - 1,
+                                   NULL, GFP_NOFS);
+       }
        for (i = 0; i < num_pages; i++) {
                page = extent_buffer_page(eb, i);
                if ((i == 0 && (eb->start & (PAGE_CACHE_SIZE - 1))) ||
@@ -3318,9 +3350,12 @@ int extent_range_uptodate(struct extent_io_tree *tree,
        int uptodate;
        unsigned long index;
 
-       ret = test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL);
-       if (ret)
-               return 1;
+       if (__eb_straddles_pages(start, end - start + 1)) {
+               ret = test_range_bit(tree, start, end,
+                                    EXTENT_UPTODATE, 1, NULL);
+               if (ret)
+                       return 1;
+       }
        while (start <= end) {
                index = start >> PAGE_CACHE_SHIFT;
                page = find_get_page(tree->mapping, index);
@@ -3348,10 +3383,12 @@ int extent_buffer_uptodate(struct extent_io_tree *tree,
        if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))
                return 1;
 
-       ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
-                          EXTENT_UPTODATE, 1, cached_state);
-       if (ret)
-               return ret;
+       if (eb_straddles_pages(eb)) {
+               ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1,
+                                  EXTENT_UPTODATE, 1, cached_state);
+               if (ret)
+                       return ret;
+       }
 
        num_pages = num_extent_pages(eb->start, eb->len);
        for (i = 0; i < num_pages; i++) {
@@ -3384,9 +3421,11 @@ int read_extent_buffer_pages(struct extent_io_tree *tree,
        if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags))
                return 0;
 
-       if (test_range_bit(tree, eb->start, eb->start + eb->len - 1,
-                          EXTENT_UPTODATE, 1, NULL)) {
-               return 0;
+       if (eb_straddles_pages(eb)) {
+               if (test_range_bit(tree, eb->start, eb->start + eb->len - 1,
+                                  EXTENT_UPTODATE, 1, NULL)) {
+                       return 0;
+               }
        }
 
        if (start) {
@@ -3490,9 +3529,8 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv,
                page = extent_buffer_page(eb, i);
 
                cur = min(len, (PAGE_CACHE_SIZE - offset));
-               kaddr = kmap_atomic(page, KM_USER1);
+               kaddr = page_address(page);
                memcpy(dst, kaddr + offset, cur);
-               kunmap_atomic(kaddr, KM_USER1);
 
                dst += cur;
                len -= cur;
@@ -3502,9 +3540,9 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv,
 }
 
 int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
-                              unsigned long min_len, char **token, char **map,
+                              unsigned long min_len, char **map,
                               unsigned long *map_start,
-                              unsigned long *map_len, int km)
+                              unsigned long *map_len)
 {
        size_t offset = start & (PAGE_CACHE_SIZE - 1);
        char *kaddr;
@@ -3534,42 +3572,12 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
        }
 
        p = extent_buffer_page(eb, i);
-       kaddr = kmap_atomic(p, km);
-       *token = kaddr;
+       kaddr = page_address(p);
        *map = kaddr + offset;
        *map_len = PAGE_CACHE_SIZE - offset;
        return 0;
 }
 
-int map_extent_buffer(struct extent_buffer *eb, unsigned long start,
-                     unsigned long min_len,
-                     char **token, char **map,
-                     unsigned long *map_start,
-                     unsigned long *map_len, int km)
-{
-       int err;
-       int save = 0;
-       if (eb->map_token) {
-               unmap_extent_buffer(eb, eb->map_token, km);
-               eb->map_token = NULL;
-               save = 1;
-       }
-       err = map_private_extent_buffer(eb, start, min_len, token, map,
-                                      map_start, map_len, km);
-       if (!err && save) {
-               eb->map_token = *token;
-               eb->kaddr = *map;
-               eb->map_start = *map_start;
-               eb->map_len = *map_len;
-       }
-       return err;
-}
-
-void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km)
-{
-       kunmap_atomic(token, km);
-}
-
 int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
                          unsigned long start,
                          unsigned long len)
@@ -3593,9 +3601,8 @@ int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
 
                cur = min(len, (PAGE_CACHE_SIZE - offset));
 
-               kaddr = kmap_atomic(page, KM_USER0);
+               kaddr = page_address(page);
                ret = memcmp(ptr, kaddr + offset, cur);
-               kunmap_atomic(kaddr, KM_USER0);
                if (ret)
                        break;
 
@@ -3628,9 +3635,8 @@ void write_extent_buffer(struct extent_buffer *eb, const void *srcv,
                WARN_ON(!PageUptodate(page));
 
                cur = min(len, PAGE_CACHE_SIZE - offset);
-               kaddr = kmap_atomic(page, KM_USER1);
+               kaddr = page_address(page);
                memcpy(kaddr + offset, src, cur);
-               kunmap_atomic(kaddr, KM_USER1);
 
                src += cur;
                len -= cur;
@@ -3659,9 +3665,8 @@ void memset_extent_buffer(struct extent_buffer *eb, char c,
                WARN_ON(!PageUptodate(page));
 
                cur = min(len, PAGE_CACHE_SIZE - offset);
-               kaddr = kmap_atomic(page, KM_USER0);
+               kaddr = page_address(page);
                memset(kaddr + offset, c, cur);
-               kunmap_atomic(kaddr, KM_USER0);
 
                len -= cur;
                offset = 0;
@@ -3692,9 +3697,8 @@ void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
 
                cur = min(len, (unsigned long)(PAGE_CACHE_SIZE - offset));
 
-               kaddr = kmap_atomic(page, KM_USER0);
+               kaddr = page_address(page);
                read_extent_buffer(src, kaddr + offset, src_offset, cur);
-               kunmap_atomic(kaddr, KM_USER0);
 
                src_offset += cur;
                len -= cur;
@@ -3707,20 +3711,17 @@ static void move_pages(struct page *dst_page, struct page *src_page,
                       unsigned long dst_off, unsigned long src_off,
                       unsigned long len)
 {
-       char *dst_kaddr = kmap_atomic(dst_page, KM_USER0);
+       char *dst_kaddr = page_address(dst_page);
        if (dst_page == src_page) {
                memmove(dst_kaddr + dst_off, dst_kaddr + src_off, len);
        } else {
-               char *src_kaddr = kmap_atomic(src_page, KM_USER1);
+               char *src_kaddr = page_address(src_page);
                char *p = dst_kaddr + dst_off + len;
                char *s = src_kaddr + src_off + len;
 
                while (len--)
                        *--p = *--s;
-
-               kunmap_atomic(src_kaddr, KM_USER1);
        }
-       kunmap_atomic(dst_kaddr, KM_USER0);
 }
 
 static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len)
@@ -3733,20 +3734,17 @@ static void copy_pages(struct page *dst_page, struct page *src_page,
                       unsigned long dst_off, unsigned long src_off,
                       unsigned long len)
 {
-       char *dst_kaddr = kmap_atomic(dst_page, KM_USER0);
+       char *dst_kaddr = page_address(dst_page);
        char *src_kaddr;
 
        if (dst_page != src_page) {
-               src_kaddr = kmap_atomic(src_page, KM_USER1);
+               src_kaddr = page_address(src_page);
        } else {
                src_kaddr = dst_kaddr;
                BUG_ON(areas_overlap(src_off, dst_off, len));
        }
 
        memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len);
-       kunmap_atomic(dst_kaddr, KM_USER0);
-       if (dst_page != src_page)
-               kunmap_atomic(src_kaddr, KM_USER1);
 }
 
 void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
index a11a92ee2d30a84ccf52284e704c5cc971f7126e..21a7ca9e72825752a3b910cdfb9fac444094b96b 100644 (file)
@@ -120,8 +120,6 @@ struct extent_state {
 struct extent_buffer {
        u64 start;
        unsigned long len;
-       char *map_token;
-       char *kaddr;
        unsigned long map_start;
        unsigned long map_len;
        struct page *first_page;
@@ -130,14 +128,26 @@ struct extent_buffer {
        struct rcu_head rcu_head;
        atomic_t refs;
 
-       /* the spinlock is used to protect most operations */
-       spinlock_t lock;
+       /* count of read lock holders on the extent buffer */
+       atomic_t write_locks;
+       atomic_t read_locks;
+       atomic_t blocking_writers;
+       atomic_t blocking_readers;
+       atomic_t spinning_readers;
+       atomic_t spinning_writers;
+
+       /* protects write locks */
+       rwlock_t lock;
 
-       /*
-        * when we keep the lock held while blocking, waiters go onto
-        * the wq
+       /* readers use lock_wq while they wait for the write
+        * lock holders to unlock
         */
-       wait_queue_head_t lock_wq;
+       wait_queue_head_t write_lock_wq;
+
+       /* writers use read_lock_wq while they wait for readers
+        * to unlock
+        */
+       wait_queue_head_t read_lock_wq;
 };
 
 static inline void extent_set_compress_type(unsigned long *bio_flags,
@@ -279,15 +289,10 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
 int extent_buffer_uptodate(struct extent_io_tree *tree,
                           struct extent_buffer *eb,
                           struct extent_state *cached_state);
-int map_extent_buffer(struct extent_buffer *eb, unsigned long offset,
-                     unsigned long min_len, char **token, char **map,
-                     unsigned long *map_start,
-                     unsigned long *map_len, int km);
 int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
-                     unsigned long min_len, char **token, char **map,
+                     unsigned long min_len, char **map,
                      unsigned long *map_start,
-                     unsigned long *map_len, int km);
-void unmap_extent_buffer(struct extent_buffer *eb, char *token, int km);
+                     unsigned long *map_len);
 int extent_range_uptodate(struct extent_io_tree *tree,
                          u64 start, u64 end);
 int extent_clear_unlock_delalloc(struct inode *inode,
index 90d4ee52cd458ac9f7bf87dfe4a34c99be27bc30..08bcfa92a2226bcfd3ba0edf6fe8eb944454612b 100644 (file)
@@ -177,6 +177,15 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
 
        WARN_ON(bio->bi_vcnt <= 0);
 
+       /*
+        * the free space stuff is only read when it hasn't been
+        * updated in the current transaction.  So, we can safely
+        * read from the commit root and sidestep a nasty deadlock
+        * between reading the free space cache and updating the csum tree.
+        */
+       if (btrfs_is_free_space_inode(root, inode))
+               path->search_commit_root = 1;
+
        disk_bytenr = (u64)bio->bi_sector << 9;
        if (dio)
                offset = logical_offset;
@@ -664,10 +673,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
        struct btrfs_sector_sum *sector_sum;
        u32 nritems;
        u32 ins_size;
-       char *eb_map;
-       char *eb_token;
-       unsigned long map_len;
-       unsigned long map_start;
        u16 csum_size =
                btrfs_super_csum_size(&root->fs_info->super_copy);
 
@@ -814,30 +819,9 @@ found:
        item_end = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
        item_end = (struct btrfs_csum_item *)((unsigned char *)item_end +
                                      btrfs_item_size_nr(leaf, path->slots[0]));
-       eb_token = NULL;
 next_sector:
 
-       if (!eb_token ||
-          (unsigned long)item + csum_size >= map_start + map_len) {
-               int err;
-
-               if (eb_token)
-                       unmap_extent_buffer(leaf, eb_token, KM_USER1);
-               eb_token = NULL;
-               err = map_private_extent_buffer(leaf, (unsigned long)item,
-                                               csum_size,
-                                               &eb_token, &eb_map,
-                                               &map_start, &map_len, KM_USER1);
-               if (err)
-                       eb_token = NULL;
-       }
-       if (eb_token) {
-               memcpy(eb_token + ((unsigned long)item & (PAGE_CACHE_SIZE - 1)),
-                      &sector_sum->sum, csum_size);
-       } else {
-               write_extent_buffer(leaf, &sector_sum->sum,
-                                   (unsigned long)item, csum_size);
-       }
+       write_extent_buffer(leaf, &sector_sum->sum, (unsigned long)item, csum_size);
 
        total_bytes += root->sectorsize;
        sector_sum++;
@@ -850,10 +834,7 @@ next_sector:
                        goto next_sector;
                }
        }
-       if (eb_token) {
-               unmap_extent_buffer(leaf, eb_token, KM_USER1);
-               eb_token = NULL;
-       }
+
        btrfs_mark_buffer_dirty(path->nodes[0]);
        if (total_bytes < sums->len) {
                btrfs_release_path(path);
index 59cbdb120ad0917a001dd9c97d5a17999e6ce59e..a35e51c9f235559c5c9a0f5f5ddea267e6c14a40 100644 (file)
@@ -1081,7 +1081,8 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
 
 again:
        for (i = 0; i < num_pages; i++) {
-               pages[i] = grab_cache_page(inode->i_mapping, index + i);
+               pages[i] = find_or_create_page(inode->i_mapping, index + i,
+                                              GFP_NOFS);
                if (!pages[i]) {
                        faili = i - 1;
                        err = -ENOMEM;
@@ -1238,9 +1239,11 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                 * managed to copy.
                 */
                if (num_pages > dirty_pages) {
-                       if (copied > 0)
-                               atomic_inc(
-                                       &BTRFS_I(inode)->outstanding_extents);
+                       if (copied > 0) {
+                               spin_lock(&BTRFS_I(inode)->lock);
+                               BTRFS_I(inode)->outstanding_extents++;
+                               spin_unlock(&BTRFS_I(inode)->lock);
+                       }
                        btrfs_delalloc_release_space(inode,
                                        (num_pages - dirty_pages) <<
                                        PAGE_CACHE_SHIFT);
index bf0d61567f3d65a24e9d11802acdd0c8c5abf32b..6377713f639c978db84f64dec2dc9541e8c8287e 100644 (file)
@@ -98,6 +98,12 @@ struct inode *lookup_free_space_inode(struct btrfs_root *root,
                return inode;
 
        spin_lock(&block_group->lock);
+       if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM) {
+               printk(KERN_INFO "Old style space inode found, converting.\n");
+               BTRFS_I(inode)->flags &= ~BTRFS_INODE_NODATASUM;
+               block_group->disk_cache_state = BTRFS_DC_CLEAR;
+       }
+
        if (!btrfs_fs_closing(root->fs_info)) {
                block_group->inode = igrab(inode);
                block_group->iref = 1;
@@ -135,7 +141,7 @@ int __create_free_space_inode(struct btrfs_root *root,
        btrfs_set_inode_gid(leaf, inode_item, 0);
        btrfs_set_inode_mode(leaf, inode_item, S_IFREG | 0600);
        btrfs_set_inode_flags(leaf, inode_item, BTRFS_INODE_NOCOMPRESS |
-                             BTRFS_INODE_PREALLOC | BTRFS_INODE_NODATASUM);
+                             BTRFS_INODE_PREALLOC);
        btrfs_set_inode_nlink(leaf, inode_item, 1);
        btrfs_set_inode_transid(leaf, inode_item, trans->transid);
        btrfs_set_inode_block_group(leaf, inode_item, offset);
@@ -239,17 +245,12 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
        struct btrfs_free_space_header *header;
        struct extent_buffer *leaf;
        struct page *page;
-       u32 *checksums = NULL, *crc;
-       char *disk_crcs = NULL;
        struct btrfs_key key;
        struct list_head bitmaps;
        u64 num_entries;
        u64 num_bitmaps;
        u64 generation;
-       u32 cur_crc = ~(u32)0;
        pgoff_t index = 0;
-       unsigned long first_page_offset;
-       int num_checksums;
        int ret = 0;
 
        INIT_LIST_HEAD(&bitmaps);
@@ -292,16 +293,6 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
        if (!num_entries)
                goto out;
 
-       /* Setup everything for doing checksumming */
-       num_checksums = i_size_read(inode) / PAGE_CACHE_SIZE;
-       checksums = crc = kzalloc(sizeof(u32) * num_checksums, GFP_NOFS);
-       if (!checksums)
-               goto out;
-       first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64);
-       disk_crcs = kzalloc(first_page_offset, GFP_NOFS);
-       if (!disk_crcs)
-               goto out;
-
        ret = readahead_cache(inode);
        if (ret)
                goto out;
@@ -311,18 +302,12 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
                struct btrfs_free_space *e;
                void *addr;
                unsigned long offset = 0;
-               unsigned long start_offset = 0;
                int need_loop = 0;
 
                if (!num_entries && !num_bitmaps)
                        break;
 
-               if (index == 0) {
-                       start_offset = first_page_offset;
-                       offset = start_offset;
-               }
-
-               page = grab_cache_page(inode->i_mapping, index);
+               page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
                if (!page)
                        goto free_cache;
 
@@ -342,8 +327,15 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
                if (index == 0) {
                        u64 *gen;
 
-                       memcpy(disk_crcs, addr, first_page_offset);
-                       gen = addr + (sizeof(u32) * num_checksums);
+                       /*
+                        * We put a bogus crc in the front of the first page in
+                        * case old kernels try to mount a fs with the new
+                        * format to make sure they discard the cache.
+                        */
+                       addr += sizeof(u64);
+                       offset += sizeof(u64);
+
+                       gen = addr;
                        if (*gen != BTRFS_I(inode)->generation) {
                                printk(KERN_ERR "btrfs: space cache generation"
                                       " (%llu) does not match inode (%llu)\n",
@@ -355,24 +347,10 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
                                page_cache_release(page);
                                goto free_cache;
                        }
-                       crc = (u32 *)disk_crcs;
-               }
-               entry = addr + start_offset;
-
-               /* First lets check our crc before we do anything fun */
-               cur_crc = ~(u32)0;
-               cur_crc = btrfs_csum_data(root, addr + start_offset, cur_crc,
-                                         PAGE_CACHE_SIZE - start_offset);
-               btrfs_csum_final(cur_crc, (char *)&cur_crc);
-               if (cur_crc != *crc) {
-                       printk(KERN_ERR "btrfs: crc mismatch for page %lu\n",
-                              index);
-                       kunmap(page);
-                       unlock_page(page);
-                       page_cache_release(page);
-                       goto free_cache;
+                       addr += sizeof(u64);
+                       offset += sizeof(u64);
                }
-               crc++;
+               entry = addr;
 
                while (1) {
                        if (!num_entries)
@@ -470,8 +448,6 @@ next:
 
        ret = 1;
 out:
-       kfree(checksums);
-       kfree(disk_crcs);
        return ret;
 free_cache:
        __btrfs_remove_free_space_cache(ctl);
@@ -569,8 +545,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
        struct btrfs_key key;
        u64 start, end, len;
        u64 bytes = 0;
-       u32 *crc, *checksums;
-       unsigned long first_page_offset;
+       u32 crc = ~(u32)0;
        int index = 0, num_pages = 0;
        int entries = 0;
        int bitmaps = 0;
@@ -590,34 +565,13 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
        num_pages = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
                PAGE_CACHE_SHIFT;
 
-       /* Since the first page has all of our checksums and our generation we
-        * need to calculate the offset into the page that we can start writing
-        * our entries.
-        */
-       first_page_offset = (sizeof(u32) * num_pages) + sizeof(u64);
-
        filemap_write_and_wait(inode->i_mapping);
        btrfs_wait_ordered_range(inode, inode->i_size &
                                 ~(root->sectorsize - 1), (u64)-1);
 
-       /* make sure we don't overflow that first page */
-       if (first_page_offset + sizeof(struct btrfs_free_space_entry) >= PAGE_CACHE_SIZE) {
-               /* this is really the same as running out of space, where we also return 0 */
-               printk(KERN_CRIT "Btrfs: free space cache was too big for the crc page\n");
-               ret = 0;
-               goto out_update;
-       }
-
-       /* We need a checksum per page. */
-       crc = checksums = kzalloc(sizeof(u32) * num_pages, GFP_NOFS);
-       if (!crc)
-               return -1;
-
        pages = kzalloc(sizeof(struct page *) * num_pages, GFP_NOFS);
-       if (!pages) {
-               kfree(crc);
+       if (!pages)
                return -1;
-       }
 
        /* Get the cluster for this block_group if it exists */
        if (block_group && !list_empty(&block_group->cluster_list))
@@ -640,7 +594,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
         * know and don't freak out.
         */
        while (index < num_pages) {
-               page = grab_cache_page(inode->i_mapping, index);
+               page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
                if (!page) {
                        int i;
 
@@ -648,7 +602,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
                                unlock_page(pages[i]);
                                page_cache_release(pages[i]);
                        }
-                       goto out_free;
+                       goto out;
                }
                pages[index] = page;
                index++;
@@ -668,17 +622,11 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
        /* Write out the extent entries */
        do {
                struct btrfs_free_space_entry *entry;
-               void *addr;
+               void *addr, *orig;
                unsigned long offset = 0;
-               unsigned long start_offset = 0;
 
                next_page = false;
 
-               if (index == 0) {
-                       start_offset = first_page_offset;
-                       offset = start_offset;
-               }
-
                if (index >= num_pages) {
                        out_of_space = true;
                        break;
@@ -686,10 +634,26 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
 
                page = pages[index];
 
-               addr = kmap(page);
-               entry = addr + start_offset;
+               orig = addr = kmap(page);
+               if (index == 0) {
+                       u64 *gen;
 
-               memset(addr, 0, PAGE_CACHE_SIZE);
+                       /*
+                        * We're going to put in a bogus crc for this page to
+                        * make sure that old kernels who aren't aware of this
+                        * format will be sure to discard the cache.
+                        */
+                       addr += sizeof(u64);
+                       offset += sizeof(u64);
+
+                       gen = addr;
+                       *gen = trans->transid;
+                       addr += sizeof(u64);
+                       offset += sizeof(u64);
+               }
+               entry = addr;
+
+               memset(addr, 0, PAGE_CACHE_SIZE - offset);
                while (node && !next_page) {
                        struct btrfs_free_space *e;
 
@@ -752,13 +716,19 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
                                next_page = true;
                        entry++;
                }
-               *crc = ~(u32)0;
-               *crc = btrfs_csum_data(root, addr + start_offset, *crc,
-                                      PAGE_CACHE_SIZE - start_offset);
-               kunmap(page);
 
-               btrfs_csum_final(*crc, (char *)crc);
-               crc++;
+               /* Generate bogus crc value */
+               if (index == 0) {
+                       u32 *tmp;
+                       crc = btrfs_csum_data(root, orig + sizeof(u64), crc,
+                                             PAGE_CACHE_SIZE - sizeof(u64));
+                       btrfs_csum_final(crc, (char *)&crc);
+                       crc++;
+                       tmp = orig;
+                       *tmp = crc;
+               }
+
+               kunmap(page);
 
                bytes += PAGE_CACHE_SIZE;
 
@@ -779,11 +749,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
 
                addr = kmap(page);
                memcpy(addr, entry->bitmap, PAGE_CACHE_SIZE);
-               *crc = ~(u32)0;
-               *crc = btrfs_csum_data(root, addr, *crc, PAGE_CACHE_SIZE);
                kunmap(page);
-               btrfs_csum_final(*crc, (char *)crc);
-               crc++;
                bytes += PAGE_CACHE_SIZE;
 
                list_del_init(&entry->list);
@@ -796,7 +762,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
                                     i_size_read(inode) - 1, &cached_state,
                                     GFP_NOFS);
                ret = 0;
-               goto out_free;
+               goto out;
        }
 
        /* Zero out the rest of the pages just to make sure */
@@ -811,20 +777,6 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
                index++;
        }
 
-       /* Write the checksums and trans id to the first page */
-       {
-               void *addr;
-               u64 *gen;
-
-               page = pages[0];
-
-               addr = kmap(page);
-               memcpy(addr, checksums, sizeof(u32) * num_pages);
-               gen = addr + (sizeof(u32) * num_pages);
-               *gen = trans->transid;
-               kunmap(page);
-       }
-
        ret = btrfs_dirty_pages(root, inode, pages, num_pages, 0,
                                            bytes, &cached_state);
        btrfs_drop_pages(pages, num_pages);
@@ -833,7 +785,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
 
        if (ret) {
                ret = 0;
-               goto out_free;
+               goto out;
        }
 
        BTRFS_I(inode)->generation = trans->transid;
@@ -850,7 +802,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
                clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, bytes - 1,
                                 EXTENT_DIRTY | EXTENT_DELALLOC |
                                 EXTENT_DO_ACCOUNTING, 0, 0, NULL, GFP_NOFS);
-               goto out_free;
+               goto out;
        }
        leaf = path->nodes[0];
        if (ret > 0) {
@@ -866,7 +818,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
                                         EXTENT_DO_ACCOUNTING, 0, 0, NULL,
                                         GFP_NOFS);
                        btrfs_release_path(path);
-                       goto out_free;
+                       goto out;
                }
        }
        header = btrfs_item_ptr(leaf, path->slots[0],
@@ -879,11 +831,8 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
 
        ret = 1;
 
-out_free:
-       kfree(checksums);
+out:
        kfree(pages);
-
-out_update:
        if (ret != 1) {
                invalidate_inode_pages2_range(inode->i_mapping, 0, index);
                BTRFS_I(inode)->generation = 0;
index caa26ab5ed6833094a3334ed388edca18d2fd15a..13e6255182e3dad59af5463537dbc21abdff4bef 100644 (file)
@@ -750,15 +750,6 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
        return alloc_hint;
 }
 
-static inline bool is_free_space_inode(struct btrfs_root *root,
-                                      struct inode *inode)
-{
-       if (root == root->fs_info->tree_root ||
-           BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID)
-               return true;
-       return false;
-}
-
 /*
  * when extent_io.c finds a delayed allocation range in the file,
  * the call backs end up in this code.  The basic idea is to
@@ -791,7 +782,7 @@ static noinline int cow_file_range(struct inode *inode,
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        int ret = 0;
 
-       BUG_ON(is_free_space_inode(root, inode));
+       BUG_ON(btrfs_is_free_space_inode(root, inode));
        trans = btrfs_join_transaction(root);
        BUG_ON(IS_ERR(trans));
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
@@ -1072,7 +1063,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
        path = btrfs_alloc_path();
        BUG_ON(!path);
 
-       nolock = is_free_space_inode(root, inode);
+       nolock = btrfs_is_free_space_inode(root, inode);
 
        if (nolock)
                trans = btrfs_join_transaction_nolock(root);
@@ -1298,7 +1289,9 @@ static int btrfs_split_extent_hook(struct inode *inode,
        if (!(orig->state & EXTENT_DELALLOC))
                return 0;
 
-       atomic_inc(&BTRFS_I(inode)->outstanding_extents);
+       spin_lock(&BTRFS_I(inode)->lock);
+       BTRFS_I(inode)->outstanding_extents++;
+       spin_unlock(&BTRFS_I(inode)->lock);
        return 0;
 }
 
@@ -1316,7 +1309,9 @@ static int btrfs_merge_extent_hook(struct inode *inode,
        if (!(other->state & EXTENT_DELALLOC))
                return 0;
 
-       atomic_dec(&BTRFS_I(inode)->outstanding_extents);
+       spin_lock(&BTRFS_I(inode)->lock);
+       BTRFS_I(inode)->outstanding_extents--;
+       spin_unlock(&BTRFS_I(inode)->lock);
        return 0;
 }
 
@@ -1337,12 +1332,15 @@ static int btrfs_set_bit_hook(struct inode *inode,
        if (!(state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
                u64 len = state->end + 1 - state->start;
-               bool do_list = !is_free_space_inode(root, inode);
+               bool do_list = !btrfs_is_free_space_inode(root, inode);
 
-               if (*bits & EXTENT_FIRST_DELALLOC)
+               if (*bits & EXTENT_FIRST_DELALLOC) {
                        *bits &= ~EXTENT_FIRST_DELALLOC;
-               else
-                       atomic_inc(&BTRFS_I(inode)->outstanding_extents);
+               } else {
+                       spin_lock(&BTRFS_I(inode)->lock);
+                       BTRFS_I(inode)->outstanding_extents++;
+                       spin_unlock(&BTRFS_I(inode)->lock);
+               }
 
                spin_lock(&root->fs_info->delalloc_lock);
                BTRFS_I(inode)->delalloc_bytes += len;
@@ -1370,12 +1368,15 @@ static int btrfs_clear_bit_hook(struct inode *inode,
        if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
                u64 len = state->end + 1 - state->start;
-               bool do_list = !is_free_space_inode(root, inode);
+               bool do_list = !btrfs_is_free_space_inode(root, inode);
 
-               if (*bits & EXTENT_FIRST_DELALLOC)
+               if (*bits & EXTENT_FIRST_DELALLOC) {
                        *bits &= ~EXTENT_FIRST_DELALLOC;
-               else if (!(*bits & EXTENT_DO_ACCOUNTING))
-                       atomic_dec(&BTRFS_I(inode)->outstanding_extents);
+               } else if (!(*bits & EXTENT_DO_ACCOUNTING)) {
+                       spin_lock(&BTRFS_I(inode)->lock);
+                       BTRFS_I(inode)->outstanding_extents--;
+                       spin_unlock(&BTRFS_I(inode)->lock);
+               }
 
                if (*bits & EXTENT_DO_ACCOUNTING)
                        btrfs_delalloc_release_metadata(inode, len);
@@ -1477,7 +1478,7 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
 
        skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
 
-       if (is_free_space_inode(root, inode))
+       if (btrfs_is_free_space_inode(root, inode))
                ret = btrfs_bio_wq_end_io(root->fs_info, bio, 2);
        else
                ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
@@ -1726,7 +1727,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
                return 0;
        BUG_ON(!ordered_extent);
 
-       nolock = is_free_space_inode(root, inode);
+       nolock = btrfs_is_free_space_inode(root, inode);
 
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
                BUG_ON(!list_empty(&ordered_extent->list));
@@ -2531,13 +2532,6 @@ static void btrfs_read_locked_inode(struct inode *inode)
 
        inode_item = btrfs_item_ptr(leaf, path->slots[0],
                                    struct btrfs_inode_item);
-       if (!leaf->map_token)
-               map_private_extent_buffer(leaf, (unsigned long)inode_item,
-                                         sizeof(struct btrfs_inode_item),
-                                         &leaf->map_token, &leaf->kaddr,
-                                         &leaf->map_start, &leaf->map_len,
-                                         KM_USER1);
-
        inode->i_mode = btrfs_inode_mode(leaf, inode_item);
        inode->i_nlink = btrfs_inode_nlink(leaf, inode_item);
        inode->i_uid = btrfs_inode_uid(leaf, inode_item);
@@ -2575,11 +2569,6 @@ cache_acl:
        if (!maybe_acls)
                cache_no_acl(inode);
 
-       if (leaf->map_token) {
-               unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
-               leaf->map_token = NULL;
-       }
-
        btrfs_free_path(path);
 
        switch (inode->i_mode & S_IFMT) {
@@ -2624,13 +2613,6 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
                            struct btrfs_inode_item *item,
                            struct inode *inode)
 {
-       if (!leaf->map_token)
-               map_private_extent_buffer(leaf, (unsigned long)item,
-                                         sizeof(struct btrfs_inode_item),
-                                         &leaf->map_token, &leaf->kaddr,
-                                         &leaf->map_start, &leaf->map_len,
-                                         KM_USER1);
-
        btrfs_set_inode_uid(leaf, item, inode->i_uid);
        btrfs_set_inode_gid(leaf, item, inode->i_gid);
        btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size);
@@ -2659,11 +2641,6 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
        btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
        btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
        btrfs_set_inode_block_group(leaf, item, 0);
-
-       if (leaf->map_token) {
-               unmap_extent_buffer(leaf, leaf->map_token, KM_USER1);
-               leaf->map_token = NULL;
-       }
 }
 
 /*
@@ -2684,7 +2661,7 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
         * The data relocation inode should also be directly updated
         * without delay
         */
-       if (!is_free_space_inode(root, inode)
+       if (!btrfs_is_free_space_inode(root, inode)
            && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) {
                ret = btrfs_delayed_update_inode(trans, root, inode);
                if (!ret)
@@ -3398,7 +3375,7 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
 
        ret = -ENOMEM;
 again:
-       page = grab_cache_page(mapping, index);
+       page = find_or_create_page(mapping, index, GFP_NOFS);
        if (!page) {
                btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
                goto out;
@@ -3634,7 +3611,7 @@ void btrfs_evict_inode(struct inode *inode)
 
        truncate_inode_pages(&inode->i_data, 0);
        if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 ||
-                              is_free_space_inode(root, inode)))
+                              btrfs_is_free_space_inode(root, inode)))
                goto no_delete;
 
        if (is_bad_inode(inode)) {
@@ -4271,7 +4248,7 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
        if (BTRFS_I(inode)->dummy_inode)
                return 0;
 
-       if (btrfs_fs_closing(root->fs_info) && is_free_space_inode(root, inode))
+       if (btrfs_fs_closing(root->fs_info) && btrfs_is_free_space_inode(root, inode))
                nolock = true;
 
        if (wbc->sync_mode == WB_SYNC_ALL) {
@@ -6728,8 +6705,9 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        ei->index_cnt = (u64)-1;
        ei->last_unlink_trans = 0;
 
-       atomic_set(&ei->outstanding_extents, 0);
-       atomic_set(&ei->reserved_extents, 0);
+       spin_lock_init(&ei->lock);
+       ei->outstanding_extents = 0;
+       ei->reserved_extents = 0;
 
        ei->ordered_data_close = 0;
        ei->orphan_meta_reserved = 0;
@@ -6767,8 +6745,8 @@ void btrfs_destroy_inode(struct inode *inode)
 
        WARN_ON(!list_empty(&inode->i_dentry));
        WARN_ON(inode->i_data.nrpages);
-       WARN_ON(atomic_read(&BTRFS_I(inode)->outstanding_extents));
-       WARN_ON(atomic_read(&BTRFS_I(inode)->reserved_extents));
+       WARN_ON(BTRFS_I(inode)->outstanding_extents);
+       WARN_ON(BTRFS_I(inode)->reserved_extents);
 
        /*
         * This can happen where we create an inode, but somebody else also
@@ -6823,7 +6801,7 @@ int btrfs_drop_inode(struct inode *inode)
        struct btrfs_root *root = BTRFS_I(inode)->root;
 
        if (btrfs_root_refs(&root->root_item) == 0 &&
-           !is_free_space_inode(root, inode))
+           !btrfs_is_free_space_inode(root, inode))
                return 1;
        else
                return generic_drop_inode(inode);
index 622543309eb25e86fb39308ce077b84b4a883c70..0b980afc5eddfd4aeec80162e2eebecadd4015de 100644 (file)
@@ -859,8 +859,8 @@ again:
        /* step one, lock all the pages */
        for (i = 0; i < num_pages; i++) {
                struct page *page;
-               page = grab_cache_page(inode->i_mapping,
-                                           start_index + i);
+               page = find_or_create_page(inode->i_mapping,
+                                           start_index + i, GFP_NOFS);
                if (!page)
                        break;
 
@@ -930,7 +930,9 @@ again:
                          GFP_NOFS);
 
        if (i_done != num_pages) {
-               atomic_inc(&BTRFS_I(inode)->outstanding_extents);
+               spin_lock(&BTRFS_I(inode)->lock);
+               BTRFS_I(inode)->outstanding_extents++;
+               spin_unlock(&BTRFS_I(inode)->lock);
                btrfs_delalloc_release_space(inode,
                                     (num_pages - i_done) << PAGE_CACHE_SHIFT);
        }
index 66fa43dc3f0f9ff8b5c67e5330120fd663bf4054..d77b67c4b275731417c11e04ad38b3dc9c4d456b 100644 (file)
 #include "extent_io.h"
 #include "locking.h"
 
-static inline void spin_nested(struct extent_buffer *eb)
-{
-       spin_lock(&eb->lock);
-}
+void btrfs_assert_tree_read_locked(struct extent_buffer *eb);
 
 /*
- * Setting a lock to blocking will drop the spinlock and set the
- * flag that forces other procs who want the lock to wait.  After
- * this you can safely schedule with the lock held.
+ * if we currently have a spinning reader or writer lock
+ * (indicated by the rw flag) this will bump the count
+ * of blocking holders and drop the spinlock.
  */
-void btrfs_set_lock_blocking(struct extent_buffer *eb)
+void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw)
 {
-       if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) {
-               set_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags);
-               spin_unlock(&eb->lock);
+       if (rw == BTRFS_WRITE_LOCK) {
+               if (atomic_read(&eb->blocking_writers) == 0) {
+                       WARN_ON(atomic_read(&eb->spinning_writers) != 1);
+                       atomic_dec(&eb->spinning_writers);
+                       btrfs_assert_tree_locked(eb);
+                       atomic_inc(&eb->blocking_writers);
+                       write_unlock(&eb->lock);
+               }
+       } else if (rw == BTRFS_READ_LOCK) {
+               btrfs_assert_tree_read_locked(eb);
+               atomic_inc(&eb->blocking_readers);
+               WARN_ON(atomic_read(&eb->spinning_readers) == 0);
+               atomic_dec(&eb->spinning_readers);
+               read_unlock(&eb->lock);
        }
-       /* exit with the spin lock released and the bit set */
+       return;
 }
 
 /*
- * clearing the blocking flag will take the spinlock again.
- * After this you can't safely schedule
+ * if we currently have a blocking lock, take the spinlock
+ * and drop our blocking count
  */
-void btrfs_clear_lock_blocking(struct extent_buffer *eb)
+void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw)
 {
-       if (test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags)) {
-               spin_nested(eb);
-               clear_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags);
-               smp_mb__after_clear_bit();
+       if (rw == BTRFS_WRITE_LOCK_BLOCKING) {
+               BUG_ON(atomic_read(&eb->blocking_writers) != 1);
+               write_lock(&eb->lock);
+               WARN_ON(atomic_read(&eb->spinning_writers));
+               atomic_inc(&eb->spinning_writers);
+               if (atomic_dec_and_test(&eb->blocking_writers))
+                       wake_up(&eb->write_lock_wq);
+       } else if (rw == BTRFS_READ_LOCK_BLOCKING) {
+               BUG_ON(atomic_read(&eb->blocking_readers) == 0);
+               read_lock(&eb->lock);
+               atomic_inc(&eb->spinning_readers);
+               if (atomic_dec_and_test(&eb->blocking_readers))
+                       wake_up(&eb->read_lock_wq);
        }
-       /* exit with the spin lock held */
+       return;
 }
 
 /*
- * unfortunately, many of the places that currently set a lock to blocking
- * don't end up blocking for very long, and often they don't block
- * at all.  For a dbench 50 run, if we don't spin on the blocking bit
- * at all, the context switch rate can jump up to 400,000/sec or more.
- *
- * So, we're still stuck with this crummy spin on the blocking bit,
- * at least until the most common causes of the short blocks
- * can be dealt with.
+ * take a spinning read lock.  This will wait for any blocking
+ * writers
  */
-static int btrfs_spin_on_block(struct extent_buffer *eb)
+void btrfs_tree_read_lock(struct extent_buffer *eb)
 {
-       int i;
-
-       for (i = 0; i < 512; i++) {
-               if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
-                       return 1;
-               if (need_resched())
-                       break;
-               cpu_relax();
+again:
+       wait_event(eb->write_lock_wq, atomic_read(&eb->blocking_writers) == 0);
+       read_lock(&eb->lock);
+       if (atomic_read(&eb->blocking_writers)) {
+               read_unlock(&eb->lock);
+               wait_event(eb->write_lock_wq,
+                          atomic_read(&eb->blocking_writers) == 0);
+               goto again;
        }
-       return 0;
+       atomic_inc(&eb->read_locks);
+       atomic_inc(&eb->spinning_readers);
 }
 
 /*
- * This is somewhat different from trylock.  It will take the
- * spinlock but if it finds the lock is set to blocking, it will
- * return without the lock held.
- *
- * returns 1 if it was able to take the lock and zero otherwise
- *
- * After this call, scheduling is not safe without first calling
- * btrfs_set_lock_blocking()
+ * returns 1 if we get the read lock and 0 if we don't
+ * this won't wait for blocking writers
  */
-int btrfs_try_spin_lock(struct extent_buffer *eb)
+int btrfs_try_tree_read_lock(struct extent_buffer *eb)
 {
-       int i;
+       if (atomic_read(&eb->blocking_writers))
+               return 0;
 
-       if (btrfs_spin_on_block(eb)) {
-               spin_nested(eb);
-               if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
-                       return 1;
-               spin_unlock(&eb->lock);
+       read_lock(&eb->lock);
+       if (atomic_read(&eb->blocking_writers)) {
+               read_unlock(&eb->lock);
+               return 0;
        }
-       /* spin for a bit on the BLOCKING flag */
-       for (i = 0; i < 2; i++) {
-               cpu_relax();
-               if (!btrfs_spin_on_block(eb))
-                       break;
-
-               spin_nested(eb);
-               if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
-                       return 1;
-               spin_unlock(&eb->lock);
-       }
-       return 0;
+       atomic_inc(&eb->read_locks);
+       atomic_inc(&eb->spinning_readers);
+       return 1;
 }
 
 /*
- * the autoremove wake function will return 0 if it tried to wake up
- * a process that was already awake, which means that process won't
- * count as an exclusive wakeup.  The waitq code will continue waking
- * procs until it finds one that was actually sleeping.
- *
- * For btrfs, this isn't quite what we want.  We want a single proc
- * to be notified that the lock is ready for taking.  If that proc
- * already happen to be awake, great, it will loop around and try for
- * the lock.
- *
- * So, btrfs_wake_function always returns 1, even when the proc that we
- * tried to wake up was already awake.
+ * returns 1 if we get the read lock and 0 if we don't
+ * this won't wait for blocking writers or readers
  */
-static int btrfs_wake_function(wait_queue_t *wait, unsigned mode,
-                              int sync, void *key)
+int btrfs_try_tree_write_lock(struct extent_buffer *eb)
 {
-       autoremove_wake_function(wait, mode, sync, key);
+       if (atomic_read(&eb->blocking_writers) ||
+           atomic_read(&eb->blocking_readers))
+               return 0;
+       write_lock(&eb->lock);
+       if (atomic_read(&eb->blocking_writers) ||
+           atomic_read(&eb->blocking_readers)) {
+               write_unlock(&eb->lock);
+               return 0;
+       }
+       atomic_inc(&eb->write_locks);
+       atomic_inc(&eb->spinning_writers);
        return 1;
 }
 
 /*
- * returns with the extent buffer spinlocked.
- *
- * This will spin and/or wait as required to take the lock, and then
- * return with the spinlock held.
- *
- * After this call, scheduling is not safe without first calling
- * btrfs_set_lock_blocking()
+ * drop a spinning read lock
+ */
+void btrfs_tree_read_unlock(struct extent_buffer *eb)
+{
+       btrfs_assert_tree_read_locked(eb);
+       WARN_ON(atomic_read(&eb->spinning_readers) == 0);
+       atomic_dec(&eb->spinning_readers);
+       atomic_dec(&eb->read_locks);
+       read_unlock(&eb->lock);
+}
+
+/*
+ * drop a blocking read lock
+ */
+void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb)
+{
+       btrfs_assert_tree_read_locked(eb);
+       WARN_ON(atomic_read(&eb->blocking_readers) == 0);
+       if (atomic_dec_and_test(&eb->blocking_readers))
+               wake_up(&eb->read_lock_wq);
+       atomic_dec(&eb->read_locks);
+}
+
+/*
+ * take a spinning write lock.  This will wait for both
+ * blocking readers or writers
  */
 int btrfs_tree_lock(struct extent_buffer *eb)
 {
-       DEFINE_WAIT(wait);
-       wait.func = btrfs_wake_function;
-
-       if (!btrfs_spin_on_block(eb))
-               goto sleep;
-
-       while(1) {
-               spin_nested(eb);
-
-               /* nobody is blocking, exit with the spinlock held */
-               if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
-                       return 0;
-
-               /*
-                * we have the spinlock, but the real owner is blocking.
-                * wait for them
-                */
-               spin_unlock(&eb->lock);
-
-               /*
-                * spin for a bit, and if the blocking flag goes away,
-                * loop around
-                */
-               cpu_relax();
-               if (btrfs_spin_on_block(eb))
-                       continue;
-sleep:
-               prepare_to_wait_exclusive(&eb->lock_wq, &wait,
-                                         TASK_UNINTERRUPTIBLE);
-
-               if (test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
-                       schedule();
-
-               finish_wait(&eb->lock_wq, &wait);
+again:
+       wait_event(eb->read_lock_wq, atomic_read(&eb->blocking_readers) == 0);
+       wait_event(eb->write_lock_wq, atomic_read(&eb->blocking_writers) == 0);
+       write_lock(&eb->lock);
+       if (atomic_read(&eb->blocking_readers)) {
+               write_unlock(&eb->lock);
+               wait_event(eb->read_lock_wq,
+                          atomic_read(&eb->blocking_readers) == 0);
+               goto again;
        }
+       if (atomic_read(&eb->blocking_writers)) {
+               write_unlock(&eb->lock);
+               wait_event(eb->write_lock_wq,
+                          atomic_read(&eb->blocking_writers) == 0);
+               goto again;
+       }
+       WARN_ON(atomic_read(&eb->spinning_writers));
+       atomic_inc(&eb->spinning_writers);
+       atomic_inc(&eb->write_locks);
        return 0;
 }
 
+/*
+ * drop a spinning or a blocking write lock.
+ */
 int btrfs_tree_unlock(struct extent_buffer *eb)
 {
-       /*
-        * if we were a blocking owner, we don't have the spinlock held
-        * just clear the bit and look for waiters
-        */
-       if (test_and_clear_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
-               smp_mb__after_clear_bit();
-       else
-               spin_unlock(&eb->lock);
-
-       if (waitqueue_active(&eb->lock_wq))
-               wake_up(&eb->lock_wq);
+       int blockers = atomic_read(&eb->blocking_writers);
+
+       BUG_ON(blockers > 1);
+
+       btrfs_assert_tree_locked(eb);
+       atomic_dec(&eb->write_locks);
+
+       if (blockers) {
+               WARN_ON(atomic_read(&eb->spinning_writers));
+               atomic_dec(&eb->blocking_writers);
+               smp_wmb();
+               wake_up(&eb->write_lock_wq);
+       } else {
+               WARN_ON(atomic_read(&eb->spinning_writers) != 1);
+               atomic_dec(&eb->spinning_writers);
+               write_unlock(&eb->lock);
+       }
        return 0;
 }
 
 void btrfs_assert_tree_locked(struct extent_buffer *eb)
 {
-       if (!test_bit(EXTENT_BUFFER_BLOCKING, &eb->bflags))
-               assert_spin_locked(&eb->lock);
+       BUG_ON(!atomic_read(&eb->write_locks));
+}
+
+void btrfs_assert_tree_read_locked(struct extent_buffer *eb)
+{
+       BUG_ON(!atomic_read(&eb->read_locks));
 }
index 5c33a560a2f100c2454797d122875a76921403ab..17247ddb81a00f80e2e3e0a82c5c87e36cc564d1 100644 (file)
 #ifndef __BTRFS_LOCKING_
 #define __BTRFS_LOCKING_
 
+#define BTRFS_WRITE_LOCK 1
+#define BTRFS_READ_LOCK 2
+#define BTRFS_WRITE_LOCK_BLOCKING 3
+#define BTRFS_READ_LOCK_BLOCKING 4
+
 int btrfs_tree_lock(struct extent_buffer *eb);
 int btrfs_tree_unlock(struct extent_buffer *eb);
 int btrfs_try_spin_lock(struct extent_buffer *eb);
 
-void btrfs_set_lock_blocking(struct extent_buffer *eb);
-void btrfs_clear_lock_blocking(struct extent_buffer *eb);
+void btrfs_tree_read_lock(struct extent_buffer *eb);
+void btrfs_tree_read_unlock(struct extent_buffer *eb);
+void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb);
+void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw);
+void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw);
 void btrfs_assert_tree_locked(struct extent_buffer *eb);
+int btrfs_try_tree_read_lock(struct extent_buffer *eb);
+int btrfs_try_tree_write_lock(struct extent_buffer *eb);
+
+static inline void btrfs_tree_unlock_rw(struct extent_buffer *eb, int rw)
+{
+       if (rw == BTRFS_WRITE_LOCK || rw == BTRFS_WRITE_LOCK_BLOCKING)
+               btrfs_tree_unlock(eb);
+       else if (rw == BTRFS_READ_LOCK_BLOCKING)
+               btrfs_tree_read_unlock_blocking(eb);
+       else if (rw == BTRFS_READ_LOCK)
+               btrfs_tree_read_unlock(eb);
+       else
+               BUG();
+}
+
+static inline void btrfs_set_lock_blocking(struct extent_buffer *eb)
+{
+       btrfs_set_lock_blocking_rw(eb, BTRFS_WRITE_LOCK);
+}
+
+static inline void btrfs_clear_lock_blocking(struct extent_buffer *eb)
+{
+       btrfs_clear_lock_blocking_rw(eb, BTRFS_WRITE_LOCK_BLOCKING);
+}
 #endif
index 5e0a3dc79a453f3930e9c749c1cf08c63e5c7c6a..59bb1764273d476b7efe01a8d0948f4f473de6f2 100644 (file)
@@ -2955,7 +2955,8 @@ static int relocate_file_extent_cluster(struct inode *inode,
                        page_cache_sync_readahead(inode->i_mapping,
                                                  ra, NULL, index,
                                                  last_index + 1 - index);
-                       page = grab_cache_page(inode->i_mapping, index);
+                       page = find_or_create_page(inode->i_mapping, index,
+                                                  GFP_NOFS);
                        if (!page) {
                                btrfs_delalloc_release_metadata(inode,
                                                        PAGE_CACHE_SIZE);
index c0f7ecaf1e79a931bbb2be480c97c3d848ec4654..bc1f6ad18442bc728a10e9919b91162af1b60b4d 100644 (file)
@@ -50,36 +50,22 @@ u##bits btrfs_##name(struct extent_buffer *eb,                              \
        unsigned long part_offset = (unsigned long)s;                   \
        unsigned long offset = part_offset + offsetof(type, member);    \
        type *p;                                                        \
-       /* ugly, but we want the fast path here */                      \
-       if (eb->map_token && offset >= eb->map_start &&                 \
-           offset + sizeof(((type *)0)->member) <= eb->map_start +     \
-           eb->map_len) {                                              \
-               p = (type *)(eb->kaddr + part_offset - eb->map_start);  \
-               return le##bits##_to_cpu(p->member);                    \
-       }                                                               \
-       {                                                               \
-               int err;                                                \
-               char *map_token;                                        \
-               char *kaddr;                                            \
-               int unmap_on_exit = (eb->map_token == NULL);            \
-               unsigned long map_start;                                \
-               unsigned long map_len;                                  \
-               u##bits res;                                            \
-               err = map_extent_buffer(eb, offset,                     \
-                               sizeof(((type *)0)->member),            \
-                               &map_token, &kaddr,                     \
-                               &map_start, &map_len, KM_USER1);        \
-               if (err) {                                              \
-                       __le##bits leres;                               \
-                       read_eb_member(eb, s, type, member, &leres);    \
-                       return le##bits##_to_cpu(leres);                \
-               }                                                       \
-               p = (type *)(kaddr + part_offset - map_start);          \
-               res = le##bits##_to_cpu(p->member);                     \
-               if (unmap_on_exit)                                      \
-                       unmap_extent_buffer(eb, map_token, KM_USER1);   \
-               return res;                                             \
-       }                                                               \
+       int err;                                                \
+       char *kaddr;                                            \
+       unsigned long map_start;                                \
+       unsigned long map_len;                                  \
+       u##bits res;                                            \
+       err = map_private_extent_buffer(eb, offset,             \
+                       sizeof(((type *)0)->member),            \
+                       &kaddr, &map_start, &map_len);          \
+       if (err) {                                              \
+               __le##bits leres;                               \
+               read_eb_member(eb, s, type, member, &leres);    \
+               return le##bits##_to_cpu(leres);                \
+       }                                                       \
+       p = (type *)(kaddr + part_offset - map_start);          \
+       res = le##bits##_to_cpu(p->member);                     \
+       return res;                                             \
 }                                                                      \
 void btrfs_set_##name(struct extent_buffer *eb,                                \
                                    type *s, u##bits val)               \
@@ -87,36 +73,21 @@ void btrfs_set_##name(struct extent_buffer *eb,                             \
        unsigned long part_offset = (unsigned long)s;                   \
        unsigned long offset = part_offset + offsetof(type, member);    \
        type *p;                                                        \
-       /* ugly, but we want the fast path here */                      \
-       if (eb->map_token && offset >= eb->map_start &&                 \
-           offset + sizeof(((type *)0)->member) <= eb->map_start +     \
-           eb->map_len) {                                              \
-               p = (type *)(eb->kaddr + part_offset - eb->map_start);  \
-               p->member = cpu_to_le##bits(val);                       \
-               return;                                                 \
-       }                                                               \
-       {                                                               \
-               int err;                                                \
-               char *map_token;                                        \
-               char *kaddr;                                            \
-               int unmap_on_exit = (eb->map_token == NULL);            \
-               unsigned long map_start;                                \
-               unsigned long map_len;                                  \
-               err = map_extent_buffer(eb, offset,                     \
-                               sizeof(((type *)0)->member),            \
-                               &map_token, &kaddr,                     \
-                               &map_start, &map_len, KM_USER1);        \
-               if (err) {                                              \
-                       __le##bits val2;                                \
-                       val2 = cpu_to_le##bits(val);                    \
-                       write_eb_member(eb, s, type, member, &val2);    \
-                       return;                                         \
-               }                                                       \
-               p = (type *)(kaddr + part_offset - map_start);          \
-               p->member = cpu_to_le##bits(val);                       \
-               if (unmap_on_exit)                                      \
-                       unmap_extent_buffer(eb, map_token, KM_USER1);   \
-       }                                                               \
+       int err;                                                \
+       char *kaddr;                                            \
+       unsigned long map_start;                                \
+       unsigned long map_len;                                  \
+       err = map_private_extent_buffer(eb, offset,             \
+                       sizeof(((type *)0)->member),            \
+                       &kaddr, &map_start, &map_len);          \
+       if (err) {                                              \
+               __le##bits val2;                                \
+               val2 = cpu_to_le##bits(val);                    \
+               write_eb_member(eb, s, type, member, &val2);    \
+               return;                                         \
+       }                                                       \
+       p = (type *)(kaddr + part_offset - map_start);          \
+       p->member = cpu_to_le##bits(val);                       \
 }
 
 #include "ctree.h"
@@ -125,15 +96,6 @@ void btrfs_node_key(struct extent_buffer *eb,
                    struct btrfs_disk_key *disk_key, int nr)
 {
        unsigned long ptr = btrfs_node_key_ptr_offset(nr);
-       if (eb->map_token && ptr >= eb->map_start &&
-           ptr + sizeof(*disk_key) <= eb->map_start + eb->map_len) {
-               memcpy(disk_key, eb->kaddr + ptr - eb->map_start,
-                       sizeof(*disk_key));
-               return;
-       } else if (eb->map_token) {
-               unmap_extent_buffer(eb, eb->map_token, KM_USER1);
-               eb->map_token = NULL;
-       }
        read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
                       struct btrfs_key_ptr, key, disk_key);
 }
index 51dcec86757f071654bc3866123e65157ef0286b..eb55863bb4aee8a323783aa24536d17ec166f26d 100644 (file)
@@ -260,7 +260,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
 {
        struct btrfs_trans_handle *h;
        struct btrfs_transaction *cur_trans;
-       int retries = 0;
+       u64 num_bytes = 0;
        int ret;
 
        if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
@@ -274,6 +274,19 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
                h->block_rsv = NULL;
                goto got_it;
        }
+
+       /*
+        * Do the reservation before we join the transaction so we can do all
+        * the appropriate flushing if need be.
+        */
+       if (num_items > 0 && root != root->fs_info->chunk_root) {
+               num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
+               ret = btrfs_block_rsv_add(NULL, root,
+                                         &root->fs_info->trans_block_rsv,
+                                         num_bytes);
+               if (ret)
+                       return ERR_PTR(ret);
+       }
 again:
        h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
        if (!h)
@@ -310,24 +323,9 @@ again:
                goto again;
        }
 
-       if (num_items > 0) {
-               ret = btrfs_trans_reserve_metadata(h, root, num_items);
-               if (ret == -EAGAIN && !retries) {
-                       retries++;
-                       btrfs_commit_transaction(h, root);
-                       goto again;
-               } else if (ret == -EAGAIN) {
-                       /*
-                        * We have already retried and got EAGAIN, so really we
-                        * don't have space, so set ret to -ENOSPC.
-                        */
-                       ret = -ENOSPC;
-               }
-
-               if (ret < 0) {
-                       btrfs_end_transaction(h, root);
-                       return ERR_PTR(ret);
-               }
+       if (num_bytes) {
+               h->block_rsv = &root->fs_info->trans_block_rsv;
+               h->bytes_reserved = num_bytes;
        }
 
 got_it:
@@ -499,10 +497,17 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
        }
 
        if (lock && cur_trans->blocked && !cur_trans->in_commit) {
-               if (throttle)
+               if (throttle) {
+                       /*
+                        * We may race with somebody else here so end up having
+                        * to call end_transaction on ourselves again, so inc
+                        * our use_count.
+                        */
+                       trans->use_count++;
                        return btrfs_commit_transaction(trans, root);
-               else
+               } else {
                        wake_up_process(info->transaction_kthread);
+               }
        }
 
        WARN_ON(cur_trans != info->running_transaction);
index 4ce8a9f41d1ec3916753bd610183a82b4dc6aa21..ac278dd83175e3a64a573f9a16e154a21226ecda 100644 (file)
@@ -1730,8 +1730,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                                btrfs_read_buffer(next, ptr_gen);
 
                                btrfs_tree_lock(next);
-                               clean_tree_block(trans, root, next);
                                btrfs_set_lock_blocking(next);
+                               clean_tree_block(trans, root, next);
                                btrfs_wait_tree_block_writeback(next);
                                btrfs_tree_unlock(next);
 
@@ -1796,8 +1796,8 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
                                next = path->nodes[*level];
 
                                btrfs_tree_lock(next);
-                               clean_tree_block(trans, root, next);
                                btrfs_set_lock_blocking(next);
+                               clean_tree_block(trans, root, next);
                                btrfs_wait_tree_block_writeback(next);
                                btrfs_tree_unlock(next);
 
@@ -1864,8 +1864,8 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
                        next = path->nodes[orig_level];
 
                        btrfs_tree_lock(next);
-                       clean_tree_block(trans, log, next);
                        btrfs_set_lock_blocking(next);
+                       clean_tree_block(trans, log, next);
                        btrfs_wait_tree_block_writeback(next);
                        btrfs_tree_unlock(next);
 
index 19450bc536327c77f7add37e723b668da410eedd..b89e372c75449bf228f7ca6eb5904d5b00474b90 100644 (file)
@@ -3595,7 +3595,7 @@ int btrfs_read_sys_array(struct btrfs_root *root)
        if (!sb)
                return -ENOMEM;
        btrfs_set_buffer_uptodate(sb);
-       btrfs_set_buffer_lockdep_class(sb, 0);
+       btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0);
 
        write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE);
        array_size = btrfs_super_sys_array_size(super_copy);
index 5366fe452ab07db7402402e96351c1b956809e20..d733b9cfea343207e71bdb6d8d8b51323717c800 100644 (file)
@@ -102,43 +102,57 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
-       /* first lets see if we already have this xattr */
-       di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name,
-                               strlen(name), -1);
-       if (IS_ERR(di)) {
-               ret = PTR_ERR(di);
-               goto out;
-       }
-
-       /* ok we already have this xattr, lets remove it */
-       if (di) {
-               /* if we want create only exit */
-               if (flags & XATTR_CREATE) {
-                       ret = -EEXIST;
+       if (flags & XATTR_REPLACE) {
+               di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), name,
+                                       name_len, -1);
+               if (IS_ERR(di)) {
+                       ret = PTR_ERR(di);
+                       goto out;
+               } else if (!di) {
+                       ret = -ENODATA;
                        goto out;
                }
-
                ret = btrfs_delete_one_dir_name(trans, root, path, di);
-               BUG_ON(ret);
+               if (ret)
+                       goto out;
                btrfs_release_path(path);
+       }
 
-               /* if we don't have a value then we are removing the xattr */
-               if (!value)
+again:
+       ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode),
+                                     name, name_len, value, size);
+       if (ret == -EEXIST) {
+               if (flags & XATTR_CREATE)
                        goto out;
-       } else {
+               /*
+                * We can't use the path we already have since we won't have the
+                * proper locking for a delete, so release the path and
+                * re-lookup to delete the thing.
+                */
                btrfs_release_path(path);
+               di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode),
+                                       name, name_len, -1);
+               if (IS_ERR(di)) {
+                       ret = PTR_ERR(di);
+                       goto out;
+               } else if (!di) {
+                       /* Shouldn't happen but just in case... */
+                       btrfs_release_path(path);
+                       goto again;
+               }
 
-               if (flags & XATTR_REPLACE) {
-                       /* we couldn't find the attr to replace */
-                       ret = -ENODATA;
+               ret = btrfs_delete_one_dir_name(trans, root, path, di);
+               if (ret)
                        goto out;
+
+               /*
+                * We have a value to set, so go back and try to insert it now.
+                */
+               if (value) {
+                       btrfs_release_path(path);
+                       goto again;
                }
        }
-
-       /* ok we have to create a completely new xattr */
-       ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode),
-                                     name, name_len, value, size);
-       BUG_ON(ret);
 out:
        btrfs_free_path(path);
        return ret;
index 259991bd2112b4d40bd919d5d405b2440317831d..e76bfeb68267d19c5874eb85ddd12fac970a804e 100644 (file)
@@ -87,9 +87,15 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
        if ((cifs_pdu == NULL) || (server == NULL))
                return -EINVAL;
 
-       if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
+       if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
+           server->tcpStatus == CifsNeedNegotiate)
                return rc;
 
+       if (!server->session_estab) {
+               strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
+               return rc;
+       }
+
        cifs_pdu->Signature.Sequence.SequenceNumber =
                        cpu_to_le32(server->sequence_number);
        cifs_pdu->Signature.Sequence.Reserved = 0;
@@ -178,9 +184,15 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
        if ((cifs_pdu == NULL) || (server == NULL))
                return -EINVAL;
 
-       if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
+       if (!(cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) ||
+           server->tcpStatus == CifsNeedNegotiate)
                return rc;
 
+       if (!server->session_estab) {
+               strncpy(cifs_pdu->Signature.SecuritySignature, "BSRSPYL", 8);
+               return rc;
+       }
+
        cifs_pdu->Signature.Sequence.SequenceNumber =
                                cpu_to_le32(server->sequence_number);
        cifs_pdu->Signature.Sequence.Reserved = 0;
index 865517470967de7dd14a1ad782c32195424f51c0..212e5629cc1d01880263aaa6f0b12ef6a1a46291 100644 (file)
@@ -86,24 +86,6 @@ extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
 extern mempool_t *cifs_mid_poolp;
 
-void
-cifs_sb_active(struct super_block *sb)
-{
-       struct cifs_sb_info *server = CIFS_SB(sb);
-
-       if (atomic_inc_return(&server->active) == 1)
-               atomic_inc(&sb->s_active);
-}
-
-void
-cifs_sb_deactive(struct super_block *sb)
-{
-       struct cifs_sb_info *server = CIFS_SB(sb);
-
-       if (atomic_dec_and_test(&server->active))
-               deactivate_super(sb);
-}
-
 static int
 cifs_read_super(struct super_block *sb)
 {
index fbd050c8d52a53063319ff266568300788faf02f..cb71dc1f94d1e38dc042bf79e68614032553486a 100644 (file)
@@ -41,10 +41,6 @@ extern struct file_system_type cifs_fs_type;
 extern const struct address_space_operations cifs_addr_ops;
 extern const struct address_space_operations cifs_addr_ops_smallbuf;
 
-/* Functions related to super block operations */
-extern void cifs_sb_active(struct super_block *sb);
-extern void cifs_sb_deactive(struct super_block *sb);
-
 /* Functions related to inodes */
 extern const struct inode_operations cifs_dir_inode_ops;
 extern struct inode *cifs_root_iget(struct super_block *);
index 1fcf4e5b3112752c09180f7ec4e4e17b7693a742..38ce6d44b1451ef420bc7e233b1afac107b7b932 100644 (file)
@@ -942,8 +942,6 @@ GLOBAL_EXTERN spinlock_t siduidlock;
 GLOBAL_EXTERN spinlock_t sidgidlock;
 
 void cifs_oplock_break(struct work_struct *work);
-void cifs_oplock_break_get(struct cifsFileInfo *cfile);
-void cifs_oplock_break_put(struct cifsFileInfo *cfile);
 
 extern const struct slow_work_ops cifs_oplock_break_ops;
 
index 1a9fe7f816d1b83dd630141412d3dd109b23a385..aac37d99a487bfe9b40d1107ba67973bf212ed54 100644 (file)
@@ -107,7 +107,7 @@ static void mark_open_files_invalid(struct cifs_tcon *pTcon)
 static int
 cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
 {
-       int rc = 0;
+       int rc;
        struct cifs_ses *ses;
        struct TCP_Server_Info *server;
        struct nls_table *nls_codepage;
@@ -5720,6 +5720,7 @@ CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
        char *temp_ptr;
        char *end_of_smb;
        __u16 params, byte_count, data_offset;
+       unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
 
        cFYI(1, "In Query All EAs path %s", searchName);
 QAllEAsRetry:
@@ -5837,7 +5838,8 @@ QAllEAsRetry:
                }
 
                if (ea_name) {
-                       if (strncmp(ea_name, temp_ptr, name_len) == 0) {
+                       if (ea_name_len == name_len &&
+                           strncmp(ea_name, temp_ptr, name_len) == 0) {
                                temp_ptr += name_len + 1;
                                rc = value_len;
                                if (buf_size == 0)
index e66297bad41231af902c99d386f654130b289020..80c2e3add3a2714748336560b249b77e348c4278 100644 (file)
@@ -319,25 +319,328 @@ requeue_echo:
        queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
 }
 
+static bool
+allocate_buffers(char **bigbuf, char **smallbuf, unsigned int size,
+                bool is_large_buf)
+{
+       char *bbuf = *bigbuf, *sbuf = *smallbuf;
+
+       if (bbuf == NULL) {
+               bbuf = (char *)cifs_buf_get();
+               if (!bbuf) {
+                       cERROR(1, "No memory for large SMB response");
+                       msleep(3000);
+                       /* retry will check if exiting */
+                       return false;
+               }
+       } else if (is_large_buf) {
+               /* we are reusing a dirty large buf, clear its start */
+               memset(bbuf, 0, size);
+       }
+
+       if (sbuf == NULL) {
+               sbuf = (char *)cifs_small_buf_get();
+               if (!sbuf) {
+                       cERROR(1, "No memory for SMB response");
+                       msleep(1000);
+                       /* retry will check if exiting */
+                       return false;
+               }
+               /* beginning of smb buffer is cleared in our buf_get */
+       } else {
+               /* if existing small buf clear beginning */
+               memset(sbuf, 0, size);
+       }
+
+       *bigbuf = bbuf;
+       *smallbuf = sbuf;
+
+       return true;
+}
+
+static int
+read_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg,
+                struct kvec *iov, unsigned int to_read,
+                unsigned int *ptotal_read, bool is_header_read)
+{
+       int length, rc = 0;
+       unsigned int total_read;
+       char *buf = iov->iov_base;
+
+       for (total_read = 0; total_read < to_read; total_read += length) {
+               length = kernel_recvmsg(server->ssocket, smb_msg, iov, 1,
+                                       to_read - total_read, 0);
+               if (server->tcpStatus == CifsExiting) {
+                       /* then will exit */
+                       rc = 2;
+                       break;
+               } else if (server->tcpStatus == CifsNeedReconnect) {
+                       cifs_reconnect(server);
+                       /* Reconnect wakes up rspns q */
+                       /* Now we will reread sock */
+                       rc = 1;
+                       break;
+               } else if (length == -ERESTARTSYS ||
+                          length == -EAGAIN ||
+                          length == -EINTR) {
+                       /*
+                        * Minimum sleep to prevent looping, allowing socket
+                        * to clear and app threads to set tcpStatus
+                        * CifsNeedReconnect if server hung.
+                        */
+                       usleep_range(1000, 2000);
+                       length = 0;
+                       if (!is_header_read)
+                               continue;
+                       /* Special handling for header read */
+                       if (total_read) {
+                               iov->iov_base = (to_read - total_read) +
+                                               buf;
+                               iov->iov_len = to_read - total_read;
+                               smb_msg->msg_control = NULL;
+                               smb_msg->msg_controllen = 0;
+                               rc = 3;
+                       } else
+                               rc = 1;
+                       break;
+               } else if (length <= 0) {
+                       cERROR(1, "Received no data, expecting %d",
+                              to_read - total_read);
+                       cifs_reconnect(server);
+                       rc = 1;
+                       break;
+               }
+       }
+
+       *ptotal_read = total_read;
+       return rc;
+}
+
+static bool
+check_rfc1002_header(struct TCP_Server_Info *server, char *buf)
+{
+       char temp = *buf;
+       unsigned int pdu_length = be32_to_cpu(
+                               ((struct smb_hdr *)buf)->smb_buf_length);
+
+       /*
+        * The first byte big endian of the length field,
+        * is actually not part of the length but the type
+        * with the most common, zero, as regular data.
+        */
+       if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
+               return false;
+       } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
+               cFYI(1, "Good RFC 1002 session rsp");
+               return false;
+       } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
+               /*
+                * We get this from Windows 98 instead of an error on
+                * SMB negprot response.
+                */
+               cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
+                       pdu_length);
+               /* give server a second to clean up */
+               msleep(1000);
+               /*
+                * Always try 445 first on reconnect since we get NACK
+                * on some if we ever connected to port 139 (the NACK
+                * is since we do not begin with RFC1001 session
+                * initialize frame).
+                */
+               cifs_set_port((struct sockaddr *)
+                               &server->dstaddr, CIFS_PORT);
+               cifs_reconnect(server);
+               wake_up(&server->response_q);
+               return false;
+       } else if (temp != (char) 0) {
+               cERROR(1, "Unknown RFC 1002 frame");
+               cifs_dump_mem(" Received Data: ", buf, 4);
+               cifs_reconnect(server);
+               return false;
+       }
+
+       /* else we have an SMB response */
+       if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
+           (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
+               cERROR(1, "Invalid size SMB length %d pdu_length %d",
+                      4, pdu_length+4);
+               cifs_reconnect(server);
+               wake_up(&server->response_q);
+               return false;
+       }
+
+       return true;
+}
+
+static struct mid_q_entry *
+find_cifs_mid(struct TCP_Server_Info *server, struct smb_hdr *buf,
+             int *length, bool is_large_buf, bool *is_multi_rsp, char **bigbuf)
+{
+       struct mid_q_entry *mid = NULL, *tmp_mid, *ret = NULL;
+
+       spin_lock(&GlobalMid_Lock);
+       list_for_each_entry_safe(mid, tmp_mid, &server->pending_mid_q, qhead) {
+               if (mid->mid != buf->Mid ||
+                   mid->midState != MID_REQUEST_SUBMITTED ||
+                   mid->command != buf->Command)
+                       continue;
+
+               if (*length == 0 && check2ndT2(buf, server->maxBuf) > 0) {
+                       /* We have a multipart transact2 resp */
+                       *is_multi_rsp = true;
+                       if (mid->resp_buf) {
+                               /* merge response - fix up 1st*/
+                               *length = coalesce_t2(buf, mid->resp_buf);
+                               if (*length > 0) {
+                                       *length = 0;
+                                       mid->multiRsp = true;
+                                       break;
+                               }
+                               /* All parts received or packet is malformed. */
+                               mid->multiEnd = true;
+                               goto multi_t2_fnd;
+                       }
+                       if (!is_large_buf) {
+                               /*FIXME: switch to already allocated largebuf?*/
+                               cERROR(1, "1st trans2 resp needs bigbuf");
+                       } else {
+                               /* Have first buffer */
+                               mid->resp_buf = buf;
+                               mid->largeBuf = true;
+                               *bigbuf = NULL;
+                       }
+                       break;
+               }
+               mid->resp_buf = buf;
+               mid->largeBuf = is_large_buf;
+multi_t2_fnd:
+               if (*length == 0)
+                       mid->midState = MID_RESPONSE_RECEIVED;
+               else
+                       mid->midState = MID_RESPONSE_MALFORMED;
+#ifdef CONFIG_CIFS_STATS2
+               mid->when_received = jiffies;
+#endif
+               list_del_init(&mid->qhead);
+               ret = mid;
+               break;
+       }
+       spin_unlock(&GlobalMid_Lock);
+
+       return ret;
+}
+
+static void clean_demultiplex_info(struct TCP_Server_Info *server)
+{
+       int length;
+
+       /* take it off the list, if it's not already */
+       spin_lock(&cifs_tcp_ses_lock);
+       list_del_init(&server->tcp_ses_list);
+       spin_unlock(&cifs_tcp_ses_lock);
+
+       spin_lock(&GlobalMid_Lock);
+       server->tcpStatus = CifsExiting;
+       spin_unlock(&GlobalMid_Lock);
+       wake_up_all(&server->response_q);
+
+       /*
+        * Check if we have blocked requests that need to free. Note that
+        * cifs_max_pending is normally 50, but can be set at module install
+        * time to as little as two.
+        */
+       spin_lock(&GlobalMid_Lock);
+       if (atomic_read(&server->inFlight) >= cifs_max_pending)
+               atomic_set(&server->inFlight, cifs_max_pending - 1);
+       /*
+        * We do not want to set the max_pending too low or we could end up
+        * with the counter going negative.
+        */
+       spin_unlock(&GlobalMid_Lock);
+       /*
+        * Although there should not be any requests blocked on this queue it
+        * can not hurt to be paranoid and try to wake up requests that may
+        * haven been blocked when more than 50 at time were on the wire to the
+        * same server - they now will see the session is in exit state and get
+        * out of SendReceive.
+        */
+       wake_up_all(&server->request_q);
+       /* give those requests time to exit */
+       msleep(125);
+
+       if (server->ssocket) {
+               sock_release(server->ssocket);
+               server->ssocket = NULL;
+       }
+
+       if (!list_empty(&server->pending_mid_q)) {
+               struct list_head dispose_list;
+               struct mid_q_entry *mid_entry;
+               struct list_head *tmp, *tmp2;
+
+               INIT_LIST_HEAD(&dispose_list);
+               spin_lock(&GlobalMid_Lock);
+               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
+                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+                       cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
+                       mid_entry->midState = MID_SHUTDOWN;
+                       list_move(&mid_entry->qhead, &dispose_list);
+               }
+               spin_unlock(&GlobalMid_Lock);
+
+               /* now walk dispose list and issue callbacks */
+               list_for_each_safe(tmp, tmp2, &dispose_list) {
+                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+                       cFYI(1, "Callback mid 0x%x", mid_entry->mid);
+                       list_del_init(&mid_entry->qhead);
+                       mid_entry->callback(mid_entry);
+               }
+               /* 1/8th of sec is more than enough time for them to exit */
+               msleep(125);
+       }
+
+       if (!list_empty(&server->pending_mid_q)) {
+               /*
+                * mpx threads have not exited yet give them at least the smb
+                * send timeout time for long ops.
+                *
+                * Due to delays on oplock break requests, we need to wait at
+                * least 45 seconds before giving up on a request getting a
+                * response and going ahead and killing cifsd.
+                */
+               cFYI(1, "Wait for exit from demultiplex thread");
+               msleep(46000);
+               /*
+                * If threads still have not exited they are probably never
+                * coming home not much else we can do but free the memory.
+                */
+       }
+
+       kfree(server->hostname);
+       kfree(server);
+
+       length = atomic_dec_return(&tcpSesAllocCount);
+       if (length > 0)
+               mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
+                               GFP_KERNEL);
+}
+
 static int
 cifs_demultiplex_thread(void *p)
 {
        int length;
        struct TCP_Server_Info *server = p;
        unsigned int pdu_length, total_read;
+       char *buf = NULL, *bigbuf = NULL, *smallbuf = NULL;
        struct smb_hdr *smb_buffer = NULL;
-       struct smb_hdr *bigbuf = NULL;
-       struct smb_hdr *smallbuf = NULL;
        struct msghdr smb_msg;
        struct kvec iov;
-       struct socket *csocket = server->ssocket;
-       struct list_head *tmp, *tmp2;
        struct task_struct *task_to_wake = NULL;
        struct mid_q_entry *mid_entry;
-       char temp;
        bool isLargeBuf = false;
-       bool isMultiRsp;
-       int reconnect;
+       bool isMultiRsp = false;
+       int rc;
 
        current->flags |= PF_MEMALLOC;
        cFYI(1, "Demultiplex PID: %d", task_pid_nr(current));
@@ -351,35 +654,16 @@ cifs_demultiplex_thread(void *p)
        while (server->tcpStatus != CifsExiting) {
                if (try_to_freeze())
                        continue;
-               if (bigbuf == NULL) {
-                       bigbuf = cifs_buf_get();
-                       if (!bigbuf) {
-                               cERROR(1, "No memory for large SMB response");
-                               msleep(3000);
-                               /* retry will check if exiting */
-                               continue;
-                       }
-               } else if (isLargeBuf) {
-                       /* we are reusing a dirty large buf, clear its start */
-                       memset(bigbuf, 0, sizeof(struct smb_hdr));
-               }
 
-               if (smallbuf == NULL) {
-                       smallbuf = cifs_small_buf_get();
-                       if (!smallbuf) {
-                               cERROR(1, "No memory for SMB response");
-                               msleep(1000);
-                               /* retry will check if exiting */
-                               continue;
-                       }
-                       /* beginning of smb buffer is cleared in our buf_get */
-               } else /* if existing small buf clear beginning */
-                       memset(smallbuf, 0, sizeof(struct smb_hdr));
+               if (!allocate_buffers(&bigbuf, &smallbuf,
+                                     sizeof(struct smb_hdr), isLargeBuf))
+                       continue;
 
                isLargeBuf = false;
                isMultiRsp = false;
-               smb_buffer = smallbuf;
-               iov.iov_base = smb_buffer;
+               smb_buffer = (struct smb_hdr *)smallbuf;
+               buf = smallbuf;
+               iov.iov_base = buf;
                iov.iov_len = 4;
                smb_msg.msg_control = NULL;
                smb_msg.msg_controllen = 0;
@@ -393,158 +677,50 @@ incomplete_rcv:
                                  "Reconnecting...", server->hostname,
                                  (echo_retries * SMB_ECHO_INTERVAL / HZ));
                        cifs_reconnect(server);
-                       csocket = server->ssocket;
                        wake_up(&server->response_q);
                        continue;
                }
 
-               length =
-                   kernel_recvmsg(csocket, &smb_msg,
-                               &iov, 1, pdu_length, 0 /* BB other flags? */);
-
-               if (server->tcpStatus == CifsExiting) {
+               rc = read_from_socket(server, &smb_msg, &iov, pdu_length,
+                                     &total_read, true /* header read */);
+               if (rc == 3)
+                       goto incomplete_rcv;
+               else if (rc == 2)
                        break;
-               } else if (server->tcpStatus == CifsNeedReconnect) {
-                       cFYI(1, "Reconnect after server stopped responding");
-                       cifs_reconnect(server);
-                       cFYI(1, "call to reconnect done");
-                       csocket = server->ssocket;
-                       continue;
-               } else if (length == -ERESTARTSYS ||
-                          length == -EAGAIN ||
-                          length == -EINTR) {
-                       msleep(1); /* minimum sleep to prevent looping
-                               allowing socket to clear and app threads to set
-                               tcpStatus CifsNeedReconnect if server hung */
-                       if (pdu_length < 4) {
-                               iov.iov_base = (4 - pdu_length) +
-                                                       (char *)smb_buffer;
-                               iov.iov_len = pdu_length;
-                               smb_msg.msg_control = NULL;
-                               smb_msg.msg_controllen = 0;
-                               goto incomplete_rcv;
-                       } else
-                               continue;
-               } else if (length <= 0) {
-                       cFYI(1, "Reconnect after unexpected peek error %d",
-                               length);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
-                       wake_up(&server->response_q);
+               else if (rc == 1)
                        continue;
-               } else if (length < pdu_length) {
-                       cFYI(1, "requested %d bytes but only got %d bytes",
-                                 pdu_length, length);
-                       pdu_length -= length;
-                       msleep(1);
-                       goto incomplete_rcv;
-               }
-
-               /* The right amount was read from socket - 4 bytes */
-               /* so we can now interpret the length field */
 
-               /* the first byte big endian of the length field,
-               is actually not part of the length but the type
-               with the most common, zero, as regular data */
-               temp = *((char *) smb_buffer);
+               /*
+                * The right amount was read from socket - 4 bytes,
+                * so we can now interpret the length field.
+                */
 
-               /* Note that FC 1001 length is big endian on the wire,
-               but we convert it here so it is always manipulated
-               as host byte order */
+               /*
+                * Note that RFC 1001 length is big endian on the wire,
+                * but we convert it here so it is always manipulated
+                * as host byte order.
+                */
                pdu_length = be32_to_cpu(smb_buffer->smb_buf_length);
 
                cFYI(1, "rfc1002 length 0x%x", pdu_length+4);
-
-               if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
-                       continue;
-               } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
-                       cFYI(1, "Good RFC 1002 session rsp");
-                       continue;
-               } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
-                       /* we get this from Windows 98 instead of
-                          an error on SMB negprot response */
-                       cFYI(1, "Negative RFC1002 Session Response Error 0x%x)",
-                               pdu_length);
-                       /* give server a second to clean up  */
-                       msleep(1000);
-                       /* always try 445 first on reconnect since we get NACK
-                        * on some if we ever connected to port 139 (the NACK
-                        * is since we do not begin with RFC1001 session
-                        * initialize frame)
-                        */
-                       cifs_set_port((struct sockaddr *)
-                                       &server->dstaddr, CIFS_PORT);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
-                       wake_up(&server->response_q);
-                       continue;
-               } else if (temp != (char) 0) {
-                       cERROR(1, "Unknown RFC 1002 frame");
-                       cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
-                                     length);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
+               if (!check_rfc1002_header(server, buf))
                        continue;
-               }
-
-               /* else we have an SMB response */
-               if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
-                           (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
-                       cERROR(1, "Invalid size SMB length %d pdu_length %d",
-                                       length, pdu_length+4);
-                       cifs_reconnect(server);
-                       csocket = server->ssocket;
-                       wake_up(&server->response_q);
-                       continue;
-               }
 
                /* else length ok */
-               reconnect = 0;
-
                if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
                        isLargeBuf = true;
                        memcpy(bigbuf, smallbuf, 4);
-                       smb_buffer = bigbuf;
+                       smb_buffer = (struct smb_hdr *)bigbuf;
+                       buf = bigbuf;
                }
-               length = 0;
-               iov.iov_base = 4 + (char *)smb_buffer;
+
+               iov.iov_base = 4 + buf;
                iov.iov_len = pdu_length;
-               for (total_read = 0; total_read < pdu_length;
-                    total_read += length) {
-                       length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
-                                               pdu_length - total_read, 0);
-                       if (server->tcpStatus == CifsExiting) {
-                               /* then will exit */
-                               reconnect = 2;
-                               break;
-                       } else if (server->tcpStatus == CifsNeedReconnect) {
-                               cifs_reconnect(server);
-                               csocket = server->ssocket;
-                               /* Reconnect wakes up rspns q */
-                               /* Now we will reread sock */
-                               reconnect = 1;
-                               break;
-                       } else if (length == -ERESTARTSYS ||
-                                  length == -EAGAIN ||
-                                  length == -EINTR) {
-                               msleep(1); /* minimum sleep to prevent looping,
-                                             allowing socket to clear and app
-                                             threads to set tcpStatus
-                                             CifsNeedReconnect if server hung*/
-                               length = 0;
-                               continue;
-                       } else if (length <= 0) {
-                               cERROR(1, "Received no data, expecting %d",
-                                             pdu_length - total_read);
-                               cifs_reconnect(server);
-                               csocket = server->ssocket;
-                               reconnect = 1;
-                               break;
-                       }
-               }
-               if (reconnect == 2)
+               rc = read_from_socket(server, &smb_msg, &iov, pdu_length,
+                                     &total_read, false);
+               if (rc == 2)
                        break;
-               else if (reconnect == 1)
+               else if (rc == 1)
                        continue;
 
                total_read += 4; /* account for rfc1002 hdr */
@@ -562,75 +738,13 @@ incomplete_rcv:
                 */
                length = checkSMB(smb_buffer, smb_buffer->Mid, total_read);
                if (length != 0)
-                       cifs_dump_mem("Bad SMB: ", smb_buffer,
-                                       min_t(unsigned int, total_read, 48));
+                       cifs_dump_mem("Bad SMB: ", buf,
+                                     min_t(unsigned int, total_read, 48));
 
-               mid_entry = NULL;
                server->lstrp = jiffies;
 
-               spin_lock(&GlobalMid_Lock);
-               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-
-                       if (mid_entry->mid != smb_buffer->Mid ||
-                           mid_entry->midState != MID_REQUEST_SUBMITTED ||
-                           mid_entry->command != smb_buffer->Command) {
-                               mid_entry = NULL;
-                               continue;
-                       }
-
-                       if (length == 0 &&
-                           check2ndT2(smb_buffer, server->maxBuf) > 0) {
-                               /* We have a multipart transact2 resp */
-                               isMultiRsp = true;
-                               if (mid_entry->resp_buf) {
-                                       /* merge response - fix up 1st*/
-                                       length = coalesce_t2(smb_buffer,
-                                                       mid_entry->resp_buf);
-                                       if (length > 0) {
-                                               length = 0;
-                                               mid_entry->multiRsp = true;
-                                               break;
-                                       } else {
-                                               /* all parts received or
-                                                * packet is malformed
-                                                */
-                                               mid_entry->multiEnd = true;
-                                               goto multi_t2_fnd;
-                                       }
-                               } else {
-                                       if (!isLargeBuf) {
-                                               /*
-                                                * FIXME: switch to already
-                                                *        allocated largebuf?
-                                                */
-                                               cERROR(1, "1st trans2 resp "
-                                                         "needs bigbuf");
-                                       } else {
-                                               /* Have first buffer */
-                                               mid_entry->resp_buf =
-                                                        smb_buffer;
-                                               mid_entry->largeBuf = true;
-                                               bigbuf = NULL;
-                                       }
-                               }
-                               break;
-                       }
-                       mid_entry->resp_buf = smb_buffer;
-                       mid_entry->largeBuf = isLargeBuf;
-multi_t2_fnd:
-                       if (length == 0)
-                               mid_entry->midState = MID_RESPONSE_RECEIVED;
-                       else
-                               mid_entry->midState = MID_RESPONSE_MALFORMED;
-#ifdef CONFIG_CIFS_STATS2
-                       mid_entry->when_received = jiffies;
-#endif
-                       list_del_init(&mid_entry->qhead);
-                       break;
-               }
-               spin_unlock(&GlobalMid_Lock);
-
+               mid_entry = find_cifs_mid(server, smb_buffer, &length,
+                                         isLargeBuf, &isMultiRsp, &bigbuf);
                if (mid_entry != NULL) {
                        mid_entry->callback(mid_entry);
                        /* Was previous buf put in mpx struct for multi-rsp? */
@@ -648,7 +762,7 @@ multi_t2_fnd:
                           !isMultiRsp) {
                        cERROR(1, "No task to wake, unknown frame received! "
                                   "NumMids %d", atomic_read(&midCount));
-                       cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
+                       cifs_dump_mem("Received Data is: ", buf,
                                      sizeof(struct smb_hdr));
 #ifdef CONFIG_CIFS_DEBUG2
                        cifs_dump_detail(smb_buffer);
@@ -658,88 +772,13 @@ multi_t2_fnd:
                }
        } /* end while !EXITING */
 
-       /* take it off the list, if it's not already */
-       spin_lock(&cifs_tcp_ses_lock);
-       list_del_init(&server->tcp_ses_list);
-       spin_unlock(&cifs_tcp_ses_lock);
-
-       spin_lock(&GlobalMid_Lock);
-       server->tcpStatus = CifsExiting;
-       spin_unlock(&GlobalMid_Lock);
-       wake_up_all(&server->response_q);
-
-       /* check if we have blocked requests that need to free */
-       /* Note that cifs_max_pending is normally 50, but
-       can be set at module install time to as little as two */
-       spin_lock(&GlobalMid_Lock);
-       if (atomic_read(&server->inFlight) >= cifs_max_pending)
-               atomic_set(&server->inFlight, cifs_max_pending - 1);
-       /* We do not want to set the max_pending too low or we
-       could end up with the counter going negative */
-       spin_unlock(&GlobalMid_Lock);
-       /* Although there should not be any requests blocked on
-       this queue it can not hurt to be paranoid and try to wake up requests
-       that may haven been blocked when more than 50 at time were on the wire
-       to the same server - they now will see the session is in exit state
-       and get out of SendReceive.  */
-       wake_up_all(&server->request_q);
-       /* give those requests time to exit */
-       msleep(125);
-
-       if (server->ssocket) {
-               sock_release(csocket);
-               server->ssocket = NULL;
-       }
        /* buffer usually freed in free_mid - need to free it here on exit */
        cifs_buf_release(bigbuf);
        if (smallbuf) /* no sense logging a debug message if NULL */
                cifs_small_buf_release(smallbuf);
 
-       if (!list_empty(&server->pending_mid_q)) {
-               struct list_head dispose_list;
-
-               INIT_LIST_HEAD(&dispose_list);
-               spin_lock(&GlobalMid_Lock);
-               list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-                       cFYI(1, "Clearing mid 0x%x", mid_entry->mid);
-                       mid_entry->midState = MID_SHUTDOWN;
-                       list_move(&mid_entry->qhead, &dispose_list);
-               }
-               spin_unlock(&GlobalMid_Lock);
-
-               /* now walk dispose list and issue callbacks */
-               list_for_each_safe(tmp, tmp2, &dispose_list) {
-                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-                       cFYI(1, "Callback mid 0x%x", mid_entry->mid);
-                       list_del_init(&mid_entry->qhead);
-                       mid_entry->callback(mid_entry);
-               }
-               /* 1/8th of sec is more than enough time for them to exit */
-               msleep(125);
-       }
-
-       if (!list_empty(&server->pending_mid_q)) {
-               /* mpx threads have not exited yet give them
-               at least the smb send timeout time for long ops */
-               /* due to delays on oplock break requests, we need
-               to wait at least 45 seconds before giving up
-               on a request getting a response and going ahead
-               and killing cifsd */
-               cFYI(1, "Wait for exit from demultiplex thread");
-               msleep(46000);
-               /* if threads still have not exited they are probably never
-               coming home not much else we can do but free the memory */
-       }
-
-       kfree(server->hostname);
        task_to_wake = xchg(&server->tsk, NULL);
-       kfree(server);
-
-       length = atomic_dec_return(&tcpSesAllocCount);
-       if (length  > 0)
-               mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
-                               GFP_KERNEL);
+       clean_demultiplex_info(server);
 
        /* if server->tsk was NULL then wait for a signal before exiting */
        if (!task_to_wake) {
@@ -3193,15 +3232,9 @@ mount_fail_check:
                else
                        cifs_put_tcp_session(srvTcp);
                bdi_destroy(&cifs_sb->bdi);
-               goto out;
        }
 
-       /* volume_info->password is freed above when existing session found
-       (in which case it is not needed anymore) but when new sesion is created
-       the password ptr is put in the new session structure (in which case the
-       password will be freed at unmount time) */
 out:
-       /* zero out password before freeing */
        FreeXid(xid);
        return rc;
 }
index 378acdafa356799faa4137f608e59724ad44919a..9f41a10523a1bad91ba0a9e8581ed89f552785e2 100644 (file)
@@ -314,6 +314,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
        }
        spin_unlock(&cifs_file_list_lock);
 
+       cancel_work_sync(&cifs_file->oplock_break);
+
        if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
                int xid, rc;
 
@@ -2418,31 +2420,6 @@ void cifs_oplock_break(struct work_struct *work)
                                 cinode->clientCanCacheRead ? 1 : 0);
                cFYI(1, "Oplock release rc = %d", rc);
        }
-
-       /*
-        * We might have kicked in before is_valid_oplock_break()
-        * finished grabbing reference for us.  Make sure it's done by
-        * waiting for cifs_file_list_lock.
-        */
-       spin_lock(&cifs_file_list_lock);
-       spin_unlock(&cifs_file_list_lock);
-
-       cifs_oplock_break_put(cfile);
-}
-
-/* must be called while holding cifs_file_list_lock */
-void cifs_oplock_break_get(struct cifsFileInfo *cfile)
-{
-       cifs_sb_active(cfile->dentry->d_sb);
-       cifsFileInfo_get(cfile);
-}
-
-void cifs_oplock_break_put(struct cifsFileInfo *cfile)
-{
-       struct super_block *sb = cfile->dentry->d_sb;
-
-       cifsFileInfo_put(cfile);
-       cifs_sb_deactive(sb);
 }
 
 const struct address_space_operations cifs_addr_ops = {
index 03a1f491d39b494632ecf09845c84ac839f6a6eb..7c16933925987d7bcbb213ab5abc30b8e17655eb 100644 (file)
@@ -585,15 +585,8 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 
                                cifs_set_oplock_level(pCifsInode,
                                        pSMB->OplockLevel ? OPLOCK_READ : 0);
-                               /*
-                                * cifs_oplock_break_put() can't be called
-                                * from here.  Get reference after queueing
-                                * succeeded.  cifs_oplock_break() will
-                                * synchronize using cifs_file_list_lock.
-                                */
-                               if (queue_work(system_nrt_wq,
-                                              &netfile->oplock_break))
-                                       cifs_oplock_break_get(netfile);
+                               queue_work(system_nrt_wq,
+                                          &netfile->oplock_break);
                                netfile->oplock_break_cancelled = false;
 
                                spin_unlock(&cifs_file_list_lock);
index d3e619692ee0f0437e26d9d91d61545859f248bc..243d5872051319c78e680fc0965f2119bab8749d 100644 (file)
@@ -124,7 +124,8 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
        /*      that we use in next few lines                               */
        /* Note that header is initialized to zero in header_assemble */
        pSMB->req.AndXCommand = 0xFF;
-       pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+       pSMB->req.MaxBufferSize = cpu_to_le16(min_t(u32, CIFSMaxBufSize - 4,
+                                               USHRT_MAX));
        pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
        pSMB->req.VcNumber = get_next_vcnum(ses);
 
index 43c7c43b06f54f10c692a21df3b4158059257bbb..b36c5572b3f3739c1cae2d970d14196ed10d8ceb 100644 (file)
@@ -29,6 +29,7 @@
 #define ECRYPTFS_KERNEL_H
 
 #include <keys/user-type.h>
+#include <keys/encrypted-type.h>
 #include <linux/fs.h>
 #include <linux/fs_stack.h>
 #include <linux/namei.h>
 #include <linux/hash.h>
 #include <linux/nsproxy.h>
 #include <linux/backing-dev.h>
+#include <linux/ecryptfs.h>
 
-/* Version verification for shared data structures w/ userspace */
-#define ECRYPTFS_VERSION_MAJOR 0x00
-#define ECRYPTFS_VERSION_MINOR 0x04
-#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x03
-/* These flags indicate which features are supported by the kernel
- * module; userspace tools such as the mount helper read
- * ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine
- * how to behave. */
-#define ECRYPTFS_VERSIONING_PASSPHRASE            0x00000001
-#define ECRYPTFS_VERSIONING_PUBKEY                0x00000002
-#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004
-#define ECRYPTFS_VERSIONING_POLICY                0x00000008
-#define ECRYPTFS_VERSIONING_XATTR                 0x00000010
-#define ECRYPTFS_VERSIONING_MULTKEY               0x00000020
-#define ECRYPTFS_VERSIONING_DEVMISC               0x00000040
-#define ECRYPTFS_VERSIONING_HMAC                  0x00000080
-#define ECRYPTFS_VERSIONING_FILENAME_ENCRYPTION   0x00000100
-#define ECRYPTFS_VERSIONING_GCM                   0x00000200
-#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
-                                 | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \
-                                 | ECRYPTFS_VERSIONING_PUBKEY \
-                                 | ECRYPTFS_VERSIONING_XATTR \
-                                 | ECRYPTFS_VERSIONING_MULTKEY \
-                                 | ECRYPTFS_VERSIONING_DEVMISC \
-                                 | ECRYPTFS_VERSIONING_FILENAME_ENCRYPTION)
-#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
-#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
-#define ECRYPTFS_SALT_SIZE 8
-#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2)
-/* The original signature size is only for what is stored on disk; all
- * in-memory representations are expanded hex, so it better adapted to
- * be passed around or referenced on the command line */
-#define ECRYPTFS_SIG_SIZE 8
-#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
-#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
-#define ECRYPTFS_MAX_KEY_BYTES 64
-#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
 #define ECRYPTFS_DEFAULT_IV_BYTES 16
-#define ECRYPTFS_FILE_VERSION 0x03
 #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
 #define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192
 #define ECRYPTFS_DEFAULT_MSG_CTX_ELEMS 32
 #define ECRYPTFS_DEFAULT_SEND_TIMEOUT HZ
 #define ECRYPTFS_MAX_MSG_CTX_TTL (HZ*3)
-#define ECRYPTFS_MAX_PKI_NAME_BYTES 16
 #define ECRYPTFS_DEFAULT_NUM_USERS 4
 #define ECRYPTFS_MAX_NUM_USERS 32768
 #define ECRYPTFS_XATTR_NAME "user.ecryptfs"
 
-#define RFC2440_CIPHER_DES3_EDE 0x02
-#define RFC2440_CIPHER_CAST_5 0x03
-#define RFC2440_CIPHER_BLOWFISH 0x04
-#define RFC2440_CIPHER_AES_128 0x07
-#define RFC2440_CIPHER_AES_192 0x08
-#define RFC2440_CIPHER_AES_256 0x09
-#define RFC2440_CIPHER_TWOFISH 0x0a
-#define RFC2440_CIPHER_CAST_6 0x0b
-
-#define RFC2440_CIPHER_RSA 0x01
-
-/**
- * For convenience, we may need to pass around the encrypted session
- * key between kernel and userspace because the authentication token
- * may not be extractable.  For example, the TPM may not release the
- * private key, instead requiring the encrypted data and returning the
- * decrypted data.
- */
-struct ecryptfs_session_key {
-#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001
-#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002
-#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004
-#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008
-       u32 flags;
-       u32 encrypted_key_size;
-       u32 decrypted_key_size;
-       u8 encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
-       u8 decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
-};
-
-struct ecryptfs_password {
-       u32 password_bytes;
-       s32 hash_algo;
-       u32 hash_iterations;
-       u32 session_key_encryption_key_bytes;
-#define ECRYPTFS_PERSISTENT_PASSWORD 0x01
-#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02
-       u32 flags;
-       /* Iterated-hash concatenation of salt and passphrase */
-       u8 session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
-       u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
-       /* Always in expanded hex */
-       u8 salt[ECRYPTFS_SALT_SIZE];
-};
-
-enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};
-
-struct ecryptfs_private_key {
-       u32 key_size;
-       u32 data_len;
-       u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
-       char pki_type[ECRYPTFS_MAX_PKI_NAME_BYTES + 1];
-       u8 data[];
-};
-
-/* May be a password or a private key */
-struct ecryptfs_auth_tok {
-       u16 version; /* 8-bit major and 8-bit minor */
-       u16 token_type;
-#define ECRYPTFS_ENCRYPT_ONLY 0x00000001
-       u32 flags;
-       struct ecryptfs_session_key session_key;
-       u8 reserved[32];
-       union {
-               struct ecryptfs_password password;
-               struct ecryptfs_private_key private_key;
-       } token;
-} __attribute__ ((packed));
-
 void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok);
 extern void ecryptfs_to_hex(char *dst, char *src, size_t src_size);
 extern void ecryptfs_from_hex(char *dst, char *src, int dst_size);
@@ -185,11 +79,47 @@ struct ecryptfs_page_crypt_context {
        } param;
 };
 
+#if defined(CONFIG_ENCRYPTED_KEYS) || defined(CONFIG_ENCRYPTED_KEYS_MODULE)
+static inline struct ecryptfs_auth_tok *
+ecryptfs_get_encrypted_key_payload_data(struct key *key)
+{
+       if (key->type == &key_type_encrypted)
+               return (struct ecryptfs_auth_tok *)
+                       (&((struct encrypted_key_payload *)key->payload.data)->payload_data);
+       else
+               return NULL;
+}
+
+static inline struct key *ecryptfs_get_encrypted_key(char *sig)
+{
+       return request_key(&key_type_encrypted, sig, NULL);
+}
+
+#else
+static inline struct ecryptfs_auth_tok *
+ecryptfs_get_encrypted_key_payload_data(struct key *key)
+{
+       return NULL;
+}
+
+static inline struct key *ecryptfs_get_encrypted_key(char *sig)
+{
+       return ERR_PTR(-ENOKEY);
+}
+
+#endif /* CONFIG_ENCRYPTED_KEYS */
+
 static inline struct ecryptfs_auth_tok *
 ecryptfs_get_key_payload_data(struct key *key)
 {
-       return (struct ecryptfs_auth_tok *)
-               (((struct user_key_payload*)key->payload.data)->data);
+       struct ecryptfs_auth_tok *auth_tok;
+
+       auth_tok = ecryptfs_get_encrypted_key_payload_data(key);
+       if (!auth_tok)
+               return (struct ecryptfs_auth_tok *)
+                       (((struct user_key_payload *)key->payload.data)->data);
+       else
+               return auth_tok;
 }
 
 #define ECRYPTFS_MAX_KEYSET_SIZE 1024
index 340c657a108c5892f2453e8d6c7e923a14a37cf2..11f8582d72186d679d2452d9ce71e85f277bdbf9 100644 (file)
@@ -69,6 +69,7 @@ static int ecryptfs_inode_set(struct inode *inode, void *opaque)
        inode->i_ino = lower_inode->i_ino;
        inode->i_version++;
        inode->i_mapping->a_ops = &ecryptfs_aops;
+       inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi;
 
        if (S_ISLNK(inode->i_mode))
                inode->i_op = &ecryptfs_symlink_iops;
index fa8049ecdc64249f377b8b9d27fd230441af5272..08a2b52bf565c2aab2eab60546f961b76ca699c4 100644 (file)
@@ -1635,11 +1635,14 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,
 
        (*auth_tok_key) = request_key(&key_type_user, sig, NULL);
        if (!(*auth_tok_key) || IS_ERR(*auth_tok_key)) {
-               printk(KERN_ERR "Could not find key with description: [%s]\n",
-                      sig);
-               rc = process_request_key_err(PTR_ERR(*auth_tok_key));
-               (*auth_tok_key) = NULL;
-               goto out;
+               (*auth_tok_key) = ecryptfs_get_encrypted_key(sig);
+               if (!(*auth_tok_key) || IS_ERR(*auth_tok_key)) {
+                       printk(KERN_ERR "Could not find key with description: [%s]\n",
+                             sig);
+                       rc = process_request_key_err(PTR_ERR(*auth_tok_key));
+                       (*auth_tok_key) = NULL;
+                       goto out;
+               }
        }
        down_write(&(*auth_tok_key)->sem);
        rc = ecryptfs_verify_auth_tok_from_key(*auth_tok_key, auth_tok);
@@ -1868,11 +1871,6 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
         * just one will be sufficient to decrypt to get the FEK. */
 find_next_matching_auth_tok:
        found_auth_tok = 0;
-       if (auth_tok_key) {
-               up_write(&(auth_tok_key->sem));
-               key_put(auth_tok_key);
-               auth_tok_key = NULL;
-       }
        list_for_each_entry(auth_tok_list_item, &auth_tok_list, list) {
                candidate_auth_tok = &auth_tok_list_item->auth_tok;
                if (unlikely(ecryptfs_verbosity > 0)) {
@@ -1909,14 +1907,22 @@ found_matching_auth_tok:
                memcpy(&(candidate_auth_tok->token.private_key),
                       &(matching_auth_tok->token.private_key),
                       sizeof(struct ecryptfs_private_key));
+               up_write(&(auth_tok_key->sem));
+               key_put(auth_tok_key);
                rc = decrypt_pki_encrypted_session_key(candidate_auth_tok,
                                                       crypt_stat);
        } else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) {
                memcpy(&(candidate_auth_tok->token.password),
                       &(matching_auth_tok->token.password),
                       sizeof(struct ecryptfs_password));
+               up_write(&(auth_tok_key->sem));
+               key_put(auth_tok_key);
                rc = decrypt_passphrase_encrypted_session_key(
                        candidate_auth_tok, crypt_stat);
+       } else {
+               up_write(&(auth_tok_key->sem));
+               key_put(auth_tok_key);
+               rc = -EINVAL;
        }
        if (rc) {
                struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp;
@@ -1956,15 +1962,12 @@ found_matching_auth_tok:
 out_wipe_list:
        wipe_auth_tok_list(&auth_tok_list);
 out:
-       if (auth_tok_key) {
-               up_write(&(auth_tok_key->sem));
-               key_put(auth_tok_key);
-       }
        return rc;
 }
 
 static int
-pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
+pki_encrypt_session_key(struct key *auth_tok_key,
+                       struct ecryptfs_auth_tok *auth_tok,
                        struct ecryptfs_crypt_stat *crypt_stat,
                        struct ecryptfs_key_record *key_rec)
 {
@@ -1979,6 +1982,8 @@ pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
                                         crypt_stat->cipher,
                                         crypt_stat->key_size),
                                 crypt_stat, &payload, &payload_len);
+       up_write(&(auth_tok_key->sem));
+       key_put(auth_tok_key);
        if (rc) {
                ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n");
                goto out;
@@ -2008,6 +2013,8 @@ out:
  * write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet
  * @dest: Buffer into which to write the packet
  * @remaining_bytes: Maximum number of bytes that can be writtn
+ * @auth_tok_key: The authentication token key to unlock and put when done with
+ *                @auth_tok
  * @auth_tok: The authentication token used for generating the tag 1 packet
  * @crypt_stat: The cryptographic context
  * @key_rec: The key record struct for the tag 1 packet
@@ -2018,7 +2025,7 @@ out:
  */
 static int
 write_tag_1_packet(char *dest, size_t *remaining_bytes,
-                  struct ecryptfs_auth_tok *auth_tok,
+                  struct key *auth_tok_key, struct ecryptfs_auth_tok *auth_tok,
                   struct ecryptfs_crypt_stat *crypt_stat,
                   struct ecryptfs_key_record *key_rec, size_t *packet_size)
 {
@@ -2039,12 +2046,15 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes,
                memcpy(key_rec->enc_key,
                       auth_tok->session_key.encrypted_key,
                       auth_tok->session_key.encrypted_key_size);
+               up_write(&(auth_tok_key->sem));
+               key_put(auth_tok_key);
                goto encrypted_session_key_set;
        }
        if (auth_tok->session_key.encrypted_key_size == 0)
                auth_tok->session_key.encrypted_key_size =
                        auth_tok->token.private_key.key_size;
-       rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec);
+       rc = pki_encrypt_session_key(auth_tok_key, auth_tok, crypt_stat,
+                                    key_rec);
        if (rc) {
                printk(KERN_ERR "Failed to encrypt session key via a key "
                       "module; rc = [%d]\n", rc);
@@ -2421,6 +2431,8 @@ ecryptfs_generate_key_packet_set(char *dest_base,
                                                &max, auth_tok,
                                                crypt_stat, key_rec,
                                                &written);
+                       up_write(&(auth_tok_key->sem));
+                       key_put(auth_tok_key);
                        if (rc) {
                                ecryptfs_printk(KERN_WARNING, "Error "
                                                "writing tag 3 packet\n");
@@ -2438,8 +2450,8 @@ ecryptfs_generate_key_packet_set(char *dest_base,
                        }
                        (*len) += written;
                } else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {
-                       rc = write_tag_1_packet(dest_base + (*len),
-                                               &max, auth_tok,
+                       rc = write_tag_1_packet(dest_base + (*len), &max,
+                                               auth_tok_key, auth_tok,
                                                crypt_stat, key_rec, &written);
                        if (rc) {
                                ecryptfs_printk(KERN_WARNING, "Error "
@@ -2448,14 +2460,13 @@ ecryptfs_generate_key_packet_set(char *dest_base,
                        }
                        (*len) += written;
                } else {
+                       up_write(&(auth_tok_key->sem));
+                       key_put(auth_tok_key);
                        ecryptfs_printk(KERN_WARNING, "Unsupported "
                                        "authentication token type\n");
                        rc = -EINVAL;
                        goto out_free;
                }
-               up_write(&(auth_tok_key->sem));
-               key_put(auth_tok_key);
-               auth_tok_key = NULL;
        }
        if (likely(max > 0)) {
                dest_base[(*len)] = 0x00;
@@ -2468,11 +2479,6 @@ out_free:
 out:
        if (rc)
                (*len) = 0;
-       if (auth_tok_key) {
-               up_write(&(auth_tok_key->sem));
-               key_put(auth_tok_key);
-       }
-
        mutex_unlock(&crypt_stat->keysig_list_mutex);
        return rc;
 }
index 5c0a6a4fb052c78a3d14df3b25bfc47a26b5fe9b..503bfb0ed79b208365c50a0695243d55c43bca19 100644 (file)
@@ -61,7 +61,6 @@ extern int ext2_init_acl (struct inode *, struct inode *);
 #else
 #include <linux/sched.h>
 #define ext2_get_acl   NULL
-#define ext2_get_acl   NULL
 #define ext2_set_acl   NULL
 
 static inline int
index 1599aa985fe2accf6dcc9456a570ba942201685d..04cf3b91e5016a1f7e3ceef734c7d85574ec296d 100644 (file)
@@ -618,7 +618,12 @@ static long __writeback_inodes_wb(struct bdi_writeback *wb,
                struct super_block *sb = inode->i_sb;
 
                if (!grab_super_passive(sb)) {
-                       requeue_io(inode, wb);
+                       /*
+                        * grab_super_passive() may fail consistently due to
+                        * s_umount being grabbed by someone else. Don't use
+                        * requeue_io() to avoid busy retrying the inode/sb.
+                        */
+                       redirty_tail(inode, wb);
                        continue;
                }
                wrote += writeback_sb_inodes(sb, wb, work);
index 516516e0c2a2d6ac0bc7bff9e511755a6e660cb1..3bc073a4cf82ca74b8ed018d61afe249762b8315 100644 (file)
@@ -1018,13 +1018,13 @@ hostdata_error:
                fsname++;
        if (lm->lm_mount == NULL) {
                fs_info(sdp, "Now mounting FS...\n");
-               complete(&sdp->sd_locking_init);
+               complete_all(&sdp->sd_locking_init);
                return 0;
        }
        ret = lm->lm_mount(sdp, fsname);
        if (ret == 0)
                fs_info(sdp, "Joined cluster. Now mounting FS...\n");
-       complete(&sdp->sd_locking_init);
+       complete_all(&sdp->sd_locking_init);
        return ret;
 }
 
index 4496872cf4e7884b8f6d6b756c8854ed2e23991c..9cbd11a3f804d23e2fb005db0c1f286c4e7f94db 100644 (file)
@@ -3161,7 +3161,7 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
 {
        int rc;
        int dbitno, word, rembits, nb, nwords, wbitno, agno;
-       s8 oldroot, *leaf;
+       s8 oldroot;
        struct dmaptree *tp = (struct dmaptree *) & dp->tree;
 
        /* save the current value of the root (i.e. maximum free string)
@@ -3169,9 +3169,6 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
         */
        oldroot = tp->stree[ROOT];
 
-       /* pick up a pointer to the leaves of the dmap tree */
-       leaf = tp->stree + LEAFIND;
-
        /* determine the bit number and word within the dmap of the
         * starting block.
         */
index f6cc0c09ec637274404af7eb6419112a8203acbe..af9606057ddefa08d32904320db859af5ec4cde3 100644 (file)
@@ -1143,7 +1143,6 @@ int txCommit(tid_t tid,           /* transaction identifier */
        struct jfs_log *log;
        struct tblock *tblk;
        struct lrd *lrd;
-       int lsn;
        struct inode *ip;
        struct jfs_inode_info *jfs_ip;
        int k, n;
@@ -1310,7 +1309,7 @@ int txCommit(tid_t tid,           /* transaction identifier */
         */
        lrd->type = cpu_to_le16(LOG_COMMIT);
        lrd->length = 0;
-       lsn = lmLog(log, tblk, lrd, NULL);
+       lmLog(log, tblk, lrd, NULL);
 
        lmGroupCommit(log, tblk);
 
@@ -2935,7 +2934,6 @@ int jfs_sync(void *arg)
 {
        struct inode *ip;
        struct jfs_inode_info *jfs_ip;
-       int rc;
        tid_t tid;
 
        do {
@@ -2961,7 +2959,7 @@ int jfs_sync(void *arg)
                                 */
                                TXN_UNLOCK();
                                tid = txBegin(ip->i_sb, COMMIT_INODE);
-                               rc = txCommit(tid, 1, &ip, 0);
+                               txCommit(tid, 1, &ip, 0);
                                txEnd(tid);
                                mutex_unlock(&jfs_ip->commit_mutex);
 
index 29b1f1a21142d773d9fe0ec783745cc82cd2a21b..e17545e15664d77cf5d3af35c2c34c99123b929d 100644 (file)
@@ -893,7 +893,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
        unchar *i_fastsymlink;
        s64 xlen = 0;
        int bmask = 0, xsize;
-       s64 extent = 0, xaddr;
+       s64 xaddr;
        struct metapage *mp;
        struct super_block *sb;
        struct tblock *tblk;
@@ -993,7 +993,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                        txAbort(tid, 0);
                        goto out3;
                }
-               extent = xaddr;
                ip->i_size = ssize - 1;
                while (ssize) {
                        /* This is kind of silly since PATH_MAX == 4K */
index e374050a911c6141342bf5b464bb04fca396ce3e..8392cb85bd54401d27028f0ed2932dceb4dd98bf 100644 (file)
@@ -302,7 +302,8 @@ nlmclnt_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc)
                                /* We appear to be out of the grace period */
                                wake_up_all(&host->h_gracewait);
                        }
-                       dprintk("lockd: server returns status %d\n", resp->status);
+                       dprintk("lockd: server returns status %d\n",
+                               ntohl(resp->status));
                        return 0;       /* Okay, call complete */
                }
 
@@ -690,7 +691,8 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
                goto out;
 
        if (resp->status != nlm_lck_denied_nolocks)
-               printk("lockd: unexpected unlock status: %d\n", resp->status);
+               printk("lockd: unexpected unlock status: %d\n",
+                       ntohl(resp->status));
        /* What to do now? I'm out of my depth... */
        status = -ENOLCK;
 out:
@@ -843,6 +845,7 @@ nlm_stat_to_errno(__be32 status)
                return -ENOLCK;
 #endif
        }
-       printk(KERN_NOTICE "lockd: unexpected server status %d\n", status);
+       printk(KERN_NOTICE "lockd: unexpected server status %d\n",
+                ntohl(status));
        return -ENOLCK;
 }
index 81515545ba755af46d4763d15560283087596d0b..be020771c6b46188b9c4534a99c4014c76ed5957 100644 (file)
@@ -77,16 +77,23 @@ config NFS_V4
 config NFS_V4_1
        bool "NFS client support for NFSv4.1 (EXPERIMENTAL)"
        depends on NFS_FS && NFS_V4 && EXPERIMENTAL
+       select SUNRPC_BACKCHANNEL
        select PNFS_FILE_LAYOUT
+       select PNFS_BLOCK
+       select MD
+       select BLK_DEV_DM
        help
          This option enables support for minor version 1 of the NFSv4 protocol
-         (RFC 5661) in the kernel's NFS client.
+         (RFC 5661 and RFC 5663) in the kernel's NFS client.
 
          If unsure, say N.
 
 config PNFS_FILE_LAYOUT
        tristate
 
+config PNFS_BLOCK
+       tristate
+
 config PNFS_OBJLAYOUT
        tristate "Provide support for the pNFS Objects Layout Driver for NFSv4.1 pNFS (EXPERIMENTAL)"
        depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
index 6a34f7dd0e6f628a6ed0e68d09d09879dd03f366..b58613d0abb3f62eaa3bb29fd4b8141ebdb596d6 100644 (file)
@@ -23,3 +23,4 @@ obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
 nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
 
 obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/
+obj-$(CONFIG_PNFS_BLOCK) += blocklayout/
diff --git a/fs/nfs/blocklayout/Makefile b/fs/nfs/blocklayout/Makefile
new file mode 100644 (file)
index 0000000..d581550
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for the pNFS block layout driver kernel module
+#
+obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o
+blocklayoutdriver-objs := blocklayout.o extents.o blocklayoutdev.o blocklayoutdm.o
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
new file mode 100644 (file)
index 0000000..e56564d
--- /dev/null
@@ -0,0 +1,1019 @@
+/*
+ *  linux/fs/nfs/blocklayout/blocklayout.c
+ *
+ *  Module for the NFSv4.1 pNFS block layout driver.
+ *
+ *  Copyright (c) 2006 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@citi.umich.edu>
+ *  Fred Isaman <iisaman@umich.edu>
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.  if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/bio.h>         /* struct bio */
+#include <linux/buffer_head.h> /* various write calls */
+
+#include "blocklayout.h"
+
+#define NFSDBG_FACILITY        NFSDBG_PNFS_LD
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andy Adamson <andros@citi.umich.edu>");
+MODULE_DESCRIPTION("The NFSv4.1 pNFS Block layout driver");
+
+struct dentry *bl_device_pipe;
+wait_queue_head_t bl_wq;
+
+static void print_page(struct page *page)
+{
+       dprintk("PRINTPAGE page %p\n", page);
+       dprintk("       PagePrivate %d\n", PagePrivate(page));
+       dprintk("       PageUptodate %d\n", PageUptodate(page));
+       dprintk("       PageError %d\n", PageError(page));
+       dprintk("       PageDirty %d\n", PageDirty(page));
+       dprintk("       PageReferenced %d\n", PageReferenced(page));
+       dprintk("       PageLocked %d\n", PageLocked(page));
+       dprintk("       PageWriteback %d\n", PageWriteback(page));
+       dprintk("       PageMappedToDisk %d\n", PageMappedToDisk(page));
+       dprintk("\n");
+}
+
+/* Given the be associated with isect, determine if page data needs to be
+ * initialized.
+ */
+static int is_hole(struct pnfs_block_extent *be, sector_t isect)
+{
+       if (be->be_state == PNFS_BLOCK_NONE_DATA)
+               return 1;
+       else if (be->be_state != PNFS_BLOCK_INVALID_DATA)
+               return 0;
+       else
+               return !bl_is_sector_init(be->be_inval, isect);
+}
+
+/* Given the be associated with isect, determine if page data can be
+ * written to disk.
+ */
+static int is_writable(struct pnfs_block_extent *be, sector_t isect)
+{
+       return (be->be_state == PNFS_BLOCK_READWRITE_DATA ||
+               be->be_state == PNFS_BLOCK_INVALID_DATA);
+}
+
+/* The data we are handed might be spread across several bios.  We need
+ * to track when the last one is finished.
+ */
+struct parallel_io {
+       struct kref refcnt;
+       struct rpc_call_ops call_ops;
+       void (*pnfs_callback) (void *data);
+       void *data;
+};
+
+static inline struct parallel_io *alloc_parallel(void *data)
+{
+       struct parallel_io *rv;
+
+       rv  = kmalloc(sizeof(*rv), GFP_NOFS);
+       if (rv) {
+               rv->data = data;
+               kref_init(&rv->refcnt);
+       }
+       return rv;
+}
+
+static inline void get_parallel(struct parallel_io *p)
+{
+       kref_get(&p->refcnt);
+}
+
+static void destroy_parallel(struct kref *kref)
+{
+       struct parallel_io *p = container_of(kref, struct parallel_io, refcnt);
+
+       dprintk("%s enter\n", __func__);
+       p->pnfs_callback(p->data);
+       kfree(p);
+}
+
+static inline void put_parallel(struct parallel_io *p)
+{
+       kref_put(&p->refcnt, destroy_parallel);
+}
+
+static struct bio *
+bl_submit_bio(int rw, struct bio *bio)
+{
+       if (bio) {
+               get_parallel(bio->bi_private);
+               dprintk("%s submitting %s bio %u@%llu\n", __func__,
+                       rw == READ ? "read" : "write",
+                       bio->bi_size, (unsigned long long)bio->bi_sector);
+               submit_bio(rw, bio);
+       }
+       return NULL;
+}
+
+static struct bio *bl_alloc_init_bio(int npg, sector_t isect,
+                                    struct pnfs_block_extent *be,
+                                    void (*end_io)(struct bio *, int err),
+                                    struct parallel_io *par)
+{
+       struct bio *bio;
+
+       bio = bio_alloc(GFP_NOIO, npg);
+       if (!bio)
+               return NULL;
+
+       bio->bi_sector = isect - be->be_f_offset + be->be_v_offset;
+       bio->bi_bdev = be->be_mdev;
+       bio->bi_end_io = end_io;
+       bio->bi_private = par;
+       return bio;
+}
+
+static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw,
+                                     sector_t isect, struct page *page,
+                                     struct pnfs_block_extent *be,
+                                     void (*end_io)(struct bio *, int err),
+                                     struct parallel_io *par)
+{
+retry:
+       if (!bio) {
+               bio = bl_alloc_init_bio(npg, isect, be, end_io, par);
+               if (!bio)
+                       return ERR_PTR(-ENOMEM);
+       }
+       if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
+               bio = bl_submit_bio(rw, bio);
+               goto retry;
+       }
+       return bio;
+}
+
+static void bl_set_lo_fail(struct pnfs_layout_segment *lseg)
+{
+       if (lseg->pls_range.iomode == IOMODE_RW) {
+               dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__);
+               set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
+       } else {
+               dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__);
+               set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
+       }
+}
+
+/* This is basically copied from mpage_end_io_read */
+static void bl_end_io_read(struct bio *bio, int err)
+{
+       struct parallel_io *par = bio->bi_private;
+       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct nfs_read_data *rdata = (struct nfs_read_data *)par->data;
+
+       do {
+               struct page *page = bvec->bv_page;
+
+               if (--bvec >= bio->bi_io_vec)
+                       prefetchw(&bvec->bv_page->flags);
+               if (uptodate)
+                       SetPageUptodate(page);
+       } while (bvec >= bio->bi_io_vec);
+       if (!uptodate) {
+               if (!rdata->pnfs_error)
+                       rdata->pnfs_error = -EIO;
+               bl_set_lo_fail(rdata->lseg);
+       }
+       bio_put(bio);
+       put_parallel(par);
+}
+
+static void bl_read_cleanup(struct work_struct *work)
+{
+       struct rpc_task *task;
+       struct nfs_read_data *rdata;
+       dprintk("%s enter\n", __func__);
+       task = container_of(work, struct rpc_task, u.tk_work);
+       rdata = container_of(task, struct nfs_read_data, task);
+       pnfs_ld_read_done(rdata);
+}
+
+static void
+bl_end_par_io_read(void *data)
+{
+       struct nfs_read_data *rdata = data;
+
+       INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup);
+       schedule_work(&rdata->task.u.tk_work);
+}
+
+/* We don't want normal .rpc_call_done callback used, so we replace it
+ * with this stub.
+ */
+static void bl_rpc_do_nothing(struct rpc_task *task, void *calldata)
+{
+       return;
+}
+
+static enum pnfs_try_status
+bl_read_pagelist(struct nfs_read_data *rdata)
+{
+       int i, hole;
+       struct bio *bio = NULL;
+       struct pnfs_block_extent *be = NULL, *cow_read = NULL;
+       sector_t isect, extent_length = 0;
+       struct parallel_io *par;
+       loff_t f_offset = rdata->args.offset;
+       size_t count = rdata->args.count;
+       struct page **pages = rdata->args.pages;
+       int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT;
+
+       dprintk("%s enter nr_pages %u offset %lld count %Zd\n", __func__,
+              rdata->npages, f_offset, count);
+
+       par = alloc_parallel(rdata);
+       if (!par)
+               goto use_mds;
+       par->call_ops = *rdata->mds_ops;
+       par->call_ops.rpc_call_done = bl_rpc_do_nothing;
+       par->pnfs_callback = bl_end_par_io_read;
+       /* At this point, we can no longer jump to use_mds */
+
+       isect = (sector_t) (f_offset >> SECTOR_SHIFT);
+       /* Code assumes extents are page-aligned */
+       for (i = pg_index; i < rdata->npages; i++) {
+               if (!extent_length) {
+                       /* We've used up the previous extent */
+                       bl_put_extent(be);
+                       bl_put_extent(cow_read);
+                       bio = bl_submit_bio(READ, bio);
+                       /* Get the next one */
+                       be = bl_find_get_extent(BLK_LSEG2EXT(rdata->lseg),
+                                            isect, &cow_read);
+                       if (!be) {
+                               rdata->pnfs_error = -EIO;
+                               goto out;
+                       }
+                       extent_length = be->be_length -
+                               (isect - be->be_f_offset);
+                       if (cow_read) {
+                               sector_t cow_length = cow_read->be_length -
+                                       (isect - cow_read->be_f_offset);
+                               extent_length = min(extent_length, cow_length);
+                       }
+               }
+               hole = is_hole(be, isect);
+               if (hole && !cow_read) {
+                       bio = bl_submit_bio(READ, bio);
+                       /* Fill hole w/ zeroes w/o accessing device */
+                       dprintk("%s Zeroing page for hole\n", __func__);
+                       zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE);
+                       print_page(pages[i]);
+                       SetPageUptodate(pages[i]);
+               } else {
+                       struct pnfs_block_extent *be_read;
+
+                       be_read = (hole && cow_read) ? cow_read : be;
+                       bio = bl_add_page_to_bio(bio, rdata->npages - i, READ,
+                                                isect, pages[i], be_read,
+                                                bl_end_io_read, par);
+                       if (IS_ERR(bio)) {
+                               rdata->pnfs_error = PTR_ERR(bio);
+                               goto out;
+                       }
+               }
+               isect += PAGE_CACHE_SECTORS;
+               extent_length -= PAGE_CACHE_SECTORS;
+       }
+       if ((isect << SECTOR_SHIFT) >= rdata->inode->i_size) {
+               rdata->res.eof = 1;
+               rdata->res.count = rdata->inode->i_size - f_offset;
+       } else {
+               rdata->res.count = (isect << SECTOR_SHIFT) - f_offset;
+       }
+out:
+       bl_put_extent(be);
+       bl_put_extent(cow_read);
+       bl_submit_bio(READ, bio);
+       put_parallel(par);
+       return PNFS_ATTEMPTED;
+
+ use_mds:
+       dprintk("Giving up and using normal NFS\n");
+       return PNFS_NOT_ATTEMPTED;
+}
+
+static void mark_extents_written(struct pnfs_block_layout *bl,
+                                __u64 offset, __u32 count)
+{
+       sector_t isect, end;
+       struct pnfs_block_extent *be;
+
+       dprintk("%s(%llu, %u)\n", __func__, offset, count);
+       if (count == 0)
+               return;
+       isect = (offset & (long)(PAGE_CACHE_MASK)) >> SECTOR_SHIFT;
+       end = (offset + count + PAGE_CACHE_SIZE - 1) & (long)(PAGE_CACHE_MASK);
+       end >>= SECTOR_SHIFT;
+       while (isect < end) {
+               sector_t len;
+               be = bl_find_get_extent(bl, isect, NULL);
+               BUG_ON(!be); /* FIXME */
+               len = min(end, be->be_f_offset + be->be_length) - isect;
+               if (be->be_state == PNFS_BLOCK_INVALID_DATA)
+                       bl_mark_for_commit(be, isect, len); /* What if fails? */
+               isect += len;
+               bl_put_extent(be);
+       }
+}
+
+static void bl_end_io_write_zero(struct bio *bio, int err)
+{
+       struct parallel_io *par = bio->bi_private;
+       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct nfs_write_data *wdata = (struct nfs_write_data *)par->data;
+
+       do {
+               struct page *page = bvec->bv_page;
+
+               if (--bvec >= bio->bi_io_vec)
+                       prefetchw(&bvec->bv_page->flags);
+               /* This is the zeroing page we added */
+               end_page_writeback(page);
+               page_cache_release(page);
+       } while (bvec >= bio->bi_io_vec);
+       if (!uptodate) {
+               if (!wdata->pnfs_error)
+                       wdata->pnfs_error = -EIO;
+               bl_set_lo_fail(wdata->lseg);
+       }
+       bio_put(bio);
+       put_parallel(par);
+}
+
+/* This is basically copied from mpage_end_io_read */
+static void bl_end_io_write(struct bio *bio, int err)
+{
+       struct parallel_io *par = bio->bi_private;
+       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       struct nfs_write_data *wdata = (struct nfs_write_data *)par->data;
+
+       if (!uptodate) {
+               if (!wdata->pnfs_error)
+                       wdata->pnfs_error = -EIO;
+               bl_set_lo_fail(wdata->lseg);
+       }
+       bio_put(bio);
+       put_parallel(par);
+}
+
+/* Function scheduled for call during bl_end_par_io_write,
+ * it marks sectors as written and extends the commitlist.
+ */
+static void bl_write_cleanup(struct work_struct *work)
+{
+       struct rpc_task *task;
+       struct nfs_write_data *wdata;
+       dprintk("%s enter\n", __func__);
+       task = container_of(work, struct rpc_task, u.tk_work);
+       wdata = container_of(task, struct nfs_write_data, task);
+       if (!wdata->pnfs_error) {
+               /* Marks for LAYOUTCOMMIT */
+               mark_extents_written(BLK_LSEG2EXT(wdata->lseg),
+                                    wdata->args.offset, wdata->args.count);
+       }
+       pnfs_ld_write_done(wdata);
+}
+
+/* Called when last of bios associated with a bl_write_pagelist call finishes */
+static void bl_end_par_io_write(void *data)
+{
+       struct nfs_write_data *wdata = data;
+
+       wdata->task.tk_status = 0;
+       wdata->verf.committed = NFS_FILE_SYNC;
+       INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup);
+       schedule_work(&wdata->task.u.tk_work);
+}
+
+/* FIXME STUB - mark intersection of layout and page as bad, so is not
+ * used again.
+ */
+static void mark_bad_read(void)
+{
+       return;
+}
+
+/*
+ * map_block:  map a requested I/0 block (isect) into an offset in the LVM
+ * block_device
+ */
+static void
+map_block(struct buffer_head *bh, sector_t isect, struct pnfs_block_extent *be)
+{
+       dprintk("%s enter be=%p\n", __func__, be);
+
+       set_buffer_mapped(bh);
+       bh->b_bdev = be->be_mdev;
+       bh->b_blocknr = (isect - be->be_f_offset + be->be_v_offset) >>
+           (be->be_mdev->bd_inode->i_blkbits - SECTOR_SHIFT);
+
+       dprintk("%s isect %llu, bh->b_blocknr %ld, using bsize %Zd\n",
+               __func__, (unsigned long long)isect, (long)bh->b_blocknr,
+               bh->b_size);
+       return;
+}
+
+/* Given an unmapped page, zero it or read in page for COW, page is locked
+ * by caller.
+ */
+static int
+init_page_for_write(struct page *page, struct pnfs_block_extent *cow_read)
+{
+       struct buffer_head *bh = NULL;
+       int ret = 0;
+       sector_t isect;
+
+       dprintk("%s enter, %p\n", __func__, page);
+       BUG_ON(PageUptodate(page));
+       if (!cow_read) {
+               zero_user_segment(page, 0, PAGE_SIZE);
+               SetPageUptodate(page);
+               goto cleanup;
+       }
+
+       bh = alloc_page_buffers(page, PAGE_CACHE_SIZE, 0);
+       if (!bh) {
+               ret = -ENOMEM;
+               goto cleanup;
+       }
+
+       isect = (sector_t) page->index << PAGE_CACHE_SECTOR_SHIFT;
+       map_block(bh, isect, cow_read);
+       if (!bh_uptodate_or_lock(bh))
+               ret = bh_submit_read(bh);
+       if (ret)
+               goto cleanup;
+       SetPageUptodate(page);
+
+cleanup:
+       bl_put_extent(cow_read);
+       if (bh)
+               free_buffer_head(bh);
+       if (ret) {
+               /* Need to mark layout with bad read...should now
+                * just use nfs4 for reads and writes.
+                */
+               mark_bad_read();
+       }
+       return ret;
+}
+
+static enum pnfs_try_status
+bl_write_pagelist(struct nfs_write_data *wdata, int sync)
+{
+       int i, ret, npg_zero, pg_index, last = 0;
+       struct bio *bio = NULL;
+       struct pnfs_block_extent *be = NULL, *cow_read = NULL;
+       sector_t isect, last_isect = 0, extent_length = 0;
+       struct parallel_io *par;
+       loff_t offset = wdata->args.offset;
+       size_t count = wdata->args.count;
+       struct page **pages = wdata->args.pages;
+       struct page *page;
+       pgoff_t index;
+       u64 temp;
+       int npg_per_block =
+           NFS_SERVER(wdata->inode)->pnfs_blksize >> PAGE_CACHE_SHIFT;
+
+       dprintk("%s enter, %Zu@%lld\n", __func__, count, offset);
+       /* At this point, wdata->pages is a (sequential) list of nfs_pages.
+        * We want to write each, and if there is an error set pnfs_error
+        * to have it redone using nfs.
+        */
+       par = alloc_parallel(wdata);
+       if (!par)
+               return PNFS_NOT_ATTEMPTED;
+       par->call_ops = *wdata->mds_ops;
+       par->call_ops.rpc_call_done = bl_rpc_do_nothing;
+       par->pnfs_callback = bl_end_par_io_write;
+       /* At this point, have to be more careful with error handling */
+
+       isect = (sector_t) ((offset & (long)PAGE_CACHE_MASK) >> SECTOR_SHIFT);
+       be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg), isect, &cow_read);
+       if (!be || !is_writable(be, isect)) {
+               dprintk("%s no matching extents!\n", __func__);
+               wdata->pnfs_error = -EINVAL;
+               goto out;
+       }
+
+       /* First page inside INVALID extent */
+       if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+               temp = offset >> PAGE_CACHE_SHIFT;
+               npg_zero = do_div(temp, npg_per_block);
+               isect = (sector_t) (((offset - npg_zero * PAGE_CACHE_SIZE) &
+                                    (long)PAGE_CACHE_MASK) >> SECTOR_SHIFT);
+               extent_length = be->be_length - (isect - be->be_f_offset);
+
+fill_invalid_ext:
+               dprintk("%s need to zero %d pages\n", __func__, npg_zero);
+               for (;npg_zero > 0; npg_zero--) {
+                       /* page ref released in bl_end_io_write_zero */
+                       index = isect >> PAGE_CACHE_SECTOR_SHIFT;
+                       dprintk("%s zero %dth page: index %lu isect %llu\n",
+                               __func__, npg_zero, index,
+                               (unsigned long long)isect);
+                       page =
+                           find_or_create_page(wdata->inode->i_mapping, index,
+                                               GFP_NOFS);
+                       if (!page) {
+                               dprintk("%s oom\n", __func__);
+                               wdata->pnfs_error = -ENOMEM;
+                               goto out;
+                       }
+
+                       /* PageDirty: Other will write this out
+                        * PageWriteback: Other is writing this out
+                        * PageUptodate: It was read before
+                        * sector_initialized: already written out
+                        */
+                       if (PageDirty(page) || PageWriteback(page) ||
+                           bl_is_sector_init(be->be_inval, isect)) {
+                               print_page(page);
+                               unlock_page(page);
+                               page_cache_release(page);
+                               goto next_page;
+                       }
+                       if (!PageUptodate(page)) {
+                               /* New page, readin or zero it */
+                               init_page_for_write(page, cow_read);
+                       }
+                       set_page_writeback(page);
+                       unlock_page(page);
+
+                       ret = bl_mark_sectors_init(be->be_inval, isect,
+                                                      PAGE_CACHE_SECTORS,
+                                                      NULL);
+                       if (unlikely(ret)) {
+                               dprintk("%s bl_mark_sectors_init fail %d\n",
+                                       __func__, ret);
+                               end_page_writeback(page);
+                               page_cache_release(page);
+                               wdata->pnfs_error = ret;
+                               goto out;
+                       }
+                       bio = bl_add_page_to_bio(bio, npg_zero, WRITE,
+                                                isect, page, be,
+                                                bl_end_io_write_zero, par);
+                       if (IS_ERR(bio)) {
+                               wdata->pnfs_error = PTR_ERR(bio);
+                               goto out;
+                       }
+                       /* FIXME: This should be done in bi_end_io */
+                       mark_extents_written(BLK_LSEG2EXT(wdata->lseg),
+                                            page->index << PAGE_CACHE_SHIFT,
+                                            PAGE_CACHE_SIZE);
+next_page:
+                       isect += PAGE_CACHE_SECTORS;
+                       extent_length -= PAGE_CACHE_SECTORS;
+               }
+               if (last)
+                       goto write_done;
+       }
+       bio = bl_submit_bio(WRITE, bio);
+
+       /* Middle pages */
+       pg_index = wdata->args.pgbase >> PAGE_CACHE_SHIFT;
+       for (i = pg_index; i < wdata->npages; i++) {
+               if (!extent_length) {
+                       /* We've used up the previous extent */
+                       bl_put_extent(be);
+                       bio = bl_submit_bio(WRITE, bio);
+                       /* Get the next one */
+                       be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg),
+                                            isect, NULL);
+                       if (!be || !is_writable(be, isect)) {
+                               wdata->pnfs_error = -EINVAL;
+                               goto out;
+                       }
+                       extent_length = be->be_length -
+                           (isect - be->be_f_offset);
+               }
+               if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+                       ret = bl_mark_sectors_init(be->be_inval, isect,
+                                                      PAGE_CACHE_SECTORS,
+                                                      NULL);
+                       if (unlikely(ret)) {
+                               dprintk("%s bl_mark_sectors_init fail %d\n",
+                                       __func__, ret);
+                               wdata->pnfs_error = ret;
+                               goto out;
+                       }
+               }
+               bio = bl_add_page_to_bio(bio, wdata->npages - i, WRITE,
+                                        isect, pages[i], be,
+                                        bl_end_io_write, par);
+               if (IS_ERR(bio)) {
+                       wdata->pnfs_error = PTR_ERR(bio);
+                       goto out;
+               }
+               isect += PAGE_CACHE_SECTORS;
+               last_isect = isect;
+               extent_length -= PAGE_CACHE_SECTORS;
+       }
+
+       /* Last page inside INVALID extent */
+       if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+               bio = bl_submit_bio(WRITE, bio);
+               temp = last_isect >> PAGE_CACHE_SECTOR_SHIFT;
+               npg_zero = npg_per_block - do_div(temp, npg_per_block);
+               if (npg_zero < npg_per_block) {
+                       last = 1;
+                       goto fill_invalid_ext;
+               }
+       }
+
+write_done:
+       wdata->res.count = (last_isect << SECTOR_SHIFT) - (offset);
+       if (count < wdata->res.count) {
+               wdata->res.count = count;
+       }
+out:
+       bl_put_extent(be);
+       bl_submit_bio(WRITE, bio);
+       put_parallel(par);
+       return PNFS_ATTEMPTED;
+}
+
+/* FIXME - range ignored */
+static void
+release_extents(struct pnfs_block_layout *bl, struct pnfs_layout_range *range)
+{
+       int i;
+       struct pnfs_block_extent *be;
+
+       spin_lock(&bl->bl_ext_lock);
+       for (i = 0; i < EXTENT_LISTS; i++) {
+               while (!list_empty(&bl->bl_extents[i])) {
+                       be = list_first_entry(&bl->bl_extents[i],
+                                             struct pnfs_block_extent,
+                                             be_node);
+                       list_del(&be->be_node);
+                       bl_put_extent(be);
+               }
+       }
+       spin_unlock(&bl->bl_ext_lock);
+}
+
+static void
+release_inval_marks(struct pnfs_inval_markings *marks)
+{
+       struct pnfs_inval_tracking *pos, *temp;
+
+       list_for_each_entry_safe(pos, temp, &marks->im_tree.mtt_stub, it_link) {
+               list_del(&pos->it_link);
+               kfree(pos);
+       }
+       return;
+}
+
+static void bl_free_layout_hdr(struct pnfs_layout_hdr *lo)
+{
+       struct pnfs_block_layout *bl = BLK_LO2EXT(lo);
+
+       dprintk("%s enter\n", __func__);
+       release_extents(bl, NULL);
+       release_inval_marks(&bl->bl_inval);
+       kfree(bl);
+}
+
+static struct pnfs_layout_hdr *bl_alloc_layout_hdr(struct inode *inode,
+                                                  gfp_t gfp_flags)
+{
+       struct pnfs_block_layout *bl;
+
+       dprintk("%s enter\n", __func__);
+       bl = kzalloc(sizeof(*bl), gfp_flags);
+       if (!bl)
+               return NULL;
+       spin_lock_init(&bl->bl_ext_lock);
+       INIT_LIST_HEAD(&bl->bl_extents[0]);
+       INIT_LIST_HEAD(&bl->bl_extents[1]);
+       INIT_LIST_HEAD(&bl->bl_commit);
+       INIT_LIST_HEAD(&bl->bl_committing);
+       bl->bl_count = 0;
+       bl->bl_blocksize = NFS_SERVER(inode)->pnfs_blksize >> SECTOR_SHIFT;
+       BL_INIT_INVAL_MARKS(&bl->bl_inval, bl->bl_blocksize);
+       return &bl->bl_layout;
+}
+
+static void bl_free_lseg(struct pnfs_layout_segment *lseg)
+{
+       dprintk("%s enter\n", __func__);
+       kfree(lseg);
+}
+
+/* We pretty much ignore lseg, and store all data layout wide, so we
+ * can correctly merge.
+ */
+static struct pnfs_layout_segment *bl_alloc_lseg(struct pnfs_layout_hdr *lo,
+                                                struct nfs4_layoutget_res *lgr,
+                                                gfp_t gfp_flags)
+{
+       struct pnfs_layout_segment *lseg;
+       int status;
+
+       dprintk("%s enter\n", __func__);
+       lseg = kzalloc(sizeof(*lseg), gfp_flags);
+       if (!lseg)
+               return ERR_PTR(-ENOMEM);
+       status = nfs4_blk_process_layoutget(lo, lgr, gfp_flags);
+       if (status) {
+               /* We don't want to call the full-blown bl_free_lseg,
+                * since on error extents were not touched.
+                */
+               kfree(lseg);
+               return ERR_PTR(status);
+       }
+       return lseg;
+}
+
+static void
+bl_encode_layoutcommit(struct pnfs_layout_hdr *lo, struct xdr_stream *xdr,
+                      const struct nfs4_layoutcommit_args *arg)
+{
+       dprintk("%s enter\n", __func__);
+       encode_pnfs_block_layoutupdate(BLK_LO2EXT(lo), xdr, arg);
+}
+
+static void
+bl_cleanup_layoutcommit(struct nfs4_layoutcommit_data *lcdata)
+{
+       struct pnfs_layout_hdr *lo = NFS_I(lcdata->args.inode)->layout;
+
+       dprintk("%s enter\n", __func__);
+       clean_pnfs_block_layoutupdate(BLK_LO2EXT(lo), &lcdata->args, lcdata->res.status);
+}
+
+static void free_blk_mountid(struct block_mount_id *mid)
+{
+       if (mid) {
+               struct pnfs_block_dev *dev;
+               spin_lock(&mid->bm_lock);
+               while (!list_empty(&mid->bm_devlist)) {
+                       dev = list_first_entry(&mid->bm_devlist,
+                                              struct pnfs_block_dev,
+                                              bm_node);
+                       list_del(&dev->bm_node);
+                       bl_free_block_dev(dev);
+               }
+               spin_unlock(&mid->bm_lock);
+               kfree(mid);
+       }
+}
+
+/* This is mostly copied from the filelayout's get_device_info function.
+ * It seems much of this should be at the generic pnfs level.
+ */
+static struct pnfs_block_dev *
+nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh,
+                       struct nfs4_deviceid *d_id)
+{
+       struct pnfs_device *dev;
+       struct pnfs_block_dev *rv = NULL;
+       u32 max_resp_sz;
+       int max_pages;
+       struct page **pages = NULL;
+       int i, rc;
+
+       /*
+        * Use the session max response size as the basis for setting
+        * GETDEVICEINFO's maxcount
+        */
+       max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
+       max_pages = max_resp_sz >> PAGE_SHIFT;
+       dprintk("%s max_resp_sz %u max_pages %d\n",
+               __func__, max_resp_sz, max_pages);
+
+       dev = kmalloc(sizeof(*dev), GFP_NOFS);
+       if (!dev) {
+               dprintk("%s kmalloc failed\n", __func__);
+               return NULL;
+       }
+
+       pages = kzalloc(max_pages * sizeof(struct page *), GFP_NOFS);
+       if (pages == NULL) {
+               kfree(dev);
+               return NULL;
+       }
+       for (i = 0; i < max_pages; i++) {
+               pages[i] = alloc_page(GFP_NOFS);
+               if (!pages[i])
+                       goto out_free;
+       }
+
+       memcpy(&dev->dev_id, d_id, sizeof(*d_id));
+       dev->layout_type = LAYOUT_BLOCK_VOLUME;
+       dev->pages = pages;
+       dev->pgbase = 0;
+       dev->pglen = PAGE_SIZE * max_pages;
+       dev->mincount = 0;
+
+       dprintk("%s: dev_id: %s\n", __func__, dev->dev_id.data);
+       rc = nfs4_proc_getdeviceinfo(server, dev);
+       dprintk("%s getdevice info returns %d\n", __func__, rc);
+       if (rc)
+               goto out_free;
+
+       rv = nfs4_blk_decode_device(server, dev);
+ out_free:
+       for (i = 0; i < max_pages; i++)
+               __free_page(pages[i]);
+       kfree(pages);
+       kfree(dev);
+       return rv;
+}
+
+static int
+bl_set_layoutdriver(struct nfs_server *server, const struct nfs_fh *fh)
+{
+       struct block_mount_id *b_mt_id = NULL;
+       struct pnfs_devicelist *dlist = NULL;
+       struct pnfs_block_dev *bdev;
+       LIST_HEAD(block_disklist);
+       int status = 0, i;
+
+       dprintk("%s enter\n", __func__);
+
+       if (server->pnfs_blksize == 0) {
+               dprintk("%s Server did not return blksize\n", __func__);
+               return -EINVAL;
+       }
+       b_mt_id = kzalloc(sizeof(struct block_mount_id), GFP_NOFS);
+       if (!b_mt_id) {
+               status = -ENOMEM;
+               goto out_error;
+       }
+       /* Initialize nfs4 block layout mount id */
+       spin_lock_init(&b_mt_id->bm_lock);
+       INIT_LIST_HEAD(&b_mt_id->bm_devlist);
+
+       dlist = kmalloc(sizeof(struct pnfs_devicelist), GFP_NOFS);
+       if (!dlist) {
+               status = -ENOMEM;
+               goto out_error;
+       }
+       dlist->eof = 0;
+       while (!dlist->eof) {
+               status = nfs4_proc_getdevicelist(server, fh, dlist);
+               if (status)
+                       goto out_error;
+               dprintk("%s GETDEVICELIST numdevs=%i, eof=%i\n",
+                       __func__, dlist->num_devs, dlist->eof);
+               for (i = 0; i < dlist->num_devs; i++) {
+                       bdev = nfs4_blk_get_deviceinfo(server, fh,
+                                                      &dlist->dev_id[i]);
+                       if (!bdev) {
+                               status = -ENODEV;
+                               goto out_error;
+                       }
+                       spin_lock(&b_mt_id->bm_lock);
+                       list_add(&bdev->bm_node, &b_mt_id->bm_devlist);
+                       spin_unlock(&b_mt_id->bm_lock);
+               }
+       }
+       dprintk("%s SUCCESS\n", __func__);
+       server->pnfs_ld_data = b_mt_id;
+
+ out_return:
+       kfree(dlist);
+       return status;
+
+ out_error:
+       free_blk_mountid(b_mt_id);
+       goto out_return;
+}
+
+static int
+bl_clear_layoutdriver(struct nfs_server *server)
+{
+       struct block_mount_id *b_mt_id = server->pnfs_ld_data;
+
+       dprintk("%s enter\n", __func__);
+       free_blk_mountid(b_mt_id);
+       dprintk("%s RETURNS\n", __func__);
+       return 0;
+}
+
+static const struct nfs_pageio_ops bl_pg_read_ops = {
+       .pg_init = pnfs_generic_pg_init_read,
+       .pg_test = pnfs_generic_pg_test,
+       .pg_doio = pnfs_generic_pg_readpages,
+};
+
+static const struct nfs_pageio_ops bl_pg_write_ops = {
+       .pg_init = pnfs_generic_pg_init_write,
+       .pg_test = pnfs_generic_pg_test,
+       .pg_doio = pnfs_generic_pg_writepages,
+};
+
+static struct pnfs_layoutdriver_type blocklayout_type = {
+       .id                             = LAYOUT_BLOCK_VOLUME,
+       .name                           = "LAYOUT_BLOCK_VOLUME",
+       .read_pagelist                  = bl_read_pagelist,
+       .write_pagelist                 = bl_write_pagelist,
+       .alloc_layout_hdr               = bl_alloc_layout_hdr,
+       .free_layout_hdr                = bl_free_layout_hdr,
+       .alloc_lseg                     = bl_alloc_lseg,
+       .free_lseg                      = bl_free_lseg,
+       .encode_layoutcommit            = bl_encode_layoutcommit,
+       .cleanup_layoutcommit           = bl_cleanup_layoutcommit,
+       .set_layoutdriver               = bl_set_layoutdriver,
+       .clear_layoutdriver             = bl_clear_layoutdriver,
+       .pg_read_ops                    = &bl_pg_read_ops,
+       .pg_write_ops                   = &bl_pg_write_ops,
+};
+
+static const struct rpc_pipe_ops bl_upcall_ops = {
+       .upcall         = bl_pipe_upcall,
+       .downcall       = bl_pipe_downcall,
+       .destroy_msg    = bl_pipe_destroy_msg,
+};
+
+static int __init nfs4blocklayout_init(void)
+{
+       struct vfsmount *mnt;
+       struct path path;
+       int ret;
+
+       dprintk("%s: NFSv4 Block Layout Driver Registering...\n", __func__);
+
+       ret = pnfs_register_layoutdriver(&blocklayout_type);
+       if (ret)
+               goto out;
+
+       init_waitqueue_head(&bl_wq);
+
+       mnt = rpc_get_mount();
+       if (IS_ERR(mnt)) {
+               ret = PTR_ERR(mnt);
+               goto out_remove;
+       }
+
+       ret = vfs_path_lookup(mnt->mnt_root,
+                             mnt,
+                             NFS_PIPE_DIRNAME, 0, &path);
+       if (ret)
+               goto out_remove;
+
+       bl_device_pipe = rpc_mkpipe(path.dentry, "blocklayout", NULL,
+                                   &bl_upcall_ops, 0);
+       if (IS_ERR(bl_device_pipe)) {
+               ret = PTR_ERR(bl_device_pipe);
+               goto out_remove;
+       }
+out:
+       return ret;
+
+out_remove:
+       pnfs_unregister_layoutdriver(&blocklayout_type);
+       return ret;
+}
+
+static void __exit nfs4blocklayout_exit(void)
+{
+       dprintk("%s: NFSv4 Block Layout Driver Unregistering...\n",
+              __func__);
+
+       pnfs_unregister_layoutdriver(&blocklayout_type);
+       rpc_unlink(bl_device_pipe);
+}
+
+MODULE_ALIAS("nfs-layouttype4-3");
+
+module_init(nfs4blocklayout_init);
+module_exit(nfs4blocklayout_exit);
diff --git a/fs/nfs/blocklayout/blocklayout.h b/fs/nfs/blocklayout/blocklayout.h
new file mode 100644 (file)
index 0000000..f27d827
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ *  linux/fs/nfs/blocklayout/blocklayout.h
+ *
+ *  Module for the NFSv4.1 pNFS block layout driver.
+ *
+ *  Copyright (c) 2006 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@citi.umich.edu>
+ *  Fred Isaman <iisaman@umich.edu>
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.  if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+#ifndef FS_NFS_NFS4BLOCKLAYOUT_H
+#define FS_NFS_NFS4BLOCKLAYOUT_H
+
+#include <linux/device-mapper.h>
+#include <linux/nfs_fs.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
+
+#include "../pnfs.h"
+
+#define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT)
+#define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
+
+struct block_mount_id {
+       spinlock_t                      bm_lock;    /* protects list */
+       struct list_head                bm_devlist; /* holds pnfs_block_dev */
+};
+
+struct pnfs_block_dev {
+       struct list_head                bm_node;
+       struct nfs4_deviceid            bm_mdevid;    /* associated devid */
+       struct block_device             *bm_mdev;     /* meta device itself */
+};
+
+enum exstate4 {
+       PNFS_BLOCK_READWRITE_DATA       = 0,
+       PNFS_BLOCK_READ_DATA            = 1,
+       PNFS_BLOCK_INVALID_DATA         = 2, /* mapped, but data is invalid */
+       PNFS_BLOCK_NONE_DATA            = 3  /* unmapped, it's a hole */
+};
+
+#define MY_MAX_TAGS (15) /* tag bitnums used must be less than this */
+
+struct my_tree {
+       sector_t                mtt_step_size;  /* Internal sector alignment */
+       struct list_head        mtt_stub; /* Should be a radix tree */
+};
+
+struct pnfs_inval_markings {
+       spinlock_t      im_lock;
+       struct my_tree  im_tree;        /* Sectors that need LAYOUTCOMMIT */
+       sector_t        im_block_size;  /* Server blocksize in sectors */
+};
+
+struct pnfs_inval_tracking {
+       struct list_head it_link;
+       int              it_sector;
+       int              it_tags;
+};
+
+/* sector_t fields are all in 512-byte sectors */
+struct pnfs_block_extent {
+       struct kref     be_refcnt;
+       struct list_head be_node;       /* link into lseg list */
+       struct nfs4_deviceid be_devid;  /* FIXME: could use device cache instead */
+       struct block_device *be_mdev;
+       sector_t        be_f_offset;    /* the starting offset in the file */
+       sector_t        be_length;      /* the size of the extent */
+       sector_t        be_v_offset;    /* the starting offset in the volume */
+       enum exstate4   be_state;       /* the state of this extent */
+       struct pnfs_inval_markings *be_inval; /* tracks INVAL->RW transition */
+};
+
+/* Shortened extent used by LAYOUTCOMMIT */
+struct pnfs_block_short_extent {
+       struct list_head bse_node;
+       struct nfs4_deviceid bse_devid;
+       struct block_device *bse_mdev;
+       sector_t        bse_f_offset;   /* the starting offset in the file */
+       sector_t        bse_length;     /* the size of the extent */
+};
+
+static inline void
+BL_INIT_INVAL_MARKS(struct pnfs_inval_markings *marks, sector_t blocksize)
+{
+       spin_lock_init(&marks->im_lock);
+       INIT_LIST_HEAD(&marks->im_tree.mtt_stub);
+       marks->im_block_size = blocksize;
+       marks->im_tree.mtt_step_size = min((sector_t)PAGE_CACHE_SECTORS,
+                                          blocksize);
+}
+
+enum extentclass4 {
+       RW_EXTENT       = 0, /* READWRTE and INVAL */
+       RO_EXTENT       = 1, /* READ and NONE */
+       EXTENT_LISTS    = 2,
+};
+
+static inline int bl_choose_list(enum exstate4 state)
+{
+       if (state == PNFS_BLOCK_READ_DATA || state == PNFS_BLOCK_NONE_DATA)
+               return RO_EXTENT;
+       else
+               return RW_EXTENT;
+}
+
+struct pnfs_block_layout {
+       struct pnfs_layout_hdr bl_layout;
+       struct pnfs_inval_markings bl_inval; /* tracks INVAL->RW transition */
+       spinlock_t              bl_ext_lock;   /* Protects list manipulation */
+       struct list_head        bl_extents[EXTENT_LISTS]; /* R and RW extents */
+       struct list_head        bl_commit;      /* Needs layout commit */
+       struct list_head        bl_committing;  /* Layout committing */
+       unsigned int            bl_count;       /* entries in bl_commit */
+       sector_t                bl_blocksize;  /* Server blocksize in sectors */
+};
+
+#define BLK_ID(lo) ((struct block_mount_id *)(NFS_SERVER(lo->plh_inode)->pnfs_ld_data))
+
+static inline struct pnfs_block_layout *
+BLK_LO2EXT(struct pnfs_layout_hdr *lo)
+{
+       return container_of(lo, struct pnfs_block_layout, bl_layout);
+}
+
+static inline struct pnfs_block_layout *
+BLK_LSEG2EXT(struct pnfs_layout_segment *lseg)
+{
+       return BLK_LO2EXT(lseg->pls_layout);
+}
+
+struct bl_dev_msg {
+       int status;
+       uint32_t major, minor;
+};
+
+struct bl_msg_hdr {
+       u8  type;
+       u16 totallen; /* length of entire message, including hdr itself */
+};
+
+extern struct dentry *bl_device_pipe;
+extern wait_queue_head_t bl_wq;
+
+#define BL_DEVICE_UMOUNT               0x0 /* Umount--delete devices */
+#define BL_DEVICE_MOUNT                0x1 /* Mount--create devices*/
+#define BL_DEVICE_REQUEST_INIT         0x0 /* Start request */
+#define BL_DEVICE_REQUEST_PROC         0x1 /* User level process succeeds */
+#define BL_DEVICE_REQUEST_ERR          0x2 /* User level process fails */
+
+/* blocklayoutdev.c */
+ssize_t bl_pipe_upcall(struct file *, struct rpc_pipe_msg *,
+                      char __user *, size_t);
+ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t);
+void bl_pipe_destroy_msg(struct rpc_pipe_msg *);
+struct block_device *nfs4_blkdev_get(dev_t dev);
+int nfs4_blkdev_put(struct block_device *bdev);
+struct pnfs_block_dev *nfs4_blk_decode_device(struct nfs_server *server,
+                                               struct pnfs_device *dev);
+int nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
+                               struct nfs4_layoutget_res *lgr, gfp_t gfp_flags);
+
+/* blocklayoutdm.c */
+void bl_free_block_dev(struct pnfs_block_dev *bdev);
+
+/* extents.c */
+struct pnfs_block_extent *
+bl_find_get_extent(struct pnfs_block_layout *bl, sector_t isect,
+               struct pnfs_block_extent **cow_read);
+int bl_mark_sectors_init(struct pnfs_inval_markings *marks,
+                            sector_t offset, sector_t length,
+                            sector_t **pages);
+void bl_put_extent(struct pnfs_block_extent *be);
+struct pnfs_block_extent *bl_alloc_extent(void);
+int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect);
+int encode_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
+                                  struct xdr_stream *xdr,
+                                  const struct nfs4_layoutcommit_args *arg);
+void clean_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
+                                  const struct nfs4_layoutcommit_args *arg,
+                                  int status);
+int bl_add_merge_extent(struct pnfs_block_layout *bl,
+                        struct pnfs_block_extent *new);
+int bl_mark_for_commit(struct pnfs_block_extent *be,
+                       sector_t offset, sector_t length);
+
+#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
diff --git a/fs/nfs/blocklayout/blocklayoutdev.c b/fs/nfs/blocklayout/blocklayoutdev.c
new file mode 100644 (file)
index 0000000..a83b393
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ *  linux/fs/nfs/blocklayout/blocklayoutdev.c
+ *
+ *  Device operations for the pnfs nfs4 file layout driver.
+ *
+ *  Copyright (c) 2006 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@citi.umich.edu>
+ *  Fred Isaman <iisaman@umich.edu>
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.  if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+#include <linux/module.h>
+#include <linux/buffer_head.h> /* __bread */
+
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/hash.h>
+
+#include "blocklayout.h"
+
+#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
+
+static int decode_sector_number(__be32 **rp, sector_t *sp)
+{
+       uint64_t s;
+
+       *rp = xdr_decode_hyper(*rp, &s);
+       if (s & 0x1ff) {
+               printk(KERN_WARNING "%s: sector not aligned\n", __func__);
+               return -1;
+       }
+       *sp = s >> SECTOR_SHIFT;
+       return 0;
+}
+
+/* Open a block_device by device number. */
+struct block_device *nfs4_blkdev_get(dev_t dev)
+{
+       struct block_device *bd;
+
+       dprintk("%s enter\n", __func__);
+       bd = blkdev_get_by_dev(dev, FMODE_READ, NULL);
+       if (IS_ERR(bd))
+               goto fail;
+       return bd;
+fail:
+       dprintk("%s failed to open device : %ld\n",
+                       __func__, PTR_ERR(bd));
+       return NULL;
+}
+
+/*
+ * Release the block device
+ */
+int nfs4_blkdev_put(struct block_device *bdev)
+{
+       dprintk("%s for device %d:%d\n", __func__, MAJOR(bdev->bd_dev),
+                       MINOR(bdev->bd_dev));
+       return blkdev_put(bdev, FMODE_READ);
+}
+
+/*
+ * Shouldn't there be a rpc_generic_upcall() to do this for us?
+ */
+ssize_t bl_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
+                      char __user *dst, size_t buflen)
+{
+       char *data = (char *)msg->data + msg->copied;
+       size_t mlen = min(msg->len - msg->copied, buflen);
+       unsigned long left;
+
+       left = copy_to_user(dst, data, mlen);
+       if (left == mlen) {
+               msg->errno = -EFAULT;
+               return -EFAULT;
+       }
+
+       mlen -= left;
+       msg->copied += mlen;
+       msg->errno = 0;
+       return mlen;
+}
+
+static struct bl_dev_msg bl_mount_reply;
+
+ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
+                        size_t mlen)
+{
+       if (mlen != sizeof (struct bl_dev_msg))
+               return -EINVAL;
+
+       if (copy_from_user(&bl_mount_reply, src, mlen) != 0)
+               return -EFAULT;
+
+       wake_up(&bl_wq);
+
+       return mlen;
+}
+
+void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
+{
+       if (msg->errno >= 0)
+               return;
+       wake_up(&bl_wq);
+}
+
+/*
+ * Decodes pnfs_block_deviceaddr4 which is XDR encoded in dev->dev_addr_buf.
+ */
+struct pnfs_block_dev *
+nfs4_blk_decode_device(struct nfs_server *server,
+                      struct pnfs_device *dev)
+{
+       struct pnfs_block_dev *rv = NULL;
+       struct block_device *bd = NULL;
+       struct rpc_pipe_msg msg;
+       struct bl_msg_hdr bl_msg = {
+               .type = BL_DEVICE_MOUNT,
+               .totallen = dev->mincount,
+       };
+       uint8_t *dataptr;
+       DECLARE_WAITQUEUE(wq, current);
+       struct bl_dev_msg *reply = &bl_mount_reply;
+       int offset, len, i;
+
+       dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
+       dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data,
+               dev->mincount);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS);
+       if (!msg.data) {
+               rv = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+
+       memcpy(msg.data, &bl_msg, sizeof(bl_msg));
+       dataptr = (uint8_t *) msg.data;
+       len = dev->mincount;
+       offset = sizeof(bl_msg);
+       for (i = 0; len > 0; i++) {
+               memcpy(&dataptr[offset], page_address(dev->pages[i]),
+                               len < PAGE_CACHE_SIZE ? len : PAGE_CACHE_SIZE);
+               len -= PAGE_CACHE_SIZE;
+               offset += PAGE_CACHE_SIZE;
+       }
+       msg.len = sizeof(bl_msg) + dev->mincount;
+
+       dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
+       add_wait_queue(&bl_wq, &wq);
+       if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) {
+               remove_wait_queue(&bl_wq, &wq);
+               goto out;
+       }
+
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule();
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&bl_wq, &wq);
+
+       if (reply->status != BL_DEVICE_REQUEST_PROC) {
+               dprintk("%s failed to open device: %d\n",
+                       __func__, reply->status);
+               rv = ERR_PTR(-EINVAL);
+               goto out;
+       }
+
+       bd = nfs4_blkdev_get(MKDEV(reply->major, reply->minor));
+       if (IS_ERR(bd)) {
+               dprintk("%s failed to open device : %ld\n",
+                       __func__, PTR_ERR(bd));
+               goto out;
+       }
+
+       rv = kzalloc(sizeof(*rv), GFP_NOFS);
+       if (!rv) {
+               rv = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+
+       rv->bm_mdev = bd;
+       memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid));
+       dprintk("%s Created device %s with bd_block_size %u\n",
+               __func__,
+               bd->bd_disk->disk_name,
+               bd->bd_block_size);
+
+out:
+       kfree(msg.data);
+       return rv;
+}
+
+/* Map deviceid returned by the server to constructed block_device */
+static struct block_device *translate_devid(struct pnfs_layout_hdr *lo,
+                                           struct nfs4_deviceid *id)
+{
+       struct block_device *rv = NULL;
+       struct block_mount_id *mid;
+       struct pnfs_block_dev *dev;
+
+       dprintk("%s enter, lo=%p, id=%p\n", __func__, lo, id);
+       mid = BLK_ID(lo);
+       spin_lock(&mid->bm_lock);
+       list_for_each_entry(dev, &mid->bm_devlist, bm_node) {
+               if (memcmp(id->data, dev->bm_mdevid.data,
+                          NFS4_DEVICEID4_SIZE) == 0) {
+                       rv = dev->bm_mdev;
+                       goto out;
+               }
+       }
+ out:
+       spin_unlock(&mid->bm_lock);
+       dprintk("%s returning %p\n", __func__, rv);
+       return rv;
+}
+
+/* Tracks info needed to ensure extents in layout obey constraints of spec */
+struct layout_verification {
+       u32 mode;       /* R or RW */
+       u64 start;      /* Expected start of next non-COW extent */
+       u64 inval;      /* Start of INVAL coverage */
+       u64 cowread;    /* End of COW read coverage */
+};
+
+/* Verify the extent meets the layout requirements of the pnfs-block draft,
+ * section 2.3.1.
+ */
+static int verify_extent(struct pnfs_block_extent *be,
+                        struct layout_verification *lv)
+{
+       if (lv->mode == IOMODE_READ) {
+               if (be->be_state == PNFS_BLOCK_READWRITE_DATA ||
+                   be->be_state == PNFS_BLOCK_INVALID_DATA)
+                       return -EIO;
+               if (be->be_f_offset != lv->start)
+                       return -EIO;
+               lv->start += be->be_length;
+               return 0;
+       }
+       /* lv->mode == IOMODE_RW */
+       if (be->be_state == PNFS_BLOCK_READWRITE_DATA) {
+               if (be->be_f_offset != lv->start)
+                       return -EIO;
+               if (lv->cowread > lv->start)
+                       return -EIO;
+               lv->start += be->be_length;
+               lv->inval = lv->start;
+               return 0;
+       } else if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
+               if (be->be_f_offset != lv->start)
+                       return -EIO;
+               lv->start += be->be_length;
+               return 0;
+       } else if (be->be_state == PNFS_BLOCK_READ_DATA) {
+               if (be->be_f_offset > lv->start)
+                       return -EIO;
+               if (be->be_f_offset < lv->inval)
+                       return -EIO;
+               if (be->be_f_offset < lv->cowread)
+                       return -EIO;
+               /* It looks like you might want to min this with lv->start,
+                * but you really don't.
+                */
+               lv->inval = lv->inval + be->be_length;
+               lv->cowread = be->be_f_offset + be->be_length;
+               return 0;
+       } else
+               return -EIO;
+}
+
+/* XDR decode pnfs_block_layout4 structure */
+int
+nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
+                          struct nfs4_layoutget_res *lgr, gfp_t gfp_flags)
+{
+       struct pnfs_block_layout *bl = BLK_LO2EXT(lo);
+       int i, status = -EIO;
+       uint32_t count;
+       struct pnfs_block_extent *be = NULL, *save;
+       struct xdr_stream stream;
+       struct xdr_buf buf;
+       struct page *scratch;
+       __be32 *p;
+       struct layout_verification lv = {
+               .mode = lgr->range.iomode,
+               .start = lgr->range.offset >> SECTOR_SHIFT,
+               .inval = lgr->range.offset >> SECTOR_SHIFT,
+               .cowread = lgr->range.offset >> SECTOR_SHIFT,
+       };
+       LIST_HEAD(extents);
+
+       dprintk("---> %s\n", __func__);
+
+       scratch = alloc_page(gfp_flags);
+       if (!scratch)
+               return -ENOMEM;
+
+       xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
+       xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
+
+       p = xdr_inline_decode(&stream, 4);
+       if (unlikely(!p))
+               goto out_err;
+
+       count = be32_to_cpup(p++);
+
+       dprintk("%s enter, number of extents %i\n", __func__, count);
+       p = xdr_inline_decode(&stream, (28 + NFS4_DEVICEID4_SIZE) * count);
+       if (unlikely(!p))
+               goto out_err;
+
+       /* Decode individual extents, putting them in temporary
+        * staging area until whole layout is decoded to make error
+        * recovery easier.
+        */
+       for (i = 0; i < count; i++) {
+               be = bl_alloc_extent();
+               if (!be) {
+                       status = -ENOMEM;
+                       goto out_err;
+               }
+               memcpy(&be->be_devid, p, NFS4_DEVICEID4_SIZE);
+               p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
+               be->be_mdev = translate_devid(lo, &be->be_devid);
+               if (!be->be_mdev)
+                       goto out_err;
+
+               /* The next three values are read in as bytes,
+                * but stored as 512-byte sector lengths
+                */
+               if (decode_sector_number(&p, &be->be_f_offset) < 0)
+                       goto out_err;
+               if (decode_sector_number(&p, &be->be_length) < 0)
+                       goto out_err;
+               if (decode_sector_number(&p, &be->be_v_offset) < 0)
+                       goto out_err;
+               be->be_state = be32_to_cpup(p++);
+               if (be->be_state == PNFS_BLOCK_INVALID_DATA)
+                       be->be_inval = &bl->bl_inval;
+               if (verify_extent(be, &lv)) {
+                       dprintk("%s verify failed\n", __func__);
+                       goto out_err;
+               }
+               list_add_tail(&be->be_node, &extents);
+       }
+       if (lgr->range.offset + lgr->range.length !=
+                       lv.start << SECTOR_SHIFT) {
+               dprintk("%s Final length mismatch\n", __func__);
+               be = NULL;
+               goto out_err;
+       }
+       if (lv.start < lv.cowread) {
+               dprintk("%s Final uncovered COW extent\n", __func__);
+               be = NULL;
+               goto out_err;
+       }
+       /* Extents decoded properly, now try to merge them in to
+        * existing layout extents.
+        */
+       spin_lock(&bl->bl_ext_lock);
+       list_for_each_entry_safe(be, save, &extents, be_node) {
+               list_del(&be->be_node);
+               status = bl_add_merge_extent(bl, be);
+               if (status) {
+                       spin_unlock(&bl->bl_ext_lock);
+                       /* This is a fairly catastrophic error, as the
+                        * entire layout extent lists are now corrupted.
+                        * We should have some way to distinguish this.
+                        */
+                       be = NULL;
+                       goto out_err;
+               }
+       }
+       spin_unlock(&bl->bl_ext_lock);
+       status = 0;
+ out:
+       __free_page(scratch);
+       dprintk("%s returns %i\n", __func__, status);
+       return status;
+
+ out_err:
+       bl_put_extent(be);
+       while (!list_empty(&extents)) {
+               be = list_first_entry(&extents, struct pnfs_block_extent,
+                                     be_node);
+               list_del(&be->be_node);
+               bl_put_extent(be);
+       }
+       goto out;
+}
diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c
new file mode 100644 (file)
index 0000000..d055c75
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  linux/fs/nfs/blocklayout/blocklayoutdm.c
+ *
+ *  Module for the NFSv4.1 pNFS block layout driver.
+ *
+ *  Copyright (c) 2007 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Fred Isaman <iisaman@umich.edu>
+ *  Andy Adamson <andros@citi.umich.edu>
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.  if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+#include <linux/genhd.h> /* gendisk - used in a dprintk*/
+#include <linux/sched.h>
+#include <linux/hash.h>
+
+#include "blocklayout.h"
+
+#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
+
+static void dev_remove(dev_t dev)
+{
+       struct rpc_pipe_msg msg;
+       struct bl_dev_msg bl_umount_request;
+       struct bl_msg_hdr bl_msg = {
+               .type = BL_DEVICE_UMOUNT,
+               .totallen = sizeof(bl_umount_request),
+       };
+       uint8_t *dataptr;
+       DECLARE_WAITQUEUE(wq, current);
+
+       dprintk("Entering %s\n", __func__);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
+       if (!msg.data)
+               goto out;
+
+       memset(&bl_umount_request, 0, sizeof(bl_umount_request));
+       bl_umount_request.major = MAJOR(dev);
+       bl_umount_request.minor = MINOR(dev);
+
+       memcpy(msg.data, &bl_msg, sizeof(bl_msg));
+       dataptr = (uint8_t *) msg.data;
+       memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
+       msg.len = sizeof(bl_msg) + bl_msg.totallen;
+
+       add_wait_queue(&bl_wq, &wq);
+       if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) {
+               remove_wait_queue(&bl_wq, &wq);
+               goto out;
+       }
+
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule();
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&bl_wq, &wq);
+
+out:
+       kfree(msg.data);
+}
+
+/*
+ * Release meta device
+ */
+static void nfs4_blk_metadev_release(struct pnfs_block_dev *bdev)
+{
+       int rv;
+
+       dprintk("%s Releasing\n", __func__);
+       rv = nfs4_blkdev_put(bdev->bm_mdev);
+       if (rv)
+               printk(KERN_ERR "%s nfs4_blkdev_put returns %d\n",
+                               __func__, rv);
+
+       dev_remove(bdev->bm_mdev->bd_dev);
+}
+
+void bl_free_block_dev(struct pnfs_block_dev *bdev)
+{
+       if (bdev) {
+               if (bdev->bm_mdev) {
+                       dprintk("%s Removing DM device: %d:%d\n",
+                               __func__,
+                               MAJOR(bdev->bm_mdev->bd_dev),
+                               MINOR(bdev->bm_mdev->bd_dev));
+                       nfs4_blk_metadev_release(bdev);
+               }
+               kfree(bdev);
+       }
+}
diff --git a/fs/nfs/blocklayout/extents.c b/fs/nfs/blocklayout/extents.c
new file mode 100644 (file)
index 0000000..19fa7b0
--- /dev/null
@@ -0,0 +1,935 @@
+/*
+ *  linux/fs/nfs/blocklayout/blocklayout.h
+ *
+ *  Module for the NFSv4.1 pNFS block layout driver.
+ *
+ *  Copyright (c) 2006 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson <andros@citi.umich.edu>
+ *  Fred Isaman <iisaman@umich.edu>
+ *
+ * permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any purpose,
+ * so long as the name of the university of michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.  if
+ * the above copyright notice or any other identification of the
+ * university of michigan is included in any copy of any portion of
+ * this software, then the disclaimer below must also be included.
+ *
+ * this software is provided as is, without representation from the
+ * university of michigan as to its fitness for any purpose, and without
+ * warranty by the university of michigan of any kind, either express
+ * or implied, including without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  the regents
+ * of the university of michigan shall not be liable for any damages,
+ * including special, indirect, incidental, or consequential damages,
+ * with respect to any claim arising out or in connection with the use
+ * of the software, even if it has been or is hereafter advised of the
+ * possibility of such damages.
+ */
+
+#include "blocklayout.h"
+#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
+
+/* Bit numbers */
+#define EXTENT_INITIALIZED 0
+#define EXTENT_WRITTEN     1
+#define EXTENT_IN_COMMIT   2
+#define INTERNAL_EXISTS    MY_MAX_TAGS
+#define INTERNAL_MASK      ((1 << INTERNAL_EXISTS) - 1)
+
+/* Returns largest t<=s s.t. t%base==0 */
+static inline sector_t normalize(sector_t s, int base)
+{
+       sector_t tmp = s; /* Since do_div modifies its argument */
+       return s - do_div(tmp, base);
+}
+
+static inline sector_t normalize_up(sector_t s, int base)
+{
+       return normalize(s + base - 1, base);
+}
+
+/* Complete stub using list while determine API wanted */
+
+/* Returns tags, or negative */
+static int32_t _find_entry(struct my_tree *tree, u64 s)
+{
+       struct pnfs_inval_tracking *pos;
+
+       dprintk("%s(%llu) enter\n", __func__, s);
+       list_for_each_entry_reverse(pos, &tree->mtt_stub, it_link) {
+               if (pos->it_sector > s)
+                       continue;
+               else if (pos->it_sector == s)
+                       return pos->it_tags & INTERNAL_MASK;
+               else
+                       break;
+       }
+       return -ENOENT;
+}
+
+static inline
+int _has_tag(struct my_tree *tree, u64 s, int32_t tag)
+{
+       int32_t tags;
+
+       dprintk("%s(%llu, %i) enter\n", __func__, s, tag);
+       s = normalize(s, tree->mtt_step_size);
+       tags = _find_entry(tree, s);
+       if ((tags < 0) || !(tags & (1 << tag)))
+               return 0;
+       else
+               return 1;
+}
+
+/* Creates entry with tag, or if entry already exists, unions tag to it.
+ * If storage is not NULL, newly created entry will use it.
+ * Returns number of entries added, or negative on error.
+ */
+static int _add_entry(struct my_tree *tree, u64 s, int32_t tag,
+                     struct pnfs_inval_tracking *storage)
+{
+       int found = 0;
+       struct pnfs_inval_tracking *pos;
+
+       dprintk("%s(%llu, %i, %p) enter\n", __func__, s, tag, storage);
+       list_for_each_entry_reverse(pos, &tree->mtt_stub, it_link) {
+               if (pos->it_sector > s)
+                       continue;
+               else if (pos->it_sector == s) {
+                       found = 1;
+                       break;
+               } else
+                       break;
+       }
+       if (found) {
+               pos->it_tags |= (1 << tag);
+               return 0;
+       } else {
+               struct pnfs_inval_tracking *new;
+               if (storage)
+                       new = storage;
+               else {
+                       new = kmalloc(sizeof(*new), GFP_NOFS);
+                       if (!new)
+                               return -ENOMEM;
+               }
+               new->it_sector = s;
+               new->it_tags = (1 << tag);
+               list_add(&new->it_link, &pos->it_link);
+               return 1;
+       }
+}
+
+/* XXXX Really want option to not create */
+/* Over range, unions tag with existing entries, else creates entry with tag */
+static int _set_range(struct my_tree *tree, int32_t tag, u64 s, u64 length)
+{
+       u64 i;
+
+       dprintk("%s(%i, %llu, %llu) enter\n", __func__, tag, s, length);
+       for (i = normalize(s, tree->mtt_step_size); i < s + length;
+            i += tree->mtt_step_size)
+               if (_add_entry(tree, i, tag, NULL))
+                       return -ENOMEM;
+       return 0;
+}
+
+/* Ensure that future operations on given range of tree will not malloc */
+static int _preload_range(struct my_tree *tree, u64 offset, u64 length)
+{
+       u64 start, end, s;
+       int count, i, used = 0, status = -ENOMEM;
+       struct pnfs_inval_tracking **storage;
+
+       dprintk("%s(%llu, %llu) enter\n", __func__, offset, length);
+       start = normalize(offset, tree->mtt_step_size);
+       end = normalize_up(offset + length, tree->mtt_step_size);
+       count = (int)(end - start) / (int)tree->mtt_step_size;
+
+       /* Pre-malloc what memory we might need */
+       storage = kmalloc(sizeof(*storage) * count, GFP_NOFS);
+       if (!storage)
+               return -ENOMEM;
+       for (i = 0; i < count; i++) {
+               storage[i] = kmalloc(sizeof(struct pnfs_inval_tracking),
+                                    GFP_NOFS);
+               if (!storage[i])
+                       goto out_cleanup;
+       }
+
+       /* Now need lock - HOW??? */
+
+       for (s = start; s < end; s += tree->mtt_step_size)
+               used += _add_entry(tree, s, INTERNAL_EXISTS, storage[used]);
+
+       /* Unlock - HOW??? */
+       status = 0;
+
+ out_cleanup:
+       for (i = used; i < count; i++) {
+               if (!storage[i])
+                       break;
+               kfree(storage[i]);
+       }
+       kfree(storage);
+       return status;
+}
+
+static void set_needs_init(sector_t *array, sector_t offset)
+{
+       sector_t *p = array;
+
+       dprintk("%s enter\n", __func__);
+       if (!p)
+               return;
+       while (*p < offset)
+               p++;
+       if (*p == offset)
+               return;
+       else if (*p == ~0) {
+               *p++ = offset;
+               *p = ~0;
+               return;
+       } else {
+               sector_t *save = p;
+               dprintk("%s Adding %llu\n", __func__, (u64)offset);
+               while (*p != ~0)
+                       p++;
+               p++;
+               memmove(save + 1, save, (char *)p - (char *)save);
+               *save = offset;
+               return;
+       }
+}
+
+/* We are relying on page lock to serialize this */
+int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect)
+{
+       int rv;
+
+       spin_lock(&marks->im_lock);
+       rv = _has_tag(&marks->im_tree, isect, EXTENT_INITIALIZED);
+       spin_unlock(&marks->im_lock);
+       return rv;
+}
+
+/* Assume start, end already sector aligned */
+static int
+_range_has_tag(struct my_tree *tree, u64 start, u64 end, int32_t tag)
+{
+       struct pnfs_inval_tracking *pos;
+       u64 expect = 0;
+
+       dprintk("%s(%llu, %llu, %i) enter\n", __func__, start, end, tag);
+       list_for_each_entry_reverse(pos, &tree->mtt_stub, it_link) {
+               if (pos->it_sector >= end)
+                       continue;
+               if (!expect) {
+                       if ((pos->it_sector == end - tree->mtt_step_size) &&
+                           (pos->it_tags & (1 << tag))) {
+                               expect = pos->it_sector - tree->mtt_step_size;
+                               if (pos->it_sector < tree->mtt_step_size || expect < start)
+                                       return 1;
+                               continue;
+                       } else {
+                               return 0;
+                       }
+               }
+               if (pos->it_sector != expect || !(pos->it_tags & (1 << tag)))
+                       return 0;
+               expect -= tree->mtt_step_size;
+               if (expect < start)
+                       return 1;
+       }
+       return 0;
+}
+
+static int is_range_written(struct pnfs_inval_markings *marks,
+                           sector_t start, sector_t end)
+{
+       int rv;
+
+       spin_lock(&marks->im_lock);
+       rv = _range_has_tag(&marks->im_tree, start, end, EXTENT_WRITTEN);
+       spin_unlock(&marks->im_lock);
+       return rv;
+}
+
+/* Marks sectors in [offest, offset_length) as having been initialized.
+ * All lengths are step-aligned, where step is min(pagesize, blocksize).
+ * Notes where partial block is initialized, and helps prepare it for
+ * complete initialization later.
+ */
+/* Currently assumes offset is page-aligned */
+int bl_mark_sectors_init(struct pnfs_inval_markings *marks,
+                            sector_t offset, sector_t length,
+                            sector_t **pages)
+{
+       sector_t s, start, end;
+       sector_t *array = NULL; /* Pages to mark */
+
+       dprintk("%s(offset=%llu,len=%llu) enter\n",
+               __func__, (u64)offset, (u64)length);
+       s = max((sector_t) 3,
+               2 * (marks->im_block_size / (PAGE_CACHE_SECTORS)));
+       dprintk("%s set max=%llu\n", __func__, (u64)s);
+       if (pages) {
+               array = kmalloc(s * sizeof(sector_t), GFP_NOFS);
+               if (!array)
+                       goto outerr;
+               array[0] = ~0;
+       }
+
+       start = normalize(offset, marks->im_block_size);
+       end = normalize_up(offset + length, marks->im_block_size);
+       if (_preload_range(&marks->im_tree, start, end - start))
+               goto outerr;
+
+       spin_lock(&marks->im_lock);
+
+       for (s = normalize_up(start, PAGE_CACHE_SECTORS);
+            s < offset; s += PAGE_CACHE_SECTORS) {
+               dprintk("%s pre-area pages\n", __func__);
+               /* Portion of used block is not initialized */
+               if (!_has_tag(&marks->im_tree, s, EXTENT_INITIALIZED))
+                       set_needs_init(array, s);
+       }
+       if (_set_range(&marks->im_tree, EXTENT_INITIALIZED, offset, length))
+               goto out_unlock;
+       for (s = normalize_up(offset + length, PAGE_CACHE_SECTORS);
+            s < end; s += PAGE_CACHE_SECTORS) {
+               dprintk("%s post-area pages\n", __func__);
+               if (!_has_tag(&marks->im_tree, s, EXTENT_INITIALIZED))
+                       set_needs_init(array, s);
+       }
+
+       spin_unlock(&marks->im_lock);
+
+       if (pages) {
+               if (array[0] == ~0) {
+                       kfree(array);
+                       *pages = NULL;
+               } else
+                       *pages = array;
+       }
+       return 0;
+
+ out_unlock:
+       spin_unlock(&marks->im_lock);
+ outerr:
+       if (pages) {
+               kfree(array);
+               *pages = NULL;
+       }
+       return -ENOMEM;
+}
+
+/* Marks sectors in [offest, offset+length) as having been written to disk.
+ * All lengths should be block aligned.
+ */
+static int mark_written_sectors(struct pnfs_inval_markings *marks,
+                               sector_t offset, sector_t length)
+{
+       int status;
+
+       dprintk("%s(offset=%llu,len=%llu) enter\n", __func__,
+               (u64)offset, (u64)length);
+       spin_lock(&marks->im_lock);
+       status = _set_range(&marks->im_tree, EXTENT_WRITTEN, offset, length);
+       spin_unlock(&marks->im_lock);
+       return status;
+}
+
+static void print_short_extent(struct pnfs_block_short_extent *be)
+{
+       dprintk("PRINT SHORT EXTENT extent %p\n", be);
+       if (be) {
+               dprintk("        be_f_offset %llu\n", (u64)be->bse_f_offset);
+               dprintk("        be_length   %llu\n", (u64)be->bse_length);
+       }
+}
+
+static void print_clist(struct list_head *list, unsigned int count)
+{
+       struct pnfs_block_short_extent *be;
+       unsigned int i = 0;
+
+       ifdebug(FACILITY) {
+               printk(KERN_DEBUG "****************\n");
+               printk(KERN_DEBUG "Extent list looks like:\n");
+               list_for_each_entry(be, list, bse_node) {
+                       i++;
+                       print_short_extent(be);
+               }
+               if (i != count)
+                       printk(KERN_DEBUG "\n\nExpected %u entries\n\n\n", count);
+               printk(KERN_DEBUG "****************\n");
+       }
+}
+
+/* Note: In theory, we should do more checking that devid's match between
+ * old and new, but if they don't, the lists are too corrupt to salvage anyway.
+ */
+/* Note this is very similar to bl_add_merge_extent */
+static void add_to_commitlist(struct pnfs_block_layout *bl,
+                             struct pnfs_block_short_extent *new)
+{
+       struct list_head *clist = &bl->bl_commit;
+       struct pnfs_block_short_extent *old, *save;
+       sector_t end = new->bse_f_offset + new->bse_length;
+
+       dprintk("%s enter\n", __func__);
+       print_short_extent(new);
+       print_clist(clist, bl->bl_count);
+       bl->bl_count++;
+       /* Scan for proper place to insert, extending new to the left
+        * as much as possible.
+        */
+       list_for_each_entry_safe(old, save, clist, bse_node) {
+               if (new->bse_f_offset < old->bse_f_offset)
+                       break;
+               if (end <= old->bse_f_offset + old->bse_length) {
+                       /* Range is already in list */
+                       bl->bl_count--;
+                       kfree(new);
+                       return;
+               } else if (new->bse_f_offset <=
+                               old->bse_f_offset + old->bse_length) {
+                       /* new overlaps or abuts existing be */
+                       if (new->bse_mdev == old->bse_mdev) {
+                               /* extend new to fully replace old */
+                               new->bse_length += new->bse_f_offset -
+                                               old->bse_f_offset;
+                               new->bse_f_offset = old->bse_f_offset;
+                               list_del(&old->bse_node);
+                               bl->bl_count--;
+                               kfree(old);
+                       }
+               }
+       }
+       /* Note that if we never hit the above break, old will not point to a
+        * valid extent.  However, in that case &old->bse_node==list.
+        */
+       list_add_tail(&new->bse_node, &old->bse_node);
+       /* Scan forward for overlaps.  If we find any, extend new and
+        * remove the overlapped extent.
+        */
+       old = list_prepare_entry(new, clist, bse_node);
+       list_for_each_entry_safe_continue(old, save, clist, bse_node) {
+               if (end < old->bse_f_offset)
+                       break;
+               /* new overlaps or abuts old */
+               if (new->bse_mdev == old->bse_mdev) {
+                       if (end < old->bse_f_offset + old->bse_length) {
+                               /* extend new to fully cover old */
+                               end = old->bse_f_offset + old->bse_length;
+                               new->bse_length = end - new->bse_f_offset;
+                       }
+                       list_del(&old->bse_node);
+                       bl->bl_count--;
+                       kfree(old);
+               }
+       }
+       dprintk("%s: after merging\n", __func__);
+       print_clist(clist, bl->bl_count);
+}
+
+/* Note the range described by offset, length is guaranteed to be contained
+ * within be.
+ */
+int bl_mark_for_commit(struct pnfs_block_extent *be,
+                   sector_t offset, sector_t length)
+{
+       sector_t new_end, end = offset + length;
+       struct pnfs_block_short_extent *new;
+       struct pnfs_block_layout *bl = container_of(be->be_inval,
+                                                   struct pnfs_block_layout,
+                                                   bl_inval);
+
+       new = kmalloc(sizeof(*new), GFP_NOFS);
+       if (!new)
+               return -ENOMEM;
+
+       mark_written_sectors(be->be_inval, offset, length);
+       /* We want to add the range to commit list, but it must be
+        * block-normalized, and verified that the normalized range has
+        * been entirely written to disk.
+        */
+       new->bse_f_offset = offset;
+       offset = normalize(offset, bl->bl_blocksize);
+       if (offset < new->bse_f_offset) {
+               if (is_range_written(be->be_inval, offset, new->bse_f_offset))
+                       new->bse_f_offset = offset;
+               else
+                       new->bse_f_offset = offset + bl->bl_blocksize;
+       }
+       new_end = normalize_up(end, bl->bl_blocksize);
+       if (end < new_end) {
+               if (is_range_written(be->be_inval, end, new_end))
+                       end = new_end;
+               else
+                       end = new_end - bl->bl_blocksize;
+       }
+       if (end <= new->bse_f_offset) {
+               kfree(new);
+               return 0;
+       }
+       new->bse_length = end - new->bse_f_offset;
+       new->bse_devid = be->be_devid;
+       new->bse_mdev = be->be_mdev;
+
+       spin_lock(&bl->bl_ext_lock);
+       /* new will be freed, either by add_to_commitlist if it decides not
+        * to use it, or after LAYOUTCOMMIT uses it in the commitlist.
+        */
+       add_to_commitlist(bl, new);
+       spin_unlock(&bl->bl_ext_lock);
+       return 0;
+}
+
+static void print_bl_extent(struct pnfs_block_extent *be)
+{
+       dprintk("PRINT EXTENT extent %p\n", be);
+       if (be) {
+               dprintk("        be_f_offset %llu\n", (u64)be->be_f_offset);
+               dprintk("        be_length   %llu\n", (u64)be->be_length);
+               dprintk("        be_v_offset %llu\n", (u64)be->be_v_offset);
+               dprintk("        be_state    %d\n", be->be_state);
+       }
+}
+
+static void
+destroy_extent(struct kref *kref)
+{
+       struct pnfs_block_extent *be;
+
+       be = container_of(kref, struct pnfs_block_extent, be_refcnt);
+       dprintk("%s be=%p\n", __func__, be);
+       kfree(be);
+}
+
+void
+bl_put_extent(struct pnfs_block_extent *be)
+{
+       if (be) {
+               dprintk("%s enter %p (%i)\n", __func__, be,
+                       atomic_read(&be->be_refcnt.refcount));
+               kref_put(&be->be_refcnt, destroy_extent);
+       }
+}
+
+struct pnfs_block_extent *bl_alloc_extent(void)
+{
+       struct pnfs_block_extent *be;
+
+       be = kmalloc(sizeof(struct pnfs_block_extent), GFP_NOFS);
+       if (!be)
+               return NULL;
+       INIT_LIST_HEAD(&be->be_node);
+       kref_init(&be->be_refcnt);
+       be->be_inval = NULL;
+       return be;
+}
+
+static void print_elist(struct list_head *list)
+{
+       struct pnfs_block_extent *be;
+       dprintk("****************\n");
+       dprintk("Extent list looks like:\n");
+       list_for_each_entry(be, list, be_node) {
+               print_bl_extent(be);
+       }
+       dprintk("****************\n");
+}
+
+static inline int
+extents_consistent(struct pnfs_block_extent *old, struct pnfs_block_extent *new)
+{
+       /* Note this assumes new->be_f_offset >= old->be_f_offset */
+       return (new->be_state == old->be_state) &&
+               ((new->be_state == PNFS_BLOCK_NONE_DATA) ||
+                ((new->be_v_offset - old->be_v_offset ==
+                  new->be_f_offset - old->be_f_offset) &&
+                 new->be_mdev == old->be_mdev));
+}
+
+/* Adds new to appropriate list in bl, modifying new and removing existing
+ * extents as appropriate to deal with overlaps.
+ *
+ * See bl_find_get_extent for list constraints.
+ *
+ * Refcount on new is already set.  If end up not using it, or error out,
+ * need to put the reference.
+ *
+ * bl->bl_ext_lock is held by caller.
+ */
+int
+bl_add_merge_extent(struct pnfs_block_layout *bl,
+                    struct pnfs_block_extent *new)
+{
+       struct pnfs_block_extent *be, *tmp;
+       sector_t end = new->be_f_offset + new->be_length;
+       struct list_head *list;
+
+       dprintk("%s enter with be=%p\n", __func__, new);
+       print_bl_extent(new);
+       list = &bl->bl_extents[bl_choose_list(new->be_state)];
+       print_elist(list);
+
+       /* Scan for proper place to insert, extending new to the left
+        * as much as possible.
+        */
+       list_for_each_entry_safe_reverse(be, tmp, list, be_node) {
+               if (new->be_f_offset >= be->be_f_offset + be->be_length)
+                       break;
+               if (new->be_f_offset >= be->be_f_offset) {
+                       if (end <= be->be_f_offset + be->be_length) {
+                               /* new is a subset of existing be*/
+                               if (extents_consistent(be, new)) {
+                                       dprintk("%s: new is subset, ignoring\n",
+                                               __func__);
+                                       bl_put_extent(new);
+                                       return 0;
+                               } else {
+                                       goto out_err;
+                               }
+                       } else {
+                               /* |<--   be   -->|
+                                *          |<--   new   -->| */
+                               if (extents_consistent(be, new)) {
+                                       /* extend new to fully replace be */
+                                       new->be_length += new->be_f_offset -
+                                               be->be_f_offset;
+                                       new->be_f_offset = be->be_f_offset;
+                                       new->be_v_offset = be->be_v_offset;
+                                       dprintk("%s: removing %p\n", __func__, be);
+                                       list_del(&be->be_node);
+                                       bl_put_extent(be);
+                               } else {
+                                       goto out_err;
+                               }
+                       }
+               } else if (end >= be->be_f_offset + be->be_length) {
+                       /* new extent overlap existing be */
+                       if (extents_consistent(be, new)) {
+                               /* extend new to fully replace be */
+                               dprintk("%s: removing %p\n", __func__, be);
+                               list_del(&be->be_node);
+                               bl_put_extent(be);
+                       } else {
+                               goto out_err;
+                       }
+               } else if (end > be->be_f_offset) {
+                       /*           |<--   be   -->|
+                        *|<--   new   -->| */
+                       if (extents_consistent(new, be)) {
+                               /* extend new to fully replace be */
+                               new->be_length += be->be_f_offset + be->be_length -
+                                       new->be_f_offset - new->be_length;
+                               dprintk("%s: removing %p\n", __func__, be);
+                               list_del(&be->be_node);
+                               bl_put_extent(be);
+                       } else {
+                               goto out_err;
+                       }
+               }
+       }
+       /* Note that if we never hit the above break, be will not point to a
+        * valid extent.  However, in that case &be->be_node==list.
+        */
+       list_add(&new->be_node, &be->be_node);
+       dprintk("%s: inserting new\n", __func__);
+       print_elist(list);
+       /* FIXME - The per-list consistency checks have all been done,
+        * should now check cross-list consistency.
+        */
+       return 0;
+
+ out_err:
+       bl_put_extent(new);
+       return -EIO;
+}
+
+/* Returns extent, or NULL.  If a second READ extent exists, it is returned
+ * in cow_read, if given.
+ *
+ * The extents are kept in two seperate ordered lists, one for READ and NONE,
+ * one for READWRITE and INVALID.  Within each list, we assume:
+ * 1. Extents are ordered by file offset.
+ * 2. For any given isect, there is at most one extents that matches.
+ */
+struct pnfs_block_extent *
+bl_find_get_extent(struct pnfs_block_layout *bl, sector_t isect,
+           struct pnfs_block_extent **cow_read)
+{
+       struct pnfs_block_extent *be, *cow, *ret;
+       int i;
+
+       dprintk("%s enter with isect %llu\n", __func__, (u64)isect);
+       cow = ret = NULL;
+       spin_lock(&bl->bl_ext_lock);
+       for (i = 0; i < EXTENT_LISTS; i++) {
+               list_for_each_entry_reverse(be, &bl->bl_extents[i], be_node) {
+                       if (isect >= be->be_f_offset + be->be_length)
+                               break;
+                       if (isect >= be->be_f_offset) {
+                               /* We have found an extent */
+                               dprintk("%s Get %p (%i)\n", __func__, be,
+                                       atomic_read(&be->be_refcnt.refcount));
+                               kref_get(&be->be_refcnt);
+                               if (!ret)
+                                       ret = be;
+                               else if (be->be_state != PNFS_BLOCK_READ_DATA)
+                                       bl_put_extent(be);
+                               else
+                                       cow = be;
+                               break;
+                       }
+               }
+               if (ret &&
+                   (!cow_read || ret->be_state != PNFS_BLOCK_INVALID_DATA))
+                       break;
+       }
+       spin_unlock(&bl->bl_ext_lock);
+       if (cow_read)
+               *cow_read = cow;
+       print_bl_extent(ret);
+       return ret;
+}
+
+/* Similar to bl_find_get_extent, but called with lock held, and ignores cow */
+static struct pnfs_block_extent *
+bl_find_get_extent_locked(struct pnfs_block_layout *bl, sector_t isect)
+{
+       struct pnfs_block_extent *be, *ret = NULL;
+       int i;
+
+       dprintk("%s enter with isect %llu\n", __func__, (u64)isect);
+       for (i = 0; i < EXTENT_LISTS; i++) {
+               if (ret)
+                       break;
+               list_for_each_entry_reverse(be, &bl->bl_extents[i], be_node) {
+                       if (isect >= be->be_f_offset + be->be_length)
+                               break;
+                       if (isect >= be->be_f_offset) {
+                               /* We have found an extent */
+                               dprintk("%s Get %p (%i)\n", __func__, be,
+                                       atomic_read(&be->be_refcnt.refcount));
+                               kref_get(&be->be_refcnt);
+                               ret = be;
+                               break;
+                       }
+               }
+       }
+       print_bl_extent(ret);
+       return ret;
+}
+
+int
+encode_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
+                              struct xdr_stream *xdr,
+                              const struct nfs4_layoutcommit_args *arg)
+{
+       struct pnfs_block_short_extent *lce, *save;
+       unsigned int count = 0;
+       __be32 *p, *xdr_start;
+
+       dprintk("%s enter\n", __func__);
+       /* BUG - creation of bl_commit is buggy - need to wait for
+        * entire block to be marked WRITTEN before it can be added.
+        */
+       spin_lock(&bl->bl_ext_lock);
+       /* Want to adjust for possible truncate */
+       /* We now want to adjust argument range */
+
+       /* XDR encode the ranges found */
+       xdr_start = xdr_reserve_space(xdr, 8);
+       if (!xdr_start)
+               goto out;
+       list_for_each_entry_safe(lce, save, &bl->bl_commit, bse_node) {
+               p = xdr_reserve_space(xdr, 7 * 4 + sizeof(lce->bse_devid.data));
+               if (!p)
+                       break;
+               p = xdr_encode_opaque_fixed(p, lce->bse_devid.data, NFS4_DEVICEID4_SIZE);
+               p = xdr_encode_hyper(p, lce->bse_f_offset << SECTOR_SHIFT);
+               p = xdr_encode_hyper(p, lce->bse_length << SECTOR_SHIFT);
+               p = xdr_encode_hyper(p, 0LL);
+               *p++ = cpu_to_be32(PNFS_BLOCK_READWRITE_DATA);
+               list_del(&lce->bse_node);
+               list_add_tail(&lce->bse_node, &bl->bl_committing);
+               bl->bl_count--;
+               count++;
+       }
+       xdr_start[0] = cpu_to_be32((xdr->p - xdr_start - 1) * 4);
+       xdr_start[1] = cpu_to_be32(count);
+out:
+       spin_unlock(&bl->bl_ext_lock);
+       dprintk("%s found %i ranges\n", __func__, count);
+       return 0;
+}
+
+/* Helper function to set_to_rw that initialize a new extent */
+static void
+_prep_new_extent(struct pnfs_block_extent *new,
+                struct pnfs_block_extent *orig,
+                sector_t offset, sector_t length, int state)
+{
+       kref_init(&new->be_refcnt);
+       /* don't need to INIT_LIST_HEAD(&new->be_node) */
+       memcpy(&new->be_devid, &orig->be_devid, sizeof(struct nfs4_deviceid));
+       new->be_mdev = orig->be_mdev;
+       new->be_f_offset = offset;
+       new->be_length = length;
+       new->be_v_offset = orig->be_v_offset - orig->be_f_offset + offset;
+       new->be_state = state;
+       new->be_inval = orig->be_inval;
+}
+
+/* Tries to merge be with extent in front of it in list.
+ * Frees storage if not used.
+ */
+static struct pnfs_block_extent *
+_front_merge(struct pnfs_block_extent *be, struct list_head *head,
+            struct pnfs_block_extent *storage)
+{
+       struct pnfs_block_extent *prev;
+
+       if (!storage)
+               goto no_merge;
+       if (&be->be_node == head || be->be_node.prev == head)
+               goto no_merge;
+       prev = list_entry(be->be_node.prev, struct pnfs_block_extent, be_node);
+       if ((prev->be_f_offset + prev->be_length != be->be_f_offset) ||
+           !extents_consistent(prev, be))
+               goto no_merge;
+       _prep_new_extent(storage, prev, prev->be_f_offset,
+                        prev->be_length + be->be_length, prev->be_state);
+       list_replace(&prev->be_node, &storage->be_node);
+       bl_put_extent(prev);
+       list_del(&be->be_node);
+       bl_put_extent(be);
+       return storage;
+
+ no_merge:
+       kfree(storage);
+       return be;
+}
+
+static u64
+set_to_rw(struct pnfs_block_layout *bl, u64 offset, u64 length)
+{
+       u64 rv = offset + length;
+       struct pnfs_block_extent *be, *e1, *e2, *e3, *new, *old;
+       struct pnfs_block_extent *children[3];
+       struct pnfs_block_extent *merge1 = NULL, *merge2 = NULL;
+       int i = 0, j;
+
+       dprintk("%s(%llu, %llu)\n", __func__, offset, length);
+       /* Create storage for up to three new extents e1, e2, e3 */
+       e1 = kmalloc(sizeof(*e1), GFP_ATOMIC);
+       e2 = kmalloc(sizeof(*e2), GFP_ATOMIC);
+       e3 = kmalloc(sizeof(*e3), GFP_ATOMIC);
+       /* BUG - we are ignoring any failure */
+       if (!e1 || !e2 || !e3)
+               goto out_nosplit;
+
+       spin_lock(&bl->bl_ext_lock);
+       be = bl_find_get_extent_locked(bl, offset);
+       rv = be->be_f_offset + be->be_length;
+       if (be->be_state != PNFS_BLOCK_INVALID_DATA) {
+               spin_unlock(&bl->bl_ext_lock);
+               goto out_nosplit;
+       }
+       /* Add e* to children, bumping e*'s krefs */
+       if (be->be_f_offset != offset) {
+               _prep_new_extent(e1, be, be->be_f_offset,
+                                offset - be->be_f_offset,
+                                PNFS_BLOCK_INVALID_DATA);
+               children[i++] = e1;
+               print_bl_extent(e1);
+       } else
+               merge1 = e1;
+       _prep_new_extent(e2, be, offset,
+                        min(length, be->be_f_offset + be->be_length - offset),
+                        PNFS_BLOCK_READWRITE_DATA);
+       children[i++] = e2;
+       print_bl_extent(e2);
+       if (offset + length < be->be_f_offset + be->be_length) {
+               _prep_new_extent(e3, be, e2->be_f_offset + e2->be_length,
+                                be->be_f_offset + be->be_length -
+                                offset - length,
+                                PNFS_BLOCK_INVALID_DATA);
+               children[i++] = e3;
+               print_bl_extent(e3);
+       } else
+               merge2 = e3;
+
+       /* Remove be from list, and insert the e* */
+       /* We don't get refs on e*, since this list is the base reference
+        * set when init'ed.
+        */
+       if (i < 3)
+               children[i] = NULL;
+       new = children[0];
+       list_replace(&be->be_node, &new->be_node);
+       bl_put_extent(be);
+       new = _front_merge(new, &bl->bl_extents[RW_EXTENT], merge1);
+       for (j = 1; j < i; j++) {
+               old = new;
+               new = children[j];
+               list_add(&new->be_node, &old->be_node);
+       }
+       if (merge2) {
+               /* This is a HACK, should just create a _back_merge function */
+               new = list_entry(new->be_node.next,
+                                struct pnfs_block_extent, be_node);
+               new = _front_merge(new, &bl->bl_extents[RW_EXTENT], merge2);
+       }
+       spin_unlock(&bl->bl_ext_lock);
+
+       /* Since we removed the base reference above, be is now scheduled for
+        * destruction.
+        */
+       bl_put_extent(be);
+       dprintk("%s returns %llu after split\n", __func__, rv);
+       return rv;
+
+ out_nosplit:
+       kfree(e1);
+       kfree(e2);
+       kfree(e3);
+       dprintk("%s returns %llu without splitting\n", __func__, rv);
+       return rv;
+}
+
+void
+clean_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
+                             const struct nfs4_layoutcommit_args *arg,
+                             int status)
+{
+       struct pnfs_block_short_extent *lce, *save;
+
+       dprintk("%s status %d\n", __func__, status);
+       list_for_each_entry_safe(lce, save, &bl->bl_committing, bse_node) {
+               if (likely(!status)) {
+                       u64 offset = lce->bse_f_offset;
+                       u64 end = offset + lce->bse_length;
+
+                       do {
+                               offset = set_to_rw(bl, offset, end - offset);
+                       } while (offset < end);
+                       list_del(&lce->bse_node);
+
+                       kfree(lce);
+               } else {
+                       list_del(&lce->bse_node);
+                       spin_lock(&bl->bl_ext_lock);
+                       add_to_commitlist(bl, lce);
+                       spin_unlock(&bl->bl_ext_lock);
+               }
+       }
+}
index d4d1954e9bb989148d25cda962c008dfd0d29b37..74780f9f852c6d3c5a01d71c3e2461ace4322963 100644 (file)
@@ -111,6 +111,7 @@ int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nf
 static u32 initiate_file_draining(struct nfs_client *clp,
                                  struct cb_layoutrecallargs *args)
 {
+       struct nfs_server *server;
        struct pnfs_layout_hdr *lo;
        struct inode *ino;
        bool found = false;
@@ -118,21 +119,28 @@ static u32 initiate_file_draining(struct nfs_client *clp,
        LIST_HEAD(free_me_list);
 
        spin_lock(&clp->cl_lock);
-       list_for_each_entry(lo, &clp->cl_layouts, plh_layouts) {
-               if (nfs_compare_fh(&args->cbl_fh,
-                                  &NFS_I(lo->plh_inode)->fh))
-                       continue;
-               ino = igrab(lo->plh_inode);
-               if (!ino)
-                       continue;
-               found = true;
-               /* Without this, layout can be freed as soon
-                * as we release cl_lock.
-                */
-               get_layout_hdr(lo);
-               break;
+       rcu_read_lock();
+       list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
+               list_for_each_entry(lo, &server->layouts, plh_layouts) {
+                       if (nfs_compare_fh(&args->cbl_fh,
+                                          &NFS_I(lo->plh_inode)->fh))
+                               continue;
+                       ino = igrab(lo->plh_inode);
+                       if (!ino)
+                               continue;
+                       found = true;
+                       /* Without this, layout can be freed as soon
+                        * as we release cl_lock.
+                        */
+                       get_layout_hdr(lo);
+                       break;
+               }
+               if (found)
+                       break;
        }
+       rcu_read_unlock();
        spin_unlock(&clp->cl_lock);
+
        if (!found)
                return NFS4ERR_NOMATCHING_LAYOUT;
 
@@ -154,6 +162,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
 static u32 initiate_bulk_draining(struct nfs_client *clp,
                                  struct cb_layoutrecallargs *args)
 {
+       struct nfs_server *server;
        struct pnfs_layout_hdr *lo;
        struct inode *ino;
        u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
@@ -167,18 +176,24 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
        };
 
        spin_lock(&clp->cl_lock);
-       list_for_each_entry(lo, &clp->cl_layouts, plh_layouts) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
                if ((args->cbl_recall_type == RETURN_FSID) &&
-                   memcmp(&NFS_SERVER(lo->plh_inode)->fsid,
-                          &args->cbl_fsid, sizeof(struct nfs_fsid)))
-                       continue;
-               if (!igrab(lo->plh_inode))
+                   memcmp(&server->fsid, &args->cbl_fsid,
+                          sizeof(struct nfs_fsid)))
                        continue;
-               get_layout_hdr(lo);
-               BUG_ON(!list_empty(&lo->plh_bulk_recall));
-               list_add(&lo->plh_bulk_recall, &recall_list);
+
+               list_for_each_entry(lo, &server->layouts, plh_layouts) {
+                       if (!igrab(lo->plh_inode))
+                               continue;
+                       get_layout_hdr(lo);
+                       BUG_ON(!list_empty(&lo->plh_bulk_recall));
+                       list_add(&lo->plh_bulk_recall, &recall_list);
+               }
        }
+       rcu_read_unlock();
        spin_unlock(&clp->cl_lock);
+
        list_for_each_entry_safe(lo, tmp,
                                 &recall_list, plh_bulk_recall) {
                ino = lo->plh_inode;
index b3dc2b88b65b139bae97fab53ad46be6b51846ab..5833fbbf59b05532638cedc7aea694c137b4e534 100644 (file)
@@ -105,7 +105,7 @@ struct rpc_program nfs_program = {
        .nrvers                 = ARRAY_SIZE(nfs_version),
        .version                = nfs_version,
        .stats                  = &nfs_rpcstat,
-       .pipe_dir_name          = "/nfs",
+       .pipe_dir_name          = NFS_PIPE_DIRNAME,
 };
 
 struct rpc_stat nfs_rpcstat = {
@@ -188,9 +188,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
        cred = rpc_lookup_machine_cred();
        if (!IS_ERR(cred))
                clp->cl_machine_cred = cred;
-#if defined(CONFIG_NFS_V4_1)
-       INIT_LIST_HEAD(&clp->cl_layouts);
-#endif
        nfs_fscache_get_client_cookie(clp);
 
        return clp;
@@ -293,6 +290,7 @@ static void nfs_free_client(struct nfs_client *clp)
        nfs4_deviceid_purge_client(clp);
 
        kfree(clp->cl_hostname);
+       kfree(clp->server_scope);
        kfree(clp);
 
        dprintk("<-- nfs_free_client()\n");
@@ -906,7 +904,9 @@ error:
 /*
  * Load up the server record from information gained in an fsinfo record
  */
-static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *fsinfo)
+static void nfs_server_set_fsinfo(struct nfs_server *server,
+                                 struct nfs_fh *mntfh,
+                                 struct nfs_fsinfo *fsinfo)
 {
        unsigned long max_rpc_payload;
 
@@ -936,7 +936,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *
        if (server->wsize > NFS_MAX_FILE_IO_SIZE)
                server->wsize = NFS_MAX_FILE_IO_SIZE;
        server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       set_pnfs_layoutdriver(server, fsinfo->layouttype);
+       server->pnfs_blksize = fsinfo->blksize;
+       set_pnfs_layoutdriver(server, mntfh, fsinfo->layouttype);
 
        server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
 
@@ -982,7 +983,7 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
        if (error < 0)
                goto out_error;
 
-       nfs_server_set_fsinfo(server, &fsinfo);
+       nfs_server_set_fsinfo(server, mntfh, &fsinfo);
 
        /* Get some general file system info */
        if (server->namelen == 0) {
@@ -1062,6 +1063,7 @@ static struct nfs_server *nfs_alloc_server(void)
        INIT_LIST_HEAD(&server->client_link);
        INIT_LIST_HEAD(&server->master_link);
        INIT_LIST_HEAD(&server->delegations);
+       INIT_LIST_HEAD(&server->layouts);
 
        atomic_set(&server->active, 0);
 
@@ -1464,7 +1466,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
        dprintk("<-- %s %p\n", __func__, clp);
        return clp;
 }
-EXPORT_SYMBOL(nfs4_set_ds_client);
+EXPORT_SYMBOL_GPL(nfs4_set_ds_client);
 
 /*
  * Session has been established, and the client marked ready.
index dd25c2aec37598f23f63d5a4decf128121609cd7..321a66bc3846453602c10e6bc5838dea88721a40 100644 (file)
@@ -398,12 +398,11 @@ int nfs_inode_return_delegation(struct inode *inode)
        return err;
 }
 
-static void nfs_mark_return_delegation(struct nfs_delegation *delegation)
+static void nfs_mark_return_delegation(struct nfs_server *server,
+               struct nfs_delegation *delegation)
 {
-       struct nfs_client *clp = NFS_SERVER(delegation->inode)->nfs_client;
-
        set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
-       set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
+       set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
 }
 
 /**
@@ -441,7 +440,7 @@ static void nfs_mark_return_all_delegation_types(struct nfs_server *server,
                if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
                        continue;
                if (delegation->type & flags)
-                       nfs_mark_return_delegation(delegation);
+                       nfs_mark_return_delegation(server, delegation);
        }
 }
 
@@ -508,7 +507,7 @@ static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
        list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
                if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
                        continue;
-               nfs_mark_return_delegation(delegation);
+               nfs_mark_return_delegation(server, delegation);
        }
 }
 
@@ -539,7 +538,8 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
 int nfs_async_inode_return_delegation(struct inode *inode,
                                      const nfs4_stateid *stateid)
 {
-       struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+       struct nfs_server *server = NFS_SERVER(inode);
+       struct nfs_client *clp = server->nfs_client;
        struct nfs_delegation *delegation;
 
        rcu_read_lock();
@@ -549,7 +549,7 @@ int nfs_async_inode_return_delegation(struct inode *inode,
                rcu_read_unlock();
                return -ENOENT;
        }
-       nfs_mark_return_delegation(delegation);
+       nfs_mark_return_delegation(server, delegation);
        rcu_read_unlock();
 
        nfs_delegation_run_state_manager(clp);
index 57f578e2560a0be44a6e29978627f315f57db01d..b238d95ac48c7b926ff1e02eae157ea09fa58a68 100644 (file)
@@ -134,18 +134,19 @@ const struct inode_operations nfs4_dir_inode_operations = {
 
 #endif /* CONFIG_NFS_V4 */
 
-static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred)
+static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred)
 {
        struct nfs_open_dir_context *ctx;
        ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
        if (ctx != NULL) {
                ctx->duped = 0;
+               ctx->attr_gencount = NFS_I(dir)->attr_gencount;
                ctx->dir_cookie = 0;
                ctx->dup_cookie = 0;
                ctx->cred = get_rpccred(cred);
-       } else
-               ctx = ERR_PTR(-ENOMEM);
-       return ctx;
+               return ctx;
+       }
+       return  ERR_PTR(-ENOMEM);
 }
 
 static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx)
@@ -173,7 +174,7 @@ nfs_opendir(struct inode *inode, struct file *filp)
        cred = rpc_lookup_cred();
        if (IS_ERR(cred))
                return PTR_ERR(cred);
-       ctx = alloc_nfs_open_dir_context(cred);
+       ctx = alloc_nfs_open_dir_context(inode, cred);
        if (IS_ERR(ctx)) {
                res = PTR_ERR(ctx);
                goto out;
@@ -323,7 +324,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
 {
        loff_t diff = desc->file->f_pos - desc->current_index;
        unsigned int index;
-       struct nfs_open_dir_context *ctx = desc->file->private_data;
 
        if (diff < 0)
                goto out_eof;
@@ -336,7 +336,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
        index = (unsigned int)diff;
        *desc->dir_cookie = array->array[index].cookie;
        desc->cache_entry_index = index;
-       ctx->duped = 0;
        return 0;
 out_eof:
        desc->eof = 1;
@@ -349,14 +348,34 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
        int i;
        loff_t new_pos;
        int status = -EAGAIN;
-       struct nfs_open_dir_context *ctx = desc->file->private_data;
 
        for (i = 0; i < array->size; i++) {
                if (array->array[i].cookie == *desc->dir_cookie) {
+                       struct nfs_inode *nfsi = NFS_I(desc->file->f_path.dentry->d_inode);
+                       struct nfs_open_dir_context *ctx = desc->file->private_data;
+
                        new_pos = desc->current_index + i;
-                       if (new_pos < desc->file->f_pos) {
+                       if (ctx->attr_gencount != nfsi->attr_gencount
+                           || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) {
+                               ctx->duped = 0;
+                               ctx->attr_gencount = nfsi->attr_gencount;
+                       } else if (new_pos < desc->file->f_pos) {
+                               if (ctx->duped > 0
+                                   && ctx->dup_cookie == *desc->dir_cookie) {
+                                       if (printk_ratelimit()) {
+                                               pr_notice("NFS: directory %s/%s contains a readdir loop."
+                                                               "Please contact your server vendor.  "
+                                                               "The file: %s has duplicate cookie %llu\n",
+                                                               desc->file->f_dentry->d_parent->d_name.name,
+                                                               desc->file->f_dentry->d_name.name,
+                                                               array->array[i].string.name,
+                                                               *desc->dir_cookie);
+                                       }
+                                       status = -ELOOP;
+                                       goto out;
+                               }
                                ctx->dup_cookie = *desc->dir_cookie;
-                               ctx->duped = 1;
+                               ctx->duped = -1;
                        }
                        desc->file->f_pos = new_pos;
                        desc->cache_entry_index = i;
@@ -368,6 +387,7 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
                if (*desc->dir_cookie == array->last_cookie)
                        desc->eof = 1;
        }
+out:
        return status;
 }
 
@@ -740,19 +760,6 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
        struct nfs_cache_array *array = NULL;
        struct nfs_open_dir_context *ctx = file->private_data;
 
-       if (ctx->duped != 0 && ctx->dup_cookie == *desc->dir_cookie) {
-               if (printk_ratelimit()) {
-                       pr_notice("NFS: directory %s/%s contains a readdir loop.  "
-                               "Please contact your server vendor.  "
-                               "Offending cookie: %llu\n",
-                               file->f_dentry->d_parent->d_name.name,
-                               file->f_dentry->d_name.name,
-                               *desc->dir_cookie);
-               }
-               res = -ELOOP;
-               goto out;
-       }
-
        array = nfs_readdir_get_array(desc->page);
        if (IS_ERR(array)) {
                res = PTR_ERR(array);
@@ -774,6 +781,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
                        *desc->dir_cookie = array->array[i+1].cookie;
                else
                        *desc->dir_cookie = array->last_cookie;
+               if (ctx->duped != 0)
+                       ctx->duped = 1;
        }
        if (array->eof_index >= 0)
                desc->eof = 1;
@@ -805,6 +814,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
        struct page     *page = NULL;
        int             status;
        struct inode *inode = desc->file->f_path.dentry->d_inode;
+       struct nfs_open_dir_context *ctx = desc->file->private_data;
 
        dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
                        (unsigned long long)*desc->dir_cookie);
@@ -818,6 +828,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
        desc->page_index = 0;
        desc->last_cookie = *desc->dir_cookie;
        desc->page = page;
+       ctx->duped = 0;
 
        status = nfs_readdir_xdr_to_array(desc, page, inode);
        if (status < 0)
index 2a55347a2daa85f66aa24b44d7bb7c93efe1d409..ab12913dd473bb1ef1ea27260699fbd4f7d76430 100644 (file)
@@ -277,6 +277,9 @@ extern void nfs_sb_deactive(struct super_block *sb);
 extern char *nfs_path(char **p, struct dentry *dentry,
                      char *buffer, ssize_t buflen);
 extern struct vfsmount *nfs_d_automount(struct path *path);
+#ifdef CONFIG_NFS_V4
+rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
+#endif
 
 /* getroot.c */
 extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *,
@@ -288,12 +291,22 @@ extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *,
 extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh);
 #endif
 
+struct nfs_pageio_descriptor;
 /* read.c */
 extern int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt,
                             const struct rpc_call_ops *call_ops);
 extern void nfs_read_prepare(struct rpc_task *task, void *calldata);
+extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc,
+               struct list_head *head);
+
+extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);
+extern void nfs_readdata_release(struct nfs_read_data *rdata);
 
 /* write.c */
+extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc,
+               struct list_head *head);
+extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio);
+extern void nfs_writedata_release(struct nfs_write_data *wdata);
 extern void nfs_commit_free(struct nfs_write_data *p);
 extern int nfs_initiate_write(struct nfs_write_data *data,
                              struct rpc_clnt *clnt,
index 1f063bacd2857caa119f4dce1bf429402b0be909..8102391bb3744077ae778af2d5bdb5d135ed3fbf 100644 (file)
@@ -119,7 +119,7 @@ Elong:
 }
 
 #ifdef CONFIG_NFS_V4
-static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
+rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
 {
        struct gss_api_mech *mech;
        struct xdr_netobj oid;
index b788f2eb1ba08a07d4b18b2b050d4e8845b3609b..1ec1a85fa71c027b2523dcac7636a0a43a552165 100644 (file)
@@ -48,6 +48,7 @@ enum nfs4_client_state {
        NFS4CLNT_SESSION_RESET,
        NFS4CLNT_RECALL_SLOT,
        NFS4CLNT_LEASE_CONFIRM,
+       NFS4CLNT_SERVER_SCOPE_MISMATCH,
 };
 
 enum nfs4_session_state {
@@ -66,6 +67,8 @@ struct nfs4_minor_version_ops {
                        int cache_reply);
        int     (*validate_stateid)(struct nfs_delegation *,
                        const nfs4_stateid *);
+       int     (*find_root_sec)(struct nfs_server *, struct nfs_fh *,
+                       struct nfs_fsinfo *);
        const struct nfs4_state_recovery_ops *reboot_recovery_ops;
        const struct nfs4_state_recovery_ops *nograce_recovery_ops;
        const struct nfs4_state_maintenance_ops *state_renewal_ops;
@@ -315,7 +318,7 @@ extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
 extern const u32 nfs4_fattr_bitmap[2];
 extern const u32 nfs4_statfs_bitmap[2];
 extern const u32 nfs4_pathconf_bitmap[2];
-extern const u32 nfs4_fsinfo_bitmap[2];
+extern const u32 nfs4_fsinfo_bitmap[3];
 extern const u32 nfs4_fs_locations_bitmap[2];
 
 /* nfs4renewd.c */
@@ -349,6 +352,8 @@ extern void nfs4_schedule_state_manager(struct nfs_client *);
 extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *);
 extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
 extern void nfs41_handle_recall_slot(struct nfs_client *clp);
+extern void nfs41_handle_server_scope(struct nfs_client *,
+                                     struct server_scope **);
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
 extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
 extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t);
index f9d03abcd04cd803f7ec69fcd81a84eba2d7f66b..e8915d4840ad48457f23ecaac9e551fed5fa5652 100644 (file)
@@ -170,7 +170,7 @@ filelayout_set_layoutcommit(struct nfs_write_data *wdata)
 
        pnfs_set_layoutcommit(wdata);
        dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, wdata->inode->i_ino,
-               (unsigned long) wdata->lseg->pls_end_pos);
+               (unsigned long) NFS_I(wdata->inode)->layout->plh_lwb);
 }
 
 /*
@@ -334,6 +334,9 @@ filelayout_read_pagelist(struct nfs_read_data *data)
                __func__, data->inode->i_ino,
                data->args.pgbase, (size_t)data->args.count, offset);
 
+       if (test_bit(NFS_DEVICEID_INVALID, &FILELAYOUT_DEVID_NODE(lseg)->flags))
+               return PNFS_NOT_ATTEMPTED;
+
        /* Retrieve the correct rpc_client for the byte range */
        j = nfs4_fl_calc_j_index(lseg, offset);
        idx = nfs4_fl_calc_ds_index(lseg, j);
@@ -344,8 +347,7 @@ filelayout_read_pagelist(struct nfs_read_data *data)
                set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
                return PNFS_NOT_ATTEMPTED;
        }
-       dprintk("%s USE DS:ip %x %hu\n", __func__,
-               ntohl(ds->ds_ip_addr), ntohs(ds->ds_port));
+       dprintk("%s USE DS: %s\n", __func__, ds->ds_remotestr);
 
        /* No multipath support. Use first DS */
        data->ds_clp = ds->ds_clp;
@@ -374,6 +376,9 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
        struct nfs_fh *fh;
        int status;
 
+       if (test_bit(NFS_DEVICEID_INVALID, &FILELAYOUT_DEVID_NODE(lseg)->flags))
+               return PNFS_NOT_ATTEMPTED;
+
        /* Retrieve the correct rpc_client for the byte range */
        j = nfs4_fl_calc_j_index(lseg, offset);
        idx = nfs4_fl_calc_ds_index(lseg, j);
@@ -384,9 +389,9 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
                set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
                return PNFS_NOT_ATTEMPTED;
        }
-       dprintk("%s ino %lu sync %d req %Zu@%llu DS:%x:%hu\n", __func__,
+       dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s\n", __func__,
                data->inode->i_ino, sync, (size_t) data->args.count, offset,
-               ntohl(ds->ds_ip_addr), ntohs(ds->ds_port));
+               ds->ds_remotestr);
 
        data->write_done_cb = filelayout_write_done_cb;
        data->ds_clp = ds->ds_clp;
@@ -428,6 +433,14 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
 
        dprintk("--> %s\n", __func__);
 
+       /* FIXME: remove this check when layout segment support is added */
+       if (lgr->range.offset != 0 ||
+           lgr->range.length != NFS4_MAX_UINT64) {
+               dprintk("%s Only whole file layouts supported. Use MDS i/o\n",
+                       __func__);
+               goto out;
+       }
+
        if (fl->pattern_offset > lgr->range.offset) {
                dprintk("%s pattern_offset %lld too large\n",
                                __func__, fl->pattern_offset);
@@ -449,6 +462,10 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
                        goto out;
        } else
                dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
+       /* Found deviceid is being reaped */
+       if (test_bit(NFS_DEVICEID_INVALID, &dsaddr->id_node.flags))
+                       goto out_put;
+
        fl->dsaddr = dsaddr;
 
        if (fl->first_stripe_index < 0 ||
@@ -659,7 +676,7 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
  * return true  : coalesce page
  * return false : don't coalesce page
  */
-bool
+static bool
 filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
                   struct nfs_page *req)
 {
@@ -670,8 +687,6 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
            !nfs_generic_pg_test(pgio, prev, req))
                return false;
 
-       if (!pgio->pg_lseg)
-               return 1;
        p_stripe = (u64)prev->wb_index << PAGE_CACHE_SHIFT;
        r_stripe = (u64)req->wb_index << PAGE_CACHE_SHIFT;
        stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;
@@ -682,6 +697,52 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
        return (p_stripe == r_stripe);
 }
 
+void
+filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
+                       struct nfs_page *req)
+{
+       BUG_ON(pgio->pg_lseg != NULL);
+
+       pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
+                                          req->wb_context,
+                                          0,
+                                          NFS4_MAX_UINT64,
+                                          IOMODE_READ,
+                                          GFP_KERNEL);
+       /* If no lseg, fall back to read through mds */
+       if (pgio->pg_lseg == NULL)
+               nfs_pageio_reset_read_mds(pgio);
+}
+
+void
+filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
+                        struct nfs_page *req)
+{
+       BUG_ON(pgio->pg_lseg != NULL);
+
+       pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
+                                          req->wb_context,
+                                          0,
+                                          NFS4_MAX_UINT64,
+                                          IOMODE_RW,
+                                          GFP_NOFS);
+       /* If no lseg, fall back to write through mds */
+       if (pgio->pg_lseg == NULL)
+               nfs_pageio_reset_write_mds(pgio);
+}
+
+static const struct nfs_pageio_ops filelayout_pg_read_ops = {
+       .pg_init = filelayout_pg_init_read,
+       .pg_test = filelayout_pg_test,
+       .pg_doio = pnfs_generic_pg_readpages,
+};
+
+static const struct nfs_pageio_ops filelayout_pg_write_ops = {
+       .pg_init = filelayout_pg_init_write,
+       .pg_test = filelayout_pg_test,
+       .pg_doio = pnfs_generic_pg_writepages,
+};
+
 static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg)
 {
        return !FILELAYOUT_LSEG(lseg)->commit_through_mds;
@@ -879,7 +940,8 @@ static struct pnfs_layoutdriver_type filelayout_type = {
        .owner                  = THIS_MODULE,
        .alloc_lseg             = filelayout_alloc_lseg,
        .free_lseg              = filelayout_free_lseg,
-       .pg_test                = filelayout_pg_test,
+       .pg_read_ops            = &filelayout_pg_read_ops,
+       .pg_write_ops           = &filelayout_pg_write_ops,
        .mark_pnfs_commit       = filelayout_mark_pnfs_commit,
        .choose_commit_list     = filelayout_choose_commit_list,
        .commit_pagelist        = filelayout_commit_pagelist,
@@ -902,5 +964,7 @@ static void __exit nfs4filelayout_exit(void)
        pnfs_unregister_layoutdriver(&filelayout_type);
 }
 
+MODULE_ALIAS("nfs-layouttype4-1");
+
 module_init(nfs4filelayout_init);
 module_exit(nfs4filelayout_exit);
index cebe01e3795e949345ed169d3c4e0e2d10b6a62b..2e42284253fa600ba9266afc6111711653558949 100644 (file)
@@ -47,10 +47,17 @@ enum stripetype4 {
 };
 
 /* Individual ip address */
+struct nfs4_pnfs_ds_addr {
+       struct sockaddr_storage da_addr;
+       size_t                  da_addrlen;
+       struct list_head        da_node;  /* nfs4_pnfs_dev_hlist dev_dslist */
+       char                    *da_remotestr;  /* human readable addr+port */
+};
+
 struct nfs4_pnfs_ds {
        struct list_head        ds_node;  /* nfs4_pnfs_dev_hlist dev_dslist */
-       u32                     ds_ip_addr;
-       u32                     ds_port;
+       char                    *ds_remotestr;  /* comma sep list of addrs */
+       struct list_head        ds_addrs;
        struct nfs_client       *ds_clp;
        atomic_t                ds_count;
 };
@@ -89,6 +96,12 @@ FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg)
                            generic_hdr);
 }
 
+static inline struct nfs4_deviceid_node *
+FILELAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg)
+{
+       return &FILELAYOUT_LSEG(lseg)->dsaddr->id_node;
+}
+
 extern struct nfs_fh *
 nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j);
 
index 3b7bf13772641ac8409aef9e4e70d6eca99e7ec3..ed388aae96893628dfcecb25743acac320b8a1b4 100644 (file)
@@ -56,54 +56,139 @@ print_ds(struct nfs4_pnfs_ds *ds)
                printk("%s NULL device\n", __func__);
                return;
        }
-       printk("        ip_addr %x port %hu\n"
+       printk("        ds %s\n"
                "        ref count %d\n"
                "        client %p\n"
                "        cl_exchange_flags %x\n",
-               ntohl(ds->ds_ip_addr), ntohs(ds->ds_port),
+               ds->ds_remotestr,
                atomic_read(&ds->ds_count), ds->ds_clp,
                ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0);
 }
 
-/* nfs4_ds_cache_lock is held */
-static struct nfs4_pnfs_ds *
-_data_server_lookup_locked(u32 ip_addr, u32 port)
+static bool
+same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
 {
-       struct nfs4_pnfs_ds *ds;
+       struct sockaddr_in *a, *b;
+       struct sockaddr_in6 *a6, *b6;
+
+       if (addr1->sa_family != addr2->sa_family)
+               return false;
+
+       switch (addr1->sa_family) {
+       case AF_INET:
+               a = (struct sockaddr_in *)addr1;
+               b = (struct sockaddr_in *)addr2;
+
+               if (a->sin_addr.s_addr == b->sin_addr.s_addr &&
+                   a->sin_port == b->sin_port)
+                       return true;
+               break;
+
+       case AF_INET6:
+               a6 = (struct sockaddr_in6 *)addr1;
+               b6 = (struct sockaddr_in6 *)addr2;
+
+               /* LINKLOCAL addresses must have matching scope_id */
+               if (ipv6_addr_scope(&a6->sin6_addr) ==
+                   IPV6_ADDR_SCOPE_LINKLOCAL &&
+                   a6->sin6_scope_id != b6->sin6_scope_id)
+                       return false;
+
+               if (ipv6_addr_equal(&a6->sin6_addr, &b6->sin6_addr) &&
+                   a6->sin6_port == b6->sin6_port)
+                       return true;
+               break;
+
+       default:
+               dprintk("%s: unhandled address family: %u\n",
+                       __func__, addr1->sa_family);
+               return false;
+       }
 
-       dprintk("_data_server_lookup: ip_addr=%x port=%hu\n",
-                       ntohl(ip_addr), ntohs(port));
+       return false;
+}
 
-       list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) {
-               if (ds->ds_ip_addr == ip_addr &&
-                   ds->ds_port == port) {
-                       return ds;
+/*
+ * Lookup DS by addresses.  The first matching address returns true.
+ * nfs4_ds_cache_lock is held
+ */
+static struct nfs4_pnfs_ds *
+_data_server_lookup_locked(struct list_head *dsaddrs)
+{
+       struct nfs4_pnfs_ds *ds;
+       struct nfs4_pnfs_ds_addr *da1, *da2;
+
+       list_for_each_entry(da1, dsaddrs, da_node) {
+               list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) {
+                       list_for_each_entry(da2, &ds->ds_addrs, da_node) {
+                               if (same_sockaddr(
+                                       (struct sockaddr *)&da1->da_addr,
+                                       (struct sockaddr *)&da2->da_addr))
+                                       return ds;
+                       }
                }
        }
        return NULL;
 }
 
+/*
+ * Compare two lists of addresses.
+ */
+static bool
+_data_server_match_all_addrs_locked(struct list_head *dsaddrs1,
+                                   struct list_head *dsaddrs2)
+{
+       struct nfs4_pnfs_ds_addr *da1, *da2;
+       size_t count1 = 0,
+              count2 = 0;
+
+       list_for_each_entry(da1, dsaddrs1, da_node)
+               count1++;
+
+       list_for_each_entry(da2, dsaddrs2, da_node) {
+               bool found = false;
+               count2++;
+               list_for_each_entry(da1, dsaddrs1, da_node) {
+                       if (same_sockaddr((struct sockaddr *)&da1->da_addr,
+                               (struct sockaddr *)&da2->da_addr)) {
+                               found = true;
+                               break;
+                       }
+               }
+               if (!found)
+                       return false;
+       }
+
+       return (count1 == count2);
+}
+
 /*
  * Create an rpc connection to the nfs4_pnfs_ds data server
- * Currently only support IPv4
+ * Currently only supports IPv4 and IPv6 addresses
  */
 static int
 nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
 {
-       struct nfs_client *clp;
-       struct sockaddr_in sin;
+       struct nfs_client *clp = ERR_PTR(-EIO);
+       struct nfs4_pnfs_ds_addr *da;
        int status = 0;
 
-       dprintk("--> %s ip:port %x:%hu au_flavor %d\n", __func__,
-               ntohl(ds->ds_ip_addr), ntohs(ds->ds_port),
+       dprintk("--> %s DS %s au_flavor %d\n", __func__, ds->ds_remotestr,
                mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor);
 
-       sin.sin_family = AF_INET;
-       sin.sin_addr.s_addr = ds->ds_ip_addr;
-       sin.sin_port = ds->ds_port;
+       BUG_ON(list_empty(&ds->ds_addrs));
+
+       list_for_each_entry(da, &ds->ds_addrs, da_node) {
+               dprintk("%s: DS %s: trying address %s\n",
+                       __func__, ds->ds_remotestr, da->da_remotestr);
+
+               clp = nfs4_set_ds_client(mds_srv->nfs_client,
+                                (struct sockaddr *)&da->da_addr,
+                                da->da_addrlen, IPPROTO_TCP);
+               if (!IS_ERR(clp))
+                       break;
+       }
 
-       clp = nfs4_set_ds_client(mds_srv->nfs_client, (struct sockaddr *)&sin,
-                                sizeof(sin), IPPROTO_TCP);
        if (IS_ERR(clp)) {
                status = PTR_ERR(clp);
                goto out;
@@ -115,8 +200,8 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
                        goto out_put;
                }
                ds->ds_clp = clp;
-               dprintk("%s [existing] ip=%x, port=%hu\n", __func__,
-                       ntohl(ds->ds_ip_addr), ntohs(ds->ds_port));
+               dprintk("%s [existing] server=%s\n", __func__,
+                       ds->ds_remotestr);
                goto out;
        }
 
@@ -135,8 +220,7 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
                goto out_put;
 
        ds->ds_clp = clp;
-       dprintk("%s [new] ip=%x, port=%hu\n", __func__, ntohl(ds->ds_ip_addr),
-               ntohs(ds->ds_port));
+       dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
 out:
        return status;
 out_put:
@@ -147,12 +231,25 @@ out_put:
 static void
 destroy_ds(struct nfs4_pnfs_ds *ds)
 {
+       struct nfs4_pnfs_ds_addr *da;
+
        dprintk("--> %s\n", __func__);
        ifdebug(FACILITY)
                print_ds(ds);
 
        if (ds->ds_clp)
                nfs_put_client(ds->ds_clp);
+
+       while (!list_empty(&ds->ds_addrs)) {
+               da = list_first_entry(&ds->ds_addrs,
+                                     struct nfs4_pnfs_ds_addr,
+                                     da_node);
+               list_del_init(&da->da_node);
+               kfree(da->da_remotestr);
+               kfree(da);
+       }
+
+       kfree(ds->ds_remotestr);
        kfree(ds);
 }
 
@@ -179,31 +276,96 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
        kfree(dsaddr);
 }
 
+/*
+ * Create a string with a human readable address and port to avoid
+ * complicated setup around many dprinks.
+ */
+static char *
+nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags)
+{
+       struct nfs4_pnfs_ds_addr *da;
+       char *remotestr;
+       size_t len;
+       char *p;
+
+       len = 3;        /* '{', '}' and eol */
+       list_for_each_entry(da, dsaddrs, da_node) {
+               len += strlen(da->da_remotestr) + 1;    /* string plus comma */
+       }
+
+       remotestr = kzalloc(len, gfp_flags);
+       if (!remotestr)
+               return NULL;
+
+       p = remotestr;
+       *(p++) = '{';
+       len--;
+       list_for_each_entry(da, dsaddrs, da_node) {
+               size_t ll = strlen(da->da_remotestr);
+
+               if (ll > len)
+                       goto out_err;
+
+               memcpy(p, da->da_remotestr, ll);
+               p += ll;
+               len -= ll;
+
+               if (len < 1)
+                       goto out_err;
+               (*p++) = ',';
+               len--;
+       }
+       if (len < 2)
+               goto out_err;
+       *(p++) = '}';
+       *p = '\0';
+       return remotestr;
+out_err:
+       kfree(remotestr);
+       return NULL;
+}
+
 static struct nfs4_pnfs_ds *
-nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port, gfp_t gfp_flags)
+nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
 {
-       struct nfs4_pnfs_ds *tmp_ds, *ds;
+       struct nfs4_pnfs_ds *tmp_ds, *ds = NULL;
+       char *remotestr;
 
-       ds = kzalloc(sizeof(*tmp_ds), gfp_flags);
+       if (list_empty(dsaddrs)) {
+               dprintk("%s: no addresses defined\n", __func__);
+               goto out;
+       }
+
+       ds = kzalloc(sizeof(*ds), gfp_flags);
        if (!ds)
                goto out;
 
+       /* this is only used for debugging, so it's ok if its NULL */
+       remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags);
+
        spin_lock(&nfs4_ds_cache_lock);
-       tmp_ds = _data_server_lookup_locked(ip_addr, port);
+       tmp_ds = _data_server_lookup_locked(dsaddrs);
        if (tmp_ds == NULL) {
-               ds->ds_ip_addr = ip_addr;
-               ds->ds_port = port;
+               INIT_LIST_HEAD(&ds->ds_addrs);
+               list_splice_init(dsaddrs, &ds->ds_addrs);
+               ds->ds_remotestr = remotestr;
                atomic_set(&ds->ds_count, 1);
                INIT_LIST_HEAD(&ds->ds_node);
                ds->ds_clp = NULL;
                list_add(&ds->ds_node, &nfs4_data_server_cache);
-               dprintk("%s add new data server ip 0x%x\n", __func__,
-                       ds->ds_ip_addr);
+               dprintk("%s add new data server %s\n", __func__,
+                       ds->ds_remotestr);
        } else {
+               if (!_data_server_match_all_addrs_locked(&tmp_ds->ds_addrs,
+                                                        dsaddrs)) {
+                       dprintk("%s:  multipath address mismatch: %s != %s",
+                               __func__, tmp_ds->ds_remotestr, remotestr);
+               }
+               kfree(remotestr);
                kfree(ds);
                atomic_inc(&tmp_ds->ds_count);
-               dprintk("%s data server found ip 0x%x, inc'ed ds_count to %d\n",
-                       __func__, tmp_ds->ds_ip_addr,
+               dprintk("%s data server %s found, inc'ed ds_count to %d\n",
+                       __func__, tmp_ds->ds_remotestr,
                        atomic_read(&tmp_ds->ds_count));
                ds = tmp_ds;
        }
@@ -213,18 +375,22 @@ out:
 }
 
 /*
- * Currently only support ipv4, and one multi-path address.
+ * Currently only supports ipv4, ipv6 and one multi-path address.
  */
-static struct nfs4_pnfs_ds *
-decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode, gfp_t gfp_flags)
+static struct nfs4_pnfs_ds_addr *
+decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags)
 {
-       struct nfs4_pnfs_ds *ds = NULL;
-       char *buf;
-       const char *ipend, *pstr;
-       u32 ip_addr, port;
-       int nlen, rlen, i;
+       struct nfs4_pnfs_ds_addr *da = NULL;
+       char *buf, *portstr;
+       u32 port;
+       int nlen, rlen;
        int tmp[2];
        __be32 *p;
+       char *netid, *match_netid;
+       size_t len, match_netid_len;
+       char *startsep = "";
+       char *endsep = "";
+
 
        /* r_netid */
        p = xdr_inline_decode(streamp, 4);
@@ -236,64 +402,123 @@ decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode, gfp_t gfp_fla
        if (unlikely(!p))
                goto out_err;
 
-       /* Check that netid is "tcp" */
-       if (nlen != 3 ||  memcmp((char *)p, "tcp", 3)) {
-               dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__);
+       netid = kmalloc(nlen+1, gfp_flags);
+       if (unlikely(!netid))
                goto out_err;
-       }
 
-       /* r_addr */
+       netid[nlen] = '\0';
+       memcpy(netid, p, nlen);
+
+       /* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */
        p = xdr_inline_decode(streamp, 4);
        if (unlikely(!p))
-               goto out_err;
+               goto out_free_netid;
        rlen = be32_to_cpup(p);
 
        p = xdr_inline_decode(streamp, rlen);
        if (unlikely(!p))
-               goto out_err;
+               goto out_free_netid;
 
-       /* ipv6 length plus port is legal */
-       if (rlen > INET6_ADDRSTRLEN + 8) {
+       /* port is ".ABC.DEF", 8 chars max */
+       if (rlen > INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN + 8) {
                dprintk("%s: Invalid address, length %d\n", __func__,
                        rlen);
-               goto out_err;
+               goto out_free_netid;
        }
        buf = kmalloc(rlen + 1, gfp_flags);
        if (!buf) {
                dprintk("%s: Not enough memory\n", __func__);
-               goto out_err;
+               goto out_free_netid;
        }
        buf[rlen] = '\0';
        memcpy(buf, p, rlen);
 
-       /* replace the port dots with dashes for the in4_pton() delimiter*/
-       for (i = 0; i < 2; i++) {
-               char *res = strrchr(buf, '.');
-               if (!res) {
-                       dprintk("%s: Failed finding expected dots in port\n",
-                               __func__);
-                       goto out_free;
-               }
-               *res = '-';
+       /* replace port '.' with '-' */
+       portstr = strrchr(buf, '.');
+       if (!portstr) {
+               dprintk("%s: Failed finding expected dot in port\n",
+                       __func__);
+               goto out_free_buf;
+       }
+       *portstr = '-';
+
+       /* find '.' between address and port */
+       portstr = strrchr(buf, '.');
+       if (!portstr) {
+               dprintk("%s: Failed finding expected dot between address and "
+                       "port\n", __func__);
+               goto out_free_buf;
        }
+       *portstr = '\0';
 
-       /* Currently only support ipv4 address */
-       if (in4_pton(buf, rlen, (u8 *)&ip_addr, '-', &ipend) == 0) {
-               dprintk("%s: Only ipv4 addresses supported\n", __func__);
-               goto out_free;
+       da = kzalloc(sizeof(*da), gfp_flags);
+       if (unlikely(!da))
+               goto out_free_buf;
+
+       INIT_LIST_HEAD(&da->da_node);
+
+       if (!rpc_pton(buf, portstr-buf, (struct sockaddr *)&da->da_addr,
+                     sizeof(da->da_addr))) {
+               dprintk("%s: error parsing address %s\n", __func__, buf);
+               goto out_free_da;
        }
 
-       /* port */
-       pstr = ipend;
-       sscanf(pstr, "-%d-%d", &tmp[0], &tmp[1]);
+       portstr++;
+       sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]);
        port = htons((tmp[0] << 8) | (tmp[1]));
 
-       ds = nfs4_pnfs_ds_add(inode, ip_addr, port, gfp_flags);
-       dprintk("%s: Decoded address and port %s\n", __func__, buf);
-out_free:
+       switch (da->da_addr.ss_family) {
+       case AF_INET:
+               ((struct sockaddr_in *)&da->da_addr)->sin_port = port;
+               da->da_addrlen = sizeof(struct sockaddr_in);
+               match_netid = "tcp";
+               match_netid_len = 3;
+               break;
+
+       case AF_INET6:
+               ((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port;
+               da->da_addrlen = sizeof(struct sockaddr_in6);
+               match_netid = "tcp6";
+               match_netid_len = 4;
+               startsep = "[";
+               endsep = "]";
+               break;
+
+       default:
+               dprintk("%s: unsupported address family: %u\n",
+                       __func__, da->da_addr.ss_family);
+               goto out_free_da;
+       }
+
+       if (nlen != match_netid_len || strncmp(netid, match_netid, nlen)) {
+               dprintk("%s: ERROR: r_netid \"%s\" != \"%s\"\n",
+                       __func__, netid, match_netid);
+               goto out_free_da;
+       }
+
+       /* save human readable address */
+       len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7;
+       da->da_remotestr = kzalloc(len, gfp_flags);
+
+       /* NULL is ok, only used for dprintk */
+       if (da->da_remotestr)
+               snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep,
+                        buf, endsep, ntohs(port));
+
+       dprintk("%s: Parsed DS addr %s\n", __func__, da->da_remotestr);
        kfree(buf);
+       kfree(netid);
+       return da;
+
+out_free_da:
+       kfree(da);
+out_free_buf:
+       dprintk("%s: Error parsing DS addr: %s\n", __func__, buf);
+       kfree(buf);
+out_free_netid:
+       kfree(netid);
 out_err:
-       return ds;
+       return NULL;
 }
 
 /* Decode opaque device data and return the result */
@@ -310,6 +535,8 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
        struct xdr_stream stream;
        struct xdr_buf buf;
        struct page *scratch;
+       struct list_head dsaddrs;
+       struct nfs4_pnfs_ds_addr *da;
 
        /* set up xdr stream */
        scratch = alloc_page(gfp_flags);
@@ -386,6 +613,8 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
                                NFS_SERVER(ino)->nfs_client,
                                &pdev->dev_id);
 
+       INIT_LIST_HEAD(&dsaddrs);
+
        for (i = 0; i < dsaddr->ds_num; i++) {
                int j;
                u32 mp_count;
@@ -395,48 +624,43 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
                        goto out_err_free_deviceid;
 
                mp_count = be32_to_cpup(p); /* multipath count */
-               if (mp_count > 1) {
-                       printk(KERN_WARNING
-                              "%s: Multipath count %d not supported, "
-                              "skipping all greater than 1\n", __func__,
-                               mp_count);
-               }
                for (j = 0; j < mp_count; j++) {
-                       if (j == 0) {
-                               dsaddr->ds_list[i] = decode_and_add_ds(&stream,
-                                       ino, gfp_flags);
-                               if (dsaddr->ds_list[i] == NULL)
-                                       goto out_err_free_deviceid;
-                       } else {
-                               u32 len;
-                               /* skip extra multipath */
-
-                               /* read len, skip */
-                               p = xdr_inline_decode(&stream, 4);
-                               if (unlikely(!p))
-                                       goto out_err_free_deviceid;
-                               len = be32_to_cpup(p);
-
-                               p = xdr_inline_decode(&stream, len);
-                               if (unlikely(!p))
-                                       goto out_err_free_deviceid;
-
-                               /* read len, skip */
-                               p = xdr_inline_decode(&stream, 4);
-                               if (unlikely(!p))
-                                       goto out_err_free_deviceid;
-                               len = be32_to_cpup(p);
-
-                               p = xdr_inline_decode(&stream, len);
-                               if (unlikely(!p))
-                                       goto out_err_free_deviceid;
-                       }
+                       da = decode_ds_addr(&stream, gfp_flags);
+                       if (da)
+                               list_add_tail(&da->da_node, &dsaddrs);
+               }
+               if (list_empty(&dsaddrs)) {
+                       dprintk("%s: no suitable DS addresses found\n",
+                               __func__);
+                       goto out_err_free_deviceid;
+               }
+
+               dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags);
+               if (!dsaddr->ds_list[i])
+                       goto out_err_drain_dsaddrs;
+
+               /* If DS was already in cache, free ds addrs */
+               while (!list_empty(&dsaddrs)) {
+                       da = list_first_entry(&dsaddrs,
+                                             struct nfs4_pnfs_ds_addr,
+                                             da_node);
+                       list_del_init(&da->da_node);
+                       kfree(da->da_remotestr);
+                       kfree(da);
                }
        }
 
        __free_page(scratch);
        return dsaddr;
 
+out_err_drain_dsaddrs:
+       while (!list_empty(&dsaddrs)) {
+               da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr,
+                                     da_node);
+               list_del_init(&da->da_node);
+               kfree(da->da_remotestr);
+               kfree(da);
+       }
 out_err_free_deviceid:
        nfs4_fl_free_deviceid(dsaddr);
        /* stripe_indicies was part of dsaddr */
@@ -591,13 +815,13 @@ nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j)
 
 static void
 filelayout_mark_devid_negative(struct nfs4_file_layout_dsaddr *dsaddr,
-                              int err, u32 ds_addr)
+                              int err, const char *ds_remotestr)
 {
        u32 *p = (u32 *)&dsaddr->id_node.deviceid;
 
-       printk(KERN_ERR "NFS: data server %x connection error %d."
+       printk(KERN_ERR "NFS: data server %s connection error %d."
                " Deviceid [%x%x%x%x] marked out of use.\n",
-               ds_addr, err, p[0], p[1], p[2], p[3]);
+               ds_remotestr, err, p[0], p[1], p[2], p[3]);
 
        spin_lock(&nfs4_ds_cache_lock);
        dsaddr->flags |= NFS4_DEVICE_ID_NEG_ENTRY;
@@ -628,7 +852,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
                err = nfs4_ds_connect(s, ds);
                if (err) {
                        filelayout_mark_devid_negative(dsaddr, err,
-                                                      ntohl(ds->ds_ip_addr));
+                                                      ds->ds_remotestr);
                        return NULL;
                }
        }
index 26bece8f30830254e917b859799669576fad304a..8c77039e7a811a0fb08ab5e8f7f04e82e087642d 100644 (file)
@@ -80,7 +80,10 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
                            struct nfs_fattr *fattr, struct iattr *sattr,
                            struct nfs4_state *state);
-
+#ifdef CONFIG_NFS_V4_1
+static int nfs41_test_stateid(struct nfs_server *, struct nfs4_state *);
+static int nfs41_free_stateid(struct nfs_server *, struct nfs4_state *);
+#endif
 /* Prevent leaks of NFSv4 errors into userland */
 static int nfs4_map_errors(int err)
 {
@@ -137,12 +140,13 @@ const u32 nfs4_pathconf_bitmap[2] = {
        0
 };
 
-const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE
+const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
                        | FATTR4_WORD0_MAXREAD
                        | FATTR4_WORD0_MAXWRITE
                        | FATTR4_WORD0_LEASE_TIME,
                        FATTR4_WORD1_TIME_DELTA
-                       | FATTR4_WORD1_FS_LAYOUT_TYPES
+                       | FATTR4_WORD1_FS_LAYOUT_TYPES,
+                       FATTR4_WORD2_LAYOUT_BLKSIZE
 };
 
 const u32 nfs4_fs_locations_bitmap[2] = {
@@ -1689,6 +1693,20 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
        return ret;
 }
 
+#if defined(CONFIG_NFS_V4_1)
+static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
+{
+       int status;
+       struct nfs_server *server = NFS_SERVER(state->inode);
+
+       status = nfs41_test_stateid(server, state);
+       if (status == NFS_OK)
+               return 0;
+       nfs41_free_stateid(server, state);
+       return nfs4_open_expired(sp, state);
+}
+#endif
+
 /*
  * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-*
  * fields corresponding to attributes that were used to store the verifier.
@@ -2252,13 +2270,14 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
 static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
                              struct nfs_fsinfo *info)
 {
+       int minor_version = server->nfs_client->cl_minorversion;
        int status = nfs4_lookup_root(server, fhandle, info);
        if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
                /*
                 * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
                 * by nfs4_map_errors() as this function exits.
                 */
-               status = nfs4_find_root_sec(server, fhandle, info);
+               status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
        if (status == 0)
                status = nfs4_server_capabilities(server, fhandle);
        if (status == 0)
@@ -4441,6 +4460,20 @@ out:
        return err;
 }
 
+#if defined(CONFIG_NFS_V4_1)
+static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
+{
+       int status;
+       struct nfs_server *server = NFS_SERVER(state->inode);
+
+       status = nfs41_test_stateid(server, state);
+       if (status == NFS_OK)
+               return 0;
+       nfs41_free_stateid(server, state);
+       return nfs4_lock_expired(state, request);
+}
+#endif
+
 static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
        struct nfs_inode *nfsi = NFS_I(state->inode);
@@ -4779,6 +4812,16 @@ out_inval:
        return -NFS4ERR_INVAL;
 }
 
+static bool
+nfs41_same_server_scope(struct server_scope *a, struct server_scope *b)
+{
+       if (a->server_scope_sz == b->server_scope_sz &&
+           memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0)
+               return true;
+
+       return false;
+}
+
 /*
  * nfs4_proc_exchange_id()
  *
@@ -4821,9 +4864,31 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
                                init_utsname()->domainname,
                                clp->cl_rpcclient->cl_auth->au_flavor);
 
+       res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL);
+       if (unlikely(!res.server_scope))
+               return -ENOMEM;
+
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
        if (!status)
                status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
+
+       if (!status) {
+               if (clp->server_scope &&
+                   !nfs41_same_server_scope(clp->server_scope,
+                                            res.server_scope)) {
+                       dprintk("%s: server_scope mismatch detected\n",
+                               __func__);
+                       set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state);
+                       kfree(clp->server_scope);
+                       clp->server_scope = NULL;
+               }
+
+               if (!clp->server_scope)
+                       clp->server_scope = res.server_scope;
+               else
+                       kfree(res.server_scope);
+       }
+
        dprintk("<-- %s status= %d\n", __func__, status);
        return status;
 }
@@ -5704,7 +5769,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutreturn *lrp = calldata;
        struct nfs_server *server;
-       struct pnfs_layout_hdr *lo = NFS_I(lrp->args.inode)->layout;
+       struct pnfs_layout_hdr *lo = lrp->args.layout;
 
        dprintk("--> %s\n", __func__);
 
@@ -5733,7 +5798,7 @@ static void nfs4_layoutreturn_release(void *calldata)
        struct nfs4_layoutreturn *lrp = calldata;
 
        dprintk("--> %s\n", __func__);
-       put_layout_hdr(NFS_I(lrp->args.inode)->layout);
+       put_layout_hdr(lrp->args.layout);
        kfree(calldata);
        dprintk("<-- %s\n", __func__);
 }
@@ -5770,6 +5835,54 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
        return status;
 }
 
+/*
+ * Retrieve the list of Data Server devices from the MDS.
+ */
+static int _nfs4_getdevicelist(struct nfs_server *server,
+                                   const struct nfs_fh *fh,
+                                   struct pnfs_devicelist *devlist)
+{
+       struct nfs4_getdevicelist_args args = {
+               .fh = fh,
+               .layoutclass = server->pnfs_curr_ld->id,
+       };
+       struct nfs4_getdevicelist_res res = {
+               .devlist = devlist,
+       };
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICELIST],
+               .rpc_argp = &args,
+               .rpc_resp = &res,
+       };
+       int status;
+
+       dprintk("--> %s\n", __func__);
+       status = nfs4_call_sync(server->client, server, &msg, &args.seq_args,
+                               &res.seq_res, 0);
+       dprintk("<-- %s status=%d\n", __func__, status);
+       return status;
+}
+
+int nfs4_proc_getdevicelist(struct nfs_server *server,
+                           const struct nfs_fh *fh,
+                           struct pnfs_devicelist *devlist)
+{
+       struct nfs4_exception exception = { };
+       int err;
+
+       do {
+               err = nfs4_handle_exception(server,
+                               _nfs4_getdevicelist(server, fh, devlist),
+                               &exception);
+       } while (exception.retry);
+
+       dprintk("%s: err=%d, num_devs=%u\n", __func__,
+               err, devlist->num_devs);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(nfs4_proc_getdevicelist);
+
 static int
 _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
 {
@@ -5848,9 +5961,16 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
 static void nfs4_layoutcommit_release(void *calldata)
 {
        struct nfs4_layoutcommit_data *data = calldata;
+       struct pnfs_layout_segment *lseg, *tmp;
 
+       pnfs_cleanup_layoutcommit(data);
        /* Matched by references in pnfs_set_layoutcommit */
-       put_lseg(data->lseg);
+       list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) {
+               list_del_init(&lseg->pls_lc_list);
+               if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
+                                      &lseg->pls_flags))
+                       put_lseg(lseg);
+       }
        put_rpccred(data->cred);
        kfree(data);
 }
@@ -5901,6 +6021,143 @@ out:
        rpc_put_task(task);
        return status;
 }
+
+static int
+_nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
+                   struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
+{
+       struct nfs41_secinfo_no_name_args args = {
+               .style = SECINFO_STYLE_CURRENT_FH,
+       };
+       struct nfs4_secinfo_res res = {
+               .flavors = flavors,
+       };
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO_NO_NAME],
+               .rpc_argp = &args,
+               .rpc_resp = &res,
+       };
+       return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
+}
+
+static int
+nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
+                          struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
+{
+       struct nfs4_exception exception = { };
+       int err;
+       do {
+               err = _nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
+               switch (err) {
+               case 0:
+               case -NFS4ERR_WRONGSEC:
+               case -NFS4ERR_NOTSUPP:
+                       break;
+               default:
+                       err = nfs4_handle_exception(server, err, &exception);
+               }
+       } while (exception.retry);
+       return err;
+}
+
+static int
+nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
+                   struct nfs_fsinfo *info)
+{
+       int err;
+       struct page *page;
+       rpc_authflavor_t flavor;
+       struct nfs4_secinfo_flavors *flavors;
+
+       page = alloc_page(GFP_KERNEL);
+       if (!page) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       flavors = page_address(page);
+       err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
+
+       /*
+        * Fall back on "guess and check" method if
+        * the server doesn't support SECINFO_NO_NAME
+        */
+       if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) {
+               err = nfs4_find_root_sec(server, fhandle, info);
+               goto out_freepage;
+       }
+       if (err)
+               goto out_freepage;
+
+       flavor = nfs_find_best_sec(flavors);
+       if (err == 0)
+               err = nfs4_lookup_root_sec(server, fhandle, info, flavor);
+
+out_freepage:
+       put_page(page);
+       if (err == -EACCES)
+               return -EPERM;
+out:
+       return err;
+}
+static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state)
+{
+       int status;
+       struct nfs41_test_stateid_args args = {
+               .stateid = &state->stateid,
+       };
+       struct nfs41_test_stateid_res res;
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID],
+               .rpc_argp = &args,
+               .rpc_resp = &res,
+       };
+       args.seq_args.sa_session = res.seq_res.sr_session = NULL;
+       status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1);
+       return status;
+}
+
+static int nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state)
+{
+       struct nfs4_exception exception = { };
+       int err;
+       do {
+               err = nfs4_handle_exception(server,
+                               _nfs41_test_stateid(server, state),
+                               &exception);
+       } while (exception.retry);
+       return err;
+}
+
+static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *state)
+{
+       int status;
+       struct nfs41_free_stateid_args args = {
+               .stateid = &state->stateid,
+       };
+       struct nfs41_free_stateid_res res;
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID],
+               .rpc_argp = &args,
+               .rpc_resp = &res,
+       };
+
+       args.seq_args.sa_session = res.seq_res.sr_session = NULL;
+       status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1);
+       return status;
+}
+
+static int nfs41_free_stateid(struct nfs_server *server, struct nfs4_state *state)
+{
+       struct nfs4_exception exception = { };
+       int err;
+       do {
+               err = nfs4_handle_exception(server,
+                               _nfs4_free_stateid(server, state),
+                               &exception);
+       } while (exception.retry);
+       return err;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
@@ -5937,8 +6194,8 @@ struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
 struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
        .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
        .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
-       .recover_open   = nfs4_open_expired,
-       .recover_lock   = nfs4_lock_expired,
+       .recover_open   = nfs41_open_expired,
+       .recover_lock   = nfs41_lock_expired,
        .establish_clid = nfs41_init_clientid,
        .get_clid_cred  = nfs4_get_exchange_id_cred,
 };
@@ -5962,6 +6219,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
        .minor_version = 0,
        .call_sync = _nfs4_call_sync,
        .validate_stateid = nfs4_validate_delegation_stateid,
+       .find_root_sec = nfs4_find_root_sec,
        .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
        .state_renewal_ops = &nfs40_state_renewal_ops,
@@ -5972,6 +6230,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
        .minor_version = 1,
        .call_sync = _nfs4_call_sync_session,
        .validate_stateid = nfs41_validate_delegation_stateid,
+       .find_root_sec = nfs41_find_root_sec,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
        .state_renewal_ops = &nfs41_state_renewal_ops,
index 7acfe884362619d74c41fb9917badf660e9a33dc..72ab97ef3d617fdee9d2f538908dcac245f42093 100644 (file)
@@ -1643,7 +1643,14 @@ static void nfs4_state_manager(struct nfs_client *clp)
                                goto out_error;
                        }
                        clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
-                       set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
+
+                       if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH,
+                                              &clp->cl_state))
+                               nfs4_state_start_reclaim_nograce(clp);
+                       else
+                               set_bit(NFS4CLNT_RECLAIM_REBOOT,
+                                       &clp->cl_state);
+
                        pnfs_destroy_all_layouts(clp);
                }
 
index e6e8f3b9a1dea29908a5179a38293dfbefce0ad8..1dce12f41a4f8d48ceedccf192f64fd7617f6713 100644 (file)
@@ -113,7 +113,11 @@ static int nfs4_stat_to_errno(int);
 #define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
 #define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
 #define encode_fsinfo_maxsz    (encode_getattr_maxsz)
-#define decode_fsinfo_maxsz    (op_decode_hdr_maxsz + 15)
+/* The 5 accounts for the PNFS attributes, and assumes that at most three
+ * layout types will be returned.
+ */
+#define decode_fsinfo_maxsz    (op_decode_hdr_maxsz + \
+                                nfs4_fattr_bitmap_maxsz + 4 + 8 + 5)
 #define encode_renew_maxsz     (op_encode_hdr_maxsz + 3)
 #define decode_renew_maxsz     (op_decode_hdr_maxsz)
 #define encode_setclientid_maxsz \
@@ -314,6 +318,17 @@ static int nfs4_stat_to_errno(int);
                                XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
 #define encode_reclaim_complete_maxsz  (op_encode_hdr_maxsz + 4)
 #define decode_reclaim_complete_maxsz  (op_decode_hdr_maxsz + 4)
+#define encode_getdevicelist_maxsz (op_encode_hdr_maxsz + 4 + \
+                               encode_verifier_maxsz)
+#define decode_getdevicelist_maxsz (op_decode_hdr_maxsz + \
+                               2 /* nfs_cookie4 gdlr_cookie */ + \
+                               decode_verifier_maxsz \
+                                 /* verifier4 gdlr_verifier */ + \
+                               1 /* gdlr_deviceid_list count */ + \
+                               XDR_QUADLEN(NFS4_PNFS_GETDEVLIST_MAXNUM * \
+                                           NFS4_DEVICEID4_SIZE) \
+                                 /* gdlr_deviceid_list */ + \
+                               1 /* bool gdlr_eof */)
 #define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + 4 + \
                                XDR_QUADLEN(NFS4_DEVICEID4_SIZE))
 #define decode_getdeviceinfo_maxsz (op_decode_hdr_maxsz + \
@@ -343,6 +358,14 @@ static int nfs4_stat_to_errno(int);
                                1 /* FIXME: opaque lrf_body always empty at the moment */)
 #define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \
                                1 + decode_stateid_maxsz)
+#define encode_secinfo_no_name_maxsz (op_encode_hdr_maxsz + 1)
+#define decode_secinfo_no_name_maxsz decode_secinfo_maxsz
+#define encode_test_stateid_maxsz      (op_encode_hdr_maxsz + 2 + \
+                                        XDR_QUADLEN(NFS4_STATEID_SIZE))
+#define decode_test_stateid_maxsz      (op_decode_hdr_maxsz + 2 + 1)
+#define encode_free_stateid_maxsz      (op_encode_hdr_maxsz + 1 + \
+                                        XDR_QUADLEN(NFS4_STATEID_SIZE))
+#define decode_free_stateid_maxsz      (op_decode_hdr_maxsz + 1)
 #else /* CONFIG_NFS_V4_1 */
 #define encode_sequence_maxsz  0
 #define decode_sequence_maxsz  0
@@ -740,6 +763,14 @@ static int nfs4_stat_to_errno(int);
 #define NFS4_dec_reclaim_complete_sz   (compound_decode_hdr_maxsz + \
                                         decode_sequence_maxsz + \
                                         decode_reclaim_complete_maxsz)
+#define NFS4_enc_getdevicelist_sz (compound_encode_hdr_maxsz + \
+                               encode_sequence_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_getdevicelist_maxsz)
+#define NFS4_dec_getdevicelist_sz (compound_decode_hdr_maxsz + \
+                               decode_sequence_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_getdevicelist_maxsz)
 #define NFS4_enc_getdeviceinfo_sz (compound_encode_hdr_maxsz +    \
                                encode_sequence_maxsz +\
                                encode_getdeviceinfo_maxsz)
@@ -772,6 +803,26 @@ static int nfs4_stat_to_errno(int);
                                decode_sequence_maxsz + \
                                decode_putfh_maxsz + \
                                decode_layoutreturn_maxsz)
+#define NFS4_enc_secinfo_no_name_sz    (compound_encode_hdr_maxsz + \
+                                       encode_sequence_maxsz + \
+                                       encode_putrootfh_maxsz +\
+                                       encode_secinfo_no_name_maxsz)
+#define NFS4_dec_secinfo_no_name_sz    (compound_decode_hdr_maxsz + \
+                                       decode_sequence_maxsz + \
+                                       decode_putrootfh_maxsz + \
+                                       decode_secinfo_no_name_maxsz)
+#define NFS4_enc_test_stateid_sz       (compound_encode_hdr_maxsz + \
+                                        encode_sequence_maxsz + \
+                                        encode_test_stateid_maxsz)
+#define NFS4_dec_test_stateid_sz       (compound_decode_hdr_maxsz + \
+                                        decode_sequence_maxsz + \
+                                        decode_test_stateid_maxsz)
+#define NFS4_enc_free_stateid_sz       (compound_encode_hdr_maxsz + \
+                                        encode_sequence_maxsz + \
+                                        encode_free_stateid_maxsz)
+#define NFS4_dec_free_stateid_sz       (compound_decode_hdr_maxsz + \
+                                        decode_sequence_maxsz + \
+                                        decode_free_stateid_maxsz)
 
 const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
                                      compound_encode_hdr_maxsz +
@@ -1076,6 +1127,35 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm
        hdr->replen += decode_getattr_maxsz;
 }
 
+static void
+encode_getattr_three(struct xdr_stream *xdr,
+                    uint32_t bm0, uint32_t bm1, uint32_t bm2,
+                    struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 4);
+       *p = cpu_to_be32(OP_GETATTR);
+       if (bm2) {
+               p = reserve_space(xdr, 16);
+               *p++ = cpu_to_be32(3);
+               *p++ = cpu_to_be32(bm0);
+               *p++ = cpu_to_be32(bm1);
+               *p = cpu_to_be32(bm2);
+       } else if (bm1) {
+               p = reserve_space(xdr, 12);
+               *p++ = cpu_to_be32(2);
+               *p++ = cpu_to_be32(bm0);
+               *p = cpu_to_be32(bm1);
+       } else {
+               p = reserve_space(xdr, 8);
+               *p++ = cpu_to_be32(1);
+               *p = cpu_to_be32(bm0);
+       }
+       hdr->nops++;
+       hdr->replen += decode_getattr_maxsz;
+}
+
 static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
 {
        encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
@@ -1084,8 +1164,11 @@ static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct c
 
 static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
 {
-       encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
-                          bitmask[1] & nfs4_fsinfo_bitmap[1], hdr);
+       encode_getattr_three(xdr,
+                            bitmask[0] & nfs4_fsinfo_bitmap[0],
+                            bitmask[1] & nfs4_fsinfo_bitmap[1],
+                            bitmask[2] & nfs4_fsinfo_bitmap[2],
+                            hdr);
 }
 
 static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
@@ -1826,6 +1909,26 @@ static void encode_sequence(struct xdr_stream *xdr,
 }
 
 #ifdef CONFIG_NFS_V4_1
+static void
+encode_getdevicelist(struct xdr_stream *xdr,
+                    const struct nfs4_getdevicelist_args *args,
+                    struct compound_hdr *hdr)
+{
+       __be32 *p;
+       nfs4_verifier dummy = {
+               .data = "dummmmmy",
+       };
+
+       p = reserve_space(xdr, 20);
+       *p++ = cpu_to_be32(OP_GETDEVICELIST);
+       *p++ = cpu_to_be32(args->layoutclass);
+       *p++ = cpu_to_be32(NFS4_PNFS_GETDEVLIST_MAXNUM);
+       xdr_encode_hyper(p, 0ULL);                          /* cookie */
+       encode_nfs4_verifier(xdr, &dummy);
+       hdr->nops++;
+       hdr->replen += decode_getdevicelist_maxsz;
+}
+
 static void
 encode_getdeviceinfo(struct xdr_stream *xdr,
                     const struct nfs4_getdeviceinfo_args *args,
@@ -1888,7 +1991,7 @@ encode_layoutcommit(struct xdr_stream *xdr,
        *p++ = cpu_to_be32(OP_LAYOUTCOMMIT);
        /* Only whole file layouts */
        p = xdr_encode_hyper(p, 0); /* offset */
-       p = xdr_encode_hyper(p, NFS4_MAX_UINT64); /* length */
+       p = xdr_encode_hyper(p, args->lastbytewritten + 1);     /* length */
        *p++ = cpu_to_be32(0); /* reclaim */
        p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE);
        *p++ = cpu_to_be32(1); /* newoffset = TRUE */
@@ -1938,6 +2041,46 @@ encode_layoutreturn(struct xdr_stream *xdr,
        hdr->nops++;
        hdr->replen += decode_layoutreturn_maxsz;
 }
+
+static int
+encode_secinfo_no_name(struct xdr_stream *xdr,
+                      const struct nfs41_secinfo_no_name_args *args,
+                      struct compound_hdr *hdr)
+{
+       __be32 *p;
+       p = reserve_space(xdr, 8);
+       *p++ = cpu_to_be32(OP_SECINFO_NO_NAME);
+       *p++ = cpu_to_be32(args->style);
+       hdr->nops++;
+       hdr->replen += decode_secinfo_no_name_maxsz;
+       return 0;
+}
+
+static void encode_test_stateid(struct xdr_stream *xdr,
+                               struct nfs41_test_stateid_args *args,
+                               struct compound_hdr *hdr)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 8 + NFS4_STATEID_SIZE);
+       *p++ = cpu_to_be32(OP_TEST_STATEID);
+       *p++ = cpu_to_be32(1);
+       xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
+       hdr->nops++;
+       hdr->replen += decode_test_stateid_maxsz;
+}
+
+static void encode_free_stateid(struct xdr_stream *xdr,
+                               struct nfs41_free_stateid_args *args,
+                               struct compound_hdr *hdr)
+{
+       __be32 *p;
+       p = reserve_space(xdr, 4 + NFS4_STATEID_SIZE);
+       *p++ = cpu_to_be32(OP_FREE_STATEID);
+       xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
+       hdr->nops++;
+       hdr->replen += decode_free_stateid_maxsz;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 /*
@@ -2536,7 +2679,7 @@ static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
        struct compound_hdr hdr = {
                .nops   = 0,
        };
-       const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
+       const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
 
        encode_compound_hdr(xdr, req, &hdr);
        encode_setclientid_confirm(xdr, arg, &hdr);
@@ -2680,7 +2823,7 @@ static void nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req,
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->la_seq_args),
        };
-       const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
+       const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
 
        encode_compound_hdr(xdr, req, &hdr);
        encode_sequence(xdr, &args->la_seq_args, &hdr);
@@ -2706,6 +2849,24 @@ static void nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req,
        encode_nops(&hdr);
 }
 
+/*
+ * Encode GETDEVICELIST request
+ */
+static void nfs4_xdr_enc_getdevicelist(struct rpc_rqst *req,
+                                      struct xdr_stream *xdr,
+                                      struct nfs4_getdevicelist_args *args)
+{
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_putfh(xdr, args->fh, &hdr);
+       encode_getdevicelist(xdr, args, &hdr);
+       encode_nops(&hdr);
+}
+
 /*
  * Encode GETDEVICEINFO request
  */
@@ -2790,6 +2951,59 @@ static void nfs4_xdr_enc_layoutreturn(struct rpc_rqst *req,
        encode_layoutreturn(xdr, args, &hdr);
        encode_nops(&hdr);
 }
+
+/*
+ * Encode SECINFO_NO_NAME request
+ */
+static int nfs4_xdr_enc_secinfo_no_name(struct rpc_rqst *req,
+                                       struct xdr_stream *xdr,
+                                       struct nfs41_secinfo_no_name_args *args)
+{
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_putrootfh(xdr, &hdr);
+       encode_secinfo_no_name(xdr, args, &hdr);
+       encode_nops(&hdr);
+       return 0;
+}
+
+/*
+ *  Encode TEST_STATEID request
+ */
+static void nfs4_xdr_enc_test_stateid(struct rpc_rqst *req,
+                                     struct xdr_stream *xdr,
+                                     struct nfs41_test_stateid_args *args)
+{
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_test_stateid(xdr, args, &hdr);
+       encode_nops(&hdr);
+}
+
+/*
+ *  Encode FREE_STATEID request
+ */
+static void nfs4_xdr_enc_free_stateid(struct rpc_rqst *req,
+                                    struct xdr_stream *xdr,
+                                    struct nfs41_free_stateid_args *args)
+{
+       struct compound_hdr hdr = {
+               .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+       };
+
+       encode_compound_hdr(xdr, req, &hdr);
+       encode_sequence(xdr, &args->seq_args, &hdr);
+       encode_free_stateid(xdr, args, &hdr);
+       encode_nops(&hdr);
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
@@ -2890,14 +3104,17 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
                goto out_overflow;
        bmlen = be32_to_cpup(p);
 
-       bitmap[0] = bitmap[1] = 0;
+       bitmap[0] = bitmap[1] = bitmap[2] = 0;
        p = xdr_inline_decode(xdr, (bmlen << 2));
        if (unlikely(!p))
                goto out_overflow;
        if (bmlen > 0) {
                bitmap[0] = be32_to_cpup(p++);
-               if (bmlen > 1)
-                       bitmap[1] = be32_to_cpup(p);
+               if (bmlen > 1) {
+                       bitmap[1] = be32_to_cpup(p++);
+                       if (bmlen > 2)
+                               bitmap[2] = be32_to_cpup(p);
+               }
        }
        return 0;
 out_overflow:
@@ -2929,8 +3146,9 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3
                        return ret;
                bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
        } else
-               bitmask[0] = bitmask[1] = 0;
-       dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]);
+               bitmask[0] = bitmask[1] = bitmask[2] = 0;
+       dprintk("%s: bitmask=%08x:%08x:%08x\n", __func__,
+               bitmask[0], bitmask[1], bitmask[2]);
        return 0;
 }
 
@@ -3984,7 +4202,7 @@ out_overflow:
 static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2] = {0};
+       uint32_t attrlen, bitmap[3] = {0};
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4010,7 +4228,7 @@ xdr_error:
 static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2] = {0};
+       uint32_t attrlen, bitmap[3] = {0};
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4042,7 +4260,7 @@ xdr_error:
 static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2] = {0};
+       uint32_t attrlen, bitmap[3] = {0};
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4182,7 +4400,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
 {
        __be32 *savep;
        uint32_t attrlen,
-                bitmap[2] = {0};
+                bitmap[3] = {0};
        int status;
 
        status = decode_op_hdr(xdr, OP_GETATTR);
@@ -4268,10 +4486,32 @@ static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
        return status;
 }
 
+/*
+ * The prefered block size for layout directed io
+ */
+static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
+                                     uint32_t *res)
+{
+       __be32 *p;
+
+       dprintk("%s: bitmap is %x\n", __func__, bitmap[2]);
+       *res = 0;
+       if (bitmap[2] & FATTR4_WORD2_LAYOUT_BLKSIZE) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p)) {
+                       print_overflow_msg(__func__, xdr);
+                       return -EIO;
+               }
+               *res = be32_to_cpup(p);
+               bitmap[2] &= ~FATTR4_WORD2_LAYOUT_BLKSIZE;
+       }
+       return 0;
+}
+
 static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 {
        __be32 *savep;
-       uint32_t attrlen, bitmap[2];
+       uint32_t attrlen, bitmap[3];
        int status;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
@@ -4299,6 +4539,9 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
        status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype);
        if (status != 0)
                goto xdr_error;
+       status = decode_attr_layout_blksize(xdr, bitmap, &fsinfo->blksize);
+       if (status)
+               goto xdr_error;
 
        status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
@@ -4718,7 +4961,7 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
 {
        __be32 *savep;
        uint32_t attrlen,
-                bitmap[2] = {0};
+                bitmap[3] = {0};
        struct kvec *iov = req->rq_rcv_buf.head;
        int status;
 
@@ -4977,11 +5220,17 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        if (unlikely(status))
                return status;
 
-       /* Throw away server_scope */
+       /* Save server_scope */
        status = decode_opaque_inline(xdr, &dummy, &dummy_str);
        if (unlikely(status))
                return status;
 
+       if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+               return -EIO;
+
+       memcpy(res->server_scope->server_scope, dummy_str, dummy);
+       res->server_scope->server_scope_sz = dummy;
+
        /* Throw away Implementation id array */
        status = decode_opaque_inline(xdr, &dummy, &dummy_str);
        if (unlikely(status))
@@ -5141,6 +5390,53 @@ out_overflow:
 }
 
 #if defined(CONFIG_NFS_V4_1)
+/*
+ * TODO: Need to handle case when EOF != true;
+ */
+static int decode_getdevicelist(struct xdr_stream *xdr,
+                               struct pnfs_devicelist *res)
+{
+       __be32 *p;
+       int status, i;
+       struct nfs_writeverf verftemp;
+
+       status = decode_op_hdr(xdr, OP_GETDEVICELIST);
+       if (status)
+               return status;
+
+       p = xdr_inline_decode(xdr, 8 + 8 + 4);
+       if (unlikely(!p))
+               goto out_overflow;
+
+       /* TODO: Skip cookie for now */
+       p += 2;
+
+       /* Read verifier */
+       p = xdr_decode_opaque_fixed(p, verftemp.verifier, 8);
+
+       res->num_devs = be32_to_cpup(p);
+
+       dprintk("%s: num_dev %d\n", __func__, res->num_devs);
+
+       if (res->num_devs > NFS4_PNFS_GETDEVLIST_MAXNUM) {
+               printk(KERN_ERR "%s too many result dev_num %u\n",
+                               __func__, res->num_devs);
+               return -EIO;
+       }
+
+       p = xdr_inline_decode(xdr,
+                             res->num_devs * NFS4_DEVICEID4_SIZE + 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       for (i = 0; i < res->num_devs; i++)
+               p = xdr_decode_opaque_fixed(p, res->dev_id[i].data,
+                                           NFS4_DEVICEID4_SIZE);
+       res->eof = be32_to_cpup(p);
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
 
 static int decode_getdeviceinfo(struct xdr_stream *xdr,
                                struct pnfs_device *pdev)
@@ -5303,6 +5599,7 @@ static int decode_layoutcommit(struct xdr_stream *xdr,
        int status;
 
        status = decode_op_hdr(xdr, OP_LAYOUTCOMMIT);
+       res->status = status;
        if (status)
                return status;
 
@@ -5322,6 +5619,55 @@ out_overflow:
        print_overflow_msg(__func__, xdr);
        return -EIO;
 }
+
+static int decode_test_stateid(struct xdr_stream *xdr,
+                              struct nfs41_test_stateid_res *res)
+{
+       __be32 *p;
+       int status;
+       int num_res;
+
+       status = decode_op_hdr(xdr, OP_TEST_STATEID);
+       if (status)
+               return status;
+
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       num_res = be32_to_cpup(p++);
+       if (num_res != 1)
+               goto out;
+
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       res->status = be32_to_cpup(p++);
+       return res->status;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+out:
+       return -EIO;
+}
+
+static int decode_free_stateid(struct xdr_stream *xdr,
+                              struct nfs41_free_stateid_res *res)
+{
+       __be32 *p;
+       int status;
+
+       status = decode_op_hdr(xdr, OP_FREE_STATEID);
+       if (status)
+               return status;
+
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       res->status = be32_to_cpup(p++);
+       return res->status;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 /*
@@ -6365,6 +6711,32 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp,
        return status;
 }
 
+/*
+ * Decode GETDEVICELIST response
+ */
+static int nfs4_xdr_dec_getdevicelist(struct rpc_rqst *rqstp,
+                                     struct xdr_stream *xdr,
+                                     struct nfs4_getdevicelist_res *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       dprintk("encoding getdevicelist!\n");
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status != 0)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status != 0)
+               goto out;
+       status = decode_putfh(xdr);
+       if (status != 0)
+               goto out;
+       status = decode_getdevicelist(xdr, res->devlist);
+out:
+       return status;
+}
+
 /*
  * Decode GETDEVINFO response
  */
@@ -6461,6 +6833,72 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
 out:
        return status;
 }
+
+/*
+ * Decode SECINFO_NO_NAME response
+ */
+static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp,
+                                       struct xdr_stream *xdr,
+                                       struct nfs4_secinfo_res *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status)
+               goto out;
+       status = decode_putrootfh(xdr);
+       if (status)
+               goto out;
+       status = decode_secinfo(xdr, res);
+out:
+       return status;
+}
+
+/*
+ * Decode TEST_STATEID response
+ */
+static int nfs4_xdr_dec_test_stateid(struct rpc_rqst *rqstp,
+                                    struct xdr_stream *xdr,
+                                    struct nfs41_test_stateid_res *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status)
+               goto out;
+       status = decode_test_stateid(xdr, res);
+out:
+       return status;
+}
+
+/*
+ * Decode FREE_STATEID response
+ */
+static int nfs4_xdr_dec_free_stateid(struct rpc_rqst *rqstp,
+                                    struct xdr_stream *xdr,
+                                    struct nfs41_free_stateid_res *res)
+{
+       struct compound_hdr hdr;
+       int status;
+
+       status = decode_compound_hdr(xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_sequence(xdr, &res->seq_res, rqstp);
+       if (status)
+               goto out;
+       status = decode_free_stateid(xdr, res);
+out:
+       return status;
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 /**
@@ -6480,7 +6918,7 @@ out:
 int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                       int plus)
 {
-       uint32_t bitmap[2] = {0};
+       uint32_t bitmap[3] = {0};
        uint32_t len;
        __be32 *p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
@@ -6663,6 +7101,10 @@ struct rpc_procinfo      nfs4_procedures[] = {
        PROC(LAYOUTGET,         enc_layoutget,          dec_layoutget),
        PROC(LAYOUTCOMMIT,      enc_layoutcommit,       dec_layoutcommit),
        PROC(LAYOUTRETURN,      enc_layoutreturn,       dec_layoutreturn),
+       PROC(SECINFO_NO_NAME,   enc_secinfo_no_name,    dec_secinfo_no_name),
+       PROC(TEST_STATEID,      enc_test_stateid,       dec_test_stateid),
+       PROC(FREE_STATEID,      enc_free_stateid,       dec_free_stateid),
+       PROC(GETDEVICELIST,     enc_getdevicelist,      dec_getdevicelist),
 #endif /* CONFIG_NFS_V4_1 */
 };
 
index 8ff2ea3f10ef865ecd2b60ee89122afb159f6cdc..9383ca7245bc7f3ef5a5eeeb9a3b64248f933079 100644 (file)
@@ -1000,13 +1000,22 @@ static bool objio_pg_test(struct nfs_pageio_descriptor *pgio,
        if (!pnfs_generic_pg_test(pgio, prev, req))
                return false;
 
-       if (pgio->pg_lseg == NULL)
-               return true;
-
        return pgio->pg_count + req->wb_bytes <=
                        OBJIO_LSEG(pgio->pg_lseg)->max_io_size;
 }
 
+static const struct nfs_pageio_ops objio_pg_read_ops = {
+       .pg_init = pnfs_generic_pg_init_read,
+       .pg_test = objio_pg_test,
+       .pg_doio = pnfs_generic_pg_readpages,
+};
+
+static const struct nfs_pageio_ops objio_pg_write_ops = {
+       .pg_init = pnfs_generic_pg_init_write,
+       .pg_test = objio_pg_test,
+       .pg_doio = pnfs_generic_pg_writepages,
+};
+
 static struct pnfs_layoutdriver_type objlayout_type = {
        .id = LAYOUT_OSD2_OBJECTS,
        .name = "LAYOUT_OSD2_OBJECTS",
@@ -1020,7 +1029,8 @@ static struct pnfs_layoutdriver_type objlayout_type = {
 
        .read_pagelist           = objlayout_read_pagelist,
        .write_pagelist          = objlayout_write_pagelist,
-       .pg_test                 = objio_pg_test,
+       .pg_read_ops             = &objio_pg_read_ops,
+       .pg_write_ops            = &objio_pg_write_ops,
 
        .free_deviceid_node      = objio_free_deviceid_node,
 
@@ -1055,5 +1065,7 @@ objlayout_exit(void)
               __func__);
 }
 
+MODULE_ALIAS("nfs-layouttype4-2");
+
 module_init(objlayout_init);
 module_exit(objlayout_exit);
index 18449f43c568313f67abc036036fa7110b19d0e7..b60970cc7f1f0f688c80b80674848b940265625c 100644 (file)
@@ -230,7 +230,7 @@ EXPORT_SYMBOL_GPL(nfs_generic_pg_test);
  */
 void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
                     struct inode *inode,
-                    int (*doio)(struct nfs_pageio_descriptor *),
+                    const struct nfs_pageio_ops *pg_ops,
                     size_t bsize,
                     int io_flags)
 {
@@ -240,13 +240,12 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
        desc->pg_bsize = bsize;
        desc->pg_base = 0;
        desc->pg_moreio = 0;
+       desc->pg_recoalesce = 0;
        desc->pg_inode = inode;
-       desc->pg_doio = doio;
+       desc->pg_ops = pg_ops;
        desc->pg_ioflags = io_flags;
        desc->pg_error = 0;
        desc->pg_lseg = NULL;
-       desc->pg_test = nfs_generic_pg_test;
-       pnfs_pageio_init(desc, inode);
 }
 
 /**
@@ -276,7 +275,7 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
                return false;
        if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
                return false;
-       return pgio->pg_test(pgio, prev, req);
+       return pgio->pg_ops->pg_test(pgio, prev, req);
 }
 
 /**
@@ -297,6 +296,8 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
                if (!nfs_can_coalesce_requests(prev, req, desc))
                        return 0;
        } else {
+               if (desc->pg_ops->pg_init)
+                       desc->pg_ops->pg_init(desc, req);
                desc->pg_base = req->wb_pgbase;
        }
        nfs_list_remove_request(req);
@@ -311,7 +312,7 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
 static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
 {
        if (!list_empty(&desc->pg_list)) {
-               int error = desc->pg_doio(desc);
+               int error = desc->pg_ops->pg_doio(desc);
                if (error < 0)
                        desc->pg_error = error;
                else
@@ -331,7 +332,7 @@ static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
  * Returns true if the request 'req' was successfully coalesced into the
  * existing list of pages 'desc'.
  */
-int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
+static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
                           struct nfs_page *req)
 {
        while (!nfs_pageio_do_add_request(desc, req)) {
@@ -340,17 +341,67 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
                if (desc->pg_error < 0)
                        return 0;
                desc->pg_moreio = 0;
+               if (desc->pg_recoalesce)
+                       return 0;
        }
        return 1;
 }
 
+static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
+{
+       LIST_HEAD(head);
+
+       do {
+               list_splice_init(&desc->pg_list, &head);
+               desc->pg_bytes_written -= desc->pg_count;
+               desc->pg_count = 0;
+               desc->pg_base = 0;
+               desc->pg_recoalesce = 0;
+
+               while (!list_empty(&head)) {
+                       struct nfs_page *req;
+
+                       req = list_first_entry(&head, struct nfs_page, wb_list);
+                       nfs_list_remove_request(req);
+                       if (__nfs_pageio_add_request(desc, req))
+                               continue;
+                       if (desc->pg_error < 0)
+                               return 0;
+                       break;
+               }
+       } while (desc->pg_recoalesce);
+       return 1;
+}
+
+int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
+               struct nfs_page *req)
+{
+       int ret;
+
+       do {
+               ret = __nfs_pageio_add_request(desc, req);
+               if (ret)
+                       break;
+               if (desc->pg_error < 0)
+                       break;
+               ret = nfs_do_recoalesce(desc);
+       } while (ret);
+       return ret;
+}
+
 /**
  * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor
  * @desc: pointer to io descriptor
  */
 void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
 {
-       nfs_pageio_doio(desc);
+       for (;;) {
+               nfs_pageio_doio(desc);
+               if (!desc->pg_recoalesce)
+                       break;
+               if (!nfs_do_recoalesce(desc))
+                       break;
+       }
 }
 
 /**
@@ -369,7 +420,7 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
        if (!list_empty(&desc->pg_list)) {
                struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev);
                if (index != prev->wb_index + 1)
-                       nfs_pageio_doio(desc);
+                       nfs_pageio_complete(desc);
        }
 }
 
index 29c0ca7fc347cdf8cebf6bd83960de18942ca4e4..e550e8836c3759acb041e035078387a869e1f2c8 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 #include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
 #include "internal.h"
 #include "pnfs.h"
 #include "iostat.h"
@@ -75,8 +76,11 @@ find_pnfs_driver(u32 id)
 void
 unset_pnfs_layoutdriver(struct nfs_server *nfss)
 {
-       if (nfss->pnfs_curr_ld)
+       if (nfss->pnfs_curr_ld) {
+               if (nfss->pnfs_curr_ld->clear_layoutdriver)
+                       nfss->pnfs_curr_ld->clear_layoutdriver(nfss);
                module_put(nfss->pnfs_curr_ld->owner);
+       }
        nfss->pnfs_curr_ld = NULL;
 }
 
@@ -87,7 +91,8 @@ unset_pnfs_layoutdriver(struct nfs_server *nfss)
  * @id layout type. Zero (illegal layout type) indicates pNFS not in use.
  */
 void
-set_pnfs_layoutdriver(struct nfs_server *server, u32 id)
+set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
+                     u32 id)
 {
        struct pnfs_layoutdriver_type *ld_type = NULL;
 
@@ -114,6 +119,13 @@ set_pnfs_layoutdriver(struct nfs_server *server, u32 id)
                goto out_no_driver;
        }
        server->pnfs_curr_ld = ld_type;
+       if (ld_type->set_layoutdriver
+           && ld_type->set_layoutdriver(server, mntfh)) {
+               printk(KERN_ERR "%s: Error initializing pNFS layout driver %u.\n",
+                               __func__, id);
+               module_put(ld_type->owner);
+               goto out_no_driver;
+       }
 
        dprintk("%s: pNFS module for %u set\n", __func__, id);
        return;
@@ -189,6 +201,7 @@ static void
 pnfs_free_layout_hdr(struct pnfs_layout_hdr *lo)
 {
        struct pnfs_layoutdriver_type *ld = NFS_SERVER(lo->plh_inode)->pnfs_curr_ld;
+       put_rpccred(lo->plh_lc_cred);
        return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo);
 }
 
@@ -223,6 +236,7 @@ static void
 init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
 {
        INIT_LIST_HEAD(&lseg->pls_list);
+       INIT_LIST_HEAD(&lseg->pls_lc_list);
        atomic_set(&lseg->pls_refcount, 1);
        smp_mb();
        set_bit(NFS_LSEG_VALID, &lseg->pls_flags);
@@ -448,11 +462,20 @@ pnfs_destroy_layout(struct nfs_inode *nfsi)
 void
 pnfs_destroy_all_layouts(struct nfs_client *clp)
 {
+       struct nfs_server *server;
        struct pnfs_layout_hdr *lo;
        LIST_HEAD(tmp_list);
 
+       nfs4_deviceid_mark_client_invalid(clp);
+       nfs4_deviceid_purge_client(clp);
+
        spin_lock(&clp->cl_lock);
-       list_splice_init(&clp->cl_layouts, &tmp_list);
+       rcu_read_lock();
+       list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
+               if (!list_empty(&server->layouts))
+                       list_splice_init(&server->layouts, &tmp_list);
+       }
+       rcu_read_unlock();
        spin_unlock(&clp->cl_lock);
 
        while (!list_empty(&tmp_list)) {
@@ -661,6 +684,7 @@ _pnfs_return_layout(struct inode *ino)
        lrp->args.stateid = stateid;
        lrp->args.layout_type = NFS_SERVER(ino)->pnfs_curr_ld->id;
        lrp->args.inode = ino;
+       lrp->args.layout = lo;
        lrp->clp = NFS_SERVER(ino)->nfs_client;
 
        status = nfs4_proc_layoutreturn(lrp);
@@ -805,7 +829,9 @@ out:
 }
 
 static struct pnfs_layout_hdr *
-alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags)
+alloc_init_layout_hdr(struct inode *ino,
+                     struct nfs_open_context *ctx,
+                     gfp_t gfp_flags)
 {
        struct pnfs_layout_hdr *lo;
 
@@ -817,11 +843,14 @@ alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags)
        INIT_LIST_HEAD(&lo->plh_segs);
        INIT_LIST_HEAD(&lo->plh_bulk_recall);
        lo->plh_inode = ino;
+       lo->plh_lc_cred = get_rpccred(ctx->state->owner->so_cred);
        return lo;
 }
 
 static struct pnfs_layout_hdr *
-pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags)
+pnfs_find_alloc_layout(struct inode *ino,
+                      struct nfs_open_context *ctx,
+                      gfp_t gfp_flags)
 {
        struct nfs_inode *nfsi = NFS_I(ino);
        struct pnfs_layout_hdr *new = NULL;
@@ -836,7 +865,7 @@ pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags)
                        return nfsi->layout;
        }
        spin_unlock(&ino->i_lock);
-       new = alloc_init_layout_hdr(ino, gfp_flags);
+       new = alloc_init_layout_hdr(ino, ctx, gfp_flags);
        spin_lock(&ino->i_lock);
 
        if (likely(nfsi->layout == NULL))       /* Won the race? */
@@ -920,7 +949,8 @@ pnfs_update_layout(struct inode *ino,
        };
        unsigned pg_offset;
        struct nfs_inode *nfsi = NFS_I(ino);
-       struct nfs_client *clp = NFS_SERVER(ino)->nfs_client;
+       struct nfs_server *server = NFS_SERVER(ino);
+       struct nfs_client *clp = server->nfs_client;
        struct pnfs_layout_hdr *lo;
        struct pnfs_layout_segment *lseg = NULL;
        bool first = false;
@@ -928,7 +958,7 @@ pnfs_update_layout(struct inode *ino,
        if (!pnfs_enabled_sb(NFS_SERVER(ino)))
                return NULL;
        spin_lock(&ino->i_lock);
-       lo = pnfs_find_alloc_layout(ino, gfp_flags);
+       lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
        if (lo == NULL) {
                dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
                goto out_unlock;
@@ -964,7 +994,7 @@ pnfs_update_layout(struct inode *ino,
                 */
                spin_lock(&clp->cl_lock);
                BUG_ON(!list_empty(&lo->plh_layouts));
-               list_add_tail(&lo->plh_layouts, &clp->cl_layouts);
+               list_add_tail(&lo->plh_layouts, &server->layouts);
                spin_unlock(&clp->cl_lock);
        }
 
@@ -973,7 +1003,8 @@ pnfs_update_layout(struct inode *ino,
                arg.offset -= pg_offset;
                arg.length += pg_offset;
        }
-       arg.length = PAGE_CACHE_ALIGN(arg.length);
+       if (arg.length != NFS4_MAX_UINT64)
+               arg.length = PAGE_CACHE_ALIGN(arg.length);
 
        lseg = send_layoutget(lo, ctx, &arg, gfp_flags);
        if (!lseg && first) {
@@ -991,6 +1022,7 @@ out_unlock:
        spin_unlock(&ino->i_lock);
        goto out;
 }
+EXPORT_SYMBOL_GPL(pnfs_update_layout);
 
 int
 pnfs_layout_process(struct nfs4_layoutget *lgp)
@@ -1048,35 +1080,71 @@ out_forget_reply:
        goto out;
 }
 
+void
+pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+{
+       BUG_ON(pgio->pg_lseg != NULL);
+
+       pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
+                                          req->wb_context,
+                                          req_offset(req),
+                                          req->wb_bytes,
+                                          IOMODE_READ,
+                                          GFP_KERNEL);
+       /* If no lseg, fall back to read through mds */
+       if (pgio->pg_lseg == NULL)
+               nfs_pageio_reset_read_mds(pgio);
+
+}
+EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_read);
+
+void
+pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+{
+       BUG_ON(pgio->pg_lseg != NULL);
+
+       pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
+                                          req->wb_context,
+                                          req_offset(req),
+                                          req->wb_bytes,
+                                          IOMODE_RW,
+                                          GFP_NOFS);
+       /* If no lseg, fall back to write through mds */
+       if (pgio->pg_lseg == NULL)
+               nfs_pageio_reset_write_mds(pgio);
+}
+EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write);
+
 bool
-pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
-                    struct nfs_page *req)
+pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode)
 {
-       enum pnfs_iomode access_type;
-       gfp_t gfp_flags;
+       struct nfs_server *server = NFS_SERVER(inode);
+       struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
 
-       /* We assume that pg_ioflags == 0 iff we're reading a page */
-       if (pgio->pg_ioflags == 0) {
-               access_type = IOMODE_READ;
-               gfp_flags = GFP_KERNEL;
-       } else {
-               access_type = IOMODE_RW;
-               gfp_flags = GFP_NOFS;
-       }
+       if (ld == NULL)
+               return false;
+       nfs_pageio_init(pgio, inode, ld->pg_read_ops, server->rsize, 0);
+       return true;
+}
 
-       if (pgio->pg_lseg == NULL) {
-               if (pgio->pg_count != prev->wb_bytes)
-                       return true;
-               /* This is first coelesce call for a series of nfs_pages */
-               pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
-                                                  prev->wb_context,
-                                                  req_offset(prev),
-                                                  pgio->pg_count,
-                                                  access_type,
-                                                  gfp_flags);
-               if (pgio->pg_lseg == NULL)
-                       return true;
-       }
+bool
+pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags)
+{
+       struct nfs_server *server = NFS_SERVER(inode);
+       struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
+
+       if (ld == NULL)
+               return false;
+       nfs_pageio_init(pgio, inode, ld->pg_write_ops, server->wsize, ioflags);
+       return true;
+}
+
+bool
+pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
+                    struct nfs_page *req)
+{
+       if (pgio->pg_lseg == NULL)
+               return nfs_generic_pg_test(pgio, prev, req);
 
        /*
         * Test if a nfs_page is fully contained in the pnfs_layout_range.
@@ -1120,15 +1188,30 @@ pnfs_ld_write_done(struct nfs_write_data *data)
 }
 EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
 
-enum pnfs_try_status
+static void
+pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
+               struct nfs_write_data *data)
+{
+       list_splice_tail_init(&data->pages, &desc->pg_list);
+       if (data->req && list_empty(&data->req->wb_list))
+               nfs_list_add_request(data->req, &desc->pg_list);
+       nfs_pageio_reset_write_mds(desc);
+       desc->pg_recoalesce = 1;
+       nfs_writedata_release(data);
+}
+
+static enum pnfs_try_status
 pnfs_try_to_write_data(struct nfs_write_data *wdata,
-                       const struct rpc_call_ops *call_ops, int how)
+                       const struct rpc_call_ops *call_ops,
+                       struct pnfs_layout_segment *lseg,
+                       int how)
 {
        struct inode *inode = wdata->inode;
        enum pnfs_try_status trypnfs;
        struct nfs_server *nfss = NFS_SERVER(inode);
 
        wdata->mds_ops = call_ops;
+       wdata->lseg = get_lseg(lseg);
 
        dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__,
                inode->i_ino, wdata->args.count, wdata->args.offset, how);
@@ -1144,6 +1227,44 @@ pnfs_try_to_write_data(struct nfs_write_data *wdata,
        return trypnfs;
 }
 
+static void
+pnfs_do_multiple_writes(struct nfs_pageio_descriptor *desc, struct list_head *head, int how)
+{
+       struct nfs_write_data *data;
+       const struct rpc_call_ops *call_ops = desc->pg_rpc_callops;
+       struct pnfs_layout_segment *lseg = desc->pg_lseg;
+
+       desc->pg_lseg = NULL;
+       while (!list_empty(head)) {
+               enum pnfs_try_status trypnfs;
+
+               data = list_entry(head->next, struct nfs_write_data, list);
+               list_del_init(&data->list);
+
+               trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how);
+               if (trypnfs == PNFS_NOT_ATTEMPTED)
+                       pnfs_write_through_mds(desc, data);
+       }
+       put_lseg(lseg);
+}
+
+int
+pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
+{
+       LIST_HEAD(head);
+       int ret;
+
+       ret = nfs_generic_flush(desc, &head);
+       if (ret != 0) {
+               put_lseg(desc->pg_lseg);
+               desc->pg_lseg = NULL;
+               return ret;
+       }
+       pnfs_do_multiple_writes(desc, &head, desc->pg_ioflags);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages);
+
 /*
  * Called by non rpc-based layout drivers
  */
@@ -1167,18 +1288,32 @@ pnfs_ld_read_done(struct nfs_read_data *data)
 }
 EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
 
+static void
+pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
+               struct nfs_read_data *data)
+{
+       list_splice_tail_init(&data->pages, &desc->pg_list);
+       if (data->req && list_empty(&data->req->wb_list))
+               nfs_list_add_request(data->req, &desc->pg_list);
+       nfs_pageio_reset_read_mds(desc);
+       desc->pg_recoalesce = 1;
+       nfs_readdata_release(data);
+}
+
 /*
  * Call the appropriate parallel I/O subsystem read function.
  */
-enum pnfs_try_status
+static enum pnfs_try_status
 pnfs_try_to_read_data(struct nfs_read_data *rdata,
-                      const struct rpc_call_ops *call_ops)
+                      const struct rpc_call_ops *call_ops,
+                      struct pnfs_layout_segment *lseg)
 {
        struct inode *inode = rdata->inode;
        struct nfs_server *nfss = NFS_SERVER(inode);
        enum pnfs_try_status trypnfs;
 
        rdata->mds_ops = call_ops;
+       rdata->lseg = get_lseg(lseg);
 
        dprintk("%s: Reading ino:%lu %u@%llu\n",
                __func__, inode->i_ino, rdata->args.count, rdata->args.offset);
@@ -1194,17 +1329,56 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata,
        return trypnfs;
 }
 
+static void
+pnfs_do_multiple_reads(struct nfs_pageio_descriptor *desc, struct list_head *head)
+{
+       struct nfs_read_data *data;
+       const struct rpc_call_ops *call_ops = desc->pg_rpc_callops;
+       struct pnfs_layout_segment *lseg = desc->pg_lseg;
+
+       desc->pg_lseg = NULL;
+       while (!list_empty(head)) {
+               enum pnfs_try_status trypnfs;
+
+               data = list_entry(head->next, struct nfs_read_data, list);
+               list_del_init(&data->list);
+
+               trypnfs = pnfs_try_to_read_data(data, call_ops, lseg);
+               if (trypnfs == PNFS_NOT_ATTEMPTED)
+                       pnfs_read_through_mds(desc, data);
+       }
+       put_lseg(lseg);
+}
+
+int
+pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
+{
+       LIST_HEAD(head);
+       int ret;
+
+       ret = nfs_generic_pagein(desc, &head);
+       if (ret != 0) {
+               put_lseg(desc->pg_lseg);
+               desc->pg_lseg = NULL;
+               return ret;
+       }
+       pnfs_do_multiple_reads(desc, &head);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages);
+
 /*
- * Currently there is only one (whole file) write lseg.
+ * There can be multiple RW segments.
  */
-static struct pnfs_layout_segment *pnfs_list_write_lseg(struct inode *inode)
+static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
 {
-       struct pnfs_layout_segment *lseg, *rv = NULL;
+       struct pnfs_layout_segment *lseg;
 
-       list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
-               if (lseg->pls_range.iomode == IOMODE_RW)
-                       rv = lseg;
-       return rv;
+       list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
+               if (lseg->pls_range.iomode == IOMODE_RW &&
+                   test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
+                       list_add(&lseg->pls_lc_list, listp);
+       }
 }
 
 void
@@ -1216,17 +1390,19 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
 
        spin_lock(&nfsi->vfs_inode.i_lock);
        if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
-               /* references matched in nfs4_layoutcommit_release */
-               get_lseg(wdata->lseg);
-               wdata->lseg->pls_lc_cred =
-                       get_rpccred(wdata->args.context->state->owner->so_cred);
                mark_as_dirty = true;
                dprintk("%s: Set layoutcommit for inode %lu ",
                        __func__, wdata->inode->i_ino);
        }
-       if (end_pos > wdata->lseg->pls_end_pos)
-               wdata->lseg->pls_end_pos = end_pos;
+       if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &wdata->lseg->pls_flags)) {
+               /* references matched in nfs4_layoutcommit_release */
+               get_lseg(wdata->lseg);
+       }
+       if (end_pos > nfsi->layout->plh_lwb)
+               nfsi->layout->plh_lwb = end_pos;
        spin_unlock(&nfsi->vfs_inode.i_lock);
+       dprintk("%s: lseg %p end_pos %llu\n",
+               __func__, wdata->lseg, nfsi->layout->plh_lwb);
 
        /* if pnfs_layoutcommit_inode() runs between inode locks, the next one
         * will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */
@@ -1235,6 +1411,14 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
 }
 EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit);
 
+void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data)
+{
+       struct nfs_server *nfss = NFS_SERVER(data->args.inode);
+
+       if (nfss->pnfs_curr_ld->cleanup_layoutcommit)
+               nfss->pnfs_curr_ld->cleanup_layoutcommit(data);
+}
+
 /*
  * For the LAYOUT4_NFSV4_1_FILES layout type, NFS_DATA_SYNC WRITEs and
  * NFS_UNSTABLE WRITEs with a COMMIT to data servers must store enough
@@ -1248,8 +1432,6 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 {
        struct nfs4_layoutcommit_data *data;
        struct nfs_inode *nfsi = NFS_I(inode);
-       struct pnfs_layout_segment *lseg;
-       struct rpc_cred *cred;
        loff_t end_pos;
        int status = 0;
 
@@ -1266,30 +1448,25 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
                goto out;
        }
 
+       INIT_LIST_HEAD(&data->lseg_list);
        spin_lock(&inode->i_lock);
        if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
                spin_unlock(&inode->i_lock);
                kfree(data);
                goto out;
        }
-       /*
-        * Currently only one (whole file) write lseg which is referenced
-        * in pnfs_set_layoutcommit and will be found.
-        */
-       lseg = pnfs_list_write_lseg(inode);
 
-       end_pos = lseg->pls_end_pos;
-       cred = lseg->pls_lc_cred;
-       lseg->pls_end_pos = 0;
-       lseg->pls_lc_cred = NULL;
+       pnfs_list_write_lseg(inode, &data->lseg_list);
+
+       end_pos = nfsi->layout->plh_lwb;
+       nfsi->layout->plh_lwb = 0;
 
        memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data,
                sizeof(nfsi->layout->plh_stateid.data));
        spin_unlock(&inode->i_lock);
 
        data->args.inode = inode;
-       data->lseg = lseg;
-       data->cred = cred;
+       data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
        nfs_fattr_init(&data->fattr);
        data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
        data->res.fattr = &data->fattr;
index 96bf4e6f45beda6d9646c5b19a48d13ef1ec3f5d..01cbfd54f3cb814a868ee6096790f16184e40075 100644 (file)
 enum {
        NFS_LSEG_VALID = 0,     /* cleared when lseg is recalled/returned */
        NFS_LSEG_ROC,           /* roc bit received from server */
+       NFS_LSEG_LAYOUTCOMMIT,  /* layoutcommit bit set for layoutcommit */
 };
 
 struct pnfs_layout_segment {
        struct list_head pls_list;
+       struct list_head pls_lc_list;
        struct pnfs_layout_range pls_range;
        atomic_t pls_refcount;
        unsigned long pls_flags;
        struct pnfs_layout_hdr *pls_layout;
-       struct rpc_cred *pls_lc_cred; /* LAYOUTCOMMIT credential */
-       loff_t pls_end_pos; /* LAYOUTCOMMIT write end */
 };
 
 enum pnfs_try_status {
@@ -80,6 +80,9 @@ struct pnfs_layoutdriver_type {
        struct module *owner;
        unsigned flags;
 
+       int (*set_layoutdriver) (struct nfs_server *, const struct nfs_fh *);
+       int (*clear_layoutdriver) (struct nfs_server *);
+
        struct pnfs_layout_hdr * (*alloc_layout_hdr) (struct inode *inode, gfp_t gfp_flags);
        void (*free_layout_hdr) (struct pnfs_layout_hdr *);
 
@@ -87,7 +90,8 @@ struct pnfs_layoutdriver_type {
        void (*free_lseg) (struct pnfs_layout_segment *lseg);
 
        /* test for nfs page cache coalescing */
-       bool (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
+       const struct nfs_pageio_ops *pg_read_ops;
+       const struct nfs_pageio_ops *pg_write_ops;
 
        /* Returns true if layoutdriver wants to divert this request to
         * driver's commit routine.
@@ -109,6 +113,8 @@ struct pnfs_layoutdriver_type {
                                     struct xdr_stream *xdr,
                                     const struct nfs4_layoutreturn_args *args);
 
+       void (*cleanup_layoutcommit) (struct nfs4_layoutcommit_data *data);
+
        void (*encode_layoutcommit) (struct pnfs_layout_hdr *layoutid,
                                     struct xdr_stream *xdr,
                                     const struct nfs4_layoutcommit_args *args);
@@ -124,6 +130,8 @@ struct pnfs_layout_hdr {
        unsigned long           plh_block_lgets; /* block LAYOUTGET if >0 */
        u32                     plh_barrier; /* ignore lower seqids */
        unsigned long           plh_flags;
+       loff_t                  plh_lwb; /* last write byte for layoutcommit */
+       struct rpc_cred         *plh_lc_cred; /* layoutcommit cred */
        struct inode            *plh_inode;
 };
 
@@ -136,10 +144,21 @@ struct pnfs_device {
        unsigned int  pglen;
 };
 
+#define NFS4_PNFS_GETDEVLIST_MAXNUM 16
+
+struct pnfs_devicelist {
+       unsigned int            eof;
+       unsigned int            num_devs;
+       struct nfs4_deviceid    dev_id[NFS4_PNFS_GETDEVLIST_MAXNUM];
+};
+
 extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *);
 extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
 
 /* nfs4proc.c */
+extern int nfs4_proc_getdevicelist(struct nfs_server *server,
+                                  const struct nfs_fh *fh,
+                                  struct pnfs_devicelist *devlist);
 extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
                                   struct pnfs_device *dev);
 extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
@@ -148,16 +167,16 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp);
 /* pnfs.c */
 void get_layout_hdr(struct pnfs_layout_hdr *lo);
 void put_lseg(struct pnfs_layout_segment *lseg);
-struct pnfs_layout_segment *
-pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
-                  loff_t pos, u64 count, enum pnfs_iomode access_type,
-                  gfp_t gfp_flags);
-void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
+
+bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *);
+bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *, int);
+
+void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32);
 void unset_pnfs_layoutdriver(struct nfs_server *);
-enum pnfs_try_status pnfs_try_to_write_data(struct nfs_write_data *,
-                                            const struct rpc_call_ops *, int);
-enum pnfs_try_status pnfs_try_to_read_data(struct nfs_read_data *,
-                                           const struct rpc_call_ops *);
+void pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *, struct nfs_page *);
+int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc);
+void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *, struct nfs_page *);
+int pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc);
 bool pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, struct nfs_page *req);
 int pnfs_layout_process(struct nfs4_layoutget *lgp);
 void pnfs_free_lseg_list(struct list_head *tmp_list);
@@ -178,10 +197,24 @@ void pnfs_roc_release(struct inode *ino);
 void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
 bool pnfs_roc_drain(struct inode *ino, u32 *barrier);
 void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
+void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
 int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
 int _pnfs_return_layout(struct inode *);
 int pnfs_ld_write_done(struct nfs_write_data *);
 int pnfs_ld_read_done(struct nfs_read_data *);
+struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino,
+                                              struct nfs_open_context *ctx,
+                                              loff_t pos,
+                                              u64 count,
+                                              enum pnfs_iomode iomode,
+                                              gfp_t gfp_flags);
+
+void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp);
+
+/* nfs4_deviceid_flags */
+enum {
+       NFS_DEVICEID_INVALID = 0,       /* set when MDS clientid recalled */
+};
 
 /* pnfs_dev.c */
 struct nfs4_deviceid_node {
@@ -189,13 +222,13 @@ struct nfs4_deviceid_node {
        struct hlist_node               tmpnode;
        const struct pnfs_layoutdriver_type *ld;
        const struct nfs_client         *nfs_client;
+       unsigned long                   flags;
        struct nfs4_deviceid            deviceid;
        atomic_t                        ref;
 };
 
 void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id);
 struct nfs4_deviceid_node *nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
-struct nfs4_deviceid_node *nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
 void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *);
 void nfs4_init_deviceid_node(struct nfs4_deviceid_node *,
                             const struct pnfs_layoutdriver_type *,
@@ -293,15 +326,6 @@ static inline int pnfs_return_layout(struct inode *ino)
        return 0;
 }
 
-static inline void pnfs_pageio_init(struct nfs_pageio_descriptor *pgio,
-                                   struct inode *inode)
-{
-       struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
-
-       if (ld)
-               pgio->pg_test = ld->pg_test;
-}
-
 #else  /* CONFIG_NFS_V4_1 */
 
 static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
@@ -322,28 +346,6 @@ static inline void put_lseg(struct pnfs_layout_segment *lseg)
 {
 }
 
-static inline struct pnfs_layout_segment *
-pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
-                  loff_t pos, u64 count, enum pnfs_iomode access_type,
-                  gfp_t gfp_flags)
-{
-       return NULL;
-}
-
-static inline enum pnfs_try_status
-pnfs_try_to_read_data(struct nfs_read_data *data,
-                     const struct rpc_call_ops *call_ops)
-{
-       return PNFS_NOT_ATTEMPTED;
-}
-
-static inline enum pnfs_try_status
-pnfs_try_to_write_data(struct nfs_write_data *data,
-                      const struct rpc_call_ops *call_ops, int how)
-{
-       return PNFS_NOT_ATTEMPTED;
-}
-
 static inline int pnfs_return_layout(struct inode *ino)
 {
        return 0;
@@ -377,7 +379,8 @@ pnfs_roc_drain(struct inode *ino, u32 *barrier)
        return false;
 }
 
-static inline void set_pnfs_layoutdriver(struct nfs_server *s, u32 id)
+static inline void set_pnfs_layoutdriver(struct nfs_server *s,
+                                        const struct nfs_fh *mntfh, u32 id)
 {
 }
 
@@ -385,9 +388,14 @@ static inline void unset_pnfs_layoutdriver(struct nfs_server *s)
 {
 }
 
-static inline void pnfs_pageio_init(struct nfs_pageio_descriptor *pgio,
-                                   struct inode *inode)
+static inline bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode)
+{
+       return false;
+}
+
+static inline bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags)
 {
+       return false;
 }
 
 static inline void
index f0f8e1e22f6c945119ff359491dce07b79a0cf69..6fda5228ef5627d45da3cdf4933e6a098b018820 100644 (file)
@@ -100,8 +100,8 @@ _find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
 
        rcu_read_lock();
        d = _lookup_deviceid(ld, clp, id, hash);
-       if (d && !atomic_inc_not_zero(&d->ref))
-               d = NULL;
+       if (d != NULL)
+               atomic_inc(&d->ref);
        rcu_read_unlock();
        return d;
 }
@@ -115,15 +115,15 @@ nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
 EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid);
 
 /*
- * Unhash and put deviceid
+ * Remove a deviceid from cache
  *
  * @clp nfs_client associated with deviceid
  * @id the deviceid to unhash
  *
  * @ret the unhashed node, if found and dereferenced to zero, NULL otherwise.
  */
-struct nfs4_deviceid_node *
-nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *ld,
+void
+nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld,
                         const struct nfs_client *clp, const struct nfs4_deviceid *id)
 {
        struct nfs4_deviceid_node *d;
@@ -134,7 +134,7 @@ nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *ld,
        rcu_read_unlock();
        if (!d) {
                spin_unlock(&nfs4_deviceid_lock);
-               return NULL;
+               return;
        }
        hlist_del_init_rcu(&d->node);
        spin_unlock(&nfs4_deviceid_lock);
@@ -142,28 +142,7 @@ nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *ld,
 
        /* balance the initial ref set in pnfs_insert_deviceid */
        if (atomic_dec_and_test(&d->ref))
-               return d;
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(nfs4_unhash_put_deviceid);
-
-/*
- * Delete a deviceid from cache
- *
- * @clp struct nfs_client qualifying the deviceid
- * @id deviceid to delete
- */
-void
-nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld,
-                    const struct nfs_client *clp, const struct nfs4_deviceid *id)
-{
-       struct nfs4_deviceid_node *d;
-
-       d = nfs4_unhash_put_deviceid(ld, clp, id);
-       if (!d)
-               return;
-       d->ld->free_deviceid_node(d);
+               d->ld->free_deviceid_node(d);
 }
 EXPORT_SYMBOL_GPL(nfs4_delete_deviceid);
 
@@ -177,6 +156,7 @@ nfs4_init_deviceid_node(struct nfs4_deviceid_node *d,
        INIT_HLIST_NODE(&d->tmpnode);
        d->ld = ld;
        d->nfs_client = nfs_client;
+       d->flags = 0;
        d->deviceid = *id;
        atomic_set(&d->ref, 1);
 }
@@ -221,16 +201,15 @@ EXPORT_SYMBOL_GPL(nfs4_insert_deviceid_node);
  *
  * @d deviceid node to put
  *
- * @ret true iff the node was deleted
+ * return true iff the node was deleted
+ * Note that since the test for d->ref == 0 is sufficient to establish
+ * that the node is no longer hashed in the global device id cache.
  */
 bool
 nfs4_put_deviceid_node(struct nfs4_deviceid_node *d)
 {
-       if (!atomic_dec_and_lock(&d->ref, &nfs4_deviceid_lock))
+       if (!atomic_dec_and_test(&d->ref))
                return false;
-       hlist_del_init_rcu(&d->node);
-       spin_unlock(&nfs4_deviceid_lock);
-       synchronize_rcu();
        d->ld->free_deviceid_node(d);
        return true;
 }
@@ -275,3 +254,22 @@ nfs4_deviceid_purge_client(const struct nfs_client *clp)
        for (h = 0; h < NFS4_DEVICE_ID_HASH_SIZE; h++)
                _deviceid_purge_client(clp, h);
 }
+
+/*
+ * Stop use of all deviceids associated with an nfs_client
+ */
+void
+nfs4_deviceid_mark_client_invalid(struct nfs_client *clp)
+{
+       struct nfs4_deviceid_node *d;
+       struct hlist_node *n;
+       int i;
+
+       rcu_read_lock();
+       for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i ++){
+               hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[i], node)
+                       if (d->nfs_client == clp)
+                               set_bit(NFS_DEVICEID_INVALID, &d->flags);
+       }
+       rcu_read_unlock();
+}
index a68679f538fc34fb778c5bee50337ef228083e1b..2171c043ab080a13803b95c59363eab9db1533c5 100644 (file)
@@ -30,8 +30,7 @@
 
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
-static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc);
-static int nfs_pagein_one(struct nfs_pageio_descriptor *desc);
+static const struct nfs_pageio_ops nfs_pageio_read_ops;
 static const struct rpc_call_ops nfs_read_partial_ops;
 static const struct rpc_call_ops nfs_read_full_ops;
 
@@ -68,7 +67,7 @@ void nfs_readdata_free(struct nfs_read_data *p)
        mempool_free(p, nfs_rdata_mempool);
 }
 
-static void nfs_readdata_release(struct nfs_read_data *rdata)
+void nfs_readdata_release(struct nfs_read_data *rdata)
 {
        put_lseg(rdata->lseg);
        put_nfs_open_context(rdata->args.context);
@@ -113,6 +112,27 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
        }
 }
 
+static void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio,
+               struct inode *inode)
+{
+       nfs_pageio_init(pgio, inode, &nfs_pageio_read_ops,
+                       NFS_SERVER(inode)->rsize, 0);
+}
+
+void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio)
+{
+       pgio->pg_ops = &nfs_pageio_read_ops;
+       pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize;
+}
+EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
+
+static void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
+               struct inode *inode)
+{
+       if (!pnfs_pageio_init_read(pgio, inode))
+               nfs_pageio_init_read_mds(pgio, inode);
+}
+
 int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
                       struct page *page)
 {
@@ -131,14 +151,9 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
        if (len < PAGE_CACHE_SIZE)
                zero_user_segment(page, len, PAGE_CACHE_SIZE);
 
-       nfs_pageio_init(&pgio, inode, NULL, 0, 0);
-       nfs_list_add_request(new, &pgio.pg_list);
-       pgio.pg_count = len;
-
-       if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
-               nfs_pagein_multi(&pgio);
-       else
-               nfs_pagein_one(&pgio);
+       nfs_pageio_init_read(&pgio, inode);
+       nfs_pageio_add_request(&pgio, new);
+       nfs_pageio_complete(&pgio);
        return 0;
 }
 
@@ -202,17 +217,14 @@ EXPORT_SYMBOL_GPL(nfs_initiate_read);
 /*
  * Set up the NFS read request struct
  */
-static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
-               const struct rpc_call_ops *call_ops,
-               unsigned int count, unsigned int offset,
-               struct pnfs_layout_segment *lseg)
+static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
+               unsigned int count, unsigned int offset)
 {
        struct inode *inode = req->wb_context->dentry->d_inode;
 
        data->req         = req;
        data->inode       = inode;
        data->cred        = req->wb_context->cred;
-       data->lseg        = get_lseg(lseg);
 
        data->args.fh     = NFS_FH(inode);
        data->args.offset = req_offset(req) + offset;
@@ -226,14 +238,36 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
        data->res.count   = count;
        data->res.eof     = 0;
        nfs_fattr_init(&data->fattr);
+}
 
-       if (data->lseg &&
-           (pnfs_try_to_read_data(data, call_ops) == PNFS_ATTEMPTED))
-               return 0;
+static int nfs_do_read(struct nfs_read_data *data,
+               const struct rpc_call_ops *call_ops)
+{
+       struct inode *inode = data->args.context->dentry->d_inode;
 
        return nfs_initiate_read(data, NFS_CLIENT(inode), call_ops);
 }
 
+static int
+nfs_do_multiple_reads(struct list_head *head,
+               const struct rpc_call_ops *call_ops)
+{
+       struct nfs_read_data *data;
+       int ret = 0;
+
+       while (!list_empty(head)) {
+               int ret2;
+
+               data = list_entry(head->next, struct nfs_read_data, list);
+               list_del_init(&data->list);
+
+               ret2 = nfs_do_read(data, call_ops);
+               if (ret == 0)
+                       ret = ret2;
+       }
+       return ret;
+}
+
 static void
 nfs_async_read_error(struct list_head *head)
 {
@@ -260,20 +294,19 @@ nfs_async_read_error(struct list_head *head)
  * won't see the new data until our attribute cache is updated.  This is more
  * or less conventional NFS client behavior.
  */
-static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc)
+static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head *res)
 {
        struct nfs_page *req = nfs_list_entry(desc->pg_list.next);
        struct page *page = req->wb_page;
        struct nfs_read_data *data;
-       size_t rsize = NFS_SERVER(desc->pg_inode)->rsize, nbytes;
+       size_t rsize = desc->pg_bsize, nbytes;
        unsigned int offset;
        int requests = 0;
        int ret = 0;
-       struct pnfs_layout_segment *lseg;
-       LIST_HEAD(list);
 
        nfs_list_remove_request(req);
 
+       offset = 0;
        nbytes = desc->pg_count;
        do {
                size_t len = min(nbytes,rsize);
@@ -281,45 +314,21 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc)
                data = nfs_readdata_alloc(1);
                if (!data)
                        goto out_bad;
-               list_add(&data->pages, &list);
+               data->pagevec[0] = page;
+               nfs_read_rpcsetup(req, data, len, offset);
+               list_add(&data->list, res);
                requests++;
                nbytes -= len;
+               offset += len;
        } while(nbytes != 0);
        atomic_set(&req->wb_complete, requests);
-
-       BUG_ON(desc->pg_lseg != NULL);
-       lseg = pnfs_update_layout(desc->pg_inode, req->wb_context,
-                                 req_offset(req), desc->pg_count,
-                                 IOMODE_READ, GFP_KERNEL);
        ClearPageError(page);
-       offset = 0;
-       nbytes = desc->pg_count;
-       do {
-               int ret2;
-
-               data = list_entry(list.next, struct nfs_read_data, pages);
-               list_del_init(&data->pages);
-
-               data->pagevec[0] = page;
-
-               if (nbytes < rsize)
-                       rsize = nbytes;
-               ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
-                                        rsize, offset, lseg);
-               if (ret == 0)
-                       ret = ret2;
-               offset += rsize;
-               nbytes -= rsize;
-       } while (nbytes != 0);
-       put_lseg(lseg);
-       desc->pg_lseg = NULL;
-
+       desc->pg_rpc_callops = &nfs_read_partial_ops;
        return ret;
-
 out_bad:
-       while (!list_empty(&list)) {
-               data = list_entry(list.next, struct nfs_read_data, pages);
-               list_del(&data->pages);
+       while (!list_empty(res)) {
+               data = list_entry(res->next, struct nfs_read_data, list);
+               list_del(&data->list);
                nfs_readdata_free(data);
        }
        SetPageError(page);
@@ -327,19 +336,19 @@ out_bad:
        return -ENOMEM;
 }
 
-static int nfs_pagein_one(struct nfs_pageio_descriptor *desc)
+static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, struct list_head *res)
 {
        struct nfs_page         *req;
        struct page             **pages;
        struct nfs_read_data    *data;
        struct list_head *head = &desc->pg_list;
-       struct pnfs_layout_segment *lseg = desc->pg_lseg;
-       int ret = -ENOMEM;
+       int ret = 0;
 
        data = nfs_readdata_alloc(nfs_page_array_len(desc->pg_base,
                                                     desc->pg_count));
        if (!data) {
                nfs_async_read_error(head);
+               ret = -ENOMEM;
                goto out;
        }
 
@@ -352,19 +361,37 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc)
                *pages++ = req->wb_page;
        }
        req = nfs_list_entry(data->pages.next);
-       if ((!lseg) && list_is_singular(&data->pages))
-               lseg = pnfs_update_layout(desc->pg_inode, req->wb_context,
-                                         req_offset(req), desc->pg_count,
-                                         IOMODE_READ, GFP_KERNEL);
 
-       ret = nfs_read_rpcsetup(req, data, &nfs_read_full_ops, desc->pg_count,
-                               0, lseg);
+       nfs_read_rpcsetup(req, data, desc->pg_count, 0);
+       list_add(&data->list, res);
+       desc->pg_rpc_callops = &nfs_read_full_ops;
 out:
-       put_lseg(lseg);
-       desc->pg_lseg = NULL;
        return ret;
 }
 
+int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, struct list_head *head)
+{
+       if (desc->pg_bsize < PAGE_CACHE_SIZE)
+               return nfs_pagein_multi(desc, head);
+       return nfs_pagein_one(desc, head);
+}
+
+static int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
+{
+       LIST_HEAD(head);
+       int ret;
+
+       ret = nfs_generic_pagein(desc, &head);
+       if (ret == 0)
+               ret = nfs_do_multiple_reads(&head, desc->pg_rpc_callops);
+       return ret;
+}
+
+static const struct nfs_pageio_ops nfs_pageio_read_ops = {
+       .pg_test = nfs_generic_pg_test,
+       .pg_doio = nfs_generic_pg_readpages,
+};
+
 /*
  * This is the callback from RPC telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
@@ -635,8 +662,6 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
                .pgio = &pgio,
        };
        struct inode *inode = mapping->host;
-       struct nfs_server *server = NFS_SERVER(inode);
-       size_t rsize = server->rsize;
        unsigned long npages;
        int ret = -ESTALE;
 
@@ -664,10 +689,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
        if (ret == 0)
                goto read_complete; /* all pages were read */
 
-       if (rsize < PAGE_CACHE_SIZE)
-               nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
-       else
-               nfs_pageio_init(&pgio, inode, nfs_pagein_one, rsize, 0);
+       nfs_pageio_init_read(&pgio, inode);
 
        ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
 
index 8d6864c2a5fa07623e484953e709944c3245cbeb..b2fbbde58e442b7ae442f0afad3901fd4d5bde3c 100644 (file)
@@ -147,7 +147,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n
 
        alias = d_lookup(parent, &data->args.name);
        if (alias != NULL) {
-               int ret = 0;
+               int ret;
                void *devname_garbage = NULL;
 
                /*
@@ -155,14 +155,16 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n
                 * the sillyrename information to the aliased dentry.
                 */
                nfs_free_dname(data);
+               ret = nfs_copy_dname(alias, data);
                spin_lock(&alias->d_lock);
-               if (alias->d_inode != NULL &&
+               if (ret == 0 && alias->d_inode != NULL &&
                    !(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
                        devname_garbage = alias->d_fsdata;
                        alias->d_fsdata = data;
                        alias->d_flags |= DCACHE_NFSFS_RENAMED;
                        ret = 1;
-               }
+               } else
+                       ret = 0;
                spin_unlock(&alias->d_lock);
                nfs_dec_sillycount(dir);
                dput(alias);
@@ -171,8 +173,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n
                 * point dentry is definitely not a root, so we won't need
                 * that anymore.
                 */
-               if (devname_garbage)
-                       kfree(devname_garbage);
+               kfree(devname_garbage);
                return ret;
        }
        data->dir = igrab(dir);
@@ -204,8 +205,6 @@ static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
        if (parent == NULL)
                goto out_free;
        dir = parent->d_inode;
-       if (nfs_copy_dname(dentry, data) != 0)
-               goto out_dput;
        /* Non-exclusive lock protects against concurrent lookup() calls */
        spin_lock(&dir->i_lock);
        if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) == 0) {
@@ -366,6 +365,8 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata)
        struct nfs_renamedata *data = calldata;
        struct inode *old_dir = data->old_dir;
        struct inode *new_dir = data->new_dir;
+       struct dentry *old_dentry = data->old_dentry;
+       struct dentry *new_dentry = data->new_dentry;
 
        if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) {
                nfs_restart_rpc(task, NFS_SERVER(old_dir)->nfs_client);
@@ -373,12 +374,12 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata)
        }
 
        if (task->tk_status != 0) {
-               nfs_cancel_async_unlink(data->old_dentry);
+               nfs_cancel_async_unlink(old_dentry);
                return;
        }
 
-       nfs_set_verifier(data->old_dentry, nfs_save_change_attribute(old_dir));
-       d_move(data->old_dentry, data->new_dentry);
+       d_drop(old_dentry);
+       d_drop(new_dentry);
 }
 
 /**
@@ -501,6 +502,14 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
  * and only performs the unlink once the last reference to it is put.
  *
  * The final cleanup is done during dentry_iput.
+ *
+ * (Note: NFSv4 is stateful, and has opens, so in theory an NFSv4 server
+ * could take responsibility for keeping open files referenced.  The server
+ * would also need to ensure that opened-but-deleted files were kept over
+ * reboots.  However, we may not assume a server does so.  (RFC 5661
+ * does provide an OPEN4_RESULT_PRESERVE_UNLINKED flag that a server can
+ * use to advertise that it does this; some day we may take advantage of
+ * it.))
  */
 int
 nfs_sillyrename(struct inode *dir, struct dentry *dentry)
@@ -560,6 +569,14 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
        if (error)
                goto out_dput;
 
+       /* populate unlinkdata with the right dname */
+       error = nfs_copy_dname(sdentry,
+                               (struct nfs_unlinkdata *)dentry->d_fsdata);
+       if (error) {
+               nfs_cancel_async_unlink(dentry);
+               goto out_dput;
+       }
+
        /* run the rename task, undo unlink if it fails */
        task = nfs_async_rename(dir, dir, dentry, sdentry);
        if (IS_ERR(task)) {
index 00e37501fa3bfb3be0ced9abac5372338f1cbf75..b39b37f8091306548dd6516b3865002b1bb72ade 100644 (file)
@@ -97,7 +97,7 @@ void nfs_writedata_free(struct nfs_write_data *p)
        mempool_free(p, nfs_wdata_mempool);
 }
 
-static void nfs_writedata_release(struct nfs_write_data *wdata)
+void nfs_writedata_release(struct nfs_write_data *wdata)
 {
        put_lseg(wdata->lseg);
        put_nfs_open_context(wdata->args.context);
@@ -845,11 +845,9 @@ EXPORT_SYMBOL_GPL(nfs_initiate_write);
 /*
  * Set up the argument/result storage required for the RPC call.
  */
-static int nfs_write_rpcsetup(struct nfs_page *req,
+static void nfs_write_rpcsetup(struct nfs_page *req,
                struct nfs_write_data *data,
-               const struct rpc_call_ops *call_ops,
                unsigned int count, unsigned int offset,
-               struct pnfs_layout_segment *lseg,
                int how)
 {
        struct inode *inode = req->wb_context->dentry->d_inode;
@@ -860,7 +858,6 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
        data->req = req;
        data->inode = inode = req->wb_context->dentry->d_inode;
        data->cred = req->wb_context->cred;
-       data->lseg = get_lseg(lseg);
 
        data->args.fh     = NFS_FH(inode);
        data->args.offset = req_offset(req) + offset;
@@ -872,24 +869,51 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
        data->args.context = get_nfs_open_context(req->wb_context);
        data->args.lock_context = req->wb_lock_context;
        data->args.stable  = NFS_UNSTABLE;
-       if (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) {
-               data->args.stable = NFS_DATA_SYNC;
-               if (!nfs_need_commit(NFS_I(inode)))
-                       data->args.stable = NFS_FILE_SYNC;
+       switch (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) {
+       case 0:
+               break;
+       case FLUSH_COND_STABLE:
+               if (nfs_need_commit(NFS_I(inode)))
+                       break;
+       default:
+               data->args.stable = NFS_FILE_SYNC;
        }
 
        data->res.fattr   = &data->fattr;
        data->res.count   = count;
        data->res.verf    = &data->verf;
        nfs_fattr_init(&data->fattr);
+}
 
-       if (data->lseg &&
-           (pnfs_try_to_write_data(data, call_ops, how) == PNFS_ATTEMPTED))
-               return 0;
+static int nfs_do_write(struct nfs_write_data *data,
+               const struct rpc_call_ops *call_ops,
+               int how)
+{
+       struct inode *inode = data->args.context->dentry->d_inode;
 
        return nfs_initiate_write(data, NFS_CLIENT(inode), call_ops, how);
 }
 
+static int nfs_do_multiple_writes(struct list_head *head,
+               const struct rpc_call_ops *call_ops,
+               int how)
+{
+       struct nfs_write_data *data;
+       int ret = 0;
+
+       while (!list_empty(head)) {
+               int ret2;
+
+               data = list_entry(head->next, struct nfs_write_data, list);
+               list_del_init(&data->list);
+               
+               ret2 = nfs_do_write(data, call_ops, how);
+                if (ret == 0)
+                        ret = ret2;
+       }
+       return ret;
+}
+
 /* If a nfs_flush_* function fails, it should remove reqs from @head and
  * call this on each, which will prepare them to be retried on next
  * writeback using standard nfs.
@@ -907,17 +931,15 @@ static void nfs_redirty_request(struct nfs_page *req)
  * Generate multiple small requests to write out a single
  * contiguous dirty area on one page.
  */
-static int nfs_flush_multi(struct nfs_pageio_descriptor *desc)
+static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head *res)
 {
        struct nfs_page *req = nfs_list_entry(desc->pg_list.next);
        struct page *page = req->wb_page;
        struct nfs_write_data *data;
-       size_t wsize = NFS_SERVER(desc->pg_inode)->wsize, nbytes;
+       size_t wsize = desc->pg_bsize, nbytes;
        unsigned int offset;
        int requests = 0;
        int ret = 0;
-       struct pnfs_layout_segment *lseg;
-       LIST_HEAD(list);
 
        nfs_list_remove_request(req);
 
@@ -927,6 +949,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc)
                desc->pg_ioflags &= ~FLUSH_COND_STABLE;
 
 
+       offset = 0;
        nbytes = desc->pg_count;
        do {
                size_t len = min(nbytes, wsize);
@@ -934,45 +957,21 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc)
                data = nfs_writedata_alloc(1);
                if (!data)
                        goto out_bad;
-               list_add(&data->pages, &list);
+               data->pagevec[0] = page;
+               nfs_write_rpcsetup(req, data, wsize, offset, desc->pg_ioflags);
+               list_add(&data->list, res);
                requests++;
                nbytes -= len;
+               offset += len;
        } while (nbytes != 0);
        atomic_set(&req->wb_complete, requests);
-
-       BUG_ON(desc->pg_lseg);
-       lseg = pnfs_update_layout(desc->pg_inode, req->wb_context,
-                                 req_offset(req), desc->pg_count,
-                                 IOMODE_RW, GFP_NOFS);
-       ClearPageError(page);
-       offset = 0;
-       nbytes = desc->pg_count;
-       do {
-               int ret2;
-
-               data = list_entry(list.next, struct nfs_write_data, pages);
-               list_del_init(&data->pages);
-
-               data->pagevec[0] = page;
-
-               if (nbytes < wsize)
-                       wsize = nbytes;
-               ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
-                                         wsize, offset, lseg, desc->pg_ioflags);
-               if (ret == 0)
-                       ret = ret2;
-               offset += wsize;
-               nbytes -= wsize;
-       } while (nbytes != 0);
-
-       put_lseg(lseg);
-       desc->pg_lseg = NULL;
+       desc->pg_rpc_callops = &nfs_write_partial_ops;
        return ret;
 
 out_bad:
-       while (!list_empty(&list)) {
-               data = list_entry(list.next, struct nfs_write_data, pages);
-               list_del(&data->pages);
+       while (!list_empty(res)) {
+               data = list_entry(res->next, struct nfs_write_data, list);
+               list_del(&data->list);
                nfs_writedata_free(data);
        }
        nfs_redirty_request(req);
@@ -987,14 +986,13 @@ out_bad:
  * This is the case if nfs_updatepage detects a conflicting request
  * that has been written but not committed.
  */
-static int nfs_flush_one(struct nfs_pageio_descriptor *desc)
+static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *res)
 {
        struct nfs_page         *req;
        struct page             **pages;
        struct nfs_write_data   *data;
        struct list_head *head = &desc->pg_list;
-       struct pnfs_layout_segment *lseg = desc->pg_lseg;
-       int ret;
+       int ret = 0;
 
        data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base,
                                                      desc->pg_count));
@@ -1016,32 +1014,62 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc)
                *pages++ = req->wb_page;
        }
        req = nfs_list_entry(data->pages.next);
-       if ((!lseg) && list_is_singular(&data->pages))
-               lseg = pnfs_update_layout(desc->pg_inode, req->wb_context,
-                                         req_offset(req), desc->pg_count,
-                                         IOMODE_RW, GFP_NOFS);
 
        if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
            (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit))
                desc->pg_ioflags &= ~FLUSH_COND_STABLE;
 
        /* Set up the argument struct */
-       ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags);
+       nfs_write_rpcsetup(req, data, desc->pg_count, 0, desc->pg_ioflags);
+       list_add(&data->list, res);
+       desc->pg_rpc_callops = &nfs_write_full_ops;
 out:
-       put_lseg(lseg); /* Cleans any gotten in ->pg_test */
-       desc->pg_lseg = NULL;
        return ret;
 }
 
-static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
+int nfs_generic_flush(struct nfs_pageio_descriptor *desc, struct list_head *head)
+{
+       if (desc->pg_bsize < PAGE_CACHE_SIZE)
+               return nfs_flush_multi(desc, head);
+       return nfs_flush_one(desc, head);
+}
+
+static int nfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
+{
+       LIST_HEAD(head);
+       int ret;
+
+       ret = nfs_generic_flush(desc, &head);
+       if (ret == 0)
+               ret = nfs_do_multiple_writes(&head, desc->pg_rpc_callops,
+                               desc->pg_ioflags);
+       return ret;
+}
+
+static const struct nfs_pageio_ops nfs_pageio_write_ops = {
+       .pg_test = nfs_generic_pg_test,
+       .pg_doio = nfs_generic_pg_writepages,
+};
+
+static void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
                                  struct inode *inode, int ioflags)
 {
-       size_t wsize = NFS_SERVER(inode)->wsize;
+       nfs_pageio_init(pgio, inode, &nfs_pageio_write_ops,
+                               NFS_SERVER(inode)->wsize, ioflags);
+}
+
+void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio)
+{
+       pgio->pg_ops = &nfs_pageio_write_ops;
+       pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->wsize;
+}
+EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds);
 
-       if (wsize < PAGE_CACHE_SIZE)
-               nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags);
-       else
-               nfs_pageio_init(pgio, inode, nfs_flush_one, wsize, ioflags);
+static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
+                                 struct inode *inode, int ioflags)
+{
+       if (!pnfs_pageio_init_write(pgio, inode, ioflags))
+               nfs_pageio_init_write_mds(pgio, inode, ioflags);
 }
 
 /*
index f1637f17c37c8b39c353c455c040d63d6e3637ed..9d99131d0d65455e522f2f42fb3a6f8ef3dc2c28 100644 (file)
@@ -620,8 +620,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
        if (!ent) goto out;
 
        memset(ent, 0, sizeof(struct proc_dir_entry));
-       memcpy(((char *) ent) + sizeof(struct proc_dir_entry), fn, len + 1);
-       ent->name = ((char *) ent) + sizeof(*ent);
+       memcpy(ent->name, fn, len + 1);
        ent->namelen = len;
        ent->mode = mode;
        ent->nlink = nlink;
index 9020ac15baaaf4d3791fb190a50654e557851e95..f738024ccc8e5de951c58fb3822eb6383b91c7d2 100644 (file)
@@ -197,15 +197,15 @@ static __net_init int proc_net_ns_init(struct net *net)
        int err;
 
        err = -ENOMEM;
-       netd = kzalloc(sizeof(*netd), GFP_KERNEL);
+       netd = kzalloc(sizeof(*netd) + 4, GFP_KERNEL);
        if (!netd)
                goto out;
 
        netd->data = net;
        netd->nlink = 2;
-       netd->name = "net";
        netd->namelen = 3;
        netd->parent = &proc_root;
+       memcpy(netd->name, "net", 4);
 
        err = -EEXIST;
        net_statd = proc_net_mkdir(net, "stat", netd);
index d6c3b416529b9709f2db526be706dbb415902ea3..9a8a2b77b87479621838ee00c928a43edbe938e9 100644 (file)
@@ -186,13 +186,13 @@ static const struct inode_operations proc_root_inode_operations = {
 struct proc_dir_entry proc_root = {
        .low_ino        = PROC_ROOT_INO, 
        .namelen        = 5, 
-       .name           = "/proc",
        .mode           = S_IFDIR | S_IRUGO | S_IXUGO, 
        .nlink          = 2, 
        .count          = ATOMIC_INIT(1),
        .proc_iops      = &proc_root_inode_operations, 
        .proc_fops      = &proc_root_operations,
        .parent         = &proc_root,
+       .name           = "/proc",
 };
 
 int pid_ns_prepare_proc(struct pid_namespace *ns)
index b2b411985591a7f8a18cfd0b1ccb7d1a14b737d5..d1fe74506c4c621aa8399b758126d2f8f0875c23 100644 (file)
@@ -1224,6 +1224,9 @@ _xfs_buf_ioapply(
                rw = READ;
        }
 
+       /* we only use the buffer cache for meta-data */
+       rw |= REQ_META;
+
 next_chunk:
        atomic_inc(&bp->b_io_remaining);
        nr_pages = BIO_MAX_SECTORS >> (PAGE_SHIFT - BBSHIFT);
index 825390e1c13850985c634fcbaec19c88ce2d6e46..7f7b42469ea7c9653903d0ffbe00769d40a168eb 100644 (file)
@@ -149,7 +149,9 @@ xfs_file_fsync(
 
        xfs_iflags_clear(ip, XFS_ITRUNCATED);
 
+       xfs_ilock(ip, XFS_IOLOCK_SHARED);
        xfs_ioend_wait(ip);
+       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
 
        if (mp->m_flags & XFS_MOUNT_BARRIER) {
                /*
index 6544c3236bc8dd51bff1c8d9935d1f979830553c..b9c172b3fbbec1c6b8ac2874151f0bb1aa19240d 100644 (file)
@@ -1194,9 +1194,14 @@ xfs_setup_inode(
                break;
        }
 
-       /* if there is no attribute fork no ACL can exist on this inode */
-       if (!XFS_IFORK_Q(ip))
+       /*
+        * If there is no attribute fork no ACL can exist on this inode,
+        * and it can't have any file capabilities attached to it either.
+        */
+       if (!XFS_IFORK_Q(ip)) {
+               inode_has_no_xattr(inode);
                cache_no_acl(inode);
+       }
 
        xfs_iflags_clear(ip, XFS_INEW);
        barrier();
index 2c656ef49473b0f429d15861dfde1e1c6eb0b292..39632d94135490ac94dee48ff5f037d29d5592ac 100644 (file)
@@ -51,7 +51,10 @@ extern int posix_acl_default_exists(struct inode *inode);
 extern const struct xattr_handler xfs_xattr_acl_access_handler;
 extern const struct xattr_handler xfs_xattr_acl_default_handler;
 #else
-# define xfs_get_acl(inode, type)                      NULL
+static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
+{
+       return NULL;
+}
 # define xfs_inherit_acl(inode, default_acl)           0
 # define xfs_acl_chmod(inode)                          0
 # define posix_acl_access_exists(inode)                        0
index 2925726529f8029fcd4ba3ecaf4b22efec285f0c..5bfcb8779f9f63c93907aa45aa1a83bcfbf186a4 100644 (file)
@@ -692,6 +692,24 @@ xfs_da_join(xfs_da_state_t *state)
        return(error);
 }
 
+#ifdef DEBUG
+static void
+xfs_da_blkinfo_onlychild_validate(struct xfs_da_blkinfo *blkinfo, __u16 level)
+{
+       __be16  magic = blkinfo->magic;
+
+       if (level == 1) {
+               ASSERT(magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
+                      magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
+       } else
+               ASSERT(magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
+       ASSERT(!blkinfo->forw);
+       ASSERT(!blkinfo->back);
+}
+#else  /* !DEBUG */
+#define        xfs_da_blkinfo_onlychild_validate(blkinfo, level)
+#endif /* !DEBUG */
+
 /*
  * We have only one entry in the root.  Copy the only remaining child of
  * the old root to block 0 as the new root node.
@@ -700,8 +718,6 @@ STATIC int
 xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk)
 {
        xfs_da_intnode_t *oldroot;
-       /* REFERENCED */
-       xfs_da_blkinfo_t *blkinfo;
        xfs_da_args_t *args;
        xfs_dablk_t child;
        xfs_dabuf_t *bp;
@@ -732,15 +748,9 @@ xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk)
        if (error)
                return(error);
        ASSERT(bp != NULL);
-       blkinfo = bp->data;
-       if (be16_to_cpu(oldroot->hdr.level) == 1) {
-               ASSERT(blkinfo->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
-                      blkinfo->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
-       } else {
-               ASSERT(blkinfo->magic == cpu_to_be16(XFS_DA_NODE_MAGIC));
-       }
-       ASSERT(!blkinfo->forw);
-       ASSERT(!blkinfo->back);
+       xfs_da_blkinfo_onlychild_validate(bp->data,
+                                       be16_to_cpu(oldroot->hdr.level));
+
        memcpy(root_blk->bp->data, bp->data, state->blocksize);
        xfs_da_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1);
        error = xfs_da_shrink_inode(args, child, bp);
index 95855017a32b23a972a4504fcf51f75116cb3473..1d4541370a648d06f2336858d55dabb61531cef1 100644 (file)
@@ -1,6 +1,11 @@
 /*
  * Copyright (C) 2010 IBM Corporation
- * Author: Mimi Zohar <zohar@us.ibm.com>
+ * Copyright (C) 2010 Politecnico di Torino, Italy
+ *                    TORSEC group -- http://security.polito.it
+ *
+ * Authors:
+ * Mimi Zohar <zohar@us.ibm.com>
+ * Roberto Sassu <roberto.sassu@polito.it>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 struct encrypted_key_payload {
        struct rcu_head rcu;
+       char *format;           /* datablob: format */
        char *master_desc;      /* datablob: master key name */
        char *datalen;          /* datablob: decrypted key length */
        u8 *iv;                 /* datablob: iv */
        u8 *encrypted_data;     /* datablob: encrypted data */
        unsigned short datablob_len;    /* length of datablob */
        unsigned short decrypted_datalen;       /* decrypted data length */
-       u8 decrypted_data[0];   /* decrypted data +  datablob + hmac */
+       unsigned short payload_datalen;         /* payload data length */
+       unsigned short encrypted_key_format;    /* encrypted key format */
+       u8 *decrypted_data;     /* decrypted data */
+       u8 payload_data[0];     /* payload data + datablob + hmac */
 };
 
 extern struct key_type key_type_encrypted;
index 8414de22a779dc5561a2729d2605368a5344a487..544abdb2238ccdffda329816578b41bb954fc617 100644 (file)
@@ -51,5 +51,8 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
 
 extern void cper_print_aer(const char *prefix, int cper_severity,
                           struct aer_capability_regs *aer);
+extern int cper_severity_to_aer(int cper_severity);
+extern void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
+                             int severity);
 #endif //_AER_H_
 
index fec66bd24f22d26429dda8c03a025d37c6508d4d..d47bccd604e446bca90d171fd0562844fb46bdd8 100644 (file)
@@ -67,7 +67,7 @@ typedef struct audio_status {
 
 
 typedef
-struct audio_karaoke{  /* if Vocal1 or Vocal2 are non-zero, they get mixed  */
+struct audio_karaoke {  /* if Vocal1 or Vocal2 are non-zero, they get mixed  */
        int vocal1;    /* into left and right t at 70% each */
        int vocal2;    /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets*/
        int melody;    /* mixed into the left channel and */
diff --git a/include/linux/ecryptfs.h b/include/linux/ecryptfs.h
new file mode 100644 (file)
index 0000000..2224a8c
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef _LINUX_ECRYPTFS_H
+#define _LINUX_ECRYPTFS_H
+
+/* Version verification for shared data structures w/ userspace */
+#define ECRYPTFS_VERSION_MAJOR 0x00
+#define ECRYPTFS_VERSION_MINOR 0x04
+#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x03
+/* These flags indicate which features are supported by the kernel
+ * module; userspace tools such as the mount helper read
+ * ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine
+ * how to behave. */
+#define ECRYPTFS_VERSIONING_PASSPHRASE            0x00000001
+#define ECRYPTFS_VERSIONING_PUBKEY                0x00000002
+#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004
+#define ECRYPTFS_VERSIONING_POLICY                0x00000008
+#define ECRYPTFS_VERSIONING_XATTR                 0x00000010
+#define ECRYPTFS_VERSIONING_MULTKEY               0x00000020
+#define ECRYPTFS_VERSIONING_DEVMISC               0x00000040
+#define ECRYPTFS_VERSIONING_HMAC                  0x00000080
+#define ECRYPTFS_VERSIONING_FILENAME_ENCRYPTION   0x00000100
+#define ECRYPTFS_VERSIONING_GCM                   0x00000200
+#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
+                                 | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \
+                                 | ECRYPTFS_VERSIONING_PUBKEY \
+                                 | ECRYPTFS_VERSIONING_XATTR \
+                                 | ECRYPTFS_VERSIONING_MULTKEY \
+                                 | ECRYPTFS_VERSIONING_DEVMISC \
+                                 | ECRYPTFS_VERSIONING_FILENAME_ENCRYPTION)
+#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
+#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
+#define ECRYPTFS_SALT_SIZE 8
+#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2)
+/* The original signature size is only for what is stored on disk; all
+ * in-memory representations are expanded hex, so it better adapted to
+ * be passed around or referenced on the command line */
+#define ECRYPTFS_SIG_SIZE 8
+#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
+#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
+#define ECRYPTFS_MAX_KEY_BYTES 64
+#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
+#define ECRYPTFS_FILE_VERSION 0x03
+#define ECRYPTFS_MAX_PKI_NAME_BYTES 16
+
+#define RFC2440_CIPHER_DES3_EDE 0x02
+#define RFC2440_CIPHER_CAST_5 0x03
+#define RFC2440_CIPHER_BLOWFISH 0x04
+#define RFC2440_CIPHER_AES_128 0x07
+#define RFC2440_CIPHER_AES_192 0x08
+#define RFC2440_CIPHER_AES_256 0x09
+#define RFC2440_CIPHER_TWOFISH 0x0a
+#define RFC2440_CIPHER_CAST_6 0x0b
+
+#define RFC2440_CIPHER_RSA 0x01
+
+/**
+ * For convenience, we may need to pass around the encrypted session
+ * key between kernel and userspace because the authentication token
+ * may not be extractable.  For example, the TPM may not release the
+ * private key, instead requiring the encrypted data and returning the
+ * decrypted data.
+ */
+struct ecryptfs_session_key {
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002
+#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004
+#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008
+       u32 flags;
+       u32 encrypted_key_size;
+       u32 decrypted_key_size;
+       u8 encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+       u8 decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
+};
+
+struct ecryptfs_password {
+       u32 password_bytes;
+       s32 hash_algo;
+       u32 hash_iterations;
+       u32 session_key_encryption_key_bytes;
+#define ECRYPTFS_PERSISTENT_PASSWORD 0x01
+#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02
+       u32 flags;
+       /* Iterated-hash concatenation of salt and passphrase */
+       u8 session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+       u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
+       /* Always in expanded hex */
+       u8 salt[ECRYPTFS_SALT_SIZE];
+};
+
+enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};
+
+struct ecryptfs_private_key {
+       u32 key_size;
+       u32 data_len;
+       u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
+       char pki_type[ECRYPTFS_MAX_PKI_NAME_BYTES + 1];
+       u8 data[];
+};
+
+/* May be a password or a private key */
+struct ecryptfs_auth_tok {
+       u16 version; /* 8-bit major and 8-bit minor */
+       u16 token_type;
+#define ECRYPTFS_ENCRYPT_ONLY 0x00000001
+       u32 flags;
+       struct ecryptfs_session_key session_key;
+       u8 reserved[32];
+       union {
+               struct ecryptfs_password password;
+               struct ecryptfs_private_key private_key;
+       } token;
+} __attribute__ ((packed));
+
+#endif /* _LINUX_ECRYPTFS_H */
index 3bc63e6a02f7390909cd128fbd1fceb4c41c7df7..03489ca92ded4e1f901af97a76e0ca042297cdd0 100644 (file)
@@ -76,6 +76,8 @@
 #define IFF_BRIDGE_PORT        0x4000          /* device used as bridge port */
 #define IFF_OVS_DATAPATH       0x8000  /* device used as Open vSwitch
                                         * datapath port */
+#define IFF_TX_SKB_SHARING     0x10000 /* The interface supports sharing
+                                        * skbs on transmit */
 
 #define IF_GET_IFACE   0x0001          /* for querying only */
 #define IF_GET_PROTO   0x0002
index 771d6d85667d68a17c24c452979f8d37cc628082..068784e17972a1ffd907f4365bd5f774e70bcfdf 100644 (file)
@@ -119,9 +119,9 @@ struct input_keymap_entry {
 #define EVIOCGSND(len)         _IOC(_IOC_READ, 'E', 0x1a, len)         /* get all sounds status */
 #define EVIOCGSW(len)          _IOC(_IOC_READ, 'E', 0x1b, len)         /* get all switch states */
 
-#define EVIOCGBIT(ev,len)      _IOC(_IOC_READ, 'E', 0x20 + ev, len)    /* get event bits */
-#define EVIOCGABS(abs)         _IOR('E', 0x40 + abs, struct input_absinfo)     /* get abs value/limits */
-#define EVIOCSABS(abs)         _IOW('E', 0xc0 + abs, struct input_absinfo)     /* set abs value/limits */
+#define EVIOCGBIT(ev,len)      _IOC(_IOC_READ, 'E', 0x20 + (ev), len)  /* get event bits */
+#define EVIOCGABS(abs)         _IOR('E', 0x40 + (abs), struct input_absinfo)   /* get abs value/limits */
+#define EVIOCSABS(abs)         _IOW('E', 0xc0 + (abs), struct input_absinfo)   /* set abs value/limits */
 
 #define EVIOCSFF               _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))   /* send a force effect to a force feedback device */
 #define EVIOCRMFF              _IOW('E', 0x81, int)                    /* Erase a force effect */
diff --git a/include/linux/input/kxtj9.h b/include/linux/input/kxtj9.h
new file mode 100644 (file)
index 0000000..f6bac89
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 Kionix, Inc.
+ * Written by Chris Hudson <chudson@kionix.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
+ */
+
+#ifndef __KXTJ9_H__
+#define __KXTJ9_H__
+
+#define KXTJ9_I2C_ADDR         0x0F
+
+struct kxtj9_platform_data {
+       unsigned int min_interval;      /* minimum poll interval (in milli-seconds) */
+
+       /*
+        * By default, x is axis 0, y is axis 1, z is axis 2; these can be
+        * changed to account for sensor orientation within the host device.
+        */
+       u8 axis_map_x;
+       u8 axis_map_y;
+       u8 axis_map_z;
+
+       /*
+        * Each axis can be negated to account for sensor orientation within
+        * the host device.
+        */
+       bool negate_x;
+       bool negate_y;
+       bool negate_z;
+
+       /* CTRL_REG1: set resolution, g-range, data ready enable */
+       /* Output resolution: 8-bit valid or 12-bit valid */
+       #define RES_8BIT                0
+       #define RES_12BIT               (1 << 6)
+       u8 res_12bit;
+       /* Output g-range: +/-2g, 4g, or 8g */
+       #define KXTJ9_G_2G              0
+       #define KXTJ9_G_4G              (1 << 3)
+       #define KXTJ9_G_8G              (1 << 4)
+       u8 g_range;
+
+       /* DATA_CTRL_REG: controls the output data rate of the part */
+       #define ODR12_5F                0
+       #define ODR25F                  1
+       #define ODR50F                  2
+       #define ODR100F                 3
+       #define ODR200F                 4
+       #define ODR400F                 5
+       #define ODR800F                 6
+       u8 data_odr_init;
+
+       int (*init)(void);
+       void (*exit)(void);
+       int (*power_on)(void);
+       int (*power_off)(void);
+};
+#endif  /* __KXTJ9_H__ */
index c2ebfe66177c18ec978b896a9d99f8d11f8f2e5f..9d57a71775b5714b5d67df7857142eaa6f349ebe 100644 (file)
@@ -162,6 +162,7 @@ extern int allocate_resource(struct resource *root, struct resource *new,
                                                       resource_size_t,
                                                       resource_size_t),
                             void *alignf_data);
+struct resource *lookup_resource(struct resource *root, resource_size_t start);
 int adjust_resource(struct resource *res, resource_size_t start,
                    resource_size_t size);
 resource_size_t resource_alignment(struct resource *res);
index 5f695041090cc327ff41b72a625b6025a438226b..87a06f345bd2c5820e61ec5a5f9e4d5a77e55d77 100644 (file)
@@ -108,14 +108,18 @@ enum {
 };
 
 struct msi_desc;
+struct irq_domain;
 
 /**
  * struct irq_data - per irq and irq chip data passed down to chip functions
  * @irq:               interrupt number
+ * @hwirq:             hardware interrupt number, local to the interrupt domain
  * @node:              node index useful for balancing
  * @state_use_accessors: status information for irq chip functions.
  *                     Use accessor functions to deal with it
  * @chip:              low level interrupt hardware access
+ * @domain:            Interrupt translation domain; responsible for mapping
+ *                     between hwirq number and linux irq number.
  * @handler_data:      per-IRQ data for the irq_chip methods
  * @chip_data:         platform-specific per-chip private data for the chip
  *                     methods, to allow shared chip implementations
@@ -128,9 +132,11 @@ struct msi_desc;
  */
 struct irq_data {
        unsigned int            irq;
+       unsigned long           hwirq;
        unsigned int            node;
        unsigned int            state_use_accessors;
        struct irq_chip         *chip;
+       struct irq_domain       *domain;
        void                    *handler_data;
        void                    *chip_data;
        struct msi_desc         *msi_desc;
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
new file mode 100644 (file)
index 0000000..e807ad6
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * irq_domain - IRQ translation domains
+ *
+ * Translation infrastructure between hw and linux irq numbers.  This is
+ * helpful for interrupt controllers to implement mapping between hardware
+ * irq numbers and the Linux irq number space.
+ *
+ * irq_domains also have a hook for translating device tree interrupt
+ * representation into a hardware irq number that can be mapped back to a
+ * Linux irq number without any extra platform support code.
+ *
+ * irq_domain is expected to be embedded in an interrupt controller's private
+ * data structure.
+ */
+#ifndef _LINUX_IRQDOMAIN_H
+#define _LINUX_IRQDOMAIN_H
+
+#include <linux/irq.h>
+#include <linux/mod_devicetable.h>
+
+#ifdef CONFIG_IRQ_DOMAIN
+struct device_node;
+struct irq_domain;
+
+/**
+ * struct irq_domain_ops - Methods for irq_domain objects
+ * @to_irq: (optional) given a local hardware irq number, return the linux
+ *          irq number.  If to_irq is not implemented, then the irq_domain
+ *          will use this translation: irq = (domain->irq_base + hwirq)
+ * @dt_translate: Given a device tree node and interrupt specifier, decode
+ *                the hardware irq number and linux irq type value.
+ */
+struct irq_domain_ops {
+       unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq);
+
+#ifdef CONFIG_OF
+       int (*dt_translate)(struct irq_domain *d, struct device_node *node,
+                           const u32 *intspec, unsigned int intsize,
+                           unsigned long *out_hwirq, unsigned int *out_type);
+#endif /* CONFIG_OF */
+};
+
+/**
+ * struct irq_domain - Hardware interrupt number translation object
+ * @list: Element in global irq_domain list.
+ * @irq_base: Start of irq_desc range assigned to the irq_domain.  The creator
+ *            of the irq_domain is responsible for allocating the array of
+ *            irq_desc structures.
+ * @nr_irq: Number of irqs managed by the irq domain
+ * @ops: pointer to irq_domain methods
+ * @priv: private data pointer for use by owner.  Not touched by irq_domain
+ *        core code.
+ * @of_node: (optional) Pointer to device tree nodes associated with the
+ *           irq_domain.  Used when decoding device tree interrupt specifiers.
+ */
+struct irq_domain {
+       struct list_head list;
+       unsigned int irq_base;
+       unsigned int nr_irq;
+       const struct irq_domain_ops *ops;
+       void *priv;
+       struct device_node *of_node;
+};
+
+/**
+ * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number
+ *
+ * Returns the linux irq number associated with a hardware irq.  By default,
+ * the mapping is irq == domain->irq_base + hwirq, but this mapping can
+ * be overridden if the irq_domain implements a .to_irq() hook.
+ */
+static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
+                                            unsigned long hwirq)
+{
+       return d->ops->to_irq ? d->ops->to_irq(d, hwirq) : d->irq_base + hwirq;
+}
+
+extern void irq_domain_add(struct irq_domain *domain);
+extern void irq_domain_del(struct irq_domain *domain);
+#endif /* CONFIG_IRQ_DOMAIN */
+
+#if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
+extern void irq_domain_add_simple(struct device_node *controller, int irq_base);
+extern void irq_domain_generate_simple(const struct of_device_id *match,
+                                       u64 phys_base, unsigned int irq_start);
+#else /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
+static inline void irq_domain_generate_simple(const struct of_device_id *match,
+                                       u64 phys_base, unsigned int irq_start) { }
+#endif /* CONFIG_IRQ_DOMAIN && CONFIG_OF_IRQ */
+
+#endif /* _LINUX_IRQDOMAIN_H */
diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h
new file mode 100644 (file)
index 0000000..067eda0
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __LINUX_KCONFIG_H
+#define __LINUX_KCONFIG_H
+
+#include <generated/autoconf.h>
+
+/*
+ * Helper macros to use CONFIG_ options in C expressions. Note that
+ * these only work with boolean and tristate options.
+ */
+
+/*
+ * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
+ * 0 otherwise.
+ *
+ */
+#define IS_ENABLED(option) \
+       (__enabled_ ## option || __enabled_ ## option ## _MODULE)
+
+/*
+ * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
+ * otherwise. For boolean options, this is equivalent to
+ * IS_ENABLED(CONFIG_FOO).
+ */
+#define IS_BUILTIN(option) __enabled_ ## option
+
+/*
+ * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0
+ * otherwise.
+ */
+#define IS_MODULE(option) __enabled_ ## option ## _MODULE
+
+#endif /* __LINUX_KCONFIG_H */
index 9a43ad792cfc95bd452b4bebc828737d7ff864eb..46ac9a50528d5b6ca03e30d1fd55a01a486fcbea 100644 (file)
 
 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define DIV_ROUND_UP_ULL(ll,d) \
+       ({ unsigned long long _tmp = (ll)+(d)-1; do_div(_tmp, d); _tmp; })
+
+#if BITS_PER_LONG == 32
+# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP_ULL(ll, d)
+#else
+# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP(ll,d)
+#endif
 
 /* The `const' in roundup() prevents gcc-3.3 from calling __divdi3 */
 #define roundup(x, y) (                                        \
diff --git a/include/linux/mfd/aat2870.h b/include/linux/mfd/aat2870.h
new file mode 100644 (file)
index 0000000..89212df
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * linux/include/linux/mfd/aat2870.h
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ * Author: Jin Park <jinyoungp@nvidia.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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __LINUX_MFD_AAT2870_H
+#define __LINUX_MFD_AAT2870_H
+
+#include <linux/debugfs.h>
+#include <linux/i2c.h>
+
+/* Register offsets */
+#define AAT2870_BL_CH_EN       0x00
+#define AAT2870_BLM            0x01
+#define AAT2870_BLS            0x02
+#define AAT2870_BL1            0x03
+#define AAT2870_BL2            0x04
+#define AAT2870_BL3            0x05
+#define AAT2870_BL4            0x06
+#define AAT2870_BL5            0x07
+#define AAT2870_BL6            0x08
+#define AAT2870_BL7            0x09
+#define AAT2870_BL8            0x0A
+#define AAT2870_FLR            0x0B
+#define AAT2870_FM             0x0C
+#define AAT2870_FS             0x0D
+#define AAT2870_ALS_CFG0       0x0E
+#define AAT2870_ALS_CFG1       0x0F
+#define AAT2870_ALS_CFG2       0x10
+#define AAT2870_AMB            0x11
+#define AAT2870_ALS0           0x12
+#define AAT2870_ALS1           0x13
+#define AAT2870_ALS2           0x14
+#define AAT2870_ALS3           0x15
+#define AAT2870_ALS4           0x16
+#define AAT2870_ALS5           0x17
+#define AAT2870_ALS6           0x18
+#define AAT2870_ALS7           0x19
+#define AAT2870_ALS8           0x1A
+#define AAT2870_ALS9           0x1B
+#define AAT2870_ALSA           0x1C
+#define AAT2870_ALSB           0x1D
+#define AAT2870_ALSC           0x1E
+#define AAT2870_ALSD           0x1F
+#define AAT2870_ALSE           0x20
+#define AAT2870_ALSF           0x21
+#define AAT2870_SUB_SET                0x22
+#define AAT2870_SUB_CTRL       0x23
+#define AAT2870_LDO_AB         0x24
+#define AAT2870_LDO_CD         0x25
+#define AAT2870_LDO_EN         0x26
+#define AAT2870_REG_NUM                0x27
+
+/* Device IDs */
+enum aat2870_id {
+       AAT2870_ID_BL,
+       AAT2870_ID_LDOA,
+       AAT2870_ID_LDOB,
+       AAT2870_ID_LDOC,
+       AAT2870_ID_LDOD
+};
+
+/* Backlight channels */
+#define AAT2870_BL_CH1         0x01
+#define AAT2870_BL_CH2         0x02
+#define AAT2870_BL_CH3         0x04
+#define AAT2870_BL_CH4         0x08
+#define AAT2870_BL_CH5         0x10
+#define AAT2870_BL_CH6         0x20
+#define AAT2870_BL_CH7         0x40
+#define AAT2870_BL_CH8         0x80
+#define AAT2870_BL_CH_ALL      0xFF
+
+/* Backlight current magnitude (mA) */
+enum aat2870_current {
+       AAT2870_CURRENT_0_45,
+       AAT2870_CURRENT_0_90,
+       AAT2870_CURRENT_1_80,
+       AAT2870_CURRENT_2_70,
+       AAT2870_CURRENT_3_60,
+       AAT2870_CURRENT_4_50,
+       AAT2870_CURRENT_5_40,
+       AAT2870_CURRENT_6_30,
+       AAT2870_CURRENT_7_20,
+       AAT2870_CURRENT_8_10,
+       AAT2870_CURRENT_9_00,
+       AAT2870_CURRENT_9_90,
+       AAT2870_CURRENT_10_8,
+       AAT2870_CURRENT_11_7,
+       AAT2870_CURRENT_12_6,
+       AAT2870_CURRENT_13_5,
+       AAT2870_CURRENT_14_4,
+       AAT2870_CURRENT_15_3,
+       AAT2870_CURRENT_16_2,
+       AAT2870_CURRENT_17_1,
+       AAT2870_CURRENT_18_0,
+       AAT2870_CURRENT_18_9,
+       AAT2870_CURRENT_19_8,
+       AAT2870_CURRENT_20_7,
+       AAT2870_CURRENT_21_6,
+       AAT2870_CURRENT_22_5,
+       AAT2870_CURRENT_23_4,
+       AAT2870_CURRENT_24_3,
+       AAT2870_CURRENT_25_2,
+       AAT2870_CURRENT_26_1,
+       AAT2870_CURRENT_27_0,
+       AAT2870_CURRENT_27_9
+};
+
+struct aat2870_register {
+       bool readable;
+       bool writeable;
+       u8 value;
+};
+
+struct aat2870_data {
+       struct device *dev;
+       struct i2c_client *client;
+
+       struct mutex io_lock;
+       struct aat2870_register *reg_cache; /* register cache */
+       int en_pin; /* enable GPIO pin (if < 0, ignore this value) */
+       bool is_enable;
+
+       /* init and uninit for platform specified */
+       int (*init)(struct aat2870_data *aat2870);
+       void (*uninit)(struct aat2870_data *aat2870);
+
+       /* i2c io funcntions */
+       int (*read)(struct aat2870_data *aat2870, u8 addr, u8 *val);
+       int (*write)(struct aat2870_data *aat2870, u8 addr, u8 val);
+       int (*update)(struct aat2870_data *aat2870, u8 addr, u8 mask, u8 val);
+
+       /* for debugfs */
+       struct dentry *dentry_root;
+       struct dentry *dentry_reg;
+};
+
+struct aat2870_subdev_info {
+       int id;
+       const char *name;
+       void *platform_data;
+};
+
+struct aat2870_platform_data {
+       int en_pin; /* enable GPIO pin (if < 0, ignore this value) */
+
+       struct aat2870_subdev_info *subdevs;
+       int num_subdevs;
+
+       /* init and uninit for platform specified */
+       int (*init)(struct aat2870_data *aat2870);
+       void (*uninit)(struct aat2870_data *aat2870);
+};
+
+struct aat2870_bl_platform_data {
+       /* backlight channels, default is AAT2870_BL_CH_ALL */
+       int channels;
+       /* backlight current magnitude, default is AAT2870_CURRENT_27_9 */
+       int max_current;
+       /* maximum brightness, default is 255 */
+       int max_brightness;
+};
+
+#endif /* __LINUX_MFD_AAT2870_H */
index b318430751983cf284069b99e6f2f4fa387deb94..838c6b487cc533193f60b7372f85a5080c89c7a5 100644 (file)
@@ -28,6 +28,7 @@
 #define AB8500_INTERRUPT       0xE
 #define AB8500_RTC             0xF
 #define AB8500_MISC            0x10
+#define AB8500_DEVELOPMENT     0x11
 #define AB8500_DEBUG           0x12
 #define AB8500_PROD_TEST       0x13
 #define AB8500_OTP_EMUL                0x15
 #define AB8500_INT_ACC_DETECT_21DB_F   37
 #define AB8500_INT_ACC_DETECT_21DB_R   38
 #define AB8500_INT_GP_SW_ADC_CONV_END  39
-#define AB8500_INT_ACC_DETECT_1DB_F    33
-#define AB8500_INT_ACC_DETECT_1DB_R    34
-#define AB8500_INT_ACC_DETECT_22DB_F   35
-#define AB8500_INT_ACC_DETECT_22DB_R   36
-#define AB8500_INT_ACC_DETECT_21DB_F   37
-#define AB8500_INT_ACC_DETECT_21DB_R   38
-#define AB8500_INT_GP_SW_ADC_CONV_END  39
 #define AB8500_INT_GPIO6R              40
 #define AB8500_INT_GPIO7R              41
 #define AB8500_INT_GPIO8R              42
index 60931d089422c1add45e93a8a813ebeb69d9835c..0bbd13dbe336bdbbcbb86b2caf9453feac4009fd 100644 (file)
@@ -107,11 +107,16 @@ struct max8997_platform_data {
        unsigned int buck5_voltage[8];
        bool buck5_gpiodvs;
 
+       /* ---- Charger control ---- */
+       /* eoc stands for 'end of charge' */
+       int eoc_mA; /* 50 ~ 200mA by 10mA step */
+       /* charge Full Timeout */
+       int timeout; /* 0 (no timeout), 5, 6, 7 hours */
+
        /* MUIC: Not implemented */
        /* HAPTIC: Not implemented */
        /* RTC: Not implemented */
        /* Flash: Not implemented */
-       /* Charger control: Not implemented */
 };
 
 #endif /* __LINUX_MFD_MAX8998_H */
index 61daa167b576908aa376c9a7eb2015e7634678a3..f4f0dfa4698a988ce1112e08ec9350363dccdf49 100644 (file)
@@ -87,6 +87,15 @@ struct max8998_regulator_data {
  * @wakeup: Allow to wake up from suspend
  * @rtc_delay: LP3974 RTC chip bug that requires delay after a register
  * write before reading it.
+ * @eoc: End of Charge Level in percent: 10% ~ 45% by 5% step
+ *   If it equals 0, leave it unchanged.
+ *   Otherwise, it is a invalid value.
+ * @restart: Restart Level in mV: 100, 150, 200, and -1 for disable.
+ *   If it equals 0, leave it unchanged.
+ *   Otherwise, it is a invalid value.
+ * @timeout: Full Timeout in hours: 5, 6, 7, and -1 for disable.
+ *   If it equals 0, leave it unchanged.
+ *   Otherwise, leave it unchanged.
  */
 struct max8998_platform_data {
        struct max8998_regulator_data   *regulators;
@@ -107,6 +116,9 @@ struct max8998_platform_data {
        int                             buck2_default_idx;
        bool                            wakeup;
        bool                            rtc_delay;
+       int                             eoc;
+       int                             restart;
+       int                             timeout;
 };
 
 #endif /*  __LINUX_MFD_MAX8998_H */
index e762c270d8d45aece64e91fc46f0ec16ec773968..be1af7c42e576ecd9881276401df8ee5a49d694f 100644 (file)
@@ -57,6 +57,7 @@ struct stmpe_variant_info;
  * @irq_lock: IRQ bus lock
  * @dev: device, mostly for dev_dbg()
  * @i2c: i2c client
+ * @partnum: part number
  * @variant: the detected STMPE model number
  * @regs: list of addresses of registers which are at different addresses on
  *       different variants.  Indexed by one of STMPE_IDX_*.
@@ -121,6 +122,8 @@ struct stmpe_keypad_platform_data {
  * @norequest_mask: bitmask specifying which GPIOs should _not_ be
  *                 requestable due to different usage (e.g. touch, keypad)
  *                 STMPE_GPIO_NOREQ_* macros can be used here.
+ * @setup: board specific setup callback.
+ * @remove: board specific remove callback
  */
 struct stmpe_gpio_platform_data {
        int gpio_base;
index 73572c65d04f17e8bb6729689035bbe721c516f8..82b4c8801a4fc673fc4c7c0451bdb11330c821c7 100644 (file)
@@ -791,6 +791,7 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask);
 void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base);
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
                struct tps65910_platform_data *pdata);
+int tps65910_irq_exit(struct tps65910 *tps65910);
 
 static inline int tps65910_chip_id(struct tps65910 *tps65910)
 {
diff --git a/include/linux/mfd/tps65912.h b/include/linux/mfd/tps65912.h
new file mode 100644 (file)
index 0000000..aaceab4
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * tps65912.h  --  TI TPS6591x
+ *
+ * Copyright 2011 Texas Instruments Inc.
+ *
+ * Author: Margarita Olaya <magi@slimlogic.co.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 of the License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_TPS65912_H
+#define __LINUX_MFD_TPS65912_H
+
+/* TPS regulator type list */
+#define REGULATOR_LDO          0
+#define REGULATOR_DCDC         1
+
+/*
+ * List of registers for TPS65912
+ */
+
+#define TPS65912_DCDC1_CTRL            0x00
+#define TPS65912_DCDC2_CTRL            0x01
+#define TPS65912_DCDC3_CTRL            0x02
+#define TPS65912_DCDC4_CTRL            0x03
+#define TPS65912_DCDC1_OP              0x04
+#define TPS65912_DCDC1_AVS             0x05
+#define TPS65912_DCDC1_LIMIT           0x06
+#define TPS65912_DCDC2_OP              0x07
+#define TPS65912_DCDC2_AVS             0x08
+#define TPS65912_DCDC2_LIMIT           0x09
+#define TPS65912_DCDC3_OP              0x0A
+#define TPS65912_DCDC3_AVS             0x0B
+#define TPS65912_DCDC3_LIMIT           0x0C
+#define TPS65912_DCDC4_OP              0x0D
+#define TPS65912_DCDC4_AVS             0x0E
+#define TPS65912_DCDC4_LIMIT           0x0F
+#define TPS65912_LDO1_OP               0x10
+#define TPS65912_LDO1_AVS              0x11
+#define TPS65912_LDO1_LIMIT            0x12
+#define TPS65912_LDO2_OP               0x13
+#define TPS65912_LDO2_AVS              0x14
+#define TPS65912_LDO2_LIMIT            0x15
+#define TPS65912_LDO3_OP               0x16
+#define TPS65912_LDO3_AVS              0x17
+#define TPS65912_LDO3_LIMIT            0x18
+#define TPS65912_LDO4_OP               0x19
+#define TPS65912_LDO4_AVS              0x1A
+#define TPS65912_LDO4_LIMIT            0x1B
+#define TPS65912_LDO5                  0x1C
+#define TPS65912_LDO6                  0x1D
+#define TPS65912_LDO7                  0x1E
+#define TPS65912_LDO8                  0x1F
+#define TPS65912_LDO9                  0x20
+#define TPS65912_LDO10                 0x21
+#define TPS65912_THRM                  0x22
+#define TPS65912_CLK32OUT              0x23
+#define TPS65912_DEVCTRL               0x24
+#define TPS65912_DEVCTRL2              0x25
+#define TPS65912_I2C_SPI_CFG           0x26
+#define TPS65912_KEEP_ON               0x27
+#define TPS65912_KEEP_ON2              0x28
+#define TPS65912_SET_OFF1              0x29
+#define TPS65912_SET_OFF2              0x2A
+#define TPS65912_DEF_VOLT              0x2B
+#define TPS65912_DEF_VOLT_MAPPING      0x2C
+#define TPS65912_DISCHARGE             0x2D
+#define TPS65912_DISCHARGE2            0x2E
+#define TPS65912_EN1_SET1              0x2F
+#define TPS65912_EN1_SET2              0x30
+#define TPS65912_EN2_SET1              0x31
+#define TPS65912_EN2_SET2              0x32
+#define TPS65912_EN3_SET1              0x33
+#define TPS65912_EN3_SET2              0x34
+#define TPS65912_EN4_SET1              0x35
+#define TPS65912_EN4_SET2              0x36
+#define TPS65912_PGOOD                 0x37
+#define TPS65912_PGOOD2                        0x38
+#define TPS65912_INT_STS               0x39
+#define TPS65912_INT_MSK               0x3A
+#define TPS65912_INT_STS2              0x3B
+#define TPS65912_INT_MSK2              0x3C
+#define TPS65912_INT_STS3              0x3D
+#define TPS65912_INT_MSK3              0x3E
+#define TPS65912_INT_STS4              0x3F
+#define TPS65912_INT_MSK4              0x40
+#define TPS65912_GPIO1                 0x41
+#define TPS65912_GPIO2                 0x42
+#define TPS65912_GPIO3                 0x43
+#define TPS65912_GPIO4                 0x44
+#define TPS65912_GPIO5                 0x45
+#define TPS65912_VMON                  0x46
+#define TPS65912_LEDA_CTRL1            0x47
+#define TPS65912_LEDA_CTRL2            0x48
+#define TPS65912_LEDA_CTRL3            0x49
+#define TPS65912_LEDA_CTRL4            0x4A
+#define TPS65912_LEDA_CTRL5            0x4B
+#define TPS65912_LEDA_CTRL6            0x4C
+#define TPS65912_LEDA_CTRL7            0x4D
+#define TPS65912_LEDA_CTRL8            0x4E
+#define TPS65912_LEDB_CTRL1            0x4F
+#define TPS65912_LEDB_CTRL2            0x50
+#define TPS65912_LEDB_CTRL3            0x51
+#define TPS65912_LEDB_CTRL4            0x52
+#define TPS65912_LEDB_CTRL5            0x53
+#define TPS65912_LEDB_CTRL6            0x54
+#define TPS65912_LEDB_CTRL7            0x55
+#define TPS65912_LEDB_CTRL8            0x56
+#define TPS65912_LEDC_CTRL1            0x57
+#define TPS65912_LEDC_CTRL2            0x58
+#define TPS65912_LEDC_CTRL3            0x59
+#define TPS65912_LEDC_CTRL4            0x5A
+#define TPS65912_LEDC_CTRL5            0x5B
+#define TPS65912_LEDC_CTRL6            0x5C
+#define TPS65912_LEDC_CTRL7            0x5D
+#define TPS65912_LEDC_CTRL8            0x5E
+#define TPS65912_LED_RAMP_UP_TIME      0x5F
+#define TPS65912_LED_RAMP_DOWN_TIME    0x60
+#define TPS65912_LED_SEQ_EN            0x61
+#define TPS65912_LOADSWITCH            0x62
+#define TPS65912_SPARE                 0x63
+#define TPS65912_VERNUM                        0x64
+#define TPS6591X_MAX_REGISTER          0x64
+
+/* IRQ Definitions */
+#define TPS65912_IRQ_PWRHOLD_F         0
+#define TPS65912_IRQ_VMON              1
+#define TPS65912_IRQ_PWRON             2
+#define TPS65912_IRQ_PWRON_LP          3
+#define TPS65912_IRQ_PWRHOLD_R         4
+#define TPS65912_IRQ_HOTDIE            5
+#define TPS65912_IRQ_GPIO1_R           6
+#define TPS65912_IRQ_GPIO1_F           7
+#define TPS65912_IRQ_GPIO2_R           8
+#define TPS65912_IRQ_GPIO2_F           9
+#define TPS65912_IRQ_GPIO3_R           10
+#define TPS65912_IRQ_GPIO3_F           11
+#define TPS65912_IRQ_GPIO4_R           12
+#define TPS65912_IRQ_GPIO4_F           13
+#define TPS65912_IRQ_GPIO5_R           14
+#define TPS65912_IRQ_GPIO5_F           15
+#define TPS65912_IRQ_PGOOD_DCDC1       16
+#define TPS65912_IRQ_PGOOD_DCDC2       17
+#define TPS65912_IRQ_PGOOD_DCDC3       18
+#define TPS65912_IRQ_PGOOD_DCDC4       19
+#define TPS65912_IRQ_PGOOD_LDO1                20
+#define TPS65912_IRQ_PGOOD_LDO2                21
+#define TPS65912_IRQ_PGOOD_LDO3                22
+#define TPS65912_IRQ_PGOOD_LDO4                23
+#define TPS65912_IRQ_PGOOD_LDO5                24
+#define TPS65912_IRQ_PGOOD_LDO6                25
+#define TPS65912_IRQ_PGOOD_LDO7                26
+#define TPS65912_IRQ_PGOOD_LD08                27
+#define TPS65912_IRQ_PGOOD_LDO9                28
+#define TPS65912_IRQ_PGOOD_LDO10       29
+
+#define TPS65912_NUM_IRQ               30
+
+/* GPIO 1 and 2 Register Definitions */
+#define GPIO_SLEEP_MASK                        0x80
+#define GPIO_SLEEP_SHIFT               7
+#define GPIO_DEB_MASK                  0x10
+#define GPIO_DEB_SHIFT                 4
+#define GPIO_CFG_MASK                  0x04
+#define GPIO_CFG_SHIFT                 2
+#define GPIO_STS_MASK                  0x02
+#define GPIO_STS_SHIFT                 1
+#define GPIO_SET_MASK                  0x01
+#define GPIO_SET_SHIFT                 0
+
+/* GPIO 3 Register Definitions */
+#define GPIO3_SLEEP_MASK               0x80
+#define GPIO3_SLEEP_SHIFT              7
+#define GPIO3_SEL_MASK                 0x40
+#define GPIO3_SEL_SHIFT                        6
+#define GPIO3_ODEN_MASK                        0x20
+#define GPIO3_ODEN_SHIFT               5
+#define GPIO3_DEB_MASK                 0x10
+#define GPIO3_DEB_SHIFT                        4
+#define GPIO3_PDEN_MASK                        0x08
+#define GPIO3_PDEN_SHIFT               3
+#define GPIO3_CFG_MASK                 0x04
+#define GPIO3_CFG_SHIFT                        2
+#define GPIO3_STS_MASK                 0x02
+#define GPIO3_STS_SHIFT                        1
+#define GPIO3_SET_MASK                 0x01
+#define GPIO3_SET_SHIFT                        0
+
+/* GPIO 4 Register Definitions */
+#define GPIO4_SLEEP_MASK               0x80
+#define GPIO4_SLEEP_SHIFT              7
+#define GPIO4_SEL_MASK                 0x40
+#define GPIO4_SEL_SHIFT                        6
+#define GPIO4_ODEN_MASK                        0x20
+#define GPIO4_ODEN_SHIFT               5
+#define GPIO4_DEB_MASK                 0x10
+#define GPIO4_DEB_SHIFT                        4
+#define GPIO4_PDEN_MASK                        0x08
+#define GPIO4_PDEN_SHIFT               3
+#define GPIO4_CFG_MASK                 0x04
+#define GPIO4_CFG_SHIFT                        2
+#define GPIO4_STS_MASK                 0x02
+#define GPIO4_STS_SHIFT                        1
+#define GPIO4_SET_MASK                 0x01
+#define GPIO4_SET_SHIFT                        0
+
+/* Register THERM  (0x80) register.RegisterDescription */
+#define THERM_THERM_HD_MASK            0x20
+#define THERM_THERM_HD_SHIFT           5
+#define THERM_THERM_TS_MASK            0x10
+#define THERM_THERM_TS_SHIFT           4
+#define THERM_THERM_HDSEL_MASK         0x0C
+#define THERM_THERM_HDSEL_SHIFT                2
+#define THERM_RSVD1_MASK               0x02
+#define THERM_RSVD1_SHIFT              1
+#define THERM_THERM_STATE_MASK         0x01
+#define THERM_THERM_STATE_SHIFT                0
+
+/* Register DCDCCTRL1 register.RegisterDescription */
+#define DCDCCTRL_VCON_ENABLE_MASK      0x80
+#define DCDCCTRL_VCON_ENABLE_SHIFT     7
+#define DCDCCTRL_VCON_RANGE1_MASK      0x40
+#define DCDCCTRL_VCON_RANGE1_SHIFT     6
+#define DCDCCTRL_VCON_RANGE0_MASK      0x20
+#define DCDCCTRL_VCON_RANGE0_SHIFT     5
+#define DCDCCTRL_TSTEP2_MASK           0x10
+#define DCDCCTRL_TSTEP2_SHIFT          4
+#define DCDCCTRL_TSTEP1_MASK           0x08
+#define DCDCCTRL_TSTEP1_SHIFT          3
+#define DCDCCTRL_TSTEP0_MASK           0x04
+#define DCDCCTRL_TSTEP0_SHIFT          2
+#define DCDCCTRL_DCDC1_MODE_MASK       0x02
+#define DCDCCTRL_DCDC1_MODE_SHIFT      1
+
+/* Register DCDCCTRL2 and DCDCCTRL3 register.RegisterDescription */
+#define DCDCCTRL_TSTEP2_MASK           0x10
+#define DCDCCTRL_TSTEP2_SHIFT          4
+#define DCDCCTRL_TSTEP1_MASK           0x08
+#define DCDCCTRL_TSTEP1_SHIFT          3
+#define DCDCCTRL_TSTEP0_MASK           0x04
+#define DCDCCTRL_TSTEP0_SHIFT          2
+#define DCDCCTRL_DCDC_MODE_MASK                0x02
+#define DCDCCTRL_DCDC_MODE_SHIFT       1
+#define DCDCCTRL_RSVD0_MASK            0x01
+#define DCDCCTRL_RSVD0_SHIFT           0
+
+/* Register DCDCCTRL4 register.RegisterDescription */
+#define DCDCCTRL_RAMP_TIME_MASK                0x01
+#define DCDCCTRL_RAMP_TIME_SHIFT       0
+
+/* Register DCDCx_AVS */
+#define DCDC_AVS_ENABLE_MASK           0x80
+#define DCDC_AVS_ENABLE_SHIFT          7
+#define DCDC_AVS_ECO_MASK              0x40
+#define DCDC_AVS_ECO_SHIFT             6
+
+/* Register DCDCx_LIMIT */
+#define DCDC_LIMIT_RANGE_MASK          0xC0
+#define DCDC_LIMIT_RANGE_SHIFT         6
+#define DCDC_LIMIT_MAX_SEL_MASK                0x3F
+#define DCDC_LIMIT_MAX_SEL_SHIFT       0
+
+/**
+ * struct tps65912_board
+ * Board platform dat may be used to initialize regulators.
+ */
+struct tps65912_board {
+       int is_dcdc1_avs;
+       int is_dcdc2_avs;
+       int is_dcdc3_avs;
+       int is_dcdc4_avs;
+       int irq;
+       int irq_base;
+       int gpio_base;
+       struct regulator_init_data *tps65912_pmic_init_data;
+};
+
+/**
+ * struct tps65912 - tps65912 sub-driver chip access routines
+ */
+
+struct tps65912 {
+       struct device *dev;
+       /* for read/write acces */
+       struct mutex io_mutex;
+
+       /* For device IO interfaces: I2C or SPI */
+       void *control_data;
+
+       int (*read)(struct tps65912 *tps65912, u8 reg, int size, void *dest);
+       int (*write)(struct tps65912 *tps65912, u8 reg, int size, void *src);
+
+       /* Client devices */
+       struct tps65912_pmic *pmic;
+
+       /* GPIO Handling */
+       struct gpio_chip gpio;
+
+       /* IRQ Handling */
+       struct mutex irq_lock;
+       int chip_irq;
+       int irq_base;
+       int irq_num;
+       u32 irq_mask;
+};
+
+struct tps65912_platform_data {
+       int irq;
+       int irq_base;
+};
+
+unsigned int tps_chip(void);
+
+int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask);
+int tps65912_clear_bits(struct tps65912 *tps65912, u8 reg, u8 mask);
+int tps65912_reg_read(struct tps65912 *tps65912, u8 reg);
+int tps65912_reg_write(struct tps65912 *tps65912, u8 reg, u8 val);
+int tps65912_device_init(struct tps65912 *tps65912);
+void tps65912_device_exit(struct tps65912 *tps65912);
+int tps65912_irq_init(struct tps65912 *tps65912, int irq,
+                       struct tps65912_platform_data *pdata);
+
+#endif /*  __LINUX_MFD_TPS65912_H */
index 0d515ee1c24747319b561f0f0bda98dd1e50903e..8dda8ded5cda666c0147a197188c6f5de98030f4 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/completion.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
 
 /*
  * Register values.
 #define WM831X_ON_PIN_TO_SHIFT                       0  /* ON_PIN_TO - [1:0] */
 #define WM831X_ON_PIN_TO_WIDTH                       2  /* ON_PIN_TO - [1:0] */
 
+/*
+ * R16528 (0x4090) - Clock Control 1
+ */
+#define WM831X_CLKOUT_ENA                       0x8000  /* CLKOUT_ENA */
+#define WM831X_CLKOUT_ENA_MASK                  0x8000  /* CLKOUT_ENA */
+#define WM831X_CLKOUT_ENA_SHIFT                     15  /* CLKOUT_ENA */
+#define WM831X_CLKOUT_ENA_WIDTH                      1  /* CLKOUT_ENA */
+#define WM831X_CLKOUT_OD                        0x2000  /* CLKOUT_OD */
+#define WM831X_CLKOUT_OD_MASK                   0x2000  /* CLKOUT_OD */
+#define WM831X_CLKOUT_OD_SHIFT                      13  /* CLKOUT_OD */
+#define WM831X_CLKOUT_OD_WIDTH                       1  /* CLKOUT_OD */
+#define WM831X_CLKOUT_SLOT_MASK                 0x0700  /* CLKOUT_SLOT - [10:8] */
+#define WM831X_CLKOUT_SLOT_SHIFT                     8  /* CLKOUT_SLOT - [10:8] */
+#define WM831X_CLKOUT_SLOT_WIDTH                     3  /* CLKOUT_SLOT - [10:8] */
+#define WM831X_CLKOUT_SLPSLOT_MASK              0x0070  /* CLKOUT_SLPSLOT - [6:4] */
+#define WM831X_CLKOUT_SLPSLOT_SHIFT                  4  /* CLKOUT_SLPSLOT - [6:4] */
+#define WM831X_CLKOUT_SLPSLOT_WIDTH                  3  /* CLKOUT_SLPSLOT - [6:4] */
+#define WM831X_CLKOUT_SRC                       0x0001  /* CLKOUT_SRC */
+#define WM831X_CLKOUT_SRC_MASK                  0x0001  /* CLKOUT_SRC */
+#define WM831X_CLKOUT_SRC_SHIFT                      0  /* CLKOUT_SRC */
+#define WM831X_CLKOUT_SRC_WIDTH                      1  /* CLKOUT_SRC */
+
+/*
+ * R16529 (0x4091) - Clock Control 2
+ */
+#define WM831X_XTAL_INH                         0x8000  /* XTAL_INH */
+#define WM831X_XTAL_INH_MASK                    0x8000  /* XTAL_INH */
+#define WM831X_XTAL_INH_SHIFT                       15  /* XTAL_INH */
+#define WM831X_XTAL_INH_WIDTH                        1  /* XTAL_INH */
+#define WM831X_XTAL_ENA                         0x2000  /* XTAL_ENA */
+#define WM831X_XTAL_ENA_MASK                    0x2000  /* XTAL_ENA */
+#define WM831X_XTAL_ENA_SHIFT                       13  /* XTAL_ENA */
+#define WM831X_XTAL_ENA_WIDTH                        1  /* XTAL_ENA */
+#define WM831X_XTAL_BKUPENA                     0x1000  /* XTAL_BKUPENA */
+#define WM831X_XTAL_BKUPENA_MASK                0x1000  /* XTAL_BKUPENA */
+#define WM831X_XTAL_BKUPENA_SHIFT                   12  /* XTAL_BKUPENA */
+#define WM831X_XTAL_BKUPENA_WIDTH                    1  /* XTAL_BKUPENA */
+#define WM831X_FLL_AUTO                         0x0080  /* FLL_AUTO */
+#define WM831X_FLL_AUTO_MASK                    0x0080  /* FLL_AUTO */
+#define WM831X_FLL_AUTO_SHIFT                        7  /* FLL_AUTO */
+#define WM831X_FLL_AUTO_WIDTH                        1  /* FLL_AUTO */
+#define WM831X_FLL_AUTO_FREQ_MASK               0x0007  /* FLL_AUTO_FREQ - [2:0] */
+#define WM831X_FLL_AUTO_FREQ_SHIFT                   0  /* FLL_AUTO_FREQ - [2:0] */
+#define WM831X_FLL_AUTO_FREQ_WIDTH                   3  /* FLL_AUTO_FREQ - [2:0] */
+
+/*
+ * R16530 (0x4092) - FLL Control 1
+ */
+#define WM831X_FLL_FRAC                         0x0004  /* FLL_FRAC */
+#define WM831X_FLL_FRAC_MASK                    0x0004  /* FLL_FRAC */
+#define WM831X_FLL_FRAC_SHIFT                        2  /* FLL_FRAC */
+#define WM831X_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM831X_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM831X_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM831X_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM831X_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM831X_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM831X_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM831X_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM831X_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R16531 (0x4093) - FLL Control 2
+ */
+#define WM831X_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM831X_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM831X_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM831X_FLL_CTRL_RATE_MASK               0x0070  /* FLL_CTRL_RATE - [6:4] */
+#define WM831X_FLL_CTRL_RATE_SHIFT                   4  /* FLL_CTRL_RATE - [6:4] */
+#define WM831X_FLL_CTRL_RATE_WIDTH                   3  /* FLL_CTRL_RATE - [6:4] */
+#define WM831X_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM831X_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM831X_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R16532 (0x4094) - FLL Control 3
+ */
+#define WM831X_FLL_K_MASK                       0xFFFF  /* FLL_K - [15:0] */
+#define WM831X_FLL_K_SHIFT                           0  /* FLL_K - [15:0] */
+#define WM831X_FLL_K_WIDTH                          16  /* FLL_K - [15:0] */
+
+/*
+ * R16533 (0x4095) - FLL Control 4
+ */
+#define WM831X_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM831X_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM831X_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM831X_FLL_GAIN_MASK                    0x000F  /* FLL_GAIN - [3:0] */
+#define WM831X_FLL_GAIN_SHIFT                        0  /* FLL_GAIN - [3:0] */
+#define WM831X_FLL_GAIN_WIDTH                        4  /* FLL_GAIN - [3:0] */
+
+/*
+ * R16534 (0x4096) - FLL Control 5
+ */
+#define WM831X_FLL_CLK_REF_DIV_MASK             0x0018  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM831X_FLL_CLK_REF_DIV_SHIFT                 3  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM831X_FLL_CLK_REF_DIV_WIDTH                 2  /* FLL_CLK_REF_DIV - [4:3] */
+#define WM831X_FLL_CLK_SRC_MASK                 0x0003  /* FLL_CLK_SRC - [1:0] */
+#define WM831X_FLL_CLK_SRC_SHIFT                     0  /* FLL_CLK_SRC - [1:0] */
+#define WM831X_FLL_CLK_SRC_WIDTH                     2  /* FLL_CLK_SRC - [1:0] */
+
 struct regulator_dev;
 
 #define WM831X_NUM_IRQ_REGS 5
+#define WM831X_NUM_GPIO_REGS 16
 
 enum wm831x_parent {
        WM8310 = 0x8310,
@@ -248,6 +351,12 @@ enum wm831x_parent {
        WM8326 = 0x8326,
 };
 
+struct wm831x;
+enum wm831x_auxadc;
+
+typedef int (*wm831x_auxadc_read_fn)(struct wm831x *wm831x,
+                                    enum wm831x_auxadc input);
+
 struct wm831x {
        struct mutex io_lock;
 
@@ -261,7 +370,7 @@ struct wm831x {
 
        int irq;  /* Our chip IRQ */
        struct mutex irq_lock;
-       unsigned int irq_base;
+       int irq_base;
        int irq_masks_cur[WM831X_NUM_IRQ_REGS];   /* Currently active value */
        int irq_masks_cache[WM831X_NUM_IRQ_REGS]; /* Cached hardware value */
 
@@ -272,8 +381,13 @@ struct wm831x {
 
        int num_gpio;
 
+       /* Used by the interrupt controller code to post writes */
+       int gpio_update[WM831X_NUM_GPIO_REGS];
+
        struct mutex auxadc_lock;
-       struct completion auxadc_done;
+       struct list_head auxadc_pending;
+       u16 auxadc_active;
+       wm831x_auxadc_read_fn auxadc_read;
 
        /* The WM831x has a security key blocking access to certain
         * registers.  The mutex is taken by the accessors for locking
@@ -300,5 +414,6 @@ void wm831x_device_exit(struct wm831x *wm831x);
 int wm831x_device_suspend(struct wm831x *wm831x);
 int wm831x_irq_init(struct wm831x *wm831x, int irq);
 void wm831x_irq_exit(struct wm831x *wm831x);
+void wm831x_auxadc_init(struct wm831x *wm831x);
 
 #endif
index ff42d700293fc71485d80f092c978fd633919b27..0ba24599fe514e9963d1b665ad83e1ac12f418bf 100644 (file)
@@ -120,6 +120,9 @@ struct wm831x_pdata {
        /** Put the /IRQ line into CMOS mode */
        bool irq_cmos;
 
+       /** Disable the touchscreen */
+       bool disable_touch;
+
        int irq_base;
        int gpio_base;
        int gpio_defaults[WM831X_GPIO_NUM];
index 027935c86c688df2315d7ea4862d2c8e233ab8aa..774b8952deb46cff7ab12a76936f1cad25ebae4d 100644 (file)
@@ -30,23 +30,61 @@ struct address_space;
  * moment. Note that we have no way to track which tasks are using
  * a page, though if it is a pagecache page, rmap structures can tell us
  * who is mapping it.
+ *
+ * The objects in struct page are organized in double word blocks in
+ * order to allows us to use atomic double word operations on portions
+ * of struct page. That is currently only used by slub but the arrangement
+ * allows the use of atomic double word operations on the flags/mapping
+ * and lru list pointers also.
  */
 struct page {
+       /* First double word block */
        unsigned long flags;            /* Atomic flags, some possibly
                                         * updated asynchronously */
-       atomic_t _count;                /* Usage count, see below. */
-       union {
-               atomic_t _mapcount;     /* Count of ptes mapped in mms,
-                                        * to show when page is mapped
-                                        * & limit reverse map searches.
+       struct address_space *mapping;  /* If low bit clear, points to
+                                        * inode address_space, or NULL.
+                                        * If page mapped as anonymous
+                                        * memory, low bit is set, and
+                                        * it points to anon_vma object:
+                                        * see PAGE_MAPPING_ANON below.
                                         */
-               struct {                /* SLUB */
-                       u16 inuse;
-                       u16 objects;
+       /* Second double word */
+       struct {
+               union {
+                       pgoff_t index;          /* Our offset within mapping. */
+                       void *freelist;         /* slub first free object */
+               };
+
+               union {
+                       /* Used for cmpxchg_double in slub */
+                       unsigned long counters;
+
+                       struct {
+
+                               union {
+                                       atomic_t _mapcount;     /* Count of ptes mapped in mms,
+                                                        * to show when page is mapped
+                                                        * & limit reverse map searches.
+                                                        */
+
+                                       struct {
+                                               unsigned inuse:16;
+                                               unsigned objects:15;
+                                               unsigned frozen:1;
+                                       };
+                               };
+                               atomic_t _count;                /* Usage count, see below. */
+                       };
                };
        };
+
+       /* Third double word block */
+       struct list_head lru;           /* Pageout list, eg. active_list
+                                        * protected by zone->lru_lock !
+                                        */
+
+       /* Remainder is not double word aligned */
        union {
-           struct {
                unsigned long private;          /* Mapping-private opaque data:
                                                 * usually used for buffer_heads
                                                 * if PagePrivate set; used for
@@ -54,27 +92,13 @@ struct page {
                                                 * indicates order in the buddy
                                                 * system if PG_buddy is set.
                                                 */
-               struct address_space *mapping;  /* If low bit clear, points to
-                                                * inode address_space, or NULL.
-                                                * If page mapped as anonymous
-                                                * memory, low bit is set, and
-                                                * it points to anon_vma object:
-                                                * see PAGE_MAPPING_ANON below.
-                                                */
-           };
 #if USE_SPLIT_PTLOCKS
-           spinlock_t ptl;
+               spinlock_t ptl;
 #endif
-           struct kmem_cache *slab;    /* SLUB: Pointer to slab */
-           struct page *first_page;    /* Compound tail pages */
-       };
-       union {
-               pgoff_t index;          /* Our offset within mapping. */
-               void *freelist;         /* SLUB: freelist req. slab lock */
+               struct kmem_cache *slab;        /* SLUB: Pointer to slab */
+               struct page *first_page;        /* Compound tail pages */
        };
-       struct list_head lru;           /* Pageout list, eg. active_list
-                                        * protected by zone->lru_lock !
-                                        */
+
        /*
         * On machines where all RAM is mapped into kernel address space,
         * we can simply calculate the virtual address. On machines with
@@ -100,7 +124,16 @@ struct page {
         */
        void *shadow;
 #endif
-};
+}
+/*
+ * If another subsystem starts using the double word pairing for atomic
+ * operations on struct page then it must change the #if to ensure
+ * proper alignment of the page struct.
+ */
+#if defined(CONFIG_SLUB) && defined(CONFIG_CMPXCHG_LOCAL)
+       __attribute__((__aligned__(2*sizeof(unsigned long))))
+#endif
+;
 
 typedef unsigned long __nocast vm_flags_t;
 
index 2ed0b6cf11c56de2aeb568bc6d1bd6201d4b75ce..ddee79bb8f1583e8dd45a46e25e264da84967104 100644 (file)
@@ -1132,7 +1132,7 @@ struct net_device {
        spinlock_t              addr_list_lock;
        struct netdev_hw_addr_list      uc;     /* Unicast mac addresses */
        struct netdev_hw_addr_list      mc;     /* Multicast mac addresses */
-       int                     uc_promisc;
+       bool                    uc_promisc;
        unsigned int            promiscuity;
        unsigned int            allmulti;
 
@@ -1679,9 +1679,12 @@ static inline int skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen)
 static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen,
                                        unsigned int offset)
 {
+       if (!pskb_may_pull(skb, hlen))
+               return NULL;
+
        NAPI_GRO_CB(skb)->frag0 = NULL;
        NAPI_GRO_CB(skb)->frag0_len = 0;
-       return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
+       return skb->data + offset;
 }
 
 static inline void *skb_gro_mac_header(struct sk_buff *skb)
index f387919bbc59777fcdf5b246458472054407dc71..8c6ee44914cb4c7dc464167a2163625ac6c6f8f8 100644 (file)
@@ -29,6 +29,8 @@
 #define NFS_MNT_VERSION                1
 #define NFS_MNT3_VERSION       3
 
+#define NFS_PIPE_DIRNAME "/nfs"
+
 /*
  * NFS stats. The good thing with these values is that NFSv3 errors are
  * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
index 504b289ba6806ec7d4c6016f2cf9471f1b7f0370..76f99e8714f3f46f3fb9f51318483cecc6a8f0fe 100644 (file)
@@ -563,6 +563,10 @@ enum {
        NFSPROC4_CLNT_GETDEVICEINFO,
        NFSPROC4_CLNT_LAYOUTCOMMIT,
        NFSPROC4_CLNT_LAYOUTRETURN,
+       NFSPROC4_CLNT_SECINFO_NO_NAME,
+       NFSPROC4_CLNT_TEST_STATEID,
+       NFSPROC4_CLNT_FREE_STATEID,
+       NFSPROC4_CLNT_GETDEVICELIST,
 };
 
 /* nfs41 types */
index 8b579beb63586c9561c9da1c2c87790587ebf84c..b96fb99072ffdb4fbdb687438d19d5a629106a02 100644 (file)
@@ -99,9 +99,10 @@ struct nfs_open_context {
 
 struct nfs_open_dir_context {
        struct rpc_cred *cred;
+       unsigned long attr_gencount;
        __u64 dir_cookie;
        __u64 dup_cookie;
-       int duped;
+       signed char duped;
 };
 
 /*
index 08c444aa0411618aa426272f06768d6fa716f0d1..b5479df8378d2fe3981ffab93bb5ff39980e9474 100644 (file)
@@ -16,6 +16,7 @@ struct nfs4_sequence_args;
 struct nfs4_sequence_res;
 struct nfs_server;
 struct nfs4_minor_version_ops;
+struct server_scope;
 
 /*
  * The nfs_client identifies our client state to the server.
@@ -77,12 +78,13 @@ struct nfs_client {
        /* The flags used for obtaining the clientid during EXCHANGE_ID */
        u32                     cl_exchange_flags;
        struct nfs4_session     *cl_session;    /* sharred session */
-       struct list_head        cl_layouts;
 #endif /* CONFIG_NFS_V4 */
 
 #ifdef CONFIG_NFS_FSCACHE
        struct fscache_cookie   *fscache;       /* client index cache cookie */
 #endif
+
+       struct server_scope     *server_scope;  /* from exchange_id */
 };
 
 /*
@@ -129,8 +131,9 @@ struct nfs_server {
        struct fscache_cookie   *fscache;       /* superblock cookie */
 #endif
 
+       u32                     pnfs_blksize;   /* layout_blksize attr */
 #ifdef CONFIG_NFS_V4
-       u32                     attr_bitmask[2];/* V4 bitmask representing the set
+       u32                     attr_bitmask[3];/* V4 bitmask representing the set
                                                   of attributes supported on this
                                                   filesystem */
        u32                     cache_consistency_bitmask[2];
@@ -143,12 +146,14 @@ struct nfs_server {
                                                   filesystem */
        struct pnfs_layoutdriver_type  *pnfs_curr_ld; /* Active layout driver */
        struct rpc_wait_queue   roc_rpcwaitq;
+       void                    *pnfs_ld_data;  /* per mount point data */
 
        /* the following fields are protected by nfs_client->cl_lock */
        struct rb_root          state_owners;
        struct rb_root          openowner_id;
        struct rb_root          lockowner_id;
 #endif
+       struct list_head        layouts;
        struct list_head        delegations;
        void (*destroy)(struct nfs_server *);
 
index 25311b3bedf855574eb79170ea7b25d98962b0d6..e2791a27a901ec046f6eff6082b48a06a63b91c8 100644 (file)
@@ -55,20 +55,28 @@ struct nfs_page {
        struct nfs_writeverf    wb_verf;        /* Commit cookie */
 };
 
+struct nfs_pageio_descriptor;
+struct nfs_pageio_ops {
+       void    (*pg_init)(struct nfs_pageio_descriptor *, struct nfs_page *);
+       bool    (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
+       int     (*pg_doio)(struct nfs_pageio_descriptor *);
+};
+
 struct nfs_pageio_descriptor {
        struct list_head        pg_list;
        unsigned long           pg_bytes_written;
        size_t                  pg_count;
        size_t                  pg_bsize;
        unsigned int            pg_base;
-       char                    pg_moreio;
+       unsigned char           pg_moreio : 1,
+                               pg_recoalesce : 1;
 
        struct inode            *pg_inode;
-       int                     (*pg_doio)(struct nfs_pageio_descriptor *);
+       const struct nfs_pageio_ops *pg_ops;
        int                     pg_ioflags;
        int                     pg_error;
+       const struct rpc_call_ops *pg_rpc_callops;
        struct pnfs_layout_segment *pg_lseg;
-       bool                    (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
 };
 
 #define NFS_WBACK_BUSY(req)    (test_bit(PG_BUSY,&(req)->wb_flags))
@@ -85,7 +93,7 @@ extern        int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst,
                          pgoff_t idx_start, unsigned int npages, int tag);
 extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
                             struct inode *inode,
-                            int (*doio)(struct nfs_pageio_descriptor *desc),
+                            const struct nfs_pageio_ops *pg_ops,
                             size_t bsize,
                             int how);
 extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *,
@@ -100,7 +108,6 @@ extern      void nfs_unlock_request(struct nfs_page *req);
 extern int nfs_set_page_tag_locked(struct nfs_page *req);
 extern  void nfs_clear_page_tag_locked(struct nfs_page *req);
 
-
 /*
  * Lock the page of an asynchronous request without getting a new reference
  */
index 00848d86ffb250fe50b7e5090986646aac43aa47..569ea5b76fda77f7b436eff5b873333dd3029121 100644 (file)
@@ -122,6 +122,7 @@ struct nfs_fsinfo {
        struct timespec         time_delta; /* server time granularity */
        __u32                   lease_time; /* in seconds */
        __u32                   layouttype; /* supported pnfs layout driver */
+       __u32                   blksize; /* preferred pnfs io block size */
 };
 
 struct nfs_fsstat {
@@ -235,6 +236,17 @@ struct nfs4_layoutget {
        gfp_t gfp_flags;
 };
 
+struct nfs4_getdevicelist_args {
+       const struct nfs_fh *fh;
+       u32 layoutclass;
+       struct nfs4_sequence_args seq_args;
+};
+
+struct nfs4_getdevicelist_res {
+       struct pnfs_devicelist *devlist;
+       struct nfs4_sequence_res seq_res;
+};
+
 struct nfs4_getdeviceinfo_args {
        struct pnfs_device *pdev;
        struct nfs4_sequence_args seq_args;
@@ -257,21 +269,23 @@ struct nfs4_layoutcommit_res {
        struct nfs_fattr *fattr;
        const struct nfs_server *server;
        struct nfs4_sequence_res seq_res;
+       int status;
 };
 
 struct nfs4_layoutcommit_data {
        struct rpc_task task;
        struct nfs_fattr fattr;
-       struct pnfs_layout_segment *lseg;
+       struct list_head lseg_list;
        struct rpc_cred *cred;
        struct nfs4_layoutcommit_args args;
        struct nfs4_layoutcommit_res res;
 };
 
 struct nfs4_layoutreturn_args {
-       __u32   layout_type;
+       struct pnfs_layout_hdr *layout;
        struct inode *inode;
        nfs4_stateid stateid;
+       __u32   layout_type;
        struct nfs4_sequence_args seq_args;
 };
 
@@ -942,7 +956,7 @@ struct nfs4_server_caps_arg {
 };
 
 struct nfs4_server_caps_res {
-       u32                             attr_bitmask[2];
+       u32                             attr_bitmask[3];
        u32                             acl_bitmask;
        u32                             has_links;
        u32                             has_symlinks;
@@ -1060,6 +1074,7 @@ struct server_scope {
 struct nfs41_exchange_id_res {
        struct nfs_client               *client;
        u32                             flags;
+       struct server_scope             *server_scope;
 };
 
 struct nfs41_create_session_args {
@@ -1083,6 +1098,34 @@ struct nfs41_reclaim_complete_args {
 struct nfs41_reclaim_complete_res {
        struct nfs4_sequence_res        seq_res;
 };
+
+#define SECINFO_STYLE_CURRENT_FH 0
+#define SECINFO_STYLE_PARENT 1
+struct nfs41_secinfo_no_name_args {
+       int                             style;
+       struct nfs4_sequence_args       seq_args;
+};
+
+struct nfs41_test_stateid_args {
+       nfs4_stateid                    *stateid;
+       struct nfs4_sequence_args       seq_args;
+};
+
+struct nfs41_test_stateid_res {
+       unsigned int                    status;
+       struct nfs4_sequence_res        seq_res;
+};
+
+struct nfs41_free_stateid_args {
+       nfs4_stateid                    *stateid;
+       struct nfs4_sequence_args       seq_args;
+};
+
+struct nfs41_free_stateid_res {
+       unsigned int                    status;
+       struct nfs4_sequence_res        seq_res;
+};
+
 #endif /* CONFIG_NFS_V4_1 */
 
 struct nfs_page;
@@ -1096,6 +1139,7 @@ struct nfs_read_data {
        struct rpc_cred         *cred;
        struct nfs_fattr        fattr;  /* fattr storage */
        struct list_head        pages;  /* Coalesced read requests */
+       struct list_head        list;   /* lists of struct nfs_read_data */
        struct nfs_page         *req;   /* multi ops per nfs_page */
        struct page             **pagevec;
        unsigned int            npages; /* Max length of pagevec */
@@ -1119,6 +1163,7 @@ struct nfs_write_data {
        struct nfs_fattr        fattr;
        struct nfs_writeverf    verf;
        struct list_head        pages;          /* Coalesced requests we wish to flush */
+       struct list_head        list;           /* lists of struct nfs_write_data */
        struct nfs_page         *req;           /* multi ops per nfs_page */
        struct page             **pagevec;
        unsigned int            npages;         /* Max length of pagevec */
index aec8025c786a66c24900f1f2e5bdc89c6418c579..52280a2b5e632b1c402b50a99dcbb9891ff83564 100644 (file)
@@ -57,6 +57,8 @@ extern int of_mm_gpiochip_add(struct device_node *np,
 extern void of_gpiochip_add(struct gpio_chip *gc);
 extern void of_gpiochip_remove(struct gpio_chip *gc);
 extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np);
+extern int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
+                               const void *gpio_spec, u32 *flags);
 
 #else /* CONFIG_OF_GPIO */
 
@@ -72,6 +74,13 @@ static inline unsigned int of_gpio_count(struct device_node *np)
        return 0;
 }
 
+static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
+                                      struct device_node *np,
+                                      const void *gpio_spec, u32 *flags)
+{
+       return -ENOSYS;
+}
+
 static inline void of_gpiochip_add(struct gpio_chip *gc) { }
 static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
 
index e6955f5d1f08a7069ce7b9335815f7ef6e77dd04..cd2e61ce4e83243480231fb7fa9c3df566e9e59b 100644 (file)
@@ -63,6 +63,9 @@ extern int of_irq_map_one(struct device_node *device, int index,
 extern unsigned int irq_create_of_mapping(struct device_node *controller,
                                          const u32 *intspec,
                                          unsigned int intsize);
+#ifdef CONFIG_IRQ_DOMAIN
+extern void irq_dispose_mapping(unsigned int irq);
+#endif
 extern int of_irq_to_resource(struct device_node *dev, int index,
                              struct resource *r);
 extern int of_irq_count(struct device_node *dev);
@@ -70,6 +73,7 @@ extern int of_irq_to_resource_table(struct device_node *dev,
                struct resource *res, int nr_irqs);
 extern struct device_node *of_irq_find_parent(struct device_node *child);
 
+
 #endif /* CONFIG_OF_IRQ */
 #endif /* CONFIG_OF */
 #endif /* __OF_IRQ_H */
index e913081fb52a19350e99afcdf2de09e5a844eb36..f47464188710e8271e37faaa8a457da95e3533df 100644 (file)
@@ -9,6 +9,7 @@
 
 #ifdef CONFIG_OF_NET
 #include <linux/of.h>
+extern const int of_get_phy_mode(struct device_node *np);
 extern const void *of_get_mac_address(struct device_node *np);
 #endif
 
index 3e5a1b189a4196d393f7dca96903a83b1d2a277a..e90a673be67e1eebb4c98ba30c198ede805dcb82 100644 (file)
@@ -124,9 +124,6 @@ enum pageflags {
 
        /* SLOB */
        PG_slob_free = PG_private,
-
-       /* SLUB */
-       PG_slub_frozen = PG_active,
 };
 
 #ifndef __GENERATING_BOUNDS_H
@@ -212,8 +209,6 @@ PAGEFLAG(SwapBacked, swapbacked) __CLEARPAGEFLAG(SwapBacked, swapbacked)
 
 __PAGEFLAG(SlobFree, slob_free)
 
-__PAGEFLAG(SlubFrozen, slub_frozen)
-
 /*
  * Private page markings that may be used by the filesystem that owns the page
  * for its own purposes.
index 3a5626df37cec41e50b02b2a822ee191501a2a32..f27893b3b724205b3411e9081b99b4ca8e4429c2 100644 (file)
@@ -843,8 +843,8 @@ void pci_enable_ido(struct pci_dev *dev, unsigned long type);
 void pci_disable_ido(struct pci_dev *dev, unsigned long type);
 
 enum pci_obff_signal_type {
-       PCI_EXP_OBFF_SIGNAL_L0,
-       PCI_EXP_OBFF_SIGNAL_ALWAYS,
+       PCI_EXP_OBFF_SIGNAL_L0 = 0,
+       PCI_EXP_OBFF_SIGNAL_ALWAYS = 1,
 };
 int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type);
 void pci_disable_obff(struct pci_dev *dev);
@@ -879,7 +879,7 @@ void pdev_enable_device(struct pci_dev *);
 void pdev_sort_resources(struct pci_dev *, struct resource_list *);
 int pci_enable_resources(struct pci_dev *, int mask);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
-                   int (*)(struct pci_dev *, u8, u8));
+                   int (*)(const struct pci_dev *, u8, u8));
 #define HAVE_PCI_REQ_REGIONS   2
 int __must_check pci_request_regions(struct pci_dev *, const char *);
 int __must_check pci_request_regions_exclusive(struct pci_dev *, const char *);
index ad5186354d92402a6441f126896f592f476ddcdd..54fc4138955f820b9c3918e04082450941f44358 100644 (file)
@@ -53,6 +53,7 @@
 
 /* Interface Mode definitions */
 typedef enum {
+       PHY_INTERFACE_MODE_NA,
        PHY_INTERFACE_MODE_MII,
        PHY_INTERFACE_MODE_GMII,
        PHY_INTERFACE_MODE_SGMII,
@@ -62,7 +63,8 @@ typedef enum {
        PHY_INTERFACE_MODE_RGMII_ID,
        PHY_INTERFACE_MODE_RGMII_RXID,
        PHY_INTERFACE_MODE_RGMII_TXID,
-       PHY_INTERFACE_MODE_RTBI
+       PHY_INTERFACE_MODE_RTBI,
+       PHY_INTERFACE_MODE_SMII,
 } phy_interface_t;
 
 
diff --git a/include/linux/platform_data/ntc_thermistor.h b/include/linux/platform_data/ntc_thermistor.h
new file mode 100644 (file)
index 0000000..abd2862
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * ntc_thermistor.h - NTC Thermistors
+ *
+ *  Copyright (C) 2010 Samsung Electronics
+ *  MyungJoo Ham <myungjoo.ham@samsung.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
+ */
+#ifndef _LINUX_NTC_H
+#define _LINUX_NTC_H
+
+enum ntc_thermistor_type {
+       TYPE_NCPXXWB473,
+       TYPE_NCPXXWL333,
+};
+
+struct ntc_thermistor_platform_data {
+       /*
+        * One (not both) of read_uV and read_ohm should be provided and only
+        * one of the two should be provided.
+        * Both functions should return negative value for an error case.
+        *
+        * pullup_uV, pullup_ohm, pulldown_ohm, and connect are required to use
+        * read_uV()
+        *
+        * How to setup pullup_ohm, pulldown_ohm, and connect is
+        * described at Documentation/hwmon/ntc
+        *
+        * pullup/down_ohm: 0 for infinite / not-connected
+        */
+       int (*read_uV)(void);
+       unsigned int pullup_uV;
+
+       unsigned int pullup_ohm;
+       unsigned int pulldown_ohm;
+       enum { NTC_CONNECTED_POSITIVE, NTC_CONNECTED_GROUND } connect;
+
+       int (*read_ohm)(void);
+};
+
+#endif /* _LINUX_NTC_H */
index 76efbdd01622caab5360ca5a5e49287ae691ece6..435dd5fa7453144b459253d1cb339f981ef7b5f7 100644 (file)
@@ -41,9 +41,6 @@
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
-#include <scsi/osd_protocol.h>
-
-#define PNFS_OSD_OSDNAME_MAXSIZE 256
 
 /*
  * draft-ietf-nfsv4-minorversion-22
@@ -99,12 +96,6 @@ struct pnfs_osd_objid {
 #define _DEVID_HI(oid_device_id) \
        (unsigned long long)be64_to_cpup(((__be64 *)(oid_device_id)->data) + 1)
 
-static inline int
-pnfs_osd_objid_xdr_sz(void)
-{
-       return (NFS4_DEVICEID4_SIZE / 4) + 2 + 2;
-}
-
 enum pnfs_osd_version {
        PNFS_OSD_MISSING              = 0,
        PNFS_OSD_VERSION_1            = 1,
@@ -189,8 +180,6 @@ struct pnfs_osd_targetid {
        struct nfs4_string              oti_scsi_device_id;
 };
 
-enum { PNFS_OSD_TARGETID_MAX = 1 + PNFS_OSD_OSDNAME_MAXSIZE / 4 };
-
 /*   struct netaddr4 {
  *       // see struct rpcb in RFC1833
  *       string r_netid<>;    // network id
@@ -207,12 +196,6 @@ struct pnfs_osd_targetaddr {
        struct pnfs_osd_net_addr        ota_netaddr;
 };
 
-enum {
-       NETWORK_ID_MAX = 16 / 4,
-       UNIVERSAL_ADDRESS_MAX = 64 / 4,
-       PNFS_OSD_TARGETADDR_MAX = 3 +  NETWORK_ID_MAX + UNIVERSAL_ADDRESS_MAX,
-};
-
 struct pnfs_osd_deviceaddr {
        struct pnfs_osd_targetid        oda_targetid;
        struct pnfs_osd_targetaddr      oda_targetaddr;
@@ -222,15 +205,6 @@ struct pnfs_osd_deviceaddr {
        struct nfs4_string              oda_osdname;
 };
 
-enum {
-       ODA_OSDNAME_MAX = PNFS_OSD_OSDNAME_MAXSIZE / 4,
-       PNFS_OSD_DEVICEADDR_MAX =
-               PNFS_OSD_TARGETID_MAX + PNFS_OSD_TARGETADDR_MAX +
-               2 /*oda_lun*/ +
-               1 + OSD_SYSTEMID_LEN +
-               1 + ODA_OSDNAME_MAX,
-};
-
 /* LAYOUTCOMMIT: layoutupdate */
 
 /*   union pnfs_osd_deltaspaceused4 switch (bool dsu_valid) {
@@ -279,7 +253,7 @@ struct pnfs_osd_ioerr {
        u32                     oer_errno;
 };
 
-/* OSD XDR API */
+/* OSD XDR Client API */
 /* Layout helpers */
 /* Layout decoding is done in two parts:
  * 1. First Call pnfs_osd_xdr_decode_layout_map to read in only the header part
@@ -337,8 +311,7 @@ extern int
 pnfs_osd_xdr_encode_layoutupdate(struct xdr_stream *xdr,
                                 struct pnfs_osd_layoutupdate *lou);
 
-/* osd_ioerror encoding/decoding (layout_return) */
-/* Client */
+/* osd_ioerror encoding (layout_return) */
 extern __be32 *pnfs_osd_xdr_ioerr_reserve_space(struct xdr_stream *xdr);
 extern void pnfs_osd_xdr_encode_ioerr(__be32 *p, struct pnfs_osd_ioerr *ioerr);
 
index b0843b68af9268a3726f7c26191f09e363f3716f..1398eb004e836add6db693adc77926e32e540dd7 100644 (file)
  * @battery_detect:            GPIO which is used to detect battery presence
  * @battery_detect_present:    gpio state when battery is present (0 / 1)
  * @i2c_retry_count:           # of times to retry on i2c IO failure
+ * @poll_retry_count:          # of times to retry looking for new status after
+ *                             external change notification
  */
 struct bq20z75_platform_data {
        int battery_detect;
        int battery_detect_present;
        int i2c_retry_count;
+       int poll_retry_count;
 };
 
 #endif
index 7995deb8bfc1858090e3756082a38b9806d58ddc..fe99211fb2b8c99cac624244b02d9b819ce3a9d7 100644 (file)
 #ifndef __MAX17042_BATTERY_H_
 #define __MAX17042_BATTERY_H_
 
+#define MAX17042_STATUS_BattAbsent     (1 << 3)
+#define MAX17042_BATTERY_FULL  (100)
+#define MAX17042_DEFAULT_SNS_RESISTOR  (10000)
+
+enum max17042_register {
+       MAX17042_STATUS         = 0x00,
+       MAX17042_VALRT_Th       = 0x01,
+       MAX17042_TALRT_Th       = 0x02,
+       MAX17042_SALRT_Th       = 0x03,
+       MAX17042_AtRate         = 0x04,
+       MAX17042_RepCap         = 0x05,
+       MAX17042_RepSOC         = 0x06,
+       MAX17042_Age            = 0x07,
+       MAX17042_TEMP           = 0x08,
+       MAX17042_VCELL          = 0x09,
+       MAX17042_Current        = 0x0A,
+       MAX17042_AvgCurrent     = 0x0B,
+       MAX17042_Qresidual      = 0x0C,
+       MAX17042_SOC            = 0x0D,
+       MAX17042_AvSOC          = 0x0E,
+       MAX17042_RemCap         = 0x0F,
+       MAX17402_FullCAP        = 0x10,
+       MAX17042_TTE            = 0x11,
+       MAX17042_V_empty        = 0x12,
+
+       MAX17042_RSLOW          = 0x14,
+
+       MAX17042_AvgTA          = 0x16,
+       MAX17042_Cycles         = 0x17,
+       MAX17042_DesignCap      = 0x18,
+       MAX17042_AvgVCELL       = 0x19,
+       MAX17042_MinMaxTemp     = 0x1A,
+       MAX17042_MinMaxVolt     = 0x1B,
+       MAX17042_MinMaxCurr     = 0x1C,
+       MAX17042_CONFIG         = 0x1D,
+       MAX17042_ICHGTerm       = 0x1E,
+       MAX17042_AvCap          = 0x1F,
+       MAX17042_ManName        = 0x20,
+       MAX17042_DevName        = 0x21,
+       MAX17042_DevChem        = 0x22,
+
+       MAX17042_TempNom        = 0x24,
+       MAX17042_TempCold       = 0x25,
+       MAX17042_TempHot        = 0x26,
+       MAX17042_AIN            = 0x27,
+       MAX17042_LearnCFG       = 0x28,
+       MAX17042_SHFTCFG        = 0x29,
+       MAX17042_RelaxCFG       = 0x2A,
+       MAX17042_MiscCFG        = 0x2B,
+       MAX17042_TGAIN          = 0x2C,
+       MAx17042_TOFF           = 0x2D,
+       MAX17042_CGAIN          = 0x2E,
+       MAX17042_COFF           = 0x2F,
+
+       MAX17042_Q_empty        = 0x33,
+       MAX17042_T_empty        = 0x34,
+
+       MAX17042_RCOMP0         = 0x38,
+       MAX17042_TempCo         = 0x39,
+       MAX17042_Rx             = 0x3A,
+       MAX17042_T_empty0       = 0x3B,
+       MAX17042_TaskPeriod     = 0x3C,
+       MAX17042_FSTAT          = 0x3D,
+
+       MAX17042_SHDNTIMER      = 0x3F,
+
+       MAX17042_VFRemCap       = 0x4A,
+
+       MAX17042_QH             = 0x4D,
+       MAX17042_QL             = 0x4E,
+};
+
+/*
+ * used for setting a register to a desired value
+ * addr : address for a register
+ * data : setting value for the register
+ */
+struct max17042_reg_data {
+       u8 addr;
+       u16 data;
+};
+
 struct max17042_platform_data {
+       struct max17042_reg_data *init_data;
+       int num_init_data; /* Number of enties in init_data array */
        bool enable_current_sense;
+
+       /*
+        * R_sns in micro-ohms.
+        * default 10000 (if r_sns = 0) as it is the recommended value by
+        * the datasheet although it can be changed by board designers.
+        */
+       unsigned int r_sns;
 };
 
 #endif /* __MAX17042_BATTERY_H_ */
index 650af6deaf8fa50e1b8e812e98346380958252e8..643b96c7a94f3cc78d6750b878ad0a0b00c2ea58 100644 (file)
@@ -50,8 +50,6 @@ typedef       int (write_proc_t)(struct file *file, const char __user *buffer,
 
 struct proc_dir_entry {
        unsigned int low_ino;
-       unsigned int namelen;
-       const char *name;
        mode_t mode;
        nlink_t nlink;
        uid_t uid;
@@ -73,9 +71,11 @@ struct proc_dir_entry {
        write_proc_t *write_proc;
        atomic_t count;         /* use count */
        int pde_users;  /* number of callers into module in progress */
-       spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
        struct completion *pde_unload_completion;
        struct list_head pde_openers;   /* who did ->open, but not ->release */
+       spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
+       u8 namelen;
+       char name[];
 };
 
 enum kcore_type {
index 75cbf4f62fe8a6bc6af1e20d99c0c3d3d0853c82..9e65d9e20662d84dac1fdf6627b9d2503deb1770 100644 (file)
@@ -245,10 +245,16 @@ struct mdp_superblock_1 {
        __u8    device_uuid[16]; /* user-space setable, ignored by kernel */
        __u8    devflags;       /* per-device flags.  Only one defined...*/
 #define        WriteMostly1    1       /* mask for writemostly flag in above */
-       __u8    pad2[64-57];    /* set to 0 when writing */
+       /* Bad block log.  If there are any bad blocks the feature flag is set.
+        * If offset and size are non-zero, that space is reserved and available
+        */
+       __u8    bblog_shift;    /* shift from sectors to block size */
+       __le16  bblog_size;     /* number of sectors reserved for list */
+       __le32  bblog_offset;   /* sector offset from superblock to bblog,
+                                * signed - not unsigned */
 
        /* array state information - 64 bytes */
-       __le64  utime;          /* 40 bits second, 24 btes microseconds */
+       __le64  utime;          /* 40 bits second, 24 bits microseconds */
        __le64  events;         /* incremented when superblock updated */
        __le64  resync_offset;  /* data before this offset (from data_offset) known to be in sync */
        __le32  sb_csum;        /* checksum up to devs[max_dev] */
@@ -270,8 +276,8 @@ struct mdp_superblock_1 {
                                           * must be honoured
                                           */
 #define        MD_FEATURE_RESHAPE_ACTIVE       4
+#define        MD_FEATURE_BAD_BLOCKS           8 /* badblock list is not empty */
 
-#define        MD_FEATURE_ALL                  (1|2|4)
+#define        MD_FEATURE_ALL                  (1|2|4|8)
 
 #endif 
-
index a2afc9fbe1869369d3d8c3165091ab3e9f73c46f..8bffe9ae2ca076cc1ec9b5cdf706f18d900e1c97 100644 (file)
@@ -8,6 +8,8 @@
  * Generic header for SuperH SCI(F) (used by sh/sh64/h8300 and related parts)
  */
 
+#define SCIx_NOT_SUPPORTED     (-1)
+
 enum {
        SCBRR_ALGO_1,           /* ((clk + 16 * bps) / (16 * bps) - 1) */
        SCBRR_ALGO_2,           /* ((clk + 16 * bps) / (32 * bps) - 1) */
@@ -25,6 +27,28 @@ enum {
 #define SCSCR_CKE1     (1 << 1)
 #define SCSCR_CKE0     (1 << 0)
 
+/* SCxSR SCI */
+#define SCI_TDRE  0x80
+#define SCI_RDRF  0x40
+#define SCI_ORER  0x20
+#define SCI_FER   0x10
+#define SCI_PER   0x08
+#define SCI_TEND  0x04
+
+#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
+
+/* SCxSR SCIF */
+#define SCIF_ER    0x0080
+#define SCIF_TEND  0x0040
+#define SCIF_TDFE  0x0020
+#define SCIF_BRK   0x0010
+#define SCIF_FER   0x0008
+#define SCIF_PER   0x0004
+#define SCIF_RDF   0x0002
+#define SCIF_DR    0x0001
+
+#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
+
 /* Offsets into the sci_port->irqs array */
 enum {
        SCIx_ERI_IRQ,
@@ -32,6 +56,24 @@ enum {
        SCIx_TXI_IRQ,
        SCIx_BRI_IRQ,
        SCIx_NR_IRQS,
+
+       SCIx_MUX_IRQ = SCIx_NR_IRQS,    /* special case */
+};
+
+enum {
+       SCIx_PROBE_REGTYPE,
+
+       SCIx_SCI_REGTYPE,
+       SCIx_IRDA_REGTYPE,
+       SCIx_SCIFA_REGTYPE,
+       SCIx_SCIFB_REGTYPE,
+       SCIx_SH3_SCIF_REGTYPE,
+       SCIx_SH4_SCIF_REGTYPE,
+       SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
+       SCIx_SH4_SCIF_FIFODATA_REGTYPE,
+       SCIx_SH7705_SCIF_REGTYPE,
+
+       SCIx_NR_REGTYPES,
 };
 
 #define SCIx_IRQ_MUXED(irq)            \
@@ -42,8 +84,29 @@ enum {
        [SCIx_BRI_IRQ]  = (irq),        \
 }
 
+#define SCIx_IRQ_IS_MUXED(port)                        \
+       ((port)->cfg->irqs[SCIx_ERI_IRQ] ==     \
+        (port)->cfg->irqs[SCIx_RXI_IRQ]) ||    \
+       ((port)->cfg->irqs[SCIx_ERI_IRQ] &&     \
+        !(port)->cfg->irqs[SCIx_RXI_IRQ])
+/*
+ * SCI register subset common for all port types.
+ * Not all registers will exist on all parts.
+ */
+enum {
+       SCSMR, SCBRR, SCSCR, SCxSR,
+       SCFCR, SCFDR, SCxTDR, SCxRDR,
+       SCLSR, SCTFDR, SCRFDR, SCSPTR,
+
+       SCIx_NR_REGS,
+};
+
 struct device;
 
+struct plat_sci_port_ops {
+       void (*init_pins)(struct uart_port *, unsigned int cflag);
+};
+
 /*
  * Platform device specific platform_data struct
  */
@@ -56,6 +119,18 @@ struct plat_sci_port {
        unsigned int    scbrr_algo_id;          /* SCBRR calculation algo */
        unsigned int    scscr;                  /* SCSCR initialization */
 
+       /*
+        * Platform overrides if necessary, defaults otherwise.
+        */
+       int             overrun_bit;
+       unsigned int    error_mask;
+
+       int             port_reg;
+       unsigned char   regshift;
+       unsigned char   regtype;
+
+       struct plat_sci_port_ops        *ops;
+
        struct device   *dma_dev;
 
        unsigned int    dma_slave_tx;
index 9a52f72527dc5a38831686cb824bf043258c8a19..3ccf18648d0ae885d5421695b45b8b16b2856f61 100644 (file)
@@ -147,4 +147,8 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr,
 int sh_clk_div6_register(struct clk *clks, int nr);
 int sh_clk_div6_reparent_register(struct clk *clks, int nr);
 
+#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
+#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
+#define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk }
+
 #endif /* __SH_CLOCK_H */
index b08cd4efa15c60818ae37606cfc983f6fc3e7a9d..cb2dd118cc0ffb91e62ad7746d230b0376f442dd 100644 (file)
@@ -62,6 +62,12 @@ struct sh_dmae_pdata {
        const unsigned int *ts_shift;
        int ts_shift_num;
        u16 dmaor_init;
+       unsigned int chcr_offset;
+       u32 chcr_ie_bit;
+
+       unsigned int dmaor_is_32bit:1;
+       unsigned int needs_tend_set:1;
+       unsigned int no_dmars:1;
 };
 
 /* DMA register */
@@ -71,6 +77,8 @@ struct sh_dmae_pdata {
 #define CHCR   0x0C
 #define DMAOR  0x40
 
+#define TEND   0x18 /* USB-DMAC */
+
 /* DMAOR definitions */
 #define DMAOR_AE       0x00000004
 #define DMAOR_NMIF     0x00000002
index 7d27ffde01902a7a29687c5ef36b607d290c694d..92808b86703ba7a63f786407144ec28f10ad13bc 100644 (file)
@@ -95,6 +95,9 @@ struct shmid_kernel /* private to the kernel */
        pid_t                   shm_cprid;
        pid_t                   shm_lprid;
        struct user_struct      *mlock_user;
+
+       /* The task created the shm object.  NULL if the task is dead. */
+       struct task_struct      *shm_creator;
 };
 
 /* shm_mode upper byte flags */
index 4b35c06dfbc5448b46b85422659f5552af817c37..f58d6413d230225c4e9771b63169d3d99a3aeca8 100644 (file)
@@ -24,6 +24,7 @@ enum stat_item {
        ALLOC_FROM_PARTIAL,     /* Cpu slab acquired from partial list */
        ALLOC_SLAB,             /* Cpu slab acquired from page allocator */
        ALLOC_REFILL,           /* Refill cpu slab from slab freelist */
+       ALLOC_NODE_MISMATCH,    /* Switching cpu slab */
        FREE_SLAB,              /* Slab freed to the page allocator */
        CPUSLAB_FLUSH,          /* Abandoning of the cpu slab */
        DEACTIVATE_FULL,        /* Cpu slab was full when deactivated */
@@ -31,8 +32,10 @@ enum stat_item {
        DEACTIVATE_TO_HEAD,     /* Cpu slab was moved to the head of partials */
        DEACTIVATE_TO_TAIL,     /* Cpu slab was moved to the tail of partials */
        DEACTIVATE_REMOTE_FREES,/* Slab contained remotely freed objects */
+       DEACTIVATE_BYPASS,      /* Implicit deactivation */
        ORDER_FALLBACK,         /* Number of times fallback was necessary */
        CMPXCHG_DOUBLE_CPU_FAIL,/* Failure of this_cpu_cmpxchg_double */
+       CMPXCHG_DOUBLE_FAIL,    /* Number of times that cmpxchg double did not match */
        NR_SLUB_STAT_ITEMS };
 
 struct kmem_cache_cpu {
index 082884295f80028a9a9aa3ea4255ad2cea3984d0..f7f3ce340c083f04b311f06aac1e8e34239c8016 100644 (file)
@@ -31,7 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <linux/sunrpc/xprt.h>
 #include <linux/sunrpc/sched.h>
 
-#ifdef CONFIG_NFS_V4_1
+#ifdef CONFIG_SUNRPC_BACKCHANNEL
 struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt);
 void xprt_free_bc_request(struct rpc_rqst *req);
 int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs);
@@ -47,7 +47,7 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
                return 1;
        return 0;
 }
-#else /* CONFIG_NFS_V4_1 */
+#else /* CONFIG_SUNRPC_BACKCHANNEL */
 static inline int xprt_setup_backchannel(struct rpc_xprt *xprt,
                                         unsigned int min_reqs)
 {
@@ -62,6 +62,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
 static inline void xprt_free_bc_request(struct rpc_rqst *req)
 {
 }
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 #endif /* _LINUX_SUNRPC_BC_XPRT_H */
 
index fe2d8e6b923b416908220e2ef70bed01dee60897..e7756896f3ca292f4398304f7761b691232df131 100644 (file)
@@ -227,6 +227,10 @@ void               rpc_init_wait_queue(struct rpc_wait_queue *, const char *);
 void           rpc_destroy_wait_queue(struct rpc_wait_queue *);
 void           rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
                                        rpc_action action);
+void           rpc_sleep_on_priority(struct rpc_wait_queue *,
+                                       struct rpc_task *,
+                                       rpc_action action,
+                                       int priority);
 void           rpc_wake_up_queued_task(struct rpc_wait_queue *,
                                        struct rpc_task *);
 void           rpc_wake_up(struct rpc_wait_queue *);
index 2f1e5186e0495cd2c0514ef5d3aedc1cec100958..223588a976a096af5f214b28e6e66e507a9b2e89 100644 (file)
@@ -92,7 +92,7 @@ struct svc_serv {
        struct module *         sv_module;      /* optional module to count when
                                                 * adding threads */
        svc_thread_fn           sv_function;    /* main function for threads */
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
        struct list_head        sv_cb_list;     /* queue for callback requests
                                                 * that arrive over the same
                                                 * connection */
@@ -100,7 +100,7 @@ struct svc_serv {
        wait_queue_head_t       sv_cb_waitq;    /* sleep here if there are no
                                                 * entries in the svc_cb_list */
        struct svc_xprt         *sv_bc_xprt;    /* callback on fore channel */
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 };
 
 /*
index 81cce3b3ee668195f406988cf35ef43394b8e846..15518a152ac3db6e973a95685d50d200e6a1f475 100644 (file)
@@ -22,6 +22,7 @@
 #define RPC_MIN_SLOT_TABLE     (2U)
 #define RPC_DEF_SLOT_TABLE     (16U)
 #define RPC_MAX_SLOT_TABLE     (128U)
+#define RPC_MAX_SLOT_TABLE_LIMIT       (65536U)
 
 /*
  * This describes a timeout strategy
@@ -100,18 +101,18 @@ struct rpc_rqst {
        ktime_t                 rq_xtime;       /* transmit time stamp */
        int                     rq_ntrans;
 
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
        struct list_head        rq_bc_list;     /* Callback service list */
        unsigned long           rq_bc_pa_state; /* Backchannel prealloc state */
        struct list_head        rq_bc_pa_list;  /* Backchannel prealloc list */
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANEL */
 };
 #define rq_svec                        rq_snd_buf.head
 #define rq_slen                        rq_snd_buf.len
 
 struct rpc_xprt_ops {
        void            (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize);
-       int             (*reserve_xprt)(struct rpc_task *task);
+       int             (*reserve_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
        void            (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task);
        void            (*rpcbind)(struct rpc_task *task);
        void            (*set_port)(struct rpc_xprt *xprt, unsigned short port);
@@ -164,12 +165,12 @@ struct rpc_xprt {
 
        struct rpc_wait_queue   binding;        /* requests waiting on rpcbind */
        struct rpc_wait_queue   sending;        /* requests waiting to send */
-       struct rpc_wait_queue   resend;         /* requests waiting to resend */
        struct rpc_wait_queue   pending;        /* requests in flight */
        struct rpc_wait_queue   backlog;        /* waiting for slot */
        struct list_head        free;           /* free slots */
-       struct rpc_rqst *       slot;           /* slot table storage */
-       unsigned int            max_reqs;       /* total slots */
+       unsigned int            max_reqs;       /* max number of slots */
+       unsigned int            min_reqs;       /* min number of slots */
+       atomic_t                num_reqs;       /* total slots */
        unsigned long           state;          /* transport state */
        unsigned char           shutdown   : 1, /* being shut down */
                                resvport   : 1; /* use a reserved port */
@@ -200,7 +201,7 @@ struct rpc_xprt {
        u32                     xid;            /* Next XID value to use */
        struct rpc_task *       snd_task;       /* Task blocked in send */
        struct svc_xprt         *bc_xprt;       /* NFSv4.1 backchannel */
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
        struct svc_serv         *bc_serv;       /* The RPC service which will */
                                                /* process the callback */
        unsigned int            bc_alloc_count; /* Total number of preallocs */
@@ -208,7 +209,7 @@ struct rpc_xprt {
                                                 * items */
        struct list_head        bc_pa_list;     /* List of preallocated
                                                 * backchannel rpc_rqst's */
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
        struct list_head        recv;
 
        struct {
@@ -228,15 +229,15 @@ struct rpc_xprt {
        const char              *address_strings[RPC_DISPLAY_MAX];
 };
 
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 /*
  * Backchannel flags
  */
 #define        RPC_BC_PA_IN_USE        0x0001          /* Preallocated backchannel */
                                                /* buffer in use */
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 static inline int bc_prealloc(struct rpc_rqst *req)
 {
        return test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
@@ -246,7 +247,7 @@ static inline int bc_prealloc(struct rpc_rqst *req)
 {
        return 0;
 }
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
 struct xprt_create {
        int                     ident;          /* XPRT_TRANSPORT identifier */
@@ -271,8 +272,8 @@ struct xprt_class {
 struct rpc_xprt                *xprt_create_transport(struct xprt_create *args);
 void                   xprt_connect(struct rpc_task *task);
 void                   xprt_reserve(struct rpc_task *task);
-int                    xprt_reserve_xprt(struct rpc_task *task);
-int                    xprt_reserve_xprt_cong(struct rpc_task *task);
+int                    xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
+int                    xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
 int                    xprt_prepare_transmit(struct rpc_task *task);
 void                   xprt_transmit(struct rpc_task *task);
 void                   xprt_end_transmit(struct rpc_task *task);
@@ -282,7 +283,9 @@ void                        xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
 void                   xprt_release(struct rpc_task *task);
 struct rpc_xprt *      xprt_get(struct rpc_xprt *xprt);
 void                   xprt_put(struct rpc_xprt *xprt);
-struct rpc_xprt *      xprt_alloc(struct net *net, int size, int max_req);
+struct rpc_xprt *      xprt_alloc(struct net *net, size_t size,
+                               unsigned int num_prealloc,
+                               unsigned int max_req);
 void                   xprt_free(struct rpc_xprt *);
 
 static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p)
@@ -321,7 +324,6 @@ void                        xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);
 #define XPRT_CLOSING           (6)
 #define XPRT_CONNECTION_ABORT  (7)
 #define XPRT_CONNECTION_CLOSE  (8)
-#define XPRT_INITIALIZED       (9)
 
 static inline void xprt_set_connected(struct rpc_xprt *xprt)
 {
index 8a4c309d23444450a13a9e675cdc51e4a14376f4..fca24cc504367ea6218c6d6c01c03ccf497ffb38 100644 (file)
@@ -376,7 +376,16 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG   */
 #define V4L2_PIX_FMT_JPEG     v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG     */
 #define V4L2_PIX_FMT_DV       v4l2_fourcc('d', 'v', 's', 'd') /* 1394          */
-#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4    */
+#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */
+#define V4L2_PIX_FMT_H264     v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */
+#define V4L2_PIX_FMT_H264_NO_SC v4l2_fourcc('A', 'V', 'C', '1') /* H264 without start codes */
+#define V4L2_PIX_FMT_H263     v4l2_fourcc('H', '2', '6', '3') /* H263          */
+#define V4L2_PIX_FMT_MPEG1    v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES     */
+#define V4L2_PIX_FMT_MPEG2    v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES     */
+#define V4L2_PIX_FMT_MPEG4    v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 ES     */
+#define V4L2_PIX_FMT_XVID     v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid           */
+#define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */
+#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
 
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_CPIA1    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -402,6 +411,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
 #define V4L2_PIX_FMT_KONICA420  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
 #define V4L2_PIX_FMT_JPGL      v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */
+#define V4L2_PIX_FMT_SE401      v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */
 
 /*
  *     F O R M A T   E N U M E R A T I O N
@@ -1026,6 +1036,7 @@ struct v4l2_ext_controls {
 #define V4L2_CTRL_CLASS_MPEG 0x00990000        /* MPEG-compression controls */
 #define V4L2_CTRL_CLASS_CAMERA 0x009a0000      /* Camera class controls */
 #define V4L2_CTRL_CLASS_FM_TX 0x009b0000       /* FM Modulator control class */
+#define V4L2_CTRL_CLASS_FLASH 0x009c0000       /* Camera flash controls */
 
 #define V4L2_CTRL_ID_MASK                (0x0fffffff)
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
@@ -1039,6 +1050,7 @@ enum v4l2_ctrl_type {
        V4L2_CTRL_TYPE_INTEGER64     = 5,
        V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
        V4L2_CTRL_TYPE_STRING        = 7,
+       V4L2_CTRL_TYPE_BITMASK       = 8,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
@@ -1144,14 +1156,19 @@ enum v4l2_colorfx {
 #define V4L2_CID_ILLUMINATORS_1                        (V4L2_CID_BASE+37)
 #define V4L2_CID_ILLUMINATORS_2                        (V4L2_CID_BASE+38)
 
+#define V4L2_CID_MIN_BUFFERS_FOR_CAPTURE       (V4L2_CID_BASE+39)
+#define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT                (V4L2_CID_BASE+40)
+
 /* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+39)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+41)
+
+/* Minimum number of buffer neede by the device */
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE                     (V4L2_CTRL_CLASS_MPEG | 0x900)
 #define V4L2_CID_MPEG_CLASS                    (V4L2_CTRL_CLASS_MPEG | 1)
 
-/*  MPEG streams */
+/*  MPEG streams, specific to multiplexed streams */
 #define V4L2_CID_MPEG_STREAM_TYPE              (V4L2_CID_MPEG_BASE+0)
 enum v4l2_mpeg_stream_type {
        V4L2_MPEG_STREAM_TYPE_MPEG2_PS   = 0, /* MPEG-2 program stream */
@@ -1173,7 +1190,7 @@ enum v4l2_mpeg_stream_vbi_fmt {
        V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1,  /* VBI in private packets, IVTV format */
 };
 
-/*  MPEG audio */
+/*  MPEG audio controls specific to multiplexed streams  */
 #define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ      (V4L2_CID_MPEG_BASE+100)
 enum v4l2_mpeg_audio_sampling_freq {
        V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
@@ -1289,7 +1306,7 @@ enum v4l2_mpeg_audio_ac3_bitrate {
        V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18,
 };
 
-/*  MPEG video */
+/*  MPEG video controls specific to multiplexed streams */
 #define V4L2_CID_MPEG_VIDEO_ENCODING           (V4L2_CID_MPEG_BASE+200)
 enum v4l2_mpeg_video_encoding {
        V4L2_MPEG_VIDEO_ENCODING_MPEG_1     = 0,
@@ -1317,6 +1334,141 @@ enum v4l2_mpeg_video_bitrate_mode {
 #define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
 #define V4L2_CID_MPEG_VIDEO_MUTE               (V4L2_CID_MPEG_BASE+210)
 #define V4L2_CID_MPEG_VIDEO_MUTE_YUV           (V4L2_CID_MPEG_BASE+211)
+#define V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE            (V4L2_CID_MPEG_BASE+212)
+#define V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER       (V4L2_CID_MPEG_BASE+213)
+#define V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB            (V4L2_CID_MPEG_BASE+214)
+#define V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE                    (V4L2_CID_MPEG_BASE+215)
+#define V4L2_CID_MPEG_VIDEO_HEADER_MODE                                (V4L2_CID_MPEG_BASE+216)
+enum v4l2_mpeg_video_header_mode {
+       V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE                    = 0,
+       V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME       = 1,
+
+};
+#define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC                        (V4L2_CID_MPEG_BASE+217)
+#define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE               (V4L2_CID_MPEG_BASE+218)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES      (V4L2_CID_MPEG_BASE+219)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB         (V4L2_CID_MPEG_BASE+220)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE           (V4L2_CID_MPEG_BASE+221)
+enum v4l2_mpeg_video_multi_slice_mode {
+       V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE         = 0,
+       V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB          = 1,
+       V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES       = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_VBV_SIZE                   (V4L2_CID_MPEG_BASE+222)
+#define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP            (V4L2_CID_MPEG_BASE+300)
+#define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP            (V4L2_CID_MPEG_BASE+301)
+#define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP            (V4L2_CID_MPEG_BASE+302)
+#define V4L2_CID_MPEG_VIDEO_H263_MIN_QP                        (V4L2_CID_MPEG_BASE+303)
+#define V4L2_CID_MPEG_VIDEO_H263_MAX_QP                        (V4L2_CID_MPEG_BASE+304)
+#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP            (V4L2_CID_MPEG_BASE+350)
+#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP            (V4L2_CID_MPEG_BASE+351)
+#define V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP            (V4L2_CID_MPEG_BASE+352)
+#define V4L2_CID_MPEG_VIDEO_H264_MIN_QP                        (V4L2_CID_MPEG_BASE+353)
+#define V4L2_CID_MPEG_VIDEO_H264_MAX_QP                        (V4L2_CID_MPEG_BASE+354)
+#define V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM         (V4L2_CID_MPEG_BASE+355)
+#define V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE              (V4L2_CID_MPEG_BASE+356)
+#define V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE          (V4L2_CID_MPEG_BASE+357)
+enum v4l2_mpeg_video_h264_entropy_mode {
+       V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC = 0,
+       V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_I_PERIOD              (V4L2_CID_MPEG_BASE+358)
+#define V4L2_CID_MPEG_VIDEO_H264_LEVEL                 (V4L2_CID_MPEG_BASE+359)
+enum v4l2_mpeg_video_h264_level {
+       V4L2_MPEG_VIDEO_H264_LEVEL_1_0  = 0,
+       V4L2_MPEG_VIDEO_H264_LEVEL_1B   = 1,
+       V4L2_MPEG_VIDEO_H264_LEVEL_1_1  = 2,
+       V4L2_MPEG_VIDEO_H264_LEVEL_1_2  = 3,
+       V4L2_MPEG_VIDEO_H264_LEVEL_1_3  = 4,
+       V4L2_MPEG_VIDEO_H264_LEVEL_2_0  = 5,
+       V4L2_MPEG_VIDEO_H264_LEVEL_2_1  = 6,
+       V4L2_MPEG_VIDEO_H264_LEVEL_2_2  = 7,
+       V4L2_MPEG_VIDEO_H264_LEVEL_3_0  = 8,
+       V4L2_MPEG_VIDEO_H264_LEVEL_3_1  = 9,
+       V4L2_MPEG_VIDEO_H264_LEVEL_3_2  = 10,
+       V4L2_MPEG_VIDEO_H264_LEVEL_4_0  = 11,
+       V4L2_MPEG_VIDEO_H264_LEVEL_4_1  = 12,
+       V4L2_MPEG_VIDEO_H264_LEVEL_4_2  = 13,
+       V4L2_MPEG_VIDEO_H264_LEVEL_5_0  = 14,
+       V4L2_MPEG_VIDEO_H264_LEVEL_5_1  = 15,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA     (V4L2_CID_MPEG_BASE+360)
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA      (V4L2_CID_MPEG_BASE+361)
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE      (V4L2_CID_MPEG_BASE+362)
+enum v4l2_mpeg_video_h264_loop_filter_mode {
+       V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED                           = 0,
+       V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED                          = 1,
+       V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY        = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_PROFILE               (V4L2_CID_MPEG_BASE+363)
+enum v4l2_mpeg_video_h264_profile {
+       V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE                   = 0,
+       V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE       = 1,
+       V4L2_MPEG_VIDEO_H264_PROFILE_MAIN                       = 2,
+       V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED                   = 3,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH                       = 4,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10                    = 5,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422                   = 6,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE        = 7,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA              = 8,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA             = 9,
+       V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA             = 10,
+       V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA            = 11,
+       V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE          = 12,
+       V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH              = 13,
+       V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA        = 14,
+       V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH                = 15,
+       V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH             = 16,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT    (V4L2_CID_MPEG_BASE+364)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH     (V4L2_CID_MPEG_BASE+365)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE                (V4L2_CID_MPEG_BASE+366)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC           (V4L2_CID_MPEG_BASE+367)
+enum v4l2_mpeg_video_h264_vui_sar_idc {
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED    = 0,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1            = 1,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11          = 2,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11          = 3,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11          = 4,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33          = 5,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11          = 6,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11          = 7,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11          = 8,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33          = 9,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11          = 10,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11          = 11,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33          = 12,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99         = 13,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3            = 14,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2            = 15,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1            = 16,
+       V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED       = 17,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP   (V4L2_CID_MPEG_BASE+400)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP   (V4L2_CID_MPEG_BASE+401)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP   (V4L2_CID_MPEG_BASE+402)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP       (V4L2_CID_MPEG_BASE+403)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP       (V4L2_CID_MPEG_BASE+404)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL                (V4L2_CID_MPEG_BASE+405)
+enum v4l2_mpeg_video_mpeg4_level {
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_0   = 0,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B  = 1,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_1   = 2,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_2   = 3,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_3   = 4,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B  = 5,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_4   = 6,
+       V4L2_MPEG_VIDEO_MPEG4_LEVEL_5   = 7,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE      (V4L2_CID_MPEG_BASE+406)
+enum v4l2_mpeg_video_mpeg4_profile {
+       V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE                            = 0,
+       V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE                   = 1,
+       V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE                              = 2,
+       V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE                   = 3,
+       V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY        = 4,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL         (V4L2_CID_MPEG_BASE+407)
 
 /*  MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
 #define V4L2_CID_MPEG_CX2341X_BASE                             (V4L2_CTRL_CLASS_MPEG | 0x1000)
@@ -1359,6 +1511,33 @@ enum v4l2_mpeg_cx2341x_video_median_filter_type {
 #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP   (V4L2_CID_MPEG_CX2341X_BASE+10)
 #define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS        (V4L2_CID_MPEG_CX2341X_BASE+11)
 
+/*  MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */
+#define V4L2_CID_MPEG_MFC51_BASE                               (V4L2_CTRL_CLASS_MPEG | 0x1100)
+
+#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY           (V4L2_CID_MPEG_MFC51_BASE+0)
+#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE    (V4L2_CID_MPEG_MFC51_BASE+1)
+#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE                      (V4L2_CID_MPEG_MFC51_BASE+2)
+enum v4l2_mpeg_mfc51_video_frame_skip_mode {
+       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED          = 0,
+       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT       = 1,
+       V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT         = 2,
+};
+#define V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE                     (V4L2_CID_MPEG_MFC51_BASE+3)
+enum v4l2_mpeg_mfc51_video_force_frame_type {
+       V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED         = 0,
+       V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME          = 1,
+       V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED        = 2,
+};
+#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING                              (V4L2_CID_MPEG_MFC51_BASE+4)
+#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV                          (V4L2_CID_MPEG_MFC51_BASE+5)
+#define V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT                  (V4L2_CID_MPEG_MFC51_BASE+6)
+#define V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF                    (V4L2_CID_MPEG_MFC51_BASE+7)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY            (V4L2_CID_MPEG_MFC51_BASE+50)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK                        (V4L2_CID_MPEG_MFC51_BASE+51)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH              (V4L2_CID_MPEG_MFC51_BASE+52)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC              (V4L2_CID_MPEG_MFC51_BASE+53)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P               (V4L2_CID_MPEG_MFC51_BASE+54)
+
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE     (V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS          (V4L2_CTRL_CLASS_CAMERA | 1)
@@ -1427,6 +1606,41 @@ enum v4l2_preemphasis {
 #define V4L2_CID_TUNE_POWER_LEVEL              (V4L2_CID_FM_TX_CLASS_BASE + 113)
 #define V4L2_CID_TUNE_ANTENNA_CAPACITOR                (V4L2_CID_FM_TX_CLASS_BASE + 114)
 
+/* Flash and privacy (indicator) light controls */
+#define V4L2_CID_FLASH_CLASS_BASE              (V4L2_CTRL_CLASS_FLASH | 0x900)
+#define V4L2_CID_FLASH_CLASS                   (V4L2_CTRL_CLASS_FLASH | 1)
+
+#define V4L2_CID_FLASH_LED_MODE                        (V4L2_CID_FLASH_CLASS_BASE + 1)
+enum v4l2_flash_led_mode {
+       V4L2_FLASH_LED_MODE_NONE,
+       V4L2_FLASH_LED_MODE_FLASH,
+       V4L2_FLASH_LED_MODE_TORCH,
+};
+
+#define V4L2_CID_FLASH_STROBE_SOURCE           (V4L2_CID_FLASH_CLASS_BASE + 2)
+enum v4l2_flash_strobe_source {
+       V4L2_FLASH_STROBE_SOURCE_SOFTWARE,
+       V4L2_FLASH_STROBE_SOURCE_EXTERNAL,
+};
+
+#define V4L2_CID_FLASH_STROBE                  (V4L2_CID_FLASH_CLASS_BASE + 3)
+#define V4L2_CID_FLASH_STROBE_STOP             (V4L2_CID_FLASH_CLASS_BASE + 4)
+#define V4L2_CID_FLASH_STROBE_STATUS           (V4L2_CID_FLASH_CLASS_BASE + 5)
+
+#define V4L2_CID_FLASH_TIMEOUT                 (V4L2_CID_FLASH_CLASS_BASE + 6)
+#define V4L2_CID_FLASH_INTENSITY               (V4L2_CID_FLASH_CLASS_BASE + 7)
+#define V4L2_CID_FLASH_TORCH_INTENSITY         (V4L2_CID_FLASH_CLASS_BASE + 8)
+#define V4L2_CID_FLASH_INDICATOR_INTENSITY     (V4L2_CID_FLASH_CLASS_BASE + 9)
+
+#define V4L2_CID_FLASH_FAULT                   (V4L2_CID_FLASH_CLASS_BASE + 10)
+#define V4L2_FLASH_FAULT_OVER_VOLTAGE          (1 << 0)
+#define V4L2_FLASH_FAULT_TIMEOUT               (1 << 1)
+#define V4L2_FLASH_FAULT_OVER_TEMPERATURE      (1 << 2)
+#define V4L2_FLASH_FAULT_SHORT_CIRCUIT         (1 << 3)
+
+#define V4L2_CID_FLASH_CHARGE                  (V4L2_CID_FLASH_CLASS_BASE + 11)
+#define V4L2_CID_FLASH_READY                   (V4L2_CID_FLASH_CLASS_BASE + 12)
+
 /*
  *     T U N I N G
  */
@@ -1791,6 +2005,7 @@ struct v4l2_streamparm {
 #define V4L2_EVENT_ALL                         0
 #define V4L2_EVENT_VSYNC                       1
 #define V4L2_EVENT_EOS                         2
+#define V4L2_EVENT_CTRL                                3
 #define V4L2_EVENT_PRIVATE_START               0x08000000
 
 /* Payload for V4L2_EVENT_VSYNC */
@@ -1799,21 +2014,46 @@ struct v4l2_event_vsync {
        __u8 field;
 } __attribute__ ((packed));
 
+/* Payload for V4L2_EVENT_CTRL */
+#define V4L2_EVENT_CTRL_CH_VALUE               (1 << 0)
+#define V4L2_EVENT_CTRL_CH_FLAGS               (1 << 1)
+
+struct v4l2_event_ctrl {
+       __u32 changes;
+       __u32 type;
+       union {
+               __s32 value;
+               __s64 value64;
+       };
+       __u32 flags;
+       __s32 minimum;
+       __s32 maximum;
+       __s32 step;
+       __s32 default_value;
+};
+
 struct v4l2_event {
        __u32                           type;
        union {
                struct v4l2_event_vsync vsync;
+               struct v4l2_event_ctrl  ctrl;
                __u8                    data[64];
        } u;
        __u32                           pending;
        __u32                           sequence;
        struct timespec                 timestamp;
-       __u32                           reserved[9];
+       __u32                           id;
+       __u32                           reserved[8];
 };
 
+#define V4L2_EVENT_SUB_FL_SEND_INITIAL         (1 << 0)
+#define V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK       (1 << 1)
+
 struct v4l2_event_subscription {
        __u32                           type;
-       __u32                           reserved[7];
+       __u32                           id;
+       __u32                           flags;
+       __u32                           reserved[5];
 };
 
 /*
index 011bcfeb9f090a7a49dbf54c4819d3306160c852..111843f88b2a97dc87434631335ab95b6e786b45 100644 (file)
@@ -59,6 +59,84 @@ struct watchdog_info {
 #define WATCHDOG_NOWAYOUT      0
 #endif
 
+struct watchdog_ops;
+struct watchdog_device;
+
+/** struct watchdog_ops - The watchdog-devices operations
+ *
+ * @owner:     The module owner.
+ * @start:     The routine for starting the watchdog device.
+ * @stop:      The routine for stopping the watchdog device.
+ * @ping:      The routine that sends a keepalive ping to the watchdog device.
+ * @status:    The routine that shows the status of the watchdog device.
+ * @set_timeout:The routine for setting the watchdog devices timeout value.
+ * @ioctl:     The routines that handles extra ioctl calls.
+ *
+ * The watchdog_ops structure contains a list of low-level operations
+ * that control a watchdog device. It also contains the module that owns
+ * these operations. The start and stop function are mandatory, all other
+ * functions are optonal.
+ */
+struct watchdog_ops {
+       struct module *owner;
+       /* mandatory operations */
+       int (*start)(struct watchdog_device *);
+       int (*stop)(struct watchdog_device *);
+       /* optional operations */
+       int (*ping)(struct watchdog_device *);
+       unsigned int (*status)(struct watchdog_device *);
+       int (*set_timeout)(struct watchdog_device *, unsigned int);
+       long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
+};
+
+/** struct watchdog_device - The structure that defines a watchdog device
+ *
+ * @info:      Pointer to a watchdog_info structure.
+ * @ops:       Pointer to the list of watchdog operations.
+ * @bootstatus:        Status of the watchdog device at boot.
+ * @timeout:   The watchdog devices timeout value.
+ * @min_timeout:The watchdog devices minimum timeout value.
+ * @max_timeout:The watchdog devices maximum timeout value.
+ * @driver-data:Pointer to the drivers private data.
+ * @status:    Field that contains the devices internal status bits.
+ *
+ * The watchdog_device structure contains all information about a
+ * watchdog timer device.
+ *
+ * The driver-data field may not be accessed directly. It must be accessed
+ * via the watchdog_set_drvdata and watchdog_get_drvdata helpers.
+ */
+struct watchdog_device {
+       const struct watchdog_info *info;
+       const struct watchdog_ops *ops;
+       unsigned int bootstatus;
+       unsigned int timeout;
+       unsigned int min_timeout;
+       unsigned int max_timeout;
+       void *driver_data;
+       unsigned long status;
+/* Bit numbers for status flags */
+#define WDOG_ACTIVE            0       /* Is the watchdog running/active */
+#define WDOG_DEV_OPEN          1       /* Opened via /dev/watchdog ? */
+#define WDOG_ALLOW_RELEASE     2       /* Did we receive the magic char ? */
+#define WDOG_NO_WAY_OUT                3       /* Is 'nowayout' feature set ? */
+};
+
+/* Use the following functions to manipulate watchdog driver specific data */
+static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data)
+{
+       wdd->driver_data = data;
+}
+
+static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
+{
+       return wdd->driver_data;
+}
+
+/* drivers/watchdog/core/watchdog_core.c */
+extern int watchdog_register_device(struct watchdog_device *);
+extern void watchdog_unregister_device(struct watchdog_device *);
+
 #endif /* __KERNEL__ */
 
 #endif  /* ifndef _LINUX_WATCHDOG_H */
index 38e8c4d9289e6a3aff5eb5fb975e1b4cd29597db..fd98bb968219f19724b84d19202888b6e564d26d 100644 (file)
 #define WM97XX_ADCSEL_X                0x1000  /* x coord measurement */
 #define WM97XX_ADCSEL_Y                0x2000  /* y coord measurement */
 #define WM97XX_ADCSEL_PRES     0x3000  /* pressure measurement */
-#define WM97XX_ADCSEL_MASK     0x7000
+#define WM97XX_AUX_ID1         0x4000
+#define WM97XX_AUX_ID2         0x5000
+#define WM97XX_AUX_ID3         0x6000
+#define WM97XX_AUX_ID4         0x7000
+#define WM97XX_ADCSEL_MASK     0x7000  /* ADC selection mask */
 #define WM97XX_COO             0x0800  /* enable coordinate mode */
 #define WM97XX_CTC             0x0400  /* enable continuous mode */
 #define WM97XX_CM_RATE_93      0x0000  /* 93.75Hz continuous rate */
 #define WM97XX_PRP_DET_DIG     0xc000  /* setect on, digitise on */
 #define WM97XX_RPR             0x2000  /* wake up on pen down */
 #define WM97XX_PEN_DOWN                0x8000  /* pen is down */
-#define WM97XX_ADCSRC_MASK     0x7000  /* ADC source mask */
-
-#define WM97XX_AUX_ID1         0x8001
-#define WM97XX_AUX_ID2         0x8002
-#define WM97XX_AUX_ID3         0x8003
-#define WM97XX_AUX_ID4         0x8004
-
 
 /* WM9712 Bits */
 #define WM9712_45W             0x1000  /* set for 5-wire touchscreen */
diff --git a/include/media/adp1653.h b/include/media/adp1653.h
new file mode 100644 (file)
index 0000000..50a1af8
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * include/media/adp1653.h
+ *
+ * Copyright (C) 2008--2011 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Contributors:
+ *     Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *     Tuukka Toivonen <tuukkat76@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.
+ *
+ * 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
+ *
+ */
+
+#ifndef ADP1653_H
+#define ADP1653_H
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#define ADP1653_NAME                           "adp1653"
+#define ADP1653_I2C_ADDR                       (0x60 >> 1)
+
+/* Register definitions */
+#define ADP1653_REG_OUT_SEL                    0x00
+#define ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN    0x01
+#define ADP1653_REG_OUT_SEL_HPLED_TORCH_MAX    0x0b
+#define ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN    0x0c
+#define ADP1653_REG_OUT_SEL_HPLED_FLASH_MAX    0x1f
+#define ADP1653_REG_OUT_SEL_HPLED_SHIFT                3
+#define ADP1653_REG_OUT_SEL_ILED_MAX           0x07
+#define ADP1653_REG_OUT_SEL_ILED_SHIFT         0
+
+#define ADP1653_REG_CONFIG                     0x01
+#define ADP1653_REG_CONFIG_TMR_CFG             (1 << 4)
+#define ADP1653_REG_CONFIG_TMR_SET_MAX         0x0f
+#define ADP1653_REG_CONFIG_TMR_SET_SHIFT       0
+
+#define ADP1653_REG_SW_STROBE                  0x02
+#define ADP1653_REG_SW_STROBE_SW_STROBE                (1 << 0)
+
+#define ADP1653_REG_FAULT                      0x03
+#define ADP1653_REG_FAULT_FLT_SCP              (1 << 3)
+#define ADP1653_REG_FAULT_FLT_OT               (1 << 2)
+#define ADP1653_REG_FAULT_FLT_TMR              (1 << 1)
+#define ADP1653_REG_FAULT_FLT_OV               (1 << 0)
+
+#define ADP1653_INDICATOR_INTENSITY_MIN                0
+#define ADP1653_INDICATOR_INTENSITY_STEP       2500
+#define ADP1653_INDICATOR_INTENSITY_MAX                \
+       (ADP1653_REG_OUT_SEL_ILED_MAX * ADP1653_INDICATOR_INTENSITY_STEP)
+#define ADP1653_INDICATOR_INTENSITY_uA_TO_REG(a) \
+       ((a) / ADP1653_INDICATOR_INTENSITY_STEP)
+#define ADP1653_INDICATOR_INTENSITY_REG_TO_uA(a) \
+       ((a) * ADP1653_INDICATOR_INTENSITY_STEP)
+
+#define ADP1653_FLASH_INTENSITY_BASE           35
+#define ADP1653_FLASH_INTENSITY_STEP           15
+#define ADP1653_FLASH_INTENSITY_MIN                                    \
+       (ADP1653_FLASH_INTENSITY_BASE                                   \
+        + ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN * ADP1653_FLASH_INTENSITY_STEP)
+#define ADP1653_FLASH_INTENSITY_MAX                    \
+       (ADP1653_FLASH_INTENSITY_MIN +                  \
+        (ADP1653_REG_OUT_SEL_HPLED_FLASH_MAX -         \
+         ADP1653_REG_OUT_SEL_HPLED_FLASH_MIN + 1) *    \
+        ADP1653_FLASH_INTENSITY_STEP)
+
+#define ADP1653_FLASH_INTENSITY_mA_TO_REG(a)                           \
+       ((a) < ADP1653_FLASH_INTENSITY_BASE ? 0 :                       \
+        (((a) - ADP1653_FLASH_INTENSITY_BASE) / ADP1653_FLASH_INTENSITY_STEP))
+#define ADP1653_FLASH_INTENSITY_REG_TO_mA(a)           \
+       ((a) * ADP1653_FLASH_INTENSITY_STEP + ADP1653_FLASH_INTENSITY_BASE)
+
+#define ADP1653_TORCH_INTENSITY_MIN                                    \
+       (ADP1653_FLASH_INTENSITY_BASE                                   \
+        + ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN * ADP1653_FLASH_INTENSITY_STEP)
+#define ADP1653_TORCH_INTENSITY_MAX                    \
+       (ADP1653_TORCH_INTENSITY_MIN +                  \
+        (ADP1653_REG_OUT_SEL_HPLED_TORCH_MAX -         \
+         ADP1653_REG_OUT_SEL_HPLED_TORCH_MIN + 1) *    \
+        ADP1653_FLASH_INTENSITY_STEP)
+
+struct adp1653_platform_data {
+       int (*power)(struct v4l2_subdev *sd, int on);
+
+       u32 max_flash_timeout;          /* flash light timeout in us */
+       u32 max_flash_intensity;        /* led intensity, flash mode */
+       u32 max_torch_intensity;        /* led intensity, torch mode */
+       u32 max_indicator_intensity;    /* indicator led intensity */
+};
+
+#define to_adp1653_flash(sd)   container_of(sd, struct adp1653_flash, subdev)
+
+struct adp1653_flash {
+       struct v4l2_subdev subdev;
+       struct adp1653_platform_data *platform_data;
+
+       struct v4l2_ctrl_handler ctrls;
+       struct v4l2_ctrl *led_mode;
+       struct v4l2_ctrl *flash_timeout;
+       struct v4l2_ctrl *flash_intensity;
+       struct v4l2_ctrl *torch_intensity;
+       struct v4l2_ctrl *indicator_intensity;
+
+       struct mutex power_lock;
+       int power_count;
+       int fault;
+};
+
+#endif /* ADP1653_H */
diff --git a/include/media/atmel-isi.h b/include/media/atmel-isi.h
new file mode 100644 (file)
index 0000000..26cece5
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Register definitions for the Atmel Image Sensor Interface.
+ *
+ * Copyright (C) 2011 Atmel Corporation
+ * Josh Wu, <josh.wu@atmel.com>
+ *
+ * Based on previous work by Lars Haring, <lars.haring@atmel.com>
+ * and Sedji Gaouaou
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ATMEL_ISI_H__
+#define __ATMEL_ISI_H__
+
+#include <linux/types.h>
+
+/* ISI_V2 register offsets */
+#define ISI_CFG1                               0x0000
+#define ISI_CFG2                               0x0004
+#define ISI_PSIZE                              0x0008
+#define ISI_PDECF                              0x000c
+#define ISI_Y2R_SET0                           0x0010
+#define ISI_Y2R_SET1                           0x0014
+#define ISI_R2Y_SET0                           0x0018
+#define ISI_R2Y_SET1                           0x001C
+#define ISI_R2Y_SET2                           0x0020
+#define ISI_CTRL                               0x0024
+#define ISI_STATUS                             0x0028
+#define ISI_INTEN                              0x002C
+#define ISI_INTDIS                             0x0030
+#define ISI_INTMASK                            0x0034
+#define ISI_DMA_CHER                           0x0038
+#define ISI_DMA_CHDR                           0x003C
+#define ISI_DMA_CHSR                           0x0040
+#define ISI_DMA_P_ADDR                         0x0044
+#define ISI_DMA_P_CTRL                         0x0048
+#define ISI_DMA_P_DSCR                         0x004C
+#define ISI_DMA_C_ADDR                         0x0050
+#define ISI_DMA_C_CTRL                         0x0054
+#define ISI_DMA_C_DSCR                         0x0058
+
+/* Bitfields in CFG1 */
+#define ISI_CFG1_HSYNC_POL_ACTIVE_LOW          (1 << 2)
+#define ISI_CFG1_VSYNC_POL_ACTIVE_LOW          (1 << 3)
+#define ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING     (1 << 4)
+#define ISI_CFG1_EMB_SYNC                      (1 << 6)
+#define ISI_CFG1_CRC_SYNC                      (1 << 7)
+/* Constants for FRATE(ISI_V2) */
+#define                ISI_CFG1_FRATE_CAPTURE_ALL      (0 << 8)
+#define                ISI_CFG1_FRATE_DIV_2            (1 << 8)
+#define                ISI_CFG1_FRATE_DIV_3            (2 << 8)
+#define                ISI_CFG1_FRATE_DIV_4            (3 << 8)
+#define                ISI_CFG1_FRATE_DIV_5            (4 << 8)
+#define                ISI_CFG1_FRATE_DIV_6            (5 << 8)
+#define                ISI_CFG1_FRATE_DIV_7            (6 << 8)
+#define                ISI_CFG1_FRATE_DIV_8            (7 << 8)
+#define ISI_CFG1_DISCR                         (1 << 11)
+#define ISI_CFG1_FULL_MODE                     (1 << 12)
+
+/* Bitfields in CFG2 */
+#define ISI_CFG2_GRAYSCALE                     (1 << 13)
+/* Constants for YCC_SWAP(ISI_V2) */
+#define                ISI_CFG2_YCC_SWAP_DEFAULT       (0 << 28)
+#define                ISI_CFG2_YCC_SWAP_MODE_1        (1 << 28)
+#define                ISI_CFG2_YCC_SWAP_MODE_2        (2 << 28)
+#define                ISI_CFG2_YCC_SWAP_MODE_3        (3 << 28)
+#define ISI_CFG2_IM_VSIZE_OFFSET               0
+#define ISI_CFG2_IM_HSIZE_OFFSET               16
+#define ISI_CFG2_IM_VSIZE_MASK         (0x7FF << ISI_CFG2_IM_VSIZE_OFFSET)
+#define ISI_CFG2_IM_HSIZE_MASK         (0x7FF << ISI_CFG2_IM_HSIZE_OFFSET)
+
+/* Bitfields in CTRL */
+/* Also using in SR(ISI_V2) */
+#define ISI_CTRL_EN                            (1 << 0)
+#define ISI_CTRL_CDC                           (1 << 8)
+/* Also using in SR/IER/IDR/IMR(ISI_V2) */
+#define ISI_CTRL_DIS                           (1 << 1)
+#define ISI_CTRL_SRST                          (1 << 2)
+
+/* Bitfields in SR */
+#define ISI_SR_SIP                             (1 << 19)
+/* Also using in SR/IER/IDR/IMR */
+#define ISI_SR_VSYNC                           (1 << 10)
+#define ISI_SR_PXFR_DONE                       (1 << 16)
+#define ISI_SR_CXFR_DONE                       (1 << 17)
+#define ISI_SR_P_OVR                           (1 << 24)
+#define ISI_SR_C_OVR                           (1 << 25)
+#define ISI_SR_CRC_ERR                         (1 << 26)
+#define ISI_SR_FR_OVR                          (1 << 27)
+
+/* Bitfields in DMA_C_CTRL & in DMA_P_CTRL */
+#define ISI_DMA_CTRL_FETCH                     (1 << 0)
+#define ISI_DMA_CTRL_WB                                (1 << 1)
+#define ISI_DMA_CTRL_IEN                       (1 << 2)
+#define ISI_DMA_CTRL_DONE                      (1 << 3)
+
+/* Bitfields in DMA_CHSR/CHER/CHDR */
+#define ISI_DMA_CHSR_P_CH                      (1 << 0)
+#define ISI_DMA_CHSR_C_CH                      (1 << 1)
+
+/* Definition for isi_platform_data */
+#define ISI_DATAWIDTH_8                                0x01
+#define ISI_DATAWIDTH_10                       0x02
+
+struct isi_platform_data {
+       u8 has_emb_sync;
+       u8 emb_crc_sync;
+       u8 hsync_act_low;
+       u8 vsync_act_low;
+       u8 pclk_act_falling;
+       u8 isi_full_mode;
+       u32 data_width_flags;
+       /* Using for ISI_CFG1 */
+       u32 frate;
+};
+
+#endif /* __ATMEL_ISI_H__ */
diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h
new file mode 100644 (file)
index 0000000..8b11fb0
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2010 Texas Instruments 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_H
+#define _VPBE_H
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/davinci/vpbe_osd.h>
+#include <media/davinci/vpbe_venc.h>
+#include <media/davinci/vpbe_types.h>
+
+/* OSD configuration info */
+struct osd_config_info {
+       char module_name[32];
+};
+
+struct vpbe_output {
+       struct v4l2_output output;
+       /*
+        * If output capabilities include dv_preset, list supported presets
+        * below
+        */
+       char *subdev_name;
+       /*
+        * defualt_mode identifies the default timings set at the venc or
+        * external encoder.
+        */
+       char *default_mode;
+       /*
+        * Fields below are used for supporting multiple modes. For example,
+        * LCD panel might support different modes and they are listed here.
+        * Similarly for supporting external encoders, lcd controller port
+        * requires a set of non-standard timing values to be listed here for
+        * each supported mode since venc is used in non-standard timing mode
+        * for interfacing with external encoder similar to configuring lcd
+        * panel timings
+        */
+       unsigned int num_modes;
+       struct vpbe_enc_mode_info *modes;
+       /*
+        * Bus configuration goes here for external encoders. Some encoders
+        * may require multiple interface types for each of the output. For
+        * example, SD modes would use YCC8 where as HD mode would use YCC16.
+        * Not sure if this is needed on a per mode basis instead of per
+        * output basis. If per mode is needed, we may have to move this to
+        * mode_info structure
+        */
+};
+
+/* encoder configuration info */
+struct encoder_config_info {
+       char module_name[32];
+       /* Is this an i2c device ? */
+       unsigned int is_i2c:1;
+       /* i2c subdevice board info */
+       struct i2c_board_info board_info;
+};
+
+/* structure for defining vpbe display subsystem components */
+struct vpbe_config {
+       char module_name[32];
+       /* i2c bus adapter no */
+       int i2c_adapter_id;
+       struct osd_config_info osd;
+       struct encoder_config_info venc;
+       /* external encoder information goes here */
+       int num_ext_encoders;
+       struct encoder_config_info *ext_encoders;
+       int num_outputs;
+       /* Order is venc outputs followed by LCD and then external encoders */
+       struct vpbe_output *outputs;
+};
+
+struct vpbe_device;
+
+struct vpbe_device_ops {
+       /* crop cap for the display */
+       int (*g_cropcap)(struct vpbe_device *vpbe_dev,
+                        struct v4l2_cropcap *cropcap);
+
+       /* Enumerate the outputs */
+       int (*enum_outputs)(struct vpbe_device *vpbe_dev,
+                           struct v4l2_output *output);
+
+       /* Set output to the given index */
+       int (*set_output)(struct vpbe_device *vpbe_dev,
+                        int index);
+
+       /* Get current output */
+       unsigned int (*get_output)(struct vpbe_device *vpbe_dev);
+
+       /* Set DV preset at current output */
+       int (*s_dv_preset)(struct vpbe_device *vpbe_dev,
+                          struct v4l2_dv_preset *dv_preset);
+
+       /* Get DV presets supported at the output */
+       int (*g_dv_preset)(struct vpbe_device *vpbe_dev,
+                          struct v4l2_dv_preset *dv_preset);
+
+       /* Enumerate the DV Presets supported at the output */
+       int (*enum_dv_presets)(struct vpbe_device *vpbe_dev,
+                              struct v4l2_dv_enum_preset *preset_info);
+
+       /* Set std at the output */
+       int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id);
+
+       /* Get the current std at the output */
+       int (*g_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id);
+
+       /* initialize the device */
+       int (*initialize)(struct device *dev, struct vpbe_device *vpbe_dev);
+
+       /* De-initialize the device */
+       void (*deinitialize)(struct device *dev, struct vpbe_device *vpbe_dev);
+
+       /* Get the current mode info */
+       int (*get_mode_info)(struct vpbe_device *vpbe_dev,
+                            struct vpbe_enc_mode_info*);
+
+       /*
+        * Set the current mode in the encoder. Alternate way of setting
+        * standard or DV preset or custom timings in the encoder
+        */
+       int (*set_mode)(struct vpbe_device *vpbe_dev,
+                       struct vpbe_enc_mode_info*);
+       /* Power management operations */
+       int (*suspend)(struct vpbe_device *vpbe_dev);
+       int (*resume)(struct vpbe_device *vpbe_dev);
+};
+
+/* struct for vpbe device */
+struct vpbe_device {
+       /* V4l2 device */
+       struct v4l2_device v4l2_dev;
+       /* vpbe dispay controller cfg */
+       struct vpbe_config *cfg;
+       /* parent device */
+       struct device *pdev;
+       /* external encoder v4l2 sub devices */
+       struct v4l2_subdev **encoders;
+       /* current encoder index */
+       int current_sd_index;
+       struct mutex lock;
+       /* device initialized */
+       int initialized;
+       /* vpbe dac clock */
+       struct clk *dac_clk;
+       /* osd_device pointer */
+       struct osd_state *osd_device;
+       /*
+        * fields below are accessed by users of vpbe_device. Not the
+        * ones above
+        */
+
+       /* current output */
+       int current_out_index;
+       /* lock used by caller to do atomic operation on vpbe device */
+       /* current timings set in the controller */
+       struct vpbe_enc_mode_info current_timings;
+       /* venc sub device */
+       struct v4l2_subdev *venc;
+       /* device operations below */
+       struct vpbe_device_ops ops;
+};
+
+#endif
diff --git a/include/media/davinci/vpbe_display.h b/include/media/davinci/vpbe_display.h
new file mode 100644 (file)
index 0000000..dbf6b37
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.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 program is distributed WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef VPBE_DISPLAY_H
+#define VPBE_DISPLAY_H
+
+/* Header files */
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/davinci/vpbe_types.h>
+#include <media/davinci/vpbe_osd.h>
+#include <media/davinci/vpbe.h>
+
+#define VPBE_DISPLAY_MAX_DEVICES 2
+
+enum vpbe_display_device_id {
+       VPBE_DISPLAY_DEVICE_0,
+       VPBE_DISPLAY_DEVICE_1
+};
+
+#define VPBE_DISPLAY_DRV_NAME  "vpbe-display"
+
+#define VPBE_DISPLAY_MAJOR_RELEASE              1
+#define VPBE_DISPLAY_MINOR_RELEASE              0
+#define VPBE_DISPLAY_BUILD                      1
+#define VPBE_DISPLAY_VERSION_CODE ((VPBE_DISPLAY_MAJOR_RELEASE << 16) | \
+       (VPBE_DISPLAY_MINOR_RELEASE << 8)  | \
+       VPBE_DISPLAY_BUILD)
+
+#define VPBE_DISPLAY_VALID_FIELD(field)   ((V4L2_FIELD_NONE == field) || \
+        (V4L2_FIELD_ANY == field) || (V4L2_FIELD_INTERLACED == field))
+
+/* Exp ratio numerator and denominator constants */
+#define VPBE_DISPLAY_H_EXP_RATIO_N     9
+#define VPBE_DISPLAY_H_EXP_RATIO_D     8
+#define VPBE_DISPLAY_V_EXP_RATIO_N     6
+#define VPBE_DISPLAY_V_EXP_RATIO_D     5
+
+/* Zoom multiplication factor */
+#define VPBE_DISPLAY_ZOOM_4X   4
+#define VPBE_DISPLAY_ZOOM_2X   2
+
+/* Structures */
+struct display_layer_info {
+       int enable;
+       /* Layer ID used by Display Manager */
+       enum osd_layer id;
+       struct osd_layer_config config;
+       enum osd_zoom_factor h_zoom;
+       enum osd_zoom_factor v_zoom;
+       enum osd_h_exp_ratio h_exp;
+       enum osd_v_exp_ratio v_exp;
+};
+
+/* vpbe display object structure */
+struct vpbe_layer {
+       /* number of buffers in fbuffers */
+       unsigned int numbuffers;
+       /* Pointer to the vpbe_display */
+       struct vpbe_display *disp_dev;
+       /* Pointer pointing to current v4l2_buffer */
+       struct videobuf_buffer *cur_frm;
+       /* Pointer pointing to next v4l2_buffer */
+       struct videobuf_buffer *next_frm;
+       /* videobuf specific parameters
+        * Buffer queue used in video-buf
+        */
+       struct videobuf_queue buffer_queue;
+       /* Queue of filled frames */
+       struct list_head dma_queue;
+       /* Used in video-buf */
+       spinlock_t irqlock;
+       /* V4l2 specific parameters */
+       /* Identifies video device for this layer */
+       struct video_device video_dev;
+       /* This field keeps track of type of buffer exchange mechanism user
+        * has selected
+        */
+       enum v4l2_memory memory;
+       /* Used to keep track of state of the priority */
+       struct v4l2_prio_state prio;
+       /* Used to store pixel format */
+       struct v4l2_pix_format pix_fmt;
+       enum v4l2_field buf_field;
+       /* Video layer configuration params */
+       struct display_layer_info layer_info;
+       /* vpbe specific parameters
+        * enable window for display
+        */
+       unsigned char window_enable;
+       /* number of open instances of the layer */
+       unsigned int usrs;
+       /* number of users performing IO */
+       unsigned int io_usrs;
+       /* Indicates id of the field which is being displayed */
+       unsigned int field_id;
+       /* Indicates whether streaming started */
+       unsigned char started;
+       /* Identifies device object */
+       enum vpbe_display_device_id device_id;
+       /* facilitation of ioctl ops lock by v4l2*/
+       struct mutex opslock;
+       u8 layer_first_int;
+};
+
+/* vpbe device structure */
+struct vpbe_display {
+       /* layer specific parameters */
+       /* lock for isr updates to buf layers*/
+       spinlock_t dma_queue_lock;
+       /* C-Plane offset from start of y-plane */
+       unsigned int cbcr_ofst;
+       struct vpbe_layer *dev[VPBE_DISPLAY_MAX_DEVICES];
+       struct vpbe_device *vpbe_dev;
+       struct osd_state *osd_device;
+};
+
+/* File handle structure */
+struct vpbe_fh {
+       /* vpbe device structure */
+       struct vpbe_display *disp_dev;
+       /* pointer to layer object for opened device */
+       struct vpbe_layer *layer;
+       /* Indicates whether this file handle is doing IO */
+       unsigned char io_allowed;
+       /* Used to keep track priority of this instance */
+       enum v4l2_priority prio;
+};
+
+struct buf_config_params {
+       unsigned char min_numbuffers;
+       unsigned char numbuffers[VPBE_DISPLAY_MAX_DEVICES];
+       unsigned int min_bufsize[VPBE_DISPLAY_MAX_DEVICES];
+       unsigned int layer_bufsize[VPBE_DISPLAY_MAX_DEVICES];
+};
+
+#endif /* VPBE_DISPLAY_H */
diff --git a/include/media/davinci/vpbe_osd.h b/include/media/davinci/vpbe_osd.h
new file mode 100644 (file)
index 0000000..d7e397a
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2007-2009 Texas Instruments Inc
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * Andy Lowe (alowe@mvista.com), MontaVista Software
+ * - Initial version
+ * Murali Karicheri (mkaricheri@gmail.com), Texas Instruments Ltd.
+ * - ported to sub device interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2..
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _OSD_H
+#define _OSD_H
+
+#include <media/davinci/vpbe_types.h>
+
+#define VPBE_OSD_SUBDEV_NAME "vpbe-osd"
+
+/**
+ * enum osd_layer
+ * @WIN_OSD0: On-Screen Display Window 0
+ * @WIN_VID0: Video Window 0
+ * @WIN_OSD1: On-Screen Display Window 1
+ * @WIN_VID1: Video Window 1
+ *
+ * Description:
+ * An enumeration of the osd display layers.
+ */
+enum osd_layer {
+       WIN_OSD0,
+       WIN_VID0,
+       WIN_OSD1,
+       WIN_VID1,
+};
+
+/**
+ * enum osd_win_layer
+ * @OSDWIN_OSD0: On-Screen Display Window 0
+ * @OSDWIN_OSD1: On-Screen Display Window 1
+ *
+ * Description:
+ * An enumeration of the OSD Window layers.
+ */
+enum osd_win_layer {
+       OSDWIN_OSD0,
+       OSDWIN_OSD1,
+};
+
+/**
+ * enum osd_pix_format
+ * @PIXFMT_1BPP: 1-bit-per-pixel bitmap
+ * @PIXFMT_2BPP: 2-bits-per-pixel bitmap
+ * @PIXFMT_4BPP: 4-bits-per-pixel bitmap
+ * @PIXFMT_8BPP: 8-bits-per-pixel bitmap
+ * @PIXFMT_RGB565: 16-bits-per-pixel RGB565
+ * @PIXFMT_YCbCrI: YUV 4:2:2
+ * @PIXFMT_RGB888: 24-bits-per-pixel RGB888
+ * @PIXFMT_YCrCbI: YUV 4:2:2 with chroma swap
+ * @PIXFMT_NV12: YUV 4:2:0 planar
+ * @PIXFMT_OSD_ATTR: OSD Attribute Window pixel format (4bpp)
+ *
+ * Description:
+ * An enumeration of the DaVinci pixel formats.
+ */
+enum osd_pix_format {
+       PIXFMT_1BPP = 0,
+       PIXFMT_2BPP,
+       PIXFMT_4BPP,
+       PIXFMT_8BPP,
+       PIXFMT_RGB565,
+       PIXFMT_YCbCrI,
+       PIXFMT_RGB888,
+       PIXFMT_YCrCbI,
+       PIXFMT_NV12,
+       PIXFMT_OSD_ATTR,
+};
+
+/**
+ * enum osd_h_exp_ratio
+ * @H_EXP_OFF: no expansion (1/1)
+ * @H_EXP_9_OVER_8: 9/8 expansion ratio
+ * @H_EXP_3_OVER_2: 3/2 expansion ratio
+ *
+ * Description:
+ * An enumeration of the available horizontal expansion ratios.
+ */
+enum osd_h_exp_ratio {
+       H_EXP_OFF,
+       H_EXP_9_OVER_8,
+       H_EXP_3_OVER_2,
+};
+
+/**
+ * enum osd_v_exp_ratio
+ * @V_EXP_OFF: no expansion (1/1)
+ * @V_EXP_6_OVER_5: 6/5 expansion ratio
+ *
+ * Description:
+ * An enumeration of the available vertical expansion ratios.
+ */
+enum osd_v_exp_ratio {
+       V_EXP_OFF,
+       V_EXP_6_OVER_5,
+};
+
+/**
+ * enum osd_zoom_factor
+ * @ZOOM_X1: no zoom (x1)
+ * @ZOOM_X2: x2 zoom
+ * @ZOOM_X4: x4 zoom
+ *
+ * Description:
+ * An enumeration of the available zoom factors.
+ */
+enum osd_zoom_factor {
+       ZOOM_X1,
+       ZOOM_X2,
+       ZOOM_X4,
+};
+
+/**
+ * enum osd_clut
+ * @ROM_CLUT: ROM CLUT
+ * @RAM_CLUT: RAM CLUT
+ *
+ * Description:
+ * An enumeration of the available Color Lookup Tables (CLUTs).
+ */
+enum osd_clut {
+       ROM_CLUT,
+       RAM_CLUT,
+};
+
+/**
+ * enum osd_rom_clut
+ * @ROM_CLUT0: Macintosh CLUT
+ * @ROM_CLUT1: CLUT from DM270 and prior devices
+ *
+ * Description:
+ * An enumeration of the ROM Color Lookup Table (CLUT) options.
+ */
+enum osd_rom_clut {
+       ROM_CLUT0,
+       ROM_CLUT1,
+};
+
+/**
+ * enum osd_blending_factor
+ * @OSD_0_VID_8: OSD pixels are fully transparent
+ * @OSD_1_VID_7: OSD pixels contribute 1/8, video pixels contribute 7/8
+ * @OSD_2_VID_6: OSD pixels contribute 2/8, video pixels contribute 6/8
+ * @OSD_3_VID_5: OSD pixels contribute 3/8, video pixels contribute 5/8
+ * @OSD_4_VID_4: OSD pixels contribute 4/8, video pixels contribute 4/8
+ * @OSD_5_VID_3: OSD pixels contribute 5/8, video pixels contribute 3/8
+ * @OSD_6_VID_2: OSD pixels contribute 6/8, video pixels contribute 2/8
+ * @OSD_8_VID_0: OSD pixels are fully opaque
+ *
+ * Description:
+ * An enumeration of the DaVinci pixel blending factor options.
+ */
+enum osd_blending_factor {
+       OSD_0_VID_8,
+       OSD_1_VID_7,
+       OSD_2_VID_6,
+       OSD_3_VID_5,
+       OSD_4_VID_4,
+       OSD_5_VID_3,
+       OSD_6_VID_2,
+       OSD_8_VID_0,
+};
+
+/**
+ * enum osd_blink_interval
+ * @BLINK_X1: blink interval is 1 vertical refresh cycle
+ * @BLINK_X2: blink interval is 2 vertical refresh cycles
+ * @BLINK_X3: blink interval is 3 vertical refresh cycles
+ * @BLINK_X4: blink interval is 4 vertical refresh cycles
+ *
+ * Description:
+ * An enumeration of the DaVinci pixel blinking interval options.
+ */
+enum osd_blink_interval {
+       BLINK_X1,
+       BLINK_X2,
+       BLINK_X3,
+       BLINK_X4,
+};
+
+/**
+ * enum osd_cursor_h_width
+ * @H_WIDTH_1: horizontal line width is 1 pixel
+ * @H_WIDTH_4: horizontal line width is 4 pixels
+ * @H_WIDTH_8: horizontal line width is 8 pixels
+ * @H_WIDTH_12: horizontal line width is 12 pixels
+ * @H_WIDTH_16: horizontal line width is 16 pixels
+ * @H_WIDTH_20: horizontal line width is 20 pixels
+ * @H_WIDTH_24: horizontal line width is 24 pixels
+ * @H_WIDTH_28: horizontal line width is 28 pixels
+ */
+enum osd_cursor_h_width {
+       H_WIDTH_1,
+       H_WIDTH_4,
+       H_WIDTH_8,
+       H_WIDTH_12,
+       H_WIDTH_16,
+       H_WIDTH_20,
+       H_WIDTH_24,
+       H_WIDTH_28,
+};
+
+/**
+ * enum davinci_cursor_v_width
+ * @V_WIDTH_1: vertical line width is 1 line
+ * @V_WIDTH_2: vertical line width is 2 lines
+ * @V_WIDTH_4: vertical line width is 4 lines
+ * @V_WIDTH_6: vertical line width is 6 lines
+ * @V_WIDTH_8: vertical line width is 8 lines
+ * @V_WIDTH_10: vertical line width is 10 lines
+ * @V_WIDTH_12: vertical line width is 12 lines
+ * @V_WIDTH_14: vertical line width is 14 lines
+ */
+enum osd_cursor_v_width {
+       V_WIDTH_1,
+       V_WIDTH_2,
+       V_WIDTH_4,
+       V_WIDTH_6,
+       V_WIDTH_8,
+       V_WIDTH_10,
+       V_WIDTH_12,
+       V_WIDTH_14,
+};
+
+/**
+ * struct osd_cursor_config
+ * @xsize: horizontal size in pixels
+ * @ysize: vertical size in lines
+ * @xpos: horizontal offset in pixels from the left edge of the display
+ * @ypos: vertical offset in lines from the top of the display
+ * @interlaced: Non-zero if the display is interlaced, or zero otherwise
+ * @h_width: horizontal line width
+ * @v_width: vertical line width
+ * @clut: the CLUT selector (ROM or RAM) for the cursor color
+ * @clut_index: an index into the CLUT for the cursor color
+ *
+ * Description:
+ * A structure describing the configuration parameters of the hardware
+ * rectangular cursor.
+ */
+struct osd_cursor_config {
+       unsigned xsize;
+       unsigned ysize;
+       unsigned xpos;
+       unsigned ypos;
+       int interlaced;
+       enum osd_cursor_h_width h_width;
+       enum osd_cursor_v_width v_width;
+       enum osd_clut clut;
+       unsigned char clut_index;
+};
+
+/**
+ * struct osd_layer_config
+ * @pixfmt: pixel format
+ * @line_length: offset in bytes between start of each line in memory
+ * @xsize: number of horizontal pixels displayed per line
+ * @ysize: number of lines displayed
+ * @xpos: horizontal offset in pixels from the left edge of the display
+ * @ypos: vertical offset in lines from the top of the display
+ * @interlaced: Non-zero if the display is interlaced, or zero otherwise
+ *
+ * Description:
+ * A structure describing the configuration parameters of an On-Screen Display
+ * (OSD) or video layer related to how the image is stored in memory.
+ * @line_length must be a multiple of the cache line size (32 bytes).
+ */
+struct osd_layer_config {
+       enum osd_pix_format pixfmt;
+       unsigned line_length;
+       unsigned xsize;
+       unsigned ysize;
+       unsigned xpos;
+       unsigned ypos;
+       int interlaced;
+};
+
+/* parameters that apply on a per-window (OSD or video) basis */
+struct osd_window_state {
+       int is_allocated;
+       int is_enabled;
+       unsigned long fb_base_phys;
+       enum osd_zoom_factor h_zoom;
+       enum osd_zoom_factor v_zoom;
+       struct osd_layer_config lconfig;
+};
+
+/* parameters that apply on a per-OSD-window basis */
+struct osd_osdwin_state {
+       enum osd_clut clut;
+       enum osd_blending_factor blend;
+       int colorkey_blending;
+       unsigned colorkey;
+       int rec601_attenuation;
+       /* index is pixel value */
+       unsigned char palette_map[16];
+};
+
+/* hardware rectangular cursor parameters */
+struct osd_cursor_state {
+       int is_enabled;
+       struct osd_cursor_config config;
+};
+
+struct osd_state;
+
+struct vpbe_osd_ops {
+       int (*initialize)(struct osd_state *sd);
+       int (*request_layer)(struct osd_state *sd, enum osd_layer layer);
+       void (*release_layer)(struct osd_state *sd, enum osd_layer layer);
+       int (*enable_layer)(struct osd_state *sd, enum osd_layer layer,
+                           int otherwin);
+       void (*disable_layer)(struct osd_state *sd, enum osd_layer layer);
+       int (*set_layer_config)(struct osd_state *sd, enum osd_layer layer,
+                               struct osd_layer_config *lconfig);
+       void (*get_layer_config)(struct osd_state *sd, enum osd_layer layer,
+                                struct osd_layer_config *lconfig);
+       void (*start_layer)(struct osd_state *sd, enum osd_layer layer,
+                           unsigned long fb_base_phys,
+                           unsigned long cbcr_ofst);
+       void (*set_left_margin)(struct osd_state *sd, u32 val);
+       void (*set_top_margin)(struct osd_state *sd, u32 val);
+       void (*set_interpolation_filter)(struct osd_state *sd, int filter);
+       int (*set_vid_expansion)(struct osd_state *sd,
+                                       enum osd_h_exp_ratio h_exp,
+                                       enum osd_v_exp_ratio v_exp);
+       void (*get_vid_expansion)(struct osd_state *sd,
+                                       enum osd_h_exp_ratio *h_exp,
+                                       enum osd_v_exp_ratio *v_exp);
+       void (*set_zoom)(struct osd_state *sd, enum osd_layer layer,
+                               enum osd_zoom_factor h_zoom,
+                               enum osd_zoom_factor v_zoom);
+};
+
+struct osd_state {
+       enum vpbe_version vpbe_type;
+       spinlock_t lock;
+       struct device *dev;
+       dma_addr_t osd_base_phys;
+       unsigned long osd_base;
+       unsigned long osd_size;
+       /* 1-->the isr will toggle the VID0 ping-pong buffer */
+       int pingpong;
+       int interpolation_filter;
+       int field_inversion;
+       enum osd_h_exp_ratio osd_h_exp;
+       enum osd_v_exp_ratio osd_v_exp;
+       enum osd_h_exp_ratio vid_h_exp;
+       enum osd_v_exp_ratio vid_v_exp;
+       enum osd_clut backg_clut;
+       unsigned backg_clut_index;
+       enum osd_rom_clut rom_clut;
+       int is_blinking;
+       /* attribute window blinking enabled */
+       enum osd_blink_interval blink;
+       /* YCbCrI or YCrCbI */
+       enum osd_pix_format yc_pixfmt;
+       /* columns are Y, Cb, Cr */
+       unsigned char clut_ram[256][3];
+       struct osd_cursor_state cursor;
+       /* OSD0, VID0, OSD1, VID1 */
+       struct osd_window_state win[4];
+       /* OSD0, OSD1 */
+       struct osd_osdwin_state osdwin[2];
+       /* OSD device Operations */
+       struct vpbe_osd_ops ops;
+};
+
+struct osd_platform_data {
+       enum vpbe_version vpbe_type;
+       int  field_inv_wa_enable;
+};
+
+#endif
diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h
new file mode 100644 (file)
index 0000000..727f551
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010 Texas Instruments 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_TYPES_H
+#define _VPBE_TYPES_H
+
+enum vpbe_version {
+       VPBE_VERSION_1 = 1,
+       VPBE_VERSION_2,
+       VPBE_VERSION_3,
+};
+
+/* vpbe_timing_type - Timing types used in vpbe device */
+enum vpbe_enc_timings_type {
+       VPBE_ENC_STD = 0x1,
+       VPBE_ENC_DV_PRESET = 0x2,
+       VPBE_ENC_CUSTOM_TIMINGS = 0x4,
+       /* Used when set timings through FB device interface */
+       VPBE_ENC_TIMINGS_INVALID = 0x8,
+};
+
+union vpbe_timings {
+       v4l2_std_id std_id;
+       unsigned int dv_preset;
+};
+
+/*
+ * struct vpbe_enc_mode_info
+ * @name: ptr to name string of the standard, "NTSC", "PAL" etc
+ * @std: standard or non-standard mode. 1 - standard, 0 - nonstandard
+ * @interlaced: 1 - interlaced, 0 - non interlaced/progressive
+ * @xres: x or horizontal resolution of the display
+ * @yres: y or vertical resolution of the display
+ * @fps: frame per second
+ * @left_margin: left margin of the display
+ * @right_margin: right margin of the display
+ * @upper_margin: upper margin of the display
+ * @lower_margin: lower margin of the display
+ * @hsync_len: h-sync length
+ * @vsync_len: v-sync length
+ * @flags: bit field: bit usage is documented below
+ *
+ * Description:
+ *  Structure holding timing and resolution information of a standard.
+ * Used by vpbe_device to set required non-standard timing in the
+ * venc when lcd controller output is connected to a external encoder.
+ * A table of timings is maintained in vpbe device to set this in
+ * venc when external encoder is connected to lcd controller output.
+ * Encoder may provide a g_dv_timings() API to override these values
+ * as needed.
+ *
+ *  Notes
+ *  ------
+ *  if_type should be used only by encoder manager and encoder.
+ *  flags usage
+ *     b0 (LSB) - hsync polarity, 0 - negative, 1 - positive
+ *     b1       - vsync polarity, 0 - negative, 1 - positive
+ *     b2       - field id polarity, 0 - negative, 1  - positive
+ */
+struct vpbe_enc_mode_info {
+       unsigned char *name;
+       enum vpbe_enc_timings_type timings_type;
+       union vpbe_timings timings;
+       unsigned int interlaced;
+       unsigned int xres;
+       unsigned int yres;
+       struct v4l2_fract aspect;
+       struct v4l2_fract fps;
+       unsigned int left_margin;
+       unsigned int right_margin;
+       unsigned int upper_margin;
+       unsigned int lower_margin;
+       unsigned int hsync_len;
+       unsigned int vsync_len;
+       unsigned int flags;
+};
+
+#endif
diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h
new file mode 100644 (file)
index 0000000..426c205
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Texas Instruments 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 version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _VPBE_VENC_H
+#define _VPBE_VENC_H
+
+#include <media/v4l2-subdev.h>
+#include <media/davinci/vpbe_types.h>
+
+#define VPBE_VENC_SUBDEV_NAME "vpbe-venc"
+
+/* venc events */
+#define VENC_END_OF_FRAME      BIT(0)
+#define VENC_FIRST_FIELD       BIT(1)
+#define VENC_SECOND_FIELD      BIT(2)
+
+struct venc_platform_data {
+       enum vpbe_version venc_type;
+       int (*setup_clock)(enum vpbe_enc_timings_type type,
+                          unsigned int mode);
+       /* Number of LCD outputs supported */
+       int num_lcd_outputs;
+};
+
+enum venc_ioctls {
+       VENC_GET_FLD = 1,
+};
+
+/* exported functions */
+struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev,
+               const char *venc_name);
+#endif
diff --git a/include/media/mmp-camera.h b/include/media/mmp-camera.h
new file mode 100644 (file)
index 0000000..7611963
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Information for the Marvell Armada MMP camera
+ */
+
+struct mmp_camera_platform_data {
+       struct platform_device *i2c_device;
+       int sensor_power_gpio;
+       int sensor_reset_gpio;
+};
diff --git a/include/media/ov7670.h b/include/media/ov7670.h
new file mode 100644 (file)
index 0000000..b133bc1
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * A V4L2 driver for OmniVision OV7670 cameras.
+ *
+ * Copyright 2010 One Laptop Per Child
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#ifndef __OV7670_H
+#define __OV7670_H
+
+struct ov7670_config {
+       int min_width;                  /* Filter out smaller sizes */
+       int min_height;                 /* Filter out smaller sizes */
+       int clock_speed;                /* External clock speed (MHz) */
+       bool use_smbus;                 /* Use smbus I/O instead of I2C */
+};
+
+#endif
index 60536c74c1ea2ad2b6c58a5e31928ebfcd73a9a0..b1f19b77ecd44c570f6d54c4e3018e877aa783f1 100644 (file)
@@ -117,7 +117,7 @@ struct rc_dev {
        int                             (*s_tx_carrier)(struct rc_dev *dev, u32 carrier);
        int                             (*s_tx_duty_cycle)(struct rc_dev *dev, u32 duty_cycle);
        int                             (*s_rx_carrier_range)(struct rc_dev *dev, u32 min, u32 max);
-       int                             (*tx_ir)(struct rc_dev *dev, int *txbuf, u32 n);
+       int                             (*tx_ir)(struct rc_dev *dev, unsigned *txbuf, unsigned n);
        void                            (*s_idle)(struct rc_dev *dev, bool enable);
        int                             (*s_learning_mode)(struct rc_dev *dev, int enable);
        int                             (*s_carrier_report) (struct rc_dev *dev, int enable);
index 4e1409ec2613d7b013569651d4d7137de45d3941..17c9759ae77bfbcc67241e33a9a6f1cfba8f8729 100644 (file)
 #define RC_TYPE_JVC    (1  << 3)       /* JVC protocol */
 #define RC_TYPE_SONY   (1  << 4)       /* Sony12/15/20 protocol */
 #define RC_TYPE_RC5_SZ (1  << 5)       /* RC5 variant used by Streamzap */
+#define RC_TYPE_MCE_KBD        (1  << 29)      /* RC6-ish MCE keyboard/mouse */
 #define RC_TYPE_LIRC   (1  << 30)      /* Pass raw IR to lirc userspace */
 #define RC_TYPE_OTHER  (1u << 31)
 
 #define RC_TYPE_ALL (RC_TYPE_RC5 | RC_TYPE_NEC  | RC_TYPE_RC6  | \
                     RC_TYPE_JVC | RC_TYPE_SONY | RC_TYPE_LIRC | \
-                    RC_TYPE_RC5_SZ | RC_TYPE_OTHER)
+                    RC_TYPE_RC5_SZ | RC_TYPE_MCE_KBD | RC_TYPE_OTHER)
 
 struct rc_map_table {
        u32     scancode;
index 80346a6d28a98c0ddd6354dabc09c1eb0765783e..48413b410f152863e166560af398ba3ff77c7ce5 100644 (file)
@@ -7,10 +7,18 @@
 #define SH_CEU_FLAG_VSYNC_LOW          (1 << 3) /* default High if possible */
 
 struct device;
+struct resource;
+
+struct sh_mobile_ceu_companion {
+       u32             num_resources;
+       struct resource *resource;
+       int             id;
+       void            *platform_data;
+};
 
 struct sh_mobile_ceu_info {
        unsigned long flags;
-       struct device *csi2_dev;
+       struct sh_mobile_ceu_companion *csi2;
 };
 
 #endif /* __ASM_SH_MOBILE_CEU_H__ */
index 4d2615174461263e0d692ac1728abbda44bf7875..c586c4f7f16bb261378f3850034f6f8186fa4510 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef SH_MIPI_CSI
 #define SH_MIPI_CSI
 
+#include <linux/list.h>
+
 enum sh_csi2_phy {
        SH_CSI2_PHY_MAIN,
        SH_CSI2_PHY_SUB,
@@ -33,14 +35,14 @@ struct sh_csi2_client_config {
        struct platform_device *pdev;   /* client platform device */
 };
 
+struct v4l2_device;
+
 struct sh_csi2_pdata {
        enum sh_csi2_type type;
        unsigned int flags;
        struct sh_csi2_client_config *clients;
        int num_clients;
+       struct v4l2_device *v4l2_dev;
 };
 
-struct device;
-struct v4l2_device;
-
 #endif
index 238bd334fd839164bc5c262d5a456ffec4da85b8..7582952dceae2810469584a7ae814356aecec5db 100644 (file)
 #include <media/videobuf2-core.h>
 #include <media/v4l2-device.h>
 
-extern struct bus_type soc_camera_bus_type;
-
 struct file;
+struct soc_camera_link;
 
 struct soc_camera_device {
-       struct list_head list;
-       struct device dev;
+       struct list_head list;          /* list of all registered devices */
+       struct soc_camera_link *link;
        struct device *pdev;            /* Platform device */
+       struct device *parent;          /* Camera host device */
+       struct device *control;         /* E.g., the i2c client */
        s32 user_width;
        s32 user_height;
        u32 bytesperline;               /* for padding, zero if unused */
@@ -66,8 +67,6 @@ struct soc_camera_host_ops {
        struct module *owner;
        int (*add)(struct soc_camera_device *);
        void (*remove)(struct soc_camera_device *);
-       int (*suspend)(struct soc_camera_device *, pm_message_t);
-       int (*resume)(struct soc_camera_device *);
        /*
         * .get_formats() is called for each client device format, but
         * .put_formats() is only called once. Further, if any of the calls to
@@ -109,12 +108,6 @@ struct soc_camera_host_ops {
 #define SOCAM_SENSOR_INVERT_HSYNC      (1 << 2)
 #define SOCAM_SENSOR_INVERT_VSYNC      (1 << 3)
 #define SOCAM_SENSOR_INVERT_DATA       (1 << 4)
-#define SOCAM_MIPI_1LANE               (1 << 5)
-#define SOCAM_MIPI_2LANE               (1 << 6)
-#define SOCAM_MIPI_3LANE               (1 << 7)
-#define SOCAM_MIPI_4LANE               (1 << 8)
-#define SOCAM_MIPI     (SOCAM_MIPI_1LANE | SOCAM_MIPI_2LANE | \
-                       SOCAM_MIPI_3LANE | SOCAM_MIPI_4LANE)
 
 struct i2c_board_info;
 struct regulator_bulk_data;
@@ -134,11 +127,11 @@ struct soc_camera_link {
        int num_regulators;
 
        /*
-        * For non-I2C devices platform platform has to provide methods to
-        * add a device to the system and to remove
+        * For non-I2C devices platform has to provide methods to add a device
+        * to the system and to remove it
         */
-       int (*add_device)(struct soc_camera_link *, struct device *);
-       void (*del_device)(struct soc_camera_link *);
+       int (*add_device)(struct soc_camera_device *);
+       void (*del_device)(struct soc_camera_device *);
        /* Optional callbacks to power on or off and reset the sensor */
        int (*power)(struct device *, int);
        int (*reset)(struct device *);
@@ -152,12 +145,6 @@ struct soc_camera_link {
        void (*free_bus)(struct soc_camera_link *);
 };
 
-static inline struct soc_camera_device *to_soc_camera_dev(
-       const struct device *dev)
-{
-       return container_of(dev, struct soc_camera_device, dev);
-}
-
 static inline struct soc_camera_host *to_soc_camera_host(
        const struct device *dev)
 {
@@ -169,13 +156,13 @@ static inline struct soc_camera_host *to_soc_camera_host(
 static inline struct soc_camera_link *to_soc_camera_link(
        const struct soc_camera_device *icd)
 {
-       return icd->dev.platform_data;
+       return icd->link;
 }
 
 static inline struct device *to_soc_camera_control(
        const struct soc_camera_device *icd)
 {
-       return dev_get_drvdata(&icd->dev);
+       return icd->control;
 }
 
 static inline struct v4l2_subdev *soc_camera_to_subdev(
@@ -207,11 +194,8 @@ struct soc_camera_format_xlate {
 };
 
 struct soc_camera_ops {
-       int (*suspend)(struct soc_camera_device *, pm_message_t state);
-       int (*resume)(struct soc_camera_device *);
        unsigned long (*query_bus_param)(struct soc_camera_device *);
        int (*set_bus_param)(struct soc_camera_device *, unsigned long);
-       int (*enum_input)(struct soc_camera_device *, struct v4l2_input *);
        const struct v4l2_queryctrl *controls;
        int num_controls;
 };
@@ -270,6 +254,12 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
 #define SOCAM_PCLK_SAMPLE_FALLING      (1 << 13)
 #define SOCAM_DATA_ACTIVE_HIGH         (1 << 14)
 #define SOCAM_DATA_ACTIVE_LOW          (1 << 15)
+#define SOCAM_MIPI_1LANE               (1 << 16)
+#define SOCAM_MIPI_2LANE               (1 << 17)
+#define SOCAM_MIPI_3LANE               (1 << 18)
+#define SOCAM_MIPI_4LANE               (1 << 19)
+#define SOCAM_MIPI     (SOCAM_MIPI_1LANE | SOCAM_MIPI_2LANE | \
+                       SOCAM_MIPI_3LANE | SOCAM_MIPI_4LANE)
 
 #define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_4 | SOCAM_DATAWIDTH_8 | \
                              SOCAM_DATAWIDTH_9 | SOCAM_DATAWIDTH_10 | \
index 6d7a4fd00fc064a42f77b3e0caba5fb66c3f1f40..74f0fa15ca47af62b90e84fe677ff1694684ec23 100644 (file)
@@ -21,7 +21,7 @@ struct soc_camera_platform_info {
        unsigned long format_depth;
        struct v4l2_mbus_framefmt format;
        unsigned long bus_param;
-       struct device *dev;
+       struct soc_camera_device *icd;
        int (*set_capture)(struct soc_camera_platform_info *info, int enable);
 };
 
@@ -30,8 +30,7 @@ static inline void soc_camera_platform_release(struct platform_device **pdev)
        *pdev = NULL;
 }
 
-static inline int soc_camera_platform_add(const struct soc_camera_link *icl,
-                                         struct device *dev,
+static inline int soc_camera_platform_add(struct soc_camera_device *icd,
                                          struct platform_device **pdev,
                                          struct soc_camera_link *plink,
                                          void (*release)(struct device *dev),
@@ -40,7 +39,7 @@ static inline int soc_camera_platform_add(const struct soc_camera_link *icl,
        struct soc_camera_platform_info *info = plink->priv;
        int ret;
 
-       if (icl != plink)
+       if (icd->link != plink)
                return -ENODEV;
 
        if (*pdev)
@@ -50,7 +49,7 @@ static inline int soc_camera_platform_add(const struct soc_camera_link *icl,
        if (!*pdev)
                return -ENOMEM;
 
-       info->dev = dev;
+       info->icd = icd;
 
        (*pdev)->dev.platform_data = info;
        (*pdev)->dev.release = release;
@@ -59,17 +58,17 @@ static inline int soc_camera_platform_add(const struct soc_camera_link *icl,
        if (ret < 0) {
                platform_device_put(*pdev);
                *pdev = NULL;
-               info->dev = NULL;
+               info->icd = NULL;
        }
 
        return ret;
 }
 
-static inline void soc_camera_platform_del(const struct soc_camera_link *icl,
+static inline void soc_camera_platform_del(const struct soc_camera_device *icd,
                                           struct platform_device *pdev,
                                           const struct soc_camera_link *plink)
 {
-       if (icl != plink || !pdev)
+       if (icd->link != plink || !pdev)
                return;
 
        platform_device_unregister(pdev);
index a59a84854dc1959d5ef2e6c7d4e4f261fcc2d5ce..a40a6a348d21b10ba5d75f439bcd8805ee8342fa 100644 (file)
 
 struct timb_radio_platform_data {
        int i2c_adapter; /* I2C adapter where the tuner and dsp are attached */
-       struct {
-               struct i2c_board_info *info;
-       } tuner;
-       struct {
-               const char *module_name;
-               struct i2c_board_info *info;
-       } dsp;
+       struct i2c_board_info *tuner;
+       struct i2c_board_info *dsp;
 };
 
 #endif
index 963e33471835d6360620d4714eaec7d8b54bf0ed..89c290b69a5c6bf345f7d6e27d3b1921301b87fc 100644 (file)
 #define TUNER_PHILIPS_FMD1216MEX_MK3   78
 #define TUNER_PHILIPS_FM1216MK5                79
 #define TUNER_PHILIPS_FQ1216LME_MK3    80      /* Active loopthrough, no FM */
+#define TUNER_XC4000                   81      /* Xceive Silicon Tuner */
+
 #define TUNER_PARTSNIC_PTI_5NF05       81
 #define TUNER_PHILIPS_CU1216L           82
 #define TUNER_NXP_TDA18271             83
index b3edb67a83114e10af4409a46388187c84a5c53e..63fd9d3db296aae685bc0672daadd9f4d703a92e 100644 (file)
@@ -76,6 +76,7 @@ enum {
        V4L2_IDENT_OV6650 = 258,
        V4L2_IDENT_OV2640 = 259,
        V4L2_IDENT_OV9740 = 260,
+       V4L2_IDENT_OV5642 = 261,
 
        /* module saa7146: reserved range 300-309 */
        V4L2_IDENT_SAA7146 = 300,
@@ -185,8 +186,9 @@ enum {
        /* module wm8775: just ident 8775 */
        V4L2_IDENT_WM8775 = 8775,
 
-       /* module cafe_ccic, just ident 8801 */
+       /* Marvell controllers starting at 8801 */
        V4L2_IDENT_CAFE = 8801,
+       V4L2_IDENT_ARMADA610 = 8802,
 
        /* AKM AK8813/AK8814 */
        V4L2_IDENT_AK8813 = 8813,
index 97d063837b61fb48b315d04da9096375480772f8..13fe4d744aba0563f6664996e584eb9998ab9ed3 100644 (file)
 
 /* forward references */
 struct v4l2_ctrl_handler;
+struct v4l2_ctrl_helper;
 struct v4l2_ctrl;
 struct video_device;
 struct v4l2_subdev;
+struct v4l2_subscribed_event;
+struct v4l2_fh;
 
 /** struct v4l2_ctrl_ops - The control operations that the driver has to provide.
   * @g_volatile_ctrl: Get a new value for this control. Generally only relevant
@@ -51,6 +54,7 @@ struct v4l2_ctrl_ops {
 
 /** struct v4l2_ctrl - The control structure.
   * @node:     The list node.
+  * @ev_subs:  The list of control event subscriptions.
   * @handler:  The handler that owns the control.
   * @cluster:  Point to start of cluster array.
   * @ncontrols:        Number of controls in cluster array.
@@ -65,6 +69,15 @@ struct v4l2_ctrl_ops {
   *            control's current value cannot be cached and needs to be
   *            retrieved through the g_volatile_ctrl op. Drivers can set
   *            this flag.
+  * @is_auto:   If set, then this control selects whether the other cluster
+  *            members are in 'automatic' mode or 'manual' mode. This is
+  *            used for autogain/gain type clusters. Drivers should never
+  *            set this flag directly.
+  * @manual_mode_value: If the is_auto flag is set, then this is the value
+  *            of the auto control that determines if that control is in
+  *            manual mode. So if the value of the auto control equals this
+  *            value, then the whole cluster is in manual mode. Drivers should
+  *            never set this flag directly.
   * @ops:      The control ops.
   * @id:       The control ID.
   * @name:     The control name.
@@ -97,6 +110,7 @@ struct v4l2_ctrl_ops {
 struct v4l2_ctrl {
        /* Administrative fields */
        struct list_head node;
+       struct list_head ev_subs;
        struct v4l2_ctrl_handler *handler;
        struct v4l2_ctrl **cluster;
        unsigned ncontrols;
@@ -105,6 +119,8 @@ struct v4l2_ctrl {
        unsigned int is_new:1;
        unsigned int is_private:1;
        unsigned int is_volatile:1;
+       unsigned int is_auto:1;
+       unsigned int manual_mode_value:8;
 
        const struct v4l2_ctrl_ops *ops;
        u32 id;
@@ -134,6 +150,7 @@ struct v4l2_ctrl {
   * @node:     List node for the sorted list.
   * @next:     Single-link list node for the hash.
   * @ctrl:     The actual control information.
+  * @helper:   Pointer to helper struct. Used internally in prepare_ext_ctrls().
   *
   * Each control handler has a list of these refs. The list_head is used to
   * keep a sorted-by-control-ID list of all controls, while the next pointer
@@ -143,6 +160,7 @@ struct v4l2_ctrl_ref {
        struct list_head node;
        struct v4l2_ctrl_ref *next;
        struct v4l2_ctrl *ctrl;
+       struct v4l2_ctrl_helper *helper;
 };
 
 /** struct v4l2_ctrl_handler - The control handler keeps track of all the
@@ -363,6 +381,40 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
 void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls);
 
 
+/** v4l2_ctrl_auto_cluster() - Mark all controls in the cluster as belonging to
+  * that cluster and set it up for autofoo/foo-type handling.
+  * @ncontrols:        The number of controls in this cluster.
+  * @controls: The cluster control array of size @ncontrols. The first control
+  *            must be the 'auto' control (e.g. autogain, autoexposure, etc.)
+  * @manual_val: The value for the first control in the cluster that equals the
+  *            manual setting.
+  * @set_volatile: If true, then all controls except the first auto control will
+  *            have is_volatile set to true. If false, then is_volatile will not
+  *            be touched.
+  *
+  * Use for control groups where one control selects some automatic feature and
+  * the other controls are only active whenever the automatic feature is turned
+  * off (manual mode). Typical examples: autogain vs gain, auto-whitebalance vs
+  * red and blue balance, etc.
+  *
+  * The behavior of such controls is as follows:
+  *
+  * When the autofoo control is set to automatic, then any manual controls
+  * are set to inactive and any reads will call g_volatile_ctrl (if the control
+  * was marked volatile).
+  *
+  * When the autofoo control is set to manual, then any manual controls will
+  * be marked active, and any reads will just return the current value without
+  * going through g_volatile_ctrl.
+  *
+  * In addition, this function will set the V4L2_CTRL_FLAG_UPDATE flag
+  * on the autofoo control and V4L2_CTRL_FLAG_INACTIVE on the foo control(s)
+  * if autofoo is in auto mode.
+  */
+void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
+                       u8 manual_val, bool set_volatile);
+
+
 /** v4l2_ctrl_find() - Find a control with the given ID.
   * @hdl:      The control handler.
   * @id:       The control ID to find.
@@ -379,9 +431,9 @@ struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id);
   * This sets or clears the V4L2_CTRL_FLAG_INACTIVE flag atomically.
   * Does nothing if @ctrl == NULL.
   * This will usually be called from within the s_ctrl op.
+  * The V4L2_EVENT_CTRL event will be generated afterwards.
   *
-  * This function can be called regardless of whether the control handler
-  * is locked or not.
+  * This function assumes that the control handler is locked.
   */
 void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active);
 
@@ -391,11 +443,12 @@ void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active);
   *
   * This sets or clears the V4L2_CTRL_FLAG_GRABBED flag atomically.
   * Does nothing if @ctrl == NULL.
+  * The V4L2_EVENT_CTRL event will be generated afterwards.
   * This will usually be called when starting or stopping streaming in the
   * driver.
   *
-  * This function can be called regardless of whether the control handler
-  * is locked or not.
+  * This function assumes that the control handler is not locked and will
+  * take the lock itself.
   */
 void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed);
 
@@ -440,15 +493,22 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
   */
 int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
 
+/* Internal helper functions that deal with control events. */
+void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
+               struct v4l2_subscribed_event *sev);
+void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
+               struct v4l2_subscribed_event *sev);
 
 /* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */
 int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc);
 int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm);
 int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl);
-int v4l2_s_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *ctrl);
+int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+                                               struct v4l2_control *ctrl);
 int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c);
 int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c);
-int v4l2_s_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *c);
+int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+                                               struct v4l2_ext_controls *c);
 
 /* Helpers for subdevices. If the associated ctrl_handler == NULL then they
    will all return -EINVAL. */
index 3b86177c8cd2b1f1af6ffd35dc2a597b46a11150..5f14e8895ce2a5ff3c2b119246317cf55f89d9b0 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/wait.h>
 
+/*
+ * Overview:
+ *
+ * Events are subscribed per-filehandle. An event specification consists of a
+ * type and is optionally associated with an object identified through the
+ * 'id' field. So an event is uniquely identified by the (type, id) tuple.
+ *
+ * The v4l2-fh struct has a list of subscribed events. The v4l2_subscribed_event
+ * struct is added to that list, one for every subscribed event.
+ *
+ * Each v4l2_subscribed_event struct ends with an array of v4l2_kevent structs.
+ * This array (ringbuffer, really) is used to store any events raised by the
+ * driver. The v4l2_kevent struct links into the 'available' list of the
+ * v4l2_fh struct so VIDIOC_DQEVENT will know which event to dequeue first.
+ *
+ * Finally, if the event subscription is associated with a particular object
+ * such as a V4L2 control, then that object needs to know about that as well
+ * so that an event can be raised by that object. So the 'node' field can
+ * be used to link the v4l2_subscribed_event struct into a list of that
+ * object.
+ *
+ * So to summarize:
+ *
+ * struct v4l2_fh has two lists: one of the subscribed events, and one of the
+ * pending events.
+ *
+ * struct v4l2_subscribed_event has a ringbuffer of raised (pending) events of
+ * that particular type.
+ *
+ * If struct v4l2_subscribed_event is associated with a specific object, then
+ * that object will have an internal list of struct v4l2_subscribed_event so
+ * it knows who subscribed an event to that object.
+ */
+
 struct v4l2_fh;
+struct v4l2_subscribed_event;
 struct video_device;
 
+/** struct v4l2_kevent - Internal kernel event struct.
+  * @list:     List node for the v4l2_fh->available list.
+  * @sev:      Pointer to parent v4l2_subscribed_event.
+  * @event:    The event itself.
+  */
 struct v4l2_kevent {
        struct list_head        list;
+       struct v4l2_subscribed_event *sev;
        struct v4l2_event       event;
 };
 
+/** struct v4l2_subscribed_event - Internal struct representing a subscribed event.
+  * @list:     List node for the v4l2_fh->subscribed list.
+  * @type:     Event type.
+  * @id:       Associated object ID (e.g. control ID). 0 if there isn't any.
+  * @flags:    Copy of v4l2_event_subscription->flags.
+  * @fh:       Filehandle that subscribed to this event.
+  * @node:     List node that hooks into the object's event list (if there is one).
+  * @replace:  Optional callback that can replace event 'old' with event 'new'.
+  * @merge:    Optional callback that can merge event 'old' into event 'new'.
+  * @elems:    The number of elements in the events array.
+  * @first:    The index of the events containing the oldest available event.
+  * @in_use:   The number of queued events.
+  * @events:   An array of @elems events.
+  */
 struct v4l2_subscribed_event {
        struct list_head        list;
        u32                     type;
+       u32                     id;
+       u32                     flags;
+       struct v4l2_fh          *fh;
+       struct list_head        node;
+       void                    (*replace)(struct v4l2_event *old,
+                                          const struct v4l2_event *new);
+       void                    (*merge)(const struct v4l2_event *old,
+                                        struct v4l2_event *new);
+       unsigned                elems;
+       unsigned                first;
+       unsigned                in_use;
+       struct v4l2_kevent      events[];
 };
 
-struct v4l2_events {
-       wait_queue_head_t       wait;
-       struct list_head        subscribed; /* Subscribed events */
-       struct list_head        free; /* Events ready for use */
-       struct list_head        available; /* Dequeueable event */
-       unsigned int            navailable;
-       unsigned int            nallocated; /* Number of allocated events */
-       u32                     sequence;
-};
-
-int v4l2_event_init(struct v4l2_fh *fh);
-int v4l2_event_alloc(struct v4l2_fh *fh, unsigned int n);
-void v4l2_event_free(struct v4l2_fh *fh);
 int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
                       int nonblocking);
 void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev);
+void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev);
 int v4l2_event_pending(struct v4l2_fh *fh);
 int v4l2_event_subscribe(struct v4l2_fh *fh,
-                        struct v4l2_event_subscription *sub);
+                        struct v4l2_event_subscription *sub, unsigned elems);
 int v4l2_event_unsubscribe(struct v4l2_fh *fh,
                           struct v4l2_event_subscription *sub);
+void v4l2_event_unsubscribe_all(struct v4l2_fh *fh);
 
 #endif /* V4L2_EVENT_H */
index 0206aa55be24cd2b47e685f44918a9fa721ee96f..52513c225c182c6d8d5a4906b78a40a45834f112 100644 (file)
 #include <linux/list.h>
 
 struct video_device;
-struct v4l2_events;
+struct v4l2_ctrl_handler;
 
 struct v4l2_fh {
        struct list_head        list;
        struct video_device     *vdev;
-       struct v4l2_events      *events; /* events, pending and subscribed */
+       struct v4l2_ctrl_handler *ctrl_handler;
        enum v4l2_priority      prio;
+
+       /* Events */
+       wait_queue_head_t       wait;
+       struct list_head        subscribed; /* Subscribed events */
+       struct list_head        available; /* Dequeueable event */
+       unsigned int            navailable;
+       u32                     sequence;
 };
 
 /*
@@ -44,7 +51,7 @@ struct v4l2_fh {
  * from driver's v4l2_file_operations->open() handler if the driver
  * uses v4l2_fh.
  */
-int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev);
+void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev);
 /*
  * Add the fh to the list of file handles on a video_device. The file
  * handle must be initialised first.
index 971c7fa29614092cc35fd4cf736ece5c54df5d3e..6114007c8c744d053dd328a883f378e19bfd9681 100644 (file)
 
 #include <linux/v4l2-mediabus.h>
 
+/* Parallel flags */
+/*
+ * Can the client run in master or in slave mode. By "Master mode" an operation
+ * mode is meant, when the client (e.g., a camera sensor) is producing
+ * horizontal and vertical synchronisation. In "Slave mode" the host is
+ * providing these signals to the slave.
+ */
+#define V4L2_MBUS_MASTER                       (1 << 0)
+#define V4L2_MBUS_SLAVE                                (1 << 1)
+/* Which signal polarities it supports */
+/* Note: in BT.656 mode HSYNC and VSYNC are unused */
+#define V4L2_MBUS_HSYNC_ACTIVE_HIGH            (1 << 2)
+#define V4L2_MBUS_HSYNC_ACTIVE_LOW             (1 << 3)
+#define V4L2_MBUS_VSYNC_ACTIVE_HIGH            (1 << 4)
+#define V4L2_MBUS_VSYNC_ACTIVE_LOW             (1 << 5)
+#define V4L2_MBUS_PCLK_SAMPLE_RISING           (1 << 6)
+#define V4L2_MBUS_PCLK_SAMPLE_FALLING          (1 << 7)
+#define V4L2_MBUS_DATA_ACTIVE_HIGH             (1 << 8)
+#define V4L2_MBUS_DATA_ACTIVE_LOW              (1 << 9)
+
+/* Serial flags */
+/* How many lanes the client can use */
+#define V4L2_MBUS_CSI2_1_LANE                  (1 << 0)
+#define V4L2_MBUS_CSI2_2_LANE                  (1 << 1)
+#define V4L2_MBUS_CSI2_3_LANE                  (1 << 2)
+#define V4L2_MBUS_CSI2_4_LANE                  (1 << 3)
+/* On which channels it can send video data */
+#define V4L2_MBUS_CSI2_CHANNEL_0               (1 << 4)
+#define V4L2_MBUS_CSI2_CHANNEL_1               (1 << 5)
+#define V4L2_MBUS_CSI2_CHANNEL_2               (1 << 6)
+#define V4L2_MBUS_CSI2_CHANNEL_3               (1 << 7)
+/* Does it support only continuous or also non-continuous clock mode */
+#define V4L2_MBUS_CSI2_CONTINUOUS_CLOCK                (1 << 8)
+#define V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK     (1 << 9)
+
+#define V4L2_MBUS_CSI2_LANES           (V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_2_LANE | \
+                                        V4L2_MBUS_CSI2_3_LANE | V4L2_MBUS_CSI2_4_LANE)
+#define V4L2_MBUS_CSI2_CHANNELS                (V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CHANNEL_1 | \
+                                        V4L2_MBUS_CSI2_CHANNEL_2 | V4L2_MBUS_CSI2_CHANNEL_3)
+
+/**
+ * v4l2_mbus_type - media bus type
+ * @V4L2_MBUS_PARALLEL:        parallel interface with hsync and vsync
+ * @V4L2_MBUS_BT656:   parallel interface with embedded synchronisation, can
+ *                     also be used for BT.1120
+ * @V4L2_MBUS_CSI2:    MIPI CSI-2 serial interface
+ */
+enum v4l2_mbus_type {
+       V4L2_MBUS_PARALLEL,
+       V4L2_MBUS_BT656,
+       V4L2_MBUS_CSI2,
+};
+
+/**
+ * v4l2_mbus_config - media bus configuration
+ * @type:      in: interface type
+ * @flags:     in / out: configuration flags, depending on @type
+ */
+struct v4l2_mbus_config {
+       enum v4l2_mbus_type type;
+       unsigned int flags;
+};
+
 static inline void v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt,
                                const struct v4l2_mbus_framefmt *mbus_fmt)
 {
index 2884e3e69cb15b31442624444111a3585ebc8e9c..257da1a30f668ea631780f5e9ec21d1224e52565 100644 (file)
@@ -229,6 +229,12 @@ struct v4l2_subdev_audio_ops {
    s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by
        video input devices.
 
+   g_std_output: get current standard for video OUTPUT devices. This is ignored
+       by video input devices.
+
+   g_tvnorms_output: get v4l2_std_id with all standards supported by video
+       OUTPUT device. This is ignored by video input devices.
+
    s_crystal_freq: sets the frequency of the crystal used to generate the
        clocks in Hz. An extra flags field allows device specific configuration
        regarding clock frequency dividers, etc. If not used, then set flags
@@ -243,6 +249,8 @@ struct v4l2_subdev_audio_ops {
    s_dv_preset: set dv (Digital Video) preset in the sub device. Similar to
        s_std()
 
+   g_dv_preset: get current dv (Digital Video) preset in the sub device.
+
    query_dv_preset: query dv preset in the sub device. This is similar to
        querystd()
 
@@ -259,12 +267,20 @@ struct v4l2_subdev_audio_ops {
    try_mbus_fmt: try to set a pixel format on a video data source
 
    s_mbus_fmt: set a pixel format on a video data source
+
+   g_mbus_config: get supported mediabus configurations
+
+   s_mbus_config: set a certain mediabus configuration. This operation is added
+       for compatibility with soc-camera drivers and should not be used by new
+       software.
  */
 struct v4l2_subdev_video_ops {
        int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config);
        int (*s_crystal_freq)(struct v4l2_subdev *sd, u32 freq, u32 flags);
        int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
+       int (*g_std_output)(struct v4l2_subdev *sd, v4l2_std_id *std);
        int (*querystd)(struct v4l2_subdev *sd, v4l2_std_id *std);
+       int (*g_tvnorms_output)(struct v4l2_subdev *sd, v4l2_std_id *std);
        int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
        int (*s_stream)(struct v4l2_subdev *sd, int enable);
        int (*cropcap)(struct v4l2_subdev *sd, struct v4l2_cropcap *cc);
@@ -282,6 +298,8 @@ struct v4l2_subdev_video_ops {
                        struct v4l2_dv_enum_preset *preset);
        int (*s_dv_preset)(struct v4l2_subdev *sd,
                        struct v4l2_dv_preset *preset);
+       int (*g_dv_preset)(struct v4l2_subdev *sd,
+                       struct v4l2_dv_preset *preset);
        int (*query_dv_preset)(struct v4l2_subdev *sd,
                        struct v4l2_dv_preset *preset);
        int (*s_dv_timings)(struct v4l2_subdev *sd,
@@ -298,6 +316,10 @@ struct v4l2_subdev_video_ops {
                            struct v4l2_mbus_framefmt *fmt);
        int (*s_mbus_fmt)(struct v4l2_subdev *sd,
                          struct v4l2_mbus_framefmt *fmt);
+       int (*g_mbus_config)(struct v4l2_subdev *sd,
+                            struct v4l2_mbus_config *cfg);
+       int (*s_mbus_config)(struct v4l2_subdev *sd,
+                            const struct v4l2_mbus_config *cfg);
 };
 
 /*
@@ -513,8 +535,6 @@ struct v4l2_subdev {
        void *host_priv;
        /* subdev device node */
        struct video_device devnode;
-       /* number of events to be allocated on open */
-       unsigned int nevents;
 };
 
 #define media_entity_to_v4l2_subdev(ent) \
index 63e5b8f6b7dd303f36105fc230c105330b673544..00dbfac9c6e1b76f447141072ccdb593c0e723c6 100644 (file)
        .prod_id = { (v1), NULL, NULL, NULL }, \
        .prod_id_hash = { (vh1), 0, 0, 0 }, }
 
+#define PCMCIA_DEVICE_MANF_CARD_PROD_ID3(manf, card, v3, vh3) { \
+       .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+                       PCMCIA_DEV_ID_MATCH_CARD_ID| \
+                       PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+       .manf_id = (manf), \
+       .card_id = (card), \
+       .prod_id = { NULL, NULL, (v3), NULL }, \
+       .prod_id_hash = { 0, 0, (vh3), 0 }, }
+
 
 /* multi-function devices */
 
index 4ad02041b667f6291c456a1361e50ab31bfe2b58..8225d8063ec48ab6a579d7a74c2f29031e157b20 100644 (file)
@@ -78,7 +78,6 @@ struct fc_frame {
 };
 
 struct fcoe_rcv_info {
-       struct packet_type  *ptype;
        struct fc_lport *fr_dev;        /* transport layer private pointer */
        struct fc_seq   *fr_seq;        /* for use with exchange manager */
        struct fc_fcp_pkt *fr_fsp;      /* for the corresponding fcp I/O */
index ea68b3c56dbf3e27a4185952b127247f2409334d..988ba06b3ad628c9b12935fd4fa17687d1328221 100644 (file)
 /* default iSCSI listen port for incoming connections */
 #define ISCSI_LISTEN_PORT      3260
 
+/* iSCSI header length */
+#define ISCSI_HDR_LEN          48
+
+/* iSCSI CRC32C length */
+#define ISCSI_CRC_LEN          4
+
 /* Padding word length */
 #define ISCSI_PAD_LEN          4
 
+/*
+ * Serial Number Arithmetic, 32 bits, RFC1982
+ */
+
+static inline int iscsi_sna_lt(u32 n1, u32 n2)
+{
+       return (s32)(n1 - n2) < 0;
+}
+
+static inline int iscsi_sna_lte(u32 n1, u32 n2)
+{
+       return (s32)(n1 - n2) <= 0;
+}
+
+static inline int iscsi_sna_gt(u32 n1, u32 n2)
+{
+       return (s32)(n1 - n2) > 0;
+}
+
+static inline int iscsi_sna_gte(u32 n1, u32 n2)
+{
+       return (s32)(n1 - n2) >= 0;
+}
+
 /*
  * useful common(control and data pathes) macro
  */
@@ -116,7 +146,7 @@ struct iscsi_ahs_hdr {
 #define ISCSI_CDB_SIZE                 16
 
 /* iSCSI PDU Header */
-struct iscsi_cmd {
+struct iscsi_scsi_req {
        uint8_t opcode;
        uint8_t flags;
        __be16 rsvd2;
@@ -161,7 +191,7 @@ struct iscsi_ecdb_ahdr {
 };
 
 /* SCSI Response Header */
-struct iscsi_cmd_rsp {
+struct iscsi_scsi_rsp {
        uint8_t opcode;
        uint8_t flags;
        uint8_t response;
@@ -406,7 +436,7 @@ struct iscsi_text_rsp {
 };
 
 /* Login Header */
-struct iscsi_login {
+struct iscsi_login_req {
        uint8_t opcode;
        uint8_t flags;
        uint8_t max_version;    /* Max. version supported */
@@ -427,7 +457,13 @@ struct iscsi_login {
 #define ISCSI_FLAG_LOGIN_TRANSIT               0x80
 #define ISCSI_FLAG_LOGIN_CONTINUE              0x40
 #define ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK    0x0C    /* 2 bits */
+#define ISCSI_FLAG_LOGIN_CURRENT_STAGE1                0x04
+#define ISCSI_FLAG_LOGIN_CURRENT_STAGE2                0x08
+#define ISCSI_FLAG_LOGIN_CURRENT_STAGE3                0x0C
 #define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK       0x03    /* 2 bits */
+#define ISCSI_FLAG_LOGIN_NEXT_STAGE1           0x01
+#define ISCSI_FLAG_LOGIN_NEXT_STAGE2           0x02
+#define ISCSI_FLAG_LOGIN_NEXT_STAGE3           0x03
 
 #define ISCSI_LOGIN_CURRENT_STAGE(flags) \
        ((flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2)
@@ -550,17 +586,25 @@ struct iscsi_logout_rsp {
 struct iscsi_snack {
        uint8_t opcode;
        uint8_t flags;
-       uint8_t rsvd2[14];
+       uint8_t rsvd2[2];
+       uint8_t hlength;
+       uint8_t dlength[3];
+       uint8_t lun[8];
        itt_t    itt;
+       __be32  ttt;
+       uint8_t rsvd3[4];
+       __be32  exp_statsn;
+       uint8_t rsvd4[8];
        __be32  begrun;
        __be32  runlength;
-       __be32  exp_statsn;
-       __be32  rsvd3;
-       __be32  exp_datasn;
-       uint8_t rsvd6[8];
 };
 
 /* SNACK PDU flags */
+#define ISCSI_FLAG_SNACK_TYPE_DATA             0
+#define ISCSI_FLAG_SNACK_TYPE_R2T              0
+#define ISCSI_FLAG_SNACK_TYPE_STATUS           1
+#define ISCSI_FLAG_SNACK_TYPE_DATA_ACK         2
+#define ISCSI_FLAG_SNACK_TYPE_RDATA            3
 #define ISCSI_FLAG_SNACK_TYPE_MASK     0x0F    /* 4 bits */
 
 /* Reject Message Header */
index e1bad1130616f1441d1aa061f048a4ea74c606e7..57e71fa33f7ce8eac899870d9e11937a2240a6dd 100644 (file)
@@ -507,6 +507,18 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream);
 void snd_pcm_vma_notify_data(void *client, void *data);
 int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
 
+
+#ifdef CONFIG_SND_DEBUG
+void snd_pcm_debug_name(struct snd_pcm_substream *substream,
+                          char *name, size_t len);
+#else
+static inline void
+snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
+{
+       *buf = 0;
+}
+#endif
+
 /*
  *  PCM library
  */
@@ -749,17 +761,18 @@ static inline const struct snd_interval *hw_param_interval_c(const struct snd_pc
        return &params->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
 }
 
-#define params_access(p) ((__force snd_pcm_access_t)snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS)))
-#define params_format(p) ((__force snd_pcm_format_t)snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_FORMAT)))
-#define params_subformat(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_SUBFORMAT))
-#define params_channels(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min
-#define params_rate(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_RATE)->min
-#define params_period_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min
-#define params_period_bytes(p) ((params_period_size(p)*snd_pcm_format_physical_width(params_format(p))*params_channels(p))/8)
-#define params_periods(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIODS)->min
-#define params_buffer_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min
-#define params_buffer_bytes(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min
-
+#define params_channels(p) \
+       (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min)
+#define params_rate(p) \
+       (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_RATE)->min)
+#define params_period_size(p) \
+       (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min)
+#define params_periods(p) \
+       (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_PERIODS)->min)
+#define params_buffer_size(p) \
+       (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min)
+#define params_buffer_bytes(p) \
+       (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min)
 
 int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v);
 void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c);
index 85cf1cf4f31a7a202e8e5faa91f992f3aa1a90ef..f494f1e3c900ef775a56909e2baeb6e99bd120ca 100644 (file)
@@ -337,5 +337,19 @@ static inline unsigned int sub(unsigned int a, unsigned int b)
        return 0;
 }
 
-#endif /* __SOUND_PCM_PARAMS_H */
+#define params_access(p) ((__force snd_pcm_access_t)\
+               snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_ACCESS)))
+#define params_format(p) ((__force snd_pcm_format_t)\
+               snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_FORMAT)))
+#define params_subformat(p) \
+       snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_SUBFORMAT))
 
+static inline unsigned int
+params_period_bytes(const struct snd_pcm_hw_params *p)
+{
+       return (params_period_size(p) *
+               snd_pcm_format_physical_width(params_format(p)) *
+               params_channels(p)) / 8;
+}
+
+#endif /* __SOUND_PCM_PARAMS_H */
index e09505c5a49097208ff29a344e8a0354514ab846..e0583b7769cb505648f005be33f8b6c10f3c4049 100644 (file)
        .get = snd_soc_dapm_get_enum_virt, \
        .put = snd_soc_dapm_put_enum_virt, \
        .private_value = (unsigned long)&xenum }
+#define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_enum_double, \
+       .get = xget, \
+       .put = xput, \
+       .private_value = (unsigned long)&xenum }
 #define SOC_DAPM_VALUE_ENUM(xname, xenum) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_enum_double, \
index d2ea112fc20f0615a156c7a7c9909da6611ef786..726e94742a5ccf733923914c1f90b1717b9fd6cb 100644 (file)
@@ -23,8 +23,8 @@
  */
 
 #include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-dev.h>
-#include <media/v4l2-ioctl.h>
 
 #define TEA575X_FMIF   10700
 
@@ -42,18 +42,20 @@ struct snd_tea575x_ops {
 };
 
 struct snd_tea575x {
-       struct video_device *vd;        /* video device */
+       struct video_device vd;         /* video device */
        bool tea5759;                   /* 5759 chip is present */
        bool mute;                      /* Device is muted? */
        bool stereo;                    /* receiving stereo */
        bool tuned;                     /* tuned to a station */
        unsigned int val;               /* hw value */
        unsigned long freq;             /* frequency */
-       unsigned long in_use;           /* set if the device is in use */
+       struct mutex mutex;
        struct snd_tea575x_ops *ops;
        void *private_data;
        u8 card[32];
        u8 bus_info[32];
+       struct v4l2_ctrl_handler ctrl_handler;
+       int (*ext_init)(struct snd_tea575x *tea);
 };
 
 int snd_tea575x_init(struct snd_tea575x *tea);
index 44d8decee09e65990cde0a9ecac01f0451a77fed..92f1a796829e8bf175f23fd5f84e1c4bb1aebf26 100644 (file)
@@ -8,6 +8,8 @@
 #include <asm/paravirt_types.h>
 #include <asm/xen/trace_types.h>
 
+struct multicall_entry;
+
 /* Multicalls */
 DECLARE_EVENT_CLASS(xen_mc__batch,
            TP_PROTO(enum paravirt_lazy_mode mode),
index 892b97f8e1576f969821688820350a0020762641..3b55ef22f8db2415ee10de5675f435da59fec44f 100644 (file)
@@ -21,8 +21,6 @@
 #include <linux/list.h>
 #include <linux/kobject.h>
 #include <linux/device.h>
-#include <linux/platform_device.h>
-#include <asm/atomic.h>
 
 #define DISPC_IRQ_FRAMEDONE            (1 << 0)
 #define DISPC_IRQ_VSYNC                        (1 << 1)
@@ -136,12 +134,6 @@ enum omap_display_caps {
        OMAP_DSS_DISPLAY_CAP_TEAR_ELIM          = 1 << 1,
 };
 
-enum omap_dss_update_mode {
-       OMAP_DSS_UPDATE_DISABLED = 0,
-       OMAP_DSS_UPDATE_AUTO,
-       OMAP_DSS_UPDATE_MANUAL,
-};
-
 enum omap_dss_display_state {
        OMAP_DSS_DISPLAY_DISABLED = 0,
        OMAP_DSS_DISPLAY_ACTIVE,
@@ -246,7 +238,7 @@ int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel);
 
 /* Board specific data */
 struct omap_dss_board_info {
-       int (*get_last_off_on_transaction_id)(struct device *dev);
+       int (*get_context_loss_count)(struct device *dev);
        int num_devices;
        struct omap_dss_device **devices;
        struct omap_dss_device *default_device;
@@ -266,8 +258,6 @@ static inline int omap_display_init(struct omap_dss_board_info *board_data)
 struct omap_display_platform_data {
        struct omap_dss_board_info *board_data;
        /* TODO: Additional members to be added when PM is considered */
-
-       bool (*opt_clock_available)(const char *clk_role);
 };
 
 struct omap_video_timings {
@@ -300,6 +290,12 @@ extern const struct omap_video_timings omap_dss_pal_timings;
 extern const struct omap_video_timings omap_dss_ntsc_timings;
 #endif
 
+struct omap_dss_cpr_coefs {
+       s16 rr, rg, rb;
+       s16 gr, gg, gb;
+       s16 br, bg, bb;
+};
+
 struct omap_overlay_info {
        bool enabled;
 
@@ -359,6 +355,9 @@ struct omap_overlay_manager_info {
        bool trans_enabled;
 
        bool alpha_enabled;
+
+       bool cpr_enable;
+       struct omap_dss_cpr_coefs cpr_coefs;
 };
 
 struct omap_overlay_manager {
@@ -526,11 +525,6 @@ struct omap_dss_driver {
        int (*resume)(struct omap_dss_device *display);
        int (*run_test)(struct omap_dss_device *display, int test);
 
-       int (*set_update_mode)(struct omap_dss_device *dssdev,
-                       enum omap_dss_update_mode);
-       enum omap_dss_update_mode (*get_update_mode)(
-                       struct omap_dss_device *dssdev);
-
        int (*update)(struct omap_dss_device *dssdev,
                               u16 x, u16 y, u16 w, u16 h);
        int (*sync)(struct omap_dss_device *dssdev);
index 3f5b14365f33e54408c5e89d3b15aacbc2c1435b..9fb044f3b345e5e61ea072e255ab3b67b5ce3539 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -131,6 +131,12 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
+static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
+{
+       rcu_read_lock();
+       spin_lock(&ipcp->shm_perm.lock);
+}
+
 static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
                                                int id)
 {
@@ -231,76 +237,77 @@ static void shm_close(struct vm_area_struct *vma)
        up_write(&shm_ids(ns).rw_mutex);
 }
 
+/* Called with ns->shm_ids(ns).rw_mutex locked */
 static int shm_try_destroy_current(int id, void *p, void *data)
 {
        struct ipc_namespace *ns = data;
-       struct shmid_kernel *shp = shm_lock(ns, id);
+       struct kern_ipc_perm *ipcp = p;
+       struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
 
-       if (IS_ERR(shp))
+       if (shp->shm_creator != current)
                return 0;
 
-       if (shp->shm_cprid != task_tgid_vnr(current)) {
-               shm_unlock(shp);
+       /*
+        * Mark it as orphaned to destroy the segment when
+        * kernel.shm_rmid_forced is changed.
+        * It is noop if the following shm_may_destroy() returns true.
+        */
+       shp->shm_creator = NULL;
+
+       /*
+        * Don't even try to destroy it.  If shm_rmid_forced=0 and IPC_RMID
+        * is not set, it shouldn't be deleted here.
+        */
+       if (!ns->shm_rmid_forced)
                return 0;
-       }
 
-       if (shm_may_destroy(ns, shp))
+       if (shm_may_destroy(ns, shp)) {
+               shm_lock_by_ptr(shp);
                shm_destroy(ns, shp);
-       else
-               shm_unlock(shp);
+       }
        return 0;
 }
 
+/* Called with ns->shm_ids(ns).rw_mutex locked */
 static int shm_try_destroy_orphaned(int id, void *p, void *data)
 {
        struct ipc_namespace *ns = data;
-       struct shmid_kernel *shp = shm_lock(ns, id);
-       struct task_struct *task;
-
-       if (IS_ERR(shp))
-               return 0;
+       struct kern_ipc_perm *ipcp = p;
+       struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
 
        /*
         * We want to destroy segments without users and with already
         * exit'ed originating process.
         *
-        * XXX: the originating process may exist in another pid namespace.
+        * As shp->* are changed under rw_mutex, it's safe to skip shp locking.
         */
-       task = find_task_by_vpid(shp->shm_cprid);
-       if (task != NULL) {
-               shm_unlock(shp);
+       if (shp->shm_creator != NULL)
                return 0;
-       }
 
-       if (shm_may_destroy(ns, shp))
+       if (shm_may_destroy(ns, shp)) {
+               shm_lock_by_ptr(shp);
                shm_destroy(ns, shp);
-       else
-               shm_unlock(shp);
+       }
        return 0;
 }
 
 void shm_destroy_orphaned(struct ipc_namespace *ns)
 {
        down_write(&shm_ids(ns).rw_mutex);
-       idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
+       if (&shm_ids(ns).in_use)
+               idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
        up_write(&shm_ids(ns).rw_mutex);
 }
 
 
 void exit_shm(struct task_struct *task)
 {
-       struct nsproxy *nsp = task->nsproxy;
-       struct ipc_namespace *ns;
-
-       if (!nsp)
-               return;
-       ns = nsp->ipc_ns;
-       if (!ns || !ns->shm_rmid_forced)
-               return;
+       struct ipc_namespace *ns = task->nsproxy->ipc_ns;
 
        /* Destroy all already created segments, but not mapped yet */
        down_write(&shm_ids(ns).rw_mutex);
-       idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
+       if (&shm_ids(ns).in_use)
+               idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
        up_write(&shm_ids(ns).rw_mutex);
 }
 
@@ -494,6 +501,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        shp->shm_segsz = size;
        shp->shm_nattch = 0;
        shp->shm_file = file;
+       shp->shm_creator = current;
        /*
         * shmid gets reported as "inode#" in /proc/pid/maps.
         * proc-ps tools use this. Changing this will break them.
index 984458035d4acdad7737a9ebeff584e4b34e9568..1d2b6ceea95d9d268191a76fd486e7958cc2d05c 100644 (file)
  */
 
 #include <linux/cgroup.h>
+#include <linux/cred.h>
 #include <linux/ctype.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/init_task.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/mm.h>
@@ -1514,6 +1516,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                struct cgroup *root_cgrp = &root->top_cgroup;
                struct inode *inode;
                struct cgroupfs_root *existing_root;
+               const struct cred *cred;
                int i;
 
                BUG_ON(sb->s_root != NULL);
@@ -1593,7 +1596,9 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                BUG_ON(!list_empty(&root_cgrp->children));
                BUG_ON(root->number_of_cgroups != 1);
 
+               cred = override_creds(&init_cred);
                cgroup_populate_dir(root_cgrp);
+               revert_creds(cred);
                mutex_unlock(&cgroup_mutex);
                mutex_unlock(&inode->i_mutex);
        } else {
index 18197ae2d46544d09df56204e25fb50a142b150e..e2435ee9993a329bee48252a38af4ca69e6c4742 100644 (file)
@@ -158,6 +158,7 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
                        __put_user(ts->tv_sec, &cts->tv_sec) ||
                        __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
 }
+EXPORT_SYMBOL_GPL(put_compat_timespec);
 
 static long compat_nanosleep_restart(struct restart_block *restart)
 {
@@ -992,11 +993,8 @@ asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat
        sigset_from_compat(&newset, &newset32);
        sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
 
-       spin_lock_irq(&current->sighand->siglock);
        current->saved_sigmask = current->blocked;
-       current->blocked = newset;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       set_current_blocked(&newset);
 
        current->state = TASK_INTERRUPTIBLE;
        schedule();
index d1d051b38e0b5fc1c84eb3bb94b85373d7d6bf47..5a38bf4de641d249ddc590d4397e6b96e8fbfbef 100644 (file)
@@ -52,6 +52,10 @@ config IRQ_EDGE_EOI_HANDLER
 config GENERIC_IRQ_CHIP
        bool
 
+# Generic irq_domain hw <--> linux irq number translation
+config IRQ_DOMAIN
+       bool
+
 # Support forced irq threading
 config IRQ_FORCED_THREADING
        bool
index 73290056cfb6d11a77799684b49f1a888bebbade..fff17381f0afc66739d17eb1a696d701970ec20e 100644 (file)
@@ -2,6 +2,7 @@
 obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o
 obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o
 obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
+obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
 obj-$(CONFIG_PM_SLEEP) += pm.o
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
new file mode 100644 (file)
index 0000000..d5828da
--- /dev/null
@@ -0,0 +1,180 @@
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+static LIST_HEAD(irq_domain_list);
+static DEFINE_MUTEX(irq_domain_mutex);
+
+/**
+ * irq_domain_add() - Register an irq_domain
+ * @domain: ptr to initialized irq_domain structure
+ *
+ * Registers an irq_domain structure.  The irq_domain must at a minimum be
+ * initialized with an ops structure pointer, and either a ->to_irq hook or
+ * a valid irq_base value.  Everything else is optional.
+ */
+void irq_domain_add(struct irq_domain *domain)
+{
+       struct irq_data *d;
+       int hwirq;
+
+       /*
+        * This assumes that the irq_domain owner has already allocated
+        * the irq_descs.  This block will be removed when support for dynamic
+        * allocation of irq_descs is added to irq_domain.
+        */
+       for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
+               d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+               if (d || d->domain) {
+                       /* things are broken; just report, don't clean up */
+                       WARN(1, "error: irq_desc already assigned to a domain");
+                       return;
+               }
+               d->domain = domain;
+               d->hwirq = hwirq;
+       }
+
+       mutex_lock(&irq_domain_mutex);
+       list_add(&domain->list, &irq_domain_list);
+       mutex_unlock(&irq_domain_mutex);
+}
+
+/**
+ * irq_domain_del() - Unregister an irq_domain
+ * @domain: ptr to registered irq_domain.
+ */
+void irq_domain_del(struct irq_domain *domain)
+{
+       struct irq_data *d;
+       int hwirq;
+
+       mutex_lock(&irq_domain_mutex);
+       list_del(&domain->list);
+       mutex_unlock(&irq_domain_mutex);
+
+       /* Clear the irq_domain assignments */
+       for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
+               d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+               d->domain = NULL;
+       }
+}
+
+#if defined(CONFIG_OF_IRQ)
+/**
+ * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
+ *
+ * Used by the device tree interrupt mapping code to translate a device tree
+ * interrupt specifier to a valid linux irq number.  Returns either a valid
+ * linux IRQ number or 0.
+ *
+ * When the caller no longer need the irq number returned by this function it
+ * should arrange to call irq_dispose_mapping().
+ */
+unsigned int irq_create_of_mapping(struct device_node *controller,
+                                  const u32 *intspec, unsigned int intsize)
+{
+       struct irq_domain *domain;
+       unsigned long hwirq;
+       unsigned int irq, type;
+       int rc = -EINVAL;
+
+       /* Find a domain which can translate the irq spec */
+       mutex_lock(&irq_domain_mutex);
+       list_for_each_entry(domain, &irq_domain_list, list) {
+               if (!domain->ops->dt_translate)
+                       continue;
+               rc = domain->ops->dt_translate(domain, controller,
+                                       intspec, intsize, &hwirq, &type);
+               if (rc == 0)
+                       break;
+       }
+       mutex_unlock(&irq_domain_mutex);
+
+       if (rc != 0)
+               return 0;
+
+       irq = irq_domain_to_irq(domain, hwirq);
+       if (type != IRQ_TYPE_NONE)
+               irq_set_irq_type(irq, type);
+       pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n",
+                controller->full_name, (int)hwirq, irq, type);
+       return irq;
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
+
+/**
+ * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping()
+ * @irq: linux irq number to be discarded
+ *
+ * Calling this function indicates the caller no longer needs a reference to
+ * the linux irq number returned by a prior call to irq_create_of_mapping().
+ */
+void irq_dispose_mapping(unsigned int irq)
+{
+       /*
+        * nothing yet; will be filled when support for dynamic allocation of
+        * irq_descs is added to irq_domain
+        */
+}
+EXPORT_SYMBOL_GPL(irq_dispose_mapping);
+
+int irq_domain_simple_dt_translate(struct irq_domain *d,
+                           struct device_node *controller,
+                           const u32 *intspec, unsigned int intsize,
+                           unsigned long *out_hwirq, unsigned int *out_type)
+{
+       if (d->of_node != controller)
+               return -EINVAL;
+       if (intsize < 1)
+               return -EINVAL;
+
+       *out_hwirq = intspec[0];
+       *out_type = IRQ_TYPE_NONE;
+       if (intsize > 1)
+               *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+       return 0;
+}
+
+struct irq_domain_ops irq_domain_simple_ops = {
+       .dt_translate = irq_domain_simple_dt_translate,
+};
+EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
+
+/**
+ * irq_domain_create_simple() - Set up a 'simple' translation range
+ */
+void irq_domain_add_simple(struct device_node *controller, int irq_base)
+{
+       struct irq_domain *domain;
+
+       domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+       if (!domain) {
+               WARN_ON(1);
+               return;
+       }
+
+       domain->irq_base = irq_base;
+       domain->of_node = of_node_get(controller);
+       domain->ops = &irq_domain_simple_ops;
+       irq_domain_add(domain);
+}
+EXPORT_SYMBOL_GPL(irq_domain_add_simple);
+
+void irq_domain_generate_simple(const struct of_device_id *match,
+                               u64 phys_base, unsigned int irq_start)
+{
+       struct device_node *node;
+       pr_info("looking for phys_base=%llx, irq_start=%i\n",
+               (unsigned long long) phys_base, (int) irq_start);
+       node = of_find_matching_node_by_address(NULL, match, phys_base);
+       if (node)
+               irq_domain_add_simple(node, irq_start);
+       else
+               pr_info("no node found\n");
+}
+EXPORT_SYMBOL_GPL(irq_domain_generate_simple);
+#endif /* CONFIG_OF_IRQ */
index 3ff40178dce77d21fdd1ec508fc2baab5e87db84..3b3cedc52592164e11689375c4bb7d054df293cf 100644 (file)
@@ -553,6 +553,27 @@ int allocate_resource(struct resource *root, struct resource *new,
 
 EXPORT_SYMBOL(allocate_resource);
 
+/**
+ * lookup_resource - find an existing resource by a resource start address
+ * @root: root resource descriptor
+ * @start: resource start address
+ *
+ * Returns a pointer to the resource if found, NULL otherwise
+ */
+struct resource *lookup_resource(struct resource *root, resource_size_t start)
+{
+       struct resource *res;
+
+       read_lock(&resource_lock);
+       for (res = root->child; res; res = res->sibling) {
+               if (res->start == start)
+                       break;
+       }
+       read_unlock(&resource_lock);
+
+       return res;
+}
+
 /*
  * Insert a resource into the resource tree. If successful, return NULL,
  * otherwise return the conflicting resource (compare to __request_resource())
index d7f70aed1cc0fca14dcfa15e36cd7af326f62d74..291c9700be750c0cdfae41bed029bf34b72c9bf4 100644 (file)
@@ -3102,15 +3102,11 @@ SYSCALL_DEFINE0(sgetmask)
 
 SYSCALL_DEFINE1(ssetmask, int, newmask)
 {
-       int old;
-
-       spin_lock_irq(&current->sighand->siglock);
-       old = current->blocked.sig[0];
+       int old = current->blocked.sig[0];
+       sigset_t newset;
 
-       siginitset(&current->blocked, newmask & ~(sigmask(SIGKILL)|
-                                                 sigmask(SIGSTOP)));
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       siginitset(&newset, newmask & ~(sigmask(SIGKILL) | sigmask(SIGSTOP)));
+       set_current_blocked(&newset);
 
        return old;
 }
@@ -3167,11 +3163,8 @@ SYSCALL_DEFINE2(rt_sigsuspend, sigset_t __user *, unewset, size_t, sigsetsize)
                return -EFAULT;
        sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
 
-       spin_lock_irq(&current->sighand->siglock);
        current->saved_sigmask = current->blocked;
-       current->blocked = newset;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       set_current_blocked(&newset);
 
        current->state = TASK_INTERRUPTIBLE;
        schedule();
index 1e523ed47c619d385465a7080f44fabe68d115cb..95947400702bad1961fac92ea91a3707713a907a 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3403,7 +3403,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        cache_alloc_debugcheck_before(cachep, flags);
        local_irq_save(save_flags);
 
-       if (nodeid == -1)
+       if (nodeid == NUMA_NO_NODE)
                nodeid = slab_node;
 
        if (unlikely(!cachep->nodelists[nodeid])) {
@@ -3934,7 +3934,7 @@ fail:
 
 struct ccupdate_struct {
        struct kmem_cache *cachep;
-       struct array_cache *new[NR_CPUS];
+       struct array_cache *new[0];
 };
 
 static void do_ccupdate_local(void *info)
@@ -3956,7 +3956,8 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
        struct ccupdate_struct *new;
        int i;
 
-       new = kzalloc(sizeof(*new), gfp);
+       new = kzalloc(sizeof(*new) + nr_cpu_ids * sizeof(struct array_cache *),
+                     gfp);
        if (!new)
                return -ENOMEM;
 
index f8f5e8efeb88ee093a7d2e5535f3b2b56d467e4e..eb5a8f93338a1819d026dedf71d9db452c3c62cf 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2,10 +2,11 @@
  * SLUB: A slab allocator that limits cache line use instead of queuing
  * objects in per cpu and per node lists.
  *
- * The allocator synchronizes using per slab locks and only
- * uses a centralized lock to manage a pool of partial slabs.
+ * The allocator synchronizes using per slab locks or atomic operatios
+ * and only uses a centralized lock to manage a pool of partial slabs.
  *
  * (C) 2007 SGI, Christoph Lameter
+ * (C) 2011 Linux Foundation, Christoph Lameter
  */
 
 #include <linux/mm.h>
 
 /*
  * Lock order:
- *   1. slab_lock(page)
- *   2. slab->list_lock
+ *   1. slub_lock (Global Semaphore)
+ *   2. node->list_lock
+ *   3. slab_lock(page) (Only on some arches and for debugging)
  *
- *   The slab_lock protects operations on the object of a particular
- *   slab and its metadata in the page struct. If the slab lock
- *   has been taken then no allocations nor frees can be performed
- *   on the objects in the slab nor can the slab be added or removed
- *   from the partial or full lists since this would mean modifying
- *   the page_struct of the slab.
+ *   slub_lock
+ *
+ *   The role of the slub_lock is to protect the list of all the slabs
+ *   and to synchronize major metadata changes to slab cache structures.
+ *
+ *   The slab_lock is only used for debugging and on arches that do not
+ *   have the ability to do a cmpxchg_double. It only protects the second
+ *   double word in the page struct. Meaning
+ *     A. page->freelist       -> List of object free in a page
+ *     B. page->counters       -> Counters of objects
+ *     C. page->frozen         -> frozen state
+ *
+ *   If a slab is frozen then it is exempt from list management. It is not
+ *   on any list. The processor that froze the slab is the one who can
+ *   perform list operations on the page. Other processors may put objects
+ *   onto the freelist but the processor that froze the slab is the only
+ *   one that can retrieve the objects from the page's freelist.
  *
  *   The list_lock protects the partial and full list on each node and
  *   the partial slab counter. If taken then no new slabs may be added or
  *   slabs, operations can continue without any centralized lock. F.e.
  *   allocating a long series of objects that fill up slabs does not require
  *   the list lock.
- *
- *   The lock order is sometimes inverted when we are trying to get a slab
- *   off a list. We take the list_lock and then look for a page on the list
- *   to use. While we do that objects in the slabs may be freed. We can
- *   only operate on the slab if we have also taken the slab_lock. So we use
- *   a slab_trylock() on the slab. If trylock was successful then no frees
- *   can occur anymore and we can use the slab for allocations etc. If the
- *   slab_trylock() does not succeed then frees are in progress in the slab and
- *   we must stay away from it for a while since we may cause a bouncing
- *   cacheline if we try to acquire the lock. So go onto the next slab.
- *   If all pages are busy then we may allocate a new slab instead of reusing
- *   a partial slab. A new slab has no one operating on it and thus there is
- *   no danger of cacheline contention.
- *
  *   Interrupts are disabled during allocation and deallocation in order to
  *   make the slab allocator safe to use in the context of an irq. In addition
  *   interrupts are disabled to ensure that the processor does not change
@@ -132,6 +131,9 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
 /* Enable to test recovery from slab corruption on boot */
 #undef SLUB_RESILIENCY_TEST
 
+/* Enable to log cmpxchg failures */
+#undef SLUB_DEBUG_CMPXCHG
+
 /*
  * Mininum number of partial slabs. These will be left on the partial
  * lists even if they are empty. kmem_cache_shrink may reclaim them.
@@ -167,10 +169,11 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
 
 #define OO_SHIFT       16
 #define OO_MASK                ((1 << OO_SHIFT) - 1)
-#define MAX_OBJS_PER_PAGE      65535 /* since page.objects is u16 */
+#define MAX_OBJS_PER_PAGE      32767 /* since page.objects is u15 */
 
 /* Internal SLUB flags */
 #define __OBJECT_POISON                0x80000000UL /* Poison object */
+#define __CMPXCHG_DOUBLE       0x40000000UL /* Use cmpxchg_double */
 
 static int kmem_size = sizeof(struct kmem_cache);
 
@@ -343,11 +346,99 @@ static inline int oo_objects(struct kmem_cache_order_objects x)
        return x.x & OO_MASK;
 }
 
+/*
+ * Per slab locking using the pagelock
+ */
+static __always_inline void slab_lock(struct page *page)
+{
+       bit_spin_lock(PG_locked, &page->flags);
+}
+
+static __always_inline void slab_unlock(struct page *page)
+{
+       __bit_spin_unlock(PG_locked, &page->flags);
+}
+
+/* Interrupts must be disabled (for the fallback code to work right) */
+static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
+               void *freelist_old, unsigned long counters_old,
+               void *freelist_new, unsigned long counters_new,
+               const char *n)
+{
+       VM_BUG_ON(!irqs_disabled());
+#ifdef CONFIG_CMPXCHG_DOUBLE
+       if (s->flags & __CMPXCHG_DOUBLE) {
+               if (cmpxchg_double(&page->freelist,
+                       freelist_old, counters_old,
+                       freelist_new, counters_new))
+               return 1;
+       } else
+#endif
+       {
+               slab_lock(page);
+               if (page->freelist == freelist_old && page->counters == counters_old) {
+                       page->freelist = freelist_new;
+                       page->counters = counters_new;
+                       slab_unlock(page);
+                       return 1;
+               }
+               slab_unlock(page);
+       }
+
+       cpu_relax();
+       stat(s, CMPXCHG_DOUBLE_FAIL);
+
+#ifdef SLUB_DEBUG_CMPXCHG
+       printk(KERN_INFO "%s %s: cmpxchg double redo ", n, s->name);
+#endif
+
+       return 0;
+}
+
+static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
+               void *freelist_old, unsigned long counters_old,
+               void *freelist_new, unsigned long counters_new,
+               const char *n)
+{
+#ifdef CONFIG_CMPXCHG_DOUBLE
+       if (s->flags & __CMPXCHG_DOUBLE) {
+               if (cmpxchg_double(&page->freelist,
+                       freelist_old, counters_old,
+                       freelist_new, counters_new))
+               return 1;
+       } else
+#endif
+       {
+               unsigned long flags;
+
+               local_irq_save(flags);
+               slab_lock(page);
+               if (page->freelist == freelist_old && page->counters == counters_old) {
+                       page->freelist = freelist_new;
+                       page->counters = counters_new;
+                       slab_unlock(page);
+                       local_irq_restore(flags);
+                       return 1;
+               }
+               slab_unlock(page);
+               local_irq_restore(flags);
+       }
+
+       cpu_relax();
+       stat(s, CMPXCHG_DOUBLE_FAIL);
+
+#ifdef SLUB_DEBUG_CMPXCHG
+       printk(KERN_INFO "%s %s: cmpxchg double redo ", n, s->name);
+#endif
+
+       return 0;
+}
+
 #ifdef CONFIG_SLUB_DEBUG
 /*
  * Determine a map of object in use on a page.
  *
- * Slab lock or node listlock must be held to guarantee that the page does
+ * Node listlock must be held to guarantee that the page does
  * not vanish from under us.
  */
 static void get_map(struct kmem_cache *s, struct page *page, unsigned long *map)
@@ -838,10 +929,11 @@ static int check_slab(struct kmem_cache *s, struct page *page)
 static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
 {
        int nr = 0;
-       void *fp = page->freelist;
+       void *fp;
        void *object = NULL;
        unsigned long max_objects;
 
+       fp = page->freelist;
        while (fp && nr <= page->objects) {
                if (fp == search)
                        return 1;
@@ -946,26 +1038,27 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
 
 /*
  * Tracking of fully allocated slabs for debugging purposes.
+ *
+ * list_lock must be held.
  */
-static void add_full(struct kmem_cache_node *n, struct page *page)
+static void add_full(struct kmem_cache *s,
+       struct kmem_cache_node *n, struct page *page)
 {
-       spin_lock(&n->list_lock);
+       if (!(s->flags & SLAB_STORE_USER))
+               return;
+
        list_add(&page->lru, &n->full);
-       spin_unlock(&n->list_lock);
 }
 
+/*
+ * list_lock must be held.
+ */
 static void remove_full(struct kmem_cache *s, struct page *page)
 {
-       struct kmem_cache_node *n;
-
        if (!(s->flags & SLAB_STORE_USER))
                return;
 
-       n = get_node(s, page_to_nid(page));
-
-       spin_lock(&n->list_lock);
        list_del(&page->lru);
-       spin_unlock(&n->list_lock);
 }
 
 /* Tracking of the number of slabs for debugging purposes */
@@ -1021,11 +1114,6 @@ static noinline int alloc_debug_processing(struct kmem_cache *s, struct page *pa
        if (!check_slab(s, page))
                goto bad;
 
-       if (!on_freelist(s, page, object)) {
-               object_err(s, page, object, "Object already allocated");
-               goto bad;
-       }
-
        if (!check_valid_pointer(s, page, object)) {
                object_err(s, page, object, "Freelist Pointer check fails");
                goto bad;
@@ -1058,6 +1146,12 @@ bad:
 static noinline int free_debug_processing(struct kmem_cache *s,
                 struct page *page, void *object, unsigned long addr)
 {
+       unsigned long flags;
+       int rc = 0;
+
+       local_irq_save(flags);
+       slab_lock(page);
+
        if (!check_slab(s, page))
                goto fail;
 
@@ -1072,7 +1166,7 @@ static noinline int free_debug_processing(struct kmem_cache *s,
        }
 
        if (!check_object(s, page, object, SLUB_RED_ACTIVE))
-               return 0;
+               goto out;
 
        if (unlikely(s != page->slab)) {
                if (!PageSlab(page)) {
@@ -1089,18 +1183,19 @@ static noinline int free_debug_processing(struct kmem_cache *s,
                goto fail;
        }
 
-       /* Special debug activities for freeing objects */
-       if (!PageSlubFrozen(page) && !page->freelist)
-               remove_full(s, page);
        if (s->flags & SLAB_STORE_USER)
                set_track(s, object, TRACK_FREE, addr);
        trace(s, page, object, 0);
        init_object(s, object, SLUB_RED_INACTIVE);
-       return 1;
+       rc = 1;
+out:
+       slab_unlock(page);
+       local_irq_restore(flags);
+       return rc;
 
 fail:
        slab_fix(s, "Object at 0x%p not freed", object);
-       return 0;
+       goto out;
 }
 
 static int __init setup_slub_debug(char *str)
@@ -1200,7 +1295,9 @@ static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
                        { return 1; }
 static inline int check_object(struct kmem_cache *s, struct page *page,
                        void *object, u8 val) { return 1; }
-static inline void add_full(struct kmem_cache_node *n, struct page *page) {}
+static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
+                                       struct page *page) {}
+static inline void remove_full(struct kmem_cache *s, struct page *page) {}
 static inline unsigned long kmem_cache_flags(unsigned long objsize,
        unsigned long flags, const char *name,
        void (*ctor)(void *))
@@ -1252,6 +1349,11 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
        struct kmem_cache_order_objects oo = s->oo;
        gfp_t alloc_gfp;
 
+       flags &= gfp_allowed_mask;
+
+       if (flags & __GFP_WAIT)
+               local_irq_enable();
+
        flags |= s->allocflags;
 
        /*
@@ -1268,12 +1370,17 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
                 * Try a lower order alloc if possible
                 */
                page = alloc_slab_page(flags, node, oo);
-               if (!page)
-                       return NULL;
 
-               stat(s, ORDER_FALLBACK);
+               if (page)
+                       stat(s, ORDER_FALLBACK);
        }
 
+       if (flags & __GFP_WAIT)
+               local_irq_disable();
+
+       if (!page)
+               return NULL;
+
        if (kmemcheck_enabled
                && !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) {
                int pages = 1 << oo_order(oo);
@@ -1341,6 +1448,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
 
        page->freelist = start;
        page->inuse = 0;
+       page->frozen = 1;
 out:
        return page;
 }
@@ -1418,77 +1526,87 @@ static void discard_slab(struct kmem_cache *s, struct page *page)
 }
 
 /*
- * Per slab locking using the pagelock
- */
-static __always_inline void slab_lock(struct page *page)
-{
-       bit_spin_lock(PG_locked, &page->flags);
-}
-
-static __always_inline void slab_unlock(struct page *page)
-{
-       __bit_spin_unlock(PG_locked, &page->flags);
-}
-
-static __always_inline int slab_trylock(struct page *page)
-{
-       int rc = 1;
-
-       rc = bit_spin_trylock(PG_locked, &page->flags);
-       return rc;
-}
-
-/*
- * Management of partially allocated slabs
+ * Management of partially allocated slabs.
+ *
+ * list_lock must be held.
  */
-static void add_partial(struct kmem_cache_node *n,
+static inline void add_partial(struct kmem_cache_node *n,
                                struct page *page, int tail)
 {
-       spin_lock(&n->list_lock);
        n->nr_partial++;
        if (tail)
                list_add_tail(&page->lru, &n->partial);
        else
                list_add(&page->lru, &n->partial);
-       spin_unlock(&n->list_lock);
 }
 
-static inline void __remove_partial(struct kmem_cache_node *n,
+/*
+ * list_lock must be held.
+ */
+static inline void remove_partial(struct kmem_cache_node *n,
                                        struct page *page)
 {
        list_del(&page->lru);
        n->nr_partial--;
 }
 
-static void remove_partial(struct kmem_cache *s, struct page *page)
-{
-       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
-
-       spin_lock(&n->list_lock);
-       __remove_partial(n, page);
-       spin_unlock(&n->list_lock);
-}
-
 /*
- * Lock slab and remove from the partial list.
+ * Lock slab, remove from the partial list and put the object into the
+ * per cpu freelist.
  *
  * Must hold list_lock.
  */
-static inline int lock_and_freeze_slab(struct kmem_cache_node *n,
-                                                       struct page *page)
+static inline int acquire_slab(struct kmem_cache *s,
+               struct kmem_cache_node *n, struct page *page)
 {
-       if (slab_trylock(page)) {
-               __remove_partial(n, page);
-               __SetPageSlubFrozen(page);
+       void *freelist;
+       unsigned long counters;
+       struct page new;
+
+       /*
+        * Zap the freelist and set the frozen bit.
+        * The old freelist is the list of objects for the
+        * per cpu allocation list.
+        */
+       do {
+               freelist = page->freelist;
+               counters = page->counters;
+               new.counters = counters;
+               new.inuse = page->objects;
+
+               VM_BUG_ON(new.frozen);
+               new.frozen = 1;
+
+       } while (!__cmpxchg_double_slab(s, page,
+                       freelist, counters,
+                       NULL, new.counters,
+                       "lock and freeze"));
+
+       remove_partial(n, page);
+
+       if (freelist) {
+               /* Populate the per cpu freelist */
+               this_cpu_write(s->cpu_slab->freelist, freelist);
+               this_cpu_write(s->cpu_slab->page, page);
+               this_cpu_write(s->cpu_slab->node, page_to_nid(page));
                return 1;
+       } else {
+               /*
+                * Slab page came from the wrong list. No object to allocate
+                * from. Put it onto the correct list and continue partial
+                * scan.
+                */
+               printk(KERN_ERR "SLUB: %s : Page without available objects on"
+                       " partial list\n", s->name);
+               return 0;
        }
-       return 0;
 }
 
 /*
  * Try to allocate a partial slab from a specific node.
  */
-static struct page *get_partial_node(struct kmem_cache_node *n)
+static struct page *get_partial_node(struct kmem_cache *s,
+                                       struct kmem_cache_node *n)
 {
        struct page *page;
 
@@ -1503,7 +1621,7 @@ static struct page *get_partial_node(struct kmem_cache_node *n)
 
        spin_lock(&n->list_lock);
        list_for_each_entry(page, &n->partial, lru)
-               if (lock_and_freeze_slab(n, page))
+               if (acquire_slab(s, n, page))
                        goto out;
        page = NULL;
 out:
@@ -1554,7 +1672,7 @@ static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
 
                if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
                                n->nr_partial > s->min_partial) {
-                       page = get_partial_node(n);
+                       page = get_partial_node(s, n);
                        if (page) {
                                put_mems_allowed();
                                return page;
@@ -1574,60 +1692,13 @@ static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node)
        struct page *page;
        int searchnode = (node == NUMA_NO_NODE) ? numa_node_id() : node;
 
-       page = get_partial_node(get_node(s, searchnode));
+       page = get_partial_node(s, get_node(s, searchnode));
        if (page || node != NUMA_NO_NODE)
                return page;
 
        return get_any_partial(s, flags);
 }
 
-/*
- * Move a page back to the lists.
- *
- * Must be called with the slab lock held.
- *
- * On exit the slab lock will have been dropped.
- */
-static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
-       __releases(bitlock)
-{
-       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
-
-       __ClearPageSlubFrozen(page);
-       if (page->inuse) {
-
-               if (page->freelist) {
-                       add_partial(n, page, tail);
-                       stat(s, tail ? DEACTIVATE_TO_TAIL : DEACTIVATE_TO_HEAD);
-               } else {
-                       stat(s, DEACTIVATE_FULL);
-                       if (kmem_cache_debug(s) && (s->flags & SLAB_STORE_USER))
-                               add_full(n, page);
-               }
-               slab_unlock(page);
-       } else {
-               stat(s, DEACTIVATE_EMPTY);
-               if (n->nr_partial < s->min_partial) {
-                       /*
-                        * Adding an empty slab to the partial slabs in order
-                        * to avoid page allocator overhead. This slab needs
-                        * to come after the other slabs with objects in
-                        * so that the others get filled first. That way the
-                        * size of the partial list stays small.
-                        *
-                        * kmem_cache_shrink can reclaim any empty slabs from
-                        * the partial list.
-                        */
-                       add_partial(n, page, 1);
-                       slab_unlock(page);
-               } else {
-                       slab_unlock(page);
-                       stat(s, FREE_SLAB);
-                       discard_slab(s, page);
-               }
-       }
-}
-
 #ifdef CONFIG_PREEMPT
 /*
  * Calculate the next globally unique transaction for disambiguiation
@@ -1694,45 +1765,164 @@ void init_kmem_cache_cpus(struct kmem_cache *s)
        for_each_possible_cpu(cpu)
                per_cpu_ptr(s->cpu_slab, cpu)->tid = init_tid(cpu);
 }
+/*
+ * Remove the cpu slab
+ */
+
 /*
  * Remove the cpu slab
  */
 static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
-       __releases(bitlock)
 {
+       enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
        struct page *page = c->page;
-       int tail = 1;
-
-       if (page->freelist)
+       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+       int lock = 0;
+       enum slab_modes l = M_NONE, m = M_NONE;
+       void *freelist;
+       void *nextfree;
+       int tail = 0;
+       struct page new;
+       struct page old;
+
+       if (page->freelist) {
                stat(s, DEACTIVATE_REMOTE_FREES);
+               tail = 1;
+       }
+
+       c->tid = next_tid(c->tid);
+       c->page = NULL;
+       freelist = c->freelist;
+       c->freelist = NULL;
+
+       /*
+        * Stage one: Free all available per cpu objects back
+        * to the page freelist while it is still frozen. Leave the
+        * last one.
+        *
+        * There is no need to take the list->lock because the page
+        * is still frozen.
+        */
+       while (freelist && (nextfree = get_freepointer(s, freelist))) {
+               void *prior;
+               unsigned long counters;
+
+               do {
+                       prior = page->freelist;
+                       counters = page->counters;
+                       set_freepointer(s, freelist, prior);
+                       new.counters = counters;
+                       new.inuse--;
+                       VM_BUG_ON(!new.frozen);
+
+               } while (!__cmpxchg_double_slab(s, page,
+                       prior, counters,
+                       freelist, new.counters,
+                       "drain percpu freelist"));
+
+               freelist = nextfree;
+       }
+
        /*
-        * Merge cpu freelist into slab freelist. Typically we get here
-        * because both freelists are empty. So this is unlikely
-        * to occur.
+        * Stage two: Ensure that the page is unfrozen while the
+        * list presence reflects the actual number of objects
+        * during unfreeze.
+        *
+        * We setup the list membership and then perform a cmpxchg
+        * with the count. If there is a mismatch then the page
+        * is not unfrozen but the page is on the wrong list.
+        *
+        * Then we restart the process which may have to remove
+        * the page from the list that we just put it on again
+        * because the number of objects in the slab may have
+        * changed.
         */
-       while (unlikely(c->freelist)) {
-               void **object;
+redo:
 
-               tail = 0;       /* Hot objects. Put the slab first */
+       old.freelist = page->freelist;
+       old.counters = page->counters;
+       VM_BUG_ON(!old.frozen);
 
-               /* Retrieve object from cpu_freelist */
-               object = c->freelist;
-               c->freelist = get_freepointer(s, c->freelist);
+       /* Determine target state of the slab */
+       new.counters = old.counters;
+       if (freelist) {
+               new.inuse--;
+               set_freepointer(s, freelist, old.freelist);
+               new.freelist = freelist;
+       } else
+               new.freelist = old.freelist;
+
+       new.frozen = 0;
+
+       if (!new.inuse && n->nr_partial < s->min_partial)
+               m = M_FREE;
+       else if (new.freelist) {
+               m = M_PARTIAL;
+               if (!lock) {
+                       lock = 1;
+                       /*
+                        * Taking the spinlock removes the possiblity
+                        * that acquire_slab() will see a slab page that
+                        * is frozen
+                        */
+                       spin_lock(&n->list_lock);
+               }
+       } else {
+               m = M_FULL;
+               if (kmem_cache_debug(s) && !lock) {
+                       lock = 1;
+                       /*
+                        * This also ensures that the scanning of full
+                        * slabs from diagnostic functions will not see
+                        * any frozen slabs.
+                        */
+                       spin_lock(&n->list_lock);
+               }
+       }
+
+       if (l != m) {
+
+               if (l == M_PARTIAL)
+
+                       remove_partial(n, page);
+
+               else if (l == M_FULL)
+
+                       remove_full(s, page);
+
+               if (m == M_PARTIAL) {
+
+                       add_partial(n, page, tail);
+                       stat(s, tail ? DEACTIVATE_TO_TAIL : DEACTIVATE_TO_HEAD);
+
+               } else if (m == M_FULL) {
 
-               /* And put onto the regular freelist */
-               set_freepointer(s, object, page->freelist);
-               page->freelist = object;
-               page->inuse--;
+                       stat(s, DEACTIVATE_FULL);
+                       add_full(s, n, page);
+
+               }
+       }
+
+       l = m;
+       if (!__cmpxchg_double_slab(s, page,
+                               old.freelist, old.counters,
+                               new.freelist, new.counters,
+                               "unfreezing slab"))
+               goto redo;
+
+       if (lock)
+               spin_unlock(&n->list_lock);
+
+       if (m == M_FREE) {
+               stat(s, DEACTIVATE_EMPTY);
+               discard_slab(s, page);
+               stat(s, FREE_SLAB);
        }
-       c->page = NULL;
-       c->tid = next_tid(c->tid);
-       unfreeze_slab(s, page, tail);
 }
 
 static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
 {
        stat(s, CPUSLAB_FLUSH);
-       slab_lock(c->page);
        deactivate_slab(s, c);
 }
 
@@ -1861,6 +2051,8 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
        void **object;
        struct page *page;
        unsigned long flags;
+       struct page new;
+       unsigned long counters;
 
        local_irq_save(flags);
 #ifdef CONFIG_PREEMPT
@@ -1879,72 +2071,97 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
        if (!page)
                goto new_slab;
 
-       slab_lock(page);
-       if (unlikely(!node_match(c, node)))
-               goto another_slab;
+       if (unlikely(!node_match(c, node))) {
+               stat(s, ALLOC_NODE_MISMATCH);
+               deactivate_slab(s, c);
+               goto new_slab;
+       }
+
+       stat(s, ALLOC_SLOWPATH);
+
+       do {
+               object = page->freelist;
+               counters = page->counters;
+               new.counters = counters;
+               VM_BUG_ON(!new.frozen);
+
+               /*
+                * If there is no object left then we use this loop to
+                * deactivate the slab which is simple since no objects
+                * are left in the slab and therefore we do not need to
+                * put the page back onto the partial list.
+                *
+                * If there are objects left then we retrieve them
+                * and use them to refill the per cpu queue.
+               */
+
+               new.inuse = page->objects;
+               new.frozen = object != NULL;
+
+       } while (!__cmpxchg_double_slab(s, page,
+                       object, counters,
+                       NULL, new.counters,
+                       "__slab_alloc"));
+
+       if (unlikely(!object)) {
+               c->page = NULL;
+               stat(s, DEACTIVATE_BYPASS);
+               goto new_slab;
+       }
 
        stat(s, ALLOC_REFILL);
 
 load_freelist:
-       object = page->freelist;
-       if (unlikely(!object))
-               goto another_slab;
-       if (kmem_cache_debug(s))
-               goto debug;
-
+       VM_BUG_ON(!page->frozen);
        c->freelist = get_freepointer(s, object);
-       page->inuse = page->objects;
-       page->freelist = NULL;
-
-       slab_unlock(page);
        c->tid = next_tid(c->tid);
        local_irq_restore(flags);
-       stat(s, ALLOC_SLOWPATH);
        return object;
 
-another_slab:
-       deactivate_slab(s, c);
-
 new_slab:
        page = get_partial(s, gfpflags, node);
        if (page) {
                stat(s, ALLOC_FROM_PARTIAL);
-               c->node = page_to_nid(page);
-               c->page = page;
+               object = c->freelist;
+
+               if (kmem_cache_debug(s))
+                       goto debug;
                goto load_freelist;
        }
 
-       gfpflags &= gfp_allowed_mask;
-       if (gfpflags & __GFP_WAIT)
-               local_irq_enable();
-
        page = new_slab(s, gfpflags, node);
 
-       if (gfpflags & __GFP_WAIT)
-               local_irq_disable();
-
        if (page) {
                c = __this_cpu_ptr(s->cpu_slab);
-               stat(s, ALLOC_SLAB);
                if (c->page)
                        flush_slab(s, c);
 
-               slab_lock(page);
-               __SetPageSlubFrozen(page);
+               /*
+                * No other reference to the page yet so we can
+                * muck around with it freely without cmpxchg
+                */
+               object = page->freelist;
+               page->freelist = NULL;
+               page->inuse = page->objects;
+
+               stat(s, ALLOC_SLAB);
                c->node = page_to_nid(page);
                c->page = page;
+
+               if (kmem_cache_debug(s))
+                       goto debug;
                goto load_freelist;
        }
        if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
                slab_out_of_memory(s, gfpflags, node);
        local_irq_restore(flags);
        return NULL;
+
 debug:
-       if (!alloc_debug_processing(s, page, object, addr))
-               goto another_slab;
+       if (!object || !alloc_debug_processing(s, page, object, addr))
+               goto new_slab;
 
-       page->inuse++;
-       page->freelist = get_freepointer(s, object);
+       c->freelist = get_freepointer(s, object);
        deactivate_slab(s, c);
        c->page = NULL;
        c->node = NUMA_NO_NODE;
@@ -2096,40 +2313,75 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
 {
        void *prior;
        void **object = (void *)x;
-       unsigned long flags;
+       int was_frozen;
+       int inuse;
+       struct page new;
+       unsigned long counters;
+       struct kmem_cache_node *n = NULL;
+       unsigned long uninitialized_var(flags);
 
-       local_irq_save(flags);
-       slab_lock(page);
        stat(s, FREE_SLOWPATH);
 
        if (kmem_cache_debug(s) && !free_debug_processing(s, page, x, addr))
-               goto out_unlock;
+               return;
 
-       prior = page->freelist;
-       set_freepointer(s, object, prior);
-       page->freelist = object;
-       page->inuse--;
+       do {
+               prior = page->freelist;
+               counters = page->counters;
+               set_freepointer(s, object, prior);
+               new.counters = counters;
+               was_frozen = new.frozen;
+               new.inuse--;
+               if ((!new.inuse || !prior) && !was_frozen && !n) {
+                        n = get_node(s, page_to_nid(page));
+                       /*
+                        * Speculatively acquire the list_lock.
+                        * If the cmpxchg does not succeed then we may
+                        * drop the list_lock without any processing.
+                        *
+                        * Otherwise the list_lock will synchronize with
+                        * other processors updating the list of slabs.
+                        */
+                        spin_lock_irqsave(&n->list_lock, flags);
+               }
+               inuse = new.inuse;
 
-       if (unlikely(PageSlubFrozen(page))) {
-               stat(s, FREE_FROZEN);
-               goto out_unlock;
-       }
+       } while (!cmpxchg_double_slab(s, page,
+               prior, counters,
+               object, new.counters,
+               "__slab_free"));
 
-       if (unlikely(!page->inuse))
-               goto slab_empty;
+       if (likely(!n)) {
+                /*
+                * The list lock was not taken therefore no list
+                * activity can be necessary.
+                */
+                if (was_frozen)
+                        stat(s, FREE_FROZEN);
+                return;
+        }
 
        /*
-        * Objects left in the slab. If it was not on the partial list before
-        * then add it.
+        * was_frozen may have been set after we acquired the list_lock in
+        * an earlier loop. So we need to check it here again.
         */
-       if (unlikely(!prior)) {
-               add_partial(get_node(s, page_to_nid(page)), page, 1);
-               stat(s, FREE_ADD_PARTIAL);
-       }
+       if (was_frozen)
+               stat(s, FREE_FROZEN);
+       else {
+               if (unlikely(!inuse && n->nr_partial > s->min_partial))
+                        goto slab_empty;
 
-out_unlock:
-       slab_unlock(page);
-       local_irq_restore(flags);
+               /*
+                * Objects left in the slab. If it was not on the partial list before
+                * then add it.
+                */
+               if (unlikely(!prior)) {
+                       remove_full(s, page);
+                       add_partial(n, page, 0);
+                       stat(s, FREE_ADD_PARTIAL);
+               }
+       }
+       spin_unlock_irqrestore(&n->list_lock, flags);
        return;
 
 slab_empty:
@@ -2137,11 +2389,11 @@ slab_empty:
                /*
                 * Slab still on the partial list.
                 */
-               remove_partial(s, page);
+               remove_partial(n, page);
                stat(s, FREE_REMOVE_PARTIAL);
        }
-       slab_unlock(page);
-       local_irq_restore(flags);
+
+       spin_unlock_irqrestore(&n->list_lock, flags);
        stat(s, FREE_SLAB);
        discard_slab(s, page);
 }
@@ -2415,7 +2667,6 @@ static void early_kmem_cache_node_alloc(int node)
 {
        struct page *page;
        struct kmem_cache_node *n;
-       unsigned long flags;
 
        BUG_ON(kmem_cache_node->size < sizeof(struct kmem_cache_node));
 
@@ -2433,6 +2684,7 @@ static void early_kmem_cache_node_alloc(int node)
        BUG_ON(!n);
        page->freelist = get_freepointer(kmem_cache_node, n);
        page->inuse++;
+       page->frozen = 0;
        kmem_cache_node->node[node] = n;
 #ifdef CONFIG_SLUB_DEBUG
        init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
@@ -2441,14 +2693,7 @@ static void early_kmem_cache_node_alloc(int node)
        init_kmem_cache_node(n, kmem_cache_node);
        inc_slabs_node(kmem_cache_node, node, page->objects);
 
-       /*
-        * lockdep requires consistent irq usage for each lock
-        * so even though there cannot be a race this early in
-        * the boot sequence, we still disable irqs.
-        */
-       local_irq_save(flags);
        add_partial(n, page, 0);
-       local_irq_restore(flags);
 }
 
 static void free_kmem_cache_nodes(struct kmem_cache *s)
@@ -2654,6 +2899,12 @@ static int kmem_cache_open(struct kmem_cache *s,
                }
        }
 
+#ifdef CONFIG_CMPXCHG_DOUBLE
+       if (system_has_cmpxchg_double() && (s->flags & SLAB_DEBUG_FLAGS) == 0)
+               /* Enable fast mode */
+               s->flags |= __CMPXCHG_DOUBLE;
+#endif
+
        /*
         * The larger the object size is, the more pages we want on the partial
         * list to avoid pounding the page allocator excessively.
@@ -2726,7 +2977,7 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
        spin_lock_irqsave(&n->list_lock, flags);
        list_for_each_entry_safe(page, h, &n->partial, lru) {
                if (!page->inuse) {
-                       __remove_partial(n, page);
+                       remove_partial(n, page);
                        discard_slab(s, page);
                } else {
                        list_slab_objects(s, page,
@@ -3094,14 +3345,8 @@ int kmem_cache_shrink(struct kmem_cache *s)
                 * list_lock. page->inuse here is the upper limit.
                 */
                list_for_each_entry_safe(page, t, &n->partial, lru) {
-                       if (!page->inuse && slab_trylock(page)) {
-                               /*
-                                * Must hold slab lock here because slab_free
-                                * may have freed the last object and be
-                                * waiting to release the slab.
-                                */
-                               __remove_partial(n, page);
-                               slab_unlock(page);
+                       if (!page->inuse) {
+                               remove_partial(n, page);
                                discard_slab(s, page);
                        } else {
                                list_move(&page->lru,
@@ -3689,12 +3934,9 @@ static int validate_slab(struct kmem_cache *s, struct page *page,
 static void validate_slab_slab(struct kmem_cache *s, struct page *page,
                                                unsigned long *map)
 {
-       if (slab_trylock(page)) {
-               validate_slab(s, page, map);
-               slab_unlock(page);
-       } else
-               printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
-                       s->name, page);
+       slab_lock(page);
+       validate_slab(s, page, map);
+       slab_unlock(page);
 }
 
 static int validate_slab_node(struct kmem_cache *s,
@@ -4342,8 +4584,10 @@ static ssize_t sanity_checks_store(struct kmem_cache *s,
                                const char *buf, size_t length)
 {
        s->flags &= ~SLAB_DEBUG_FREE;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_DEBUG_FREE;
+       }
        return length;
 }
 SLAB_ATTR(sanity_checks);
@@ -4357,8 +4601,10 @@ static ssize_t trace_store(struct kmem_cache *s, const char *buf,
                                                        size_t length)
 {
        s->flags &= ~SLAB_TRACE;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_TRACE;
+       }
        return length;
 }
 SLAB_ATTR(trace);
@@ -4375,8 +4621,10 @@ static ssize_t red_zone_store(struct kmem_cache *s,
                return -EBUSY;
 
        s->flags &= ~SLAB_RED_ZONE;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_RED_ZONE;
+       }
        calculate_sizes(s, -1);
        return length;
 }
@@ -4394,8 +4642,10 @@ static ssize_t poison_store(struct kmem_cache *s,
                return -EBUSY;
 
        s->flags &= ~SLAB_POISON;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_POISON;
+       }
        calculate_sizes(s, -1);
        return length;
 }
@@ -4413,8 +4663,10 @@ static ssize_t store_user_store(struct kmem_cache *s,
                return -EBUSY;
 
        s->flags &= ~SLAB_STORE_USER;
-       if (buf[0] == '1')
+       if (buf[0] == '1') {
+               s->flags &= ~__CMPXCHG_DOUBLE;
                s->flags |= SLAB_STORE_USER;
+       }
        calculate_sizes(s, -1);
        return length;
 }
@@ -4579,6 +4831,7 @@ STAT_ATTR(FREE_REMOVE_PARTIAL, free_remove_partial);
 STAT_ATTR(ALLOC_FROM_PARTIAL, alloc_from_partial);
 STAT_ATTR(ALLOC_SLAB, alloc_slab);
 STAT_ATTR(ALLOC_REFILL, alloc_refill);
+STAT_ATTR(ALLOC_NODE_MISMATCH, alloc_node_mismatch);
 STAT_ATTR(FREE_SLAB, free_slab);
 STAT_ATTR(CPUSLAB_FLUSH, cpuslab_flush);
 STAT_ATTR(DEACTIVATE_FULL, deactivate_full);
@@ -4586,7 +4839,10 @@ STAT_ATTR(DEACTIVATE_EMPTY, deactivate_empty);
 STAT_ATTR(DEACTIVATE_TO_HEAD, deactivate_to_head);
 STAT_ATTR(DEACTIVATE_TO_TAIL, deactivate_to_tail);
 STAT_ATTR(DEACTIVATE_REMOTE_FREES, deactivate_remote_frees);
+STAT_ATTR(DEACTIVATE_BYPASS, deactivate_bypass);
 STAT_ATTR(ORDER_FALLBACK, order_fallback);
+STAT_ATTR(CMPXCHG_DOUBLE_CPU_FAIL, cmpxchg_double_cpu_fail);
+STAT_ATTR(CMPXCHG_DOUBLE_FAIL, cmpxchg_double_fail);
 #endif
 
 static struct attribute *slab_attrs[] = {
@@ -4636,6 +4892,7 @@ static struct attribute *slab_attrs[] = {
        &alloc_from_partial_attr.attr,
        &alloc_slab_attr.attr,
        &alloc_refill_attr.attr,
+       &alloc_node_mismatch_attr.attr,
        &free_slab_attr.attr,
        &cpuslab_flush_attr.attr,
        &deactivate_full_attr.attr,
@@ -4643,7 +4900,10 @@ static struct attribute *slab_attrs[] = {
        &deactivate_to_head_attr.attr,
        &deactivate_to_tail_attr.attr,
        &deactivate_remote_frees_attr.attr,
+       &deactivate_bypass_attr.attr,
        &order_fallback_attr.attr,
+       &cmpxchg_double_fail_attr.attr,
+       &cmpxchg_double_cpu_fail_attr.attr,
 #endif
 #ifdef CONFIG_FAILSLAB
        &failslab_attr.attr,
index 934e221c1d071e5403bd805e0064debc19d5b3f0..9d40a071d0382e7e893483066fa3bb5285fa8bc0 100644 (file)
@@ -695,7 +695,7 @@ void vlan_setup(struct net_device *dev)
        ether_setup(dev);
 
        dev->priv_flags         |= IFF_802_1Q_VLAN;
-       dev->priv_flags         &= ~IFF_XMIT_DST_RELEASE;
+       dev->priv_flags         &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
        dev->tx_queue_len       = 0;
 
        dev->netdev_ops         = &vlan_netdev_ops;
index 8c100c9dae2833bcf3963a2cc4c8a9a2fcbdc064..d4f5dff7c95510f9b31cbd0797210f9105c0e098 100644 (file)
@@ -231,6 +231,7 @@ void bnep_net_setup(struct net_device *dev)
        dev->addr_len = ETH_ALEN;
 
        ether_setup(dev);
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->netdev_ops = &bnep_netdev_ops;
 
        dev->watchdog_timeo  = HZ * 2;
index 9444c5cb413798f8b620f1a3a6b703a7c413e55e..17d67b579beb0c3f6f97bfd8add5d7027741854a 100644 (file)
@@ -4497,10 +4497,10 @@ void __dev_set_rx_mode(struct net_device *dev)
                 */
                if (!netdev_uc_empty(dev) && !dev->uc_promisc) {
                        __dev_set_promiscuity(dev, 1);
-                       dev->uc_promisc = 1;
+                       dev->uc_promisc = true;
                } else if (netdev_uc_empty(dev) && dev->uc_promisc) {
                        __dev_set_promiscuity(dev, -1);
-                       dev->uc_promisc = 0;
+                       dev->uc_promisc = false;
                }
 
                if (ops->ndo_set_multicast_list)
index f76079cd750c618da16014b97a4d781bbc65e878..e35a6fbb81107229d05610ae89161905c927d6a0 100644 (file)
@@ -1070,7 +1070,9 @@ static ssize_t pktgen_if_write(struct file *file,
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
                        return len;
-
+               if ((value > 0) &&
+                   (!(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
+                       return -ENOTSUPP;
                i += len;
                pkt_dev->clone_skb = value;
 
@@ -3555,7 +3557,6 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
        pkt_dev->min_pkt_size = ETH_ZLEN;
        pkt_dev->max_pkt_size = ETH_ZLEN;
        pkt_dev->nfrags = 0;
-       pkt_dev->clone_skb = pg_clone_skb_d;
        pkt_dev->delay = pg_delay_d;
        pkt_dev->count = pg_count_d;
        pkt_dev->sofar = 0;
@@ -3563,7 +3564,6 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
        pkt_dev->udp_src_max = 9;
        pkt_dev->udp_dst_min = 9;
        pkt_dev->udp_dst_max = 9;
-
        pkt_dev->vlan_p = 0;
        pkt_dev->vlan_cfi = 0;
        pkt_dev->vlan_id = 0xffff;
@@ -3575,6 +3575,8 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
        err = pktgen_setup_dev(pkt_dev, ifname);
        if (err)
                goto out1;
+       if (pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)
+               pkt_dev->clone_skb = pg_clone_skb_d;
 
        pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir,
                                          &pktgen_if_fops, pkt_dev);
index 5cffb63f481a9a43f8af4c7f5e69e26e45a7aa06..27997d35ebd3f405bf1df2a2d2d599bfe7fbbdb9 100644 (file)
@@ -231,6 +231,7 @@ EXPORT_SYMBOL(eth_header_parse);
  * eth_header_cache - fill cache entry from neighbour
  * @neigh: source neighbour
  * @hh: destination cache entry
+ * @type: Ethernet type field
  * Create an Ethernet header template from the neighbour.
  */
 int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh, __be16 type)
@@ -339,6 +340,7 @@ void ether_setup(struct net_device *dev)
        dev->addr_len           = ETH_ALEN;
        dev->tx_queue_len       = 1000; /* Ethernet wants good queues */
        dev->flags              = IFF_BROADCAST|IFF_MULTICAST;
+       dev->priv_flags         = IFF_TX_SKB_SHARING;
 
        memset(dev->broadcast, 0xFF, ETH_ALEN);
 
index 37b3c188d8b3391db01bab97dbb9b87d8ca1efbb..bc19bd06dd006f548282e25f33c7d6ef056a54ac 100644 (file)
@@ -1134,15 +1134,15 @@ static void inetdev_send_gratuitous_arp(struct net_device *dev,
                                        struct in_device *in_dev)
 
 {
-       struct in_ifaddr *ifa = in_dev->ifa_list;
-
-       if (!ifa)
-               return;
+       struct in_ifaddr *ifa;
 
-       arp_send(ARPOP_REQUEST, ETH_P_ARP,
-                ifa->ifa_local, dev,
-                ifa->ifa_local, NULL,
-                dev->dev_addr, NULL);
+       for (ifa = in_dev->ifa_list; ifa;
+            ifa = ifa->ifa_next) {
+               arp_send(ARPOP_REQUEST, ETH_P_ARP,
+                        ifa->ifa_local, dev,
+                        ifa->ifa_local, NULL,
+                        dev->dev_addr, NULL);
+       }
 }
 
 /* Called only under RTNL semaphore */
index a06c53c14d841e07083ca9dbab9423bf607d914d..a55500cc0b29ab710e012d42f0862a95f4750669 100644 (file)
@@ -1481,6 +1481,8 @@ static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
 static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
 {
        struct in6_addr addr;
+       if (ifp->prefix_len == 127) /* RFC 6164 */
+               return;
        ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
        if (ipv6_addr_any(&addr))
                return;
index a8193f52c13c28ddb17c3e1c100b009d259a3d8f..d2726a74597d104eb3fa57b2f6b48ab297106f23 100644 (file)
@@ -103,7 +103,7 @@ static struct net_device_ops l2tp_eth_netdev_ops = {
 static void l2tp_eth_dev_setup(struct net_device *dev)
 {
        ether_setup(dev);
-
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->netdev_ops         = &l2tp_eth_netdev_ops;
        dev->destructor         = free_netdev;
 }
index cd5fb40d3fd4bbb7579d21e8a37a1e27a1e1ffe4..556e7e6ddf0a6b26dda29a33c00ee6c4d0ffed5b 100644 (file)
@@ -698,6 +698,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
 static void ieee80211_if_setup(struct net_device *dev)
 {
        ether_setup(dev);
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->netdev_ops = &ieee80211_dataif_ops;
        dev->destructor = free_netdev;
 }
index 26ed35c7751e230361d3ef5fc461b1e30c99c5ea..b1cbbcd9255854a7d52571688160bf3d87baf483 100644 (file)
@@ -580,7 +580,7 @@ int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 }
 EXPORT_SYMBOL(sock_sendmsg);
 
-int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size)
+static int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size)
 {
        struct kiocb iocb;
        struct sock_iocb siocb;
index b2198e65d8bbec47798ccd841707e40c844dc908..ffd243d09188dee10d2dffa34d642f7c941b9013 100644 (file)
@@ -4,6 +4,10 @@ config SUNRPC
 config SUNRPC_GSS
        tristate
 
+config SUNRPC_BACKCHANNEL
+       bool
+       depends on SUNRPC
+
 config SUNRPC_XPRT_RDMA
        tristate
        depends on SUNRPC && INFINIBAND && INFINIBAND_ADDR_TRANS && EXPERIMENTAL
index 9d2fca5ad14a889c36cc5e782c10bcd64d959e97..8209a0411bca18ca92f5d13175bc04ffa09d1812 100644 (file)
@@ -13,6 +13,6 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
            addr.o rpcb_clnt.o timer.o xdr.o \
            sunrpc_syms.o cache.o rpc_pipe.o \
            svc_xprt.o
-sunrpc-$(CONFIG_NFS_V4_1) += backchannel_rqst.o bc_svc.o
+sunrpc-$(CONFIG_SUNRPC_BACKCHANNEL) += backchannel_rqst.o bc_svc.o
 sunrpc-$(CONFIG_PROC_FS) += stats.o
 sunrpc-$(CONFIG_SYSCTL) += sysctl.o
index cf06af3b63c676068343b46941bc1dd59380440a..91eaa26e4c425e184bb74088d00fe47d233c4343 100644 (file)
@@ -29,8 +29,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define RPCDBG_FACILITY        RPCDBG_TRANS
 #endif
 
-#if defined(CONFIG_NFS_V4_1)
-
 /*
  * Helper routines that track the number of preallocation elements
  * on the transport.
@@ -174,7 +172,7 @@ out_free:
        dprintk("RPC:       setup backchannel transport failed\n");
        return -1;
 }
-EXPORT_SYMBOL(xprt_setup_backchannel);
+EXPORT_SYMBOL_GPL(xprt_setup_backchannel);
 
 /*
  * Destroys the backchannel preallocated structures.
@@ -204,7 +202,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
        dprintk("RPC:        backchannel list empty= %s\n",
                list_empty(&xprt->bc_pa_list) ? "true" : "false");
 }
-EXPORT_SYMBOL(xprt_destroy_backchannel);
+EXPORT_SYMBOL_GPL(xprt_destroy_backchannel);
 
 /*
  * One or more rpc_rqst structure have been preallocated during the
@@ -279,4 +277,3 @@ void xprt_free_bc_request(struct rpc_rqst *req)
        spin_unlock_bh(&xprt->bc_pa_lock);
 }
 
-#endif /* CONFIG_NFS_V4_1 */
index 1dd1a6890007d75ac7cf5b9daf5bcd8241fda789..0b2eb388cbda3c6d863557797ad786b992444931 100644 (file)
@@ -27,8 +27,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * reply over an existing open connection previously established by the client.
  */
 
-#if defined(CONFIG_NFS_V4_1)
-
 #include <linux/module.h>
 
 #include <linux/sunrpc/xprt.h>
@@ -63,4 +61,3 @@ int bc_send(struct rpc_rqst *req)
        return ret;
 }
 
-#endif /* CONFIG_NFS_V4_1 */
index c50818f0473b36851f2117c5be915a4da4d6a544..c5347d29cfb75d9b045d4ad3a7d5231e03f59100 100644 (file)
@@ -64,9 +64,9 @@ static void   call_decode(struct rpc_task *task);
 static void    call_bind(struct rpc_task *task);
 static void    call_bind_status(struct rpc_task *task);
 static void    call_transmit(struct rpc_task *task);
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 static void    call_bc_transmit(struct rpc_task *task);
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 static void    call_status(struct rpc_task *task);
 static void    call_transmit_status(struct rpc_task *task);
 static void    call_refresh(struct rpc_task *task);
@@ -715,7 +715,7 @@ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags,
 }
 EXPORT_SYMBOL_GPL(rpc_call_async);
 
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 /**
  * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run
  * rpc_execute against it
@@ -758,7 +758,7 @@ out:
        dprintk("RPC: rpc_run_bc_task: task= %p\n", task);
        return task;
 }
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
 void
 rpc_call_start(struct rpc_task *task)
@@ -1361,7 +1361,7 @@ call_transmit_status(struct rpc_task *task)
        }
 }
 
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 /*
  * 5b. Send the backchannel RPC reply.  On error, drop the reply.  In
  * addition, disconnect on connectivity errors.
@@ -1425,7 +1425,7 @@ call_bc_transmit(struct rpc_task *task)
        }
        rpc_wake_up_queued_task(&req->rq_xprt->pending, task);
 }
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
 /*
  * 6.  Sort out the RPC call status
@@ -1550,8 +1550,7 @@ call_decode(struct rpc_task *task)
        kxdrdproc_t     decode = task->tk_msg.rpc_proc->p_decode;
        __be32          *p;
 
-       dprintk("RPC: %5u call_decode (status %d)\n",
-                       task->tk_pid, task->tk_status);
+       dprint_status(task);
 
        if (task->tk_flags & RPC_CALL_MAJORSEEN) {
                if (clnt->cl_chatty)
index 4814e246a874ac1c19c51c5c36e7bbcd60b2d373..d12ffa5458115e3912f8b7f22a337963d8d3213c 100644 (file)
@@ -97,14 +97,16 @@ __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task)
 /*
  * Add new request to a priority queue.
  */
-static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, struct rpc_task *task)
+static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue,
+               struct rpc_task *task,
+               unsigned char queue_priority)
 {
        struct list_head *q;
        struct rpc_task *t;
 
        INIT_LIST_HEAD(&task->u.tk_wait.links);
-       q = &queue->tasks[task->tk_priority];
-       if (unlikely(task->tk_priority > queue->maxpriority))
+       q = &queue->tasks[queue_priority];
+       if (unlikely(queue_priority > queue->maxpriority))
                q = &queue->tasks[queue->maxpriority];
        list_for_each_entry(t, q, u.tk_wait.list) {
                if (t->tk_owner == task->tk_owner) {
@@ -123,12 +125,14 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, struct r
  * improve overall performance.
  * Everyone else gets appended to the queue to ensure proper FIFO behavior.
  */
-static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
+static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
+               struct rpc_task *task,
+               unsigned char queue_priority)
 {
        BUG_ON (RPC_IS_QUEUED(task));
 
        if (RPC_IS_PRIORITY(queue))
-               __rpc_add_wait_queue_priority(queue, task);
+               __rpc_add_wait_queue_priority(queue, task, queue_priority);
        else if (RPC_IS_SWAPPER(task))
                list_add(&task->u.tk_wait.list, &queue->tasks[0]);
        else
@@ -311,13 +315,15 @@ static void rpc_make_runnable(struct rpc_task *task)
  * NB: An RPC task will only receive interrupt-driven events as long
  * as it's on a wait queue.
  */
-static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
-                       rpc_action action)
+static void __rpc_sleep_on_priority(struct rpc_wait_queue *q,
+               struct rpc_task *task,
+               rpc_action action,
+               unsigned char queue_priority)
 {
        dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n",
                        task->tk_pid, rpc_qname(q), jiffies);
 
-       __rpc_add_wait_queue(q, task);
+       __rpc_add_wait_queue(q, task, queue_priority);
 
        BUG_ON(task->tk_callback != NULL);
        task->tk_callback = action;
@@ -334,11 +340,25 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
         * Protect the queue operations.
         */
        spin_lock_bh(&q->lock);
-       __rpc_sleep_on(q, task, action);
+       __rpc_sleep_on_priority(q, task, action, task->tk_priority);
        spin_unlock_bh(&q->lock);
 }
 EXPORT_SYMBOL_GPL(rpc_sleep_on);
 
+void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task,
+               rpc_action action, int priority)
+{
+       /* We shouldn't ever put an inactive task to sleep */
+       BUG_ON(!RPC_IS_ACTIVATED(task));
+
+       /*
+        * Protect the queue operations.
+        */
+       spin_lock_bh(&q->lock);
+       __rpc_sleep_on_priority(q, task, action, priority - RPC_PRIORITY_LOW);
+       spin_unlock_bh(&q->lock);
+}
+
 /**
  * __rpc_do_wake_up_task - wake up a single rpc_task
  * @queue: wait queue
index 2b90292e95053acace4d02a3269b960591b3b426..6a69a1131fb77eb8014f77f404e26389976a3445 100644 (file)
@@ -1252,7 +1252,7 @@ svc_process(struct svc_rqst *rqstp)
        }
 }
 
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 /*
  * Process a backchannel RPC request that arrived over an existing
  * outbound connection
@@ -1300,8 +1300,8 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
                return 0;
        }
 }
-EXPORT_SYMBOL(bc_svc_process);
-#endif /* CONFIG_NFS_V4_1 */
+EXPORT_SYMBOL_GPL(bc_svc_process);
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
 /*
  * Return (transport-specific) limit on the rpc payload.
index f2cb5b881dea979bc83c62e52ee3ec167eee8bbc..767d494de7a262e40a59e8842ca316ae8a61059d 100644 (file)
@@ -68,12 +68,12 @@ static void         svc_sock_free(struct svc_xprt *);
 static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
                                          struct net *, struct sockaddr *,
                                          int, int);
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 static struct svc_xprt *svc_bc_create_socket(struct svc_serv *, int,
                                             struct net *, struct sockaddr *,
                                             int, int);
 static void svc_bc_sock_free(struct svc_xprt *xprt);
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key svc_key[2];
@@ -1243,7 +1243,7 @@ static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
        return svc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags);
 }
 
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 static struct svc_xprt *svc_bc_create_socket(struct svc_serv *, int,
                                             struct net *, struct sockaddr *,
                                             int, int);
@@ -1284,7 +1284,7 @@ static void svc_cleanup_bc_xprt_sock(void)
 {
        svc_unreg_xprt_class(&svc_tcp_bc_class);
 }
-#else /* CONFIG_NFS_V4_1 */
+#else /* CONFIG_SUNRPC_BACKCHANNEL */
 static void svc_init_bc_xprt_sock(void)
 {
 }
@@ -1292,7 +1292,7 @@ static void svc_init_bc_xprt_sock(void)
 static void svc_cleanup_bc_xprt_sock(void)
 {
 }
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
 static struct svc_xprt_ops svc_tcp_ops = {
        .xpo_create = svc_tcp_create,
@@ -1623,7 +1623,7 @@ static void svc_sock_free(struct svc_xprt *xprt)
        kfree(svsk);
 }
 
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 /*
  * Create a back channel svc_xprt which shares the fore channel socket.
  */
@@ -1662,4 +1662,4 @@ static void svc_bc_sock_free(struct svc_xprt *xprt)
        if (xprt)
                kfree(container_of(xprt, struct svc_sock, sk_xprt));
 }
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
index f008c14ad34cc03703f6550e95b0144c8a572402..277ebd4bf095fd973af455363a2bf0fc476511bd 100644 (file)
@@ -126,7 +126,7 @@ xdr_terminate_string(struct xdr_buf *buf, const u32 len)
        kaddr[buf->page_base + len] = '\0';
        kunmap_atomic(kaddr, KM_USER0);
 }
-EXPORT_SYMBOL(xdr_terminate_string);
+EXPORT_SYMBOL_GPL(xdr_terminate_string);
 
 void
 xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
index ce5eb68a9664f6a93776304b304c80029efce84d..9b6a4d1ea8f800def10f4db686c71d6cf4d6c563 100644 (file)
@@ -62,6 +62,7 @@
 /*
  * Local functions
  */
+static void     xprt_init(struct rpc_xprt *xprt, struct net *net);
 static void    xprt_request_init(struct rpc_task *, struct rpc_xprt *);
 static void    xprt_connect_status(struct rpc_task *task);
 static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
@@ -191,10 +192,10 @@ EXPORT_SYMBOL_GPL(xprt_load_transport);
  * transport connects from colliding with writes.  No congestion control
  * is provided.
  */
-int xprt_reserve_xprt(struct rpc_task *task)
+int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
-       struct rpc_xprt *xprt = req->rq_xprt;
+       int priority;
 
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
                if (task == xprt->snd_task)
@@ -202,8 +203,10 @@ int xprt_reserve_xprt(struct rpc_task *task)
                goto out_sleep;
        }
        xprt->snd_task = task;
-       req->rq_bytes_sent = 0;
-       req->rq_ntrans++;
+       if (req != NULL) {
+               req->rq_bytes_sent = 0;
+               req->rq_ntrans++;
+       }
 
        return 1;
 
@@ -212,10 +215,13 @@ out_sleep:
                        task->tk_pid, xprt);
        task->tk_timeout = 0;
        task->tk_status = -EAGAIN;
-       if (req->rq_ntrans)
-               rpc_sleep_on(&xprt->resend, task, NULL);
+       if (req == NULL)
+               priority = RPC_PRIORITY_LOW;
+       else if (!req->rq_ntrans)
+               priority = RPC_PRIORITY_NORMAL;
        else
-               rpc_sleep_on(&xprt->sending, task, NULL);
+               priority = RPC_PRIORITY_HIGH;
+       rpc_sleep_on_priority(&xprt->sending, task, NULL, priority);
        return 0;
 }
 EXPORT_SYMBOL_GPL(xprt_reserve_xprt);
@@ -239,22 +245,24 @@ static void xprt_clear_locked(struct rpc_xprt *xprt)
  * integrated into the decision of whether a request is allowed to be
  * woken up and given access to the transport.
  */
-int xprt_reserve_xprt_cong(struct rpc_task *task)
+int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
 {
-       struct rpc_xprt *xprt = task->tk_xprt;
        struct rpc_rqst *req = task->tk_rqstp;
+       int priority;
 
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) {
                if (task == xprt->snd_task)
                        return 1;
                goto out_sleep;
        }
+       if (req == NULL) {
+               xprt->snd_task = task;
+               return 1;
+       }
        if (__xprt_get_cong(xprt, task)) {
                xprt->snd_task = task;
-               if (req) {
-                       req->rq_bytes_sent = 0;
-                       req->rq_ntrans++;
-               }
+               req->rq_bytes_sent = 0;
+               req->rq_ntrans++;
                return 1;
        }
        xprt_clear_locked(xprt);
@@ -262,10 +270,13 @@ out_sleep:
        dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt);
        task->tk_timeout = 0;
        task->tk_status = -EAGAIN;
-       if (req && req->rq_ntrans)
-               rpc_sleep_on(&xprt->resend, task, NULL);
+       if (req == NULL)
+               priority = RPC_PRIORITY_LOW;
+       else if (!req->rq_ntrans)
+               priority = RPC_PRIORITY_NORMAL;
        else
-               rpc_sleep_on(&xprt->sending, task, NULL);
+               priority = RPC_PRIORITY_HIGH;
+       rpc_sleep_on_priority(&xprt->sending, task, NULL, priority);
        return 0;
 }
 EXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong);
@@ -275,7 +286,7 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
        int retval;
 
        spin_lock_bh(&xprt->transport_lock);
-       retval = xprt->ops->reserve_xprt(task);
+       retval = xprt->ops->reserve_xprt(xprt, task);
        spin_unlock_bh(&xprt->transport_lock);
        return retval;
 }
@@ -288,12 +299,9 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt)
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
                return;
 
-       task = rpc_wake_up_next(&xprt->resend);
-       if (!task) {
-               task = rpc_wake_up_next(&xprt->sending);
-               if (!task)
-                       goto out_unlock;
-       }
+       task = rpc_wake_up_next(&xprt->sending);
+       if (task == NULL)
+               goto out_unlock;
 
        req = task->tk_rqstp;
        xprt->snd_task = task;
@@ -310,24 +318,25 @@ out_unlock:
 static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
 {
        struct rpc_task *task;
+       struct rpc_rqst *req;
 
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
                return;
        if (RPCXPRT_CONGESTED(xprt))
                goto out_unlock;
-       task = rpc_wake_up_next(&xprt->resend);
-       if (!task) {
-               task = rpc_wake_up_next(&xprt->sending);
-               if (!task)
-                       goto out_unlock;
+       task = rpc_wake_up_next(&xprt->sending);
+       if (task == NULL)
+               goto out_unlock;
+
+       req = task->tk_rqstp;
+       if (req == NULL) {
+               xprt->snd_task = task;
+               return;
        }
        if (__xprt_get_cong(xprt, task)) {
-               struct rpc_rqst *req = task->tk_rqstp;
                xprt->snd_task = task;
-               if (req) {
-                       req->rq_bytes_sent = 0;
-                       req->rq_ntrans++;
-               }
+               req->rq_bytes_sent = 0;
+               req->rq_ntrans++;
                return;
        }
 out_unlock:
@@ -852,7 +861,7 @@ int xprt_prepare_transmit(struct rpc_task *task)
                err = req->rq_reply_bytes_recvd;
                goto out_unlock;
        }
-       if (!xprt->ops->reserve_xprt(task))
+       if (!xprt->ops->reserve_xprt(xprt, task))
                err = -EAGAIN;
 out_unlock:
        spin_unlock_bh(&xprt->transport_lock);
@@ -928,28 +937,66 @@ void xprt_transmit(struct rpc_task *task)
        spin_unlock_bh(&xprt->transport_lock);
 }
 
+static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt, gfp_t gfp_flags)
+{
+       struct rpc_rqst *req = ERR_PTR(-EAGAIN);
+
+       if (!atomic_add_unless(&xprt->num_reqs, 1, xprt->max_reqs))
+               goto out;
+       req = kzalloc(sizeof(struct rpc_rqst), gfp_flags);
+       if (req != NULL)
+               goto out;
+       atomic_dec(&xprt->num_reqs);
+       req = ERR_PTR(-ENOMEM);
+out:
+       return req;
+}
+
+static bool xprt_dynamic_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
+{
+       if (atomic_add_unless(&xprt->num_reqs, -1, xprt->min_reqs)) {
+               kfree(req);
+               return true;
+       }
+       return false;
+}
+
 static void xprt_alloc_slot(struct rpc_task *task)
 {
        struct rpc_xprt *xprt = task->tk_xprt;
+       struct rpc_rqst *req;
 
-       task->tk_status = 0;
-       if (task->tk_rqstp)
-               return;
        if (!list_empty(&xprt->free)) {
-               struct rpc_rqst *req = list_entry(xprt->free.next, struct rpc_rqst, rq_list);
-               list_del_init(&req->rq_list);
-               task->tk_rqstp = req;
-               xprt_request_init(task, xprt);
-               return;
+               req = list_entry(xprt->free.next, struct rpc_rqst, rq_list);
+               list_del(&req->rq_list);
+               goto out_init_req;
+       }
+       req = xprt_dynamic_alloc_slot(xprt, GFP_NOWAIT);
+       if (!IS_ERR(req))
+               goto out_init_req;
+       switch (PTR_ERR(req)) {
+       case -ENOMEM:
+               rpc_delay(task, HZ >> 2);
+               dprintk("RPC:       dynamic allocation of request slot "
+                               "failed! Retrying\n");
+               break;
+       case -EAGAIN:
+               rpc_sleep_on(&xprt->backlog, task, NULL);
+               dprintk("RPC:       waiting for request slot\n");
        }
-       dprintk("RPC:       waiting for request slot\n");
        task->tk_status = -EAGAIN;
-       task->tk_timeout = 0;
-       rpc_sleep_on(&xprt->backlog, task, NULL);
+       return;
+out_init_req:
+       task->tk_status = 0;
+       task->tk_rqstp = req;
+       xprt_request_init(task, xprt);
 }
 
 static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
 {
+       if (xprt_dynamic_free_slot(xprt, req))
+               return;
+
        memset(req, 0, sizeof(*req));   /* mark unused */
 
        spin_lock(&xprt->reserve_lock);
@@ -958,25 +1005,49 @@ static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
        spin_unlock(&xprt->reserve_lock);
 }
 
-struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req)
+static void xprt_free_all_slots(struct rpc_xprt *xprt)
+{
+       struct rpc_rqst *req;
+       while (!list_empty(&xprt->free)) {
+               req = list_first_entry(&xprt->free, struct rpc_rqst, rq_list);
+               list_del(&req->rq_list);
+               kfree(req);
+       }
+}
+
+struct rpc_xprt *xprt_alloc(struct net *net, size_t size,
+               unsigned int num_prealloc,
+               unsigned int max_alloc)
 {
        struct rpc_xprt *xprt;
+       struct rpc_rqst *req;
+       int i;
 
        xprt = kzalloc(size, GFP_KERNEL);
        if (xprt == NULL)
                goto out;
-       atomic_set(&xprt->count, 1);
 
-       xprt->max_reqs = max_req;
-       xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL);
-       if (xprt->slot == NULL)
+       xprt_init(xprt, net);
+
+       for (i = 0; i < num_prealloc; i++) {
+               req = kzalloc(sizeof(struct rpc_rqst), GFP_KERNEL);
+               if (!req)
+                       break;
+               list_add(&req->rq_list, &xprt->free);
+       }
+       if (i < num_prealloc)
                goto out_free;
+       if (max_alloc > num_prealloc)
+               xprt->max_reqs = max_alloc;
+       else
+               xprt->max_reqs = num_prealloc;
+       xprt->min_reqs = num_prealloc;
+       atomic_set(&xprt->num_reqs, num_prealloc);
 
-       xprt->xprt_net = get_net(net);
        return xprt;
 
 out_free:
-       kfree(xprt);
+       xprt_free(xprt);
 out:
        return NULL;
 }
@@ -985,7 +1056,7 @@ EXPORT_SYMBOL_GPL(xprt_alloc);
 void xprt_free(struct rpc_xprt *xprt)
 {
        put_net(xprt->xprt_net);
-       kfree(xprt->slot);
+       xprt_free_all_slots(xprt);
        kfree(xprt);
 }
 EXPORT_SYMBOL_GPL(xprt_free);
@@ -1001,10 +1072,24 @@ void xprt_reserve(struct rpc_task *task)
 {
        struct rpc_xprt *xprt = task->tk_xprt;
 
-       task->tk_status = -EIO;
+       task->tk_status = 0;
+       if (task->tk_rqstp != NULL)
+               return;
+
+       /* Note: grabbing the xprt_lock_write() here is not strictly needed,
+        * but ensures that we throttle new slot allocation if the transport
+        * is congested (e.g. if reconnecting or if we're out of socket
+        * write buffer space).
+        */
+       task->tk_timeout = 0;
+       task->tk_status = -EAGAIN;
+       if (!xprt_lock_write(xprt, task))
+               return;
+
        spin_lock(&xprt->reserve_lock);
        xprt_alloc_slot(task);
        spin_unlock(&xprt->reserve_lock);
+       xprt_release_write(xprt, task);
 }
 
 static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
@@ -1021,6 +1106,7 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
 {
        struct rpc_rqst *req = task->tk_rqstp;
 
+       INIT_LIST_HEAD(&req->rq_list);
        req->rq_timeout = task->tk_client->cl_timeout->to_initval;
        req->rq_task    = task;
        req->rq_xprt    = xprt;
@@ -1073,6 +1159,34 @@ void xprt_release(struct rpc_task *task)
                xprt_free_bc_request(req);
 }
 
+static void xprt_init(struct rpc_xprt *xprt, struct net *net)
+{
+       atomic_set(&xprt->count, 1);
+
+       spin_lock_init(&xprt->transport_lock);
+       spin_lock_init(&xprt->reserve_lock);
+
+       INIT_LIST_HEAD(&xprt->free);
+       INIT_LIST_HEAD(&xprt->recv);
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
+       spin_lock_init(&xprt->bc_pa_lock);
+       INIT_LIST_HEAD(&xprt->bc_pa_list);
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
+
+       xprt->last_used = jiffies;
+       xprt->cwnd = RPC_INITCWND;
+       xprt->bind_index = 0;
+
+       rpc_init_wait_queue(&xprt->binding, "xprt_binding");
+       rpc_init_wait_queue(&xprt->pending, "xprt_pending");
+       rpc_init_priority_wait_queue(&xprt->sending, "xprt_sending");
+       rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog");
+
+       xprt_init_xid(xprt);
+
+       xprt->xprt_net = get_net(net);
+}
+
 /**
  * xprt_create_transport - create an RPC transport
  * @args: rpc transport creation arguments
@@ -1081,7 +1195,6 @@ void xprt_release(struct rpc_task *task)
 struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
 {
        struct rpc_xprt *xprt;
-       struct rpc_rqst *req;
        struct xprt_class *t;
 
        spin_lock(&xprt_list_lock);
@@ -1100,46 +1213,17 @@ found:
        if (IS_ERR(xprt)) {
                dprintk("RPC:       xprt_create_transport: failed, %ld\n",
                                -PTR_ERR(xprt));
-               return xprt;
+               goto out;
        }
-       if (test_and_set_bit(XPRT_INITIALIZED, &xprt->state))
-               /* ->setup returned a pre-initialized xprt: */
-               return xprt;
-
-       spin_lock_init(&xprt->transport_lock);
-       spin_lock_init(&xprt->reserve_lock);
-
-       INIT_LIST_HEAD(&xprt->free);
-       INIT_LIST_HEAD(&xprt->recv);
-#if defined(CONFIG_NFS_V4_1)
-       spin_lock_init(&xprt->bc_pa_lock);
-       INIT_LIST_HEAD(&xprt->bc_pa_list);
-#endif /* CONFIG_NFS_V4_1 */
-
        INIT_WORK(&xprt->task_cleanup, xprt_autoclose);
        if (xprt_has_timer(xprt))
                setup_timer(&xprt->timer, xprt_init_autodisconnect,
                            (unsigned long)xprt);
        else
                init_timer(&xprt->timer);
-       xprt->last_used = jiffies;
-       xprt->cwnd = RPC_INITCWND;
-       xprt->bind_index = 0;
-
-       rpc_init_wait_queue(&xprt->binding, "xprt_binding");
-       rpc_init_wait_queue(&xprt->pending, "xprt_pending");
-       rpc_init_wait_queue(&xprt->sending, "xprt_sending");
-       rpc_init_wait_queue(&xprt->resend, "xprt_resend");
-       rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog");
-
-       /* initialize free list */
-       for (req = &xprt->slot[xprt->max_reqs-1]; req >= &xprt->slot[0]; req--)
-               list_add(&req->rq_list, &xprt->free);
-
-       xprt_init_xid(xprt);
-
        dprintk("RPC:       created transport %p with %u slots\n", xprt,
                        xprt->max_reqs);
+out:
        return xprt;
 }
 
@@ -1157,7 +1241,6 @@ static void xprt_destroy(struct rpc_xprt *xprt)
        rpc_destroy_wait_queue(&xprt->binding);
        rpc_destroy_wait_queue(&xprt->pending);
        rpc_destroy_wait_queue(&xprt->sending);
-       rpc_destroy_wait_queue(&xprt->resend);
        rpc_destroy_wait_queue(&xprt->backlog);
        cancel_work_sync(&xprt->task_cleanup);
        /*
index 0867070bb5ca2a9fc1e9749c6c06412cdc9c40ff..b446e100286f7aca96f81ca10d6cb176471d55d5 100644 (file)
@@ -283,6 +283,7 @@ xprt_setup_rdma(struct xprt_create *args)
        }
 
        xprt = xprt_alloc(args->net, sizeof(struct rpcrdma_xprt),
+                       xprt_rdma_slot_table_entries,
                        xprt_rdma_slot_table_entries);
        if (xprt == NULL) {
                dprintk("RPC:       %s: couldn't allocate rpcrdma_xprt\n",
@@ -452,9 +453,8 @@ xprt_rdma_connect(struct rpc_task *task)
 }
 
 static int
-xprt_rdma_reserve_xprt(struct rpc_task *task)
+xprt_rdma_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
 {
-       struct rpc_xprt *xprt = task->tk_xprt;
        struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
        int credits = atomic_read(&r_xprt->rx_buf.rb_credits);
 
@@ -466,7 +466,7 @@ xprt_rdma_reserve_xprt(struct rpc_task *task)
                BUG_ON(r_xprt->rx_buf.rb_cwndscale <= 0);
        }
        xprt->cwnd = credits * r_xprt->rx_buf.rb_cwndscale;
-       return xprt_reserve_xprt_cong(task);
+       return xprt_reserve_xprt_cong(xprt, task);
 }
 
 /*
index ddf05288d9f1a60a3eed994fb969bc9103c0e7c6..08c5d5a128fc44e835a6f6ac13f6b81a5387c889 100644 (file)
@@ -109,7 +109,7 @@ struct rpcrdma_ep {
  */
 
 /* temporary static scatter/gather max */
-#define RPCRDMA_MAX_DATA_SEGS  (8)     /* max scatter/gather */
+#define RPCRDMA_MAX_DATA_SEGS  (64)    /* max scatter/gather */
 #define RPCRDMA_MAX_SEGS       (RPCRDMA_MAX_DATA_SEGS + 2) /* head+tail = 2 */
 #define MAX_RPCRDMAHDR (\
        /* max supported RPC/RDMA header */ \
index 72abb735893321d4616d5d9b0801e5cb6f777cff..d7f97ef265904f0ddc0d691360f1e920dc63210b 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/sunrpc/svcsock.h>
 #include <linux/sunrpc/xprtsock.h>
 #include <linux/file.h>
-#ifdef CONFIG_NFS_V4_1
+#ifdef CONFIG_SUNRPC_BACKCHANNEL
 #include <linux/sunrpc/bc_xprt.h>
 #endif
 
@@ -54,7 +54,8 @@ static void xs_close(struct rpc_xprt *xprt);
  * xprtsock tunables
  */
 unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE;
-unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE;
+unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE;
+unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE;
 
 unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT;
 unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT;
@@ -75,6 +76,7 @@ static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO;
 
 static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE;
 static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE;
+static unsigned int max_tcp_slot_table_limit = RPC_MAX_SLOT_TABLE_LIMIT;
 static unsigned int xprt_min_resvport_limit = RPC_MIN_RESVPORT;
 static unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT;
 
@@ -103,6 +105,15 @@ static ctl_table xs_tunables_table[] = {
                .extra1         = &min_slot_table_size,
                .extra2         = &max_slot_table_size
        },
+       {
+               .procname       = "tcp_max_slot_table_entries",
+               .data           = &xprt_max_tcp_slot_table_entries,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &min_slot_table_size,
+               .extra2         = &max_tcp_slot_table_limit
+       },
        {
                .procname       = "min_resvport",
                .data           = &xprt_min_resvport,
@@ -755,6 +766,8 @@ static void xs_tcp_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
        if (task == NULL)
                goto out_release;
        req = task->tk_rqstp;
+       if (req == NULL)
+               goto out_release;
        if (req->rq_bytes_sent == 0)
                goto out_release;
        if (req->rq_bytes_sent == req->rq_snd_buf.len)
@@ -1236,7 +1249,7 @@ static inline int xs_tcp_read_reply(struct rpc_xprt *xprt,
        return 0;
 }
 
-#if defined(CONFIG_NFS_V4_1)
+#if defined(CONFIG_SUNRPC_BACKCHANNEL)
 /*
  * Obtains an rpc_rqst previously allocated and invokes the common
  * tcp read code to read the data.  The result is placed in the callback
@@ -1299,7 +1312,7 @@ static inline int _xs_tcp_read_data(struct rpc_xprt *xprt,
 {
        return xs_tcp_read_reply(xprt, desc);
 }
-#endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
 /*
  * Read data off the transport.  This can be either an RPC_CALL or an
@@ -2489,7 +2502,8 @@ static int xs_init_anyaddr(const int family, struct sockaddr *sap)
 }
 
 static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
-                                     unsigned int slot_table_size)
+                                     unsigned int slot_table_size,
+                                     unsigned int max_slot_table_size)
 {
        struct rpc_xprt *xprt;
        struct sock_xprt *new;
@@ -2499,7 +2513,8 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
                return ERR_PTR(-EBADF);
        }
 
-       xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size);
+       xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size,
+                       max_slot_table_size);
        if (xprt == NULL) {
                dprintk("RPC:       xs_setup_xprt: couldn't allocate "
                                "rpc_xprt\n");
@@ -2541,7 +2556,8 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args)
        struct rpc_xprt *xprt;
        struct rpc_xprt *ret;
 
-       xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
+       xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries,
+                       xprt_max_tcp_slot_table_entries);
        if (IS_ERR(xprt))
                return xprt;
        transport = container_of(xprt, struct sock_xprt, xprt);
@@ -2605,7 +2621,8 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
        struct sock_xprt *transport;
        struct rpc_xprt *ret;
 
-       xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries);
+       xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries,
+                       xprt_udp_slot_table_entries);
        if (IS_ERR(xprt))
                return xprt;
        transport = container_of(xprt, struct sock_xprt, xprt);
@@ -2681,7 +2698,8 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
        struct sock_xprt *transport;
        struct rpc_xprt *ret;
 
-       xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
+       xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries,
+                       xprt_max_tcp_slot_table_entries);
        if (IS_ERR(xprt))
                return xprt;
        transport = container_of(xprt, struct sock_xprt, xprt);
@@ -2760,7 +2778,8 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
                 */
                 return args->bc_xprt->xpt_bc_xprt;
        }
-       xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
+       xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries,
+                       xprt_tcp_slot_table_entries);
        if (IS_ERR(xprt))
                return xprt;
        transport = container_of(xprt, struct sock_xprt, xprt);
@@ -2947,8 +2966,26 @@ static struct kernel_param_ops param_ops_slot_table_size = {
 #define param_check_slot_table_size(name, p) \
        __param_check(name, p, unsigned int);
 
+static int param_set_max_slot_table_size(const char *val,
+                                    const struct kernel_param *kp)
+{
+       return param_set_uint_minmax(val, kp,
+                       RPC_MIN_SLOT_TABLE,
+                       RPC_MAX_SLOT_TABLE_LIMIT);
+}
+
+static struct kernel_param_ops param_ops_max_slot_table_size = {
+       .set = param_set_max_slot_table_size,
+       .get = param_get_uint,
+};
+
+#define param_check_max_slot_table_size(name, p) \
+       __param_check(name, p, unsigned int);
+
 module_param_named(tcp_slot_table_entries, xprt_tcp_slot_table_entries,
                   slot_table_size, 0644);
+module_param_named(tcp_max_slot_table_entries, xprt_max_tcp_slot_table_entries,
+                  max_slot_table_size, 0644);
 module_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries,
                   slot_table_size, 0644);
 
index 1ad0f39fe0913415b47888f74d12651529ee9cc5..02751dbc5a97fab55abdefb9936dfc24c2d4ef22 100644 (file)
@@ -903,7 +903,7 @@ static bool ignore_reg_update(struct wiphy *wiphy,
            initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
            !is_world_regdom(last_request->alpha2)) {
                REG_DBG_PRINT("Ignoring regulatory request %s "
-                             "since the driver requires its own regulaotry "
+                             "since the driver requires its own regulatory "
                              "domain to be set first",
                              reg_initiator_name(initiator));
                return true;
@@ -1125,12 +1125,13 @@ void wiphy_update_regulatory(struct wiphy *wiphy,
        enum ieee80211_band band;
 
        if (ignore_reg_update(wiphy, initiator))
-               goto out;
+               return;
+
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                if (wiphy->bands[band])
                        handle_band(wiphy, band, initiator);
        }
-out:
+
        reg_process_beacons(wiphy);
        reg_process_ht_flags(wiphy);
        if (wiphy->reg_notifier)
index 0b4276c047b282f3b696e39a12c2291160046d7b..82d2eb285b705daac83e5c690620a7500ba5f1f9 100644 (file)
@@ -170,8 +170,8 @@ mconf-objs     := mconf.o zconf.tab.o $(lxdialog)
 nconf-objs     := nconf.o zconf.tab.o nconf.gui.o
 kxgettext-objs := kxgettext.o zconf.tab.o
 qconf-cxxobjs  := qconf.o
-qconf-objs     := kconfig_load.o zconf.tab.o
-gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
+qconf-objs     := zconf.tab.o
+gconf-objs     := gconf.o zconf.tab.o
 
 hostprogs-y := conf
 
@@ -203,7 +203,7 @@ ifeq ($(gconf-target),1)
        hostprogs-y += gconf
 endif
 
-clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck .tmp_gtkcheck
+clean-files    := qconf.moc .tmp_qtcheck .tmp_gtkcheck
 clean-files    += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h
 clean-files     += mconf qconf gconf nconf
 clean-files     += config.pot linux.pot
@@ -226,12 +226,12 @@ HOSTCFLAGS_zconf.tab.o    := -I$(src)
 LEX_PREFIX_zconf       := zconf
 YACC_PREFIX_zconf      := zconf
 
-HOSTLOADLIBES_qconf    = $(KC_QT_LIBS) -ldl
-HOSTCXXFLAGS_qconf.o   = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
+HOSTLOADLIBES_qconf    = $(KC_QT_LIBS)
+HOSTCXXFLAGS_qconf.o   = $(KC_QT_CFLAGS)
 
-HOSTLOADLIBES_gconf    = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl
+HOSTLOADLIBES_gconf    = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
 HOSTCFLAGS_gconf.o     = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
-                          -D LKC_DIRECT_LINK
+                          -Wno-missing-prototypes
 
 HOSTLOADLIBES_mconf   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
 
@@ -321,18 +321,11 @@ endif
 
 $(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c
 
-$(obj)/kconfig_load.o: $(obj)/lkc_defs.h
-
-$(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h
-
-$(obj)/gconf.o: $(obj)/lkc_defs.h
+$(obj)/qconf.o: $(obj)/qconf.moc
 
 $(obj)/%.moc: $(src)/%.h
        $(KC_QT_MOC) -i $< -o $@
 
-$(obj)/lkc_defs.h: $(src)/lkc_proto.h
-       $(Q)sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
-
 # Extract gconf menu items for I18N support
 $(obj)/gconf.glade.h: $(obj)/gconf.glade
        $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \
index 006ad817cd5f003023a7308b471eb9c4e46ba5de..f208f900ed3a8747f9bfd949b2221000d5021607 100644 (file)
 #include <sys/stat.h>
 #include <sys/time.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 static void conf(struct menu *menu);
 static void check_conf(struct menu *menu);
+static void xfgets(char *str, int size, FILE *in);
 
 enum input_mode {
        oldaskconfig,
@@ -35,8 +35,6 @@ enum input_mode {
        oldnoconfig,
 } input_mode = oldaskconfig;
 
-char *defconfig_file;
-
 static int indent = 1;
 static int valid_stdin = 1;
 static int sync_kconfig;
@@ -106,6 +104,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
                        return 0;
                }
                check_stdin();
+               /* fall through */
        case oldaskconfig:
                fflush(stdout);
                xfgets(line, 128, stdin);
@@ -150,6 +149,7 @@ static int conf_string(struct menu *menu)
                                def = NULL;
                                break;
                        }
+                       /* fall through */
                default:
                        line[strlen(line)-1] = 0;
                        def = line;
@@ -304,6 +304,7 @@ static int conf_choice(struct menu *menu)
                                break;
                        }
                        check_stdin();
+                       /* fall through */
                case oldaskconfig:
                        fflush(stdout);
                        xfgets(line, 128, stdin);
@@ -369,6 +370,7 @@ static void conf(struct menu *menu)
                                check_conf(menu);
                                return;
                        }
+                       /* fall through */
                case P_COMMENT:
                        prompt = menu_get_prompt(menu);
                        if (prompt)
@@ -456,10 +458,30 @@ static struct option long_opts[] = {
        {NULL, 0, NULL, 0}
 };
 
+static void conf_usage(const char *progname)
+{
+
+       printf("Usage: %s [option] <kconfig-file>\n", progname);
+       printf("[option] is _one_ of the following:\n");
+       printf("  --listnewconfig         List new options\n");
+       printf("  --oldaskconfig          Start a new configuration using a line-oriented program\n");
+       printf("  --oldconfig             Update a configuration using a provided .config as base\n");
+       printf("  --silentoldconfig       Same as oldconfig, but quietly, additionally update deps\n");
+       printf("  --oldnoconfig           Same as silentoldconfig but set new symbols to no\n");
+       printf("  --defconfig <file>      New config with default defined in <file>\n");
+       printf("  --savedefconfig <file>  Save the minimal current configuration to <file>\n");
+       printf("  --allnoconfig           New config where all options are answered with no\n");
+       printf("  --allyesconfig          New config where all options are answered with yes\n");
+       printf("  --allmodconfig          New config where all options are answered with mod\n");
+       printf("  --alldefconfig          New config with all symbols set to default\n");
+       printf("  --randconfig            New config with random answer to all options\n");
+}
+
 int main(int ac, char **av)
 {
+       const char *progname = av[0];
        int opt;
-       const char *name;
+       const char *name, *defconfig_file = NULL /* gcc uninit */;
        struct stat tmpstat;
 
        setlocale(LC_ALL, "");
@@ -491,14 +513,24 @@ int main(int ac, char **av)
                        srand(seed);
                        break;
                }
+               case oldaskconfig:
+               case oldconfig:
+               case allnoconfig:
+               case allyesconfig:
+               case allmodconfig:
+               case alldefconfig:
+               case listnewconfig:
+               case oldnoconfig:
+                       break;
                case '?':
-                       fprintf(stderr, _("See README for usage info\n"));
+                       conf_usage(progname);
                        exit(1);
                        break;
                }
        }
        if (ac == optind) {
                printf(_("%s: Kconfig file missing\n"), av[0]);
+               conf_usage(progname);
                exit(1);
        }
        name = av[optind];
@@ -641,13 +673,11 @@ int main(int ac, char **av)
        }
        return 0;
 }
+
 /*
  * Helper function to facilitate fgets() by Jean Sacren.
  */
-void xfgets(str, size, in)
-       char *str;
-       int size;
-       FILE *in;
+void xfgets(char *str, int size, FILE *in)
 {
        if (fgets(str, size, in) == NULL)
                fprintf(stderr, "\nError in reading or end of file.\n");
index 2bafd9a7c8daa0c7f80edb0294f5686995832c9f..59b667cae5f33e4437e1beaa6bdfcdcb93bc8fcb 100644 (file)
@@ -7,13 +7,13 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 static void conf_warning(const char *fmt, ...)
@@ -128,6 +128,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        sym->flags |= def_flags;
                        break;
                }
+               /* fall through */
        case S_BOOLEAN:
                if (p[0] == 'y') {
                        sym->def[def].tri = yes;
@@ -140,7 +141,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        break;
                }
                conf_warning("symbol value '%s' invalid for %s", p, sym->name);
-               break;
+               return 1;
        case S_OTHER:
                if (*p != '"') {
                        for (p2 = p; *p2 && !isspace(*p2); p2++)
@@ -148,6 +149,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        sym->type = S_STRING;
                        goto done;
                }
+               /* fall through */
        case S_STRING:
                if (*p++ != '"')
                        break;
@@ -162,6 +164,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        conf_warning("invalid string found");
                        return 1;
                }
+               /* fall through */
        case S_INT:
        case S_HEX:
        done:
@@ -237,6 +240,7 @@ load:
                case S_STRING:
                        if (sym->def[def].val)
                                free(sym->def[def].val);
+                       /* fall through */
                default:
                        sym->def[def].val = NULL;
                        sym->def[def].tri = no;
@@ -363,6 +367,7 @@ int conf_read(const char *name)
                                        break;
                                if (!sym_is_choice(sym))
                                        goto sym_ok;
+                               /* fall through */
                        default:
                                if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
                                        goto sym_ok;
@@ -417,64 +422,202 @@ int conf_read(const char *name)
        return 0;
 }
 
-/* Write a S_STRING */
-static void conf_write_string(bool headerfile, const char *name,
-                              const char *str, FILE *out)
+/*
+ * Kconfig configuration printer
+ *
+ * This printer is used when generating the resulting configuration after
+ * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
+ * passing a non-NULL argument to the printer.
+ *
+ */
+static void
+kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
 {
-       int l;
-       if (headerfile)
-               fprintf(out, "#define %s%s \"", CONFIG_, name);
-       else
-               fprintf(out, "%s%s=\"", CONFIG_, name);
-
-       while (1) {
-               l = strcspn(str, "\"\\");
+
+       switch (sym->type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               if (*value == 'n') {
+                       bool skip_unset = (arg != NULL);
+
+                       if (!skip_unset)
+                               fprintf(fp, "# %s%s is not set\n",
+                                   CONFIG_, sym->name);
+                       return;
+               }
+               break;
+       default:
+               break;
+       }
+
+       fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
+}
+
+static void
+kconfig_print_comment(FILE *fp, const char *value, void *arg)
+{
+       const char *p = value;
+       size_t l;
+
+       for (;;) {
+               l = strcspn(p, "\n");
+               fprintf(fp, "#");
                if (l) {
-                       xfwrite(str, l, 1, out);
-                       str += l;
+                       fprintf(fp, " ");
+                       fwrite(p, l, 1, fp);
+                       p += l;
                }
-               if (!*str)
+               fprintf(fp, "\n");
+               if (*p++ == '\0')
                        break;
-               fprintf(out, "\\%c", *str++);
        }
-       fputs("\"\n", out);
 }
 
-static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
+static struct conf_printer kconfig_printer_cb =
+{
+       .print_symbol = kconfig_print_symbol,
+       .print_comment = kconfig_print_comment,
+};
+
+/*
+ * Header printer
+ *
+ * This printer is used when generating the `include/generated/autoconf.h' file.
+ */
+static void
+header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
 {
-       const char *str;
 
        switch (sym->type) {
        case S_BOOLEAN:
-       case S_TRISTATE:
-               switch (sym_get_tristate_value(sym)) {
-               case no:
-                       if (write_no)
-                               fprintf(out, "# %s%s is not set\n",
-                                   CONFIG_, sym->name);
-                       break;
-               case mod:
-                       fprintf(out, "%s%s=m\n", CONFIG_, sym->name);
-                       break;
-               case yes:
-                       fprintf(out, "%s%s=y\n", CONFIG_, sym->name);
+       case S_TRISTATE: {
+               const char *suffix = "";
+
+               switch (*value) {
+               case 'n':
                        break;
+               case 'm':
+                       suffix = "_MODULE";
+                       /* fall through */
+               default:
+                       fprintf(fp, "#define %s%s%s 1\n",
+                           CONFIG_, sym->name, suffix);
                }
+               /*
+                * Generate the __enabled_CONFIG_* and
+                * __enabled_CONFIG_*_MODULE macros for use by the
+                * IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is
+                * generated even for booleans so that the IS_ENABLED() macro
+                * works.
+                */
+               fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n",
+                               sym->name, (*value == 'y'));
+               fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n",
+                               sym->name, (*value == 'm'));
                break;
-       case S_STRING:
-               conf_write_string(false, sym->name, sym_get_string_value(sym), out);
+       }
+       case S_HEX: {
+               const char *prefix = "";
+
+               if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
+                       prefix = "0x";
+               fprintf(fp, "#define %s%s %s%s\n",
+                   CONFIG_, sym->name, prefix, value);
                break;
-       case S_HEX:
+       }
+       case S_STRING:
        case S_INT:
-               str = sym_get_string_value(sym);
-               fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str);
+               fprintf(fp, "#define %s%s %s\n",
+                   CONFIG_, sym->name, value);
+               break;
+       default:
                break;
+       }
+
+}
+
+static void
+header_print_comment(FILE *fp, const char *value, void *arg)
+{
+       const char *p = value;
+       size_t l;
+
+       fprintf(fp, "/*\n");
+       for (;;) {
+               l = strcspn(p, "\n");
+               fprintf(fp, " *");
+               if (l) {
+                       fprintf(fp, " ");
+                       fwrite(p, l, 1, fp);
+                       p += l;
+               }
+               fprintf(fp, "\n");
+               if (*p++ == '\0')
+                       break;
+       }
+       fprintf(fp, " */\n");
+}
+
+static struct conf_printer header_printer_cb =
+{
+       .print_symbol = header_print_symbol,
+       .print_comment = header_print_comment,
+};
+
+/*
+ * Tristate printer
+ *
+ * This printer is used when generating the `include/config/tristate.conf' file.
+ */
+static void
+tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+       if (sym->type == S_TRISTATE && *value != 'n')
+               fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value));
+}
+
+static struct conf_printer tristate_printer_cb =
+{
+       .print_symbol = tristate_print_symbol,
+       .print_comment = kconfig_print_comment,
+};
+
+static void conf_write_symbol(FILE *fp, struct symbol *sym,
+                             struct conf_printer *printer, void *printer_arg)
+{
+       const char *str;
+
+       switch (sym->type) {
        case S_OTHER:
        case S_UNKNOWN:
                break;
+       case S_STRING:
+               str = sym_get_string_value(sym);
+               str = sym_escape_string_value(str);
+               printer->print_symbol(fp, sym, str, printer_arg);
+               free((void *)str);
+               break;
+       default:
+               str = sym_get_string_value(sym);
+               printer->print_symbol(fp, sym, str, printer_arg);
        }
 }
 
+static void
+conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
+{
+       char buf[256];
+
+       snprintf(buf, sizeof(buf),
+           "\n"
+           "Automatically generated file; DO NOT EDIT.\n"
+           "%s\n",
+           rootmenu.prompt->text);
+
+       printer->print_comment(fp, buf, printer_arg);
+}
+
 /*
  * Write out a minimal config.
  * All values that has default values are skipped as this is redundant.
@@ -531,7 +674,7 @@ int conf_write_defconfig(const char *filename)
                                                goto next_menu;
                                }
                        }
-                       conf_write_symbol(sym, out, true);
+                       conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
                }
 next_menu:
                if (menu->list != NULL) {
@@ -596,11 +739,7 @@ int conf_write(const char *name)
        if (!out)
                return 1;
 
-       fprintf(out, _("#\n"
-                      "# Automatically generated make config: don't edit\n"
-                      "# %s\n"
-                      "#\n"),
-                    rootmenu.prompt->text);
+       conf_write_heading(out, &kconfig_printer_cb, NULL);
 
        if (!conf_get_changed())
                sym_clear_all_valid();
@@ -621,8 +760,8 @@ int conf_write(const char *name)
                        if (!(sym->flags & SYMBOL_WRITE))
                                goto next;
                        sym->flags &= ~SYMBOL_WRITE;
-                       /* Write config symbol to file */
-                       conf_write_symbol(sym, out, true);
+
+                       conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
                }
 
 next:
@@ -771,7 +910,6 @@ out:
 int conf_write_autoconf(void)
 {
        struct symbol *sym;
-       const char *str;
        const char *name;
        FILE *out, *tristate, *out_h;
        int i;
@@ -800,68 +938,23 @@ int conf_write_autoconf(void)
                return 1;
        }
 
-       fprintf(out, "#\n"
-                    "# Automatically generated make config: don't edit\n"
-                    "# %s\n"
-                    "#\n",
-                    rootmenu.prompt->text);
-       fprintf(tristate, "#\n"
-                         "# Automatically generated - do not edit\n"
-                         "\n");
-       fprintf(out_h, "/*\n"
-                      " * Automatically generated C config: don't edit\n"
-                      " * %s\n"
-                      " */\n",
-                      rootmenu.prompt->text);
+       conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+       conf_write_heading(tristate, &tristate_printer_cb, NULL);
+
+       conf_write_heading(out_h, &header_printer_cb, NULL);
 
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
                if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
                        continue;
 
-               /* write symbol to config file */
-               conf_write_symbol(sym, out, false);
+               /* write symbol to auto.conf, tristate and header files */
+               conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
 
-               /* update autoconf and tristate files */
-               switch (sym->type) {
-               case S_BOOLEAN:
-               case S_TRISTATE:
-                       switch (sym_get_tristate_value(sym)) {
-                       case no:
-                               break;
-                       case mod:
-                               fprintf(tristate, "%s%s=M\n",
-                                   CONFIG_, sym->name);
-                               fprintf(out_h, "#define %s%s_MODULE 1\n",
-                                   CONFIG_, sym->name);
-                               break;
-                       case yes:
-                               if (sym->type == S_TRISTATE)
-                                       fprintf(tristate,"%s%s=Y\n",
-                                           CONFIG_, sym->name);
-                               fprintf(out_h, "#define %s%s 1\n",
-                                   CONFIG_, sym->name);
-                               break;
-                       }
-                       break;
-               case S_STRING:
-                       conf_write_string(true, sym->name, sym_get_string_value(sym), out_h);
-                       break;
-               case S_HEX:
-                       str = sym_get_string_value(sym);
-                       if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
-                               fprintf(out_h, "#define %s%s 0x%s\n",
-                                   CONFIG_, sym->name, str);
-                               break;
-                       }
-               case S_INT:
-                       str = sym_get_string_value(sym);
-                       fprintf(out_h, "#define %s%s %s\n",
-                           CONFIG_, sym->name, str);
-                       break;
-               default:
-                       break;
-               }
+               conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
+
+               conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
        }
        fclose(out);
        fclose(tristate);
index 001003452f6872aef385099f1d660ffa1054a288..290ce41f8ba46fcee2d61b6d7f3bd157593f4b66 100644 (file)
@@ -7,15 +7,13 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define DEBUG_EXPR     0
 
 struct expr *expr_alloc_symbol(struct symbol *sym)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = E_SYMBOL;
        e->left.sym = sym;
        return e;
@@ -23,8 +21,7 @@ struct expr *expr_alloc_symbol(struct symbol *sym)
 
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = type;
        e->left.expr = ce;
        return e;
@@ -32,8 +29,7 @@ struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 
 struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = type;
        e->left.expr = e1;
        e->right.expr = e2;
@@ -42,8 +38,7 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e
 
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = type;
        e->left.sym = s1;
        e->right.sym = s2;
index 16bfae2d321742bd5bf06e0a17e3e6377b47ef71..80fce57080cc36787e01efc00fe8a111efa3d0ff 100644 (file)
@@ -172,8 +172,6 @@ struct menu {
 #define MENU_CHANGED           0x0001
 #define MENU_ROOT              0x0002
 
-#ifndef SWIG
-
 extern struct file *file_list;
 extern struct file *current_file;
 struct file *lookup_file(const char *name);
@@ -218,7 +216,6 @@ static inline int expr_is_no(struct expr *e)
 {
        return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
 }
-#endif
 
 #ifdef __cplusplus
 }
index a11d5f7b9eeb1f793514fb8548b646a7414ca321..9f4438027df4201b9fb34d4191cdb3da9ac4994f 100644 (file)
@@ -285,8 +285,6 @@ void init_left_tree(void)
 static void renderer_edited(GtkCellRendererText * cell,
                            const gchar * path_string,
                            const gchar * new_text, gpointer user_data);
-static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
-                            gchar * arg1, gpointer user_data);
 
 void init_right_tree(void)
 {
@@ -320,8 +318,6 @@ void init_right_tree(void)
                                            "inconsistent", COL_BTNINC,
                                            "visible", COL_BTNVIS,
                                            "radio", COL_BTNRAD, NULL);
-       /*g_signal_connect(G_OBJECT(renderer), "toggled",
-          G_CALLBACK(renderer_toggled), NULL); */
        renderer = gtk_cell_renderer_text_new();
        gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
                                        renderer, FALSE);
@@ -888,35 +884,6 @@ static void toggle_sym_value(struct menu *menu)
                display_tree_part();    //fixme: keep exp/coll
 }
 
-static void renderer_toggled(GtkCellRendererToggle * cell,
-                            gchar * path_string, gpointer user_data)
-{
-       GtkTreePath *path, *sel_path = NULL;
-       GtkTreeIter iter, sel_iter;
-       GtkTreeSelection *sel;
-       struct menu *menu;
-
-       path = gtk_tree_path_new_from_string(path_string);
-       if (!gtk_tree_model_get_iter(model2, &iter, path))
-               return;
-
-       sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
-       if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
-               sel_path = gtk_tree_model_get_path(model2, &sel_iter);
-       if (!sel_path)
-               goto out1;
-       if (gtk_tree_path_compare(path, sel_path))
-               goto out2;
-
-       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
-       toggle_sym_value(menu);
-
-      out2:
-       gtk_tree_path_free(sel_path);
-      out1:
-       gtk_tree_path_free(path);
-}
-
 static gint column2index(GtkTreeViewColumn * column)
 {
        gint i;
@@ -1172,6 +1139,7 @@ static gchar **fill_row(struct menu *menu)
                        row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
                if (sym_is_choice(sym))
                        break;
+               /* fall through */
        case S_TRISTATE:
                val = sym_get_tristate_value(sym);
                switch (val) {
@@ -1506,10 +1474,6 @@ int main(int ac, char *av[])
        char *env;
        gchar *glade_file;
 
-#ifndef LKC_DIRECT_LINK
-       kconfig_load();
-#endif
-
        bindtextdomain(PACKAGE, LOCALEDIR);
        bind_textdomain_codeset(PACKAGE, "UTF-8");
        textdomain(PACKAGE);
diff --git a/scripts/kconfig/kconfig_load.c b/scripts/kconfig/kconfig_load.c
deleted file mode 100644 (file)
index dbdcaad..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <dlfcn.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "lkc.h"
-
-#define P(name,type,arg)       type (*name ## _p) arg
-#include "lkc_proto.h"
-#undef P
-
-void kconfig_load(void)
-{
-       void *handle;
-       char *error;
-
-       handle = dlopen("./libkconfig.so", RTLD_LAZY);
-       if (!handle) {
-               handle = dlopen("./scripts/kconfig/libkconfig.so", RTLD_LAZY);
-               if (!handle) {
-                       fprintf(stderr, "%s\n", dlerror());
-                       exit(1);
-               }
-       }
-
-#define P(name,type,arg)                       \
-{                                              \
-       name ## _p = dlsym(handle, #name);      \
-        if ((error = dlerror()))  {            \
-                fprintf(stderr, "%s\n", error);        \
-               exit(1);                        \
-       }                                       \
-}
-#include "lkc_proto.h"
-#undef P
-}
index e9d8e791bf0d2d71e19dbaa447488b138a5d00fe..2858738b22d5aeac27154f74af433540839d37a6 100644 (file)
@@ -7,7 +7,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 static char *escape(const char* text, char *bf, int len)
index f34a0a9b50f1eeba364465b849d25d9c5e73face..b633bdb9f3d47c815be8727b155471167135626a 100644 (file)
@@ -21,12 +21,7 @@ static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c;
 extern "C" {
 #endif
 
-#ifdef LKC_DIRECT_LINK
 #define P(name,type,arg)       extern type name arg
-#else
-#include "lkc_defs.h"
-#define P(name,type,arg)       extern type (*name ## _p) arg
-#endif
 #include "lkc_proto.h"
 #undef P
 
@@ -79,9 +74,6 @@ void zconf_nextfile(const char *name);
 int zconf_lineno(void);
 const char *zconf_curname(void);
 
-/* conf.c */
-void xfgets(char *str, int size, FILE *in);
-
 /* confdata.c */
 const char *conf_get_configname(void);
 const char *conf_get_autoconfig_name(void);
@@ -90,6 +82,11 @@ void sym_set_change_count(int count);
 void sym_add_change_count(int count);
 void conf_set_all_new_symbols(enum conf_def_mode mode);
 
+struct conf_printer {
+       void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
+       void (*print_comment)(FILE *, const char *, void *);
+};
+
 /* confdata.c and expr.c */
 static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
 {
@@ -97,9 +94,6 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
                fprintf(stderr, "\nError in writing or end of file.\n");
 }
 
-/* kconfig_load.c */
-void kconfig_load(void);
-
 /* menu.c */
 void _menu_init(void);
 void menu_warn(struct menu *menu, const char *fmt, ...);
index 17342fef38b94b877f0b5e93481314c27211d093..47fe9c340f9a20b9b6bd9871d18d79ea9ddc7d1d 100644 (file)
@@ -31,6 +31,7 @@ P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
 P(sym_lookup,struct symbol *,(const char *name, int flags));
 P(sym_find,struct symbol *,(const char *name));
 P(sym_expand_string_value,const char *,(const char *in));
+P(sym_escape_string_value, const char *,(const char *in));
 P(sym_re_search,struct symbol **,(const char *pattern));
 P(sym_type_name,const char *,(enum symbol_type type));
 P(sym_calc_value,void,(struct symbol *sym));
index d433c7a24745ff75278132bb9930e242f0785f86..820d2b6800fb5d856a56394cd9786610337fc8b8 100644 (file)
@@ -18,7 +18,6 @@
 #include <unistd.h>
 #include <locale.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lxdialog/dialog.h"
 
@@ -845,6 +844,7 @@ int main(int ac, char **av)
                                "\n\n"));
                        return 1;
                }
+               /* fall through */
        case -1:
                printf(_("\n\n"
                        "*** End of the configuration.\n"
index 5fdf10dc1d8a45eb2ed06bffbb9425233b02c006..d66008639a43f46e60235dee932558a6c4d00223 100644 (file)
@@ -3,10 +3,11 @@
  * Released under the terms of the GNU GPL v2.0.
  */
 
+#include <ctype.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 static const char nohelp_text[] = N_(
@@ -350,7 +351,7 @@ void menu_finalize(struct menu *parent)
                        last_menu->next = NULL;
                }
 
-               sym->dir_dep.expr = parent->dep;
+               sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
        }
        for (menu = parent->list; menu; menu = menu->next) {
                if (sym && sym_is_choice(sym) &&
index 488dd741078747132b08dc9afb33001f4a03db5a..39ca1f1640eaf6f27cdaa0ce5a9399b42ee89e4e 100644 (file)
@@ -7,7 +7,7 @@
  */
 #define _GNU_SOURCE
 #include <string.h>
-#define LKC_DIRECT_LINK
+
 #include "lkc.h"
 #include "nconf.h"
 #include <ctype.h>
@@ -1067,7 +1067,6 @@ static void conf(struct menu *menu)
        struct menu *submenu = 0;
        const char *prompt = menu_get_prompt(menu);
        struct symbol *sym;
-       struct menu *active_menu = NULL;
        int res;
        int current_index = 0;
        int last_top_row = 0;
@@ -1152,13 +1151,9 @@ static void conf(struct menu *menu)
                        continue;
 
                submenu = (struct menu *) item_data();
-               active_menu = (struct menu *)item_data();
                if (!submenu || !menu_is_visible(submenu))
                        continue;
-               if (submenu)
-                       sym = submenu->sym;
-               else
-                       sym = NULL;
+               sym = submenu->sym;
 
                switch (res) {
                case ' ':
@@ -1222,20 +1217,13 @@ static void conf_message_callback(const char *fmt, va_list ap)
 
 static void show_help(struct menu *menu)
 {
-       struct gstr help = str_new();
-
-       if (menu && menu->sym && menu_has_help(menu)) {
-               if (menu->sym->name) {
-                       str_printf(&help, "%s%s:\n\n", CONFIG_, menu->sym->name);
-                       str_append(&help, _(menu_get_help(menu)));
-                       str_append(&help, "\n");
-                       get_symbol_str(&help, menu->sym);
-               } else {
-                       str_append(&help, _(menu_get_help(menu)));
-               }
-       } else {
-               str_append(&help, nohelp_text);
-       }
+       struct gstr help;
+
+       if (!menu)
+               return;
+
+       help = str_new();
+       menu_get_ext_help(menu, &help);
        show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
        str_free(&help);
 }
index c2796b866f8f14a37453f409429b900e1f11ba44..df274febb3e51d6331c5b64e4f29a64f51817538 100644 (file)
@@ -1478,10 +1478,13 @@ void ConfigMainWindow::loadConfig(void)
        ConfigView::updateListAll();
 }
 
-void ConfigMainWindow::saveConfig(void)
+bool ConfigMainWindow::saveConfig(void)
 {
-       if (conf_write(NULL))
+       if (conf_write(NULL)) {
                QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+               return false;
+       }
+       return true;
 }
 
 void ConfigMainWindow::saveConfigAs(void)
@@ -1642,7 +1645,11 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
        mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
        switch (mb.exec()) {
        case QMessageBox::Yes:
-               saveConfig();
+               if (saveConfig())
+                       e->accept();
+               else
+                       e->ignore();
+               break;
        case QMessageBox::No:
                e->accept();
                break;
@@ -1745,10 +1752,6 @@ int main(int ac, char** av)
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
 
-#ifndef LKC_DIRECT_LINK
-       kconfig_load();
-#endif
-
        progname = av[0];
        configApp = new QApplication(ac, av);
        if (ac > 1 && av[1][0] == '-') {
index 91677d900dbd0aa68e07ca74a90709d5182edcf5..3715b3e7212c9adccdc25483e632487a64360b54 100644 (file)
@@ -311,7 +311,7 @@ public slots:
        void listFocusChanged(void);
        void goBack(void);
        void loadConfig(void);
-       void saveConfig(void);
+       bool saveConfig(void);
        void saveConfigAs(void);
        void searchConfig(void);
        void showSingleView(void);
index a796c95fe8a0eb460688cf7ab8201a6e77d4c794..071f00c3046e69e77112a4e5cf56d4f686fc101f 100644 (file)
@@ -9,7 +9,6 @@
 #include <regex.h>
 #include <sys/utsname.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 struct symbol symbol_yes = {
@@ -751,7 +750,8 @@ const char *sym_get_string_value(struct symbol *sym)
                case no:
                        return "n";
                case mod:
-                       return "m";
+                       sym_calc_value(modules_sym);
+                       return (modules_sym->curr.tri == no) ? "n" : "m";
                case yes:
                        return "y";
                }
@@ -893,6 +893,49 @@ const char *sym_expand_string_value(const char *in)
        return res;
 }
 
+const char *sym_escape_string_value(const char *in)
+{
+       const char *p;
+       size_t reslen;
+       char *res;
+       size_t l;
+
+       reslen = strlen(in) + strlen("\"\"") + 1;
+
+       p = in;
+       for (;;) {
+               l = strcspn(p, "\"\\");
+               p += l;
+
+               if (p[0] == '\0')
+                       break;
+
+               reslen++;
+               p++;
+       }
+
+       res = malloc(reslen);
+       res[0] = '\0';
+
+       strcat(res, "\"");
+
+       p = in;
+       for (;;) {
+               l = strcspn(p, "\"\\");
+               strncat(res, p, l);
+               p += l;
+
+               if (p[0] == '\0')
+                       break;
+
+               strcat(res, "\\");
+               strncat(res, p++, 1);
+       }
+
+       strcat(res, "\"");
+       return res;
+}
+
 struct symbol **sym_re_search(const char *pattern)
 {
        struct symbol *sym, **sym_arr = NULL;
index 6330cc871a471495e6820be441c96ea61c6886a1..d0b8b2318e489577fd82713fd79b1759c3ff170b 100644 (file)
@@ -5,6 +5,8 @@
  * Released under the terms of the GNU GPL v2.0.
  */
 
+#include <stdarg.h>
+#include <stdlib.h>
 #include <string.h>
 #include "lkc.h"
 
index ddee5fc51811d93aeee760adf9c9b31e68c967c0..00f9d3a9cf8b96fd85639339019bf1bc2afab306 100644 (file)
@@ -14,7 +14,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define START_STRSIZE  16
index 906c09911748c2efaba1bef5de59a3199a1dfff2..c32b1a49f5a30923b70e097e7241735772ad4b67 100644 (file)
@@ -776,7 +776,6 @@ char *zconftext;
 #include <string.h>
 #include <unistd.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define START_STRSIZE  16
index 211e1a277037f813aa8c4fb83d4a7aecb300b5ab..f636141e7bfd73526569bb96d300faba322761fe 100644 (file)
@@ -87,7 +87,6 @@
 #include <string.h>
 #include <stdbool.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
index c38cc5aa8ed19ca55a22bc6b10034af01063443f..864da07ba4aadc02a71a0e4b8414ef330f570674 100644 (file)
@@ -11,7 +11,6 @@
 #include <string.h>
 #include <stdbool.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
index 7312bf9f7afcb6e6c8f96b68d600b0675f2ee146..c1e18ba5bdc09c65d259ad4bd9f374ef04dffd2f 100644 (file)
@@ -73,7 +73,6 @@ static int may_change_ptraced_domain(struct task_struct *task,
                cred = get_task_cred(tracer);
                tracerp = aa_cred_profile(cred);
        }
-       rcu_read_unlock();
 
        /* not ptraced */
        if (!tracer || unconfined(tracerp))
@@ -82,6 +81,7 @@ static int may_change_ptraced_domain(struct task_struct *task,
        error = aa_may_ptrace(tracer, tracerp, to_profile, PTRACE_MODE_ATTACH);
 
 out:
+       rcu_read_unlock();
        if (cred)
                put_cred(cred);
 
index 3d2fd141dff76f078d171e2abf28fd4e97b5378c..37832026e58a234c249b44959f6cba5aa1dacbb5 100644 (file)
@@ -127,7 +127,7 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
        *inheritable = cred->cap_inheritable;
        *permitted = cred->cap_permitted;
 
-       if (!unconfined(profile)) {
+       if (!unconfined(profile) && !COMPLAIN_MODE(profile)) {
                *effective = cap_intersect(*effective, profile->caps.allow);
                *permitted = cap_intersect(*permitted, profile->caps.allow);
        }
index 1bf090a885feed4791cab9b8a6947bde347f868e..b34cc6ee6900c3be1453e6aa205b5469f5461f03 100644 (file)
@@ -14,7 +14,7 @@ obj-y := \
        user_defined.o
 
 obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
-obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted.o
+obj-$(CONFIG_ENCRYPTED_KEYS) += ecryptfs_format.o encrypted.o
 obj-$(CONFIG_KEYS_COMPAT) += compat.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/security/keys/ecryptfs_format.c b/security/keys/ecryptfs_format.c
new file mode 100644 (file)
index 0000000..6daa3b6
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * ecryptfs_format.c: helper functions for the encrypted key type
+ *
+ * Copyright (C) 2006 International Business Machines Corp.
+ * Copyright (C) 2010 Politecnico di Torino, Italy
+ *                    TORSEC group -- http://security.polito.it
+ *
+ * Authors:
+ * Michael A. Halcrow <mahalcro@us.ibm.com>
+ * Tyler Hicks <tyhicks@ou.edu>
+ * Roberto Sassu <roberto.sassu@polito.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include "ecryptfs_format.h"
+
+u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok)
+{
+       return auth_tok->token.password.session_key_encryption_key;
+}
+EXPORT_SYMBOL(ecryptfs_get_auth_tok_key);
+
+/*
+ * ecryptfs_get_versions()
+ *
+ * Source code taken from the software 'ecryptfs-utils' version 83.
+ *
+ */
+void ecryptfs_get_versions(int *major, int *minor, int *file_version)
+{
+       *major = ECRYPTFS_VERSION_MAJOR;
+       *minor = ECRYPTFS_VERSION_MINOR;
+       if (file_version)
+               *file_version = ECRYPTFS_SUPPORTED_FILE_VERSION;
+}
+EXPORT_SYMBOL(ecryptfs_get_versions);
+
+/*
+ * ecryptfs_fill_auth_tok - fill the ecryptfs_auth_tok structure
+ *
+ * Fill the ecryptfs_auth_tok structure with required ecryptfs data.
+ * The source code is inspired to the original function generate_payload()
+ * shipped with the software 'ecryptfs-utils' version 83.
+ *
+ */
+int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok,
+                          const char *key_desc)
+{
+       int major, minor;
+
+       ecryptfs_get_versions(&major, &minor, NULL);
+       auth_tok->version = (((uint16_t)(major << 8) & 0xFF00)
+                            | ((uint16_t)minor & 0x00FF));
+       auth_tok->token_type = ECRYPTFS_PASSWORD;
+       strncpy((char *)auth_tok->token.password.signature, key_desc,
+               ECRYPTFS_PASSWORD_SIG_SIZE);
+       auth_tok->token.password.session_key_encryption_key_bytes =
+               ECRYPTFS_MAX_KEY_BYTES;
+       /*
+        * Removed auth_tok->token.password.salt and
+        * auth_tok->token.password.session_key_encryption_key
+        * initialization from the original code
+        */
+       /* TODO: Make the hash parameterizable via policy */
+       auth_tok->token.password.flags |=
+               ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET;
+       /* The kernel code will encrypt the session key. */
+       auth_tok->session_key.encrypted_key[0] = 0;
+       auth_tok->session_key.encrypted_key_size = 0;
+       /* Default; subject to change by kernel eCryptfs */
+       auth_tok->token.password.hash_algo = PGP_DIGEST_ALGO_SHA512;
+       auth_tok->token.password.flags &= ~(ECRYPTFS_PERSISTENT_PASSWORD);
+       return 0;
+}
+EXPORT_SYMBOL(ecryptfs_fill_auth_tok);
+
+MODULE_LICENSE("GPL");
diff --git a/security/keys/ecryptfs_format.h b/security/keys/ecryptfs_format.h
new file mode 100644 (file)
index 0000000..40294de
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * ecryptfs_format.h: helper functions for the encrypted key type
+ *
+ * Copyright (C) 2006 International Business Machines Corp.
+ * Copyright (C) 2010 Politecnico di Torino, Italy
+ *                    TORSEC group -- http://security.polito.it
+ *
+ * Authors:
+ * Michael A. Halcrow <mahalcro@us.ibm.com>
+ * Tyler Hicks <tyhicks@ou.edu>
+ * Roberto Sassu <roberto.sassu@polito.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ */
+
+#ifndef __KEYS_ECRYPTFS_H
+#define __KEYS_ECRYPTFS_H
+
+#include <linux/ecryptfs.h>
+
+#define PGP_DIGEST_ALGO_SHA512   10
+
+u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok);
+void ecryptfs_get_versions(int *major, int *minor, int *file_version);
+int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok,
+                          const char *key_desc);
+
+#endif /* __KEYS_ECRYPTFS_H */
index b1cba5bf0a5e3d092b57318a242014e915af04ff..e7eca9ec4c65ffdda866f1a7d713506818fd3c9c 100644 (file)
@@ -1,8 +1,11 @@
 /*
  * Copyright (C) 2010 IBM Corporation
+ * Copyright (C) 2010 Politecnico di Torino, Italy
+ *                    TORSEC group -- http://security.polito.it
  *
- * Author:
+ * Authors:
  * Mimi Zohar <zohar@us.ibm.com>
+ * Roberto Sassu <roberto.sassu@polito.it>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <linux/rcupdate.h>
 #include <linux/scatterlist.h>
 #include <linux/crypto.h>
+#include <linux/ctype.h>
 #include <crypto/hash.h>
 #include <crypto/sha.h>
 #include <crypto/aes.h>
 
 #include "encrypted.h"
+#include "ecryptfs_format.h"
 
 static const char KEY_TRUSTED_PREFIX[] = "trusted:";
 static const char KEY_USER_PREFIX[] = "user:";
 static const char hash_alg[] = "sha256";
 static const char hmac_alg[] = "hmac(sha256)";
 static const char blkcipher_alg[] = "cbc(aes)";
+static const char key_format_default[] = "default";
+static const char key_format_ecryptfs[] = "ecryptfs";
 static unsigned int ivsize;
 static int blksize;
 
 #define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
 #define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
+#define KEY_ECRYPTFS_DESC_LEN 16
 #define HASH_SIZE SHA256_DIGEST_SIZE
 #define MAX_DATA_SIZE 4096
 #define MIN_DATA_SIZE  20
@@ -58,6 +66,16 @@ enum {
        Opt_err = -1, Opt_new, Opt_load, Opt_update
 };
 
+enum {
+       Opt_error = -1, Opt_default, Opt_ecryptfs
+};
+
+static const match_table_t key_format_tokens = {
+       {Opt_default, "default"},
+       {Opt_ecryptfs, "ecryptfs"},
+       {Opt_error, NULL}
+};
+
 static const match_table_t key_tokens = {
        {Opt_new, "new"},
        {Opt_load, "load"},
@@ -81,10 +99,38 @@ static int aes_get_sizes(void)
        return 0;
 }
 
+/*
+ * valid_ecryptfs_desc - verify the description of a new/loaded encrypted key
+ *
+ * The description of a encrypted key with format 'ecryptfs' must contain
+ * exactly 16 hexadecimal characters.
+ *
+ */
+static int valid_ecryptfs_desc(const char *ecryptfs_desc)
+{
+       int i;
+
+       if (strlen(ecryptfs_desc) != KEY_ECRYPTFS_DESC_LEN) {
+               pr_err("encrypted_key: key description must be %d hexadecimal "
+                      "characters long\n", KEY_ECRYPTFS_DESC_LEN);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < KEY_ECRYPTFS_DESC_LEN; i++) {
+               if (!isxdigit(ecryptfs_desc[i])) {
+                       pr_err("encrypted_key: key description must contain "
+                              "only hexadecimal characters\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key
  *
- * key-type:= "trusted:" | "encrypted:"
+ * key-type:= "trusted:" | "user:"
  * desc:= master-key description
  *
  * Verify that 'key-type' is valid and that 'desc' exists. On key update,
@@ -118,8 +164,9 @@ out:
  * datablob_parse - parse the keyctl data
  *
  * datablob format:
- * new <master-key name> <decrypted data length>
- * load <master-key name> <decrypted data length> <encrypted iv + data>
+ * new [<format>] <master-key name> <decrypted data length>
+ * load [<format>] <master-key name> <decrypted data length>
+ *     <encrypted iv + data>
  * update <new-master-key name>
  *
  * Tokenizes a copy of the keyctl data, returning a pointer to each token,
@@ -127,52 +174,95 @@ out:
  *
  * On success returns 0, otherwise -EINVAL.
  */
-static int datablob_parse(char *datablob, char **master_desc,
-                         char **decrypted_datalen, char **hex_encoded_iv)
+static int datablob_parse(char *datablob, const char **format,
+                         char **master_desc, char **decrypted_datalen,
+                         char **hex_encoded_iv)
 {
        substring_t args[MAX_OPT_ARGS];
        int ret = -EINVAL;
        int key_cmd;
-       char *p;
+       int key_format;
+       char *p, *keyword;
+
+       keyword = strsep(&datablob, " \t");
+       if (!keyword) {
+               pr_info("encrypted_key: insufficient parameters specified\n");
+               return ret;
+       }
+       key_cmd = match_token(keyword, key_tokens, args);
 
+       /* Get optional format: default | ecryptfs */
        p = strsep(&datablob, " \t");
-       if (!p)
+       if (!p) {
+               pr_err("encrypted_key: insufficient parameters specified\n");
                return ret;
-       key_cmd = match_token(p, key_tokens, args);
+       }
 
-       *master_desc = strsep(&datablob, " \t");
-       if (!*master_desc)
+       key_format = match_token(p, key_format_tokens, args);
+       switch (key_format) {
+       case Opt_ecryptfs:
+       case Opt_default:
+               *format = p;
+               *master_desc = strsep(&datablob, " \t");
+               break;
+       case Opt_error:
+               *master_desc = p;
+               break;
+       }
+
+       if (!*master_desc) {
+               pr_info("encrypted_key: master key parameter is missing\n");
                goto out;
+       }
 
-       if (valid_master_desc(*master_desc, NULL) < 0)
+       if (valid_master_desc(*master_desc, NULL) < 0) {
+               pr_info("encrypted_key: master key parameter \'%s\' "
+                       "is invalid\n", *master_desc);
                goto out;
+       }
 
        if (decrypted_datalen) {
                *decrypted_datalen = strsep(&datablob, " \t");
-               if (!*decrypted_datalen)
+               if (!*decrypted_datalen) {
+                       pr_info("encrypted_key: keylen parameter is missing\n");
                        goto out;
+               }
        }
 
        switch (key_cmd) {
        case Opt_new:
-               if (!decrypted_datalen)
+               if (!decrypted_datalen) {
+                       pr_info("encrypted_key: keyword \'%s\' not allowed "
+                               "when called from .update method\n", keyword);
                        break;
+               }
                ret = 0;
                break;
        case Opt_load:
-               if (!decrypted_datalen)
+               if (!decrypted_datalen) {
+                       pr_info("encrypted_key: keyword \'%s\' not allowed "
+                               "when called from .update method\n", keyword);
                        break;
+               }
                *hex_encoded_iv = strsep(&datablob, " \t");
-               if (!*hex_encoded_iv)
+               if (!*hex_encoded_iv) {
+                       pr_info("encrypted_key: hex blob is missing\n");
                        break;
+               }
                ret = 0;
                break;
        case Opt_update:
-               if (decrypted_datalen)
+               if (decrypted_datalen) {
+                       pr_info("encrypted_key: keyword \'%s\' not allowed "
+                               "when called from .instantiate method\n",
+                               keyword);
                        break;
+               }
                ret = 0;
                break;
        case Opt_err:
+               pr_info("encrypted_key: keyword \'%s\' not recognized\n",
+                       keyword);
                break;
        }
 out:
@@ -197,8 +287,8 @@ static char *datablob_format(struct encrypted_key_payload *epayload,
        ascii_buf[asciiblob_len] = '\0';
 
        /* copy datablob master_desc and datalen strings */
-       len = sprintf(ascii_buf, "%s %s ", epayload->master_desc,
-                     epayload->datalen);
+       len = sprintf(ascii_buf, "%s %s %s ", epayload->format,
+                     epayload->master_desc, epayload->datalen);
 
        /* convert the hex encoded iv, encrypted-data and HMAC to ascii */
        bufp = &ascii_buf[len];
@@ -378,11 +468,13 @@ static struct key *request_master_key(struct encrypted_key_payload *epayload,
        } else
                goto out;
 
-       if (IS_ERR(mkey))
+       if (IS_ERR(mkey)) {
                pr_info("encrypted_key: key %s not found",
                        epayload->master_desc);
-       if (mkey)
-               dump_master_key(*master_key, *master_keylen);
+               goto out;
+       }
+
+       dump_master_key(*master_key, *master_keylen);
 out:
        return mkey;
 }
@@ -439,9 +531,9 @@ static int datablob_hmac_append(struct encrypted_key_payload *epayload,
        if (ret < 0)
                goto out;
 
-       digest = epayload->master_desc + epayload->datablob_len;
+       digest = epayload->format + epayload->datablob_len;
        ret = calc_hmac(digest, derived_key, sizeof derived_key,
-                       epayload->master_desc, epayload->datablob_len);
+                       epayload->format, epayload->datablob_len);
        if (!ret)
                dump_hmac(NULL, digest, HASH_SIZE);
 out:
@@ -450,26 +542,35 @@ out:
 
 /* verify HMAC before decrypting encrypted key */
 static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
-                               const u8 *master_key, size_t master_keylen)
+                               const u8 *format, const u8 *master_key,
+                               size_t master_keylen)
 {
        u8 derived_key[HASH_SIZE];
        u8 digest[HASH_SIZE];
        int ret;
+       char *p;
+       unsigned short len;
 
        ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
        if (ret < 0)
                goto out;
 
-       ret = calc_hmac(digest, derived_key, sizeof derived_key,
-                       epayload->master_desc, epayload->datablob_len);
+       len = epayload->datablob_len;
+       if (!format) {
+               p = epayload->master_desc;
+               len -= strlen(epayload->format) + 1;
+       } else
+               p = epayload->format;
+
+       ret = calc_hmac(digest, derived_key, sizeof derived_key, p, len);
        if (ret < 0)
                goto out;
-       ret = memcmp(digest, epayload->master_desc + epayload->datablob_len,
+       ret = memcmp(digest, epayload->format + epayload->datablob_len,
                     sizeof digest);
        if (ret) {
                ret = -EINVAL;
                dump_hmac("datablob",
-                         epayload->master_desc + epayload->datablob_len,
+                         epayload->format + epayload->datablob_len,
                          HASH_SIZE);
                dump_hmac("calc", digest, HASH_SIZE);
        }
@@ -514,13 +615,16 @@ out:
 
 /* Allocate memory for decrypted key and datablob. */
 static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
+                                                        const char *format,
                                                         const char *master_desc,
                                                         const char *datalen)
 {
        struct encrypted_key_payload *epayload = NULL;
        unsigned short datablob_len;
        unsigned short decrypted_datalen;
+       unsigned short payload_datalen;
        unsigned int encrypted_datalen;
+       unsigned int format_len;
        long dlen;
        int ret;
 
@@ -528,29 +632,43 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
        if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE)
                return ERR_PTR(-EINVAL);
 
+       format_len = (!format) ? strlen(key_format_default) : strlen(format);
        decrypted_datalen = dlen;
+       payload_datalen = decrypted_datalen;
+       if (format && !strcmp(format, key_format_ecryptfs)) {
+               if (dlen != ECRYPTFS_MAX_KEY_BYTES) {
+                       pr_err("encrypted_key: keylen for the ecryptfs format "
+                              "must be equal to %d bytes\n",
+                              ECRYPTFS_MAX_KEY_BYTES);
+                       return ERR_PTR(-EINVAL);
+               }
+               decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES;
+               payload_datalen = sizeof(struct ecryptfs_auth_tok);
+       }
+
        encrypted_datalen = roundup(decrypted_datalen, blksize);
 
-       datablob_len = strlen(master_desc) + 1 + strlen(datalen) + 1
-           + ivsize + 1 + encrypted_datalen;
+       datablob_len = format_len + 1 + strlen(master_desc) + 1
+           + strlen(datalen) + 1 + ivsize + 1 + encrypted_datalen;
 
-       ret = key_payload_reserve(key, decrypted_datalen + datablob_len
+       ret = key_payload_reserve(key, payload_datalen + datablob_len
                                  + HASH_SIZE + 1);
        if (ret < 0)
                return ERR_PTR(ret);
 
-       epayload = kzalloc(sizeof(*epayload) + decrypted_datalen +
+       epayload = kzalloc(sizeof(*epayload) + payload_datalen +
                           datablob_len + HASH_SIZE + 1, GFP_KERNEL);
        if (!epayload)
                return ERR_PTR(-ENOMEM);
 
+       epayload->payload_datalen = payload_datalen;
        epayload->decrypted_datalen = decrypted_datalen;
        epayload->datablob_len = datablob_len;
        return epayload;
 }
 
 static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
-                                const char *hex_encoded_iv)
+                                const char *format, const char *hex_encoded_iv)
 {
        struct key *mkey;
        u8 derived_key[HASH_SIZE];
@@ -571,14 +689,14 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
        hex2bin(epayload->iv, hex_encoded_iv, ivsize);
        hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen);
 
-       hmac = epayload->master_desc + epayload->datablob_len;
+       hmac = epayload->format + epayload->datablob_len;
        hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE);
 
        mkey = request_master_key(epayload, &master_key, &master_keylen);
        if (IS_ERR(mkey))
                return PTR_ERR(mkey);
 
-       ret = datablob_hmac_verify(epayload, master_key, master_keylen);
+       ret = datablob_hmac_verify(epayload, format, master_key, master_keylen);
        if (ret < 0) {
                pr_err("encrypted_key: bad hmac (%d)\n", ret);
                goto out;
@@ -598,13 +716,28 @@ out:
 }
 
 static void __ekey_init(struct encrypted_key_payload *epayload,
-                       const char *master_desc, const char *datalen)
+                       const char *format, const char *master_desc,
+                       const char *datalen)
 {
-       epayload->master_desc = epayload->decrypted_data
-           + epayload->decrypted_datalen;
+       unsigned int format_len;
+
+       format_len = (!format) ? strlen(key_format_default) : strlen(format);
+       epayload->format = epayload->payload_data + epayload->payload_datalen;
+       epayload->master_desc = epayload->format + format_len + 1;
        epayload->datalen = epayload->master_desc + strlen(master_desc) + 1;
        epayload->iv = epayload->datalen + strlen(datalen) + 1;
        epayload->encrypted_data = epayload->iv + ivsize + 1;
+       epayload->decrypted_data = epayload->payload_data;
+
+       if (!format)
+               memcpy(epayload->format, key_format_default, format_len);
+       else {
+               if (!strcmp(format, key_format_ecryptfs))
+                       epayload->decrypted_data =
+                               ecryptfs_get_auth_tok_key((struct ecryptfs_auth_tok *)epayload->payload_data);
+
+               memcpy(epayload->format, format, format_len);
+       }
 
        memcpy(epayload->master_desc, master_desc, strlen(master_desc));
        memcpy(epayload->datalen, datalen, strlen(datalen));
@@ -617,19 +750,29 @@ static void __ekey_init(struct encrypted_key_payload *epayload,
  * itself.  For an old key, decrypt the hex encoded data.
  */
 static int encrypted_init(struct encrypted_key_payload *epayload,
+                         const char *key_desc, const char *format,
                          const char *master_desc, const char *datalen,
                          const char *hex_encoded_iv)
 {
        int ret = 0;
 
-       __ekey_init(epayload, master_desc, datalen);
+       if (format && !strcmp(format, key_format_ecryptfs)) {
+               ret = valid_ecryptfs_desc(key_desc);
+               if (ret < 0)
+                       return ret;
+
+               ecryptfs_fill_auth_tok((struct ecryptfs_auth_tok *)epayload->payload_data,
+                                      key_desc);
+       }
+
+       __ekey_init(epayload, format, master_desc, datalen);
        if (!hex_encoded_iv) {
                get_random_bytes(epayload->iv, ivsize);
 
                get_random_bytes(epayload->decrypted_data,
                                 epayload->decrypted_datalen);
        } else
-               ret = encrypted_key_decrypt(epayload, hex_encoded_iv);
+               ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv);
        return ret;
 }
 
@@ -646,6 +789,7 @@ static int encrypted_instantiate(struct key *key, const void *data,
 {
        struct encrypted_key_payload *epayload = NULL;
        char *datablob = NULL;
+       const char *format = NULL;
        char *master_desc = NULL;
        char *decrypted_datalen = NULL;
        char *hex_encoded_iv = NULL;
@@ -659,18 +803,19 @@ static int encrypted_instantiate(struct key *key, const void *data,
                return -ENOMEM;
        datablob[datalen] = 0;
        memcpy(datablob, data, datalen);
-       ret = datablob_parse(datablob, &master_desc, &decrypted_datalen,
-                            &hex_encoded_iv);
+       ret = datablob_parse(datablob, &format, &master_desc,
+                            &decrypted_datalen, &hex_encoded_iv);
        if (ret < 0)
                goto out;
 
-       epayload = encrypted_key_alloc(key, master_desc, decrypted_datalen);
+       epayload = encrypted_key_alloc(key, format, master_desc,
+                                      decrypted_datalen);
        if (IS_ERR(epayload)) {
                ret = PTR_ERR(epayload);
                goto out;
        }
-       ret = encrypted_init(epayload, master_desc, decrypted_datalen,
-                            hex_encoded_iv);
+       ret = encrypted_init(epayload, key->description, format, master_desc,
+                            decrypted_datalen, hex_encoded_iv);
        if (ret < 0) {
                kfree(epayload);
                goto out;
@@ -706,6 +851,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen)
        struct encrypted_key_payload *new_epayload;
        char *buf;
        char *new_master_desc = NULL;
+       const char *format = NULL;
        int ret = 0;
 
        if (datalen <= 0 || datalen > 32767 || !data)
@@ -717,7 +863,7 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen)
 
        buf[datalen] = 0;
        memcpy(buf, data, datalen);
-       ret = datablob_parse(buf, &new_master_desc, NULL, NULL);
+       ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL);
        if (ret < 0)
                goto out;
 
@@ -725,18 +871,19 @@ static int encrypted_update(struct key *key, const void *data, size_t datalen)
        if (ret < 0)
                goto out;
 
-       new_epayload = encrypted_key_alloc(key, new_master_desc,
-                                          epayload->datalen);
+       new_epayload = encrypted_key_alloc(key, epayload->format,
+                                          new_master_desc, epayload->datalen);
        if (IS_ERR(new_epayload)) {
                ret = PTR_ERR(new_epayload);
                goto out;
        }
 
-       __ekey_init(new_epayload, new_master_desc, epayload->datalen);
+       __ekey_init(new_epayload, epayload->format, new_master_desc,
+                   epayload->datalen);
 
        memcpy(new_epayload->iv, epayload->iv, ivsize);
-       memcpy(new_epayload->decrypted_data, epayload->decrypted_data,
-              epayload->decrypted_datalen);
+       memcpy(new_epayload->payload_data, epayload->payload_data,
+              epayload->payload_datalen);
 
        rcu_assign_pointer(key->payload.data, new_epayload);
        call_rcu(&epayload->rcu, encrypted_rcu_free);
index 6cff37529b80210c3bc2b789c44662bb56a33f52..60d4e3f5e4bb21373900fb4cedb0907f61f68ea1 100644 (file)
@@ -251,6 +251,8 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
 
        if (IS_ERR(authkey_ref)) {
                authkey = ERR_CAST(authkey_ref);
+               if (authkey == ERR_PTR(-EAGAIN))
+                       authkey = ERR_PTR(-ENOKEY);
                goto error;
        }
 
index c8f385793235189d2534670dc811bc401dfed47d..7c7f8c16c10fcd2260e4ba7af4e9f5a7e98bb8eb 100644 (file)
@@ -9,3 +9,64 @@ config SECURITY_TOMOYO
          Required userspace tools and further information may be
          found at <http://tomoyo.sourceforge.jp/>.
          If you are unsure how to answer this question, answer N.
+
+config SECURITY_TOMOYO_MAX_ACCEPT_ENTRY
+       int "Default maximal count for learning mode"
+       default 2048
+       range 0 2147483647
+       depends on SECURITY_TOMOYO
+       help
+         This is the default value for maximal ACL entries
+         that are automatically appended into policy at "learning mode".
+         Some programs access thousands of objects, so running
+         such programs in "learning mode" dulls the system response
+         and consumes much memory.
+         This is the safeguard for such programs.
+
+config SECURITY_TOMOYO_MAX_AUDIT_LOG
+       int "Default maximal count for audit log"
+       default 1024
+       range 0 2147483647
+       depends on SECURITY_TOMOYO
+       help
+         This is the default value for maximal entries for
+         audit logs that the kernel can hold on memory.
+         You can read the log via /sys/kernel/security/tomoyo/audit.
+         If you don't need audit logs, you may set this value to 0.
+
+config SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+       bool "Activate without calling userspace policy loader."
+       default n
+       depends on SECURITY_TOMOYO
+       ---help---
+         Say Y here if you want to activate access control as soon as built-in
+         policy was loaded. This option will be useful for systems where
+         operations which can lead to the hijacking of the boot sequence are
+         needed before loading the policy. For example, you can activate
+         immediately after loading the fixed part of policy which will allow
+         only operations needed for mounting a partition which contains the
+         variant part of policy and verifying (e.g. running GPG check) and
+         loading the variant part of policy. Since you can start using
+         enforcing mode from the beginning, you can reduce the possibility of
+         hijacking the boot sequence.
+
+config SECURITY_TOMOYO_POLICY_LOADER
+       string "Location of userspace policy loader"
+       default "/sbin/tomoyo-init"
+       depends on SECURITY_TOMOYO
+       depends on !SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+       ---help---
+         This is the default pathname of policy loader which is called before
+         activation. You can override this setting via TOMOYO_loader= kernel
+         command line option.
+
+config SECURITY_TOMOYO_ACTIVATION_TRIGGER
+       string "Trigger for calling userspace policy loader"
+       default "/sbin/init"
+       depends on SECURITY_TOMOYO
+       depends on !SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+       ---help---
+         This is the default pathname of activation trigger.
+         You can override this setting via TOMOYO_trigger= kernel command line
+         option. For example, if you pass init=/bin/systemd option, you may
+         want to also pass TOMOYO_trigger=/bin/systemd option.
index 91640e96bd065776af1ffeffa23f06b5208ff368..95278b71fc2155ccb4ac603d5b1e93da44d56f59 100644 (file)
@@ -1 +1,48 @@
-obj-y = common.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o
+obj-y = audit.o common.o condition.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o
+
+$(obj)/policy/profile.conf:
+       @mkdir -p $(obj)/policy/
+       @echo Creating an empty policy/profile.conf
+       @touch $@
+
+$(obj)/policy/exception_policy.conf:
+       @mkdir -p $(obj)/policy/
+       @echo Creating a default policy/exception_policy.conf
+       @echo initialize_domain /sbin/modprobe from any >> $@
+       @echo initialize_domain /sbin/hotplug from any >> $@
+
+$(obj)/policy/domain_policy.conf:
+       @mkdir -p $(obj)/policy/
+       @echo Creating an empty policy/domain_policy.conf
+       @touch $@
+
+$(obj)/policy/manager.conf:
+       @mkdir -p $(obj)/policy/
+       @echo Creating an empty policy/manager.conf
+       @touch $@
+
+$(obj)/policy/stat.conf:
+       @mkdir -p $(obj)/policy/
+       @echo Creating an empty policy/stat.conf
+       @touch $@
+
+$(obj)/builtin-policy.h: $(obj)/policy/profile.conf $(obj)/policy/exception_policy.conf $(obj)/policy/domain_policy.conf $(obj)/policy/manager.conf $(obj)/policy/stat.conf
+       @echo Generating built-in policy for TOMOYO 2.4.x.
+       @echo "static char tomoyo_builtin_profile[] __initdata =" > $@.tmp
+       @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/profile.conf >> $@.tmp
+       @echo "\"\";" >> $@.tmp
+       @echo "static char tomoyo_builtin_exception_policy[] __initdata =" >> $@.tmp
+       @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/exception_policy.conf >> $@.tmp
+       @echo "\"\";" >> $@.tmp
+       @echo "static char tomoyo_builtin_domain_policy[] __initdata =" >> $@.tmp
+       @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/domain_policy.conf >> $@.tmp
+       @echo "\"\";" >> $@.tmp
+       @echo "static char tomoyo_builtin_manager[] __initdata =" >> $@.tmp
+       @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/manager.conf >> $@.tmp
+       @echo "\"\";" >> $@.tmp
+       @echo "static char tomoyo_builtin_stat[] __initdata =" >> $@.tmp
+       @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/stat.conf >> $@.tmp
+       @echo "\"\";" >> $@.tmp
+       @mv $@.tmp $@
+
+$(obj)/common.o: $(obj)/builtin-policy.h
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c
new file mode 100644 (file)
index 0000000..5dbb1f7
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * security/tomoyo/audit.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/slab.h>
+
+/**
+ * tomoyo_print_bprm - Print "struct linux_binprm" for auditing.
+ *
+ * @bprm: Pointer to "struct linux_binprm".
+ * @dump: Pointer to "struct tomoyo_page_dump".
+ *
+ * Returns the contents of @bprm on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+static char *tomoyo_print_bprm(struct linux_binprm *bprm,
+                              struct tomoyo_page_dump *dump)
+{
+       static const int tomoyo_buffer_len = 4096 * 2;
+       char *buffer = kzalloc(tomoyo_buffer_len, GFP_NOFS);
+       char *cp;
+       char *last_start;
+       int len;
+       unsigned long pos = bprm->p;
+       int offset = pos % PAGE_SIZE;
+       int argv_count = bprm->argc;
+       int envp_count = bprm->envc;
+       bool truncated = false;
+       if (!buffer)
+               return NULL;
+       len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ ");
+       cp = buffer + len;
+       if (!argv_count) {
+               memmove(cp, "} envp[]={ ", 11);
+               cp += 11;
+       }
+       last_start = cp;
+       while (argv_count || envp_count) {
+               if (!tomoyo_dump_page(bprm, pos, dump))
+                       goto out;
+               pos += PAGE_SIZE - offset;
+               /* Read. */
+               while (offset < PAGE_SIZE) {
+                       const char *kaddr = dump->data;
+                       const unsigned char c = kaddr[offset++];
+                       if (cp == last_start)
+                               *cp++ = '"';
+                       if (cp >= buffer + tomoyo_buffer_len - 32) {
+                               /* Reserve some room for "..." string. */
+                               truncated = true;
+                       } else if (c == '\\') {
+                               *cp++ = '\\';
+                               *cp++ = '\\';
+                       } else if (c > ' ' && c < 127) {
+                               *cp++ = c;
+                       } else if (!c) {
+                               *cp++ = '"';
+                               *cp++ = ' ';
+                               last_start = cp;
+                       } else {
+                               *cp++ = '\\';
+                               *cp++ = (c >> 6) + '0';
+                               *cp++ = ((c >> 3) & 7) + '0';
+                               *cp++ = (c & 7) + '0';
+                       }
+                       if (c)
+                               continue;
+                       if (argv_count) {
+                               if (--argv_count == 0) {
+                                       if (truncated) {
+                                               cp = last_start;
+                                               memmove(cp, "... ", 4);
+                                               cp += 4;
+                                       }
+                                       memmove(cp, "} envp[]={ ", 11);
+                                       cp += 11;
+                                       last_start = cp;
+                                       truncated = false;
+                               }
+                       } else if (envp_count) {
+                               if (--envp_count == 0) {
+                                       if (truncated) {
+                                               cp = last_start;
+                                               memmove(cp, "... ", 4);
+                                               cp += 4;
+                                       }
+                               }
+                       }
+                       if (!argv_count && !envp_count)
+                               break;
+               }
+               offset = 0;
+       }
+       *cp++ = '}';
+       *cp = '\0';
+       return buffer;
+out:
+       snprintf(buffer, tomoyo_buffer_len - 1,
+                "argv[]={ ... } envp[]= { ... }");
+       return buffer;
+}
+
+/**
+ * tomoyo_filetype - Get string representation of file type.
+ *
+ * @mode: Mode value for stat().
+ *
+ * Returns file type string.
+ */
+static inline const char *tomoyo_filetype(const mode_t mode)
+{
+       switch (mode & S_IFMT) {
+       case S_IFREG:
+       case 0:
+               return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FILE];
+       case S_IFDIR:
+               return tomoyo_condition_keyword[TOMOYO_TYPE_IS_DIRECTORY];
+       case S_IFLNK:
+               return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SYMLINK];
+       case S_IFIFO:
+               return tomoyo_condition_keyword[TOMOYO_TYPE_IS_FIFO];
+       case S_IFSOCK:
+               return tomoyo_condition_keyword[TOMOYO_TYPE_IS_SOCKET];
+       case S_IFBLK:
+               return tomoyo_condition_keyword[TOMOYO_TYPE_IS_BLOCK_DEV];
+       case S_IFCHR:
+               return tomoyo_condition_keyword[TOMOYO_TYPE_IS_CHAR_DEV];
+       }
+       return "unknown"; /* This should not happen. */
+}
+
+/**
+ * tomoyo_print_header - Get header line of audit log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns string representation.
+ *
+ * This function uses kmalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+static char *tomoyo_print_header(struct tomoyo_request_info *r)
+{
+       struct tomoyo_time stamp;
+       const pid_t gpid = task_pid_nr(current);
+       struct tomoyo_obj_info *obj = r->obj;
+       static const int tomoyo_buffer_len = 4096;
+       char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
+       int pos;
+       u8 i;
+       if (!buffer)
+               return NULL;
+       {
+               struct timeval tv;
+               do_gettimeofday(&tv);
+               tomoyo_convert_time(tv.tv_sec, &stamp);
+       }
+       pos = snprintf(buffer, tomoyo_buffer_len - 1,
+                      "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
+                      "granted=%s (global-pid=%u) task={ pid=%u ppid=%u "
+                      "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u "
+                      "fsuid=%u fsgid=%u }", stamp.year, stamp.month,
+                      stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile,
+                      tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid,
+                      tomoyo_sys_getpid(), tomoyo_sys_getppid(),
+                      current_uid(), current_gid(), current_euid(),
+                      current_egid(), current_suid(), current_sgid(),
+                      current_fsuid(), current_fsgid());
+       if (!obj)
+               goto no_obj_info;
+       if (!obj->validate_done) {
+               tomoyo_get_attributes(obj);
+               obj->validate_done = true;
+       }
+       for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
+               struct tomoyo_mini_stat *stat;
+               unsigned int dev;
+               mode_t mode;
+               if (!obj->stat_valid[i])
+                       continue;
+               stat = &obj->stat[i];
+               dev = stat->dev;
+               mode = stat->mode;
+               if (i & 1) {
+                       pos += snprintf(buffer + pos,
+                                       tomoyo_buffer_len - 1 - pos,
+                                       " path%u.parent={ uid=%u gid=%u "
+                                       "ino=%lu perm=0%o }", (i >> 1) + 1,
+                                       stat->uid, stat->gid, (unsigned long)
+                                       stat->ino, stat->mode & S_IALLUGO);
+                       continue;
+               }
+               pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
+                               " path%u={ uid=%u gid=%u ino=%lu major=%u"
+                               " minor=%u perm=0%o type=%s", (i >> 1) + 1,
+                               stat->uid, stat->gid, (unsigned long)
+                               stat->ino, MAJOR(dev), MINOR(dev),
+                               mode & S_IALLUGO, tomoyo_filetype(mode));
+               if (S_ISCHR(mode) || S_ISBLK(mode)) {
+                       dev = stat->rdev;
+                       pos += snprintf(buffer + pos,
+                                       tomoyo_buffer_len - 1 - pos,
+                                       " dev_major=%u dev_minor=%u",
+                                       MAJOR(dev), MINOR(dev));
+               }
+               pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
+                               " }");
+       }
+no_obj_info:
+       if (pos < tomoyo_buffer_len - 1)
+               return buffer;
+       kfree(buffer);
+       return NULL;
+}
+
+/**
+ * tomoyo_init_log - Allocate buffer for audit logs.
+ *
+ * @r:    Pointer to "struct tomoyo_request_info".
+ * @len:  Buffer size needed for @fmt and @args.
+ * @fmt:  The printf()'s format string.
+ * @args: va_list structure for @fmt.
+ *
+ * Returns pointer to allocated memory.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
+                     va_list args)
+{
+       char *buf = NULL;
+       char *bprm_info = NULL;
+       const char *header = NULL;
+       char *realpath = NULL;
+       const char *symlink = NULL;
+       int pos;
+       const char *domainname = r->domain->domainname->name;
+       header = tomoyo_print_header(r);
+       if (!header)
+               return NULL;
+       /* +10 is for '\n' etc. and '\0'. */
+       len += strlen(domainname) + strlen(header) + 10;
+       if (r->ee) {
+               struct file *file = r->ee->bprm->file;
+               realpath = tomoyo_realpath_from_path(&file->f_path);
+               bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump);
+               if (!realpath || !bprm_info)
+                       goto out;
+               /* +80 is for " exec={ realpath=\"%s\" argc=%d envc=%d %s }" */
+               len += strlen(realpath) + 80 + strlen(bprm_info);
+       } else if (r->obj && r->obj->symlink_target) {
+               symlink = r->obj->symlink_target->name;
+               /* +18 is for " symlink.target=\"%s\"" */
+               len += 18 + strlen(symlink);
+       }
+       len = tomoyo_round2(len);
+       buf = kzalloc(len, GFP_NOFS);
+       if (!buf)
+               goto out;
+       len--;
+       pos = snprintf(buf, len, "%s", header);
+       if (realpath) {
+               struct linux_binprm *bprm = r->ee->bprm;
+               pos += snprintf(buf + pos, len - pos,
+                               " exec={ realpath=\"%s\" argc=%d envc=%d %s }",
+                               realpath, bprm->argc, bprm->envc, bprm_info);
+       } else if (symlink)
+               pos += snprintf(buf + pos, len - pos, " symlink.target=\"%s\"",
+                               symlink);
+       pos += snprintf(buf + pos, len - pos, "\n%s\n", domainname);
+       vsnprintf(buf + pos, len - pos, fmt, args);
+out:
+       kfree(realpath);
+       kfree(bprm_info);
+       kfree(header);
+       return buf;
+}
+
+/* Wait queue for /sys/kernel/security/tomoyo/audit. */
+static DECLARE_WAIT_QUEUE_HEAD(tomoyo_log_wait);
+
+/* Structure for audit log. */
+struct tomoyo_log {
+       struct list_head list;
+       char *log;
+       int size;
+};
+
+/* The list for "struct tomoyo_log". */
+static LIST_HEAD(tomoyo_log);
+
+/* Lock for "struct list_head tomoyo_log". */
+static DEFINE_SPINLOCK(tomoyo_log_lock);
+
+/* Length of "stuct list_head tomoyo_log". */
+static unsigned int tomoyo_log_count;
+
+/**
+ * tomoyo_get_audit - Get audit mode.
+ *
+ * @ns:          Pointer to "struct tomoyo_policy_namespace".
+ * @profile:     Profile number.
+ * @index:       Index number of functionality.
+ * @is_granted:  True if granted log, false otherwise.
+ *
+ * Returns true if this request should be audited, false otherwise.
+ */
+static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
+                            const u8 profile, const u8 index,
+                            const bool is_granted)
+{
+       u8 mode;
+       const u8 category = tomoyo_index2category[index] +
+               TOMOYO_MAX_MAC_INDEX;
+       struct tomoyo_profile *p;
+       if (!tomoyo_policy_loaded)
+               return false;
+       p = tomoyo_profile(ns, profile);
+       if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
+               return false;
+       mode = p->config[index];
+       if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+               mode = p->config[category];
+       if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+               mode = p->default_config;
+       if (is_granted)
+               return mode & TOMOYO_CONFIG_WANT_GRANT_LOG;
+       return mode & TOMOYO_CONFIG_WANT_REJECT_LOG;
+}
+
+/**
+ * tomoyo_write_log2 - Write an audit log.
+ *
+ * @r:    Pointer to "struct tomoyo_request_info".
+ * @len:  Buffer size needed for @fmt and @args.
+ * @fmt:  The printf()'s format string.
+ * @args: va_list structure for @fmt.
+ *
+ * Returns nothing.
+ */
+void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
+                      va_list args)
+{
+       char *buf;
+       struct tomoyo_log *entry;
+       bool quota_exceeded = false;
+       if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted))
+               goto out;
+       buf = tomoyo_init_log(r, len, fmt, args);
+       if (!buf)
+               goto out;
+       entry = kzalloc(sizeof(*entry), GFP_NOFS);
+       if (!entry) {
+               kfree(buf);
+               goto out;
+       }
+       entry->log = buf;
+       len = tomoyo_round2(strlen(buf) + 1);
+       /*
+        * The entry->size is used for memory quota checks.
+        * Don't go beyond strlen(entry->log).
+        */
+       entry->size = len + tomoyo_round2(sizeof(*entry));
+       spin_lock(&tomoyo_log_lock);
+       if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] &&
+           tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >=
+           tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT]) {
+               quota_exceeded = true;
+       } else {
+               tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] += entry->size;
+               list_add_tail(&entry->list, &tomoyo_log);
+               tomoyo_log_count++;
+       }
+       spin_unlock(&tomoyo_log_lock);
+       if (quota_exceeded) {
+               kfree(buf);
+               kfree(entry);
+               goto out;
+       }
+       wake_up(&tomoyo_log_wait);
+out:
+       return;
+}
+
+/**
+ * tomoyo_write_log - Write an audit log.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @fmt: The printf()'s format string, followed by parameters.
+ *
+ * Returns nothing.
+ */
+void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
+{
+       va_list args;
+       int len;
+       va_start(args, fmt);
+       len = vsnprintf((char *) &len, 1, fmt, args) + 1;
+       va_end(args);
+       va_start(args, fmt);
+       tomoyo_write_log2(r, len, fmt, args);
+       va_end(args);
+}
+
+/**
+ * tomoyo_read_log - Read an audit log.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
+void tomoyo_read_log(struct tomoyo_io_buffer *head)
+{
+       struct tomoyo_log *ptr = NULL;
+       if (head->r.w_pos)
+               return;
+       kfree(head->read_buf);
+       head->read_buf = NULL;
+       spin_lock(&tomoyo_log_lock);
+       if (!list_empty(&tomoyo_log)) {
+               ptr = list_entry(tomoyo_log.next, typeof(*ptr), list);
+               list_del(&ptr->list);
+               tomoyo_log_count--;
+               tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] -= ptr->size;
+       }
+       spin_unlock(&tomoyo_log_lock);
+       if (ptr) {
+               head->read_buf = ptr->log;
+               head->r.w[head->r.w_pos++] = head->read_buf;
+               kfree(ptr);
+       }
+}
+
+/**
+ * tomoyo_poll_log - Wait for an audit log.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
+ *
+ * Returns POLLIN | POLLRDNORM when ready to read an audit log.
+ */
+int tomoyo_poll_log(struct file *file, poll_table *wait)
+{
+       if (tomoyo_log_count)
+               return POLLIN | POLLRDNORM;
+       poll_wait(file, &tomoyo_log_wait, wait);
+       if (tomoyo_log_count)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
index a0d09e56874b6a3b7bf23d48631cfede23a105c7..c8439cf2a448869820cc5dbf175c45956d9d7698 100644 (file)
@@ -1,9 +1,7 @@
 /*
  * security/tomoyo/common.c
  *
- * Common functions for TOMOYO.
- *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include <linux/uaccess.h>
 #include <linux/security.h>
 #include "common.h"
 
-static struct tomoyo_profile tomoyo_default_profile = {
-       .learning = &tomoyo_default_profile.preference,
-       .permissive = &tomoyo_default_profile.preference,
-       .enforcing = &tomoyo_default_profile.preference,
-       .preference.enforcing_verbose = true,
-       .preference.learning_max_entry = 2048,
-       .preference.learning_verbose = false,
-       .preference.permissive_verbose = true
+/* String table for operation mode. */
+const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = {
+       [TOMOYO_CONFIG_DISABLED]   = "disabled",
+       [TOMOYO_CONFIG_LEARNING]   = "learning",
+       [TOMOYO_CONFIG_PERMISSIVE] = "permissive",
+       [TOMOYO_CONFIG_ENFORCING]  = "enforcing"
 };
 
-/* Profile version. Currently only 20090903 is defined. */
-static unsigned int tomoyo_profile_version;
+/* String table for /sys/kernel/security/tomoyo/profile */
+const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+                                      + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
+       [TOMOYO_MAC_FILE_EXECUTE]    = "execute",
+       [TOMOYO_MAC_FILE_OPEN]       = "open",
+       [TOMOYO_MAC_FILE_CREATE]     = "create",
+       [TOMOYO_MAC_FILE_UNLINK]     = "unlink",
+       [TOMOYO_MAC_FILE_GETATTR]    = "getattr",
+       [TOMOYO_MAC_FILE_MKDIR]      = "mkdir",
+       [TOMOYO_MAC_FILE_RMDIR]      = "rmdir",
+       [TOMOYO_MAC_FILE_MKFIFO]     = "mkfifo",
+       [TOMOYO_MAC_FILE_MKSOCK]     = "mksock",
+       [TOMOYO_MAC_FILE_TRUNCATE]   = "truncate",
+       [TOMOYO_MAC_FILE_SYMLINK]    = "symlink",
+       [TOMOYO_MAC_FILE_MKBLOCK]    = "mkblock",
+       [TOMOYO_MAC_FILE_MKCHAR]     = "mkchar",
+       [TOMOYO_MAC_FILE_LINK]       = "link",
+       [TOMOYO_MAC_FILE_RENAME]     = "rename",
+       [TOMOYO_MAC_FILE_CHMOD]      = "chmod",
+       [TOMOYO_MAC_FILE_CHOWN]      = "chown",
+       [TOMOYO_MAC_FILE_CHGRP]      = "chgrp",
+       [TOMOYO_MAC_FILE_IOCTL]      = "ioctl",
+       [TOMOYO_MAC_FILE_CHROOT]     = "chroot",
+       [TOMOYO_MAC_FILE_MOUNT]      = "mount",
+       [TOMOYO_MAC_FILE_UMOUNT]     = "unmount",
+       [TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root",
+       [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
+};
 
-/* Profile table. Memory is allocated as needed. */
-static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
+/* String table for conditions. */
+const char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = {
+       [TOMOYO_TASK_UID]             = "task.uid",
+       [TOMOYO_TASK_EUID]            = "task.euid",
+       [TOMOYO_TASK_SUID]            = "task.suid",
+       [TOMOYO_TASK_FSUID]           = "task.fsuid",
+       [TOMOYO_TASK_GID]             = "task.gid",
+       [TOMOYO_TASK_EGID]            = "task.egid",
+       [TOMOYO_TASK_SGID]            = "task.sgid",
+       [TOMOYO_TASK_FSGID]           = "task.fsgid",
+       [TOMOYO_TASK_PID]             = "task.pid",
+       [TOMOYO_TASK_PPID]            = "task.ppid",
+       [TOMOYO_EXEC_ARGC]            = "exec.argc",
+       [TOMOYO_EXEC_ENVC]            = "exec.envc",
+       [TOMOYO_TYPE_IS_SOCKET]       = "socket",
+       [TOMOYO_TYPE_IS_SYMLINK]      = "symlink",
+       [TOMOYO_TYPE_IS_FILE]         = "file",
+       [TOMOYO_TYPE_IS_BLOCK_DEV]    = "block",
+       [TOMOYO_TYPE_IS_DIRECTORY]    = "directory",
+       [TOMOYO_TYPE_IS_CHAR_DEV]     = "char",
+       [TOMOYO_TYPE_IS_FIFO]         = "fifo",
+       [TOMOYO_MODE_SETUID]          = "setuid",
+       [TOMOYO_MODE_SETGID]          = "setgid",
+       [TOMOYO_MODE_STICKY]          = "sticky",
+       [TOMOYO_MODE_OWNER_READ]      = "owner_read",
+       [TOMOYO_MODE_OWNER_WRITE]     = "owner_write",
+       [TOMOYO_MODE_OWNER_EXECUTE]   = "owner_execute",
+       [TOMOYO_MODE_GROUP_READ]      = "group_read",
+       [TOMOYO_MODE_GROUP_WRITE]     = "group_write",
+       [TOMOYO_MODE_GROUP_EXECUTE]   = "group_execute",
+       [TOMOYO_MODE_OTHERS_READ]     = "others_read",
+       [TOMOYO_MODE_OTHERS_WRITE]    = "others_write",
+       [TOMOYO_MODE_OTHERS_EXECUTE]  = "others_execute",
+       [TOMOYO_EXEC_REALPATH]        = "exec.realpath",
+       [TOMOYO_SYMLINK_TARGET]       = "symlink.target",
+       [TOMOYO_PATH1_UID]            = "path1.uid",
+       [TOMOYO_PATH1_GID]            = "path1.gid",
+       [TOMOYO_PATH1_INO]            = "path1.ino",
+       [TOMOYO_PATH1_MAJOR]          = "path1.major",
+       [TOMOYO_PATH1_MINOR]          = "path1.minor",
+       [TOMOYO_PATH1_PERM]           = "path1.perm",
+       [TOMOYO_PATH1_TYPE]           = "path1.type",
+       [TOMOYO_PATH1_DEV_MAJOR]      = "path1.dev_major",
+       [TOMOYO_PATH1_DEV_MINOR]      = "path1.dev_minor",
+       [TOMOYO_PATH2_UID]            = "path2.uid",
+       [TOMOYO_PATH2_GID]            = "path2.gid",
+       [TOMOYO_PATH2_INO]            = "path2.ino",
+       [TOMOYO_PATH2_MAJOR]          = "path2.major",
+       [TOMOYO_PATH2_MINOR]          = "path2.minor",
+       [TOMOYO_PATH2_PERM]           = "path2.perm",
+       [TOMOYO_PATH2_TYPE]           = "path2.type",
+       [TOMOYO_PATH2_DEV_MAJOR]      = "path2.dev_major",
+       [TOMOYO_PATH2_DEV_MINOR]      = "path2.dev_minor",
+       [TOMOYO_PATH1_PARENT_UID]     = "path1.parent.uid",
+       [TOMOYO_PATH1_PARENT_GID]     = "path1.parent.gid",
+       [TOMOYO_PATH1_PARENT_INO]     = "path1.parent.ino",
+       [TOMOYO_PATH1_PARENT_PERM]    = "path1.parent.perm",
+       [TOMOYO_PATH2_PARENT_UID]     = "path2.parent.uid",
+       [TOMOYO_PATH2_PARENT_GID]     = "path2.parent.gid",
+       [TOMOYO_PATH2_PARENT_INO]     = "path2.parent.ino",
+       [TOMOYO_PATH2_PARENT_PERM]    = "path2.parent.perm",
+};
 
-/* String table for functionality that takes 4 modes. */
-static const char *tomoyo_mode[4] = {
-       "disabled", "learning", "permissive", "enforcing"
+/* String table for PREFERENCE keyword. */
+static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = {
+       [TOMOYO_PREF_MAX_AUDIT_LOG]      = "max_audit_log",
+       [TOMOYO_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
 };
 
-/* String table for /sys/kernel/security/tomoyo/profile */
-static const char *tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
-                                      + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
-       [TOMOYO_MAC_FILE_EXECUTE]    = "file::execute",
-       [TOMOYO_MAC_FILE_OPEN]       = "file::open",
-       [TOMOYO_MAC_FILE_CREATE]     = "file::create",
-       [TOMOYO_MAC_FILE_UNLINK]     = "file::unlink",
-       [TOMOYO_MAC_FILE_MKDIR]      = "file::mkdir",
-       [TOMOYO_MAC_FILE_RMDIR]      = "file::rmdir",
-       [TOMOYO_MAC_FILE_MKFIFO]     = "file::mkfifo",
-       [TOMOYO_MAC_FILE_MKSOCK]     = "file::mksock",
-       [TOMOYO_MAC_FILE_TRUNCATE]   = "file::truncate",
-       [TOMOYO_MAC_FILE_SYMLINK]    = "file::symlink",
-       [TOMOYO_MAC_FILE_REWRITE]    = "file::rewrite",
-       [TOMOYO_MAC_FILE_MKBLOCK]    = "file::mkblock",
-       [TOMOYO_MAC_FILE_MKCHAR]     = "file::mkchar",
-       [TOMOYO_MAC_FILE_LINK]       = "file::link",
-       [TOMOYO_MAC_FILE_RENAME]     = "file::rename",
-       [TOMOYO_MAC_FILE_CHMOD]      = "file::chmod",
-       [TOMOYO_MAC_FILE_CHOWN]      = "file::chown",
-       [TOMOYO_MAC_FILE_CHGRP]      = "file::chgrp",
-       [TOMOYO_MAC_FILE_IOCTL]      = "file::ioctl",
-       [TOMOYO_MAC_FILE_CHROOT]     = "file::chroot",
-       [TOMOYO_MAC_FILE_MOUNT]      = "file::mount",
-       [TOMOYO_MAC_FILE_UMOUNT]     = "file::umount",
-       [TOMOYO_MAC_FILE_PIVOT_ROOT] = "file::pivot_root",
-       [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
+/* String table for path operation. */
+const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
+       [TOMOYO_TYPE_EXECUTE]    = "execute",
+       [TOMOYO_TYPE_READ]       = "read",
+       [TOMOYO_TYPE_WRITE]      = "write",
+       [TOMOYO_TYPE_APPEND]     = "append",
+       [TOMOYO_TYPE_UNLINK]     = "unlink",
+       [TOMOYO_TYPE_GETATTR]    = "getattr",
+       [TOMOYO_TYPE_RMDIR]      = "rmdir",
+       [TOMOYO_TYPE_TRUNCATE]   = "truncate",
+       [TOMOYO_TYPE_SYMLINK]    = "symlink",
+       [TOMOYO_TYPE_CHROOT]     = "chroot",
+       [TOMOYO_TYPE_UMOUNT]     = "unmount",
+};
+
+/* String table for categories. */
+static const char * const tomoyo_category_keywords
+[TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
+       [TOMOYO_MAC_CATEGORY_FILE]       = "file",
 };
 
 /* Permit policy management by non-root user? */
@@ -71,11 +146,20 @@ static bool tomoyo_manage_by_non_root;
  *
  * @value: Bool value.
  */
-static const char *tomoyo_yesno(const unsigned int value)
+const char *tomoyo_yesno(const unsigned int value)
 {
        return value ? "yes" : "no";
 }
 
+/**
+ * tomoyo_addprintf - strncat()-like-snprintf().
+ *
+ * @buffer: Buffer to write to. Must be '\0'-terminated.
+ * @len:    Size of @buffer.
+ * @fmt:    The printf()'s format string, followed by parameters.
+ *
+ * Returns nothing.
+ */
 static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...)
 {
        va_list args;
@@ -96,7 +180,7 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head)
 {
        while (head->r.w_pos) {
                const char *w = head->r.w[0];
-               int len = strlen(w);
+               size_t len = strlen(w);
                if (len) {
                        if (len > head->read_user_buf_avail)
                                len = head->read_user_buf_avail;
@@ -111,7 +195,7 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head)
                head->r.w[0] = w;
                if (*w)
                        return false;
-               /* Add '\0' for query. */
+               /* Add '\0' for audit logs and query. */
                if (head->poll) {
                        if (!head->read_user_buf_avail ||
                            copy_to_user(head->read_user_buf, "", 1))
@@ -155,8 +239,8 @@ static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
 void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
 {
        va_list args;
-       int len;
-       int pos = head->r.avail;
+       size_t len;
+       size_t pos = head->r.avail;
        int size = head->readbuf_size - pos;
        if (size <= 0)
                return;
@@ -171,17 +255,87 @@ void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
        tomoyo_set_string(head, head->read_buf + pos);
 }
 
+/**
+ * tomoyo_set_space - Put a space to "struct tomoyo_io_buffer" structure.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
 static void tomoyo_set_space(struct tomoyo_io_buffer *head)
 {
        tomoyo_set_string(head, " ");
 }
 
+/**
+ * tomoyo_set_lf - Put a line feed to "struct tomoyo_io_buffer" structure.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
 static bool tomoyo_set_lf(struct tomoyo_io_buffer *head)
 {
        tomoyo_set_string(head, "\n");
        return !head->r.w_pos;
 }
 
+/**
+ * tomoyo_set_slash - Put a shash to "struct tomoyo_io_buffer" structure.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_set_slash(struct tomoyo_io_buffer *head)
+{
+       tomoyo_set_string(head, "/");
+}
+
+/* List of namespaces. */
+LIST_HEAD(tomoyo_namespace_list);
+/* True if namespace other than tomoyo_kernel_namespace is defined. */
+static bool tomoyo_namespace_enabled;
+
+/**
+ * tomoyo_init_policy_namespace - Initialize namespace.
+ *
+ * @ns: Pointer to "struct tomoyo_policy_namespace".
+ *
+ * Returns nothing.
+ */
+void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns)
+{
+       unsigned int idx;
+       for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++)
+               INIT_LIST_HEAD(&ns->acl_group[idx]);
+       for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
+               INIT_LIST_HEAD(&ns->group_list[idx]);
+       for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
+               INIT_LIST_HEAD(&ns->policy_list[idx]);
+       ns->profile_version = 20100903;
+       tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
+       list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
+}
+
+/**
+ * tomoyo_print_namespace - Print namespace header.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_namespace(struct tomoyo_io_buffer *head)
+{
+       if (!tomoyo_namespace_enabled)
+               return;
+       tomoyo_set_string(head,
+                         container_of(head->r.ns,
+                                      struct tomoyo_policy_namespace,
+                                      namespace_list)->name);
+       tomoyo_set_space(head);
+}
+
 /**
  * tomoyo_print_name_union - Print a tomoyo_name_union.
  *
@@ -192,7 +346,7 @@ static void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
                                    const struct tomoyo_name_union *ptr)
 {
        tomoyo_set_space(head);
-       if (ptr->is_group) {
+       if (ptr->group) {
                tomoyo_set_string(head, "@");
                tomoyo_set_string(head, ptr->group->group_name->name);
        } else {
@@ -201,24 +355,46 @@ static void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
 }
 
 /**
- * tomoyo_print_number_union - Print a tomoyo_number_union.
+ * tomoyo_print_name_union_quoted - Print a tomoyo_name_union with a quote.
  *
- * @head:       Pointer to "struct tomoyo_io_buffer".
- * @ptr:        Pointer to "struct tomoyo_number_union".
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr:  Pointer to "struct tomoyo_name_union".
+ *
+ * Returns nothing.
  */
-static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
-                                     const struct tomoyo_number_union *ptr)
+static void tomoyo_print_name_union_quoted(struct tomoyo_io_buffer *head,
+                                          const struct tomoyo_name_union *ptr)
 {
-       tomoyo_set_space(head);
-       if (ptr->is_group) {
+       if (ptr->group) {
+               tomoyo_set_string(head, "@");
+               tomoyo_set_string(head, ptr->group->group_name->name);
+       } else {
+               tomoyo_set_string(head, "\"");
+               tomoyo_set_string(head, ptr->filename->name);
+               tomoyo_set_string(head, "\"");
+       }
+}
+
+/**
+ * tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr:  Pointer to "struct tomoyo_number_union".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_number_union_nospace
+(struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr)
+{
+       if (ptr->group) {
                tomoyo_set_string(head, "@");
                tomoyo_set_string(head, ptr->group->group_name->name);
        } else {
                int i;
                unsigned long min = ptr->values[0];
                const unsigned long max = ptr->values[1];
-               u8 min_type = ptr->min_type;
-               const u8 max_type = ptr->max_type;
+               u8 min_type = ptr->value_type[0];
+               const u8 max_type = ptr->value_type[1];
                char buffer[128];
                buffer[0] = '\0';
                for (i = 0; i < 2; i++) {
@@ -232,8 +408,8 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
                                                 "0%lo", min);
                                break;
                        default:
-                               tomoyo_addprintf(buffer, sizeof(buffer),
-                                                "%lu", min);
+                               tomoyo_addprintf(buffer, sizeof(buffer), "%lu",
+                                                min);
                                break;
                        }
                        if (min == max && min_type == max_type)
@@ -246,36 +422,54 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
        }
 }
 
+/**
+ * tomoyo_print_number_union - Print a tomoyo_number_union.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr:  Pointer to "struct tomoyo_number_union".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
+                                     const struct tomoyo_number_union *ptr)
+{
+       tomoyo_set_space(head);
+       tomoyo_print_number_union_nospace(head, ptr);
+}
+
 /**
  * tomoyo_assign_profile - Create a new profile.
  *
+ * @ns:      Pointer to "struct tomoyo_policy_namespace".
  * @profile: Profile number to create.
  *
  * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
  */
-static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile)
+static struct tomoyo_profile *tomoyo_assign_profile
+(struct tomoyo_policy_namespace *ns, const unsigned int profile)
 {
        struct tomoyo_profile *ptr;
        struct tomoyo_profile *entry;
        if (profile >= TOMOYO_MAX_PROFILES)
                return NULL;
-       ptr = tomoyo_profile_ptr[profile];
+       ptr = ns->profile_ptr[profile];
        if (ptr)
                return ptr;
        entry = kzalloc(sizeof(*entry), GFP_NOFS);
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                goto out;
-       ptr = tomoyo_profile_ptr[profile];
+       ptr = ns->profile_ptr[profile];
        if (!ptr && tomoyo_memory_ok(entry)) {
                ptr = entry;
-               ptr->learning = &tomoyo_default_profile.preference;
-               ptr->permissive = &tomoyo_default_profile.preference;
-               ptr->enforcing = &tomoyo_default_profile.preference;
-               ptr->default_config = TOMOYO_CONFIG_DISABLED;
+               ptr->default_config = TOMOYO_CONFIG_DISABLED |
+                       TOMOYO_CONFIG_WANT_GRANT_LOG |
+                       TOMOYO_CONFIG_WANT_REJECT_LOG;
                memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
                       sizeof(ptr->config));
+               ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024;
+               ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048;
                mb(); /* Avoid out-of-order execution. */
-               tomoyo_profile_ptr[profile] = ptr;
+               ns->profile_ptr[profile] = ptr;
                entry = NULL;
        }
        mutex_unlock(&tomoyo_policy_lock);
@@ -287,19 +481,29 @@ static struct tomoyo_profile *tomoyo_assign_profile(const unsigned int profile)
 /**
  * tomoyo_profile - Find a profile.
  *
+ * @ns:      Pointer to "struct tomoyo_policy_namespace".
  * @profile: Profile number to find.
  *
  * Returns pointer to "struct tomoyo_profile".
  */
-struct tomoyo_profile *tomoyo_profile(const u8 profile)
+struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
+                                     const u8 profile)
 {
-       struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile];
-       if (!tomoyo_policy_loaded)
-               return &tomoyo_default_profile;
-       BUG_ON(!ptr);
+       static struct tomoyo_profile tomoyo_null_profile;
+       struct tomoyo_profile *ptr = ns->profile_ptr[profile];
+       if (!ptr)
+               ptr = &tomoyo_null_profile;
        return ptr;
 }
 
+/**
+ * tomoyo_find_yesno - Find values for specified keyword.
+ *
+ * @string: String to check.
+ * @find:   Name of keyword.
+ *
+ * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
+ */
 static s8 tomoyo_find_yesno(const char *string, const char *find)
 {
        const char *cp = strstr(string, find);
@@ -313,18 +517,15 @@ static s8 tomoyo_find_yesno(const char *string, const char *find)
        return -1;
 }
 
-static void tomoyo_set_bool(bool *b, const char *string, const char *find)
-{
-       switch (tomoyo_find_yesno(string, find)) {
-       case 1:
-               *b = true;
-               break;
-       case 0:
-               *b = false;
-               break;
-       }
-}
-
+/**
+ * tomoyo_set_uint - Set value for specified preference.
+ *
+ * @i:      Pointer to "unsigned int".
+ * @string: String to check.
+ * @find:   Name of keyword.
+ *
+ * Returns nothing.
+ */
 static void tomoyo_set_uint(unsigned int *i, const char *string,
                            const char *find)
 {
@@ -333,51 +534,16 @@ static void tomoyo_set_uint(unsigned int *i, const char *string,
                sscanf(cp + strlen(find), "=%u", i);
 }
 
-static void tomoyo_set_pref(const char *name, const char *value,
-                           const bool use_default,
-                           struct tomoyo_profile *profile)
-{
-       struct tomoyo_preference **pref;
-       bool *verbose;
-       if (!strcmp(name, "enforcing")) {
-               if (use_default) {
-                       pref = &profile->enforcing;
-                       goto set_default;
-               }
-               profile->enforcing = &profile->preference;
-               verbose = &profile->preference.enforcing_verbose;
-               goto set_verbose;
-       }
-       if (!strcmp(name, "permissive")) {
-               if (use_default) {
-                       pref = &profile->permissive;
-                       goto set_default;
-               }
-               profile->permissive = &profile->preference;
-               verbose = &profile->preference.permissive_verbose;
-               goto set_verbose;
-       }
-       if (!strcmp(name, "learning")) {
-               if (use_default) {
-                       pref = &profile->learning;
-                       goto set_default;
-               }
-               profile->learning = &profile->preference;
-               tomoyo_set_uint(&profile->preference.learning_max_entry, value,
-                            "max_entry");
-               verbose = &profile->preference.learning_verbose;
-               goto set_verbose;
-       }
-       return;
- set_default:
-       *pref = &tomoyo_default_profile.preference;
-       return;
- set_verbose:
-       tomoyo_set_bool(verbose, value, "verbose");
-}
-
+/**
+ * tomoyo_set_mode - Set mode for specified profile.
+ *
+ * @name:    Name of functionality.
+ * @value:   Mode for @name.
+ * @profile: Pointer to "struct tomoyo_profile".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_set_mode(char *name, const char *value,
-                          const bool use_default,
                           struct tomoyo_profile *profile)
 {
        u8 i;
@@ -389,7 +555,17 @@ static int tomoyo_set_mode(char *name, const char *value,
                config = 0;
                for (i = 0; i < TOMOYO_MAX_MAC_INDEX
                             + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
-                       if (strcmp(name, tomoyo_mac_keywords[i]))
+                       int len = 0;
+                       if (i < TOMOYO_MAX_MAC_INDEX) {
+                               const u8 c = tomoyo_index2category[i];
+                               const char *category =
+                                       tomoyo_category_keywords[c];
+                               len = strlen(category);
+                               if (strncmp(name, category, len) ||
+                                   name[len++] != ':' || name[len++] != ':')
+                                       continue;
+                       }
+                       if (strcmp(name + len, tomoyo_mac_keywords[i]))
                                continue;
                        config = profile->config[i];
                        break;
@@ -399,7 +575,7 @@ static int tomoyo_set_mode(char *name, const char *value,
        } else {
                return -EINVAL;
        }
-       if (use_default) {
+       if (strstr(value, "use_default")) {
                config = TOMOYO_CONFIG_USE_DEFAULT;
        } else {
                u8 mode;
@@ -410,6 +586,24 @@ static int tomoyo_set_mode(char *name, const char *value,
                                 * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'.
                                 */
                                config = (config & ~7) | mode;
+               if (config != TOMOYO_CONFIG_USE_DEFAULT) {
+                       switch (tomoyo_find_yesno(value, "grant_log")) {
+                       case 1:
+                               config |= TOMOYO_CONFIG_WANT_GRANT_LOG;
+                               break;
+                       case 0:
+                               config &= ~TOMOYO_CONFIG_WANT_GRANT_LOG;
+                               break;
+                       }
+                       switch (tomoyo_find_yesno(value, "reject_log")) {
+                       case 1:
+                               config |= TOMOYO_CONFIG_WANT_REJECT_LOG;
+                               break;
+                       case 0:
+                               config &= ~TOMOYO_CONFIG_WANT_REJECT_LOG;
+                               break;
+                       }
+               }
        }
        if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
                profile->config[i] = config;
@@ -429,34 +623,22 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
 {
        char *data = head->write_buf;
        unsigned int i;
-       bool use_default = false;
        char *cp;
        struct tomoyo_profile *profile;
-       if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1)
+       if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
+           == 1)
                return 0;
        i = simple_strtoul(data, &cp, 10);
-       if (data == cp) {
-               profile = &tomoyo_default_profile;
-       } else {
-               if (*cp != '-')
-                       return -EINVAL;
-               data = cp + 1;
-               profile = tomoyo_assign_profile(i);
-               if (!profile)
-                       return -EINVAL;
-       }
+       if (*cp != '-')
+               return -EINVAL;
+       data = cp + 1;
+       profile = tomoyo_assign_profile(head->w.ns, i);
+       if (!profile)
+               return -EINVAL;
        cp = strchr(data, '=');
        if (!cp)
                return -EINVAL;
        *cp++ = '\0';
-       if (profile != &tomoyo_default_profile)
-               use_default = strstr(cp, "use_default") != NULL;
-       if (tomoyo_str_starts(&data, "PREFERENCE::")) {
-               tomoyo_set_pref(data, cp, use_default, profile);
-               return 0;
-       }
-       if (profile == &tomoyo_default_profile)
-               return -EINVAL;
        if (!strcmp(data, "COMMENT")) {
                static DEFINE_SPINLOCK(lock);
                const struct tomoyo_path_info *new_comment
@@ -471,77 +653,62 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
                tomoyo_put_name(old_comment);
                return 0;
        }
-       return tomoyo_set_mode(data, cp, use_default, profile);
-}
-
-static void tomoyo_print_preference(struct tomoyo_io_buffer *head,
-                                   const int idx)
-{
-       struct tomoyo_preference *pref = &tomoyo_default_profile.preference;
-       const struct tomoyo_profile *profile = idx >= 0 ?
-               tomoyo_profile_ptr[idx] : NULL;
-       char buffer[16] = "";
-       if (profile) {
-               buffer[sizeof(buffer) - 1] = '\0';
-               snprintf(buffer, sizeof(buffer) - 1, "%u-", idx);
-       }
-       if (profile) {
-               pref = profile->learning;
-               if (pref == &tomoyo_default_profile.preference)
-                       goto skip1;
-       }
-       tomoyo_io_printf(head, "%sPREFERENCE::%s={ "
-                        "verbose=%s max_entry=%u }\n",
-                        buffer, "learning",
-                        tomoyo_yesno(pref->learning_verbose),
-                        pref->learning_max_entry);
- skip1:
-       if (profile) {
-               pref = profile->permissive;
-               if (pref == &tomoyo_default_profile.preference)
-                       goto skip2;
-       }
-       tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n",
-                        buffer, "permissive",
-                        tomoyo_yesno(pref->permissive_verbose));
- skip2:
-       if (profile) {
-               pref = profile->enforcing;
-               if (pref == &tomoyo_default_profile.preference)
-                       return;
+       if (!strcmp(data, "PREFERENCE")) {
+               for (i = 0; i < TOMOYO_MAX_PREF; i++)
+                       tomoyo_set_uint(&profile->pref[i], cp,
+                                       tomoyo_pref_keywords[i]);
+               return 0;
        }
-       tomoyo_io_printf(head, "%sPREFERENCE::%s={ verbose=%s }\n",
-                        buffer, "enforcing",
-                        tomoyo_yesno(pref->enforcing_verbose));
+       return tomoyo_set_mode(data, cp, profile);
 }
 
+/**
+ * tomoyo_print_config - Print mode for specified functionality.
+ *
+ * @head:   Pointer to "struct tomoyo_io_buffer".
+ * @config: Mode for that functionality.
+ *
+ * Returns nothing.
+ *
+ * Caller prints functionality's name.
+ */
 static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 config)
 {
-       tomoyo_io_printf(head, "={ mode=%s }\n", tomoyo_mode[config & 3]);
+       tomoyo_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
+                        tomoyo_mode[config & 3],
+                        tomoyo_yesno(config & TOMOYO_CONFIG_WANT_GRANT_LOG),
+                        tomoyo_yesno(config & TOMOYO_CONFIG_WANT_REJECT_LOG));
 }
 
 /**
  * tomoyo_read_profile - Read profile table.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
  */
 static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
 {
        u8 index;
+       struct tomoyo_policy_namespace *ns =
+               container_of(head->r.ns, typeof(*ns), namespace_list);
        const struct tomoyo_profile *profile;
+       if (head->r.eof)
+               return;
  next:
        index = head->r.index;
-       profile = tomoyo_profile_ptr[index];
+       profile = ns->profile_ptr[index];
        switch (head->r.step) {
        case 0:
-               tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903");
-               tomoyo_print_preference(head, -1);
+               tomoyo_print_namespace(head);
+               tomoyo_io_printf(head, "PROFILE_VERSION=%u\n",
+                                ns->profile_version);
                head->r.step++;
                break;
        case 1:
                for ( ; head->r.index < TOMOYO_MAX_PROFILES;
                      head->r.index++)
-                       if (tomoyo_profile_ptr[head->r.index])
+                       if (ns->profile_ptr[head->r.index])
                                break;
                if (head->r.index == TOMOYO_MAX_PROFILES)
                        return;
@@ -549,16 +716,25 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
                break;
        case 2:
                {
+                       u8 i;
                        const struct tomoyo_path_info *comment =
                                profile->comment;
+                       tomoyo_print_namespace(head);
                        tomoyo_io_printf(head, "%u-COMMENT=", index);
                        tomoyo_set_string(head, comment ? comment->name : "");
                        tomoyo_set_lf(head);
+                       tomoyo_io_printf(head, "%u-PREFERENCE={ ", index);
+                       for (i = 0; i < TOMOYO_MAX_PREF; i++)
+                               tomoyo_io_printf(head, "%s=%u ",
+                                                tomoyo_pref_keywords[i],
+                                                profile->pref[i]);
+                       tomoyo_set_string(head, "}\n");
                        head->r.step++;
                }
                break;
        case 3:
                {
+                       tomoyo_print_namespace(head);
                        tomoyo_io_printf(head, "%u-%s", index, "CONFIG");
                        tomoyo_print_config(head, profile->default_config);
                        head->r.bit = 0;
@@ -572,15 +748,22 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
                        const u8 config = profile->config[i];
                        if (config == TOMOYO_CONFIG_USE_DEFAULT)
                                continue;
-                       tomoyo_io_printf(head, "%u-%s%s", index, "CONFIG::",
-                                        tomoyo_mac_keywords[i]);
+                       tomoyo_print_namespace(head);
+                       if (i < TOMOYO_MAX_MAC_INDEX)
+                               tomoyo_io_printf(head, "%u-CONFIG::%s::%s",
+                                                index,
+                                                tomoyo_category_keywords
+                                                [tomoyo_index2category[i]],
+                                                tomoyo_mac_keywords[i]);
+                       else
+                               tomoyo_io_printf(head, "%u-CONFIG::%s", index,
+                                                tomoyo_mac_keywords[i]);
                        tomoyo_print_config(head, config);
                        head->r.bit++;
                        break;
                }
                if (head->r.bit == TOMOYO_MAX_MAC_INDEX
                    + TOMOYO_MAX_MAC_CATEGORY_INDEX) {
-                       tomoyo_print_preference(head, index);
                        head->r.index++;
                        head->r.step = 1;
                }
@@ -590,6 +773,14 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
                goto next;
 }
 
+/**
+ * tomoyo_same_manager - Check for duplicated "struct tomoyo_manager" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
 static bool tomoyo_same_manager(const struct tomoyo_acl_head *a,
                                const struct tomoyo_acl_head *b)
 {
@@ -611,8 +802,13 @@ static int tomoyo_update_manager_entry(const char *manager,
                                       const bool is_delete)
 {
        struct tomoyo_manager e = { };
-       int error;
-
+       struct tomoyo_acl_param param = {
+               /* .ns = &tomoyo_kernel_namespace, */
+               .is_delete = is_delete,
+               .list = &tomoyo_kernel_namespace.
+               policy_list[TOMOYO_ID_MANAGER],
+       };
+       int error = is_delete ? -ENOENT : -ENOMEM;
        if (tomoyo_domain_def(manager)) {
                if (!tomoyo_correct_domain(manager))
                        return -EINVAL;
@@ -622,12 +818,11 @@ static int tomoyo_update_manager_entry(const char *manager,
                        return -EINVAL;
        }
        e.manager = tomoyo_get_name(manager);
-       if (!e.manager)
-               return -ENOMEM;
-       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
-                                    &tomoyo_policy_list[TOMOYO_ID_MANAGER],
-                                    tomoyo_same_manager);
-       tomoyo_put_name(e.manager);
+       if (e.manager) {
+               error = tomoyo_update_policy(&e.head, sizeof(e), &param,
+                                            tomoyo_same_manager);
+               tomoyo_put_name(e.manager);
+       }
        return error;
 }
 
@@ -643,13 +838,12 @@ static int tomoyo_update_manager_entry(const char *manager,
 static int tomoyo_write_manager(struct tomoyo_io_buffer *head)
 {
        char *data = head->write_buf;
-       bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
 
        if (!strcmp(data, "manage_by_non_root")) {
-               tomoyo_manage_by_non_root = !is_delete;
+               tomoyo_manage_by_non_root = !head->w.is_delete;
                return 0;
        }
-       return tomoyo_update_manager_entry(data, is_delete);
+       return tomoyo_update_manager_entry(data, head->w.is_delete);
 }
 
 /**
@@ -663,8 +857,8 @@ static void tomoyo_read_manager(struct tomoyo_io_buffer *head)
 {
        if (head->r.eof)
                return;
-       list_for_each_cookie(head->r.acl,
-                            &tomoyo_policy_list[TOMOYO_ID_MANAGER]) {
+       list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.
+                            policy_list[TOMOYO_ID_MANAGER]) {
                struct tomoyo_manager *ptr =
                        list_entry(head->r.acl, typeof(*ptr), head.list);
                if (ptr->head.is_deleted)
@@ -697,8 +891,8 @@ static bool tomoyo_manager(void)
                return true;
        if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
                return false;
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
-                               head.list) {
+       list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.
+                               policy_list[TOMOYO_ID_MANAGER], head.list) {
                if (!ptr->head.is_deleted && ptr->is_domain
                    && !tomoyo_pathcmp(domainname, ptr->manager)) {
                        found = true;
@@ -710,8 +904,8 @@ static bool tomoyo_manager(void)
        exe = tomoyo_get_exe();
        if (!exe)
                return false;
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
-                               head.list) {
+       list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.
+                               policy_list[TOMOYO_ID_MANAGER], head.list) {
                if (!ptr->head.is_deleted && !ptr->is_domain
                    && !strcmp(exe, ptr->manager->name)) {
                        found = true;
@@ -732,7 +926,7 @@ static bool tomoyo_manager(void)
 }
 
 /**
- * tomoyo_select_one - Parse select command.
+ * tomoyo_select_domain - Parse select command.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  * @data: String to parse.
@@ -741,16 +935,15 @@ static bool tomoyo_manager(void)
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data)
+static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
+                                const char *data)
 {
        unsigned int pid;
        struct tomoyo_domain_info *domain = NULL;
        bool global_pid = false;
-
-       if (!strcmp(data, "allow_execute")) {
-               head->r.print_execute_only = true;
-               return true;
-       }
+       if (strncmp(data, "select ", 7))
+               return false;
+       data += 7;
        if (sscanf(data, "pid=%u", &pid) == 1 ||
            (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
                struct task_struct *p;
@@ -769,7 +962,7 @@ static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data)
                        domain = tomoyo_find_domain(data + 7);
        } else
                return false;
-       head->write_var1 = domain;
+       head->w.domain = domain;
        /* Accessing read_buf is safe because head->io_sem is held. */
        if (!head->read_buf)
                return true; /* Do nothing if open(O_WRONLY). */
@@ -821,20 +1014,47 @@ static int tomoyo_delete_domain(char *domainname)
 /**
  * tomoyo_write_domain2 - Write domain policy.
  *
- * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ns:        Pointer to "struct tomoyo_policy_namespace".
+ * @list:      Pointer to "struct list_head".
+ * @data:      Policy to be interpreted.
+ * @is_delete: True if it is a delete request.
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain,
+static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
+                               struct list_head *list, char *data,
                                const bool is_delete)
 {
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT))
-               return tomoyo_write_mount(data, domain, is_delete);
-       return tomoyo_write_file(data, domain, is_delete);
+       struct tomoyo_acl_param param = {
+               .ns = ns,
+               .list = list,
+               .data = data,
+               .is_delete = is_delete,
+       };
+       static const struct {
+               const char *keyword;
+               int (*write) (struct tomoyo_acl_param *);
+       } tomoyo_callback[1] = {
+               { "file ", tomoyo_write_file },
+       };
+       u8 i;
+       for (i = 0; i < 1; i++) {
+               if (!tomoyo_str_starts(&param.data,
+                                      tomoyo_callback[i].keyword))
+                       continue;
+               return tomoyo_callback[i].write(&param);
+       }
+       return -EINVAL;
 }
 
+/* String table for domain flags. */
+const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS] = {
+       [TOMOYO_DIF_QUOTA_WARNED]      = "quota_exceeded\n",
+       [TOMOYO_DIF_TRANSITION_FAILED] = "transition_failed\n",
+};
+
 /**
  * tomoyo_write_domain - Write domain policy.
  *
@@ -847,69 +1067,198 @@ static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain,
 static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
 {
        char *data = head->write_buf;
-       struct tomoyo_domain_info *domain = head->write_var1;
-       bool is_delete = false;
-       bool is_select = false;
+       struct tomoyo_policy_namespace *ns;
+       struct tomoyo_domain_info *domain = head->w.domain;
+       const bool is_delete = head->w.is_delete;
+       bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
        unsigned int profile;
-
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE))
-               is_delete = true;
-       else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT))
-               is_select = true;
-       if (is_select && tomoyo_select_one(head, data))
-               return 0;
-       /* Don't allow updating policies by non manager programs. */
-       if (!tomoyo_manager())
-               return -EPERM;
-       if (tomoyo_domain_def(data)) {
+       if (*data == '<') {
                domain = NULL;
                if (is_delete)
                        tomoyo_delete_domain(data);
                else if (is_select)
                        domain = tomoyo_find_domain(data);
                else
-                       domain = tomoyo_assign_domain(data, 0);
-               head->write_var1 = domain;
+                       domain = tomoyo_assign_domain(data, false);
+               head->w.domain = domain;
                return 0;
        }
        if (!domain)
                return -EINVAL;
-
-       if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1
+       ns = domain->ns;
+       if (sscanf(data, "use_profile %u", &profile) == 1
            && profile < TOMOYO_MAX_PROFILES) {
-               if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)
+               if (!tomoyo_policy_loaded || ns->profile_ptr[profile])
                        domain->profile = (u8) profile;
                return 0;
        }
-       if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
-               domain->ignore_global_allow_read = !is_delete;
-               return 0;
-       }
-       if (!strcmp(data, TOMOYO_KEYWORD_QUOTA_EXCEEDED)) {
-               domain->quota_warned = !is_delete;
+       if (sscanf(data, "use_group %u\n", &profile) == 1
+           && profile < TOMOYO_MAX_ACL_GROUPS) {
+               if (!is_delete)
+                       domain->group = (u8) profile;
                return 0;
        }
-       if (!strcmp(data, TOMOYO_KEYWORD_TRANSITION_FAILED)) {
-               domain->transition_failed = !is_delete;
+       for (profile = 0; profile < TOMOYO_MAX_DOMAIN_INFO_FLAGS; profile++) {
+               const char *cp = tomoyo_dif[profile];
+               if (strncmp(data, cp, strlen(cp) - 1))
+                       continue;
+               domain->flags[profile] = !is_delete;
                return 0;
        }
-       return tomoyo_write_domain2(data, domain, is_delete);
+       return tomoyo_write_domain2(ns, &domain->acl_info_list, data,
+                                   is_delete);
 }
 
 /**
- * tomoyo_fns - Find next set bit.
+ * tomoyo_print_condition - Print condition part.
  *
- * @perm: 8 bits value.
- * @bit:  First bit to find.
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @cond: Pointer to "struct tomoyo_condition".
  *
- * Returns next on-bit on success, 8 otherwise.
+ * Returns true on success, false otherwise.
  */
-static u8 tomoyo_fns(const u8 perm, u8 bit)
+static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
+                                  const struct tomoyo_condition *cond)
 {
-       for ( ; bit < 8; bit++)
-               if (perm & (1 << bit))
+       switch (head->r.cond_step) {
+       case 0:
+               head->r.cond_index = 0;
+               head->r.cond_step++;
+               /* fall through */
+       case 1:
+               {
+                       const u16 condc = cond->condc;
+                       const struct tomoyo_condition_element *condp =
+                               (typeof(condp)) (cond + 1);
+                       const struct tomoyo_number_union *numbers_p =
+                               (typeof(numbers_p)) (condp + condc);
+                       const struct tomoyo_name_union *names_p =
+                               (typeof(names_p))
+                               (numbers_p + cond->numbers_count);
+                       const struct tomoyo_argv *argv =
+                               (typeof(argv)) (names_p + cond->names_count);
+                       const struct tomoyo_envp *envp =
+                               (typeof(envp)) (argv + cond->argc);
+                       u16 skip;
+                       for (skip = 0; skip < head->r.cond_index; skip++) {
+                               const u8 left = condp->left;
+                               const u8 right = condp->right;
+                               condp++;
+                               switch (left) {
+                               case TOMOYO_ARGV_ENTRY:
+                                       argv++;
+                                       continue;
+                               case TOMOYO_ENVP_ENTRY:
+                                       envp++;
+                                       continue;
+                               case TOMOYO_NUMBER_UNION:
+                                       numbers_p++;
+                                       break;
+                               }
+                               switch (right) {
+                               case TOMOYO_NAME_UNION:
+                                       names_p++;
+                                       break;
+                               case TOMOYO_NUMBER_UNION:
+                                       numbers_p++;
+                                       break;
+                               }
+                       }
+                       while (head->r.cond_index < condc) {
+                               const u8 match = condp->equals;
+                               const u8 left = condp->left;
+                               const u8 right = condp->right;
+                               if (!tomoyo_flush(head))
+                                       return false;
+                               condp++;
+                               head->r.cond_index++;
+                               tomoyo_set_space(head);
+                               switch (left) {
+                               case TOMOYO_ARGV_ENTRY:
+                                       tomoyo_io_printf(head,
+                                                        "exec.argv[%lu]%s=\"",
+                                                        argv->index, argv->
+                                                        is_not ? "!" : "");
+                                       tomoyo_set_string(head,
+                                                         argv->value->name);
+                                       tomoyo_set_string(head, "\"");
+                                       argv++;
+                                       continue;
+                               case TOMOYO_ENVP_ENTRY:
+                                       tomoyo_set_string(head,
+                                                         "exec.envp[\"");
+                                       tomoyo_set_string(head,
+                                                         envp->name->name);
+                                       tomoyo_io_printf(head, "\"]%s=", envp->
+                                                        is_not ? "!" : "");
+                                       if (envp->value) {
+                                               tomoyo_set_string(head, "\"");
+                                               tomoyo_set_string(head, envp->
+                                                                 value->name);
+                                               tomoyo_set_string(head, "\"");
+                                       } else {
+                                               tomoyo_set_string(head,
+                                                                 "NULL");
+                                       }
+                                       envp++;
+                                       continue;
+                               case TOMOYO_NUMBER_UNION:
+                                       tomoyo_print_number_union_nospace
+                                               (head, numbers_p++);
+                                       break;
+                               default:
+                                       tomoyo_set_string(head,
+                                              tomoyo_condition_keyword[left]);
+                                       break;
+                               }
+                               tomoyo_set_string(head, match ? "=" : "!=");
+                               switch (right) {
+                               case TOMOYO_NAME_UNION:
+                                       tomoyo_print_name_union_quoted
+                                               (head, names_p++);
+                                       break;
+                               case TOMOYO_NUMBER_UNION:
+                                       tomoyo_print_number_union_nospace
+                                               (head, numbers_p++);
+                                       break;
+                               default:
+                                       tomoyo_set_string(head,
+                                         tomoyo_condition_keyword[right]);
+                                       break;
+                               }
+                       }
+               }
+               head->r.cond_step++;
+               /* fall through */
+       case 2:
+               if (!tomoyo_flush(head))
                        break;
-       return bit;
+               head->r.cond_step++;
+               /* fall through */
+       case 3:
+               tomoyo_set_lf(head);
+               return true;
+       }
+       return false;
+}
+
+/**
+ * tomoyo_set_group - Print "acl_group " header keyword and category name.
+ *
+ * @head:     Pointer to "struct tomoyo_io_buffer".
+ * @category: Category name.
+ *
+ * Returns nothing.
+ */
+static void tomoyo_set_group(struct tomoyo_io_buffer *head,
+                            const char *category)
+{
+       if (head->type == TOMOYO_EXCEPTIONPOLICY) {
+               tomoyo_print_namespace(head);
+               tomoyo_io_printf(head, "acl_group %u ",
+                                head->r.acl_group_index);
+       }
+       tomoyo_set_string(head, category);
 }
 
 /**
@@ -924,63 +1273,96 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
                               struct tomoyo_acl_info *acl)
 {
        const u8 acl_type = acl->type;
+       bool first = true;
        u8 bit;
 
+       if (head->r.print_cond_part)
+               goto print_cond_part;
        if (acl->is_deleted)
                return true;
- next:
-       bit = head->r.bit;
        if (!tomoyo_flush(head))
                return false;
        else if (acl_type == TOMOYO_TYPE_PATH_ACL) {
                struct tomoyo_path_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
                const u16 perm = ptr->perm;
-               for ( ; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
+               for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
                        if (!(perm & (1 << bit)))
                                continue;
-                       if (head->r.print_execute_only &&
+                       if (head->r.print_transition_related_only &&
                            bit != TOMOYO_TYPE_EXECUTE)
                                continue;
-                       /* Print "read/write" instead of "read" and "write". */
-                       if ((bit == TOMOYO_TYPE_READ ||
-                            bit == TOMOYO_TYPE_WRITE)
-                           && (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
-                               continue;
-                       break;
+                       if (first) {
+                               tomoyo_set_group(head, "file ");
+                               first = false;
+                       } else {
+                               tomoyo_set_slash(head);
+                       }
+                       tomoyo_set_string(head, tomoyo_path_keyword[bit]);
                }
-               if (bit >= TOMOYO_MAX_PATH_OPERATION)
-                       goto done;
-               tomoyo_io_printf(head, "allow_%s", tomoyo_path_keyword[bit]);
+               if (first)
+                       return true;
                tomoyo_print_name_union(head, &ptr->name);
-       } else if (head->r.print_execute_only) {
+       } else if (head->r.print_transition_related_only) {
                return true;
        } else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
                struct tomoyo_path2_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
-               bit = tomoyo_fns(ptr->perm, bit);
-               if (bit >= TOMOYO_MAX_PATH2_OPERATION)
-                       goto done;
-               tomoyo_io_printf(head, "allow_%s", tomoyo_path2_keyword[bit]);
+               const u8 perm = ptr->perm;
+               for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
+                       if (!(perm & (1 << bit)))
+                               continue;
+                       if (first) {
+                               tomoyo_set_group(head, "file ");
+                               first = false;
+                       } else {
+                               tomoyo_set_slash(head);
+                       }
+                       tomoyo_set_string(head, tomoyo_mac_keywords
+                                         [tomoyo_pp2mac[bit]]);
+               }
+               if (first)
+                       return true;
                tomoyo_print_name_union(head, &ptr->name1);
                tomoyo_print_name_union(head, &ptr->name2);
        } else if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) {
                struct tomoyo_path_number_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
-               bit = tomoyo_fns(ptr->perm, bit);
-               if (bit >= TOMOYO_MAX_PATH_NUMBER_OPERATION)
-                       goto done;
-               tomoyo_io_printf(head, "allow_%s",
-                                tomoyo_path_number_keyword[bit]);
+               const u8 perm = ptr->perm;
+               for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) {
+                       if (!(perm & (1 << bit)))
+                               continue;
+                       if (first) {
+                               tomoyo_set_group(head, "file ");
+                               first = false;
+                       } else {
+                               tomoyo_set_slash(head);
+                       }
+                       tomoyo_set_string(head, tomoyo_mac_keywords
+                                         [tomoyo_pn2mac[bit]]);
+               }
+               if (first)
+                       return true;
                tomoyo_print_name_union(head, &ptr->name);
                tomoyo_print_number_union(head, &ptr->number);
        } else if (acl_type == TOMOYO_TYPE_MKDEV_ACL) {
                struct tomoyo_mkdev_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
-               bit = tomoyo_fns(ptr->perm, bit);
-               if (bit >= TOMOYO_MAX_MKDEV_OPERATION)
-                       goto done;
-               tomoyo_io_printf(head, "allow_%s", tomoyo_mkdev_keyword[bit]);
+               const u8 perm = ptr->perm;
+               for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) {
+                       if (!(perm & (1 << bit)))
+                               continue;
+                       if (first) {
+                               tomoyo_set_group(head, "file ");
+                               first = false;
+                       } else {
+                               tomoyo_set_slash(head);
+                       }
+                       tomoyo_set_string(head, tomoyo_mac_keywords
+                                         [tomoyo_pnnn2mac[bit]]);
+               }
+               if (first)
+                       return true;
                tomoyo_print_name_union(head, &ptr->name);
                tomoyo_print_number_union(head, &ptr->mode);
                tomoyo_print_number_union(head, &ptr->major);
@@ -988,35 +1370,41 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
        } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
                struct tomoyo_mount_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
-               tomoyo_io_printf(head, "allow_mount");
+               tomoyo_set_group(head, "file mount");
                tomoyo_print_name_union(head, &ptr->dev_name);
                tomoyo_print_name_union(head, &ptr->dir_name);
                tomoyo_print_name_union(head, &ptr->fs_type);
                tomoyo_print_number_union(head, &ptr->flags);
        }
-       head->r.bit = bit + 1;
-       tomoyo_io_printf(head, "\n");
-       if (acl_type != TOMOYO_TYPE_MOUNT_ACL)
-               goto next;
- done:
-       head->r.bit = 0;
+       if (acl->cond) {
+               head->r.print_cond_part = true;
+               head->r.cond_step = 0;
+               if (!tomoyo_flush(head))
+                       return false;
+print_cond_part:
+               if (!tomoyo_print_condition(head, acl->cond))
+                       return false;
+               head->r.print_cond_part = false;
+       } else {
+               tomoyo_set_lf(head);
+       }
        return true;
 }
 
 /**
  * tomoyo_read_domain2 - Read domain policy.
  *
- * @head:   Pointer to "struct tomoyo_io_buffer".
- * @domain: Pointer to "struct tomoyo_domain_info".
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @list: Pointer to "struct list_head".
  *
  * Caller holds tomoyo_read_lock().
  *
  * Returns true on success, false otherwise.
  */
 static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
-                               struct tomoyo_domain_info *domain)
+                               struct list_head *list)
 {
-       list_for_each_cookie(head->r.acl, &domain->acl_info_list) {
+       list_for_each_cookie(head->r.acl, list) {
                struct tomoyo_acl_info *ptr =
                        list_entry(head->r.acl, typeof(*ptr), list);
                if (!tomoyo_print_entry(head, ptr))
@@ -1041,6 +1429,7 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
                struct tomoyo_domain_info *domain =
                        list_entry(head->r.domain, typeof(*domain), list);
                switch (head->r.step) {
+                       u8 i;
                case 0:
                        if (domain->is_deleted &&
                            !head->r.print_this_domain_only)
@@ -1048,22 +1437,18 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
                        /* Print domainname and flags. */
                        tomoyo_set_string(head, domain->domainname->name);
                        tomoyo_set_lf(head);
-                       tomoyo_io_printf(head,
-                                        TOMOYO_KEYWORD_USE_PROFILE "%u\n",
+                       tomoyo_io_printf(head, "use_profile %u\n",
                                         domain->profile);
-                       if (domain->quota_warned)
-                               tomoyo_set_string(head, "quota_exceeded\n");
-                       if (domain->transition_failed)
-                               tomoyo_set_string(head, "transition_failed\n");
-                       if (domain->ignore_global_allow_read)
-                               tomoyo_set_string(head,
-                                      TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ
-                                                 "\n");
+                       tomoyo_io_printf(head, "use_group %u\n",
+                                        domain->group);
+                       for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++)
+                               if (domain->flags[i])
+                                       tomoyo_set_string(head, tomoyo_dif[i]);
                        head->r.step++;
                        tomoyo_set_lf(head);
                        /* fall through */
                case 1:
-                       if (!tomoyo_read_domain2(head, domain))
+                       if (!tomoyo_read_domain2(head, &domain->acl_info_list))
                                return;
                        head->r.step++;
                        if (!tomoyo_set_lf(head))
@@ -1080,82 +1465,15 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
 }
 
 /**
- * tomoyo_write_domain_profile - Assign profile for specified domain.
+ * tomoyo_write_pid: Specify PID to obtain domainname.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
  *
- * Returns 0 on success, -EINVAL otherwise.
- *
- * This is equivalent to doing
- *
- *     ( echo "select " $domainname; echo "use_profile " $profile ) |
- *     /usr/sbin/tomoyo-loadpolicy -d
- *
- * Caller holds tomoyo_read_lock().
+ * Returns 0.
  */
-static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
+static int tomoyo_write_pid(struct tomoyo_io_buffer *head)
 {
-       char *data = head->write_buf;
-       char *cp = strchr(data, ' ');
-       struct tomoyo_domain_info *domain;
-       unsigned long profile;
-
-       if (!cp)
-               return -EINVAL;
-       *cp = '\0';
-       domain = tomoyo_find_domain(cp + 1);
-       if (strict_strtoul(data, 10, &profile))
-               return -EINVAL;
-       if (domain && profile < TOMOYO_MAX_PROFILES
-           && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
-               domain->profile = (u8) profile;
-       return 0;
-}
-
-/**
- * tomoyo_read_domain_profile - Read only domainname and profile.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns list of profile number and domainname pairs.
- *
- * This is equivalent to doing
- *
- *     grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy |
- *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
- *     domainname = $0; } else if ( $1 == "use_profile" ) {
- *     print $2 " " domainname; domainname = ""; } } ; '
- *
- * Caller holds tomoyo_read_lock().
- */
-static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
-{
-       if (head->r.eof)
-               return;
-       list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
-               struct tomoyo_domain_info *domain =
-                       list_entry(head->r.domain, typeof(*domain), list);
-               if (domain->is_deleted)
-                       continue;
-               if (!tomoyo_flush(head))
-                       return;
-               tomoyo_io_printf(head, "%u ", domain->profile);
-               tomoyo_set_string(head, domain->domainname->name);
-               tomoyo_set_lf(head);
-       }
-       head->r.eof = true;
-}
-
-/**
- * tomoyo_write_pid: Specify PID to obtain domainname.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns 0.
- */
-static int tomoyo_write_pid(struct tomoyo_io_buffer *head)
-{
-       head->r.eof = false;
+       head->r.eof = false;
        return 0;
 }
 
@@ -1204,18 +1522,20 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
        tomoyo_set_string(head, domain->domainname->name);
 }
 
+/* String table for domain transition control keywords. */
 static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
-       [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE]
-       = TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN,
-       [TOMOYO_TRANSITION_CONTROL_INITIALIZE]
-       = TOMOYO_KEYWORD_INITIALIZE_DOMAIN,
-       [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN,
-       [TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN
+       [TOMOYO_TRANSITION_CONTROL_NO_RESET]      = "no_reset_domain ",
+       [TOMOYO_TRANSITION_CONTROL_RESET]         = "reset_domain ",
+       [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
+       [TOMOYO_TRANSITION_CONTROL_INITIALIZE]    = "initialize_domain ",
+       [TOMOYO_TRANSITION_CONTROL_NO_KEEP]       = "no_keep_domain ",
+       [TOMOYO_TRANSITION_CONTROL_KEEP]          = "keep_domain ",
 };
 
+/* String table for grouping keywords. */
 static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
-       [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP,
-       [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP
+       [TOMOYO_PATH_GROUP]   = "path_group ",
+       [TOMOYO_NUMBER_GROUP] = "number_group ",
 };
 
 /**
@@ -1229,29 +1549,30 @@ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
  */
 static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
 {
-       char *data = head->write_buf;
-       bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
-       u8 i;
-       static const struct {
-               const char *keyword;
-               int (*write) (char *, const bool);
-       } tomoyo_callback[4] = {
-               { TOMOYO_KEYWORD_AGGREGATOR, tomoyo_write_aggregator },
-               { TOMOYO_KEYWORD_FILE_PATTERN, tomoyo_write_pattern },
-               { TOMOYO_KEYWORD_DENY_REWRITE, tomoyo_write_no_rewrite },
-               { TOMOYO_KEYWORD_ALLOW_READ, tomoyo_write_globally_readable },
+       const bool is_delete = head->w.is_delete;
+       struct tomoyo_acl_param param = {
+               .ns = head->w.ns,
+               .is_delete = is_delete,
+               .data = head->write_buf,
        };
-
+       u8 i;
+       if (tomoyo_str_starts(&param.data, "aggregator "))
+               return tomoyo_write_aggregator(&param);
        for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
-               if (tomoyo_str_starts(&data, tomoyo_transition_type[i]))
-                       return tomoyo_write_transition_control(data, is_delete,
-                                                              i);
-       for (i = 0; i < 4; i++)
-               if (tomoyo_str_starts(&data, tomoyo_callback[i].keyword))
-                       return tomoyo_callback[i].write(data, is_delete);
+               if (tomoyo_str_starts(&param.data, tomoyo_transition_type[i]))
+                       return tomoyo_write_transition_control(&param, i);
        for (i = 0; i < TOMOYO_MAX_GROUP; i++)
-               if (tomoyo_str_starts(&data, tomoyo_group_name[i]))
-                       return tomoyo_write_group(data, is_delete, i);
+               if (tomoyo_str_starts(&param.data, tomoyo_group_name[i]))
+                       return tomoyo_write_group(&param, i);
+       if (tomoyo_str_starts(&param.data, "acl_group ")) {
+               unsigned int group;
+               char *data;
+               group = simple_strtoul(param.data, &data, 10);
+               if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ')
+                       return tomoyo_write_domain2
+                               (head->w.ns, &head->w.ns->acl_group[group],
+                                data, is_delete);
+       }
        return -EINVAL;
 }
 
@@ -1267,9 +1588,12 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
  */
 static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
 {
-       list_for_each_cookie(head->r.group, &tomoyo_group_list[idx]) {
+       struct tomoyo_policy_namespace *ns =
+               container_of(head->r.ns, typeof(*ns), namespace_list);
+       struct list_head *list = &ns->group_list[idx];
+       list_for_each_cookie(head->r.group, list) {
                struct tomoyo_group *group =
-                       list_entry(head->r.group, typeof(*group), list);
+                       list_entry(head->r.group, typeof(*group), head.list);
                list_for_each_cookie(head->r.acl, &group->member_list) {
                        struct tomoyo_acl_head *ptr =
                                list_entry(head->r.acl, typeof(*ptr), list);
@@ -1277,6 +1601,7 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
                                continue;
                        if (!tomoyo_flush(head))
                                return false;
+                       tomoyo_print_namespace(head);
                        tomoyo_set_string(head, tomoyo_group_name[idx]);
                        tomoyo_set_string(head, group->group_name->name);
                        if (idx == TOMOYO_PATH_GROUP) {
@@ -1310,7 +1635,10 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
  */
 static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
 {
-       list_for_each_cookie(head->r.acl, &tomoyo_policy_list[idx]) {
+       struct tomoyo_policy_namespace *ns =
+               container_of(head->r.ns, typeof(*ns), namespace_list);
+       struct list_head *list = &ns->policy_list[idx];
+       list_for_each_cookie(head->r.acl, list) {
                struct tomoyo_acl_head *acl =
                        container_of(head->r.acl, typeof(*acl), list);
                if (acl->is_deleted)
@@ -1322,35 +1650,23 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
                        {
                                struct tomoyo_transition_control *ptr =
                                        container_of(acl, typeof(*ptr), head);
-                               tomoyo_set_string(head,
-                                                 tomoyo_transition_type
+                               tomoyo_print_namespace(head);
+                               tomoyo_set_string(head, tomoyo_transition_type
                                                  [ptr->type]);
-                               if (ptr->program)
-                                       tomoyo_set_string(head,
-                                                         ptr->program->name);
-                               if (ptr->program && ptr->domainname)
-                                       tomoyo_set_string(head, " from ");
-                               if (ptr->domainname)
-                                       tomoyo_set_string(head,
-                                                         ptr->domainname->
-                                                         name);
-                       }
-                       break;
-               case TOMOYO_ID_GLOBALLY_READABLE:
-                       {
-                               struct tomoyo_readable_file *ptr =
-                                       container_of(acl, typeof(*ptr), head);
-                               tomoyo_set_string(head,
-                                                 TOMOYO_KEYWORD_ALLOW_READ);
-                               tomoyo_set_string(head, ptr->filename->name);
+                               tomoyo_set_string(head, ptr->program ?
+                                                 ptr->program->name : "any");
+                               tomoyo_set_string(head, " from ");
+                               tomoyo_set_string(head, ptr->domainname ?
+                                                 ptr->domainname->name :
+                                                 "any");
                        }
                        break;
                case TOMOYO_ID_AGGREGATOR:
                        {
                                struct tomoyo_aggregator *ptr =
                                        container_of(acl, typeof(*ptr), head);
-                               tomoyo_set_string(head,
-                                                 TOMOYO_KEYWORD_AGGREGATOR);
+                               tomoyo_print_namespace(head);
+                               tomoyo_set_string(head, "aggregator ");
                                tomoyo_set_string(head,
                                                  ptr->original_name->name);
                                tomoyo_set_space(head);
@@ -1358,24 +1674,6 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
                                               ptr->aggregated_name->name);
                        }
                        break;
-               case TOMOYO_ID_PATTERN:
-                       {
-                               struct tomoyo_no_pattern *ptr =
-                                       container_of(acl, typeof(*ptr), head);
-                               tomoyo_set_string(head,
-                                                 TOMOYO_KEYWORD_FILE_PATTERN);
-                               tomoyo_set_string(head, ptr->pattern->name);
-                       }
-                       break;
-               case TOMOYO_ID_NO_REWRITE:
-                       {
-                               struct tomoyo_no_rewrite *ptr =
-                                       container_of(acl, typeof(*ptr), head);
-                               tomoyo_set_string(head,
-                                                 TOMOYO_KEYWORD_DENY_REWRITE);
-                               tomoyo_set_string(head, ptr->pattern->name);
-                       }
-                       break;
                default:
                        continue;
                }
@@ -1394,6 +1692,8 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
  */
 static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
 {
+       struct tomoyo_policy_namespace *ns =
+               container_of(head->r.ns, typeof(*ns), namespace_list);
        if (head->r.eof)
                return;
        while (head->r.step < TOMOYO_MAX_POLICY &&
@@ -1406,106 +1706,123 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
                head->r.step++;
        if (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
                return;
+       while (head->r.step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP
+              + TOMOYO_MAX_ACL_GROUPS) {
+               head->r.acl_group_index = head->r.step - TOMOYO_MAX_POLICY
+                       - TOMOYO_MAX_GROUP;
+               if (!tomoyo_read_domain2(head, &ns->acl_group
+                                        [head->r.acl_group_index]))
+                       return;
+               head->r.step++;
+       }
        head->r.eof = true;
 }
 
-/**
- * tomoyo_print_header - Get header line of audit log.
- *
- * @r: Pointer to "struct tomoyo_request_info".
- *
- * Returns string representation.
- *
- * This function uses kmalloc(), so caller must kfree() if this function
- * didn't return NULL.
- */
-static char *tomoyo_print_header(struct tomoyo_request_info *r)
-{
-       struct timeval tv;
-       const pid_t gpid = task_pid_nr(current);
-       static const int tomoyo_buffer_len = 4096;
-       char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
-       pid_t ppid;
-       if (!buffer)
-               return NULL;
-       do_gettimeofday(&tv);
-       rcu_read_lock();
-       ppid = task_tgid_vnr(current->real_parent);
-       rcu_read_unlock();
-       snprintf(buffer, tomoyo_buffer_len - 1,
-                "#timestamp=%lu profile=%u mode=%s (global-pid=%u)"
-                " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u"
-                " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }",
-                tv.tv_sec, r->profile, tomoyo_mode[r->mode], gpid,
-                task_tgid_vnr(current), ppid,
-                current_uid(), current_gid(), current_euid(),
-                current_egid(), current_suid(), current_sgid(),
-                current_fsuid(), current_fsgid());
-       return buffer;
-}
-
-/**
- * tomoyo_init_audit_log - Allocate buffer for audit logs.
- *
- * @len: Required size.
- * @r:   Pointer to "struct tomoyo_request_info".
- *
- * Returns pointer to allocated memory.
- *
- * The @len is updated to add the header lines' size on success.
- *
- * This function uses kzalloc(), so caller must kfree() if this function
- * didn't return NULL.
- */
-static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r)
-{
-       char *buf = NULL;
-       const char *header;
-       const char *domainname;
-       if (!r->domain)
-               r->domain = tomoyo_domain();
-       domainname = r->domain->domainname->name;
-       header = tomoyo_print_header(r);
-       if (!header)
-               return NULL;
-       *len += strlen(domainname) + strlen(header) + 10;
-       buf = kzalloc(*len, GFP_NOFS);
-       if (buf)
-               snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname);
-       kfree(header);
-       return buf;
-}
-
-/* Wait queue for tomoyo_query_list. */
+/* Wait queue for kernel -> userspace notification. */
 static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait);
-
-/* Lock for manipulating tomoyo_query_list. */
-static DEFINE_SPINLOCK(tomoyo_query_list_lock);
+/* Wait queue for userspace -> kernel notification. */
+static DECLARE_WAIT_QUEUE_HEAD(tomoyo_answer_wait);
 
 /* Structure for query. */
 struct tomoyo_query {
        struct list_head list;
        char *query;
-       int query_len;
+       size_t query_len;
        unsigned int serial;
-       int timer;
-       int answer;
+       u8 timer;
+       u8 answer;
+       u8 retry;
 };
 
 /* The list for "struct tomoyo_query". */
 static LIST_HEAD(tomoyo_query_list);
 
+/* Lock for manipulating tomoyo_query_list. */
+static DEFINE_SPINLOCK(tomoyo_query_list_lock);
+
 /*
  * Number of "struct file" referring /sys/kernel/security/tomoyo/query
  * interface.
  */
 static atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
 
+/**
+ * tomoyo_truncate - Truncate a line.
+ *
+ * @str: String to truncate.
+ *
+ * Returns length of truncated @str.
+ */
+static int tomoyo_truncate(char *str)
+{
+       char *start = str;
+       while (*(unsigned char *) str > (unsigned char) ' ')
+               str++;
+       *str = '\0';
+       return strlen(start) + 1;
+}
+
+/**
+ * tomoyo_add_entry - Add an ACL to current thread's domain. Used by learning mode.
+ *
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @header: Lines containing ACL.
+ *
+ * Returns nothing.
+ */
+static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header)
+{
+       char *buffer;
+       char *realpath = NULL;
+       char *argv0 = NULL;
+       char *symlink = NULL;
+       char *cp = strchr(header, '\n');
+       int len;
+       if (!cp)
+               return;
+       cp = strchr(cp + 1, '\n');
+       if (!cp)
+               return;
+       *cp++ = '\0';
+       len = strlen(cp) + 1;
+       /* strstr() will return NULL if ordering is wrong. */
+       if (*cp == 'f') {
+               argv0 = strstr(header, " argv[]={ \"");
+               if (argv0) {
+                       argv0 += 10;
+                       len += tomoyo_truncate(argv0) + 14;
+               }
+               realpath = strstr(header, " exec={ realpath=\"");
+               if (realpath) {
+                       realpath += 8;
+                       len += tomoyo_truncate(realpath) + 6;
+               }
+               symlink = strstr(header, " symlink.target=\"");
+               if (symlink)
+                       len += tomoyo_truncate(symlink + 1) + 1;
+       }
+       buffer = kmalloc(len, GFP_NOFS);
+       if (!buffer)
+               return;
+       snprintf(buffer, len - 1, "%s", cp);
+       if (realpath)
+               tomoyo_addprintf(buffer, len, " exec.%s", realpath);
+       if (argv0)
+               tomoyo_addprintf(buffer, len, " exec.argv[0]=%s", argv0);
+       if (symlink)
+               tomoyo_addprintf(buffer, len, "%s", symlink);
+       tomoyo_normalize_line(buffer);
+       if (!tomoyo_write_domain2(domain->ns, &domain->acl_info_list, buffer,
+                                 false))
+               tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
+       kfree(buffer);
+}
+
 /**
  * tomoyo_supervisor - Ask for the supervisor's decision.
  *
- * @r:       Pointer to "struct tomoyo_request_info".
- * @fmt:     The printf()'s format string, followed by parameters.
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @fmt: The printf()'s format string, followed by parameters.
  *
  * Returns 0 if the supervisor decided to permit the access request which
  * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the
@@ -1515,88 +1832,79 @@ static atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
 int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
 {
        va_list args;
-       int error = -EPERM;
-       int pos;
+       int error;
        int len;
        static unsigned int tomoyo_serial;
-       struct tomoyo_query *entry = NULL;
+       struct tomoyo_query entry = { };
        bool quota_exceeded = false;
-       char *header;
+       va_start(args, fmt);
+       len = vsnprintf((char *) &len, 1, fmt, args) + 1;
+       va_end(args);
+       /* Write /sys/kernel/security/tomoyo/audit. */
+       va_start(args, fmt);
+       tomoyo_write_log2(r, len, fmt, args);
+       va_end(args);
+       /* Nothing more to do if granted. */
+       if (r->granted)
+               return 0;
+       if (r->mode)
+               tomoyo_update_stat(r->mode);
        switch (r->mode) {
-               char *buffer;
+       case TOMOYO_CONFIG_ENFORCING:
+               error = -EPERM;
+               if (atomic_read(&tomoyo_query_observers))
+                       break;
+               goto out;
        case TOMOYO_CONFIG_LEARNING:
-               if (!tomoyo_domain_quota_is_ok(r))
-                       return 0;
-               va_start(args, fmt);
-               len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4;
-               va_end(args);
-               buffer = kmalloc(len, GFP_NOFS);
-               if (!buffer)
-                       return 0;
-               va_start(args, fmt);
-               vsnprintf(buffer, len - 1, fmt, args);
-               va_end(args);
-               tomoyo_normalize_line(buffer);
-               tomoyo_write_domain2(buffer, r->domain, false);
-               kfree(buffer);
+               error = 0;
+               /* Check max_learning_entry parameter. */
+               if (tomoyo_domain_quota_is_ok(r))
+                       break;
                /* fall through */
-       case TOMOYO_CONFIG_PERMISSIVE:
+       default:
                return 0;
        }
-       if (!r->domain)
-               r->domain = tomoyo_domain();
-       if (!atomic_read(&tomoyo_query_observers))
-               return -EPERM;
+       /* Get message. */
        va_start(args, fmt);
-       len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
+       entry.query = tomoyo_init_log(r, len, fmt, args);
        va_end(args);
-       header = tomoyo_init_audit_log(&len, r);
-       if (!header)
+       if (!entry.query)
                goto out;
-       entry = kzalloc(sizeof(*entry), GFP_NOFS);
-       if (!entry)
-               goto out;
-       entry->query = kzalloc(len, GFP_NOFS);
-       if (!entry->query)
+       entry.query_len = strlen(entry.query) + 1;
+       if (!error) {
+               tomoyo_add_entry(r->domain, entry.query);
                goto out;
-       len = ksize(entry->query);
+       }
+       len = tomoyo_round2(entry.query_len);
        spin_lock(&tomoyo_query_list_lock);
-       if (tomoyo_quota_for_query && tomoyo_query_memory_size + len +
-           sizeof(*entry) >= tomoyo_quota_for_query) {
+       if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] &&
+           tomoyo_memory_used[TOMOYO_MEMORY_QUERY] + len
+           >= tomoyo_memory_quota[TOMOYO_MEMORY_QUERY]) {
                quota_exceeded = true;
        } else {
-               tomoyo_query_memory_size += len + sizeof(*entry);
-               entry->serial = tomoyo_serial++;
+               entry.serial = tomoyo_serial++;
+               entry.retry = r->retry;
+               tomoyo_memory_used[TOMOYO_MEMORY_QUERY] += len;
+               list_add_tail(&entry.list, &tomoyo_query_list);
        }
        spin_unlock(&tomoyo_query_list_lock);
        if (quota_exceeded)
                goto out;
-       pos = snprintf(entry->query, len - 1, "Q%u-%hu\n%s",
-                      entry->serial, r->retry, header);
-       kfree(header);
-       header = NULL;
-       va_start(args, fmt);
-       vsnprintf(entry->query + pos, len - 1 - pos, fmt, args);
-       entry->query_len = strlen(entry->query) + 1;
-       va_end(args);
-       spin_lock(&tomoyo_query_list_lock);
-       list_add_tail(&entry->list, &tomoyo_query_list);
-       spin_unlock(&tomoyo_query_list_lock);
        /* Give 10 seconds for supervisor's opinion. */
-       for (entry->timer = 0;
-            atomic_read(&tomoyo_query_observers) && entry->timer < 100;
-            entry->timer++) {
-               wake_up(&tomoyo_query_wait);
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ / 10);
-               if (entry->answer)
+       while (entry.timer < 10) {
+               wake_up_all(&tomoyo_query_wait);
+               if (wait_event_interruptible_timeout
+                   (tomoyo_answer_wait, entry.answer ||
+                    !atomic_read(&tomoyo_query_observers), HZ))
                        break;
+               else
+                       entry.timer++;
        }
        spin_lock(&tomoyo_query_list_lock);
-       list_del(&entry->list);
-       tomoyo_query_memory_size -= len + sizeof(*entry);
+       list_del(&entry.list);
+       tomoyo_memory_used[TOMOYO_MEMORY_QUERY] -= len;
        spin_unlock(&tomoyo_query_list_lock);
-       switch (entry->answer) {
+       switch (entry.answer) {
        case 3: /* Asked to retry by administrator. */
                error = TOMOYO_RETRY_REQUEST;
                r->retry++;
@@ -1605,18 +1913,12 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
                /* Granted by administrator. */
                error = 0;
                break;
-       case 0:
-               /* Timed out. */
-               break;
        default:
-               /* Rejected by administrator. */
+               /* Timed out or rejected by administrator. */
                break;
        }
- out:
-       if (entry)
-               kfree(entry->query);
-       kfree(entry);
-       kfree(header);
+out:
+       kfree(entry.query);
        return error;
 }
 
@@ -1663,8 +1965,8 @@ static int tomoyo_poll_query(struct file *file, poll_table *wait)
 static void tomoyo_read_query(struct tomoyo_io_buffer *head)
 {
        struct list_head *tmp;
-       int pos = 0;
-       int len = 0;
+       unsigned int pos = 0;
+       size_t len = 0;
        char *buf;
        if (head->r.w_pos)
                return;
@@ -1687,7 +1989,7 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head)
                head->r.query_index = 0;
                return;
        }
-       buf = kzalloc(len, GFP_NOFS);
+       buf = kzalloc(len + 32, GFP_NOFS);
        if (!buf)
                return;
        pos = 0;
@@ -1703,7 +2005,8 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head)
                 * can change, but I don't care.
                 */
                if (len == ptr->query_len)
-                       memmove(buf, ptr->query, len);
+                       snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial,
+                                ptr->retry, ptr->query);
                break;
        }
        spin_unlock(&tomoyo_query_list_lock);
@@ -1760,7 +2063,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
 static void tomoyo_read_version(struct tomoyo_io_buffer *head)
 {
        if (!head->r.eof) {
-               tomoyo_io_printf(head, "2.3.0");
+               tomoyo_io_printf(head, "2.4.0");
                head->r.eof = true;
        }
 }
@@ -1785,15 +2088,111 @@ static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
        }
 }
 
+/* String table for /sys/kernel/security/tomoyo/stat interface. */
+static const char * const tomoyo_policy_headers[TOMOYO_MAX_POLICY_STAT] = {
+       [TOMOYO_STAT_POLICY_UPDATES]    = "update:",
+       [TOMOYO_STAT_POLICY_LEARNING]   = "violation in learning mode:",
+       [TOMOYO_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:",
+       [TOMOYO_STAT_POLICY_ENFORCING]  = "violation in enforcing mode:",
+};
+
+/* String table for /sys/kernel/security/tomoyo/stat interface. */
+static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = {
+       [TOMOYO_MEMORY_POLICY] = "policy:",
+       [TOMOYO_MEMORY_AUDIT]  = "audit log:",
+       [TOMOYO_MEMORY_QUERY]  = "query message:",
+};
+
+/* Timestamp counter for last updated. */
+static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT];
+/* Counter for number of updates. */
+static unsigned int tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT];
+
+/**
+ * tomoyo_update_stat - Update statistic counters.
+ *
+ * @index: Index for policy type.
+ *
+ * Returns nothing.
+ */
+void tomoyo_update_stat(const u8 index)
+{
+       struct timeval tv;
+       do_gettimeofday(&tv);
+       /*
+        * I don't use atomic operations because race condition is not fatal.
+        */
+       tomoyo_stat_updated[index]++;
+       tomoyo_stat_modified[index] = tv.tv_sec;
+}
+
+/**
+ * tomoyo_read_stat - Read statistic data.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
+static void tomoyo_read_stat(struct tomoyo_io_buffer *head)
+{
+       u8 i;
+       unsigned int total = 0;
+       if (head->r.eof)
+               return;
+       for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) {
+               tomoyo_io_printf(head, "Policy %-30s %10u",
+                                tomoyo_policy_headers[i],
+                                tomoyo_stat_updated[i]);
+               if (tomoyo_stat_modified[i]) {
+                       struct tomoyo_time stamp;
+                       tomoyo_convert_time(tomoyo_stat_modified[i], &stamp);
+                       tomoyo_io_printf(head, " (Last: %04u/%02u/%02u "
+                                        "%02u:%02u:%02u)",
+                                        stamp.year, stamp.month, stamp.day,
+                                        stamp.hour, stamp.min, stamp.sec);
+               }
+               tomoyo_set_lf(head);
+       }
+       for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) {
+               unsigned int used = tomoyo_memory_used[i];
+               total += used;
+               tomoyo_io_printf(head, "Memory used by %-22s %10u",
+                                tomoyo_memory_headers[i], used);
+               used = tomoyo_memory_quota[i];
+               if (used)
+                       tomoyo_io_printf(head, " (Quota: %10u)", used);
+               tomoyo_set_lf(head);
+       }
+       tomoyo_io_printf(head, "Total memory used:                    %10u\n",
+                        total);
+       head->r.eof = true;
+}
+
+/**
+ * tomoyo_write_stat - Set memory quota.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+static int tomoyo_write_stat(struct tomoyo_io_buffer *head)
+{
+       char *data = head->write_buf;
+       u8 i;
+       if (tomoyo_str_starts(&data, "Memory used by "))
+               for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++)
+                       if (tomoyo_str_starts(&data, tomoyo_memory_headers[i]))
+                               sscanf(data, "%u", &tomoyo_memory_quota[i]);
+       return 0;
+}
+
 /**
  * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface.
  *
  * @type: Type of interface.
  * @file: Pointer to "struct file".
  *
- * Associates policy handler and returns 0 on success, -ENOMEM otherwise.
- *
- * Caller acquires tomoyo_read_lock().
+ * Returns 0 on success, negative value otherwise.
  */
 int tomoyo_open_control(const u8 type, struct file *file)
 {
@@ -1814,15 +2213,15 @@ int tomoyo_open_control(const u8 type, struct file *file)
                head->write = tomoyo_write_exception;
                head->read = tomoyo_read_exception;
                break;
+       case TOMOYO_AUDIT:
+               /* /sys/kernel/security/tomoyo/audit */
+               head->poll = tomoyo_poll_log;
+               head->read = tomoyo_read_log;
+               break;
        case TOMOYO_SELFDOMAIN:
                /* /sys/kernel/security/tomoyo/self_domain */
                head->read = tomoyo_read_self_domain;
                break;
-       case TOMOYO_DOMAIN_STATUS:
-               /* /sys/kernel/security/tomoyo/.domain_status */
-               head->write = tomoyo_write_domain_profile;
-               head->read = tomoyo_read_domain_profile;
-               break;
        case TOMOYO_PROCESS_STATUS:
                /* /sys/kernel/security/tomoyo/.process_status */
                head->write = tomoyo_write_pid;
@@ -1833,11 +2232,11 @@ int tomoyo_open_control(const u8 type, struct file *file)
                head->read = tomoyo_read_version;
                head->readbuf_size = 128;
                break;
-       case TOMOYO_MEMINFO:
-               /* /sys/kernel/security/tomoyo/meminfo */
-               head->write = tomoyo_write_memory_quota;
-               head->read = tomoyo_read_memory_counter;
-               head->readbuf_size = 512;
+       case TOMOYO_STAT:
+               /* /sys/kernel/security/tomoyo/stat */
+               head->write = tomoyo_write_stat;
+               head->read = tomoyo_read_stat;
+               head->readbuf_size = 1024;
                break;
        case TOMOYO_PROFILE:
                /* /sys/kernel/security/tomoyo/profile */
@@ -1887,26 +2286,16 @@ int tomoyo_open_control(const u8 type, struct file *file)
                        return -ENOMEM;
                }
        }
-       if (type != TOMOYO_QUERY)
-               head->reader_idx = tomoyo_read_lock();
-       file->private_data = head;
-       /*
-        * Call the handler now if the file is
-        * /sys/kernel/security/tomoyo/self_domain
-        * so that the user can use
-        * cat < /sys/kernel/security/tomoyo/self_domain"
-        * to know the current process's domainname.
-        */
-       if (type == TOMOYO_SELFDOMAIN)
-               tomoyo_read_control(file, NULL, 0);
        /*
         * If the file is /sys/kernel/security/tomoyo/query , increment the
         * observer counter.
         * The obserber counter is used by tomoyo_supervisor() to see if
         * there is some process monitoring /sys/kernel/security/tomoyo/query.
         */
-       else if (type == TOMOYO_QUERY)
+       if (type == TOMOYO_QUERY)
                atomic_inc(&tomoyo_query_observers);
+       file->private_data = head;
+       tomoyo_notify_gc(head, true);
        return 0;
 }
 
@@ -1917,7 +2306,8 @@ int tomoyo_open_control(const u8 type, struct file *file)
  * @wait: Pointer to "poll_table".
  *
  * Waits for read readiness.
- * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd .
+ * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd and
+ * /sys/kernel/security/tomoyo/audit is handled by /usr/sbin/tomoyo-auditd.
  */
 int tomoyo_poll_control(struct file *file, poll_table *wait)
 {
@@ -1927,22 +2317,59 @@ int tomoyo_poll_control(struct file *file, poll_table *wait)
        return head->poll(file, wait);
 }
 
+/**
+ * tomoyo_set_namespace_cursor - Set namespace to read.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head)
+{
+       struct list_head *ns;
+       if (head->type != TOMOYO_EXCEPTIONPOLICY &&
+           head->type != TOMOYO_PROFILE)
+               return;
+       /*
+        * If this is the first read, or reading previous namespace finished
+        * and has more namespaces to read, update the namespace cursor.
+        */
+       ns = head->r.ns;
+       if (!ns || (head->r.eof && ns->next != &tomoyo_namespace_list)) {
+               /* Clearing is OK because tomoyo_flush() returned true. */
+               memset(&head->r, 0, sizeof(head->r));
+               head->r.ns = ns ? ns->next : tomoyo_namespace_list.next;
+       }
+}
+
+/**
+ * tomoyo_has_more_namespace - Check for unread namespaces.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns true if we have more entries to print, false otherwise.
+ */
+static inline bool tomoyo_has_more_namespace(struct tomoyo_io_buffer *head)
+{
+       return (head->type == TOMOYO_EXCEPTIONPOLICY ||
+               head->type == TOMOYO_PROFILE) && head->r.eof &&
+               head->r.ns->next != &tomoyo_namespace_list;
+}
+
 /**
  * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
  *
- * @file:       Pointer to "struct file".
+ * @head:       Pointer to "struct tomoyo_io_buffer".
  * @buffer:     Poiner to buffer to write to.
  * @buffer_len: Size of @buffer.
  *
  * Returns bytes read on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
  */
-int tomoyo_read_control(struct file *file, char __user *buffer,
-                       const int buffer_len)
+ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
+                           const int buffer_len)
 {
        int len;
-       struct tomoyo_io_buffer *head = file->private_data;
+       int idx;
 
        if (!head->read)
                return -ENOSYS;
@@ -1950,64 +2377,156 @@ int tomoyo_read_control(struct file *file, char __user *buffer,
                return -EINTR;
        head->read_user_buf = buffer;
        head->read_user_buf_avail = buffer_len;
+       idx = tomoyo_read_lock();
        if (tomoyo_flush(head))
                /* Call the policy handler. */
-               head->read(head);
-       tomoyo_flush(head);
+               do {
+                       tomoyo_set_namespace_cursor(head);
+                       head->read(head);
+               } while (tomoyo_flush(head) &&
+                        tomoyo_has_more_namespace(head));
+       tomoyo_read_unlock(idx);
        len = head->read_user_buf - buffer;
        mutex_unlock(&head->io_sem);
        return len;
 }
 
+/**
+ * tomoyo_parse_policy - Parse a policy line.
+ *
+ * @head: Poiter to "struct tomoyo_io_buffer".
+ * @line: Line to parse.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line)
+{
+       /* Delete request? */
+       head->w.is_delete = !strncmp(line, "delete ", 7);
+       if (head->w.is_delete)
+               memmove(line, line + 7, strlen(line + 7) + 1);
+       /* Selecting namespace to update. */
+       if (head->type == TOMOYO_EXCEPTIONPOLICY ||
+           head->type == TOMOYO_PROFILE) {
+               if (*line == '<') {
+                       char *cp = strchr(line, ' ');
+                       if (cp) {
+                               *cp++ = '\0';
+                               head->w.ns = tomoyo_assign_namespace(line);
+                               memmove(line, cp, strlen(cp) + 1);
+                       } else
+                               head->w.ns = NULL;
+               } else
+                       head->w.ns = &tomoyo_kernel_namespace;
+               /* Don't allow updating if namespace is invalid. */
+               if (!head->w.ns)
+                       return -ENOENT;
+       }
+       /* Do the update. */
+       return head->write(head);
+}
+
 /**
  * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface.
  *
- * @file:       Pointer to "struct file".
+ * @head:       Pointer to "struct tomoyo_io_buffer".
  * @buffer:     Pointer to buffer to read from.
  * @buffer_len: Size of @buffer.
  *
  * Returns @buffer_len on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_control(struct file *file, const char __user *buffer,
-                        const int buffer_len)
+ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
+                            const char __user *buffer, const int buffer_len)
 {
-       struct tomoyo_io_buffer *head = file->private_data;
        int error = buffer_len;
-       int avail_len = buffer_len;
+       size_t avail_len = buffer_len;
        char *cp0 = head->write_buf;
-
+       int idx;
        if (!head->write)
                return -ENOSYS;
        if (!access_ok(VERIFY_READ, buffer, buffer_len))
                return -EFAULT;
-       /* Don't allow updating policies by non manager programs. */
-       if (head->write != tomoyo_write_pid &&
-           head->write != tomoyo_write_domain && !tomoyo_manager())
-               return -EPERM;
        if (mutex_lock_interruptible(&head->io_sem))
                return -EINTR;
+       idx = tomoyo_read_lock();
        /* Read a line and dispatch it to the policy handler. */
        while (avail_len > 0) {
                char c;
-               if (head->write_avail >= head->writebuf_size - 1) {
-                       error = -ENOMEM;
-                       break;
-               } else if (get_user(c, buffer)) {
+               if (head->w.avail >= head->writebuf_size - 1) {
+                       const int len = head->writebuf_size * 2;
+                       char *cp = kzalloc(len, GFP_NOFS);
+                       if (!cp) {
+                               error = -ENOMEM;
+                               break;
+                       }
+                       memmove(cp, cp0, head->w.avail);
+                       kfree(cp0);
+                       head->write_buf = cp;
+                       cp0 = cp;
+                       head->writebuf_size = len;
+               }
+               if (get_user(c, buffer)) {
                        error = -EFAULT;
                        break;
                }
                buffer++;
                avail_len--;
-               cp0[head->write_avail++] = c;
+               cp0[head->w.avail++] = c;
                if (c != '\n')
                        continue;
-               cp0[head->write_avail - 1] = '\0';
-               head->write_avail = 0;
+               cp0[head->w.avail - 1] = '\0';
+               head->w.avail = 0;
                tomoyo_normalize_line(cp0);
-               head->write(head);
+               if (!strcmp(cp0, "reset")) {
+                       head->w.ns = &tomoyo_kernel_namespace;
+                       head->w.domain = NULL;
+                       memset(&head->r, 0, sizeof(head->r));
+                       continue;
+               }
+               /* Don't allow updating policies by non manager programs. */
+               switch (head->type) {
+               case TOMOYO_PROCESS_STATUS:
+                       /* This does not write anything. */
+                       break;
+               case TOMOYO_DOMAINPOLICY:
+                       if (tomoyo_select_domain(head, cp0))
+                               continue;
+                       /* fall through */
+               case TOMOYO_EXCEPTIONPOLICY:
+                       if (!strcmp(cp0, "select transition_only")) {
+                               head->r.print_transition_related_only = true;
+                               continue;
+                       }
+                       /* fall through */
+               default:
+                       if (!tomoyo_manager()) {
+                               error = -EPERM;
+                               goto out;
+                       }
+               }
+               switch (tomoyo_parse_policy(head, cp0)) {
+               case -EPERM:
+                       error = -EPERM;
+                       goto out;
+               case 0:
+                       switch (head->type) {
+                       case TOMOYO_DOMAINPOLICY:
+                       case TOMOYO_EXCEPTIONPOLICY:
+                       case TOMOYO_STAT:
+                       case TOMOYO_PROFILE:
+                       case TOMOYO_MANAGER:
+                               tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               }
        }
+out:
+       tomoyo_read_unlock(idx);
        mutex_unlock(&head->io_sem);
        return error;
 }
@@ -2015,35 +2534,20 @@ int tomoyo_write_control(struct file *file, const char __user *buffer,
 /**
  * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface.
  *
- * @file: Pointer to "struct file".
- *
- * Releases memory and returns 0.
+ * @head: Pointer to "struct tomoyo_io_buffer".
  *
- * Caller looses tomoyo_read_lock().
+ * Returns 0.
  */
-int tomoyo_close_control(struct file *file)
+int tomoyo_close_control(struct tomoyo_io_buffer *head)
 {
-       struct tomoyo_io_buffer *head = file->private_data;
-       const bool is_write = !!head->write_buf;
-
        /*
         * If the file is /sys/kernel/security/tomoyo/query , decrement the
         * observer counter.
         */
-       if (head->type == TOMOYO_QUERY)
-               atomic_dec(&tomoyo_query_observers);
-       else
-               tomoyo_read_unlock(head->reader_idx);
-       /* Release memory used for policy I/O. */
-       kfree(head->read_buf);
-       head->read_buf = NULL;
-       kfree(head->write_buf);
-       head->write_buf = NULL;
-       kfree(head);
-       head = NULL;
-       file->private_data = NULL;
-       if (is_write)
-               tomoyo_run_gc();
+       if (head->type == TOMOYO_QUERY &&
+           atomic_dec_and_test(&tomoyo_query_observers))
+               wake_up_all(&tomoyo_answer_wait);
+       tomoyo_notify_gc(head, false);
        return 0;
 }
 
@@ -2055,27 +2559,90 @@ void tomoyo_check_profile(void)
        struct tomoyo_domain_info *domain;
        const int idx = tomoyo_read_lock();
        tomoyo_policy_loaded = true;
-       /* Check all profiles currently assigned to domains are defined. */
+       printk(KERN_INFO "TOMOYO: 2.4.0\n");
        list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
                const u8 profile = domain->profile;
-               if (tomoyo_profile_ptr[profile])
+               const struct tomoyo_policy_namespace *ns = domain->ns;
+               if (ns->profile_version != 20100903)
+                       printk(KERN_ERR
+                              "Profile version %u is not supported.\n",
+                              ns->profile_version);
+               else if (!ns->profile_ptr[profile])
+                       printk(KERN_ERR
+                              "Profile %u (used by '%s') is not defined.\n",
+                              profile, domain->domainname->name);
+               else
                        continue;
-               printk(KERN_ERR "You need to define profile %u before using it.\n",
-                      profile);
-               printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ "
+               printk(KERN_ERR
+                      "Userland tools for TOMOYO 2.4 must be installed and "
+                      "policy must be initialized.\n");
+               printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ "
                       "for more information.\n");
-               panic("Profile %u (used by '%s') not defined.\n",
-                     profile, domain->domainname->name);
+               panic("STOP!");
        }
        tomoyo_read_unlock(idx);
-       if (tomoyo_profile_version != 20090903) {
-               printk(KERN_ERR "You need to install userland programs for "
-                      "TOMOYO 2.3 and initialize policy configuration.\n");
-               printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ "
-                      "for more information.\n");
-               panic("Profile version %u is not supported.\n",
-                     tomoyo_profile_version);
-       }
-       printk(KERN_INFO "TOMOYO: 2.3.0\n");
        printk(KERN_INFO "Mandatory Access Control activated.\n");
 }
+
+/**
+ * tomoyo_load_builtin_policy - Load built-in policy.
+ *
+ * Returns nothing.
+ */
+void __init tomoyo_load_builtin_policy(void)
+{
+       /*
+        * This include file is manually created and contains built-in policy
+        * named "tomoyo_builtin_profile", "tomoyo_builtin_exception_policy",
+        * "tomoyo_builtin_domain_policy", "tomoyo_builtin_manager",
+        * "tomoyo_builtin_stat" in the form of "static char [] __initdata".
+        */
+#include "builtin-policy.h"
+       u8 i;
+       const int idx = tomoyo_read_lock();
+       for (i = 0; i < 5; i++) {
+               struct tomoyo_io_buffer head = { };
+               char *start = "";
+               switch (i) {
+               case 0:
+                       start = tomoyo_builtin_profile;
+                       head.type = TOMOYO_PROFILE;
+                       head.write = tomoyo_write_profile;
+                       break;
+               case 1:
+                       start = tomoyo_builtin_exception_policy;
+                       head.type = TOMOYO_EXCEPTIONPOLICY;
+                       head.write = tomoyo_write_exception;
+                       break;
+               case 2:
+                       start = tomoyo_builtin_domain_policy;
+                       head.type = TOMOYO_DOMAINPOLICY;
+                       head.write = tomoyo_write_domain;
+                       break;
+               case 3:
+                       start = tomoyo_builtin_manager;
+                       head.type = TOMOYO_MANAGER;
+                       head.write = tomoyo_write_manager;
+                       break;
+               case 4:
+                       start = tomoyo_builtin_stat;
+                       head.type = TOMOYO_STAT;
+                       head.write = tomoyo_write_stat;
+                       break;
+               }
+               while (1) {
+                       char *end = strchr(start, '\n');
+                       if (!end)
+                               break;
+                       *end = '\0';
+                       tomoyo_normalize_line(start);
+                       head.write_buf = start;
+                       tomoyo_parse_policy(&head, start);
+                       start = end + 1;
+               }
+       }
+       tomoyo_read_unlock(idx);
+#ifdef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+       tomoyo_check_profile();
+#endif
+}
index 7c66bd898782ce0c6fa8ea037cd19dfd78fc8bfe..f7fbaa66e443dcd95aaa4002eedd49f87ffedde1 100644 (file)
@@ -21,7 +21,8 @@
 #include <linux/list.h>
 #include <linux/cred.h>
 #include <linux/poll.h>
-struct linux_binprm;
+#include <linux/binfmts.h>
+#include <linux/highmem.h>
 
 /********** Constants definitions. **********/
 
@@ -38,66 +39,149 @@ struct linux_binprm;
 /* Profile number is an integer between 0 and 255. */
 #define TOMOYO_MAX_PROFILES 256
 
+/* Group number is an integer between 0 and 255. */
+#define TOMOYO_MAX_ACL_GROUPS 256
+
+/* Index numbers for "struct tomoyo_condition". */
+enum tomoyo_conditions_index {
+       TOMOYO_TASK_UID,             /* current_uid()   */
+       TOMOYO_TASK_EUID,            /* current_euid()  */
+       TOMOYO_TASK_SUID,            /* current_suid()  */
+       TOMOYO_TASK_FSUID,           /* current_fsuid() */
+       TOMOYO_TASK_GID,             /* current_gid()   */
+       TOMOYO_TASK_EGID,            /* current_egid()  */
+       TOMOYO_TASK_SGID,            /* current_sgid()  */
+       TOMOYO_TASK_FSGID,           /* current_fsgid() */
+       TOMOYO_TASK_PID,             /* sys_getpid()   */
+       TOMOYO_TASK_PPID,            /* sys_getppid()  */
+       TOMOYO_EXEC_ARGC,            /* "struct linux_binprm *"->argc */
+       TOMOYO_EXEC_ENVC,            /* "struct linux_binprm *"->envc */
+       TOMOYO_TYPE_IS_SOCKET,       /* S_IFSOCK */
+       TOMOYO_TYPE_IS_SYMLINK,      /* S_IFLNK */
+       TOMOYO_TYPE_IS_FILE,         /* S_IFREG */
+       TOMOYO_TYPE_IS_BLOCK_DEV,    /* S_IFBLK */
+       TOMOYO_TYPE_IS_DIRECTORY,    /* S_IFDIR */
+       TOMOYO_TYPE_IS_CHAR_DEV,     /* S_IFCHR */
+       TOMOYO_TYPE_IS_FIFO,         /* S_IFIFO */
+       TOMOYO_MODE_SETUID,          /* S_ISUID */
+       TOMOYO_MODE_SETGID,          /* S_ISGID */
+       TOMOYO_MODE_STICKY,          /* S_ISVTX */
+       TOMOYO_MODE_OWNER_READ,      /* S_IRUSR */
+       TOMOYO_MODE_OWNER_WRITE,     /* S_IWUSR */
+       TOMOYO_MODE_OWNER_EXECUTE,   /* S_IXUSR */
+       TOMOYO_MODE_GROUP_READ,      /* S_IRGRP */
+       TOMOYO_MODE_GROUP_WRITE,     /* S_IWGRP */
+       TOMOYO_MODE_GROUP_EXECUTE,   /* S_IXGRP */
+       TOMOYO_MODE_OTHERS_READ,     /* S_IROTH */
+       TOMOYO_MODE_OTHERS_WRITE,    /* S_IWOTH */
+       TOMOYO_MODE_OTHERS_EXECUTE,  /* S_IXOTH */
+       TOMOYO_EXEC_REALPATH,
+       TOMOYO_SYMLINK_TARGET,
+       TOMOYO_PATH1_UID,
+       TOMOYO_PATH1_GID,
+       TOMOYO_PATH1_INO,
+       TOMOYO_PATH1_MAJOR,
+       TOMOYO_PATH1_MINOR,
+       TOMOYO_PATH1_PERM,
+       TOMOYO_PATH1_TYPE,
+       TOMOYO_PATH1_DEV_MAJOR,
+       TOMOYO_PATH1_DEV_MINOR,
+       TOMOYO_PATH2_UID,
+       TOMOYO_PATH2_GID,
+       TOMOYO_PATH2_INO,
+       TOMOYO_PATH2_MAJOR,
+       TOMOYO_PATH2_MINOR,
+       TOMOYO_PATH2_PERM,
+       TOMOYO_PATH2_TYPE,
+       TOMOYO_PATH2_DEV_MAJOR,
+       TOMOYO_PATH2_DEV_MINOR,
+       TOMOYO_PATH1_PARENT_UID,
+       TOMOYO_PATH1_PARENT_GID,
+       TOMOYO_PATH1_PARENT_INO,
+       TOMOYO_PATH1_PARENT_PERM,
+       TOMOYO_PATH2_PARENT_UID,
+       TOMOYO_PATH2_PARENT_GID,
+       TOMOYO_PATH2_PARENT_INO,
+       TOMOYO_PATH2_PARENT_PERM,
+       TOMOYO_MAX_CONDITION_KEYWORD,
+       TOMOYO_NUMBER_UNION,
+       TOMOYO_NAME_UNION,
+       TOMOYO_ARGV_ENTRY,
+       TOMOYO_ENVP_ENTRY,
+};
+
+
+/* Index numbers for stat(). */
+enum tomoyo_path_stat_index {
+       /* Do not change this order. */
+       TOMOYO_PATH1,
+       TOMOYO_PATH1_PARENT,
+       TOMOYO_PATH2,
+       TOMOYO_PATH2_PARENT,
+       TOMOYO_MAX_PATH_STAT
+};
+
+/* Index numbers for operation mode. */
 enum tomoyo_mode_index {
        TOMOYO_CONFIG_DISABLED,
        TOMOYO_CONFIG_LEARNING,
        TOMOYO_CONFIG_PERMISSIVE,
        TOMOYO_CONFIG_ENFORCING,
-       TOMOYO_CONFIG_USE_DEFAULT = 255
+       TOMOYO_CONFIG_MAX_MODE,
+       TOMOYO_CONFIG_WANT_REJECT_LOG =  64,
+       TOMOYO_CONFIG_WANT_GRANT_LOG  = 128,
+       TOMOYO_CONFIG_USE_DEFAULT     = 255,
 };
 
+/* Index numbers for entry type. */
 enum tomoyo_policy_id {
        TOMOYO_ID_GROUP,
        TOMOYO_ID_PATH_GROUP,
        TOMOYO_ID_NUMBER_GROUP,
        TOMOYO_ID_TRANSITION_CONTROL,
        TOMOYO_ID_AGGREGATOR,
-       TOMOYO_ID_GLOBALLY_READABLE,
-       TOMOYO_ID_PATTERN,
-       TOMOYO_ID_NO_REWRITE,
        TOMOYO_ID_MANAGER,
+       TOMOYO_ID_CONDITION,
        TOMOYO_ID_NAME,
        TOMOYO_ID_ACL,
        TOMOYO_ID_DOMAIN,
        TOMOYO_MAX_POLICY
 };
 
+/* Index numbers for domain's attributes. */
+enum tomoyo_domain_info_flags_index {
+       /* Quota warnning flag.   */
+       TOMOYO_DIF_QUOTA_WARNED,
+       /*
+        * This domain was unable to create a new domain at
+        * tomoyo_find_next_domain() because the name of the domain to be
+        * created was too long or it could not allocate memory.
+        * More than one process continued execve() without domain transition.
+        */
+       TOMOYO_DIF_TRANSITION_FAILED,
+       TOMOYO_MAX_DOMAIN_INFO_FLAGS
+};
+
+/* Index numbers for group entries. */
 enum tomoyo_group_id {
        TOMOYO_PATH_GROUP,
        TOMOYO_NUMBER_GROUP,
        TOMOYO_MAX_GROUP
 };
 
-/* Keywords for ACLs. */
-#define TOMOYO_KEYWORD_AGGREGATOR                "aggregator "
-#define TOMOYO_KEYWORD_ALLOW_MOUNT               "allow_mount "
-#define TOMOYO_KEYWORD_ALLOW_READ                "allow_read "
-#define TOMOYO_KEYWORD_DELETE                    "delete "
-#define TOMOYO_KEYWORD_DENY_REWRITE              "deny_rewrite "
-#define TOMOYO_KEYWORD_FILE_PATTERN              "file_pattern "
-#define TOMOYO_KEYWORD_INITIALIZE_DOMAIN         "initialize_domain "
-#define TOMOYO_KEYWORD_KEEP_DOMAIN               "keep_domain "
-#define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN      "no_initialize_domain "
-#define TOMOYO_KEYWORD_NO_KEEP_DOMAIN            "no_keep_domain "
-#define TOMOYO_KEYWORD_PATH_GROUP                "path_group "
-#define TOMOYO_KEYWORD_NUMBER_GROUP              "number_group "
-#define TOMOYO_KEYWORD_SELECT                    "select "
-#define TOMOYO_KEYWORD_USE_PROFILE               "use_profile "
-#define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ  "ignore_global_allow_read"
-#define TOMOYO_KEYWORD_QUOTA_EXCEEDED            "quota_exceeded"
-#define TOMOYO_KEYWORD_TRANSITION_FAILED         "transition_failed"
-/* A domain definition starts with <kernel>. */
-#define TOMOYO_ROOT_NAME                         "<kernel>"
-#define TOMOYO_ROOT_NAME_LEN                     (sizeof(TOMOYO_ROOT_NAME) - 1)
-
-/* Value type definition. */
-#define TOMOYO_VALUE_TYPE_INVALID     0
-#define TOMOYO_VALUE_TYPE_DECIMAL     1
-#define TOMOYO_VALUE_TYPE_OCTAL       2
-#define TOMOYO_VALUE_TYPE_HEXADECIMAL 3
+/* Index numbers for type of numeric values. */
+enum tomoyo_value_type {
+       TOMOYO_VALUE_TYPE_INVALID,
+       TOMOYO_VALUE_TYPE_DECIMAL,
+       TOMOYO_VALUE_TYPE_OCTAL,
+       TOMOYO_VALUE_TYPE_HEXADECIMAL,
+};
 
+/* Index numbers for domain transition control keywords. */
 enum tomoyo_transition_type {
        /* Do not change this order, */
+       TOMOYO_TRANSITION_CONTROL_NO_RESET,
+       TOMOYO_TRANSITION_CONTROL_RESET,
        TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE,
        TOMOYO_TRANSITION_CONTROL_INITIALIZE,
        TOMOYO_TRANSITION_CONTROL_NO_KEEP,
@@ -114,35 +198,29 @@ enum tomoyo_acl_entry_type_index {
        TOMOYO_TYPE_MOUNT_ACL,
 };
 
-/* Index numbers for File Controls. */
-
-/*
- * TOMOYO_TYPE_READ_WRITE is special. TOMOYO_TYPE_READ_WRITE is automatically
- * set if both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are set.
- * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically set if
- * TOMOYO_TYPE_READ_WRITE is set.
- * TOMOYO_TYPE_READ_WRITE is automatically cleared if either TOMOYO_TYPE_READ
- * or TOMOYO_TYPE_WRITE is cleared.
- * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically cleared if
- * TOMOYO_TYPE_READ_WRITE is cleared.
- */
-
+/* Index numbers for access controls with one pathname. */
 enum tomoyo_path_acl_index {
-       TOMOYO_TYPE_READ_WRITE,
        TOMOYO_TYPE_EXECUTE,
        TOMOYO_TYPE_READ,
        TOMOYO_TYPE_WRITE,
+       TOMOYO_TYPE_APPEND,
        TOMOYO_TYPE_UNLINK,
+       TOMOYO_TYPE_GETATTR,
        TOMOYO_TYPE_RMDIR,
        TOMOYO_TYPE_TRUNCATE,
        TOMOYO_TYPE_SYMLINK,
-       TOMOYO_TYPE_REWRITE,
        TOMOYO_TYPE_CHROOT,
        TOMOYO_TYPE_UMOUNT,
        TOMOYO_MAX_PATH_OPERATION
 };
 
-#define TOMOYO_RW_MASK ((1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE))
+/* Index numbers for /sys/kernel/security/tomoyo/stat interface. */
+enum tomoyo_memory_stat_type {
+       TOMOYO_MEMORY_POLICY,
+       TOMOYO_MEMORY_AUDIT,
+       TOMOYO_MEMORY_QUERY,
+       TOMOYO_MAX_MEMORY_STAT
+};
 
 enum tomoyo_mkdev_acl_index {
        TOMOYO_TYPE_MKBLOCK,
@@ -150,6 +228,7 @@ enum tomoyo_mkdev_acl_index {
        TOMOYO_MAX_MKDEV_OPERATION
 };
 
+/* Index numbers for access controls with two pathnames. */
 enum tomoyo_path2_acl_index {
        TOMOYO_TYPE_LINK,
        TOMOYO_TYPE_RENAME,
@@ -157,6 +236,7 @@ enum tomoyo_path2_acl_index {
        TOMOYO_MAX_PATH2_OPERATION
 };
 
+/* Index numbers for access controls with one pathname and one number. */
 enum tomoyo_path_number_acl_index {
        TOMOYO_TYPE_CREATE,
        TOMOYO_TYPE_MKDIR,
@@ -169,31 +249,45 @@ enum tomoyo_path_number_acl_index {
        TOMOYO_MAX_PATH_NUMBER_OPERATION
 };
 
+/* Index numbers for /sys/kernel/security/tomoyo/ interfaces. */
 enum tomoyo_securityfs_interface_index {
        TOMOYO_DOMAINPOLICY,
        TOMOYO_EXCEPTIONPOLICY,
-       TOMOYO_DOMAIN_STATUS,
        TOMOYO_PROCESS_STATUS,
-       TOMOYO_MEMINFO,
+       TOMOYO_STAT,
        TOMOYO_SELFDOMAIN,
+       TOMOYO_AUDIT,
        TOMOYO_VERSION,
        TOMOYO_PROFILE,
        TOMOYO_QUERY,
        TOMOYO_MANAGER
 };
 
+/* Index numbers for special mount operations. */
+enum tomoyo_special_mount {
+       TOMOYO_MOUNT_BIND,            /* mount --bind /source /dest   */
+       TOMOYO_MOUNT_MOVE,            /* mount --move /old /new       */
+       TOMOYO_MOUNT_REMOUNT,         /* mount -o remount /dir        */
+       TOMOYO_MOUNT_MAKE_UNBINDABLE, /* mount --make-unbindable /dir */
+       TOMOYO_MOUNT_MAKE_PRIVATE,    /* mount --make-private /dir    */
+       TOMOYO_MOUNT_MAKE_SLAVE,      /* mount --make-slave /dir      */
+       TOMOYO_MOUNT_MAKE_SHARED,     /* mount --make-shared /dir     */
+       TOMOYO_MAX_SPECIAL_MOUNT
+};
+
+/* Index numbers for functionality. */
 enum tomoyo_mac_index {
        TOMOYO_MAC_FILE_EXECUTE,
        TOMOYO_MAC_FILE_OPEN,
        TOMOYO_MAC_FILE_CREATE,
        TOMOYO_MAC_FILE_UNLINK,
+       TOMOYO_MAC_FILE_GETATTR,
        TOMOYO_MAC_FILE_MKDIR,
        TOMOYO_MAC_FILE_RMDIR,
        TOMOYO_MAC_FILE_MKFIFO,
        TOMOYO_MAC_FILE_MKSOCK,
        TOMOYO_MAC_FILE_TRUNCATE,
        TOMOYO_MAC_FILE_SYMLINK,
-       TOMOYO_MAC_FILE_REWRITE,
        TOMOYO_MAC_FILE_MKBLOCK,
        TOMOYO_MAC_FILE_MKCHAR,
        TOMOYO_MAC_FILE_LINK,
@@ -209,38 +303,66 @@ enum tomoyo_mac_index {
        TOMOYO_MAX_MAC_INDEX
 };
 
+/* Index numbers for category of functionality. */
 enum tomoyo_mac_category_index {
        TOMOYO_MAC_CATEGORY_FILE,
        TOMOYO_MAX_MAC_CATEGORY_INDEX
 };
 
-#define TOMOYO_RETRY_REQUEST 1 /* Retry this request. */
-
-/********** Structure definitions. **********/
-
 /*
- * tomoyo_acl_head is a structure which is used for holding elements not in
- * domain policy.
- * It has following fields.
+ * Retry this request. Returned by tomoyo_supervisor() if policy violation has
+ * occurred in enforcing mode and the userspace daemon decided to retry.
  *
- *  (1) "list" which is linked to tomoyo_policy_list[] .
- *  (2) "is_deleted" is a bool which is true if marked as deleted, false
- *      otherwise.
+ * We must choose a positive value in order to distinguish "granted" (which is
+ * 0) and "rejected" (which is a negative value) and "retry".
  */
+#define TOMOYO_RETRY_REQUEST 1
+
+/* Index numbers for /sys/kernel/security/tomoyo/stat interface. */
+enum tomoyo_policy_stat_type {
+       /* Do not change this order. */
+       TOMOYO_STAT_POLICY_UPDATES,
+       TOMOYO_STAT_POLICY_LEARNING,   /* == TOMOYO_CONFIG_LEARNING */
+       TOMOYO_STAT_POLICY_PERMISSIVE, /* == TOMOYO_CONFIG_PERMISSIVE */
+       TOMOYO_STAT_POLICY_ENFORCING,  /* == TOMOYO_CONFIG_ENFORCING */
+       TOMOYO_MAX_POLICY_STAT
+};
+
+/* Index numbers for profile's PREFERENCE values. */
+enum tomoyo_pref_index {
+       TOMOYO_PREF_MAX_AUDIT_LOG,
+       TOMOYO_PREF_MAX_LEARNING_ENTRY,
+       TOMOYO_MAX_PREF
+};
+
+/********** Structure definitions. **********/
+
+/* Common header for holding ACL entries. */
 struct tomoyo_acl_head {
        struct list_head list;
        bool is_deleted;
 } __packed;
 
-/*
- * tomoyo_request_info is a structure which is used for holding
- *
- * (1) Domain information of current process.
- * (2) How many retries are made for this request.
- * (3) Profile number used for this request.
- * (4) Access control mode of the profile.
- */
+/* Common header for shared entries. */
+struct tomoyo_shared_acl_head {
+       struct list_head list;
+       atomic_t users;
+} __packed;
+
+struct tomoyo_policy_namespace;
+
+/* Structure for request info. */
 struct tomoyo_request_info {
+       /*
+        * For holding parameters specific to operations which deal files.
+        * NULL if not dealing files.
+        */
+       struct tomoyo_obj_info *obj;
+       /*
+        * For holding parameters specific to execve() request.
+        * NULL if not dealing do_execve().
+        */
+       struct tomoyo_execve *ee;
        struct tomoyo_domain_info *domain;
        /* For holding parameters. */
        union {
@@ -248,11 +370,13 @@ struct tomoyo_request_info {
                        const struct tomoyo_path_info *filename;
                        /* For using wildcards at tomoyo_find_next_domain(). */
                        const struct tomoyo_path_info *matched_path;
+                       /* One of values in "enum tomoyo_path_acl_index". */
                        u8 operation;
                } path;
                struct {
                        const struct tomoyo_path_info *filename1;
                        const struct tomoyo_path_info *filename2;
+                       /* One of values in "enum tomoyo_path2_acl_index". */
                        u8 operation;
                } path2;
                struct {
@@ -260,11 +384,16 @@ struct tomoyo_request_info {
                        unsigned int mode;
                        unsigned int major;
                        unsigned int minor;
+                       /* One of values in "enum tomoyo_mkdev_acl_index". */
                        u8 operation;
                } mkdev;
                struct {
                        const struct tomoyo_path_info *filename;
                        unsigned long number;
+                       /*
+                        * One of values in
+                        * "enum tomoyo_path_number_acl_index".
+                        */
                        u8 operation;
                } path_number;
                struct {
@@ -283,26 +412,7 @@ struct tomoyo_request_info {
        u8 type;
 };
 
-/*
- * tomoyo_path_info is a structure which is used for holding a string data
- * used by TOMOYO.
- * This structure has several fields for supporting pattern matching.
- *
- * (1) "name" is the '\0' terminated string data.
- * (2) "hash" is full_name_hash(name, strlen(name)).
- *     This allows tomoyo_pathcmp() to compare by hash before actually compare
- *     using strcmp().
- * (3) "const_len" is the length of the initial segment of "name" which
- *     consists entirely of non wildcard characters. In other words, the length
- *     which we can compare two strings using strncmp().
- * (4) "is_dir" is a bool which is true if "name" ends with "/",
- *     false otherwise.
- *     TOMOYO distinguishes directory and non-directory. A directory ends with
- *     "/" and non-directory does not end with "/".
- * (5) "is_patterned" is a bool which is true if "name" contains wildcard
- *     characters, false otherwise. This allows TOMOYO to use "hash" and
- *     strcmp() for string comparison if "is_patterned" is false.
- */
+/* Structure for holding a token. */
 struct tomoyo_path_info {
        const char *name;
        u32 hash;          /* = full_name_hash(name, strlen(name)) */
@@ -311,36 +421,32 @@ struct tomoyo_path_info {
        bool is_patterned; /* = tomoyo_path_contains_pattern(name) */
 };
 
-/*
- * tomoyo_name is a structure which is used for linking
- * "struct tomoyo_path_info" into tomoyo_name_list .
- */
+/* Structure for holding string data. */
 struct tomoyo_name {
-       struct list_head list;
-       atomic_t users;
+       struct tomoyo_shared_acl_head head;
        struct tomoyo_path_info entry;
 };
 
+/* Structure for holding a word. */
 struct tomoyo_name_union {
+       /* Either @filename or @group is NULL. */
        const struct tomoyo_path_info *filename;
        struct tomoyo_group *group;
-       u8 is_group;
 };
 
+/* Structure for holding a number. */
 struct tomoyo_number_union {
        unsigned long values[2];
-       struct tomoyo_group *group;
-       u8 min_type;
-       u8 max_type;
-       u8 is_group;
+       struct tomoyo_group *group; /* Maybe NULL. */
+       /* One of values in "enum tomoyo_value_type". */
+       u8 value_type[2];
 };
 
 /* Structure for "path_group"/"number_group" directive. */
 struct tomoyo_group {
-       struct list_head list;
+       struct tomoyo_shared_acl_head head;
        const struct tomoyo_path_info *group_name;
        struct list_head member_list;
-       atomic_t users;
 };
 
 /* Structure for "path_group" directive. */
@@ -355,130 +461,158 @@ struct tomoyo_number_group {
        struct tomoyo_number_union number;
 };
 
-/*
- * tomoyo_acl_info is a structure which is used for holding
- *
- *  (1) "list" which is linked to the ->acl_info_list of
- *      "struct tomoyo_domain_info"
- *  (2) "is_deleted" is a bool which is true if this domain is marked as
- *      "deleted", false otherwise.
- *  (3) "type" which tells type of the entry.
- *
- * Packing "struct tomoyo_acl_info" allows
- * "struct tomoyo_path_acl" to embed "u16" and "struct tomoyo_path2_acl"
- * "struct tomoyo_path_number_acl" "struct tomoyo_mkdev_acl" to embed
- * "u8" without enlarging their structure size.
- */
+/* Subset of "struct stat". Used by conditional ACL and audit logs. */
+struct tomoyo_mini_stat {
+       uid_t uid;
+       gid_t gid;
+       ino_t ino;
+       mode_t mode;
+       dev_t dev;
+       dev_t rdev;
+};
+
+/* Structure for dumping argv[] and envp[] of "struct linux_binprm". */
+struct tomoyo_page_dump {
+       struct page *page;    /* Previously dumped page. */
+       char *data;           /* Contents of "page". Size is PAGE_SIZE. */
+};
+
+/* Structure for attribute checks in addition to pathname checks. */
+struct tomoyo_obj_info {
+       /*
+        * True if tomoyo_get_attributes() was already called, false otherwise.
+        */
+       bool validate_done;
+       /* True if @stat[] is valid. */
+       bool stat_valid[TOMOYO_MAX_PATH_STAT];
+       /* First pathname. Initialized with { NULL, NULL } if no path. */
+       struct path path1;
+       /* Second pathname. Initialized with { NULL, NULL } if no path. */
+       struct path path2;
+       /*
+        * Information on @path1, @path1's parent directory, @path2, @path2's
+        * parent directory.
+        */
+       struct tomoyo_mini_stat stat[TOMOYO_MAX_PATH_STAT];
+       /*
+        * Content of symbolic link to be created. NULL for operations other
+        * than symlink().
+        */
+       struct tomoyo_path_info *symlink_target;
+};
+
+/* Structure for argv[]. */
+struct tomoyo_argv {
+       unsigned long index;
+       const struct tomoyo_path_info *value;
+       bool is_not;
+};
+
+/* Structure for envp[]. */
+struct tomoyo_envp {
+       const struct tomoyo_path_info *name;
+       const struct tomoyo_path_info *value;
+       bool is_not;
+};
+
+/* Structure for execve() operation. */
+struct tomoyo_execve {
+       struct tomoyo_request_info r;
+       struct tomoyo_obj_info obj;
+       struct linux_binprm *bprm;
+       /* For dumping argv[] and envp[]. */
+       struct tomoyo_page_dump dump;
+       /* For temporary use. */
+       char *tmp; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
+};
+
+/* Structure for entries which follows "struct tomoyo_condition". */
+struct tomoyo_condition_element {
+       /*
+        * Left hand operand. A "struct tomoyo_argv" for TOMOYO_ARGV_ENTRY, a
+        * "struct tomoyo_envp" for TOMOYO_ENVP_ENTRY is attached to the tail
+        * of the array of this struct.
+        */
+       u8 left;
+       /*
+        * Right hand operand. A "struct tomoyo_number_union" for
+        * TOMOYO_NUMBER_UNION, a "struct tomoyo_name_union" for
+        * TOMOYO_NAME_UNION is attached to the tail of the array of this
+        * struct.
+        */
+       u8 right;
+       /* Equation operator. True if equals or overlaps, false otherwise. */
+       bool equals;
+};
+
+/* Structure for optional arguments. */
+struct tomoyo_condition {
+       struct tomoyo_shared_acl_head head;
+       u32 size; /* Memory size allocated for this entry. */
+       u16 condc; /* Number of conditions in this struct. */
+       u16 numbers_count; /* Number of "struct tomoyo_number_union values". */
+       u16 names_count; /* Number of "struct tomoyo_name_union names". */
+       u16 argc; /* Number of "struct tomoyo_argv". */
+       u16 envc; /* Number of "struct tomoyo_envp". */
+       /*
+        * struct tomoyo_condition_element condition[condc];
+        * struct tomoyo_number_union values[numbers_count];
+        * struct tomoyo_name_union names[names_count];
+        * struct tomoyo_argv argv[argc];
+        * struct tomoyo_envp envp[envc];
+        */
+};
+
+/* Common header for individual entries. */
 struct tomoyo_acl_info {
        struct list_head list;
+       struct tomoyo_condition *cond; /* Maybe NULL. */
        bool is_deleted;
-       u8 type; /* = one of values in "enum tomoyo_acl_entry_type_index". */
+       u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */
 } __packed;
 
-/*
- * tomoyo_domain_info is a structure which is used for holding permissions
- * (e.g. "allow_read /lib/libc-2.5.so") given to each domain.
- * It has following fields.
- *
- *  (1) "list" which is linked to tomoyo_domain_list .
- *  (2) "acl_info_list" which is linked to "struct tomoyo_acl_info".
- *  (3) "domainname" which holds the name of the domain.
- *  (4) "profile" which remembers profile number assigned to this domain.
- *  (5) "is_deleted" is a bool which is true if this domain is marked as
- *      "deleted", false otherwise.
- *  (6) "quota_warned" is a bool which is used for suppressing warning message
- *      when learning mode learned too much entries.
- *  (7) "ignore_global_allow_read" is a bool which is true if this domain
- *      should ignore "allow_read" directive in exception policy.
- *  (8) "transition_failed" is a bool which is set to true when this domain was
- *      unable to create a new domain at tomoyo_find_next_domain() because the
- *      name of the domain to be created was too long or it could not allocate
- *      memory. If set to true, more than one process continued execve()
- *      without domain transition.
- *  (9) "users" is an atomic_t that holds how many "struct cred"->security
- *      are referring this "struct tomoyo_domain_info". If is_deleted == true
- *      and users == 0, this struct will be kfree()d upon next garbage
- *      collection.
- *
- * A domain's lifecycle is an analogy of files on / directory.
- * Multiple domains with the same domainname cannot be created (as with
- * creating files with the same filename fails with -EEXIST).
- * If a process reached a domain, that process can reside in that domain after
- * that domain is marked as "deleted" (as with a process can access an already
- * open()ed file after that file was unlink()ed).
- */
+/* Structure for domain information. */
 struct tomoyo_domain_info {
        struct list_head list;
        struct list_head acl_info_list;
        /* Name of this domain. Never NULL.          */
        const struct tomoyo_path_info *domainname;
+       /* Namespace for this domain. Never NULL. */
+       struct tomoyo_policy_namespace *ns;
        u8 profile;        /* Profile number to use. */
+       u8 group;          /* Group number to use.   */
        bool is_deleted;   /* Delete flag.           */
-       bool quota_warned; /* Quota warnning flag.   */
-       bool ignore_global_allow_read; /* Ignore "allow_read" flag. */
-       bool transition_failed; /* Domain transition failed flag. */
+       bool flags[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
        atomic_t users; /* Number of referring credentials. */
 };
 
 /*
- * tomoyo_path_acl is a structure which is used for holding an
- * entry with one pathname operation (e.g. open(), mkdir()).
- * It has following fields.
- *
- *  (1) "head" which is a "struct tomoyo_acl_info".
- *  (2) "perm" which is a bitmask of permitted operations.
- *  (3) "name" is the pathname.
- *
- * Directives held by this structure are "allow_read/write", "allow_execute",
- * "allow_read", "allow_write", "allow_unlink", "allow_rmdir",
- * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_chroot" and
- * "allow_unmount".
+ * Structure for "file execute", "file read", "file write", "file append",
+ * "file unlink", "file getattr", "file rmdir", "file truncate",
+ * "file symlink", "file chroot" and "file unmount" directive.
  */
 struct tomoyo_path_acl {
        struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */
-       u16 perm;
+       u16 perm; /* Bitmask of values in "enum tomoyo_path_acl_index". */
        struct tomoyo_name_union name;
 };
 
 /*
- * tomoyo_path_number_acl is a structure which is used for holding an
- * entry with one pathname and one number operation.
- * It has following fields.
- *
- *  (1) "head" which is a "struct tomoyo_acl_info".
- *  (2) "perm" which is a bitmask of permitted operations.
- *  (3) "name" is the pathname.
- *  (4) "number" is the numeric value.
- *
- * Directives held by this structure are "allow_create", "allow_mkdir",
- * "allow_ioctl", "allow_mkfifo", "allow_mksock", "allow_chmod", "allow_chown"
- * and "allow_chgrp".
- *
+ * Structure for "file create", "file mkdir", "file mkfifo", "file mksock",
+ * "file ioctl", "file chmod", "file chown" and "file chgrp" directive.
  */
 struct tomoyo_path_number_acl {
        struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_NUMBER_ACL */
+       /* Bitmask of values in "enum tomoyo_path_number_acl_index". */
        u8 perm;
        struct tomoyo_name_union name;
        struct tomoyo_number_union number;
 };
 
-/*
- * tomoyo_mkdev_acl is a structure which is used for holding an
- * entry with one pathname and three numbers operation.
- * It has following fields.
- *
- *  (1) "head" which is a "struct tomoyo_acl_info".
- *  (2) "perm" which is a bitmask of permitted operations.
- *  (3) "mode" is the create mode.
- *  (4) "major" is the major number of device node.
- *  (5) "minor" is the minor number of device node.
- *
- * Directives held by this structure are "allow_mkchar", "allow_mkblock".
- *
- */
+/* Structure for "file mkblock" and "file mkchar" directive. */
 struct tomoyo_mkdev_acl {
        struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MKDEV_ACL */
-       u8 perm;
+       u8 perm; /* Bitmask of values in "enum tomoyo_mkdev_acl_index". */
        struct tomoyo_name_union name;
        struct tomoyo_number_union mode;
        struct tomoyo_number_union major;
@@ -486,38 +620,16 @@ struct tomoyo_mkdev_acl {
 };
 
 /*
- * tomoyo_path2_acl is a structure which is used for holding an
- * entry with two pathnames operation (i.e. link(), rename() and pivot_root()).
- * It has following fields.
- *
- *  (1) "head" which is a "struct tomoyo_acl_info".
- *  (2) "perm" which is a bitmask of permitted operations.
- *  (3) "name1" is the source/old pathname.
- *  (4) "name2" is the destination/new pathname.
- *
- * Directives held by this structure are "allow_rename", "allow_link" and
- * "allow_pivot_root".
+ * Structure for "file rename", "file link" and "file pivot_root" directive.
  */
 struct tomoyo_path2_acl {
        struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */
-       u8 perm;
+       u8 perm; /* Bitmask of values in "enum tomoyo_path2_acl_index". */
        struct tomoyo_name_union name1;
        struct tomoyo_name_union name2;
 };
 
-/*
- * tomoyo_mount_acl is a structure which is used for holding an
- * entry for mount operation.
- * It has following fields.
- *
- *  (1) "head" which is a "struct tomoyo_acl_info".
- *  (2) "dev_name" is the device name.
- *  (3) "dir_name" is the mount point.
- *  (4) "fs_type" is the filesystem type.
- *  (5) "flags" is the mount flags.
- *
- * Directive held by this structure is "allow_mount".
- */
+/* Structure for "file mount" directive. */
 struct tomoyo_mount_acl {
        struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */
        struct tomoyo_name_union dev_name;
@@ -526,7 +638,15 @@ struct tomoyo_mount_acl {
        struct tomoyo_number_union flags;
 };
 
-#define TOMOYO_MAX_IO_READ_QUEUE 32
+/* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */
+struct tomoyo_acl_param {
+       char *data;
+       struct list_head *list;
+       struct tomoyo_policy_namespace *ns;
+       bool is_delete;
+};
+
+#define TOMOYO_MAX_IO_READ_QUEUE 64
 
 /*
  * Structure for reading/writing policy via /sys/kernel/security/tomoyo
@@ -538,95 +658,55 @@ struct tomoyo_io_buffer {
        int (*poll) (struct file *file, poll_table *wait);
        /* Exclusive lock for this structure.   */
        struct mutex io_sem;
-       /* Index returned by tomoyo_read_lock(). */
-       int reader_idx;
        char __user *read_user_buf;
-       int read_user_buf_avail;
+       size_t read_user_buf_avail;
        struct {
+               struct list_head *ns;
                struct list_head *domain;
                struct list_head *group;
                struct list_head *acl;
-               int avail;
-               int step;
-               int query_index;
+               size_t avail;
+               unsigned int step;
+               unsigned int query_index;
                u16 index;
+               u16 cond_index;
+               u8 acl_group_index;
+               u8 cond_step;
                u8 bit;
                u8 w_pos;
                bool eof;
                bool print_this_domain_only;
-               bool print_execute_only;
+               bool print_transition_related_only;
+               bool print_cond_part;
                const char *w[TOMOYO_MAX_IO_READ_QUEUE];
        } r;
-       /* The position currently writing to.   */
-       struct tomoyo_domain_info *write_var1;
+       struct {
+               struct tomoyo_policy_namespace *ns;
+               /* The position currently writing to.   */
+               struct tomoyo_domain_info *domain;
+               /* Bytes available for writing.         */
+               size_t avail;
+               bool is_delete;
+       } w;
        /* Buffer for reading.                  */
        char *read_buf;
        /* Size of read buffer.                 */
-       int readbuf_size;
+       size_t readbuf_size;
        /* Buffer for writing.                  */
        char *write_buf;
-       /* Bytes available for writing.         */
-       int write_avail;
        /* Size of write buffer.                */
-       int writebuf_size;
+       size_t writebuf_size;
        /* Type of this interface.              */
-       u8 type;
-};
-
-/*
- * tomoyo_readable_file is a structure which is used for holding
- * "allow_read" entries.
- * It has following fields.
- *
- *  (1) "head" is "struct tomoyo_acl_head".
- *  (2) "filename" is a pathname which is allowed to open(O_RDONLY).
- */
-struct tomoyo_readable_file {
-       struct tomoyo_acl_head head;
-       const struct tomoyo_path_info *filename;
-};
-
-/*
- * tomoyo_no_pattern is a structure which is used for holding
- * "file_pattern" entries.
- * It has following fields.
- *
- *  (1) "head" is "struct tomoyo_acl_head".
- *  (2) "pattern" is a pathname pattern which is used for converting pathnames
- *      to pathname patterns during learning mode.
- */
-struct tomoyo_no_pattern {
-       struct tomoyo_acl_head head;
-       const struct tomoyo_path_info *pattern;
-};
-
-/*
- * tomoyo_no_rewrite is a structure which is used for holding
- * "deny_rewrite" entries.
- * It has following fields.
- *
- *  (1) "head" is "struct tomoyo_acl_head".
- *  (2) "pattern" is a pathname which is by default not permitted to modify
- *      already existing content.
- */
-struct tomoyo_no_rewrite {
-       struct tomoyo_acl_head head;
-       const struct tomoyo_path_info *pattern;
+       enum tomoyo_securityfs_interface_index type;
+       /* Users counter protected by tomoyo_io_buffer_list_lock. */
+       u8 users;
+       /* List for telling GC not to kfree() elements. */
+       struct list_head list;
 };
 
 /*
- * tomoyo_transition_control is a structure which is used for holding
- * "initialize_domain"/"no_initialize_domain"/"keep_domain"/"no_keep_domain"
- * entries.
- * It has following fields.
- *
- *  (1) "head" is "struct tomoyo_acl_head".
- *  (2) "type" is type of this entry.
- *  (3) "is_last_name" is a bool which is true if "domainname" is "the last
- *      component of a domainname", false otherwise.
- *  (4) "domainname" which is "a domainname" or "the last component of a
- *      domainname".
- *  (5) "program" which is a program's pathname.
+ * Structure for "initialize_domain"/"no_initialize_domain"/"keep_domain"/
+ * "no_keep_domain" keyword.
  */
 struct tomoyo_transition_control {
        struct tomoyo_acl_head head;
@@ -637,32 +717,14 @@ struct tomoyo_transition_control {
        const struct tomoyo_path_info *program;    /* Maybe NULL */
 };
 
-/*
- * tomoyo_aggregator is a structure which is used for holding
- * "aggregator" entries.
- * It has following fields.
- *
- *  (1) "head" is "struct tomoyo_acl_head".
- *  (2) "original_name" which is originally requested name.
- *  (3) "aggregated_name" which is name to rewrite.
- */
+/* Structure for "aggregator" keyword. */
 struct tomoyo_aggregator {
        struct tomoyo_acl_head head;
        const struct tomoyo_path_info *original_name;
        const struct tomoyo_path_info *aggregated_name;
 };
 
-/*
- * tomoyo_manager is a structure which is used for holding list of
- * domainnames or programs which are permitted to modify configuration via
- * /sys/kernel/security/tomoyo/ interface.
- * It has following fields.
- *
- *  (1) "head" is "struct tomoyo_acl_head".
- *  (2) "is_domain" is a bool which is true if "manager" is a domainname, false
- *      otherwise.
- *  (3) "manager" is a domainname or a program's pathname.
- */
+/* Structure for policy manager. */
 struct tomoyo_manager {
        struct tomoyo_acl_head head;
        bool is_domain;  /* True if manager is a domainname. */
@@ -677,6 +739,7 @@ struct tomoyo_preference {
        bool permissive_verbose;
 };
 
+/* Structure for /sys/kernel/security/tomnoyo/profile interface. */
 struct tomoyo_profile {
        const struct tomoyo_path_info *comment;
        struct tomoyo_preference *learning;
@@ -685,323 +748,409 @@ struct tomoyo_profile {
        struct tomoyo_preference preference;
        u8 default_config;
        u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX];
+       unsigned int pref[TOMOYO_MAX_PREF];
+};
+
+/* Structure for representing YYYY/MM/DD hh/mm/ss. */
+struct tomoyo_time {
+       u16 year;
+       u8 month;
+       u8 day;
+       u8 hour;
+       u8 min;
+       u8 sec;
+};
+
+/* Structure for policy namespace. */
+struct tomoyo_policy_namespace {
+       /* Profile table. Memory is allocated as needed. */
+       struct tomoyo_profile *profile_ptr[TOMOYO_MAX_PROFILES];
+       /* List of "struct tomoyo_group". */
+       struct list_head group_list[TOMOYO_MAX_GROUP];
+       /* List of policy. */
+       struct list_head policy_list[TOMOYO_MAX_POLICY];
+       /* The global ACL referred by "use_group" keyword. */
+       struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS];
+       /* List for connecting to tomoyo_namespace_list list. */
+       struct list_head namespace_list;
+       /* Profile version. Currently only 20100903 is defined. */
+       unsigned int profile_version;
+       /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
+       const char *name;
 };
 
 /********** Function prototypes. **********/
 
-/* Check whether the given string starts with the given keyword. */
-bool tomoyo_str_starts(char **src, const char *find);
-/* Get tomoyo_realpath() of current process. */
-const char *tomoyo_get_exe(void);
-/* Format string. */
-void tomoyo_normalize_line(unsigned char *buffer);
-/* Print warning or error message on console. */
-void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
-     __attribute__ ((format(printf, 2, 3)));
-/* Check all profiles currently assigned to domains are defined. */
-void tomoyo_check_profile(void);
-/* Open operation for /sys/kernel/security/tomoyo/ interface. */
-int tomoyo_open_control(const u8 type, struct file *file);
-/* Close /sys/kernel/security/tomoyo/ interface. */
-int tomoyo_close_control(struct file *file);
-/* Poll operation for /sys/kernel/security/tomoyo/ interface. */
-int tomoyo_poll_control(struct file *file, poll_table *wait);
-/* Read operation for /sys/kernel/security/tomoyo/ interface. */
-int tomoyo_read_control(struct file *file, char __user *buffer,
-                       const int buffer_len);
-/* Write operation for /sys/kernel/security/tomoyo/ interface. */
-int tomoyo_write_control(struct file *file, const char __user *buffer,
-                        const int buffer_len);
-/* Check whether the domain has too many ACL entries to hold. */
-bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r);
-/* Print out of memory warning message. */
-void tomoyo_warn_oom(const char *function);
-/* Check whether the given name matches the given name_union. */
-const struct tomoyo_path_info *
-tomoyo_compare_name_union(const struct tomoyo_path_info *name,
-                         const struct tomoyo_name_union *ptr);
-/* Check whether the given number matches the given number_union. */
 bool tomoyo_compare_number_union(const unsigned long value,
                                 const struct tomoyo_number_union *ptr);
-int tomoyo_get_mode(const u8 profile, const u8 index);
-void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
-       __attribute__ ((format(printf, 2, 3)));
-/* Check whether the domainname is correct. */
+bool tomoyo_condition(struct tomoyo_request_info *r,
+                     const struct tomoyo_condition *cond);
 bool tomoyo_correct_domain(const unsigned char *domainname);
-/* Check whether the token is correct. */
 bool tomoyo_correct_path(const char *filename);
 bool tomoyo_correct_word(const char *string);
-/* Check whether the token can be a domainname. */
 bool tomoyo_domain_def(const unsigned char *buffer);
-bool tomoyo_parse_name_union(const char *filename,
-                            struct tomoyo_name_union *ptr);
-/* Check whether the given filename matches the given path_group. */
-const struct tomoyo_path_info *
-tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
-                         const struct tomoyo_group *group);
-/* Check whether the given value matches the given number_group. */
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r);
+bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
+                     struct tomoyo_page_dump *dump);
+bool tomoyo_memory_ok(void *ptr);
 bool tomoyo_number_matches_group(const unsigned long min,
                                 const unsigned long max,
                                 const struct tomoyo_group *group);
-/* Check whether the given filename matches the given pattern. */
+bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
+                            struct tomoyo_name_union *ptr);
+bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
+                              struct tomoyo_number_union *ptr);
 bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
                                 const struct tomoyo_path_info *pattern);
-
-bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num);
-/* Tokenize a line. */
-bool tomoyo_tokenize(char *buffer, char *w[], size_t size);
-/* Write domain policy violation warning message to console? */
-bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain);
-/* Fill "struct tomoyo_request_info". */
-int tomoyo_init_request_info(struct tomoyo_request_info *r,
-                            struct tomoyo_domain_info *domain,
-                            const u8 index);
-/* Check permission for mount operation. */
-int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
-                           unsigned long flags, void *data_page);
-/* Create "aggregator" entry in exception policy. */
-int tomoyo_write_aggregator(char *data, const bool is_delete);
-int tomoyo_write_transition_control(char *data, const bool is_delete,
-                                   const u8 type);
-/*
- * Create "allow_read/write", "allow_execute", "allow_read", "allow_write",
- * "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir",
- * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar",
- * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_rename" and
- * "allow_link" entry in domain policy.
- */
-int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
-                     const bool is_delete);
-/* Create "allow_read" entry in exception policy. */
-int tomoyo_write_globally_readable(char *data, const bool is_delete);
-/* Create "allow_mount" entry in domain policy. */
-int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
-                      const bool is_delete);
-/* Create "deny_rewrite" entry in exception policy. */
-int tomoyo_write_no_rewrite(char *data, const bool is_delete);
-/* Create "file_pattern" entry in exception policy. */
-int tomoyo_write_pattern(char *data, const bool is_delete);
-/* Create "path_group"/"number_group" entry in exception policy. */
-int tomoyo_write_group(char *data, const bool is_delete, const u8 type);
-int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
-     __attribute__ ((format(printf, 2, 3)));
-/* Find a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
-/* Find or create a domain by the given name. */
-struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
-                                               const u8 profile);
-struct tomoyo_profile *tomoyo_profile(const u8 profile);
-/*
- * Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
- */
-struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 type);
-
-/* Check mode for specified functionality. */
-unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
-                               const u8 index);
-/* Fill in "struct tomoyo_path_info" members. */
-void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
-/* Run policy loader when /sbin/init starts. */
-void tomoyo_load_policy(const char *filename);
-
-void tomoyo_put_number_union(struct tomoyo_number_union *ptr);
-
-/* Convert binary string to ascii string. */
+bool tomoyo_permstr(const char *string, const char *keyword);
+bool tomoyo_str_starts(char **src, const char *find);
 char *tomoyo_encode(const char *str);
-
-/*
- * Returns realpath(3) of the given pathname except that
- * ignores chroot'ed root and does not follow the final symlink.
- */
-char *tomoyo_realpath_nofollow(const char *pathname);
-/*
- * Returns realpath(3) of the given pathname except that
- * ignores chroot'ed root and the pathname is already solved.
- */
+char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
+                     va_list args);
+char *tomoyo_read_token(struct tomoyo_acl_param *param);
 char *tomoyo_realpath_from_path(struct path *path);
-/* Get patterned pathname. */
-const char *tomoyo_pattern(const struct tomoyo_path_info *filename);
-
-/* Check memory quota. */
-bool tomoyo_memory_ok(void *ptr);
-void *tomoyo_commit_ok(void *data, const unsigned int size);
-
-/*
- * Keep the given name on the RAM.
- * The RAM is shared, so NEVER try to modify or kfree() the returned name.
- */
+char *tomoyo_realpath_nofollow(const char *pathname);
+const char *tomoyo_get_exe(void);
+const char *tomoyo_yesno(const unsigned int value);
+const struct tomoyo_path_info *tomoyo_compare_name_union
+(const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr);
 const struct tomoyo_path_info *tomoyo_get_name(const char *name);
-
-/* Check for memory usage. */
-void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
-
-/* Set memory quota. */
-int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head);
-
-/* Initialize mm related code. */
-void __init tomoyo_mm_init(void);
-int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
-                          const struct tomoyo_path_info *filename);
+const struct tomoyo_path_info *tomoyo_path_matches_group
+(const struct tomoyo_path_info *pathname, const struct tomoyo_group *group);
 int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
                                 struct path *path, const int flag);
-int tomoyo_path_number_perm(const u8 operation, struct path *path,
-                           unsigned long number);
+int tomoyo_close_control(struct tomoyo_io_buffer *head);
+int tomoyo_find_next_domain(struct linux_binprm *bprm);
+int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
+                   const u8 index);
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+                            struct tomoyo_domain_info *domain,
+                            const u8 index);
 int tomoyo_mkdev_perm(const u8 operation, struct path *path,
                      const unsigned int mode, unsigned int dev);
-int tomoyo_path_perm(const u8 operation, struct path *path);
+int tomoyo_mount_permission(char *dev_name, struct path *path,
+                           const char *type, unsigned long flags,
+                           void *data_page);
+int tomoyo_open_control(const u8 type, struct file *file);
 int tomoyo_path2_perm(const u8 operation, struct path *path1,
                      struct path *path2);
-int tomoyo_find_next_domain(struct linux_binprm *bprm);
-
-void tomoyo_print_ulong(char *buffer, const int buffer_len,
-                       const unsigned long value, const u8 type);
-
-/* Drop refcount on tomoyo_name_union. */
-void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
-
-/* Run garbage collector. */
-void tomoyo_run_gc(void);
-
-void tomoyo_memory_free(void *ptr);
-
+int tomoyo_path_number_perm(const u8 operation, struct path *path,
+                           unsigned long number);
+int tomoyo_path_perm(const u8 operation, struct path *path,
+                    const char *target);
+int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
+                          const struct tomoyo_path_info *filename);
+int tomoyo_poll_control(struct file *file, poll_table *wait);
+int tomoyo_poll_log(struct file *file, poll_table *wait);
+int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+       __printf(2, 3);
 int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
-                        bool is_delete, struct tomoyo_domain_info *domain,
-                        bool (*check_duplicate) (const struct tomoyo_acl_info
-                                                 *,
-                                                 const struct tomoyo_acl_info
-                                                 *),
-                        bool (*merge_duplicate) (struct tomoyo_acl_info *,
-                                                 struct tomoyo_acl_info *,
-                                                 const bool));
+                        struct tomoyo_acl_param *param,
+                        bool (*check_duplicate)
+                        (const struct tomoyo_acl_info *,
+                         const struct tomoyo_acl_info *),
+                        bool (*merge_duplicate)
+                        (struct tomoyo_acl_info *, struct tomoyo_acl_info *,
+                         const bool));
 int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
-                        bool is_delete, struct list_head *list,
-                        bool (*check_duplicate) (const struct tomoyo_acl_head
-                                                 *,
-                                                 const struct tomoyo_acl_head
-                                                 *));
+                        struct tomoyo_acl_param *param,
+                        bool (*check_duplicate)
+                        (const struct tomoyo_acl_head *,
+                         const struct tomoyo_acl_head *));
+int tomoyo_write_aggregator(struct tomoyo_acl_param *param);
+int tomoyo_write_file(struct tomoyo_acl_param *param);
+int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type);
+int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
+                                   const u8 type);
+ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
+                           const int buffer_len);
+ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
+                            const char __user *buffer, const int buffer_len);
+struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param);
+struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
+                                               const bool transit);
+struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
+struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
+                                     const u8 idx);
+struct tomoyo_policy_namespace *tomoyo_assign_namespace
+(const char *domainname);
+struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
+                                     const u8 profile);
+unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
+                               const u8 index);
+u8 tomoyo_parse_ulong(unsigned long *result, char **str);
+void *tomoyo_commit_ok(void *data, const unsigned int size);
+void __init tomoyo_load_builtin_policy(void);
+void __init tomoyo_mm_init(void);
 void tomoyo_check_acl(struct tomoyo_request_info *r,
                      bool (*check_entry) (struct tomoyo_request_info *,
                                           const struct tomoyo_acl_info *));
+void tomoyo_check_profile(void);
+void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp);
+void tomoyo_del_condition(struct list_head *element);
+void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
+void tomoyo_get_attributes(struct tomoyo_obj_info *obj);
+void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns);
+void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
+        __printf(2, 3);
+void tomoyo_load_policy(const char *filename);
+void tomoyo_memory_free(void *ptr);
+void tomoyo_normalize_line(unsigned char *buffer);
+void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register);
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+                       const unsigned long value, const u8 type);
+void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr);
+void tomoyo_read_log(struct tomoyo_io_buffer *head);
+void tomoyo_update_stat(const u8 index);
+void tomoyo_warn_oom(const char *function);
+void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
+       __printf(2, 3);
+void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
+                      va_list args);
 
 /********** External variable definitions. **********/
 
-/* Lock for GC. */
-extern struct srcu_struct tomoyo_ss;
-
-/* The list for "struct tomoyo_domain_info". */
+extern bool tomoyo_policy_loaded;
+extern const char * const tomoyo_condition_keyword
+[TOMOYO_MAX_CONDITION_KEYWORD];
+extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
+extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+                                             + TOMOYO_MAX_MAC_CATEGORY_INDEX];
+extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE];
+extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
+extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX];
+extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION];
+extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION];
+extern const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION];
+extern struct list_head tomoyo_condition_list;
 extern struct list_head tomoyo_domain_list;
-
-extern struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
-extern struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
 extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
-
-/* Lock for protecting policy. */
+extern struct list_head tomoyo_namespace_list;
 extern struct mutex tomoyo_policy_lock;
-
-/* Has /sbin/init started? */
-extern bool tomoyo_policy_loaded;
-
-/* The kernel's domain. */
+extern struct srcu_struct tomoyo_ss;
 extern struct tomoyo_domain_info tomoyo_kernel_domain;
-
-extern const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
-extern const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION];
-extern const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION];
-extern const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION];
-
-extern unsigned int tomoyo_quota_for_query;
-extern unsigned int tomoyo_query_memory_size;
+extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
+extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
+extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
 
 /********** Inlined functions. **********/
 
+/**
+ * tomoyo_read_lock - Take lock for protecting policy.
+ *
+ * Returns index number for tomoyo_read_unlock().
+ */
 static inline int tomoyo_read_lock(void)
 {
        return srcu_read_lock(&tomoyo_ss);
 }
 
+/**
+ * tomoyo_read_unlock - Release lock for protecting policy.
+ *
+ * @idx: Index number returned by tomoyo_read_lock().
+ *
+ * Returns nothing.
+ */
 static inline void tomoyo_read_unlock(int idx)
 {
        srcu_read_unlock(&tomoyo_ss, idx);
 }
 
-/* strcmp() for "struct tomoyo_path_info" structure. */
-static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
-                                 const struct tomoyo_path_info *b)
+/**
+ * tomoyo_sys_getppid - Copy of getppid().
+ *
+ * Returns parent process's PID.
+ *
+ * Alpha does not have getppid() defined. To be able to build this module on
+ * Alpha, I have to copy getppid() from kernel/timer.c.
+ */
+static inline pid_t tomoyo_sys_getppid(void)
 {
-       return a->hash != b->hash || strcmp(a->name, b->name);
+       pid_t pid;
+       rcu_read_lock();
+       pid = task_tgid_vnr(current->real_parent);
+       rcu_read_unlock();
+       return pid;
 }
 
 /**
- * tomoyo_valid - Check whether the character is a valid char.
+ * tomoyo_sys_getpid - Copy of getpid().
  *
- * @c: The character to check.
+ * Returns current thread's PID.
  *
- * Returns true if @c is a valid character, false otherwise.
+ * Alpha does not have getpid() defined. To be able to build this module on
+ * Alpha, I have to copy getpid() from kernel/timer.c.
  */
-static inline bool tomoyo_valid(const unsigned char c)
+static inline pid_t tomoyo_sys_getpid(void)
 {
-       return c > ' ' && c < 127;
+       return task_tgid_vnr(current);
 }
 
 /**
- * tomoyo_invalid - Check whether the character is an invalid char.
+ * tomoyo_pathcmp - strcmp() for "struct tomoyo_path_info" structure.
  *
- * @c: The character to check.
+ * @a: Pointer to "struct tomoyo_path_info".
+ * @b: Pointer to "struct tomoyo_path_info".
  *
- * Returns true if @c is an invalid character, false otherwise.
+ * Returns true if @a == @b, false otherwise.
  */
-static inline bool tomoyo_invalid(const unsigned char c)
+static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a,
+                                 const struct tomoyo_path_info *b)
 {
-       return c && (c <= ' ' || c >= 127);
+       return a->hash != b->hash || strcmp(a->name, b->name);
 }
 
+/**
+ * tomoyo_put_name - Drop reference on "struct tomoyo_name".
+ *
+ * @name: Pointer to "struct tomoyo_path_info". Maybe NULL.
+ *
+ * Returns nothing.
+ */
 static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
 {
        if (name) {
                struct tomoyo_name *ptr =
                        container_of(name, typeof(*ptr), entry);
-               atomic_dec(&ptr->users);
+               atomic_dec(&ptr->head.users);
        }
 }
 
+/**
+ * tomoyo_put_condition - Drop reference on "struct tomoyo_condition".
+ *
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
+ *
+ * Returns nothing.
+ */
+static inline void tomoyo_put_condition(struct tomoyo_condition *cond)
+{
+       if (cond)
+               atomic_dec(&cond->head.users);
+}
+
+/**
+ * tomoyo_put_group - Drop reference on "struct tomoyo_group".
+ *
+ * @group: Pointer to "struct tomoyo_group". Maybe NULL.
+ *
+ * Returns nothing.
+ */
 static inline void tomoyo_put_group(struct tomoyo_group *group)
 {
        if (group)
-               atomic_dec(&group->users);
+               atomic_dec(&group->head.users);
 }
 
+/**
+ * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread.
+ *
+ * Returns pointer to "struct tomoyo_domain_info" for current thread.
+ */
 static inline struct tomoyo_domain_info *tomoyo_domain(void)
 {
        return current_cred()->security;
 }
 
+/**
+ * tomoyo_real_domain - Get "struct tomoyo_domain_info" for specified thread.
+ *
+ * @task: Pointer to "struct task_struct".
+ *
+ * Returns pointer to "struct tomoyo_security" for specified thread.
+ */
 static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
                                                            *task)
 {
        return task_cred_xxx(task, security);
 }
 
-static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *p1,
-                                          const struct tomoyo_acl_info *p2)
+/**
+ * tomoyo_same_name_union - Check for duplicated "struct tomoyo_name_union" entry.
+ *
+ * @a: Pointer to "struct tomoyo_name_union".
+ * @b: Pointer to "struct tomoyo_name_union".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_same_name_union
+(const struct tomoyo_name_union *a, const struct tomoyo_name_union *b)
 {
-       return p1->type == p2->type;
+       return a->filename == b->filename && a->group == b->group;
 }
 
-static inline bool tomoyo_same_name_union
-(const struct tomoyo_name_union *p1, const struct tomoyo_name_union *p2)
+/**
+ * tomoyo_same_number_union - Check for duplicated "struct tomoyo_number_union" entry.
+ *
+ * @a: Pointer to "struct tomoyo_number_union".
+ * @b: Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_same_number_union
+(const struct tomoyo_number_union *a, const struct tomoyo_number_union *b)
 {
-       return p1->filename == p2->filename && p1->group == p2->group &&
-               p1->is_group == p2->is_group;
+       return a->values[0] == b->values[0] && a->values[1] == b->values[1] &&
+               a->group == b->group && a->value_type[0] == b->value_type[0] &&
+               a->value_type[1] == b->value_type[1];
 }
 
-static inline bool tomoyo_same_number_union
-(const struct tomoyo_number_union *p1, const struct tomoyo_number_union *p2)
+/**
+ * tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread.
+ *
+ * Returns pointer to "struct tomoyo_policy_namespace" for current thread.
+ */
+static inline struct tomoyo_policy_namespace *tomoyo_current_namespace(void)
+{
+       return tomoyo_domain()->ns;
+}
+
+#if defined(CONFIG_SLOB)
+
+/**
+ * tomoyo_round2 - Round up to power of 2 for calculating memory usage.
+ *
+ * @size: Size to be rounded up.
+ *
+ * Returns @size.
+ *
+ * Since SLOB does not round up, this function simply returns @size.
+ */
+static inline int tomoyo_round2(size_t size)
+{
+       return size;
+}
+
+#else
+
+/**
+ * tomoyo_round2 - Round up to power of 2 for calculating memory usage.
+ *
+ * @size: Size to be rounded up.
+ *
+ * Returns rounded size.
+ *
+ * Strictly speaking, SLAB may be able to allocate (e.g.) 96 bytes instead of
+ * (e.g.) 128 bytes.
+ */
+static inline int tomoyo_round2(size_t size)
 {
-       return p1->values[0] == p2->values[0] && p1->values[1] == p2->values[1]
-               && p1->group == p2->group && p1->min_type == p2->min_type &&
-               p1->max_type == p2->max_type && p1->is_group == p2->is_group;
+#if PAGE_SIZE == 4096
+       size_t bsize = 32;
+#else
+       size_t bsize = 64;
+#endif
+       if (!size)
+               return 0;
+       while (size > bsize)
+               bsize <<= 1;
+       return bsize;
 }
 
+#endif
+
 /**
  * list_for_each_cookie - iterate over a list with cookie.
  * @pos:        the &struct list_head to use as a loop cursor.
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c
new file mode 100644 (file)
index 0000000..8a05f71
--- /dev/null
@@ -0,0 +1,1035 @@
+/*
+ * security/tomoyo/condition.c
+ *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
+ */
+
+#include "common.h"
+#include <linux/slab.h>
+
+/* List of "struct tomoyo_condition". */
+LIST_HEAD(tomoyo_condition_list);
+
+/**
+ * tomoyo_argv - Check argv[] in "struct linux_binbrm".
+ *
+ * @index:   Index number of @arg_ptr.
+ * @arg_ptr: Contents of argv[@index].
+ * @argc:    Length of @argv.
+ * @argv:    Pointer to "struct tomoyo_argv".
+ * @checked: Set to true if @argv[@index] was found.
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_argv(const unsigned int index, const char *arg_ptr,
+                       const int argc, const struct tomoyo_argv *argv,
+                       u8 *checked)
+{
+       int i;
+       struct tomoyo_path_info arg;
+       arg.name = arg_ptr;
+       for (i = 0; i < argc; argv++, checked++, i++) {
+               bool result;
+               if (index != argv->index)
+                       continue;
+               *checked = 1;
+               tomoyo_fill_path_info(&arg);
+               result = tomoyo_path_matches_pattern(&arg, argv->value);
+               if (argv->is_not)
+                       result = !result;
+               if (!result)
+                       return false;
+       }
+       return true;
+}
+
+/**
+ * tomoyo_envp - Check envp[] in "struct linux_binbrm".
+ *
+ * @env_name:  The name of environment variable.
+ * @env_value: The value of environment variable.
+ * @envc:      Length of @envp.
+ * @envp:      Pointer to "struct tomoyo_envp".
+ * @checked:   Set to true if @envp[@env_name] was found.
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_envp(const char *env_name, const char *env_value,
+                       const int envc, const struct tomoyo_envp *envp,
+                       u8 *checked)
+{
+       int i;
+       struct tomoyo_path_info name;
+       struct tomoyo_path_info value;
+       name.name = env_name;
+       tomoyo_fill_path_info(&name);
+       value.name = env_value;
+       tomoyo_fill_path_info(&value);
+       for (i = 0; i < envc; envp++, checked++, i++) {
+               bool result;
+               if (!tomoyo_path_matches_pattern(&name, envp->name))
+                       continue;
+               *checked = 1;
+               if (envp->value) {
+                       result = tomoyo_path_matches_pattern(&value,
+                                                            envp->value);
+                       if (envp->is_not)
+                               result = !result;
+               } else {
+                       result = true;
+                       if (!envp->is_not)
+                               result = !result;
+               }
+               if (!result)
+                       return false;
+       }
+       return true;
+}
+
+/**
+ * tomoyo_scan_bprm - Scan "struct linux_binprm".
+ *
+ * @ee:   Pointer to "struct tomoyo_execve".
+ * @argc: Length of @argc.
+ * @argv: Pointer to "struct tomoyo_argv".
+ * @envc: Length of @envp.
+ * @envp: Poiner to "struct tomoyo_envp".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
+                            const u16 argc, const struct tomoyo_argv *argv,
+                            const u16 envc, const struct tomoyo_envp *envp)
+{
+       struct linux_binprm *bprm = ee->bprm;
+       struct tomoyo_page_dump *dump = &ee->dump;
+       char *arg_ptr = ee->tmp;
+       int arg_len = 0;
+       unsigned long pos = bprm->p;
+       int offset = pos % PAGE_SIZE;
+       int argv_count = bprm->argc;
+       int envp_count = bprm->envc;
+       bool result = true;
+       u8 local_checked[32];
+       u8 *checked;
+       if (argc + envc <= sizeof(local_checked)) {
+               checked = local_checked;
+               memset(local_checked, 0, sizeof(local_checked));
+       } else {
+               checked = kzalloc(argc + envc, GFP_NOFS);
+               if (!checked)
+                       return false;
+       }
+       while (argv_count || envp_count) {
+               if (!tomoyo_dump_page(bprm, pos, dump)) {
+                       result = false;
+                       goto out;
+               }
+               pos += PAGE_SIZE - offset;
+               while (offset < PAGE_SIZE) {
+                       /* Read. */
+                       const char *kaddr = dump->data;
+                       const unsigned char c = kaddr[offset++];
+                       if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
+                               if (c == '\\') {
+                                       arg_ptr[arg_len++] = '\\';
+                                       arg_ptr[arg_len++] = '\\';
+                               } else if (c > ' ' && c < 127) {
+                                       arg_ptr[arg_len++] = c;
+                               } else {
+                                       arg_ptr[arg_len++] = '\\';
+                                       arg_ptr[arg_len++] = (c >> 6) + '0';
+                                       arg_ptr[arg_len++] =
+                                               ((c >> 3) & 7) + '0';
+                                       arg_ptr[arg_len++] = (c & 7) + '0';
+                               }
+                       } else {
+                               arg_ptr[arg_len] = '\0';
+                       }
+                       if (c)
+                               continue;
+                       /* Check. */
+                       if (argv_count) {
+                               if (!tomoyo_argv(bprm->argc - argv_count,
+                                                arg_ptr, argc, argv,
+                                                checked)) {
+                                       result = false;
+                                       break;
+                               }
+                               argv_count--;
+                       } else if (envp_count) {
+                               char *cp = strchr(arg_ptr, '=');
+                               if (cp) {
+                                       *cp = '\0';
+                                       if (!tomoyo_envp(arg_ptr, cp + 1,
+                                                        envc, envp,
+                                                        checked + argc)) {
+                                               result = false;
+                                               break;
+                                       }
+                               }
+                               envp_count--;
+                       } else {
+                               break;
+                       }
+                       arg_len = 0;
+               }
+               offset = 0;
+               if (!result)
+                       break;
+       }
+out:
+       if (result) {
+               int i;
+               /* Check not-yet-checked entries. */
+               for (i = 0; i < argc; i++) {
+                       if (checked[i])
+                               continue;
+                       /*
+                        * Return true only if all unchecked indexes in
+                        * bprm->argv[] are not matched.
+                        */
+                       if (argv[i].is_not)
+                               continue;
+                       result = false;
+                       break;
+               }
+               for (i = 0; i < envc; envp++, i++) {
+                       if (checked[argc + i])
+                               continue;
+                       /*
+                        * Return true only if all unchecked environ variables
+                        * in bprm->envp[] are either undefined or not matched.
+                        */
+                       if ((!envp->value && !envp->is_not) ||
+                           (envp->value && envp->is_not))
+                               continue;
+                       result = false;
+                       break;
+               }
+       }
+       if (checked != local_checked)
+               kfree(checked);
+       return result;
+}
+
+/**
+ * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition".
+ *
+ * @file:  Pointer to "struct file".
+ * @ptr:   Pointer to "struct tomoyo_name_union".
+ * @match: True if "exec.realpath=", false if "exec.realpath!=".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_scan_exec_realpath(struct file *file,
+                                     const struct tomoyo_name_union *ptr,
+                                     const bool match)
+{
+       bool result;
+       struct tomoyo_path_info exe;
+       if (!file)
+               return false;
+       exe.name = tomoyo_realpath_from_path(&file->f_path);
+       if (!exe.name)
+               return false;
+       tomoyo_fill_path_info(&exe);
+       result = tomoyo_compare_name_union(&exe, ptr);
+       kfree(exe.name);
+       return result == match;
+}
+
+/**
+ * tomoyo_get_dqword - tomoyo_get_name() for a quoted string.
+ *
+ * @start: String to save.
+ *
+ * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ */
+static const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
+{
+       char *cp = start + strlen(start) - 1;
+       if (cp == start || *start++ != '"' || *cp != '"')
+               return NULL;
+       *cp = '\0';
+       if (*start && !tomoyo_correct_word(start))
+               return NULL;
+       return tomoyo_get_name(start);
+}
+
+/**
+ * tomoyo_parse_name_union_quoted - Parse a quoted word.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @ptr:   Pointer to "struct tomoyo_name_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param,
+                                          struct tomoyo_name_union *ptr)
+{
+       char *filename = param->data;
+       if (*filename == '@')
+               return tomoyo_parse_name_union(param, ptr);
+       ptr->filename = tomoyo_get_dqword(filename);
+       return ptr->filename != NULL;
+}
+
+/**
+ * tomoyo_parse_argv - Parse an argv[] condition part.
+ *
+ * @left:  Lefthand value.
+ * @right: Righthand value.
+ * @argv:  Pointer to "struct tomoyo_argv".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_parse_argv(char *left, char *right,
+                             struct tomoyo_argv *argv)
+{
+       if (tomoyo_parse_ulong(&argv->index, &left) !=
+           TOMOYO_VALUE_TYPE_DECIMAL || *left++ != ']' || *left)
+               return false;
+       argv->value = tomoyo_get_dqword(right);
+       return argv->value != NULL;
+}
+
+/**
+ * tomoyo_parse_envp - Parse an envp[] condition part.
+ *
+ * @left:  Lefthand value.
+ * @right: Righthand value.
+ * @envp:  Pointer to "struct tomoyo_envp".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_parse_envp(char *left, char *right,
+                             struct tomoyo_envp *envp)
+{
+       const struct tomoyo_path_info *name;
+       const struct tomoyo_path_info *value;
+       char *cp = left + strlen(left) - 1;
+       if (*cp-- != ']' || *cp != '"')
+               goto out;
+       *cp = '\0';
+       if (!tomoyo_correct_word(left))
+               goto out;
+       name = tomoyo_get_name(left);
+       if (!name)
+               goto out;
+       if (!strcmp(right, "NULL")) {
+               value = NULL;
+       } else {
+               value = tomoyo_get_dqword(right);
+               if (!value) {
+                       tomoyo_put_name(name);
+                       goto out;
+               }
+       }
+       envp->name = name;
+       envp->value = value;
+       return true;
+out:
+       return false;
+}
+
+/**
+ * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
+ *
+ * @a: Pointer to "struct tomoyo_condition".
+ * @b: Pointer to "struct tomoyo_condition".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
+                                        const struct tomoyo_condition *b)
+{
+       return a->size == b->size && a->condc == b->condc &&
+               a->numbers_count == b->numbers_count &&
+               a->names_count == b->names_count &&
+               a->argc == b->argc && a->envc == b->envc &&
+               !memcmp(a + 1, b + 1, a->size - sizeof(*a));
+}
+
+/**
+ * tomoyo_condition_type - Get condition type.
+ *
+ * @word: Keyword string.
+ *
+ * Returns one of values in "enum tomoyo_conditions_index" on success,
+ * TOMOYO_MAX_CONDITION_KEYWORD otherwise.
+ */
+static u8 tomoyo_condition_type(const char *word)
+{
+       u8 i;
+       for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
+               if (!strcmp(word, tomoyo_condition_keyword[i]))
+                       break;
+       }
+       return i;
+}
+
+/* Define this to enable debug mode. */
+/* #define DEBUG_CONDITION */
+
+#ifdef DEBUG_CONDITION
+#define dprintk printk
+#else
+#define dprintk(...) do { } while (0)
+#endif
+
+/**
+ * tomoyo_commit_condition - Commit "struct tomoyo_condition".
+ *
+ * @entry: Pointer to "struct tomoyo_condition".
+ *
+ * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
+ *
+ * This function merges duplicated entries. This function returns NULL if
+ * @entry is not duplicated but memory quota for policy has exceeded.
+ */
+static struct tomoyo_condition *tomoyo_commit_condition
+(struct tomoyo_condition *entry)
+{
+       struct tomoyo_condition *ptr;
+       bool found = false;
+       if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
+               dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
+               ptr = NULL;
+               found = true;
+               goto out;
+       }
+       list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) {
+               if (!tomoyo_same_condition(ptr, entry))
+                       continue;
+               /* Same entry found. Share this entry. */
+               atomic_inc(&ptr->head.users);
+               found = true;
+               break;
+       }
+       if (!found) {
+               if (tomoyo_memory_ok(entry)) {
+                       atomic_set(&entry->head.users, 1);
+                       list_add_rcu(&entry->head.list,
+                                    &tomoyo_condition_list);
+               } else {
+                       found = true;
+                       ptr = NULL;
+               }
+       }
+       mutex_unlock(&tomoyo_policy_lock);
+out:
+       if (found) {
+               tomoyo_del_condition(&entry->head.list);
+               kfree(entry);
+               entry = ptr;
+       }
+       return entry;
+}
+
+/**
+ * tomoyo_get_condition - Parse condition part.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
+ */
+struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
+{
+       struct tomoyo_condition *entry = NULL;
+       struct tomoyo_condition_element *condp = NULL;
+       struct tomoyo_number_union *numbers_p = NULL;
+       struct tomoyo_name_union *names_p = NULL;
+       struct tomoyo_argv *argv = NULL;
+       struct tomoyo_envp *envp = NULL;
+       struct tomoyo_condition e = { };
+       char * const start_of_string = param->data;
+       char * const end_of_string = start_of_string + strlen(start_of_string);
+       char *pos;
+rerun:
+       pos = start_of_string;
+       while (1) {
+               u8 left = -1;
+               u8 right = -1;
+               char *left_word = pos;
+               char *cp;
+               char *right_word;
+               bool is_not;
+               if (!*left_word)
+                       break;
+               /*
+                * Since left-hand condition does not allow use of "path_group"
+                * or "number_group" and environment variable's names do not
+                * accept '=', it is guaranteed that the original line consists
+                * of one or more repetition of $left$operator$right blocks
+                * where "$left is free from '=' and ' '" and "$operator is
+                * either '=' or '!='" and "$right is free from ' '".
+                * Therefore, we can reconstruct the original line at the end
+                * of dry run even if we overwrite $operator with '\0'.
+                */
+               cp = strchr(pos, ' ');
+               if (cp) {
+                       *cp = '\0'; /* Will restore later. */
+                       pos = cp + 1;
+               } else {
+                       pos = "";
+               }
+               right_word = strchr(left_word, '=');
+               if (!right_word || right_word == left_word)
+                       goto out;
+               is_not = *(right_word - 1) == '!';
+               if (is_not)
+                       *(right_word++ - 1) = '\0'; /* Will restore later. */
+               else if (*(right_word + 1) != '=')
+                       *right_word++ = '\0'; /* Will restore later. */
+               else
+                       goto out;
+               dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
+                       is_not ? "!" : "", right_word);
+               if (!strncmp(left_word, "exec.argv[", 10)) {
+                       if (!argv) {
+                               e.argc++;
+                               e.condc++;
+                       } else {
+                               e.argc--;
+                               e.condc--;
+                               left = TOMOYO_ARGV_ENTRY;
+                               argv->is_not = is_not;
+                               if (!tomoyo_parse_argv(left_word + 10,
+                                                      right_word, argv++))
+                                       goto out;
+                       }
+                       goto store_value;
+               }
+               if (!strncmp(left_word, "exec.envp[\"", 11)) {
+                       if (!envp) {
+                               e.envc++;
+                               e.condc++;
+                       } else {
+                               e.envc--;
+                               e.condc--;
+                               left = TOMOYO_ENVP_ENTRY;
+                               envp->is_not = is_not;
+                               if (!tomoyo_parse_envp(left_word + 11,
+                                                      right_word, envp++))
+                                       goto out;
+                       }
+                       goto store_value;
+               }
+               left = tomoyo_condition_type(left_word);
+               dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
+                       left);
+               if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
+                       if (!numbers_p) {
+                               e.numbers_count++;
+                       } else {
+                               e.numbers_count--;
+                               left = TOMOYO_NUMBER_UNION;
+                               param->data = left_word;
+                               if (*left_word == '@' ||
+                                   !tomoyo_parse_number_union(param,
+                                                              numbers_p++))
+                                       goto out;
+                       }
+               }
+               if (!condp)
+                       e.condc++;
+               else
+                       e.condc--;
+               if (left == TOMOYO_EXEC_REALPATH ||
+                   left == TOMOYO_SYMLINK_TARGET) {
+                       if (!names_p) {
+                               e.names_count++;
+                       } else {
+                               e.names_count--;
+                               right = TOMOYO_NAME_UNION;
+                               param->data = right_word;
+                               if (!tomoyo_parse_name_union_quoted(param,
+                                                                   names_p++))
+                                       goto out;
+                       }
+                       goto store_value;
+               }
+               right = tomoyo_condition_type(right_word);
+               if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
+                       if (!numbers_p) {
+                               e.numbers_count++;
+                       } else {
+                               e.numbers_count--;
+                               right = TOMOYO_NUMBER_UNION;
+                               param->data = right_word;
+                               if (!tomoyo_parse_number_union(param,
+                                                              numbers_p++))
+                                       goto out;
+                       }
+               }
+store_value:
+               if (!condp) {
+                       dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
+                               "match=%u\n", __LINE__, left, right, !is_not);
+                       continue;
+               }
+               condp->left = left;
+               condp->right = right;
+               condp->equals = !is_not;
+               dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
+                       __LINE__, condp->left, condp->right,
+                       condp->equals);
+               condp++;
+       }
+       dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
+               __LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
+               e.envc);
+       if (entry) {
+               BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
+                      e.condc);
+               return tomoyo_commit_condition(entry);
+       }
+       e.size = sizeof(*entry)
+               + e.condc * sizeof(struct tomoyo_condition_element)
+               + e.numbers_count * sizeof(struct tomoyo_number_union)
+               + e.names_count * sizeof(struct tomoyo_name_union)
+               + e.argc * sizeof(struct tomoyo_argv)
+               + e.envc * sizeof(struct tomoyo_envp);
+       entry = kzalloc(e.size, GFP_NOFS);
+       if (!entry)
+               return NULL;
+       *entry = e;
+       condp = (struct tomoyo_condition_element *) (entry + 1);
+       numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
+       names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
+       argv = (struct tomoyo_argv *) (names_p + e.names_count);
+       envp = (struct tomoyo_envp *) (argv + e.argc);
+       {
+               bool flag = false;
+               for (pos = start_of_string; pos < end_of_string; pos++) {
+                       if (*pos)
+                               continue;
+                       if (flag) /* Restore " ". */
+                               *pos = ' ';
+                       else if (*(pos + 1) == '=') /* Restore "!=". */
+                               *pos = '!';
+                       else /* Restore "=". */
+                               *pos = '=';
+                       flag = !flag;
+               }
+       }
+       goto rerun;
+out:
+       dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
+       if (entry) {
+               tomoyo_del_condition(&entry->head.list);
+               kfree(entry);
+       }
+       return NULL;
+}
+
+/**
+ * tomoyo_get_attributes - Revalidate "struct inode".
+ *
+ * @obj: Pointer to "struct tomoyo_obj_info".
+ *
+ * Returns nothing.
+ */
+void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
+{
+       u8 i;
+       struct dentry *dentry = NULL;
+
+       for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
+               struct inode *inode;
+               switch (i) {
+               case TOMOYO_PATH1:
+                       dentry = obj->path1.dentry;
+                       if (!dentry)
+                               continue;
+                       break;
+               case TOMOYO_PATH2:
+                       dentry = obj->path2.dentry;
+                       if (!dentry)
+                               continue;
+                       break;
+               default:
+                       if (!dentry)
+                               continue;
+                       dentry = dget_parent(dentry);
+                       break;
+               }
+               inode = dentry->d_inode;
+               if (inode) {
+                       struct tomoyo_mini_stat *stat = &obj->stat[i];
+                       stat->uid  = inode->i_uid;
+                       stat->gid  = inode->i_gid;
+                       stat->ino  = inode->i_ino;
+                       stat->mode = inode->i_mode;
+                       stat->dev  = inode->i_sb->s_dev;
+                       stat->rdev = inode->i_rdev;
+                       obj->stat_valid[i] = true;
+               }
+               if (i & 1) /* i == TOMOYO_PATH1_PARENT ||
+                             i == TOMOYO_PATH2_PARENT */
+                       dput(dentry);
+       }
+}
+
+/**
+ * tomoyo_condition - Check condition part.
+ *
+ * @r:    Pointer to "struct tomoyo_request_info".
+ * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_condition(struct tomoyo_request_info *r,
+                     const struct tomoyo_condition *cond)
+{
+       u32 i;
+       unsigned long min_v[2] = { 0, 0 };
+       unsigned long max_v[2] = { 0, 0 };
+       const struct tomoyo_condition_element *condp;
+       const struct tomoyo_number_union *numbers_p;
+       const struct tomoyo_name_union *names_p;
+       const struct tomoyo_argv *argv;
+       const struct tomoyo_envp *envp;
+       struct tomoyo_obj_info *obj;
+       u16 condc;
+       u16 argc;
+       u16 envc;
+       struct linux_binprm *bprm = NULL;
+       if (!cond)
+               return true;
+       condc = cond->condc;
+       argc = cond->argc;
+       envc = cond->envc;
+       obj = r->obj;
+       if (r->ee)
+               bprm = r->ee->bprm;
+       if (!bprm && (argc || envc))
+               return false;
+       condp = (struct tomoyo_condition_element *) (cond + 1);
+       numbers_p = (const struct tomoyo_number_union *) (condp + condc);
+       names_p = (const struct tomoyo_name_union *)
+               (numbers_p + cond->numbers_count);
+       argv = (const struct tomoyo_argv *) (names_p + cond->names_count);
+       envp = (const struct tomoyo_envp *) (argv + argc);
+       for (i = 0; i < condc; i++) {
+               const bool match = condp->equals;
+               const u8 left = condp->left;
+               const u8 right = condp->right;
+               bool is_bitop[2] = { false, false };
+               u8 j;
+               condp++;
+               /* Check argv[] and envp[] later. */
+               if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY)
+                       continue;
+               /* Check string expressions. */
+               if (right == TOMOYO_NAME_UNION) {
+                       const struct tomoyo_name_union *ptr = names_p++;
+                       switch (left) {
+                               struct tomoyo_path_info *symlink;
+                               struct tomoyo_execve *ee;
+                               struct file *file;
+                       case TOMOYO_SYMLINK_TARGET:
+                               symlink = obj ? obj->symlink_target : NULL;
+                               if (!symlink ||
+                                   !tomoyo_compare_name_union(symlink, ptr)
+                                   == match)
+                                       goto out;
+                               break;
+                       case TOMOYO_EXEC_REALPATH:
+                               ee = r->ee;
+                               file = ee ? ee->bprm->file : NULL;
+                               if (!tomoyo_scan_exec_realpath(file, ptr,
+                                                              match))
+                                       goto out;
+                               break;
+                       }
+                       continue;
+               }
+               /* Check numeric or bit-op expressions. */
+               for (j = 0; j < 2; j++) {
+                       const u8 index = j ? right : left;
+                       unsigned long value = 0;
+                       switch (index) {
+                       case TOMOYO_TASK_UID:
+                               value = current_uid();
+                               break;
+                       case TOMOYO_TASK_EUID:
+                               value = current_euid();
+                               break;
+                       case TOMOYO_TASK_SUID:
+                               value = current_suid();
+                               break;
+                       case TOMOYO_TASK_FSUID:
+                               value = current_fsuid();
+                               break;
+                       case TOMOYO_TASK_GID:
+                               value = current_gid();
+                               break;
+                       case TOMOYO_TASK_EGID:
+                               value = current_egid();
+                               break;
+                       case TOMOYO_TASK_SGID:
+                               value = current_sgid();
+                               break;
+                       case TOMOYO_TASK_FSGID:
+                               value = current_fsgid();
+                               break;
+                       case TOMOYO_TASK_PID:
+                               value = tomoyo_sys_getpid();
+                               break;
+                       case TOMOYO_TASK_PPID:
+                               value = tomoyo_sys_getppid();
+                               break;
+                       case TOMOYO_TYPE_IS_SOCKET:
+                               value = S_IFSOCK;
+                               break;
+                       case TOMOYO_TYPE_IS_SYMLINK:
+                               value = S_IFLNK;
+                               break;
+                       case TOMOYO_TYPE_IS_FILE:
+                               value = S_IFREG;
+                               break;
+                       case TOMOYO_TYPE_IS_BLOCK_DEV:
+                               value = S_IFBLK;
+                               break;
+                       case TOMOYO_TYPE_IS_DIRECTORY:
+                               value = S_IFDIR;
+                               break;
+                       case TOMOYO_TYPE_IS_CHAR_DEV:
+                               value = S_IFCHR;
+                               break;
+                       case TOMOYO_TYPE_IS_FIFO:
+                               value = S_IFIFO;
+                               break;
+                       case TOMOYO_MODE_SETUID:
+                               value = S_ISUID;
+                               break;
+                       case TOMOYO_MODE_SETGID:
+                               value = S_ISGID;
+                               break;
+                       case TOMOYO_MODE_STICKY:
+                               value = S_ISVTX;
+                               break;
+                       case TOMOYO_MODE_OWNER_READ:
+                               value = S_IRUSR;
+                               break;
+                       case TOMOYO_MODE_OWNER_WRITE:
+                               value = S_IWUSR;
+                               break;
+                       case TOMOYO_MODE_OWNER_EXECUTE:
+                               value = S_IXUSR;
+                               break;
+                       case TOMOYO_MODE_GROUP_READ:
+                               value = S_IRGRP;
+                               break;
+                       case TOMOYO_MODE_GROUP_WRITE:
+                               value = S_IWGRP;
+                               break;
+                       case TOMOYO_MODE_GROUP_EXECUTE:
+                               value = S_IXGRP;
+                               break;
+                       case TOMOYO_MODE_OTHERS_READ:
+                               value = S_IROTH;
+                               break;
+                       case TOMOYO_MODE_OTHERS_WRITE:
+                               value = S_IWOTH;
+                               break;
+                       case TOMOYO_MODE_OTHERS_EXECUTE:
+                               value = S_IXOTH;
+                               break;
+                       case TOMOYO_EXEC_ARGC:
+                               if (!bprm)
+                                       goto out;
+                               value = bprm->argc;
+                               break;
+                       case TOMOYO_EXEC_ENVC:
+                               if (!bprm)
+                                       goto out;
+                               value = bprm->envc;
+                               break;
+                       case TOMOYO_NUMBER_UNION:
+                               /* Fetch values later. */
+                               break;
+                       default:
+                               if (!obj)
+                                       goto out;
+                               if (!obj->validate_done) {
+                                       tomoyo_get_attributes(obj);
+                                       obj->validate_done = true;
+                               }
+                               {
+                                       u8 stat_index;
+                                       struct tomoyo_mini_stat *stat;
+                                       switch (index) {
+                                       case TOMOYO_PATH1_UID:
+                                       case TOMOYO_PATH1_GID:
+                                       case TOMOYO_PATH1_INO:
+                                       case TOMOYO_PATH1_MAJOR:
+                                       case TOMOYO_PATH1_MINOR:
+                                       case TOMOYO_PATH1_TYPE:
+                                       case TOMOYO_PATH1_DEV_MAJOR:
+                                       case TOMOYO_PATH1_DEV_MINOR:
+                                       case TOMOYO_PATH1_PERM:
+                                               stat_index = TOMOYO_PATH1;
+                                               break;
+                                       case TOMOYO_PATH2_UID:
+                                       case TOMOYO_PATH2_GID:
+                                       case TOMOYO_PATH2_INO:
+                                       case TOMOYO_PATH2_MAJOR:
+                                       case TOMOYO_PATH2_MINOR:
+                                       case TOMOYO_PATH2_TYPE:
+                                       case TOMOYO_PATH2_DEV_MAJOR:
+                                       case TOMOYO_PATH2_DEV_MINOR:
+                                       case TOMOYO_PATH2_PERM:
+                                               stat_index = TOMOYO_PATH2;
+                                               break;
+                                       case TOMOYO_PATH1_PARENT_UID:
+                                       case TOMOYO_PATH1_PARENT_GID:
+                                       case TOMOYO_PATH1_PARENT_INO:
+                                       case TOMOYO_PATH1_PARENT_PERM:
+                                               stat_index =
+                                                       TOMOYO_PATH1_PARENT;
+                                               break;
+                                       case TOMOYO_PATH2_PARENT_UID:
+                                       case TOMOYO_PATH2_PARENT_GID:
+                                       case TOMOYO_PATH2_PARENT_INO:
+                                       case TOMOYO_PATH2_PARENT_PERM:
+                                               stat_index =
+                                                       TOMOYO_PATH2_PARENT;
+                                               break;
+                                       default:
+                                               goto out;
+                                       }
+                                       if (!obj->stat_valid[stat_index])
+                                               goto out;
+                                       stat = &obj->stat[stat_index];
+                                       switch (index) {
+                                       case TOMOYO_PATH1_UID:
+                                       case TOMOYO_PATH2_UID:
+                                       case TOMOYO_PATH1_PARENT_UID:
+                                       case TOMOYO_PATH2_PARENT_UID:
+                                               value = stat->uid;
+                                               break;
+                                       case TOMOYO_PATH1_GID:
+                                       case TOMOYO_PATH2_GID:
+                                       case TOMOYO_PATH1_PARENT_GID:
+                                       case TOMOYO_PATH2_PARENT_GID:
+                                               value = stat->gid;
+                                               break;
+                                       case TOMOYO_PATH1_INO:
+                                       case TOMOYO_PATH2_INO:
+                                       case TOMOYO_PATH1_PARENT_INO:
+                                       case TOMOYO_PATH2_PARENT_INO:
+                                               value = stat->ino;
+                                               break;
+                                       case TOMOYO_PATH1_MAJOR:
+                                       case TOMOYO_PATH2_MAJOR:
+                                               value = MAJOR(stat->dev);
+                                               break;
+                                       case TOMOYO_PATH1_MINOR:
+                                       case TOMOYO_PATH2_MINOR:
+                                               value = MINOR(stat->dev);
+                                               break;
+                                       case TOMOYO_PATH1_TYPE:
+                                       case TOMOYO_PATH2_TYPE:
+                                               value = stat->mode & S_IFMT;
+                                               break;
+                                       case TOMOYO_PATH1_DEV_MAJOR:
+                                       case TOMOYO_PATH2_DEV_MAJOR:
+                                               value = MAJOR(stat->rdev);
+                                               break;
+                                       case TOMOYO_PATH1_DEV_MINOR:
+                                       case TOMOYO_PATH2_DEV_MINOR:
+                                               value = MINOR(stat->rdev);
+                                               break;
+                                       case TOMOYO_PATH1_PERM:
+                                       case TOMOYO_PATH2_PERM:
+                                       case TOMOYO_PATH1_PARENT_PERM:
+                                       case TOMOYO_PATH2_PARENT_PERM:
+                                               value = stat->mode & S_IALLUGO;
+                                               break;
+                                       }
+                               }
+                               break;
+                       }
+                       max_v[j] = value;
+                       min_v[j] = value;
+                       switch (index) {
+                       case TOMOYO_MODE_SETUID:
+                       case TOMOYO_MODE_SETGID:
+                       case TOMOYO_MODE_STICKY:
+                       case TOMOYO_MODE_OWNER_READ:
+                       case TOMOYO_MODE_OWNER_WRITE:
+                       case TOMOYO_MODE_OWNER_EXECUTE:
+                       case TOMOYO_MODE_GROUP_READ:
+                       case TOMOYO_MODE_GROUP_WRITE:
+                       case TOMOYO_MODE_GROUP_EXECUTE:
+                       case TOMOYO_MODE_OTHERS_READ:
+                       case TOMOYO_MODE_OTHERS_WRITE:
+                       case TOMOYO_MODE_OTHERS_EXECUTE:
+                               is_bitop[j] = true;
+                       }
+               }
+               if (left == TOMOYO_NUMBER_UNION) {
+                       /* Fetch values now. */
+                       const struct tomoyo_number_union *ptr = numbers_p++;
+                       min_v[0] = ptr->values[0];
+                       max_v[0] = ptr->values[1];
+               }
+               if (right == TOMOYO_NUMBER_UNION) {
+                       /* Fetch values now. */
+                       const struct tomoyo_number_union *ptr = numbers_p++;
+                       if (ptr->group) {
+                               if (tomoyo_number_matches_group(min_v[0],
+                                                               max_v[0],
+                                                               ptr->group)
+                                   == match)
+                                       continue;
+                       } else {
+                               if ((min_v[0] <= ptr->values[1] &&
+                                    max_v[0] >= ptr->values[0]) == match)
+                                       continue;
+                       }
+                       goto out;
+               }
+               /*
+                * Bit operation is valid only when counterpart value
+                * represents permission.
+                */
+               if (is_bitop[0] && is_bitop[1]) {
+                       goto out;
+               } else if (is_bitop[0]) {
+                       switch (right) {
+                       case TOMOYO_PATH1_PERM:
+                       case TOMOYO_PATH1_PARENT_PERM:
+                       case TOMOYO_PATH2_PERM:
+                       case TOMOYO_PATH2_PARENT_PERM:
+                               if (!(max_v[0] & max_v[1]) == !match)
+                                       continue;
+                       }
+                       goto out;
+               } else if (is_bitop[1]) {
+                       switch (left) {
+                       case TOMOYO_PATH1_PERM:
+                       case TOMOYO_PATH1_PARENT_PERM:
+                       case TOMOYO_PATH2_PERM:
+                       case TOMOYO_PATH2_PARENT_PERM:
+                               if (!(max_v[0] & max_v[1]) == !match)
+                                       continue;
+                       }
+                       goto out;
+               }
+               /* Normal value range comparison. */
+               if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
+                       continue;
+out:
+               return false;
+       }
+       /* Check argv[] and envp[] now. */
+       if (r->ee && (argc || envc))
+               return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp);
+       return true;
+}
index 35388408e475470b6c2467db248a05b1b01c2ca7..cd0f92d88bb43a35c99230c52effb311da0d5213 100644 (file)
@@ -1,9 +1,7 @@
 /*
  * security/tomoyo/domain.c
  *
- * Domain transition functions for TOMOYO.
- *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include "common.h"
@@ -20,8 +18,7 @@ struct tomoyo_domain_info tomoyo_kernel_domain;
  *
  * @new_entry:       Pointer to "struct tomoyo_acl_info".
  * @size:            Size of @new_entry in bytes.
- * @is_delete:       True if it is a delete request.
- * @list:            Pointer to "struct list_head".
+ * @param:           Pointer to "struct tomoyo_acl_param".
  * @check_duplicate: Callback function to find duplicated entry.
  *
  * Returns 0 on success, negative value otherwise.
@@ -29,25 +26,26 @@ struct tomoyo_domain_info tomoyo_kernel_domain;
  * Caller holds tomoyo_read_lock().
  */
 int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
-                        bool is_delete, struct list_head *list,
+                        struct tomoyo_acl_param *param,
                         bool (*check_duplicate) (const struct tomoyo_acl_head
                                                  *,
                                                  const struct tomoyo_acl_head
                                                  *))
 {
-       int error = is_delete ? -ENOENT : -ENOMEM;
+       int error = param->is_delete ? -ENOENT : -ENOMEM;
        struct tomoyo_acl_head *entry;
+       struct list_head *list = param->list;
 
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                return -ENOMEM;
        list_for_each_entry_rcu(entry, list, list) {
                if (!check_duplicate(entry, new_entry))
                        continue;
-               entry->is_deleted = is_delete;
+               entry->is_deleted = param->is_delete;
                error = 0;
                break;
        }
-       if (error && !is_delete) {
+       if (error && !param->is_delete) {
                entry = tomoyo_commit_ok(new_entry, size);
                if (entry) {
                        list_add_tail_rcu(&entry->list, list);
@@ -58,13 +56,26 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
        return error;
 }
 
+/**
+ * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
+                                       const struct tomoyo_acl_info *b)
+{
+       return a->type == b->type && a->cond == b->cond;
+}
+
 /**
  * tomoyo_update_domain - Update an entry for domain policy.
  *
  * @new_entry:       Pointer to "struct tomoyo_acl_info".
  * @size:            Size of @new_entry in bytes.
- * @is_delete:       True if it is a delete request.
- * @domain:          Pointer to "struct tomoyo_domain_info".
+ * @param:           Pointer to "struct tomoyo_acl_param".
  * @check_duplicate: Callback function to find duplicated entry.
  * @merge_duplicate: Callback function to merge duplicated entry.
  *
@@ -73,7 +84,7 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
  * Caller holds tomoyo_read_lock().
  */
 int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
-                        bool is_delete, struct tomoyo_domain_info *domain,
+                        struct tomoyo_acl_param *param,
                         bool (*check_duplicate) (const struct tomoyo_acl_info
                                                  *,
                                                  const struct tomoyo_acl_info
@@ -82,13 +93,21 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
                                                  struct tomoyo_acl_info *,
                                                  const bool))
 {
+       const bool is_delete = param->is_delete;
        int error = is_delete ? -ENOENT : -ENOMEM;
        struct tomoyo_acl_info *entry;
+       struct list_head * const list = param->list;
 
+       if (param->data[0]) {
+               new_entry->cond = tomoyo_get_condition(param);
+               if (!new_entry->cond)
+                       return -EINVAL;
+       }
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
-               return error;
-       list_for_each_entry_rcu(entry, &domain->acl_info_list, list) {
-               if (!check_duplicate(entry, new_entry))
+               goto out;
+       list_for_each_entry_rcu(entry, list, list) {
+               if (!tomoyo_same_acl_head(entry, new_entry) ||
+                   !check_duplicate(entry, new_entry))
                        continue;
                if (merge_duplicate)
                        entry->is_deleted = merge_duplicate(entry, new_entry,
@@ -101,28 +120,50 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
        if (error && !is_delete) {
                entry = tomoyo_commit_ok(new_entry, size);
                if (entry) {
-                       list_add_tail_rcu(&entry->list, &domain->acl_info_list);
+                       list_add_tail_rcu(&entry->list, list);
                        error = 0;
                }
        }
        mutex_unlock(&tomoyo_policy_lock);
+out:
+       tomoyo_put_condition(new_entry->cond);
        return error;
 }
 
+/**
+ * tomoyo_check_acl - Do permission check.
+ *
+ * @r:           Pointer to "struct tomoyo_request_info".
+ * @check_entry: Callback function to check type specific parameters.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
 void tomoyo_check_acl(struct tomoyo_request_info *r,
                      bool (*check_entry) (struct tomoyo_request_info *,
                                           const struct tomoyo_acl_info *))
 {
        const struct tomoyo_domain_info *domain = r->domain;
        struct tomoyo_acl_info *ptr;
+       bool retried = false;
+       const struct list_head *list = &domain->acl_info_list;
 
-       list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+retry:
+       list_for_each_entry_rcu(ptr, list, list) {
                if (ptr->is_deleted || ptr->type != r->param_type)
                        continue;
-               if (check_entry(r, ptr)) {
-                       r->granted = true;
-                       return;
-               }
+               if (!check_entry(r, ptr))
+                       continue;
+               if (!tomoyo_condition(r, ptr->cond))
+                       continue;
+               r->granted = true;
+               return;
+       }
+       if (!retried) {
+               retried = true;
+               list = &domain->ns->acl_group[domain->group];
+               goto retry;
        }
        r->granted = false;
 }
@@ -130,24 +171,29 @@ void tomoyo_check_acl(struct tomoyo_request_info *r,
 /* The list for "struct tomoyo_domain_info". */
 LIST_HEAD(tomoyo_domain_list);
 
-struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
-struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
-
 /**
  * tomoyo_last_word - Get last component of a domainname.
  *
- * @domainname: Domainname to check.
+ * @name: Domainname to check.
  *
  * Returns the last word of @domainname.
  */
 static const char *tomoyo_last_word(const char *name)
 {
-        const char *cp = strrchr(name, ' ');
-        if (cp)
-                return cp + 1;
-        return name;
+       const char *cp = strrchr(name, ' ');
+       if (cp)
+               return cp + 1;
+       return name;
 }
 
+/**
+ * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
 static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
                                           const struct tomoyo_acl_head *b)
 {
@@ -163,30 +209,36 @@ static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
 }
 
 /**
- * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list.
+ * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
  *
- * @domainname: The name of domain. Maybe NULL.
- * @program:    The name of program. Maybe NULL.
- * @type:       Type of transition.
- * @is_delete:  True if it is a delete request.
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @type:  Type of this entry.
  *
  * Returns 0 on success, negative value otherwise.
  */
-static int tomoyo_update_transition_control_entry(const char *domainname,
-                                                 const char *program,
-                                                 const u8 type,
-                                                 const bool is_delete)
+int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
+                                   const u8 type)
 {
        struct tomoyo_transition_control e = { .type = type };
-       int error = is_delete ? -ENOENT : -ENOMEM;
-       if (program) {
+       int error = param->is_delete ? -ENOENT : -ENOMEM;
+       char *program = param->data;
+       char *domainname = strstr(program, " from ");
+       if (domainname) {
+               *domainname = '\0';
+               domainname += 6;
+       } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
+                  type == TOMOYO_TRANSITION_CONTROL_KEEP) {
+               domainname = program;
+               program = NULL;
+       }
+       if (program && strcmp(program, "any")) {
                if (!tomoyo_correct_path(program))
                        return -EINVAL;
                e.program = tomoyo_get_name(program);
                if (!e.program)
                        goto out;
        }
-       if (domainname) {
+       if (domainname && strcmp(domainname, "any")) {
                if (!tomoyo_correct_domain(domainname)) {
                        if (!tomoyo_correct_path(domainname))
                                goto out;
@@ -196,126 +248,136 @@ static int tomoyo_update_transition_control_entry(const char *domainname,
                if (!e.domainname)
                        goto out;
        }
-       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
-                                    &tomoyo_policy_list
-                                    [TOMOYO_ID_TRANSITION_CONTROL],
+       param->list = &param->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
+       error = tomoyo_update_policy(&e.head, sizeof(e), param,
                                     tomoyo_same_transition_control);
- out:
+out:
        tomoyo_put_name(e.domainname);
        tomoyo_put_name(e.program);
        return error;
 }
 
 /**
- * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
+ * tomoyo_scan_transition - Try to find specific domain transition type.
  *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
- * @type:      Type of this entry.
+ * @list:       Pointer to "struct list_head".
+ * @domainname: The name of current domain.
+ * @program:    The name of requested program.
+ * @last_name:  The last component of @domainname.
+ * @type:       One of values in "enum tomoyo_transition_type".
  *
- * Returns 0 on success, negative value otherwise.
+ * Returns true if found one, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_transition_control(char *data, const bool is_delete,
-                                   const u8 type)
+static inline bool tomoyo_scan_transition
+(const struct list_head *list, const struct tomoyo_path_info *domainname,
+ const struct tomoyo_path_info *program, const char *last_name,
+ const enum tomoyo_transition_type type)
 {
-       char *domainname = strstr(data, " from ");
-       if (domainname) {
-               *domainname = '\0';
-               domainname += 6;
-       } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
-                  type == TOMOYO_TRANSITION_CONTROL_KEEP) {
-               domainname = data;
-               data = NULL;
+       const struct tomoyo_transition_control *ptr;
+       list_for_each_entry_rcu(ptr, list, head.list) {
+               if (ptr->head.is_deleted || ptr->type != type)
+                       continue;
+               if (ptr->domainname) {
+                       if (!ptr->is_last_name) {
+                               if (ptr->domainname != domainname)
+                                       continue;
+                       } else {
+                               /*
+                                * Use direct strcmp() since this is
+                                * unlikely used.
+                                */
+                               if (strcmp(ptr->domainname->name, last_name))
+                                       continue;
+                       }
+               }
+               if (ptr->program && tomoyo_pathcmp(ptr->program, program))
+                       continue;
+               return true;
        }
-       return tomoyo_update_transition_control_entry(domainname, data, type,
-                                                     is_delete);
+       return false;
 }
 
 /**
  * tomoyo_transition_type - Get domain transition type.
  *
- * @domainname: The name of domain.
- * @program:    The name of program.
+ * @ns:         Pointer to "struct tomoyo_policy_namespace".
+ * @domainname: The name of current domain.
+ * @program:    The name of requested program.
  *
- * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program
- * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing
- * @program suppresses domain transition, others otherwise.
+ * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes
+ * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if
+ * executing @program reinitializes domain transition within that namespace,
+ * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
+ * others otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname,
-                                const struct tomoyo_path_info *program)
+static enum tomoyo_transition_type tomoyo_transition_type
+(const struct tomoyo_policy_namespace *ns,
+ const struct tomoyo_path_info *domainname,
+ const struct tomoyo_path_info *program)
 {
-       const struct tomoyo_transition_control *ptr;
        const char *last_name = tomoyo_last_word(domainname->name);
-       u8 type;
-       for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) {
- next:
-               list_for_each_entry_rcu(ptr, &tomoyo_policy_list
-                                       [TOMOYO_ID_TRANSITION_CONTROL],
-                                       head.list) {
-                       if (ptr->head.is_deleted || ptr->type != type)
-                               continue;
-                       if (ptr->domainname) {
-                               if (!ptr->is_last_name) {
-                                       if (ptr->domainname != domainname)
-                                               continue;
-                               } else {
-                                       /*
-                                        * Use direct strcmp() since this is
-                                        * unlikely used.
-                                        */
-                                       if (strcmp(ptr->domainname->name,
-                                                  last_name))
-                                               continue;
-                               }
-                       }
-                       if (ptr->program &&
-                           tomoyo_pathcmp(ptr->program, program))
-                               continue;
-                       if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) {
-                               /*
-                                * Do not check for initialize_domain if
-                                * no_initialize_domain matched.
-                                */
-                               type = TOMOYO_TRANSITION_CONTROL_NO_KEEP;
-                               goto next;
-                       }
-                       goto done;
+       enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET;
+       while (type < TOMOYO_MAX_TRANSITION_TYPE) {
+               const struct list_head * const list =
+                       &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
+               if (!tomoyo_scan_transition(list, domainname, program,
+                                           last_name, type)) {
+                       type++;
+                       continue;
                }
+               if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET &&
+                   type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE)
+                       break;
+               /*
+                * Do not check for reset_domain if no_reset_domain matched.
+                * Do not check for initialize_domain if no_initialize_domain
+                * matched.
+                */
+               type++;
+               type++;
        }
- done:
        return type;
 }
 
+/**
+ * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
 static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
                                   const struct tomoyo_acl_head *b)
 {
-       const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), head);
-       const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), head);
+       const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1),
+                                                         head);
+       const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2),
+                                                         head);
        return p1->original_name == p2->original_name &&
                p1->aggregated_name == p2->aggregated_name;
 }
 
 /**
- * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator" list.
+ * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
  *
- * @original_name:   The original program's name.
- * @aggregated_name: The program name to use.
- * @is_delete:       True if it is a delete request.
+ * @param: Pointer to "struct tomoyo_acl_param".
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_aggregator_entry(const char *original_name,
-                                         const char *aggregated_name,
-                                         const bool is_delete)
+int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
 {
        struct tomoyo_aggregator e = { };
-       int error = is_delete ? -ENOENT : -ENOMEM;
-
-       if (!tomoyo_correct_path(original_name) ||
+       int error = param->is_delete ? -ENOENT : -ENOMEM;
+       const char *original_name = tomoyo_read_token(param);
+       const char *aggregated_name = tomoyo_read_token(param);
+       if (!tomoyo_correct_word(original_name) ||
            !tomoyo_correct_path(aggregated_name))
                return -EINVAL;
        e.original_name = tomoyo_get_name(original_name);
@@ -323,83 +385,181 @@ static int tomoyo_update_aggregator_entry(const char *original_name,
        if (!e.original_name || !e.aggregated_name ||
            e.aggregated_name->is_patterned) /* No patterns allowed. */
                goto out;
-       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
-                                    &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR],
+       param->list = &param->ns->policy_list[TOMOYO_ID_AGGREGATOR];
+       error = tomoyo_update_policy(&e.head, sizeof(e), param,
                                     tomoyo_same_aggregator);
- out:
+out:
        tomoyo_put_name(e.original_name);
        tomoyo_put_name(e.aggregated_name);
        return error;
 }
 
 /**
- * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
+ * tomoyo_find_namespace - Find specified namespace.
  *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
+ * @name: Name of namespace to find.
+ * @len:  Length of @name.
  *
- * Returns 0 on success, negative value otherwise.
+ * Returns pointer to "struct tomoyo_policy_namespace" if found,
+ * NULL otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_aggregator(char *data, const bool is_delete)
+static struct tomoyo_policy_namespace *tomoyo_find_namespace
+(const char *name, const unsigned int len)
 {
-       char *cp = strchr(data, ' ');
+       struct tomoyo_policy_namespace *ns;
+       list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
+               if (strncmp(name, ns->name, len) ||
+                   (name[len] && name[len] != ' '))
+                       continue;
+               return ns;
+       }
+       return NULL;
+}
 
-       if (!cp)
-               return -EINVAL;
-       *cp++ = '\0';
-       return tomoyo_update_aggregator_entry(data, cp, is_delete);
+/**
+ * tomoyo_assign_namespace - Create a new namespace.
+ *
+ * @domainname: Name of namespace to create.
+ *
+ * Returns pointer to "struct tomoyo_policy_namespace" on success,
+ * NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
+{
+       struct tomoyo_policy_namespace *ptr;
+       struct tomoyo_policy_namespace *entry;
+       const char *cp = domainname;
+       unsigned int len = 0;
+       while (*cp && *cp++ != ' ')
+               len++;
+       ptr = tomoyo_find_namespace(domainname, len);
+       if (ptr)
+               return ptr;
+       if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname))
+               return NULL;
+       entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS);
+       if (!entry)
+               return NULL;
+       if (mutex_lock_interruptible(&tomoyo_policy_lock))
+               goto out;
+       ptr = tomoyo_find_namespace(domainname, len);
+       if (!ptr && tomoyo_memory_ok(entry)) {
+               char *name = (char *) (entry + 1);
+               ptr = entry;
+               memmove(name, domainname, len);
+               name[len] = '\0';
+               entry->name = name;
+               tomoyo_init_policy_namespace(entry);
+               entry = NULL;
+       }
+       mutex_unlock(&tomoyo_policy_lock);
+out:
+       kfree(entry);
+       return ptr;
 }
 
 /**
- * tomoyo_assign_domain - Create a domain.
+ * tomoyo_namespace_jump - Check for namespace jump.
+ *
+ * @domainname: Name of domain.
+ *
+ * Returns true if namespace differs, false otherwise.
+ */
+static bool tomoyo_namespace_jump(const char *domainname)
+{
+       const char *namespace = tomoyo_current_namespace()->name;
+       const int len = strlen(namespace);
+       return strncmp(domainname, namespace, len) ||
+               (domainname[len] && domainname[len] != ' ');
+}
+
+/**
+ * tomoyo_assign_domain - Create a domain or a namespace.
  *
  * @domainname: The name of domain.
- * @profile:    Profile number to assign if the domain was newly created.
+ * @transit:    True if transit to domain found or created.
  *
  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
 struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
-                                               const u8 profile)
+                                               const bool transit)
 {
-       struct tomoyo_domain_info *entry;
-       struct tomoyo_domain_info *domain = NULL;
-       const struct tomoyo_path_info *saved_domainname;
-       bool found = false;
-
-       if (!tomoyo_correct_domain(domainname))
+       struct tomoyo_domain_info e = { };
+       struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
+       bool created = false;
+       if (entry) {
+               if (transit) {
+                       /*
+                        * Since namespace is created at runtime, profiles may
+                        * not be created by the moment the process transits to
+                        * that domain. Do not perform domain transition if
+                        * profile for that domain is not yet created.
+                        */
+                       if (!entry->ns->profile_ptr[entry->profile])
+                               return NULL;
+               }
+               return entry;
+       }
+       /* Requested domain does not exist. */
+       /* Don't create requested domain if domainname is invalid. */
+       if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 ||
+           !tomoyo_correct_domain(domainname))
+               return NULL;
+       /*
+        * Since definition of profiles and acl_groups may differ across
+        * namespaces, do not inherit "use_profile" and "use_group" settings
+        * by automatically creating requested domain upon domain transition.
+        */
+       if (transit && tomoyo_namespace_jump(domainname))
+               return NULL;
+       e.ns = tomoyo_assign_namespace(domainname);
+       if (!e.ns)
                return NULL;
-       saved_domainname = tomoyo_get_name(domainname);
-       if (!saved_domainname)
+       /*
+        * "use_profile" and "use_group" settings for automatically created
+        * domains are inherited from current domain. These are 0 for manually
+        * created domains.
+        */
+       if (transit) {
+               const struct tomoyo_domain_info *domain = tomoyo_domain();
+               e.profile = domain->profile;
+               e.group = domain->group;
+       }
+       e.domainname = tomoyo_get_name(domainname);
+       if (!e.domainname)
                return NULL;
-       entry = kzalloc(sizeof(*entry), GFP_NOFS);
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                goto out;
-       list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
-               if (domain->is_deleted ||
-                   tomoyo_pathcmp(saved_domainname, domain->domainname))
-                       continue;
-               found = true;
-               break;
-       }
-       if (!found && tomoyo_memory_ok(entry)) {
-               INIT_LIST_HEAD(&entry->acl_info_list);
-               entry->domainname = saved_domainname;
-               saved_domainname = NULL;
-               entry->profile = profile;
-               list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
-               domain = entry;
-               entry = NULL;
-               found = true;
+       entry = tomoyo_find_domain(domainname);
+       if (!entry) {
+               entry = tomoyo_commit_ok(&e, sizeof(e));
+               if (entry) {
+                       INIT_LIST_HEAD(&entry->acl_info_list);
+                       list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
+                       created = true;
+               }
        }
        mutex_unlock(&tomoyo_policy_lock);
- out:
-       tomoyo_put_name(saved_domainname);
-       kfree(entry);
-       return found ? domain : NULL;
+out:
+       tomoyo_put_name(e.domainname);
+       if (entry && transit) {
+               if (created) {
+                       struct tomoyo_request_info r;
+                       tomoyo_init_request_info(&r, entry,
+                                                TOMOYO_MAC_FILE_EXECUTE);
+                       r.granted = false;
+                       tomoyo_write_log(&r, "use_profile %u\n",
+                                        entry->profile);
+                       tomoyo_write_log(&r, "use_group %u\n", entry->group);
+               }
+       }
+       return entry;
 }
 
 /**
@@ -413,22 +573,27 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
  */
 int tomoyo_find_next_domain(struct linux_binprm *bprm)
 {
-       struct tomoyo_request_info r;
-       char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
        struct tomoyo_domain_info *old_domain = tomoyo_domain();
        struct tomoyo_domain_info *domain = NULL;
        const char *original_name = bprm->filename;
-       u8 mode;
-       bool is_enforce;
        int retval = -ENOMEM;
        bool need_kfree = false;
+       bool reject_on_transition_failure = false;
        struct tomoyo_path_info rn = { }; /* real name */
-
-       mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
-       is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
-       if (!tmp)
-               goto out;
-
+       struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
+       if (!ee)
+               return -ENOMEM;
+       ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
+       if (!ee->tmp) {
+               kfree(ee);
+               return -ENOMEM;
+       }
+       /* ee->dump->data is allocated by tomoyo_dump_page(). */
+       tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE);
+       ee->r.ee = ee;
+       ee->bprm = bprm;
+       ee->r.obj = &ee->obj;
+       ee->obj.path1 = bprm->file->f_path;
  retry:
        if (need_kfree) {
                kfree(rn.name);
@@ -445,8 +610,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
        /* Check 'aggregator' directive. */
        {
                struct tomoyo_aggregator *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_policy_list
-                                       [TOMOYO_ID_AGGREGATOR], head.list) {
+               struct list_head *list =
+                       &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
+               /* Check 'aggregator' directive. */
+               list_for_each_entry_rcu(ptr, list, head.list) {
                        if (ptr->head.is_deleted ||
                            !tomoyo_path_matches_pattern(&rn,
                                                         ptr->original_name))
@@ -460,7 +627,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
        }
 
        /* Check execute permission. */
-       retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn);
+       retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn);
        if (retval == TOMOYO_RETRY_REQUEST)
                goto retry;
        if (retval < 0)
@@ -471,20 +638,30 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
         * wildcard) rather than the pathname passed to execve()
         * (which never contains wildcard).
         */
-       if (r.param.path.matched_path) {
+       if (ee->r.param.path.matched_path) {
                if (need_kfree)
                        kfree(rn.name);
                need_kfree = false;
                /* This is OK because it is read only. */
-               rn = *r.param.path.matched_path;
+               rn = *ee->r.param.path.matched_path;
        }
 
        /* Calculate domain to transit to. */
-       switch (tomoyo_transition_type(old_domain->domainname, &rn)) {
+       switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
+                                      &rn)) {
+       case TOMOYO_TRANSITION_CONTROL_RESET:
+               /* Transit to the root of specified namespace. */
+               snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name);
+               /*
+                * Make do_execve() fail if domain transition across namespaces
+                * has failed.
+                */
+               reject_on_transition_failure = true;
+               break;
        case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
-               /* Transit to the child of tomoyo_kernel_domain domain. */
-               snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " "
-                        "%s", rn.name);
+               /* Transit to the child of current namespace's root. */
+               snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+                        old_domain->ns->name, rn.name);
                break;
        case TOMOYO_TRANSITION_CONTROL_KEEP:
                /* Keep current domain. */
@@ -502,33 +679,32 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
                        domain = old_domain;
                } else {
                        /* Normal domain transition. */
-                       snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
+                       snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
                                 old_domain->domainname->name, rn.name);
                }
                break;
        }
-       if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
-               goto done;
-       domain = tomoyo_find_domain(tmp);
+       if (!domain)
+               domain = tomoyo_assign_domain(ee->tmp, true);
        if (domain)
-               goto done;
-       if (is_enforce) {
-               int error = tomoyo_supervisor(&r, "# wants to create domain\n"
-                                             "%s\n", tmp);
-               if (error == TOMOYO_RETRY_REQUEST)
-                       goto retry;
-               if (error < 0)
-                       goto done;
+               retval = 0;
+       else if (reject_on_transition_failure) {
+               printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n",
+                      ee->tmp);
+               retval = -ENOMEM;
+       } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
+               retval = -ENOMEM;
+       else {
+               retval = 0;
+               if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) {
+                       old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true;
+                       ee->r.granted = false;
+                       tomoyo_write_log(&ee->r, "%s", tomoyo_dif
+                                        [TOMOYO_DIF_TRANSITION_FAILED]);
+                       printk(KERN_WARNING
+                              "ERROR: Domain '%s' not defined.\n", ee->tmp);
+               }
        }
-       domain = tomoyo_assign_domain(tmp, old_domain->profile);
- done:
-       if (domain)
-               goto out;
-       printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
-       if (is_enforce)
-               retval = -EPERM;
-       else
-               old_domain->transition_failed = true;
  out:
        if (!domain)
                domain = old_domain;
@@ -537,6 +713,54 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
        bprm->cred->security = domain;
        if (need_kfree)
                kfree(rn.name);
-       kfree(tmp);
+       kfree(ee->tmp);
+       kfree(ee->dump.data);
+       kfree(ee);
        return retval;
 }
+
+/**
+ * tomoyo_dump_page - Dump a page to buffer.
+ *
+ * @bprm: Pointer to "struct linux_binprm".
+ * @pos:  Location to dump.
+ * @dump: Poiner to "struct tomoyo_page_dump".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
+                     struct tomoyo_page_dump *dump)
+{
+       struct page *page;
+       /* dump->data is released by tomoyo_finish_execve(). */
+       if (!dump->data) {
+               dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
+               if (!dump->data)
+                       return false;
+       }
+       /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
+#ifdef CONFIG_MMU
+       if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
+               return false;
+#else
+       page = bprm->page[pos / PAGE_SIZE];
+#endif
+       if (page != dump->page) {
+               const unsigned int offset = pos % PAGE_SIZE;
+               /*
+                * Maybe kmap()/kunmap() should be used here.
+                * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
+                * So do I.
+                */
+               char *kaddr = kmap_atomic(page, KM_USER0);
+               dump->page = page;
+               memcpy(dump->data + offset, kaddr + offset,
+                      PAGE_SIZE - offset);
+               kunmap_atomic(kaddr, KM_USER0);
+       }
+       /* Same with put_arg_page(page) in fs/exec.c */
+#ifdef CONFIG_MMU
+       put_page(page);
+#endif
+       return true;
+}
index d64e8ecb6fb3e7cbb923cbf80e8cbb993872279b..743c35f5084a1125c63e04043bdfb71bb8128651 100644 (file)
@@ -1,80 +1,51 @@
 /*
  * security/tomoyo/file.c
  *
- * Pathname restriction functions.
- *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include "common.h"
 #include <linux/slab.h>
 
-/* Keyword array for operations with one pathname. */
-const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
-       [TOMOYO_TYPE_READ_WRITE] = "read/write",
-       [TOMOYO_TYPE_EXECUTE]    = "execute",
-       [TOMOYO_TYPE_READ]       = "read",
-       [TOMOYO_TYPE_WRITE]      = "write",
-       [TOMOYO_TYPE_UNLINK]     = "unlink",
-       [TOMOYO_TYPE_RMDIR]      = "rmdir",
-       [TOMOYO_TYPE_TRUNCATE]   = "truncate",
-       [TOMOYO_TYPE_SYMLINK]    = "symlink",
-       [TOMOYO_TYPE_REWRITE]    = "rewrite",
-       [TOMOYO_TYPE_CHROOT]     = "chroot",
-       [TOMOYO_TYPE_UMOUNT]     = "unmount",
-};
-
-/* Keyword array for operations with one pathname and three numbers. */
-const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = {
-       [TOMOYO_TYPE_MKBLOCK]    = "mkblock",
-       [TOMOYO_TYPE_MKCHAR]     = "mkchar",
-};
-
-/* Keyword array for operations with two pathnames. */
-const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
-       [TOMOYO_TYPE_LINK]       = "link",
-       [TOMOYO_TYPE_RENAME]     = "rename",
-       [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
-};
-
-/* Keyword array for operations with one pathname and one number. */
-const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
-       [TOMOYO_TYPE_CREATE]     = "create",
-       [TOMOYO_TYPE_MKDIR]      = "mkdir",
-       [TOMOYO_TYPE_MKFIFO]     = "mkfifo",
-       [TOMOYO_TYPE_MKSOCK]     = "mksock",
-       [TOMOYO_TYPE_IOCTL]      = "ioctl",
-       [TOMOYO_TYPE_CHMOD]      = "chmod",
-       [TOMOYO_TYPE_CHOWN]      = "chown",
-       [TOMOYO_TYPE_CHGRP]      = "chgrp",
-};
-
+/*
+ * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index".
+ */
 static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
-       [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN,
        [TOMOYO_TYPE_EXECUTE]    = TOMOYO_MAC_FILE_EXECUTE,
        [TOMOYO_TYPE_READ]       = TOMOYO_MAC_FILE_OPEN,
        [TOMOYO_TYPE_WRITE]      = TOMOYO_MAC_FILE_OPEN,
+       [TOMOYO_TYPE_APPEND]     = TOMOYO_MAC_FILE_OPEN,
        [TOMOYO_TYPE_UNLINK]     = TOMOYO_MAC_FILE_UNLINK,
+       [TOMOYO_TYPE_GETATTR]    = TOMOYO_MAC_FILE_GETATTR,
        [TOMOYO_TYPE_RMDIR]      = TOMOYO_MAC_FILE_RMDIR,
        [TOMOYO_TYPE_TRUNCATE]   = TOMOYO_MAC_FILE_TRUNCATE,
        [TOMOYO_TYPE_SYMLINK]    = TOMOYO_MAC_FILE_SYMLINK,
-       [TOMOYO_TYPE_REWRITE]    = TOMOYO_MAC_FILE_REWRITE,
        [TOMOYO_TYPE_CHROOT]     = TOMOYO_MAC_FILE_CHROOT,
        [TOMOYO_TYPE_UMOUNT]     = TOMOYO_MAC_FILE_UMOUNT,
 };
 
-static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
+/*
+ * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index".
+ */
+const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
        [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
        [TOMOYO_TYPE_MKCHAR]  = TOMOYO_MAC_FILE_MKCHAR,
 };
 
-static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
+/*
+ * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index".
+ */
+const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
        [TOMOYO_TYPE_LINK]       = TOMOYO_MAC_FILE_LINK,
        [TOMOYO_TYPE_RENAME]     = TOMOYO_MAC_FILE_RENAME,
        [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
 };
 
-static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+/*
+ * Mapping table from "enum tomoyo_path_number_acl_index" to
+ * "enum tomoyo_mac_index".
+ */
+const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
        [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
        [TOMOYO_TYPE_MKDIR]  = TOMOYO_MAC_FILE_MKDIR,
        [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
@@ -85,41 +56,76 @@ static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
        [TOMOYO_TYPE_CHGRP]  = TOMOYO_MAC_FILE_CHGRP,
 };
 
+/**
+ * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union".
+ *
+ * @ptr: Pointer to "struct tomoyo_name_union".
+ *
+ * Returns nothing.
+ */
 void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
 {
-       if (!ptr)
-               return;
-       if (ptr->is_group)
-               tomoyo_put_group(ptr->group);
-       else
-               tomoyo_put_name(ptr->filename);
+       tomoyo_put_group(ptr->group);
+       tomoyo_put_name(ptr->filename);
 }
 
+/**
+ * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not.
+ *
+ * @name: Pointer to "struct tomoyo_path_info".
+ * @ptr:  Pointer to "struct tomoyo_name_union".
+ *
+ * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise.
+ */
 const struct tomoyo_path_info *
 tomoyo_compare_name_union(const struct tomoyo_path_info *name,
                          const struct tomoyo_name_union *ptr)
 {
-       if (ptr->is_group)
+       if (ptr->group)
                return tomoyo_path_matches_group(name, ptr->group);
        if (tomoyo_path_matches_pattern(name, ptr->filename))
                return ptr->filename;
        return NULL;
 }
 
+/**
+ * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union".
+ *
+ * @ptr: Pointer to "struct tomoyo_number_union".
+ *
+ * Returns nothing.
+ */
 void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
 {
-       if (ptr && ptr->is_group)
-               tomoyo_put_group(ptr->group);
+       tomoyo_put_group(ptr->group);
 }
 
+/**
+ * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not.
+ *
+ * @value: Number to check.
+ * @ptr:   Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true if @value matches @ptr, false otherwise.
+ */
 bool tomoyo_compare_number_union(const unsigned long value,
                                 const struct tomoyo_number_union *ptr)
 {
-       if (ptr->is_group)
+       if (ptr->group)
                return tomoyo_number_matches_group(value, value, ptr->group);
        return value >= ptr->values[0] && value <= ptr->values[1];
 }
 
+/**
+ * tomoyo_add_slash - Add trailing '/' if needed.
+ *
+ * @buf: Pointer to "struct tomoyo_path_info".
+ *
+ * Returns nothing.
+ *
+ * @buf must be generated by tomoyo_encode() because this function does not
+ * allocate memory for adding '/'.
+ */
 static void tomoyo_add_slash(struct tomoyo_path_info *buf)
 {
        if (buf->is_dir)
@@ -131,24 +137,6 @@ static void tomoyo_add_slash(struct tomoyo_path_info *buf)
        tomoyo_fill_path_info(buf);
 }
 
-/**
- * tomoyo_strendswith - Check whether the token ends with the given token.
- *
- * @name: The token to check.
- * @tail: The token to find.
- *
- * Returns true if @name ends with @tail, false otherwise.
- */
-static bool tomoyo_strendswith(const char *name, const char *tail)
-{
-       int len;
-
-       if (!name || !tail)
-               return false;
-       len = strlen(name) - strlen(tail);
-       return len >= 0 && !strcmp(name + len, tail);
-}
-
 /**
  * tomoyo_get_realpath - Get realpath.
  *
@@ -164,7 +152,7 @@ static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
                tomoyo_fill_path_info(buf);
                return true;
        }
-        return false;
+       return false;
 }
 
 /**
@@ -176,13 +164,9 @@ static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
  */
 static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
 {
-       const char *operation = tomoyo_path_keyword[r->param.path.operation];
-       const struct tomoyo_path_info *filename = r->param.path.filename;
-       if (r->granted)
-               return 0;
-       tomoyo_warn_log(r, "%s %s", operation, filename->name);
-       return tomoyo_supervisor(r, "allow_%s %s\n", operation,
-                                tomoyo_pattern(filename));
+       return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword
+                                [r->param.path.operation],
+                                r->param.path.filename->name);
 }
 
 /**
@@ -194,16 +178,10 @@ static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
  */
 static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
 {
-       const char *operation = tomoyo_path2_keyword[r->param.path2.operation];
-       const struct tomoyo_path_info *filename1 = r->param.path2.filename1;
-       const struct tomoyo_path_info *filename2 = r->param.path2.filename2;
-       if (r->granted)
-               return 0;
-       tomoyo_warn_log(r, "%s %s %s", operation, filename1->name,
-                       filename2->name);
-       return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
-                                tomoyo_pattern(filename1),
-                                tomoyo_pattern(filename2));
+       return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
+                                [tomoyo_pp2mac[r->param.path2.operation]],
+                                r->param.path2.filename1->name,
+                                r->param.path2.filename2->name);
 }
 
 /**
@@ -215,24 +193,18 @@ static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
  */
 static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
 {
-       const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation];
-       const struct tomoyo_path_info *filename = r->param.mkdev.filename;
-       const unsigned int major = r->param.mkdev.major;
-       const unsigned int minor = r->param.mkdev.minor;
-       const unsigned int mode = r->param.mkdev.mode;
-       if (r->granted)
-               return 0;
-       tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode,
-                       major, minor);
-       return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation,
-                                tomoyo_pattern(filename), mode, major, minor);
+       return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n",
+                                tomoyo_mac_keywords
+                                [tomoyo_pnnn2mac[r->param.mkdev.operation]],
+                                r->param.mkdev.filename->name,
+                                r->param.mkdev.mode, r->param.mkdev.major,
+                                r->param.mkdev.minor);
 }
 
 /**
  * tomoyo_audit_path_number_log - Audit path/number request log.
  *
- * @r:     Pointer to "struct tomoyo_request_info".
- * @error: Error code.
+ * @r: Pointer to "struct tomoyo_request_info".
  *
  * Returns 0 on success, negative value otherwise.
  */
@@ -240,11 +212,7 @@ static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
 {
        const u8 type = r->param.path_number.operation;
        u8 radix;
-       const struct tomoyo_path_info *filename = r->param.path_number.filename;
-       const char *operation = tomoyo_path_number_keyword[type];
        char buffer[64];
-       if (r->granted)
-               return 0;
        switch (type) {
        case TOMOYO_TYPE_CREATE:
        case TOMOYO_TYPE_MKDIR:
@@ -262,251 +230,23 @@ static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
        }
        tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
                           radix);
-       tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer);
-       return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
-                                tomoyo_pattern(filename), buffer);
-}
-
-static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a,
-                                         const struct tomoyo_acl_head *b)
-{
-       return container_of(a, struct tomoyo_readable_file,
-                           head)->filename ==
-               container_of(b, struct tomoyo_readable_file,
-                            head)->filename;
-}
-
-/**
- * tomoyo_update_globally_readable_entry - Update "struct tomoyo_readable_file" list.
- *
- * @filename:  Filename unconditionally permitted to open() for reading.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_update_globally_readable_entry(const char *filename,
-                                                const bool is_delete)
-{
-       struct tomoyo_readable_file e = { };
-       int error;
-
-       if (!tomoyo_correct_word(filename))
-               return -EINVAL;
-       e.filename = tomoyo_get_name(filename);
-       if (!e.filename)
-               return -ENOMEM;
-       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
-                                    &tomoyo_policy_list
-                                    [TOMOYO_ID_GLOBALLY_READABLE],
-                                    tomoyo_same_globally_readable);
-       tomoyo_put_name(e.filename);
-       return error;
-}
-
-/**
- * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
- *
- * @filename: The filename to check.
- *
- * Returns true if any domain can open @filename for reading, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static bool tomoyo_globally_readable_file(const struct tomoyo_path_info *
-                                            filename)
-{
-       struct tomoyo_readable_file *ptr;
-       bool found = false;
-
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_list
-                               [TOMOYO_ID_GLOBALLY_READABLE], head.list) {
-               if (!ptr->head.is_deleted &&
-                   tomoyo_path_matches_pattern(filename, ptr->filename)) {
-                       found = true;
-                       break;
-               }
-       }
-       return found;
-}
-
-/**
- * tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list.
- *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_globally_readable(char *data, const bool is_delete)
-{
-       return tomoyo_update_globally_readable_entry(data, is_delete);
-}
-
-static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a,
-                               const struct tomoyo_acl_head *b)
-{
-       return container_of(a, struct tomoyo_no_pattern, head)->pattern ==
-               container_of(b, struct tomoyo_no_pattern, head)->pattern;
-}
-
-/**
- * tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list.
- *
- * @pattern:   Pathname pattern.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_update_file_pattern_entry(const char *pattern,
-                                           const bool is_delete)
-{
-       struct tomoyo_no_pattern e = { };
-       int error;
-
-       if (!tomoyo_correct_word(pattern))
-               return -EINVAL;
-       e.pattern = tomoyo_get_name(pattern);
-       if (!e.pattern)
-               return -ENOMEM;
-       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
-                                    &tomoyo_policy_list[TOMOYO_ID_PATTERN],
-                                    tomoyo_same_pattern);
-       tomoyo_put_name(e.pattern);
-       return error;
-}
-
-/**
- * tomoyo_pattern - Get patterned pathname.
- *
- * @filename: The filename to find patterned pathname.
- *
- * Returns pointer to pathname pattern if matched, @filename otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-const char *tomoyo_pattern(const struct tomoyo_path_info *filename)
-{
-       struct tomoyo_no_pattern *ptr;
-       const struct tomoyo_path_info *pattern = NULL;
-
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN],
-                               head.list) {
-               if (ptr->head.is_deleted)
-                       continue;
-               if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
-                       continue;
-               pattern = ptr->pattern;
-               if (tomoyo_strendswith(pattern->name, "/\\*")) {
-                       /* Do nothing. Try to find the better match. */
-               } else {
-                       /* This would be the better match. Use this. */
-                       break;
-               }
-       }
-       if (pattern)
-               filename = pattern;
-       return filename->name;
-}
-
-/**
- * tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list.
- *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_pattern(char *data, const bool is_delete)
-{
-       return tomoyo_update_file_pattern_entry(data, is_delete);
-}
-
-static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a,
-                                  const struct tomoyo_acl_head *b)
-{
-       return container_of(a, struct tomoyo_no_rewrite, head)->pattern
-               == container_of(b, struct tomoyo_no_rewrite, head)
-               ->pattern;
-}
-
-/**
- * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list.
- *
- * @pattern:   Pathname pattern that are not rewritable by default.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_update_no_rewrite_entry(const char *pattern,
-                                         const bool is_delete)
-{
-       struct tomoyo_no_rewrite e = { };
-       int error;
-
-       if (!tomoyo_correct_word(pattern))
-               return -EINVAL;
-       e.pattern = tomoyo_get_name(pattern);
-       if (!e.pattern)
-               return -ENOMEM;
-       error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
-                                    &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
-                                    tomoyo_same_no_rewrite);
-       tomoyo_put_name(e.pattern);
-       return error;
+       return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
+                                [tomoyo_pn2mac[type]],
+                                r->param.path_number.filename->name, buffer);
 }
 
 /**
- * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
+ * tomoyo_check_path_acl - Check permission for path operation.
  *
- * @filename: Filename to check.
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
  *
- * Returns true if @filename is specified by "deny_rewrite" directive,
- * false otherwise.
+ * Returns true if granted, false otherwise.
  *
- * Caller holds tomoyo_read_lock().
+ * To be able to use wildcard for domain transition, this function sets
+ * matching entry on success. Since the caller holds tomoyo_read_lock(),
+ * it is safe to set matching entry.
  */
-static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename)
-{
-       struct tomoyo_no_rewrite *ptr;
-       bool found = false;
-
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
-                               head.list) {
-               if (ptr->head.is_deleted)
-                       continue;
-               if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
-                       continue;
-               found = true;
-               break;
-       }
-       return found;
-}
-
-/**
- * tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list.
- *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_no_rewrite(char *data, const bool is_delete)
-{
-       return tomoyo_update_no_rewrite_entry(data, is_delete);
-}
-
 static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
                                  const struct tomoyo_acl_info *ptr)
 {
@@ -521,6 +261,14 @@ static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
        return false;
 }
 
+/**
+ * tomoyo_check_path_number_acl - Check permission for path number operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
 static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
                                         const struct tomoyo_acl_info *ptr)
 {
@@ -533,6 +281,14 @@ static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
                                          &acl->name);
 }
 
+/**
+ * tomoyo_check_path2_acl - Check permission for path path operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
 static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
                                   const struct tomoyo_acl_info *ptr)
 {
@@ -544,8 +300,16 @@ static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
                                             &acl->name2);
 }
 
+/**
+ * tomoyo_check_mkdev_acl - Check permission for path number number number operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
 static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
-                               const struct tomoyo_acl_info *ptr)
+                                  const struct tomoyo_acl_info *ptr)
 {
        const struct tomoyo_mkdev_acl *acl =
                container_of(ptr, typeof(*acl), head);
@@ -560,15 +324,31 @@ static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
                                          &acl->name);
 }
 
+/**
+ * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
 static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
                                 const struct tomoyo_acl_info *b)
 {
        const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
        const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
-       return tomoyo_same_acl_head(&p1->head, &p2->head) &&
-               tomoyo_same_name_union(&p1->name, &p2->name);
+       return tomoyo_same_name_union(&p1->name, &p2->name);
 }
 
+/**
+ * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
 static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
                                  struct tomoyo_acl_info *b,
                                  const bool is_delete)
@@ -577,19 +357,10 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
                ->perm;
        u16 perm = *a_perm;
        const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
-       if (is_delete) {
+       if (is_delete)
                perm &= ~b_perm;
-               if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK)
-                       perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
-               else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE)))
-                       perm &= ~TOMOYO_RW_MASK;
-       } else {
+       else
                perm |= b_perm;
-               if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK)
-                       perm |= (1 << TOMOYO_TYPE_READ_WRITE);
-               else if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
-                       perm |= TOMOYO_RW_MASK;
-       }
        *a_perm = perm;
        return !perm;
 }
@@ -597,52 +368,62 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
 /**
  * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
  *
- * @type:      Type of operation.
- * @filename:  Filename.
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
+ * @perm:  Permission.
+ * @param: Pointer to "struct tomoyo_acl_param".
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_path_acl(const u8 type, const char *filename,
-                                 struct tomoyo_domain_info * const domain,
-                                 const bool is_delete)
+static int tomoyo_update_path_acl(const u16 perm,
+                                 struct tomoyo_acl_param *param)
 {
        struct tomoyo_path_acl e = {
                .head.type = TOMOYO_TYPE_PATH_ACL,
-               .perm = 1 << type
+               .perm = perm
        };
        int error;
-       if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE))
-               e.perm |= TOMOYO_RW_MASK;
-       if (!tomoyo_parse_name_union(filename, &e.name))
-               return -EINVAL;
-       error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
-                                    tomoyo_same_path_acl,
-                                    tomoyo_merge_path_acl);
+       if (!tomoyo_parse_name_union(param, &e.name))
+               error = -EINVAL;
+       else
+               error = tomoyo_update_domain(&e.head, sizeof(e), param,
+                                            tomoyo_same_path_acl,
+                                            tomoyo_merge_path_acl);
        tomoyo_put_name_union(&e.name);
        return error;
 }
 
+/**
+ * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
 static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
                                         const struct tomoyo_acl_info *b)
 {
-       const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1),
-                                                               head);
-       const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2),
-                                                               head);
-       return tomoyo_same_acl_head(&p1->head, &p2->head)
-               && tomoyo_same_name_union(&p1->name, &p2->name)
-               && tomoyo_same_number_union(&p1->mode, &p2->mode)
-               && tomoyo_same_number_union(&p1->major, &p2->major)
-               && tomoyo_same_number_union(&p1->minor, &p2->minor);
+       const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
+       const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
+       return tomoyo_same_name_union(&p1->name, &p2->name) &&
+               tomoyo_same_number_union(&p1->mode, &p2->mode) &&
+               tomoyo_same_number_union(&p1->major, &p2->major) &&
+               tomoyo_same_number_union(&p1->minor, &p2->minor);
 }
 
+/**
+ * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
 static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
-                                         struct tomoyo_acl_info *b,
-                                         const bool is_delete)
+                                  struct tomoyo_acl_info *b,
+                                  const bool is_delete)
 {
        u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
                                         head)->perm;
@@ -660,37 +441,30 @@ static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
 /**
  * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
  *
- * @type:      Type of operation.
- * @filename:  Filename.
- * @mode:      Create mode.
- * @major:     Device major number.
- * @minor:     Device minor number.
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
+ * @perm:  Permission.
+ * @param: Pointer to "struct tomoyo_acl_param".
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
-                                         char *mode, char *major, char *minor,
-                                         struct tomoyo_domain_info * const
-                                         domain, const bool is_delete)
+static int tomoyo_update_mkdev_acl(const u8 perm,
+                                  struct tomoyo_acl_param *param)
 {
        struct tomoyo_mkdev_acl e = {
                .head.type = TOMOYO_TYPE_MKDEV_ACL,
-               .perm = 1 << type
+               .perm = perm
        };
-       int error = is_delete ? -ENOENT : -ENOMEM;
-       if (!tomoyo_parse_name_union(filename, &e.name) ||
-           !tomoyo_parse_number_union(mode, &e.mode) ||
-           !tomoyo_parse_number_union(major, &e.major) ||
-           !tomoyo_parse_number_union(minor, &e.minor))
-               goto out;
-       error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
-                                    tomoyo_same_mkdev_acl,
-                                    tomoyo_merge_mkdev_acl);
- out:
+       int error;
+       if (!tomoyo_parse_name_union(param, &e.name) ||
+           !tomoyo_parse_number_union(param, &e.mode) ||
+           !tomoyo_parse_number_union(param, &e.major) ||
+           !tomoyo_parse_number_union(param, &e.minor))
+               error = -EINVAL;
+       else
+               error = tomoyo_update_domain(&e.head, sizeof(e), param,
+                                            tomoyo_same_mkdev_acl,
+                                            tomoyo_merge_mkdev_acl);
        tomoyo_put_name_union(&e.name);
        tomoyo_put_number_union(&e.mode);
        tomoyo_put_number_union(&e.major);
@@ -698,16 +472,32 @@ static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
        return error;
 }
 
+/**
+ * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
 static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
                                  const struct tomoyo_acl_info *b)
 {
        const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
        const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
-       return tomoyo_same_acl_head(&p1->head, &p2->head)
-               && tomoyo_same_name_union(&p1->name1, &p2->name1)
-               && tomoyo_same_name_union(&p1->name2, &p2->name2);
+       return tomoyo_same_name_union(&p1->name1, &p2->name1) &&
+               tomoyo_same_name_union(&p1->name2, &p2->name2);
 }
 
+/**
+ * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
 static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
                                   struct tomoyo_acl_info *b,
                                   const bool is_delete)
@@ -727,33 +517,28 @@ static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
 /**
  * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
  *
- * @type:      Type of operation.
- * @filename1: First filename.
- * @filename2: Second filename.
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
+ * @perm:  Permission.
+ * @param: Pointer to "struct tomoyo_acl_param".
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
-                                  const char *filename2,
-                                  struct tomoyo_domain_info * const domain,
-                                  const bool is_delete)
+static int tomoyo_update_path2_acl(const u8 perm,
+                                  struct tomoyo_acl_param *param)
 {
        struct tomoyo_path2_acl e = {
                .head.type = TOMOYO_TYPE_PATH2_ACL,
-               .perm = 1 << type
+               .perm = perm
        };
-       int error = is_delete ? -ENOENT : -ENOMEM;
-       if (!tomoyo_parse_name_union(filename1, &e.name1) ||
-           !tomoyo_parse_name_union(filename2, &e.name2))
-               goto out;
-       error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
-                                    tomoyo_same_path2_acl,
-                                    tomoyo_merge_path2_acl);
- out:
+       int error;
+       if (!tomoyo_parse_name_union(param, &e.name1) ||
+           !tomoyo_parse_name_union(param, &e.name2))
+               error = -EINVAL;
+       else
+               error = tomoyo_update_domain(&e.head, sizeof(e), param,
+                                            tomoyo_same_path2_acl,
+                                            tomoyo_merge_path2_acl);
        tomoyo_put_name_union(&e.name1);
        tomoyo_put_name_union(&e.name2);
        return error;
@@ -775,9 +560,8 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
 {
        int error;
 
- next:
        r->type = tomoyo_p2mac[operation];
-       r->mode = tomoyo_get_mode(r->profile, r->type);
+       r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
        if (r->mode == TOMOYO_CONFIG_DISABLED)
                return 0;
        r->param_type = TOMOYO_TYPE_PATH_ACL;
@@ -785,10 +569,6 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
        r->param.path.operation = operation;
        do {
                tomoyo_check_acl(r, tomoyo_check_path_acl);
-               if (!r->granted && operation == TOMOYO_TYPE_READ &&
-                   !r->domain->ignore_global_allow_read &&
-                   tomoyo_globally_readable_file(filename))
-                       r->granted = true;
                error = tomoyo_audit_path_log(r);
                /*
                 * Do not retry for execute request, for alias may have
@@ -796,19 +576,17 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
                 */
        } while (error == TOMOYO_RETRY_REQUEST &&
                 operation != TOMOYO_TYPE_EXECUTE);
-       /*
-        * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
-        * we need to check "allow_rewrite" permission if the filename is
-        * specified by "deny_rewrite" keyword.
-        */
-       if (!error && operation == TOMOYO_TYPE_TRUNCATE &&
-           tomoyo_no_rewrite_file(filename)) {
-               operation = TOMOYO_TYPE_REWRITE;
-               goto next;
-       }
        return error;
 }
 
+/**
+ * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b except permission bits, false otherwise.
+ */
 static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
                                        const struct tomoyo_acl_info *b)
 {
@@ -816,11 +594,19 @@ static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
                                                               head);
        const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
                                                               head);
-       return tomoyo_same_acl_head(&p1->head, &p2->head)
-               && tomoyo_same_name_union(&p1->name, &p2->name)
-               && tomoyo_same_number_union(&p1->number, &p2->number);
+       return tomoyo_same_name_union(&p1->name, &p2->name) &&
+               tomoyo_same_number_union(&p1->number, &p2->number);
 }
 
+/**
+ * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry.
+ *
+ * @a:         Pointer to "struct tomoyo_acl_info".
+ * @b:         Pointer to "struct tomoyo_acl_info".
+ * @is_delete: True for @a &= ~@b, false for @a |= @b.
+ *
+ * Returns true if @a is empty, false otherwise.
+ */
 static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
                                         struct tomoyo_acl_info *b,
                                         const bool is_delete)
@@ -841,33 +627,26 @@ static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
 /**
  * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
  *
- * @type:      Type of operation.
- * @filename:  Filename.
- * @number:    Number.
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
+ * @perm:  Permission.
+ * @param: Pointer to "struct tomoyo_acl_param".
  *
  * Returns 0 on success, negative value otherwise.
  */
-static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
-                                        char *number,
-                                        struct tomoyo_domain_info * const
-                                        domain,
-                                        const bool is_delete)
+static int tomoyo_update_path_number_acl(const u8 perm,
+                                        struct tomoyo_acl_param *param)
 {
        struct tomoyo_path_number_acl e = {
                .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
-               .perm = 1 << type
+               .perm = perm
        };
-       int error = is_delete ? -ENOENT : -ENOMEM;
-       if (!tomoyo_parse_name_union(filename, &e.name))
-               return -EINVAL;
-       if (!tomoyo_parse_number_union(number, &e.number))
-               goto out;
-       error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
-                                    tomoyo_same_path_number_acl,
-                                    tomoyo_merge_path_number_acl);
- out:
+       int error;
+       if (!tomoyo_parse_name_union(param, &e.name) ||
+           !tomoyo_parse_number_union(param, &e.number))
+               error = -EINVAL;
+       else
+               error = tomoyo_update_domain(&e.head, sizeof(e), param,
+                                            tomoyo_same_path_number_acl,
+                                            tomoyo_merge_path_number_acl);
        tomoyo_put_name_union(&e.name);
        tomoyo_put_number_union(&e.number);
        return error;
@@ -886,16 +665,20 @@ int tomoyo_path_number_perm(const u8 type, struct path *path,
                            unsigned long number)
 {
        struct tomoyo_request_info r;
+       struct tomoyo_obj_info obj = {
+               .path1 = *path,
+       };
        int error = -ENOMEM;
        struct tomoyo_path_info buf;
        int idx;
 
        if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
-           == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
+           == TOMOYO_CONFIG_DISABLED || !path->dentry)
                return 0;
        idx = tomoyo_read_lock();
        if (!tomoyo_get_realpath(&buf, path))
                goto out;
+       r.obj = &obj;
        if (type == TOMOYO_TYPE_MKDIR)
                tomoyo_add_slash(&buf);
        r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
@@ -930,45 +713,30 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
        int error = 0;
        struct tomoyo_path_info buf;
        struct tomoyo_request_info r;
+       struct tomoyo_obj_info obj = {
+               .path1 = *path,
+       };
        int idx;
 
-       if (!path->mnt ||
-           (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
-               return 0;
        buf.name = NULL;
        r.mode = TOMOYO_CONFIG_DISABLED;
        idx = tomoyo_read_lock();
-       /*
-        * If the filename is specified by "deny_rewrite" keyword,
-        * we need to check "allow_rewrite" permission when the filename is not
-        * opened for append mode or the filename is truncated at open time.
-        */
-       if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
-           && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
+       if (acc_mode &&
+           tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
            != TOMOYO_CONFIG_DISABLED) {
                if (!tomoyo_get_realpath(&buf, path)) {
                        error = -ENOMEM;
                        goto out;
                }
-               if (tomoyo_no_rewrite_file(&buf))
-                       error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
+               r.obj = &obj;
+               if (acc_mode & MAY_READ)
+                       error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ,
+                                                      &buf);
+               if (!error && (acc_mode & MAY_WRITE))
+                       error = tomoyo_path_permission(&r, (flag & O_APPEND) ?
+                                                      TOMOYO_TYPE_APPEND :
+                                                      TOMOYO_TYPE_WRITE,
                                                       &buf);
-       }
-       if (!error && acc_mode &&
-           tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
-           != TOMOYO_CONFIG_DISABLED) {
-               u8 operation;
-               if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
-                       error = -ENOMEM;
-                       goto out;
-               }
-               if (acc_mode == (MAY_READ | MAY_WRITE))
-                       operation = TOMOYO_TYPE_READ_WRITE;
-               else if (acc_mode == MAY_READ)
-                       operation = TOMOYO_TYPE_READ;
-               else
-                       operation = TOMOYO_TYPE_WRITE;
-               error = tomoyo_path_permission(&r, operation, &buf);
        }
  out:
        kfree(buf.name);
@@ -979,46 +747,57 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
 }
 
 /**
- * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount".
+ * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount".
  *
  * @operation: Type of operation.
  * @path:      Pointer to "struct path".
+ * @target:    Symlink's target if @operation is TOMOYO_TYPE_SYMLINK,
+ *             NULL otherwise.
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_path_perm(const u8 operation, struct path *path)
+int tomoyo_path_perm(const u8 operation, struct path *path, const char *target)
 {
-       int error = -ENOMEM;
-       struct tomoyo_path_info buf;
        struct tomoyo_request_info r;
+       struct tomoyo_obj_info obj = {
+               .path1 = *path,
+       };
+       int error;
+       struct tomoyo_path_info buf;
+       bool is_enforce;
+       struct tomoyo_path_info symlink_target;
        int idx;
 
-       if (!path->mnt)
-               return 0;
        if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
            == TOMOYO_CONFIG_DISABLED)
                return 0;
+       is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);
+       error = -ENOMEM;
        buf.name = NULL;
        idx = tomoyo_read_lock();
        if (!tomoyo_get_realpath(&buf, path))
                goto out;
+       r.obj = &obj;
        switch (operation) {
-       case TOMOYO_TYPE_REWRITE:
-               if (!tomoyo_no_rewrite_file(&buf)) {
-                       error = 0;
-                       goto out;
-               }
-               break;
        case TOMOYO_TYPE_RMDIR:
        case TOMOYO_TYPE_CHROOT:
                tomoyo_add_slash(&buf);
                break;
+       case TOMOYO_TYPE_SYMLINK:
+               symlink_target.name = tomoyo_encode(target);
+               if (!symlink_target.name)
+                       goto out;
+               tomoyo_fill_path_info(&symlink_target);
+               obj.symlink_target = &symlink_target;
+               break;
        }
        error = tomoyo_path_permission(&r, operation, &buf);
+       if (operation == TOMOYO_TYPE_SYMLINK)
+               kfree(symlink_target.name);
  out:
        kfree(buf.name);
        tomoyo_read_unlock(idx);
-       if (r.mode != TOMOYO_CONFIG_ENFORCING)
+       if (!is_enforce)
                error = 0;
        return error;
 }
@@ -1034,20 +813,23 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
  * Returns 0 on success, negative value otherwise.
  */
 int tomoyo_mkdev_perm(const u8 operation, struct path *path,
-                            const unsigned int mode, unsigned int dev)
+                     const unsigned int mode, unsigned int dev)
 {
        struct tomoyo_request_info r;
+       struct tomoyo_obj_info obj = {
+               .path1 = *path,
+       };
        int error = -ENOMEM;
        struct tomoyo_path_info buf;
        int idx;
 
-       if (!path->mnt ||
-           tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
+       if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
            == TOMOYO_CONFIG_DISABLED)
                return 0;
        idx = tomoyo_read_lock();
        error = -ENOMEM;
        if (tomoyo_get_realpath(&buf, path)) {
+               r.obj = &obj;
                dev = new_decode_dev(dev);
                r.param_type = TOMOYO_TYPE_MKDEV_ACL;
                r.param.mkdev.filename = &buf;
@@ -1081,10 +863,13 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
        struct tomoyo_path_info buf1;
        struct tomoyo_path_info buf2;
        struct tomoyo_request_info r;
+       struct tomoyo_obj_info obj = {
+               .path1 = *path1,
+               .path2 = *path2,
+       };
        int idx;
 
-       if (!path1->mnt || !path2->mnt ||
-           tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
+       if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
            == TOMOYO_CONFIG_DISABLED)
                return 0;
        buf1.name = NULL;
@@ -1096,16 +881,17 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
        switch (operation) {
                struct dentry *dentry;
        case TOMOYO_TYPE_RENAME:
-        case TOMOYO_TYPE_LINK:
+       case TOMOYO_TYPE_LINK:
                dentry = path1->dentry;
-               if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
-                        break;
-                /* fall through */
-        case TOMOYO_TYPE_PIVOT_ROOT:
-                tomoyo_add_slash(&buf1);
-                tomoyo_add_slash(&buf2);
+               if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
+                       break;
+               /* fall through */
+       case TOMOYO_TYPE_PIVOT_ROOT:
+               tomoyo_add_slash(&buf1);
+               tomoyo_add_slash(&buf2);
                break;
-        }
+       }
+       r.obj = &obj;
        r.param_type = TOMOYO_TYPE_PATH2_ACL;
        r.param.path2.operation = operation;
        r.param.path2.filename1 = &buf1;
@@ -1123,54 +909,92 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
        return error;
 }
 
+/**
+ * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_info".
+ * @b: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
+static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
+                                 const struct tomoyo_acl_info *b)
+{
+       const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
+       const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
+       return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
+               tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
+               tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
+               tomoyo_same_number_union(&p1->flags, &p2->flags);
+}
+
+/**
+ * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param)
+{
+       struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
+       int error;
+       if (!tomoyo_parse_name_union(param, &e.dev_name) ||
+           !tomoyo_parse_name_union(param, &e.dir_name) ||
+           !tomoyo_parse_name_union(param, &e.fs_type) ||
+           !tomoyo_parse_number_union(param, &e.flags))
+               error = -EINVAL;
+       else
+               error = tomoyo_update_domain(&e.head, sizeof(e), param,
+                                            tomoyo_same_mount_acl, NULL);
+       tomoyo_put_name_union(&e.dev_name);
+       tomoyo_put_name_union(&e.dir_name);
+       tomoyo_put_name_union(&e.fs_type);
+       tomoyo_put_number_union(&e.flags);
+       return error;
+}
+
 /**
  * tomoyo_write_file - Update file related list.
  *
- * @data:      String to parse.
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
+ * @param: Pointer to "struct tomoyo_acl_param".
  *
  * Returns 0 on success, negative value otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
-                     const bool is_delete)
+int tomoyo_write_file(struct tomoyo_acl_param *param)
 {
-       char *w[5];
+       u16 perm = 0;
        u8 type;
-       if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
-               return -EINVAL;
-       if (strncmp(w[0], "allow_", 6))
-               goto out;
-       w[0] += 6;
-       for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
-               if (strcmp(w[0], tomoyo_path_keyword[type]))
-                       continue;
-               return tomoyo_update_path_acl(type, w[1], domain, is_delete);
-       }
-       if (!w[2][0])
-               goto out;
-       for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
-               if (strcmp(w[0], tomoyo_path2_keyword[type]))
-                       continue;
-               return tomoyo_update_path2_acl(type, w[1], w[2], domain,
-                                              is_delete);
-       }
-       for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
-               if (strcmp(w[0], tomoyo_path_number_keyword[type]))
-                       continue;
-               return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
-                                                    is_delete);
-       }
-       if (!w[3][0] || !w[4][0])
-               goto out;
-       for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) {
-               if (strcmp(w[0], tomoyo_mkdev_keyword[type]))
-                       continue;
-               return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3],
-                                              w[4], domain, is_delete);
-       }
- out:
+       const char *operation = tomoyo_read_token(param);
+       for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++)
+               if (tomoyo_permstr(operation, tomoyo_path_keyword[type]))
+                       perm |= 1 << type;
+       if (perm)
+               return tomoyo_update_path_acl(perm, param);
+       for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++)
+               if (tomoyo_permstr(operation,
+                                  tomoyo_mac_keywords[tomoyo_pp2mac[type]]))
+                       perm |= 1 << type;
+       if (perm)
+               return tomoyo_update_path2_acl(perm, param);
+       for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++)
+               if (tomoyo_permstr(operation,
+                                  tomoyo_mac_keywords[tomoyo_pn2mac[type]]))
+                       perm |= 1 << type;
+       if (perm)
+               return tomoyo_update_path_number_acl(perm, param);
+       for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++)
+               if (tomoyo_permstr(operation,
+                                  tomoyo_mac_keywords[tomoyo_pnnn2mac[type]]))
+                       perm |= 1 << type;
+       if (perm)
+               return tomoyo_update_mkdev_acl(perm, param);
+       if (tomoyo_permstr(operation,
+                          tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT]))
+               return tomoyo_update_mount_acl(param);
        return -EINVAL;
 }
index a877e4c3b1019d962da68ad792816d8e6aa28e1d..ae135fbbbe955b922c0fe3dbe6d8d158dc6fa9d1 100644 (file)
 /*
  * security/tomoyo/gc.c
  *
- * Implementation of the Domain-Based Mandatory Access Control.
- *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
- *
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include "common.h"
 #include <linux/kthread.h>
 #include <linux/slab.h>
 
+/* The list for "struct tomoyo_io_buffer". */
+static LIST_HEAD(tomoyo_io_buffer_list);
+/* Lock for protecting tomoyo_io_buffer_list. */
+static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock);
+
+/* Size of an element. */
+static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = {
+       [TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group),
+       [TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group),
+       [TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group),
+       [TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator),
+       [TOMOYO_ID_TRANSITION_CONTROL] =
+       sizeof(struct tomoyo_transition_control),
+       [TOMOYO_ID_MANAGER] = sizeof(struct tomoyo_manager),
+       /* [TOMOYO_ID_CONDITION] = "struct tomoyo_condition"->size, */
+       /* [TOMOYO_ID_NAME] = "struct tomoyo_name"->size, */
+       /* [TOMOYO_ID_ACL] =
+          tomoyo_acl_size["struct tomoyo_acl_info"->type], */
+       [TOMOYO_ID_DOMAIN] = sizeof(struct tomoyo_domain_info),
+};
+
+/* Size of a domain ACL element. */
+static const u8 tomoyo_acl_size[] = {
+       [TOMOYO_TYPE_PATH_ACL] = sizeof(struct tomoyo_path_acl),
+       [TOMOYO_TYPE_PATH2_ACL] = sizeof(struct tomoyo_path2_acl),
+       [TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl),
+       [TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl),
+       [TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl),
+};
+
+/**
+ * tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not.
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns true if @element is used by /sys/kernel/security/tomoyo/ users,
+ * false otherwise.
+ */
+static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element)
+{
+       struct tomoyo_io_buffer *head;
+       bool in_use = false;
+
+       spin_lock(&tomoyo_io_buffer_list_lock);
+       list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
+               head->users++;
+               spin_unlock(&tomoyo_io_buffer_list_lock);
+               if (mutex_lock_interruptible(&head->io_sem)) {
+                       in_use = true;
+                       goto out;
+               }
+               if (head->r.domain == element || head->r.group == element ||
+                   head->r.acl == element || &head->w.domain->list == element)
+                       in_use = true;
+               mutex_unlock(&head->io_sem);
+out:
+               spin_lock(&tomoyo_io_buffer_list_lock);
+               head->users--;
+               if (in_use)
+                       break;
+       }
+       spin_unlock(&tomoyo_io_buffer_list_lock);
+       return in_use;
+}
+
+/**
+ * tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not.
+ *
+ * @string: String to check.
+ * @size:   Memory allocated for @string .
+ *
+ * Returns true if @string is used by /sys/kernel/security/tomoyo/ users,
+ * false otherwise.
+ */
+static bool tomoyo_name_used_by_io_buffer(const char *string,
+                                         const size_t size)
+{
+       struct tomoyo_io_buffer *head;
+       bool in_use = false;
+
+       spin_lock(&tomoyo_io_buffer_list_lock);
+       list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
+               int i;
+               head->users++;
+               spin_unlock(&tomoyo_io_buffer_list_lock);
+               if (mutex_lock_interruptible(&head->io_sem)) {
+                       in_use = true;
+                       goto out;
+               }
+               for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) {
+                       const char *w = head->r.w[i];
+                       if (w < string || w > string + size)
+                               continue;
+                       in_use = true;
+                       break;
+               }
+               mutex_unlock(&head->io_sem);
+out:
+               spin_lock(&tomoyo_io_buffer_list_lock);
+               head->users--;
+               if (in_use)
+                       break;
+       }
+       spin_unlock(&tomoyo_io_buffer_list_lock);
+       return in_use;
+}
+
+/* Structure for garbage collection. */
 struct tomoyo_gc {
        struct list_head list;
-       int type;
+       enum tomoyo_policy_id type;
+       size_t size;
        struct list_head *element;
 };
-static LIST_HEAD(tomoyo_gc_queue);
-static DEFINE_MUTEX(tomoyo_gc_mutex);
+/* List of entries to be deleted. */
+static LIST_HEAD(tomoyo_gc_list);
+/* Length of tomoyo_gc_list. */
+static int tomoyo_gc_list_len;
 
-/* Caller holds tomoyo_policy_lock mutex. */
+/**
+ * tomoyo_add_to_gc - Add an entry to to be deleted list.
+ *
+ * @type:    One of values in "enum tomoyo_policy_id".
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_policy_lock mutex.
+ *
+ * Adding an entry needs kmalloc(). Thus, if we try to add thousands of
+ * entries at once, it will take too long time. Thus, do not add more than 128
+ * entries per a scan. But to be able to handle worst case where all entries
+ * are in-use, we accept one more entry per a scan.
+ *
+ * If we use singly linked list using "struct list_head"->prev (which is
+ * LIST_POISON2), we can avoid kmalloc().
+ */
 static bool tomoyo_add_to_gc(const int type, struct list_head *element)
 {
        struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
        if (!entry)
                return false;
        entry->type = type;
+       if (type == TOMOYO_ID_ACL)
+               entry->size = tomoyo_acl_size[
+                             container_of(element,
+                                          typeof(struct tomoyo_acl_info),
+                                          list)->type];
+       else if (type == TOMOYO_ID_NAME)
+               entry->size = strlen(container_of(element,
+                                                 typeof(struct tomoyo_name),
+                                                 head.list)->entry.name) + 1;
+       else if (type == TOMOYO_ID_CONDITION)
+               entry->size =
+                       container_of(element, typeof(struct tomoyo_condition),
+                                    head.list)->size;
+       else
+               entry->size = tomoyo_element_size[type];
        entry->element = element;
-       list_add(&entry->list, &tomoyo_gc_queue);
+       list_add(&entry->list, &tomoyo_gc_list);
        list_del_rcu(element);
-       return true;
+       return tomoyo_gc_list_len++ < 128;
 }
 
-static void tomoyo_del_allow_read(struct list_head *element)
-{
-       struct tomoyo_readable_file *ptr =
-               container_of(element, typeof(*ptr), head.list);
-       tomoyo_put_name(ptr->filename);
-}
-
-static void tomoyo_del_file_pattern(struct list_head *element)
-{
-       struct tomoyo_no_pattern *ptr =
-               container_of(element, typeof(*ptr), head.list);
-       tomoyo_put_name(ptr->pattern);
-}
-
-static void tomoyo_del_no_rewrite(struct list_head *element)
+/**
+ * tomoyo_element_linked_by_gc - Validate next element of an entry.
+ *
+ * @element: Pointer to an element.
+ * @size:    Size of @element in byte.
+ *
+ * Returns true if @element is linked by other elements in the garbage
+ * collector's queue, false otherwise.
+ */
+static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size)
 {
-       struct tomoyo_no_rewrite *ptr =
-               container_of(element, typeof(*ptr), head.list);
-       tomoyo_put_name(ptr->pattern);
+       struct tomoyo_gc *p;
+       list_for_each_entry(p, &tomoyo_gc_list, list) {
+               const u8 *ptr = (const u8 *) p->element->next;
+               if (ptr < element || element + size < ptr)
+                       continue;
+               return true;
+       }
+       return false;
 }
 
+/**
+ * tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
 static void tomoyo_del_transition_control(struct list_head *element)
 {
        struct tomoyo_transition_control *ptr =
@@ -61,6 +208,13 @@ static void tomoyo_del_transition_control(struct list_head *element)
        tomoyo_put_name(ptr->program);
 }
 
+/**
+ * tomoyo_del_aggregator - Delete members in "struct tomoyo_aggregator".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
 static void tomoyo_del_aggregator(struct list_head *element)
 {
        struct tomoyo_aggregator *ptr =
@@ -69,6 +223,13 @@ static void tomoyo_del_aggregator(struct list_head *element)
        tomoyo_put_name(ptr->aggregated_name);
 }
 
+/**
+ * tomoyo_del_manager - Delete members in "struct tomoyo_manager".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
 static void tomoyo_del_manager(struct list_head *element)
 {
        struct tomoyo_manager *ptr =
@@ -76,10 +237,18 @@ static void tomoyo_del_manager(struct list_head *element)
        tomoyo_put_name(ptr->manager);
 }
 
+/**
+ * tomoyo_del_acl - Delete members in "struct tomoyo_acl_info".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
 static void tomoyo_del_acl(struct list_head *element)
 {
        struct tomoyo_acl_info *acl =
                container_of(element, typeof(*acl), list);
+       tomoyo_put_condition(acl->cond);
        switch (acl->type) {
        case TOMOYO_TYPE_PATH_ACL:
                {
@@ -127,6 +296,13 @@ static void tomoyo_del_acl(struct list_head *element)
        }
 }
 
+/**
+ * tomoyo_del_domain - Delete members in "struct tomoyo_domain_info".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns true if deleted, false otherwise.
+ */
 static bool tomoyo_del_domain(struct list_head *element)
 {
        struct tomoyo_domain_info *domain =
@@ -165,13 +341,65 @@ static bool tomoyo_del_domain(struct list_head *element)
        return true;
 }
 
+/**
+ * tomoyo_del_condition - Delete members in "struct tomoyo_condition".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
+void tomoyo_del_condition(struct list_head *element)
+{
+       struct tomoyo_condition *cond = container_of(element, typeof(*cond),
+                                                    head.list);
+       const u16 condc = cond->condc;
+       const u16 numbers_count = cond->numbers_count;
+       const u16 names_count = cond->names_count;
+       const u16 argc = cond->argc;
+       const u16 envc = cond->envc;
+       unsigned int i;
+       const struct tomoyo_condition_element *condp
+               = (const struct tomoyo_condition_element *) (cond + 1);
+       struct tomoyo_number_union *numbers_p
+               = (struct tomoyo_number_union *) (condp + condc);
+       struct tomoyo_name_union *names_p
+               = (struct tomoyo_name_union *) (numbers_p + numbers_count);
+       const struct tomoyo_argv *argv
+               = (const struct tomoyo_argv *) (names_p + names_count);
+       const struct tomoyo_envp *envp
+               = (const struct tomoyo_envp *) (argv + argc);
+       for (i = 0; i < numbers_count; i++)
+               tomoyo_put_number_union(numbers_p++);
+       for (i = 0; i < names_count; i++)
+               tomoyo_put_name_union(names_p++);
+       for (i = 0; i < argc; argv++, i++)
+               tomoyo_put_name(argv->value);
+       for (i = 0; i < envc; envp++, i++) {
+               tomoyo_put_name(envp->name);
+               tomoyo_put_name(envp->value);
+       }
+}
 
+/**
+ * tomoyo_del_name - Delete members in "struct tomoyo_name".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
 static void tomoyo_del_name(struct list_head *element)
 {
        const struct tomoyo_name *ptr =
-               container_of(element, typeof(*ptr), list);
+               container_of(element, typeof(*ptr), head.list);
 }
 
+/**
+ * tomoyo_del_path_group - Delete members in "struct tomoyo_path_group".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
 static void tomoyo_del_path_group(struct list_head *element)
 {
        struct tomoyo_path_group *member =
@@ -179,20 +407,43 @@ static void tomoyo_del_path_group(struct list_head *element)
        tomoyo_put_name(member->member_name);
 }
 
+/**
+ * tomoyo_del_group - Delete "struct tomoyo_group".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
 static void tomoyo_del_group(struct list_head *element)
 {
        struct tomoyo_group *group =
-               container_of(element, typeof(*group), list);
+               container_of(element, typeof(*group), head.list);
        tomoyo_put_name(group->group_name);
 }
 
+/**
+ * tomoyo_del_number_group - Delete members in "struct tomoyo_number_group".
+ *
+ * @element: Pointer to "struct list_head".
+ *
+ * Returns nothing.
+ */
 static void tomoyo_del_number_group(struct list_head *element)
 {
        struct tomoyo_number_group *member =
                container_of(element, typeof(*member), head.list);
 }
 
-static bool tomoyo_collect_member(struct list_head *member_list, int id)
+/**
+ * tomoyo_collect_member - Delete elements with "struct tomoyo_acl_head".
+ *
+ * @id:          One of values in "enum tomoyo_policy_id".
+ * @member_list: Pointer to "struct list_head".
+ *
+ * Returns true if some elements are deleted, false otherwise.
+ */
+static bool tomoyo_collect_member(const enum tomoyo_policy_id id,
+                                 struct list_head *member_list)
 {
        struct tomoyo_acl_head *member;
        list_for_each_entry(member, member_list, list) {
@@ -201,13 +452,20 @@ static bool tomoyo_collect_member(struct list_head *member_list, int id)
                if (!tomoyo_add_to_gc(id, &member->list))
                        return false;
        }
-        return true;
+       return true;
 }
 
-static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain)
+/**
+ * tomoyo_collect_acl - Delete elements in "struct tomoyo_domain_info".
+ *
+ * @list: Pointer to "struct list_head".
+ *
+ * Returns true if some elements are deleted, false otherwise.
+ */
+static bool tomoyo_collect_acl(struct list_head *list)
 {
        struct tomoyo_acl_info *acl;
-       list_for_each_entry(acl, &domain->acl_info_list, list) {
+       list_for_each_entry(acl, list, list) {
                if (!acl->is_deleted)
                        continue;
                if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
@@ -216,19 +474,24 @@ static bool tomoyo_collect_acl(struct tomoyo_domain_info *domain)
        return true;
 }
 
+/**
+ * tomoyo_collect_entry - Scan lists for deleted elements.
+ *
+ * Returns nothing.
+ */
 static void tomoyo_collect_entry(void)
 {
        int i;
+       enum tomoyo_policy_id id;
+       struct tomoyo_policy_namespace *ns;
+       int idx;
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                return;
-       for (i = 0; i < TOMOYO_MAX_POLICY; i++) {
-               if (!tomoyo_collect_member(&tomoyo_policy_list[i], i))
-                       goto unlock;
-       }
+       idx = tomoyo_read_lock();
        {
                struct tomoyo_domain_info *domain;
                list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
-                       if (!tomoyo_collect_acl(domain))
+                       if (!tomoyo_collect_acl(&domain->acl_info_list))
                                goto unlock;
                        if (!domain->is_deleted || atomic_read(&domain->users))
                                continue;
@@ -241,48 +504,93 @@ static void tomoyo_collect_entry(void)
                                goto unlock;
                }
        }
-       for (i = 0; i < TOMOYO_MAX_HASH; i++) {
-               struct tomoyo_name *ptr;
-               list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], list) {
-                       if (atomic_read(&ptr->users))
-                               continue;
-                       if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
+       list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) {
+               for (id = 0; id < TOMOYO_MAX_POLICY; id++)
+                       if (!tomoyo_collect_member(id, &ns->policy_list[id]))
                                goto unlock;
+               for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
+                       if (!tomoyo_collect_acl(&ns->acl_group[i]))
+                               goto unlock;
+               for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
+                       struct list_head *list = &ns->group_list[i];
+                       struct tomoyo_group *group;
+                       switch (i) {
+                       case 0:
+                               id = TOMOYO_ID_PATH_GROUP;
+                               break;
+                       default:
+                               id = TOMOYO_ID_NUMBER_GROUP;
+                               break;
+                       }
+                       list_for_each_entry(group, list, head.list) {
+                               if (!tomoyo_collect_member
+                                   (id, &group->member_list))
+                                       goto unlock;
+                               if (!list_empty(&group->member_list) ||
+                                   atomic_read(&group->head.users))
+                                       continue;
+                               if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP,
+                                                     &group->head.list))
+                                       goto unlock;
+                       }
                }
        }
-       for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
-               struct list_head *list = &tomoyo_group_list[i];
-               int id;
-               struct tomoyo_group *group;
-               switch (i) {
-               case 0:
-                       id = TOMOYO_ID_PATH_GROUP;
-                       break;
-               default:
-                       id = TOMOYO_ID_NUMBER_GROUP;
-                       break;
-               }
-               list_for_each_entry(group, list, list) {
-                       if (!tomoyo_collect_member(&group->member_list, id))
-                               goto unlock;
-                       if (!list_empty(&group->member_list) ||
-                           atomic_read(&group->users))
+       id = TOMOYO_ID_CONDITION;
+       for (i = 0; i < TOMOYO_MAX_HASH + 1; i++) {
+               struct list_head *list = !i ?
+                       &tomoyo_condition_list : &tomoyo_name_list[i - 1];
+               struct tomoyo_shared_acl_head *ptr;
+               list_for_each_entry(ptr, list, list) {
+                       if (atomic_read(&ptr->users))
                                continue;
-                       if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP, &group->list))
+                       if (!tomoyo_add_to_gc(id, &ptr->list))
                                goto unlock;
                }
+               id = TOMOYO_ID_NAME;
        }
- unlock:
+unlock:
+       tomoyo_read_unlock(idx);
        mutex_unlock(&tomoyo_policy_lock);
 }
 
-static void tomoyo_kfree_entry(void)
+/**
+ * tomoyo_kfree_entry - Delete entries in tomoyo_gc_list.
+ *
+ * Returns true if some entries were kfree()d, false otherwise.
+ */
+static bool tomoyo_kfree_entry(void)
 {
        struct tomoyo_gc *p;
        struct tomoyo_gc *tmp;
+       bool result = false;
 
-       list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) {
+       list_for_each_entry_safe(p, tmp, &tomoyo_gc_list, list) {
                struct list_head *element = p->element;
+
+               /*
+                * list_del_rcu() in tomoyo_add_to_gc() guarantees that the
+                * list element became no longer reachable from the list which
+                * the element was originally on (e.g. tomoyo_domain_list).
+                * Also, synchronize_srcu() in tomoyo_gc_thread() guarantees
+                * that the list element became no longer referenced by syscall
+                * users.
+                *
+                * However, there are three users which may still be using the
+                * list element. We need to defer until all of these users
+                * forget the list element.
+                *
+                * Firstly, defer until "struct tomoyo_io_buffer"->r.{domain,
+                * group,acl} and "struct tomoyo_io_buffer"->w.domain forget
+                * the list element.
+                */
+               if (tomoyo_struct_used_by_io_buffer(element))
+                       continue;
+               /*
+                * Secondly, defer until all other elements in the
+                * tomoyo_gc_list list forget the list element.
+                */
+               if (tomoyo_element_linked_by_gc((const u8 *) element, p->size))
+                       continue;
                switch (p->type) {
                case TOMOYO_ID_TRANSITION_CONTROL:
                        tomoyo_del_transition_control(element);
@@ -290,19 +598,21 @@ static void tomoyo_kfree_entry(void)
                case TOMOYO_ID_AGGREGATOR:
                        tomoyo_del_aggregator(element);
                        break;
-               case TOMOYO_ID_GLOBALLY_READABLE:
-                       tomoyo_del_allow_read(element);
-                       break;
-               case TOMOYO_ID_PATTERN:
-                       tomoyo_del_file_pattern(element);
-                       break;
-               case TOMOYO_ID_NO_REWRITE:
-                       tomoyo_del_no_rewrite(element);
-                       break;
                case TOMOYO_ID_MANAGER:
                        tomoyo_del_manager(element);
                        break;
+               case TOMOYO_ID_CONDITION:
+                       tomoyo_del_condition(element);
+                       break;
                case TOMOYO_ID_NAME:
+                       /*
+                        * Thirdly, defer until all "struct tomoyo_io_buffer"
+                        * ->r.w[] forget the list element.
+                        */
+                       if (tomoyo_name_used_by_io_buffer(
+                           container_of(element, typeof(struct tomoyo_name),
+                                        head.list)->entry.name, p->size))
+                               continue;
                        tomoyo_del_name(element);
                        break;
                case TOMOYO_ID_ACL:
@@ -321,34 +631,95 @@ static void tomoyo_kfree_entry(void)
                case TOMOYO_ID_NUMBER_GROUP:
                        tomoyo_del_number_group(element);
                        break;
+               case TOMOYO_MAX_POLICY:
+                       break;
                }
                tomoyo_memory_free(element);
                list_del(&p->list);
                kfree(p);
+               tomoyo_gc_list_len--;
+               result = true;
        }
+       return result;
 }
 
+/**
+ * tomoyo_gc_thread - Garbage collector thread function.
+ *
+ * @unused: Unused.
+ *
+ * In case OOM-killer choose this thread for termination, we create this thread
+ * as a short live thread whenever /sys/kernel/security/tomoyo/ interface was
+ * close()d.
+ *
+ * Returns 0.
+ */
 static int tomoyo_gc_thread(void *unused)
 {
+       /* Garbage collector thread is exclusive. */
+       static DEFINE_MUTEX(tomoyo_gc_mutex);
+       if (!mutex_trylock(&tomoyo_gc_mutex))
+               goto out;
        daemonize("GC for TOMOYO");
-       if (mutex_trylock(&tomoyo_gc_mutex)) {
-               int i;
-               for (i = 0; i < 10; i++) {
-                       tomoyo_collect_entry();
-                       if (list_empty(&tomoyo_gc_queue))
-                               break;
-                       synchronize_srcu(&tomoyo_ss);
-                       tomoyo_kfree_entry();
+       do {
+               tomoyo_collect_entry();
+               if (list_empty(&tomoyo_gc_list))
+                       break;
+               synchronize_srcu(&tomoyo_ss);
+       } while (tomoyo_kfree_entry());
+       {
+               struct tomoyo_io_buffer *head;
+               struct tomoyo_io_buffer *tmp;
+
+               spin_lock(&tomoyo_io_buffer_list_lock);
+               list_for_each_entry_safe(head, tmp, &tomoyo_io_buffer_list,
+                                        list) {
+                       if (head->users)
+                               continue;
+                       list_del(&head->list);
+                       kfree(head->read_buf);
+                       kfree(head->write_buf);
+                       kfree(head);
                }
-               mutex_unlock(&tomoyo_gc_mutex);
+               spin_unlock(&tomoyo_io_buffer_list_lock);
        }
-       do_exit(0);
+       mutex_unlock(&tomoyo_gc_mutex);
+out:
+       /* This acts as do_exit(0). */
+       return 0;
 }
 
-void tomoyo_run_gc(void)
+/**
+ * tomoyo_notify_gc - Register/unregister /sys/kernel/security/tomoyo/ users.
+ *
+ * @head:        Pointer to "struct tomoyo_io_buffer".
+ * @is_register: True if register, false if unregister.
+ *
+ * Returns nothing.
+ */
+void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register)
 {
-       struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL,
-                                                 "GC for TOMOYO");
-       if (!IS_ERR(task))
-               wake_up_process(task);
+       bool is_write = false;
+
+       spin_lock(&tomoyo_io_buffer_list_lock);
+       if (is_register) {
+               head->users = 1;
+               list_add(&head->list, &tomoyo_io_buffer_list);
+       } else {
+               is_write = head->write_buf != NULL;
+               if (!--head->users) {
+                       list_del(&head->list);
+                       kfree(head->read_buf);
+                       kfree(head->write_buf);
+                       kfree(head);
+               }
+       }
+       spin_unlock(&tomoyo_io_buffer_list_lock);
+       if (is_write) {
+               struct task_struct *task = kthread_create(tomoyo_gc_thread,
+                                                         NULL,
+                                                         "GC for TOMOYO");
+               if (!IS_ERR(task))
+                       wake_up_process(task);
+       }
 }
index e94352ce723f7466ff1cde6f2bda16ac03119269..5fb0e1298400e040bcc724f1196a4c9e02154f4c 100644 (file)
@@ -1,21 +1,37 @@
 /*
  * security/tomoyo/group.c
  *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include <linux/slab.h>
 #include "common.h"
 
+/**
+ * tomoyo_same_path_group - Check for duplicated "struct tomoyo_path_group" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
 static bool tomoyo_same_path_group(const struct tomoyo_acl_head *a,
-                               const struct tomoyo_acl_head *b)
+                                  const struct tomoyo_acl_head *b)
 {
        return container_of(a, struct tomoyo_path_group, head)->member_name ==
                container_of(b, struct tomoyo_path_group, head)->member_name;
 }
 
+/**
+ * tomoyo_same_number_group - Check for duplicated "struct tomoyo_number_group" entry.
+ *
+ * @a: Pointer to "struct tomoyo_acl_head".
+ * @b: Pointer to "struct tomoyo_acl_head".
+ *
+ * Returns true if @a == @b, false otherwise.
+ */
 static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a,
-                                 const struct tomoyo_acl_head *b)
+                                    const struct tomoyo_acl_head *b)
 {
        return !memcmp(&container_of(a, struct tomoyo_number_group, head)
                       ->number,
@@ -28,48 +44,41 @@ static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a,
 /**
  * tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
  *
- * @data:      String to parse.
- * @is_delete: True if it is a delete request.
- * @type:      Type of this group.
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @type:  Type of this group.
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_write_group(char *data, const bool is_delete, const u8 type)
+int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type)
 {
-       struct tomoyo_group *group;
-       struct list_head *member;
-       char *w[2];
+       struct tomoyo_group *group = tomoyo_get_group(param, type);
        int error = -EINVAL;
-       if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
-               return -EINVAL;
-       group = tomoyo_get_group(w[0], type);
        if (!group)
                return -ENOMEM;
-       member = &group->member_list;
+       param->list = &group->member_list;
        if (type == TOMOYO_PATH_GROUP) {
                struct tomoyo_path_group e = { };
-               e.member_name = tomoyo_get_name(w[1]);
+               e.member_name = tomoyo_get_name(tomoyo_read_token(param));
                if (!e.member_name) {
                        error = -ENOMEM;
                        goto out;
                }
-               error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
-                                            member, tomoyo_same_path_group);
+               error = tomoyo_update_policy(&e.head, sizeof(e), param,
+                                         tomoyo_same_path_group);
                tomoyo_put_name(e.member_name);
        } else if (type == TOMOYO_NUMBER_GROUP) {
                struct tomoyo_number_group e = { };
-               if (w[1][0] == '@'
-                   || !tomoyo_parse_number_union(w[1], &e.number)
-                   || e.number.values[0] > e.number.values[1])
+               if (param->data[0] == '@' ||
+                   !tomoyo_parse_number_union(param, &e.number))
                        goto out;
-               error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
-                                            member, tomoyo_same_number_group);
+               error = tomoyo_update_policy(&e.head, sizeof(e), param,
+                                         tomoyo_same_number_group);
                /*
                 * tomoyo_put_number_union() is not needed because
-                * w[1][0] != '@'.
+                * param->data[0] != '@'.
                 */
        }
- out:
+out:
        tomoyo_put_group(group);
        return error;
 }
@@ -77,8 +86,8 @@ int tomoyo_write_group(char *data, const bool is_delete, const u8 type)
 /**
  * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group.
  *
- * @pathname:        The name of pathname.
- * @group:           Pointer to "struct tomoyo_path_group".
+ * @pathname: The name of pathname.
+ * @group:    Pointer to "struct tomoyo_path_group".
  *
  * Returns matched member's pathname if @pathname matches pathnames in @group,
  * NULL otherwise.
index 3312e5624f246d0a663077ab24a4407ce4aafbdb..67975405140f4413010830bc737746815e2b1914 100644 (file)
@@ -1,15 +1,32 @@
 /*
  * security/tomoyo/load_policy.c
  *
- * Policy loader launcher for TOMOYO.
- *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include "common.h"
 
-/* path to policy loader */
-static const char *tomoyo_loader = "/sbin/tomoyo-init";
+#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
+
+/*
+ * Path to the policy loader. (default = CONFIG_SECURITY_TOMOYO_POLICY_LOADER)
+ */
+static const char *tomoyo_loader;
+
+/**
+ * tomoyo_loader_setup - Set policy loader.
+ *
+ * @str: Program to use as a policy loader (e.g. /sbin/tomoyo-init ).
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_loader_setup(char *str)
+{
+       tomoyo_loader = str;
+       return 0;
+}
+
+__setup("TOMOYO_loader=", tomoyo_loader_setup);
 
 /**
  * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
@@ -18,24 +35,38 @@ static const char *tomoyo_loader = "/sbin/tomoyo-init";
  */
 static bool tomoyo_policy_loader_exists(void)
 {
-       /*
-        * Don't activate MAC if the policy loader doesn't exist.
-        * If the initrd includes /sbin/init but real-root-dev has not
-        * mounted on / yet, activating MAC will block the system since
-        * policies are not loaded yet.
-        * Thus, let do_execve() call this function every time.
-        */
        struct path path;
-
+       if (!tomoyo_loader)
+               tomoyo_loader = CONFIG_SECURITY_TOMOYO_POLICY_LOADER;
        if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
-               printk(KERN_INFO "Not activating Mandatory Access Control now "
-                      "since %s doesn't exist.\n", tomoyo_loader);
+               printk(KERN_INFO "Not activating Mandatory Access Control "
+                      "as %s does not exist.\n", tomoyo_loader);
                return false;
        }
        path_put(&path);
        return true;
 }
 
+/*
+ * Path to the trigger. (default = CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER)
+ */
+static const char *tomoyo_trigger;
+
+/**
+ * tomoyo_trigger_setup - Set trigger for activation.
+ *
+ * @str: Program to use as an activation trigger (e.g. /sbin/init ).
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_trigger_setup(char *str)
+{
+       tomoyo_trigger = str;
+       return 0;
+}
+
+__setup("TOMOYO_trigger=", tomoyo_trigger_setup);
+
 /**
  * tomoyo_load_policy - Run external policy loader to load policy.
  *
@@ -51,24 +82,19 @@ static bool tomoyo_policy_loader_exists(void)
  */
 void tomoyo_load_policy(const char *filename)
 {
+       static bool done;
        char *argv[2];
        char *envp[3];
 
-       if (tomoyo_policy_loaded)
+       if (tomoyo_policy_loaded || done)
                return;
-       /*
-        * Check filename is /sbin/init or /sbin/tomoyo-start.
-        * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
-        * be passed.
-        * You can create /sbin/tomoyo-start by
-        * "ln -s /bin/true /sbin/tomoyo-start".
-        */
-       if (strcmp(filename, "/sbin/init") &&
-           strcmp(filename, "/sbin/tomoyo-start"))
+       if (!tomoyo_trigger)
+               tomoyo_trigger = CONFIG_SECURITY_TOMOYO_ACTIVATION_TRIGGER;
+       if (strcmp(filename, tomoyo_trigger))
                return;
        if (!tomoyo_policy_loader_exists())
                return;
-
+       done = true;
        printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
               tomoyo_loader);
        argv[0] = (char *) tomoyo_loader;
@@ -79,3 +105,5 @@ void tomoyo_load_policy(const char *filename)
        call_usermodehelper(argv[0], argv, envp, 1);
        tomoyo_check_profile();
 }
+
+#endif
index 42a7b1ba8cbf221ceeaa188c2089fa2a99e01a94..7a56051146c22035af9cc5027e84c9ac6fed8fa2 100644 (file)
@@ -1,9 +1,7 @@
 /*
  * security/tomoyo/memory.c
  *
- * Memory management functions for TOMOYO.
- *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include <linux/hash.h>
@@ -29,10 +27,12 @@ void tomoyo_warn_oom(const char *function)
                panic("MAC Initialization failed.\n");
 }
 
-/* Memory allocated for policy. */
-static atomic_t tomoyo_policy_memory_size;
-/* Quota for holding policy. */
-static unsigned int tomoyo_quota_for_policy;
+/* Lock for protecting tomoyo_memory_used. */
+static DEFINE_SPINLOCK(tomoyo_policy_memory_lock);
+/* Memoy currently used by policy/audit log/query. */
+unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
+/* Memory quota for "policy"/"audit log"/"query". */
+unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
 
 /**
  * tomoyo_memory_ok - Check memory quota.
@@ -45,15 +45,20 @@ static unsigned int tomoyo_quota_for_policy;
  */
 bool tomoyo_memory_ok(void *ptr)
 {
-       size_t s = ptr ? ksize(ptr) : 0;
-       atomic_add(s, &tomoyo_policy_memory_size);
-       if (ptr && (!tomoyo_quota_for_policy ||
-                   atomic_read(&tomoyo_policy_memory_size)
-                   <= tomoyo_quota_for_policy)) {
-               memset(ptr, 0, s);
-               return true;
+       if (ptr) {
+               const size_t s = ksize(ptr);
+               bool result;
+               spin_lock(&tomoyo_policy_memory_lock);
+               tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s;
+               result = !tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] ||
+                       tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <=
+                       tomoyo_memory_quota[TOMOYO_MEMORY_POLICY];
+               if (!result)
+                       tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s;
+               spin_unlock(&tomoyo_policy_memory_lock);
+               if (result)
+                       return true;
        }
-       atomic_sub(s, &tomoyo_policy_memory_size);
        tomoyo_warn_oom(__func__);
        return false;
 }
@@ -86,22 +91,28 @@ void *tomoyo_commit_ok(void *data, const unsigned int size)
  */
 void tomoyo_memory_free(void *ptr)
 {
-       atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
+       size_t s = ksize(ptr);
+       spin_lock(&tomoyo_policy_memory_lock);
+       tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s;
+       spin_unlock(&tomoyo_policy_memory_lock);
        kfree(ptr);
 }
 
 /**
  * tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
  *
- * @group_name: The name of address group.
- * @idx:        Index number.
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @idx:   Index number.
  *
  * Returns pointer to "struct tomoyo_group" on success, NULL otherwise.
  */
-struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx)
+struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
+                                     const u8 idx)
 {
        struct tomoyo_group e = { };
        struct tomoyo_group *group = NULL;
+       struct list_head *list;
+       const char *group_name = tomoyo_read_token(param);
        bool found = false;
        if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP)
                return NULL;
@@ -110,10 +121,11 @@ struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx)
                return NULL;
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                goto out;
-       list_for_each_entry(group, &tomoyo_group_list[idx], list) {
+       list = &param->ns->group_list[idx];
+       list_for_each_entry(group, list, head.list) {
                if (e.group_name != group->group_name)
                        continue;
-               atomic_inc(&group->users);
+               atomic_inc(&group->head.users);
                found = true;
                break;
        }
@@ -121,15 +133,14 @@ struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx)
                struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e));
                if (entry) {
                        INIT_LIST_HEAD(&entry->member_list);
-                       atomic_set(&entry->users, 1);
-                       list_add_tail_rcu(&entry->list,
-                                         &tomoyo_group_list[idx]);
+                       atomic_set(&entry->head.users, 1);
+                       list_add_tail_rcu(&entry->head.list, list);
                        group = entry;
                        found = true;
                }
        }
        mutex_unlock(&tomoyo_policy_lock);
- out:
+out:
        tomoyo_put_name(e.group_name);
        return found ? group : NULL;
 }
@@ -154,7 +165,6 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
        struct tomoyo_name *ptr;
        unsigned int hash;
        int len;
-       int allocated_len;
        struct list_head *head;
 
        if (!name)
@@ -164,120 +174,43 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
        head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
        if (mutex_lock_interruptible(&tomoyo_policy_lock))
                return NULL;
-       list_for_each_entry(ptr, head, list) {
+       list_for_each_entry(ptr, head, head.list) {
                if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
                        continue;
-               atomic_inc(&ptr->users);
+               atomic_inc(&ptr->head.users);
                goto out;
        }
        ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
-       allocated_len = ptr ? ksize(ptr) : 0;
-       if (!ptr || (tomoyo_quota_for_policy &&
-                    atomic_read(&tomoyo_policy_memory_size) + allocated_len
-                    > tomoyo_quota_for_policy)) {
+       if (tomoyo_memory_ok(ptr)) {
+               ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+               memmove((char *) ptr->entry.name, name, len);
+               atomic_set(&ptr->head.users, 1);
+               tomoyo_fill_path_info(&ptr->entry);
+               list_add_tail(&ptr->head.list, head);
+       } else {
                kfree(ptr);
                ptr = NULL;
-               tomoyo_warn_oom(__func__);
-               goto out;
        }
-       atomic_add(allocated_len, &tomoyo_policy_memory_size);
-       ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
-       memmove((char *) ptr->entry.name, name, len);
-       atomic_set(&ptr->users, 1);
-       tomoyo_fill_path_info(&ptr->entry);
-       list_add_tail(&ptr->list, head);
- out:
+out:
        mutex_unlock(&tomoyo_policy_lock);
        return ptr ? &ptr->entry : NULL;
 }
 
+/* Initial namespace.*/
+struct tomoyo_policy_namespace tomoyo_kernel_namespace;
+
 /**
  * tomoyo_mm_init - Initialize mm related code.
  */
 void __init tomoyo_mm_init(void)
 {
        int idx;
-
-       for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
-               INIT_LIST_HEAD(&tomoyo_policy_list[idx]);
-       for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
-               INIT_LIST_HEAD(&tomoyo_group_list[idx]);
        for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
                INIT_LIST_HEAD(&tomoyo_name_list[idx]);
+       tomoyo_kernel_namespace.name = "<kernel>";
+       tomoyo_init_policy_namespace(&tomoyo_kernel_namespace);
+       tomoyo_kernel_domain.ns = &tomoyo_kernel_namespace;
        INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
-       tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
+       tomoyo_kernel_domain.domainname = tomoyo_get_name("<kernel>");
        list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
-       idx = tomoyo_read_lock();
-       if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
-               panic("Can't register tomoyo_kernel_domain");
-       {
-               /* Load built-in policy. */
-               tomoyo_write_transition_control("/sbin/hotplug", false,
-                                       TOMOYO_TRANSITION_CONTROL_INITIALIZE);
-               tomoyo_write_transition_control("/sbin/modprobe", false,
-                                       TOMOYO_TRANSITION_CONTROL_INITIALIZE);
-       }
-       tomoyo_read_unlock(idx);
-}
-
-
-/* Memory allocated for query lists. */
-unsigned int tomoyo_query_memory_size;
-/* Quota for holding query lists. */
-unsigned int tomoyo_quota_for_query;
-
-/**
- * tomoyo_read_memory_counter - Check for memory usage in bytes.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns memory usage.
- */
-void tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
-{
-       if (!head->r.eof) {
-               const unsigned int policy
-                       = atomic_read(&tomoyo_policy_memory_size);
-               const unsigned int query = tomoyo_query_memory_size;
-               char buffer[64];
-
-               memset(buffer, 0, sizeof(buffer));
-               if (tomoyo_quota_for_policy)
-                       snprintf(buffer, sizeof(buffer) - 1,
-                                "   (Quota: %10u)",
-                                tomoyo_quota_for_policy);
-               else
-                       buffer[0] = '\0';
-               tomoyo_io_printf(head, "Policy:       %10u%s\n", policy,
-                                buffer);
-               if (tomoyo_quota_for_query)
-                       snprintf(buffer, sizeof(buffer) - 1,
-                                "   (Quota: %10u)",
-                                tomoyo_quota_for_query);
-               else
-                       buffer[0] = '\0';
-               tomoyo_io_printf(head, "Query lists:  %10u%s\n", query,
-                                buffer);
-               tomoyo_io_printf(head, "Total:        %10u\n", policy + query);
-               head->r.eof = true;
-       }
-}
-
-/**
- * tomoyo_write_memory_quota - Set memory quota.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns 0.
- */
-int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
-{
-       char *data = head->write_buf;
-       unsigned int size;
-
-       if (sscanf(data, "Policy: %u", &size) == 1)
-               tomoyo_quota_for_policy = size;
-       else if (sscanf(data, "Query lists: %u", &size) == 1)
-               tomoyo_quota_for_query = size;
-       return 0;
 }
index 9fc2e15841c96f54edbefb24a96c40405d06bedd..bee09d0620575a5ff5de8e681af1380beeb5ce44 100644 (file)
@@ -1,28 +1,22 @@
 /*
  * security/tomoyo/mount.c
  *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include <linux/slab.h>
 #include "common.h"
 
-/* Keywords for mount restrictions. */
-
-/* Allow to call 'mount --bind /source_dir /dest_dir' */
-#define TOMOYO_MOUNT_BIND_KEYWORD                        "--bind"
-/* Allow to call 'mount --move /old_dir    /new_dir ' */
-#define TOMOYO_MOUNT_MOVE_KEYWORD                        "--move"
-/* Allow to call 'mount -o remount /dir             ' */
-#define TOMOYO_MOUNT_REMOUNT_KEYWORD                     "--remount"
-/* Allow to call 'mount --make-unbindable /dir'       */
-#define TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD             "--make-unbindable"
-/* Allow to call 'mount --make-private /dir'          */
-#define TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD                "--make-private"
-/* Allow to call 'mount --make-slave /dir'            */
-#define TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD                  "--make-slave"
-/* Allow to call 'mount --make-shared /dir'           */
-#define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD                 "--make-shared"
+/* String table for special mount operations. */
+static const char * const tomoyo_mounts[TOMOYO_MAX_SPECIAL_MOUNT] = {
+       [TOMOYO_MOUNT_BIND]            = "--bind",
+       [TOMOYO_MOUNT_MOVE]            = "--move",
+       [TOMOYO_MOUNT_REMOUNT]         = "--remount",
+       [TOMOYO_MOUNT_MAKE_UNBINDABLE] = "--make-unbindable",
+       [TOMOYO_MOUNT_MAKE_PRIVATE]    = "--make-private",
+       [TOMOYO_MOUNT_MAKE_SLAVE]      = "--make-slave",
+       [TOMOYO_MOUNT_MAKE_SHARED]     = "--make-shared",
+};
 
 /**
  * tomoyo_audit_mount_log - Audit mount log.
  */
 static int tomoyo_audit_mount_log(struct tomoyo_request_info *r)
 {
-       const char *dev = r->param.mount.dev->name;
-       const char *dir = r->param.mount.dir->name;
-       const char *type = r->param.mount.type->name;
-       const unsigned long flags = r->param.mount.flags;
-       if (r->granted)
-               return 0;
-       if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD))
-               tomoyo_warn_log(r, "mount -o remount %s 0x%lX", dir, flags);
-       else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD)
-                || !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD))
-               tomoyo_warn_log(r, "mount %s %s %s 0x%lX", type, dev, dir,
-                               flags);
-       else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
-                !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
-                !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
-                !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD))
-               tomoyo_warn_log(r, "mount %s %s 0x%lX", type, dir, flags);
-       else
-               tomoyo_warn_log(r, "mount -t %s %s %s 0x%lX", type, dev, dir,
-                               flags);
-       return tomoyo_supervisor(r,
-                                TOMOYO_KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n",
-                                tomoyo_pattern(r->param.mount.dev),
-                                tomoyo_pattern(r->param.mount.dir), type,
-                                flags);
+       return tomoyo_supervisor(r, "file mount %s %s %s 0x%lX\n",
+                                r->param.mount.dev->name,
+                                r->param.mount.dir->name,
+                                r->param.mount.type->name,
+                                r->param.mount.flags);
 }
 
+/**
+ * tomoyo_check_mount_acl - Check permission for path path path number operation.
+ *
+ * @r:   Pointer to "struct tomoyo_request_info".
+ * @ptr: Pointer to "struct tomoyo_acl_info".
+ *
+ * Returns true if granted, false otherwise.
+ */
 static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
                                   const struct tomoyo_acl_info *ptr)
 {
        const struct tomoyo_mount_acl *acl =
                container_of(ptr, typeof(*acl), head);
-       return tomoyo_compare_number_union(r->param.mount.flags, &acl->flags) &&
-               tomoyo_compare_name_union(r->param.mount.type, &acl->fs_type) &&
-               tomoyo_compare_name_union(r->param.mount.dir, &acl->dir_name) &&
+       return tomoyo_compare_number_union(r->param.mount.flags,
+                                          &acl->flags) &&
+               tomoyo_compare_name_union(r->param.mount.type,
+                                         &acl->fs_type) &&
+               tomoyo_compare_name_union(r->param.mount.dir,
+                                         &acl->dir_name) &&
                (!r->param.mount.need_dev ||
-                tomoyo_compare_name_union(r->param.mount.dev, &acl->dev_name));
+                tomoyo_compare_name_union(r->param.mount.dev,
+                                          &acl->dev_name));
 }
 
 /**
  * tomoyo_mount_acl - Check permission for mount() operation.
  *
  * @r:        Pointer to "struct tomoyo_request_info".
- * @dev_name: Name of device file.
+ * @dev_name: Name of device file. Maybe NULL.
  * @dir:      Pointer to "struct path".
  * @type:     Name of filesystem type.
  * @flags:    Mount options.
@@ -86,8 +72,10 @@ static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
  * Caller holds tomoyo_read_lock().
  */
 static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
-                           struct path *dir, char *type, unsigned long flags)
+                           struct path *dir, const char *type,
+                           unsigned long flags)
 {
+       struct tomoyo_obj_info obj = { };
        struct path path;
        struct file_system_type *fstype = NULL;
        const char *requested_type = NULL;
@@ -98,6 +86,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
        struct tomoyo_path_info rdir;
        int need_dev = 0;
        int error = -ENOMEM;
+       r->obj = &obj;
 
        /* Get fstype. */
        requested_type = tomoyo_encode(type);
@@ -107,6 +96,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
        tomoyo_fill_path_info(&rtype);
 
        /* Get mount point. */
+       obj.path2 = *dir;
        requested_dir_name = tomoyo_realpath_from_path(dir);
        if (!requested_dir_name) {
                error = -ENOMEM;
@@ -116,15 +106,15 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
        tomoyo_fill_path_info(&rdir);
 
        /* Compare fs name. */
-       if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) {
+       if (type == tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]) {
                /* dev_name is ignored. */
-       } else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
-                  !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
-                  !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
-                  !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) {
+       } else if (type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE] ||
+                  type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE] ||
+                  type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE] ||
+                  type == tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]) {
                /* dev_name is ignored. */
-       } else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) ||
-                  !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) {
+       } else if (type == tomoyo_mounts[TOMOYO_MOUNT_BIND] ||
+                  type == tomoyo_mounts[TOMOYO_MOUNT_MOVE]) {
                need_dev = -1; /* dev_name is a directory */
        } else {
                fstype = get_fs_type(type);
@@ -142,8 +132,8 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
                        error = -ENOENT;
                        goto out;
                }
+               obj.path1 = path;
                requested_dev_name = tomoyo_realpath_from_path(&path);
-               path_put(&path);
                if (!requested_dev_name) {
                        error = -ENOENT;
                        goto out;
@@ -176,22 +166,26 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
        if (fstype)
                put_filesystem(fstype);
        kfree(requested_type);
+       /* Drop refcount obtained by kern_path(). */
+       if (obj.path1.dentry)
+               path_put(&obj.path1);
        return error;
 }
 
 /**
  * tomoyo_mount_permission - Check permission for mount() operation.
  *
- * @dev_name:  Name of device file.
+ * @dev_name:  Name of device file. Maybe NULL.
  * @path:      Pointer to "struct path".
- * @type:      Name of filesystem type. May be NULL.
+ * @type:      Name of filesystem type. Maybe NULL.
  * @flags:     Mount options.
- * @data_page: Optional data. May be NULL.
+ * @data_page: Optional data. Maybe NULL.
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
-                           unsigned long flags, void *data_page)
+int tomoyo_mount_permission(char *dev_name, struct path *path,
+                           const char *type, unsigned long flags,
+                           void *data_page)
 {
        struct tomoyo_request_info r;
        int error;
@@ -203,31 +197,31 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
        if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
                flags &= ~MS_MGC_MSK;
        if (flags & MS_REMOUNT) {
-               type = TOMOYO_MOUNT_REMOUNT_KEYWORD;
+               type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT];
                flags &= ~MS_REMOUNT;
        }
        if (flags & MS_MOVE) {
-               type = TOMOYO_MOUNT_MOVE_KEYWORD;
+               type = tomoyo_mounts[TOMOYO_MOUNT_MOVE];
                flags &= ~MS_MOVE;
        }
        if (flags & MS_BIND) {
-               type = TOMOYO_MOUNT_BIND_KEYWORD;
+               type = tomoyo_mounts[TOMOYO_MOUNT_BIND];
                flags &= ~MS_BIND;
        }
        if (flags & MS_UNBINDABLE) {
-               type = TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD;
+               type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE];
                flags &= ~MS_UNBINDABLE;
        }
        if (flags & MS_PRIVATE) {
-               type = TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD;
+               type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE];
                flags &= ~MS_PRIVATE;
        }
        if (flags & MS_SLAVE) {
-               type = TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD;
+               type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE];
                flags &= ~MS_SLAVE;
        }
        if (flags & MS_SHARED) {
-               type = TOMOYO_MOUNT_MAKE_SHARED_KEYWORD;
+               type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED];
                flags &= ~MS_SHARED;
        }
        if (!type)
@@ -237,49 +231,3 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
        tomoyo_read_unlock(idx);
        return error;
 }
-
-static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
-                                 const struct tomoyo_acl_info *b)
-{
-       const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
-       const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
-       return tomoyo_same_acl_head(&p1->head, &p2->head) &&
-               tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
-               tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
-               tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
-               tomoyo_same_number_union(&p1->flags, &p2->flags);
-}
-
-/**
- * tomoyo_write_mount - Write "struct tomoyo_mount_acl" list.
- *
- * @data:      String to parse.
- * @domain:    Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
-                      const bool is_delete)
-{
-       struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
-       int error = is_delete ? -ENOENT : -ENOMEM;
-       char *w[4];
-       if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0])
-               return -EINVAL;
-       if (!tomoyo_parse_name_union(w[0], &e.dev_name) ||
-           !tomoyo_parse_name_union(w[1], &e.dir_name) ||
-           !tomoyo_parse_name_union(w[2], &e.fs_type) ||
-           !tomoyo_parse_number_union(w[3], &e.flags))
-               goto out;
-       error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
-                                    tomoyo_same_mount_acl, NULL);
- out:
-       tomoyo_put_name_union(&e.dev_name);
-       tomoyo_put_name_union(&e.dir_name);
-       tomoyo_put_name_union(&e.fs_type);
-       tomoyo_put_number_union(&e.flags);
-       return error;
-}
index 8d95e91c9fc4bdd070b1f29038876cd37cc7c31b..6c601bd300f386a9faff38e335c4f9c6dbdfa541 100644 (file)
@@ -1,9 +1,7 @@
 /*
  * security/tomoyo/realpath.c
  *
- * Pathname calculation functions for TOMOYO.
- *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include <linux/types.h>
@@ -69,6 +67,161 @@ char *tomoyo_encode(const char *str)
        return cp0;
 }
 
+/**
+ * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
+ *
+ * @path:   Pointer to "struct path".
+ * @buffer: Pointer to buffer to return value in.
+ * @buflen: Sizeof @buffer.
+ *
+ * Returns the buffer on success, an error code otherwise.
+ *
+ * If dentry is a directory, trailing '/' is appended.
+ */
+static char *tomoyo_get_absolute_path(struct path *path, char * const buffer,
+                                     const int buflen)
+{
+       char *pos = ERR_PTR(-ENOMEM);
+       if (buflen >= 256) {
+               struct path ns_root = { };
+               /* go to whatever namespace root we are under */
+               pos = __d_path(path, &ns_root, buffer, buflen - 1);
+               if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
+                       struct inode *inode = path->dentry->d_inode;
+                       if (inode && S_ISDIR(inode->i_mode)) {
+                               buffer[buflen - 2] = '/';
+                               buffer[buflen - 1] = '\0';
+                       }
+               }
+       }
+       return pos;
+}
+
+/**
+ * tomoyo_get_dentry_path - Get the path of a dentry.
+ *
+ * @dentry: Pointer to "struct dentry".
+ * @buffer: Pointer to buffer to return value in.
+ * @buflen: Sizeof @buffer.
+ *
+ * Returns the buffer on success, an error code otherwise.
+ *
+ * If dentry is a directory, trailing '/' is appended.
+ */
+static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer,
+                                   const int buflen)
+{
+       char *pos = ERR_PTR(-ENOMEM);
+       if (buflen >= 256) {
+               pos = dentry_path_raw(dentry, buffer, buflen - 1);
+               if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
+                       struct inode *inode = dentry->d_inode;
+                       if (inode && S_ISDIR(inode->i_mode)) {
+                               buffer[buflen - 2] = '/';
+                               buffer[buflen - 1] = '\0';
+                       }
+               }
+       }
+       return pos;
+}
+
+/**
+ * tomoyo_get_local_path - Get the path of a dentry.
+ *
+ * @dentry: Pointer to "struct dentry".
+ * @buffer: Pointer to buffer to return value in.
+ * @buflen: Sizeof @buffer.
+ *
+ * Returns the buffer on success, an error code otherwise.
+ */
+static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
+                                  const int buflen)
+{
+       struct super_block *sb = dentry->d_sb;
+       char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen);
+       if (IS_ERR(pos))
+               return pos;
+       /* Convert from $PID to self if $PID is current thread. */
+       if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
+               char *ep;
+               const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
+               if (*ep == '/' && pid && pid ==
+                   task_tgid_nr_ns(current, sb->s_fs_info)) {
+                       pos = ep - 5;
+                       if (pos < buffer)
+                               goto out;
+                       memmove(pos, "/self", 5);
+               }
+               goto prepend_filesystem_name;
+       }
+       /* Use filesystem name for unnamed devices. */
+       if (!MAJOR(sb->s_dev))
+               goto prepend_filesystem_name;
+       {
+               struct inode *inode = sb->s_root->d_inode;
+               /*
+                * Use filesystem name if filesystem does not support rename()
+                * operation.
+                */
+               if (inode->i_op && !inode->i_op->rename)
+                       goto prepend_filesystem_name;
+       }
+       /* Prepend device name. */
+       {
+               char name[64];
+               int name_len;
+               const dev_t dev = sb->s_dev;
+               name[sizeof(name) - 1] = '\0';
+               snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
+                        MINOR(dev));
+               name_len = strlen(name);
+               pos -= name_len;
+               if (pos < buffer)
+                       goto out;
+               memmove(pos, name, name_len);
+               return pos;
+       }
+       /* Prepend filesystem name. */
+prepend_filesystem_name:
+       {
+               const char *name = sb->s_type->name;
+               const int name_len = strlen(name);
+               pos -= name_len + 1;
+               if (pos < buffer)
+                       goto out;
+               memmove(pos, name, name_len);
+               pos[name_len] = ':';
+       }
+       return pos;
+out:
+       return ERR_PTR(-ENOMEM);
+}
+
+/**
+ * tomoyo_get_socket_name - Get the name of a socket.
+ *
+ * @path:   Pointer to "struct path".
+ * @buffer: Pointer to buffer to return value in.
+ * @buflen: Sizeof @buffer.
+ *
+ * Returns the buffer.
+ */
+static char *tomoyo_get_socket_name(struct path *path, char * const buffer,
+                                   const int buflen)
+{
+       struct inode *inode = path->dentry->d_inode;
+       struct socket *sock = inode ? SOCKET_I(inode) : NULL;
+       struct sock *sk = sock ? sock->sk : NULL;
+       if (sk) {
+               snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
+                        "protocol=%u]", sk->sk_family, sk->sk_type,
+                        sk->sk_protocol);
+       } else {
+               snprintf(buffer, buflen, "socket:[unknown]");
+       }
+       return buffer;
+}
+
 /**
  * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
  *
@@ -90,55 +243,42 @@ char *tomoyo_realpath_from_path(struct path *path)
        char *name = NULL;
        unsigned int buf_len = PAGE_SIZE / 2;
        struct dentry *dentry = path->dentry;
-       bool is_dir;
+       struct super_block *sb;
        if (!dentry)
                return NULL;
-       is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
+       sb = dentry->d_sb;
        while (1) {
-               struct path ns_root = { .mnt = NULL, .dentry = NULL };
                char *pos;
+               struct inode *inode;
                buf_len <<= 1;
                kfree(buf);
                buf = kmalloc(buf_len, GFP_NOFS);
                if (!buf)
                        break;
+               /* To make sure that pos is '\0' terminated. */
+               buf[buf_len - 1] = '\0';
                /* Get better name for socket. */
-               if (dentry->d_sb->s_magic == SOCKFS_MAGIC) {
-                       struct inode *inode = dentry->d_inode;
-                       struct socket *sock = inode ? SOCKET_I(inode) : NULL;
-                       struct sock *sk = sock ? sock->sk : NULL;
-                       if (sk) {
-                               snprintf(buf, buf_len - 1, "socket:[family=%u:"
-                                        "type=%u:protocol=%u]", sk->sk_family,
-                                        sk->sk_type, sk->sk_protocol);
-                       } else {
-                               snprintf(buf, buf_len - 1, "socket:[unknown]");
-                       }
-                       name = tomoyo_encode(buf);
-                       break;
+               if (sb->s_magic == SOCKFS_MAGIC) {
+                       pos = tomoyo_get_socket_name(path, buf, buf_len - 1);
+                       goto encode;
                }
-               /* For "socket:[\$]" and "pipe:[\$]". */
+               /* For "pipe:[\$]". */
                if (dentry->d_op && dentry->d_op->d_dname) {
                        pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
-                       if (IS_ERR(pos))
-                               continue;
-                       name = tomoyo_encode(pos);
-                       break;
-               }
-               /* If we don't have a vfsmount, we can't calculate. */
-               if (!path->mnt)
-                       break;
-               /* go to whatever namespace root we are under */
-               pos = __d_path(path, &ns_root, buf, buf_len);
-               /* Prepend "/proc" prefix if using internal proc vfs mount. */
-               if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
-                   (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
-                       pos -= 5;
-                       if (pos >= buf)
-                               memcpy(pos, "/proc", 5);
-                       else
-                               pos = ERR_PTR(-ENOMEM);
+                       goto encode;
                }
+               inode = sb->s_root->d_inode;
+               /*
+                * Get local name for filesystems without rename() operation
+                * or dentry without vfsmount.
+                */
+               if (!path->mnt || (inode->i_op && !inode->i_op->rename))
+                       pos = tomoyo_get_local_path(path->dentry, buf,
+                                                   buf_len - 1);
+               /* Get absolute name for the rest. */
+               else
+                       pos = tomoyo_get_absolute_path(path, buf, buf_len - 1);
+encode:
                if (IS_ERR(pos))
                        continue;
                name = tomoyo_encode(pos);
@@ -147,16 +287,6 @@ char *tomoyo_realpath_from_path(struct path *path)
        kfree(buf);
        if (!name)
                tomoyo_warn_oom(__func__);
-       else if (is_dir && *name) {
-               /* Append trailing '/' if dentry is a directory. */
-               char *pos = name + strlen(name) - 1;
-               if (*pos != '/')
-                       /*
-                        * This is OK because tomoyo_encode() reserves space
-                        * for appending "/".
-                        */
-                       *++pos = '/';
-       }
        return name;
 }
 
index e43d5554b50628b823db9f026f98e2191bc6090e..a49c3bfd4dd5825ce960e32c75e357ebdbcb1b92 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * security/tomoyo/common.c
+ * security/tomoyo/securityfs_if.c
  *
- * Securityfs interface for TOMOYO.
- *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include <linux/security.h>
@@ -34,11 +32,11 @@ static int tomoyo_open(struct inode *inode, struct file *file)
  */
 static int tomoyo_release(struct inode *inode, struct file *file)
 {
-       return tomoyo_close_control(file);
+       return tomoyo_close_control(file->private_data);
 }
 
 /**
- * tomoyo_poll - poll() for /proc/ccs/ interface.
+ * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface.
  *
  * @file: Pointer to "struct file".
  * @wait: Pointer to "poll_table".
@@ -63,7 +61,7 @@ static unsigned int tomoyo_poll(struct file *file, poll_table *wait)
 static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
                           loff_t *ppos)
 {
-       return tomoyo_read_control(file, buf, count);
+       return tomoyo_read_control(file->private_data, buf, count);
 }
 
 /**
@@ -79,7 +77,7 @@ static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
 static ssize_t tomoyo_write(struct file *file, const char __user *buf,
                            size_t count, loff_t *ppos)
 {
-       return tomoyo_write_control(file, buf, count);
+       return tomoyo_write_control(file->private_data, buf, count);
 }
 
 /*
@@ -135,14 +133,14 @@ static int __init tomoyo_initerface_init(void)
                            TOMOYO_DOMAINPOLICY);
        tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
                            TOMOYO_EXCEPTIONPOLICY);
+       tomoyo_create_entry("audit",            0400, tomoyo_dir,
+                           TOMOYO_AUDIT);
        tomoyo_create_entry("self_domain",      0400, tomoyo_dir,
                            TOMOYO_SELFDOMAIN);
-       tomoyo_create_entry(".domain_status",   0600, tomoyo_dir,
-                           TOMOYO_DOMAIN_STATUS);
        tomoyo_create_entry(".process_status",  0600, tomoyo_dir,
                            TOMOYO_PROCESS_STATUS);
-       tomoyo_create_entry("meminfo",          0600, tomoyo_dir,
-                           TOMOYO_MEMINFO);
+       tomoyo_create_entry("stat",             0644, tomoyo_dir,
+                           TOMOYO_STAT);
        tomoyo_create_entry("profile",          0600, tomoyo_dir,
                            TOMOYO_PROFILE);
        tomoyo_create_entry("manager",          0600, tomoyo_dir,
index 95d3f95722378583c4a0bbd1bb97f77d4368d155..f776400a8f3136aefb705aa2893e250ec4122939 100644 (file)
@@ -1,20 +1,35 @@
 /*
  * security/tomoyo/tomoyo.c
  *
- * LSM hooks for TOMOYO Linux.
- *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include <linux/security.h>
 #include "common.h"
 
+/**
+ * tomoyo_cred_alloc_blank - Target for security_cred_alloc_blank().
+ *
+ * @new: Pointer to "struct cred".
+ * @gfp: Memory allocation flags.
+ *
+ * Returns 0.
+ */
 static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp)
 {
        new->security = NULL;
        return 0;
 }
 
+/**
+ * tomoyo_cred_prepare - Target for security_prepare_creds().
+ *
+ * @new: Pointer to "struct cred".
+ * @old: Pointer to "struct cred".
+ * @gfp: Memory allocation flags.
+ *
+ * Returns 0.
+ */
 static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
                               gfp_t gfp)
 {
@@ -25,11 +40,22 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
        return 0;
 }
 
+/**
+ * tomoyo_cred_transfer - Target for security_transfer_creds().
+ *
+ * @new: Pointer to "struct cred".
+ * @old: Pointer to "struct cred".
+ */
 static void tomoyo_cred_transfer(struct cred *new, const struct cred *old)
 {
        tomoyo_cred_prepare(new, old, 0);
 }
 
+/**
+ * tomoyo_cred_free - Target for security_cred_free().
+ *
+ * @cred: Pointer to "struct cred".
+ */
 static void tomoyo_cred_free(struct cred *cred)
 {
        struct tomoyo_domain_info *domain = cred->security;
@@ -37,6 +63,13 @@ static void tomoyo_cred_free(struct cred *cred)
                atomic_dec(&domain->users);
 }
 
+/**
+ * tomoyo_bprm_set_creds - Target for security_bprm_set_creds().
+ *
+ * @bprm: Pointer to "struct linux_binprm".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
 {
        int rc;
@@ -51,12 +84,14 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
         */
        if (bprm->cred_prepared)
                return 0;
+#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
        /*
         * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested
         * for the first time.
         */
        if (!tomoyo_policy_loaded)
                tomoyo_load_policy(bprm->filename);
+#endif
        /*
         * Release reference to "struct tomoyo_domain_info" stored inside
         * "bprm->cred->security". New reference to "struct tomoyo_domain_info"
@@ -73,6 +108,13 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
        return 0;
 }
 
+/**
+ * tomoyo_bprm_check_security - Target for security_bprm_check().
+ *
+ * @bprm: Pointer to "struct linux_binprm".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
 {
        struct tomoyo_domain_info *domain = bprm->cred->security;
@@ -90,20 +132,59 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
        /*
         * Read permission is checked against interpreters using next domain.
         */
-       return tomoyo_check_open_permission(domain, &bprm->file->f_path, O_RDONLY);
+       return tomoyo_check_open_permission(domain, &bprm->file->f_path,
+                                           O_RDONLY);
+}
+
+/**
+ * tomoyo_inode_getattr - Target for security_inode_getattr().
+ *
+ * @mnt:    Pointer to "struct vfsmount".
+ * @dentry: Pointer to "struct dentry".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+{
+       struct path path = { mnt, dentry };
+       return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, &path, NULL);
 }
 
+/**
+ * tomoyo_path_truncate - Target for security_path_truncate().
+ *
+ * @path: Pointer to "struct path".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_truncate(struct path *path)
 {
-       return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path);
+       return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL);
 }
 
+/**
+ * tomoyo_path_unlink - Target for security_path_unlink().
+ *
+ * @parent: Pointer to "struct path".
+ * @dentry: Pointer to "struct dentry".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry)
 {
        struct path path = { parent->mnt, dentry };
-       return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path);
+       return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL);
 }
 
+/**
+ * tomoyo_path_mkdir - Target for security_path_mkdir().
+ *
+ * @parent: Pointer to "struct path".
+ * @dentry: Pointer to "struct dentry".
+ * @mode:   DAC permission mode.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
                             int mode)
 {
@@ -112,19 +193,46 @@ static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
                                       mode & S_IALLUGO);
 }
 
+/**
+ * tomoyo_path_rmdir - Target for security_path_rmdir().
+ *
+ * @parent: Pointer to "struct path".
+ * @dentry: Pointer to "struct dentry".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry)
 {
        struct path path = { parent->mnt, dentry };
-       return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path);
+       return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL);
 }
 
+/**
+ * tomoyo_path_symlink - Target for security_path_symlink().
+ *
+ * @parent:   Pointer to "struct path".
+ * @dentry:   Pointer to "struct dentry".
+ * @old_name: Symlink's content.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry,
                               const char *old_name)
 {
        struct path path = { parent->mnt, dentry };
-       return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path);
+       return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name);
 }
 
+/**
+ * tomoyo_path_mknod - Target for security_path_mknod().
+ *
+ * @parent: Pointer to "struct path".
+ * @dentry: Pointer to "struct dentry".
+ * @mode:   DAC permission mode.
+ * @dev:    Device attributes.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
                             int mode, unsigned int dev)
 {
@@ -155,6 +263,15 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
        return tomoyo_path_number_perm(type, &path, perm);
 }
 
+/**
+ * tomoyo_path_link - Target for security_path_link().
+ *
+ * @old_dentry: Pointer to "struct dentry".
+ * @new_dir:    Pointer to "struct path".
+ * @new_dentry: Pointer to "struct dentry".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
                            struct dentry *new_dentry)
 {
@@ -163,6 +280,16 @@ static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
        return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2);
 }
 
+/**
+ * tomoyo_path_rename - Target for security_path_rename().
+ *
+ * @old_parent: Pointer to "struct path".
+ * @old_dentry: Pointer to "struct dentry".
+ * @new_parent: Pointer to "struct path".
+ * @new_dentry: Pointer to "struct dentry".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_rename(struct path *old_parent,
                              struct dentry *old_dentry,
                              struct path *new_parent,
@@ -173,14 +300,32 @@ static int tomoyo_path_rename(struct path *old_parent,
        return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2);
 }
 
+/**
+ * tomoyo_file_fcntl - Target for security_file_fcntl().
+ *
+ * @file: Pointer to "struct file".
+ * @cmd:  Command for fcntl().
+ * @arg:  Argument for @cmd.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
                             unsigned long arg)
 {
-       if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
-               return tomoyo_path_perm(TOMOYO_TYPE_REWRITE, &file->f_path);
-       return 0;
+       if (!(cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)))
+               return 0;
+       return tomoyo_check_open_permission(tomoyo_domain(), &file->f_path,
+                                           O_WRONLY | (arg & O_APPEND));
 }
 
+/**
+ * tomoyo_dentry_open - Target for security_dentry_open().
+ *
+ * @f:    Pointer to "struct file".
+ * @cred: Pointer to "struct cred".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
 {
        int flags = f->f_flags;
@@ -190,12 +335,30 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
        return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags);
 }
 
+/**
+ * tomoyo_file_ioctl - Target for security_file_ioctl().
+ *
+ * @file: Pointer to "struct file".
+ * @cmd:  Command for ioctl().
+ * @arg:  Argument for @cmd.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
                             unsigned long arg)
 {
        return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd);
 }
 
+/**
+ * tomoyo_path_chmod - Target for security_path_chmod().
+ *
+ * @dentry: Pointer to "struct dentry".
+ * @mnt:    Pointer to "struct vfsmount".
+ * @mode:   DAC permission mode.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
                             mode_t mode)
 {
@@ -204,6 +367,15 @@ static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
                                       mode & S_IALLUGO);
 }
 
+/**
+ * tomoyo_path_chown - Target for security_path_chown().
+ *
+ * @path: Pointer to "struct path".
+ * @uid:  Owner ID.
+ * @gid:  Group ID.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid)
 {
        int error = 0;
@@ -214,23 +386,57 @@ static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid)
        return error;
 }
 
+/**
+ * tomoyo_path_chroot - Target for security_path_chroot().
+ *
+ * @path: Pointer to "struct path".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_path_chroot(struct path *path)
 {
-       return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path);
+       return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path, NULL);
 }
 
+/**
+ * tomoyo_sb_mount - Target for security_sb_mount().
+ *
+ * @dev_name: Name of device file. Maybe NULL.
+ * @path:     Pointer to "struct path".
+ * @type:     Name of filesystem type. Maybe NULL.
+ * @flags:    Mount options.
+ * @data:     Optional data. Maybe NULL.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_sb_mount(char *dev_name, struct path *path,
                           char *type, unsigned long flags, void *data)
 {
        return tomoyo_mount_permission(dev_name, path, type, flags, data);
 }
 
+/**
+ * tomoyo_sb_umount - Target for security_sb_umount().
+ *
+ * @mnt:   Pointer to "struct vfsmount".
+ * @flags: Unmount options.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_sb_umount(struct vfsmount *mnt, int flags)
 {
        struct path path = { mnt, mnt->mnt_root };
-       return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path);
+       return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL);
 }
 
+/**
+ * tomoyo_sb_pivotroot - Target for security_sb_pivotroot().
+ *
+ * @old_path: Pointer to "struct path".
+ * @new_path: Pointer to "struct path".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path)
 {
        return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path);
@@ -258,6 +464,7 @@ static struct security_operations tomoyo_security_ops = {
        .path_mknod          = tomoyo_path_mknod,
        .path_link           = tomoyo_path_link,
        .path_rename         = tomoyo_path_rename,
+       .inode_getattr       = tomoyo_inode_getattr,
        .file_ioctl          = tomoyo_file_ioctl,
        .path_chmod          = tomoyo_path_chmod,
        .path_chown          = tomoyo_path_chown,
@@ -270,6 +477,11 @@ static struct security_operations tomoyo_security_ops = {
 /* Lock for GC. */
 struct srcu_struct tomoyo_ss;
 
+/**
+ * tomoyo_init - Register TOMOYO Linux as a LSM module.
+ *
+ * Returns 0.
+ */
 static int __init tomoyo_init(void)
 {
        struct cred *cred = (struct cred *) current_cred();
index 6d5393204d951ef0bdd2d7306ff8648bdf141078..c36bd1107fc8bbf549dbbc11b7ca7c21b61276a1 100644 (file)
@@ -1,9 +1,7 @@
 /*
  * security/tomoyo/util.c
  *
- * Utility functions for TOMOYO.
- *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  */
 
 #include <linux/slab.h>
@@ -15,18 +13,130 @@ DEFINE_MUTEX(tomoyo_policy_lock);
 /* Has /sbin/init started? */
 bool tomoyo_policy_loaded;
 
+/*
+ * Mapping table from "enum tomoyo_mac_index" to
+ * "enum tomoyo_mac_category_index".
+ */
+const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
+       /* CONFIG::file group */
+       [TOMOYO_MAC_FILE_EXECUTE]    = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_OPEN]       = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_CREATE]     = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_UNLINK]     = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_GETATTR]    = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_MKDIR]      = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_RMDIR]      = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_MKFIFO]     = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_MKSOCK]     = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_TRUNCATE]   = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_SYMLINK]    = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_MKBLOCK]    = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_MKCHAR]     = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_LINK]       = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_RENAME]     = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_CHMOD]      = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_CHOWN]      = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_CHGRP]      = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_IOCTL]      = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_CHROOT]     = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_MOUNT]      = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_UMOUNT]     = TOMOYO_MAC_CATEGORY_FILE,
+       [TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE,
+};
+
+/**
+ * tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
+ *
+ * @time:  Seconds since 1970/01/01 00:00:00.
+ * @stamp: Pointer to "struct tomoyo_time".
+ *
+ * Returns nothing.
+ *
+ * This function does not handle Y2038 problem.
+ */
+void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp)
+{
+       static const u16 tomoyo_eom[2][12] = {
+               { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+               { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+       };
+       u16 y;
+       u8 m;
+       bool r;
+       stamp->sec = time % 60;
+       time /= 60;
+       stamp->min = time % 60;
+       time /= 60;
+       stamp->hour = time % 24;
+       time /= 24;
+       for (y = 1970; ; y++) {
+               const unsigned short days = (y & 3) ? 365 : 366;
+               if (time < days)
+                       break;
+               time -= days;
+       }
+       r = (y & 3) == 0;
+       for (m = 0; m < 11 && time >= tomoyo_eom[r][m]; m++)
+               ;
+       if (m)
+               time -= tomoyo_eom[r][m - 1];
+       stamp->year = y;
+       stamp->month = ++m;
+       stamp->day = ++time;
+}
+
+/**
+ * tomoyo_permstr - Find permission keywords.
+ *
+ * @string: String representation for permissions in foo/bar/buz format.
+ * @keyword: Keyword to find from @string/
+ *
+ * Returns ture if @keyword was found in @string, false otherwise.
+ *
+ * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
+ */
+bool tomoyo_permstr(const char *string, const char *keyword)
+{
+       const char *cp = strstr(string, keyword);
+       if (cp)
+               return cp == string || *(cp - 1) == '/';
+       return false;
+}
+
+/**
+ * tomoyo_read_token - Read a word from a line.
+ *
+ * @param: Pointer to "struct tomoyo_acl_param".
+ *
+ * Returns a word on success, "" otherwise.
+ *
+ * To allow the caller to skip NULL check, this function returns "" rather than
+ * NULL if there is no more words to read.
+ */
+char *tomoyo_read_token(struct tomoyo_acl_param *param)
+{
+       char *pos = param->data;
+       char *del = strchr(pos, ' ');
+       if (del)
+               *del++ = '\0';
+       else
+               del = pos + strlen(pos);
+       param->data = del;
+       return pos;
+}
+
 /**
  * tomoyo_parse_ulong - Parse an "unsigned long" value.
  *
  * @result: Pointer to "unsigned long".
  * @str:    Pointer to string to parse.
  *
- * Returns value type on success, 0 otherwise.
+ * Returns one of values in "enum tomoyo_value_type".
  *
  * The @src is updated to point the first character after the value
  * on success.
  */
-static u8 tomoyo_parse_ulong(unsigned long *result, char **str)
+u8 tomoyo_parse_ulong(unsigned long *result, char **str)
 {
        const char *cp = *str;
        char *ep;
@@ -43,7 +153,7 @@ static u8 tomoyo_parse_ulong(unsigned long *result, char **str)
        }
        *result = simple_strtoul(cp, &ep, base);
        if (cp == ep)
-               return 0;
+               return TOMOYO_VALUE_TYPE_INVALID;
        *str = ep;
        switch (base) {
        case 16:
@@ -81,63 +191,65 @@ void tomoyo_print_ulong(char *buffer, const int buffer_len,
 /**
  * tomoyo_parse_name_union - Parse a tomoyo_name_union.
  *
- * @filename: Name or name group.
- * @ptr:      Pointer to "struct tomoyo_name_union".
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @ptr:   Pointer to "struct tomoyo_name_union".
  *
  * Returns true on success, false otherwise.
  */
-bool tomoyo_parse_name_union(const char *filename,
+bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
                             struct tomoyo_name_union *ptr)
 {
-       if (!tomoyo_correct_word(filename))
-               return false;
-       if (filename[0] == '@') {
-               ptr->group = tomoyo_get_group(filename + 1, TOMOYO_PATH_GROUP);
-               ptr->is_group = true;
+       char *filename;
+       if (param->data[0] == '@') {
+               param->data++;
+               ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP);
                return ptr->group != NULL;
        }
+       filename = tomoyo_read_token(param);
+       if (!tomoyo_correct_word(filename))
+               return false;
        ptr->filename = tomoyo_get_name(filename);
-       ptr->is_group = false;
        return ptr->filename != NULL;
 }
 
 /**
  * tomoyo_parse_number_union - Parse a tomoyo_number_union.
  *
- * @data: Number or number range or number group.
- * @ptr:  Pointer to "struct tomoyo_number_union".
+ * @param: Pointer to "struct tomoyo_acl_param".
+ * @ptr:   Pointer to "struct tomoyo_number_union".
  *
  * Returns true on success, false otherwise.
  */
-bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num)
+bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
+                              struct tomoyo_number_union *ptr)
 {
+       char *data;
        u8 type;
        unsigned long v;
-       memset(num, 0, sizeof(*num));
-       if (data[0] == '@') {
-               if (!tomoyo_correct_word(data))
-                       return false;
-               num->group = tomoyo_get_group(data + 1, TOMOYO_NUMBER_GROUP);
-               num->is_group = true;
-               return num->group != NULL;
+       memset(ptr, 0, sizeof(*ptr));
+       if (param->data[0] == '@') {
+               param->data++;
+               ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP);
+               return ptr->group != NULL;
        }
+       data = tomoyo_read_token(param);
        type = tomoyo_parse_ulong(&v, &data);
-       if (!type)
+       if (type == TOMOYO_VALUE_TYPE_INVALID)
                return false;
-       num->values[0] = v;
-       num->min_type = type;
+       ptr->values[0] = v;
+       ptr->value_type[0] = type;
        if (!*data) {
-               num->values[1] = v;
-               num->max_type = type;
+               ptr->values[1] = v;
+               ptr->value_type[1] = type;
                return true;
        }
        if (*data++ != '-')
                return false;
        type = tomoyo_parse_ulong(&v, &data);
-       if (!type || *data)
+       if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
                return false;
-       num->values[1] = v;
-       num->max_type = type;
+       ptr->values[1] = v;
+       ptr->value_type[1] = type;
        return true;
 }
 
@@ -184,6 +296,30 @@ static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
        return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
 }
 
+/**
+ * tomoyo_valid - Check whether the character is a valid char.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is a valid character, false otherwise.
+ */
+static inline bool tomoyo_valid(const unsigned char c)
+{
+       return c > ' ' && c < 127;
+}
+
+/**
+ * tomoyo_invalid - Check whether the character is an invalid char.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is an invalid character, false otherwise.
+ */
+static inline bool tomoyo_invalid(const unsigned char c)
+{
+       return c && (c <= ' ' || c >= 127);
+}
+
 /**
  * tomoyo_str_starts - Check whether the given string starts with the given keyword.
  *
@@ -237,37 +373,10 @@ void tomoyo_normalize_line(unsigned char *buffer)
        *dp = '\0';
 }
 
-/**
- * tomoyo_tokenize - Tokenize string.
- *
- * @buffer: The line to tokenize.
- * @w:      Pointer to "char *".
- * @size:   Sizeof @w .
- *
- * Returns true on success, false otherwise.
- */
-bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
-{
-       int count = size / sizeof(char *);
-       int i;
-       for (i = 0; i < count; i++)
-               w[i] = "";
-       for (i = 0; i < count; i++) {
-               char *cp = strchr(buffer, ' ');
-               if (cp)
-                       *cp = '\0';
-               w[i] = buffer;
-               if (!cp)
-                       break;
-               buffer = cp + 1;
-       }
-       return i < count || !*buffer;
-}
-
 /**
  * tomoyo_correct_word2 - Validate a string.
  *
- * @string: The string to check. May be non-'\0'-terminated.
+ * @string: The string to check. Maybe non-'\0'-terminated.
  * @len:    Length of @string.
  *
  * Check whether the given string follows the naming rules.
@@ -377,26 +486,21 @@ bool tomoyo_correct_path(const char *filename)
  */
 bool tomoyo_correct_domain(const unsigned char *domainname)
 {
-       if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
-                                  TOMOYO_ROOT_NAME_LEN))
-               goto out;
-       domainname += TOMOYO_ROOT_NAME_LEN;
-       if (!*domainname)
+       if (!domainname || !tomoyo_domain_def(domainname))
+               return false;
+       domainname = strchr(domainname, ' ');
+       if (!domainname++)
                return true;
-       if (*domainname++ != ' ')
-               goto out;
        while (1) {
                const unsigned char *cp = strchr(domainname, ' ');
                if (!cp)
                        break;
                if (*domainname != '/' ||
                    !tomoyo_correct_word2(domainname, cp - domainname))
-                       goto out;
+                       return false;
                domainname = cp + 1;
        }
        return tomoyo_correct_path(domainname);
- out:
-       return false;
 }
 
 /**
@@ -408,7 +512,19 @@ bool tomoyo_correct_domain(const unsigned char *domainname)
  */
 bool tomoyo_domain_def(const unsigned char *buffer)
 {
-       return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
+       const unsigned char *cp;
+       int len;
+       if (*buffer != '<')
+               return false;
+       cp = strchr(buffer, ' ');
+       if (!cp)
+               len = strlen(buffer);
+       else
+               len = cp - buffer;
+       if (buffer[len - 1] != '>' ||
+           !tomoyo_correct_word2(buffer + 1, len - 2))
+               return false;
+       return true;
 }
 
 /**
@@ -794,22 +910,24 @@ const char *tomoyo_get_exe(void)
 /**
  * tomoyo_get_mode - Get MAC mode.
  *
+ * @ns:      Pointer to "struct tomoyo_policy_namespace".
  * @profile: Profile number.
  * @index:   Index number of functionality.
  *
  * Returns mode.
  */
-int tomoyo_get_mode(const u8 profile, const u8 index)
+int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
+                   const u8 index)
 {
        u8 mode;
        const u8 category = TOMOYO_MAC_CATEGORY_FILE;
        if (!tomoyo_policy_loaded)
                return TOMOYO_CONFIG_DISABLED;
-       mode = tomoyo_profile(profile)->config[index];
+       mode = tomoyo_profile(ns, profile)->config[index];
        if (mode == TOMOYO_CONFIG_USE_DEFAULT)
-               mode = tomoyo_profile(profile)->config[category];
+               mode = tomoyo_profile(ns, profile)->config[category];
        if (mode == TOMOYO_CONFIG_USE_DEFAULT)
-               mode = tomoyo_profile(profile)->default_config;
+               mode = tomoyo_profile(ns, profile)->default_config;
        return mode & 3;
 }
 
@@ -833,64 +951,10 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r,
        profile = domain->profile;
        r->profile = profile;
        r->type = index;
-       r->mode = tomoyo_get_mode(profile, index);
+       r->mode = tomoyo_get_mode(domain->ns, profile, index);
        return r->mode;
 }
 
-/**
- * tomoyo_last_word - Get last component of a line.
- *
- * @line: A line.
- *
- * Returns the last word of a line.
- */
-const char *tomoyo_last_word(const char *name)
-{
-       const char *cp = strrchr(name, ' ');
-       if (cp)
-               return cp + 1;
-       return name;
-}
-
-/**
- * tomoyo_warn_log - Print warning or error message on console.
- *
- * @r:   Pointer to "struct tomoyo_request_info".
- * @fmt: The printf()'s format string, followed by parameters.
- */
-void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
-{
-       va_list args;
-       char *buffer;
-       const struct tomoyo_domain_info * const domain = r->domain;
-       const struct tomoyo_profile *profile = tomoyo_profile(domain->profile);
-       switch (r->mode) {
-       case TOMOYO_CONFIG_ENFORCING:
-               if (!profile->enforcing->enforcing_verbose)
-                       return;
-               break;
-       case TOMOYO_CONFIG_PERMISSIVE:
-               if (!profile->permissive->permissive_verbose)
-                       return;
-               break;
-       case TOMOYO_CONFIG_LEARNING:
-               if (!profile->learning->learning_verbose)
-                       return;
-               break;
-       }
-       buffer = kmalloc(4096, GFP_NOFS);
-       if (!buffer)
-               return;
-       va_start(args, fmt);
-       vsnprintf(buffer, 4095, fmt, args);
-       va_end(args);
-       buffer[4095] = '\0';
-       printk(KERN_WARNING "%s: Access %s denied for %s\n",
-              r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
-              tomoyo_last_word(domain->domainname->name));
-       kfree(buffer);
-}
-
 /**
  * tomoyo_domain_quota_is_ok - Check for domain's quota.
  *
@@ -911,52 +975,43 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
        if (!domain)
                return true;
        list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+               u16 perm;
+               u8 i;
                if (ptr->is_deleted)
                        continue;
                switch (ptr->type) {
-                       u16 perm;
-                       u8 i;
                case TOMOYO_TYPE_PATH_ACL:
                        perm = container_of(ptr, struct tomoyo_path_acl, head)
                                ->perm;
-                       for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++)
-                               if (perm & (1 << i))
-                                       count++;
-                       if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
-                               count -= 2;
                        break;
                case TOMOYO_TYPE_PATH2_ACL:
                        perm = container_of(ptr, struct tomoyo_path2_acl, head)
                                ->perm;
-                       for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++)
-                               if (perm & (1 << i))
-                                       count++;
                        break;
                case TOMOYO_TYPE_PATH_NUMBER_ACL:
                        perm = container_of(ptr, struct tomoyo_path_number_acl,
                                            head)->perm;
-                       for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++)
-                               if (perm & (1 << i))
-                                       count++;
                        break;
                case TOMOYO_TYPE_MKDEV_ACL:
                        perm = container_of(ptr, struct tomoyo_mkdev_acl,
                                            head)->perm;
-                       for (i = 0; i < TOMOYO_MAX_MKDEV_OPERATION; i++)
-                               if (perm & (1 << i))
-                                       count++;
                        break;
                default:
-                       count++;
+                       perm = 1;
                }
+               for (i = 0; i < 16; i++)
+                       if (perm & (1 << i))
+                               count++;
        }
-       if (count < tomoyo_profile(domain->profile)->learning->
-           learning_max_entry)
+       if (count < tomoyo_profile(domain->ns, domain->profile)->
+           pref[TOMOYO_PREF_MAX_LEARNING_ENTRY])
                return true;
-       if (!domain->quota_warned) {
-               domain->quota_warned = true;
-               printk(KERN_WARNING "TOMOYO-WARNING: "
-                      "Domain '%s' has so many ACLs to hold. "
+       if (!domain->flags[TOMOYO_DIF_QUOTA_WARNED]) {
+               domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true;
+               /* r->granted = false; */
+               tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]);
+               printk(KERN_WARNING "WARNING: "
+                      "Domain '%s' has too many ACLs to hold. "
                       "Stopped learning mode.\n", domain->domainname->name);
        }
        return false;
index f1341308bedaa585311896d3b62dcca8b86395cb..86d0caf91b35036c1431e4ec9552a560b3deed5c 100644 (file)
@@ -128,7 +128,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
        }
 }
 
-static void pcm_debug_name(struct snd_pcm_substream *substream,
+#ifdef CONFIG_SND_DEBUG
+void snd_pcm_debug_name(struct snd_pcm_substream *substream,
                           char *name, size_t len)
 {
        snprintf(name, len, "pcmC%dD%d%c:%d",
@@ -137,6 +138,8 @@ static void pcm_debug_name(struct snd_pcm_substream *substream,
                 substream->stream ? 'c' : 'p',
                 substream->number);
 }
+EXPORT_SYMBOL(snd_pcm_debug_name);
+#endif
 
 #define XRUN_DEBUG_BASIC       (1<<0)
 #define XRUN_DEBUG_STACK       (1<<1)  /* dump also stack */
@@ -168,7 +171,7 @@ static void xrun(struct snd_pcm_substream *substream)
        snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
        if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
                char name[16];
-               pcm_debug_name(substream, name, sizeof(name));
+               snd_pcm_debug_name(substream, name, sizeof(name));
                snd_printd(KERN_DEBUG "XRUN: %s\n", name);
                dump_stack_on_xrun(substream);
        }
@@ -243,7 +246,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
                return;
        if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
                return;
-       pcm_debug_name(substream, name, sizeof(name));
+       snd_pcm_debug_name(substream, name, sizeof(name));
        for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) {
                entry = &log->entries[idx];
                if (entry->period_size == 0)
@@ -319,7 +322,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
        if (pos >= runtime->buffer_size) {
                if (printk_ratelimit()) {
                        char name[16];
-                       pcm_debug_name(substream, name, sizeof(name));
+                       snd_pcm_debug_name(substream, name, sizeof(name));
                        xrun_log_show(substream);
                        snd_printd(KERN_ERR  "BUG: %s, pos = %ld, "
                                   "buffer size = %ld, period size = %ld\n",
@@ -364,7 +367,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
        if (xrun_debug(substream, in_interrupt ?
                        XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
                char name[16];
-               pcm_debug_name(substream, name, sizeof(name));
+               snd_pcm_debug_name(substream, name, sizeof(name));
                snd_printd("%s_update: %s: pos=%u/%u/%u, "
                           "hwptr=%ld/%ld/%ld/%ld\n",
                           in_interrupt ? "period" : "hwptr",
index 4831800239d3b786081de5b17b06bff2e2d8caa9..484a35b3715f6142a5d806c6b798651a71b789fd 100644 (file)
 
 #include <asm/io.h>
 #include <linux/delay.h>
-#include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/version.h>
-#include <sound/core.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
 #include <sound/tea575x-tuner.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -62,17 +62,6 @@ module_param(radio_nr, int, 0);
 #define TEA575X_BIT_DUMMY      (1<<15)         /* buffer */
 #define TEA575X_BIT_FREQ_MASK  0x7fff
 
-static struct v4l2_queryctrl radio_qctrl[] = {
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       }
-};
-
 /*
  * lowlevel part
  */
@@ -266,83 +255,23 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return 0;
 }
 
-static int vidioc_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *qc)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
-               if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
+static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       struct snd_tea575x *tea = video_drvdata(file);
+       struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = tea->mute;
+               tea->mute = ctrl->val;
+               snd_tea575x_set_freq(tea);
                return 0;
        }
-       return -EINVAL;
-}
 
-static int vidioc_s_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *ctrl)
-{
-       struct snd_tea575x *tea = video_drvdata(file);
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUDIO_MUTE:
-               if (tea->mute != ctrl->value) {
-                       tea->mute = ctrl->value;
-                       snd_tea575x_set_freq(tea);
-               }
-               return 0;
-       }
        return -EINVAL;
 }
 
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       if (i != 0)
-               return -EINVAL;
-       return 0;
-}
-
-static int snd_tea575x_exclusive_open(struct file *file)
-{
-       struct snd_tea575x *tea = video_drvdata(file);
-
-       return test_and_set_bit(0, &tea->in_use) ? -EBUSY : 0;
-}
-
-static int snd_tea575x_exclusive_release(struct file *file)
-{
-       struct snd_tea575x *tea = video_drvdata(file);
-
-       clear_bit(0, &tea->in_use);
-       return 0;
-}
-
 static const struct v4l2_file_operations tea575x_fops = {
        .owner          = THIS_MODULE,
-       .open           = snd_tea575x_exclusive_open,
-       .release        = snd_tea575x_exclusive_release,
-       .ioctl          = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
@@ -351,20 +280,19 @@ static const struct v4l2_ioctl_ops tea575x_ioctl_ops = {
        .vidioc_s_tuner     = vidioc_s_tuner,
        .vidioc_g_audio     = vidioc_g_audio,
        .vidioc_s_audio     = vidioc_s_audio,
-       .vidioc_g_input     = vidioc_g_input,
-       .vidioc_s_input     = vidioc_s_input,
        .vidioc_g_frequency = vidioc_g_frequency,
        .vidioc_s_frequency = vidioc_s_frequency,
-       .vidioc_queryctrl   = vidioc_queryctrl,
-       .vidioc_g_ctrl      = vidioc_g_ctrl,
-       .vidioc_s_ctrl      = vidioc_s_ctrl,
 };
 
 static struct video_device tea575x_radio = {
        .name           = "tea575x-tuner",
        .fops           = &tea575x_fops,
        .ioctl_ops      = &tea575x_ioctl_ops,
-       .release        = video_device_release,
+       .release        = video_device_release_empty,
+};
+
+static const struct v4l2_ctrl_ops tea575x_ctrl_ops = {
+       .s_ctrl = tea575x_s_ctrl,
 };
 
 /*
@@ -373,7 +301,6 @@ static struct video_device tea575x_radio = {
 int snd_tea575x_init(struct snd_tea575x *tea)
 {
        int retval;
-       struct video_device *tea575x_radio_inst;
 
        tea->mute = 1;
 
@@ -381,43 +308,49 @@ int snd_tea575x_init(struct snd_tea575x *tea)
        if (snd_tea575x_read(tea) != 0x55AA)
                return -ENODEV;
 
-       tea->in_use = 0;
        tea->val = TEA575X_BIT_BAND_FM | TEA575X_BIT_SEARCH_10_40;
        tea->freq = 90500 * 16;         /* 90.5Mhz default */
+       snd_tea575x_set_freq(tea);
 
-       tea575x_radio_inst = video_device_alloc();
-       if (tea575x_radio_inst == NULL) {
-               printk(KERN_ERR "tea575x-tuner: not enough memory\n");
-               return -ENOMEM;
-       }
+       tea->vd = tea575x_radio;
+       video_set_drvdata(&tea->vd, tea);
+       mutex_init(&tea->mutex);
+       tea->vd.lock = &tea->mutex;
 
-       memcpy(tea575x_radio_inst, &tea575x_radio, sizeof(tea575x_radio));
+       v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
+       tea->vd.ctrl_handler = &tea->ctrl_handler;
+       v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+       retval = tea->ctrl_handler.error;
+       if (retval) {
+               printk(KERN_ERR "tea575x-tuner: can't initialize controls\n");
+               v4l2_ctrl_handler_free(&tea->ctrl_handler);
+               return retval;
+       }
 
-       strcpy(tea575x_radio.name, tea->tea5759 ?
-                                  "TEA5759 radio" : "TEA5757 radio");
+       if (tea->ext_init) {
+               retval = tea->ext_init(tea);
+               if (retval) {
+                       v4l2_ctrl_handler_free(&tea->ctrl_handler);
+                       return retval;
+               }
+       }
 
-       video_set_drvdata(tea575x_radio_inst, tea);
+       v4l2_ctrl_handler_setup(&tea->ctrl_handler);
 
-       retval = video_register_device(tea575x_radio_inst,
-                                      VFL_TYPE_RADIO, radio_nr);
+       retval = video_register_device(&tea->vd, VFL_TYPE_RADIO, radio_nr);
        if (retval) {
                printk(KERN_ERR "tea575x-tuner: can't register video device!\n");
-               kfree(tea575x_radio_inst);
+               v4l2_ctrl_handler_free(&tea->ctrl_handler);
                return retval;
        }
 
-       snd_tea575x_set_freq(tea);
-       tea->vd = tea575x_radio_inst;
-
        return 0;
 }
 
 void snd_tea575x_exit(struct snd_tea575x *tea)
 {
-       if (tea->vd) {
-               video_unregister_device(tea->vd);
-               tea->vd = NULL;
-       }
+       video_unregister_device(&tea->vd);
+       v4l2_ctrl_handler_free(&tea->ctrl_handler);
 }
 
 static int __init alsa_tea575x_module_init(void)
index 4d2a6ae978f720baa57faa391b665b060018da47..8a197fd3c57e07602156d11f3acd1debe33e504c 100644 (file)
@@ -458,7 +458,7 @@ static int ad1848_set_recmask(ad1848_info * devc, int mask)
        return mask;
 }
 
-static void change_bits(ad1848_info * devc, unsigned char *regval,
+static void oss_change_bits(ad1848_info *devc, unsigned char *regval,
                        unsigned char *muteval, int dev, int chn, int newval)
 {
        unsigned char mask;
@@ -516,10 +516,10 @@ static void ad1848_mixer_set_channel(ad1848_info *devc, int dev, int value, int
 
        if (muteregoffs != regoffs) {
                muteval = ad_read(devc, muteregoffs);
-               change_bits(devc, &val, &muteval, dev, channel, value);
+               oss_change_bits(devc, &val, &muteval, dev, channel, value);
        }
        else
-               change_bits(devc, &val, &val, dev, channel, value);
+               oss_change_bits(devc, &val, &val, dev, channel, value);
 
        spin_lock_irqsave(&devc->lock,flags);
        ad_write(devc, regoffs, val);
index 2039d31b7e2248f25fdf3b38c81f264e1669ed4e..f8f3b7a66b7377fcc25fc84b76c8b9b63af44181 100644 (file)
@@ -232,7 +232,7 @@ static int detect_mixer(sb_devc * devc)
        return 1;
 }
 
-static void change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval)
+static void oss_change_bits(sb_devc *devc, unsigned char *regval, int dev, int chn, int newval)
 {
        unsigned char mask;
        int shift;
@@ -284,7 +284,7 @@ int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right)
                return -EINVAL;
 
        val = sb_getmixer(devc, regoffs);
-       change_bits(devc, &val, dev, LEFT_CHN, left);
+       oss_change_bits(devc, &val, dev, LEFT_CHN, left);
 
        if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs)    /*
                                                                 * Change register
@@ -304,7 +304,7 @@ int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right)
                                                         * Read the new one
                                                         */
        }
-       change_bits(devc, &val, dev, RIGHT_CHN, right);
+       oss_change_bits(devc, &val, dev, RIGHT_CHN, right);
 
        sb_setmixer(devc, regoffs, val);
 
index e90d103e177eab214d07dcc8e5a51ea62d91d76f..50abf5bf8e096039c54f1b351d14493fe8dd9012 100644 (file)
@@ -565,8 +565,8 @@ config SND_FM801_TEA575X_BOOL
 
 config SND_TEA575X
        tristate
-       depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO
-       default SND_FM801 || SND_ES1968
+       depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO || RADIO_SF16FMR2
+       default SND_FM801 || SND_ES1968 || RADIO_SF16FMR2
 
 source "sound/pci/hda/Kconfig"
 
index b941d2541ddab492b2b1ac97f36c6fda938f77eb..eae62ebbd2952d3c0559a08dc7989247c52d56c9 100644 (file)
 #include <sound/tlv.h>
 #include <sound/hwdep.h>
 
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
 MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx");
 
-#if defined CONFIG_SND_DEBUG
-/* copied from pcm_lib.c, hope later patch will make that version public
-and this copy can be removed */
-static inline void
-snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
-{
-       snprintf(buf, size, "pcmC%dD%d%c:%d",
-                substream->pcm->card->number,
-                substream->pcm->device,
-                substream->stream ? 'c' : 'p',
-                substream->number);
-}
-#else
-static inline void
-snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
-{
-       *buf = 0;
-}
-#endif
-
 #if defined CONFIG_SND_DEBUG_VERBOSE
 /**
  * snd_printddd - very verbose debug printk
index 65fcf4770731d1e0fa5606112f3c741f38dab7b0..9683f84ecdc835ea964932e358b4a66bcbc6a628 100644 (file)
@@ -107,7 +107,6 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        union hpi_response_buffer_v1 *hr;
        u16 res_max_size;
        u32 uncopied_bytes;
-       struct hpi_adapter *pa = NULL;
        int err = 0;
 
        if (cmd != HPI_IOCTL_LINUX)
@@ -182,8 +181,9 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                /* -1=no data 0=read from user mem, 1=write to user mem */
                int wrflag = -1;
                u32 adapter = hm->h.adapter_index;
+               struct hpi_adapter *pa = &adapters[adapter];
 
-               if ((adapter > HPI_MAX_ADAPTERS) || (!pa->type)) {
+               if ((adapter >= HPI_MAX_ADAPTERS) || (!pa->type)) {
                        hpi_init_response(&hr->r0, HPI_OBJ_ADAPTER,
                                HPI_ADAPTER_OPEN,
                                HPI_ERROR_BAD_ADAPTER_NUMBER);
@@ -197,9 +197,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        goto out;
                }
 
-               pa = &adapters[adapter];
-
-               if (mutex_lock_interruptible(&adapters[adapter].mutex)) {
+               if (mutex_lock_interruptible(&pa->mutex)) {
                        err = -EINTR;
                        goto out;
                }
@@ -235,8 +233,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                                        "stream buffer size %d\n",
                                                        size);
 
-                                               mutex_unlock(&adapters
-                                                       [adapter].mutex);
+                                               mutex_unlock(&pa->mutex);
                                                err = -EINVAL;
                                                goto out;
                                        }
@@ -277,7 +274,7 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                        uncopied_bytes, size);
                }
 
-               mutex_unlock(&adapters[adapter].mutex);
+               mutex_unlock(&pa->mutex);
        }
 
        /* on return response size must be set */
index 7489b46085512fd004046f17a1bd6823d01b5e39..bb7e102d6726284e4a50808a7f887d7128fcffed 100644 (file)
@@ -243,6 +243,7 @@ config SND_HDA_GENERIC
 
 config SND_HDA_POWER_SAVE
        bool "Aggressive power-saving on HD-audio"
+       depends on PM
        help
          Say Y here to enable more aggressive power-saving mode on
          HD-audio driver.  The power-saving timeout can be configured
index 9c27a3a4c4d5a99c81b8820db9e14bb29421ada0..3e7850c238c314113d47330ecb2aa2d3d59982f3 100644 (file)
@@ -91,8 +91,10 @@ EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static void hda_power_work(struct work_struct *work);
 static void hda_keep_power_on(struct hda_codec *codec);
+#define hda_codec_is_power_on(codec)   ((codec)->power_on)
 #else
 static inline void hda_keep_power_on(struct hda_codec *codec) {}
+#define hda_codec_is_power_on(codec)   1
 #endif
 
 /**
@@ -1101,7 +1103,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_HDA(snd_hda_shutup_pins);
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */
 static void restore_shutup_pins(struct hda_codec *codec)
 {
@@ -1499,7 +1501,7 @@ static void purify_inactive_streams(struct hda_codec *codec)
        }
 }
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 /* clean up all streams; called from suspend */
 static void hda_cleanup_all_streams(struct hda_codec *codec)
 {
@@ -1838,7 +1840,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo);
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 /**
  * snd_hda_codec_resume_amp - Resume all AMP commands from the cache
  * @codec: HD-audio codec
@@ -1868,7 +1870,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
        }
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
-#endif /* SND_HDA_NEEDS_RESUME */
+#endif /* CONFIG_PM */
 
 static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
                             unsigned int ofs)
@@ -3082,7 +3084,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
 }
 EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 /*
  * command cache
  */
@@ -3199,53 +3201,32 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
                                          seq->param);
 }
 EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache);
-#endif /* SND_HDA_NEEDS_RESUME */
+#endif /* CONFIG_PM */
 
-/*
- * set power state of the codec
- */
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
-                               unsigned int power_state)
+void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
+                                   unsigned int power_state,
+                                   bool eapd_workaround)
 {
-       hda_nid_t nid;
+       hda_nid_t nid = codec->start_nid;
        int i;
 
-       /* this delay seems necessary to avoid click noise at power-down */
-       if (power_state == AC_PWRST_D3)
-               msleep(100);
-       snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
-                           power_state);
-       /* partial workaround for "azx_get_response timeout" */
-       if (power_state == AC_PWRST_D0 &&
-           (codec->vendor_id & 0xffff0000) == 0x14f10000)
-               msleep(10);
-
-       nid = codec->start_nid;
        for (i = 0; i < codec->num_nodes; i++, nid++) {
                unsigned int wcaps = get_wcaps(codec, nid);
-               if (wcaps & AC_WCAP_POWER) {
-                       unsigned int wid_type = get_wcaps_type(wcaps);
-                       if (power_state == AC_PWRST_D3 &&
-                           wid_type == AC_WID_PIN) {
-                               unsigned int pincap;
-                               /*
-                                * don't power down the widget if it controls
-                                * eapd and EAPD_BTLENABLE is set.
-                                */
-                               pincap = snd_hda_query_pin_caps(codec, nid);
-                               if (pincap & AC_PINCAP_EAPD) {
-                                       int eapd = snd_hda_codec_read(codec,
-                                               nid, 0,
+               if (!(wcaps & AC_WCAP_POWER))
+                       continue;
+               /* don't power down the widget if it controls eapd and
+                * EAPD_BTLENABLE is set.
+                */
+               if (eapd_workaround && power_state == AC_PWRST_D3 &&
+                   get_wcaps_type(wcaps) == AC_WID_PIN &&
+                   (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) {
+                       int eapd = snd_hda_codec_read(codec, nid, 0,
                                                AC_VERB_GET_EAPD_BTLENABLE, 0);
-                                       eapd &= 0x02;
-                                       if (eapd)
-                                               continue;
-                               }
-                       }
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           power_state);
+                       if (eapd & 0x02)
+                               continue;
                }
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
+                                   power_state);
        }
 
        if (power_state == AC_PWRST_D0) {
@@ -3262,6 +3243,26 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
                } while (time_after_eq(end_time, jiffies));
        }
 }
+EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
+
+/*
+ * set power state of the codec
+ */
+static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+                               unsigned int power_state)
+{
+       if (codec->patch_ops.set_power_state) {
+               codec->patch_ops.set_power_state(codec, fg, power_state);
+               return;
+       }
+
+       /* this delay seems necessary to avoid click noise at power-down */
+       if (power_state == AC_PWRST_D3)
+               msleep(100);
+       snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+                           power_state);
+       snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
+}
 
 #ifdef CONFIG_SND_HDA_HWDEP
 /* execute additional init verbs */
@@ -3274,7 +3275,7 @@ static void hda_exec_init_verbs(struct hda_codec *codec)
 static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
 #endif
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 /*
  * call suspend and power-down; used both from PM and power-save
  */
@@ -3315,7 +3316,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
                snd_hda_codec_resume_cache(codec);
        }
 }
-#endif /* SND_HDA_NEEDS_RESUME */
+#endif /* CONFIG_PM */
 
 
 /**
@@ -4071,9 +4072,6 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
 EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
-                               unsigned int power_state);
-
 static void hda_power_work(struct work_struct *work)
 {
        struct hda_codec *codec =
@@ -4376,11 +4374,8 @@ void snd_hda_bus_reboot_notify(struct hda_bus *bus)
        if (!bus)
                return;
        list_for_each_entry(codec, &bus->codec_list, list) {
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-               if (!codec->power_on)
-                       continue;
-#endif
-               if (codec->patch_ops.reboot_notify)
+               if (hda_codec_is_power_on(codec) &&
+                   codec->patch_ops.reboot_notify)
                        codec->patch_ops.reboot_notify(codec);
        }
 }
@@ -5079,11 +5074,10 @@ int snd_hda_suspend(struct hda_bus *bus)
        struct hda_codec *codec;
 
        list_for_each_entry(codec, &bus->codec_list, list) {
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-               if (!codec->power_on)
-                       continue;
-#endif
-               hda_call_codec_suspend(codec);
+               if (hda_codec_is_power_on(codec))
+                       hda_call_codec_suspend(codec);
+               if (codec->patch_ops.post_suspend)
+                       codec->patch_ops.post_suspend(codec);
        }
        return 0;
 }
@@ -5103,6 +5097,8 @@ int snd_hda_resume(struct hda_bus *bus)
        struct hda_codec *codec;
 
        list_for_each_entry(codec, &bus->codec_list, list) {
+               if (codec->patch_ops.pre_resume)
+                       codec->patch_ops.pre_resume(codec);
                if (snd_hda_codec_needs_resume(codec))
                        hda_call_codec_resume(codec);
        }
index f465e07a4879cce4a634a0874cb69f6456fd33c2..755f2b0f9d8e427b8401d4edb871ae5fa694411a 100644 (file)
 #include <sound/pcm.h>
 #include <sound/hwdep.h>
 
-#if defined(CONFIG_PM) || defined(CONFIG_SND_HDA_POWER_SAVE)
-#define SND_HDA_NEEDS_RESUME   /* resume control code is required */
-#endif
-
 /*
  * nodes
  */
@@ -704,8 +700,12 @@ struct hda_codec_ops {
        int (*init)(struct hda_codec *codec);
        void (*free)(struct hda_codec *codec);
        void (*unsol_event)(struct hda_codec *codec, unsigned int res);
-#ifdef SND_HDA_NEEDS_RESUME
+       void (*set_power_state)(struct hda_codec *codec, hda_nid_t fg,
+                               unsigned int power_state);
+#ifdef CONFIG_PM
        int (*suspend)(struct hda_codec *codec, pm_message_t state);
+       int (*post_suspend)(struct hda_codec *codec);
+       int (*pre_resume)(struct hda_codec *codec);
        int (*resume)(struct hda_codec *codec);
 #endif
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -927,7 +927,7 @@ void snd_hda_sequence_write(struct hda_codec *codec,
 int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex);
 
 /* cached write */
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
                              int direct, unsigned int verb, unsigned int parm);
 void snd_hda_sequence_write_cache(struct hda_codec *codec,
@@ -1008,6 +1008,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
  */
 void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen);
 void snd_hda_bus_reboot_notify(struct hda_bus *bus);
+void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
+                                   unsigned int power_state,
+                                   bool eapd_workaround);
 
 /*
  * power management
index 88b277e974096333e847755ae2aaa9dcd05ec84d..2e7ac31afa8df9b320c0e263c1754df5620c7357 100644 (file)
@@ -131,7 +131,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
                             int direction, int idx, int mask, int val);
 int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
                             int dir, int idx, int mask, int val);
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 void snd_hda_codec_resume_amp(struct hda_codec *codec);
 #endif
 
index 1362c8ba4d1ff7988ea9f53b4bbee1ef04dcadf7..8648917acffb57f3af713ef7e9f57828e04b8ef4 100644 (file)
@@ -563,7 +563,7 @@ static void ad198x_free(struct hda_codec *codec)
        snd_hda_detach_beep_device(codec);
 }
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
 {
        ad198x_shutup(codec);
@@ -579,7 +579,7 @@ static const struct hda_codec_ops ad198x_patch_ops = {
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        .check_power_status = ad198x_check_power_status,
 #endif
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
        .suspend = ad198x_suspend,
 #endif
        .reboot_notify = ad198x_shutup,
index 7f93739b1e3339cf131d13f5372c9f5da9abf401..47d6ffc9b5b5c34e4834fb25d163e2384ca0117e 100644 (file)
@@ -25,6 +25,7 @@
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
+#include <sound/tlv.h>
 
 /*
  */
@@ -61,9 +62,15 @@ struct cs_spec {
 
        unsigned int hp_detect:1;
        unsigned int mic_detect:1;
+       /* CS421x */
+       unsigned int spdif_detect:1;
+       unsigned int sense_b:1;
+       hda_nid_t vendor_nid;
+       struct hda_input_mux input_mux;
+       unsigned int last_input;
 };
 
-/* available models */
+/* available models with CS420x */
 enum {
        CS420X_MBP53,
        CS420X_MBP55,
@@ -72,6 +79,12 @@ enum {
        CS420X_MODELS
 };
 
+/* CS421x boards */
+enum {
+       CS421X_CDB4210,
+       CS421X_MODELS
+};
+
 /* Vendor-specific processing widget */
 #define CS420X_VENDOR_NID      0x11
 #define CS_DIG_OUT1_PIN_NID    0x10
@@ -111,21 +124,42 @@ enum {
 /* 0x0009 - 0x0014 -> 12 test regs */
 /* 0x0015 - visibility reg */
 
+/*
+ * Cirrus Logic CS4210
+ *
+ * 1 DAC => HP(sense) / Speakers,
+ * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
+ * 1 SPDIF OUT => SPDIF Trasmitter(sense)
+*/
+#define CS4210_DAC_NID         0x02
+#define CS4210_ADC_NID         0x03
+#define CS421X_VENDOR_NID      0x0B
+#define CS421X_DMIC_PIN_NID    0x09 /* Port E */
+#define CS421X_SPDIF_PIN_NID   0x0A /* Port H */
+
+#define CS421X_IDX_DEV_CFG     0x01
+#define CS421X_IDX_ADC_CFG     0x02
+#define CS421X_IDX_DAC_CFG     0x03
+#define CS421X_IDX_SPK_CTL     0x04
+
+#define SPDIF_EVENT            0x04
 
 static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
 {
-       snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
+       struct cs_spec *spec = codec->spec;
+       snd_hda_codec_write(codec, spec->vendor_nid, 0,
                            AC_VERB_SET_COEF_INDEX, idx);
-       return snd_hda_codec_read(codec, CS420X_VENDOR_NID, 0,
+       return snd_hda_codec_read(codec, spec->vendor_nid, 0,
                                  AC_VERB_GET_PROC_COEF, 0);
 }
 
 static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
                                      unsigned int coef)
 {
-       snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
+       struct cs_spec *spec = codec->spec;
+       snd_hda_codec_write(codec, spec->vendor_nid, 0,
                            AC_VERB_SET_COEF_INDEX, idx);
-       snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0,
+       snd_hda_codec_write(codec, spec->vendor_nid, 0,
                            AC_VERB_SET_PROC_COEF, coef);
 }
 
@@ -347,15 +381,12 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
        nid = codec->start_nid;
        for (i = 0; i < codec->num_nodes; i++, nid++) {
                unsigned int type;
-               int idx;
                type = get_wcaps_type(get_wcaps(codec, nid));
                if (type != AC_WID_AUD_IN)
                        continue;
-               idx = snd_hda_get_conn_index(codec, nid, pin, 0);
-               if (idx >= 0) {
-                       *idxp = idx;
+               *idxp = snd_hda_get_conn_index(codec, nid, pin, false);
+               if (*idxp >= 0)
                        return nid;
-               }
        }
        return 0;
 }
@@ -835,6 +866,8 @@ static int build_digital_input(struct hda_codec *codec)
 
 /*
  * auto-mute and auto-mic switching
+ * CS421x auto-output redirecting
+ * HP/SPK/SPDIF
  */
 
 static void cs_automute(struct hda_codec *codec)
@@ -842,9 +875,25 @@ static void cs_automute(struct hda_codec *codec)
        struct cs_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        unsigned int hp_present;
+       unsigned int spdif_present;
        hda_nid_t nid;
        int i;
 
+       spdif_present = 0;
+       if (cfg->dig_outs) {
+               nid = cfg->dig_out_pins[0];
+               if (is_jack_detectable(codec, nid)) {
+                       /*
+                       TODO: SPDIF output redirect when SENSE_B is enabled.
+                       Shared (SENSE_A) jack (e.g HP/mini-TOSLINK)
+                       assumed.
+                       */
+                       if (snd_hda_jack_detect(codec, nid)
+                               /* && spec->sense_b */)
+                               spdif_present = 1;
+               }
+       }
+
        hp_present = 0;
        for (i = 0; i < cfg->hp_outs; i++) {
                nid = cfg->hp_pins[i];
@@ -854,11 +903,19 @@ static void cs_automute(struct hda_codec *codec)
                if (hp_present)
                        break;
        }
+
+       /* mute speakers if spdif or hp jack is plugged in */
        for (i = 0; i < cfg->speaker_outs; i++) {
                nid = cfg->speaker_pins[i];
                snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
                                    hp_present ? 0 : PIN_OUT);
+               /* detect on spdif is specific to CS421x */
+               if (spec->vendor_nid == CS421X_VENDOR_NID) {
+                       snd_hda_codec_write(codec, nid, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                       spdif_present ? 0 : PIN_OUT);
+               }
        }
        if (spec->board_config == CS420X_MBP53 ||
            spec->board_config == CS420X_MBP55 ||
@@ -867,21 +924,62 @@ static void cs_automute(struct hda_codec *codec)
                snd_hda_codec_write(codec, 0x01, 0,
                                    AC_VERB_SET_GPIO_DATA, gpio);
        }
+
+       /* specific to CS421x */
+       if (spec->vendor_nid == CS421X_VENDOR_NID) {
+               /* mute HPs if spdif jack (SENSE_B) is present */
+               for (i = 0; i < cfg->hp_outs; i++) {
+                       nid = cfg->hp_pins[i];
+                       snd_hda_codec_write(codec, nid, 0,
+                               AC_VERB_SET_PIN_WIDGET_CONTROL,
+                               (spdif_present && spec->sense_b) ? 0 : PIN_HP);
+               }
+
+               /* SPDIF TX on/off */
+               if (cfg->dig_outs) {
+                       nid = cfg->dig_out_pins[0];
+                       snd_hda_codec_write(codec, nid, 0,
+                               AC_VERB_SET_PIN_WIDGET_CONTROL,
+                               spdif_present ? PIN_OUT : 0);
+
+               }
+               /* Update board GPIOs if neccessary ... */
+       }
 }
 
+/*
+ * Auto-input redirect for CS421x
+ * Switch max 3 inputs of a single ADC (nid 3)
+*/
+
 static void cs_automic(struct hda_codec *codec)
 {
        struct cs_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        hda_nid_t nid;
        unsigned int present;
-       
+
        nid = cfg->inputs[spec->automic_idx].pin;
        present = snd_hda_jack_detect(codec, nid);
-       if (present)
-               change_cur_input(codec, spec->automic_idx, 0);
-       else
-               change_cur_input(codec, !spec->automic_idx, 0);
+
+       /* specific to CS421x, single ADC */
+       if (spec->vendor_nid == CS421X_VENDOR_NID) {
+               if (present) {
+                       spec->last_input = spec->cur_input;
+                       spec->cur_input = spec->automic_idx;
+               } else  {
+                       spec->cur_input = spec->last_input;
+               }
+
+               snd_hda_codec_write_cache(codec, spec->cur_adc, 0,
+                                       AC_VERB_SET_CONNECT_SEL,
+                                       spec->adc_idx[spec->cur_input]);
+       } else {
+               if (present)
+                       change_cur_input(codec, spec->automic_idx, 0);
+               else
+                       change_cur_input(codec, !spec->automic_idx, 0);
+       }
 }
 
 /*
@@ -911,23 +1009,28 @@ static void init_output(struct hda_codec *codec)
        for (i = 0; i < cfg->line_outs; i++)
                snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+       /* HP */
        for (i = 0; i < cfg->hp_outs; i++) {
                hda_nid_t nid = cfg->hp_pins[i];
                snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
                if (!cfg->speaker_outs)
                        continue;
-               if (is_jack_detectable(codec, nid)) {
+               if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
                        snd_hda_codec_write(codec, nid, 0,
                                            AC_VERB_SET_UNSOLICITED_ENABLE,
                                            AC_USRSP_EN | HP_EVENT);
                        spec->hp_detect = 1;
                }
        }
+
+       /* Speaker */
        for (i = 0; i < cfg->speaker_outs; i++)
                snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-       if (spec->hp_detect)
+
+       /* SPDIF is enabled on presence detect for CS421x */
+       if (spec->hp_detect || spec->spdif_detect)
                cs_automute(codec);
 }
 
@@ -961,19 +1064,31 @@ static void init_input(struct hda_codec *codec)
                                            AC_VERB_SET_UNSOLICITED_ENABLE,
                                            AC_USRSP_EN | MIC_EVENT);
        }
-       change_cur_input(codec, spec->cur_input, 1);
-       if (spec->mic_detect)
-               cs_automic(codec);
-
-       coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
-       if (is_active_pin(codec, CS_DMIC2_PIN_NID))
-               coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */
-       if (is_active_pin(codec, CS_DMIC1_PIN_NID))
-               coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0 
-                                * No effect if SPDIF_OUT2 is selected in 
-                                * IDX_SPDIF_CTL.
-                                 */
-       cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
+       /* specific to CS421x */
+       if (spec->vendor_nid == CS421X_VENDOR_NID) {
+               if (spec->mic_detect)
+                       cs_automic(codec);
+               else  {
+                       spec->cur_adc = spec->adc_nid[spec->cur_input];
+                       snd_hda_codec_write(codec, spec->cur_adc, 0,
+                                       AC_VERB_SET_CONNECT_SEL,
+                                       spec->adc_idx[spec->cur_input]);
+               }
+       } else {
+               change_cur_input(codec, spec->cur_input, 1);
+               if (spec->mic_detect)
+                       cs_automic(codec);
+
+               coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */
+               if (is_active_pin(codec, CS_DMIC2_PIN_NID))
+                       coef |= 0x0500; /* DMIC2 2 chan on, GPIO1 off */
+               if (is_active_pin(codec, CS_DMIC1_PIN_NID))
+                       coef |= 0x1800; /* DMIC1 2 chan on, GPIO0 off
+                                        * No effect if SPDIF_OUT2 is
+                                        * selected in IDX_SPDIF_CTL.
+                                       */
+               cs_vendor_coef_set(codec, IDX_ADC_CFG, coef);
+       }
 }
 
 static const struct hda_verb cs_coef_init_verbs[] = {
@@ -1221,16 +1336,16 @@ static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
        [CS420X_IMAC27] = imac27_pincfgs,
 };
 
-static void fix_pincfg(struct hda_codec *codec, int model)
+static void fix_pincfg(struct hda_codec *codec, int model,
+                      const struct cs_pincfg **pin_configs)
 {
-       const struct cs_pincfg *cfg = cs_pincfgs[model];
+       const struct cs_pincfg *cfg = pin_configs[model];
        if (!cfg)
                return;
        for (; cfg->nid; cfg++)
                snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
 }
 
-
 static int patch_cs420x(struct hda_codec *codec)
 {
        struct cs_spec *spec;
@@ -1241,11 +1356,13 @@ static int patch_cs420x(struct hda_codec *codec)
                return -ENOMEM;
        codec->spec = spec;
 
+       spec->vendor_nid = CS420X_VENDOR_NID;
+
        spec->board_config =
                snd_hda_check_board_config(codec, CS420X_MODELS,
                                           cs420x_models, cs420x_cfg_tbl);
        if (spec->board_config >= 0)
-               fix_pincfg(codec, spec->board_config);
+               fix_pincfg(codec, spec->board_config, cs_pincfgs);
 
        switch (spec->board_config) {
        case CS420X_IMAC27:
@@ -1272,6 +1389,562 @@ static int patch_cs420x(struct hda_codec *codec)
        return err;
 }
 
+/*
+ * Cirrus Logic CS4210
+ *
+ * 1 DAC => HP(sense) / Speakers,
+ * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
+ * 1 SPDIF OUT => SPDIF Trasmitter(sense)
+*/
+
+/* CS4210 board names */
+static const char *cs421x_models[CS421X_MODELS] = {
+       [CS421X_CDB4210] = "cdb4210",
+};
+
+static const struct snd_pci_quirk cs421x_cfg_tbl[] = {
+       /* Test Intel board + CDB2410  */
+       SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
+       {} /* terminator */
+};
+
+/* CS4210 board pinconfigs */
+/* Default CS4210 (CDB4210)*/
+static const struct cs_pincfg cdb4210_pincfgs[] = {
+       { 0x05, 0x0321401f },
+       { 0x06, 0x90170010 },
+       { 0x07, 0x03813031 },
+       { 0x08, 0xb7a70037 },
+       { 0x09, 0xb7a6003e },
+       { 0x0a, 0x034510f0 },
+       {} /* terminator */
+};
+
+static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = {
+       [CS421X_CDB4210] = cdb4210_pincfgs,
+};
+
+static const struct hda_verb cs421x_coef_init_verbs[] = {
+       {0x0B, AC_VERB_SET_PROC_STATE, 1},
+       {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
+       /*
+           Disable Coefficient Index Auto-Increment(DAI)=1,
+           PDREF=0
+       */
+       {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
+       /* ADC SZCMode = Digital Soft Ramp */
+       {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
+       {0x0B, AC_VERB_SET_PROC_COEF,
+        (0x0002 /* DAC SZCMode = Digital Soft Ramp */
+         | 0x0004 /* Mute DAC on FIFO error */
+         | 0x0008 /* Enable DAC High Pass Filter */
+         )},
+       {} /* terminator */
+};
+
+/* Errata: CS4210 rev A1 Silicon
+ *
+ * http://www.cirrus.com/en/pubs/errata/
+ *
+ * Description:
+ * 1. Performance degredation is present in the ADC.
+ * 2. Speaker output is not completely muted upon HP detect.
+ * 3. Noise is present when clipping occurs on the amplified
+ *    speaker outputs.
+ *
+ * Workaround:
+ * The following verb sequence written to the registers during
+ * initialization will correct the issues listed above.
+ */
+
+static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
+       {0x0B, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
+       {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
+       {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
+       {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
+       {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
+       {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
+
+       {} /* terminator */
+};
+
+/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
+static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
+
+static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 3;
+       return 0;
+}
+
+static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] =
+               cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
+       return 0;
+}
+
+static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+       unsigned int vol = ucontrol->value.integer.value[0];
+       unsigned int coef =
+               cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
+       unsigned int original_coef = coef;
+
+       coef &= ~0x0003;
+       coef |= (vol & 0x0003);
+       if (original_coef == coef)
+               return 0;
+       else {
+               cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
+               return 1;
+       }
+}
+
+static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = {
+
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+       .name = "Speaker Boost Playback Volume",
+       .info = cs421x_boost_vol_info,
+       .get = cs421x_boost_vol_get,
+       .put = cs421x_boost_vol_put,
+       .tlv = { .p = cs421x_speaker_boost_db_scale },
+};
+
+static void cs421x_pinmux_init(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       unsigned int def_conf, coef;
+
+       /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
+       coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+
+       if (spec->gpio_mask)
+               coef |= 0x0008; /* B1,B2 are GPIOs */
+       else
+               coef &= ~0x0008;
+
+       if (spec->sense_b)
+               coef |= 0x0010; /* B2 is SENSE_B, not inverted  */
+       else
+               coef &= ~0x0010;
+
+       cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+
+       if ((spec->gpio_mask || spec->sense_b) &&
+           is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
+
+               /*
+                   GPIO or SENSE_B forced - disconnect the DMIC pin.
+               */
+               def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
+               def_conf &= ~AC_DEFCFG_PORT_CONN;
+               def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
+               snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
+       }
+}
+
+static void init_cs421x_digital(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+
+       for (i = 0; i < cfg->dig_outs; i++) {
+               hda_nid_t nid = cfg->dig_out_pins[i];
+               if (!cfg->speaker_outs)
+                       continue;
+               if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
+
+                       snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_UNSOLICITED_ENABLE,
+                                   AC_USRSP_EN | SPDIF_EVENT);
+                       spec->spdif_detect = 1;
+               }
+       }
+}
+
+static int cs421x_init(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+
+       snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
+       snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
+
+       cs421x_pinmux_init(codec);
+
+       if (spec->gpio_mask) {
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+                                   spec->gpio_mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+                                   spec->gpio_dir);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_data);
+       }
+
+       init_output(codec);
+       init_input(codec);
+       init_cs421x_digital(codec);
+
+       return 0;
+}
+
+/*
+ * CS4210 Input MUX (1 ADC)
+ */
+static int cs421x_mux_enum_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct cs_spec *spec = codec->spec;
+
+       return snd_hda_input_mux_info(&spec->input_mux, uinfo);
+}
+
+static int cs421x_mux_enum_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct cs_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->cur_input;
+       return 0;
+}
+
+static int cs421x_mux_enum_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct cs_spec *spec = codec->spec;
+
+       return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol,
+                               spec->adc_nid[0], &spec->cur_input);
+
+}
+
+static struct snd_kcontrol_new cs421x_capture_source = {
+
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Source",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = cs421x_mux_enum_info,
+       .get = cs421x_mux_enum_get,
+       .put = cs421x_mux_enum_put,
+};
+
+static int cs421x_add_input_volume_control(struct hda_codec *codec, int item)
+{
+       struct cs_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       const struct hda_input_mux *imux = &spec->input_mux;
+       hda_nid_t pin = cfg->inputs[item].pin;
+       struct snd_kcontrol *kctl;
+       u32 caps;
+
+       if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP))
+               return 0;
+
+       caps = query_amp_caps(codec, pin, HDA_INPUT);
+       caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+       if (caps <= 1)
+               return 0;
+
+       return add_volume(codec,  imux->items[item].label, 0,
+                         HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl);
+}
+
+/* add a (input-boost) volume control to the given input pin */
+static int build_cs421x_input(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct hda_input_mux *imux = &spec->input_mux;
+       int i, err, type_idx;
+       const char *label;
+
+       if (!spec->num_inputs)
+               return 0;
+
+       /* make bind-capture */
+       spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw);
+       spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol);
+       for (i = 0; i < 2; i++) {
+               struct snd_kcontrol *kctl;
+               int n;
+               if (!spec->capture_bind[i])
+                       return -ENOMEM;
+               kctl = snd_ctl_new1(&cs_capture_ctls[i], codec);
+               if (!kctl)
+                       return -ENOMEM;
+               kctl->private_value = (long)spec->capture_bind[i];
+               err = snd_hda_ctl_add(codec, 0, kctl);
+               if (err < 0)
+                       return err;
+               for (n = 0; n < AUTO_PIN_LAST; n++) {
+                       if (!spec->adc_nid[n])
+                               continue;
+                       err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       /* Add Input MUX Items + Capture Volume/Switch */
+       for (i = 0; i < spec->num_inputs; i++) {
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               snd_hda_add_imux_item(imux, label, spec->adc_idx[i], &type_idx);
+
+               err = cs421x_add_input_volume_control(codec, i);
+               if (err < 0)
+                       return err;
+       }
+
+       /*
+           Add 'Capture Source' Switch if
+               * 2 inputs and no mic detec
+               * 3 inputs
+       */
+       if ((spec->num_inputs == 2 && !spec->mic_detect) ||
+           (spec->num_inputs == 3)) {
+
+               err = snd_hda_ctl_add(codec, spec->adc_nid[0],
+                             snd_ctl_new1(&cs421x_capture_source, codec));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/* Single DAC (Mute/Gain) */
+static int build_cs421x_output(struct hda_codec *codec)
+{
+       hda_nid_t dac = CS4210_DAC_NID;
+       struct cs_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct snd_kcontrol *kctl;
+       int err;
+       char *name = "HP/Speakers";
+
+       fix_volume_caps(codec, dac);
+       if (!spec->vmaster_sw) {
+               err = add_vmaster(codec, dac);
+               if (err < 0)
+                       return err;
+       }
+
+       err = add_mute(codec, name, 0,
+                       HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl);
+       if (err < 0)
+               return err;
+       err = snd_ctl_add_slave(spec->vmaster_sw, kctl);
+       if (err < 0)
+               return err;
+
+       err = add_volume(codec, name, 0,
+                       HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl);
+       if (err < 0)
+               return err;
+       err = snd_ctl_add_slave(spec->vmaster_vol, kctl);
+       if (err < 0)
+               return err;
+
+       if (cfg->speaker_outs) {
+               err = snd_hda_ctl_add(codec, 0,
+                       snd_ctl_new1(&cs421x_speaker_bost_ctl, codec));
+               if (err < 0)
+                       return err;
+       }
+       return err;
+}
+
+static int cs421x_build_controls(struct hda_codec *codec)
+{
+       int err;
+
+       err = build_cs421x_output(codec);
+       if (err < 0)
+               return err;
+       err = build_cs421x_input(codec);
+       if (err < 0)
+               return err;
+       err = build_digital_output(codec);
+       if (err < 0)
+               return err;
+       return cs421x_init(codec);
+}
+
+static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       switch ((res >> 26) & 0x3f) {
+       case HP_EVENT:
+       case SPDIF_EVENT:
+               cs_automute(codec);
+               break;
+
+       case MIC_EVENT:
+               cs_automic(codec);
+               break;
+       }
+}
+
+static int parse_cs421x_input(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t pin = cfg->inputs[i].pin;
+               spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]);
+               spec->cur_input = spec->last_input = i;
+               spec->num_inputs++;
+
+               /* check whether the automatic mic switch is available */
+               if (is_ext_mic(codec, i) && cfg->num_inputs >= 2) {
+                       spec->mic_detect = 1;
+                       spec->automic_idx = i;
+               }
+       }
+       return 0;
+}
+
+static int cs421x_parse_auto_config(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       if (err < 0)
+               return err;
+       err = parse_output(codec);
+       if (err < 0)
+               return err;
+       err = parse_cs421x_input(codec);
+       if (err < 0)
+               return err;
+       err = parse_digital_output(codec);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+       Manage PDREF, when transitioning to D3hot
+       (DAC,ADC) -> D3, PDREF=1, AFG->D3
+*/
+static int cs421x_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       unsigned int coef;
+
+       snd_hda_shutup_pins(codec);
+
+       snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
+                           AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
+       snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
+                           AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
+
+       coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+       coef |= 0x0004; /* PDREF */
+       cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+
+       return 0;
+}
+#endif
+
+static struct hda_codec_ops cs4210_patch_ops = {
+       .build_controls = cs421x_build_controls,
+       .build_pcms = cs_build_pcms,
+       .init = cs421x_init,
+       .free = cs_free,
+       .unsol_event = cs421x_unsol_event,
+#ifdef CONFIG_PM
+       .suspend = cs421x_suspend,
+#endif
+};
+
+static int patch_cs421x(struct hda_codec *codec)
+{
+       struct cs_spec *spec;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+
+       spec->vendor_nid = CS421X_VENDOR_NID;
+
+       spec->board_config =
+               snd_hda_check_board_config(codec, CS421X_MODELS,
+                                          cs421x_models, cs421x_cfg_tbl);
+       if (spec->board_config >= 0)
+               fix_pincfg(codec, spec->board_config, cs421x_pincfgs);
+       /*
+           Setup GPIO/SENSE for each board (if used)
+       */
+       switch (spec->board_config) {
+       case CS421X_CDB4210:
+               snd_printd("CS4210 board: %s\n",
+                       cs421x_models[spec->board_config]);
+/*             spec->gpio_mask = 3;
+               spec->gpio_dir = 3;
+               spec->gpio_data = 3;
+*/
+               spec->sense_b = 1;
+
+               break;
+       }
+
+       /*
+           Update the GPIO/DMIC/SENSE_B pinmux before the configuration
+           is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
+           is disabled.
+       */
+       cs421x_pinmux_init(codec);
+
+       err = cs421x_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       codec->patch_ops = cs4210_patch_ops;
+
+       return 0;
+
+ error:
+       kfree(codec->spec);
+       codec->spec = NULL;
+       return err;
+}
+
 
 /*
  * patch entries
@@ -1279,11 +1952,13 @@ static int patch_cs420x(struct hda_codec *codec)
 static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
        { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
        { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
+       { .id = 0x10134210, .name = "CS4210", .patch = patch_cs421x },
        {} /* terminator */
 };
 
 MODULE_ALIAS("snd-hda-codec-id:10134206");
 MODULE_ALIAS("snd-hda-codec-id:10134207");
+MODULE_ALIAS("snd-hda-codec-id:10134210");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
index 884f67b8f4e093ea415fa249fbb4e9c95afe865d..502fc94994531118926bd8846befcd39a1d55325 100644 (file)
@@ -446,6 +446,19 @@ static int conexant_init_jacks(struct hda_codec *codec)
        return 0;
 }
 
+static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg,
+                              unsigned int power_state)
+{
+       if (power_state == AC_PWRST_D3)
+               msleep(100);
+       snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+                           power_state);
+       /* partial workaround for "azx_get_response timeout" */
+       if (power_state == AC_PWRST_D0)
+               msleep(10);
+       snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
+}
+
 static int conexant_init(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
@@ -588,6 +601,7 @@ static const struct hda_codec_ops conexant_patch_ops = {
        .build_pcms = conexant_build_pcms,
        .init = conexant_init,
        .free = conexant_free,
+       .set_power_state = conexant_set_power,
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        .suspend = conexant_suspend,
 #endif
index 52ce07534e5b1db51b1c68428a9b9268f9fc3bf8..e125c60fe3527abafd690c6825c19c57956c8265 100644 (file)
@@ -895,13 +895,15 @@ static void alc_init_auto_hp(struct hda_codec *codec)
        if (present == 3)
                spec->automute_hp_lo = 1; /* both HP and LO automute */
 
-       if (!cfg->speaker_pins[0]) {
+       if (!cfg->speaker_pins[0] &&
+           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
                memcpy(cfg->speaker_pins, cfg->line_out_pins,
                       sizeof(cfg->speaker_pins));
                cfg->speaker_outs = cfg->line_outs;
        }
 
-       if (!cfg->hp_pins[0]) {
+       if (!cfg->hp_pins[0] &&
+           cfg->line_out_type == AUTO_PIN_HP_OUT) {
                memcpy(cfg->hp_pins, cfg->line_out_pins,
                       sizeof(cfg->hp_pins));
                cfg->hp_outs = cfg->line_outs;
@@ -920,6 +922,7 @@ static void alc_init_auto_hp(struct hda_codec *codec)
                spec->automute_mode = ALC_AUTOMUTE_PIN;
        }
        if (spec->automute && cfg->line_out_pins[0] &&
+           cfg->speaker_pins[0] &&
            cfg->line_out_pins[0] != cfg->hp_pins[0] &&
            cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
                for (i = 0; i < cfg->line_outs; i++) {
@@ -1911,7 +1914,7 @@ static int alc_build_controls(struct hda_codec *codec)
                                return err;
                }
        }
-       if (spec->cap_mixer) {
+       if (spec->cap_mixer && spec->adc_nids) {
                const char *kname = kctl ? kctl->id.name : NULL;
                for (knew = spec->cap_mixer; knew->name; knew++) {
                        if (kname && strcmp(knew->name, kname) == 0)
@@ -2386,7 +2389,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state)
 }
 #endif
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 static int alc_resume(struct hda_codec *codec)
 {
        msleep(150); /* to avoid pop noise */
@@ -2406,7 +2409,7 @@ static const struct hda_codec_ops alc_patch_ops = {
        .init = alc_init,
        .free = alc_free,
        .unsol_event = alc_unsol_event,
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
        .resume = alc_resume,
 #endif
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -2801,7 +2804,8 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
        int i;
 
  again:
-       spec->multiout.num_dacs = 0;
+       /* set num_dacs once to full for alc_auto_look_for_dac() */
+       spec->multiout.num_dacs = cfg->line_outs;
        spec->multiout.hp_nid = 0;
        spec->multiout.extra_out_nid[0] = 0;
        memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
@@ -2834,6 +2838,8 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec)
                }
        }
 
+       /* re-count num_dacs and squash invalid entries */
+       spec->multiout.num_dacs = 0;
        for (i = 0; i < cfg->line_outs; i++) {
                if (spec->private_dac_nids[i])
                        spec->multiout.num_dacs++;
@@ -3674,7 +3680,7 @@ static int patch_alc880(struct hda_codec *codec)
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc880_presets[board_config]);
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
@@ -3801,7 +3807,7 @@ static int patch_alc260(struct hda_codec *codec)
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc260_presets[board_config]);
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
@@ -3980,7 +3986,7 @@ static int patch_alc882(struct hda_codec *codec)
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc882_presets[board_config]);
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
@@ -4134,7 +4140,7 @@ static int patch_alc262(struct hda_codec *codec)
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc262_presets[board_config]);
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
@@ -4290,7 +4296,7 @@ static int patch_alc268(struct hda_codec *codec)
                                          (0 << AC_AMPCAP_MUTE_SHIFT));
        }
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
@@ -4410,7 +4416,7 @@ static void alc269_shutup(struct hda_codec *codec)
        }
 }
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 static int alc269_resume(struct hda_codec *codec)
 {
        if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
@@ -4433,7 +4439,7 @@ static int alc269_resume(struct hda_codec *codec)
        hda_call_check_power_status(codec, 0x01);
        return 0;
 }
-#endif /* SND_HDA_NEEDS_RESUME */
+#endif /* CONFIG_PM */
 
 static void alc269_fixup_hweq(struct hda_codec *codec,
                               const struct alc_fixup *fix, int action)
@@ -4702,7 +4708,7 @@ static int patch_alc269(struct hda_codec *codec)
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc269_presets[board_config]);
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
@@ -4725,7 +4731,7 @@ static int patch_alc269(struct hda_codec *codec)
        spec->vmaster_nid = 0x02;
 
        codec->patch_ops = alc_patch_ops;
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
        codec->patch_ops.resume = alc269_resume;
 #endif
        if (board_config == ALC_MODEL_AUTO)
@@ -4840,7 +4846,7 @@ static int patch_alc861(struct hda_codec *codec)
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc861_presets[board_config]);
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
@@ -4981,7 +4987,7 @@ static int patch_alc861vd(struct hda_codec *codec)
                add_verb(spec, alc660vd_eapd_verbs);
        }
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
@@ -5197,7 +5203,7 @@ static int patch_alc662(struct hda_codec *codec)
        if (board_config != ALC_MODEL_AUTO)
                setup_preset(codec, &alc662_presets[board_config]);
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
@@ -5333,7 +5339,7 @@ static int patch_alc680(struct hda_codec *codec)
 #endif
        }
 
-       if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
+       if (!spec->no_analog && !spec->adc_nids) {
                alc_auto_fill_adc_caps(codec);
                alc_rebuild_imux_for_auto_mic(codec);
                alc_remove_invalid_adc_nids(codec);
index 56425a53cf1bbbc3c8a71f6d249c0ad66bae6868..aa376b59c006227f0f9be4a6349abb8ac4dff6d5 100644 (file)
@@ -95,6 +95,7 @@ enum {
        STAC_92HD83XXX_PWR_REF,
        STAC_DELL_S14,
        STAC_92HD83XXX_HP,
+       STAC_92HD83XXX_HP_cNB11_INTQUAD,
        STAC_HP_DV7_4000,
        STAC_92HD83XXX_MODELS
 };
@@ -212,6 +213,7 @@ struct sigmatel_spec {
        unsigned int gpio_mute;
        unsigned int gpio_led;
        unsigned int gpio_led_polarity;
+       unsigned int vref_led;
 
        /* stream */
        unsigned int stream_delay;
@@ -671,6 +673,30 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static int stac_vrefout_set(struct hda_codec *codec,
+                                       hda_nid_t nid, unsigned int new_vref)
+{
+       int error, pinctl;
+
+       snd_printdd("%s, nid %x ctl %x\n", __func__, nid, new_vref);
+       pinctl = snd_hda_codec_read(codec, nid, 0,
+                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+       if (pinctl < 0)
+               return pinctl;
+
+       pinctl &= 0xff;
+       pinctl &= ~AC_PINCTL_VREFEN;
+       pinctl |= (new_vref & AC_PINCTL_VREFEN);
+
+       error = snd_hda_codec_write_cache(codec, nid, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+       if (error < 0)
+               return error;
+
+       return 1;
+}
+
 static unsigned int stac92xx_vref_set(struct hda_codec *codec,
                                        hda_nid_t nid, unsigned int new_vref)
 {
@@ -1636,10 +1662,17 @@ static const unsigned int hp_dv7_4000_pin_configs[10] = {
        0x40f000f0, 0x40f000f0,
 };
 
+static const unsigned int hp_cNB11_intquad_pin_configs[10] = {
+       0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110,
+       0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130,
+       0x40f000f0, 0x40f000f0,
+};
+
 static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
        [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
        [STAC_DELL_S14] = dell_s14_pin_configs,
+       [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs,
        [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
 };
 
@@ -1649,6 +1682,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
        [STAC_92HD83XXX_PWR_REF] = "mic-ref",
        [STAC_DELL_S14] = "dell-s14",
        [STAC_92HD83XXX_HP] = "hp",
+       [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad",
        [STAC_HP_DV7_4000] = "hp-dv7-4000",
 };
 
@@ -1661,7 +1695,47 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
                      "unknown Dell", STAC_DELL_S14),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600,
-                     "HP", STAC_92HD83XXX_HP),
+                         "HP", STAC_92HD83XXX_HP),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1657,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355B,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355C,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355D,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355E,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355F,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3560,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358B,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358C,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358D,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3591,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3592,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
        {} /* terminator */
 };
 
@@ -4020,6 +4094,8 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
 {
        unsigned int gpiostate, gpiomask, gpiodir;
 
+       snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
+
        gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
                                       AC_VERB_GET_GPIO_DATA, 0);
        gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
@@ -4209,10 +4285,12 @@ static void stac_store_hints(struct hda_codec *codec)
                spec->eapd_switch = val;
        get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity);
        if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
-               spec->gpio_mask |= spec->gpio_led;
-               spec->gpio_dir |= spec->gpio_led;
-               if (spec->gpio_led_polarity)
-                       spec->gpio_data |= spec->gpio_led;
+               if (spec->gpio_led <= 8) {
+                       spec->gpio_mask |= spec->gpio_led;
+                       spec->gpio_dir |= spec->gpio_led;
+                       if (spec->gpio_led_polarity)
+                               spec->gpio_data |= spec->gpio_led;
+               }
        }
 }
 
@@ -4382,11 +4460,26 @@ static void stac92xx_free_kctls(struct hda_codec *codec)
        snd_array_free(&spec->kctls);
 }
 
+static void stac92xx_shutup_pins(struct hda_codec *codec)
+{
+       unsigned int i, def_conf;
+
+       if (codec->bus->shutdown)
+               return;
+       for (i = 0; i < codec->init_pins.used; i++) {
+               struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
+               def_conf = snd_hda_codec_get_pincfg(codec, pin->nid);
+               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
+                       snd_hda_codec_write(codec, pin->nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       }
+}
+
 static void stac92xx_shutup(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
 
-       snd_hda_shutup_pins(codec);
+       stac92xx_shutup_pins(codec);
 
        if (spec->eapd_mask)
                stac_gpio_set(codec, spec->gpio_mask,
@@ -4784,10 +4877,11 @@ static int find_mute_led_gpio(struct hda_codec *codec, int default_polarity)
        if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
                while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
                                                                NULL, dev))) {
-                       if (sscanf(dev->name, "HP_Mute_LED_%d_%d",
+                       if (sscanf(dev->name, "HP_Mute_LED_%d_%x",
                                  &spec->gpio_led_polarity,
                                  &spec->gpio_led) == 2) {
-                               spec->gpio_led = 1 << spec->gpio_led;
+                               if (spec->gpio_led < 4)
+                                       spec->gpio_led = 1 << spec->gpio_led;
                                return 1;
                        }
                        if (sscanf(dev->name, "HP_Mute_LED_%d",
@@ -4885,7 +4979,7 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer,
 #define stac927x_proc_hook     NULL
 #endif
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 static int stac92xx_resume(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4901,29 +4995,81 @@ static int stac92xx_resume(struct hda_codec *codec)
                        stac_issue_unsol_event(codec,
                                               spec->autocfg.line_out_pins[0]);
        }
+       return 0;
+}
+
+static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       stac92xx_shutup(codec);
+       return 0;
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int stac92xx_pre_resume(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
        /* sync mute LED */
-       if (spec->gpio_led)
-               hda_call_check_power_status(codec, 0x01);
+       if (spec->gpio_led) {
+               if (spec->gpio_led <= 8) {
+                       stac_gpio_set(codec, spec->gpio_mask,
+                                       spec->gpio_dir, spec->gpio_data);
+               } else {
+                       stac_vrefout_set(codec,
+                                       spec->gpio_led, spec->vref_led);
+               }
+       }
        return 0;
 }
 
+static int stac92xx_post_suspend(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       if (spec->gpio_led > 8) {
+               /* with vref-out pin used for mute led control
+                * codec AFG is prevented from D3 state, but on
+                * system suspend it can (and should) be used
+                */
+               snd_hda_codec_read(codec, codec->afg, 0,
+                               AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+       }
+       return 0;
+}
+
+static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+                               unsigned int power_state)
+{
+       unsigned int afg_power_state = power_state;
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (power_state == AC_PWRST_D3) {
+               if (spec->gpio_led > 8) {
+                       /* with vref-out pin used for mute led control
+                        * codec AFG is prevented from D3 state
+                        */
+                       afg_power_state = AC_PWRST_D1;
+               }
+               /* this delay seems necessary to avoid click noise at power-down */
+               msleep(100);
+       }
+       snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
+                       afg_power_state);
+       snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
+}
+
 /*
- * using power check for controlling mute led of HP notebooks
- * check for mute state only on Speakers (nid = 0x10)
- *
- * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise
- * the LED is NOT working properly !
- *
- * Changed name to reflect that it now works for any designated
- * model, not just HP HDX.
+ * For this feature CONFIG_SND_HDA_POWER_SAVE is needed
+ * as mute LED state is updated in check_power_status hook
  */
-
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static int stac92xx_hp_check_power_status(struct hda_codec *codec,
-                                             hda_nid_t nid)
+static int stac92xx_update_led_status(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
-       int i, muted = 1;
+       int i, num_ext_dacs, muted = 1;
+       unsigned int muted_lvl, notmtd_lvl;
+       hda_nid_t nid;
+
+       if (!spec->gpio_led)
+               return 0;
 
        for (i = 0; i < spec->multiout.num_dacs; i++) {
                nid = spec->multiout.dac_nids[i];
@@ -4933,27 +5079,58 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec,
                        break;
                }
        }
-       if (muted)
-               spec->gpio_data &= ~spec->gpio_led; /* orange */
-       else
-               spec->gpio_data |= spec->gpio_led; /* white */
-
-       if (!spec->gpio_led_polarity) {
-               /* LED state is inverted on these systems */
-               spec->gpio_data ^= spec->gpio_led;
+       if (muted && spec->multiout.hp_nid)
+               if (!(snd_hda_codec_amp_read(codec,
+                               spec->multiout.hp_nid, 0, HDA_OUTPUT, 0) &
+                                       HDA_AMP_MUTE)) {
+                       muted = 0; /* HP is not muted */
+               }
+       num_ext_dacs = ARRAY_SIZE(spec->multiout.extra_out_nid);
+       for (i = 0; muted && i < num_ext_dacs; i++) {
+               nid = spec->multiout.extra_out_nid[i];
+               if (nid == 0)
+                       break;
+               if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
+                     HDA_AMP_MUTE)) {
+                       muted = 0; /* extra output is not muted */
+               }
        }
+       /*polarity defines *not* muted state level*/
+       if (spec->gpio_led <= 8) {
+               if (muted)
+                       spec->gpio_data &= ~spec->gpio_led; /* orange */
+               else
+                       spec->gpio_data |= spec->gpio_led; /* white */
 
-       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
+               if (!spec->gpio_led_polarity) {
+                       /* LED state is inverted on these systems */
+                       spec->gpio_data ^= spec->gpio_led;
+               }
+               stac_gpio_set(codec, spec->gpio_mask,
+                               spec->gpio_dir, spec->gpio_data);
+       } else {
+               notmtd_lvl = spec->gpio_led_polarity ?
+                               AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_GRD;
+               muted_lvl = spec->gpio_led_polarity ?
+                               AC_PINCTL_VREF_GRD : AC_PINCTL_VREF_HIZ;
+               spec->vref_led = muted ? muted_lvl : notmtd_lvl;
+               stac_vrefout_set(codec, spec->gpio_led, spec->vref_led);
+       }
        return 0;
 }
-#endif
 
-static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
+/*
+ * use power check for controlling mute led of HP notebooks
+ */
+static int stac92xx_check_power_status(struct hda_codec *codec,
+                                             hda_nid_t nid)
 {
-       stac92xx_shutup(codec);
+       stac92xx_update_led_status(codec);
+
        return 0;
 }
-#endif
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+#endif /* CONFIG_PM */
 
 static const struct hda_codec_ops stac92xx_patch_ops = {
        .build_controls = stac92xx_build_controls,
@@ -4961,7 +5138,7 @@ static const struct hda_codec_ops stac92xx_patch_ops = {
        .init = stac92xx_init,
        .free = stac92xx_free,
        .unsol_event = stac92xx_unsol_event,
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
        .suspend = stac92xx_suspend,
        .resume = stac92xx_resume,
 #endif
@@ -5477,12 +5654,19 @@ again:
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (spec->gpio_led) {
-               spec->gpio_mask |= spec->gpio_led;
-               spec->gpio_dir |= spec->gpio_led;
-               spec->gpio_data |= spec->gpio_led;
-               /* register check_power_status callback. */
+               if (spec->gpio_led <= 8) {
+                       spec->gpio_mask |= spec->gpio_led;
+                       spec->gpio_dir |= spec->gpio_led;
+                       spec->gpio_data |= spec->gpio_led;
+               } else {
+                       codec->patch_ops.set_power_state =
+                                       stac92xx_set_power_state;
+                       codec->patch_ops.post_suspend =
+                                       stac92xx_post_suspend;
+               }
+               codec->patch_ops.pre_resume = stac92xx_pre_resume;
                codec->patch_ops.check_power_status =
-                       stac92xx_hp_check_power_status;
+                       stac92xx_check_power_status;
        }
 #endif 
 
@@ -5805,12 +5989,19 @@ again:
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (spec->gpio_led) {
-               spec->gpio_mask |= spec->gpio_led;
-               spec->gpio_dir |= spec->gpio_led;
-               spec->gpio_data |= spec->gpio_led;
-               /* register check_power_status callback. */
+               if (spec->gpio_led <= 8) {
+                       spec->gpio_mask |= spec->gpio_led;
+                       spec->gpio_dir |= spec->gpio_led;
+                       spec->gpio_data |= spec->gpio_led;
+               } else {
+                       codec->patch_ops.set_power_state =
+                                       stac92xx_set_power_state;
+                       codec->patch_ops.post_suspend =
+                                       stac92xx_post_suspend;
+               }
+               codec->patch_ops.pre_resume = stac92xx_pre_resume;
                codec->patch_ops.check_power_status =
-                       stac92xx_hp_check_power_status;
+                       stac92xx_check_power_status;
        }
 #endif 
 
index f38160b00e169fb378bc7f43c7b58cf7ef36390c..84d8798bf33aea5f0e3f864930a67ce2b860b56f 100644 (file)
@@ -1708,7 +1708,7 @@ static void via_unsol_event(struct hda_codec *codec,
                via_gpio_control(codec);
 }
 
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
 static int via_suspend(struct hda_codec *codec, pm_message_t state)
 {
        struct via_spec *spec = codec->spec;
@@ -1736,7 +1736,7 @@ static const struct hda_codec_ops via_patch_ops = {
        .init = via_init,
        .free = via_free,
        .unsol_event = via_unsol_event,
-#ifdef SND_HDA_NEEDS_RESUME
+#ifdef CONFIG_PM
        .suspend = via_suspend,
 #endif
 #ifdef CONFIG_SND_HDA_POWER_SAVE
index ff29380c9ed30ee5eb2eda225e505b1415de0269..76258f2a2ffbe50da655eb563d58858ba9f4d3c9 100644 (file)
@@ -907,6 +907,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec,
                                struct regulator_init_data *init_data,
                                int voltage)
 {
+       dev_err(codec->dev, "this setup needs regulator support in the kernel\n");
        return -EINVAL;
 }
 
@@ -1218,6 +1219,34 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
        return 0;
 }
 
+static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec)
+{
+       struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       /* set internal ldo to 1.2v */
+       ret = ldo_regulator_register(codec, &ldo_init_data, LDO_VOLTAGE);
+       if (ret) {
+               dev_err(codec->dev,
+                       "Failed to register vddd internal supplies: %d\n", ret);
+               return ret;
+       }
+
+       sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
+                       sgtl5000->supplies);
+
+       if (ret) {
+               ldo_regulator_remove(codec);
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       dev_info(codec->dev, "Using internal LDO instead of VDDD\n");
+       return 0;
+}
+
 static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
 {
        u16 reg;
@@ -1235,30 +1264,9 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
        if (!ret)
                external_vddd = 1;
        else {
-               /* set internal ldo to 1.2v */
-               int voltage = LDO_VOLTAGE;
-
-               ret = ldo_regulator_register(codec, &ldo_init_data, voltage);
-               if (ret) {
-                       dev_err(codec->dev,
-                       "Failed to register vddd internal supplies: %d\n",
-                               ret);
-                       return ret;
-               }
-
-               sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
-
-               ret = regulator_bulk_get(codec->dev,
-                               ARRAY_SIZE(sgtl5000->supplies),
-                               sgtl5000->supplies);
-
-               if (ret) {
-                       ldo_regulator_remove(codec);
-                       dev_err(codec->dev,
-                               "Failed to request supplies: %d\n", ret);
-
+               ret = sgtl5000_replace_vddd_with_ldo(codec);
+               if (ret)
                        return ret;
-               }
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
@@ -1287,7 +1295,6 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
         * roll back to use internal LDO
         */
        if (external_vddd && rev >= 0x11) {
-               int voltage = LDO_VOLTAGE;
                /* disable all regulator first */
                regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
                                        sgtl5000->supplies);
@@ -1295,23 +1302,10 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
                regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
                                        sgtl5000->supplies);
 
-               ret = ldo_regulator_register(codec, &ldo_init_data, voltage);
+               ret = sgtl5000_replace_vddd_with_ldo(codec);
                if (ret)
                        return ret;
 
-               sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
-
-               ret = regulator_bulk_get(codec->dev,
-                               ARRAY_SIZE(sgtl5000->supplies),
-                               sgtl5000->supplies);
-               if (ret) {
-                       ldo_regulator_remove(codec);
-                       dev_err(codec->dev,
-                               "Failed to request supplies: %d\n", ret);
-
-                       return ret;
-               }
-
                ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
                                                sgtl5000->supplies);
                if (ret)
index 8499c563a9b5c3ab35eef8eba4b1fc8f44852919..60d740ebeb5bb8b7502dd93b5b2ece605407d70a 100644 (file)
@@ -3409,6 +3409,9 @@ static irqreturn_t wm8962_irq(int irq, void *data)
        active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
        active &= ~mask;
 
+       /* Acknowledge the interrupts */
+       snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
+
        if (active & WM8962_FLL_LOCK_EINT) {
                dev_dbg(codec->dev, "FLL locked\n");
                complete(&wm8962->fll_lock);
@@ -3433,9 +3436,6 @@ static irqreturn_t wm8962_irq(int irq, void *data)
                                      msecs_to_jiffies(250));
        }
 
-       /* Acknowledge the interrupts */
-       snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
-
        return IRQ_HANDLED;
 }
 
index 9259f1f348999cd5963817402023e7b8d805768e..1f11525d97e805ade146e26fe45cf9eb48ed432c 100644 (file)
@@ -62,9 +62,9 @@ static void davinci_vcif_start(struct snd_pcm_substream *substream)
        w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1);
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0);
        else
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1);
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0);
 
        writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
 }
@@ -80,9 +80,9 @@ static void davinci_vcif_stop(struct snd_pcm_substream *substream)
        /* Reset transmitter/receiver and sample rate/frame sync generators */
        w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0);
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1);
        else
-               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0);
+               MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1);
 
        writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
 }
@@ -159,6 +159,7 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                davinci_vcif_start(substream);
+               break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
index 1568eea31f41f17c062fdb7671f570a80c56db4c..c086b78539ee5075f14b76d99089e4abb7f0abf1 100644 (file)
@@ -21,6 +21,7 @@
 #include <plat/audio.h>
 
 #include "dma.h"
+#include "idma.h"
 #include "i2s.h"
 #include "i2s-regs.h"
 
@@ -60,6 +61,7 @@ struct i2s_dai {
        /* DMA parameters */
        struct s3c_dma_params dma_playback;
        struct s3c_dma_params dma_capture;
+       struct s3c_dma_params idma_playback;
        u32     quirks;
        u32     suspend_i2smod;
        u32     suspend_i2scon;
@@ -877,6 +879,10 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
        if (i2s->quirks & QUIRK_NEED_RSTCLR)
                writel(CON_RSTCLR, i2s->addr + I2SCON);
 
+       if (i2s->quirks & QUIRK_SEC_DAI)
+               idma_reg_addr_init((void *)i2s->addr,
+                                       i2s->sec_dai->idma_playback.dma_addr);
+
 probe_exit:
        /* Reset any constraint on RFS and BFS */
        i2s->rfs = 0;
@@ -1077,6 +1083,7 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev)
                sec_dai->dma_playback.dma_size = 4;
                sec_dai->base = regs_base;
                sec_dai->quirks = quirks;
+               sec_dai->idma_playback.dma_addr = i2s_cfg->idma_addr;
                sec_dai->pri_dai = pri_dai;
                pri_dai->sec_dai = sec_dai;
        }
index e44267f662166b86bfbfe2e01f77283cb6ec4ac4..83ad8ca274903cff750166606c613db1c5f79df0 100644 (file)
@@ -577,6 +577,7 @@ int snd_soc_suspend(struct device *dev)
                        case SND_SOC_BIAS_OFF:
                                codec->driver->suspend(codec, PMSG_SUSPEND);
                                codec->suspended = 1;
+                               codec->cache_sync = 1;
                                break;
                        default:
                                dev_dbg(codec->dev, "CODEC is on over suspend\n");
@@ -1140,7 +1141,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
                        }
                }
                cpu_dai->probed = 1;
-               /* mark cpu_dai as probed and add to card cpu_dai list */
+               /* mark cpu_dai as probed and add to card dai list */
                list_add(&cpu_dai->card_list, &card->dai_dev_list);
        }
 
@@ -1171,7 +1172,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
                        }
                }
 
-               /* mark cpu_dai as probed and add to card cpu_dai list */
+               /* mark codec_dai as probed and add to card dai list */
                codec_dai->probed = 1;
                list_add(&codec_dai->card_list, &card->dai_dev_list);
        }
index fbfcda06283976355a7258b93574fa2ff02033e0..7e15914b363362406e868070eb04c347e5fc8c8a 100644 (file)
@@ -124,6 +124,36 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
        return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
 }
 
+/* get snd_card from DAPM context */
+static inline struct snd_card *dapm_get_snd_card(
+       struct snd_soc_dapm_context *dapm)
+{
+       if (dapm->codec)
+               return dapm->codec->card->snd_card;
+       else if (dapm->platform)
+               return dapm->platform->card->snd_card;
+       else
+               BUG();
+
+       /* unreachable */
+       return NULL;
+}
+
+/* get soc_card from DAPM context */
+static inline struct snd_soc_card *dapm_get_soc_card(
+               struct snd_soc_dapm_context *dapm)
+{
+       if (dapm->codec)
+               return dapm->codec->card;
+       else if (dapm->platform)
+               return dapm->platform->card;
+       else
+               BUG();
+
+       /* unreachable */
+       return NULL;
+}
+
 static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
 {
        if (w->codec)
diff --git a/tools/power/cpupower/.gitignore b/tools/power/cpupower/.gitignore
new file mode 100644 (file)
index 0000000..8a83dd2
--- /dev/null
@@ -0,0 +1,22 @@
+.libs
+libcpupower.so
+libcpupower.so.0
+libcpupower.so.0.0.0
+build/ccdv
+cpufreq-info
+cpufreq-set
+cpufreq-aperf
+lib/.libs
+lib/cpufreq.lo
+lib/cpufreq.o
+lib/proc.lo
+lib/proc.o
+lib/sysfs.lo
+lib/sysfs.o
+po/cpupowerutils.pot
+po/*.gmo
+utils/cpufreq-info.o
+utils/cpufreq-set.o
+utils/cpufreq-aperf.o
+cpupower
+bench/cpufreq-bench
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
new file mode 100644 (file)
index 0000000..94c2cf0
--- /dev/null
@@ -0,0 +1,279 @@
+# Makefile for cpupower
+#
+# Copyright (C) 2005,2006 Dominik Brodowski <linux@dominikbrodowski.net>
+#
+# Based largely on the Makefile for udev by:
+#
+# Copyright (C) 2003,2004 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; 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
+#
+
+# --- CONFIGURATION BEGIN ---
+
+# Set the following to `true' to make a unstripped, unoptimized
+# binary. Leave this set to `false' for production use.
+DEBUG ?=       false
+
+# make the build silent. Set this to something else to make it noisy again.
+V ?=           false
+
+# Internationalization support (output in different languages).
+# Requires gettext.
+NLS ?=         true
+
+# Set the following to 'true' to build/install the
+# cpufreq-bench benchmarking tool
+CPUFRQ_BENCH ?= true
+
+# Prefix to the directories we're installing to
+DESTDIR ?=
+
+# --- CONFIGURATION END ---
+
+
+
+# Package-related definitions. Distributions can modify the version
+# and _should_ modify the PACKAGE_BUGREPORT definition
+
+VERSION=                       $(shell ./utils/version-gen.sh)
+LIB_MAJ=                       0.0.0
+LIB_MIN=                       0
+
+PACKAGE =                      cpupower
+PACKAGE_BUGREPORT =            cpufreq@vger.kernel.org
+LANGUAGES =                    de fr it cs pt
+
+
+# Directory definitions. These are default and most probably
+# do not need to be changed. Please note that DESTDIR is
+# added in front of any of them
+
+bindir ?=      /usr/bin
+sbindir ?=     /usr/sbin
+mandir ?=      /usr/man
+includedir ?=  /usr/include
+libdir ?=      /usr/lib
+localedir ?=   /usr/share/locale
+docdir ?=       /usr/share/doc/packages/cpupower
+confdir ?=      /etc/
+
+# Toolchain: what tools do we use, and what options do they need:
+
+CP = cp -fpR
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA  = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+
+# If you are running a cross compiler, you may want to set this
+# to something more interesting, like "arm-linux-".  If you want
+# to compile vs uClibc, that can be done here as well.
+CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc-
+CC = $(CROSS)gcc
+LD = $(CROSS)gcc
+AR = $(CROSS)ar
+STRIP = $(CROSS)strip
+RANLIB = $(CROSS)ranlib
+HOSTCC = gcc
+
+
+# Now we set up the build system
+#
+
+# set up PWD so that older versions of make will work with our build.
+PWD = $(shell pwd)
+
+GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo po/$$HLANG.gmo; done;}
+
+export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS
+
+# check if compiler option is supported
+cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;}
+
+# use '-Os' optimization if available, else use -O2
+OPTIMIZATION := $(call cc-supports,-Os,-O2)
+
+WARNINGS := -Wall -Wchar-subscripts -Wpointer-arith -Wsign-compare
+WARNINGS += $(call cc-supports,-Wno-pointer-sign)
+WARNINGS += $(call cc-supports,-Wdeclaration-after-statement)
+WARNINGS += -Wshadow
+
+CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \
+               -DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE
+
+UTIL_OBJS =  utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \
+       utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \
+       utils/helpers/pci.o utils/helpers/bitmask.o \
+       utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \
+       utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \
+       utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \
+       utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \
+       utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o
+
+UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \
+       utils/helpers/bitmask.h \
+       utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def
+
+UTIL_SRC := $(UTIL_OBJS:.o=.c)
+
+LIB_HEADERS =  lib/cpufreq.h lib/sysfs.h
+LIB_SRC =      lib/cpufreq.c lib/sysfs.c
+LIB_OBJS =     lib/cpufreq.o lib/sysfs.o
+
+CFLAGS +=      -pipe
+
+ifeq ($(strip $(NLS)),true)
+       INSTALL_NLS += install-gmo
+       COMPILE_NLS += create-gmo
+endif
+
+ifeq ($(strip $(CPUFRQ_BENCH)),true)
+       INSTALL_BENCH += install-bench
+       COMPILE_BENCH += compile-bench
+endif
+
+CFLAGS += $(WARNINGS)
+
+ifeq ($(strip $(V)),false)
+       QUIET=@
+       ECHO=@echo
+else
+       QUIET=
+       ECHO=@\#
+endif
+export QUIET ECHO
+
+# if DEBUG is enabled, then we do not strip or optimize
+ifeq ($(strip $(DEBUG)),true)
+       CFLAGS += -O1 -g -DDEBUG
+       STRIPCMD = /bin/true -Since_we_are_debugging
+else
+       CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer
+       STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment
+endif
+
+
+# the actual make rules
+
+all: libcpupower cpupower $(COMPILE_NLS) $(COMPILE_BENCH)
+
+lib/%.o: $(LIB_SRC) $(LIB_HEADERS)
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c
+
+libcpupower.so.$(LIB_MAJ): $(LIB_OBJS)
+       $(ECHO) "  LD      " $@
+       $(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \
+               -Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS)
+       @ln -sf $@ libcpupower.so
+       @ln -sf $@ libcpupower.so.$(LIB_MIN)
+
+libcpupower: libcpupower.so.$(LIB_MAJ)
+
+# Let all .o files depend on its .c file and all headers
+# Might be worth to put this into utils/Makefile at some point of time
+$(UTIL_OBJS): $(UTIL_HEADERS)
+
+.c.o:
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c
+
+cpupower: $(UTIL_OBJS) libcpupower.so.$(LIB_MAJ)
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) -lcpupower -lrt -lpci -L. -o $@ $(UTIL_OBJS)
+       $(QUIET) $(STRIPCMD) $@
+
+po/$(PACKAGE).pot: $(UTIL_SRC)
+       $(ECHO) "  GETTEXT " $@
+       $(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \
+               --keyword=_ --keyword=N_ $(UTIL_SRC) && \
+       test -f $(PACKAGE).po && \
+       mv -f $(PACKAGE).po po/$(PACKAGE).pot
+
+po/%.gmo: po/%.po
+       $(ECHO) "  MSGFMT  " $@
+       $(QUIET) msgfmt -o $@ po/$*.po
+
+create-gmo: ${GMO_FILES}
+
+update-po: po/$(PACKAGE).pot
+       $(ECHO) "  MSGMRG  " $@
+       $(QUIET) @for HLANG in $(LANGUAGES); do \
+               echo -n "Updating $$HLANG "; \
+               if msgmerge po/$$HLANG.po po/$(PACKAGE).pot -o \
+                  po/$$HLANG.new.po; then \
+                       mv -f po/$$HLANG.new.po po/$$HLANG.po; \
+               else \
+                       echo "msgmerge for $$HLANG failed!"; \
+                       rm -f po/$$HLANG.new.po; \
+               fi; \
+       done;
+
+compile-bench: libcpupower.so.$(LIB_MAJ)
+       @V=$(V) confdir=$(confdir) $(MAKE) -C bench
+
+clean:
+       -find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \
+        | xargs rm -f
+       -rm -f $(UTIL_BINS)
+       -rm -f $(IDLE_OBJS)
+       -rm -f cpupower
+       -rm -f libcpupower.so*
+       -rm -rf po/*.gmo po/*.pot
+       $(MAKE) -C bench clean
+
+
+install-lib:
+       $(INSTALL) -d $(DESTDIR)${libdir}
+       $(CP) libcpupower.so* $(DESTDIR)${libdir}/
+       $(INSTALL) -d $(DESTDIR)${includedir}
+       $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h
+
+install-tools:
+       $(INSTALL) -d $(DESTDIR)${bindir}
+       $(INSTALL_PROGRAM) cpupower $(DESTDIR)${bindir}
+
+install-man:
+       $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1
+       $(INSTALL_DATA) -D man/cpupower-frequency-set.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1
+       $(INSTALL_DATA) -D man/cpupower-frequency-info.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-info.1
+       $(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1
+       $(INSTALL_DATA) -D man/cpupower-info.1 $(DESTDIR)${mandir}/man1/cpupower-info.1
+       $(INSTALL_DATA) -D man/cpupower-monitor.1 $(DESTDIR)${mandir}/man1/cpupower-monitor.1
+
+install-gmo:
+       $(INSTALL) -d $(DESTDIR)${localedir}
+       for HLANG in $(LANGUAGES); do \
+               echo '$(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \
+               $(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \
+       done;
+
+install-bench:
+       @#DESTDIR must be set from outside to survive
+       @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench install
+
+install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH)
+
+uninstall:
+       - rm -f $(DESTDIR)${libdir}/libcpupower.*
+       - rm -f $(DESTDIR)${includedir}/cpufreq.h
+       - rm -f $(DESTDIR)${bindir}/utils/cpupower
+       - rm -f $(DESTDIR)${mandir}/man1/cpufreq-set.1
+       - rm -f $(DESTDIR)${mandir}/man1/cpufreq-info.1
+       - for HLANG in $(LANGUAGES); do \
+               rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \
+         done;
+
+.PHONY: all utils libcpupower update-po create-gmo install-lib install-tools install-man install-gmo install uninstall clean
diff --git a/tools/power/cpupower/README b/tools/power/cpupower/README
new file mode 100644 (file)
index 0000000..fd9d4c0
--- /dev/null
@@ -0,0 +1,49 @@
+The cpufrequtils package (homepage: 
+http://www.kernel.org/pub/linux/utils/kernel/cpufreq/cpufrequtils.html ) 
+consists of the following elements:
+
+requirements
+------------
+
+On x86 pciutils is needed at runtime (-lpci).
+For compilation pciutils-devel (pci/pci.h) and a gcc version
+providing cpuid.h is needed.
+For both it's not explicitly checked for (yet).
+
+
+libcpufreq
+----------
+
+"libcpufreq" is a library which offers a unified access method for userspace
+tools and programs to the cpufreq core and drivers in the Linux kernel. This
+allows for code reduction in userspace tools, a clean implementation of
+the interaction to the cpufreq core, and support for both the sysfs and proc
+interfaces [depending on configuration, see below].
+
+
+compilation and installation
+----------------------------
+
+make
+su
+make install
+
+should suffice on most systems. It builds default libcpufreq,
+cpufreq-set and cpufreq-info files and installs them in /usr/lib and
+/usr/bin, respectively. If you want to set up the paths differently and/or
+want to configure the package to your specific needs, you need to open
+"Makefile" with an editor of your choice and edit the block marked
+CONFIGURATION.
+
+
+THANKS
+------
+Many thanks to Mattia Dongili who wrote the autotoolization and
+libtoolization, the manpages and the italian language file for cpufrequtils;
+to Dave Jones for his feedback and his dump_psb tool; to Bruno Ducrot for his
+powernow-k8-decode and intel_gsic tools as well as the french language file;
+and to various others commenting on the previous (pre-)releases of 
+cpufrequtils.
+
+
+        Dominik Brodowski
diff --git a/tools/power/cpupower/ToDo b/tools/power/cpupower/ToDo
new file mode 100644 (file)
index 0000000..874b78b
--- /dev/null
@@ -0,0 +1,11 @@
+ToDos sorted by priority:
+
+- Use bitmask functions to parse CPU topology more robust
+  (current implementation has issues on AMD)
+- Try to read out boost states and frequencies on Intel
+- Adjust README
+- Somewhere saw the ability to read power consumption of
+  RAM from HW on Intel SandyBridge -> another monitor?
+- Add another c1e debug idle monitor
+  -> Is by design racy with BIOS, but could be added
+     with a --force option and some "be careful" messages
diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile
new file mode 100644 (file)
index 0000000..2b67606
--- /dev/null
@@ -0,0 +1,29 @@
+LIBS = -L../ -lm -lcpupower
+
+OBJS = main.o parse.o system.o benchmark.o
+CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\"
+
+%.o : %.c
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) -c $(CFLAGS) $< -o $@
+
+cpufreq-bench: $(OBJS)
+       $(ECHO) "  CC      " $@
+       $(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS)
+
+all: cpufreq-bench
+
+install:
+       mkdir -p $(DESTDIR)/$(sbindir)
+       mkdir -p $(DESTDIR)/$(bindir)
+       mkdir -p $(DESTDIR)/$(docdir)
+       mkdir -p $(DESTDIR)/$(confdir)
+       install -m 755 cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench
+       install -m 755 cpufreq-bench_plot.sh $(DESTDIR)/$(bindir)/cpufreq-bench_plot.sh
+       install -m 644 README-BENCH $(DESTDIR)/$(docdir)/README-BENCH
+       install -m 755 cpufreq-bench_script.sh $(DESTDIR)/$(docdir)/cpufreq-bench_script.sh
+       install -m 644 example.cfg $(DESTDIR)/$(confdir)/cpufreq-bench.conf
+
+clean:
+       rm -f *.o
+       rm -f cpufreq-bench
diff --git a/tools/power/cpupower/bench/README-BENCH b/tools/power/cpupower/bench/README-BENCH
new file mode 100644 (file)
index 0000000..8093ec7
--- /dev/null
@@ -0,0 +1,124 @@
+This is cpufreq-bench, a microbenchmark for the cpufreq framework.
+
+Purpose
+=======
+
+What is this benchmark for:
+  - Identify worst case performance loss when doing dynamic frequency
+    scaling using Linux kernel governors
+  - Identify average reaction time of a governor to CPU load changes
+  - (Stress) Testing whether a cpufreq low level driver or governor works
+    as expected
+  - Identify cpufreq related performance regressions between kernels
+  - Possibly Real time priority testing? -> what happens if there are
+    processes with a higher prio than the governor's kernel thread
+  - ...
+
+What this benchmark does *not* cover:
+  - Power saving related regressions (In fact as better the performance
+    throughput is, the worse the power savings will be, but the first should
+    mostly count more...)
+  - Real world (workloads)
+
+
+Description
+===========
+
+cpufreq-bench helps to test the condition of a given cpufreq governor.
+For that purpose, it compares the performance governor to a configured
+powersave module.
+
+
+How it works
+============
+You can specify load (100% CPU load) and sleep (0% CPU load) times in us which
+will be run X time in a row (cycles):
+
+         sleep=25000
+         load=25000
+         cycles=20
+
+This part of the configuration file will create 25ms load/sleep turns,
+repeated 20 times.
+
+Adding this:
+         sleep_step=25000
+         load_step=25000
+         rounds=5
+Will increase load and sleep time by 25ms 5 times.
+Together you get following test:
+25ms  load/sleep time repeated 20 times (cycles).
+50ms  load/sleep time repeated 20 times (cycles).
+..
+100ms load/sleep time repeated 20 times (cycles).
+
+First it is calibrated how long a specific CPU intensive calculation
+takes on this machine and needs to be run in a loop using the performance
+governor.
+Then the above test runs are processed using the performance governor
+and the governor to test. The time the calculation really needed
+with the dynamic freq scaling governor is compared with the time needed
+on full performance and you get the overall performance loss.
+
+
+Example of expected results with ondemand governor:
+
+This shows expected results of the first two test run rounds from
+above config, you there have:
+
+100% CPU load (load) | 0 % CPU load (sleep)  | round
+   25 ms             |    25 ms              |   1
+   50 ms             |    50 ms              |   2
+
+For example if ondemand governor is configured to have a 50ms
+sampling rate you get:
+
+In round 1, ondemand should have rather static 50% load and probably
+won't ever switch up (as long as up_threshold is above).
+
+In round 2, if the ondemand sampling times exactly match the load/sleep
+trigger of the cpufreq-bench, you will see no performance loss (compare with
+below possible ondemand sample kick ins (1)):
+
+But if ondemand always kicks in in the middle of the load sleep cycles, it
+will always see 50% loads and you get worst performance impact never
+switching up (compare with below possible ondemand sample kick ins (2))::
+
+      50     50   50   50ms ->time
+load -----|     |-----|     |-----|     |-----|
+          |     |     |     |     |     |     |
+sleep     |-----|     |-----|     |-----|     |----
+    |-----|-----|-----|-----|-----|-----|-----|----  ondemand sampling (1)
+         100    0    100    0    100    0    100     load seen by ondemand(%)
+       |-----|-----|-----|-----|-----|-----|-----|--   ondemand sampling (2)
+      50     50    50    50    50    50    50        load seen by ondemand(%)
+
+You can easily test all kind of load/sleep times and check whether your
+governor in average behaves as expected.
+
+
+ToDo
+====
+
+Provide a gnuplot utility script for easy generation of plots to present
+the outcome nicely.
+
+
+cpufreq-bench Command Usage
+===========================
+-l, --load=<long int>           initial load time in us
+-s, --sleep=<long int>          initial sleep time in us
+-x, --load-step=<long int>      time to be added to load time, in us
+-y, --sleep-step=<long int>     time to be added to sleep time, in us
+-c, --cpu=<unsigned int>        CPU Number to use, starting at 0
+-p, --prio=<priority>           scheduler priority, HIGH, LOW or DEFAULT
+-g, --governor=<governor>       cpufreq governor to test
+-n, --cycles=<int>              load/sleep cycles to get an avarage value to compare
+-r, --rounds<int>               load/sleep rounds
+-f, --file=<configfile>         config file to use
+-o, --output=<dir>              output dir, must exist
+-v, --verbose                   verbose output on/off
+
+Due to the high priority, the application may not be responsible for some time.
+After the benchmark, the logfile is saved in OUTPUTDIR/benchmark_TIMESTAMP.log
+
diff --git a/tools/power/cpupower/bench/benchmark.c b/tools/power/cpupower/bench/benchmark.c
new file mode 100644 (file)
index 0000000..81b1c48
--- /dev/null
@@ -0,0 +1,194 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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 <stdio.h>
+#include <unistd.h>
+#include <math.h>
+
+#include "config.h"
+#include "system.h"
+#include "benchmark.h"
+
+/* Print out progress if we log into a file */
+#define show_progress(total_time, progress_time)       \
+if (config->output != stdout) {                                \
+       fprintf(stdout, "Progress: %02lu %%\r",         \
+               (progress_time * 100) / total_time);    \
+       fflush(stdout);                                 \
+}
+
+/**
+ * compute how many rounds of calculation we should do
+ * to get the given load time
+ *
+ * @param load aimed load time in µs
+ *
+ * @retval rounds of calculation
+ **/
+
+unsigned int calculate_timespace(long load, struct config *config)
+{
+       int i;
+       long long now, then;
+       unsigned int estimated = GAUGECOUNT;
+       unsigned int rounds = 0;
+       unsigned int timed = 0;
+
+       if (config->verbose)
+               printf("calibrating load of %lius, please wait...\n", load);
+
+       /* get the initial calculation time for a specific number of rounds */
+       now = get_time();
+       ROUNDS(estimated);
+       then = get_time();
+
+       timed = (unsigned int)(then - now);
+
+       /* approximation of the wanted load time by comparing with the
+        * initial calculation time */
+       for (i = 0; i < 4; i++) {
+               rounds = (unsigned int)(load * estimated / timed);
+               dprintf("calibrating with %u rounds\n", rounds);
+               now = get_time();
+               ROUNDS(rounds);
+               then = get_time();
+
+               timed = (unsigned int)(then - now);
+               estimated = rounds;
+       }
+       if (config->verbose)
+               printf("calibration done\n");
+
+       return estimated;
+}
+
+/**
+ * benchmark
+ * generates a specific sleep an load time with the performance
+ * governor and compares the used time for same calculations done
+ * with the configured powersave governor
+ *
+ * @param config config values for the benchmark
+ *
+ **/
+
+void start_benchmark(struct config *config)
+{
+       unsigned int _round, cycle;
+       long long now, then;
+       long sleep_time = 0, load_time = 0;
+       long performance_time = 0, powersave_time = 0;
+       unsigned int calculations;
+       unsigned long total_time = 0, progress_time = 0;
+
+       sleep_time = config->sleep;
+       load_time = config->load;
+
+       /* For the progress bar */
+       for (_round = 1; _round <= config->rounds; _round++)
+               total_time += _round * (config->sleep + config->load);
+       total_time *= 2; /* powersave and performance cycles */
+
+       for (_round = 0; _round < config->rounds; _round++) {
+               performance_time = 0LL;
+               powersave_time = 0LL;
+
+               show_progress(total_time, progress_time);
+
+               /* set the cpufreq governor to "performance" which disables
+                * P-State switching. */
+               if (set_cpufreq_governor("performance", config->cpu) != 0)
+                       return;
+
+               /* calibrate the calculation time. the resulting calculation
+                * _rounds should produce a load which matches the configured
+                * load time */
+               calculations = calculate_timespace(load_time, config);
+
+               if (config->verbose)
+                       printf("_round %i: doing %u cycles with %u calculations"
+                              " for %lius\n", _round + 1, config->cycles,
+                              calculations, load_time);
+
+               fprintf(config->output, "%u %li %li ",
+                       _round, load_time, sleep_time);
+
+               if (config->verbose)
+                       printf("avarage: %lius, rps:%li\n",
+                               load_time / calculations,
+                               1000000 * calculations / load_time);
+
+               /* do some sleep/load cycles with the performance governor */
+               for (cycle = 0; cycle < config->cycles; cycle++) {
+                       now = get_time();
+                       usleep(sleep_time);
+                       ROUNDS(calculations);
+                       then = get_time();
+                       performance_time += then - now - sleep_time;
+                       if (config->verbose)
+                               printf("performance cycle took %lius, "
+                                       "sleep: %lius, "
+                                       "load: %lius, rounds: %u\n",
+                                       (long)(then - now), sleep_time,
+                                       load_time, calculations);
+               }
+               fprintf(config->output, "%li ",
+                       performance_time / config->cycles);
+
+               progress_time += sleep_time + load_time;
+               show_progress(total_time, progress_time);
+
+               /* set the powersave governor which activates P-State switching
+                * again */
+               if (set_cpufreq_governor(config->governor, config->cpu) != 0)
+                       return;
+
+               /* again, do some sleep/load cycles with the
+                * powersave governor */
+               for (cycle = 0; cycle < config->cycles; cycle++) {
+                       now = get_time();
+                       usleep(sleep_time);
+                       ROUNDS(calculations);
+                       then = get_time();
+                       powersave_time += then - now - sleep_time;
+                       if (config->verbose)
+                               printf("powersave cycle took %lius, "
+                                       "sleep: %lius, "
+                                       "load: %lius, rounds: %u\n",
+                                       (long)(then - now), sleep_time,
+                                       load_time, calculations);
+               }
+
+               progress_time += sleep_time + load_time;
+
+               /* compare the avarage sleep/load cycles  */
+               fprintf(config->output, "%li ",
+                       powersave_time / config->cycles);
+               fprintf(config->output, "%.3f\n",
+                       performance_time * 100.0 / powersave_time);
+               fflush(config->output);
+
+               if (config->verbose)
+                       printf("performance is at %.2f%%\n",
+                               performance_time * 100.0 / powersave_time);
+
+               sleep_time += config->sleep_step;
+               load_time += config->load_step;
+       }
+}
diff --git a/tools/power/cpupower/bench/benchmark.h b/tools/power/cpupower/bench/benchmark.h
new file mode 100644 (file)
index 0000000..51d7f50
--- /dev/null
@@ -0,0 +1,29 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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.
+ */
+
+/* load loop, this schould take about 1 to 2ms to complete */
+#define ROUNDS(x) {unsigned int rcnt;                         \
+               for (rcnt = 0; rcnt < x*1000; rcnt++) { \
+                       (void)(((int)(pow(rcnt, rcnt) * \
+                                     sqrt(rcnt*7230970)) ^ 7230716) ^ \
+                                     (int)atan2(rcnt, rcnt));         \
+               } }                                                     \
+
+
+void start_benchmark(struct config *config);
diff --git a/tools/power/cpupower/bench/config.h b/tools/power/cpupower/bench/config.h
new file mode 100644 (file)
index 0000000..ee6f258
--- /dev/null
@@ -0,0 +1,36 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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.
+ */
+
+/* initial loop count for the load calibration */
+#define GAUGECOUNT     1500
+
+/* default scheduling policy SCHED_OTHER */
+#define SCHEDULER      SCHED_OTHER
+
+#define PRIORITY_DEFAULT 0
+#define PRIORITY_HIGH   sched_get_priority_max(SCHEDULER)
+#define PRIORITY_LOW    sched_get_priority_min(SCHEDULER)
+
+/* enable further debug messages */
+#ifdef DEBUG
+#define dprintf printf
+#else
+#define dprintf(...) do { } while (0)
+#endif
+
diff --git a/tools/power/cpupower/bench/cpufreq-bench_plot.sh b/tools/power/cpupower/bench/cpufreq-bench_plot.sh
new file mode 100644 (file)
index 0000000..410021a
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/bash
+
+# This 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., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc.
+
+# Helper script to easily create nice plots of your cpufreq-bench results
+
+dir=`mktemp -d`
+output_file="cpufreq-bench.png"
+global_title="cpufreq-bench plot"
+picture_type="jpeg"
+file[0]=""
+
+function usage()
+{
+    echo "cpufreq-bench_plot.sh [OPTIONS] logfile [measure_title] [logfile [measure_title]] ...]"
+    echo
+    echo "Options"
+    echo "   -o output_file"
+    echo "   -t global_title"
+    echo "   -p picture_type [jpeg|gif|png|postscript|...]"
+    exit 1
+}
+
+if [ $# -eq 0 ];then
+       echo "No benchmark results file provided"
+       echo
+       usage
+fi
+
+while getopts o:t:p: name ; do
+    case $name in
+       o)
+           output_file="$OPTARG".$picture_type
+           ;;
+       t)
+           global_title="$OPTARG"
+           ;;
+       p)
+           picture_type="$OPTARG"
+           ;;
+        ?)
+           usage
+           ;;
+    esac
+done
+shift $(($OPTIND -1))
+
+plots=0
+while [ "$1" ];do
+    if [ ! -f "$1" ];then
+       echo "File $1 does not exist"
+       usage
+    fi
+    file[$plots]="$1"
+    title[$plots]="$2"
+    # echo "File: ${file[$plots]} - ${title[plots]}"
+    shift;shift
+    plots=$((plots + 1))
+done
+
+echo "set terminal $picture_type"      >> $dir/plot_script.gpl
+echo "set output \"$output_file\""     >> $dir/plot_script.gpl
+echo "set title \"$global_title\""     >> $dir/plot_script.gpl
+echo "set xlabel \"sleep/load time\""  >> $dir/plot_script.gpl
+echo "set ylabel \"Performance (%)\""  >> $dir/plot_script.gpl
+
+for((plot=0;plot<$plots;plot++));do
+
+    # Sanity check
+    ###### I am to dump to get this redirected to stderr/stdout in one awk call... #####
+    cat ${file[$plot]} |grep -v "^#" |awk '{if ($2 != $3) printf("Error in measure %d:Load time %s does not equal sleep time %s, plot will not be correct\n", $1, $2, $3); ERR=1}'
+    ###### I am to dump to get this redirected in one awk call... #####
+
+    # Parse out load time (which must be equal to sleep time for a plot), divide it by 1000
+    # to get ms and parse out the performance in percentage and write it to a temp file for plotting
+    cat ${file[$plot]} |grep -v "^#" |awk '{printf "%lu %.1f\n",$2/1000, $6}' >$dir/data_$plot
+
+    if [ $plot -eq 0 ];then
+       echo -n "plot " >> $dir/plot_script.gpl
+    fi
+    echo -n "\"$dir/data_$plot\" title \"${title[$plot]}\" with lines" >> $dir/plot_script.gpl
+    if [ $(($plot + 1)) -ne $plots ];then
+       echo -n ", " >> $dir/plot_script.gpl
+    fi
+done
+echo >> $dir/plot_script.gpl
+
+gnuplot $dir/plot_script.gpl
+rm -r $dir
\ No newline at end of file
diff --git a/tools/power/cpupower/bench/cpufreq-bench_script.sh b/tools/power/cpupower/bench/cpufreq-bench_script.sh
new file mode 100644 (file)
index 0000000..de20d2a
--- /dev/null
@@ -0,0 +1,101 @@
+#!/bin/bash
+
+# This 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., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc.
+
+# Ondemand up_threshold and sampling rate test script for cpufreq-bench
+# mircobenchmark.
+# Modify the general variables at the top or extend or copy out parts
+# if you want to test other things
+#
+
+# Default with latest kernels is 95, before micro account patches
+# it was 80, cmp. with git commit 808009131046b62ac434dbc796
+UP_THRESHOLD="60 80 95"
+# Depending on the kernel and the HW sampling rate could be restricted
+# and cannot be set that low...
+# E.g. before git commit cef9615a853ebc4972084f7 one could only set
+# min sampling rate of 80000 if CONFIG_HZ=250
+SAMPLING_RATE="20000 80000"
+
+function measure()
+{
+    local -i up_threshold_set
+    local -i sampling_rate_set
+
+    for up_threshold in $UP_THRESHOLD;do
+       for sampling_rate in $SAMPLING_RATE;do
+           # Set values in sysfs
+           echo $up_threshold >/sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold
+           echo $sampling_rate >/sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate
+           up_threshold_set=$(cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold)
+           sampling_rate_set=$(cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate)
+
+           # Verify set values in sysfs
+           if [ ${up_threshold_set} -eq ${up_threshold} ];then
+               echo "up_threshold: $up_threshold, set in sysfs: ${up_threshold_set}"
+           else
+               echo "WARNING: Tried to set up_threshold: $up_threshold, set in sysfs: ${up_threshold_set}"
+           fi
+           if [ ${sampling_rate_set} -eq ${sampling_rate} ];then
+               echo "sampling_rate: $sampling_rate, set in sysfs: ${sampling_rate_set}"
+           else
+               echo "WARNING: Tried to set sampling_rate: $sampling_rate, set in sysfs: ${sampling_rate_set}"
+           fi
+
+           # Benchmark
+           cpufreq-bench -o /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}
+       done
+    done
+}
+
+function create_plots()
+{
+    local command
+
+    for up_threshold in $UP_THRESHOLD;do
+       command="cpufreq-bench_plot.sh -o \"sampling_rate_${SAMPLING_RATE}_up_threshold_${up_threshold}\" -t \"Ondemand sampling_rate: ${SAMPLING_RATE} comparison - Up_threshold: $up_threshold %\""
+       for sampling_rate in $SAMPLING_RATE;do
+           command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"sampling_rate = $sampling_rate\""
+       done
+       echo $command
+       eval "$command"
+       echo
+    done
+
+    for sampling_rate in $SAMPLING_RATE;do
+       command="cpufreq-bench_plot.sh -o \"up_threshold_${UP_THRESHOLD}_sampling_rate_${sampling_rate}\" -t \"Ondemand up_threshold: ${UP_THRESHOLD} % comparison - sampling_rate: $sampling_rate\""
+       for up_threshold in $UP_THRESHOLD;do
+           command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"up_threshold = $up_threshold\""
+       done
+       echo $command
+       eval "$command"
+       echo
+    done
+
+    command="cpufreq-bench_plot.sh -o \"up_threshold_${UP_THRESHOLD}_sampling_rate_${SAMPLING_RATE}\" -t \"Ondemand up_threshold: ${UP_THRESHOLD} and sampling_rate ${SAMPLING_RATE} comparison\""
+    for sampling_rate in $SAMPLING_RATE;do
+       for up_threshold in $UP_THRESHOLD;do
+           command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"up_threshold = $up_threshold - sampling_rate = $sampling_rate\""
+       done
+    done
+    echo "$command"
+    eval "$command"
+}
+
+measure
+create_plots
\ No newline at end of file
diff --git a/tools/power/cpupower/bench/example.cfg b/tools/power/cpupower/bench/example.cfg
new file mode 100644 (file)
index 0000000..f91f643
--- /dev/null
@@ -0,0 +1,11 @@
+sleep = 50000
+load = 50000
+cpu = 0
+priority = LOW
+output = /var/log/cpufreq-bench
+sleep_step = 50000
+load_step = 50000
+cycles = 20
+rounds = 40
+verbose = 0
+governor = ondemand
diff --git a/tools/power/cpupower/bench/main.c b/tools/power/cpupower/bench/main.c
new file mode 100644 (file)
index 0000000..2491031
--- /dev/null
@@ -0,0 +1,202 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include "config.h"
+#include "system.h"
+#include "benchmark.h"
+
+static struct option long_options[] = {
+       {"output",      1,      0,      'o'},
+       {"sleep",       1,      0,      's'},
+       {"load",        1,      0,      'l'},
+       {"verbose",     0,      0,      'v'},
+       {"cpu",         1,      0,      'c'},
+       {"governor",    1,      0,      'g'},
+       {"prio",        1,      0,      'p'},
+       {"file",        1,      0,      'f'},
+       {"cycles",      1,      0,      'n'},
+       {"rounds",      1,      0,      'r'},
+       {"load-step",   1,      0,      'x'},
+       {"sleep-step",  1,      0,      'y'},
+       {"help",        0,      0,      'h'},
+       {0, 0, 0, 0}
+};
+
+/*******************************************************************
+ usage
+*******************************************************************/
+
+void usage()
+{
+       printf("usage: ./bench\n");
+       printf("Options:\n");
+       printf(" -l, --load=<long int>\t\tinitial load time in us\n");
+       printf(" -s, --sleep=<long int>\t\tinitial sleep time in us\n");
+       printf(" -x, --load-step=<long int>\ttime to be added to load time, in us\n");
+       printf(" -y, --sleep-step=<long int>\ttime to be added to sleep time, in us\n");
+       printf(" -c, --cpu=<cpu #>\t\t\tCPU Nr. to use, starting at 0\n");
+       printf(" -p, --prio=<priority>\t\t\tscheduler priority, HIGH, LOW or DEFAULT\n");
+       printf(" -g, --governor=<governor>\t\tcpufreq governor to test\n");
+       printf(" -n, --cycles=<int>\t\t\tload/sleep cycles\n");
+       printf(" -r, --rounds<int>\t\t\tload/sleep rounds\n");
+       printf(" -f, --file=<configfile>\t\tconfig file to use\n");
+       printf(" -o, --output=<dir>\t\t\toutput path. Filename will be OUTPUTPATH/benchmark_TIMESTAMP.log\n");
+       printf(" -v, --verbose\t\t\t\tverbose output on/off\n");
+       printf(" -h, --help\t\t\t\tPrint this help screen\n");
+       exit(1);
+}
+
+/*******************************************************************
+ main
+*******************************************************************/
+
+int main(int argc, char **argv)
+{
+       int c;
+       int option_index = 0;
+       struct config *config = NULL;
+
+       config = prepare_default_config();
+
+       if (config == NULL)
+               return EXIT_FAILURE;
+
+       while (1) {
+               c = getopt_long (argc, argv, "hg:o:s:l:vc:p:f:n:r:x:y:",
+                               long_options, &option_index);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'o':
+                       if (config->output != NULL)
+                               fclose(config->output);
+
+                       config->output = prepare_output(optarg);
+
+                       if (config->output == NULL)
+                               return EXIT_FAILURE;
+
+                       dprintf("user output path -> %s\n", optarg);
+                       break;
+               case 's':
+                       sscanf(optarg, "%li", &config->sleep);
+                       dprintf("user sleep time -> %s\n", optarg);
+                       break;
+               case 'l':
+                       sscanf(optarg, "%li", &config->load);
+                       dprintf("user load time -> %s\n", optarg);
+                       break;
+               case 'c':
+                       sscanf(optarg, "%u", &config->cpu);
+                       dprintf("user cpu -> %s\n", optarg);
+                       break;
+               case 'g':
+                       strncpy(config->governor, optarg, 14);
+                       dprintf("user governor -> %s\n", optarg);
+                       break;
+               case 'p':
+                       if (string_to_prio(optarg) != SCHED_ERR) {
+                               config->prio = string_to_prio(optarg);
+                               dprintf("user prio -> %s\n", optarg);
+                       } else {
+                               if (config != NULL) {
+                                       if (config->output != NULL)
+                                               fclose(config->output);
+                                       free(config);
+                               }
+                               usage();
+                       }
+                       break;
+               case 'n':
+                       sscanf(optarg, "%u", &config->cycles);
+                       dprintf("user cycles -> %s\n", optarg);
+                       break;
+               case 'r':
+                       sscanf(optarg, "%u", &config->rounds);
+                       dprintf("user rounds -> %s\n", optarg);
+                       break;
+               case 'x':
+                       sscanf(optarg, "%li", &config->load_step);
+                       dprintf("user load_step -> %s\n", optarg);
+                       break;
+               case 'y':
+                       sscanf(optarg, "%li", &config->sleep_step);
+                       dprintf("user sleep_step -> %s\n", optarg);
+                       break;
+               case 'f':
+                       if (prepare_config(optarg, config))
+                               return EXIT_FAILURE;
+                       break;
+               case 'v':
+                       config->verbose = 1;
+                       dprintf("verbose output enabled\n");
+                       break;
+               case 'h':
+               case '?':
+               default:
+                       if (config != NULL) {
+                               if (config->output != NULL)
+                                       fclose(config->output);
+                               free(config);
+                       }
+                       usage();
+               }
+       }
+
+       if (config->verbose) {
+               printf("starting benchmark with parameters:\n");
+               printf("config:\n\t"
+                      "sleep=%li\n\t"
+                      "load=%li\n\t"
+                      "sleep_step=%li\n\t"
+                      "load_step=%li\n\t"
+                      "cpu=%u\n\t"
+                      "cycles=%u\n\t"
+                      "rounds=%u\n\t"
+                      "governor=%s\n\n",
+                      config->sleep,
+                      config->load,
+                      config->sleep_step,
+                      config->load_step,
+                      config->cpu,
+                      config->cycles,
+                      config->rounds,
+                      config->governor);
+       }
+
+       prepare_user(config);
+       prepare_system(config);
+       start_benchmark(config);
+
+       if (config->output != stdout)
+               fclose(config->output);
+
+       free(config);
+
+       return EXIT_SUCCESS;
+}
+
diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c
new file mode 100644 (file)
index 0000000..543bba1
--- /dev/null
@@ -0,0 +1,225 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <dirent.h>
+
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "parse.h"
+#include "config.h"
+
+/**
+ * converts priority string to priority
+ *
+ * @param str string that represents a scheduler priority
+ *
+ * @retval priority
+ * @retval SCHED_ERR when the priority doesn't exit
+ **/
+
+enum sched_prio string_to_prio(const char *str)
+{
+       if (strncasecmp("high", str, strlen(str)) == 0)
+               return  SCHED_HIGH;
+       else if (strncasecmp("default", str, strlen(str)) == 0)
+               return SCHED_DEFAULT;
+       else if (strncasecmp("low", str, strlen(str)) == 0)
+               return SCHED_LOW;
+       else
+               return SCHED_ERR;
+}
+
+/**
+ * create and open logfile
+ *
+ * @param dir directory in which the logfile should be created
+ *
+ * @retval logfile on success
+ * @retval NULL when the file can't be created
+ **/
+
+FILE *prepare_output(const char *dirname)
+{
+       FILE *output = NULL;
+       int len;
+       char *filename;
+       struct utsname sysdata;
+       DIR *dir;
+
+       dir = opendir(dirname);
+       if (dir == NULL) {
+               if (mkdir(dirname, 0755)) {
+                       perror("mkdir");
+                       fprintf(stderr, "error: Cannot create dir %s\n",
+                               dirname);
+                       return NULL;
+               }
+       }
+
+       len = strlen(dirname) + 30;
+       filename = malloc(sizeof(char) * len);
+
+       if (uname(&sysdata) == 0) {
+               len += strlen(sysdata.nodename) + strlen(sysdata.release);
+               filename = realloc(filename, sizeof(char) * len);
+
+               if (filename == NULL) {
+                       perror("realloc");
+                       return NULL;
+               }
+
+               snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log",
+                       dirname, sysdata.nodename, sysdata.release, time(NULL));
+       } else {
+               snprintf(filename, len - 1, "%s/benchmark_%li.log",
+                       dirname, time(NULL));
+       }
+
+       dprintf("logilename: %s\n", filename);
+
+       output = fopen(filename, "w+");
+       if (output == NULL) {
+               perror("fopen");
+               fprintf(stderr, "error: unable to open logfile\n");
+       }
+
+       fprintf(stdout, "Logfile: %s\n", filename);
+
+       free(filename);
+       fprintf(output, "#round load sleep performance powersave percentage\n");
+       return output;
+}
+
+/**
+ * returns the default config
+ *
+ * @retval default config on success
+ * @retval NULL when the output file can't be created
+ **/
+
+struct config *prepare_default_config()
+{
+       struct config *config = malloc(sizeof(struct config));
+
+       dprintf("loading defaults\n");
+
+       config->sleep = 500000;
+       config->load = 500000;
+       config->sleep_step = 500000;
+       config->load_step = 500000;
+       config->cycles = 5;
+       config->rounds = 50;
+       config->cpu = 0;
+       config->prio = SCHED_HIGH;
+       config->verbose = 0;
+       strncpy(config->governor, "ondemand", 8);
+
+       config->output = stdout;
+
+#ifdef DEFAULT_CONFIG_FILE
+       if (prepare_config(DEFAULT_CONFIG_FILE, config))
+               return NULL;
+#endif
+       return config;
+}
+
+/**
+ * parses config file and returns the config to the caller
+ *
+ * @param path config file name
+ *
+ * @retval 1 on error
+ * @retval 0 on success
+ **/
+
+int prepare_config(const char *path, struct config *config)
+{
+       size_t len = 0;
+       char *opt, *val, *line = NULL;
+       FILE *configfile = fopen(path, "r");
+
+       if (config == NULL) {
+               fprintf(stderr, "error: config is NULL\n");
+               return 1;
+       }
+
+       if (configfile == NULL) {
+               perror("fopen");
+               fprintf(stderr, "error: unable to read configfile\n");
+               free(config);
+               return 1;
+       }
+
+       while (getline(&line, &len, configfile) != -1) {
+               if (line[0] == '#' || line[0] == ' ')
+                       continue;
+
+               sscanf(line, "%as = %as", &opt, &val);
+
+               dprintf("parsing: %s -> %s\n", opt, val);
+
+               if (strncmp("sleep", opt, strlen(opt)) == 0)
+                       sscanf(val, "%li", &config->sleep);
+
+               else if (strncmp("load", opt, strlen(opt)) == 0)
+                       sscanf(val, "%li", &config->load);
+
+               else if (strncmp("load_step", opt, strlen(opt)) == 0)
+                       sscanf(val, "%li", &config->load_step);
+
+               else if (strncmp("sleep_step", opt, strlen(opt)) == 0)
+                       sscanf(val, "%li", &config->sleep_step);
+
+               else if (strncmp("cycles", opt, strlen(opt)) == 0)
+                       sscanf(val, "%u", &config->cycles);
+
+               else if (strncmp("rounds", opt, strlen(opt)) == 0)
+                       sscanf(val, "%u", &config->rounds);
+
+               else if (strncmp("verbose", opt, strlen(opt)) == 0)
+                       sscanf(val, "%u", &config->verbose);
+
+               else if (strncmp("output", opt, strlen(opt)) == 0)
+                       config->output = prepare_output(val); 
+
+               else if (strncmp("cpu", opt, strlen(opt)) == 0)
+                       sscanf(val, "%u", &config->cpu);
+
+               else if (strncmp("governor", opt, 14) == 0)
+                       strncpy(config->governor, val, 14);
+
+               else if (strncmp("priority", opt, strlen(opt)) == 0) {
+                       if (string_to_prio(val) != SCHED_ERR)
+                               config->prio = string_to_prio(val);
+               }
+       }
+
+       free(line);
+       free(opt);
+       free(val);
+
+       return 0;
+}
diff --git a/tools/power/cpupower/bench/parse.h b/tools/power/cpupower/bench/parse.h
new file mode 100644 (file)
index 0000000..a8dc632
--- /dev/null
@@ -0,0 +1,53 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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.
+ */
+
+/* struct that holds the required config parameters */
+struct config
+{
+       long sleep;             /* sleep time in µs */
+       long load;              /* load time in µs */
+       long sleep_step;        /* time value which changes the
+                                * sleep time after every round in µs */
+       long load_step;         /* time value which changes the
+                                * load time after every round in µs */
+       unsigned int cycles;    /* calculation cycles with the same sleep/load time */
+       unsigned int rounds;    /* calculation rounds with iterated sleep/load time */
+       unsigned int cpu;       /* cpu for which the affinity is set */
+       char governor[15];      /* cpufreq governor */
+       enum sched_prio         /* possible scheduler priorities */
+       {
+               SCHED_ERR = -1,
+               SCHED_HIGH,
+               SCHED_DEFAULT,
+               SCHED_LOW
+       } prio;
+
+       unsigned int verbose;   /* verbose output */
+       FILE *output;           /* logfile */
+       char *output_filename;  /* logfile name, must be freed at the end
+                                  if output != NULL and output != stdout*/
+};
+
+enum sched_prio string_to_prio(const char *str);
+
+FILE *prepare_output(const char *dir);
+
+int prepare_config(const char *path, struct config *config);
+struct config *prepare_default_config();
+
diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c
new file mode 100644 (file)
index 0000000..f01e3f4
--- /dev/null
@@ -0,0 +1,191 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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 <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <sched.h>
+
+#include <cpufreq.h>
+
+#include "config.h"
+#include "system.h"
+
+/**
+ * returns time since epoch in µs
+ *
+ * @retval time
+ **/
+
+long long int get_time()
+{
+       struct timeval now;
+
+       gettimeofday(&now, NULL);
+
+       return (long long int)(now.tv_sec * 1000000LL + now.tv_usec);
+}
+
+/**
+ * sets the cpufreq governor
+ *
+ * @param governor cpufreq governor name
+ * @param cpu cpu for which the governor should be set
+ *
+ * @retval 0 on success
+ * @retval -1 when failed
+ **/
+
+int set_cpufreq_governor(char *governor, unsigned int cpu)
+{
+
+       dprintf("set %s as cpufreq governor\n", governor);
+
+       if (cpufreq_cpu_exists(cpu) != 0) {
+               perror("cpufreq_cpu_exists");
+               fprintf(stderr, "error: cpu %u does not exist\n", cpu);
+               return -1;
+       }
+
+       if (cpufreq_modify_policy_governor(cpu, governor) != 0) {
+               perror("cpufreq_modify_policy_governor");
+               fprintf(stderr, "error: unable to set %s governor\n", governor);
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * sets cpu affinity for the process
+ *
+ * @param cpu cpu# to which the affinity should be set
+ *
+ * @retval 0 on success
+ * @retval -1 when setting the affinity failed
+ **/
+
+int set_cpu_affinity(unsigned int cpu)
+{
+       cpu_set_t cpuset;
+
+       CPU_ZERO(&cpuset);
+       CPU_SET(cpu, &cpuset);
+
+       dprintf("set affinity to cpu #%u\n", cpu);
+
+       if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &cpuset) < 0) {
+               perror("sched_setaffinity");
+               fprintf(stderr, "warning: unable to set cpu affinity\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * sets the process priority parameter
+ *
+ * @param priority priority value
+ *
+ * @retval 0 on success
+ * @retval -1 when setting the priority failed
+ **/
+
+int set_process_priority(int priority)
+{
+       struct sched_param param;
+
+       dprintf("set scheduler priority to %i\n", priority);
+
+       param.sched_priority = priority;
+
+       if (sched_setscheduler(0, SCHEDULER, &param) < 0) {
+               perror("sched_setscheduler");
+               fprintf(stderr, "warning: unable to set scheduler priority\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * notifies the user that the benchmark may run some time
+ *
+ * @param config benchmark config values
+ *
+ **/
+
+void prepare_user(const struct config *config)
+{
+       unsigned long sleep_time = 0;
+       unsigned long load_time = 0;
+       unsigned int round;
+
+       for (round = 0; round < config->rounds; round++) {
+               sleep_time +=  2 * config->cycles *
+                       (config->sleep + config->sleep_step * round);
+               load_time += 2 * config->cycles *
+                       (config->load + config->load_step * round) +
+                       (config->load + config->load_step * round * 4);
+       }
+
+       if (config->verbose || config->output != stdout)
+               printf("approx. test duration: %im\n",
+                      (int)((sleep_time + load_time) / 60000000));
+}
+
+/**
+ * sets up the cpu affinity and scheduler priority
+ *
+ * @param config benchmark config values
+ *
+ **/
+
+void prepare_system(const struct config *config)
+{
+       if (config->verbose)
+               printf("set cpu affinity to cpu #%u\n", config->cpu);
+
+       set_cpu_affinity(config->cpu);
+
+       switch (config->prio) {
+       case SCHED_HIGH:
+               if (config->verbose)
+                       printf("high priority condition requested\n");
+
+               set_process_priority(PRIORITY_HIGH);
+               break;
+       case SCHED_LOW:
+               if (config->verbose)
+                       printf("low priority condition requested\n");
+
+               set_process_priority(PRIORITY_LOW);
+               break;
+       default:
+               if (config->verbose)
+                       printf("default priority condition requested\n");
+
+               set_process_priority(PRIORITY_DEFAULT);
+       }
+}
+
diff --git a/tools/power/cpupower/bench/system.h b/tools/power/cpupower/bench/system.h
new file mode 100644 (file)
index 0000000..3a8c858
--- /dev/null
@@ -0,0 +1,29 @@
+/*  cpufreq-bench CPUFreq microbenchmark
+ *
+ *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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 "parse.h"
+
+long long get_time();
+
+int set_cpufreq_governor(char *governor, unsigned int cpu);
+int set_cpu_affinity(unsigned int cpu);
+int set_process_priority(int priority);
+
+void prepare_user(const struct config *config);
+void prepare_system(const struct config *config);
diff --git a/tools/power/cpupower/debug/i386/Makefile b/tools/power/cpupower/debug/i386/Makefile
new file mode 100644 (file)
index 0000000..d08cc1e
--- /dev/null
@@ -0,0 +1,20 @@
+default: all
+
+centrino-decode: centrino-decode.c
+       $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c
+
+dump_psb: dump_psb.c
+       $(CC) $(CFLAGS) -o dump_psb dump_psb.c
+
+intel_gsic: intel_gsic.c
+       $(CC) $(CFLAGS) -o intel_gsic -llrmi intel_gsic.c
+
+powernow-k8-decode: powernow-k8-decode.c
+       $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c
+
+all: centrino-decode dump_psb intel_gsic powernow-k8-decode
+
+clean:
+       rm -rf centrino-decode dump_psb intel_gsic powernow-k8-decode
+
+.PHONY: all default clean
diff --git a/tools/power/cpupower/debug/i386/centrino-decode.c b/tools/power/cpupower/debug/i386/centrino-decode.c
new file mode 100644 (file)
index 0000000..7ef24cc
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *  (C) 2003 - 2004  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ * Based on code found in
+ * linux/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+ * and originally developed by Jeremy Fitzhardinge.
+ *
+ * USAGE: simply run it to decode the current settings on CPU 0,
+ *       or pass the CPU number as argument, or pass the MSR content
+ *       as argument.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define MCPU   32
+
+#define MSR_IA32_PERF_STATUS   0x198
+
+static int rdmsr(unsigned int cpu, unsigned int msr,
+                unsigned int *lo, unsigned int *hi)
+{
+       int fd;
+       char file[20];
+       unsigned long long val;
+       int retval = -1;
+
+       *lo = *hi = 0;
+
+       if (cpu > MCPU)
+               goto err1;
+
+       sprintf(file, "/dev/cpu/%d/msr", cpu);
+       fd = open(file, O_RDONLY);
+
+       if (fd < 0)
+               goto err1;
+
+       if (lseek(fd, msr, SEEK_CUR) == -1)
+               goto err2;
+
+       if (read(fd, &val, 8) != 8)
+               goto err2;
+
+       *lo = (uint32_t )(val & 0xffffffffull);
+       *hi = (uint32_t )(val>>32 & 0xffffffffull);
+
+       retval = 0;
+err2:
+       close(fd);
+err1:
+       return retval;
+}
+
+static void decode (unsigned int msr)
+{
+       unsigned int multiplier;
+       unsigned int mv;
+
+       multiplier = ((msr >> 8) & 0xFF);
+
+       mv = (((msr & 0xFF) * 16) + 700);
+
+       printf("0x%x means multiplier %d @ %d mV\n", msr, multiplier, mv);
+}
+
+static int decode_live(unsigned int cpu)
+{
+       unsigned int lo, hi;
+       int err;
+
+       err = rdmsr(cpu, MSR_IA32_PERF_STATUS, &lo, &hi);
+
+       if (err) {
+               printf("can't get MSR_IA32_PERF_STATUS for cpu %d\n", cpu);
+               printf("Possible trouble: you don't run an Enhanced SpeedStep capable cpu\n");
+               printf("or you are not root, or the msr driver is not present\n");
+               return 1;
+       }
+
+       decode(lo);
+
+       return 0;
+}
+
+int main (int argc, char **argv)
+{
+       unsigned int cpu, mode = 0;
+
+       if (argc < 2)
+               cpu = 0;
+       else {
+               cpu = strtoul(argv[1], NULL, 0);
+               if (cpu >= MCPU)
+                       mode = 1;
+       }
+
+       if (mode)
+               decode(cpu);
+       else
+               decode_live(cpu);
+
+       return 0;
+}
diff --git a/tools/power/cpupower/debug/i386/dump_psb.c b/tools/power/cpupower/debug/i386/dump_psb.c
new file mode 100644 (file)
index 0000000..8d6a475
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * dump_psb. (c) 2004, Dave Jones, Red Hat Inc.
+ * Licensed under the GPL v2.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <sys/mman.h>
+
+#define LEN (0x100000 - 0xc0000)
+#define OFFSET (0xc0000)
+
+#ifndef __packed
+#define __packed __attribute((packed))
+#endif
+
+static long relevant;
+
+static const int fid_to_mult[32] = {
+       110, 115, 120, 125, 50, 55, 60, 65,
+       70, 75, 80, 85, 90, 95, 100, 105,
+       30, 190, 40, 200, 130, 135, 140, 210,
+       150, 225, 160, 165, 170, 180, -1, -1,
+};
+
+static const int vid_to_voltage[32] = {
+       2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
+       1600, 1550, 1500, 1450, 1400, 1350, 1300, 0,
+       1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
+       1075, 1050, 1024, 1000, 975, 950, 925, 0,
+};
+
+struct psb_header {
+       char signature[10];
+       u_char version;
+       u_char flags;
+       u_short settlingtime;
+       u_char res1;
+       u_char numpst;
+} __packed;
+
+struct pst_header {
+       u_int32_t cpuid;
+       u_char fsb;
+       u_char maxfid;
+       u_char startvid;
+       u_char numpstates;
+} __packed;
+
+static u_int fsb;
+static u_int sgtc;
+
+static int
+decode_pst(char *p, int npstates)
+{
+       int i;
+       int freq, fid, vid;
+
+       for (i = 0; i < npstates; ++i) {
+               fid = *p++;
+               vid = *p++;
+               freq = 100 * fid_to_mult[fid] * fsb;
+
+               printf("   %2d %8dkHz  FID %02x (%2d.%01d)  VID %02x (%4dmV)\n",
+                      i,
+                      freq,
+                      fid, fid_to_mult[fid]/10, fid_to_mult[fid]%10,
+                      vid, vid_to_voltage[vid]);
+       }
+
+       return 0;
+}
+
+static
+void decode_psb(char *p, int numpst)
+{
+       int i;
+       struct psb_header *psb;
+       struct pst_header *pst;
+
+       psb = (struct psb_header*) p;
+
+       if (psb->version != 0x12)
+               return;
+
+       printf("PSB version: %hhx flags: %hhx settling time %hhuus res1 %hhx num pst %hhu\n",
+                       psb->version,
+                       psb->flags,
+                       psb->settlingtime,
+                       psb->res1,
+                       psb->numpst);
+       sgtc = psb->settlingtime * 100;
+
+       if (sgtc < 10000)
+               sgtc = 10000;
+
+       p = ((char *) psb) + sizeof(struct psb_header);
+
+       if (numpst < 0)
+               numpst = psb->numpst;
+       else
+               printf("Overriding number of pst :%d\n", numpst);
+
+       for (i = 0; i < numpst; i++) {
+               pst = (struct pst_header*) p;
+
+               if (relevant != 0) {
+                       if (relevant!= pst->cpuid)
+                               goto next_one;
+               }
+
+               printf("  PST %d  cpuid %.3x fsb %hhu mfid %hhx svid %hhx numberstates %hhu\n",
+                               i+1,
+                               pst->cpuid,
+                               pst->fsb,
+                               pst->maxfid,
+                               pst->startvid,
+                               pst->numpstates);
+
+               fsb = pst->fsb;
+               decode_pst(p + sizeof(struct pst_header), pst->numpstates);
+
+next_one:
+               p += sizeof(struct pst_header) + 2*pst->numpstates;
+       }
+
+}
+
+static struct option info_opts[] = {
+       {.name = "numpst",      .has_arg=no_argument,   .flag=NULL, .val='n'},
+};
+
+void print_help(void)
+{
+       printf ("Usage: dump_psb [options]\n");
+       printf ("Options:\n");
+       printf ("  -n, --numpst     Set number of PST tables to scan\n");
+       printf ("  -r, --relevant   Only display PSTs relevant to cpuid N\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+       int fd;
+       int numpst=-1;
+       int ret=0, cont=1;
+       char *mem = NULL;
+       char *p;
+
+       do {
+               ret = getopt_long(argc, argv, "hr:n:", info_opts, NULL);
+               switch (ret){
+               case '?':
+               case 'h':
+                       print_help();
+                       cont = 0;
+                       break;
+               case 'r':
+                       relevant = strtol(optarg, NULL, 16);
+                       break;
+               case 'n':
+                       numpst = strtol(optarg, NULL, 10);
+                       break;
+               case -1:
+                       cont = 0;
+                       break;
+               }
+
+       } while(cont);
+
+       fd = open("/dev/mem", O_RDONLY);
+       if (fd < 0) {
+               printf ("Couldn't open /dev/mem. Are you root?\n");
+               exit(1);
+       }
+
+       mem = mmap(mem, 0x100000 - 0xc0000, PROT_READ, MAP_SHARED, fd, 0xc0000);
+       close(fd);
+
+       for (p = mem; p - mem < LEN; p+=16) {
+               if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
+                       decode_psb(p, numpst);
+                       break;
+               }
+       }
+
+       munmap(mem, LEN);
+       return 0;
+}
diff --git a/tools/power/cpupower/debug/i386/intel_gsic.c b/tools/power/cpupower/debug/i386/intel_gsic.c
new file mode 100644 (file)
index 0000000..53f5293
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  (C) 2003  Bruno Ducrot
+ *  (C) 2004  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ * Based on code found in
+ * linux/include/asm-i386/ist.h and linux/arch/i386/kernel/setup.c
+ * and originally developed by Andy Grover <andrew.grover@intel.com>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <lrmi.h>
+
+int main (void)
+{
+       struct LRMI_regs        r;
+       int                     retval;
+
+       if (!LRMI_init())
+               return 0;
+
+       memset(&r, 0, sizeof(r));
+
+       r.eax = 0x0000E980;
+       r.edx = 0x47534943;
+
+       retval = LRMI_int(0x15, &r);
+
+       if (!retval) {
+               printf("Failed!\n");
+               return 0;
+       }
+       if (r.eax == 0x47534943) {
+               printf("BIOS supports GSIC call:\n");
+               printf("\tsignature: %c%c%c%c\n",
+                      (r.eax >> 24) & 0xff,
+                      (r.eax >> 16) & 0xff,
+                      (r.eax >> 8) & 0xff,
+                      (r.eax) & 0xff);
+               printf("\tcommand port = 0x%.4x\n",
+                      r.ebx & 0xffff);
+               printf("\tcommand =      0x%.4x\n",
+                      (r.ebx >> 16) & 0xffff);
+               printf("\tevent port =   0x%.8x\n", r.ecx);
+               printf("\tflags =        0x%.8x\n", r.edx);
+               if (((r.ebx >> 16) & 0xffff) != 0x82) {
+                       printf("non-default command value. If speedstep-smi "
+                              "doesn't work out of the box,\nyou may want to "
+                              "try out the default value by passing "
+                              "smi_cmd=0x82 to the module\n ON YOUR OWN "
+                              "RISK.\n");
+               }
+               if ((r.ebx & 0xffff) != 0xb2) {
+                       printf("non-default command port. If speedstep-smi "
+                              "doesn't work out of the box,\nyou may want to "
+                              "try out the default value by passing "
+                              "smi_port=0x82 to the module\n ON YOUR OWN "
+                              "RISK.\n");
+               }
+       } else {
+               printf("BIOS DOES NOT support GSIC call.  Dumping registers anyway:\n");
+               printf("eax = 0x%.8x\n", r.eax);
+               printf("ebx = 0x%.8x\n", r.ebx);
+               printf("ecx = 0x%.8x\n", r.ecx);
+               printf("edx = 0x%.8x\n", r.edx);
+               printf("Note also that some BIOS do not support the initial "
+                      "GSIC call, but the newer\nspeeedstep-smi driver may "
+                      "work.\nFor this, you need to pass some arguments to "
+                      "the speedstep-smi driver:\n");
+               printf("\tsmi_cmd=0x?? smi_port=0x?? smi_sig=1\n");
+               printf("\nUnfortunately, you have to know what exactly are "
+                      "smi_cmd and smi_port, and this\nis system "
+                      "dependant.\n");
+       }
+       return 1;
+}
diff --git a/tools/power/cpupower/debug/i386/powernow-k8-decode.c b/tools/power/cpupower/debug/i386/powernow-k8-decode.c
new file mode 100644 (file)
index 0000000..638a6b3
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ * Based on code found in
+ * linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+ * and originally developed by Paul Devriendt
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define MCPU 32
+
+#define MSR_FIDVID_STATUS      0xc0010042
+
+#define MSR_S_HI_CURRENT_VID   0x0000001f
+#define MSR_S_LO_CURRENT_FID   0x0000003f
+
+static int get_fidvid(uint32_t cpu, uint32_t *fid, uint32_t *vid)
+{
+       int err = 1;
+       uint64_t msr = 0;
+       int fd;
+       char file[20];
+
+       if (cpu > MCPU)
+               goto out;
+
+       sprintf(file, "/dev/cpu/%d/msr", cpu);
+
+       fd = open(file, O_RDONLY);
+       if (fd < 0)
+               goto out;
+       lseek(fd, MSR_FIDVID_STATUS, SEEK_CUR);
+       if (read(fd, &msr, 8) != 8)
+               goto err1;
+
+       *fid = ((uint32_t )(msr & 0xffffffffull)) & MSR_S_LO_CURRENT_FID;
+       *vid = ((uint32_t )(msr>>32 & 0xffffffffull)) & MSR_S_HI_CURRENT_VID;
+       err = 0;
+err1:
+       close(fd);
+out:
+       return err;
+}
+
+
+/* Return a frequency in MHz, given an input fid */
+static uint32_t find_freq_from_fid(uint32_t fid)
+{
+       return 800 + (fid * 100);
+}
+
+/* Return a voltage in miliVolts, given an input vid */
+static uint32_t find_millivolts_from_vid(uint32_t vid)
+{
+       return 1550-vid*25;
+}
+
+int main (int argc, char *argv[])
+{
+       int err;
+       int cpu;
+       uint32_t fid, vid;
+
+       if (argc < 2)
+               cpu = 0;
+       else
+               cpu = strtoul(argv[1], NULL, 0);
+
+       err = get_fidvid(cpu, &fid, &vid);
+
+       if (err) {
+               printf("can't get fid, vid from MSR\n");
+               printf("Possible trouble: you don't run a powernow-k8 capable cpu\n");
+               printf("or you are not root, or the msr driver is not present\n");
+               exit(1);
+       }
+
+       
+       printf("cpu %d currently at %d MHz and %d mV\n",
+                       cpu,
+                       find_freq_from_fid(fid),
+                       find_millivolts_from_vid(vid));
+       
+       return 0;
+}
diff --git a/tools/power/cpupower/debug/kernel/Makefile b/tools/power/cpupower/debug/kernel/Makefile
new file mode 100644 (file)
index 0000000..96b146f
--- /dev/null
@@ -0,0 +1,23 @@
+obj-m  :=
+
+KDIR   := /lib/modules/$(shell uname -r)/build
+PWD            := $(shell pwd)
+KMISC   := /lib/modules/$(shell uname -r)/cpufrequtils/
+
+ifeq ("$(CONFIG_X86_TSC)", "y")
+  obj-m         += cpufreq-test_tsc.o
+endif
+
+default:
+       $(MAKE) -C $(KDIR) M=$(PWD)
+
+clean:
+       - rm -rf *.o *.ko .tmp-versions .*.cmd .*.mod.* *.mod.c
+       - rm -rf .tmp_versions* Module.symvers modules.order
+
+install: default
+       install -d $(KMISC)
+       install -m 644 -c *.ko $(KMISC)
+       /sbin/depmod -a
+
+all:   default
diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c
new file mode 100644 (file)
index 0000000..66cace6
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * test module to check whether the TSC-based delay routine continues
+ * to work properly after cpufreq transitions. Needs ACPI to work
+ * properly.
+ *
+ * Based partly on the Power Management Timer (PMTMR) code to be found
+ * in arch/i386/kernel/timers/timer_pm.c on recent 2.6. kernels, especially
+ * code written by John Stultz. The read_pmtmr function was copied verbatim
+ * from that file.
+ *
+ * (C) 2004 Dominik Brodowski
+ *
+ * To use:
+ * 1.) pass clock=tsc to the kernel on your bootloader
+ * 2.) modprobe this module (it'll fail)
+ * 3.) change CPU frequency
+ * 4.) modprobe this module again
+ * 5.) if the third value, "diff_pmtmr", changes between 2. and 4., the
+ *     TSC-based delay routine on the Linux kernel does not correctly
+ *     handle the cpufreq transition. Please report this to
+ *     cpufreq@vger.kernel.org
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+static int pm_tmr_ioport = 0;
+
+/*helper function to safely read acpi pm timesource*/
+static u32 read_pmtmr(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 time
+        * source is not latched, so you must read it multiple
+        * times to insure a safe value is read.
+        */
+       do {
+               v1 = inl(pm_tmr_ioport);
+               v2 = inl(pm_tmr_ioport);
+               v3 = inl(pm_tmr_ioport);
+       } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
+                || (v3 > v1 && v3 < v2));
+
+       /* mask the output to 24 bits */
+       return (v2 & 0xFFFFFF);
+}
+
+static int __init cpufreq_test_tsc(void)
+{
+       u32 now, then, diff;
+       u64 now_tsc, then_tsc, diff_tsc;
+       int i;
+
+       /* the following code snipped is copied from arch/x86/kernel/acpi/boot.c
+          of Linux v2.6.25. */
+
+       /* detect the location of the ACPI PM Timer */
+       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
+               /* FADT rev. 2 */
+               if (acpi_gbl_FADT.xpm_timer_block.space_id !=
+                   ACPI_ADR_SPACE_SYSTEM_IO)
+                       return 0;
+
+               pm_tmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
+               /*
+                * "X" fields are optional extensions to the original V1.0
+                * fields, so we must selectively expand V1.0 fields if the
+                * corresponding X field is zero.
+                */
+               if (!pm_tmr_ioport)
+                       pm_tmr_ioport = acpi_gbl_FADT.pm_timer_block;
+       } else {
+               /* FADT rev. 1 */
+               pm_tmr_ioport = acpi_gbl_FADT.pm_timer_block;
+       }
+
+       printk(KERN_DEBUG "start--> \n");
+       then = read_pmtmr();
+        rdtscll(then_tsc);
+       for (i=0;i<20;i++) {
+               mdelay(100);
+               now = read_pmtmr();
+               rdtscll(now_tsc);
+               diff = (now - then) & 0xFFFFFF;
+               diff_tsc = now_tsc - then_tsc;
+               printk(KERN_DEBUG "t1: %08u t2: %08u diff_pmtmr: %08u diff_tsc: %016llu\n", then, now, diff, diff_tsc);
+               then = now;
+               then_tsc = now_tsc;
+       }
+       printk(KERN_DEBUG "<-- end \n");
+       return -ENODEV;
+}
+
+static void __exit cpufreq_none(void)
+{
+       return;
+}
+
+module_init(cpufreq_test_tsc)
+module_exit(cpufreq_none)
+
+
+MODULE_AUTHOR("Dominik Brodowski");
+MODULE_DESCRIPTION("Verify the TSC cpufreq notifier working correctly -- needs ACPI-enabled system");
+MODULE_LICENSE ("GPL");
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile
new file mode 100644 (file)
index 0000000..dbf1399
--- /dev/null
@@ -0,0 +1,14 @@
+default: all
+
+centrino-decode: centrino-decode.c
+       $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c
+
+powernow-k8-decode: powernow-k8-decode.c
+       $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c
+
+all: centrino-decode powernow-k8-decode
+
+clean:
+       rm -rf centrino-decode powernow-k8-decode
+
+.PHONY: all default clean
diff --git a/tools/power/cpupower/debug/x86_64/centrino-decode.c b/tools/power/cpupower/debug/x86_64/centrino-decode.c
new file mode 120000 (symlink)
index 0000000..26fb3f1
--- /dev/null
@@ -0,0 +1 @@
+../i386/centrino-decode.c
\ No newline at end of file
diff --git a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c b/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c
new file mode 120000 (symlink)
index 0000000..eb30c79
--- /dev/null
@@ -0,0 +1 @@
+../i386/powernow-k8-decode.c
\ No newline at end of file
diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c
new file mode 100644 (file)
index 0000000..d961101
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpufreq.h"
+#include "sysfs.h"
+
+int cpufreq_cpu_exists(unsigned int cpu)
+{
+       return sysfs_cpu_exists(cpu);
+}
+
+unsigned long cpufreq_get_freq_kernel(unsigned int cpu)
+{
+       return sysfs_get_freq_kernel(cpu);
+}
+
+unsigned long cpufreq_get_freq_hardware(unsigned int cpu)
+{
+       return sysfs_get_freq_hardware(cpu);
+}
+
+unsigned long cpufreq_get_transition_latency(unsigned int cpu)
+{
+       return sysfs_get_freq_transition_latency(cpu);
+}
+
+int cpufreq_get_hardware_limits(unsigned int cpu,
+                               unsigned long *min,
+                               unsigned long *max)
+{
+       if ((!min) || (!max))
+               return -EINVAL;
+       return sysfs_get_freq_hardware_limits(cpu, min, max);
+}
+
+char *cpufreq_get_driver(unsigned int cpu)
+{
+       return sysfs_get_freq_driver(cpu);
+}
+
+void cpufreq_put_driver(char *ptr)
+{
+       if (!ptr)
+               return;
+       free(ptr);
+}
+
+struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu)
+{
+       return sysfs_get_freq_policy(cpu);
+}
+
+void cpufreq_put_policy(struct cpufreq_policy *policy)
+{
+       if ((!policy) || (!policy->governor))
+               return;
+
+       free(policy->governor);
+       policy->governor = NULL;
+       free(policy);
+}
+
+struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned
+                                                               int cpu)
+{
+       return sysfs_get_freq_available_governors(cpu);
+}
+
+void cpufreq_put_available_governors(struct cpufreq_available_governors *any)
+{
+       struct cpufreq_available_governors *tmp, *next;
+
+       if (!any)
+               return;
+
+       tmp = any->first;
+       while (tmp) {
+               next = tmp->next;
+               if (tmp->governor)
+                       free(tmp->governor);
+               free(tmp);
+               tmp = next;
+       }
+}
+
+
+struct cpufreq_available_frequencies
+*cpufreq_get_available_frequencies(unsigned int cpu)
+{
+       return sysfs_get_available_frequencies(cpu);
+}
+
+void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies
+                               *any) {
+       struct cpufreq_available_frequencies *tmp, *next;
+
+       if (!any)
+               return;
+
+       tmp = any->first;
+       while (tmp) {
+               next = tmp->next;
+               free(tmp);
+               tmp = next;
+       }
+}
+
+
+struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu)
+{
+       return sysfs_get_freq_affected_cpus(cpu);
+}
+
+void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any)
+{
+       struct cpufreq_affected_cpus *tmp, *next;
+
+       if (!any)
+               return;
+
+       tmp = any->first;
+       while (tmp) {
+               next = tmp->next;
+               free(tmp);
+               tmp = next;
+       }
+}
+
+
+struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu)
+{
+       return sysfs_get_freq_related_cpus(cpu);
+}
+
+void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any)
+{
+       cpufreq_put_affected_cpus(any);
+}
+
+
+int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy)
+{
+       if (!policy || !(policy->governor))
+               return -EINVAL;
+
+       return sysfs_set_freq_policy(cpu, policy);
+}
+
+
+int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq)
+{
+       return sysfs_modify_freq_policy_min(cpu, min_freq);
+}
+
+
+int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq)
+{
+       return sysfs_modify_freq_policy_max(cpu, max_freq);
+}
+
+
+int cpufreq_modify_policy_governor(unsigned int cpu, char *governor)
+{
+       if ((!governor) || (strlen(governor) > 19))
+               return -EINVAL;
+
+       return sysfs_modify_freq_policy_governor(cpu, governor);
+}
+
+int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency)
+{
+       return sysfs_set_frequency(cpu, target_frequency);
+}
+
+struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu,
+                                       unsigned long long *total_time)
+{
+       return sysfs_get_freq_stats(cpu, total_time);
+}
+
+void cpufreq_put_stats(struct cpufreq_stats *any)
+{
+       struct cpufreq_stats *tmp, *next;
+
+       if (!any)
+               return;
+
+       tmp = any->first;
+       while (tmp) {
+               next = tmp->next;
+               free(tmp);
+               tmp = next;
+       }
+}
+
+unsigned long cpufreq_get_transitions(unsigned int cpu)
+{
+       return sysfs_get_freq_transitions(cpu);
+}
diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h
new file mode 100644 (file)
index 0000000..3aae8e7
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ *  cpufreq.h - definitions for libcpufreq
+ *
+ *  Copyright (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, version 2 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 _CPUFREQ_H
+#define _CPUFREQ_H 1
+
+struct cpufreq_policy {
+       unsigned long min;
+       unsigned long max;
+       char *governor;
+};
+
+struct cpufreq_available_governors {
+       char *governor;
+       struct cpufreq_available_governors *next;
+       struct cpufreq_available_governors *first;
+};
+
+struct cpufreq_available_frequencies {
+       unsigned long frequency;
+       struct cpufreq_available_frequencies *next;
+       struct cpufreq_available_frequencies *first;
+};
+
+
+struct cpufreq_affected_cpus {
+       unsigned int cpu;
+       struct cpufreq_affected_cpus *next;
+       struct cpufreq_affected_cpus *first;
+};
+
+struct cpufreq_stats {
+       unsigned long frequency;
+       unsigned long long time_in_state;
+       struct cpufreq_stats *next;
+       struct cpufreq_stats *first;
+};
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * returns 0 if the specified CPU is present (it doesn't say
+ * whether it is online!), and an error value if not.
+ */
+
+extern int cpufreq_cpu_exists(unsigned int cpu);
+
+/* determine current CPU frequency
+ * - _kernel variant means kernel's opinion of CPU frequency
+ * - _hardware variant means actual hardware CPU frequency,
+ *    which is only available to root.
+ *
+ * returns 0 on failure, else frequency in kHz.
+ */
+
+extern unsigned long cpufreq_get_freq_kernel(unsigned int cpu);
+
+extern unsigned long cpufreq_get_freq_hardware(unsigned int cpu);
+
+#define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu);
+
+
+/* determine CPU transition latency
+ *
+ * returns 0 on failure, else transition latency in 10^(-9) s = nanoseconds
+ */
+extern unsigned long cpufreq_get_transition_latency(unsigned int cpu);
+
+
+/* determine hardware CPU frequency limits
+ *
+ * These may be limited further by thermal, energy or other
+ * considerations by cpufreq policy notifiers in the kernel.
+ */
+
+extern int cpufreq_get_hardware_limits(unsigned int cpu,
+                               unsigned long *min,
+                               unsigned long *max);
+
+
+/* determine CPUfreq driver used
+ *
+ * Remember to call cpufreq_put_driver when no longer needed
+ * to avoid memory leakage, please.
+ */
+
+extern char *cpufreq_get_driver(unsigned int cpu);
+
+extern void cpufreq_put_driver(char *ptr);
+
+
+/* determine CPUfreq policy currently used
+ *
+ * Remember to call cpufreq_put_policy when no longer needed
+ * to avoid memory leakage, please.
+ */
+
+
+extern struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu);
+
+extern void cpufreq_put_policy(struct cpufreq_policy *policy);
+
+
+/* determine CPUfreq governors currently available
+ *
+ * may be modified by modprobe'ing or rmmod'ing other governors. Please
+ * free allocated memory by calling cpufreq_put_available_governors
+ * after use.
+ */
+
+
+extern struct cpufreq_available_governors
+*cpufreq_get_available_governors(unsigned int cpu);
+
+extern void cpufreq_put_available_governors(
+       struct cpufreq_available_governors *first);
+
+
+/* determine CPU frequency states available
+ *
+ * Only present on _some_ ->target() cpufreq drivers. For information purposes
+ * only. Please free allocated memory by calling
+ * cpufreq_put_available_frequencies after use.
+ */
+
+extern struct cpufreq_available_frequencies
+*cpufreq_get_available_frequencies(unsigned int cpu);
+
+extern void cpufreq_put_available_frequencies(
+               struct cpufreq_available_frequencies *first);
+
+
+/* determine affected CPUs
+ *
+ * Remember to call cpufreq_put_affected_cpus when no longer needed
+ * to avoid memory leakage, please.
+ */
+
+extern struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned
+                                                       int cpu);
+
+extern void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first);
+
+
+/* determine related CPUs
+ *
+ * Remember to call cpufreq_put_related_cpus when no longer needed
+ * to avoid memory leakage, please.
+ */
+
+extern struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned
+                                                       int cpu);
+
+extern void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first);
+
+
+/* determine stats for cpufreq subsystem
+ *
+ * This is not available in all kernel versions or configurations.
+ */
+
+extern struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu,
+                                       unsigned long long *total_time);
+
+extern void cpufreq_put_stats(struct cpufreq_stats *stats);
+
+extern unsigned long cpufreq_get_transitions(unsigned int cpu);
+
+
+/* set new cpufreq policy
+ *
+ * Tries to set the passed policy as new policy as close as possible,
+ * but results may differ depending e.g. on governors being available.
+ */
+
+extern int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy);
+
+
+/* modify a policy by only changing min/max freq or governor
+ *
+ * Does not check whether result is what was intended.
+ */
+
+extern int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq);
+extern int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq);
+extern int cpufreq_modify_policy_governor(unsigned int cpu, char *governor);
+
+
+/* set a specific frequency
+ *
+ * Does only work if userspace governor can be used and no external
+ * interference (other calls to this function or to set/modify_policy)
+ * occurs. Also does not work on ->range() cpufreq drivers.
+ */
+
+extern int cpufreq_set_frequency(unsigned int cpu,
+                               unsigned long target_frequency);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CPUFREQ_H */
diff --git a/tools/power/cpupower/lib/sysfs.c b/tools/power/cpupower/lib/sysfs.c
new file mode 100644 (file)
index 0000000..870713a
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "cpufreq.h"
+
+#define PATH_TO_CPU "/sys/devices/system/cpu/"
+#define MAX_LINE_LEN 4096
+#define SYSFS_PATH_MAX 255
+
+
+static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
+{
+       int fd;
+       ssize_t numread;
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1)
+               return 0;
+
+       numread = read(fd, buf, buflen - 1);
+       if (numread < 1) {
+               close(fd);
+               return 0;
+       }
+
+       buf[numread] = '\0';
+       close(fd);
+
+       return (unsigned int) numread;
+}
+
+
+/* CPUFREQ sysfs access **************************************************/
+
+/* helper function to read file from /sys into given buffer */
+/* fname is a relative path under "cpuX/cpufreq" dir */
+static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname,
+                                           char *buf, size_t buflen)
+{
+       char path[SYSFS_PATH_MAX];
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
+                        cpu, fname);
+       return sysfs_read_file(path, buf, buflen);
+}
+
+/* helper function to write a new value to a /sys file */
+/* fname is a relative path under "cpuX/cpufreq" dir */
+static unsigned int sysfs_cpufreq_write_file(unsigned int cpu,
+                                            const char *fname,
+                                            const char *value, size_t len)
+{
+       char path[SYSFS_PATH_MAX];
+       int fd;
+       ssize_t numwrite;
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
+                        cpu, fname);
+
+       fd = open(path, O_WRONLY);
+       if (fd == -1)
+               return 0;
+
+       numwrite = write(fd, value, len);
+       if (numwrite < 1) {
+               close(fd);
+               return 0;
+       }
+
+       close(fd);
+
+       return (unsigned int) numwrite;
+}
+
+/* read access to files which contain one numeric value */
+
+enum cpufreq_value {
+       CPUINFO_CUR_FREQ,
+       CPUINFO_MIN_FREQ,
+       CPUINFO_MAX_FREQ,
+       CPUINFO_LATENCY,
+       SCALING_CUR_FREQ,
+       SCALING_MIN_FREQ,
+       SCALING_MAX_FREQ,
+       STATS_NUM_TRANSITIONS,
+       MAX_CPUFREQ_VALUE_READ_FILES
+};
+
+static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
+       [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq",
+       [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq",
+       [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq",
+       [CPUINFO_LATENCY]  = "cpuinfo_transition_latency",
+       [SCALING_CUR_FREQ] = "scaling_cur_freq",
+       [SCALING_MIN_FREQ] = "scaling_min_freq",
+       [SCALING_MAX_FREQ] = "scaling_max_freq",
+       [STATS_NUM_TRANSITIONS] = "stats/total_trans"
+};
+
+
+static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
+                                                enum cpufreq_value which)
+{
+       unsigned long value;
+       unsigned int len;
+       char linebuf[MAX_LINE_LEN];
+       char *endp;
+
+       if (which >= MAX_CPUFREQ_VALUE_READ_FILES)
+               return 0;
+
+       len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which],
+                               linebuf, sizeof(linebuf));
+
+       if (len == 0)
+               return 0;
+
+       value = strtoul(linebuf, &endp, 0);
+
+       if (endp == linebuf || errno == ERANGE)
+               return 0;
+
+       return value;
+}
+
+/* read access to files which contain one string */
+
+enum cpufreq_string {
+       SCALING_DRIVER,
+       SCALING_GOVERNOR,
+       MAX_CPUFREQ_STRING_FILES
+};
+
+static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = {
+       [SCALING_DRIVER] = "scaling_driver",
+       [SCALING_GOVERNOR] = "scaling_governor",
+};
+
+
+static char *sysfs_cpufreq_get_one_string(unsigned int cpu,
+                                          enum cpufreq_string which)
+{
+       char linebuf[MAX_LINE_LEN];
+       char *result;
+       unsigned int len;
+
+       if (which >= MAX_CPUFREQ_STRING_FILES)
+               return NULL;
+
+       len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which],
+                               linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       result = strdup(linebuf);
+       if (result == NULL)
+               return NULL;
+
+       if (result[strlen(result) - 1] == '\n')
+               result[strlen(result) - 1] = '\0';
+
+       return result;
+}
+
+/* write access */
+
+enum cpufreq_write {
+       WRITE_SCALING_MIN_FREQ,
+       WRITE_SCALING_MAX_FREQ,
+       WRITE_SCALING_GOVERNOR,
+       WRITE_SCALING_SET_SPEED,
+       MAX_CPUFREQ_WRITE_FILES
+};
+
+static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = {
+       [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq",
+       [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq",
+       [WRITE_SCALING_GOVERNOR] = "scaling_governor",
+       [WRITE_SCALING_SET_SPEED] = "scaling_setspeed",
+};
+
+static int sysfs_cpufreq_write_one_value(unsigned int cpu,
+                                        enum cpufreq_write which,
+                                        const char *new_value, size_t len)
+{
+       if (which >= MAX_CPUFREQ_WRITE_FILES)
+               return 0;
+
+       if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which],
+                                       new_value, len) != len)
+               return -ENODEV;
+
+       return 0;
+};
+
+unsigned long sysfs_get_freq_kernel(unsigned int cpu)
+{
+       return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ);
+}
+
+unsigned long sysfs_get_freq_hardware(unsigned int cpu)
+{
+       return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ);
+}
+
+unsigned long sysfs_get_freq_transition_latency(unsigned int cpu)
+{
+       return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY);
+}
+
+int sysfs_get_freq_hardware_limits(unsigned int cpu,
+                             unsigned long *min,
+                             unsigned long *max)
+{
+       if ((!min) || (!max))
+               return -EINVAL;
+
+       *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ);
+       if (!*min)
+               return -ENODEV;
+
+       *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ);
+       if (!*max)
+               return -ENODEV;
+
+       return 0;
+}
+
+char *sysfs_get_freq_driver(unsigned int cpu)
+{
+       return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER);
+}
+
+struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu)
+{
+       struct cpufreq_policy *policy;
+
+       policy = malloc(sizeof(struct cpufreq_policy));
+       if (!policy)
+               return NULL;
+
+       policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR);
+       if (!policy->governor) {
+               free(policy);
+               return NULL;
+       }
+       policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
+       policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ);
+       if ((!policy->min) || (!policy->max)) {
+               free(policy->governor);
+               free(policy);
+               return NULL;
+       }
+
+       return policy;
+}
+
+struct cpufreq_available_governors *
+sysfs_get_freq_available_governors(unsigned int cpu) {
+       struct cpufreq_available_governors *first = NULL;
+       struct cpufreq_available_governors *current = NULL;
+       char linebuf[MAX_LINE_LEN];
+       unsigned int pos, i;
+       unsigned int len;
+
+       len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors",
+                               linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       pos = 0;
+       for (i = 0; i < len; i++) {
+               if (linebuf[i] == ' ' || linebuf[i] == '\n') {
+                       if (i - pos < 2)
+                               continue;
+                       if (current) {
+                               current->next = malloc(sizeof(*current));
+                               if (!current->next)
+                                       goto error_out;
+                               current = current->next;
+                       } else {
+                               first = malloc(sizeof(*first));
+                               if (!first)
+                                       goto error_out;
+                               current = first;
+                       }
+                       current->first = first;
+                       current->next = NULL;
+
+                       current->governor = malloc(i - pos + 1);
+                       if (!current->governor)
+                               goto error_out;
+
+                       memcpy(current->governor, linebuf + pos, i - pos);
+                       current->governor[i - pos] = '\0';
+                       pos = i + 1;
+               }
+       }
+
+       return first;
+
+ error_out:
+       while (first) {
+               current = first->next;
+               if (first->governor)
+                       free(first->governor);
+               free(first);
+               first = current;
+       }
+       return NULL;
+}
+
+
+struct cpufreq_available_frequencies *
+sysfs_get_available_frequencies(unsigned int cpu) {
+       struct cpufreq_available_frequencies *first = NULL;
+       struct cpufreq_available_frequencies *current = NULL;
+       char one_value[SYSFS_PATH_MAX];
+       char linebuf[MAX_LINE_LEN];
+       unsigned int pos, i;
+       unsigned int len;
+
+       len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies",
+                               linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       pos = 0;
+       for (i = 0; i < len; i++) {
+               if (linebuf[i] == ' ' || linebuf[i] == '\n') {
+                       if (i - pos < 2)
+                               continue;
+                       if (i - pos >= SYSFS_PATH_MAX)
+                               goto error_out;
+                       if (current) {
+                               current->next = malloc(sizeof(*current));
+                               if (!current->next)
+                                       goto error_out;
+                               current = current->next;
+                       } else {
+                               first = malloc(sizeof(*first));
+                               if (!first)
+                                       goto error_out;
+                               current = first;
+                       }
+                       current->first = first;
+                       current->next = NULL;
+
+                       memcpy(one_value, linebuf + pos, i - pos);
+                       one_value[i - pos] = '\0';
+                       if (sscanf(one_value, "%lu", &current->frequency) != 1)
+                               goto error_out;
+
+                       pos = i + 1;
+               }
+       }
+
+       return first;
+
+ error_out:
+       while (first) {
+               current = first->next;
+               free(first);
+               first = current;
+       }
+       return NULL;
+}
+
+static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu,
+                                                       const char *file)
+{
+       struct cpufreq_affected_cpus *first = NULL;
+       struct cpufreq_affected_cpus *current = NULL;
+       char one_value[SYSFS_PATH_MAX];
+       char linebuf[MAX_LINE_LEN];
+       unsigned int pos, i;
+       unsigned int len;
+
+       len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       pos = 0;
+       for (i = 0; i < len; i++) {
+               if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') {
+                       if (i - pos  < 1)
+                               continue;
+                       if (i - pos >= SYSFS_PATH_MAX)
+                               goto error_out;
+                       if (current) {
+                               current->next = malloc(sizeof(*current));
+                               if (!current->next)
+                                       goto error_out;
+                               current = current->next;
+                       } else {
+                               first = malloc(sizeof(*first));
+                               if (!first)
+                                       goto error_out;
+                               current = first;
+                       }
+                       current->first = first;
+                       current->next = NULL;
+
+                       memcpy(one_value, linebuf + pos, i - pos);
+                       one_value[i - pos] = '\0';
+
+                       if (sscanf(one_value, "%u", &current->cpu) != 1)
+                               goto error_out;
+
+                       pos = i + 1;
+               }
+       }
+
+       return first;
+
+ error_out:
+       while (first) {
+               current = first->next;
+               free(first);
+               first = current;
+       }
+       return NULL;
+}
+
+struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(unsigned int cpu)
+{
+       return sysfs_get_cpu_list(cpu, "affected_cpus");
+}
+
+struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(unsigned int cpu)
+{
+       return sysfs_get_cpu_list(cpu, "related_cpus");
+}
+
+struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu,
+                                       unsigned long long *total_time) {
+       struct cpufreq_stats *first = NULL;
+       struct cpufreq_stats *current = NULL;
+       char one_value[SYSFS_PATH_MAX];
+       char linebuf[MAX_LINE_LEN];
+       unsigned int pos, i;
+       unsigned int len;
+
+       len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state",
+                               linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       *total_time = 0;
+       pos = 0;
+       for (i = 0; i < len; i++) {
+               if (i == strlen(linebuf) || linebuf[i] == '\n') {
+                       if (i - pos < 2)
+                               continue;
+                       if ((i - pos) >= SYSFS_PATH_MAX)
+                               goto error_out;
+                       if (current) {
+                               current->next = malloc(sizeof(*current));
+                               if (!current->next)
+                                       goto error_out;
+                               current = current->next;
+                       } else {
+                               first = malloc(sizeof(*first));
+                               if (!first)
+                                       goto error_out;
+                               current = first;
+                       }
+                       current->first = first;
+                       current->next = NULL;
+
+                       memcpy(one_value, linebuf + pos, i - pos);
+                       one_value[i - pos] = '\0';
+                       if (sscanf(one_value, "%lu %llu",
+                                       &current->frequency,
+                                       &current->time_in_state) != 2)
+                               goto error_out;
+
+                       *total_time = *total_time + current->time_in_state;
+                       pos = i + 1;
+               }
+       }
+
+       return first;
+
+ error_out:
+       while (first) {
+               current = first->next;
+               free(first);
+               first = current;
+       }
+       return NULL;
+}
+
+unsigned long sysfs_get_freq_transitions(unsigned int cpu)
+{
+       return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS);
+}
+
+static int verify_gov(char *new_gov, char *passed_gov)
+{
+       unsigned int i, j = 0;
+
+       if (!passed_gov || (strlen(passed_gov) > 19))
+               return -EINVAL;
+
+       strncpy(new_gov, passed_gov, 20);
+       for (i = 0; i < 20; i++) {
+               if (j) {
+                       new_gov[i] = '\0';
+                       continue;
+               }
+               if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z'))
+                       continue;
+
+               if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z'))
+                       continue;
+
+               if (new_gov[i] == '-')
+                       continue;
+
+               if (new_gov[i] == '_')
+                       continue;
+
+               if (new_gov[i] == '\0') {
+                       j = 1;
+                       continue;
+               }
+               return -EINVAL;
+       }
+       new_gov[19] = '\0';
+       return 0;
+}
+
+int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor)
+{
+       char new_gov[SYSFS_PATH_MAX];
+
+       if (!governor)
+               return -EINVAL;
+
+       if (verify_gov(new_gov, governor))
+               return -EINVAL;
+
+       return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
+                                            new_gov, strlen(new_gov));
+};
+
+int sysfs_modify_freq_policy_max(unsigned int cpu, unsigned long max_freq)
+{
+       char value[SYSFS_PATH_MAX];
+
+       snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq);
+
+       return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
+                                            value, strlen(value));
+};
+
+
+int sysfs_modify_freq_policy_min(unsigned int cpu, unsigned long min_freq)
+{
+       char value[SYSFS_PATH_MAX];
+
+       snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq);
+
+       return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ,
+                                            value, strlen(value));
+};
+
+
+int sysfs_set_freq_policy(unsigned int cpu, struct cpufreq_policy *policy)
+{
+       char min[SYSFS_PATH_MAX];
+       char max[SYSFS_PATH_MAX];
+       char gov[SYSFS_PATH_MAX];
+       int ret;
+       unsigned long old_min;
+       int write_max_first;
+
+       if (!policy || !(policy->governor))
+               return -EINVAL;
+
+       if (policy->max < policy->min)
+               return -EINVAL;
+
+       if (verify_gov(gov, policy->governor))
+               return -EINVAL;
+
+       snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min);
+       snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max);
+
+       old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
+       write_max_first = (old_min && (policy->max < old_min) ? 0 : 1);
+
+       if (write_max_first) {
+               ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
+                                                   max, strlen(max));
+               if (ret)
+                       return ret;
+       }
+
+       ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min,
+                                           strlen(min));
+       if (ret)
+               return ret;
+
+       if (!write_max_first) {
+               ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
+                                                   max, strlen(max));
+               if (ret)
+                       return ret;
+       }
+
+       return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
+                                            gov, strlen(gov));
+}
+
+int sysfs_set_frequency(unsigned int cpu, unsigned long target_frequency)
+{
+       struct cpufreq_policy *pol = sysfs_get_freq_policy(cpu);
+       char userspace_gov[] = "userspace";
+       char freq[SYSFS_PATH_MAX];
+       int ret;
+
+       if (!pol)
+               return -ENODEV;
+
+       if (strncmp(pol->governor, userspace_gov, 9) != 0) {
+               ret = sysfs_modify_freq_policy_governor(cpu, userspace_gov);
+               if (ret) {
+                       cpufreq_put_policy(pol);
+                       return ret;
+               }
+       }
+
+       cpufreq_put_policy(pol);
+
+       snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency);
+
+       return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED,
+                                            freq, strlen(freq));
+}
+
+/* CPUFREQ sysfs access **************************************************/
+
+/* General sysfs access **************************************************/
+int sysfs_cpu_exists(unsigned int cpu)
+{
+       char file[SYSFS_PATH_MAX];
+       struct stat statbuf;
+
+       snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/", cpu);
+
+       if (stat(file, &statbuf) != 0)
+               return -ENOSYS;
+
+       return S_ISDIR(statbuf.st_mode) ? 0 : -ENOSYS;
+}
+
+/* General sysfs access **************************************************/
diff --git a/tools/power/cpupower/lib/sysfs.h b/tools/power/cpupower/lib/sysfs.h
new file mode 100644 (file)
index 0000000..c76a5e0
--- /dev/null
@@ -0,0 +1,31 @@
+/* General */
+extern unsigned int sysfs_cpu_exists(unsigned int cpu);
+
+/* CPUfreq */
+extern unsigned long sysfs_get_freq_kernel(unsigned int cpu);
+extern unsigned long sysfs_get_freq_hardware(unsigned int cpu);
+extern unsigned long sysfs_get_freq_transition_latency(unsigned int cpu);
+extern int sysfs_get_freq_hardware_limits(unsigned int cpu,
+                                       unsigned long *min, unsigned long *max);
+extern char *sysfs_get_freq_driver(unsigned int cpu);
+extern struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu);
+extern struct cpufreq_available_governors *sysfs_get_freq_available_governors(
+       unsigned int cpu);
+extern struct cpufreq_available_frequencies *sysfs_get_available_frequencies(
+       unsigned int cpu);
+extern struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(
+       unsigned int cpu);
+extern struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(
+       unsigned int cpu);
+extern struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu,
+                                               unsigned long long *total_time);
+extern unsigned long sysfs_get_freq_transitions(unsigned int cpu);
+extern int sysfs_set_freq_policy(unsigned int cpu,
+                               struct cpufreq_policy *policy);
+extern int sysfs_modify_freq_policy_min(unsigned int cpu,
+                                       unsigned long min_freq);
+extern int sysfs_modify_freq_policy_max(unsigned int cpu,
+                                       unsigned long max_freq);
+extern int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor);
+extern int sysfs_set_frequency(unsigned int cpu,
+                       unsigned long target_frequency);
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1
new file mode 100644 (file)
index 0000000..3194811
--- /dev/null
@@ -0,0 +1,76 @@
+.TH "cpufreq-info" "1" "0.1" "Mattia Dongili" ""
+.SH "NAME"
+.LP 
+cpufreq\-info \- Utility to retrieve cpufreq kernel information
+.SH "SYNTAX"
+.LP 
+cpufreq\-info [\fIoptions\fP]
+.SH "DESCRIPTION"
+.LP 
+A small tool which prints out cpufreq information helpful to developers and interested users.
+.SH "OPTIONS"
+.LP 
+.TP  
+\fB\-e\fR \fB\-\-debug\fR
+Prints out debug information.
+.TP  
+\fB\-f\fR \fB\-\-freq\fR
+Get frequency the CPU currently runs at, according to the cpufreq core.
+.TP  
+\fB\-w\fR \fB\-\-hwfreq\fR
+Get frequency the CPU currently runs at, by reading it from hardware (only available to root).
+.TP  
+\fB\-l\fR \fB\-\-hwlimits\fR
+Determine the minimum and maximum CPU frequency allowed.
+.TP  
+\fB\-d\fR \fB\-\-driver\fR
+Determines the used cpufreq kernel driver.
+.TP  
+\fB\-p\fR \fB\-\-policy\fR
+Gets the currently used cpufreq policy.
+.TP  
+\fB\-g\fR \fB\-\-governors\fR
+Determines available cpufreq governors.
+.TP  
+\fB\-a\fR \fB\-\-related\-cpus\fR
+Determines which CPUs run at the same hardware frequency.
+.TP  
+\fB\-a\fR \fB\-\-affected\-cpus\fR
+Determines which CPUs need to have their frequency coordinated by software.
+.TP  
+\fB\-s\fR \fB\-\-stats\fR
+Shows cpufreq statistics if available.
+.TP  
+\fB\-y\fR \fB\-\-latency\fR
+Determines the maximum latency on CPU frequency changes.
+.TP  
+\fB\-o\fR \fB\-\-proc\fR
+Prints out information like provided by the /proc/cpufreq interface in 2.4. and early 2.6. kernels.
+.TP  
+\fB\-m\fR \fB\-\-human\fR
+human\-readable output for the \-f, \-w, \-s and \-y parameters.
+.TP  
+\fB\-h\fR \fB\-\-help\fR
+Prints out the help screen.
+.SH "REMARKS"
+.LP 
+By default only values of core zero are displayed. How to display settings of
+other cores is described in the cpupower(1) manpage in the \-\-cpu option section.
+.LP 
+You can't specify more than one of the output specific options \-o \-e \-a \-g \-p \-d \-l \-w \-f \-y.
+.LP 
+You also can't specify the \-o option combined with the \-c option.
+.SH "FILES"
+.nf 
+\fI/sys/devices/system/cpu/cpu*/cpufreq/\fP  
+\fI/proc/cpufreq\fP (deprecated) 
+\fI/proc/sys/cpu/\fP (deprecated)
+.fi 
+.SH "AUTHORS"
+.nf
+Dominik Brodowski <linux@brodo.de> \- author 
+Mattia Dongili<malattia@gmail.com> \- first autolibtoolization
+.fi
+.SH "SEE ALSO"
+.LP 
+cpupower\-frequency\-set(1), cpupower(1)
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1
new file mode 100644 (file)
index 0000000..26e3e13
--- /dev/null
@@ -0,0 +1,54 @@
+.TH "cpufreq-set" "1" "0.1" "Mattia Dongili" ""
+.SH "NAME"
+.LP 
+cpufreq\-set \- A small tool which allows to modify cpufreq settings.
+.SH "SYNTAX"
+.LP 
+cpufreq\-set [\fIoptions\fP]
+.SH "DESCRIPTION"
+.LP 
+cpufreq\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time.
+.SH "OPTIONS"
+.LP 
+.TP 
+\fB\-d\fR \fB\-\-min\fR <FREQ>
+new minimum CPU frequency the governor may select.
+.TP 
+\fB\-u\fR \fB\-\-max\fR <FREQ>
+new maximum CPU frequency the governor may select.
+.TP 
+\fB\-g\fR \fB\-\-governor\fR <GOV>
+new cpufreq governor.
+.TP 
+\fB\-f\fR \fB\-\-freq\fR <FREQ>
+specific frequency to be set. Requires userspace governor to be available and loaded.
+.TP 
+\fB\-r\fR \fB\-\-related\fR
+modify all hardware-related CPUs at the same time
+.TP 
+\fB\-h\fR \fB\-\-help\fR
+Prints out the help screen.
+.SH "REMARKS"
+.LP 
+By default values are applied on all cores. How to modify single core
+configurations is described in the cpupower(1) manpage in the \-\-cpu option section.
+.LP 
+The \-f FREQ, \-\-freq FREQ parameter cannot be combined with any other parameter.
+.LP 
+FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz by postfixing the value with the wanted unit name, without any space (frequency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).
+.LP 
+On Linux kernels up to 2.6.29, the \-r or \-\-related parameter is ignored.
+.SH "FILES" 
+.nf
+\fI/sys/devices/system/cpu/cpu*/cpufreq/\fP  
+\fI/proc/cpufreq\fP (deprecated) 
+\fI/proc/sys/cpu/\fP (deprecated)
+.fi 
+.SH "AUTHORS"
+.nf 
+Dominik Brodowski <linux@brodo.de> \- author 
+Mattia Dongili<malattia@gmail.com> \- first autolibtoolization
+.fi
+.SH "SEE ALSO"
+.LP 
+cpupower\-frequency\-info(1), cpupower(1)
diff --git a/tools/power/cpupower/man/cpupower-info.1 b/tools/power/cpupower/man/cpupower-info.1
new file mode 100644 (file)
index 0000000..58e2119
--- /dev/null
@@ -0,0 +1,19 @@
+.TH CPUPOWER\-INFO "1" "22/02/2011" "" "cpupower Manual"
+.SH NAME
+cpupower\-info \- Shows processor power related kernel or hardware configurations
+.SH SYNOPSIS
+.ft B
+.B cpupower info [ \-b ] [ \-s ] [ \-m ]
+
+.SH DESCRIPTION
+\fBcpupower info \fP shows kernel configurations or processor hardware
+registers affecting processor power saving policies.
+
+Some options are platform wide, some affect single cores. By default values
+of core zero are displayed only. cpupower --cpu all cpuinfo will show the
+settings of all cores, see cpupower(1) how to choose specific cores.
+
+.SH "SEE ALSO"
+Options are described in detail in:
+
+cpupower(1), cpupower-set(1)
diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1
new file mode 100644 (file)
index 0000000..d5cfa26
--- /dev/null
@@ -0,0 +1,179 @@
+.TH CPUPOWER\-MONITOR "1" "22/02/2011" "" "cpupower Manual"
+.SH NAME
+cpupower\-monitor \- Report processor frequency and idle statistics
+.SH SYNOPSIS
+.ft B
+.B cpupower monitor
+.RB "\-l"
+
+.B cpupower monitor
+.RB [ "\-m <mon1>," [ "<mon2>,..." ] ]
+.RB [ "\-i seconds" ]
+.br
+.B cpupower monitor
+.RB [ "\-m <mon1>," [ "<mon2>,..." ] ]
+.RB command
+.br
+.SH DESCRIPTION
+\fBcpupower-monitor \fP reports processor topology, frequency and idle power
+state statistics. Either \fBcommand\fP is forked and
+statistics are printed upon its completion, or statistics are printed periodically.
+
+\fBcpupower-monitor \fP implements independent processor sleep state and
+frequency counters. Some are retrieved from kernel statistics, some are
+directly reading out hardware registers. Use \-l to get an overview which are
+supported on your system.
+
+.SH Options
+.PP
+\-l
+.RS 4
+List available monitors on your system. Additional details about each monitor
+are shown:
+.RS 2
+.IP \(bu
+The name in quotation marks which can be passed to the \-m parameter.
+.IP \(bu
+The number of different counters the monitor supports in brackets.
+.IP \(bu
+The amount of time in seconds the counters might overflow, due to
+implementation constraints.
+.IP \(bu
+The name and a description of each counter and its processor hierarchy level
+coverage in square brackets:
+.RS 4
+.IP \(bu
+[T] \-> Thread
+.IP \(bu
+[C] \-> Core
+.IP \(bu
+[P] \-> Processor Package (Socket)
+.IP \(bu
+[M] \-> Machine/Platform wide counter
+.RE
+.RE
+.RE
+.PP
+\-m <mon1>,<mon2>,...
+.RS 4
+Only display specific monitors. Use the monitor string(s) provided by \-l option.
+.RE
+.PP
+\-i seconds
+.RS 4
+Measure intervall.
+.RE
+.PP
+command
+.RS 4
+Measure idle and frequency characteristics of an arbitrary command/workload.
+The executable \fBcommand\fP is forked and upon its exit, statistics gathered since it was
+forked are displayed.
+.RE
+.PP
+\-v
+.RS 4
+Increase verbosity if the binary was compiled with the DEBUG option set.
+.RE
+
+.SH MONITOR DESCRIPTIONS
+.SS "Idle_Stats"
+Shows statistics of the cpuidle kernel subsystem. Values are retrieved from
+/sys/devices/system/cpu/cpu*/cpuidle/state*/.
+The kernel updates these values every time an idle state is entered or
+left. Therefore there can be some inaccuracy when cores are in an idle
+state for some time when the measure starts or ends. In worst case it can happen
+that one core stayed in an idle state for the whole measure time and the idle
+state usage time as exported by the kernel did not get updated. In this case
+a state residency of 0 percent is shown while it was 100.
+
+.SS "Mperf"
+The name comes from the aperf/mperf (average and maximum) MSR registers used
+which are available on recent X86 processors. It shows the average frequency
+(including boost frequencies).
+The fact that on all recent hardware the mperf timer stops ticking in any idle
+state it is also used to show C0 (processor is active) and Cx (processor is in
+any sleep state) times. These counters do not have the inaccuracy restrictions
+the "Idle_Stats" counters may show.
+May work poorly on Linux-2.6.20 through 2.6.29, as the \fBacpi-cpufreq \fP
+kernel frequency driver periodically cleared aperf/mperf registers in those
+kernels.
+
+.SS "Nehalem" "SandyBridge"
+Intel Core and Package sleep state counters.
+Threads (hyperthreaded cores) may not be able to enter deeper core states if
+its sibling is utilized.
+Deepest package sleep states may in reality show up as machine/platform wide
+sleep states and can only be entered if all cores are idle. Look up Intel
+manuals (some are provided in the References section) for further details.
+
+.SS "Ontario" "Liano"
+AMD laptop and desktop processor (family 12h and 14h) sleep state counters.
+The registers are accessed via PCI and therefore can still be read out while
+cores have been offlined.
+
+There is one special counter: NBP1 (North Bridge P1).
+This one always returns 0 or 1, depending on whether the North Bridge P1
+power state got entered at least once during measure time.
+Being able to enter NBP1 state also depends on graphics power management.
+Therefore this counter can be used to verify whether the graphics' driver
+power management is working as expected.
+
+.SH EXAMPLES
+
+cpupower monitor -l" may show:
+.RS 4
+Monitor "Mperf" (3 states) \- Might overflow after 922000000 s
+
+   ...
+
+Monitor "Idle_Stats" (3 states) \- Might overflow after 4294967295 s
+
+   ...
+
+.RE
+cpupower monitor \-m "Idle_Stats,Mperf" scp /tmp/test /nfs/tmp
+
+Monitor the scp command, show both Mperf and Idle_Stats states counter
+statistics, but in exchanged order.
+
+
+
+.RE
+Be careful that the typical command to fully utilize one CPU by doing:
+
+cpupower monitor cat /dev/zero >/dev/null
+
+Does not work as expected, because the measured output is redirected to
+/dev/null. This could get workarounded by putting the line into an own, tiny
+shell script. Hit CTRL\-c to terminate the command and get the measure output
+displayed.
+
+.SH REFERENCES
+"BIOS and Kernel Developer’s Guide (BKDG) for AMD Family 14h Processors"
+http://support.amd.com/us/Processor_TechDocs/43170.pdf
+
+"Intel® Turbo Boost Technology
+in Intel® Core™ Microarchitecture (Nehalem) Based Processors"
+http://download.intel.com/design/processor/applnots/320354.pdf
+
+"Intel® 64 and IA-32 Architectures Software Developer's Manual
+Volume 3B: System Programming Guide"
+http://www.intel.com/products/processor/manuals
+
+.SH FILES
+.ta
+.nf
+/dev/cpu/*/msr
+/sys/devices/system/cpu/cpu*/cpuidle/state*/.
+.fi
+
+.SH "SEE ALSO"
+powertop(8), msr(4), vmstat(8)
+.PP
+.SH AUTHORS
+.nf
+Written by Thomas Renninger <trenn@suse.de>
+
+Nehalem, SandyBridge monitors and command passing
+based on turbostat.8 from Len Brown <len.brown@intel.com>
diff --git a/tools/power/cpupower/man/cpupower-set.1 b/tools/power/cpupower/man/cpupower-set.1
new file mode 100644 (file)
index 0000000..c4954a9
--- /dev/null
@@ -0,0 +1,103 @@
+.TH CPUPOWER\-SET "1" "22/02/2011" "" "cpupower Manual"
+.SH NAME
+cpupower\-set \- Set processor power related kernel or hardware configurations
+.SH SYNOPSIS
+.ft B
+.B cpupower set [ \-b VAL ] [ \-s VAL ] [ \-m VAL ]
+
+
+.SH DESCRIPTION
+\fBcpupower set \fP sets kernel configurations or directly accesses hardware
+registers affecting processor power saving policies.
+
+Some options are platform wide, some affect single cores. By default values
+are applied on all cores. How to modify single core configurations is
+described in the cpupower(1) manpage in the \-\-cpu option section. Whether an
+option affects the whole system or can be applied to individual cores is
+described in the Options sections.
+
+Use \fBcpupower info \fP to read out current settings and whether they are
+supported on the system at all.
+
+.SH Options
+.PP
+\-\-perf-bias, \-b
+.RS 4
+Sets a register on supported Intel processore which allows software to convey
+its policy for the relative importance of performance versus energy savings to
+the  processor.
+
+The range of valid numbers is 0-15, where 0 is maximum
+performance and 15 is maximum energy efficiency.
+
+The processor uses this information in model-specific ways
+when it must select trade-offs between performance and
+energy efficiency.
+
+This policy hint does not supersede Processor Performance states
+(P-states) or CPU Idle power states (C-states), but allows
+software to have influence where it would otherwise be unable
+to express a preference.
+
+For example, this setting may tell the hardware how
+aggressively or conservatively to control frequency
+in the "turbo range" above the explicitly OS-controlled
+P-state frequency range.  It may also tell the hardware
+how aggressively it should enter the OS requested C-states.
+
+This option can be applied to individual cores only via the \-\-cpu option,
+cpupower(1).
+
+Setting the performance bias value on one CPU can modify the setting on
+related CPUs as well (for example all CPUs on one socket), because of
+hardware restrictions.
+Use \fBcpupower -c all info -b\fP to verify.
+
+This options needs the msr kernel driver (CONFIG_X86_MSR) loaded.
+.RE
+.PP
+\-\-sched\-mc,  \-m [ VAL ]
+.RE
+\-\-sched\-smt, \-s [ VAL ]
+.RS 4
+\-\-sched\-mc utilizes cores in one processor package/socket first before
+processes are scheduled to other processor packages/sockets.
+
+\-\-sched\-smt utilizes thread siblings of one processor core first before
+processes are scheduled to other cores.
+
+The impact on power consumption and performance (positiv or negativ) heavily
+depends on processor support for deep sleep states, frequency scaling and
+frequency boost modes and their dependencies between other thread siblings
+and processor cores.
+
+Taken over from kernel documentation:
+
+Adjust the kernel's multi-core scheduler support.
+
+Possible values are:
+.RS 2
+0 - No power saving load balance (default value)
+
+1 - Fill one thread/core/package first for long running threads
+
+2 - Also bias task wakeups to semi-idle cpu package for power
+savings
+.RE
+
+sched_mc_power_savings is dependent upon SCHED_MC, which is
+itself architecture dependent.
+
+sched_smt_power_savings is dependent upon SCHED_SMT, which
+is itself architecture dependent.
+
+The two files are independent of each other. It is possible
+that one file may be present without the other.
+
+.SH "SEE ALSO"
+cpupower-info(1), cpupower-monitor(1), powertop(1)
+.PP
+.SH AUTHORS
+.nf
+\-\-perf\-bias parts written by Len Brown <len.brown@intel.com>
+Thomas Renninger <trenn@suse.de>
diff --git a/tools/power/cpupower/man/cpupower.1 b/tools/power/cpupower/man/cpupower.1
new file mode 100644 (file)
index 0000000..78c20fe
--- /dev/null
@@ -0,0 +1,72 @@
+.TH CPUPOWER "1" "07/03/2011" "" "cpupower Manual"
+.SH NAME
+cpupower \- Shows and sets processor power related values
+.SH SYNOPSIS
+.ft B
+.B cpupower [ \-c cpulist ] subcommand [ARGS]
+
+.B cpupower \-v|\-\-version
+
+.B cpupower \-h|\-\-help
+
+.SH DESCRIPTION
+\fBcpupower \fP is a collection of tools to examine and tune power saving
+related features of your processor.
+
+The manpages of the subcommands (cpupower\-<subcommand>(1)) provide detailed
+descriptions of supported features. Run \fBcpupower help\fP to get an overview
+of supported subcommands.
+
+.SH Options
+.PP
+\-\-help, \-h
+.RS 4
+Shows supported subcommands and general usage.
+.RE
+.PP
+\-\-cpu cpulist,  \-c cpulist
+.RS 4
+Only show or set values for specific cores.
+This option is not supported by all subcommands, details can be found in the
+manpages of the subcommands.
+
+Some subcommands access all cores (typically the *\-set commands), some only
+the first core (typically the *\-info commands) by default.
+
+The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via
+sysfs files. Some examples:
+.RS 4
+.TP 16
+Input
+Equivalent to
+.TP
+all
+all cores
+.TP
+0\-3
+0,1,2,3
+.TP
+0\-7:2
+0,2,4,6
+.TP
+1,3,5-7
+1,3,5,6,7
+.TP
+0\-3:2,8\-15:4
+0,2,8,12       
+.RE
+.RE
+.PP
+\-\-version,  \-v
+.RS 4
+Print the package name and version number.
+
+.SH "SEE ALSO"
+cpupower-set(1), cpupower-info(1), cpupower-idle(1),
+cpupower-frequency-set(1), cpupower-frequency-info(1), cpupower-monitor(1),
+powertop(1)
+.PP
+.SH AUTHORS
+.nf
+\-\-perf\-bias parts written by Len Brown <len.brown@intel.com>
+Thomas Renninger <trenn@suse.de>
diff --git a/tools/power/cpupower/po/cs.po b/tools/power/cpupower/po/cs.po
new file mode 100644 (file)
index 0000000..cb22c45
--- /dev/null
@@ -0,0 +1,944 @@
+# translation of cs.po to Czech
+# Czech translation for cpufrequtils package
+# Czech messages for cpufrequtils.
+# Copyright (C) 2007 kavol
+# This file is distributed under the same license as the cpufrequtils package.
+#
+# Karel Volný <kavol@seznam.cz>, 2007, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: cs\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2008-06-11 16:26+0200\n"
+"Last-Translator: Karel Volný <kavol@seznam.cz>\n"
+"Language-Team: Czech <diskuze@lists.l10n.cz>\n"
+"Language: cs\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms:  nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr ""
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr ""
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr ""
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr ""
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr ""
+"Chyby v programu prosím hlaste na %s (anglicky).\n"
+"Chyby v překladu prosím hlaste na kavol@seznam.cz (česky ;-)\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr ""
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr "Nelze zjistit počet CPU (%s: %s), předpokládá se 1.\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
+msgstr ""
+"         minimální frekvence CPU - maximální frekvence CPU -  regulátor\n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid "  boost state support: \n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid "    Supported: %s\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr ""
+
+#: utils/cpufreq-info.c:164
+#, fuzzy, c-format
+msgid "    Active: %s\n"
+msgstr "  ovladač: %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid "    Boost States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid "    Total States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid "    Pstate-P%d:  %luMHz\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid "  no or unknown cpufreq driver is active on this CPU\n"
+msgstr "  pro tento CPU není aktivní žádný známý ovladač cpufreq\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid "  driver: %s\n"
+msgstr "  ovladač: %s\n"
+
+#: utils/cpufreq-info.c:219
+#, fuzzy, c-format
+msgid "  CPUs which run at the same hardware frequency: "
+msgstr "  CPU, které musí měnit frekvenci zároveň: "
+
+#: utils/cpufreq-info.c:230
+#, fuzzy, c-format
+msgid "  CPUs which need to have their frequency coordinated by software: "
+msgstr "  CPU, které musí měnit frekvenci zároveň: "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid "  maximum transition latency: "
+msgstr ""
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid "  hardware limits: "
+msgstr "  hardwarové meze: "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid "  available frequency steps: "
+msgstr "  dostupné frekvence: "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid "  available cpufreq governors: "
+msgstr "  dostupné regulátory: "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid "  current policy: frequency should be within "
+msgstr "  současná taktika: frekvence by měla být mezi "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " a "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+"                  within this range.\n"
+msgstr ""
+"  Regulátor \"%s\" může rozhodnout jakou frekvenci použít\n"
+"                    v těchto mezích.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid "  current CPU frequency is "
+msgstr "  současná frekvence CPU je "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr "  (zjištěno hardwarovým voláním)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid "  cpufreq stats: "
+msgstr "  statistika cpufreq: "
+
+#: utils/cpufreq-info.c:472
+#, fuzzy, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "Užití: cpufreq-info [přepínače]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "Přepínače:\n"
+
+#: utils/cpufreq-info.c:474
+#, fuzzy, c-format
+msgid "  -e, --debug          Prints out debug information [default]\n"
+msgstr "  -e, --debug          Vypíše ladicí informace\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+"  -f, --freq           Get frequency the CPU currently runs at, according\n"
+"                       to the cpufreq core *\n"
+msgstr ""
+"  -f, --freq           Zjistí aktuální frekvenci, na které CPU běží\n"
+"                       podle cpufreq *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+"                       it from hardware (only available to root) *\n"
+msgstr ""
+"  -w, --hwfreq         Zjistí aktuální frekvenci, na které CPU běží\n"
+"                       z hardware (dostupné jen uživateli root) *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+"  -l, --hwlimits       Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+"  -l, --hwlimits       Zjistí minimální a maximální dostupnou frekvenci CPU "
+"*\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n"
+msgstr "  -d, --driver         Zjistí aktivní ovladač cpufreq *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid "  -p, --policy         Gets the currently used cpufreq policy *\n"
+msgstr "  -p, --policy         Zjistí aktuální taktiku cpufreq *\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid "  -g, --governors      Determines available cpufreq governors *\n"
+msgstr "  -g, --governors      Zjistí dostupné regulátory cpufreq *\n"
+
+#: utils/cpufreq-info.c:483
+#, fuzzy, c-format
+msgid ""
+"  -r, --related-cpus   Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+"  -a, --affected-cpus  Zjistí, které CPU musí měnit frekvenci zároveň *\n"
+
+#: utils/cpufreq-info.c:484
+#, fuzzy, c-format
+msgid ""
+"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+"                       coordinated by software *\n"
+msgstr ""
+"  -a, --affected-cpus  Zjistí, které CPU musí měnit frekvenci zároveň *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid "  -s, --stats          Shows cpufreq statistics if available\n"
+msgstr "  -s, --stats          Zobrazí statistiku cpufreq, je-li dostupná\n"
+
+#: utils/cpufreq-info.c:487
+#, fuzzy, c-format
+msgid ""
+"  -y, --latency        Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+"  -l, --hwlimits       Zjistí minimální a maximální dostupnou frekvenci CPU "
+"*\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"cpufreq\n"
+"                       interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+"  -o, --proc           Vypíše informace ve formátu, jaký používalo rozhraní\n"
+"                       /proc/cpufreq v kernelech řady 2.4 a časné 2.6\n"
+
+#: utils/cpufreq-info.c:491
+#, fuzzy, c-format
+msgid ""
+"  -m, --human          human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+"  -m, --human          Výstup parametrů -f, -w a -s v „lidmi čitelném“ "
+"formátu\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid "  -h, --help           Prints out this screen\n"
+msgstr "  -h, --help           Vypíše tuto nápovědu\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"Není-li zadán žádný parametr nebo je-li zadán pouze přepínač -c, --cpu, "
+"jsou\n"
+"vypsány ladicí informace, což může být užitečné například při hlášení chyb.\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr ""
+"Není-li při použití přepínačů označených * zadán parametr -c nebo --cpu,\n"
+"předpokládá se jeho hodnota 0.\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr "Zadaný parametr nemůže být použit zároveň s přepínačem -c nebo --cpu\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"Nelze zadat více než jeden parametr -c nebo --cpu\n"
+"anebo více než jeden parametr určující výstup\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "neplatný nebo neznámý parametr\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr "nelze analyzovat CPU %d, vypadá to, že není přítomen\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "analyzuji CPU %d:\n"
+
+#: utils/cpufreq-set.c:25
+#, fuzzy, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "Užití: cpufreq-set [přepínače]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -d FREQ, --min FREQ      Nová nejnižší frekvence, kterou může regulátor "
+"vybrat\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -u FREQ, --max FREQ      Nová nejvyšší frekvence, kterou může regulátor "
+"zvolit\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
+msgstr "  -g GOV, --governors GOV  Nový regulátor cpufreq\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+"                           governor to be available and loaded\n"
+msgstr ""
+"  -f FREQ, --freq FREQ     Frekvence, která má být nastavena. Vyžaduje, aby "
+"byl\n"
+"                           v jádře nahrán regulátor ‚userspace‘.\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid "  -r, --related            Switches all hardware-related CPUs\n"
+msgstr ""
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, fuzzy, c-format
+msgid "  -h, --help               Prints out this screen\n"
+msgstr "  -h, --help           Vypíše tuto nápovědu\n"
+
+#: utils/cpufreq-set.c:35
+#, fuzzy, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr ""
+"Není-li při použití přepínačů označených * zadán parametr -c nebo --cpu,\n"
+"předpokládá se jeho hodnota 0.\n"
+
+#: utils/cpufreq-set.c:37
+#, fuzzy, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+"   except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+"   by postfixing the value with the wanted unit name, without any space\n"
+"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"Poznámky:\n"
+"1. Vynechání parametru -c nebo --cpu je ekvivalentní jeho nastavení na 0\n"
+"2. Přepínač -f nebo --freq nemůže být použit zároveň s žádným jiným vyjma -"
+"c\n"
+"   nebo --cpu\n"
+"3. Frekvence (FREQ) mohou být zadány v Hz, kHz (výchozí), MHz, GHz nebo THz\n"
+"   připojením názvu jednotky bez mezery mezi číslem a jednotkou\n"
+"   (FREQ v kHz =^ Hz * 0,001 = ^ MHz * 1000 =^ GHz * 1000000)\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+"   for example because of hardware which cannot be set to a specific "
+"frequency\n"
+"   or because the userspace governor isn't loaded?\n"
+msgstr ""
+"Chyba při nastavování nových hodnot. Obvyklé problémy:\n"
+"- Máte patřičná administrátorská práva? (root?)\n"
+"- Je požadovaný regulátor dostupný v jádře? (modprobe?)\n"
+"- Snažíte se nastavit neplatnou taktiku?\n"
+"- Snažíte se nastavit určitou frekvenci, ale není dostupný\n"
+"  regulátor ‚userspace‘, například protože není nahrán v jádře,\n"
+"  nebo nelze na tomto hardware nastavit určitou frekvenci?\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "neznámý nebo nepodporovaný CPU?\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"přepínač -f/--freq nemůže být použit zároveň\n"
+"s přepínačem -d/--min, -u/--max nebo -g/--governor\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"Musí být zadán alespoň jeden přepínač\n"
+"-f/--freq, -d/--min, -u/--max nebo -g/--governor\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr ""
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr ""
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr ""
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-info.c:25
+#, fuzzy, c-format
+msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
+msgstr "  -p, --policy         Zjistí aktuální taktiku cpufreq *\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr ""
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr ""
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr ""
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr ""
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr ""
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:28
+#, fuzzy, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "analyzuji CPU %d:\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:48
+#, fuzzy, c-format
+msgid "Available idle states:"
+msgstr "  dostupné frekvence: "
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:94
+#, fuzzy, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "  ovladač: %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr ""
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state:            C0\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate:              C%u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:129
+#, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid "    C%d:                  type[C%d] "
+msgstr ""
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr ""
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr ""
+
+#: utils/cpuidle-info.c:147
+#, fuzzy, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "Užití: cpufreq-info [přepínače]\n"
+
+#: utils/cpuidle-info.c:149
+#, fuzzy, c-format
+msgid "  -s, --silent         Only show general C-state information\n"
+msgstr "  -e, --debug          Vypíše ladicí informace\n"
+
+#: utils/cpuidle-info.c:150
+#, fuzzy, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+"                       interface in older kernels\n"
+msgstr ""
+"  -o, --proc           Vypíše informace ve formátu, jaký používalo rozhraní\n"
+"                       /proc/cpufreq v kernelech řady 2.4 a časné 2.6\n"
+
+#: utils/cpuidle-info.c:209
+#, fuzzy, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr ""
+"Nelze zadat více než jeden parametr -c nebo --cpu\n"
+"anebo více než jeden parametr určující výstup\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
+#~ "about\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU    Číslo CPU, o kterém se mají zjistit informace\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
+#~ "modified\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU        Číslo CPU pro který se má provést nastavení "
+#~ "cpufreq\n"
diff --git a/tools/power/cpupower/po/de.po b/tools/power/cpupower/po/de.po
new file mode 100644 (file)
index 0000000..78c09e5
--- /dev/null
@@ -0,0 +1,961 @@
+# German translations for cpufrequtils package
+# German messages for cpufrequtils.
+# Copyright (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.net>
+# This file is distributed under the same license as the cpufrequtils package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: cpufrequtils 006\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2009-08-08 17:18+0100\n"
+"Last-Translator:  <linux@dominikbrodowski.net>\n"
+"Language-Team: NONE\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr ""
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr ""
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr ""
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr ""
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr "Bitte melden Sie Fehler an %s.\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr ""
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr ""
+"Konnte nicht die Anzahl der CPUs herausfinden (%s : %s), nehme daher 1 an.\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
+msgstr ""
+"          minimale CPU-Taktfreq. -  maximale CPU-Taktfreq. -  Regler  \n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid "  boost state support: \n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid "    Supported: %s\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr ""
+
+#: utils/cpufreq-info.c:164
+#, fuzzy, c-format
+msgid "    Active: %s\n"
+msgstr "  Treiber: %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid "    Boost States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid "    Total States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid "    Pstate-P%d:  %luMHz\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid "  no or unknown cpufreq driver is active on this CPU\n"
+msgstr "  kein oder nicht bestimmbarer cpufreq-Treiber aktiv\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid "  driver: %s\n"
+msgstr "  Treiber: %s\n"
+
+#: utils/cpufreq-info.c:219
+#, c-format
+msgid "  CPUs which run at the same hardware frequency: "
+msgstr "  Folgende CPUs laufen mit der gleichen Hardware-Taktfrequenz: "
+
+#: utils/cpufreq-info.c:230
+#, c-format
+msgid "  CPUs which need to have their frequency coordinated by software: "
+msgstr "  Die Taktfrequenz folgender CPUs werden per Software koordiniert: "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid "  maximum transition latency: "
+msgstr "  Maximale Dauer eines Taktfrequenzwechsels: "
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid "  hardware limits: "
+msgstr "  Hardwarebedingte Grenzen der Taktfrequenz: "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid "  available frequency steps: "
+msgstr "  mögliche Taktfrequenzen: "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid "  available cpufreq governors: "
+msgstr "  mögliche Regler: "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid "  current policy: frequency should be within "
+msgstr "  momentane Taktik: die Frequenz soll innerhalb "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " und "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+"                  within this range.\n"
+msgstr ""
+"  liegen. Der Regler \"%s\" kann frei entscheiden,\n"
+"                    welche Taktfrequenz innerhalb dieser Grenze verwendet "
+"wird.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid "  current CPU frequency is "
+msgstr "  momentane Taktfrequenz ist "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr "  (verifiziert durch Nachfrage bei der Hardware)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid "  cpufreq stats: "
+msgstr "  Statistik:"
+
+#: utils/cpufreq-info.c:472
+#, fuzzy, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "Aufruf: cpufreq-info [Optionen]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "Optionen:\n"
+
+#: utils/cpufreq-info.c:474
+#, fuzzy, c-format
+msgid "  -e, --debug          Prints out debug information [default]\n"
+msgstr ""
+"  -e, --debug          Erzeugt detaillierte Informationen, hilfreich\n"
+"                       zum Aufspüren von Fehlern\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+"  -f, --freq           Get frequency the CPU currently runs at, according\n"
+"                       to the cpufreq core *\n"
+msgstr ""
+"  -f, --freq           Findet die momentane CPU-Taktfrquenz heraus (nach\n"
+"                       Meinung des Betriebssystems) *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+"                       it from hardware (only available to root) *\n"
+msgstr ""
+"  -w, --hwfreq         Findet die momentane CPU-Taktfrequenz heraus\n"
+"                       (verifiziert durch Nachfrage bei der Hardware)\n"
+"                       [nur der Administrator kann dies tun] *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+"  -l, --hwlimits       Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+"  -l, --hwlimits       Findet die minimale und maximale Taktfrequenz heraus "
+"*\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n"
+msgstr "  -d, --driver         Findet den momentanen Treiber heraus *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid "  -p, --policy         Gets the currently used cpufreq policy *\n"
+msgstr "  -p, --policy         Findet die momentane Taktik heraus *\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid "  -g, --governors      Determines available cpufreq governors *\n"
+msgstr "  -g, --governors      Erzeugt eine Liste mit verfügbaren Reglern *\n"
+
+#: utils/cpufreq-info.c:483
+#, c-format
+msgid ""
+"  -r, --related-cpus   Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+"  -r, --related-cpus   Findet heraus, welche CPUs mit derselben "
+"physikalischen\n"
+"                       Taktfrequenz laufen *\n"
+
+#: utils/cpufreq-info.c:484
+#, c-format
+msgid ""
+"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+"                       coordinated by software *\n"
+msgstr ""
+"  -a, --affected-cpus  Findet heraus, von welchen CPUs die Taktfrequenz "
+"durch\n"
+"                       Software koordiniert werden muss *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid "  -s, --stats          Shows cpufreq statistics if available\n"
+msgstr ""
+"  -s, --stats          Zeigt, sofern möglich, Statistiken über cpufreq an.\n"
+
+#: utils/cpufreq-info.c:487
+#, c-format
+msgid ""
+"  -y, --latency        Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+"  -y, --latency        Findet die maximale Dauer eines Taktfrequenzwechsels "
+"heraus *\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"cpufreq\n"
+"                       interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+"  -o, --proc           Erzeugt Informationen in einem ähnlichem Format zu "
+"dem\n"
+"                       der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n"
+"                       Kernel-Versionen\n"
+
+#: utils/cpufreq-info.c:491
+#, c-format
+msgid ""
+"  -m, --human          human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+"  -m, --human          Formatiert Taktfrequenz- und Zeitdauerangaben in "
+"besser\n"
+"                       lesbarer Form (MHz, GHz; us, ms)\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid "  -h, --help           Prints out this screen\n"
+msgstr "  -h, --help           Gibt diese Kurzübersicht aus\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"Sofern kein anderer Parameter als '-c, --cpu' angegeben wird, liefert "
+"dieses\n"
+"Programm Informationen, die z.B. zum Berichten von Fehlern nützlich sind.\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr ""
+"Bei den mit * markierten Parametern wird '--cpu 0' angenommen, soweit nicht\n"
+"mittels -c oder --cpu etwas anderes angegeben wird\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr "Diese Option kann nicht mit der --cpu-Option kombiniert werden\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"Man kann nicht mehr als einen --cpu-Parameter und/oder mehr als einen\n"
+"informationsspezifischen Parameter gleichzeitig angeben\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "unbekannter oder falscher Parameter\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr ""
+"Konnte nicht die CPU %d analysieren, da sie (scheinbar?) nicht existiert.\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "analysiere CPU %d:\n"
+
+#: utils/cpufreq-set.c:25
+#, fuzzy, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "Aufruf: cpufreq-set [Optionen]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -d FREQ, --min FREQ      neue minimale Taktfrequenz, die der Regler\n"
+"                           auswählen darf\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -u FREQ, --max FREQ      neue maximale Taktfrequenz, die der Regler\n"
+"                           auswählen darf\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
+msgstr "  -g GOV, --governors GOV  wechsle zu Regler GOV\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+"                           governor to be available and loaded\n"
+msgstr ""
+"  -f FREQ, --freq FREQ     setze exakte Taktfrequenz. Benötigt den Regler\n"
+"                           'userspace'.\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid "  -r, --related            Switches all hardware-related CPUs\n"
+msgstr ""
+"  -r, --related            Setze Werte für alle CPUs, deren Taktfrequenz\n"
+"                           hardwarebedingt identisch ist.\n"
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, c-format
+msgid "  -h, --help               Prints out this screen\n"
+msgstr "  -h, --help               Gibt diese Kurzübersicht aus\n"
+
+#: utils/cpufreq-set.c:35
+#, fuzzy, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr ""
+"Bei den mit * markierten Parametern wird '--cpu 0' angenommen, soweit nicht\n"
+"mittels -c oder --cpu etwas anderes angegeben wird\n"
+
+#: utils/cpufreq-set.c:37
+#, fuzzy, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+"   except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+"   by postfixing the value with the wanted unit name, without any space\n"
+"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"Hinweise:\n"
+"1. Sofern kein -c oder --cpu-Parameter angegeben ist, wird '--cpu 0'\n"
+"   angenommen\n"
+"2. Der Parameter -f bzw. --freq kann mit keinem anderen als dem Parameter\n"
+"   -c bzw. --cpu kombiniert werden\n"
+"3. FREQuenzen können in Hz, kHz (Standard), MHz, GHz oder THz eingegeben\n"
+"   werden, indem der Wert und unmittelbar anschließend (ohne Leerzeichen!)\n"
+"   die Einheit angegeben werden. (Bsp: 1GHz )\n"
+"   (FREQuenz in kHz =^ MHz * 1000 =^ GHz * 1000000).\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+"   for example because of hardware which cannot be set to a specific "
+"frequency\n"
+"   or because the userspace governor isn't loaded?\n"
+msgstr ""
+"Beim Einstellen ist ein Fehler aufgetreten. Typische Fehlerquellen sind:\n"
+"- nicht ausreichende Rechte (Administrator)\n"
+"- der Regler ist nicht verfügbar bzw. nicht geladen\n"
+"- die angegebene Taktik ist inkorrekt\n"
+"- eine spezifische Frequenz wurde angegeben, aber der Regler 'userspace'\n"
+"  kann entweder hardwarebedingt nicht genutzt werden oder ist nicht geladen\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "unbekannte oder nicht regelbare CPU\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"Der -f bzw. --freq-Parameter kann nicht mit den Parametern -d/--min, -u/--"
+"max\n"
+"oder -g/--governor kombiniert werden\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"Es muss mindestens ein Parameter aus -f/--freq, -d/--min, -u/--max oder\n"
+"-g/--governor angegeben werden.\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr ""
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr ""
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr ""
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-info.c:25
+#, fuzzy, c-format
+msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
+msgstr "  -p, --policy         Findet die momentane Taktik heraus *\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr ""
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr ""
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr ""
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr ""
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr ""
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:28
+#, fuzzy, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "analysiere CPU %d:\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:48
+#, fuzzy, c-format
+msgid "Available idle states:"
+msgstr "  mögliche Taktfrequenzen: "
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:94
+#, fuzzy, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "  Treiber: %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr ""
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state:            C0\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate:              C%u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:129
+#, fuzzy, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr "  Maximale Dauer eines Taktfrequenzwechsels: "
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid "    C%d:                  type[C%d] "
+msgstr ""
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr ""
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr ""
+
+#: utils/cpuidle-info.c:147
+#, fuzzy, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "Aufruf: cpufreq-info [Optionen]\n"
+
+#: utils/cpuidle-info.c:149
+#, fuzzy, c-format
+msgid "  -s, --silent         Only show general C-state information\n"
+msgstr ""
+"  -e, --debug          Erzeugt detaillierte Informationen, hilfreich\n"
+"                       zum Aufspüren von Fehlern\n"
+
+#: utils/cpuidle-info.c:150
+#, fuzzy, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+"                       interface in older kernels\n"
+msgstr ""
+"  -o, --proc           Erzeugt Informationen in einem ähnlichem Format zu "
+"dem\n"
+"                       der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n"
+"                       Kernel-Versionen\n"
+
+#: utils/cpuidle-info.c:209
+#, fuzzy, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr ""
+"Man kann nicht mehr als einen --cpu-Parameter und/oder mehr als einen\n"
+"informationsspezifischen Parameter gleichzeitig angeben\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
+#~ "about\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU    Nummer der CPU, über die Informationen "
+#~ "herausgefunden werden sollen\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
+#~ "modified\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU        Nummer der CPU, deren Taktfrequenz-"
+#~ "Einstellung\n"
+#~ "                           werden soll\n"
diff --git a/tools/power/cpupower/po/fr.po b/tools/power/cpupower/po/fr.po
new file mode 100644 (file)
index 0000000..245ad20
--- /dev/null
@@ -0,0 +1,947 @@
+# French translations for cpufrequtils package
+# Copyright (C) 2004 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the cpufrequtils package.
+# Ducrot Bruno <ducrot@poupinou.org>, 2004.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: cpufrequtils 0.1-pre2\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2004-11-17 15:53+1000\n"
+"Last-Translator: Bruno Ducrot <ducrot@poupinou.org>\n"
+"Language-Team: NONE\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr ""
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr ""
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr ""
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr ""
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr "Veuillez rapportez les erreurs et les bogues à %s, s'il vous plait.\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr ""
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr "Détermination du nombre de CPUs (%s : %s) impossible.  Assume 1\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
+msgstr ""
+"         Fréquence CPU minimale - Fréquence CPU maximale  - régulateur\n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid "  boost state support: \n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid "    Supported: %s\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr ""
+
+#: utils/cpufreq-info.c:164
+#, fuzzy, c-format
+msgid "    Active: %s\n"
+msgstr "  pilote : %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid "    Boost States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid "    Total States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid "    Pstate-P%d:  %luMHz\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid "  no or unknown cpufreq driver is active on this CPU\n"
+msgstr "  pas de pilotes cpufreq reconnu pour ce CPU\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid "  driver: %s\n"
+msgstr "  pilote : %s\n"
+
+#: utils/cpufreq-info.c:219
+#, fuzzy, c-format
+msgid "  CPUs which run at the same hardware frequency: "
+msgstr "  CPUs qui doivent changer de fréquences en même temps : "
+
+#: utils/cpufreq-info.c:230
+#, fuzzy, c-format
+msgid "  CPUs which need to have their frequency coordinated by software: "
+msgstr "  CPUs qui doivent changer de fréquences en même temps : "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid "  maximum transition latency: "
+msgstr ""
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid "  hardware limits: "
+msgstr "  limitation matérielle : "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid "  available frequency steps: "
+msgstr "  plage de fréquence : "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid "  available cpufreq governors: "
+msgstr "  régulateurs disponibles : "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid "  current policy: frequency should be within "
+msgstr "  tactique actuelle : la fréquence doit être comprise entre "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " et "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+"                  within this range.\n"
+msgstr ""
+"Le régulateur \"%s\" est libre de choisir la vitesse\n"
+"                  dans cette plage de fréquences.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid "  current CPU frequency is "
+msgstr "  la fréquence actuelle de ce CPU est "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr " (vérifié par un appel direct du matériel)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid "  cpufreq stats: "
+msgstr "  des statistique concernant cpufreq:"
+
+#: utils/cpufreq-info.c:472
+#, fuzzy, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "Usage : cpufreq-info [options]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "Options :\n"
+
+#: utils/cpufreq-info.c:474
+#, fuzzy, c-format
+msgid "  -e, --debug          Prints out debug information [default]\n"
+msgstr "  -e, --debug          Afficher les informations de déboguage\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+"  -f, --freq           Get frequency the CPU currently runs at, according\n"
+"                       to the cpufreq core *\n"
+msgstr ""
+"  -f, --freq           Obtenir la fréquence actuelle du CPU selon le point\n"
+"                       de vue du coeur du système de cpufreq *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+"                       it from hardware (only available to root) *\n"
+msgstr ""
+"  -w, --hwfreq         Obtenir la fréquence actuelle du CPU directement par\n"
+"                       le matériel (doit être root) *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+"  -l, --hwlimits       Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+"  -l, --hwlimits       Affiche les fréquences minimales et maximales du CPU "
+"*\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n"
+msgstr "  -d, --driver         Affiche le pilote cpufreq utilisé *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid "  -p, --policy         Gets the currently used cpufreq policy *\n"
+msgstr "  -p, --policy         Affiche la tactique actuelle de cpufreq *\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid "  -g, --governors      Determines available cpufreq governors *\n"
+msgstr ""
+"  -g, --governors      Affiche les régulateurs disponibles de cpufreq *\n"
+
+#: utils/cpufreq-info.c:483
+#, fuzzy, c-format
+msgid ""
+"  -r, --related-cpus   Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+"  -a, --affected-cpus   Affiche quels sont les CPUs qui doivent changer de\n"
+"                        fréquences en même temps *\n"
+
+#: utils/cpufreq-info.c:484
+#, fuzzy, c-format
+msgid ""
+"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+"                       coordinated by software *\n"
+msgstr ""
+"  -a, --affected-cpus   Affiche quels sont les CPUs qui doivent changer de\n"
+"                        fréquences en même temps *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid "  -s, --stats          Shows cpufreq statistics if available\n"
+msgstr ""
+"  -s, --stats          Indique des statistiques concernant cpufreq, si\n"
+"                       disponibles\n"
+
+#: utils/cpufreq-info.c:487
+#, fuzzy, c-format
+msgid ""
+"  -y, --latency        Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+"  -l, --hwlimits       Affiche les fréquences minimales et maximales du CPU "
+"*\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"cpufreq\n"
+"                       interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+"  -o, --proc           Affiche les informations en utilisant l'interface\n"
+"                       fournie par /proc/cpufreq, présente dans les "
+"versions\n"
+"                       2.4 et les anciennes versions 2.6 du noyau\n"
+
+#: utils/cpufreq-info.c:491
+#, fuzzy, c-format
+msgid ""
+"  -m, --human          human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+"  -m, --human           affiche dans un format lisible pour un humain\n"
+"                        pour les options -f, -w et -s (MHz, GHz)\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid "  -h, --help           Prints out this screen\n"
+msgstr "  -h, --help           affiche l'aide-mémoire\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"Par défaut, les informations de déboguage seront affichées si aucun\n"
+"argument, ou bien si seulement l'argument -c (--cpu) est donné, afin de\n"
+"faciliter les rapports de bogues par exemple\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr "Les arguments avec un * utiliseront le CPU 0 si -c (--cpu) est omis\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr "Cette option est incompatible avec --cpu\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n"
+"spécifier plus d'un argument de formatage\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "option invalide\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr "analyse du CPU %d impossible puisqu'il ne semble pas être présent\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "analyse du CPU %d :\n"
+
+#: utils/cpufreq-set.c:25
+#, fuzzy, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "Usage : cpufreq-set [options]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -d FREQ, --min FREQ       nouvelle fréquence minimale du CPU à utiliser\n"
+"                            par le régulateur\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -u FREQ, --max FREQ       nouvelle fréquence maximale du CPU à utiliser\n"
+"                            par le régulateur\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
+msgstr "  -g GOV, --governor GOV   active le régulateur GOV\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+"                           governor to be available and loaded\n"
+msgstr ""
+"  -f FREQ, --freq FREQ     fixe la fréquence du processeur à FREQ. Il faut\n"
+"                           que le régulateur « userspace » soit disponible \n"
+"                           et activé.\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid "  -r, --related            Switches all hardware-related CPUs\n"
+msgstr ""
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, fuzzy, c-format
+msgid "  -h, --help               Prints out this screen\n"
+msgstr "  -h, --help           affiche l'aide-mémoire\n"
+
+#: utils/cpufreq-set.c:35
+#, fuzzy, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr "Les arguments avec un * utiliseront le CPU 0 si -c (--cpu) est omis\n"
+
+#: utils/cpufreq-set.c:37
+#, fuzzy, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+"   except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+"   by postfixing the value with the wanted unit name, without any space\n"
+"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"Remarque :\n"
+"1. Le CPU numéro 0 sera utilisé par défaut si -c (ou --cpu) est omis ;\n"
+"2. l'argument -f FREQ (ou --freq FREQ) ne peut être utilisé qu'avec --cpu ;\n"
+"3. on pourra préciser l'unité des fréquences en postfixant sans aucune "
+"espace\n"
+"   les valeurs par hz, kHz (par défaut), MHz, GHz ou THz\n"
+"   (kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+"   for example because of hardware which cannot be set to a specific "
+"frequency\n"
+"   or because the userspace governor isn't loaded?\n"
+msgstr ""
+"En ajustant les nouveaux paramètres, une erreur est apparue. Les sources\n"
+"d'erreur typique sont :\n"
+"- droit d'administration insuffisant (êtes-vous root ?) ;\n"
+"- le régulateur choisi n'est pas disponible, ou bien n'est pas disponible "
+"en\n"
+"  tant que module noyau ;\n"
+"- la tactique n'est pas disponible ;\n"
+"- vous voulez utiliser l'option -f/--freq, mais le régulateur « userspace »\n"
+"  n'est pas disponible, par exemple parce que le matériel ne le supporte\n"
+"  pas, ou bien n'est tout simplement pas chargé.\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "CPU inconnu ou non supporté ?\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"l'option -f/--freq est incompatible avec les options -d/--min, -u/--max et\n"
+"-g/--governor\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"L'un de ces paramètres est obligatoire : -f/--freq, -d/--min, -u/--max et\n"
+"-g/--governor\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr ""
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr ""
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr ""
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-info.c:25
+#, fuzzy, c-format
+msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
+msgstr "  -p, --policy         Affiche la tactique actuelle de cpufreq *\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr ""
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr ""
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr ""
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr ""
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr ""
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:28
+#, fuzzy, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "analyse du CPU %d :\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:48
+#, fuzzy, c-format
+msgid "Available idle states:"
+msgstr "  plage de fréquence : "
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:94
+#, fuzzy, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "  pilote : %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr ""
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state:            C0\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate:              C%u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:129
+#, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid "    C%d:                  type[C%d] "
+msgstr ""
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr ""
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr ""
+
+#: utils/cpuidle-info.c:147
+#, fuzzy, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "Usage : cpufreq-info [options]\n"
+
+#: utils/cpuidle-info.c:149
+#, fuzzy, c-format
+msgid "  -s, --silent         Only show general C-state information\n"
+msgstr "  -e, --debug          Afficher les informations de déboguage\n"
+
+#: utils/cpuidle-info.c:150
+#, fuzzy, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+"                       interface in older kernels\n"
+msgstr ""
+"  -o, --proc           Affiche les informations en utilisant l'interface\n"
+"                       fournie par /proc/cpufreq, présente dans les "
+"versions\n"
+"                       2.4 et les anciennes versions 2.6 du noyau\n"
+
+#: utils/cpuidle-info.c:209
+#, fuzzy, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr ""
+"On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n"
+"spécifier plus d'un argument de formatage\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
+#~ "about\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU    Numéro du CPU pour lequel l'information sera "
+#~ "affichée\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
+#~ "modified\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU        numéro du CPU à prendre en compte pour les\n"
+#~ "                           changements\n"
diff --git a/tools/power/cpupower/po/it.po b/tools/power/cpupower/po/it.po
new file mode 100644 (file)
index 0000000..f80c4dd
--- /dev/null
@@ -0,0 +1,961 @@
+# Italian translations for cpufrequtils package
+# Copyright (C) 2004-2009
+# This file is distributed under the same license as the cpufrequtils package.
+# Mattia Dongili <malattia@gmail.com>.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: cpufrequtils 0.3\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2009-08-15 12:00+0900\n"
+"Last-Translator: Mattia Dongili <malattia@gmail.com>\n"
+"Language-Team: NONE\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr ""
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr ""
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr ""
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr ""
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr "Per favore, comunicare errori e malfunzionamenti a %s.\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr ""
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr "Impossibile determinare il numero di CPU (%s: %s), assumo sia 1\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
+msgstr ""
+"          frequenza minima CPU   -  frequenza massima CPU  -  gestore\n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid "  boost state support: \n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid "    Supported: %s\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr ""
+
+#: utils/cpufreq-info.c:164
+#, fuzzy, c-format
+msgid "    Active: %s\n"
+msgstr "  modulo %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid "    Boost States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid "    Total States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid "    Pstate-P%d:  %luMHz\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid "  no or unknown cpufreq driver is active on this CPU\n"
+msgstr "  nessun modulo o modulo cpufreq sconosciuto per questa CPU\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid "  driver: %s\n"
+msgstr "  modulo %s\n"
+
+#: utils/cpufreq-info.c:219
+#, c-format
+msgid "  CPUs which run at the same hardware frequency: "
+msgstr "  CPU che operano alla stessa frequenza hardware: "
+
+#: utils/cpufreq-info.c:230
+#, c-format
+msgid "  CPUs which need to have their frequency coordinated by software: "
+msgstr "  CPU che è necessario siano coordinate dal software: "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid "  maximum transition latency: "
+msgstr "  latenza massima durante la transizione: "
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid "  hardware limits: "
+msgstr "  limiti hardware: "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid "  available frequency steps: "
+msgstr "  frequenze disponibili: "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid "  available cpufreq governors: "
+msgstr "  gestori disponibili: "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid "  current policy: frequency should be within "
+msgstr "  gestore attuale: la frequenza deve mantenersi tra "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " e "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+"                  within this range.\n"
+msgstr ""
+" Il gestore \"%s\" può decidere quale velocità usare\n"
+"                  in questo intervallo.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid "  current CPU frequency is "
+msgstr "  la frequenza attuale della CPU è "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr " (ottenuta da una chiamata diretta all'hardware)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid "  cpufreq stats: "
+msgstr " statistiche cpufreq:"
+
+#: utils/cpufreq-info.c:472
+#, fuzzy, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "Uso: cpufreq-info [opzioni]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "Opzioni:\n"
+
+#: utils/cpufreq-info.c:474
+#, fuzzy, c-format
+msgid "  -e, --debug          Prints out debug information [default]\n"
+msgstr "  -e, --debug          Mostra informazioni di debug\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+"  -f, --freq           Get frequency the CPU currently runs at, according\n"
+"                       to the cpufreq core *\n"
+msgstr ""
+"  -f, --freq           Mostra la frequenza attuale della CPU secondo\n"
+"                       il modulo cpufreq *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+"                       it from hardware (only available to root) *\n"
+msgstr ""
+"  -w, --hwfreq         Mostra la frequenza attuale della CPU leggendola\n"
+"                       dall'hardware (disponibile solo per l'utente root) *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+"  -l, --hwlimits       Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+"  -l, --hwlimits       Determina le frequenze minima e massima possibili per "
+"la CPU *\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n"
+msgstr ""
+"  -d, --driver         Determina il modulo cpufreq del kernel in uso *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid "  -p, --policy         Gets the currently used cpufreq policy *\n"
+msgstr ""
+"  -p, --policy         Mostra il gestore cpufreq attualmente in uso *\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid "  -g, --governors      Determines available cpufreq governors *\n"
+msgstr "  -g, --governors      Determina i gestori cpufreq disponibili *\n"
+
+#: utils/cpufreq-info.c:483
+#, c-format
+msgid ""
+"  -r, --related-cpus   Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+"  -r, --related-cpus   Determina quali CPU operano alla stessa frequenza *\n"
+
+#: utils/cpufreq-info.c:484
+#, c-format
+msgid ""
+"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+"                       coordinated by software *\n"
+msgstr ""
+"  -a, --affected-cpus  Determina quali CPU devono avere la frequenza\n"
+"                       coordinata dal software *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid "  -s, --stats          Shows cpufreq statistics if available\n"
+msgstr "  -s, --stats          Mostra le statistiche se disponibili\n"
+
+#: utils/cpufreq-info.c:487
+#, c-format
+msgid ""
+"  -y, --latency        Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+"  -y, --latency        Determina la latenza massima durante i cambi di "
+"frequenza *\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"cpufreq\n"
+"                       interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+"  -o, --proc           Stampa le informazioni come se provenissero dalla\n"
+"                       interfaccia cpufreq /proc/ presente nei kernel\n"
+"                       2.4 ed i primi 2.6\n"
+
+#: utils/cpufreq-info.c:491
+#, c-format
+msgid ""
+"  -m, --human          human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+"  -m, --human          formatta l'output delle opzioni -f, -w, -s e -y in "
+"maniera\n"
+"                       leggibile da un essere umano\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid "  -h, --help           Prints out this screen\n"
+msgstr "  -h, --help           Stampa questa schermata\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"Se non viene specificata nessuna opzione o viene specificata solo l'opzione -"
+"c, --cpu,\n"
+"le informazioni di debug per cpufreq saranno utili ad esempio a riportare i "
+"bug.\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr ""
+"Per le opzioni segnalate con *, omettere l'opzione -c o --cpu è come "
+"specificarla\n"
+"con il valore 0\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr ""
+"L'opzione specificata a questo programma non può essere combinata con --cpu\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"Non è possibile specificare più di una volta l'opzione --cpu e/o\n"
+"specificare più di un parametro di output specifico\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "opzione sconosciuta o non valida\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr "impossibile analizzare la CPU %d poiché non sembra essere presente\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "analisi della CPU %d:\n"
+
+#: utils/cpufreq-set.c:25
+#, fuzzy, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "Uso: cpufreq-set [opzioni]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -d FREQ, --min FREQ      la nuova frequenza minima che il gestore cpufreq "
+"può scegliere\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -u FREQ, --max FREQ      la nuova frequenza massima che il gestore cpufreq "
+"può scegliere\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
+msgstr "  -g GOV, --governor GOV   nuovo gestore cpufreq\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+"                           governor to be available and loaded\n"
+msgstr ""
+"  -f FREQ, --freq FREQ     specifica la frequenza a cui impostare la CPU.\n"
+"                           È necessario che il gestore userspace sia "
+"disponibile e caricato\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid "  -r, --related            Switches all hardware-related CPUs\n"
+msgstr ""
+"  -r, --related            Modifica tutte le CPU coordinate dall'hardware\n"
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, c-format
+msgid "  -h, --help               Prints out this screen\n"
+msgstr "  -h, --help               Stampa questa schermata\n"
+
+#: utils/cpufreq-set.c:35
+#, fuzzy, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr ""
+"Per le opzioni segnalate con *, omettere l'opzione -c o --cpu è come "
+"specificarla\n"
+"con il valore 0\n"
+
+#: utils/cpufreq-set.c:37
+#, fuzzy, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+"   except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+"   by postfixing the value with the wanted unit name, without any space\n"
+"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"Note:\n"
+"1. Omettere l'opzione -c o --cpu è equivalente a impostarlo a 0\n"
+"2. l'opzione -f FREQ, --freq FREQ non può essere specificata con altre "
+"opzioni\n"
+"   ad eccezione dell'opzione -c CPU o --cpu CPU\n"
+"3. le FREQuenze possono essere specuficate in  Hz, kHz (default), MHz, GHz, "
+"or THz\n"
+"   postponendo l'unità di misura al valore senza nessuno spazio fra loro\n"
+"   (FREQuenza in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+"   for example because of hardware which cannot be set to a specific "
+"frequency\n"
+"   or because the userspace governor isn't loaded?\n"
+msgstr ""
+"Si sono verificati degli errori impostando i nuovi valori.\n"
+"Alcuni errori comuni possono essere:\n"
+"- Hai i necessari diritti di amministrazione? (super-user?)\n"
+"- Il gestore che hai richiesto è disponibile e caricato?\n"
+"- Stai provando ad impostare una politica di gestione non valida?\n"
+"- Stai provando a impostare una specifica frequenza ma il gestore\n"
+"  userspace non è disponibile, per esempio a causa dell'hardware\n"
+"  che non supporta frequenze fisse o a causa del fatto che\n"
+"  il gestore userspace non è caricato?\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "CPU errata, sconosciuta o non gestita?\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"l'opzione -f/--freq non può venire combinata con i parametri\n"
+" -d/--min, -u/--max o -g/--governor\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"Almeno una delle opzioni -f/--freq, -d/--min, -u/--max, e -g/--governor\n"
+"deve essere specificata\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr ""
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr ""
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr ""
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-info.c:25
+#, fuzzy, c-format
+msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
+msgstr ""
+"  -p, --policy         Mostra il gestore cpufreq attualmente in uso *\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr ""
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr ""
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr ""
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr ""
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr ""
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:28
+#, fuzzy, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "analisi della CPU %d:\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:48
+#, fuzzy, c-format
+msgid "Available idle states:"
+msgstr "  frequenze disponibili: "
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:94
+#, fuzzy, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "  modulo %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr ""
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state:            C0\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate:              C%u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:129
+#, fuzzy, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr "  latenza massima durante la transizione: "
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid "    C%d:                  type[C%d] "
+msgstr ""
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr ""
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr ""
+
+#: utils/cpuidle-info.c:147
+#, fuzzy, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "Uso: cpufreq-info [opzioni]\n"
+
+#: utils/cpuidle-info.c:149
+#, fuzzy, c-format
+msgid "  -s, --silent         Only show general C-state information\n"
+msgstr "  -e, --debug          Mostra informazioni di debug\n"
+
+#: utils/cpuidle-info.c:150
+#, fuzzy, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+"                       interface in older kernels\n"
+msgstr ""
+"  -o, --proc           Stampa le informazioni come se provenissero dalla\n"
+"                       interfaccia cpufreq /proc/ presente nei kernel\n"
+"                       2.4 ed i primi 2.6\n"
+
+#: utils/cpuidle-info.c:209
+#, fuzzy, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr ""
+"Non è possibile specificare più di una volta l'opzione --cpu e/o\n"
+"specificare più di un parametro di output specifico\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
+#~ "about\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU    Numero di CPU per la quale ottenere le "
+#~ "informazioni\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
+#~ "modified\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU        numero di CPU per la quale modificare le "
+#~ "impostazioni\n"
+
+#, fuzzy
+#~ msgid "  CPUs which coordinate software frequency requirements: "
+#~ msgstr ""
+#~ "  CPU per le quali e` necessario cambiare la frequenza "
+#~ "contemporaneamente: "
diff --git a/tools/power/cpupower/po/pt.po b/tools/power/cpupower/po/pt.po
new file mode 100644 (file)
index 0000000..990f526
--- /dev/null
@@ -0,0 +1,957 @@
+# Brazilian Portuguese translations for cpufrequtils package
+# Copyright (C) 2008 THE cpufrequtils'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the cpufrequtils package.
+# Claudio Eduardo <claudioeddy@gmail.com>, 2009.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: cpufrequtils 004\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-03-08 17:03+0100\n"
+"PO-Revision-Date: 2008-06-14 22:16-0400\n"
+"Last-Translator: Claudio Eduardo <claudioeddy@gmail.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: utils/idle_monitor/nhm_idle.c:36
+msgid "Processor Core C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:43
+msgid "Processor Core C6"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:51
+msgid "Processor Package C3"
+msgstr ""
+
+#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
+msgid "Processor Package C6"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:33
+msgid "Processor Core C7"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:40
+msgid "Processor Package C2"
+msgstr ""
+
+#: utils/idle_monitor/snb_idle.c:47
+msgid "Processor Package C7"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:56
+msgid "Package in sleep state (PC1 or deeper)"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:63
+msgid "Processor Package C1"
+msgstr ""
+
+#: utils/idle_monitor/amd_fam14h_idle.c:77
+msgid "North Bridge P1 boolean counter (returns 0 or 1)"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:35
+msgid "Processor Core not idle"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:42
+msgid "Processor Core in an idle state"
+msgstr ""
+
+#: utils/idle_monitor/mperf_monitor.c:50
+msgid "Average Frequency (including boost) in MHz"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:66
+#, c-format
+msgid ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:69
+#, c-format
+msgid ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c command ...]\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:71
+#, c-format
+msgid "\t -v: be more verbose\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:73
+#, c-format
+msgid "\t -h: print this help\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:74
+#, c-format
+msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:75
+#, c-format
+msgid "\t -t: show CPU topology/hierarchy\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:76
+#, c-format
+msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:77
+#, c-format
+msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:79
+#, c-format
+msgid ""
+"only one of: -t, -l, -m are allowed\n"
+"If none of them is passed,"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:80
+#, c-format
+msgid " all supported monitors are shown\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:197
+#, c-format
+msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:207
+#, c-format
+msgid " *is offline\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:236
+#, c-format
+msgid "%s: max monitor name length (%d) exceeded\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:250
+#, c-format
+msgid "No matching monitor found in %s, try -l option\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:266
+#, c-format
+msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:319
+#, c-format
+msgid "%s took %.5f seconds and exited with status %d\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:406
+#, c-format
+msgid "Cannot read number of available processors\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:417
+#, c-format
+msgid "Available monitor %s needs root access\n"
+msgstr ""
+
+#: utils/idle_monitor/cpupower-monitor.c:428
+#, c-format
+msgid "No HW Cstate monitors found\n"
+msgstr ""
+
+#: utils/cpupower.c:78
+#, c-format
+msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
+msgstr ""
+
+#: utils/cpupower.c:79
+#, c-format
+msgid "cpupower --version\n"
+msgstr ""
+
+#: utils/cpupower.c:80
+#, c-format
+msgid "Supported subcommands are:\n"
+msgstr ""
+
+#: utils/cpupower.c:83
+#, c-format
+msgid ""
+"\n"
+"Some subcommands can make use of the -c cpulist option.\n"
+msgstr ""
+
+#: utils/cpupower.c:84
+#, c-format
+msgid "Look at the general cpupower manpage how to use it\n"
+msgstr ""
+
+#: utils/cpupower.c:85
+#, c-format
+msgid "and read up the subcommand's manpage whether it is supported.\n"
+msgstr ""
+
+#: utils/cpupower.c:86
+#, c-format
+msgid ""
+"\n"
+"Use cpupower help subcommand for getting help for above subcommands.\n"
+msgstr ""
+
+#: utils/cpupower.c:91
+#, c-format
+msgid "Report errors and bugs to %s, please.\n"
+msgstr "Reporte erros e bugs para %s, por favor.\n"
+
+#: utils/cpupower.c:114
+#, c-format
+msgid "Error parsing cpu list\n"
+msgstr ""
+
+#: utils/cpupower.c:172
+#, c-format
+msgid "Subcommand %s needs root privileges\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:31
+#, c-format
+msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
+msgstr "Não foi possível contar o número de CPUs (%s: %s), assumindo 1\n"
+
+#: utils/cpufreq-info.c:63
+#, c-format
+msgid ""
+"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
+msgstr ""
+"          frequência mínina do CPU  -  frequência máxima do CPU  -  "
+"regulador\n"
+
+#: utils/cpufreq-info.c:151
+#, c-format
+msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
+msgstr ""
+
+#. P state changes via MSR are identified via cpuid 80000007
+#. on Intel and AMD, but we assume boost capable machines can do that
+#. if (cpuid_eax(0x80000000) >= 0x80000007
+#. && (cpuid_edx(0x80000007) & (1 << 7)))
+#.
+#: utils/cpufreq-info.c:161
+#, c-format
+msgid "  boost state support: \n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163
+#, c-format
+msgid "    Supported: %s\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "yes"
+msgstr ""
+
+#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
+msgid "no"
+msgstr ""
+
+#: utils/cpufreq-info.c:164
+#, fuzzy, c-format
+msgid "    Active: %s\n"
+msgstr "  driver: %s\n"
+
+#: utils/cpufreq-info.c:177
+#, c-format
+msgid "    Boost States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:178
+#, c-format
+msgid "    Total States: %d\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:181
+#, c-format
+msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:184
+#, c-format
+msgid "    Pstate-P%d:  %luMHz\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:211
+#, c-format
+msgid "  no or unknown cpufreq driver is active on this CPU\n"
+msgstr "  nenhum ou driver do cpufreq deconhecido está ativo nesse CPU\n"
+
+#: utils/cpufreq-info.c:213
+#, c-format
+msgid "  driver: %s\n"
+msgstr "  driver: %s\n"
+
+#: utils/cpufreq-info.c:219
+#, c-format
+msgid "  CPUs which run at the same hardware frequency: "
+msgstr "  CPUs que rodam na mesma frequência de hardware: "
+
+#: utils/cpufreq-info.c:230
+#, c-format
+msgid "  CPUs which need to have their frequency coordinated by software: "
+msgstr "  CPUs que precisam ter suas frequências coordenadas por software: "
+
+#: utils/cpufreq-info.c:241
+#, c-format
+msgid "  maximum transition latency: "
+msgstr "  maior latência de transição: "
+
+#: utils/cpufreq-info.c:247
+#, c-format
+msgid "  hardware limits: "
+msgstr "  limites do hardware: "
+
+#: utils/cpufreq-info.c:256
+#, c-format
+msgid "  available frequency steps: "
+msgstr "  níveis de frequência disponíveis: "
+
+#: utils/cpufreq-info.c:269
+#, c-format
+msgid "  available cpufreq governors: "
+msgstr "  reguladores do cpufreq disponíveis: "
+
+#: utils/cpufreq-info.c:280
+#, c-format
+msgid "  current policy: frequency should be within "
+msgstr "  política de frequência atual deve estar entre "
+
+#: utils/cpufreq-info.c:282
+#, c-format
+msgid " and "
+msgstr " e "
+
+#: utils/cpufreq-info.c:286
+#, c-format
+msgid ""
+"The governor \"%s\" may decide which speed to use\n"
+"                  within this range.\n"
+msgstr ""
+"O regulador \"%s\" deve decidir qual velocidade usar\n"
+"                  dentro desse limite.\n"
+
+#: utils/cpufreq-info.c:293
+#, c-format
+msgid "  current CPU frequency is "
+msgstr "  frequência atual do CPU é "
+
+#: utils/cpufreq-info.c:296
+#, c-format
+msgid " (asserted by call to hardware)"
+msgstr " (declarado por chamada ao hardware)"
+
+#: utils/cpufreq-info.c:304
+#, c-format
+msgid "  cpufreq stats: "
+msgstr "  status do cpufreq: "
+
+#: utils/cpufreq-info.c:472
+#, fuzzy, c-format
+msgid "Usage: cpupower freqinfo [options]\n"
+msgstr "Uso: cpufreq-info [opções]\n"
+
+#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
+#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
+#, c-format
+msgid "Options:\n"
+msgstr "Opções:\n"
+
+#: utils/cpufreq-info.c:474
+#, fuzzy, c-format
+msgid "  -e, --debug          Prints out debug information [default]\n"
+msgstr "  -e, --debug          Mostra informação de debug\n"
+
+#: utils/cpufreq-info.c:475
+#, c-format
+msgid ""
+"  -f, --freq           Get frequency the CPU currently runs at, according\n"
+"                       to the cpufreq core *\n"
+msgstr ""
+"  -f, --freq           Obtem a frequência na qual o CPU roda no momento, de "
+"acordo\n"
+"                       com o núcleo do cpufreq *\n"
+
+#: utils/cpufreq-info.c:477
+#, c-format
+msgid ""
+"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+"                       it from hardware (only available to root) *\n"
+msgstr ""
+"  -w, --hwfreq         Obtem a frequência na qual o CPU está operando no "
+"momento,\n"
+"                       através de leitura no hardware (disponível somente "
+"para root) *\n"
+
+#: utils/cpufreq-info.c:479
+#, c-format
+msgid ""
+"  -l, --hwlimits       Determine the minimum and maximum CPU frequency "
+"allowed *\n"
+msgstr ""
+"  -l, --hwlimits       Determina a frequência mínima e máxima do CPU "
+"permitida *\n"
+
+#: utils/cpufreq-info.c:480
+#, c-format
+msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n"
+msgstr ""
+"  -d,  --driver         Determina o driver do kernel do cpufreq usado *\n"
+
+#: utils/cpufreq-info.c:481
+#, c-format
+msgid "  -p, --policy         Gets the currently used cpufreq policy *\n"
+msgstr ""
+"--p, --policy         Obtem a política do cpufreq em uso no momento *\n"
+
+#: utils/cpufreq-info.c:482
+#, c-format
+msgid "  -g, --governors      Determines available cpufreq governors *\n"
+msgstr ""
+"  -g, --governors      Determina reguladores do cpufreq disponíveis *\n"
+
+#: utils/cpufreq-info.c:483
+#, c-format
+msgid ""
+"  -r, --related-cpus   Determines which CPUs run at the same hardware "
+"frequency *\n"
+msgstr ""
+"  -r, --related-cpus   Determina quais CPUs rodam na mesma frequência de "
+"hardware *\n"
+
+#: utils/cpufreq-info.c:484
+#, c-format
+msgid ""
+"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+"                       coordinated by software *\n"
+msgstr ""
+"  -a, --affected-cpus  Determina quais CPUs precisam ter suas frequências\n"
+"                       coordenadas por software *\n"
+
+#: utils/cpufreq-info.c:486
+#, c-format
+msgid "  -s, --stats          Shows cpufreq statistics if available\n"
+msgstr "  -s, --stats          Mostra estatísticas do cpufreq se disponíveis\n"
+
+#: utils/cpufreq-info.c:487
+#, c-format
+msgid ""
+"  -y, --latency        Determines the maximum latency on CPU frequency "
+"changes *\n"
+msgstr ""
+"  -y, --latency        Determina a latência máxima nas trocas de frequência "
+"do CPU *\n"
+
+#: utils/cpufreq-info.c:488
+#, c-format
+msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
+msgstr ""
+
+#: utils/cpufreq-info.c:489
+#, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"cpufreq\n"
+"                       interface in 2.4. and early 2.6. kernels\n"
+msgstr ""
+"  -o, --proc           Mostra informação do tipo provida pela interface /"
+"proc/cpufreq\n"
+"                       em kernels 2.4. e mais recentes 2.6\n"
+
+#: utils/cpufreq-info.c:491
+#, c-format
+msgid ""
+"  -m, --human          human-readable output for the -f, -w, -s and -y "
+"parameters\n"
+msgstr ""
+"  -m, --human          saída legível para humanos para os parâmetros -f, -w, "
+"-s e -y\n"
+
+#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152
+#, c-format
+msgid "  -h, --help           Prints out this screen\n"
+msgstr " -h, --help           Imprime essa tela\n"
+
+#: utils/cpufreq-info.c:495
+#, c-format
+msgid ""
+"If no argument or only the -c, --cpu parameter is given, debug output about\n"
+"cpufreq is printed which is useful e.g. for reporting bugs.\n"
+msgstr ""
+"Se nenhum argumento ou somente o parâmetro -c, --cpu é dado, informação de "
+"debug sobre\n"
+"o cpufreq é mostrada, o que é útil por exemplo para reportar bugs.\n"
+
+#: utils/cpufreq-info.c:497
+#, c-format
+msgid ""
+"For the arguments marked with *, omitting the -c or --cpu argument is\n"
+"equivalent to setting it to zero\n"
+msgstr ""
+"Para os argumentos marcados com *, omitir o argumento -c ou --cpu é\n"
+"equivalente a setá-lo como zero\n"
+
+#: utils/cpufreq-info.c:580
+#, c-format
+msgid ""
+"The argument passed to this tool can't be combined with passing a --cpu "
+"argument\n"
+msgstr ""
+"O argumento usado pra essa ferramenta não pode ser combinado com um "
+"argumento --cpu\n"
+
+#: utils/cpufreq-info.c:596
+#, c-format
+msgid ""
+"You can't specify more than one --cpu parameter and/or\n"
+"more than one output-specific argument\n"
+msgstr ""
+"Você não pode especificar mais do que um parâmetro --cpu e/ou\n"
+"mais do que um argumento de saída específico\n"
+
+#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
+#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
+#, c-format
+msgid "invalid or unknown argument\n"
+msgstr "argumento inválido ou desconhecido\n"
+
+#: utils/cpufreq-info.c:617
+#, c-format
+msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
+msgstr ""
+"não foi possível analisar o CPU % já que o mesmo parece não estar presente\n"
+
+#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
+#, c-format
+msgid "analyzing CPU %d:\n"
+msgstr "analisando o CPU %d:\n"
+
+#: utils/cpufreq-set.c:25
+#, fuzzy, c-format
+msgid "Usage: cpupower frequency-set [options]\n"
+msgstr "Uso: cpufreq-set [opções]\n"
+
+#: utils/cpufreq-set.c:27
+#, c-format
+msgid ""
+"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -d FREQ, --min FREQ      nova frequência mínima do CPU que o regulador "
+"deve selecionar\n"
+
+#: utils/cpufreq-set.c:28
+#, c-format
+msgid ""
+"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may "
+"select\n"
+msgstr ""
+"  -u FREQ, --max FREQ      nova frequência máxima do CPU que o regulador "
+"deve escolher\n"
+
+#: utils/cpufreq-set.c:29
+#, c-format
+msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
+msgstr "  -g GOV, --governor GOV   novo regulador do cpufreq\n"
+
+#: utils/cpufreq-set.c:30
+#, c-format
+msgid ""
+"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+"                           governor to be available and loaded\n"
+msgstr ""
+"  -f FREQ, --freq FREQ     frequência específica para ser setada. Necessita "
+"que o regulador em\n"
+"                           nível de usuário esteja disponível e carregado\n"
+
+#: utils/cpufreq-set.c:32
+#, c-format
+msgid "  -r, --related            Switches all hardware-related CPUs\n"
+msgstr ""
+"  -r, --related            Modifica todos os CPUs relacionados ao hardware\n"
+
+#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
+#, c-format
+msgid "  -h, --help               Prints out this screen\n"
+msgstr " -h, --help           Mostra essa tela\n"
+
+#: utils/cpufreq-set.c:35
+#, fuzzy, c-format
+msgid ""
+"Notes:\n"
+"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
+msgstr ""
+"Para os argumentos marcados com *, omitir o argumento -c ou --cpu é\n"
+"equivalente a setá-lo como zero\n"
+
+#: utils/cpufreq-set.c:37
+#, fuzzy, c-format
+msgid ""
+"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other "
+"parameter\n"
+"   except the -c CPU, --cpu CPU parameter\n"
+"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+"   by postfixing the value with the wanted unit name, without any space\n"
+"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+msgstr ""
+"Notas:\n"
+"1. Omitir o argumento -c or --cpu é equivalente a setá-lo como zero\n"
+"2. O parâmetro -f FREQ, --freq FREQ não pode ser combinado com qualquer "
+"outro parâmetro\n"
+"   exceto com o parâmetro -c CPU, --cpu CPU\n"
+"3. FREQuências podem ser usadas em Hz, kHz (padrão), MHz, GHz, o THz\n"
+"   colocando o nome desejado da unidade após o valor, sem qualquer espaço\n"
+"   (FREQuência em kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"
+
+#: utils/cpufreq-set.c:57
+#, c-format
+msgid ""
+"Error setting new values. Common errors:\n"
+"- Do you have proper administration rights? (super-user?)\n"
+"- Is the governor you requested available and modprobed?\n"
+"- Trying to set an invalid policy?\n"
+"- Trying to set a specific frequency, but userspace governor is not "
+"available,\n"
+"   for example because of hardware which cannot be set to a specific "
+"frequency\n"
+"   or because the userspace governor isn't loaded?\n"
+msgstr ""
+"Erro ao setar novos valores. Erros comuns:\n"
+"- Você tem direitos administrativos necessários? (super-usuário?)\n"
+"- O regulador que você requesitou está disponível e foi \"modprobed\"?\n"
+"- Tentando setar uma política inválida?\n"
+"- Tentando setar uma frequência específica, mas o regulador em nível de "
+"usuário não está disponível,\n"
+"   por exemplo devido ao hardware que não pode ser setado pra uma frequência "
+"específica\n"
+"   ou porque o regulador em nível de usuário não foi carregado?\n"
+
+#: utils/cpufreq-set.c:170
+#, c-format
+msgid "wrong, unknown or unhandled CPU?\n"
+msgstr "CPU errado, desconhecido ou inesperado?\n"
+
+#: utils/cpufreq-set.c:302
+#, c-format
+msgid ""
+"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+"-g/--governor parameters\n"
+msgstr ""
+"o parâmetro -f/--freq não pode ser combinado com os parâmetros -d/--min, -"
+"u/--max ou\n"
+"-g/--governor\n"
+
+#: utils/cpufreq-set.c:308
+#, c-format
+msgid ""
+"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+"-g/--governor must be passed\n"
+msgstr ""
+"Pelo menos um parâmetro entre -f/--freq, -d/--min, -u/--max, e\n"
+"-g/--governor deve ser usado\n"
+
+#: utils/cpufreq-set.c:347
+#, c-format
+msgid "Setting cpu: %d\n"
+msgstr ""
+
+#: utils/cpupower-set.c:22
+#, c-format
+msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:24
+#, c-format
+msgid ""
+"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-set.c:26
+#, c-format
+msgid ""
+"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:27
+#, c-format
+msgid ""
+"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler "
+"policy.\n"
+msgstr ""
+
+#: utils/cpupower-set.c:80
+#, c-format
+msgid "--perf-bias param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:91
+#, c-format
+msgid "--sched-mc param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:102
+#, c-format
+msgid "--sched-smt param out of range [0-%d]\n"
+msgstr ""
+
+#: utils/cpupower-set.c:121
+#, c-format
+msgid "Error setting sched-mc %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:127
+#, c-format
+msgid "Error setting sched-smt %s\n"
+msgstr ""
+
+#: utils/cpupower-set.c:146
+#, c-format
+msgid "Error setting perf-bias value on CPU %d\n"
+msgstr ""
+
+#: utils/cpupower-info.c:21
+#, c-format
+msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
+msgstr ""
+
+#: utils/cpupower-info.c:23
+#, c-format
+msgid ""
+"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+"                           Intel models [0-15], see manpage for details\n"
+msgstr ""
+
+#: utils/cpupower-info.c:25
+#, fuzzy, c-format
+msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
+msgstr ""
+"--p, --policy         Obtem a política do cpufreq em uso no momento *\n"
+
+#: utils/cpupower-info.c:26
+#, c-format
+msgid ""
+"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"
+msgstr ""
+
+#: utils/cpupower-info.c:28
+#, c-format
+msgid ""
+"\n"
+"Passing no option will show all info, by default only on core 0\n"
+msgstr ""
+
+#: utils/cpupower-info.c:102
+#, c-format
+msgid "System's multi core scheduler setting: "
+msgstr ""
+
+#. if sysfs file is missing it's: errno == ENOENT
+#: utils/cpupower-info.c:105 utils/cpupower-info.c:114
+#, c-format
+msgid "not supported\n"
+msgstr ""
+
+#: utils/cpupower-info.c:111
+#, c-format
+msgid "System's thread sibling scheduler setting: "
+msgstr ""
+
+#: utils/cpupower-info.c:126
+#, c-format
+msgid "Intel's performance bias setting needs root privileges\n"
+msgstr ""
+
+#: utils/cpupower-info.c:128
+#, c-format
+msgid "System does not support Intel's performance bias setting\n"
+msgstr ""
+
+#: utils/cpupower-info.c:147
+#, c-format
+msgid "Could not read perf-bias value\n"
+msgstr ""
+
+#: utils/cpupower-info.c:150
+#, c-format
+msgid "perf-bias: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:28
+#, fuzzy, c-format
+msgid "Analyzing CPU %d:\n"
+msgstr "analisando o CPU %d:\n"
+
+#: utils/cpuidle-info.c:32
+#, c-format
+msgid "CPU %u: No idle states\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:36
+#, c-format
+msgid "CPU %u: Can't read idle state info\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:41
+#, c-format
+msgid "Could not determine max idle state %u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:46
+#, c-format
+msgid "Number of idle states: %d\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:48
+#, fuzzy, c-format
+msgid "Available idle states:"
+msgstr "  níveis de frequência disponíveis: "
+
+#: utils/cpuidle-info.c:71
+#, c-format
+msgid "Flags/Description: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:74
+#, c-format
+msgid "Latency: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:76
+#, c-format
+msgid "Usage: %lu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:78
+#, c-format
+msgid "Duration: %llu\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:90
+#, c-format
+msgid "Could not determine cpuidle driver\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:94
+#, fuzzy, c-format
+msgid "CPUidle driver: %s\n"
+msgstr "  driver: %s\n"
+
+#: utils/cpuidle-info.c:99
+#, c-format
+msgid "Could not determine cpuidle governor\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:103
+#, c-format
+msgid "CPUidle governor: %s\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:122
+#, c-format
+msgid "CPU %u: Can't read C-state info\n"
+msgstr ""
+
+#. printf("Cstates: %d\n", cstates);
+#: utils/cpuidle-info.c:127
+#, c-format
+msgid "active state:            C0\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:128
+#, c-format
+msgid "max_cstate:              C%u\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:129
+#, fuzzy, c-format
+msgid "maximum allowed latency: %lu usec\n"
+msgstr "  maior latência de transição: "
+
+#: utils/cpuidle-info.c:130
+#, c-format
+msgid "states:\t\n"
+msgstr ""
+
+#: utils/cpuidle-info.c:132
+#, c-format
+msgid "    C%d:                  type[C%d] "
+msgstr ""
+
+#: utils/cpuidle-info.c:134
+#, c-format
+msgid "promotion[--] demotion[--] "
+msgstr ""
+
+#: utils/cpuidle-info.c:135
+#, c-format
+msgid "latency[%03lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:137
+#, c-format
+msgid "usage[%08lu] "
+msgstr ""
+
+#: utils/cpuidle-info.c:139
+#, c-format
+msgid "duration[%020Lu] \n"
+msgstr ""
+
+#: utils/cpuidle-info.c:147
+#, fuzzy, c-format
+msgid "Usage: cpupower idleinfo [options]\n"
+msgstr "Uso: cpufreq-info [opções]\n"
+
+#: utils/cpuidle-info.c:149
+#, fuzzy, c-format
+msgid "  -s, --silent         Only show general C-state information\n"
+msgstr "  -e, --debug          Mostra informação de debug\n"
+
+#: utils/cpuidle-info.c:150
+#, fuzzy, c-format
+msgid ""
+"  -o, --proc           Prints out information like provided by the /proc/"
+"acpi/processor/*/power\n"
+"                       interface in older kernels\n"
+msgstr ""
+"  -o, --proc           Mostra informação do tipo provida pela interface /"
+"proc/cpufreq\n"
+"                       em kernels 2.4. e mais recentes 2.6\n"
+
+#: utils/cpuidle-info.c:209
+#, fuzzy, c-format
+msgid "You can't specify more than one output-specific argument\n"
+msgstr ""
+"Você não pode especificar mais do que um parâmetro --cpu e/ou\n"
+"mais do que um argumento de saída específico\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
+#~ "about\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU    número do CPU sobre o qual as inforções devem ser "
+#~ "determinadas\n"
+
+#~ msgid ""
+#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
+#~ "modified\n"
+#~ msgstr ""
+#~ "  -c CPU, --cpu CPU        número do CPU onde as configurações do cpufreq "
+#~ "vão ser modificadas\n"
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
new file mode 100644 (file)
index 0000000..c870ffb
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef BUILTIN_H
+#define BUILTIN_H
+
+extern int cmd_set(int argc, const char **argv);
+extern int cmd_info(int argc, const char **argv);
+extern int cmd_freq_set(int argc, const char **argv);
+extern int cmd_freq_info(int argc, const char **argv);
+extern int cmd_idle_info(int argc, const char **argv);
+extern int cmd_monitor(int argc, const char **argv);
+
+extern void set_help(void);
+extern void info_help(void);
+extern void freq_set_help(void);
+extern void freq_info_help(void);
+extern void idle_info_help(void);
+extern void monitor_help(void);
+
+#endif
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
new file mode 100644 (file)
index 0000000..5a1d25f
--- /dev/null
@@ -0,0 +1,708 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+
+#include "cpufreq.h"
+#include "helpers/helpers.h"
+#include "helpers/bitmask.h"
+
+#define LINE_LEN 10
+
+static unsigned int count_cpus(void)
+{
+       FILE *fp;
+       char value[LINE_LEN];
+       unsigned int ret = 0;
+       unsigned int cpunr = 0;
+
+       fp = fopen("/proc/stat", "r");
+       if (!fp) {
+               printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));
+               return 1;
+       }
+
+       while (!feof(fp)) {
+               if (!fgets(value, LINE_LEN, fp))
+                       continue;
+               value[LINE_LEN - 1] = '\0';
+               if (strlen(value) < (LINE_LEN - 2))
+                       continue;
+               if (strstr(value, "cpu "))
+                       continue;
+               if (sscanf(value, "cpu%d ", &cpunr) != 1)
+                       continue;
+               if (cpunr > ret)
+                       ret = cpunr;
+       }
+       fclose(fp);
+
+       /* cpu count starts from 0, on error return 1 (UP) */
+       return ret + 1;
+}
+
+
+static void proc_cpufreq_output(void)
+{
+       unsigned int cpu, nr_cpus;
+       struct cpufreq_policy *policy;
+       unsigned int min_pctg = 0;
+       unsigned int max_pctg = 0;
+       unsigned long min, max;
+
+       printf(_("          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"));
+
+       nr_cpus = count_cpus();
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               policy = cpufreq_get_policy(cpu);
+               if (!policy)
+                       continue;
+
+               if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
+                       max = 0;
+               } else {
+                       min_pctg = (policy->min * 100) / max;
+                       max_pctg = (policy->max * 100) / max;
+               }
+               printf("CPU%3d    %9lu kHz (%3d %%)  -  %9lu kHz (%3d %%)  -  %s\n",
+                       cpu , policy->min, max ? min_pctg : 0, policy->max,
+                       max ? max_pctg : 0, policy->governor);
+
+               cpufreq_put_policy(policy);
+       }
+}
+
+static void print_speed(unsigned long speed)
+{
+       unsigned long tmp;
+
+       if (speed > 1000000) {
+               tmp = speed % 10000;
+               if (tmp >= 5000)
+                       speed += 10000;
+               printf("%u.%02u GHz", ((unsigned int) speed/1000000),
+                       ((unsigned int) (speed%1000000)/10000));
+       } else if (speed > 100000) {
+               tmp = speed % 1000;
+               if (tmp >= 500)
+                       speed += 1000;
+               printf("%u MHz", ((unsigned int) speed / 1000));
+       } else if (speed > 1000) {
+               tmp = speed % 100;
+               if (tmp >= 50)
+                       speed += 100;
+               printf("%u.%01u MHz", ((unsigned int) speed/1000),
+                       ((unsigned int) (speed%1000)/100));
+       } else
+               printf("%lu kHz", speed);
+
+       return;
+}
+
+static void print_duration(unsigned long duration)
+{
+       unsigned long tmp;
+
+       if (duration > 1000000) {
+               tmp = duration % 10000;
+               if (tmp >= 5000)
+                       duration += 10000;
+               printf("%u.%02u ms", ((unsigned int) duration/1000000),
+                       ((unsigned int) (duration%1000000)/10000));
+       } else if (duration > 100000) {
+               tmp = duration % 1000;
+               if (tmp >= 500)
+                       duration += 1000;
+               printf("%u us", ((unsigned int) duration / 1000));
+       } else if (duration > 1000) {
+               tmp = duration % 100;
+               if (tmp >= 50)
+                       duration += 100;
+               printf("%u.%01u us", ((unsigned int) duration/1000),
+                       ((unsigned int) (duration%1000)/100));
+       } else
+               printf("%lu ns", duration);
+
+       return;
+}
+
+/* --boost / -b */
+
+static int get_boost_mode(unsigned int cpu)
+{
+       int support, active, b_states = 0, ret, pstate_no, i;
+       /* ToDo: Make this more global */
+       unsigned long pstates[MAX_HW_PSTATES] = {0,};
+
+       if (cpupower_cpu_info.vendor != X86_VENDOR_AMD &&
+           cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
+               return 0;
+
+       ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
+       if (ret) {
+               printf(_("Error while evaluating Boost Capabilities"
+                               " on CPU %d -- are you root?\n"), cpu);
+               return ret;
+       }
+       /* P state changes via MSR are identified via cpuid 80000007
+          on Intel and AMD, but we assume boost capable machines can do that
+          if (cpuid_eax(0x80000000) >= 0x80000007
+          && (cpuid_edx(0x80000007) & (1 << 7)))
+       */
+
+       printf(_("  boost state support:\n"));
+
+       printf(_("    Supported: %s\n"), support ? _("yes") : _("no"));
+       printf(_("    Active: %s\n"), active ? _("yes") : _("no"));
+
+       if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
+           cpupower_cpu_info.family >= 0x10) {
+               ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
+                                    pstates, &pstate_no);
+               if (ret)
+                       return ret;
+
+               printf(_("    Boost States: %d\n"), b_states);
+               printf(_("    Total States: %d\n"), pstate_no);
+               for (i = 0; i < pstate_no; i++) {
+                       if (i < b_states)
+                               printf(_("    Pstate-Pb%d: %luMHz (boost state)"
+                                        "\n"), i, pstates[i]);
+                       else
+                               printf(_("    Pstate-P%d:  %luMHz\n"),
+                                      i - b_states, pstates[i]);
+               }
+       } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) {
+               double bclk;
+               unsigned long long intel_turbo_ratio = 0;
+               unsigned int ratio;
+
+               /* Any way to autodetect this ? */
+               if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB)
+                       bclk = 100.00;
+               else
+                       bclk = 133.33;
+               intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu);
+               dprint ("    Ratio: 0x%llx - bclk: %f\n",
+                       intel_turbo_ratio, bclk);
+
+               ratio = (intel_turbo_ratio >> 24) & 0xFF;
+               if (ratio)
+                       printf(_("    %.0f MHz max turbo 4 active cores\n"),
+                              ratio * bclk);
+
+               ratio = (intel_turbo_ratio >> 16) & 0xFF;
+               if (ratio)
+                       printf(_("    %.0f MHz max turbo 3 active cores\n"),
+                              ratio * bclk);
+
+               ratio = (intel_turbo_ratio >> 8) & 0xFF;
+               if (ratio)
+                       printf(_("    %.0f MHz max turbo 2 active cores\n"),
+                              ratio * bclk);
+
+               ratio = (intel_turbo_ratio >> 0) & 0xFF;
+               if (ratio)
+                       printf(_("    %.0f MHz max turbo 1 active cores\n"),
+                              ratio * bclk);
+       }
+       return 0;
+}
+
+static void debug_output_one(unsigned int cpu)
+{
+       char *driver;
+       struct cpufreq_affected_cpus *cpus;
+       struct cpufreq_available_frequencies *freqs;
+       unsigned long min, max, freq_kernel, freq_hardware;
+       unsigned long total_trans, latency;
+       unsigned long long total_time;
+       struct cpufreq_policy *policy;
+       struct cpufreq_available_governors *governors;
+       struct cpufreq_stats *stats;
+
+       if (cpufreq_cpu_exists(cpu))
+               return;
+
+       freq_kernel = cpufreq_get_freq_kernel(cpu);
+       freq_hardware = cpufreq_get_freq_hardware(cpu);
+
+       driver = cpufreq_get_driver(cpu);
+       if (!driver) {
+               printf(_("  no or unknown cpufreq driver is active on this CPU\n"));
+       } else {
+               printf(_("  driver: %s\n"), driver);
+               cpufreq_put_driver(driver);
+       }
+
+       cpus = cpufreq_get_related_cpus(cpu);
+       if (cpus) {
+               printf(_("  CPUs which run at the same hardware frequency: "));
+               while (cpus->next) {
+                       printf("%d ", cpus->cpu);
+                       cpus = cpus->next;
+               }
+               printf("%d\n", cpus->cpu);
+               cpufreq_put_related_cpus(cpus);
+       }
+
+       cpus = cpufreq_get_affected_cpus(cpu);
+       if (cpus) {
+               printf(_("  CPUs which need to have their frequency coordinated by software: "));
+               while (cpus->next) {
+                       printf("%d ", cpus->cpu);
+                       cpus = cpus->next;
+               }
+               printf("%d\n", cpus->cpu);
+               cpufreq_put_affected_cpus(cpus);
+       }
+
+       latency = cpufreq_get_transition_latency(cpu);
+       if (latency) {
+               printf(_("  maximum transition latency: "));
+               print_duration(latency);
+               printf(".\n");
+       }
+
+       if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) {
+               printf(_("  hardware limits: "));
+               print_speed(min);
+               printf(" - ");
+               print_speed(max);
+               printf("\n");
+       }
+
+       freqs = cpufreq_get_available_frequencies(cpu);
+       if (freqs) {
+               printf(_("  available frequency steps: "));
+               while (freqs->next) {
+                       print_speed(freqs->frequency);
+                       printf(", ");
+                       freqs = freqs->next;
+               }
+               print_speed(freqs->frequency);
+               printf("\n");
+               cpufreq_put_available_frequencies(freqs);
+       }
+
+       governors = cpufreq_get_available_governors(cpu);
+       if (governors) {
+               printf(_("  available cpufreq governors: "));
+               while (governors->next) {
+                       printf("%s, ", governors->governor);
+                       governors = governors->next;
+               }
+               printf("%s\n", governors->governor);
+               cpufreq_put_available_governors(governors);
+       }
+
+       policy = cpufreq_get_policy(cpu);
+       if (policy) {
+               printf(_("  current policy: frequency should be within "));
+               print_speed(policy->min);
+               printf(_(" and "));
+               print_speed(policy->max);
+
+               printf(".\n                  ");
+               printf(_("The governor \"%s\" may"
+                      " decide which speed to use\n                  within this range.\n"),
+                      policy->governor);
+               cpufreq_put_policy(policy);
+       }
+
+       if (freq_kernel || freq_hardware) {
+               printf(_("  current CPU frequency is "));
+               if (freq_hardware) {
+                       print_speed(freq_hardware);
+                       printf(_(" (asserted by call to hardware)"));
+               } else
+                       print_speed(freq_kernel);
+               printf(".\n");
+       }
+       stats = cpufreq_get_stats(cpu, &total_time);
+       if (stats) {
+               printf(_("  cpufreq stats: "));
+               while (stats) {
+                       print_speed(stats->frequency);
+                       printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
+                       stats = stats->next;
+                       if (stats)
+                               printf(", ");
+               }
+               cpufreq_put_stats(stats);
+               total_trans = cpufreq_get_transitions(cpu);
+               if (total_trans)
+                       printf("  (%lu)\n", total_trans);
+               else
+                       printf("\n");
+       }
+       get_boost_mode(cpu);
+
+}
+
+/* --freq / -f */
+
+static int get_freq_kernel(unsigned int cpu, unsigned int human)
+{
+       unsigned long freq = cpufreq_get_freq_kernel(cpu);
+       if (!freq)
+               return -EINVAL;
+       if (human) {
+               print_speed(freq);
+               printf("\n");
+       } else
+               printf("%lu\n", freq);
+       return 0;
+}
+
+
+/* --hwfreq / -w */
+
+static int get_freq_hardware(unsigned int cpu, unsigned int human)
+{
+       unsigned long freq = cpufreq_get_freq_hardware(cpu);
+       if (!freq)
+               return -EINVAL;
+       if (human) {
+               print_speed(freq);
+               printf("\n");
+       } else
+               printf("%lu\n", freq);
+       return 0;
+}
+
+/* --hwlimits / -l */
+
+static int get_hardware_limits(unsigned int cpu)
+{
+       unsigned long min, max;
+       if (cpufreq_get_hardware_limits(cpu, &min, &max))
+               return -EINVAL;
+       printf("%lu %lu\n", min, max);
+       return 0;
+}
+
+/* --driver / -d */
+
+static int get_driver(unsigned int cpu)
+{
+       char *driver = cpufreq_get_driver(cpu);
+       if (!driver)
+               return -EINVAL;
+       printf("%s\n", driver);
+       cpufreq_put_driver(driver);
+       return 0;
+}
+
+/* --policy / -p */
+
+static int get_policy(unsigned int cpu)
+{
+       struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
+       if (!policy)
+               return -EINVAL;
+       printf("%lu %lu %s\n", policy->min, policy->max, policy->governor);
+       cpufreq_put_policy(policy);
+       return 0;
+}
+
+/* --governors / -g */
+
+static int get_available_governors(unsigned int cpu)
+{
+       struct cpufreq_available_governors *governors =
+               cpufreq_get_available_governors(cpu);
+       if (!governors)
+               return -EINVAL;
+
+       while (governors->next) {
+               printf("%s ", governors->governor);
+               governors = governors->next;
+       }
+       printf("%s\n", governors->governor);
+       cpufreq_put_available_governors(governors);
+       return 0;
+}
+
+
+/* --affected-cpus  / -a */
+
+static int get_affected_cpus(unsigned int cpu)
+{
+       struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
+       if (!cpus)
+               return -EINVAL;
+
+       while (cpus->next) {
+               printf("%d ", cpus->cpu);
+               cpus = cpus->next;
+       }
+       printf("%d\n", cpus->cpu);
+       cpufreq_put_affected_cpus(cpus);
+       return 0;
+}
+
+/* --related-cpus  / -r */
+
+static int get_related_cpus(unsigned int cpu)
+{
+       struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
+       if (!cpus)
+               return -EINVAL;
+
+       while (cpus->next) {
+               printf("%d ", cpus->cpu);
+               cpus = cpus->next;
+       }
+       printf("%d\n", cpus->cpu);
+       cpufreq_put_related_cpus(cpus);
+       return 0;
+}
+
+/* --stats / -s */
+
+static int get_freq_stats(unsigned int cpu, unsigned int human)
+{
+       unsigned long total_trans = cpufreq_get_transitions(cpu);
+       unsigned long long total_time;
+       struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
+       while (stats) {
+               if (human) {
+                       print_speed(stats->frequency);
+                       printf(":%.2f%%",
+                               (100.0 * stats->time_in_state) / total_time);
+               } else
+                       printf("%lu:%llu",
+                               stats->frequency, stats->time_in_state);
+               stats = stats->next;
+               if (stats)
+                       printf(", ");
+       }
+       cpufreq_put_stats(stats);
+       if (total_trans)
+               printf("  (%lu)\n", total_trans);
+       return 0;
+}
+
+/* --latency / -y */
+
+static int get_latency(unsigned int cpu, unsigned int human)
+{
+       unsigned long latency = cpufreq_get_transition_latency(cpu);
+       if (!latency)
+               return -EINVAL;
+
+       if (human) {
+               print_duration(latency);
+               printf("\n");
+       } else
+               printf("%lu\n", latency);
+       return 0;
+}
+
+void freq_info_help(void)
+{
+       printf(_("Usage: cpupower freqinfo [options]\n"));
+       printf(_("Options:\n"));
+       printf(_("  -e, --debug          Prints out debug information [default]\n"));
+       printf(_("  -f, --freq           Get frequency the CPU currently runs at, according\n"
+              "                       to the cpufreq core *\n"));
+       printf(_("  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n"
+              "                       it from hardware (only available to root) *\n"));
+       printf(_("  -l, --hwlimits       Determine the minimum and maximum CPU frequency allowed *\n"));
+       printf(_("  -d, --driver         Determines the used cpufreq kernel driver *\n"));
+       printf(_("  -p, --policy         Gets the currently used cpufreq policy *\n"));
+       printf(_("  -g, --governors      Determines available cpufreq governors *\n"));
+       printf(_("  -r, --related-cpus   Determines which CPUs run at the same hardware frequency *\n"));
+       printf(_("  -a, --affected-cpus  Determines which CPUs need to have their frequency\n"
+                       "                       coordinated by software *\n"));
+       printf(_("  -s, --stats          Shows cpufreq statistics if available\n"));
+       printf(_("  -y, --latency        Determines the maximum latency on CPU frequency changes *\n"));
+       printf(_("  -b, --boost          Checks for turbo or boost modes  *\n"));
+       printf(_("  -o, --proc           Prints out information like provided by the /proc/cpufreq\n"
+              "                       interface in 2.4. and early 2.6. kernels\n"));
+       printf(_("  -m, --human          human-readable output for the -f, -w, -s and -y parameters\n"));
+       printf(_("  -h, --help           Prints out this screen\n"));
+
+       printf("\n");
+       printf(_("If no argument is given, full output about\n"
+              "cpufreq is printed which is useful e.g. for reporting bugs.\n\n"));
+       printf(_("By default info of CPU 0 is shown which can be overridden\n"
+                "with the cpupower --cpu main command option.\n"));
+}
+
+static struct option info_opts[] = {
+       { .name = "debug",      .has_arg = no_argument,         .flag = NULL,   .val = 'e'},
+       { .name = "boost",      .has_arg = no_argument,         .flag = NULL,   .val = 'b'},
+       { .name = "freq",       .has_arg = no_argument,         .flag = NULL,   .val = 'f'},
+       { .name = "hwfreq",     .has_arg = no_argument,         .flag = NULL,   .val = 'w'},
+       { .name = "hwlimits",   .has_arg = no_argument,         .flag = NULL,   .val = 'l'},
+       { .name = "driver",     .has_arg = no_argument,         .flag = NULL,   .val = 'd'},
+       { .name = "policy",     .has_arg = no_argument,         .flag = NULL,   .val = 'p'},
+       { .name = "governors",  .has_arg = no_argument,         .flag = NULL,   .val = 'g'},
+       { .name = "related-cpus", .has_arg = no_argument,       .flag = NULL,   .val = 'r'},
+       { .name = "affected-cpus",.has_arg = no_argument,       .flag = NULL,   .val = 'a'},
+       { .name = "stats",      .has_arg = no_argument,         .flag = NULL,   .val = 's'},
+       { .name = "latency",    .has_arg = no_argument,         .flag = NULL,   .val = 'y'},
+       { .name = "proc",       .has_arg = no_argument,         .flag = NULL,   .val = 'o'},
+       { .name = "human",      .has_arg = no_argument,         .flag = NULL,   .val = 'm'},
+       { .name = "help",       .has_arg = no_argument,         .flag = NULL,   .val = 'h'},
+       { },
+};
+
+int cmd_freq_info(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       int ret = 0, cont = 1;
+       unsigned int cpu = 0;
+       unsigned int human = 0;
+       int output_param = 0;
+
+       do {
+               ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL);
+               switch (ret) {
+               case '?':
+                       output_param = '?';
+                       cont = 0;
+                       break;
+               case 'h':
+                       output_param = 'h';
+                       cont = 0;
+                       break;
+               case -1:
+                       cont = 0;
+                       break;
+               case 'b':
+               case 'o':
+               case 'a':
+               case 'r':
+               case 'g':
+               case 'p':
+               case 'd':
+               case 'l':
+               case 'w':
+               case 'f':
+               case 'e':
+               case 's':
+               case 'y':
+                       if (output_param) {
+                               output_param = -1;
+                               cont = 0;
+                               break;
+                       }
+                       output_param = ret;
+                       break;
+               case 'm':
+                       if (human) {
+                               output_param = -1;
+                               cont = 0;
+                               break;
+                       }
+                       human = 1;
+                       break;
+               default:
+                       fprintf(stderr, "invalid or unknown argument\n");
+                       return EXIT_FAILURE;
+               }
+       } while (cont);
+
+       switch (output_param) {
+       case 'o':
+               if (!bitmask_isallclear(cpus_chosen)) {
+                       printf(_("The argument passed to this tool can't be "
+                                "combined with passing a --cpu argument\n"));
+                       return -EINVAL;
+               }
+               break;
+       case 0:
+               output_param = 'e';
+       }
+
+       ret = 0;
+
+       /* Default is: show output of CPU 0 only */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setbit(cpus_chosen, 0);
+
+       switch (output_param) {
+       case -1:
+               printf(_("You can't specify more than one --cpu parameter and/or\n"
+                      "more than one output-specific argument\n"));
+               return -EINVAL;
+       case '?':
+               printf(_("invalid or unknown argument\n"));
+               freq_info_help();
+               return -EINVAL;
+       case 'h':
+               freq_info_help();
+               return EXIT_SUCCESS;
+       case 'o':
+               proc_cpufreq_output();
+               return EXIT_SUCCESS;
+       }
+
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu))
+                       continue;
+               if (cpufreq_cpu_exists(cpu)) {
+                       printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu);
+                       continue;
+               }
+               printf(_("analyzing CPU %d:\n"), cpu);
+
+               switch (output_param) {
+               case 'b':
+                       get_boost_mode(cpu);
+                       break;
+               case 'e':
+                       debug_output_one(cpu);
+                       break;
+               case 'a':
+                       ret = get_affected_cpus(cpu);
+                       break;
+               case 'r':
+                       ret = get_related_cpus(cpu);
+                       break;
+               case 'g':
+                       ret = get_available_governors(cpu);
+                       break;
+               case 'p':
+                       ret = get_policy(cpu);
+                       break;
+               case 'd':
+                       ret = get_driver(cpu);
+                       break;
+               case 'l':
+                       ret = get_hardware_limits(cpu);
+                       break;
+               case 'w':
+                       ret = get_freq_hardware(cpu, human);
+                       break;
+               case 'f':
+                       ret = get_freq_kernel(cpu, human);
+                       break;
+               case 's':
+                       ret = get_freq_stats(cpu, human);
+                       break;
+               case 'y':
+                       ret = get_latency(cpu, human);
+                       break;
+               }
+               if (ret)
+                       return ret;
+       }
+       return ret;
+}
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
new file mode 100644 (file)
index 0000000..5f78362
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <getopt.h>
+
+#include "cpufreq.h"
+#include "helpers/helpers.h"
+
+#define NORM_FREQ_LEN 32
+
+void freq_set_help(void)
+{
+       printf(_("Usage: cpupower frequency-set [options]\n"));
+       printf(_("Options:\n"));
+       printf(_("  -d FREQ, --min FREQ      new minimum CPU frequency the governor may select\n"));
+       printf(_("  -u FREQ, --max FREQ      new maximum CPU frequency the governor may select\n"));
+       printf(_("  -g GOV, --governor GOV   new cpufreq governor\n"));
+       printf(_("  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
+              "                           governor to be available and loaded\n"));
+       printf(_("  -r, --related            Switches all hardware-related CPUs\n"));
+       printf(_("  -h, --help               Prints out this screen\n"));
+       printf("\n");
+       printf(_("Notes:\n"
+              "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"));
+       printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n"
+              "   except the -c CPU, --cpu CPU parameter\n"
+              "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+              "   by postfixing the value with the wanted unit name, without any space\n"
+              "   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"));
+
+}
+
+static struct option set_opts[] = {
+       { .name = "min",        .has_arg = required_argument,   .flag = NULL,   .val = 'd'},
+       { .name = "max",        .has_arg = required_argument,   .flag = NULL,   .val = 'u'},
+       { .name = "governor",   .has_arg = required_argument,   .flag = NULL,   .val = 'g'},
+       { .name = "freq",       .has_arg = required_argument,   .flag = NULL,   .val = 'f'},
+       { .name = "help",       .has_arg = no_argument,         .flag = NULL,   .val = 'h'},
+       { .name = "related",    .has_arg = no_argument,         .flag = NULL,   .val='r'},
+       { },
+};
+
+static void print_error(void)
+{
+       printf(_("Error setting new values. Common errors:\n"
+                       "- Do you have proper administration rights? (super-user?)\n"
+                       "- Is the governor you requested available and modprobed?\n"
+                       "- Trying to set an invalid policy?\n"
+                       "- Trying to set a specific frequency, but userspace governor is not available,\n"
+                       "   for example because of hardware which cannot be set to a specific frequency\n"
+                       "   or because the userspace governor isn't loaded?\n"));
+};
+
+struct freq_units {
+       char            *str_unit;
+       int             power_of_ten;
+};
+
+const struct freq_units def_units[] = {
+       {"hz", -3},
+       {"khz", 0}, /* default */
+       {"mhz", 3},
+       {"ghz", 6},
+       {"thz", 9},
+       {NULL, 0}
+};
+
+static void print_unknown_arg(void)
+{
+       printf(_("invalid or unknown argument\n"));
+       freq_set_help();
+}
+
+static unsigned long string_to_frequency(const char *str)
+{
+       char normalized[NORM_FREQ_LEN];
+       const struct freq_units *unit;
+       const char *scan;
+       char *end;
+       unsigned long freq;
+       int power = 0, match_count = 0, i, cp, pad;
+
+       while (*str == '0')
+               str++;
+
+       for (scan = str; isdigit(*scan) || *scan == '.'; scan++) {
+               if (*scan == '.' && match_count == 0)
+                       match_count = 1;
+               else if (*scan == '.' && match_count == 1)
+                       return 0;
+       }
+
+       if (*scan) {
+               match_count = 0;
+               for (unit = def_units; unit->str_unit; unit++) {
+                       for (i = 0;
+                            scan[i] && tolower(scan[i]) == unit->str_unit[i];
+                            ++i)
+                               continue;
+                       if (scan[i])
+                               continue;
+                       match_count++;
+                       power = unit->power_of_ten;
+               }
+               if (match_count != 1)
+                       return 0;
+       }
+
+       /* count the number of digits to be copied */
+       for (cp = 0; isdigit(str[cp]); cp++)
+               continue;
+
+       if (str[cp] == '.') {
+               while (power > -1 && isdigit(str[cp+1]))
+                       cp++, power--;
+       }
+       if (power >= -1)        /* not enough => pad */
+               pad = power + 1;
+       else                    /* to much => strip */
+               pad = 0, cp += power + 1;
+       /* check bounds */
+       if (cp <= 0 || cp + pad > NORM_FREQ_LEN - 1)
+               return 0;
+
+       /* copy digits */
+       for (i = 0; i < cp; i++, str++) {
+               if (*str == '.')
+                       str++;
+               normalized[i] = *str;
+       }
+       /* and pad */
+       for (; i < cp + pad; i++)
+               normalized[i] = '0';
+
+       /* round up, down ? */
+       match_count = (normalized[i-1] >= '5');
+       /* and drop the decimal part */
+       normalized[i-1] = 0; /* cp > 0 && pad >= 0 ==> i > 0 */
+
+       /* final conversion (and applying rounding) */
+       errno = 0;
+       freq = strtoul(normalized, &end, 10);
+       if (errno)
+               return 0;
+       else {
+               if (match_count && freq != ULONG_MAX)
+                       freq++;
+               return freq;
+       }
+}
+
+static int do_new_policy(unsigned int cpu, struct cpufreq_policy *new_pol)
+{
+       struct cpufreq_policy *cur_pol = cpufreq_get_policy(cpu);
+       int ret;
+
+       if (!cur_pol) {
+               printf(_("wrong, unknown or unhandled CPU?\n"));
+               return -EINVAL;
+       }
+
+       if (!new_pol->min)
+               new_pol->min = cur_pol->min;
+
+       if (!new_pol->max)
+               new_pol->max = cur_pol->max;
+
+       if (!new_pol->governor)
+               new_pol->governor = cur_pol->governor;
+
+       ret = cpufreq_set_policy(cpu, new_pol);
+
+       cpufreq_put_policy(cur_pol);
+
+       return ret;
+}
+
+
+static int do_one_cpu(unsigned int cpu, struct cpufreq_policy *new_pol,
+               unsigned long freq, unsigned int pc)
+{
+       switch (pc) {
+       case 0:
+               return cpufreq_set_frequency(cpu, freq);
+
+       case 1:
+               /* if only one value of a policy is to be changed, we can
+                * use a "fast path".
+                */
+               if (new_pol->min)
+                       return cpufreq_modify_policy_min(cpu, new_pol->min);
+               else if (new_pol->max)
+                       return cpufreq_modify_policy_max(cpu, new_pol->max);
+               else if (new_pol->governor)
+                       return cpufreq_modify_policy_governor(cpu,
+                                                       new_pol->governor);
+
+       default:
+               /* slow path */
+               return do_new_policy(cpu, new_pol);
+       }
+}
+
+int cmd_freq_set(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       int ret = 0, cont = 1;
+       int double_parm = 0, related = 0, policychange = 0;
+       unsigned long freq = 0;
+       char gov[20];
+       unsigned int cpu;
+
+       struct cpufreq_policy new_pol = {
+               .min = 0,
+               .max = 0,
+               .governor = NULL,
+       };
+
+       /* parameter parsing */
+       do {
+               ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL);
+               switch (ret) {
+               case '?':
+                       print_unknown_arg();
+                       return -EINVAL;
+               case 'h':
+                       freq_set_help();
+                       return 0;
+               case -1:
+                       cont = 0;
+                       break;
+               case 'r':
+                       if (related)
+                               double_parm++;
+                       related++;
+                       break;
+               case 'd':
+                       if (new_pol.min)
+                               double_parm++;
+                       policychange++;
+                       new_pol.min = string_to_frequency(optarg);
+                       if (new_pol.min == 0) {
+                               print_unknown_arg();
+                               return -EINVAL;
+                       }
+                       break;
+               case 'u':
+                       if (new_pol.max)
+                               double_parm++;
+                       policychange++;
+                       new_pol.max = string_to_frequency(optarg);
+                       if (new_pol.max == 0) {
+                               print_unknown_arg();
+                               return -EINVAL;
+                       }
+                       break;
+               case 'f':
+                       if (freq)
+                               double_parm++;
+                       freq = string_to_frequency(optarg);
+                       if (freq == 0) {
+                               print_unknown_arg();
+                               return -EINVAL;
+                       }
+                       break;
+               case 'g':
+                       if (new_pol.governor)
+                               double_parm++;
+                       policychange++;
+                       if ((strlen(optarg) < 3) || (strlen(optarg) > 18)) {
+                               print_unknown_arg();
+                               return -EINVAL;
+                       }
+                       if ((sscanf(optarg, "%s", gov)) != 1) {
+                               print_unknown_arg();
+                               return -EINVAL;
+                       }
+                       new_pol.governor = gov;
+                       break;
+               }
+       } while (cont);
+
+       /* parameter checking */
+       if (double_parm) {
+               printf("the same parameter was passed more than once\n");
+               return -EINVAL;
+       }
+
+       if (freq && policychange) {
+               printf(_("the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
+                               "-g/--governor parameters\n"));
+               return -EINVAL;
+       }
+
+       if (!freq && !policychange) {
+               printf(_("At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
+                               "-g/--governor must be passed\n"));
+               return -EINVAL;
+       }
+
+       /* Default is: set all CPUs */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setall(cpus_chosen);
+
+       /* Also set frequency settings for related CPUs if -r is passed */
+       if (related) {
+               for (cpu = bitmask_first(cpus_chosen);
+                    cpu <= bitmask_last(cpus_chosen); cpu++) {
+                       struct cpufreq_affected_cpus *cpus;
+
+                       if (!bitmask_isbitset(cpus_chosen, cpu) ||
+                           cpufreq_cpu_exists(cpu))
+                               continue;
+
+                       cpus = cpufreq_get_related_cpus(cpu);
+                       if (!cpus)
+                               break;
+                       while (cpus->next) {
+                               bitmask_setbit(cpus_chosen, cpus->cpu);
+                               cpus = cpus->next;
+                       }
+                       cpufreq_put_related_cpus(cpus);
+               }
+       }
+
+
+       /* loop over CPUs */
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu) ||
+                   cpufreq_cpu_exists(cpu))
+                       continue;
+
+               printf(_("Setting cpu: %d\n"), cpu);
+               ret = do_one_cpu(cpu, &new_pol, freq, policychange);
+               if (ret)
+                       break;
+       }
+
+       if (ret)
+               print_error();
+
+       return ret;
+}
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
new file mode 100644 (file)
index 0000000..70da357
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *  (C) 2010       Thomas Renninger <trenn@suse.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <cpufreq.h>
+
+#include "helpers/helpers.h"
+#include "helpers/sysfs.h"
+#include "helpers/bitmask.h"
+
+#define LINE_LEN 10
+
+static void cpuidle_cpu_output(unsigned int cpu, int verbose)
+{
+       int idlestates, idlestate;
+       char *tmp;
+
+       printf(_ ("Analyzing CPU %d:\n"), cpu);
+
+       idlestates = sysfs_get_idlestate_count(cpu);
+       if (idlestates == 0) {
+               printf(_("CPU %u: No idle states\n"), cpu);
+               return;
+       } else if (idlestates <= 0) {
+               printf(_("CPU %u: Can't read idle state info\n"), cpu);
+               return;
+       }
+       tmp = sysfs_get_idlestate_name(cpu, idlestates - 1);
+       if (!tmp) {
+               printf(_("Could not determine max idle state %u\n"),
+                      idlestates - 1);
+               return;
+       }
+
+       printf(_("Number of idle states: %d\n"), idlestates);
+
+       printf(_("Available idle states:"));
+       for (idlestate = 1; idlestate < idlestates; idlestate++) {
+               tmp = sysfs_get_idlestate_name(cpu, idlestate);
+               if (!tmp)
+                       continue;
+               printf(" %s", tmp);
+               free(tmp);
+       }
+       printf("\n");
+
+       if (!verbose)
+               return;
+
+       for (idlestate = 1; idlestate < idlestates; idlestate++) {
+               tmp = sysfs_get_idlestate_name(cpu, idlestate);
+               if (!tmp)
+                       continue;
+               printf("%s:\n", tmp);
+               free(tmp);
+
+               tmp = sysfs_get_idlestate_desc(cpu, idlestate);
+               if (!tmp)
+                       continue;
+               printf(_("Flags/Description: %s\n"), tmp);
+               free(tmp);
+
+               printf(_("Latency: %lu\n"),
+                      sysfs_get_idlestate_latency(cpu, idlestate));
+               printf(_("Usage: %lu\n"),
+                      sysfs_get_idlestate_usage(cpu, idlestate));
+               printf(_("Duration: %llu\n"),
+                      sysfs_get_idlestate_time(cpu, idlestate));
+       }
+       printf("\n");
+}
+
+static void cpuidle_general_output(void)
+{
+       char *tmp;
+
+       tmp = sysfs_get_cpuidle_driver();
+       if (!tmp) {
+               printf(_("Could not determine cpuidle driver\n"));
+               return;
+       }
+
+       printf(_("CPUidle driver: %s\n"), tmp);
+       free(tmp);
+
+       tmp = sysfs_get_cpuidle_governor();
+       if (!tmp) {
+               printf(_("Could not determine cpuidle governor\n"));
+               return;
+       }
+
+       printf(_("CPUidle governor: %s\n"), tmp);
+       free(tmp);
+}
+
+static void proc_cpuidle_cpu_output(unsigned int cpu)
+{
+       long max_allowed_cstate = 2000000000;
+       int cstates, cstate;
+
+       cstates = sysfs_get_idlestate_count(cpu);
+       if (cstates == 0) {
+               /*
+                * Go on and print same useless info as you'd see with
+                * cat /proc/acpi/processor/../power
+                *      printf(_("CPU %u: No C-states available\n"), cpu);
+                *      return;
+                */
+       } else if (cstates <= 0) {
+               printf(_("CPU %u: Can't read C-state info\n"), cpu);
+               return;
+       }
+       /* printf("Cstates: %d\n", cstates); */
+
+       printf(_("active state:            C0\n"));
+       printf(_("max_cstate:              C%u\n"), cstates-1);
+       printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate);
+       printf(_("states:\t\n"));
+       for (cstate = 1; cstate < cstates; cstate++) {
+               printf(_("    C%d:                  "
+                        "type[C%d] "), cstate, cstate);
+               printf(_("promotion[--] demotion[--] "));
+               printf(_("latency[%03lu] "),
+                      sysfs_get_idlestate_latency(cpu, cstate));
+               printf(_("usage[%08lu] "),
+                      sysfs_get_idlestate_usage(cpu, cstate));
+               printf(_("duration[%020Lu] \n"),
+                      sysfs_get_idlestate_time(cpu, cstate));
+       }
+}
+
+/* --freq / -f */
+
+void idle_info_help(void)
+{
+       printf(_ ("Usage: cpupower idleinfo [options]\n"));
+       printf(_ ("Options:\n"));
+       printf(_ ("  -s, --silent         Only show general C-state information\n"));
+       printf(_ ("  -o, --proc           Prints out information like provided by the /proc/acpi/processor/*/power\n"
+              "                       interface in older kernels\n"));
+       printf(_ ("  -h, --help           Prints out this screen\n"));
+
+       printf("\n");
+}
+
+static struct option info_opts[] = {
+       { .name = "silent",     .has_arg = no_argument, .flag = NULL,   .val = 's'},
+       { .name = "proc",       .has_arg = no_argument, .flag = NULL,   .val = 'o'},
+       { .name = "help",       .has_arg = no_argument, .flag = NULL,   .val = 'h'},
+       { },
+};
+
+static inline void cpuidle_exit(int fail)
+{
+       idle_info_help();
+       exit(EXIT_FAILURE);
+}
+
+int cmd_idle_info(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       int ret = 0, cont = 1, output_param = 0, verbose = 1;
+       unsigned int cpu = 0;
+
+       do {
+               ret = getopt_long(argc, argv, "hos", info_opts, NULL);
+               if (ret == -1)
+                       break;
+               switch (ret) {
+               case '?':
+                       output_param = '?';
+                       cont = 0;
+                       break;
+               case 'h':
+                       output_param = 'h';
+                       cont = 0;
+                       break;
+               case 's':
+                       verbose = 0;
+                       break;
+               case -1:
+                       cont = 0;
+                       break;
+               case 'o':
+                       if (output_param) {
+                               output_param = -1;
+                               cont = 0;
+                               break;
+                       }
+                       output_param = ret;
+                       break;
+               }
+       } while (cont);
+
+       switch (output_param) {
+       case -1:
+               printf(_("You can't specify more than one "
+                        "output-specific argument\n"));
+               cpuidle_exit(EXIT_FAILURE);
+       case '?':
+               printf(_("invalid or unknown argument\n"));
+               cpuidle_exit(EXIT_FAILURE);
+       case 'h':
+               cpuidle_exit(EXIT_SUCCESS);
+       }
+
+       /* Default is: show output of CPU 0 only */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setbit(cpus_chosen, 0);
+
+       if (output_param == 0)
+               cpuidle_general_output();
+
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu) ||
+                   cpufreq_cpu_exists(cpu))
+                       continue;
+
+               switch (output_param) {
+
+               case 'o':
+                       proc_cpuidle_cpu_output(cpu);
+                       break;
+               case 0:
+                       printf("\n");
+                       cpuidle_cpu_output(cpu, verbose);
+                       break;
+               }
+       }
+       return EXIT_SUCCESS;
+}
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
new file mode 100644 (file)
index 0000000..85253cb
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <cpufreq.h>
+#include "helpers/helpers.h"
+#include "helpers/sysfs.h"
+
+void info_help(void)
+{
+       printf(_("Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"));
+       printf(_("Options:\n"));
+       printf(_("  -b, --perf-bias    Gets CPU's power vs performance policy on some\n"
+              "                           Intel models [0-15], see manpage for details\n"));
+       printf(_("  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"));
+       printf(_("  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n"));
+       printf(_("  -h, --help               Prints out this screen\n"));
+       printf(_("\nPassing no option will show all info, by default only on core 0\n"));
+       printf("\n");
+}
+
+static struct option set_opts[] = {
+       { .name = "perf-bias",  .has_arg = optional_argument,   .flag = NULL,   .val = 'b'},
+       { .name = "sched-mc",   .has_arg = optional_argument,   .flag = NULL,   .val = 'm'},
+       { .name = "sched-smt",  .has_arg = optional_argument,   .flag = NULL,   .val = 's'},
+       { .name = "help",       .has_arg = no_argument,         .flag = NULL,   .val = 'h'},
+       { },
+};
+
+static void print_wrong_arg_exit(void)
+{
+       printf(_("invalid or unknown argument\n"));
+       info_help();
+       exit(EXIT_FAILURE);
+}
+
+int cmd_info(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       unsigned int cpu;
+
+       union {
+               struct {
+                       int sched_mc:1;
+                       int sched_smt:1;
+                       int perf_bias:1;
+               };
+               int params;
+       } params = {};
+       int ret = 0;
+
+       setlocale(LC_ALL, "");
+       textdomain(PACKAGE);
+
+       /* parameter parsing */
+       while ((ret = getopt_long(argc, argv, "msbh", set_opts, NULL)) != -1) {
+               switch (ret) {
+               case 'h':
+                       info_help();
+                       return 0;
+               case 'b':
+                       if (params.perf_bias)
+                               print_wrong_arg_exit();
+                       params.perf_bias = 1;
+                       break;
+               case 'm':
+                       if (params.sched_mc)
+                               print_wrong_arg_exit();
+                       params.sched_mc = 1;
+                       break;
+               case 's':
+                       if (params.sched_smt)
+                               print_wrong_arg_exit();
+                       params.sched_smt = 1;
+                       break;
+               default:
+                       print_wrong_arg_exit();
+               }
+       };
+
+       if (!params.params)
+               params.params = 0x7;
+
+       /* Default is: show output of CPU 0 only */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setbit(cpus_chosen, 0);
+
+       if (params.sched_mc) {
+               ret = sysfs_get_sched("mc");
+               printf(_("System's multi core scheduler setting: "));
+               if (ret < 0)
+                       /* if sysfs file is missing it's: errno == ENOENT */
+                       printf(_("not supported\n"));
+               else
+                       printf("%d\n", ret);
+       }
+       if (params.sched_smt) {
+               ret = sysfs_get_sched("smt");
+               printf(_("System's thread sibling scheduler setting: "));
+               if (ret < 0)
+                       /* if sysfs file is missing it's: errno == ENOENT */
+                       printf(_("not supported\n"));
+               else
+                       printf("%d\n", ret);
+       }
+
+       /* Add more per cpu options here */
+       if (!params.perf_bias)
+               return ret;
+
+       if (params.perf_bias) {
+               if (!run_as_root) {
+                       params.perf_bias = 0;
+                       printf(_("Intel's performance bias setting needs root privileges\n"));
+               } else if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) {
+                       printf(_("System does not support Intel's performance"
+                                " bias setting\n"));
+                       params.perf_bias = 0;
+               }
+       }
+
+       /* loop over CPUs */
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu) ||
+                   cpufreq_cpu_exists(cpu))
+                       continue;
+
+               printf(_("analyzing CPU %d:\n"), cpu);
+
+               if (params.perf_bias) {
+                       ret = msr_intel_get_perf_bias(cpu);
+                       if (ret < 0) {
+                               printf(_("Could not read perf-bias value\n"));
+                               break;
+                       } else
+                               printf(_("perf-bias: %d\n"), ret);
+               }
+       }
+       return ret;
+}
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c
new file mode 100644 (file)
index 0000000..bc1b391
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <cpufreq.h>
+#include "helpers/helpers.h"
+#include "helpers/sysfs.h"
+#include "helpers/bitmask.h"
+
+void set_help(void)
+{
+       printf(_("Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"));
+       printf(_("Options:\n"));
+       printf(_("  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n"
+              "                           Intel models [0-15], see manpage for details\n"));
+       printf(_("  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"));
+       printf(_("  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler policy.\n"));
+       printf(_("  -h, --help               Prints out this screen\n"));
+       printf("\n");
+}
+
+static struct option set_opts[] = {
+       { .name = "perf-bias",  .has_arg = optional_argument,   .flag = NULL,   .val = 'b'},
+       { .name = "sched-mc",   .has_arg = optional_argument,   .flag = NULL,   .val = 'm'},
+       { .name = "sched-smt",  .has_arg = optional_argument,   .flag = NULL,   .val = 's'},
+       { .name = "help",       .has_arg = no_argument,         .flag = NULL,   .val = 'h'},
+       { },
+};
+
+static void print_wrong_arg_exit(void)
+{
+       printf(_("invalid or unknown argument\n"));
+       set_help();
+       exit(EXIT_FAILURE);
+}
+
+int cmd_set(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind, opterr, optopt;
+       unsigned int cpu;
+
+       union {
+               struct {
+                       int sched_mc:1;
+                       int sched_smt:1;
+                       int perf_bias:1;
+               };
+               int params;
+       } params;
+       int sched_mc = 0, sched_smt = 0, perf_bias = 0;
+       int ret = 0;
+
+       setlocale(LC_ALL, "");
+       textdomain(PACKAGE);
+
+       params.params = 0;
+       /* parameter parsing */
+       while ((ret = getopt_long(argc, argv, "m:s:b:h",
+                                               set_opts, NULL)) != -1) {
+               switch (ret) {
+               case 'h':
+                       set_help();
+                       return 0;
+               case 'b':
+                       if (params.perf_bias)
+                               print_wrong_arg_exit();
+                       perf_bias = atoi(optarg);
+                       if (perf_bias < 0 || perf_bias > 15) {
+                               printf(_("--perf-bias param out "
+                                        "of range [0-%d]\n"), 15);
+                               print_wrong_arg_exit();
+                       }
+                       params.perf_bias = 1;
+                       break;
+               case 'm':
+                       if (params.sched_mc)
+                               print_wrong_arg_exit();
+                       sched_mc = atoi(optarg);
+                       if (sched_mc < 0 || sched_mc > 2) {
+                               printf(_("--sched-mc param out "
+                                        "of range [0-%d]\n"), 2);
+                               print_wrong_arg_exit();
+                       }
+                       params.sched_mc = 1;
+                       break;
+               case 's':
+                       if (params.sched_smt)
+                               print_wrong_arg_exit();
+                       sched_smt = atoi(optarg);
+                       if (sched_smt < 0 || sched_smt > 2) {
+                               printf(_("--sched-smt param out "
+                                        "of range [0-%d]\n"), 2);
+                               print_wrong_arg_exit();
+                       }
+                       params.sched_smt = 1;
+                       break;
+               default:
+                       print_wrong_arg_exit();
+               }
+       };
+
+       if (!params.params) {
+               set_help();
+               return -EINVAL;
+       }
+
+       if (params.sched_mc) {
+               ret = sysfs_set_sched("mc", sched_mc);
+               if (ret)
+                       fprintf(stderr, _("Error setting sched-mc %s\n"),
+                               (ret == -ENODEV) ? "not supported" : "");
+       }
+       if (params.sched_smt) {
+               ret = sysfs_set_sched("smt", sched_smt);
+               if (ret)
+                       fprintf(stderr, _("Error setting sched-smt %s\n"),
+                               (ret == -ENODEV) ? "not supported" : "");
+       }
+
+       /* Default is: set all CPUs */
+       if (bitmask_isallclear(cpus_chosen))
+               bitmask_setall(cpus_chosen);
+
+       /* loop over CPUs */
+       for (cpu = bitmask_first(cpus_chosen);
+            cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+               if (!bitmask_isbitset(cpus_chosen, cpu) ||
+                   cpufreq_cpu_exists(cpu))
+                       continue;
+
+               if (params.perf_bias) {
+                       ret = msr_intel_set_perf_bias(cpu, perf_bias);
+                       if (ret) {
+                               fprintf(stderr, _("Error setting perf-bias "
+                                                 "value on CPU %d\n"), cpu);
+                               break;
+                       }
+               }
+       }
+       return ret;
+}
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
new file mode 100644 (file)
index 0000000..5844ae0
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Ideas taken over from the perf userspace tool (included in the Linus
+ *  kernel git repo): subcommand builtins and param parsing.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "builtin.h"
+#include "helpers/helpers.h"
+#include "helpers/bitmask.h"
+
+struct cmd_struct {
+       const char *cmd;
+       int (*main)(int, const char **);
+       void (*usage)(void);
+       int needs_root;
+};
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+int cmd_help(int argc, const char **argv);
+
+/* Global cpu_info object available for all binaries
+ * Info only retrieved from CPU 0
+ *
+ * Values will be zero/unknown on non X86 archs
+ */
+struct cpupower_cpu_info cpupower_cpu_info;
+int run_as_root;
+/* Affected cpus chosen by -c/--cpu param */
+struct bitmask *cpus_chosen;
+
+#ifdef DEBUG
+int be_verbose;
+#endif
+
+static void print_help(void);
+
+static struct cmd_struct commands[] = {
+       { "frequency-info",     cmd_freq_info,  freq_info_help, 0       },
+       { "frequency-set",      cmd_freq_set,   freq_set_help,  1       },
+       { "idle-info",          cmd_idle_info,  idle_info_help, 0       },
+       { "set",                cmd_set,        set_help,       1       },
+       { "info",               cmd_info,       info_help,      0       },
+       { "monitor",            cmd_monitor,    monitor_help,   0       },
+       { "help",               cmd_help,       print_help,     0       },
+       /*      { "bench",      cmd_bench,      NULL,           1       }, */
+};
+
+int cmd_help(int argc, const char **argv)
+{
+       unsigned int i;
+
+       if (argc > 1) {
+               for (i = 0; i < ARRAY_SIZE(commands); i++) {
+                       struct cmd_struct *p = commands + i;
+                       if (strcmp(p->cmd, argv[1]))
+                               continue;
+                       if (p->usage) {
+                               p->usage();
+                               return EXIT_SUCCESS;
+                       }
+               }
+       }
+       print_help();
+       if (argc == 1)
+               return EXIT_SUCCESS; /* cpupower help */
+       return EXIT_FAILURE;
+}
+
+static void print_help(void)
+{
+       unsigned int i;
+
+#ifdef DEBUG
+       printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n"));
+       printf(_("  -d, --debug      May increase output (stderr) on some subcommands\n"));
+#else
+       printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n"));
+#endif
+       printf(_("cpupower --version\n"));
+       printf(_("Supported subcommands are:\n"));
+       for (i = 0; i < ARRAY_SIZE(commands); i++)
+               printf("\t%s\n", commands[i].cmd);
+       printf(_("\nSome subcommands can make use of the -c cpulist option.\n"));
+       printf(_("Look at the general cpupower manpage how to use it\n"));
+       printf(_("and read up the subcommand's manpage whether it is supported.\n"));
+       printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n"));
+}
+
+static void print_version(void)
+{
+       printf(PACKAGE " " VERSION "\n");
+       printf(_("Report errors and bugs to %s, please.\n"), PACKAGE_BUGREPORT);
+}
+
+static void handle_options(int *argc, const char ***argv)
+{
+       int ret, x, new_argc = 0;
+
+       if (*argc < 1)
+               return;
+
+       for (x = 0;  x < *argc && ((*argv)[x])[0] == '-'; x++) {
+               const char *param = (*argv)[x];
+               if (!strcmp(param, "-h") || !strcmp(param, "--help")) {
+                       print_help();
+                       exit(EXIT_SUCCESS);
+               } else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")) {
+                       if (*argc < 2) {
+                               print_help();
+                               exit(EXIT_FAILURE);
+                       }
+                       if (!strcmp((*argv)[x+1], "all"))
+                               bitmask_setall(cpus_chosen);
+                       else {
+                               ret = bitmask_parselist(
+                                               (*argv)[x+1], cpus_chosen);
+                               if (ret < 0) {
+                                       fprintf(stderr, _("Error parsing cpu "
+                                                         "list\n"));
+                                       exit(EXIT_FAILURE);
+                               }
+                       }
+                       x += 1;
+                       /* Cut out param: cpupower -c 1 info -> cpupower info */
+                       new_argc += 2;
+                       continue;
+               } else if (!strcmp(param, "-v") ||
+                       !strcmp(param, "--version")) {
+                       print_version();
+                       exit(EXIT_SUCCESS);
+#ifdef DEBUG
+               } else if (!strcmp(param, "-d") || !strcmp(param, "--debug")) {
+                       be_verbose = 1;
+                       new_argc++;
+                       continue;
+#endif
+               } else {
+                       fprintf(stderr, "Unknown option: %s\n", param);
+                       print_help();
+                       exit(EXIT_FAILURE);
+               }
+       }
+       *argc -= new_argc;
+       *argv += new_argc;
+}
+
+int main(int argc, const char *argv[])
+{
+       const char *cmd;
+       unsigned int i, ret;
+
+       cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF));
+
+       argc--;
+       argv += 1;
+
+       handle_options(&argc, &argv);
+
+       cmd = argv[0];
+
+       if (argc < 1) {
+               print_help();
+               return EXIT_FAILURE;
+       }
+
+       setlocale(LC_ALL, "");
+       textdomain(PACKAGE);
+
+       /* Turn "perf cmd --help" into "perf help cmd" */
+       if (argc > 1 && !strcmp(argv[1], "--help")) {
+               argv[1] = argv[0];
+               argv[0] = cmd = "help";
+       }
+
+       get_cpu_info(0, &cpupower_cpu_info);
+       run_as_root = !getuid();
+
+       for (i = 0; i < ARRAY_SIZE(commands); i++) {
+               struct cmd_struct *p = commands + i;
+               if (strcmp(p->cmd, cmd))
+                       continue;
+               if (!run_as_root && p->needs_root) {
+                       fprintf(stderr, _("Subcommand %s needs root "
+                                         "privileges\n"), cmd);
+                       return EXIT_FAILURE;
+               }
+               ret = p->main(argc, argv);
+               if (cpus_chosen)
+                       bitmask_free(cpus_chosen);
+               return ret;
+       }
+       print_help();
+       return EXIT_FAILURE;
+}
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
new file mode 100644 (file)
index 0000000..87d5605
--- /dev/null
@@ -0,0 +1,137 @@
+#if defined(__i386__) || defined(__x86_64__)
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include <pci/pci.h>
+
+#include "helpers/helpers.h"
+
+#define MSR_AMD_PSTATE_STATUS  0xc0010063
+#define MSR_AMD_PSTATE         0xc0010064
+#define MSR_AMD_PSTATE_LIMIT   0xc0010061
+
+union msr_pstate {
+       struct {
+               unsigned fid:6;
+               unsigned did:3;
+               unsigned vid:7;
+               unsigned res1:6;
+               unsigned nbdid:1;
+               unsigned res2:2;
+               unsigned nbvid:7;
+               unsigned iddval:8;
+               unsigned idddiv:2;
+               unsigned res3:21;
+               unsigned en:1;
+       } bits;
+       unsigned long long val;
+};
+
+static int get_did(int family, union msr_pstate pstate)
+{
+       int t;
+
+       if (family == 0x12)
+               t = pstate.val & 0xf;
+       else
+               t = pstate.bits.did;
+
+       return t;
+}
+
+static int get_cof(int family, union msr_pstate pstate)
+{
+       int t;
+       int fid, did;
+
+       did = get_did(family, pstate);
+
+       t = 0x10;
+       fid = pstate.bits.fid;
+       if (family == 0x11)
+               t = 0x8;
+
+       return (100 * (fid + t)) >> did;
+}
+
+/* Needs:
+ * cpu          -> the cpu that gets evaluated
+ * cpu_family   -> The cpu's family (0x10, 0x12,...)
+ * boots_states -> how much boost states the machines support
+ *
+ * Fills up:
+ * pstates -> a pointer to an array of size MAX_HW_PSTATES
+ *            must be initialized with zeros.
+ *            All available  HW pstates (including boost states)
+ * no      -> amount of pstates above array got filled up with
+ *
+ * returns zero on success, -1 on failure
+ */
+int decode_pstates(unsigned int cpu, unsigned int cpu_family,
+                  int boost_states, unsigned long *pstates, int *no)
+{
+       int i, psmax, pscur;
+       union msr_pstate pstate;
+       unsigned long long val;
+
+       /* Only read out frequencies from HW when CPU might be boostable
+          to keep the code as short and clean as possible.
+          Otherwise frequencies are exported via ACPI tables.
+       */
+       if (cpu_family < 0x10 || cpu_family == 0x14)
+               return -1;
+
+       if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val))
+               return -1;
+
+       psmax = (val >> 4) & 0x7;
+
+       if (read_msr(cpu, MSR_AMD_PSTATE_STATUS, &val))
+               return -1;
+
+       pscur = val & 0x7;
+
+       pscur += boost_states;
+       psmax += boost_states;
+       for (i = 0; i <= psmax; i++) {
+               if (i >= MAX_HW_PSTATES) {
+                       fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n",
+                               psmax, MAX_HW_PSTATES);
+                       return -1;
+               }
+               if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
+                       return -1;
+               pstates[i] = get_cof(cpu_family, pstate);
+       }
+       *no = i;
+       return 0;
+}
+
+int amd_pci_get_num_boost_states(int *active, int *states)
+{
+       struct pci_access *pci_acc;
+       int vendor_id = 0x1022;
+       int boost_dev_ids[4] = {0x1204, 0x1604, 0x1704, 0};
+       struct pci_dev *device;
+       uint8_t val = 0;
+
+       *active = *states = 0;
+
+       device = pci_acc_init(&pci_acc, vendor_id, boost_dev_ids);
+
+       if (device == NULL)
+               return -ENODEV;
+
+       val = pci_read_byte(device, 0x15c);
+       if (val & 3)
+               *active = 1;
+       else
+               *active = 0;
+       *states = (val >> 2) & 7;
+
+       pci_cleanup(pci_acc);
+       return 0;
+}
+#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/bitmask.c b/tools/power/cpupower/utils/helpers/bitmask.c
new file mode 100644 (file)
index 0000000..5c074c6
--- /dev/null
@@ -0,0 +1,292 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <helpers/bitmask.h>
+
+/* How many bits in an unsigned long */
+#define bitsperlong (8 * sizeof(unsigned long))
+
+/* howmany(a,b) : how many elements of size b needed to hold all of a */
+#define howmany(x, y) (((x)+((y)-1))/(y))
+
+/* How many longs in mask of n bits */
+#define longsperbits(n) howmany(n, bitsperlong)
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+/*
+ * Allocate and free `struct bitmask *`
+ */
+
+/* Allocate a new `struct bitmask` with a size of n bits */
+struct bitmask *bitmask_alloc(unsigned int n)
+{
+       struct bitmask *bmp;
+
+       bmp = malloc(sizeof(*bmp));
+       if (bmp == 0)
+               return 0;
+       bmp->size = n;
+       bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long));
+       if (bmp->maskp == 0) {
+               free(bmp);
+               return 0;
+       }
+       return bmp;
+}
+
+/* Free `struct bitmask` */
+void bitmask_free(struct bitmask *bmp)
+{
+       if (bmp == 0)
+               return;
+       free(bmp->maskp);
+       bmp->maskp = (unsigned long *)0xdeadcdef;  /* double free tripwire */
+       free(bmp);
+}
+
+/*
+ * The routines _getbit() and _setbit() are the only
+ * routines that actually understand the layout of bmp->maskp[].
+ *
+ * On little endian architectures, this could simply be an array of
+ * bytes.  But the kernel layout of bitmasks _is_ visible to userspace
+ * via the sched_(set/get)affinity calls in Linux 2.6, and on big
+ * endian architectures, it is painfully obvious that this is an
+ * array of unsigned longs.
+ */
+
+/* Return the value (0 or 1) of bit n in bitmask bmp */
+static unsigned int _getbit(const struct bitmask *bmp, unsigned int n)
+{
+       if (n < bmp->size)
+               return (bmp->maskp[n/bitsperlong] >> (n % bitsperlong)) & 1;
+       else
+               return 0;
+}
+
+/* Set bit n in bitmask bmp to value v (0 or 1) */
+static void _setbit(struct bitmask *bmp, unsigned int n, unsigned int v)
+{
+       if (n < bmp->size) {
+               if (v)
+                       bmp->maskp[n/bitsperlong] |= 1UL << (n % bitsperlong);
+               else
+                       bmp->maskp[n/bitsperlong] &=
+                               ~(1UL << (n % bitsperlong));
+       }
+}
+
+/*
+ * When parsing bitmask lists, only allow numbers, separated by one
+ * of the allowed next characters.
+ *
+ * The parameter 'sret' is the return from a sscanf "%u%c".  It is
+ * -1 if the sscanf input string was empty.  It is 0 if the first
+ * character in the sscanf input string was not a decimal number.
+ * It is 1 if the unsigned number matching the "%u" was the end of the
+ * input string.  It is 2 if one or more additional characters followed
+ * the matched unsigned number.  If it is 2, then 'nextc' is the first
+ * character following the number.  The parameter 'ok_next_chars'
+ * is the nul-terminated list of allowed next characters.
+ *
+ * The mask term just scanned was ok if and only if either the numbers
+ * matching the %u were all of the input or if the next character in
+ * the input past the numbers was one of the allowed next characters.
+ */
+static int scan_was_ok(int sret, char nextc, const char *ok_next_chars)
+{
+       return sret == 1 ||
+               (sret == 2 && strchr(ok_next_chars, nextc) != NULL);
+}
+
+static const char *nexttoken(const char *q,  int sep)
+{
+       if (q)
+               q = strchr(q, sep);
+       if (q)
+               q++;
+       return q;
+}
+
+/* Set a single bit i in bitmask */
+struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i)
+{
+       _setbit(bmp, i, 1);
+       return bmp;
+}
+
+/* Set all bits in bitmask: bmp = ~0 */
+struct bitmask *bitmask_setall(struct bitmask *bmp)
+{
+       unsigned int i;
+       for (i = 0; i < bmp->size; i++)
+               _setbit(bmp, i, 1);
+       return bmp;
+}
+
+/* Clear all bits in bitmask: bmp = 0 */
+struct bitmask *bitmask_clearall(struct bitmask *bmp)
+{
+       unsigned int i;
+       for (i = 0; i < bmp->size; i++)
+               _setbit(bmp, i, 0);
+       return bmp;
+}
+
+/* True if all bits are clear */
+int bitmask_isallclear(const struct bitmask *bmp)
+{
+       unsigned int i;
+       for (i = 0; i < bmp->size; i++)
+               if (_getbit(bmp, i))
+                       return 0;
+       return 1;
+}
+
+/* True if specified bit i is set */
+int bitmask_isbitset(const struct bitmask *bmp, unsigned int i)
+{
+       return _getbit(bmp, i);
+}
+
+/* Number of lowest set bit (min) */
+unsigned int bitmask_first(const struct bitmask *bmp)
+{
+       return bitmask_next(bmp, 0);
+}
+
+/* Number of highest set bit (max) */
+unsigned int bitmask_last(const struct bitmask *bmp)
+{
+       unsigned int i;
+       unsigned int m = bmp->size;
+       for (i = 0; i < bmp->size; i++)
+               if (_getbit(bmp, i))
+                       m = i;
+       return m;
+}
+
+/* Number of next set bit at or above given bit i */
+unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i)
+{
+       unsigned int n;
+       for (n = i; n < bmp->size; n++)
+               if (_getbit(bmp, n))
+                       break;
+       return n;
+}
+
+/*
+ * Parses a comma-separated list of numbers and ranges of numbers,
+ * with optional ':%u' strides modifying ranges, into provided bitmask.
+ * Some examples of input lists and their equivalent simple list:
+ *     Input           Equivalent to
+ *     0-3             0,1,2,3
+ *     0-7:2           0,2,4,6
+ *     1,3,5-7         1,3,5,6,7
+ *     0-3:2,8-15:4    0,2,8,12
+ */
+int bitmask_parselist(const char *buf, struct bitmask *bmp)
+{
+       const char *p, *q;
+
+       bitmask_clearall(bmp);
+
+       q = buf;
+       while (p = q, q = nexttoken(q, ','), p) {
+               unsigned int a;         /* begin of range */
+               unsigned int b;         /* end of range */
+               unsigned int s;         /* stride */
+               const char *c1, *c2;    /* next tokens after '-' or ',' */
+               char nextc;             /* char after sscanf %u match */
+               int sret;               /* sscanf return (number of matches) */
+
+               sret = sscanf(p, "%u%c", &a, &nextc);
+               if (!scan_was_ok(sret, nextc, ",-"))
+                       goto err;
+               b = a;
+               s = 1;
+               c1 = nexttoken(p, '-');
+               c2 = nexttoken(p, ',');
+               if (c1 != NULL && (c2 == NULL || c1 < c2)) {
+                       sret = sscanf(c1, "%u%c", &b, &nextc);
+                       if (!scan_was_ok(sret, nextc, ",:"))
+                               goto err;
+                       c1 = nexttoken(c1, ':');
+                       if (c1 != NULL && (c2 == NULL || c1 < c2)) {
+                               sret = sscanf(c1, "%u%c", &s, &nextc);
+                               if (!scan_was_ok(sret, nextc, ","))
+                                       goto err;
+                       }
+               }
+               if (!(a <= b))
+                       goto err;
+               if (b >= bmp->size)
+                       goto err;
+               while (a <= b) {
+                       _setbit(bmp, a, 1);
+                       a += s;
+               }
+       }
+       return 0;
+err:
+       bitmask_clearall(bmp);
+       return -1;
+}
+
+/*
+ * emit(buf, buflen, rbot, rtop, len)
+ *
+ * Helper routine for bitmask_displaylist().  Write decimal number
+ * or range to buf+len, suppressing output past buf+buflen, with optional
+ * comma-prefix.  Return len of what would be written to buf, if it
+ * all fit.
+ */
+
+static inline int emit(char *buf, int buflen, int rbot, int rtop, int len)
+{
+       if (len > 0)
+               len += snprintf(buf + len, max(buflen - len, 0), ",");
+       if (rbot == rtop)
+               len += snprintf(buf + len, max(buflen - len, 0), "%d", rbot);
+       else
+               len += snprintf(buf + len, max(buflen - len, 0), "%d-%d",
+                               rbot, rtop);
+       return len;
+}
+
+/*
+ * Write decimal list representation of bmp to buf.
+ *
+ * Output format is a comma-separated list of decimal numbers and
+ * ranges.  Consecutively set bits are shown as two hyphen-separated
+ * decimal numbers, the smallest and largest bit numbers set in
+ * the range.  Output format is compatible with the format
+ * accepted as input by bitmap_parselist().
+ *
+ * The return value is the number of characters which would be
+ * generated for the given input, excluding the trailing '\0', as
+ * per ISO C99.
+ */
+
+int bitmask_displaylist(char *buf, int buflen, const struct bitmask *bmp)
+{
+       int len = 0;
+       /* current bit is 'cur', most recently seen range is [rbot, rtop] */
+       unsigned int cur, rbot, rtop;
+
+       if (buflen > 0)
+               *buf = 0;
+       rbot = cur = bitmask_first(bmp);
+       while (cur < bmp->size) {
+               rtop = cur;
+               cur = bitmask_next(bmp, cur+1);
+               if (cur >= bmp->size || cur > rtop + 1) {
+                       len = emit(buf, buflen, rbot, rtop, len);
+                       rbot = cur;
+               }
+       }
+       return len;
+}
diff --git a/tools/power/cpupower/utils/helpers/bitmask.h b/tools/power/cpupower/utils/helpers/bitmask.h
new file mode 100644 (file)
index 0000000..eb289df
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __CPUPOWER_BITMASK__
+#define __CPUPOWER_BITMASK__
+
+/* Taken over from libbitmask, a project initiated from sgi:
+ * Url:            http://oss.sgi.com/projects/cpusets/
+ * Unfortunately it's not very widespread, therefore relevant parts are
+ * pasted here.
+ */
+
+struct bitmask {
+       unsigned int size;
+       unsigned long *maskp;
+};
+
+struct bitmask *bitmask_alloc(unsigned int n);
+void bitmask_free(struct bitmask *bmp);
+
+struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i);
+struct bitmask *bitmask_setall(struct bitmask *bmp);
+struct bitmask *bitmask_clearall(struct bitmask *bmp);
+
+unsigned int bitmask_first(const struct bitmask *bmp);
+unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i);
+unsigned int bitmask_last(const struct bitmask *bmp);
+int bitmask_isallclear(const struct bitmask *bmp);
+int bitmask_isbitset(const struct bitmask *bmp, unsigned int i);
+
+int bitmask_parselist(const char *buf, struct bitmask *bmp);
+int bitmask_displaylist(char *buf, int len, const struct bitmask *bmp);
+
+
+
+#endif /*__CPUPOWER_BITMASK__ */
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c
new file mode 100644 (file)
index 0000000..906895d
--- /dev/null
@@ -0,0 +1,176 @@
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "helpers/helpers.h"
+
+static const char *cpu_vendor_table[X86_VENDOR_MAX] = {
+       "Unknown", "GenuineIntel", "AuthenticAMD",
+};
+
+#if defined(__i386__) || defined(__x86_64__)
+
+/* from gcc */
+#include <cpuid.h>
+
+/*
+ * CPUID functions returning a single datum
+ *
+ * Define unsigned int cpuid_e[abcd]x(unsigned int op)
+ */
+#define cpuid_func(reg)                                        \
+       unsigned int cpuid_##reg(unsigned int op)       \
+       {                                               \
+       unsigned int eax, ebx, ecx, edx;                \
+       __cpuid(op, eax, ebx, ecx, edx);                \
+       return reg;                                     \
+       }
+cpuid_func(eax);
+cpuid_func(ebx);
+cpuid_func(ecx);
+cpuid_func(edx);
+
+#endif /* defined(__i386__) || defined(__x86_64__) */
+
+/* get_cpu_info
+ *
+ * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
+ *
+ * Returns 0 on success or a negativ error code
+ *
+ * TBD: Should there be a cpuid alternative for this if /proc is not mounted?
+ */
+int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info)
+{
+       FILE *fp;
+       char value[64];
+       unsigned int proc, x;
+       unsigned int unknown = 0xffffff;
+       unsigned int cpuid_level, ext_cpuid_level;
+
+       int ret = -EINVAL;
+
+       cpu_info->vendor                = X86_VENDOR_UNKNOWN;
+       cpu_info->family                = unknown;
+       cpu_info->model                 = unknown;
+       cpu_info->stepping              = unknown;
+       cpu_info->caps                  = 0;
+
+       fp = fopen("/proc/cpuinfo", "r");
+       if (!fp)
+               return -EIO;
+
+       while (!feof(fp)) {
+               if (!fgets(value, 64, fp))
+                       continue;
+               value[63 - 1] = '\0';
+
+               if (!strncmp(value, "processor\t: ", 12))
+                       sscanf(value, "processor\t: %u", &proc);
+
+               if (proc != cpu)
+                       continue;
+
+               /* Get CPU vendor */
+               if (!strncmp(value, "vendor_id", 9)) {
+                       for (x = 1; x < X86_VENDOR_MAX; x++) {
+                               if (strstr(value, cpu_vendor_table[x]))
+                                       cpu_info->vendor = x;
+                       }
+               /* Get CPU family, etc. */
+               } else if (!strncmp(value, "cpu family\t: ", 13)) {
+                       sscanf(value, "cpu family\t: %u",
+                              &cpu_info->family);
+               } else if (!strncmp(value, "model\t\t: ", 9)) {
+                       sscanf(value, "model\t\t: %u",
+                              &cpu_info->model);
+               } else if (!strncmp(value, "stepping\t: ", 10)) {
+                       sscanf(value, "stepping\t: %u",
+                              &cpu_info->stepping);
+
+                       /* Exit -> all values must have been set */
+                       if (cpu_info->vendor == X86_VENDOR_UNKNOWN ||
+                           cpu_info->family == unknown ||
+                           cpu_info->model == unknown ||
+                           cpu_info->stepping == unknown) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       ret = 0;
+                       goto out;
+               }
+       }
+       ret = -ENODEV;
+out:
+       fclose(fp);
+       /* Get some useful CPU capabilities from cpuid */
+       if (cpu_info->vendor != X86_VENDOR_AMD &&
+           cpu_info->vendor != X86_VENDOR_INTEL)
+               return ret;
+
+       cpuid_level     = cpuid_eax(0);
+       ext_cpuid_level = cpuid_eax(0x80000000);
+
+       /* Invariant TSC */
+       if (ext_cpuid_level >= 0x80000007 &&
+           (cpuid_edx(0x80000007) & (1 << 8)))
+               cpu_info->caps |= CPUPOWER_CAP_INV_TSC;
+
+       /* Aperf/Mperf registers support */
+       if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))
+               cpu_info->caps |= CPUPOWER_CAP_APERF;
+
+       /* AMD Boost state enable/disable register */
+       if (cpu_info->vendor == X86_VENDOR_AMD) {
+               if (ext_cpuid_level >= 0x80000007 &&
+                   (cpuid_edx(0x80000007) & (1 << 9)))
+                       cpu_info->caps |= CPUPOWER_CAP_AMD_CBP;
+       }
+
+       if (cpu_info->vendor == X86_VENDOR_INTEL) {
+               if (cpuid_level >= 6 &&
+                   (cpuid_eax(6) & (1 << 1)))
+                       cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA;
+       }
+
+       if (cpu_info->vendor == X86_VENDOR_INTEL) {
+               /* Intel's perf-bias MSR support */
+               if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
+                       cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
+
+               /* Intel's Turbo Ratio Limit support */
+               if (cpu_info->family == 6) {
+                       switch (cpu_info->model) {
+                       case 0x1A:      /* Core i7, Xeon 5500 series
+                                        * Bloomfield, Gainstown NHM-EP
+                                        */
+                       case 0x1E:      /* Core i7 and i5 Processor
+                                        * Clarksfield, Lynnfield, Jasper Forest
+                                        */
+                       case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
+                       case 0x25:      /* Westmere Client
+                                        * Clarkdale, Arrandale
+                                        */
+                       case 0x2C:      /* Westmere EP - Gulftown */
+                               cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
+                       case 0x2A:      /* SNB */
+                       case 0x2D:      /* SNB Xeon */
+                               cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
+                               cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
+                               break;
+                       case 0x2E:      /* Nehalem-EX Xeon - Beckton */
+                       case 0x2F:      /* Westmere-EX Xeon - Eagleton */
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       /*      printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
+               cpuid_level, ext_cpuid_level, cpu_info->caps);
+       */
+       return ret;
+}
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
new file mode 100644 (file)
index 0000000..592ee36
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ * Miscellaneous helpers which do not fit or are worth
+ * to put into separate headers
+ */
+
+#ifndef __CPUPOWERUTILS_HELPERS__
+#define __CPUPOWERUTILS_HELPERS__
+
+#include <libintl.h>
+#include <locale.h>
+
+#include "helpers/bitmask.h"
+
+/* Internationalization ****************************/
+#define _(String) gettext(String)
+#ifndef gettext_noop
+#define gettext_noop(String) String
+#endif
+#define N_(String) gettext_noop(String)
+/* Internationalization ****************************/
+
+extern int run_as_root;
+extern struct bitmask *cpus_chosen;
+
+/* Global verbose (-d) stuff *********************************/
+/*
+ * define DEBUG via global Makefile variable
+ * Debug output is sent to stderr, do:
+ * cpupower monitor 2>/tmp/debug
+ * to split debug output away from normal output
+*/
+#ifdef DEBUG
+extern int be_verbose;
+
+#define dprint(fmt, ...) {                                     \
+               if (be_verbose) {                               \
+                       fprintf(stderr, "%s: " fmt,             \
+                               __func__, ##__VA_ARGS__);       \
+               }                                               \
+       }
+#else
+static inline void dprint(const char *fmt, ...) { }
+#endif
+extern int be_verbose;
+/* Global verbose (-v) stuff *********************************/
+
+/* cpuid and cpuinfo helpers  **************************/
+enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL,
+                         X86_VENDOR_AMD, X86_VENDOR_MAX};
+
+#define CPUPOWER_CAP_INV_TSC           0x00000001
+#define CPUPOWER_CAP_APERF             0x00000002
+#define CPUPOWER_CAP_AMD_CBP           0x00000004
+#define CPUPOWER_CAP_PERF_BIAS         0x00000008
+#define CPUPOWER_CAP_HAS_TURBO_RATIO   0x00000010
+#define CPUPOWER_CAP_IS_SNB            0x00000011
+#define CPUPOWER_CAP_INTEL_IDA         0x00000012
+
+#define MAX_HW_PSTATES 10
+
+struct cpupower_cpu_info {
+       enum cpupower_cpu_vendor vendor;
+       unsigned int family;
+       unsigned int model;
+       unsigned int stepping;
+       /* CPU capabilities read out from cpuid */
+       unsigned long long caps;
+};
+
+/* get_cpu_info
+ *
+ * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
+ *
+ * Returns 0 on success or a negativ error code
+ * Only used on x86, below global's struct values are zero/unknown on
+ * other archs
+ */
+extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info);
+extern struct cpupower_cpu_info cpupower_cpu_info;
+/* cpuid and cpuinfo helpers  **************************/
+
+
+/* CPU topology/hierarchy parsing ******************/
+struct cpupower_topology {
+       /* Amount of CPU cores, packages and threads per core in the system */
+       unsigned int cores;
+       unsigned int pkgs;
+       unsigned int threads; /* per core */
+
+       /* Array gets mallocated with cores entries, holding per core info */
+       struct {
+               int pkg;
+               int core;
+               int cpu;
+       } *core_info;
+};
+
+extern int get_cpu_topology(struct cpupower_topology *cpu_top);
+extern void cpu_topology_release(struct cpupower_topology cpu_top);
+/* CPU topology/hierarchy parsing ******************/
+
+/* X86 ONLY ****************************************/
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <pci/pci.h>
+
+/* Read/Write msr ****************************/
+extern int read_msr(int cpu, unsigned int idx, unsigned long long *val);
+extern int write_msr(int cpu, unsigned int idx, unsigned long long val);
+
+extern int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val);
+extern int msr_intel_get_perf_bias(unsigned int cpu);
+extern unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu);
+
+/* Read/Write msr ****************************/
+
+/* PCI stuff ****************************/
+extern int amd_pci_get_num_boost_states(int *active, int *states);
+extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
+                                   int *dev_ids);
+
+/* PCI stuff ****************************/
+
+/* AMD HW pstate decoding **************************/
+
+extern int decode_pstates(unsigned int cpu, unsigned int cpu_family,
+                         int boost_states, unsigned long *pstates, int *no);
+
+/* AMD HW pstate decoding **************************/
+
+extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
+                                    int *active, int * states);
+/*
+ * CPUID functions returning a single datum
+ */
+unsigned int cpuid_eax(unsigned int op);
+unsigned int cpuid_ebx(unsigned int op);
+unsigned int cpuid_ecx(unsigned int op);
+unsigned int cpuid_edx(unsigned int op);
+
+/* cpuid and cpuinfo helpers  **************************/
+/* X86 ONLY ********************************************/
+#else
+static inline int decode_pstates(unsigned int cpu, unsigned int cpu_family,
+                                int boost_states, unsigned long *pstates,
+                                int *no)
+{ return -1; };
+
+static inline int read_msr(int cpu, unsigned int idx, unsigned long long *val)
+{ return -1; };
+static inline int write_msr(int cpu, unsigned int idx, unsigned long long val)
+{ return -1; };
+static inline int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val)
+{ return -1; };
+static inline int msr_intel_get_perf_bias(unsigned int cpu)
+{ return -1; };
+static inline unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu)
+{ return 0; };
+
+/* Read/Write msr ****************************/
+
+static inline int cpufreq_has_boost_support(unsigned int cpu, int *support,
+                                           int *active, int * states)
+{ return -1; }
+
+/* cpuid and cpuinfo helpers  **************************/
+
+static inline unsigned int cpuid_eax(unsigned int op) { return 0; };
+static inline unsigned int cpuid_ebx(unsigned int op) { return 0; };
+static inline unsigned int cpuid_ecx(unsigned int op) { return 0; };
+static inline unsigned int cpuid_edx(unsigned int op) { return 0; };
+#endif /* defined(__i386__) || defined(__x86_64__) */
+
+#endif /* __CPUPOWERUTILS_HELPERS__ */
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c
new file mode 100644 (file)
index 0000000..1609243
--- /dev/null
@@ -0,0 +1,27 @@
+#if defined(__i386__) || defined(__x86_64__)
+
+#include "helpers/helpers.h"
+
+int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active,
+                       int *states)
+{
+       struct cpupower_cpu_info cpu_info;
+       int ret;
+
+       *support = *active = *states = 0;
+
+       ret = get_cpu_info(0, &cpu_info);
+       if (ret)
+               return ret;
+
+       if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CBP) {
+               *support = 1;
+               amd_pci_get_num_boost_states(active, states);
+               if (ret <= 0)
+                       return ret;
+               *support = 1;
+       } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA)
+               *support = *active = 1;
+       return 0;
+}
+#endif /* #if defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/msr.c b/tools/power/cpupower/utils/helpers/msr.c
new file mode 100644 (file)
index 0000000..31a4b24
--- /dev/null
@@ -0,0 +1,115 @@
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "helpers/helpers.h"
+
+/* Intel specific MSRs */
+#define MSR_IA32_PERF_STATUS           0x198
+#define MSR_IA32_MISC_ENABLES          0x1a0
+#define MSR_IA32_ENERGY_PERF_BIAS      0x1b0
+#define MSR_NEHALEM_TURBO_RATIO_LIMIT  0x1ad
+
+/*
+ * read_msr
+ *
+ * Will return 0 on success and -1 on failure.
+ * Possible errno values could be:
+ * EFAULT -If the read/write did not fully complete
+ * EIO    -If the CPU does not support MSRs
+ * ENXIO  -If the CPU does not exist
+ */
+
+int read_msr(int cpu, unsigned int idx, unsigned long long *val)
+{
+       int fd;
+       char msr_file_name[64];
+
+       sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
+       fd = open(msr_file_name, O_RDONLY);
+       if (fd < 0)
+               return -1;
+       if (lseek(fd, idx, SEEK_CUR) == -1)
+               goto err;
+       if (read(fd, val, sizeof *val) != sizeof *val)
+               goto err;
+       close(fd);
+       return 0;
+ err:
+       close(fd);
+       return -1;
+}
+
+/*
+ * write_msr
+ *
+ * Will return 0 on success and -1 on failure.
+ * Possible errno values could be:
+ * EFAULT -If the read/write did not fully complete
+ * EIO    -If the CPU does not support MSRs
+ * ENXIO  -If the CPU does not exist
+ */
+int write_msr(int cpu, unsigned int idx, unsigned long long val)
+{
+       int fd;
+       char msr_file_name[64];
+
+       sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
+       fd = open(msr_file_name, O_WRONLY);
+       if (fd < 0)
+               return -1;
+       if (lseek(fd, idx, SEEK_CUR) == -1)
+               goto err;
+       if (write(fd, &val, sizeof val) != sizeof val)
+               goto err;
+       close(fd);
+       return 0;
+ err:
+       close(fd);
+       return -1;
+}
+
+int msr_intel_get_perf_bias(unsigned int cpu)
+{
+       unsigned long long val;
+       int ret;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
+               return -1;
+
+       ret = read_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &val);
+       if (ret)
+               return ret;
+       return val;
+}
+
+int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val)
+{
+       int ret;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
+               return -1;
+
+       ret = write_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, val);
+       if (ret)
+               return ret;
+       return 0;
+}
+
+unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu)
+{
+       unsigned long long val;
+       int ret;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO))
+               return -1;
+
+       ret = read_msr(cpu, MSR_NEHALEM_TURBO_RATIO_LIMIT, &val);
+       if (ret)
+               return ret;
+       return val;
+}
+#endif
diff --git a/tools/power/cpupower/utils/helpers/pci.c b/tools/power/cpupower/utils/helpers/pci.c
new file mode 100644 (file)
index 0000000..cd2eb6f
--- /dev/null
@@ -0,0 +1,44 @@
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <helpers/helpers.h>
+
+/*
+ * pci_acc_init
+ *
+ * PCI access helper function depending on libpci
+ *
+ * **pacc : if a valid pci_dev is returned
+ *         *pacc must be passed to pci_acc_cleanup to free it
+ *
+ * vendor_id : the pci vendor id matching the pci device to access
+ * dev_ids :   device ids matching the pci device to access
+ *
+ * Returns :
+ * struct pci_dev which can be used with pci_{read,write}_* functions
+ *                to access the PCI config space of matching pci devices
+ */
+struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
+                                   int *dev_ids)
+{
+       struct pci_filter filter_nb_link = { -1, -1, -1, -1, vendor_id, 0};
+       struct pci_dev *device;
+       unsigned int i;
+
+       *pacc = pci_alloc();
+       if (*pacc == NULL)
+               return NULL;
+
+       pci_init(*pacc);
+       pci_scan_bus(*pacc);
+
+       for (i = 0; dev_ids[i] != 0; i++) {
+               filter_nb_link.device = dev_ids[i];
+               for (device = (*pacc)->devices; device; device = device->next) {
+                       if (pci_filter_match(&filter_nb_link, device))
+                               return device;
+               }
+       }
+       pci_cleanup(*pacc);
+       return NULL;
+}
+#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
new file mode 100644 (file)
index 0000000..55e2466
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
+ *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "helpers/sysfs.h"
+
+unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
+{
+       int fd;
+       ssize_t numread;
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1)
+               return 0;
+
+       numread = read(fd, buf, buflen - 1);
+       if (numread < 1) {
+               close(fd);
+               return 0;
+       }
+
+       buf[numread] = '\0';
+       close(fd);
+
+       return (unsigned int) numread;
+}
+
+static unsigned int sysfs_write_file(const char *path,
+                                    const char *value, size_t len)
+{
+       int fd;
+       ssize_t numwrite;
+
+       fd = open(path, O_WRONLY);
+       if (fd == -1)
+               return 0;
+
+       numwrite = write(fd, value, len);
+       if (numwrite < 1) {
+               close(fd);
+               return 0;
+       }
+       close(fd);
+       return (unsigned int) numwrite;
+}
+
+/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
+
+/*
+ * helper function to read file from /sys into given buffer
+ * fname is a relative path under "cpuX/cpuidle/stateX/" dir
+ * cstates starting with 0, C0 is not counted as cstate.
+ * This means if you want C1 info, pass 0 as idlestate param
+ */
+unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
+                            const char *fname, char *buf, size_t buflen)
+{
+       char path[SYSFS_PATH_MAX];
+       int fd;
+       ssize_t numread;
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
+                cpu, idlestate, fname);
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1)
+               return 0;
+
+       numread = read(fd, buf, buflen - 1);
+       if (numread < 1) {
+               close(fd);
+               return 0;
+       }
+
+       buf[numread] = '\0';
+       close(fd);
+
+       return (unsigned int) numread;
+}
+
+/* read access to files which contain one numeric value */
+
+enum idlestate_value {
+       IDLESTATE_USAGE,
+       IDLESTATE_POWER,
+       IDLESTATE_LATENCY,
+       IDLESTATE_TIME,
+       MAX_IDLESTATE_VALUE_FILES
+};
+
+static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
+       [IDLESTATE_USAGE] = "usage",
+       [IDLESTATE_POWER] = "power",
+       [IDLESTATE_LATENCY] = "latency",
+       [IDLESTATE_TIME]  = "time",
+};
+
+static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
+                                                    unsigned int idlestate,
+                                                    enum idlestate_value which)
+{
+       unsigned long long value;
+       unsigned int len;
+       char linebuf[MAX_LINE_LEN];
+       char *endp;
+
+       if (which >= MAX_IDLESTATE_VALUE_FILES)
+               return 0;
+
+       len = sysfs_idlestate_read_file(cpu, idlestate,
+                                       idlestate_value_files[which],
+                                       linebuf, sizeof(linebuf));
+       if (len == 0)
+               return 0;
+
+       value = strtoull(linebuf, &endp, 0);
+
+       if (endp == linebuf || errno == ERANGE)
+               return 0;
+
+       return value;
+}
+
+/* read access to files which contain one string */
+
+enum idlestate_string {
+       IDLESTATE_DESC,
+       IDLESTATE_NAME,
+       MAX_IDLESTATE_STRING_FILES
+};
+
+static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
+       [IDLESTATE_DESC] = "desc",
+       [IDLESTATE_NAME] = "name",
+};
+
+
+static char *sysfs_idlestate_get_one_string(unsigned int cpu,
+                                       unsigned int idlestate,
+                                       enum idlestate_string which)
+{
+       char linebuf[MAX_LINE_LEN];
+       char *result;
+       unsigned int len;
+
+       if (which >= MAX_IDLESTATE_STRING_FILES)
+               return NULL;
+
+       len = sysfs_idlestate_read_file(cpu, idlestate,
+                                       idlestate_string_files[which],
+                                       linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       result = strdup(linebuf);
+       if (result == NULL)
+               return NULL;
+
+       if (result[strlen(result) - 1] == '\n')
+               result[strlen(result) - 1] = '\0';
+
+       return result;
+}
+
+unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
+                                       unsigned int idlestate)
+{
+       return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
+}
+
+unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
+                                       unsigned int idlestate)
+{
+       return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
+}
+
+unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
+                                       unsigned int idlestate)
+{
+       return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
+}
+
+char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
+{
+       return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
+}
+
+char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
+{
+       return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
+}
+
+/*
+ * Returns number of supported C-states of CPU core cpu
+ * Negativ in error case
+ * Zero if cpuidle does not export any C-states
+ */
+int sysfs_get_idlestate_count(unsigned int cpu)
+{
+       char file[SYSFS_PATH_MAX];
+       struct stat statbuf;
+       int idlestates = 1;
+
+
+       snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
+       if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
+               return -ENODEV;
+
+       snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
+       if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
+               return 0;
+
+       while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
+               snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
+                        "cpu%u/cpuidle/state%d", cpu, idlestates);
+               idlestates++;
+       }
+       idlestates--;
+       return idlestates;
+}
+
+/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
+
+/*
+ * helper function to read file from /sys into given buffer
+ * fname is a relative path under "cpu/cpuidle/" dir
+ */
+static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
+                                           size_t buflen)
+{
+       char path[SYSFS_PATH_MAX];
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
+
+       return sysfs_read_file(path, buf, buflen);
+}
+
+
+
+/* read access to files which contain one string */
+
+enum cpuidle_string {
+       CPUIDLE_GOVERNOR,
+       CPUIDLE_GOVERNOR_RO,
+       CPUIDLE_DRIVER,
+       MAX_CPUIDLE_STRING_FILES
+};
+
+static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
+       [CPUIDLE_GOVERNOR]      = "current_governor",
+       [CPUIDLE_GOVERNOR_RO]   = "current_governor_ro",
+       [CPUIDLE_DRIVER]        = "current_driver",
+};
+
+
+static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
+{
+       char linebuf[MAX_LINE_LEN];
+       char *result;
+       unsigned int len;
+
+       if (which >= MAX_CPUIDLE_STRING_FILES)
+               return NULL;
+
+       len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
+                               linebuf, sizeof(linebuf));
+       if (len == 0)
+               return NULL;
+
+       result = strdup(linebuf);
+       if (result == NULL)
+               return NULL;
+
+       if (result[strlen(result) - 1] == '\n')
+               result[strlen(result) - 1] = '\0';
+
+       return result;
+}
+
+char *sysfs_get_cpuidle_governor(void)
+{
+       char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
+       if (!tmp)
+               return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
+       else
+               return tmp;
+}
+
+char *sysfs_get_cpuidle_driver(void)
+{
+       return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
+}
+/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
+
+/*
+ * Get sched_mc or sched_smt settings
+ * Pass "mc" or "smt" as argument
+ *
+ * Returns negative value on failure
+ */
+int sysfs_get_sched(const char *smt_mc)
+{
+       unsigned long value;
+       char linebuf[MAX_LINE_LEN];
+       char *endp;
+       char path[SYSFS_PATH_MAX];
+
+       if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
+               return -EINVAL;
+
+       snprintf(path, sizeof(path),
+               PATH_TO_CPU "sched_%s_power_savings", smt_mc);
+       if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
+               return -1;
+       value = strtoul(linebuf, &endp, 0);
+       if (endp == linebuf || errno == ERANGE)
+               return -1;
+       return value;
+}
+
+/*
+ * Get sched_mc or sched_smt settings
+ * Pass "mc" or "smt" as argument
+ *
+ * Returns negative value on failure
+ */
+int sysfs_set_sched(const char *smt_mc, int val)
+{
+       char linebuf[MAX_LINE_LEN];
+       char path[SYSFS_PATH_MAX];
+       struct stat statbuf;
+
+       if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
+               return -EINVAL;
+
+       snprintf(path, sizeof(path),
+               PATH_TO_CPU "sched_%s_power_savings", smt_mc);
+       sprintf(linebuf, "%d", val);
+
+       if (stat(path, &statbuf) != 0)
+               return -ENODEV;
+
+       if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0)
+               return -1;
+       return 0;
+}
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h
new file mode 100644 (file)
index 0000000..f9373e0
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __CPUPOWER_HELPERS_SYSFS_H__
+#define __CPUPOWER_HELPERS_SYSFS_H__
+
+#define PATH_TO_CPU "/sys/devices/system/cpu/"
+#define MAX_LINE_LEN 255
+#define SYSFS_PATH_MAX 255
+
+extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
+
+extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
+                                               unsigned int idlestate);
+extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
+                                       unsigned int idlestate);
+extern unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
+                                               unsigned int idlestate);
+extern char *sysfs_get_idlestate_name(unsigned int cpu,
+                               unsigned int idlestate);
+extern char *sysfs_get_idlestate_desc(unsigned int cpu,
+                               unsigned int idlestate);
+extern int sysfs_get_idlestate_count(unsigned int cpu);
+
+extern char *sysfs_get_cpuidle_governor(void);
+extern char *sysfs_get_cpuidle_driver(void);
+
+extern int sysfs_get_sched(const char *smt_mc);
+extern int sysfs_set_sched(const char *smt_mc, int val);
+
+#endif /* __CPUPOWER_HELPERS_SYSFS_H__ */
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
new file mode 100644 (file)
index 0000000..385ee5c
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ * ToDo: Needs to be done more properly for AMD/Intel specifics
+ */
+
+/* Helper struct for qsort, must be in sync with cpupower_topology.cpu_info */
+/* Be careful: Need to pass unsigned to the sort, so that offlined cores are
+   in the end, but double check for -1 for offlined cpus at other places */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <helpers/helpers.h>
+#include <helpers/sysfs.h>
+
+/* returns -1 on failure, 0 on success */
+int sysfs_topology_read_file(unsigned int cpu, const char *fname)
+{
+       unsigned long value;
+       char linebuf[MAX_LINE_LEN];
+       char *endp;
+       char path[SYSFS_PATH_MAX];
+
+       snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
+                        cpu, fname);
+       if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
+               return -1;
+       value = strtoul(linebuf, &endp, 0);
+       if (endp == linebuf || errno == ERANGE)
+               return -1;
+       return value;
+}
+
+struct cpuid_core_info {
+       unsigned int pkg;
+       unsigned int thread;
+       unsigned int cpu;
+};
+
+static int __compare(const void *t1, const void *t2)
+{
+       struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
+       struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
+       if (top1->pkg < top2->pkg)
+               return -1;
+       else if (top1->pkg > top2->pkg)
+               return 1;
+       else if (top1->thread < top2->thread)
+               return -1;
+       else if (top1->thread > top2->thread)
+               return 1;
+       else if (top1->cpu < top2->cpu)
+               return -1;
+       else if (top1->cpu > top2->cpu)
+               return 1;
+       else
+               return 0;
+}
+
+/*
+ * Returns amount of cpus, negative on error, cpu_top must be
+ * passed to cpu_topology_release to free resources
+ *
+ * Array is sorted after ->pkg, ->core, then ->cpu
+ */
+int get_cpu_topology(struct cpupower_topology *cpu_top)
+{
+       int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF);
+
+       cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus);
+       if (cpu_top->core_info == NULL)
+               return -ENOMEM;
+       cpu_top->pkgs = cpu_top->cores = 0;
+       for (cpu = 0; cpu < cpus; cpu++) {
+               cpu_top->core_info[cpu].pkg =
+                       sysfs_topology_read_file(cpu, "physical_package_id");
+               if ((int)cpu_top->core_info[cpu].pkg != -1 &&
+                   cpu_top->core_info[cpu].pkg > cpu_top->pkgs)
+                       cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
+               cpu_top->core_info[cpu].core =
+                       sysfs_topology_read_file(cpu, "core_id");
+               cpu_top->core_info[cpu].cpu = cpu;
+       }
+       cpu_top->pkgs++;
+
+       qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
+             __compare);
+
+       /* Intel's cores count is not consecutively numbered, there may
+        * be a core_id of 3, but none of 2. Assume there always is 0
+        * Get amount of cores by counting duplicates in a package
+       for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) {
+               if (cpu_top->core_info[cpu].core == 0)
+       cpu_top->cores++;
+       */
+       return cpus;
+}
+
+void cpu_topology_release(struct cpupower_topology cpu_top)
+{
+       free(cpu_top.core_info);
+}
diff --git a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
new file mode 100644 (file)
index 0000000..202e555
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ *  (C) 2010,2011      Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  PCI initialization based on example code from:
+ *  Andreas Herrmann <andreas.herrmann3@amd.com>
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <time.h>
+#include <string.h>
+
+#include <pci/pci.h>
+
+#include "idle_monitor/cpupower-monitor.h"
+#include "helpers/helpers.h"
+
+/******** PCI parts could go into own file and get shared ***************/
+
+#define PCI_NON_PC0_OFFSET     0xb0
+#define PCI_PC1_OFFSET         0xb4
+#define PCI_PC6_OFFSET         0xb8
+
+#define PCI_MONITOR_ENABLE_REG  0xe0
+
+#define PCI_NON_PC0_ENABLE_BIT 0
+#define PCI_PC1_ENABLE_BIT     1
+#define PCI_PC6_ENABLE_BIT     2
+
+#define PCI_NBP1_STAT_OFFSET   0x98
+#define PCI_NBP1_ACTIVE_BIT    2
+#define PCI_NBP1_ENTERED_BIT   1
+
+#define PCI_NBP1_CAP_OFFSET    0x90
+#define PCI_NBP1_CAPABLE_BIT    31
+
+#define OVERFLOW_MS            343597 /* 32 bit register filled at 12500 HZ
+                                         (1 tick per 80ns) */
+
+enum amd_fam14h_states {NON_PC0 = 0, PC1, PC6, NBP1,
+                       AMD_FAM14H_STATE_NUM};
+
+static int fam14h_get_count_percent(unsigned int self_id, double *percent,
+                                   unsigned int cpu);
+static int fam14h_nbp1_count(unsigned int id, unsigned long long *count,
+                            unsigned int cpu);
+
+static cstate_t amd_fam14h_cstates[AMD_FAM14H_STATE_NUM] = {
+       {
+               .name                   = "!PC0",
+               .desc                   = N_("Package in sleep state (PC1 or deeper)"),
+               .id                     = NON_PC0,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = fam14h_get_count_percent,
+       },
+       {
+               .name                   = "PC1",
+               .desc                   = N_("Processor Package C1"),
+               .id                     = PC1,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = fam14h_get_count_percent,
+       },
+       {
+               .name                   = "PC6",
+               .desc                   = N_("Processor Package C6"),
+               .id                     = PC6,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = fam14h_get_count_percent,
+       },
+       {
+               .name                   = "NBP1",
+               .desc                   = N_("North Bridge P1 boolean counter (returns 0 or 1)"),
+               .id                     = NBP1,
+               .range                  = RANGE_PACKAGE,
+               .get_count              = fam14h_nbp1_count,
+       },
+};
+
+static struct pci_access *pci_acc;
+static int pci_vendor_id = 0x1022;
+static int pci_dev_ids[2] = {0x1716, 0};
+static struct pci_dev *amd_fam14h_pci_dev;
+
+static int nbp1_entered;
+
+struct timespec start_time;
+static unsigned long long timediff;
+
+#ifdef DEBUG
+struct timespec dbg_time;
+long dbg_timediff;
+#endif
+
+static unsigned long long *previous_count[AMD_FAM14H_STATE_NUM];
+static unsigned long long *current_count[AMD_FAM14H_STATE_NUM];
+
+static int amd_fam14h_get_pci_info(struct cstate *state,
+                                  unsigned int *pci_offset,
+                                  unsigned int *enable_bit,
+                                  unsigned int cpu)
+{
+       switch (state->id) {
+       case NON_PC0:
+               *enable_bit = PCI_NON_PC0_ENABLE_BIT;
+               *pci_offset = PCI_NON_PC0_OFFSET;
+               break;
+       case PC1:
+               *enable_bit = PCI_PC1_ENABLE_BIT;
+               *pci_offset = PCI_PC1_OFFSET;
+               break;
+       case PC6:
+               *enable_bit = PCI_PC6_ENABLE_BIT;
+               *pci_offset = PCI_PC6_OFFSET;
+               break;
+       case NBP1:
+               *enable_bit = PCI_NBP1_ENTERED_BIT;
+               *pci_offset = PCI_NBP1_STAT_OFFSET;
+               break;
+       default:
+               return -1;
+       };
+       return 0;
+}
+
+static int amd_fam14h_init(cstate_t *state, unsigned int cpu)
+{
+       int enable_bit, pci_offset, ret;
+       uint32_t val;
+
+       ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu);
+       if (ret)
+               return ret;
+
+       /* NBP1 needs extra treating -> write 1 to D18F6x98 bit 1 for init */
+       if (state->id == NBP1) {
+               val = pci_read_long(amd_fam14h_pci_dev, pci_offset);
+               val |= 1 << enable_bit;
+               val = pci_write_long(amd_fam14h_pci_dev, pci_offset, val);
+               return ret;
+       }
+
+       /* Enable monitor */
+       val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG);
+       dprint("Init %s: read at offset: 0x%x val: %u\n", state->name,
+              PCI_MONITOR_ENABLE_REG, (unsigned int) val);
+       val |= 1 << enable_bit;
+       pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val);
+
+       dprint("Init %s: offset: 0x%x enable_bit: %d - val: %u (%u)\n",
+              state->name, PCI_MONITOR_ENABLE_REG, enable_bit,
+              (unsigned int) val, cpu);
+
+       /* Set counter to zero */
+       pci_write_long(amd_fam14h_pci_dev, pci_offset, 0);
+       previous_count[state->id][cpu] = 0;
+
+       return 0;
+}
+
+static int amd_fam14h_disable(cstate_t *state, unsigned int cpu)
+{
+       int enable_bit, pci_offset, ret;
+       uint32_t val;
+
+       ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu);
+       if (ret)
+               return ret;
+
+       val = pci_read_long(amd_fam14h_pci_dev, pci_offset);
+       dprint("%s: offset: 0x%x %u\n", state->name, pci_offset, val);
+       if (state->id == NBP1) {
+               /* was the bit whether NBP1 got entered set? */
+               nbp1_entered = (val & (1 << PCI_NBP1_ACTIVE_BIT)) |
+                       (val & (1 << PCI_NBP1_ENTERED_BIT));
+
+               dprint("NBP1 was %sentered - 0x%x - enable_bit: "
+                      "%d - pci_offset: 0x%x\n",
+                      nbp1_entered ? "" : "not ",
+                      val, enable_bit, pci_offset);
+               return ret;
+       }
+       current_count[state->id][cpu] = val;
+
+       dprint("%s: Current -  %llu (%u)\n", state->name,
+              current_count[state->id][cpu], cpu);
+       dprint("%s: Previous - %llu (%u)\n", state->name,
+              previous_count[state->id][cpu], cpu);
+
+       val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG);
+       val &= ~(1 << enable_bit);
+       pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val);
+
+       return 0;
+}
+
+static int fam14h_nbp1_count(unsigned int id, unsigned long long *count,
+                            unsigned int cpu)
+{
+       if (id == NBP1) {
+               if (nbp1_entered)
+                       *count = 1;
+               else
+                       *count = 0;
+               return 0;
+       }
+       return -1;
+}
+static int fam14h_get_count_percent(unsigned int id, double *percent,
+                                   unsigned int cpu)
+{
+       unsigned long diff;
+
+       if (id >= AMD_FAM14H_STATE_NUM)
+               return -1;
+       /* residency count in 80ns -> divide through 12.5 to get us residency */
+       diff = current_count[id][cpu] - previous_count[id][cpu];
+
+       if (timediff == 0)
+               *percent = 0.0;
+       else
+               *percent = 100.0 * diff / timediff / 12.5;
+
+       dprint("Timediff: %llu - res~: %lu us - percent: %.2f %%\n",
+              timediff, diff * 10 / 125, *percent);
+
+       return 0;
+}
+
+static int amd_fam14h_start(void)
+{
+       int num, cpu;
+       clock_gettime(CLOCK_REALTIME, &start_time);
+       for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++)
+                       amd_fam14h_init(&amd_fam14h_cstates[num], cpu);
+       }
+#ifdef DEBUG
+       clock_gettime(CLOCK_REALTIME, &dbg_time);
+       dbg_timediff = timespec_diff_us(start_time, dbg_time);
+       dprint("Enabling counters took: %lu us\n",
+              dbg_timediff);
+#endif
+       return 0;
+}
+
+static int amd_fam14h_stop(void)
+{
+       int num, cpu;
+       struct timespec end_time;
+
+       clock_gettime(CLOCK_REALTIME, &end_time);
+
+       for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++)
+                       amd_fam14h_disable(&amd_fam14h_cstates[num], cpu);
+       }
+#ifdef DEBUG
+       clock_gettime(CLOCK_REALTIME, &dbg_time);
+       dbg_timediff = timespec_diff_us(end_time, dbg_time);
+       dprint("Disabling counters took: %lu ns\n", dbg_timediff);
+#endif
+       timediff = timespec_diff_us(start_time, end_time);
+       if (timediff / 1000 > OVERFLOW_MS)
+               print_overflow_err((unsigned int)timediff / 1000000,
+                                  OVERFLOW_MS / 1000);
+
+       return 0;
+}
+
+static int is_nbp1_capable(void)
+{
+       uint32_t val;
+       val = pci_read_long(amd_fam14h_pci_dev, PCI_NBP1_CAP_OFFSET);
+       return val & (1 << 31);
+}
+
+struct cpuidle_monitor *amd_fam14h_register(void)
+{
+       int num;
+
+       if (cpupower_cpu_info.vendor != X86_VENDOR_AMD)
+               return NULL;
+
+       if (cpupower_cpu_info.family == 0x14) {
+               if (cpu_count <= 0 || cpu_count > 2) {
+                       fprintf(stderr, "AMD fam14h: Invalid cpu count: %d\n",
+                               cpu_count);
+                       return NULL;
+               }
+       } else
+               return NULL;
+
+       /* We do not alloc for nbp1 machine wide counter */
+       for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) {
+               previous_count[num] = calloc(cpu_count,
+                                             sizeof(unsigned long long));
+               current_count[num]  = calloc(cpu_count,
+                                             sizeof(unsigned long long));
+       }
+
+       amd_fam14h_pci_dev = pci_acc_init(&pci_acc, pci_vendor_id, pci_dev_ids);
+       if (amd_fam14h_pci_dev == NULL || pci_acc == NULL)
+               return NULL;
+
+       if (!is_nbp1_capable())
+               amd_fam14h_monitor.hw_states_num = AMD_FAM14H_STATE_NUM - 1;
+
+       amd_fam14h_monitor.name_len = strlen(amd_fam14h_monitor.name);
+       return &amd_fam14h_monitor;
+}
+
+static void amd_fam14h_unregister(void)
+{
+       int num;
+       for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) {
+               free(previous_count[num]);
+               free(current_count[num]);
+       }
+       pci_cleanup(pci_acc);
+}
+
+struct cpuidle_monitor amd_fam14h_monitor = {
+       .name                   = "Ontario",
+       .hw_states              = amd_fam14h_cstates,
+       .hw_states_num          = AMD_FAM14H_STATE_NUM,
+       .start                  = amd_fam14h_start,
+       .stop                   = amd_fam14h_stop,
+       .do_register            = amd_fam14h_register,
+       .unregister             = amd_fam14h_unregister,
+       .needs_root             = 1,
+       .overflow_s             = OVERFLOW_MS / 1000,
+};
+#endif /* #if defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
new file mode 100644 (file)
index 0000000..d048b96
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+
+#include "helpers/sysfs.h"
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define CPUIDLE_STATES_MAX 10
+static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX];
+struct cpuidle_monitor cpuidle_sysfs_monitor;
+
+static unsigned long long **previous_count;
+static unsigned long long **current_count;
+struct timespec start_time;
+static unsigned long long timediff;
+
+static int cpuidle_get_count_percent(unsigned int id, double *percent,
+                                    unsigned int cpu)
+{
+       unsigned long long statediff = current_count[cpu][id]
+               - previous_count[cpu][id];
+       dprint("%s: - diff: %llu - percent: %f (%u)\n",
+              cpuidle_cstates[id].name, timediff, *percent, cpu);
+
+       if (timediff == 0)
+               *percent = 0.0;
+       else
+               *percent = ((100.0 * statediff) / timediff);
+
+       dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
+              cpuidle_cstates[id].name, timediff, statediff, *percent, cpu);
+
+       return 0;
+}
+
+static int cpuidle_start(void)
+{
+       int cpu, state;
+       clock_gettime(CLOCK_REALTIME, &start_time);
+       for (cpu = 0; cpu < cpu_count; cpu++) {
+               for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
+                    state++) {
+                       previous_count[cpu][state] =
+                               sysfs_get_idlestate_time(cpu, state);
+                       dprint("CPU %d - State: %d - Val: %llu\n",
+                              cpu, state, previous_count[cpu][state]);
+               }
+       };
+       return 0;
+}
+
+static int cpuidle_stop(void)
+{
+       int cpu, state;
+       struct timespec end_time;
+       clock_gettime(CLOCK_REALTIME, &end_time);
+       timediff = timespec_diff_us(start_time, end_time);
+
+       for (cpu = 0; cpu < cpu_count; cpu++) {
+               for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
+                    state++) {
+                       current_count[cpu][state] =
+                               sysfs_get_idlestate_time(cpu, state);
+                       dprint("CPU %d - State: %d - Val: %llu\n",
+                              cpu, state, previous_count[cpu][state]);
+               }
+       };
+       return 0;
+}
+
+void fix_up_intel_idle_driver_name(char *tmp, int num)
+{
+       /* fix up cpuidle name for intel idle driver */
+       if (!strncmp(tmp, "NHM-", 4)) {
+               switch (num) {
+               case 1:
+                       strcpy(tmp, "C1");
+                       break;
+               case 2:
+                       strcpy(tmp, "C3");
+                       break;
+               case 3:
+                       strcpy(tmp, "C6");
+                       break;
+               }
+       } else if (!strncmp(tmp, "SNB-", 4)) {
+               switch (num) {
+               case 1:
+                       strcpy(tmp, "C1");
+                       break;
+               case 2:
+                       strcpy(tmp, "C3");
+                       break;
+               case 3:
+                       strcpy(tmp, "C6");
+                       break;
+               case 4:
+                       strcpy(tmp, "C7");
+                       break;
+               }
+       } else if (!strncmp(tmp, "ATM-", 4)) {
+               switch (num) {
+               case 1:
+                       strcpy(tmp, "C1");
+                       break;
+               case 2:
+                       strcpy(tmp, "C2");
+                       break;
+               case 3:
+                       strcpy(tmp, "C4");
+                       break;
+               case 4:
+                       strcpy(tmp, "C6");
+                       break;
+               }
+       }
+}
+
+static struct cpuidle_monitor *cpuidle_register(void)
+{
+       int num;
+       char *tmp;
+
+       /* Assume idle state count is the same for all CPUs */
+       cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
+
+       if (cpuidle_sysfs_monitor.hw_states_num == 0)
+               return NULL;
+
+       for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
+               tmp = sysfs_get_idlestate_name(0, num);
+               if (tmp == NULL)
+                       continue;
+
+               fix_up_intel_idle_driver_name(tmp, num);
+               strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
+               free(tmp);
+
+               tmp = sysfs_get_idlestate_desc(0, num);
+               if (tmp == NULL)
+                       continue;
+               strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1);
+               free(tmp);
+
+               cpuidle_cstates[num].range = RANGE_THREAD;
+               cpuidle_cstates[num].id = num;
+               cpuidle_cstates[num].get_count_percent =
+                       cpuidle_get_count_percent;
+       };
+
+       /* Free this at program termination */
+       previous_count = malloc(sizeof(long long *) * cpu_count);
+       current_count = malloc(sizeof(long long *) * cpu_count);
+       for (num = 0; num < cpu_count; num++) {
+               previous_count[num] = malloc(sizeof(long long) *
+                                       cpuidle_sysfs_monitor.hw_states_num);
+               current_count[num] = malloc(sizeof(long long) *
+                                       cpuidle_sysfs_monitor.hw_states_num);
+       }
+
+       cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name);
+       return &cpuidle_sysfs_monitor;
+}
+
+void cpuidle_unregister(void)
+{
+       int num;
+
+       for (num = 0; num < cpu_count; num++) {
+               free(previous_count[num]);
+               free(current_count[num]);
+       }
+       free(previous_count);
+       free(current_count);
+}
+
+struct cpuidle_monitor cpuidle_sysfs_monitor = {
+       .name                   = "Idle_Stats",
+       .hw_states              = cpuidle_cstates,
+       .start                  = cpuidle_start,
+       .stop                   = cpuidle_stop,
+       .do_register            = cpuidle_register,
+       .unregister             = cpuidle_unregister,
+       .needs_root             = 0,
+       .overflow_s             = UINT_MAX,
+};
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
new file mode 100644 (file)
index 0000000..ba4bf06
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Output format inspired by Len Brown's <lenb@kernel.org> turbostat tool.
+ *
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <libgen.h>
+
+#include "idle_monitor/cpupower-monitor.h"
+#include "idle_monitor/idle_monitors.h"
+#include "helpers/helpers.h"
+
+/* Define pointers to all monitors.  */
+#define DEF(x) & x ## _monitor ,
+struct cpuidle_monitor *all_monitors[] = {
+#include "idle_monitors.def"
+0
+};
+
+static struct cpuidle_monitor *monitors[MONITORS_MAX];
+static unsigned int avail_monitors;
+
+static char *progname;
+
+enum operation_mode_e { list = 1, show, show_all };
+static int mode;
+static int interval = 1;
+static char *show_monitors_param;
+static struct cpupower_topology cpu_top;
+
+/* ToDo: Document this in the manpage */
+static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
+
+long long timespec_diff_us(struct timespec start, struct timespec end)
+{
+       struct timespec temp;
+       if ((end.tv_nsec - start.tv_nsec) < 0) {
+               temp.tv_sec = end.tv_sec - start.tv_sec - 1;
+               temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
+       } else {
+               temp.tv_sec = end.tv_sec - start.tv_sec;
+               temp.tv_nsec = end.tv_nsec - start.tv_nsec;
+       }
+       return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000);
+}
+
+void monitor_help(void)
+{
+       printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] command\n"));
+       printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] [ -i interval_sec ]\n"));
+       printf(_("cpupower monitor: -l\n"));
+       printf(_("\t command: pass an arbitrary command to measure specific workload\n"));
+       printf(_("\t -i: time intervall to measure for in seconds (default 1)\n"));
+       printf(_("\t -l: list available CPU sleep monitors (for use with -m)\n"));
+       printf(_("\t -m: show specific CPU sleep monitors only (in same order)\n"));
+       printf(_("\t -h: print this help\n"));
+       printf("\n");
+       printf(_("only one of: -l, -m are allowed\nIf none of them is passed,"));
+       printf(_(" all supported monitors are shown\n"));
+}
+
+void print_n_spaces(int n)
+{
+       int x;
+       for (x = 0; x < n; x++)
+               printf(" ");
+}
+
+/* size of s must be at least n + 1 */
+int fill_string_with_spaces(char *s, int n)
+{
+       int len = strlen(s);
+       if (len > n)
+               return -1;
+       for (; len < n; len++)
+               s[len] = ' ';
+       s[len] = '\0';
+       return 0;
+}
+
+void print_header(int topology_depth)
+{
+       int unsigned mon;
+       int state, need_len, pr_mon_len;
+       cstate_t s;
+       char buf[128] = "";
+       int percent_width = 4;
+
+       fill_string_with_spaces(buf, topology_depth * 5 - 1);
+       printf("%s|", buf);
+
+       for (mon = 0; mon < avail_monitors; mon++) {
+               pr_mon_len = 0;
+               need_len = monitors[mon]->hw_states_num * (percent_width + 3)
+                       - 1;
+               if (mon != 0) {
+                       printf("|| ");
+                       need_len--;
+               }
+               sprintf(buf, "%s", monitors[mon]->name);
+               fill_string_with_spaces(buf, need_len);
+               printf("%s", buf);
+       }
+       printf("\n");
+
+       if (topology_depth > 2)
+               printf("PKG |");
+       if (topology_depth > 1)
+               printf("CORE|");
+       if (topology_depth > 0)
+               printf("CPU |");
+
+       for (mon = 0; mon < avail_monitors; mon++) {
+               if (mon != 0)
+                       printf("|| ");
+               else
+                       printf(" ");
+               for (state = 0; state < monitors[mon]->hw_states_num; state++) {
+                       if (state != 0)
+                               printf(" | ");
+                       s = monitors[mon]->hw_states[state];
+                       sprintf(buf, "%s", s.name);
+                       fill_string_with_spaces(buf, percent_width);
+                       printf("%s", buf);
+               }
+               printf(" ");
+       }
+       printf("\n");
+}
+
+
+void print_results(int topology_depth, int cpu)
+{
+       unsigned int mon;
+       int state, ret;
+       double percent;
+       unsigned long long result;
+       cstate_t s;
+
+       if (topology_depth > 2)
+               printf("%4d|", cpu_top.core_info[cpu].pkg);
+       if (topology_depth > 1)
+               printf("%4d|", cpu_top.core_info[cpu].core);
+       if (topology_depth > 0)
+               printf("%4d|", cpu_top.core_info[cpu].cpu);
+
+       for (mon = 0; mon < avail_monitors; mon++) {
+               if (mon != 0)
+                       printf("||");
+
+               for (state = 0; state < monitors[mon]->hw_states_num; state++) {
+                       if (state != 0)
+                               printf("|");
+
+                       s = monitors[mon]->hw_states[state];
+
+                       if (s.get_count_percent) {
+                               ret = s.get_count_percent(s.id, &percent,
+                                                 cpu_top.core_info[cpu].cpu);
+                               if (ret)
+                                       printf("******");
+                               else if (percent >= 100.0)
+                                       printf("%6.1f", percent);
+                               else
+                                       printf("%6.2f", percent);
+                       } else if (s.get_count) {
+                               ret = s.get_count(s.id, &result,
+                                                 cpu_top.core_info[cpu].cpu);
+                               if (ret)
+                                       printf("******");
+                               else
+                                       printf("%6llu", result);
+                       } else {
+                               printf(_("Monitor %s, Counter %s has no count "
+                                        "function. Implementation error\n"),
+                                      monitors[mon]->name, s.name);
+                               exit(EXIT_FAILURE);
+                       }
+               }
+       }
+       /* cpu offline */
+       if (cpu_top.core_info[cpu].pkg == -1 ||
+           cpu_top.core_info[cpu].core == -1) {
+               printf(_(" *is offline\n"));
+               return;
+       } else
+               printf("\n");
+}
+
+
+/* param: string passed by -m param (The list of monitors to show)
+ *
+ * Monitors must have been registered already, matching monitors
+ * are picked out and available monitors array is overridden
+ * with matching ones
+ *
+ * Monitors get sorted in the same order the user passes them
+*/
+
+static void parse_monitor_param(char *param)
+{
+       unsigned int num;
+       int mon, hits = 0;
+       char *tmp = param, *token;
+       struct cpuidle_monitor *tmp_mons[MONITORS_MAX];
+
+
+       for (mon = 0; mon < MONITORS_MAX; mon++, tmp = NULL) {
+               token = strtok(tmp, ",");
+               if (token == NULL)
+                       break;
+               if (strlen(token) >= MONITOR_NAME_LEN) {
+                       printf(_("%s: max monitor name length"
+                                " (%d) exceeded\n"), token, MONITOR_NAME_LEN);
+                       continue;
+               }
+
+               for (num = 0; num < avail_monitors; num++) {
+                       if (!strcmp(monitors[num]->name, token)) {
+                               dprint("Found requested monitor: %s\n", token);
+                               tmp_mons[hits] = monitors[num];
+                               hits++;
+                       }
+               }
+       }
+       if (hits == 0) {
+               printf(_("No matching monitor found in %s, "
+                        "try -l option\n"), param);
+               monitor_help();
+               exit(EXIT_FAILURE);
+       }
+       /* Override detected/registerd monitors array with requested one */
+       memcpy(monitors, tmp_mons,
+               sizeof(struct cpuidle_monitor *) * MONITORS_MAX);
+       avail_monitors = hits;
+}
+
+void list_monitors(void)
+{
+       unsigned int mon;
+       int state;
+       cstate_t s;
+
+       for (mon = 0; mon < avail_monitors; mon++) {
+               printf(_("Monitor \"%s\" (%d states) - Might overflow after %u "
+                        "s\n"),
+                       monitors[mon]->name, monitors[mon]->hw_states_num,
+                       monitors[mon]->overflow_s);
+
+               for (state = 0; state < monitors[mon]->hw_states_num; state++) {
+                       s = monitors[mon]->hw_states[state];
+                       /*
+                        * ToDo show more state capabilities:
+                        * percent, time (granlarity)
+                        */
+                       printf("%s\t[%c] -> %s\n", s.name, range_abbr[s.range],
+                              gettext(s.desc));
+               }
+       }
+}
+
+int fork_it(char **argv)
+{
+       int status;
+       unsigned int num;
+       unsigned long long timediff;
+       pid_t child_pid;
+       struct timespec start, end;
+
+       child_pid = fork();
+       clock_gettime(CLOCK_REALTIME, &start);
+
+       for (num = 0; num < avail_monitors; num++)
+               monitors[num]->start();
+
+       if (!child_pid) {
+               /* child */
+               execvp(argv[0], argv);
+       } else {
+               /* parent */
+               if (child_pid == -1) {
+                       perror("fork");
+                       exit(1);
+               }
+
+               signal(SIGINT, SIG_IGN);
+               signal(SIGQUIT, SIG_IGN);
+               if (waitpid(child_pid, &status, 0) == -1) {
+                       perror("wait");
+                       exit(1);
+               }
+       }
+       clock_gettime(CLOCK_REALTIME, &end);
+       for (num = 0; num < avail_monitors; num++)
+               monitors[num]->stop();
+
+       timediff = timespec_diff_us(start, end);
+       if (WIFEXITED(status))
+               printf(_("%s took %.5f seconds and exited with status %d\n"),
+                       argv[0], timediff / (1000.0 * 1000),
+                       WEXITSTATUS(status));
+       return 0;
+}
+
+int do_interval_measure(int i)
+{
+       unsigned int num;
+
+       for (num = 0; num < avail_monitors; num++) {
+               dprint("HW C-state residency monitor: %s - States: %d\n",
+                      monitors[num]->name, monitors[num]->hw_states_num);
+               monitors[num]->start();
+       }
+       sleep(i);
+       for (num = 0; num < avail_monitors; num++)
+               monitors[num]->stop();
+
+       return 0;
+}
+
+static void cmdline(int argc, char *argv[])
+{
+       int opt;
+       progname = basename(argv[0]);
+
+       while ((opt = getopt(argc, argv, "+hli:m:")) != -1) {
+               switch (opt) {
+               case 'h':
+                       monitor_help();
+                       exit(EXIT_SUCCESS);
+               case 'l':
+                       if (mode) {
+                               monitor_help();
+                               exit(EXIT_FAILURE);
+                       }
+                       mode = list;
+                       break;
+               case 'i':
+                       /* only allow -i with -m or no option */
+                       if (mode && mode != show) {
+                               monitor_help();
+                               exit(EXIT_FAILURE);
+                       }
+                       interval = atoi(optarg);
+                       break;
+               case 'm':
+                       if (mode) {
+                               monitor_help();
+                               exit(EXIT_FAILURE);
+                       }
+                       mode = show;
+                       show_monitors_param = optarg;
+                       break;
+               default:
+                       monitor_help();
+                       exit(EXIT_FAILURE);
+               }
+       }
+       if (!mode)
+               mode = show_all;
+}
+
+int cmd_monitor(int argc, char **argv)
+{
+       unsigned int num;
+       struct cpuidle_monitor *test_mon;
+       int cpu;
+
+       cmdline(argc, argv);
+       cpu_count = get_cpu_topology(&cpu_top);
+       if (cpu_count < 0) {
+               printf(_("Cannot read number of available processors\n"));
+               return EXIT_FAILURE;
+       }
+
+       dprint("System has up to %d CPU cores\n", cpu_count);
+
+       for (num = 0; all_monitors[num]; num++) {
+               dprint("Try to register: %s\n", all_monitors[num]->name);
+               test_mon = all_monitors[num]->do_register();
+               if (test_mon) {
+                       if (test_mon->needs_root && !run_as_root) {
+                               fprintf(stderr, _("Available monitor %s needs "
+                                         "root access\n"), test_mon->name);
+                               continue;
+                       }
+                       monitors[avail_monitors] = test_mon;
+                       dprint("%s registered\n", all_monitors[num]->name);
+                       avail_monitors++;
+               }
+       }
+
+       if (avail_monitors == 0) {
+               printf(_("No HW Cstate monitors found\n"));
+               return 1;
+       }
+
+       if (mode == list) {
+               list_monitors();
+               exit(EXIT_SUCCESS);
+       }
+
+       if (mode == show)
+               parse_monitor_param(show_monitors_param);
+
+       dprint("Packages: %d - Cores: %d - CPUs: %d\n",
+              cpu_top.pkgs, cpu_top.cores, cpu_count);
+
+       /*
+        * if any params left, it must be a command to fork
+        */
+       if (argc - optind)
+               fork_it(argv + optind);
+       else
+               do_interval_measure(interval);
+
+       /* ToDo: Topology parsing needs fixing first to do
+          this more generically */
+       if (cpu_top.pkgs > 1)
+               print_header(3);
+       else
+               print_header(1);
+
+       for (cpu = 0; cpu < cpu_count; cpu++) {
+               if (cpu_top.pkgs > 1)
+                       print_results(3, cpu);
+               else
+                       print_results(1, cpu);
+       }
+
+       for (num = 0; num < avail_monitors; num++)
+               monitors[num]->unregister();
+
+       cpu_topology_release(cpu_top);
+       return 0;
+}
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
new file mode 100644 (file)
index 0000000..9312ee1
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ */
+
+#ifndef __CPUIDLE_INFO_HW__
+#define __CPUIDLE_INFO_HW__
+
+#include <stdarg.h>
+#include <time.h>
+
+#include "idle_monitor/idle_monitors.h"
+
+#define MONITORS_MAX 20
+#define MONITOR_NAME_LEN 20
+#define CSTATE_NAME_LEN 5
+#define CSTATE_DESC_LEN 60
+
+int cpu_count;
+
+/* Hard to define the right names ...: */
+enum power_range_e {
+       RANGE_THREAD,   /* Lowest in topology hierarcy, AMD: core, Intel: thread
+                          kernel sysfs: cpu */
+       RANGE_CORE,     /* AMD: unit, Intel: core, kernel_sysfs: core_id */
+       RANGE_PACKAGE,  /* Package, processor socket */
+       RANGE_MACHINE,  /* Machine, platform wide */
+       RANGE_MAX };
+
+typedef struct cstate {
+       int  id;
+       enum power_range_e range;
+       char name[CSTATE_NAME_LEN];
+       char desc[CSTATE_DESC_LEN];
+
+       /* either provide a percentage or a general count */
+       int (*get_count_percent)(unsigned int self_id, double *percent,
+                                unsigned int cpu);
+       int (*get_count)(unsigned int self_id, unsigned long long *count,
+                        unsigned int cpu);
+} cstate_t;
+
+struct cpuidle_monitor {
+       /* Name must not contain whitespaces */
+       char name[MONITOR_NAME_LEN];
+       int name_len;
+       int hw_states_num;
+       cstate_t *hw_states;
+       int (*start) (void);
+       int (*stop) (void);
+       struct cpuidle_monitor* (*do_register) (void);
+       void (*unregister)(void);
+       unsigned int overflow_s;
+       int needs_root;
+};
+
+extern long long timespec_diff_us(struct timespec start, struct timespec end);
+
+#define print_overflow_err(mes, ov)                                            \
+{                                                                              \
+       fprintf(stderr, gettext("Measure took %u seconds, but registers could " \
+                               "overflow at %u seconds, results "              \
+                               "could be inaccurate\n"), mes, ov);             \
+}
+
+#endif /* __CPUIDLE_INFO_HW__ */
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
new file mode 100644 (file)
index 0000000..e3f8d9b
--- /dev/null
@@ -0,0 +1,7 @@
+#if defined(__i386__) || defined(__x86_64__)
+DEF(amd_fam14h)
+DEF(intel_nhm)
+DEF(intel_snb)
+DEF(mperf)
+#endif
+DEF(cpuidle_sysfs)
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.h b/tools/power/cpupower/utils/idle_monitor/idle_monitors.h
new file mode 100644 (file)
index 0000000..4fcdeb1
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Based on the idea from Michael Matz <matz@suse.de>
+ *
+ */
+
+#ifndef _CPUIDLE_IDLE_MONITORS_H_
+#define _CPUIDLE_IDLE_MONITORS_H_
+
+#define DEF(x) extern struct cpuidle_monitor x ##_monitor;
+#include "idle_monitors.def"
+#undef DEF
+extern struct cpuidle_monitor *all_monitors[];
+
+#endif /* _CPUIDLE_IDLE_MONITORS_H_ */
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
new file mode 100644 (file)
index 0000000..63ca87a
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <cpufreq.h>
+
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define MSR_APERF      0xE8
+#define MSR_MPERF      0xE7
+
+#define MSR_TSC        0x10
+
+enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT };
+
+static int mperf_get_count_percent(unsigned int self_id, double *percent,
+                                  unsigned int cpu);
+static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
+                               unsigned int cpu);
+
+static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
+       {
+               .name                   = "C0",
+               .desc                   = N_("Processor Core not idle"),
+               .id                     = C0,
+               .range                  = RANGE_THREAD,
+               .get_count_percent      = mperf_get_count_percent,
+       },
+       {
+               .name                   = "Cx",
+               .desc                   = N_("Processor Core in an idle state"),
+               .id                     = Cx,
+               .range                  = RANGE_THREAD,
+               .get_count_percent      = mperf_get_count_percent,
+       },
+
+       {
+               .name                   = "Freq",
+               .desc                   = N_("Average Frequency (including boost) in MHz"),
+               .id                     = AVG_FREQ,
+               .range                  = RANGE_THREAD,
+               .get_count              = mperf_get_count_freq,
+       },
+};
+
+static unsigned long long tsc_at_measure_start;
+static unsigned long long tsc_at_measure_end;
+static unsigned long max_frequency;
+static unsigned long long *mperf_previous_count;
+static unsigned long long *aperf_previous_count;
+static unsigned long long *mperf_current_count;
+static unsigned long long *aperf_current_count;
+/* valid flag for all CPUs. If a MSR read failed it will be zero */
+static int *is_valid;
+
+static int mperf_get_tsc(unsigned long long *tsc)
+{
+       return read_msr(0, MSR_TSC, tsc);
+}
+
+static int mperf_init_stats(unsigned int cpu)
+{
+       unsigned long long val;
+       int ret;
+
+       ret = read_msr(cpu, MSR_APERF, &val);
+       aperf_previous_count[cpu] = val;
+       ret |= read_msr(cpu, MSR_MPERF, &val);
+       mperf_previous_count[cpu] = val;
+       is_valid[cpu] = !ret;
+
+       return 0;
+}
+
+static int mperf_measure_stats(unsigned int cpu)
+{
+       unsigned long long val;
+       int ret;
+
+       ret = read_msr(cpu, MSR_APERF, &val);
+       aperf_current_count[cpu] = val;
+       ret |= read_msr(cpu, MSR_MPERF, &val);
+       mperf_current_count[cpu] = val;
+       is_valid[cpu] = !ret;
+
+       return 0;
+}
+
+/*
+ * get_average_perf()
+ *
+ * Returns the average performance (also considers boosted frequencies)
+ *
+ * Input:
+ *   aperf_diff: Difference of the aperf register over a time period
+ *   mperf_diff: Difference of the mperf register over the same time period
+ *   max_freq:   Maximum frequency (P0)
+ *
+ * Returns:
+ *   Average performance over the time period
+ */
+static unsigned long get_average_perf(unsigned long long aperf_diff,
+                                     unsigned long long mperf_diff)
+{
+       unsigned int perf_percent = 0;
+       if (((unsigned long)(-1) / 100) < aperf_diff) {
+               int shift_count = 7;
+               aperf_diff >>= shift_count;
+               mperf_diff >>= shift_count;
+       }
+       perf_percent = (aperf_diff * 100) / mperf_diff;
+       return (max_frequency * perf_percent) / 100;
+}
+
+static int mperf_get_count_percent(unsigned int id, double *percent,
+                                  unsigned int cpu)
+{
+       unsigned long long aperf_diff, mperf_diff, tsc_diff;
+
+       if (!is_valid[cpu])
+               return -1;
+
+       if (id != C0 && id != Cx)
+               return -1;
+
+       mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
+       aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
+       tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
+
+       *percent = 100.0 * mperf_diff / tsc_diff;
+       dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n",
+              mperf_cstates[id].name, mperf_diff, tsc_diff);
+
+       if (id == Cx)
+               *percent = 100.0 - *percent;
+
+       dprint("%s: previous: %llu - current: %llu - (%u)\n",
+               mperf_cstates[id].name, mperf_diff, aperf_diff, cpu);
+       dprint("%s: %f\n", mperf_cstates[id].name, *percent);
+       return 0;
+}
+
+static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
+                               unsigned int cpu)
+{
+       unsigned long long aperf_diff, mperf_diff;
+
+       if (id != AVG_FREQ)
+               return 1;
+
+       if (!is_valid[cpu])
+               return -1;
+
+       mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
+       aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
+
+       /* Return MHz for now, might want to return KHz if column width is more
+          generic */
+       *count = get_average_perf(aperf_diff, mperf_diff) / 1000;
+       dprint("%s: %llu\n", mperf_cstates[id].name, *count);
+
+       return 0;
+}
+
+static int mperf_start(void)
+{
+       int cpu;
+       unsigned long long dbg;
+
+       mperf_get_tsc(&tsc_at_measure_start);
+
+       for (cpu = 0; cpu < cpu_count; cpu++)
+               mperf_init_stats(cpu);
+
+       mperf_get_tsc(&dbg);
+       dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start);
+       return 0;
+}
+
+static int mperf_stop(void)
+{
+       unsigned long long dbg;
+       int cpu;
+
+       mperf_get_tsc(&tsc_at_measure_end);
+
+       for (cpu = 0; cpu < cpu_count; cpu++)
+               mperf_measure_stats(cpu);
+
+       mperf_get_tsc(&dbg);
+       dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
+
+       return 0;
+}
+
+struct cpuidle_monitor mperf_monitor;
+
+struct cpuidle_monitor *mperf_register(void)
+{
+       unsigned long min;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
+               return NULL;
+
+       /* Assume min/max all the same on all cores */
+       if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) {
+               dprint("Cannot retrieve max freq from cpufreq kernel "
+                      "subsystem\n");
+               return NULL;
+       }
+
+       /* Free this at program termination */
+       is_valid = calloc(cpu_count, sizeof(int));
+       mperf_previous_count = calloc(cpu_count, sizeof(unsigned long long));
+       aperf_previous_count = calloc(cpu_count, sizeof(unsigned long long));
+       mperf_current_count = calloc(cpu_count, sizeof(unsigned long long));
+       aperf_current_count = calloc(cpu_count, sizeof(unsigned long long));
+
+       mperf_monitor.name_len = strlen(mperf_monitor.name);
+       return &mperf_monitor;
+}
+
+void mperf_unregister(void)
+{
+       free(mperf_previous_count);
+       free(aperf_previous_count);
+       free(mperf_current_count);
+       free(aperf_current_count);
+       free(is_valid);
+}
+
+struct cpuidle_monitor mperf_monitor = {
+       .name                   = "Mperf",
+       .hw_states_num          = MPERF_CSTATE_COUNT,
+       .hw_states              = mperf_cstates,
+       .start                  = mperf_start,
+       .stop                   = mperf_stop,
+       .do_register            = mperf_register,
+       .unregister             = mperf_unregister,
+       .needs_root             = 1,
+       .overflow_s             = 922000000 /* 922337203 seconds TSC overflow
+                                              at 20GHz */
+};
+#endif /* #if defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/nhm_idle.c b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c
new file mode 100644 (file)
index 0000000..d2a91dd
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Based on Len Brown's <lenb@kernel.org> turbostat tool.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define MSR_PKG_C3_RESIDENCY   0x3F8
+#define MSR_PKG_C6_RESIDENCY   0x3F9
+#define MSR_CORE_C3_RESIDENCY  0x3FC
+#define MSR_CORE_C6_RESIDENCY  0x3FD
+
+#define MSR_TSC        0x10
+
+#define NHM_CSTATE_COUNT 4
+
+enum intel_nhm_id { C3 = 0, C6, PC3, PC6, TSC = 0xFFFF };
+
+static int nhm_get_count_percent(unsigned int self_id, double *percent,
+                                unsigned int cpu);
+
+static cstate_t nhm_cstates[NHM_CSTATE_COUNT] = {
+       {
+               .name                   = "C3",
+               .desc                   = N_("Processor Core C3"),
+               .id                     = C3,
+               .range                  = RANGE_CORE,
+               .get_count_percent      = nhm_get_count_percent,
+       },
+       {
+               .name                   = "C6",
+               .desc                   = N_("Processor Core C6"),
+               .id                     = C6,
+               .range                  = RANGE_CORE,
+               .get_count_percent      = nhm_get_count_percent,
+       },
+
+       {
+               .name                   = "PC3",
+               .desc                   = N_("Processor Package C3"),
+               .id                     = PC3,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = nhm_get_count_percent,
+       },
+       {
+               .name                   = "PC6",
+               .desc                   = N_("Processor Package C6"),
+               .id                     = PC6,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = nhm_get_count_percent,
+       },
+};
+
+static unsigned long long tsc_at_measure_start;
+static unsigned long long tsc_at_measure_end;
+static unsigned long long *previous_count[NHM_CSTATE_COUNT];
+static unsigned long long *current_count[NHM_CSTATE_COUNT];
+/* valid flag for all CPUs. If a MSR read failed it will be zero */
+static int *is_valid;
+
+static int nhm_get_count(enum intel_nhm_id id, unsigned long long *val,
+                       unsigned int cpu)
+{
+       int msr;
+
+       switch (id) {
+       case C3:
+               msr = MSR_CORE_C3_RESIDENCY;
+               break;
+       case C6:
+               msr = MSR_CORE_C6_RESIDENCY;
+               break;
+       case PC3:
+               msr = MSR_PKG_C3_RESIDENCY;
+               break;
+       case PC6:
+               msr = MSR_PKG_C6_RESIDENCY;
+               break;
+       case TSC:
+               msr = MSR_TSC;
+               break;
+       default:
+               return -1;
+       };
+       if (read_msr(cpu, msr, val))
+               return -1;
+
+       return 0;
+}
+
+static int nhm_get_count_percent(unsigned int id, double *percent,
+                                unsigned int cpu)
+{
+       *percent = 0.0;
+
+       if (!is_valid[cpu])
+               return -1;
+
+       *percent = (100.0 *
+               (current_count[id][cpu] - previous_count[id][cpu])) /
+               (tsc_at_measure_end - tsc_at_measure_start);
+
+       dprint("%s: previous: %llu - current: %llu - (%u)\n",
+               nhm_cstates[id].name, previous_count[id][cpu],
+               current_count[id][cpu], cpu);
+
+       dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
+              nhm_cstates[id].name,
+              (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
+              current_count[id][cpu] - previous_count[id][cpu],
+              *percent, cpu);
+
+       return 0;
+}
+
+static int nhm_start(void)
+{
+       int num, cpu;
+       unsigned long long dbg, val;
+
+       nhm_get_count(TSC, &tsc_at_measure_start, 0);
+
+       for (num = 0; num < NHM_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       is_valid[cpu] = !nhm_get_count(num, &val, cpu);
+                       previous_count[num][cpu] = val;
+               }
+       }
+       nhm_get_count(TSC, &dbg, 0);
+       dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start);
+       return 0;
+}
+
+static int nhm_stop(void)
+{
+       unsigned long long val;
+       unsigned long long dbg;
+       int num, cpu;
+
+       nhm_get_count(TSC, &tsc_at_measure_end, 0);
+
+       for (num = 0; num < NHM_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       is_valid[cpu] = !nhm_get_count(num, &val, cpu);
+                       current_count[num][cpu] = val;
+               }
+       }
+       nhm_get_count(TSC, &dbg, 0);
+       dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
+
+       return 0;
+}
+
+struct cpuidle_monitor intel_nhm_monitor;
+
+struct cpuidle_monitor *intel_nhm_register(void)
+{
+       int num;
+
+       if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
+               return NULL;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC))
+               return NULL;
+
+       if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
+               return NULL;
+
+       /* Free this at program termination */
+       is_valid = calloc(cpu_count, sizeof(int));
+       for (num = 0; num < NHM_CSTATE_COUNT; num++) {
+               previous_count[num] = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+               current_count[num]  = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+       }
+
+       intel_nhm_monitor.name_len = strlen(intel_nhm_monitor.name);
+       return &intel_nhm_monitor;
+}
+
+void intel_nhm_unregister(void)
+{
+       int num;
+
+       for (num = 0; num < NHM_CSTATE_COUNT; num++) {
+               free(previous_count[num]);
+               free(current_count[num]);
+       }
+       free(is_valid);
+}
+
+struct cpuidle_monitor intel_nhm_monitor = {
+       .name                   = "Nehalem",
+       .hw_states_num          = NHM_CSTATE_COUNT,
+       .hw_states              = nhm_cstates,
+       .start                  = nhm_start,
+       .stop                   = nhm_stop,
+       .do_register            = intel_nhm_register,
+       .unregister             = intel_nhm_unregister,
+       .needs_root             = 1,
+       .overflow_s             = 922000000 /* 922337203 seconds TSC overflow
+                                              at 20GHz */
+};
+#endif
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
new file mode 100644 (file)
index 0000000..a1bc07c
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  Based on Len Brown's <lenb@kernel.org> turbostat tool.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "helpers/helpers.h"
+#include "idle_monitor/cpupower-monitor.h"
+
+#define MSR_PKG_C2_RESIDENCY   0x60D
+#define MSR_PKG_C7_RESIDENCY   0x3FA
+#define MSR_CORE_C7_RESIDENCY  0x3FE
+
+#define MSR_TSC        0x10
+
+enum intel_snb_id { C7 = 0, PC2, PC7, SNB_CSTATE_COUNT, TSC = 0xFFFF };
+
+static int snb_get_count_percent(unsigned int self_id, double *percent,
+                                unsigned int cpu);
+
+static cstate_t snb_cstates[SNB_CSTATE_COUNT] = {
+       {
+               .name                   = "C7",
+               .desc                   = N_("Processor Core C7"),
+               .id                     = C7,
+               .range                  = RANGE_CORE,
+               .get_count_percent      = snb_get_count_percent,
+       },
+       {
+               .name                   = "PC2",
+               .desc                   = N_("Processor Package C2"),
+               .id                     = PC2,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = snb_get_count_percent,
+       },
+       {
+               .name                   = "PC7",
+               .desc                   = N_("Processor Package C7"),
+               .id                     = PC7,
+               .range                  = RANGE_PACKAGE,
+               .get_count_percent      = snb_get_count_percent,
+       },
+};
+
+static unsigned long long tsc_at_measure_start;
+static unsigned long long tsc_at_measure_end;
+static unsigned long long *previous_count[SNB_CSTATE_COUNT];
+static unsigned long long *current_count[SNB_CSTATE_COUNT];
+/* valid flag for all CPUs. If a MSR read failed it will be zero */
+static int *is_valid;
+
+static int snb_get_count(enum intel_snb_id id, unsigned long long *val,
+                       unsigned int cpu)
+{
+       int msr;
+
+       switch (id) {
+       case C7:
+               msr = MSR_CORE_C7_RESIDENCY;
+               break;
+       case PC2:
+               msr = MSR_PKG_C2_RESIDENCY;
+               break;
+       case PC7:
+               msr = MSR_PKG_C7_RESIDENCY;
+               break;
+       case TSC:
+               msr = MSR_TSC;
+               break;
+       default:
+               return -1;
+       };
+       if (read_msr(cpu, msr, val))
+               return -1;
+       return 0;
+}
+
+static int snb_get_count_percent(unsigned int id, double *percent,
+                                unsigned int cpu)
+{
+       *percent = 0.0;
+
+       if (!is_valid[cpu])
+               return -1;
+
+       *percent = (100.0 *
+               (current_count[id][cpu] - previous_count[id][cpu])) /
+               (tsc_at_measure_end - tsc_at_measure_start);
+
+       dprint("%s: previous: %llu - current: %llu - (%u)\n",
+               snb_cstates[id].name, previous_count[id][cpu],
+               current_count[id][cpu], cpu);
+
+       dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
+              snb_cstates[id].name,
+              (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
+              current_count[id][cpu] - previous_count[id][cpu],
+              *percent, cpu);
+
+       return 0;
+}
+
+static int snb_start(void)
+{
+       int num, cpu;
+       unsigned long long val;
+
+       for (num = 0; num < SNB_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       snb_get_count(num, &val, cpu);
+                       previous_count[num][cpu] = val;
+               }
+       }
+       snb_get_count(TSC, &tsc_at_measure_start, 0);
+       return 0;
+}
+
+static int snb_stop(void)
+{
+       unsigned long long val;
+       int num, cpu;
+
+       snb_get_count(TSC, &tsc_at_measure_end, 0);
+
+       for (num = 0; num < SNB_CSTATE_COUNT; num++) {
+               for (cpu = 0; cpu < cpu_count; cpu++) {
+                       is_valid[cpu] = !snb_get_count(num, &val, cpu);
+                       current_count[num][cpu] = val;
+               }
+       }
+       return 0;
+}
+
+struct cpuidle_monitor intel_snb_monitor;
+
+static struct cpuidle_monitor *snb_register(void)
+{
+       int num;
+
+       if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL
+           || cpupower_cpu_info.family != 6)
+               return NULL;
+
+       if (cpupower_cpu_info.model != 0x2A
+           && cpupower_cpu_info.model != 0x2D)
+               return NULL;
+
+       is_valid = calloc(cpu_count, sizeof(int));
+       for (num = 0; num < SNB_CSTATE_COUNT; num++) {
+               previous_count[num] = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+               current_count[num]  = calloc(cpu_count,
+                                       sizeof(unsigned long long));
+       }
+       intel_snb_monitor.name_len = strlen(intel_snb_monitor.name);
+       return &intel_snb_monitor;
+}
+
+void snb_unregister(void)
+{
+       int num;
+       free(is_valid);
+       for (num = 0; num < SNB_CSTATE_COUNT; num++) {
+               free(previous_count[num]);
+               free(current_count[num]);
+       }
+}
+
+struct cpuidle_monitor intel_snb_monitor = {
+       .name                   = "SandyBridge",
+       .hw_states              = snb_cstates,
+       .hw_states_num          = SNB_CSTATE_COUNT,
+       .start                  = snb_start,
+       .stop                   = snb_stop,
+       .do_register            = snb_register,
+       .unregister             = snb_unregister,
+       .needs_root             = 1,
+       .overflow_s             = 922000000 /* 922337203 seconds TSC overflow
+                                              at 20GHz */
+};
+#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/version-gen.sh b/tools/power/cpupower/utils/version-gen.sh
new file mode 100755 (executable)
index 0000000..5ec41c5
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# Script which prints out the version to use for building cpupowerutils.
+# Must be called from tools/power/cpupower/
+# 
+# Heavily based on tools/perf/util/PERF-VERSION-GEN .
+
+LF='
+'
+
+# First check if there is a .git to get the version from git describe
+# otherwise try to get the version from the kernel makefile
+if test -d ../../../.git -o -f ../../../.git &&
+       VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
+       case "$VN" in
+       *$LF*) (exit 1) ;;
+       v[0-9]*)
+               git update-index -q --refresh
+               test -z "$(git diff-index --name-only HEAD --)" ||
+               VN="$VN-dirty" ;;
+       esac
+then
+       VN=$(echo "$VN" | sed -e 's/-/./g');
+else
+       eval $(grep '^VERSION[[:space:]]*=' ../../../Makefile|tr -d ' ')
+       eval $(grep '^PATCHLEVEL[[:space:]]*=' ../../../Makefile|tr -d ' ')
+       eval $(grep '^SUBLEVEL[[:space:]]*=' ../../../Makefile|tr -d ' ')
+       eval $(grep '^EXTRAVERSION[[:space:]]*=' ../../../Makefile|tr -d ' ')
+
+       VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
+fi
+
+VN=$(expr "$VN" : v*'\(.*\)')
+
+echo $VN
index 516551c9f1722f76eeaab3be04164e8ed62ee75e..868cc93f7ac23152b20a54aaa1ce3a21f2b4a626 100644 (file)
@@ -2,8 +2,9 @@
  * Slabinfo: Tool to get reports about slabs
  *
  * (C) 2007 sgi, Christoph Lameter
+ * (C) 2011 Linux Foundation, Christoph Lameter
  *
- * Compile by:
+ * Compile with:
  *
  * gcc -o slabinfo slabinfo.c
  */
@@ -39,6 +40,8 @@ struct slabinfo {
        unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
        unsigned long deactivate_to_head, deactivate_to_tail;
        unsigned long deactivate_remote_frees, order_fallback;
+       unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail;
+       unsigned long alloc_node_mismatch, deactivate_bypass;
        int numa[MAX_NODES];
        int numa_partial[MAX_NODES];
 } slabinfo[MAX_SLABS];
@@ -99,7 +102,7 @@ static void fatal(const char *x, ...)
 
 static void usage(void)
 {
-       printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n"
+       printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n"
                "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
                "-a|--aliases           Show aliases\n"
                "-A|--activity          Most active slabs first\n"
@@ -293,7 +296,7 @@ int line = 0;
 static void first_line(void)
 {
        if (show_activity)
-               printf("Name                   Objects      Alloc       Free   %%Fast Fallb O\n");
+               printf("Name                   Objects      Alloc       Free   %%Fast Fallb O CmpX   UL\n");
        else
                printf("Name                   Objects Objsize    Space "
                        "Slabs/Part/Cpu  O/S O %%Fr %%Ef Flg\n");
@@ -379,14 +382,14 @@ static void show_tracking(struct slabinfo *s)
        printf("\n%s: Kernel object allocation\n", s->name);
        printf("-----------------------------------------------------------------------\n");
        if (read_slab_obj(s, "alloc_calls"))
-               printf(buffer);
+               printf("%s", buffer);
        else
                printf("No Data\n");
 
        printf("\n%s: Kernel object freeing\n", s->name);
        printf("------------------------------------------------------------------------\n");
        if (read_slab_obj(s, "free_calls"))
-               printf(buffer);
+               printf("%s", buffer);
        else
                printf("No Data\n");
 
@@ -400,7 +403,7 @@ static void ops(struct slabinfo *s)
        if (read_slab_obj(s, "ops")) {
                printf("\n%s: kmem_cache operations\n", s->name);
                printf("--------------------------------------------\n");
-               printf(buffer);
+               printf("%s", buffer);
        } else
                printf("\n%s has no kmem_cache operations\n", s->name);
 }
@@ -462,19 +465,32 @@ static void slab_stats(struct slabinfo *s)
        if (s->cpuslab_flush)
                printf("Flushes %8lu\n", s->cpuslab_flush);
 
-       if (s->alloc_refill)
-               printf("Refill %8lu\n", s->alloc_refill);
-
        total = s->deactivate_full + s->deactivate_empty +
-                       s->deactivate_to_head + s->deactivate_to_tail;
-
-       if (total)
-               printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) "
-                       "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n",
-                       s->deactivate_full, (s->deactivate_full * 100) / total,
-                       s->deactivate_empty, (s->deactivate_empty * 100) / total,
-                       s->deactivate_to_head, (s->deactivate_to_head * 100) / total,
+                       s->deactivate_to_head + s->deactivate_to_tail + s->deactivate_bypass;
+
+       if (total) {
+               printf("\nSlab Deactivation             Ocurrences  %%\n");
+               printf("-------------------------------------------------\n");
+               printf("Slab full                     %7lu  %3lu%%\n",
+                       s->deactivate_full, (s->deactivate_full * 100) / total);
+               printf("Slab empty                    %7lu  %3lu%%\n",
+                       s->deactivate_empty, (s->deactivate_empty * 100) / total);
+               printf("Moved to head of partial list %7lu  %3lu%%\n",
+                       s->deactivate_to_head, (s->deactivate_to_head * 100) / total);
+               printf("Moved to tail of partial list %7lu  %3lu%%\n",
                        s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
+               printf("Deactivation bypass           %7lu  %3lu%%\n",
+                       s->deactivate_bypass, (s->deactivate_bypass * 100) / total);
+               printf("Refilled from foreign frees   %7lu  %3lu%%\n",
+                       s->alloc_refill, (s->alloc_refill * 100) / total);
+               printf("Node mismatch                 %7lu  %3lu%%\n",
+                       s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total);
+       }
+
+       if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail)
+               printf("\nCmpxchg_double Looping\n------------------------\n");
+               printf("Locked Cmpxchg Double redos   %lu\nUnlocked Cmpxchg Double redos %lu\n",
+                       s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail);
 }
 
 static void report(struct slabinfo *s)
@@ -573,12 +589,13 @@ static void slabcache(struct slabinfo *s)
                total_alloc = s->alloc_fastpath + s->alloc_slowpath;
                total_free = s->free_fastpath + s->free_slowpath;
 
-               printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d\n",
+               printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d %4ld %4ld\n",
                        s->name, s->objects,
                        total_alloc, total_free,
                        total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
                        total_free ? (s->free_fastpath * 100 / total_free) : 0,
-                       s->order_fallback, s->order);
+                       s->order_fallback, s->order, s->cmpxchg_double_fail,
+                       s->cmpxchg_double_cpu_fail);
        }
        else
                printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
@@ -1190,6 +1207,10 @@ static void read_slab_dir(void)
                        slab->deactivate_to_tail = get_obj("deactivate_to_tail");
                        slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
                        slab->order_fallback = get_obj("order_fallback");
+                       slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail");
+                       slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail");
+                       slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
+                       slab->deactivate_bypass = get_obj("deactivate_bypass");
                        chdir("..");
                        if (slab->name[0] == ':')
                                alias_targets++;